# frozen_string_literal: true

# From: https://github.com/ryanb/cancan/wiki/Testing-Abilities#rspec

require "cancan/matchers"

module Spree
  RSpec::Matchers.define :have_ability do |ability_hash, options = {}|
    match do |user|
      ability         = Ability.new(user)
      target          = options[:for]
      @ability_result = {}
      # e.g.: :create => {:create => true}
      ability_hash    = { ability_hash => true } if ability_hash.is_a? Symbol
      if ability_hash.is_a? Array
        ability_hash = ability_hash.inject({}){ |member, i|
          member.merge(i => true)
        }
      end
      ability_hash.each_key do |action|
        @ability_result[action] = ability.can?(action, target)
      end

      expect(ability_hash).to eq(@ability_result)
    end

    failure_message do |user|
      ability_hash, options = expected
      ability_hash = { ability_hash => true } if ability_hash.is_a? Symbol # e.g.: :create
      if ability_hash.is_a? Array
        ability_hash = ability_hash.inject({}){ |member, i|
          member.merge(i => true)
        }
      end
      target = options[:for]
      message = "expected User:#{user} to have ability: #{ability_hash} for #{target}, " \
                "but actual result is #{@ability_result}"
    end

    # to clean up output of RSpec Documentation format
    description do
      target = expected.last[:for]
      "have ability #{ability_hash.keys.join(', ')} for #{target.class.name}"
    end
  end
end
