rspec-mocks 3.13.8 → 4.0.0.beta1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- checksums.yaml.gz.sig +0 -0
- data/Changelog.md +12 -6
- data/LICENSE.md +1 -0
- data/README.md +8 -39
- data/lib/rspec/mocks/any_instance/expectation_chain.rb +1 -1
- data/lib/rspec/mocks/any_instance/proxy.rb +3 -9
- data/lib/rspec/mocks/any_instance/recorder.rb +13 -27
- data/lib/rspec/mocks/any_instance/stub_chain.rb +1 -1
- data/lib/rspec/mocks/argument_list_matcher.rb +9 -11
- data/lib/rspec/mocks/configuration.rb +1 -73
- data/lib/rspec/mocks/error_generator.rb +14 -23
- data/lib/rspec/mocks/example_methods.rb +28 -28
- data/lib/rspec/mocks/instance_method_stasher.rb +25 -102
- data/lib/rspec/mocks/message_expectation.rb +2 -3
- data/lib/rspec/mocks/method_double.rb +61 -71
- data/lib/rspec/mocks/method_reference.rb +8 -26
- data/lib/rspec/mocks/minitest_integration.rb +1 -1
- data/lib/rspec/mocks/mutate_const.rb +0 -1
- data/lib/rspec/mocks/object_reference.rb +2 -8
- data/lib/rspec/mocks/order_group.rb +4 -15
- data/lib/rspec/mocks/proxy.rb +8 -27
- data/lib/rspec/mocks/space.rb +4 -17
- data/lib/rspec/mocks/standalone.rb +2 -0
- data/lib/rspec/mocks/test_double.rb +5 -3
- data/lib/rspec/mocks/verifying_double.rb +2 -3
- data/lib/rspec/mocks/verifying_proxy.rb +2 -4
- data/lib/rspec/mocks/version.rb +1 -1
- data/lib/rspec/mocks.rb +0 -2
- data.tar.gz.sig +0 -0
- metadata +14 -15
- metadata.gz.sig +0 -0
- data/lib/rspec/mocks/syntax.rb +0 -325
|
@@ -5,93 +5,36 @@ module RSpec
|
|
|
5
5
|
def initialize(object, method)
|
|
6
6
|
@object = object
|
|
7
7
|
@method = method
|
|
8
|
+
# We don't want to create singleton class if it doesn't exist,
|
|
9
|
+
# so we don't use `object.singleton_class`.
|
|
8
10
|
@klass = (class << object; self; end)
|
|
9
11
|
|
|
10
12
|
@original_method = nil
|
|
11
|
-
@method_is_stashed = false
|
|
12
13
|
end
|
|
13
14
|
|
|
14
15
|
attr_reader :original_method
|
|
15
16
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
end
|
|
21
|
-
|
|
22
|
-
# @private
|
|
23
|
-
def stash
|
|
24
|
-
return if !method_defined_directly_on_klass? || @method_is_stashed
|
|
25
|
-
|
|
26
|
-
@klass.__send__(:alias_method, stashed_method_name, @method)
|
|
27
|
-
@method_is_stashed = true
|
|
28
|
-
end
|
|
29
|
-
|
|
30
|
-
# @private
|
|
31
|
-
def stashed_method_name
|
|
32
|
-
"obfuscated_by_rspec_mocks__#{@method}"
|
|
33
|
-
end
|
|
34
|
-
|
|
35
|
-
# @private
|
|
36
|
-
def restore
|
|
37
|
-
return unless @method_is_stashed
|
|
38
|
-
|
|
39
|
-
if @klass.__send__(:method_defined?, @method)
|
|
40
|
-
@klass.__send__(:undef_method, @method)
|
|
41
|
-
end
|
|
42
|
-
@klass.__send__(:alias_method, @method, stashed_method_name)
|
|
43
|
-
@klass.__send__(:remove_method, stashed_method_name)
|
|
44
|
-
@method_is_stashed = false
|
|
45
|
-
end
|
|
46
|
-
else
|
|
47
|
-
|
|
48
|
-
# @private
|
|
49
|
-
def method_is_stashed?
|
|
50
|
-
!!@original_method
|
|
51
|
-
end
|
|
52
|
-
|
|
53
|
-
# @private
|
|
54
|
-
def stash
|
|
55
|
-
return unless method_defined_directly_on_klass?
|
|
56
|
-
@original_method ||= ::RSpec::Support.method_handle_for(@object, @method)
|
|
57
|
-
@klass.__send__(:undef_method, @method)
|
|
58
|
-
end
|
|
17
|
+
# @private
|
|
18
|
+
def method_is_stashed?
|
|
19
|
+
!!@original_method
|
|
20
|
+
end
|
|
59
21
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
22
|
+
# @private
|
|
23
|
+
def stash
|
|
24
|
+
return unless method_defined_directly_on_klass?
|
|
25
|
+
@original_method ||= ::RSpec::Support.method_handle_for(@object, @method)
|
|
26
|
+
@klass.undef_method(@method)
|
|
27
|
+
end
|
|
63
28
|
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
29
|
+
# @private
|
|
30
|
+
def restore
|
|
31
|
+
return unless @original_method
|
|
67
32
|
|
|
68
|
-
|
|
69
|
-
@klass.__send__(:define_method, @method, @original_method)
|
|
70
|
-
end
|
|
33
|
+
@klass.undef_method(@method) if @klass.method_defined?(@method)
|
|
71
34
|
|
|
72
|
-
|
|
73
|
-
end
|
|
74
|
-
end
|
|
35
|
+
@klass.define_method(@method, @original_method)
|
|
75
36
|
|
|
76
|
-
|
|
77
|
-
# ruby 2.0.0-p247 and 2.0.0-p195 both have a bug that we can't work around :(.
|
|
78
|
-
# https://bugs.ruby-lang.org/issues/8686
|
|
79
|
-
def handle_restoration_failures
|
|
80
|
-
yield
|
|
81
|
-
rescue TypeError
|
|
82
|
-
RSpec.warn_with(
|
|
83
|
-
"RSpec failed to properly restore a partial double (#{@object.inspect}) " \
|
|
84
|
-
"to its original state due to a known bug in MRI 2.0.0-p195 & p247 " \
|
|
85
|
-
"(https://bugs.ruby-lang.org/issues/8686). This object may remain " \
|
|
86
|
-
"screwed up for the rest of this process. Please upgrade to 2.0.0-p353 or above.",
|
|
87
|
-
:call_site => nil, :use_spec_location_as_call_site => true
|
|
88
|
-
)
|
|
89
|
-
end
|
|
90
|
-
else
|
|
91
|
-
def handle_restoration_failures
|
|
92
|
-
# No known reasons for restoration to fail on other rubies.
|
|
93
|
-
yield
|
|
94
|
-
end
|
|
37
|
+
@original_method = nil
|
|
95
38
|
end
|
|
96
39
|
|
|
97
40
|
private
|
|
@@ -109,37 +52,17 @@ module RSpec
|
|
|
109
52
|
def method_owned_by_klass?
|
|
110
53
|
owner = @klass.instance_method(@method).owner
|
|
111
54
|
|
|
112
|
-
#
|
|
55
|
+
# The owner of a method on a class which has been
|
|
113
56
|
# `prepend`ed may actually be an instance, e.g.
|
|
114
57
|
# `#<MyClass:0x007fbb94e3cd10>`, rather than the expected `MyClass`.
|
|
115
58
|
owner = owner.class unless Module === owner
|
|
116
59
|
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
# end
|
|
124
|
-
#
|
|
125
|
-
# MyClass.owner(:alternate_new) returns `Class` when incorrect,
|
|
126
|
-
# but we need to consider the owner to be `MyClass` because
|
|
127
|
-
# it is not actually available on `Class` but is on `MyClass`.
|
|
128
|
-
# Hence, we verify that the owner actually has the method defined.
|
|
129
|
-
# If the given owner does not have the method defined, we assume
|
|
130
|
-
# that the method is actually owned by @klass.
|
|
131
|
-
#
|
|
132
|
-
# On 1.8, aliased methods can also report the wrong owner. Example:
|
|
133
|
-
# module M
|
|
134
|
-
# def a; end
|
|
135
|
-
# module_function :a
|
|
136
|
-
# alias b a
|
|
137
|
-
# module_function :b
|
|
138
|
-
# end
|
|
139
|
-
# The owner of M.b is the raw Module object, instead of the expected
|
|
140
|
-
# singleton class of the module
|
|
141
|
-
return true if RUBY_VERSION < '1.9' && owner == @object
|
|
142
|
-
owner == @klass || !(method_defined_on_klass?(owner))
|
|
60
|
+
owner == @klass ||
|
|
61
|
+
# When `extend self` is used, and not under `allow_any_instance_of`
|
|
62
|
+
# nor `expect_any_instance_of`.
|
|
63
|
+
(owner.singleton_class == @klass &&
|
|
64
|
+
!Mocks.space.any_instance_recorder_for(owner, true)) ||
|
|
65
|
+
!(method_defined_on_klass?(owner))
|
|
143
66
|
end
|
|
144
67
|
end
|
|
145
68
|
end
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
RSpec::Support.require_rspec_support '
|
|
1
|
+
RSpec::Support.require_rspec_support 'reentrant_mutex'
|
|
2
2
|
|
|
3
3
|
module RSpec
|
|
4
4
|
module Mocks
|
|
@@ -415,7 +415,6 @@ module RSpec
|
|
|
415
415
|
attr_reader :orig_object
|
|
416
416
|
attr_writer :expected_received_count, :expected_from, :argument_list_matcher
|
|
417
417
|
protected :expected_received_count=, :expected_from=, :error_generator=, :implementation=
|
|
418
|
-
|
|
419
418
|
# @private
|
|
420
419
|
attr_reader :type
|
|
421
420
|
|
|
@@ -849,7 +848,7 @@ module RSpec
|
|
|
849
848
|
|
|
850
849
|
def cannot_modify_further_error
|
|
851
850
|
CannotModifyFurtherError.new "This method has already been configured " \
|
|
852
|
-
|
|
851
|
+
"to call the original implementation, and cannot be modified further."
|
|
853
852
|
end
|
|
854
853
|
end
|
|
855
854
|
end
|
|
@@ -2,9 +2,6 @@ module RSpec
|
|
|
2
2
|
module Mocks
|
|
3
3
|
# @private
|
|
4
4
|
class MethodDouble
|
|
5
|
-
# @private TODO: drop in favor of FrozenError in ruby 2.5+
|
|
6
|
-
FROZEN_ERROR_MSG = /can't modify frozen/
|
|
7
|
-
|
|
8
5
|
# @private
|
|
9
6
|
attr_reader :method_name, :object, :expectations, :stubs, :method_stasher
|
|
10
7
|
|
|
@@ -24,8 +21,7 @@ module RSpec
|
|
|
24
21
|
def original_implementation_callable
|
|
25
22
|
# If original method is not present, uses the `method_missing`
|
|
26
23
|
# handler of the object. This accounts for cases where the user has not
|
|
27
|
-
# correctly defined `respond_to
|
|
28
|
-
# method handles for missing methods even if `respond_to?` is correct.
|
|
24
|
+
# correctly defined `respond_to?`.
|
|
29
25
|
@original_implementation_callable ||= original_method || method_missing_block
|
|
30
26
|
end
|
|
31
27
|
|
|
@@ -54,6 +50,8 @@ module RSpec
|
|
|
54
50
|
|
|
55
51
|
# @private
|
|
56
52
|
def object_singleton_class
|
|
53
|
+
# We can't use @object.singleton_class because this method
|
|
54
|
+
# creates a new singleton class if the object doesn't have one.
|
|
57
55
|
class << @object; self; end
|
|
58
56
|
end
|
|
59
57
|
|
|
@@ -70,8 +68,19 @@ module RSpec
|
|
|
70
68
|
|
|
71
69
|
save_original_implementation_callable!
|
|
72
70
|
definition_target.class_exec(self, method_name, @original_visibility || visibility) do |method_double, method_name, visibility|
|
|
73
|
-
|
|
74
|
-
|
|
71
|
+
if RUBY_VERSION.to_f > 3 && method_name == :respond_to?
|
|
72
|
+
define_method(method_name) do |*args, &block|
|
|
73
|
+
# This is a work around for a respond_to? check within kernel_inspect
|
|
74
|
+
if caller_locations[0].label == "Kernel#inspect"
|
|
75
|
+
super(*args, &block)
|
|
76
|
+
else
|
|
77
|
+
method_double.proxy_method_invoked(self, *args, &block)
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
else
|
|
81
|
+
define_method(method_name) do |*args, &block|
|
|
82
|
+
method_double.proxy_method_invoked(self, *args, &block)
|
|
83
|
+
end
|
|
75
84
|
end
|
|
76
85
|
# This can't be `if respond_to?(:ruby2_keywords, true)`,
|
|
77
86
|
# see https://github.com/rspec/rspec-mocks/pull/1385#issuecomment-755340298
|
|
@@ -80,14 +89,8 @@ module RSpec
|
|
|
80
89
|
end
|
|
81
90
|
|
|
82
91
|
@method_is_proxied = true
|
|
83
|
-
rescue
|
|
84
|
-
|
|
85
|
-
# RuntimeError (and FrozenError) for ruby 2.x
|
|
86
|
-
# TypeError for ruby 1.x
|
|
87
|
-
if (defined?(FrozenError) && e.is_a?(FrozenError)) || FROZEN_ERROR_MSG === e.message
|
|
88
|
-
raise ArgumentError, "Cannot proxy frozen objects, rspec-mocks relies on proxies for method stubbing and expectations."
|
|
89
|
-
end
|
|
90
|
-
raise
|
|
92
|
+
rescue FrozenError
|
|
93
|
+
raise ArgumentError, "Cannot proxy frozen objects, rspec-mocks relies on proxies for method stubbing and expectations."
|
|
91
94
|
end
|
|
92
95
|
|
|
93
96
|
# The implementation of the proxied method. Subclasses may override this
|
|
@@ -104,18 +107,15 @@ module RSpec
|
|
|
104
107
|
return unless @method_is_proxied
|
|
105
108
|
|
|
106
109
|
remove_method_from_definition_target
|
|
107
|
-
@method_stasher.restore if @method_stasher.method_is_stashed?
|
|
108
|
-
restore_original_visibility
|
|
109
110
|
|
|
110
|
-
@
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
# RuntimeError (and FrozenError) for ruby 2.x
|
|
114
|
-
# TypeError for ruby 1.x
|
|
115
|
-
if (defined?(FrozenError) && e.is_a?(FrozenError)) || FROZEN_ERROR_MSG === e.message
|
|
116
|
-
return show_frozen_warning
|
|
111
|
+
if @method_stasher.method_is_stashed?
|
|
112
|
+
@method_stasher.restore
|
|
113
|
+
restore_original_visibility
|
|
117
114
|
end
|
|
118
|
-
|
|
115
|
+
|
|
116
|
+
@method_is_proxied = false
|
|
117
|
+
rescue FrozenError
|
|
118
|
+
return show_frozen_warning
|
|
119
119
|
end
|
|
120
120
|
|
|
121
121
|
# @private
|
|
@@ -131,10 +131,7 @@ module RSpec
|
|
|
131
131
|
|
|
132
132
|
# @private
|
|
133
133
|
def restore_original_visibility
|
|
134
|
-
|
|
135
|
-
MethodReference.method_defined_at_any_visibility?(object_singleton_class, @method_name)
|
|
136
|
-
|
|
137
|
-
object_singleton_class.__send__(@original_visibility, method_name)
|
|
134
|
+
method_owner.__send__(@original_visibility, @method_name)
|
|
138
135
|
end
|
|
139
136
|
|
|
140
137
|
# @private
|
|
@@ -234,7 +231,9 @@ module RSpec
|
|
|
234
231
|
RSpec::Mocks.error_generator.raise_method_not_stubbed_error(method_name)
|
|
235
232
|
end
|
|
236
233
|
|
|
237
|
-
|
|
234
|
+
private
|
|
235
|
+
|
|
236
|
+
# Prepend alters the method lookup chain.
|
|
238
237
|
# We use an object's singleton class to define method doubles upon,
|
|
239
238
|
# however if the object has had its singleton class (as opposed to
|
|
240
239
|
# its actual class) prepended too then the the method lookup chain
|
|
@@ -244,54 +243,44 @@ module RSpec
|
|
|
244
243
|
# This code works around that by providing a mock definition target
|
|
245
244
|
# that is either the singleton class, or if necessary, a prepended module
|
|
246
245
|
# of our own.
|
|
247
|
-
#
|
|
248
|
-
if Support::RubyFeatures.module_prepends_supported?
|
|
249
|
-
|
|
250
|
-
private
|
|
251
|
-
|
|
252
|
-
# We subclass `Module` in order to be able to easily detect our prepended module.
|
|
253
|
-
RSpecPrependedModule = Class.new(Module)
|
|
254
246
|
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
end
|
|
258
|
-
|
|
259
|
-
def usable_rspec_prepended_module
|
|
260
|
-
@proxy.prepended_modules_of_singleton_class.each do |mod|
|
|
261
|
-
# If we have one of our modules prepended before one of the user's
|
|
262
|
-
# modules that defines the method, use that, since our module's
|
|
263
|
-
# definition will take precedence.
|
|
264
|
-
return mod if RSpecPrependedModule === mod
|
|
265
|
-
|
|
266
|
-
# If we hit a user module with the method defined first,
|
|
267
|
-
# we must create a new prepend module, even if one exists later,
|
|
268
|
-
# because ours will only take precedence if it comes first.
|
|
269
|
-
return new_rspec_prepended_module if mod.method_defined?(method_name)
|
|
270
|
-
end
|
|
247
|
+
# We subclass `Module` in order to be able to easily detect our prepended module.
|
|
248
|
+
RSpecPrependedModule = Class.new(Module)
|
|
271
249
|
|
|
272
|
-
|
|
273
|
-
|
|
250
|
+
def definition_target
|
|
251
|
+
@definition_target ||= usable_rspec_prepended_module || object_singleton_class
|
|
252
|
+
end
|
|
274
253
|
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
254
|
+
def usable_rspec_prepended_module
|
|
255
|
+
@proxy.prepended_modules_of_singleton_class.each do |mod|
|
|
256
|
+
# If we have one of our modules prepended before one of the user's
|
|
257
|
+
# modules that defines the method, use that, since our module's
|
|
258
|
+
# definition will take precedence.
|
|
259
|
+
return mod if RSpecPrependedModule === mod
|
|
260
|
+
|
|
261
|
+
# If we hit a user module with the method defined first,
|
|
262
|
+
# we must create a new prepend module, even if one exists later,
|
|
263
|
+
# because ours will only take precedence if it comes first.
|
|
264
|
+
return new_rspec_prepended_module if mod.method_defined?(method_name)
|
|
279
265
|
end
|
|
280
266
|
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
private
|
|
267
|
+
nil
|
|
268
|
+
end
|
|
284
269
|
|
|
285
|
-
|
|
286
|
-
|
|
270
|
+
def new_rspec_prepended_module
|
|
271
|
+
RSpecPrependedModule.new.tap do |mod|
|
|
272
|
+
@object.singleton_class.prepend mod
|
|
287
273
|
end
|
|
288
|
-
|
|
289
274
|
end
|
|
290
275
|
|
|
291
|
-
|
|
276
|
+
def method_owner
|
|
277
|
+
@method_owner ||=
|
|
278
|
+
# We do this because object.method might be overridden.
|
|
279
|
+
::RSpec::Support.method_handle_for(object, @method_name).owner
|
|
280
|
+
end
|
|
292
281
|
|
|
293
282
|
def remove_method_from_definition_target
|
|
294
|
-
definition_target.
|
|
283
|
+
definition_target.remove_method(@method_name)
|
|
295
284
|
rescue NameError
|
|
296
285
|
# This can happen when the method has been monkeyed with by
|
|
297
286
|
# something outside RSpec. This happens, for example, when
|
|
@@ -301,10 +290,11 @@ module RSpec
|
|
|
301
290
|
# Note: we could avoid rescuing this by checking
|
|
302
291
|
# `definition_target.instance_method(@method_name).owner == definition_target`,
|
|
303
292
|
# saving us from the cost of the expensive exception, but this error is
|
|
304
|
-
# extremely rare
|
|
305
|
-
#
|
|
306
|
-
#
|
|
307
|
-
#
|
|
293
|
+
# extremely rare so we'd rather avoid the cost of that check for every
|
|
294
|
+
# method double, and risk the rare situation where this exception will
|
|
295
|
+
# get raised. This was originally discovered in the core library of older
|
|
296
|
+
# unsupported Rubies, (< 3.0) but could happen in code under test
|
|
297
|
+
# during meta-programming.
|
|
308
298
|
RSpec.warn_with(
|
|
309
299
|
"WARNING: RSpec could not fully restore #{@object.inspect}." \
|
|
310
300
|
"#{@method_name}, possibly because the method has been redefined " \
|
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
RSpec::Support.require_rspec_support 'comparable_version'
|
|
2
|
-
|
|
3
1
|
module RSpec
|
|
4
2
|
module Mocks
|
|
5
3
|
# Represents a method on an object that may or may not be defined.
|
|
@@ -94,7 +92,7 @@ module RSpec
|
|
|
94
92
|
proxy = RSpec::Mocks.space.proxy_for(object)
|
|
95
93
|
respond_to = proxy.method_double_if_exists_for_message(:respond_to?)
|
|
96
94
|
|
|
97
|
-
visible = respond_to && respond_to.original_method.call(method_name) ||
|
|
95
|
+
visible = (respond_to && respond_to.original_method.call(method_name)) ||
|
|
98
96
|
object.respond_to?(method_name)
|
|
99
97
|
|
|
100
98
|
return :public if visible
|
|
@@ -124,20 +122,8 @@ module RSpec
|
|
|
124
122
|
# definition of "implemented". However, it's the best we can do.
|
|
125
123
|
alias method_defined? method_implemented?
|
|
126
124
|
|
|
127
|
-
|
|
128
|
-
|
|
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
|
|
125
|
+
def find_method(mod)
|
|
126
|
+
mod.instance_method(@method_name)
|
|
141
127
|
end
|
|
142
128
|
|
|
143
129
|
def visibility_from(mod)
|
|
@@ -162,6 +148,8 @@ module RSpec
|
|
|
162
148
|
end
|
|
163
149
|
|
|
164
150
|
def method_defined?(object)
|
|
151
|
+
# We don't want to create singleton class if it doesn't exist,
|
|
152
|
+
# so we don't use `object.singleton_class`.
|
|
165
153
|
(class << object; self; end).method_defined?(@method_name)
|
|
166
154
|
end
|
|
167
155
|
|
|
@@ -192,16 +180,10 @@ module RSpec
|
|
|
192
180
|
uses_class_new?(klass)
|
|
193
181
|
end
|
|
194
182
|
|
|
195
|
-
|
|
196
|
-
CLASS_NEW = ::Class.instance_method(:new)
|
|
183
|
+
CLASS_NEW = ::Class.instance_method(:new)
|
|
197
184
|
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
end
|
|
201
|
-
else # Ruby 2's Method#== is too strict
|
|
202
|
-
def self.uses_class_new?(klass)
|
|
203
|
-
::RSpec::Support.method_handle_for(klass, :new).owner == ::Class
|
|
204
|
-
end
|
|
185
|
+
def self.uses_class_new?(klass)
|
|
186
|
+
::RSpec::Support.method_handle_for(klass, :new) == CLASS_NEW.bind(klass)
|
|
205
187
|
end
|
|
206
188
|
|
|
207
189
|
def with_signature
|
|
@@ -28,7 +28,7 @@ module RSpec
|
|
|
28
28
|
end
|
|
29
29
|
end
|
|
30
30
|
|
|
31
|
-
Minitest::Test.
|
|
31
|
+
Minitest::Test.__send__(:include, RSpec::Mocks::MinitestIntegration)
|
|
32
32
|
|
|
33
33
|
if defined?(::Minitest::Expectation)
|
|
34
34
|
if defined?(::RSpec::Expectations) && ::Minitest::Expectation.method_defined?(:to)
|
|
@@ -248,7 +248,6 @@ module RSpec
|
|
|
248
248
|
end
|
|
249
249
|
|
|
250
250
|
if Array === @transfer_nested_constants
|
|
251
|
-
@transfer_nested_constants = @transfer_nested_constants.map(&:to_s) if RUBY_VERSION == '1.8.7'
|
|
252
251
|
undefined_constants = @transfer_nested_constants - constants_defined_on(@original_value)
|
|
253
252
|
|
|
254
253
|
if undefined_constants.any?
|
|
@@ -27,14 +27,8 @@ module RSpec
|
|
|
27
27
|
end
|
|
28
28
|
end
|
|
29
29
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
!name_of(mod)
|
|
33
|
-
end
|
|
34
|
-
else # 1.8.7
|
|
35
|
-
def self.anonymous_module?(mod)
|
|
36
|
-
name_of(mod) == ""
|
|
37
|
-
end
|
|
30
|
+
def self.anonymous_module?(mod)
|
|
31
|
+
!name_of(mod)
|
|
38
32
|
end
|
|
39
33
|
private_class_method :anonymous_module?
|
|
40
34
|
|
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
RSpec::Support.require_rspec_support 'reentrant_mutex'
|
|
2
|
-
|
|
3
1
|
module RSpec
|
|
4
2
|
module Mocks
|
|
5
3
|
# @private
|
|
@@ -7,7 +5,6 @@ module RSpec
|
|
|
7
5
|
def initialize
|
|
8
6
|
@expectations = []
|
|
9
7
|
@invocation_order = []
|
|
10
|
-
@invocation_order_mutex = Support::Mutex.new
|
|
11
8
|
@index = 0
|
|
12
9
|
end
|
|
13
10
|
|
|
@@ -17,9 +14,7 @@ module RSpec
|
|
|
17
14
|
end
|
|
18
15
|
|
|
19
16
|
def invoked(message)
|
|
20
|
-
@
|
|
21
|
-
@invocation_order << message
|
|
22
|
-
end
|
|
17
|
+
@invocation_order << message
|
|
23
18
|
end
|
|
24
19
|
|
|
25
20
|
# @private
|
|
@@ -52,9 +47,7 @@ module RSpec
|
|
|
52
47
|
|
|
53
48
|
def clear
|
|
54
49
|
@index = 0
|
|
55
|
-
@
|
|
56
|
-
@invocation_order.clear
|
|
57
|
-
end
|
|
50
|
+
@invocation_order.clear
|
|
58
51
|
@expectations.clear
|
|
59
52
|
end
|
|
60
53
|
|
|
@@ -73,15 +66,11 @@ module RSpec
|
|
|
73
66
|
end
|
|
74
67
|
|
|
75
68
|
def invoked_expectations
|
|
76
|
-
@
|
|
77
|
-
@expectations.select { |e| e.ordered? && @invocation_order.include?(e) }
|
|
78
|
-
end
|
|
69
|
+
@expectations.select { |e| e.ordered? && @invocation_order.include?(e) }
|
|
79
70
|
end
|
|
80
71
|
|
|
81
72
|
def expected_invocations
|
|
82
|
-
@
|
|
83
|
-
@invocation_order.map { |invocation| expectation_for(invocation) }.compact
|
|
84
|
-
end
|
|
73
|
+
@invocation_order.map { |invocation| expectation_for(invocation) }.compact
|
|
85
74
|
end
|
|
86
75
|
|
|
87
76
|
def expectation_for(message)
|
data/lib/rspec/mocks/proxy.rb
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
RSpec::Support.require_rspec_support
|
|
1
|
+
RSpec::Support.require_rspec_support "reentrant_mutex"
|
|
2
2
|
|
|
3
3
|
module RSpec
|
|
4
4
|
module Mocks
|
|
@@ -240,20 +240,14 @@ module RSpec
|
|
|
240
240
|
:public
|
|
241
241
|
end
|
|
242
242
|
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
# is only in the ancestor list when there are prepended modules.
|
|
249
|
-
singleton_index = ancestors.index(klass) || 0
|
|
250
|
-
|
|
251
|
-
ancestors[0, singleton_index]
|
|
252
|
-
end
|
|
243
|
+
def self.prepended_modules_of(klass)
|
|
244
|
+
ancestors = klass.ancestors
|
|
245
|
+
singleton_index = ancestors.index(klass)
|
|
246
|
+
ancestors[0, singleton_index]
|
|
247
|
+
end
|
|
253
248
|
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
end
|
|
249
|
+
def prepended_modules_of_singleton_class
|
|
250
|
+
@prepended_modules_of_singleton_class ||= RSpec::Mocks::Proxy.prepended_modules_of(@object.singleton_class)
|
|
257
251
|
end
|
|
258
252
|
|
|
259
253
|
# @private
|
|
@@ -409,19 +403,6 @@ module RSpec
|
|
|
409
403
|
|
|
410
404
|
return super unless unbound_method
|
|
411
405
|
unbound_method.bind(object)
|
|
412
|
-
# :nocov:
|
|
413
|
-
rescue TypeError
|
|
414
|
-
if RUBY_VERSION == '1.8.7'
|
|
415
|
-
# In MRI 1.8.7, a singleton method on a class cannot be rebound to its subclass
|
|
416
|
-
if unbound_method && unbound_method.owner.ancestors.first != unbound_method.owner
|
|
417
|
-
# This is a singleton method; we can't do anything with it
|
|
418
|
-
# But we can work around this using a different implementation
|
|
419
|
-
double = method_double_from_ancestor_for(message)
|
|
420
|
-
return object.method(double.method_stasher.stashed_method_name)
|
|
421
|
-
end
|
|
422
|
-
end
|
|
423
|
-
raise
|
|
424
|
-
# :nocov:
|
|
425
406
|
end
|
|
426
407
|
|
|
427
408
|
protected
|
data/lib/rspec/mocks/space.rb
CHANGED
|
@@ -137,6 +137,8 @@ module RSpec
|
|
|
137
137
|
|
|
138
138
|
# We access the ancestors through the singleton class, to avoid calling
|
|
139
139
|
# `class` in case `class` has been stubbed.
|
|
140
|
+
# We can't use `object.singleton_class` here, as this method creates
|
|
141
|
+
# a new singleton class for the object if the object doesn't have one.
|
|
140
142
|
(class << object; ancestors; end).map do |klass|
|
|
141
143
|
any_instance_recorders[klass.__id__]
|
|
142
144
|
end.compact
|
|
@@ -185,23 +187,8 @@ module RSpec
|
|
|
185
187
|
any_instance_recorders[id] = AnyInstance::Recorder.new(klass)
|
|
186
188
|
end
|
|
187
189
|
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
def id_for(object)
|
|
192
|
-
id = object.__id__
|
|
193
|
-
|
|
194
|
-
return id if object.equal?(::ObjectSpace._id2ref(id))
|
|
195
|
-
# this suggests that object.__id__ is proxying through to some wrapped object
|
|
196
|
-
|
|
197
|
-
object.instance_exec do
|
|
198
|
-
@__id_for_rspec_mocks_space ||= ::SecureRandom.uuid
|
|
199
|
-
end
|
|
200
|
-
end
|
|
201
|
-
else
|
|
202
|
-
def id_for(object)
|
|
203
|
-
object.__id__
|
|
204
|
-
end
|
|
190
|
+
def id_for(object)
|
|
191
|
+
object.__id__
|
|
205
192
|
end
|
|
206
193
|
end
|
|
207
194
|
|
|
@@ -87,21 +87,23 @@ module RSpec
|
|
|
87
87
|
end
|
|
88
88
|
end
|
|
89
89
|
|
|
90
|
+
visibility = proxy.visibility_for(message)
|
|
91
|
+
|
|
90
92
|
# Defined private and protected methods will still trigger `method_missing`
|
|
91
93
|
# when called publicly. We want ruby's method visibility error to get raised,
|
|
92
94
|
# so we simply delegate to `super` in that case.
|
|
95
|
+
# return super if visibility == :private || visibility == :protected
|
|
93
96
|
# ...well, we would delegate to `super`, but there's a JRuby
|
|
94
97
|
# bug, so we raise our own visibility error instead:
|
|
95
98
|
# https://github.com/jruby/jruby/issues/1398
|
|
96
|
-
|
|
99
|
+
# Only works without this workaround with JRuby 9.2
|
|
97
100
|
if visibility == :private || visibility == :protected
|
|
98
101
|
ErrorGenerator.new(self).raise_non_public_error(
|
|
99
102
|
message, visibility
|
|
100
103
|
)
|
|
101
104
|
end
|
|
102
105
|
|
|
103
|
-
|
|
104
|
-
raise NoMethodError if [:to_a, :to_ary].include? message
|
|
106
|
+
raise NoMethodError if message == :to_ary || message == :to_a
|
|
105
107
|
proxy.raise_unexpected_message_error(message, args)
|
|
106
108
|
end
|
|
107
109
|
|