From c41a10b395e229ce01e9cebf68a7e6e660cab413 Mon Sep 17 00:00:00 2001 From: Sylvain Joyeux Date: Wed, 13 Aug 2025 21:12:44 -0300 Subject: [PATCH 1/2] fix: display with_kw_args matchers in expectation description --- lib/flexmock/argument_matchers.rb | 15 ++++++++++++++- lib/flexmock/core_class_methods.rb | 12 ++++++++++++ lib/flexmock/expectation.rb | 1 + test/expectation_description_test.rb | 9 +++++++++ 4 files changed, 36 insertions(+), 1 deletion(-) diff --git a/lib/flexmock/argument_matchers.rb b/lib/flexmock/argument_matchers.rb index 9bf76d8..6671ce0 100644 --- a/lib/flexmock/argument_matchers.rb +++ b/lib/flexmock/argument_matchers.rb @@ -80,7 +80,20 @@ def ===(target) @expected.size == target.size end def inspect - "kw(#{@expected.inspect})" + args = @expected.map do |k, v| + k_s = case k + when Symbol + "#{k}: " + else + "#{k.inspect} => " + end + + v_s = FlexMock.forbid_mocking("") do + v.inspect + end + "#{k_s}#{v_s}" + end + args.join(", ") end end diff --git a/lib/flexmock/core_class_methods.rb b/lib/flexmock/core_class_methods.rb index 67d7b54..5f9bb80 100644 --- a/lib/flexmock/core_class_methods.rb +++ b/lib/flexmock/core_class_methods.rb @@ -97,6 +97,18 @@ def format_args(args) end end + # Class method to format a list of args (the part between the + # parenthesis). + def format_kw_args(args) + if args + FlexMock.forbid_mocking("") do + args.inspect + end + else + "**args" + end + end + # Check will assert the block returns true. If it doesn't, an # assertion failure is triggered with the given message. def check(msg, &block) # :nodoc: diff --git a/lib/flexmock/expectation.rb b/lib/flexmock/expectation.rb index 1b514d1..25add14 100644 --- a/lib/flexmock/expectation.rb +++ b/lib/flexmock/expectation.rb @@ -65,6 +65,7 @@ def to_s def description result = ["should_receive(#{@sym.inspect})"] result << ".with(#{FlexMock.format_args(@expected_args)})" if @expected_args + result << ".with_kw_args(#{FlexMock.format_kw_args(@expected_kw_args)})" if @expected_kw_args @count_validators.each do |validator| result << validator.describe end diff --git a/test/expectation_description_test.rb b/test/expectation_description_test.rb index 2e323b6..73704be 100644 --- a/test/expectation_description_test.rb +++ b/test/expectation_description_test.rb @@ -78,6 +78,15 @@ def test_with_at_least_1_at_most_10 assert_equal "should_receive(:foo).at_least.once.at_most.times(10)", @exp.description end + def test_with_kw_args + @exp.at_least.once.with_kw_args(a: 10, "b" => 20) + + description = <<~EOD + should_receive(:foo).with_kw_args(a: 10, "b" => 20).at_least.once + EOD + assert_equal description.chomp, @exp.description + end + def test_with_signature @exp.at_least.once.with_signature(required_arguments: 2, optional_arguments: 3, required_keyword_arguments: [:test], From 0d0d006834a1297c15016f6b7bbb3221b90e4a1c Mon Sep 17 00:00:00 2001 From: Sylvain Joyeux Date: Wed, 13 Aug 2025 21:13:19 -0300 Subject: [PATCH 2/2] fix: compare expected and actual keyword argument values with both === and == --- lib/flexmock/argument_matchers.rb | 5 ++++- test/should_receive_test.rb | 25 ++++++++++++++++++++++++- 2 files changed, 28 insertions(+), 2 deletions(-) diff --git a/lib/flexmock/argument_matchers.rb b/lib/flexmock/argument_matchers.rb index 6671ce0..dbbb70f 100644 --- a/lib/flexmock/argument_matchers.rb +++ b/lib/flexmock/argument_matchers.rb @@ -75,7 +75,10 @@ def initialize(expected) end def ===(target) return false unless target.kind_of?(Hash) - return false unless @expected.all? { |k, v| v === target[k] } + matching = @expected.all? do |k, v| + v === target[k] || v == target[k] + end + return false unless matching @expected.size == target.size end diff --git a/test/should_receive_test.rb b/test/should_receive_test.rb index 54fa51d..15d414c 100644 --- a/test/should_receive_test.rb +++ b/test/should_receive_test.rb @@ -439,13 +439,36 @@ def test_with_hash_non_matching end end - def test_with_kw_args_matching + def test_with_kw_args_matching_equality FlexMock.use('greeter') do |m| m.should_receive(:hi).with_kw_args(some: 10) m.hi(some: 10) end end + def test_with_kw_args_matching_with_case_operator + FlexMock.use('greeter') do |m| + m.should_receive(:hi).with_kw_args(some: 9..11) + m.hi(some: 10) + end + end + + def test_with_kw_args_matching_with_equality_operator + FlexMock.use('greeter') do |m| + m.should_receive(:hi).with_kw_args(some: 9..11) + m.hi(some: 9..11) + end + end + + def test_with_kw_args_matching_strictly_with_equality_with_the_eq_operator + assert_raises(FlexMock::CheckFailedError) do + FlexMock.use('greeter') do |m| + m.should_receive(:hi).with_kw_args(some: eq(9..11)) + m.hi(some: 10) + end + end + end + def test_with_kw_args_matches_values_separately FlexMock.use('greeter') do |m| m.should_receive(:hi).with_kw_args(a: on { |v| v == 1 }, b: 2).once