sspec-core 3.8.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (81) hide show
  1. checksums.yaml +7 -0
  2. data/.document +5 -0
  3. data/.yardopts +8 -0
  4. data/Changelog.md +2232 -0
  5. data/LICENSE.md +26 -0
  6. data/README.md +384 -0
  7. data/exe/rspec +4 -0
  8. data/lib/rspec/autorun.rb +3 -0
  9. data/lib/rspec/core.rb +185 -0
  10. data/lib/rspec/core/backtrace_formatter.rb +65 -0
  11. data/lib/rspec/core/bisect/coordinator.rb +62 -0
  12. data/lib/rspec/core/bisect/example_minimizer.rb +173 -0
  13. data/lib/rspec/core/bisect/fork_runner.rb +134 -0
  14. data/lib/rspec/core/bisect/server.rb +61 -0
  15. data/lib/rspec/core/bisect/shell_command.rb +126 -0
  16. data/lib/rspec/core/bisect/shell_runner.rb +73 -0
  17. data/lib/rspec/core/bisect/utilities.rb +58 -0
  18. data/lib/rspec/core/configuration.rb +2289 -0
  19. data/lib/rspec/core/configuration_options.rb +233 -0
  20. data/lib/rspec/core/drb.rb +113 -0
  21. data/lib/rspec/core/dsl.rb +98 -0
  22. data/lib/rspec/core/example.rb +653 -0
  23. data/lib/rspec/core/example_group.rb +885 -0
  24. data/lib/rspec/core/example_status_persister.rb +235 -0
  25. data/lib/rspec/core/filter_manager.rb +231 -0
  26. data/lib/rspec/core/flat_map.rb +20 -0
  27. data/lib/rspec/core/formatters.rb +269 -0
  28. data/lib/rspec/core/formatters/base_bisect_formatter.rb +45 -0
  29. data/lib/rspec/core/formatters/base_formatter.rb +70 -0
  30. data/lib/rspec/core/formatters/base_text_formatter.rb +75 -0
  31. data/lib/rspec/core/formatters/bisect_drb_formatter.rb +29 -0
  32. data/lib/rspec/core/formatters/bisect_progress_formatter.rb +157 -0
  33. data/lib/rspec/core/formatters/console_codes.rb +68 -0
  34. data/lib/rspec/core/formatters/deprecation_formatter.rb +223 -0
  35. data/lib/rspec/core/formatters/documentation_formatter.rb +70 -0
  36. data/lib/rspec/core/formatters/exception_presenter.rb +508 -0
  37. data/lib/rspec/core/formatters/fallback_message_formatter.rb +28 -0
  38. data/lib/rspec/core/formatters/helpers.rb +110 -0
  39. data/lib/rspec/core/formatters/html_formatter.rb +153 -0
  40. data/lib/rspec/core/formatters/html_printer.rb +414 -0
  41. data/lib/rspec/core/formatters/html_snippet_extractor.rb +120 -0
  42. data/lib/rspec/core/formatters/json_formatter.rb +102 -0
  43. data/lib/rspec/core/formatters/profile_formatter.rb +68 -0
  44. data/lib/rspec/core/formatters/progress_formatter.rb +29 -0
  45. data/lib/rspec/core/formatters/protocol.rb +182 -0
  46. data/lib/rspec/core/formatters/snippet_extractor.rb +134 -0
  47. data/lib/rspec/core/formatters/syntax_highlighter.rb +91 -0
  48. data/lib/rspec/core/hooks.rb +624 -0
  49. data/lib/rspec/core/invocations.rb +87 -0
  50. data/lib/rspec/core/memoized_helpers.rb +554 -0
  51. data/lib/rspec/core/metadata.rb +499 -0
  52. data/lib/rspec/core/metadata_filter.rb +255 -0
  53. data/lib/rspec/core/minitest_assertions_adapter.rb +31 -0
  54. data/lib/rspec/core/mocking_adapters/flexmock.rb +31 -0
  55. data/lib/rspec/core/mocking_adapters/mocha.rb +57 -0
  56. data/lib/rspec/core/mocking_adapters/null.rb +14 -0
  57. data/lib/rspec/core/mocking_adapters/rr.rb +31 -0
  58. data/lib/rspec/core/mocking_adapters/rspec.rb +32 -0
  59. data/lib/rspec/core/notifications.rb +521 -0
  60. data/lib/rspec/core/option_parser.rb +309 -0
  61. data/lib/rspec/core/ordering.rb +158 -0
  62. data/lib/rspec/core/output_wrapper.rb +29 -0
  63. data/lib/rspec/core/pending.rb +165 -0
  64. data/lib/rspec/core/profiler.rb +34 -0
  65. data/lib/rspec/core/project_initializer.rb +48 -0
  66. data/lib/rspec/core/project_initializer/.rspec +1 -0
  67. data/lib/rspec/core/project_initializer/spec/spec_helper.rb +100 -0
  68. data/lib/rspec/core/rake_task.rb +168 -0
  69. data/lib/rspec/core/reporter.rb +257 -0
  70. data/lib/rspec/core/ruby_project.rb +53 -0
  71. data/lib/rspec/core/runner.rb +199 -0
  72. data/lib/rspec/core/sandbox.rb +37 -0
  73. data/lib/rspec/core/set.rb +54 -0
  74. data/lib/rspec/core/shared_context.rb +55 -0
  75. data/lib/rspec/core/shared_example_group.rb +269 -0
  76. data/lib/rspec/core/shell_escape.rb +49 -0
  77. data/lib/rspec/core/test_unit_assertions_adapter.rb +30 -0
  78. data/lib/rspec/core/version.rb +9 -0
  79. data/lib/rspec/core/warnings.rb +40 -0
  80. data/lib/rspec/core/world.rb +275 -0
  81. metadata +257 -0
@@ -0,0 +1,885 @@
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
+ ExampleGroups.assign_const(self)
428
+
429
+ @currently_executing_a_context_hook = false
430
+
431
+ RSpec.configuration.configure_group(self)
432
+ end
433
+
434
+ # @private
435
+ def self.examples
436
+ @examples ||= []
437
+ end
438
+
439
+ # @private
440
+ def self.filtered_examples
441
+ RSpec.world.filtered_examples[self]
442
+ end
443
+
444
+ # @private
445
+ def self.descendant_filtered_examples
446
+ @descendant_filtered_examples ||= filtered_examples +
447
+ FlatMap.flat_map(children, &:descendant_filtered_examples)
448
+ end
449
+
450
+ # @private
451
+ def self.children
452
+ @children ||= []
453
+ end
454
+
455
+ # @private
456
+ # Traverses the tree of groups, starting with `self`, then the children, recursively.
457
+ # Halts the traversal of a branch of the tree as soon as the passed block returns true.
458
+ # Note that siblings groups and their sub-trees will continue to be explored.
459
+ # This is intended to make it easy to find the top-most group that satisfies some
460
+ # condition.
461
+ def self.traverse_tree_until(&block)
462
+ return if yield self
463
+
464
+ children.each do |child|
465
+ child.traverse_tree_until(&block)
466
+ end
467
+ end
468
+
469
+ # @private
470
+ def self.next_runnable_index_for(file)
471
+ if self == ExampleGroup
472
+ # We add 1 so the ids start at 1 instead of 0. This is
473
+ # necessary for this branch (but not for the other one)
474
+ # because we register examples and groups with the
475
+ # `children` and `examples` collection BEFORE this
476
+ # method is called as part of metadata hash creation,
477
+ # but the example group is recorded with
478
+ # `RSpec.world.example_group_counts_by_spec_file` AFTER
479
+ # the metadata hash is created and the group is returned
480
+ # to the caller.
481
+ RSpec.world.num_example_groups_defined_in(file) + 1
482
+ else
483
+ children.count + examples.count
484
+ end
485
+ end
486
+
487
+ # @private
488
+ def self.descendants
489
+ @_descendants ||= [self] + FlatMap.flat_map(children, &:descendants)
490
+ end
491
+
492
+ ## @private
493
+ def self.parent_groups
494
+ @parent_groups ||= ancestors.select { |a| a < RSpec::Core::ExampleGroup }
495
+ end
496
+
497
+ # @private
498
+ def self.top_level?
499
+ superclass == ExampleGroup
500
+ end
501
+
502
+ # @private
503
+ def self.ensure_example_groups_are_configured
504
+ unless defined?(@@example_groups_configured)
505
+ RSpec.configuration.configure_mock_framework
506
+ RSpec.configuration.configure_expectation_framework
507
+ # rubocop:disable Style/ClassVars
508
+ @@example_groups_configured = true
509
+ # rubocop:enable Style/ClassVars
510
+ end
511
+ end
512
+
513
+ # @private
514
+ def self.before_context_ivars
515
+ @before_context_ivars ||= {}
516
+ end
517
+
518
+ # @private
519
+ def self.store_before_context_ivars(example_group_instance)
520
+ each_instance_variable_for_example(example_group_instance) do |ivar|
521
+ before_context_ivars[ivar] = example_group_instance.instance_variable_get(ivar)
522
+ end
523
+ end
524
+
525
+ # Returns true if a `before(:context)` or `after(:context)`
526
+ # hook is currently executing.
527
+ def self.currently_executing_a_context_hook?
528
+ @currently_executing_a_context_hook
529
+ end
530
+
531
+ # @private
532
+ def self.run_before_context_hooks(example_group_instance)
533
+ set_ivars(example_group_instance, superclass_before_context_ivars)
534
+
535
+ @currently_executing_a_context_hook = true
536
+
537
+ ContextHookMemoized::Before.isolate_for_context_hook(example_group_instance) do
538
+ hooks.run(:before, :context, example_group_instance)
539
+ end
540
+ ensure
541
+ store_before_context_ivars(example_group_instance)
542
+ @currently_executing_a_context_hook = false
543
+ end
544
+
545
+ if RUBY_VERSION.to_f >= 1.9
546
+ # @private
547
+ def self.superclass_before_context_ivars
548
+ superclass.before_context_ivars
549
+ end
550
+ else # 1.8.7
551
+ # :nocov:
552
+ # @private
553
+ def self.superclass_before_context_ivars
554
+ if superclass.respond_to?(:before_context_ivars)
555
+ superclass.before_context_ivars
556
+ else
557
+ # `self` must be the singleton class of an ExampleGroup instance.
558
+ # On 1.8.7, the superclass of a singleton class of an instance of A
559
+ # is A's singleton class. On 1.9+, it's A. On 1.8.7, the first ancestor
560
+ # is A, so we can mirror 1.8.7's behavior here. Note that we have to
561
+ # search for the first that responds to `before_context_ivars`
562
+ # in case a module has been included in the singleton class.
563
+ ancestors.find { |a| a.respond_to?(:before_context_ivars) }.before_context_ivars
564
+ end
565
+ end
566
+ # :nocov:
567
+ end
568
+
569
+ # @private
570
+ def self.run_after_context_hooks(example_group_instance)
571
+ set_ivars(example_group_instance, before_context_ivars)
572
+
573
+ @currently_executing_a_context_hook = true
574
+
575
+ ContextHookMemoized::After.isolate_for_context_hook(example_group_instance) do
576
+ hooks.run(:after, :context, example_group_instance)
577
+ end
578
+ ensure
579
+ before_context_ivars.clear
580
+ @currently_executing_a_context_hook = false
581
+ end
582
+
583
+ # Runs all the examples in this group.
584
+ def self.run(reporter=RSpec::Core::NullReporter)
585
+ return if RSpec.world.wants_to_quit
586
+ reporter.example_group_started(self)
587
+
588
+ should_run_context_hooks = descendant_filtered_examples.any?
589
+ begin
590
+ run_before_context_hooks(new('before(:context) hook')) if should_run_context_hooks
591
+ result_for_this_group = run_examples(reporter)
592
+ results_for_descendants = ordering_strategy.order(children).map { |child| child.run(reporter) }.all?
593
+ result_for_this_group && results_for_descendants
594
+ rescue Pending::SkipDeclaredInExample => ex
595
+ for_filtered_examples(reporter) { |example| example.skip_with_exception(reporter, ex) }
596
+ true
597
+ rescue Support::AllExceptionsExceptOnesWeMustNotRescue => ex
598
+ for_filtered_examples(reporter) { |example| example.fail_with_exception(reporter, ex) }
599
+ RSpec.world.wants_to_quit = true if reporter.fail_fast_limit_met?
600
+ false
601
+ ensure
602
+ run_after_context_hooks(new('after(:context) hook')) if should_run_context_hooks
603
+ reporter.example_group_finished(self)
604
+ end
605
+ end
606
+
607
+ # @private
608
+ def self.ordering_strategy
609
+ order = metadata.fetch(:order, :global)
610
+ registry = RSpec.configuration.ordering_registry
611
+
612
+ registry.fetch(order) do
613
+ warn <<-WARNING.gsub(/^ +\|/, '')
614
+ |WARNING: Ignoring unknown ordering specified using `:order => #{order.inspect}` metadata.
615
+ | Falling back to configured global ordering.
616
+ | Unrecognized ordering specified at: #{location}
617
+ WARNING
618
+
619
+ registry.fetch(:global)
620
+ end
621
+ end
622
+
623
+ # @private
624
+ def self.run_examples(reporter)
625
+ ordering_strategy.order(filtered_examples).map do |example|
626
+ next if RSpec.world.wants_to_quit
627
+ instance = new(example.inspect_output)
628
+ set_ivars(instance, before_context_ivars)
629
+ succeeded = example.run(instance, reporter)
630
+ if !succeeded && reporter.fail_fast_limit_met?
631
+ RSpec.world.wants_to_quit = true
632
+ end
633
+ succeeded
634
+ end.all?
635
+ end
636
+
637
+ # @private
638
+ def self.for_filtered_examples(reporter, &block)
639
+ filtered_examples.each(&block)
640
+
641
+ children.each do |child|
642
+ reporter.example_group_started(child)
643
+ child.for_filtered_examples(reporter, &block)
644
+ reporter.example_group_finished(child)
645
+ end
646
+ false
647
+ end
648
+
649
+ # @private
650
+ def self.declaration_locations
651
+ @declaration_locations ||= [Metadata.location_tuple_from(metadata)] +
652
+ examples.map { |e| Metadata.location_tuple_from(e.metadata) } +
653
+ FlatMap.flat_map(children, &:declaration_locations)
654
+ end
655
+
656
+ # @return [String] the unique id of this example group. Pass
657
+ # this at the command line to re-run this exact example group.
658
+ def self.id
659
+ Metadata.id_from(metadata)
660
+ end
661
+
662
+ # @private
663
+ def self.top_level_description
664
+ parent_groups.last.description
665
+ end
666
+
667
+ # @private
668
+ def self.set_ivars(instance, ivars)
669
+ ivars.each { |name, value| instance.instance_variable_set(name, value) }
670
+ end
671
+
672
+ if RUBY_VERSION.to_f < 1.9
673
+ # :nocov:
674
+ # @private
675
+ INSTANCE_VARIABLE_TO_IGNORE = '@__inspect_output'.freeze
676
+ # :nocov:
677
+ else
678
+ # @private
679
+ INSTANCE_VARIABLE_TO_IGNORE = :@__inspect_output
680
+ end
681
+
682
+ # @private
683
+ def self.each_instance_variable_for_example(group)
684
+ group.instance_variables.each do |ivar|
685
+ yield ivar unless ivar == INSTANCE_VARIABLE_TO_IGNORE
686
+ end
687
+ end
688
+
689
+ def initialize(inspect_output=nil)
690
+ @__inspect_output = inspect_output || '(no description provided)'
691
+ super() # no args get passed
692
+ end
693
+
694
+ # @private
695
+ def inspect
696
+ "#<#{self.class} #{@__inspect_output}>"
697
+ end
698
+
699
+ unless method_defined?(:singleton_class) # for 1.8.7
700
+ # :nocov:
701
+ # @private
702
+ def singleton_class
703
+ class << self; self; end
704
+ end
705
+ # :nocov:
706
+ end
707
+
708
+ # @private
709
+ def self.update_inherited_metadata(updates)
710
+ metadata.update(updates) do |key, existing_group_value, new_inherited_value|
711
+ @user_metadata.key?(key) ? existing_group_value : new_inherited_value
712
+ end
713
+
714
+ RSpec.configuration.configure_group(self)
715
+ examples.each { |ex| ex.update_inherited_metadata(updates) }
716
+ children.each { |group| group.update_inherited_metadata(updates) }
717
+ end
718
+
719
+ # Raised when an RSpec API is called in the wrong scope, such as `before`
720
+ # being called from within an example rather than from within an example
721
+ # group block.
722
+ WrongScopeError = Class.new(NoMethodError)
723
+
724
+ def self.method_missing(name, *args)
725
+ if method_defined?(name)
726
+ raise WrongScopeError,
727
+ "`#{name}` is not available on an example group (e.g. a " \
728
+ "`describe` or `context` block). It is only available from " \
729
+ "within individual examples (e.g. `it` blocks) or from " \
730
+ "constructs that run in the scope of an example (e.g. " \
731
+ "`before`, `let`, etc)."
732
+ end
733
+
734
+ super
735
+ end
736
+ private_class_method :method_missing
737
+
738
+ private
739
+
740
+ def method_missing(name, *args)
741
+ if self.class.respond_to?(name)
742
+ raise WrongScopeError,
743
+ "`#{name}` is not available from within an example (e.g. an " \
744
+ "`it` block) or from constructs that run in the scope of an " \
745
+ "example (e.g. `before`, `let`, etc). It is only available " \
746
+ "on an example group (e.g. a `describe` or `context` block)."
747
+ end
748
+
749
+ super
750
+ end
751
+ end
752
+ # rubocop:enable Metrics/ClassLength
753
+
754
+ # @private
755
+ # Unnamed example group used by `SuiteHookContext`.
756
+ class AnonymousExampleGroup < ExampleGroup
757
+ def self.metadata
758
+ {}
759
+ end
760
+ end
761
+
762
+ # Contains information about the inclusion site of a shared example group.
763
+ class SharedExampleGroupInclusionStackFrame
764
+ # @return [String] the name of the shared example group
765
+ attr_reader :shared_group_name
766
+ # @return [String] the location where the shared example was included
767
+ attr_reader :inclusion_location
768
+
769
+ def initialize(shared_group_name, inclusion_location)
770
+ @shared_group_name = shared_group_name
771
+ @inclusion_location = inclusion_location
772
+ end
773
+
774
+ # @return [String] The {#inclusion_location}, formatted for display by a formatter.
775
+ def formatted_inclusion_location
776
+ @formatted_inclusion_location ||= begin
777
+ RSpec.configuration.backtrace_formatter.backtrace_line(
778
+ inclusion_location.sub(/(:\d+):in .+$/, '\1')
779
+ )
780
+ end
781
+ end
782
+
783
+ # @return [String] Description of this stack frame, in the form used by
784
+ # RSpec's built-in formatters.
785
+ def description
786
+ @description ||= "Shared Example Group: #{shared_group_name.inspect} " \
787
+ "called from #{formatted_inclusion_location}"
788
+ end
789
+
790
+ # @private
791
+ def self.current_backtrace
792
+ shared_example_group_inclusions.reverse
793
+ end
794
+
795
+ # @private
796
+ def self.with_frame(name, location)
797
+ current_stack = shared_example_group_inclusions
798
+ if current_stack.any? { |frame| frame.shared_group_name == name }
799
+ raise ArgumentError, "can't include shared examples recursively"
800
+ else
801
+ current_stack << new(name, location)
802
+ yield
803
+ end
804
+ ensure
805
+ current_stack.pop
806
+ end
807
+
808
+ # @private
809
+ def self.shared_example_group_inclusions
810
+ RSpec::Support.thread_local_data[:shared_example_group_inclusions] ||= []
811
+ end
812
+ end
813
+ end
814
+
815
+ # @private
816
+ #
817
+ # Namespace for the example group subclasses generated by top-level
818
+ # `describe`.
819
+ module ExampleGroups
820
+ extend Support::RecursiveConstMethods
821
+
822
+ def self.assign_const(group)
823
+ base_name = base_name_for(group)
824
+ const_scope = constant_scope_for(group)
825
+ name = disambiguate(base_name, const_scope)
826
+
827
+ const_scope.const_set(name, group)
828
+ end
829
+
830
+ def self.constant_scope_for(group)
831
+ const_scope = group.superclass
832
+ const_scope = self if const_scope == ::RSpec::Core::ExampleGroup
833
+ const_scope
834
+ end
835
+
836
+ def self.remove_all_constants
837
+ constants.each do |constant|
838
+ __send__(:remove_const, constant)
839
+ end
840
+ end
841
+
842
+ def self.base_name_for(group)
843
+ return "Anonymous".dup if group.description.empty?
844
+
845
+ # Convert to CamelCase.
846
+ name = ' ' + group.description
847
+ name.gsub!(/[^0-9a-zA-Z]+([0-9a-zA-Z])/) do
848
+ match = ::Regexp.last_match[1]
849
+ match.upcase!
850
+ match
851
+ end
852
+
853
+ name.lstrip! # Remove leading whitespace
854
+ name.gsub!(/\W/, ''.freeze) # JRuby, RBX and others don't like non-ascii in const names
855
+
856
+ # Ruby requires first const letter to be A-Z. Use `Nested`
857
+ # as necessary to enforce that.
858
+ name.gsub!(/\A([^A-Z]|\z)/, 'Nested\1'.freeze)
859
+
860
+ name
861
+ end
862
+
863
+ if RUBY_VERSION == '1.9.2'
864
+ # :nocov:
865
+ class << self
866
+ alias _base_name_for base_name_for
867
+ def base_name_for(group)
868
+ _base_name_for(group) + '_'
869
+ end
870
+ end
871
+ private_class_method :_base_name_for
872
+ # :nocov:
873
+ end
874
+
875
+ def self.disambiguate(name, const_scope)
876
+ return name unless const_defined_on?(const_scope, name)
877
+
878
+ # Add a trailing number if needed to disambiguate from an existing
879
+ # constant.
880
+ name << "_2"
881
+ name.next! while const_defined_on?(const_scope, name)
882
+ name
883
+ end
884
+ end
885
+ end