Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

Loading…

Fixup issue with multiline diffs in custom matchers. #423

Merged
merged 2 commits into from

2 participants

Jon Rowe Myron Marston
Jon Rowe
Owner

Fix #420 by not forcing expected to be an array in custom matchers.

Jon Rowe
Owner

I''d like a review on this to make sure its a sensible strategy for solving this problem. /cc @myronmarston

Myron Marston

Yep, planning to review this tonight. I'm out most of the afternoon.

lib/rspec/matchers/dsl.rb
@@ -287,7 +287,13 @@ class Matcher
def initialize(name, declarations, *expected)
@name = name
@actual = nil
- @expected = expected
+ if expected.size == 1
+ @no_array = true
+ @expected = expected[0]
+ else
+ @no_array = false
Myron Marston Owner

What is @no_array meant to be used for? I see it set here but never used again.

Jon Rowe Owner
JonRowe added a note

Was for something that later proved unnecessary...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Myron Marston myronmarston commented on the diff
spec/rspec/matchers/dsl_spec.rb
@@ -322,7 +322,12 @@ def foo
it "provides expected" do
matcher = new_matcher(:name, "expected string") { }
- expect(matcher.expected).to eq ['expected string']
+ expect(matcher.expected).to eq 'expected string'
Myron Marston Owner

As you've shown here, this is a breaking change, so if we go this route, we'll need to provide a deprecation warning on 2.99 when #expected is called and it's an array of 1 element.

Jon Rowe Owner
JonRowe added a note

None of the other matchers behave like this, but I guess you're right it could affect people reliant on this quirky behaviour, I'll add a 2.99 deprecation warning after this is merged.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Myron Marston

This looks like a reasonable fix, although it doesn't demonstrate adequately that it fixes the diff issue since there's no spec here demonstrating that the diff is the same for a custom matcher as for a matcher like eq. What do you think of bringing over the spec I wrote up in #420? That would help demonstrate this fixes the bug and also guard against future regressions since the diffing behavior of custom matchers is an important behavior to maintain in future releases.

Jon Rowe
Owner

Added a spec, it's not quite as simple as proposed in #420 cause ASCII control codes...

Myron Marston

LGTM.

Jon Rowe
Owner

I'd like to hold off till I get a chance to look at the behaviour of expected/actual a bit more actually, I got a weird diff with true/false when playing around with the sample custom matcher.

Myron Marston

What's an example of where this produces a weird diff?

Jon Rowe
Owner

Did you get a chance to look at the weird diff?

Myron Marston

Not yet, sorry, thanks for the reminder.

Jon Rowe
Owner

Ping?

Myron Marston
Owner

So, looking at your example, I think the diff from before is weird, and the new behavior with this change (e.g. no diff) is correct. What do you think is weird about it?

Jon Rowe
Owner

I'm ok with the lack of diff on the true/false but note that the strings aren't being diffed either...

Myron Marston
Owner

I'm ok with the lack of diff on the true/false but note that the strings aren't being diffed either...

We only provide diffs when there are multiline strings involved:

https://github.com/rspec/rspec-expectations/blob/9003d2d7ef0c124f06f135a436d84c031947a608/lib/rspec/expectations/fail_with.rb#L24-L26

Your example did not provide multiline strings so I would not expect a diff.

Jon Rowe
Owner

Fair enough

Jon Rowe
Owner

Merging because the rbx build issue is separate.

Jon Rowe JonRowe merged commit 0a961b5 into from
Jon Rowe JonRowe deleted the branch
Myron Marston
Owner

You still planning to add a deprecation warning to 2.99 for this?

Jon Rowe
Owner

Yeah on my list

Jon Rowe JonRowe restored the branch
Jon Rowe JonRowe deleted the branch
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
This page is out of date. Refresh to see the latest.
Showing with 31 additions and 2 deletions.
  1. +5 −1 lib/rspec/matchers/dsl.rb
  2. +26 −1 spec/rspec/matchers/dsl_spec.rb
6 lib/rspec/matchers/dsl.rb
View
@@ -287,7 +287,11 @@ class Matcher
def initialize(name, declarations, *expected)
@name = name
@actual = nil
- @expected = expected
+ if expected.size == 1
+ @expected = expected[0]
+ else
+ @expected = expected
+ end
class << self
# See `Macros#define_user_override` above, for an explanation.
27 spec/rspec/matchers/dsl_spec.rb
View
@@ -306,6 +306,26 @@ def foo
expect(matcher).to be_diffable
end
+ it 'handles multiline string diffs' do
+ actual = "LINE1\nline2\n"
+ expected = "line1\nline2\n"
+
+ matcher = new_matcher(:custom_match, expected) do
+ match { |actual| actual == expected }
+ diffable
+ end
+
+ diff = nil
+ begin
+ allow(RSpec::Matchers.configuration).to receive(:color?).and_return(false)
+ expect(actual).to matcher
+ rescue RSpec::Expectations::ExpectationNotMetError => e
+ diff = e.message.sub(/\A.*Diff:/m, "Diff:").gsub(/^\s*/,'')
+ end
+
+ expect(diff).to eq "Diff:\n@@ -1,3 +1,3 @@\n-line1\n+LINE1\nline2\n"
+ end
+
it 'does not confuse the diffability of different matchers' do
# Necessary to guard against a regression that involved
# using a class variable to store the diffable state,
@@ -322,7 +342,12 @@ def foo
it "provides expected" do
matcher = new_matcher(:name, "expected string") { }
- expect(matcher.expected).to eq ['expected string']
+ expect(matcher.expected).to eq 'expected string'
Myron Marston Owner

As you've shown here, this is a breaking change, so if we go this route, we'll need to provide a deprecation warning on 2.99 when #expected is called and it's an array of 1 element.

Jon Rowe Owner
JonRowe added a note

None of the other matchers behave like this, but I guess you're right it could affect people reliant on this quirky behaviour, I'll add a 2.99 deprecation warning after this is merged.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
+ end
+
+ it "provides expected when there is more than one argument" do
+ matcher = new_matcher(:name, "expected string", "another arg") { }
+ expect(matcher.expected).to eq ['expected string', "another arg"]
end
it "provides actual when `match` is used" do
Something went wrong with that request. Please try again.