diff --git a/CHANGELOG.md b/CHANGELOG.md index b51d15bd..ae6faa65 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,9 @@ ## master (unreleased) +### New features + +* [#11](https://github.com/rubocop-hq/rubocop-minitest/pull/11): Add new `Minitest/RefuteNil` cop. ([@tejasbubane ][]) + ## 0.1.0 (2019-09-01) ### New features @@ -9,3 +13,4 @@ [@koic]: https://github.com/koic [@duduribeiro]: https://github.com/duduribeiro +[@tejasbubane]: https://github.com/tejasbubane diff --git a/config/default.yml b/config/default.yml index 960e1499..87a1cb50 100644 --- a/config/default.yml +++ b/config/default.yml @@ -7,3 +7,9 @@ Minitest/AssertNil: StyleGuide: 'https://github.com/rubocop-hq/minitest-style-guide#assert-nil' Enabled: true VersionAdded: '0.1' + +Minitest/RefuteNil: + Description: 'Check if your test uses `refute_nil` instead of `refute_equal(nil, something)`.' + StyleGuide: 'https://github.com/rubocop-hq/minitest-style-guide#refute-nil' + Enabled: true + VersionAdded: '0.1.1' diff --git a/lib/rubocop/cop/minitest/refute_nil.rb b/lib/rubocop/cop/minitest/refute_nil.rb new file mode 100644 index 00000000..f80411cd --- /dev/null +++ b/lib/rubocop/cop/minitest/refute_nil.rb @@ -0,0 +1,45 @@ +# frozen_string_literal: true + +module RuboCop + module Cop + module Minitest + # Check if your test uses `refute_nil` instead of `refute_equal(nil, something)`. + # + # @example + # # bad + # refute_equal(nil, actual) + # refute_equal(nil, actual, 'the message') + # + # # good + # refute_nil(actual) + # refute_nil(actual, 'the message') + # + class RefuteNil < Cop + MSG = 'Prefer using `refute_nil(%s)` over ' \ + '`refute_equal(nil, %s)`.' + + def_node_matcher :refute_equal_with_nil, <<~PATTERN + (send nil? :refute_equal nil $_ $...) + PATTERN + + def on_send(node) + refute_equal_with_nil(node) do |actual, message| + message = message.first + + arguments = [actual.source, message&.source].compact.join(', ') + + add_offense(node, message: format(MSG, arguments: arguments)) + end + end + + def autocorrect(node) + lambda do |corrector| + arguments = node.arguments.reject(&:nil_type?) + replacement = arguments.map(&:source).join(', ') + corrector.replace(node.loc.expression, "refute_nil(#{replacement})") + end + end + end + end + end +end diff --git a/lib/rubocop/cop/minitest_cops.rb b/lib/rubocop/cop/minitest_cops.rb index e8b08a8f..58ea2447 100644 --- a/lib/rubocop/cop/minitest_cops.rb +++ b/lib/rubocop/cop/minitest_cops.rb @@ -1,3 +1,4 @@ # frozen_string_literal: true require_relative 'minitest/assert_nil' +require_relative 'minitest/refute_nil' diff --git a/manual/cops.md b/manual/cops.md index 3e61adb7..145b98aa 100644 --- a/manual/cops.md +++ b/manual/cops.md @@ -2,5 +2,6 @@ #### Department [Minitest](cops_minitest.md) * [Minitest/AssertNil](cops_minitest.md#minitestassertnil) +* [Minitest/RefuteNil](cops_minitest.md#minitestrefutenil) \ No newline at end of file diff --git a/manual/cops_minitest.md b/manual/cops_minitest.md index 82e7850d..c7f55ae3 100644 --- a/manual/cops_minitest.md +++ b/manual/cops_minitest.md @@ -23,3 +23,27 @@ assert_nil(actual, 'the message') ### References * [https://github.com/rubocop-hq/minitest-style-guide#assert-nil](https://github.com/rubocop-hq/minitest-style-guide#assert-nil) + +## Minitest/RefuteNil + +Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged +--- | --- | --- | --- | --- +Enabled | Yes | Yes | 0.1.1 | - + +Check if your test uses `refute_nil` instead of `refute_equal(nil, something)`. + +### Examples + +```ruby +# bad +refute_equal(nil, actual) +refute_equal(nil, actual, 'the message') + +# good +refute_nil(actual) +refute_nil(actual, 'the message') +``` + +### References + +* [https://github.com/rubocop-hq/minitest-style-guide#refute-nil](https://github.com/rubocop-hq/minitest-style-guide#refute-nil) diff --git a/test/rubocop/cop/minitest/refute_nil_test.rb b/test/rubocop/cop/minitest/refute_nil_test.rb new file mode 100644 index 00000000..e46428f4 --- /dev/null +++ b/test/rubocop/cop/minitest/refute_nil_test.rb @@ -0,0 +1,120 @@ +# frozen_string_literal: true + +require 'test_helper' + +class RefuteNilTest < Minitest::Test + def setup + @cop = RuboCop::Cop::Minitest::RefuteNil.new + end + + def test_adds_offense_for_use_of_refute_equal_nil + assert_offense(<<~RUBY, @cop) + class FooTest < Minitest::Test + def test_do_something + refute_equal(nil, somestuff) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Prefer using `refute_nil(somestuff)` over `refute_equal(nil, somestuff)`. + end + end + RUBY + + assert_correction(<<~RUBY, @cop) + class FooTest < Minitest::Test + def test_do_something + refute_nil(somestuff) + end + end + RUBY + end + + def test_adds_offense_for_use_of_refute_equal_nil_with_message + assert_offense(<<~RUBY, @cop) + class FooTest < Minitest::Test + def test_do_something + refute_equal(nil, somestuff, 'the message') + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Prefer using `refute_nil(somestuff, 'the message')` over `refute_equal(nil, somestuff, 'the message')`. + end + end + RUBY + + assert_correction(<<~RUBY, @cop) + class FooTest < Minitest::Test + def test_do_something + refute_nil(somestuff, 'the message') + end + end + RUBY + end + + def test_adds_offense_for_use_of_refute_equal_with_a_method_call + assert_offense(<<~RUBY, @cop) + class FooTest < Minitest::Test + def test_do_something + refute_equal(nil, obj.do_something, 'the message') + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Prefer using `refute_nil(obj.do_something, 'the message')` over `refute_equal(nil, obj.do_something, 'the message')`. + end + end + RUBY + + assert_correction(<<~RUBY, @cop) + class FooTest < Minitest::Test + def test_do_something + refute_nil(obj.do_something, 'the message') + end + end + RUBY + end + + def test_adds_offense_for_use_of_refute_equal_with_a_string_variable_in_message + assert_offense(<<~RUBY, @cop) + class FooTest < Minitest::Test + def test_do_something + message = 'the message' + refute_equal(nil, somestuff, message) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Prefer using `refute_nil(somestuff, message)` over `refute_equal(nil, somestuff, message)`. + end + end + RUBY + + assert_correction(<<~RUBY, @cop) + class FooTest < Minitest::Test + def test_do_something + message = 'the message' + refute_nil(somestuff, message) + end + end + RUBY + end + + def test_adds_offense_for_use_of_refute_equal_with_a_constant_in_message + assert_offense(<<~RUBY, @cop) + class FooTest < Minitest::Test + MESSAGE = 'the message' + + def test_do_something + refute_equal(nil, somestuff, MESSAGE) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Prefer using `refute_nil(somestuff, MESSAGE)` over `refute_equal(nil, somestuff, MESSAGE)`. + end + end + RUBY + + assert_correction(<<~RUBY, @cop) + class FooTest < Minitest::Test + MESSAGE = 'the message' + + def test_do_something + refute_nil(somestuff, MESSAGE) + end + end + RUBY + end + + def test_does_not_offend_if_using_refute_nil + assert_no_offenses(<<~RUBY, @cop) + class FooTest < Minitest::Test + def test_do_something + refute_nil(somestuff) + end + end + RUBY + end +end