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

Commit 85bcc85

Browse files
committed
Fail fast when we can't support --only-failures due to lack of config.
1 parent 7584e59 commit 85bcc85

File tree

9 files changed

+120
-4
lines changed

9 files changed

+120
-4
lines changed

features/command_line/only_failures.feature

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,3 +102,8 @@ Feature: Only Failures
102102

103103
When I run `rspec --next-failure`
104104
Then the output should contain "All examples were filtered out"
105+
106+
Scenario: Clear error given when using `--only-failures` without configuring `example_status_persistence_file_path`
107+
Given I have not configured `example_status_persistence_file_path`
108+
When I run `rspec --only-failures`
109+
Then it should fail with "To use `--only-failures`, you must first set `config.example_status_persistence_file_path`."

features/step_definitions/additional_cli_steps.rb

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,3 +138,15 @@
138138
File.open(file_name, "w") { |f| f.write(fixed) }
139139
end
140140
end
141+
142+
Then(/^it should fail with "(.*?)"$/) do |snippet|
143+
assert_failing_with(snippet)
144+
end
145+
146+
Given(/^I have not configured `example_status_persistence_file_path`$/) do
147+
in_current_dir do
148+
return unless File.exist?("spec/spec_helper.rb")
149+
return unless File.read("spec/spec_helper.rb").include?("example_status_persistence_file_path")
150+
File.open("spec/spec_helper.rb", "w") { |f| f.write("") }
151+
end
152+
end

lib/rspec/core/configuration.rb

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -176,6 +176,11 @@ def example_status_persistence_file_path=(value)
176176
define_reader :only_failures
177177
alias_method :only_failures?, :only_failures
178178

179+
# @private
180+
def only_failures_but_not_configured?
181+
only_failures? && !example_status_persistence_file_path
182+
end
183+
179184
# @macro add_setting
180185
# Clean up and exit after the first failure (default: `false`).
181186
add_setting :fail_fast

lib/rspec/core/formatters/base_text_formatter.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ def close(_notification)
6868

6969
output.puts
7070

71+
output.flush
7172
output.close unless output == $stdout
7273
end
7374
end

lib/rspec/core/reporter.rb

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -154,7 +154,7 @@ def finish
154154
@pending_examples, @load_time)
155155
notify :seed, Notifications::SeedNotification.new(@configuration.seed, seed_used?)
156156
ensure
157-
notify :close, Notifications::NullNotification
157+
close
158158
end
159159

160160
# @private
@@ -170,8 +170,19 @@ def notify(event, notification)
170170
end
171171
end
172172

173+
# @private
174+
def abort_with(msg, exit_status)
175+
message(msg)
176+
close
177+
exit!(exit_status)
178+
end
179+
173180
private
174181

182+
def close
183+
notify :close, Notifications::NullNotification
184+
end
185+
175186
def mute_profile_output?
176187
# Don't print out profiled info if there are failures and `--fail-fast` is
177188
# used, it just clutters the output.

lib/rspec/core/world.rb

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,7 @@ def reporter
112112
#
113113
# Notify reporter of filters.
114114
def announce_filters
115+
fail_if_config_and_cli_options_invalid
115116
filter_announcements = []
116117

117118
announce_inclusion_filter filter_announcements
@@ -175,6 +176,16 @@ def announce_exclusion_filter(announcements)
175176
def declaration_line_numbers
176177
@declaration_line_numbers ||= FlatMap.flat_map(example_groups, &:declaration_line_numbers)
177178
end
179+
180+
def fail_if_config_and_cli_options_invalid
181+
return unless @configuration.only_failures_but_not_configured?
182+
183+
reporter.abort_with(
184+
"\nTo use `--only-failures`, you must first set " \
185+
"`config.example_status_persistence_file_path`.",
186+
1 # exit code
187+
)
188+
end
178189
end
179190
end
180191
end

spec/rspec/core/formatters/base_text_formatter_spec.rb

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,21 @@
55
include FormatterSupport
66

77
context "when closing the formatter", :isolated_directory => true do
8+
let(:output_to_close) { File.new("./output_to_close", "w") }
9+
let(:formatter) { described_class.new(output_to_close) }
10+
811
it 'does not close an already closed output stream' do
9-
output_to_close = File.new("./output_to_close", "w")
10-
formatter = described_class.new(output_to_close)
1112
output_to_close.close
1213

1314
expect { formatter.close(RSpec::Core::Notifications::NullNotification) }.not_to raise_error
1415
end
16+
17+
it "flushes output before closing the stream so buffered bytes are not lost if we exit right away" do
18+
expect(output_to_close).to receive(:flush).ordered
19+
expect(output_to_close).to receive(:close).ordered
20+
21+
formatter.close(RSpec::Core::Notifications::NullNotification)
22+
end
1523
end
1624

1725
describe "#dump_summary" do

spec/rspec/core/reporter_spec.rb

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -206,6 +206,29 @@ module RSpec::Core
206206
end
207207
end
208208

209+
describe "#abort_with" do
210+
before { allow(reporter).to receive(:exit!) }
211+
212+
it "publishes the message and notifies :close" do
213+
listener = double("Listener")
214+
reporter.register_listener(listener, :message, :close)
215+
stream = StringIO.new
216+
217+
allow(listener).to receive(:message) { |n| stream << n.message }
218+
allow(listener).to receive(:close) { stream.close }
219+
220+
reporter.register_listener(listener)
221+
reporter.abort_with("Booom!", 1)
222+
223+
expect(stream).to have_attributes(:string => "Booom!").and be_closed
224+
end
225+
226+
it "exits with the provided exit code" do
227+
reporter.abort_with("msg", 13)
228+
expect(reporter).to have_received(:exit!).with(13)
229+
end
230+
end
231+
209232
describe "timing" do
210233
before do
211234
config.start_time = start_time

spec/rspec/core/world_spec.rb

Lines changed: 41 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -109,9 +109,49 @@ module RSpec::Core
109109
end
110110

111111
describe "#announce_filters" do
112-
let(:reporter) { double('reporter').as_null_object }
112+
let(:reporter) { instance_spy(Reporter) }
113113
before { allow(world).to receive(:reporter) { reporter } }
114114

115+
context "when --only-failures is passed" do
116+
before { configuration.force(:only_failures => true) }
117+
118+
context "and `example_status_persistence_file_path` is not configured" do
119+
it 'aborts with a message explaining the config option must be set first' do
120+
configuration.example_status_persistence_file_path = nil
121+
world.announce_filters
122+
expect(reporter).to have_received(:abort_with).with(/example_status_persistence_file_path/, 1)
123+
end
124+
end
125+
126+
context "and `example_status_persistence_file_path` is configured" do
127+
it 'does not abort' do
128+
configuration.example_status_persistence_file_path = "foo.txt"
129+
world.announce_filters
130+
expect(reporter).not_to have_received(:abort_with)
131+
end
132+
end
133+
end
134+
135+
context "when --only-failures is not passed" do
136+
before { expect(configuration.only_failures?).not_to eq true }
137+
138+
context "and `example_status_persistence_file_path` is not configured" do
139+
it 'does not abort' do
140+
configuration.example_status_persistence_file_path = nil
141+
world.announce_filters
142+
expect(reporter).not_to have_received(:abort_with)
143+
end
144+
end
145+
146+
context "and `example_status_persistence_file_path` is configured" do
147+
it 'does not abort' do
148+
configuration.example_status_persistence_file_path = "foo.txt"
149+
world.announce_filters
150+
expect(reporter).not_to have_received(:abort_with)
151+
end
152+
end
153+
end
154+
115155
context "with no examples" do
116156
before { allow(world).to receive(:example_count) { 0 } }
117157

0 commit comments

Comments
 (0)