Skip to content

Commit

Permalink
[Fix rubocop#60] Add new cop Minitest/GlobalExpectations
Browse files Browse the repository at this point in the history
To check against deprecated global expectations. These will be removed
in Minitest 6.

Closes rubocop#60
  • Loading branch information
tejasbubane committed Mar 6, 2020
1 parent 362f517 commit 00113fd
Show file tree
Hide file tree
Showing 7 changed files with 170 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

* [#60](https:/rubocop-hq/rubocop-minitest/pull/60): Add new cop `Minitest/GlobalExpectations` to check for deprecated global expectations. ([@tejasbubane][])

### Bug fixes

* [#58](https:/rubocop-hq/rubocop-minitest/pull/58): Fix a false negative for `Minitest/AssertMatch` and `Minitest/RefuteMatch` when an argument is enclosed in redundant parentheses. ([@koic][])
Expand Down
5 changes: 5 additions & 0 deletions config/default.yml
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,11 @@ Minitest/AssertTruthy:
Enabled: true
VersionAdded: '0.2'

Minitest/GlobalExpectations:
Description: 'This cop checks for deprecated global expectations.'
Enabled: true
VersionAdded: '0.7'

Minitest/RefuteEmpty:
Description: 'This cop enforces to use `refute_empty` instead of using `refute(object.empty?)`.'
StyleGuide: 'https:/rubocop-hq/minitest-style-guide#refute-empty'
Expand Down
74 changes: 74 additions & 0 deletions lib/rubocop/cop/minitest/global_expectations.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
# frozen_string_literal: true

module RuboCop
module Cop
module Minitest
# This Cop checks for deprecated global expectations
# and autocorrects them to use expect format.
#
# @example
# # bad
# n.must_equal 42
# n.wont_match b
#
# # good
# _(n).must_equal 42
# _(n).wont_match b
class GlobalExpectations < Cop
MSG = 'Prefer using `%<corrected>s`.'

VALUE_MATCHERS = %i[
be be_close_to be_empty be_instance_of be_kind_of
be_nil be_same_as be_silent be_within_epsilon equal
include match respond_to must_exist
].map do |matcher|
[:"must_#{matcher}", :"wont_#{matcher}"]
end.flatten.freeze

BLOCK_MATCHERS = %i[must_output must_raise must_throw].freeze

MATCHERS_STR = (VALUE_MATCHERS + BLOCK_MATCHERS).map do |m|
":#{m}"
end.join(' ').freeze

def_node_matcher :global_expectation?, <<~PATTERN
(send (send _ _) {#{MATCHERS_STR}} ...)
PATTERN

def on_send(node)
return unless global_expectation?(node)

message = format(MSG, corrected: correct_suggestion(node))
add_offense(node, message: message)
end

def autocorrect(node)
return unless global_expectation?(node)

lambda do |corrector|
receiver = node.receiver.loc.selector

if BLOCK_MATCHERS.include?(node.method_name)
corrector.insert_before(receiver, '_ { ')
corrector.insert_after(receiver, ' }')
else
corrector.insert_before(receiver, '_(')
corrector.insert_after(receiver, ')')
end
end
end

private

def correct_suggestion(node)
source = node.receiver.source
if BLOCK_MATCHERS.include?(node.method_name)
node.source.sub(source, "_ { #{source} }")
else
node.source.sub(source, "_(#{source})")
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 @@ -11,6 +11,7 @@
require_relative 'minitest/assert_match'
require_relative 'minitest/assert_respond_to'
require_relative 'minitest/assert_truthy'
require_relative 'minitest/global_expectations'
require_relative 'minitest/refute_empty'
require_relative 'minitest/refute_false'
require_relative 'minitest/refute_equal'
Expand Down
1 change: 1 addition & 0 deletions manual/cops.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
* [Minitest/AssertNil](cops_minitest.md#minitestassertnil)
* [Minitest/AssertRespondTo](cops_minitest.md#minitestassertrespondto)
* [Minitest/AssertTruthy](cops_minitest.md#minitestasserttruthy)
* [Minitest/GlobalExpectations](cops_minitest.md#minitestglobalexpectations)
* [Minitest/RefuteEmpty](cops_minitest.md#minitestrefuteempty)
* [Minitest/RefuteEqual](cops_minitest.md#minitestrefuteequal)
* [Minitest/RefuteFalse](cops_minitest.md#minitestrefutefalse)
Expand Down
21 changes: 21 additions & 0 deletions manual/cops_minitest.md
Original file line number Diff line number Diff line change
Expand Up @@ -220,6 +220,27 @@ assert(actual, 'message')

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

## Minitest/GlobalExpectations

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

This Cop checks for deprecated global expectations
and autocorrects them to use expect format.

### Examples

```ruby
# bad
n.must_equal 42
n.wont_match b

# good
_(n).must_equal 42
_(n).wont_match b
```

## Minitest/RefuteEmpty

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

require 'test_helper'

class GlobalExpectationsTest < Minitest::Test
RuboCop::Cop::Minitest::GlobalExpectations::VALUE_MATCHERS.each do |matcher|
define_method(:"test_registers_offense_when_using_global_#{matcher}") do
assert_offense(<<~RUBY)
it 'does something' do
n.#{matcher} 42
#{'^' * (matcher.length + 5)} Prefer using `_(n).#{matcher} 42`.
end
RUBY

assert_correction(<<~RUBY)
it 'does something' do
_(n).#{matcher} 42
end
RUBY
end

define_method(:"test_no_offense_when_using_expect_form_of_#{matcher}") do
assert_no_offenses(<<~RUBY)
it 'does something' do
_(n).#{matcher} 42
end
RUBY
end
end

def test_works_with_chained_method_calls
assert_offense(<<~RUBY)
it 'does something' do
A.foo.bar.must_equal 42
^^^^^^^^^^^^^^^^^^^^^^^ Prefer using `_(A.foo.bar).must_equal 42`.
end
RUBY
end

RuboCop::Cop::Minitest::GlobalExpectations::BLOCK_MATCHERS.each do |matcher|
define_method(:"test_registers_offense_when_using_global_#{matcher}") do
assert_offense(<<~RUBY)
it 'does something' do
n.#{matcher} 42
#{'^' * (matcher.length + 5)} Prefer using `_ { n }.#{matcher} 42`.
end
RUBY

assert_correction(<<~RUBY)
it 'does something' do
_ { n }.#{matcher} 42
end
RUBY
end

define_method(:"test_no_offense_when_using_expect_form_of_#{matcher}") do
assert_no_offenses(<<~RUBY)
it 'does something' do
_ { n }.#{matcher} 42
end
RUBY
end
end
end

0 comments on commit 00113fd

Please sign in to comment.