rspec-mocks 3.0.0 → 3.1.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.
- checksums.yaml +6 -14
- checksums.yaml.gz.sig +0 -0
- data/Changelog.md +89 -1
- data/README.md +32 -18
- data/lib/rspec/mocks/any_instance/chain.rb +2 -2
- data/lib/rspec/mocks/any_instance/expectation_chain.rb +2 -3
- data/lib/rspec/mocks/any_instance/message_chains.rb +8 -7
- data/lib/rspec/mocks/any_instance/proxy.rb +7 -3
- data/lib/rspec/mocks/any_instance/recorder.rb +27 -25
- data/lib/rspec/mocks/any_instance/stub_chain.rb +3 -5
- data/lib/rspec/mocks/argument_list_matcher.rb +4 -4
- data/lib/rspec/mocks/argument_matchers.rb +39 -6
- data/lib/rspec/mocks/configuration.rb +4 -11
- data/lib/rspec/mocks/error_generator.rb +33 -27
- data/lib/rspec/mocks/example_methods.rb +75 -7
- data/lib/rspec/mocks/instance_method_stasher.rb +5 -5
- data/lib/rspec/mocks/matchers/have_received.rb +10 -8
- data/lib/rspec/mocks/matchers/receive.rb +8 -8
- data/lib/rspec/mocks/matchers/receive_message_chain.rb +5 -6
- data/lib/rspec/mocks/matchers/receive_messages.rb +6 -7
- data/lib/rspec/mocks/message_chain.rb +5 -5
- data/lib/rspec/mocks/message_expectation.rb +66 -27
- data/lib/rspec/mocks/method_double.rb +15 -12
- data/lib/rspec/mocks/method_reference.rb +8 -7
- data/lib/rspec/mocks/mutate_const.rb +26 -100
- data/lib/rspec/mocks/object_reference.rb +12 -13
- data/lib/rspec/mocks/order_group.rb +4 -5
- data/lib/rspec/mocks/proxy.rb +35 -24
- data/lib/rspec/mocks/space.rb +25 -25
- data/lib/rspec/mocks/syntax.rb +101 -99
- data/lib/rspec/mocks/targets.rb +6 -6
- data/lib/rspec/mocks/test_double.rb +13 -4
- data/lib/rspec/mocks/verifying_double.rb +16 -16
- data/lib/rspec/mocks/verifying_message_expecation.rb +15 -13
- data/lib/rspec/mocks/verifying_proxy.rb +12 -16
- data/lib/rspec/mocks/version.rb +1 -1
- data.tar.gz.sig +0 -0
- metadata +61 -54
- metadata.gz.sig +0 -0
data/lib/rspec/mocks/proxy.rb
CHANGED
|
@@ -8,6 +8,11 @@ module RSpec
|
|
|
8
8
|
end
|
|
9
9
|
end
|
|
10
10
|
|
|
11
|
+
# @private
|
|
12
|
+
def ensure_implemented(*_args)
|
|
13
|
+
# noop for basic proxies, see VerifyingProxy for behaviour.
|
|
14
|
+
end
|
|
15
|
+
|
|
11
16
|
# @private
|
|
12
17
|
def initialize(object, order_group, name=nil, options={})
|
|
13
18
|
@object = object
|
|
@@ -37,7 +42,7 @@ module RSpec
|
|
|
37
42
|
end
|
|
38
43
|
|
|
39
44
|
# @private
|
|
40
|
-
def original_method_handle_for(
|
|
45
|
+
def original_method_handle_for(_message)
|
|
41
46
|
nil
|
|
42
47
|
end
|
|
43
48
|
|
|
@@ -84,20 +89,19 @@ module RSpec
|
|
|
84
89
|
end
|
|
85
90
|
|
|
86
91
|
@messages_received.each do |(actual_method_name, args, _)|
|
|
87
|
-
|
|
88
|
-
expectation.invoke(nil)
|
|
89
|
-
block.call(*args) if block
|
|
90
|
-
end
|
|
91
|
-
end
|
|
92
|
+
next unless expectation.matches?(actual_method_name, *args)
|
|
92
93
|
|
|
94
|
+
expectation.invoke(nil)
|
|
95
|
+
block.call(*args) if block
|
|
96
|
+
end
|
|
93
97
|
end
|
|
94
98
|
|
|
95
99
|
# @private
|
|
96
100
|
def check_for_unexpected_arguments(expectation)
|
|
97
101
|
@messages_received.each do |(method_name, args, _)|
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
102
|
+
next unless expectation.matches_name_but_not_args(method_name, *args)
|
|
103
|
+
|
|
104
|
+
raise_unexpected_message_args_error(expectation, *args)
|
|
101
105
|
end
|
|
102
106
|
end
|
|
103
107
|
|
|
@@ -124,7 +128,7 @@ module RSpec
|
|
|
124
128
|
|
|
125
129
|
# @private
|
|
126
130
|
def verify
|
|
127
|
-
@method_doubles.each_value {|d| d.verify}
|
|
131
|
+
@method_doubles.each_value { |d| d.verify }
|
|
128
132
|
end
|
|
129
133
|
|
|
130
134
|
# @private
|
|
@@ -134,12 +138,12 @@ module RSpec
|
|
|
134
138
|
|
|
135
139
|
# @private
|
|
136
140
|
def received_message?(method_name, *args, &block)
|
|
137
|
-
@messages_received.any? {|array| array == [method_name, args, block]}
|
|
141
|
+
@messages_received.any? { |array| array == [method_name, args, block] }
|
|
138
142
|
end
|
|
139
143
|
|
|
140
144
|
# @private
|
|
141
145
|
def has_negative_expectation?(message)
|
|
142
|
-
method_double_for(message).expectations.
|
|
146
|
+
method_double_for(message).expectations.find { |expectation| expectation.negative_expectation_for?(message) }
|
|
143
147
|
end
|
|
144
148
|
|
|
145
149
|
# @private
|
|
@@ -157,16 +161,19 @@ module RSpec
|
|
|
157
161
|
|
|
158
162
|
if (stub && expectation && expectation.called_max_times?) || (stub && !expectation)
|
|
159
163
|
expectation.increase_actual_received_count! if expectation && expectation.actual_received_count_matters?
|
|
160
|
-
if expectation = find_almost_matching_expectation(message, *args)
|
|
164
|
+
if (expectation = find_almost_matching_expectation(message, *args))
|
|
161
165
|
expectation.advise(*args) unless expectation.expected_messages_received?
|
|
162
166
|
end
|
|
163
167
|
stub.invoke(nil, *args, &block)
|
|
164
168
|
elsif expectation
|
|
165
169
|
expectation.invoke(stub, *args, &block)
|
|
166
|
-
elsif expectation = find_almost_matching_expectation(message, *args)
|
|
170
|
+
elsif (expectation = find_almost_matching_expectation(message, *args))
|
|
167
171
|
expectation.advise(*args) if null_object? unless expectation.expected_messages_received?
|
|
168
|
-
|
|
169
|
-
|
|
172
|
+
|
|
173
|
+
if null_object? || !has_negative_expectation?(message)
|
|
174
|
+
raise_unexpected_message_args_error(expectation, *args)
|
|
175
|
+
end
|
|
176
|
+
elsif (stub = find_almost_matching_stub(message, *args))
|
|
170
177
|
stub.advise(*args)
|
|
171
178
|
raise_missing_default_stub_error(stub, *args)
|
|
172
179
|
elsif Class === @object
|
|
@@ -192,7 +199,7 @@ module RSpec
|
|
|
192
199
|
end
|
|
193
200
|
|
|
194
201
|
# @private
|
|
195
|
-
def visibility_for(
|
|
202
|
+
def visibility_for(_method_name)
|
|
196
203
|
# This is the default (for test doubles). Subclasses override this.
|
|
197
204
|
:public
|
|
198
205
|
end
|
|
@@ -201,9 +208,13 @@ module RSpec
|
|
|
201
208
|
def prepended_modules_of_singleton_class
|
|
202
209
|
@prepended_modules_of_singleton_class ||= begin
|
|
203
210
|
singleton_class = @object.singleton_class
|
|
204
|
-
singleton_class.ancestors
|
|
205
|
-
|
|
206
|
-
|
|
211
|
+
ancestors = singleton_class.ancestors
|
|
212
|
+
|
|
213
|
+
# `|| 0` is necessary for Ruby 2.0, where the singleton class
|
|
214
|
+
# is only in the ancestor list when there are prepended modules.
|
|
215
|
+
singleton_index = ancestors.index(singleton_class) || 0
|
|
216
|
+
|
|
217
|
+
ancestors[0, singleton_index]
|
|
207
218
|
end
|
|
208
219
|
end
|
|
209
220
|
end
|
|
@@ -239,11 +250,11 @@ module RSpec
|
|
|
239
250
|
end
|
|
240
251
|
|
|
241
252
|
def find_matching_method_stub(method_name, *args)
|
|
242
|
-
method_double_for(method_name).stubs.find {|stub| stub.matches?(method_name, *args)}
|
|
253
|
+
method_double_for(method_name).stubs.find { |stub| stub.matches?(method_name, *args) }
|
|
243
254
|
end
|
|
244
255
|
|
|
245
256
|
def find_almost_matching_stub(method_name, *args)
|
|
246
|
-
method_double_for(method_name).stubs.find {|stub| stub.matches_name_but_not_args(method_name, *args)}
|
|
257
|
+
method_double_for(method_name).stubs.find { |stub| stub.matches_name_but_not_args(method_name, *args) }
|
|
247
258
|
end
|
|
248
259
|
end
|
|
249
260
|
|
|
@@ -290,7 +301,7 @@ module RSpec
|
|
|
290
301
|
end
|
|
291
302
|
|
|
292
303
|
def reset
|
|
293
|
-
@method_doubles.each_value {|d| d.reset}
|
|
304
|
+
@method_doubles.each_value { |d| d.reset }
|
|
294
305
|
super
|
|
295
306
|
end
|
|
296
307
|
|
|
@@ -410,7 +421,7 @@ module RSpec
|
|
|
410
421
|
|
|
411
422
|
private
|
|
412
423
|
|
|
413
|
-
def warn
|
|
424
|
+
def warn(method_name)
|
|
414
425
|
source = CallerFilter.first_non_rspec_line
|
|
415
426
|
Kernel.warn("An expectation of :#{method_name} was set on nil. Called from #{source}. Use allow_message_expectations_on_nil to disable warnings.")
|
|
416
427
|
end
|
data/lib/rspec/mocks/space.rb
CHANGED
|
@@ -5,23 +5,23 @@ module RSpec
|
|
|
5
5
|
# the scope of an example. Called "root" because it serves
|
|
6
6
|
# as the root of the space stack.
|
|
7
7
|
class RootSpace
|
|
8
|
-
def proxy_for(*
|
|
8
|
+
def proxy_for(*_args)
|
|
9
9
|
raise_lifecycle_message
|
|
10
10
|
end
|
|
11
11
|
|
|
12
|
-
def any_instance_recorder_for(*
|
|
12
|
+
def any_instance_recorder_for(*_args)
|
|
13
13
|
raise_lifecycle_message
|
|
14
14
|
end
|
|
15
15
|
|
|
16
|
-
def any_instance_proxy_for(*
|
|
16
|
+
def any_instance_proxy_for(*_args)
|
|
17
17
|
raise_lifecycle_message
|
|
18
18
|
end
|
|
19
19
|
|
|
20
|
-
def register_constant_mutator(
|
|
20
|
+
def register_constant_mutator(_mutator)
|
|
21
21
|
raise_lifecycle_message
|
|
22
22
|
end
|
|
23
23
|
|
|
24
|
-
def any_instance_recorders_from_ancestry_of(
|
|
24
|
+
def any_instance_recorders_from_ancestry_of(_object)
|
|
25
25
|
raise_lifecycle_message
|
|
26
26
|
end
|
|
27
27
|
|
|
@@ -31,7 +31,7 @@ module RSpec
|
|
|
31
31
|
def verify_all
|
|
32
32
|
end
|
|
33
33
|
|
|
34
|
-
def registered?(
|
|
34
|
+
def registered?(_object)
|
|
35
35
|
false
|
|
36
36
|
end
|
|
37
37
|
|
|
@@ -43,7 +43,7 @@ module RSpec
|
|
|
43
43
|
|
|
44
44
|
def raise_lifecycle_message
|
|
45
45
|
raise OutsideOfExampleError,
|
|
46
|
-
|
|
46
|
+
"The use of doubles or partial doubles from rspec-mocks outside of the per-test lifecycle is not supported."
|
|
47
47
|
end
|
|
48
48
|
end
|
|
49
49
|
|
|
@@ -65,7 +65,7 @@ module RSpec
|
|
|
65
65
|
end
|
|
66
66
|
|
|
67
67
|
def verify_all
|
|
68
|
-
proxies.
|
|
68
|
+
proxies.values.each { |proxy| proxy.verify }
|
|
69
69
|
any_instance_recorders.each_value { |recorder| recorder.verify }
|
|
70
70
|
end
|
|
71
71
|
|
|
@@ -84,7 +84,7 @@ module RSpec
|
|
|
84
84
|
@constant_mutators.find { |m| m.full_constant_name == name }
|
|
85
85
|
end
|
|
86
86
|
|
|
87
|
-
def any_instance_recorder_for(klass, only_return_existing
|
|
87
|
+
def any_instance_recorder_for(klass, only_return_existing=false)
|
|
88
88
|
any_instance_mutex.synchronize do
|
|
89
89
|
id = klass.__id__
|
|
90
90
|
any_instance_recorders.fetch(id) do
|
|
@@ -112,7 +112,7 @@ module RSpec
|
|
|
112
112
|
alias ensure_registered proxy_for
|
|
113
113
|
|
|
114
114
|
def registered?(object)
|
|
115
|
-
proxies.
|
|
115
|
+
proxies.key?(id_for object)
|
|
116
116
|
end
|
|
117
117
|
|
|
118
118
|
def any_instance_recorders_from_ancestry_of(object)
|
|
@@ -147,21 +147,21 @@ module RSpec
|
|
|
147
147
|
|
|
148
148
|
def proxy_not_found_for(id, object)
|
|
149
149
|
proxies[id] = case object
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
150
|
+
when NilClass then ProxyForNil.new(@expectation_ordering)
|
|
151
|
+
when TestDouble then object.__build_mock_proxy_unless_expired(@expectation_ordering)
|
|
152
|
+
when Class
|
|
153
|
+
if RSpec::Mocks.configuration.verify_partial_doubles?
|
|
154
|
+
VerifyingPartialClassDoubleProxy.new(self, object, @expectation_ordering)
|
|
155
|
+
else
|
|
156
|
+
PartialClassDoubleProxy.new(self, object, @expectation_ordering)
|
|
157
|
+
end
|
|
158
|
+
else
|
|
159
|
+
if RSpec::Mocks.configuration.verify_partial_doubles?
|
|
160
|
+
VerifyingPartialDoubleProxy.new(object, @expectation_ordering)
|
|
161
|
+
else
|
|
162
|
+
PartialDoubleProxy.new(object, @expectation_ordering)
|
|
163
|
+
end
|
|
164
|
+
end
|
|
165
165
|
end
|
|
166
166
|
|
|
167
167
|
def any_instance_recorder_not_found_for(id, klass)
|
data/lib/rspec/mocks/syntax.rb
CHANGED
|
@@ -10,7 +10,7 @@ module RSpec
|
|
|
10
10
|
end
|
|
11
11
|
|
|
12
12
|
# @private
|
|
13
|
-
def self.warn_unless_should_configured(method_name ,replacement
|
|
13
|
+
def self.warn_unless_should_configured(method_name , replacement="the new `:expect` syntax or explicitly enable `:should`")
|
|
14
14
|
if @warn_about_should
|
|
15
15
|
RSpec.deprecate(
|
|
16
16
|
"Using `#{method_name}` from rspec-mocks' old `:should` syntax without explicitly enabling the syntax",
|
|
@@ -23,7 +23,7 @@ module RSpec
|
|
|
23
23
|
|
|
24
24
|
# @api private
|
|
25
25
|
# Enables the should syntax (`dbl.stub`, `dbl.should_receive`, etc).
|
|
26
|
-
def self.enable_should(syntax_host
|
|
26
|
+
def self.enable_should(syntax_host=default_should_syntax_host)
|
|
27
27
|
@warn_about_should = false if syntax_host == default_should_syntax_host
|
|
28
28
|
return if should_enabled?(syntax_host)
|
|
29
29
|
|
|
@@ -41,7 +41,7 @@ module RSpec
|
|
|
41
41
|
def stub(message_or_hash, opts={}, &block)
|
|
42
42
|
::RSpec::Mocks::Syntax.warn_unless_should_configured(__method__)
|
|
43
43
|
if ::Hash === message_or_hash
|
|
44
|
-
message_or_hash.each {|message, value| stub(message).and_return value }
|
|
44
|
+
message_or_hash.each { |message, value| stub(message).and_return value }
|
|
45
45
|
else
|
|
46
46
|
::RSpec::Mocks.allow_message(self, message_or_hash, opts, &block)
|
|
47
47
|
end
|
|
@@ -86,7 +86,7 @@ module RSpec
|
|
|
86
86
|
|
|
87
87
|
# @api private
|
|
88
88
|
# Disables the should syntax (`dbl.stub`, `dbl.should_receive`, etc).
|
|
89
|
-
def self.disable_should(syntax_host
|
|
89
|
+
def self.disable_should(syntax_host=default_should_syntax_host)
|
|
90
90
|
return unless should_enabled?(syntax_host)
|
|
91
91
|
|
|
92
92
|
syntax_host.class_exec do
|
|
@@ -107,7 +107,7 @@ module RSpec
|
|
|
107
107
|
|
|
108
108
|
# @api private
|
|
109
109
|
# Enables the expect syntax (`expect(dbl).to receive`, `allow(dbl).to receive`, etc).
|
|
110
|
-
def self.enable_expect(syntax_host
|
|
110
|
+
def self.enable_expect(syntax_host=::RSpec::Mocks::ExampleMethods)
|
|
111
111
|
return if expect_enabled?(syntax_host)
|
|
112
112
|
|
|
113
113
|
syntax_host.class_exec do
|
|
@@ -147,7 +147,7 @@ module RSpec
|
|
|
147
147
|
|
|
148
148
|
# @api private
|
|
149
149
|
# Disables the expect syntax (`expect(dbl).to receive`, `allow(dbl).to receive`, etc).
|
|
150
|
-
def self.disable_expect(syntax_host
|
|
150
|
+
def self.disable_expect(syntax_host=::RSpec::Mocks::ExampleMethods)
|
|
151
151
|
return unless expect_enabled?(syntax_host)
|
|
152
152
|
|
|
153
153
|
syntax_host.class_exec do
|
|
@@ -166,13 +166,13 @@ module RSpec
|
|
|
166
166
|
|
|
167
167
|
# @api private
|
|
168
168
|
# Indicates whether or not the should syntax is enabled.
|
|
169
|
-
def self.should_enabled?(syntax_host
|
|
169
|
+
def self.should_enabled?(syntax_host=default_should_syntax_host)
|
|
170
170
|
syntax_host.method_defined?(:should_receive)
|
|
171
171
|
end
|
|
172
172
|
|
|
173
173
|
# @api private
|
|
174
174
|
# Indicates whether or not the expect syntax is enabled.
|
|
175
|
-
def self.expect_enabled?(syntax_host
|
|
175
|
+
def self.expect_enabled?(syntax_host=::RSpec::Mocks::ExampleMethods)
|
|
176
176
|
syntax_host.method_defined?(:allow)
|
|
177
177
|
end
|
|
178
178
|
|
|
@@ -202,97 +202,99 @@ module RSpec
|
|
|
202
202
|
end
|
|
203
203
|
end
|
|
204
204
|
|
|
205
|
-
|
|
206
|
-
#
|
|
207
|
-
# that
|
|
208
|
-
#
|
|
209
|
-
#
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
205
|
+
if defined?(BasicObject)
|
|
206
|
+
# The legacy `:should` syntax adds the following methods directly to
|
|
207
|
+
# `BasicObject` so that they are available off of any object. Note, however,
|
|
208
|
+
# that this syntax does not always play nice with delegate/proxy objects.
|
|
209
|
+
# We recommend you use the non-monkeypatching `:expect` syntax instead.
|
|
210
|
+
# @see Class
|
|
211
|
+
class BasicObject
|
|
212
|
+
# @method should_receive
|
|
213
|
+
# Sets an expectation that this object should receive a message before
|
|
214
|
+
# the end of the example.
|
|
215
|
+
#
|
|
216
|
+
# @example
|
|
217
|
+
#
|
|
218
|
+
# logger = double('logger')
|
|
219
|
+
# thing_that_logs = ThingThatLogs.new(logger)
|
|
220
|
+
# logger.should_receive(:log)
|
|
221
|
+
# thing_that_logs.do_something_that_logs_a_message
|
|
222
|
+
#
|
|
223
|
+
# @note This is only available when you have enabled the `should` syntax.
|
|
224
|
+
# @see RSpec::Mocks::ExampleMethods#expect
|
|
225
|
+
|
|
226
|
+
# @method should_not_receive
|
|
227
|
+
# Sets and expectation that this object should _not_ receive a message
|
|
228
|
+
# during this example.
|
|
229
|
+
# @see RSpec::Mocks::ExampleMethods#expect
|
|
230
|
+
|
|
231
|
+
# @method stub
|
|
232
|
+
# Tells the object to respond to the message with the specified value.
|
|
233
|
+
#
|
|
234
|
+
# @example
|
|
235
|
+
#
|
|
236
|
+
# counter.stub(:count).and_return(37)
|
|
237
|
+
# counter.stub(:count => 37)
|
|
238
|
+
# counter.stub(:count) { 37 }
|
|
239
|
+
#
|
|
240
|
+
# @note This is only available when you have enabled the `should` syntax.
|
|
241
|
+
# @see RSpec::Mocks::ExampleMethods#allow
|
|
242
|
+
|
|
243
|
+
# @method unstub
|
|
244
|
+
# Removes a stub. On a double, the object will no longer respond to
|
|
245
|
+
# `message`. On a real object, the original method (if it exists) is
|
|
246
|
+
# restored.
|
|
247
|
+
#
|
|
248
|
+
# This is rarely used, but can be useful when a stub is set up during a
|
|
249
|
+
# shared `before` hook for the common case, but you want to replace it
|
|
250
|
+
# for a special case.
|
|
251
|
+
#
|
|
252
|
+
# @note This is only available when you have enabled the `should` syntax.
|
|
253
|
+
|
|
254
|
+
# @method stub_chain
|
|
255
|
+
# @overload stub_chain(method1, method2)
|
|
256
|
+
# @overload stub_chain("method1.method2")
|
|
257
|
+
# @overload stub_chain(method1, method_to_value_hash)
|
|
258
|
+
#
|
|
259
|
+
# Stubs a chain of methods.
|
|
260
|
+
#
|
|
261
|
+
# ## Warning:
|
|
262
|
+
#
|
|
263
|
+
# Chains can be arbitrarily long, which makes it quite painless to
|
|
264
|
+
# violate the Law of Demeter in violent ways, so you should consider any
|
|
265
|
+
# use of `stub_chain` a code smell. Even though not all code smells
|
|
266
|
+
# indicate real problems (think fluent interfaces), `stub_chain` still
|
|
267
|
+
# results in brittle examples. For example, if you write
|
|
268
|
+
# `foo.stub_chain(:bar, :baz => 37)` in a spec and then the
|
|
269
|
+
# implementation calls `foo.baz.bar`, the stub will not work.
|
|
270
|
+
#
|
|
271
|
+
# @example
|
|
272
|
+
#
|
|
273
|
+
# double.stub_chain("foo.bar") { :baz }
|
|
274
|
+
# double.stub_chain(:foo, :bar => :baz)
|
|
275
|
+
# double.stub_chain(:foo, :bar) { :baz }
|
|
276
|
+
#
|
|
277
|
+
# # Given any of ^^ these three forms ^^:
|
|
278
|
+
# double.foo.bar # => :baz
|
|
279
|
+
#
|
|
280
|
+
# # Common use in Rails/ActiveRecord:
|
|
281
|
+
# Article.stub_chain("recent.published") { [Article.new] }
|
|
282
|
+
#
|
|
283
|
+
# @note This is only available when you have enabled the `should` syntax.
|
|
284
|
+
# @see RSpec::Mocks::ExampleMethods#receive_message_chain
|
|
285
|
+
|
|
286
|
+
# @method as_null_object
|
|
287
|
+
# Tells the object to respond to all messages. If specific stub values
|
|
288
|
+
# are declared, they'll work as expected. If not, the receiver is
|
|
289
|
+
# returned.
|
|
290
|
+
#
|
|
291
|
+
# @note This is only available when you have enabled the `should` syntax.
|
|
292
|
+
|
|
293
|
+
# @method null_object?
|
|
294
|
+
# Returns true if this object has received `as_null_object`
|
|
295
|
+
#
|
|
296
|
+
# @note This is only available when you have enabled the `should` syntax.
|
|
297
|
+
end
|
|
296
298
|
end
|
|
297
299
|
|
|
298
300
|
# The legacy `:should` syntax adds the `any_instance` to `Class`.
|
data/lib/rspec/mocks/targets.rb
CHANGED
|
@@ -15,7 +15,7 @@ module RSpec
|
|
|
15
15
|
end
|
|
16
16
|
end
|
|
17
17
|
|
|
18
|
-
def self.delegate_not_to(matcher_method, options
|
|
18
|
+
def self.delegate_not_to(matcher_method, options={})
|
|
19
19
|
method_name = options.fetch(:from)
|
|
20
20
|
define_method(method_name) do |matcher, &block|
|
|
21
21
|
case matcher
|
|
@@ -30,7 +30,7 @@ module RSpec
|
|
|
30
30
|
end
|
|
31
31
|
|
|
32
32
|
def self.disallow_negation(method_name)
|
|
33
|
-
define_method(method_name) do |matcher, *
|
|
33
|
+
define_method(method_name) do |matcher, *_args|
|
|
34
34
|
raise_negation_unsupported(method_name, matcher)
|
|
35
35
|
end
|
|
36
36
|
end
|
|
@@ -47,14 +47,14 @@ module RSpec
|
|
|
47
47
|
|
|
48
48
|
def raise_unsupported_matcher(method_name, matcher)
|
|
49
49
|
raise UnsupportedMatcherError,
|
|
50
|
-
|
|
51
|
-
|
|
50
|
+
"only the `receive` or `receive_messages` matchers are supported " \
|
|
51
|
+
"with `#{expression}(...).#{method_name}`, but you have provided: #{matcher}"
|
|
52
52
|
end
|
|
53
53
|
|
|
54
54
|
def raise_negation_unsupported(method_name, matcher)
|
|
55
55
|
raise NegationUnsupportedError,
|
|
56
|
-
|
|
57
|
-
|
|
56
|
+
"`#{expression}(...).#{method_name} #{matcher.name}` is not supported since it " \
|
|
57
|
+
"doesn't really make sense. What would it even mean?"
|
|
58
58
|
end
|
|
59
59
|
|
|
60
60
|
def expression
|
|
@@ -39,12 +39,12 @@ module RSpec
|
|
|
39
39
|
|
|
40
40
|
# @private
|
|
41
41
|
def inspect
|
|
42
|
-
"#<#{self.class}:#{
|
|
42
|
+
"#<#{self.class}:#{'0x%x' % object_id} @name=#{@name.inspect}>"
|
|
43
43
|
end
|
|
44
44
|
|
|
45
45
|
# @private
|
|
46
46
|
def to_s
|
|
47
|
-
inspect.gsub('<','[').gsub('>',']')
|
|
47
|
+
inspect.gsub('<', '[').gsub('>', ']')
|
|
48
48
|
end
|
|
49
49
|
|
|
50
50
|
# @private
|
|
@@ -53,8 +53,8 @@ module RSpec
|
|
|
53
53
|
end
|
|
54
54
|
|
|
55
55
|
# @private
|
|
56
|
-
def
|
|
57
|
-
__raise_expired_error
|
|
56
|
+
def __build_mock_proxy_unless_expired(order_group)
|
|
57
|
+
__raise_expired_error || __build_mock_proxy(order_group)
|
|
58
58
|
end
|
|
59
59
|
|
|
60
60
|
# @private
|
|
@@ -111,10 +111,19 @@ module RSpec
|
|
|
111
111
|
::RSpec::Mocks.space.proxy_for(self)
|
|
112
112
|
end
|
|
113
113
|
|
|
114
|
+
def __build_mock_proxy(order_group)
|
|
115
|
+
TestDoubleProxy.new(self, order_group, @name)
|
|
116
|
+
end
|
|
117
|
+
|
|
114
118
|
def __raise_expired_error
|
|
115
119
|
return false unless @__expired
|
|
116
120
|
ErrorGenerator.new(self, @name).raise_expired_test_double_error
|
|
117
121
|
end
|
|
122
|
+
|
|
123
|
+
def initialize_copy(other)
|
|
124
|
+
as_null_object if other.null_object?
|
|
125
|
+
super
|
|
126
|
+
end
|
|
118
127
|
end
|
|
119
128
|
|
|
120
129
|
# A generic test double object. `double`, `instance_double` and friends
|