diff --git a/CHANGELOG.md b/CHANGELOG.md index 190fc2fea..88009a4ee 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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) diff --git a/lib/rubocop/cop/rspec/predicate_matcher.rb b/lib/rubocop/cop/rspec/predicate_matcher.rb index 872e823cc..e49461b9e 100644 --- a/lib/rubocop/cop/rspec/predicate_matcher.rb +++ b/lib/rubocop/cop/rspec/predicate_matcher.rb @@ -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) @@ -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 diff --git a/spec/rubocop/cop/rspec/predicate_matcher_spec.rb b/spec/rubocop/cop/rspec/predicate_matcher_spec.rb index 149a45c6e..24b4351a4 100644 --- a/spec/rubocop/cop/rspec/predicate_matcher_spec.rb +++ b/spec/rubocop/cop/rspec/predicate_matcher_spec.rb @@ -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 @@ -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 @@ -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 @@ -384,14 +384,14 @@ '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 @@ -399,6 +399,20 @@ 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? }