redinger-rr 0.10.3
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 +221 -0
- data/README.rdoc +343 -0
- data/Rakefile +88 -0
- data/VERSION.yml +4 -0
- data/lib/rr.rb +88 -0
- data/lib/rr/adapters/rr_methods.rb +122 -0
- data/lib/rr/adapters/rspec.rb +59 -0
- data/lib/rr/adapters/test_unit.rb +29 -0
- data/lib/rr/double.rb +152 -0
- data/lib/rr/double_definitions/child_double_definition_creator.rb +27 -0
- data/lib/rr/double_definitions/double_definition.rb +348 -0
- data/lib/rr/double_definitions/double_definition_creator.rb +167 -0
- data/lib/rr/double_definitions/double_definition_creator_proxy.rb +37 -0
- data/lib/rr/double_definitions/strategies/implementation/implementation_strategy.rb +15 -0
- data/lib/rr/double_definitions/strategies/implementation/proxy.rb +62 -0
- data/lib/rr/double_definitions/strategies/implementation/reimplementation.rb +14 -0
- data/lib/rr/double_definitions/strategies/implementation/strongly_typed_reimplementation.rb +17 -0
- data/lib/rr/double_definitions/strategies/scope/instance.rb +15 -0
- data/lib/rr/double_definitions/strategies/scope/instance_of_class.rb +50 -0
- data/lib/rr/double_definitions/strategies/scope/scope_strategy.rb +15 -0
- data/lib/rr/double_definitions/strategies/strategy.rb +70 -0
- data/lib/rr/double_definitions/strategies/verification/dont_allow.rb +34 -0
- data/lib/rr/double_definitions/strategies/verification/mock.rb +44 -0
- data/lib/rr/double_definitions/strategies/verification/stub.rb +45 -0
- data/lib/rr/double_definitions/strategies/verification/verification_strategy.rb +15 -0
- data/lib/rr/double_injection.rb +180 -0
- data/lib/rr/double_matches.rb +51 -0
- data/lib/rr/errors/argument_equality_error.rb +6 -0
- data/lib/rr/errors/double_definition_error.rb +6 -0
- data/lib/rr/errors/double_not_found_error.rb +6 -0
- data/lib/rr/errors/double_order_error.rb +6 -0
- data/lib/rr/errors/rr_error.rb +20 -0
- 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/errors/times_called_error.rb +6 -0
- data/lib/rr/expectations/any_argument_expectation.rb +21 -0
- data/lib/rr/expectations/argument_equality_expectation.rb +41 -0
- data/lib/rr/expectations/times_called_expectation.rb +57 -0
- data/lib/rr/hash_with_object_id_key.rb +44 -0
- data/lib/rr/method_dispatches/base_method_dispatch.rb +108 -0
- data/lib/rr/method_dispatches/method_dispatch.rb +61 -0
- data/lib/rr/method_dispatches/method_missing_dispatch.rb +49 -0
- data/lib/rr/proc_from_block.rb +7 -0
- data/lib/rr/recorded_calls.rb +103 -0
- data/lib/rr/space.rb +123 -0
- 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 +18 -0
- data/lib/rr/times_called_matchers/at_least_matcher.rb +15 -0
- data/lib/rr/times_called_matchers/at_most_matcher.rb +23 -0
- data/lib/rr/times_called_matchers/integer_matcher.rb +19 -0
- data/lib/rr/times_called_matchers/non_terminal.rb +27 -0
- data/lib/rr/times_called_matchers/proc_matcher.rb +11 -0
- data/lib/rr/times_called_matchers/range_matcher.rb +21 -0
- data/lib/rr/times_called_matchers/terminal.rb +20 -0
- data/lib/rr/times_called_matchers/times_called_matcher.rb +44 -0
- data/lib/rr/wildcard_matchers.rb +158 -0
- data/lib/rr/wildcard_matchers/anything.rb +18 -0
- data/lib/rr/wildcard_matchers/boolean.rb +23 -0
- data/lib/rr/wildcard_matchers/duck_type.rb +32 -0
- data/lib/rr/wildcard_matchers/hash_including.rb +29 -0
- data/lib/rr/wildcard_matchers/is_a.rb +25 -0
- data/lib/rr/wildcard_matchers/numeric.rb +13 -0
- data/lib/rr/wildcard_matchers/range.rb +7 -0
- data/lib/rr/wildcard_matchers/regexp.rb +7 -0
- data/lib/rr/wildcard_matchers/satisfy.rb +26 -0
- data/spec/core_spec_suite.rb +19 -0
- data/spec/environment_fixture_setup.rb +7 -0
- data/spec/high_level_spec.rb +398 -0
- data/spec/proc_from_block_spec.rb +14 -0
- data/spec/rr/adapters/rr_methods_argument_matcher_spec.rb +67 -0
- data/spec/rr/adapters/rr_methods_creator_spec.rb +149 -0
- data/spec/rr/adapters/rr_methods_space_spec.rb +115 -0
- data/spec/rr/adapters/rr_methods_spec_helper.rb +11 -0
- data/spec/rr/adapters/rr_methods_times_matcher_spec.rb +17 -0
- data/spec/rr/double_definitions/child_double_definition_creator_spec.rb +112 -0
- data/spec/rr/double_definitions/double_definition_creator_proxy_spec.rb +155 -0
- data/spec/rr/double_definitions/double_definition_creator_spec.rb +502 -0
- data/spec/rr/double_definitions/double_definition_spec.rb +1165 -0
- data/spec/rr/double_injection/double_injection_spec.rb +339 -0
- data/spec/rr/double_injection/double_injection_verify_spec.rb +29 -0
- data/spec/rr/double_spec.rb +352 -0
- data/spec/rr/errors/rr_error_spec.rb +67 -0
- data/spec/rr/expectations/any_argument_expectation_spec.rb +47 -0
- data/spec/rr/expectations/anything_argument_equality_expectation_spec.rb +14 -0
- data/spec/rr/expectations/argument_equality_expectation_spec.rb +135 -0
- data/spec/rr/expectations/boolean_argument_equality_expectation_spec.rb +34 -0
- data/spec/rr/expectations/hash_including_argument_equality_expectation_spec.rb +82 -0
- data/spec/rr/expectations/hash_including_spec.rb +17 -0
- data/spec/rr/expectations/satisfy_argument_equality_expectation_spec.rb +59 -0
- data/spec/rr/expectations/satisfy_spec.rb +14 -0
- data/spec/rr/expectations/times_called_expectation/times_called_expectation_any_times_spec.rb +46 -0
- data/spec/rr/expectations/times_called_expectation/times_called_expectation_at_least_spec.rb +69 -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 +23 -0
- data/spec/rr/expectations/times_called_expectation/times_called_expectation_integer_spec.rb +104 -0
- data/spec/rr/expectations/times_called_expectation/times_called_expectation_proc_spec.rb +81 -0
- data/spec/rr/expectations/times_called_expectation/times_called_expectation_range_spec.rb +83 -0
- data/spec/rr/expectations/times_called_expectation/times_called_expectation_spec.rb +38 -0
- data/spec/rr/rspec/invocation_matcher_spec.rb +279 -0
- data/spec/rr/rspec/rspec_adapter_spec.rb +66 -0
- data/spec/rr/rspec/rspec_backtrace_tweaking_spec.rb +31 -0
- data/spec/rr/rspec/rspec_backtrace_tweaking_spec_fixture.rb +11 -0
- data/spec/rr/rspec/rspec_usage_spec.rb +86 -0
- data/spec/rr/space/hash_with_object_id_key_spec.rb +88 -0
- data/spec/rr/space/space_spec.rb +550 -0
- data/spec/rr/test_unit/test_helper.rb +7 -0
- data/spec/rr/test_unit/test_unit_backtrace_test.rb +36 -0
- data/spec/rr/test_unit/test_unit_integration_test.rb +57 -0
- 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/rr/wildcard_matchers/anything_spec.rb +24 -0
- data/spec/rr/wildcard_matchers/boolean_spec.rb +36 -0
- data/spec/rr/wildcard_matchers/duck_type_spec.rb +52 -0
- data/spec/rr/wildcard_matchers/is_a_spec.rb +32 -0
- data/spec/rr/wildcard_matchers/numeric_spec.rb +32 -0
- data/spec/rr/wildcard_matchers/range_spec.rb +35 -0
- data/spec/rr/wildcard_matchers/regexp_spec.rb +43 -0
- data/spec/rr_spec.rb +28 -0
- data/spec/rspec_spec_suite.rb +17 -0
- data/spec/spec_helper.rb +109 -0
- data/spec/spec_suite.rb +31 -0
- data/spec/spy_verification_spec.rb +129 -0
- data/spec/test_unit_spec_suite.rb +21 -0
- metadata +193 -0
@@ -0,0 +1,27 @@
|
|
1
|
+
module RR
|
2
|
+
module DoubleDefinitions
|
3
|
+
class ChildDoubleDefinitionCreator < DoubleDefinitionCreator # :nodoc
|
4
|
+
attr_reader :parent_double_definition
|
5
|
+
def initialize(parent_double_definition)
|
6
|
+
@parent_double_definition = parent_double_definition
|
7
|
+
super()
|
8
|
+
end
|
9
|
+
|
10
|
+
def root_subject
|
11
|
+
parent_double_definition.root_subject
|
12
|
+
end
|
13
|
+
|
14
|
+
def instance_of(*args)
|
15
|
+
raise NoMethodError
|
16
|
+
end
|
17
|
+
|
18
|
+
protected
|
19
|
+
def add_strategy(subject, method_name, definition_eval_block, &block)
|
20
|
+
super do
|
21
|
+
block.call
|
22
|
+
parent_double_definition.implemented_by(lambda {subject})
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,348 @@
|
|
1
|
+
module RR
|
2
|
+
module DoubleDefinitions
|
3
|
+
class DoubleDefinition #:nodoc:
|
4
|
+
class << self
|
5
|
+
def register_strategy_class(strategy_class, method_name)
|
6
|
+
class_eval((<<-CLASS), __FILE__, __LINE__ + 1)
|
7
|
+
def #{method_name}(subject=DoubleDefinitionCreator::NO_SUBJECT, method_name=nil, &definition_eval_block)
|
8
|
+
ChildDoubleDefinitionCreator.new(self).#{method_name}(subject, method_name, &definition_eval_block)
|
9
|
+
end
|
10
|
+
CLASS
|
11
|
+
|
12
|
+
class_eval((<<-CLASS), __FILE__, __LINE__ + 1)
|
13
|
+
def #{method_name}!(method_name=nil, &definition_eval_block)
|
14
|
+
ChildDoubleDefinitionCreator.new(self).#{method_name}!(method_name, &definition_eval_block)
|
15
|
+
end
|
16
|
+
CLASS
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
ORIGINAL_METHOD = Object.new
|
21
|
+
attr_accessor(
|
22
|
+
:argument_expectation,
|
23
|
+
:times_matcher,
|
24
|
+
:implementation,
|
25
|
+
:after_call_proc,
|
26
|
+
:yields_value,
|
27
|
+
:double,
|
28
|
+
:double_definition_creator,
|
29
|
+
:subject
|
30
|
+
)
|
31
|
+
|
32
|
+
include Space::Reader
|
33
|
+
|
34
|
+
def initialize(double_definition_creator, subject)
|
35
|
+
@implementation = nil
|
36
|
+
@argument_expectation = nil
|
37
|
+
@times_matcher = nil
|
38
|
+
@after_call_proc = nil
|
39
|
+
@yields_value = nil
|
40
|
+
@double_definition_creator = double_definition_creator
|
41
|
+
@subject = subject
|
42
|
+
end
|
43
|
+
|
44
|
+
attr_reader :argument_expectation
|
45
|
+
|
46
|
+
def root_subject
|
47
|
+
double_definition_creator.root_subject
|
48
|
+
end
|
49
|
+
|
50
|
+
module ArgumentDefinitionConstructionMethods
|
51
|
+
# Double#with sets the expectation that the Double will receive
|
52
|
+
# the passed in arguments.
|
53
|
+
#
|
54
|
+
# Passing in a block sets the return value.
|
55
|
+
#
|
56
|
+
# mock(subject).method_name.with(1, 2) {:return_value}
|
57
|
+
def with(*args, &return_value_block)
|
58
|
+
@argument_expectation = Expectations::ArgumentEqualityExpectation.new(*args)
|
59
|
+
install_method_callback return_value_block
|
60
|
+
self
|
61
|
+
end
|
62
|
+
|
63
|
+
# Double#with_any_args sets the expectation that the Double can receive
|
64
|
+
# any arguments.
|
65
|
+
#
|
66
|
+
# Passing in a block sets the return value.
|
67
|
+
#
|
68
|
+
# mock(subject).method_name.with_any_args {:return_value}
|
69
|
+
def with_any_args(&return_value_block)
|
70
|
+
@argument_expectation = Expectations::AnyArgumentExpectation.new
|
71
|
+
install_method_callback return_value_block
|
72
|
+
self
|
73
|
+
end
|
74
|
+
|
75
|
+
# Double#with_no_args sets the expectation that the Double will receive
|
76
|
+
# no arguments.
|
77
|
+
#
|
78
|
+
# Passing in a block sets the return value.
|
79
|
+
#
|
80
|
+
# mock(subject).method_name.with_no_args {:return_value}
|
81
|
+
def with_no_args(&return_value_block)
|
82
|
+
@argument_expectation = Expectations::ArgumentEqualityExpectation.new()
|
83
|
+
install_method_callback return_value_block
|
84
|
+
self
|
85
|
+
end
|
86
|
+
end
|
87
|
+
include ArgumentDefinitionConstructionMethods
|
88
|
+
|
89
|
+
module TimesDefinitionConstructionMethods
|
90
|
+
# Double#never sets the expectation that the Double will never be
|
91
|
+
# called.
|
92
|
+
#
|
93
|
+
# This method does not accept a block because it will never be called.
|
94
|
+
#
|
95
|
+
# mock(subject).method_name.never
|
96
|
+
def never
|
97
|
+
@times_matcher = TimesCalledMatchers::IntegerMatcher.new(0)
|
98
|
+
self
|
99
|
+
end
|
100
|
+
|
101
|
+
# Double#once sets the expectation that the Double will be called
|
102
|
+
# 1 time.
|
103
|
+
#
|
104
|
+
# Passing in a block sets the return value.
|
105
|
+
#
|
106
|
+
# mock(subject).method_name.once {:return_value}
|
107
|
+
def once(&return_value_block)
|
108
|
+
@times_matcher = TimesCalledMatchers::IntegerMatcher.new(1)
|
109
|
+
install_method_callback return_value_block
|
110
|
+
self
|
111
|
+
end
|
112
|
+
|
113
|
+
# Double#twice sets the expectation that the Double will be called
|
114
|
+
# 2 times.
|
115
|
+
#
|
116
|
+
# Passing in a block sets the return value.
|
117
|
+
#
|
118
|
+
# mock(subject).method_name.twice {:return_value}
|
119
|
+
def twice(&return_value_block)
|
120
|
+
@times_matcher = TimesCalledMatchers::IntegerMatcher.new(2)
|
121
|
+
install_method_callback return_value_block
|
122
|
+
self
|
123
|
+
end
|
124
|
+
|
125
|
+
# Double#at_least sets the expectation that the Double
|
126
|
+
# will be called at least n times.
|
127
|
+
# It works by creating a TimesCalledExpectation.
|
128
|
+
#
|
129
|
+
# Passing in a block sets the return value.
|
130
|
+
#
|
131
|
+
# mock(subject).method_name.at_least(4) {:return_value}
|
132
|
+
def at_least(number, &return_value_block)
|
133
|
+
@times_matcher = TimesCalledMatchers::AtLeastMatcher.new(number)
|
134
|
+
install_method_callback return_value_block
|
135
|
+
self
|
136
|
+
end
|
137
|
+
|
138
|
+
# Double#at_most allows sets the expectation that the Double
|
139
|
+
# will be called at most n times.
|
140
|
+
# It works by creating a TimesCalledExpectation.
|
141
|
+
#
|
142
|
+
# Passing in a block sets the return value.
|
143
|
+
#
|
144
|
+
# mock(subject).method_name.at_most(4) {:return_value}
|
145
|
+
def at_most(number, &return_value_block)
|
146
|
+
@times_matcher = TimesCalledMatchers::AtMostMatcher.new(number)
|
147
|
+
install_method_callback return_value_block
|
148
|
+
self
|
149
|
+
end
|
150
|
+
|
151
|
+
# Double#any_number_of_times sets an that the Double will be called
|
152
|
+
# any number of times. This effectively removes the times called expectation
|
153
|
+
# from the Doublen
|
154
|
+
#
|
155
|
+
# Passing in a block sets the return value.
|
156
|
+
#
|
157
|
+
# mock(subject).method_name.any_number_of_times
|
158
|
+
def any_number_of_times(&return_value_block)
|
159
|
+
@times_matcher = TimesCalledMatchers::AnyTimesMatcher.new
|
160
|
+
install_method_callback return_value_block
|
161
|
+
self
|
162
|
+
end
|
163
|
+
alias_method :any_times, :any_number_of_times
|
164
|
+
|
165
|
+
# Double#times creates an TimesCalledExpectation of the passed
|
166
|
+
# in number.
|
167
|
+
#
|
168
|
+
# Passing in a block sets the return value.
|
169
|
+
#
|
170
|
+
# mock(subject).method_name.times(4) {:return_value}
|
171
|
+
def times(matcher_value, &return_value_block)
|
172
|
+
@times_matcher = TimesCalledMatchers::TimesCalledMatcher.create(matcher_value)
|
173
|
+
install_method_callback return_value_block
|
174
|
+
self
|
175
|
+
end
|
176
|
+
end
|
177
|
+
include TimesDefinitionConstructionMethods
|
178
|
+
|
179
|
+
module DefinitionConstructionMethods
|
180
|
+
# Double#ordered sets the Double to have an ordered
|
181
|
+
# expectation.
|
182
|
+
#
|
183
|
+
# Passing in a block sets the return value.
|
184
|
+
#
|
185
|
+
# mock(subject).method_name.ordered {return_value}
|
186
|
+
def ordered(&return_value_block)
|
187
|
+
raise(
|
188
|
+
Errors::DoubleDefinitionError,
|
189
|
+
"Double Definitions must have a dedicated Double to be ordered. " <<
|
190
|
+
"For example, using instance_of does not allow ordered to be used. " <<
|
191
|
+
"proxy the class's #new method instead."
|
192
|
+
) unless @double
|
193
|
+
@ordered = true
|
194
|
+
space.register_ordered_double(@double)
|
195
|
+
install_method_callback return_value_block
|
196
|
+
DoubleDefinitionCreatorProxy.new(double_definition_creator)
|
197
|
+
end
|
198
|
+
alias_method :then, :ordered
|
199
|
+
|
200
|
+
# Double#yields sets the Double to invoke a passed in block when
|
201
|
+
# the Double is called.
|
202
|
+
# An Expection will be raised if no block is passed in when the
|
203
|
+
# Double is called.
|
204
|
+
#
|
205
|
+
# Passing in a block sets the return value.
|
206
|
+
#
|
207
|
+
# mock(subject).method_name.yields(yield_arg1, yield_arg2) {return_value}
|
208
|
+
# subject.method_name {|yield_arg1, yield_arg2|}
|
209
|
+
def yields(*args, &return_value_block)
|
210
|
+
@yields_value = args
|
211
|
+
install_method_callback return_value_block
|
212
|
+
self
|
213
|
+
end
|
214
|
+
|
215
|
+
# Double#after_call creates a callback that occurs after call
|
216
|
+
# is called. The passed in block receives the return value of
|
217
|
+
# the Double being called.
|
218
|
+
# An Expection will be raised if no block is passed in.
|
219
|
+
#
|
220
|
+
# mock(subject).method_name {return_value}.after_call {|return_value|}
|
221
|
+
# subject.method_name # return_value
|
222
|
+
#
|
223
|
+
# This feature is built into proxies.
|
224
|
+
# mock.proxy(User).find('1') {|user| mock(user).valid? {false}}
|
225
|
+
def after_call(&after_call_proc)
|
226
|
+
raise ArgumentError, "after_call expects a block" unless after_call_proc
|
227
|
+
@after_call_proc = after_call_proc
|
228
|
+
self
|
229
|
+
end
|
230
|
+
|
231
|
+
# Double#verbose sets the Double to print out each method call it receives.
|
232
|
+
#
|
233
|
+
# Passing in a block sets the return value
|
234
|
+
def verbose(&after_call_proc)
|
235
|
+
@verbose = true
|
236
|
+
@after_call_proc = after_call_proc
|
237
|
+
self
|
238
|
+
end
|
239
|
+
|
240
|
+
# Double#returns accepts an argument value or a block.
|
241
|
+
# It will raise an ArgumentError if both are passed in.
|
242
|
+
#
|
243
|
+
# Passing in a block causes Double to return the return value of
|
244
|
+
# the passed in block.
|
245
|
+
#
|
246
|
+
# Passing in an argument causes Double to return the argument.
|
247
|
+
def returns(*args, &implementation)
|
248
|
+
if !args.empty? && implementation
|
249
|
+
raise ArgumentError, "returns cannot accept both an argument and a block"
|
250
|
+
end
|
251
|
+
if implementation
|
252
|
+
install_method_callback implementation
|
253
|
+
else
|
254
|
+
install_method_callback(lambda do
|
255
|
+
return *args
|
256
|
+
end)
|
257
|
+
end
|
258
|
+
self
|
259
|
+
end
|
260
|
+
|
261
|
+
def implemented_by_original_method
|
262
|
+
implemented_by ORIGINAL_METHOD
|
263
|
+
self
|
264
|
+
end
|
265
|
+
|
266
|
+
# Double#implemented_by sets the implementation of the Double.
|
267
|
+
# This method takes a Proc or a Method. Passing in a Method allows
|
268
|
+
# the Double to accept blocks.
|
269
|
+
#
|
270
|
+
# obj = Object.new
|
271
|
+
# def obj.foobar
|
272
|
+
# yield(1)
|
273
|
+
# end
|
274
|
+
# mock(obj).method_name.implemented_by(obj.method(:foobar))
|
275
|
+
def implemented_by(implementation)
|
276
|
+
@implementation = implementation
|
277
|
+
self
|
278
|
+
end
|
279
|
+
|
280
|
+
def verify_method_signature
|
281
|
+
@verify_method_signature = true
|
282
|
+
self
|
283
|
+
end
|
284
|
+
alias_method :strong, :verify_method_signature
|
285
|
+
|
286
|
+
protected
|
287
|
+
def install_method_callback(block)
|
288
|
+
return unless block
|
289
|
+
if implementation_is_original_method?
|
290
|
+
after_call(&block)
|
291
|
+
else
|
292
|
+
implemented_by block
|
293
|
+
end
|
294
|
+
end
|
295
|
+
end
|
296
|
+
include DefinitionConstructionMethods
|
297
|
+
|
298
|
+
module StateQueryMethods
|
299
|
+
# Double#ordered? returns true when the Double is ordered.
|
300
|
+
#
|
301
|
+
# mock(subject).method_name.ordered?
|
302
|
+
def ordered?
|
303
|
+
@ordered
|
304
|
+
end
|
305
|
+
|
306
|
+
# Double#verbose? returns true when verbose has been called on it. It returns
|
307
|
+
# true when the double is set to print each method call it receives.
|
308
|
+
def verbose?
|
309
|
+
@verbose ? true : false
|
310
|
+
end
|
311
|
+
|
312
|
+
def exact_match?(*arguments)
|
313
|
+
raise(Errors::DoubleDefinitionError, "#argument_expectation must be defined on #{inspect}") unless @argument_expectation
|
314
|
+
@argument_expectation.exact_match?(*arguments)
|
315
|
+
end
|
316
|
+
|
317
|
+
def wildcard_match?(*arguments)
|
318
|
+
raise(Errors::DoubleDefinitionError, "#argument_expectation must be defined on #{inspect}") unless @argument_expectation
|
319
|
+
@argument_expectation.wildcard_match?(*arguments)
|
320
|
+
end
|
321
|
+
|
322
|
+
def terminal?
|
323
|
+
raise(Errors::DoubleDefinitionError, "#argument_expectation must be defined on #{inspect}") unless @times_matcher
|
324
|
+
@times_matcher.terminal?
|
325
|
+
end
|
326
|
+
|
327
|
+
def expected_arguments
|
328
|
+
argument_expectation ? argument_expectation.expected_arguments : []
|
329
|
+
end
|
330
|
+
|
331
|
+
def implementation_is_original_method?
|
332
|
+
implementation_strategy.is_a?(Strategies::Implementation::Proxy)
|
333
|
+
end
|
334
|
+
|
335
|
+
def verify_method_signature?
|
336
|
+
!!@verify_method_signature
|
337
|
+
end
|
338
|
+
alias_method :strong?, :verify_method_signature?
|
339
|
+
|
340
|
+
protected
|
341
|
+
def implementation_strategy
|
342
|
+
double_definition_creator.implementation_strategy
|
343
|
+
end
|
344
|
+
end
|
345
|
+
include StateQueryMethods
|
346
|
+
end
|
347
|
+
end
|
348
|
+
end
|
@@ -0,0 +1,167 @@
|
|
1
|
+
module RR
|
2
|
+
module DoubleDefinitions
|
3
|
+
class DoubleDefinitionCreator # :nodoc
|
4
|
+
class << self
|
5
|
+
def register_verification_strategy_class(strategy_class, method_name)
|
6
|
+
class_eval((<<-CLASS), __FILE__, __LINE__ + 1)
|
7
|
+
def #{method_name}(subject=NO_SUBJECT, method_name=nil, &definition_eval_block)
|
8
|
+
add_strategy(subject, method_name, definition_eval_block) do
|
9
|
+
self.verification_strategy = #{strategy_class.name}.new(self)
|
10
|
+
end
|
11
|
+
end
|
12
|
+
CLASS
|
13
|
+
|
14
|
+
class_eval((<<-CLASS), __FILE__, __LINE__ + 1)
|
15
|
+
def #{method_name}!(method_name=nil, &definition_eval_block)
|
16
|
+
#{method_name}(Object.new, method_name, &definition_eval_block)
|
17
|
+
end
|
18
|
+
CLASS
|
19
|
+
end
|
20
|
+
|
21
|
+
def register_implementation_strategy_class(strategy_class, method_name)
|
22
|
+
class_eval((<<-CLASS), __FILE__, __LINE__ + 1)
|
23
|
+
def #{method_name}(subject=NO_SUBJECT, method_name=nil, &definition_eval_block)
|
24
|
+
add_strategy(subject, method_name, definition_eval_block) do
|
25
|
+
self.implementation_strategy = #{strategy_class.name}.new(self)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
CLASS
|
29
|
+
|
30
|
+
class_eval((<<-CLASS), __FILE__, __LINE__ + 1)
|
31
|
+
def #{method_name}!(method_name=nil, &definition_eval_block)
|
32
|
+
#{method_name}(Object.new, method_name, &definition_eval_block)
|
33
|
+
end
|
34
|
+
CLASS
|
35
|
+
end
|
36
|
+
|
37
|
+
def register_scope_strategy_class(strategy_class, method_name)
|
38
|
+
class_eval((<<-CLASS), __FILE__, __LINE__ + 1)
|
39
|
+
def #{method_name}(subject=NO_SUBJECT, method_name=nil, &definition_eval_block)
|
40
|
+
add_strategy(subject, method_name, definition_eval_block) do
|
41
|
+
self.scope_strategy = #{strategy_class.name}.new(self)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
CLASS
|
45
|
+
|
46
|
+
class_eval((<<-CLASS), __FILE__, __LINE__ + 1)
|
47
|
+
def #{method_name}!(method_name=nil, &definition_eval_block)
|
48
|
+
#{method_name}(Object.new, method_name, &definition_eval_block)
|
49
|
+
end
|
50
|
+
CLASS
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
attr_reader :subject,
|
55
|
+
:method_name,
|
56
|
+
:args, :handler,
|
57
|
+
:definition,
|
58
|
+
:verification_strategy,
|
59
|
+
:implementation_strategy,
|
60
|
+
:scope_strategy
|
61
|
+
NO_SUBJECT = Object.new
|
62
|
+
|
63
|
+
include Space::Reader
|
64
|
+
|
65
|
+
def initialize
|
66
|
+
@verification_strategy = nil
|
67
|
+
@implementation_strategy = Strategies::Implementation::Reimplementation.new(self)
|
68
|
+
@scope_strategy = Strategies::Scope::Instance.new(self)
|
69
|
+
end
|
70
|
+
|
71
|
+
def root_subject
|
72
|
+
subject
|
73
|
+
end
|
74
|
+
|
75
|
+
def method_name
|
76
|
+
@verification_strategy.method_name
|
77
|
+
end
|
78
|
+
|
79
|
+
module StrategySetupMethods
|
80
|
+
def no_subject?
|
81
|
+
subject.__id__ === NO_SUBJECT.__id__
|
82
|
+
end
|
83
|
+
|
84
|
+
protected
|
85
|
+
def add_strategy(subject, method_name, definition_eval_block)
|
86
|
+
if method_name && definition_eval_block
|
87
|
+
raise ArgumentError, "Cannot pass in a method name and a block"
|
88
|
+
end
|
89
|
+
@subject = subject
|
90
|
+
yield
|
91
|
+
if no_subject?
|
92
|
+
self
|
93
|
+
elsif method_name
|
94
|
+
create(method_name)
|
95
|
+
else
|
96
|
+
DoubleDefinitionCreatorProxy.new(self, &definition_eval_block)
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
def verification_strategy=(verification_strategy)
|
101
|
+
verify_no_verification_strategy
|
102
|
+
verify_not_proxy_and_dont_allow(verification_strategy, implementation_strategy)
|
103
|
+
@verification_strategy = verification_strategy
|
104
|
+
verification_strategy
|
105
|
+
end
|
106
|
+
|
107
|
+
def implementation_strategy=(implementation_strategy)
|
108
|
+
verify_not_proxy_and_dont_allow(verification_strategy, implementation_strategy)
|
109
|
+
@implementation_strategy = implementation_strategy
|
110
|
+
end
|
111
|
+
|
112
|
+
def scope_strategy=(scope_strategy)
|
113
|
+
verify_not_proxy_and_dont_allow(verification_strategy, implementation_strategy)
|
114
|
+
@scope_strategy = scope_strategy
|
115
|
+
end
|
116
|
+
|
117
|
+
def verify_no_verification_strategy
|
118
|
+
strategy_already_defined_error if verification_strategy
|
119
|
+
end
|
120
|
+
|
121
|
+
def strategy_already_defined_error
|
122
|
+
raise(
|
123
|
+
Errors::DoubleDefinitionError,
|
124
|
+
"This Double already has a #{verification_strategy.name} strategy"
|
125
|
+
)
|
126
|
+
end
|
127
|
+
|
128
|
+
def verify_not_proxy_and_dont_allow(verification_strategy, implementation_strategy)
|
129
|
+
proxy_when_dont_allow_error if
|
130
|
+
verification_strategy.is_a?(Strategies::Verification::DontAllow) &&
|
131
|
+
implementation_strategy.is_a?(Strategies::Implementation::Proxy)
|
132
|
+
end
|
133
|
+
|
134
|
+
def proxy_when_dont_allow_error
|
135
|
+
raise(
|
136
|
+
Errors::DoubleDefinitionError,
|
137
|
+
"Doubles cannot be proxied when using dont_allow strategy"
|
138
|
+
)
|
139
|
+
end
|
140
|
+
|
141
|
+
def no_strategy_error
|
142
|
+
raise(
|
143
|
+
Errors::DoubleDefinitionError,
|
144
|
+
"This Double has no strategy"
|
145
|
+
)
|
146
|
+
end
|
147
|
+
end
|
148
|
+
include StrategySetupMethods
|
149
|
+
|
150
|
+
module StrategyExecutionMethods
|
151
|
+
def create(method_name, *args, &handler)
|
152
|
+
raise DoubleDefinitionCreatorError if no_subject?
|
153
|
+
@method_name, @args, @handler = method_name, args, handler
|
154
|
+
@definition = DoubleDefinition.new(self, subject)
|
155
|
+
verification_strategy ? verification_strategy.call(definition, method_name, args, handler) : no_strategy_error
|
156
|
+
implementation_strategy.call(definition, method_name, args, handler)
|
157
|
+
scope_strategy.call(definition, method_name, args, handler)
|
158
|
+
definition
|
159
|
+
end
|
160
|
+
end
|
161
|
+
include StrategyExecutionMethods
|
162
|
+
|
163
|
+
class DoubleDefinitionCreatorError < Errors::RRError
|
164
|
+
end
|
165
|
+
end
|
166
|
+
end
|
167
|
+
end
|