rr 0.6.0 → 0.7.0
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGES +10 -0
- data/README.rdoc +56 -18
- data/Rakefile +1 -2
- data/lib/rr.rb +14 -5
- data/lib/rr/adapters/rr_methods.rb +11 -0
- data/lib/rr/adapters/rspec.rb +30 -0
- data/lib/rr/adapters/test_unit.rb +4 -0
- data/lib/rr/double.rb +79 -227
- data/lib/rr/double_definitions/child_double_definition_creator.rb +4 -0
- data/lib/rr/double_definitions/double_definition.rb +138 -4
- data/lib/rr/double_definitions/double_definition_creator.rb +18 -4
- data/lib/rr/double_definitions/double_definition_creator_proxy.rb +35 -3
- data/lib/rr/double_definitions/strategies/implementation/strongly_typed_reimplementation.rb +17 -0
- data/lib/rr/double_definitions/strategies/scope/instance_of_class.rb +3 -0
- data/lib/rr/double_injection.rb +10 -6
- data/lib/rr/errors/spy_verification_errors/double_injection_not_found_error.rb +8 -0
- data/lib/rr/errors/spy_verification_errors/invocation_count_error.rb +8 -0
- data/lib/rr/errors/spy_verification_errors/spy_verification_error.rb +8 -0
- data/lib/rr/errors/subject_does_not_implement_method_error.rb +6 -0
- data/lib/rr/errors/subject_has_different_arity_error.rb +6 -0
- data/lib/rr/expectations/times_called_expectation.rb +11 -9
- data/lib/rr/recorded_calls.rb +103 -0
- data/lib/rr/space.rb +18 -8
- data/lib/rr/spy_verification.rb +48 -0
- data/lib/rr/spy_verification_proxy.rb +18 -0
- data/lib/rr/times_called_matchers/any_times_matcher.rb +2 -3
- data/lib/rr/times_called_matchers/at_least_matcher.rb +2 -3
- data/lib/rr/times_called_matchers/at_most_matcher.rb +2 -3
- data/lib/rr/times_called_matchers/times_called_matcher.rb +4 -4
- data/spec/core_spec_suite.rb +1 -0
- data/spec/high_level_spec.rb +151 -14
- data/spec/rr/adapters/rr_methods_space_spec.rb +2 -2
- data/spec/rr/double_definitions/child_double_definition_creator_spec.rb +9 -0
- data/spec/rr/double_definitions/double_definition_creator_proxy_spec.rb +91 -19
- data/spec/rr/double_definitions/double_definition_creator_spec.rb +7 -0
- data/spec/rr/double_definitions/double_definition_spec.rb +53 -10
- data/spec/rr/double_injection/double_injection_dispatching_spec.rb +14 -15
- data/spec/rr/double_injection/double_injection_verify_spec.rb +1 -1
- data/spec/rr/double_spec.rb +79 -445
- data/spec/rr/errors/rr_error_spec.rb +49 -47
- data/spec/rr/expectations/times_called_expectation/times_called_expectation_any_times_spec.rb +4 -3
- data/spec/rr/expectations/times_called_expectation/times_called_expectation_at_least_spec.rb +3 -2
- data/spec/rr/expectations/times_called_expectation/times_called_expectation_at_most_spec.rb +3 -2
- data/spec/rr/expectations/times_called_expectation/times_called_expectation_helper.rb +2 -2
- data/spec/rr/expectations/times_called_expectation/times_called_expectation_integer_spec.rb +3 -3
- data/spec/rr/expectations/times_called_expectation/times_called_expectation_proc_spec.rb +6 -5
- data/spec/rr/expectations/times_called_expectation/times_called_expectation_range_spec.rb +3 -2
- data/spec/rr/expectations/times_called_expectation/times_called_expectation_spec.rb +3 -2
- data/spec/rr/rspec/invocation_matcher_spec.rb +259 -0
- data/spec/rr/rspec/rspec_adapter_spec.rb +1 -1
- data/spec/rr/rspec/rspec_usage_spec.rb +43 -24
- data/spec/rr/space/hash_with_object_id_key_spec.rb +2 -2
- data/spec/rr/space/space_spec.rb +27 -9
- data/spec/rr/test_unit/test_unit_integration_test.rb +10 -0
- data/spec/spec_helper.rb +4 -1
- data/spec/spy_verification_spec.rb +129 -0
- metadata +100 -88
data/CHANGES
CHANGED
@@ -1,3 +1,13 @@
|
|
1
|
+
* 0.7.0
|
2
|
+
- Added spies (Patchs by Joe Ferris, Michael Niessner & Mike Mangino)
|
3
|
+
- Added strongly typed reimplementation doubles (Patch by Michael Niessner)
|
4
|
+
|
5
|
+
* 0.6.2
|
6
|
+
- Fixed DoubleDefinition chaining edge cases
|
7
|
+
|
8
|
+
* 0.6.1
|
9
|
+
- DoubleDefinitionCreatorProxy definition eval block is instance_evaled when the arity is not 1. When the arity is 1, the block is yielded with the DoubleDefinitionCreatorProxy passed in.
|
10
|
+
|
1
11
|
* 0.6.0
|
2
12
|
- Friendlier DoubleNotFound error message
|
3
13
|
- Implemented Double strategy creation methods (#mock, #stub, #proxy, #instance_of, and ! equivalents) on DoubleDefinition
|
data/README.rdoc
CHANGED
@@ -23,8 +23,7 @@ double for tests. The following are test doubles:
|
|
23
23
|
* Proxies
|
24
24
|
http://xunitpatterns.com/Test%20Double.html
|
25
25
|
|
26
|
-
Currently RR implements mocks, stubs, and
|
27
|
-
support spies.
|
26
|
+
Currently RR implements mocks, stubs, proxies, and spies. Fakes usually require custom code, so it is beyond the scope of RR.
|
28
27
|
|
29
28
|
== Using RR
|
30
29
|
=== test/unit
|
@@ -202,14 +201,50 @@ Put double scenarios on instances of a Class.
|
|
202
201
|
|
203
202
|
mock.instance_of(User).valid? {false}
|
204
203
|
|
204
|
+
=== Spies
|
205
|
+
|
206
|
+
Adding a DoubleInjection to an Object + Method (done by stub, mock, or dont_allow) causes RR to record any method
|
207
|
+
invocations to the Object + method. Assertions can then be made on the recorded method calls.
|
208
|
+
|
209
|
+
==== test/unit
|
210
|
+
|
211
|
+
subject = Object.new
|
212
|
+
stub(subject).foo
|
213
|
+
subject.foo(1)
|
214
|
+
assert_received(subject) {|subject| subject.foo(1)}
|
215
|
+
assert_received(subject) {|subject| subject.bar} # This fails
|
216
|
+
|
217
|
+
==== rspec
|
218
|
+
|
219
|
+
subject = Object.new
|
220
|
+
stub(subject).foo
|
221
|
+
subject.foo(1)
|
222
|
+
subject.should have_received.foo(1)
|
223
|
+
subject.should have_received.bar # this fails
|
224
|
+
|
205
225
|
=== Block Syntax
|
226
|
+
The block syntax has two modes
|
227
|
+
* A normal block mode with a DoubleDefinitionCreatorProxy argument
|
228
|
+
|
206
229
|
script = MyScript.new
|
207
|
-
mock(script) do |
|
208
|
-
|
209
|
-
|
210
|
-
|
230
|
+
mock(script) do |expect|
|
231
|
+
expect.system("cd #{RAILS_ENV}") {true}
|
232
|
+
expect.system("rake foo:bar") {true}
|
233
|
+
expect.system("rake baz") {true}
|
211
234
|
end
|
212
235
|
|
236
|
+
* An instance_eval mode where the DoubleDefinitionCreatorProxy is instance_evaled
|
237
|
+
|
238
|
+
script = MyScript.new
|
239
|
+
mock(script) do
|
240
|
+
system("cd #{RAILS_ENV}") {true}
|
241
|
+
system("rake foo:bar") {true}
|
242
|
+
system("rake baz") {true}
|
243
|
+
end
|
244
|
+
|
245
|
+
=== Block Syntax with explicit DoubleDefinitionCreatorProxy argument
|
246
|
+
|
247
|
+
|
213
248
|
=== Double Graphs
|
214
249
|
RR has a method-chaining api support for Double graphs. For example,
|
215
250
|
lets say you want an object to receive a method call to #foo, and have
|
@@ -273,19 +308,22 @@ In RR, you would do:
|
|
273
308
|
== Special Thanks To
|
274
309
|
With any development effort, there are countless people who have contributed
|
275
310
|
to making it possible. We all are standing on the shoulders of giants.
|
276
|
-
*
|
277
|
-
*
|
278
|
-
*
|
279
|
-
*
|
280
|
-
* Parker Thompson for pairing with me
|
311
|
+
* Aslak Hellesoy for Developing Rspec
|
312
|
+
* Dan North for syntax ideas
|
313
|
+
* Dave Astels for some BDD inspiration
|
314
|
+
* David Chelimsky for encouragement to make the RR framework, for developing the Rspec mock framework, and syntax ideas
|
281
315
|
* Felix Morio for pairing with me
|
282
|
-
* Jeff Whitmire for documentation suggestions
|
283
|
-
* David Chelimsky for encouragement to make the RR framework, for developing
|
284
|
-
the Rspec mock framework, and syntax ideas
|
285
316
|
* Gerard Meszaros for his excellent book "xUnit Test Patterns"
|
286
|
-
* Dan North for syntax ideas
|
287
|
-
* Jim Weirich for developing Flexmock, the first Terse ruby mock framework in Ruby
|
288
317
|
* James Mead for developing Mocha
|
289
|
-
*
|
318
|
+
* Joe Ferris for patches
|
319
|
+
* Jeff Whitmire for documentation suggestions
|
320
|
+
* Jim Weirich for developing Flexmock, the first Terse ruby mock framework in Ruby
|
321
|
+
* Joe Ferris for patches
|
322
|
+
* Matthew O'Conner for patches
|
323
|
+
* Michael Niessner for patches and pairing with me
|
324
|
+
* Mike Mangino (from Elevated Rails) for patches and pairing with me
|
325
|
+
* Nick Kallen for documentation suggestions, bug reports, and patches
|
326
|
+
* Nathan Sobo for various ideas and inspiration for cleaner and more expressive code
|
327
|
+
* Parker Thompson for pairing with me
|
328
|
+
* Pivotal Labs for sponsoring RR development
|
290
329
|
* Stephen Baker for Developing Rspec
|
291
|
-
* Dave Astels for some BDD inspiration
|
data/Rakefile
CHANGED
@@ -26,7 +26,7 @@ def run_suite
|
|
26
26
|
end
|
27
27
|
|
28
28
|
PKG_NAME = "rr"
|
29
|
-
PKG_VERSION = "0.
|
29
|
+
PKG_VERSION = "0.7.0"
|
30
30
|
PKG_FILES = FileList[
|
31
31
|
'[A-Z]*',
|
32
32
|
'*.rb',
|
@@ -52,7 +52,6 @@ spec = Gem::Specification.new do |s|
|
|
52
52
|
|
53
53
|
s.test_files = Dir.glob('spec/*_spec.rb')
|
54
54
|
s.require_path = 'lib'
|
55
|
-
s.autorequire = 'rr'
|
56
55
|
s.author = "Brian Takita"
|
57
56
|
s.email = "brian@pivotallabs.com"
|
58
57
|
s.homepage = "http://pivotallabs.com"
|
data/lib/rr.rb
CHANGED
@@ -1,14 +1,22 @@
|
|
1
1
|
dir = File.dirname(__FILE__)
|
2
|
+
require 'rubygems'
|
3
|
+
|
2
4
|
require "#{dir}/rr/errors/rr_error"
|
5
|
+
require "#{dir}/rr/errors/subject_does_not_implement_method_error"
|
6
|
+
require "#{dir}/rr/errors/subject_has_different_arity_error"
|
3
7
|
require "#{dir}/rr/errors/double_definition_error"
|
4
8
|
require "#{dir}/rr/errors/double_not_found_error"
|
5
9
|
require "#{dir}/rr/errors/double_order_error"
|
6
10
|
require "#{dir}/rr/errors/argument_equality_error"
|
7
11
|
require "#{dir}/rr/errors/times_called_error"
|
12
|
+
require "#{dir}/rr/errors/spy_verification_errors/spy_verification_error"
|
13
|
+
require "#{dir}/rr/errors/spy_verification_errors/double_injection_not_found_error"
|
14
|
+
require "#{dir}/rr/errors/spy_verification_errors/invocation_count_error"
|
8
15
|
|
9
16
|
require "#{dir}/rr/space"
|
10
17
|
require "#{dir}/rr/double_injection"
|
11
18
|
require "#{dir}/rr/hash_with_object_id_key"
|
19
|
+
require "#{dir}/rr/recorded_calls"
|
12
20
|
|
13
21
|
require "#{dir}/rr/double_definitions/double_definition_creator_proxy"
|
14
22
|
require "#{dir}/rr/double_definitions/double_definition_creator"
|
@@ -24,6 +32,7 @@ require "#{dir}/rr/double_definitions/strategies/verification/stub"
|
|
24
32
|
require "#{dir}/rr/double_definitions/strategies/verification/dont_allow"
|
25
33
|
require "#{dir}/rr/double_definitions/strategies/implementation/implementation_strategy"
|
26
34
|
require "#{dir}/rr/double_definitions/strategies/implementation/reimplementation"
|
35
|
+
require "#{dir}/rr/double_definitions/strategies/implementation/strongly_typed_reimplementation"
|
27
36
|
require "#{dir}/rr/double_definitions/strategies/implementation/proxy"
|
28
37
|
require "#{dir}/rr/double_definitions/strategies/scope/scope_strategy"
|
29
38
|
require "#{dir}/rr/double_definitions/strategies/scope/instance"
|
@@ -54,11 +63,15 @@ require "#{dir}/rr/times_called_matchers/proc_matcher"
|
|
54
63
|
require "#{dir}/rr/times_called_matchers/at_least_matcher"
|
55
64
|
require "#{dir}/rr/times_called_matchers/at_most_matcher"
|
56
65
|
|
66
|
+
require "#{dir}/rr/spy_verification_proxy"
|
67
|
+
require "#{dir}/rr/spy_verification"
|
68
|
+
|
57
69
|
require "#{dir}/rr/adapters/rspec"
|
58
70
|
require "#{dir}/rr/adapters/test_unit"
|
59
71
|
|
60
72
|
module RR
|
61
73
|
class << self
|
74
|
+
include Adapters::RRMethods
|
62
75
|
(RR::Space.instance_methods - Object.instance_methods).each do |method_name|
|
63
76
|
returns_method = <<-METHOD
|
64
77
|
def #{method_name}(*args, &block)
|
@@ -67,9 +80,5 @@ module RR
|
|
67
80
|
METHOD
|
68
81
|
class_eval(returns_method, __FILE__, __LINE__ - 4)
|
69
82
|
end
|
70
|
-
|
71
|
-
def method_missing(method_name, *args, &block)
|
72
|
-
RR::Space.instance.__send__(method_name, *args, &block)
|
73
|
-
end
|
74
83
|
end
|
75
|
-
end
|
84
|
+
end
|
@@ -99,7 +99,18 @@ module RR
|
|
99
99
|
expectation_proc ||= block
|
100
100
|
RR::WildcardMatchers::Satisfy.new(expectation_proc)
|
101
101
|
end
|
102
|
+
|
103
|
+
def spy(subject)
|
104
|
+
methods_to_stub = subject.public_methods - ["methods", "==", "__send__", "__id__"]
|
105
|
+
methods_to_stub.each do |method|
|
106
|
+
stub.proxy(subject, method)
|
107
|
+
end
|
108
|
+
end
|
102
109
|
|
110
|
+
def received(subject)
|
111
|
+
RR::SpyVerificationProxy.new(subject)
|
112
|
+
end
|
113
|
+
|
103
114
|
instance_methods.each do |name|
|
104
115
|
alias_method "rr_#{name}", name
|
105
116
|
end
|
data/lib/rr/adapters/rspec.rb
CHANGED
@@ -18,6 +18,36 @@ module RR
|
|
18
18
|
def teardown_mocks_for_rspec
|
19
19
|
RR.reset
|
20
20
|
end
|
21
|
+
|
22
|
+
def have_received(method = nil)
|
23
|
+
InvocationMatcher.new(method)
|
24
|
+
end
|
25
|
+
|
26
|
+
class InvocationMatcher < SpyVerificationProxy
|
27
|
+
attr_reader :failure_message
|
28
|
+
|
29
|
+
def initialize(method = nil)
|
30
|
+
method_missing(method) if method
|
31
|
+
end
|
32
|
+
|
33
|
+
def matches?(subject)
|
34
|
+
@verification.subject = subject
|
35
|
+
RR::Space.instance.recorded_calls.match_error(@verification) ? false : true
|
36
|
+
end
|
37
|
+
|
38
|
+
def nil?
|
39
|
+
false
|
40
|
+
end
|
41
|
+
|
42
|
+
def method_missing(method_name, *args, &block)
|
43
|
+
if @verification
|
44
|
+
@verification.send(method_name, *args)
|
45
|
+
else
|
46
|
+
@verification = super
|
47
|
+
end
|
48
|
+
self
|
49
|
+
end
|
50
|
+
end
|
21
51
|
end
|
22
52
|
end
|
23
53
|
end
|
data/lib/rr/double.rb
CHANGED
@@ -16,7 +16,7 @@ module RR
|
|
16
16
|
end
|
17
17
|
end
|
18
18
|
|
19
|
-
attr_reader :times_called, :double_injection, :definition
|
19
|
+
attr_reader :times_called, :double_injection, :definition, :times_called_expectation
|
20
20
|
include Space::Reader
|
21
21
|
|
22
22
|
def initialize(double_injection, definition)
|
@@ -25,193 +25,10 @@ module RR
|
|
25
25
|
@times_called = 0
|
26
26
|
@times_called_expectation = Expectations::TimesCalledExpectation.new(self)
|
27
27
|
definition.double = self
|
28
|
+
verify_method_signature if definition.verify_method_signature?
|
28
29
|
double_injection.register_double self
|
29
30
|
end
|
30
|
-
|
31
|
-
# Double#with sets the expectation that the Double will receive
|
32
|
-
# the passed in arguments.
|
33
|
-
#
|
34
|
-
# Passing in a block sets the return value.
|
35
|
-
#
|
36
|
-
# mock(subject).method_name.with(1, 2) {:return_value}
|
37
|
-
def with(*args, &returns)
|
38
|
-
definition.with(*args, &returns)
|
39
|
-
end
|
40
|
-
|
41
|
-
# Double#with_any_args sets the expectation that the Double can receive
|
42
|
-
# any arguments.
|
43
|
-
#
|
44
|
-
# Passing in a block sets the return value.
|
45
|
-
#
|
46
|
-
# mock(subject).method_name.with_any_args {:return_value}
|
47
|
-
def with_any_args(&returns)
|
48
|
-
definition.with_any_args(&returns)
|
49
|
-
end
|
50
|
-
|
51
|
-
# Double#with_no_args sets the expectation that the Double will receive
|
52
|
-
# no arguments.
|
53
|
-
#
|
54
|
-
# Passing in a block sets the return value.
|
55
|
-
#
|
56
|
-
# mock(subject).method_name.with_no_args {:return_value}
|
57
|
-
def with_no_args(&returns)
|
58
|
-
definition.with_no_args(&returns)
|
59
|
-
end
|
60
|
-
|
61
|
-
# Double#never sets the expectation that the Double will never be
|
62
|
-
# called.
|
63
|
-
#
|
64
|
-
# This method does not accept a block because it will never be called.
|
65
|
-
#
|
66
|
-
# mock(subject).method_name.never
|
67
|
-
def never
|
68
|
-
definition.never
|
69
|
-
end
|
70
|
-
|
71
|
-
# Double#once sets the expectation that the Double will be called
|
72
|
-
# 1 time.
|
73
|
-
#
|
74
|
-
# Passing in a block sets the return value.
|
75
|
-
#
|
76
|
-
# mock(subject).method_name.once {:return_value}
|
77
|
-
def once(&returns)
|
78
|
-
definition.once(&returns)
|
79
|
-
end
|
80
|
-
|
81
|
-
# Double#twice sets the expectation that the Double will be called
|
82
|
-
# 2 times.
|
83
|
-
#
|
84
|
-
# Passing in a block sets the return value.
|
85
|
-
#
|
86
|
-
# mock(subject).method_name.twice {:return_value}
|
87
|
-
def twice(&returns)
|
88
|
-
definition.twice(&returns)
|
89
|
-
end
|
90
|
-
|
91
|
-
# Double#at_least sets the expectation that the Double
|
92
|
-
# will be called at least n times.
|
93
|
-
# It works by creating a TimesCalledExpectation.
|
94
|
-
#
|
95
|
-
# Passing in a block sets the return value.
|
96
|
-
#
|
97
|
-
# mock(subject).method_name.at_least(4) {:return_value}
|
98
|
-
def at_least(number, &returns)
|
99
|
-
definition.at_least(number, &returns)
|
100
|
-
end
|
101
|
-
|
102
|
-
# Double#at_most allows sets the expectation that the Double
|
103
|
-
# will be called at most n times.
|
104
|
-
# It works by creating a TimesCalledExpectation.
|
105
|
-
#
|
106
|
-
# Passing in a block sets the return value.
|
107
|
-
#
|
108
|
-
# mock(subject).method_name.at_most(4) {:return_value}
|
109
|
-
def at_most(number, &returns)
|
110
|
-
definition.at_most(number, &returns)
|
111
|
-
end
|
112
|
-
|
113
|
-
# Double#any_number_of_times sets an that the Double will be called
|
114
|
-
# any number of times. This effectively removes the times called expectation
|
115
|
-
# from the Doublen
|
116
|
-
#
|
117
|
-
# Passing in a block sets the return value.
|
118
|
-
#
|
119
|
-
# mock(subject).method_name.any_number_of_times
|
120
|
-
def any_number_of_times(&returns)
|
121
|
-
definition.any_number_of_times(&returns)
|
122
|
-
end
|
123
|
-
|
124
|
-
# Double#times creates an TimesCalledExpectation of the passed
|
125
|
-
# in number.
|
126
|
-
#
|
127
|
-
# Passing in a block sets the return value.
|
128
|
-
#
|
129
|
-
# mock(subject).method_name.times(4) {:return_value}
|
130
|
-
def times(number, &returns)
|
131
|
-
definition.times(number, &returns)
|
132
|
-
end
|
133
|
-
|
134
|
-
# Double#ordered sets the Double to have an ordered
|
135
|
-
# expectation.
|
136
|
-
#
|
137
|
-
# Passing in a block sets the return value.
|
138
|
-
#
|
139
|
-
# mock(subject).method_name.ordered {return_value}
|
140
|
-
def ordered(&returns)
|
141
|
-
definition.ordered(&returns)
|
142
|
-
end
|
143
|
-
|
144
|
-
# Double#ordered? returns true when the Double is ordered.
|
145
|
-
#
|
146
|
-
# mock(subject).method_name.ordered?
|
147
|
-
def ordered?
|
148
|
-
definition.ordered?
|
149
|
-
end
|
150
|
-
|
151
|
-
# Double#verbose sets the Double to print out each method call it receives.
|
152
|
-
#
|
153
|
-
# Passing in a block sets the return value
|
154
|
-
def verbose(&block)
|
155
|
-
definition.verbose(&block)
|
156
|
-
end
|
157
|
-
|
158
|
-
# Double#verbose? returns true when verbose has been called on it. It returns
|
159
|
-
# true when the double is set to print each method call it receives.
|
160
|
-
def verbose?
|
161
|
-
definition.verbose?
|
162
|
-
end
|
163
|
-
|
164
|
-
# Double#yields sets the Double to invoke a passed in block when
|
165
|
-
# the Double is called.
|
166
|
-
# An Expection will be raised if no block is passed in when the
|
167
|
-
# Double is called.
|
168
|
-
#
|
169
|
-
# Passing in a block sets the return value.
|
170
|
-
#
|
171
|
-
# mock(subject).method_name.yields(yield_arg1, yield_arg2) {return_value}
|
172
|
-
# subject.method_name {|yield_arg1, yield_arg2|}
|
173
|
-
def yields(*args, &returns)
|
174
|
-
definition.yields(*args, &returns)
|
175
|
-
end
|
176
|
-
|
177
|
-
# Double#after_call creates a callback that occurs after call
|
178
|
-
# is called. The passed in block receives the return value of
|
179
|
-
# the Double being called.
|
180
|
-
# An Expection will be raised if no block is passed in.
|
181
|
-
#
|
182
|
-
# mock(subject).method_name {return_value}.after_call {|return_value|}
|
183
|
-
# subject.method_name # return_value
|
184
|
-
#
|
185
|
-
# This feature is built into proxies.
|
186
|
-
# mock.proxy(User).find('1') {|user| mock(user).valid? {false}}
|
187
|
-
def after_call(&block)
|
188
|
-
definition.after_call &block
|
189
|
-
end
|
190
|
-
|
191
|
-
# Double#returns accepts an argument value or a block.
|
192
|
-
# It will raise an ArgumentError if both are passed in.
|
193
|
-
#
|
194
|
-
# Passing in a block causes Double to return the return value of
|
195
|
-
# the passed in block.
|
196
|
-
#
|
197
|
-
# Passing in an argument causes Double to return the argument.
|
198
|
-
def returns(*args, &implementation)
|
199
|
-
definition.returns(*args, &implementation)
|
200
|
-
end
|
201
|
-
|
202
|
-
# Double#implemented_by sets the implementation of the Double.
|
203
|
-
# This method takes a Proc or a Method. Passing in a Method allows
|
204
|
-
# the Double to accept blocks.
|
205
|
-
#
|
206
|
-
# obj = Object.new
|
207
|
-
# def obj.foobar
|
208
|
-
# yield(1)
|
209
|
-
# end
|
210
|
-
# mock(obj).method_name.implemented_by(obj.method(:foobar))
|
211
|
-
def implemented_by(implementation)
|
212
|
-
definition.implemented_by implementation
|
213
|
-
end
|
214
|
-
|
31
|
+
|
215
32
|
# Double#call calls the Double's implementation. The return
|
216
33
|
# value of the implementation is returned.
|
217
34
|
#
|
@@ -228,23 +45,6 @@ module RR
|
|
228
45
|
definition.after_call_proc ? extract_subject_from_return_value(definition.after_call_proc.call(return_value)) : return_value
|
229
46
|
end
|
230
47
|
|
231
|
-
def yields!(block)
|
232
|
-
if definition.yields_value
|
233
|
-
if block
|
234
|
-
block.call(*definition.yields_value)
|
235
|
-
else
|
236
|
-
raise ArgumentError, "A Block must be passed into the method call when using yields"
|
237
|
-
end
|
238
|
-
end
|
239
|
-
end
|
240
|
-
protected :yields!
|
241
|
-
|
242
|
-
def call_implementation(double_injection, *args, &block)
|
243
|
-
return_value = do_call_implementation_and_get_return_value(double_injection, *args, &block)
|
244
|
-
extract_subject_from_return_value(return_value)
|
245
|
-
end
|
246
|
-
protected :call_implementation
|
247
|
-
|
248
48
|
# Double#exact_match? returns true when the passed in arguments
|
249
49
|
# exactly match the ArgumentEqualityExpectation arguments.
|
250
50
|
def exact_match?(*arguments)
|
@@ -260,7 +60,7 @@ module RR
|
|
260
60
|
# Double#attempt? returns true when the
|
261
61
|
# TimesCalledExpectation is satisfied.
|
262
62
|
def attempt?
|
263
|
-
|
63
|
+
verify_times_matcher_is_set
|
264
64
|
times_called_expectation.attempt?
|
265
65
|
end
|
266
66
|
|
@@ -268,13 +68,13 @@ module RR
|
|
268
68
|
# is satisfied for this double. A TimesCalledError
|
269
69
|
# is raised if the TimesCalledExpectation is not met.
|
270
70
|
def verify
|
271
|
-
|
71
|
+
verify_times_matcher_is_set
|
272
72
|
times_called_expectation.verify!
|
273
73
|
true
|
274
74
|
end
|
275
75
|
|
276
76
|
def terminal?
|
277
|
-
|
77
|
+
verify_times_matcher_is_set
|
278
78
|
times_called_expectation.terminal?
|
279
79
|
end
|
280
80
|
|
@@ -285,41 +85,85 @@ module RR
|
|
285
85
|
|
286
86
|
# The Arguments that this Double expects
|
287
87
|
def expected_arguments
|
288
|
-
|
88
|
+
verify_argument_expectation_is_set
|
289
89
|
argument_expectation.expected_arguments
|
290
90
|
end
|
291
91
|
|
292
92
|
# The TimesCalledMatcher for the TimesCalledExpectation
|
293
93
|
def times_matcher
|
294
|
-
|
94
|
+
definition.times_matcher
|
295
95
|
end
|
296
96
|
|
297
|
-
def
|
298
|
-
|
299
|
-
@times_called_expectation
|
97
|
+
def formatted_name
|
98
|
+
self.class.formatted_name(method_name, expected_arguments)
|
300
99
|
end
|
301
100
|
|
302
|
-
|
303
|
-
|
101
|
+
protected
|
102
|
+
def ordered?
|
103
|
+
definition.ordered?
|
104
|
+
end
|
105
|
+
|
106
|
+
def verbose?
|
107
|
+
definition.verbose?
|
304
108
|
end
|
305
|
-
|
306
|
-
|
109
|
+
|
110
|
+
def yields!(block)
|
111
|
+
if definition.yields_value
|
112
|
+
if block
|
113
|
+
block.call(*definition.yields_value)
|
114
|
+
else
|
115
|
+
raise ArgumentError, "A Block must be passed into the method call when using yields"
|
116
|
+
end
|
117
|
+
end
|
307
118
|
end
|
308
|
-
protected :implementation=
|
309
119
|
|
310
|
-
def
|
311
|
-
|
120
|
+
def call_implementation(double_injection, *args, &block)
|
121
|
+
return_value = do_call_implementation_and_get_return_value(double_injection, *args, &block)
|
122
|
+
extract_subject_from_return_value(return_value)
|
312
123
|
end
|
313
|
-
|
314
|
-
|
124
|
+
|
125
|
+
def verify_times_matcher_is_set
|
126
|
+
unless definition.times_matcher
|
127
|
+
raise RR::Errors::DoubleDefinitionError, "#definition.times_matcher is not set"
|
128
|
+
end
|
315
129
|
end
|
316
|
-
protected :argument_expectation=
|
317
130
|
|
318
|
-
def
|
319
|
-
|
131
|
+
def verify_argument_expectation_is_set
|
132
|
+
unless definition.argument_expectation
|
133
|
+
raise RR::Errors::DoubleDefinitionError, "#definition.argument_expectation is not set"
|
134
|
+
end
|
320
135
|
end
|
321
136
|
|
322
|
-
|
137
|
+
def verify_method_signature
|
138
|
+
raise RR::Errors::SubjectDoesNotImplementMethodError unless definition.subject.respond_to?(double_injection.send(:original_method_name))
|
139
|
+
raise RR::Errors::SubjectHasDifferentArityError unless arity_matches?
|
140
|
+
end
|
141
|
+
|
142
|
+
def subject_arity
|
143
|
+
definition.subject.method(double_injection.send(:original_method_name)).arity
|
144
|
+
end
|
145
|
+
|
146
|
+
def subject_accepts_only_varargs?
|
147
|
+
subject_arity == -1
|
148
|
+
end
|
149
|
+
|
150
|
+
def subject_accepts_varargs?
|
151
|
+
subject_arity < 0
|
152
|
+
end
|
153
|
+
|
154
|
+
def arity_matches?
|
155
|
+
return true if subject_accepts_only_varargs?
|
156
|
+
if subject_accepts_varargs?
|
157
|
+
return ((subject_arity * -1) - 1) <= args.size
|
158
|
+
else
|
159
|
+
return subject_arity == args.size
|
160
|
+
end
|
161
|
+
end
|
162
|
+
|
163
|
+
def args
|
164
|
+
definition.argument_expectation.expected_arguments
|
165
|
+
end
|
166
|
+
|
323
167
|
def do_call_implementation_and_get_return_value(double_injection, *args, &block)
|
324
168
|
if definition.implementation_is_original_method?
|
325
169
|
if double_injection.object_has_original_method?
|
@@ -349,12 +193,20 @@ module RR
|
|
349
193
|
def extract_subject_from_return_value(return_value)
|
350
194
|
case return_value
|
351
195
|
when DoubleDefinitions::DoubleDefinition
|
352
|
-
return_value.
|
196
|
+
return_value.root_subject
|
353
197
|
when DoubleDefinitions::DoubleDefinitionCreatorProxy
|
354
|
-
return_value.__creator__.
|
198
|
+
return_value.__creator__.root_subject
|
355
199
|
else
|
356
200
|
return_value
|
357
201
|
end
|
358
202
|
end
|
203
|
+
|
204
|
+
def implementation
|
205
|
+
definition.implementation
|
206
|
+
end
|
207
|
+
|
208
|
+
def argument_expectation
|
209
|
+
definition.argument_expectation
|
210
|
+
end
|
359
211
|
end
|
360
|
-
end
|
212
|
+
end
|