rspec-mocks 3.0.4 → 3.12.6
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- checksums.yaml.gz.sig +0 -0
- data/.document +1 -1
- data/.yardopts +1 -1
- data/Changelog.md +512 -2
- data/{License.txt → LICENSE.md} +5 -4
- data/README.md +113 -30
- data/lib/rspec/mocks/any_instance/chain.rb +5 -3
- data/lib/rspec/mocks/any_instance/error_generator.rb +31 -0
- data/lib/rspec/mocks/any_instance/expect_chain_chain.rb +1 -5
- data/lib/rspec/mocks/any_instance/expectation_chain.rb +9 -8
- data/lib/rspec/mocks/any_instance/message_chains.rb +7 -8
- data/lib/rspec/mocks/any_instance/proxy.rb +14 -5
- data/lib/rspec/mocks/any_instance/recorder.rb +61 -31
- data/lib/rspec/mocks/any_instance/stub_chain.rb +15 -11
- data/lib/rspec/mocks/any_instance/stub_chain_chain.rb +1 -5
- data/lib/rspec/mocks/any_instance.rb +1 -0
- data/lib/rspec/mocks/argument_list_matcher.rb +55 -10
- data/lib/rspec/mocks/argument_matchers.rb +88 -30
- data/lib/rspec/mocks/configuration.rb +61 -13
- data/lib/rspec/mocks/error_generator.rb +250 -107
- data/lib/rspec/mocks/example_methods.rb +151 -28
- data/lib/rspec/mocks/instance_method_stasher.rb +17 -6
- data/lib/rspec/mocks/matchers/have_received.rb +50 -20
- data/lib/rspec/mocks/matchers/receive.rb +39 -11
- data/lib/rspec/mocks/matchers/receive_message_chain.rb +22 -7
- data/lib/rspec/mocks/matchers/receive_messages.rb +12 -7
- data/lib/rspec/mocks/message_chain.rb +3 -7
- data/lib/rspec/mocks/message_expectation.rb +466 -307
- data/lib/rspec/mocks/method_double.rb +88 -29
- data/lib/rspec/mocks/method_reference.rb +85 -25
- data/lib/rspec/mocks/minitest_integration.rb +68 -0
- data/lib/rspec/mocks/mutate_const.rb +50 -109
- data/lib/rspec/mocks/object_reference.rb +89 -32
- data/lib/rspec/mocks/order_group.rb +4 -5
- data/lib/rspec/mocks/proxy.rb +156 -60
- data/lib/rspec/mocks/space.rb +52 -35
- data/lib/rspec/mocks/standalone.rb +1 -1
- data/lib/rspec/mocks/syntax.rb +26 -30
- data/lib/rspec/mocks/targets.rb +55 -28
- data/lib/rspec/mocks/test_double.rb +43 -7
- data/lib/rspec/mocks/verifying_double.rb +27 -33
- data/lib/rspec/mocks/{verifying_message_expecation.rb → verifying_message_expectation.rb} +11 -16
- data/lib/rspec/mocks/verifying_proxy.rb +77 -26
- data/lib/rspec/mocks/version.rb +1 -1
- data/lib/rspec/mocks.rb +8 -1
- data.tar.gz.sig +0 -0
- metadata +80 -43
- metadata.gz.sig +0 -0
@@ -11,11 +11,11 @@ module RSpec
|
|
11
11
|
|
12
12
|
# @overload double()
|
13
13
|
# @overload double(name)
|
14
|
-
# @param name [String/Symbol]
|
14
|
+
# @param name [String/Symbol] name or description to be used in failure messages
|
15
15
|
# @overload double(stubs)
|
16
16
|
# @param stubs (Hash) hash of message/return-value pairs
|
17
17
|
# @overload double(name, stubs)
|
18
|
-
# @param name [String/Symbol]
|
18
|
+
# @param name [String/Symbol] name or description to be used in failure messages
|
19
19
|
# @param stubs (Hash) hash of message/return-value pairs
|
20
20
|
# @return (Double)
|
21
21
|
#
|
@@ -24,7 +24,6 @@ module RSpec
|
|
24
24
|
# hash of message/return-value pairs.
|
25
25
|
#
|
26
26
|
# @example
|
27
|
-
#
|
28
27
|
# book = double("book", :title => "The RSpec Book")
|
29
28
|
# book.title #=> "The RSpec Book"
|
30
29
|
#
|
@@ -38,9 +37,16 @@ module RSpec
|
|
38
37
|
|
39
38
|
# @overload instance_double(doubled_class)
|
40
39
|
# @param doubled_class [String, Class]
|
40
|
+
# @overload instance_double(doubled_class, name)
|
41
|
+
# @param doubled_class [String, Class]
|
42
|
+
# @param name [String/Symbol] name or description to be used in failure messages
|
41
43
|
# @overload instance_double(doubled_class, stubs)
|
42
44
|
# @param doubled_class [String, Class]
|
43
45
|
# @param stubs [Hash] hash of message/return-value pairs
|
46
|
+
# @overload instance_double(doubled_class, name, stubs)
|
47
|
+
# @param doubled_class [String, Class]
|
48
|
+
# @param name [String/Symbol] name or description to be used in failure messages
|
49
|
+
# @param stubs [Hash] hash of message/return-value pairs
|
44
50
|
# @return InstanceVerifyingDouble
|
45
51
|
#
|
46
52
|
# Constructs a test double against a specific class. If the given class
|
@@ -54,9 +60,16 @@ module RSpec
|
|
54
60
|
|
55
61
|
# @overload class_double(doubled_class)
|
56
62
|
# @param doubled_class [String, Module]
|
63
|
+
# @overload class_double(doubled_class, name)
|
64
|
+
# @param doubled_class [String, Module]
|
65
|
+
# @param name [String/Symbol] name or description to be used in failure messages
|
57
66
|
# @overload class_double(doubled_class, stubs)
|
58
67
|
# @param doubled_class [String, Module]
|
59
68
|
# @param stubs [Hash] hash of message/return-value pairs
|
69
|
+
# @overload class_double(doubled_class, name, stubs)
|
70
|
+
# @param doubled_class [String, Module]
|
71
|
+
# @param name [String/Symbol] name or description to be used in failure messages
|
72
|
+
# @param stubs [Hash] hash of message/return-value pairs
|
60
73
|
# @return ClassVerifyingDouble
|
61
74
|
#
|
62
75
|
# Constructs a test double against a specific class. If the given class
|
@@ -70,9 +83,16 @@ module RSpec
|
|
70
83
|
|
71
84
|
# @overload object_double(object_or_name)
|
72
85
|
# @param object_or_name [String, Object]
|
86
|
+
# @overload object_double(object_or_name, name)
|
87
|
+
# @param object_or_name [String, Object]
|
88
|
+
# @param name [String/Symbol] name or description to be used in failure messages
|
73
89
|
# @overload object_double(object_or_name, stubs)
|
74
90
|
# @param object_or_name [String, Object]
|
75
91
|
# @param stubs [Hash] hash of message/return-value pairs
|
92
|
+
# @overload object_double(object_or_name, name, stubs)
|
93
|
+
# @param object_or_name [String, Object]
|
94
|
+
# @param name [String/Symbol] name or description to be used in failure messages
|
95
|
+
# @param stubs [Hash] hash of message/return-value pairs
|
76
96
|
# @return ObjectVerifyingDouble
|
77
97
|
#
|
78
98
|
# Constructs a test double against a specific object. Only the methods
|
@@ -84,11 +104,100 @@ module RSpec
|
|
84
104
|
ExampleMethods.declare_verifying_double(ObjectVerifyingDouble, ref, *args)
|
85
105
|
end
|
86
106
|
|
107
|
+
# @overload spy()
|
108
|
+
# @overload spy(name)
|
109
|
+
# @param name [String/Symbol] name or description to be used in failure messages
|
110
|
+
# @overload spy(stubs)
|
111
|
+
# @param stubs (Hash) hash of message/return-value pairs
|
112
|
+
# @overload spy(name, stubs)
|
113
|
+
# @param name [String/Symbol] name or description to be used in failure messages
|
114
|
+
# @param stubs (Hash) hash of message/return-value pairs
|
115
|
+
# @return (Double)
|
116
|
+
#
|
117
|
+
# Constructs a test double that is optimized for use with
|
118
|
+
# `have_received`. With a normal double one has to stub methods in order
|
119
|
+
# to be able to spy them. A spy automatically spies on all methods.
|
120
|
+
def spy(*args)
|
121
|
+
double(*args).as_null_object
|
122
|
+
end
|
123
|
+
|
124
|
+
# @overload instance_spy(doubled_class)
|
125
|
+
# @param doubled_class [String, Class]
|
126
|
+
# @overload instance_spy(doubled_class, name)
|
127
|
+
# @param doubled_class [String, Class]
|
128
|
+
# @param name [String/Symbol] name or description to be used in failure messages
|
129
|
+
# @overload instance_spy(doubled_class, stubs)
|
130
|
+
# @param doubled_class [String, Class]
|
131
|
+
# @param stubs [Hash] hash of message/return-value pairs
|
132
|
+
# @overload instance_spy(doubled_class, name, stubs)
|
133
|
+
# @param doubled_class [String, Class]
|
134
|
+
# @param name [String/Symbol] name or description to be used in failure messages
|
135
|
+
# @param stubs [Hash] hash of message/return-value pairs
|
136
|
+
# @return InstanceVerifyingDouble
|
137
|
+
#
|
138
|
+
# Constructs a test double that is optimized for use with `have_received`
|
139
|
+
# against a specific class. If the given class name has been loaded, only
|
140
|
+
# instance methods defined on the class are allowed to be stubbed. With
|
141
|
+
# a normal double one has to stub methods in order to be able to spy
|
142
|
+
# them. An instance_spy automatically spies on all instance methods to
|
143
|
+
# which the class responds.
|
144
|
+
def instance_spy(*args)
|
145
|
+
instance_double(*args).as_null_object
|
146
|
+
end
|
147
|
+
|
148
|
+
# @overload object_spy(object_or_name)
|
149
|
+
# @param object_or_name [String, Object]
|
150
|
+
# @overload object_spy(object_or_name, name)
|
151
|
+
# @param object_or_name [String, Class]
|
152
|
+
# @param name [String/Symbol] name or description to be used in failure messages
|
153
|
+
# @overload object_spy(object_or_name, stubs)
|
154
|
+
# @param object_or_name [String, Object]
|
155
|
+
# @param stubs [Hash] hash of message/return-value pairs
|
156
|
+
# @overload object_spy(object_or_name, name, stubs)
|
157
|
+
# @param object_or_name [String, Class]
|
158
|
+
# @param name [String/Symbol] name or description to be used in failure messages
|
159
|
+
# @param stubs [Hash] hash of message/return-value pairs
|
160
|
+
# @return ObjectVerifyingDouble
|
161
|
+
#
|
162
|
+
# Constructs a test double that is optimized for use with `have_received`
|
163
|
+
# against a specific object. Only instance methods defined on the object
|
164
|
+
# are allowed to be stubbed. With a normal double one has to stub
|
165
|
+
# methods in order to be able to spy them. An object_spy automatically
|
166
|
+
# spies on all methods to which the object responds.
|
167
|
+
def object_spy(*args)
|
168
|
+
object_double(*args).as_null_object
|
169
|
+
end
|
170
|
+
|
171
|
+
# @overload class_spy(doubled_class)
|
172
|
+
# @param doubled_class [String, Module]
|
173
|
+
# @overload class_spy(doubled_class, name)
|
174
|
+
# @param doubled_class [String, Class]
|
175
|
+
# @param name [String/Symbol] name or description to be used in failure messages
|
176
|
+
# @overload class_spy(doubled_class, stubs)
|
177
|
+
# @param doubled_class [String, Module]
|
178
|
+
# @param stubs [Hash] hash of message/return-value pairs
|
179
|
+
# @overload class_spy(doubled_class, name, stubs)
|
180
|
+
# @param doubled_class [String, Class]
|
181
|
+
# @param name [String/Symbol] name or description to be used in failure messages
|
182
|
+
# @param stubs [Hash] hash of message/return-value pairs
|
183
|
+
# @return ClassVerifyingDouble
|
184
|
+
#
|
185
|
+
# Constructs a test double that is optimized for use with `have_received`
|
186
|
+
# against a specific class. If the given class name has been loaded,
|
187
|
+
# only class methods defined on the class are allowed to be stubbed.
|
188
|
+
# With a normal double one has to stub methods in order to be able to spy
|
189
|
+
# them. An class_spy automatically spies on all class methods to which the
|
190
|
+
# class responds.
|
191
|
+
def class_spy(*args)
|
192
|
+
class_double(*args).as_null_object
|
193
|
+
end
|
194
|
+
|
87
195
|
# Disables warning messages about expectations being set on nil.
|
88
196
|
#
|
89
197
|
# By default warning messages are issued when expectations are set on
|
90
198
|
# nil. This is to prevent false-positives and to catch potential bugs
|
91
199
|
# early on.
|
200
|
+
# @deprecated Use {RSpec::Mocks::Configuration#allow_message_expectations_on_nil} instead.
|
92
201
|
def allow_message_expectations_on_nil
|
93
202
|
RSpec::Mocks.space.proxy_for(nil).warn_about_expectations = false
|
94
203
|
end
|
@@ -110,7 +219,6 @@ module RSpec
|
|
110
219
|
# @return [Object] the stubbed value of the constant
|
111
220
|
#
|
112
221
|
# @example
|
113
|
-
#
|
114
222
|
# stub_const("MyClass", Class.new) # => Replaces (or defines) MyClass with a new class object.
|
115
223
|
# stub_const("SomeModel::PER_PAGE", 5) # => Sets SomeModel::PER_PAGE to 5.
|
116
224
|
#
|
@@ -130,7 +238,7 @@ module RSpec
|
|
130
238
|
# stub_const("CardDeck", Class.new, :transfer_nested_constants => [:SUITS])
|
131
239
|
# CardDeck::SUITS # => our suits array
|
132
240
|
# CardDeck::NUM_CARDS # => uninitialized constant error
|
133
|
-
def stub_const(constant_name, value, options
|
241
|
+
def stub_const(constant_name, value, options={})
|
134
242
|
ConstantMutator.stub(constant_name, value, options)
|
135
243
|
end
|
136
244
|
|
@@ -144,15 +252,15 @@ module RSpec
|
|
144
252
|
# The current constant scoping at the point of call is not considered.
|
145
253
|
#
|
146
254
|
# @example
|
147
|
-
#
|
148
255
|
# hide_const("MyClass") # => MyClass is now an undefined constant
|
149
256
|
def hide_const(constant_name)
|
150
257
|
ConstantMutator.hide(constant_name)
|
151
258
|
end
|
152
259
|
|
153
260
|
# Verifies that the given object received the expected message during the
|
154
|
-
# course of the test.
|
155
|
-
#
|
261
|
+
# course of the test. On a spy objects or as null object doubles this
|
262
|
+
# works for any method, on other objects the method must have
|
263
|
+
# been stubbed beforehand in order for messages to be verified.
|
156
264
|
#
|
157
265
|
# Stubbing and verifying messages received in this way implements the
|
158
266
|
# Test Spy pattern.
|
@@ -161,23 +269,36 @@ module RSpec
|
|
161
269
|
# called.
|
162
270
|
#
|
163
271
|
# @example
|
164
|
-
#
|
165
272
|
# invitation = double('invitation', accept: true)
|
166
273
|
# user.accept_invitation(invitation)
|
167
274
|
# expect(invitation).to have_received(:accept)
|
168
275
|
#
|
169
276
|
# # You can also use most message expectations:
|
170
277
|
# expect(invitation).to have_received(:accept).with(mailer).once
|
278
|
+
#
|
279
|
+
# @note `have_received(...).with(...)` is unable to work properly when
|
280
|
+
# passed arguments are mutated after the spy records the received message.
|
171
281
|
def have_received(method_name, &block)
|
172
282
|
Matchers::HaveReceived.new(method_name, &block)
|
173
283
|
end
|
174
284
|
|
285
|
+
# Turns off the verifying of partial doubles for the duration of the
|
286
|
+
# block, this is useful in situations where methods are defined at run
|
287
|
+
# time and you wish to define stubs for them but not turn off partial
|
288
|
+
# doubles for the entire run suite. (e.g. view specs in rspec-rails).
|
289
|
+
def without_partial_double_verification
|
290
|
+
original_state = Mocks.configuration.temporarily_suppress_partial_double_verification
|
291
|
+
Mocks.configuration.temporarily_suppress_partial_double_verification = true
|
292
|
+
yield
|
293
|
+
ensure
|
294
|
+
Mocks.configuration.temporarily_suppress_partial_double_verification = original_state
|
295
|
+
end
|
296
|
+
|
175
297
|
# @method expect
|
176
298
|
# Used to wrap an object in preparation for setting a mock expectation
|
177
299
|
# on it.
|
178
300
|
#
|
179
301
|
# @example
|
180
|
-
#
|
181
302
|
# expect(obj).to receive(:foo).with(5).and_return(:return_value)
|
182
303
|
#
|
183
304
|
# @note This method is usually provided by rspec-expectations. However,
|
@@ -190,7 +311,6 @@ module RSpec
|
|
190
311
|
# on it.
|
191
312
|
#
|
192
313
|
# @example
|
193
|
-
#
|
194
314
|
# allow(dbl).to receive(:foo).with(5).and_return(:return_value)
|
195
315
|
#
|
196
316
|
# @note If you disable the `:expect` syntax this method will be undefined.
|
@@ -200,7 +320,6 @@ module RSpec
|
|
200
320
|
# on instances of it.
|
201
321
|
#
|
202
322
|
# @example
|
203
|
-
#
|
204
323
|
# expect_any_instance_of(MyClass).to receive(:foo)
|
205
324
|
#
|
206
325
|
# @note If you disable the `:expect` syntax this method will be undefined.
|
@@ -210,7 +329,6 @@ module RSpec
|
|
210
329
|
# on instances of it.
|
211
330
|
#
|
212
331
|
# @example
|
213
|
-
#
|
214
332
|
# allow_any_instance_of(MyClass).to receive(:foo)
|
215
333
|
#
|
216
334
|
# @note This is only available when you have enabled the `expect` syntax.
|
@@ -223,7 +341,6 @@ module RSpec
|
|
223
341
|
# times, and configure how the object should respond to the message.
|
224
342
|
#
|
225
343
|
# @example
|
226
|
-
#
|
227
344
|
# expect(obj).to receive(:hello).with("world").exactly(3).times
|
228
345
|
#
|
229
346
|
# @note If you disable the `:expect` syntax this method will be undefined.
|
@@ -236,7 +353,6 @@ module RSpec
|
|
236
353
|
# interface.
|
237
354
|
#
|
238
355
|
# @example
|
239
|
-
#
|
240
356
|
# allow(obj).to receive_messages(:speak => "Hello World")
|
241
357
|
# allow(obj).to receive_messages(:speak => "Hello", :meow => "Meow")
|
242
358
|
#
|
@@ -260,16 +376,15 @@ module RSpec
|
|
260
376
|
# implementation calls `foo.baz.bar`, the stub will not work.
|
261
377
|
#
|
262
378
|
# @example
|
379
|
+
# allow(double).to receive_message_chain("foo.bar") { :baz }
|
380
|
+
# allow(double).to receive_message_chain(:foo, :bar => :baz)
|
381
|
+
# allow(double).to receive_message_chain(:foo, :bar) { :baz }
|
263
382
|
#
|
264
|
-
#
|
265
|
-
#
|
266
|
-
# allow(double).to receive_message_chain(:foo, :bar) { :baz }
|
267
|
-
#
|
268
|
-
# # Given any of ^^ these three forms ^^:
|
269
|
-
# double.foo.bar # => :baz
|
383
|
+
# # Given any of ^^ these three forms ^^:
|
384
|
+
# double.foo.bar # => :baz
|
270
385
|
#
|
271
|
-
#
|
272
|
-
#
|
386
|
+
# # Common use in Rails/ActiveRecord:
|
387
|
+
# allow(Article).to receive_message_chain("recent.published") { [Article.new] }
|
273
388
|
#
|
274
389
|
# @note If you disable the `:expect` syntax this method will be undefined.
|
275
390
|
|
@@ -277,20 +392,28 @@ module RSpec
|
|
277
392
|
def self.included(klass)
|
278
393
|
klass.class_exec do
|
279
394
|
# This gets mixed in so that if `RSpec::Matchers` is included in
|
280
|
-
# `klass` later,
|
395
|
+
# `klass` later, its definition of `expect` will take precedence.
|
281
396
|
include ExpectHost unless method_defined?(:expect)
|
282
397
|
end
|
283
398
|
end
|
284
399
|
|
400
|
+
# @private
|
401
|
+
def self.extended(object)
|
402
|
+
# This gets extended in so that if `RSpec::Matchers` is included in
|
403
|
+
# `klass` later, its definition of `expect` will take precedence.
|
404
|
+
object.extend ExpectHost unless object.respond_to?(:expect)
|
405
|
+
end
|
406
|
+
|
285
407
|
# @private
|
286
408
|
def self.declare_verifying_double(type, ref, *args)
|
287
409
|
if RSpec::Mocks.configuration.verify_doubled_constant_names? &&
|
288
410
|
!ref.defined?
|
289
411
|
|
290
|
-
|
291
|
-
|
292
|
-
|
293
|
-
|
412
|
+
RSpec::Mocks.error_generator.raise_verifying_double_not_defined_error(ref)
|
413
|
+
end
|
414
|
+
|
415
|
+
RSpec::Mocks.configuration.verifying_double_callbacks.each do |block|
|
416
|
+
block.call(ref)
|
294
417
|
end
|
295
418
|
|
296
419
|
declare_double(type, ref, *args)
|
@@ -31,7 +31,6 @@ module RSpec
|
|
31
31
|
def stashed_method_name
|
32
32
|
"obfuscated_by_rspec_mocks__#{@method}"
|
33
33
|
end
|
34
|
-
private :stashed_method_name
|
35
34
|
|
36
35
|
# @private
|
37
36
|
def restore
|
@@ -53,8 +52,9 @@ module RSpec
|
|
53
52
|
|
54
53
|
# @private
|
55
54
|
def stash
|
56
|
-
return
|
55
|
+
return unless method_defined_directly_on_klass?
|
57
56
|
@original_method ||= ::RSpec::Support.method_handle_for(@object, @method)
|
57
|
+
@klass.__send__(:undef_method, @method)
|
58
58
|
end
|
59
59
|
|
60
60
|
# @private
|
@@ -80,9 +80,9 @@ module RSpec
|
|
80
80
|
yield
|
81
81
|
rescue TypeError
|
82
82
|
RSpec.warn_with(
|
83
|
-
"RSpec failed to properly restore a partial double (#{@object.inspect}) "
|
84
|
-
"to its original state due to a known bug in MRI 2.0.0-p195 & p247 "
|
85
|
-
"(https://bugs.ruby-lang.org/issues/8686). This object may remain "
|
83
|
+
"RSpec failed to properly restore a partial double (#{@object.inspect}) " \
|
84
|
+
"to its original state due to a known bug in MRI 2.0.0-p195 & p247 " \
|
85
|
+
"(https://bugs.ruby-lang.org/issues/8686). This object may remain " \
|
86
86
|
"screwed up for the rest of this process. Please upgrade to 2.0.0-p353 or above.",
|
87
87
|
:call_site => nil, :use_spec_location_as_call_site => true
|
88
88
|
)
|
@@ -102,7 +102,7 @@ module RSpec
|
|
102
102
|
end
|
103
103
|
|
104
104
|
# @private
|
105
|
-
def method_defined_on_klass?(klass
|
105
|
+
def method_defined_on_klass?(klass=@klass)
|
106
106
|
MethodReference.method_defined_at_any_visibility?(klass, @method)
|
107
107
|
end
|
108
108
|
|
@@ -128,6 +128,17 @@ module RSpec
|
|
128
128
|
# Hence, we verify that the owner actually has the method defined.
|
129
129
|
# If the given owner does not have the method defined, we assume
|
130
130
|
# that the method is actually owned by @klass.
|
131
|
+
#
|
132
|
+
# On 1.8, aliased methods can also report the wrong owner. Example:
|
133
|
+
# module M
|
134
|
+
# def a; end
|
135
|
+
# module_function :a
|
136
|
+
# alias b a
|
137
|
+
# module_function :b
|
138
|
+
# end
|
139
|
+
# The owner of M.b is the raw Module object, instead of the expected
|
140
|
+
# singleton class of the module
|
141
|
+
return true if RUBY_VERSION < '1.9' && owner == @object
|
131
142
|
owner == @klass || !(method_defined_on_klass?(owner))
|
132
143
|
end
|
133
144
|
end
|
@@ -3,9 +3,11 @@ module RSpec
|
|
3
3
|
module Matchers
|
4
4
|
# @private
|
5
5
|
class HaveReceived
|
6
|
-
|
7
|
-
|
8
|
-
|
6
|
+
include Matcher
|
7
|
+
|
8
|
+
COUNT_CONSTRAINTS = %w[exactly at_least at_most times time once twice thrice]
|
9
|
+
ARGS_CONSTRAINTS = %w[with]
|
10
|
+
CONSTRAINTS = COUNT_CONSTRAINTS + ARGS_CONSTRAINTS + %w[ordered]
|
9
11
|
|
10
12
|
def initialize(method_name, &block)
|
11
13
|
@method_name = method_name
|
@@ -14,7 +16,7 @@ module RSpec
|
|
14
16
|
@subject = nil
|
15
17
|
end
|
16
18
|
|
17
|
-
def
|
19
|
+
def matcher_name
|
18
20
|
"have_received"
|
19
21
|
end
|
20
22
|
|
@@ -36,15 +38,15 @@ module RSpec
|
|
36
38
|
end
|
37
39
|
|
38
40
|
def failure_message
|
39
|
-
|
41
|
+
capture_failure_message
|
40
42
|
end
|
41
43
|
|
42
44
|
def failure_message_when_negated
|
43
|
-
|
45
|
+
capture_failure_message
|
44
46
|
end
|
45
47
|
|
46
48
|
def description
|
47
|
-
expect.
|
49
|
+
(@expectation ||= expect).description_for("have received")
|
48
50
|
end
|
49
51
|
|
50
52
|
CONSTRAINTS.each do |expectation|
|
@@ -54,14 +56,40 @@ module RSpec
|
|
54
56
|
end
|
55
57
|
end
|
56
58
|
|
59
|
+
def setup_expectation(subject, &block)
|
60
|
+
notify_failure_message unless matches?(subject, &block)
|
61
|
+
end
|
62
|
+
|
63
|
+
def setup_negative_expectation(subject, &block)
|
64
|
+
notify_failure_message unless does_not_match?(subject, &block)
|
65
|
+
end
|
66
|
+
|
67
|
+
def setup_allowance(_subject, &_block)
|
68
|
+
disallow("allow", " as it would have no effect")
|
69
|
+
end
|
70
|
+
|
71
|
+
def setup_any_instance_allowance(_subject, &_block)
|
72
|
+
disallow("allow_any_instance_of")
|
73
|
+
end
|
74
|
+
|
75
|
+
def setup_any_instance_expectation(_subject, &_block)
|
76
|
+
disallow("expect_any_instance_of")
|
77
|
+
end
|
78
|
+
|
79
|
+
def setup_any_instance_negative_expectation(_subject, &_block)
|
80
|
+
disallow("expect_any_instance_of")
|
81
|
+
end
|
82
|
+
|
57
83
|
private
|
58
84
|
|
85
|
+
def disallow(type, reason="")
|
86
|
+
RSpec::Mocks.error_generator.raise_have_received_disallowed(type, reason)
|
87
|
+
end
|
88
|
+
|
59
89
|
def expect
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
expectation
|
64
|
-
end
|
90
|
+
expectation = mock_proxy.build_expectation(@method_name)
|
91
|
+
apply_constraints_to expectation
|
92
|
+
expectation
|
65
93
|
end
|
66
94
|
|
67
95
|
def apply_constraints_to(expectation)
|
@@ -71,23 +99,25 @@ module RSpec
|
|
71
99
|
end
|
72
100
|
|
73
101
|
def ensure_count_unconstrained
|
74
|
-
|
75
|
-
|
76
|
-
"can't use #{count_constraint} when negative"
|
77
|
-
end
|
102
|
+
return unless count_constraint
|
103
|
+
RSpec::Mocks.error_generator.raise_cant_constrain_count_for_negated_have_received_error(count_constraint)
|
78
104
|
end
|
79
105
|
|
80
106
|
def count_constraint
|
81
|
-
@constraints.map(&:first).
|
107
|
+
@constraints.map(&:first).find do |constraint|
|
82
108
|
COUNT_CONSTRAINTS.include?(constraint)
|
83
109
|
end
|
84
110
|
end
|
85
111
|
|
86
|
-
def
|
112
|
+
def capture_failure_message
|
113
|
+
RSpec::Support.with_failure_notifier(Proc.new { |err, _opt| return err.message }) do
|
114
|
+
notify_failure_message
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
def notify_failure_message
|
87
119
|
mock_proxy.check_for_unexpected_arguments(@expectation)
|
88
120
|
@expectation.generate_error
|
89
|
-
rescue RSpec::Mocks::MockExpectationError => error
|
90
|
-
error.message
|
91
121
|
end
|
92
122
|
|
93
123
|
def expected_messages_received_in_order?
|
@@ -5,19 +5,25 @@ module RSpec
|
|
5
5
|
module Matchers
|
6
6
|
# @private
|
7
7
|
class Receive
|
8
|
+
include Matcher
|
9
|
+
|
8
10
|
def initialize(message, block)
|
9
11
|
@message = message
|
10
12
|
@block = block
|
11
13
|
@recorded_customizations = []
|
12
14
|
end
|
13
15
|
|
14
|
-
def
|
16
|
+
def matcher_name
|
15
17
|
"receive"
|
16
18
|
end
|
17
19
|
|
20
|
+
def description
|
21
|
+
describable.description_for("receive")
|
22
|
+
end
|
23
|
+
|
18
24
|
def setup_expectation(subject, &block)
|
19
25
|
warn_if_any_instance("expect", subject)
|
20
|
-
setup_mock_proxy_method_substitute(subject, :add_message_expectation, block)
|
26
|
+
@describable = setup_mock_proxy_method_substitute(subject, :add_message_expectation, block)
|
21
27
|
end
|
22
28
|
alias matches? setup_expectation
|
23
29
|
|
@@ -49,26 +55,32 @@ module RSpec
|
|
49
55
|
setup_any_instance_method_substitute(subject, :stub, block)
|
50
56
|
end
|
51
57
|
|
58
|
+
own_methods = (instance_methods - superclass.instance_methods)
|
52
59
|
MessageExpectation.public_instance_methods(false).each do |method|
|
53
|
-
next if
|
60
|
+
next if own_methods.include?(method)
|
54
61
|
|
55
62
|
define_method(method) do |*args, &block|
|
56
63
|
@recorded_customizations << ExpectationCustomization.new(method, args, block)
|
57
64
|
self
|
58
65
|
end
|
66
|
+
ruby2_keywords(method) if respond_to?(:ruby2_keywords, true)
|
59
67
|
end
|
60
68
|
|
61
69
|
private
|
62
70
|
|
71
|
+
def describable
|
72
|
+
@describable ||= DefaultDescribable.new(@message)
|
73
|
+
end
|
74
|
+
|
63
75
|
def warn_if_any_instance(expression, subject)
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
)
|
71
|
-
|
76
|
+
return unless AnyInstance::Proxy === subject
|
77
|
+
|
78
|
+
RSpec.warning(
|
79
|
+
"`#{expression}(#{subject.klass}.any_instance).to` " \
|
80
|
+
"is probably not what you meant, it does not operate on " \
|
81
|
+
"any instance of `#{subject.klass}`. " \
|
82
|
+
"Use `#{expression}_any_instance_of(#{subject.klass}).to` instead."
|
83
|
+
)
|
72
84
|
end
|
73
85
|
|
74
86
|
def setup_mock_proxy_method_substitute(subject, method, block)
|
@@ -100,6 +112,22 @@ module RSpec
|
|
100
112
|
last.block ||= block
|
101
113
|
nil
|
102
114
|
end
|
115
|
+
|
116
|
+
# MessageExpectation objects are able to describe themselves in detail.
|
117
|
+
# We use this as a fall back when a MessageExpectation is not available.
|
118
|
+
# @private
|
119
|
+
class DefaultDescribable
|
120
|
+
def initialize(message)
|
121
|
+
@message = message
|
122
|
+
end
|
123
|
+
|
124
|
+
# This is much simpler for the `any_instance` case than what the
|
125
|
+
# user may want, but I'm not up for putting a bunch of effort
|
126
|
+
# into full descriptions for `any_instance` expectations at this point :(.
|
127
|
+
def description_for(verb)
|
128
|
+
"#{verb} #{@message}"
|
129
|
+
end
|
130
|
+
end
|
103
131
|
end
|
104
132
|
end
|
105
133
|
end
|
@@ -5,23 +5,29 @@ module RSpec
|
|
5
5
|
module Matchers
|
6
6
|
# @private
|
7
7
|
class ReceiveMessageChain
|
8
|
+
include Matcher
|
9
|
+
|
8
10
|
def initialize(chain, &block)
|
9
11
|
@chain = chain
|
10
12
|
@block = block
|
11
13
|
@recorded_customizations = []
|
12
14
|
end
|
13
15
|
|
14
|
-
[:with, :and_return, :and_throw, :and_raise, :and_yield, :and_call_original].each do |msg|
|
16
|
+
[:with, :and_return, :and_invoke, :and_throw, :and_raise, :and_yield, :and_call_original].each do |msg|
|
15
17
|
define_method(msg) do |*args, &block|
|
16
18
|
@recorded_customizations << ExpectationCustomization.new(msg, args, block)
|
17
19
|
self
|
18
20
|
end
|
19
21
|
end
|
20
22
|
|
21
|
-
def
|
23
|
+
def matcher_name
|
22
24
|
"receive_message_chain"
|
23
25
|
end
|
24
26
|
|
27
|
+
def description
|
28
|
+
"receive message chain #{formatted_chain}"
|
29
|
+
end
|
30
|
+
|
25
31
|
def setup_allowance(subject, &block)
|
26
32
|
chain = StubChain.stub_chain_on(subject, *@chain, &(@block || block))
|
27
33
|
replay_customizations(chain)
|
@@ -44,11 +50,10 @@ module RSpec
|
|
44
50
|
replay_customizations(chain)
|
45
51
|
end
|
46
52
|
|
47
|
-
def setup_negative_expectation(*
|
48
|
-
raise NegationUnsupportedError
|
49
|
-
|
50
|
-
|
51
|
-
)
|
53
|
+
def setup_negative_expectation(*_args)
|
54
|
+
raise NegationUnsupportedError,
|
55
|
+
"`expect(...).not_to receive_message_chain` is not supported " \
|
56
|
+
"since it doesn't really make sense. What would it even mean?"
|
52
57
|
end
|
53
58
|
|
54
59
|
alias matches? setup_expectation
|
@@ -61,6 +66,16 @@ module RSpec
|
|
61
66
|
customization.playback_onto(chain)
|
62
67
|
end
|
63
68
|
end
|
69
|
+
|
70
|
+
def formatted_chain
|
71
|
+
@formatted_chain ||= @chain.map do |part|
|
72
|
+
if Hash === part
|
73
|
+
part.keys.first.to_s
|
74
|
+
else
|
75
|
+
part.to_s
|
76
|
+
end
|
77
|
+
end.join(".")
|
78
|
+
end
|
64
79
|
end
|
65
80
|
end
|
66
81
|
end
|