Skip to content

Commit

Permalink
[Fix rubocop#157] Add new Minitest/EmptyLinesBeforeAssertionMethod cop
Browse files Browse the repository at this point in the history
Fixes rubocop#157.

This PR adds new `Minitest/EmptyLinesBeforeAssertionMethod` cop.

This cop enforces empty line before assertion method.

```ruby
# bad
do_something
assert_equal(expected, actual)

# good
do_something

assert_equal(expected, actual)
```
  • Loading branch information
koic committed Mar 10, 2022
1 parent b784f45 commit e2481fb
Show file tree
Hide file tree
Showing 6 changed files with 241 additions and 2 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/EmptyLinesBeforeAssertionMethod` cop. ([@koic][])
5 changes: 5 additions & 0 deletions config/default.yml
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,11 @@ Minitest/AssertWithExpectedArgument:
Safe: false
VersionAdded: '0.11'

Minitest/EmptyLinesBeforeAssertionMethod:
Description: 'Add empty line after assertion method.'
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_lines_before_assertion_method.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
# This cop enforces empty line before assertion method.
#
# @example
#
# # bad
# do_something
# assert_equal(expected, actual)
#
# # good
# do_something
#
# assert_equal(expected, actual)
#
class EmptyLinesBeforeAssertionMethod < 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 @@ -21,6 +21,7 @@
require_relative 'minitest/assert_respond_to'
require_relative 'minitest/assert_silent'
require_relative 'minitest/assert_truthy'
require_relative 'minitest/empty_lines_before_assertion_method'
require_relative 'minitest/global_expectations'
require_relative 'minitest/literal_as_actual_argument'
require_relative 'minitest/multiple_assertions'
Expand Down
4 changes: 2 additions & 2 deletions test/project_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -52,8 +52,8 @@ def test_entry_has_an_issue_number_prefixed_with_sharp
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}$}
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_lines_before_assertion_method_test.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,156 @@
# frozen_string_literal: true

require 'test_helper'

class EmptyLinesBeforeAssertionMethodTest < 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_method
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_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 e2481fb

Please sign in to comment.