floehopper-mocha 0.9.3.20081220175348

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 (162) hide show
  1. data/COPYING +3 -0
  2. data/MIT-LICENSE +7 -0
  3. data/README +35 -0
  4. data/RELEASE +257 -0
  5. data/Rakefile +199 -0
  6. data/examples/misc.rb +44 -0
  7. data/examples/mocha.rb +26 -0
  8. data/examples/stubba.rb +65 -0
  9. data/lib/mocha/any_instance_method.rb +54 -0
  10. data/lib/mocha/argument_iterator.rb +21 -0
  11. data/lib/mocha/backtrace_filter.rb +17 -0
  12. data/lib/mocha/cardinality.rb +95 -0
  13. data/lib/mocha/central.rb +27 -0
  14. data/lib/mocha/change_state_side_effect.rb +19 -0
  15. data/lib/mocha/class_method.rb +86 -0
  16. data/lib/mocha/configuration.rb +60 -0
  17. data/lib/mocha/deprecation.rb +22 -0
  18. data/lib/mocha/exception_raiser.rb +17 -0
  19. data/lib/mocha/expectation.rb +451 -0
  20. data/lib/mocha/expectation_error.rb +15 -0
  21. data/lib/mocha/expectation_list.rb +50 -0
  22. data/lib/mocha/in_state_ordering_constraint.rb +19 -0
  23. data/lib/mocha/inspect.rb +67 -0
  24. data/lib/mocha/instance_method.rb +16 -0
  25. data/lib/mocha/is_a.rb +9 -0
  26. data/lib/mocha/logger.rb +15 -0
  27. data/lib/mocha/metaclass.rb +13 -0
  28. data/lib/mocha/method_matcher.rb +21 -0
  29. data/lib/mocha/mini_test_adapter.rb +50 -0
  30. data/lib/mocha/mock.rb +200 -0
  31. data/lib/mocha/mockery.rb +181 -0
  32. data/lib/mocha/module_method.rb +16 -0
  33. data/lib/mocha/multiple_yields.rb +20 -0
  34. data/lib/mocha/names.rb +53 -0
  35. data/lib/mocha/no_yields.rb +11 -0
  36. data/lib/mocha/object.rb +187 -0
  37. data/lib/mocha/parameter_matchers/all_of.rb +42 -0
  38. data/lib/mocha/parameter_matchers/any_of.rb +47 -0
  39. data/lib/mocha/parameter_matchers/any_parameters.rb +40 -0
  40. data/lib/mocha/parameter_matchers/anything.rb +33 -0
  41. data/lib/mocha/parameter_matchers/base.rb +15 -0
  42. data/lib/mocha/parameter_matchers/equals.rb +42 -0
  43. data/lib/mocha/parameter_matchers/has_entries.rb +45 -0
  44. data/lib/mocha/parameter_matchers/has_entry.rb +56 -0
  45. data/lib/mocha/parameter_matchers/has_key.rb +42 -0
  46. data/lib/mocha/parameter_matchers/has_value.rb +42 -0
  47. data/lib/mocha/parameter_matchers/includes.rb +40 -0
  48. data/lib/mocha/parameter_matchers/instance_of.rb +42 -0
  49. data/lib/mocha/parameter_matchers/is_a.rb +42 -0
  50. data/lib/mocha/parameter_matchers/kind_of.rb +42 -0
  51. data/lib/mocha/parameter_matchers/not.rb +42 -0
  52. data/lib/mocha/parameter_matchers/object.rb +15 -0
  53. data/lib/mocha/parameter_matchers/optionally.rb +55 -0
  54. data/lib/mocha/parameter_matchers/regexp_matches.rb +43 -0
  55. data/lib/mocha/parameter_matchers/responds_with.rb +43 -0
  56. data/lib/mocha/parameter_matchers/yaml_equivalent.rb +43 -0
  57. data/lib/mocha/parameter_matchers.rb +27 -0
  58. data/lib/mocha/parameters_matcher.rb +37 -0
  59. data/lib/mocha/pretty_parameters.rb +28 -0
  60. data/lib/mocha/return_values.rb +31 -0
  61. data/lib/mocha/sequence.rb +42 -0
  62. data/lib/mocha/single_return_value.rb +17 -0
  63. data/lib/mocha/single_yield.rb +18 -0
  64. data/lib/mocha/standalone.rb +166 -0
  65. data/lib/mocha/state_machine.rb +91 -0
  66. data/lib/mocha/stubbing_error.rb +16 -0
  67. data/lib/mocha/test_case_adapter.rb +103 -0
  68. data/lib/mocha/unexpected_invocation.rb +18 -0
  69. data/lib/mocha/yield_parameters.rb +31 -0
  70. data/lib/mocha.rb +47 -0
  71. data/lib/mocha_standalone.rb +2 -0
  72. data/lib/stubba.rb +4 -0
  73. data/test/acceptance/acceptance_test_helper.rb +38 -0
  74. data/test/acceptance/bug_18914_test.rb +43 -0
  75. data/test/acceptance/bug_21465_test.rb +34 -0
  76. data/test/acceptance/bug_21563_test.rb +25 -0
  77. data/test/acceptance/expected_invocation_count_test.rb +196 -0
  78. data/test/acceptance/failure_messages_test.rb +64 -0
  79. data/test/acceptance/minitest_test.rb +130 -0
  80. data/test/acceptance/mocha_example_test.rb +98 -0
  81. data/test/acceptance/mocha_test_result_test.rb +84 -0
  82. data/test/acceptance/mock_test.rb +100 -0
  83. data/test/acceptance/mock_with_initializer_block_test.rb +51 -0
  84. data/test/acceptance/mocked_methods_dispatch_test.rb +78 -0
  85. data/test/acceptance/optional_parameters_test.rb +70 -0
  86. data/test/acceptance/parameter_matcher_test.rb +209 -0
  87. data/test/acceptance/partial_mocks_test.rb +47 -0
  88. data/test/acceptance/return_value_test.rb +52 -0
  89. data/test/acceptance/sequence_test.rb +186 -0
  90. data/test/acceptance/standalone_test.rb +139 -0
  91. data/test/acceptance/states_test.rb +70 -0
  92. data/test/acceptance/stub_any_instance_method_test.rb +195 -0
  93. data/test/acceptance/stub_class_method_test.rb +203 -0
  94. data/test/acceptance/stub_everything_test.rb +56 -0
  95. data/test/acceptance/stub_instance_method_test.rb +203 -0
  96. data/test/acceptance/stub_module_method_test.rb +163 -0
  97. data/test/acceptance/stub_test.rb +52 -0
  98. data/test/acceptance/stubba_example_test.rb +102 -0
  99. data/test/acceptance/stubba_test.rb +15 -0
  100. data/test/acceptance/stubba_test_result_test.rb +66 -0
  101. data/test/acceptance/stubbing_error_backtrace_test.rb +64 -0
  102. data/test/acceptance/stubbing_method_unnecessarily_test.rb +65 -0
  103. data/test/acceptance/stubbing_non_existent_any_instance_method_test.rb +130 -0
  104. data/test/acceptance/stubbing_non_existent_class_method_test.rb +157 -0
  105. data/test/acceptance/stubbing_non_existent_instance_method_test.rb +147 -0
  106. data/test/acceptance/stubbing_non_public_any_instance_method_test.rb +130 -0
  107. data/test/acceptance/stubbing_non_public_class_method_test.rb +163 -0
  108. data/test/acceptance/stubbing_non_public_instance_method_test.rb +143 -0
  109. data/test/acceptance/stubbing_on_non_mock_object_test.rb +64 -0
  110. data/test/deprecation_disabler.rb +15 -0
  111. data/test/execution_point.rb +36 -0
  112. data/test/method_definer.rb +24 -0
  113. data/test/simple_counter.rb +13 -0
  114. data/test/test_helper.rb +11 -0
  115. data/test/test_runner.rb +33 -0
  116. data/test/unit/any_instance_method_test.rb +126 -0
  117. data/test/unit/array_inspect_test.rb +16 -0
  118. data/test/unit/backtrace_filter_test.rb +19 -0
  119. data/test/unit/cardinality_test.rb +56 -0
  120. data/test/unit/central_test.rb +65 -0
  121. data/test/unit/change_state_side_effect_test.rb +41 -0
  122. data/test/unit/class_method_test.rb +237 -0
  123. data/test/unit/date_time_inspect_test.rb +21 -0
  124. data/test/unit/exception_raiser_test.rb +42 -0
  125. data/test/unit/expectation_list_test.rb +57 -0
  126. data/test/unit/expectation_test.rb +459 -0
  127. data/test/unit/hash_inspect_test.rb +16 -0
  128. data/test/unit/in_state_ordering_constraint_test.rb +43 -0
  129. data/test/unit/metaclass_test.rb +22 -0
  130. data/test/unit/method_matcher_test.rb +23 -0
  131. data/test/unit/mock_test.rb +295 -0
  132. data/test/unit/mockery_test.rb +149 -0
  133. data/test/unit/multiple_yields_test.rb +18 -0
  134. data/test/unit/no_yields_test.rb +18 -0
  135. data/test/unit/object_inspect_test.rb +37 -0
  136. data/test/unit/object_test.rb +82 -0
  137. data/test/unit/parameter_matchers/all_of_test.rb +26 -0
  138. data/test/unit/parameter_matchers/any_of_test.rb +26 -0
  139. data/test/unit/parameter_matchers/anything_test.rb +21 -0
  140. data/test/unit/parameter_matchers/equals_test.rb +25 -0
  141. data/test/unit/parameter_matchers/has_entries_test.rb +51 -0
  142. data/test/unit/parameter_matchers/has_entry_test.rb +62 -0
  143. data/test/unit/parameter_matchers/has_key_test.rb +36 -0
  144. data/test/unit/parameter_matchers/has_value_test.rb +37 -0
  145. data/test/unit/parameter_matchers/includes_test.rb +25 -0
  146. data/test/unit/parameter_matchers/instance_of_test.rb +25 -0
  147. data/test/unit/parameter_matchers/is_a_test.rb +25 -0
  148. data/test/unit/parameter_matchers/kind_of_test.rb +25 -0
  149. data/test/unit/parameter_matchers/not_test.rb +26 -0
  150. data/test/unit/parameter_matchers/regexp_matches_test.rb +25 -0
  151. data/test/unit/parameter_matchers/responds_with_test.rb +25 -0
  152. data/test/unit/parameter_matchers/stub_matcher.rb +27 -0
  153. data/test/unit/parameter_matchers/yaml_equivalent_test.rb +25 -0
  154. data/test/unit/parameters_matcher_test.rb +121 -0
  155. data/test/unit/return_values_test.rb +63 -0
  156. data/test/unit/sequence_test.rb +104 -0
  157. data/test/unit/single_return_value_test.rb +14 -0
  158. data/test/unit/single_yield_test.rb +18 -0
  159. data/test/unit/state_machine_test.rb +98 -0
  160. data/test/unit/string_inspect_test.rb +11 -0
  161. data/test/unit/yield_parameters_test.rb +93 -0
  162. metadata +226 -0
@@ -0,0 +1,451 @@
1
+ require 'mocha/method_matcher'
2
+ require 'mocha/parameters_matcher'
3
+ require 'mocha/expectation_error'
4
+ require 'mocha/return_values'
5
+ require 'mocha/exception_raiser'
6
+ require 'mocha/yield_parameters'
7
+ require 'mocha/is_a'
8
+ require 'mocha/in_state_ordering_constraint'
9
+ require 'mocha/change_state_side_effect'
10
+ require 'mocha/cardinality'
11
+
12
+ module Mocha # :nodoc:
13
+
14
+ # Methods on expectations returned from Mock#expects, Mock#stubs, Object#expects and Object#stubs.
15
+ class Expectation
16
+
17
+ # :call-seq: times(range) -> expectation
18
+ #
19
+ # Modifies expectation so that the number of calls to the expected method must be within a specific +range+.
20
+ #
21
+ # +range+ can be specified as an exact integer or as a range of integers
22
+ # object = mock()
23
+ # object.expects(:expected_method).times(3)
24
+ # 3.times { object.expected_method }
25
+ # # => verify succeeds
26
+ #
27
+ # object = mock()
28
+ # object.expects(:expected_method).times(3)
29
+ # 2.times { object.expected_method }
30
+ # # => verify fails
31
+ #
32
+ # object = mock()
33
+ # object.expects(:expected_method).times(2..4)
34
+ # 3.times { object.expected_method }
35
+ # # => verify succeeds
36
+ #
37
+ # object = mock()
38
+ # object.expects(:expected_method).times(2..4)
39
+ # object.expected_method
40
+ # # => verify fails
41
+ def times(range)
42
+ @cardinality = Cardinality.times(range)
43
+ self
44
+ end
45
+
46
+ # :call-seq: once() -> expectation
47
+ #
48
+ # Modifies expectation so that the expected method must be called exactly once.
49
+ # Note that this is the default behaviour for an expectation, but you may wish to use it for clarity/emphasis.
50
+ # object = mock()
51
+ # object.expects(:expected_method).once
52
+ # object.expected_method
53
+ # # => verify succeeds
54
+ #
55
+ # object = mock()
56
+ # object.expects(:expected_method).once
57
+ # object.expected_method
58
+ # object.expected_method
59
+ # # => verify fails
60
+ #
61
+ # object = mock()
62
+ # object.expects(:expected_method).once
63
+ # # => verify fails
64
+ def once
65
+ @cardinality = Cardinality.exactly(1)
66
+ self
67
+ end
68
+
69
+ # :call-seq: never() -> expectation
70
+ #
71
+ # Modifies expectation so that the expected method must never be called.
72
+ # object = mock()
73
+ # object.expects(:expected_method).never
74
+ # object.expected_method
75
+ # # => verify fails
76
+ #
77
+ # object = mock()
78
+ # object.expects(:expected_method).never
79
+ # object.expected_method
80
+ # # => verify succeeds
81
+ def never
82
+ @cardinality = Cardinality.exactly(0)
83
+ self
84
+ end
85
+
86
+ # :call-seq: at_least(minimum_number_of_times) -> expectation
87
+ #
88
+ # Modifies expectation so that the expected method must be called at least a +minimum_number_of_times+.
89
+ # object = mock()
90
+ # object.expects(:expected_method).at_least(2)
91
+ # 3.times { object.expected_method }
92
+ # # => verify succeeds
93
+ #
94
+ # object = mock()
95
+ # object.expects(:expected_method).at_least(2)
96
+ # object.expected_method
97
+ # # => verify fails
98
+ def at_least(minimum_number_of_times)
99
+ @cardinality = Cardinality.at_least(minimum_number_of_times)
100
+ self
101
+ end
102
+
103
+ # :call-seq: at_least_once() -> expectation
104
+ #
105
+ # Modifies expectation so that the expected method must be called at least once.
106
+ # object = mock()
107
+ # object.expects(:expected_method).at_least_once
108
+ # object.expected_method
109
+ # # => verify succeeds
110
+ #
111
+ # object = mock()
112
+ # object.expects(:expected_method).at_least_once
113
+ # # => verify fails
114
+ def at_least_once
115
+ at_least(1)
116
+ self
117
+ end
118
+
119
+ # :call-seq: at_most(maximum_number_of_times) -> expectation
120
+ #
121
+ # Modifies expectation so that the expected method must be called at most a +maximum_number_of_times+.
122
+ # object = mock()
123
+ # object.expects(:expected_method).at_most(2)
124
+ # 2.times { object.expected_method }
125
+ # # => verify succeeds
126
+ #
127
+ # object = mock()
128
+ # object.expects(:expected_method).at_most(2)
129
+ # 3.times { object.expected_method }
130
+ # # => verify fails
131
+ def at_most(maximum_number_of_times)
132
+ @cardinality = Cardinality.at_most(maximum_number_of_times)
133
+ self
134
+ end
135
+
136
+ # :call-seq: at_most_once() -> expectation
137
+ #
138
+ # Modifies expectation so that the expected method must be called at most once.
139
+ # object = mock()
140
+ # object.expects(:expected_method).at_most_once
141
+ # object.expected_method
142
+ # # => verify succeeds
143
+ #
144
+ # object = mock()
145
+ # object.expects(:expected_method).at_most_once
146
+ # 2.times { object.expected_method }
147
+ # # => verify fails
148
+ def at_most_once()
149
+ at_most(1)
150
+ self
151
+ end
152
+
153
+ # :call-seq: with(*expected_parameters, &matching_block) -> expectation
154
+ #
155
+ # Modifies expectation so that the expected method must be called with +expected_parameters+.
156
+ # object = mock()
157
+ # object.expects(:expected_method).with(:param1, :param2)
158
+ # object.expected_method(:param1, :param2)
159
+ # # => verify succeeds
160
+ #
161
+ # object = mock()
162
+ # object.expects(:expected_method).with(:param1, :param2)
163
+ # object.expected_method(:param3)
164
+ # # => verify fails
165
+ # May be used with parameter matchers in Mocha::ParameterMatchers.
166
+ #
167
+ # If a +matching_block+ is given, the block is called with the parameters passed to the expected method.
168
+ # The expectation is matched if the block evaluates to +true+.
169
+ # object = mock()
170
+ # object.expects(:expected_method).with() { |value| value % 4 == 0 }
171
+ # object.expected_method(16)
172
+ # # => verify succeeds
173
+ #
174
+ # object = mock()
175
+ # object.expects(:expected_method).with() { |value| value % 4 == 0 }
176
+ # object.expected_method(17)
177
+ # # => verify fails
178
+ def with(*expected_parameters, &matching_block)
179
+ @parameters_matcher = ParametersMatcher.new(expected_parameters, &matching_block)
180
+ self
181
+ end
182
+
183
+ # :call-seq: yields(*parameters) -> expectation
184
+ #
185
+ # Modifies expectation so that when the expected method is called, it yields with the specified +parameters+.
186
+ # object = mock()
187
+ # object.expects(:expected_method).yields('result')
188
+ # yielded_value = nil
189
+ # object.expected_method { |value| yielded_value = value }
190
+ # yielded_value # => 'result'
191
+ # May be called multiple times on the same expectation for consecutive invocations. Also see Expectation#then.
192
+ # object = mock()
193
+ # object.stubs(:expected_method).yields(1).then.yields(2)
194
+ # yielded_values_from_first_invocation = []
195
+ # yielded_values_from_second_invocation = []
196
+ # object.expected_method { |value| yielded_values_from_first_invocation << value } # first invocation
197
+ # object.expected_method { |value| yielded_values_from_second_invocation << value } # second invocation
198
+ # yielded_values_from_first_invocation # => [1]
199
+ # yielded_values_from_second_invocation # => [2]
200
+ def yields(*parameters)
201
+ @yield_parameters.add(*parameters)
202
+ self
203
+ end
204
+
205
+ # :call-seq: multiple_yields(*parameter_groups) -> expectation
206
+ #
207
+ # Modifies expectation so that when the expected method is called, it yields multiple times per invocation with the specified +parameter_groups+.
208
+ # object = mock()
209
+ # object.expects(:expected_method).multiple_yields(['result_1', 'result_2'], ['result_3'])
210
+ # yielded_values = []
211
+ # object.expected_method { |*values| yielded_values << values }
212
+ # yielded_values # => [['result_1', 'result_2'], ['result_3]]
213
+ # May be called multiple times on the same expectation for consecutive invocations. Also see Expectation#then.
214
+ # object = mock()
215
+ # object.stubs(:expected_method).multiple_yields([1, 2], [3]).then.multiple_yields([4], [5, 6])
216
+ # yielded_values_from_first_invocation = []
217
+ # yielded_values_from_second_invocation = []
218
+ # object.expected_method { |*values| yielded_values_from_first_invocation << values } # first invocation
219
+ # object.expected_method { |*values| yielded_values_from_second_invocation << values } # second invocation
220
+ # yielded_values_from_first_invocation # => [[1, 2], [3]]
221
+ # yielded_values_from_second_invocation # => [[4], [5, 6]]
222
+ def multiple_yields(*parameter_groups)
223
+ @yield_parameters.multiple_add(*parameter_groups)
224
+ self
225
+ end
226
+
227
+ # :call-seq: returns(value) -> expectation
228
+ # returns(*values) -> expectation
229
+ #
230
+ # Modifies expectation so that when the expected method is called, it returns the specified +value+.
231
+ # object = mock()
232
+ # object.stubs(:stubbed_method).returns('result')
233
+ # object.stubbed_method # => 'result'
234
+ # object.stubbed_method # => 'result'
235
+ # If multiple +values+ are given, these are returned in turn on consecutive calls to the method.
236
+ # object = mock()
237
+ # object.stubs(:stubbed_method).returns(1, 2)
238
+ # object.stubbed_method # => 1
239
+ # object.stubbed_method # => 2
240
+ # May be called multiple times on the same expectation. Also see Expectation#then.
241
+ # object = mock()
242
+ # object.stubs(:expected_method).returns(1, 2).then.returns(3)
243
+ # object.expected_method # => 1
244
+ # object.expected_method # => 2
245
+ # object.expected_method # => 3
246
+ # May be called in conjunction with Expectation#raises on the same expectation.
247
+ # object = mock()
248
+ # object.stubs(:expected_method).returns(1, 2).then.raises(Exception)
249
+ # object.expected_method # => 1
250
+ # object.expected_method # => 2
251
+ # object.expected_method # => raises exception of class Exception1
252
+ # Note that in Ruby a method returning multiple values is exactly equivalent to a method returning an Array of those values.
253
+ # object = mock()
254
+ # object.stubs(:expected_method).returns([1, 2])
255
+ # x, y = object.expected_method
256
+ # x # => 1
257
+ # y # => 2
258
+ def returns(*values)
259
+ @return_values += ReturnValues.build(*values)
260
+ self
261
+ end
262
+
263
+ # :call-seq: raises(exception = RuntimeError, message = nil) -> expectation
264
+ #
265
+ # Modifies expectation so that when the expected method is called, it raises the specified +exception+ with the specified +message+.
266
+ # object = mock()
267
+ # object.expects(:expected_method).raises(Exception, 'message')
268
+ # object.expected_method # => raises exception of class Exception and with message 'message'
269
+ # May be called multiple times on the same expectation. Also see Expectation#then.
270
+ # object = mock()
271
+ # object.stubs(:expected_method).raises(Exception1).then.raises(Exception2)
272
+ # object.expected_method # => raises exception of class Exception1
273
+ # object.expected_method # => raises exception of class Exception2
274
+ # May be called in conjunction with Expectation#returns on the same expectation.
275
+ # object = mock()
276
+ # object.stubs(:expected_method).raises(Exception).then.returns(2, 3)
277
+ # object.expected_method # => raises exception of class Exception1
278
+ # object.expected_method # => 2
279
+ # object.expected_method # => 3
280
+ def raises(exception = RuntimeError, message = nil)
281
+ @return_values += ReturnValues.new(ExceptionRaiser.new(exception, message))
282
+ self
283
+ end
284
+
285
+ # :call-seq: then() -> expectation
286
+ # then(state_machine.is(state)) -> expectation
287
+ #
288
+ # <tt>then()</tt> is used as syntactic sugar to improve readability. It has no effect on state of the expectation.
289
+ # object = mock()
290
+ # object.stubs(:expected_method).returns(1, 2).then.raises(Exception).then.returns(4)
291
+ # object.expected_method # => 1
292
+ # object.expected_method # => 2
293
+ # object.expected_method # => raises exception of class Exception
294
+ # object.expected_method # => 4
295
+ #
296
+ # <tt>then(state_machine.is(state))</tt> is used to change the +state_machine+ to the specified +state+ when the invocation occurs.
297
+ #
298
+ # See also Standalone#states, StateMachine and Expectation#when.
299
+ # power = states('power').starts_as('off')
300
+ #
301
+ # radio = mock('radio')
302
+ # radio.expects(:switch_on).then(power.is('on'))
303
+ # radio.expects(:select_channel).with('BBC Radio 4').when(power.is('on'))
304
+ # radio.expects(:adjust_volume).with(+5).when(power.is('on'))
305
+ # radio.expects(:select_channel).with('BBC World Service').when(power.is('on'))
306
+ # radio.expects(:adjust_volume).with(-5).when(power.is('on'))
307
+ # radio.expects(:switch_off).then(power.is('off'))
308
+ def then(*parameters)
309
+ if parameters.length == 1
310
+ state = parameters.first
311
+ add_side_effect(ChangeStateSideEffect.new(state))
312
+ end
313
+ self
314
+ end
315
+
316
+ # :call-seq: when(state_machine.is(state)) -> exception
317
+ #
318
+ # Constrains the expectation to occur only when the +state_machine+ is in the named +state+.
319
+ #
320
+ # See also Standalone#states, StateMachine#starts_as and Expectation#then.
321
+ # power = states('power').starts_as('off')
322
+ #
323
+ # radio = mock('radio')
324
+ # radio.expects(:switch_on).then(power.is('on'))
325
+ # radio.expects(:select_channel).with('BBC Radio 4').when(power.is('on'))
326
+ # radio.expects(:adjust_volume).with(+5).when(power.is('on'))
327
+ # radio.expects(:select_channel).with('BBC World Service').when(power.is('on'))
328
+ # radio.expects(:adjust_volume).with(-5).when(power.is('on'))
329
+ # radio.expects(:switch_off).then(power.is('off'))
330
+ def when(state_predicate)
331
+ add_ordering_constraint(InStateOrderingConstraint.new(state_predicate))
332
+ self
333
+ end
334
+
335
+ # :call-seq: in_sequence(*sequences) -> expectation
336
+ #
337
+ # Constrains this expectation so that it must be invoked at the current point in the sequence.
338
+ #
339
+ # To expect a sequence of invocations, write the expectations in order and add the in_sequence(sequence) clause to each one.
340
+ #
341
+ # Expectations in a sequence can have any invocation count.
342
+ #
343
+ # If an expectation in a sequence is stubbed, rather than expected, it can be skipped in the sequence.
344
+ #
345
+ # See also Standalone#sequence.
346
+ # breakfast = sequence('breakfast')
347
+ #
348
+ # egg = mock('egg')
349
+ # egg.expects(:crack).in_sequence(breakfast)
350
+ # egg.expects(:fry).in_sequence(breakfast)
351
+ # egg.expects(:eat).in_sequence(breakfast)
352
+ def in_sequence(*sequences)
353
+ sequences.each { |sequence| add_in_sequence_ordering_constraint(sequence) }
354
+ self
355
+ end
356
+
357
+ # :stopdoc:
358
+
359
+ attr_reader :backtrace
360
+
361
+ def initialize(mock, expected_method_name, backtrace = nil)
362
+ @mock = mock
363
+ @method_matcher = MethodMatcher.new(expected_method_name.to_sym)
364
+ @parameters_matcher = ParametersMatcher.new
365
+ @ordering_constraints = []
366
+ @side_effects = []
367
+ @cardinality, @invocation_count = Cardinality.exactly(1), 0
368
+ @return_values = ReturnValues.new
369
+ @yield_parameters = YieldParameters.new
370
+ @backtrace = backtrace || caller
371
+ end
372
+
373
+ def add_ordering_constraint(ordering_constraint)
374
+ @ordering_constraints << ordering_constraint
375
+ end
376
+
377
+ def add_in_sequence_ordering_constraint(sequence)
378
+ sequence.constrain_as_next_in_sequence(self)
379
+ end
380
+
381
+ def add_side_effect(side_effect)
382
+ @side_effects << side_effect
383
+ end
384
+
385
+ def perform_side_effects
386
+ @side_effects.each { |side_effect| side_effect.perform }
387
+ end
388
+
389
+ def in_correct_order?
390
+ @ordering_constraints.all? { |ordering_constraint| ordering_constraint.allows_invocation_now? }
391
+ end
392
+
393
+ def matches_method?(method_name)
394
+ @method_matcher.match?(method_name)
395
+ end
396
+
397
+ def match?(actual_method_name, *actual_parameters)
398
+ @method_matcher.match?(actual_method_name) && @parameters_matcher.match?(actual_parameters) && in_correct_order?
399
+ end
400
+
401
+ def invocations_allowed?
402
+ @cardinality.invocations_allowed?(@invocation_count)
403
+ end
404
+
405
+ def satisfied?
406
+ @cardinality.satisfied?(@invocation_count)
407
+ end
408
+
409
+ def invoke
410
+ @invocation_count += 1
411
+ perform_side_effects()
412
+ if block_given? then
413
+ @yield_parameters.next_invocation.each do |yield_parameters|
414
+ yield(*yield_parameters)
415
+ end
416
+ end
417
+ @return_values.next
418
+ end
419
+
420
+ def verified?(assertion_counter = nil)
421
+ assertion_counter.increment if assertion_counter && @cardinality.needs_verifying?
422
+ @cardinality.verified?(@invocation_count)
423
+ end
424
+
425
+ def used?
426
+ @cardinality.used?(@invocation_count)
427
+ end
428
+
429
+ def mocha_inspect
430
+ message = "#{@cardinality.mocha_inspect}, "
431
+ message << case @invocation_count
432
+ when 0 then "not yet invoked"
433
+ when 1 then "already invoked once"
434
+ when 2 then "already invoked twice"
435
+ else "already invoked #{@invocation_count} times"
436
+ end
437
+ message << ": "
438
+ message << method_signature
439
+ message << "; #{@ordering_constraints.map { |oc| oc.mocha_inspect }.join("; ")}" unless @ordering_constraints.empty?
440
+ message
441
+ end
442
+
443
+ def method_signature
444
+ "#{@mock.mocha_inspect}.#{@method_matcher.mocha_inspect}#{@parameters_matcher.mocha_inspect}"
445
+ end
446
+
447
+ # :startdoc:
448
+
449
+ end
450
+
451
+ end
@@ -0,0 +1,15 @@
1
+ require 'mocha/backtrace_filter'
2
+
3
+ module Mocha
4
+
5
+ class ExpectationError < StandardError
6
+
7
+ def initialize(message = nil, backtrace = [])
8
+ super(message)
9
+ filter = BacktraceFilter.new
10
+ set_backtrace(filter.filtered(backtrace))
11
+ end
12
+
13
+ end
14
+
15
+ end
@@ -0,0 +1,50 @@
1
+ module Mocha # :nodoc:
2
+
3
+ class ExpectationList
4
+
5
+ def initialize
6
+ @expectations = []
7
+ end
8
+
9
+ def add(expectation)
10
+ @expectations.unshift(expectation)
11
+ expectation
12
+ end
13
+
14
+ def matches_method?(method_name)
15
+ @expectations.any? { |expectation| expectation.matches_method?(method_name) }
16
+ end
17
+
18
+ def match(method_name, *arguments)
19
+ matching_expectations(method_name, *arguments).first
20
+ end
21
+
22
+ def match_allowing_invocation(method_name, *arguments)
23
+ matching_expectations(method_name, *arguments).detect { |e| e.invocations_allowed? }
24
+ end
25
+
26
+ def verified?(assertion_counter = nil)
27
+ @expectations.all? { |expectation| expectation.verified?(assertion_counter) }
28
+ end
29
+
30
+ def to_a
31
+ @expectations
32
+ end
33
+
34
+ def to_set
35
+ @expectations.to_set
36
+ end
37
+
38
+ def length
39
+ @expectations.length
40
+ end
41
+
42
+ private
43
+
44
+ def matching_expectations(method_name, *arguments)
45
+ @expectations.select { |e| e.match?(method_name, *arguments) }
46
+ end
47
+
48
+ end
49
+
50
+ end
@@ -0,0 +1,19 @@
1
+ module Mocha
2
+
3
+ class InStateOrderingConstraint
4
+
5
+ def initialize(state_predicate)
6
+ @state_predicate = state_predicate
7
+ end
8
+
9
+ def allows_invocation_now?
10
+ @state_predicate.active?
11
+ end
12
+
13
+ def mocha_inspect
14
+ "when #{@state_predicate.mocha_inspect}"
15
+ end
16
+
17
+ end
18
+
19
+ end
@@ -0,0 +1,67 @@
1
+ require 'date'
2
+
3
+ module Mocha
4
+
5
+ module ObjectMethods
6
+ def mocha_inspect
7
+ address = self.__id__ * 2
8
+ address += 0x100000000 if address < 0
9
+ inspect =~ /#</ ? "#<#{self.class}:0x#{'%x' % address}>" : inspect
10
+ end
11
+ end
12
+
13
+ module StringMethods
14
+ def mocha_inspect
15
+ inspect.gsub(/\"/, "'")
16
+ end
17
+ end
18
+
19
+ module ArrayMethods
20
+ def mocha_inspect
21
+ "[#{collect { |member| member.mocha_inspect }.join(', ')}]"
22
+ end
23
+ end
24
+
25
+ module HashMethods
26
+ def mocha_inspect
27
+ "{#{collect { |key, value| "#{key.mocha_inspect} => #{value.mocha_inspect}" }.join(', ')}}"
28
+ end
29
+ end
30
+
31
+ module TimeMethods
32
+ def mocha_inspect
33
+ "#{inspect} (#{to_f} secs)"
34
+ end
35
+ end
36
+
37
+ module DateMethods
38
+ def mocha_inspect
39
+ to_s
40
+ end
41
+ end
42
+
43
+ end
44
+
45
+ class Object
46
+ include Mocha::ObjectMethods
47
+ end
48
+
49
+ class String
50
+ include Mocha::StringMethods
51
+ end
52
+
53
+ class Array
54
+ include Mocha::ArrayMethods
55
+ end
56
+
57
+ class Hash
58
+ include Mocha::HashMethods
59
+ end
60
+
61
+ class Time
62
+ include Mocha::TimeMethods
63
+ end
64
+
65
+ class Date
66
+ include Mocha::DateMethods
67
+ end
@@ -0,0 +1,16 @@
1
+ require 'mocha/class_method'
2
+
3
+ module Mocha
4
+
5
+ class InstanceMethod < ClassMethod
6
+
7
+ def method_exists?(method)
8
+ return true if stubbee.public_methods(false).include?(method)
9
+ return true if stubbee.protected_methods(false).include?(method)
10
+ return true if stubbee.private_methods(false).include?(method)
11
+ return false
12
+ end
13
+
14
+ end
15
+
16
+ end
data/lib/mocha/is_a.rb ADDED
@@ -0,0 +1,9 @@
1
+ class Object
2
+
3
+ # :stopdoc:
4
+
5
+ alias_method :__is_a__, :is_a?
6
+
7
+ # :startdoc:
8
+
9
+ end
@@ -0,0 +1,15 @@
1
+ module Mocha
2
+
3
+ class Logger
4
+
5
+ def initialize(io)
6
+ @io = io
7
+ end
8
+
9
+ def warn(message)
10
+ @io.puts "WARNING: #{message}"
11
+ end
12
+
13
+ end
14
+
15
+ end
@@ -0,0 +1,13 @@
1
+ module Mocha
2
+
3
+ module ObjectMethods
4
+ def __metaclass__
5
+ class << self; self; end
6
+ end
7
+ end
8
+
9
+ end
10
+
11
+ class Object
12
+ include Mocha::ObjectMethods
13
+ end
@@ -0,0 +1,21 @@
1
+ module Mocha
2
+
3
+ class MethodMatcher
4
+
5
+ attr_reader :expected_method_name
6
+
7
+ def initialize(expected_method_name)
8
+ @expected_method_name = expected_method_name
9
+ end
10
+
11
+ def match?(actual_method_name)
12
+ @expected_method_name == actual_method_name
13
+ end
14
+
15
+ def mocha_inspect
16
+ "#{@expected_method_name}"
17
+ end
18
+
19
+ end
20
+
21
+ end