Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Newer
Older
100644 797 lines (684 sloc) 28.145 kB
2014378 @jimmycuadra Prevent example groups named "Config" from generating a deprecation w…
jimmycuadra authored
1 RSpec::Support.require_rspec_support 'recursive_const_methods'
2
bcb1dfa @dchelimsky change top-level module from Rspec to RSpec
dchelimsky authored
3 module RSpec
afca728 @spicycode Initial migration of Micronaut to Spec/Core
spicycode authored
4 module Core
d024dc9 @dchelimsky rdoc - use the {name} syntax for links [ci skip]
dchelimsky authored
5 # ExampleGroup and {Example} are the main structural elements of
5fc29a1 @yous Fix grammer
yous authored
6 # rspec-core. Consider this example:
480f419 @dchelimsky rename ClassMethods/InstanceMethods to ExampleGroupMethods/ExampleMet…
dchelimsky authored
7 #
8 # describe Thing do
9 # it "does something" do
10 # end
11 # end
12 #
13 # The object returned by `describe Thing` is a subclass of ExampleGroup.
14 # The object returned by `it "does something"` is an instance of Example,
15 # which serves as a wrapper for an instance of the ExampleGroup in which it
16 # is declared.
3951d7c @myronmarston Improve docs.
myronmarston authored
17 #
18 # Example group bodies (e.g. `describe` or `context` blocks) are evaluated
19 # in the context of a new subclass of ExampleGroup. Individual examples are
0ecabf9 @yous Keep comment line length to 80
yous authored
20 # evaluated in the context of an instance of the specific ExampleGroup
21 # subclass to which they belong.
a443297 @myronmarston Improve docs some more.
myronmarston authored
22 #
23 # Besides the class methods defined here, there are other interesting macros
0ecabf9 @yous Keep comment line length to 80
yous authored
24 # defined in {Hooks}, {MemoizedHelpers::ClassMethods} and
9653904 @myronmarston Revert "Reify shared example groups as a first-class type."
myronmarston authored
25 # {SharedExampleGroup}. There are additional instance methods available to
26 # your examples defined in {MemoizedHelpers} and {Pending}.
6cbbaa7 @spicycode Renamed spec/core/behaviour -> spec/core/example_group
spicycode authored
27 class ExampleGroup
d06ffe8 @alex-tan Setup rubocop
alex-tan authored
28 extend Hooks
17782b0 @dchelimsky easier on the eyes
dchelimsky authored
29
0c70d63 @exviva Combine Let and Subject modules into one
exviva authored
30 include MemoizedHelpers
d06ffe8 @alex-tan Setup rubocop
alex-tan authored
31 extend MemoizedHelpers::ClassMethods
9415f86 @dchelimsky add group.top_level_description
dchelimsky authored
32 include Pending
9653904 @myronmarston Revert "Reify shared example groups as a first-class type."
myronmarston authored
33 extend SharedExampleGroup
e9f9556 @spicycode Initial metadata reorg, still needs cleanup
spicycode authored
34
350fe50 @myronmarston Make example group alias definitions idempotent w/ no warnings.
myronmarston authored
35 # @private
36 def self.idempotently_define_singleton_method(name, &definition)
37 (class << self; self; end).module_exec do
3932d82 Check if method belongs to singleton_class before removing it
Alex Kwiatkowski and Ryan Ong authored
38 remove_method(name) if method_defined?(name) && instance_method(name).owner == self
350fe50 @myronmarston Make example group alias definitions idempotent w/ no warnings.
myronmarston authored
39 define_method(name, &definition)
9415f86 @dchelimsky add group.top_level_description
dchelimsky authored
40 end
909fd04 @myronmarston Refactor example group macros.
myronmarston authored
41 end
9415f86 @dchelimsky add group.top_level_description
dchelimsky authored
42
6ccf70b @myronmarston Provide doc groupings.
myronmarston authored
43 # @!group Metadata
44
e41ae45 @myronmarston Organize ExampleGroup methods into a logical order.
myronmarston authored
45 # The [Metadata](Metadata) object associated with this group.
46 # @see Metadata
47 def self.metadata
a1a3dc4 @myronmarston Improve perf of metadata-based shared group inclusion.
myronmarston authored
48 @metadata ||= nil
49 end
50
51 # Temporarily replace the provided metadata.
52 # Intended primarily to allow an example group's singleton class
53 # to return the metadata of the example that it exists for. This
54 # is necessary for shared example group inclusion to work properly
55 # with singleton example groups.
56 # @private
57 def self.with_replaced_metadata(meta)
58 orig_metadata = metadata
59 @metadata = meta
60 yield
61 ensure
62 @metadata = orig_metadata
e41ae45 @myronmarston Organize ExampleGroup methods into a logical order.
myronmarston authored
63 end
64
65 # @private
66 # @return [Metadata] belonging to the parent of a nested {ExampleGroup}
67 def self.superclass_metadata
d06ffe8 @alex-tan Setup rubocop
alex-tan authored
68 @superclass_metadata ||= superclass.respond_to?(:metadata) ? superclass.metadata : nil
e41ae45 @myronmarston Organize ExampleGroup methods into a logical order.
myronmarston authored
69 end
70
909fd04 @myronmarston Refactor example group macros.
myronmarston authored
71 # @private
72 def self.delegate_to_metadata(*names)
73 names.each do |name|
350fe50 @myronmarston Make example group alias definitions idempotent w/ no warnings.
myronmarston authored
74 idempotently_define_singleton_method(name) { metadata.fetch(name) }
909fd04 @myronmarston Refactor example group macros.
myronmarston authored
75 end
76 end
763eaab @dchelimsky better messages for xit, xspecify, xexample
dchelimsky authored
77
909fd04 @myronmarston Refactor example group macros.
myronmarston authored
78 delegate_to_metadata :described_class, :file_path, :location
79
e41ae45 @myronmarston Organize ExampleGroup methods into a logical order.
myronmarston authored
80 # @return [String] the current example group description
81 def self.description
82 description = metadata[:description]
83 RSpec.configuration.format_docstrings_block.call(description)
84 end
85
86 # Returns the class or module passed to the `describe` method (or alias).
87 # Returns nil if the subject is not a class or module.
88 # @example
89 # describe Thing do
90 # it "does something" do
91 # described_class == Thing
92 # end
93 # end
94 #
95 def described_class
96 self.class.described_class
97 end
98
6ccf70b @myronmarston Provide doc groupings.
myronmarston authored
99 # @!endgroup
100
101 # @!group Defining Examples
102
909fd04 @myronmarston Refactor example group macros.
myronmarston authored
103 # @private
104 # @macro [attach] define_example_method
3951d7c @myronmarston Improve docs.
myronmarston authored
105 # @!scope class
2e27245 @myronmarston Fix docs for example/example_group alias methods.
myronmarston authored
106 # @overload $1
107 # @overload $1(&example_implementation)
108 # @param example_implementation [Block] The implementation of the example.
109 # @overload $1(doc_string, *metadata_keys, metadata={})
110 # @param doc_string [String] The example's doc string.
111 # @param metadata [Hash] Metadata for the example.
112 # @param metadata_keys [Array<Symbol>] Metadata tags for the example.
113 # Will be transformed into hash entries with `true` values.
114 # @overload $1(doc_string, *metadata_keys, metadata={}, &example_implementation)
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 # @param example_implementation [Block] The implementation of the example.
909fd04 @myronmarston Refactor example group macros.
myronmarston authored
120 # @yield [Example] the example object
3951d7c @myronmarston Improve docs.
myronmarston authored
121 # @example
122 # $1 do
123 # end
124 #
125 # $1 "does something" do
126 # end
127 #
2e27245 @myronmarston Fix docs for example/example_group alias methods.
myronmarston authored
128 # $1 "does something", :slow, :uses_js do
129 # end
130 #
3951d7c @myronmarston Improve docs.
myronmarston authored
131 # $1 "does something", :with => 'additional metadata' do
132 # end
133 #
134 # $1 "does something" do |ex|
135 # # ex is the Example object that contains metadata about the example
136 # end
909fd04 @myronmarston Refactor example group macros.
myronmarston authored
137 def self.define_example_method(name, extra_options={})
350fe50 @myronmarston Make example group alias definitions idempotent w/ no warnings.
myronmarston authored
138 idempotently_define_singleton_method(name) do |*all_args, &block|
909fd04 @myronmarston Refactor example group macros.
myronmarston authored
139 desc, *args = *all_args
55d699a @myronmarston Fix `:pending` metadata to always work.
myronmarston authored
140
909fd04 @myronmarston Refactor example group macros.
myronmarston authored
141 options = Metadata.build_hash_from(args)
142 options.update(:skip => RSpec::Core::Pending::NOT_YET_IMPLEMENTED) unless block
143 options.update(extra_options)
144
42f8694 @myronmarston Refactor example creation.
myronmarston authored
145 example = RSpec::Core::Example.new(self, desc, options, block)
146 examples << example
147 example
43ec3a8 @dchelimsky RDoc improvements for shared examples, Example, and Procsy.
dchelimsky authored
148 end
909fd04 @myronmarston Refactor example group macros.
myronmarston authored
149 end
921a744 @dchelimsky more refactoring
dchelimsky authored
150
909fd04 @myronmarston Refactor example group macros.
myronmarston authored
151 # Defines an example within a group.
152 define_example_method :example
153 # Defines an example within a group.
3951d7c @myronmarston Improve docs.
myronmarston authored
154 # This is the primary API to define a code example.
909fd04 @myronmarston Refactor example group macros.
myronmarston authored
155 define_example_method :it
156 # Defines an example within a group.
3951d7c @myronmarston Improve docs.
myronmarston authored
157 # Useful for when your docstring does not read well off of `it`.
158 # @example
159 # RSpec.describe MyClass do
160 # specify "#do_something is deprecated" do
161 # # ...
162 # end
163 # end
909fd04 @myronmarston Refactor example group macros.
myronmarston authored
164 define_example_method :specify
165
5fc29a1 @yous Fix grammer
yous authored
166 # Shortcut to define an example with `:focus => true`.
909fd04 @myronmarston Refactor example group macros.
myronmarston authored
167 # @see example
fbcceb2 @myronmarston Add fspecify and fexample for parity with fit.
myronmarston authored
168 define_example_method :focus, :focus => true
5fc29a1 @yous Fix grammer
yous authored
169 # Shortcut to define an example with `:focus => true`.
909fd04 @myronmarston Refactor example group macros.
myronmarston authored
170 # @see example
fbcceb2 @myronmarston Add fspecify and fexample for parity with fit.
myronmarston authored
171 define_example_method :fexample, :focus => true
5fc29a1 @yous Fix grammer
yous authored
172 # Shortcut to define an example with `:focus => true`.
fbcceb2 @myronmarston Add fspecify and fexample for parity with fit.
myronmarston authored
173 # @see example
174 define_example_method :fit, :focus => true
5fc29a1 @yous Fix grammer
yous authored
175 # Shortcut to define an example with `:focus => true`.
fbcceb2 @myronmarston Add fspecify and fexample for parity with fit.
myronmarston authored
176 # @see example
177 define_example_method :fspecify, :focus => true
5fc29a1 @yous Fix grammer
yous authored
178 # Shortcut to define an example with `:skip => 'Temporarily skipped with xexample'`.
909fd04 @myronmarston Refactor example group macros.
myronmarston authored
179 # @see example
180 define_example_method :xexample, :skip => 'Temporarily skipped with xexample'
5fc29a1 @yous Fix grammer
yous authored
181 # Shortcut to define an example with `:skip => 'Temporarily skipped with xit'`.
909fd04 @myronmarston Refactor example group macros.
myronmarston authored
182 # @see example
183 define_example_method :xit, :skip => 'Temporarily skipped with xit'
5fc29a1 @yous Fix grammer
yous authored
184 # Shortcut to define an example with `:skip => 'Temporarily skipped with xspecify'`.
909fd04 @myronmarston Refactor example group macros.
myronmarston authored
185 # @see example
186 define_example_method :xspecify, :skip => 'Temporarily skipped with xspecify'
3951d7c @myronmarston Improve docs.
myronmarston authored
187 # Shortcut to define an example with `:skip => true`
909fd04 @myronmarston Refactor example group macros.
myronmarston authored
188 # @see example
189 define_example_method :skip, :skip => true
3951d7c @myronmarston Improve docs.
myronmarston authored
190 # Shortcut to define an example with `:pending => true`
909fd04 @myronmarston Refactor example group macros.
myronmarston authored
191 # @see example
192 define_example_method :pending, :pending => true
43ec3a8 @dchelimsky RDoc improvements for shared examples, Example, and Procsy.
dchelimsky authored
193
6ccf70b @myronmarston Provide doc groupings.
myronmarston authored
194 # @!endgroup
195
196 # @!group Defining Example Groups
197
909fd04 @myronmarston Refactor example group macros.
myronmarston authored
198 # @private
2e27245 @myronmarston Fix docs for example/example_group alias methods.
myronmarston authored
199 # @macro [attach] define_example_group_method
3951d7c @myronmarston Improve docs.
myronmarston authored
200 # @!scope class
2e27245 @myronmarston Fix docs for example/example_group alias methods.
myronmarston authored
201 # @overload $1
202 # @overload $1(&example_group_definition)
203 # @param example_group_definition [Block] The definition of the example group.
204 # @overload $1(doc_string, *metadata_keys, metadata={}, &example_implementation)
205 # @param doc_string [String] The group's doc string.
206 # @param metadata [Hash] Metadata for the group.
207 # @param metadata_keys [Array<Symbol>] Metadata tags for the group.
208 # Will be transformed into hash entries with `true` values.
209 # @param example_group_definition [Block] The definition of the example group.
7a72f38 @dchelimsky rdoc
dchelimsky authored
210 #
b8acc5c @myronmarston Refactor example group aliasing.
myronmarston authored
211 # Generates a subclass of this example group which inherits
212 # everything except the examples themselves.
213 #
214 # @example
7a72f38 @dchelimsky rdoc
dchelimsky authored
215 #
b8acc5c @myronmarston Refactor example group aliasing.
myronmarston authored
216 # RSpec.describe "something" do # << This describe method is defined in
217 # # << RSpec::Core::DSL, included in the
218 # # << global namespace (optional)
7a72f38 @dchelimsky rdoc
dchelimsky authored
219 # before do
220 # do_something_before
221 # end
222 #
223 # let(:thing) { Thing.new }
224 #
b8acc5c @myronmarston Refactor example group aliasing.
myronmarston authored
225 # $1 "attribute (of something)" do
7a72f38 @dchelimsky rdoc
dchelimsky authored
226 # # examples in the group get the before hook
227 # # declared above, and can access `thing`
228 # end
229 # end
230 #
231 # @see DSL#describe
b8acc5c @myronmarston Refactor example group aliasing.
myronmarston authored
232 def self.define_example_group_method(name, metadata={})
350fe50 @myronmarston Make example group alias definitions idempotent w/ no warnings.
myronmarston authored
233 idempotently_define_singleton_method(name) do |*args, &example_group_block|
6a18dbd @myronmarston Standardize on rspec-support’s thread local data hash.
myronmarston authored
234 thread_data = RSpec::Support.thread_local_data
a56d9e8 @xaviershay Prevent creating an isolated context when already inside a context.
xaviershay authored
235 top_level = self == ExampleGroup
b8acc5c @myronmarston Refactor example group aliasing.
myronmarston authored
236
a56d9e8 @xaviershay Prevent creating an isolated context when already inside a context.
xaviershay authored
237 if top_level
238 if thread_data[:in_example_group]
d06ffe8 @alex-tan Setup rubocop
alex-tan authored
239 raise "Creating an isolated context from within a context is " \
240 "not allowed. Change `RSpec.#{name}` to `#{name}` or " \
a56d9e8 @xaviershay Prevent creating an isolated context when already inside a context.
xaviershay authored
241 "move this to a top-level scope."
242 end
243
244 thread_data[:in_example_group] = true
245 end
246
247 begin
248
249 description = args.shift
250 combined_metadata = metadata.dup
251 combined_metadata.merge!(args.pop) if args.last.is_a? Hash
252 args << combined_metadata
253
254 subclass(self, description, args, &example_group_block).tap do |child|
255 children << child
256 end
257
258 ensure
259 thread_data.delete(:in_example_group) if top_level
b8acc5c @myronmarston Refactor example group aliasing.
myronmarston authored
260 end
000a5d5 @myronmarston Allow hashes and symbols to be used as an implicit subject.
myronmarston authored
261 end
b8acc5c @myronmarston Refactor example group aliasing.
myronmarston authored
262
263 RSpec::Core::DSL.expose_example_group_alias(name)
4b4ff67 @dchelimsky Refactor example group hierarchy into a tree
dchelimsky authored
264 end
265
b8acc5c @myronmarston Refactor example group aliasing.
myronmarston authored
266 define_example_group_method :example_group
267
0ecabf9 @yous Keep comment line length to 80
yous authored
268 # An alias of `example_group`. Generally used when grouping examples by a
269 # thing you are describing (e.g. an object, class or method).
59590ef @myronmarston Add additional example group aliases.
myronmarston authored
270 # @see example_group
b8acc5c @myronmarston Refactor example group aliasing.
myronmarston authored
271 define_example_group_method :describe
59590ef @myronmarston Add additional example group aliases.
myronmarston authored
272
273 # An alias of `example_group`. Generally used when grouping examples
b8acc5c @myronmarston Refactor example group aliasing.
myronmarston authored
274 # contextually (e.g. "with xyz", "when xyz" or "if xyz").
59590ef @myronmarston Add additional example group aliases.
myronmarston authored
275 # @see example_group
b8acc5c @myronmarston Refactor example group aliasing.
myronmarston authored
276 define_example_group_method :context
17a3b5a @dchelimsky small refactorings
dchelimsky authored
277
e156ec1 @myronmarston Further doc improvements.
myronmarston authored
278 # Shortcut to temporarily make an example group skipped.
59590ef @myronmarston Add additional example group aliases.
myronmarston authored
279 # @see example_group
b8acc5c @myronmarston Refactor example group aliasing.
myronmarston authored
280 define_example_group_method :xdescribe, :skip => "Temporarily skipped with xdescribe"
59590ef @myronmarston Add additional example group aliases.
myronmarston authored
281
e156ec1 @myronmarston Further doc improvements.
myronmarston authored
282 # Shortcut to temporarily make an example group skipped.
59590ef @myronmarston Add additional example group aliases.
myronmarston authored
283 # @see example_group
b8acc5c @myronmarston Refactor example group aliasing.
myronmarston authored
284 define_example_group_method :xcontext, :skip => "Temporarily skipped with xcontext"
59590ef @myronmarston Add additional example group aliases.
myronmarston authored
285
6ccf70b @myronmarston Provide doc groupings.
myronmarston authored
286 # Shortcut to define an example group with `:focus => true`.
59590ef @myronmarston Add additional example group aliases.
myronmarston authored
287 # @see example_group
2d1004f @myronmarston Remove `:focused` metadata.
myronmarston authored
288 define_example_group_method :fdescribe, :focus => true
59590ef @myronmarston Add additional example group aliases.
myronmarston authored
289
6ccf70b @myronmarston Provide doc groupings.
myronmarston authored
290 # Shortcut to define an example group with `:focus => true`.
59590ef @myronmarston Add additional example group aliases.
myronmarston authored
291 # @see example_group
2d1004f @myronmarston Remove `:focused` metadata.
myronmarston authored
292 define_example_group_method :fcontext, :focus => true
59590ef @myronmarston Add additional example group aliases.
myronmarston authored
293
6ccf70b @myronmarston Provide doc groupings.
myronmarston authored
294 # @!endgroup
295
296 # @!group Including Shared Example Groups
297
feb5e85 @dchelimsky rdoc - use yard's @private tag to hide a lot of noise. More to go, bu…
dchelimsky authored
298 # @private
e41ae45 @myronmarston Organize ExampleGroup methods into a logical order.
myronmarston authored
299 # @macro [attach] define_nested_shared_group_method
300 # @!scope class
301 #
9653904 @myronmarston Revert "Reify shared example groups as a first-class type."
myronmarston authored
302 # @see SharedExampleGroup
e41ae45 @myronmarston Organize ExampleGroup methods into a logical order.
myronmarston authored
303 def self.define_nested_shared_group_method(new_name, report_label="it should behave like")
350fe50 @myronmarston Make example group alias definitions idempotent w/ no warnings.
myronmarston authored
304 idempotently_define_singleton_method(new_name) do |name, *args, &customization_block|
5fc29a1 @yous Fix grammer
yous authored
305 # Pass :caller so the :location metadata is set properly.
306 # Otherwise, it'll be set to the next line because that's
e41ae45 @myronmarston Organize ExampleGroup methods into a logical order.
myronmarston authored
307 # the block's source_location.
fdd33ef @myronmarston Add shared group inclusion backtrace to example metadata.
myronmarston authored
308 group = example_group("#{report_label} #{name}", :caller => (the_caller = caller)) do
309 find_and_eval_shared("examples", name, the_caller.first, *args, &customization_block)
e41ae45 @myronmarston Organize ExampleGroup methods into a logical order.
myronmarston authored
310 end
311 group.metadata[:shared_group_name] = name
312 group
313 end
314 end
315
316 # Generates a nested example group and includes the shared content
317 # mapped to `name` in the nested group.
318 define_nested_shared_group_method :it_behaves_like, "behaves like"
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_should_behave_like
322
323 # Includes shared content mapped to `name` directly in the group in which
324 # it is declared, as opposed to `it_behaves_like`, which creates a nested
0ecabf9 @yous Keep comment line length to 80
yous authored
325 # group. If given a block, that block is also eval'd in the current
326 # context.
e41ae45 @myronmarston Organize ExampleGroup methods into a logical order.
myronmarston authored
327 #
9653904 @myronmarston Revert "Reify shared example groups as a first-class type."
myronmarston authored
328 # @see SharedExampleGroup
e41ae45 @myronmarston Organize ExampleGroup methods into a logical order.
myronmarston authored
329 def self.include_context(name, *args, &block)
fdd33ef @myronmarston Add shared group inclusion backtrace to example metadata.
myronmarston authored
330 find_and_eval_shared("context", name, caller.first, *args, &block)
e41ae45 @myronmarston Organize ExampleGroup methods into a logical order.
myronmarston authored
331 end
332
333 # Includes shared content mapped to `name` directly in the group in which
334 # it is declared, as opposed to `it_behaves_like`, which creates a nested
0ecabf9 @yous Keep comment line length to 80
yous authored
335 # group. If given a block, that block is also eval'd in the current
336 # context.
e41ae45 @myronmarston Organize ExampleGroup methods into a logical order.
myronmarston authored
337 #
9653904 @myronmarston Revert "Reify shared example groups as a first-class type."
myronmarston authored
338 # @see SharedExampleGroup
e41ae45 @myronmarston Organize ExampleGroup methods into a logical order.
myronmarston authored
339 def self.include_examples(name, *args, &block)
fdd33ef @myronmarston Add shared group inclusion backtrace to example metadata.
myronmarston authored
340 find_and_eval_shared("examples", name, caller.first, *args, &block)
e41ae45 @myronmarston Organize ExampleGroup methods into a logical order.
myronmarston authored
341 end
342
343 # @private
fdd33ef @myronmarston Add shared group inclusion backtrace to example metadata.
myronmarston authored
344 def self.find_and_eval_shared(label, name, inclusion_location, *args, &customization_block)
d06ffe8 @alex-tan Setup rubocop
alex-tan authored
345 shared_block = RSpec.world.shared_example_group_registry.find(parent_groups, name)
346
347 unless shared_block
e41ae45 @myronmarston Organize ExampleGroup methods into a logical order.
myronmarston authored
348 raise ArgumentError, "Could not find shared #{label} #{name.inspect}"
349 end
350
a1a3dc4 @myronmarston Improve perf of metadata-based shared group inclusion.
myronmarston authored
351 SharedExampleGroupInclusionStackFrame.with_frame(name, Metadata.relative_path(inclusion_location)) do
fdd33ef @myronmarston Add shared group inclusion backtrace to example metadata.
myronmarston authored
352 module_exec(*args, &shared_block)
353 module_exec(&customization_block) if customization_block
354 end
e41ae45 @myronmarston Organize ExampleGroup methods into a logical order.
myronmarston authored
355 end
356
6ccf70b @myronmarston Provide doc groupings.
myronmarston authored
357 # @!endgroup
358
e41ae45 @myronmarston Organize ExampleGroup methods into a logical order.
myronmarston authored
359 # @private
b8acc5c @myronmarston Refactor example group aliasing.
myronmarston authored
360 def self.subclass(parent, description, args, &example_group_block)
8363707 @dchelimsky Add specs to show after(:each) is run
dchelimsky authored
361 subclass = Class.new(parent)
b8acc5c @myronmarston Refactor example group aliasing.
myronmarston authored
362 subclass.set_it_up(description, *args, &example_group_block)
8d89dbe @myronmarston Prefer *_exec over *_eval.
myronmarston authored
363 subclass.module_exec(&example_group_block) if example_group_block
a43d59d @myronmarston Delay inclusion of `LetDefinitions` module.
myronmarston authored
364
365 # The LetDefinitions module must be included _after_ other modules
e795f1a @cupakromer Minor typo and trailing whitespace fix.
cupakromer authored
366 # to ensure that it takes precedence when there are name collisions.
a43d59d @myronmarston Delay inclusion of `LetDefinitions` module.
myronmarston authored
367 # Thus, we delay including it until after the example group block
368 # has been eval'd.
690a294 @alindeman Small refactor to add intention revealing message
alindeman authored
369 MemoizedHelpers.define_helpers_on(subclass)
a43d59d @myronmarston Delay inclusion of `LetDefinitions` module.
myronmarston authored
370
8363707 @dchelimsky Add specs to show after(:each) is run
dchelimsky authored
371 subclass
afca728 @spicycode Initial migration of Micronaut to Spec/Core
spicycode authored
372 end
373
feb5e85 @dchelimsky rdoc - use yard's @private tag to hide a lot of noise. More to go, bu…
dchelimsky authored
374 # @private
f251894 @myronmarston Remove unnecessary shift/unshift.
myronmarston authored
375 def self.set_it_up(description, *args, &example_group_block)
e41ae45 @myronmarston Organize ExampleGroup methods into a logical order.
myronmarston authored
376 # Ruby 1.9 has a bug that can lead to infinite recursion and a
377 # SystemStackError if you include a module in a superclass after
378 # including it in a subclass: https://gist.github.com/845896
0ecabf9 @yous Keep comment line length to 80
yous authored
379 # To prevent this, we must include any modules in
380 # RSpec::Core::ExampleGroup before users create example groups and have
381 # a chance to include the same module in a subclass of
382 # RSpec::Core::ExampleGroup. So we need to configure example groups
383 # here.
e41ae45 @myronmarston Organize ExampleGroup methods into a logical order.
myronmarston authored
384 ensure_example_groups_are_configured
385
386 user_metadata = Metadata.build_hash_from(args)
387
388 @metadata = Metadata::ExampleGroupHash.create(
057e729 @myronmarston Add ids to examples and groups.
myronmarston authored
389 superclass_metadata, user_metadata,
390 superclass.method(:next_runnable_index_for),
391 description, *args, &example_group_block
e41ae45 @myronmarston Organize ExampleGroup methods into a logical order.
myronmarston authored
392 )
5dc5088 @myronmarston Assign example group constant earlier.
myronmarston authored
393 ExampleGroups.assign_const(self)
e41ae45 @myronmarston Organize ExampleGroup methods into a logical order.
myronmarston authored
394
395 hooks.register_globals(self, RSpec.configuration.hooks)
1160685 @myronmarston Remove unneeded layer of indirection.
myronmarston authored
396 RSpec.configuration.configure_group(self)
e41ae45 @myronmarston Organize ExampleGroup methods into a logical order.
myronmarston authored
397 end
398
399 # @private
400 def self.examples
401 @examples ||= []
402 end
403
404 # @private
405 def self.filtered_examples
406 RSpec.world.filtered_examples[self]
407 end
408
409 # @private
410 def self.descendant_filtered_examples
e3cd4b7 @yous Reduce line length to 130
yous authored
411 @descendant_filtered_examples ||= filtered_examples +
15de144 @myronmarston Prefer `flat_map` to `inject`.
myronmarston authored
412 FlatMap.flat_map(children, &:descendant_filtered_examples)
e41ae45 @myronmarston Organize ExampleGroup methods into a logical order.
myronmarston authored
413 end
414
415 # @private
b84371e @dchelimsky Move filtering examples to world, reducing feature envy
dchelimsky authored
416 def self.children
a755aa6 @alindeman Example groups can override the default ordering.
alindeman authored
417 @children ||= []
b84371e @dchelimsky Move filtering examples to world, reducing feature envy
dchelimsky authored
418 end
419
feb5e85 @dchelimsky rdoc - use yard's @private tag to hide a lot of noise. More to go, bu…
dchelimsky authored
420 # @private
057e729 @myronmarston Add ids to examples and groups.
myronmarston authored
421 def self.next_runnable_index_for(file)
422 if self == ExampleGroup
423 RSpec.world.num_example_groups_defined_in(file)
424 else
425 children.count + examples.count
426 end + 1
427 end
428
429 # @private
fa42f5b @dchelimsky it's descendant, silly
dchelimsky authored
430 def self.descendants
15de144 @myronmarston Prefer `flat_map` to `inject`.
myronmarston authored
431 @_descendants ||= [self] + FlatMap.flat_map(children, &:descendants)
b84371e @dchelimsky Move filtering examples to world, reducing feature envy
dchelimsky authored
432 end
433
9e8b6b9 @myronmarston Don't override #ancestors.
myronmarston authored
434 ## @private
435 def self.parent_groups
d06ffe8 @alex-tan Setup rubocop
alex-tan authored
436 @parent_groups ||= ancestors.select { |a| a < RSpec::Core::ExampleGroup }
ff4df6b @dchelimsky select from Ruby's ancestors instead of building up our own
dchelimsky authored
437 end
438
feb5e85 @dchelimsky rdoc - use yard's @private tag to hide a lot of noise. More to go, bu…
dchelimsky authored
439 # @private
bc11555 @myronmarston Fix group profile output regressions introduced in #1971.
myronmarston authored
440 def self.top_level?
441 superclass == ExampleGroup
442 end
443
444 # @private
622a4b7 @myronmarston Fix how RSpec::Matchers is included in RSpec::Core::Example group to …
myronmarston authored
445 def self.ensure_example_groups_are_configured
2b2ef40 @dchelimsky Change class level instance var to class's class var so the block is
dchelimsky authored
446 unless defined?(@@example_groups_configured)
622a4b7 @myronmarston Fix how RSpec::Matchers is included in RSpec::Core::Example group to …
myronmarston authored
447 RSpec.configuration.configure_mock_framework
448 RSpec.configuration.configure_expectation_framework
d06ffe8 @alex-tan Setup rubocop
alex-tan authored
449 # rubocop:disable Style/ClassVars
2b2ef40 @dchelimsky Change class level instance var to class's class var so the block is
dchelimsky authored
450 @@example_groups_configured = true
d06ffe8 @alex-tan Setup rubocop
alex-tan authored
451 # rubocop:enable Style/ClassVars
622a4b7 @myronmarston Fix how RSpec::Matchers is included in RSpec::Core::Example group to …
myronmarston authored
452 end
453 end
454
feb5e85 @dchelimsky rdoc - use yard's @private tag to hide a lot of noise. More to go, bu…
dchelimsky authored
455 # @private
b123c6a @myronmarston Make `:example` and `:context` scopes primary.
myronmarston authored
456 def self.before_context_ivars
457 @before_context_ivars ||= {}
afca728 @spicycode Initial migration of Micronaut to Spec/Core
spicycode authored
458 end
459
feb5e85 @dchelimsky rdoc - use yard's @private tag to hide a lot of noise. More to go, bu…
dchelimsky authored
460 # @private
b123c6a @myronmarston Make `:example` and `:context` scopes primary.
myronmarston authored
461 def self.store_before_context_ivars(example_group_instance)
c1356c7 @myronmarston Fewer array allocations.
myronmarston authored
462 each_instance_variable_for_example(example_group_instance) do |ivar|
b123c6a @myronmarston Make `:example` and `:context` scopes primary.
myronmarston authored
463 before_context_ivars[ivar] = example_group_instance.instance_variable_get(ivar)
d06ffe8 @alex-tan Setup rubocop
alex-tan authored
464 end
afca728 @spicycode Initial migration of Micronaut to Spec/Core
spicycode authored
465 end
e9f9556 @spicycode Initial metadata reorg, still needs cleanup
spicycode authored
466
feb5e85 @dchelimsky rdoc - use yard's @private tag to hide a lot of noise. More to go, bu…
dchelimsky authored
467 # @private
b123c6a @myronmarston Make `:example` and `:context` scopes primary.
myronmarston authored
468 def self.run_before_context_hooks(example_group_instance)
639db76 @myronmarston Run `:context` hooks from shared contexts that apply to one example.
myronmarston authored
469 set_ivars(example_group_instance, superclass_before_context_ivars)
108649a @myronmarston Include caller in warning msg for `let` usage in `before(:all)`.
myronmarston authored
470
ffe00a1 @JoshCheek Make memoized helpers threadsafe
JoshCheek authored
471 ContextHookMemoized::Before.isolate_for_context_hook(example_group_instance) do
b847426 @myronmarston Refactor how context hooks get run.
myronmarston authored
472 hooks.run(:before, :context, example_group_instance)
49370db @samphippen Ensure before(:all) state is always propagated to after(:all)
samphippen authored
473 end
b847426 @myronmarston Refactor how context hooks get run.
myronmarston authored
474 ensure
475 store_before_context_ivars(example_group_instance)
afca728 @spicycode Initial migration of Micronaut to Spec/Core
spicycode authored
476 end
477
639db76 @myronmarston Run `:context` hooks from shared contexts that apply to one example.
myronmarston authored
478 if RUBY_VERSION.to_f >= 1.9
479 # @private
480 def self.superclass_before_context_ivars
481 superclass.before_context_ivars
482 end
483 else # 1.8.7
76e6976 @myronmarston Exclude version/platform-specific code from simplecov.
myronmarston authored
484 # :nocov:
639db76 @myronmarston Run `:context` hooks from shared contexts that apply to one example.
myronmarston authored
485 # @private
486 def self.superclass_before_context_ivars
487 if superclass.respond_to?(:before_context_ivars)
488 superclass.before_context_ivars
489 else
490 # `self` must be the singleton class of an ExampleGroup instance.
491 # On 1.8.7, the superclass of a singleton class of an instance of A
492 # is A's singleton class. On 1.9+, it's A. On 1.8.7, the first ancestor
493 # is A, so we can mirror 1.8.7's behavior here. Note that we have to
494 # search for the first that responds to `before_context_ivars`
495 # in case a module has been included in the singleton class.
496 ancestors.find { |a| a.respond_to?(:before_context_ivars) }.before_context_ivars
497 end
498 end
76e6976 @myronmarston Exclude version/platform-specific code from simplecov.
myronmarston authored
499 # :nocov:
639db76 @myronmarston Run `:context` hooks from shared contexts that apply to one example.
myronmarston authored
500 end
501
84cb5f2 @dchelimsky rdoc
dchelimsky authored
502 # @private
b123c6a @myronmarston Make `:example` and `:context` scopes primary.
myronmarston authored
503 def self.run_after_context_hooks(example_group_instance)
504 set_ivars(example_group_instance, before_context_ivars)
9e7dcd3 @myronmarston Rescue errors in after(:all) and print them out.
myronmarston authored
505
ffe00a1 @JoshCheek Make memoized helpers threadsafe
JoshCheek authored
506 ContextHookMemoized::After.isolate_for_context_hook(example_group_instance) do
b123c6a @myronmarston Make `:example` and `:context` scopes primary.
myronmarston authored
507 hooks.run(:after, :context, example_group_instance)
f5930e7 @myronmarston Error rather than warn when `let` accessed in :all hook.
myronmarston authored
508 end
b847426 @myronmarston Refactor how context hooks get run.
myronmarston authored
509 ensure
510 before_context_ivars.clear
21d6f6b @dchelimsky make sure before/after(:all) gets run even in subclasses
dchelimsky authored
511 end
512
5fc29a1 @yous Fix grammer
yous authored
513 # Runs all the examples in this group.
2633182 @JonRowe switch NullReporter to not be an instance
JonRowe authored
514 def self.run(reporter=RSpec::Core::NullReporter)
e747c7f @myronmarston Don't purge example groups when a `--fail-fast` failure is hit.
myronmarston authored
515 return if RSpec.world.wants_to_quit
f80e68a @dchelimsky Deprecate add_example_group in formatters
dchelimsky authored
516 reporter.example_group_started(self)
b25fea3 @spicycode gh#21 Resolution, 1 remaining pending test
spicycode authored
517
b847426 @myronmarston Refactor how context hooks get run.
myronmarston authored
518 should_run_context_hooks = descendant_filtered_examples.any?
20389a4 @dchelimsky ensure the things that happen after the return val is set
dchelimsky authored
519 begin
b847426 @myronmarston Refactor how context hooks get run.
myronmarston authored
520 run_before_context_hooks(new('before(:context) hook')) if should_run_context_hooks
1012613 @dchelimsky object per example
dchelimsky authored
521 result_for_this_group = run_examples(reporter)
10aca90 @myronmarston Simplify ordering API.
myronmarston authored
522 results_for_descendants = ordering_strategy.order(children).map { |child| child.run(reporter) }.all?
d6964f7 @dchelimsky Ensure that child groups are run even when there are failures in parent
dchelimsky authored
523 result_for_this_group && results_for_descendants
5c21c76 @xaviershay Remove support for pending in before(:all) hooks.
xaviershay authored
524 rescue Pending::SkipDeclaredInExample => ex
d06ffe8 @alex-tan Setup rubocop
alex-tan authored
525 for_filtered_examples(reporter) { |example| example.skip_with_exception(reporter, ex) }
8e69df1 @myronmarston Groups with `before(:all) { skip }` should pass.
myronmarston authored
526 true
b25fea3 @spicycode gh#21 Resolution, 1 remaining pending test
spicycode authored
527 rescue Exception => ex
0b42695 @xaviershay Move private methods from RSpec to RSpec.world.
xaviershay authored
528 RSpec.world.wants_to_quit = true if fail_fast?
d06ffe8 @alex-tan Setup rubocop
alex-tan authored
529 for_filtered_examples(reporter) { |example| example.fail_with_exception(reporter, ex) }
795c22d @myronmarston Explicitly indicate that the example group failed.
myronmarston authored
530 false
20389a4 @dchelimsky ensure the things that happen after the return val is set
dchelimsky authored
531 ensure
b847426 @myronmarston Refactor how context hooks get run.
myronmarston authored
532 run_after_context_hooks(new('after(:context) hook')) if should_run_context_hooks
4dc8bfb @iromeo Add example_group_finished message to reporter/formatters.
iromeo authored
533 reporter.example_group_finished(self)
20389a4 @dchelimsky ensure the things that happen after the return val is set
dchelimsky authored
534 end
afca728 @spicycode Initial migration of Micronaut to Spec/Core
spicycode authored
535 end
e9f9556 @spicycode Initial metadata reorg, still needs cleanup
spicycode authored
536
a755aa6 @alindeman Example groups can override the default ordering.
alindeman authored
537 # @private
10aca90 @myronmarston Simplify ordering API.
myronmarston authored
538 def self.ordering_strategy
9b16f3e @myronmarston Refactoring: use `:global` for global ordering.
myronmarston authored
539 order = metadata.fetch(:order, :global)
10aca90 @myronmarston Simplify ordering API.
myronmarston authored
540 registry = RSpec.configuration.ordering_registry
2f1d906 @myronmarston Print a warning when given an unrecognized :order option.
myronmarston authored
541
542 registry.fetch(order) do
543 warn <<-WARNING.gsub(/^ +\|/, '')
544 |WARNING: Ignoring unknown ordering specified using `:order => #{order.inspect}` metadata.
545 | Falling back to configured global ordering.
7a01061 @myronmarston Leverage metadata delegation a bit more.
myronmarston authored
546 | Unrecognized ordering specified at: #{location}
2f1d906 @myronmarston Print a warning when given an unrecognized :order option.
myronmarston authored
547 WARNING
548
9b16f3e @myronmarston Refactoring: use `:global` for global ordering.
myronmarston authored
549 registry.fetch(:global)
2f1d906 @myronmarston Print a warning when given an unrecognized :order option.
myronmarston authored
550 end
551 end
552
553 # @private
7a72f38 @dchelimsky rdoc
dchelimsky authored
554 def self.run_examples(reporter)
10aca90 @myronmarston Simplify ordering API.
myronmarston authored
555 ordering_strategy.order(filtered_examples).map do |example|
0b42695 @xaviershay Move private methods from RSpec to RSpec.world.
xaviershay authored
556 next if RSpec.world.wants_to_quit
ffd7492 @kcdragon Add better `inspect` output for ExampleGroup
kcdragon authored
557 instance = new(example.inspect_output)
b123c6a @myronmarston Make `:example` and `:context` scopes primary.
myronmarston authored
558 set_ivars(instance, before_context_ivars)
7a72f38 @dchelimsky rdoc
dchelimsky authored
559 succeeded = example.run(instance, reporter)
0b42695 @xaviershay Move private methods from RSpec to RSpec.world.
xaviershay authored
560 RSpec.world.wants_to_quit = true if fail_fast? && !succeeded
7a72f38 @dchelimsky rdoc
dchelimsky authored
561 succeeded
562 end.all?
563 end
564
84cb5f2 @dchelimsky rdoc
dchelimsky authored
565 # @private
5c21c76 @xaviershay Remove support for pending in before(:all) hooks.
xaviershay authored
566 def self.for_filtered_examples(reporter, &block)
567 filtered_examples.each(&block)
135009c @myronmarston Fix before(:all) error handling so that it fails examples in nested g…
myronmarston authored
568
569 children.each do |child|
570 reporter.example_group_started(child)
5c21c76 @xaviershay Remove support for pending in before(:all) hooks.
xaviershay authored
571 child.for_filtered_examples(reporter, &block)
135009c @myronmarston Fix before(:all) error handling so that it fails examples in nested g…
myronmarston authored
572 reporter.example_group_finished(child)
573 end
79273a7 @dnurzynski Fix exit_status after Exception raised in before :all hook
dnurzynski authored
574 false
b25fea3 @spicycode gh#21 Resolution, 1 remaining pending test
spicycode authored
575 end
576
84cb5f2 @dchelimsky rdoc
dchelimsky authored
577 # @private
3d8eebf @dchelimsky Move decision about failing fast from example to group
dchelimsky authored
578 def self.fail_fast?
579 RSpec.configuration.fail_fast?
580 end
581
84cb5f2 @dchelimsky rdoc
dchelimsky authored
582 # @private
40d471b @dchelimsky refactor some names, abstactions, scopes, etc
dchelimsky authored
583 def self.declaration_line_numbers
f3ec09f @myronmarston Change nesting structure of example group metadata.
myronmarston authored
584 @declaration_line_numbers ||= [metadata[:line_number]] +
d06ffe8 @alex-tan Setup rubocop
alex-tan authored
585 examples.map { |e| e.metadata[:line_number] } +
15de144 @myronmarston Prefer `flat_map` to `inject`.
myronmarston authored
586 FlatMap.flat_map(children, &:declaration_line_numbers)
40d471b @dchelimsky refactor some names, abstactions, scopes, etc
dchelimsky authored
587 end
588
057e729 @myronmarston Add ids to examples and groups.
myronmarston authored
589 # @return [String] the unique id of this example group. Pass
590 # this at the command line to re-run this exact example group.
591 def self.id
592 Metadata.id_from(metadata)
593 end
594
feb5e85 @dchelimsky rdoc - use yard's @private tag to hide a lot of noise. More to go, bu…
dchelimsky authored
595 # @private
9415f86 @dchelimsky add group.top_level_description
dchelimsky authored
596 def self.top_level_description
9e8b6b9 @myronmarston Don't override #ancestors.
myronmarston authored
597 parent_groups.last.description
9415f86 @dchelimsky add group.top_level_description
dchelimsky authored
598 end
599
feb5e85 @dchelimsky rdoc - use yard's @private tag to hide a lot of noise. More to go, bu…
dchelimsky authored
600 # @private
6730505 @dchelimsky remove __reset__ from ExampleGroup instance namespace
dchelimsky authored
601 def self.set_ivars(instance, ivars)
d06ffe8 @alex-tan Setup rubocop
alex-tan authored
602 ivars.each { |name, value| instance.instance_variable_set(name, value) }
6730505 @dchelimsky remove __reset__ from ExampleGroup instance namespace
dchelimsky authored
603 end
604
ffd7492 @kcdragon Add better `inspect` output for ExampleGroup
kcdragon authored
605 if RUBY_VERSION.to_f < 1.9
76e6976 @myronmarston Exclude version/platform-specific code from simplecov.
myronmarston authored
606 # :nocov:
1d5020b @benmoss Add missing private doc markers
benmoss authored
607 # @private
c1356c7 @myronmarston Fewer array allocations.
myronmarston authored
608 INSTANCE_VARIABLE_TO_IGNORE = '@__inspect_output'.freeze
76e6976 @myronmarston Exclude version/platform-specific code from simplecov.
myronmarston authored
609 # :nocov:
ffd7492 @kcdragon Add better `inspect` output for ExampleGroup
kcdragon authored
610 else
1d5020b @benmoss Add missing private doc markers
benmoss authored
611 # @private
c1356c7 @myronmarston Fewer array allocations.
myronmarston authored
612 INSTANCE_VARIABLE_TO_IGNORE = :@__inspect_output
613 end
614
615 # @private
616 def self.each_instance_variable_for_example(group)
617 group.instance_variables.each do |ivar|
618 yield ivar unless ivar == INSTANCE_VARIABLE_TO_IGNORE
ffd7492 @kcdragon Add better `inspect` output for ExampleGroup
kcdragon authored
619 end
620 end
621
622 def initialize(inspect_output=nil)
623 @__inspect_output = inspect_output || '(no description provided)'
ffe00a1 @JoshCheek Make memoized helpers threadsafe
JoshCheek authored
624 super() # no args get passed
ffd7492 @kcdragon Add better `inspect` output for ExampleGroup
kcdragon authored
625 end
626
627 # @private
628 def inspect
629 "#<#{self.class} #{@__inspect_output}>"
630 end
13c6674 @myronmarston Provide friendly errors when users call RSpec APIs from the wrong con…
myronmarston authored
631
ab2b613 @myronmarston Got things to work on 1.8.7.
myronmarston authored
632 unless method_defined?(:singleton_class) # for 1.8.7
76e6976 @myronmarston Exclude version/platform-specific code from simplecov.
myronmarston authored
633 # :nocov:
ab2b613 @myronmarston Got things to work on 1.8.7.
myronmarston authored
634 # @private
635 def singleton_class
636 class << self; self; end
637 end
76e6976 @myronmarston Exclude version/platform-specific code from simplecov.
myronmarston authored
638 # :nocov:
ab2b613 @myronmarston Got things to work on 1.8.7.
myronmarston authored
639 end
640
13c6674 @myronmarston Provide friendly errors when users call RSpec APIs from the wrong con…
myronmarston authored
641 # Raised when an RSpec API is called in the wrong scope, such as `before`
642 # being called from within an example rather than from within an example
643 # group block.
644 WrongScopeError = Class.new(NoMethodError)
645
646 def self.method_missing(name, *args)
647 if method_defined?(name)
648 raise WrongScopeError,
649 "`#{name}` is not available on an example group (e.g. a " \
650 "`describe` or `context` block). It is only available from " \
651 "within individual examples (e.g. `it` blocks) or from " \
652 "constructs that run in the scope of an example (e.g. " \
653 "`before`, `let`, etc)."
654 end
655
656 super
657 end
658 private_class_method :method_missing
659
660 private
661
662 def method_missing(name, *args)
663 if self.class.respond_to?(name)
664 raise WrongScopeError,
665 "`#{name}` is not available from within an example (e.g. an " \
666 "`it` block) or from constructs that run in the scope of an " \
667 "example (e.g. `before`, `let`, etc). It is only available " \
668 "on an example group (e.g. a `describe` or `context` block)."
669 end
670
671 super
672 end
ab88b2e @myronmarston Clean up `instance_exec_with_rescue`.
myronmarston authored
673 end
6ddb29d @spicycode Lets make ivars not so leaky between examples (WIP)
spicycode authored
674
ab88b2e @myronmarston Clean up `instance_exec_with_rescue`.
myronmarston authored
675 # @private
676 # Unnamed example group used by `SuiteHookContext`.
677 class AnonymousExampleGroup < ExampleGroup
678 def self.metadata
679 {}
e516329 @dchelimsky resolve minor feature envy
dchelimsky authored
680 end
afca728 @spicycode Initial migration of Micronaut to Spec/Core
spicycode authored
681 end
fdd33ef @myronmarston Add shared group inclusion backtrace to example metadata.
myronmarston authored
682
683 # Contains information about the inclusion site of a shared example group.
a0f02d0 @myronmarston Improve shared group backtrace in failure output.
myronmarston authored
684 class SharedExampleGroupInclusionStackFrame
685 # @return [String] the name of the shared example group
686 attr_reader :shared_group_name
687 # @return [String] the location where the shared example was included
688 attr_reader :inclusion_location
689
690 def initialize(shared_group_name, inclusion_location)
691 @shared_group_name = shared_group_name
692 @inclusion_location = inclusion_location
693 end
694
695 # @return [String] The {#inclusion_location}, formatted for display by a formatter.
696 def formatted_inclusion_location
697 @formatted_inclusion_location ||= begin
698 RSpec.configuration.backtrace_formatter.backtrace_line(
699 inclusion_location.sub(/(:\d+):in .+$/, '\1')
700 )
701 end
702 end
703
704 # @return [String] Description of this stack frame, in the form used by
705 # RSpec's built-in formatters.
706 def description
707 @description ||= "Shared Example Group: #{shared_group_name.inspect} " \
708 "called from #{formatted_inclusion_location}"
709 end
710
fdd33ef @myronmarston Add shared group inclusion backtrace to example metadata.
myronmarston authored
711 # @private
712 def self.current_backtrace
6a18dbd @myronmarston Standardize on rspec-support’s thread local data hash.
myronmarston authored
713 shared_example_group_inclusions.reverse
fdd33ef @myronmarston Add shared group inclusion backtrace to example metadata.
myronmarston authored
714 end
715
716 # @private
717 def self.with_frame(name, location)
6a18dbd @myronmarston Standardize on rspec-support’s thread local data hash.
myronmarston authored
718 current_stack = shared_example_group_inclusions
fdd33ef @myronmarston Add shared group inclusion backtrace to example metadata.
myronmarston authored
719 current_stack << new(name, location)
720 yield
721 ensure
722 current_stack.pop
723 end
6a18dbd @myronmarston Standardize on rspec-support’s thread local data hash.
myronmarston authored
724
725 # @private
726 def self.shared_example_group_inclusions
727 RSpec::Support.thread_local_data[:shared_example_group_inclusions] ||= []
728 end
fdd33ef @myronmarston Add shared group inclusion backtrace to example metadata.
myronmarston authored
729 end
afca728 @spicycode Initial migration of Micronaut to Spec/Core
spicycode authored
730 end
4dd5ff5 @myronmarston Give example group classes a friendly const name.
myronmarston authored
731
526ed4e @yelled3 Achieve 100% doc coverage
yelled3 authored
732 # @private
733 #
0ecabf9 @yous Keep comment line length to 80
yous authored
734 # Namespace for the example group subclasses generated by top-level
735 # `describe`.
3923c7e @myronmarston Rename UserGroups to ExampleGroups.
myronmarston authored
736 module ExampleGroups
2014378 @jimmycuadra Prevent example groups named "Config" from generating a deprecation w…
jimmycuadra authored
737 extend Support::RecursiveConstMethods
738
4dd5ff5 @myronmarston Give example group classes a friendly const name.
myronmarston authored
739 def self.assign_const(group)
740 base_name = base_name_for(group)
741 const_scope = constant_scope_for(group)
742 name = disambiguate(base_name, const_scope)
743
744 const_scope.const_set(name, group)
745 end
746
747 def self.constant_scope_for(group)
748 const_scope = group.superclass
380c1bd Prevent load-order issue in constant_scope_for with more explicit use of
Daniela Wellisz authored
749 const_scope = self if const_scope == ::RSpec::Core::ExampleGroup
4dd5ff5 @myronmarston Give example group classes a friendly const name.
myronmarston authored
750 const_scope
751 end
752
753 def self.base_name_for(group)
754 return "Anonymous" if group.description.empty?
755
5fc29a1 @yous Fix grammer
yous authored
756 # Convert to CamelCase.
70bc97d @myronmarston Use fewer string allocations when creating the example group constant.
myronmarston authored
757 name = ' ' << group.description
758 name.gsub!(/[^0-9a-zA-Z]+([0-9a-zA-Z])/) do
d7f5e3e @durran Allow Regexp class to be described
durran authored
759 match = ::Regexp.last_match[1]
70bc97d @myronmarston Use fewer string allocations when creating the example group constant.
myronmarston authored
760 match.upcase!
761 match
762 end
4dd5ff5 @myronmarston Give example group classes a friendly const name.
myronmarston authored
763
f61bb6f @JonRowe whitespace cleanup
JonRowe authored
764 name.lstrip! # Remove leading whitespace
70bc97d @myronmarston Use fewer string allocations when creating the example group constant.
myronmarston authored
765 name.gsub!(/\W/, ''.freeze) # JRuby, RBX and others don't like non-ascii in const names
4dd5ff5 @myronmarston Give example group classes a friendly const name.
myronmarston authored
766
767 # Ruby requires first const letter to be A-Z. Use `Nested`
768 # as necessary to enforce that.
70bc97d @myronmarston Use fewer string allocations when creating the example group constant.
myronmarston authored
769 name.gsub!(/\A([^A-Z]|\z)/, 'Nested\1'.freeze)
4dd5ff5 @myronmarston Give example group classes a friendly const name.
myronmarston authored
770
771 name
772 end
773
a0acf2e @JonRowe deal with 1.9.2 issue by appending a _ on all constant names
JonRowe authored
774 if RUBY_VERSION == '1.9.2'
76e6976 @myronmarston Exclude version/platform-specific code from simplecov.
myronmarston authored
775 # :nocov:
a0acf2e @JonRowe deal with 1.9.2 issue by appending a _ on all constant names
JonRowe authored
776 class << self
777 alias _base_name_for base_name_for
778 def base_name_for(group)
779 _base_name_for(group) + '_'
780 end
781 end
782 private_class_method :_base_name_for
76e6976 @myronmarston Exclude version/platform-specific code from simplecov.
myronmarston authored
783 # :nocov:
a0acf2e @JonRowe deal with 1.9.2 issue by appending a _ on all constant names
JonRowe authored
784 end
785
4dd5ff5 @myronmarston Give example group classes a friendly const name.
myronmarston authored
786 def self.disambiguate(name, const_scope)
2014378 @jimmycuadra Prevent example groups named "Config" from generating a deprecation w…
jimmycuadra authored
787 return name unless const_defined_on?(const_scope, name)
4dd5ff5 @myronmarston Give example group classes a friendly const name.
myronmarston authored
788
0ecabf9 @yous Keep comment line length to 80
yous authored
789 # Add a trailing number if needed to disambiguate from an existing
790 # constant.
4dd5ff5 @myronmarston Give example group classes a friendly const name.
myronmarston authored
791 name << "_2"
2014378 @jimmycuadra Prevent example groups named "Config" from generating a deprecation w…
jimmycuadra authored
792 name.next! while const_defined_on?(const_scope, name)
4dd5ff5 @myronmarston Give example group classes a friendly const name.
myronmarston authored
793 name
794 end
795 end
98f4077 @spicycode Initial shared behaviour work.
spicycode authored
796 end
Something went wrong with that request. Please try again.