rspec-mocks 3.8.1

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.
Files changed (51) hide show
  1. checksums.yaml +7 -0
  2. checksums.yaml.gz.sig +0 -0
  3. data.tar.gz.sig +3 -0
  4. data/.document +5 -0
  5. data/.yardopts +6 -0
  6. data/Changelog.md +1108 -0
  7. data/LICENSE.md +25 -0
  8. data/README.md +460 -0
  9. data/lib/rspec/mocks.rb +130 -0
  10. data/lib/rspec/mocks/any_instance.rb +11 -0
  11. data/lib/rspec/mocks/any_instance/chain.rb +110 -0
  12. data/lib/rspec/mocks/any_instance/error_generator.rb +31 -0
  13. data/lib/rspec/mocks/any_instance/expect_chain_chain.rb +31 -0
  14. data/lib/rspec/mocks/any_instance/expectation_chain.rb +50 -0
  15. data/lib/rspec/mocks/any_instance/message_chains.rb +83 -0
  16. data/lib/rspec/mocks/any_instance/proxy.rb +116 -0
  17. data/lib/rspec/mocks/any_instance/recorder.rb +289 -0
  18. data/lib/rspec/mocks/any_instance/stub_chain.rb +51 -0
  19. data/lib/rspec/mocks/any_instance/stub_chain_chain.rb +23 -0
  20. data/lib/rspec/mocks/argument_list_matcher.rb +100 -0
  21. data/lib/rspec/mocks/argument_matchers.rb +320 -0
  22. data/lib/rspec/mocks/configuration.rb +212 -0
  23. data/lib/rspec/mocks/error_generator.rb +369 -0
  24. data/lib/rspec/mocks/example_methods.rb +434 -0
  25. data/lib/rspec/mocks/instance_method_stasher.rb +146 -0
  26. data/lib/rspec/mocks/marshal_extension.rb +41 -0
  27. data/lib/rspec/mocks/matchers/expectation_customization.rb +20 -0
  28. data/lib/rspec/mocks/matchers/have_received.rb +134 -0
  29. data/lib/rspec/mocks/matchers/receive.rb +132 -0
  30. data/lib/rspec/mocks/matchers/receive_message_chain.rb +82 -0
  31. data/lib/rspec/mocks/matchers/receive_messages.rb +77 -0
  32. data/lib/rspec/mocks/message_chain.rb +87 -0
  33. data/lib/rspec/mocks/message_expectation.rb +741 -0
  34. data/lib/rspec/mocks/method_double.rb +287 -0
  35. data/lib/rspec/mocks/method_reference.rb +202 -0
  36. data/lib/rspec/mocks/minitest_integration.rb +68 -0
  37. data/lib/rspec/mocks/mutate_const.rb +339 -0
  38. data/lib/rspec/mocks/object_reference.rb +149 -0
  39. data/lib/rspec/mocks/order_group.rb +81 -0
  40. data/lib/rspec/mocks/proxy.rb +485 -0
  41. data/lib/rspec/mocks/space.rb +238 -0
  42. data/lib/rspec/mocks/standalone.rb +3 -0
  43. data/lib/rspec/mocks/syntax.rb +325 -0
  44. data/lib/rspec/mocks/targets.rb +124 -0
  45. data/lib/rspec/mocks/test_double.rb +171 -0
  46. data/lib/rspec/mocks/verifying_double.rb +129 -0
  47. data/lib/rspec/mocks/verifying_message_expectation.rb +54 -0
  48. data/lib/rspec/mocks/verifying_proxy.rb +220 -0
  49. data/lib/rspec/mocks/version.rb +9 -0
  50. metadata +221 -0
  51. metadata.gz.sig +0 -0
@@ -0,0 +1,81 @@
1
+ module RSpec
2
+ module Mocks
3
+ # @private
4
+ class OrderGroup
5
+ def initialize
6
+ @expectations = []
7
+ @invocation_order = []
8
+ @index = 0
9
+ end
10
+
11
+ # @private
12
+ def register(expectation)
13
+ @expectations << expectation
14
+ end
15
+
16
+ def invoked(message)
17
+ @invocation_order << message
18
+ end
19
+
20
+ # @private
21
+ def ready_for?(expectation)
22
+ remaining_expectations.find(&:ordered?) == expectation
23
+ end
24
+
25
+ # @private
26
+ def consume
27
+ remaining_expectations.each_with_index do |expectation, index|
28
+ next unless expectation.ordered?
29
+
30
+ @index += index + 1
31
+ return expectation
32
+ end
33
+ nil
34
+ end
35
+
36
+ # @private
37
+ def handle_order_constraint(expectation)
38
+ return unless expectation.ordered? && remaining_expectations.include?(expectation)
39
+ return consume if ready_for?(expectation)
40
+ expectation.raise_out_of_order_error
41
+ end
42
+
43
+ def verify_invocation_order(expectation)
44
+ expectation.raise_out_of_order_error unless expectations_invoked_in_order?
45
+ true
46
+ end
47
+
48
+ def clear
49
+ @index = 0
50
+ @invocation_order.clear
51
+ @expectations.clear
52
+ end
53
+
54
+ def empty?
55
+ @expectations.empty?
56
+ end
57
+
58
+ private
59
+
60
+ def remaining_expectations
61
+ @expectations[@index..-1] || []
62
+ end
63
+
64
+ def expectations_invoked_in_order?
65
+ invoked_expectations == expected_invocations
66
+ end
67
+
68
+ def invoked_expectations
69
+ @expectations.select { |e| e.ordered? && @invocation_order.include?(e) }
70
+ end
71
+
72
+ def expected_invocations
73
+ @invocation_order.map { |invocation| expectation_for(invocation) }.compact
74
+ end
75
+
76
+ def expectation_for(message)
77
+ @expectations.find { |e| message == e }
78
+ end
79
+ end
80
+ end
81
+ end
@@ -0,0 +1,485 @@
1
+ module RSpec
2
+ module Mocks
3
+ # @private
4
+ class Proxy
5
+ # @private
6
+ SpecificMessage = Struct.new(:object, :message, :args) do
7
+ def ==(expectation)
8
+ expectation.orig_object == object && expectation.matches?(message, *args)
9
+ end
10
+ end
11
+
12
+ # @private
13
+ def ensure_implemented(*_args)
14
+ # noop for basic proxies, see VerifyingProxy for behaviour.
15
+ end
16
+
17
+ # @private
18
+ def initialize(object, order_group, options={})
19
+ @object = object
20
+ @order_group = order_group
21
+ @error_generator = ErrorGenerator.new(object)
22
+ @messages_received = []
23
+ @options = options
24
+ @null_object = false
25
+ @method_doubles = Hash.new { |h, k| h[k] = MethodDouble.new(@object, k, self) }
26
+ end
27
+
28
+ # @private
29
+ attr_reader :object
30
+
31
+ # @private
32
+ def null_object?
33
+ @null_object
34
+ end
35
+
36
+ # @private
37
+ # Tells the object to ignore any messages that aren't explicitly set as
38
+ # stubs or message expectations.
39
+ def as_null_object
40
+ @null_object = true
41
+ @object
42
+ end
43
+
44
+ # @private
45
+ def original_method_handle_for(_message)
46
+ nil
47
+ end
48
+
49
+ DEFAULT_MESSAGE_EXPECTATION_OPTS = {}.freeze
50
+
51
+ # @private
52
+ def add_message_expectation(method_name, opts=DEFAULT_MESSAGE_EXPECTATION_OPTS, &block)
53
+ location = opts.fetch(:expected_from) { CallerFilter.first_non_rspec_line }
54
+ meth_double = method_double_for(method_name)
55
+
56
+ if null_object? && !block
57
+ meth_double.add_default_stub(@error_generator, @order_group, location, opts) do
58
+ @object
59
+ end
60
+ end
61
+
62
+ meth_double.add_expectation @error_generator, @order_group, location, opts, &block
63
+ end
64
+
65
+ # @private
66
+ def add_simple_expectation(method_name, response, location)
67
+ method_double_for(method_name).add_simple_expectation method_name, response, @error_generator, location
68
+ end
69
+
70
+ # @private
71
+ def build_expectation(method_name)
72
+ meth_double = method_double_for(method_name)
73
+
74
+ meth_double.build_expectation(
75
+ @error_generator,
76
+ @order_group
77
+ )
78
+ end
79
+
80
+ # @private
81
+ def replay_received_message_on(expectation, &block)
82
+ expected_method_name = expectation.message
83
+ meth_double = method_double_for(expected_method_name)
84
+
85
+ if meth_double.expectations.any?
86
+ @error_generator.raise_expectation_on_mocked_method(expected_method_name)
87
+ end
88
+
89
+ unless null_object? || meth_double.stubs.any?
90
+ @error_generator.raise_expectation_on_unstubbed_method(expected_method_name)
91
+ end
92
+
93
+ @messages_received.each do |(actual_method_name, args, received_block)|
94
+ next unless expectation.matches?(actual_method_name, *args)
95
+
96
+ expectation.safe_invoke(nil)
97
+ block.call(*args, &received_block) if block
98
+ end
99
+ end
100
+
101
+ # @private
102
+ def check_for_unexpected_arguments(expectation)
103
+ return if @messages_received.empty?
104
+
105
+ return if @messages_received.any? { |method_name, args, _| expectation.matches?(method_name, *args) }
106
+
107
+ name_but_not_args, others = @messages_received.partition do |(method_name, args, _)|
108
+ expectation.matches_name_but_not_args(method_name, *args)
109
+ end
110
+
111
+ return if name_but_not_args.empty? && !others.empty?
112
+
113
+ expectation.raise_unexpected_message_args_error(name_but_not_args.map { |args| args[1] })
114
+ end
115
+
116
+ # @private
117
+ def add_stub(method_name, opts={}, &implementation)
118
+ location = opts.fetch(:expected_from) { CallerFilter.first_non_rspec_line }
119
+ method_double_for(method_name).add_stub @error_generator, @order_group, location, opts, &implementation
120
+ end
121
+
122
+ # @private
123
+ def add_simple_stub(method_name, response)
124
+ method_double_for(method_name).add_simple_stub method_name, response
125
+ end
126
+
127
+ # @private
128
+ def remove_stub(method_name)
129
+ method_double_for(method_name).remove_stub
130
+ end
131
+
132
+ # @private
133
+ def remove_stub_if_present(method_name)
134
+ method_double_for(method_name).remove_stub_if_present
135
+ end
136
+
137
+ # @private
138
+ def verify
139
+ @method_doubles.each_value { |d| d.verify }
140
+ end
141
+
142
+ # @private
143
+ def reset
144
+ @messages_received.clear
145
+ end
146
+
147
+ # @private
148
+ def received_message?(method_name, *args, &block)
149
+ @messages_received.any? { |array| array == [method_name, args, block] }
150
+ end
151
+
152
+ # @private
153
+ def messages_arg_list
154
+ @messages_received.map { |_, args, _| args }
155
+ end
156
+
157
+ # @private
158
+ def has_negative_expectation?(message)
159
+ method_double_for(message).expectations.find { |expectation| expectation.negative_expectation_for?(message) }
160
+ end
161
+
162
+ # @private
163
+ def record_message_received(message, *args, &block)
164
+ @order_group.invoked SpecificMessage.new(object, message, args)
165
+ @messages_received << [message, args, block]
166
+ end
167
+
168
+ # @private
169
+ def message_received(message, *args, &block)
170
+ record_message_received message, *args, &block
171
+
172
+ expectation = find_matching_expectation(message, *args)
173
+ stub = find_matching_method_stub(message, *args)
174
+
175
+ if (stub && expectation && expectation.called_max_times?) || (stub && !expectation)
176
+ expectation.increase_actual_received_count! if expectation && expectation.actual_received_count_matters?
177
+ if (expectation = find_almost_matching_expectation(message, *args))
178
+ expectation.advise(*args) unless expectation.expected_messages_received?
179
+ end
180
+ stub.invoke(nil, *args, &block)
181
+ elsif expectation
182
+ expectation.unadvise(messages_arg_list)
183
+ expectation.invoke(stub, *args, &block)
184
+ elsif (expectation = find_almost_matching_expectation(message, *args))
185
+ expectation.advise(*args) if null_object? unless expectation.expected_messages_received?
186
+
187
+ if null_object? || !has_negative_expectation?(message)
188
+ expectation.raise_unexpected_message_args_error([args])
189
+ end
190
+ elsif (stub = find_almost_matching_stub(message, *args))
191
+ stub.advise(*args)
192
+ raise_missing_default_stub_error(stub, [args])
193
+ elsif Class === @object
194
+ @object.superclass.__send__(message, *args, &block)
195
+ else
196
+ @object.__send__(:method_missing, message, *args, &block)
197
+ end
198
+ end
199
+
200
+ # @private
201
+ def raise_unexpected_message_error(method_name, args)
202
+ @error_generator.raise_unexpected_message_error method_name, args
203
+ end
204
+
205
+ # @private
206
+ def raise_missing_default_stub_error(expectation, args_for_multiple_calls)
207
+ @error_generator.raise_missing_default_stub_error(expectation, args_for_multiple_calls)
208
+ end
209
+
210
+ # @private
211
+ def visibility_for(_method_name)
212
+ # This is the default (for test doubles). Subclasses override this.
213
+ :public
214
+ end
215
+
216
+ if Support::RubyFeatures.module_prepends_supported?
217
+ def self.prepended_modules_of(klass)
218
+ ancestors = klass.ancestors
219
+
220
+ # `|| 0` is necessary for Ruby 2.0, where the singleton class
221
+ # is only in the ancestor list when there are prepended modules.
222
+ singleton_index = ancestors.index(klass) || 0
223
+
224
+ ancestors[0, singleton_index]
225
+ end
226
+
227
+ def prepended_modules_of_singleton_class
228
+ @prepended_modules_of_singleton_class ||= RSpec::Mocks::Proxy.prepended_modules_of(@object.singleton_class)
229
+ end
230
+ end
231
+
232
+ # @private
233
+ def method_double_if_exists_for_message(message)
234
+ method_double_for(message) if @method_doubles.key?(message.to_sym)
235
+ end
236
+
237
+ private
238
+
239
+ def method_double_for(message)
240
+ @method_doubles[message.to_sym]
241
+ end
242
+
243
+ def find_matching_expectation(method_name, *args)
244
+ find_best_matching_expectation_for(method_name) do |expectation|
245
+ expectation.matches?(method_name, *args)
246
+ end
247
+ end
248
+
249
+ def find_almost_matching_expectation(method_name, *args)
250
+ find_best_matching_expectation_for(method_name) do |expectation|
251
+ expectation.matches_name_but_not_args(method_name, *args)
252
+ end
253
+ end
254
+
255
+ def find_best_matching_expectation_for(method_name)
256
+ first_match = nil
257
+
258
+ method_double_for(method_name).expectations.each do |expectation|
259
+ next unless yield expectation
260
+ return expectation unless expectation.called_max_times?
261
+ first_match ||= expectation
262
+ end
263
+
264
+ first_match
265
+ end
266
+
267
+ def find_matching_method_stub(method_name, *args)
268
+ method_double_for(method_name).stubs.find { |stub| stub.matches?(method_name, *args) }
269
+ end
270
+
271
+ def find_almost_matching_stub(method_name, *args)
272
+ method_double_for(method_name).stubs.find { |stub| stub.matches_name_but_not_args(method_name, *args) }
273
+ end
274
+ end
275
+
276
+ # @private
277
+ class TestDoubleProxy < Proxy
278
+ def reset
279
+ @method_doubles.clear
280
+ object.__disallow_further_usage!
281
+ super
282
+ end
283
+ end
284
+
285
+ # @private
286
+ class PartialDoubleProxy < Proxy
287
+ def original_method_handle_for(message)
288
+ if any_instance_class_recorder_observing_method?(@object.class, message)
289
+ message = ::RSpec::Mocks.space.
290
+ any_instance_recorder_for(@object.class).
291
+ build_alias_method_name(message)
292
+ end
293
+
294
+ ::RSpec::Support.method_handle_for(@object, message)
295
+ rescue NameError
296
+ nil
297
+ end
298
+
299
+ # @private
300
+ def add_simple_expectation(method_name, response, location)
301
+ method_double_for(method_name).configure_method
302
+ super
303
+ end
304
+
305
+ # @private
306
+ def add_simple_stub(method_name, response)
307
+ method_double_for(method_name).configure_method
308
+ super
309
+ end
310
+
311
+ # @private
312
+ def visibility_for(method_name)
313
+ # We fall back to :public because by default we allow undefined methods
314
+ # to be stubbed, and when we do so, we make them public.
315
+ MethodReference.method_visibility_for(@object, method_name) || :public
316
+ end
317
+
318
+ def reset
319
+ @method_doubles.each_value { |d| d.reset }
320
+ super
321
+ end
322
+
323
+ def message_received(message, *args, &block)
324
+ RSpec::Mocks.space.any_instance_recorders_from_ancestry_of(object).each do |subscriber|
325
+ subscriber.notify_received_message(object, message, args, block)
326
+ end
327
+ super
328
+ end
329
+
330
+ private
331
+
332
+ def any_instance_class_recorder_observing_method?(klass, method_name)
333
+ only_return_existing = true
334
+ recorder = ::RSpec::Mocks.space.any_instance_recorder_for(klass, only_return_existing)
335
+ return true if recorder && recorder.already_observing?(method_name)
336
+
337
+ superklass = klass.superclass
338
+ return false if superklass.nil?
339
+ any_instance_class_recorder_observing_method?(superklass, method_name)
340
+ end
341
+ end
342
+
343
+ # @private
344
+ # When we mock or stub a method on a class, we have to treat it a bit different,
345
+ # because normally singleton method definitions only affect the object on which
346
+ # they are defined, but on classes they affect subclasses, too. As a result,
347
+ # we need some special handling to get the original method.
348
+ module PartialClassDoubleProxyMethods
349
+ def initialize(source_space, *args)
350
+ @source_space = source_space
351
+ super(*args)
352
+ end
353
+
354
+ # Consider this situation:
355
+ #
356
+ # class A; end
357
+ # class B < A; end
358
+ #
359
+ # allow(A).to receive(:new)
360
+ # expect(B).to receive(:new).and_call_original
361
+ #
362
+ # When getting the original definition for `B.new`, we cannot rely purely on
363
+ # using `B.method(:new)` before our redefinition is defined on `B`, because
364
+ # `B.method(:new)` will return a method that will execute the stubbed version
365
+ # of the method on `A` since singleton methods on classes are in the lookup
366
+ # hierarchy.
367
+ #
368
+ # To do it properly, we need to find the original definition of `new` from `A`
369
+ # from _before_ `A` was stubbed, and we need to rebind it to `B` so that it will
370
+ # run with the proper `self`.
371
+ #
372
+ # That's what this method (together with `original_unbound_method_handle_from_ancestor_for`)
373
+ # does.
374
+ def original_method_handle_for(message)
375
+ unbound_method = superclass_proxy &&
376
+ superclass_proxy.original_unbound_method_handle_from_ancestor_for(message.to_sym)
377
+
378
+ return super unless unbound_method
379
+ unbound_method.bind(object)
380
+ # :nocov:
381
+ rescue TypeError
382
+ if RUBY_VERSION == '1.8.7'
383
+ # In MRI 1.8.7, a singleton method on a class cannot be rebound to its subclass
384
+ if unbound_method && unbound_method.owner.ancestors.first != unbound_method.owner
385
+ # This is a singleton method; we can't do anything with it
386
+ # But we can work around this using a different implementation
387
+ double = method_double_from_ancestor_for(message)
388
+ return object.method(double.method_stasher.stashed_method_name)
389
+ end
390
+ end
391
+ raise
392
+ # :nocov:
393
+ end
394
+
395
+ protected
396
+
397
+ def original_unbound_method_handle_from_ancestor_for(message)
398
+ double = method_double_from_ancestor_for(message)
399
+ double && double.original_method.unbind
400
+ end
401
+
402
+ def method_double_from_ancestor_for(message)
403
+ @method_doubles.fetch(message) do
404
+ # The fact that there is no method double for this message indicates
405
+ # that it has not been redefined by rspec-mocks. We need to continue
406
+ # looking up the ancestor chain.
407
+ return superclass_proxy &&
408
+ superclass_proxy.method_double_from_ancestor_for(message)
409
+ end
410
+ end
411
+
412
+ def superclass_proxy
413
+ return @superclass_proxy if defined?(@superclass_proxy)
414
+
415
+ if (superclass = object.superclass)
416
+ @superclass_proxy = @source_space.superclass_proxy_for(superclass)
417
+ else
418
+ @superclass_proxy = nil
419
+ end
420
+ end
421
+ end
422
+
423
+ # @private
424
+ class PartialClassDoubleProxy < PartialDoubleProxy
425
+ include PartialClassDoubleProxyMethods
426
+ end
427
+
428
+ # @private
429
+ class ProxyForNil < PartialDoubleProxy
430
+ def initialize(order_group)
431
+ set_expectation_behavior
432
+ super(nil, order_group)
433
+ end
434
+
435
+ attr_accessor :disallow_expectations
436
+ attr_accessor :warn_about_expectations
437
+
438
+ def add_message_expectation(method_name, opts={}, &block)
439
+ warn_or_raise!(method_name)
440
+ super
441
+ end
442
+
443
+ def add_stub(method_name, opts={}, &implementation)
444
+ warn_or_raise!(method_name)
445
+ super
446
+ end
447
+
448
+ private
449
+
450
+ def set_expectation_behavior
451
+ case RSpec::Mocks.configuration.allow_message_expectations_on_nil
452
+ when false
453
+ @warn_about_expectations = false
454
+ @disallow_expectations = true
455
+ when true
456
+ @warn_about_expectations = false
457
+ @disallow_expectations = false
458
+ else
459
+ @warn_about_expectations = true
460
+ @disallow_expectations = false
461
+ end
462
+ end
463
+
464
+ def warn_or_raise!(method_name)
465
+ # This method intentionally swallows the message when
466
+ # neither disallow_expectations nor warn_about_expectations
467
+ # are set to true.
468
+ if disallow_expectations
469
+ raise_error(method_name)
470
+ elsif warn_about_expectations
471
+ warn(method_name)
472
+ end
473
+ end
474
+
475
+ def warn(method_name)
476
+ warning_msg = @error_generator.expectation_on_nil_message(method_name)
477
+ RSpec.warning(warning_msg)
478
+ end
479
+
480
+ def raise_error(method_name)
481
+ @error_generator.raise_expectation_on_nil_error(method_name)
482
+ end
483
+ end
484
+ end
485
+ end