Skip to content

Commit

Permalink
Add new RSpec/MinitestAssertions cop
Browse files Browse the repository at this point in the history
Resolve: #1485
  • Loading branch information
ydah committed Nov 18, 2022
1 parent 4b98ef6 commit 392f388
Show file tree
Hide file tree
Showing 8 changed files with 174 additions and 0 deletions.
2 changes: 2 additions & 0 deletions .rubocop.yml
Original file line number Diff line number Diff line change
Expand Up @@ -128,3 +128,5 @@ RSpec/SubjectDeclaration:
Enabled: true
RSpec/VerifiedDoubleReference:
Enabled: true
RSpec/MinitestAssertions:
Enabled: true
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

## Master (Unreleased)

- Add new `RSpec/MinitestAssertions` cop. ([@ydah])
- Add new `RSpec/FactoryBot/FactoryNameStyle` cop. ([@ydah])
- Fix wrong autocorrection in `n_times` style on `RSpec/FactoryBot/CreateList`. ([@r7kamura])
- Fix a false positive for `RSpec/FactoryBot/ConsistentParenthesesStyle` when using `generate` with multiple arguments. ([@ydah])
Expand Down
6 changes: 6 additions & 0 deletions config/default.yml
Original file line number Diff line number Diff line change
Expand Up @@ -573,6 +573,12 @@ RSpec/MessageSpies:
VersionAdded: '1.9'
Reference: https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/MessageSpies

RSpec/MinitestAssertions:
Description: Check if using Minitest matchers.
Enabled: pending
VersionAdded: "<<next>>"
Reference: https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/MinitestAssertions

RSpec/MissingExampleGroupArgument:
Description: Checks that the first argument to an example group is not empty.
Enabled: true
Expand Down
1 change: 1 addition & 0 deletions docs/modules/ROOT/pages/cops.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@
* xref:cops_rspec.adoc#rspecmessagechain[RSpec/MessageChain]
* xref:cops_rspec.adoc#rspecmessageexpectation[RSpec/MessageExpectation]
* xref:cops_rspec.adoc#rspecmessagespies[RSpec/MessageSpies]
* xref:cops_rspec.adoc#rspecminitestassertions[RSpec/MinitestAssertions]
* xref:cops_rspec.adoc#rspecmissingexamplegroupargument[RSpec/MissingExampleGroupArgument]
* xref:cops_rspec.adoc#rspecmultipledescribes[RSpec/MultipleDescribes]
* xref:cops_rspec.adoc#rspecmultipleexpectations[RSpec/MultipleExpectations]
Expand Down
33 changes: 33 additions & 0 deletions docs/modules/ROOT/pages/cops_rspec.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -2946,6 +2946,39 @@ do_something

* https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/MessageSpies

== RSpec/MinitestAssertions

|===
| Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed

| Pending
| Yes
| Yes
| <<next>>
| -
|===

Check if using Minitest matchers.

=== Examples

[source,ruby]
----
# bad
assert_equal(a, b)
assert_equal a, b, "must be equal"
refute_equal(a, b)
# good
expect(a).to eq(b)
expect(a).to(eq(b), "must be equal")
expect(a).not_to eq(b)
----

=== References

* https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/MinitestAssertions

== RSpec/MissingExampleGroupArgument

|===
Expand Down
57 changes: 57 additions & 0 deletions lib/rubocop/cop/rspec/minitest_assertions.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
# frozen_string_literal: true

module RuboCop
module Cop
module RSpec
# Check if using Minitest matchers.
#
# @example
# # bad
# assert_equal(a, b)
# assert_equal a, b, "must be equal"
# refute_equal(a, b)
#
# # good
# expect(a).to eq(b)
# expect(a).to(eq(b), "must be equal")
# expect(a).not_to eq(b)
#
class MinitestAssertions < Base
extend AutoCorrector

MSG = 'Use `%<prefer>s`.'
RESTRICT_ON_SEND = %i[assert_equal refute_equal].freeze

# @!method minitest_assertion(node)
def_node_matcher :minitest_assertion, <<-PATTERN
(send nil? {:assert_equal :refute_equal} $_ $_ $_?)
PATTERN

def on_send(node)
minitest_assertion(node) do |expected, actual, failure_message|
prefer = replacement(node, expected, actual, failure_message.first)
add_offense(node, message: message(prefer)) do |corrector|
corrector.replace(node, prefer)
end
end
end

private

def replacement(node, expected, actual, failure_message)
runner = node.method?(:assert_equal) ? 'to' : 'not_to'
if failure_message.nil?
"expect(#{expected.source}).#{runner} eq(#{actual.source})"
else
"expect(#{expected.source}).#{runner}(eq(#{actual.source}), " \
"#{failure_message.source})"
end
end

def message(prefer)
format(MSG, prefer: prefer)
end
end
end
end
end
1 change: 1 addition & 0 deletions lib/rubocop/cop/rspec_cops.rb
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@
require_relative 'rspec/message_chain'
require_relative 'rspec/message_expectation'
require_relative 'rspec/message_spies'
require_relative 'rspec/minitest_assertions'
require_relative 'rspec/missing_example_group_argument'
require_relative 'rspec/multiple_describes'
require_relative 'rspec/multiple_expectations'
Expand Down
73 changes: 73 additions & 0 deletions spec/rubocop/cop/rspec/minitest_assertions_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
# frozen_string_literal: true

RSpec.describe RuboCop::Cop::RSpec::MinitestAssertions, :config do
it 'registers an offense when using `assert_equal`' do
expect_offense(<<~RUBY)
assert_equal(a, b)
^^^^^^^^^^^^^^^^^^ Use `expect(a).to eq(b)`.
RUBY

expect_correction(<<~RUBY)
expect(a).to eq(b)
RUBY
end

it 'registers an offense when using `assert_equal` with no parentheses' do
expect_offense(<<~RUBY)
assert_equal a, b
^^^^^^^^^^^^^^^^^ Use `expect(a).to eq(b)`.
RUBY

expect_correction(<<~RUBY)
expect(a).to eq(b)
RUBY
end

it 'registers an offense when using `assert_equal` with failure message' do
expect_offense(<<~RUBY)
assert_equal a, b, "must be equal"
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Use `expect(a).to(eq(b), "must be equal")`.
RUBY

expect_correction(<<~RUBY)
expect(a).to(eq(b), "must be equal")
RUBY
end

it 'registers an offense when using `assert_equal` with ' \
'multi-line arguments' do
expect_offense(<<~RUBY)
assert_equal(a,
^^^^^^^^^^^^^^^ Use `expect(a).to(eq(b), "must be equal")`.
b,
"must be equal")
RUBY

expect_correction(<<~RUBY)
expect(a).to(eq(b), "must be equal")
RUBY
end

it 'registers an offense when using `refute_equal`' do
expect_offense(<<~RUBY)
refute_equal a, b
^^^^^^^^^^^^^^^^^ Use `expect(a).not_to eq(b)`.
RUBY

expect_correction(<<~RUBY)
expect(a).not_to eq(b)
RUBY
end

it 'does not register an offense when using `expect(a).to eq(b)`' do
expect_no_offenses(<<~RUBY)
expect(a).to eq(b)
RUBY
end

it 'does not register an offense when using `expect(a).not_to eq(b)`' do
expect_no_offenses(<<~RUBY)
expect(a).not_to eq(b)
RUBY
end
end

0 comments on commit 392f388

Please sign in to comment.