hsume2-state_machine 1.0.1

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 (110) hide show
  1. data/CHANGELOG.rdoc +413 -0
  2. data/LICENSE +20 -0
  3. data/README.rdoc +717 -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.rb +448 -0
  28. data/lib/state_machine/alternate_machine.rb +79 -0
  29. data/lib/state_machine/assertions.rb +36 -0
  30. data/lib/state_machine/branch.rb +224 -0
  31. data/lib/state_machine/callback.rb +236 -0
  32. data/lib/state_machine/condition_proxy.rb +94 -0
  33. data/lib/state_machine/error.rb +13 -0
  34. data/lib/state_machine/eval_helpers.rb +86 -0
  35. data/lib/state_machine/event.rb +304 -0
  36. data/lib/state_machine/event_collection.rb +139 -0
  37. data/lib/state_machine/extensions.rb +149 -0
  38. data/lib/state_machine/initializers.rb +4 -0
  39. data/lib/state_machine/initializers/merb.rb +1 -0
  40. data/lib/state_machine/initializers/rails.rb +25 -0
  41. data/lib/state_machine/integrations.rb +110 -0
  42. data/lib/state_machine/integrations/active_model.rb +502 -0
  43. data/lib/state_machine/integrations/active_model/locale.rb +11 -0
  44. data/lib/state_machine/integrations/active_model/observer.rb +45 -0
  45. data/lib/state_machine/integrations/active_model/versions.rb +31 -0
  46. data/lib/state_machine/integrations/active_record.rb +424 -0
  47. data/lib/state_machine/integrations/active_record/locale.rb +20 -0
  48. data/lib/state_machine/integrations/active_record/versions.rb +143 -0
  49. data/lib/state_machine/integrations/base.rb +91 -0
  50. data/lib/state_machine/integrations/data_mapper.rb +392 -0
  51. data/lib/state_machine/integrations/data_mapper/observer.rb +210 -0
  52. data/lib/state_machine/integrations/data_mapper/versions.rb +62 -0
  53. data/lib/state_machine/integrations/mongo_mapper.rb +272 -0
  54. data/lib/state_machine/integrations/mongo_mapper/locale.rb +4 -0
  55. data/lib/state_machine/integrations/mongo_mapper/versions.rb +110 -0
  56. data/lib/state_machine/integrations/mongoid.rb +357 -0
  57. data/lib/state_machine/integrations/mongoid/locale.rb +4 -0
  58. data/lib/state_machine/integrations/mongoid/versions.rb +18 -0
  59. data/lib/state_machine/integrations/sequel.rb +428 -0
  60. data/lib/state_machine/integrations/sequel/versions.rb +36 -0
  61. data/lib/state_machine/machine.rb +1873 -0
  62. data/lib/state_machine/machine_collection.rb +87 -0
  63. data/lib/state_machine/matcher.rb +123 -0
  64. data/lib/state_machine/matcher_helpers.rb +54 -0
  65. data/lib/state_machine/node_collection.rb +157 -0
  66. data/lib/state_machine/path.rb +120 -0
  67. data/lib/state_machine/path_collection.rb +90 -0
  68. data/lib/state_machine/state.rb +271 -0
  69. data/lib/state_machine/state_collection.rb +112 -0
  70. data/lib/state_machine/transition.rb +458 -0
  71. data/lib/state_machine/transition_collection.rb +244 -0
  72. data/lib/tasks/state_machine.rake +1 -0
  73. data/lib/tasks/state_machine.rb +27 -0
  74. data/test/files/en.yml +17 -0
  75. data/test/files/switch.rb +11 -0
  76. data/test/functional/alternate_state_machine_test.rb +122 -0
  77. data/test/functional/state_machine_test.rb +993 -0
  78. data/test/test_helper.rb +4 -0
  79. data/test/unit/assertions_test.rb +40 -0
  80. data/test/unit/branch_test.rb +890 -0
  81. data/test/unit/callback_test.rb +701 -0
  82. data/test/unit/condition_proxy_test.rb +328 -0
  83. data/test/unit/error_test.rb +43 -0
  84. data/test/unit/eval_helpers_test.rb +222 -0
  85. data/test/unit/event_collection_test.rb +358 -0
  86. data/test/unit/event_test.rb +985 -0
  87. data/test/unit/integrations/active_model_test.rb +1097 -0
  88. data/test/unit/integrations/active_record_test.rb +2021 -0
  89. data/test/unit/integrations/base_test.rb +99 -0
  90. data/test/unit/integrations/data_mapper_test.rb +1909 -0
  91. data/test/unit/integrations/mongo_mapper_test.rb +1611 -0
  92. data/test/unit/integrations/mongoid_test.rb +1591 -0
  93. data/test/unit/integrations/sequel_test.rb +1523 -0
  94. data/test/unit/integrations_test.rb +61 -0
  95. data/test/unit/invalid_event_test.rb +20 -0
  96. data/test/unit/invalid_parallel_transition_test.rb +18 -0
  97. data/test/unit/invalid_transition_test.rb +77 -0
  98. data/test/unit/machine_collection_test.rb +599 -0
  99. data/test/unit/machine_test.rb +3043 -0
  100. data/test/unit/matcher_helpers_test.rb +37 -0
  101. data/test/unit/matcher_test.rb +155 -0
  102. data/test/unit/node_collection_test.rb +217 -0
  103. data/test/unit/path_collection_test.rb +266 -0
  104. data/test/unit/path_test.rb +485 -0
  105. data/test/unit/state_collection_test.rb +310 -0
  106. data/test/unit/state_machine_test.rb +31 -0
  107. data/test/unit/state_test.rb +924 -0
  108. data/test/unit/transition_collection_test.rb +2102 -0
  109. data/test/unit/transition_test.rb +1541 -0
  110. metadata +207 -0
@@ -0,0 +1,2102 @@
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_failure { @callbacks << :state_after }
650
+ @status.after_failure { @callbacks << :status_after }
651
+
652
+ @transitions.perform
653
+ assert_equal [:status_after, :state_after], @callbacks
654
+ end
655
+
656
+ def test_should_run_after_failure_callbacks_if_action_fails_for_second_transition
657
+ @klass.class_eval do
658
+ def save_status
659
+ false
660
+ end
661
+ end
662
+
663
+ @callbacks = []
664
+ @state.after_failure { @callbacks << :state_after }
665
+ @status.after_failure { @callbacks << :status_after }
666
+
667
+ @transitions.perform
668
+ assert_equal [:status_after, :state_after], @callbacks
669
+ end
670
+ end
671
+
672
+ class TransitionCollectionWithMixedActionsTest < Test::Unit::TestCase
673
+ def setup
674
+ @klass = Class.new do
675
+ def save
676
+ true
677
+ end
678
+ end
679
+
680
+ @state = StateMachine::Machine.new(@klass, :initial => :parked, :action => :save)
681
+ @state.state :idling
682
+ @state.event :ignite
683
+
684
+ @status = StateMachine::Machine.new(@klass, :status, :initial => :first_gear)
685
+ @status.state :second_gear
686
+ @status.event :shift_up
687
+
688
+ @object = @klass.new
689
+
690
+ @transitions = StateMachine::TransitionCollection.new([
691
+ @state_transition = StateMachine::Transition.new(@object, @state, :ignite, :parked, :idling),
692
+ @status_transition = StateMachine::Transition.new(@object, @status, :shift_up, :first_gear, :second_gear)
693
+ ])
694
+ @result = @transitions.perform
695
+ end
696
+
697
+ def test_should_succeed
698
+ assert_equal true, @result
699
+ end
700
+
701
+ def test_should_persist_states
702
+ assert_equal 'idling', @object.state
703
+ assert_equal 'second_gear', @object.status
704
+ end
705
+
706
+ def test_should_store_results_in_transitions
707
+ assert_equal true, @state_transition.result
708
+ assert_nil @status_transition.result
709
+ end
710
+ end
711
+
712
+ class TransitionCollectionWithBlockTest < Test::Unit::TestCase
713
+ def setup
714
+ @klass = Class.new do
715
+ attr_reader :actions
716
+
717
+ def save
718
+ (@actions ||= []) << :save
719
+ end
720
+ end
721
+
722
+ @state = StateMachine::Machine.new(@klass, :state, :initial => :parked, :action => :save)
723
+ @state.state :idling
724
+ @state.event :ignite
725
+
726
+ @status = StateMachine::Machine.new(@klass, :status, :initial => :first_gear, :action => :save)
727
+ @status.state :second_gear
728
+ @status.event :shift_up
729
+
730
+ @object = @klass.new
731
+ @transitions = StateMachine::TransitionCollection.new([
732
+ @state_transition = StateMachine::Transition.new(@object, @state, :ignite, :parked, :idling),
733
+ @status_transition = StateMachine::Transition.new(@object, @status, :shift_up, :first_gear, :second_gear)
734
+ ])
735
+ @result = @transitions.perform { 1 }
736
+ end
737
+
738
+ def test_should_succeed
739
+ assert_equal 1, @result
740
+ end
741
+
742
+ def test_should_persist_states
743
+ assert_equal 'idling', @object.state
744
+ assert_equal 'second_gear', @object.status
745
+ end
746
+
747
+ def test_should_not_run_machine_actions
748
+ assert_nil @object.actions
749
+ end
750
+
751
+ def test_should_use_result_as_transition_result
752
+ assert_equal 1, @state_transition.result
753
+ assert_equal 1, @status_transition.result
754
+ end
755
+ end
756
+
757
+ class TransitionCollectionWithActionFailedTest < Test::Unit::TestCase
758
+ def setup
759
+ @klass = Class.new do
760
+ def save
761
+ false
762
+ end
763
+ end
764
+ @before_count = 0
765
+ @around_before_count = 0
766
+ @after_count = 0
767
+ @around_after_count = 0
768
+ @failure_count = 0
769
+
770
+ @machine = StateMachine::Machine.new(@klass, :initial => :parked, :action => :save)
771
+ @machine.state :idling
772
+ @machine.event :ignite
773
+
774
+ @machine.before_transition {@before_count += 1}
775
+ @machine.after_transition {@after_count += 1}
776
+ @machine.around_transition {|block| @around_before_count += 1; block.call; @around_after_count += 1}
777
+ @machine.after_failure {@failure_count += 1}
778
+
779
+ @object = @klass.new
780
+
781
+ @transitions = StateMachine::TransitionCollection.new([
782
+ StateMachine::Transition.new(@object, @machine, :ignite, :parked, :idling)
783
+ ])
784
+ @result = @transitions.perform
785
+ end
786
+
787
+ def test_should_not_succeed
788
+ assert_equal false, @result
789
+ end
790
+
791
+ def test_should_not_persist_state
792
+ assert_equal 'parked', @object.state
793
+ end
794
+
795
+ def test_should_run_before_callbacks
796
+ assert_equal 1, @before_count
797
+ end
798
+
799
+ def test_should_run_around_callbacks_before_yield
800
+ assert_equal 1, @around_before_count
801
+ end
802
+
803
+ def test_should_not_run_after_callbacks
804
+ assert_equal 0, @after_count
805
+ end
806
+
807
+ def test_should_not_run_around_callbacks
808
+ assert_equal 0, @around_after_count
809
+ end
810
+
811
+ def test_should_run_failure_callbacks
812
+ assert_equal 1, @failure_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
+ @failure_count = 0
828
+
829
+ @machine = StateMachine::Machine.new(@klass, :initial => :parked, :action => :save)
830
+ @machine.state :idling
831
+ @machine.event :ignite
832
+
833
+ @machine.before_transition {@before_count += 1}
834
+ @machine.after_transition {@after_count += 1}
835
+ @machine.around_transition {|block| @around_before_count += 1; block.call; @around_after_count += 1}
836
+ @machine.after_failure {@failure_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 1, @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
+
876
+ def test_should_not_run_failure_callbacks
877
+ assert_equal 0, @failure_count
878
+ end
879
+ end
880
+
881
+ class TransitionCollectionWithCallbacksTest < Test::Unit::TestCase
882
+ def setup
883
+ @klass = Class.new do
884
+ attr_reader :saved
885
+
886
+ def save
887
+ @saved = true
888
+ end
889
+ end
890
+
891
+ @before_callbacks = []
892
+ @after_callbacks = []
893
+
894
+ @state = StateMachine::Machine.new(@klass, :initial => :parked, :action => :save)
895
+ @state.state :idling
896
+ @state.event :ignite
897
+ @state.before_transition {@before_callbacks << :state_before}
898
+ @state.after_transition {@after_callbacks << :state_after}
899
+ @state.around_transition {|block| @before_callbacks << :state_around; block.call; @after_callbacks << :state_around}
900
+
901
+ @status = StateMachine::Machine.new(@klass, :status, :initial => :first_gear, :action => :save)
902
+ @status.state :second_gear
903
+ @status.event :shift_up
904
+ @status.before_transition {@before_callbacks << :status_before}
905
+ @status.after_transition {@after_callbacks << :status_after}
906
+ @status.around_transition {|block| @before_callbacks << :status_around; block.call; @after_callbacks << :status_around}
907
+
908
+ @object = @klass.new
909
+ @transitions = StateMachine::TransitionCollection.new([
910
+ StateMachine::Transition.new(@object, @state, :ignite, :parked, :idling),
911
+ StateMachine::Transition.new(@object, @status, :shift_up, :first_gear, :second_gear)
912
+ ])
913
+ end
914
+
915
+ def test_should_run_before_callbacks_in_order
916
+ @transitions.perform
917
+ assert_equal [:state_before, :state_around, :status_before, :status_around], @before_callbacks
918
+ end
919
+
920
+ def test_should_halt_if_before_callback_halted_for_first_transition
921
+ @state.before_transition {throw :halt}
922
+
923
+ assert_equal false, @transitions.perform
924
+ assert_equal [:state_before, :state_around], @before_callbacks
925
+ end
926
+
927
+ def test_should_halt_if_before_callback_halted_for_second_transition
928
+ @status.before_transition {throw :halt}
929
+
930
+ assert_equal false, @transitions.perform
931
+ assert_equal [:state_before, :state_around, :status_before, :status_around], @before_callbacks
932
+ end
933
+
934
+ def test_should_halt_if_around_callback_halted_before_yield_for_first_transition
935
+ @state.around_transition {throw :halt}
936
+
937
+ assert_equal false, @transitions.perform
938
+ assert_equal [:state_before, :state_around], @before_callbacks
939
+ end
940
+
941
+ def test_should_halt_if_around_callback_halted_before_yield_for_second_transition
942
+ @status.around_transition {throw :halt}
943
+
944
+ assert_equal false, @transitions.perform
945
+ assert_equal [:state_before, :state_around, :status_before, :status_around], @before_callbacks
946
+ end
947
+
948
+ def test_should_run_after_callbacks_in_reverse_order
949
+ @transitions.perform
950
+ assert_equal [:status_around, :status_after, :state_around, :state_after], @after_callbacks
951
+ end
952
+
953
+ def test_should_not_halt_if_after_callback_halted_for_first_transition
954
+ @state.after_transition {throw :halt}
955
+
956
+ assert_equal true, @transitions.perform
957
+ assert_equal [:status_around, :status_after, :state_around, :state_after], @after_callbacks
958
+ end
959
+
960
+ def test_should_not_halt_if_around_callback_halted_for_second_transition
961
+ @status.around_transition {|block| block.call; throw :halt}
962
+
963
+ assert_equal true, @transitions.perform
964
+ assert_equal [:state_around, :state_after], @after_callbacks
965
+ end
966
+
967
+ def test_should_run_before_callbacks_before_persisting_the_state
968
+ @state.before_transition {|object| @before_state = object.state}
969
+ @state.around_transition {|object, transition, block| @around_state = object.state; block.call}
970
+ @transitions.perform
971
+
972
+ assert_equal 'parked', @before_state
973
+ assert_equal 'parked', @around_state
974
+ end
975
+
976
+ def test_should_persist_state_before_running_action
977
+ @klass.class_eval do
978
+ attr_reader :saved_on_persist
979
+
980
+ def state=(value)
981
+ @state = value
982
+ @saved_on_persist = @saved
983
+ end
984
+ end
985
+
986
+ @transitions.perform
987
+ assert !@object.saved_on_persist
988
+ end
989
+
990
+ def test_should_persist_state_before_running_action_block
991
+ @klass.class_eval do
992
+ attr_writer :saved
993
+ attr_reader :saved_on_persist
994
+
995
+ def state=(value)
996
+ @state = value
997
+ @saved_on_persist = @saved
998
+ end
999
+ end
1000
+
1001
+ @transitions.perform { @object.saved = true }
1002
+ assert !@object.saved_on_persist
1003
+ end
1004
+
1005
+ def test_should_run_after_callbacks_after_running_the_action
1006
+ @state.after_transition {|object| @after_saved = object.saved}
1007
+ @state.around_transition {|object, transition, block| block.call; @around_saved = object.saved}
1008
+ @transitions.perform
1009
+
1010
+ assert @after_saved
1011
+ assert @around_saved
1012
+ end
1013
+ end
1014
+
1015
+ class TransitionCollectionWithBeforeCallbackHaltTest < Test::Unit::TestCase
1016
+ def setup
1017
+ @klass = Class.new do
1018
+ attr_reader :saved
1019
+
1020
+ def save
1021
+ @saved = true
1022
+ end
1023
+ end
1024
+ @before_count = 0
1025
+ @after_count = 0
1026
+
1027
+ @machine = StateMachine::Machine.new(@klass, :initial => :parked, :action => :save)
1028
+ @machine.state :idling
1029
+ @machine.event :ignite
1030
+
1031
+ @machine.before_transition {@before_count += 1; throw :halt}
1032
+ @machine.before_transition {@before_count += 1}
1033
+ @machine.after_transition {@after_count += 1}
1034
+ @machine.around_transition {|block| @before_count += 1; block.call; @after_count += 1}
1035
+
1036
+ @object = @klass.new
1037
+
1038
+ @transitions = StateMachine::TransitionCollection.new([
1039
+ StateMachine::Transition.new(@object, @machine, :ignite, :parked, :idling)
1040
+ ])
1041
+ @result = @transitions.perform
1042
+ end
1043
+
1044
+ def test_should_not_succeed
1045
+ assert_equal false, @result
1046
+ end
1047
+
1048
+ def test_should_not_persist_state
1049
+ assert_equal 'parked', @object.state
1050
+ end
1051
+
1052
+ def test_should_not_run_action
1053
+ assert !@object.saved
1054
+ end
1055
+
1056
+ def test_should_not_run_further_before_callbacks
1057
+ assert_equal 1, @before_count
1058
+ end
1059
+
1060
+ def test_should_not_run_after_callbacks
1061
+ assert_equal 0, @after_count
1062
+ end
1063
+ end
1064
+
1065
+ class TransitionCollectionWithAfterCallbackHaltTest < Test::Unit::TestCase
1066
+ def setup
1067
+ @klass = Class.new do
1068
+ attr_reader :saved
1069
+
1070
+ def save
1071
+ @saved = true
1072
+ end
1073
+ end
1074
+ @before_count = 0
1075
+ @after_count = 0
1076
+
1077
+ @machine = StateMachine::Machine.new(@klass, :initial => :parked, :action => :save)
1078
+ @machine.state :idling
1079
+ @machine.event :ignite
1080
+
1081
+ @machine.before_transition {@before_count += 1}
1082
+ @machine.after_transition {@after_count += 1; throw :halt}
1083
+ @machine.after_transition {@after_count += 1}
1084
+ @machine.around_transition {|block| @before_count += 1; block.call; @after_count += 1}
1085
+
1086
+ @object = @klass.new
1087
+
1088
+ @transitions = StateMachine::TransitionCollection.new([
1089
+ StateMachine::Transition.new(@object, @machine, :ignite, :parked, :idling)
1090
+ ])
1091
+ @result = @transitions.perform
1092
+ end
1093
+
1094
+ def test_should_succeed
1095
+ assert_equal true, @result
1096
+ end
1097
+
1098
+ def test_should_persist_state
1099
+ assert_equal 'idling', @object.state
1100
+ end
1101
+
1102
+ def test_should_run_before_callbacks
1103
+ assert_equal 2, @before_count
1104
+ end
1105
+
1106
+ def test_should_not_run_further_after_callbacks
1107
+ assert_equal 2, @after_count
1108
+ end
1109
+ end
1110
+
1111
+ class TransitionCollectionWithSkippedAfterCallbacksTest < Test::Unit::TestCase
1112
+ def setup
1113
+ @klass = Class.new
1114
+
1115
+ @machine = StateMachine::Machine.new(@klass, :initial => :parked)
1116
+ @machine.state :idling
1117
+ @machine.event :ignite
1118
+ @machine.after_transition {@ran_after = true}
1119
+ @machine.around_transition {|block| @ran_around_before = true; block.call; @ran_around_after = true}
1120
+
1121
+ @object = @klass.new
1122
+
1123
+ @transitions = StateMachine::TransitionCollection.new([
1124
+ @transition = StateMachine::Transition.new(@object, @machine, :ignite, :parked, :idling)
1125
+ ], :after => false)
1126
+ @result = @transitions.perform
1127
+ end
1128
+
1129
+ def test_should_succeed
1130
+ assert_equal true, @result
1131
+ end
1132
+
1133
+ def test_should_not_run_after_callbacks
1134
+ assert !@ran_after
1135
+ end
1136
+
1137
+ def test_should_not_run_around_callbacks_after_yield
1138
+ assert !@ran_around_after
1139
+ end
1140
+
1141
+ def test_should_run_after_callbacks_on_subsequent_perform
1142
+ StateMachine::TransitionCollection.new([@transition]).perform
1143
+ assert @ran_after
1144
+ end
1145
+
1146
+ def test_should_run_around_callbacks_after_yield_on_subsequent_perform
1147
+ StateMachine::TransitionCollection.new([@transition]).perform
1148
+ assert @ran_around_after
1149
+ end
1150
+
1151
+ def test_should_not_rerun_around_callbacks_before_yield_on_subsequent_perform
1152
+ @ran_around_before = false
1153
+ StateMachine::TransitionCollection.new([@transition]).perform
1154
+
1155
+ assert !@ran_around_before
1156
+ end
1157
+ end
1158
+
1159
+ class TransitionCollectionWithActionHookBaseTest < Test::Unit::TestCase
1160
+ def setup
1161
+ @superclass = Class.new do
1162
+ def save
1163
+ true
1164
+ end
1165
+ end
1166
+
1167
+ @klass = Class.new(@superclass) do
1168
+ attr_reader :saved, :state_on_save, :state_event_on_save, :state_event_transition_on_save
1169
+
1170
+ def save
1171
+ @saved = true
1172
+ @state_on_save = state
1173
+ @state_event_on_save = state_event
1174
+ @state_event_transition_on_save = state_event_transition
1175
+ super
1176
+ end
1177
+ end
1178
+
1179
+ @machine = StateMachine::Machine.new(@klass, :initial => :parked, :action => :save)
1180
+ @machine.state :idling
1181
+ @machine.event :ignite
1182
+
1183
+ @object = @klass.new
1184
+
1185
+ @transition = StateMachine::Transition.new(@object, @machine, :ignite, :parked, :idling)
1186
+ end
1187
+
1188
+ def default_test
1189
+ end
1190
+ end
1191
+
1192
+ class TransitionCollectionWithActionHookAndSkippedActionTest < TransitionCollectionWithActionHookBaseTest
1193
+ def setup
1194
+ super
1195
+ @result = StateMachine::TransitionCollection.new([@transition], :actions => false).perform
1196
+ end
1197
+
1198
+ def test_should_succeed
1199
+ assert_equal true, @result
1200
+ end
1201
+
1202
+ def test_should_not_run_action
1203
+ assert !@object.saved
1204
+ end
1205
+ end
1206
+
1207
+ class TransitionCollectionWithActionHookAndSkippedAfterCallbacksTest < TransitionCollectionWithActionHookBaseTest
1208
+ def setup
1209
+ super
1210
+ @result = StateMachine::TransitionCollection.new([@transition], :after => false).perform
1211
+ end
1212
+
1213
+ def test_should_succeed
1214
+ assert_equal true, @result
1215
+ end
1216
+
1217
+ def test_should_run_action
1218
+ assert @object.saved
1219
+ end
1220
+
1221
+ def test_should_have_already_persisted_when_running_action
1222
+ assert_equal 'idling', @object.state_on_save
1223
+ end
1224
+
1225
+ def test_should_not_have_event_during_action
1226
+ assert_nil @object.state_event_on_save
1227
+ end
1228
+
1229
+ def test_should_not_write_event
1230
+ assert_nil @object.state_event
1231
+ end
1232
+
1233
+ def test_should_not_have_event_transition_during_save
1234
+ assert_nil @object.state_event_transition_on_save
1235
+ end
1236
+
1237
+ def test_should_not_write_event_attribute
1238
+ assert_nil @object.send(:state_event_transition)
1239
+ end
1240
+ end
1241
+
1242
+ class TransitionCollectionWithActionHookAndBlockTest < TransitionCollectionWithActionHookBaseTest
1243
+ def setup
1244
+ super
1245
+ @result = StateMachine::TransitionCollection.new([@transition]).perform { true }
1246
+ end
1247
+
1248
+ def test_should_succeed
1249
+ assert_equal true, @result
1250
+ end
1251
+
1252
+ def test_should_not_run_action
1253
+ assert !@object.saved
1254
+ end
1255
+ end
1256
+
1257
+ class TransitionCollectionWithActionHookInvalidTest < TransitionCollectionWithActionHookBaseTest
1258
+ def setup
1259
+ super
1260
+ @result = StateMachine::TransitionCollection.new([@transition, nil]).perform
1261
+ end
1262
+
1263
+ def test_should_not_succeed
1264
+ assert_equal false, @result
1265
+ end
1266
+
1267
+ def test_should_not_run_action
1268
+ assert !@object.saved
1269
+ end
1270
+ end
1271
+
1272
+ class TransitionCollectionWithActionHookWithNilActionTest < TransitionCollectionWithActionHookBaseTest
1273
+ def setup
1274
+ super
1275
+
1276
+ @machine = StateMachine::Machine.new(@klass, :status, :initial => :first_gear)
1277
+ @machine.state :second_gear
1278
+ @machine.event :shift_up
1279
+
1280
+ @result = StateMachine::TransitionCollection.new([@transition, StateMachine::Transition.new(@object, @machine, :shift_up, :first_gear, :second_gear)]).perform
1281
+ end
1282
+
1283
+ def test_should_succeed
1284
+ assert_equal true, @result
1285
+ end
1286
+
1287
+ def test_should_run_action
1288
+ assert @object.saved
1289
+ end
1290
+
1291
+ def test_should_have_already_persisted_when_running_action
1292
+ assert_equal 'idling', @object.state_on_save
1293
+ end
1294
+
1295
+ def test_should_not_have_event_during_action
1296
+ assert_nil @object.state_event_on_save
1297
+ end
1298
+
1299
+ def test_should_not_write_event
1300
+ assert_nil @object.state_event
1301
+ end
1302
+
1303
+ def test_should_not_have_event_transition_during_save
1304
+ assert_nil @object.state_event_transition_on_save
1305
+ end
1306
+
1307
+ def test_should_not_write_event_attribute
1308
+ assert_nil @object.send(:state_event_transition)
1309
+ end
1310
+ end
1311
+
1312
+ class TransitionCollectionWithActionHookWithDifferentActionsTest < TransitionCollectionWithActionHookBaseTest
1313
+ def setup
1314
+ super
1315
+
1316
+ @klass.class_eval do
1317
+ def save_status
1318
+ true
1319
+ end
1320
+ end
1321
+
1322
+ @machine = StateMachine::Machine.new(@klass, :status, :initial => :first_gear, :action => :save_status)
1323
+ @machine.state :second_gear
1324
+ @machine.event :shift_up
1325
+
1326
+ @result = StateMachine::TransitionCollection.new([@transition, StateMachine::Transition.new(@object, @machine, :shift_up, :first_gear, :second_gear)]).perform
1327
+ end
1328
+
1329
+ def test_should_succeed
1330
+ assert_equal true, @result
1331
+ end
1332
+
1333
+ def test_should_run_action
1334
+ assert @object.saved
1335
+ end
1336
+
1337
+ def test_should_have_already_persisted_when_running_action
1338
+ assert_equal 'idling', @object.state_on_save
1339
+ end
1340
+
1341
+ def test_should_not_have_event_during_action
1342
+ assert_nil @object.state_event_on_save
1343
+ end
1344
+
1345
+ def test_should_not_write_event
1346
+ assert_nil @object.state_event
1347
+ end
1348
+
1349
+ def test_should_not_have_event_transition_during_save
1350
+ assert_nil @object.state_event_transition_on_save
1351
+ end
1352
+
1353
+ def test_should_not_write_event_attribute
1354
+ assert_nil @object.send(:state_event_transition)
1355
+ end
1356
+ end
1357
+
1358
+ class TransitionCollectionWithActionHookTest < TransitionCollectionWithActionHookBaseTest
1359
+ def setup
1360
+ super
1361
+ @result = StateMachine::TransitionCollection.new([@transition]).perform
1362
+ end
1363
+
1364
+ def test_should_succeed
1365
+ assert_equal true, @result
1366
+ end
1367
+
1368
+ def test_should_run_action
1369
+ assert @object.saved
1370
+ end
1371
+
1372
+ def test_should_not_have_already_persisted_when_running_action
1373
+ assert_equal 'parked', @object.state_on_save
1374
+ end
1375
+
1376
+ def test_should_persist
1377
+ assert_equal 'idling', @object.state
1378
+ end
1379
+
1380
+ def test_should_not_have_event_during_action
1381
+ assert_nil @object.state_event_on_save
1382
+ end
1383
+
1384
+ def test_should_not_write_event
1385
+ assert_nil @object.state_event
1386
+ end
1387
+
1388
+ def test_should_have_event_transition_during_action
1389
+ assert_equal @transition, @object.state_event_transition_on_save
1390
+ end
1391
+
1392
+ def test_should_not_write_event_transition
1393
+ assert_nil @object.send(:state_event_transition)
1394
+ end
1395
+
1396
+ def test_should_mark_event_transition_as_transient
1397
+ assert @transition.transient?
1398
+ end
1399
+ end
1400
+
1401
+ class TransitionCollectionWithActionHookMultipleTest < TransitionCollectionWithActionHookBaseTest
1402
+ def setup
1403
+ super
1404
+
1405
+ @status_machine = StateMachine::Machine.new(@klass, :status, :initial => :first_gear, :action => :save)
1406
+ @status_machine.state :second_gear
1407
+ @status_machine.event :shift_up
1408
+
1409
+ @klass.class_eval do
1410
+ attr_reader :status_on_save, :status_event_on_save, :status_event_transition_on_save
1411
+
1412
+ def save
1413
+ @saved = true
1414
+ @state_on_save = state
1415
+ @state_event_on_save = state_event
1416
+ @state_event_transition_on_save = state_event_transition
1417
+ @status_on_save = status
1418
+ @status_event_on_save = status_event
1419
+ @status_event_transition_on_save = status_event_transition
1420
+ super
1421
+ 1
1422
+ end
1423
+ end
1424
+
1425
+ @object = @klass.new
1426
+ @state_transition = StateMachine::Transition.new(@object, @machine, :ignite, :parked, :idling)
1427
+ @status_transition = StateMachine::Transition.new(@object, @status_machine, :shift_up, :first_gear, :second_gear)
1428
+
1429
+ @result = StateMachine::TransitionCollection.new([@state_transition, @status_transition]).perform
1430
+ end
1431
+
1432
+ def test_should_succeed
1433
+ assert_equal 1, @result
1434
+ end
1435
+
1436
+ def test_should_run_action
1437
+ assert @object.saved
1438
+ end
1439
+
1440
+ def test_should_not_have_already_persisted_when_running_action
1441
+ assert_equal 'parked', @object.state_on_save
1442
+ assert_equal 'first_gear', @object.status_on_save
1443
+ end
1444
+
1445
+ def test_should_persist
1446
+ assert_equal 'idling', @object.state
1447
+ assert_equal 'second_gear', @object.status
1448
+ end
1449
+
1450
+ def test_should_not_have_events_during_action
1451
+ assert_nil @object.state_event_on_save
1452
+ assert_nil @object.status_event_on_save
1453
+ end
1454
+
1455
+ def test_should_not_write_events
1456
+ assert_nil @object.state_event
1457
+ assert_nil @object.status_event
1458
+ end
1459
+
1460
+ def test_should_have_event_transitions_during_action
1461
+ assert_equal @state_transition, @object.state_event_transition_on_save
1462
+ assert_equal @status_transition, @object.status_event_transition_on_save
1463
+ end
1464
+
1465
+ def test_should_not_write_event_transitions
1466
+ assert_nil @object.send(:state_event_transition)
1467
+ assert_nil @object.send(:status_event_transition)
1468
+ end
1469
+
1470
+ def test_should_mark_event_transitions_as_transient
1471
+ assert @state_transition.transient?
1472
+ assert @status_transition.transient?
1473
+ end
1474
+ end
1475
+
1476
+ class TransitionCollectionWithActionHookErrorTest < TransitionCollectionWithActionHookBaseTest
1477
+ def setup
1478
+ super
1479
+
1480
+ @superclass.class_eval do
1481
+ def save
1482
+ raise ArgumentError
1483
+ end
1484
+ end
1485
+
1486
+ begin; StateMachine::TransitionCollection.new([@transition]).perform; rescue; end
1487
+ end
1488
+
1489
+ def test_should_not_write_event
1490
+ assert_nil @object.state_event
1491
+ end
1492
+
1493
+ def test_should_not_write_event_transition
1494
+ assert_nil @object.send(:state_event_transition)
1495
+ end
1496
+ end
1497
+
1498
+ class AttributeTransitionCollectionByDefaultTest < Test::Unit::TestCase
1499
+ def setup
1500
+ @transitions = StateMachine::AttributeTransitionCollection.new
1501
+ end
1502
+
1503
+ def test_should_skip_actions
1504
+ assert @transitions.skip_actions
1505
+ end
1506
+
1507
+ def test_should_not_skip_after
1508
+ assert !@transitions.skip_after
1509
+ end
1510
+
1511
+ def test_should_not_use_transaction
1512
+ assert !@transitions.use_transaction
1513
+ end
1514
+
1515
+ def test_should_be_empty
1516
+ assert @transitions.empty?
1517
+ end
1518
+ end
1519
+
1520
+ class AttributeTransitionCollectionWithEventsTest < Test::Unit::TestCase
1521
+ def setup
1522
+ @klass = Class.new
1523
+
1524
+ @state = StateMachine::Machine.new(@klass, :initial => :parked, :action => :save)
1525
+ @state.state :idling
1526
+ @state.event :ignite
1527
+
1528
+ @status = StateMachine::Machine.new(@klass, :status, :initial => :first_gear, :action => :save)
1529
+ @status.state :second_gear
1530
+ @status.event :shift_up
1531
+
1532
+ @object = @klass.new
1533
+ @object.state_event = 'ignite'
1534
+ @object.status_event = 'shift_up'
1535
+
1536
+ @transitions = StateMachine::AttributeTransitionCollection.new([
1537
+ @state_transition = StateMachine::Transition.new(@object, @state, :ignite, :parked, :idling),
1538
+ @status_transition = StateMachine::Transition.new(@object, @status, :shift_up, :first_gear, :second_gear)
1539
+ ])
1540
+ @result = @transitions.perform
1541
+ end
1542
+
1543
+ def test_should_succeed
1544
+ assert_equal true, @result
1545
+ end
1546
+
1547
+ def test_should_persist_states
1548
+ assert_equal 'idling', @object.state
1549
+ assert_equal 'second_gear', @object.status
1550
+ end
1551
+
1552
+ def test_should_clear_events
1553
+ assert_nil @object.state_event
1554
+ assert_nil @object.status_event
1555
+ end
1556
+
1557
+ def test_should_not_write_event_transitions
1558
+ assert_nil @object.send(:state_event_transition)
1559
+ assert_nil @object.send(:status_event_transition)
1560
+ end
1561
+ end
1562
+
1563
+ class AttributeTransitionCollectionWithEventTransitionsTest < Test::Unit::TestCase
1564
+ def setup
1565
+ @klass = Class.new
1566
+
1567
+ @state = StateMachine::Machine.new(@klass, :initial => :parked, :action => :save)
1568
+ @state.state :idling
1569
+ @state.event :ignite
1570
+
1571
+ @status = StateMachine::Machine.new(@klass, :status, :initial => :first_gear, :action => :save)
1572
+ @status.state :second_gear
1573
+ @status.event :shift_up
1574
+
1575
+ @object = @klass.new
1576
+ @object.send(:state_event_transition=, @state_transition = StateMachine::Transition.new(@object, @state, :ignite, :parked, :idling))
1577
+ @object.send(:status_event_transition=, @status_transition = StateMachine::Transition.new(@object, @status, :shift_up, :first_gear, :second_gear))
1578
+
1579
+ @transitions = StateMachine::AttributeTransitionCollection.new([@state_transition, @status_transition])
1580
+ @result = @transitions.perform
1581
+ end
1582
+
1583
+ def test_should_succeed
1584
+ assert_equal true, @result
1585
+ end
1586
+
1587
+ def test_should_persist_states
1588
+ assert_equal 'idling', @object.state
1589
+ assert_equal 'second_gear', @object.status
1590
+ end
1591
+
1592
+ def test_should_not_write_events
1593
+ assert_nil @object.state_event
1594
+ assert_nil @object.status_event
1595
+ end
1596
+
1597
+ def test_should_clear_event_transitions
1598
+ assert_nil @object.send(:state_event_transition)
1599
+ assert_nil @object.send(:status_event_transition)
1600
+ end
1601
+ end
1602
+
1603
+ class AttributeTransitionCollectionWithActionFailedTest < Test::Unit::TestCase
1604
+ def setup
1605
+ @klass = Class.new
1606
+
1607
+ @state = StateMachine::Machine.new(@klass, :initial => :parked, :action => :save)
1608
+ @state.state :idling
1609
+ @state.event :ignite
1610
+
1611
+ @status = StateMachine::Machine.new(@klass, :status, :initial => :first_gear, :action => :save)
1612
+ @status.state :second_gear
1613
+ @status.event :shift_up
1614
+
1615
+ @object = @klass.new
1616
+ @object.state_event = 'ignite'
1617
+ @object.status_event = 'shift_up'
1618
+
1619
+ @transitions = StateMachine::AttributeTransitionCollection.new([
1620
+ @state_transition = StateMachine::Transition.new(@object, @state, :ignite, :parked, :idling),
1621
+ @status_transition = StateMachine::Transition.new(@object, @status, :shift_up, :first_gear, :second_gear)
1622
+ ])
1623
+ @result = @transitions.perform { false }
1624
+ end
1625
+
1626
+ def test_should_not_succeed
1627
+ assert_equal false, @result
1628
+ end
1629
+
1630
+ def test_should_not_persist_states
1631
+ assert_equal 'parked', @object.state
1632
+ assert_equal 'first_gear', @object.status
1633
+ end
1634
+
1635
+ def test_should_not_clear_events
1636
+ assert_equal :ignite, @object.state_event
1637
+ assert_equal :shift_up, @object.status_event
1638
+ end
1639
+
1640
+ def test_should_not_write_event_transitions
1641
+ assert_nil @object.send(:state_event_transition)
1642
+ assert_nil @object.send(:status_event_transition)
1643
+ end
1644
+ end
1645
+
1646
+ class AttributeTransitionCollectionWithActionErrorTest < Test::Unit::TestCase
1647
+ def setup
1648
+ @klass = Class.new
1649
+
1650
+ @state = StateMachine::Machine.new(@klass, :initial => :parked, :action => :save)
1651
+ @state.state :idling
1652
+ @state.event :ignite
1653
+
1654
+ @status = StateMachine::Machine.new(@klass, :status, :initial => :first_gear, :action => :save)
1655
+ @status.state :second_gear
1656
+ @status.event :shift_up
1657
+
1658
+ @object = @klass.new
1659
+ @object.state_event = 'ignite'
1660
+ @object.status_event = 'shift_up'
1661
+
1662
+ @transitions = StateMachine::AttributeTransitionCollection.new([
1663
+ @state_transition = StateMachine::Transition.new(@object, @state, :ignite, :parked, :idling),
1664
+ @status_transition = StateMachine::Transition.new(@object, @status, :shift_up, :first_gear, :second_gear)
1665
+ ])
1666
+
1667
+ begin; @transitions.perform { raise ArgumentError }; rescue; end
1668
+ end
1669
+
1670
+ def test_should_not_persist_states
1671
+ assert_equal 'parked', @object.state
1672
+ assert_equal 'first_gear', @object.status
1673
+ end
1674
+
1675
+ def test_should_not_clear_events
1676
+ assert_equal :ignite, @object.state_event
1677
+ assert_equal :shift_up, @object.status_event
1678
+ end
1679
+
1680
+ def test_should_not_write_event_transitions
1681
+ assert_nil @object.send(:state_event_transition)
1682
+ assert_nil @object.send(:status_event_transition)
1683
+ end
1684
+ end
1685
+
1686
+ class AttributeTransitionCollectionWithCallbacksTest < Test::Unit::TestCase
1687
+ def setup
1688
+ @klass = Class.new
1689
+
1690
+ @state = StateMachine::Machine.new(@klass, :initial => :parked, :action => :save)
1691
+ @state.state :idling
1692
+ @state.event :ignite
1693
+
1694
+ @status = StateMachine::Machine.new(@klass, :status, :initial => :first_gear, :action => :save)
1695
+ @status.state :second_gear
1696
+ @status.event :shift_up
1697
+
1698
+ @object = @klass.new
1699
+
1700
+ @transitions = StateMachine::AttributeTransitionCollection.new([
1701
+ @state_transition = StateMachine::Transition.new(@object, @state, :ignite, :parked, :idling),
1702
+ @status_transition = StateMachine::Transition.new(@object, @status, :shift_up, :first_gear, :second_gear)
1703
+ ])
1704
+ end
1705
+
1706
+ def test_should_not_have_events_during_before_callbacks
1707
+ @state.before_transition {|object, transition| @before_state_event = object.state_event }
1708
+ @state.around_transition {|object, transition, block| @around_state_event = object.state_event; block.call }
1709
+ @transitions.perform
1710
+
1711
+ assert_nil @before_state_event
1712
+ assert_nil @around_state_event
1713
+ end
1714
+
1715
+ def test_should_not_have_events_during_action
1716
+ @transitions.perform { @state_event = @object.state_event }
1717
+
1718
+ assert_nil @state_event
1719
+ end
1720
+
1721
+ def test_should_not_have_events_during_after_callbacks
1722
+ @state.after_transition {|object, transition| @after_state_event = object.state_event }
1723
+ @state.around_transition {|object, transition, block| block.call; @around_state_event = object.state_event }
1724
+ @transitions.perform
1725
+
1726
+ assert_nil @state_event
1727
+ end
1728
+
1729
+ def test_should_not_have_event_transitions_during_before_callbacks
1730
+ @state.before_transition {|object, transition| @state_event_transition = object.send(:state_event_transition) }
1731
+ @transitions.perform
1732
+
1733
+ assert_nil @state_event_transition
1734
+ end
1735
+
1736
+ def test_should_not_have_event_transitions_during_action
1737
+ @transitions.perform { @state_event_transition = @object.send(:state_event_transition) }
1738
+
1739
+ assert_nil @state_event_transition
1740
+ end
1741
+
1742
+ def test_should_not_have_event_transitions_during_after_callbacks
1743
+ @state.after_transition {|object, transition| @after_state_event_transition = object.send(:state_event_transition) }
1744
+ @state.around_transition {|object, transition, block| block.call; @around_state_event_transition = object.send(:state_event_transition) }
1745
+ @transitions.perform
1746
+
1747
+ assert_nil @after_state_event_transition
1748
+ assert_nil @around_state_event_transition
1749
+ end
1750
+ end
1751
+
1752
+ class AttributeTransitionCollectionWithBeforeCallbackHaltTest < Test::Unit::TestCase
1753
+ def setup
1754
+ @klass = Class.new
1755
+
1756
+ @machine = StateMachine::Machine.new(@klass, :initial => :parked, :action => :save)
1757
+ @machine.state :idling
1758
+ @machine.event :ignite
1759
+
1760
+ @machine.before_transition {throw :halt}
1761
+
1762
+ @object = @klass.new
1763
+ @object.state_event = 'ignite'
1764
+
1765
+ @transitions = StateMachine::AttributeTransitionCollection.new([
1766
+ StateMachine::Transition.new(@object, @machine, :ignite, :parked, :idling)
1767
+ ])
1768
+ @result = @transitions.perform
1769
+ end
1770
+
1771
+ def test_should_not_succeed
1772
+ assert_equal false, @result
1773
+ end
1774
+
1775
+ def test_should_not_clear_event
1776
+ assert_equal :ignite, @object.state_event
1777
+ end
1778
+
1779
+ def test_should_not_write_event_transition
1780
+ assert_nil @object.send(:state_event_transition)
1781
+ end
1782
+ end
1783
+
1784
+ class AttributeTransitionCollectionWithBeforeCallbackErrorTest < Test::Unit::TestCase
1785
+ def setup
1786
+ @klass = Class.new
1787
+
1788
+ @machine = StateMachine::Machine.new(@klass, :initial => :parked, :action => :save)
1789
+ @machine.state :idling
1790
+ @machine.event :ignite
1791
+
1792
+ @machine.before_transition {raise ArgumentError}
1793
+
1794
+ @object = @klass.new
1795
+ @object.state_event = 'ignite'
1796
+
1797
+ @transitions = StateMachine::AttributeTransitionCollection.new([
1798
+ StateMachine::Transition.new(@object, @machine, :ignite, :parked, :idling)
1799
+ ])
1800
+ begin; @transitions.perform; rescue; end
1801
+ end
1802
+
1803
+ def test_should_not_clear_event
1804
+ assert_equal :ignite, @object.state_event
1805
+ end
1806
+
1807
+ def test_should_not_write_event_transition
1808
+ assert_nil @object.send(:state_event_transition)
1809
+ end
1810
+ end
1811
+
1812
+ class AttributeTransitionCollectionWithAroundCallbackBeforeYieldHaltTest < Test::Unit::TestCase
1813
+ def setup
1814
+ @klass = Class.new
1815
+
1816
+ @machine = StateMachine::Machine.new(@klass, :initial => :parked, :action => :save)
1817
+ @machine.state :idling
1818
+ @machine.event :ignite
1819
+
1820
+ @machine.around_transition {throw :halt}
1821
+
1822
+ @object = @klass.new
1823
+ @object.state_event = 'ignite'
1824
+
1825
+ @transitions = StateMachine::AttributeTransitionCollection.new([
1826
+ StateMachine::Transition.new(@object, @machine, :ignite, :parked, :idling)
1827
+ ])
1828
+ @result = @transitions.perform
1829
+ end
1830
+
1831
+ def test_should_not_succeed
1832
+ assert_equal false, @result
1833
+ end
1834
+
1835
+ def test_should_not_clear_event
1836
+ assert_equal :ignite, @object.state_event
1837
+ end
1838
+
1839
+ def test_should_not_write_event_transition
1840
+ assert_nil @object.send(:state_event_transition)
1841
+ end
1842
+ end
1843
+
1844
+ class AttributeTransitionCollectionWithAroundAfterYieldCallbackErrorTest < Test::Unit::TestCase
1845
+ def setup
1846
+ @klass = Class.new
1847
+
1848
+ @machine = StateMachine::Machine.new(@klass, :initial => :parked, :action => :save)
1849
+ @machine.state :idling
1850
+ @machine.event :ignite
1851
+
1852
+ @machine.before_transition {raise ArgumentError}
1853
+
1854
+ @object = @klass.new
1855
+ @object.state_event = 'ignite'
1856
+
1857
+ @transitions = StateMachine::AttributeTransitionCollection.new([
1858
+ StateMachine::Transition.new(@object, @machine, :ignite, :parked, :idling)
1859
+ ])
1860
+ begin; @transitions.perform; rescue; end
1861
+ end
1862
+
1863
+ def test_should_not_clear_event
1864
+ assert_equal :ignite, @object.state_event
1865
+ end
1866
+
1867
+ def test_should_not_write_event_transition
1868
+ assert_nil @object.send(:state_event_transition)
1869
+ end
1870
+ end
1871
+
1872
+ class AttributeTransitionCollectionWithSkippedAfterCallbacksTest < Test::Unit::TestCase
1873
+ def setup
1874
+ @klass = Class.new
1875
+
1876
+ @state = StateMachine::Machine.new(@klass, :initial => :parked, :action => :save)
1877
+ @state.state :idling
1878
+ @state.event :ignite
1879
+
1880
+ @status = StateMachine::Machine.new(@klass, :status, :initial => :first_gear, :action => :save)
1881
+ @status.state :second_gear
1882
+ @status.event :shift_up
1883
+
1884
+ @object = @klass.new
1885
+ @object.state_event = 'ignite'
1886
+ @object.status_event = 'shift_up'
1887
+
1888
+ @transitions = StateMachine::AttributeTransitionCollection.new([
1889
+ @state_transition = StateMachine::Transition.new(@object, @state, :ignite, :parked, :idling),
1890
+ @status_transition = StateMachine::Transition.new(@object, @status, :shift_up, :first_gear, :second_gear)
1891
+ ], :after => false)
1892
+ end
1893
+
1894
+ def test_should_clear_events
1895
+ @transitions.perform
1896
+ assert_nil @object.state_event
1897
+ assert_nil @object.status_event
1898
+ end
1899
+
1900
+ def test_should_write_event_transitions_if_success
1901
+ @transitions.perform { true }
1902
+ assert_equal @state_transition, @object.send(:state_event_transition)
1903
+ assert_equal @status_transition, @object.send(:status_event_transition)
1904
+ end
1905
+
1906
+ def test_should_not_write_event_transitions_if_failed
1907
+ @transitions.perform { false }
1908
+ assert_nil @object.send(:state_event_transition)
1909
+ assert_nil @object.send(:status_event_transition)
1910
+ end
1911
+ end
1912
+
1913
+ class AttributeTransitionCollectionWithAfterCallbackHaltTest < Test::Unit::TestCase
1914
+ def setup
1915
+ @klass = Class.new
1916
+
1917
+ @machine = StateMachine::Machine.new(@klass, :initial => :parked, :action => :save)
1918
+ @machine.state :idling
1919
+ @machine.event :ignite
1920
+
1921
+ @machine.after_transition {throw :halt}
1922
+
1923
+ @object = @klass.new
1924
+ @object.state_event = 'ignite'
1925
+
1926
+ @transitions = StateMachine::AttributeTransitionCollection.new([
1927
+ StateMachine::Transition.new(@object, @machine, :ignite, :parked, :idling)
1928
+ ])
1929
+ @result = @transitions.perform
1930
+ end
1931
+
1932
+ def test_should_succeed
1933
+ assert_equal true, @result
1934
+ end
1935
+
1936
+ def test_should_clear_event
1937
+ assert_nil @object.state_event
1938
+ end
1939
+
1940
+ def test_should_not_write_event_transition
1941
+ assert_nil @object.send(:state_event_transition)
1942
+ end
1943
+ end
1944
+
1945
+ class AttributeTransitionCollectionWithAfterCallbackErrorTest < Test::Unit::TestCase
1946
+ def setup
1947
+ @klass = Class.new
1948
+
1949
+ @machine = StateMachine::Machine.new(@klass, :initial => :parked, :action => :save)
1950
+ @machine.state :idling
1951
+ @machine.event :ignite
1952
+
1953
+ @machine.after_transition {raise ArgumentError}
1954
+
1955
+ @object = @klass.new
1956
+ @object.state_event = 'ignite'
1957
+
1958
+ @transitions = StateMachine::AttributeTransitionCollection.new([
1959
+ StateMachine::Transition.new(@object, @machine, :ignite, :parked, :idling)
1960
+ ])
1961
+ begin; @transitions.perform; rescue; end
1962
+ end
1963
+
1964
+ def test_should_clear_event
1965
+ assert_nil @object.state_event
1966
+ end
1967
+
1968
+ def test_should_not_write_event_transition
1969
+ assert_nil @object.send(:state_event_transition)
1970
+ end
1971
+ end
1972
+
1973
+ class AttributeTransitionCollectionWithAroundCallbackAfterYieldHaltTest < Test::Unit::TestCase
1974
+ def setup
1975
+ @klass = Class.new
1976
+
1977
+ @machine = StateMachine::Machine.new(@klass, :initial => :parked, :action => :save)
1978
+ @machine.state :idling
1979
+ @machine.event :ignite
1980
+
1981
+ @machine.around_transition {|block| block.call; throw :halt}
1982
+
1983
+ @object = @klass.new
1984
+ @object.state_event = 'ignite'
1985
+
1986
+ @transitions = StateMachine::AttributeTransitionCollection.new([
1987
+ StateMachine::Transition.new(@object, @machine, :ignite, :parked, :idling)
1988
+ ])
1989
+ @result = @transitions.perform
1990
+ end
1991
+
1992
+ def test_should_succeed
1993
+ assert_equal true, @result
1994
+ end
1995
+
1996
+ def test_should_clear_event
1997
+ assert_nil @object.state_event
1998
+ end
1999
+
2000
+ def test_should_not_write_event_transition
2001
+ assert_nil @object.send(:state_event_transition)
2002
+ end
2003
+ end
2004
+
2005
+ class AttributeTransitionCollectionWithAfterCallbackErrorTest < Test::Unit::TestCase
2006
+ def setup
2007
+ @klass = Class.new
2008
+
2009
+ @machine = StateMachine::Machine.new(@klass, :initial => :parked, :action => :save)
2010
+ @machine.state :idling
2011
+ @machine.event :ignite
2012
+
2013
+ @machine.around_transition {|block| block.call; raise ArgumentError}
2014
+
2015
+ @object = @klass.new
2016
+ @object.state_event = 'ignite'
2017
+
2018
+ @transitions = StateMachine::AttributeTransitionCollection.new([
2019
+ StateMachine::Transition.new(@object, @machine, :ignite, :parked, :idling)
2020
+ ])
2021
+ begin; @transitions.perform; rescue; end
2022
+ end
2023
+
2024
+ def test_should_clear_event
2025
+ assert_nil @object.state_event
2026
+ end
2027
+
2028
+ def test_should_not_write_event_transition
2029
+ assert_nil @object.send(:state_event_transition)
2030
+ end
2031
+ end
2032
+
2033
+ class AttributeTransitionCollectionMarshallingTest < Test::Unit::TestCase
2034
+ def setup
2035
+ @klass = Class.new
2036
+ self.class.const_set('Example', @klass)
2037
+
2038
+ @machine = StateMachine::Machine.new(@klass, :initial => :parked, :action => :save)
2039
+ @machine.state :idling
2040
+ @machine.event :ignite
2041
+
2042
+ @object = @klass.new
2043
+ @object.state_event = 'ignite'
2044
+ end
2045
+
2046
+ def test_should_marshal_during_before_callbacks
2047
+ @machine.before_transition {|object, transition| Marshal.dump(object)}
2048
+ assert_nothing_raised do
2049
+ transitions(:after => false).perform { true }
2050
+ transitions.perform { true }
2051
+ end
2052
+ end
2053
+
2054
+ def test_should_marshal_during_action
2055
+ assert_nothing_raised do
2056
+ transitions(:after => false).perform do
2057
+ Marshal.dump(@object)
2058
+ true
2059
+ end
2060
+
2061
+ transitions.perform do
2062
+ Marshal.dump(@object)
2063
+ true
2064
+ end
2065
+ end
2066
+ end
2067
+
2068
+ def test_should_marshal_during_after_callbacks
2069
+ @machine.after_transition {|object, transition| Marshal.dump(object)}
2070
+ assert_nothing_raised do
2071
+ transitions(:after => false).perform { true }
2072
+ transitions.perform { true }
2073
+ end
2074
+ end
2075
+
2076
+ def test_should_marshal_during_around_callbacks_before_yield
2077
+ @machine.around_transition {|object, transition, block| Marshal.dump(object); block.call}
2078
+ assert_nothing_raised do
2079
+ transitions(:after => false).perform { true }
2080
+ transitions.perform { true }
2081
+ end
2082
+ end
2083
+
2084
+ def test_should_marshal_during_around_callbacks_after_yield
2085
+ @machine.around_transition {|object, transition, block| block.call; Marshal.dump(object)}
2086
+ assert_nothing_raised do
2087
+ transitions(:after => false).perform { true }
2088
+ transitions.perform { true }
2089
+ end
2090
+ end
2091
+
2092
+ def teardown
2093
+ self.class.send(:remove_const, 'Example')
2094
+ end
2095
+
2096
+ private
2097
+ def transitions(options = {})
2098
+ StateMachine::AttributeTransitionCollection.new([
2099
+ StateMachine::Transition.new(@object, @machine, :ignite, :parked, :idling)
2100
+ ], options)
2101
+ end
2102
+ end