rspec-mocks 2.99.4 → 3.0.0.beta1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|