Skip to content

Commit

Permalink
Make Minitest/RefuteMatch aware of refute_operator
Browse files Browse the repository at this point in the history
This PR makes `Minitest/RefuteMatch` aware of `refute_operator` and `assert_operator`.
  • Loading branch information
koic committed Oct 8, 2023
1 parent f2396a6 commit f55259b
Show file tree
Hide file tree
Showing 3 changed files with 105 additions and 12 deletions.
@@ -0,0 +1 @@
* [#269](https://github.com/rubocop/rubocop-minitest/pull/269): Make `Minitest/RefuteMatch` aware of `refute_operator` and `assert_operator`. ([@koic][])
48 changes: 45 additions & 3 deletions lib/rubocop/cop/minitest/refute_match.rb
Expand Up @@ -12,17 +12,59 @@ module Minitest
# refute(matcher.match?(string))
# refute(matcher =~ string)
# refute_operator(matcher, :=~, string)
# assert_operator(matcher, :!~, string)
# refute(matcher.match(string), 'message')
#
# # good
# refute_match(matcher, string)
# refute_match(matcher, string, 'message')
#
class RefuteMatch < Base
extend MinitestCopRule
include ArgumentRangeHelper
extend AutoCorrector

define_rule :refute, target_method: %i[match match? =~],
preferred_method: :refute_match, inverse: 'regexp_type?'
MSG = 'Prefer using `refute_match(%<preferred>s)`.'
RESTRICT_ON_SEND = %i[refute refute_operator assert_operator].freeze

def_node_matcher :refute_match, <<~PATTERN
{
(send nil? :refute (send $_ {:match :match? :=~} $_) $...)
(send nil? :refute_operator $_ (sym :=~) $_ $...)
(send nil? :assert_operator $_ (sym :!~) $_ $...)
}
PATTERN

# rubocop:disable Metrics/AbcSize
def on_send(node)
refute_match(node) do |expected, actual, rest_args|
basic_arguments = order_expected_and_actual(expected, actual)
preferred = (message_arg = rest_args.first) ? "#{basic_arguments}, #{message_arg.source}" : basic_arguments
message = format(MSG, preferred: preferred)

add_offense(node, message: message) do |corrector|
corrector.replace(node.loc.selector, 'refute_match')

range = if node.method?(:refute)
node.first_argument
else
node.first_argument.source_range.begin.join(node.arguments[2].source_range.end)
end

corrector.replace(range, basic_arguments)
end
end
end
# rubocop:enable Metrics/AbcSize

private

def order_expected_and_actual(expected, actual)
if actual.regexp_type?
[actual, expected]
else
[expected, actual]
end.map(&:source).join(', ')
end
end
end
end
Expand Down
68 changes: 59 additions & 9 deletions test/rubocop/cop/minitest/refute_match_test.rb
Expand Up @@ -105,24 +105,54 @@ def test_do_something
RUBY
end

# Redundant parentheses should be removed in another cop.
define_method("test_registers_offense_when_using_refute_with_#{matcher}_in_redundant_parentheses") do
assert_offense(<<~RUBY, matcher: matcher)
assert_no_offenses(<<~RUBY, matcher: matcher)
class FooTest < Minitest::Test
def test_do_something
refute((matcher.#{matcher}(string)))
^^^^^^^^^^^^^^^^^{matcher}^^^^^^^^^^ Prefer using `refute_match(matcher, string)`.
end
end
RUBY
end
end

assert_correction(<<~RUBY)
class FooTest < Minitest::Test
def test_do_something
refute_match((matcher, string))
end
def test_registers_offense_when_using_refute_operator_with_match_operator
assert_offense(<<~RUBY)
class FooTest < Minitest::Test
def test_do_something
refute_operator(matcher, :=~, object)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Prefer using `refute_match(matcher, object)`.
end
RUBY
end
end
RUBY

assert_correction(<<~RUBY)
class FooTest < Minitest::Test
def test_do_something
refute_match(matcher, object)
end
end
RUBY
end

def test_registers_offense_when_using_assert_operator_with_mismatch_operator
assert_offense(<<~RUBY)
class FooTest < Minitest::Test
def test_do_something
assert_operator(matcher, :!~, object)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Prefer using `refute_match(matcher, object)`.
end
end
RUBY

assert_correction(<<~RUBY)
class FooTest < Minitest::Test
def test_do_something
refute_match(matcher, object)
end
end
RUBY
end

def test_does_not_register_offense_when_using_refute_match
Expand Down Expand Up @@ -154,4 +184,24 @@ def test_do_something
end
RUBY
end

def test_does_registers_offense_when_using_refute_operator_with_mismatch_operator
assert_no_offenses(<<~RUBY)
class FooTest < Minitest::Test
def test_do_something
refute_operator(matcher, :!~, :object)
end
end
RUBY
end

def test_does_registers_offense_when_using_assert_operator_with_match_operator
assert_no_offenses(<<~RUBY)
class FooTest < Minitest::Test
def test_do_something
assert_operator(matcher, :=~, :object)
end
end
RUBY
end
end

0 comments on commit f55259b

Please sign in to comment.