rr 0.4.8 → 0.4.9

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.
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