spree-state_machine 2.0.0.beta1

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