diff --git a/lib/rspec/core/runner.rb b/lib/rspec/core/runner.rb index f8587f6fcd..d0645b929e 100644 --- a/lib/rspec/core/runner.rb +++ b/lib/rspec/core/runner.rb @@ -5,7 +5,18 @@ class Runner # Register an at_exit hook that runs the suite. def self.autorun return if autorun_disabled? || installed_at_exit? || running_in_drb? - at_exit { exit run(ARGV, $stderr, $stdout).to_i unless $! } + at_exit do + # Don't bother running any specs and just let the program terminate + # if we got here due to an unrescued exception (anything other than + # SystemExit, which is raised when somebody calls Kernel#exit). + next if $! and not $!.kind_of? SystemExit + + # We got here because either the end of the program was reached or + # somebody called Kernel#exit. Run the specs and then override any + # existing exit status with RSpec's exit status if any specs failed. + status = run(ARGV, $stderr, $stdout).to_i + exit status if status != 0 + end @installed_at_exit = true end AT_EXIT_HOOK_BACKTRACE_LINE = "#{__FILE__}:#{__LINE__ - 2}:in `autorun'" diff --git a/spec/rspec/core/runner_spec.rb b/spec/rspec/core/runner_spec.rb index 91ba0b7d02..12608d7f4c 100644 --- a/spec/rspec/core/runner_spec.rb +++ b/spec/rspec/core/runner_spec.rb @@ -20,6 +20,25 @@ module RSpec::Core RSpec::Core::Runner.should_receive(:at_exit).never RSpec::Core::Runner.autorun end + + context 'when dealing with exceptions' do + let(:ruby) { 'ruby -I lib -r rspec/autorun' } + + it 'runs specs if no exception was raised' do + `#{ruby} -e nil`.should_not be_empty + end + + it 'runs specs if SystemExit was raised' do + `#{ruby} -e exit`.should_not be_empty + `#{ruby} -e 'at_exit { exit }'`.should_not be_empty + `#{ruby} -e 'at_exit { raise SystemExit }'`.should_not be_empty + end + + it 'does not run specs if an exception other than SystemExit was raised' do + `#{ruby} -e 'at_exit { raise }' 2>/dev/null`.should be_empty + `#{ruby} -e 'at_exit { raise Exception }' 2>/dev/null`.should be_empty + end + end end describe "#run" do