rspec-core 3.5.4 → 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 +165 -2
- data/README.md +16 -16
- data/lib/rspec/core.rb +2 -1
- 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 +10 -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 +315 -79
- data/lib/rspec/core/configuration_options.rb +43 -4
- data/lib/rspec/core/did_you_mean.rb +46 -0
- data/lib/rspec/core/drb.rb +3 -1
- data/lib/rspec/core/example.rb +19 -12
- data/lib/rspec/core/example_group.rb +17 -7
- data/lib/rspec/core/formatters.rb +28 -11
- data/lib/rspec/core/formatters/base_bisect_formatter.rb +45 -0
- data/lib/rspec/core/formatters/base_formatter.rb +1 -1
- data/lib/rspec/core/formatters/base_text_formatter.rb +3 -5
- 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/console_codes.rb +7 -4
- data/lib/rspec/core/formatters/deprecation_formatter.rb +9 -9
- data/lib/rspec/core/formatters/documentation_formatter.rb +37 -4
- data/lib/rspec/core/formatters/exception_presenter.rb +21 -4
- data/lib/rspec/core/formatters/failure_list_formatter.rb +23 -0
- data/lib/rspec/core/formatters/html_formatter.rb +4 -2
- data/lib/rspec/core/formatters/html_printer.rb +3 -3
- data/lib/rspec/core/formatters/html_snippet_extractor.rb +4 -0
- data/lib/rspec/core/formatters/json_formatter.rb +9 -3
- data/lib/rspec/core/formatters/progress_formatter.rb +1 -0
- data/lib/rspec/core/formatters/protocol.rb +43 -42
- data/lib/rspec/core/formatters/snippet_extractor.rb +1 -3
- data/lib/rspec/core/{source → formatters}/syntax_highlighter.rb +21 -1
- data/lib/rspec/core/hooks.rb +18 -10
- data/lib/rspec/core/invocations.rb +30 -10
- data/lib/rspec/core/memoized_helpers.rb +36 -14
- data/lib/rspec/core/metadata.rb +2 -3
- data/lib/rspec/core/metadata_filter.rb +29 -17
- data/lib/rspec/core/notifications.rb +34 -11
- data/lib/rspec/core/option_parser.rb +32 -4
- data/lib/rspec/core/output_wrapper.rb +29 -0
- data/lib/rspec/core/profiler.rb +3 -1
- data/lib/rspec/core/project_initializer/.rspec +0 -1
- data/lib/rspec/core/project_initializer/spec/spec_helper.rb +1 -4
- data/lib/rspec/core/rake_task.rb +21 -1
- data/lib/rspec/core/reporter.rb +33 -16
- data/lib/rspec/core/runner.rb +31 -15
- data/lib/rspec/core/set.rb +5 -0
- data/lib/rspec/core/shared_example_group.rb +41 -19
- data/lib/rspec/core/shell_escape.rb +2 -2
- data/lib/rspec/core/version.rb +1 -1
- data/lib/rspec/core/world.rb +24 -5
- metadata +26 -20
- metadata.gz.sig +0 -0
- data/lib/rspec/core/formatters/bisect_formatter.rb +0 -69
- data/lib/rspec/core/source.rb +0 -86
- data/lib/rspec/core/source/location.rb +0 -13
- data/lib/rspec/core/source/node.rb +0 -93
- data/lib/rspec/core/source/token.rb +0 -87
@@ -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.
|
@@ -25,12 +23,17 @@ module RSpec
|
|
25
23
|
self.files_or_directories_to_run = files_or_directories_to_run
|
26
24
|
self.latest_run_results = nil
|
27
25
|
run_output = yield
|
28
|
-
|
26
|
+
|
27
|
+
if latest_run_results.nil? || latest_run_results.all_example_ids.empty?
|
28
|
+
raise BisectFailedError.for_failed_spec_run(run_output)
|
29
|
+
end
|
30
|
+
|
31
|
+
latest_run_results
|
29
32
|
end
|
30
33
|
|
31
34
|
def start
|
32
35
|
# Only allow remote DRb requests from this machine.
|
33
|
-
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 ])
|
34
37
|
|
35
38
|
# We pass `nil` as the first arg to allow it to pick a DRb port.
|
36
39
|
@drb = DRb.start_service(nil, self)
|
@@ -44,21 +47,14 @@ module RSpec
|
|
44
47
|
@drb_port ||= Integer(@drb.uri[/\d+$/])
|
45
48
|
end
|
46
49
|
|
47
|
-
# Fetched via DRb by the
|
50
|
+
# Fetched via DRb by the BisectDRbFormatter to determine when to abort.
|
48
51
|
attr_accessor :expected_failures
|
49
52
|
|
50
|
-
# Set via DRb by the
|
53
|
+
# Set via DRb by the BisectDRbFormatter with the results of the run.
|
51
54
|
attr_accessor :latest_run_results
|
52
55
|
|
53
56
|
# Fetched via DRb to tell clients which files to run
|
54
57
|
attr_accessor :files_or_directories_to_run
|
55
|
-
|
56
|
-
private
|
57
|
-
|
58
|
-
def raise_bisect_failed(run_output)
|
59
|
-
raise BisectFailedError, "Failed to get results from the spec " \
|
60
|
-
"run. Spec run output:\n\n#{run_output}"
|
61
|
-
end
|
62
58
|
end
|
63
59
|
end
|
64
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
|
@@ -1,6 +1,7 @@
|
|
1
1
|
RSpec::Support.require_rspec_core "backtrace_formatter"
|
2
2
|
RSpec::Support.require_rspec_core "ruby_project"
|
3
3
|
RSpec::Support.require_rspec_core "formatters/deprecation_formatter"
|
4
|
+
RSpec::Support.require_rspec_core "output_wrapper"
|
4
5
|
|
5
6
|
module RSpec
|
6
7
|
module Core
|
@@ -8,10 +9,24 @@ module RSpec
|
|
8
9
|
|
9
10
|
# Stores runtime configuration information.
|
10
11
|
#
|
11
|
-
# Configuration options are loaded from
|
12
|
-
#
|
13
|
-
#
|
14
|
-
#
|
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.
|
15
30
|
#
|
16
31
|
# @example Standard settings
|
17
32
|
# RSpec.configure do |c|
|
@@ -88,7 +103,6 @@ module RSpec
|
|
88
103
|
|
89
104
|
# @macro [attach] add_setting
|
90
105
|
# @!attribute [rw] $1
|
91
|
-
# @!method $1=(value)
|
92
106
|
#
|
93
107
|
# @macro [attach] define_reader
|
94
108
|
# @!attribute [r] $1
|
@@ -100,6 +114,7 @@ module RSpec
|
|
100
114
|
#
|
101
115
|
# @note Other scripts invoking `rspec` indirectly will ignore this
|
102
116
|
# setting.
|
117
|
+
# @return [String]
|
103
118
|
add_read_only_setting :default_path
|
104
119
|
def default_path=(path)
|
105
120
|
project_source_dirs << path
|
@@ -109,6 +124,7 @@ module RSpec
|
|
109
124
|
# @macro add_setting
|
110
125
|
# Run examples over DRb (default: `false`). RSpec doesn't supply the DRb
|
111
126
|
# server, but you can use tools like spork.
|
127
|
+
# @return [Boolean]
|
112
128
|
add_setting :drb
|
113
129
|
|
114
130
|
# @macro add_setting
|
@@ -121,6 +137,7 @@ module RSpec
|
|
121
137
|
|
122
138
|
# Indicates if the DSL has been exposed off of modules and `main`.
|
123
139
|
# Default: true
|
140
|
+
# @return [Boolean]
|
124
141
|
def expose_dsl_globally?
|
125
142
|
Core::DSL.exposed_globally?
|
126
143
|
end
|
@@ -141,7 +158,7 @@ module RSpec
|
|
141
158
|
|
142
159
|
# Determines where deprecation warnings are printed.
|
143
160
|
# Defaults to `$stderr`.
|
144
|
-
# @return [IO, String] IO
|
161
|
+
# @return [IO, String] IO or filename to write to
|
145
162
|
define_reader :deprecation_stream
|
146
163
|
|
147
164
|
# Determines where deprecation warnings are printed.
|
@@ -160,7 +177,7 @@ module RSpec
|
|
160
177
|
|
161
178
|
# @macro define_reader
|
162
179
|
# The file path to use for persisting example statuses. Necessary for the
|
163
|
-
# `--only-failures` and `--next-
|
180
|
+
# `--only-failures` and `--next-failure` CLI options.
|
164
181
|
#
|
165
182
|
# @overload example_status_persistence_file_path
|
166
183
|
# @return [String] the file path
|
@@ -169,7 +186,7 @@ module RSpec
|
|
169
186
|
define_reader :example_status_persistence_file_path
|
170
187
|
|
171
188
|
# Sets the file path to use for persisting example statuses. Necessary for the
|
172
|
-
# `--only-failures` and `--next-
|
189
|
+
# `--only-failures` and `--next-failure` CLI options.
|
173
190
|
def example_status_persistence_file_path=(value)
|
174
191
|
@example_status_persistence_file_path = value
|
175
192
|
clear_values_derived_from_example_status_persistence_file_path
|
@@ -185,10 +202,33 @@ module RSpec
|
|
185
202
|
only_failures? && !example_status_persistence_file_path
|
186
203
|
end
|
187
204
|
|
188
|
-
# @macro
|
205
|
+
# @macro define_reader
|
189
206
|
# If specified, indicates the number of failures required before cleaning
|
190
|
-
# up and exit (default: `nil`).
|
191
|
-
|
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
|
192
232
|
|
193
233
|
# @macro add_setting
|
194
234
|
# Prints the formatter output of your suite without running any
|
@@ -197,24 +237,33 @@ module RSpec
|
|
197
237
|
|
198
238
|
# @macro add_setting
|
199
239
|
# The exit code to return if there are any failures (default: 1).
|
240
|
+
# @return [Integer]
|
200
241
|
add_setting :failure_exit_code
|
201
242
|
|
243
|
+
# @macro add_setting
|
244
|
+
# Whether or not to fail when there are no RSpec examples (default: false).
|
245
|
+
# @return [Boolean]
|
246
|
+
add_setting :fail_if_no_examples
|
247
|
+
|
202
248
|
# @macro define_reader
|
203
249
|
# Indicates files configured to be required.
|
250
|
+
# @return [Array<String>]
|
204
251
|
define_reader :requires
|
205
252
|
|
206
253
|
# @macro define_reader
|
207
254
|
# Returns dirs that have been prepended to the load path by the `-I`
|
208
255
|
# command line option.
|
256
|
+
# @return [Array<String>]
|
209
257
|
define_reader :libs
|
210
258
|
|
211
259
|
# @macro add_setting
|
212
260
|
# Determines where RSpec will send its output.
|
213
261
|
# Default: `$stdout`.
|
262
|
+
# @return [IO, String]
|
214
263
|
define_reader :output_stream
|
215
264
|
|
216
265
|
# Set the output stream for reporter.
|
217
|
-
# @attr value [IO]
|
266
|
+
# @attr value [IO, String] IO to write to or filename to write to, defaults to $stdout
|
218
267
|
def output_stream=(value)
|
219
268
|
if @reporter && !value.equal?(@output_stream)
|
220
269
|
warn "RSpec's reporter has already been initialized with " \
|
@@ -223,11 +272,13 @@ module RSpec
|
|
223
272
|
"it to take effect. (Called from #{CallerFilter.first_non_rspec_line})"
|
224
273
|
else
|
225
274
|
@output_stream = value
|
275
|
+
output_wrapper.output = @output_stream
|
226
276
|
end
|
227
277
|
end
|
228
278
|
|
229
279
|
# @macro define_reader
|
230
280
|
# Load files matching this pattern (default: `'**{,/*/**}/*_spec.rb'`).
|
281
|
+
# @return [String]
|
231
282
|
define_reader :pattern
|
232
283
|
|
233
284
|
# Set pattern to match files to load.
|
@@ -238,6 +289,7 @@ module RSpec
|
|
238
289
|
|
239
290
|
# @macro define_reader
|
240
291
|
# Exclude files matching this pattern.
|
292
|
+
# @return [String]
|
241
293
|
define_reader :exclude_pattern
|
242
294
|
|
243
295
|
# Set pattern to match files to exclude.
|
@@ -259,6 +311,7 @@ module RSpec
|
|
259
311
|
# @macro add_setting
|
260
312
|
# Report the times for the slowest examples (default: `false`).
|
261
313
|
# Use this to specify the number of examples to include in the profile.
|
314
|
+
# @return [Boolean]
|
262
315
|
add_setting :profile_examples
|
263
316
|
|
264
317
|
# @macro add_setting
|
@@ -269,55 +322,56 @@ module RSpec
|
|
269
322
|
add_setting :run_all_when_everything_filtered
|
270
323
|
|
271
324
|
# @macro add_setting
|
272
|
-
# Color to use to indicate success.
|
273
|
-
#
|
274
|
-
#
|
275
|
-
#
|
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]
|
276
329
|
add_setting :success_color
|
277
330
|
|
278
331
|
# @macro add_setting
|
279
|
-
# Color to use to print pending examples.
|
280
|
-
#
|
281
|
-
#
|
282
|
-
#
|
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]
|
283
336
|
add_setting :pending_color
|
284
337
|
|
285
338
|
# @macro add_setting
|
286
|
-
# Color to use to indicate failure.
|
287
|
-
#
|
288
|
-
#
|
289
|
-
#
|
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]
|
290
343
|
add_setting :failure_color
|
291
344
|
|
292
345
|
# @macro add_setting
|
293
|
-
# The default output color.
|
294
|
-
#
|
295
|
-
#
|
296
|
-
#
|
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]
|
297
350
|
add_setting :default_color
|
298
351
|
|
299
352
|
# @macro add_setting
|
300
|
-
# Color used when a pending example is fixed.
|
301
|
-
#
|
302
|
-
#
|
303
|
-
#
|
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]
|
304
357
|
add_setting :fixed_color
|
305
358
|
|
306
359
|
# @macro add_setting
|
307
|
-
# Color used to print details.
|
308
|
-
#
|
309
|
-
#
|
310
|
-
#
|
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]
|
311
364
|
add_setting :detail_color
|
312
365
|
|
313
366
|
# @macro add_setting
|
314
367
|
# Don't print filter info i.e. "Run options: include {:focus=>true}"
|
315
368
|
# (default `false`).
|
369
|
+
# return [Boolean]
|
316
370
|
add_setting :silence_filter_announcements
|
317
371
|
|
318
|
-
#
|
319
|
-
#
|
320
|
-
#
|
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.
|
321
375
|
def treat_symbols_as_metadata_keys_with_true_values=(_value)
|
322
376
|
RSpec.deprecate(
|
323
377
|
"RSpec::Core::Configuration#treat_symbols_as_metadata_keys_with_true_values=",
|
@@ -381,19 +435,55 @@ module RSpec
|
|
381
435
|
end
|
382
436
|
|
383
437
|
# Record the start time of the spec suite to measure load time.
|
438
|
+
# return [Time]
|
384
439
|
add_setting :start_time
|
385
440
|
|
386
441
|
# @macro add_setting
|
387
442
|
# Use threadsafe options where available.
|
388
443
|
# Currently this will place a mutex around memoized values such as let blocks.
|
444
|
+
# return [Boolean]
|
389
445
|
add_setting :threadsafe
|
390
446
|
|
391
447
|
# @macro add_setting
|
392
448
|
# Maximum count of failed source lines to display in the failure reports.
|
393
449
|
# (default `10`).
|
450
|
+
# return [Integer]
|
394
451
|
add_setting :max_displayed_failure_line_count
|
395
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
|
+
|
396
485
|
# @private
|
486
|
+
# @deprecated Use {#color_mode} = :on, instead of {#color} with {#tty}
|
397
487
|
add_setting :tty
|
398
488
|
# @private
|
399
489
|
attr_writer :files_to_run
|
@@ -404,8 +494,9 @@ module RSpec
|
|
404
494
|
# @private
|
405
495
|
attr_reader :backtrace_formatter, :ordering_manager, :loaded_spec_files
|
406
496
|
|
407
|
-
# rubocop:disable Metrics/AbcSize
|
408
|
-
|
497
|
+
# rubocop:disable Metrics/AbcSize, Metrics/MethodLength
|
498
|
+
|
499
|
+
# Build an object to store runtime configuration options and set defaults
|
409
500
|
def initialize
|
410
501
|
# rubocop:disable Style/GlobalVars
|
411
502
|
@start_time = $_rspec_core_load_started_at || ::RSpec::Core::Time.now
|
@@ -415,6 +506,9 @@ module RSpec
|
|
415
506
|
@extend_modules = FilterableItemRepository::QueryOptimized.new(:any?)
|
416
507
|
@prepend_modules = FilterableItemRepository::QueryOptimized.new(:any?)
|
417
508
|
|
509
|
+
@bisect_runner = RSpec::Support::RubyFeatures.fork_supported? ? :fork : :shell
|
510
|
+
@bisect_runner_class = nil
|
511
|
+
|
418
512
|
@before_suite_hooks = []
|
419
513
|
@after_suite_hooks = []
|
420
514
|
|
@@ -422,9 +516,11 @@ module RSpec
|
|
422
516
|
@files_or_directories_to_run = []
|
423
517
|
@loaded_spec_files = Set.new
|
424
518
|
@color = false
|
519
|
+
@color_mode = :automatic
|
425
520
|
@pattern = '**{,/*/**}/*_spec.rb'
|
426
521
|
@exclude_pattern = ''
|
427
522
|
@failure_exit_code = 1
|
523
|
+
@fail_if_no_examples = false
|
428
524
|
@spec_files_loaded = false
|
429
525
|
|
430
526
|
@backtrace_formatter = BacktraceFormatter.new
|
@@ -456,8 +552,7 @@ module RSpec
|
|
456
552
|
|
457
553
|
define_built_in_hooks
|
458
554
|
end
|
459
|
-
# rubocop:enable Metrics/MethodLength
|
460
|
-
# rubocop:enable Metrics/AbcSize
|
555
|
+
# rubocop:enable Metrics/MethodLength, Metrics/AbcSize
|
461
556
|
|
462
557
|
# @private
|
463
558
|
#
|
@@ -473,8 +568,14 @@ module RSpec
|
|
473
568
|
# @private
|
474
569
|
def reset
|
475
570
|
@spec_files_loaded = false
|
571
|
+
reset_reporter
|
572
|
+
end
|
573
|
+
|
574
|
+
# @private
|
575
|
+
def reset_reporter
|
476
576
|
@reporter = nil
|
477
577
|
@formatter_loader = nil
|
578
|
+
@output_wrapper = nil
|
478
579
|
end
|
479
580
|
|
480
581
|
# @private
|
@@ -532,6 +633,7 @@ module RSpec
|
|
532
633
|
end
|
533
634
|
|
534
635
|
# Returns the configured mock framework adapter module.
|
636
|
+
# @return [Symbol]
|
535
637
|
def mock_framework
|
536
638
|
if @mock_framework.nil?
|
537
639
|
begin
|
@@ -559,12 +661,13 @@ module RSpec
|
|
559
661
|
# To override this behaviour and display a full backtrace, use
|
560
662
|
# `--backtrace` on the command line, in a `.rspec` file, or in the
|
561
663
|
# `rspec_options` attribute of RSpec's rake task.
|
664
|
+
# @return [Array<Regexp>]
|
562
665
|
def backtrace_exclusion_patterns
|
563
666
|
@backtrace_formatter.exclusion_patterns
|
564
667
|
end
|
565
668
|
|
566
669
|
# Set regular expressions used to exclude lines in backtrace.
|
567
|
-
# @param patterns [Regexp] set
|
670
|
+
# @param patterns [Array<Regexp>] set backtrace_formatter exlusion_patterns
|
568
671
|
def backtrace_exclusion_patterns=(patterns)
|
569
672
|
@backtrace_formatter.exclusion_patterns = patterns
|
570
673
|
end
|
@@ -577,12 +680,13 @@ module RSpec
|
|
577
680
|
# will be included.
|
578
681
|
#
|
579
682
|
# You can modify the list via the getter, or replace it with the setter.
|
683
|
+
# @return [Array<Regexp>]
|
580
684
|
def backtrace_inclusion_patterns
|
581
685
|
@backtrace_formatter.inclusion_patterns
|
582
686
|
end
|
583
687
|
|
584
688
|
# Set regular expressions used to include lines in backtrace.
|
585
|
-
# @attr patterns [Regexp] set backtrace_formatter inclusion_patterns
|
689
|
+
# @attr patterns [Array<Regexp>] set backtrace_formatter inclusion_patterns
|
586
690
|
def backtrace_inclusion_patterns=(patterns)
|
587
691
|
@backtrace_formatter.inclusion_patterns = patterns
|
588
692
|
end
|
@@ -773,24 +877,54 @@ module RSpec
|
|
773
877
|
@backtrace_formatter.full_backtrace = true_or_false
|
774
878
|
end
|
775
879
|
|
776
|
-
#
|
777
|
-
#
|
880
|
+
# Enables color output if the output is a TTY. As of RSpec 3.6, this is
|
881
|
+
# the default behavior and this option is retained only for backwards
|
882
|
+
# compatibility.
|
778
883
|
#
|
884
|
+
# @deprecated No longer recommended because of complex behavior. Instead,
|
885
|
+
# rely on the fact that TTYs will display color by default, or set
|
886
|
+
# {#color_mode} to :on to display color on a non-TTY output.
|
887
|
+
# @see color_mode
|
779
888
|
# @see color_enabled?
|
780
889
|
# @return [Boolean]
|
781
890
|
def color
|
782
891
|
value_for(:color) { @color }
|
783
892
|
end
|
784
893
|
|
894
|
+
# The mode for determining whether to display output in color. One of:
|
895
|
+
#
|
896
|
+
# - :automatic - the output will be in color if the output is a TTY (the
|
897
|
+
# default)
|
898
|
+
# - :on - the output will be in color, whether or not the output is a TTY
|
899
|
+
# - :off - the output will not be in color
|
900
|
+
#
|
901
|
+
# @see color_enabled?
|
902
|
+
# @return [Boolean]
|
903
|
+
def color_mode
|
904
|
+
value_for(:color_mode) { @color_mode }
|
905
|
+
end
|
906
|
+
|
785
907
|
# Check if color is enabled for a particular output.
|
786
908
|
# @param output [IO] an output stream to use, defaults to the current
|
787
909
|
# `output_stream`
|
788
910
|
# @return [Boolean]
|
789
911
|
def color_enabled?(output=output_stream)
|
790
|
-
|
912
|
+
case color_mode
|
913
|
+
when :on then true
|
914
|
+
when :off then false
|
915
|
+
else # automatic
|
916
|
+
output_to_tty?(output) || (color && tty?)
|
917
|
+
end
|
791
918
|
end
|
792
919
|
|
920
|
+
# Set the color mode.
|
921
|
+
attr_writer :color_mode
|
922
|
+
|
793
923
|
# Toggle output color.
|
924
|
+
#
|
925
|
+
# @deprecated No longer recommended because of complex behavior. Instead,
|
926
|
+
# rely on the fact that TTYs will display color by default, or set
|
927
|
+
# {:color_mode} to :on to display color on a non-TTY output.
|
794
928
|
attr_writer :color
|
795
929
|
|
796
930
|
# @private
|
@@ -813,19 +947,22 @@ module RSpec
|
|
813
947
|
end
|
814
948
|
|
815
949
|
# @overload add_formatter(formatter)
|
950
|
+
# @overload add_formatter(formatter, output)
|
816
951
|
#
|
817
|
-
#
|
818
|
-
#
|
819
|
-
# `
|
952
|
+
# @param formatter [Class, String, Object] formatter to use. Can be any of the
|
953
|
+
# string values supported from the CLI (`p`/`progress`,
|
954
|
+
# `d`/`doc`/`documentation`, `h`/`html`, or `j`/`json`), any
|
955
|
+
# class that implements the formatter protocol and has registered
|
956
|
+
# itself with RSpec as a formatter, or a formatter instance.
|
957
|
+
# @param output [String, IO] where the formatter will write its output.
|
958
|
+
# Can be an IO object or a string path to a file. If not provided,
|
959
|
+
# the configured `output_stream` (`$stdout`, by default) will be used.
|
820
960
|
#
|
821
|
-
#
|
961
|
+
# Adds a formatter to the set RSpec will use for this run.
|
822
962
|
#
|
823
|
-
#
|
824
|
-
|
825
|
-
|
826
|
-
def add_formatter(formatter_to_use, *paths)
|
827
|
-
paths << output_stream if paths.empty?
|
828
|
-
formatter_loader.add formatter_to_use, *paths
|
963
|
+
# @see RSpec::Core::Formatters::Protocol
|
964
|
+
def add_formatter(formatter, output=output_wrapper)
|
965
|
+
formatter_loader.add(formatter, output)
|
829
966
|
end
|
830
967
|
alias_method :formatter=, :add_formatter
|
831
968
|
|
@@ -890,7 +1027,7 @@ module RSpec
|
|
890
1027
|
@reporter_buffer || @reporter ||=
|
891
1028
|
begin
|
892
1029
|
@reporter_buffer = DeprecationReporterBuffer.new
|
893
|
-
formatter_loader.
|
1030
|
+
formatter_loader.prepare_default output_wrapper, deprecation_stream
|
894
1031
|
@reporter_buffer.play_onto(formatter_loader.reporter)
|
895
1032
|
@reporter_buffer = nil
|
896
1033
|
formatter_loader.reporter
|
@@ -934,7 +1071,9 @@ module RSpec
|
|
934
1071
|
if (path = example_status_persistence_file_path)
|
935
1072
|
begin
|
936
1073
|
ExampleStatusPersister.load_from(path).inject(statuses) do |hash, example|
|
937
|
-
|
1074
|
+
status = example[:status]
|
1075
|
+
status = UNKNOWN_STATUS unless VALID_STATUSES.include?(status)
|
1076
|
+
hash[example.fetch(:example_id)] = status
|
938
1077
|
hash
|
939
1078
|
end
|
940
1079
|
rescue SystemCallError => e
|
@@ -954,6 +1093,15 @@ module RSpec
|
|
954
1093
|
# @private
|
955
1094
|
FAILED_STATUS = "failed".freeze
|
956
1095
|
|
1096
|
+
# @private
|
1097
|
+
PASSED_STATUS = "passed".freeze
|
1098
|
+
|
1099
|
+
# @private
|
1100
|
+
PENDING_STATUS = "pending".freeze
|
1101
|
+
|
1102
|
+
# @private
|
1103
|
+
VALID_STATUSES = [UNKNOWN_STATUS, FAILED_STATUS, PASSED_STATUS, PENDING_STATUS]
|
1104
|
+
|
957
1105
|
# @private
|
958
1106
|
def spec_files_with_failures
|
959
1107
|
@spec_files_with_failures ||= last_run_statuses.inject(Set.new) do |files, (id, status)|
|
@@ -981,7 +1129,7 @@ module RSpec
|
|
981
1129
|
#
|
982
1130
|
# # This lets you do this:
|
983
1131
|
#
|
984
|
-
# describe Thing do
|
1132
|
+
# RSpec.describe Thing do
|
985
1133
|
# pending "does something" do
|
986
1134
|
# thing = Thing.new
|
987
1135
|
# end
|
@@ -989,7 +1137,7 @@ module RSpec
|
|
989
1137
|
#
|
990
1138
|
# # ... which is the equivalent of
|
991
1139
|
#
|
992
|
-
# describe Thing do
|
1140
|
+
# RSpec.describe Thing do
|
993
1141
|
# it "does something", :pending => true do
|
994
1142
|
# thing = Thing.new
|
995
1143
|
# end
|
@@ -1042,7 +1190,7 @@ module RSpec
|
|
1042
1190
|
#
|
1043
1191
|
# # allows the user to include a shared example group like:
|
1044
1192
|
#
|
1045
|
-
# describe Entity do
|
1193
|
+
# RSpec.describe Entity do
|
1046
1194
|
# it_has_behavior 'sortability' do
|
1047
1195
|
# let(:sortable) { Entity.new }
|
1048
1196
|
# end
|
@@ -1391,7 +1539,7 @@ module RSpec
|
|
1391
1539
|
def requires=(paths)
|
1392
1540
|
directories = ['lib', default_path].select { |p| File.directory? p }
|
1393
1541
|
RSpec::Core::RubyProject.add_to_load_path(*directories)
|
1394
|
-
paths.each { |path| require path }
|
1542
|
+
paths.each { |path| load_file_handling_errors(:require, path) }
|
1395
1543
|
@requires += paths
|
1396
1544
|
end
|
1397
1545
|
|
@@ -1432,7 +1580,7 @@ module RSpec
|
|
1432
1580
|
|
1433
1581
|
files_to_run.uniq.each do |f|
|
1434
1582
|
file = File.expand_path(f)
|
1435
|
-
load file
|
1583
|
+
load_file_handling_errors(:load, file)
|
1436
1584
|
loaded_spec_files << file
|
1437
1585
|
end
|
1438
1586
|
|
@@ -1460,8 +1608,6 @@ module RSpec
|
|
1460
1608
|
end
|
1461
1609
|
|
1462
1610
|
# @private
|
1463
|
-
# @macro [attach] delegate_to_ordering_manager
|
1464
|
-
# @!method $1
|
1465
1611
|
def self.delegate_to_ordering_manager(*methods)
|
1466
1612
|
methods.each do |method|
|
1467
1613
|
define_method method do |*args, &block|
|
@@ -1470,12 +1616,12 @@ module RSpec
|
|
1470
1616
|
end
|
1471
1617
|
end
|
1472
1618
|
|
1473
|
-
#
|
1619
|
+
# @!method seed=(value)
|
1474
1620
|
#
|
1475
1621
|
# Sets the seed value and sets the default global ordering to random.
|
1476
1622
|
delegate_to_ordering_manager :seed=
|
1477
1623
|
|
1478
|
-
#
|
1624
|
+
# @!method seed
|
1479
1625
|
# Seed for random ordering (default: generated randomly each run).
|
1480
1626
|
#
|
1481
1627
|
# When you run specs with `--order random`, RSpec generates a random seed
|
@@ -1489,7 +1635,7 @@ module RSpec
|
|
1489
1635
|
# don't accidentally leave the seed encoded.
|
1490
1636
|
delegate_to_ordering_manager :seed
|
1491
1637
|
|
1492
|
-
#
|
1638
|
+
# @!method order=(value)
|
1493
1639
|
#
|
1494
1640
|
# Sets the default global ordering strategy. By default this can be one
|
1495
1641
|
# of `:defined`, `:random`, but is customizable through the
|
@@ -1499,7 +1645,8 @@ module RSpec
|
|
1499
1645
|
# @see #register_ordering
|
1500
1646
|
delegate_to_ordering_manager :order=
|
1501
1647
|
|
1502
|
-
#
|
1648
|
+
# @!method register_ordering(name)
|
1649
|
+
#
|
1503
1650
|
# Registers a named ordering strategy that can later be
|
1504
1651
|
# used to order an example group's subgroups by adding
|
1505
1652
|
# `:order => <name>` metadata to the example group.
|
@@ -1594,7 +1741,7 @@ module RSpec
|
|
1594
1741
|
# rspec.expose_current_running_example_as :example
|
1595
1742
|
# end
|
1596
1743
|
#
|
1597
|
-
# describe MyClass do
|
1744
|
+
# RSpec.describe MyClass do
|
1598
1745
|
# before do
|
1599
1746
|
# # `example` can be used here because of the above config.
|
1600
1747
|
# do_something if example.metadata[:type] == "foo"
|
@@ -1658,7 +1805,7 @@ module RSpec
|
|
1658
1805
|
# mocks.patch_marshal_to_support_partial_doubles = false
|
1659
1806
|
# end
|
1660
1807
|
#
|
1661
|
-
# config.
|
1808
|
+
# config.expect_with :rspec do |expectations|
|
1662
1809
|
# expectations.syntax = :expect
|
1663
1810
|
# end
|
1664
1811
|
# end
|
@@ -1712,7 +1859,7 @@ module RSpec
|
|
1712
1859
|
# require 'support/db'
|
1713
1860
|
# end
|
1714
1861
|
# end
|
1715
|
-
def when_first_matching_example_defined(*filters
|
1862
|
+
def when_first_matching_example_defined(*filters)
|
1716
1863
|
specified_meta = Metadata.build_hash_from(filters, :warn_about_example_group_filtering)
|
1717
1864
|
|
1718
1865
|
callback = lambda do |example_or_group_meta|
|
@@ -1721,9 +1868,9 @@ module RSpec
|
|
1721
1868
|
return unless example_or_group_meta.key?(:example_group)
|
1722
1869
|
|
1723
1870
|
# Ensure the callback only fires once.
|
1724
|
-
@derived_metadata_blocks.
|
1871
|
+
@derived_metadata_blocks.delete(callback, specified_meta)
|
1725
1872
|
|
1726
|
-
|
1873
|
+
yield
|
1727
1874
|
end
|
1728
1875
|
|
1729
1876
|
@derived_metadata_blocks.append(callback, specified_meta)
|
@@ -1731,9 +1878,28 @@ module RSpec
|
|
1731
1878
|
|
1732
1879
|
# @private
|
1733
1880
|
def apply_derived_metadata_to(metadata)
|
1734
|
-
|
1735
|
-
|
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
|
1736
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."
|
1737
1903
|
end
|
1738
1904
|
|
1739
1905
|
# Defines a `before` hook. See {Hooks#before} for full docs.
|
@@ -1749,6 +1915,12 @@ module RSpec
|
|
1749
1915
|
handle_suite_hook(scope, meta) do
|
1750
1916
|
@before_suite_hooks << Hooks::BeforeHook.new(block, {})
|
1751
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
|
+
|
1752
1924
|
add_hook_to_existing_matching_groups(meta, scope) { |g| g.before(scope, *meta, &block) }
|
1753
1925
|
super(scope, *meta, &block)
|
1754
1926
|
end
|
@@ -1772,6 +1944,12 @@ module RSpec
|
|
1772
1944
|
handle_suite_hook(scope, meta) do
|
1773
1945
|
@before_suite_hooks.unshift Hooks::BeforeHook.new(block, {})
|
1774
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
|
+
|
1775
1953
|
add_hook_to_existing_matching_groups(meta, scope) { |g| g.prepend_before(scope, *meta, &block) }
|
1776
1954
|
super(scope, *meta, &block)
|
1777
1955
|
end
|
@@ -1790,6 +1968,12 @@ module RSpec
|
|
1790
1968
|
handle_suite_hook(scope, meta) do
|
1791
1969
|
@after_suite_hooks.unshift Hooks::AfterHook.new(block, {})
|
1792
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
|
+
|
1793
1977
|
add_hook_to_existing_matching_groups(meta, scope) { |g| g.after(scope, *meta, &block) }
|
1794
1978
|
super(scope, *meta, &block)
|
1795
1979
|
end
|
@@ -1813,6 +1997,12 @@ module RSpec
|
|
1813
1997
|
handle_suite_hook(scope, meta) do
|
1814
1998
|
@after_suite_hooks << Hooks::AfterHook.new(block, {})
|
1815
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
|
+
|
1816
2006
|
add_hook_to_existing_matching_groups(meta, scope) { |g| g.append_after(scope, *meta, &block) }
|
1817
2007
|
super(scope, *meta, &block)
|
1818
2008
|
end
|
@@ -1822,6 +2012,12 @@ module RSpec
|
|
1822
2012
|
#
|
1823
2013
|
# See {Hooks#around} for full `around` hook docs.
|
1824
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
|
+
|
1825
2021
|
add_hook_to_existing_matching_groups(meta, scope) { |g| g.around(scope, *meta, &block) }
|
1826
2022
|
super(scope, *meta, &block)
|
1827
2023
|
end
|
@@ -1857,8 +2053,38 @@ module RSpec
|
|
1857
2053
|
@on_example_group_definition_callbacks ||= []
|
1858
2054
|
end
|
1859
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
|
+
|
1860
2073
|
private
|
1861
2074
|
|
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
|
2082
|
+
rescue Support::AllExceptionsExceptOnesWeMustNotRescue => ex
|
2083
|
+
relative_file = Metadata.relative_path(file)
|
2084
|
+
reporter.notify_non_example_exception(ex, "An error occurred while loading #{relative_file}.")
|
2085
|
+
RSpec.world.wants_to_quit = true
|
2086
|
+
end
|
2087
|
+
|
1862
2088
|
def handle_suite_hook(scope, meta)
|
1863
2089
|
return nil unless scope == :suite
|
1864
2090
|
|
@@ -1882,6 +2108,12 @@ module RSpec
|
|
1882
2108
|
hook.run(context)
|
1883
2109
|
rescue Support::AllExceptionsExceptOnesWeMustNotRescue => ex
|
1884
2110
|
context.set_exception(ex)
|
2111
|
+
|
2112
|
+
# Do not run subsequent `before` hooks if one fails.
|
2113
|
+
# But for `after` hooks, we run them all so that all
|
2114
|
+
# cleanup bits get a chance to complete, minimizing the
|
2115
|
+
# chance that resources get left behind.
|
2116
|
+
break if hooks.equal?(@before_suite_hooks)
|
1885
2117
|
end
|
1886
2118
|
end
|
1887
2119
|
end
|
@@ -1985,8 +2217,12 @@ module RSpec
|
|
1985
2217
|
)
|
1986
2218
|
end
|
1987
2219
|
|
2220
|
+
def output_wrapper
|
2221
|
+
@output_wrapper ||= OutputWrapper.new(output_stream)
|
2222
|
+
end
|
2223
|
+
|
1988
2224
|
def output_to_tty?(output=output_stream)
|
1989
|
-
|
2225
|
+
output.respond_to?(:tty?) && output.tty?
|
1990
2226
|
end
|
1991
2227
|
|
1992
2228
|
def conditionally_disable_mocks_monkey_patching
|