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

Commit 27b187d

Browse files
committed
Allow limiting count of displayed failed lines
1 parent 438512e commit 27b187d

File tree

6 files changed

+109
-15
lines changed

6 files changed

+109
-15
lines changed

lib/rspec/core/configuration.rb

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

335+
# @macro add_setting
336+
# Maximum count of failed source lines to display in the failure reports.
337+
# (default `10`).
338+
add_setting :max_displayed_failure_line_count
339+
335340
# @private
336341
add_setting :tty
337342
# @private
@@ -387,6 +392,7 @@ def initialize
387392
@libs = []
388393
@derived_metadata_blocks = FilterableItemRepository::QueryOptimized.new(:any?)
389394
@threadsafe = true
395+
@max_displayed_failure_line_count = 10
390396

391397
define_built_in_hooks
392398
end

lib/rspec/core/formatters/exception_presenter.rb

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -192,8 +192,9 @@ def read_failed_lines
192192
end
193193

194194
file_path, line_number = matching_line.match(/(.+?):(\d+)(|:\d+)/)[1..2]
195+
max_line_count = RSpec.configuration.max_displayed_failure_line_count
195196
RSpec::Support.require_rspec_core "formatters/snippet_extractor"
196-
SnippetExtractor.extract_expression_lines_at(file_path, line_number.to_i)
197+
SnippetExtractor.extract_expression_lines_at(file_path, line_number.to_i, max_line_count)
197198
rescue SnippetExtractor::NoSuchFileError
198199
["Unable to find #{file_path} to read failed line"]
199200
rescue SnippetExtractor::NoSuchLineError

lib/rspec/core/formatters/snippet_extractor.rb

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -30,20 +30,30 @@ def self.source_from_file(path)
3030
:on_heredoc_beg => :on_heredoc_end
3131
}
3232

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

40-
def initialize(source, beginning_line_number)
44+
def initialize(source, beginning_line_number, max_line_count=nil)
4145
@source = source
4246
@beginning_line_number = beginning_line_number
47+
@max_line_count = max_line_count
4348
end
4449

4550
def expression_lines
4651
line_range = line_range_of_expression
52+
53+
if max_line_count && line_range.count > max_line_count
54+
line_range = (line_range.begin)..(line_range.begin + max_line_count - 1)
55+
end
56+
4757
source.lines[(line_range.begin - 1)..(line_range.end - 1)]
4858
rescue NoExpressionAtLineError
4959
[self.class.extract_line_at(source.path, beginning_line_number)]
@@ -118,7 +128,7 @@ def location_nodes_at_beginning_line
118128
end
119129
else
120130
# :nocov:
121-
def self.extract_expression_lines_at(file_path, beginning_line_number)
131+
def self.extract_expression_lines_at(file_path, beginning_line_number, *)
122132
[extract_line_at(file_path, beginning_line_number)]
123133
end
124134
# :nocov:

spec/rspec/core/configuration_spec.rb

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2172,6 +2172,17 @@ def emulate_not_configured_expectation_framework
21722172
end
21732173
end
21742174

2175+
describe '#max_displayed_failure_line_count' do
2176+
it 'defaults to 10' do
2177+
expect(config.max_displayed_failure_line_count).to eq 10
2178+
end
2179+
2180+
it 'is configurable' do
2181+
config.max_displayed_failure_line_count = 5
2182+
expect(config.max_displayed_failure_line_count).to eq 5
2183+
end
2184+
end
2185+
21752186
# assigns files_or_directories_to_run and triggers post-processing
21762187
# via `files_to_run`.
21772188
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
@@ -177,18 +177,35 @@ def read_failed_lines
177177
context 'when the failed expression spans multiple lines', :if => RSpec::Support::RubyFeatures.ripper_supported? do
178178
let(:exception) do
179179
begin
180-
expect('RSpec').to start_with('R').
180+
expect('RSpec').to be_a(String).
181+
and start_with('R').
181182
and end_with('z')
182183
rescue RSpec::Expectations::ExpectationNotMetError => exception
183184
exception
184185
end
185186
end
186187

187-
it 'returns all the lines' do
188-
expect(read_failed_lines).to eq([
189-
" expect('RSpec').to start_with('R').",
190-
" and end_with('z')"
191-
])
188+
context 'and the line count does not exceed RSpec.configuration.max_displayed_failure_line_count' do
189+
it 'returns all the lines' do
190+
expect(read_failed_lines).to eq([
191+
" expect('RSpec').to be_a(String).",
192+
" and start_with('R').",
193+
" and end_with('z')"
194+
])
195+
end
196+
end
197+
198+
context 'and the line count exceeds RSpec.configuration.max_displayed_failure_line_count' do
199+
before do
200+
RSpec.configuration.max_displayed_failure_line_count = 2
201+
end
202+
203+
it 'returns the lines without exceeding the max count' do
204+
expect(read_failed_lines).to eq([
205+
" expect('RSpec').to be_a(String).",
206+
" and start_with('R')."
207+
])
208+
end
192209
end
193210
end
194211

spec/rspec/core/formatters/snippet_extractor_spec.rb

Lines changed: 50 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(file_path, line_number)
6+
SnippetExtractor.extract_expression_lines_at(file_path, line_number, max_line_count)
77
end
88

99
let(:file_path) do
@@ -24,6 +24,10 @@ module RSpec::Core::Formatters
2424
location
2525
end
2626

27+
let(:max_line_count) do
28+
nil
29+
end
30+
2731
let(:error) do
2832
begin
2933
source
@@ -245,6 +249,51 @@ def another_expression(*)
245249
])
246250
end
247251
end
252+
253+
context 'when max line count is given' do
254+
let(:max_line_count) do
255+
2
256+
end
257+
258+
let(:source) do
259+
do_something_fail "line1", [
260+
"line2",
261+
"line3"
262+
]
263+
end
264+
265+
it 'returns the lines without exceeding the given count' do
266+
expect(expression_lines).to eq([
267+
' do_something_fail "line1", [',
268+
' "line2",'
269+
])
270+
end
271+
end
272+
273+
context 'when max line count is 1' do
274+
let(:max_line_count) do
275+
1
276+
end
277+
278+
let(:source) do
279+
do_something_fail "line1", [
280+
"line2",
281+
"line3"
282+
]
283+
end
284+
285+
before do
286+
RSpec.reset # Clear source cache
287+
end
288+
289+
it 'returns the line without parsing the source for efficiency' do
290+
require 'ripper'
291+
expect(Ripper).not_to receive(:sexp)
292+
expect(expression_lines).to eq([
293+
' do_something_fail "line1", ['
294+
])
295+
end
296+
end
248297
end
249298

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

0 commit comments

Comments
 (0)