Skip to content

Commit 9df327a

Browse files
committed
feat: support "in_delta" assertions in RSpec/Rails/MinitestAssertions
1 parent 89a45c1 commit 9df327a

File tree

3 files changed

+152
-0
lines changed

3 files changed

+152
-0
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
- Support asserts with messages in `Rspec/BeEmpty`. ([@G-Rath])
66
- Add support for `assert_empty`, `assert_not_empty` and `refute_empty` to `RSpec/Rails/MinitestAssertions`. ([@ydah])
77
- Support correcting some `*_predicate` assertions in `RSpec/Rails/MinitestAssertions`. ([@G-Rath])
8+
- Support correcting `*_in_delta` assertions in `RSpec/Rails/MinitestAssertions`. ([@G-Rath])
89
- Support correcting `*_match` assertions in `RSpec/Rails/MinitestAssertions`. ([@G-Rath])
910
- Support correcting `*_instance_of` assertions in `RSpec/Rails/MinitestAssertions`. ([@G-Rath])
1011
- Support correcting `*_includes` assertions in `RSpec/Rails/MinitestAssertions`. ([@G-Rath])

lib/rubocop/cop/rspec_rails/minitest_assertions.rb

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,36 @@ def assertion
126126
end
127127
end
128128

129+
# :nodoc:
130+
class InDeltaAssertion < BasicAssertion
131+
MATCHERS = %i[
132+
assert_in_delta
133+
assert_not_in_delta
134+
refute_in_delta
135+
].freeze
136+
137+
# @!method self.minitest_assertion(node)
138+
def_node_matcher 'self.minitest_assertion', <<~PATTERN # rubocop:disable InternalAffairs/NodeMatcherDirective
139+
(send nil? {:assert_in_delta :assert_not_in_delta :refute_in_delta} $_ $_ $!{sym str}? $_?)
140+
PATTERN
141+
142+
def self.match(expected, actual, delta, failure_message)
143+
return nil if delta.empty? && !failure_message.empty?
144+
145+
new(expected, actual, delta.first, failure_message.first)
146+
end
147+
148+
def initialize(expected, actual, delta, fail_message)
149+
super(expected, actual, fail_message)
150+
151+
@delta = delta&.source || '0.001'
152+
end
153+
154+
def assertion
155+
"be_within(#{@delta}).of(#{expected})"
156+
end
157+
end
158+
129159
# :nodoc:
130160
class PredicateAssertion < BasicAssertion
131161
MATCHERS = %i[

spec/rubocop/cop/rspec_rails/minitest_assertions_spec.rb

Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -271,6 +271,127 @@
271271
end
272272
end
273273

274+
context 'with in_delta assertions' do
275+
it 'registers an offense when using `assert_in_delta`' do
276+
expect_offense(<<~RUBY)
277+
assert_in_delta(a, b)
278+
^^^^^^^^^^^^^^^^^^^^^ Use `expect(b).to be_within(0.001).of(a)`.
279+
RUBY
280+
281+
expect_correction(<<~RUBY)
282+
expect(b).to be_within(0.001).of(a)
283+
RUBY
284+
end
285+
286+
it 'registers an offense when using `assert_in_delta` with ' \
287+
'no parentheses' do
288+
expect_offense(<<~RUBY)
289+
assert_in_delta a, b
290+
^^^^^^^^^^^^^^^^^^^^ Use `expect(b).to be_within(0.001).of(a)`.
291+
RUBY
292+
293+
expect_correction(<<~RUBY)
294+
expect(b).to be_within(0.001).of(a)
295+
RUBY
296+
end
297+
298+
it 'registers an offense when using `assert_in_delta` with ' \
299+
'a custom delta' do
300+
expect_offense(<<~RUBY)
301+
assert_in_delta a, b, 1
302+
^^^^^^^^^^^^^^^^^^^^^^^ Use `expect(b).to be_within(1).of(a)`.
303+
RUBY
304+
305+
expect_correction(<<~RUBY)
306+
expect(b).to be_within(1).of(a)
307+
RUBY
308+
end
309+
310+
it 'registers an offense when using `assert_in_delta` with ' \
311+
'a custom delta from a variable' do
312+
expect_offense(<<~RUBY)
313+
delta = 1
314+
315+
assert_in_delta a, b, delta
316+
^^^^^^^^^^^^^^^^^^^^^^^^^^^ Use `expect(b).to be_within(delta).of(a)`.
317+
RUBY
318+
319+
expect_correction(<<~RUBY)
320+
delta = 1
321+
322+
expect(b).to be_within(delta).of(a)
323+
RUBY
324+
end
325+
326+
it 'registers an offense when using `assert_in_delta` with ' \
327+
'a custom delta and a failure message' do
328+
expect_offense(<<~RUBY)
329+
assert_in_delta a, b, 1, "must be within delta"
330+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Use `expect(b).to(be_within(1).of(a), "must be within delta")`.
331+
RUBY
332+
333+
expect_correction(<<~RUBY)
334+
expect(b).to(be_within(1).of(a), "must be within delta")
335+
RUBY
336+
end
337+
338+
it 'registers an offense when using `assert_in_delta` with ' \
339+
'multi-line arguments' do
340+
expect_offense(<<~RUBY)
341+
assert_in_delta(a,
342+
^^^^^^^^^^^^^^^^^^ Use `expect(b).to be_within(1).of(a)`.
343+
b,
344+
1)
345+
RUBY
346+
347+
expect_correction(<<~RUBY)
348+
expect(b).to be_within(1).of(a)
349+
RUBY
350+
end
351+
352+
it 'registers an offense when using `assert_not_in_delta`' do
353+
expect_offense(<<~RUBY)
354+
assert_not_in_delta a, b
355+
^^^^^^^^^^^^^^^^^^^^^^^^ Use `expect(b).not_to be_within(0.001).of(a)`.
356+
RUBY
357+
358+
expect_correction(<<~RUBY)
359+
expect(b).not_to be_within(0.001).of(a)
360+
RUBY
361+
end
362+
363+
it 'registers an offense when using `refute_in_delta`' do
364+
expect_offense(<<~RUBY)
365+
refute_in_delta a, b
366+
^^^^^^^^^^^^^^^^^^^^ Use `expect(b).not_to be_within(0.001).of(a)`.
367+
RUBY
368+
369+
expect_correction(<<~RUBY)
370+
expect(b).not_to be_within(0.001).of(a)
371+
RUBY
372+
end
373+
374+
it 'does not register an offense when ' \
375+
'using `expect(b).to be_within(1).of(a)`' do
376+
expect_no_offenses(<<~RUBY)
377+
expect(b).to be_within(1).of(a)
378+
RUBY
379+
end
380+
381+
it 'does not register an offense when ' \
382+
'using `expect(b).not_to be_within(1).of(a)`' do
383+
expect_no_offenses(<<~RUBY)
384+
expect(b).not_to be_within(1).of(a)
385+
RUBY
386+
end
387+
388+
it 'does not register an offense when the delta is missing' do
389+
expect_no_offenses(<<~RUBY)
390+
assert_in_delta a, b, "whoops, we forgot about the actual delta!"
391+
RUBY
392+
end
393+
end
394+
274395
context 'with match assertions' do
275396
it 'registers an offense when using `assert_match`' do
276397
expect_offense(<<~RUBY)

0 commit comments

Comments
 (0)