rspec-core 3.5.4 → 3.9.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|