rr 0.4.3 → 0.4.4
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.
- 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;
|