rspec-core 3.8.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (84) hide show
  1. checksums.yaml +7 -0
  2. checksums.yaml.gz.sig +0 -0
  3. data.tar.gz.sig +0 -0
  4. data/.document +5 -0
  5. data/.yardopts +8 -0
  6. data/Changelog.md +2243 -0
  7. data/LICENSE.md +26 -0
  8. data/README.md +384 -0
  9. data/exe/rspec +4 -0
  10. data/lib/rspec/autorun.rb +3 -0
  11. data/lib/rspec/core.rb +185 -0
  12. data/lib/rspec/core/backtrace_formatter.rb +65 -0
  13. data/lib/rspec/core/bisect/coordinator.rb +62 -0
  14. data/lib/rspec/core/bisect/example_minimizer.rb +173 -0
  15. data/lib/rspec/core/bisect/fork_runner.rb +134 -0
  16. data/lib/rspec/core/bisect/server.rb +61 -0
  17. data/lib/rspec/core/bisect/shell_command.rb +126 -0
  18. data/lib/rspec/core/bisect/shell_runner.rb +73 -0
  19. data/lib/rspec/core/bisect/utilities.rb +58 -0
  20. data/lib/rspec/core/configuration.rb +2308 -0
  21. data/lib/rspec/core/configuration_options.rb +233 -0
  22. data/lib/rspec/core/drb.rb +113 -0
  23. data/lib/rspec/core/dsl.rb +98 -0
  24. data/lib/rspec/core/example.rb +656 -0
  25. data/lib/rspec/core/example_group.rb +889 -0
  26. data/lib/rspec/core/example_status_persister.rb +235 -0
  27. data/lib/rspec/core/filter_manager.rb +231 -0
  28. data/lib/rspec/core/flat_map.rb +20 -0
  29. data/lib/rspec/core/formatters.rb +269 -0
  30. data/lib/rspec/core/formatters/base_bisect_formatter.rb +45 -0
  31. data/lib/rspec/core/formatters/base_formatter.rb +70 -0
  32. data/lib/rspec/core/formatters/base_text_formatter.rb +75 -0
  33. data/lib/rspec/core/formatters/bisect_drb_formatter.rb +29 -0
  34. data/lib/rspec/core/formatters/bisect_progress_formatter.rb +157 -0
  35. data/lib/rspec/core/formatters/console_codes.rb +68 -0
  36. data/lib/rspec/core/formatters/deprecation_formatter.rb +223 -0
  37. data/lib/rspec/core/formatters/documentation_formatter.rb +70 -0
  38. data/lib/rspec/core/formatters/exception_presenter.rb +508 -0
  39. data/lib/rspec/core/formatters/fallback_message_formatter.rb +28 -0
  40. data/lib/rspec/core/formatters/helpers.rb +110 -0
  41. data/lib/rspec/core/formatters/html_formatter.rb +153 -0
  42. data/lib/rspec/core/formatters/html_printer.rb +414 -0
  43. data/lib/rspec/core/formatters/html_snippet_extractor.rb +120 -0
  44. data/lib/rspec/core/formatters/json_formatter.rb +102 -0
  45. data/lib/rspec/core/formatters/profile_formatter.rb +68 -0
  46. data/lib/rspec/core/formatters/progress_formatter.rb +29 -0
  47. data/lib/rspec/core/formatters/protocol.rb +182 -0
  48. data/lib/rspec/core/formatters/snippet_extractor.rb +134 -0
  49. data/lib/rspec/core/formatters/syntax_highlighter.rb +91 -0
  50. data/lib/rspec/core/hooks.rb +624 -0
  51. data/lib/rspec/core/invocations.rb +87 -0
  52. data/lib/rspec/core/memoized_helpers.rb +554 -0
  53. data/lib/rspec/core/metadata.rb +498 -0
  54. data/lib/rspec/core/metadata_filter.rb +255 -0
  55. data/lib/rspec/core/minitest_assertions_adapter.rb +31 -0
  56. data/lib/rspec/core/mocking_adapters/flexmock.rb +31 -0
  57. data/lib/rspec/core/mocking_adapters/mocha.rb +57 -0
  58. data/lib/rspec/core/mocking_adapters/null.rb +14 -0
  59. data/lib/rspec/core/mocking_adapters/rr.rb +31 -0
  60. data/lib/rspec/core/mocking_adapters/rspec.rb +32 -0
  61. data/lib/rspec/core/notifications.rb +521 -0
  62. data/lib/rspec/core/option_parser.rb +309 -0
  63. data/lib/rspec/core/ordering.rb +158 -0
  64. data/lib/rspec/core/output_wrapper.rb +29 -0
  65. data/lib/rspec/core/pending.rb +165 -0
  66. data/lib/rspec/core/profiler.rb +34 -0
  67. data/lib/rspec/core/project_initializer.rb +48 -0
  68. data/lib/rspec/core/project_initializer/.rspec +1 -0
  69. data/lib/rspec/core/project_initializer/spec/spec_helper.rb +100 -0
  70. data/lib/rspec/core/rake_task.rb +168 -0
  71. data/lib/rspec/core/reporter.rb +257 -0
  72. data/lib/rspec/core/ruby_project.rb +53 -0
  73. data/lib/rspec/core/runner.rb +199 -0
  74. data/lib/rspec/core/sandbox.rb +37 -0
  75. data/lib/rspec/core/set.rb +54 -0
  76. data/lib/rspec/core/shared_context.rb +55 -0
  77. data/lib/rspec/core/shared_example_group.rb +269 -0
  78. data/lib/rspec/core/shell_escape.rb +49 -0
  79. data/lib/rspec/core/test_unit_assertions_adapter.rb +30 -0
  80. data/lib/rspec/core/version.rb +9 -0
  81. data/lib/rspec/core/warnings.rb +40 -0
  82. data/lib/rspec/core/world.rb +275 -0
  83. metadata +292 -0
  84. metadata.gz.sig +0 -0
@@ -0,0 +1,889 @@
1
+ RSpec::Support.require_rspec_support 'recursive_const_methods'
2
+
3
+ module RSpec
4
+ module Core
5
+ # rubocop:disable Metrics/ClassLength
6
+
7
+ # ExampleGroup and {Example} are the main structural elements of
8
+ # rspec-core. Consider this example:
9
+ #
10
+ # describe Thing do
11
+ # it "does something" do
12
+ # end
13
+ # end
14
+ #
15
+ # The object returned by `describe Thing` is a subclass of ExampleGroup.
16
+ # The object returned by `it "does something"` is an instance of Example,
17
+ # which serves as a wrapper for an instance of the ExampleGroup in which it
18
+ # is declared.
19
+ #
20
+ # Example group bodies (e.g. `describe` or `context` blocks) are evaluated
21
+ # in the context of a new subclass of ExampleGroup. Individual examples are
22
+ # evaluated in the context of an instance of the specific ExampleGroup
23
+ # subclass to which they belong.
24
+ #
25
+ # Besides the class methods defined here, there are other interesting macros
26
+ # defined in {Hooks}, {MemoizedHelpers::ClassMethods} and
27
+ # {SharedExampleGroup}. There are additional instance methods available to
28
+ # your examples defined in {MemoizedHelpers} and {Pending}.
29
+ class ExampleGroup
30
+ extend Hooks
31
+
32
+ include MemoizedHelpers
33
+ extend MemoizedHelpers::ClassMethods
34
+ include Pending
35
+ extend SharedExampleGroup
36
+
37
+ # Define a singleton method for the singleton class (remove the method if
38
+ # it's already been defined).
39
+ # @private
40
+ def self.idempotently_define_singleton_method(name, &definition)
41
+ (class << self; self; end).module_exec do
42
+ remove_method(name) if method_defined?(name) && instance_method(name).owner == self
43
+ define_method(name, &definition)
44
+ end
45
+ end
46
+
47
+ # @!group Metadata
48
+
49
+ # The [Metadata](Metadata) object associated with this group.
50
+ # @see Metadata
51
+ def self.metadata
52
+ @metadata ||= nil
53
+ end
54
+
55
+ # Temporarily replace the provided metadata.
56
+ # Intended primarily to allow an example group's singleton class
57
+ # to return the metadata of the example that it exists for. This
58
+ # is necessary for shared example group inclusion to work properly
59
+ # with singleton example groups.
60
+ # @private
61
+ def self.with_replaced_metadata(meta)
62
+ orig_metadata = metadata
63
+ @metadata = meta
64
+ yield
65
+ ensure
66
+ @metadata = orig_metadata
67
+ end
68
+
69
+ # @private
70
+ # @return [Metadata] belonging to the parent of a nested {ExampleGroup}
71
+ def self.superclass_metadata
72
+ @superclass_metadata ||= superclass.respond_to?(:metadata) ? superclass.metadata : nil
73
+ end
74
+
75
+ # @private
76
+ def self.delegate_to_metadata(*names)
77
+ names.each do |name|
78
+ idempotently_define_singleton_method(name) { metadata.fetch(name) }
79
+ end
80
+ end
81
+
82
+ delegate_to_metadata :described_class, :file_path, :location
83
+
84
+ # @return [String] the current example group description
85
+ def self.description
86
+ description = metadata[:description]
87
+ RSpec.configuration.format_docstrings_block.call(description)
88
+ end
89
+
90
+ # Returns the class or module passed to the `describe` method (or alias).
91
+ # Returns nil if the subject is not a class or module.
92
+ # @example
93
+ # describe Thing do
94
+ # it "does something" do
95
+ # described_class == Thing
96
+ # end
97
+ # end
98
+ #
99
+ def described_class
100
+ self.class.described_class
101
+ end
102
+
103
+ # @!endgroup
104
+
105
+ # @!group Defining Examples
106
+
107
+ # @private
108
+ # @macro [attach] define_example_method
109
+ # @!scope class
110
+ # @method $1
111
+ # @overload $1
112
+ # @overload $1(&example_implementation)
113
+ # @param example_implementation [Block] The implementation of the example.
114
+ # @overload $1(doc_string, *metadata_keys, metadata={})
115
+ # @param doc_string [String] The example's doc string.
116
+ # @param metadata [Hash] Metadata for the example.
117
+ # @param metadata_keys [Array<Symbol>] Metadata tags for the example.
118
+ # Will be transformed into hash entries with `true` values.
119
+ # @overload $1(doc_string, *metadata_keys, metadata={}, &example_implementation)
120
+ # @param doc_string [String] The example's doc string.
121
+ # @param metadata [Hash] Metadata for the example.
122
+ # @param metadata_keys [Array<Symbol>] Metadata tags for the example.
123
+ # Will be transformed into hash entries with `true` values.
124
+ # @param example_implementation [Block] The implementation of the example.
125
+ # @yield [Example] the example object
126
+ # @example
127
+ # $1 do
128
+ # end
129
+ #
130
+ # $1 "does something" do
131
+ # end
132
+ #
133
+ # $1 "does something", :slow, :uses_js do
134
+ # end
135
+ #
136
+ # $1 "does something", :with => 'additional metadata' do
137
+ # end
138
+ #
139
+ # $1 "does something" do |ex|
140
+ # # ex is the Example object that contains metadata about the example
141
+ # end
142
+ def self.define_example_method(name, extra_options={})
143
+ idempotently_define_singleton_method(name) do |*all_args, &block|
144
+ desc, *args = *all_args
145
+
146
+ options = Metadata.build_hash_from(args)
147
+ options.update(:skip => RSpec::Core::Pending::NOT_YET_IMPLEMENTED) unless block
148
+ options.update(extra_options)
149
+
150
+ RSpec::Core::Example.new(self, desc, options, block)
151
+ end
152
+ end
153
+
154
+ # Defines an example within a group.
155
+ define_example_method :example
156
+ # Defines an example within a group.
157
+ # This is the primary API to define a code example.
158
+ define_example_method :it
159
+ # Defines an example within a group.
160
+ # Useful for when your docstring does not read well off of `it`.
161
+ # @example
162
+ # RSpec.describe MyClass do
163
+ # specify "#do_something is deprecated" do
164
+ # # ...
165
+ # end
166
+ # end
167
+ define_example_method :specify
168
+
169
+ # Shortcut to define an example with `:focus => true`.
170
+ # @see example
171
+ define_example_method :focus, :focus => true
172
+ # Shortcut to define an example with `:focus => true`.
173
+ # @see example
174
+ define_example_method :fexample, :focus => true
175
+ # Shortcut to define an example with `:focus => true`.
176
+ # @see example
177
+ define_example_method :fit, :focus => true
178
+ # Shortcut to define an example with `:focus => true`.
179
+ # @see example
180
+ define_example_method :fspecify, :focus => true
181
+ # Shortcut to define an example with `:skip => 'Temporarily skipped with xexample'`.
182
+ # @see example
183
+ define_example_method :xexample, :skip => 'Temporarily skipped with xexample'
184
+ # Shortcut to define an example with `:skip => 'Temporarily skipped with xit'`.
185
+ # @see example
186
+ define_example_method :xit, :skip => 'Temporarily skipped with xit'
187
+ # Shortcut to define an example with `:skip => 'Temporarily skipped with xspecify'`.
188
+ # @see example
189
+ define_example_method :xspecify, :skip => 'Temporarily skipped with xspecify'
190
+ # Shortcut to define an example with `:skip => true`
191
+ # @see example
192
+ define_example_method :skip, :skip => true
193
+ # Shortcut to define an example with `:pending => true`
194
+ # @see example
195
+ define_example_method :pending, :pending => true
196
+
197
+ # @!endgroup
198
+
199
+ # @!group Defining Example Groups
200
+
201
+ # @private
202
+ # @macro [attach] define_example_group_method
203
+ # @!scope class
204
+ # @overload $1
205
+ # @overload $1(&example_group_definition)
206
+ # @param example_group_definition [Block] The definition of the example group.
207
+ # @overload $1(doc_string, *metadata_keys, metadata={}, &example_implementation)
208
+ # @param doc_string [String] The group's doc string.
209
+ # @param metadata [Hash] Metadata for the group.
210
+ # @param metadata_keys [Array<Symbol>] Metadata tags for the group.
211
+ # Will be transformed into hash entries with `true` values.
212
+ # @param example_group_definition [Block] The definition of the example group.
213
+ #
214
+ # Generates a subclass of this example group which inherits
215
+ # everything except the examples themselves.
216
+ #
217
+ # @example
218
+ #
219
+ # RSpec.describe "something" do # << This describe method is defined in
220
+ # # << RSpec::Core::DSL, included in the
221
+ # # << global namespace (optional)
222
+ # before do
223
+ # do_something_before
224
+ # end
225
+ #
226
+ # let(:thing) { Thing.new }
227
+ #
228
+ # $1 "attribute (of something)" do
229
+ # # examples in the group get the before hook
230
+ # # declared above, and can access `thing`
231
+ # end
232
+ # end
233
+ #
234
+ # @see DSL#describe
235
+ def self.define_example_group_method(name, metadata={})
236
+ idempotently_define_singleton_method(name) do |*args, &example_group_block|
237
+ thread_data = RSpec::Support.thread_local_data
238
+ top_level = self == ExampleGroup
239
+
240
+ registration_collection =
241
+ if top_level
242
+ if thread_data[:in_example_group]
243
+ raise "Creating an isolated context from within a context is " \
244
+ "not allowed. Change `RSpec.#{name}` to `#{name}` or " \
245
+ "move this to a top-level scope."
246
+ end
247
+
248
+ thread_data[:in_example_group] = true
249
+ RSpec.world.example_groups
250
+ else
251
+ children
252
+ end
253
+
254
+ begin
255
+ description = args.shift
256
+ combined_metadata = metadata.dup
257
+ combined_metadata.merge!(args.pop) if args.last.is_a? Hash
258
+ args << combined_metadata
259
+
260
+ subclass(self, description, args, registration_collection, &example_group_block)
261
+ ensure
262
+ thread_data.delete(:in_example_group) if top_level
263
+ end
264
+ end
265
+
266
+ RSpec::Core::DSL.expose_example_group_alias(name)
267
+ end
268
+
269
+ define_example_group_method :example_group
270
+
271
+ # An alias of `example_group`. Generally used when grouping examples by a
272
+ # thing you are describing (e.g. an object, class or method).
273
+ # @see example_group
274
+ define_example_group_method :describe
275
+
276
+ # An alias of `example_group`. Generally used when grouping examples
277
+ # contextually (e.g. "with xyz", "when xyz" or "if xyz").
278
+ # @see example_group
279
+ define_example_group_method :context
280
+
281
+ # Shortcut to temporarily make an example group skipped.
282
+ # @see example_group
283
+ define_example_group_method :xdescribe, :skip => "Temporarily skipped with xdescribe"
284
+
285
+ # Shortcut to temporarily make an example group skipped.
286
+ # @see example_group
287
+ define_example_group_method :xcontext, :skip => "Temporarily skipped with xcontext"
288
+
289
+ # Shortcut to define an example group with `:focus => true`.
290
+ # @see example_group
291
+ define_example_group_method :fdescribe, :focus => true
292
+
293
+ # Shortcut to define an example group with `:focus => true`.
294
+ # @see example_group
295
+ define_example_group_method :fcontext, :focus => true
296
+
297
+ # @!endgroup
298
+
299
+ # @!group Including Shared Example Groups
300
+
301
+ # @private
302
+ # @macro [attach] define_nested_shared_group_method
303
+ # @!scope class
304
+ #
305
+ # @see SharedExampleGroup
306
+ def self.define_nested_shared_group_method(new_name, report_label="it should behave like")
307
+ idempotently_define_singleton_method(new_name) do |name, *args, &customization_block|
308
+ # Pass :caller so the :location metadata is set properly.
309
+ # Otherwise, it'll be set to the next line because that's
310
+ # the block's source_location.
311
+ group = example_group("#{report_label} #{name}", :caller => (the_caller = caller)) do
312
+ find_and_eval_shared("examples", name, the_caller.first, *args, &customization_block)
313
+ end
314
+ group.metadata[:shared_group_name] = name
315
+ group
316
+ end
317
+ end
318
+
319
+ # Generates a nested example group and includes the shared content
320
+ # mapped to `name` in the nested group.
321
+ define_nested_shared_group_method :it_behaves_like, "behaves like"
322
+ # Generates a nested example group and includes the shared content
323
+ # mapped to `name` in the nested group.
324
+ define_nested_shared_group_method :it_should_behave_like
325
+
326
+ # Includes shared content mapped to `name` directly in the group in which
327
+ # it is declared, as opposed to `it_behaves_like`, which creates a nested
328
+ # group. If given a block, that block is also eval'd in the current
329
+ # context.
330
+ #
331
+ # @see SharedExampleGroup
332
+ def self.include_context(name, *args, &block)
333
+ find_and_eval_shared("context", name, caller.first, *args, &block)
334
+ end
335
+
336
+ # Includes shared content mapped to `name` directly in the group in which
337
+ # it is declared, as opposed to `it_behaves_like`, which creates a nested
338
+ # group. If given a block, that block is also eval'd in the current
339
+ # context.
340
+ #
341
+ # @see SharedExampleGroup
342
+ def self.include_examples(name, *args, &block)
343
+ find_and_eval_shared("examples", name, caller.first, *args, &block)
344
+ end
345
+
346
+ # Clear memoized values when adding/removing examples
347
+ # @private
348
+ def self.reset_memoized
349
+ @descendant_filtered_examples = nil
350
+ @_descendants = nil
351
+ @parent_groups = nil
352
+ @declaration_locations = nil
353
+ end
354
+
355
+ # Adds an example to the example group
356
+ def self.add_example(example)
357
+ reset_memoized
358
+ examples << example
359
+ end
360
+
361
+ # Removes an example from the example group
362
+ def self.remove_example(example)
363
+ reset_memoized
364
+ examples.delete example
365
+ end
366
+
367
+ # @private
368
+ def self.find_and_eval_shared(label, name, inclusion_location, *args, &customization_block)
369
+ shared_module = RSpec.world.shared_example_group_registry.find(parent_groups, name)
370
+
371
+ unless shared_module
372
+ raise ArgumentError, "Could not find shared #{label} #{name.inspect}"
373
+ end
374
+
375
+ shared_module.include_in(
376
+ self, Metadata.relative_path(inclusion_location),
377
+ args, customization_block
378
+ )
379
+ end
380
+
381
+ # @!endgroup
382
+
383
+ # @private
384
+ def self.subclass(parent, description, args, registration_collection, &example_group_block)
385
+ subclass = Class.new(parent)
386
+ subclass.set_it_up(description, args, registration_collection, &example_group_block)
387
+ subclass.module_exec(&example_group_block) if example_group_block
388
+
389
+ # The LetDefinitions module must be included _after_ other modules
390
+ # to ensure that it takes precedence when there are name collisions.
391
+ # Thus, we delay including it until after the example group block
392
+ # has been eval'd.
393
+ MemoizedHelpers.define_helpers_on(subclass)
394
+
395
+ subclass
396
+ end
397
+
398
+ # @private
399
+ def self.set_it_up(description, args, registration_collection, &example_group_block)
400
+ # Ruby 1.9 has a bug that can lead to infinite recursion and a
401
+ # SystemStackError if you include a module in a superclass after
402
+ # including it in a subclass: https://gist.github.com/845896
403
+ # To prevent this, we must include any modules in
404
+ # RSpec::Core::ExampleGroup before users create example groups and have
405
+ # a chance to include the same module in a subclass of
406
+ # RSpec::Core::ExampleGroup. So we need to configure example groups
407
+ # here.
408
+ ensure_example_groups_are_configured
409
+
410
+ # Register the example with the group before creating the metadata hash.
411
+ # This is necessary since creating the metadata hash triggers
412
+ # `when_first_matching_example_defined` callbacks, in which users can
413
+ # load RSpec support code which defines hooks. For that to work, the
414
+ # examples and example groups must be registered at the time the
415
+ # support code is called or be defined afterwards.
416
+ # Begin defined beforehand but registered afterwards causes hooks to
417
+ # not be applied where they should.
418
+ registration_collection << self
419
+
420
+ @user_metadata = Metadata.build_hash_from(args)
421
+
422
+ @metadata = Metadata::ExampleGroupHash.create(
423
+ superclass_metadata, @user_metadata,
424
+ superclass.method(:next_runnable_index_for),
425
+ description, *args, &example_group_block
426
+ )
427
+
428
+ config = RSpec.configuration
429
+ config.apply_derived_metadata_to(@metadata)
430
+
431
+ ExampleGroups.assign_const(self)
432
+
433
+ @currently_executing_a_context_hook = false
434
+
435
+ config.configure_group(self)
436
+ end
437
+
438
+ # @private
439
+ def self.examples
440
+ @examples ||= []
441
+ end
442
+
443
+ # @private
444
+ def self.filtered_examples
445
+ RSpec.world.filtered_examples[self]
446
+ end
447
+
448
+ # @private
449
+ def self.descendant_filtered_examples
450
+ @descendant_filtered_examples ||= filtered_examples +
451
+ FlatMap.flat_map(children, &:descendant_filtered_examples)
452
+ end
453
+
454
+ # @private
455
+ def self.children
456
+ @children ||= []
457
+ end
458
+
459
+ # @private
460
+ # Traverses the tree of groups, starting with `self`, then the children, recursively.
461
+ # Halts the traversal of a branch of the tree as soon as the passed block returns true.
462
+ # Note that siblings groups and their sub-trees will continue to be explored.
463
+ # This is intended to make it easy to find the top-most group that satisfies some
464
+ # condition.
465
+ def self.traverse_tree_until(&block)
466
+ return if yield self
467
+
468
+ children.each do |child|
469
+ child.traverse_tree_until(&block)
470
+ end
471
+ end
472
+
473
+ # @private
474
+ def self.next_runnable_index_for(file)
475
+ if self == ExampleGroup
476
+ # We add 1 so the ids start at 1 instead of 0. This is
477
+ # necessary for this branch (but not for the other one)
478
+ # because we register examples and groups with the
479
+ # `children` and `examples` collection BEFORE this
480
+ # method is called as part of metadata hash creation,
481
+ # but the example group is recorded with
482
+ # `RSpec.world.example_group_counts_by_spec_file` AFTER
483
+ # the metadata hash is created and the group is returned
484
+ # to the caller.
485
+ RSpec.world.num_example_groups_defined_in(file) + 1
486
+ else
487
+ children.count + examples.count
488
+ end
489
+ end
490
+
491
+ # @private
492
+ def self.descendants
493
+ @_descendants ||= [self] + FlatMap.flat_map(children, &:descendants)
494
+ end
495
+
496
+ ## @private
497
+ def self.parent_groups
498
+ @parent_groups ||= ancestors.select { |a| a < RSpec::Core::ExampleGroup }
499
+ end
500
+
501
+ # @private
502
+ def self.top_level?
503
+ superclass == ExampleGroup
504
+ end
505
+
506
+ # @private
507
+ def self.ensure_example_groups_are_configured
508
+ unless defined?(@@example_groups_configured)
509
+ RSpec.configuration.configure_mock_framework
510
+ RSpec.configuration.configure_expectation_framework
511
+ # rubocop:disable Style/ClassVars
512
+ @@example_groups_configured = true
513
+ # rubocop:enable Style/ClassVars
514
+ end
515
+ end
516
+
517
+ # @private
518
+ def self.before_context_ivars
519
+ @before_context_ivars ||= {}
520
+ end
521
+
522
+ # @private
523
+ def self.store_before_context_ivars(example_group_instance)
524
+ each_instance_variable_for_example(example_group_instance) do |ivar|
525
+ before_context_ivars[ivar] = example_group_instance.instance_variable_get(ivar)
526
+ end
527
+ end
528
+
529
+ # Returns true if a `before(:context)` or `after(:context)`
530
+ # hook is currently executing.
531
+ def self.currently_executing_a_context_hook?
532
+ @currently_executing_a_context_hook
533
+ end
534
+
535
+ # @private
536
+ def self.run_before_context_hooks(example_group_instance)
537
+ set_ivars(example_group_instance, superclass_before_context_ivars)
538
+
539
+ @currently_executing_a_context_hook = true
540
+
541
+ ContextHookMemoized::Before.isolate_for_context_hook(example_group_instance) do
542
+ hooks.run(:before, :context, example_group_instance)
543
+ end
544
+ ensure
545
+ store_before_context_ivars(example_group_instance)
546
+ @currently_executing_a_context_hook = false
547
+ end
548
+
549
+ if RUBY_VERSION.to_f >= 1.9
550
+ # @private
551
+ def self.superclass_before_context_ivars
552
+ superclass.before_context_ivars
553
+ end
554
+ else # 1.8.7
555
+ # :nocov:
556
+ # @private
557
+ def self.superclass_before_context_ivars
558
+ if superclass.respond_to?(:before_context_ivars)
559
+ superclass.before_context_ivars
560
+ else
561
+ # `self` must be the singleton class of an ExampleGroup instance.
562
+ # On 1.8.7, the superclass of a singleton class of an instance of A
563
+ # is A's singleton class. On 1.9+, it's A. On 1.8.7, the first ancestor
564
+ # is A, so we can mirror 1.8.7's behavior here. Note that we have to
565
+ # search for the first that responds to `before_context_ivars`
566
+ # in case a module has been included in the singleton class.
567
+ ancestors.find { |a| a.respond_to?(:before_context_ivars) }.before_context_ivars
568
+ end
569
+ end
570
+ # :nocov:
571
+ end
572
+
573
+ # @private
574
+ def self.run_after_context_hooks(example_group_instance)
575
+ set_ivars(example_group_instance, before_context_ivars)
576
+
577
+ @currently_executing_a_context_hook = true
578
+
579
+ ContextHookMemoized::After.isolate_for_context_hook(example_group_instance) do
580
+ hooks.run(:after, :context, example_group_instance)
581
+ end
582
+ ensure
583
+ before_context_ivars.clear
584
+ @currently_executing_a_context_hook = false
585
+ end
586
+
587
+ # Runs all the examples in this group.
588
+ def self.run(reporter=RSpec::Core::NullReporter)
589
+ return if RSpec.world.wants_to_quit
590
+ reporter.example_group_started(self)
591
+
592
+ should_run_context_hooks = descendant_filtered_examples.any?
593
+ begin
594
+ run_before_context_hooks(new('before(:context) hook')) if should_run_context_hooks
595
+ result_for_this_group = run_examples(reporter)
596
+ results_for_descendants = ordering_strategy.order(children).map { |child| child.run(reporter) }.all?
597
+ result_for_this_group && results_for_descendants
598
+ rescue Pending::SkipDeclaredInExample => ex
599
+ for_filtered_examples(reporter) { |example| example.skip_with_exception(reporter, ex) }
600
+ true
601
+ rescue Support::AllExceptionsExceptOnesWeMustNotRescue => ex
602
+ for_filtered_examples(reporter) { |example| example.fail_with_exception(reporter, ex) }
603
+ RSpec.world.wants_to_quit = true if reporter.fail_fast_limit_met?
604
+ false
605
+ ensure
606
+ run_after_context_hooks(new('after(:context) hook')) if should_run_context_hooks
607
+ reporter.example_group_finished(self)
608
+ end
609
+ end
610
+
611
+ # @private
612
+ def self.ordering_strategy
613
+ order = metadata.fetch(:order, :global)
614
+ registry = RSpec.configuration.ordering_registry
615
+
616
+ registry.fetch(order) do
617
+ warn <<-WARNING.gsub(/^ +\|/, '')
618
+ |WARNING: Ignoring unknown ordering specified using `:order => #{order.inspect}` metadata.
619
+ | Falling back to configured global ordering.
620
+ | Unrecognized ordering specified at: #{location}
621
+ WARNING
622
+
623
+ registry.fetch(:global)
624
+ end
625
+ end
626
+
627
+ # @private
628
+ def self.run_examples(reporter)
629
+ ordering_strategy.order(filtered_examples).map do |example|
630
+ next if RSpec.world.wants_to_quit
631
+ instance = new(example.inspect_output)
632
+ set_ivars(instance, before_context_ivars)
633
+ succeeded = example.run(instance, reporter)
634
+ if !succeeded && reporter.fail_fast_limit_met?
635
+ RSpec.world.wants_to_quit = true
636
+ end
637
+ succeeded
638
+ end.all?
639
+ end
640
+
641
+ # @private
642
+ def self.for_filtered_examples(reporter, &block)
643
+ filtered_examples.each(&block)
644
+
645
+ children.each do |child|
646
+ reporter.example_group_started(child)
647
+ child.for_filtered_examples(reporter, &block)
648
+ reporter.example_group_finished(child)
649
+ end
650
+ false
651
+ end
652
+
653
+ # @private
654
+ def self.declaration_locations
655
+ @declaration_locations ||= [Metadata.location_tuple_from(metadata)] +
656
+ examples.map { |e| Metadata.location_tuple_from(e.metadata) } +
657
+ FlatMap.flat_map(children, &:declaration_locations)
658
+ end
659
+
660
+ # @return [String] the unique id of this example group. Pass
661
+ # this at the command line to re-run this exact example group.
662
+ def self.id
663
+ Metadata.id_from(metadata)
664
+ end
665
+
666
+ # @private
667
+ def self.top_level_description
668
+ parent_groups.last.description
669
+ end
670
+
671
+ # @private
672
+ def self.set_ivars(instance, ivars)
673
+ ivars.each { |name, value| instance.instance_variable_set(name, value) }
674
+ end
675
+
676
+ if RUBY_VERSION.to_f < 1.9
677
+ # :nocov:
678
+ # @private
679
+ INSTANCE_VARIABLE_TO_IGNORE = '@__inspect_output'.freeze
680
+ # :nocov:
681
+ else
682
+ # @private
683
+ INSTANCE_VARIABLE_TO_IGNORE = :@__inspect_output
684
+ end
685
+
686
+ # @private
687
+ def self.each_instance_variable_for_example(group)
688
+ group.instance_variables.each do |ivar|
689
+ yield ivar unless ivar == INSTANCE_VARIABLE_TO_IGNORE
690
+ end
691
+ end
692
+
693
+ def initialize(inspect_output=nil)
694
+ @__inspect_output = inspect_output || '(no description provided)'
695
+ super() # no args get passed
696
+ end
697
+
698
+ # @private
699
+ def inspect
700
+ "#<#{self.class} #{@__inspect_output}>"
701
+ end
702
+
703
+ unless method_defined?(:singleton_class) # for 1.8.7
704
+ # :nocov:
705
+ # @private
706
+ def singleton_class
707
+ class << self; self; end
708
+ end
709
+ # :nocov:
710
+ end
711
+
712
+ # @private
713
+ def self.update_inherited_metadata(updates)
714
+ metadata.update(updates) do |key, existing_group_value, new_inherited_value|
715
+ @user_metadata.key?(key) ? existing_group_value : new_inherited_value
716
+ end
717
+
718
+ RSpec.configuration.configure_group(self)
719
+ examples.each { |ex| ex.update_inherited_metadata(updates) }
720
+ children.each { |group| group.update_inherited_metadata(updates) }
721
+ end
722
+
723
+ # Raised when an RSpec API is called in the wrong scope, such as `before`
724
+ # being called from within an example rather than from within an example
725
+ # group block.
726
+ WrongScopeError = Class.new(NoMethodError)
727
+
728
+ def self.method_missing(name, *args)
729
+ if method_defined?(name)
730
+ raise WrongScopeError,
731
+ "`#{name}` is not available on an example group (e.g. a " \
732
+ "`describe` or `context` block). It is only available from " \
733
+ "within individual examples (e.g. `it` blocks) or from " \
734
+ "constructs that run in the scope of an example (e.g. " \
735
+ "`before`, `let`, etc)."
736
+ end
737
+
738
+ super
739
+ end
740
+ private_class_method :method_missing
741
+
742
+ private
743
+
744
+ def method_missing(name, *args)
745
+ if self.class.respond_to?(name)
746
+ raise WrongScopeError,
747
+ "`#{name}` is not available from within an example (e.g. an " \
748
+ "`it` block) or from constructs that run in the scope of an " \
749
+ "example (e.g. `before`, `let`, etc). It is only available " \
750
+ "on an example group (e.g. a `describe` or `context` block)."
751
+ end
752
+
753
+ super
754
+ end
755
+ end
756
+ # rubocop:enable Metrics/ClassLength
757
+
758
+ # @private
759
+ # Unnamed example group used by `SuiteHookContext`.
760
+ class AnonymousExampleGroup < ExampleGroup
761
+ def self.metadata
762
+ {}
763
+ end
764
+ end
765
+
766
+ # Contains information about the inclusion site of a shared example group.
767
+ class SharedExampleGroupInclusionStackFrame
768
+ # @return [String] the name of the shared example group
769
+ attr_reader :shared_group_name
770
+ # @return [String] the location where the shared example was included
771
+ attr_reader :inclusion_location
772
+
773
+ def initialize(shared_group_name, inclusion_location)
774
+ @shared_group_name = shared_group_name
775
+ @inclusion_location = inclusion_location
776
+ end
777
+
778
+ # @return [String] The {#inclusion_location}, formatted for display by a formatter.
779
+ def formatted_inclusion_location
780
+ @formatted_inclusion_location ||= begin
781
+ RSpec.configuration.backtrace_formatter.backtrace_line(
782
+ inclusion_location.sub(/(:\d+):in .+$/, '\1')
783
+ )
784
+ end
785
+ end
786
+
787
+ # @return [String] Description of this stack frame, in the form used by
788
+ # RSpec's built-in formatters.
789
+ def description
790
+ @description ||= "Shared Example Group: #{shared_group_name.inspect} " \
791
+ "called from #{formatted_inclusion_location}"
792
+ end
793
+
794
+ # @private
795
+ def self.current_backtrace
796
+ shared_example_group_inclusions.reverse
797
+ end
798
+
799
+ # @private
800
+ def self.with_frame(name, location)
801
+ current_stack = shared_example_group_inclusions
802
+ if current_stack.any? { |frame| frame.shared_group_name == name }
803
+ raise ArgumentError, "can't include shared examples recursively"
804
+ else
805
+ current_stack << new(name, location)
806
+ yield
807
+ end
808
+ ensure
809
+ current_stack.pop
810
+ end
811
+
812
+ # @private
813
+ def self.shared_example_group_inclusions
814
+ RSpec::Support.thread_local_data[:shared_example_group_inclusions] ||= []
815
+ end
816
+ end
817
+ end
818
+
819
+ # @private
820
+ #
821
+ # Namespace for the example group subclasses generated by top-level
822
+ # `describe`.
823
+ module ExampleGroups
824
+ extend Support::RecursiveConstMethods
825
+
826
+ def self.assign_const(group)
827
+ base_name = base_name_for(group)
828
+ const_scope = constant_scope_for(group)
829
+ name = disambiguate(base_name, const_scope)
830
+
831
+ const_scope.const_set(name, group)
832
+ end
833
+
834
+ def self.constant_scope_for(group)
835
+ const_scope = group.superclass
836
+ const_scope = self if const_scope == ::RSpec::Core::ExampleGroup
837
+ const_scope
838
+ end
839
+
840
+ def self.remove_all_constants
841
+ constants.each do |constant|
842
+ __send__(:remove_const, constant)
843
+ end
844
+ end
845
+
846
+ def self.base_name_for(group)
847
+ return "Anonymous".dup if group.description.empty?
848
+
849
+ # Convert to CamelCase.
850
+ name = ' ' + group.description
851
+ name.gsub!(/[^0-9a-zA-Z]+([0-9a-zA-Z])/) do
852
+ match = ::Regexp.last_match[1]
853
+ match.upcase!
854
+ match
855
+ end
856
+
857
+ name.lstrip! # Remove leading whitespace
858
+ name.gsub!(/\W/, ''.freeze) # JRuby, RBX and others don't like non-ascii in const names
859
+
860
+ # Ruby requires first const letter to be A-Z. Use `Nested`
861
+ # as necessary to enforce that.
862
+ name.gsub!(/\A([^A-Z]|\z)/, 'Nested\1'.freeze)
863
+
864
+ name
865
+ end
866
+
867
+ if RUBY_VERSION == '1.9.2'
868
+ # :nocov:
869
+ class << self
870
+ alias _base_name_for base_name_for
871
+ def base_name_for(group)
872
+ _base_name_for(group) + '_'
873
+ end
874
+ end
875
+ private_class_method :_base_name_for
876
+ # :nocov:
877
+ end
878
+
879
+ def self.disambiguate(name, const_scope)
880
+ return name unless const_defined_on?(const_scope, name)
881
+
882
+ # Add a trailing number if needed to disambiguate from an existing
883
+ # constant.
884
+ name << "_2"
885
+ name.next! while const_defined_on?(const_scope, name)
886
+ name
887
+ end
888
+ end
889
+ end