rspec-core 2.10.1 → 2.11.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/Changelog.md +35 -2
- data/README.md +14 -13
- data/features/command_line/example_name_option.feature +15 -0
- data/features/helper_methods/modules.feature +3 -3
- data/lib/rspec/core.rb +6 -2
- data/lib/rspec/core/configuration.rb +61 -26
- data/lib/rspec/core/configuration_options.rb +5 -1
- data/lib/rspec/core/deprecation.rb +0 -15
- data/lib/rspec/core/drb_command_line.rb +3 -0
- data/lib/rspec/core/drb_options.rb +3 -1
- data/lib/rspec/core/dsl.rb +4 -2
- data/lib/rspec/core/example.rb +85 -23
- data/lib/rspec/core/example_group.rb +103 -78
- data/lib/rspec/core/hooks.rb +68 -33
- data/lib/rspec/core/let.rb +0 -1
- data/lib/rspec/core/mocking/with_mocha.rb +10 -4
- data/lib/rspec/core/option_parser.rb +3 -2
- data/lib/rspec/core/project_initializer.rb +7 -1
- data/lib/rspec/core/runner.rb +2 -2
- data/lib/rspec/core/shared_context.rb +2 -2
- data/lib/rspec/core/shared_example_group.rb +38 -14
- data/lib/rspec/core/subject.rb +67 -52
- data/lib/rspec/core/version.rb +1 -1
- data/spec/rspec/core/command_line_spec.rb +68 -126
- data/spec/rspec/core/configuration_options_spec.rb +20 -4
- data/spec/rspec/core/configuration_spec.rb +61 -21
- data/spec/rspec/core/drb_command_line_spec.rb +1 -0
- data/spec/rspec/core/drb_options_spec.rb +1 -0
- data/spec/rspec/core/dsl_spec.rb +17 -0
- data/spec/rspec/core/example_group_spec.rb +19 -11
- data/spec/rspec/core/example_spec.rb +34 -0
- data/spec/rspec/core/option_parser_spec.rb +2 -1
- data/spec/rspec/core/shared_example_group_spec.rb +9 -9
- data/spec/rspec/core/subject_spec.rb +14 -0
- data/spec/rspec/core_spec.rb +18 -8
- data/spec/spec_helper.rb +1 -2
- metadata +7 -5
@@ -1,7 +1,7 @@
|
|
1
1
|
module RSpec
|
2
2
|
module Core
|
3
|
-
# ExampleGroup and Example are the main structural elements of
|
4
|
-
# Consider this example:
|
3
|
+
# ExampleGroup and {Example} are the main structural elements of
|
4
|
+
# rspec-core. Consider this example:
|
5
5
|
#
|
6
6
|
# describe Thing do
|
7
7
|
# it "does something" do
|
@@ -47,81 +47,118 @@ module RSpec
|
|
47
47
|
alias_method :display_name, :description
|
48
48
|
# @private
|
49
49
|
alias_method :describes, :described_class
|
50
|
-
end
|
51
|
-
|
52
|
-
# @private
|
53
|
-
def self.define_example_method(name, extra_options={})
|
54
|
-
module_eval(<<-END_RUBY, __FILE__, __LINE__)
|
55
|
-
def self.#{name}(desc=nil, *args, &block)
|
56
|
-
options = build_metadata_hash_from(args)
|
57
|
-
options.update(:pending => RSpec::Core::Pending::NOT_YET_IMPLEMENTED) unless block
|
58
|
-
options.update(#{extra_options.inspect})
|
59
|
-
examples << RSpec::Core::Example.new(self, desc, options, block)
|
60
|
-
examples.last
|
61
|
-
end
|
62
|
-
END_RUBY
|
63
|
-
end
|
64
|
-
|
65
|
-
define_example_method :example
|
66
|
-
define_example_method :it
|
67
|
-
define_example_method :specify
|
68
50
|
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
51
|
+
# @private
|
52
|
+
# @macro [attach] define_example_method
|
53
|
+
# @param [String] name
|
54
|
+
# @param [Hash] extra_options
|
55
|
+
# @param [Block] implementation
|
56
|
+
def self.define_example_method(name, extra_options={})
|
57
|
+
module_eval(<<-END_RUBY, __FILE__, __LINE__)
|
58
|
+
def #{name}(desc=nil, *args, &block)
|
59
|
+
options = build_metadata_hash_from(args)
|
60
|
+
options.update(:pending => RSpec::Core::Pending::NOT_YET_IMPLEMENTED) unless block
|
61
|
+
options.update(#{extra_options.inspect})
|
62
|
+
examples << RSpec::Core::Example.new(self, desc, options, block)
|
63
|
+
examples.last
|
64
|
+
end
|
65
|
+
END_RUBY
|
66
|
+
end
|
76
67
|
|
77
|
-
|
78
|
-
|
79
|
-
|
68
|
+
# Defines an example within a group.
|
69
|
+
define_example_method :example
|
70
|
+
# Defines an example within a group.
|
71
|
+
#
|
72
|
+
# @see example
|
73
|
+
define_example_method :it
|
74
|
+
# Defines an example within a group.
|
75
|
+
# This is here primarily for backward compatibility with early versions
|
76
|
+
# of RSpec which used `context` and `specify` instead of `describe` and
|
77
|
+
# `it`.
|
78
|
+
define_example_method :specify
|
79
|
+
|
80
|
+
# Shortcut to define an example with `:focus` => true
|
81
|
+
define_example_method :focus, :focused => true, :focus => true
|
82
|
+
# Shortcut to define an example with `:focus` => true
|
83
|
+
define_example_method :focused, :focused => true, :focus => true
|
84
|
+
|
85
|
+
# Shortcut to define an example with :pending => true
|
86
|
+
define_example_method :pending, :pending => true
|
87
|
+
# Shortcut to define an example with :pending => 'Temporarily disabled with xexample'
|
88
|
+
define_example_method :xexample, :pending => 'Temporarily disabled with xexample'
|
89
|
+
# Shortcut to define an example with :pending => 'Temporarily disabled with xit'
|
90
|
+
define_example_method :xit, :pending => 'Temporarily disabled with xit'
|
91
|
+
# Shortcut to define an example with :pending => 'Temporarily disabled with xspecify'
|
92
|
+
define_example_method :xspecify, :pending => 'Temporarily disabled with xspecify'
|
93
|
+
|
94
|
+
# Works like `alias_method :name, :example` with the added benefit of
|
95
|
+
# assigning default metadata to the generated example.
|
96
|
+
#
|
97
|
+
# @note Use with caution. This extends the language used in your
|
98
|
+
# specs, but does not add any additional documentation. We use this
|
99
|
+
# in rspec to define methods like `focus` and `xit`, but we also add
|
100
|
+
# docs for those methods.
|
101
|
+
def alias_example_to name, extra={}
|
102
|
+
(class << self; self; end).define_example_method name, extra
|
103
|
+
end
|
80
104
|
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
105
|
+
# @private
|
106
|
+
# @macro [attach] define_nested_shared_group_method
|
107
|
+
#
|
108
|
+
# @see SharedExampleGroup
|
109
|
+
def self.define_nested_shared_group_method(new_name, report_label=nil)
|
110
|
+
module_eval(<<-END_RUBY, __FILE__, __LINE__)
|
111
|
+
def #{new_name}(name, *args, &customization_block)
|
112
|
+
group = describe("#{report_label || "it should behave like"} \#{name}") do
|
113
|
+
find_and_eval_shared("examples", name, *args, &customization_block)
|
114
|
+
end
|
115
|
+
group.metadata[:shared_group_name] = name
|
116
|
+
group
|
87
117
|
end
|
88
|
-
|
89
|
-
|
90
|
-
end
|
91
|
-
END_RUBY
|
92
|
-
end
|
93
|
-
|
94
|
-
define_nested_shared_group_method :it_should_behave_like
|
118
|
+
END_RUBY
|
119
|
+
end
|
95
120
|
|
96
|
-
|
97
|
-
|
121
|
+
# Generates a nested example group and includes the shared content
|
122
|
+
# mapped to `name` in the nested group.
|
123
|
+
define_nested_shared_group_method :it_behaves_like, "behaves like"
|
124
|
+
# Generates a nested example group and includes the shared content
|
125
|
+
# mapped to `name` in the nested group.
|
126
|
+
define_nested_shared_group_method :it_should_behave_like
|
127
|
+
|
128
|
+
# Works like `alias_method :name, :it_behaves_like` with the added
|
129
|
+
# benefit of assigning default metadata to the generated example.
|
130
|
+
#
|
131
|
+
# @note Use with caution. This extends the language used in your
|
132
|
+
# specs, but does not add any additional documentation. We use this
|
133
|
+
# in rspec to define `it_should_behave_like` (for backward
|
134
|
+
# compatibility), but we also add docs for that method.
|
135
|
+
def alias_it_behaves_like_to name, *args, &block
|
136
|
+
(class << self; self; end).define_nested_shared_group_method name, *args, &block
|
137
|
+
end
|
98
138
|
end
|
99
139
|
|
100
|
-
|
101
|
-
|
102
|
-
#
|
140
|
+
# Includes shared content mapped to `name` directly in the group in which
|
141
|
+
# it is declared, as opposed to `it_behaves_like`, which creates a nested
|
142
|
+
# group. If given a block, that block is also eval'd in the current context.
|
103
143
|
#
|
104
144
|
# @see SharedExampleGroup
|
105
|
-
def self.include_context(name, *args)
|
106
|
-
|
145
|
+
def self.include_context(name, *args, &block)
|
146
|
+
find_and_eval_shared("context", name, *args, &block)
|
107
147
|
end
|
108
148
|
|
109
|
-
# Includes shared content
|
149
|
+
# Includes shared content mapped to `name` directly in the group in which
|
150
|
+
# it is declared, as opposed to `it_behaves_like`, which creates a nested
|
151
|
+
# group. If given a block, that block is also eval'd in the current context.
|
110
152
|
#
|
111
153
|
# @see SharedExampleGroup
|
112
|
-
def self.include_examples(name, *args)
|
113
|
-
|
114
|
-
end
|
115
|
-
|
116
|
-
# @private
|
117
|
-
def self.block_not_supported(label)
|
118
|
-
warn("Customization blocks not supported for include_#{label}. Use it_behaves_like instead.")
|
154
|
+
def self.include_examples(name, *args, &block)
|
155
|
+
find_and_eval_shared("examples", name, *args, &block)
|
119
156
|
end
|
120
157
|
|
121
158
|
# @private
|
122
159
|
def self.find_and_eval_shared(label, name, *args, &customization_block)
|
123
160
|
raise ArgumentError, "Could not find shared #{label} #{name.inspect}" unless
|
124
|
-
|
161
|
+
shared_block = world.shared_example_groups[name]
|
125
162
|
|
126
163
|
module_eval_with_args(*args, &shared_block)
|
127
164
|
module_eval(&customization_block) if customization_block
|
@@ -149,7 +186,7 @@ module RSpec
|
|
149
186
|
end
|
150
187
|
|
151
188
|
# @private
|
152
|
-
# @return [Metadata] belonging to the parent of a nested
|
189
|
+
# @return [Metadata] belonging to the parent of a nested {ExampleGroup}
|
153
190
|
def self.superclass_metadata
|
154
191
|
@superclass_metadata ||= self.superclass.respond_to?(:metadata) ? self.superclass.metadata : nil
|
155
192
|
end
|
@@ -247,19 +284,7 @@ module RSpec
|
|
247
284
|
args.unshift(symbol_description) if symbol_description
|
248
285
|
@metadata = RSpec::Core::Metadata.new(superclass_metadata).process(*args)
|
249
286
|
world.configure_group(self)
|
250
|
-
|
251
|
-
RSpec.configuration.hooks[_when][:each].each do |hook|
|
252
|
-
unless ancestors.any? {|a| a.hooks[_when][:each].include? hook }
|
253
|
-
hooks[_when][:each] << hook # each's get filtered later per example
|
254
|
-
end
|
255
|
-
end
|
256
|
-
next if _when == :around # no around(:all) hooks
|
257
|
-
RSpec.configuration.hooks[_when][:all].each do |hook|
|
258
|
-
unless ancestors.any? {|a| a.hooks[_when][:all].include? hook }
|
259
|
-
hooks[_when][:all] << hook if hook.options_apply?(self)
|
260
|
-
end
|
261
|
-
end
|
262
|
-
end
|
287
|
+
hooks.register_globals(self, RSpec.configuration.hooks)
|
263
288
|
end
|
264
289
|
|
265
290
|
# @private
|
@@ -318,7 +343,7 @@ An error occurred in an after(:all) hook.
|
|
318
343
|
#{e.class}: #{e.message}
|
319
344
|
occurred at #{e.backtrace.first}
|
320
345
|
|
321
|
-
|
346
|
+
EOS
|
322
347
|
end
|
323
348
|
end
|
324
349
|
|
@@ -401,11 +426,11 @@ An error occurred in an after(:all) hook.
|
|
401
426
|
end
|
402
427
|
|
403
428
|
# @attr_reader
|
404
|
-
# Returns the
|
429
|
+
# Returns the {Example} object that wraps this instance of
|
405
430
|
# `ExampleGroup`
|
406
431
|
attr_accessor :example
|
407
432
|
|
408
|
-
# @deprecated use
|
433
|
+
# @deprecated use {ExampleGroup#example}
|
409
434
|
def running_example
|
410
435
|
RSpec.deprecate("running_example", "example")
|
411
436
|
example
|
@@ -428,12 +453,12 @@ An error occurred in an after(:all) hook.
|
|
428
453
|
# @private
|
429
454
|
# instance_evals the block, capturing and reporting an exception if
|
430
455
|
# raised
|
431
|
-
def instance_eval_with_rescue(&hook)
|
456
|
+
def instance_eval_with_rescue(context = nil, &hook)
|
432
457
|
begin
|
433
458
|
instance_eval(&hook)
|
434
459
|
rescue Exception => e
|
435
460
|
raise unless example
|
436
|
-
example.set_exception(e)
|
461
|
+
example.set_exception(e, context)
|
437
462
|
end
|
438
463
|
end
|
439
464
|
end
|
data/lib/rspec/core/hooks.rb
CHANGED
@@ -32,7 +32,7 @@ module RSpec
|
|
32
32
|
include HookExtension
|
33
33
|
|
34
34
|
def run(example)
|
35
|
-
example.instance_eval_with_rescue(&self)
|
35
|
+
example.instance_eval_with_rescue("in an after hook", &self)
|
36
36
|
end
|
37
37
|
|
38
38
|
def display_name
|
@@ -48,7 +48,16 @@ module RSpec
|
|
48
48
|
end
|
49
49
|
end
|
50
50
|
|
51
|
+
module HookCollectionAliases
|
52
|
+
def self.included(host)
|
53
|
+
host.send :alias_method, :prepend, :unshift
|
54
|
+
host.send :alias_method, :append, :push
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
51
58
|
class HookCollection < Array
|
59
|
+
include HookCollectionAliases
|
60
|
+
|
52
61
|
def for(example_or_group)
|
53
62
|
self.class.new(select {|hook| hook.options_apply?(example_or_group)}).
|
54
63
|
with(example_or_group)
|
@@ -64,18 +73,9 @@ module RSpec
|
|
64
73
|
end
|
65
74
|
end
|
66
75
|
|
67
|
-
class GroupHookCollection < Array
|
68
|
-
def for(group)
|
69
|
-
@group = group
|
70
|
-
self
|
71
|
-
end
|
72
|
-
|
73
|
-
def run
|
74
|
-
shift.run(@group) until empty?
|
75
|
-
end
|
76
|
-
end
|
77
|
-
|
78
76
|
class AroundHookCollection < Array
|
77
|
+
include HookCollectionAliases
|
78
|
+
|
79
79
|
def for(example, initial_procsy=nil)
|
80
80
|
self.class.new(select {|hook| hook.options_apply?(example)}).
|
81
81
|
with(example, initial_procsy)
|
@@ -96,13 +96,43 @@ module RSpec
|
|
96
96
|
end
|
97
97
|
end
|
98
98
|
|
99
|
+
class GroupHookCollection < Array
|
100
|
+
def for(group)
|
101
|
+
@group = group
|
102
|
+
self
|
103
|
+
end
|
104
|
+
|
105
|
+
def run
|
106
|
+
shift.run(@group) until empty?
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
module RegistersGlobals
|
111
|
+
def register_globals host, globals
|
112
|
+
[:before, :after, :around].each do |position|
|
113
|
+
process host, globals, position, :each
|
114
|
+
next if position == :around # no around(:all) hooks
|
115
|
+
process host, globals, position, :all
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
private
|
120
|
+
def process host, globals, position, scope
|
121
|
+
globals[position][scope].each do |hook|
|
122
|
+
unless host.ancestors.any? { |a| a.hooks[position][scope].include? hook }
|
123
|
+
self[position][scope] << hook if scope == :each || hook.options_apply?(host)
|
124
|
+
end
|
125
|
+
end
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
99
129
|
# @private
|
100
130
|
def hooks
|
101
131
|
@hooks ||= {
|
102
132
|
:around => { :each => AroundHookCollection.new },
|
103
|
-
:before => { :each =>
|
104
|
-
:after => { :each =>
|
105
|
-
}
|
133
|
+
:before => { :each => HookCollection.new, :all => HookCollection.new, :suite => HookCollection.new },
|
134
|
+
:after => { :each => HookCollection.new, :all => HookCollection.new, :suite => HookCollection.new }
|
135
|
+
}.extend(RegistersGlobals)
|
106
136
|
end
|
107
137
|
|
108
138
|
# @api public
|
@@ -126,12 +156,11 @@ module RSpec
|
|
126
156
|
#
|
127
157
|
# Declare a block of code to be run before each example (using `:each`)
|
128
158
|
# or once before any example (using `:all`). These are usually declared
|
129
|
-
# directly in the
|
130
|
-
#
|
159
|
+
# directly in the {ExampleGroup} to which they apply, but they can also
|
160
|
+
# be shared across multiple groups.
|
131
161
|
#
|
132
162
|
# You can also use `before(:suite)` to run a block of code before any
|
133
|
-
# example groups are run. This should be declared in
|
134
|
-
# [RSpec.configure](../../RSpec#configure-class_method)
|
163
|
+
# example groups are run. This should be declared in {RSpec.configure}
|
135
164
|
#
|
136
165
|
# Instance variables declared in `before(:each)` or `before(:all)` are
|
137
166
|
# accessible within each example.
|
@@ -232,7 +261,7 @@ module RSpec
|
|
232
261
|
# rspec-rails, but it will not be wrapped in a transaction for you, so
|
233
262
|
# you are on your own to clean up in an `after(:all)` block.
|
234
263
|
#
|
235
|
-
# @example before(:each) declared in an
|
264
|
+
# @example before(:each) declared in an {ExampleGroup}
|
236
265
|
#
|
237
266
|
# describe Thing do
|
238
267
|
# before(:each) do
|
@@ -244,7 +273,7 @@ module RSpec
|
|
244
273
|
# end
|
245
274
|
# end
|
246
275
|
#
|
247
|
-
# @example before(:all) declared in an
|
276
|
+
# @example before(:all) declared in an {ExampleGroup}
|
248
277
|
#
|
249
278
|
# describe Parser do
|
250
279
|
# before(:all) do
|
@@ -264,8 +293,7 @@ module RSpec
|
|
264
293
|
# end
|
265
294
|
# end
|
266
295
|
def before(*args, &block)
|
267
|
-
|
268
|
-
hooks[:before][scope] << block.extend(BeforeHookExtension).with(options)
|
296
|
+
register_hook :append, :before, *args, &block
|
269
297
|
end
|
270
298
|
|
271
299
|
alias_method :append_before, :before
|
@@ -275,8 +303,7 @@ module RSpec
|
|
275
303
|
#
|
276
304
|
# See #before for scoping semantics.
|
277
305
|
def prepend_before(*args, &block)
|
278
|
-
|
279
|
-
hooks[:before][scope].unshift block.extend(BeforeHookExtension).with(options)
|
306
|
+
register_hook :prepend, :before, *args, &block
|
280
307
|
end
|
281
308
|
|
282
309
|
# @api public
|
@@ -328,8 +355,7 @@ module RSpec
|
|
328
355
|
# Similarly, if more than one `after` is declared within any one scope,
|
329
356
|
# they are run in reverse order of that in which they are declared.
|
330
357
|
def after(*args, &block)
|
331
|
-
|
332
|
-
hooks[:after][scope].unshift block.extend(AfterHookExtension).with(options)
|
358
|
+
register_hook :prepend, :after, *args, &block
|
333
359
|
end
|
334
360
|
|
335
361
|
alias_method :prepend_after, :after
|
@@ -339,8 +365,7 @@ module RSpec
|
|
339
365
|
#
|
340
366
|
# See #after for scoping semantics.
|
341
367
|
def append_after(*args, &block)
|
342
|
-
|
343
|
-
hooks[:after][scope] << block.extend(AfterHookExtension).with(options)
|
368
|
+
register_hook :append, :after, *args, &block
|
344
369
|
end
|
345
370
|
|
346
371
|
# @api public
|
@@ -388,8 +413,7 @@ module RSpec
|
|
388
413
|
# around(:each) {|ex| FakeFS(&ex)}
|
389
414
|
#
|
390
415
|
def around(*args, &block)
|
391
|
-
|
392
|
-
hooks[:around][scope].unshift block.extend(AroundHookExtension).with(options)
|
416
|
+
register_hook :prepend, :around, *args, &block
|
393
417
|
end
|
394
418
|
|
395
419
|
# @private
|
@@ -407,6 +431,14 @@ module RSpec
|
|
407
431
|
|
408
432
|
private
|
409
433
|
|
434
|
+
SCOPES = [:each, :all, :suite]
|
435
|
+
|
436
|
+
EXTENSIONS = {
|
437
|
+
:before => BeforeHookExtension,
|
438
|
+
:after => AfterHookExtension,
|
439
|
+
:around => AroundHookExtension
|
440
|
+
}
|
441
|
+
|
410
442
|
def before_all_hooks_for(group)
|
411
443
|
GroupHookCollection.new(hooks[:before][:all]).for(group)
|
412
444
|
end
|
@@ -423,6 +455,11 @@ module RSpec
|
|
423
455
|
HookCollection.new(ancestors.map {|a| a.hooks[:after][:each]}.flatten).for(example)
|
424
456
|
end
|
425
457
|
|
458
|
+
def register_hook prepend_or_append, hook, *args, &block
|
459
|
+
scope, options = scope_and_options_from(*args)
|
460
|
+
hooks[hook][scope].send(prepend_or_append, block.extend(EXTENSIONS[hook]).with(options))
|
461
|
+
end
|
462
|
+
|
426
463
|
def find_hook(hook, scope, example_or_group, initial_procsy)
|
427
464
|
case [hook, scope]
|
428
465
|
when [:before, :all]
|
@@ -440,8 +477,6 @@ module RSpec
|
|
440
477
|
end
|
441
478
|
end
|
442
479
|
|
443
|
-
SCOPES = [:each, :all, :suite]
|
444
|
-
|
445
480
|
def scope_and_options_from(*args)
|
446
481
|
return extract_scope_from(args), build_metadata_hash_from(args)
|
447
482
|
end
|