rr 0.4.8 → 0.4.9

Sign up to get free protection for your applications and to get access to all the features.
Files changed (52) hide show
  1. data/CHANGES +3 -0
  2. data/{README → README.rdoc} +14 -6
  3. data/Rakefile +2 -2
  4. data/lib/rr.rb +11 -3
  5. data/lib/rr/adapters/rr_methods.rb +12 -12
  6. data/lib/rr/adapters/rspec.rb +3 -3
  7. data/lib/rr/adapters/test_unit.rb +3 -3
  8. data/lib/rr/double.rb +12 -10
  9. data/lib/rr/double_creator.rb +48 -45
  10. data/lib/rr/double_definition.rb +17 -149
  11. data/lib/rr/double_definition_builder.rb +11 -11
  12. data/lib/rr/double_definition_creator.rb +156 -0
  13. data/lib/rr/{double_method_proxy.rb → double_definition_creator_proxy.rb} +2 -2
  14. data/lib/rr/double_injection.rb +6 -6
  15. data/lib/rr/double_matches.rb +40 -40
  16. data/lib/rr/errors/rr_error.rb +1 -1
  17. data/lib/rr/expectations/times_called_expectation.rb +1 -1
  18. data/lib/rr/space.rb +9 -30
  19. data/spec/high_level_spec.rb +140 -143
  20. data/spec/rr/adapters/rr_methods_creator_spec.rb +21 -21
  21. data/spec/rr/adapters/rr_methods_space_spec.rb +2 -2
  22. data/spec/rr/double/double_injection_dispatching_spec.rb +15 -15
  23. data/spec/rr/double/double_injection_reset_spec.rb +1 -1
  24. data/spec/rr/double/double_injection_verify_spec.rb +5 -4
  25. data/spec/rr/{double_method_proxy_spec.rb → double_definition_creator_proxy_spec.rb} +12 -10
  26. data/spec/rr/{double_creator_spec.rb → double_definition_creator_spec.rb} +166 -124
  27. data/spec/rr/double_definition_spec.rb +637 -642
  28. data/spec/rr/double_spec.rb +44 -43
  29. data/spec/rr/errors/rr_error_spec.rb +6 -6
  30. data/spec/rr/expectations/times_called_expectation/times_called_expectation_any_times_spec.rb +3 -3
  31. data/spec/rr/expectations/times_called_expectation/times_called_expectation_at_least_spec.rb +8 -8
  32. data/spec/rr/expectations/times_called_expectation/times_called_expectation_at_most_spec.rb +11 -13
  33. data/spec/rr/expectations/times_called_expectation/times_called_expectation_helper.rb +2 -2
  34. data/spec/rr/expectations/times_called_expectation/times_called_expectation_integer_spec.rb +19 -19
  35. data/spec/rr/expectations/times_called_expectation/times_called_expectation_proc_spec.rb +16 -16
  36. data/spec/rr/expectations/times_called_expectation/times_called_expectation_range_spec.rb +16 -16
  37. data/spec/rr/expectations/times_called_expectation/times_called_expectation_spec.rb +7 -11
  38. data/spec/rr/rspec/rspec_adapter_spec.rb +10 -10
  39. data/spec/rr/rspec/rspec_backtrace_tweaking_spec.rb +1 -1
  40. data/spec/rr/space/space_spec.rb +372 -18
  41. data/spec/rr/test_unit/test_unit_backtrace_test.rb +1 -1
  42. data/spec/rr/times_called_matchers/proc_matcher_spec.rb +3 -3
  43. data/spec/rr/times_called_matchers/times_called_matcher_spec.rb +3 -3
  44. data/spec/spec_helper.rb +14 -3
  45. data/spec/spec_suite.rb +2 -2
  46. metadata +47 -45
  47. data/spec/rr/double/double_injection_register_scenario_spec.rb +0 -24
  48. data/spec/rr/space/space_create_spec.rb +0 -268
  49. data/spec/rr/space/space_helper.rb +0 -7
  50. data/spec/rr/space/space_register_spec.rb +0 -32
  51. data/spec/rr/space/space_reset_spec.rb +0 -131
  52. data/spec/rr/space/space_verify_spec.rb +0 -181
@@ -1,7 +1,4 @@
1
1
  module RR
2
- # RR::Double is the use case for a method call.
3
- # It has the ArgumentEqualityExpectation, TimesCalledExpectation,
4
- # and the implementation.
5
2
  class DoubleDefinition #:nodoc:
6
3
  ORIGINAL_METHOD = Object.new
7
4
  attr_accessor :times_called,
@@ -13,144 +10,76 @@ module RR
13
10
  :double
14
11
  attr_reader :block_callback_strategy
15
12
 
16
- def initialize(space)
17
- @space = space
13
+ include Space::Reader
14
+
15
+ def initialize
18
16
  @implementation = nil
19
17
  @argument_expectation = nil
20
18
  @times_matcher = nil
21
19
  @after_call_value = nil
22
20
  @yields_value = nil
23
- returns_block_callback_strategy!
21
+ returns_block_callback_strategy
24
22
  end
25
23
 
26
- # Double#with sets the expectation that the Double will receive
27
- # the passed in arguments.
28
- #
29
- # Passing in a block sets the return value.
30
- #
31
- # mock(subject).method_name.with(1, 2) {:return_value}
32
24
  def with(*args, &returns)
33
25
  @argument_expectation = Expectations::ArgumentEqualityExpectation.new(*args)
34
26
  install_method_callback returns
35
27
  self
36
28
  end
37
29
 
38
- # Double#with_any_args sets the expectation that the Double can receive
39
- # any arguments.
40
- #
41
- # Passing in a block sets the return value.
42
- #
43
- # mock(subject).method_name.with_any_args {:return_value}
44
30
  def with_any_args(&returns)
45
31
  @argument_expectation = Expectations::AnyArgumentExpectation.new
46
32
  install_method_callback returns
47
33
  self
48
34
  end
49
35
 
50
- # Double#with_no_args sets the expectation that the Double will receive
51
- # no arguments.
52
- #
53
- # Passing in a block sets the return value.
54
- #
55
- # mock(subject).method_name.with_no_args {:return_value}
56
36
  def with_no_args(&returns)
57
37
  @argument_expectation = Expectations::ArgumentEqualityExpectation.new()
58
38
  install_method_callback returns
59
39
  self
60
40
  end
61
41
 
62
- # Double#never sets the expectation that the Double will never be
63
- # called.
64
- #
65
- # This method does not accept a block because it will never be called.
66
- #
67
- # mock(subject).method_name.never
68
42
  def never
69
43
  @times_matcher = TimesCalledMatchers::IntegerMatcher.new(0)
70
44
  self
71
45
  end
72
46
 
73
- # Double#once sets the expectation that the Double will be called
74
- # 1 time.
75
- #
76
- # Passing in a block sets the return value.
77
- #
78
- # mock(subject).method_name.once {:return_value}
79
47
  def once(&returns)
80
48
  @times_matcher = TimesCalledMatchers::IntegerMatcher.new(1)
81
49
  install_method_callback returns
82
50
  self
83
51
  end
84
52
 
85
- # Double#twice sets the expectation that the Double will be called
86
- # 2 times.
87
- #
88
- # Passing in a block sets the return value.
89
- #
90
- # mock(subject).method_name.twice {:return_value}
91
53
  def twice(&returns)
92
54
  @times_matcher = TimesCalledMatchers::IntegerMatcher.new(2)
93
55
  install_method_callback returns
94
56
  self
95
57
  end
96
58
 
97
- # Double#at_least sets the expectation that the Double
98
- # will be called at least n times.
99
- # It works by creating a TimesCalledExpectation.
100
- #
101
- # Passing in a block sets the return value.
102
- #
103
- # mock(subject).method_name.at_least(4) {:return_value}
104
59
  def at_least(number, &returns)
105
60
  @times_matcher = TimesCalledMatchers::AtLeastMatcher.new(number)
106
61
  install_method_callback returns
107
62
  self
108
63
  end
109
64
 
110
- # Double#at_most allows sets the expectation that the Double
111
- # will be called at most n times.
112
- # It works by creating a TimesCalledExpectation.
113
- #
114
- # Passing in a block sets the return value.
115
- #
116
- # mock(subject).method_name.at_most(4) {:return_value}
117
65
  def at_most(number, &returns)
118
66
  @times_matcher = TimesCalledMatchers::AtMostMatcher.new(number)
119
67
  install_method_callback returns
120
68
  self
121
69
  end
122
70
 
123
- # Double#any_number_of_times sets an that the Double will be called
124
- # any number of times. This effectively removes the times called expectation
125
- # from the Doublen
126
- #
127
- # Passing in a block sets the return value.
128
- #
129
- # mock(subject).method_name.any_number_of_times
130
71
  def any_number_of_times(&returns)
131
72
  @times_matcher = TimesCalledMatchers::AnyTimesMatcher.new
132
73
  install_method_callback returns
133
74
  self
134
75
  end
135
76
 
136
- # Double#times creates an TimesCalledExpectation of the passed
137
- # in number.
138
- #
139
- # Passing in a block sets the return value.
140
- #
141
- # mock(subject).method_name.times(4) {:return_value}
142
77
  def times(matcher_value, &returns)
143
78
  @times_matcher = TimesCalledMatchers::TimesCalledMatcher.create(matcher_value)
144
79
  install_method_callback returns
145
80
  self
146
81
  end
147
82
 
148
- # Double#ordered sets the Double to have an ordered
149
- # expectation.
150
- #
151
- # Passing in a block sets the return value.
152
- #
153
- # mock(subject).method_name.ordered {return_value}
154
83
  def ordered(&returns)
155
84
  raise(
156
85
  Errors::DoubleDefinitionError,
@@ -159,121 +88,65 @@ module RR
159
88
  "proxy the class's #new method instead."
160
89
  ) unless @double
161
90
  @ordered = true
162
- @space.ordered_doubles << @double unless @space.ordered_doubles.include?(@double)
91
+ space.ordered_doubles << @double unless space.ordered_doubles.include?(@double)
163
92
  install_method_callback returns
164
93
  self
165
94
  end
166
95
 
167
- # Double#ordered? returns true when the Double is ordered.
168
- #
169
- # mock(subject).method_name.ordered?
170
96
  def ordered?
171
97
  @ordered
172
98
  end
173
99
 
174
- # Double#yields sets the Double to invoke a passed in block when
175
- # the Double is called.
176
- # An Expection will be raised if no block is passed in when the
177
- # Double is called.
178
- #
179
- # Passing in a block sets the return value.
180
- #
181
- # mock(subject).method_name.yields(yield_arg1, yield_arg2) {return_value}
182
- # subject.method_name {|yield_arg1, yield_arg2|}
183
100
  def yields(*args, &returns)
184
101
  @yields_value = args
185
102
  install_method_callback returns
186
103
  self
187
104
  end
188
105
 
189
- # Double#after_call creates a callback that occurs after call
190
- # is called. The passed in block receives the return value of
191
- # the Double being called.
192
- # An Expection will be raised if no block is passed in.
193
- #
194
- # mock(subject).method_name {return_value}.after_call {|return_value|}
195
- # subject.method_name # return_value
196
- #
197
- # This feature is built into proxys.
198
- # mock.proxy(User).find('1') {|user| mock(user).valid? {false}}
199
106
  def after_call(&block)
200
107
  raise ArgumentError, "after_call expects a block" unless block
201
108
  @after_call_value = block
202
109
  self
203
110
  end
204
111
 
205
- # Double#verbose sets the Double to print out each method call it receives.
206
- #
207
- # Passing in a block sets the return value
208
112
  def verbose(&block)
209
113
  @verbose = true
210
114
  @after_call_value = block
211
115
  self
212
116
  end
213
117
 
214
- # Double#verbose? returns true when verbose has been called on it. It returns
215
- # true when the double is set to print each method call it receives.
216
118
  def verbose?
217
119
  @verbose ? true : false
218
120
  end
219
121
 
220
- # Double#returns accepts an argument value or a block.
221
- # It will raise an ArgumentError if both are passed in.
222
- #
223
- # Passing in a block causes Double to return the return value of
224
- # the passed in block.
225
- #
226
- # Passing in an argument causes Double to return the argument.
227
- def returns(value=nil, &implementation)
228
- if value && implementation
122
+ def returns(*args, &implementation)
123
+ value = args.first
124
+ if !args.empty? && implementation
229
125
  raise ArgumentError, "returns cannot accept both an argument and a block"
230
126
  end
231
- if value.nil?
127
+ if implementation
232
128
  implemented_by implementation
233
129
  else
234
- implemented_by proc {value}
130
+ implemented_by lambda {value}
235
131
  end
236
132
  self
237
133
  end
238
134
 
239
- # Double#implemented_by sets the implementation of the Double.
240
- # This method takes a Proc or a Method. Passing in a Method allows
241
- # the Double to accept blocks.
242
- #
243
- # obj = Object.new
244
- # def obj.foobar
245
- # yield(1)
246
- # end
247
- # mock(obj).method_name.implemented_by(obj.method(:foobar))
248
- def implemented_by(implementation)
249
- @implementation = implementation
135
+ def proxy
136
+ implemented_by ORIGINAL_METHOD
250
137
  self
251
138
  end
252
139
 
253
- # Double#implemented_by_original_method sets the implementation
254
- # of the Double to be the original method.
255
- # This is primarily used with proxyies.
256
- #
257
- # obj = Object.new
258
- # def obj.foobar
259
- # yield(1)
260
- # end
261
- # mock(obj).method_name.implemented_by_original_method
262
- # obj.foobar {|arg| puts arg} # puts 1
263
- def implemented_by_original_method
264
- implemented_by ORIGINAL_METHOD
140
+ def implemented_by(implementation)
141
+ @implementation = implementation
265
142
  self
266
143
  end
267
144
 
268
- # Double#exact_match? returns true when the passed in arguments
269
- # exactly match the ArgumentEqualityExpectation arguments.
270
145
  def exact_match?(*arguments)
271
146
  return false unless @argument_expectation
272
147
  @argument_expectation.exact_match?(*arguments)
273
148
  end
274
149
 
275
- # Double#wildcard_match? returns true when the passed in arguments
276
- # wildcard match the ArgumentEqualityExpectation arguments.
277
150
  def wildcard_match?(*arguments)
278
151
  return false unless @argument_expectation
279
152
  @argument_expectation.wildcard_match?(*arguments)
@@ -284,28 +157,23 @@ module RR
284
157
  @times_matcher.terminal?
285
158
  end
286
159
 
287
- # The Arguments that this Double expects
288
160
  def expected_arguments
289
161
  return [] unless argument_expectation
290
162
  argument_expectation.expected_arguments
291
163
  end
292
164
 
293
- def returns_block_callback_strategy! # :nodoc:
165
+ def returns_block_callback_strategy # :nodoc:
294
166
  @block_callback_strategy = :returns
295
167
  end
296
168
 
297
- def after_call_block_callback_strategy! # :nodoc:
169
+ def after_call_block_callback_strategy # :nodoc:
298
170
  @block_callback_strategy = :after_call
299
171
  end
300
172
 
301
173
  protected
302
174
  def install_method_callback(block)
303
175
  return unless block
304
- case @block_callback_strategy
305
- when :returns; returns(&block)
306
- when :after_call; after_call(&block)
307
- else raise "Unknown block_callback_strategy: #{@block_callback_strategy.inspect}"
308
- end
176
+ __send__(@block_callback_strategy, &block)
309
177
  end
310
178
  end
311
179
  end
@@ -8,22 +8,22 @@ module RR
8
8
  @handler = handler
9
9
  end
10
10
 
11
- def mock!
11
+ def mock
12
12
  @definition.with(*@args).once
13
13
  end
14
14
 
15
- def stub!
15
+ def stub
16
16
  @definition.any_number_of_times
17
- permissive_argument!
17
+ permissive_argument
18
18
  end
19
19
 
20
- def dont_allow!
20
+ def dont_allow
21
21
  @definition.never
22
- permissive_argument!
23
- reimplementation!
22
+ permissive_argument
23
+ reimplementation
24
24
  end
25
25
 
26
- def permissive_argument!
26
+ def permissive_argument
27
27
  if @args.empty?
28
28
  @definition.with_any_args
29
29
  else
@@ -31,13 +31,13 @@ module RR
31
31
  end
32
32
  end
33
33
 
34
- def reimplementation!
34
+ def reimplementation
35
35
  @definition.returns(&@handler)
36
36
  end
37
37
 
38
- def proxy!
39
- @definition.after_call_block_callback_strategy!
40
- @definition.implemented_by_original_method
38
+ def proxy
39
+ @definition.after_call_block_callback_strategy
40
+ @definition.proxy
41
41
  @definition.after_call(&@handler) if @handler
42
42
  end
43
43
  end
@@ -0,0 +1,156 @@
1
+ module RR
2
+ class DoubleDefinitionCreator # :nodoc
3
+ NO_SUBJECT_ARG = Object.new
4
+
5
+ include Space::Reader
6
+ include Errors
7
+
8
+ def initialize
9
+ @core_strategy = nil
10
+ @using_proxy_strategy = false
11
+ @using_instance_of_strategy = nil
12
+ end
13
+
14
+ def mock(subject=NO_SUBJECT_ARG, method_name=nil, &definition) # :nodoc
15
+ add_strategy(subject, method_name, definition) do
16
+ set_core_strategy :mock
17
+ end
18
+ end
19
+
20
+ def stub(subject=NO_SUBJECT_ARG, method_name=nil, &definition) # :nodoc
21
+ add_strategy(subject, method_name, definition) do
22
+ set_core_strategy :stub
23
+ end
24
+ end
25
+
26
+ def dont_allow(subject=NO_SUBJECT_ARG, method_name=nil, &definition) # :nodoc
27
+ add_strategy(subject, method_name, definition) do
28
+ set_core_strategy :dont_allow
29
+ end
30
+ end
31
+ alias_method :do_not_allow, :dont_allow
32
+ alias_method :dont_call, :dont_allow
33
+ alias_method :do_not_call, :dont_allow
34
+
35
+ def proxy(subject=NO_SUBJECT_ARG, method_name=nil, &definition) # :nodoc
36
+ add_strategy(subject, method_name, definition) do
37
+ proxy_when_dont_allow_error if @core_strategy == :dont_allow
38
+ @using_proxy_strategy = true
39
+ end
40
+ end
41
+ alias_method :probe, :proxy
42
+
43
+ def instance_of(subject=NO_SUBJECT_ARG, method_name=nil, &definition) # :nodoc
44
+ if subject != NO_SUBJECT_ARG && !subject.is_a?(Class)
45
+ raise ArgumentError, "instance_of only accepts class objects" unless subject.is_a?(Class)
46
+ end
47
+ add_strategy(subject, method_name, definition) do
48
+ @using_instance_of_strategy = true
49
+ return self if subject === NO_SUBJECT_ARG
50
+ end
51
+ end
52
+
53
+ def create(subject, method_name, *args, &handler)
54
+ @args = args
55
+ @handler = handler
56
+ if @using_instance_of_strategy
57
+ setup_doubles_for_class_instances(subject, method_name)
58
+ else
59
+ setup_double(subject, method_name)
60
+ end
61
+ transform
62
+ @definition
63
+ end
64
+
65
+ protected
66
+ def add_strategy(subject, method_name, definition)
67
+ if method_name && definition
68
+ raise ArgumentError, "Cannot pass in a method name and a block"
69
+ end
70
+ yield
71
+ if subject.__id__ === NO_SUBJECT_ARG.__id__
72
+ self
73
+ elsif method_name
74
+ create subject, method_name, &definition
75
+ else
76
+ DoubleDefinitionCreatorProxy.new(self, subject, &definition)
77
+ end
78
+ end
79
+
80
+ def set_core_strategy(strategy)
81
+ verify_no_core_strategy
82
+ @core_strategy = strategy
83
+ proxy_when_dont_allow_error if strategy == :dont_allow && @using_proxy_strategy
84
+ end
85
+
86
+ def setup_double(subject, method_name)
87
+ @double_injection = space.double_injection(subject, method_name)
88
+ @double = Double.new(@double_injection)
89
+ @definition = @double.definition
90
+ end
91
+
92
+ def setup_doubles_for_class_instances(subject, method_name)
93
+ class_double = space.double_injection(subject, :new)
94
+ class_double = Double.new(class_double)
95
+
96
+ instance_method_name = method_name
97
+
98
+ @definition = DoubleDefinition.new
99
+ class_handler = lambda do |return_value|
100
+ double_injection = space.double_injection(return_value, instance_method_name)
101
+ Double.new(double_injection, @definition)
102
+ return_value
103
+ end
104
+
105
+ builder = DoubleDefinitionBuilder.new(
106
+ class_double.definition,
107
+ [],
108
+ class_handler
109
+ )
110
+ builder.stub
111
+ builder.proxy
112
+ end
113
+
114
+ def transform
115
+ builder = DoubleDefinitionBuilder.new(@definition, @args, @handler)
116
+
117
+ verify_strategy
118
+ builder.__send__(@core_strategy)
119
+
120
+ if @using_proxy_strategy
121
+ builder.proxy
122
+ else
123
+ builder.reimplementation
124
+ end
125
+ end
126
+
127
+ def verify_no_core_strategy
128
+ strategy_already_defined_error if @core_strategy
129
+ end
130
+
131
+ def strategy_already_defined_error
132
+ raise(
133
+ DoubleDefinitionError,
134
+ "This Double already has a #{@core_strategy} strategy"
135
+ )
136
+ end
137
+
138
+ def verify_strategy
139
+ no_strategy_error unless @core_strategy
140
+ end
141
+
142
+ def no_strategy_error
143
+ raise(
144
+ DoubleDefinitionError,
145
+ "This Double has no strategy"
146
+ )
147
+ end
148
+
149
+ def proxy_when_dont_allow_error
150
+ raise(
151
+ DoubleDefinitionError,
152
+ "Doubles cannot be proxied when using dont_allow strategy"
153
+ )
154
+ end
155
+ end
156
+ end