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

Commit 39f7ffc

Browse files
committed
Prevent malformed exception messages from exiting RSpec
1 parent 019efb6 commit 39f7ffc

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
@@ -19,6 +19,8 @@ Bug Fixes:
1919
* Predicates for pending examples, (in `RSpec::Core::Example`, `#pending?`, `#skipped?` and
2020
`#pending_fixed?`) now return boolean values rather than truthy values.
2121
(Marc-André Lafortune, #2756, #2758)
22+
* Exceptions which have a message which cannot be cast to a string will no longer
23+
cause a crash. (Jon Rowe, #2761)
2224

2325
### 3.9.2 / 2020-05-02
2426
[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,11 +174,19 @@ 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
@exception_lines ||= begin
179187
lines = []
180188
lines << "#{exception_class_name}:" unless exception_class_name =~ /RSpec/
181-
encoded_string(exception.message.to_s).split("\n").each do |line|
189+
encoded_string(exception_message_string(exception)).split("\n").each do |line|
182190
lines << (line.empty? ? line : " #{line}")
183191
end
184192
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)