rspec-core 3.2.3 → 3.3.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
@@ -4,23 +4,36 @@ require 'optparse'
|
|
4
4
|
module RSpec::Core
|
5
5
|
# @private
|
6
6
|
class Parser
|
7
|
-
def self.parse(args)
|
8
|
-
new.parse(
|
7
|
+
def self.parse(args, source=nil)
|
8
|
+
new(args).parse(source)
|
9
9
|
end
|
10
10
|
|
11
|
-
|
12
|
-
|
11
|
+
attr_reader :original_args
|
12
|
+
|
13
|
+
def initialize(original_args)
|
14
|
+
@original_args = original_args
|
15
|
+
end
|
16
|
+
|
17
|
+
def parse(source=nil)
|
18
|
+
return { :files_or_directories_to_run => [] } if original_args.empty?
|
19
|
+
args = original_args.dup
|
13
20
|
|
14
21
|
options = args.delete('--tty') ? { :tty => true } : {}
|
15
22
|
begin
|
16
23
|
parser(options).parse!(args)
|
17
24
|
rescue OptionParser::InvalidOption => e
|
18
|
-
|
25
|
+
failure = e.message
|
26
|
+
failure << " (defined in #{source})" if source
|
27
|
+
abort "#{failure}\n\nPlease use --help for a listing of valid options"
|
19
28
|
end
|
20
29
|
|
30
|
+
options[:files_or_directories_to_run] = args
|
21
31
|
options
|
22
32
|
end
|
23
33
|
|
34
|
+
private
|
35
|
+
|
36
|
+
# rubocop:disable MethodLength
|
24
37
|
def parser(options)
|
25
38
|
OptionParser.new do |parser|
|
26
39
|
parser.banner = "Usage: rspec [options] [files or directories]\n\n"
|
@@ -51,12 +64,13 @@ module RSpec::Core
|
|
51
64
|
options[:order] = "rand:#{seed}"
|
52
65
|
end
|
53
66
|
|
54
|
-
parser.on('--
|
55
|
-
|
67
|
+
parser.on('--bisect[=verbose]', 'Repeatedly runs the suite in order to isolate the failures to the ',
|
68
|
+
' smallest reproducible case.') do |argument|
|
69
|
+
bisect_and_exit(argument)
|
56
70
|
end
|
57
71
|
|
58
|
-
parser.on('--no-fail-fast', '
|
59
|
-
options
|
72
|
+
parser.on('--[no-]fail-fast', 'Abort the run on first failure.') do |value|
|
73
|
+
set_fail_fast(options, value)
|
60
74
|
end
|
61
75
|
|
62
76
|
parser.on('--failure-exit-code CODE', Integer,
|
@@ -78,9 +92,7 @@ module RSpec::Core
|
|
78
92
|
end
|
79
93
|
|
80
94
|
parser.on('--init', 'Initialize your project with RSpec.') do |_cmd|
|
81
|
-
|
82
|
-
ProjectInitializer.new.run
|
83
|
-
exit
|
95
|
+
initialize_project_and_exit
|
84
96
|
end
|
85
97
|
|
86
98
|
parser.separator("\n **** Output ****\n\n")
|
@@ -143,14 +155,29 @@ module RSpec::Core
|
|
143
155
|
|
144
156
|
**** Filtering/tags ****
|
145
157
|
|
146
|
-
In addition to the following options for selecting specific files, groups,
|
147
|
-
|
158
|
+
In addition to the following options for selecting specific files, groups, or
|
159
|
+
examples, you can select individual examples by appending the line number(s) to
|
148
160
|
the filename:
|
149
161
|
|
150
|
-
rspec path/to/a_spec.rb:37
|
162
|
+
rspec path/to/a_spec.rb:37:87
|
163
|
+
|
164
|
+
You can also pass example ids enclosed in square brackets:
|
165
|
+
|
166
|
+
rspec path/to/a_spec.rb[1:5,1:6] # run the 5th and 6th examples/groups defined in the 1st group
|
151
167
|
|
152
168
|
FILTERING
|
153
169
|
|
170
|
+
parser.on('--only-failures', "Filter to just the examples that failed the last time they ran.") do
|
171
|
+
configure_only_failures(options)
|
172
|
+
end
|
173
|
+
|
174
|
+
parser.on("--next-failure", "Apply `--only-failures` and abort after one failure.",
|
175
|
+
" (Equivalent to `--only-failures --fail-fast --order defined`)") do
|
176
|
+
configure_only_failures(options)
|
177
|
+
set_fail_fast(options, true)
|
178
|
+
options[:order] ||= 'defined'
|
179
|
+
end
|
180
|
+
|
154
181
|
parser.on('-P', '--pattern PATTERN', 'Load files matching pattern (default: "spec/**/*_spec.rb").') do |o|
|
155
182
|
options[:pattern] = o
|
156
183
|
end
|
@@ -175,18 +202,19 @@ FILTERING
|
|
175
202
|
name, value = tag.gsub(/^(~@|~|@)/, '').split(':', 2)
|
176
203
|
name = name.to_sym
|
177
204
|
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
205
|
+
parsed_value = case value
|
206
|
+
when nil then true # The default value for tags is true
|
207
|
+
when 'true' then true
|
208
|
+
when 'false' then false
|
209
|
+
when 'nil' then nil
|
210
|
+
when /^:/ then value[1..-1].to_sym
|
211
|
+
when /^\d+$/ then Integer(value)
|
212
|
+
when /^\d+.\d+$/ then Float(value)
|
213
|
+
else
|
214
|
+
value
|
215
|
+
end
|
216
|
+
|
217
|
+
add_tag_filter(options, filter_type, name, parsed_value)
|
190
218
|
end
|
191
219
|
|
192
220
|
parser.on('--default-path PATH', 'Set the default path where RSpec looks for examples (can',
|
@@ -197,8 +225,7 @@ FILTERING
|
|
197
225
|
parser.separator("\n **** Utility ****\n\n")
|
198
226
|
|
199
227
|
parser.on('-v', '--version', 'Display the version.') do
|
200
|
-
|
201
|
-
exit
|
228
|
+
print_version_and_exit
|
202
229
|
end
|
203
230
|
|
204
231
|
# These options would otherwise be confusing to users, so we forcibly
|
@@ -210,9 +237,7 @@ FILTERING
|
|
210
237
|
invalid_options = %w[-d --I]
|
211
238
|
|
212
239
|
parser.on_tail('-h', '--help', "You're looking at it.") do
|
213
|
-
|
214
|
-
puts parser.to_s.gsub(/^\s+(#{invalid_options.join('|')})\s*$\n/, '')
|
215
|
-
exit
|
240
|
+
print_help_and_exit(parser, invalid_options)
|
216
241
|
end
|
217
242
|
|
218
243
|
# This prevents usage of the invalid_options.
|
@@ -224,5 +249,53 @@ FILTERING
|
|
224
249
|
|
225
250
|
end
|
226
251
|
end
|
252
|
+
# rubocop:enable MethodLength
|
253
|
+
|
254
|
+
def add_tag_filter(options, filter_type, tag_name, value=true)
|
255
|
+
(options[filter_type] ||= {})[tag_name] = value
|
256
|
+
end
|
257
|
+
|
258
|
+
def set_fail_fast(options, value)
|
259
|
+
options[:fail_fast] = value
|
260
|
+
end
|
261
|
+
|
262
|
+
def configure_only_failures(options)
|
263
|
+
options[:only_failures] = true
|
264
|
+
add_tag_filter(options, :inclusion_filter, :last_run_status, 'failed')
|
265
|
+
end
|
266
|
+
|
267
|
+
def initialize_project_and_exit
|
268
|
+
RSpec::Support.require_rspec_core "project_initializer"
|
269
|
+
ProjectInitializer.new.run
|
270
|
+
exit
|
271
|
+
end
|
272
|
+
|
273
|
+
def bisect_and_exit(argument)
|
274
|
+
RSpec::Support.require_rspec_core "bisect/coordinator"
|
275
|
+
|
276
|
+
success = Bisect::Coordinator.bisect_with(
|
277
|
+
original_args,
|
278
|
+
RSpec.configuration,
|
279
|
+
bisect_formatter_for(argument)
|
280
|
+
)
|
281
|
+
|
282
|
+
exit(success ? 0 : 1)
|
283
|
+
end
|
284
|
+
|
285
|
+
def bisect_formatter_for(argument)
|
286
|
+
return Formatters::BisectDebugFormatter if argument == "verbose"
|
287
|
+
Formatters::BisectProgressFormatter
|
288
|
+
end
|
289
|
+
|
290
|
+
def print_version_and_exit
|
291
|
+
puts RSpec::Core::Version::STRING
|
292
|
+
exit
|
293
|
+
end
|
294
|
+
|
295
|
+
def print_help_and_exit(parser, invalid_options)
|
296
|
+
# Removing the blank invalid options from the output.
|
297
|
+
puts parser.to_s.gsub(/^\s+(#{invalid_options.join('|')})\s*$\n/, '')
|
298
|
+
exit
|
299
|
+
end
|
227
300
|
end
|
228
301
|
end
|
data/lib/rspec/core/ordering.rb
CHANGED
@@ -1,14 +1,5 @@
|
|
1
1
|
module RSpec
|
2
2
|
module Core
|
3
|
-
if defined?(::Random)
|
4
|
-
# @private
|
5
|
-
RandomNumberGenerator = ::Random
|
6
|
-
else
|
7
|
-
RSpec::Support.require_rspec_core "backport_random"
|
8
|
-
# @private
|
9
|
-
RandomNumberGenerator = RSpec::Core::Backports::Random
|
10
|
-
end
|
11
|
-
|
12
3
|
# @private
|
13
4
|
module Ordering
|
14
5
|
# @private
|
@@ -33,26 +24,38 @@ module RSpec
|
|
33
24
|
|
34
25
|
def order(items)
|
35
26
|
@used = true
|
36
|
-
|
37
|
-
|
27
|
+
|
28
|
+
seed = @configuration.seed.to_s
|
29
|
+
items.sort_by { |item| jenkins_hash_digest(seed + item.id) }
|
38
30
|
end
|
39
31
|
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
32
|
+
private
|
33
|
+
|
34
|
+
# http://en.wikipedia.org/wiki/Jenkins_hash_function
|
35
|
+
# Jenkins provides a good distribution and is simpler than MD5.
|
36
|
+
# It's a bit slower than MD5 (primarily because `Digest::MD5` is
|
37
|
+
# implemented in C) but has the advantage of not requiring us
|
38
|
+
# to load another part of stdlib, which we try to minimize.
|
39
|
+
def jenkins_hash_digest(string)
|
40
|
+
hash = 0
|
41
|
+
|
42
|
+
string.each_byte do |byte|
|
43
|
+
hash += byte
|
44
|
+
hash &= MAX_32_BIT
|
45
|
+
hash += ((hash << 10) & MAX_32_BIT)
|
46
|
+
hash &= MAX_32_BIT
|
47
|
+
hash ^= hash >> 6
|
54
48
|
end
|
49
|
+
|
50
|
+
hash += ((hash << 3) & MAX_32_BIT)
|
51
|
+
hash &= MAX_32_BIT
|
52
|
+
hash ^= hash >> 11
|
53
|
+
hash += ((hash << 15) & MAX_32_BIT)
|
54
|
+
hash &= MAX_32_BIT
|
55
|
+
hash
|
55
56
|
end
|
57
|
+
|
58
|
+
MAX_32_BIT = 4_294_967_295
|
56
59
|
end
|
57
60
|
|
58
61
|
# @private
|
@@ -0,0 +1,32 @@
|
|
1
|
+
module RSpec
|
2
|
+
module Core
|
3
|
+
# @private
|
4
|
+
class Profiler
|
5
|
+
NOTIFICATIONS = [:example_group_started, :example_group_finished, :example_started]
|
6
|
+
|
7
|
+
def initialize
|
8
|
+
@example_groups = Hash.new { |h, k| h[k] = { :count => 0 } }
|
9
|
+
end
|
10
|
+
|
11
|
+
attr_reader :example_groups
|
12
|
+
|
13
|
+
def example_group_started(notification)
|
14
|
+
return unless notification.group.top_level?
|
15
|
+
|
16
|
+
@example_groups[notification.group][:start] = Time.now
|
17
|
+
@example_groups[notification.group][:description] = notification.group.top_level_description
|
18
|
+
end
|
19
|
+
|
20
|
+
def example_group_finished(notification)
|
21
|
+
return unless notification.group.top_level?
|
22
|
+
|
23
|
+
@example_groups[notification.group][:total_time] = Time.now - @example_groups[notification.group][:start]
|
24
|
+
end
|
25
|
+
|
26
|
+
def example_started(notification)
|
27
|
+
group = notification.example.example_group.parent_groups.last
|
28
|
+
@example_groups[group][:count] += 1
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -50,10 +50,15 @@ RSpec.configure do |config|
|
|
50
50
|
config.filter_run :focus
|
51
51
|
config.run_all_when_everything_filtered = true
|
52
52
|
|
53
|
+
# Allows RSpec to persist some state between runs in order to support
|
54
|
+
# the `--only-failures` and `--next-failure` CLI options. We recommend
|
55
|
+
# you configure your source control system to ignore this file.
|
56
|
+
config.example_status_persistence_file_path = "spec/examples.txt"
|
57
|
+
|
53
58
|
# Limits the available syntax to the non-monkey patched syntax that is
|
54
59
|
# recommended. For more details, see:
|
55
60
|
# - http://myronmars.to/n/dev-blog/2012/06/rspecs-new-expectation-syntax
|
56
|
-
# - http://teaisaweso.me/blog/2013/05/27/rspecs-new-message-expectation-syntax/
|
61
|
+
# - http://www.teaisaweso.me/blog/2013/05/27/rspecs-new-message-expectation-syntax/
|
57
62
|
# - http://myronmars.to/n/dev-blog/2014/05/notable-changes-in-rspec-3#new__config_option_to_disable_rspeccore_monkey_patching
|
58
63
|
config.disable_monkey_patching!
|
59
64
|
|
data/lib/rspec/core/rake_task.rb
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
require 'rake'
|
2
2
|
require 'rake/tasklib'
|
3
3
|
require 'rspec/support/ruby_features'
|
4
|
+
require 'rspec/core/shell_escape'
|
4
5
|
|
5
6
|
module RSpec
|
6
7
|
module Core
|
@@ -9,6 +10,7 @@ module RSpec
|
|
9
10
|
# @see Rakefile
|
10
11
|
class RakeTask < ::Rake::TaskLib
|
11
12
|
include ::Rake::DSL if defined?(::Rake::DSL)
|
13
|
+
include RSpec::Core::ShellEscape
|
12
14
|
|
13
15
|
# Default path to the RSpec executable.
|
14
16
|
DEFAULT_RSPEC_PATH = File.expand_path('../../../../exe/rspec', __FILE__)
|
@@ -63,16 +65,12 @@ module RSpec
|
|
63
65
|
# @private
|
64
66
|
def run_task(verbose)
|
65
67
|
command = spec_command
|
68
|
+
puts command if verbose
|
66
69
|
|
67
|
-
|
68
|
-
|
69
|
-
success = system(command)
|
70
|
-
rescue
|
71
|
-
puts failure_message if failure_message
|
72
|
-
end
|
73
|
-
|
74
|
-
return unless fail_on_error && !success
|
70
|
+
return if system(command)
|
71
|
+
puts failure_message if failure_message
|
75
72
|
|
73
|
+
return unless fail_on_error
|
76
74
|
$stderr.puts "#{command} failed" if verbose
|
77
75
|
exit $?.exitstatus
|
78
76
|
end
|
@@ -126,18 +124,6 @@ module RSpec
|
|
126
124
|
end
|
127
125
|
end
|
128
126
|
|
129
|
-
if RSpec::Support::OS.windows?
|
130
|
-
def escape(shell_command)
|
131
|
-
"'#{shell_command.gsub("'", "\'")}'"
|
132
|
-
end
|
133
|
-
else
|
134
|
-
require 'shellwords'
|
135
|
-
|
136
|
-
def escape(shell_command)
|
137
|
-
shell_command.shellescape
|
138
|
-
end
|
139
|
-
end
|
140
|
-
|
141
127
|
def file_exclusion_specification
|
142
128
|
" --exclude-pattern #{escape exclude_pattern}" if exclude_pattern
|
143
129
|
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
module RSpec
|
2
|
+
module Core
|
3
|
+
# Allows a thread to lock out other threads from a critical section of code,
|
4
|
+
# while allowing the thread with the lock to reenter that section.
|
5
|
+
#
|
6
|
+
# Based on Monitor as of 2.2 - https://github.com/ruby/ruby/blob/eb7ddaa3a47bf48045d26c72eb0f263a53524ebc/lib/monitor.rb#L9
|
7
|
+
#
|
8
|
+
# Depends on Mutex, but Mutex is only available as part of core since 1.9.1:
|
9
|
+
# exists - http://ruby-doc.org/core-1.9.1/Mutex.html
|
10
|
+
# dne - http://ruby-doc.org/core-1.9.0/Mutex.html
|
11
|
+
#
|
12
|
+
# @private
|
13
|
+
class ReentrantMutex
|
14
|
+
def initialize
|
15
|
+
@owner = nil
|
16
|
+
@count = 0
|
17
|
+
@mutex = Mutex.new
|
18
|
+
end
|
19
|
+
|
20
|
+
def synchronize
|
21
|
+
enter
|
22
|
+
yield
|
23
|
+
ensure
|
24
|
+
exit
|
25
|
+
end
|
26
|
+
|
27
|
+
private
|
28
|
+
|
29
|
+
def enter
|
30
|
+
@mutex.lock if @owner != Thread.current
|
31
|
+
@owner = Thread.current
|
32
|
+
@count += 1
|
33
|
+
end
|
34
|
+
|
35
|
+
def exit
|
36
|
+
@count -= 1
|
37
|
+
return unless @count == 0
|
38
|
+
@owner = nil
|
39
|
+
@mutex.unlock
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
if defined? ::Mutex
|
44
|
+
# On 1.9 and up, this is in core, so we just use the real one
|
45
|
+
Mutex = ::Mutex
|
46
|
+
else # For 1.8.7
|
47
|
+
# :nocov:
|
48
|
+
RSpec::Support.require_rspec_core "mutex"
|
49
|
+
# :nocov:
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
data/lib/rspec/core/reporter.rb
CHANGED
@@ -2,6 +2,15 @@ module RSpec::Core
|
|
2
2
|
# A reporter will send notifications to listeners, usually formatters for the
|
3
3
|
# spec suite run.
|
4
4
|
class Reporter
|
5
|
+
# @private
|
6
|
+
RSPEC_NOTIFICATIONS = Set.new(
|
7
|
+
[
|
8
|
+
:close, :deprecation, :deprecation_summary, :dump_failures, :dump_pending,
|
9
|
+
:dump_profile, :dump_summary, :example_failed, :example_group_finished,
|
10
|
+
:example_group_started, :example_passed, :example_pending, :example_started,
|
11
|
+
:message, :seed, :start, :start_dump, :stop
|
12
|
+
])
|
13
|
+
|
5
14
|
def initialize(configuration)
|
6
15
|
@configuration = configuration
|
7
16
|
@listeners = Hash.new { |h, k| h[k] = Set.new }
|
@@ -19,6 +28,13 @@ module RSpec::Core
|
|
19
28
|
@examples = []
|
20
29
|
@failed_examples = []
|
21
30
|
@pending_examples = []
|
31
|
+
@profiler = Profiler.new if defined?(@profiler)
|
32
|
+
end
|
33
|
+
|
34
|
+
# @private
|
35
|
+
def setup_profiler
|
36
|
+
@profiler = Profiler.new
|
37
|
+
register_listener @profiler, *Profiler::NOTIFICATIONS
|
22
38
|
end
|
23
39
|
|
24
40
|
# Registers a listener to a list of notifications. The reporter will send
|
@@ -40,7 +56,6 @@ module RSpec::Core
|
|
40
56
|
@listeners[notification].to_a
|
41
57
|
end
|
42
58
|
|
43
|
-
# @api
|
44
59
|
# @overload report(count, &block)
|
45
60
|
# @overload report(count, &block)
|
46
61
|
# @param expected_example_count [Integer] the number of examples being run
|
@@ -73,11 +88,26 @@ module RSpec::Core
|
|
73
88
|
notify :start, Notifications::StartNotification.new(expected_example_count, @load_time)
|
74
89
|
end
|
75
90
|
|
76
|
-
# @
|
91
|
+
# @param message [#to_s] A message object to send to formatters
|
92
|
+
#
|
93
|
+
# Send a custom message to supporting formatters.
|
77
94
|
def message(message)
|
78
95
|
notify :message, Notifications::MessageNotification.new(message)
|
79
96
|
end
|
80
97
|
|
98
|
+
# @param event [Symbol] Name of the custom event to trigger on formatters
|
99
|
+
# @param options [Hash] Hash of arguments to provide via `CustomNotification`
|
100
|
+
#
|
101
|
+
# Publish a custom event to supporting registered formatters.
|
102
|
+
# @see RSpec::Core::Notifications::CustomNotification
|
103
|
+
def publish(event, options={})
|
104
|
+
if RSPEC_NOTIFICATIONS.include? event
|
105
|
+
raise "RSpec::Core::Reporter#publish is intended for sending custom " \
|
106
|
+
"events not internal RSpec ones, please rename your custom event."
|
107
|
+
end
|
108
|
+
notify event, Notifications::CustomNotification.for(options)
|
109
|
+
end
|
110
|
+
|
81
111
|
# @private
|
82
112
|
def example_group_started(group)
|
83
113
|
notify :example_group_started, Notifications::GroupNotification.new(group) unless group.descendant_filtered_examples.empty?
|
@@ -118,20 +148,28 @@ module RSpec::Core
|
|
118
148
|
|
119
149
|
# @private
|
120
150
|
def finish
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
151
|
+
close_after do
|
152
|
+
stop
|
153
|
+
notify :start_dump, Notifications::NullNotification
|
154
|
+
notify :dump_pending, Notifications::ExamplesNotification.new(self)
|
155
|
+
notify :dump_failures, Notifications::ExamplesNotification.new(self)
|
156
|
+
notify :deprecation_summary, Notifications::NullNotification
|
157
|
+
unless mute_profile_output?
|
158
|
+
notify :dump_profile, Notifications::ProfileNotification.new(@duration, @examples,
|
159
|
+
@configuration.profile_examples,
|
160
|
+
@profiler.example_groups)
|
161
|
+
end
|
162
|
+
notify :dump_summary, Notifications::SummaryNotification.new(@duration, @examples, @failed_examples,
|
163
|
+
@pending_examples, @load_time)
|
164
|
+
notify :seed, Notifications::SeedNotification.new(@configuration.seed, seed_used?)
|
129
165
|
end
|
130
|
-
|
131
|
-
|
132
|
-
|
166
|
+
end
|
167
|
+
|
168
|
+
# @private
|
169
|
+
def close_after
|
170
|
+
yield
|
133
171
|
ensure
|
134
|
-
|
172
|
+
close
|
135
173
|
end
|
136
174
|
|
137
175
|
# @private
|
@@ -147,8 +185,19 @@ module RSpec::Core
|
|
147
185
|
end
|
148
186
|
end
|
149
187
|
|
188
|
+
# @private
|
189
|
+
def abort_with(msg, exit_status)
|
190
|
+
message(msg)
|
191
|
+
close
|
192
|
+
exit!(exit_status)
|
193
|
+
end
|
194
|
+
|
150
195
|
private
|
151
196
|
|
197
|
+
def close
|
198
|
+
notify :close, Notifications::NullNotification
|
199
|
+
end
|
200
|
+
|
152
201
|
def mute_profile_output?
|
153
202
|
# Don't print out profiled info if there are failures and `--fail-fast` is
|
154
203
|
# used, it just clutters the output.
|
@@ -163,10 +212,9 @@ module RSpec::Core
|
|
163
212
|
# @private
|
164
213
|
# # Used in place of a {Reporter} for situations where we don't want reporting output.
|
165
214
|
class NullReporter
|
166
|
-
|
167
|
-
|
168
|
-
def method_missing(*)
|
215
|
+
def self.method_missing(*)
|
169
216
|
# ignore
|
170
217
|
end
|
218
|
+
private_class_method :method_missing
|
171
219
|
end
|
172
220
|
end
|