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,287 @@
1
+ module RSpec
2
+ module Mocks
3
+ # @private
4
+ class MethodDouble
5
+ # @private
6
+ attr_reader :method_name, :object, :expectations, :stubs, :method_stasher
7
+
8
+ # @private
9
+ def initialize(object, method_name, proxy)
10
+ @method_name = method_name
11
+ @object = object
12
+ @proxy = proxy
13
+
14
+ @original_visibility = nil
15
+ @method_stasher = InstanceMethodStasher.new(object, method_name)
16
+ @method_is_proxied = false
17
+ @expectations = []
18
+ @stubs = []
19
+ end
20
+
21
+ def original_implementation_callable
22
+ # If original method is not present, uses the `method_missing`
23
+ # handler of the object. This accounts for cases where the user has not
24
+ # correctly defined `respond_to?`, and also 1.8 which does not provide
25
+ # method handles for missing methods even if `respond_to?` is correct.
26
+ @original_implementation_callable ||= original_method ||
27
+ Proc.new do |*args, &block|
28
+ @object.__send__(:method_missing, @method_name, *args, &block)
29
+ end
30
+ end
31
+
32
+ alias_method :save_original_implementation_callable!, :original_implementation_callable
33
+
34
+ def original_method
35
+ @original_method ||=
36
+ @method_stasher.original_method ||
37
+ @proxy.original_method_handle_for(method_name)
38
+ end
39
+
40
+ # @private
41
+ def visibility
42
+ @proxy.visibility_for(@method_name)
43
+ end
44
+
45
+ # @private
46
+ def object_singleton_class
47
+ class << @object; self; end
48
+ end
49
+
50
+ # @private
51
+ def configure_method
52
+ @original_visibility = visibility
53
+ @method_stasher.stash unless @method_is_proxied
54
+ define_proxy_method
55
+ end
56
+
57
+ # @private
58
+ def define_proxy_method
59
+ return if @method_is_proxied
60
+
61
+ save_original_implementation_callable!
62
+ definition_target.class_exec(self, method_name, @original_visibility || visibility) do |method_double, method_name, visibility|
63
+ define_method(method_name) do |*args, &block|
64
+ method_double.proxy_method_invoked(self, *args, &block)
65
+ end
66
+ __send__(visibility, method_name)
67
+ end
68
+
69
+ @method_is_proxied = true
70
+ end
71
+
72
+ # The implementation of the proxied method. Subclasses may override this
73
+ # method to perform additional operations.
74
+ #
75
+ # @private
76
+ def proxy_method_invoked(_obj, *args, &block)
77
+ @proxy.message_received method_name, *args, &block
78
+ end
79
+
80
+ # @private
81
+ def restore_original_method
82
+ return show_frozen_warning if object_singleton_class.frozen?
83
+ return unless @method_is_proxied
84
+
85
+ remove_method_from_definition_target
86
+ @method_stasher.restore if @method_stasher.method_is_stashed?
87
+ restore_original_visibility
88
+
89
+ @method_is_proxied = false
90
+ end
91
+
92
+ # @private
93
+ def show_frozen_warning
94
+ RSpec.warn_with(
95
+ "WARNING: rspec-mocks was unable to restore the original `#{@method_name}` " \
96
+ "method on #{@object.inspect} because it has been frozen. If you reuse this " \
97
+ "object, `#{@method_name}` will continue to respond with its stub implementation.",
98
+ :call_site => nil,
99
+ :use_spec_location_as_call_site => true
100
+ )
101
+ end
102
+
103
+ # @private
104
+ def restore_original_visibility
105
+ return unless @original_visibility &&
106
+ MethodReference.method_defined_at_any_visibility?(object_singleton_class, @method_name)
107
+
108
+ object_singleton_class.__send__(@original_visibility, method_name)
109
+ end
110
+
111
+ # @private
112
+ def verify
113
+ expectations.each { |e| e.verify_messages_received }
114
+ end
115
+
116
+ # @private
117
+ def reset
118
+ restore_original_method
119
+ clear
120
+ end
121
+
122
+ # @private
123
+ def clear
124
+ expectations.clear
125
+ stubs.clear
126
+ end
127
+
128
+ # The type of message expectation to create has been extracted to its own
129
+ # method so that subclasses can override it.
130
+ #
131
+ # @private
132
+ def message_expectation_class
133
+ MessageExpectation
134
+ end
135
+
136
+ # @private
137
+ def add_expectation(error_generator, expectation_ordering, expected_from, opts, &implementation)
138
+ configure_method
139
+ expectation = message_expectation_class.new(error_generator, expectation_ordering,
140
+ expected_from, self, :expectation, opts, &implementation)
141
+ expectations << expectation
142
+ expectation
143
+ end
144
+
145
+ # @private
146
+ def build_expectation(error_generator, expectation_ordering)
147
+ expected_from = IGNORED_BACKTRACE_LINE
148
+ message_expectation_class.new(error_generator, expectation_ordering, expected_from, self)
149
+ end
150
+
151
+ # @private
152
+ def add_stub(error_generator, expectation_ordering, expected_from, opts={}, &implementation)
153
+ configure_method
154
+ stub = message_expectation_class.new(error_generator, expectation_ordering, expected_from,
155
+ self, :stub, opts, &implementation)
156
+ stubs.unshift stub
157
+ stub
158
+ end
159
+
160
+ # A simple stub can only return a concrete value for a message, and
161
+ # cannot match on arguments. It is used as an optimization over
162
+ # `add_stub` / `add_expectation` where it is known in advance that this
163
+ # is all that will be required of a stub, such as when passing attributes
164
+ # to the `double` example method. They do not stash or restore existing method
165
+ # definitions.
166
+ #
167
+ # @private
168
+ def add_simple_stub(method_name, response)
169
+ setup_simple_method_double method_name, response, stubs
170
+ end
171
+
172
+ # @private
173
+ def add_simple_expectation(method_name, response, error_generator, backtrace_line)
174
+ setup_simple_method_double method_name, response, expectations, error_generator, backtrace_line
175
+ end
176
+
177
+ # @private
178
+ def setup_simple_method_double(method_name, response, collection, error_generator=nil, backtrace_line=nil)
179
+ define_proxy_method
180
+
181
+ me = SimpleMessageExpectation.new(method_name, response, error_generator, backtrace_line)
182
+ collection.unshift me
183
+ me
184
+ end
185
+
186
+ # @private
187
+ def add_default_stub(*args, &implementation)
188
+ return if stubs.any?
189
+ add_stub(*args, &implementation)
190
+ end
191
+
192
+ # @private
193
+ def remove_stub
194
+ raise_method_not_stubbed_error if stubs.empty?
195
+ remove_stub_if_present
196
+ end
197
+
198
+ # @private
199
+ def remove_stub_if_present
200
+ expectations.empty? ? reset : stubs.clear
201
+ end
202
+
203
+ # @private
204
+ def raise_method_not_stubbed_error
205
+ RSpec::Mocks.error_generator.raise_method_not_stubbed_error(method_name)
206
+ end
207
+
208
+ # In Ruby 2.0.0 and above prepend will alter the method lookup chain.
209
+ # We use an object's singleton class to define method doubles upon,
210
+ # however if the object has had its singleton class (as opposed to
211
+ # its actual class) prepended too then the the method lookup chain
212
+ # will look in the prepended module first, **before** the singleton
213
+ # class.
214
+ #
215
+ # This code works around that by providing a mock definition target
216
+ # that is either the singleton class, or if necessary, a prepended module
217
+ # of our own.
218
+ #
219
+ if Support::RubyFeatures.module_prepends_supported?
220
+
221
+ private
222
+
223
+ # We subclass `Module` in order to be able to easily detect our prepended module.
224
+ RSpecPrependedModule = Class.new(Module)
225
+
226
+ def definition_target
227
+ @definition_target ||= usable_rspec_prepended_module || object_singleton_class
228
+ end
229
+
230
+ def usable_rspec_prepended_module
231
+ @proxy.prepended_modules_of_singleton_class.each do |mod|
232
+ # If we have one of our modules prepended before one of the user's
233
+ # modules that defines the method, use that, since our module's
234
+ # definition will take precedence.
235
+ return mod if RSpecPrependedModule === mod
236
+
237
+ # If we hit a user module with the method defined first,
238
+ # we must create a new prepend module, even if one exists later,
239
+ # because ours will only take precedence if it comes first.
240
+ return new_rspec_prepended_module if mod.method_defined?(method_name)
241
+ end
242
+
243
+ nil
244
+ end
245
+
246
+ def new_rspec_prepended_module
247
+ RSpecPrependedModule.new.tap do |mod|
248
+ object_singleton_class.__send__ :prepend, mod
249
+ end
250
+ end
251
+
252
+ else
253
+
254
+ private
255
+
256
+ def definition_target
257
+ object_singleton_class
258
+ end
259
+
260
+ end
261
+
262
+ private
263
+
264
+ def remove_method_from_definition_target
265
+ definition_target.__send__(:remove_method, @method_name)
266
+ rescue NameError
267
+ # This can happen when the method has been monkeyed with by
268
+ # something outside RSpec. This happens, for example, when
269
+ # `file.write` has been stubbed, and then `file.reopen(other_io)`
270
+ # is later called, as `File#reopen` appears to redefine `write`.
271
+ #
272
+ # Note: we could avoid rescuing this by checking
273
+ # `definition_target.instance_method(@method_name).owner == definition_target`,
274
+ # saving us from the cost of the expensive exception, but this error is
275
+ # extremely rare (it was discovered on 2014-12-30, only happens on
276
+ # RUBY_VERSION < 2.0 and our spec suite only hits this condition once),
277
+ # so we'd rather avoid the cost of that check for every method double,
278
+ # and risk the rare situation where this exception will get raised.
279
+ RSpec.warn_with(
280
+ "WARNING: RSpec could not fully restore #{@object.inspect}." \
281
+ "#{@method_name}, possibly because the method has been redefined " \
282
+ "by something outside of RSpec."
283
+ )
284
+ end
285
+ end
286
+ end
287
+ end
@@ -0,0 +1,202 @@
1
+ RSpec::Support.require_rspec_support 'comparable_version'
2
+
3
+ module RSpec
4
+ module Mocks
5
+ # Represents a method on an object that may or may not be defined.
6
+ # The method may be an instance method on a module or a method on
7
+ # any object.
8
+ #
9
+ # @private
10
+ class MethodReference
11
+ def self.for(object_reference, method_name)
12
+ new(object_reference, method_name)
13
+ end
14
+
15
+ def initialize(object_reference, method_name)
16
+ @object_reference = object_reference
17
+ @method_name = method_name
18
+ end
19
+
20
+ # A method is implemented if sending the message does not result in
21
+ # a `NoMethodError`. It might be dynamically implemented by
22
+ # `method_missing`.
23
+ def implemented?
24
+ @object_reference.when_loaded do |m|
25
+ method_implemented?(m)
26
+ end
27
+ end
28
+
29
+ # Returns true if we definitively know that sending the method
30
+ # will result in a `NoMethodError`.
31
+ #
32
+ # This is not simply the inverse of `implemented?`: there are
33
+ # cases when we don't know if a method is implemented and
34
+ # both `implemented?` and `unimplemented?` will return false.
35
+ def unimplemented?
36
+ @object_reference.when_loaded do |_m|
37
+ return !implemented?
38
+ end
39
+
40
+ # If it's not loaded, then it may be implemented but we can't check.
41
+ false
42
+ end
43
+
44
+ # A method is defined if we are able to get a `Method` object for it.
45
+ # In that case, we can assert against metadata like the arity.
46
+ def defined?
47
+ @object_reference.when_loaded do |m|
48
+ method_defined?(m)
49
+ end
50
+ end
51
+
52
+ def with_signature
53
+ return unless (original = original_method)
54
+ yield Support::MethodSignature.new(original)
55
+ end
56
+
57
+ def visibility
58
+ @object_reference.when_loaded do |m|
59
+ return visibility_from(m)
60
+ end
61
+
62
+ # When it's not loaded, assume it's public. We don't want to
63
+ # wrongly treat the method as private.
64
+ :public
65
+ end
66
+
67
+ def self.instance_method_visibility_for(klass, method_name)
68
+ if klass.public_method_defined?(method_name)
69
+ :public
70
+ elsif klass.private_method_defined?(method_name)
71
+ :private
72
+ elsif klass.protected_method_defined?(method_name)
73
+ :protected
74
+ end
75
+ end
76
+
77
+ class << self
78
+ alias method_defined_at_any_visibility? instance_method_visibility_for
79
+ end
80
+
81
+ def self.method_visibility_for(object, method_name)
82
+ vis = instance_method_visibility_for(class << object; self; end, method_name)
83
+
84
+ # If the method is not defined on the class, `instance_method_visibility_for`
85
+ # returns `nil`. However, it may be handled dynamically by `method_missing`,
86
+ # so here we check `respond_to` (passing false to not check private methods).
87
+ #
88
+ # This only considers the public case, but I don't think it's possible to
89
+ # write `method_missing` in such a way that it handles a dynamic message
90
+ # with private or protected visibility. Ruby doesn't provide you with
91
+ # the caller info.
92
+ return vis unless vis.nil?
93
+
94
+ proxy = RSpec::Mocks.space.proxy_for(object)
95
+ respond_to = proxy.method_double_if_exists_for_message(:respond_to?)
96
+
97
+ visible = respond_to && respond_to.original_method.call(method_name) ||
98
+ object.respond_to?(method_name)
99
+
100
+ return :public if visible
101
+ end
102
+
103
+ private
104
+
105
+ def original_method
106
+ @object_reference.when_loaded do |m|
107
+ self.defined? && find_method(m)
108
+ end
109
+ end
110
+ end
111
+
112
+ # @private
113
+ class InstanceMethodReference < MethodReference
114
+ private
115
+
116
+ def method_implemented?(mod)
117
+ MethodReference.method_defined_at_any_visibility?(mod, @method_name)
118
+ end
119
+
120
+ # Ideally, we'd use `respond_to?` for `method_implemented?` but we need a
121
+ # reference to an instance to do that and we don't have one. Note that
122
+ # we may get false negatives: if the method is implemented via
123
+ # `method_missing`, we'll return `false` even though it meets our
124
+ # definition of "implemented". However, it's the best we can do.
125
+ alias method_defined? method_implemented?
126
+
127
+ # works around the fact that repeated calls for method parameters will
128
+ # falsely return empty arrays on JRuby in certain circumstances, this
129
+ # is necessary here because we can't dup/clone UnboundMethods.
130
+ #
131
+ # This is necessary due to a bug in JRuby prior to 1.7.5 fixed in:
132
+ # https://github.com/jruby/jruby/commit/99a0613fe29935150d76a9a1ee4cf2b4f63f4a27
133
+ if RUBY_PLATFORM == 'java' && RSpec::Support::ComparableVersion.new(JRUBY_VERSION) < '1.7.5'
134
+ def find_method(mod)
135
+ mod.dup.instance_method(@method_name)
136
+ end
137
+ else
138
+ def find_method(mod)
139
+ mod.instance_method(@method_name)
140
+ end
141
+ end
142
+
143
+ def visibility_from(mod)
144
+ MethodReference.instance_method_visibility_for(mod, @method_name)
145
+ end
146
+ end
147
+
148
+ # @private
149
+ class ObjectMethodReference < MethodReference
150
+ def self.for(object_reference, method_name)
151
+ if ClassNewMethodReference.applies_to?(method_name) { object_reference.when_loaded { |o| o } }
152
+ ClassNewMethodReference.new(object_reference, method_name)
153
+ else
154
+ super
155
+ end
156
+ end
157
+
158
+ private
159
+
160
+ def method_implemented?(object)
161
+ object.respond_to?(@method_name, true)
162
+ end
163
+
164
+ def method_defined?(object)
165
+ (class << object; self; end).method_defined?(@method_name)
166
+ end
167
+
168
+ def find_method(object)
169
+ object.method(@method_name)
170
+ end
171
+
172
+ def visibility_from(object)
173
+ MethodReference.method_visibility_for(object, @method_name)
174
+ end
175
+ end
176
+
177
+ # When a class's `.new` method is stubbed, we want to use the method
178
+ # signature from `#initialize` because `.new`'s signature is a generic
179
+ # `def new(*args)` and it simply delegates to `#initialize` and forwards
180
+ # all args...so the method with the actually used signature is `#initialize`.
181
+ #
182
+ # This method reference implementation handles that specific case.
183
+ # @private
184
+ class ClassNewMethodReference < ObjectMethodReference
185
+ def self.applies_to?(method_name)
186
+ return false unless method_name == :new
187
+ klass = yield
188
+ return false unless klass.respond_to?(:new, true)
189
+
190
+ # We only want to apply our special logic to normal `new` methods.
191
+ # Methods that the user has monkeyed with should be left as-is.
192
+ ::RSpec::Support.method_handle_for(klass, :new).owner == ::Class
193
+ end
194
+
195
+ def with_signature
196
+ @object_reference.when_loaded do |klass|
197
+ yield Support::MethodSignature.new(klass.instance_method(:initialize))
198
+ end
199
+ end
200
+ end
201
+ end
202
+ end