Skip to content

Commit

Permalink
Handle assertions in conditionals branches in `Minitest/MultipleAsser…
Browse files Browse the repository at this point in the history
…tions` cop
  • Loading branch information
fatkodima committed Apr 16, 2023
1 parent 2d049d1 commit 774da8b
Show file tree
Hide file tree
Showing 3 changed files with 205 additions and 6 deletions.
1 change: 1 addition & 0 deletions changelog/change_handle_assertions_in_conditionals.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
* [#249](https://github.com/rubocop/rubocop-minitest/pull/249): Handle assertions in conditionals branches in `Minitest/MultipleAssertions` cop. ([@fatkodima][])
33 changes: 32 additions & 1 deletion lib/rubocop/cop/minitest/multiple_assertions.rb
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,14 @@ module Minitest
# def test_another_asserts_once
# assert_empty(array)
# end
#
# def test_conditional_assertion
# if condition
# assert foo
# else
# assert bar
# end
# end
# end
#
class MultipleAssertions < Base
Expand All @@ -36,7 +44,7 @@ def on_class(class_node)
return unless test_class?(class_node)

test_cases(class_node).each do |node|
assertions_count = assertions_count(node)
assertions_count = assertions_count(node.body)

next unless assertions_count > max_assertions

Expand All @@ -49,6 +57,29 @@ def on_class(class_node)

private

def assertions_count(node)
return 0 unless node.is_a?(RuboCop::AST::Node)

assertions =
case node.type
when :if, :case
assertions_count_in_branches(node.branches)
when :rescue
assertions_count(node.body) + assertions_count_in_branches(node.branches)
when :block
assertions_count(node.body)
else
node.each_child_node.sum { |child| assertions_count(child) }
end

assertions += 1 if assertion_method?(node)
assertions
end

def assertions_count_in_branches(branches)
branches.map { |branch| assertions_count(branch) }.max
end

def max_assertions
Integer(cop_config.fetch('Max', 3))
end
Expand Down
177 changes: 172 additions & 5 deletions test/rubocop/cop/minitest/multiple_assertions_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -93,26 +93,193 @@ def test_generates_a_todo_based_on_the_worst_violation
class FooTest < Minitest::Test
def test_asserts_once
assert_equal(foo, bar)
assert_equal(baz, bar)
end
def test_asserts_two_times
def test_asserts_four_times
assert_equal(foo, bar)
assert_equal(foo, bar)
assert_equal(foo, bar)
assert_equal(foo, bar)
assert_equal(baz, bar)
end
end
RUBY

assert_equal({ 'Max' => 2 }, @cop.config_to_allow_offenses[:exclude_limit])
assert_equal({ 'Max' => 4 }, @cop.config_to_allow_offenses[:exclude_limit])
end

def test_registers_offense_when_multiple_assertions_in_the_test_block
assert_offense(<<~RUBY)
class FooTest < ActiveSupport::TestCase
test 'something' do
^^^^^^^^^^^^^^^^^^^ Test case has too many assertions [2/1].
assert_equal(foo, bar)
assert_empty(array)
end
end
RUBY
end

def test_does_not_register_offense_when_multiple_expectations_in_the_test_block
def test_registers_offense_when_multiple_assertions_inside_conditional
assert_offense(<<~RUBY)
class FooTest < ActiveSupport::TestCase
test 'something' do
^^^^^^^^^^^^^^^^^^^ Test case has too many assertions [2/1].
if condition
assert_equal(foo, bar)
assert_empty(array)
else
assert_equal(foo, baz)
end
end
end
RUBY
end

def test_does_not_register_offense_when_single_assertion_inside_conditional
assert_no_offenses(<<~RUBY)
class FooTest < ActiveSupport::TestCase
test 'something' do
if condition
assert_equal(foo, bar)
else
assert_equal(foo, baz)
end
end
end
RUBY
end

def test_registers_offense_when_multiple_expectations_inside_case
assert_offense(<<~RUBY)
class FooTest < ActiveSupport::TestCase
test 'something' do
^^^^^^^^^^^^^^^^^^^ Test case has too many assertions [3/1].
case
when condition1
assert_equal(foo, bar)
assert_empty(array)
when condition2
assert_equal(foo, bar)
assert_empty(array)
assert_equal(foo, baz)
else
assert_equal(foo, zoo)
end
end
end
RUBY
end

def test_does_not_register_offense_when_single_assertion_inside_case
assert_no_offenses(<<~RUBY)
class FooTest < ActiveSupport::TestCase
test 'something' do
case
when condition1
assert_equal(foo, bar)
else
assert_equal(foo, zoo)
end
end
end
RUBY
end

def test_registers_offense_when_multiple_expectations_inside_rescue
assert_offense(<<~RUBY)
class FooTest < ActiveSupport::TestCase
test 'something' do
^^^^^^^^^^^^^^^^^^^ Test case has too many assertions [3/1].
do_something
rescue Foo
assert_equal(foo, bar)
assert_empty(array)
rescue Bar
assert_equal(foo, bar)
assert_empty(array)
assert_equal(foo, baz)
end
end
RUBY
end

def test_does_not_register_offense_when_single_assertion_inside_rescue
assert_no_offenses(<<~RUBY)
class FooTest < ActiveSupport::TestCase
test 'something' do
do_something
rescue Foo
assert_equal(foo, bar)
end
end
RUBY
end

def test_registers_offense_when_complex_structure_with_multiple_assertions
configure_max_assertions(2)

assert_offense(<<~RUBY)
class FooTest < ActiveSupport::TestCase
test 'something' do
^^^^^^^^^^^^^^^^^^^ Test case has too many assertions [4/2].
if condition1
assert foo
elsif condition2
assert foo
else
begin
do_something
assert foo
rescue Foo
assert foo
assert foo
rescue Bar
# noop
rescue Zoo
case
when condition
assert foo
assert foo
assert foo
else
assert foo
assert foo
end
else
assert foo
end
end
end
end
RUBY
end

def test_does_not_register_offense_when_complex_structure_with_single_assertion
assert_no_offenses(<<~RUBY)
class FooTest < ActiveSupport::TestCase
test 'something' do
if condition1
assert foo
elsif condition2
assert foo
else
begin
do_something
rescue Foo
assert foo
rescue Bar
# noop
rescue Zoo
case
when condition
assert foo
else
assert foo
end
else
assert foo
end
end
end
end
RUBY
Expand Down

0 comments on commit 774da8b

Please sign in to comment.