rspec-core 3.3.0 → 3.4.0
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 +4 -4
- checksums.yaml.gz.sig +0 -0
- data/.document +1 -1
- data/.yardopts +1 -1
- data/Changelog.md +88 -0
- data/{License.txt → LICENSE.md} +6 -5
- data/README.md +18 -3
- data/lib/rspec/core/bisect/example_minimizer.rb +78 -39
- data/lib/rspec/core/configuration.rb +87 -25
- data/lib/rspec/core/configuration_options.rb +1 -1
- data/lib/rspec/core/example.rb +55 -7
- data/lib/rspec/core/example_group.rb +28 -8
- data/lib/rspec/core/example_status_persister.rb +16 -16
- data/lib/rspec/core/formatters/bisect_progress_formatter.rb +44 -15
- data/lib/rspec/core/formatters/exception_presenter.rb +150 -59
- data/lib/rspec/core/formatters/helpers.rb +1 -1
- data/lib/rspec/core/formatters/html_formatter.rb +3 -3
- data/lib/rspec/core/formatters/html_printer.rb +2 -3
- data/lib/rspec/core/formatters/html_snippet_extractor.rb +116 -0
- data/lib/rspec/core/formatters/protocol.rb +9 -0
- data/lib/rspec/core/formatters/snippet_extractor.rb +124 -97
- data/lib/rspec/core/formatters.rb +2 -1
- data/lib/rspec/core/hooks.rb +2 -2
- data/lib/rspec/core/memoized_helpers.rb +2 -2
- data/lib/rspec/core/metadata.rb +3 -2
- data/lib/rspec/core/metadata_filter.rb +11 -6
- data/lib/rspec/core/notifications.rb +3 -2
- data/lib/rspec/core/option_parser.rb +22 -4
- data/lib/rspec/core/project_initializer/spec/spec_helper.rb +2 -2
- data/lib/rspec/core/rake_task.rb +12 -3
- data/lib/rspec/core/reporter.rb +18 -2
- data/lib/rspec/core/ruby_project.rb +1 -1
- data/lib/rspec/core/shared_example_group.rb +2 -0
- data/lib/rspec/core/source/location.rb +13 -0
- data/lib/rspec/core/source/node.rb +93 -0
- data/lib/rspec/core/source/syntax_highlighter.rb +71 -0
- data/lib/rspec/core/source/token.rb +43 -0
- data/lib/rspec/core/source.rb +76 -0
- data/lib/rspec/core/version.rb +1 -1
- data/lib/rspec/core/world.rb +25 -6
- data.tar.gz.sig +0 -0
- metadata +14 -11
- metadata.gz.sig +0 -0
- data/lib/rspec/core/bisect/subset_enumerator.rb +0 -39
- data/lib/rspec/core/mutex.rb +0 -63
- data/lib/rspec/core/reentrant_mutex.rb +0 -52
@@ -1,3 +1,7 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
RSpec::Support.require_rspec_core "formatters/snippet_extractor"
|
3
|
+
RSpec::Support.require_rspec_support "encoded_string"
|
4
|
+
|
1
5
|
module RSpec
|
2
6
|
module Core
|
3
7
|
module Formatters
|
@@ -11,7 +15,7 @@ module RSpec
|
|
11
15
|
@exception = exception
|
12
16
|
@example = example
|
13
17
|
@message_color = options.fetch(:message_color) { RSpec.configuration.failure_color }
|
14
|
-
@description = options.fetch(:
|
18
|
+
@description = options.fetch(:description) { example.full_description }
|
15
19
|
@detail_formatter = options.fetch(:detail_formatter) { Proc.new {} }
|
16
20
|
@extra_detail_formatter = options.fetch(:extra_detail_formatter) { Proc.new {} }
|
17
21
|
@backtrace_formatter = options.fetch(:backtrace_formatter) { RSpec.configuration.backtrace_formatter }
|
@@ -30,8 +34,36 @@ module RSpec
|
|
30
34
|
end
|
31
35
|
end
|
32
36
|
|
33
|
-
def formatted_backtrace
|
34
|
-
backtrace_formatter.format_backtrace(exception.backtrace, example.metadata)
|
37
|
+
def formatted_backtrace(exception=@exception)
|
38
|
+
backtrace_formatter.format_backtrace((exception.backtrace || []), example.metadata) +
|
39
|
+
formatted_cause(exception)
|
40
|
+
end
|
41
|
+
|
42
|
+
if RSpec::Support::RubyFeatures.supports_exception_cause?
|
43
|
+
def formatted_cause(exception)
|
44
|
+
last_cause = final_exception(exception)
|
45
|
+
cause = []
|
46
|
+
|
47
|
+
if exception.cause
|
48
|
+
cause << '------------------'
|
49
|
+
cause << '--- Caused by: ---'
|
50
|
+
cause << "#{exception_class_name(last_cause)}:" unless exception_class_name(last_cause) =~ /RSpec/
|
51
|
+
|
52
|
+
encoded_string(last_cause.message.to_s).split("\n").each do |line|
|
53
|
+
cause << " #{line}"
|
54
|
+
end
|
55
|
+
|
56
|
+
cause << (" #{backtrace_formatter.format_backtrace(last_cause.backtrace, example.metadata).first}")
|
57
|
+
end
|
58
|
+
|
59
|
+
cause
|
60
|
+
end
|
61
|
+
else
|
62
|
+
# :nocov:
|
63
|
+
def formatted_cause(_)
|
64
|
+
[]
|
65
|
+
end
|
66
|
+
# :nocov:
|
35
67
|
end
|
36
68
|
|
37
69
|
def colorized_formatted_backtrace(colorizer=::RSpec::Core::Formatters::ConsoleCodes)
|
@@ -41,24 +73,31 @@ module RSpec
|
|
41
73
|
end
|
42
74
|
|
43
75
|
def fully_formatted(failure_number, colorizer=::RSpec::Core::Formatters::ConsoleCodes)
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
"\n#{alignment_basis}#{description_and_detail(colorizer, indentation)}" \
|
48
|
-
"\n#{formatted_message_and_backtrace(colorizer, indentation)}" \
|
49
|
-
"#{extra_detail_formatter.call(failure_number, colorizer, indentation)}"
|
76
|
+
lines = fully_formatted_lines(failure_number, colorizer)
|
77
|
+
lines.join("\n") << "\n"
|
50
78
|
end
|
51
79
|
|
52
|
-
def
|
53
|
-
|
80
|
+
def fully_formatted_lines(failure_number, colorizer)
|
81
|
+
lines = [
|
82
|
+
description,
|
83
|
+
detail_formatter.call(example, colorizer),
|
84
|
+
formatted_message_and_backtrace(colorizer),
|
85
|
+
extra_detail_formatter.call(failure_number, colorizer),
|
86
|
+
].compact.flatten
|
87
|
+
|
88
|
+
lines = indent_lines(lines, failure_number)
|
89
|
+
lines.unshift("")
|
90
|
+
lines
|
54
91
|
end
|
55
92
|
|
56
93
|
private
|
57
94
|
|
58
|
-
def
|
59
|
-
|
60
|
-
|
61
|
-
|
95
|
+
def final_exception(exception)
|
96
|
+
if exception.cause
|
97
|
+
final_exception(exception.cause)
|
98
|
+
else
|
99
|
+
exception
|
100
|
+
end
|
62
101
|
end
|
63
102
|
|
64
103
|
if String.method_defined?(:encoding)
|
@@ -80,23 +119,71 @@ module RSpec
|
|
80
119
|
# :nocov:
|
81
120
|
end
|
82
121
|
|
83
|
-
def
|
122
|
+
def indent_lines(lines, failure_number)
|
123
|
+
alignment_basis = "#{' ' * @indentation}#{failure_number}) "
|
124
|
+
indentation = ' ' * alignment_basis.length
|
125
|
+
|
126
|
+
lines.each_with_index.map do |line, index|
|
127
|
+
if index == 0
|
128
|
+
"#{alignment_basis}#{line}"
|
129
|
+
elsif line.empty?
|
130
|
+
line
|
131
|
+
else
|
132
|
+
"#{indentation}#{line}"
|
133
|
+
end
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
def exception_class_name(exception=@exception)
|
84
138
|
name = exception.class.name.to_s
|
85
139
|
name = "(anonymous error class)" if name == ''
|
86
140
|
name
|
87
141
|
end
|
88
142
|
|
89
143
|
def failure_lines
|
90
|
-
@failure_lines ||=
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
lines << " #{line}"
|
97
|
-
end
|
98
|
-
lines
|
144
|
+
@failure_lines ||= [].tap do |lines|
|
145
|
+
lines.concat(failure_slash_error_lines)
|
146
|
+
|
147
|
+
sections = [failure_slash_error_lines, exception_lines]
|
148
|
+
if sections.any? { |section| section.size > 1 } && !exception_lines.first.empty?
|
149
|
+
lines << ''
|
99
150
|
end
|
151
|
+
|
152
|
+
lines.concat(exception_lines)
|
153
|
+
lines.concat(extra_failure_lines)
|
154
|
+
end
|
155
|
+
end
|
156
|
+
|
157
|
+
def failure_slash_error_lines
|
158
|
+
lines = read_failed_lines
|
159
|
+
if lines.count == 1
|
160
|
+
lines[0] = "Failure/Error: #{lines[0].strip}"
|
161
|
+
else
|
162
|
+
least_indentation = SnippetExtractor.least_indentation_from(lines)
|
163
|
+
lines = lines.map { |line| line.sub(/^#{least_indentation}/, ' ') }
|
164
|
+
lines.unshift('Failure/Error:')
|
165
|
+
end
|
166
|
+
lines
|
167
|
+
end
|
168
|
+
|
169
|
+
def exception_lines
|
170
|
+
lines = []
|
171
|
+
lines << "#{exception_class_name}:" unless exception_class_name =~ /RSpec/
|
172
|
+
encoded_string(exception.message.to_s).split("\n").each do |line|
|
173
|
+
lines << (line.empty? ? line : " #{line}")
|
174
|
+
end
|
175
|
+
lines
|
176
|
+
end
|
177
|
+
|
178
|
+
def extra_failure_lines
|
179
|
+
@extra_failure_lines ||= begin
|
180
|
+
lines = Array(example.metadata[:extra_failure_lines])
|
181
|
+
unless lines.empty?
|
182
|
+
lines.unshift('')
|
183
|
+
lines.push('')
|
184
|
+
end
|
185
|
+
lines
|
186
|
+
end
|
100
187
|
end
|
101
188
|
|
102
189
|
def add_shared_group_lines(lines, colorizer)
|
@@ -109,42 +196,45 @@ module RSpec
|
|
109
196
|
lines
|
110
197
|
end
|
111
198
|
|
112
|
-
def
|
199
|
+
def read_failed_lines
|
113
200
|
matching_line = find_failed_line
|
114
201
|
unless matching_line
|
115
|
-
return "Unable to find matching line from backtrace"
|
202
|
+
return ["Unable to find matching line from backtrace"]
|
116
203
|
end
|
117
204
|
|
118
205
|
file_path, line_number = matching_line.match(/(.+?):(\d+)(|:\d+)/)[1..2]
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
206
|
+
max_line_count = RSpec.configuration.max_displayed_failure_line_count
|
207
|
+
lines = SnippetExtractor.extract_expression_lines_at(file_path, line_number.to_i, max_line_count)
|
208
|
+
RSpec.world.source_cache.syntax_highlighter.highlight(lines)
|
209
|
+
rescue SnippetExtractor::NoSuchFileError
|
210
|
+
["Unable to find #{file_path} to read failed line"]
|
211
|
+
rescue SnippetExtractor::NoSuchLineError
|
212
|
+
["Unable to find matching line in #{file_path}"]
|
126
213
|
rescue SecurityError
|
127
|
-
"Unable to read failed line"
|
214
|
+
["Unable to read failed line"]
|
128
215
|
end
|
129
216
|
|
130
217
|
def find_failed_line
|
131
|
-
|
132
|
-
|
218
|
+
line_regex = RSpec.configuration.in_project_source_dir_regex
|
219
|
+
loaded_spec_files = RSpec.configuration.loaded_spec_files
|
220
|
+
|
221
|
+
exception_backtrace.find do |line|
|
133
222
|
next unless (line_path = line[/(.+?):(\d+)(|:\d+)/, 1])
|
134
|
-
File.expand_path(line_path)
|
135
|
-
|
223
|
+
path = File.expand_path(line_path)
|
224
|
+
loaded_spec_files.include?(path) || path =~ line_regex
|
225
|
+
end || exception_backtrace.first
|
136
226
|
end
|
137
227
|
|
138
|
-
def formatted_message_and_backtrace(colorizer
|
228
|
+
def formatted_message_and_backtrace(colorizer)
|
139
229
|
lines = colorized_message_lines(colorizer) + colorized_formatted_backtrace(colorizer)
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
lines.each do |line|
|
144
|
-
formatted << RSpec::Support::EncodedString.new("#{indentation}#{line}\n", encoding_of(formatted))
|
230
|
+
encoding = encoding_of("")
|
231
|
+
lines.map do |line|
|
232
|
+
RSpec::Support::EncodedString.new(line, encoding)
|
145
233
|
end
|
234
|
+
end
|
146
235
|
|
147
|
-
|
236
|
+
def exception_backtrace
|
237
|
+
exception.backtrace || []
|
148
238
|
end
|
149
239
|
|
150
240
|
# @private
|
@@ -176,9 +266,9 @@ module RSpec
|
|
176
266
|
def pending_options
|
177
267
|
if @execution_result.pending_fixed?
|
178
268
|
{
|
179
|
-
:
|
180
|
-
:message_color
|
181
|
-
:failure_lines
|
269
|
+
:description => "#{@example.full_description} FIXED",
|
270
|
+
:message_color => RSpec.configuration.fixed_color,
|
271
|
+
:failure_lines => [
|
182
272
|
"Expected pending '#{@execution_result.pending_message}' to fail. No Error was raised."
|
183
273
|
]
|
184
274
|
}
|
@@ -201,8 +291,6 @@ module RSpec
|
|
201
291
|
options[:message_color])
|
202
292
|
)
|
203
293
|
|
204
|
-
options[:description_formatter] &&= Proc.new {}
|
205
|
-
|
206
294
|
return options unless exception.aggregation_metadata[:hide_backtrace]
|
207
295
|
options[:backtrace_formatter] = EmptyBacktraceFormatter
|
208
296
|
options
|
@@ -213,7 +301,7 @@ module RSpec
|
|
213
301
|
end
|
214
302
|
|
215
303
|
def multiple_exception_summarizer(exception, prior_detail_formatter, color)
|
216
|
-
lambda do |example, colorizer
|
304
|
+
lambda do |example, colorizer|
|
217
305
|
summary = if exception.aggregation_metadata[:hide_backtrace]
|
218
306
|
# Since the backtrace is hidden, the subfailures will come
|
219
307
|
# immediately after this, and using `:` will read well.
|
@@ -226,27 +314,30 @@ module RSpec
|
|
226
314
|
|
227
315
|
summary = colorizer.wrap(summary, color || RSpec.configuration.failure_color)
|
228
316
|
return summary unless prior_detail_formatter
|
229
|
-
|
317
|
+
[
|
318
|
+
prior_detail_formatter.call(example, colorizer),
|
319
|
+
summary
|
320
|
+
]
|
230
321
|
end
|
231
322
|
end
|
232
323
|
|
233
324
|
def sub_failure_list_formatter(exception, message_color)
|
234
325
|
common_backtrace_truncater = CommonBacktraceTruncater.new(exception)
|
235
326
|
|
236
|
-
lambda do |failure_number, colorizer
|
237
|
-
exception.all_exceptions.each_with_index
|
327
|
+
lambda do |failure_number, colorizer|
|
328
|
+
FlatMap.flat_map(exception.all_exceptions.each_with_index) do |failure, index|
|
238
329
|
options = with_multiple_error_options_as_needed(
|
239
330
|
failure,
|
240
|
-
:
|
241
|
-
:indentation =>
|
331
|
+
:description => nil,
|
332
|
+
:indentation => 0,
|
242
333
|
:message_color => message_color || RSpec.configuration.failure_color,
|
243
334
|
:skip_shared_group_trace => true
|
244
335
|
)
|
245
336
|
|
246
337
|
failure = common_backtrace_truncater.with_truncated_backtrace(failure)
|
247
338
|
presenter = ExceptionPresenter.new(failure, @example, options)
|
248
|
-
presenter.
|
249
|
-
end
|
339
|
+
presenter.fully_formatted_lines("#{failure_number}.#{index + 1}", colorizer)
|
340
|
+
end
|
250
341
|
end
|
251
342
|
end
|
252
343
|
|
@@ -92,7 +92,7 @@ module RSpec
|
|
92
92
|
# Given a list of example ids, organizes them into a compact, ordered list.
|
93
93
|
def self.organize_ids(ids)
|
94
94
|
grouped = ids.inject(Hash.new { |h, k| h[k] = [] }) do |hash, id|
|
95
|
-
file, id =
|
95
|
+
file, id = Example.parse_id(id)
|
96
96
|
hash[file] << id
|
97
97
|
hash
|
98
98
|
end
|
@@ -137,12 +137,12 @@ module RSpec
|
|
137
137
|
# spec. For example, you could output links to images or other files
|
138
138
|
# produced during the specs.
|
139
139
|
def extra_failure_content(failure)
|
140
|
-
RSpec::Support.require_rspec_core "formatters/
|
141
|
-
backtrace = failure.exception.backtrace.map do |line|
|
140
|
+
RSpec::Support.require_rspec_core "formatters/html_snippet_extractor"
|
141
|
+
backtrace = (failure.exception.backtrace || []).map do |line|
|
142
142
|
RSpec.configuration.backtrace_formatter.backtrace_line(line)
|
143
143
|
end
|
144
144
|
backtrace.compact!
|
145
|
-
@snippet_extractor ||=
|
145
|
+
@snippet_extractor ||= HtmlSnippetExtractor.new
|
146
146
|
" <pre class=\"ruby\"><code>#{@snippet_extractor.snippet(backtrace)}</code></pre>"
|
147
147
|
end
|
148
148
|
end
|
@@ -33,10 +33,10 @@ module RSpec
|
|
33
33
|
"<span class='duration'>#{formatted_run_time}s</span></dd>"
|
34
34
|
end
|
35
35
|
|
36
|
-
# rubocop:disable
|
36
|
+
# rubocop:disable Metrics/ParameterLists
|
37
37
|
def print_example_failed(pending_fixed, description, run_time, failure_id,
|
38
38
|
exception, extra_content)
|
39
|
-
# rubocop:enable
|
39
|
+
# rubocop:enable Metrics/ParameterLists
|
40
40
|
formatted_run_time = "%.5f" % run_time
|
41
41
|
|
42
42
|
@output.puts " <dd class=\"example #{pending_fixed ? 'pending_fixed' : 'failed'}\">"
|
@@ -139,7 +139,6 @@ module RSpec
|
|
139
139
|
EOF
|
140
140
|
# rubocop:enable LineLength
|
141
141
|
|
142
|
-
# rubocop:disable LineLength
|
143
142
|
GLOBAL_SCRIPTS = <<-EOF
|
144
143
|
|
145
144
|
function addClass(element_id, classname) {
|
@@ -0,0 +1,116 @@
|
|
1
|
+
module RSpec
|
2
|
+
module Core
|
3
|
+
module Formatters
|
4
|
+
# @api private
|
5
|
+
#
|
6
|
+
# Extracts code snippets by looking at the backtrace of the passed error
|
7
|
+
# and applies synax highlighting and line numbers using html.
|
8
|
+
class HtmlSnippetExtractor
|
9
|
+
# @private
|
10
|
+
module NullConverter
|
11
|
+
def self.convert(code)
|
12
|
+
%Q(#{code}\n<span class="comment"># Install the coderay gem to get syntax highlighting</span>)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
# @private
|
17
|
+
module CoderayConverter
|
18
|
+
def self.convert(code)
|
19
|
+
CodeRay.scan(code, :ruby).html(:line_numbers => false)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
# rubocop:disable Style/ClassVars
|
24
|
+
@@converter = NullConverter
|
25
|
+
begin
|
26
|
+
require 'coderay'
|
27
|
+
@@converter = CoderayConverter
|
28
|
+
# rubocop:disable Lint/HandleExceptions
|
29
|
+
rescue LoadError
|
30
|
+
# it'll fall back to the NullConverter assigned above
|
31
|
+
# rubocop:enable Lint/HandleExceptions
|
32
|
+
end
|
33
|
+
|
34
|
+
# rubocop:enable Style/ClassVars
|
35
|
+
|
36
|
+
# @api private
|
37
|
+
#
|
38
|
+
# Extract lines of code corresponding to a backtrace.
|
39
|
+
#
|
40
|
+
# @param backtrace [String] the backtrace from a test failure
|
41
|
+
# @return [String] highlighted code snippet indicating where the test
|
42
|
+
# failure occured
|
43
|
+
#
|
44
|
+
# @see #post_process
|
45
|
+
def snippet(backtrace)
|
46
|
+
raw_code, line = snippet_for(backtrace[0])
|
47
|
+
highlighted = @@converter.convert(raw_code)
|
48
|
+
post_process(highlighted, line)
|
49
|
+
end
|
50
|
+
# rubocop:enable Style/ClassVars
|
51
|
+
|
52
|
+
# @api private
|
53
|
+
#
|
54
|
+
# Create a snippet from a line of code.
|
55
|
+
#
|
56
|
+
# @param error_line [String] file name with line number (i.e.
|
57
|
+
# 'foo_spec.rb:12')
|
58
|
+
# @return [String] lines around the target line within the file
|
59
|
+
#
|
60
|
+
# @see #lines_around
|
61
|
+
def snippet_for(error_line)
|
62
|
+
if error_line =~ /(.*):(\d+)/
|
63
|
+
file = Regexp.last_match[1]
|
64
|
+
line = Regexp.last_match[2].to_i
|
65
|
+
[lines_around(file, line), line]
|
66
|
+
else
|
67
|
+
["# Couldn't get snippet for #{error_line}", 1]
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
# @api private
|
72
|
+
#
|
73
|
+
# Extract lines of code centered around a particular line within a
|
74
|
+
# source file.
|
75
|
+
#
|
76
|
+
# @param file [String] filename
|
77
|
+
# @param line [Fixnum] line number
|
78
|
+
# @return [String] lines around the target line within the file (2 above
|
79
|
+
# and 1 below).
|
80
|
+
def lines_around(file, line)
|
81
|
+
if File.file?(file)
|
82
|
+
lines = File.read(file).split("\n")
|
83
|
+
min = [0, line - 3].max
|
84
|
+
max = [line + 1, lines.length - 1].min
|
85
|
+
selected_lines = []
|
86
|
+
selected_lines.join("\n")
|
87
|
+
lines[min..max].join("\n")
|
88
|
+
else
|
89
|
+
"# Couldn't get snippet for #{file}"
|
90
|
+
end
|
91
|
+
rescue SecurityError
|
92
|
+
"# Couldn't get snippet for #{file}"
|
93
|
+
end
|
94
|
+
|
95
|
+
# @api private
|
96
|
+
#
|
97
|
+
# Adds line numbers to all lines and highlights the line where the
|
98
|
+
# failure occurred using html `span` tags.
|
99
|
+
#
|
100
|
+
# @param highlighted [String] syntax-highlighted snippet surrounding the
|
101
|
+
# offending line of code
|
102
|
+
# @param offending_line [Fixnum] line where failure occured
|
103
|
+
# @return [String] completed snippet
|
104
|
+
def post_process(highlighted, offending_line)
|
105
|
+
new_lines = []
|
106
|
+
highlighted.split("\n").each_with_index do |line, i|
|
107
|
+
new_line = "<span class=\"linenum\">#{offending_line + i - 2}</span>#{line}"
|
108
|
+
new_line = "<span class=\"offending\">#{new_line}</span>" if i == 2
|
109
|
+
new_lines << new_line
|
110
|
+
end
|
111
|
+
new_lines.join("\n")
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|
@@ -66,6 +66,15 @@ module RSpec
|
|
66
66
|
# @param notification [ExampleNotification] containing example subclass
|
67
67
|
# of `RSpec::Core::Example`
|
68
68
|
|
69
|
+
# @method example_finished
|
70
|
+
# @api public
|
71
|
+
# @group Example Notifications
|
72
|
+
#
|
73
|
+
# Invoked at the end of the execution of each example.
|
74
|
+
#
|
75
|
+
# @param notification [ExampleNotification] containing example subclass
|
76
|
+
# of `RSpec::Core::Example`
|
77
|
+
|
69
78
|
# @method example_passed
|
70
79
|
# @api public
|
71
80
|
# @group Example Notifications
|