Skip to content

Commit 04458c8

Browse files
committed
Merge pull request rspec#1897 from rspec/fix-filtering-regression
Fix filtering regression
2 parents fb955fd + a4fbf01 commit 04458c8

File tree

6 files changed

+116
-47
lines changed

6 files changed

+116
-47
lines changed

lib/rspec/core/filter_manager.rb

Lines changed: 25 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -35,12 +35,15 @@ def prune(examples)
3535
examples = prune_conditionally_filtered_examples(examples)
3636

3737
if inclusions.standalone?
38-
examples.select { |e| include?(e) }
38+
examples.select { |e| inclusions.include_example?(e) }
3939
else
40-
locations = inclusions.fetch(:locations) { Hash.new([]) }
41-
ids = inclusions.fetch(:ids) { Hash.new([]) }
40+
locations, ids, non_scoped_inclusions = inclusions.split_file_scoped_rules
4241

43-
examples.select { |e| priority_include?(e, ids, locations) || (!exclude?(e) && include?(e)) }
42+
examples.select do |ex|
43+
file_scoped_include?(ex.metadata, ids, locations) do
44+
!exclusions.include_example?(ex) && non_scoped_inclusions.include_example?(ex)
45+
end
46+
end
4447
end
4548
end
4649

@@ -76,14 +79,6 @@ def add_path_to_arrays_filter(filter_key, path, values)
7679
inclusions.add(filter_key => filter)
7780
end
7881

79-
def exclude?(example)
80-
exclusions.include_example?(example)
81-
end
82-
83-
def include?(example)
84-
inclusions.include_example?(example)
85-
end
86-
8782
def prune_conditionally_filtered_examples(examples)
8883
examples.reject do |ex|
8984
meta = ex.metadata
@@ -96,10 +91,14 @@ def prune_conditionally_filtered_examples(examples)
9691
# and there is a `:slow => true` exclusion filter), but only for specs
9792
# defined in the same file as the location filters. Excluded specs in
9893
# other files should still be excluded.
99-
def priority_include?(example, ids, locations)
100-
return true if MetadataFilter.filter_applies?(:ids, ids, example.metadata)
101-
return false if locations[example.metadata[:absolute_file_path]].empty?
102-
MetadataFilter.filter_applies?(:locations, locations, example.metadata)
94+
def file_scoped_include?(ex_metadata, ids, locations)
95+
no_location_filters = locations[ex_metadata[:absolute_file_path]].empty?
96+
no_id_filters = ids[ex_metadata[:rerun_file_path]].empty?
97+
98+
return yield if no_location_filters && no_id_filters
99+
100+
MetadataFilter.filter_applies?(:ids, ids, ex_metadata) ||
101+
MetadataFilter.filter_applies?(:locations, locations, ex_metadata)
103102
end
104103
end
105104

@@ -119,8 +118,8 @@ def self.build
119118
[exclusions, inclusions]
120119
end
121120

122-
def initialize(*args, &block)
123-
@rules = Hash.new(*args, &block)
121+
def initialize(rules={})
122+
@rules = rules
124123
end
125124

126125
def add(updated)
@@ -196,6 +195,14 @@ def standalone?
196195
is_standalone_filter?(@rules)
197196
end
198197

198+
def split_file_scoped_rules
199+
rules_dup = @rules.dup
200+
locations = rules_dup.delete(:locations) { Hash.new([]) }
201+
ids = rules_dup.delete(:ids) { Hash.new([]) }
202+
203+
return locations, ids, self.class.new(rules_dup)
204+
end
205+
199206
private
200207

201208
def apply_standalone_filter(updated)

lib/rspec/core/metadata_filter.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ def id_filter_applies?(rerun_paths_to_scoped_ids, metadata)
5353

5454
def location_filter_applies?(locations, metadata)
5555
line_numbers = example_group_declaration_lines(locations, metadata)
56-
line_numbers.empty? || line_number_filter_applies?(line_numbers, metadata)
56+
line_number_filter_applies?(line_numbers, metadata)
5757
end
5858

5959
def line_number_filter_applies?(line_numbers, metadata)

spec/integration/filtering_spec.rb

Lines changed: 42 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,14 @@
55
before { clean_current_dir }
66

77
it 'prints a rerun command for shared examples in external files that works to rerun' do
8-
write_file "spec/support/shared_examples.rb", """
8+
write_file "spec/support/shared_examples.rb", "
99
RSpec.shared_examples 'with a failing example' do
1010
example { expect(1).to eq(2) } # failing
1111
example { expect(2).to eq(2) } # passing
1212
end
13-
"""
13+
"
1414

15-
write_file "spec/host_group_spec.rb", """
15+
write_file "spec/host_group_spec.rb", "
1616
load File.expand_path('../support/shared_examples.rb', __FILE__)
1717
1818
RSpec.describe 'A group with shared examples' do
@@ -22,7 +22,7 @@
2222
RSpec.describe 'A group with a passing example' do
2323
example { expect(1).to eq(1) }
2424
end
25-
"""
25+
"
2626

2727
run_command ""
2828
expect(last_cmd_stdout).to include("3 examples, 1 failure")
@@ -40,7 +40,7 @@ def run_rerun_command_for_failing_spec
4040

4141
context "with a shared example containing a context in a separate file" do
4242
it "runs the example nested inside the shared" do
43-
write_file_formatted 'spec/shared_example.rb', """
43+
write_file_formatted 'spec/shared_example.rb', "
4444
RSpec.shared_examples_for 'a shared example' do
4545
it 'succeeds' do
4646
end
@@ -50,15 +50,15 @@ def run_rerun_command_for_failing_spec
5050
end
5151
end
5252
end
53-
"""
53+
"
5454

55-
write_file_formatted 'spec/simple_spec.rb', """
55+
write_file_formatted 'spec/simple_spec.rb', "
5656
require File.join(File.dirname(__FILE__), 'shared_example.rb')
5757
5858
RSpec.describe 'top level' do
5959
it_behaves_like 'a shared example'
6060
end
61-
"""
61+
"
6262

6363
run_command 'spec/simple_spec.rb:3 -fd'
6464
expect(last_cmd_stdout).to match(/2 examples, 0 failures/)
@@ -67,7 +67,7 @@ def run_rerun_command_for_failing_spec
6767

6868
context "passing a line-number filter" do
6969
it "trumps exclusions, except for :if/:unless (which are absolute exclusions)" do
70-
write_file_formatted 'spec/a_spec.rb', """
70+
write_file_formatted 'spec/a_spec.rb', "
7171
RSpec.configure do |c|
7272
c.filter_run_excluding :slow
7373
end
@@ -82,7 +82,7 @@ def run_rerun_command_for_failing_spec
8282
example('ex 4', :slow ) { }
8383
example('ex 5', :if => false) { }
8484
end
85-
"""
85+
"
8686

8787
run_command "spec/a_spec.rb -fd"
8888
expect(last_cmd_stdout).to include("1 example, 0 failures", "ex 3").and exclude("ex 1", "ex 2", "ex 4", "ex 5")
@@ -100,14 +100,14 @@ def run_rerun_command_for_failing_spec
100100

101101
context "passing a line-number-filtered file and a non-filtered file" do
102102
it "applies the line number filtering only to the filtered file, running all specs in the non-filtered file except excluded ones" do
103-
write_file_formatted "spec/file_1_spec.rb", """
103+
write_file_formatted "spec/file_1_spec.rb", "
104104
RSpec.describe 'File 1' do
105105
it('passes') { }
106106
it('fails') { fail }
107107
end
108-
"""
108+
"
109109

110-
write_file_formatted "spec/file_2_spec.rb", """
110+
write_file_formatted "spec/file_2_spec.rb", "
111111
RSpec.configure do |c|
112112
c.filter_run_excluding :exclude_me
113113
end
@@ -117,31 +117,53 @@ def run_rerun_command_for_failing_spec
117117
it('passes') { }
118118
it('fails', :exclude_me) { fail }
119119
end
120-
"""
120+
"
121121

122122
run_command "spec/file_1_spec.rb:2 spec/file_2_spec.rb -fd"
123123
expect(last_cmd_stdout).to match(/3 examples, 0 failures/)
124124
expect(last_cmd_stdout).not_to match(/fails/)
125125
end
126+
127+
it 'applies command line tag filters only to files that lack a line number filter' do
128+
write_file_formatted "spec/file_1_spec.rb", "
129+
RSpec.describe 'File 1' do
130+
it('is selected by line') { }
131+
it('is not selected', :tag) { }
132+
end
133+
"
134+
135+
write_file_formatted "spec/file_2_spec.rb", "
136+
RSpec.describe 'File 2' do
137+
it('is not selected') { }
138+
it('is selected by tag', :tag) { }
139+
end
140+
"
141+
142+
run_command "spec/file_1_spec.rb:2 spec/file_2_spec.rb --tag tag -fd"
143+
expect(last_cmd_stdout).to include(
144+
"2 examples, 0 failures",
145+
"is selected by line", "is selected by tag"
146+
).and exclude("not selected")
147+
end
126148
end
127149

128150
context "passing example ids at the command line" do
129151
it "selects matching examples" do
130-
write_file_formatted "spec/file_1_spec.rb", """
152+
write_file_formatted "spec/file_1_spec.rb", "
131153
RSpec.describe 'File 1' do
132154
1.upto(3) do |i|
133155
example('ex ' + i.to_s) { expect(i).to be_odd }
134156
end
135157
end
136-
"""
158+
"
137159

138-
write_file_formatted "spec/file_2_spec.rb", """
160+
write_file_formatted "spec/file_2_spec.rb", "
139161
RSpec.describe 'File 2' do
140162
1.upto(3) do |i|
141163
example('ex ' + i.to_s) { expect(i).to be_even }
142164
end
143165
end
144-
"""
166+
"
145167

146168
# Using the form that Metadata.relative_path returns...
147169
run_command "./spec/file_1_spec.rb[1:1,1:3] ./spec/file_2_spec.rb[1:2]"
@@ -162,7 +184,7 @@ def run_rerun_command_for_failing_spec
162184
end
163185

164186
it "selects matching example groups" do
165-
write_file_formatted "spec/file_1_spec.rb", """
187+
write_file_formatted "spec/file_1_spec.rb", "
166188
RSpec.describe 'Group 1' do
167189
example { fail }
168190
@@ -175,7 +197,7 @@ def run_rerun_command_for_failing_spec
175197
example { fail }
176198
end
177199
end
178-
"""
200+
"
179201

180202
run_command "./spec/file_1_spec.rb[1:2]"
181203
expect(last_cmd_stdout).to match(/2 examples, 0 failures/)

spec/integration/order_spec.rb

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
include_context "aruba support"
55

66
before :all do
7-
write_file 'spec/simple_spec.rb', """
7+
write_file 'spec/simple_spec.rb', "
88
RSpec.describe 'group 1' do
99
specify('group 1 example 1') {}
1010
specify('group 1 example 2') {}
@@ -15,9 +15,9 @@
1515
specify('group 1-1 example 3') {}
1616
end
1717
end
18-
"""
18+
"
1919

20-
write_file 'spec/simple_spec2.rb', """
20+
write_file 'spec/simple_spec2.rb', "
2121
RSpec.describe 'group 2' do
2222
specify('group 2 example 1') {}
2323
specify('group 2 example 2') {}
@@ -28,9 +28,9 @@
2828
specify('group 2-1 example 3') {}
2929
end
3030
end
31-
"""
31+
"
3232

33-
write_file 'spec/order_spec.rb', """
33+
write_file 'spec/order_spec.rb', "
3434
RSpec.describe 'group 1' do
3535
specify('group 1 example 1') {}
3636
specify('group 1 example 2') {}
@@ -76,7 +76,7 @@
7676
RSpec.describe('group 8') { specify('example') {} }
7777
RSpec.describe('group 9') { specify('example') {} }
7878
RSpec.describe('group 10') { specify('example') {} }
79-
"""
79+
"
8080
end
8181

8282
describe '--order rand' do
@@ -150,7 +150,7 @@
150150
after { remove_file 'spec/custom_order_spec.rb' }
151151

152152
before do
153-
write_file 'spec/custom_order_spec.rb', """
153+
write_file 'spec/custom_order_spec.rb', "
154154
RSpec.configure do |config|
155155
config.register_ordering :global do |list|
156156
list.sort_by { |item| item.description }
@@ -167,7 +167,7 @@
167167
RSpec.describe 'group A' do
168168
specify('group A example 1') {}
169169
end
170-
"""
170+
"
171171
end
172172

173173
it 'orders the groups and examples by the provided strategy' do

spec/rspec/core/filter_manager_spec.rb

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,25 @@ def example_with(*args)
129129

130130
expect(filter_manager.prune([included, excluded])).to eq([included])
131131
end
132+
133+
it "still applies inclusion filters to examples from files with no #{type} filters" do
134+
group = RSpec.describe("group")
135+
included_via_loc_or_id = group.example("inc via #{type}"); line = __LINE__
136+
excluded_via_loc_or_id = group.example("exc via #{type}", :foo)
137+
138+
included_via_tag, excluded_via_tag = instance_eval <<-EOS, "some/other_spec.rb", 1
139+
group = RSpec.describe("group")
140+
[group.example("inc via tag", :foo), group.example("exc via tag")]
141+
EOS
142+
143+
add_filter(:line_number => line, :scoped_id => "1:1")
144+
filter_manager.include_with_low_priority :foo => true
145+
146+
expect(filter_manager.prune([
147+
included_via_loc_or_id, excluded_via_loc_or_id,
148+
included_via_tag, excluded_via_tag
149+
]).map(&:description)).to eq([included_via_loc_or_id, included_via_tag].map(&:description))
150+
end
132151
end
133152

134153
describe "location filtering" do
@@ -299,6 +318,24 @@ def add_filter(options)
299318
filter_manager.add_ids(Metadata.relative_path(__FILE__), %w[ 2 ])
300319
expect(filter_manager.prune([ex_1, ex_2, ex_3])).to eq([ex_2, ex_3])
301320
end
321+
322+
it 'uses the rerun file path when applying the id filter' do
323+
ex_1, ex_2 = instance_eval <<-EOS, "./some/spec.rb", 1
324+
ex_1 = ex_2 = nil
325+
326+
RSpec.shared_examples "shared" do
327+
ex_1 = example("ex 1")
328+
ex_2 = example("ex 2")
329+
end
330+
331+
[ex_1, ex_2]
332+
EOS
333+
334+
RSpec.describe { include_examples "shared" }
335+
336+
filter_manager.add_ids(__FILE__, %w[ 1:1 ])
337+
expect(filter_manager.prune([ex_1, ex_2]).map(&:description)).to eq([ex_1].map(&:description))
338+
end
302339
end
303340
end
304341

spec/support/aruba_support.rb

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@ module ArubaLoader
1313
attr_reader :last_cmd_stdout, :last_cmd_stderr
1414

1515
def run_command(cmd)
16+
RSpec.configuration.color = true
17+
1618
temp_stdout = StringIO.new
1719
temp_stderr = StringIO.new
1820
RSpec::Core::Metadata.instance_variable_set(:@relative_path_regex, nil)
@@ -23,6 +25,7 @@ def run_command(cmd)
2325
end
2426
ensure
2527
RSpec.reset
28+
RSpec.configuration.color = true
2629
RSpec::Core::Metadata.instance_variable_set(:@relative_path_regex, nil)
2730

2831
# Ensure it gets cached with a proper value -- if we leave it set to nil,

0 commit comments

Comments
 (0)