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

Commit 59f4519

Browse files
committed
Merge pull request #2170 from rspec/issue-2136
When filtering, do not consider declaration lines from other files.
2 parents 00a8288 + 358733a commit 59f4519

File tree

9 files changed

+119
-39
lines changed

9 files changed

+119
-39
lines changed

Changelog.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,9 @@ Bug Fixes:
55

66
* Prevent a `TypeError` from occuring when running via the rake task when
77
Ruby crashes. (Patrik Wenger, #2161)
8+
* Only consider example and group declaration lines from a specific file
9+
when applying line number filtering, instead of considering all
10+
declaration lines from all spec files. (Myron Marston, #2170)
811

912
### 3.5.0.beta1 / 2016-02-06
1013
[Full Changelog](http://github.com/rspec/rspec-core/compare/v3.4.2...v3.5.0.beta1)

lib/rspec/core/example_group.rb

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -347,7 +347,7 @@ def self.reset_memoized
347347
@descendant_filtered_examples = nil
348348
@_descendants = nil
349349
@parent_groups = nil
350-
@declaration_line_numbers = nil
350+
@declaration_locations = nil
351351
end
352352

353353
# Adds an example to the example group
@@ -613,10 +613,10 @@ def self.for_filtered_examples(reporter, &block)
613613
end
614614

615615
# @private
616-
def self.declaration_line_numbers
617-
@declaration_line_numbers ||= [metadata[:line_number]] +
618-
examples.map { |e| e.metadata[:line_number] } +
619-
FlatMap.flat_map(children, &:declaration_line_numbers)
616+
def self.declaration_locations
617+
@declaration_locations ||= [Metadata.location_tuple_from(metadata)] +
618+
examples.map { |e| Metadata.location_tuple_from(e.metadata) } +
619+
FlatMap.flat_map(children, &:declaration_locations)
620620
end
621621

622622
# @return [String] the unique id of this example group. Pass

lib/rspec/core/metadata.rb

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,11 @@ def self.id_from(metadata)
106106
"#{metadata[:rerun_file_path]}[#{metadata[:scoped_id]}]"
107107
end
108108

109+
# @private
110+
def self.location_tuple_from(metadata)
111+
[metadata[:absolute_file_path], metadata[:line_number]]
112+
end
113+
109114
# @private
110115
# Used internally to populate metadata hashes with computed keys
111116
# managed by RSpec.

lib/rspec/core/metadata_filter.rb

Lines changed: 10 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,9 @@ def apply?(predicate, filters, metadata)
1515
# @private
1616
def filter_applies?(key, value, metadata)
1717
silence_metadata_example_group_deprecations do
18-
return location_filter_applies?(value, metadata) if key == :locations
19-
return id_filter_applies?(value, metadata) if key == :ids
20-
return filters_apply?(key, value, metadata) if Hash === value
18+
return location_filter_applies?(value, metadata) if key == :locations
19+
return id_filter_applies?(value, metadata) if key == :ids
20+
return filters_apply?(key, value, metadata) if Hash === value
2121

2222
return false unless metadata.key?(key)
2323
return true if TrueClass === value && !!metadata[key]
@@ -49,13 +49,14 @@ def id_filter_applies?(rerun_paths_to_scoped_ids, metadata)
4949
end
5050

5151
def location_filter_applies?(locations, metadata)
52-
line_numbers = example_group_declaration_lines(locations, metadata)
53-
line_number_filter_applies?(line_numbers, metadata)
54-
end
52+
Metadata.ascend(metadata).any? do |meta|
53+
file_path = meta[:absolute_file_path]
54+
line_num = meta[:line_number]
5555

56-
def line_number_filter_applies?(line_numbers, metadata)
57-
preceding_declaration_lines = line_numbers.map { |n| RSpec.world.preceding_declaration_line(n) }
58-
!(relevant_line_numbers(metadata) & preceding_declaration_lines).empty?
56+
locations[file_path].any? do |filter_line_num|
57+
line_num == RSpec.world.preceding_declaration_line(file_path, filter_line_num)
58+
end
59+
end
5960
end
6061

6162
def proc_filter_applies?(key, proc, metadata)
@@ -66,16 +67,6 @@ def proc_filter_applies?(key, proc, metadata)
6667
end
6768
end
6869

69-
def relevant_line_numbers(metadata)
70-
Metadata.ascend(metadata).map { |meta| meta[:line_number] }
71-
end
72-
73-
def example_group_declaration_lines(locations, metadata)
74-
FlatMap.flat_map(Metadata.ascend(metadata)) do |meta|
75-
locations[meta[:absolute_file_path]]
76-
end.uniq
77-
end
78-
7970
def filters_apply?(key, value, metadata)
8071
subhash = metadata[key]
8172
return false unless Hash === subhash || HashImitatable === subhash

lib/rspec/core/world.rb

Lines changed: 21 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -96,10 +96,12 @@ def all_examples
9696
# @api private
9797
#
9898
# Find line number of previous declaration.
99-
def preceding_declaration_line(filter_line)
100-
declaration_line_numbers.sort.inject(nil) do |highest_prior_declaration_line, line|
101-
line <= filter_line ? line : highest_prior_declaration_line
99+
def preceding_declaration_line(absolute_file_name, filter_line)
100+
line_numbers = descending_declaration_line_numbers_by_file.fetch(absolute_file_name) do
101+
return nil
102102
end
103+
104+
line_numbers.find { |num| num <= filter_line }
103105
end
104106

105107
# @private
@@ -179,8 +181,22 @@ def announce_exclusion_filter(announcements)
179181

180182
private
181183

182-
def declaration_line_numbers
183-
@declaration_line_numbers ||= FlatMap.flat_map(example_groups, &:declaration_line_numbers)
184+
def descending_declaration_line_numbers_by_file
185+
@descending_declaration_line_numbers_by_file ||= begin
186+
declaration_locations = FlatMap.flat_map(example_groups, &:declaration_locations)
187+
hash_of_arrays = Hash.new { |h, k| h[k] = [] }
188+
189+
# TODO: change `inject` to `each_with_object` when we drop 1.8.7 support.
190+
line_nums_by_file = declaration_locations.inject(hash_of_arrays) do |hash, (file_name, line_number)|
191+
hash[file_name] << line_number
192+
hash
193+
end
194+
195+
line_nums_by_file.each_value do |list|
196+
list.sort!
197+
list.reverse!
198+
end
199+
end
184200
end
185201

186202
def fail_if_config_and_cli_options_invalid

spec/integration/filtering_spec.rb

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,33 @@ def run_rerun_command_for_failing_spec
9696
run_command "spec/a_spec.rb:13 -fd" # selecting :if => false example
9797
expect(last_cmd_stdout).to include("0 examples, 0 failures").and exclude("ex 1", "ex 2", "ex 3", "ex 4", "ex 5")
9898
end
99+
100+
it 'works correctly when line numbers align with a shared example group line number from another file' do
101+
write_file_formatted 'spec/support/shared_examples_with_matching_line.rb', "
102+
# line 1
103+
# line 2
104+
# line 3
105+
RSpec.shared_examples_for 'shared examples' do # line 4
106+
it 'fails' do # line 5
107+
fail 'shared example'
108+
end
109+
end
110+
"
111+
112+
write_file_formatted 'spec/some_spec.rb', "
113+
require File.expand_path('../support/shared_examples_with_matching_line', __FILE__) # line 1
114+
RSpec.describe 'A group' do # line 2
115+
it_behaves_like 'shared examples' # line 3
116+
# line 4
117+
it 'passes' do # line 5
118+
expect(1).to eq(1)
119+
end
120+
end
121+
"
122+
123+
run_command "spec/some_spec.rb:5"
124+
expect(last_cmd_stdout).to include("1 example, 0 failures")
125+
end
99126
end
100127

101128
context "passing a line-number-filtered file and a non-filtered file" do

spec/rspec/core/example_group_spec.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1878,7 +1878,7 @@ def foo; end
18781878
def group_ids group
18791879
ids = []
18801880
['descendant_filtered_examples', 'descendants',
1881-
'parent_groups', 'declaration_line_numbers', 'before_context_ivars'].each do |method|
1881+
'parent_groups', 'declaration_locations', 'before_context_ivars'].each do |method|
18821882
ids << group.send(method).object_id
18831883
end
18841884
ids

spec/rspec/core/metadata_filter_spec.rb

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -52,8 +52,8 @@ def filter_applies?(key, value, metadata)
5252
}}
5353

5454
before do
55-
expect(world).to receive(:preceding_declaration_line).at_least(:once) do |v|
56-
preceeding_declaration_lines[v]
55+
expect(world).to receive(:preceding_declaration_line).at_least(:once) do |_file_name, line_num|
56+
preceeding_declaration_lines[line_num]
5757
end
5858
end
5959

spec/rspec/core/world_spec.rb

Lines changed: 45 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -91,31 +91,35 @@ module RSpec::Core
9191
let(:group_declaration_line) { group.metadata[:line_number] }
9292
let(:example_declaration_line) { group_declaration_line + 2 }
9393

94+
def preceding_declaration_line(line_num)
95+
world.preceding_declaration_line(__FILE__, line_num)
96+
end
97+
9498
context "with one example" do
9599
before { world.register(group) }
96100

97101
it "returns nil if no example or group precedes the line" do
98-
expect(world.preceding_declaration_line(group_declaration_line - 1)).to be_nil
102+
expect(preceding_declaration_line(group_declaration_line - 1)).to be_nil
99103
end
100104

101105
it "returns the argument line number if a group starts on that line" do
102-
expect(world.preceding_declaration_line(group_declaration_line)).to eq(group_declaration_line)
106+
expect(preceding_declaration_line(group_declaration_line)).to eq(group_declaration_line)
103107
end
104108

105109
it "returns the argument line number if an example starts on that line" do
106-
expect(world.preceding_declaration_line(example_declaration_line)).to eq(example_declaration_line)
110+
expect(preceding_declaration_line(example_declaration_line)).to eq(example_declaration_line)
107111
end
108112

109113
it "returns line number of a group that immediately precedes the argument line" do
110-
expect(world.preceding_declaration_line(group_declaration_line + 1)).to eq(group_declaration_line)
114+
expect(preceding_declaration_line(group_declaration_line + 1)).to eq(group_declaration_line)
111115
end
112116

113117
it "returns line number of an example that immediately precedes the argument line" do
114-
expect(world.preceding_declaration_line(example_declaration_line + 1)).to eq(example_declaration_line)
118+
expect(preceding_declaration_line(example_declaration_line + 1)).to eq(example_declaration_line)
115119
end
116120
end
117121

118-
context "with two exaples and the second example is registre first" do
122+
context "with two groups and the second example is registered first" do
119123
let(:second_group_declaration_line) { second_group.metadata[:line_number] }
120124

121125
before do
@@ -124,7 +128,41 @@ module RSpec::Core
124128
end
125129

126130
it 'return line number of group if a group start on that line' do
127-
expect(world.preceding_declaration_line(second_group_declaration_line)).to eq(second_group_declaration_line)
131+
expect(preceding_declaration_line(second_group_declaration_line)).to eq(second_group_declaration_line)
132+
end
133+
end
134+
135+
context "with groups from multiple files registered" do
136+
another_file = File.join(__FILE__, "another_spec_file.rb")
137+
138+
let(:group_from_another_file) do
139+
instance_eval <<-EOS, another_file, 1
140+
RSpec.describe("third group") do
141+
142+
example("inside of a gropu")
143+
144+
end
145+
EOS
146+
end
147+
148+
before do
149+
world.register(group)
150+
world.register(group_from_another_file)
151+
end
152+
153+
it "returns nil if given a file name with no declarations" do
154+
expect(world.preceding_declaration_line("/some/other/file.rb", 100_000)).to eq(nil)
155+
end
156+
157+
it "considers only declaration lines from the provided files", :aggregate_failures do
158+
expect(world.preceding_declaration_line(another_file, 1)).to eq(1)
159+
expect(world.preceding_declaration_line(another_file, 2)).to eq(1)
160+
expect(world.preceding_declaration_line(another_file, 3)).to eq(3)
161+
expect(world.preceding_declaration_line(another_file, 4)).to eq(3)
162+
expect(world.preceding_declaration_line(another_file, 5)).to eq(3)
163+
expect(world.preceding_declaration_line(another_file, 100_000)).to eq(3)
164+
165+
expect(world.preceding_declaration_line(__FILE__, group_declaration_line + 1)).to eq(group_declaration_line)
128166
end
129167
end
130168
end

0 commit comments

Comments
 (0)