-
-
Notifications
You must be signed in to change notification settings - Fork 395
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Prevent Aliased Matchers from Overriding Expected Data #1116
base: main
Are you sure you want to change the base?
Prevent Aliased Matchers from Overriding Expected Data #1116
Conversation
The aliased matcher implementation of a description currently replaces all instance of the old matcher's name with the new matcher's name. However, in cases where the expected value has the same string as the old matcher's name, it would also get replaced. This change makes it so only the first instance of the old matcher's name is replaced in the description.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for tackling this, a bit of feedback above!
lib/rspec/matchers/dsl.rb
Outdated
@@ -29,7 +29,7 @@ module DSL | |||
# @see RSpec::Matchers | |||
def alias_matcher(new_name, old_name, options={}, &description_override) | |||
description_override ||= lambda do |old_desc| | |||
old_desc.gsub(EnglishPhrasing.split_words(old_name), EnglishPhrasing.split_words(new_name)) | |||
old_desc.sub(EnglishPhrasing.split_words(old_name), EnglishPhrasing.split_words(new_name)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this needs to only match the start of the string, this might still accidentally override terms if the original description is not generated.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the feedback! Can you clarify this a bit? #sub
matches the first occurrence, so are you saying something like matching the first n characters of the string?
Also, what do you mean by if the original description is not generated? Since BaseMatcher
implements description, I would think that they all would have a description. Unless a class implements its own description which does not contain the name of the matcher.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you clarify this a bit? #sub matches the first occurrence, so are you saying something like matching the first n characters of the string?
"hello_old_name".sub("old_name","new_name")
would produce "hello_new_name"
but we don't want that. We only want to replace old_name
as it was generated initially.
Also, what do you mean by if the original description is not generated? Since BaseMatcher implements description, I would think that they all would have a description.
Similarly it is possible for matchers to implement description
themselves and it might mean they don't contain the old_name at all, in this case we shouldn't be replacing the first instance blindly as it might not be in the description but in the expected.
|
||
it 'does not override data in the description with the same name as the matcher' do | ||
matcher = my_repeating_override | ||
expect(matcher.description).to eq("my repeating override my repeating base matcher") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It'd prefer a practical example showing the problem using fail_with
, even the one from rspec/rspec-rails#1835 would suffice.
8279d26
to
7e54f1f
Compare
A flag was added when generating an aliased matcher's description to better control how the old matcher's name is replaced. However, this broke the existing API for overriding a matcher's new description. This class allows to maintain backwards compatability gracefully.
old_desc | ||
end | ||
end | ||
end |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is a lot of added complication, and still doesn't remove the global sub in favour of a "start of string only" replace.
Do you have any questions on how to proceed with this @lnestor ? |
@lnestor Are you interested in wrapping this up? |
Previous Behavior
The aliased matcher implementation of a description currently replaces all instance of the old matcher's name in the new matcher's name. If it happens that the expected values include the old matcher's name, these also get overwritten. In the examples below, the string
"include"
is replaced in both the outputs by the new matcher's name.New Behavior
This change makes it so it only replaces the first instance of the original name so none of the expected data is also overwritten. The two above error outputs would be the following:
expected {} to match (a hash including {:my_string => "a string with 'include'"})
expected "some random string" to match (a string including "a string with 'include'")
I saw this in rspec/rspec-rails#1835.