Skip to content

Commit

Permalink
Merge pull request #1554 from ydah/fix-false-positive-rspec-Predicate…
Browse files Browse the repository at this point in the history
…Matcher

Fix a false positive for `RSpec/PredicateMatcher` when multiple arguments and not replaceable method
  • Loading branch information
bquorning committed Jan 16, 2023
1 parent 9e8c975 commit e84141a
Show file tree
Hide file tree
Showing 3 changed files with 41 additions and 15 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
- Fix a false positive for `RSpec/NoExpectationExample` when using skipped in metadata is multiline string. ([@ydah])
- Fix a false positive for `RSpec/ContextMethod` when multi-line context with `#` at the beginning. ([@ydah])
- Fix an incorrect autocorrect for `RSpec/PredicateMatcher` when multiline expect and predicate method with heredoc. ([@ydah])
- Fix a false positive for `RSpec/PredicateMatcher` when `include` with multiple argument. ([@ydah])

## 2.17.0 (2023-01-13)

Expand Down
11 changes: 11 additions & 0 deletions lib/rubocop/cop/rspec/predicate_matcher.rb
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,8 @@ def check_explicit(node) # rubocop:disable Metrics/MethodLength
return if part_of_ignored_node?(node)

predicate_matcher?(node) do |actual, matcher|
next unless replaceable_matcher?(matcher)

add_offense(node, message: message_explicit(matcher)) do |corrector|
next if uncorrectable_matcher?(node, matcher)

Expand All @@ -157,6 +159,15 @@ def check_explicit(node) # rubocop:disable Metrics/MethodLength
end
end

def replaceable_matcher?(matcher)
case matcher.method_name.to_s
when 'include'
matcher.arguments.one?
else
true
end
end

def uncorrectable_matcher?(node, matcher)
heredoc_argument?(matcher) && !same_line?(node, matcher)
end
Expand Down
44 changes: 29 additions & 15 deletions spec/rubocop/cop/rspec/predicate_matcher_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -95,14 +95,14 @@

it 'registers an offense for a predicate method with heredoc' do
expect_offense(<<~RUBY)
expect(foo.include?(<<~TEXT)).to be_truthy
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Prefer using `include` matcher over `include?`.
expect(foo.something?(<<~TEXT)).to be_truthy
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Prefer using `be_something` matcher over `something?`.
bar
TEXT
RUBY

expect_correction(<<~RUBY)
expect(foo).to include(<<~TEXT)
expect(foo).to be_something(<<~TEXT)
bar
TEXT
RUBY
Expand Down Expand Up @@ -346,14 +346,14 @@
'heredoc and multiline expect' do
expect_offense(<<~RUBY)
expect(foo)
^^^^^^^^^^^ Prefer using `include?` over `include` matcher.
.to include(<<~TEXT)
^^^^^^^^^^^ Prefer using `something?` over `be_something` matcher.
.to be_something(<<~TEXT)
bar
TEXT
expect(foo)
^^^^^^^^^^^ Prefer using `include?` over `include` matcher.
.to include(bar, <<~TEXT, 'baz')
^^^^^^^^^^^ Prefer using `something?` over `be_something` matcher.
.to be_something(bar, <<~TEXT, 'baz')
bar
TEXT
RUBY
Expand All @@ -365,14 +365,14 @@
'heredoc include #{} and multiline expect' do
expect_offense(<<~'RUBY')
expect(foo)
^^^^^^^^^^^ Prefer using `include?` over `include` matcher.
.to include(<<~TEXT)
^^^^^^^^^^^ Prefer using `something?` over `be_something` matcher.
.to be_something(<<~TEXT)
#{bar}
TEXT
expect(foo)
^^^^^^^^^^^ Prefer using `include?` over `include` matcher.
.to include(bar, <<~TEXT, 'baz')
^^^^^^^^^^^ Prefer using `something?` over `be_something` matcher.
.to be_something(bar, <<~TEXT, 'baz')
#{bar}
TEXT
RUBY
Expand All @@ -384,21 +384,35 @@
'heredoc surrounded by back ticks and multiline expect' do
expect_offense(<<~'RUBY')
expect(foo)
^^^^^^^^^^^ Prefer using `include?` over `include` matcher.
.to include(<<~`COMMAND`)
^^^^^^^^^^^ Prefer using `something?` over `be_something` matcher.
.to be_something(<<~`COMMAND`)
pwd
COMMAND
expect(foo)
^^^^^^^^^^^ Prefer using `include?` over `include` matcher.
.to include(bar, <<~COMMAND, 'baz')
^^^^^^^^^^^ Prefer using `something?` over `be_something` matcher.
.to be_something(bar, <<~COMMAND, 'baz')
pwd
COMMAND
RUBY

expect_no_corrections
end

it 'does not register an offense for a `include` ' \
'with no argument' do
expect_no_offenses(<<~RUBY)
expect(foo).to include
RUBY
end

it 'does not register an offense for a `include` ' \
'with multiple arguments' do
expect_no_offenses(<<~RUBY)
expect(foo).to include(foo, bar)
RUBY
end

it 'registers an offense for a predicate method with a block' do
expect_offense(<<~RUBY)
expect(foo).to be_all { |x| x.present? }
Expand Down

0 comments on commit e84141a

Please sign in to comment.