rspec-core 3.0.4 → 3.12.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +5 -5
- checksums.yaml.gz.sig +0 -0
- data/.document +1 -1
- data/.yardopts +2 -1
- data/Changelog.md +888 -2
- data/{License.txt → LICENSE.md} +6 -5
- data/README.md +165 -24
- data/lib/rspec/autorun.rb +1 -0
- data/lib/rspec/core/backtrace_formatter.rb +19 -20
- data/lib/rspec/core/bisect/coordinator.rb +62 -0
- data/lib/rspec/core/bisect/example_minimizer.rb +173 -0
- data/lib/rspec/core/bisect/fork_runner.rb +138 -0
- data/lib/rspec/core/bisect/server.rb +61 -0
- data/lib/rspec/core/bisect/shell_command.rb +126 -0
- data/lib/rspec/core/bisect/shell_runner.rb +73 -0
- data/lib/rspec/core/bisect/utilities.rb +69 -0
- data/lib/rspec/core/configuration.rb +1287 -246
- data/lib/rspec/core/configuration_options.rb +95 -35
- data/lib/rspec/core/did_you_mean.rb +46 -0
- data/lib/rspec/core/drb.rb +21 -12
- data/lib/rspec/core/dsl.rb +10 -6
- data/lib/rspec/core/example.rb +305 -113
- data/lib/rspec/core/example_group.rb +431 -223
- data/lib/rspec/core/example_status_persister.rb +235 -0
- data/lib/rspec/core/filter_manager.rb +86 -115
- data/lib/rspec/core/flat_map.rb +6 -4
- data/lib/rspec/core/formatters/base_bisect_formatter.rb +45 -0
- data/lib/rspec/core/formatters/base_formatter.rb +14 -116
- data/lib/rspec/core/formatters/base_text_formatter.rb +18 -21
- data/lib/rspec/core/formatters/bisect_drb_formatter.rb +29 -0
- data/lib/rspec/core/formatters/bisect_progress_formatter.rb +157 -0
- data/lib/rspec/core/formatters/console_codes.rb +29 -18
- data/lib/rspec/core/formatters/deprecation_formatter.rb +16 -16
- data/lib/rspec/core/formatters/documentation_formatter.rb +49 -16
- data/lib/rspec/core/formatters/exception_presenter.rb +525 -0
- data/lib/rspec/core/formatters/failure_list_formatter.rb +23 -0
- data/lib/rspec/core/formatters/fallback_message_formatter.rb +28 -0
- data/lib/rspec/core/formatters/helpers.rb +45 -15
- data/lib/rspec/core/formatters/html_formatter.rb +33 -28
- data/lib/rspec/core/formatters/html_printer.rb +30 -20
- data/lib/rspec/core/formatters/html_snippet_extractor.rb +120 -0
- data/lib/rspec/core/formatters/json_formatter.rb +18 -9
- data/lib/rspec/core/formatters/profile_formatter.rb +10 -9
- data/lib/rspec/core/formatters/progress_formatter.rb +5 -4
- data/lib/rspec/core/formatters/protocol.rb +182 -0
- data/lib/rspec/core/formatters/snippet_extractor.rb +113 -82
- data/lib/rspec/core/formatters/syntax_highlighter.rb +91 -0
- data/lib/rspec/core/formatters.rb +81 -41
- data/lib/rspec/core/hooks.rb +314 -244
- data/lib/rspec/core/invocations.rb +87 -0
- data/lib/rspec/core/memoized_helpers.rb +161 -51
- data/lib/rspec/core/metadata.rb +132 -61
- data/lib/rspec/core/metadata_filter.rb +224 -64
- data/lib/rspec/core/minitest_assertions_adapter.rb +6 -3
- data/lib/rspec/core/mocking_adapters/flexmock.rb +4 -2
- data/lib/rspec/core/mocking_adapters/mocha.rb +11 -9
- data/lib/rspec/core/mocking_adapters/null.rb +2 -0
- data/lib/rspec/core/mocking_adapters/rr.rb +3 -1
- data/lib/rspec/core/mocking_adapters/rspec.rb +3 -1
- data/lib/rspec/core/notifications.rb +192 -206
- data/lib/rspec/core/option_parser.rb +174 -69
- data/lib/rspec/core/ordering.rb +48 -35
- data/lib/rspec/core/output_wrapper.rb +29 -0
- data/lib/rspec/core/pending.rb +25 -33
- data/lib/rspec/core/profiler.rb +34 -0
- data/lib/rspec/core/project_initializer/.rspec +0 -2
- data/lib/rspec/core/project_initializer/spec/spec_helper.rb +59 -39
- data/lib/rspec/core/project_initializer.rb +5 -3
- data/lib/rspec/core/rake_task.rb +99 -55
- data/lib/rspec/core/reporter.rb +128 -15
- data/lib/rspec/core/ruby_project.rb +14 -6
- data/lib/rspec/core/runner.rb +96 -45
- data/lib/rspec/core/sandbox.rb +37 -0
- data/lib/rspec/core/set.rb +54 -0
- data/lib/rspec/core/shared_example_group.rb +133 -43
- data/lib/rspec/core/shell_escape.rb +49 -0
- data/lib/rspec/core/test_unit_assertions_adapter.rb +4 -4
- data/lib/rspec/core/version.rb +1 -1
- data/lib/rspec/core/warnings.rb +6 -6
- data/lib/rspec/core/world.rb +172 -68
- data/lib/rspec/core.rb +66 -21
- data.tar.gz.sig +0 -0
- metadata +93 -69
- metadata.gz.sig +0 -0
- data/lib/rspec/core/backport_random.rb +0 -336
|
@@ -1,17 +1,32 @@
|
|
|
1
|
-
require 'fileutils'
|
|
2
|
-
|
|
3
1
|
RSpec::Support.require_rspec_core "backtrace_formatter"
|
|
4
2
|
RSpec::Support.require_rspec_core "ruby_project"
|
|
5
3
|
RSpec::Support.require_rspec_core "formatters/deprecation_formatter"
|
|
4
|
+
RSpec::Support.require_rspec_core "output_wrapper"
|
|
6
5
|
|
|
7
6
|
module RSpec
|
|
8
7
|
module Core
|
|
8
|
+
# rubocop:disable Metrics/ClassLength
|
|
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|
|
|
@@ -32,27 +47,37 @@ module RSpec
|
|
|
32
47
|
class Configuration
|
|
33
48
|
include RSpec::Core::Hooks
|
|
34
49
|
|
|
50
|
+
# Module that holds `attr_reader` declarations. It's in a separate
|
|
51
|
+
# module to allow us to override those methods and use `super`.
|
|
52
|
+
# @private
|
|
53
|
+
Readers = Module.new
|
|
54
|
+
include Readers
|
|
55
|
+
|
|
35
56
|
# @private
|
|
36
57
|
class MustBeConfiguredBeforeExampleGroupsError < StandardError; end
|
|
37
58
|
|
|
38
59
|
# @private
|
|
39
60
|
def self.define_reader(name)
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
61
|
+
Readers.class_eval do
|
|
62
|
+
remove_method name if method_defined?(name)
|
|
63
|
+
attr_reader name
|
|
43
64
|
end
|
|
65
|
+
|
|
66
|
+
define_method(name) { value_for(name) { super() } }
|
|
44
67
|
end
|
|
45
68
|
|
|
46
69
|
# @private
|
|
47
|
-
def self.
|
|
70
|
+
def self.define_alias(name, alias_name)
|
|
48
71
|
alias_method alias_name, name
|
|
49
72
|
alias_method "#{alias_name}=", "#{name}="
|
|
50
|
-
|
|
73
|
+
define_predicate alias_name
|
|
51
74
|
end
|
|
52
75
|
|
|
53
76
|
# @private
|
|
54
|
-
def self.
|
|
55
|
-
|
|
77
|
+
def self.define_predicate(name)
|
|
78
|
+
define_method "#{name}?" do
|
|
79
|
+
!!send(name)
|
|
80
|
+
end
|
|
56
81
|
end
|
|
57
82
|
|
|
58
83
|
# @private
|
|
@@ -60,27 +85,26 @@ module RSpec
|
|
|
60
85
|
# Invoked by the `add_setting` instance method. Use that method on a
|
|
61
86
|
# `Configuration` instance rather than this class method.
|
|
62
87
|
def self.add_setting(name, opts={})
|
|
63
|
-
raise "Use the instance add_setting method if you want to set a default" if opts.
|
|
88
|
+
raise "Use the instance add_setting method if you want to set a default" if opts.key?(:default)
|
|
64
89
|
attr_writer name
|
|
65
90
|
add_read_only_setting name
|
|
66
91
|
|
|
67
92
|
Array(opts[:alias_with]).each do |alias_name|
|
|
68
|
-
|
|
93
|
+
define_alias(name, alias_name)
|
|
69
94
|
end
|
|
70
95
|
end
|
|
71
96
|
|
|
72
97
|
# @private
|
|
73
98
|
#
|
|
74
|
-
# As `add_setting` but only add the reader
|
|
99
|
+
# As `add_setting` but only add the reader.
|
|
75
100
|
def self.add_read_only_setting(name, opts={})
|
|
76
|
-
raise "Use the instance add_setting method if you want to set a default" if opts.
|
|
101
|
+
raise "Use the instance add_setting method if you want to set a default" if opts.key?(:default)
|
|
77
102
|
define_reader name
|
|
78
|
-
|
|
103
|
+
define_predicate name
|
|
79
104
|
end
|
|
80
105
|
|
|
81
106
|
# @macro [attach] add_setting
|
|
82
107
|
# @!attribute [rw] $1
|
|
83
|
-
# @!method $1=(value)
|
|
84
108
|
#
|
|
85
109
|
# @macro [attach] define_reader
|
|
86
110
|
# @!attribute [r] $1
|
|
@@ -89,11 +113,20 @@ module RSpec
|
|
|
89
113
|
# Path to use if no path is provided to the `rspec` command (default:
|
|
90
114
|
# `"spec"`). Allows you to just type `rspec` instead of `rspec spec` to
|
|
91
115
|
# run all the examples in the `spec` directory.
|
|
92
|
-
|
|
116
|
+
#
|
|
117
|
+
# @note Other scripts invoking `rspec` indirectly will ignore this
|
|
118
|
+
# setting.
|
|
119
|
+
# @return [String]
|
|
120
|
+
add_read_only_setting :default_path
|
|
121
|
+
def default_path=(path)
|
|
122
|
+
project_source_dirs << path
|
|
123
|
+
@default_path = path
|
|
124
|
+
end
|
|
93
125
|
|
|
94
126
|
# @macro add_setting
|
|
95
127
|
# Run examples over DRb (default: `false`). RSpec doesn't supply the DRb
|
|
96
128
|
# server, but you can use tools like spork.
|
|
129
|
+
# @return [Boolean]
|
|
97
130
|
add_setting :drb
|
|
98
131
|
|
|
99
132
|
# @macro add_setting
|
|
@@ -106,6 +139,7 @@ module RSpec
|
|
|
106
139
|
|
|
107
140
|
# Indicates if the DSL has been exposed off of modules and `main`.
|
|
108
141
|
# Default: true
|
|
142
|
+
# @return [Boolean]
|
|
109
143
|
def expose_dsl_globally?
|
|
110
144
|
Core::DSL.exposed_globally?
|
|
111
145
|
end
|
|
@@ -126,26 +160,77 @@ module RSpec
|
|
|
126
160
|
|
|
127
161
|
# Determines where deprecation warnings are printed.
|
|
128
162
|
# Defaults to `$stderr`.
|
|
129
|
-
# @return [IO, String] IO
|
|
163
|
+
# @return [IO, String] IO or filename to write to
|
|
130
164
|
define_reader :deprecation_stream
|
|
131
165
|
|
|
132
166
|
# Determines where deprecation warnings are printed.
|
|
133
167
|
# @param value [IO, String] IO to write to or filename to write to
|
|
134
168
|
def deprecation_stream=(value)
|
|
135
169
|
if @reporter && !value.equal?(@deprecation_stream)
|
|
136
|
-
warn "RSpec's reporter has already been initialized with "
|
|
137
|
-
"#{deprecation_stream.inspect} as the deprecation stream, so your change to "
|
|
138
|
-
"`deprecation_stream` will be ignored. You should configure it earlier for "
|
|
139
|
-
"it to take effect, or use the `--deprecation-out` CLI option. "
|
|
170
|
+
warn "RSpec's reporter has already been initialized with " \
|
|
171
|
+
"#{deprecation_stream.inspect} as the deprecation stream, so your change to "\
|
|
172
|
+
"`deprecation_stream` will be ignored. You should configure it earlier for " \
|
|
173
|
+
"it to take effect, or use the `--deprecation-out` CLI option. " \
|
|
140
174
|
"(Called from #{CallerFilter.first_non_rspec_line})"
|
|
141
175
|
else
|
|
142
176
|
@deprecation_stream = value
|
|
143
177
|
end
|
|
144
178
|
end
|
|
145
179
|
|
|
146
|
-
# @macro
|
|
147
|
-
#
|
|
148
|
-
|
|
180
|
+
# @macro define_reader
|
|
181
|
+
# The file path to use for persisting example statuses. Necessary for the
|
|
182
|
+
# `--only-failures` and `--next-failure` CLI options.
|
|
183
|
+
#
|
|
184
|
+
# @overload example_status_persistence_file_path
|
|
185
|
+
# @return [String] the file path
|
|
186
|
+
# @overload example_status_persistence_file_path=(value)
|
|
187
|
+
# @param value [String] the file path
|
|
188
|
+
define_reader :example_status_persistence_file_path
|
|
189
|
+
|
|
190
|
+
# Sets the file path to use for persisting example statuses. Necessary for the
|
|
191
|
+
# `--only-failures` and `--next-failure` CLI options.
|
|
192
|
+
def example_status_persistence_file_path=(value)
|
|
193
|
+
@example_status_persistence_file_path = value
|
|
194
|
+
clear_values_derived_from_example_status_persistence_file_path
|
|
195
|
+
end
|
|
196
|
+
|
|
197
|
+
# @macro define_reader
|
|
198
|
+
# Indicates if the `--only-failures` (or `--next-failure`) flag is being used.
|
|
199
|
+
define_reader :only_failures
|
|
200
|
+
alias_method :only_failures?, :only_failures
|
|
201
|
+
|
|
202
|
+
# @private
|
|
203
|
+
def only_failures_but_not_configured?
|
|
204
|
+
only_failures? && !example_status_persistence_file_path
|
|
205
|
+
end
|
|
206
|
+
|
|
207
|
+
# @macro define_reader
|
|
208
|
+
# If specified, indicates the number of failures required before cleaning
|
|
209
|
+
# up and exit (default: `nil`). Can also be `true` to fail and exit on first
|
|
210
|
+
# failure
|
|
211
|
+
define_reader :fail_fast
|
|
212
|
+
|
|
213
|
+
# @see fail_fast
|
|
214
|
+
def fail_fast=(value)
|
|
215
|
+
case value
|
|
216
|
+
when true, 'true'
|
|
217
|
+
@fail_fast = true
|
|
218
|
+
when false, 'false', 0
|
|
219
|
+
@fail_fast = false
|
|
220
|
+
when nil
|
|
221
|
+
@fail_fast = nil
|
|
222
|
+
else
|
|
223
|
+
@fail_fast = value.to_i
|
|
224
|
+
|
|
225
|
+
if value.to_i == 0
|
|
226
|
+
# TODO: in RSpec 4, consider raising an error here.
|
|
227
|
+
RSpec.warning "Cannot set `RSpec.configuration.fail_fast`" \
|
|
228
|
+
" to `#{value.inspect}`. Only `true`, `false`, `nil` and integers" \
|
|
229
|
+
" are valid values."
|
|
230
|
+
@fail_fast = true
|
|
231
|
+
end
|
|
232
|
+
end
|
|
233
|
+
end
|
|
149
234
|
|
|
150
235
|
# @macro add_setting
|
|
151
236
|
# Prints the formatter output of your suite without running any
|
|
@@ -154,143 +239,310 @@ module RSpec
|
|
|
154
239
|
|
|
155
240
|
# @macro add_setting
|
|
156
241
|
# The exit code to return if there are any failures (default: 1).
|
|
242
|
+
# @return [Integer]
|
|
157
243
|
add_setting :failure_exit_code
|
|
158
244
|
|
|
245
|
+
# @macro add_setting
|
|
246
|
+
# The exit code to return if there are any errors outside examples (default: failure_exit_code)
|
|
247
|
+
# @return [Integer]
|
|
248
|
+
add_setting :error_exit_code
|
|
249
|
+
|
|
250
|
+
# @macro add_setting
|
|
251
|
+
# Whether or not to fail when there are no RSpec examples (default: false).
|
|
252
|
+
# @return [Boolean]
|
|
253
|
+
add_setting :fail_if_no_examples
|
|
254
|
+
|
|
159
255
|
# @macro define_reader
|
|
160
|
-
# Indicates files configured to be required
|
|
256
|
+
# Indicates files configured to be required.
|
|
257
|
+
# @return [Array<String>]
|
|
161
258
|
define_reader :requires
|
|
162
259
|
|
|
163
260
|
# @macro define_reader
|
|
164
|
-
# Returns dirs that have been prepended to the load path by the `-I`
|
|
261
|
+
# Returns dirs that have been prepended to the load path by the `-I`
|
|
262
|
+
# command line option.
|
|
263
|
+
# @return [Array<String>]
|
|
165
264
|
define_reader :libs
|
|
166
265
|
|
|
167
266
|
# @macro add_setting
|
|
168
267
|
# Determines where RSpec will send its output.
|
|
169
268
|
# Default: `$stdout`.
|
|
269
|
+
# @return [IO, String]
|
|
170
270
|
define_reader :output_stream
|
|
171
271
|
|
|
172
|
-
# Set the output stream for reporter
|
|
173
|
-
# @attr value [IO]
|
|
272
|
+
# Set the output stream for reporter.
|
|
273
|
+
# @attr value [IO, String] IO to write to or filename to write to, defaults to $stdout
|
|
174
274
|
def output_stream=(value)
|
|
175
275
|
if @reporter && !value.equal?(@output_stream)
|
|
176
|
-
warn "RSpec's reporter has already been initialized with "
|
|
177
|
-
"#{output_stream.inspect} as the output stream, so your change to "
|
|
178
|
-
"`output_stream` will be ignored. You should configure it earlier for "
|
|
276
|
+
warn "RSpec's reporter has already been initialized with " \
|
|
277
|
+
"#{output_stream.inspect} as the output stream, so your change to "\
|
|
278
|
+
"`output_stream` will be ignored. You should configure it earlier for " \
|
|
179
279
|
"it to take effect. (Called from #{CallerFilter.first_non_rspec_line})"
|
|
180
280
|
else
|
|
181
281
|
@output_stream = value
|
|
282
|
+
output_wrapper.output = @output_stream
|
|
182
283
|
end
|
|
183
284
|
end
|
|
184
285
|
|
|
185
286
|
# @macro define_reader
|
|
186
|
-
# Load files matching this pattern (default: `'
|
|
287
|
+
# Load files matching this pattern (default: `'**{,/*/**}/*_spec.rb'`).
|
|
288
|
+
# @return [String]
|
|
187
289
|
define_reader :pattern
|
|
188
290
|
|
|
189
|
-
# Set pattern to match files to load
|
|
291
|
+
# Set pattern to match files to load.
|
|
190
292
|
# @attr value [String] the filename pattern to filter spec files by
|
|
191
293
|
def pattern=(value)
|
|
192
|
-
|
|
193
|
-
RSpec.warning "Configuring `pattern` to #{value} has no effect since RSpec has already loaded the spec files."
|
|
194
|
-
end
|
|
195
|
-
@pattern = value
|
|
196
|
-
@files_to_run = nil
|
|
294
|
+
update_pattern_attr :pattern, value
|
|
197
295
|
end
|
|
198
296
|
|
|
297
|
+
# @macro define_reader
|
|
298
|
+
# Exclude files matching this pattern.
|
|
299
|
+
# @return [String]
|
|
300
|
+
define_reader :exclude_pattern
|
|
301
|
+
|
|
302
|
+
# Set pattern to match files to exclude.
|
|
303
|
+
# @attr value [String] the filename pattern to exclude spec files by
|
|
304
|
+
def exclude_pattern=(value)
|
|
305
|
+
update_pattern_attr :exclude_pattern, value
|
|
306
|
+
end
|
|
307
|
+
|
|
308
|
+
# @macro add_setting
|
|
309
|
+
# Specifies which directories contain the source code for your project.
|
|
310
|
+
# When a failure occurs, RSpec looks through the backtrace to find a
|
|
311
|
+
# a line of source to print. It first looks for a line coming from
|
|
312
|
+
# one of the project source directories so that, for example, it prints
|
|
313
|
+
# the expectation or assertion call rather than the source code from
|
|
314
|
+
# the expectation or assertion framework.
|
|
315
|
+
# @return [Array<String>]
|
|
316
|
+
add_setting :project_source_dirs
|
|
317
|
+
|
|
199
318
|
# @macro add_setting
|
|
200
319
|
# Report the times for the slowest examples (default: `false`).
|
|
201
320
|
# Use this to specify the number of examples to include in the profile.
|
|
202
|
-
|
|
321
|
+
# @return [Boolean]
|
|
322
|
+
attr_writer :profile_examples
|
|
323
|
+
define_predicate :profile_examples
|
|
203
324
|
|
|
204
325
|
# @macro add_setting
|
|
205
|
-
# Run all examples if none match the configured filters
|
|
326
|
+
# Run all examples if none match the configured filters
|
|
327
|
+
# (default: `false`).
|
|
328
|
+
# @deprecated Use {#filter_run_when_matching} instead for the specific
|
|
329
|
+
# filters that you want to be ignored if none match.
|
|
206
330
|
add_setting :run_all_when_everything_filtered
|
|
207
331
|
|
|
208
332
|
# @macro add_setting
|
|
209
|
-
# Color to use to indicate success.
|
|
210
|
-
#
|
|
211
|
-
#
|
|
212
|
-
#
|
|
333
|
+
# Color to use to indicate success. Defaults to `:green` but can be set
|
|
334
|
+
# to one of the following: `[:black, :white, :red, :green, :yellow,
|
|
335
|
+
# :blue, :magenta, :cyan]`
|
|
336
|
+
# @return [Symbol]
|
|
213
337
|
add_setting :success_color
|
|
214
338
|
|
|
215
339
|
# @macro add_setting
|
|
216
|
-
# Color to use to print pending examples.
|
|
217
|
-
#
|
|
218
|
-
#
|
|
219
|
-
#
|
|
340
|
+
# Color to use to print pending examples. Defaults to `:yellow` but can
|
|
341
|
+
# be set to one of the following: `[:black, :white, :red, :green,
|
|
342
|
+
# :yellow, :blue, :magenta, :cyan]`
|
|
343
|
+
# @return [Symbol]
|
|
220
344
|
add_setting :pending_color
|
|
221
345
|
|
|
222
346
|
# @macro add_setting
|
|
223
|
-
# Color to use to indicate failure.
|
|
224
|
-
#
|
|
225
|
-
#
|
|
226
|
-
#
|
|
347
|
+
# Color to use to indicate failure. Defaults to `:red` but can be set to
|
|
348
|
+
# one of the following: `[:black, :white, :red, :green, :yellow, :blue,
|
|
349
|
+
# :magenta, :cyan]`
|
|
350
|
+
# @return [Symbol]
|
|
227
351
|
add_setting :failure_color
|
|
228
352
|
|
|
229
353
|
# @macro add_setting
|
|
230
|
-
# The default output color.
|
|
231
|
-
#
|
|
232
|
-
#
|
|
233
|
-
#
|
|
354
|
+
# The default output color. Defaults to `:white` but can be set to one of
|
|
355
|
+
# the following: `[:black, :white, :red, :green, :yellow, :blue,
|
|
356
|
+
# :magenta, :cyan]`
|
|
357
|
+
# @return [Symbol]
|
|
234
358
|
add_setting :default_color
|
|
235
359
|
|
|
236
360
|
# @macro add_setting
|
|
237
|
-
# Color used when a pending example is fixed.
|
|
238
|
-
#
|
|
239
|
-
#
|
|
240
|
-
#
|
|
361
|
+
# Color used when a pending example is fixed. Defaults to `:blue` but can
|
|
362
|
+
# be set to one of the following: `[:black, :white, :red, :green,
|
|
363
|
+
# :yellow, :blue, :magenta, :cyan]`
|
|
364
|
+
# @return [Symbol]
|
|
241
365
|
add_setting :fixed_color
|
|
242
366
|
|
|
243
367
|
# @macro add_setting
|
|
244
|
-
# Color used to print details.
|
|
245
|
-
#
|
|
246
|
-
#
|
|
247
|
-
#
|
|
368
|
+
# Color used to print details. Defaults to `:cyan` but can be set to one
|
|
369
|
+
# of the following: `[:black, :white, :red, :green, :yellow, :blue,
|
|
370
|
+
# :magenta, :cyan]`
|
|
371
|
+
# @return [Symbol]
|
|
248
372
|
add_setting :detail_color
|
|
249
373
|
|
|
250
|
-
#
|
|
251
|
-
#
|
|
252
|
-
#
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
374
|
+
# @macro add_setting
|
|
375
|
+
# Don't print filter info i.e. "Run options: include {:focus=>true}"
|
|
376
|
+
# (default `false`).
|
|
377
|
+
# return [Boolean]
|
|
378
|
+
add_setting :silence_filter_announcements
|
|
379
|
+
|
|
380
|
+
# @deprecated This config option was added in RSpec 2 to pave the way
|
|
381
|
+
# for this being the default behavior in RSpec 3. Now this option is
|
|
382
|
+
# a no-op.
|
|
383
|
+
def treat_symbols_as_metadata_keys_with_true_values=(_value)
|
|
384
|
+
RSpec.deprecate(
|
|
385
|
+
"RSpec::Core::Configuration#treat_symbols_as_metadata_keys_with_true_values=",
|
|
386
|
+
:message => "RSpec::Core::Configuration#treat_symbols_as_metadata_keys_with_true_values= " \
|
|
387
|
+
"is deprecated, it is now set to true as default and " \
|
|
388
|
+
"setting it to false has no effect."
|
|
389
|
+
)
|
|
390
|
+
end
|
|
391
|
+
|
|
392
|
+
# @macro define_reader
|
|
393
|
+
# Configures how RSpec treats metadata passed as part of a shared example
|
|
394
|
+
# group definition. For example, given this shared example group definition:
|
|
395
|
+
#
|
|
396
|
+
# RSpec.shared_context "uses DB", :db => true do
|
|
397
|
+
# around(:example) do |ex|
|
|
398
|
+
# MyORM.transaction(:rollback => true, &ex)
|
|
399
|
+
# end
|
|
400
|
+
# end
|
|
401
|
+
#
|
|
402
|
+
# ...there are two ways RSpec can treat the `:db => true` metadata, each
|
|
403
|
+
# of which has a corresponding config option:
|
|
404
|
+
#
|
|
405
|
+
# 1. `:trigger_inclusion`: this shared context will be implicitly included
|
|
406
|
+
# in any groups (or examples) that have `:db => true` metadata.
|
|
407
|
+
# 2. `:apply_to_host_groups`: the metadata will be inherited by the metadata
|
|
408
|
+
# hash of all host groups and examples.
|
|
409
|
+
#
|
|
410
|
+
# `:trigger_inclusion` is the legacy behavior from before RSpec 3.5 but should
|
|
411
|
+
# be considered deprecated. Instead, you can explicitly include a group with
|
|
412
|
+
# `include_context`:
|
|
413
|
+
#
|
|
414
|
+
# RSpec.describe "My model" do
|
|
415
|
+
# include_context "uses DB"
|
|
416
|
+
# end
|
|
417
|
+
#
|
|
418
|
+
# ...or you can configure RSpec to include the context based on matching metadata
|
|
419
|
+
# using an API that mirrors configured module inclusion:
|
|
420
|
+
#
|
|
421
|
+
# RSpec.configure do |rspec|
|
|
422
|
+
# rspec.include_context "uses DB", :db => true
|
|
423
|
+
# end
|
|
424
|
+
#
|
|
425
|
+
# `:apply_to_host_groups` is a new feature of RSpec 3.5 and will be the only
|
|
426
|
+
# supported behavior in RSpec 4.
|
|
427
|
+
#
|
|
428
|
+
# @overload shared_context_metadata_behavior
|
|
429
|
+
# @return [:trigger_inclusion, :apply_to_host_groups] the configured behavior
|
|
430
|
+
# @overload shared_context_metadata_behavior=(value)
|
|
431
|
+
# @param value [:trigger_inclusion, :apply_to_host_groups] sets the configured behavior
|
|
432
|
+
define_reader :shared_context_metadata_behavior
|
|
433
|
+
# @see shared_context_metadata_behavior
|
|
434
|
+
def shared_context_metadata_behavior=(value)
|
|
435
|
+
case value
|
|
436
|
+
when :trigger_inclusion, :apply_to_host_groups
|
|
437
|
+
@shared_context_metadata_behavior = value
|
|
438
|
+
else
|
|
439
|
+
raise ArgumentError, "Cannot set `RSpec.configuration." \
|
|
440
|
+
"shared_context_metadata_behavior` to `#{value.inspect}`. Only " \
|
|
441
|
+
"`:trigger_inclusion` and `:apply_to_host_groups` are valid values."
|
|
442
|
+
end
|
|
257
443
|
end
|
|
258
444
|
|
|
259
|
-
# Record the start time of the spec suite to measure load time
|
|
445
|
+
# Record the start time of the spec suite to measure load time.
|
|
446
|
+
# return [Time]
|
|
260
447
|
add_setting :start_time
|
|
261
448
|
|
|
449
|
+
# @macro add_setting
|
|
450
|
+
# Use threadsafe options where available.
|
|
451
|
+
# Currently this will place a mutex around memoized values such as let blocks.
|
|
452
|
+
# return [Boolean]
|
|
453
|
+
add_setting :threadsafe
|
|
454
|
+
|
|
455
|
+
# @macro add_setting
|
|
456
|
+
# Maximum count of failed source lines to display in the failure reports.
|
|
457
|
+
# (default `10`).
|
|
458
|
+
# return [Integer]
|
|
459
|
+
add_setting :max_displayed_failure_line_count
|
|
460
|
+
|
|
461
|
+
# Determines which bisect runner implementation gets used to run subsets
|
|
462
|
+
# of the suite during a bisection. Your choices are:
|
|
463
|
+
#
|
|
464
|
+
# - `:shell`: Performs a spec run by shelling out, booting RSpec and your
|
|
465
|
+
# application environment each time. This runner is the most widely
|
|
466
|
+
# compatible runner, but is not as fast. On platforms that do not
|
|
467
|
+
# support forking, this is the default.
|
|
468
|
+
# - `:fork`: Pre-boots RSpec and your application environment in a parent
|
|
469
|
+
# process, and then forks a child process for each spec run. This runner
|
|
470
|
+
# tends to be significantly faster than the `:shell` runner but cannot
|
|
471
|
+
# be used in some situations. On platforms that support forking, this
|
|
472
|
+
# is the default. If you use this runner, you should ensure that all
|
|
473
|
+
# of your one-time setup logic goes in a `before(:suite)` hook instead
|
|
474
|
+
# of getting run at the top-level of a file loaded by `--require`.
|
|
475
|
+
#
|
|
476
|
+
# @note This option will only be used by `--bisect` if you set it in a file
|
|
477
|
+
# loaded via `--require`.
|
|
478
|
+
#
|
|
479
|
+
# @return [Symbol]
|
|
480
|
+
attr_reader :bisect_runner
|
|
481
|
+
def bisect_runner=(value)
|
|
482
|
+
if @bisect_runner_class && value != @bisect_runner
|
|
483
|
+
raise "`config.bisect_runner = #{value.inspect}` can no longer take " \
|
|
484
|
+
"effect as the #{@bisect_runner.inspect} bisect runnner is already " \
|
|
485
|
+
"in use. This config setting must be set in a file loaded by a " \
|
|
486
|
+
"`--require` option (passed at the CLI or in a `.rspec` file) for " \
|
|
487
|
+
"it to have any effect."
|
|
488
|
+
end
|
|
489
|
+
|
|
490
|
+
@bisect_runner = value
|
|
491
|
+
end
|
|
492
|
+
|
|
262
493
|
# @private
|
|
494
|
+
# @deprecated Use {#color_mode} = :on, instead of {#color} with {#tty}
|
|
263
495
|
add_setting :tty
|
|
264
496
|
# @private
|
|
265
|
-
add_setting :include_or_extend_modules
|
|
266
|
-
# @private
|
|
267
497
|
attr_writer :files_to_run
|
|
268
498
|
# @private
|
|
269
|
-
|
|
499
|
+
attr_accessor :filter_manager, :world
|
|
270
500
|
# @private
|
|
271
|
-
attr_accessor :
|
|
501
|
+
attr_accessor :static_config_filter_manager
|
|
272
502
|
# @private
|
|
273
|
-
attr_reader :backtrace_formatter, :ordering_manager
|
|
503
|
+
attr_reader :backtrace_formatter, :ordering_manager, :loaded_spec_files
|
|
504
|
+
|
|
505
|
+
# rubocop:disable Metrics/AbcSize
|
|
506
|
+
# rubocop:disable Metrics/MethodLength
|
|
274
507
|
|
|
508
|
+
# Build an object to store runtime configuration options and set defaults
|
|
275
509
|
def initialize
|
|
510
|
+
# rubocop:disable Style/GlobalVars
|
|
276
511
|
@start_time = $_rspec_core_load_started_at || ::RSpec::Core::Time.now
|
|
512
|
+
# rubocop:enable Style/GlobalVars
|
|
277
513
|
@expectation_frameworks = []
|
|
278
|
-
@
|
|
514
|
+
@include_modules = FilterableItemRepository::QueryOptimized.new(:any?)
|
|
515
|
+
@extend_modules = FilterableItemRepository::QueryOptimized.new(:any?)
|
|
516
|
+
@prepend_modules = FilterableItemRepository::QueryOptimized.new(:any?)
|
|
517
|
+
|
|
518
|
+
@bisect_runner = RSpec::Support::RubyFeatures.fork_supported? ? :fork : :shell
|
|
519
|
+
@bisect_runner_class = nil
|
|
520
|
+
|
|
521
|
+
@before_suite_hooks = []
|
|
522
|
+
@after_suite_hooks = []
|
|
523
|
+
|
|
279
524
|
@mock_framework = nil
|
|
280
525
|
@files_or_directories_to_run = []
|
|
526
|
+
@loaded_spec_files = Set.new
|
|
281
527
|
@color = false
|
|
282
|
-
@
|
|
528
|
+
@color_mode = :automatic
|
|
529
|
+
@pattern = '**{,/*/**}/*_spec.rb'
|
|
530
|
+
@exclude_pattern = ''
|
|
283
531
|
@failure_exit_code = 1
|
|
532
|
+
@error_exit_code = nil # so it can be overridden by failure exit code
|
|
533
|
+
@fail_if_no_examples = false
|
|
284
534
|
@spec_files_loaded = false
|
|
285
535
|
|
|
286
536
|
@backtrace_formatter = BacktraceFormatter.new
|
|
287
537
|
|
|
288
538
|
@default_path = 'spec'
|
|
539
|
+
@project_source_dirs = %w[ spec lib app ]
|
|
289
540
|
@deprecation_stream = $stderr
|
|
290
541
|
@output_stream = $stdout
|
|
291
542
|
@reporter = nil
|
|
292
543
|
@reporter_buffer = nil
|
|
293
544
|
@filter_manager = FilterManager.new
|
|
545
|
+
@static_config_filter_manager = FilterManager.new
|
|
294
546
|
@ordering_manager = Ordering::ConfigurationManager.new
|
|
295
547
|
@preferred_options = {}
|
|
296
548
|
@failure_color = :red
|
|
@@ -302,8 +554,16 @@ module RSpec
|
|
|
302
554
|
@profile_examples = false
|
|
303
555
|
@requires = []
|
|
304
556
|
@libs = []
|
|
305
|
-
@derived_metadata_blocks =
|
|
557
|
+
@derived_metadata_blocks = FilterableItemRepository::QueryOptimized.new(:any?)
|
|
558
|
+
@threadsafe = true
|
|
559
|
+
@max_displayed_failure_line_count = 10
|
|
560
|
+
@world = World::Null
|
|
561
|
+
@shared_context_metadata_behavior = :trigger_inclusion
|
|
562
|
+
|
|
563
|
+
define_built_in_hooks
|
|
306
564
|
end
|
|
565
|
+
# rubocop:enable Metrics/AbcSize
|
|
566
|
+
# rubocop:enable Metrics/MethodLength
|
|
307
567
|
|
|
308
568
|
# @private
|
|
309
569
|
#
|
|
@@ -311,27 +571,47 @@ module RSpec
|
|
|
311
571
|
def force(hash)
|
|
312
572
|
ordering_manager.force(hash)
|
|
313
573
|
@preferred_options.merge!(hash)
|
|
574
|
+
|
|
575
|
+
return unless hash.key?(:example_status_persistence_file_path)
|
|
576
|
+
clear_values_derived_from_example_status_persistence_file_path
|
|
314
577
|
end
|
|
315
578
|
|
|
316
579
|
# @private
|
|
317
580
|
def reset
|
|
318
581
|
@spec_files_loaded = false
|
|
582
|
+
reset_reporter
|
|
583
|
+
end
|
|
584
|
+
|
|
585
|
+
# @private
|
|
586
|
+
def reset_reporter
|
|
319
587
|
@reporter = nil
|
|
320
588
|
@formatter_loader = nil
|
|
589
|
+
@output_wrapper = nil
|
|
590
|
+
end
|
|
591
|
+
|
|
592
|
+
# @private
|
|
593
|
+
def reset_filters
|
|
594
|
+
self.filter_manager = FilterManager.new
|
|
595
|
+
filter_manager.include_only(
|
|
596
|
+
Metadata.deep_hash_dup(static_config_filter_manager.inclusions.rules)
|
|
597
|
+
)
|
|
598
|
+
filter_manager.exclude_only(
|
|
599
|
+
Metadata.deep_hash_dup(static_config_filter_manager.exclusions.rules)
|
|
600
|
+
)
|
|
321
601
|
end
|
|
322
602
|
|
|
323
603
|
# @overload add_setting(name)
|
|
324
604
|
# @overload add_setting(name, opts)
|
|
325
605
|
# @option opts [Symbol] :default
|
|
326
606
|
#
|
|
327
|
-
#
|
|
607
|
+
# Set a default value for the generated getter and predicate methods:
|
|
328
608
|
#
|
|
329
609
|
# add_setting(:foo, :default => "default value")
|
|
330
610
|
#
|
|
331
611
|
# @option opts [Symbol] :alias_with
|
|
332
612
|
#
|
|
333
|
-
# Use `:alias_with` to alias the setter, getter, and predicate to
|
|
334
|
-
# name, or names:
|
|
613
|
+
# Use `:alias_with` to alias the setter, getter, and predicate to
|
|
614
|
+
# another name, or names:
|
|
335
615
|
#
|
|
336
616
|
# add_setting(:foo, :alias_with => :bar)
|
|
337
617
|
# add_setting(:foo, :alias_with => [:bar, :baz])
|
|
@@ -354,7 +634,7 @@ module RSpec
|
|
|
354
634
|
#
|
|
355
635
|
# RSpec.configuration.foo=(value)
|
|
356
636
|
# RSpec.configuration.foo
|
|
357
|
-
# RSpec.configuration.foo? #
|
|
637
|
+
# RSpec.configuration.foo? # Returns true if foo returns anything but nil or false.
|
|
358
638
|
def add_setting(name, opts={})
|
|
359
639
|
default = opts.delete(:default)
|
|
360
640
|
(class << self; self; end).class_exec do
|
|
@@ -363,13 +643,20 @@ module RSpec
|
|
|
363
643
|
__send__("#{name}=", default) if default
|
|
364
644
|
end
|
|
365
645
|
|
|
366
|
-
# Returns the configured mock framework adapter module
|
|
646
|
+
# Returns the configured mock framework adapter module.
|
|
647
|
+
# @return [Symbol]
|
|
367
648
|
def mock_framework
|
|
368
|
-
|
|
649
|
+
if @mock_framework.nil?
|
|
650
|
+
begin
|
|
651
|
+
mock_with :rspec
|
|
652
|
+
rescue LoadError
|
|
653
|
+
mock_with :nothing
|
|
654
|
+
end
|
|
655
|
+
end
|
|
369
656
|
@mock_framework
|
|
370
657
|
end
|
|
371
658
|
|
|
372
|
-
# Delegates to mock_framework=(framework)
|
|
659
|
+
# Delegates to mock_framework=(framework).
|
|
373
660
|
def mock_framework=(framework)
|
|
374
661
|
mock_with framework
|
|
375
662
|
end
|
|
@@ -377,20 +664,21 @@ module RSpec
|
|
|
377
664
|
# Regexps used to exclude lines from backtraces.
|
|
378
665
|
#
|
|
379
666
|
# Excludes lines from ruby (and jruby) source, installed gems, anything
|
|
380
|
-
# in any "bin" directory, and any of the
|
|
667
|
+
# in any "bin" directory, and any of the RSpec libs (outside gem
|
|
381
668
|
# installs) by default.
|
|
382
669
|
#
|
|
383
670
|
# You can modify the list via the getter, or replace it with the setter.
|
|
384
671
|
#
|
|
385
672
|
# To override this behaviour and display a full backtrace, use
|
|
386
|
-
# `--backtrace`on the command line, in a `.rspec` file, or in the
|
|
673
|
+
# `--backtrace` on the command line, in a `.rspec` file, or in the
|
|
387
674
|
# `rspec_options` attribute of RSpec's rake task.
|
|
675
|
+
# @return [Array<Regexp>]
|
|
388
676
|
def backtrace_exclusion_patterns
|
|
389
677
|
@backtrace_formatter.exclusion_patterns
|
|
390
678
|
end
|
|
391
679
|
|
|
392
|
-
# Set regular expressions used to exclude lines in backtrace
|
|
393
|
-
# @param patterns [Regexp] set
|
|
680
|
+
# Set regular expressions used to exclude lines in backtrace.
|
|
681
|
+
# @param patterns [Array<Regexp>] set backtrace_formatter exclusion_patterns
|
|
394
682
|
def backtrace_exclusion_patterns=(patterns)
|
|
395
683
|
@backtrace_formatter.exclusion_patterns = patterns
|
|
396
684
|
end
|
|
@@ -403,16 +691,39 @@ module RSpec
|
|
|
403
691
|
# will be included.
|
|
404
692
|
#
|
|
405
693
|
# You can modify the list via the getter, or replace it with the setter.
|
|
694
|
+
# @return [Array<Regexp>]
|
|
406
695
|
def backtrace_inclusion_patterns
|
|
407
696
|
@backtrace_formatter.inclusion_patterns
|
|
408
697
|
end
|
|
409
698
|
|
|
410
|
-
# Set regular expressions used to include lines in backtrace
|
|
411
|
-
# @attr patterns [Regexp] set backtrace_formatter inclusion_patterns
|
|
699
|
+
# Set regular expressions used to include lines in backtrace.
|
|
700
|
+
# @attr patterns [Array<Regexp>] set backtrace_formatter inclusion_patterns
|
|
412
701
|
def backtrace_inclusion_patterns=(patterns)
|
|
413
702
|
@backtrace_formatter.inclusion_patterns = patterns
|
|
414
703
|
end
|
|
415
704
|
|
|
705
|
+
# Adds {#backtrace_exclusion_patterns} that will filter lines from
|
|
706
|
+
# the named gems from backtraces.
|
|
707
|
+
#
|
|
708
|
+
# @param gem_names [Array<String>] Names of the gems to filter
|
|
709
|
+
#
|
|
710
|
+
# @example
|
|
711
|
+
# RSpec.configure do |config|
|
|
712
|
+
# config.filter_gems_from_backtrace "rack", "rake"
|
|
713
|
+
# end
|
|
714
|
+
#
|
|
715
|
+
# @note The patterns this adds will match the named gems in their common
|
|
716
|
+
# locations (e.g. system gems, vendored with bundler, installed as a
|
|
717
|
+
# :git dependency with bundler, etc) but is not guaranteed to work for
|
|
718
|
+
# all possible gem locations. For example, if you have the gem source
|
|
719
|
+
# in a directory with a completely unrelated name, and use bundler's
|
|
720
|
+
# :path option, this will not filter it.
|
|
721
|
+
def filter_gems_from_backtrace(*gem_names)
|
|
722
|
+
gem_names.each do |name|
|
|
723
|
+
@backtrace_formatter.filter_gem(name)
|
|
724
|
+
end
|
|
725
|
+
end
|
|
726
|
+
|
|
416
727
|
# @private
|
|
417
728
|
MOCKING_ADAPTERS = {
|
|
418
729
|
:rspec => :RSpec,
|
|
@@ -445,28 +756,29 @@ module RSpec
|
|
|
445
756
|
# teardown_mocks_for_rspec
|
|
446
757
|
# - called after verify_mocks_for_rspec (even if there are errors)
|
|
447
758
|
#
|
|
448
|
-
# If the module responds to `configuration` and `mock_with` receives a
|
|
449
|
-
# it will yield the configuration object to the block e.g.
|
|
759
|
+
# If the module responds to `configuration` and `mock_with` receives a
|
|
760
|
+
# block, it will yield the configuration object to the block e.g.
|
|
450
761
|
#
|
|
451
762
|
# config.mock_with OtherMockFrameworkAdapter do |mod_config|
|
|
452
763
|
# mod_config.custom_setting = true
|
|
453
764
|
# end
|
|
454
765
|
def mock_with(framework)
|
|
455
|
-
framework_module =
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
766
|
+
framework_module =
|
|
767
|
+
if framework.is_a?(Module)
|
|
768
|
+
framework
|
|
769
|
+
else
|
|
770
|
+
const_name = MOCKING_ADAPTERS.fetch(framework) do
|
|
771
|
+
raise ArgumentError,
|
|
772
|
+
"Unknown mocking framework: #{framework.inspect}. " \
|
|
773
|
+
"Pass a module or one of #{MOCKING_ADAPTERS.keys.inspect}"
|
|
774
|
+
end
|
|
775
|
+
|
|
776
|
+
RSpec::Support.require_rspec_core "mocking_adapters/#{const_name.to_s.downcase}"
|
|
777
|
+
RSpec::Core::MockingAdapters.const_get(const_name)
|
|
462
778
|
end
|
|
463
779
|
|
|
464
|
-
RSpec::Support.require_rspec_core "mocking_adapters/#{const_name.to_s.downcase}"
|
|
465
|
-
RSpec::Core::MockingAdapters.const_get(const_name)
|
|
466
|
-
end
|
|
467
|
-
|
|
468
780
|
new_name, old_name = [framework_module, @mock_framework].map do |mod|
|
|
469
|
-
mod.respond_to?(:framework_name) ?
|
|
781
|
+
mod.respond_to?(:framework_name) ? mod.framework_name : :unnamed
|
|
470
782
|
end
|
|
471
783
|
|
|
472
784
|
unless new_name == old_name
|
|
@@ -474,7 +786,8 @@ module RSpec
|
|
|
474
786
|
end
|
|
475
787
|
|
|
476
788
|
if block_given?
|
|
477
|
-
raise "#{framework_module} must respond to `configuration` so that
|
|
789
|
+
raise "#{framework_module} must respond to `configuration` so that " \
|
|
790
|
+
"mock_with can yield it." unless framework_module.respond_to?(:configuration)
|
|
478
791
|
yield framework_module.configuration
|
|
479
792
|
end
|
|
480
793
|
|
|
@@ -483,11 +796,17 @@ module RSpec
|
|
|
483
796
|
|
|
484
797
|
# Returns the configured expectation framework adapter module(s)
|
|
485
798
|
def expectation_frameworks
|
|
486
|
-
|
|
799
|
+
if @expectation_frameworks.empty?
|
|
800
|
+
begin
|
|
801
|
+
expect_with :rspec
|
|
802
|
+
rescue LoadError
|
|
803
|
+
expect_with Module.new
|
|
804
|
+
end
|
|
805
|
+
end
|
|
487
806
|
@expectation_frameworks
|
|
488
807
|
end
|
|
489
808
|
|
|
490
|
-
# Delegates to expect_with(framework)
|
|
809
|
+
# Delegates to expect_with(framework).
|
|
491
810
|
def expectation_framework=(framework)
|
|
492
811
|
expect_with(framework)
|
|
493
812
|
end
|
|
@@ -522,7 +841,13 @@ module RSpec
|
|
|
522
841
|
framework
|
|
523
842
|
when :rspec
|
|
524
843
|
require 'rspec/expectations'
|
|
525
|
-
|
|
844
|
+
|
|
845
|
+
# Tag this exception class so our exception formatting logic knows
|
|
846
|
+
# that it satisfies the `MultipleExceptionError` interface.
|
|
847
|
+
::RSpec::Expectations::MultipleExpectationsNotMetError.__send__(
|
|
848
|
+
:include, MultipleExceptionError::InterfaceTag
|
|
849
|
+
)
|
|
850
|
+
|
|
526
851
|
::RSpec::Matchers
|
|
527
852
|
when :test_unit
|
|
528
853
|
require 'rspec/core/test_unit_assertions_adapter'
|
|
@@ -540,56 +865,79 @@ module RSpec
|
|
|
540
865
|
end
|
|
541
866
|
|
|
542
867
|
if block_given?
|
|
543
|
-
raise "expect_with only accepts a block with a single argument.
|
|
544
|
-
|
|
868
|
+
raise "expect_with only accepts a block with a single argument. " \
|
|
869
|
+
"Call expect_with #{modules.length} times, " \
|
|
870
|
+
"once with each argument, instead." if modules.length > 1
|
|
871
|
+
raise "#{modules.first} must respond to `configuration` so that " \
|
|
872
|
+
"expect_with can yield it." unless modules.first.respond_to?(:configuration)
|
|
545
873
|
yield modules.first.configuration
|
|
546
874
|
end
|
|
547
875
|
|
|
548
876
|
@expectation_frameworks.push(*modules)
|
|
549
877
|
end
|
|
550
878
|
|
|
551
|
-
# Check if full backtrace is enabled
|
|
879
|
+
# Check if full backtrace is enabled.
|
|
552
880
|
# @return [Boolean] is full backtrace enabled
|
|
553
881
|
def full_backtrace?
|
|
554
882
|
@backtrace_formatter.full_backtrace?
|
|
555
883
|
end
|
|
556
884
|
|
|
557
|
-
# Toggle full backtrace
|
|
885
|
+
# Toggle full backtrace.
|
|
558
886
|
# @attr true_or_false [Boolean] toggle full backtrace display
|
|
559
887
|
def full_backtrace=(true_or_false)
|
|
560
888
|
@backtrace_formatter.full_backtrace = true_or_false
|
|
561
889
|
end
|
|
562
890
|
|
|
563
|
-
#
|
|
564
|
-
#
|
|
891
|
+
# Enables color output if the output is a TTY. As of RSpec 3.6, this is
|
|
892
|
+
# the default behavior and this option is retained only for backwards
|
|
893
|
+
# compatibility.
|
|
565
894
|
#
|
|
895
|
+
# @deprecated No longer recommended because of complex behavior. Instead,
|
|
896
|
+
# rely on the fact that TTYs will display color by default, or set
|
|
897
|
+
# {#color_mode} to :on to display color on a non-TTY output.
|
|
898
|
+
# @see color_mode
|
|
566
899
|
# @see color_enabled?
|
|
567
900
|
# @return [Boolean]
|
|
568
901
|
def color
|
|
569
|
-
value_for(:color
|
|
902
|
+
value_for(:color) { @color }
|
|
570
903
|
end
|
|
571
904
|
|
|
572
|
-
#
|
|
573
|
-
#
|
|
574
|
-
#
|
|
905
|
+
# The mode for determining whether to display output in color. One of:
|
|
906
|
+
#
|
|
907
|
+
# - :automatic - the output will be in color if the output is a TTY (the
|
|
908
|
+
# default)
|
|
909
|
+
# - :on - the output will be in color, whether or not the output is a TTY
|
|
910
|
+
# - :off - the output will not be in color
|
|
911
|
+
#
|
|
912
|
+
# @see color_enabled?
|
|
575
913
|
# @return [Boolean]
|
|
576
|
-
def
|
|
577
|
-
|
|
914
|
+
def color_mode
|
|
915
|
+
value_for(:color_mode) { @color_mode }
|
|
578
916
|
end
|
|
579
917
|
|
|
580
|
-
#
|
|
581
|
-
# @
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
918
|
+
# Check if color is enabled for a particular output.
|
|
919
|
+
# @param output [IO] an output stream to use, defaults to the current
|
|
920
|
+
# `output_stream`
|
|
921
|
+
# @return [Boolean]
|
|
922
|
+
def color_enabled?(output=output_stream)
|
|
923
|
+
case color_mode
|
|
924
|
+
when :on then true
|
|
925
|
+
when :off then false
|
|
926
|
+
else # automatic
|
|
927
|
+
output_to_tty?(output) || (color && tty?)
|
|
590
928
|
end
|
|
591
929
|
end
|
|
592
930
|
|
|
931
|
+
# Set the color mode.
|
|
932
|
+
attr_writer :color_mode
|
|
933
|
+
|
|
934
|
+
# Toggle output color.
|
|
935
|
+
#
|
|
936
|
+
# @deprecated No longer recommended because of complex behavior. Instead,
|
|
937
|
+
# rely on the fact that TTYs will display color by default, or set
|
|
938
|
+
# {:color_mode} to :on to display color on a non-TTY output.
|
|
939
|
+
attr_writer :color
|
|
940
|
+
|
|
593
941
|
# @private
|
|
594
942
|
def libs=(libs)
|
|
595
943
|
libs.map do |lib|
|
|
@@ -601,7 +949,7 @@ module RSpec
|
|
|
601
949
|
# Run examples matching on `description` in all files to run.
|
|
602
950
|
# @param description [String, Regexp] the pattern to filter on
|
|
603
951
|
def full_description=(description)
|
|
604
|
-
filter_run :full_description => Regexp.union(*Array(description).map {|d| Regexp.new(d) })
|
|
952
|
+
filter_run :full_description => Regexp.union(*Array(description).map { |d| Regexp.new(d) })
|
|
605
953
|
end
|
|
606
954
|
|
|
607
955
|
# @return [Array] full description filter
|
|
@@ -610,19 +958,22 @@ module RSpec
|
|
|
610
958
|
end
|
|
611
959
|
|
|
612
960
|
# @overload add_formatter(formatter)
|
|
961
|
+
# @overload add_formatter(formatter, output)
|
|
613
962
|
#
|
|
614
|
-
#
|
|
615
|
-
#
|
|
616
|
-
# `
|
|
963
|
+
# @param formatter [Class, String, Object] formatter to use. Can be any of the
|
|
964
|
+
# string values supported from the CLI (`p`/`progress`,
|
|
965
|
+
# `d`/`doc`/`documentation`, `h`/`html`, or `j`/`json`), any
|
|
966
|
+
# class that implements the formatter protocol and has registered
|
|
967
|
+
# itself with RSpec as a formatter, or a formatter instance.
|
|
968
|
+
# @param output [String, IO] where the formatter will write its output.
|
|
969
|
+
# Can be an IO object or a string path to a file. If not provided,
|
|
970
|
+
# the configured `output_stream` (`$stdout`, by default) will be used.
|
|
617
971
|
#
|
|
618
|
-
#
|
|
972
|
+
# Adds a formatter to the set RSpec will use for this run.
|
|
619
973
|
#
|
|
620
|
-
#
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
def add_formatter(formatter_to_use, *paths)
|
|
624
|
-
paths << output_stream if paths.empty?
|
|
625
|
-
formatter_loader.add formatter_to_use, *paths
|
|
974
|
+
# @see RSpec::Core::Formatters::Protocol
|
|
975
|
+
def add_formatter(formatter, output=output_wrapper)
|
|
976
|
+
formatter_loader.add(formatter, output)
|
|
626
977
|
end
|
|
627
978
|
alias_method :formatter=, :add_formatter
|
|
628
979
|
|
|
@@ -680,14 +1031,14 @@ module RSpec
|
|
|
680
1031
|
end
|
|
681
1032
|
end
|
|
682
1033
|
|
|
683
|
-
# @
|
|
1034
|
+
# @return [RSpec::Core::Reporter] the currently configured reporter
|
|
684
1035
|
def reporter
|
|
685
1036
|
# @reporter_buffer should only ever be set in this method to cover
|
|
686
1037
|
# initialization of @reporter.
|
|
687
1038
|
@reporter_buffer || @reporter ||=
|
|
688
1039
|
begin
|
|
689
1040
|
@reporter_buffer = DeprecationReporterBuffer.new
|
|
690
|
-
formatter_loader.
|
|
1041
|
+
formatter_loader.prepare_default output_wrapper, deprecation_stream
|
|
691
1042
|
@reporter_buffer.play_onto(formatter_loader.reporter)
|
|
692
1043
|
@reporter_buffer = nil
|
|
693
1044
|
formatter_loader.reporter
|
|
@@ -696,10 +1047,10 @@ module RSpec
|
|
|
696
1047
|
|
|
697
1048
|
# @api private
|
|
698
1049
|
#
|
|
699
|
-
# Defaults `profile_examples` to 10 examples when `@profile_examples` is
|
|
700
|
-
#
|
|
1050
|
+
# Defaults `profile_examples` to 10 examples when `@profile_examples` is
|
|
1051
|
+
# `true`.
|
|
701
1052
|
def profile_examples
|
|
702
|
-
profile = value_for(:profile_examples
|
|
1053
|
+
profile = value_for(:profile_examples) { @profile_examples }
|
|
703
1054
|
if profile && !profile.is_a?(Integer)
|
|
704
1055
|
10
|
|
705
1056
|
else
|
|
@@ -710,17 +1061,66 @@ module RSpec
|
|
|
710
1061
|
# @private
|
|
711
1062
|
def files_or_directories_to_run=(*files)
|
|
712
1063
|
files = files.flatten
|
|
713
|
-
|
|
1064
|
+
|
|
1065
|
+
if (command == 'rspec' || Runner.running_in_drb?) && default_path && files.empty?
|
|
1066
|
+
files << default_path
|
|
1067
|
+
end
|
|
1068
|
+
|
|
714
1069
|
@files_or_directories_to_run = files
|
|
715
1070
|
@files_to_run = nil
|
|
716
1071
|
end
|
|
717
1072
|
|
|
718
|
-
# The spec files RSpec will run
|
|
1073
|
+
# The spec files RSpec will run.
|
|
719
1074
|
# @return [Array] specified files about to run
|
|
720
1075
|
def files_to_run
|
|
721
1076
|
@files_to_run ||= get_files_to_run(@files_or_directories_to_run)
|
|
722
1077
|
end
|
|
723
1078
|
|
|
1079
|
+
# @private
|
|
1080
|
+
def last_run_statuses
|
|
1081
|
+
@last_run_statuses ||= Hash.new(UNKNOWN_STATUS).tap do |statuses|
|
|
1082
|
+
if (path = example_status_persistence_file_path)
|
|
1083
|
+
begin
|
|
1084
|
+
ExampleStatusPersister.load_from(path).inject(statuses) do |hash, example|
|
|
1085
|
+
status = example[:status]
|
|
1086
|
+
status = UNKNOWN_STATUS unless VALID_STATUSES.include?(status)
|
|
1087
|
+
hash[example.fetch(:example_id)] = status
|
|
1088
|
+
hash
|
|
1089
|
+
end
|
|
1090
|
+
rescue SystemCallError => e
|
|
1091
|
+
RSpec.warning "Could not read from #{path.inspect} (configured as " \
|
|
1092
|
+
"`config.example_status_persistence_file_path`) due " \
|
|
1093
|
+
"to a system error: #{e.inspect}. Please check that " \
|
|
1094
|
+
"the config option is set to an accessible, valid " \
|
|
1095
|
+
"file path", :call_site => nil
|
|
1096
|
+
end
|
|
1097
|
+
end
|
|
1098
|
+
end
|
|
1099
|
+
end
|
|
1100
|
+
|
|
1101
|
+
# @private
|
|
1102
|
+
UNKNOWN_STATUS = "unknown".freeze
|
|
1103
|
+
|
|
1104
|
+
# @private
|
|
1105
|
+
FAILED_STATUS = "failed".freeze
|
|
1106
|
+
|
|
1107
|
+
# @private
|
|
1108
|
+
PASSED_STATUS = "passed".freeze
|
|
1109
|
+
|
|
1110
|
+
# @private
|
|
1111
|
+
PENDING_STATUS = "pending".freeze
|
|
1112
|
+
|
|
1113
|
+
# @private
|
|
1114
|
+
VALID_STATUSES = [UNKNOWN_STATUS, FAILED_STATUS, PASSED_STATUS, PENDING_STATUS]
|
|
1115
|
+
|
|
1116
|
+
# @private
|
|
1117
|
+
def spec_files_with_failures
|
|
1118
|
+
@spec_files_with_failures ||= last_run_statuses.inject(Set.new) do |files, (id, status)|
|
|
1119
|
+
files << Example.parse_id(id).first if status == FAILED_STATUS
|
|
1120
|
+
files
|
|
1121
|
+
end.to_a
|
|
1122
|
+
end
|
|
1123
|
+
|
|
724
1124
|
# Creates a method that delegates to `example` including the submitted
|
|
725
1125
|
# `args`. Used internally to add variants of `example` like `pending`:
|
|
726
1126
|
# @param name [String] example name alias
|
|
@@ -729,8 +1129,8 @@ module RSpec
|
|
|
729
1129
|
# @note The specific example alias below (`pending`) is already
|
|
730
1130
|
# defined for you.
|
|
731
1131
|
# @note Use with caution. This extends the language used in your
|
|
732
|
-
# specs, but does not add any additional documentation.
|
|
733
|
-
# in
|
|
1132
|
+
# specs, but does not add any additional documentation. We use this
|
|
1133
|
+
# in RSpec to define methods like `focus` and `xit`, but we also add
|
|
734
1134
|
# docs for those methods.
|
|
735
1135
|
#
|
|
736
1136
|
# @example
|
|
@@ -740,7 +1140,7 @@ module RSpec
|
|
|
740
1140
|
#
|
|
741
1141
|
# # This lets you do this:
|
|
742
1142
|
#
|
|
743
|
-
# describe Thing do
|
|
1143
|
+
# RSpec.describe Thing do
|
|
744
1144
|
# pending "does something" do
|
|
745
1145
|
# thing = Thing.new
|
|
746
1146
|
# end
|
|
@@ -748,7 +1148,7 @@ module RSpec
|
|
|
748
1148
|
#
|
|
749
1149
|
# # ... which is the equivalent of
|
|
750
1150
|
#
|
|
751
|
-
# describe Thing do
|
|
1151
|
+
# RSpec.describe Thing do
|
|
752
1152
|
# it "does something", :pending => true do
|
|
753
1153
|
# thing = Thing.new
|
|
754
1154
|
# end
|
|
@@ -801,7 +1201,7 @@ module RSpec
|
|
|
801
1201
|
#
|
|
802
1202
|
# # allows the user to include a shared example group like:
|
|
803
1203
|
#
|
|
804
|
-
# describe Entity do
|
|
1204
|
+
# RSpec.describe Entity do
|
|
805
1205
|
# it_has_behavior 'sortability' do
|
|
806
1206
|
# let(:sortable) { Entity.new }
|
|
807
1207
|
# end
|
|
@@ -813,10 +1213,10 @@ module RSpec
|
|
|
813
1213
|
# # ...sortability examples here
|
|
814
1214
|
#
|
|
815
1215
|
# @note Use with caution. This extends the language used in your
|
|
816
|
-
# specs, but does not add any additional documentation.
|
|
817
|
-
# in
|
|
1216
|
+
# specs, but does not add any additional documentation. We use this
|
|
1217
|
+
# in RSpec to define `it_should_behave_like` (for backward
|
|
818
1218
|
# compatibility), but we also add docs for that method.
|
|
819
|
-
def alias_it_behaves_like_to(new_name, report_label
|
|
1219
|
+
def alias_it_behaves_like_to(new_name, report_label='')
|
|
820
1220
|
RSpec::Core::ExampleGroup.define_nested_shared_group_method(new_name, report_label)
|
|
821
1221
|
end
|
|
822
1222
|
alias_method :alias_it_should_behave_like_to, :alias_it_behaves_like_to
|
|
@@ -831,32 +1231,48 @@ module RSpec
|
|
|
831
1231
|
# or config files (e.g. `.rspec`).
|
|
832
1232
|
#
|
|
833
1233
|
# @example
|
|
834
|
-
# #
|
|
1234
|
+
# # Given this declaration.
|
|
835
1235
|
# describe "something", :foo => 'bar' do
|
|
836
1236
|
# # ...
|
|
837
1237
|
# end
|
|
838
1238
|
#
|
|
839
|
-
# #
|
|
1239
|
+
# # Any of the following will include that group.
|
|
840
1240
|
# config.filter_run_including :foo => 'bar'
|
|
841
1241
|
# config.filter_run_including :foo => /^ba/
|
|
842
1242
|
# config.filter_run_including :foo => lambda {|v| v == 'bar'}
|
|
843
1243
|
# config.filter_run_including :foo => lambda {|v,m| m[:foo] == 'bar'}
|
|
844
1244
|
#
|
|
845
|
-
# #
|
|
1245
|
+
# # Given a proc with an arity of 1, the lambda is passed the value
|
|
1246
|
+
# # related to the key, e.g.
|
|
846
1247
|
# config.filter_run_including :foo => lambda {|v| v == 'bar'}
|
|
847
1248
|
#
|
|
848
|
-
# #
|
|
849
|
-
# # and the metadata itself e.g.
|
|
1249
|
+
# # Given a proc with an arity of 2, the lambda is passed the value
|
|
1250
|
+
# # related to the key, and the metadata itself e.g.
|
|
850
1251
|
# config.filter_run_including :foo => lambda {|v,m| m[:foo] == 'bar'}
|
|
851
1252
|
#
|
|
852
1253
|
# filter_run_including :foo # same as filter_run_including :foo => true
|
|
853
1254
|
def filter_run_including(*args)
|
|
854
1255
|
meta = Metadata.build_hash_from(args, :warn_about_example_group_filtering)
|
|
855
1256
|
filter_manager.include_with_low_priority meta
|
|
1257
|
+
static_config_filter_manager.include_with_low_priority Metadata.deep_hash_dup(meta)
|
|
856
1258
|
end
|
|
857
|
-
|
|
858
1259
|
alias_method :filter_run, :filter_run_including
|
|
859
1260
|
|
|
1261
|
+
# Applies the provided filter only if any of examples match, in constrast
|
|
1262
|
+
# to {#filter_run}, which always applies even if no examples match, in
|
|
1263
|
+
# which case no examples will be run. This allows you to leave configured
|
|
1264
|
+
# filters in place that are intended only for temporary use. The most common
|
|
1265
|
+
# example is focus filtering: `config.filter_run_when_matching :focus`.
|
|
1266
|
+
# With that configured, you can temporarily focus an example or group
|
|
1267
|
+
# by tagging it with `:focus` metadata, or prefixing it with an `f`
|
|
1268
|
+
# (as in `fdescribe`, `fcontext` and `fit`) since those are aliases for
|
|
1269
|
+
# `describe`/`context`/`it` with `:focus` metadata.
|
|
1270
|
+
def filter_run_when_matching(*args)
|
|
1271
|
+
when_first_matching_example_defined(*args) do
|
|
1272
|
+
filter_run(*args)
|
|
1273
|
+
end
|
|
1274
|
+
end
|
|
1275
|
+
|
|
860
1276
|
# Clears and reassigns the `inclusion_filter`. Set to `nil` if you don't
|
|
861
1277
|
# want any inclusion filter at all.
|
|
862
1278
|
#
|
|
@@ -889,28 +1305,30 @@ module RSpec
|
|
|
889
1305
|
# or config files (e.g. `.rspec`).
|
|
890
1306
|
#
|
|
891
1307
|
# @example
|
|
892
|
-
# #
|
|
1308
|
+
# # Given this declaration.
|
|
893
1309
|
# describe "something", :foo => 'bar' do
|
|
894
1310
|
# # ...
|
|
895
1311
|
# end
|
|
896
1312
|
#
|
|
897
|
-
# #
|
|
1313
|
+
# # Any of the following will exclude that group.
|
|
898
1314
|
# config.filter_run_excluding :foo => 'bar'
|
|
899
1315
|
# config.filter_run_excluding :foo => /^ba/
|
|
900
1316
|
# config.filter_run_excluding :foo => lambda {|v| v == 'bar'}
|
|
901
1317
|
# config.filter_run_excluding :foo => lambda {|v,m| m[:foo] == 'bar'}
|
|
902
1318
|
#
|
|
903
|
-
# #
|
|
1319
|
+
# # Given a proc with an arity of 1, the lambda is passed the value
|
|
1320
|
+
# # related to the key, e.g.
|
|
904
1321
|
# config.filter_run_excluding :foo => lambda {|v| v == 'bar'}
|
|
905
1322
|
#
|
|
906
|
-
# #
|
|
907
|
-
# # and the metadata itself e.g.
|
|
1323
|
+
# # Given a proc with an arity of 2, the lambda is passed the value
|
|
1324
|
+
# # related to the key, and the metadata itself e.g.
|
|
908
1325
|
# config.filter_run_excluding :foo => lambda {|v,m| m[:foo] == 'bar'}
|
|
909
1326
|
#
|
|
910
1327
|
# filter_run_excluding :foo # same as filter_run_excluding :foo => true
|
|
911
1328
|
def filter_run_excluding(*args)
|
|
912
1329
|
meta = Metadata.build_hash_from(args, :warn_about_example_group_filtering)
|
|
913
1330
|
filter_manager.exclude_with_low_priority meta
|
|
1331
|
+
static_config_filter_manager.exclude_with_low_priority Metadata.deep_hash_dup(meta)
|
|
914
1332
|
end
|
|
915
1333
|
|
|
916
1334
|
# Clears and reassigns the `exclusion_filter`. Set to `nil` if you don't
|
|
@@ -932,8 +1350,8 @@ module RSpec
|
|
|
932
1350
|
end
|
|
933
1351
|
|
|
934
1352
|
# Tells RSpec to include `mod` in example groups. Methods defined in
|
|
935
|
-
# `mod` are exposed to examples (not example groups).
|
|
936
|
-
# constrain the groups in which to include the module.
|
|
1353
|
+
# `mod` are exposed to examples (not example groups). Use `filters` to
|
|
1354
|
+
# constrain the groups or examples in which to include the module.
|
|
937
1355
|
#
|
|
938
1356
|
# @example
|
|
939
1357
|
#
|
|
@@ -943,6 +1361,12 @@ module RSpec
|
|
|
943
1361
|
# end
|
|
944
1362
|
# end
|
|
945
1363
|
#
|
|
1364
|
+
# module PreferencesHelpers
|
|
1365
|
+
# def preferences(user, preferences = {})
|
|
1366
|
+
# # ...
|
|
1367
|
+
# end
|
|
1368
|
+
# end
|
|
1369
|
+
#
|
|
946
1370
|
# module UserHelpers
|
|
947
1371
|
# def users(username)
|
|
948
1372
|
# # ...
|
|
@@ -950,26 +1374,87 @@ module RSpec
|
|
|
950
1374
|
# end
|
|
951
1375
|
#
|
|
952
1376
|
# RSpec.configure do |config|
|
|
953
|
-
# config.include(UserHelpers) # included in all
|
|
1377
|
+
# config.include(UserHelpers) # included in all groups
|
|
1378
|
+
#
|
|
1379
|
+
# # included in examples with `:preferences` metadata
|
|
1380
|
+
# config.include(PreferenceHelpers, :preferences)
|
|
1381
|
+
#
|
|
1382
|
+
# # included in examples with `:type => :request` metadata
|
|
954
1383
|
# config.include(AuthenticationHelpers, :type => :request)
|
|
955
1384
|
# end
|
|
956
1385
|
#
|
|
957
|
-
# describe "edit profile", :type => :request do
|
|
1386
|
+
# describe "edit profile", :preferences, :type => :request do
|
|
958
1387
|
# it "can be viewed by owning user" do
|
|
959
|
-
# login_as users(:jdoe)
|
|
1388
|
+
# login_as preferences(users(:jdoe), :lang => 'es')
|
|
960
1389
|
# get "/profiles/jdoe"
|
|
961
1390
|
# assert_select ".username", :text => 'jdoe'
|
|
962
1391
|
# end
|
|
963
1392
|
# end
|
|
964
1393
|
#
|
|
1394
|
+
# @note Filtered module inclusions can also be applied to
|
|
1395
|
+
# individual examples that have matching metadata. Just like
|
|
1396
|
+
# Ruby's object model is that every object has a singleton class
|
|
1397
|
+
# which has only a single instance, RSpec's model is that every
|
|
1398
|
+
# example has a singleton example group containing just the one
|
|
1399
|
+
# example.
|
|
1400
|
+
#
|
|
1401
|
+
# @see #include_context
|
|
965
1402
|
# @see #extend
|
|
1403
|
+
# @see #prepend
|
|
966
1404
|
def include(mod, *filters)
|
|
967
|
-
|
|
968
|
-
|
|
1405
|
+
define_mixed_in_module(mod, filters, @include_modules, :include) do |group|
|
|
1406
|
+
safe_include(mod, group)
|
|
1407
|
+
end
|
|
1408
|
+
end
|
|
1409
|
+
|
|
1410
|
+
# Tells RSpec to include the named shared example group in example groups.
|
|
1411
|
+
# Use `filters` to constrain the groups or examples in which to include
|
|
1412
|
+
# the example group.
|
|
1413
|
+
#
|
|
1414
|
+
# @example
|
|
1415
|
+
#
|
|
1416
|
+
# RSpec.shared_context "example admin user" do
|
|
1417
|
+
# let(:admin_user) { create_user(:admin) }
|
|
1418
|
+
# end
|
|
1419
|
+
#
|
|
1420
|
+
# RSpec.shared_context "example guest user" do
|
|
1421
|
+
# let(:guest_user) { create_user(:guest) }
|
|
1422
|
+
# end
|
|
1423
|
+
#
|
|
1424
|
+
# RSpec.configure do |config|
|
|
1425
|
+
# config.include_context "example guest user", :type => :request
|
|
1426
|
+
# config.include_context "example admin user", :admin, :type => :request
|
|
1427
|
+
# end
|
|
1428
|
+
#
|
|
1429
|
+
# RSpec.describe "The admin page", :type => :request do
|
|
1430
|
+
# it "can be viewed by admins", :admin do
|
|
1431
|
+
# login_with admin_user
|
|
1432
|
+
# get "/admin"
|
|
1433
|
+
# expect(response).to be_ok
|
|
1434
|
+
# end
|
|
1435
|
+
#
|
|
1436
|
+
# it "cannot be viewed by guests" do
|
|
1437
|
+
# login_with guest_user
|
|
1438
|
+
# get "/admin"
|
|
1439
|
+
# expect(response).to be_forbidden
|
|
1440
|
+
# end
|
|
1441
|
+
# end
|
|
1442
|
+
#
|
|
1443
|
+
# @note Filtered context inclusions can also be applied to
|
|
1444
|
+
# individual examples that have matching metadata. Just like
|
|
1445
|
+
# Ruby's object model is that every object has a singleton class
|
|
1446
|
+
# which has only a single instance, RSpec's model is that every
|
|
1447
|
+
# example has a singleton example group containing just the one
|
|
1448
|
+
# example.
|
|
1449
|
+
#
|
|
1450
|
+
# @see #include
|
|
1451
|
+
def include_context(shared_group_name, *filters)
|
|
1452
|
+
shared_module = world.shared_example_group_registry.find([:main], shared_group_name)
|
|
1453
|
+
include shared_module, *filters
|
|
969
1454
|
end
|
|
970
1455
|
|
|
971
|
-
# Tells RSpec to extend example groups with `mod`.
|
|
972
|
-
# `mod` are exposed to example groups (not examples).
|
|
1456
|
+
# Tells RSpec to extend example groups with `mod`. Methods defined in
|
|
1457
|
+
# `mod` are exposed to example groups (not examples). Use `filters` to
|
|
973
1458
|
# constrain the groups to extend.
|
|
974
1459
|
#
|
|
975
1460
|
# Similar to `include`, but behavior is added to example groups, which
|
|
@@ -984,12 +1469,20 @@ module RSpec
|
|
|
984
1469
|
# end
|
|
985
1470
|
# end
|
|
986
1471
|
#
|
|
1472
|
+
# module PermissionHelpers
|
|
1473
|
+
# def define_permissions
|
|
1474
|
+
# # ...
|
|
1475
|
+
# end
|
|
1476
|
+
# end
|
|
1477
|
+
#
|
|
987
1478
|
# RSpec.configure do |config|
|
|
988
1479
|
# config.extend(UiHelpers, :type => :request)
|
|
1480
|
+
# config.extend(PermissionHelpers, :with_permissions, :type => :request)
|
|
989
1481
|
# end
|
|
990
1482
|
#
|
|
991
|
-
# describe "edit profile", :type => :request do
|
|
1483
|
+
# describe "edit profile", :with_permissions, :type => :request do
|
|
992
1484
|
# run_in_browser
|
|
1485
|
+
# define_permissions
|
|
993
1486
|
#
|
|
994
1487
|
# it "does stuff in the client" do
|
|
995
1488
|
# # ...
|
|
@@ -997,46 +1490,100 @@ module RSpec
|
|
|
997
1490
|
# end
|
|
998
1491
|
#
|
|
999
1492
|
# @see #include
|
|
1493
|
+
# @see #prepend
|
|
1000
1494
|
def extend(mod, *filters)
|
|
1001
|
-
|
|
1002
|
-
|
|
1495
|
+
define_mixed_in_module(mod, filters, @extend_modules, :extend) do |group|
|
|
1496
|
+
safe_extend(mod, group)
|
|
1497
|
+
end
|
|
1498
|
+
end
|
|
1499
|
+
|
|
1500
|
+
if RSpec::Support::RubyFeatures.module_prepends_supported?
|
|
1501
|
+
# Tells RSpec to prepend example groups with `mod`. Methods defined in
|
|
1502
|
+
# `mod` are exposed to examples (not example groups). Use `filters` to
|
|
1503
|
+
# constrain the groups in which to prepend the module.
|
|
1504
|
+
#
|
|
1505
|
+
# Similar to `include`, but module is included before the example group's class
|
|
1506
|
+
# in the ancestor chain.
|
|
1507
|
+
#
|
|
1508
|
+
# @example
|
|
1509
|
+
#
|
|
1510
|
+
# module OverrideMod
|
|
1511
|
+
# def override_me
|
|
1512
|
+
# "overridden"
|
|
1513
|
+
# end
|
|
1514
|
+
# end
|
|
1515
|
+
#
|
|
1516
|
+
# RSpec.configure do |config|
|
|
1517
|
+
# config.prepend(OverrideMod, :method => :prepend)
|
|
1518
|
+
# end
|
|
1519
|
+
#
|
|
1520
|
+
# describe "overriding example's class", :method => :prepend do
|
|
1521
|
+
# it "finds the user" do
|
|
1522
|
+
# self.class.class_eval do
|
|
1523
|
+
# def override_me
|
|
1524
|
+
# end
|
|
1525
|
+
# end
|
|
1526
|
+
# override_me # => "overridden"
|
|
1527
|
+
# # ...
|
|
1528
|
+
# end
|
|
1529
|
+
# end
|
|
1530
|
+
#
|
|
1531
|
+
# @see #include
|
|
1532
|
+
# @see #extend
|
|
1533
|
+
def prepend(mod, *filters)
|
|
1534
|
+
define_mixed_in_module(mod, filters, @prepend_modules, :prepend) do |group|
|
|
1535
|
+
safe_prepend(mod, group)
|
|
1536
|
+
end
|
|
1537
|
+
end
|
|
1003
1538
|
end
|
|
1004
1539
|
|
|
1005
1540
|
# @private
|
|
1006
1541
|
#
|
|
1007
|
-
# Used internally to extend a group with modules using `include` and/or
|
|
1542
|
+
# Used internally to extend a group with modules using `include`, `prepend` and/or
|
|
1008
1543
|
# `extend`.
|
|
1009
1544
|
def configure_group(group)
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1545
|
+
group.hooks.register_globals(group, hooks)
|
|
1546
|
+
|
|
1547
|
+
configure_group_with group, @include_modules, :safe_include
|
|
1548
|
+
configure_group_with group, @extend_modules, :safe_extend
|
|
1549
|
+
configure_group_with group, @prepend_modules, :safe_prepend
|
|
1014
1550
|
end
|
|
1015
1551
|
|
|
1016
1552
|
# @private
|
|
1017
|
-
|
|
1018
|
-
|
|
1553
|
+
#
|
|
1554
|
+
# Used internally to extend the singleton class of a single example's
|
|
1555
|
+
# example group instance with modules using `include` and/or `extend`.
|
|
1556
|
+
def configure_example(example, example_hooks)
|
|
1557
|
+
example_hooks.register_global_singleton_context_hooks(example, hooks)
|
|
1558
|
+
singleton_group = example.example_group_instance.singleton_class
|
|
1559
|
+
|
|
1560
|
+
# We replace the metadata so that SharedExampleGroupModule#included
|
|
1561
|
+
# has access to the example's metadata[:location].
|
|
1562
|
+
singleton_group.with_replaced_metadata(example.metadata) do
|
|
1563
|
+
modules = @include_modules.items_for(example.metadata)
|
|
1564
|
+
modules.each do |mod|
|
|
1565
|
+
safe_include(mod, example.example_group_instance.singleton_class)
|
|
1566
|
+
end
|
|
1567
|
+
|
|
1568
|
+
MemoizedHelpers.define_helpers_on(singleton_group) unless modules.empty?
|
|
1569
|
+
end
|
|
1019
1570
|
end
|
|
1020
1571
|
|
|
1021
1572
|
# @private
|
|
1022
1573
|
def requires=(paths)
|
|
1023
1574
|
directories = ['lib', default_path].select { |p| File.directory? p }
|
|
1024
1575
|
RSpec::Core::RubyProject.add_to_load_path(*directories)
|
|
1025
|
-
paths.each {|path| require path}
|
|
1576
|
+
paths.each { |path| load_file_handling_errors(:require, path) }
|
|
1026
1577
|
@requires += paths
|
|
1027
1578
|
end
|
|
1028
1579
|
|
|
1029
1580
|
# @private
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
host.extend(mod) unless host.singleton_class < mod
|
|
1034
|
-
end
|
|
1035
|
-
else
|
|
1036
|
-
# @private
|
|
1037
|
-
def safe_extend(mod, host)
|
|
1038
|
-
host.extend(mod) unless (class << host; self; end).included_modules.include?(mod)
|
|
1581
|
+
def in_project_source_dir_regex
|
|
1582
|
+
regexes = project_source_dirs.map do |dir|
|
|
1583
|
+
/\A#{Regexp.escape(File.expand_path(dir))}\//
|
|
1039
1584
|
end
|
|
1585
|
+
|
|
1586
|
+
Regexp.union(regexes)
|
|
1040
1587
|
end
|
|
1041
1588
|
|
|
1042
1589
|
# @private
|
|
@@ -1055,7 +1602,22 @@ module RSpec
|
|
|
1055
1602
|
|
|
1056
1603
|
# @private
|
|
1057
1604
|
def load_spec_files
|
|
1058
|
-
|
|
1605
|
+
# Note which spec files world is already aware of.
|
|
1606
|
+
# This is generally only needed for when the user runs
|
|
1607
|
+
# `ruby path/to/spec.rb` (and loads `rspec/autorun`) --
|
|
1608
|
+
# in that case, the spec file was loaded by `ruby` and
|
|
1609
|
+
# isn't loaded by us here so we only know about it because
|
|
1610
|
+
# of an example group being registered in it.
|
|
1611
|
+
world.registered_example_group_files.each do |f|
|
|
1612
|
+
loaded_spec_files << f # the registered files are already expended absolute paths
|
|
1613
|
+
end
|
|
1614
|
+
|
|
1615
|
+
files_to_run.uniq.each do |f|
|
|
1616
|
+
file = File.expand_path(f)
|
|
1617
|
+
load_file_handling_errors(:load, file)
|
|
1618
|
+
loaded_spec_files << file
|
|
1619
|
+
end
|
|
1620
|
+
|
|
1059
1621
|
@spec_files_loaded = true
|
|
1060
1622
|
end
|
|
1061
1623
|
|
|
@@ -1065,7 +1627,8 @@ module RSpec
|
|
|
1065
1627
|
# Formats the docstring output using the block provided.
|
|
1066
1628
|
#
|
|
1067
1629
|
# @example
|
|
1068
|
-
# # This will strip the descriptions of both examples and example
|
|
1630
|
+
# # This will strip the descriptions of both examples and example
|
|
1631
|
+
# # groups.
|
|
1069
1632
|
# RSpec.configure do |config|
|
|
1070
1633
|
# config.format_docstrings { |s| s.strip }
|
|
1071
1634
|
# end
|
|
@@ -1079,8 +1642,6 @@ module RSpec
|
|
|
1079
1642
|
end
|
|
1080
1643
|
|
|
1081
1644
|
# @private
|
|
1082
|
-
# @macro [attach] delegate_to_ordering_manager
|
|
1083
|
-
# @!method $1
|
|
1084
1645
|
def self.delegate_to_ordering_manager(*methods)
|
|
1085
1646
|
methods.each do |method|
|
|
1086
1647
|
define_method method do |*args, &block|
|
|
@@ -1089,12 +1650,12 @@ module RSpec
|
|
|
1089
1650
|
end
|
|
1090
1651
|
end
|
|
1091
1652
|
|
|
1092
|
-
#
|
|
1653
|
+
# @!method seed=(value)
|
|
1093
1654
|
#
|
|
1094
1655
|
# Sets the seed value and sets the default global ordering to random.
|
|
1095
1656
|
delegate_to_ordering_manager :seed=
|
|
1096
1657
|
|
|
1097
|
-
#
|
|
1658
|
+
# @!method seed
|
|
1098
1659
|
# Seed for random ordering (default: generated randomly each run).
|
|
1099
1660
|
#
|
|
1100
1661
|
# When you run specs with `--order random`, RSpec generates a random seed
|
|
@@ -1108,20 +1669,28 @@ module RSpec
|
|
|
1108
1669
|
# don't accidentally leave the seed encoded.
|
|
1109
1670
|
delegate_to_ordering_manager :seed
|
|
1110
1671
|
|
|
1111
|
-
#
|
|
1672
|
+
# @!method order=(value)
|
|
1673
|
+
#
|
|
1674
|
+
# Sets the default global ordering strategy. By default this can be one
|
|
1675
|
+
# of `:defined`, `:random`, but is customizable through the
|
|
1676
|
+
# `register_ordering` API. If order is set to `'rand:<seed>'`,
|
|
1677
|
+
# the seed will also be set.
|
|
1112
1678
|
#
|
|
1113
|
-
#
|
|
1679
|
+
# @see #register_ordering
|
|
1114
1680
|
delegate_to_ordering_manager :order=
|
|
1115
1681
|
|
|
1116
|
-
#
|
|
1682
|
+
# @!method register_ordering(name)
|
|
1683
|
+
#
|
|
1117
1684
|
# Registers a named ordering strategy that can later be
|
|
1118
1685
|
# used to order an example group's subgroups by adding
|
|
1119
1686
|
# `:order => <name>` metadata to the example group.
|
|
1120
1687
|
#
|
|
1121
1688
|
# @param name [Symbol] The name of the ordering.
|
|
1122
1689
|
# @yield Block that will order the given examples or example groups
|
|
1123
|
-
# @yieldparam list [Array<RSpec::Core::Example>,
|
|
1124
|
-
#
|
|
1690
|
+
# @yieldparam list [Array<RSpec::Core::Example>,
|
|
1691
|
+
# Array<RSpec::Core::ExampleGroup>] The examples or groups to order
|
|
1692
|
+
# @yieldreturn [Array<RSpec::Core::Example>,
|
|
1693
|
+
# Array<RSpec::Core::ExampleGroup>] The re-ordered examples or groups
|
|
1125
1694
|
#
|
|
1126
1695
|
# @example
|
|
1127
1696
|
# RSpec.configure do |rspec|
|
|
@@ -1130,19 +1699,38 @@ module RSpec
|
|
|
1130
1699
|
# end
|
|
1131
1700
|
# end
|
|
1132
1701
|
#
|
|
1133
|
-
# describe MyClass, :order => :reverse do
|
|
1702
|
+
# RSpec.describe 'MyClass', :order => :reverse do
|
|
1134
1703
|
# # ...
|
|
1135
1704
|
# end
|
|
1136
1705
|
#
|
|
1137
1706
|
# @note Pass the symbol `:global` to set the ordering strategy that
|
|
1138
1707
|
# will be used to order the top-level example groups and any example
|
|
1139
1708
|
# groups that do not have declared `:order` metadata.
|
|
1709
|
+
#
|
|
1710
|
+
# @example
|
|
1711
|
+
# RSpec.configure do |rspec|
|
|
1712
|
+
# rspec.register_ordering :global do |examples|
|
|
1713
|
+
# acceptance, other = examples.partition do |example|
|
|
1714
|
+
# example.metadata[:type] == :acceptance
|
|
1715
|
+
# end
|
|
1716
|
+
# other + acceptance
|
|
1717
|
+
# end
|
|
1718
|
+
# end
|
|
1719
|
+
#
|
|
1720
|
+
# RSpec.describe 'MyClass', :type => :acceptance do
|
|
1721
|
+
# # will run last
|
|
1722
|
+
# end
|
|
1723
|
+
#
|
|
1724
|
+
# RSpec.describe 'MyClass' do
|
|
1725
|
+
# # will run first
|
|
1726
|
+
# end
|
|
1727
|
+
#
|
|
1140
1728
|
delegate_to_ordering_manager :register_ordering
|
|
1141
1729
|
|
|
1142
1730
|
# @private
|
|
1143
1731
|
delegate_to_ordering_manager :seed_used?, :ordering_registry
|
|
1144
1732
|
|
|
1145
|
-
# Set Ruby warnings on or off
|
|
1733
|
+
# Set Ruby warnings on or off.
|
|
1146
1734
|
def warnings=(value)
|
|
1147
1735
|
$VERBOSE = !!value
|
|
1148
1736
|
end
|
|
@@ -1152,6 +1740,25 @@ module RSpec
|
|
|
1152
1740
|
$VERBOSE
|
|
1153
1741
|
end
|
|
1154
1742
|
|
|
1743
|
+
# @private
|
|
1744
|
+
RAISE_ERROR_WARNING_NOTIFIER = lambda { |message| raise message }
|
|
1745
|
+
|
|
1746
|
+
# Turns warnings into errors. This can be useful when
|
|
1747
|
+
# you want RSpec to run in a 'strict' no warning situation.
|
|
1748
|
+
#
|
|
1749
|
+
# @example
|
|
1750
|
+
#
|
|
1751
|
+
# RSpec.configure do |rspec|
|
|
1752
|
+
# rspec.raise_on_warning = true
|
|
1753
|
+
# end
|
|
1754
|
+
def raise_on_warning=(value)
|
|
1755
|
+
if value
|
|
1756
|
+
RSpec::Support.warning_notifier = RAISE_ERROR_WARNING_NOTIFIER
|
|
1757
|
+
else
|
|
1758
|
+
RSpec::Support.warning_notifier = RSpec::Support::DEFAULT_WARNING_NOTIFIER
|
|
1759
|
+
end
|
|
1760
|
+
end
|
|
1761
|
+
|
|
1155
1762
|
# Exposes the current running example via the named
|
|
1156
1763
|
# helper method. RSpec 2.x exposed this via `example`,
|
|
1157
1764
|
# but in RSpec 3.0, the example is instead exposed via
|
|
@@ -1168,7 +1775,7 @@ module RSpec
|
|
|
1168
1775
|
# rspec.expose_current_running_example_as :example
|
|
1169
1776
|
# end
|
|
1170
1777
|
#
|
|
1171
|
-
# describe MyClass do
|
|
1778
|
+
# RSpec.describe MyClass do
|
|
1172
1779
|
# before do
|
|
1173
1780
|
# # `example` can be used here because of the above config.
|
|
1174
1781
|
# do_something if example.metadata[:type] == "foo"
|
|
@@ -1205,7 +1812,7 @@ module RSpec
|
|
|
1205
1812
|
# `shared_examples_for`, etc) onto `main` and `Module`, instead
|
|
1206
1813
|
# requiring you to prefix these methods with `RSpec.`. It enables
|
|
1207
1814
|
# expect-only syntax for rspec-mocks and rspec-expectations. It
|
|
1208
|
-
# simply disables monkey patching on whatever pieces of
|
|
1815
|
+
# simply disables monkey patching on whatever pieces of RSpec
|
|
1209
1816
|
# the user is using.
|
|
1210
1817
|
#
|
|
1211
1818
|
# @note It configures rspec-mocks and rspec-expectations only
|
|
@@ -1213,12 +1820,12 @@ module RSpec
|
|
|
1213
1820
|
# by not setting `mock_with` or `expect_with` to anything else).
|
|
1214
1821
|
#
|
|
1215
1822
|
# @note If the user uses this options with `mock_with :mocha`
|
|
1216
|
-
# (or
|
|
1823
|
+
# (or similar) they will still have monkey patching active
|
|
1217
1824
|
# in their test environment from mocha.
|
|
1218
1825
|
#
|
|
1219
1826
|
# @example
|
|
1220
1827
|
#
|
|
1221
|
-
# # It disables all monkey patching
|
|
1828
|
+
# # It disables all monkey patching.
|
|
1222
1829
|
# RSpec.configure do |config|
|
|
1223
1830
|
# config.disable_monkey_patching!
|
|
1224
1831
|
# end
|
|
@@ -1232,7 +1839,7 @@ module RSpec
|
|
|
1232
1839
|
# mocks.patch_marshal_to_support_partial_doubles = false
|
|
1233
1840
|
# end
|
|
1234
1841
|
#
|
|
1235
|
-
# config.
|
|
1842
|
+
# config.expect_with :rspec do |expectations|
|
|
1236
1843
|
# expectations.syntax = :expect
|
|
1237
1844
|
# end
|
|
1238
1845
|
# end
|
|
@@ -1248,73 +1855,423 @@ module RSpec
|
|
|
1248
1855
|
|
|
1249
1856
|
# Defines a callback that can assign derived metadata values.
|
|
1250
1857
|
#
|
|
1251
|
-
# @param filters [Array<Symbol>, Hash] metadata filters that determine
|
|
1252
|
-
# or group metadata hashes the callback will be triggered
|
|
1253
|
-
# the callback will be run against the metadata
|
|
1254
|
-
#
|
|
1255
|
-
#
|
|
1858
|
+
# @param filters [Array<Symbol>, Hash] metadata filters that determine
|
|
1859
|
+
# which example or group metadata hashes the callback will be triggered
|
|
1860
|
+
# for. If none are given, the callback will be run against the metadata
|
|
1861
|
+
# hashes of all groups and examples.
|
|
1862
|
+
# @yieldparam metadata [Hash] original metadata hash from an example or
|
|
1863
|
+
# group. Mutate this in your block as needed.
|
|
1256
1864
|
#
|
|
1257
1865
|
# @example
|
|
1258
1866
|
# RSpec.configure do |config|
|
|
1259
|
-
# # Tag all groups and examples in the spec/unit directory with
|
|
1867
|
+
# # Tag all groups and examples in the spec/unit directory with
|
|
1868
|
+
# # :type => :unit
|
|
1260
1869
|
# config.define_derived_metadata(:file_path => %r{/spec/unit/}) do |metadata|
|
|
1261
1870
|
# metadata[:type] = :unit
|
|
1262
1871
|
# end
|
|
1263
1872
|
# end
|
|
1264
1873
|
def define_derived_metadata(*filters, &block)
|
|
1265
1874
|
meta = Metadata.build_hash_from(filters, :warn_about_example_group_filtering)
|
|
1266
|
-
@derived_metadata_blocks
|
|
1875
|
+
@derived_metadata_blocks.append(block, meta)
|
|
1876
|
+
end
|
|
1877
|
+
|
|
1878
|
+
# Defines a callback that runs after the first example with matching
|
|
1879
|
+
# metadata is defined. If no examples are defined with matching metadata,
|
|
1880
|
+
# it will not get called at all.
|
|
1881
|
+
#
|
|
1882
|
+
# This can be used to ensure some setup is performed (such as bootstrapping
|
|
1883
|
+
# a DB or loading a specific file that adds significantly to the boot time)
|
|
1884
|
+
# if needed (as indicated by the presence of an example with matching metadata)
|
|
1885
|
+
# but avoided otherwise.
|
|
1886
|
+
#
|
|
1887
|
+
# @example
|
|
1888
|
+
# RSpec.configure do |config|
|
|
1889
|
+
# config.when_first_matching_example_defined(:db) do
|
|
1890
|
+
# # Load a support file that does some heavyweight setup,
|
|
1891
|
+
# # including bootstrapping the DB, but only if we have loaded
|
|
1892
|
+
# # any examples tagged with `:db`.
|
|
1893
|
+
# require 'support/db'
|
|
1894
|
+
# end
|
|
1895
|
+
# end
|
|
1896
|
+
def when_first_matching_example_defined(*filters)
|
|
1897
|
+
specified_meta = Metadata.build_hash_from(filters, :warn_about_example_group_filtering)
|
|
1898
|
+
|
|
1899
|
+
callback = lambda do |example_or_group_meta|
|
|
1900
|
+
# Example groups do not have `:example_group` metadata
|
|
1901
|
+
# (instead they have `:parent_example_group` metadata).
|
|
1902
|
+
return unless example_or_group_meta.key?(:example_group)
|
|
1903
|
+
|
|
1904
|
+
# Ensure the callback only fires once.
|
|
1905
|
+
@derived_metadata_blocks.delete(callback, specified_meta)
|
|
1906
|
+
|
|
1907
|
+
yield
|
|
1908
|
+
end
|
|
1909
|
+
|
|
1910
|
+
@derived_metadata_blocks.append(callback, specified_meta)
|
|
1267
1911
|
end
|
|
1268
1912
|
|
|
1269
1913
|
# @private
|
|
1270
1914
|
def apply_derived_metadata_to(metadata)
|
|
1271
|
-
|
|
1272
|
-
|
|
1915
|
+
already_run_blocks = Set.new
|
|
1916
|
+
|
|
1917
|
+
# We loop and attempt to re-apply metadata blocks to support cascades
|
|
1918
|
+
# (e.g. where a derived bit of metadata triggers the application of
|
|
1919
|
+
# another piece of derived metadata, etc)
|
|
1920
|
+
#
|
|
1921
|
+
# We limit our looping to 200 times as a way to detect infinitely recursing derived metadata blocks.
|
|
1922
|
+
# It's hard to imagine a valid use case for a derived metadata cascade greater than 200 iterations.
|
|
1923
|
+
200.times do
|
|
1924
|
+
return if @derived_metadata_blocks.items_for(metadata).all? do |block|
|
|
1925
|
+
already_run_blocks.include?(block).tap do |skip_block|
|
|
1926
|
+
block.call(metadata) unless skip_block
|
|
1927
|
+
already_run_blocks << block
|
|
1928
|
+
end
|
|
1929
|
+
end
|
|
1930
|
+
end
|
|
1931
|
+
|
|
1932
|
+
# If we got here, then `@derived_metadata_blocks.items_for(metadata).all?` never returned
|
|
1933
|
+
# `true` above and we treat this as an attempt to recurse infinitely. It's better to fail
|
|
1934
|
+
# with a clear # error than hang indefinitely, which is what would happen if we didn't limit
|
|
1935
|
+
# the looping above.
|
|
1936
|
+
raise SystemStackError, "Attempted to recursively derive metadata indefinitely."
|
|
1937
|
+
end
|
|
1938
|
+
|
|
1939
|
+
# Defines a `before` hook. See {Hooks#before} for full docs.
|
|
1940
|
+
#
|
|
1941
|
+
# This method differs from {Hooks#before} in only one way: it supports
|
|
1942
|
+
# the `:suite` scope. Hooks with the `:suite` scope will be run once before
|
|
1943
|
+
# the first example of the entire suite is executed. Conditions passed along
|
|
1944
|
+
# with `:suite` are effectively ignored.
|
|
1945
|
+
#
|
|
1946
|
+
# @see #prepend_before
|
|
1947
|
+
# @see #after
|
|
1948
|
+
# @see #append_after
|
|
1949
|
+
def before(scope=nil, *meta, &block)
|
|
1950
|
+
handle_suite_hook(scope, meta) do
|
|
1951
|
+
@before_suite_hooks << Hooks::BeforeHook.new(block, {})
|
|
1952
|
+
end || begin
|
|
1953
|
+
# defeat Ruby 2.5 lazy proc allocation to ensure
|
|
1954
|
+
# the methods below are passed the same proc instances
|
|
1955
|
+
# so `Hook` equality is preserved. For more info, see:
|
|
1956
|
+
# https://bugs.ruby-lang.org/issues/14045#note-5
|
|
1957
|
+
block.__id__
|
|
1958
|
+
|
|
1959
|
+
add_hook_to_existing_matching_groups(meta, scope) { |g| g.before(scope, *meta, &block) }
|
|
1960
|
+
super(scope, *meta, &block)
|
|
1961
|
+
end
|
|
1962
|
+
end
|
|
1963
|
+
alias_method :append_before, :before
|
|
1964
|
+
|
|
1965
|
+
# Adds `block` to the start of the list of `before` blocks in the same
|
|
1966
|
+
# scope (`:example`, `:context`, or `:suite`), in contrast to {#before},
|
|
1967
|
+
# which adds the hook to the end of the list.
|
|
1968
|
+
#
|
|
1969
|
+
# See {Hooks#before} for full `before` hook docs.
|
|
1970
|
+
#
|
|
1971
|
+
# This method differs from {Hooks#prepend_before} in only one way: it supports
|
|
1972
|
+
# the `:suite` scope. Hooks with the `:suite` scope will be run once before
|
|
1973
|
+
# the first example of the entire suite is executed. Conditions passed along
|
|
1974
|
+
# with `:suite` are effectively ignored.
|
|
1975
|
+
#
|
|
1976
|
+
# @see #before
|
|
1977
|
+
# @see #after
|
|
1978
|
+
# @see #append_after
|
|
1979
|
+
def prepend_before(scope=nil, *meta, &block)
|
|
1980
|
+
handle_suite_hook(scope, meta) do
|
|
1981
|
+
@before_suite_hooks.unshift Hooks::BeforeHook.new(block, {})
|
|
1982
|
+
end || begin
|
|
1983
|
+
# defeat Ruby 2.5 lazy proc allocation to ensure
|
|
1984
|
+
# the methods below are passed the same proc instances
|
|
1985
|
+
# so `Hook` equality is preserved. For more info, see:
|
|
1986
|
+
# https://bugs.ruby-lang.org/issues/14045#note-5
|
|
1987
|
+
block.__id__
|
|
1988
|
+
|
|
1989
|
+
add_hook_to_existing_matching_groups(meta, scope) { |g| g.prepend_before(scope, *meta, &block) }
|
|
1990
|
+
super(scope, *meta, &block)
|
|
1991
|
+
end
|
|
1992
|
+
end
|
|
1993
|
+
|
|
1994
|
+
# Defines a `after` hook. See {Hooks#after} for full docs.
|
|
1995
|
+
#
|
|
1996
|
+
# This method differs from {Hooks#after} in only one way: it supports
|
|
1997
|
+
# the `:suite` scope. Hooks with the `:suite` scope will be run once after
|
|
1998
|
+
# the last example of the entire suite is executed. Conditions passed along
|
|
1999
|
+
# with `:suite` are effectively ignored.
|
|
2000
|
+
#
|
|
2001
|
+
# @see #append_after
|
|
2002
|
+
# @see #before
|
|
2003
|
+
# @see #prepend_before
|
|
2004
|
+
def after(scope=nil, *meta, &block)
|
|
2005
|
+
handle_suite_hook(scope, meta) do
|
|
2006
|
+
@after_suite_hooks.unshift Hooks::AfterHook.new(block, {})
|
|
2007
|
+
end || begin
|
|
2008
|
+
# defeat Ruby 2.5 lazy proc allocation to ensure
|
|
2009
|
+
# the methods below are passed the same proc instances
|
|
2010
|
+
# so `Hook` equality is preserved. For more info, see:
|
|
2011
|
+
# https://bugs.ruby-lang.org/issues/14045#note-5
|
|
2012
|
+
block.__id__
|
|
2013
|
+
|
|
2014
|
+
add_hook_to_existing_matching_groups(meta, scope) { |g| g.after(scope, *meta, &block) }
|
|
2015
|
+
super(scope, *meta, &block)
|
|
2016
|
+
end
|
|
2017
|
+
end
|
|
2018
|
+
alias_method :prepend_after, :after
|
|
2019
|
+
|
|
2020
|
+
# Adds `block` to the end of the list of `after` blocks in the same
|
|
2021
|
+
# scope (`:example`, `:context`, or `:suite`), in contrast to {#after},
|
|
2022
|
+
# which adds the hook to the start of the list.
|
|
2023
|
+
#
|
|
2024
|
+
# See {Hooks#after} for full `after` hook docs.
|
|
2025
|
+
#
|
|
2026
|
+
# This method differs from {Hooks#append_after} in only one way: it supports
|
|
2027
|
+
# the `:suite` scope. Hooks with the `:suite` scope will be run once after
|
|
2028
|
+
# the last example of the entire suite is executed. Conditions passed along
|
|
2029
|
+
# with `:suite` are effectively ignored.
|
|
2030
|
+
#
|
|
2031
|
+
# @see #append_after
|
|
2032
|
+
# @see #before
|
|
2033
|
+
# @see #prepend_before
|
|
2034
|
+
def append_after(scope=nil, *meta, &block)
|
|
2035
|
+
handle_suite_hook(scope, meta) do
|
|
2036
|
+
@after_suite_hooks << Hooks::AfterHook.new(block, {})
|
|
2037
|
+
end || begin
|
|
2038
|
+
# defeat Ruby 2.5 lazy proc allocation to ensure
|
|
2039
|
+
# the methods below are passed the same proc instances
|
|
2040
|
+
# so `Hook` equality is preserved. For more info, see:
|
|
2041
|
+
# https://bugs.ruby-lang.org/issues/14045#note-5
|
|
2042
|
+
block.__id__
|
|
2043
|
+
|
|
2044
|
+
add_hook_to_existing_matching_groups(meta, scope) { |g| g.append_after(scope, *meta, &block) }
|
|
2045
|
+
super(scope, *meta, &block)
|
|
2046
|
+
end
|
|
2047
|
+
end
|
|
2048
|
+
|
|
2049
|
+
# Registers `block` as an `around` hook.
|
|
2050
|
+
#
|
|
2051
|
+
# See {Hooks#around} for full `around` hook docs.
|
|
2052
|
+
def around(scope=nil, *meta, &block)
|
|
2053
|
+
# defeat Ruby 2.5 lazy proc allocation to ensure
|
|
2054
|
+
# the methods below are passed the same proc instances
|
|
2055
|
+
# so `Hook` equality is preserved. For more info, see:
|
|
2056
|
+
# https://bugs.ruby-lang.org/issues/14045#note-5
|
|
2057
|
+
block.__id__
|
|
2058
|
+
|
|
2059
|
+
add_hook_to_existing_matching_groups(meta, scope) { |g| g.around(scope, *meta, &block) }
|
|
2060
|
+
super(scope, *meta, &block)
|
|
2061
|
+
end
|
|
2062
|
+
|
|
2063
|
+
# @private
|
|
2064
|
+
def with_suite_hooks
|
|
2065
|
+
return yield if dry_run?
|
|
2066
|
+
|
|
2067
|
+
begin
|
|
2068
|
+
RSpec.current_scope = :before_suite_hook
|
|
2069
|
+
run_suite_hooks("a `before(:suite)` hook", @before_suite_hooks)
|
|
2070
|
+
yield
|
|
2071
|
+
ensure
|
|
2072
|
+
RSpec.current_scope = :after_suite_hook
|
|
2073
|
+
run_suite_hooks("an `after(:suite)` hook", @after_suite_hooks)
|
|
2074
|
+
RSpec.current_scope = :suite
|
|
2075
|
+
end
|
|
2076
|
+
end
|
|
2077
|
+
|
|
2078
|
+
# @private
|
|
2079
|
+
# Holds the various registered hooks. Here we use a FilterableItemRepository
|
|
2080
|
+
# implementation that is specifically optimized for the read/write patterns
|
|
2081
|
+
# of the config object.
|
|
2082
|
+
def hooks
|
|
2083
|
+
@hooks ||= HookCollections.new(self, FilterableItemRepository::QueryOptimized)
|
|
2084
|
+
end
|
|
2085
|
+
|
|
2086
|
+
# Invokes block before defining an example group
|
|
2087
|
+
def on_example_group_definition(&block)
|
|
2088
|
+
on_example_group_definition_callbacks << block
|
|
2089
|
+
end
|
|
2090
|
+
|
|
2091
|
+
# @api private
|
|
2092
|
+
# Returns an array of blocks to call before defining an example group
|
|
2093
|
+
def on_example_group_definition_callbacks
|
|
2094
|
+
@on_example_group_definition_callbacks ||= []
|
|
2095
|
+
end
|
|
2096
|
+
|
|
2097
|
+
# @private
|
|
2098
|
+
def bisect_runner_class
|
|
2099
|
+
@bisect_runner_class ||= begin
|
|
2100
|
+
case bisect_runner
|
|
2101
|
+
when :fork
|
|
2102
|
+
RSpec::Support.require_rspec_core 'bisect/fork_runner'
|
|
2103
|
+
Bisect::ForkRunner
|
|
2104
|
+
when :shell
|
|
2105
|
+
RSpec::Support.require_rspec_core 'bisect/shell_runner'
|
|
2106
|
+
Bisect::ShellRunner
|
|
2107
|
+
else
|
|
2108
|
+
raise "Unsupported value for `bisect_runner` (#{bisect_runner.inspect}). " \
|
|
2109
|
+
"Only `:fork` and `:shell` are supported."
|
|
2110
|
+
end
|
|
1273
2111
|
end
|
|
1274
2112
|
end
|
|
1275
2113
|
|
|
1276
2114
|
private
|
|
1277
2115
|
|
|
2116
|
+
def load_file_handling_errors(method, file)
|
|
2117
|
+
__send__(method, file)
|
|
2118
|
+
rescue LoadError => ex
|
|
2119
|
+
relative_file = Metadata.relative_path(file)
|
|
2120
|
+
suggestions = DidYouMean.new(relative_file).call
|
|
2121
|
+
reporter.notify_non_example_exception(ex, "An error occurred while loading #{relative_file}.#{suggestions}")
|
|
2122
|
+
RSpec.world.wants_to_quit = true
|
|
2123
|
+
rescue Support::AllExceptionsExceptOnesWeMustNotRescue => ex
|
|
2124
|
+
relative_file = Metadata.relative_path(file)
|
|
2125
|
+
reporter.notify_non_example_exception(ex, "An error occurred while loading #{relative_file}.")
|
|
2126
|
+
RSpec.world.wants_to_quit = true
|
|
2127
|
+
rescue SystemExit => ex
|
|
2128
|
+
relative_file = Metadata.relative_path(file)
|
|
2129
|
+
reporter.notify_non_example_exception(
|
|
2130
|
+
ex,
|
|
2131
|
+
"While loading #{relative_file} an `exit` / `raise SystemExit` occurred, RSpec will now quit."
|
|
2132
|
+
)
|
|
2133
|
+
RSpec.world.rspec_is_quitting = true
|
|
2134
|
+
raise ex
|
|
2135
|
+
end
|
|
2136
|
+
|
|
2137
|
+
def handle_suite_hook(scope, meta)
|
|
2138
|
+
return nil unless scope == :suite
|
|
2139
|
+
|
|
2140
|
+
unless meta.empty?
|
|
2141
|
+
# TODO: in RSpec 4, consider raising an error here.
|
|
2142
|
+
# We warn only for backwards compatibility.
|
|
2143
|
+
RSpec.warn_with "WARNING: `:suite` hooks do not support metadata since " \
|
|
2144
|
+
"they apply to the suite as a whole rather than " \
|
|
2145
|
+
"any individual example or example group that has metadata. " \
|
|
2146
|
+
"The metadata you have provided (#{meta.inspect}) will be ignored."
|
|
2147
|
+
end
|
|
2148
|
+
|
|
2149
|
+
yield
|
|
2150
|
+
end
|
|
2151
|
+
|
|
2152
|
+
def run_suite_hooks(hook_description, hooks)
|
|
2153
|
+
context = SuiteHookContext.new(hook_description, reporter)
|
|
2154
|
+
|
|
2155
|
+
hooks.each do |hook|
|
|
2156
|
+
begin
|
|
2157
|
+
hook.run(context)
|
|
2158
|
+
rescue Support::AllExceptionsExceptOnesWeMustNotRescue => ex
|
|
2159
|
+
context.set_exception(ex)
|
|
2160
|
+
|
|
2161
|
+
# Do not run subsequent `before` hooks if one fails.
|
|
2162
|
+
# But for `after` hooks, we run them all so that all
|
|
2163
|
+
# cleanup bits get a chance to complete, minimizing the
|
|
2164
|
+
# chance that resources get left behind.
|
|
2165
|
+
break if hooks.equal?(@before_suite_hooks)
|
|
2166
|
+
end
|
|
2167
|
+
end
|
|
2168
|
+
end
|
|
2169
|
+
|
|
1278
2170
|
def get_files_to_run(paths)
|
|
1279
|
-
FlatMap.flat_map(paths) do |path|
|
|
2171
|
+
files = FlatMap.flat_map(paths_to_check(paths)) do |path|
|
|
1280
2172
|
path = path.gsub(File::ALT_SEPARATOR, File::SEPARATOR) if File::ALT_SEPARATOR
|
|
1281
2173
|
File.directory?(path) ? gather_directories(path) : extract_location(path)
|
|
1282
|
-
end.
|
|
2174
|
+
end.uniq
|
|
2175
|
+
|
|
2176
|
+
return files unless only_failures?
|
|
2177
|
+
relative_files = files.map { |f| Metadata.relative_path(File.expand_path f) }
|
|
2178
|
+
intersection = (relative_files & spec_files_with_failures.to_a)
|
|
2179
|
+
intersection.empty? ? files : intersection
|
|
2180
|
+
end
|
|
2181
|
+
|
|
2182
|
+
def paths_to_check(paths)
|
|
2183
|
+
return paths if pattern_might_load_specs_from_vendored_dirs?
|
|
2184
|
+
paths + [Dir.getwd]
|
|
2185
|
+
end
|
|
2186
|
+
|
|
2187
|
+
def pattern_might_load_specs_from_vendored_dirs?
|
|
2188
|
+
pattern.split(File::SEPARATOR).first.include?('**')
|
|
1283
2189
|
end
|
|
1284
2190
|
|
|
1285
2191
|
def gather_directories(path)
|
|
2192
|
+
include_files = get_matching_files(path, pattern)
|
|
2193
|
+
exclude_files = get_matching_files(path, exclude_pattern)
|
|
2194
|
+
(include_files - exclude_files).uniq
|
|
2195
|
+
end
|
|
2196
|
+
|
|
2197
|
+
def get_matching_files(path, pattern)
|
|
2198
|
+
raw_files = Dir[file_glob_from(path, pattern)]
|
|
2199
|
+
raw_files.map { |file| File.expand_path(file) }.sort
|
|
2200
|
+
end
|
|
2201
|
+
|
|
2202
|
+
def file_glob_from(path, pattern)
|
|
1286
2203
|
stripped = "{#{pattern.gsub(/\s*,\s*/, ',')}}"
|
|
1287
|
-
|
|
1288
|
-
|
|
2204
|
+
return stripped if pattern =~ /^(\.\/)?#{Regexp.escape path}/ || absolute_pattern?(pattern)
|
|
2205
|
+
File.join(path, stripped)
|
|
2206
|
+
end
|
|
2207
|
+
|
|
2208
|
+
if RSpec::Support::OS.windows?
|
|
2209
|
+
# :nocov:
|
|
2210
|
+
def absolute_pattern?(pattern)
|
|
2211
|
+
pattern =~ /\A[A-Z]:\\/ || windows_absolute_network_path?(pattern)
|
|
2212
|
+
end
|
|
2213
|
+
|
|
2214
|
+
def windows_absolute_network_path?(pattern)
|
|
2215
|
+
return false unless ::File::ALT_SEPARATOR
|
|
2216
|
+
pattern.start_with?(::File::ALT_SEPARATOR + ::File::ALT_SEPARATOR)
|
|
2217
|
+
end
|
|
2218
|
+
# :nocov:
|
|
2219
|
+
else
|
|
2220
|
+
def absolute_pattern?(pattern)
|
|
2221
|
+
pattern.start_with?(File::Separator)
|
|
2222
|
+
end
|
|
1289
2223
|
end
|
|
1290
2224
|
|
|
1291
2225
|
def extract_location(path)
|
|
1292
|
-
|
|
1293
|
-
|
|
2226
|
+
match = /^(.*?)((?:\:\d+)+)$/.match(path)
|
|
2227
|
+
|
|
2228
|
+
if match
|
|
2229
|
+
captures = match.captures
|
|
2230
|
+
path = captures[0]
|
|
2231
|
+
lines = captures[1][1..-1].split(":").map(&:to_i)
|
|
1294
2232
|
filter_manager.add_location path, lines
|
|
2233
|
+
else
|
|
2234
|
+
path, scoped_ids = Example.parse_id(path)
|
|
2235
|
+
filter_manager.add_ids(path, scoped_ids.split(/\s*,\s*/)) if scoped_ids
|
|
1295
2236
|
end
|
|
1296
|
-
|
|
2237
|
+
|
|
2238
|
+
return [] if path == default_path
|
|
2239
|
+
File.expand_path(path)
|
|
1297
2240
|
end
|
|
1298
2241
|
|
|
1299
2242
|
def command
|
|
1300
2243
|
$0.split(File::SEPARATOR).last
|
|
1301
2244
|
end
|
|
1302
2245
|
|
|
1303
|
-
def value_for(key
|
|
1304
|
-
@preferred_options.
|
|
2246
|
+
def value_for(key)
|
|
2247
|
+
@preferred_options.fetch(key) { yield }
|
|
1305
2248
|
end
|
|
1306
2249
|
|
|
1307
|
-
def
|
|
1308
|
-
|
|
1309
|
-
|
|
1310
|
-
|
|
1311
|
-
|
|
1312
|
-
|
|
2250
|
+
def define_built_in_hooks
|
|
2251
|
+
around(:example, :aggregate_failures => true) do |procsy|
|
|
2252
|
+
begin
|
|
2253
|
+
aggregate_failures(nil, :hide_backtrace => true, &procsy)
|
|
2254
|
+
rescue Support::AllExceptionsExceptOnesWeMustNotRescue => exception
|
|
2255
|
+
procsy.example.set_aggregate_failures_exception(exception)
|
|
2256
|
+
end
|
|
1313
2257
|
end
|
|
1314
2258
|
end
|
|
1315
2259
|
|
|
2260
|
+
def assert_no_example_groups_defined(config_option)
|
|
2261
|
+
return unless world.example_groups.any?
|
|
2262
|
+
|
|
2263
|
+
raise MustBeConfiguredBeforeExampleGroupsError.new(
|
|
2264
|
+
"RSpec's #{config_option} configuration option must be configured before " \
|
|
2265
|
+
"any example groups are defined, but you have already defined a group."
|
|
2266
|
+
)
|
|
2267
|
+
end
|
|
2268
|
+
|
|
2269
|
+
def output_wrapper
|
|
2270
|
+
@output_wrapper ||= OutputWrapper.new(output_stream)
|
|
2271
|
+
end
|
|
2272
|
+
|
|
1316
2273
|
def output_to_tty?(output=output_stream)
|
|
1317
|
-
|
|
2274
|
+
output.respond_to?(:tty?) && output.tty?
|
|
1318
2275
|
end
|
|
1319
2276
|
|
|
1320
2277
|
def conditionally_disable_mocks_monkey_patching
|
|
@@ -1339,6 +2296,90 @@ module RSpec
|
|
|
1339
2296
|
def rspec_expectations_loaded?
|
|
1340
2297
|
defined?(RSpec::Expectations.configuration)
|
|
1341
2298
|
end
|
|
2299
|
+
|
|
2300
|
+
def update_pattern_attr(name, value)
|
|
2301
|
+
if @spec_files_loaded
|
|
2302
|
+
RSpec.warning "Configuring `#{name}` to #{value} has no effect since " \
|
|
2303
|
+
"RSpec has already loaded the spec files."
|
|
2304
|
+
end
|
|
2305
|
+
|
|
2306
|
+
instance_variable_set(:"@#{name}", value)
|
|
2307
|
+
@files_to_run = nil
|
|
2308
|
+
end
|
|
2309
|
+
|
|
2310
|
+
def clear_values_derived_from_example_status_persistence_file_path
|
|
2311
|
+
@last_run_statuses = nil
|
|
2312
|
+
@spec_files_with_failures = nil
|
|
2313
|
+
end
|
|
2314
|
+
|
|
2315
|
+
def configure_group_with(group, module_list, application_method)
|
|
2316
|
+
module_list.items_for(group.metadata).each do |mod|
|
|
2317
|
+
__send__(application_method, mod, group)
|
|
2318
|
+
end
|
|
2319
|
+
end
|
|
2320
|
+
|
|
2321
|
+
def add_hook_to_existing_matching_groups(meta, scope, &block)
|
|
2322
|
+
# For example hooks, we have to apply it to each of the top level
|
|
2323
|
+
# groups, even if the groups do not match. When we apply it, we
|
|
2324
|
+
# apply it with the metadata, so it will only apply to examples
|
|
2325
|
+
# in the group that match the metadata.
|
|
2326
|
+
# #2280 for background and discussion.
|
|
2327
|
+
if scope == :example || scope == :each || scope.nil?
|
|
2328
|
+
world.example_groups.each(&block)
|
|
2329
|
+
else
|
|
2330
|
+
meta = Metadata.build_hash_from(meta.dup)
|
|
2331
|
+
on_existing_matching_groups(meta, &block)
|
|
2332
|
+
end
|
|
2333
|
+
end
|
|
2334
|
+
|
|
2335
|
+
def on_existing_matching_groups(meta)
|
|
2336
|
+
world.traverse_example_group_trees_until do |group|
|
|
2337
|
+
metadata_applies_to_group?(meta, group).tap do |applies|
|
|
2338
|
+
yield group if applies
|
|
2339
|
+
end
|
|
2340
|
+
end
|
|
2341
|
+
end
|
|
2342
|
+
|
|
2343
|
+
def metadata_applies_to_group?(meta, group)
|
|
2344
|
+
meta.empty? || MetadataFilter.apply?(:any?, meta, group.metadata)
|
|
2345
|
+
end
|
|
2346
|
+
|
|
2347
|
+
if RSpec::Support::RubyFeatures.module_prepends_supported?
|
|
2348
|
+
def safe_prepend(mod, host)
|
|
2349
|
+
host.__send__(:prepend, mod) unless host < mod
|
|
2350
|
+
end
|
|
2351
|
+
end
|
|
2352
|
+
|
|
2353
|
+
if RUBY_VERSION.to_f >= 1.9
|
|
2354
|
+
def safe_include(mod, host)
|
|
2355
|
+
host.__send__(:include, mod) unless host < mod
|
|
2356
|
+
end
|
|
2357
|
+
|
|
2358
|
+
def safe_extend(mod, host)
|
|
2359
|
+
host.extend(mod) unless host.singleton_class < mod
|
|
2360
|
+
end
|
|
2361
|
+
else # for 1.8.7
|
|
2362
|
+
# :nocov:
|
|
2363
|
+
def safe_include(mod, host)
|
|
2364
|
+
host.__send__(:include, mod) unless host.included_modules.include?(mod)
|
|
2365
|
+
end
|
|
2366
|
+
|
|
2367
|
+
def safe_extend(mod, host)
|
|
2368
|
+
host.extend(mod) unless (class << host; self; end).included_modules.include?(mod)
|
|
2369
|
+
end
|
|
2370
|
+
# :nocov:
|
|
2371
|
+
end
|
|
2372
|
+
|
|
2373
|
+
def define_mixed_in_module(mod, filters, mod_list, config_method, &block)
|
|
2374
|
+
unless Module === mod
|
|
2375
|
+
raise TypeError, "`RSpec.configuration.#{config_method}` expects a module but got: #{mod.inspect}"
|
|
2376
|
+
end
|
|
2377
|
+
|
|
2378
|
+
meta = Metadata.build_hash_from(filters, :warn_about_example_group_filtering)
|
|
2379
|
+
mod_list.append(mod, meta)
|
|
2380
|
+
on_existing_matching_groups(meta, &block)
|
|
2381
|
+
end
|
|
1342
2382
|
end
|
|
2383
|
+
# rubocop:enable Metrics/ClassLength
|
|
1343
2384
|
end
|
|
1344
2385
|
end
|