rspec-mocks 2.99.4 → 3.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 +14 -6
- checksums.yaml.gz.sig +2 -0
- data.tar.gz.sig +1 -0
- data/Changelog.md +89 -105
- data/License.txt +1 -0
- data/README.md +77 -57
- data/features/argument_matchers/explicit.feature +5 -5
- data/features/argument_matchers/general_matchers.feature +10 -10
- data/features/argument_matchers/type_matchers.feature +3 -3
- data/features/message_expectations/allow_any_instance_of.feature +1 -1
- data/features/message_expectations/any_instance.feature +27 -5
- data/features/message_expectations/call_original.feature +2 -2
- data/features/message_expectations/expect_message_using_expect.feature +2 -2
- data/features/message_expectations/expect_message_using_should_receive.feature +2 -2
- data/features/message_expectations/receive_counts.feature +7 -7
- data/features/message_expectations/warn_when_expectation_is_set_on_nil.feature +3 -3
- data/features/method_stubs/README.md +3 -0
- data/features/method_stubs/any_instance.feature +11 -11
- data/features/method_stubs/as_null_object.feature +4 -4
- data/features/method_stubs/simple_return_value_with_stub.feature +7 -7
- data/features/method_stubs/stub_chain.feature +3 -3
- data/features/method_stubs/stub_implementation.feature +2 -2
- data/features/method_stubs/to_ary.feature +2 -2
- data/features/mutating_constants/hiding_defined_constant.feature +2 -2
- data/features/mutating_constants/stub_defined_constant.feature +5 -5
- data/features/mutating_constants/stub_undefined_constant.feature +6 -6
- data/features/outside_rspec/configuration.feature +0 -2
- data/features/outside_rspec/standalone.feature +1 -1
- data/features/spies/spy_partial_mock_method.feature +2 -2
- data/features/spies/spy_pure_mock_method.feature +5 -5
- data/features/spies/spy_unstubbed_method.feature +1 -1
- data/features/support/env.rb +10 -1
- data/features/test_frameworks/test_unit.feature +1 -1
- data/features/verifying_doubles/class_doubles.feature +88 -0
- data/features/verifying_doubles/dynamic_classes.feature +72 -0
- data/features/verifying_doubles/introduction.feature +85 -0
- data/features/verifying_doubles/object_doubles.feature +65 -0
- data/features/verifying_doubles/partial_doubles.feature +34 -0
- data/lib/rspec/mocks.rb +8 -34
- data/lib/rspec/mocks/any_instance/chain.rb +4 -34
- data/lib/rspec/mocks/any_instance/expectation_chain.rb +14 -4
- data/lib/rspec/mocks/any_instance/message_chains.rb +27 -12
- data/lib/rspec/mocks/any_instance/recorder.rb +23 -31
- data/lib/rspec/mocks/any_instance/stub_chain.rb +9 -4
- data/lib/rspec/mocks/argument_list_matcher.rb +8 -1
- data/lib/rspec/mocks/argument_matchers.rb +26 -12
- data/lib/rspec/mocks/arity_calculator.rb +66 -0
- data/lib/rspec/mocks/configuration.rb +42 -14
- data/lib/rspec/mocks/error_generator.rb +34 -10
- data/lib/rspec/mocks/example_methods.rb +64 -19
- data/lib/rspec/mocks/extensions/marshal.rb +0 -15
- data/lib/rspec/mocks/framework.rb +4 -4
- data/lib/rspec/mocks/instance_method_stasher.rb +80 -62
- data/lib/rspec/mocks/matchers/have_received.rb +18 -14
- data/lib/rspec/mocks/matchers/receive.rb +29 -7
- data/lib/rspec/mocks/matchers/receive_messages.rb +72 -0
- data/lib/rspec/mocks/message_expectation.rb +95 -148
- data/lib/rspec/mocks/method_double.rb +77 -139
- data/lib/rspec/mocks/method_reference.rb +95 -0
- data/lib/rspec/mocks/mock.rb +1 -1
- data/lib/rspec/mocks/mutate_const.rb +12 -9
- data/lib/rspec/mocks/object_reference.rb +90 -0
- data/lib/rspec/mocks/order_group.rb +49 -7
- data/lib/rspec/mocks/proxy.rb +72 -33
- data/lib/rspec/mocks/proxy_for_nil.rb +2 -2
- data/lib/rspec/mocks/space.rb +13 -18
- data/lib/rspec/mocks/stub_chain.rb +2 -2
- data/lib/rspec/mocks/syntax.rb +61 -36
- data/lib/rspec/mocks/targets.rb +40 -19
- data/lib/rspec/mocks/test_double.rb +12 -56
- data/lib/rspec/mocks/verifying_double.rb +77 -0
- data/lib/rspec/mocks/verifying_message_expecation.rb +60 -0
- data/lib/rspec/mocks/verifying_proxy.rb +151 -0
- data/lib/rspec/mocks/version.rb +1 -1
- data/spec/rspec/mocks/and_call_original_spec.rb +34 -30
- data/spec/rspec/mocks/and_yield_spec.rb +2 -2
- data/spec/rspec/mocks/any_instance/message_chains_spec.rb +1 -1
- data/spec/rspec/mocks/any_instance_spec.rb +53 -260
- data/spec/rspec/mocks/argument_expectation_spec.rb +4 -4
- data/spec/rspec/mocks/arity_calculator_spec.rb +95 -0
- data/spec/rspec/mocks/array_including_matcher_spec.rb +41 -0
- data/spec/rspec/mocks/at_least_spec.rb +4 -32
- data/spec/rspec/mocks/block_return_value_spec.rb +4 -135
- data/spec/rspec/mocks/combining_implementation_instructions_spec.rb +10 -11
- data/spec/rspec/mocks/configuration_spec.rb +79 -0
- data/spec/rspec/mocks/double_spec.rb +10 -78
- data/spec/rspec/mocks/extensions/marshal_spec.rb +0 -8
- data/spec/rspec/mocks/failing_argument_matchers_spec.rb +49 -4
- data/spec/rspec/mocks/instance_method_stasher_spec.rb +20 -3
- data/spec/rspec/mocks/matchers/have_received_spec.rb +74 -0
- data/spec/rspec/mocks/matchers/receive_messages_spec.rb +140 -0
- data/spec/rspec/mocks/matchers/receive_spec.rb +82 -42
- data/spec/rspec/mocks/methods_spec.rb +1 -1
- data/spec/rspec/mocks/{bug_report_830_spec.rb → mock_expectation_error_spec.rb} +4 -3
- data/spec/rspec/mocks/mock_ordering_spec.rb +11 -0
- data/spec/rspec/mocks/mock_space_spec.rb +10 -1
- data/spec/rspec/mocks/mock_spec.rb +26 -82
- data/spec/rspec/mocks/multiple_return_value_spec.rb +1 -1
- data/spec/rspec/mocks/mutate_const_spec.rb +18 -5
- data/spec/rspec/mocks/null_object_mock_spec.rb +6 -4
- data/spec/rspec/mocks/options_hash_spec.rb +3 -3
- data/spec/rspec/mocks/order_group_spec.rb +27 -0
- data/spec/rspec/mocks/partial_mock_spec.rb +101 -1
- data/spec/rspec/mocks/passing_argument_matchers_spec.rb +3 -20
- data/spec/rspec/mocks/record_messages_spec.rb +4 -4
- data/spec/rspec/mocks/serialization_spec.rb +4 -6
- data/spec/rspec/mocks/space_spec.rb +3 -3
- data/spec/rspec/mocks/stub_chain_spec.rb +0 -12
- data/spec/rspec/mocks/stub_spec.rb +23 -44
- data/spec/rspec/mocks/test_double_spec.rb +3 -22
- data/spec/rspec/mocks/verifying_double_spec.rb +327 -0
- data/spec/rspec/mocks/verifying_message_expecation_spec.rb +68 -0
- data/spec/rspec/mocks_spec.rb +16 -39
- data/spec/spec_helper.rb +29 -18
- metadata +131 -86
- metadata.gz.sig +1 -0
- data/features/message_expectations/expect_any_instance_of.feature +0 -27
- data/lib/rspec/mocks/caller_filter.rb +0 -60
- data/lib/rspec/mocks/deprecation.rb +0 -26
- data/lib/rspec/mocks/extensions/instance_exec.rb +0 -34
- data/lib/rspec/mocks/extensions/proc.rb +0 -63
- data/lib/spec/mocks.rb +0 -4
- data/spec/rspec/mocks/and_return_spec.rb +0 -17
- data/spec/rspec/mocks/any_number_of_times_spec.rb +0 -36
- data/spec/rspec/mocks/before_all_spec.rb +0 -74
- data/spec/rspec/mocks/bug_report_10260_spec.rb +0 -8
- data/spec/rspec/mocks/bug_report_10263_spec.rb +0 -27
- data/spec/rspec/mocks/bug_report_11545_spec.rb +0 -32
- data/spec/rspec/mocks/bug_report_496_spec.rb +0 -17
- data/spec/rspec/mocks/bug_report_600_spec.rb +0 -22
- data/spec/rspec/mocks/bug_report_7611_spec.rb +0 -16
- data/spec/rspec/mocks/bug_report_8165_spec.rb +0 -31
- data/spec/rspec/mocks/bug_report_957_spec.rb +0 -22
@@ -1,9 +1,9 @@
|
|
1
1
|
module RSpec
|
2
2
|
module Mocks
|
3
3
|
# @private
|
4
|
-
class MethodDouble
|
4
|
+
class MethodDouble
|
5
5
|
# @private
|
6
|
-
attr_reader :method_name, :object
|
6
|
+
attr_reader :method_name, :object, :expectations, :stubs
|
7
7
|
|
8
8
|
# @private
|
9
9
|
def initialize(object, method_name, proxy)
|
@@ -11,21 +11,27 @@ module RSpec
|
|
11
11
|
@object = object
|
12
12
|
@proxy = proxy
|
13
13
|
|
14
|
-
@
|
14
|
+
@original_visibility = nil
|
15
|
+
@method_stasher = InstanceMethodStasher.new(object, method_name)
|
15
16
|
@method_is_proxied = false
|
16
|
-
|
17
|
-
|
17
|
+
@expectations = []
|
18
|
+
@stubs = []
|
18
19
|
end
|
19
20
|
|
20
|
-
|
21
|
-
|
22
|
-
|
21
|
+
def original_method
|
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_method ||=
|
27
|
+
@method_stasher.original_method ||
|
28
|
+
@proxy.method_handle_for(method_name) ||
|
29
|
+
Proc.new do |*args, &block|
|
30
|
+
@object.__send__(:method_missing, @method_name, *args, &block)
|
31
|
+
end
|
23
32
|
end
|
24
33
|
|
25
|
-
|
26
|
-
def stubs
|
27
|
-
self[:stubs]
|
28
|
-
end
|
34
|
+
alias_method :save_original_method!, :original_method
|
29
35
|
|
30
36
|
# @private
|
31
37
|
def visibility
|
@@ -40,119 +46,6 @@ module RSpec
|
|
40
46
|
end
|
41
47
|
end
|
42
48
|
|
43
|
-
class ProcWithBlock < Struct.new(:object, :method_name)
|
44
|
-
|
45
|
-
def call(*args, &block)
|
46
|
-
self.object.__send__(:method_missing, self.method_name, *args, &block)
|
47
|
-
end
|
48
|
-
|
49
|
-
end
|
50
|
-
|
51
|
-
# @private
|
52
|
-
def original_method
|
53
|
-
if @method_stasher.method_is_stashed?
|
54
|
-
# Example: a singleton method defined on @object
|
55
|
-
::RSpec::Mocks.method_handle_for(@object, @method_stasher.stashed_method_name)
|
56
|
-
elsif meth = original_unrecorded_any_instance_method
|
57
|
-
# Example: a method that has been mocked through
|
58
|
-
# klass.any_instance.should_receive(:msg).and_call_original
|
59
|
-
# any_instance.should_receive(:msg) causes the method to be
|
60
|
-
# replaced with a proxy method, and then `and_call_original`
|
61
|
-
# is recorded and played back on the object instance. We need
|
62
|
-
# special handling here to get a handle on the original method
|
63
|
-
# object rather than the proxy method.
|
64
|
-
meth
|
65
|
-
else
|
66
|
-
# Example: an instance method defined on one of @object's ancestors.
|
67
|
-
original_method_from_ancestry
|
68
|
-
end
|
69
|
-
rescue NameError
|
70
|
-
# We have no way of knowing if the object's method_missing
|
71
|
-
# will handle this message or not...but we can at least try.
|
72
|
-
# If it's not handled, a `NoMethodError` will be raised, just
|
73
|
-
# like normally.
|
74
|
-
ProcWithBlock.new(@object,@method_name)
|
75
|
-
end
|
76
|
-
|
77
|
-
def original_unrecorded_any_instance_method
|
78
|
-
return nil unless any_instance_class_recorder_observing_method?(@object.class)
|
79
|
-
alias_name = ::RSpec::Mocks.any_instance_recorder_for(@object.class).build_alias_method_name(@method_name)
|
80
|
-
@object.method(alias_name)
|
81
|
-
end
|
82
|
-
|
83
|
-
def any_instance_class_recorder_observing_method?(klass)
|
84
|
-
return true if ::RSpec::Mocks.any_instance_recorder_for(klass).already_observing?(@method_name)
|
85
|
-
superklass = klass.superclass
|
86
|
-
return false if superklass.nil?
|
87
|
-
any_instance_class_recorder_observing_method?(superklass)
|
88
|
-
end
|
89
|
-
|
90
|
-
our_singleton_class = class << self; self; end
|
91
|
-
if our_singleton_class.ancestors.include? our_singleton_class
|
92
|
-
# In Ruby 2.1, ancestors include the correct ancestors, including the singleton classes
|
93
|
-
def original_method_from_ancestry
|
94
|
-
# Lookup in the ancestry, skipping over the singleton class itself
|
95
|
-
original_method_from_ancestor(object_singleton_class.ancestors.drop(1))
|
96
|
-
end
|
97
|
-
else
|
98
|
-
# @private
|
99
|
-
def original_method_from_ancestry
|
100
|
-
original_method_from_ancestor(object_singleton_class.ancestors)
|
101
|
-
rescue NameError
|
102
|
-
raise unless @object.respond_to?(:superclass)
|
103
|
-
|
104
|
-
# Example: a singleton method defined on @object's superclass.
|
105
|
-
#
|
106
|
-
# Note: we have to give precedence to instance methods
|
107
|
-
# defined on @object's class, because in a case like:
|
108
|
-
#
|
109
|
-
# `klass.should_receive(:new).and_call_original`
|
110
|
-
#
|
111
|
-
# ...we want `Class#new` bound to `klass` (which will return
|
112
|
-
# an instance of `klass`), not `klass.superclass.new` (which
|
113
|
-
# would return an instance of `klass.superclass`).
|
114
|
-
original_method_from_superclass
|
115
|
-
end
|
116
|
-
end
|
117
|
-
|
118
|
-
def original_method_from_ancestor(ancestors)
|
119
|
-
klass, *rest = ancestors
|
120
|
-
klass.instance_method(@method_name).bind(@object)
|
121
|
-
rescue NameError
|
122
|
-
raise if rest.empty?
|
123
|
-
original_method_from_ancestor(rest)
|
124
|
-
end
|
125
|
-
|
126
|
-
if RUBY_VERSION.to_f > 1.8
|
127
|
-
# @private
|
128
|
-
def original_method_from_superclass
|
129
|
-
@object.superclass.
|
130
|
-
singleton_class.
|
131
|
-
instance_method(@method_name).
|
132
|
-
bind(@object)
|
133
|
-
end
|
134
|
-
else
|
135
|
-
# Our implementation for 1.9 (above) causes an error on 1.8:
|
136
|
-
# TypeError: singleton method bound for a different object
|
137
|
-
#
|
138
|
-
# This doesn't work quite right in all circumstances but it's the
|
139
|
-
# best we can do.
|
140
|
-
# @private
|
141
|
-
def original_method_from_superclass
|
142
|
-
::Kernel.warn <<-WARNING.gsub(/^ +\|/, '')
|
143
|
-
|
|
144
|
-
|WARNING: On ruby 1.8, rspec-mocks is unable to bind the original
|
145
|
-
|`#{@method_name}` method to your partial mock object (#{@object})
|
146
|
-
|for `and_call_original`. The superclass's `#{@method_name}` is being
|
147
|
-
|used instead; however, it may not work correctly when executed due
|
148
|
-
|to the fact that `self` will be #{@object.superclass}, not #{@object}.
|
149
|
-
|
|
150
|
-
|Called from: #{CallerFilter.first_non_rspec_line}
|
151
|
-
WARNING
|
152
|
-
|
153
|
-
@object.superclass.method(@method_name)
|
154
|
-
end
|
155
|
-
end
|
156
49
|
# @private
|
157
50
|
def object_singleton_class
|
158
51
|
class << @object; self; end
|
@@ -160,7 +53,7 @@ module RSpec
|
|
160
53
|
|
161
54
|
# @private
|
162
55
|
def configure_method
|
163
|
-
@original_visibility =
|
56
|
+
@original_visibility = [visibility, method_name]
|
164
57
|
@method_stasher.stash unless @method_is_proxied
|
165
58
|
define_proxy_method
|
166
59
|
end
|
@@ -169,18 +62,24 @@ module RSpec
|
|
169
62
|
def define_proxy_method
|
170
63
|
return if @method_is_proxied
|
171
64
|
|
172
|
-
|
173
|
-
|
174
|
-
|
65
|
+
save_original_method!
|
66
|
+
|
67
|
+
object_singleton_class.class_exec(self, method_name, visibility) do |method_double, method_name, visibility|
|
68
|
+
define_method(method_name) do |*args, &block|
|
69
|
+
method_double.proxy_method_invoked(self, *args, &block)
|
175
70
|
end
|
176
|
-
|
177
|
-
|
71
|
+
self.__send__ visibility, method_name
|
72
|
+
end
|
73
|
+
|
178
74
|
@method_is_proxied = true
|
179
75
|
end
|
180
76
|
|
77
|
+
# The implementation of the proxied method. Subclasses may override this
|
78
|
+
# method to perform additional operations.
|
79
|
+
#
|
181
80
|
# @private
|
182
|
-
def
|
183
|
-
|
81
|
+
def proxy_method_invoked(obj, *args, &block)
|
82
|
+
@proxy.message_received method_name, *args, &block
|
184
83
|
end
|
185
84
|
|
186
85
|
# @private
|
@@ -188,7 +87,9 @@ module RSpec
|
|
188
87
|
return unless @method_is_proxied
|
189
88
|
|
190
89
|
object_singleton_class.__send__(:remove_method, @method_name)
|
191
|
-
@method_stasher.
|
90
|
+
if @method_stasher.method_is_stashed?
|
91
|
+
@method_stasher.restore
|
92
|
+
end
|
192
93
|
restore_original_visibility
|
193
94
|
|
194
95
|
@method_is_proxied = false
|
@@ -196,8 +97,11 @@ module RSpec
|
|
196
97
|
|
197
98
|
# @private
|
198
99
|
def restore_original_visibility
|
199
|
-
return unless
|
200
|
-
|
100
|
+
return unless @original_visibility &&
|
101
|
+
(object_singleton_class.method_defined?(@method_name) ||
|
102
|
+
object_singleton_class.private_method_defined?(@method_name))
|
103
|
+
|
104
|
+
object_singleton_class.__send__(*@original_visibility)
|
201
105
|
end
|
202
106
|
|
203
107
|
# @private
|
@@ -217,10 +121,18 @@ module RSpec
|
|
217
121
|
stubs.clear
|
218
122
|
end
|
219
123
|
|
124
|
+
# The type of message expectation to create has been extracted to its own
|
125
|
+
# method so that subclasses can override it.
|
126
|
+
#
|
127
|
+
# @private
|
128
|
+
def message_expectation_class
|
129
|
+
MessageExpectation
|
130
|
+
end
|
131
|
+
|
220
132
|
# @private
|
221
133
|
def add_expectation(error_generator, expectation_ordering, expected_from, opts, &implementation)
|
222
134
|
configure_method
|
223
|
-
expectation =
|
135
|
+
expectation = message_expectation_class.new(error_generator, expectation_ordering,
|
224
136
|
expected_from, self, 1, opts, &implementation)
|
225
137
|
expectations << expectation
|
226
138
|
expectation
|
@@ -229,18 +141,44 @@ module RSpec
|
|
229
141
|
# @private
|
230
142
|
def build_expectation(error_generator, expectation_ordering)
|
231
143
|
expected_from = IGNORED_BACKTRACE_LINE
|
232
|
-
|
144
|
+
message_expectation_class.new(error_generator, expectation_ordering, expected_from, self)
|
233
145
|
end
|
234
146
|
|
235
147
|
# @private
|
236
148
|
def add_stub(error_generator, expectation_ordering, expected_from, opts={}, &implementation)
|
237
149
|
configure_method
|
238
|
-
stub =
|
150
|
+
stub = message_expectation_class.new(error_generator, expectation_ordering, expected_from,
|
239
151
|
self, :any, opts, &implementation)
|
240
152
|
stubs.unshift stub
|
241
153
|
stub
|
242
154
|
end
|
243
155
|
|
156
|
+
# A simple stub can only return a concrete value for a message, and
|
157
|
+
# cannot match on arguments. It is used as an optimization over
|
158
|
+
# `add_stub` / `add_expectation` where it is known in advance that this
|
159
|
+
# is all that will be required of a stub, such as when passing attributes
|
160
|
+
# to the `double` example method. They do not stash or restore existing method
|
161
|
+
# definitions.
|
162
|
+
#
|
163
|
+
# @private
|
164
|
+
def add_simple_stub(method_name, response)
|
165
|
+
setup_simple_method_double method_name, response, stubs
|
166
|
+
end
|
167
|
+
|
168
|
+
# @private
|
169
|
+
def add_simple_expectation(method_name, response, error_generator, backtrace_line)
|
170
|
+
setup_simple_method_double method_name, response, expectations, error_generator, backtrace_line
|
171
|
+
end
|
172
|
+
|
173
|
+
# @private
|
174
|
+
def setup_simple_method_double(method_name, response, collection, error_generator = nil, backtrace_line = nil)
|
175
|
+
define_proxy_method
|
176
|
+
|
177
|
+
me = SimpleMessageExpectation.new(method_name, response, error_generator, backtrace_line)
|
178
|
+
collection.unshift me
|
179
|
+
me
|
180
|
+
end
|
181
|
+
|
244
182
|
# @private
|
245
183
|
def add_default_stub(*args, &implementation)
|
246
184
|
return if stubs.any?
|
@@ -0,0 +1,95 @@
|
|
1
|
+
module RSpec
|
2
|
+
module Mocks
|
3
|
+
# Represents a method on a module that may or may not be defined.
|
4
|
+
#
|
5
|
+
# @private
|
6
|
+
class MethodReference
|
7
|
+
def initialize(module_reference, method_name)
|
8
|
+
@module_reference = module_reference
|
9
|
+
@method_name = method_name
|
10
|
+
end
|
11
|
+
|
12
|
+
# A method is implemented if sending the message does not result in
|
13
|
+
# a `NoMethodError`. It might be dynamically implemented by
|
14
|
+
# `method_missing`.
|
15
|
+
def implemented?
|
16
|
+
@module_reference.when_loaded do |m|
|
17
|
+
method_implemented?(m)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
# A method is defined if we are able to get a `Method` object for it.
|
22
|
+
# In that case, we can assert against metadata like the arity.
|
23
|
+
def defined?
|
24
|
+
@module_reference.when_loaded do |m|
|
25
|
+
method_defined?(m)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def when_defined
|
30
|
+
if original = original_method
|
31
|
+
yield original
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
# Yields to the block if the method is not implemented.
|
36
|
+
def when_unimplemented
|
37
|
+
yield unless implemented?
|
38
|
+
end
|
39
|
+
|
40
|
+
private
|
41
|
+
def original_method
|
42
|
+
@module_reference.when_loaded do |m|
|
43
|
+
self.defined? && find_method(m)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
# @private
|
49
|
+
class InstanceMethodReference < MethodReference
|
50
|
+
private
|
51
|
+
def method_implemented?(m)
|
52
|
+
m.method_defined?(@method_name)
|
53
|
+
end
|
54
|
+
|
55
|
+
# Ideally, we'd use `respond_to?` for `method_implemented?` but we need a
|
56
|
+
# reference to an instance to do that and we don't have one. Note that
|
57
|
+
# we may get false negatives: if the method is implemented via
|
58
|
+
# `method_missing`, we'll return `false` even though it meets our
|
59
|
+
# definition of "implemented". However, it's the best we can do.
|
60
|
+
alias method_defined? method_implemented?
|
61
|
+
|
62
|
+
# works around the fact that repeated calls for method parameters will
|
63
|
+
# falsely return empty arrays on JRuby in certain circumstances, this
|
64
|
+
# is necessary here because we can't dup/clone UnboundMethods.
|
65
|
+
#
|
66
|
+
# This is necessary due to a bug in JRuby prior to 1.7.5 fixed in:
|
67
|
+
# https://github.com/jruby/jruby/commit/99a0613fe29935150d76a9a1ee4cf2b4f63f4a27
|
68
|
+
if RUBY_PLATFORM == 'java' && JRUBY_VERSION.split('.')[-1].to_i < 5
|
69
|
+
def find_method(m)
|
70
|
+
m.dup.instance_method(@method_name)
|
71
|
+
end
|
72
|
+
else
|
73
|
+
def find_method(m)
|
74
|
+
m.instance_method(@method_name)
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
# @private
|
80
|
+
class ObjectMethodReference < MethodReference
|
81
|
+
private
|
82
|
+
def method_implemented?(m)
|
83
|
+
m.respond_to?(@method_name)
|
84
|
+
end
|
85
|
+
|
86
|
+
def method_defined?(m)
|
87
|
+
(class << m; self; end).method_defined?(@method_name)
|
88
|
+
end
|
89
|
+
|
90
|
+
def find_method(m)
|
91
|
+
m.method(@method_name)
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
data/lib/rspec/mocks/mock.rb
CHANGED
@@ -64,7 +64,7 @@ module RSpec
|
|
64
64
|
|
65
65
|
def recursive_const_defined?(const_name)
|
66
66
|
normalize_const_name(const_name).split('::').inject([Object, '']) do |(mod, full_name), name|
|
67
|
-
yield(full_name, name) if block_given? && !
|
67
|
+
yield(full_name, name) if block_given? && !(Module === mod)
|
68
68
|
return false unless const_defined_on?(mod, name)
|
69
69
|
[get_const_defined_on(mod, name), [mod, name].join('::')]
|
70
70
|
end
|
@@ -167,16 +167,16 @@ module RSpec
|
|
167
167
|
# so you can stub constants in other contexts (e.g. helper
|
168
168
|
# classes).
|
169
169
|
def self.stub(constant_name, value, options = {})
|
170
|
-
space = RSpec::Mocks.space
|
171
|
-
space.print_out_of_example_deprecation if space.outside_example
|
172
|
-
|
173
170
|
mutator = if recursive_const_defined?(constant_name, &raise_on_invalid_const)
|
174
171
|
DefinedConstantReplacer
|
175
172
|
else
|
176
173
|
UndefinedConstantSetter
|
177
174
|
end
|
178
175
|
|
179
|
-
mutate(mutator.new(constant_name, value, options
|
176
|
+
mutate(mutator.new(constant_name, value, options.fetch(
|
177
|
+
:transfer_nested_constants,
|
178
|
+
RSpec::Mocks.configuration.transfer_nested_constants?
|
179
|
+
)))
|
180
180
|
value
|
181
181
|
end
|
182
182
|
|
@@ -190,9 +190,6 @@ module RSpec
|
|
190
190
|
# so you can hide constants in other contexts (e.g. helper
|
191
191
|
# classes).
|
192
192
|
def self.hide(constant_name)
|
193
|
-
space = RSpec::Mocks.space
|
194
|
-
space.print_out_of_example_deprecation if space.outside_example
|
195
|
-
|
196
193
|
return unless recursive_const_defined?(constant_name)
|
197
194
|
|
198
195
|
mutate(ConstantHider.new(constant_name, nil, { }))
|
@@ -294,7 +291,7 @@ module RSpec
|
|
294
291
|
end
|
295
292
|
end
|
296
293
|
|
297
|
-
if @transfer_nested_constants
|
294
|
+
if Array === @transfer_nested_constants
|
298
295
|
@transfer_nested_constants = @transfer_nested_constants.map(&:to_s) if RUBY_VERSION == '1.8.7'
|
299
296
|
undefined_constants = @transfer_nested_constants - constants_defined_on(@original_value)
|
300
297
|
|
@@ -399,5 +396,11 @@ module RSpec
|
|
399
396
|
end
|
400
397
|
end
|
401
398
|
end
|
399
|
+
|
400
|
+
# Keeps backwards compatibility since we had released an rspec-mocks that
|
401
|
+
# only supported stubbing. Later, we released the hide_const feature and
|
402
|
+
# decided that the term "mutator" was a better term to wrap up the concept
|
403
|
+
# of both stubbing and hiding.
|
404
|
+
ConstantStubber = ConstantMutator
|
402
405
|
end
|
403
406
|
end
|