Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Include backtrace in errors reported by raise_error matcher. #177

Merged
merged 1 commit into from
Oct 9, 2012
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions Changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
13 changes: 12 additions & 1 deletion lib/rspec/matchers/built_in/raise_error.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
29 changes: 29 additions & 0 deletions lib/rspec/matchers/configuration.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
28 changes: 28 additions & 0 deletions spec/rspec/matchers/configuration_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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) }

Expand Down
30 changes: 30 additions & 0 deletions spec/rspec/matchers/raise_error_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand Down