rspec-mocks 3.0.4 → 3.12.6
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 +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
|