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

Commit 226d48a

Browse files
committed
Ensure derived values are updated when the config setting updates.
It’s easier to make this work by moving the `spec_files_with_failures` and the `last_run_statuses` methods off of `world` and over to `configuration.
1 parent 1fd70fe commit 226d48a

File tree

5 files changed

+112
-41
lines changed

5 files changed

+112
-41
lines changed

lib/rspec/core/configuration.rb

Lines changed: 48 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -154,10 +154,22 @@ def deprecation_stream=(value)
154154
end
155155
end
156156

157-
# @macro add_setting
158-
# Sets a file path to use for persisting example statuses. Necessary for the
157+
# @macro define_reader
158+
# The file path to use for persisting example statuses. Necessary for the
159+
# `--only-failures` and `--next-failures` CLI options.
160+
#
161+
# @overload example_status_persistence_file_path
162+
# @return [String] the file path
163+
# @overload example_status_persistence_file_path=(value)
164+
# @param value [String] the file path
165+
define_reader :example_status_persistence_file_path
166+
167+
# Sets the file path to use for persisting example statuses. Necessary for the
159168
# `--only-failures` and `--next-failures` CLI options.
160-
add_setting :example_status_persistence_file_path
169+
def example_status_persistence_file_path=(value)
170+
@example_status_persistence_file_path = value
171+
clear_values_derived_from_example_status_persistence_file_path
172+
end
161173

162174
# @macro define_reader
163175
# Indicates if the `--only-failures` (or `--next-failure`) flag is being used.
@@ -353,6 +365,10 @@ def initialize
353365
def force(hash)
354366
ordering_manager.force(hash)
355367
@preferred_options.merge!(hash)
368+
369+
if hash.key?(:example_status_persistence_file_path)
370+
clear_values_derived_from_example_status_persistence_file_path
371+
end
356372
end
357373

358374
# @private
@@ -820,14 +836,37 @@ def files_or_directories_to_run=(*files)
820836
def files_to_run
821837
@files_to_run ||= begin
822838
if @files_or_directories_to_run_defaulted && only_failures?
823-
files_with_failures = RSpec.world.spec_files_with_failures.to_a
839+
files_with_failures = spec_files_with_failures.to_a
824840
@files_or_directories_to_run = files_with_failures if files_with_failures.any?
825841
end
826842

827843
get_files_to_run(@files_or_directories_to_run)
828844
end
829845
end
830846

847+
# @private
848+
def last_run_statuses
849+
@last_run_statuses ||= if (path = example_status_persistence_file_path)
850+
ExampleStatusPersister.load_from(path).inject({}) do |hash, example|
851+
hash[example.fetch(:example_id)] = example.fetch(:status)
852+
hash
853+
end
854+
else
855+
{}
856+
end
857+
end
858+
859+
# @private
860+
FAILED_STATUS = "failed".freeze
861+
862+
# @private
863+
def spec_files_with_failures
864+
@spec_files_with_failures ||= last_run_statuses.inject(Set.new) do |files, (id, status)|
865+
files << id.split(ON_SQUARE_BRACKETS).first if status == FAILED_STATUS
866+
files
867+
end.to_a
868+
end
869+
831870
# Creates a method that delegates to `example` including the submitted
832871
# `args`. Used internally to add variants of `example` like `pending`:
833872
# @param name [String] example name alias
@@ -1703,6 +1742,11 @@ def update_pattern_attr(name, value)
17031742
instance_variable_set(:"@#{name}", value)
17041743
@files_to_run = nil
17051744
end
1745+
1746+
def clear_values_derived_from_example_status_persistence_file_path
1747+
@last_run_statuses = nil
1748+
@spec_files_with_failures = nil
1749+
end
17061750
end
17071751
# rubocop:enable Style/ClassLength
17081752
end

lib/rspec/core/example.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -163,7 +163,7 @@ def initialize(example_group_class, description, user_metadata, example_block=ni
163163
# This should perhaps be done in `Metadata::ExampleHash.create`,
164164
# but the logic there has no knowledge of `RSpec.world` and we
165165
# want to keep it that way. It's easier to just assign it here.
166-
@metadata[:last_run_status] = RSpec.world.last_run_statuses[id]
166+
@metadata[:last_run_status] = RSpec.configuration.last_run_statuses[id]
167167

168168
@example_group_instance = @exception = nil
169169
@clock = RSpec::Core::Time

lib/rspec/core/world.rb

Lines changed: 0 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -108,31 +108,6 @@ def reporter
108108
@configuration.reporter
109109
end
110110

111-
# @private
112-
def last_run_statuses
113-
@last_run_statuses ||=
114-
if (path = @configuration.example_status_persistence_file_path)
115-
ExampleStatusPersister.load_from(path).inject({}) do |hash, example|
116-
hash[example.fetch(:example_id)] = example.fetch(:status)
117-
hash
118-
end
119-
else
120-
{}
121-
end
122-
end
123-
124-
# @private
125-
def spec_files_with_failures
126-
@spec_files_with_failures ||=
127-
last_run_statuses.inject(Set.new) do |files, (id, status)|
128-
files << id.split(Configuration::ON_SQUARE_BRACKETS).first if status == FAILED_STATUS
129-
files
130-
end.to_a
131-
end
132-
133-
# @private
134-
FAILED_STATUS = "failed".freeze
135-
136111
# @api private
137112
#
138113
# Notify reporter of filters.

spec/rspec/core/configuration/only_failures_support_spec.rb

Lines changed: 61 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
module RSpec::Core
22
RSpec.describe Configuration, "--only-failures support" do
33
let(:config) { Configuration.new }
4-
let(:world) { World.new(config) }
54

65
def simulate_persisted_examples(*examples)
76
config.example_status_persistence_file_path = "examples.txt"
@@ -12,25 +11,31 @@ def simulate_persisted_examples(*examples)
1211

1312
describe "#last_run_statuses" do
1413
def last_run_statuses
15-
world.last_run_statuses
14+
config.last_run_statuses
1615
end
1716

1817
context "when `example_status_persistence_file_path` is configured" do
19-
it 'gets the last run statuses from the ExampleStatusPersister' do
18+
before do
2019
simulate_persisted_examples(
2120
{ :example_id => "id_1", :status => "passed" },
2221
{ :example_id => "id_2", :status => "failed" }
2322
)
23+
end
2424

25+
it 'gets the last run statuses from the ExampleStatusPersister' do
2526
expect(last_run_statuses).to eq(
2627
'id_1' => 'passed', 'id_2' => 'failed'
2728
)
2829
end
30+
31+
it 'returns a memoized value' do
32+
expect(last_run_statuses).to be(last_run_statuses)
33+
end
2934
end
3035

3136
context "when `example_status_persistence_file_path` is not configured" do
3237
it 'returns a memoized value' do
33-
expect(last_run_statuses).to be(world.last_run_statuses)
38+
expect(last_run_statuses).to be(last_run_statuses)
3439
end
3540

3641
it 'returns a blank hash without attempting to load the persisted statuses' do
@@ -42,11 +47,36 @@ def last_run_statuses
4247
expect(last_run_statuses).to eq({})
4348
end
4449
end
50+
51+
def allows_value_to_change_when_updated
52+
simulate_persisted_examples(
53+
{ :example_id => "id_1", :status => "passed" },
54+
{ :example_id => "id_2", :status => "failed" }
55+
)
56+
57+
config.example_status_persistence_file_path = nil
58+
59+
expect {
60+
yield
61+
}.to change { last_run_statuses }.to('id_1' => 'passed', 'id_2' => 'failed')
62+
end
63+
64+
it 'allows the value to be updated when `example_status_persistence_file_path` is set after first access' do
65+
allows_value_to_change_when_updated do
66+
config.example_status_persistence_file_path = "examples.txt"
67+
end
68+
end
69+
70+
it 'allows the value to be updated when `example_status_persistence_file_path` is forced after first access' do
71+
allows_value_to_change_when_updated do
72+
config.force(:example_status_persistence_file_path => "examples.txt")
73+
end
74+
end
4575
end
4676

4777
describe "#spec_files_with_failures" do
4878
def spec_files_with_failures
49-
world.spec_files_with_failures
79+
config.spec_files_with_failures
5080
end
5181

5282
context "when `example_status_persistence_file_path` is configured" do
@@ -62,7 +92,7 @@ def spec_files_with_failures
6292

6393
expect(spec_files_with_failures).to(
6494
be_an(Array) &
65-
be(world.spec_files_with_failures) &
95+
be(spec_files_with_failures) &
6696
contain_exactly("./spec_1.rb", "./spec_5.rb")
6797
)
6898
end
@@ -73,10 +103,32 @@ def spec_files_with_failures
73103
config.example_status_persistence_file_path = nil
74104

75105
expect(spec_files_with_failures).to(
76-
eq([]) & be(world.spec_files_with_failures)
106+
eq([]) & be(spec_files_with_failures)
77107
)
78108
end
79109
end
110+
111+
def allows_value_to_change_when_updated
112+
simulate_persisted_examples({ :example_id => "./spec_1.rb[1:1]", :status => "failed" })
113+
114+
config.example_status_persistence_file_path = nil
115+
116+
expect {
117+
yield
118+
}.to change { spec_files_with_failures }.to(["./spec_1.rb"])
119+
end
120+
121+
it 'allows the value to be updated when `example_status_persistence_file_path` is set after first access' do
122+
allows_value_to_change_when_updated do
123+
config.example_status_persistence_file_path = "examples.txt"
124+
end
125+
end
126+
127+
it 'allows the value to be updated when `example_status_persistence_file_path` is forced after first access' do
128+
allows_value_to_change_when_updated do
129+
config.force(:example_status_persistence_file_path => "examples.txt")
130+
end
131+
end
80132
end
81133

82134
describe "#files_to_run, when `only_failures` is set" do
@@ -93,7 +145,7 @@ def spec_files_with_failures
93145
before do
94146
expect(files_loaded_via_default_path).not_to eq(files_with_failures)
95147
config.default_path = default_path
96-
allow(RSpec.world).to receive_messages(:spec_files_with_failures => files_with_failures)
148+
allow(config).to receive_messages(:spec_files_with_failures => files_with_failures)
97149
config.force(:only_failures => true)
98150
end
99151

@@ -104,7 +156,7 @@ def spec_files_with_failures
104156
end
105157

106158
it 'loads the default path if there are no files with failures' do
107-
allow(RSpec.world).to receive_messages(:spec_files_with_failures => [])
159+
allow(config).to receive_messages(:spec_files_with_failures => [])
108160
config.files_or_directories_to_run = []
109161
expect(config.files_to_run).to eq(files_loaded_via_default_path)
110162
end

spec/rspec/core/metadata_spec.rb

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -169,14 +169,14 @@ def metadata_for(*args)
169169
end
170170

171171
describe ":last_run_status" do
172-
it 'assigns it by looking up world.last_run_statuses[id]' do
172+
it 'assigns it by looking up configuration.last_run_statuses[id]' do
173173
looked_up_ids = []
174174
last_run_statuses = Hash.new do |hash, id|
175175
looked_up_ids << id
176176
"some_status"
177177
end
178178

179-
allow(RSpec.world).to receive(:last_run_statuses).and_return(last_run_statuses)
179+
allow(RSpec.configuration).to receive(:last_run_statuses).and_return(last_run_statuses)
180180
example = RSpec.describe.example
181181

182182
expect(example.metadata[:last_run_status]).to eq("some_status")

0 commit comments

Comments
 (0)