hsume2-state_machine 1.0.1

Sign up to get free protection for your applications and to get access to all the features.
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