minispec 0.0.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 +7 -0
- data/.pryrc +2 -0
- data/Gemfile +4 -0
- data/LICENSE +22 -0
- data/README.md +2140 -0
- data/Rakefile +11 -0
- data/bin/minispec +4 -0
- data/lib/minispec.rb +175 -0
- data/lib/minispec/api.rb +2 -0
- data/lib/minispec/api/class.rb +195 -0
- data/lib/minispec/api/class/after.rb +49 -0
- data/lib/minispec/api/class/around.rb +54 -0
- data/lib/minispec/api/class/before.rb +101 -0
- data/lib/minispec/api/class/helpers.rb +116 -0
- data/lib/minispec/api/class/let.rb +44 -0
- data/lib/minispec/api/class/tests.rb +33 -0
- data/lib/minispec/api/instance.rb +158 -0
- data/lib/minispec/api/instance/mocks/doubles.rb +36 -0
- data/lib/minispec/api/instance/mocks/mocks.rb +319 -0
- data/lib/minispec/api/instance/mocks/spies.rb +17 -0
- data/lib/minispec/api/instance/mocks/stubs.rb +105 -0
- data/lib/minispec/helpers.rb +1 -0
- data/lib/minispec/helpers/array.rb +56 -0
- data/lib/minispec/helpers/booleans.rb +108 -0
- data/lib/minispec/helpers/generic.rb +24 -0
- data/lib/minispec/helpers/mocks/expectations.rb +29 -0
- data/lib/minispec/helpers/mocks/spies.rb +36 -0
- data/lib/minispec/helpers/raise.rb +44 -0
- data/lib/minispec/helpers/throw.rb +29 -0
- data/lib/minispec/mocks.rb +11 -0
- data/lib/minispec/mocks/expectations.rb +77 -0
- data/lib/minispec/mocks/stubs.rb +178 -0
- data/lib/minispec/mocks/validations.rb +80 -0
- data/lib/minispec/mocks/validations/amount.rb +63 -0
- data/lib/minispec/mocks/validations/arguments.rb +161 -0
- data/lib/minispec/mocks/validations/caller.rb +43 -0
- data/lib/minispec/mocks/validations/order.rb +47 -0
- data/lib/minispec/mocks/validations/raise.rb +111 -0
- data/lib/minispec/mocks/validations/return.rb +74 -0
- data/lib/minispec/mocks/validations/throw.rb +91 -0
- data/lib/minispec/mocks/validations/yield.rb +141 -0
- data/lib/minispec/proxy.rb +201 -0
- data/lib/minispec/reporter.rb +185 -0
- data/lib/minispec/utils.rb +139 -0
- data/lib/minispec/utils/differ.rb +325 -0
- data/lib/minispec/utils/pretty_print.rb +51 -0
- data/lib/minispec/utils/raise.rb +123 -0
- data/lib/minispec/utils/throw.rb +140 -0
- data/minispec.gemspec +27 -0
- data/test/mocks/expectations/amount.rb +67 -0
- data/test/mocks/expectations/arguments.rb +126 -0
- data/test/mocks/expectations/caller.rb +55 -0
- data/test/mocks/expectations/generic.rb +35 -0
- data/test/mocks/expectations/order.rb +46 -0
- data/test/mocks/expectations/raise.rb +166 -0
- data/test/mocks/expectations/return.rb +71 -0
- data/test/mocks/expectations/throw.rb +113 -0
- data/test/mocks/expectations/yield.rb +109 -0
- data/test/mocks/spies/amount.rb +68 -0
- data/test/mocks/spies/arguments.rb +57 -0
- data/test/mocks/spies/generic.rb +61 -0
- data/test/mocks/spies/order.rb +38 -0
- data/test/mocks/spies/raise.rb +158 -0
- data/test/mocks/spies/return.rb +71 -0
- data/test/mocks/spies/throw.rb +113 -0
- data/test/mocks/spies/yield.rb +101 -0
- data/test/mocks/test__doubles.rb +98 -0
- data/test/mocks/test__expectations.rb +27 -0
- data/test/mocks/test__mocks.rb +197 -0
- data/test/mocks/test__proxies.rb +61 -0
- data/test/mocks/test__spies.rb +43 -0
- data/test/mocks/test__stubs.rb +427 -0
- data/test/proxified_asserts.rb +34 -0
- data/test/setup.rb +53 -0
- data/test/test__around.rb +58 -0
- data/test/test__assert.rb +510 -0
- data/test/test__before_and_after.rb +117 -0
- data/test/test__before_and_after_all.rb +71 -0
- data/test/test__helpers.rb +197 -0
- data/test/test__raise.rb +104 -0
- data/test/test__skip.rb +41 -0
- data/test/test__throw.rb +103 -0
- metadata +196 -0
@@ -0,0 +1,36 @@
|
|
1
|
+
module MiniSpec
|
2
|
+
module InstanceAPI
|
3
|
+
|
4
|
+
# creates a double object.
|
5
|
+
# if one or more arguments given, first argument will be used as name, unless it is a Hash.
|
6
|
+
# arguments that goes after first one are treated as stubs.
|
7
|
+
#
|
8
|
+
# @example create a double that will respond to `color` and reported as :apple
|
9
|
+
# apple = double(:apple, :color) { 'Red' }
|
10
|
+
# apple.color # => Red
|
11
|
+
#
|
12
|
+
# @example injecting a double into a real battle and expecting it to receive some messages
|
13
|
+
# user = double(:user, :name, :address)
|
14
|
+
# expect(user).to_receive(:name, :address)
|
15
|
+
# Shipping.new.get_address_for(user)
|
16
|
+
#
|
17
|
+
# @example spy on a double
|
18
|
+
# user = double(:user, :name, :address)
|
19
|
+
# Shipping.new.get_address_for(user)
|
20
|
+
# assert(user).received(:name, :address)
|
21
|
+
#
|
22
|
+
def double *args, &proc
|
23
|
+
name = args.first.is_a?(Hash) ? nil : args.shift
|
24
|
+
|
25
|
+
object = Object.new
|
26
|
+
object.define_singleton_method(:__ms__double_instance) {true}
|
27
|
+
object.define_singleton_method(:inspect) {name} if name
|
28
|
+
|
29
|
+
hashes, rest = args.partition {|s| s.is_a?(Hash)}
|
30
|
+
hashes.each {|h| stub(object, h)}
|
31
|
+
rest.each {|s| stub(object, s, &proc)}
|
32
|
+
|
33
|
+
object
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,319 @@
|
|
1
|
+
module MiniSpec
|
2
|
+
module InstanceAPI
|
3
|
+
|
4
|
+
# the mock is basically a stub with difference it will also add a expectation.
|
5
|
+
# that's it, a mock will stub a method on a object and
|
6
|
+
# will expect that stub to be called before test finished.
|
7
|
+
#
|
8
|
+
# the `mock` method will return the actual stub
|
9
|
+
# so you can build chained constraints on it.
|
10
|
+
#
|
11
|
+
# @note if mocked method exists it's visibility will be kept
|
12
|
+
#
|
13
|
+
# @example make `some_object` to respond to `:some_method`
|
14
|
+
# and expect `:some_method` to be called before current test finished.
|
15
|
+
# also make `:some_method` to behave differently depending on given arguments.
|
16
|
+
# so if called with [:a, :b] arguments it will return 'called with a, b'.
|
17
|
+
# called with [:x, :y] arguments it will return 'called with x, y'.
|
18
|
+
# called with any other arguments or without arguments at all it returns 'whatever'.
|
19
|
+
#
|
20
|
+
# mock(some_object, :some_method).
|
21
|
+
# with(:a, :b) { 'called with a, b' }.
|
22
|
+
# with(:x, :y) { 'called with x, y' }.
|
23
|
+
# with_any { 'whatever' }
|
24
|
+
#
|
25
|
+
def mock object, method, visibility = nil, &proc
|
26
|
+
if method.is_a?(Hash)
|
27
|
+
proc && raise(ArgumentError, 'Both Hash and block given. Please use either one.')
|
28
|
+
method.each_pair {|m,r| mock(object, m, visibility, &proc {r})}
|
29
|
+
return MiniSpec::Mocks::HashedStub
|
30
|
+
end
|
31
|
+
visibility ||= MiniSpec::Utils.method_visibility(object, method) || :public
|
32
|
+
# IMPORTANT! stub should be defined before expectation
|
33
|
+
stub = stub(object, method, visibility, &proc)
|
34
|
+
expect(object).to_receive(method)
|
35
|
+
stub
|
36
|
+
end
|
37
|
+
|
38
|
+
# mocking multiple methods at once
|
39
|
+
#
|
40
|
+
# @param object
|
41
|
+
# @param *methods
|
42
|
+
# @param &proc
|
43
|
+
# @return MiniSpec::Mocks::MultipleStubsProxy instance
|
44
|
+
#
|
45
|
+
def mocks object, *methods, &proc
|
46
|
+
MiniSpec::Mocks::MultipleStubsProxy.new(methods.map {|m| mock(object, m, &proc)})
|
47
|
+
end
|
48
|
+
|
49
|
+
# same as `mock` except it will enforce public visibility on mocked method.
|
50
|
+
def public_mock object, method, &proc
|
51
|
+
mock(object, method, :public, &proc)
|
52
|
+
end
|
53
|
+
|
54
|
+
def public_mocks object, *methods, &proc
|
55
|
+
MiniSpec::Mocks::MultipleStubsProxy.new(methods.map {|m| public_mock(object, m, &proc)})
|
56
|
+
end
|
57
|
+
|
58
|
+
def protected_mock object, method, &proc
|
59
|
+
mock(object, method, :protected, &proc)
|
60
|
+
end
|
61
|
+
|
62
|
+
def protected_mocks object, *methods, &proc
|
63
|
+
MiniSpec::Mocks::MultipleStubsProxy.new(methods.map {|m| mock(object, m, :protected, &proc)})
|
64
|
+
end
|
65
|
+
|
66
|
+
def private_mock object, method, &proc
|
67
|
+
mock(object, method, :private, &proc)
|
68
|
+
end
|
69
|
+
|
70
|
+
def private_mocks object, *methods, &proc
|
71
|
+
MiniSpec::Mocks::MultipleStubsProxy.new(methods.map {|m| mock(object, m, :private, &proc)})
|
72
|
+
end
|
73
|
+
|
74
|
+
# overriding given method of given object with a proxy
|
75
|
+
# so MiniSpec can later check whether given method was called.
|
76
|
+
#
|
77
|
+
# if given method does not exists a NoMethodError raised
|
78
|
+
#
|
79
|
+
# @note doubles and stubs will be skipped as they are already proxified
|
80
|
+
#
|
81
|
+
# @example
|
82
|
+
# proxy(obj, :a)
|
83
|
+
# assert(obj).received(:a) # checking whether obj received :a message
|
84
|
+
#
|
85
|
+
# @param object
|
86
|
+
# @param method_name
|
87
|
+
def proxy object, method_name
|
88
|
+
# do not proxify doubles
|
89
|
+
return if object.respond_to?(:__ms__double_instance)
|
90
|
+
|
91
|
+
# do not proxify stubs
|
92
|
+
return if (x = @__ms__stubs__originals) && (x = x[object]) && x[method_name]
|
93
|
+
|
94
|
+
proxies = (@__ms__proxies[object] ||= [])
|
95
|
+
return if proxies.include?(method_name)
|
96
|
+
proxies << method_name
|
97
|
+
|
98
|
+
# method exists and it is a singleton.
|
99
|
+
# `nil?` method can be overridden only through a singleton
|
100
|
+
if method_name == :nil? || object.singleton_methods.include?(method_name)
|
101
|
+
return __ms__mocks__define_singleton_proxy(object, method_name)
|
102
|
+
end
|
103
|
+
|
104
|
+
# method exists and it is not a singleton, define a regular proxy
|
105
|
+
if visibility = MiniSpec::Utils.method_visibility(object, method_name)
|
106
|
+
return __ms__mocks__define_regular_proxy(object, method_name, visibility)
|
107
|
+
end
|
108
|
+
|
109
|
+
raise(NoMethodError, '%s does not respond to %s. Can not proxify an un-existing method.' % [
|
110
|
+
object.inspect, method_name.inspect
|
111
|
+
])
|
112
|
+
end
|
113
|
+
|
114
|
+
# replaces given method with a proxy
|
115
|
+
# that collects received messages and calls the original method.
|
116
|
+
#
|
117
|
+
# @param object
|
118
|
+
# @param method_name
|
119
|
+
# @param visibility
|
120
|
+
def __ms__mocks__define_regular_proxy object, method_name, visibility
|
121
|
+
method = object.method(method_name).unbind
|
122
|
+
method = __ms__mocks__regular_proxy(object, method_name, method)
|
123
|
+
extender = Module.new do
|
124
|
+
define_method(method_name, &method)
|
125
|
+
private method_name if visibility == :private
|
126
|
+
protected method_name if visibility == :protected
|
127
|
+
end
|
128
|
+
object.extend(extender)
|
129
|
+
end
|
130
|
+
|
131
|
+
# defines a singleton proxy
|
132
|
+
# that collects received messages and calls the original method.
|
133
|
+
#
|
134
|
+
# @param object
|
135
|
+
# @param method_name
|
136
|
+
def __ms__mocks__define_singleton_proxy object, method_name
|
137
|
+
method = object.method(method_name).unbind
|
138
|
+
method = __ms__mocks__regular_proxy(object, method_name, method)
|
139
|
+
object.define_singleton_method(method_name, &method)
|
140
|
+
end
|
141
|
+
|
142
|
+
# defines a singleton proxy
|
143
|
+
# that collects received messages and calls nothing.
|
144
|
+
#
|
145
|
+
# @note registering methods added this way so they can be undefined after test run
|
146
|
+
#
|
147
|
+
# @param object
|
148
|
+
# @param method_name
|
149
|
+
def __ms__mocks__define_void_proxy object, method_name
|
150
|
+
(@__ms__stubs__originals[object] ||= {})[method_name] = []
|
151
|
+
method = __ms__mocks__regular_proxy(object, method_name)
|
152
|
+
object.define_singleton_method(method_name, &method)
|
153
|
+
end
|
154
|
+
|
155
|
+
# returns a proc to be used with `define_method`.
|
156
|
+
# the proc will collect received messages then will call original method, if any.
|
157
|
+
#
|
158
|
+
# messages are stored into `@__ms__messages` Array
|
159
|
+
# each single message looks like:
|
160
|
+
# {object: ..., method: ..., arguments: ..., returned: ..., raised: ..., yielded: ...}
|
161
|
+
# `:returned` key are filled if original method called and it does not throw nor raise.
|
162
|
+
# `:raised` key are filled if original method called and it raises an error.
|
163
|
+
# `:yielded` key are filled if original method called with a block that was yielded.
|
164
|
+
#
|
165
|
+
# @param object
|
166
|
+
# @param method_name
|
167
|
+
# @param method [UnboundMethod] original method, unbounded, to be called after stat collected.
|
168
|
+
# if `nil`, there are two scenarios:
|
169
|
+
# 1. if method name is `:nil?` it returns `self == nil` after stat collected
|
170
|
+
# 2. otherwise it simply returns after stat collected
|
171
|
+
def __ms__mocks__regular_proxy object, method_name, method = nil
|
172
|
+
method_name.is_a?(Symbol) || raise(ArgumentError, 'method name should be a Symbol')
|
173
|
+
|
174
|
+
if :method_missing == method_name
|
175
|
+
return __ms__mocks__method_missing_proxy(object, method)
|
176
|
+
end
|
177
|
+
messages = @__ms__messages
|
178
|
+
Proc.new do |*args, &block|
|
179
|
+
message = {
|
180
|
+
object: object,
|
181
|
+
method: method_name,
|
182
|
+
arguments: args,
|
183
|
+
caller: Array(caller)
|
184
|
+
}
|
185
|
+
messages.push(message)
|
186
|
+
|
187
|
+
return self == nil if method_name == :nil?
|
188
|
+
return unless method
|
189
|
+
|
190
|
+
proc = block ? Proc.new do |*a,&b|
|
191
|
+
message[:yielded] = a
|
192
|
+
block.call(*a,&b)
|
193
|
+
end : nil
|
194
|
+
|
195
|
+
begin
|
196
|
+
message[:returned] = method.bind(self).call(*args, &proc)
|
197
|
+
rescue Exception => e
|
198
|
+
message[:raised] = e
|
199
|
+
end
|
200
|
+
message.freeze
|
201
|
+
message[:raised] ? raise(message[:raised]) : message[:returned]
|
202
|
+
end
|
203
|
+
end
|
204
|
+
|
205
|
+
# replace `method_missing` method with a proxy that collects
|
206
|
+
# received messages and calls original `method_missing` method.
|
207
|
+
# stat are collected for two methods:
|
208
|
+
# 1. `method_missing` itself
|
209
|
+
# 2. method what `method_missing` received as first argument
|
210
|
+
#
|
211
|
+
# stat has same format as on `__ms__mocks__regular_proxy`
|
212
|
+
# @see (#__ms__mocks__regular_proxy)
|
213
|
+
#
|
214
|
+
# @param object
|
215
|
+
# @param method [UnboundMethod] original `method_missing` method, unbounded
|
216
|
+
def __ms__mocks__method_missing_proxy object, method
|
217
|
+
messages = @__ms__messages
|
218
|
+
Proc.new do |meth, *args, &block|
|
219
|
+
message = {
|
220
|
+
object: object,
|
221
|
+
method: :method_missing,
|
222
|
+
arguments: [meth, *args],
|
223
|
+
caller: Array(caller)
|
224
|
+
}
|
225
|
+
messages.push(message)
|
226
|
+
|
227
|
+
message = {object: object, method: meth, arguments: args}
|
228
|
+
messages.push(message)
|
229
|
+
|
230
|
+
proc = block ? Proc.new do |*a,&b|
|
231
|
+
message[:yielded] = a
|
232
|
+
block.call(*a,&b)
|
233
|
+
end : nil
|
234
|
+
|
235
|
+
begin
|
236
|
+
message[:returned] = method.bind(self).call(meth, *args, &proc)
|
237
|
+
rescue Exception => e
|
238
|
+
message[:raised] = e
|
239
|
+
end
|
240
|
+
message.freeze
|
241
|
+
message[:raised] ? raise(message[:raised]) : message[:returned]
|
242
|
+
end
|
243
|
+
end
|
244
|
+
|
245
|
+
# restoring stubbed methods.
|
246
|
+
#
|
247
|
+
# it processes `@__ms__stubs__originals` Hash where keys are the objects
|
248
|
+
# and values are the object's methods to be restored.
|
249
|
+
# each value is a Array where first element is the method name
|
250
|
+
# and the second element is what previous method was.
|
251
|
+
# - if second element is an empty Array
|
252
|
+
# that mean method were not defined before stubbing, so simply undefine it.
|
253
|
+
# - if second element is a Array with last element set to :singleton Symbol,
|
254
|
+
# the method was a singleton before stubbing it,
|
255
|
+
# so defining a singleton method using second element's first element.
|
256
|
+
# - if second element is a Array with last element set to
|
257
|
+
# any of :public, :protected, :private Symbol
|
258
|
+
# an method with according visibility will be defined
|
259
|
+
# using second element's first element.
|
260
|
+
#
|
261
|
+
# @example there was no `x` method before stubbing
|
262
|
+
#
|
263
|
+
# # => {#<Object:0x007f92bb2b52c8>=>{:x=>[]}}
|
264
|
+
#
|
265
|
+
# @example `a` method was a singleton before stubbing
|
266
|
+
#
|
267
|
+
# # => {#<Object:0x007f92bb2c5998>=>{:a=>[#<Method: #<Object:0x007f92bb2c5998>.a>, :singleton]}}
|
268
|
+
#
|
269
|
+
# @example `a` was a public method before stubbing
|
270
|
+
#
|
271
|
+
# # => {#<#<Class:0x007f92bb2cdbe8>:0x007f92bb2cd850>=>{:a=>[#<Method: #<Class:0x007f92bb2cdbe8>#a>, :public]}}
|
272
|
+
#
|
273
|
+
def __ms__mocks__restore_originals
|
274
|
+
return unless stubs = @__ms__stubs__originals
|
275
|
+
stubs.each_pair do |object, methods|
|
276
|
+
methods.each_pair do |method_name, method|
|
277
|
+
|
278
|
+
# clearing proxies cache so the method can be proxied again during current test
|
279
|
+
(x = @__ms__proxies[object]) && x.delete(method_name)
|
280
|
+
|
281
|
+
if method.last.nil?
|
282
|
+
MiniSpec::Utils.undefine_method(object, method_name)
|
283
|
+
elsif method.last == :singleton
|
284
|
+
object.define_singleton_method(method_name, &method.first)
|
285
|
+
else
|
286
|
+
extender = Module.new do
|
287
|
+
define_method(method_name, &method.first)
|
288
|
+
private method_name if method.last == :private
|
289
|
+
protected method_name if method.last == :protected
|
290
|
+
end
|
291
|
+
object.extend(extender)
|
292
|
+
end
|
293
|
+
|
294
|
+
end
|
295
|
+
end
|
296
|
+
# clearing cache for cases when this run during current test
|
297
|
+
stubs.clear
|
298
|
+
end
|
299
|
+
|
300
|
+
# it is critical to iterate over a "statical" copy of messages array,
|
301
|
+
# otherwise iteration will generate a uncatchable infinite loop
|
302
|
+
# when messages array are updated during iteration.
|
303
|
+
def __ms__mocks__messages_copy
|
304
|
+
@__ms__messages.dup
|
305
|
+
end
|
306
|
+
|
307
|
+
# takes a copy of received messages and returns
|
308
|
+
# only messages received by given object
|
309
|
+
#
|
310
|
+
# @param object
|
311
|
+
def __ms__mocks__instance_messages object
|
312
|
+
__ms__mocks__messages_copy.select {|m| m[:object] == object}.freeze
|
313
|
+
end
|
314
|
+
|
315
|
+
def __ms__mocks__validate_expectations
|
316
|
+
catch(:__ms__stop_evaluation) { @__ms__expectations.each(&:validate!) }
|
317
|
+
end
|
318
|
+
end
|
319
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module MiniSpec
|
2
|
+
module InstanceAPI
|
3
|
+
|
4
|
+
# basically by proxying an object we attach a spy on it
|
5
|
+
# so any received messages will be reported
|
6
|
+
#
|
7
|
+
# @example spying user for :login and :logout messages
|
8
|
+
# user = User.new
|
9
|
+
# spy(user, :login, :logout)
|
10
|
+
# # ...
|
11
|
+
# assert(user).received(:login, :logout)
|
12
|
+
#
|
13
|
+
def spy object, *methods
|
14
|
+
methods.each {|method| proxy(object, method)}
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,105 @@
|
|
1
|
+
module MiniSpec
|
2
|
+
module InstanceAPI
|
3
|
+
|
4
|
+
# stubbing given method and keeps original visibility
|
5
|
+
#
|
6
|
+
# if a block given, it will receive original method as first argument
|
7
|
+
# and any passed parameters as rest arguments.
|
8
|
+
#
|
9
|
+
# @example make Some::Remote::API.call to return success
|
10
|
+
# stub(Some::Remote::API, :call) { :success }
|
11
|
+
#
|
12
|
+
# @example call original
|
13
|
+
# stub(obj, :a) {|orig| orig.call}
|
14
|
+
#
|
15
|
+
# @param object object to define stub on
|
16
|
+
# @param stub method to be stubbed.
|
17
|
+
# if a Hash given, keys will be stubbed methods and values return values
|
18
|
+
# @param [Proc] &proc block to be yielded when stub called
|
19
|
+
# @return MiniSpec::Mocks::Stub instance
|
20
|
+
#
|
21
|
+
def stub object, stub, visibility = nil, &proc
|
22
|
+
[Symbol, String, Hash].include?(stub.class) ||
|
23
|
+
raise(ArgumentError, 'a Symbol, String or Hash expected')
|
24
|
+
|
25
|
+
if stub.is_a?(Hash)
|
26
|
+
return hash_stub(object, stub, visibility, &proc)
|
27
|
+
elsif stub =~ /\./
|
28
|
+
return chained_stub(object, stub, visibility, &proc)
|
29
|
+
end
|
30
|
+
|
31
|
+
visibility ||= MiniSpec::Utils.method_visibility(object, stub) || :public
|
32
|
+
stubs = (@__ms__stubs[object.__id__] ||= {})
|
33
|
+
stubs[stub] ||= MiniSpec::Mocks::Stub.new(object, @__ms__messages, @__ms__stubs__originals)
|
34
|
+
stubs[stub].stubify(stub, visibility, &proc)
|
35
|
+
stubs[stub]
|
36
|
+
end
|
37
|
+
|
38
|
+
# @example make `obj.a` to return :x and `obj.b` to return :y
|
39
|
+
# stub(obj, :a => :x, :b => :y)
|
40
|
+
#
|
41
|
+
def hash_stub object, hash, visibility = nil, &proc
|
42
|
+
proc && raise(ArgumentError, 'Both Hash and block given. Please use either one.')
|
43
|
+
hash.each_pair do |s,v|
|
44
|
+
stub(object, s, visibility, &proc {v})
|
45
|
+
end
|
46
|
+
return MiniSpec::Mocks::HashedStub
|
47
|
+
end
|
48
|
+
|
49
|
+
# @example define a chained stub
|
50
|
+
# stub(obj, 'a.b.c')
|
51
|
+
#
|
52
|
+
def chained_stub object, chain, visibility = nil, &block
|
53
|
+
chain = chain.split('.').map(&:to_sym)
|
54
|
+
base, last_index = self, chain.size - 1
|
55
|
+
chain.each_with_index do |m,i|
|
56
|
+
next_object = (i == last_index ? nil : Struct.new(chain[i+1]).new)
|
57
|
+
return stub(object, m, visibility, &block) unless next_object
|
58
|
+
stub(object, m, visibility) { next_object }
|
59
|
+
object = next_object
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
# same as `stub` except it defines multiple stubs at once
|
64
|
+
#
|
65
|
+
# @param object
|
66
|
+
# @param *stubs
|
67
|
+
# @param &proc
|
68
|
+
# @return MiniSpec::Mocks::MultipleStubsProxy instance
|
69
|
+
#
|
70
|
+
def stubs object, *stubs, &proc
|
71
|
+
MiniSpec::Mocks::MultipleStubsProxy.new(stubs.map {|s| stub(object, s, &proc)})
|
72
|
+
end
|
73
|
+
|
74
|
+
# stubbing a method and enforce public visibility on it.
|
75
|
+
# that's it, even if method exists and it is not public,
|
76
|
+
# after stubbing it will become public.
|
77
|
+
def public_stub object, stub, &proc
|
78
|
+
stub(object, stub, :public, &proc)
|
79
|
+
end
|
80
|
+
|
81
|
+
def public_stubs object, *stubs, &proc
|
82
|
+
MiniSpec::Mocks::MultipleStubsProxy.new(stubs.map {|s| public_stub(object, s, &proc)})
|
83
|
+
end
|
84
|
+
|
85
|
+
# same as stub except it defines protected stubs
|
86
|
+
# (@see #stub)
|
87
|
+
def protected_stub object, stub, &proc
|
88
|
+
stub(object, stub, :protected, &proc)
|
89
|
+
end
|
90
|
+
|
91
|
+
def protected_stubs object, *stubs, &proc
|
92
|
+
MiniSpec::Mocks::MultipleStubsProxy.new(stubs.map {|s| protected_stub(object, s, &proc)})
|
93
|
+
end
|
94
|
+
|
95
|
+
# same as stub except it defines private stubs
|
96
|
+
# (@see #stub)
|
97
|
+
def private_stub object, stub, &proc
|
98
|
+
stub(object, stub, :private, &proc)
|
99
|
+
end
|
100
|
+
|
101
|
+
def private_stubs object, *stubs, &proc
|
102
|
+
MiniSpec::Mocks::MultipleStubsProxy.new(stubs.map {|s| private_stub(object, s, &proc)})
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|