Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Include backtrace in errors reported by `raise_error` matcher.

It's hard to troubleshoot unexpected errors when the backtrace is silenced,
as it was previously.

Closes #59.
  • Loading branch information...
commit 4a919ab37d3642b7efa1a370f76afdc94fd3e336 1 parent 1644904
@myronmarston myronmarston authored
View
2  Changelog.md
@@ -4,6 +4,8 @@
Enhancements
* Colorize diffs if the `--color` option is configured. (Alex Coplan)
+* Include backtraces in unexpected errors handled by `raise_error`
+ matcher (Myron Marston)
Bug fixes
View
13 lib/rspec/matchers/built_in/raise_error.rb
@@ -87,8 +87,19 @@ def expected_error
end
end
+ def format_backtrace(backtrace)
+ formatter = Matchers.configuration.backtrace_formatter
+ formatter.format_backtrace(backtrace)
+ end
+
def given_error
- @actual_error.nil? ? " but nothing was raised" : ", got #{@actual_error.inspect}"
+ return " but nothing was raised" unless @actual_error
+
+ backtrace = format_backtrace(@actual_error.backtrace)
+ [
+ ", got #{@actual_error.inspect} with backtrace:",
+ *backtrace
+ ].join("\n # ")
end
end
end
View
29 lib/rspec/matchers/configuration.rb
@@ -64,6 +64,35 @@ def add_should_and_should_not_to(*modules)
Expectations::Syntax.enable_should(mod)
end
end
+
+ # Sets or gets the backtrace formatter. The backtrace formatter should
+ # implement `#format_backtrace(Array<String>)`. This is used
+ # to format backtraces of errors handled by the `raise_error`
+ # matcher.
+ #
+ # If you are using rspec-core, rspec-core's backtrace formatting
+ # will be used (including respecting the presence or absence of
+ # the `--backtrace` option).
+ #
+ # @overload backtrace_formatter
+ # @return [#format_backtrace] the backtrace formatter
+ # @overload backtrace_formatter=
+ # @param value [#format_backtrace] sets the backtrace formatter
+ attr_writer :backtrace_formatter
+ def backtrace_formatter
+ @backtrace_formatter ||= if defined?(::RSpec::Core::BacktraceFormatter)
+ ::RSpec::Core::BacktraceFormatter
+ else
+ NullBacktraceFormatter
+ end
+ end
+
+ # @api private
+ NullBacktraceFormatter = Module.new do
+ def self.format_backtrace(backtrace)
+ backtrace
+ end
+ end
end
# The configuration object
View
28 spec/rspec/matchers/configuration_spec.rb
@@ -13,6 +13,34 @@ module Matchers
describe Configuration do
let(:config) { Configuration.new }
+ describe "#backtrace_formatter" do
+ let(:original_backtrace) { %w[ clean-me/a.rb other/file.rb clean-me/b.rb ] }
+ let(:cleaned_backtrace) { %w[ other/file.rb ] }
+
+ let(:formatted_backtrace) do
+ config.backtrace_formatter.format_backtrace(original_backtrace)
+ end
+
+ before do
+ RSpec.configuration.stub(:backtrace_clean_patterns) { [/clean-me/] }
+ end
+
+ it "defaults to rspec-core's backtrace formatter when rspec-core is loaded" do
+ expect(config.backtrace_formatter).to be(RSpec::Core::BacktraceFormatter)
+ expect(formatted_backtrace).to eq(cleaned_backtrace)
+ end
+
+ it "defaults to a null formatter when rspec-core is not loaded" do
+ stub_const("RSpec::Core", nil) # so the formatter module is not loaded
+ expect(formatted_backtrace).to eq(original_backtrace)
+ end
+
+ it "can be set to another backtrace formatter" do
+ config.backtrace_formatter = stub(:format_backtrace => ['a'])
+ expect(formatted_backtrace).to eq(['a'])
+ end
+ end
+
context 'on an interpreter that does not provide BasicObject', :unless => defined?(::BasicObject) do
before { RSpec::Expectations::Syntax.disable_should(Delegator) }
View
30 spec/rspec/matchers/raise_error_spec.rb
@@ -51,6 +51,27 @@
lambda { raise RuntimeError, "example message" }.should_not raise_error
}.should fail_with(/expected no Exception, got #<RuntimeError: example message>/)
end
+
+ it 'includes the backtrace of the error that was raised in the error message' do
+ expect {
+ expect { raise "boom" }.not_to raise_error
+ }.to raise_error { |e|
+ backtrace_line = "#{File.basename(__FILE__)}:#{__LINE__ - 2}"
+ e.message.should include("with backtrace", backtrace_line)
+ }
+ end
+
+ it 'formats the backtrace using the configured backtrace formatter' do
+ RSpec::Matchers.configuration.backtrace_formatter.
+ stub(:format_backtrace).
+ and_return("formatted-backtrace")
+
+ expect {
+ expect { raise "boom" }.not_to raise_error
+ }.to raise_error { |e|
+ e.message.should include("with backtrace", "formatted-backtrace")
+ }
+ end
end
describe "should raise_error(message)" do
@@ -77,6 +98,15 @@
lambda {raise NameError.new('blarg')}.should raise_error('blah')
end.should fail_with(/expected Exception with \"blah\", got #<NameError: blarg>/)
end
+
+ it 'includes the backtrace of any other error in the failure message' do
+ expect {
+ expect { raise "boom" }.to raise_error(ArgumentError)
+ }.to raise_error { |e|
+ backtrace_line = "#{File.basename(__FILE__)}:#{__LINE__ - 2}"
+ e.message.should include("with backtrace", backtrace_line)
+ }
+ end
end
describe "should_not raise_error(message)" do
Please sign in to comment.
Something went wrong with that request. Please try again.