-
Notifications
You must be signed in to change notification settings - Fork 281
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
adding ability to check for smell message contents #732
adding ability to check for smell message contents #732
Conversation
ah, okay, totally should have rebased first ... |
052ee8f
to
a1ef382
Compare
match = true | ||
%i(message lines context source).each do |var| | ||
other_var = other_vars[var] | ||
match &= (send(var) == other_var) if other_var |
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.
Please check out "common_parameters_equal?" - this is rather the way to go.
thanks for the comments @troessner - we can do this - and I've done it, but it gives me 100+ errors through the rest of the code base where many other tests have to be updated stuff like: it 'reports one-letter variable name' do
src = 'def simple(fred) x = jim(45) end'
expect(src).to reek_of(:UncommunicativeVariableName, name: 'x' )
end to
I suspect it might take me an hour or so to work through all fixing those ... having made the change and got it basically working I'm keen to see it merged in, but there's a lot of overhead here :-) but good for me to familiarize myself with the rest of the codebase ... In the meantime here's the relevant code: def matches_smell_type?(klass)
smell_classes.include?(klass.to_s)
end
def matches_smell_details?(details = {})
details_equal?(details)
end
def matches?(klass, details = {})
matches_smell_type?(klass) && matches_smell_details?(details)
end
def details_equal?(other_details)
detail_keys = %i(message lines context source parameters)
other_details.keys.each do |key|
unless detail_keys.include?(key)
raise ArgumentError, "The detail #{key} you want to check for doesn't exist"
end
end
match = true
other_details.each do |other_key, other_value|
match &= (send(other_key) == other_value)
end
match
end I'm not so happy with the length of the details equal method, but well anyway, that's a stab at it - will see if I can get all the 100+ errors fixed up and give you a green build on this ... |
def matches_smell_details?(details = {})
details_equal?(details)
end
def matches?(klass, details = {})
matches_smell_type?(klass) && matches_smell_details?(details)
end AFAIS the "details_equal?" method is now just an unnecessary redirection - we can kill that and just use "matches_smell_details?" def details_equal?(other_details)
detail_keys = %i(message lines context source parameters)
other_details.keys.each do |key|
unless detail_keys.include?(key)
raise ArgumentError, "The detail #{key} you want to check for doesn't exist"
end
end
match = true
other_details.each do |other_key, other_value|
match &= (send(other_key) == other_value)
end
match
end Using "&=" always feels weird and is normally not necessary in Ruby. other_details.all? do |other_key, other_value|
send(other_key) == other_value
end and get rid of the whole "match" / boolean thingie. You normally never need booleans in combination with Enumerable's in ruby. Additionally, you need to cater to "parameters" in "details_equal?" which it doesn't seem to do anymore? |
thanks for those tips @troessner - I've incorporated them into the lastest code update - see what you think |
@@ -17,6 +17,8 @@ class SmellWarning | |||
attr_reader :context, :lines, :message, :parameters, :smell_detector, :source | |||
def_delegators :smell_detector, :smell_category, :smell_type | |||
|
|||
DETAIL_KEYS = %i(message lines context source parameters) |
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.
"details_key" is not really expressive - how about COMPARABLE_ATTRIBUTES ?
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.
We compare two things:
1.) "attributes": message lines context source parameters
and
2.) "parameters". This "attribute" has "keys". So let's use "keys" only in the context of "parameters", but not in the context of "attributes"
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.
Actually just see my comment directly below regarding "matches_smell_details?", that should make everthing clear ;)
thanks @troessner - have made some updates based on your suggestions. Take a look. I wasn't sure about putting the body of See how you like this latest variation |
end | ||
|
||
def matches?(klass, other_smell_details = {}) | ||
matches_smell_type?(klass) && matches_smell_details?(other_smell_details) |
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.
Let's also rename that to "attributes" here and below.
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.
done
Almost there - some small changes and then lets get this merged ;) |
@@ -87,30 +87,42 @@ | |||
end | |||
|
|||
context '#matches?' do | |||
let(:uncommunicative) do | |||
let(:uncomm) do |
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.
Why this change? "uncomm" is a really bad name, lets revert that.
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 was to avoid the lines getting too long ...
@tansaku please adress my latest comments and squash to one commit, then we can merge this bad boy ;) |
@troessner 2 of 3 addressed - pushing back on one (see above) - will squash once your satisfied :-) |
or should I squash in anticipation ... |
hmm, squashing much harder than I thought - complex conflicts in many more files - have made my way through them, but now stuck on two fails: 1) Reek::Spec::ShouldReekOf smell types and smell details smell type is matching but smell details are not sets the proper error message
Failure/Error: expect(matcher.failure_message).to\
expected "Expected string to reek of UncommunicativeVariableName, but it didn't" to match "Expected string to reek of UncommunicativeVariableName (which it did) with smell details {:parameters=>{:name=>\"x\"}}, which it didn't"
# ./spec/reek/spec/should_reek_of_spec.rb:110:in `block (4 levels) in <top (required)>'
2) Reek::Spec::ShouldReekOf smell types and smell details smell type is matching but smell details are not sets the proper error message when negated
Failure/Error: expect(matcher.failure_message_when_negated).to\
expected "Expected string not to reek of UncommunicativeVariableName, but it did" to match "Expected string not to reek of UncommunicativeVariableName with smell details {:parameters=>{:name=>\"x\"}}, but it did"
# ./spec/reek/spec/should_reek_of_spec.rb:118:in `block (4 levels) in <top (required)>'
Finished in 2.11 seconds (files took 1.03 seconds to load)
804 examples, 2 failures
which seem to relate to changes in def matches?(actual)
self.examiner = Examiner.new(actual, configuration: configuration)
set_failure_messages
matching_smell_types? && matching_smell_details?
end to def matches?(actual)
self.examiner = Examiner.new(actual, configuration: configuration)
self.all_smells = examiner.smells
all_smells.any? { |warning| warning.matches?(smell_category, smell_details) }
end so the failure messages are not being set in quite the same way they were before ...? So to fix this I'm not sure which direction others are going in - are those tests that I have failing at the moment being dropped since we are going with simpler error messages that don't distinguish between smell type and associated attribute matches? Either way I'm confused as I thought I was rebasing to master, and master on github doesn't seem to have the same updated code as I've just pulled in ... |
Code looks good to me! Now we only need to sort out your problems above ;) |
a084086
to
b0ee968
Compare
thanks @troessner I've force pushed the single squashed commit so you can see precisely where we're up to. I'm not going to be able to look at this again till Monday, so if you can see the resolution here that would be very helpful. I believe I could resolve it either by removing the two failing tests, or by changing (reverting?) Your help very much appreciated |
You need to rebase against origin/master (which is basically the master the from this very repository), fix the conflicts and then force push. |
That's what I thought I did. I'll have another look later today. If I'm doing 'git rebase -i master' I need to do 'git fetch upstream' and git merge upstream/master first? I thought I did do that already but will double check |
b0ee968
to
48af7db
Compare
okay, looks like the problem was that I forget the Anyway, green now. Hopefully this should be ready to merge. Ironically even after all this, this only completes clearing my throat to get started on smell message internationalisation for #589 :-) |
|
||
it 'reports the smells when should_not fails' do | ||
expect(matcher.matches?(smelly_code)).to be_truthy | ||
expect(matcher.failure_message_when_negated).to match('UncommunicativeVariableName') |
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.
Where is this example coming from all of a sudden? I'd rather remove this.
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 it might just be due to the funky rebase I did against an old master
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.
investigating and I didn't write this. It is an artifact of the funky rebase - this file had huge merge conflicts and I did my best to get it into the right shape, but because my local master was behind the upstream master it all went a bit wrong - have removed this test
it 'does not match on different vars' do | ||
expect(uncommunicative.matches?(:UncommunicativeVariableName, | ||
parameters: { test: 'something' }, | ||
message: 'nothing')).to be_falsy | ||
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.
SmellWarning#matches_attributes? from here https://github.com/troessner/reek/pull/732/files#diff-4c9efdbf77261fe0d68c190a1db4e3fcR58 is a very powerful method now that is not spec'ed at all it sees. Can you please add some specs?
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 had a thought already about how we are not testing attribute match failure and had already written a test for that which I thought to include in a subsequent pull request. I include that now, although that is still in the SmellWarning#matches? context. Various of the code paths of SmellWarning#matches_attributes? are tested via the SmellWarning#matches? context. Should they be broken out into a separate context? tested in both (no I guess) or should SmellWarning#matches_attributes? become a private method?
I'm afraid I still can't merge this since I found some other issues in my final review, see my latest comments. Please address those and then we can merge this.;) |
thanks @troessner hoping to get to this soon - I already had some other additional tests for that long method that I was going to drop into a separate pull request - busy week - will try to get to this before the end of it :-) |
@@ -8,7 +8,7 @@ | |||
module Fred | |||
def simple(x) x + 1; end | |||
end | |||
').to reek_of(:UncommunicativeParameterName, name: 'x') | |||
').to reek_of(:UncommunicativeParameterName, parameters: { name: 'x' }) |
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 we should strive for a solution that doesn't need this extra key.
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.
That sounds like a noble goal, but this is a reflection of the instance variables we have on smell_warning:
def initialize(smell_detector, context: '', lines: raise, message: raise,
source: raise, parameters: {})
@smell_detector = smell_detector
@source = source
@context = context.to_s
@lines = lines
@message = message
@parameters = parameters
end
parameters is a hash - the others are not. If we want to match against both the instance variables where one is a hash, we need to distinguish them with keys. Maybe all the parameters should become instance variables to avoid the need for the nested parameters so to speak, but getting involved in this debate I feel a strong sense of "Yak-shaving" :-) I'm all for improving reek, but I really want to get to adding the internationalization functionality for which having the ability to check the message associated with a smell is a pre-requisite.
Maybe when making these changes is a great opportunity for a larger refactoring, but I don't feel qualified to do it. Particularly I feel I am so far away from having an end user feature to drive the decisions that I can't really argue for or against this.
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.
Agree with @tansaku, see above.
…p for more sophisticated version that will check more than just class name and params and updates all spec files to allow for new smell warning matches? format
48af7db
to
7427972
Compare
I re-reviewed this one and I am of the opinion that we should merge it now. |
No objections. LGTM! |
Merged! |
adding ability to check for smell message contents
thanks @troessner and @mvz pleased to see that merged in - now onto the real work :-) |
So this is another tiny step towards #589 getting set up so that we can actually test that a smell message has changed