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
data/lib/rspec/core/example.rb
CHANGED
|
@@ -9,7 +9,7 @@ module RSpec
|
|
|
9
9
|
#
|
|
10
10
|
# This allows us to provide rich metadata about each individual
|
|
11
11
|
# example without adding tons of methods directly to the ExampleGroup
|
|
12
|
-
# that users may
|
|
12
|
+
# that users may inadvertently redefine.
|
|
13
13
|
#
|
|
14
14
|
# Useful for configuring logging and/or taking some action based
|
|
15
15
|
# on the state of an example's metadata.
|
|
@@ -44,14 +44,15 @@ module RSpec
|
|
|
44
44
|
class Example
|
|
45
45
|
# @private
|
|
46
46
|
#
|
|
47
|
-
# Used to define methods that delegate to this example's metadata
|
|
47
|
+
# Used to define methods that delegate to this example's metadata.
|
|
48
48
|
def self.delegate_to_metadata(key)
|
|
49
49
|
define_method(key) { @metadata[key] }
|
|
50
50
|
end
|
|
51
51
|
|
|
52
52
|
# @return [ExecutionResult] represents the result of running this example.
|
|
53
53
|
delegate_to_metadata :execution_result
|
|
54
|
-
# @return [String] the relative path to the file where this example was
|
|
54
|
+
# @return [String] the relative path to the file where this example was
|
|
55
|
+
# defined.
|
|
55
56
|
delegate_to_metadata :file_path
|
|
56
57
|
# @return [String] the full description (including the docstrings of
|
|
57
58
|
# all parent example groups).
|
|
@@ -59,30 +60,101 @@ module RSpec
|
|
|
59
60
|
# @return [String] the exact source location of this example in a form
|
|
60
61
|
# like `./path/to/spec.rb:17`
|
|
61
62
|
delegate_to_metadata :location
|
|
62
|
-
# @return [Boolean] flag that indicates that the example is not expected
|
|
63
|
-
# It will be run and will either have a pending result (if a
|
|
64
|
-
# or a failed result (if no failure occurs).
|
|
63
|
+
# @return [Boolean] flag that indicates that the example is not expected
|
|
64
|
+
# to pass. It will be run and will either have a pending result (if a
|
|
65
|
+
# failure occurs) or a failed result (if no failure occurs).
|
|
65
66
|
delegate_to_metadata :pending
|
|
66
67
|
# @return [Boolean] flag that will cause the example to not run.
|
|
67
68
|
# The {ExecutionResult} status will be `:pending`.
|
|
68
69
|
delegate_to_metadata :skip
|
|
69
70
|
|
|
70
71
|
# Returns the string submitted to `example` or its aliases (e.g.
|
|
71
|
-
# `specify`, `it`, etc).
|
|
72
|
-
# do_something }`) it returns the message generated
|
|
73
|
-
# there is one, otherwise returns a message including
|
|
74
|
-
# example.
|
|
72
|
+
# `specify`, `it`, etc). If no string is submitted (e.g.
|
|
73
|
+
# `it { is_expected.to do_something }`) it returns the message generated
|
|
74
|
+
# by the matcher if there is one, otherwise returns a message including
|
|
75
|
+
# the location of the example.
|
|
75
76
|
def description
|
|
76
|
-
description = metadata[:description].to_s.empty?
|
|
77
|
-
|
|
78
|
-
|
|
77
|
+
description = if metadata[:description].to_s.empty?
|
|
78
|
+
location_description
|
|
79
|
+
else
|
|
80
|
+
metadata[:description]
|
|
81
|
+
end
|
|
82
|
+
|
|
79
83
|
RSpec.configuration.format_docstrings_block.call(description)
|
|
80
84
|
end
|
|
81
85
|
|
|
86
|
+
# Returns a description of the example that always includes the location.
|
|
87
|
+
def inspect_output
|
|
88
|
+
inspect_output = "\"#{description}\""
|
|
89
|
+
unless metadata[:description].to_s.empty?
|
|
90
|
+
inspect_output += " (#{location})"
|
|
91
|
+
end
|
|
92
|
+
inspect_output
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
# Returns the location-based argument that can be passed to the `rspec` command to rerun this example.
|
|
96
|
+
def location_rerun_argument
|
|
97
|
+
@location_rerun_argument ||= begin
|
|
98
|
+
loaded_spec_files = RSpec.configuration.loaded_spec_files
|
|
99
|
+
|
|
100
|
+
Metadata.ascending(metadata) do |meta|
|
|
101
|
+
return meta[:location] if loaded_spec_files.include?(meta[:absolute_file_path])
|
|
102
|
+
end
|
|
103
|
+
end
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
# Returns the location-based argument that can be passed to the `rspec` command to rerun this example.
|
|
107
|
+
#
|
|
108
|
+
# @deprecated Use {#location_rerun_argument} instead.
|
|
109
|
+
# @note If there are multiple examples identified by this location, they will use {#id}
|
|
110
|
+
# to rerun instead, but this method will still return the location (that's why it is deprecated!).
|
|
111
|
+
def rerun_argument
|
|
112
|
+
location_rerun_argument
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
# @return [String] the unique id of this example. Pass
|
|
116
|
+
# this at the command line to re-run this exact example.
|
|
117
|
+
def id
|
|
118
|
+
@id ||= Metadata.id_from(metadata)
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
# @private
|
|
122
|
+
def self.parse_id(id)
|
|
123
|
+
# http://rubular.com/r/OMZSAPcAfn
|
|
124
|
+
id.match(/\A(.*?)(?:\[([\d\s:,]+)\])?\z/).captures
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
# Duplicates the example and overrides metadata with the provided
|
|
128
|
+
# hash.
|
|
129
|
+
#
|
|
130
|
+
# @param metadata_overrides [Hash] the hash to override the example metadata
|
|
131
|
+
# @return [Example] a duplicate of the example with modified metadata
|
|
132
|
+
def duplicate_with(metadata_overrides={})
|
|
133
|
+
new_metadata = metadata.clone.merge(metadata_overrides)
|
|
134
|
+
|
|
135
|
+
RSpec::Core::Metadata::RESERVED_KEYS.each do |reserved_key|
|
|
136
|
+
new_metadata.delete reserved_key
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
# don't clone the example group because the new example
|
|
140
|
+
# must belong to the same example group (not a clone).
|
|
141
|
+
#
|
|
142
|
+
# block is nil in new_metadata so we have to get it from metadata.
|
|
143
|
+
Example.new(example_group, description.clone,
|
|
144
|
+
new_metadata, metadata[:block])
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
# @private
|
|
148
|
+
def update_inherited_metadata(updates)
|
|
149
|
+
metadata.update(updates) do |_key, existing_example_value, _new_inherited_value|
|
|
150
|
+
existing_example_value
|
|
151
|
+
end
|
|
152
|
+
end
|
|
153
|
+
|
|
82
154
|
# @attr_reader
|
|
83
155
|
#
|
|
84
156
|
# Returns the first exception raised in the context of running this
|
|
85
|
-
# example (nil if no exception is raised)
|
|
157
|
+
# example (nil if no exception is raised).
|
|
86
158
|
attr_reader :exception
|
|
87
159
|
|
|
88
160
|
# @attr_reader
|
|
@@ -102,31 +174,70 @@ module RSpec
|
|
|
102
174
|
attr_accessor :clock
|
|
103
175
|
|
|
104
176
|
# Creates a new instance of Example.
|
|
105
|
-
# @param example_group_class [Class] the subclass of ExampleGroup in which
|
|
106
|
-
#
|
|
107
|
-
# @param
|
|
108
|
-
#
|
|
177
|
+
# @param example_group_class [Class] the subclass of ExampleGroup in which
|
|
178
|
+
# this Example is declared
|
|
179
|
+
# @param description [String] the String passed to the `it` method (or
|
|
180
|
+
# alias)
|
|
181
|
+
# @param user_metadata [Hash] additional args passed to `it` to be used as
|
|
182
|
+
# metadata
|
|
183
|
+
# @param example_block [Proc] the block of code that represents the
|
|
184
|
+
# example
|
|
109
185
|
# @api private
|
|
110
186
|
def initialize(example_group_class, description, user_metadata, example_block=nil)
|
|
111
187
|
@example_group_class = example_group_class
|
|
112
188
|
@example_block = example_block
|
|
113
189
|
|
|
190
|
+
# Register the example with the group before creating the metadata hash.
|
|
191
|
+
# This is necessary since creating the metadata hash triggers
|
|
192
|
+
# `when_first_matching_example_defined` callbacks, in which users can
|
|
193
|
+
# load RSpec support code which defines hooks. For that to work, the
|
|
194
|
+
# examples and example groups must be registered at the time the
|
|
195
|
+
# support code is called or be defined afterwards.
|
|
196
|
+
# Begin defined beforehand but registered afterwards causes hooks to
|
|
197
|
+
# not be applied where they should.
|
|
198
|
+
example_group_class.examples << self
|
|
199
|
+
|
|
114
200
|
@metadata = Metadata::ExampleHash.create(
|
|
115
|
-
@example_group_class.metadata, user_metadata,
|
|
201
|
+
@example_group_class.metadata, user_metadata,
|
|
202
|
+
example_group_class.method(:next_runnable_index_for),
|
|
203
|
+
description, example_block
|
|
116
204
|
)
|
|
117
205
|
|
|
206
|
+
config = RSpec.configuration
|
|
207
|
+
config.apply_derived_metadata_to(@metadata)
|
|
208
|
+
|
|
209
|
+
# This should perhaps be done in `Metadata::ExampleHash.create`,
|
|
210
|
+
# but the logic there has no knowledge of `RSpec.world` and we
|
|
211
|
+
# want to keep it that way. It's easier to just assign it here.
|
|
212
|
+
@metadata[:last_run_status] = config.last_run_statuses[id]
|
|
213
|
+
|
|
118
214
|
@example_group_instance = @exception = nil
|
|
119
215
|
@clock = RSpec::Core::Time
|
|
216
|
+
@reporter = RSpec::Core::NullReporter
|
|
120
217
|
end
|
|
121
218
|
|
|
219
|
+
# Provide a human-readable representation of this class
|
|
220
|
+
def inspect
|
|
221
|
+
"#<#{self.class.name} #{description.inspect}>"
|
|
222
|
+
end
|
|
223
|
+
alias to_s inspect
|
|
224
|
+
|
|
225
|
+
# @return [RSpec::Core::Reporter] the current reporter for the example
|
|
226
|
+
attr_reader :reporter
|
|
227
|
+
|
|
122
228
|
# Returns the example group class that provides the context for running
|
|
123
229
|
# this example.
|
|
124
230
|
def example_group
|
|
125
231
|
@example_group_class
|
|
126
232
|
end
|
|
127
233
|
|
|
128
|
-
|
|
129
|
-
|
|
234
|
+
def pending?
|
|
235
|
+
!!pending
|
|
236
|
+
end
|
|
237
|
+
|
|
238
|
+
def skipped?
|
|
239
|
+
!!skip
|
|
240
|
+
end
|
|
130
241
|
|
|
131
242
|
# @api private
|
|
132
243
|
# instance_execs the block passed to the constructor in the context of
|
|
@@ -134,50 +245,71 @@ module RSpec
|
|
|
134
245
|
# @param example_group_instance the instance of an ExampleGroup subclass
|
|
135
246
|
def run(example_group_instance, reporter)
|
|
136
247
|
@example_group_instance = example_group_instance
|
|
248
|
+
@reporter = reporter
|
|
249
|
+
RSpec.configuration.configure_example(self, hooks)
|
|
137
250
|
RSpec.current_example = self
|
|
138
251
|
|
|
139
252
|
start(reporter)
|
|
253
|
+
Pending.mark_pending!(self, pending) if pending?
|
|
140
254
|
|
|
141
255
|
begin
|
|
142
256
|
if skipped?
|
|
143
257
|
Pending.mark_pending! self, skip
|
|
144
258
|
elsif !RSpec.configuration.dry_run?
|
|
145
|
-
|
|
259
|
+
with_around_and_singleton_context_hooks do
|
|
146
260
|
begin
|
|
147
261
|
run_before_example
|
|
262
|
+
RSpec.current_scope = :example
|
|
148
263
|
@example_group_instance.instance_exec(self, &@example_block)
|
|
149
264
|
|
|
150
265
|
if pending?
|
|
151
266
|
Pending.mark_fixed! self
|
|
152
267
|
|
|
153
268
|
raise Pending::PendingExampleFixedError,
|
|
154
|
-
|
|
155
|
-
|
|
269
|
+
'Expected example to fail since it is pending, but it passed.',
|
|
270
|
+
[location]
|
|
156
271
|
end
|
|
157
|
-
rescue Pending::SkipDeclaredInExample
|
|
272
|
+
rescue Pending::SkipDeclaredInExample => _
|
|
273
|
+
# The "=> _" is normally useless but on JRuby it is a workaround
|
|
274
|
+
# for a bug that prevents us from getting backtraces:
|
|
275
|
+
# https://github.com/jruby/jruby/issues/4467
|
|
276
|
+
#
|
|
158
277
|
# no-op, required metadata has already been set by the `skip`
|
|
159
278
|
# method.
|
|
160
|
-
rescue
|
|
279
|
+
rescue AllExceptionsExcludingDangerousOnesOnRubiesThatAllowIt => e
|
|
161
280
|
set_exception(e)
|
|
162
281
|
ensure
|
|
282
|
+
RSpec.current_scope = :after_example_hook
|
|
163
283
|
run_after_example
|
|
164
284
|
end
|
|
165
285
|
end
|
|
166
286
|
end
|
|
167
|
-
rescue
|
|
287
|
+
rescue Support::AllExceptionsExceptOnesWeMustNotRescue => e
|
|
168
288
|
set_exception(e)
|
|
169
289
|
ensure
|
|
170
|
-
@example_group_instance
|
|
171
|
-
@example_group_instance.instance_variable_set(ivar, nil)
|
|
172
|
-
end
|
|
173
|
-
@example_group_instance = nil
|
|
290
|
+
@example_group_instance = nil # if you love something... let it go
|
|
174
291
|
end
|
|
175
292
|
|
|
176
293
|
finish(reporter)
|
|
177
294
|
ensure
|
|
295
|
+
execution_result.ensure_timing_set(clock)
|
|
178
296
|
RSpec.current_example = nil
|
|
179
297
|
end
|
|
180
298
|
|
|
299
|
+
if RSpec::Support::Ruby.jruby? || RUBY_VERSION.to_f < 1.9
|
|
300
|
+
# :nocov:
|
|
301
|
+
# For some reason, rescuing `Support::AllExceptionsExceptOnesWeMustNotRescue`
|
|
302
|
+
# in place of `Exception` above can cause the exit status to be the wrong
|
|
303
|
+
# thing. I have no idea why. See:
|
|
304
|
+
# https://github.com/rspec/rspec-core/pull/2063#discussion_r38284978
|
|
305
|
+
# @private
|
|
306
|
+
AllExceptionsExcludingDangerousOnesOnRubiesThatAllowIt = Exception
|
|
307
|
+
# :nocov:
|
|
308
|
+
else
|
|
309
|
+
# @private
|
|
310
|
+
AllExceptionsExcludingDangerousOnesOnRubiesThatAllowIt = Support::AllExceptionsExceptOnesWeMustNotRescue
|
|
311
|
+
end
|
|
312
|
+
|
|
181
313
|
# Wraps both a `Proc` and an {Example} for use in {Hooks#around
|
|
182
314
|
# around} hooks. In around hooks we need to yield this special
|
|
183
315
|
# kind of object (rather than the raw {Example}) because when
|
|
@@ -190,7 +322,7 @@ module RSpec
|
|
|
190
322
|
# if ex.metadata[:key] == :some_value && some_global_condition
|
|
191
323
|
# raise "some message"
|
|
192
324
|
# end
|
|
193
|
-
# ex.run # run delegates to ex.call
|
|
325
|
+
# ex.run # run delegates to ex.call.
|
|
194
326
|
# end
|
|
195
327
|
# end
|
|
196
328
|
#
|
|
@@ -201,67 +333,105 @@ module RSpec
|
|
|
201
333
|
attr_reader :example
|
|
202
334
|
|
|
203
335
|
Example.public_instance_methods(false).each do |name|
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
336
|
+
name_sym = name.to_sym
|
|
337
|
+
next if name_sym == :run || name_sym == :inspect || name_sym == :to_s
|
|
338
|
+
|
|
339
|
+
define_method(name) { |*a, &b| @example.__send__(name, *a, &b) }
|
|
207
340
|
end
|
|
208
341
|
|
|
209
342
|
Proc.public_instance_methods(false).each do |name|
|
|
343
|
+
name_sym = name.to_sym
|
|
344
|
+
next if name_sym == :call || name_sym == :inspect || name_sym == :to_s || name_sym == :to_proc
|
|
345
|
+
|
|
210
346
|
define_method(name) { |*a, &b| @proc.__send__(name, *a, &b) }
|
|
211
347
|
end
|
|
348
|
+
|
|
349
|
+
# Calls the proc and notes that the example has been executed.
|
|
350
|
+
def call(*args, &block)
|
|
351
|
+
@executed = true
|
|
352
|
+
@proc.call(*args, &block)
|
|
353
|
+
end
|
|
212
354
|
alias run call
|
|
213
355
|
|
|
356
|
+
# Provides a wrapped proc that will update our `executed?` state when
|
|
357
|
+
# executed.
|
|
358
|
+
def to_proc
|
|
359
|
+
method(:call).to_proc
|
|
360
|
+
end
|
|
361
|
+
|
|
214
362
|
def initialize(example, &block)
|
|
215
|
-
@example
|
|
216
|
-
@proc
|
|
363
|
+
@example = example
|
|
364
|
+
@proc = block
|
|
365
|
+
@executed = false
|
|
217
366
|
end
|
|
218
367
|
|
|
219
368
|
# @private
|
|
220
369
|
def wrap(&block)
|
|
221
370
|
self.class.new(example, &block)
|
|
222
371
|
end
|
|
223
|
-
end
|
|
224
372
|
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
373
|
+
# Indicates whether or not the around hook has executed the example.
|
|
374
|
+
def executed?
|
|
375
|
+
@executed
|
|
376
|
+
end
|
|
377
|
+
|
|
378
|
+
# @private
|
|
379
|
+
def inspect
|
|
380
|
+
@example.inspect.gsub('Example', 'Example::Procsy')
|
|
381
|
+
end
|
|
228
382
|
end
|
|
229
383
|
|
|
230
384
|
# @private
|
|
231
|
-
|
|
232
|
-
|
|
385
|
+
#
|
|
386
|
+
# The exception that will be displayed to the user -- either the failure of
|
|
387
|
+
# the example or the `pending_exception` if the example is pending.
|
|
388
|
+
def display_exception
|
|
389
|
+
@exception || execution_result.pending_exception
|
|
233
390
|
end
|
|
234
391
|
|
|
235
392
|
# @private
|
|
236
|
-
|
|
237
|
-
|
|
393
|
+
#
|
|
394
|
+
# Assigns the exception that will be displayed to the user -- either the failure of
|
|
395
|
+
# the example or the `pending_exception` if the example is pending.
|
|
396
|
+
def display_exception=(ex)
|
|
397
|
+
if pending? && !(Pending::PendingExampleFixedError === ex)
|
|
398
|
+
@exception = nil
|
|
399
|
+
execution_result.pending_fixed = false
|
|
400
|
+
execution_result.pending_exception = ex
|
|
401
|
+
else
|
|
402
|
+
@exception = ex
|
|
403
|
+
end
|
|
238
404
|
end
|
|
239
405
|
|
|
406
|
+
# rubocop:disable Naming/AccessorMethodName
|
|
407
|
+
|
|
240
408
|
# @private
|
|
241
409
|
#
|
|
242
410
|
# Used internally to set an exception in an after hook, which
|
|
243
411
|
# captures the exception but doesn't raise it.
|
|
244
|
-
def set_exception(exception
|
|
245
|
-
|
|
246
|
-
execution_result.pending_exception = exception
|
|
247
|
-
else
|
|
248
|
-
if @exception
|
|
249
|
-
# An error has already been set; we don't want to override it,
|
|
250
|
-
# but we also don't want silence the error, so let's print it.
|
|
251
|
-
msg = <<-EOS
|
|
412
|
+
def set_exception(exception)
|
|
413
|
+
return self.display_exception = exception unless display_exception
|
|
252
414
|
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
415
|
+
unless RSpec::Core::MultipleExceptionError === display_exception
|
|
416
|
+
self.display_exception = RSpec::Core::MultipleExceptionError.new(display_exception)
|
|
417
|
+
end
|
|
256
418
|
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
end
|
|
419
|
+
display_exception.add exception
|
|
420
|
+
end
|
|
260
421
|
|
|
261
|
-
|
|
262
|
-
|
|
422
|
+
# @private
|
|
423
|
+
#
|
|
424
|
+
# Used to set the exception when `aggregate_failures` fails.
|
|
425
|
+
def set_aggregate_failures_exception(exception)
|
|
426
|
+
return set_exception(exception) unless display_exception
|
|
427
|
+
|
|
428
|
+
exception = RSpec::Core::MultipleExceptionError::InterfaceTag.for(exception)
|
|
429
|
+
exception.add display_exception
|
|
430
|
+
self.display_exception = exception
|
|
263
431
|
end
|
|
264
432
|
|
|
433
|
+
# rubocop:enable Naming/AccessorMethodName
|
|
434
|
+
|
|
265
435
|
# @private
|
|
266
436
|
#
|
|
267
437
|
# Used internally to set an exception and fail without actually executing
|
|
@@ -275,20 +445,13 @@ module RSpec
|
|
|
275
445
|
# @private
|
|
276
446
|
#
|
|
277
447
|
# Used internally to skip without actually executing the example when
|
|
278
|
-
# skip is used in before(:context)
|
|
448
|
+
# skip is used in before(:context).
|
|
279
449
|
def skip_with_exception(reporter, exception)
|
|
280
450
|
start(reporter)
|
|
281
451
|
Pending.mark_skipped! self, exception.argument
|
|
282
452
|
finish(reporter)
|
|
283
453
|
end
|
|
284
454
|
|
|
285
|
-
# @private
|
|
286
|
-
def instance_exec_with_rescue(context, &block)
|
|
287
|
-
@example_group_instance.instance_exec(self, &block)
|
|
288
|
-
rescue Exception => e
|
|
289
|
-
set_exception(e, context)
|
|
290
|
-
end
|
|
291
|
-
|
|
292
455
|
# @private
|
|
293
456
|
def instance_exec(*args, &block)
|
|
294
457
|
@example_group_instance.instance_exec(*args, &block)
|
|
@@ -296,14 +459,15 @@ module RSpec
|
|
|
296
459
|
|
|
297
460
|
private
|
|
298
461
|
|
|
299
|
-
def
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
462
|
+
def hooks
|
|
463
|
+
example_group_instance.singleton_class.hooks
|
|
464
|
+
end
|
|
465
|
+
|
|
466
|
+
def with_around_example_hooks
|
|
467
|
+
RSpec.current_scope = :before_example_hook
|
|
468
|
+
hooks.run(:around, :example, self) { yield }
|
|
469
|
+
rescue Support::AllExceptionsExceptOnesWeMustNotRescue => e
|
|
470
|
+
set_exception(e)
|
|
307
471
|
end
|
|
308
472
|
|
|
309
473
|
def start(reporter)
|
|
@@ -315,50 +479,52 @@ module RSpec
|
|
|
315
479
|
pending_message = execution_result.pending_message
|
|
316
480
|
|
|
317
481
|
if @exception
|
|
318
|
-
record_finished :failed
|
|
319
482
|
execution_result.exception = @exception
|
|
483
|
+
record_finished :failed, reporter
|
|
320
484
|
reporter.example_failed self
|
|
321
485
|
false
|
|
322
486
|
elsif pending_message
|
|
323
|
-
record_finished :pending
|
|
324
487
|
execution_result.pending_message = pending_message
|
|
488
|
+
record_finished :pending, reporter
|
|
325
489
|
reporter.example_pending self
|
|
326
490
|
true
|
|
327
491
|
else
|
|
328
|
-
record_finished :passed
|
|
492
|
+
record_finished :passed, reporter
|
|
329
493
|
reporter.example_passed self
|
|
330
494
|
true
|
|
331
495
|
end
|
|
332
496
|
end
|
|
333
497
|
|
|
334
|
-
def record_finished(status)
|
|
498
|
+
def record_finished(status, reporter)
|
|
335
499
|
execution_result.record_finished(status, clock.now)
|
|
500
|
+
reporter.example_finished(self)
|
|
336
501
|
end
|
|
337
502
|
|
|
338
503
|
def run_before_example
|
|
339
504
|
@example_group_instance.setup_mocks_for_rspec
|
|
340
|
-
|
|
505
|
+
hooks.run(:before, :example, self)
|
|
506
|
+
end
|
|
507
|
+
|
|
508
|
+
def with_around_and_singleton_context_hooks
|
|
509
|
+
singleton_context_hooks_host = example_group_instance.singleton_class
|
|
510
|
+
singleton_context_hooks_host.run_before_context_hooks(example_group_instance)
|
|
511
|
+
with_around_example_hooks { yield }
|
|
512
|
+
ensure
|
|
513
|
+
singleton_context_hooks_host.run_after_context_hooks(example_group_instance)
|
|
341
514
|
end
|
|
342
515
|
|
|
343
516
|
def run_after_example
|
|
344
|
-
|
|
517
|
+
assign_generated_description if defined?(::RSpec::Matchers)
|
|
518
|
+
hooks.run(:after, :example, self)
|
|
345
519
|
verify_mocks
|
|
346
|
-
assign_generated_description if RSpec.configuration.expecting_with_rspec?
|
|
347
|
-
rescue Exception => e
|
|
348
|
-
set_exception(e, "in an `after(:example)` hook")
|
|
349
520
|
ensure
|
|
350
521
|
@example_group_instance.teardown_mocks_for_rspec
|
|
351
522
|
end
|
|
352
523
|
|
|
353
524
|
def verify_mocks
|
|
354
525
|
@example_group_instance.verify_mocks_for_rspec if mocks_need_verification?
|
|
355
|
-
rescue
|
|
356
|
-
|
|
357
|
-
execution_result.pending_fixed = false
|
|
358
|
-
@exception = nil
|
|
359
|
-
else
|
|
360
|
-
set_exception(e)
|
|
361
|
-
end
|
|
526
|
+
rescue Support::AllExceptionsExceptOnesWeMustNotRescue => e
|
|
527
|
+
set_exception(e)
|
|
362
528
|
end
|
|
363
529
|
|
|
364
530
|
def mocks_need_verification?
|
|
@@ -366,22 +532,23 @@ module RSpec
|
|
|
366
532
|
end
|
|
367
533
|
|
|
368
534
|
def assign_generated_description
|
|
369
|
-
if metadata[:description].empty? && (description =
|
|
535
|
+
if metadata[:description].empty? && (description = generate_description)
|
|
370
536
|
metadata[:description] = description
|
|
371
|
-
metadata[:full_description]
|
|
537
|
+
metadata[:full_description] += description
|
|
372
538
|
end
|
|
373
|
-
rescue Exception => e
|
|
374
|
-
set_exception(e, "while assigning the example description")
|
|
375
539
|
ensure
|
|
376
540
|
RSpec::Matchers.clear_generated_description
|
|
377
541
|
end
|
|
378
542
|
|
|
379
|
-
def
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
543
|
+
def generate_description
|
|
544
|
+
RSpec::Matchers.generated_description
|
|
545
|
+
rescue Support::AllExceptionsExceptOnesWeMustNotRescue => e
|
|
546
|
+
location_description + " (Got an error when generating description " \
|
|
547
|
+
"from matcher: #{e.class}: #{e.message} -- #{e.backtrace.first})"
|
|
548
|
+
end
|
|
549
|
+
|
|
550
|
+
def location_description
|
|
551
|
+
"example at #{location}"
|
|
385
552
|
end
|
|
386
553
|
|
|
387
554
|
# Represents the result of executing an example.
|
|
@@ -418,18 +585,39 @@ module RSpec
|
|
|
418
585
|
# this indicates whether or not it now passes.
|
|
419
586
|
attr_accessor :pending_fixed
|
|
420
587
|
|
|
421
|
-
|
|
588
|
+
def pending_fixed?
|
|
589
|
+
!!pending_fixed
|
|
590
|
+
end
|
|
591
|
+
|
|
592
|
+
# @return [Boolean] Indicates if the example was completely skipped
|
|
593
|
+
# (typically done via `:skip` metadata or the `skip` method). Skipped examples
|
|
594
|
+
# will have a `:pending` result. A `:pending` result can also come from examples
|
|
595
|
+
# that were marked as `:pending`, which causes them to be run, and produces a
|
|
596
|
+
# `:failed` result if the example passes.
|
|
597
|
+
def example_skipped?
|
|
598
|
+
status == :pending && !pending_exception
|
|
599
|
+
end
|
|
422
600
|
|
|
423
601
|
# @api private
|
|
424
602
|
# Records the finished status of the example.
|
|
425
603
|
def record_finished(status, finished_at)
|
|
426
|
-
self.status
|
|
427
|
-
|
|
428
|
-
|
|
604
|
+
self.status = status
|
|
605
|
+
calculate_run_time(finished_at)
|
|
606
|
+
end
|
|
607
|
+
|
|
608
|
+
# @api private
|
|
609
|
+
# Populates finished_at and run_time if it has not yet been set
|
|
610
|
+
def ensure_timing_set(clock)
|
|
611
|
+
calculate_run_time(clock.now) unless finished_at
|
|
429
612
|
end
|
|
430
613
|
|
|
431
614
|
private
|
|
432
615
|
|
|
616
|
+
def calculate_run_time(finished_at)
|
|
617
|
+
self.finished_at = finished_at
|
|
618
|
+
self.run_time = (finished_at - started_at).to_f
|
|
619
|
+
end
|
|
620
|
+
|
|
433
621
|
# For backwards compatibility we present `status` as a string
|
|
434
622
|
# when presenting the legacy hash interface.
|
|
435
623
|
def hash_for_delegation
|
|
@@ -451,7 +639,7 @@ module RSpec
|
|
|
451
639
|
end
|
|
452
640
|
end
|
|
453
641
|
|
|
454
|
-
def issue_deprecation(
|
|
642
|
+
def issue_deprecation(_method_name, *_args)
|
|
455
643
|
RSpec.deprecate("Treating `metadata[:execution_result]` as a hash",
|
|
456
644
|
:replacement => "the attributes methods to access the data")
|
|
457
645
|
end
|
|
@@ -461,14 +649,18 @@ module RSpec
|
|
|
461
649
|
# @private
|
|
462
650
|
# Provides an execution context for before/after :suite hooks.
|
|
463
651
|
class SuiteHookContext < Example
|
|
464
|
-
def initialize
|
|
465
|
-
super(AnonymousExampleGroup,
|
|
652
|
+
def initialize(hook_description, reporter)
|
|
653
|
+
super(AnonymousExampleGroup, hook_description, {})
|
|
654
|
+
@example_group_instance = AnonymousExampleGroup.new
|
|
655
|
+
@reporter = reporter
|
|
466
656
|
end
|
|
467
657
|
|
|
468
|
-
#
|
|
469
|
-
def set_exception(exception
|
|
470
|
-
|
|
658
|
+
# rubocop:disable Naming/AccessorMethodName
|
|
659
|
+
def set_exception(exception)
|
|
660
|
+
reporter.notify_non_example_exception(exception, "An error occurred in #{description}.")
|
|
661
|
+
RSpec.world.wants_to_quit = true
|
|
471
662
|
end
|
|
663
|
+
# rubocop:enable Naming/AccessorMethodName
|
|
472
664
|
end
|
|
473
665
|
end
|
|
474
666
|
end
|