rspec-core 3.8.0 → 3.12.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +5 -5
- checksums.yaml.gz.sig +0 -0
- data/Changelog.md +154 -0
- data/README.md +20 -20
- data/lib/rspec/core/bisect/fork_runner.rb +6 -2
- data/lib/rspec/core/bisect/server.rb +1 -1
- data/lib/rspec/core/bisect/utilities.rb +12 -1
- data/lib/rspec/core/configuration.rb +126 -30
- data/lib/rspec/core/did_you_mean.rb +46 -0
- data/lib/rspec/core/drb.rb +7 -0
- data/lib/rspec/core/example.rb +18 -5
- data/lib/rspec/core/example_group.rb +36 -16
- data/lib/rspec/core/example_status_persister.rb +2 -2
- data/lib/rspec/core/filter_manager.rb +1 -1
- data/lib/rspec/core/formatters/console_codes.rb +17 -9
- data/lib/rspec/core/formatters/documentation_formatter.rb +35 -3
- data/lib/rspec/core/formatters/exception_presenter.rb +40 -12
- data/lib/rspec/core/formatters/failure_list_formatter.rb +23 -0
- data/lib/rspec/core/formatters/helpers.rb +9 -1
- data/lib/rspec/core/formatters/html_printer.rb +1 -3
- data/lib/rspec/core/formatters/html_snippet_extractor.rb +2 -2
- data/lib/rspec/core/formatters.rb +12 -2
- data/lib/rspec/core/hooks.rb +43 -21
- data/lib/rspec/core/invocations.rb +1 -1
- data/lib/rspec/core/memoized_helpers.rb +60 -15
- data/lib/rspec/core/metadata.rb +2 -3
- data/lib/rspec/core/metadata_filter.rb +1 -1
- data/lib/rspec/core/option_parser.rb +27 -13
- data/lib/rspec/core/ordering.rb +12 -1
- data/lib/rspec/core/pending.rb +8 -16
- data/lib/rspec/core/project_initializer/spec/spec_helper.rb +2 -4
- data/lib/rspec/core/rake_task.rb +22 -2
- data/lib/rspec/core/reporter.rb +9 -1
- data/lib/rspec/core/runner.rb +16 -3
- data/lib/rspec/core/shared_example_group.rb +4 -2
- data/lib/rspec/core/version.rb +1 -1
- data/lib/rspec/core/world.rb +17 -5
- data/lib/rspec/core.rb +27 -0
- data.tar.gz.sig +0 -0
- metadata +21 -15
- metadata.gz.sig +0 -0
@@ -0,0 +1,46 @@
|
|
1
|
+
module RSpec
|
2
|
+
module Core
|
3
|
+
# @private
|
4
|
+
# Wrapper around Ruby's `DidYouMean::SpellChecker` when available to provide file name suggestions.
|
5
|
+
class DidYouMean
|
6
|
+
attr_reader :relative_file_name
|
7
|
+
|
8
|
+
def initialize(relative_file_name)
|
9
|
+
@relative_file_name = relative_file_name
|
10
|
+
end
|
11
|
+
|
12
|
+
if defined?(::DidYouMean::SpellChecker)
|
13
|
+
# provide probable suggestions
|
14
|
+
def call
|
15
|
+
checker = ::DidYouMean::SpellChecker.new(:dictionary => Dir["spec/**/*.rb"])
|
16
|
+
probables = checker.correct(relative_file_name.sub('./', ''))[0..2]
|
17
|
+
return '' unless probables.any?
|
18
|
+
|
19
|
+
formats probables
|
20
|
+
end
|
21
|
+
else
|
22
|
+
# return a hint if API for ::DidYouMean::SpellChecker not supported
|
23
|
+
def call
|
24
|
+
"\nHint: Install the `did_you_mean` gem in order to provide suggestions for similarly named files."
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
private
|
29
|
+
|
30
|
+
def formats(probables)
|
31
|
+
rspec_format = probables.map { |s, _| "rspec ./#{s}" }
|
32
|
+
red_font(top_and_tail rspec_format)
|
33
|
+
end
|
34
|
+
|
35
|
+
def top_and_tail(rspec_format)
|
36
|
+
spaces = ' ' * 20
|
37
|
+
rspec_format.insert(0, ' - Did you mean?').join("\n#{spaces}") + "\n"
|
38
|
+
end
|
39
|
+
|
40
|
+
def red_font(mytext)
|
41
|
+
colorizer = ::RSpec::Core::Formatters::ConsoleCodes
|
42
|
+
colorizer.wrap mytext, :failure
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
data/lib/rspec/core/drb.rb
CHANGED
@@ -51,6 +51,7 @@ module RSpec
|
|
51
51
|
argv << "--order" << @submitted_options[:order] if @submitted_options[:order]
|
52
52
|
|
53
53
|
add_failure_exit_code(argv)
|
54
|
+
add_error_exit_code(argv)
|
54
55
|
add_full_description(argv)
|
55
56
|
add_filter(argv, :inclusion, @filter_manager.inclusions)
|
56
57
|
add_filter(argv, :exclusion, @filter_manager.exclusions)
|
@@ -67,6 +68,12 @@ module RSpec
|
|
67
68
|
argv << "--failure-exit-code" << @submitted_options[:failure_exit_code].to_s
|
68
69
|
end
|
69
70
|
|
71
|
+
def add_error_exit_code(argv)
|
72
|
+
return unless @submitted_options[:error_exit_code]
|
73
|
+
|
74
|
+
argv << "--error-exit-code" << @submitted_options[:error_exit_code].to_s
|
75
|
+
end
|
76
|
+
|
70
77
|
def add_full_description(argv)
|
71
78
|
return unless @submitted_options[:full_description]
|
72
79
|
|
data/lib/rspec/core/example.rb
CHANGED
@@ -203,10 +203,13 @@ module RSpec
|
|
203
203
|
description, example_block
|
204
204
|
)
|
205
205
|
|
206
|
+
config = RSpec.configuration
|
207
|
+
config.apply_derived_metadata_to(@metadata)
|
208
|
+
|
206
209
|
# This should perhaps be done in `Metadata::ExampleHash.create`,
|
207
210
|
# but the logic there has no knowledge of `RSpec.world` and we
|
208
211
|
# want to keep it that way. It's easier to just assign it here.
|
209
|
-
@metadata[:last_run_status] =
|
212
|
+
@metadata[:last_run_status] = config.last_run_statuses[id]
|
210
213
|
|
211
214
|
@example_group_instance = @exception = nil
|
212
215
|
@clock = RSpec::Core::Time
|
@@ -228,8 +231,13 @@ module RSpec
|
|
228
231
|
@example_group_class
|
229
232
|
end
|
230
233
|
|
231
|
-
|
232
|
-
|
234
|
+
def pending?
|
235
|
+
!!pending
|
236
|
+
end
|
237
|
+
|
238
|
+
def skipped?
|
239
|
+
!!skip
|
240
|
+
end
|
233
241
|
|
234
242
|
# @api private
|
235
243
|
# instance_execs the block passed to the constructor in the context of
|
@@ -251,6 +259,7 @@ module RSpec
|
|
251
259
|
with_around_and_singleton_context_hooks do
|
252
260
|
begin
|
253
261
|
run_before_example
|
262
|
+
RSpec.current_scope = :example
|
254
263
|
@example_group_instance.instance_exec(self, &@example_block)
|
255
264
|
|
256
265
|
if pending?
|
@@ -270,6 +279,7 @@ module RSpec
|
|
270
279
|
rescue AllExceptionsExcludingDangerousOnesOnRubiesThatAllowIt => e
|
271
280
|
set_exception(e)
|
272
281
|
ensure
|
282
|
+
RSpec.current_scope = :after_example_hook
|
273
283
|
run_after_example
|
274
284
|
end
|
275
285
|
end
|
@@ -367,7 +377,7 @@ module RSpec
|
|
367
377
|
|
368
378
|
# @private
|
369
379
|
def inspect
|
370
|
-
@example.inspect.gsub('Example', '
|
380
|
+
@example.inspect.gsub('Example', 'Example::Procsy')
|
371
381
|
end
|
372
382
|
end
|
373
383
|
|
@@ -454,6 +464,7 @@ module RSpec
|
|
454
464
|
end
|
455
465
|
|
456
466
|
def with_around_example_hooks
|
467
|
+
RSpec.current_scope = :before_example_hook
|
457
468
|
hooks.run(:around, :example, self) { yield }
|
458
469
|
rescue Support::AllExceptionsExceptOnesWeMustNotRescue => e
|
459
470
|
set_exception(e)
|
@@ -574,7 +585,9 @@ module RSpec
|
|
574
585
|
# this indicates whether or not it now passes.
|
575
586
|
attr_accessor :pending_fixed
|
576
587
|
|
577
|
-
|
588
|
+
def pending_fixed?
|
589
|
+
!!pending_fixed
|
590
|
+
end
|
578
591
|
|
579
592
|
# @return [Boolean] Indicates if the example was completely skipped
|
580
593
|
# (typically done via `:skip` metadata or the `skip` method). Skipped examples
|
@@ -7,7 +7,7 @@ module RSpec
|
|
7
7
|
# ExampleGroup and {Example} are the main structural elements of
|
8
8
|
# rspec-core. Consider this example:
|
9
9
|
#
|
10
|
-
# describe Thing do
|
10
|
+
# RSpec.describe Thing do
|
11
11
|
# it "does something" do
|
12
12
|
# end
|
13
13
|
# end
|
@@ -90,7 +90,7 @@ module RSpec
|
|
90
90
|
# Returns the class or module passed to the `describe` method (or alias).
|
91
91
|
# Returns nil if the subject is not a class or module.
|
92
92
|
# @example
|
93
|
-
# describe Thing do
|
93
|
+
# RSpec.describe Thing do
|
94
94
|
# it "does something" do
|
95
95
|
# described_class == Thing
|
96
96
|
# end
|
@@ -111,16 +111,14 @@ module RSpec
|
|
111
111
|
# @overload $1
|
112
112
|
# @overload $1(&example_implementation)
|
113
113
|
# @param example_implementation [Block] The implementation of the example.
|
114
|
-
# @overload $1(doc_string, *
|
114
|
+
# @overload $1(doc_string, *metadata)
|
115
115
|
# @param doc_string [String] The example's doc string.
|
116
|
-
# @param metadata [Hash] Metadata for the example.
|
117
|
-
#
|
118
|
-
#
|
119
|
-
# @overload $1(doc_string, *metadata_keys, metadata={}, &example_implementation)
|
116
|
+
# @param metadata [Array<Symbol>, Hash] Metadata for the example.
|
117
|
+
# Symbols will be transformed into hash entries with `true` values.
|
118
|
+
# @overload $1(doc_string, *metadata, &example_implementation)
|
120
119
|
# @param doc_string [String] The example's doc string.
|
121
|
-
# @param metadata [Hash] Metadata for the example.
|
122
|
-
#
|
123
|
-
# Will be transformed into hash entries with `true` values.
|
120
|
+
# @param metadata [Array<Symbol>, Hash] Metadata for the example.
|
121
|
+
# Symbols will be transformed into hash entries with `true` values.
|
124
122
|
# @param example_implementation [Block] The implementation of the example.
|
125
123
|
# @yield [Example] the example object
|
126
124
|
# @example
|
@@ -139,6 +137,11 @@ module RSpec
|
|
139
137
|
# $1 "does something" do |ex|
|
140
138
|
# # ex is the Example object that contains metadata about the example
|
141
139
|
# end
|
140
|
+
#
|
141
|
+
# @example
|
142
|
+
# $1 "does something", :slow, :load_factor => 100 do
|
143
|
+
# end
|
144
|
+
#
|
142
145
|
def self.define_example_method(name, extra_options={})
|
143
146
|
idempotently_define_singleton_method(name) do |*all_args, &block|
|
144
147
|
desc, *args = *all_args
|
@@ -204,11 +207,10 @@ module RSpec
|
|
204
207
|
# @overload $1
|
205
208
|
# @overload $1(&example_group_definition)
|
206
209
|
# @param example_group_definition [Block] The definition of the example group.
|
207
|
-
# @overload $1(doc_string, *
|
210
|
+
# @overload $1(doc_string, *metadata, &example_implementation)
|
208
211
|
# @param doc_string [String] The group's doc string.
|
209
|
-
# @param metadata [Hash] Metadata for the group.
|
210
|
-
#
|
211
|
-
# Will be transformed into hash entries with `true` values.
|
212
|
+
# @param metadata [Array<Symbol>, Hash] Metadata for the group.
|
213
|
+
# Symbols will be transformed into hash entries with `true` values.
|
212
214
|
# @param example_group_definition [Block] The definition of the example group.
|
213
215
|
#
|
214
216
|
# Generates a subclass of this example group which inherits
|
@@ -223,12 +225,21 @@ module RSpec
|
|
223
225
|
# do_something_before
|
224
226
|
# end
|
225
227
|
#
|
228
|
+
# before(:example, :clean_env) do
|
229
|
+
# env.clear!
|
230
|
+
# end
|
231
|
+
#
|
226
232
|
# let(:thing) { Thing.new }
|
227
233
|
#
|
228
234
|
# $1 "attribute (of something)" do
|
229
235
|
# # examples in the group get the before hook
|
230
236
|
# # declared above, and can access `thing`
|
231
237
|
# end
|
238
|
+
#
|
239
|
+
# $1 "needs additional setup", :clean_env, :implementation => JSON do
|
240
|
+
# # specifies that hooks with matching metadata
|
241
|
+
# # should be be run additionally
|
242
|
+
# end
|
232
243
|
# end
|
233
244
|
#
|
234
245
|
# @see DSL#describe
|
@@ -424,11 +435,15 @@ module RSpec
|
|
424
435
|
superclass.method(:next_runnable_index_for),
|
425
436
|
description, *args, &example_group_block
|
426
437
|
)
|
438
|
+
|
439
|
+
config = RSpec.configuration
|
440
|
+
config.apply_derived_metadata_to(@metadata)
|
441
|
+
|
427
442
|
ExampleGroups.assign_const(self)
|
428
443
|
|
429
444
|
@currently_executing_a_context_hook = false
|
430
445
|
|
431
|
-
|
446
|
+
config.configure_group(self)
|
432
447
|
end
|
433
448
|
|
434
449
|
# @private
|
@@ -587,6 +602,7 @@ module RSpec
|
|
587
602
|
|
588
603
|
should_run_context_hooks = descendant_filtered_examples.any?
|
589
604
|
begin
|
605
|
+
RSpec.current_scope = :before_context_hook
|
590
606
|
run_before_context_hooks(new('before(:context) hook')) if should_run_context_hooks
|
591
607
|
result_for_this_group = run_examples(reporter)
|
592
608
|
results_for_descendants = ordering_strategy.order(children).map { |child| child.run(reporter) }.all?
|
@@ -599,6 +615,7 @@ module RSpec
|
|
599
615
|
RSpec.world.wants_to_quit = true if reporter.fail_fast_limit_met?
|
600
616
|
false
|
601
617
|
ensure
|
618
|
+
RSpec.current_scope = :after_context_hook
|
602
619
|
run_after_context_hooks(new('after(:context) hook')) if should_run_context_hooks
|
603
620
|
reporter.example_group_finished(self)
|
604
621
|
end
|
@@ -686,6 +703,7 @@ module RSpec
|
|
686
703
|
end
|
687
704
|
end
|
688
705
|
|
706
|
+
# @private
|
689
707
|
def initialize(inspect_output=nil)
|
690
708
|
@__inspect_output = inspect_output || '(no description provided)'
|
691
709
|
super() # no args get passed
|
@@ -746,8 +764,9 @@ module RSpec
|
|
746
764
|
"on an example group (e.g. a `describe` or `context` block)."
|
747
765
|
end
|
748
766
|
|
749
|
-
super
|
767
|
+
super(name, *args)
|
750
768
|
end
|
769
|
+
ruby2_keywords :method_missing if respond_to?(:ruby2_keywords, true)
|
751
770
|
end
|
752
771
|
# rubocop:enable Metrics/ClassLength
|
753
772
|
|
@@ -766,6 +785,7 @@ module RSpec
|
|
766
785
|
# @return [String] the location where the shared example was included
|
767
786
|
attr_reader :inclusion_location
|
768
787
|
|
788
|
+
# @private
|
769
789
|
def initialize(shared_group_name, inclusion_location)
|
770
790
|
@shared_group_name = shared_group_name
|
771
791
|
@inclusion_location = inclusion_location
|
@@ -63,7 +63,7 @@ module RSpec
|
|
63
63
|
# were loaded but not executed (due to filtering, `--fail-fast`
|
64
64
|
# or whatever) should have a `:status` of `UNKNOWN_STATUS`.
|
65
65
|
#
|
66
|
-
# This
|
66
|
+
# This will produce a new list that:
|
67
67
|
# - Will be missing examples from previous runs that we know for sure
|
68
68
|
# no longer exist.
|
69
69
|
# - Will have the latest known status for any examples that either
|
@@ -164,7 +164,7 @@ module RSpec
|
|
164
164
|
end
|
165
165
|
|
166
166
|
def formatted_value_rows
|
167
|
-
@
|
167
|
+
@formatted_value_rows ||= rows.map do |row|
|
168
168
|
formatted_row_from(row)
|
169
169
|
end
|
170
170
|
end
|
@@ -7,15 +7,23 @@ module RSpec
|
|
7
7
|
# @private
|
8
8
|
VT100_CODES =
|
9
9
|
{
|
10
|
-
:black
|
11
|
-
:red
|
12
|
-
:green
|
13
|
-
:yellow
|
14
|
-
:blue
|
15
|
-
:magenta
|
16
|
-
:cyan
|
17
|
-
:white
|
18
|
-
:
|
10
|
+
:black => 30,
|
11
|
+
:red => 31,
|
12
|
+
:green => 32,
|
13
|
+
:yellow => 33,
|
14
|
+
:blue => 34,
|
15
|
+
:magenta => 35,
|
16
|
+
:cyan => 36,
|
17
|
+
:white => 37,
|
18
|
+
:bold_black => '1;30',
|
19
|
+
:bold_red => '1;31',
|
20
|
+
:bold_green => '1;32',
|
21
|
+
:bold_yellow => '1;33',
|
22
|
+
:bold_blue => '1;34',
|
23
|
+
:bold_magenta => '1;35',
|
24
|
+
:bold_cyan => '1;36',
|
25
|
+
:bold_white => '1;37',
|
26
|
+
:bold => 1,
|
19
27
|
}
|
20
28
|
# @private
|
21
29
|
VT100_CODE_VALUES = VT100_CODES.invert
|
@@ -6,12 +6,19 @@ module RSpec
|
|
6
6
|
module Formatters
|
7
7
|
# @private
|
8
8
|
class DocumentationFormatter < BaseTextFormatter
|
9
|
-
Formatters.register self, :example_group_started, :example_group_finished,
|
9
|
+
Formatters.register self, :example_started, :example_group_started, :example_group_finished,
|
10
10
|
:example_passed, :example_pending, :example_failed
|
11
11
|
|
12
12
|
def initialize(output)
|
13
13
|
super
|
14
14
|
@group_level = 0
|
15
|
+
|
16
|
+
@example_running = false
|
17
|
+
@messages = []
|
18
|
+
end
|
19
|
+
|
20
|
+
def example_started(_notification)
|
21
|
+
@example_running = true
|
15
22
|
end
|
16
23
|
|
17
24
|
def example_group_started(notification)
|
@@ -27,19 +34,44 @@ module RSpec
|
|
27
34
|
|
28
35
|
def example_passed(passed)
|
29
36
|
output.puts passed_output(passed.example)
|
37
|
+
|
38
|
+
flush_messages
|
39
|
+
@example_running = false
|
30
40
|
end
|
31
41
|
|
32
42
|
def example_pending(pending)
|
33
43
|
output.puts pending_output(pending.example,
|
34
44
|
pending.example.execution_result.pending_message)
|
45
|
+
|
46
|
+
flush_messages
|
47
|
+
@example_running = false
|
35
48
|
end
|
36
49
|
|
37
50
|
def example_failed(failure)
|
38
51
|
output.puts failure_output(failure.example)
|
52
|
+
|
53
|
+
flush_messages
|
54
|
+
@example_running = false
|
55
|
+
end
|
56
|
+
|
57
|
+
def message(notification)
|
58
|
+
if @example_running
|
59
|
+
@messages << notification.message
|
60
|
+
else
|
61
|
+
output.puts "#{current_indentation}#{notification.message}"
|
62
|
+
end
|
39
63
|
end
|
40
64
|
|
41
65
|
private
|
42
66
|
|
67
|
+
def flush_messages
|
68
|
+
@messages.each do |message|
|
69
|
+
output.puts "#{current_indentation(1)}#{message}"
|
70
|
+
end
|
71
|
+
|
72
|
+
@messages.clear
|
73
|
+
end
|
74
|
+
|
43
75
|
def passed_output(example)
|
44
76
|
ConsoleCodes.wrap("#{current_indentation}#{example.description.strip}", :success)
|
45
77
|
end
|
@@ -61,8 +93,8 @@ module RSpec
|
|
61
93
|
@next_failure_index += 1
|
62
94
|
end
|
63
95
|
|
64
|
-
def current_indentation
|
65
|
-
' ' * @group_level
|
96
|
+
def current_indentation(offset=0)
|
97
|
+
' ' * (@group_level + offset)
|
66
98
|
end
|
67
99
|
end
|
68
100
|
end
|
@@ -43,7 +43,7 @@ module RSpec
|
|
43
43
|
|
44
44
|
if RSpec::Support::RubyFeatures.supports_exception_cause?
|
45
45
|
def formatted_cause(exception)
|
46
|
-
last_cause = final_exception(exception)
|
46
|
+
last_cause = final_exception(exception, [exception])
|
47
47
|
cause = []
|
48
48
|
|
49
49
|
if exception.cause
|
@@ -51,11 +51,13 @@ module RSpec
|
|
51
51
|
cause << '--- Caused by: ---'
|
52
52
|
cause << "#{exception_class_name(last_cause)}:" unless exception_class_name(last_cause) =~ /RSpec/
|
53
53
|
|
54
|
-
encoded_string(last_cause
|
54
|
+
encoded_string(exception_message_string(last_cause)).split("\n").each do |line|
|
55
55
|
cause << " #{line}"
|
56
56
|
end
|
57
57
|
|
58
|
-
|
58
|
+
unless last_cause.backtrace.nil? || last_cause.backtrace.empty?
|
59
|
+
cause << (" #{backtrace_formatter.format_backtrace(last_cause.backtrace, example.metadata).first}")
|
60
|
+
end
|
59
61
|
end
|
60
62
|
|
61
63
|
cause
|
@@ -81,7 +83,7 @@ module RSpec
|
|
81
83
|
|
82
84
|
def fully_formatted_lines(failure_number, colorizer)
|
83
85
|
lines = [
|
84
|
-
description,
|
86
|
+
encoded_description(description),
|
85
87
|
detail_formatter.call(example, colorizer),
|
86
88
|
formatted_message_and_backtrace(colorizer),
|
87
89
|
extra_detail_formatter.call(failure_number, colorizer),
|
@@ -96,7 +98,8 @@ module RSpec
|
|
96
98
|
|
97
99
|
def final_exception(exception, previous=[])
|
98
100
|
cause = exception.cause
|
99
|
-
|
101
|
+
|
102
|
+
if cause && Exception === cause && !previous.include?(cause)
|
100
103
|
previous << cause
|
101
104
|
final_exception(cause, previous)
|
102
105
|
else
|
@@ -171,21 +174,31 @@ module RSpec
|
|
171
174
|
lines
|
172
175
|
end
|
173
176
|
|
177
|
+
# rubocop:disable Lint/RescueException
|
178
|
+
def exception_message_string(exception)
|
179
|
+
exception.message.to_s
|
180
|
+
rescue Exception => other
|
181
|
+
"A #{exception.class} for which `exception.message.to_s` raises #{other.class}."
|
182
|
+
end
|
183
|
+
# rubocop:enable Lint/RescueException
|
184
|
+
|
174
185
|
def exception_lines
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
186
|
+
@exception_lines ||= begin
|
187
|
+
lines = []
|
188
|
+
lines << "#{exception_class_name}:" unless exception_class_name =~ /RSpec/
|
189
|
+
encoded_string(exception_message_string(exception)).split("\n").each do |line|
|
190
|
+
lines << (line.empty? ? line : " #{line}")
|
191
|
+
end
|
192
|
+
lines
|
179
193
|
end
|
180
|
-
lines
|
181
194
|
end
|
182
195
|
|
183
196
|
def extra_failure_lines
|
184
197
|
@extra_failure_lines ||= begin
|
185
198
|
lines = Array(example.metadata[:extra_failure_lines])
|
186
199
|
unless lines.empty?
|
187
|
-
lines.unshift('')
|
188
|
-
lines.push('')
|
200
|
+
lines.unshift('') unless lines.first == ''
|
201
|
+
lines.push('') unless lines.last == ''
|
189
202
|
end
|
190
203
|
lines
|
191
204
|
end
|
@@ -229,6 +242,10 @@ module RSpec
|
|
229
242
|
line_regex = RSpec.configuration.in_project_source_dir_regex
|
230
243
|
loaded_spec_files = RSpec.configuration.loaded_spec_files
|
231
244
|
|
245
|
+
exception_backtrace.reject! do |line|
|
246
|
+
line.start_with?("<internal:")
|
247
|
+
end
|
248
|
+
|
232
249
|
exception_backtrace.find do |line|
|
233
250
|
next unless (line_path = line[/(.+?):(\d+)(|:\d+)/, 1])
|
234
251
|
path = File.expand_path(line_path)
|
@@ -244,6 +261,17 @@ module RSpec
|
|
244
261
|
end
|
245
262
|
end
|
246
263
|
|
264
|
+
if String.method_defined?(:encoding)
|
265
|
+
def encoded_description(description)
|
266
|
+
return if description.nil?
|
267
|
+
encoded_string(description)
|
268
|
+
end
|
269
|
+
else # for 1.8.7
|
270
|
+
def encoded_description(description)
|
271
|
+
description
|
272
|
+
end
|
273
|
+
end
|
274
|
+
|
247
275
|
def exception_backtrace
|
248
276
|
exception.backtrace || []
|
249
277
|
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
RSpec::Support.require_rspec_core "formatters/base_formatter"
|
2
|
+
|
3
|
+
module RSpec
|
4
|
+
module Core
|
5
|
+
module Formatters
|
6
|
+
# @private
|
7
|
+
class FailureListFormatter < BaseFormatter
|
8
|
+
Formatters.register self, :example_failed, :dump_profile, :message
|
9
|
+
|
10
|
+
def example_failed(failure)
|
11
|
+
output.puts "#{failure.example.location}:#{failure.example.description}"
|
12
|
+
end
|
13
|
+
|
14
|
+
# Discard profile and messages
|
15
|
+
#
|
16
|
+
# These outputs are not really relevant in the context of this failure
|
17
|
+
# list formatter.
|
18
|
+
def dump_profile(_profile); end
|
19
|
+
def message(_message); end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -86,7 +86,15 @@ module RSpec
|
|
86
86
|
# @param string [String] word to be pluralized
|
87
87
|
# @return [String] pluralized word
|
88
88
|
def self.pluralize(count, string)
|
89
|
-
|
89
|
+
pluralized_string = if count.to_f == 1
|
90
|
+
string
|
91
|
+
elsif string.end_with?('s') # e.g. "process"
|
92
|
+
"#{string}es" # e.g. "processes"
|
93
|
+
else
|
94
|
+
"#{string}s"
|
95
|
+
end
|
96
|
+
|
97
|
+
"#{count} #{pluralized_string}"
|
90
98
|
end
|
91
99
|
|
92
100
|
# @api private
|
@@ -33,10 +33,8 @@ module RSpec
|
|
33
33
|
"<span class='duration'>#{formatted_run_time}s</span></dd>"
|
34
34
|
end
|
35
35
|
|
36
|
-
# rubocop:disable Metrics/ParameterLists
|
37
36
|
def print_example_failed(pending_fixed, description, run_time, failure_id,
|
38
37
|
exception, extra_content)
|
39
|
-
# rubocop:enable Metrics/ParameterLists
|
40
38
|
formatted_run_time = "%.5f" % run_time
|
41
39
|
|
42
40
|
@output.puts " <dd class=\"example #{pending_fixed ? 'pending_fixed' : 'failed'}\">"
|
@@ -215,7 +213,7 @@ function assign_display_style_for_group(classname, display_flag, subgroup_flag)
|
|
215
213
|
}
|
216
214
|
}
|
217
215
|
EOF
|
218
|
-
# rubocop:enable LineLength
|
216
|
+
# rubocop:enable Layout/LineLength
|
219
217
|
|
220
218
|
GLOBAL_STYLES = <<-EOF
|
221
219
|
#rspec-header {
|
@@ -43,7 +43,7 @@ module RSpec
|
|
43
43
|
#
|
44
44
|
# @param backtrace [String] the backtrace from a test failure
|
45
45
|
# @return [String] highlighted code snippet indicating where the test
|
46
|
-
# failure
|
46
|
+
# failure occurred
|
47
47
|
#
|
48
48
|
# @see #post_process
|
49
49
|
def snippet(backtrace)
|
@@ -103,7 +103,7 @@ module RSpec
|
|
103
103
|
#
|
104
104
|
# @param highlighted [String] syntax-highlighted snippet surrounding the
|
105
105
|
# offending line of code
|
106
|
-
# @param offending_line [Fixnum] line where failure
|
106
|
+
# @param offending_line [Fixnum] line where failure occurred
|
107
107
|
# @return [String] completed snippet
|
108
108
|
def post_process(highlighted, offending_line)
|
109
109
|
new_lines = []
|
@@ -1,4 +1,5 @@
|
|
1
1
|
RSpec::Support.require_rspec_support "directory_maker"
|
2
|
+
|
2
3
|
# ## Built-in Formatters
|
3
4
|
#
|
4
5
|
# * progress (default) - Prints dots for passing examples, `F` for failures, `*`
|
@@ -74,10 +75,11 @@ module RSpec::Core::Formatters
|
|
74
75
|
autoload :JsonFormatter, 'rspec/core/formatters/json_formatter'
|
75
76
|
autoload :BisectDRbFormatter, 'rspec/core/formatters/bisect_drb_formatter'
|
76
77
|
autoload :ExceptionPresenter, 'rspec/core/formatters/exception_presenter'
|
78
|
+
autoload :FailureListFormatter, 'rspec/core/formatters/failure_list_formatter'
|
77
79
|
|
78
80
|
# Register the formatter class
|
79
81
|
# @param formatter_class [Class] formatter class to register
|
80
|
-
# @param notifications [Symbol
|
82
|
+
# @param notifications [Array<Symbol>] one or more notifications to be
|
81
83
|
# registered to the specified formatter
|
82
84
|
#
|
83
85
|
# @see RSpec::Core::Formatters::BaseFormatter
|
@@ -192,10 +194,16 @@ module RSpec::Core::Formatters
|
|
192
194
|
|
193
195
|
def duplicate_formatter_exists?(new_formatter)
|
194
196
|
@formatters.any? do |formatter|
|
195
|
-
formatter.class == new_formatter.class &&
|
197
|
+
formatter.class == new_formatter.class &&
|
198
|
+
has_matching_output?(formatter, new_formatter)
|
196
199
|
end
|
197
200
|
end
|
198
201
|
|
202
|
+
def has_matching_output?(formatter, new_formatter)
|
203
|
+
return true unless formatter.respond_to?(:output) && new_formatter.respond_to?(:output)
|
204
|
+
formatter.output == new_formatter.output
|
205
|
+
end
|
206
|
+
|
199
207
|
def existing_formatter_implements?(notification)
|
200
208
|
@reporter.registered_listeners(notification).any?
|
201
209
|
end
|
@@ -212,6 +220,8 @@ module RSpec::Core::Formatters
|
|
212
220
|
JsonFormatter
|
213
221
|
when 'bisect-drb'
|
214
222
|
BisectDRbFormatter
|
223
|
+
when 'f', 'failures'
|
224
|
+
FailureListFormatter
|
215
225
|
end
|
216
226
|
end
|
217
227
|
|