flexmock 1.3.3 → 2.0.0.rc1
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
- data/.autotest +3 -0
- data/.gitignore +14 -0
- data/.togglerc +7 -0
- data/.travis.yml +5 -0
- data/.yardopts +2 -0
- data/CHANGES +11 -0
- data/Gemfile +1 -4
- data/README.md +39 -11
- data/Rakefile +6 -217
- data/doc/examples/rspec_examples_spec.rb +244 -0
- data/doc/examples/test_unit_examples_test.rb +240 -0
- data/doc/jamis.rb +591 -0
- data/flexmock.gemspec +33 -0
- data/lib/flexmock.rb +0 -1
- data/lib/flexmock/composite_expectation.rb +1 -1
- data/lib/flexmock/core.rb +3 -7
- data/lib/flexmock/core_class_methods.rb +5 -1
- data/lib/flexmock/default_framework_adapter.rb +2 -2
- data/lib/flexmock/expectation.rb +29 -3
- data/lib/flexmock/expectation_director.rb +1 -1
- data/lib/flexmock/minitest.rb +13 -0
- data/lib/flexmock/minitest_extensions.rb +26 -0
- data/lib/flexmock/minitest_integration.rb +111 -0
- data/lib/flexmock/mock_container.rb +1 -2
- data/lib/flexmock/partial_mock.rb +61 -104
- data/lib/flexmock/recorder.rb +1 -2
- data/lib/flexmock/rspec.rb +6 -3
- data/lib/flexmock/test_unit_integration.rb +14 -0
- data/lib/flexmock/validators.rb +5 -4
- data/lib/flexmock/version.rb +1 -9
- data/rakelib/metrics.rake +40 -0
- data/rakelib/preview.rake +4 -0
- data/rakelib/tags.rake +18 -0
- data/todo.txt +20 -0
- metadata +61 -86
- data/Gemfile.lock +0 -20
- data/doc/examples/rspec_examples_spec.rdoc +0 -245
- data/doc/examples/test_unit_examples_test.rdoc +0 -241
- data/test/aliasing_test.rb +0 -66
- data/test/assert_spy_called_test.rb +0 -119
- data/test/base_class_test.rb +0 -71
- data/test/based_partials_test.rb +0 -51
- data/test/container_methods_test.rb +0 -118
- data/test/default_framework_adapter_test.rb +0 -38
- data/test/demeter_mocking_test.rb +0 -191
- data/test/deprecated_methods_test.rb +0 -225
- data/test/examples_from_readme_test.rb +0 -157
- data/test/expectation_description_test.rb +0 -80
- data/test/extended_should_receive_test.rb +0 -69
- data/test/flexmodel_test.rb +0 -54
- data/test/mock_builder_test.rb +0 -68
- data/test/naming_test.rb +0 -84
- data/test/new_instances_test.rb +0 -215
- data/test/object_extensions_test.rb +0 -25
- data/test/partial_mock_test.rb +0 -458
- data/test/record_mode_test.rb +0 -158
- data/test/redirect_error.rb +0 -16
- data/test/rspec_integration/integration_spec.rb +0 -56
- data/test/rspec_integration/spy_example_spec.rb +0 -207
- data/test/samples_test.rb +0 -283
- data/test/should_ignore_missing_test.rb +0 -84
- data/test/should_receive_test.rb +0 -1155
- data/test/spys_test.rb +0 -215
- data/test/symbol_extensions_test.rb +0 -8
- data/test/test_class_extensions.rb +0 -34
- data/test/test_setup.rb +0 -92
- data/test/test_unit_integration/auto_test_unit_test.rb +0 -42
- data/test/test_unit_integration/minitest_teardown_test.rb +0 -14
- data/test/tu_integration_test.rb +0 -99
- data/test/undefined_test.rb +0 -87
data/flexmock.gemspec
ADDED
@@ -0,0 +1,33 @@
|
|
1
|
+
require './lib/flexmock/version.rb'
|
2
|
+
spec = Gem::Specification.new do |s|
|
3
|
+
#### Basic information.
|
4
|
+
s.name = 'flexmock'
|
5
|
+
s.version = FlexMock::VERSION
|
6
|
+
s.summary = "Simple and Flexible Mock Objects for Testing"
|
7
|
+
s.description = %{
|
8
|
+
FlexMock is a extremely simple mock object class compatible
|
9
|
+
with the Minitest framework. Although the FlexMock's
|
10
|
+
interface is simple, it is very flexible.
|
11
|
+
}
|
12
|
+
|
13
|
+
s.required_ruby_version = ">= 2.0"
|
14
|
+
|
15
|
+
s.license = 'MIT'
|
16
|
+
|
17
|
+
#### Dependencies and requirements.
|
18
|
+
|
19
|
+
s.add_development_dependency 'minitest'
|
20
|
+
s.add_development_dependency 'rake'
|
21
|
+
|
22
|
+
#### Which files are to be included in this gem? Everything! (Except CVS directories.)
|
23
|
+
|
24
|
+
s.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
25
|
+
s.require_paths = ['lib'] # Use these for libraries.]
|
26
|
+
|
27
|
+
#### Author and project details.
|
28
|
+
|
29
|
+
s.authors = ["Jim Weirich", "Sylvain Joyeux"]
|
30
|
+
s.email = "sylvain.joyeux@m4x.org"
|
31
|
+
s.homepage = "https://github.com/doudou/flexmock"
|
32
|
+
end
|
33
|
+
|
data/lib/flexmock.rb
CHANGED
@@ -40,7 +40,7 @@ class FlexMock
|
|
40
40
|
# applied to the new expectation.
|
41
41
|
def should_receive(*args, &block)
|
42
42
|
@expectations.first.mock.
|
43
|
-
flexmock_define_expectation(caller
|
43
|
+
flexmock_define_expectation(caller, *args, &block)
|
44
44
|
end
|
45
45
|
|
46
46
|
# Return a string representations
|
data/lib/flexmock/core.rb
CHANGED
@@ -191,8 +191,7 @@ class FlexMock
|
|
191
191
|
# See Expectation for a list of declarators that can be used.
|
192
192
|
#
|
193
193
|
def should_receive(*args)
|
194
|
-
|
195
|
-
flexmock_define_expectation(location, *args)
|
194
|
+
flexmock_define_expectation(caller, *args)
|
196
195
|
end
|
197
196
|
|
198
197
|
# Using +location+, define the expectations specified by +args+.
|
@@ -230,13 +229,10 @@ class FlexMock
|
|
230
229
|
# that the mock name is added to the error message .
|
231
230
|
def flexmock_wrap(&block)
|
232
231
|
yield
|
233
|
-
rescue FlexMock.framework_adapter.assertion_failed_error => ex
|
234
|
-
raise
|
235
|
-
"in mock '#{@flexmock_name}': #{ex.message}",
|
236
|
-
ex.backtrace
|
232
|
+
rescue FlexMock.framework_adapter.assertion_failed_error, FlexMock.framework_adapter.check_failed_error => ex
|
233
|
+
raise ex, "in mock '#{@flexmock_name}': #{ex.message}", ex.backtrace
|
237
234
|
end
|
238
235
|
|
239
|
-
|
240
236
|
# Override the existing definition of method +method_name+ in the
|
241
237
|
# mock. Most methods depend on the method_missing trick to be
|
242
238
|
# invoked. However, if the method already exists, it will not call
|
@@ -67,7 +67,11 @@ class FlexMock
|
|
67
67
|
# Check will assert the block returns true. If it doesn't, an
|
68
68
|
# assertion failure is triggered with the given message.
|
69
69
|
def check(msg, &block) # :nodoc:
|
70
|
-
FlexMock.framework_adapter.
|
70
|
+
if FlexMock.framework_adapter.respond_to?(:check)
|
71
|
+
FlexMock.framework_adapter.check(msg, &block)
|
72
|
+
else
|
73
|
+
FlexMock.framework_adapter.make_assertion(msg, &block)
|
74
|
+
end
|
71
75
|
end
|
72
76
|
|
73
77
|
end
|
data/lib/flexmock/expectation.rb
CHANGED
@@ -68,10 +68,22 @@ class FlexMock
|
|
68
68
|
result
|
69
69
|
end
|
70
70
|
|
71
|
+
# Validate that this expectation is eligible for an extra call
|
72
|
+
def validate_eligible
|
73
|
+
@count_validators.each do |v|
|
74
|
+
if !v.eligible?(@actual_count)
|
75
|
+
v.validate(@actual_count + 1)
|
76
|
+
end
|
77
|
+
end
|
78
|
+
rescue CountValidator::ValidationFailed => e
|
79
|
+
FlexMock.framework_adapter.check(e.message) { false }
|
80
|
+
end
|
81
|
+
|
71
82
|
# Verify the current call with the given arguments matches the
|
72
83
|
# expectations recorded in this object.
|
73
84
|
def verify_call(*args)
|
74
85
|
validate_order
|
86
|
+
validate_eligible
|
75
87
|
@actual_count += 1
|
76
88
|
perform_yielding(args)
|
77
89
|
return_value(args)
|
@@ -140,6 +152,8 @@ class FlexMock
|
|
140
152
|
@count_validators.each do |v|
|
141
153
|
v.validate(@actual_count)
|
142
154
|
end
|
155
|
+
rescue CountValidator::ValidationFailed => e
|
156
|
+
FlexMock.framework_adapter.make_assertion(e.message, @location) { false }
|
143
157
|
end
|
144
158
|
|
145
159
|
# Does the argument list match this expectation's argument
|
@@ -278,7 +292,15 @@ class FlexMock
|
|
278
292
|
def pass_thru(&block)
|
279
293
|
block ||= lambda { |value| value }
|
280
294
|
and_return { |*args|
|
281
|
-
|
295
|
+
begin
|
296
|
+
block.call(@mock.flexmock_invoke_original(@sym, args))
|
297
|
+
rescue NoMethodError => e
|
298
|
+
if e.name == @sym
|
299
|
+
raise e, "#{e.message} while performing #pass_thru in expectation object #{self}"
|
300
|
+
else
|
301
|
+
raise
|
302
|
+
end
|
303
|
+
end
|
282
304
|
}
|
283
305
|
end
|
284
306
|
|
@@ -417,8 +439,12 @@ class FlexMock
|
|
417
439
|
def flexmock_location_filter
|
418
440
|
yield
|
419
441
|
rescue Exception => ex
|
420
|
-
|
421
|
-
|
442
|
+
bt = @location.dup
|
443
|
+
flexmock_dir = File.expand_path(File.dirname(__FILE__))
|
444
|
+
while bt.first.start_with?(flexmock_dir)
|
445
|
+
bt.shift
|
446
|
+
end
|
447
|
+
raise ex, ex.message, bt
|
422
448
|
end
|
423
449
|
|
424
450
|
end
|
@@ -40,7 +40,7 @@ class FlexMock
|
|
40
40
|
call_record.expectation = exp if call_record
|
41
41
|
FlexMock.check(
|
42
42
|
"no matching handler found for " +
|
43
|
-
FlexMock.format_call(@sym, args)) { !
|
43
|
+
FlexMock.format_call(@sym, args)) { !exp.nil? }
|
44
44
|
returned_value = exp.verify_call(*args)
|
45
45
|
returned_value
|
46
46
|
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
#---
|
4
|
+
# Copyright 2003-2013 by Jim Weirich (jim.weirich@gmail.com).
|
5
|
+
# All rights reserved.
|
6
|
+
|
7
|
+
# Permission is granted for use, copying, modification, distribution,
|
8
|
+
# and distribution of modified versions of this work as long as the
|
9
|
+
# above copyright notice is included.
|
10
|
+
#+++
|
11
|
+
|
12
|
+
require 'flexmock/minitest_integration'
|
13
|
+
require 'flexmock/minitest_extensions'
|
@@ -0,0 +1,26 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
#---
|
4
|
+
# Copyright 2003-2013 by Jim Weirich (jim.weirich@gmail.com).
|
5
|
+
# All rights reserved.
|
6
|
+
|
7
|
+
# Permission is granted for use, copying, modification, distribution,
|
8
|
+
# and distribution of modified versions of this work as long as the
|
9
|
+
# above copyright notice is included.
|
10
|
+
#+++
|
11
|
+
|
12
|
+
begin
|
13
|
+
# Minitest 5.0+
|
14
|
+
require 'minitest/test'
|
15
|
+
class Minitest::Test
|
16
|
+
include FlexMock::Minitest
|
17
|
+
end
|
18
|
+
|
19
|
+
rescue LoadError
|
20
|
+
# Minitest < 5.0, as shipped with ruby at least up to 2.1
|
21
|
+
require 'minitest/unit'
|
22
|
+
class MiniTest::Unit::TestCase
|
23
|
+
include FlexMock::Minitest
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
@@ -0,0 +1,111 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
#---
|
4
|
+
# Copyright 2003-2013 by Jim Weirich (jim.weirich@gmail.com).
|
5
|
+
# All rights reserved.
|
6
|
+
|
7
|
+
# Permission is granted for use, copying, modification, distribution,
|
8
|
+
# and distribution of modified versions of this work as long as the
|
9
|
+
# above copyright notice is included.
|
10
|
+
#+++
|
11
|
+
|
12
|
+
begin
|
13
|
+
require 'minitest/assertions'
|
14
|
+
rescue LoadError
|
15
|
+
require 'minitest/unit'
|
16
|
+
end
|
17
|
+
|
18
|
+
require 'flexmock/base'
|
19
|
+
require 'flexmock/test_unit_assert_spy_called'
|
20
|
+
|
21
|
+
class FlexMock
|
22
|
+
|
23
|
+
# Minitest::Test Integration.
|
24
|
+
#
|
25
|
+
# Include this module in any Test subclass (in test-style minitest) or or
|
26
|
+
# describe block (in spec-style minitest) to get integration with FlexMock.
|
27
|
+
# When this module is included, the mock container methods (e.g. flexmock(),
|
28
|
+
# flexstub()) will be available.
|
29
|
+
#
|
30
|
+
module Minitest
|
31
|
+
include ArgumentTypes
|
32
|
+
include MockContainer
|
33
|
+
include TestUnitAssertions
|
34
|
+
|
35
|
+
# Teardown the test case, verifying any mocks that might have been
|
36
|
+
# defined in this test case.
|
37
|
+
def before_teardown
|
38
|
+
super
|
39
|
+
@flexmock_teardown_failure = nil
|
40
|
+
if respond_to?(:capture_exceptions)
|
41
|
+
capture_exceptions do
|
42
|
+
flexmock_teardown
|
43
|
+
end
|
44
|
+
else
|
45
|
+
begin
|
46
|
+
flexmock_teardown
|
47
|
+
rescue Exception => e
|
48
|
+
@flexmock_teardown_failure = e
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
def after_teardown
|
54
|
+
if @flexmock_teardown_failure
|
55
|
+
raise @flexmock_teardown_failure
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
class CheckFailedError < RuntimeError; end
|
61
|
+
|
62
|
+
# Adapter for adapting FlexMock to the Test::Unit framework.
|
63
|
+
#
|
64
|
+
class MinitestFrameworkAdapter
|
65
|
+
if defined?(Minitest::Test)
|
66
|
+
include Minitest::Assertions
|
67
|
+
else
|
68
|
+
include MiniTest::Assertions
|
69
|
+
end
|
70
|
+
|
71
|
+
attr_accessor :assertions
|
72
|
+
|
73
|
+
def initialize
|
74
|
+
@assertions = 0
|
75
|
+
end
|
76
|
+
|
77
|
+
def filtered_backtrace
|
78
|
+
bt = caller
|
79
|
+
flexmock_dir = File.expand_path(File.dirname(__FILE__))
|
80
|
+
while bt.first.start_with?(flexmock_dir)
|
81
|
+
bt.shift
|
82
|
+
end
|
83
|
+
bt
|
84
|
+
end
|
85
|
+
|
86
|
+
def make_assertion(msg, backtrace = caller, &block)
|
87
|
+
assert(yield, msg)
|
88
|
+
rescue Exception => e
|
89
|
+
e.set_backtrace backtrace
|
90
|
+
raise e
|
91
|
+
end
|
92
|
+
|
93
|
+
def check(msg, &block)
|
94
|
+
unless yield
|
95
|
+
msg = msg.call if msg.is_a?(Proc)
|
96
|
+
raise CheckFailedError, msg, filtered_backtrace
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
def assertion_failed_error
|
101
|
+
MiniTest::Assertion
|
102
|
+
end
|
103
|
+
|
104
|
+
def check_failed_error
|
105
|
+
CheckFailedError
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
@framework_adapter = MinitestFrameworkAdapter.new
|
110
|
+
end
|
111
|
+
|
@@ -118,9 +118,8 @@ class FlexMock
|
|
118
118
|
# the mock object.
|
119
119
|
#
|
120
120
|
def flexmock(*args, &block)
|
121
|
-
location = caller.first
|
122
121
|
@flexmock_worker ||= MockBuilder.new(self)
|
123
|
-
@flexmock_worker.define_a_mock(
|
122
|
+
@flexmock_worker.define_a_mock(caller, *args, &block)
|
124
123
|
end
|
125
124
|
alias flexstub flexmock
|
126
125
|
|
@@ -28,21 +28,27 @@ class FlexMock
|
|
28
28
|
|
29
29
|
attr_reader :mock
|
30
30
|
|
31
|
+
ProxyBox = Struct.new :proxy
|
32
|
+
|
31
33
|
# Make a partial mock proxy and install it on the target +obj+.
|
32
34
|
def self.make_proxy_for(obj, container, name, safe_mode)
|
33
35
|
name ||= "flexmock(#{obj.class.to_s})"
|
34
36
|
if ! proxy_defined_on?(obj)
|
35
37
|
mock = FlexMock.new(name, container)
|
36
38
|
proxy = PartialMockProxy.new(obj, mock, safe_mode)
|
37
|
-
obj.
|
39
|
+
if obj.instance_variable_defined?("@flexmock_proxy")
|
40
|
+
obj.instance_variable_get("@flexmock_proxy").proxy = proxy
|
41
|
+
else
|
42
|
+
obj.instance_variable_set("@flexmock_proxy", ProxyBox.new(proxy))
|
43
|
+
end
|
38
44
|
end
|
39
|
-
obj.instance_variable_get("@flexmock_proxy")
|
45
|
+
obj.instance_variable_get("@flexmock_proxy").proxy
|
40
46
|
end
|
41
47
|
|
42
48
|
# Is there a mock proxy defined on the domain object?
|
43
49
|
def self.proxy_defined_on?(obj)
|
44
50
|
obj.instance_variable_defined?("@flexmock_proxy") &&
|
45
|
-
obj.instance_variable_get("@flexmock_proxy")
|
51
|
+
obj.instance_variable_get("@flexmock_proxy").proxy
|
46
52
|
end
|
47
53
|
|
48
54
|
# The following methods are added to partial mocks so that they
|
@@ -61,6 +67,7 @@ class FlexMock
|
|
61
67
|
@mock = mock
|
62
68
|
@method_definitions = {}
|
63
69
|
@methods_proxied = []
|
70
|
+
@proxy_definition_module = nil
|
64
71
|
unless safe_mode
|
65
72
|
add_mock_method(:should_receive)
|
66
73
|
MOCK_METHODS.each do |sym|
|
@@ -97,8 +104,7 @@ class FlexMock
|
|
97
104
|
#
|
98
105
|
# See Expectation for a list of declarators that can be used.
|
99
106
|
def should_receive(*args)
|
100
|
-
|
101
|
-
flexmock_define_expectation(location, *args)
|
107
|
+
flexmock_define_expectation(caller, *args)
|
102
108
|
end
|
103
109
|
|
104
110
|
def flexmock_define_expectation(location, *args)
|
@@ -118,9 +124,9 @@ class FlexMock
|
|
118
124
|
|
119
125
|
def add_mock_method(method_name)
|
120
126
|
stow_existing_definition(method_name)
|
121
|
-
|
127
|
+
proxy_module_eval do
|
122
128
|
define_method(method_name) { |*args, &block|
|
123
|
-
proxy =
|
129
|
+
proxy = __flexmock_proxy or
|
124
130
|
fail "Missing FlexMock proxy " +
|
125
131
|
"(for method_name=#{method_name.inspect}, self=\#{self})"
|
126
132
|
proxy.send(method_name, *args, &block)
|
@@ -149,11 +155,10 @@ class FlexMock
|
|
149
155
|
def new_instances(*allocators, &block)
|
150
156
|
fail ArgumentError, "new_instances requires a Class to stub" unless
|
151
157
|
Class === @obj
|
152
|
-
location = caller
|
158
|
+
location = caller
|
153
159
|
allocators = [:new] if allocators.empty?
|
154
160
|
expectation_recorder = ExpectationRecorder.new
|
155
161
|
allocators.each do |allocate_method|
|
156
|
-
check_allocate_method(allocate_method)
|
157
162
|
flexmock_define_expectation(location, allocate_method).and_return { |*args|
|
158
163
|
create_new_mocked_object(
|
159
164
|
allocate_method, args, expectation_recorder, block)
|
@@ -181,8 +186,15 @@ class FlexMock
|
|
181
186
|
# Invoke the original definition of method on the object supported by
|
182
187
|
# the stub.
|
183
188
|
def flexmock_invoke_original(method, args)
|
184
|
-
|
185
|
-
|
189
|
+
if original_method = @method_definitions[method]
|
190
|
+
if Proc === args.last
|
191
|
+
block = args.last
|
192
|
+
args = args[0..-2]
|
193
|
+
end
|
194
|
+
original_method.bind(@obj).call(*args, &block)
|
195
|
+
else
|
196
|
+
@obj.__send__(:method_missing, method, *args, &block)
|
197
|
+
end
|
186
198
|
end
|
187
199
|
|
188
200
|
# Verify that the mock has been properly called. After verification,
|
@@ -194,11 +206,16 @@ class FlexMock
|
|
194
206
|
# Remove all traces of the mocking framework from the existing object.
|
195
207
|
def flexmock_teardown
|
196
208
|
if ! detached?
|
197
|
-
|
198
|
-
|
199
|
-
|
209
|
+
proxy_module_eval do
|
210
|
+
methods = instance_methods(false).to_a
|
211
|
+
methods.each do |m|
|
212
|
+
remove_method m
|
213
|
+
end
|
214
|
+
end
|
215
|
+
if @obj.instance_variable_defined?(:@flexmock_proxy) &&
|
216
|
+
(box = @obj.instance_variable_get(:@flexmock_proxy))
|
217
|
+
box.proxy = nil
|
200
218
|
end
|
201
|
-
@obj.instance_variable_set("@flexmock_proxy", nil)
|
202
219
|
@obj = nil
|
203
220
|
end
|
204
221
|
end
|
@@ -235,16 +252,9 @@ class FlexMock
|
|
235
252
|
|
236
253
|
private
|
237
254
|
|
238
|
-
def check_allocate_method(allocate_method)
|
239
|
-
if allocate_method == :allocate && RUBY_VERSION >= "1.9"
|
240
|
-
fail UsageError,
|
241
|
-
"Cannot mock the allocation method using new_instances in Ruby 1.9"
|
242
|
-
end
|
243
|
-
end
|
244
|
-
|
245
255
|
# The singleton class of the object.
|
246
256
|
def target_singleton_class
|
247
|
-
|
257
|
+
@obj.singleton_class
|
248
258
|
end
|
249
259
|
|
250
260
|
# Evaluate a block (or string) in the context of the singleton
|
@@ -253,8 +263,20 @@ class FlexMock
|
|
253
263
|
target_singleton_class.class_eval(*args, &block)
|
254
264
|
end
|
255
265
|
|
256
|
-
|
257
|
-
|
266
|
+
# Evaluate a block into the module we use to define the proxy methods
|
267
|
+
def proxy_module_eval(*args, &block)
|
268
|
+
if !@proxy_definition_module
|
269
|
+
obj = @obj
|
270
|
+
@proxy_definition_module = m = Module.new do
|
271
|
+
define_method(:__flexmock_proxy) do
|
272
|
+
if box = obj.instance_variable_get(:@flexmock_proxy)
|
273
|
+
box.proxy
|
274
|
+
end
|
275
|
+
end
|
276
|
+
end
|
277
|
+
target_class_eval { prepend m }
|
278
|
+
end
|
279
|
+
@proxy_definition_module.class_eval(*args, &block)
|
258
280
|
end
|
259
281
|
|
260
282
|
# Hide the existing method definition with a singleton defintion
|
@@ -271,109 +293,44 @@ class FlexMock
|
|
271
293
|
# Stow the existing method definition so that it can be recovered
|
272
294
|
# later.
|
273
295
|
def stow_existing_definition(method_name)
|
274
|
-
|
275
|
-
|
276
|
-
|
277
|
-
@method_definitions[method_name] = create_aliased_definition(@obj, new_alias)
|
278
|
-
end
|
279
|
-
remove_current_method(method_name) if singleton?(method_name)
|
280
|
-
end
|
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
|
-
|
296
|
-
# Create an alias for the existing +method_name+. Returns the new
|
297
|
-
# alias name. If the aliasing process fails (because the method
|
298
|
-
# doesn't really exist, then return nil.
|
299
|
-
def create_alias_for_existing_method(method_name)
|
300
|
-
new_alias = new_name(method_name)
|
301
|
-
unless @obj.respond_to?(new_alias)
|
302
|
-
safe_alias_method(new_alias, method_name)
|
303
|
-
end
|
304
|
-
new_alias
|
305
|
-
end
|
306
|
-
|
307
|
-
# Create an alias for the existing method named +method_name+. It
|
308
|
-
# is possible that +method_name+ is implemented via a
|
309
|
-
# meta-programming, so we provide for the case that the
|
310
|
-
# method_name does not exist.
|
311
|
-
def safe_alias_method(new_alias, method_name)
|
312
|
-
target_class_eval do
|
313
|
-
begin
|
314
|
-
alias_method(new_alias, method_name)
|
315
|
-
rescue NameError
|
316
|
-
nil
|
317
|
-
end
|
296
|
+
if !@methods_proxied.include?(method_name)
|
297
|
+
@method_definitions[method_name] = target_class_eval { instance_method(method_name) }
|
298
|
+
@methods_proxied << method_name
|
318
299
|
end
|
300
|
+
rescue NameError
|
319
301
|
end
|
320
302
|
|
321
303
|
# Define a proxy method that forwards to our mock object. The
|
322
304
|
# proxy method is defined as a singleton method on the object
|
323
305
|
# being mocked.
|
324
306
|
def define_proxy_method(method_name)
|
325
|
-
if method_name
|
326
|
-
|
327
|
-
|
328
|
-
|
329
|
-
instance_variable_get('@flexmock_proxy').
|
330
|
-
mock.__send__(:#{method_name}, *args, &block)
|
307
|
+
if method_name =~ /=$/
|
308
|
+
proxy_module_eval do
|
309
|
+
define_method(method_name) do |*args, &block|
|
310
|
+
__flexmock_proxy.mock.__send__(method_name, *args, &block)
|
331
311
|
end
|
332
|
-
|
312
|
+
end
|
333
313
|
else
|
334
|
-
|
335
|
-
target_class_eval %{
|
314
|
+
proxy_module_eval <<-EOD
|
336
315
|
def #{method_name}(*args, &block)
|
337
|
-
|
338
|
-
mock.#{method_name}(*args, &block)
|
316
|
+
__flexmock_proxy.mock.#{method_name}(*args, &block)
|
339
317
|
end
|
340
|
-
|
341
|
-
_ = true # make rcov recognize the above eval is covered
|
318
|
+
EOD
|
342
319
|
end
|
343
320
|
end
|
344
321
|
|
345
322
|
# Restore the original singleton defintion for method_name that
|
346
323
|
# was saved earlier.
|
347
324
|
def restore_original_definition(method_name)
|
348
|
-
|
349
|
-
|
350
|
-
if method_def
|
351
|
-
the_alias = new_name(method_name)
|
352
|
-
target_class_eval do
|
353
|
-
alias_method(method_name, the_alias)
|
354
|
-
end
|
355
|
-
end
|
356
|
-
rescue NameError => _
|
357
|
-
# Alias attempt failed
|
358
|
-
nil
|
325
|
+
proxy_module_eval do
|
326
|
+
remove_method method_name
|
359
327
|
end
|
360
328
|
end
|
361
329
|
|
362
|
-
# Remove the current method if it is a singleton method of the
|
363
|
-
# object being mocked.
|
364
|
-
def remove_current_method(method_name)
|
365
|
-
target_class_eval { remove_method(method_name) }
|
366
|
-
end
|
367
|
-
|
368
330
|
# Have we been detached from the existing object?
|
369
331
|
def detached?
|
370
332
|
@obj.nil?
|
371
333
|
end
|
372
334
|
|
373
|
-
# Generate a name to be used to alias the original behavior.
|
374
|
-
def new_name(old_name)
|
375
|
-
"flexmock_original_behavior_for_#{old_name}"
|
376
|
-
end
|
377
|
-
|
378
335
|
end
|
379
336
|
end
|