Skip to content
This repository was archived by the owner on Nov 30, 2024. It is now read-only.

Commit e6455b9

Browse files
committed
Merge pull request #2761 from rspec/fix-message-to_s-loop
Prevent malformed exception messages from exiting RSpec
1 parent 456388f commit e6455b9

File tree

3 files changed

+38
-2
lines changed

3 files changed

+38
-2
lines changed

Changelog.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ Bug Fixes:
1111
* Predicates for pending examples, (in `RSpec::Core::Example`, `#pending?`, `#skipped?` and
1212
`#pending_fixed?`) now return boolean values rather than truthy values.
1313
(Marc-André Lafortune, #2756, #2758)
14+
* Exceptions which have a message which cannot be cast to a string will no longer
15+
cause a crash. (Jon Rowe, #2761)
1416

1517
### 3.9.2 / 2020-05-02
1618
[Full Changelog](http://github.com/rspec/rspec-core/compare/v3.9.1...v3.9.2)

lib/rspec/core/formatters/exception_presenter.rb

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ def formatted_cause(exception)
5151
cause << '--- Caused by: ---'
5252
cause << "#{exception_class_name(last_cause)}:" unless exception_class_name(last_cause) =~ /RSpec/
5353

54-
encoded_string(last_cause.message.to_s).split("\n").each do |line|
54+
encoded_string(exception_message_string(last_cause)).split("\n").each do |line|
5555
cause << " #{line}"
5656
end
5757

@@ -174,10 +174,18 @@ def failure_slash_error_lines
174174
lines
175175
end
176176

177+
# rubocop:disable Lint/RescueException
178+
def exception_message_string(exception)
179+
exception.message.to_s
180+
rescue Exception => other
181+
"A #{exception.class} for which `exception.message.to_s` raises #{other.class}."
182+
end
183+
# rubocop:enable Lint/RescueException
184+
177185
def exception_lines
178186
lines = []
179187
lines << "#{exception_class_name}:" unless exception_class_name =~ /RSpec/
180-
encoded_string(exception.message.to_s).split("\n").each do |line|
188+
encoded_string(exception_message_string(exception)).split("\n").each do |line|
181189
lines << (line.empty? ? line : " #{line}")
182190
end
183191
lines

spec/rspec/core/formatters/exception_presenter_spec.rb

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -260,6 +260,32 @@ def initialize(message, backtrace = [], cause = nil)
260260
EOS
261261
end
262262

263+
it 'will work then the message to_s raises a looped exception' do
264+
raising_to_s_klass =
265+
Class.new do
266+
def to_s
267+
raise StandardError, self
268+
end
269+
end
270+
271+
if RSpec::Support::Ruby.jruby?
272+
expected_error = Java::JavaLang::StackOverflowError
273+
else
274+
expected_error = StandardError
275+
end
276+
277+
incorrect_message_exception = FakeException.new(raising_to_s_klass.new, [])
278+
279+
the_presenter = Formatters::ExceptionPresenter.new(incorrect_message_exception, example)
280+
281+
expect(the_presenter.fully_formatted(1)).to eq(<<-EOS.gsub(/^ +\|/, ''))
282+
|
283+
| 1) Example
284+
| Failure/Error: Unable to find matching line from backtrace
285+
| A #{FakeException} for which `exception.message.to_s` raises #{expected_error}.
286+
EOS
287+
end
288+
263289
it "adds extra failure lines from the example metadata" do
264290
extra_example = example.clone
265291
failure_line = 'http://www.example.com/job_details/123'

0 commit comments

Comments
 (0)