From e7303e923d2e11c368e5394644d3255abe1a3b02 Mon Sep 17 00:00:00 2001 From: David Chelimsky Date: Sat, 4 Sep 2010 17:23:10 -0500 Subject: [PATCH] Make eq and eql matchers diffable and clean up when to/not diff --- features/expectations/diffing.feature | 60 +++++++++++++++++++++ lib/rspec/expectations/fail_with.rb | 6 ++- lib/rspec/matchers/eq.rb | 3 ++ lib/rspec/matchers/eql.rb | 3 ++ spec/rspec/expectations/fail_with_spec.rb | 65 ++++++++++++++++------- spec/rspec/matchers/eq_spec.rb | 4 ++ spec/rspec/matchers/eql_spec.rb | 4 ++ 7 files changed, 125 insertions(+), 20 deletions(-) create mode 100644 features/expectations/diffing.feature diff --git a/features/expectations/diffing.feature b/features/expectations/diffing.feature new file mode 100644 index 000000000..0e1db529b --- /dev/null +++ b/features/expectations/diffing.feature @@ -0,0 +1,60 @@ +Feature: diffing + + When appropriate, failure messages will automatically include a diff. + + Scenario: diff for a multiline string + Given a file named "example_spec.rb" with: + """ + describe "a multiline string" do + it "is like another string" do + expected = <<-EXPECTED + this is the + expected + string + EXPECTED + actual = <<-ACTUAL + this is the + actual + string + ACTUAL + actual.should eq(expected) + end + end + """ + When I run "rspec example_spec.rb" + Then the output should contain: + """ + Diff: + @@ -1,4 +1,4 @@ + this is the + - expected + + actual + string + # ./example_spec.rb:13 + """ + + Scenario: no diff for a single line strings + Given a file named "example_spec.rb" with: + """ + describe "a single line string" do + it "is like another string" do + expected = "this string" + actual = "that string" + actual.should eq(expected) + end + end + """ + When I run "rspec example_spec.rb" + Then the output should not contain "Diff:" + + Scenario: no diff for numbers + Given a file named "example_spec.rb" with: + """ + describe "a number" do + it "is like another number" do + 1.should eq(2) + end + end + """ + When I run "rspec example_spec.rb" + Then the output should not contain "Diff:" diff --git a/lib/rspec/expectations/fail_with.rb b/lib/rspec/expectations/fail_with.rb index a0d46bc5b..c3b03e3ea 100644 --- a/lib/rspec/expectations/fail_with.rb +++ b/lib/rspec/expectations/fail_with.rb @@ -21,7 +21,7 @@ def fail_with(message, expected=nil, actual=nil) # :nodoc: if any_multiline_strings?(actual, expected) message << "\nDiff:" << self.differ.diff_as_string(actual, expected) end - elsif no_procs?(actual, expected) + elsif no_procs?(actual, expected) && no_numbers?(actual, expected) message << "\nDiff:" << self.differ.diff_as_object(actual, expected) end end @@ -42,6 +42,10 @@ def all_strings?(*args) def any_multiline_strings?(*args) all_strings?(*args) && args.any? {|a| a =~ /\n/} end + + def no_numbers?(*args) + args.none? {|a| Numeric === a} + end end end end diff --git a/lib/rspec/matchers/eq.rb b/lib/rspec/matchers/eq.rb index 1540b010e..95a012173 100644 --- a/lib/rspec/matchers/eq.rb +++ b/lib/rspec/matchers/eq.rb @@ -14,6 +14,9 @@ module Matchers # 5.should_not eq(3) def eq(expected) Matcher.new :eq, expected do |_expected_| + + diffable + match do |actual| actual == _expected_ end diff --git a/lib/rspec/matchers/eql.rb b/lib/rspec/matchers/eql.rb index 26dc51875..574386be6 100644 --- a/lib/rspec/matchers/eql.rb +++ b/lib/rspec/matchers/eql.rb @@ -14,6 +14,9 @@ module Matchers # 5.should_not eql(3) def eql(expected) Matcher.new :eql, expected do |_expected_| + + diffable + match do |actual| actual.eql?(_expected_) end diff --git a/spec/rspec/expectations/fail_with_spec.rb b/spec/rspec/expectations/fail_with_spec.rb index aae8768e2..84646e27e 100644 --- a/spec/rspec/expectations/fail_with_spec.rb +++ b/spec/rspec/expectations/fail_with_spec.rb @@ -6,35 +6,62 @@ before(:each) do RSpec::Expectations.stub(:differ) { differ } end - + + it "calls differ if expected/actual are not strings (or numbers or procs)" do + differ.should_receive(:diff_as_object).and_return("diff") + lambda { + RSpec::Expectations.fail_with "the message", Object.new, Object.new + }.should fail_with("the message\nDiff:diff") + end + + context "with two strings" do + context "and actual is multiline" do + it "calls differ" do + differ.should_receive(:diff_as_string).and_return("diff") + lambda { + RSpec::Expectations.fail_with "the message", "expected\nthis", "actual" + }.should fail_with("the message\nDiff:diff") + end + end + + context "and expected is multiline" do + it "calls differ" do + differ.should_receive(:diff_as_string).and_return("diff") + lambda { + RSpec::Expectations.fail_with "the message", "expected", "actual\nthat" + }.should fail_with("the message\nDiff:diff") + end + end + + context "and both are single line strings" do + it "does not call differ" do + differ.should_not_receive(:diff_as_string) + lambda { + RSpec::Expectations.fail_with("the message", "expected", "actual") + }.should fail_with("the message") + end + end + end + it "does not call differ if no expected/actual" do lambda { RSpec::Expectations.fail_with "the message" }.should fail_with("the message") end - - it "calls differ if expected/actual are presented separately" do - differ.should_receive(:diff_as_string).and_return("diff") + + it "does not call differ expected is Numeric" do lambda { - RSpec::Expectations.fail_with "the message", "expected\nthis", "actual" - }.should fail_with("the message\nDiff:diff") - end - - it "does not call differ if expected/actual are single line strings" do - differ.should_not_receive(:diff_as_string) - RSpec::Expectations.fail_with("the message", "expected", "actual") rescue nil + RSpec::Expectations.fail_with "the message", 1, "1" + }.should fail_with("the message") end - - it "calls differ if expected/actual are not strings" do - differ.should_receive(:diff_as_object).and_return("diff") + + it "does not call differ when actual is Numeric" do lambda { - RSpec::Expectations.fail_with "the message", Object.new, Object.new - }.should fail_with("the message\nDiff:diff") + RSpec::Expectations.fail_with "the message", "1", 1 + }.should fail_with("the message") end - + it "does not call differ if expected or actual are procs" do - differ.should_not_receive(:diff_as_string) - differ.should_not_receive(:diff_as_object) lambda { RSpec::Expectations.fail_with "the message", lambda {}, lambda {} }.should fail_with("the message") diff --git a/spec/rspec/matchers/eq_spec.rb b/spec/rspec/matchers/eq_spec.rb index 7875db5ff..aa558c24b 100644 --- a/spec/rspec/matchers/eq_spec.rb +++ b/spec/rspec/matchers/eq_spec.rb @@ -3,6 +3,10 @@ module RSpec module Matchers describe "eq" do + it "is diffable" do + eq(1).should be_diffable + end + it "matches when actual == expected" do 1.should eq(1) end diff --git a/spec/rspec/matchers/eql_spec.rb b/spec/rspec/matchers/eql_spec.rb index 2ef614d30..f7c3bae2e 100644 --- a/spec/rspec/matchers/eql_spec.rb +++ b/spec/rspec/matchers/eql_spec.rb @@ -3,6 +3,10 @@ module RSpec module Matchers describe "eql" do + it "is diffable" do + eql(1).should be_diffable + end + it "matches when actual.eql?(expected)" do 1.should eql(1) end