rr 0.4.3 → 0.4.4
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGES +4 -0
- data/README +25 -0
- data/Rakefile +1 -1
- data/lib/rr/double.rb +10 -10
- data/lib/rr/double_creator.rb +5 -5
- data/lib/rr/double_injection.rb +7 -7
- data/lib/rr/double_method_proxy.rb +1 -2
- data/lib/rr/space.rb +21 -21
- data/lib/rr/wildcard_matchers/anything.rb +4 -0
- data/lib/rr/wildcard_matchers/boolean.rb +4 -0
- data/lib/rr/wildcard_matchers/duck_type.rb +7 -0
- data/lib/rr/wildcard_matchers/is_a.rb +4 -0
- data/lib/rr/wildcard_matchers/numeric.rb +4 -0
- data/spec/high_level_spec.rb +14 -0
- data/spec/rr/adapters/rr_methods_space_spec.rb +16 -16
- data/spec/rr/double/double_injection_bind_spec.rb +47 -20
- data/spec/rr/double/double_injection_dispatching_spec.rb +26 -20
- data/spec/rr/double/double_injection_has_original_method_spec.rb +10 -11
- data/spec/rr/double/double_injection_register_scenario_spec.rb +6 -6
- data/spec/rr/double/double_injection_reset_spec.rb +11 -14
- data/spec/rr/double/double_injection_spec.rb +18 -12
- data/spec/rr/double/double_injection_verify_spec.rb +5 -5
- data/spec/rr/double_definition_spec.rb +5 -5
- data/spec/rr/double_method_proxy_spec.rb +5 -5
- data/spec/rr/double_spec.rb +48 -48
- data/spec/rr/expectations/anything_spec.rb +14 -0
- data/spec/rr/expectations/boolean_spec.rb +14 -0
- data/spec/rr/expectations/duck_type_spec.rb +14 -0
- data/spec/rr/expectations/is_a_spec.rb +14 -0
- data/spec/rr/expectations/numeric_spec.rb +14 -0
- data/spec/rr/expectations/range_spec.rb +10 -0
- data/spec/rr/expectations/regexp_spec.rb +10 -0
- data/spec/rr/expectations/times_called_expectation/times_called_expectation_helper.rb +3 -3
- data/spec/rr/rspec/rspec_adapter_spec.rb +12 -12
- data/spec/rr/space/space_create_spec.rb +27 -37
- data/spec/rr/space/space_register_spec.rb +3 -3
- data/spec/rr/space/space_reset_spec.rb +24 -24
- data/spec/rr/space/space_spec.rb +2 -2
- data/spec/rr/space/space_verify_spec.rb +18 -18
- metadata +9 -2
data/CHANGES
CHANGED
data/README
CHANGED
@@ -186,6 +186,30 @@ Put double scenarios on instances of a Class.
|
|
186
186
|
m.system("rake baz") {true}
|
187
187
|
end
|
188
188
|
|
189
|
+
=== Wildcard matchers
|
190
|
+
==== anything
|
191
|
+
mock(object).foobar(1, anything)
|
192
|
+
object.foobar(1, :my_symbol)
|
193
|
+
|
194
|
+
==== is_a
|
195
|
+
mock(object).foobar(is_a(Time))
|
196
|
+
object.foobar(Time.now)
|
197
|
+
|
198
|
+
==== numeric
|
199
|
+
mock(object).foobar(numeric)
|
200
|
+
object.foobar(99)
|
201
|
+
|
202
|
+
==== numeric
|
203
|
+
mock(object).foobar(boolean)
|
204
|
+
object.foobar(false)
|
205
|
+
|
206
|
+
==== duck_type
|
207
|
+
mock(object).foobar(duck_type(:walk, :talk))
|
208
|
+
arg = Object.new
|
209
|
+
def arg.walk; 'waddle'; end
|
210
|
+
def arg.talk; 'quack'; end
|
211
|
+
object.foobar(arg)
|
212
|
+
|
189
213
|
== Special Thanks To
|
190
214
|
With any development effort, there are countless people who have contributed
|
191
215
|
to making it possible. We all are standing on the shoulders of giants.
|
@@ -193,6 +217,7 @@ to making it possible. We all are standing on the shoulders of giants.
|
|
193
217
|
* Parker Thompson for pairing with me
|
194
218
|
* Felix Morio for pairing with me
|
195
219
|
* Jeff Whitmire for documentation suggestions
|
220
|
+
* Nick Kallen for documentation suggestion & bug reports
|
196
221
|
* David Chelimsky for encouragement to make the RR framework, for developing
|
197
222
|
the Rspec mock framework, and syntax ideas
|
198
223
|
* Gerald Meszaros for his excellent book "xUnit Test Patterns"
|
data/Rakefile
CHANGED
data/lib/rr/double.rb
CHANGED
@@ -16,11 +16,11 @@ module RR
|
|
16
16
|
end
|
17
17
|
end
|
18
18
|
|
19
|
-
attr_reader :times_called, :
|
19
|
+
attr_reader :times_called, :double_injection, :definition
|
20
20
|
|
21
|
-
def initialize(space,
|
21
|
+
def initialize(space, double_injection, definition)
|
22
22
|
@space = space
|
23
|
-
@
|
23
|
+
@double_injection = double_injection
|
24
24
|
@definition = definition
|
25
25
|
@times_called = 0
|
26
26
|
@times_called_expectation = Expectations::TimesCalledExpectation.new(self)
|
@@ -216,11 +216,11 @@ module RR
|
|
216
216
|
#
|
217
217
|
# A TimesCalledError is raised when the times called
|
218
218
|
# exceeds the expected TimesCalledExpectation.
|
219
|
-
def call(
|
219
|
+
def call(double_injection, *args, &block)
|
220
220
|
self.times_called_expectation.attempt! if definition.times_matcher
|
221
221
|
@space.verify_ordered_double(self) if ordered?
|
222
222
|
yields!(block)
|
223
|
-
return_value = call_implementation(
|
223
|
+
return_value = call_implementation(double_injection, *args, &block)
|
224
224
|
return return_value unless definition.after_call_value
|
225
225
|
definition.after_call_value.call(return_value)
|
226
226
|
end
|
@@ -235,14 +235,14 @@ module RR
|
|
235
235
|
end
|
236
236
|
protected :yields!
|
237
237
|
|
238
|
-
def call_implementation(
|
238
|
+
def call_implementation(double_injection, *args, &block)
|
239
239
|
return nil unless implementation
|
240
240
|
|
241
241
|
if implementation === DoubleDefinition::ORIGINAL_METHOD
|
242
|
-
if
|
243
|
-
return
|
242
|
+
if double_injection.object_has_original_method?
|
243
|
+
return double_injection.call_original_method(*args, &block)
|
244
244
|
else
|
245
|
-
return
|
245
|
+
return double_injection.object.__send__(
|
246
246
|
:method_missing,
|
247
247
|
method_name,
|
248
248
|
*args,
|
@@ -295,7 +295,7 @@ module RR
|
|
295
295
|
|
296
296
|
# The method name that this Double is attatched to
|
297
297
|
def method_name
|
298
|
-
|
298
|
+
double_injection.method_name
|
299
299
|
end
|
300
300
|
|
301
301
|
# The Arguments that this Double expects
|
data/lib/rr/double_creator.rb
CHANGED
@@ -200,21 +200,21 @@ module RR
|
|
200
200
|
|
201
201
|
protected
|
202
202
|
def setup_double(subject, method_name)
|
203
|
-
@
|
204
|
-
@double = @space.double(@
|
203
|
+
@double_injection = @space.double_injection(subject, method_name)
|
204
|
+
@double = @space.double(@double_injection)
|
205
205
|
@definition = @double.definition
|
206
206
|
end
|
207
207
|
|
208
208
|
def setup_class_probing_instances(subject, method_name)
|
209
|
-
class_double = @space.
|
209
|
+
class_double = @space.double_injection(subject, :new)
|
210
210
|
class_double = @space.double(class_double)
|
211
211
|
|
212
212
|
instance_method_name = method_name
|
213
213
|
|
214
214
|
@definition = @space.double_definition
|
215
215
|
class_handler = proc do |return_value|
|
216
|
-
|
217
|
-
@space.double(
|
216
|
+
double_injection = @space.double_injection(return_value, instance_method_name)
|
217
|
+
@space.double(double_injection, @definition)
|
218
218
|
return_value
|
219
219
|
end
|
220
220
|
|
data/lib/rr/double_injection.rb
CHANGED
@@ -1,13 +1,12 @@
|
|
1
1
|
module RR
|
2
2
|
# RR::DoubleInjection is the binding of an object and a method.
|
3
|
-
# A
|
3
|
+
# A double_injection has 0 to many Double objects. Each Double
|
4
4
|
# has Argument Expectations and Times called Expectations.
|
5
5
|
class DoubleInjection
|
6
6
|
MethodArguments = Struct.new(:arguments, :block)
|
7
|
-
attr_reader :
|
7
|
+
attr_reader :object, :method_name, :doubles
|
8
8
|
|
9
|
-
def initialize(
|
10
|
-
@space = space
|
9
|
+
def initialize(object, method_name)
|
11
10
|
@object = object
|
12
11
|
@method_name = method_name.to_sym
|
13
12
|
if object_has_method?(method_name)
|
@@ -30,7 +29,7 @@ module RR
|
|
30
29
|
returns_method = <<-METHOD
|
31
30
|
def #{@method_name}(*args, &block)
|
32
31
|
arguments = MethodArguments.new(args, block)
|
33
|
-
#{placeholder_name}
|
32
|
+
__send__('#{placeholder_name}', arguments)
|
34
33
|
end
|
35
34
|
METHOD
|
36
35
|
meta.class_eval(returns_method, __FILE__, __LINE__ - 5)
|
@@ -69,7 +68,7 @@ module RR
|
|
69
68
|
def define_implementation_placeholder
|
70
69
|
me = self
|
71
70
|
meta.send(:define_method, placeholder_name) do |arguments|
|
72
|
-
me.
|
71
|
+
me.__send__(:call_method, arguments.arguments, arguments.block)
|
73
72
|
end
|
74
73
|
end
|
75
74
|
|
@@ -108,7 +107,8 @@ module RR
|
|
108
107
|
end
|
109
108
|
|
110
109
|
def double_not_found_error(*args)
|
111
|
-
message = "
|
110
|
+
message = "On object #{object},\n"
|
111
|
+
message << "unexpected method invocation #{Double.formatted_name(@method_name, args)}, expected\n"
|
112
112
|
message << Double.list_message_part(@doubles)
|
113
113
|
raise Errors::DoubleNotFoundError, message
|
114
114
|
end
|
data/lib/rr/space.rb
CHANGED
@@ -15,10 +15,10 @@ module RR
|
|
15
15
|
end
|
16
16
|
end
|
17
17
|
|
18
|
-
attr_reader :
|
18
|
+
attr_reader :double_injections, :ordered_doubles
|
19
19
|
attr_accessor :trim_backtrace
|
20
20
|
def initialize
|
21
|
-
@
|
21
|
+
@double_injections = HashWithObjectIdKey.new
|
22
22
|
@ordered_doubles = []
|
23
23
|
@trim_backtrace = false
|
24
24
|
end
|
@@ -27,7 +27,7 @@ module RR
|
|
27
27
|
if method_name && definition
|
28
28
|
raise ArgumentError, "Cannot pass in a method name and a block"
|
29
29
|
end
|
30
|
-
proxy = DoubleMethodProxy.new(
|
30
|
+
proxy = DoubleMethodProxy.new(creator, object, &definition)
|
31
31
|
return proxy unless method_name
|
32
32
|
proxy.__send__(method_name)
|
33
33
|
end
|
@@ -38,10 +38,10 @@ module RR
|
|
38
38
|
end
|
39
39
|
|
40
40
|
# Creates and registers a Double to be verified.
|
41
|
-
def double(
|
42
|
-
double = Double.new(self,
|
41
|
+
def double(double_injection, definition = double_definition)
|
42
|
+
double = Double.new(self, double_injection, definition)
|
43
43
|
double.definition.double = double
|
44
|
-
|
44
|
+
double_injection.register_double double
|
45
45
|
double
|
46
46
|
end
|
47
47
|
|
@@ -53,14 +53,14 @@ module RR
|
|
53
53
|
# in object and method_name.
|
54
54
|
# When a DoubleInjection is created, it binds the dispatcher to the
|
55
55
|
# object.
|
56
|
-
def
|
57
|
-
|
58
|
-
return
|
56
|
+
def double_injection(object, method_name)
|
57
|
+
double_injection = @double_injections[object][method_name.to_sym]
|
58
|
+
return double_injection if double_injection
|
59
59
|
|
60
|
-
|
61
|
-
@
|
62
|
-
|
63
|
-
|
60
|
+
double_injection = DoubleInjection.new(object, method_name.to_sym)
|
61
|
+
@double_injections[object][method_name.to_sym] = double_injection
|
62
|
+
double_injection.bind
|
63
|
+
double_injection
|
64
64
|
end
|
65
65
|
|
66
66
|
# Registers the ordered Double to be verified.
|
@@ -88,7 +88,7 @@ module RR
|
|
88
88
|
# Verifies all the DoubleInjection objects have met their
|
89
89
|
# TimesCalledExpectations.
|
90
90
|
def verify_doubles
|
91
|
-
@
|
91
|
+
@double_injections.each do |object, method_double_map|
|
92
92
|
method_double_map.keys.each do |method_name|
|
93
93
|
verify_double(object, method_name)
|
94
94
|
end
|
@@ -98,21 +98,21 @@ module RR
|
|
98
98
|
# Resets the registered Doubles and ordered Doubles
|
99
99
|
def reset
|
100
100
|
reset_ordered_doubles
|
101
|
-
|
101
|
+
reset_double_injections
|
102
102
|
end
|
103
103
|
|
104
104
|
# Verifies the DoubleInjection for the passed in object and method_name.
|
105
105
|
def verify_double(object, method_name)
|
106
|
-
@
|
106
|
+
@double_injections[object][method_name].verify
|
107
107
|
ensure
|
108
108
|
reset_double object, method_name
|
109
109
|
end
|
110
110
|
|
111
111
|
# Resets the DoubleInjection for the passed in object and method_name.
|
112
112
|
def reset_double(object, method_name)
|
113
|
-
|
114
|
-
@
|
115
|
-
|
113
|
+
double_injection = @double_injections[object].delete(method_name)
|
114
|
+
@double_injections.delete(object) if @double_injections[object].empty?
|
115
|
+
double_injection.reset
|
116
116
|
end
|
117
117
|
|
118
118
|
protected
|
@@ -122,8 +122,8 @@ module RR
|
|
122
122
|
end
|
123
123
|
|
124
124
|
# Resets the registered Doubles for the next test run.
|
125
|
-
def
|
126
|
-
@
|
125
|
+
def reset_double_injections
|
126
|
+
@double_injections.each do |object, method_double_map|
|
127
127
|
method_double_map.keys.each do |method_name|
|
128
128
|
reset_double(object, method_name)
|
129
129
|
end
|
@@ -15,6 +15,13 @@ module RR
|
|
15
15
|
return true
|
16
16
|
end
|
17
17
|
|
18
|
+
def inspect
|
19
|
+
formatted_required_methods = required_methods.collect do |method_name|
|
20
|
+
method_name.inspect
|
21
|
+
end.join(', ')
|
22
|
+
"duck_type(#{formatted_required_methods})"
|
23
|
+
end
|
24
|
+
|
18
25
|
def ==(other)
|
19
26
|
return false unless other.is_a?(self.class)
|
20
27
|
self.required_methods == other.required_methods
|
data/spec/high_level_spec.rb
CHANGED
@@ -60,6 +60,15 @@ describe "RR mock:" do
|
|
60
60
|
@obj.foobar(:failure)
|
61
61
|
end.should raise_error( RR::Errors::DoubleNotFoundError )
|
62
62
|
end
|
63
|
+
|
64
|
+
it "mocks methods without letters" do
|
65
|
+
mock(@obj) == 55
|
66
|
+
|
67
|
+
@obj == 55
|
68
|
+
proc do
|
69
|
+
@obj == 99
|
70
|
+
end.should raise_error(RR::Errors::DoubleNotFoundError)
|
71
|
+
end
|
63
72
|
end
|
64
73
|
|
65
74
|
describe "RR proxy:" do
|
@@ -170,4 +179,9 @@ describe "RR stub:" do
|
|
170
179
|
end
|
171
180
|
Date.new.to_s.should == "The Date"
|
172
181
|
end
|
182
|
+
|
183
|
+
it "stubs methods without letters" do
|
184
|
+
stub(@obj).__send__(:==) {:equality}
|
185
|
+
(@obj == 55).should == :equality
|
186
|
+
end
|
173
187
|
end
|
@@ -20,16 +20,16 @@ module RR
|
|
20
20
|
end
|
21
21
|
|
22
22
|
describe RRMethods, "#verify" do
|
23
|
-
it "#verify verifies and deletes the
|
24
|
-
|
23
|
+
it "#verify verifies and deletes the double_injections" do
|
24
|
+
verifies_all_double_injections {verify}
|
25
25
|
end
|
26
26
|
|
27
|
-
it "#rr_verify verifies and deletes the
|
28
|
-
|
27
|
+
it "#rr_verify verifies and deletes the double_injections" do
|
28
|
+
verifies_all_double_injections {rr_verify}
|
29
29
|
end
|
30
30
|
|
31
|
-
def
|
32
|
-
double1 = @space.
|
31
|
+
def verifies_all_double_injections
|
32
|
+
double1 = @space.double_injection(@object1, @method_name)
|
33
33
|
double1_verify_calls = 0
|
34
34
|
double1_reset_calls = 0
|
35
35
|
(
|
@@ -43,7 +43,7 @@ module RR
|
|
43
43
|
double1_reset_calls += 1
|
44
44
|
end
|
45
45
|
end
|
46
|
-
double2 = @space.
|
46
|
+
double2 = @space.double_injection(@object2, @method_name)
|
47
47
|
double2_verify_calls = 0
|
48
48
|
double2_reset_calls = 0
|
49
49
|
(
|
@@ -75,17 +75,17 @@ module RR
|
|
75
75
|
removes_ordered_doubles {rr_reset}
|
76
76
|
end
|
77
77
|
|
78
|
-
it "#reset resets all
|
79
|
-
|
78
|
+
it "#reset resets all double_injections" do
|
79
|
+
resets_all_double_injections {reset}
|
80
80
|
end
|
81
81
|
|
82
|
-
it "#rr_reset resets all
|
83
|
-
|
82
|
+
it "#rr_reset resets all double_injections" do
|
83
|
+
resets_all_double_injections {rr_reset}
|
84
84
|
end
|
85
85
|
|
86
86
|
def removes_ordered_doubles
|
87
|
-
double1 = @space.
|
88
|
-
double2 = @space.
|
87
|
+
double1 = @space.double_injection(@object1, :foobar1)
|
88
|
+
double2 = @space.double_injection(@object1, :foobar2)
|
89
89
|
|
90
90
|
double1 = @space.double(double1)
|
91
91
|
double2 = @space.double(double2)
|
@@ -99,8 +99,8 @@ module RR
|
|
99
99
|
@space.ordered_doubles.should be_empty
|
100
100
|
end
|
101
101
|
|
102
|
-
def
|
103
|
-
double1 = @space.
|
102
|
+
def resets_all_double_injections
|
103
|
+
double1 = @space.double_injection(@object1, @method_name)
|
104
104
|
double1_reset_calls = 0
|
105
105
|
(
|
106
106
|
class << double1;
|
@@ -110,7 +110,7 @@ module RR
|
|
110
110
|
double1_reset_calls += 1
|
111
111
|
end
|
112
112
|
end
|
113
|
-
double2 = @space.
|
113
|
+
double2 = @space.double_injection(@object2, @method_name)
|
114
114
|
double2_reset_calls = 0
|
115
115
|
(
|
116
116
|
class << double2;
|