Skip to content

Commit

Permalink
- (Re)Fixed marshalling of exceptions, neutering them in 2 passes.
Browse files Browse the repository at this point in the history
[git-p4: depot-paths = "//src/minitest/dev/": change = 13432]
  • Loading branch information
zenspider committed Jun 11, 2022
1 parent 001b19e commit 31b95ed
Show file tree
Hide file tree
Showing 2 changed files with 59 additions and 5 deletions.
23 changes: 19 additions & 4 deletions lib/minitest/test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -203,12 +203,27 @@ def capture_exceptions # :nodoc:

def sanitize_exception e # :nodoc:
Marshal.dump e
e
e # good: use as-is
rescue TypeError
neuter_exception e
end

def neuter_exception e
bt = e.backtrace
e = RuntimeError.new "Wrapped undumpable exception for: #{e.class}: #{e.message}"
e.set_backtrace bt
e
msg = e.message.dup

new_exception e.class, msg, bt # e.class can be a problem...
rescue TypeError
msg.prepend "Neutered Exception #{e.class}: "

new_exception RuntimeError, msg, bt # but if this raises, we die
end

def new_exception klass, msg, bt
ne = klass.new msg
ne.set_backtrace bt
Marshal.dump ne # can raise TypeError
ne
end

def with_info_handler &block # :nodoc:
Expand Down
41 changes: 40 additions & 1 deletion test/minitest/test_minitest_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -838,13 +838,52 @@ def test_spec_marshal
end

def test_spec_marshal_with_exception
klass = describe("whatever") { it("passes") { raise Class.new(StandardError)} }
klass = describe("whatever") {
it("raises, badly") {
raise Class.new(StandardError), "this is bad!"
}
}

rm = klass.runnable_methods.first

# Run the test
@tc = klass.new(rm).run

assert_kind_of Minitest::Result, @tc
assert_instance_of Minitest::UnexpectedError, @tc.failure

msg = @tc.failure.error.message
assert_includes msg, "Neutered Exception #<Class:"
assert_includes msg, "this is bad!"

# Pass it over the wire
over_the_wire = Marshal.load Marshal.dump @tc

assert_equal @tc.time, over_the_wire.time
assert_equal @tc.name, over_the_wire.name
assert_equal @tc.assertions, over_the_wire.assertions
assert_equal @tc.failures, over_the_wire.failures
assert_equal @tc.klass, over_the_wire.klass
end

def test_spec_marshal_with_exception_nameerror
klass = describe("whatever") {
it("raises nameerror") {
NOPE::does_not_exist
}
}

rm = klass.runnable_methods.first

# Run the test
@tc = klass.new(rm).run

assert_kind_of Minitest::Result, @tc
assert_instance_of Minitest::UnexpectedError, @tc.failure

msg = @tc.failure.error.message
assert_includes msg, "uninitialized constant TestMinitestRunnable::NOPE"
assert_includes msg, "NOPE::does_not_exist"

# Pass it over the wire
over_the_wire = Marshal.load Marshal.dump @tc
Expand Down

0 comments on commit 31b95ed

Please sign in to comment.