flexmock 2.3.0 → 2.3.1
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/lib/flexmock/core.rb +44 -13
- data/lib/flexmock/expectation.rb +0 -5
- data/lib/flexmock/expectation_builder.rb +1 -1
- data/lib/flexmock/mock_container.rb +2 -1
- data/lib/flexmock/partial_mock.rb +84 -23
- data/lib/flexmock/validators.rb +44 -12
- data/lib/flexmock/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 16f8df99b548903abdd25fef26a98df2906448bf
|
4
|
+
data.tar.gz: 7ce30d1e5ada1a4d679e53db575bd3d942b8e836
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 7ff6a1a9172b9df71a8d5d3c8717304cad88d7947ea212c45417f53106001b71587879bfcd9684301440fc766db0a48552f5fc80b81dbd55e4d65c81acc55a23
|
7
|
+
data.tar.gz: e93acaa91ace46df1fd14ead3c4790b857a654fb901d6a4d08193eae607abf65eeefa78e199b5e034855c72752d5b7bb824aa2d88455b229c740842dc2e8871a
|
data/lib/flexmock/core.rb
CHANGED
@@ -45,7 +45,7 @@ class FlexMock
|
|
45
45
|
include Ordering
|
46
46
|
|
47
47
|
attr_reader :flexmock_name
|
48
|
-
|
48
|
+
attr_reader :flexmock_container_stack
|
49
49
|
|
50
50
|
class << self
|
51
51
|
attr_accessor :partials_are_based
|
@@ -54,21 +54,50 @@ class FlexMock
|
|
54
54
|
self.partials_are_based = false
|
55
55
|
self.partials_verify_signatures = false
|
56
56
|
|
57
|
+
# Null object for {#parent_mock}
|
58
|
+
class NullParentMock
|
59
|
+
def flexmock_expectations_for(sym)
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
57
63
|
# Create a FlexMock object with the given name. The name is used in
|
58
64
|
# error messages. If no container is given, create a new, one-off
|
59
65
|
# container for this mock.
|
60
|
-
def initialize(name="unknown", container=nil)
|
66
|
+
def initialize(name="unknown", container=nil, parent: nil)
|
61
67
|
@flexmock_name = name
|
62
68
|
@flexmock_closed = false
|
69
|
+
@flexmock_container_stack = Array.new
|
63
70
|
@expectations = Hash.new
|
64
|
-
@ignore_missing = false
|
65
71
|
@verified = false
|
66
72
|
@calls = []
|
67
73
|
@base_class = nil
|
74
|
+
if parent
|
75
|
+
@ignore_missing = parent.ignore_missing?
|
76
|
+
@parent_mock = parent
|
77
|
+
else
|
78
|
+
@ignore_missing = false
|
79
|
+
@parent_mock = NullParentMock.new
|
80
|
+
end
|
68
81
|
container = UseContainer.new if container.nil?
|
69
82
|
container.flexmock_remember(self)
|
70
83
|
end
|
71
84
|
|
85
|
+
def ignore_missing?
|
86
|
+
@ignore_missing
|
87
|
+
end
|
88
|
+
|
89
|
+
def flexmock_container
|
90
|
+
flexmock_container_stack.last
|
91
|
+
end
|
92
|
+
|
93
|
+
def push_flexmock_container(container)
|
94
|
+
flexmock_container_stack.push(container)
|
95
|
+
end
|
96
|
+
|
97
|
+
def pop_flexmock_container
|
98
|
+
flexmock_container_stack.pop
|
99
|
+
end
|
100
|
+
|
72
101
|
# Return the inspection string for a mock.
|
73
102
|
def inspect
|
74
103
|
"<FlexMock:#{flexmock_name}>"
|
@@ -117,8 +146,8 @@ class FlexMock
|
|
117
146
|
flexmock_wrap do
|
118
147
|
if flexmock_closed?
|
119
148
|
FlexMock.undefined
|
120
|
-
elsif
|
121
|
-
|
149
|
+
elsif exp = flexmock_expectations_for(sym)
|
150
|
+
exp.call(enhanced_args, call_record)
|
122
151
|
elsif @base_class && @base_class.flexmock_defined?(sym)
|
123
152
|
FlexMock.undefined
|
124
153
|
elsif @ignore_missing
|
@@ -139,13 +168,14 @@ class FlexMock
|
|
139
168
|
|
140
169
|
# Find the mock expectation for method sym and arguments.
|
141
170
|
def flexmock_find_expectation(method_name, *args) # :nodoc:
|
142
|
-
exp =
|
143
|
-
|
171
|
+
if exp = flexmock_expectations_for(method_name)
|
172
|
+
exp.find_expectation(*args)
|
173
|
+
end
|
144
174
|
end
|
145
175
|
|
146
176
|
# Return the expectation director for a method name.
|
147
177
|
def flexmock_expectations_for(method_name) # :nodoc:
|
148
|
-
@expectations[method_name]
|
178
|
+
@expectations[method_name] || @parent_mock.flexmock_expectations_for(method_name)
|
149
179
|
end
|
150
180
|
|
151
181
|
def flexmock_base_class
|
@@ -183,9 +213,9 @@ class FlexMock
|
|
183
213
|
|
184
214
|
# Override the built-in +method+ to include the mocked methods.
|
185
215
|
def method(method_name)
|
186
|
-
|
216
|
+
flexmock_expectations_for(method_name) || super
|
187
217
|
rescue NameError => ex
|
188
|
-
if
|
218
|
+
if ignore_missing?
|
189
219
|
proc { FlexMock.undefined }
|
190
220
|
else
|
191
221
|
raise ex
|
@@ -218,10 +248,11 @@ class FlexMock
|
|
218
248
|
# Using +location+, define the expectations specified by +args+.
|
219
249
|
def flexmock_define_expectation(location, *args)
|
220
250
|
@last_expectation = EXP_BUILDER.parse_should_args(self, args) do |method_name|
|
221
|
-
|
251
|
+
exp = flexmock_expectations_for(method_name) || ExpectationDirector.new(method_name)
|
252
|
+
@expectations[method_name] = exp
|
222
253
|
result = Expectation.new(self, method_name, location)
|
223
|
-
|
224
|
-
override_existing_method(method_name) if flexmock_respond_to?(method_name)
|
254
|
+
exp << result
|
255
|
+
override_existing_method(method_name) if flexmock_respond_to?(method_name, true)
|
225
256
|
result = ExplicitNeeded.new(result, method_name, @base_class) if
|
226
257
|
@base_class && ! @base_class.flexmock_defined?(method_name)
|
227
258
|
result
|
data/lib/flexmock/expectation.rb
CHANGED
@@ -143,11 +143,6 @@ class FlexMock
|
|
143
143
|
@count_validators.all? { |v| v.eligible?(@actual_count) }
|
144
144
|
end
|
145
145
|
|
146
|
-
# Is this expectation constrained by any call counts?
|
147
|
-
def call_count_constrained?
|
148
|
-
! @count_validators.empty?
|
149
|
-
end
|
150
|
-
|
151
146
|
# Validate that the order
|
152
147
|
def validate_order
|
153
148
|
if @order_number
|
@@ -52,6 +52,7 @@ class FlexMock
|
|
52
52
|
def flexmock_close
|
53
53
|
flexmock_created_mocks.each do |m|
|
54
54
|
m.flexmock_teardown
|
55
|
+
m.pop_flexmock_container
|
55
56
|
end
|
56
57
|
@flexmock_created_mocks = []
|
57
58
|
end
|
@@ -127,7 +128,7 @@ class FlexMock
|
|
127
128
|
def flexmock_remember(mocking_object)
|
128
129
|
@flexmock_created_mocks ||= []
|
129
130
|
@flexmock_created_mocks << mocking_object
|
130
|
-
mocking_object.
|
131
|
+
mocking_object.push_flexmock_container(self)
|
131
132
|
mocking_object
|
132
133
|
end
|
133
134
|
|
@@ -28,27 +28,64 @@ class FlexMock
|
|
28
28
|
|
29
29
|
attr_reader :mock
|
30
30
|
|
31
|
-
|
31
|
+
# Boxing of the flexmock proxy
|
32
|
+
#
|
33
|
+
# It is managed as a stack in order to allow to setup containers recursively
|
34
|
+
# (as e.g. FlexMock.use( ... ) checks)
|
35
|
+
class ProxyBox
|
36
|
+
attr_reader :stack
|
37
|
+
|
38
|
+
Element = Struct.new :proxy, :container
|
39
|
+
|
40
|
+
def initialize
|
41
|
+
@stack = [Element.new]
|
42
|
+
end
|
43
|
+
|
44
|
+
# Tests whether the given container is the one on which the current proxy
|
45
|
+
# acts
|
46
|
+
def container
|
47
|
+
stack.last.container
|
48
|
+
end
|
49
|
+
|
50
|
+
def proxy
|
51
|
+
stack.last.proxy
|
52
|
+
end
|
53
|
+
|
54
|
+
def push(proxy, container)
|
55
|
+
stack.push(Element.new(proxy, container))
|
56
|
+
end
|
57
|
+
|
58
|
+
def pop
|
59
|
+
if !stack.empty?
|
60
|
+
stack.pop
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
def empty?
|
65
|
+
stack.size == 1
|
66
|
+
end
|
67
|
+
end
|
32
68
|
|
33
69
|
# Make a partial mock proxy and install it on the target +obj+.
|
34
70
|
def self.make_proxy_for(obj, container, name, safe_mode)
|
35
71
|
name ||= "flexmock(#{obj.class.to_s})"
|
36
|
-
if !
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
obj.instance_variable_get("@flexmock_proxy").proxy = proxy
|
41
|
-
else
|
42
|
-
obj.instance_variable_set("@flexmock_proxy", ProxyBox.new(proxy))
|
43
|
-
end
|
72
|
+
if !obj.instance_variable_defined?("@flexmock_proxy")
|
73
|
+
proxy_box = obj.instance_variable_set("@flexmock_proxy", ProxyBox.new)
|
74
|
+
else
|
75
|
+
proxy_box = obj.instance_variable_get("@flexmock_proxy")
|
44
76
|
end
|
45
|
-
obj.instance_variable_get("@flexmock_proxy").proxy
|
46
|
-
end
|
47
77
|
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
78
|
+
if proxy_box.container != container
|
79
|
+
if !proxy_box.empty?
|
80
|
+
parent_proxy, _ = proxy_box.proxy
|
81
|
+
parent_mock = parent_proxy.mock
|
82
|
+
end
|
83
|
+
|
84
|
+
mock = FlexMock.new(name, container, parent: parent_mock)
|
85
|
+
proxy = PartialMockProxy.new(obj, mock, safe_mode, parent: parent_proxy)
|
86
|
+
proxy_box.push(proxy, container)
|
87
|
+
end
|
88
|
+
proxy_box.proxy
|
52
89
|
end
|
53
90
|
|
54
91
|
# The following methods are added to partial mocks so that they
|
@@ -62,14 +99,21 @@ class FlexMock
|
|
62
99
|
:invoke_original
|
63
100
|
]
|
64
101
|
|
102
|
+
attr_reader :method_definitions
|
103
|
+
|
65
104
|
# Initialize a PartialMockProxy object.
|
66
|
-
def initialize(obj, mock, safe_mode)
|
105
|
+
def initialize(obj, mock, safe_mode, parent: nil)
|
67
106
|
@obj = obj
|
68
107
|
@mock = mock
|
69
|
-
@method_definitions = {}
|
70
|
-
@methods_proxied = []
|
71
108
|
@proxy_definition_module = nil
|
72
109
|
@initialize_override = nil
|
110
|
+
|
111
|
+
if parent
|
112
|
+
@method_definitions = parent.method_definitions.dup
|
113
|
+
else
|
114
|
+
@method_definitions = {}
|
115
|
+
end
|
116
|
+
|
73
117
|
unless safe_mode
|
74
118
|
add_mock_method(:should_receive)
|
75
119
|
MOCK_METHODS.each do |sym|
|
@@ -85,6 +129,14 @@ class FlexMock
|
|
85
129
|
@mock
|
86
130
|
end
|
87
131
|
|
132
|
+
def push_flexmock_container(container)
|
133
|
+
@mock.push_flexmock_container(container)
|
134
|
+
end
|
135
|
+
|
136
|
+
def pop_flexmock_container
|
137
|
+
@mock.pop_flexmock_container
|
138
|
+
end
|
139
|
+
|
88
140
|
# :call-seq:
|
89
141
|
# should_receive(:method_name)
|
90
142
|
# should_receive(:method1, method2, ...)
|
@@ -119,9 +171,20 @@ class FlexMock
|
|
119
171
|
flexmock_invoke_original(m, args)
|
120
172
|
end
|
121
173
|
|
174
|
+
# Whether the given method's original definition has been stored
|
175
|
+
def has_original_method?(m)
|
176
|
+
@method_definitions.has_key?(m)
|
177
|
+
end
|
178
|
+
|
179
|
+
# Whether the given method is already being proxied
|
180
|
+
def has_proxied_method?(m)
|
181
|
+
@proxy_definition_module &&
|
182
|
+
@proxy_definition_module.method_defined?(m)
|
183
|
+
end
|
184
|
+
|
122
185
|
def flexmock_define_expectation(location, *args)
|
123
186
|
EXP_BUILDER.parse_should_args(self, args) do |method_name|
|
124
|
-
if
|
187
|
+
if !has_proxied_method?(method_name) && !has_original_method?(method_name)
|
125
188
|
hide_existing_method(method_name)
|
126
189
|
end
|
127
190
|
ex = @mock.flexmock_define_expectation(location, method_name)
|
@@ -278,7 +341,7 @@ class FlexMock
|
|
278
341
|
end
|
279
342
|
if @obj.instance_variable_defined?(:@flexmock_proxy) &&
|
280
343
|
(box = @obj.instance_variable_get(:@flexmock_proxy))
|
281
|
-
box.
|
344
|
+
box.pop
|
282
345
|
end
|
283
346
|
@obj = nil
|
284
347
|
end
|
@@ -358,9 +421,8 @@ class FlexMock
|
|
358
421
|
# Stow the existing method definition so that it can be recovered
|
359
422
|
# later.
|
360
423
|
def stow_existing_definition(method_name)
|
361
|
-
if !@
|
424
|
+
if !@method_definitions.has_key?(method_name)
|
362
425
|
@method_definitions[method_name] = target_class_eval { instance_method(method_name) }
|
363
|
-
@methods_proxied << method_name
|
364
426
|
end
|
365
427
|
@method_definitions[method_name]
|
366
428
|
rescue NameError
|
@@ -390,6 +452,5 @@ class FlexMock
|
|
390
452
|
def detached?
|
391
453
|
@obj.nil?
|
392
454
|
end
|
393
|
-
|
394
455
|
end
|
395
456
|
end
|
data/lib/flexmock/validators.rb
CHANGED
@@ -213,18 +213,28 @@ class FlexMock
|
|
213
213
|
# @param [Array] args
|
214
214
|
# @raise ValidationFailed
|
215
215
|
def validate(args)
|
216
|
+
args = args.dup
|
216
217
|
kw_args = Hash.new
|
218
|
+
|
219
|
+
last_is_proc = false
|
220
|
+
begin
|
221
|
+
if args.last.kind_of?(Proc)
|
222
|
+
args.pop
|
223
|
+
last_is_proc = true
|
224
|
+
end
|
225
|
+
rescue NoMethodError
|
226
|
+
end
|
227
|
+
|
228
|
+
last_is_kw_hash = false
|
217
229
|
if expects_keyword_arguments?
|
218
230
|
last_is_kw_hash =
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
end
|
231
|
+
begin
|
232
|
+
args.last.kind_of?(Hash)
|
233
|
+
rescue NoMethodError
|
234
|
+
end
|
224
235
|
|
225
236
|
if last_is_kw_hash
|
226
|
-
kw_args = args
|
227
|
-
args = args[0..-2]
|
237
|
+
kw_args = args.pop
|
228
238
|
elsif requires_keyword_arguments?
|
229
239
|
raise ValidationFailed, "#{@exp} expects keyword arguments but none were provided"
|
230
240
|
end
|
@@ -232,12 +242,34 @@ class FlexMock
|
|
232
242
|
|
233
243
|
# There is currently no way to disambiguate "given a block" from "given a
|
234
244
|
# proc as last argument" ... give some leeway in this case
|
245
|
+
positional_count = args.size
|
246
|
+
|
247
|
+
if required_arguments > positional_count
|
248
|
+
if requires_keyword_arguments?
|
249
|
+
raise ValidationFailed, "#{@exp} expects at least #{required_arguments} positional arguments but got only #{positional_count}"
|
250
|
+
end
|
251
|
+
|
252
|
+
if (required_arguments - positional_count) == 1 && (last_is_kw_hash || last_is_proc)
|
253
|
+
if last_is_kw_hash
|
254
|
+
last_is_kw_hash = false
|
255
|
+
kw_args = Hash.new
|
256
|
+
else
|
257
|
+
last_is_proc = false
|
258
|
+
end
|
259
|
+
positional_count += 1
|
260
|
+
elsif (required_arguments - positional_count) == 2 && (last_is_kw_hash && last_is_proc)
|
261
|
+
last_is_kw_hash = false
|
262
|
+
kw_args = Hash.new
|
263
|
+
last_is_proc = false
|
264
|
+
positional_count += 2
|
265
|
+
else
|
266
|
+
raise ValidationFailed, "#{@exp} expects at least #{required_arguments} positional arguments but got only #{positional_count}"
|
267
|
+
end
|
268
|
+
end
|
235
269
|
|
236
|
-
if required_arguments
|
237
|
-
|
238
|
-
|
239
|
-
if !args.last.kind_of?(Proc) || (required_arguments + optional_arguments) < args.size - 1
|
240
|
-
raise ValidationFailed, "#{@exp} expects at most #{required_arguments + optional_arguments} positional arguments but got #{args.size}"
|
270
|
+
if !splat? && (required_arguments + optional_arguments) < positional_count
|
271
|
+
if !last_is_proc || (required_arguments + optional_arguments) < positional_count - 1
|
272
|
+
raise ValidationFailed, "#{@exp} expects at most #{required_arguments + optional_arguments} positional arguments but got #{positional_count}"
|
241
273
|
end
|
242
274
|
end
|
243
275
|
|
data/lib/flexmock/version.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: flexmock
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.3.
|
4
|
+
version: 2.3.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jim Weirich
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2016-10-
|
12
|
+
date: 2016-10-27 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: minitest
|