flexmock 1.3.2 → 1.3.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/Gemfile.lock +9 -9
- data/Rakefile +3 -1
- data/lib/flexmock.rb +1 -1
- data/lib/flexmock/argument_matchers.rb +1 -1
- data/lib/flexmock/argument_types.rb +1 -2
- data/lib/flexmock/base.rb +2 -1
- data/lib/flexmock/call_record.rb +30 -0
- data/lib/flexmock/call_validator.rb +68 -0
- data/lib/flexmock/composite_expectation.rb +56 -0
- data/lib/flexmock/core.rb +30 -64
- data/lib/flexmock/core_class_methods.rb +1 -1
- data/lib/flexmock/default_framework_adapter.rb +1 -1
- data/lib/flexmock/deprecated_methods.rb +8 -3
- data/lib/flexmock/errors.rb +1 -1
- data/lib/flexmock/expectation.rb +7 -84
- data/lib/flexmock/expectation_builder.rb +133 -0
- data/lib/flexmock/expectation_director.rb +6 -4
- data/lib/flexmock/expectation_recorder.rb +42 -0
- data/lib/flexmock/extensions/active_record_model.rb +109 -0
- data/lib/flexmock/mock_builder.rb +139 -0
- data/lib/flexmock/mock_container.rb +13 -214
- data/lib/flexmock/noop.rb +1 -1
- data/lib/flexmock/ordering.rb +1 -2
- data/lib/flexmock/partial_mock.rb +95 -57
- data/lib/flexmock/rails.rb +1 -1
- data/lib/flexmock/recorder.rb +4 -3
- data/lib/flexmock/rspec.rb +1 -1
- data/lib/flexmock/rspec_spy_matcher.rb +4 -0
- data/lib/flexmock/spy_describers.rb +22 -5
- data/lib/flexmock/test_unit.rb +2 -40
- data/lib/flexmock/test_unit_integration.rb +4 -4
- data/lib/flexmock/test_unit_testcase_extensions.rb +49 -0
- data/lib/flexmock/undefined.rb +1 -1
- data/lib/flexmock/validators.rb +18 -12
- data/lib/flexmock/version.rb +1 -1
- data/test/based_partials_test.rb +1 -1
- data/test/container_methods_test.rb +1 -1
- data/test/default_framework_adapter_test.rb +1 -1
- data/test/demeter_mocking_test.rb +52 -2
- data/test/deprecated_methods_test.rb +1 -1
- data/test/examples_from_readme_test.rb +1 -1
- data/test/expectation_description_test.rb +1 -1
- data/test/extended_should_receive_test.rb +1 -1
- data/test/mock_builder_test.rb +68 -0
- data/test/naming_test.rb +1 -1
- data/test/new_instances_test.rb +1 -1
- data/test/partial_mock_test.rb +23 -6
- data/test/record_mode_test.rb +1 -1
- data/test/rspec_integration/integration_spec.rb +1 -1
- data/test/samples_test.rb +1 -2
- data/test/should_ignore_missing_test.rb +1 -1
- data/test/should_receive_test.rb +1 -1
- data/test/test_setup.rb +17 -0
- data/test/test_unit_integration/auto_test_unit_test.rb +1 -1
- data/test/tu_integration_test.rb +1 -1
- data/test/undefined_test.rb +1 -1
- metadata +52 -52
- data/TAGS +0 -1056
- data/lib/flexmock/composite.rb +0 -10
- data/lib/flexmock/rails/view_mocking.rb +0 -144
- data/test/rails_view_stub_test.rb +0 -145
@@ -1,7 +1,7 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
|
3
3
|
#---
|
4
|
-
# Copyright 2003-
|
4
|
+
# Copyright 2003-2013 by Jim Weirich (jim.weirich@gmail.com).
|
5
5
|
# All rights reserved.
|
6
6
|
|
7
7
|
# Permission is granted for use, copying, modification, distribution,
|
@@ -12,10 +12,11 @@
|
|
12
12
|
require 'flexmock/noop'
|
13
13
|
require 'flexmock/argument_types'
|
14
14
|
require 'flexmock/ordering'
|
15
|
+
require 'flexmock/mock_builder'
|
15
16
|
|
16
17
|
class FlexMock
|
17
18
|
|
18
|
-
|
19
|
+
|
19
20
|
# Mock container methods
|
20
21
|
#
|
21
22
|
# Include this module in to get integration with FlexMock. When this module
|
@@ -116,60 +117,10 @@ class FlexMock
|
|
116
117
|
# for a partial mock, flexmock will return the domain object rather than
|
117
118
|
# the mock object.
|
118
119
|
#
|
119
|
-
def flexmock(*args)
|
120
|
+
def flexmock(*args, &block)
|
120
121
|
location = caller.first
|
121
|
-
|
122
|
-
|
123
|
-
domain_obj = nil
|
124
|
-
safe_mode = false
|
125
|
-
model_class = nil
|
126
|
-
base_class = nil
|
127
|
-
mock = nil
|
128
|
-
while ! args.empty?
|
129
|
-
case args.first
|
130
|
-
when :base, :safe
|
131
|
-
safe_mode = (args.shift == :safe)
|
132
|
-
domain_obj = args.shift
|
133
|
-
when :model
|
134
|
-
args.shift
|
135
|
-
model_class = args.shift
|
136
|
-
when :on
|
137
|
-
args.shift
|
138
|
-
base_class = args.shift
|
139
|
-
name ||= "#{base_class} Mock"
|
140
|
-
when String, Symbol
|
141
|
-
name = args.shift.to_s
|
142
|
-
when Hash
|
143
|
-
quick_defs = args.shift
|
144
|
-
when FlexMock
|
145
|
-
mock = args.shift
|
146
|
-
else
|
147
|
-
domain_obj = args.shift
|
148
|
-
end
|
149
|
-
end
|
150
|
-
raise UsageError, "a block is required in safe mode" if safe_mode && ! block_given?
|
151
|
-
|
152
|
-
if domain_obj
|
153
|
-
mock = ContainerHelper.make_partial_proxy(self, domain_obj, name, safe_mode)
|
154
|
-
result = domain_obj
|
155
|
-
elsif model_class
|
156
|
-
id = ContainerHelper.next_id
|
157
|
-
mock ||= FlexMock.new("#{model_class}_#{id}", self)
|
158
|
-
result = mock
|
159
|
-
else
|
160
|
-
mock ||= FlexMock.new(name || "unknown", self)
|
161
|
-
result = mock
|
162
|
-
end
|
163
|
-
if base_class
|
164
|
-
mock.flexmock_based_on(base_class)
|
165
|
-
elsif domain_obj && FlexMock.partials_are_based
|
166
|
-
mock.flexmock_based_on(domain_obj.class)
|
167
|
-
end
|
168
|
-
mock.flexmock_define_expectation(location, quick_defs)
|
169
|
-
yield(mock) if block_given?
|
170
|
-
flexmock_remember(mock)
|
171
|
-
ContainerHelper.add_model_methods(mock, model_class, id, location) if model_class
|
172
|
-
result
|
122
|
+
@flexmock_worker ||= MockBuilder.new(self)
|
123
|
+
@flexmock_worker.define_a_mock(location, *args, &block)
|
173
124
|
end
|
174
125
|
alias flexstub flexmock
|
175
126
|
|
@@ -187,171 +138,19 @@ class FlexMock
|
|
187
138
|
# indicate the test isn't over yet. From our point of view we are
|
188
139
|
# only interested if the test has actually failed, so we wrap the
|
189
140
|
# raw call to passed? and handle accordingly.
|
190
|
-
def flexmock_test_has_failed?
|
141
|
+
def flexmock_test_has_failed? # :nodoc:
|
191
142
|
passed? == false
|
192
143
|
end
|
193
144
|
end
|
194
145
|
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
# testing framework test cases. Since we don't want to pollute the
|
199
|
-
# method namespace of the class that mixes in MockContainer, a
|
200
|
-
# number of MockContainer methods were moved into ContainerHelper to
|
201
|
-
# to isoloate the names.
|
202
|
-
#
|
203
|
-
class MockContainerHelper
|
204
|
-
include FlexMock::ArgumentTypes
|
205
|
-
|
206
|
-
# Return the next id for mocked models.
|
207
|
-
def next_id
|
208
|
-
@id_counter ||= 10000
|
209
|
-
@id_counter += 1
|
210
|
-
end
|
211
|
-
|
212
|
-
# :call-seq:
|
213
|
-
# parse_should_args(args) { |symbol| ... }
|
214
|
-
#
|
215
|
-
# This method provides common handling for the various should_receive
|
216
|
-
# argument lists. It sorts out the differences between symbols, arrays and
|
217
|
-
# hashes, and identifies the method names specified by each. As each
|
218
|
-
# method name is identified, create a mock expectation for it using the
|
219
|
-
# supplied block.
|
220
|
-
def parse_should_args(mock, args, &block) # :nodoc:
|
221
|
-
result = CompositeExpectation.new
|
222
|
-
args.each do |arg|
|
223
|
-
case arg
|
224
|
-
when Hash
|
225
|
-
arg.each do |k,v|
|
226
|
-
exp = build_demeter_chain(mock, k, &block).and_return(v)
|
227
|
-
result.add(exp)
|
228
|
-
end
|
229
|
-
when Symbol, String
|
230
|
-
result.add(build_demeter_chain(mock, arg, &block))
|
231
|
-
end
|
232
|
-
end
|
233
|
-
result
|
234
|
-
end
|
235
|
-
|
236
|
-
# Automatically add mocks for some common methods in ActiveRecord
|
237
|
-
# models.
|
238
|
-
def add_model_methods(mock, model_class, id, location)
|
239
|
-
container = mock.flexmock_container
|
240
|
-
|
241
|
-
mock_errors = container.flexmock("errors")
|
242
|
-
mock_errors.flexmock_define_expectation(location, :count).and_return(0).by_default
|
243
|
-
mock_errors.flexmock_define_expectation(location, :full_messages).and_return([]).by_default
|
244
|
-
|
245
|
-
mock.flexmock_define_expectation(location, :id).and_return(id).by_default
|
246
|
-
mock.flexmock_define_expectation(location, :to_params).and_return(id.to_s).by_default
|
247
|
-
mock.flexmock_define_expectation(location, :new_record?).and_return(false).by_default
|
248
|
-
mock.flexmock_define_expectation(location, :class).and_return(model_class).by_default
|
249
|
-
mock.flexmock_define_expectation(location, :errors).and_return(mock_errors).by_default
|
250
|
-
|
251
|
-
# HACK: Ruby 1.9 needs the following lambda so that model_class
|
252
|
-
# is correctly bound below.
|
253
|
-
lambda { }
|
254
|
-
mock.flexmock_define_expectation(location, :is_a?).with(any).and_return { |other|
|
255
|
-
other == model_class
|
256
|
-
}.by_default
|
257
|
-
mock.flexmock_define_expectation(location, :instance_of?).with(any).and_return { |other|
|
258
|
-
other == model_class
|
259
|
-
}.by_default
|
260
|
-
mock.flexmock_define_expectation(location, :kind_of?).with(any).and_return { |other|
|
261
|
-
model_class.ancestors.include?(other)
|
262
|
-
}.by_default
|
263
|
-
end
|
264
|
-
|
265
|
-
# Create a PartialMockProxy for the given object. Use +name+ as
|
266
|
-
# the name of the mock object.
|
267
|
-
def make_partial_proxy(container, obj, name, safe_mode)
|
268
|
-
name ||= "flexmock(#{obj.class.to_s})"
|
269
|
-
if !obj.instance_variable_defined?("@flexmock_proxy") || obj.instance_variable_get("@flexmock_proxy").nil?
|
270
|
-
mock = FlexMock.new(name, container)
|
271
|
-
proxy = PartialMockProxy.new(obj, mock, safe_mode)
|
272
|
-
obj.instance_variable_set("@flexmock_proxy", proxy)
|
273
|
-
end
|
274
|
-
obj.instance_variable_get("@flexmock_proxy")
|
146
|
+
class ExtensionRegistry
|
147
|
+
def add_extension(extension)
|
148
|
+
extensions << extension
|
275
149
|
end
|
276
|
-
|
277
|
-
|
278
|
-
|
279
|
-
# Build the chain of mocks for demeter style mocking.
|
280
|
-
#
|
281
|
-
# Warning: Nasty code ahead.
|
282
|
-
#
|
283
|
-
# This method builds a chain of mocks to support demeter style
|
284
|
-
# mocking. Given a mock chain of "first.second.third.last", we
|
285
|
-
# must build a chain of mock methods that return the next mock in
|
286
|
-
# the chain. The expectation for the last method of the chain is
|
287
|
-
# returned as the result of the method.
|
288
|
-
#
|
289
|
-
# Things to consider:
|
290
|
-
#
|
291
|
-
# (1) The expectation for the "first" method must be created by
|
292
|
-
# the proper mechanism, which is supplied by the block parameter
|
293
|
-
# "block". In other words, first expectation is created by
|
294
|
-
# calling the block. (This allows us to create expectations on
|
295
|
-
# both pure mocks and partial mocks, with the block handling the
|
296
|
-
# details).
|
297
|
-
#
|
298
|
-
# (2) Although the first mock is arbitrary, the remaining mocks in
|
299
|
-
# the chain will always be pure mocks created specifically for
|
300
|
-
# this purpose.
|
301
|
-
#
|
302
|
-
# (3) The expectations for all methods but the last in the chain
|
303
|
-
# will be setup to expect no parameters and to return the next
|
304
|
-
# mock in the chain.
|
305
|
-
#
|
306
|
-
# (4) It could very well be the case that several demeter chains
|
307
|
-
# will be defined on a single mock object, and those chains could
|
308
|
-
# share some of the same methods (e.g. "mock.one.two.read" and
|
309
|
-
# "mock.one.two.write" both share the methods "one" and "two").
|
310
|
-
# It is important that the shared methods return the same mocks in
|
311
|
-
# both chains.
|
312
|
-
#
|
313
|
-
def build_demeter_chain(mock, arg, &block)
|
314
|
-
container = mock.flexmock_container
|
315
|
-
names = arg.to_s.split('.')
|
316
|
-
check_method_names(names)
|
317
|
-
exp = nil
|
318
|
-
next_exp = lambda { |n| block.call(n) }
|
319
|
-
loop do
|
320
|
-
method_name = names.shift.to_sym
|
321
|
-
exp = mock.flexmock_find_expectation(method_name)
|
322
|
-
need_new_exp = exp.nil? || names.empty?
|
323
|
-
exp = next_exp.call(method_name) if need_new_exp
|
324
|
-
break if names.empty?
|
325
|
-
if need_new_exp
|
326
|
-
mock = container.flexmock("demeter_#{method_name}")
|
327
|
-
exp.with_no_args.and_return(mock)
|
328
|
-
else
|
329
|
-
mock = exp._return_value([])
|
330
|
-
end
|
331
|
-
check_proper_mock(mock, method_name)
|
332
|
-
next_exp = lambda { |n| mock.should_receive(n) }
|
333
|
-
end
|
334
|
-
exp
|
335
|
-
end
|
336
|
-
|
337
|
-
# Check that the given mock is a real FlexMock mock.
|
338
|
-
def check_proper_mock(mock, method_name)
|
339
|
-
unless mock.kind_of?(FlexMock)
|
340
|
-
fail FlexMock::UsageError,
|
341
|
-
"Conflicting mock declaration for '#{method_name}' in demeter style mock"
|
342
|
-
end
|
343
|
-
end
|
344
|
-
|
345
|
-
METHOD_NAME_RE = /^([A-Za-z_][A-Za-z0-9_]*[=!?]?|\[\]=?||\*\*|<<|>>|<=>|[<>=!]=|[=!]~|===|[-+]@|[-+\*\/%&^|<>~`!])$/
|
346
|
-
|
347
|
-
# Check that all the names in the list are valid method names.
|
348
|
-
def check_method_names(names)
|
349
|
-
names.each do |name|
|
350
|
-
fail FlexMock::UsageError, "Ill-formed method name '#{name}'" if
|
351
|
-
name !~ METHOD_NAME_RE
|
352
|
-
end
|
150
|
+
def extensions
|
151
|
+
@extensions ||= []
|
353
152
|
end
|
354
153
|
end
|
355
154
|
|
356
|
-
|
155
|
+
CONTAINER_HELPER = ExtensionRegistry.new
|
357
156
|
end
|
data/lib/flexmock/noop.rb
CHANGED
data/lib/flexmock/ordering.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
|
3
3
|
#---
|
4
|
-
# Copyright 2003-
|
4
|
+
# Copyright 2003-2013 by Jim Weirich (jim.weirich@gmail.com).
|
5
5
|
# All rights reserved.
|
6
6
|
|
7
7
|
# Permission is granted for use, copying, modification, distribution,
|
@@ -11,7 +11,6 @@
|
|
11
11
|
|
12
12
|
class FlexMock
|
13
13
|
|
14
|
-
# #################################################################
|
15
14
|
# The ordering module contains the methods and data structures used
|
16
15
|
# to determine proper orderring of mocked calls. By providing the
|
17
16
|
# functionality in a module, a individual mock object can order its
|
@@ -1,7 +1,7 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
|
3
3
|
#---
|
4
|
-
# Copyright 2003-
|
4
|
+
# Copyright 2003-2013 by Jim Weirich (jim.weirich@gmail.com).
|
5
5
|
# All rights reserved.
|
6
6
|
|
7
7
|
# Permission is granted for use, copying, modification, distribution,
|
@@ -10,24 +10,41 @@
|
|
10
10
|
#+++
|
11
11
|
|
12
12
|
require 'flexmock/noop'
|
13
|
+
require 'flexmock/expectation_builder'
|
13
14
|
|
14
15
|
class FlexMock
|
15
16
|
|
16
|
-
# #########################################################################
|
17
17
|
# PartialMockProxy is used to mate the mock framework to an existing
|
18
|
-
# object.
|
19
|
-
#
|
20
|
-
#
|
21
|
-
#
|
22
|
-
#
|
23
|
-
#
|
24
|
-
#
|
18
|
+
# object. The object is "enhanced" with a reference to a mock object
|
19
|
+
# (stored in <tt>@flexmock_proxy</tt>). When the +should_receive+
|
20
|
+
# method is sent to the proxy, it overrides the existing object's
|
21
|
+
# method by creating singleton method that forwards to the mock.
|
22
|
+
# When testing is complete, PartialMockProxy will erase the mocking
|
23
|
+
# infrastructure from the object being mocked (e.g. remove instance
|
24
|
+
# variables and mock singleton methods).
|
25
25
|
#
|
26
26
|
class PartialMockProxy
|
27
27
|
include Ordering
|
28
28
|
|
29
29
|
attr_reader :mock
|
30
30
|
|
31
|
+
# Make a partial mock proxy and install it on the target +obj+.
|
32
|
+
def self.make_proxy_for(obj, container, name, safe_mode)
|
33
|
+
name ||= "flexmock(#{obj.class.to_s})"
|
34
|
+
if ! proxy_defined_on?(obj)
|
35
|
+
mock = FlexMock.new(name, container)
|
36
|
+
proxy = PartialMockProxy.new(obj, mock, safe_mode)
|
37
|
+
obj.instance_variable_set("@flexmock_proxy", proxy)
|
38
|
+
end
|
39
|
+
obj.instance_variable_get("@flexmock_proxy")
|
40
|
+
end
|
41
|
+
|
42
|
+
# Is there a mock proxy defined on the domain object?
|
43
|
+
def self.proxy_defined_on?(obj)
|
44
|
+
obj.instance_variable_defined?("@flexmock_proxy") &&
|
45
|
+
obj.instance_variable_get("@flexmock_proxy")
|
46
|
+
end
|
47
|
+
|
31
48
|
# The following methods are added to partial mocks so that they
|
32
49
|
# can act like a mock.
|
33
50
|
|
@@ -35,7 +52,7 @@ class FlexMock
|
|
35
52
|
:should_receive, :new_instances,
|
36
53
|
:should_receive_with_location,
|
37
54
|
:flexmock_get, :flexmock_teardown, :flexmock_verify,
|
38
|
-
:flexmock_received?, :flexmock_calls,
|
55
|
+
:flexmock_received?, :flexmock_calls, :flexmock_find_expectation
|
39
56
|
]
|
40
57
|
|
41
58
|
# Initialize a PartialMockProxy object.
|
@@ -85,25 +102,27 @@ class FlexMock
|
|
85
102
|
end
|
86
103
|
|
87
104
|
def flexmock_define_expectation(location, *args)
|
88
|
-
|
89
|
-
unless @methods_proxied.include?(
|
90
|
-
hide_existing_method(
|
105
|
+
EXP_BUILDER.parse_should_args(self, args) do |method_name|
|
106
|
+
unless @methods_proxied.include?(method_name)
|
107
|
+
hide_existing_method(method_name)
|
91
108
|
end
|
92
|
-
ex = @mock.flexmock_define_expectation(location,
|
109
|
+
ex = @mock.flexmock_define_expectation(location, method_name)
|
93
110
|
ex.mock = self
|
94
111
|
ex
|
95
112
|
end
|
96
113
|
end
|
97
114
|
|
115
|
+
def flexmock_find_expectation(*args)
|
116
|
+
@mock.flexmock_find_expectation(*args)
|
117
|
+
end
|
118
|
+
|
98
119
|
def add_mock_method(method_name)
|
99
120
|
stow_existing_definition(method_name)
|
100
|
-
|
121
|
+
target_class_eval do
|
101
122
|
define_method(method_name) { |*args, &block|
|
102
|
-
proxy = instance_variable_get("@flexmock_proxy")
|
103
|
-
if proxy.nil?
|
123
|
+
proxy = instance_variable_get("@flexmock_proxy") or
|
104
124
|
fail "Missing FlexMock proxy " +
|
105
|
-
|
106
|
-
end
|
125
|
+
"(for method_name=#{method_name.inspect}, self=\#{self})"
|
107
126
|
proxy.send(method_name, *args, &block)
|
108
127
|
}
|
109
128
|
end
|
@@ -128,39 +147,43 @@ class FlexMock
|
|
128
147
|
# flexmock(ClassName).new_instances(:make).should_receive(...)
|
129
148
|
#
|
130
149
|
def new_instances(*allocators, &block)
|
131
|
-
fail ArgumentError, "new_instances requires a Class to stub" unless
|
150
|
+
fail ArgumentError, "new_instances requires a Class to stub" unless
|
151
|
+
Class === @obj
|
132
152
|
location = caller.first
|
133
153
|
allocators = [:new] if allocators.empty?
|
134
|
-
|
154
|
+
expectation_recorder = ExpectationRecorder.new
|
135
155
|
allocators.each do |allocate_method|
|
136
156
|
check_allocate_method(allocate_method)
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
# versions.
|
141
|
-
lambda { }
|
142
|
-
self.flexmock_define_expectation(location, allocate_method).and_return { |*args|
|
143
|
-
new_obj = invoke_original(allocate_method, args)
|
144
|
-
mock = flexmock_container.flexmock(new_obj)
|
145
|
-
block.call(mock) if block_given?
|
146
|
-
result.apply(mock)
|
147
|
-
new_obj
|
157
|
+
flexmock_define_expectation(location, allocate_method).and_return { |*args|
|
158
|
+
create_new_mocked_object(
|
159
|
+
allocate_method, args, expectation_recorder, block)
|
148
160
|
}
|
149
161
|
end
|
150
|
-
|
162
|
+
expectation_recorder
|
163
|
+
end
|
164
|
+
|
165
|
+
# Create a new mocked object.
|
166
|
+
#
|
167
|
+
# The mocked object is created using the following steps:
|
168
|
+
# (1) Allocate with the original allocation method (and args)
|
169
|
+
# (2) Pass to the block for custom configuration.
|
170
|
+
# (3) Apply any recorded expecations
|
171
|
+
#
|
172
|
+
def create_new_mocked_object(allocate_method, args, recorder, block)
|
173
|
+
new_obj = flexmock_invoke_original(allocate_method, args)
|
174
|
+
mock = flexmock_container.flexmock(new_obj)
|
175
|
+
block.call(mock) unless block.nil?
|
176
|
+
recorder.apply(mock)
|
177
|
+
new_obj
|
151
178
|
end
|
179
|
+
private :create_new_mocked_object
|
152
180
|
|
153
181
|
# Invoke the original definition of method on the object supported by
|
154
182
|
# the stub.
|
155
|
-
def
|
183
|
+
def flexmock_invoke_original(method, args)
|
156
184
|
method_proc = @method_definitions[method]
|
157
185
|
method_proc.call(*args)
|
158
186
|
end
|
159
|
-
private :invoke_original
|
160
|
-
|
161
|
-
def flexmock_invoke_original(method, args)
|
162
|
-
invoke_original(method, args)
|
163
|
-
end
|
164
187
|
|
165
188
|
# Verify that the mock has been properly called. After verification,
|
166
189
|
# detach the mocking infrastructure from the existing object.
|
@@ -214,15 +237,22 @@ class FlexMock
|
|
214
237
|
|
215
238
|
def check_allocate_method(allocate_method)
|
216
239
|
if allocate_method == :allocate && RUBY_VERSION >= "1.9"
|
217
|
-
fail UsageError,
|
240
|
+
fail UsageError,
|
241
|
+
"Cannot mock the allocation method using new_instances in Ruby 1.9"
|
218
242
|
end
|
219
243
|
end
|
220
244
|
|
221
245
|
# The singleton class of the object.
|
222
|
-
def
|
246
|
+
def target_singleton_class
|
223
247
|
class << @obj; self; end
|
224
248
|
end
|
225
249
|
|
250
|
+
# Evaluate a block (or string) in the context of the singleton
|
251
|
+
# class of the target partial object.
|
252
|
+
def target_class_eval(*args, &block)
|
253
|
+
target_singleton_class.class_eval(*args, &block)
|
254
|
+
end
|
255
|
+
|
226
256
|
def singleton?(method_name)
|
227
257
|
@obj.flexmock_singleton_defined?(method_name)
|
228
258
|
end
|
@@ -244,19 +274,25 @@ class FlexMock
|
|
244
274
|
@methods_proxied << method_name
|
245
275
|
new_alias = create_alias_for_existing_method(method_name)
|
246
276
|
if new_alias
|
247
|
-
|
248
|
-
@method_definitions[method_name] = Proc.new { |*args|
|
249
|
-
block = nil
|
250
|
-
if Proc === args.last
|
251
|
-
block = args.last
|
252
|
-
args = args[0...-1]
|
253
|
-
end
|
254
|
-
my_object.send(new_alias, *args, &block)
|
255
|
-
}
|
277
|
+
@method_definitions[method_name] = create_aliased_definition(@obj, new_alias)
|
256
278
|
end
|
257
279
|
remove_current_method(method_name) if singleton?(method_name)
|
258
280
|
end
|
259
281
|
|
282
|
+
# Create a method definition that invokes the original behavior
|
283
|
+
# via the alias.
|
284
|
+
def create_aliased_definition(my_object, new_alias)
|
285
|
+
Proc.new { |*args|
|
286
|
+
block = nil
|
287
|
+
if Proc === args.last
|
288
|
+
block = args.last
|
289
|
+
args = args[0...-1]
|
290
|
+
end
|
291
|
+
my_object.send(new_alias, *args, &block)
|
292
|
+
}
|
293
|
+
end
|
294
|
+
private :create_aliased_definition
|
295
|
+
|
260
296
|
# Create an alias for the existing +method_name+. Returns the new
|
261
297
|
# alias name. If the aliasing process fails (because the method
|
262
298
|
# doesn't really exist, then return nil.
|
@@ -273,7 +309,7 @@ class FlexMock
|
|
273
309
|
# meta-programming, so we provide for the case that the
|
274
310
|
# method_name does not exist.
|
275
311
|
def safe_alias_method(new_alias, method_name)
|
276
|
-
|
312
|
+
target_class_eval do
|
277
313
|
begin
|
278
314
|
alias_method(new_alias, method_name)
|
279
315
|
rescue NameError
|
@@ -288,16 +324,18 @@ class FlexMock
|
|
288
324
|
def define_proxy_method(method_name)
|
289
325
|
if method_name.to_s =~ /=$/
|
290
326
|
eval_line = __LINE__ + 1
|
291
|
-
|
327
|
+
target_class_eval %{
|
292
328
|
def #{method_name}(*args, &block)
|
293
|
-
instance_variable_get('@flexmock_proxy').
|
329
|
+
instance_variable_get('@flexmock_proxy').
|
330
|
+
mock.__send__(:#{method_name}, *args, &block)
|
294
331
|
end
|
295
332
|
}, __FILE__, eval_line
|
296
333
|
else
|
297
334
|
eval_line = __LINE__ + 1
|
298
|
-
|
335
|
+
target_class_eval %{
|
299
336
|
def #{method_name}(*args, &block)
|
300
|
-
instance_variable_get('@flexmock_proxy').
|
337
|
+
instance_variable_get('@flexmock_proxy').
|
338
|
+
mock.#{method_name}(*args, &block)
|
301
339
|
end
|
302
340
|
}, __FILE__, eval_line
|
303
341
|
_ = true # make rcov recognize the above eval is covered
|
@@ -311,7 +349,7 @@ class FlexMock
|
|
311
349
|
method_def = @method_definitions[method_name]
|
312
350
|
if method_def
|
313
351
|
the_alias = new_name(method_name)
|
314
|
-
|
352
|
+
target_class_eval do
|
315
353
|
alias_method(method_name, the_alias)
|
316
354
|
end
|
317
355
|
end
|
@@ -324,7 +362,7 @@ class FlexMock
|
|
324
362
|
# Remove the current method if it is a singleton method of the
|
325
363
|
# object being mocked.
|
326
364
|
def remove_current_method(method_name)
|
327
|
-
|
365
|
+
target_class_eval { remove_method(method_name) }
|
328
366
|
end
|
329
367
|
|
330
368
|
# Have we been detached from the existing object?
|