rr 0.3.11 → 0.4.0
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 +8 -3
- data/README +130 -39
- data/Rakefile +6 -5
- data/lib/rr.rb +8 -8
- data/lib/rr/adapters/rr_methods.rb +228 -0
- data/lib/rr/adapters/rspec.rb +1 -1
- data/lib/rr/adapters/test_unit.rb +1 -1
- data/lib/rr/double.rb +294 -89
- data/lib/rr/{scenario_creator.rb → double_creator.rb} +65 -66
- data/lib/rr/{scenario_definition.rb → double_definition.rb} +36 -36
- data/lib/rr/{scenario_definition_builder.rb → double_definition_builder.rb} +3 -3
- data/lib/rr/double_insertion.rb +132 -0
- data/lib/rr/{scenario_matches.rb → double_matches.rb} +2 -2
- data/lib/rr/{scenario_method_proxy.rb → double_method_proxy.rb} +2 -2
- data/lib/rr/errors/argument_equality_error.rb +3 -3
- data/lib/rr/errors/rr_error.rb +13 -13
- data/lib/rr/errors/scenario_definition_error.rb +3 -3
- data/lib/rr/errors/scenario_not_found_error.rb +3 -3
- data/lib/rr/errors/scenario_order_error.rb +3 -3
- data/lib/rr/errors/times_called_error.rb +3 -3
- data/lib/rr/expectations/any_argument_expectation.rb +1 -1
- data/lib/rr/expectations/argument_equality_expectation.rb +1 -1
- data/lib/rr/expectations/times_called_expectation.rb +1 -1
- data/lib/rr/hash_with_object_id_key.rb +1 -1
- data/lib/rr/space.rb +40 -40
- data/lib/rr/times_called_matchers/any_times_matcher.rb +13 -13
- data/lib/rr/times_called_matchers/at_least_matcher.rb +11 -11
- data/lib/rr/times_called_matchers/at_most_matcher.rb +16 -16
- data/lib/rr/times_called_matchers/integer_matcher.rb +13 -13
- data/lib/rr/times_called_matchers/non_terminal.rb +21 -21
- data/lib/rr/times_called_matchers/proc_matcher.rb +7 -7
- data/lib/rr/times_called_matchers/range_matcher.rb +14 -14
- data/lib/rr/times_called_matchers/terminal.rb +16 -16
- data/lib/rr/times_called_matchers/times_called_matcher.rb +32 -32
- data/spec/core_spec_suite.rb +18 -0
- data/{examples → spec}/environment_fixture_setup.rb +0 -1
- data/{examples/high_level_example.rb → spec/high_level_spec.rb} +11 -11
- data/spec/rr/adapters/rr_methods_argument_matcher_spec.rb +67 -0
- data/spec/rr/adapters/rr_methods_creator_spec.rb +365 -0
- data/spec/rr/adapters/rr_methods_space_spec.rb +134 -0
- data/spec/rr/adapters/rr_methods_spec_helper.rb +11 -0
- data/{examples/rr/extensions/instance_methods_times_matcher_example.rb → spec/rr/adapters/rr_methods_times_matcher_spec.rb} +4 -4
- data/spec/rr/double/double_insertion_bind_spec.rb +78 -0
- data/spec/rr/double/double_insertion_dispatching_spec.rb +221 -0
- data/spec/rr/double/double_insertion_has_original_method_spec.rb +56 -0
- data/spec/rr/double/double_insertion_register_scenario_spec.rb +24 -0
- data/spec/rr/double/double_insertion_reset_spec.rb +89 -0
- data/spec/rr/double/double_insertion_spec.rb +66 -0
- data/spec/rr/double/double_insertion_verify_spec.rb +23 -0
- data/spec/rr/double_creator_spec.rb +454 -0
- data/{examples/rr/scenario_definition_example.rb → spec/rr/double_definition_spec.rb} +143 -143
- data/spec/rr/double_method_proxy_spec.rb +71 -0
- data/spec/rr/double_spec.rb +654 -0
- data/spec/rr/errors/rr_error_spec.rb +65 -0
- data/spec/rr/expectations/any_argument_expectation_spec.rb +47 -0
- data/spec/rr/expectations/anything_argument_equality_expectation_spec.rb +38 -0
- data/spec/rr/expectations/argument_equality_expectation_spec.rb +58 -0
- data/spec/rr/expectations/boolean_argument_equality_expectation_spec.rb +53 -0
- data/spec/rr/expectations/duck_type_argument_equality_expectation_spec.rb +71 -0
- data/spec/rr/expectations/is_a_argument_equality_expectation_spec.rb +51 -0
- data/spec/rr/expectations/numeric_argument_equality_expectation_spec.rb +47 -0
- data/spec/rr/expectations/range_argument_equality_expectation_spec.rb +59 -0
- data/spec/rr/expectations/regexp_argument_equality_expectation_spec.rb +72 -0
- data/spec/rr/expectations/times_called_expectation/times_called_expectation_any_times_spec.rb +43 -0
- data/spec/rr/expectations/times_called_expectation/times_called_expectation_at_least_spec.rb +67 -0
- data/spec/rr/expectations/times_called_expectation/times_called_expectation_at_most_spec.rb +71 -0
- data/spec/rr/expectations/times_called_expectation/times_called_expectation_helper.rb +21 -0
- data/spec/rr/expectations/times_called_expectation/times_called_expectation_integer_spec.rb +103 -0
- data/spec/rr/expectations/times_called_expectation/times_called_expectation_proc_spec.rb +79 -0
- data/spec/rr/expectations/times_called_expectation/times_called_expectation_range_spec.rb +81 -0
- data/spec/rr/expectations/times_called_expectation/times_called_expectation_spec.rb +40 -0
- data/spec/rr/rspec/rspec_adapter_spec.rb +65 -0
- data/spec/rr/rspec/rspec_backtrace_tweaking_spec.rb +52 -0
- data/spec/rr/rspec/rspec_usage_spec.rb +67 -0
- data/spec/rr/space/hash_with_object_id_key_spec.rb +88 -0
- data/spec/rr/space/space_create_spec.rb +278 -0
- data/spec/rr/space/space_helper.rb +7 -0
- data/spec/rr/space/space_register_spec.rb +32 -0
- data/spec/rr/space/space_reset_spec.rb +131 -0
- data/spec/rr/space/space_spec.rb +32 -0
- data/spec/rr/space/space_verify_spec.rb +181 -0
- data/{examples → spec}/rr/test_unit/test_helper.rb +1 -1
- data/{examples → spec}/rr/test_unit/test_unit_backtrace_test.rb +0 -0
- data/{examples → spec}/rr/test_unit/test_unit_integration_test.rb +4 -4
- data/spec/rr/times_called_matchers/any_times_matcher_spec.rb +47 -0
- data/spec/rr/times_called_matchers/at_least_matcher_spec.rb +55 -0
- data/spec/rr/times_called_matchers/at_most_matcher_spec.rb +70 -0
- data/spec/rr/times_called_matchers/integer_matcher_spec.rb +70 -0
- data/spec/rr/times_called_matchers/proc_matcher_spec.rb +55 -0
- data/spec/rr/times_called_matchers/range_matcher_spec.rb +76 -0
- data/spec/rr/times_called_matchers/times_called_matcher_spec.rb +118 -0
- data/spec/rspec_spec_suite.rb +16 -0
- data/spec/spec_helper.rb +9 -0
- data/{examples/example_suite.rb → spec/spec_suite.rb} +3 -3
- data/{examples/test_unit_example_suite.rb → spec/test_unit_spec_suite.rb} +0 -0
- metadata +93 -93
- data/examples/core_example_suite.rb +0 -31
- data/examples/example_helper.rb +0 -9
- data/examples/rr/double/double_bind_example.rb +0 -70
- data/examples/rr/double/double_dispatching_example.rb +0 -236
- data/examples/rr/double/double_example.rb +0 -66
- data/examples/rr/double/double_has_original_method_example.rb +0 -56
- data/examples/rr/double/double_register_scenario_example.rb +0 -24
- data/examples/rr/double/double_reset_example.rb +0 -89
- data/examples/rr/double/double_verify_example.rb +0 -23
- data/examples/rr/errors/rr_error_example.rb +0 -65
- data/examples/rr/expectations/any_argument_expectation_example.rb +0 -52
- data/examples/rr/expectations/anything_argument_equality_expectation_example.rb +0 -38
- data/examples/rr/expectations/argument_equality_expectation_example.rb +0 -62
- data/examples/rr/expectations/boolean_argument_equality_expectation_example.rb +0 -48
- data/examples/rr/expectations/duck_type_argument_equality_expectation_example.rb +0 -67
- data/examples/rr/expectations/is_a_argument_equality_expectation_example.rb +0 -50
- data/examples/rr/expectations/numeric_argument_equality_expectation_example.rb +0 -46
- data/examples/rr/expectations/range_argument_equality_expectation_example.rb +0 -59
- data/examples/rr/expectations/regexp_argument_equality_expectation_example.rb +0 -67
- data/examples/rr/expectations/times_called_expectation/times_called_expectation_any_times_example.rb +0 -50
- data/examples/rr/expectations/times_called_expectation/times_called_expectation_at_least_example.rb +0 -73
- data/examples/rr/expectations/times_called_expectation/times_called_expectation_at_most_example.rb +0 -77
- data/examples/rr/expectations/times_called_expectation/times_called_expectation_example.rb +0 -42
- data/examples/rr/expectations/times_called_expectation/times_called_expectation_helper.rb +0 -20
- data/examples/rr/expectations/times_called_expectation/times_called_expectation_integer_example.rb +0 -111
- data/examples/rr/expectations/times_called_expectation/times_called_expectation_proc_example.rb +0 -88
- data/examples/rr/expectations/times_called_expectation/times_called_expectation_range_example.rb +0 -90
- data/examples/rr/extensions/instance_methods_argument_matcher_example.rb +0 -65
- data/examples/rr/extensions/instance_methods_creator_example.rb +0 -363
- data/examples/rr/extensions/instance_methods_example_helper.rb +0 -11
- data/examples/rr/extensions/instance_methods_space_example.rb +0 -122
- data/examples/rr/rspec/rspec_adapter_example.rb +0 -63
- data/examples/rr/rspec/rspec_backtrace_tweaking_example.rb +0 -36
- data/examples/rr/rspec/rspec_usage_example.rb +0 -65
- data/examples/rr/scenario_creator_example.rb +0 -459
- data/examples/rr/scenario_example.rb +0 -701
- data/examples/rr/scenario_method_proxy_example.rb +0 -71
- data/examples/rr/space/hash_with_object_id_key_example.rb +0 -86
- data/examples/rr/space/space_create_example.rb +0 -278
- data/examples/rr/space/space_example.rb +0 -29
- data/examples/rr/space/space_helper.rb +0 -7
- data/examples/rr/space/space_register_example.rb +0 -32
- data/examples/rr/space/space_reset_example.rb +0 -120
- data/examples/rr/space/space_verify_example.rb +0 -169
- data/examples/rr/times_called_matchers/any_times_matcher_example.rb +0 -63
- data/examples/rr/times_called_matchers/at_least_matcher_example.rb +0 -70
- data/examples/rr/times_called_matchers/at_most_matcher_example.rb +0 -85
- data/examples/rr/times_called_matchers/integer_matcher_example.rb +0 -91
- data/examples/rr/times_called_matchers/proc_matcher_example.rb +0 -77
- data/examples/rr/times_called_matchers/range_matcher_example.rb +0 -97
- data/examples/rr/times_called_matchers/times_called_matcher_example.rb +0 -53
- data/examples/rspec_example_suite.rb +0 -25
- data/lib/rr/extensions/instance_methods.rb +0 -228
- data/lib/rr/scenario.rb +0 -337
data/lib/rr/adapters/rspec.rb
CHANGED
data/lib/rr/double.rb
CHANGED
@@ -1,132 +1,337 @@
|
|
1
1
|
module RR
|
2
|
-
# RR::Double is the
|
3
|
-
#
|
4
|
-
#
|
2
|
+
# RR::Double is the use case for a method call.
|
3
|
+
# It has the ArgumentEqualityExpectation, TimesCalledExpectation,
|
4
|
+
# and the implementation.
|
5
5
|
class Double
|
6
|
-
|
7
|
-
|
6
|
+
class << self
|
7
|
+
def formatted_name(method_name, args)
|
8
|
+
formatted_errors = args.collect {|arg| arg.inspect}.join(', ')
|
9
|
+
"#{method_name}(#{formatted_errors})"
|
10
|
+
end
|
8
11
|
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
if object_has_method?(method_name)
|
14
|
-
meta.send(:alias_method, original_method_name, method_name)
|
12
|
+
def list_message_part(scenarios)
|
13
|
+
scenarios.collect do |scenario|
|
14
|
+
"- #{formatted_name(scenario.method_name, scenario.expected_arguments)}"
|
15
|
+
end.join("\n")
|
15
16
|
end
|
16
|
-
@scenarios = []
|
17
17
|
end
|
18
18
|
|
19
|
-
|
20
|
-
|
21
|
-
def
|
22
|
-
@
|
19
|
+
attr_reader :times_called, :double_insertion, :definition
|
20
|
+
|
21
|
+
def initialize(space, double_insertion, definition)
|
22
|
+
@space = space
|
23
|
+
@double_insertion = double_insertion
|
24
|
+
@definition = definition
|
25
|
+
@times_called = 0
|
26
|
+
@times_called_expectation = Expectations::TimesCalledExpectation.new(self)
|
23
27
|
end
|
24
28
|
|
25
|
-
#
|
26
|
-
#
|
27
|
-
#
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
#{placeholder_name}(arguments)
|
34
|
-
end
|
35
|
-
METHOD
|
36
|
-
meta.class_eval(returns_method, __FILE__, __LINE__ - 5)
|
29
|
+
# Double#with sets the expectation that the Double will receive
|
30
|
+
# the passed in arguments.
|
31
|
+
#
|
32
|
+
# Passing in a block sets the return value.
|
33
|
+
#
|
34
|
+
# mock(subject).method_name.with(1, 2) {:return_value}
|
35
|
+
def with(*args, &returns)
|
36
|
+
definition.with(*args, &returns)
|
37
37
|
end
|
38
38
|
|
39
|
-
#
|
40
|
-
#
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
39
|
+
# Double#with_any_args sets the expectation that the Double can receive
|
40
|
+
# any arguments.
|
41
|
+
#
|
42
|
+
# Passing in a block sets the return value.
|
43
|
+
#
|
44
|
+
# mock(subject).method_name.with_any_args {:return_value}
|
45
|
+
def with_any_args(&returns)
|
46
|
+
definition.with_any_args(&returns)
|
45
47
|
end
|
46
48
|
|
47
|
-
#
|
48
|
-
#
|
49
|
-
#
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
else
|
56
|
-
meta.send(:remove_method, @method_name)
|
57
|
-
end
|
49
|
+
# Double#with_no_args sets the expectation that the Double will receive
|
50
|
+
# no arguments.
|
51
|
+
#
|
52
|
+
# Passing in a block sets the return value.
|
53
|
+
#
|
54
|
+
# mock(subject).method_name.with_no_args {:return_value}
|
55
|
+
def with_no_args(&returns)
|
56
|
+
definition.with_no_args(&returns)
|
58
57
|
end
|
59
58
|
|
60
|
-
|
61
|
-
|
59
|
+
# Double#never sets the expectation that the Double will never be
|
60
|
+
# called.
|
61
|
+
#
|
62
|
+
# This method does not accept a block because it will never be called.
|
63
|
+
#
|
64
|
+
# mock(subject).method_name.never
|
65
|
+
def never
|
66
|
+
definition.never
|
62
67
|
end
|
63
68
|
|
64
|
-
|
65
|
-
|
69
|
+
# Double#once sets the expectation that the Double will be called
|
70
|
+
# 1 time.
|
71
|
+
#
|
72
|
+
# Passing in a block sets the return value.
|
73
|
+
#
|
74
|
+
# mock(subject).method_name.once {:return_value}
|
75
|
+
def once(&returns)
|
76
|
+
definition.once(&returns)
|
66
77
|
end
|
67
78
|
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
79
|
+
# Double#twice sets the expectation that the Double will be called
|
80
|
+
# 2 times.
|
81
|
+
#
|
82
|
+
# Passing in a block sets the return value.
|
83
|
+
#
|
84
|
+
# mock(subject).method_name.twice {:return_value}
|
85
|
+
def twice(&returns)
|
86
|
+
definition.twice(&returns)
|
74
87
|
end
|
75
88
|
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
89
|
+
# Double#at_least sets the expectation that the Double
|
90
|
+
# will be called at least n times.
|
91
|
+
# It works by creating a TimesCalledExpectation.
|
92
|
+
#
|
93
|
+
# Passing in a block sets the return value.
|
94
|
+
#
|
95
|
+
# mock(subject).method_name.at_least(4) {:return_value}
|
96
|
+
def at_least(number, &returns)
|
97
|
+
definition.at_least(number, &returns)
|
81
98
|
end
|
82
99
|
|
83
|
-
|
84
|
-
|
100
|
+
# Double#at_most allows sets the expectation that the Double
|
101
|
+
# will be called at most n times.
|
102
|
+
# It works by creating a TimesCalledExpectation.
|
103
|
+
#
|
104
|
+
# Passing in a block sets the return value.
|
105
|
+
#
|
106
|
+
# mock(subject).method_name.at_most(4) {:return_value}
|
107
|
+
def at_most(number, &returns)
|
108
|
+
definition.at_most(number, &returns)
|
109
|
+
end
|
85
110
|
|
86
|
-
|
87
|
-
|
88
|
-
|
111
|
+
# Double#any_number_of_times sets an that the Double will be called
|
112
|
+
# any number of times. This effectively removes the times called expectation
|
113
|
+
# from the Doublen
|
114
|
+
#
|
115
|
+
# Passing in a block sets the return value.
|
116
|
+
#
|
117
|
+
# mock(subject).method_name.any_number_of_times
|
118
|
+
def any_number_of_times(&returns)
|
119
|
+
definition.any_number_of_times(&returns)
|
120
|
+
end
|
89
121
|
|
90
|
-
|
91
|
-
|
92
|
-
|
122
|
+
# Double#times creates an TimesCalledExpectation of the passed
|
123
|
+
# in number.
|
124
|
+
#
|
125
|
+
# Passing in a block sets the return value.
|
126
|
+
#
|
127
|
+
# mock(subject).method_name.times(4) {:return_value}
|
128
|
+
def times(number, &returns)
|
129
|
+
definition.times(number, &returns)
|
130
|
+
end
|
131
|
+
|
132
|
+
# Double#ordered sets the Double to have an ordered
|
133
|
+
# expectation.
|
134
|
+
#
|
135
|
+
# Passing in a block sets the return value.
|
136
|
+
#
|
137
|
+
# mock(subject).method_name.ordered {return_value}
|
138
|
+
def ordered(&returns)
|
139
|
+
definition.ordered(&returns)
|
140
|
+
end
|
93
141
|
|
94
|
-
|
95
|
-
|
142
|
+
# Double#ordered? returns true when the Double is ordered.
|
143
|
+
#
|
144
|
+
# mock(subject).method_name.ordered?
|
145
|
+
def ordered?
|
146
|
+
definition.ordered?
|
147
|
+
end
|
148
|
+
|
149
|
+
# Double#yields sets the Double to invoke a passed in block when
|
150
|
+
# the Double is called.
|
151
|
+
# An Expection will be raised if no block is passed in when the
|
152
|
+
# Double is called.
|
153
|
+
#
|
154
|
+
# Passing in a block sets the return value.
|
155
|
+
#
|
156
|
+
# mock(subject).method_name.yields(yield_arg1, yield_arg2) {return_value}
|
157
|
+
# subject.method_name {|yield_arg1, yield_arg2|}
|
158
|
+
def yields(*args, &returns)
|
159
|
+
definition.yields(*args, &returns)
|
160
|
+
end
|
161
|
+
|
162
|
+
# Double#after_call creates a callback that occurs after call
|
163
|
+
# is called. The passed in block receives the return value of
|
164
|
+
# the Double being called.
|
165
|
+
# An Expection will be raised if no block is passed in.
|
166
|
+
#
|
167
|
+
# mock(subject).method_name {return_value}.after_call {|return_value|}
|
168
|
+
# subject.method_name # return_value
|
169
|
+
#
|
170
|
+
# This feature is built into proxies.
|
171
|
+
# mock.proxy(User).find('1') {|user| mock(user).valid? {false}}
|
172
|
+
def after_call(&block)
|
173
|
+
definition.after_call &block
|
174
|
+
end
|
175
|
+
|
176
|
+
# Double#returns accepts an argument value or a block.
|
177
|
+
# It will raise an ArgumentError if both are passed in.
|
178
|
+
#
|
179
|
+
# Passing in a block causes Double to return the return value of
|
180
|
+
# the passed in block.
|
181
|
+
#
|
182
|
+
# Passing in an argument causes Double to return the argument.
|
183
|
+
def returns(value=nil, &implementation)
|
184
|
+
definition.returns(value, &implementation)
|
185
|
+
end
|
186
|
+
|
187
|
+
# Double#implemented_by sets the implementation of the Double.
|
188
|
+
# This method takes a Proc or a Method. Passing in a Method allows
|
189
|
+
# the Double to accept blocks.
|
190
|
+
#
|
191
|
+
# obj = Object.new
|
192
|
+
# def obj.foobar
|
193
|
+
# yield(1)
|
194
|
+
# end
|
195
|
+
# mock(obj).method_name.implemented_by(obj.method(:foobar))
|
196
|
+
def implemented_by(implementation)
|
197
|
+
definition.implemented_by implementation
|
198
|
+
end
|
199
|
+
|
200
|
+
# Double#implemented_by_original_method sets the implementation
|
201
|
+
# of the Double to be the original method.
|
202
|
+
# This is primarily used with proxy.
|
203
|
+
#
|
204
|
+
# obj = Object.new
|
205
|
+
# def obj.foobar
|
206
|
+
# yield(1)
|
207
|
+
# end
|
208
|
+
# mock(obj).method_name.implemented_by_original_method
|
209
|
+
# obj.foobar {|arg| puts arg} # puts 1
|
210
|
+
def implemented_by_original_method
|
211
|
+
definition.implemented_by_original_method
|
212
|
+
end
|
213
|
+
|
214
|
+
# Double#call calls the Double's implementation. The return
|
215
|
+
# value of the implementation is returned.
|
216
|
+
#
|
217
|
+
# A TimesCalledError is raised when the times called
|
218
|
+
# exceeds the expected TimesCalledExpectation.
|
219
|
+
def call(double_insertion, *args, &block)
|
220
|
+
self.times_called_expectation.attempt! if definition.times_matcher
|
221
|
+
@space.verify_ordered_scenario(self) if ordered?
|
222
|
+
yields!(block)
|
223
|
+
return_value = call_implementation(double_insertion, *args, &block)
|
224
|
+
return return_value unless definition.after_call_value
|
225
|
+
definition.after_call_value.call(return_value)
|
226
|
+
end
|
227
|
+
|
228
|
+
def yields!(block)
|
229
|
+
if definition.yields_value
|
230
|
+
unless block
|
231
|
+
raise ArgumentError, "A Block must be passed into the method call when using yields"
|
232
|
+
end
|
233
|
+
block.call(*definition.yields_value)
|
96
234
|
end
|
235
|
+
end
|
236
|
+
protected :yields!
|
97
237
|
|
98
|
-
|
99
|
-
|
238
|
+
def call_implementation(double_insertion, *args, &block)
|
239
|
+
return nil unless implementation
|
240
|
+
|
241
|
+
if implementation === DoubleDefinition::ORIGINAL_METHOD
|
242
|
+
if double_insertion.object_has_original_method?
|
243
|
+
return double_insertion.call_original_method(*args, &block)
|
244
|
+
else
|
245
|
+
return double_insertion.object.__send__(
|
246
|
+
:method_missing,
|
247
|
+
method_name,
|
248
|
+
*args,
|
249
|
+
&block
|
250
|
+
)
|
251
|
+
end
|
100
252
|
end
|
101
253
|
|
102
|
-
|
103
|
-
|
104
|
-
|
254
|
+
if implementation.is_a?(Method)
|
255
|
+
return implementation.call(*args, &block)
|
256
|
+
else
|
257
|
+
args << block if block
|
258
|
+
return implementation.call(*args)
|
105
259
|
end
|
260
|
+
end
|
261
|
+
protected :call_implementation
|
262
|
+
|
263
|
+
# Double#exact_match? returns true when the passed in arguments
|
264
|
+
# exactly match the ArgumentEqualityExpectation arguments.
|
265
|
+
def exact_match?(*arguments)
|
266
|
+
definition.exact_match?(*arguments)
|
267
|
+
end
|
106
268
|
|
107
|
-
|
269
|
+
# Double#wildcard_match? returns true when the passed in arguments
|
270
|
+
# wildcard match the ArgumentEqualityExpectation arguments.
|
271
|
+
def wildcard_match?(*arguments)
|
272
|
+
definition.wildcard_match?(*arguments)
|
108
273
|
end
|
109
274
|
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
275
|
+
# Double#attempt? returns true when the
|
276
|
+
# TimesCalledExpectation is satisfied.
|
277
|
+
def attempt?
|
278
|
+
return true unless definition.times_matcher
|
279
|
+
times_called_expectation.attempt?
|
114
280
|
end
|
115
281
|
|
116
|
-
|
117
|
-
|
282
|
+
# Double#verify verifies the the TimesCalledExpectation
|
283
|
+
# is satisfied for this scenario. A TimesCalledError
|
284
|
+
# is raised if the TimesCalledExpectation is not met.
|
285
|
+
def verify
|
286
|
+
return true unless definition.times_matcher
|
287
|
+
times_called_expectation.verify!
|
288
|
+
true
|
289
|
+
end
|
290
|
+
|
291
|
+
def terminal?
|
292
|
+
return false unless definition.times_matcher
|
293
|
+
times_called_expectation.terminal?
|
294
|
+
end
|
295
|
+
|
296
|
+
# The method name that this Double is attatched to
|
297
|
+
def method_name
|
298
|
+
double_insertion.method_name
|
299
|
+
end
|
300
|
+
|
301
|
+
# The Arguments that this Double expects
|
302
|
+
def expected_arguments
|
303
|
+
return [] unless argument_expectation
|
304
|
+
argument_expectation.expected_arguments
|
118
305
|
end
|
119
306
|
|
120
|
-
|
121
|
-
|
307
|
+
# The TimesCalledMatcher for the TimesCalledExpectation
|
308
|
+
def times_matcher
|
309
|
+
times_called_expectation.matcher
|
122
310
|
end
|
123
311
|
|
124
|
-
def
|
125
|
-
@
|
312
|
+
def times_called_expectation
|
313
|
+
@times_called_expectation.matcher = definition.times_matcher
|
314
|
+
@times_called_expectation
|
315
|
+
end
|
316
|
+
|
317
|
+
def implementation
|
318
|
+
definition.implementation
|
319
|
+
end
|
320
|
+
def implementation=(value)
|
321
|
+
definition.implementation = value
|
322
|
+
end
|
323
|
+
protected :implementation=
|
324
|
+
|
325
|
+
def argument_expectation
|
326
|
+
definition.argument_expectation
|
327
|
+
end
|
328
|
+
def argument_expectation=(value)
|
329
|
+
definition.argument_expectation = value
|
126
330
|
end
|
331
|
+
protected :argument_expectation=
|
127
332
|
|
128
|
-
def
|
129
|
-
(
|
333
|
+
def formatted_name
|
334
|
+
self.class.formatted_name(method_name, expected_arguments)
|
130
335
|
end
|
131
336
|
end
|
132
|
-
end
|
337
|
+
end
|
@@ -1,12 +1,11 @@
|
|
1
1
|
module RR
|
2
|
-
# RR::
|
2
|
+
# RR::DoubleCreator provides a strategies to create a Double.
|
3
3
|
# The strategies are:
|
4
4
|
# * mock
|
5
5
|
# * stub
|
6
|
-
# *
|
7
|
-
#
|
8
|
-
|
9
|
-
class ScenarioCreator
|
6
|
+
# * proxy
|
7
|
+
# * dont_allow
|
8
|
+
class DoubleCreator
|
10
9
|
NO_SUBJECT_ARG = Object.new
|
11
10
|
|
12
11
|
attr_reader :space
|
@@ -15,29 +14,29 @@ module RR
|
|
15
14
|
def initialize(space)
|
16
15
|
@space = space
|
17
16
|
@strategy = nil
|
18
|
-
@
|
17
|
+
@proxy = false
|
19
18
|
@instance_of = nil
|
20
19
|
@instance_of_method_name = nil
|
21
20
|
end
|
22
21
|
|
23
|
-
# This method sets the
|
24
|
-
# sets the default state of the
|
25
|
-
# with arguments exactly one time. The
|
22
|
+
# This method sets the Double to have a mock strategy. A mock strategy
|
23
|
+
# sets the default state of the Double to expect the method call
|
24
|
+
# with arguments exactly one time. The Double's expectations can be
|
26
25
|
# changed.
|
27
26
|
#
|
28
|
-
# This method can be chained with
|
29
|
-
# mock.
|
27
|
+
# This method can be chained with proxy.
|
28
|
+
# mock.proxy(subject).method_name_1
|
30
29
|
# or
|
31
|
-
#
|
30
|
+
# proxy.mock(subject).method_name_1
|
32
31
|
#
|
33
|
-
# When passed the subject, a
|
32
|
+
# When passed the subject, a DoubleMethodProxy is returned. Passing
|
34
33
|
# a method with arguments to the proxy will set up expectations that
|
35
34
|
# the a call to the subject's method with the arguments will happen.
|
36
35
|
# mock(subject).method_name_1 {return_value_1}
|
37
36
|
# mock(subject).method_name_2(arg1, arg2) {return_value_2}
|
38
37
|
#
|
39
38
|
# When passed the subject and the method_name, this method returns
|
40
|
-
# a mock
|
39
|
+
# a mock Double with the method already set.
|
41
40
|
#
|
42
41
|
# mock(subject, :method_name_1) {return_value_1}
|
43
42
|
# mock(subject, :method_name_2).with(arg1, arg2) {return_value_2}
|
@@ -54,17 +53,17 @@ module RR
|
|
54
53
|
RR::Space.scenario_method_proxy(self, subject, method_name, &definition)
|
55
54
|
end
|
56
55
|
|
57
|
-
# This method sets the
|
58
|
-
# sets the default state of the
|
59
|
-
# with any arguments any number of times. The
|
56
|
+
# This method sets the Double to have a stub strategy. A stub strategy
|
57
|
+
# sets the default state of the Double to expect the method call
|
58
|
+
# with any arguments any number of times. The Double's
|
60
59
|
# expectations can be changed.
|
61
60
|
#
|
62
|
-
# This method can be chained with
|
63
|
-
# stub.
|
61
|
+
# This method can be chained with proxy.
|
62
|
+
# stub.proxy(subject).method_name_1
|
64
63
|
# or
|
65
|
-
#
|
64
|
+
# proxy.stub(subject).method_name_1
|
66
65
|
#
|
67
|
-
# When passed the subject, a
|
66
|
+
# When passed the subject, a DoubleMethodProxy is returned. Passing
|
68
67
|
# a method with arguments to the proxy will set up expectations that
|
69
68
|
# the a call to the subject's method with the arguments will happen,
|
70
69
|
# and return the prescribed value.
|
@@ -72,7 +71,7 @@ module RR
|
|
72
71
|
# stub(subject).method_name_2(arg_1, arg_2) {return_value_2}
|
73
72
|
#
|
74
73
|
# When passed the subject and the method_name, this method returns
|
75
|
-
# a stub
|
74
|
+
# a stub Double with the method already set.
|
76
75
|
#
|
77
76
|
# mock(subject, :method_name_1) {return_value_1}
|
78
77
|
# mock(subject, :method_name_2).with(arg1, arg2) {return_value_2}
|
@@ -89,50 +88,50 @@ module RR
|
|
89
88
|
RR::Space.scenario_method_proxy(self, subject, method_name, &definition)
|
90
89
|
end
|
91
90
|
|
92
|
-
# This method sets the
|
93
|
-
# A
|
94
|
-
# to expect never to be called. The
|
91
|
+
# This method sets the Double to have a dont_allow strategy.
|
92
|
+
# A dont_allow strategy sets the default state of the Double
|
93
|
+
# to expect never to be called. The Double's expectations can be
|
95
94
|
# changed.
|
96
95
|
#
|
97
96
|
# The following example sets the expectation that subject.method_name
|
98
97
|
# will never be called with arg1 and arg2.
|
99
98
|
#
|
100
|
-
#
|
99
|
+
# dont_allow(subject).method_name(arg1, arg2)
|
101
100
|
#
|
102
|
-
#
|
103
|
-
#
|
101
|
+
# dont_allow also supports a block sytnax.
|
102
|
+
# dont_allow(subject) do |m|
|
104
103
|
# m.method1 # Do not allow method1 with any arguments
|
105
104
|
# m.method2(arg1, arg2) # Do not allow method2 with arguments arg1 and arg2
|
106
105
|
# m.method3.with_no_args # Do not allow method3 with no arguments
|
107
106
|
# end
|
108
|
-
def
|
107
|
+
def dont_allow(subject=NO_SUBJECT_ARG, method_name=nil, &definition)
|
109
108
|
strategy_error! if @strategy
|
110
|
-
|
111
|
-
@strategy = :
|
109
|
+
proxy_when_dont_allow_error! if @proxy
|
110
|
+
@strategy = :dont_allow
|
112
111
|
return self if subject.__id__ === NO_SUBJECT_ARG.__id__
|
113
112
|
RR::Space.scenario_method_proxy(self, subject, method_name, &definition)
|
114
113
|
end
|
115
|
-
alias_method :
|
116
|
-
alias_method :
|
117
|
-
alias_method :
|
114
|
+
alias_method :do_not_allow, :dont_allow
|
115
|
+
alias_method :dont_call, :dont_allow
|
116
|
+
alias_method :do_not_call, :dont_allow
|
118
117
|
|
119
|
-
# This method add
|
118
|
+
# This method add proxy capabilities to the Double. proxy can be called
|
120
119
|
# with mock or stub.
|
121
120
|
#
|
122
|
-
# mock.
|
121
|
+
# mock.proxy(controller.template).render(:partial => "my/socks")
|
123
122
|
#
|
124
|
-
# stub.
|
123
|
+
# stub.proxy(controller.template).render(:partial => "my/socks") do |html|
|
125
124
|
# html.should include("My socks are wet")
|
126
125
|
# html
|
127
126
|
# end
|
128
127
|
#
|
129
|
-
# mock.
|
128
|
+
# mock.proxy(controller.template).render(:partial => "my/socks") do |html|
|
130
129
|
# html.should include("My socks are wet")
|
131
130
|
# "My new return value"
|
132
131
|
# end
|
133
132
|
#
|
134
|
-
# mock.
|
135
|
-
# mock.
|
133
|
+
# mock.proxy also takes a block for definitions.
|
134
|
+
# mock.proxy(subject) do
|
136
135
|
# render(:partial => "my/socks")
|
137
136
|
#
|
138
137
|
# render(:partial => "my/socks") do |html|
|
@@ -151,31 +150,31 @@ module RR
|
|
151
150
|
# end
|
152
151
|
# end
|
153
152
|
#
|
154
|
-
# Passing a block to the
|
153
|
+
# Passing a block to the Double (after the method name and arguments)
|
155
154
|
# allows you to intercept the return value.
|
156
155
|
# The return value can be modified, validated, and/or overridden by
|
157
156
|
# passing in a block. The return value of the block will replace
|
158
157
|
# the actual return value.
|
159
158
|
#
|
160
|
-
# mock.
|
159
|
+
# mock.proxy(controller.template).render(:partial => "my/socks") do |html|
|
161
160
|
# html.should include("My socks are wet")
|
162
161
|
# "My new return value"
|
163
162
|
# end
|
164
|
-
def
|
165
|
-
|
166
|
-
@
|
163
|
+
def proxy(subject=NO_SUBJECT_ARG, method_name=nil, &definition)
|
164
|
+
proxy_when_dont_allow_error! if @strategy == :dont_allow
|
165
|
+
@proxy = true
|
167
166
|
return self if subject.__id__ === NO_SUBJECT_ARG.__id__
|
168
167
|
RR::Space.scenario_method_proxy(self, subject, method_name, &definition)
|
169
168
|
end
|
170
|
-
alias_method :
|
169
|
+
alias_method :probe, :proxy
|
171
170
|
|
172
171
|
# Calling instance_of will cause all instances of the passed in Class
|
173
|
-
# to have the
|
172
|
+
# to have the Double defined.
|
174
173
|
#
|
175
174
|
# The following example mocks all User's valid? method and return false.
|
176
175
|
# mock.instance_of(User).valid? {false}
|
177
176
|
#
|
178
|
-
# The following example mocks and
|
177
|
+
# The following example mocks and proxies User#projects and returns the
|
179
178
|
# first 3 projects.
|
180
179
|
# mock.instance_of(User).projects do |projects|
|
181
180
|
# projects[0..2]
|
@@ -201,45 +200,45 @@ module RR
|
|
201
200
|
|
202
201
|
protected
|
203
202
|
def setup_scenario(subject, method_name)
|
204
|
-
@
|
205
|
-
@scenario = @space.scenario(@
|
203
|
+
@double_insertion = @space.double_insertion(subject, method_name)
|
204
|
+
@scenario = @space.scenario(@double_insertion)
|
206
205
|
@definition = @scenario.definition
|
207
206
|
end
|
208
207
|
|
209
208
|
def setup_class_probing_instances(subject, method_name)
|
210
|
-
class_double = @space.
|
209
|
+
class_double = @space.double_insertion(subject, :new)
|
211
210
|
class_scenario = @space.scenario(class_double)
|
212
211
|
|
213
212
|
instance_method_name = method_name
|
214
213
|
|
215
214
|
@definition = @space.scenario_definition
|
216
215
|
class_handler = proc do |return_value|
|
217
|
-
|
218
|
-
@space.scenario(
|
216
|
+
double_insertion = @space.double_insertion(return_value, instance_method_name)
|
217
|
+
@space.scenario(double_insertion, @definition)
|
219
218
|
return_value
|
220
219
|
end
|
221
220
|
|
222
|
-
builder =
|
221
|
+
builder = DoubleDefinitionBuilder.new(
|
223
222
|
class_scenario.definition,
|
224
223
|
[],
|
225
224
|
class_handler
|
226
225
|
)
|
227
226
|
builder.stub!
|
228
|
-
builder.
|
227
|
+
builder.proxy!
|
229
228
|
end
|
230
229
|
|
231
230
|
def transform!
|
232
|
-
builder =
|
231
|
+
builder = DoubleDefinitionBuilder.new(@definition, @args, @handler)
|
233
232
|
|
234
233
|
case @strategy
|
235
234
|
when :mock; builder.mock!
|
236
235
|
when :stub; builder.stub!
|
237
|
-
when :
|
236
|
+
when :dont_allow; builder.dont_allow!
|
238
237
|
else no_strategy_error!
|
239
238
|
end
|
240
239
|
|
241
|
-
if @
|
242
|
-
builder.
|
240
|
+
if @proxy
|
241
|
+
builder.proxy!
|
243
242
|
else
|
244
243
|
builder.reimplementation!
|
245
244
|
end
|
@@ -247,22 +246,22 @@ module RR
|
|
247
246
|
|
248
247
|
def strategy_error!
|
249
248
|
raise(
|
250
|
-
|
251
|
-
"This
|
249
|
+
DoubleDefinitionError,
|
250
|
+
"This Double already has a #{@strategy} strategy"
|
252
251
|
)
|
253
252
|
end
|
254
253
|
|
255
254
|
def no_strategy_error!
|
256
255
|
raise(
|
257
|
-
|
258
|
-
"This
|
256
|
+
DoubleDefinitionError,
|
257
|
+
"This Double has no strategy"
|
259
258
|
)
|
260
259
|
end
|
261
260
|
|
262
|
-
def
|
261
|
+
def proxy_when_dont_allow_error!
|
263
262
|
raise(
|
264
|
-
|
265
|
-
"
|
263
|
+
DoubleDefinitionError,
|
264
|
+
"Doubles cannot be proxied when using dont_allow strategy"
|
266
265
|
)
|
267
266
|
end
|
268
267
|
end
|