<commit_before>module ChefSpec::Matchers
  class ResourceMatcher
    def initialize(resource_name, expected_action, expected_identity)
      @resource_name     = resource_name
      @expected_action   = expected_action
      @expected_identity = expected_identity
    end

    def with(parameters = {})
      params.merge!(parameters)
      self
    end

    def at_compile_time
      raise ArgumentError, 'Cannot specify both .at_converge_time and .at_compile_time!' if @converge_time
      @compile_time = true
      self
    end

    def at_converge_time
      raise ArgumentError, 'Cannot specify both .at_compile_time and .at_converge_time!' if @compile_time
      @converge_time = true
      self
    end

    #
    # Allow users to specify fancy #with matchers.
    #
    def method_missing(m, *args, &block)
      if m.to_s =~ /^with_(.+)$/
        with($1.to_sym => args.first)
        self
      else
        super
      end
    end

    def description
      %Q{#{@expected_action} #{@resource_name} "#{@expected_identity}"}
    end

    def matches?(runner)
      @runner = runner

      if resource
        ChefSpec::Coverage.cover!(resource)
        resource.performed_action?(@expected_action) && unmatched_parameters.empty? && correct_phase?
      else
        false
      end
    end

    def failure_message
      if resource
        if resource.performed_action?(@expected_action)
          if unmatched_parameters.empty?
            if @compile_time
              %Q{expected "#{resource.to_s}" to be run at compile time}
            else
              %Q{expected "#{resource.to_s}" to be run at converge time}
            end
          else
            %Q{expected "#{resource.to_s}" to have parameters:} \
            "\n\n" \
            "  " + unmatched_parameters.collect { |parameter, h|
              "#{parameter} #{h[:expected].inspect}, was #{h[:actual].inspect}"
            }.join("\n  ")
          end
        else
          %Q{expected "#{resource.to_s}" actions #{resource.performed_actions.inspect}} \
          " to include :#{@expected_action}"
        end
      else
        %Q{expected "#{@resource_name}[#{@expected_identity}]"} \
        " with action :#{@expected_action} to be in Chef run." \
        " Other #{@resource_name} resources:" \
        "\n\n" \
        "  " + similar_resources.map(&:to_s).join("\n  ") + "\n "
      end
    end

    def failure_message_when_negated<commit_msg>Output a diff when multi-line resource parameters are unmatched<commit_after>require 'rspec/matchers/expecteds_for_multiple_diffs'
require 'rspec/expectations/fail_with'

module ChefSpec::Matchers
  class ResourceMatcher
    def initialize(resource_name, expected_action, expected_identity)
      @resource_name     = resource_name
      @expected_action   = expected_action
      @expected_identity = expected_identity
    end

    def with(parameters = {})
      params.merge!(parameters)
      self
    end

    def at_compile_time
      raise ArgumentError, 'Cannot specify both .at_converge_time and .at_compile_time!' if @converge_time
      @compile_time = true
      self
    end

    def at_converge_time
      raise ArgumentError, 'Cannot specify both .at_compile_time and .at_converge_time!' if @compile_time
      @converge_time = true
      self
    end

    #
    # Allow users to specify fancy #with matchers.
    #
    def method_missing(m, *args, &block)
      if m.to_s =~ /^with_(.+)$/
        with($1.to_sym => args.first)
        self
      else
        super
      end
    end

    def description
      %Q{#{@expected_action} #{@resource_name} "#{@expected_identity}"}
    end

    def matches?(runner)
      @runner = runner

      if resource
        ChefSpec::Coverage.cover!(resource)
        resource.performed_action?(@expected_action) && unmatched_parameters.empty? && correct_phase?
      else
        false
      end
    end

    def failure_message
      if resource
        if resource.performed_action?(@expected_action)
          if unmatched_parameters.empty?
            if @compile_time
              %Q{expected "#{resource.to_s}" to be run at compile time}
            else
              %Q{expected "#{resource.to_s}" to be run at converge time}
            end
          else
            message = %Q{expected "#{resource.to_s}" to have parameters:} \
            "\n\n" \
            "  " + unmatched_parameters.collect { |parameter, h|
              msg = "#{parameter} #{h[:expected].inspect}, was #{h[:actual].inspect}"
              diff = ::RSpec::Matchers::ExpectedsForMultipleDiffs.from(h[:expected]) \
                     .message_with_diff(message, ::RSpec::Expectations::differ, h[:actual])
              msg += diff if diff
              msg
            }.join("\n  ")
          end
        else
          %Q{expected "#{resource.to_s}" actions #{resource.performed_actions.inspect}} \
          " to include :#{@expected_action}"
        end
      else
        %Q{expected "#{@resource_name}[#{@expected_identity}]"} \
        " with action :#{@expected_action} to be in Chef run." \
        " Other #{@resource_name} resources:" \
        "\n\n" \
        "  " + similar_resources.map(&:to_s).join("\n  ") + "\n "
      end
    end

    def failure_message_when_negated
{'fraction_non_alphanumeric': 0.10887326619798594, 'fraction_numerical': 0.0003800114003420103, 'mean_word_length': 2.21760391198044, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 5, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6601254', 'n_tokens_mistral': 1560, 'n_tokens_neox': 1543, 'n_words': 361}