Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
* [#332](https://github.com/rubocop/rubocop-minitest/issues/332): Fix false positives for `Minitest/NoAssertions` when using matcher methods. ([@koic][])
18 changes: 4 additions & 14 deletions lib/rubocop/cop/minitest/global_expectations.rb
Original file line number Diff line number Diff line change
Expand Up @@ -87,20 +87,10 @@ class GlobalExpectations < Base

MSG = 'Use `%<preferred>s` instead.'

VALUE_MATCHERS = %i[
must_be_empty must_equal must_be_close_to must_be_within_delta
must_be_within_epsilon must_include must_be_instance_of must_be_kind_of
must_match must_be_nil must_be must_respond_to must_be_same_as
path_must_exist path_wont_exist wont_be_empty wont_equal wont_be_close_to
wont_be_within_delta wont_be_within_epsilon wont_include wont_be_instance_of
wont_be_kind_of wont_match wont_be_nil wont_be wont_respond_to wont_be_same_as
].freeze

BLOCK_MATCHERS = %i[
must_output must_pattern_match must_raise must_be_silent must_throw wont_pattern_match
].freeze

RESTRICT_ON_SEND = VALUE_MATCHERS + BLOCK_MATCHERS
VALUE_MATCHERS = MinitestExplorationHelpers::VALUE_MATCHERS
BLOCK_MATCHERS = MinitestExplorationHelpers::BLOCK_MATCHERS

RESTRICT_ON_SEND = MinitestExplorationHelpers::MATCHER_METHODS

# There are aliases for the `_` method - `expect` and `value`
DSL_METHODS = %i[_ expect value].freeze
Expand Down
19 changes: 19 additions & 0 deletions lib/rubocop/cop/minitest/no_assertions.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ module Cop
module Minitest
# Checks if test cases contain any assertion calls.
#
# Matchers such as `must_equal` and `wont_match` are also treated as assertion methods.
#
# @example
# # bad
# class FooTest < Minitest::Test
Expand All @@ -19,6 +21,23 @@ module Minitest
# end
# end
#
# # bad
# class FooTest < ActiveSupport::TestCase
# describe 'foo' do
# it 'test equal' do
# end
# end
# end
#
# # good
# class FooTest < ActiveSupport::TestCase
# describe 'foo' do
# it 'test equal' do
# musts.must_equal expected_musts
# end
# end
# end
#
class NoAssertions < Base
include MinitestExplorationHelpers

Expand Down
26 changes: 21 additions & 5 deletions lib/rubocop/cop/mixin/minitest_exploration_helpers.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,22 @@ module MinitestExplorationHelpers
include DefNode
extend NodePattern::Macros

ASSERTION_PREFIXES = %w[assert refute].freeze
VALUE_MATCHERS = %i[
must_be_empty must_equal must_be_close_to must_be_within_delta
must_be_within_epsilon must_include must_be_instance_of must_be_kind_of
must_match must_be_nil must_be must_respond_to must_be_same_as
path_must_exist path_wont_exist wont_be_empty wont_equal wont_be_close_to
wont_be_within_delta wont_be_within_epsilon wont_include wont_be_instance_of
wont_be_kind_of wont_match wont_be_nil wont_be wont_respond_to wont_be_same_as
].freeze

BLOCK_MATCHERS = %i[
must_output must_pattern_match must_raise must_be_silent must_throw wont_pattern_match
].freeze

MATCHER_METHODS = VALUE_MATCHERS + BLOCK_MATCHERS

ASSERTION_PREFIXES = %i[assert refute].freeze

LIFECYCLE_HOOK_METHODS_IN_ORDER = %i[
before_setup
Expand Down Expand Up @@ -99,17 +114,18 @@ def assertions_count(node)
end
end

# rubocop:disable Metrics/CyclomaticComplexity
def assertion_method?(node)
return false unless node
return assertion_method?(node.expression) if node.assignment? && node.respond_to?(:expression)
return false unless node.type?(:send, :any_block)

ASSERTION_PREFIXES.any? do |prefix|
method_name = node.method_name
method_name = node.method_name
assertion_method = ASSERTION_PREFIXES.any? { |prefix| method_name.start_with?(prefix.to_s) }

method_name.start_with?(prefix) || node.method?(:flunk)
end
assertion_method || node.method?(:flunk) || MATCHER_METHODS.include?(method_name)
end
# rubocop:enable Metrics/CyclomaticComplexity

def lifecycle_hook_method?(node)
node.def_type? && LIFECYCLE_HOOK_METHODS.include?(node.method_name)
Expand Down
24 changes: 24 additions & 0 deletions test/rubocop/cop/minitest/no_assertions_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,30 @@ def test_the_truth
RUBY
end

def test_register_no_offense_if_test_has_must_be_empty_assertion
assert_no_offenses(<<~RUBY)
class FooTest < Minitest::Test
describe 'foo' do
it 'must have good data' do
_(invalid_recs).must_be_empty ->{ do_something }
end
end
end
RUBY
end

def test_register_no_offense_if_test_has_must_include_assertion
assert_no_offenses(<<~RUBY)
class FooTest < Minitest::Test
describe 'foo' do
it 'must include [false, true]' do
value([false, true]).must_include value
end
end
end
RUBY
end

def test_register_no_offense_for_unrelated_methods
assert_no_offenses(<<~RUBY)
class FooTest < Minitest::Test
Expand Down