rspec-core 3.2.3 → 3.3.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.tar.gz.sig +0 -0
- data/Changelog.md +75 -0
- data/README.md +137 -20
- data/lib/rspec/autorun.rb +1 -0
- data/lib/rspec/core.rb +8 -16
- data/lib/rspec/core/backtrace_formatter.rb +1 -3
- data/lib/rspec/core/bisect/coordinator.rb +66 -0
- data/lib/rspec/core/bisect/example_minimizer.rb +130 -0
- data/lib/rspec/core/bisect/runner.rb +139 -0
- data/lib/rspec/core/bisect/server.rb +61 -0
- data/lib/rspec/core/bisect/subset_enumerator.rb +39 -0
- data/lib/rspec/core/configuration.rb +134 -5
- data/lib/rspec/core/configuration_options.rb +21 -10
- data/lib/rspec/core/example.rb +84 -50
- data/lib/rspec/core/example_group.rb +46 -18
- data/lib/rspec/core/example_status_persister.rb +235 -0
- data/lib/rspec/core/filter_manager.rb +43 -28
- data/lib/rspec/core/flat_map.rb +2 -0
- data/lib/rspec/core/formatters.rb +30 -20
- data/lib/rspec/core/formatters/base_text_formatter.rb +1 -0
- data/lib/rspec/core/formatters/bisect_formatter.rb +68 -0
- data/lib/rspec/core/formatters/bisect_progress_formatter.rb +115 -0
- data/lib/rspec/core/formatters/deprecation_formatter.rb +0 -1
- data/lib/rspec/core/formatters/documentation_formatter.rb +0 -4
- data/lib/rspec/core/formatters/exception_presenter.rb +389 -0
- data/lib/rspec/core/formatters/fallback_message_formatter.rb +28 -0
- data/lib/rspec/core/formatters/helpers.rb +22 -2
- data/lib/rspec/core/formatters/html_formatter.rb +1 -4
- data/lib/rspec/core/formatters/html_printer.rb +2 -6
- data/lib/rspec/core/formatters/json_formatter.rb +6 -4
- data/lib/rspec/core/formatters/snippet_extractor.rb +12 -7
- data/lib/rspec/core/hooks.rb +8 -2
- data/lib/rspec/core/memoized_helpers.rb +77 -17
- data/lib/rspec/core/metadata.rb +24 -10
- data/lib/rspec/core/metadata_filter.rb +16 -3
- data/lib/rspec/core/mutex.rb +63 -0
- data/lib/rspec/core/notifications.rb +84 -189
- data/lib/rspec/core/option_parser.rb +105 -32
- data/lib/rspec/core/ordering.rb +28 -25
- data/lib/rspec/core/profiler.rb +32 -0
- data/lib/rspec/core/project_initializer/spec/spec_helper.rb +6 -1
- data/lib/rspec/core/rake_task.rb +6 -20
- data/lib/rspec/core/reentrant_mutex.rb +52 -0
- data/lib/rspec/core/reporter.rb +65 -17
- data/lib/rspec/core/runner.rb +38 -14
- data/lib/rspec/core/set.rb +49 -0
- data/lib/rspec/core/shared_example_group.rb +3 -1
- data/lib/rspec/core/shell_escape.rb +49 -0
- data/lib/rspec/core/version.rb +1 -1
- data/lib/rspec/core/world.rb +31 -20
- metadata +35 -7
- metadata.gz.sig +0 -0
- data/lib/rspec/core/backport_random.rb +0 -339
@@ -17,6 +17,7 @@ module RSpec
|
|
17
17
|
silence_metadata_example_group_deprecations do
|
18
18
|
return filter_applies_to_any_value?(key, value, metadata) if Array === metadata[key] && !(Proc === value)
|
19
19
|
return location_filter_applies?(value, metadata) if key == :locations
|
20
|
+
return id_filter_applies?(value, metadata) if key == :ids
|
20
21
|
return filters_apply?(key, value, metadata) if Hash === value
|
21
22
|
|
22
23
|
return false unless metadata.key?(key)
|
@@ -42,9 +43,17 @@ module RSpec
|
|
42
43
|
metadata[key].any? { |v| filter_applies?(key, v, key => value) }
|
43
44
|
end
|
44
45
|
|
46
|
+
def id_filter_applies?(rerun_paths_to_scoped_ids, metadata)
|
47
|
+
scoped_ids = rerun_paths_to_scoped_ids.fetch(metadata[:rerun_file_path]) { return false }
|
48
|
+
|
49
|
+
Metadata.ascend(metadata).any? do |meta|
|
50
|
+
scoped_ids.include?(meta[:scoped_id])
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
45
54
|
def location_filter_applies?(locations, metadata)
|
46
55
|
line_numbers = example_group_declaration_lines(locations, metadata)
|
47
|
-
|
56
|
+
line_number_filter_applies?(line_numbers, metadata)
|
48
57
|
end
|
49
58
|
|
50
59
|
def line_number_filter_applies?(line_numbers, metadata)
|
@@ -69,10 +78,10 @@ module RSpec
|
|
69
78
|
end
|
70
79
|
|
71
80
|
def silence_metadata_example_group_deprecations
|
72
|
-
RSpec.
|
81
|
+
RSpec::Support.thread_local_data[:silence_metadata_example_group_deprecations] = true
|
73
82
|
yield
|
74
83
|
ensure
|
75
|
-
RSpec.
|
84
|
+
RSpec::Support.thread_local_data.delete(:silence_metadata_example_group_deprecations)
|
76
85
|
end
|
77
86
|
end
|
78
87
|
end
|
@@ -118,6 +127,7 @@ module RSpec
|
|
118
127
|
end
|
119
128
|
|
120
129
|
unless [].respond_to?(:each_with_object) # For 1.8.7
|
130
|
+
# :nocov:
|
121
131
|
undef items_for
|
122
132
|
def items_for(request_meta)
|
123
133
|
@items_and_filters.inject([]) do |to_return, (item, item_meta)|
|
@@ -126,6 +136,7 @@ module RSpec
|
|
126
136
|
to_return
|
127
137
|
end
|
128
138
|
end
|
139
|
+
# :nocov:
|
129
140
|
end
|
130
141
|
end
|
131
142
|
|
@@ -208,6 +219,7 @@ module RSpec
|
|
208
219
|
end
|
209
220
|
|
210
221
|
unless [].respond_to?(:each_with_object) # For 1.8.7
|
222
|
+
# :nocov:
|
211
223
|
undef proc_keys_from
|
212
224
|
def proc_keys_from(metadata)
|
213
225
|
metadata.inject([]) do |to_return, (key, value)|
|
@@ -215,6 +227,7 @@ module RSpec
|
|
215
227
|
to_return
|
216
228
|
end
|
217
229
|
end
|
230
|
+
# :nocov:
|
218
231
|
end
|
219
232
|
end
|
220
233
|
end
|
@@ -0,0 +1,63 @@
|
|
1
|
+
module RSpec
|
2
|
+
module Core
|
3
|
+
# On 1.8.7, it's in the stdlib.
|
4
|
+
# We don't want to load the stdlib, b/c this is a test tool, and can affect the test environment,
|
5
|
+
# causing tests to pass where they should fail.
|
6
|
+
#
|
7
|
+
# So we're transcribing/modifying it from https://github.com/ruby/ruby/blob/v1_8_7_374/lib/thread.rb#L56
|
8
|
+
# Some methods we don't need are deleted.
|
9
|
+
# Anything I don't understand (there's quite a bit, actually) is left in.
|
10
|
+
# Some formating changes are made to appease the robot overlord:
|
11
|
+
# https://travis-ci.org/rspec/rspec-core/jobs/54410874
|
12
|
+
# @private
|
13
|
+
class Mutex
|
14
|
+
def initialize
|
15
|
+
@waiting = []
|
16
|
+
@locked = false
|
17
|
+
@waiting.taint
|
18
|
+
taint
|
19
|
+
end
|
20
|
+
|
21
|
+
# @private
|
22
|
+
def lock
|
23
|
+
while Thread.critical = true && @locked
|
24
|
+
@waiting.push Thread.current
|
25
|
+
Thread.stop
|
26
|
+
end
|
27
|
+
@locked = true
|
28
|
+
Thread.critical = false
|
29
|
+
self
|
30
|
+
end
|
31
|
+
|
32
|
+
# @private
|
33
|
+
def unlock
|
34
|
+
return unless @locked
|
35
|
+
Thread.critical = true
|
36
|
+
@locked = false
|
37
|
+
begin
|
38
|
+
t = @waiting.shift
|
39
|
+
t.wakeup if t
|
40
|
+
rescue ThreadError
|
41
|
+
retry
|
42
|
+
end
|
43
|
+
Thread.critical = false
|
44
|
+
begin
|
45
|
+
t.run if t
|
46
|
+
rescue ThreadError
|
47
|
+
:noop
|
48
|
+
end
|
49
|
+
self
|
50
|
+
end
|
51
|
+
|
52
|
+
# @private
|
53
|
+
def synchronize
|
54
|
+
lock
|
55
|
+
begin
|
56
|
+
yield
|
57
|
+
ensure
|
58
|
+
unlock
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end unless defined?(::RSpec::Core::Mutex) # Avoid warnings for library wide checks spec
|
62
|
+
end
|
63
|
+
end
|
@@ -1,4 +1,6 @@
|
|
1
|
+
RSpec::Support.require_rspec_core "formatters/exception_presenter"
|
1
2
|
RSpec::Support.require_rspec_core "formatters/helpers"
|
3
|
+
RSpec::Support.require_rspec_core "shell_escape"
|
2
4
|
RSpec::Support.require_rspec_support "encoded_string"
|
3
5
|
|
4
6
|
module RSpec::Core
|
@@ -38,17 +40,19 @@ module RSpec::Core
|
|
38
40
|
def self.for(example)
|
39
41
|
execution_result = example.execution_result
|
40
42
|
|
41
|
-
if execution_result.
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
43
|
+
return SkippedExampleNotification.new(example) if execution_result.example_skipped?
|
44
|
+
return new(example) unless execution_result.status == :pending || execution_result.status == :failed
|
45
|
+
|
46
|
+
klass = if execution_result.pending_fixed?
|
47
|
+
PendingExampleFixedNotification
|
48
|
+
elsif execution_result.status == :pending
|
49
|
+
PendingExampleFailedAsExpectedNotification
|
50
|
+
else
|
51
|
+
FailedExampleNotification
|
52
|
+
end
|
53
|
+
|
54
|
+
exception_presenter = Formatters::ExceptionPresenter::Factory.new(example).build
|
55
|
+
klass.new(example, exception_presenter)
|
52
56
|
end
|
53
57
|
|
54
58
|
private_class_method :new
|
@@ -135,7 +139,8 @@ module RSpec::Core
|
|
135
139
|
end
|
136
140
|
|
137
141
|
# The `FailedExampleNotification` extends `ExampleNotification` with
|
138
|
-
# things useful for
|
142
|
+
# things useful for examples that have failure info -- typically a
|
143
|
+
# failed or pending spec.
|
139
144
|
#
|
140
145
|
# @example
|
141
146
|
# def example_failed(notification)
|
@@ -151,19 +156,19 @@ module RSpec::Core
|
|
151
156
|
|
152
157
|
# @return [Exception] The example failure
|
153
158
|
def exception
|
154
|
-
|
159
|
+
@exception_presenter.exception
|
155
160
|
end
|
156
161
|
|
157
162
|
# @return [String] The example description
|
158
163
|
def description
|
159
|
-
|
164
|
+
@exception_presenter.description
|
160
165
|
end
|
161
166
|
|
162
167
|
# Returns the message generated for this failure line by line.
|
163
168
|
#
|
164
169
|
# @return [Array<String>] The example failure message
|
165
170
|
def message_lines
|
166
|
-
|
171
|
+
@exception_presenter.message_lines
|
167
172
|
end
|
168
173
|
|
169
174
|
# Returns the message generated for this failure colorized line by line.
|
@@ -171,16 +176,14 @@ module RSpec::Core
|
|
171
176
|
# @param colorizer [#wrap] An object to colorize the message_lines by
|
172
177
|
# @return [Array<String>] The example failure message colorized
|
173
178
|
def colorized_message_lines(colorizer=::RSpec::Core::Formatters::ConsoleCodes)
|
174
|
-
|
175
|
-
colorizer.wrap line, message_color
|
176
|
-
end
|
179
|
+
@exception_presenter.colorized_message_lines(colorizer)
|
177
180
|
end
|
178
181
|
|
179
182
|
# Returns the failures formatted backtrace.
|
180
183
|
#
|
181
184
|
# @return [Array<String>] the examples backtrace lines
|
182
185
|
def formatted_backtrace
|
183
|
-
|
186
|
+
@exception_presenter.formatted_backtrace
|
184
187
|
end
|
185
188
|
|
186
189
|
# Returns the failures colorized formatted backtrace.
|
@@ -188,170 +191,28 @@ module RSpec::Core
|
|
188
191
|
# @param colorizer [#wrap] An object to colorize the message_lines by
|
189
192
|
# @return [Array<String>] the examples colorized backtrace lines
|
190
193
|
def colorized_formatted_backtrace(colorizer=::RSpec::Core::Formatters::ConsoleCodes)
|
191
|
-
|
192
|
-
colorizer.wrap "# #{backtrace_info}", RSpec.configuration.detail_color
|
193
|
-
end
|
194
|
+
@exception_presenter.colorized_formatted_backtrace(colorizer)
|
194
195
|
end
|
195
196
|
|
196
197
|
# @return [String] The failure information fully formatted in the way that
|
197
198
|
# RSpec's built-in formatters emit.
|
198
199
|
def fully_formatted(failure_number, colorizer=::RSpec::Core::Formatters::ConsoleCodes)
|
199
|
-
|
200
|
-
end
|
201
|
-
|
202
|
-
private
|
203
|
-
|
204
|
-
if String.method_defined?(:encoding)
|
205
|
-
def encoding_of(string)
|
206
|
-
string.encoding
|
207
|
-
end
|
208
|
-
else
|
209
|
-
def encoding_of(_string)
|
210
|
-
end
|
211
|
-
end
|
212
|
-
|
213
|
-
def backtrace_formatter
|
214
|
-
RSpec.configuration.backtrace_formatter
|
215
|
-
end
|
216
|
-
|
217
|
-
def exception_class_name
|
218
|
-
name = exception.class.name.to_s
|
219
|
-
name = "(anonymous error class)" if name == ''
|
220
|
-
name
|
221
|
-
end
|
222
|
-
|
223
|
-
def failure_lines
|
224
|
-
@failure_lines ||=
|
225
|
-
begin
|
226
|
-
lines = ["Failure/Error: #{read_failed_line.strip}"]
|
227
|
-
lines << "#{exception_class_name}:" unless exception_class_name =~ /RSpec/
|
228
|
-
exception.message.to_s.split("\n").each do |line|
|
229
|
-
lines << " #{line}" if exception.message
|
230
|
-
end
|
231
|
-
lines
|
232
|
-
end
|
233
|
-
end
|
234
|
-
|
235
|
-
def add_shared_group_lines(lines, colorizer)
|
236
|
-
example.metadata[:shared_group_inclusion_backtrace].each do |frame|
|
237
|
-
lines << colorizer.wrap(frame.description, RSpec.configuration.default_color)
|
238
|
-
end
|
239
|
-
|
240
|
-
lines
|
241
|
-
end
|
242
|
-
|
243
|
-
def read_failed_line
|
244
|
-
matching_line = find_failed_line
|
245
|
-
unless matching_line
|
246
|
-
return "Unable to find matching line from backtrace"
|
247
|
-
end
|
248
|
-
|
249
|
-
file_path, line_number = matching_line.match(/(.+?):(\d+)(|:\d+)/)[1..2]
|
250
|
-
|
251
|
-
if File.exist?(file_path)
|
252
|
-
File.readlines(file_path)[line_number.to_i - 1] ||
|
253
|
-
"Unable to find matching line in #{file_path}"
|
254
|
-
else
|
255
|
-
"Unable to find #{file_path} to read failed line"
|
256
|
-
end
|
257
|
-
rescue SecurityError
|
258
|
-
"Unable to read failed line"
|
259
|
-
end
|
260
|
-
|
261
|
-
def find_failed_line
|
262
|
-
example_path = example.metadata[:absolute_file_path].downcase
|
263
|
-
exception.backtrace.find do |line|
|
264
|
-
next unless (line_path = line[/(.+?):(\d+)(|:\d+)/, 1])
|
265
|
-
File.expand_path(line_path).downcase == example_path
|
266
|
-
end
|
267
|
-
end
|
268
|
-
|
269
|
-
def formatted_message_and_backtrace(colorizer)
|
270
|
-
formatted = ""
|
271
|
-
|
272
|
-
colorized_message_lines(colorizer).each do |line|
|
273
|
-
formatted << RSpec::Support::EncodedString.new(" #{line}\n", encoding_of(formatted))
|
274
|
-
end
|
275
|
-
|
276
|
-
colorized_formatted_backtrace(colorizer).each do |line|
|
277
|
-
formatted << RSpec::Support::EncodedString.new(" #{line}\n", encoding_of(formatted))
|
278
|
-
end
|
279
|
-
|
280
|
-
formatted
|
281
|
-
end
|
282
|
-
|
283
|
-
def message_color
|
284
|
-
RSpec.configuration.failure_color
|
285
|
-
end
|
286
|
-
end
|
287
|
-
|
288
|
-
# The `PendingExampleFixedNotification` extends `ExampleNotification` with
|
289
|
-
# things useful for specs that pass when they are expected to fail.
|
290
|
-
#
|
291
|
-
# @attr [RSpec::Core::Example] example the current example
|
292
|
-
# @see ExampleNotification
|
293
|
-
class PendingExampleFixedNotification < FailedExampleNotification
|
294
|
-
public_class_method :new
|
295
|
-
|
296
|
-
# Returns the examples description.
|
297
|
-
#
|
298
|
-
# @return [String] The example description
|
299
|
-
def description
|
300
|
-
"#{example.full_description} FIXED"
|
301
|
-
end
|
302
|
-
|
303
|
-
# Returns the message generated for this failure line by line.
|
304
|
-
#
|
305
|
-
# @return [Array<String>] The example failure message
|
306
|
-
def message_lines
|
307
|
-
["Expected pending '#{example.execution_result.pending_message}' to fail. No Error was raised."]
|
200
|
+
@exception_presenter.fully_formatted(failure_number, colorizer)
|
308
201
|
end
|
309
202
|
|
310
|
-
# Returns the message generated for this failure colorized line by line.
|
311
|
-
#
|
312
|
-
# @param colorizer [#wrap] An object to colorize the message_lines by
|
313
|
-
# @return [Array<String>] The example failure message colorized
|
314
|
-
def colorized_message_lines(colorizer=::RSpec::Core::Formatters::ConsoleCodes)
|
315
|
-
message_lines.map { |line| colorizer.wrap(line, RSpec.configuration.fixed_color) }
|
316
|
-
end
|
317
|
-
end
|
318
|
-
|
319
|
-
# @private
|
320
|
-
module PendingExampleNotificationMethods
|
321
203
|
private
|
322
204
|
|
323
|
-
def
|
324
|
-
|
325
|
-
|
205
|
+
def initialize(example, exception_presenter=Formatters::ExceptionPresenter.new(example.execution_result.exception, example))
|
206
|
+
@exception_presenter = exception_presenter
|
207
|
+
super(example)
|
326
208
|
end
|
327
209
|
end
|
328
210
|
|
329
|
-
#
|
330
|
-
|
331
|
-
#
|
332
|
-
# @attr [RSpec::Core::Example] example the current example
|
333
|
-
# @see ExampleNotification
|
334
|
-
class PendingExampleFailedAsExpectedNotification < FailedExampleNotification
|
335
|
-
include PendingExampleNotificationMethods
|
336
|
-
public_class_method :new
|
337
|
-
|
338
|
-
# @return [Exception] The exception that occurred while the pending example was executed
|
339
|
-
def exception
|
340
|
-
example.execution_result.pending_exception
|
341
|
-
end
|
342
|
-
|
343
|
-
# @return [String] The pending detail fully formatted in the way that
|
344
|
-
# RSpec's built-in formatters emit.
|
345
|
-
def fully_formatted(pending_number, colorizer=::RSpec::Core::Formatters::ConsoleCodes)
|
346
|
-
fully_formatted_header(pending_number, colorizer) << formatted_message_and_backtrace(colorizer)
|
347
|
-
end
|
348
|
-
|
349
|
-
private
|
211
|
+
# @deprecated Use {FailedExampleNotification} instead.
|
212
|
+
class PendingExampleFixedNotification < FailedExampleNotification; end
|
350
213
|
|
351
|
-
|
352
|
-
|
353
|
-
end
|
354
|
-
end
|
214
|
+
# @deprecated Use {FailedExampleNotification} instead.
|
215
|
+
class PendingExampleFailedAsExpectedNotification < FailedExampleNotification; end
|
355
216
|
|
356
217
|
# The `SkippedExampleNotification` extends `ExampleNotification` with
|
357
218
|
# things useful for specs that are skipped.
|
@@ -359,14 +220,15 @@ module RSpec::Core
|
|
359
220
|
# @attr [RSpec::Core::Example] example the current example
|
360
221
|
# @see ExampleNotification
|
361
222
|
class SkippedExampleNotification < ExampleNotification
|
362
|
-
include PendingExampleNotificationMethods
|
363
223
|
public_class_method :new
|
364
224
|
|
365
225
|
# @return [String] The pending detail fully formatted in the way that
|
366
226
|
# RSpec's built-in formatters emit.
|
367
227
|
def fully_formatted(pending_number, colorizer=::RSpec::Core::Formatters::ConsoleCodes)
|
368
228
|
formatted_caller = RSpec.configuration.backtrace_formatter.backtrace_line(example.location)
|
369
|
-
|
229
|
+
colorizer.wrap("\n #{pending_number}) #{example.full_description}", :pending) << "\n " <<
|
230
|
+
Formatters::ExceptionPresenter::PENDING_DETAIL_FORMATTER.call(example, colorizer) <<
|
231
|
+
"\n" << colorizer.wrap(" # #{formatted_caller}\n", :detail)
|
370
232
|
end
|
371
233
|
end
|
372
234
|
|
@@ -477,7 +339,7 @@ module RSpec::Core
|
|
477
339
|
def colorized_rerun_commands(colorizer=::RSpec::Core::Formatters::ConsoleCodes)
|
478
340
|
"\nFailed examples:\n\n" +
|
479
341
|
failed_examples.map do |example|
|
480
|
-
colorizer.wrap("rspec #{example
|
342
|
+
colorizer.wrap("rspec #{rerun_argument_for(example)}", RSpec.configuration.failure_color) + " " +
|
481
343
|
colorizer.wrap("# #{example.full_description}", RSpec.configuration.detail_color)
|
482
344
|
end.join("\n")
|
483
345
|
end
|
@@ -507,6 +369,28 @@ module RSpec::Core
|
|
507
369
|
|
508
370
|
formatted
|
509
371
|
end
|
372
|
+
|
373
|
+
private
|
374
|
+
|
375
|
+
include RSpec::Core::ShellEscape
|
376
|
+
|
377
|
+
def rerun_argument_for(example)
|
378
|
+
location = example.location_rerun_argument
|
379
|
+
return location unless duplicate_rerun_locations.include?(location)
|
380
|
+
conditionally_quote(example.id)
|
381
|
+
end
|
382
|
+
|
383
|
+
def duplicate_rerun_locations
|
384
|
+
@duplicate_rerun_locations ||= begin
|
385
|
+
locations = RSpec.world.all_examples.map(&:location_rerun_argument)
|
386
|
+
|
387
|
+
Set.new.tap do |s|
|
388
|
+
locations.group_by { |l| l }.each do |l, ls|
|
389
|
+
s << l if ls.count > 1
|
390
|
+
end
|
391
|
+
end
|
392
|
+
end
|
393
|
+
end
|
510
394
|
end
|
511
395
|
|
512
396
|
# The `ProfileNotification` holds information about the results of running a
|
@@ -516,8 +400,16 @@ module RSpec::Core
|
|
516
400
|
# @attr duration [Float] the time taken (in seconds) to run the suite
|
517
401
|
# @attr examples [Array<RSpec::Core::Example>] the examples run
|
518
402
|
# @attr number_of_examples [Fixnum] the number of examples to profile
|
519
|
-
|
403
|
+
# @attr example_groups [Array<RSpec::Core::Profiler>] example groups run
|
520
404
|
class ProfileNotification
|
405
|
+
def initialize(duration, examples, number_of_examples, example_groups)
|
406
|
+
@duration = duration
|
407
|
+
@examples = examples
|
408
|
+
@number_of_examples = number_of_examples
|
409
|
+
@example_groups = example_groups
|
410
|
+
end
|
411
|
+
attr_reader :duration, :examples, :number_of_examples
|
412
|
+
|
521
413
|
# @return [Array<RSpec::Core::Example>] the slowest examples
|
522
414
|
def slowest_examples
|
523
415
|
@slowest_examples ||=
|
@@ -551,26 +443,15 @@ module RSpec::Core
|
|
551
443
|
private
|
552
444
|
|
553
445
|
def calculate_slowest_groups
|
554
|
-
example_groups = {}
|
555
|
-
|
556
|
-
examples.each do |example|
|
557
|
-
location = example.example_group.parent_groups.last.metadata[:location]
|
558
|
-
|
559
|
-
location_hash = example_groups[location] ||= Hash.new(0)
|
560
|
-
location_hash[:total_time] += example.execution_result.run_time
|
561
|
-
location_hash[:count] += 1
|
562
|
-
next if location_hash.key?(:description)
|
563
|
-
location_hash[:description] = example.example_group.top_level_description
|
564
|
-
end
|
565
|
-
|
566
446
|
# stop if we've only one example group
|
567
|
-
return {} if example_groups.keys.length <= 1
|
447
|
+
return {} if @example_groups.keys.length <= 1
|
568
448
|
|
569
|
-
example_groups.each_value do |hash|
|
449
|
+
@example_groups.each_value do |hash|
|
570
450
|
hash[:average] = hash[:total_time].to_f / hash[:count]
|
571
451
|
end
|
572
452
|
|
573
|
-
example_groups.sort_by { |_, hash| -hash[:average] }.first(number_of_examples)
|
453
|
+
groups = @example_groups.sort_by { |_, hash| -hash[:average] }.first(number_of_examples)
|
454
|
+
groups.map { |group, data| [group.location, data] }
|
574
455
|
end
|
575
456
|
end
|
576
457
|
|
@@ -599,5 +480,19 @@ module RSpec::Core
|
|
599
480
|
# currently require no information, but we may wish to extend in future.
|
600
481
|
class NullNotification
|
601
482
|
end
|
483
|
+
|
484
|
+
# `CustomNotification` is used when sending custom events to formatters /
|
485
|
+
# other registered listeners, it creates attributes based on supplied hash
|
486
|
+
# of options.
|
487
|
+
class CustomNotification < Struct
|
488
|
+
# @param options [Hash] A hash of method / value pairs to create on this notification
|
489
|
+
# @return [CustomNotification]
|
490
|
+
#
|
491
|
+
# Build a custom notification based on the supplied option key / values.
|
492
|
+
def self.for(options={})
|
493
|
+
return NullNotification if options.keys.empty?
|
494
|
+
new(*options.keys).new(*options.values)
|
495
|
+
end
|
496
|
+
end
|
602
497
|
end
|
603
498
|
end
|