Repository: freerange/mocha (Ruby)

Issue:
Since #648 `has_entry` no longer matches by exact value
Since https://github.com/freerange/mocha/pull/648, `has_entry`'s behaviour changed:

```ruby
require "bundler/setup"
require "minitest/autorun"
require "mocha/minitest"
require "mocha/mock"

class FooTest < Minitest::Test
  def setup
    @mock = mock("foo")
  end

  def test_mocha_mocking_kw_args_with_has_entry
    @mock.expects(:bar).with(has_entry(:a, k: "v"))

    @mock.bar(a: { k: "v", extra: "extra" })
  end
end
```

In the versions before the linked PR the test above would fail because `{ k: "v", extra: "extra" }` is different than the expected `{k: "v"}`. But after that PR the test above succeeds.


Discussion: @ElvinEfendi Thanks for reporting this - sorry for the slow response - I've been away on leave. I'll take a look as soon as I can.
@ElvinEfendi

I've had an initial look at this and I agree that it is an accidental regression caused by #648.

Many thanks for supplying a test that reproduces the problem.

I've attempted a quick fix in #655.

If you get a chance, could you try out the code in the [`fix-has-entry-with-keyword-args-regression` branch](https://github.com/freerange/mocha/tree/fix-has-entry-with-keyword-args-regression) and see if it fixes your problem...?



Fix (patch):
diff --git a/lib/mocha/parameter_matchers/base.rb b/lib/mocha/parameter_matchers/base.rb
index 52725d70e..8c1fa22d8 100644
--- a/lib/mocha/parameter_matchers/base.rb
+++ b/lib/mocha/parameter_matchers/base.rb
@@ -2,11 +2,6 @@ module Mocha
   module ParameterMatchers
     # @abstract Subclass and implement +#matches?+ and +#mocha_inspect+ to define a custom matcher. Also add a suitably named instance method to {ParameterMatchers} to build an instance of the new matcher c.f. {#equals}.
     class Base
-      # @private
-      def to_matcher(_expectation = nil)
-        self
-      end
-
       # A shorthand way of combining two matchers when both must match.
       #
       # Returns a new {AllOf} parameter matcher combining two matchers using a logical AND.
diff --git a/lib/mocha/parameter_matchers/instance_methods.rb b/lib/mocha/parameter_matchers/instance_methods.rb
index 8b41464d4..d86da04fd 100644
--- a/lib/mocha/parameter_matchers/instance_methods.rb
+++ b/lib/mocha/parameter_matchers/instance_methods.rb
@@ -1,3 +1,4 @@
+require 'mocha/parameter_matchers/base'
 require 'mocha/parameter_matchers/equals'
 require 'mocha/parameter_matchers/positional_or_keyword_hash'
 
@@ -6,8 +7,14 @@ module ParameterMatchers
     # @private
     module InstanceMethods
       # @private
-      def to_matcher(_expectation = nil)
-        Mocha::ParameterMatchers::Equals.new(self)
+      def to_matcher(expectation: nil, top_level: false)
+        if is_a?(Base)
+          self
+        elsif is_a?(Hash) && top_level
+          Mocha::ParameterMatchers::PositionalOrKeywordHash.new(self, expectation)
+        else
+          Mocha::ParameterMatchers::Equals.new(self)
+        end
       end
     end
   end
@@ -17,11 +24,3 @@ def to_matcher(_expectation = nil)
 class Object
   include Mocha::ParameterMatchers::InstanceMethods
 end
-
-# @private
-class Hash
-  # @private
-  def to_matcher(expectation = nil)
-    Mocha::ParameterMatchers::PositionalOrKeywordHash.new(self, expectation)
-  end
-end
diff --git a/lib/mocha/parameters_matcher.rb b/lib/mocha/parameters_matcher.rb
index 6cd434294..72645fe61 100644
--- a/lib/mocha/parameters_matcher.rb
+++ b/lib/mocha/parameters_matcher.rb
@@ -28,7 +28,7 @@ def mocha_inspect
     end
 
     def matchers
-      @expected_parameters.map { |p| p.to_matcher(@expectation) }
+      @expected_parameters.map { |p| p.to_matcher(expectation: @expectation, top_level: true) }
     end
   end
 end