rspec-core 3.7.0 → 3.9.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 +5 -5
- checksums.yaml.gz.sig +0 -0
- data.tar.gz.sig +0 -0
- data/Changelog.md +80 -2
- data/README.md +16 -16
- data/lib/rspec/core.rb +1 -0
- data/lib/rspec/core/bisect/coordinator.rb +26 -30
- data/lib/rspec/core/bisect/example_minimizer.rb +12 -8
- data/lib/rspec/core/bisect/fork_runner.rb +134 -0
- data/lib/rspec/core/bisect/server.rb +5 -14
- data/lib/rspec/core/bisect/{runner.rb → shell_command.rb} +27 -70
- data/lib/rspec/core/bisect/shell_runner.rb +73 -0
- data/lib/rspec/core/bisect/utilities.rb +58 -0
- data/lib/rspec/core/configuration.rb +219 -62
- data/lib/rspec/core/configuration_options.rb +41 -4
- data/lib/rspec/core/did_you_mean.rb +46 -0
- data/lib/rspec/core/example.rb +8 -5
- data/lib/rspec/core/example_group.rb +8 -3
- data/lib/rspec/core/formatters.rb +13 -6
- data/lib/rspec/core/formatters/base_bisect_formatter.rb +45 -0
- data/lib/rspec/core/formatters/bisect_drb_formatter.rb +29 -0
- data/lib/rspec/core/formatters/bisect_progress_formatter.rb +29 -16
- data/lib/rspec/core/formatters/deprecation_formatter.rb +3 -1
- data/lib/rspec/core/formatters/documentation_formatter.rb +35 -3
- data/lib/rspec/core/formatters/exception_presenter.rb +13 -1
- data/lib/rspec/core/formatters/failure_list_formatter.rb +23 -0
- data/lib/rspec/core/formatters/html_printer.rb +0 -2
- data/lib/rspec/core/formatters/protocol.rb +17 -17
- data/lib/rspec/core/formatters/syntax_highlighter.rb +19 -19
- data/lib/rspec/core/hooks.rb +15 -9
- data/lib/rspec/core/invocations.rb +8 -6
- data/lib/rspec/core/memoized_helpers.rb +33 -14
- data/lib/rspec/core/metadata.rb +2 -3
- data/lib/rspec/core/option_parser.rb +8 -0
- data/lib/rspec/core/profiler.rb +3 -1
- data/lib/rspec/core/rake_task.rb +21 -1
- data/lib/rspec/core/reporter.rb +11 -6
- data/lib/rspec/core/runner.rb +25 -14
- data/lib/rspec/core/shared_example_group.rb +2 -4
- data/lib/rspec/core/shell_escape.rb +2 -2
- data/lib/rspec/core/version.rb +1 -1
- data/lib/rspec/core/world.rb +11 -0
- metadata +22 -13
- metadata.gz.sig +0 -0
- data/lib/rspec/core/formatters/bisect_formatter.rb +0 -69
@@ -1,13 +1,11 @@
|
|
1
1
|
require 'drb/drb'
|
2
2
|
require 'drb/acl'
|
3
|
+
RSpec::Support.require_rspec_core "bisect/utilities"
|
3
4
|
|
4
5
|
module RSpec
|
5
6
|
module Core
|
6
7
|
# @private
|
7
8
|
module Bisect
|
8
|
-
# @private
|
9
|
-
BisectFailedError = Class.new(StandardError)
|
10
|
-
|
11
9
|
# @private
|
12
10
|
# A DRb server that receives run results from a separate RSpec process
|
13
11
|
# started by the bisect process.
|
@@ -27,7 +25,7 @@ module RSpec
|
|
27
25
|
run_output = yield
|
28
26
|
|
29
27
|
if latest_run_results.nil? || latest_run_results.all_example_ids.empty?
|
30
|
-
|
28
|
+
raise BisectFailedError.for_failed_spec_run(run_output)
|
31
29
|
end
|
32
30
|
|
33
31
|
latest_run_results
|
@@ -35,7 +33,7 @@ module RSpec
|
|
35
33
|
|
36
34
|
def start
|
37
35
|
# Only allow remote DRb requests from this machine.
|
38
|
-
DRb.install_acl ACL.new(%w[ deny all allow localhost allow 127.0.0.1 ])
|
36
|
+
DRb.install_acl ACL.new(%w[ deny all allow localhost allow 127.0.0.1 allow ::1 ])
|
39
37
|
|
40
38
|
# We pass `nil` as the first arg to allow it to pick a DRb port.
|
41
39
|
@drb = DRb.start_service(nil, self)
|
@@ -49,21 +47,14 @@ module RSpec
|
|
49
47
|
@drb_port ||= Integer(@drb.uri[/\d+$/])
|
50
48
|
end
|
51
49
|
|
52
|
-
# Fetched via DRb by the
|
50
|
+
# Fetched via DRb by the BisectDRbFormatter to determine when to abort.
|
53
51
|
attr_accessor :expected_failures
|
54
52
|
|
55
|
-
# Set via DRb by the
|
53
|
+
# Set via DRb by the BisectDRbFormatter with the results of the run.
|
56
54
|
attr_accessor :latest_run_results
|
57
55
|
|
58
56
|
# Fetched via DRb to tell clients which files to run
|
59
57
|
attr_accessor :files_or_directories_to_run
|
60
|
-
|
61
|
-
private
|
62
|
-
|
63
|
-
def raise_bisect_failed(run_output)
|
64
|
-
raise BisectFailedError, "Failed to get results from the spec " \
|
65
|
-
"run. Spec run output:\n\n#{run_output}"
|
66
|
-
end
|
67
58
|
end
|
68
59
|
end
|
69
60
|
end
|
@@ -1,36 +1,30 @@
|
|
1
1
|
RSpec::Support.require_rspec_core "shell_escape"
|
2
|
-
require 'open3'
|
3
2
|
require 'shellwords'
|
4
3
|
|
5
4
|
module RSpec
|
6
5
|
module Core
|
7
6
|
module Bisect
|
8
|
-
# Provides an API to run the suite for a
|
9
|
-
# the given bisect server to capture the results.
|
7
|
+
# Provides an API to generate shell commands to run the suite for a
|
8
|
+
# set of locations, using the given bisect server to capture the results.
|
10
9
|
# @private
|
11
|
-
class
|
10
|
+
class ShellCommand
|
12
11
|
attr_reader :original_cli_args
|
13
12
|
|
14
|
-
def initialize(
|
15
|
-
@server = server
|
13
|
+
def initialize(original_cli_args)
|
16
14
|
@original_cli_args = original_cli_args.reject { |arg| arg.start_with?("--bisect") }
|
17
15
|
end
|
18
16
|
|
19
|
-
def
|
20
|
-
run_locations(locations, original_results.failed_example_ids)
|
21
|
-
end
|
22
|
-
|
23
|
-
def command_for(locations)
|
17
|
+
def command_for(locations, server)
|
24
18
|
parts = []
|
25
19
|
|
26
20
|
parts << RUBY << load_path
|
27
21
|
parts << open3_safe_escape(RSpec::Core.path_to_executable)
|
28
22
|
|
29
|
-
parts << "--format" << "bisect"
|
30
|
-
parts << "--drb-port" <<
|
23
|
+
parts << "--format" << "bisect-drb"
|
24
|
+
parts << "--drb-port" << server.drb_port
|
31
25
|
|
32
|
-
parts.concat
|
33
|
-
parts.concat
|
26
|
+
parts.concat(reusable_cli_options)
|
27
|
+
parts.concat(locations.map { |l| open3_safe_escape(l) })
|
34
28
|
|
35
29
|
parts.join(" ")
|
36
30
|
end
|
@@ -46,8 +40,24 @@ module RSpec
|
|
46
40
|
parts.join(" ")
|
47
41
|
end
|
48
42
|
|
49
|
-
def
|
50
|
-
|
43
|
+
def original_locations
|
44
|
+
parsed_original_cli_options.fetch(:files_or_directories_to_run)
|
45
|
+
end
|
46
|
+
|
47
|
+
def bisect_environment_hash
|
48
|
+
if ENV.key?('SPEC_OPTS')
|
49
|
+
{ 'SPEC_OPTS' => spec_opts_without_bisect }
|
50
|
+
else
|
51
|
+
{}
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
def spec_opts_without_bisect
|
56
|
+
Shellwords.join(
|
57
|
+
Shellwords.split(ENV.fetch('SPEC_OPTS', '')).reject do |arg|
|
58
|
+
arg =~ /^--bisect/
|
59
|
+
end
|
60
|
+
)
|
51
61
|
end
|
52
62
|
|
53
63
|
private
|
@@ -63,61 +73,12 @@ module RSpec
|
|
63
73
|
alias open3_safe_escape escape
|
64
74
|
end
|
65
75
|
|
66
|
-
def run_locations(*capture_args)
|
67
|
-
@server.capture_run_results(*capture_args) do
|
68
|
-
run_command command_for([])
|
69
|
-
end
|
70
|
-
end
|
71
|
-
|
72
|
-
# `Open3.capture2e` does not work on JRuby:
|
73
|
-
# https://github.com/jruby/jruby/issues/2766
|
74
|
-
if Open3.respond_to?(:capture2e) && !RSpec::Support::Ruby.jruby?
|
75
|
-
def run_command(cmd)
|
76
|
-
Open3.capture2e(bisect_environment_hash, cmd).first
|
77
|
-
end
|
78
|
-
else # for 1.8.7
|
79
|
-
# :nocov:
|
80
|
-
def run_command(cmd)
|
81
|
-
out = err = nil
|
82
|
-
|
83
|
-
original_spec_opts = ENV['SPEC_OPTS']
|
84
|
-
ENV['SPEC_OPTS'] = spec_opts_without_bisect
|
85
|
-
|
86
|
-
Open3.popen3(cmd) do |_, stdout, stderr|
|
87
|
-
# Reading the streams blocks until the process is complete
|
88
|
-
out = stdout.read
|
89
|
-
err = stderr.read
|
90
|
-
end
|
91
|
-
|
92
|
-
"Stdout:\n#{out}\n\nStderr:\n#{err}"
|
93
|
-
ensure
|
94
|
-
ENV['SPEC_OPTS'] = original_spec_opts
|
95
|
-
end
|
96
|
-
# :nocov:
|
97
|
-
end
|
98
|
-
|
99
|
-
def bisect_environment_hash
|
100
|
-
if ENV.key?('SPEC_OPTS')
|
101
|
-
{ 'SPEC_OPTS' => spec_opts_without_bisect }
|
102
|
-
else
|
103
|
-
{}
|
104
|
-
end
|
105
|
-
end
|
106
|
-
|
107
76
|
def environment_repro_parts
|
108
77
|
bisect_environment_hash.map do |k, v|
|
109
78
|
%Q(#{k}="#{v}")
|
110
79
|
end
|
111
80
|
end
|
112
81
|
|
113
|
-
def spec_opts_without_bisect
|
114
|
-
Shellwords.join(
|
115
|
-
Shellwords.split(ENV.fetch('SPEC_OPTS', '')).reject do |arg|
|
116
|
-
arg =~ /^--bisect/
|
117
|
-
end
|
118
|
-
)
|
119
|
-
end
|
120
|
-
|
121
82
|
def reusable_cli_options
|
122
83
|
@reusable_cli_options ||= begin
|
123
84
|
opts = original_cli_args_without_locations
|
@@ -146,10 +107,6 @@ module RSpec
|
|
146
107
|
@parsed_original_cli_options ||= Parser.parse(@original_cli_args)
|
147
108
|
end
|
148
109
|
|
149
|
-
def original_locations
|
150
|
-
parsed_original_cli_options.fetch(:files_or_directories_to_run)
|
151
|
-
end
|
152
|
-
|
153
110
|
def load_path
|
154
111
|
@load_path ||= "-I#{$LOAD_PATH.map { |p| open3_safe_escape(p) }.join(':')}"
|
155
112
|
end
|
@@ -0,0 +1,73 @@
|
|
1
|
+
require 'open3'
|
2
|
+
RSpec::Support.require_rspec_core "bisect/server"
|
3
|
+
|
4
|
+
module RSpec
|
5
|
+
module Core
|
6
|
+
module Bisect
|
7
|
+
# Provides an API to run the suite for a set of locations, using
|
8
|
+
# the given bisect server to capture the results.
|
9
|
+
#
|
10
|
+
# Sets of specs are run by shelling out.
|
11
|
+
# @private
|
12
|
+
class ShellRunner
|
13
|
+
def self.start(shell_command, _spec_runner)
|
14
|
+
Server.run do |server|
|
15
|
+
yield new(server, shell_command)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def self.name
|
20
|
+
:shell
|
21
|
+
end
|
22
|
+
|
23
|
+
def initialize(server, shell_command)
|
24
|
+
@server = server
|
25
|
+
@shell_command = shell_command
|
26
|
+
end
|
27
|
+
|
28
|
+
def run(locations)
|
29
|
+
run_locations(locations, original_results.failed_example_ids)
|
30
|
+
end
|
31
|
+
|
32
|
+
def original_results
|
33
|
+
@original_results ||= run_locations(@shell_command.original_locations)
|
34
|
+
end
|
35
|
+
|
36
|
+
private
|
37
|
+
|
38
|
+
def run_locations(*capture_args)
|
39
|
+
@server.capture_run_results(*capture_args) do
|
40
|
+
run_command @shell_command.command_for([], @server)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
# `Open3.capture2e` does not work on JRuby:
|
45
|
+
# https://github.com/jruby/jruby/issues/2766
|
46
|
+
if Open3.respond_to?(:capture2e) && !RSpec::Support::Ruby.jruby?
|
47
|
+
def run_command(cmd)
|
48
|
+
Open3.capture2e(@shell_command.bisect_environment_hash, cmd).first
|
49
|
+
end
|
50
|
+
else # for 1.8.7
|
51
|
+
# :nocov:
|
52
|
+
def run_command(cmd)
|
53
|
+
out = err = nil
|
54
|
+
|
55
|
+
original_spec_opts = ENV['SPEC_OPTS']
|
56
|
+
ENV['SPEC_OPTS'] = @shell_command.spec_opts_without_bisect
|
57
|
+
|
58
|
+
Open3.popen3(cmd) do |_, stdout, stderr|
|
59
|
+
# Reading the streams blocks until the process is complete
|
60
|
+
out = stdout.read
|
61
|
+
err = stderr.read
|
62
|
+
end
|
63
|
+
|
64
|
+
"Stdout:\n#{out}\n\nStderr:\n#{err}"
|
65
|
+
ensure
|
66
|
+
ENV['SPEC_OPTS'] = original_spec_opts
|
67
|
+
end
|
68
|
+
# :nocov:
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
module RSpec
|
2
|
+
module Core
|
3
|
+
module Bisect
|
4
|
+
# @private
|
5
|
+
ExampleSetDescriptor = Struct.new(:all_example_ids, :failed_example_ids)
|
6
|
+
|
7
|
+
# @private
|
8
|
+
class BisectFailedError < StandardError
|
9
|
+
def self.for_failed_spec_run(spec_output)
|
10
|
+
new("Failed to get results from the spec run. Spec run output:\n\n" +
|
11
|
+
spec_output)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
# Wraps a `formatter` providing a simple means to notify it in place
|
16
|
+
# of an `RSpec::Core::Reporter`, without involving configuration in
|
17
|
+
# any way.
|
18
|
+
# @private
|
19
|
+
class Notifier
|
20
|
+
def initialize(formatter)
|
21
|
+
@formatter = formatter
|
22
|
+
end
|
23
|
+
|
24
|
+
def publish(event, *args)
|
25
|
+
return unless @formatter.respond_to?(event)
|
26
|
+
notification = Notifications::CustomNotification.for(*args)
|
27
|
+
@formatter.__send__(event, notification)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
# Wraps a pipe to support sending objects between a child and
|
32
|
+
# parent process.
|
33
|
+
# @private
|
34
|
+
class Channel
|
35
|
+
def initialize
|
36
|
+
@read_io, @write_io = IO.pipe
|
37
|
+
end
|
38
|
+
|
39
|
+
def send(message)
|
40
|
+
packet = Marshal.dump(message)
|
41
|
+
@write_io.write("#{packet.bytesize}\n#{packet}")
|
42
|
+
end
|
43
|
+
|
44
|
+
# rubocop:disable Security/MarshalLoad
|
45
|
+
def receive
|
46
|
+
packet_size = Integer(@read_io.gets)
|
47
|
+
Marshal.load(@read_io.read(packet_size))
|
48
|
+
end
|
49
|
+
# rubocop:enable Security/MarshalLoad
|
50
|
+
|
51
|
+
def close
|
52
|
+
@read_io.close
|
53
|
+
@write_io.close
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
@@ -9,10 +9,24 @@ module RSpec
|
|
9
9
|
|
10
10
|
# Stores runtime configuration information.
|
11
11
|
#
|
12
|
-
# Configuration options are loaded from
|
13
|
-
#
|
14
|
-
#
|
15
|
-
#
|
12
|
+
# Configuration options are loaded from multiple files and joined together
|
13
|
+
# with command-line switches and the `SPEC_OPTS` environment variable.
|
14
|
+
#
|
15
|
+
# Precedence order (where later entries overwrite earlier entries on
|
16
|
+
# conflicts):
|
17
|
+
#
|
18
|
+
# * Global (`$XDG_CONFIG_HOME/rspec/options`, or `~/.rspec` if it does
|
19
|
+
# not exist)
|
20
|
+
# * Project-specific (`./.rspec`)
|
21
|
+
# * Local (`./.rspec-local`)
|
22
|
+
# * Command-line options
|
23
|
+
# * `SPEC_OPTS`
|
24
|
+
#
|
25
|
+
# For example, an option set in the local file will override an option set
|
26
|
+
# in your global file.
|
27
|
+
#
|
28
|
+
# The global, project-specific and local files can all be overridden with a
|
29
|
+
# separate custom file using the --options command-line parameter.
|
16
30
|
#
|
17
31
|
# @example Standard settings
|
18
32
|
# RSpec.configure do |c|
|
@@ -89,7 +103,6 @@ module RSpec
|
|
89
103
|
|
90
104
|
# @macro [attach] add_setting
|
91
105
|
# @!attribute [rw] $1
|
92
|
-
# @!method $1=(value)
|
93
106
|
#
|
94
107
|
# @macro [attach] define_reader
|
95
108
|
# @!attribute [r] $1
|
@@ -101,6 +114,7 @@ module RSpec
|
|
101
114
|
#
|
102
115
|
# @note Other scripts invoking `rspec` indirectly will ignore this
|
103
116
|
# setting.
|
117
|
+
# @return [String]
|
104
118
|
add_read_only_setting :default_path
|
105
119
|
def default_path=(path)
|
106
120
|
project_source_dirs << path
|
@@ -110,6 +124,7 @@ module RSpec
|
|
110
124
|
# @macro add_setting
|
111
125
|
# Run examples over DRb (default: `false`). RSpec doesn't supply the DRb
|
112
126
|
# server, but you can use tools like spork.
|
127
|
+
# @return [Boolean]
|
113
128
|
add_setting :drb
|
114
129
|
|
115
130
|
# @macro add_setting
|
@@ -122,6 +137,7 @@ module RSpec
|
|
122
137
|
|
123
138
|
# Indicates if the DSL has been exposed off of modules and `main`.
|
124
139
|
# Default: true
|
140
|
+
# @return [Boolean]
|
125
141
|
def expose_dsl_globally?
|
126
142
|
Core::DSL.exposed_globally?
|
127
143
|
end
|
@@ -186,10 +202,33 @@ module RSpec
|
|
186
202
|
only_failures? && !example_status_persistence_file_path
|
187
203
|
end
|
188
204
|
|
189
|
-
# @macro
|
205
|
+
# @macro define_reader
|
190
206
|
# If specified, indicates the number of failures required before cleaning
|
191
|
-
# up and exit (default: `nil`).
|
192
|
-
|
207
|
+
# up and exit (default: `nil`). Can also be `true` to fail and exit on first
|
208
|
+
# failure
|
209
|
+
define_reader :fail_fast
|
210
|
+
|
211
|
+
# @see fail_fast
|
212
|
+
def fail_fast=(value)
|
213
|
+
case value
|
214
|
+
when true, 'true'
|
215
|
+
@fail_fast = true
|
216
|
+
when false, 'false', 0
|
217
|
+
@fail_fast = false
|
218
|
+
when nil
|
219
|
+
@fail_fast = nil
|
220
|
+
else
|
221
|
+
@fail_fast = value.to_i
|
222
|
+
|
223
|
+
if value.to_i == 0
|
224
|
+
# TODO: in RSpec 4, consider raising an error here.
|
225
|
+
RSpec.warning "Cannot set `RSpec.configuration.fail_fast`" \
|
226
|
+
" to `#{value.inspect}`. Only `true`, `false`, `nil` and integers" \
|
227
|
+
" are valid values."
|
228
|
+
@fail_fast = true
|
229
|
+
end
|
230
|
+
end
|
231
|
+
end
|
193
232
|
|
194
233
|
# @macro add_setting
|
195
234
|
# Prints the formatter output of your suite without running any
|
@@ -198,24 +237,29 @@ module RSpec
|
|
198
237
|
|
199
238
|
# @macro add_setting
|
200
239
|
# The exit code to return if there are any failures (default: 1).
|
240
|
+
# @return [Integer]
|
201
241
|
add_setting :failure_exit_code
|
202
242
|
|
203
243
|
# @macro add_setting
|
204
244
|
# Whether or not to fail when there are no RSpec examples (default: false).
|
245
|
+
# @return [Boolean]
|
205
246
|
add_setting :fail_if_no_examples
|
206
247
|
|
207
248
|
# @macro define_reader
|
208
249
|
# Indicates files configured to be required.
|
250
|
+
# @return [Array<String>]
|
209
251
|
define_reader :requires
|
210
252
|
|
211
253
|
# @macro define_reader
|
212
254
|
# Returns dirs that have been prepended to the load path by the `-I`
|
213
255
|
# command line option.
|
256
|
+
# @return [Array<String>]
|
214
257
|
define_reader :libs
|
215
258
|
|
216
259
|
# @macro add_setting
|
217
260
|
# Determines where RSpec will send its output.
|
218
261
|
# Default: `$stdout`.
|
262
|
+
# @return [IO, String]
|
219
263
|
define_reader :output_stream
|
220
264
|
|
221
265
|
# Set the output stream for reporter.
|
@@ -234,6 +278,7 @@ module RSpec
|
|
234
278
|
|
235
279
|
# @macro define_reader
|
236
280
|
# Load files matching this pattern (default: `'**{,/*/**}/*_spec.rb'`).
|
281
|
+
# @return [String]
|
237
282
|
define_reader :pattern
|
238
283
|
|
239
284
|
# Set pattern to match files to load.
|
@@ -244,6 +289,7 @@ module RSpec
|
|
244
289
|
|
245
290
|
# @macro define_reader
|
246
291
|
# Exclude files matching this pattern.
|
292
|
+
# @return [String]
|
247
293
|
define_reader :exclude_pattern
|
248
294
|
|
249
295
|
# Set pattern to match files to exclude.
|
@@ -265,6 +311,7 @@ module RSpec
|
|
265
311
|
# @macro add_setting
|
266
312
|
# Report the times for the slowest examples (default: `false`).
|
267
313
|
# Use this to specify the number of examples to include in the profile.
|
314
|
+
# @return [Boolean]
|
268
315
|
add_setting :profile_examples
|
269
316
|
|
270
317
|
# @macro add_setting
|
@@ -275,55 +322,56 @@ module RSpec
|
|
275
322
|
add_setting :run_all_when_everything_filtered
|
276
323
|
|
277
324
|
# @macro add_setting
|
278
|
-
# Color to use to indicate success.
|
279
|
-
#
|
280
|
-
#
|
281
|
-
#
|
325
|
+
# Color to use to indicate success. Defaults to `:green` but can be set
|
326
|
+
# to one of the following: `[:black, :white, :red, :green, :yellow,
|
327
|
+
# :blue, :magenta, :cyan]`
|
328
|
+
# @return [Symbol]
|
282
329
|
add_setting :success_color
|
283
330
|
|
284
331
|
# @macro add_setting
|
285
|
-
# Color to use to print pending examples.
|
286
|
-
#
|
287
|
-
#
|
288
|
-
#
|
332
|
+
# Color to use to print pending examples. Defaults to `:yellow` but can
|
333
|
+
# be set to one of the following: `[:black, :white, :red, :green,
|
334
|
+
# :yellow, :blue, :magenta, :cyan]`
|
335
|
+
# @return [Symbol]
|
289
336
|
add_setting :pending_color
|
290
337
|
|
291
338
|
# @macro add_setting
|
292
|
-
# Color to use to indicate failure.
|
293
|
-
#
|
294
|
-
#
|
295
|
-
#
|
339
|
+
# Color to use to indicate failure. Defaults to `:red` but can be set to
|
340
|
+
# one of the following: `[:black, :white, :red, :green, :yellow, :blue,
|
341
|
+
# :magenta, :cyan]`
|
342
|
+
# @return [Symbol]
|
296
343
|
add_setting :failure_color
|
297
344
|
|
298
345
|
# @macro add_setting
|
299
|
-
# The default output color.
|
300
|
-
#
|
301
|
-
#
|
302
|
-
#
|
346
|
+
# The default output color. Defaults to `:white` but can be set to one of
|
347
|
+
# the following: `[:black, :white, :red, :green, :yellow, :blue,
|
348
|
+
# :magenta, :cyan]`
|
349
|
+
# @return [Symbol]
|
303
350
|
add_setting :default_color
|
304
351
|
|
305
352
|
# @macro add_setting
|
306
|
-
# Color used when a pending example is fixed.
|
307
|
-
#
|
308
|
-
#
|
309
|
-
#
|
353
|
+
# Color used when a pending example is fixed. Defaults to `:blue` but can
|
354
|
+
# be set to one of the following: `[:black, :white, :red, :green,
|
355
|
+
# :yellow, :blue, :magenta, :cyan]`
|
356
|
+
# @return [Symbol]
|
310
357
|
add_setting :fixed_color
|
311
358
|
|
312
359
|
# @macro add_setting
|
313
|
-
# Color used to print details.
|
314
|
-
#
|
315
|
-
#
|
316
|
-
#
|
360
|
+
# Color used to print details. Defaults to `:cyan` but can be set to one
|
361
|
+
# of the following: `[:black, :white, :red, :green, :yellow, :blue,
|
362
|
+
# :magenta, :cyan]`
|
363
|
+
# @return [Symbol]
|
317
364
|
add_setting :detail_color
|
318
365
|
|
319
366
|
# @macro add_setting
|
320
367
|
# Don't print filter info i.e. "Run options: include {:focus=>true}"
|
321
368
|
# (default `false`).
|
369
|
+
# return [Boolean]
|
322
370
|
add_setting :silence_filter_announcements
|
323
371
|
|
324
|
-
#
|
325
|
-
#
|
326
|
-
#
|
372
|
+
# @deprecated This config option was added in RSpec 2 to pave the way
|
373
|
+
# for this being the default behavior in RSpec 3. Now this option is
|
374
|
+
# a no-op.
|
327
375
|
def treat_symbols_as_metadata_keys_with_true_values=(_value)
|
328
376
|
RSpec.deprecate(
|
329
377
|
"RSpec::Core::Configuration#treat_symbols_as_metadata_keys_with_true_values=",
|
@@ -387,18 +435,53 @@ module RSpec
|
|
387
435
|
end
|
388
436
|
|
389
437
|
# Record the start time of the spec suite to measure load time.
|
438
|
+
# return [Time]
|
390
439
|
add_setting :start_time
|
391
440
|
|
392
441
|
# @macro add_setting
|
393
442
|
# Use threadsafe options where available.
|
394
443
|
# Currently this will place a mutex around memoized values such as let blocks.
|
444
|
+
# return [Boolean]
|
395
445
|
add_setting :threadsafe
|
396
446
|
|
397
447
|
# @macro add_setting
|
398
448
|
# Maximum count of failed source lines to display in the failure reports.
|
399
449
|
# (default `10`).
|
450
|
+
# return [Integer]
|
400
451
|
add_setting :max_displayed_failure_line_count
|
401
452
|
|
453
|
+
# Determines which bisect runner implementation gets used to run subsets
|
454
|
+
# of the suite during a bisection. Your choices are:
|
455
|
+
#
|
456
|
+
# - `:shell`: Performs a spec run by shelling out, booting RSpec and your
|
457
|
+
# application environment each time. This runner is the most widely
|
458
|
+
# compatible runner, but is not as fast. On platforms that do not
|
459
|
+
# support forking, this is the default.
|
460
|
+
# - `:fork`: Pre-boots RSpec and your application environment in a parent
|
461
|
+
# process, and then forks a child process for each spec run. This runner
|
462
|
+
# tends to be significantly faster than the `:shell` runner but cannot
|
463
|
+
# be used in some situations. On platforms that support forking, this
|
464
|
+
# is the default. If you use this runner, you should ensure that all
|
465
|
+
# of your one-time setup logic goes in a `before(:suite)` hook instead
|
466
|
+
# of getting run at the top-level of a file loaded by `--require`.
|
467
|
+
#
|
468
|
+
# @note This option will only be used by `--bisect` if you set it in a file
|
469
|
+
# loaded via `--require`.
|
470
|
+
#
|
471
|
+
# @return [Symbol]
|
472
|
+
attr_reader :bisect_runner
|
473
|
+
def bisect_runner=(value)
|
474
|
+
if @bisect_runner_class && value != @bisect_runner
|
475
|
+
raise "`config.bisect_runner = #{value.inspect}` can no longer take " \
|
476
|
+
"effect as the #{@bisect_runner.inspect} bisect runnner is already " \
|
477
|
+
"in use. This config setting must be set in a file loaded by a " \
|
478
|
+
"`--require` option (passed at the CLI or in a `.rspec` file) for " \
|
479
|
+
"it to have any effect."
|
480
|
+
end
|
481
|
+
|
482
|
+
@bisect_runner = value
|
483
|
+
end
|
484
|
+
|
402
485
|
# @private
|
403
486
|
# @deprecated Use {#color_mode} = :on, instead of {#color} with {#tty}
|
404
487
|
add_setting :tty
|
@@ -411,8 +494,7 @@ module RSpec
|
|
411
494
|
# @private
|
412
495
|
attr_reader :backtrace_formatter, :ordering_manager, :loaded_spec_files
|
413
496
|
|
414
|
-
# rubocop:disable Metrics/AbcSize
|
415
|
-
# rubocop:disable Metrics/MethodLength
|
497
|
+
# rubocop:disable Metrics/AbcSize, Metrics/MethodLength
|
416
498
|
|
417
499
|
# Build an object to store runtime configuration options and set defaults
|
418
500
|
def initialize
|
@@ -424,6 +506,9 @@ module RSpec
|
|
424
506
|
@extend_modules = FilterableItemRepository::QueryOptimized.new(:any?)
|
425
507
|
@prepend_modules = FilterableItemRepository::QueryOptimized.new(:any?)
|
426
508
|
|
509
|
+
@bisect_runner = RSpec::Support::RubyFeatures.fork_supported? ? :fork : :shell
|
510
|
+
@bisect_runner_class = nil
|
511
|
+
|
427
512
|
@before_suite_hooks = []
|
428
513
|
@after_suite_hooks = []
|
429
514
|
|
@@ -467,8 +552,7 @@ module RSpec
|
|
467
552
|
|
468
553
|
define_built_in_hooks
|
469
554
|
end
|
470
|
-
# rubocop:enable Metrics/MethodLength
|
471
|
-
# rubocop:enable Metrics/AbcSize
|
555
|
+
# rubocop:enable Metrics/MethodLength, Metrics/AbcSize
|
472
556
|
|
473
557
|
# @private
|
474
558
|
#
|
@@ -549,6 +633,7 @@ module RSpec
|
|
549
633
|
end
|
550
634
|
|
551
635
|
# Returns the configured mock framework adapter module.
|
636
|
+
# @return [Symbol]
|
552
637
|
def mock_framework
|
553
638
|
if @mock_framework.nil?
|
554
639
|
begin
|
@@ -576,12 +661,13 @@ module RSpec
|
|
576
661
|
# To override this behaviour and display a full backtrace, use
|
577
662
|
# `--backtrace` on the command line, in a `.rspec` file, or in the
|
578
663
|
# `rspec_options` attribute of RSpec's rake task.
|
664
|
+
# @return [Array<Regexp>]
|
579
665
|
def backtrace_exclusion_patterns
|
580
666
|
@backtrace_formatter.exclusion_patterns
|
581
667
|
end
|
582
668
|
|
583
669
|
# Set regular expressions used to exclude lines in backtrace.
|
584
|
-
# @param patterns [Regexp] set
|
670
|
+
# @param patterns [Array<Regexp>] set backtrace_formatter exlusion_patterns
|
585
671
|
def backtrace_exclusion_patterns=(patterns)
|
586
672
|
@backtrace_formatter.exclusion_patterns = patterns
|
587
673
|
end
|
@@ -594,12 +680,13 @@ module RSpec
|
|
594
680
|
# will be included.
|
595
681
|
#
|
596
682
|
# You can modify the list via the getter, or replace it with the setter.
|
683
|
+
# @return [Array<Regexp>]
|
597
684
|
def backtrace_inclusion_patterns
|
598
685
|
@backtrace_formatter.inclusion_patterns
|
599
686
|
end
|
600
687
|
|
601
688
|
# Set regular expressions used to include lines in backtrace.
|
602
|
-
# @attr patterns [Regexp] set backtrace_formatter inclusion_patterns
|
689
|
+
# @attr patterns [Array<Regexp>] set backtrace_formatter inclusion_patterns
|
603
690
|
def backtrace_inclusion_patterns=(patterns)
|
604
691
|
@backtrace_formatter.inclusion_patterns = patterns
|
605
692
|
end
|
@@ -862,11 +949,11 @@ module RSpec
|
|
862
949
|
# @overload add_formatter(formatter)
|
863
950
|
# @overload add_formatter(formatter, output)
|
864
951
|
#
|
865
|
-
# @param formatter [Class, String] formatter to use. Can be any of the
|
952
|
+
# @param formatter [Class, String, Object] formatter to use. Can be any of the
|
866
953
|
# string values supported from the CLI (`p`/`progress`,
|
867
|
-
# `d`/`doc`/`documentation`, `h`/`html`, or `j`/`json`)
|
954
|
+
# `d`/`doc`/`documentation`, `h`/`html`, or `j`/`json`), any
|
868
955
|
# class that implements the formatter protocol and has registered
|
869
|
-
# itself with RSpec as a formatter.
|
956
|
+
# itself with RSpec as a formatter, or a formatter instance.
|
870
957
|
# @param output [String, IO] where the formatter will write its output.
|
871
958
|
# Can be an IO object or a string path to a file. If not provided,
|
872
959
|
# the configured `output_stream` (`$stdout`, by default) will be used.
|
@@ -1042,7 +1129,7 @@ module RSpec
|
|
1042
1129
|
#
|
1043
1130
|
# # This lets you do this:
|
1044
1131
|
#
|
1045
|
-
# describe Thing do
|
1132
|
+
# RSpec.describe Thing do
|
1046
1133
|
# pending "does something" do
|
1047
1134
|
# thing = Thing.new
|
1048
1135
|
# end
|
@@ -1050,7 +1137,7 @@ module RSpec
|
|
1050
1137
|
#
|
1051
1138
|
# # ... which is the equivalent of
|
1052
1139
|
#
|
1053
|
-
# describe Thing do
|
1140
|
+
# RSpec.describe Thing do
|
1054
1141
|
# it "does something", :pending => true do
|
1055
1142
|
# thing = Thing.new
|
1056
1143
|
# end
|
@@ -1103,7 +1190,7 @@ module RSpec
|
|
1103
1190
|
#
|
1104
1191
|
# # allows the user to include a shared example group like:
|
1105
1192
|
#
|
1106
|
-
# describe Entity do
|
1193
|
+
# RSpec.describe Entity do
|
1107
1194
|
# it_has_behavior 'sortability' do
|
1108
1195
|
# let(:sortable) { Entity.new }
|
1109
1196
|
# end
|
@@ -1452,7 +1539,7 @@ module RSpec
|
|
1452
1539
|
def requires=(paths)
|
1453
1540
|
directories = ['lib', default_path].select { |p| File.directory? p }
|
1454
1541
|
RSpec::Core::RubyProject.add_to_load_path(*directories)
|
1455
|
-
paths.each { |path| require path }
|
1542
|
+
paths.each { |path| load_file_handling_errors(:require, path) }
|
1456
1543
|
@requires += paths
|
1457
1544
|
end
|
1458
1545
|
|
@@ -1493,7 +1580,7 @@ module RSpec
|
|
1493
1580
|
|
1494
1581
|
files_to_run.uniq.each do |f|
|
1495
1582
|
file = File.expand_path(f)
|
1496
|
-
|
1583
|
+
load_file_handling_errors(:load, file)
|
1497
1584
|
loaded_spec_files << file
|
1498
1585
|
end
|
1499
1586
|
|
@@ -1521,8 +1608,6 @@ module RSpec
|
|
1521
1608
|
end
|
1522
1609
|
|
1523
1610
|
# @private
|
1524
|
-
# @macro [attach] delegate_to_ordering_manager
|
1525
|
-
# @!method $1
|
1526
1611
|
def self.delegate_to_ordering_manager(*methods)
|
1527
1612
|
methods.each do |method|
|
1528
1613
|
define_method method do |*args, &block|
|
@@ -1531,12 +1616,12 @@ module RSpec
|
|
1531
1616
|
end
|
1532
1617
|
end
|
1533
1618
|
|
1534
|
-
#
|
1619
|
+
# @!method seed=(value)
|
1535
1620
|
#
|
1536
1621
|
# Sets the seed value and sets the default global ordering to random.
|
1537
1622
|
delegate_to_ordering_manager :seed=
|
1538
1623
|
|
1539
|
-
#
|
1624
|
+
# @!method seed
|
1540
1625
|
# Seed for random ordering (default: generated randomly each run).
|
1541
1626
|
#
|
1542
1627
|
# When you run specs with `--order random`, RSpec generates a random seed
|
@@ -1550,7 +1635,7 @@ module RSpec
|
|
1550
1635
|
# don't accidentally leave the seed encoded.
|
1551
1636
|
delegate_to_ordering_manager :seed
|
1552
1637
|
|
1553
|
-
#
|
1638
|
+
# @!method order=(value)
|
1554
1639
|
#
|
1555
1640
|
# Sets the default global ordering strategy. By default this can be one
|
1556
1641
|
# of `:defined`, `:random`, but is customizable through the
|
@@ -1560,7 +1645,8 @@ module RSpec
|
|
1560
1645
|
# @see #register_ordering
|
1561
1646
|
delegate_to_ordering_manager :order=
|
1562
1647
|
|
1563
|
-
#
|
1648
|
+
# @!method register_ordering(name)
|
1649
|
+
#
|
1564
1650
|
# Registers a named ordering strategy that can later be
|
1565
1651
|
# used to order an example group's subgroups by adding
|
1566
1652
|
# `:order => <name>` metadata to the example group.
|
@@ -1655,7 +1741,7 @@ module RSpec
|
|
1655
1741
|
# rspec.expose_current_running_example_as :example
|
1656
1742
|
# end
|
1657
1743
|
#
|
1658
|
-
# describe MyClass do
|
1744
|
+
# RSpec.describe MyClass do
|
1659
1745
|
# before do
|
1660
1746
|
# # `example` can be used here because of the above config.
|
1661
1747
|
# do_something if example.metadata[:type] == "foo"
|
@@ -1773,7 +1859,7 @@ module RSpec
|
|
1773
1859
|
# require 'support/db'
|
1774
1860
|
# end
|
1775
1861
|
# end
|
1776
|
-
def when_first_matching_example_defined(*filters
|
1862
|
+
def when_first_matching_example_defined(*filters)
|
1777
1863
|
specified_meta = Metadata.build_hash_from(filters, :warn_about_example_group_filtering)
|
1778
1864
|
|
1779
1865
|
callback = lambda do |example_or_group_meta|
|
@@ -1784,7 +1870,7 @@ module RSpec
|
|
1784
1870
|
# Ensure the callback only fires once.
|
1785
1871
|
@derived_metadata_blocks.delete(callback, specified_meta)
|
1786
1872
|
|
1787
|
-
|
1873
|
+
yield
|
1788
1874
|
end
|
1789
1875
|
|
1790
1876
|
@derived_metadata_blocks.append(callback, specified_meta)
|
@@ -1792,9 +1878,28 @@ module RSpec
|
|
1792
1878
|
|
1793
1879
|
# @private
|
1794
1880
|
def apply_derived_metadata_to(metadata)
|
1795
|
-
|
1796
|
-
|
1881
|
+
already_run_blocks = Set.new
|
1882
|
+
|
1883
|
+
# We loop and attempt to re-apply metadata blocks to support cascades
|
1884
|
+
# (e.g. where a derived bit of metadata triggers the application of
|
1885
|
+
# another piece of derived metadata, etc)
|
1886
|
+
#
|
1887
|
+
# We limit our looping to 200 times as a way to detect infinitely recursing derived metadata blocks.
|
1888
|
+
# It's hard to imagine a valid use case for a derived metadata cascade greater than 200 iterations.
|
1889
|
+
200.times do
|
1890
|
+
return if @derived_metadata_blocks.items_for(metadata).all? do |block|
|
1891
|
+
already_run_blocks.include?(block).tap do |skip_block|
|
1892
|
+
block.call(metadata) unless skip_block
|
1893
|
+
already_run_blocks << block
|
1894
|
+
end
|
1895
|
+
end
|
1797
1896
|
end
|
1897
|
+
|
1898
|
+
# If we got here, then `@derived_metadata_blocks.items_for(metadata).all?` never returned
|
1899
|
+
# `true` above and we treat this as an attempt to recurse infinitely. It's better to fail
|
1900
|
+
# with a clear # error than hang indefinitely, which is what would happen if we didn't limit
|
1901
|
+
# the looping above.
|
1902
|
+
raise SystemStackError, "Attempted to recursively derive metadata indefinitely."
|
1798
1903
|
end
|
1799
1904
|
|
1800
1905
|
# Defines a `before` hook. See {Hooks#before} for full docs.
|
@@ -1810,6 +1915,12 @@ module RSpec
|
|
1810
1915
|
handle_suite_hook(scope, meta) do
|
1811
1916
|
@before_suite_hooks << Hooks::BeforeHook.new(block, {})
|
1812
1917
|
end || begin
|
1918
|
+
# defeat Ruby 2.5 lazy proc allocation to ensure
|
1919
|
+
# the methods below are passed the same proc instances
|
1920
|
+
# so `Hook` equality is preserved. For more info, see:
|
1921
|
+
# https://bugs.ruby-lang.org/issues/14045#note-5
|
1922
|
+
block.__id__
|
1923
|
+
|
1813
1924
|
add_hook_to_existing_matching_groups(meta, scope) { |g| g.before(scope, *meta, &block) }
|
1814
1925
|
super(scope, *meta, &block)
|
1815
1926
|
end
|
@@ -1833,6 +1944,12 @@ module RSpec
|
|
1833
1944
|
handle_suite_hook(scope, meta) do
|
1834
1945
|
@before_suite_hooks.unshift Hooks::BeforeHook.new(block, {})
|
1835
1946
|
end || begin
|
1947
|
+
# defeat Ruby 2.5 lazy proc allocation to ensure
|
1948
|
+
# the methods below are passed the same proc instances
|
1949
|
+
# so `Hook` equality is preserved. For more info, see:
|
1950
|
+
# https://bugs.ruby-lang.org/issues/14045#note-5
|
1951
|
+
block.__id__
|
1952
|
+
|
1836
1953
|
add_hook_to_existing_matching_groups(meta, scope) { |g| g.prepend_before(scope, *meta, &block) }
|
1837
1954
|
super(scope, *meta, &block)
|
1838
1955
|
end
|
@@ -1851,6 +1968,12 @@ module RSpec
|
|
1851
1968
|
handle_suite_hook(scope, meta) do
|
1852
1969
|
@after_suite_hooks.unshift Hooks::AfterHook.new(block, {})
|
1853
1970
|
end || begin
|
1971
|
+
# defeat Ruby 2.5 lazy proc allocation to ensure
|
1972
|
+
# the methods below are passed the same proc instances
|
1973
|
+
# so `Hook` equality is preserved. For more info, see:
|
1974
|
+
# https://bugs.ruby-lang.org/issues/14045#note-5
|
1975
|
+
block.__id__
|
1976
|
+
|
1854
1977
|
add_hook_to_existing_matching_groups(meta, scope) { |g| g.after(scope, *meta, &block) }
|
1855
1978
|
super(scope, *meta, &block)
|
1856
1979
|
end
|
@@ -1874,6 +1997,12 @@ module RSpec
|
|
1874
1997
|
handle_suite_hook(scope, meta) do
|
1875
1998
|
@after_suite_hooks << Hooks::AfterHook.new(block, {})
|
1876
1999
|
end || begin
|
2000
|
+
# defeat Ruby 2.5 lazy proc allocation to ensure
|
2001
|
+
# the methods below are passed the same proc instances
|
2002
|
+
# so `Hook` equality is preserved. For more info, see:
|
2003
|
+
# https://bugs.ruby-lang.org/issues/14045#note-5
|
2004
|
+
block.__id__
|
2005
|
+
|
1877
2006
|
add_hook_to_existing_matching_groups(meta, scope) { |g| g.append_after(scope, *meta, &block) }
|
1878
2007
|
super(scope, *meta, &block)
|
1879
2008
|
end
|
@@ -1883,6 +2012,12 @@ module RSpec
|
|
1883
2012
|
#
|
1884
2013
|
# See {Hooks#around} for full `around` hook docs.
|
1885
2014
|
def around(scope=nil, *meta, &block)
|
2015
|
+
# defeat Ruby 2.5 lazy proc allocation to ensure
|
2016
|
+
# the methods below are passed the same proc instances
|
2017
|
+
# so `Hook` equality is preserved. For more info, see:
|
2018
|
+
# https://bugs.ruby-lang.org/issues/14045#note-5
|
2019
|
+
block.__id__
|
2020
|
+
|
1886
2021
|
add_hook_to_existing_matching_groups(meta, scope) { |g| g.around(scope, *meta, &block) }
|
1887
2022
|
super(scope, *meta, &block)
|
1888
2023
|
end
|
@@ -1918,10 +2053,32 @@ module RSpec
|
|
1918
2053
|
@on_example_group_definition_callbacks ||= []
|
1919
2054
|
end
|
1920
2055
|
|
2056
|
+
# @private
|
2057
|
+
def bisect_runner_class
|
2058
|
+
@bisect_runner_class ||= begin
|
2059
|
+
case bisect_runner
|
2060
|
+
when :fork
|
2061
|
+
RSpec::Support.require_rspec_core 'bisect/fork_runner'
|
2062
|
+
Bisect::ForkRunner
|
2063
|
+
when :shell
|
2064
|
+
RSpec::Support.require_rspec_core 'bisect/shell_runner'
|
2065
|
+
Bisect::ShellRunner
|
2066
|
+
else
|
2067
|
+
raise "Unsupported value for `bisect_runner` (#{bisect_runner.inspect}). " \
|
2068
|
+
"Only `:fork` and `:shell` are supported."
|
2069
|
+
end
|
2070
|
+
end
|
2071
|
+
end
|
2072
|
+
|
1921
2073
|
private
|
1922
2074
|
|
1923
|
-
def
|
1924
|
-
|
2075
|
+
def load_file_handling_errors(method, file)
|
2076
|
+
__send__(method, file)
|
2077
|
+
rescue LoadError => ex
|
2078
|
+
relative_file = Metadata.relative_path(file)
|
2079
|
+
suggestions = DidYouMean.new(relative_file).call
|
2080
|
+
reporter.notify_non_example_exception(ex, "An error occurred while loading #{relative_file}.#{suggestions}")
|
2081
|
+
RSpec.world.wants_to_quit = true
|
1925
2082
|
rescue Support::AllExceptionsExceptOnesWeMustNotRescue => ex
|
1926
2083
|
relative_file = Metadata.relative_path(file)
|
1927
2084
|
reporter.notify_non_example_exception(ex, "An error occurred while loading #{relative_file}.")
|