rspec-mocks-diag 3.8.1.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (48) hide show
  1. checksums.yaml +7 -0
  2. data/.document +5 -0
  3. data/.yardopts +6 -0
  4. data/Changelog.md +1108 -0
  5. data/LICENSE.md +25 -0
  6. data/README.md +460 -0
  7. data/lib/rspec/mocks.rb +130 -0
  8. data/lib/rspec/mocks/any_instance.rb +11 -0
  9. data/lib/rspec/mocks/any_instance/chain.rb +110 -0
  10. data/lib/rspec/mocks/any_instance/error_generator.rb +31 -0
  11. data/lib/rspec/mocks/any_instance/expect_chain_chain.rb +31 -0
  12. data/lib/rspec/mocks/any_instance/expectation_chain.rb +50 -0
  13. data/lib/rspec/mocks/any_instance/message_chains.rb +83 -0
  14. data/lib/rspec/mocks/any_instance/proxy.rb +116 -0
  15. data/lib/rspec/mocks/any_instance/recorder.rb +289 -0
  16. data/lib/rspec/mocks/any_instance/stub_chain.rb +51 -0
  17. data/lib/rspec/mocks/any_instance/stub_chain_chain.rb +23 -0
  18. data/lib/rspec/mocks/argument_list_matcher.rb +100 -0
  19. data/lib/rspec/mocks/argument_matchers.rb +320 -0
  20. data/lib/rspec/mocks/configuration.rb +212 -0
  21. data/lib/rspec/mocks/error_generator.rb +378 -0
  22. data/lib/rspec/mocks/example_methods.rb +434 -0
  23. data/lib/rspec/mocks/instance_method_stasher.rb +146 -0
  24. data/lib/rspec/mocks/marshal_extension.rb +41 -0
  25. data/lib/rspec/mocks/matchers/expectation_customization.rb +20 -0
  26. data/lib/rspec/mocks/matchers/have_received.rb +134 -0
  27. data/lib/rspec/mocks/matchers/receive.rb +132 -0
  28. data/lib/rspec/mocks/matchers/receive_message_chain.rb +82 -0
  29. data/lib/rspec/mocks/matchers/receive_messages.rb +77 -0
  30. data/lib/rspec/mocks/message_chain.rb +87 -0
  31. data/lib/rspec/mocks/message_expectation.rb +748 -0
  32. data/lib/rspec/mocks/method_double.rb +287 -0
  33. data/lib/rspec/mocks/method_reference.rb +202 -0
  34. data/lib/rspec/mocks/minitest_integration.rb +68 -0
  35. data/lib/rspec/mocks/mutate_const.rb +339 -0
  36. data/lib/rspec/mocks/object_reference.rb +149 -0
  37. data/lib/rspec/mocks/order_group.rb +81 -0
  38. data/lib/rspec/mocks/proxy.rb +485 -0
  39. data/lib/rspec/mocks/space.rb +238 -0
  40. data/lib/rspec/mocks/standalone.rb +3 -0
  41. data/lib/rspec/mocks/syntax.rb +325 -0
  42. data/lib/rspec/mocks/targets.rb +124 -0
  43. data/lib/rspec/mocks/test_double.rb +171 -0
  44. data/lib/rspec/mocks/verifying_double.rb +129 -0
  45. data/lib/rspec/mocks/verifying_message_expectation.rb +54 -0
  46. data/lib/rspec/mocks/verifying_proxy.rb +220 -0
  47. data/lib/rspec/mocks/version.rb +9 -0
  48. metadata +186 -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