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,378 @@
1
+ RSpec::Support.require_rspec_support "object_formatter"
2
+
3
+ module RSpec
4
+ module Mocks
5
+ # Raised when a message expectation is not satisfied.
6
+ MockExpectationError = Class.new(Exception)
7
+
8
+ # Raised when a test double is used after it has been torn
9
+ # down (typically at the end of an rspec-core example).
10
+ ExpiredTestDoubleError = Class.new(MockExpectationError)
11
+
12
+ # Raised when doubles or partial doubles are used outside of the per-test lifecycle.
13
+ OutsideOfExampleError = Class.new(StandardError)
14
+
15
+ # Raised when an expectation customization method (e.g. `with`,
16
+ # `and_return`) is called on a message expectation which has already been
17
+ # invoked.
18
+ MockExpectationAlreadyInvokedError = Class.new(Exception)
19
+
20
+ # Raised for situations that RSpec cannot support due to mutations made
21
+ # externally on arguments that RSpec is holding onto to use for later
22
+ # comparisons.
23
+ #
24
+ # @deprecated We no longer raise this error but the constant remains until
25
+ # RSpec 4 for SemVer reasons.
26
+ CannotSupportArgMutationsError = Class.new(StandardError)
27
+
28
+ # @private
29
+ UnsupportedMatcherError = Class.new(StandardError)
30
+ # @private
31
+ NegationUnsupportedError = Class.new(StandardError)
32
+ # @private
33
+ VerifyingDoubleNotDefinedError = Class.new(StandardError)
34
+
35
+ # @private
36
+ class ErrorGenerator
37
+ attr_writer :opts
38
+
39
+ def initialize(target=nil)
40
+ @target = target
41
+ end
42
+
43
+ # @private
44
+ def opts
45
+ @opts ||= {}
46
+ end
47
+
48
+ # @private
49
+ def raise_unexpected_message_error(message, args)
50
+ __raise "#{intro} received unexpected message :#{message} with #{format_args(args)}"
51
+ end
52
+
53
+ # @private
54
+ def raise_unexpected_message_args_error(expectation, args_for_multiple_calls, source_id=nil)
55
+ __raise error_message(expectation, args_for_multiple_calls), nil, source_id
56
+ end
57
+
58
+ # @private
59
+ def raise_missing_default_stub_error(expectation, args_for_multiple_calls)
60
+ __raise(
61
+ error_message(expectation, args_for_multiple_calls) +
62
+ "\n Please stub a default value first if message might be received with other args as well. \n"
63
+ )
64
+ end
65
+
66
+ # @private
67
+ def raise_similar_message_args_error(expectation, args_for_multiple_calls, backtrace_line=nil)
68
+ __raise error_message(expectation, args_for_multiple_calls), backtrace_line
69
+ end
70
+
71
+ def default_error_message(expectation, expected_args, actual_args)
72
+ "#{intro} received #{expectation.message.inspect} #{unexpected_arguments_message(expected_args, actual_args)}".dup
73
+ end
74
+
75
+ # rubocop:disable Metrics/ParameterLists
76
+ # @private
77
+ def raise_expectation_error(message, expected_received_count, argument_list_matcher,
78
+ actual_received_count, expectation_count_type, args,
79
+ backtrace_line=nil, source_id=nil, args_history=nil)
80
+ expected_part = expected_part_of_expectation_error(expected_received_count, expectation_count_type, argument_list_matcher)
81
+ received_part = received_part_of_expectation_error(actual_received_count, args, args_history)
82
+ __raise "(#{intro(:unwrapped)}).#{message}#{format_args(args)}\n #{expected_part}\n #{received_part}", backtrace_line, source_id
83
+ end
84
+ # rubocop:enable Metrics/ParameterLists
85
+
86
+ # @private
87
+ def raise_unimplemented_error(doubled_module, method_name, object)
88
+ message = case object
89
+ when InstanceVerifyingDouble
90
+ "the %s class does not implement the instance method: %s".dup <<
91
+ if ObjectMethodReference.for(doubled_module, method_name).implemented?
92
+ ". Perhaps you meant to use `class_double` instead?"
93
+ else
94
+ ""
95
+ end
96
+ when ClassVerifyingDouble
97
+ "the %s class does not implement the class method: %s".dup <<
98
+ if InstanceMethodReference.for(doubled_module, method_name).implemented?
99
+ ". Perhaps you meant to use `instance_double` instead?"
100
+ else
101
+ ""
102
+ end
103
+ else
104
+ "%s does not implement: %s"
105
+ end
106
+
107
+ __raise message % [doubled_module.description, method_name]
108
+ end
109
+
110
+ # @private
111
+ def raise_non_public_error(method_name, visibility)
112
+ raise NoMethodError, "%s method `%s' called on %s" % [
113
+ visibility, method_name, intro
114
+ ]
115
+ end
116
+
117
+ # @private
118
+ def raise_invalid_arguments_error(verifier)
119
+ __raise verifier.error_message
120
+ end
121
+
122
+ # @private
123
+ def raise_expired_test_double_error
124
+ raise ExpiredTestDoubleError,
125
+ "#{intro} was originally created in one example but has leaked into " \
126
+ "another example and can no longer be used. rspec-mocks' doubles are " \
127
+ "designed to only last for one example, and you need to create a new " \
128
+ "one in each example you wish to use it for."
129
+ end
130
+
131
+ # @private
132
+ def describe_expectation(verb, message, expected_received_count, _actual_received_count, args)
133
+ "#{verb} #{message}#{format_args(args)} #{count_message(expected_received_count)}"
134
+ end
135
+
136
+ # @private
137
+ def raise_out_of_order_error(message)
138
+ __raise "#{intro} received :#{message} out of order"
139
+ end
140
+
141
+ # @private
142
+ def raise_missing_block_error(args_to_yield)
143
+ __raise "#{intro} asked to yield |#{arg_list(args_to_yield)}| but no block was passed"
144
+ end
145
+
146
+ # @private
147
+ def raise_wrong_arity_error(args_to_yield, signature)
148
+ __raise "#{intro} yielded |#{arg_list(args_to_yield)}| to block with #{signature.description}"
149
+ end
150
+
151
+ # @private
152
+ def raise_only_valid_on_a_partial_double(method)
153
+ __raise "#{intro} is a pure test double. `#{method}` is only " \
154
+ "available on a partial double."
155
+ end
156
+
157
+ # @private
158
+ def raise_expectation_on_unstubbed_method(method)
159
+ __raise "#{intro} expected to have received #{method}, but that " \
160
+ "object is not a spy or method has not been stubbed."
161
+ end
162
+
163
+ # @private
164
+ def raise_expectation_on_mocked_method(method)
165
+ __raise "#{intro} expected to have received #{method}, but that " \
166
+ "method has been mocked instead of stubbed or spied."
167
+ end
168
+
169
+ # @private
170
+ def raise_double_negation_error(wrapped_expression)
171
+ __raise "Isn't life confusing enough? You've already set a " \
172
+ "negative message expectation and now you are trying to " \
173
+ "negate it again with `never`. What does an expression like " \
174
+ "`#{wrapped_expression}.not_to receive(:msg).never` even mean?"
175
+ end
176
+
177
+ # @private
178
+ def raise_verifying_double_not_defined_error(ref)
179
+ notify(VerifyingDoubleNotDefinedError.new(
180
+ "#{ref.description.inspect} is not a defined constant. " \
181
+ "Perhaps you misspelt it? " \
182
+ "Disable check with `verify_doubled_constant_names` configuration option."
183
+ ))
184
+ end
185
+
186
+ # @private
187
+ def raise_have_received_disallowed(type, reason)
188
+ __raise "Using #{type}(...) with the `have_received` " \
189
+ "matcher is not supported#{reason}."
190
+ end
191
+
192
+ # @private
193
+ def raise_cant_constrain_count_for_negated_have_received_error(count_constraint)
194
+ __raise "can't use #{count_constraint} when negative"
195
+ end
196
+
197
+ # @private
198
+ def raise_method_not_stubbed_error(method_name)
199
+ __raise "The method `#{method_name}` was not stubbed or was already unstubbed"
200
+ end
201
+
202
+ # @private
203
+ def raise_already_invoked_error(message, calling_customization)
204
+ error_message = "The message expectation for #{intro}.#{message} has already been invoked " \
205
+ "and cannot be modified further (e.g. using `#{calling_customization}`). All message expectation " \
206
+ "customizations must be applied before it is used for the first time."
207
+
208
+ notify MockExpectationAlreadyInvokedError.new(error_message)
209
+ end
210
+
211
+ def raise_expectation_on_nil_error(method_name)
212
+ __raise expectation_on_nil_message(method_name)
213
+ end
214
+
215
+ def expectation_on_nil_message(method_name)
216
+ "An expectation of `:#{method_name}` was set on `nil`. " \
217
+ "To allow expectations on `nil` and suppress this message, set `RSpec::Mocks.configuration.allow_message_expectations_on_nil` to `true`. " \
218
+ "To disallow expectations on `nil`, set `RSpec::Mocks.configuration.allow_message_expectations_on_nil` to `false`"
219
+ end
220
+
221
+ # @private
222
+ def intro(unwrapped=false)
223
+ case @target
224
+ when TestDouble then TestDoubleFormatter.format(@target, unwrapped)
225
+ when Class then
226
+ formatted = "#{@target.inspect} (class)"
227
+ return formatted if unwrapped
228
+ "#<#{formatted}>"
229
+ when NilClass then "nil"
230
+ else @target.inspect
231
+ end
232
+ end
233
+
234
+ # @private
235
+ def method_call_args_description(args, generic_prefix=" with arguments: ", matcher_prefix=" with ")
236
+ case args.first
237
+ when ArgumentMatchers::AnyArgsMatcher then "#{matcher_prefix}any arguments"
238
+ when ArgumentMatchers::NoArgsMatcher then "#{matcher_prefix}no arguments"
239
+ else
240
+ if yield
241
+ "#{generic_prefix}#{format_args(args)}"
242
+ else
243
+ ""
244
+ end
245
+ end
246
+ end
247
+
248
+ private
249
+
250
+ def received_part_of_expectation_error(actual_received_count, args, args_history=nil)
251
+ extra = ''
252
+ if args_history
253
+ args_history.each_with_index do |(arg, backtrace), index|
254
+ extra += "\n call #{index+1}: #{arg.inspect}"
255
+ backtrace.each do |line|
256
+ extra += "\n from #{line}"
257
+ end
258
+ end
259
+ end
260
+ "received: #{count_message(actual_received_count)}" +
261
+ method_call_args_description(args) do
262
+ actual_received_count > 0 && args.length > 0
263
+ end + extra
264
+ end
265
+
266
+ def expected_part_of_expectation_error(expected_received_count, expectation_count_type, argument_list_matcher)
267
+ "expected: #{count_message(expected_received_count, expectation_count_type)}" +
268
+ method_call_args_description(argument_list_matcher.expected_args) do
269
+ argument_list_matcher.expected_args.length > 0
270
+ end
271
+ end
272
+
273
+ def unexpected_arguments_message(expected_args_string, actual_args_string)
274
+ "with unexpected arguments\n expected: #{expected_args_string}\n got: #{actual_args_string}"
275
+ end
276
+
277
+ def error_message(expectation, args_for_multiple_calls)
278
+ expected_args = format_args(expectation.expected_args)
279
+ actual_args = format_received_args(args_for_multiple_calls)
280
+ message = default_error_message(expectation, expected_args, actual_args)
281
+
282
+ if args_for_multiple_calls.one?
283
+ diff = diff_message(expectation.expected_args, args_for_multiple_calls.first)
284
+ message << "\nDiff:#{diff}" unless diff.strip.empty?
285
+ end
286
+
287
+ message
288
+ end
289
+
290
+ def diff_message(expected_args, actual_args)
291
+ formatted_expected_args = expected_args.map do |x|
292
+ RSpec::Support.rspec_description_for_object(x)
293
+ end
294
+
295
+ formatted_expected_args, actual_args = unpack_string_args(formatted_expected_args, actual_args)
296
+
297
+ differ.diff(actual_args, formatted_expected_args)
298
+ end
299
+
300
+ def unpack_string_args(formatted_expected_args, actual_args)
301
+ if [formatted_expected_args, actual_args].all? { |x| list_of_exactly_one_string?(x) }
302
+ [formatted_expected_args.first, actual_args.first]
303
+ else
304
+ [formatted_expected_args, actual_args]
305
+ end
306
+ end
307
+
308
+ def list_of_exactly_one_string?(args)
309
+ Array === args && args.count == 1 && String === args.first
310
+ end
311
+
312
+ def differ
313
+ RSpec::Support::Differ.new(:color => RSpec::Mocks.configuration.color?)
314
+ end
315
+
316
+ def __raise(message, backtrace_line=nil, source_id=nil)
317
+ message = opts[:message] unless opts[:message].nil?
318
+ exception = RSpec::Mocks::MockExpectationError.new(message)
319
+ prepend_to_backtrace(exception, backtrace_line) if backtrace_line
320
+ notify exception, :source_id => source_id
321
+ end
322
+
323
+ if RSpec::Support::Ruby.jruby?
324
+ def prepend_to_backtrace(exception, line)
325
+ raise exception
326
+ rescue RSpec::Mocks::MockExpectationError => with_backtrace
327
+ with_backtrace.backtrace.unshift(line)
328
+ end
329
+ else
330
+ def prepend_to_backtrace(exception, line)
331
+ exception.set_backtrace(caller.unshift line)
332
+ end
333
+ end
334
+
335
+ def notify(*args)
336
+ RSpec::Support.notify_failure(*args)
337
+ end
338
+
339
+ def format_args(args)
340
+ return "(no args)" if args.empty?
341
+ "(#{arg_list(args)})"
342
+ end
343
+
344
+ def arg_list(args)
345
+ args.map { |arg| RSpec::Support::ObjectFormatter.format(arg) }.join(", ")
346
+ end
347
+
348
+ def format_received_args(args_for_multiple_calls)
349
+ grouped_args(args_for_multiple_calls).map do |args_for_one_call, index|
350
+ "#{format_args(args_for_one_call)}#{group_count(index, args_for_multiple_calls)}"
351
+ end.join("\n ")
352
+ end
353
+
354
+ def count_message(count, expectation_count_type=nil)
355
+ return "at least #{times(count.abs)}" if count < 0 || expectation_count_type == :at_least
356
+ return "at most #{times(count)}" if expectation_count_type == :at_most
357
+ times(count)
358
+ end
359
+
360
+ def times(count)
361
+ "#{count} time#{count == 1 ? '' : 's'}"
362
+ end
363
+
364
+ def grouped_args(args)
365
+ Hash[args.group_by { |x| x }.map { |k, v| [k, v.count] }]
366
+ end
367
+
368
+ def group_count(index, args)
369
+ " (#{times(index)})" if args.size > 1 || index > 1
370
+ end
371
+ end
372
+
373
+ # @private
374
+ def self.error_generator
375
+ @error_generator ||= ErrorGenerator.new
376
+ end
377
+ end
378
+ end
@@ -0,0 +1,434 @@
1
+ RSpec::Support.require_rspec_mocks 'object_reference'
2
+
3
+ module RSpec
4
+ module Mocks
5
+ # Contains methods intended to be used from within code examples.
6
+ # Mix this in to your test context (such as a test framework base class)
7
+ # to use rspec-mocks with your test framework. If you're using rspec-core,
8
+ # it'll take care of doing this for you.
9
+ module ExampleMethods
10
+ include RSpec::Mocks::ArgumentMatchers
11
+
12
+ # @overload double()
13
+ # @overload double(name)
14
+ # @param name [String/Symbol] name or description to be used in failure messages
15
+ # @overload double(stubs)
16
+ # @param stubs (Hash) hash of message/return-value pairs
17
+ # @overload double(name, stubs)
18
+ # @param name [String/Symbol] name or description to be used in failure messages
19
+ # @param stubs (Hash) hash of message/return-value pairs
20
+ # @return (Double)
21
+ #
22
+ # Constructs an instance of [RSpec::Mocks::Double](RSpec::Mocks::Double) configured
23
+ # with an optional name, used for reporting in failure messages, and an optional
24
+ # hash of message/return-value pairs.
25
+ #
26
+ # @example
27
+ # book = double("book", :title => "The RSpec Book")
28
+ # book.title #=> "The RSpec Book"
29
+ #
30
+ # card = double("card", :suit => "Spades", :rank => "A")
31
+ # card.suit #=> "Spades"
32
+ # card.rank #=> "A"
33
+ #
34
+ def double(*args)
35
+ ExampleMethods.declare_double(Double, *args)
36
+ end
37
+
38
+ # @overload instance_double(doubled_class)
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
43
+ # @overload instance_double(doubled_class, stubs)
44
+ # @param doubled_class [String, Class]
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
50
+ # @return InstanceVerifyingDouble
51
+ #
52
+ # Constructs a test double against a specific class. If the given class
53
+ # name has been loaded, only instance methods defined on the class are
54
+ # allowed to be stubbed. In all other ways it behaves like a
55
+ # [double](double).
56
+ def instance_double(doubled_class, *args)
57
+ ref = ObjectReference.for(doubled_class)
58
+ ExampleMethods.declare_verifying_double(InstanceVerifyingDouble, ref, *args)
59
+ end
60
+
61
+ # @overload class_double(doubled_class)
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
66
+ # @overload class_double(doubled_class, stubs)
67
+ # @param doubled_class [String, Module]
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
73
+ # @return ClassVerifyingDouble
74
+ #
75
+ # Constructs a test double against a specific class. If the given class
76
+ # name has been loaded, only class methods defined on the class are
77
+ # allowed to be stubbed. In all other ways it behaves like a
78
+ # [double](double).
79
+ def class_double(doubled_class, *args)
80
+ ref = ObjectReference.for(doubled_class)
81
+ ExampleMethods.declare_verifying_double(ClassVerifyingDouble, ref, *args)
82
+ end
83
+
84
+ # @overload object_double(object_or_name)
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
89
+ # @overload object_double(object_or_name, stubs)
90
+ # @param object_or_name [String, Object]
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
96
+ # @return ObjectVerifyingDouble
97
+ #
98
+ # Constructs a test double against a specific object. Only the methods
99
+ # the object responds to are allowed to be stubbed. If a String argument
100
+ # is provided, it is assumed to reference a constant object which is used
101
+ # for verification. In all other ways it behaves like a [double](double).
102
+ def object_double(object_or_name, *args)
103
+ ref = ObjectReference.for(object_or_name, :allow_direct_object_refs)
104
+ ExampleMethods.declare_verifying_double(ObjectVerifyingDouble, ref, *args)
105
+ end
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
+
195
+ # Disables warning messages about expectations being set on nil.
196
+ #
197
+ # By default warning messages are issued when expectations are set on
198
+ # nil. This is to prevent false-positives and to catch potential bugs
199
+ # early on.
200
+ # @deprecated Use {RSpec::Mocks::Configuration#allow_message_expectations_on_nil} instead.
201
+ def allow_message_expectations_on_nil
202
+ RSpec::Mocks.space.proxy_for(nil).warn_about_expectations = false
203
+ end
204
+
205
+ # Stubs the named constant with the given value.
206
+ # Like method stubs, the constant will be restored
207
+ # to its original value (or lack of one, if it was
208
+ # undefined) when the example completes.
209
+ #
210
+ # @param constant_name [String] The fully qualified name of the constant. The current
211
+ # constant scoping at the point of call is not considered.
212
+ # @param value [Object] The value to make the constant refer to. When the
213
+ # example completes, the constant will be restored to its prior state.
214
+ # @param options [Hash] Stubbing options.
215
+ # @option options :transfer_nested_constants [Boolean, Array<Symbol>] Determines
216
+ # what nested constants, if any, will be transferred from the original value
217
+ # of the constant to the new value of the constant. This only works if both
218
+ # the original and new values are modules (or classes).
219
+ # @return [Object] the stubbed value of the constant
220
+ #
221
+ # @example
222
+ # stub_const("MyClass", Class.new) # => Replaces (or defines) MyClass with a new class object.
223
+ # stub_const("SomeModel::PER_PAGE", 5) # => Sets SomeModel::PER_PAGE to 5.
224
+ #
225
+ # class CardDeck
226
+ # SUITS = [:Spades, :Diamonds, :Clubs, :Hearts]
227
+ # NUM_CARDS = 52
228
+ # end
229
+ #
230
+ # stub_const("CardDeck", Class.new)
231
+ # CardDeck::SUITS # => uninitialized constant error
232
+ # CardDeck::NUM_CARDS # => uninitialized constant error
233
+ #
234
+ # stub_const("CardDeck", Class.new, :transfer_nested_constants => true)
235
+ # CardDeck::SUITS # => our suits array
236
+ # CardDeck::NUM_CARDS # => 52
237
+ #
238
+ # stub_const("CardDeck", Class.new, :transfer_nested_constants => [:SUITS])
239
+ # CardDeck::SUITS # => our suits array
240
+ # CardDeck::NUM_CARDS # => uninitialized constant error
241
+ def stub_const(constant_name, value, options={})
242
+ ConstantMutator.stub(constant_name, value, options)
243
+ end
244
+
245
+ # Hides the named constant with the given value. The constant will be
246
+ # undefined for the duration of the test.
247
+ #
248
+ # Like method stubs, the constant will be restored to its original value
249
+ # when the example completes.
250
+ #
251
+ # @param constant_name [String] The fully qualified name of the constant.
252
+ # The current constant scoping at the point of call is not considered.
253
+ #
254
+ # @example
255
+ # hide_const("MyClass") # => MyClass is now an undefined constant
256
+ def hide_const(constant_name)
257
+ ConstantMutator.hide(constant_name)
258
+ end
259
+
260
+ # Verifies that the given object received the expected message during the
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.
264
+ #
265
+ # Stubbing and verifying messages received in this way implements the
266
+ # Test Spy pattern.
267
+ #
268
+ # @param method_name [Symbol] name of the method expected to have been
269
+ # called.
270
+ #
271
+ # @example
272
+ # invitation = double('invitation', accept: true)
273
+ # user.accept_invitation(invitation)
274
+ # expect(invitation).to have_received(:accept)
275
+ #
276
+ # # You can also use most message expectations:
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.
281
+ def have_received(method_name, &block)
282
+ Matchers::HaveReceived.new(method_name, &block)
283
+ end
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
+
297
+ # @method expect
298
+ # Used to wrap an object in preparation for setting a mock expectation
299
+ # on it.
300
+ #
301
+ # @example
302
+ # expect(obj).to receive(:foo).with(5).and_return(:return_value)
303
+ #
304
+ # @note This method is usually provided by rspec-expectations. However,
305
+ # if you use rspec-mocks without rspec-expectations, there's a definition
306
+ # of it that is made available here. If you disable the `:expect` syntax
307
+ # this method will be undefined.
308
+
309
+ # @method allow
310
+ # Used to wrap an object in preparation for stubbing a method
311
+ # on it.
312
+ #
313
+ # @example
314
+ # allow(dbl).to receive(:foo).with(5).and_return(:return_value)
315
+ #
316
+ # @note If you disable the `:expect` syntax this method will be undefined.
317
+
318
+ # @method expect_any_instance_of
319
+ # Used to wrap a class in preparation for setting a mock expectation
320
+ # on instances of it.
321
+ #
322
+ # @example
323
+ # expect_any_instance_of(MyClass).to receive(:foo)
324
+ #
325
+ # @note If you disable the `:expect` syntax this method will be undefined.
326
+
327
+ # @method allow_any_instance_of
328
+ # Used to wrap a class in preparation for stubbing a method
329
+ # on instances of it.
330
+ #
331
+ # @example
332
+ # allow_any_instance_of(MyClass).to receive(:foo)
333
+ #
334
+ # @note This is only available when you have enabled the `expect` syntax.
335
+
336
+ # @method receive
337
+ # Used to specify a message that you expect or allow an object
338
+ # to receive. The object returned by `receive` supports the same
339
+ # fluent interface that `should_receive` and `stub` have always
340
+ # supported, allowing you to constrain the arguments or number of
341
+ # times, and configure how the object should respond to the message.
342
+ #
343
+ # @example
344
+ # expect(obj).to receive(:hello).with("world").exactly(3).times
345
+ #
346
+ # @note If you disable the `:expect` syntax this method will be undefined.
347
+
348
+ # @method receive_messages
349
+ # Shorthand syntax used to setup message(s), and their return value(s),
350
+ # that you expect or allow an object to receive. The method takes a hash
351
+ # of messages and their respective return values. Unlike with `receive`,
352
+ # you cannot apply further customizations using a block or the fluent
353
+ # interface.
354
+ #
355
+ # @example
356
+ # allow(obj).to receive_messages(:speak => "Hello World")
357
+ # allow(obj).to receive_messages(:speak => "Hello", :meow => "Meow")
358
+ #
359
+ # @note If you disable the `:expect` syntax this method will be undefined.
360
+
361
+ # @method receive_message_chain
362
+ # @overload receive_message_chain(method1, method2)
363
+ # @overload receive_message_chain("method1.method2")
364
+ # @overload receive_message_chain(method1, method_to_value_hash)
365
+ #
366
+ # stubs/mocks a chain of messages on an object or test double.
367
+ #
368
+ # ## Warning:
369
+ #
370
+ # Chains can be arbitrarily long, which makes it quite painless to
371
+ # violate the Law of Demeter in violent ways, so you should consider any
372
+ # use of `receive_message_chain` a code smell. Even though not all code smells
373
+ # indicate real problems (think fluent interfaces), `receive_message_chain` still
374
+ # results in brittle examples. For example, if you write
375
+ # `allow(foo).to receive_message_chain(:bar, :baz => 37)` in a spec and then the
376
+ # implementation calls `foo.baz.bar`, the stub will not work.
377
+ #
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 }
382
+ #
383
+ # # Given any of ^^ these three forms ^^:
384
+ # double.foo.bar # => :baz
385
+ #
386
+ # # Common use in Rails/ActiveRecord:
387
+ # allow(Article).to receive_message_chain("recent.published") { [Article.new] }
388
+ #
389
+ # @note If you disable the `:expect` syntax this method will be undefined.
390
+
391
+ # @private
392
+ def self.included(klass)
393
+ klass.class_exec do
394
+ # This gets mixed in so that if `RSpec::Matchers` is included in
395
+ # `klass` later, its definition of `expect` will take precedence.
396
+ include ExpectHost unless method_defined?(:expect)
397
+ end
398
+ end
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
+
407
+ # @private
408
+ def self.declare_verifying_double(type, ref, *args)
409
+ if RSpec::Mocks.configuration.verify_doubled_constant_names? &&
410
+ !ref.defined?
411
+
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)
417
+ end
418
+
419
+ declare_double(type, ref, *args)
420
+ end
421
+
422
+ # @private
423
+ def self.declare_double(type, *args)
424
+ args << {} unless Hash === args.last
425
+ type.new(*args)
426
+ end
427
+
428
+ # This module exists to host the `expect` method for cases where
429
+ # rspec-mocks is used w/o rspec-expectations.
430
+ module ExpectHost
431
+ end
432
+ end
433
+ end
434
+ end