From 6f03ce6fe905d397cc2f9aaeb624ade0e61719ca Mon Sep 17 00:00:00 2001 From: Koichi ITO Date: Sun, 29 Oct 2023 15:40:00 +0900 Subject: [PATCH] Add new `Minitest/RedundantMessageArgument` cop This PR adds new `Minitest/RedundantMessageArgument` cop that detects redundant message argument in assertion methods. The message argument `nil` is redundant because it is the default value. ```ruby # bad assert_equal(expected, actual, nil) # good assert_equal(expected, actual) assert_equal(expected, actual, 'message') ``` --- ...minitest_redundant_message_argument_cop.md | 1 + config/default.yml | 5 + .../minitest/redundant_message_argument.rb | 88 +++++ lib/rubocop/cop/minitest_cops.rb | 1 + .../redundant_message_argument_test.rb | 363 ++++++++++++++++++ 5 files changed, 458 insertions(+) create mode 100644 changelog/new_add_new_minitest_redundant_message_argument_cop.md create mode 100644 lib/rubocop/cop/minitest/redundant_message_argument.rb create mode 100644 test/rubocop/cop/minitest/redundant_message_argument_test.rb diff --git a/changelog/new_add_new_minitest_redundant_message_argument_cop.md b/changelog/new_add_new_minitest_redundant_message_argument_cop.md new file mode 100644 index 00000000..821a49ae --- /dev/null +++ b/changelog/new_add_new_minitest_redundant_message_argument_cop.md @@ -0,0 +1 @@ +* [#272](https://github.com/rubocop/rubocop-minitest/pull/272): Add new Minitest/RedundantMessageArgument cop. ([@koic][]) diff --git a/config/default.yml b/config/default.yml index 3837d5bc..55a0736c 100644 --- a/config/default.yml +++ b/config/default.yml @@ -198,6 +198,11 @@ Minitest/NonPublicTestMethod: Severity: warning VersionAdded: '0.27' +Minitest/RedundantMessageArgument: + Description: 'Detects redundant message argument in assertion methods.' + Enabled: pending + VersionAdded: '<>' + Minitest/RefuteEmpty: Description: 'This cop enforces to use `refute_empty` instead of using `refute(object.empty?)`.' StyleGuide: 'https://minitest.rubystyle.guide#refute-empty' diff --git a/lib/rubocop/cop/minitest/redundant_message_argument.rb b/lib/rubocop/cop/minitest/redundant_message_argument.rb new file mode 100644 index 00000000..0a0411ab --- /dev/null +++ b/lib/rubocop/cop/minitest/redundant_message_argument.rb @@ -0,0 +1,88 @@ +# frozen_string_literal: true + +module RuboCop + module Cop + module Minitest + # Detects redundant message argument in assertion methods. + # The message argument `nil` is redundant because it is the default value. + # + # @example + # + # # bad + # assert_equal(expected, actual, nil) + # + # # good + # assert_equal(expected, actual) + # assert_equal(expected, actual, 'message') + # + class RedundantMessageArgument < Base + extend AutoCorrector + + MSG = 'Remove the redundant message argument.' + + RESTRICT_ON_SEND = %i[ + assert assert_empty assert_equal assert_same assert_in_delta assert_in_epsilon assert_includes + assert_instance_of assert_kind_of assert_match assert_nil assert_operator assert_path_exists + assert_predicate assert_respond_to assert_same assert_throws + flunk + refute refute_empty refute_equal refute_in_delta refute_in_epsilon refute_includes + refute_instance_of refute_kind_of refute_match refute_nil refute_operator refute_path_exists + refute_predicate refute_respond_to refute_same + ].freeze + + # @!method bad_method?(node) + def_node_matcher :redundant_message_argument, <<~PATTERN + { + (send nil? :assert _ $nil) + (send nil? :assert_empty _ $nil) + (send nil? :assert_equal _ _ $nil) + (send nil? :assert_in_delta _ _ _ $nil) + (send nil? :assert_in_epsilon _ _ _ $nil) + (send nil? :assert_includes _ _ $nil) + (send nil? :assert_instance_of _ _ $nil) + (send nil? :assert_kind_of _ _ $nil) + (send nil? :assert_match _ _ $nil) + (send nil? :assert_nil _ $nil) + (send nil? :assert_operator _ _ _ $nil) + (send nil? :assert_path_exists _ $nil) + (send nil? :assert_predicate _ _ $nil) + (send nil? :assert_respond_to _ _ $nil) + (send nil? :assert_same _ _ $nil) + (send nil? :assert_throws _ $nil) + (send nil? :flunk $nil) + (send nil? :refute _ $nil) + (send nil? :refute_empty _ $nil) + (send nil? :refute_equal _ _ $nil) + (send nil? :refute_in_delta _ _ _ $nil) + (send nil? :refute_in_epsilon _ _ _ $nil) + (send nil? :refute_includes _ _ $nil) + (send nil? :refute_instance_of _ _ $nil) + (send nil? :refute_kind_of _ _ $nil) + (send nil? :refute_match _ _ $nil) + (send nil? :refute_nil _ $nil) + (send nil? :refute_operator _ _ _ $nil) + (send nil? :refute_path_exists _ $nil) + (send nil? :refute_predicate _ _ $nil) + (send nil? :refute_respond_to _ _ $nil) + (send nil? :refute_same _ _ $nil) + } + PATTERN + + def on_send(node) + return unless (redundant_message_argument = redundant_message_argument(node)) + + add_offense(redundant_message_argument) do |corrector| + if node.arguments.one? + range = redundant_message_argument + else + index = node.arguments.index(redundant_message_argument) + range = node.arguments[index - 1].source_range.end.join(redundant_message_argument.source_range.end) + end + + corrector.remove(range) + end + end + end + end + end +end diff --git a/lib/rubocop/cop/minitest_cops.rb b/lib/rubocop/cop/minitest_cops.rb index 58675e7a..2a5ea138 100644 --- a/lib/rubocop/cop/minitest_cops.rb +++ b/lib/rubocop/cop/minitest_cops.rb @@ -30,6 +30,7 @@ require_relative 'minitest/assert_truthy' require_relative 'minitest/duplicate_test_run' require_relative 'minitest/empty_line_before_assertion_methods' +require_relative 'minitest/redundant_message_argument' require_relative 'minitest/return_in_test_method' require_relative 'minitest/test_file_name' require_relative 'minitest/global_expectations' diff --git a/test/rubocop/cop/minitest/redundant_message_argument_test.rb b/test/rubocop/cop/minitest/redundant_message_argument_test.rb new file mode 100644 index 00000000..cb96b081 --- /dev/null +++ b/test/rubocop/cop/minitest/redundant_message_argument_test.rb @@ -0,0 +1,363 @@ +# frozen_string_literal: true + +require_relative '../../../test_helper' + +class RedundantMessageArgumentTest < Minitest::Test + def test_registers_offense_when_using_redundant_message_argument_in_assert + assert_offense(<<~RUBY) + assert(test, nil) + ^^^ Remove the redundant message argument. + RUBY + + assert_correction(<<~RUBY) + assert(test) + RUBY + end + + def test_registers_offense_when_using_redundant_message_argument_in_assert_empty + assert_offense(<<~RUBY) + assert_empty(obj, nil) + ^^^ Remove the redundant message argument. + RUBY + + assert_correction(<<~RUBY) + assert_empty(obj) + RUBY + end + + def test_registers_offense_when_using_redundant_message_argument_in_assert_equal + assert_offense(<<~RUBY) + assert_equal(exp, act, nil) + ^^^ Remove the redundant message argument. + RUBY + + assert_correction(<<~RUBY) + assert_equal(exp, act) + RUBY + end + + def test_registers_offense_when_using_redundant_message_argument_in_assert_in_delta + assert_offense(<<~RUBY) + assert_in_delta(exp, act, delta, nil) + ^^^ Remove the redundant message argument. + RUBY + + assert_correction(<<~RUBY) + assert_in_delta(exp, act, delta) + RUBY + end + + def test_registers_offense_when_using_redundant_message_argument_in_assert_in_epsilon + assert_offense(<<~RUBY) + assert_in_epsilon(exp, act, epsilon, nil) + ^^^ Remove the redundant message argument. + RUBY + + assert_correction(<<~RUBY) + assert_in_epsilon(exp, act, epsilon) + RUBY + end + + def test_registers_offense_when_using_redundant_message_argument_in_assert_includes + assert_offense(<<~RUBY) + assert_includes(collection, obj, nil) + ^^^ Remove the redundant message argument. + RUBY + + assert_correction(<<~RUBY) + assert_includes(collection, obj) + RUBY + end + + def test_registers_offense_when_using_redundant_message_argument_in_assert_instance_of + assert_offense(<<~RUBY) + assert_instance_of(cls, obj, nil) + ^^^ Remove the redundant message argument. + RUBY + + assert_correction(<<~RUBY) + assert_instance_of(cls, obj) + RUBY + end + + def test_registers_offense_when_using_redundant_message_argument_in_assert_kind_of + assert_offense(<<~RUBY) + assert_kind_of(cls, obj, nil) + ^^^ Remove the redundant message argument. + RUBY + + assert_correction(<<~RUBY) + assert_kind_of(cls, obj) + RUBY + end + + def test_registers_offense_when_using_redundant_message_argument_in_assert_match + assert_offense(<<~RUBY) + assert_match(matcher, obj, nil) + ^^^ Remove the redundant message argument. + RUBY + + assert_correction(<<~RUBY) + assert_match(matcher, obj) + RUBY + end + + def test_registers_offense_when_using_redundant_message_argument_in_assert_nil + assert_offense(<<~RUBY) + assert_nil(obj, nil) + ^^^ Remove the redundant message argument. + RUBY + + assert_correction(<<~RUBY) + assert_nil(obj) + RUBY + end + + def test_registers_offense_when_using_redundant_message_argument_in_assert_operator + assert_offense(<<~RUBY) + assert_operator(o1, op, op, nil) + ^^^ Remove the redundant message argument. + RUBY + + assert_correction(<<~RUBY) + assert_operator(o1, op, op) + RUBY + end + + def test_registers_offense_when_using_redundant_message_argument_in_assert_path_exists + assert_offense(<<~RUBY) + assert_path_exists(path, nil) + ^^^ Remove the redundant message argument. + RUBY + + assert_correction(<<~RUBY) + assert_path_exists(path) + RUBY + end + + def test_registers_offense_when_using_redundant_message_argument_in_assert_predicate + assert_offense(<<~RUBY) + assert_predicate(o1, op, nil) + ^^^ Remove the redundant message argument. + RUBY + + assert_correction(<<~RUBY) + assert_predicate(o1, op) + RUBY + end + + def test_registers_offense_when_using_redundant_message_argument_in_assert_respond_to + assert_offense(<<~RUBY) + assert_respond_to(obj, meth, nil) + ^^^ Remove the redundant message argument. + RUBY + + assert_correction(<<~RUBY) + assert_respond_to(obj, meth) + RUBY + end + + def test_registers_offense_when_using_redundant_message_argument_in_assert_same + assert_offense(<<~RUBY) + assert_same(exp, act, nil) + ^^^ Remove the redundant message argument. + RUBY + + assert_correction(<<~RUBY) + assert_same(exp, act) + RUBY + end + + def test_registers_offense_when_using_redundant_message_argument_in_assert_throws + assert_offense(<<~RUBY) + assert_throws(sym, nil) + ^^^ Remove the redundant message argument. + RUBY + + assert_correction(<<~RUBY) + assert_throws(sym) + RUBY + end + + def test_registers_offense_when_using_redundant_message_argument_in_flunk + assert_offense(<<~RUBY) + flunk(nil) + ^^^ Remove the redundant message argument. + RUBY + + assert_correction(<<~RUBY) + flunk() + RUBY + end + + def test_registers_offense_when_using_redundant_message_argument_in_refute + assert_offense(<<~RUBY) + refute(test, nil) + ^^^ Remove the redundant message argument. + RUBY + + assert_correction(<<~RUBY) + refute(test) + RUBY + end + + def test_registers_offense_when_using_redundant_message_argument_in_refute_empty + assert_offense(<<~RUBY) + refute_empty(obj, nil) + ^^^ Remove the redundant message argument. + RUBY + + assert_correction(<<~RUBY) + refute_empty(obj) + RUBY + end + + def test_registers_offense_when_using_redundant_message_argument_in_refute_equal + assert_offense(<<~RUBY) + refute_equal(exp, act, nil) + ^^^ Remove the redundant message argument. + RUBY + + assert_correction(<<~RUBY) + refute_equal(exp, act) + RUBY + end + + def test_registers_offense_when_using_redundant_message_argument_in_refute_in_delta + assert_offense(<<~RUBY) + refute_in_delta(exp, act, delta, nil) + ^^^ Remove the redundant message argument. + RUBY + + assert_correction(<<~RUBY) + refute_in_delta(exp, act, delta) + RUBY + end + + def test_registers_offense_when_using_redundant_message_argument_in_refute_in_epsilon + assert_offense(<<~RUBY) + refute_in_epsilon(exp, act, epsilon, nil) + ^^^ Remove the redundant message argument. + RUBY + + assert_correction(<<~RUBY) + refute_in_epsilon(exp, act, epsilon) + RUBY + end + + def test_registers_offense_when_using_redundant_message_argument_in_refute_includes + assert_offense(<<~RUBY) + refute_includes(collection, obj, nil) + ^^^ Remove the redundant message argument. + RUBY + + assert_correction(<<~RUBY) + refute_includes(collection, obj) + RUBY + end + + def test_registers_offense_when_using_redundant_message_argument_in_refute_instance_of + assert_offense(<<~RUBY) + refute_instance_of(cls, obj, nil) + ^^^ Remove the redundant message argument. + RUBY + + assert_correction(<<~RUBY) + refute_instance_of(cls, obj) + RUBY + end + + def test_registers_offense_when_using_redundant_message_argument_in_refute_kind_of + assert_offense(<<~RUBY) + refute_kind_of(cls, obj, nil) + ^^^ Remove the redundant message argument. + RUBY + + assert_correction(<<~RUBY) + refute_kind_of(cls, obj) + RUBY + end + + def test_registers_offense_when_using_redundant_message_argument_in_refute_match + assert_offense(<<~RUBY) + refute_match(matcher, obj, nil) + ^^^ Remove the redundant message argument. + RUBY + + assert_correction(<<~RUBY) + refute_match(matcher, obj) + RUBY + end + + def test_registers_offense_when_using_redundant_message_argument_in_refute_nil + assert_offense(<<~RUBY) + refute_nil(obj, nil) + ^^^ Remove the redundant message argument. + RUBY + + assert_correction(<<~RUBY) + refute_nil(obj) + RUBY + end + + def test_registers_offense_when_using_redundant_message_argument_in_refute_operator + assert_offense(<<~RUBY) + refute_operator(o1, op, op, nil) + ^^^ Remove the redundant message argument. + RUBY + + assert_correction(<<~RUBY) + refute_operator(o1, op, op) + RUBY + end + + def test_registers_offense_when_using_redundant_message_argument_in_refute_path_exists + assert_offense(<<~RUBY) + refute_path_exists(path, nil) + ^^^ Remove the redundant message argument. + RUBY + + assert_correction(<<~RUBY) + refute_path_exists(path) + RUBY + end + + def test_registers_offense_when_using_redundant_message_argument_in_refute_predicate + assert_offense(<<~RUBY) + refute_predicate(o1, op, nil) + ^^^ Remove the redundant message argument. + RUBY + + assert_correction(<<~RUBY) + refute_predicate(o1, op) + RUBY + end + + def test_registers_offense_when_using_redundant_message_argument_in_refute_respond_to + assert_offense(<<~RUBY) + refute_respond_to(obj, meth, nil) + ^^^ Remove the redundant message argument. + RUBY + + assert_correction(<<~RUBY) + refute_respond_to(obj, meth) + RUBY + end + + def test_registers_offense_when_using_redundant_message_argument_in_refute_same + assert_offense(<<~RUBY) + refute_same(exp, act, nil) + ^^^ Remove the redundant message argument. + RUBY + + assert_correction(<<~RUBY) + refute_same(exp, act) + RUBY + end + + def test_does_not_register_offense_when_using_useful_message_argument_in_assert + assert_no_offenses(<<~RUBY) + assert(test, 'message') + RUBY + end +end