Skip to content

Commit

Permalink
Merge pull request #163 from koic/add_new_minitest_empty_line_before_…
Browse files Browse the repository at this point in the history
…assertion_method_cop

[Fix #157] Add new `Minitest/EmptyLineBeforeAssertionMethods` cop
  • Loading branch information
koic authored Oct 15, 2022
2 parents 6e78333 + 6d8a9e7 commit 11f5529
Show file tree
Hide file tree
Showing 6 changed files with 240 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
* [#157](https://github.com/rubocop/rubocop-minitest/issues/157): Add new `Minitest/EmptyLineBeforeAssertionMethods` cop. ([@koic][])
5 changes: 5 additions & 0 deletions config/default.yml
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,11 @@ Minitest/DuplicateTestRun:
Enabled: pending
VersionAdded: '0.19'

Minitest/EmptyLineBeforeAssertionMethods:
Description: 'Add empty line before assertion methods.'
Enabled: pending
VersionAdded: '<<next>>'

Minitest/GlobalExpectations:
Description: 'This cop checks for deprecated global expectations.'
StyleGuide: 'https://minitest.rubystyle.guide#global-expectations'
Expand Down
76 changes: 76 additions & 0 deletions lib/rubocop/cop/minitest/empty_line_before_assertion_methods.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
# frozen_string_literal: true

module RuboCop
module Cop
module Minitest
# Enforces empty line before assertion methods because it separates assertion phase.
#
# @example
#
# # bad
# do_something
# assert_equal(expected, actual)
#
# # good
# do_something
#
# assert_equal(expected, actual)
#
class EmptyLineBeforeAssertionMethods < Base
include MinitestExplorationHelpers
extend AutoCorrector

MSG = 'Add empty line before assertion.'

def on_send(node)
return unless assertion_method?(node)
return unless (previous_line_node = node.left_sibling)
return if accept_previous_line?(previous_line_node, node)

previous_line_node = previous_line_node.arguments.last if use_heredoc_argument?(previous_line_node)
return unless no_empty_line?(previous_line_node, node)

register_offense(node, previous_line_node)
end

private

def accept_previous_line?(previous_line_node, node)
return true if previous_line_node.args_type? || node.parent.basic_conditional?

previous_line_node.send_type? && assertion_method?(previous_line_node)
end

def use_heredoc_argument?(node)
node.respond_to?(:arguments) && heredoc?(node.arguments.last)
end

def heredoc?(last_argument)
last_argument.respond_to?(:heredoc?) && last_argument.heredoc?
end

def no_empty_line?(previous_line_node, node)
previous_line = if heredoc?(previous_line_node)
previous_line_node.loc.heredoc_end.line
else
previous_line_node.loc.last_line
end

previous_line + 1 == node.loc.line
end

def register_offense(node, previous_line_node)
add_offense(node) do |corrector|
range = if heredoc?(previous_line_node)
previous_line_node.loc.heredoc_end
else
previous_line_node
end

corrector.insert_after(range, "\n")
end
end
end
end
end
end
1 change: 1 addition & 0 deletions lib/rubocop/cop/minitest_cops.rb
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
require_relative 'minitest/assert_silent'
require_relative 'minitest/assert_truthy'
require_relative 'minitest/duplicate_test_run'
require_relative 'minitest/empty_line_before_assertion_methods'
require_relative 'minitest/global_expectations'
require_relative 'minitest/literal_as_actual_argument'
require_relative 'minitest/multiple_assertions'
Expand Down
1 change: 1 addition & 0 deletions test/project_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ def test_entry_has_a_valid_url
@issues.each do |issue|
number = issue[:number].gsub(/\D/, '')
pattern = %r{^https://github\.com/rubocop/rubocop-minitest/(?:issues|pull)/#{number}$}

assert_match(pattern, issue[:url])
end
end
Expand Down
156 changes: 156 additions & 0 deletions test/rubocop/cop/minitest/empty_line_before_assertion_methods_test.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,156 @@
# frozen_string_literal: true

require 'test_helper'

class EmptyLineBeforeAssertionMethodsTest < Minitest::Test
def test_registers_offense_when_using_method_call_before_assertion_method
assert_offense(<<~RUBY)
def test_do_something
do_something
assert_equal(expected, actual)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Add empty line before assertion.
end
RUBY

assert_correction(<<~RUBY)
def test_do_something
do_something
assert_equal(expected, actual)
end
RUBY
end

def test_registers_offense_when_using_method_call_with_line_breaked_args_before_assertion_method
assert_offense(<<~RUBY)
def test_do_something
do_something(
foo,
bar
)
assert_equal(expected, actual)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Add empty line before assertion.
end
RUBY

assert_correction(<<~RUBY)
def test_do_something
do_something(
foo,
bar
)
assert_equal(expected, actual)
end
RUBY
end

def test_registers_offense_when_using_heredoc_before_assertion_method
assert_offense(<<~RUBY)
def test_do_something
<<~EOS
text
EOS
assert_equal(expected, actual)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Add empty line before assertion.
end
RUBY

assert_correction(<<~RUBY)
def test_do_something
<<~EOS
text
EOS
assert_equal(expected, actual)
end
RUBY
end

def test_registers_offense_when_using_method_call_with_heredoc_arg_before_assertion_method
assert_offense(<<~RUBY)
def test_do_something
do_something(<<~EOS)
text
EOS
assert_equal(expected, actual)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Add empty line before assertion.
end
RUBY

assert_correction(<<~RUBY)
def test_do_something
do_something(<<~EOS)
text
EOS
assert_equal(expected, actual)
end
RUBY
end

def test_does_not_register_offense_when_using_empty_line_before_assertion_methods
assert_no_offenses(<<~RUBY)
def test_do_something
do_something
assert_equal(expected, actual)
end
RUBY
end

def test_does_not_register_offense_when_using_assertion_method_at_top_level
assert_no_offenses(<<~RUBY)
assert_equal(expected, actual)
RUBY
end

def test_does_not_register_offense_when_using_assertion_method_at_top_of_block_body
assert_no_offenses(<<~RUBY)
def test_do_something
do_something do
assert_equal(expected, actual)
end
end
RUBY
end

def test_does_not_register_offense_when_using_assertion_method_at_top_of_if_body
assert_no_offenses(<<~RUBY)
def test_do_something
if condition
assert_equal(expected, actual)
end
end
RUBY
end

def test_does_not_register_offense_when_using_assertion_method_at_top_of_while_body
assert_no_offenses(<<~RUBY)
def test_do_something
while condition
assert_equal(expected, actual)
end
end
RUBY
end

def test_does_not_register_offense_when_using_assertion_method_at_top_of_until_body
assert_no_offenses(<<~RUBY)
def test_do_something
until condition
assert_equal(expected, actual)
end
end
RUBY
end

def test_does_not_register_offense_when_using_assertion_methods_which_are_continuous_without_empty_line
assert_no_offenses(<<~RUBY)
def test_do_something
assert_not foo
assert bar
end
RUBY
end
end

0 comments on commit 11f5529

Please sign in to comment.