From b993756c9ab69e5c19af1ac81a231784455bcdc1 Mon Sep 17 00:00:00 2001 From: Karl Heitmann Date: Tue, 23 Apr 2024 22:51:01 -0400 Subject: [PATCH 01/11] Fix diff output when a fuzzy finder anything is inside an expected hash --- lib/rspec/support/differ.rb | 23 +++++++++++++++++++++-- spec/rspec/support/differ_spec.rb | 18 ++++++++++++++++++ 2 files changed, 39 insertions(+), 2 deletions(-) diff --git a/lib/rspec/support/differ.rb b/lib/rspec/support/differ.rb index 9488296ed..141132b9d 100644 --- a/lib/rspec/support/differ.rb +++ b/lib/rspec/support/differ.rb @@ -18,8 +18,12 @@ def diff(actual, expected) if any_multiline_strings?(actual, expected) diff = diff_as_string(coerce_to_string(actual), coerce_to_string(expected)) end - elsif no_procs?(actual, expected) && no_numbers?(actual, expected) - diff = diff_as_object(actual, expected) + elsif no_procs_and_no_numbers?(actual, expected) + if Hash === expected && hash_with_anything?(expected) + diff = diff_as_object_with_anything(actual, expected) + else + diff = diff_as_object(actual, expected) + end end end @@ -56,6 +60,13 @@ def diff_as_string(actual, expected) end # rubocop:enable Metrics/MethodLength + def diff_as_object_with_anything(actual, expected) + expected.select { |_, v| RSpec::Mocks::ArgumentMatchers::AnyArgMatcher === v }.each_key do |k| + expected[k] = actual[k] + end + diff_as_object(actual, expected) + end + def diff_as_object(actual, expected) actual_as_string = object_to_string(actual) expected_as_string = object_to_string(expected) @@ -73,6 +84,14 @@ def initialize(opts={}) private + def hash_with_anything?(arg) + safely_flatten(arg).any? { |a| RSpec::Mocks::ArgumentMatchers::AnyArgMatcher === a } + end + + def no_procs_and_no_numbers?(*args) + no_procs?(args) && no_numbers?(args) + end + def no_procs?(*args) safely_flatten(args).none? { |a| Proc === a } end diff --git a/spec/rspec/support/differ_spec.rb b/spec/rspec/support/differ_spec.rb index cbd1ed28f..04f1422ef 100644 --- a/spec/rspec/support/differ_spec.rb +++ b/spec/rspec/support/differ_spec.rb @@ -555,6 +555,24 @@ def inspect; ""; end expect(differ.diff(false, true)).to_not be_empty end end + + describe "fuzzy matcher anything" do + it "outputs only key value pair that triggered diff, anything_key should absorb actual value" do + actual = { :fixed => "fixed", :trigger => "trigger", :anything_key => "bcdd0399-1cfe-4de1-a481-ca6b17d41ed8" } + expected = { :fixed => "fixed", :trigger => "wrong", :anything_key => anything } + diff = differ.diff(actual, expected) + expected_diff = dedent(<<-'EOD') + | + |@@ -1,4 +1,4 @@ + | :anything_key => "bcdd0399-1cfe-4de1-a481-ca6b17d41ed8", + | :fixed => "fixed", + |-:trigger => "wrong", + |+:trigger => "trigger", + | + EOD + expect(diff).to be_diffed_as(expected_diff) + end + end end end end From 4c22e70a08ae289453b70128c54cbd5ac0246a48 Mon Sep 17 00:00:00 2001 From: Karl Heitmann Date: Sat, 25 May 2024 18:21:20 -0400 Subject: [PATCH 02/11] Add code review feedback, this feat works only ruby version > 1.8.7 --- lib/rspec/support/differ.rb | 4 ++-- spec/rspec/support/differ_spec.rb | 33 +++++++++++++++++-------------- 2 files changed, 20 insertions(+), 17 deletions(-) diff --git a/lib/rspec/support/differ.rb b/lib/rspec/support/differ.rb index 141132b9d..5705e3217 100644 --- a/lib/rspec/support/differ.rb +++ b/lib/rspec/support/differ.rb @@ -19,7 +19,7 @@ def diff(actual, expected) diff = diff_as_string(coerce_to_string(actual), coerce_to_string(expected)) end elsif no_procs_and_no_numbers?(actual, expected) - if Hash === expected && hash_with_anything?(expected) + if (RUBY_VERSION.to_f > 1.8) && hash_with_anything?(expected) diff = diff_as_object_with_anything(actual, expected) else diff = diff_as_object(actual, expected) @@ -85,7 +85,7 @@ def initialize(opts={}) private def hash_with_anything?(arg) - safely_flatten(arg).any? { |a| RSpec::Mocks::ArgumentMatchers::AnyArgMatcher === a } + Hash === arg && safely_flatten(arg).any? { |a| RSpec::Mocks::ArgumentMatchers::AnyArgMatcher === a } end def no_procs_and_no_numbers?(*args) diff --git a/spec/rspec/support/differ_spec.rb b/spec/rspec/support/differ_spec.rb index 04f1422ef..90f6bb947 100644 --- a/spec/rspec/support/differ_spec.rb +++ b/spec/rspec/support/differ_spec.rb @@ -556,21 +556,24 @@ def inspect; ""; end end end - describe "fuzzy matcher anything" do - it "outputs only key value pair that triggered diff, anything_key should absorb actual value" do - actual = { :fixed => "fixed", :trigger => "trigger", :anything_key => "bcdd0399-1cfe-4de1-a481-ca6b17d41ed8" } - expected = { :fixed => "fixed", :trigger => "wrong", :anything_key => anything } - diff = differ.diff(actual, expected) - expected_diff = dedent(<<-'EOD') - | - |@@ -1,4 +1,4 @@ - | :anything_key => "bcdd0399-1cfe-4de1-a481-ca6b17d41ed8", - | :fixed => "fixed", - |-:trigger => "wrong", - |+:trigger => "trigger", - | - EOD - expect(diff).to be_diffed_as(expected_diff) + unless RUBY_VERSION == '1.8.7' + describe "fuzzy matcher anything" do + it "outputs only key value pair that triggered diff, anything_key should absorb actual value" do + actual = { :fixed => "fixed", :trigger => "trigger", :anything_key => "bcdd0399-1cfe-4de1-a481-ca6b17d41ed8" } + expected = { :fixed => "fixed", :trigger => "wrong", :anything_key => anything } + diff = differ.diff(actual, expected) + expected_diff = dedent(<<-'EOD') + | + |@@ -1,4 +1,4 @@ + | :anything_key => "bcdd0399-1cfe-4de1-a481-ca6b17d41ed8", + | :fixed => "fixed", + |-:trigger => "wrong", + |+:trigger => "trigger", + | + EOD + # puts diff + expect(diff).to be_diffed_as(expected_diff) + end end end end From 048ac0ab5169f42467ca40d58c6a1464f4a940b4 Mon Sep 17 00:00:00 2001 From: Karl Heitmann Date: Thu, 30 May 2024 01:17:12 -0400 Subject: [PATCH 03/11] simplifies no_procs? and no_numbers? by removing star operator --- lib/rspec/support/differ.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/rspec/support/differ.rb b/lib/rspec/support/differ.rb index 5705e3217..dd4373993 100644 --- a/lib/rspec/support/differ.rb +++ b/lib/rspec/support/differ.rb @@ -92,7 +92,7 @@ def no_procs_and_no_numbers?(*args) no_procs?(args) && no_numbers?(args) end - def no_procs?(*args) + def no_procs?(args) safely_flatten(args).none? { |a| Proc === a } end @@ -104,7 +104,7 @@ def any_multiline_strings?(*args) all_strings?(*args) && safely_flatten(args).any? { |a| multiline?(a) } end - def no_numbers?(*args) + def no_numbers?(args) safely_flatten(args).none? { |a| Numeric === a } end From c3e9ea926463829a048a131f7b85fef16c186ef5 Mon Sep 17 00:00:00 2001 From: Karl Heitmann Date: Sat, 8 Jun 2024 17:21:09 -0400 Subject: [PATCH 04/11] introduces Differ#all_hashes to check actual and expected are Hash --- lib/rspec/support/differ.rb | 26 ++++++++++-------------- spec/rspec/support/differ_spec.rb | 33 ++++++++++++++----------------- 2 files changed, 25 insertions(+), 34 deletions(-) diff --git a/lib/rspec/support/differ.rb b/lib/rspec/support/differ.rb index dd4373993..2ef5d437e 100644 --- a/lib/rspec/support/differ.rb +++ b/lib/rspec/support/differ.rb @@ -18,12 +18,10 @@ def diff(actual, expected) if any_multiline_strings?(actual, expected) diff = diff_as_string(coerce_to_string(actual), coerce_to_string(expected)) end - elsif no_procs_and_no_numbers?(actual, expected) - if (RUBY_VERSION.to_f > 1.8) && hash_with_anything?(expected) - diff = diff_as_object_with_anything(actual, expected) - else - diff = diff_as_object(actual, expected) - end + elsif all_hashes?(actual, expected) + diff = diff_hashes_as_object(actual, expected) + elsif no_procs?(actual, expected) && no_numbers?(actual, expected) + diff = diff_as_object(actual, expected) end end @@ -60,7 +58,7 @@ def diff_as_string(actual, expected) end # rubocop:enable Metrics/MethodLength - def diff_as_object_with_anything(actual, expected) + def diff_hashes_as_object(actual, expected) expected.select { |_, v| RSpec::Mocks::ArgumentMatchers::AnyArgMatcher === v }.each_key do |k| expected[k] = actual[k] end @@ -84,16 +82,12 @@ def initialize(opts={}) private - def hash_with_anything?(arg) - Hash === arg && safely_flatten(arg).any? { |a| RSpec::Mocks::ArgumentMatchers::AnyArgMatcher === a } - end - - def no_procs_and_no_numbers?(*args) - no_procs?(args) && no_numbers?(args) + def no_procs?(*args) + safely_flatten(args).none? { |a| Proc === a } end - def no_procs?(args) - safely_flatten(args).none? { |a| Proc === a } + def all_hashes?(actual, expected) + defined?(RSpec::Mocks::ArgumentMatchers::AnyArgMatcher) && (Hash === actual) && (Hash === expected) end def all_strings?(*args) @@ -104,7 +98,7 @@ def any_multiline_strings?(*args) all_strings?(*args) && safely_flatten(args).any? { |a| multiline?(a) } end - def no_numbers?(args) + def no_numbers?(*args) safely_flatten(args).none? { |a| Numeric === a } end diff --git a/spec/rspec/support/differ_spec.rb b/spec/rspec/support/differ_spec.rb index 90f6bb947..04f1422ef 100644 --- a/spec/rspec/support/differ_spec.rb +++ b/spec/rspec/support/differ_spec.rb @@ -556,24 +556,21 @@ def inspect; ""; end end end - unless RUBY_VERSION == '1.8.7' - describe "fuzzy matcher anything" do - it "outputs only key value pair that triggered diff, anything_key should absorb actual value" do - actual = { :fixed => "fixed", :trigger => "trigger", :anything_key => "bcdd0399-1cfe-4de1-a481-ca6b17d41ed8" } - expected = { :fixed => "fixed", :trigger => "wrong", :anything_key => anything } - diff = differ.diff(actual, expected) - expected_diff = dedent(<<-'EOD') - | - |@@ -1,4 +1,4 @@ - | :anything_key => "bcdd0399-1cfe-4de1-a481-ca6b17d41ed8", - | :fixed => "fixed", - |-:trigger => "wrong", - |+:trigger => "trigger", - | - EOD - # puts diff - expect(diff).to be_diffed_as(expected_diff) - end + describe "fuzzy matcher anything" do + it "outputs only key value pair that triggered diff, anything_key should absorb actual value" do + actual = { :fixed => "fixed", :trigger => "trigger", :anything_key => "bcdd0399-1cfe-4de1-a481-ca6b17d41ed8" } + expected = { :fixed => "fixed", :trigger => "wrong", :anything_key => anything } + diff = differ.diff(actual, expected) + expected_diff = dedent(<<-'EOD') + | + |@@ -1,4 +1,4 @@ + | :anything_key => "bcdd0399-1cfe-4de1-a481-ca6b17d41ed8", + | :fixed => "fixed", + |-:trigger => "wrong", + |+:trigger => "trigger", + | + EOD + expect(diff).to be_diffed_as(expected_diff) end end end From 416cd49be56c5394ab49ff712cf8bea78b4e7abd Mon Sep 17 00:00:00 2001 From: Karl Heitmann Date: Sat, 8 Jun 2024 21:59:44 -0400 Subject: [PATCH 05/11] if AnyArgMatcher is defined, diff_hashes_as_object folds anything --- lib/rspec/support/differ.rb | 21 ++++++++++++++++++--- spec/rspec/support/differ_spec.rb | 6 ++++++ 2 files changed, 24 insertions(+), 3 deletions(-) diff --git a/lib/rspec/support/differ.rb b/lib/rspec/support/differ.rb index 2ef5d437e..fba799293 100644 --- a/lib/rspec/support/differ.rb +++ b/lib/rspec/support/differ.rb @@ -59,10 +59,25 @@ def diff_as_string(actual, expected) # rubocop:enable Metrics/MethodLength def diff_hashes_as_object(actual, expected) - expected.select { |_, v| RSpec::Mocks::ArgumentMatchers::AnyArgMatcher === v }.each_key do |k| - expected[k] = actual[k] + if defined?(RSpec::Mocks::ArgumentMatchers::AnyArgMatcher) + anything_hash = expected.select { |_, v| RSpec::Mocks::ArgumentMatchers::AnyArgMatcher === v } + + anything_hash.each_key do |k| + expected[k] = actual[k] + end + + diff_string = diff_as_object(actual, expected) + + if defined?(RSpec::Mocks::ArgumentMatchers::AnyArgMatcher) + anything_hash.each do |k, v| + expected[k] = v + end + end + + diff_string + else + diff_as_object(actual, expected) end - diff_as_object(actual, expected) end def diff_as_object(actual, expected) diff --git a/spec/rspec/support/differ_spec.rb b/spec/rspec/support/differ_spec.rb index 04f1422ef..38e0a61a7 100644 --- a/spec/rspec/support/differ_spec.rb +++ b/spec/rspec/support/differ_spec.rb @@ -572,6 +572,12 @@ def inspect; ""; end EOD expect(diff).to be_diffed_as(expected_diff) end + it "checks the 'expected' var continues having the 'anything' fuzzy matcher, it has not mutated" do + actual = { :fixed => "fixed", :trigger => "trigger", :anything_key => "bcdd0399-1cfe-4de1-a481-ca6b17d41ed8" } + expected = { :fixed => "fixed", :trigger => "wrong", :anything_key => anything } + differ.diff(actual, expected) + expect(expected).to eq({ :fixed => "fixed", :trigger => "wrong", :anything_key => anything }) + end end end end From 0dea76973799b5f9b1381722a0510a86dcbea1ea Mon Sep 17 00:00:00 2001 From: Karl Heitmann Date: Tue, 11 Jun 2024 22:44:17 -0400 Subject: [PATCH 06/11] fix: removed unnecesary rspec-mock check --- lib/rspec/support/differ.rb | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/lib/rspec/support/differ.rb b/lib/rspec/support/differ.rb index fba799293..ba832fd7e 100644 --- a/lib/rspec/support/differ.rb +++ b/lib/rspec/support/differ.rb @@ -68,10 +68,8 @@ def diff_hashes_as_object(actual, expected) diff_string = diff_as_object(actual, expected) - if defined?(RSpec::Mocks::ArgumentMatchers::AnyArgMatcher) - anything_hash.each do |k, v| - expected[k] = v - end + anything_hash.each do |k, v| + expected[k] = v end diff_string From 31f086ec4df181e89e9bd1199c728971168d04d4 Mon Sep 17 00:00:00 2001 From: Karl Heitmann Date: Fri, 14 Jun 2024 23:03:56 -0400 Subject: [PATCH 07/11] applied code review feedback: removed defined? check and use reduce --- lib/rspec/support/differ.rb | 24 +++++++++++------------- spec/rspec/support/differ_spec.rb | 1 + 2 files changed, 12 insertions(+), 13 deletions(-) diff --git a/lib/rspec/support/differ.rb b/lib/rspec/support/differ.rb index ba832fd7e..b2afa6881 100644 --- a/lib/rspec/support/differ.rb +++ b/lib/rspec/support/differ.rb @@ -60,19 +60,17 @@ def diff_as_string(actual, expected) def diff_hashes_as_object(actual, expected) if defined?(RSpec::Mocks::ArgumentMatchers::AnyArgMatcher) - anything_hash = expected.select { |_, v| RSpec::Mocks::ArgumentMatchers::AnyArgMatcher === v } - - anything_hash.each_key do |k| - expected[k] = actual[k] - end - - diff_string = diff_as_object(actual, expected) - - anything_hash.each do |k, v| - expected[k] = v - end + expected_to_diff = + expected.reduce({}) do |hash, (key, value)| + if RSpec::Mocks::ArgumentMatchers::AnyArgMatcher === value + hash[key] = actual[key] + else + hash[key] = expected[key] + end + hash + end - diff_string + diff_as_object(actual, expected_to_diff) else diff_as_object(actual, expected) end @@ -100,7 +98,7 @@ def no_procs?(*args) end def all_hashes?(actual, expected) - defined?(RSpec::Mocks::ArgumentMatchers::AnyArgMatcher) && (Hash === actual) && (Hash === expected) + (Hash === actual) && (Hash === expected) end def all_strings?(*args) diff --git a/spec/rspec/support/differ_spec.rb b/spec/rspec/support/differ_spec.rb index 38e0a61a7..1232dc881 100644 --- a/spec/rspec/support/differ_spec.rb +++ b/spec/rspec/support/differ_spec.rb @@ -572,6 +572,7 @@ def inspect; ""; end EOD expect(diff).to be_diffed_as(expected_diff) end + it "checks the 'expected' var continues having the 'anything' fuzzy matcher, it has not mutated" do actual = { :fixed => "fixed", :trigger => "trigger", :anything_key => "bcdd0399-1cfe-4de1-a481-ca6b17d41ed8" } expected = { :fixed => "fixed", :trigger => "wrong", :anything_key => anything } From dd7a4c7e169e17323671571b6e19c301e99da0fa Mon Sep 17 00:00:00 2001 From: Karl Heitmann Date: Fri, 14 Jun 2024 23:26:44 -0400 Subject: [PATCH 08/11] code review feedback: defines `diff_hashes_as_object` conditionally --- lib/rspec/support/differ.rb | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/lib/rspec/support/differ.rb b/lib/rspec/support/differ.rb index b2afa6881..51d83c0b3 100644 --- a/lib/rspec/support/differ.rb +++ b/lib/rspec/support/differ.rb @@ -58,8 +58,8 @@ def diff_as_string(actual, expected) end # rubocop:enable Metrics/MethodLength - def diff_hashes_as_object(actual, expected) - if defined?(RSpec::Mocks::ArgumentMatchers::AnyArgMatcher) + if defined?(RSpec::Mocks::ArgumentMatchers::AnyArgMatcher) + def diff_hashes_as_object(actual, expected) expected_to_diff = expected.reduce({}) do |hash, (key, value)| if RSpec::Mocks::ArgumentMatchers::AnyArgMatcher === value @@ -71,7 +71,9 @@ def diff_hashes_as_object(actual, expected) end diff_as_object(actual, expected_to_diff) - else + end + else + def diff_hashes_as_object(actual, expected) diff_as_object(actual, expected) end end From 938096ccb8d80289aec89d0758e0dc93ee1093f1 Mon Sep 17 00:00:00 2001 From: Karl Heitmann Date: Sat, 15 Jun 2024 21:19:54 -0400 Subject: [PATCH 09/11] Changes Differ by "Differ" to load AnyArgMatcher before loading Differ --- spec/rspec/support/differ_spec.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/rspec/support/differ_spec.rb b/spec/rspec/support/differ_spec.rb index 1232dc881..1ab291a3f 100644 --- a/spec/rspec/support/differ_spec.rb +++ b/spec/rspec/support/differ_spec.rb @@ -6,7 +6,7 @@ module RSpec module Support - RSpec.describe Differ do + RSpec.describe "Differ" do include Spec::DiffHelpers describe '#diff' do From 7046659939172d8e4ae0795223e8aea6353916fd Mon Sep 17 00:00:00 2001 From: Karl Heitmann Date: Wed, 26 Jun 2024 23:56:09 -0400 Subject: [PATCH 10/11] code review feedback: invert expected_to_diff to actual_to_diff --- lib/rspec/support/differ.rb | 13 ++++++------- spec/rspec/support/differ_spec.rb | 2 +- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/lib/rspec/support/differ.rb b/lib/rspec/support/differ.rb index 51d83c0b3..83d135da4 100644 --- a/lib/rspec/support/differ.rb +++ b/lib/rspec/support/differ.rb @@ -60,17 +60,16 @@ def diff_as_string(actual, expected) if defined?(RSpec::Mocks::ArgumentMatchers::AnyArgMatcher) def diff_hashes_as_object(actual, expected) - expected_to_diff = - expected.reduce({}) do |hash, (key, value)| - if RSpec::Mocks::ArgumentMatchers::AnyArgMatcher === value - hash[key] = actual[key] - else + actual_to_diff = + actual.reduce({}) do |hash, (key, value)| + if RSpec::Mocks::ArgumentMatchers::AnyArgMatcher === expected[key] hash[key] = expected[key] + else + hash[key] = actual[key] end hash end - - diff_as_object(actual, expected_to_diff) + diff_as_object(actual_to_diff, expected) end else def diff_hashes_as_object(actual, expected) diff --git a/spec/rspec/support/differ_spec.rb b/spec/rspec/support/differ_spec.rb index 1ab291a3f..1a7450069 100644 --- a/spec/rspec/support/differ_spec.rb +++ b/spec/rspec/support/differ_spec.rb @@ -564,7 +564,7 @@ def inspect; ""; end expected_diff = dedent(<<-'EOD') | |@@ -1,4 +1,4 @@ - | :anything_key => "bcdd0399-1cfe-4de1-a481-ca6b17d41ed8", + | :anything_key => anything, | :fixed => "fixed", |-:trigger => "wrong", |+:trigger => "trigger", From 6b7ff69299e2b1470819dfaf25d1b7cd0ea66c85 Mon Sep 17 00:00:00 2001 From: Phil Pirozhkov Date: Thu, 27 Jun 2024 12:45:27 +0300 Subject: [PATCH 11/11] Update lib/rspec/support/differ.rb Co-authored-by: Jon Rowe --- lib/rspec/support/differ.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/rspec/support/differ.rb b/lib/rspec/support/differ.rb index 83d135da4..e63b63501 100644 --- a/lib/rspec/support/differ.rb +++ b/lib/rspec/support/differ.rb @@ -61,7 +61,7 @@ def diff_as_string(actual, expected) if defined?(RSpec::Mocks::ArgumentMatchers::AnyArgMatcher) def diff_hashes_as_object(actual, expected) actual_to_diff = - actual.reduce({}) do |hash, (key, value)| + actual.keys.reduce({}) do |hash, key| if RSpec::Mocks::ArgumentMatchers::AnyArgMatcher === expected[key] hash[key] = expected[key] else