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

Commit a4b516f

Browse files
committed
Allow limiting count of displayed failed lines
1 parent eca0b40 commit a4b516f

File tree

6 files changed

+112
-15
lines changed

6 files changed

+112
-15
lines changed

lib/rspec/core/configuration.rb

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -318,6 +318,11 @@ def treat_symbols_as_metadata_keys_with_true_values=(_value)
318318
# Currently this will place a mutex around memoized values such as let blocks.
319319
add_setting :threadsafe
320320

321+
# @macro add_setting
322+
# Maximum count of failed source lines to display in the failure reports.
323+
# (default `10`).
324+
add_setting :max_displayed_count_of_failed_lines
325+
321326
# @private
322327
add_setting :tty
323328
# @private
@@ -372,6 +377,7 @@ def initialize
372377
@libs = []
373378
@derived_metadata_blocks = FilterableItemRepository::QueryOptimized.new(:any?)
374379
@threadsafe = true
380+
@max_displayed_count_of_failed_lines = 10
375381

376382
define_built_in_hooks
377383
end

lib/rspec/core/formatters/exception_presenter.rb

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -177,7 +177,8 @@ def read_failed_lines
177177
end
178178

179179
file_path, line_number = matching_line.match(/(.+?):(\d+)(|:\d+)/)[1..2]
180-
SnippetExtractor.extract_expression_lines_at(file_path, line_number.to_i)
180+
max_line_count = RSpec.configuration.max_displayed_count_of_failed_lines
181+
SnippetExtractor.extract_expression_lines_at(file_path, line_number.to_i, max_line_count)
181182
rescue SnippetExtractor::NoSuchFileError
182183
["Unable to find #{file_path} to read failed line"]
183184
rescue SnippetExtractor::NoSuchLineError

lib/rspec/core/formatters/snippet_extractor.rb

Lines changed: 21 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -29,11 +29,15 @@ def self.raise_error_if_file_does_not_exist!(path)
2929
:on_heredoc_beg => :on_heredoc_end
3030
}
3131

32-
attr_reader :source, :beginning_line_number
33-
34-
def self.extract_expression_lines_at(file_path, beginning_line_number)
35-
source = source_from_file(file_path)
36-
new(source, beginning_line_number).expression_lines
32+
attr_reader :source, :beginning_line_number, :max_line_count
33+
34+
def self.extract_expression_lines_at(file_path, beginning_line_number, max_line_count=nil)
35+
if max_line_count == 1
36+
[extract_line_at(file_path, beginning_line_number)]
37+
else
38+
source = source_from_file(file_path)
39+
new(source, beginning_line_number, max_line_count).expression_lines
40+
end
3741
end
3842

3943
def self.source_from_file(path)
@@ -42,13 +46,23 @@ def self.source_from_file(path)
4246
@source_cache[path] ||= Source.from_file(path)
4347
end
4448

45-
def initialize(source, beginning_line_number)
49+
def self.clear_source_cache!
50+
@source_cache = nil
51+
end
52+
53+
def initialize(source, beginning_line_number, max_line_count=nil)
4654
@source = source
4755
@beginning_line_number = beginning_line_number
56+
@max_line_count = max_line_count
4857
end
4958

5059
def expression_lines
5160
line_range = line_range_of_expression
61+
62+
if max_line_count && line_range.count > max_line_count
63+
line_range = (line_range.begin)..(line_range.begin + max_line_count - 1)
64+
end
65+
5266
source.lines[(line_range.begin - 1)..(line_range.end - 1)]
5367
rescue NoExpressionAtLineError
5468
[self.class.extract_line_at(source.path, beginning_line_number)]
@@ -110,7 +124,7 @@ def location_nodes_at_beginning_line
110124
end
111125
else
112126
# :nocov:
113-
def self.extract_expression_lines_at(file_path, beginning_line_number)
127+
def self.extract_expression_lines_at(file_path, beginning_line_number, *)
114128
[extract_line_at(file_path, beginning_line_number)]
115129
end
116130
# :nocov:

spec/rspec/core/configuration_spec.rb

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2148,6 +2148,17 @@ def emulate_not_configured_expectation_framework
21482148
end
21492149
end
21502150

2151+
describe '#max_displayed_count_of_failed_lines' do
2152+
it 'defaults to 10' do
2153+
expect(config.max_displayed_count_of_failed_lines).to eq 10
2154+
end
2155+
2156+
it 'is configurable' do
2157+
config.max_displayed_count_of_failed_lines = 5
2158+
expect(config.max_displayed_count_of_failed_lines).to eq 5
2159+
end
2160+
end
2161+
21512162
# assigns files_or_directories_to_run and triggers post-processing
21522163
# via `files_to_run`.
21532164
def assign_files_or_directories_to_run(*value)

spec/rspec/core/formatters/exception_presenter_spec.rb

Lines changed: 23 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -167,18 +167,35 @@ def read_failed_lines
167167
context 'when the failed expression spans multiple lines', :if => RSpec::Support::RubyFeatures.ripper_supported? do
168168
let(:exception) do
169169
begin
170-
expect('RSpec').to start_with('R').
170+
expect('RSpec').to be_a(String).
171+
and start_with('R').
171172
and end_with('z')
172173
rescue RSpec::Expectations::ExpectationNotMetError => exception
173174
exception
174175
end
175176
end
176177

177-
it 'returns all the lines' do
178-
expect(read_failed_lines).to eq([
179-
" expect('RSpec').to start_with('R').",
180-
" and end_with('z')"
181-
])
178+
context 'and the line count does not exceed RSpec.configuration.max_displayed_count_of_failed_lines' do
179+
it 'returns all the lines' do
180+
expect(read_failed_lines).to eq([
181+
" expect('RSpec').to be_a(String).",
182+
" and start_with('R').",
183+
" and end_with('z')"
184+
])
185+
end
186+
end
187+
188+
context 'and the line count exceeds RSpec.configuration.max_displayed_count_of_failed_lines' do
189+
before do
190+
RSpec.configuration.max_displayed_count_of_failed_lines = 2
191+
end
192+
193+
it 'returns the lines without exceeding the max count' do
194+
expect(read_failed_lines).to eq([
195+
" expect('RSpec').to be_a(String).",
196+
" and start_with('R')."
197+
])
198+
end
182199
end
183200
end
184201

spec/rspec/core/formatters/snippet_extractor_spec.rb

Lines changed: 49 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
module RSpec::Core::Formatters
44
RSpec.describe SnippetExtractor do
55
subject(:expression_lines) do
6-
SnippetExtractor.extract_expression_lines_at(*location)
6+
SnippetExtractor.extract_expression_lines_at(*location, max_line_count)
77
end
88

99
let(:location) do
@@ -26,6 +26,10 @@ module RSpec::Core::Formatters
2626
end
2727
end
2828

29+
let(:max_line_count) do
30+
nil
31+
end
32+
2933
context 'when the given file does not exist' do
3034
let(:location) do
3135
['/non-existent.rb', 1]
@@ -201,6 +205,50 @@ def another_expression
201205
])
202206
end
203207
end
208+
209+
context 'when max line count is given' do
210+
let(:max_line_count) do
211+
2
212+
end
213+
214+
let(:source) do
215+
raise RuntimerError, "line1", [
216+
"line2",
217+
"line3"
218+
]
219+
end
220+
221+
it 'returns the lines without exceeding the given count' do
222+
expect(expression_lines).to eq([
223+
' raise RuntimerError, "line1", [',
224+
' "line2",'
225+
])
226+
end
227+
end
228+
229+
context 'when max line count is 1' do
230+
let(:max_line_count) do
231+
1
232+
end
233+
234+
let(:source) do
235+
raise RuntimerError, "line1", [
236+
"line2",
237+
"line3"
238+
]
239+
end
240+
241+
before do
242+
SnippetExtractor.clear_source_cache!
243+
end
244+
245+
it 'returns the line without parsing the source for efficiency' do
246+
expect(Ripper).not_to receive(:sexp)
247+
expect(expression_lines).to eq([
248+
' raise RuntimerError, "line1", ['
249+
])
250+
end
251+
end
204252
end
205253

206254
context 'in Ripper unsupported environment', :unless => RSpec::Support::RubyFeatures.ripper_supported? do

0 commit comments

Comments
 (0)