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
@@ -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
|