Skip to content
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

Fix false positive for relative file path runs with long namespaces (fixes #1091) #1099

Merged
merged 1 commit into from
Dec 13, 2020
Merged

Conversation

ahukkanen
Copy link
Contributor

@ahukkanen ahukkanen commented Nov 21, 2020

This is a PR that fixes the issue that is further explained at #1091.

This was broken by this commit included in the PR #869:
811ae08#diff-5b709885b35566a0c699ad4a3200b9b7acbc28ef640fa56a8e66f6c732420a34

It turned out to be extremely difficult (at least I don't know how after multiple tries and experiments) to fix the issue described at #1091 using the file name globs. Therefore I switched to regular expression based matching which allows a more specific targeting for the case in question.

The removed specs originate from this commit in the PR #917:
23ad402#diff-5bc1941f9b92914876efec6f7fcc70b153e82194d960213a280078c6cb4b0c3a

The removed specs are no longer needed because it now uses absolute paths as it did prior to merging #869. I believe these were also issues introduced by #869.

Fixes #1091


Before submitting the PR make sure the following are checked:

  • Feature branch is up-to-date with master (if not - rebase it).
  • Squashed related commits together.
  • Added tests.
  • Updated documentation.
  • Added an entry to the CHANGELOG.md if the new code introduces user-observable changes.
  • The build (bundle exec rake) passes (be sure to run this locally, since it may produce updated documentation that you will need to commit).

Copy link
Collaborator

@bquorning bquorning left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree this looks like a better solution to the problems that #869 and #917 were fixing.

But I wonder if this PR works on Windows (do we need to split by File::SEPARATOR and join with '/' before calling #match?) or case sensitive filesystems.

Comment on lines 91 to 92
offense_suffix = pattern.gsub('.*', '*').gsub('[^/]*', '*')
.sub('\.rb', '.rb')
Copy link
Collaborator

@bquorning bquorning Nov 25, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How about if we substitute as little as possible, so very narrowly matching the regex-specific parts of the string? E.g.

Suggested change
offense_suffix = pattern.gsub('.*', '*').gsub('[^/]*', '*')
.sub('\.rb', '.rb')
offense_suffix = pattern.gsub('.*', '*').sub('[^/]', '')
.sub('\.', '.')

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure, it's changed now.

File.fnmatch?("*#{glob}", filename)
def filename_ends_with?(pattern)
filename = File.expand_path(processed_source.buffer.name)
filename.match?(".*#{pattern}$")
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

.* is unnecessary at the beginning (or end) of a regex.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could we move the $ (which should probably be \z?) into the pattern itself? Then this line would become simply filename.match?(pattern)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • You are right about unnecessary .* in the beginning. It is removed.
  • We cannot move the $ or \z to the pattern_for method because it would then appear in the offense messages unless it is also substituted. I think that it makes sense to keep the ending part of the pattern in the filename_ends_with? method.
  • Regarding $ or \z I guess either one is fine. Is there any case when a single filename can be multiline?

@bquorning
Copy link
Collaborator

  • Squashed related commits together. - (❓ - couldn't you squash when merging?)

We don’t use GitHub’s “Squash and merge” option, since it fails to create a merge commit.

@bquorning bquorning requested review from Darhazer and pirj December 1, 2020 07:36
Copy link
Member

@pirj pirj left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's strange that the cop fails to detect an offence in:

RSpec.describe Object, "should" do

or

RSpec.describe Object, "#should" do

when inspecting spec/rspec/expectations/extensions/kernel_spec.rb.
But it was like that before this change as well.

Yet another case that this cop is missing (both before and after the change) is a namespace:

# spec/rspec/expectations/configuration_spec.rb
module RSpec
  module Mocks # Should be Expectations
    RSpec.describe Configuration do

Those two are not blockers, but more like ideas if you'd like to follow-up on this.

There's a new legitimate offence detected:

/Users/pirj/source/rspec-dev/repos/rspec-expectations/spec/rspec/expectations/syntax_spec.rb:88:3: C: RSpec/FilePath: Spec path should end with expectations*_spec.rb.
  RSpec.describe Expectations do
  ^^^^^^^^^^^^^^^^^^^^^^^^^^^

👍

I couldn't break the cop by testing locally.

Looks good, the change is quite elegant, and besides fixing all the cases is now easier to read. Thanks a lot!

spec/rubocop/cop/rspec/file_path_spec.rb Outdated Show resolved Hide resolved
lib/rubocop/cop/rspec/file_path.rb Show resolved Hide resolved
Copy link
Collaborator

@bquorning bquorning left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you please 1) add a changelog entry, and 2) rebase the PR, squashing all commits down to one?

lib/rubocop/cop/rspec/file_path.rb Outdated Show resolved Hide resolved
@bquorning
Copy link
Collaborator

But I wonder if this PR works on Windows (do we need to split by File::SEPARATOR and join with '/' before calling #match?) or case sensitive filesystems.

Do we have any Windows users around?

@pirj
Copy link
Member

pirj commented Dec 12, 2020

Please add a Changelog entry, squash commits and I believe we're ready to merge.
Thanks once again!

When rubocop is run in a relative path to a spec with long
namespace, e.g. in the same directory, the FilePath spec will
return incorrect matches.

This fixes them by switching to a regular expression based pattern
matching which allows more specific matchign than the previously
used globs.

Adds new specs to ensure the file extension is matched against the
ruby file extension (.rb).

Fixes #1091
@ahukkanen
Copy link
Contributor Author

@pirj Changelog added and commits are squashed.

@pirj pirj requested a review from bquorning December 12, 2020 16:50
@ahukkanen
Copy link
Contributor Author

But I wonder if this PR works on Windows (do we need to split by File::SEPARATOR and join with '/' before calling #match?) or case sensitive filesystems.

Do we have any Windows users around?

@bquorning I tested this under Windows and it seems to work fine there as is. This is because processed_source.buffer.name returns the filename with forward slashes also under Windows.

Copy link
Collaborator

@bquorning bquorning left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you 🙏🏼

@bquorning bquorning merged commit dc10758 into rubocop:master Dec 13, 2020
@ahukkanen ahukkanen deleted the fix/1091 branch January 10, 2021 14:24
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

RSpec/FilePath is broken with vscode-ruby after 1.39.0 (2020-05-01)
3 participants