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.
Files changed (64) hide show
  1. checksums.yaml +5 -5
  2. checksums.yaml.gz.sig +0 -0
  3. data.tar.gz.sig +0 -0
  4. data/Changelog.md +165 -2
  5. data/README.md +16 -16
  6. data/lib/rspec/core.rb +2 -1
  7. data/lib/rspec/core/bisect/coordinator.rb +26 -30
  8. data/lib/rspec/core/bisect/example_minimizer.rb +12 -8
  9. data/lib/rspec/core/bisect/fork_runner.rb +134 -0
  10. data/lib/rspec/core/bisect/server.rb +10 -14
  11. data/lib/rspec/core/bisect/{runner.rb → shell_command.rb} +27 -70
  12. data/lib/rspec/core/bisect/shell_runner.rb +73 -0
  13. data/lib/rspec/core/bisect/utilities.rb +58 -0
  14. data/lib/rspec/core/configuration.rb +315 -79
  15. data/lib/rspec/core/configuration_options.rb +43 -4
  16. data/lib/rspec/core/did_you_mean.rb +46 -0
  17. data/lib/rspec/core/drb.rb +3 -1
  18. data/lib/rspec/core/example.rb +19 -12
  19. data/lib/rspec/core/example_group.rb +17 -7
  20. data/lib/rspec/core/formatters.rb +28 -11
  21. data/lib/rspec/core/formatters/base_bisect_formatter.rb +45 -0
  22. data/lib/rspec/core/formatters/base_formatter.rb +1 -1
  23. data/lib/rspec/core/formatters/base_text_formatter.rb +3 -5
  24. data/lib/rspec/core/formatters/bisect_drb_formatter.rb +29 -0
  25. data/lib/rspec/core/formatters/bisect_progress_formatter.rb +29 -16
  26. data/lib/rspec/core/formatters/console_codes.rb +7 -4
  27. data/lib/rspec/core/formatters/deprecation_formatter.rb +9 -9
  28. data/lib/rspec/core/formatters/documentation_formatter.rb +37 -4
  29. data/lib/rspec/core/formatters/exception_presenter.rb +21 -4
  30. data/lib/rspec/core/formatters/failure_list_formatter.rb +23 -0
  31. data/lib/rspec/core/formatters/html_formatter.rb +4 -2
  32. data/lib/rspec/core/formatters/html_printer.rb +3 -3
  33. data/lib/rspec/core/formatters/html_snippet_extractor.rb +4 -0
  34. data/lib/rspec/core/formatters/json_formatter.rb +9 -3
  35. data/lib/rspec/core/formatters/progress_formatter.rb +1 -0
  36. data/lib/rspec/core/formatters/protocol.rb +43 -42
  37. data/lib/rspec/core/formatters/snippet_extractor.rb +1 -3
  38. data/lib/rspec/core/{source → formatters}/syntax_highlighter.rb +21 -1
  39. data/lib/rspec/core/hooks.rb +18 -10
  40. data/lib/rspec/core/invocations.rb +30 -10
  41. data/lib/rspec/core/memoized_helpers.rb +36 -14
  42. data/lib/rspec/core/metadata.rb +2 -3
  43. data/lib/rspec/core/metadata_filter.rb +29 -17
  44. data/lib/rspec/core/notifications.rb +34 -11
  45. data/lib/rspec/core/option_parser.rb +32 -4
  46. data/lib/rspec/core/output_wrapper.rb +29 -0
  47. data/lib/rspec/core/profiler.rb +3 -1
  48. data/lib/rspec/core/project_initializer/.rspec +0 -1
  49. data/lib/rspec/core/project_initializer/spec/spec_helper.rb +1 -4
  50. data/lib/rspec/core/rake_task.rb +21 -1
  51. data/lib/rspec/core/reporter.rb +33 -16
  52. data/lib/rspec/core/runner.rb +31 -15
  53. data/lib/rspec/core/set.rb +5 -0
  54. data/lib/rspec/core/shared_example_group.rb +41 -19
  55. data/lib/rspec/core/shell_escape.rb +2 -2
  56. data/lib/rspec/core/version.rb +1 -1
  57. data/lib/rspec/core/world.rb +24 -5
  58. metadata +26 -20
  59. metadata.gz.sig +0 -0
  60. data/lib/rspec/core/formatters/bisect_formatter.rb +0 -69
  61. data/lib/rspec/core/source.rb +0 -86
  62. data/lib/rspec/core/source/location.rb +0 -13
  63. data/lib/rspec/core/source/node.rb +0 -93
  64. 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
- latest_run_results || raise_bisect_failed(run_output)
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 BisectFormatter to determine when to abort.
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 BisectFormatter with the results of the run.
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 set of locations, using
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 Runner
10
+ class ShellCommand
12
11
  attr_reader :original_cli_args
13
12
 
14
- def initialize(server, original_cli_args)
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 run(locations)
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" << @server.drb_port
23
+ parts << "--format" << "bisect-drb"
24
+ parts << "--drb-port" << server.drb_port
31
25
 
32
- parts.concat reusable_cli_options
33
- parts.concat locations.map { |l| open3_safe_escape(l) }
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 original_results
50
- @original_results ||= run_locations(original_locations)
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 `~/.rspec`, `.rspec`,
12
- # `.rspec-local`, command line switches, and the `SPEC_OPTS` environment
13
- # variable (listed in lowest to highest precedence; for example, an option
14
- # in `~/.rspec` can be overridden by an option in `.rspec-local`).
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 to write to or filename to write to
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-failures` CLI options.
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-failures` CLI options.
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 add_setting
205
+ # @macro define_reader
189
206
  # If specified, indicates the number of failures required before cleaning
190
- # up and exit (default: `nil`).
191
- add_setting :fail_fast
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] value for output, defaults to $stdout
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
- # @param color [Symbol] defaults to `:green` but can be set to one of the
274
- # following: `[:black, :white, :red, :green, :yellow, :blue, :magenta,
275
- # :cyan]`
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
- # @param color [Symbol] defaults to `:yellow` but can be set to one of the
281
- # following: `[:black, :white, :red, :green, :yellow, :blue, :magenta,
282
- # :cyan]`
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
- # @param color [Symbol] defaults to `:red` but can be set to one of the
288
- # following: `[:black, :white, :red, :green, :yellow, :blue, :magenta,
289
- # :cyan]`
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
- # @param color [Symbol] defaults to `:white` but can be set to one of the
295
- # following: `[:black, :white, :red, :green, :yellow, :blue, :magenta,
296
- # :cyan]`
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
- # @param color [Symbol] defaults to `:blue` but can be set to one of the
302
- # following: `[:black, :white, :red, :green, :yellow, :blue, :magenta,
303
- # :cyan]`
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
- # @param color [Symbol] defaults to `:cyan` but can be set to one of the
309
- # following: `[:black, :white, :red, :green, :yellow, :blue, :magenta,
310
- # :cyan]`
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
- # Deprecated. This config option was added in RSpec 2 to pave the way
319
- # for this being the default behavior in RSpec 3. Now this option is
320
- # a no-op.
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
- # rubocop:disable Metrics/MethodLength
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 the backtrace exlusion pattern
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
- # Returns the configuration option for color, but should not
777
- # be used to check if color is supported.
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
- output_to_tty?(output) && color
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
- # Adds a formatter to the formatters collection. `formatter` can be a
818
- # string representing any of the built-in formatters (see
819
- # `built_in_formatter`), or a custom formatter class.
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
- # ### Note
961
+ # Adds a formatter to the set RSpec will use for this run.
822
962
  #
823
- # For internal purposes, `add_formatter` also accepts the name of a class
824
- # and paths to use for output streams, but you should consider that a
825
- # private api that may change at any time without notice.
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.setup_default output_stream, deprecation_stream
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
- hash[example.fetch(:example_id)] = example.fetch(:status)
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
- # @macro delegate_to_ordering_manager
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
- # @macro delegate_to_ordering_manager
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
- # @macro delegate_to_ordering_manager
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
- # @macro delegate_to_ordering_manager
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.mock_with :rspec do |expectations|
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, &block)
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.items_for(specified_meta).delete(callback)
1871
+ @derived_metadata_blocks.delete(callback, specified_meta)
1725
1872
 
1726
- block.call
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
- @derived_metadata_blocks.items_for(metadata).each do |block|
1735
- block.call(metadata)
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
- tty? || (output.respond_to?(:tty?) && output.tty?)
2225
+ output.respond_to?(:tty?) && output.tty?
1990
2226
  end
1991
2227
 
1992
2228
  def conditionally_disable_mocks_monkey_patching