require 'rails_helper'

describe Ability do
  let(:user_options) { {} }
  let(:user) { build :user, user_options }
  subject { Ability.new user }
  before do
    Rails.application.initializers.find{|i| i.name == 'dunlop.ability'}.run
  end

  describe '#user_roles, #user_class_roles, #setup_dunlop_class_based_abilities' do
    it "handles class based authorizations correctly" do
      user_options[:role_names] = [
        'rubbish',
        'a-b-c-d',
        'read-class-ABC',
        'download-class-SourceFile',
        'download-class-SourceFile::MySource'
      ]

      subject.user_roles.should       eq [Dunlop::Ability::UserRole.new('download', 'class', 'SourceFile::MySource')]
      subject.all_class_roles.should eq  [Dunlop::Ability::UserRole.new('download', 'class', 'SourceFile::MySource')]

      allow( user ).to receive(:inspect).and_return "Test User" # devise 4.2.0 issue

      expect( user ).not_to receive(:role_names) # memoize result
      subject.user_roles

      subject.should     be_able_to :download, SourceFile::MySource
      subject.should_not be_able_to :download, SourceFile
      subject.should_not be_able_to :manage,   SourceFile::MySource
    end

    it "authorizes the engine when authorized as app" do
      user_options[:role_names] = ['read-app-dunlop']
      subject.should     be_able_to :read,   Dunlop::Engine
      subject.should_not be_able_to :manage, Dunlop::Engine
    end

    it "authorizes the engine when authorized as adapter" do
      user_options[:role_names] = ['read-adapter-dunlop']
      subject.should     be_able_to :read,   Dunlop::Engine
      subject.should_not be_able_to :manage, Dunlop::Engine
    end

    it "authorized camelized classes on model specification" do
      user_options[:role_names] = ['read-model-source-file/my_source']
      subject.should     be_able_to :read,   SourceFile::MySource
      subject.should_not be_able_to :manage, SourceFile::MySource
    end
  end

  describe "#setup_dunlop_class_based_abilities" do
    it "sets :index ability to top level class" do
      user_options[:role_names] = [
        'download-class-SourceFile::MySource'
      ]

      subject.should_not be_able_to :download, SourceFile
      subject.should     be_able_to :index,    SourceFile
    end
  end

  describe "advanced permissions (see spec/dummy/app/models/ability.rb for implementation)" do
    it "can edit other users with the same domain is advanced permission manage-domain-User is present as admin role" do
      user_options[:role_names_admin] = [
        'manage-domain-User'
      ]
      user.my_domain = "ServiceProviderA"

      other_user_same_domain  = build :user, my_domain: "ServiceProviderA"
      other_user_other_domain = build :user, my_domain: "ServiceProviderB"

      subject.should     be_able_to :manage, other_user_same_domain
      subject.should_not be_able_to :manage, other_user_other_domain
    end
  end

  describe ".alias_subject" do
    let(:ability_class) do
      Class.new do
        include Dunlop::Ability
        add_dunlop_allowed_authorization_classes!
        alias_subject WorkflowInstanceBatch, to: WorkflowInstance
      end
    end

    # The dunlop has a default of alias_subject WorkflowInstanceBatch, to: WorkflowInstance
    # lets test this one
    it "copies permissions on target" do
      ability = ability_class.new(build(:user, role_names: ['download-class-WorkflowInstance']))
      ability.should_not be_able_to :update,   WorkflowInstance
      ability.should     be_able_to :download, WorkflowInstance
      ability.should_not be_able_to :update,   WorkflowInstance::Scenario1
      ability.should     be_able_to :download, WorkflowInstance::Scenario1
      ability.should_not be_able_to :update,   WorkflowInstanceBatch
      ability.should     be_able_to :download, WorkflowInstanceBatch
      ability.should_not be_able_to :update,   WorkflowInstanceBatch::Scenario1
      ability.should     be_able_to :download, WorkflowInstanceBatch::Scenario1
    end
  end
end
