Skip to content

Commit

Permalink
Add cop to enfore refute_empty over refute(actual.empty?)
Browse files Browse the repository at this point in the history
  • Loading branch information
abhaynikam committed Oct 1, 2019
1 parent 7a42f9f commit 870b213
Show file tree
Hide file tree
Showing 7 changed files with 183 additions and 0 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@

## master (unreleased)

### New features

* [#20](https://github.com/rubocop-hq/rubocop-minitest/pull/20): Add new `Minitest/RefuteEmpty` cop. ([@abhaynikam][])

## 0.2.1 (2019-09-24)

### Bug fixes
Expand Down
6 changes: 6 additions & 0 deletions config/default.yml
Original file line number Diff line number Diff line change
Expand Up @@ -31,3 +31,9 @@ Minitest/RefuteNil:
StyleGuide: 'https://github.com/rubocop-hq/minitest-style-guide#refute-nil'
Enabled: true
VersionAdded: '0.2'

Minitest/RefuteEmpty:
Description: 'Check if your test uses `refute_empty` instead of `refute(actual.empty?)`.'
StyleGuide: 'https://github.com/rubocop-hq/minitest-style-guide#refute-empty'
Enabled: true
VersionAdded: '0.3'
50 changes: 50 additions & 0 deletions lib/rubocop/cop/minitest/refute_empty.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
# frozen_string_literal: true

module RuboCop
module Cop
module Minitest
# Check if your test uses `refute_empty` instead of `refute(actual.empty?)`.
#
# @example
# # bad
# refute(actual.empty?)
# refute(actual.empty?, 'the message')
#
# # good
# refute_empty(actual)
# refute_empty(actual, 'the message')
#
class RefuteEmpty < Cop
MSG = 'Prefer using `refute_empty(%<arguments>s)` over ' \
'`refute(%<receiver>s)`.'

def_node_matcher :refute_with_empty, <<~PATTERN
(send nil? :refute $(send $_ :empty?) $...)
PATTERN

def on_send(node)
refute_with_empty(node) do |first_receiver_arg, actual, rest_receiver_arg|
message = rest_receiver_arg.first

arguments = [actual.source, message&.source].compact.join(', ')
receiver = [first_receiver_arg.source, message&.source].compact.join(', ')

offense_message = format(MSG, arguments: arguments, receiver: receiver)
add_offense(node, message: offense_message)
end
end

def autocorrect(node)
lambda do |corrector|
refute_with_empty(node) do |_first_receiver_arg, actual, rest_receiver_arg|
message = rest_receiver_arg.first

replacement = [actual.source, message&.source].compact.join(', ')
corrector.replace(node.loc.expression, "refute_empty(#{replacement})")
end
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 @@ -4,4 +4,5 @@
require_relative 'minitest/assert_nil'
require_relative 'minitest/assert_includes'
require_relative 'minitest/assert_truthy'
require_relative 'minitest/refute_empty'
require_relative 'minitest/refute_nil'
1 change: 1 addition & 0 deletions manual/cops.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
* [Minitest/AssertIncludes](cops_minitest.md#minitestassertincludes)
* [Minitest/AssertNil](cops_minitest.md#minitestassertnil)
* [Minitest/AssertTruthy](cops_minitest.md#minitestasserttruthy)
* [Minitest/RefuteEmpty](cops_minitest.md#minitestrefuteempty)
* [Minitest/RefuteNil](cops_minitest.md#minitestrefutenil)

<!-- END_COP_LIST -->
20 changes: 20 additions & 0 deletions manual/cops_minitest.md
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,26 @@ assert(actual, 'the message')

* [https://github.com/rubocop-hq/minitest-style-guide#assert-truthy](https://github.com/rubocop-hq/minitest-style-guide#assert-truthy)

## Minitest/RefuteEmpty

Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged
--- | --- | --- | --- | ---
Enabled | Yes | Yes | - | -

Check if your test uses `refute_empty` instead of `refute(actual.empty?)`.

### Examples

```ruby
# bad
assert(actual.empty?)
assert(actual.empty?, 'the message')

# good
refute_empty(actual)
refute_empty(actual, 'the message')
```

## Minitest/RefuteNil

Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged
Expand Down
101 changes: 101 additions & 0 deletions test/rubocop/cop/minitest/refute_empty_test.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
# frozen_string_literal: true

require 'test_helper'

class RefuteEmptyTest < Minitest::Test
def setup
@cop = RuboCop::Cop::Minitest::RefuteEmpty.new
end

def test_registers_offense_when_using_refute_with_empty
assert_offense(<<~RUBY, @cop)
class FooTest < Minitest::Test
def test_do_something
refute(somestuff.empty?)
^^^^^^^^^^^^^^^^^^^^^^^^ Prefer using `refute_empty(somestuff)` over `refute(somestuff.empty?)`.
end
end
RUBY

assert_correction(<<~RUBY, @cop)
class FooTest < Minitest::Test
def test_do_something
refute_empty(somestuff)
end
end
RUBY
end

def test_registers_offense_when_using_refute_with_empty_and_string_message
assert_offense(<<~RUBY, @cop)
class FooTest < Minitest::Test
def test_do_something
refute(somestuff.empty?, 'the message')
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Prefer using `refute_empty(somestuff, 'the message')` over `refute(somestuff.empty?, 'the message')`.
end
end
RUBY

assert_correction(<<~RUBY, @cop)
class FooTest < Minitest::Test
def test_do_something
refute_empty(somestuff, 'the message')
end
end
RUBY
end

def test_registers_offense_when_using_refute_with_empty_and_variable_message
assert_offense(<<~RUBY, @cop)
class FooTest < Minitest::Test
def test_do_something
message = 'the message'
refute(somestuff.empty?, message)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Prefer using `refute_empty(somestuff, message)` over `refute(somestuff.empty?, message)`.
end
end
RUBY

assert_correction(<<~RUBY, @cop)
class FooTest < Minitest::Test
def test_do_something
message = 'the message'
refute_empty(somestuff, message)
end
end
RUBY
end

def test_registers_offense_when_using_refute_with_empty_and_constant_message
assert_offense(<<~RUBY, @cop)
class FooTest < Minitest::Test
MESSAGE = 'the message'
def test_do_something
refute(somestuff.empty?, MESSAGE)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Prefer using `refute_empty(somestuff, MESSAGE)` over `refute(somestuff.empty?, MESSAGE)`.
end
end
RUBY

assert_correction(<<~RUBY, @cop)
class FooTest < Minitest::Test
MESSAGE = 'the message'
def test_do_something
refute_empty(somestuff, MESSAGE)
end
end
RUBY
end

def refute_empty_method
assert_no_offenses(<<~RUBY, @cop)
class FooTest < Minitest::Test
def test_do_something
refute_empty(somestuff)
end
end
RUBY
end
end

0 comments on commit 870b213

Please sign in to comment.