Skip to content

Commit 9eb23a6

Browse files
authored
Merge pull request #1940 from r7kamura/unspecified-exception-chain
Fix false-negative for `UnspecifiedException` when matcher is chained
2 parents ce4cd77 + 60199ba commit 9eb23a6

File tree

3 files changed

+49
-15
lines changed

3 files changed

+49
-15
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+
- Fix false-negative for `UnspecifiedException` when matcher is chained. ([@r7kamura])
6+
57
## 3.0.3 (2024-07-12)
68

79
- Add support for Unicode RIGHT SINGLE QUOTATION MARK in `RSpec/ExampleWording`. ([@jdufresne])

lib/rubocop/cop/rspec/unspecified_exception.rb

Lines changed: 20 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -32,34 +32,39 @@ module RSpec
3232
#
3333
class UnspecifiedException < Base
3434
MSG = 'Specify the exception being captured'
35-
RESTRICT_ON_SEND = %i[to].freeze
3635

37-
# @!method empty_raise_error_or_exception(node)
38-
def_node_matcher :empty_raise_error_or_exception, <<~PATTERN
39-
(send
40-
(block
41-
(send nil? :expect) ...)
42-
:to
43-
(send nil? {:raise_error :raise_exception})
44-
)
36+
RESTRICT_ON_SEND = %i[
37+
raise_exception
38+
raise_error
39+
].freeze
40+
41+
# @!method expect_to?(node)
42+
def_node_matcher :expect_to?, <<~PATTERN
43+
(send (block (send nil? :expect) ...) :to ...)
4544
PATTERN
4645

4746
def on_send(node)
4847
return unless empty_exception_matcher?(node)
4948

50-
add_offense(node.children.last)
49+
add_offense(node)
5150
end
5251

5352
private
5453

5554
def empty_exception_matcher?(node)
56-
empty_raise_error_or_exception(node) && !block_with_args?(node.parent)
57-
end
55+
return false if node.arguments? || node.block_literal?
5856

59-
def block_with_args?(node)
60-
return false unless node&.block_type?
57+
expect_to = find_expect_to(node)
58+
return false unless expect_to
59+
return false if expect_to.block_node&.arguments?
60+
61+
true
62+
end
6163

62-
node.arguments?
64+
def find_expect_to(node)
65+
node.each_ancestor(:send).find do |ancestor|
66+
expect_to?(ancestor)
67+
end
6368
end
6469
end
6570
end

spec/rubocop/cop/rspec/unspecified_exception_spec.rb

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -171,5 +171,32 @@
171171
}.to raise_exception(my_exception)
172172
RUBY
173173
end
174+
175+
it 'detects chained offenses' do
176+
expect_offense(<<~RUBY)
177+
expect {
178+
foo
179+
}.to raise_exception.and change { bar }
180+
^^^^^^^^^^^^^^^ Specify the exception being captured
181+
RUBY
182+
end
183+
184+
it 'detects more chained offenses' do
185+
expect_offense(<<~RUBY)
186+
expect {
187+
foo
188+
}.to raise_exception.and change { bar }.and change { baz }
189+
^^^^^^^^^^^^^^^ Specify the exception being captured
190+
RUBY
191+
end
192+
193+
it 'detects more complex chained offenses' do
194+
expect_offense(<<~RUBY)
195+
expect {
196+
foo
197+
}.to change { bar }.and raise_exception.and change { baz }
198+
^^^^^^^^^^^^^^^ Specify the exception being captured
199+
RUBY
200+
end
174201
end
175202
end

0 commit comments

Comments
 (0)