Skip to content

Commit 8ee8c41

Browse files
committed
Add new RSpec/IdenticalEqualityAssertion cop
Closes #1130
1 parent 956f3b5 commit 8ee8c41

File tree

7 files changed

+138
-0
lines changed

7 files changed

+138
-0
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22

33
## Master (Unreleased)
44

5+
* Add new `RSpec/IdenticalEqualityAssertion` cop. ([@tejasbubane][])
6+
57
## 2.2.0 (2021-02-02)
68

79
* Fix `HooksBeforeExamples`, `LeadingSubject`, `LetBeforeExamples` and `ScatteredLet` autocorrection to take into account inline comments and comments immediately before the moved node. ([@Darhazer][])

config/default.yml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -349,6 +349,12 @@ RSpec/HooksBeforeExamples:
349349
VersionAdded: '1.29'
350350
StyleGuide: https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/HooksBeforeExamples
351351

352+
RSpec/IdenticalEqualityAssertion:
353+
Description: Checks for equality assertions with identical expressions on both sides.
354+
Enabled: pending
355+
VersionAdded: '2.3'
356+
StyleGuide: https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/IdenticalEqualityAssertion
357+
352358
RSpec/ImplicitBlockExpectation:
353359
Description: Check that implicit block expectation syntax is not used.
354360
Enabled: true

docs/modules/ROOT/pages/cops.adoc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
* xref:cops_rspec.adoc#rspecfocus[RSpec/Focus]
3636
* xref:cops_rspec.adoc#rspechookargument[RSpec/HookArgument]
3737
* xref:cops_rspec.adoc#rspechooksbeforeexamples[RSpec/HooksBeforeExamples]
38+
* xref:cops_rspec.adoc#rspecidenticalequalityassertion[RSpec/IdenticalEqualityAssertion]
3839
* xref:cops_rspec.adoc#rspecimplicitblockexpectation[RSpec/ImplicitBlockExpectation]
3940
* xref:cops_rspec.adoc#rspecimplicitexpect[RSpec/ImplicitExpect]
4041
* xref:cops_rspec.adoc#rspecimplicitsubject[RSpec/ImplicitSubject]

docs/modules/ROOT/pages/cops_rspec.adoc

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1690,6 +1690,37 @@ end
16901690

16911691
* https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/HooksBeforeExamples
16921692

1693+
== RSpec/IdenticalEqualityAssertion
1694+
1695+
|===
1696+
| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged
1697+
1698+
| Pending
1699+
| Yes
1700+
| No
1701+
| 2.3
1702+
| -
1703+
|===
1704+
1705+
Checks for equality assertions with identical expressions on both sides.
1706+
1707+
=== Examples
1708+
1709+
[source,ruby]
1710+
----
1711+
# bad
1712+
expect(foo.bar).to eq(foo.bar)
1713+
expect(foo.bar).to eql(foo.bar)
1714+
1715+
# good
1716+
expect(foo.bar).to eq(2)
1717+
expect(foo.bar).to eql(2)
1718+
----
1719+
1720+
=== References
1721+
1722+
* https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/IdenticalEqualityAssertion
1723+
16931724
== RSpec/ImplicitBlockExpectation
16941725

16951726
|===
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
# frozen_string_literal: true
2+
3+
module RuboCop
4+
module Cop
5+
module RSpec
6+
# Checks for equality assertions with identical expressions on both sides.
7+
#
8+
# @example
9+
#
10+
# # bad
11+
# expect(foo.bar).to eq(foo.bar)
12+
# expect(foo.bar).to eql(foo.bar)
13+
#
14+
# # good
15+
# expect(foo.bar).to eq(2)
16+
# expect(foo.bar).to eql(2)
17+
#
18+
class IdenticalEqualityAssertion < Base
19+
MSG = 'Identical expressions on both sides of the equality may indicate a flawed test.'
20+
RESTRICT_ON_SEND = %i[to].freeze
21+
22+
def_node_matcher :equality_check?, <<~PATTERN
23+
(send (send nil? :expect $_) :to
24+
{(send nil? {:eql :eq :be} $_)
25+
(send (send nil? :be) :== $_)})
26+
PATTERN
27+
28+
def on_send(node)
29+
equality_check?(node) do |left, right|
30+
return unless left == right
31+
32+
add_offense(node)
33+
end
34+
end
35+
end
36+
end
37+
end
38+
end

lib/rubocop/cop/rspec_cops.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@
4747
require_relative 'rspec/focus'
4848
require_relative 'rspec/hook_argument'
4949
require_relative 'rspec/hooks_before_examples'
50+
require_relative 'rspec/identical_equality_assertion'
5051
require_relative 'rspec/implicit_block_expectation'
5152
require_relative 'rspec/implicit_expect'
5253
require_relative 'rspec/implicit_subject'
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
# frozen_string_literal: true
2+
3+
RSpec.describe RuboCop::Cop::RSpec::IdenticalEqualityAssertion do
4+
let(:msg) { 'Identical expressions on both sides of the equality may indicate a flawed test.' }
5+
6+
it 'registers an offense when using identical expressions with `eq`' do
7+
expect_offense(<<~RUBY)
8+
expect(foo.bar).to eq(foo.bar)
9+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ #{msg}
10+
RUBY
11+
end
12+
13+
it 'registers an offense when using identical expressions with `eql`' do
14+
expect_offense(<<~RUBY)
15+
expect(foo.bar.baz).to eql(foo.bar.baz)
16+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ #{msg}
17+
RUBY
18+
end
19+
20+
it 'registers an offense for trivial constants' do
21+
expect_offense(<<~RUBY)
22+
expect(42).to eq(42)
23+
^^^^^^^^^^^^^^^^^^^^ #{msg}
24+
RUBY
25+
end
26+
27+
it 'registers an offense for complex constants' do
28+
expect_offense(<<~RUBY)
29+
expect({a: 1, b: :b}).to eql({a: 1, b: :b})
30+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ #{msg}
31+
RUBY
32+
end
33+
34+
it 'registers an offense for identical expression with be' do
35+
expect_offense(<<~RUBY)
36+
expect(foo.bar).to be(foo.bar)
37+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ #{msg}
38+
RUBY
39+
end
40+
41+
it 'registers an offense for identical expression with be ==' do
42+
expect_offense(<<~RUBY)
43+
expect(foo.bar).to be == foo.bar
44+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ #{msg}
45+
RUBY
46+
end
47+
48+
it 'does not register offense for different expressions' do
49+
expect_no_offenses(<<~RUBY)
50+
expect(foo.bar).to eq(bar.foo)
51+
RUBY
52+
end
53+
54+
it 'checks for whole expression' do
55+
expect_no_offenses(<<~RUBY)
56+
expect(Foo.new(1).foo).to eql(Foo.new(2).bar)
57+
RUBY
58+
end
59+
end

0 commit comments

Comments
 (0)