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,1384 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../test_helper')
2
+
3
+ class TransitionTest < Test::Unit::TestCase
4
+ def setup
5
+ @klass = Class.new
6
+ @machine = StateMachine::Machine.new(@klass)
7
+ @machine.state :parked, :idling
8
+ @machine.event :ignite
9
+
10
+ @object = @klass.new
11
+ @object.state = 'parked'
12
+
13
+ @transition = StateMachine::Transition.new(@object, @machine, :ignite, :parked, :idling)
14
+ end
15
+
16
+ def test_should_have_an_object
17
+ assert_equal @object, @transition.object
18
+ end
19
+
20
+ def test_should_have_a_machine
21
+ assert_equal @machine, @transition.machine
22
+ end
23
+
24
+ def test_should_have_an_event
25
+ assert_equal :ignite, @transition.event
26
+ end
27
+
28
+ def test_should_have_a_qualified_event
29
+ assert_equal :ignite, @transition.qualified_event
30
+ end
31
+
32
+ def test_should_have_a_human_event
33
+ assert_equal 'ignite', @transition.human_event
34
+ end
35
+
36
+ def test_should_have_a_from_value
37
+ assert_equal 'parked', @transition.from
38
+ end
39
+
40
+ def test_should_have_a_from_name
41
+ assert_equal :parked, @transition.from_name
42
+ end
43
+
44
+ def test_should_have_a_qualified_from_name
45
+ assert_equal :parked, @transition.qualified_from_name
46
+ end
47
+
48
+ def test_should_have_a_human_from_name
49
+ assert_equal 'parked', @transition.human_from_name
50
+ end
51
+
52
+ def test_should_have_a_to_value
53
+ assert_equal 'idling', @transition.to
54
+ end
55
+
56
+ def test_should_have_a_to_name
57
+ assert_equal :idling, @transition.to_name
58
+ end
59
+
60
+ def test_should_have_a_qualified_to_name
61
+ assert_equal :idling, @transition.qualified_to_name
62
+ end
63
+
64
+ def test_should_have_a_human_to_name
65
+ assert_equal 'idling', @transition.human_to_name
66
+ end
67
+
68
+ def test_should_have_an_attribute
69
+ assert_equal :state, @transition.attribute
70
+ end
71
+
72
+ def test_should_not_have_an_action
73
+ assert_nil @transition.action
74
+ end
75
+
76
+ def test_should_not_be_transient
77
+ assert_equal false, @transition.transient?
78
+ end
79
+
80
+ def test_should_generate_attributes
81
+ expected = {:object => @object, :attribute => :state, :event => :ignite, :from => 'parked', :to => 'idling'}
82
+ assert_equal expected, @transition.attributes
83
+ end
84
+
85
+ def test_should_have_empty_args
86
+ assert_equal [], @transition.args
87
+ end
88
+
89
+ def test_should_not_have_a_result
90
+ assert_nil @transition.result
91
+ end
92
+
93
+ def test_should_use_pretty_inspect
94
+ assert_equal '#<StateMachine::Transition attribute=:state event=:ignite from="parked" from_name=:parked to="idling" to_name=:idling>', @transition.inspect
95
+ end
96
+ end
97
+
98
+ class TransitionWithInvalidNodesTest < Test::Unit::TestCase
99
+ def setup
100
+ @klass = Class.new
101
+ @machine = StateMachine::Machine.new(@klass)
102
+ @machine.state :parked, :idling
103
+ @machine.event :ignite
104
+
105
+ @object = @klass.new
106
+ @object.state = 'parked'
107
+ end
108
+
109
+ def test_should_raise_exception_without_event
110
+ assert_raise(IndexError) { StateMachine::Transition.new(@object, @machine, nil, :parked, :idling) }
111
+ end
112
+
113
+ def test_should_raise_exception_with_invalid_event
114
+ assert_raise(IndexError) { StateMachine::Transition.new(@object, @machine, :invalid, :parked, :idling) }
115
+ end
116
+
117
+ def test_should_raise_exception_with_invalid_from_state
118
+ assert_raise(IndexError) { StateMachine::Transition.new(@object, @machine, :ignite, :invalid, :idling) }
119
+ end
120
+
121
+ def test_should_raise_exception_with_invalid_to_state
122
+ assert_raise(IndexError) { StateMachine::Transition.new(@object, @machine, :ignite, :parked, :invalid) }
123
+ end
124
+ end
125
+
126
+ class TransitionWithDynamicToValueTest < Test::Unit::TestCase
127
+ def setup
128
+ @klass = Class.new
129
+ @machine = StateMachine::Machine.new(@klass)
130
+ @machine.state :parked
131
+ @machine.state :idling, :value => lambda {1}
132
+ @machine.event :ignite
133
+
134
+ @object = @klass.new
135
+ @object.state = 'parked'
136
+ @transition = StateMachine::Transition.new(@object, @machine, :ignite, :parked, :idling)
137
+ end
138
+
139
+ def test_should_evaluate_to_value
140
+ assert_equal 1, @transition.to
141
+ end
142
+ end
143
+
144
+ class TransitionLoopbackTest < Test::Unit::TestCase
145
+ def setup
146
+ @klass = Class.new
147
+ @machine = StateMachine::Machine.new(@klass)
148
+ @machine.state :parked
149
+ @machine.event :park
150
+
151
+ @object = @klass.new
152
+ @object.state = 'parked'
153
+ @transition = StateMachine::Transition.new(@object, @machine, :park, :parked, :parked)
154
+ end
155
+
156
+ def test_should_be_loopback
157
+ assert @transition.loopback?
158
+ end
159
+ end
160
+
161
+ class TransitionWithDifferentStatesTest < Test::Unit::TestCase
162
+ def setup
163
+ @klass = Class.new
164
+ @machine = StateMachine::Machine.new(@klass)
165
+ @machine.state :parked, :idling
166
+ @machine.event :ignite
167
+
168
+ @object = @klass.new
169
+ @object.state = 'parked'
170
+ @transition = StateMachine::Transition.new(@object, @machine, :ignite, :parked, :idling)
171
+ end
172
+
173
+ def test_should_not_be_loopback
174
+ assert !@transition.loopback?
175
+ end
176
+ end
177
+
178
+ class TransitionWithNamespaceTest < Test::Unit::TestCase
179
+ def setup
180
+ @klass = Class.new
181
+ @machine = StateMachine::Machine.new(@klass, :namespace => 'alarm')
182
+ @machine.state :off, :active
183
+ @machine.event :activate
184
+
185
+ @object = @klass.new
186
+ @object.state = 'off'
187
+
188
+ @transition = StateMachine::Transition.new(@object, @machine, :activate, :off, :active)
189
+ end
190
+
191
+ def test_should_have_an_event
192
+ assert_equal :activate, @transition.event
193
+ end
194
+
195
+ def test_should_have_a_qualified_event
196
+ assert_equal :activate_alarm, @transition.qualified_event
197
+ end
198
+
199
+ def test_should_have_a_from_name
200
+ assert_equal :off, @transition.from_name
201
+ end
202
+
203
+ def test_should_have_a_qualified_from_name
204
+ assert_equal :alarm_off, @transition.qualified_from_name
205
+ end
206
+
207
+ def test_should_have_a_human_from_name
208
+ assert_equal 'off', @transition.human_from_name
209
+ end
210
+
211
+ def test_should_have_a_to_name
212
+ assert_equal :active, @transition.to_name
213
+ end
214
+
215
+ def test_should_have_a_qualified_to_name
216
+ assert_equal :alarm_active, @transition.qualified_to_name
217
+ end
218
+
219
+ def test_should_have_a_human_to_name
220
+ assert_equal 'active', @transition.human_to_name
221
+ end
222
+ end
223
+
224
+ class TransitionWithCustomMachineAttributeTest < Test::Unit::TestCase
225
+ def setup
226
+ @klass = Class.new
227
+ @machine = StateMachine::Machine.new(@klass, :state, :attribute => :state_id)
228
+ @machine.state :off, :value => 1
229
+ @machine.state :active, :value => 2
230
+ @machine.event :activate
231
+
232
+ @object = @klass.new
233
+ @object.state_id = 1
234
+
235
+ @transition = StateMachine::Transition.new(@object, @machine, :activate, :off, :active)
236
+ end
237
+
238
+ def test_should_persist
239
+ @transition.persist
240
+ assert_equal 2, @object.state_id
241
+ end
242
+
243
+ def test_should_rollback
244
+ @object.state_id = 2
245
+ @transition.rollback
246
+
247
+ assert_equal 1, @object.state_id
248
+ end
249
+ end
250
+
251
+ class TransitionWithoutReadingStateTest < Test::Unit::TestCase
252
+ def setup
253
+ @klass = Class.new
254
+ @machine = StateMachine::Machine.new(@klass)
255
+ @machine.state :parked, :idling
256
+ @machine.event :ignite
257
+
258
+ @object = @klass.new
259
+ @object.state = 'idling'
260
+ @transition = StateMachine::Transition.new(@object, @machine, :ignite, :parked, :idling, false)
261
+ end
262
+
263
+ def test_should_not_read_from_value_from_object
264
+ assert_equal 'parked', @transition.from
265
+ end
266
+
267
+ def test_should_have_to_value
268
+ assert_equal 'idling', @transition.to
269
+ end
270
+ end
271
+
272
+ class TransitionWithActionTest < Test::Unit::TestCase
273
+ def setup
274
+ @klass = Class.new do
275
+ def save
276
+ end
277
+ end
278
+
279
+ @machine = StateMachine::Machine.new(@klass, :action => :save)
280
+ @machine.state :parked, :idling
281
+ @machine.event :ignite
282
+
283
+ @object = @klass.new
284
+ @object.state = 'parked'
285
+
286
+ @transition = StateMachine::Transition.new(@object, @machine, :ignite, :parked, :idling)
287
+ end
288
+
289
+ def test_should_have_an_action
290
+ assert_equal :save, @transition.action
291
+ end
292
+
293
+ def test_should_not_have_a_result
294
+ assert_nil @transition.result
295
+ end
296
+ end
297
+
298
+ class TransitionAfterBeingPersistedTest < Test::Unit::TestCase
299
+ def setup
300
+ @klass = Class.new
301
+ @machine = StateMachine::Machine.new(@klass, :action => :save)
302
+ @machine.state :parked, :idling
303
+ @machine.event :ignite
304
+
305
+ @object = @klass.new
306
+ @object.state = 'parked'
307
+
308
+ @transition = StateMachine::Transition.new(@object, @machine, :ignite, :parked, :idling)
309
+ @transition.persist
310
+ end
311
+
312
+ def test_should_update_state_value
313
+ assert_equal 'idling', @object.state
314
+ end
315
+
316
+ def test_should_not_change_from_state
317
+ assert_equal 'parked', @transition.from
318
+ end
319
+
320
+ def test_should_not_change_to_state
321
+ assert_equal 'idling', @transition.to
322
+ end
323
+
324
+ def test_should_not_be_able_to_persist_twice
325
+ @object.state = 'parked'
326
+ @transition.persist
327
+ assert_equal 'parked', @object.state
328
+ end
329
+
330
+ def test_should_be_able_to_persist_again_after_resetting
331
+ @object.state = 'parked'
332
+ @transition.reset
333
+ @transition.persist
334
+ assert_equal 'idling', @object.state
335
+ end
336
+
337
+ def test_should_revert_to_from_state_on_rollback
338
+ @transition.rollback
339
+ assert_equal 'parked', @object.state
340
+ end
341
+ end
342
+
343
+ class TransitionAfterBeingRolledBackTest < Test::Unit::TestCase
344
+ def setup
345
+ @klass = Class.new
346
+ @machine = StateMachine::Machine.new(@klass, :action => :save)
347
+ @machine.state :parked, :idling
348
+ @machine.event :ignite
349
+
350
+ @object = @klass.new
351
+ @object.state = 'parked'
352
+
353
+ @transition = StateMachine::Transition.new(@object, @machine, :ignite, :parked, :idling)
354
+ @object.state = 'idling'
355
+
356
+ @transition.rollback
357
+ end
358
+
359
+ def test_should_update_state_value_to_from_state
360
+ assert_equal 'parked', @object.state
361
+ end
362
+
363
+ def test_should_not_change_from_state
364
+ assert_equal 'parked', @transition.from
365
+ end
366
+
367
+ def test_should_not_change_to_state
368
+ assert_equal 'idling', @transition.to
369
+ end
370
+
371
+ def test_should_still_be_able_to_persist
372
+ @transition.persist
373
+ assert_equal 'idling', @object.state
374
+ end
375
+ end
376
+
377
+ class TransitionWithoutCallbacksTest < Test::Unit::TestCase
378
+ def setup
379
+ @klass = Class.new
380
+
381
+ @machine = StateMachine::Machine.new(@klass)
382
+ @machine.state :parked, :idling
383
+ @machine.event :ignite
384
+
385
+ @object = @klass.new
386
+ @object.state = 'parked'
387
+ @transition = StateMachine::Transition.new(@object, @machine, :ignite, :parked, :idling)
388
+ end
389
+
390
+ def test_should_succeed
391
+ assert_equal true, @transition.run_callbacks
392
+ end
393
+
394
+ def test_should_succeed_if_after_callbacks_skipped
395
+ assert_equal true, @transition.run_callbacks(:after => false)
396
+ end
397
+
398
+ def test_should_call_block_if_provided
399
+ @transition.run_callbacks { @ran_block = true; {} }
400
+ assert @ran_block
401
+ end
402
+
403
+ def test_should_track_block_result
404
+ @transition.run_callbacks {{:result => 1}}
405
+ assert_equal 1, @transition.result
406
+ end
407
+ end
408
+
409
+ class TransitionWithBeforeCallbacksTest < Test::Unit::TestCase
410
+ def setup
411
+ @klass = Class.new
412
+
413
+ @machine = StateMachine::Machine.new(@klass)
414
+ @machine.state :parked, :idling
415
+ @machine.event :ignite
416
+
417
+ @object = @klass.new
418
+ @object.state = 'parked'
419
+ @transition = StateMachine::Transition.new(@object, @machine, :ignite, :parked, :idling)
420
+ end
421
+
422
+ def test_should_run_before_callbacks
423
+ @machine.before_transition {@run = true}
424
+ result = @transition.run_callbacks
425
+
426
+ assert_equal true, result
427
+ assert_equal true, @run
428
+ end
429
+
430
+ def test_should_only_run_those_that_match_transition_context
431
+ @count = 0
432
+ callback = lambda {@count += 1}
433
+
434
+ @machine.before_transition :from => :parked, :to => :idling, :on => :park, :do => callback
435
+ @machine.before_transition :from => :parked, :to => :parked, :on => :park, :do => callback
436
+ @machine.before_transition :from => :parked, :to => :idling, :on => :ignite, :do => callback
437
+ @machine.before_transition :from => :idling, :to => :idling, :on => :park, :do => callback
438
+ @transition.run_callbacks
439
+
440
+ assert_equal 1, @count
441
+ end
442
+
443
+ def test_should_pass_transition_as_argument
444
+ @machine.before_transition {|*args| @args = args}
445
+ @transition.run_callbacks
446
+
447
+ assert_equal [@object, @transition], @args
448
+ end
449
+
450
+ def test_should_catch_halts
451
+ @machine.before_transition {throw :halt}
452
+
453
+ result = nil
454
+ assert_nothing_thrown { result = @transition.run_callbacks }
455
+ assert_equal false, result
456
+ end
457
+
458
+ def test_should_not_catch_exceptions
459
+ @machine.before_transition {raise ArgumentError}
460
+ assert_raise(ArgumentError) { @transition.run_callbacks }
461
+ end
462
+
463
+ def test_should_not_be_able_to_run_twice
464
+ @count = 0
465
+ @machine.before_transition {@count += 1}
466
+ @transition.run_callbacks
467
+ @transition.run_callbacks
468
+ assert_equal 1, @count
469
+ end
470
+
471
+ def test_should_be_able_to_run_again_after_halt
472
+ @count = 0
473
+ @machine.before_transition {@count += 1; throw :halt}
474
+ @transition.run_callbacks
475
+ @transition.run_callbacks
476
+ assert_equal 2, @count
477
+ end
478
+
479
+ def test_should_be_able_to_run_again_after_resetting
480
+ @count = 0
481
+ @machine.before_transition {@count += 1}
482
+ @transition.run_callbacks
483
+ @transition.reset
484
+ @transition.run_callbacks
485
+ assert_equal 2, @count
486
+ end
487
+
488
+ def test_should_succeed_if_block_result_is_false
489
+ @machine.before_transition {@run = true}
490
+ assert_equal true, @transition.run_callbacks {{:result => false}}
491
+ assert @run
492
+ end
493
+
494
+ def test_should_succeed_if_block_result_is_true
495
+ @machine.before_transition {@run = true}
496
+ assert_equal true, @transition.run_callbacks {{:result => true}}
497
+ assert @run
498
+ end
499
+
500
+ def test_should_succeed_if_block_success_is_false
501
+ @machine.before_transition {@run = true}
502
+ assert_equal true, @transition.run_callbacks {{:success => false}}
503
+ assert @run
504
+ end
505
+
506
+ def test_should_succeed_if_block_success_is_false
507
+ @machine.before_transition {@run = true}
508
+ assert_equal true, @transition.run_callbacks {{:success => true}}
509
+ assert @run
510
+ end
511
+ end
512
+
513
+ class TransitionWithMultipleBeforeCallbacksTest < Test::Unit::TestCase
514
+ def setup
515
+ @klass = Class.new
516
+
517
+ @machine = StateMachine::Machine.new(@klass)
518
+ @machine.state :parked, :idling
519
+ @machine.event :ignite
520
+
521
+ @object = @klass.new
522
+ @object.state = 'parked'
523
+ @transition = StateMachine::Transition.new(@object, @machine, :ignite, :parked, :idling)
524
+ end
525
+
526
+ def test_should_run_in_the_order_they_were_defined
527
+ @callbacks = []
528
+ @machine.before_transition {@callbacks << 1}
529
+ @machine.before_transition {@callbacks << 2}
530
+ @transition.run_callbacks
531
+
532
+ assert_equal [1, 2], @callbacks
533
+ end
534
+
535
+ def test_should_not_run_further_callbacks_if_halted
536
+ @callbacks = []
537
+ @machine.before_transition {@callbacks << 1; throw :halt}
538
+ @machine.before_transition {@callbacks << 2}
539
+
540
+ assert_equal false, @transition.run_callbacks
541
+ assert_equal [1], @callbacks
542
+ end
543
+
544
+ def test_should_fail_if_any_callback_halted
545
+ @machine.before_transition {true}
546
+ @machine.before_transition {throw :halt}
547
+
548
+ assert_equal false, @transition.run_callbacks
549
+ end
550
+ end
551
+
552
+ class TransitionWithAfterCallbacksTest < Test::Unit::TestCase
553
+ def setup
554
+ @klass = Class.new
555
+
556
+ @machine = StateMachine::Machine.new(@klass)
557
+ @machine.state :parked, :idling
558
+ @machine.event :ignite
559
+
560
+ @object = @klass.new
561
+ @object.state = 'parked'
562
+ @transition = StateMachine::Transition.new(@object, @machine, :ignite, :parked, :idling)
563
+ end
564
+
565
+ def test_should_run_after_callbacks
566
+ @machine.after_transition {|object| @run = true}
567
+ result = @transition.run_callbacks
568
+
569
+ assert_equal true, result
570
+ assert_equal true, @run
571
+ end
572
+
573
+ def test_should_only_run_those_that_match_transition_context
574
+ @count = 0
575
+ callback = lambda {@count += 1}
576
+
577
+ @machine.after_transition :from => :parked, :to => :idling, :on => :park, :do => callback
578
+ @machine.after_transition :from => :parked, :to => :parked, :on => :park, :do => callback
579
+ @machine.after_transition :from => :parked, :to => :idling, :on => :ignite, :do => callback
580
+ @machine.after_transition :from => :idling, :to => :idling, :on => :park, :do => callback
581
+ @transition.run_callbacks
582
+
583
+ assert_equal 1, @count
584
+ end
585
+
586
+ def test_should_not_run_if_not_successful
587
+ @machine.after_transition {|object| @run = true}
588
+ @transition.run_callbacks {{:success => false}}
589
+ assert !@run
590
+ end
591
+
592
+ def test_should_run_if_not_successful_and_includes_failures
593
+ @machine.after_transition(:include_failures => true) {|object| @run = true}
594
+ @transition.run_callbacks {{:success => false}}
595
+ assert @run
596
+ end
597
+
598
+ def test_should_run_if_successful
599
+ @machine.after_transition {|object| @run = true}
600
+ @transition.run_callbacks {{:success => true}}
601
+ assert @run
602
+ end
603
+
604
+ def test_should_run_if_successful_and_includes_failures
605
+ @machine.after_transition(:include_failures => true) {|object| @run = true}
606
+ @transition.run_callbacks {{:success => true}}
607
+ assert @run
608
+ end
609
+
610
+ def test_should_pass_transition_as_argument
611
+ @machine.after_transition {|*args| @args = args}
612
+
613
+ @transition.run_callbacks
614
+ assert_equal [@object, @transition], @args
615
+ end
616
+
617
+ def test_should_catch_halts
618
+ @machine.after_transition {throw :halt}
619
+
620
+ result = nil
621
+ assert_nothing_thrown { result = @transition.run_callbacks }
622
+ assert_equal true, result
623
+ end
624
+
625
+ def test_should_not_catch_exceptions
626
+ @machine.after_transition {raise ArgumentError}
627
+ assert_raise(ArgumentError) { @transition.run_callbacks }
628
+ end
629
+
630
+ def test_should_not_be_able_to_run_twice
631
+ @count = 0
632
+ @machine.after_transition {@count += 1}
633
+ @transition.run_callbacks
634
+ @transition.run_callbacks
635
+ assert_equal 1, @count
636
+ end
637
+
638
+ def test_should_not_be_able_to_run_twice_if_halted
639
+ @count = 0
640
+ @machine.after_transition {@count += 1; throw :halt}
641
+ @transition.run_callbacks
642
+ @transition.run_callbacks
643
+ assert_equal 1, @count
644
+ end
645
+
646
+ def test_should_be_able_to_run_again_after_resetting
647
+ @count = 0
648
+ @machine.after_transition {@count += 1}
649
+ @transition.run_callbacks
650
+ @transition.reset
651
+ @transition.run_callbacks
652
+ assert_equal 2, @count
653
+ end
654
+ end
655
+
656
+ class TransitionWithMultipleAfterCallbacksTest < Test::Unit::TestCase
657
+ def setup
658
+ @klass = Class.new
659
+
660
+ @machine = StateMachine::Machine.new(@klass)
661
+ @machine.state :parked, :idling
662
+ @machine.event :ignite
663
+
664
+ @object = @klass.new
665
+ @object.state = 'parked'
666
+ @transition = StateMachine::Transition.new(@object, @machine, :ignite, :parked, :idling)
667
+ end
668
+
669
+ def test_should_run_in_the_order_they_were_defined
670
+ @callbacks = []
671
+ @machine.after_transition {@callbacks << 1}
672
+ @machine.after_transition {@callbacks << 2}
673
+ @transition.run_callbacks
674
+
675
+ assert_equal [1, 2], @callbacks
676
+ end
677
+
678
+ def test_should_not_run_further_callbacks_if_halted
679
+ @callbacks = []
680
+ @machine.after_transition {@callbacks << 1; throw :halt}
681
+ @machine.after_transition {@callbacks << 2}
682
+
683
+ assert_equal true, @transition.run_callbacks
684
+ assert_equal [1], @callbacks
685
+ end
686
+
687
+ def test_should_fail_if_any_callback_halted
688
+ @machine.after_transition {true}
689
+ @machine.after_transition {throw :halt}
690
+
691
+ assert_equal true, @transition.run_callbacks
692
+ end
693
+ end
694
+
695
+ class TransitionWithAroundCallbacksTest < Test::Unit::TestCase
696
+ def setup
697
+ @klass = Class.new
698
+
699
+ @machine = StateMachine::Machine.new(@klass)
700
+ @machine.state :parked, :idling
701
+ @machine.event :ignite
702
+
703
+ @object = @klass.new
704
+ @object.state = 'parked'
705
+ @transition = StateMachine::Transition.new(@object, @machine, :ignite, :parked, :idling)
706
+ end
707
+
708
+ def test_should_run_around_callbacks
709
+ @machine.around_transition {|object, transition, block| @run_before = true; block.call; @run_after = true}
710
+ result = @transition.run_callbacks
711
+
712
+ assert_equal true, result
713
+ assert_equal true, @run_before
714
+ assert_equal true, @run_after
715
+ end
716
+
717
+ def test_should_only_run_those_that_match_transition_context
718
+ @count = 0
719
+ callback = lambda {|object, transition, block| @count += 1; block.call}
720
+
721
+ @machine.around_transition :from => :parked, :to => :idling, :on => :park, :do => callback
722
+ @machine.around_transition :from => :parked, :to => :parked, :on => :park, :do => callback
723
+ @machine.around_transition :from => :parked, :to => :idling, :on => :ignite, :do => callback
724
+ @machine.around_transition :from => :idling, :to => :idling, :on => :park, :do => callback
725
+ @transition.run_callbacks
726
+
727
+ assert_equal 1, @count
728
+ end
729
+
730
+ def test_should_pass_transition_as_argument
731
+ @machine.around_transition {|*args| block = args.pop; @args = args; block.call}
732
+ @transition.run_callbacks
733
+
734
+ assert_equal [@object, @transition], @args
735
+ end
736
+
737
+ def test_should_run_block_between_callback
738
+ @callbacks = []
739
+ @machine.around_transition {|block| @callbacks << :before; block.call; @callbacks << :after}
740
+ @transition.run_callbacks { @callbacks << :within; {:success => true} }
741
+
742
+ assert_equal [:before, :within, :after], @callbacks
743
+ end
744
+
745
+ def test_should_have_access_to_result_after_yield
746
+ @machine.around_transition {|block| @before_result = @transition.result; block.call; @after_result = @transition.result}
747
+ @transition.run_callbacks {{:result => 1, :success => true}}
748
+
749
+ assert_nil @before_result
750
+ assert_equal 1, @after_result
751
+ end
752
+
753
+ def test_should_catch_before_yield_halts
754
+ @machine.around_transition {throw :halt}
755
+
756
+ result = nil
757
+ assert_nothing_thrown { result = @transition.run_callbacks }
758
+ assert_equal false, result
759
+ end
760
+
761
+ def test_should_catch_after_yield_halts
762
+ @machine.around_transition {|block| block.call; throw :halt}
763
+
764
+ result = nil
765
+ assert_nothing_thrown { result = @transition.run_callbacks }
766
+ assert_equal true, result
767
+ end
768
+
769
+ def test_should_not_catch_before_yield
770
+ @machine.around_transition {raise ArgumentError}
771
+ assert_raise(ArgumentError) { @transition.run_callbacks }
772
+ end
773
+
774
+ def test_should_not_catch_after_yield
775
+ @machine.around_transition {|block| block.call; raise ArgumentError}
776
+ assert_raise(ArgumentError) { @transition.run_callbacks }
777
+ end
778
+
779
+ def test_should_fail_if_not_yielded
780
+ @machine.around_transition {}
781
+
782
+ result = nil
783
+ assert_nothing_thrown { result = @transition.run_callbacks }
784
+ assert_equal false, result
785
+ end
786
+
787
+ def test_should_not_be_able_to_run_twice
788
+ @before_count = 0
789
+ @after_count = 0
790
+ @machine.around_transition {|block| @before_count += 1; block.call; @after_count += 1}
791
+ @transition.run_callbacks
792
+ @transition.run_callbacks
793
+ assert_equal 1, @before_count
794
+ assert_equal 1, @after_count
795
+ end
796
+
797
+ def test_should_be_able_to_run_again_after_resetting
798
+ @before_count = 0
799
+ @after_count = 0
800
+ @machine.around_transition {|block| @before_count += 1; block.call; @after_count += 1}
801
+ @transition.run_callbacks
802
+ @transition.reset
803
+ @transition.run_callbacks
804
+ assert_equal 2, @before_count
805
+ assert_equal 2, @after_count
806
+ end
807
+
808
+ def test_should_succeed_if_block_result_is_false
809
+ @machine.around_transition {|block| @before_run = true; block.call; @after_run = true}
810
+ assert_equal true, @transition.run_callbacks {{:success => true, :result => false}}
811
+ assert @before_run
812
+ assert @after_run
813
+ end
814
+
815
+ def test_should_succeed_if_block_result_is_true
816
+ @machine.around_transition {|block| @before_run = true; block.call; @after_run = true}
817
+ assert_equal true, @transition.run_callbacks {{:success => true, :result => true}}
818
+ assert @before_run
819
+ assert @after_run
820
+ end
821
+
822
+ def test_should_only_run_before_if_block_success_is_false
823
+ @machine.around_transition {|block| @before_run = true; block.call; @after_run = true}
824
+ assert_equal true, @transition.run_callbacks {{:success => false}}
825
+ assert @before_run
826
+ assert !@after_run
827
+ end
828
+
829
+ def test_should_succeed_if_including_failure_and_block_success_is_false
830
+ @machine.around_transition(:include_failures => true) {|block| @before_run = true; block.call; @after_run = true}
831
+ assert_equal true, @transition.run_callbacks {{:success => false}}
832
+ assert @before_run
833
+ assert @after_run
834
+ end
835
+
836
+ def test_should_succeed_if_block_success_is_false
837
+ @machine.around_transition {|block| @before_run = true; block.call; @after_run = true}
838
+ assert_equal true, @transition.run_callbacks {{:success => true}}
839
+ assert @before_run
840
+ assert @after_run
841
+ end
842
+ end
843
+
844
+ class TransitionWithMultipleAroundCallbacksTest < Test::Unit::TestCase
845
+ def setup
846
+ @klass = Class.new
847
+
848
+ @machine = StateMachine::Machine.new(@klass)
849
+ @machine.state :parked, :idling
850
+ @machine.event :ignite
851
+
852
+ @object = @klass.new
853
+ @object.state = 'parked'
854
+ @transition = StateMachine::Transition.new(@object, @machine, :ignite, :parked, :idling)
855
+ end
856
+
857
+ def test_should_before_yield_in_the_order_they_were_defined
858
+ @callbacks = []
859
+ @machine.around_transition {|block| @callbacks << 1; block.call}
860
+ @machine.around_transition {|block| @callbacks << 2; block.call}
861
+ @transition.run_callbacks
862
+
863
+ assert_equal [1, 2], @callbacks
864
+ end
865
+
866
+ def test_should_before_yield_multiple_methods_in_the_order_they_were_defined
867
+ @callbacks = []
868
+ @machine.around_transition(lambda {|block| @callbacks << 1; block.call}, lambda {|block| @callbacks << 2; block.call})
869
+ @machine.around_transition(lambda {|block| @callbacks << 3; block.call}, lambda {|block| @callbacks << 4; block.call})
870
+ @transition.run_callbacks
871
+
872
+ assert_equal [1, 2, 3, 4], @callbacks
873
+ end
874
+
875
+ def test_should_after_yield_in_the_reverse_order_they_were_defined
876
+ @callbacks = []
877
+ @machine.around_transition {|block| block.call; @callbacks << 1}
878
+ @machine.around_transition {|block| block.call; @callbacks << 2}
879
+ @transition.run_callbacks
880
+
881
+ assert_equal [2, 1], @callbacks
882
+ end
883
+
884
+ def test_should_after_yield_multiple_methods_in_the_reverse_order_they_were_defined
885
+ @callbacks = []
886
+ @machine.around_transition(lambda {|block| block.call; @callbacks << 1}) {|block| block.call; @callbacks << 2}
887
+ @machine.around_transition(lambda {|block| block.call; @callbacks << 3}) {|block| block.call; @callbacks << 4}
888
+ @transition.run_callbacks
889
+
890
+ assert_equal [4, 3, 2, 1], @callbacks
891
+ end
892
+
893
+ def test_should_run_block_between_callback
894
+ @callbacks = []
895
+ @machine.around_transition {|block| @callbacks << :before_1; block.call; @callbacks << :after_1}
896
+ @machine.around_transition {|block| @callbacks << :before_2; block.call; @callbacks << :after_2}
897
+ @transition.run_callbacks { @callbacks << :within; {:success => true} }
898
+
899
+ assert_equal [:before_1, :before_2, :within, :after_2, :after_1], @callbacks
900
+ end
901
+
902
+ def test_should_have_access_to_result_after_yield
903
+ @machine.around_transition {|block| @before_result_1 = @transition.result; block.call; @after_result_1 = @transition.result}
904
+ @machine.around_transition {|block| @before_result_2 = @transition.result; block.call; @after_result_2 = @transition.result}
905
+ @transition.run_callbacks {{:result => 1, :success => true}}
906
+
907
+ assert_nil @before_result_1
908
+ assert_nil @before_result_2
909
+ assert_equal 1, @after_result_1
910
+ assert_equal 1, @after_result_2
911
+ end
912
+
913
+ def test_should_fail_if_any_before_yield_halted
914
+ @machine.around_transition {|block| block.call}
915
+ @machine.around_transition {throw :halt}
916
+
917
+ assert_equal false, @transition.run_callbacks
918
+ end
919
+
920
+ def test_should_not_continue_around_callbacks_if_before_yield_halted
921
+ @callbacks = []
922
+ @machine.around_transition {@callbacks << 1; throw :halt}
923
+ @machine.around_transition {|block| @callbacks << 2; block.call; @callbacks << 3}
924
+
925
+ assert_equal false, @transition.run_callbacks
926
+ assert_equal [1], @callbacks
927
+ end
928
+
929
+ def test_should_not_continue_around_callbacks_if_later_before_yield_halted
930
+ @callbacks = []
931
+ @machine.around_transition {|block| block.call; @callbacks << 1}
932
+ @machine.around_transition {throw :halt}
933
+
934
+ @transition.run_callbacks
935
+ assert_equal [], @callbacks
936
+ end
937
+
938
+ def test_should_not_run_further_callbacks_if_after_yield_halted
939
+ @callbacks = []
940
+ @machine.around_transition {|block| block.call; @callbacks << 1}
941
+ @machine.around_transition {|block| block.call; throw :halt}
942
+
943
+ assert_equal true, @transition.run_callbacks
944
+ assert_equal [], @callbacks
945
+ end
946
+
947
+ def test_should_fail_if_any_fail_to_yield
948
+ @callbacks = []
949
+ @machine.around_transition {@callbacks << 1}
950
+ @machine.around_transition {|block| @callbacks << 2; block.call; @callbacks << 3}
951
+
952
+ assert_equal false, @transition.run_callbacks
953
+ assert_equal [1], @callbacks
954
+ end
955
+ end
956
+
957
+ class TransitionWithMixedCallbacksTest < Test::Unit::TestCase
958
+ def setup
959
+ @klass = Class.new
960
+
961
+ @machine = StateMachine::Machine.new(@klass)
962
+ @machine.state :parked, :idling
963
+ @machine.event :ignite
964
+
965
+ @object = @klass.new
966
+ @object.state = 'parked'
967
+ @transition = StateMachine::Transition.new(@object, @machine, :ignite, :parked, :idling)
968
+ end
969
+
970
+ def test_should_before_and_around_callbacks_in_order_defined
971
+ @callbacks = []
972
+ @machine.before_transition {@callbacks << :before_1}
973
+ @machine.around_transition {|block| @callbacks << :around; block.call}
974
+ @machine.before_transition {@callbacks << :before_2}
975
+
976
+ assert_equal true, @transition.run_callbacks
977
+ assert_equal [:before_1, :around, :before_2], @callbacks
978
+ end
979
+
980
+ def test_should_run_around_callbacks_before_after_callbacks
981
+ @callbacks = []
982
+ @machine.after_transition {@callbacks << :after_1}
983
+ @machine.around_transition {|block| block.call; @callbacks << :after_2}
984
+ @machine.after_transition {@callbacks << :after_3}
985
+
986
+ assert_equal true, @transition.run_callbacks
987
+ assert_equal [:after_2, :after_1, :after_3], @callbacks
988
+ end
989
+
990
+ def test_should_have_access_to_result_for_both_after_and_around_callbacks
991
+ @machine.after_transition {@after_result = @transition.result}
992
+ @machine.around_transition {|block| block.call; @around_result = @transition.result}
993
+
994
+ @transition.run_callbacks {{:result => 1, :success => true}}
995
+ assert_equal 1, @after_result
996
+ assert_equal 1, @around_result
997
+ end
998
+
999
+ def test_should_not_run_further_callbacks_if_before_callback_halts
1000
+ @callbacks = []
1001
+ @machine.before_transition {@callbacks << :before_1}
1002
+ @machine.around_transition {|block| @callbacks << :before_around_1; block.call; @callbacks << :after_around_1}
1003
+ @machine.before_transition {@callbacks << :before_2; throw :halt}
1004
+ @machine.around_transition {|block| @callbacks << :before_around_2; block.call; @callbacks << :after_around_2}
1005
+ @machine.after_transition {@callbacks << :after}
1006
+
1007
+ assert_equal false, @transition.run_callbacks
1008
+ assert_equal [:before_1, :before_around_1, :before_2], @callbacks
1009
+ end
1010
+
1011
+ def test_should_not_run_further_callbacks_if_before_yield_halts
1012
+ @callbacks = []
1013
+ @machine.before_transition {@callbacks << :before_1}
1014
+ @machine.around_transition {|block| @callbacks << :before_around_1; throw :halt}
1015
+ @machine.before_transition {@callbacks << :before_2; throw :halt}
1016
+ @machine.around_transition {|block| @callbacks << :before_around_2; block.call; @callbacks << :after_around_2}
1017
+ @machine.after_transition {@callbacks << :after}
1018
+
1019
+ assert_equal false, @transition.run_callbacks
1020
+ assert_equal [:before_1, :before_around_1], @callbacks
1021
+ end
1022
+
1023
+ def test_should_not_run_further_callbacks_if_around_callback_fails_to_yield
1024
+ @callbacks = []
1025
+ @machine.before_transition {@callbacks << :before_1}
1026
+ @machine.around_transition {|block| @callbacks << :before_around_1}
1027
+ @machine.before_transition {@callbacks << :before_2; throw :halt}
1028
+ @machine.around_transition {|block| @callbacks << :before_around_2; block.call; @callbacks << :after_around_2}
1029
+ @machine.after_transition {@callbacks << :after}
1030
+
1031
+ assert_equal false, @transition.run_callbacks
1032
+ assert_equal [:before_1, :before_around_1], @callbacks
1033
+ end
1034
+
1035
+ def test_should_not_run_further_callbacks_if_after_yield_halts
1036
+ @callbacks = []
1037
+ @machine.before_transition {@callbacks << :before_1}
1038
+ @machine.around_transition {|block| @callbacks << :before_around_1; block.call; @callbacks << :after_around_1; throw :halt}
1039
+ @machine.before_transition {@callbacks << :before_2}
1040
+ @machine.around_transition {|block| @callbacks << :before_around_2; block.call; @callbacks << :after_around_2}
1041
+ @machine.after_transition {@callbacks << :after}
1042
+
1043
+ assert_equal true, @transition.run_callbacks
1044
+ assert_equal [:before_1, :before_around_1, :before_2, :before_around_2, :after_around_2, :after_around_1], @callbacks
1045
+ end
1046
+
1047
+ def test_should_not_run_further_callbacks_if_after_callback_halts
1048
+ @callbacks = []
1049
+ @machine.before_transition {@callbacks << :before_1}
1050
+ @machine.around_transition {|block| @callbacks << :before_around_1; block.call; @callbacks << :after_around_1}
1051
+ @machine.before_transition {@callbacks << :before_2}
1052
+ @machine.around_transition {|block| @callbacks << :before_around_2; block.call; @callbacks << :after_around_2}
1053
+ @machine.after_transition {@callbacks << :after_1; throw :halt}
1054
+ @machine.after_transition {@callbacks << :after_2}
1055
+
1056
+ assert_equal true, @transition.run_callbacks
1057
+ assert_equal [:before_1, :before_around_1, :before_2, :before_around_2, :after_around_2, :after_around_1, :after_1], @callbacks
1058
+ end
1059
+
1060
+ def test_should_run_any_callbacks_that_include_failures_if_block_success_is_false
1061
+ @callbacks = []
1062
+ @machine.around_transition {|block| block.call; @callbacks << :after_around_1}
1063
+ @machine.around_transition(:include_failures => true) {|block| block.call; @callbacks << :after_around_2}
1064
+ @machine.after_transition {@callbacks << :after_1}
1065
+ @machine.after_transition(:include_failures => true) {@callbacks << :after_2}
1066
+
1067
+ assert_equal true, @transition.run_callbacks {{:success => false}}
1068
+ assert_equal [:after_around_2, :after_2], @callbacks
1069
+ end
1070
+ end
1071
+
1072
+ class TransitionWithAfterCallbacksSkippedTest < Test::Unit::TestCase
1073
+ def setup
1074
+ @klass = Class.new
1075
+
1076
+ @machine = StateMachine::Machine.new(@klass)
1077
+ @machine.state :parked, :idling
1078
+ @machine.event :ignite
1079
+
1080
+ @object = @klass.new
1081
+ @object.state = 'parked'
1082
+ @transition = StateMachine::Transition.new(@object, @machine, :ignite, :parked, :idling)
1083
+ end
1084
+
1085
+ def test_should_run_before_callbacks
1086
+ @machine.before_transition {@run = true}
1087
+
1088
+ assert_equal true, @transition.run_callbacks(:after => false)
1089
+ assert @run
1090
+ end
1091
+
1092
+ def test_should_run_around_callbacks_before_yield
1093
+ @machine.around_transition {|block| @run = true; block.call}
1094
+
1095
+ assert_equal true, @transition.run_callbacks(:after => false)
1096
+ assert @run
1097
+ end
1098
+
1099
+ def test_should_not_run_after_callbacks
1100
+ @machine.after_transition {@run = true}
1101
+
1102
+ assert_equal true, @transition.run_callbacks(:after => false)
1103
+ assert !@run
1104
+ end
1105
+
1106
+ def test_should_not_run_around_callbacks_after_yield
1107
+ @machine.around_transition {|block| block.call; @run = true}
1108
+
1109
+ assert_equal true, @transition.run_callbacks(:after => false)
1110
+ assert !@run
1111
+ end
1112
+
1113
+ def test_should_run_after_callbacks_that_include_failures_if_block_success_is_false
1114
+ @machine.after_transition(:include_failures => true) {@run = true}
1115
+
1116
+ assert_equal true, @transition.run_callbacks(:after => false) {{:success => false}}
1117
+ assert @run
1118
+ end
1119
+
1120
+ def test_should_run_around_callbacks_that_include_failures_if_block_success_is_false
1121
+ @machine.around_transition(:include_failures => true) {|block| block.call; @run = true}
1122
+
1123
+ assert_equal true, @transition.run_callbacks(:after => false) {{:success => false}}
1124
+ assert @run
1125
+ end
1126
+
1127
+ def test_should_continue_around_transition_execution_on_second_call
1128
+ @callbacks = []
1129
+ @machine.around_transition {|block| @callbacks << :before_around_1; block.call; @callbacks << :after_around_1}
1130
+ @machine.around_transition {|block| @callbacks << :before_around_2; block.call; @callbacks << :after_around_2}
1131
+ @machine.after_transition {@callbacks << :after}
1132
+
1133
+ assert_equal true, @transition.run_callbacks(:after => false)
1134
+ assert_equal [:before_around_1, :before_around_2], @callbacks
1135
+
1136
+ assert_equal true, @transition.run_callbacks
1137
+ assert_equal [:before_around_1, :before_around_2, :after_around_2, :after_around_1, :after], @callbacks
1138
+ end
1139
+
1140
+ def test_should_not_run_further_callbacks_if_halted_during_continue_around_transition
1141
+ @callbacks = []
1142
+ @machine.around_transition {|block| @callbacks << :before_around_1; block.call; @callbacks << :after_around_1}
1143
+ @machine.around_transition {|block| @callbacks << :before_around_2; block.call; @callbacks << :after_around_2; throw :halt}
1144
+ @machine.after_transition {@callbacks << :after}
1145
+
1146
+ assert_equal true, @transition.run_callbacks(:after => false)
1147
+ assert_equal [:before_around_1, :before_around_2], @callbacks
1148
+
1149
+ assert_equal true, @transition.run_callbacks
1150
+ assert_equal [:before_around_1, :before_around_2, :after_around_2], @callbacks
1151
+ end
1152
+
1153
+ def test_should_not_be_able_to_continue_twice
1154
+ @count = 0
1155
+ @machine.around_transition {|block| block.call; @count += 1}
1156
+ @machine.after_transition {@count += 1}
1157
+
1158
+ @transition.run_callbacks(:after => false)
1159
+
1160
+ 2.times do
1161
+ assert_equal true, @transition.run_callbacks
1162
+ assert_equal 2, @count
1163
+ end
1164
+ end
1165
+
1166
+ def test_should_not_be_able_to_continue_again_after_halted
1167
+ @count = 0
1168
+ @machine.around_transition {|block| block.call; @count += 1; throw :halt}
1169
+ @machine.after_transition {@count += 1}
1170
+
1171
+ @transition.run_callbacks(:after => false)
1172
+
1173
+ 2.times do
1174
+ assert_equal true, @transition.run_callbacks
1175
+ assert_equal 1, @count
1176
+ end
1177
+ end
1178
+
1179
+ def test_should_have_access_to_result_after_continued
1180
+ @machine.around_transition {|block| @around_before_result = @transition.result; block.call; @around_after_result = @transition.result}
1181
+ @machine.after_transition {@after_result = @transition.result}
1182
+
1183
+ @transition.run_callbacks(:after => false)
1184
+ @transition.run_callbacks {{:result => 1}}
1185
+
1186
+ assert_nil @around_before_result
1187
+ assert_equal 1, @around_after_result
1188
+ assert_equal 1, @after_result
1189
+ end
1190
+
1191
+ def test_should_raise_exceptions_during_around_callbacks_after_yield_in_second_execution
1192
+ @machine.around_transition {|block| block.call; raise ArgumentError}
1193
+
1194
+ assert_nothing_raised { @transition.run_callbacks(:after => false) }
1195
+ assert_raise(ArgumentError) { @transition.run_callbacks }
1196
+ end
1197
+ end
1198
+
1199
+ class TransitionAfterBeingPerformedTest < Test::Unit::TestCase
1200
+ def setup
1201
+ @klass = Class.new do
1202
+ attr_reader :saved, :save_state
1203
+
1204
+ def save
1205
+ @save_state = state
1206
+ @saved = true
1207
+ 1
1208
+ end
1209
+ end
1210
+
1211
+ @machine = StateMachine::Machine.new(@klass, :action => :save)
1212
+ @machine.state :parked, :idling
1213
+ @machine.event :ignite
1214
+
1215
+ @object = @klass.new
1216
+ @object.state = 'parked'
1217
+ @transition = StateMachine::Transition.new(@object, @machine, :ignite, :parked, :idling)
1218
+ @result = @transition.perform
1219
+ end
1220
+
1221
+ def test_should_have_empty_args
1222
+ assert_equal [], @transition.args
1223
+ end
1224
+
1225
+ def test_should_have_a_result
1226
+ assert_equal 1, @transition.result
1227
+ end
1228
+
1229
+ def test_should_be_successful
1230
+ assert_equal true, @result
1231
+ end
1232
+
1233
+ def test_should_change_the_current_state
1234
+ assert_equal 'idling', @object.state
1235
+ end
1236
+
1237
+ def test_should_run_the_action
1238
+ assert @object.saved
1239
+ end
1240
+
1241
+ def test_should_run_the_action_after_saving_the_state
1242
+ assert_equal 'idling', @object.save_state
1243
+ end
1244
+ end
1245
+
1246
+ class TransitionWithPerformArgumentsTest < Test::Unit::TestCase
1247
+ def setup
1248
+ @klass = Class.new do
1249
+ attr_reader :saved
1250
+
1251
+ def save
1252
+ @saved = true
1253
+ end
1254
+ end
1255
+
1256
+ @machine = StateMachine::Machine.new(@klass, :action => :save)
1257
+ @machine.state :parked, :idling
1258
+ @machine.event :ignite
1259
+
1260
+ @object = @klass.new
1261
+ @object.state = 'parked'
1262
+ @transition = StateMachine::Transition.new(@object, @machine, :ignite, :parked, :idling)
1263
+ end
1264
+
1265
+ def test_should_have_arguments
1266
+ @transition.perform(1, 2)
1267
+
1268
+ assert_equal [1, 2], @transition.args
1269
+ assert @object.saved
1270
+ end
1271
+
1272
+ def test_should_not_include_run_action_in_arguments
1273
+ @transition.perform(1, 2, false)
1274
+
1275
+ assert_equal [1, 2], @transition.args
1276
+ assert !@object.saved
1277
+ end
1278
+ end
1279
+
1280
+ class TransitionWithoutRunningActionTest < Test::Unit::TestCase
1281
+ def setup
1282
+ @klass = Class.new do
1283
+ attr_reader :saved
1284
+
1285
+ def save
1286
+ @saved = true
1287
+ end
1288
+ end
1289
+
1290
+ @machine = StateMachine::Machine.new(@klass, :action => :save)
1291
+ @machine.state :parked, :idling
1292
+ @machine.event :ignite
1293
+ @machine.after_transition {|object| @run_after = true}
1294
+
1295
+ @object = @klass.new
1296
+ @object.state = 'parked'
1297
+ @transition = StateMachine::Transition.new(@object, @machine, :ignite, :parked, :idling)
1298
+ @result = @transition.perform(false)
1299
+ end
1300
+
1301
+ def test_should_have_empty_args
1302
+ assert_equal [], @transition.args
1303
+ end
1304
+
1305
+ def test_should_not_have_a_result
1306
+ assert_nil @transition.result
1307
+ end
1308
+
1309
+ def test_should_be_successful
1310
+ assert_equal true, @result
1311
+ end
1312
+
1313
+ def test_should_change_the_current_state
1314
+ assert_equal 'idling', @object.state
1315
+ end
1316
+
1317
+ def test_should_not_run_the_action
1318
+ assert !@object.saved
1319
+ end
1320
+
1321
+ def test_should_run_after_callbacks
1322
+ assert @run_after
1323
+ end
1324
+ end
1325
+
1326
+ class TransitionWithTransactionsTest < Test::Unit::TestCase
1327
+ def setup
1328
+ @klass = Class.new do
1329
+ class << self
1330
+ attr_accessor :running_transaction
1331
+ end
1332
+
1333
+ attr_accessor :result
1334
+
1335
+ def save
1336
+ @result = self.class.running_transaction
1337
+ true
1338
+ end
1339
+ end
1340
+
1341
+ @machine = StateMachine::Machine.new(@klass, :action => :save)
1342
+ @machine.state :parked, :idling
1343
+ @machine.event :ignite
1344
+
1345
+ @object = @klass.new
1346
+ @object.state = 'parked'
1347
+ @transition = StateMachine::Transition.new(@object, @machine, :ignite, :parked, :idling)
1348
+
1349
+ class << @machine
1350
+ def within_transaction(object)
1351
+ owner_class.running_transaction = object
1352
+ yield
1353
+ owner_class.running_transaction = false
1354
+ end
1355
+ end
1356
+ end
1357
+
1358
+ def test_should_run_blocks_within_transaction_for_object
1359
+ @transition.within_transaction do
1360
+ @result = @klass.running_transaction
1361
+ end
1362
+
1363
+ assert_equal @object, @result
1364
+ end
1365
+ end
1366
+
1367
+ class TransitionTransientTest < Test::Unit::TestCase
1368
+ def setup
1369
+ @klass = Class.new
1370
+
1371
+ @machine = StateMachine::Machine.new(@klass)
1372
+ @machine.state :parked, :idling
1373
+ @machine.event :ignite
1374
+
1375
+ @object = @klass.new
1376
+ @object.state = 'parked'
1377
+ @transition = StateMachine::Transition.new(@object, @machine, :ignite, :parked, :idling)
1378
+ @transition.transient = true
1379
+ end
1380
+
1381
+ def test_should_be_transient
1382
+ assert @transition.transient?
1383
+ end
1384
+ end