verborghs-state_machine 0.9.4

Sign up to get free protection for your applications and to get access to all the features.
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,2098 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../test_helper')
2
+
3
+ class TransitionCollectionTest < Test::Unit::TestCase
4
+ def test_should_raise_exception_if_invalid_option_specified
5
+ exception = assert_raise(ArgumentError) {StateMachine::TransitionCollection.new([], :invalid => true)}
6
+
7
+ end
8
+
9
+ def test_should_raise_exception_if_multiple_transitions_for_same_attribute_specified
10
+ @klass = Class.new
11
+
12
+ @machine = StateMachine::Machine.new(@klass, :initial => :parked)
13
+ @machine.state :parked, :idling
14
+ @machine.event :ignite
15
+
16
+ @object = @klass.new
17
+
18
+ exception = assert_raise(ArgumentError) do
19
+ StateMachine::TransitionCollection.new([
20
+ StateMachine::Transition.new(@object, @machine, :ignite, :parked, :idling),
21
+ StateMachine::Transition.new(@object, @machine, :ignite, :parked, :idling)
22
+ ])
23
+ end
24
+ assert_equal 'Cannot perform multiple transitions in parallel for the same state machine attribute', exception.message
25
+ end
26
+ end
27
+
28
+ class TransitionCollectionByDefaultTest < Test::Unit::TestCase
29
+ def setup
30
+ @transitions = StateMachine::TransitionCollection.new
31
+ end
32
+
33
+ def test_should_not_skip_actions
34
+ assert !@transitions.skip_actions
35
+ end
36
+
37
+ def test_should_not_skip_after
38
+ assert !@transitions.skip_after
39
+ end
40
+
41
+ def test_should_use_transaction
42
+ assert @transitions.use_transaction
43
+ end
44
+
45
+ def test_should_be_empty
46
+ assert @transitions.empty?
47
+ end
48
+ end
49
+
50
+ class TransitionCollectionEmptyWithoutBlockTest < Test::Unit::TestCase
51
+ def setup
52
+ @transitions = StateMachine::TransitionCollection.new
53
+ @result = @transitions.perform
54
+ end
55
+
56
+ def test_should_succeed
57
+ assert_equal true, @result
58
+ end
59
+ end
60
+
61
+
62
+ class TransitionCollectionEmptyWithBlockTest < Test::Unit::TestCase
63
+ def setup
64
+ @transitions = StateMachine::TransitionCollection.new
65
+ end
66
+
67
+ def test_should_raise_exception_if_perform_raises_exception
68
+ assert_raise(ArgumentError) { @transitions.perform { raise ArgumentError } }
69
+ end
70
+
71
+ def test_should_use_block_result_if_non_boolean
72
+ assert_equal 1, @transitions.perform { 1 }
73
+ end
74
+
75
+ def test_should_use_block_result_if_false
76
+ assert_equal false, @transitions.perform { false }
77
+ end
78
+
79
+ def test_should_use_block_reslut_if_nil
80
+ assert_equal nil, @transitions.perform { nil }
81
+ end
82
+ end
83
+
84
+ class TransitionCollectionInvalidTest < Test::Unit::TestCase
85
+ def setup
86
+ @transitions = StateMachine::TransitionCollection.new([false])
87
+ end
88
+
89
+ def test_should_be_empty
90
+ assert @transitions.empty?
91
+ end
92
+
93
+ def test_should_not_succeed
94
+ assert_equal false, @transitions.perform
95
+ end
96
+
97
+ def test_should_not_run_perform_block
98
+ ran_block = false
99
+ @transitions.perform { ran_block = true }
100
+ assert !ran_block
101
+ end
102
+ end
103
+
104
+ class TransitionCollectionPartialInvalidTest < Test::Unit::TestCase
105
+ def setup
106
+ @klass = Class.new do
107
+ attr_accessor :ran_transaction
108
+ end
109
+
110
+ @machine = StateMachine::Machine.new(@klass, :initial => :parked)
111
+ @machine.state :idling
112
+ @machine.event :ignite
113
+ @machine.before_transition {@ran_before = true}
114
+ @machine.after_transition {@ran_after = true}
115
+ @machine.around_transition {|block| @ran_around_before = true; block.call; @ran_around_after = true}
116
+
117
+ class << @machine
118
+ def within_transaction(object)
119
+ object.ran_transaction = true
120
+ end
121
+ end
122
+
123
+ @object = @klass.new
124
+
125
+ @transitions = StateMachine::TransitionCollection.new([
126
+ StateMachine::Transition.new(@object, @machine, :ignite, :parked, :idling),
127
+ false
128
+ ])
129
+ end
130
+
131
+ def test_should_not_store_invalid_values
132
+ assert_equal 1, @transitions.length
133
+ end
134
+
135
+ def test_should_not_succeed
136
+ assert_equal false, @transitions.perform
137
+ end
138
+
139
+ def test_should_not_start_transaction
140
+ assert !@object.ran_transaction
141
+ end
142
+
143
+ def test_should_not_run_perform_block
144
+ ran_block = false
145
+ @transitions.perform { ran_block = true }
146
+ assert !ran_block
147
+ end
148
+
149
+ def test_should_not_run_before_callbacks
150
+ assert !@ran_before
151
+ end
152
+
153
+ def test_should_not_persist_states
154
+ assert_equal 'parked', @object.state
155
+ end
156
+
157
+ def test_should_not_run_after_callbacks
158
+ assert !@ran_after
159
+ end
160
+
161
+ def test_should_not_run_around_callbacks_before_yield
162
+ assert !@ran_around_before
163
+ end
164
+
165
+ def test_should_not_run_around_callbacks_after_yield
166
+ assert !@ran_around_after
167
+ end
168
+ end
169
+
170
+ class TransitionCollectionValidTest < Test::Unit::TestCase
171
+ def setup
172
+ @klass = Class.new do
173
+ attr_reader :persisted
174
+
175
+ def initialize
176
+ super
177
+ @persisted = []
178
+ end
179
+
180
+ def state=(value)
181
+ @persisted << 'state' if @persisted
182
+ @state = value
183
+ end
184
+
185
+ def status=(value)
186
+ @persisted << 'status' if @persisted
187
+ @status = value
188
+ end
189
+ end
190
+
191
+ @state = StateMachine::Machine.new(@klass, :initial => :parked)
192
+ @state.state :idling
193
+ @state.event :ignite
194
+ @status = StateMachine::Machine.new(@klass, :status, :initial => :first_gear)
195
+ @status.state :second_gear
196
+ @status.event :shift_up
197
+
198
+ @object = @klass.new
199
+
200
+ @result = StateMachine::TransitionCollection.new([
201
+ @state_transition = StateMachine::Transition.new(@object, @state, :ignite, :parked, :idling),
202
+ @status_transition = StateMachine::Transition.new(@object, @status, :shift_up, :first_gear, :second_gear)
203
+ ]).perform
204
+ end
205
+
206
+ def test_should_succeed
207
+ assert_equal true, @result
208
+ end
209
+
210
+ def test_should_persist_each_state
211
+ assert_equal 'idling', @object.state
212
+ assert_equal 'second_gear', @object.status
213
+ end
214
+
215
+ def test_should_persist_in_order
216
+ assert_equal ['state', 'status'], @object.persisted
217
+ end
218
+
219
+ def test_should_store_results_in_transitions
220
+ assert_nil @state_transition.result
221
+ assert_nil @status_transition.result
222
+ end
223
+ end
224
+
225
+ class TransitionCollectionWithoutTransactionsTest < Test::Unit::TestCase
226
+ def setup
227
+ @klass = Class.new do
228
+ attr_accessor :ran_transaction
229
+ end
230
+
231
+ @machine = StateMachine::Machine.new(@klass, :initial => :parked)
232
+ @machine.state :idling
233
+ @machine.event :ignite
234
+
235
+ class << @machine
236
+ def within_transaction(object)
237
+ object.ran_transaction = true
238
+ end
239
+ end
240
+
241
+ @object = @klass.new
242
+ @transitions = StateMachine::TransitionCollection.new([
243
+ StateMachine::Transition.new(@object, @machine, :ignite, :parked, :idling)
244
+ ], :transaction => false)
245
+ @transitions.perform
246
+ end
247
+
248
+ def test_should_not_run_within_transaction
249
+ assert !@object.ran_transaction
250
+ end
251
+ end
252
+
253
+ class TransitionCollectionWithTransactionsTest < Test::Unit::TestCase
254
+ def setup
255
+ @klass = Class.new do
256
+ attr_accessor :running_transaction, :cancelled_transaction
257
+ end
258
+
259
+ @machine = StateMachine::Machine.new(@klass, :initial => :parked)
260
+ @machine.state :idling
261
+ @machine.event :ignite
262
+
263
+ class << @machine
264
+ def within_transaction(object)
265
+ object.running_transaction = true
266
+ object.cancelled_transaction = yield == false
267
+ object.running_transaction = false
268
+ end
269
+ end
270
+
271
+ @object = @klass.new
272
+ @transitions = StateMachine::TransitionCollection.new([
273
+ StateMachine::Transition.new(@object, @machine, :ignite, :parked, :idling)
274
+ ], :transaction => true)
275
+ end
276
+
277
+ def test_should_run_before_callbacks_within_transaction
278
+ @machine.before_transition {|object| @in_transaction = object.running_transaction}
279
+ @transitions.perform
280
+
281
+ assert @in_transaction
282
+ end
283
+
284
+ def test_should_run_action_within_transaction
285
+ @transitions.perform { @in_transaction = @object.running_transaction }
286
+
287
+ assert @in_transaction
288
+ end
289
+
290
+ def test_should_run_after_callbacks_within_transaction
291
+ @machine.after_transition {|object| @in_transaction = object.running_transaction}
292
+ @transitions.perform
293
+
294
+ assert @in_transaction
295
+ end
296
+
297
+ def test_should_cancel_the_transaction_on_before_halt
298
+ @machine.before_transition {throw :halt}
299
+
300
+ @transitions.perform
301
+ assert @object.cancelled_transaction
302
+ end
303
+
304
+ def test_should_cancel_the_transaction_on_action_failure
305
+ @transitions.perform { false }
306
+ assert @object.cancelled_transaction
307
+ end
308
+
309
+ def test_should_not_cancel_the_transaction_on_after_halt
310
+ @machine.after_transition {throw :halt}
311
+
312
+ @transitions.perform
313
+ assert !@object.cancelled_transaction
314
+ end
315
+ end
316
+
317
+ class TransitionCollectionWithEmptyActionsTest < Test::Unit::TestCase
318
+ def setup
319
+ @klass = Class.new
320
+
321
+ @state = StateMachine::Machine.new(@klass, :initial => :parked)
322
+ @state.state :idling
323
+ @state.event :ignite
324
+
325
+ @status = StateMachine::Machine.new(@klass, :status, :initial => :first_gear)
326
+ @status.state :second_gear
327
+ @status.event :shift_up
328
+
329
+ @object = @klass.new
330
+
331
+ @transitions = StateMachine::TransitionCollection.new([
332
+ @state_transition = StateMachine::Transition.new(@object, @state, :ignite, :parked, :idling),
333
+ @status_transition = StateMachine::Transition.new(@object, @status, :shift_up, :first_gear, :second_gear)
334
+ ])
335
+
336
+ @object.state = 'idling'
337
+ @object.status = 'second_gear'
338
+
339
+ @result = @transitions.perform
340
+ end
341
+
342
+ def test_should_succeed
343
+ assert_equal true, @result
344
+ end
345
+
346
+ def test_should_persist_states
347
+ assert_equal 'idling', @object.state
348
+ assert_equal 'second_gear', @object.status
349
+ end
350
+
351
+ def test_should_store_results_in_transitions
352
+ assert_nil @state_transition.result
353
+ assert_nil @status_transition.result
354
+ end
355
+ end
356
+
357
+ class TransitionCollectionWithSkippedActionsTest < Test::Unit::TestCase
358
+ def setup
359
+ @klass = Class.new do
360
+ attr_reader :actions
361
+
362
+ def save_state
363
+ (@actions ||= []) << :save_state
364
+ :save_state
365
+ end
366
+
367
+ def save_status
368
+ (@actions ||= []) << :save_status
369
+ :save_status
370
+ end
371
+ end
372
+
373
+ @callbacks = []
374
+
375
+ @state = StateMachine::Machine.new(@klass, :initial => :parked, :action => :save_state)
376
+ @state.state :idling
377
+ @state.event :ignite
378
+ @state.before_transition {@callbacks << :state_before}
379
+ @state.after_transition {@callbacks << :state_after}
380
+ @state.around_transition {|block| @callbacks << :state_around_before; block.call; @callbacks << :state_around_after}
381
+
382
+ @status = StateMachine::Machine.new(@klass, :status, :initial => :first_gear, :action => :save_status)
383
+ @status.state :second_gear
384
+ @status.event :shift_up
385
+ @status.before_transition {@callbacks << :status_before}
386
+ @status.after_transition {@callbacks << :status_after}
387
+ @status.around_transition {|block| @callbacks << :status_around_before; block.call; @callbacks << :status_around_after}
388
+
389
+ @object = @klass.new
390
+
391
+ @transitions = StateMachine::TransitionCollection.new([
392
+ @state_transition = StateMachine::Transition.new(@object, @state, :ignite, :parked, :idling),
393
+ @status_transition = StateMachine::Transition.new(@object, @status, :shift_up, :first_gear, :second_gear)
394
+ ], :actions => false)
395
+ @result = @transitions.perform
396
+ end
397
+
398
+ def test_should_skip_actions
399
+ assert_equal true, @transitions.skip_actions
400
+ end
401
+
402
+ def test_should_succeed
403
+ assert_equal true, @result
404
+ end
405
+
406
+ def test_should_persist_states
407
+ assert_equal 'idling', @object.state
408
+ assert_equal 'second_gear', @object.status
409
+ end
410
+
411
+ def test_should_not_run_actions
412
+ assert_nil @object.actions
413
+ end
414
+
415
+ def test_should_store_results_in_transitions
416
+ assert_nil @state_transition.result
417
+ assert_nil @status_transition.result
418
+ end
419
+
420
+ def test_should_run_all_callbacks
421
+ assert_equal [:state_before, :state_around_before, :status_before, :status_around_before, :status_around_after, :status_after, :state_around_after, :state_after], @callbacks
422
+ end
423
+ end
424
+
425
+ class TransitionCollectionWithSkippedActionsAndBlockTest < Test::Unit::TestCase
426
+ def setup
427
+ @klass = Class.new
428
+
429
+ @machine = StateMachine::Machine.new(@klass, :initial => :parked, :action => :save_state)
430
+ @machine.state :idling
431
+ @machine.event :ignite
432
+
433
+ @object = @klass.new
434
+
435
+ @transitions = StateMachine::TransitionCollection.new([
436
+ @state_transition = StateMachine::Transition.new(@object, @machine, :ignite, :parked, :idling)
437
+ ], :actions => false)
438
+ @result = @transitions.perform { @ran_block = true; 1 }
439
+ end
440
+
441
+ def test_should_succeed
442
+ assert_equal 1, @result
443
+ end
444
+
445
+ def test_should_persist_states
446
+ assert_equal 'idling', @object.state
447
+ end
448
+
449
+ def test_should_run_block
450
+ assert @ran_block
451
+ end
452
+
453
+ def test_should_store_results_in_transitions
454
+ assert_equal 1, @state_transition.result
455
+ end
456
+ end
457
+
458
+ class TransitionCollectionWithDuplicateActionsTest < Test::Unit::TestCase
459
+ def setup
460
+ @klass = Class.new do
461
+ attr_reader :actions
462
+
463
+ def save
464
+ (@actions ||= []) << :save
465
+ :save
466
+ end
467
+ end
468
+
469
+ @state = StateMachine::Machine.new(@klass, :initial => :parked, :action => :save)
470
+ @state.state :idling
471
+ @state.event :ignite
472
+
473
+ @status = StateMachine::Machine.new(@klass, :status, :initial => :first_gear, :action => :save)
474
+ @status.state :second_gear
475
+ @status.event :shift_up
476
+
477
+ @object = @klass.new
478
+
479
+ @transitions = StateMachine::TransitionCollection.new([
480
+ @state_transition = StateMachine::Transition.new(@object, @state, :ignite, :parked, :idling),
481
+ @status_transition = StateMachine::Transition.new(@object, @status, :shift_up, :first_gear, :second_gear)
482
+ ])
483
+ @result = @transitions.perform
484
+ end
485
+
486
+ def test_should_succeed
487
+ assert_equal :save, @result
488
+ end
489
+
490
+ def test_should_persist_states
491
+ assert_equal 'idling', @object.state
492
+ assert_equal 'second_gear', @object.status
493
+ end
494
+
495
+ def test_should_run_action_once
496
+ assert_equal [:save], @object.actions
497
+ end
498
+
499
+ def test_should_store_results_in_transitions
500
+ assert_equal :save, @state_transition.result
501
+ assert_equal :save, @status_transition.result
502
+ end
503
+ end
504
+
505
+ class TransitionCollectionWithDifferentActionsTest < Test::Unit::TestCase
506
+ def setup
507
+ @klass = Class.new do
508
+ attr_reader :actions
509
+
510
+ def save_state
511
+ (@actions ||= []) << :save_state
512
+ :save_state
513
+ end
514
+
515
+ def save_status
516
+ (@actions ||= []) << :save_status
517
+ :save_status
518
+ end
519
+ end
520
+
521
+ @state = StateMachine::Machine.new(@klass, :initial => :parked, :action => :save_state)
522
+ @state.state :idling
523
+ @state.event :ignite
524
+
525
+ @status = StateMachine::Machine.new(@klass, :status, :initial => :first_gear, :action => :save_status)
526
+ @status.state :second_gear
527
+ @status.event :shift_up
528
+
529
+ @object = @klass.new
530
+
531
+ @transitions = StateMachine::TransitionCollection.new([
532
+ @state_transition = StateMachine::Transition.new(@object, @state, :ignite, :parked, :idling),
533
+ @status_transition = StateMachine::Transition.new(@object, @status, :shift_up, :first_gear, :second_gear)
534
+ ])
535
+ end
536
+
537
+ def test_should_succeed
538
+ assert_equal true, @transitions.perform
539
+ end
540
+
541
+ def test_should_persist_states
542
+ @transitions.perform
543
+ assert_equal 'idling', @object.state
544
+ assert_equal 'second_gear', @object.status
545
+ end
546
+
547
+ def test_should_run_actions_in_order
548
+ @transitions.perform
549
+ assert_equal [:save_state, :save_status], @object.actions
550
+ end
551
+
552
+ def test_should_store_results_in_transitions
553
+ @transitions.perform
554
+ assert_equal :save_state, @state_transition.result
555
+ assert_equal :save_status, @status_transition.result
556
+ end
557
+
558
+ def test_should_not_halt_if_action_fails_for_first_transition
559
+ @klass.class_eval do
560
+ def save_state
561
+ (@actions ||= []) << :save_state
562
+ false
563
+ end
564
+ end
565
+
566
+
567
+ assert_equal false, @transitions.perform
568
+ assert_equal [:save_state, :save_status], @object.actions
569
+ end
570
+
571
+ def test_should_halt_if_action_fails_for_second_transition
572
+ @klass.class_eval do
573
+ def save_status
574
+ (@actions ||= []) << :save_status
575
+ false
576
+ end
577
+ end
578
+
579
+ assert_equal false, @transitions.perform
580
+ assert_equal [:save_state, :save_status], @object.actions
581
+ end
582
+
583
+ def test_should_rollback_if_action_errors_for_first_transition
584
+ @klass.class_eval do
585
+ def save_state
586
+ raise ArgumentError
587
+ end
588
+ end
589
+
590
+ begin; @transitions.perform; rescue; end
591
+ assert_equal 'parked', @object.state
592
+ assert_equal 'first_gear', @object.status
593
+ end
594
+
595
+ def test_should_rollback_if_action_errors_for_second_transition
596
+ @klass.class_eval do
597
+ def save_status
598
+ raise ArgumentError
599
+ end
600
+ end
601
+
602
+ begin; @transitions.perform; rescue; end
603
+ assert_equal 'parked', @object.state
604
+ assert_equal 'first_gear', @object.status
605
+ end
606
+
607
+ def test_should_not_run_after_callbacks_if_action_fails_for_first_transition
608
+ @klass.class_eval do
609
+ def save_state
610
+ false
611
+ end
612
+ end
613
+
614
+ @callbacks = []
615
+ @state.after_transition { @callbacks << :state_after }
616
+ @state.around_transition {|block| block.call; @callbacks << :state_around }
617
+ @status.after_transition { @callbacks << :status_after }
618
+ @status.around_transition {|block| block.call; @callbacks << :status_around }
619
+
620
+ @transitions.perform
621
+ assert_equal [], @callbacks
622
+ end
623
+
624
+ def test_should_not_run_after_callbacks_if_action_fails_for_second_transition
625
+ @klass.class_eval do
626
+ def save_status
627
+ false
628
+ end
629
+ end
630
+
631
+ @callbacks = []
632
+ @state.after_transition { @callbacks << :state_after }
633
+ @state.around_transition {|block| block.call; @callbacks << :state_around }
634
+ @status.after_transition { @callbacks << :status_after }
635
+ @status.around_transition {|block| block.call; @callbacks << :status_around }
636
+
637
+ @transitions.perform
638
+ assert_equal [], @callbacks
639
+ end
640
+
641
+ def test_should_run_after_failure_callbacks_if_action_fails_for_first_transition
642
+ @klass.class_eval do
643
+ def save_state
644
+ false
645
+ end
646
+ end
647
+
648
+ @callbacks = []
649
+ @state.after_transition(:include_failures => true) { @callbacks << :state_after }
650
+ @state.around_transition(:include_failures => true) {|block| block.call; @callbacks << :state_around }
651
+ @status.after_transition(:include_failures => true) { @callbacks << :status_after }
652
+ @status.around_transition(:include_failures => true) {|block| block.call; @callbacks << :status_around }
653
+
654
+ @transitions.perform
655
+ assert_equal [:status_around, :status_after, :state_around, :state_after], @callbacks
656
+ end
657
+
658
+ def test_should_run_after_failure_callbacks_if_action_fails_for_second_transition
659
+ @klass.class_eval do
660
+ def save_status
661
+ false
662
+ end
663
+ end
664
+
665
+ @callbacks = []
666
+ @state.after_transition(:include_failures => true) { @callbacks << :state_after }
667
+ @state.around_transition(:include_failures => true) {|block| block.call; @callbacks << :state_around }
668
+ @status.after_transition(:include_failures => true) { @callbacks << :status_after }
669
+ @status.around_transition(:include_failures => true) {|block| block.call; @callbacks << :status_around }
670
+
671
+ @transitions.perform
672
+ assert_equal [:status_around, :status_after, :state_around, :state_after], @callbacks
673
+ end
674
+ end
675
+
676
+ class TransitionCollectionWithMixedActionsTest < Test::Unit::TestCase
677
+ def setup
678
+ @klass = Class.new do
679
+ def save
680
+ true
681
+ end
682
+ end
683
+
684
+ @state = StateMachine::Machine.new(@klass, :initial => :parked, :action => :save)
685
+ @state.state :idling
686
+ @state.event :ignite
687
+
688
+ @status = StateMachine::Machine.new(@klass, :status, :initial => :first_gear)
689
+ @status.state :second_gear
690
+ @status.event :shift_up
691
+
692
+ @object = @klass.new
693
+
694
+ @transitions = StateMachine::TransitionCollection.new([
695
+ @state_transition = StateMachine::Transition.new(@object, @state, :ignite, :parked, :idling),
696
+ @status_transition = StateMachine::Transition.new(@object, @status, :shift_up, :first_gear, :second_gear)
697
+ ])
698
+ @result = @transitions.perform
699
+ end
700
+
701
+ def test_should_succeed
702
+ assert_equal true, @result
703
+ end
704
+
705
+ def test_should_persist_states
706
+ assert_equal 'idling', @object.state
707
+ assert_equal 'second_gear', @object.status
708
+ end
709
+
710
+ def test_should_store_results_in_transitions
711
+ assert_equal true, @state_transition.result
712
+ assert_nil @status_transition.result
713
+ end
714
+ end
715
+
716
+ class TransitionCollectionWithBlockTest < Test::Unit::TestCase
717
+ def setup
718
+ @klass = Class.new do
719
+ attr_reader :actions
720
+
721
+ def save
722
+ (@actions ||= []) << :save
723
+ end
724
+ end
725
+
726
+ @state = StateMachine::Machine.new(@klass, :state, :initial => :parked, :action => :save)
727
+ @state.state :idling
728
+ @state.event :ignite
729
+
730
+ @status = StateMachine::Machine.new(@klass, :status, :initial => :first_gear, :action => :save)
731
+ @status.state :second_gear
732
+ @status.event :shift_up
733
+
734
+ @object = @klass.new
735
+ @transitions = StateMachine::TransitionCollection.new([
736
+ @state_transition = StateMachine::Transition.new(@object, @state, :ignite, :parked, :idling),
737
+ @status_transition = StateMachine::Transition.new(@object, @status, :shift_up, :first_gear, :second_gear)
738
+ ])
739
+ @result = @transitions.perform { 1 }
740
+ end
741
+
742
+ def test_should_succeed
743
+ assert_equal 1, @result
744
+ end
745
+
746
+ def test_should_persist_states
747
+ assert_equal 'idling', @object.state
748
+ assert_equal 'second_gear', @object.status
749
+ end
750
+
751
+ def test_should_not_run_machine_actions
752
+ assert_nil @object.actions
753
+ end
754
+
755
+ def test_should_use_result_as_transition_result
756
+ assert_equal 1, @state_transition.result
757
+ assert_equal 1, @status_transition.result
758
+ end
759
+ end
760
+
761
+ class TransitionCollectionWithActionFailedTest < Test::Unit::TestCase
762
+ def setup
763
+ @klass = Class.new do
764
+ def save
765
+ false
766
+ end
767
+ end
768
+ @before_count = 0
769
+ @around_before_count = 0
770
+ @after_count = 0
771
+ @around_after_count = 0
772
+
773
+ @machine = StateMachine::Machine.new(@klass, :initial => :parked, :action => :save)
774
+ @machine.state :idling
775
+ @machine.event :ignite
776
+
777
+ @machine.before_transition {@before_count += 1}
778
+ @machine.after_transition {@after_count += 1}
779
+ @machine.after_transition(:include_failures => true) {@after_count += 1}
780
+ @machine.around_transition {|block| @around_before_count += 1; block.call; @around_after_count += 1}
781
+ @machine.around_transition(:include_failures => true) {|block| @around_before_count += 1; block.call; @around_after_count += 1}
782
+
783
+ @object = @klass.new
784
+
785
+ @transitions = StateMachine::TransitionCollection.new([
786
+ StateMachine::Transition.new(@object, @machine, :ignite, :parked, :idling)
787
+ ])
788
+ @result = @transitions.perform
789
+ end
790
+
791
+ def test_should_not_succeed
792
+ assert_equal false, @result
793
+ end
794
+
795
+ def test_should_not_persist_state
796
+ assert_equal 'parked', @object.state
797
+ end
798
+
799
+ def test_should_run_before_callbacks
800
+ assert_equal 1, @before_count
801
+ end
802
+
803
+ def test_should_run_around_callbacks_before_yield
804
+ assert_equal 2, @around_before_count
805
+ end
806
+
807
+ def test_should_only_run_after_callbacks_that_include_failures
808
+ assert_equal 1, @after_count
809
+ end
810
+
811
+ def test_should_only_run_around_callbacks_after_yield_that_include_failures
812
+ assert_equal 1, @around_after_count
813
+ end
814
+ end
815
+
816
+ class TransitionCollectionWithActionErrorTest < Test::Unit::TestCase
817
+ def setup
818
+ @klass = Class.new do
819
+ def save
820
+ raise ArgumentError
821
+ end
822
+ end
823
+ @before_count = 0
824
+ @around_before_count = 0
825
+ @after_count = 0
826
+ @around_after_count = 0
827
+
828
+ @machine = StateMachine::Machine.new(@klass, :initial => :parked, :action => :save)
829
+ @machine.state :idling
830
+ @machine.event :ignite
831
+
832
+ @machine.before_transition {@before_count += 1}
833
+ @machine.after_transition {@after_count += 1}
834
+ @machine.after_transition(:include_failures => true) {@after_count += 1}
835
+ @machine.around_transition {|block| @around_before_count += 1; block.call; @around_after_count += 1}
836
+ @machine.around_transition(:include_failures => true) {|block| @around_before_count += 1; block.call; @around_after_count += 1}
837
+
838
+ @object = @klass.new
839
+
840
+ @transitions = StateMachine::TransitionCollection.new([
841
+ StateMachine::Transition.new(@object, @machine, :ignite, :parked, :idling)
842
+ ])
843
+
844
+ @raised = true
845
+ begin
846
+ @transitions.perform
847
+ @raised = false
848
+ rescue ArgumentError
849
+ end
850
+ end
851
+
852
+ def test_should_not_catch_exception
853
+ assert @raised
854
+ end
855
+
856
+ def test_should_not_persist_state
857
+ assert_equal 'parked', @object.state
858
+ end
859
+
860
+ def test_should_run_before_callbacks
861
+ assert_equal 1, @before_count
862
+ end
863
+
864
+ def test_should_run_around_callbacks_before_yield
865
+ assert_equal 2, @around_before_count
866
+ end
867
+
868
+ def test_should_not_run_after_callbacks
869
+ assert_equal 0, @after_count
870
+ end
871
+
872
+ def test_should_not_run_around_callbacks_after_yield
873
+ assert_equal 0, @around_after_count
874
+ end
875
+ end
876
+
877
+ class TransitionCollectionWithCallbacksTest < Test::Unit::TestCase
878
+ def setup
879
+ @klass = Class.new do
880
+ attr_reader :saved
881
+
882
+ def save
883
+ @saved = true
884
+ end
885
+ end
886
+
887
+ @before_callbacks = []
888
+ @after_callbacks = []
889
+
890
+ @state = StateMachine::Machine.new(@klass, :initial => :parked, :action => :save)
891
+ @state.state :idling
892
+ @state.event :ignite
893
+ @state.before_transition {@before_callbacks << :state_before}
894
+ @state.after_transition(:include_failures => true) {@after_callbacks << :state_after}
895
+ @state.around_transition(:include_failures => true) {|block| @before_callbacks << :state_around; block.call; @after_callbacks << :state_around}
896
+
897
+ @status = StateMachine::Machine.new(@klass, :status, :initial => :first_gear, :action => :save)
898
+ @status.state :second_gear
899
+ @status.event :shift_up
900
+ @status.before_transition {@before_callbacks << :status_before}
901
+ @status.after_transition(:include_failures => true) {@after_callbacks << :status_after}
902
+ @status.around_transition(:include_failures => true) {|block| @before_callbacks << :status_around; block.call; @after_callbacks << :status_around}
903
+
904
+ @object = @klass.new
905
+ @transitions = StateMachine::TransitionCollection.new([
906
+ StateMachine::Transition.new(@object, @state, :ignite, :parked, :idling),
907
+ StateMachine::Transition.new(@object, @status, :shift_up, :first_gear, :second_gear)
908
+ ])
909
+ end
910
+
911
+ def test_should_run_before_callbacks_in_order
912
+ @transitions.perform
913
+ assert_equal [:state_before, :state_around, :status_before, :status_around], @before_callbacks
914
+ end
915
+
916
+ def test_should_halt_if_before_callback_halted_for_first_transition
917
+ @state.before_transition {throw :halt}
918
+
919
+ assert_equal false, @transitions.perform
920
+ assert_equal [:state_before, :state_around], @before_callbacks
921
+ end
922
+
923
+ def test_should_halt_if_before_callback_halted_for_second_transition
924
+ @status.before_transition {throw :halt}
925
+
926
+ assert_equal false, @transitions.perform
927
+ assert_equal [:state_before, :state_around, :status_before, :status_around], @before_callbacks
928
+ end
929
+
930
+ def test_should_halt_if_around_callback_halted_before_yield_for_first_transition
931
+ @state.around_transition {throw :halt}
932
+
933
+ assert_equal false, @transitions.perform
934
+ assert_equal [:state_before, :state_around], @before_callbacks
935
+ end
936
+
937
+ def test_should_halt_if_around_callback_halted_before_yield_for_second_transition
938
+ @status.around_transition {throw :halt}
939
+
940
+ assert_equal false, @transitions.perform
941
+ assert_equal [:state_before, :state_around, :status_before, :status_around], @before_callbacks
942
+ end
943
+
944
+ def test_should_run_after_callbacks_in_reverse_order
945
+ @transitions.perform
946
+ assert_equal [:status_around, :status_after, :state_around, :state_after], @after_callbacks
947
+ end
948
+
949
+ def test_should_not_halt_if_after_callback_halted_for_first_transition
950
+ @state.after_transition(:include_failures => true) {throw :halt}
951
+
952
+ assert_equal true, @transitions.perform
953
+ assert_equal [:status_around, :status_after, :state_around, :state_after], @after_callbacks
954
+ end
955
+
956
+ def test_should_not_halt_if_around_callback_halted_for_second_transition
957
+ @status.around_transition(:include_failures => true) {|block| block.call; throw :halt}
958
+
959
+ assert_equal true, @transitions.perform
960
+ assert_equal [:state_around, :state_after], @after_callbacks
961
+ end
962
+
963
+ def test_should_run_before_callbacks_before_persisting_the_state
964
+ @state.before_transition {|object| @before_state = object.state}
965
+ @state.around_transition {|object, transition, block| @around_state = object.state; block.call}
966
+ @transitions.perform
967
+
968
+ assert_equal 'parked', @before_state
969
+ assert_equal 'parked', @around_state
970
+ end
971
+
972
+ def test_should_persist_state_before_running_action
973
+ @klass.class_eval do
974
+ attr_reader :saved_on_persist
975
+
976
+ def state=(value)
977
+ @state = value
978
+ @saved_on_persist = @saved
979
+ end
980
+ end
981
+
982
+ @transitions.perform
983
+ assert !@object.saved_on_persist
984
+ end
985
+
986
+ def test_should_persist_state_before_running_action_block
987
+ @klass.class_eval do
988
+ attr_writer :saved
989
+ attr_reader :saved_on_persist
990
+
991
+ def state=(value)
992
+ @state = value
993
+ @saved_on_persist = @saved
994
+ end
995
+ end
996
+
997
+ @transitions.perform { @object.saved = true }
998
+ assert !@object.saved_on_persist
999
+ end
1000
+
1001
+ def test_should_run_after_callbacks_after_running_the_action
1002
+ @state.after_transition {|object| @after_saved = object.saved}
1003
+ @state.around_transition {|object, transition, block| block.call; @around_saved = object.saved}
1004
+ @transitions.perform
1005
+
1006
+ assert @after_saved
1007
+ assert @around_saved
1008
+ end
1009
+ end
1010
+
1011
+ class TransitionCollectionWithBeforeCallbackHaltTest < Test::Unit::TestCase
1012
+ def setup
1013
+ @klass = Class.new do
1014
+ attr_reader :saved
1015
+
1016
+ def save
1017
+ @saved = true
1018
+ end
1019
+ end
1020
+ @before_count = 0
1021
+ @after_count = 0
1022
+
1023
+ @machine = StateMachine::Machine.new(@klass, :initial => :parked, :action => :save)
1024
+ @machine.state :idling
1025
+ @machine.event :ignite
1026
+
1027
+ @machine.before_transition {@before_count += 1; throw :halt}
1028
+ @machine.before_transition {@before_count += 1}
1029
+ @machine.after_transition {@after_count += 1}
1030
+ @machine.around_transition {|block| @before_count += 1; block.call; @after_count += 1}
1031
+
1032
+ @object = @klass.new
1033
+
1034
+ @transitions = StateMachine::TransitionCollection.new([
1035
+ StateMachine::Transition.new(@object, @machine, :ignite, :parked, :idling)
1036
+ ])
1037
+ @result = @transitions.perform
1038
+ end
1039
+
1040
+ def test_should_not_succeed
1041
+ assert_equal false, @result
1042
+ end
1043
+
1044
+ def test_should_not_persist_state
1045
+ assert_equal 'parked', @object.state
1046
+ end
1047
+
1048
+ def test_should_not_run_action
1049
+ assert !@object.saved
1050
+ end
1051
+
1052
+ def test_should_not_run_further_before_callbacks
1053
+ assert_equal 1, @before_count
1054
+ end
1055
+
1056
+ def test_should_not_run_after_callbacks
1057
+ assert_equal 0, @after_count
1058
+ end
1059
+ end
1060
+
1061
+ class TransitionCollectionWithAfterCallbackHaltTest < Test::Unit::TestCase
1062
+ def setup
1063
+ @klass = Class.new do
1064
+ attr_reader :saved
1065
+
1066
+ def save
1067
+ @saved = true
1068
+ end
1069
+ end
1070
+ @before_count = 0
1071
+ @after_count = 0
1072
+
1073
+ @machine = StateMachine::Machine.new(@klass, :initial => :parked, :action => :save)
1074
+ @machine.state :idling
1075
+ @machine.event :ignite
1076
+
1077
+ @machine.before_transition {@before_count += 1}
1078
+ @machine.after_transition {@after_count += 1; throw :halt}
1079
+ @machine.after_transition {@after_count += 1}
1080
+ @machine.around_transition {|block| @before_count += 1; block.call; @after_count += 1}
1081
+
1082
+ @object = @klass.new
1083
+
1084
+ @transitions = StateMachine::TransitionCollection.new([
1085
+ StateMachine::Transition.new(@object, @machine, :ignite, :parked, :idling)
1086
+ ])
1087
+ @result = @transitions.perform
1088
+ end
1089
+
1090
+ def test_should_succeed
1091
+ assert_equal true, @result
1092
+ end
1093
+
1094
+ def test_should_persist_state
1095
+ assert_equal 'idling', @object.state
1096
+ end
1097
+
1098
+ def test_should_run_before_callbacks
1099
+ assert_equal 2, @before_count
1100
+ end
1101
+
1102
+ def test_should_not_run_further_after_callbacks
1103
+ assert_equal 2, @after_count
1104
+ end
1105
+ end
1106
+
1107
+ class TransitionCollectionWithSkippedAfterCallbacksTest < Test::Unit::TestCase
1108
+ def setup
1109
+ @klass = Class.new
1110
+
1111
+ @machine = StateMachine::Machine.new(@klass, :initial => :parked)
1112
+ @machine.state :idling
1113
+ @machine.event :ignite
1114
+ @machine.after_transition {@ran_after = true}
1115
+ @machine.around_transition {|block| @ran_around_before = true; block.call; @ran_around_after = true}
1116
+
1117
+ @object = @klass.new
1118
+
1119
+ @transitions = StateMachine::TransitionCollection.new([
1120
+ @transition = StateMachine::Transition.new(@object, @machine, :ignite, :parked, :idling)
1121
+ ], :after => false)
1122
+ @result = @transitions.perform
1123
+ end
1124
+
1125
+ def test_should_succeed
1126
+ assert_equal true, @result
1127
+ end
1128
+
1129
+ def test_should_not_run_after_callbacks
1130
+ assert !@ran_after
1131
+ end
1132
+
1133
+ def test_should_not_run_around_callbacks_after_yield
1134
+ assert !@ran_around_after
1135
+ end
1136
+
1137
+ def test_should_run_after_callbacks_on_subsequent_perform
1138
+ StateMachine::TransitionCollection.new([@transition]).perform
1139
+ assert @ran_after
1140
+ end
1141
+
1142
+ def test_should_run_around_callbacks_after_yield_on_subsequent_perform
1143
+ StateMachine::TransitionCollection.new([@transition]).perform
1144
+ assert @ran_around_after
1145
+ end
1146
+
1147
+ def test_should_not_rerun_around_callbacks_before_yield_on_subsequent_perform
1148
+ @ran_around_before = false
1149
+ StateMachine::TransitionCollection.new([@transition]).perform
1150
+
1151
+ assert !@ran_around_before
1152
+ end
1153
+ end
1154
+
1155
+ class TransitionCollectionWithActionHelperBaseTest < Test::Unit::TestCase
1156
+ def setup
1157
+ @superclass = Class.new do
1158
+ def save
1159
+ true
1160
+ end
1161
+ end
1162
+
1163
+ @klass = Class.new(@superclass) do
1164
+ attr_reader :saved, :state_on_save, :state_event_on_save, :state_event_transition_on_save
1165
+
1166
+ def save
1167
+ @saved = true
1168
+ @state_on_save = state
1169
+ @state_event_on_save = state_event
1170
+ @state_event_transition_on_save = state_event_transition
1171
+ super
1172
+ end
1173
+ end
1174
+
1175
+ @machine = StateMachine::Machine.new(@klass, :initial => :parked, :action => :save)
1176
+ @machine.state :idling
1177
+ @machine.event :ignite
1178
+
1179
+ @object = @klass.new
1180
+
1181
+ @transition = StateMachine::Transition.new(@object, @machine, :ignite, :parked, :idling)
1182
+ end
1183
+
1184
+ def default_test
1185
+ end
1186
+ end
1187
+
1188
+ class TransitionCollectionWithActionHelperAndSkippedActionTest < TransitionCollectionWithActionHelperBaseTest
1189
+ def setup
1190
+ super
1191
+ @result = StateMachine::TransitionCollection.new([@transition], :actions => false).perform
1192
+ end
1193
+
1194
+ def test_should_succeed
1195
+ assert_equal true, @result
1196
+ end
1197
+
1198
+ def test_should_not_run_action
1199
+ assert !@object.saved
1200
+ end
1201
+ end
1202
+
1203
+ class TransitionCollectionWithActionHelperAndSkippedAfterCallbacksTest < TransitionCollectionWithActionHelperBaseTest
1204
+ def setup
1205
+ super
1206
+ @result = StateMachine::TransitionCollection.new([@transition], :after => false).perform
1207
+ end
1208
+
1209
+ def test_should_succeed
1210
+ assert_equal true, @result
1211
+ end
1212
+
1213
+ def test_should_run_action
1214
+ assert @object.saved
1215
+ end
1216
+
1217
+ def test_should_have_already_persisted_when_running_action
1218
+ assert_equal 'idling', @object.state_on_save
1219
+ end
1220
+
1221
+ def test_should_not_have_event_during_action
1222
+ assert_nil @object.state_event_on_save
1223
+ end
1224
+
1225
+ def test_should_not_write_event
1226
+ assert_nil @object.state_event
1227
+ end
1228
+
1229
+ def test_should_not_have_event_transition_during_save
1230
+ assert_nil @object.state_event_transition_on_save
1231
+ end
1232
+
1233
+ def test_should_not_write_event_attribute
1234
+ assert_nil @object.send(:state_event_transition)
1235
+ end
1236
+ end
1237
+
1238
+ class TransitionCollectionWithActionHelperAndBlockTest < TransitionCollectionWithActionHelperBaseTest
1239
+ def setup
1240
+ super
1241
+ @result = StateMachine::TransitionCollection.new([@transition]).perform { true }
1242
+ end
1243
+
1244
+ def test_should_succeed
1245
+ assert_equal true, @result
1246
+ end
1247
+
1248
+ def test_should_not_run_action
1249
+ assert !@object.saved
1250
+ end
1251
+ end
1252
+
1253
+ class TransitionCollectionWithActionHelperInvalidTest < TransitionCollectionWithActionHelperBaseTest
1254
+ def setup
1255
+ super
1256
+ @result = StateMachine::TransitionCollection.new([@transition, nil]).perform
1257
+ end
1258
+
1259
+ def test_should_not_succeed
1260
+ assert_equal false, @result
1261
+ end
1262
+
1263
+ def test_should_not_run_action
1264
+ assert !@object.saved
1265
+ end
1266
+ end
1267
+
1268
+ class TransitionCollectionWithActionHelperWithNilActionTest < TransitionCollectionWithActionHelperBaseTest
1269
+ def setup
1270
+ super
1271
+
1272
+ @machine = StateMachine::Machine.new(@klass, :status, :initial => :parked)
1273
+ @machine.state :idling
1274
+ @machine.event :ignite
1275
+
1276
+ @result = StateMachine::TransitionCollection.new([@transition, StateMachine::Transition.new(@object, @machine, :ignite, :parked, :idling)]).perform
1277
+ end
1278
+
1279
+ def test_should_succeed
1280
+ assert_equal true, @result
1281
+ end
1282
+
1283
+ def test_should_run_action
1284
+ assert @object.saved
1285
+ end
1286
+
1287
+ def test_should_have_already_persisted_when_running_action
1288
+ assert_equal 'idling', @object.state_on_save
1289
+ end
1290
+
1291
+ def test_should_not_have_event_during_action
1292
+ assert_nil @object.state_event_on_save
1293
+ end
1294
+
1295
+ def test_should_not_write_event
1296
+ assert_nil @object.state_event
1297
+ end
1298
+
1299
+ def test_should_not_have_event_transition_during_save
1300
+ assert_nil @object.state_event_transition_on_save
1301
+ end
1302
+
1303
+ def test_should_not_write_event_attribute
1304
+ assert_nil @object.send(:state_event_transition)
1305
+ end
1306
+ end
1307
+
1308
+ class TransitionCollectionWithActionHelperWithDifferentActionsTest < TransitionCollectionWithActionHelperBaseTest
1309
+ def setup
1310
+ super
1311
+
1312
+ @klass.class_eval do
1313
+ def save_status
1314
+ true
1315
+ end
1316
+ end
1317
+
1318
+ @machine = StateMachine::Machine.new(@klass, :status, :initial => :parked, :action => :save_status)
1319
+ @machine.state :idling
1320
+ @machine.event :ignite
1321
+
1322
+ @result = StateMachine::TransitionCollection.new([@transition, StateMachine::Transition.new(@object, @machine, :ignite, :parked, :idling)]).perform
1323
+ end
1324
+
1325
+ def test_should_succeed
1326
+ assert_equal true, @result
1327
+ end
1328
+
1329
+ def test_should_run_action
1330
+ assert @object.saved
1331
+ end
1332
+
1333
+ def test_should_have_already_persisted_when_running_action
1334
+ assert_equal 'idling', @object.state_on_save
1335
+ end
1336
+
1337
+ def test_should_not_have_event_during_action
1338
+ assert_nil @object.state_event_on_save
1339
+ end
1340
+
1341
+ def test_should_not_write_event
1342
+ assert_nil @object.state_event
1343
+ end
1344
+
1345
+ def test_should_not_have_event_transition_during_save
1346
+ assert_nil @object.state_event_transition_on_save
1347
+ end
1348
+
1349
+ def test_should_not_write_event_attribute
1350
+ assert_nil @object.send(:state_event_transition)
1351
+ end
1352
+ end
1353
+
1354
+ class TransitionCollectionWithActionHelperTest < TransitionCollectionWithActionHelperBaseTest
1355
+ def setup
1356
+ super
1357
+ @result = StateMachine::TransitionCollection.new([@transition]).perform
1358
+ end
1359
+
1360
+ def test_should_succeed
1361
+ assert_equal true, @result
1362
+ end
1363
+
1364
+ def test_should_run_action
1365
+ assert @object.saved
1366
+ end
1367
+
1368
+ def test_should_not_have_already_persisted_when_running_action
1369
+ assert_equal 'parked', @object.state_on_save
1370
+ end
1371
+
1372
+ def test_should_persist
1373
+ assert_equal 'idling', @object.state
1374
+ end
1375
+
1376
+ def test_should_not_have_event_during_action
1377
+ assert_nil @object.state_event_on_save
1378
+ end
1379
+
1380
+ def test_should_not_write_event
1381
+ assert_nil @object.state_event
1382
+ end
1383
+
1384
+ def test_should_have_event_transition_during_action
1385
+ assert_equal @transition, @object.state_event_transition_on_save
1386
+ end
1387
+
1388
+ def test_should_not_write_event_transition
1389
+ assert_nil @object.send(:state_event_transition)
1390
+ end
1391
+
1392
+ def test_should_mark_event_transition_as_transient
1393
+ assert @transition.transient?
1394
+ end
1395
+ end
1396
+
1397
+ class TransitionCollectionWithActionHelperMultipleTest < TransitionCollectionWithActionHelperBaseTest
1398
+ def setup
1399
+ super
1400
+
1401
+ @status_machine = StateMachine::Machine.new(@klass, :status, :initial => :first_gear, :action => :save)
1402
+ @status_machine.state :second_gear
1403
+ @status_machine.event :shift_up
1404
+
1405
+ @klass.class_eval do
1406
+ attr_reader :status_on_save, :status_event_on_save, :status_event_transition_on_save
1407
+
1408
+ def save
1409
+ @saved = true
1410
+ @state_on_save = state
1411
+ @state_event_on_save = state_event
1412
+ @state_event_transition_on_save = state_event_transition
1413
+ @status_on_save = status
1414
+ @status_event_on_save = status_event
1415
+ @status_event_transition_on_save = status_event_transition
1416
+ super
1417
+ 1
1418
+ end
1419
+ end
1420
+
1421
+ @object = @klass.new
1422
+ @state_transition = StateMachine::Transition.new(@object, @machine, :ignite, :parked, :idling)
1423
+ @status_transition = StateMachine::Transition.new(@object, @status_machine, :shift_up, :first_gear, :second_gear)
1424
+
1425
+ @result = StateMachine::TransitionCollection.new([@state_transition, @status_transition]).perform
1426
+ end
1427
+
1428
+ def test_should_succeed
1429
+ assert_equal 1, @result
1430
+ end
1431
+
1432
+ def test_should_run_action
1433
+ assert @object.saved
1434
+ end
1435
+
1436
+ def test_should_not_have_already_persisted_when_running_action
1437
+ assert_equal 'parked', @object.state_on_save
1438
+ assert_equal 'first_gear', @object.status_on_save
1439
+ end
1440
+
1441
+ def test_should_persist
1442
+ assert_equal 'idling', @object.state
1443
+ assert_equal 'second_gear', @object.status
1444
+ end
1445
+
1446
+ def test_should_not_have_events_during_action
1447
+ assert_nil @object.state_event_on_save
1448
+ assert_nil @object.status_event_on_save
1449
+ end
1450
+
1451
+ def test_should_not_write_events
1452
+ assert_nil @object.state_event
1453
+ assert_nil @object.status_event
1454
+ end
1455
+
1456
+ def test_should_have_event_transitions_during_action
1457
+ assert_equal @state_transition, @object.state_event_transition_on_save
1458
+ assert_equal @status_transition, @object.status_event_transition_on_save
1459
+ end
1460
+
1461
+ def test_should_not_write_event_transitions
1462
+ assert_nil @object.send(:state_event_transition)
1463
+ assert_nil @object.send(:status_event_transition)
1464
+ end
1465
+
1466
+ def test_should_mark_event_transitions_as_transient
1467
+ assert @state_transition.transient?
1468
+ assert @status_transition.transient?
1469
+ end
1470
+ end
1471
+
1472
+ class TransitionCollectionWithActionHelperErrorTest < TransitionCollectionWithActionHelperBaseTest
1473
+ def setup
1474
+ super
1475
+
1476
+ @superclass.class_eval do
1477
+ def save
1478
+ raise ArgumentError
1479
+ end
1480
+ end
1481
+
1482
+ begin; StateMachine::TransitionCollection.new([@transition]).perform; rescue; end
1483
+ end
1484
+
1485
+ def test_should_not_write_event
1486
+ assert_nil @object.state_event
1487
+ end
1488
+
1489
+ def test_should_not_write_event_transition
1490
+ assert_nil @object.send(:state_event_transition)
1491
+ end
1492
+ end
1493
+
1494
+ class AttributeTransitionCollectionByDefaultTest < Test::Unit::TestCase
1495
+ def setup
1496
+ @transitions = StateMachine::AttributeTransitionCollection.new
1497
+ end
1498
+
1499
+ def test_should_skip_actions
1500
+ assert @transitions.skip_actions
1501
+ end
1502
+
1503
+ def test_should_not_skip_after
1504
+ assert !@transitions.skip_after
1505
+ end
1506
+
1507
+ def test_should_not_use_transaction
1508
+ assert !@transitions.use_transaction
1509
+ end
1510
+
1511
+ def test_should_be_empty
1512
+ assert @transitions.empty?
1513
+ end
1514
+ end
1515
+
1516
+ class AttributeTransitionCollectionWithEventsTest < Test::Unit::TestCase
1517
+ def setup
1518
+ @klass = Class.new
1519
+
1520
+ @state = StateMachine::Machine.new(@klass, :initial => :parked, :action => :save)
1521
+ @state.state :idling
1522
+ @state.event :ignite
1523
+
1524
+ @status = StateMachine::Machine.new(@klass, :status, :initial => :first_gear, :action => :save)
1525
+ @status.state :second_gear
1526
+ @status.event :shift_up
1527
+
1528
+ @object = @klass.new
1529
+ @object.state_event = 'ignite'
1530
+ @object.status_event = 'shift_up'
1531
+
1532
+ @transitions = StateMachine::AttributeTransitionCollection.new([
1533
+ @state_transition = StateMachine::Transition.new(@object, @state, :ignite, :parked, :idling),
1534
+ @status_transition = StateMachine::Transition.new(@object, @status, :shift_up, :first_gear, :second_gear)
1535
+ ])
1536
+ @result = @transitions.perform
1537
+ end
1538
+
1539
+ def test_should_succeed
1540
+ assert_equal true, @result
1541
+ end
1542
+
1543
+ def test_should_persist_states
1544
+ assert_equal 'idling', @object.state
1545
+ assert_equal 'second_gear', @object.status
1546
+ end
1547
+
1548
+ def test_should_clear_events
1549
+ assert_nil @object.state_event
1550
+ assert_nil @object.status_event
1551
+ end
1552
+
1553
+ def test_should_not_write_event_transitions
1554
+ assert_nil @object.send(:state_event_transition)
1555
+ assert_nil @object.send(:status_event_transition)
1556
+ end
1557
+ end
1558
+
1559
+ class AttributeTransitionCollectionWithEventTransitionsTest < Test::Unit::TestCase
1560
+ def setup
1561
+ @klass = Class.new
1562
+
1563
+ @state = StateMachine::Machine.new(@klass, :initial => :parked, :action => :save)
1564
+ @state.state :idling
1565
+ @state.event :ignite
1566
+
1567
+ @status = StateMachine::Machine.new(@klass, :status, :initial => :first_gear, :action => :save)
1568
+ @status.state :second_gear
1569
+ @status.event :shift_up
1570
+
1571
+ @object = @klass.new
1572
+ @object.send(:state_event_transition=, @state_transition = StateMachine::Transition.new(@object, @state, :ignite, :parked, :idling))
1573
+ @object.send(:status_event_transition=, @status_transition = StateMachine::Transition.new(@object, @status, :shift_up, :first_gear, :second_gear))
1574
+
1575
+ @transitions = StateMachine::AttributeTransitionCollection.new([@state_transition, @status_transition])
1576
+ @result = @transitions.perform
1577
+ end
1578
+
1579
+ def test_should_succeed
1580
+ assert_equal true, @result
1581
+ end
1582
+
1583
+ def test_should_persist_states
1584
+ assert_equal 'idling', @object.state
1585
+ assert_equal 'second_gear', @object.status
1586
+ end
1587
+
1588
+ def test_should_not_write_events
1589
+ assert_nil @object.state_event
1590
+ assert_nil @object.status_event
1591
+ end
1592
+
1593
+ def test_should_clear_event_transitions
1594
+ assert_nil @object.send(:state_event_transition)
1595
+ assert_nil @object.send(:status_event_transition)
1596
+ end
1597
+ end
1598
+
1599
+ class AttributeTransitionCollectionWithActionFailedTest < Test::Unit::TestCase
1600
+ def setup
1601
+ @klass = Class.new
1602
+
1603
+ @state = StateMachine::Machine.new(@klass, :initial => :parked, :action => :save)
1604
+ @state.state :idling
1605
+ @state.event :ignite
1606
+
1607
+ @status = StateMachine::Machine.new(@klass, :status, :initial => :first_gear, :action => :save)
1608
+ @status.state :second_gear
1609
+ @status.event :shift_up
1610
+
1611
+ @object = @klass.new
1612
+ @object.state_event = 'ignite'
1613
+ @object.status_event = 'shift_up'
1614
+
1615
+ @transitions = StateMachine::AttributeTransitionCollection.new([
1616
+ @state_transition = StateMachine::Transition.new(@object, @state, :ignite, :parked, :idling),
1617
+ @status_transition = StateMachine::Transition.new(@object, @status, :shift_up, :first_gear, :second_gear)
1618
+ ])
1619
+ @result = @transitions.perform { false }
1620
+ end
1621
+
1622
+ def test_should_not_succeed
1623
+ assert_equal false, @result
1624
+ end
1625
+
1626
+ def test_should_not_persist_states
1627
+ assert_equal 'parked', @object.state
1628
+ assert_equal 'first_gear', @object.status
1629
+ end
1630
+
1631
+ def test_should_not_clear_events
1632
+ assert_equal :ignite, @object.state_event
1633
+ assert_equal :shift_up, @object.status_event
1634
+ end
1635
+
1636
+ def test_should_not_write_event_transitions
1637
+ assert_nil @object.send(:state_event_transition)
1638
+ assert_nil @object.send(:status_event_transition)
1639
+ end
1640
+ end
1641
+
1642
+ class AttributeTransitionCollectionWithActionErrorTest < Test::Unit::TestCase
1643
+ def setup
1644
+ @klass = Class.new
1645
+
1646
+ @state = StateMachine::Machine.new(@klass, :initial => :parked, :action => :save)
1647
+ @state.state :idling
1648
+ @state.event :ignite
1649
+
1650
+ @status = StateMachine::Machine.new(@klass, :status, :initial => :first_gear, :action => :save)
1651
+ @status.state :second_gear
1652
+ @status.event :shift_up
1653
+
1654
+ @object = @klass.new
1655
+ @object.state_event = 'ignite'
1656
+ @object.status_event = 'shift_up'
1657
+
1658
+ @transitions = StateMachine::AttributeTransitionCollection.new([
1659
+ @state_transition = StateMachine::Transition.new(@object, @state, :ignite, :parked, :idling),
1660
+ @status_transition = StateMachine::Transition.new(@object, @status, :shift_up, :first_gear, :second_gear)
1661
+ ])
1662
+
1663
+ begin; @transitions.perform { raise ArgumentError }; rescue; end
1664
+ end
1665
+
1666
+ def test_should_not_persist_states
1667
+ assert_equal 'parked', @object.state
1668
+ assert_equal 'first_gear', @object.status
1669
+ end
1670
+
1671
+ def test_should_not_clear_events
1672
+ assert_equal :ignite, @object.state_event
1673
+ assert_equal :shift_up, @object.status_event
1674
+ end
1675
+
1676
+ def test_should_not_write_event_transitions
1677
+ assert_nil @object.send(:state_event_transition)
1678
+ assert_nil @object.send(:status_event_transition)
1679
+ end
1680
+ end
1681
+
1682
+ class AttributeTransitionCollectionWithCallbacksTest < Test::Unit::TestCase
1683
+ def setup
1684
+ @klass = Class.new
1685
+
1686
+ @state = StateMachine::Machine.new(@klass, :initial => :parked, :action => :save)
1687
+ @state.state :idling
1688
+ @state.event :ignite
1689
+
1690
+ @status = StateMachine::Machine.new(@klass, :status, :initial => :first_gear, :action => :save)
1691
+ @status.state :second_gear
1692
+ @status.event :shift_up
1693
+
1694
+ @object = @klass.new
1695
+
1696
+ @transitions = StateMachine::AttributeTransitionCollection.new([
1697
+ @state_transition = StateMachine::Transition.new(@object, @state, :ignite, :parked, :idling),
1698
+ @status_transition = StateMachine::Transition.new(@object, @status, :shift_up, :first_gear, :second_gear)
1699
+ ])
1700
+ end
1701
+
1702
+ def test_should_not_have_events_during_before_callbacks
1703
+ @state.before_transition {|object, transition| @before_state_event = object.state_event }
1704
+ @state.around_transition {|object, transition, block| @around_state_event = object.state_event; block.call }
1705
+ @transitions.perform
1706
+
1707
+ assert_nil @before_state_event
1708
+ assert_nil @around_state_event
1709
+ end
1710
+
1711
+ def test_should_not_have_events_during_action
1712
+ @transitions.perform { @state_event = @object.state_event }
1713
+
1714
+ assert_nil @state_event
1715
+ end
1716
+
1717
+ def test_should_not_have_events_during_after_callbacks
1718
+ @state.after_transition {|object, transition| @after_state_event = object.state_event }
1719
+ @state.around_transition {|object, transition, block| block.call; @around_state_event = object.state_event }
1720
+ @transitions.perform
1721
+
1722
+ assert_nil @state_event
1723
+ end
1724
+
1725
+ def test_should_not_have_event_transitions_during_before_callbacks
1726
+ @state.before_transition {|object, transition| @state_event_transition = object.send(:state_event_transition) }
1727
+ @transitions.perform
1728
+
1729
+ assert_nil @state_event_transition
1730
+ end
1731
+
1732
+ def test_should_not_have_event_transitions_during_action
1733
+ @transitions.perform { @state_event_transition = @object.send(:state_event_transition) }
1734
+
1735
+ assert_nil @state_event_transition
1736
+ end
1737
+
1738
+ def test_should_not_have_event_transitions_during_after_callbacks
1739
+ @state.after_transition {|object, transition| @after_state_event_transition = object.send(:state_event_transition) }
1740
+ @state.around_transition {|object, transition, block| block.call; @around_state_event_transition = object.send(:state_event_transition) }
1741
+ @transitions.perform
1742
+
1743
+ assert_nil @after_state_event_transition
1744
+ assert_nil @around_state_event_transition
1745
+ end
1746
+ end
1747
+
1748
+ class AttributeTransitionCollectionWithBeforeCallbackHaltTest < Test::Unit::TestCase
1749
+ def setup
1750
+ @klass = Class.new
1751
+
1752
+ @machine = StateMachine::Machine.new(@klass, :initial => :parked, :action => :save)
1753
+ @machine.state :idling
1754
+ @machine.event :ignite
1755
+
1756
+ @machine.before_transition {throw :halt}
1757
+
1758
+ @object = @klass.new
1759
+ @object.state_event = 'ignite'
1760
+
1761
+ @transitions = StateMachine::AttributeTransitionCollection.new([
1762
+ StateMachine::Transition.new(@object, @machine, :ignite, :parked, :idling)
1763
+ ])
1764
+ @result = @transitions.perform
1765
+ end
1766
+
1767
+ def test_should_not_succeed
1768
+ assert_equal false, @result
1769
+ end
1770
+
1771
+ def test_should_not_clear_event
1772
+ assert_equal :ignite, @object.state_event
1773
+ end
1774
+
1775
+ def test_should_not_write_event_transition
1776
+ assert_nil @object.send(:state_event_transition)
1777
+ end
1778
+ end
1779
+
1780
+ class AttributeTransitionCollectionWithBeforeCallbackErrorTest < Test::Unit::TestCase
1781
+ def setup
1782
+ @klass = Class.new
1783
+
1784
+ @machine = StateMachine::Machine.new(@klass, :initial => :parked, :action => :save)
1785
+ @machine.state :idling
1786
+ @machine.event :ignite
1787
+
1788
+ @machine.before_transition {raise ArgumentError}
1789
+
1790
+ @object = @klass.new
1791
+ @object.state_event = 'ignite'
1792
+
1793
+ @transitions = StateMachine::AttributeTransitionCollection.new([
1794
+ StateMachine::Transition.new(@object, @machine, :ignite, :parked, :idling)
1795
+ ])
1796
+ begin; @transitions.perform; rescue; end
1797
+ end
1798
+
1799
+ def test_should_not_clear_event
1800
+ assert_equal :ignite, @object.state_event
1801
+ end
1802
+
1803
+ def test_should_not_write_event_transition
1804
+ assert_nil @object.send(:state_event_transition)
1805
+ end
1806
+ end
1807
+
1808
+ class AttributeTransitionCollectionWithAroundCallbackBeforeYieldHaltTest < Test::Unit::TestCase
1809
+ def setup
1810
+ @klass = Class.new
1811
+
1812
+ @machine = StateMachine::Machine.new(@klass, :initial => :parked, :action => :save)
1813
+ @machine.state :idling
1814
+ @machine.event :ignite
1815
+
1816
+ @machine.around_transition {throw :halt}
1817
+
1818
+ @object = @klass.new
1819
+ @object.state_event = 'ignite'
1820
+
1821
+ @transitions = StateMachine::AttributeTransitionCollection.new([
1822
+ StateMachine::Transition.new(@object, @machine, :ignite, :parked, :idling)
1823
+ ])
1824
+ @result = @transitions.perform
1825
+ end
1826
+
1827
+ def test_should_not_succeed
1828
+ assert_equal false, @result
1829
+ end
1830
+
1831
+ def test_should_not_clear_event
1832
+ assert_equal :ignite, @object.state_event
1833
+ end
1834
+
1835
+ def test_should_not_write_event_transition
1836
+ assert_nil @object.send(:state_event_transition)
1837
+ end
1838
+ end
1839
+
1840
+ class AttributeTransitionCollectionWithAroundAfterYieldCallbackErrorTest < Test::Unit::TestCase
1841
+ def setup
1842
+ @klass = Class.new
1843
+
1844
+ @machine = StateMachine::Machine.new(@klass, :initial => :parked, :action => :save)
1845
+ @machine.state :idling
1846
+ @machine.event :ignite
1847
+
1848
+ @machine.before_transition {raise ArgumentError}
1849
+
1850
+ @object = @klass.new
1851
+ @object.state_event = 'ignite'
1852
+
1853
+ @transitions = StateMachine::AttributeTransitionCollection.new([
1854
+ StateMachine::Transition.new(@object, @machine, :ignite, :parked, :idling)
1855
+ ])
1856
+ begin; @transitions.perform; rescue; end
1857
+ end
1858
+
1859
+ def test_should_not_clear_event
1860
+ assert_equal :ignite, @object.state_event
1861
+ end
1862
+
1863
+ def test_should_not_write_event_transition
1864
+ assert_nil @object.send(:state_event_transition)
1865
+ end
1866
+ end
1867
+
1868
+ class AttributeTransitionCollectionWithSkippedAfterCallbacksTest < Test::Unit::TestCase
1869
+ def setup
1870
+ @klass = Class.new
1871
+
1872
+ @state = StateMachine::Machine.new(@klass, :initial => :parked, :action => :save)
1873
+ @state.state :idling
1874
+ @state.event :ignite
1875
+
1876
+ @status = StateMachine::Machine.new(@klass, :status, :initial => :first_gear, :action => :save)
1877
+ @status.state :second_gear
1878
+ @status.event :shift_up
1879
+
1880
+ @object = @klass.new
1881
+ @object.state_event = 'ignite'
1882
+ @object.status_event = 'shift_up'
1883
+
1884
+ @transitions = StateMachine::AttributeTransitionCollection.new([
1885
+ @state_transition = StateMachine::Transition.new(@object, @state, :ignite, :parked, :idling),
1886
+ @status_transition = StateMachine::Transition.new(@object, @status, :shift_up, :first_gear, :second_gear)
1887
+ ], :after => false)
1888
+ end
1889
+
1890
+ def test_should_clear_events
1891
+ @transitions.perform
1892
+ assert_nil @object.state_event
1893
+ assert_nil @object.status_event
1894
+ end
1895
+
1896
+ def test_should_write_event_transitions_if_success
1897
+ @transitions.perform { true }
1898
+ assert_equal @state_transition, @object.send(:state_event_transition)
1899
+ assert_equal @status_transition, @object.send(:status_event_transition)
1900
+ end
1901
+
1902
+ def test_should_not_write_event_transitions_if_failed
1903
+ @transitions.perform { false }
1904
+ assert_nil @object.send(:state_event_transition)
1905
+ assert_nil @object.send(:status_event_transition)
1906
+ end
1907
+ end
1908
+
1909
+ class AttributeTransitionCollectionWithAfterCallbackHaltTest < Test::Unit::TestCase
1910
+ def setup
1911
+ @klass = Class.new
1912
+
1913
+ @machine = StateMachine::Machine.new(@klass, :initial => :parked, :action => :save)
1914
+ @machine.state :idling
1915
+ @machine.event :ignite
1916
+
1917
+ @machine.after_transition {throw :halt}
1918
+
1919
+ @object = @klass.new
1920
+ @object.state_event = 'ignite'
1921
+
1922
+ @transitions = StateMachine::AttributeTransitionCollection.new([
1923
+ StateMachine::Transition.new(@object, @machine, :ignite, :parked, :idling)
1924
+ ])
1925
+ @result = @transitions.perform
1926
+ end
1927
+
1928
+ def test_should_succeed
1929
+ assert_equal true, @result
1930
+ end
1931
+
1932
+ def test_should_clear_event
1933
+ assert_nil @object.state_event
1934
+ end
1935
+
1936
+ def test_should_not_write_event_transition
1937
+ assert_nil @object.send(:state_event_transition)
1938
+ end
1939
+ end
1940
+
1941
+ class AttributeTransitionCollectionWithAfterCallbackErrorTest < Test::Unit::TestCase
1942
+ def setup
1943
+ @klass = Class.new
1944
+
1945
+ @machine = StateMachine::Machine.new(@klass, :initial => :parked, :action => :save)
1946
+ @machine.state :idling
1947
+ @machine.event :ignite
1948
+
1949
+ @machine.after_transition {raise ArgumentError}
1950
+
1951
+ @object = @klass.new
1952
+ @object.state_event = 'ignite'
1953
+
1954
+ @transitions = StateMachine::AttributeTransitionCollection.new([
1955
+ StateMachine::Transition.new(@object, @machine, :ignite, :parked, :idling)
1956
+ ])
1957
+ begin; @transitions.perform; rescue; end
1958
+ end
1959
+
1960
+ def test_should_clear_event
1961
+ assert_nil @object.state_event
1962
+ end
1963
+
1964
+ def test_should_not_write_event_transition
1965
+ assert_nil @object.send(:state_event_transition)
1966
+ end
1967
+ end
1968
+
1969
+ class AttributeTransitionCollectionWithAroundCallbackAfterYieldHaltTest < Test::Unit::TestCase
1970
+ def setup
1971
+ @klass = Class.new
1972
+
1973
+ @machine = StateMachine::Machine.new(@klass, :initial => :parked, :action => :save)
1974
+ @machine.state :idling
1975
+ @machine.event :ignite
1976
+
1977
+ @machine.around_transition {|block| block.call; throw :halt}
1978
+
1979
+ @object = @klass.new
1980
+ @object.state_event = 'ignite'
1981
+
1982
+ @transitions = StateMachine::AttributeTransitionCollection.new([
1983
+ StateMachine::Transition.new(@object, @machine, :ignite, :parked, :idling)
1984
+ ])
1985
+ @result = @transitions.perform
1986
+ end
1987
+
1988
+ def test_should_succeed
1989
+ assert_equal true, @result
1990
+ end
1991
+
1992
+ def test_should_clear_event
1993
+ assert_nil @object.state_event
1994
+ end
1995
+
1996
+ def test_should_not_write_event_transition
1997
+ assert_nil @object.send(:state_event_transition)
1998
+ end
1999
+ end
2000
+
2001
+ class AttributeTransitionCollectionWithAfterCallbackErrorTest < Test::Unit::TestCase
2002
+ def setup
2003
+ @klass = Class.new
2004
+
2005
+ @machine = StateMachine::Machine.new(@klass, :initial => :parked, :action => :save)
2006
+ @machine.state :idling
2007
+ @machine.event :ignite
2008
+
2009
+ @machine.around_transition {|block| block.call; raise ArgumentError}
2010
+
2011
+ @object = @klass.new
2012
+ @object.state_event = 'ignite'
2013
+
2014
+ @transitions = StateMachine::AttributeTransitionCollection.new([
2015
+ StateMachine::Transition.new(@object, @machine, :ignite, :parked, :idling)
2016
+ ])
2017
+ begin; @transitions.perform; rescue; end
2018
+ end
2019
+
2020
+ def test_should_clear_event
2021
+ assert_nil @object.state_event
2022
+ end
2023
+
2024
+ def test_should_not_write_event_transition
2025
+ assert_nil @object.send(:state_event_transition)
2026
+ end
2027
+ end
2028
+
2029
+ class AttributeTransitionCollectionMarshallingTest < Test::Unit::TestCase
2030
+ def setup
2031
+ @klass = Class.new
2032
+ self.class.const_set('Example', @klass)
2033
+
2034
+ @machine = StateMachine::Machine.new(@klass, :initial => :parked, :action => :save)
2035
+ @machine.state :idling
2036
+ @machine.event :ignite
2037
+
2038
+ @object = @klass.new
2039
+ @object.state_event = 'ignite'
2040
+ end
2041
+
2042
+ def test_should_marshal_during_before_callbacks
2043
+ @machine.before_transition {|object, transition| Marshal.dump(object)}
2044
+ assert_nothing_raised do
2045
+ transitions(:after => false).perform { true }
2046
+ transitions.perform { true }
2047
+ end
2048
+ end
2049
+
2050
+ def test_should_marshal_during_action
2051
+ assert_nothing_raised do
2052
+ transitions(:after => false).perform do
2053
+ Marshal.dump(@object)
2054
+ true
2055
+ end
2056
+
2057
+ transitions.perform do
2058
+ Marshal.dump(@object)
2059
+ true
2060
+ end
2061
+ end
2062
+ end
2063
+
2064
+ def test_should_marshal_during_after_callbacks
2065
+ @machine.after_transition {|object, transition| Marshal.dump(object)}
2066
+ assert_nothing_raised do
2067
+ transitions(:after => false).perform { true }
2068
+ transitions.perform { true }
2069
+ end
2070
+ end
2071
+
2072
+ def test_should_marshal_during_around_callbacks_before_yield
2073
+ @machine.around_transition {|object, transition, block| Marshal.dump(object); block.call}
2074
+ assert_nothing_raised do
2075
+ transitions(:after => false).perform { true }
2076
+ transitions.perform { true }
2077
+ end
2078
+ end
2079
+
2080
+ def test_should_marshal_during_around_callbacks_after_yield
2081
+ @machine.around_transition {|object, transition, block| block.call; Marshal.dump(object)}
2082
+ assert_nothing_raised do
2083
+ transitions(:after => false).perform { true }
2084
+ transitions.perform { true }
2085
+ end
2086
+ end
2087
+
2088
+ def teardown
2089
+ self.class.send(:remove_const, 'Example')
2090
+ end
2091
+
2092
+ private
2093
+ def transitions(options = {})
2094
+ StateMachine::AttributeTransitionCollection.new([
2095
+ StateMachine::Transition.new(@object, @machine, :ignite, :parked, :idling)
2096
+ ], options)
2097
+ end
2098
+ end