verborghs-state_machine 0.9.4

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 (89) hide show
  1. data/CHANGELOG.rdoc +360 -0
  2. data/LICENSE +20 -0
  3. data/README.rdoc +635 -0
  4. data/Rakefile +77 -0
  5. data/examples/AutoShop_state.png +0 -0
  6. data/examples/Car_state.png +0 -0
  7. data/examples/TrafficLight_state.png +0 -0
  8. data/examples/Vehicle_state.png +0 -0
  9. data/examples/auto_shop.rb +11 -0
  10. data/examples/car.rb +19 -0
  11. data/examples/merb-rest/controller.rb +51 -0
  12. data/examples/merb-rest/model.rb +28 -0
  13. data/examples/merb-rest/view_edit.html.erb +24 -0
  14. data/examples/merb-rest/view_index.html.erb +23 -0
  15. data/examples/merb-rest/view_new.html.erb +13 -0
  16. data/examples/merb-rest/view_show.html.erb +17 -0
  17. data/examples/rails-rest/controller.rb +43 -0
  18. data/examples/rails-rest/migration.rb +11 -0
  19. data/examples/rails-rest/model.rb +23 -0
  20. data/examples/rails-rest/view_edit.html.erb +25 -0
  21. data/examples/rails-rest/view_index.html.erb +23 -0
  22. data/examples/rails-rest/view_new.html.erb +14 -0
  23. data/examples/rails-rest/view_show.html.erb +17 -0
  24. data/examples/traffic_light.rb +7 -0
  25. data/examples/vehicle.rb +31 -0
  26. data/init.rb +1 -0
  27. data/lib/state_machine/assertions.rb +36 -0
  28. data/lib/state_machine/callback.rb +241 -0
  29. data/lib/state_machine/condition_proxy.rb +106 -0
  30. data/lib/state_machine/eval_helpers.rb +83 -0
  31. data/lib/state_machine/event.rb +267 -0
  32. data/lib/state_machine/event_collection.rb +122 -0
  33. data/lib/state_machine/extensions.rb +149 -0
  34. data/lib/state_machine/guard.rb +230 -0
  35. data/lib/state_machine/initializers/merb.rb +1 -0
  36. data/lib/state_machine/initializers/rails.rb +5 -0
  37. data/lib/state_machine/initializers.rb +4 -0
  38. data/lib/state_machine/integrations/active_model/locale.rb +11 -0
  39. data/lib/state_machine/integrations/active_model/observer.rb +45 -0
  40. data/lib/state_machine/integrations/active_model.rb +445 -0
  41. data/lib/state_machine/integrations/active_record/locale.rb +20 -0
  42. data/lib/state_machine/integrations/active_record.rb +522 -0
  43. data/lib/state_machine/integrations/data_mapper/observer.rb +175 -0
  44. data/lib/state_machine/integrations/data_mapper.rb +379 -0
  45. data/lib/state_machine/integrations/mongo_mapper.rb +309 -0
  46. data/lib/state_machine/integrations/sequel.rb +356 -0
  47. data/lib/state_machine/integrations.rb +83 -0
  48. data/lib/state_machine/machine.rb +1645 -0
  49. data/lib/state_machine/machine_collection.rb +64 -0
  50. data/lib/state_machine/matcher.rb +123 -0
  51. data/lib/state_machine/matcher_helpers.rb +54 -0
  52. data/lib/state_machine/node_collection.rb +152 -0
  53. data/lib/state_machine/state.rb +260 -0
  54. data/lib/state_machine/state_collection.rb +112 -0
  55. data/lib/state_machine/transition.rb +399 -0
  56. data/lib/state_machine/transition_collection.rb +244 -0
  57. data/lib/state_machine.rb +421 -0
  58. data/lib/tasks/state_machine.rake +1 -0
  59. data/lib/tasks/state_machine.rb +27 -0
  60. data/test/files/en.yml +9 -0
  61. data/test/files/switch.rb +11 -0
  62. data/test/functional/state_machine_test.rb +980 -0
  63. data/test/test_helper.rb +4 -0
  64. data/test/unit/assertions_test.rb +40 -0
  65. data/test/unit/callback_test.rb +728 -0
  66. data/test/unit/condition_proxy_test.rb +328 -0
  67. data/test/unit/eval_helpers_test.rb +222 -0
  68. data/test/unit/event_collection_test.rb +324 -0
  69. data/test/unit/event_test.rb +795 -0
  70. data/test/unit/guard_test.rb +909 -0
  71. data/test/unit/integrations/active_model_test.rb +956 -0
  72. data/test/unit/integrations/active_record_test.rb +1918 -0
  73. data/test/unit/integrations/data_mapper_test.rb +1814 -0
  74. data/test/unit/integrations/mongo_mapper_test.rb +1382 -0
  75. data/test/unit/integrations/sequel_test.rb +1492 -0
  76. data/test/unit/integrations_test.rb +50 -0
  77. data/test/unit/invalid_event_test.rb +7 -0
  78. data/test/unit/invalid_transition_test.rb +7 -0
  79. data/test/unit/machine_collection_test.rb +565 -0
  80. data/test/unit/machine_test.rb +2349 -0
  81. data/test/unit/matcher_helpers_test.rb +37 -0
  82. data/test/unit/matcher_test.rb +155 -0
  83. data/test/unit/node_collection_test.rb +207 -0
  84. data/test/unit/state_collection_test.rb +280 -0
  85. data/test/unit/state_machine_test.rb +31 -0
  86. data/test/unit/state_test.rb +848 -0
  87. data/test/unit/transition_collection_test.rb +2098 -0
  88. data/test/unit/transition_test.rb +1384 -0
  89. metadata +176 -0
@@ -0,0 +1,728 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../test_helper')
2
+
3
+ class CallbackTest < Test::Unit::TestCase
4
+ def test_should_raise_exception_if_invalid_type_specified
5
+ exception = assert_raise(ArgumentError) { StateMachine::Callback.new(:invalid) {} }
6
+ assert_equal 'Type must be :before, :after, or :around', exception.message
7
+ end
8
+
9
+ def test_should_not_raise_exception_if_using_before_type
10
+ assert_nothing_raised { StateMachine::Callback.new(:before) {} }
11
+ end
12
+
13
+ def test_should_not_raise_exception_if_using_after_type
14
+ assert_nothing_raised { StateMachine::Callback.new(:after) {} }
15
+ end
16
+
17
+ def test_should_not_raise_exception_if_using_around_type
18
+ assert_nothing_raised { StateMachine::Callback.new(:around) {} }
19
+ end
20
+
21
+ def test_should_raise_exception_if_no_methods_specified
22
+ exception = assert_raise(ArgumentError) { StateMachine::Callback.new(:before) }
23
+ assert_equal 'Method(s) for callback must be specified', exception.message
24
+ end
25
+
26
+ def test_should_not_raise_exception_if_method_specified_in_do_option
27
+ assert_nothing_raised { StateMachine::Callback.new(:before, :do => :run) }
28
+ end
29
+
30
+ def test_should_not_raise_exception_if_method_specified_as_argument
31
+ assert_nothing_raised { StateMachine::Callback.new(:before, :run) }
32
+ end
33
+
34
+ def test_should_not_raise_exception_if_method_specified_as_block
35
+ assert_nothing_raised { StateMachine::Callback.new(:before, :run) {} }
36
+ end
37
+
38
+ def test_should_not_raise_exception_if_implicit_option_specified
39
+ assert_nothing_raised { StateMachine::Callback.new(:before, :do => :run, :invalid => :valid) }
40
+ end
41
+
42
+ def test_should_not_bind_to_objects
43
+ assert !StateMachine::Callback.bind_to_object
44
+ end
45
+
46
+ def test_should_not_have_a_terminator
47
+ assert_nil StateMachine::Callback.terminator
48
+ end
49
+ end
50
+
51
+ class CallbackByDefaultTest < Test::Unit::TestCase
52
+ def setup
53
+ @callback = StateMachine::Callback.new(:before) {}
54
+ end
55
+
56
+ def test_should_have_type
57
+ assert_equal :before, @callback.type
58
+ end
59
+
60
+ def test_should_not_have_a_terminator
61
+ assert_nil @callback.terminator
62
+ end
63
+
64
+ def test_should_have_a_guard_with_all_matcher_requirements
65
+ assert_equal StateMachine::AllMatcher.instance, @callback.guard.event_requirement
66
+ assert_equal StateMachine::AllMatcher.instance, @callback.guard.state_requirements.first[:from]
67
+ assert_equal StateMachine::AllMatcher.instance, @callback.guard.state_requirements.first[:to]
68
+ end
69
+
70
+ def test_should_not_have_any_known_states
71
+ assert_equal [], @callback.known_states
72
+ end
73
+ end
74
+
75
+ class CallbackWithMethodArgumentTest < Test::Unit::TestCase
76
+ def setup
77
+ @callback = StateMachine::Callback.new(:before, lambda {|*args| @args = args})
78
+
79
+ @object = Object.new
80
+ @result = @callback.call(@object)
81
+ end
82
+
83
+ def test_should_be_successful
84
+ assert @result
85
+ end
86
+
87
+ def test_should_call_with_empty_context
88
+ assert_equal [@object], @args
89
+ end
90
+ end
91
+
92
+ class CallbackWithMultipleMethodArgumentsTest < Test::Unit::TestCase
93
+ def setup
94
+ @callback = StateMachine::Callback.new(:before, :run_1, :run_2)
95
+
96
+ class << @object = Object.new
97
+ attr_accessor :callbacks
98
+
99
+ def run_1
100
+ (@callbacks ||= []) << :run_1
101
+ end
102
+
103
+ def run_2
104
+ (@callbacks ||= []) << :run_2
105
+ end
106
+ end
107
+
108
+ @result = @callback.call(@object)
109
+ end
110
+
111
+ def test_should_be_successful
112
+ assert @result
113
+ end
114
+
115
+ def test_should_call_each_callback_in_order
116
+ assert_equal [:run_1, :run_2], @object.callbacks
117
+ end
118
+ end
119
+
120
+ class CallbackWithDoMethodTest < Test::Unit::TestCase
121
+ def setup
122
+ @callback = StateMachine::Callback.new(:before, :do => lambda {|*args| @args = args})
123
+
124
+ @object = Object.new
125
+ @result = @callback.call(@object)
126
+ end
127
+
128
+ def test_should_be_successful
129
+ assert @result
130
+ end
131
+
132
+ def test_should_call_with_empty_context
133
+ assert_equal [@object], @args
134
+ end
135
+ end
136
+
137
+ class CallbackWithMultipleDoMethodsTest < Test::Unit::TestCase
138
+ def setup
139
+ @callback = StateMachine::Callback.new(:before, :do => [:run_1, :run_2])
140
+
141
+ class << @object = Object.new
142
+ attr_accessor :callbacks
143
+
144
+ def run_1
145
+ (@callbacks ||= []) << :run_1
146
+ end
147
+
148
+ def run_2
149
+ (@callbacks ||= []) << :run_2
150
+ end
151
+ end
152
+
153
+ @result = @callback.call(@object)
154
+ end
155
+
156
+ def test_should_be_successful
157
+ assert @result
158
+ end
159
+
160
+ def test_should_call_each_callback_in_order
161
+ assert_equal [:run_1, :run_2], @object.callbacks
162
+ end
163
+ end
164
+
165
+ class CallbackWithBlockTest < Test::Unit::TestCase
166
+ def setup
167
+ @callback = StateMachine::Callback.new(:before) do |*args|
168
+ @args = args
169
+ end
170
+
171
+ @object = Object.new
172
+ @result = @callback.call(@object)
173
+ end
174
+
175
+ def test_should_be_successful
176
+ assert @result
177
+ end
178
+
179
+ def test_should_call_with_empty_context
180
+ assert_equal [@object], @args
181
+ end
182
+ end
183
+
184
+ class CallbackWithMixedMethodsTest < Test::Unit::TestCase
185
+ def setup
186
+ @callback = StateMachine::Callback.new(:before, :run_argument, :do => :run_do) do |object|
187
+ object.callbacks << :block
188
+ end
189
+
190
+ class << @object = Object.new
191
+ attr_accessor :callbacks
192
+
193
+ def run_argument
194
+ (@callbacks ||= []) << :argument
195
+ end
196
+
197
+ def run_do
198
+ (@callbacks ||= []) << :do
199
+ end
200
+ end
201
+
202
+ @result = @callback.call(@object)
203
+ end
204
+
205
+ def test_should_be_successful
206
+ assert @result
207
+ end
208
+
209
+ def test_should_call_each_callback_in_order
210
+ assert_equal [:argument, :do, :block], @object.callbacks
211
+ end
212
+ end
213
+
214
+ class CallbackWithExplicitRequirementsTest < Test::Unit::TestCase
215
+ def setup
216
+ @object = Object.new
217
+ @callback = StateMachine::Callback.new(:before, :from => :parked, :to => :idling, :on => :ignite, :do => lambda {})
218
+ end
219
+
220
+ def test_should_call_with_empty_context
221
+ assert @callback.call(@object, {})
222
+ end
223
+
224
+ def test_should_not_call_if_from_not_included
225
+ assert !@callback.call(@object, :from => :idling)
226
+ end
227
+
228
+ def test_should_not_call_if_to_not_included
229
+ assert !@callback.call(@object, :to => :parked)
230
+ end
231
+
232
+ def test_should_not_call_if_on_not_included
233
+ assert !@callback.call(@object, :on => :park)
234
+ end
235
+
236
+ def test_should_call_if_all_requirements_met
237
+ assert @callback.call(@object, :from => :parked, :to => :idling, :on => :ignite)
238
+ end
239
+
240
+ def test_should_include_in_known_states
241
+ assert_equal [:parked, :idling], @callback.known_states
242
+ end
243
+ end
244
+
245
+ class CallbackWithImplicitRequirementsTest < Test::Unit::TestCase
246
+ def setup
247
+ @object = Object.new
248
+ @callback = StateMachine::Callback.new(:before, :parked => :idling, :on => :ignite, :do => lambda {})
249
+ end
250
+
251
+ def test_should_call_with_empty_context
252
+ assert @callback.call(@object, {})
253
+ end
254
+
255
+ def test_should_not_call_if_from_not_included
256
+ assert !@callback.call(@object, :from => :idling)
257
+ end
258
+
259
+ def test_should_not_call_if_to_not_included
260
+ assert !@callback.call(@object, :to => :parked)
261
+ end
262
+
263
+ def test_should_not_call_if_on_not_included
264
+ assert !@callback.call(@object, :on => :park)
265
+ end
266
+
267
+ def test_should_call_if_all_requirements_met
268
+ assert @callback.call(@object, :from => :parked, :to => :idling, :on => :ignite)
269
+ end
270
+
271
+ def test_should_include_in_known_states
272
+ assert_equal [:parked, :idling], @callback.known_states
273
+ end
274
+ end
275
+
276
+ class CallbackWithIfConditionTest < Test::Unit::TestCase
277
+ def setup
278
+ @object = Object.new
279
+ end
280
+
281
+ def test_should_call_if_true
282
+ callback = StateMachine::Callback.new(:before, :if => lambda {true}, :do => lambda {})
283
+ assert callback.call(@object)
284
+ end
285
+
286
+ def test_should_not_call_if_false
287
+ callback = StateMachine::Callback.new(:before, :if => lambda {false}, :do => lambda {})
288
+ assert !callback.call(@object)
289
+ end
290
+ end
291
+
292
+ class CallbackWithUnlessConditionTest < Test::Unit::TestCase
293
+ def setup
294
+ @object = Object.new
295
+ end
296
+
297
+ def test_should_call_if_false
298
+ callback = StateMachine::Callback.new(:before, :unless => lambda {false}, :do => lambda {})
299
+ assert callback.call(@object)
300
+ end
301
+
302
+ def test_should_not_call_if_true
303
+ callback = StateMachine::Callback.new(:before, :unless => lambda {true}, :do => lambda {})
304
+ assert !callback.call(@object)
305
+ end
306
+ end
307
+
308
+ class CallbackWithoutTerminatorTest < Test::Unit::TestCase
309
+ def setup
310
+ @object = Object.new
311
+ end
312
+
313
+ def test_should_not_halt_if_result_is_false
314
+ callback = StateMachine::Callback.new(:before, :do => lambda {false}, :terminator => nil)
315
+ assert_nothing_thrown { callback.call(@object) }
316
+ end
317
+ end
318
+
319
+ class CallbackWithTerminatorTest < Test::Unit::TestCase
320
+ def setup
321
+ @object = Object.new
322
+ end
323
+
324
+ def test_should_not_halt_if_terminator_does_not_match
325
+ callback = StateMachine::Callback.new(:before, :do => lambda {false}, :terminator => lambda {|result| result == true})
326
+ assert_nothing_thrown { callback.call(@object) }
327
+ end
328
+
329
+ def test_should_halt_if_terminator_matches
330
+ callback = StateMachine::Callback.new(:before, :do => lambda {false}, :terminator => lambda {|result| result == false})
331
+ assert_throws(:halt) { callback.call(@object) }
332
+ end
333
+
334
+ def test_should_halt_if_terminator_matches_any_method
335
+ callback = StateMachine::Callback.new(:before, :do => [lambda {true}, lambda {false}], :terminator => lambda {|result| result == false})
336
+ assert_throws(:halt) { callback.call(@object) }
337
+ end
338
+ end
339
+
340
+ class CallbackWithoutArgumentsTest < Test::Unit::TestCase
341
+ def setup
342
+ @callback = StateMachine::Callback.new(:before, :do => lambda {|object| @arg = object})
343
+
344
+ @object = Object.new
345
+ @callback.call(@object, {}, 1, 2, 3)
346
+ end
347
+
348
+ def test_should_call_method_with_object_as_argument
349
+ assert_equal @object, @arg
350
+ end
351
+ end
352
+
353
+ class CallbackWithArgumentsTest < Test::Unit::TestCase
354
+ def setup
355
+ @callback = StateMachine::Callback.new(:before, :do => lambda {|*args| @args = args})
356
+
357
+ @object = Object.new
358
+ @callback.call(@object, {}, 1, 2, 3)
359
+ end
360
+
361
+ def test_should_call_method_with_all_arguments
362
+ assert_equal [@object, 1, 2, 3], @args
363
+ end
364
+ end
365
+
366
+ class CallbackWithUnboundMethodTest < Test::Unit::TestCase
367
+ def setup
368
+ @callback = StateMachine::Callback.new(:before, :do => lambda {|*args| @context = args.unshift(self)})
369
+
370
+ @object = Object.new
371
+ @callback.call(@object, {}, 1, 2, 3)
372
+ end
373
+
374
+ def test_should_call_method_outside_the_context_of_the_object
375
+ assert_equal [self, @object, 1, 2, 3], @context
376
+ end
377
+ end
378
+
379
+ class CallbackWithBoundMethodTest < Test::Unit::TestCase
380
+ def setup
381
+ @object = Object.new
382
+ end
383
+
384
+ def test_should_call_method_within_the_context_of_the_object_for_block_methods
385
+ context = nil
386
+ callback = StateMachine::Callback.new(:before, :do => lambda {|*args| context = [self] + args}, :bind_to_object => true)
387
+ callback.call(@object, {}, 1, 2, 3)
388
+
389
+ assert_equal [@object, 1, 2, 3], context
390
+ end
391
+
392
+ def test_should_ignore_option_for_symbolic_methods
393
+ class << @object
394
+ attr_reader :context
395
+
396
+ def after_ignite(*args)
397
+ @context = args
398
+ end
399
+ end
400
+
401
+ callback = StateMachine::Callback.new(:before, :do => :after_ignite, :bind_to_object => true)
402
+ callback.call(@object)
403
+
404
+ assert_equal [], @object.context
405
+ end
406
+
407
+ def test_should_ignore_option_for_string_methods
408
+ callback = StateMachine::Callback.new(:before, :do => '[1, 2, 3]', :bind_to_object => true)
409
+ assert callback.call(@object)
410
+ end
411
+ end
412
+
413
+ class CallbackWithMultipleBoundMethodsTest < Test::Unit::TestCase
414
+ def setup
415
+ @object = Object.new
416
+
417
+ first_context = nil
418
+ second_context = nil
419
+
420
+ @callback = StateMachine::Callback.new(:before, :do => [lambda {first_context = self}, lambda {second_context = self}], :bind_to_object => true)
421
+ @callback.call(@object)
422
+
423
+ @first_context = first_context
424
+ @second_context = second_context
425
+ end
426
+
427
+ def test_should_call_each_method_within_the_context_of_the_object
428
+ assert_equal @object, @first_context
429
+ assert_equal @object, @second_context
430
+ end
431
+ end
432
+
433
+ class CallbackWithApplicationBoundObjectTest < Test::Unit::TestCase
434
+ def setup
435
+ @original_bind_to_object = StateMachine::Callback.bind_to_object
436
+ StateMachine::Callback.bind_to_object = true
437
+
438
+ context = nil
439
+ @callback = StateMachine::Callback.new(:before, :do => lambda {|*args| context = self})
440
+
441
+ @object = Object.new
442
+ @callback.call(@object)
443
+ @context = context
444
+ end
445
+
446
+ def test_should_call_method_within_the_context_of_the_object
447
+ assert_equal @object, @context
448
+ end
449
+
450
+ def teardown
451
+ StateMachine::Callback.bind_to_object = @original_bind_to_object
452
+ end
453
+ end
454
+
455
+ class CallbackWithBoundMethodAndArgumentsTest < Test::Unit::TestCase
456
+ def setup
457
+ @object = Object.new
458
+ end
459
+
460
+ def test_should_include_single_argument_if_specified
461
+ context = nil
462
+ callback = StateMachine::Callback.new(:before, :do => lambda {|arg1| context = [arg1]}, :bind_to_object => true)
463
+ callback.call(@object, {}, 1)
464
+ assert_equal [1], context
465
+ end
466
+
467
+ def test_should_include_multiple_arguments_if_specified
468
+ context = nil
469
+ callback = StateMachine::Callback.new(:before, :do => lambda {|arg1, arg2, arg3| context = [arg1, arg2, arg3]}, :bind_to_object => true)
470
+ callback.call(@object, {}, 1, 2, 3)
471
+ assert_equal [1, 2, 3], context
472
+ end
473
+
474
+ def test_should_include_arguments_if_splat_used
475
+ context = nil
476
+ callback = StateMachine::Callback.new(:before, :do => lambda {|*args| context = args}, :bind_to_object => true)
477
+ callback.call(@object, {}, 1, 2, 3)
478
+ assert_equal [1, 2, 3], context
479
+ end
480
+ end
481
+
482
+ class CallbackWithApplicationTerminatorTest < Test::Unit::TestCase
483
+ def setup
484
+ @original_terminator = StateMachine::Callback.bind_to_object
485
+ StateMachine::Callback.terminator = lambda {|result| result == false}
486
+
487
+ @object = Object.new
488
+ end
489
+
490
+ def test_should_not_halt_if_terminator_does_not_match
491
+ callback = StateMachine::Callback.new(:before, :do => lambda {true})
492
+ assert_nothing_thrown { callback.call(@object) }
493
+ end
494
+
495
+ def test_should_halt_if_terminator_matches
496
+ callback = StateMachine::Callback.new(:before, :do => lambda {false})
497
+ assert_throws(:halt) { callback.call(@object) }
498
+ end
499
+
500
+ def teardown
501
+ StateMachine::Callback.bind_to_object = @original_bind_to_object
502
+ end
503
+ end
504
+
505
+ class CallbackWithAroundTypeAndBlockTest < Test::Unit::TestCase
506
+ def setup
507
+ @object = Object.new
508
+ @callbacks = []
509
+ end
510
+
511
+ def test_should_evaluate_before_without_after
512
+ callback = StateMachine::Callback.new(:around, lambda {|*args| block = args.pop; @args = args; block.call})
513
+ assert callback.call(@object)
514
+ assert_equal [@object], @args
515
+ end
516
+
517
+ def test_should_evaluate_after_without_before
518
+ callback = StateMachine::Callback.new(:around, lambda {|*args| block = args.pop; block.call; @args = args})
519
+ assert callback.call(@object)
520
+ assert_equal [@object], @args
521
+ end
522
+
523
+ def test_should_halt_if_not_yielded
524
+ callback = StateMachine::Callback.new(:around, lambda {|block|})
525
+ assert_throws(:halt) { callback.call(@object) }
526
+ end
527
+
528
+ def test_should_call_block_after_before
529
+ callback = StateMachine::Callback.new(:around, lambda {|block| @callbacks << :before; block.call})
530
+ assert callback.call(@object) { @callbacks << :block }
531
+ assert_equal [:before, :block], @callbacks
532
+ end
533
+
534
+ def test_should_call_block_before_after
535
+ @callbacks = []
536
+ callback = StateMachine::Callback.new(:around, lambda {|block| block.call; @callbacks << :after})
537
+ assert callback.call(@object) { @callbacks << :block }
538
+ assert_equal [:block, :after], @callbacks
539
+ end
540
+
541
+ def test_should_halt_if_block_halts
542
+ callback = StateMachine::Callback.new(:around, lambda {|block| block.call; @callbacks << :after})
543
+ assert_throws(:halt) { callback.call(@object) { throw :halt } }
544
+ assert_equal [], @callbacks
545
+ end
546
+ end
547
+
548
+ class CallbackWithAroundTypeAndMultipleMethodsTest < Test::Unit::TestCase
549
+ def setup
550
+ @callback = StateMachine::Callback.new(:around, :run_1, :run_2)
551
+
552
+ class << @object = Object.new
553
+ attr_accessor :before_callbacks
554
+ attr_accessor :after_callbacks
555
+
556
+ def run_1
557
+ (@before_callbacks ||= []) << :run_1
558
+ yield
559
+ (@after_callbacks ||= []) << :run_1
560
+ end
561
+
562
+ def run_2
563
+ (@before_callbacks ||= []) << :run_2
564
+ yield
565
+ (@after_callbacks ||= []) << :run_2
566
+ end
567
+ end
568
+ end
569
+
570
+ def test_should_succeed
571
+ assert @callback.call(@object)
572
+ end
573
+
574
+ def test_should_evaluate_before_callbacks_in_order
575
+ @callback.call(@object)
576
+ assert_equal [:run_1, :run_2], @object.before_callbacks
577
+ end
578
+
579
+ def test_should_evaluate_after_callbacks_in_reverse_order
580
+ @callback.call(@object)
581
+ assert_equal [:run_2, :run_1], @object.after_callbacks
582
+ end
583
+
584
+ def test_should_call_block_after_before_callbacks
585
+ @callback.call(@object) { (@object.before_callbacks ||= []) << :block }
586
+ assert_equal [:run_1, :run_2, :block], @object.before_callbacks
587
+ end
588
+
589
+ def test_should_call_block_before_after_callbacks
590
+ @callback.call(@object) { (@object.after_callbacks ||= []) << :block }
591
+ assert_equal [:block, :run_2, :run_1], @object.after_callbacks
592
+ end
593
+
594
+ def test_should_halt_if_first_doesnt_yield
595
+ class << @object
596
+ def run_1
597
+ (@before_callbacks ||= []) << :run_1
598
+ end
599
+ end
600
+
601
+ catch(:halt) do
602
+ @callback.call(@object) { (@object.before_callbacks ||= []) << :block }
603
+ end
604
+
605
+ assert_equal [:run_1], @object.before_callbacks
606
+ assert_nil @object.after_callbacks
607
+ end
608
+
609
+ def test_should_halt_if_last_doesnt_yield
610
+ class << @object
611
+ def run_2
612
+ (@before_callbacks ||= []) << :run_2
613
+ end
614
+ end
615
+
616
+ catch(:halt) { @callback.call(@object) }
617
+ assert_equal [:run_1, :run_2], @object.before_callbacks
618
+ assert_nil @object.after_callbacks
619
+ end
620
+
621
+ def test_should_not_evaluate_further_methods_if_after_halts
622
+ class << @object
623
+ def run_2
624
+ (@before_callbacks ||= []) << :run_2
625
+ yield
626
+ (@after_callbacks ||= []) << :run_2
627
+ throw :halt
628
+ end
629
+ end
630
+
631
+ catch(:halt) { @callback.call(@object) }
632
+ assert_equal [:run_1, :run_2], @object.before_callbacks
633
+ assert_equal [:run_2], @object.after_callbacks
634
+ end
635
+ end
636
+
637
+ class CallbackWithAroundTypeAndArgumentsTest < Test::Unit::TestCase
638
+ def setup
639
+ @object = Object.new
640
+ end
641
+
642
+ def test_should_include_object_if_specified
643
+ callback = StateMachine::Callback.new(:around, lambda {|object, block| @args = [object]; block.call})
644
+ callback.call(@object)
645
+ assert_equal [@object], @args
646
+ end
647
+
648
+ def test_should_include_arguments_if_specified
649
+ callback = StateMachine::Callback.new(:around, lambda {|object, arg1, arg2, arg3, block| @args = [object, arg1, arg2, arg3]; block.call})
650
+ callback.call(@object, {}, 1, 2, 3)
651
+ assert_equal [@object, 1, 2, 3], @args
652
+ end
653
+
654
+ def test_should_include_arguments_if_splat_used
655
+ callback = StateMachine::Callback.new(:around, lambda {|*args| block = args.pop; @args = args; block.call})
656
+ callback.call(@object, {}, 1, 2, 3)
657
+ assert_equal [@object, 1, 2, 3], @args
658
+ end
659
+ end
660
+
661
+ class CallbackWithAroundTypeAndTerminatorTest < Test::Unit::TestCase
662
+ def setup
663
+ @object = Object.new
664
+ end
665
+
666
+ def test_should_not_halt_if_terminator_does_not_match
667
+ callback = StateMachine::Callback.new(:around, :do => lambda {|block| block.call(false); false}, :terminator => lambda {|result| result == true})
668
+ assert_nothing_thrown { callback.call(@object) }
669
+ end
670
+
671
+ def test_should_not_halt_if_terminator_matches
672
+ callback = StateMachine::Callback.new(:around, :do => lambda {|block| block.call(false); false}, :terminator => lambda {|result| result == false})
673
+ assert_nothing_thrown { callback.call(@object) }
674
+ end
675
+ end
676
+
677
+ class CallbackWithAroundTypeAndBoundMethodTest < Test::Unit::TestCase
678
+ def setup
679
+ @object = Object.new
680
+ end
681
+
682
+ def test_should_call_method_within_the_context_of_the_object
683
+ context = nil
684
+ callback = StateMachine::Callback.new(:around, :do => lambda {|block| context = self; block.call}, :bind_to_object => true)
685
+ callback.call(@object, {}, 1, 2, 3)
686
+
687
+ assert_equal @object, context
688
+ end
689
+
690
+ def test_should_include_arguments_if_specified
691
+ context = nil
692
+ callback = StateMachine::Callback.new(:around, :do => lambda {|*args| block = args.pop; context = args; block.call}, :bind_to_object => true)
693
+ callback.call(@object, {}, 1, 2, 3)
694
+
695
+ assert_equal [1, 2, 3], context
696
+ end
697
+ end
698
+
699
+ class CallbackSuccessMatcherTest < Test::Unit::TestCase
700
+ def setup
701
+ @object = Object.new
702
+ end
703
+
704
+ def test_should_match_if_not_specified
705
+ callback = StateMachine::Callback.new(:before) {}
706
+ assert callback.matches_success?(true)
707
+ end
708
+
709
+ def test_should_match_if_true_and_not_including_failures
710
+ callback = StateMachine::Callback.new(:before, :include_failures => false) {}
711
+ assert callback.matches_success?(true)
712
+ end
713
+
714
+ def test_should_match_if_true_and_including_failures
715
+ callback = StateMachine::Callback.new(:before, :include_failures => true) {}
716
+ assert callback.matches_success?(true)
717
+ end
718
+
719
+ def test_should_not_match_if_false_and_not_including_failures
720
+ callback = StateMachine::Callback.new(:before, :include_failures => false) {}
721
+ assert !callback.matches_success?(false)
722
+ end
723
+
724
+ def test_Should_match_if_false_and_including_failures
725
+ callback = StateMachine::Callback.new(:before, :include_failures => true) {}
726
+ assert callback.matches_success?(false)
727
+ end
728
+ end