<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 matches?(runner)
      @runner = runner

      if resource
        resource.performed_action?(@expected_action) && unmatched_parameters.empty? && correct_phase?
      else
        false
      end
    end

    def failure_message_for_should
      if resource
        if resource.performed_action?(@expected_action)
          if unmatched_parameters.empty?
            if @compile_time
              "expected '#{resource.to_s}' to be run at compile time, but was converge time"
            else
              "expected '#{resource.to_s}' to be run at converge time, but was compile time"
            end
          else
            "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
          "expected '#{resource.to_s}' actions #{resource.performed_actions.inspect}" \
          " to include ':#{@expected_action}'"
        end
      else
        "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_for_should_not
      if resource
        message = "expected '#{resource.to_s}' actions #{resource.performed_actions.inspect} to not exist"
      else
        message = "expected '#{resource.to_s}' to not exist"
      end

      message << " at compile time" if @compile_time
      message << " at converge time" if @converge_time
      message
    end

    def description
      "#{@expected_action} #{@resource_name}"
    end

    private
      def unmatched_parameters<commit_msg>Include expected identity in documentatin output (fixes #239)<commit_after>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 matches?(runner)
      @runner = runner

      if resource
        resource.performed_action?(@expected_action) && unmatched_parameters.empty? && correct_phase?
      else
        false
      end
    end

    def failure_message_for_should
      if resource
        if resource.performed_action?(@expected_action)
          if unmatched_parameters.empty?
            if @compile_time
              "expected '#{resource.to_s}' to be run at compile time, but was converge time"
            else
              "expected '#{resource.to_s}' to be run at converge time, but was compile time"
            end
          else
            "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
          "expected '#{resource.to_s}' actions #{resource.performed_actions.inspect}" \
          " to include ':#{@expected_action}'"
        end
      else
        "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_for_should_not
      if resource
        message = "expected '#{resource.to_s}' actions #{resource.performed_actions.inspect} to not exist"
      else
        message = "expected '#{resource.to_s}' to not exist"
      end

      message << " at compile time" if @compile_time
      message << " at converge time" if @converge_time
      message
    end

    def description
      "#{@expected_action} #{@resource_name} '#{@expected_identity}'"
    end

    private
      def unmatched_parameters
{'fraction_non_alphanumeric': 0.10278561354019747, 'fraction_numerical': 0.0008815232722143865, 'mean_word_length': 2.217810550198525, 'pattern_counts': {'":': 0, '<': 11, '<?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': '2877176', 'n_tokens_mistral': 1661, 'n_tokens_neox': 1631, 'n_words': 427}