state_machines 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (79) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +21 -0
  3. data/.idea/.name +1 -0
  4. data/.idea/.rakeTasks +7 -0
  5. data/.idea/cssxfire.xml +9 -0
  6. data/.idea/encodings.xml +5 -0
  7. data/.idea/misc.xml +5 -0
  8. data/.idea/modules.xml +12 -0
  9. data/.idea/scopes/scope_settings.xml +5 -0
  10. data/.idea/state_machine2.iml +34 -0
  11. data/.idea/vcs.xml +9 -0
  12. data/.idea/workspace.xml +1156 -0
  13. data/.rspec +3 -0
  14. data/.travis.yml +8 -0
  15. data/Gemfile +4 -0
  16. data/LICENSE.txt +23 -0
  17. data/README.md +29 -0
  18. data/Rakefile +1 -0
  19. data/lib/state_machines/assertions.rb +40 -0
  20. data/lib/state_machines/branch.rb +187 -0
  21. data/lib/state_machines/callback.rb +220 -0
  22. data/lib/state_machines/core.rb +25 -0
  23. data/lib/state_machines/core_ext/class/state_machine.rb +5 -0
  24. data/lib/state_machines/core_ext.rb +2 -0
  25. data/lib/state_machines/error.rb +13 -0
  26. data/lib/state_machines/eval_helpers.rb +87 -0
  27. data/lib/state_machines/event.rb +246 -0
  28. data/lib/state_machines/event_collection.rb +141 -0
  29. data/lib/state_machines/extensions.rb +148 -0
  30. data/lib/state_machines/helper_module.rb +17 -0
  31. data/lib/state_machines/integrations/base.rb +100 -0
  32. data/lib/state_machines/integrations.rb +113 -0
  33. data/lib/state_machines/machine.rb +2234 -0
  34. data/lib/state_machines/machine_collection.rb +84 -0
  35. data/lib/state_machines/macro_methods.rb +520 -0
  36. data/lib/state_machines/matcher.rb +123 -0
  37. data/lib/state_machines/matcher_helpers.rb +54 -0
  38. data/lib/state_machines/node_collection.rb +221 -0
  39. data/lib/state_machines/path.rb +120 -0
  40. data/lib/state_machines/path_collection.rb +90 -0
  41. data/lib/state_machines/state.rb +276 -0
  42. data/lib/state_machines/state_collection.rb +112 -0
  43. data/lib/state_machines/state_context.rb +138 -0
  44. data/lib/state_machines/transition.rb +470 -0
  45. data/lib/state_machines/transition_collection.rb +245 -0
  46. data/lib/state_machines/version.rb +3 -0
  47. data/lib/state_machines/yard.rb +8 -0
  48. data/lib/state_machines.rb +3 -0
  49. data/spec/errors/default_spec.rb +14 -0
  50. data/spec/errors/with_message_spec.rb +39 -0
  51. data/spec/helpers/helper_spec.rb +14 -0
  52. data/spec/internal/app/models/auto_shop.rb +31 -0
  53. data/spec/internal/app/models/car.rb +19 -0
  54. data/spec/internal/app/models/model_base.rb +6 -0
  55. data/spec/internal/app/models/motorcycle.rb +9 -0
  56. data/spec/internal/app/models/traffic_light.rb +47 -0
  57. data/spec/internal/app/models/vehicle.rb +123 -0
  58. data/spec/machine_spec.rb +3167 -0
  59. data/spec/matcher_helpers_spec.rb +39 -0
  60. data/spec/matcher_spec.rb +157 -0
  61. data/spec/models/auto_shop_spec.rb +41 -0
  62. data/spec/models/car_spec.rb +90 -0
  63. data/spec/models/motorcycle_spec.rb +44 -0
  64. data/spec/models/traffic_light_spec.rb +56 -0
  65. data/spec/models/vehicle_spec.rb +580 -0
  66. data/spec/node_collection_spec.rb +371 -0
  67. data/spec/path_collection_spec.rb +271 -0
  68. data/spec/path_spec.rb +488 -0
  69. data/spec/spec_helper.rb +6 -0
  70. data/spec/state_collection_spec.rb +352 -0
  71. data/spec/state_context_spec.rb +442 -0
  72. data/spec/state_machine_spec.rb +29 -0
  73. data/spec/state_spec.rb +970 -0
  74. data/spec/support/migration_helpers.rb +50 -0
  75. data/spec/support/models.rb +6 -0
  76. data/spec/transition_collection_spec.rb +2199 -0
  77. data/spec/transition_spec.rb +1558 -0
  78. data/state_machines.gemspec +23 -0
  79. metadata +194 -0
@@ -0,0 +1,2199 @@
1
+ require 'spec_helper'
2
+ describe StateMachines::TransitionCollection do
3
+ context '' do
4
+ it 'should_raise_exception_if_invalid_option_specified' do
5
+ assert_raise(ArgumentError) { StateMachines::TransitionCollection.new([], :invalid => true) }
6
+ #assert_equal 'Invalid key(s): invalid', exception.message
7
+ end
8
+
9
+ it 'should_raise_exception_if_multiple_transitions_for_same_attribute_specified' do
10
+ @klass = Class.new
11
+
12
+ @machine = StateMachines::Machine.new(@klass, :initial => :parked)
13
+ @machine.state :parked, :idling
14
+ @machine.event :ignite
15
+
16
+ @object = @klass.new
17
+
18
+ assert_raise(ArgumentError) do
19
+ StateMachines::TransitionCollection.new([
20
+ StateMachines::Transition.new(@object, @machine, :ignite, :parked, :idling),
21
+ StateMachines::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
+ context 'ByDefault' do
29
+ before(:each) do
30
+ @transitions = StateMachines::TransitionCollection.new
31
+ end
32
+
33
+ it 'should_not_skip_actions' do
34
+ assert !@transitions.skip_actions
35
+ end
36
+
37
+ it 'should_not_skip_after' do
38
+ assert !@transitions.skip_after
39
+ end
40
+
41
+ it 'should_use_transaction' do
42
+ assert @transitions.use_transaction
43
+ end
44
+
45
+ it 'should_be_empty' do
46
+ assert @transitions.empty?
47
+ end
48
+ end
49
+
50
+ context 'EmptyWithoutBlock' do
51
+ before(:each) do
52
+ @transitions = StateMachines::TransitionCollection.new
53
+ @result = @transitions.perform
54
+ end
55
+
56
+ it 'should_succeed' do
57
+ assert_equal true, @result
58
+ end
59
+ end
60
+
61
+
62
+ context 'EmptyWithBlock' do
63
+ before(:each) do
64
+ @transitions = StateMachines::TransitionCollection.new
65
+ end
66
+
67
+ it 'should_raise_exception_if_perform_raises_exception' do
68
+ assert_raise(ArgumentError) { @transitions.perform { raise ArgumentError } }
69
+ end
70
+
71
+ it 'should_use_block_result_if_non_boolean' do
72
+ assert_equal 1, @transitions.perform { 1 }
73
+ end
74
+
75
+ it 'should_use_block_result_if_false' do
76
+ assert_equal false, @transitions.perform { false }
77
+ end
78
+
79
+ it 'should_use_block_reslut_if_nil' do
80
+ assert_equal nil, @transitions.perform { nil }
81
+ end
82
+ end
83
+
84
+ context 'Invalid' do
85
+ before(:each) do
86
+ @transitions = StateMachines::TransitionCollection.new([false])
87
+ end
88
+
89
+ it 'should_be_empty' do
90
+ assert @transitions.empty?
91
+ end
92
+
93
+ it 'should_not_succeed' do
94
+ assert_equal false, @transitions.perform
95
+ end
96
+
97
+ it 'should_not_run_perform_block' do
98
+ ran_block = false
99
+ @transitions.perform { ran_block = true }
100
+ assert !ran_block
101
+ end
102
+ end
103
+
104
+ context 'PartialInvalid' do
105
+ before(:each) do
106
+ @klass = Class.new do
107
+ attr_accessor :ran_transaction
108
+ end
109
+
110
+ @callbacks = []
111
+
112
+ @machine = StateMachines::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 = StateMachines::TransitionCollection.new([
128
+ StateMachines::Transition.new(@object, @machine, :ignite, :parked, :idling),
129
+ false
130
+ ])
131
+ end
132
+
133
+ it 'should_not_store_invalid_values' do
134
+ assert_equal 1, @transitions.length
135
+ end
136
+
137
+ it 'should_not_succeed' do
138
+ assert_equal false, @transitions.perform
139
+ end
140
+
141
+ it 'should_not_start_transaction' do
142
+ assert !@object.ran_transaction
143
+ end
144
+
145
+ it 'should_not_run_perform_block' do
146
+ ran_block = false
147
+ @transitions.perform { ran_block = true }
148
+ assert !ran_block
149
+ end
150
+
151
+ it 'should_not_run_before_callbacks' do
152
+ assert !@callbacks.include?(:before)
153
+ end
154
+
155
+ it 'should_not_persist_states' do
156
+ assert_equal 'parked', @object.state
157
+ end
158
+
159
+ it 'should_not_run_after_callbacks' do
160
+ assert !@callbacks.include?(:after)
161
+ end
162
+
163
+ it 'should_not_run_around_callbacks_before_yield' do
164
+ assert !@callbacks.include?(:around_before)
165
+ end
166
+
167
+ it 'should_not_run_around_callbacks_after_yield' do
168
+ assert !@callbacks.include?(:around_after)
169
+ end
170
+ end
171
+
172
+ context 'Valid' do
173
+ before(:each) do
174
+ @klass = Class.new do
175
+ attr_reader :persisted
176
+
177
+ def initialize
178
+ @persisted = nil
179
+
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 = StateMachines::Machine.new(@klass, :initial => :parked)
195
+ @state.state :idling
196
+ @state.event :ignite
197
+ @status = StateMachines::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 = StateMachines::TransitionCollection.new([
204
+ @state_transition = StateMachines::Transition.new(@object, @state, :ignite, :parked, :idling),
205
+ @status_transition = StateMachines::Transition.new(@object, @status, :shift_up, :first_gear, :second_gear)
206
+ ]).perform
207
+ end
208
+
209
+ it 'should_succeed' do
210
+ assert_equal true, @result
211
+ end
212
+
213
+ it 'should_persist_each_state' do
214
+ assert_equal 'idling', @object.state
215
+ assert_equal 'second_gear', @object.status
216
+ end
217
+
218
+ it 'should_persist_in_order' do
219
+ assert_equal ['state', 'status'], @object.persisted
220
+ end
221
+
222
+ it 'should_store_results_in_transitions' do
223
+ assert_nil @state_transition.result
224
+ assert_nil @status_transition.result
225
+ end
226
+ end
227
+
228
+ context 'WithoutTransactions' do
229
+ before(:each) do
230
+ @klass = Class.new do
231
+ attr_accessor :ran_transaction
232
+ end
233
+
234
+ @machine = StateMachines::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 = StateMachines::TransitionCollection.new([
246
+ StateMachines::Transition.new(@object, @machine, :ignite, :parked, :idling)
247
+ ], :transaction => false)
248
+ @transitions.perform
249
+ end
250
+
251
+ it 'should_not_run_within_transaction' do
252
+ assert !@object.ran_transaction
253
+ end
254
+ end
255
+
256
+ context 'WithTransactions' do
257
+ before(:each) do
258
+ @klass = Class.new do
259
+ attr_accessor :running_transaction, :cancelled_transaction
260
+ end
261
+
262
+ @machine = StateMachines::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 = StateMachines::TransitionCollection.new([
276
+ StateMachines::Transition.new(@object, @machine, :ignite, :parked, :idling)
277
+ ], :transaction => true)
278
+ end
279
+
280
+ it 'should_run_before_callbacks_within_transaction' do
281
+ @machine.before_transition { |object| @in_transaction = object.running_transaction }
282
+ @transitions.perform
283
+
284
+ assert @in_transaction
285
+ end
286
+
287
+ it 'should_run_action_within_transaction' do
288
+ @transitions.perform { @in_transaction = @object.running_transaction }
289
+
290
+ assert @in_transaction
291
+ end
292
+
293
+ it 'should_run_after_callbacks_within_transaction' do
294
+ @machine.after_transition { |object| @in_transaction = object.running_transaction }
295
+ @transitions.perform
296
+
297
+ assert @in_transaction
298
+ end
299
+
300
+ it 'should_cancel_the_transaction_on_before_halt' do
301
+ @machine.before_transition { throw :halt }
302
+
303
+ @transitions.perform
304
+ assert @object.cancelled_transaction
305
+ end
306
+
307
+ it 'should_cancel_the_transaction_on_action_failure' do
308
+ @transitions.perform { false }
309
+ assert @object.cancelled_transaction
310
+ end
311
+
312
+ it 'should_not_cancel_the_transaction_on_after_halt' do
313
+ @machine.after_transition { throw :halt }
314
+
315
+ @transitions.perform
316
+ assert !@object.cancelled_transaction
317
+ end
318
+ end
319
+
320
+ context 'WithEmptyActions' do
321
+ before(:each) do
322
+ @klass = Class.new
323
+
324
+ @state = StateMachines::Machine.new(@klass, :initial => :parked)
325
+ @state.state :idling
326
+ @state.event :ignite
327
+
328
+ @status = StateMachines::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 = StateMachines::TransitionCollection.new([
335
+ @state_transition = StateMachines::Transition.new(@object, @state, :ignite, :parked, :idling),
336
+ @status_transition = StateMachines::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
+ it 'should_succeed' do
346
+ assert_equal true, @result
347
+ end
348
+
349
+ it 'should_persist_states' do
350
+ assert_equal 'idling', @object.state
351
+ assert_equal 'second_gear', @object.status
352
+ end
353
+
354
+ it 'should_store_results_in_transitions' do
355
+ assert_nil @state_transition.result
356
+ assert_nil @status_transition.result
357
+ end
358
+ end
359
+
360
+ context 'WithSkippedActions' do
361
+ before(:each) do
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 = StateMachines::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 = StateMachines::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 = StateMachines::TransitionCollection.new([
395
+ @state_transition = StateMachines::Transition.new(@object, @state, :ignite, :parked, :idling),
396
+ @status_transition = StateMachines::Transition.new(@object, @status, :shift_up, :first_gear, :second_gear)
397
+ ], :actions => false)
398
+ @result = @transitions.perform
399
+ end
400
+
401
+ it 'should_skip_actions' do
402
+ assert_equal true, @transitions.skip_actions
403
+ end
404
+
405
+ it 'should_succeed' do
406
+ assert_equal true, @result
407
+ end
408
+
409
+ it 'should_persist_states' do
410
+ assert_equal 'idling', @object.state
411
+ assert_equal 'second_gear', @object.status
412
+ end
413
+
414
+ it 'should_not_run_actions' do
415
+ assert_nil @object.actions
416
+ end
417
+
418
+ it 'should_store_results_in_transitions' do
419
+ assert_nil @state_transition.result
420
+ assert_nil @status_transition.result
421
+ end
422
+
423
+ it 'should_run_all_callbacks' do
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
+ context 'WithSkippedActionsAndBlock' do
429
+ before(:each) do
430
+ @klass = Class.new
431
+
432
+ @machine = StateMachines::Machine.new(@klass, :initial => :parked, :action => :save_state)
433
+ @machine.state :idling
434
+ @machine.event :ignite
435
+
436
+ @object = @klass.new
437
+
438
+ @transitions = StateMachines::TransitionCollection.new([
439
+ @state_transition = StateMachines::Transition.new(@object, @machine, :ignite, :parked, :idling)
440
+ ], :actions => false)
441
+ @result = @transitions.perform { @ran_block = true; 1 }
442
+ end
443
+
444
+ it 'should_succeed' do
445
+ assert_equal 1, @result
446
+ end
447
+
448
+ it 'should_persist_states' do
449
+ assert_equal 'idling', @object.state
450
+ end
451
+
452
+ it 'should_run_block' do
453
+ assert @ran_block
454
+ end
455
+
456
+ it 'should_store_results_in_transitions' do
457
+ assert_equal 1, @state_transition.result
458
+ end
459
+ end
460
+
461
+ context 'WithDuplicateActions' do
462
+ before(:each) do
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 = StateMachines::Machine.new(@klass, :initial => :parked, :action => :save)
473
+ @state.state :idling
474
+ @state.event :ignite
475
+
476
+ @status = StateMachines::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 = StateMachines::TransitionCollection.new([
483
+ @state_transition = StateMachines::Transition.new(@object, @state, :ignite, :parked, :idling),
484
+ @status_transition = StateMachines::Transition.new(@object, @status, :shift_up, :first_gear, :second_gear)
485
+ ])
486
+ @result = @transitions.perform
487
+ end
488
+
489
+ it 'should_succeed' do
490
+ assert_equal :save, @result
491
+ end
492
+
493
+ it 'should_persist_states' do
494
+ assert_equal 'idling', @object.state
495
+ assert_equal 'second_gear', @object.status
496
+ end
497
+
498
+ it 'should_run_action_once' do
499
+ assert_equal [:save], @object.actions
500
+ end
501
+
502
+ it 'should_store_results_in_transitions' do
503
+ assert_equal :save, @state_transition.result
504
+ assert_equal :save, @status_transition.result
505
+ end
506
+ end
507
+
508
+ context 'WithDifferentActions' do
509
+ before(:each) do
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 = StateMachines::Machine.new(@klass, :initial => :parked, :action => :save_state)
525
+ @state.state :idling
526
+ @state.event :ignite
527
+
528
+ @status = StateMachines::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 = StateMachines::TransitionCollection.new([
535
+ @state_transition = StateMachines::Transition.new(@object, @state, :ignite, :parked, :idling),
536
+ @status_transition = StateMachines::Transition.new(@object, @status, :shift_up, :first_gear, :second_gear)
537
+ ])
538
+ end
539
+
540
+ it 'should_succeed' do
541
+ assert_equal true, @transitions.perform
542
+ end
543
+
544
+ it 'should_persist_states' do
545
+ @transitions.perform
546
+ assert_equal 'idling', @object.state
547
+ assert_equal 'second_gear', @object.status
548
+ end
549
+
550
+ it 'should_run_actions_in_order' do
551
+ @transitions.perform
552
+ assert_equal [:save_state, :save_status], @object.actions
553
+ end
554
+
555
+ it 'should_store_results_in_transitions' do
556
+ @transitions.perform
557
+ assert_equal :save_state, @state_transition.result
558
+ assert_equal :save_status, @status_transition.result
559
+ end
560
+
561
+ it 'should_not_halt_if_action_fails_for_first_transition' do
562
+ @klass.class_eval do
563
+ remove_method :save_state
564
+
565
+ def save_state
566
+ (@actions ||= []) << :save_state
567
+ false
568
+ end
569
+ end
570
+
571
+
572
+ assert_equal false, @transitions.perform
573
+ assert_equal [:save_state, :save_status], @object.actions
574
+ end
575
+
576
+ it 'should_halt_if_action_fails_for_second_transition' do
577
+ @klass.class_eval do
578
+ remove_method :save_status
579
+
580
+ def save_status
581
+ (@actions ||= []) << :save_status
582
+ false
583
+ end
584
+ end
585
+
586
+ assert_equal false, @transitions.perform
587
+ assert_equal [:save_state, :save_status], @object.actions
588
+ end
589
+
590
+ it 'should_rollback_if_action_errors_for_first_transition' do
591
+ @klass.class_eval do
592
+ remove_method :save_state
593
+
594
+ def save_state
595
+ raise ArgumentError
596
+ end
597
+ end
598
+
599
+ begin
600
+ ; @transitions.perform;
601
+ rescue;
602
+ end
603
+ assert_equal 'parked', @object.state
604
+ assert_equal 'first_gear', @object.status
605
+ end
606
+
607
+ it 'should_rollback_if_action_errors_for_second_transition' do
608
+ @klass.class_eval do
609
+ remove_method :save_status
610
+
611
+ def save_status
612
+ raise ArgumentError
613
+ end
614
+ end
615
+
616
+ begin
617
+ ; @transitions.perform;
618
+ rescue;
619
+ end
620
+ assert_equal 'parked', @object.state
621
+ assert_equal 'first_gear', @object.status
622
+ end
623
+
624
+ it 'should_not_run_after_callbacks_if_action_fails_for_first_transition' do
625
+ @klass.class_eval do
626
+ remove_method :save_state
627
+
628
+ def save_state
629
+ false
630
+ end
631
+ end
632
+
633
+ @callbacks = []
634
+ @state.after_transition { @callbacks << :state_after }
635
+ @state.around_transition { |block| block.call; @callbacks << :state_around }
636
+ @status.after_transition { @callbacks << :status_after }
637
+ @status.around_transition { |block| block.call; @callbacks << :status_around }
638
+
639
+ @transitions.perform
640
+ assert_equal [], @callbacks
641
+ end
642
+
643
+ it 'should_not_run_after_callbacks_if_action_fails_for_second_transition' do
644
+ @klass.class_eval do
645
+ remove_method :save_status
646
+
647
+ def save_status
648
+ false
649
+ end
650
+ end
651
+
652
+ @callbacks = []
653
+ @state.after_transition { @callbacks << :state_after }
654
+ @state.around_transition { |block| block.call; @callbacks << :state_around }
655
+ @status.after_transition { @callbacks << :status_after }
656
+ @status.around_transition { |block| block.call; @callbacks << :status_around }
657
+
658
+ @transitions.perform
659
+ assert_equal [], @callbacks
660
+ end
661
+
662
+ it 'should_run_after_failure_callbacks_if_action_fails_for_first_transition' do
663
+ @klass.class_eval do
664
+ remove_method :save_state
665
+
666
+ def save_state
667
+ false
668
+ end
669
+ end
670
+
671
+ @callbacks = []
672
+ @state.after_failure { @callbacks << :state_after }
673
+ @status.after_failure { @callbacks << :status_after }
674
+
675
+ @transitions.perform
676
+ assert_equal [:status_after, :state_after], @callbacks
677
+ end
678
+
679
+ it 'should_run_after_failure_callbacks_if_action_fails_for_second_transition' do
680
+ @klass.class_eval do
681
+ remove_method :save_status
682
+
683
+ def save_status
684
+ false
685
+ end
686
+ end
687
+
688
+ @callbacks = []
689
+ @state.after_failure { @callbacks << :state_after }
690
+ @status.after_failure { @callbacks << :status_after }
691
+
692
+ @transitions.perform
693
+ assert_equal [:status_after, :state_after], @callbacks
694
+ end
695
+ end
696
+
697
+ context 'WithMixedActions' do
698
+ before(:each) do
699
+ @klass = Class.new do
700
+ def save
701
+ true
702
+ end
703
+ end
704
+
705
+ @state = StateMachines::Machine.new(@klass, :initial => :parked, :action => :save)
706
+ @state.state :idling
707
+ @state.event :ignite
708
+
709
+ @status = StateMachines::Machine.new(@klass, :status, :initial => :first_gear)
710
+ @status.state :second_gear
711
+ @status.event :shift_up
712
+
713
+ @object = @klass.new
714
+
715
+ @transitions = StateMachines::TransitionCollection.new([
716
+ @state_transition = StateMachines::Transition.new(@object, @state, :ignite, :parked, :idling),
717
+ @status_transition = StateMachines::Transition.new(@object, @status, :shift_up, :first_gear, :second_gear)
718
+ ])
719
+ @result = @transitions.perform
720
+ end
721
+
722
+ it 'should_succeed' do
723
+ assert_equal true, @result
724
+ end
725
+
726
+ it 'should_persist_states' do
727
+ assert_equal 'idling', @object.state
728
+ assert_equal 'second_gear', @object.status
729
+ end
730
+
731
+ it 'should_store_results_in_transitions' do
732
+ assert_equal true, @state_transition.result
733
+ assert_nil @status_transition.result
734
+ end
735
+ end
736
+
737
+ context 'WithBlock' do
738
+ before(:each) do
739
+ @klass = Class.new do
740
+ attr_reader :actions
741
+
742
+ def save
743
+ (@actions ||= []) << :save
744
+ end
745
+ end
746
+
747
+ @state = StateMachines::Machine.new(@klass, :state, :initial => :parked, :action => :save)
748
+ @state.state :idling
749
+ @state.event :ignite
750
+
751
+ @status = StateMachines::Machine.new(@klass, :status, :initial => :first_gear, :action => :save)
752
+ @status.state :second_gear
753
+ @status.event :shift_up
754
+
755
+ @object = @klass.new
756
+ @transitions = StateMachines::TransitionCollection.new([
757
+ @state_transition = StateMachines::Transition.new(@object, @state, :ignite, :parked, :idling),
758
+ @status_transition = StateMachines::Transition.new(@object, @status, :shift_up, :first_gear, :second_gear)
759
+ ])
760
+ @result = @transitions.perform { 1 }
761
+ end
762
+
763
+ it 'should_succeed' do
764
+ assert_equal 1, @result
765
+ end
766
+
767
+ it 'should_persist_states' do
768
+ assert_equal 'idling', @object.state
769
+ assert_equal 'second_gear', @object.status
770
+ end
771
+
772
+ it 'should_not_run_machine_actions' do
773
+ assert_nil @object.actions
774
+ end
775
+
776
+ it 'should_use_result_as_transition_result' do
777
+ assert_equal 1, @state_transition.result
778
+ assert_equal 1, @status_transition.result
779
+ end
780
+ end
781
+
782
+ context 'WithActionFailed' do
783
+ before(:each) do
784
+ @klass = Class.new do
785
+ def save
786
+ false
787
+ end
788
+ end
789
+ @before_count = 0
790
+ @around_before_count = 0
791
+ @after_count = 0
792
+ @around_after_count = 0
793
+ @failure_count = 0
794
+
795
+ @machine = StateMachines::Machine.new(@klass, :initial => :parked, :action => :save)
796
+ @machine.state :idling
797
+ @machine.event :ignite
798
+
799
+ @machine.before_transition { @before_count += 1 }
800
+ @machine.after_transition { @after_count += 1 }
801
+ @machine.around_transition { |block| @around_before_count += 1; block.call; @around_after_count += 1 }
802
+ @machine.after_failure { @failure_count += 1 }
803
+
804
+ @object = @klass.new
805
+
806
+ @transitions = StateMachines::TransitionCollection.new([
807
+ StateMachines::Transition.new(@object, @machine, :ignite, :parked, :idling)
808
+ ])
809
+ @result = @transitions.perform
810
+ end
811
+
812
+ it 'should_not_succeed' do
813
+ assert_equal false, @result
814
+ end
815
+
816
+ it 'should_not_persist_state' do
817
+ assert_equal 'parked', @object.state
818
+ end
819
+
820
+ it 'should_run_before_callbacks' do
821
+ assert_equal 1, @before_count
822
+ end
823
+
824
+ it 'should_run_around_callbacks_before_yield' do
825
+ assert_equal 1, @around_before_count
826
+ end
827
+
828
+ it 'should_not_run_after_callbacks' do
829
+ assert_equal 0, @after_count
830
+ end
831
+
832
+ it 'should_not_run_around_callbacks' do
833
+ assert_equal 0, @around_after_count
834
+ end
835
+
836
+ it 'should_run_failure_callbacks' do
837
+ assert_equal 1, @failure_count
838
+ end
839
+ end
840
+
841
+ context 'WithActionError' do
842
+ before(:each) do
843
+ @klass = Class.new do
844
+ def save
845
+ raise ArgumentError
846
+ end
847
+ end
848
+ @before_count = 0
849
+ @around_before_count = 0
850
+ @after_count = 0
851
+ @around_after_count = 0
852
+ @failure_count = 0
853
+
854
+ @machine = StateMachines::Machine.new(@klass, :initial => :parked, :action => :save)
855
+ @machine.state :idling
856
+ @machine.event :ignite
857
+
858
+ @machine.before_transition { @before_count += 1 }
859
+ @machine.after_transition { @after_count += 1 }
860
+ @machine.around_transition { |block| @around_before_count += 1; block.call; @around_after_count += 1 }
861
+ @machine.after_failure { @failure_count += 1 }
862
+
863
+ @object = @klass.new
864
+
865
+ @transitions = StateMachines::TransitionCollection.new([
866
+ StateMachines::Transition.new(@object, @machine, :ignite, :parked, :idling)
867
+ ])
868
+
869
+ @raised = true
870
+ begin
871
+ @transitions.perform
872
+ @raised = false
873
+ rescue ArgumentError
874
+ end
875
+ end
876
+
877
+ it 'should_not_catch_exception' do
878
+ assert @raised
879
+ end
880
+
881
+ it 'should_not_persist_state' do
882
+ assert_equal 'parked', @object.state
883
+ end
884
+
885
+ it 'should_run_before_callbacks' do
886
+ assert_equal 1, @before_count
887
+ end
888
+
889
+ it 'should_run_around_callbacks_before_yield' do
890
+ assert_equal 1, @around_before_count
891
+ end
892
+
893
+ it 'should_not_run_after_callbacks' do
894
+ assert_equal 0, @after_count
895
+ end
896
+
897
+ it 'should_not_run_around_callbacks_after_yield' do
898
+ assert_equal 0, @around_after_count
899
+ end
900
+
901
+ it 'should_not_run_failure_callbacks' do
902
+ assert_equal 0, @failure_count
903
+ end
904
+ end
905
+
906
+ context 'WithCallbacks' do
907
+ before(:each) do
908
+ @klass = Class.new do
909
+ attr_reader :saved
910
+
911
+ def save
912
+ @saved = true
913
+ end
914
+ end
915
+
916
+ @before_callbacks = []
917
+ @after_callbacks = []
918
+
919
+ @state = StateMachines::Machine.new(@klass, :initial => :parked, :action => :save)
920
+ @state.state :idling
921
+ @state.event :ignite
922
+ @state.before_transition { @before_callbacks << :state_before }
923
+ @state.after_transition { @after_callbacks << :state_after }
924
+ @state.around_transition { |block| @before_callbacks << :state_around; block.call; @after_callbacks << :state_around }
925
+
926
+ @status = StateMachines::Machine.new(@klass, :status, :initial => :first_gear, :action => :save)
927
+ @status.state :second_gear
928
+ @status.event :shift_up
929
+ @status.before_transition { @before_callbacks << :status_before }
930
+ @status.after_transition { @after_callbacks << :status_after }
931
+ @status.around_transition { |block| @before_callbacks << :status_around; block.call; @after_callbacks << :status_around }
932
+
933
+ @object = @klass.new
934
+ @transitions = StateMachines::TransitionCollection.new([
935
+ StateMachines::Transition.new(@object, @state, :ignite, :parked, :idling),
936
+ StateMachines::Transition.new(@object, @status, :shift_up, :first_gear, :second_gear)
937
+ ])
938
+ end
939
+
940
+ it 'should_run_before_callbacks_in_order' do
941
+ @transitions.perform
942
+ assert_equal [:state_before, :state_around, :status_before, :status_around], @before_callbacks
943
+ end
944
+
945
+ it 'should_halt_if_before_callback_halted_for_first_transition' do
946
+ @state.before_transition { throw :halt }
947
+
948
+ assert_equal false, @transitions.perform
949
+ assert_equal [:state_before, :state_around], @before_callbacks
950
+ end
951
+
952
+ it 'should_halt_if_before_callback_halted_for_second_transition' do
953
+ @status.before_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
+ it 'should_halt_if_around_callback_halted_before_yield_for_first_transition' do
960
+ @state.around_transition { throw :halt }
961
+
962
+ assert_equal false, @transitions.perform
963
+ assert_equal [:state_before, :state_around], @before_callbacks
964
+ end
965
+
966
+ it 'should_halt_if_around_callback_halted_before_yield_for_second_transition' do
967
+ @status.around_transition { throw :halt }
968
+
969
+ assert_equal false, @transitions.perform
970
+ assert_equal [:state_before, :state_around, :status_before, :status_around], @before_callbacks
971
+ end
972
+
973
+ it 'should_run_after_callbacks_in_reverse_order' do
974
+ @transitions.perform
975
+ assert_equal [:status_around, :status_after, :state_around, :state_after], @after_callbacks
976
+ end
977
+
978
+ it 'should_not_halt_if_after_callback_halted_for_first_transition' do
979
+ @state.after_transition { throw :halt }
980
+
981
+ assert_equal true, @transitions.perform
982
+ assert_equal [:status_around, :status_after, :state_around, :state_after], @after_callbacks
983
+ end
984
+
985
+ it 'should_not_halt_if_around_callback_halted_for_second_transition' do
986
+ @status.around_transition { |block| block.call; throw :halt }
987
+
988
+ assert_equal true, @transitions.perform
989
+ assert_equal [:state_around, :state_after], @after_callbacks
990
+ end
991
+
992
+ it 'should_run_before_callbacks_before_persisting_the_state' do
993
+ @state.before_transition { |object| @before_state = object.state }
994
+ @state.around_transition { |object, transition, block| @around_state = object.state; block.call }
995
+ @transitions.perform
996
+
997
+ assert_equal 'parked', @before_state
998
+ assert_equal 'parked', @around_state
999
+ end
1000
+
1001
+ it 'should_persist_state_before_running_action' do
1002
+ @klass.class_eval do
1003
+ attr_reader :saved_on_persist
1004
+
1005
+ def state=(value)
1006
+ @state = value
1007
+ @saved_on_persist = saved
1008
+ end
1009
+ end
1010
+
1011
+ @transitions.perform
1012
+ assert !@object.saved_on_persist
1013
+ end
1014
+
1015
+ it 'should_persist_state_before_running_action_block' do
1016
+ @klass.class_eval do
1017
+ attr_writer :saved
1018
+ attr_reader :saved_on_persist
1019
+
1020
+ def state=(value)
1021
+ @state = value
1022
+ @saved_on_persist = saved
1023
+ end
1024
+ end
1025
+
1026
+ @transitions.perform { @object.saved = true }
1027
+ assert !@object.saved_on_persist
1028
+ end
1029
+
1030
+ it 'should_run_after_callbacks_after_running_the_action' do
1031
+ @state.after_transition { |object| @after_saved = object.saved }
1032
+ @state.around_transition { |object, transition, block| block.call; @around_saved = object.saved }
1033
+ @transitions.perform
1034
+
1035
+ assert @after_saved
1036
+ assert @around_saved
1037
+ end
1038
+ end
1039
+
1040
+ context 'WithBeforeCallbackHalt' do
1041
+ before(:each) do
1042
+ @klass = Class.new do
1043
+ attr_reader :saved
1044
+
1045
+ def save
1046
+ @saved = true
1047
+ end
1048
+ end
1049
+ @before_count = 0
1050
+ @after_count = 0
1051
+
1052
+ @machine = StateMachines::Machine.new(@klass, :initial => :parked, :action => :save)
1053
+ @machine.state :idling
1054
+ @machine.event :ignite
1055
+
1056
+ @machine.before_transition { @before_count += 1; throw :halt }
1057
+ @machine.before_transition { @before_count += 1 }
1058
+ @machine.after_transition { @after_count += 1 }
1059
+ @machine.around_transition { |block| @before_count += 1; block.call; @after_count += 1 }
1060
+
1061
+ @object = @klass.new
1062
+
1063
+ @transitions = StateMachines::TransitionCollection.new([
1064
+ StateMachines::Transition.new(@object, @machine, :ignite, :parked, :idling)
1065
+ ])
1066
+ @result = @transitions.perform
1067
+ end
1068
+
1069
+ it 'should_not_succeed' do
1070
+ assert_equal false, @result
1071
+ end
1072
+
1073
+ it 'should_not_persist_state' do
1074
+ assert_equal 'parked', @object.state
1075
+ end
1076
+
1077
+ it 'should_not_run_action' do
1078
+ assert !@object.saved
1079
+ end
1080
+
1081
+ it 'should_not_run_further_before_callbacks' do
1082
+ assert_equal 1, @before_count
1083
+ end
1084
+
1085
+ it 'should_not_run_after_callbacks' do
1086
+ assert_equal 0, @after_count
1087
+ end
1088
+ end
1089
+
1090
+ context 'WithAfterCallbackHalt' do
1091
+ before(:each) do
1092
+ @klass = Class.new do
1093
+ attr_reader :saved
1094
+
1095
+ def save
1096
+ @saved = true
1097
+ end
1098
+ end
1099
+ @before_count = 0
1100
+ @after_count = 0
1101
+
1102
+ @machine = StateMachines::Machine.new(@klass, :initial => :parked, :action => :save)
1103
+ @machine.state :idling
1104
+ @machine.event :ignite
1105
+
1106
+ @machine.before_transition { @before_count += 1 }
1107
+ @machine.after_transition { @after_count += 1; throw :halt }
1108
+ @machine.after_transition { @after_count += 1 }
1109
+ @machine.around_transition { |block| @before_count += 1; block.call; @after_count += 1 }
1110
+
1111
+ @object = @klass.new
1112
+
1113
+ @transitions = StateMachines::TransitionCollection.new([
1114
+ StateMachines::Transition.new(@object, @machine, :ignite, :parked, :idling)
1115
+ ])
1116
+ @result = @transitions.perform
1117
+ end
1118
+
1119
+ it 'should_succeed' do
1120
+ assert_equal true, @result
1121
+ end
1122
+
1123
+ it 'should_persist_state' do
1124
+ assert_equal 'idling', @object.state
1125
+ end
1126
+
1127
+ it 'should_run_before_callbacks' do
1128
+ assert_equal 2, @before_count
1129
+ end
1130
+
1131
+ it 'should_not_run_further_after_callbacks' do
1132
+ assert_equal 2, @after_count
1133
+ end
1134
+ end
1135
+
1136
+ context 'WithSkippedAfterCallbacks' do
1137
+ before(:each) do
1138
+ @klass = Class.new
1139
+
1140
+ @callbacks = []
1141
+
1142
+ @machine = StateMachines::Machine.new(@klass, :initial => :parked)
1143
+ @machine.state :idling
1144
+ @machine.event :ignite
1145
+ @machine.after_transition { @callbacks << :after }
1146
+
1147
+ @object = @klass.new
1148
+
1149
+ @transitions = StateMachines::TransitionCollection.new([
1150
+ @transition = StateMachines::Transition.new(@object, @machine, :ignite, :parked, :idling)
1151
+ ], :after => false)
1152
+ @result = @transitions.perform
1153
+ end
1154
+
1155
+ it 'should_succeed' do
1156
+ assert_equal true, @result
1157
+ end
1158
+
1159
+ it 'should_not_run_after_callbacks' do
1160
+ assert !@callbacks.include?(:after)
1161
+ end
1162
+
1163
+ it 'should_run_after_callbacks_on_subsequent_perform' do
1164
+ StateMachines::TransitionCollection.new([@transition]).perform
1165
+ assert @callbacks.include?(:after)
1166
+ end
1167
+ end
1168
+
1169
+ if StateMachines::Transition.pause_supported?
1170
+ context 'WithSkippedAfterCallbacksAndAroundCallbacks' do
1171
+ before(:each) do
1172
+ @klass = Class.new
1173
+
1174
+ @callbacks = []
1175
+
1176
+ @machine = StateMachines::Machine.new(@klass, :initial => :parked)
1177
+ @machine.state :idling
1178
+ @machine.event :ignite
1179
+ @machine.around_transition { |block| @callbacks << :around_before; block.call; @callbacks << :around_after }
1180
+
1181
+ @object = @klass.new
1182
+
1183
+ @transitions = StateMachines::TransitionCollection.new([
1184
+ @transition = StateMachines::Transition.new(@object, @machine, :ignite, :parked, :idling)
1185
+ ], :after => false)
1186
+ @result = @transitions.perform
1187
+ end
1188
+
1189
+ it 'should_succeed' do
1190
+ assert_equal true, @result
1191
+ end
1192
+
1193
+ it 'should_not_run_around_callbacks_after_yield' do
1194
+ assert !@callbacks.include?(:around_after)
1195
+ end
1196
+
1197
+ it 'should_run_around_callbacks_after_yield_on_subsequent_perform' do
1198
+ StateMachines::TransitionCollection.new([@transition]).perform
1199
+ assert @callbacks.include?(:around_after)
1200
+ end
1201
+
1202
+ it 'should_not_rerun_around_callbacks_before_yield_on_subsequent_perform' do
1203
+ @callbacks = []
1204
+ StateMachines::TransitionCollection.new([@transition]).perform
1205
+
1206
+ assert !@callbacks.include?(:around_before)
1207
+ end
1208
+ end
1209
+ else
1210
+ context 'WithSkippedAfterCallbacksAndAroundCallbacks' do
1211
+ before(:each) do
1212
+ @klass = Class.new
1213
+
1214
+ @callbacks = []
1215
+
1216
+ @machine = StateMachines::Machine.new(@klass, :initial => :parked)
1217
+ @machine.state :idling
1218
+ @machine.event :ignite
1219
+ @machine.around_transition { |block| @callbacks << :around_before; block.call; @callbacks << :around_after }
1220
+
1221
+ @object = @klass.new
1222
+
1223
+ @transitions = StateMachines::TransitionCollection.new([
1224
+ @transition = StateMachines::Transition.new(@object, @machine, :ignite, :parked, :idling)
1225
+ ], :after => false)
1226
+ end
1227
+
1228
+ it 'should_raise_exception' do
1229
+ assert_raise(ArgumentError) { @transitions.perform }
1230
+ end
1231
+ end
1232
+ end
1233
+
1234
+ xit 'WithActionHookBase' do
1235
+ before(:each) do
1236
+ @class = Class.new do
1237
+ def save
1238
+ true
1239
+ end
1240
+ end
1241
+
1242
+ @klass = Class.new(@class) do
1243
+ attr_reader :saved, :state_on_save, :state_event_on_save, :state_event_transition_on_save
1244
+
1245
+ def save
1246
+ @saved = true
1247
+ @state_on_save = state
1248
+ @state_event_on_save = state_event
1249
+ @state_event_transition_on_save = state_event_transition
1250
+
1251
+ end
1252
+ end
1253
+
1254
+ @machine = StateMachines::Machine.new(@klass, :initial => :parked, :action => :save)
1255
+ @machine.state :idling
1256
+ @machine.event :ignite
1257
+
1258
+ @object = @klass.new
1259
+
1260
+ @transition = StateMachines::Transition.new(@object, @machine, :ignite, :parked, :idling)
1261
+ end
1262
+
1263
+
1264
+ context 'WithActionHookAndSkippedAction' do
1265
+ before(:each) do
1266
+ @result = StateMachines::TransitionCollection.new([@transition], :actions => false).perform
1267
+ end
1268
+
1269
+ it 'should_succeed' do
1270
+ assert_equal true, @result
1271
+ end
1272
+
1273
+ it 'should_not_run_action' do
1274
+ assert !@object.saved
1275
+ end
1276
+ end
1277
+
1278
+ context 'WithActionHookAndSkippedAfterCallbacks' do
1279
+ before(:each) do
1280
+ @result = StateMachines::TransitionCollection.new([@transition], :after => false).perform
1281
+ end
1282
+
1283
+ it 'should_succeed' do
1284
+ assert_equal true, @result
1285
+ end
1286
+
1287
+ it 'should_run_action' do
1288
+ assert @object.saved
1289
+ end
1290
+
1291
+ it 'should_have_already_persisted_when_running_action' do
1292
+ assert_equal 'idling', @object.state_on_save
1293
+ end
1294
+
1295
+ it 'should_not_have_event_during_action' do
1296
+ assert_nil @object.state_event_on_save
1297
+ end
1298
+
1299
+ it 'should_not_write_event' do
1300
+ assert_nil @object.state_event
1301
+ end
1302
+
1303
+ it 'should_not_have_event_transition_during_save' do
1304
+ assert_nil @object.state_event_transition_on_save
1305
+ end
1306
+
1307
+ it 'should_not_write_event_attribute' do
1308
+ assert_nil @object.send(:state_event_transition)
1309
+ end
1310
+ end
1311
+
1312
+ context 'WithActionHookAndBlock' do
1313
+ before(:each) do
1314
+
1315
+ @result = StateMachines::TransitionCollection.new([@transition]).perform { true }
1316
+ end
1317
+
1318
+ it 'should_succeed' do
1319
+ assert_equal true, @result
1320
+ end
1321
+
1322
+ it 'should_not_run_action' do
1323
+ assert !@object.saved
1324
+ end
1325
+ end
1326
+
1327
+ context 'WithActionHookInvalid' do
1328
+ before(:each) do
1329
+
1330
+ @result = StateMachines::TransitionCollection.new([@transition, nil]).perform
1331
+ end
1332
+
1333
+ it 'should_not_succeed' do
1334
+ assert_equal false, @result
1335
+ end
1336
+
1337
+ it 'should_not_run_action' do
1338
+ assert !@object.saved
1339
+ end
1340
+ end
1341
+
1342
+ context 'WithActionHookWithNilAction' do
1343
+ before(:each) do
1344
+
1345
+
1346
+ @machine = StateMachines::Machine.new(@klass, :status, :initial => :first_gear)
1347
+ @machine.state :second_gear
1348
+ @machine.event :shift_up
1349
+
1350
+ @result = StateMachines::TransitionCollection.new([@transition, StateMachines::Transition.new(@object, @machine, :shift_up, :first_gear, :second_gear)]).perform
1351
+ end
1352
+
1353
+ it 'should_succeed' do
1354
+ assert_equal true, @result
1355
+ end
1356
+
1357
+ it 'should_run_action' do
1358
+ assert @object.saved
1359
+ end
1360
+
1361
+ it 'should_have_already_persisted_when_running_action' do
1362
+ assert_equal 'idling', @object.state_on_save
1363
+ end
1364
+
1365
+ it 'should_not_have_event_during_action' do
1366
+ assert_nil @object.state_event_on_save
1367
+ end
1368
+
1369
+ it 'should_not_write_event' do
1370
+ assert_nil @object.state_event
1371
+ end
1372
+
1373
+ it 'should_not_have_event_transition_during_save' do
1374
+ assert_nil @object.state_event_transition_on_save
1375
+ end
1376
+
1377
+ it 'should_not_write_event_attribute' do
1378
+ assert_nil @object.send(:state_event_transition)
1379
+ end
1380
+ end
1381
+
1382
+ context 'WithActionHookWithDifferentActions' do
1383
+ before(:each) do
1384
+
1385
+
1386
+ @klass.class_eval do
1387
+ def save_status
1388
+ true
1389
+ end
1390
+ end
1391
+
1392
+ @machine = StateMachines::Machine.new(@klass, :status, :initial => :first_gear, :action => :save_status)
1393
+ @machine.state :second_gear
1394
+ @machine.event :shift_up
1395
+
1396
+ @result = StateMachines::TransitionCollection.new([@transition, StateMachines::Transition.new(@object, @machine, :shift_up, :first_gear, :second_gear)]).perform
1397
+ end
1398
+
1399
+ it 'should_succeed' do
1400
+ assert_equal true, @result
1401
+ end
1402
+
1403
+ it 'should_run_action' do
1404
+ assert @object.saved
1405
+ end
1406
+
1407
+ it 'should_have_already_persisted_when_running_action' do
1408
+ assert_equal 'idling', @object.state_on_save
1409
+ end
1410
+
1411
+ it 'should_not_have_event_during_action' do
1412
+ assert_nil @object.state_event_on_save
1413
+ end
1414
+
1415
+ it 'should_not_write_event' do
1416
+ assert_nil @object.state_event
1417
+ end
1418
+
1419
+ it 'should_not_have_event_transition_during_save' do
1420
+ assert_nil @object.state_event_transition_on_save
1421
+ end
1422
+
1423
+ it 'should_not_write_event_attribute' do
1424
+ assert_nil @object.send(:state_event_transition)
1425
+ end
1426
+ end
1427
+
1428
+ context 'WithActionHook' do
1429
+ before(:each) do
1430
+
1431
+ @result = StateMachines::TransitionCollection.new([@transition]).perform
1432
+ end
1433
+
1434
+ it 'should_succeed' do
1435
+ assert_equal true, @result
1436
+ end
1437
+
1438
+ it 'should_run_action' do
1439
+ assert @object.saved
1440
+ end
1441
+
1442
+ it 'should_not_have_already_persisted_when_running_action' do
1443
+ assert_equal 'parked', @object.state_on_save
1444
+ end
1445
+
1446
+ it 'should_persist' do
1447
+ assert_equal 'idling', @object.state
1448
+ end
1449
+
1450
+ it 'should_not_have_event_during_action' do
1451
+ assert_nil @object.state_event_on_save
1452
+ end
1453
+
1454
+ it 'should_not_write_event' do
1455
+ assert_nil @object.state_event
1456
+ end
1457
+
1458
+ it 'should_have_event_transition_during_action' do
1459
+ assert_equal @transition, @object.state_event_transition_on_save
1460
+ end
1461
+
1462
+ it 'should_not_write_event_transition' do
1463
+ assert_nil @object.send(:state_event_transition)
1464
+ end
1465
+
1466
+ it 'should_mark_event_transition_as_transient' do
1467
+ assert @transition.transient?
1468
+ end
1469
+ end
1470
+
1471
+ context 'WithActionHookMultiple' do
1472
+ before(:each) do
1473
+
1474
+
1475
+ @status_machine = StateMachines::Machine.new(@klass, :status, :initial => :first_gear, :action => :save)
1476
+ @status_machine.state :second_gear
1477
+ @status_machine.event :shift_up
1478
+
1479
+ @klass.class_eval do
1480
+ attr_reader :status_on_save, :status_event_on_save, :status_event_transition_on_save
1481
+
1482
+ remove_method :save
1483
+
1484
+ def save
1485
+ @saved = true
1486
+ @state_on_save = state
1487
+ @state_event_on_save = state_event
1488
+ @state_event_transition_on_save = state_event_transition
1489
+ @status_on_save = status
1490
+ @status_event_on_save = status_event
1491
+ @status_event_transition_on_save = status_event_transition
1492
+
1493
+ 1
1494
+ end
1495
+ end
1496
+
1497
+ @object = @klass.new
1498
+ @state_transition = StateMachines::Transition.new(@object, @machine, :ignite, :parked, :idling)
1499
+ @status_transition = StateMachines::Transition.new(@object, @status_machine, :shift_up, :first_gear, :second_gear)
1500
+
1501
+ @result = StateMachines::TransitionCollection.new([@state_transition, @status_transition]).perform
1502
+ end
1503
+
1504
+ it 'should_succeed' do
1505
+ assert_equal 1, @result
1506
+ end
1507
+
1508
+ it 'should_run_action' do
1509
+ assert @object.saved
1510
+ end
1511
+
1512
+ it 'should_not_have_already_persisted_when_running_action' do
1513
+ assert_equal 'parked', @object.state_on_save
1514
+ assert_equal 'first_gear', @object.status_on_save
1515
+ end
1516
+
1517
+ it 'should_persist' do
1518
+ assert_equal 'idling', @object.state
1519
+ assert_equal 'second_gear', @object.status
1520
+ end
1521
+
1522
+ it 'should_not_have_events_during_action' do
1523
+ assert_nil @object.state_event_on_save
1524
+ assert_nil @object.status_event_on_save
1525
+ end
1526
+
1527
+ it 'should_not_write_events' do
1528
+ assert_nil @object.state_event
1529
+ assert_nil @object.status_event
1530
+ end
1531
+
1532
+ it 'should_have_event_transitions_during_action' do
1533
+ assert_equal @state_transition, @object.state_event_transition_on_save
1534
+ assert_equal @status_transition, @object.status_event_transition_on_save
1535
+ end
1536
+
1537
+ it 'should_not_write_event_transitions' do
1538
+ assert_nil @object.send(:state_event_transition)
1539
+ assert_nil @object.send(:status_event_transition)
1540
+ end
1541
+
1542
+ it 'should_mark_event_transitions_as_transient' do
1543
+ assert @state_transition.transient?
1544
+ assert @status_transition.transient?
1545
+ end
1546
+ end
1547
+
1548
+ context 'WithActionHookError' do
1549
+ before(:each) do
1550
+
1551
+
1552
+ @class.class_eval do
1553
+ remove_method :save
1554
+
1555
+ def save
1556
+ raise ArgumentError
1557
+ end
1558
+ end
1559
+
1560
+ begin
1561
+ ; StateMachines::TransitionCollection.new([@transition]).perform;
1562
+ rescue;
1563
+ end
1564
+ end
1565
+
1566
+ it 'should_not_write_event' do
1567
+ assert_nil @object.state_event
1568
+ end
1569
+
1570
+ it 'should_not_write_event_transition' do
1571
+ assert_nil @object.send(:state_event_transition)
1572
+ end
1573
+ end
1574
+
1575
+ context 'AttributeTransitionCollectionByDefault' do
1576
+ before(:each) do
1577
+ @transitions = StateMachines::AttributeTransitionCollection.new
1578
+ end
1579
+
1580
+ it 'should_skip_actions' do
1581
+ assert @transitions.skip_actions
1582
+ end
1583
+
1584
+ it 'should_not_skip_after' do
1585
+ assert !@transitions.skip_after
1586
+ end
1587
+
1588
+ it 'should_not_use_transaction' do
1589
+ assert !@transitions.use_transaction
1590
+ end
1591
+
1592
+ it 'should_be_empty' do
1593
+ assert @transitions.empty?
1594
+ end
1595
+ end
1596
+
1597
+ context 'AttributeTransitionCollectionWithEvents' do
1598
+ before(:each) do
1599
+ @klass = Class.new
1600
+
1601
+ @state = StateMachines::Machine.new(@klass, :initial => :parked, :action => :save)
1602
+ @state.state :idling
1603
+ @state.event :ignite
1604
+
1605
+ @status = StateMachines::Machine.new(@klass, :status, :initial => :first_gear, :action => :save)
1606
+ @status.state :second_gear
1607
+ @status.event :shift_up
1608
+
1609
+ @object = @klass.new
1610
+ @object.state_event = 'ignite'
1611
+ @object.status_event = 'shift_up'
1612
+
1613
+ @transitions = StateMachines::AttributeTransitionCollection.new([
1614
+ @state_transition = StateMachines::Transition.new(@object, @state, :ignite, :parked, :idling),
1615
+ @status_transition = StateMachines::Transition.new(@object, @status, :shift_up, :first_gear, :second_gear)
1616
+ ])
1617
+ @result = @transitions.perform
1618
+ end
1619
+
1620
+ it 'should_succeed' do
1621
+ assert_equal true, @result
1622
+ end
1623
+
1624
+ it 'should_persist_states' do
1625
+ assert_equal 'idling', @object.state
1626
+ assert_equal 'second_gear', @object.status
1627
+ end
1628
+
1629
+ it 'should_clear_events' do
1630
+ assert_nil @object.state_event
1631
+ assert_nil @object.status_event
1632
+ end
1633
+
1634
+ it 'should_not_write_event_transitions' do
1635
+ assert_nil @object.send(:state_event_transition)
1636
+ assert_nil @object.send(:status_event_transition)
1637
+ end
1638
+ end
1639
+
1640
+ context 'AttributeTransitionCollectionWithEventTransitions' do
1641
+ before(:each) do
1642
+ @klass = Class.new
1643
+
1644
+ @state = StateMachines::Machine.new(@klass, :initial => :parked, :action => :save)
1645
+ @state.state :idling
1646
+ @state.event :ignite
1647
+
1648
+ @status = StateMachines::Machine.new(@klass, :status, :initial => :first_gear, :action => :save)
1649
+ @status.state :second_gear
1650
+ @status.event :shift_up
1651
+
1652
+ @object = @klass.new
1653
+ @object.send(:state_event_transition=, @state_transition = StateMachines::Transition.new(@object, @state, :ignite, :parked, :idling))
1654
+ @object.send(:status_event_transition=, @status_transition = StateMachines::Transition.new(@object, @status, :shift_up, :first_gear, :second_gear))
1655
+
1656
+ @transitions = StateMachines::AttributeTransitionCollection.new([@state_transition, @status_transition])
1657
+ @result = @transitions.perform
1658
+ end
1659
+
1660
+ it 'should_succeed' do
1661
+ assert_equal true, @result
1662
+ end
1663
+
1664
+ it 'should_persist_states' do
1665
+ assert_equal 'idling', @object.state
1666
+ assert_equal 'second_gear', @object.status
1667
+ end
1668
+
1669
+ it 'should_not_write_events' do
1670
+ assert_nil @object.state_event
1671
+ assert_nil @object.status_event
1672
+ end
1673
+
1674
+ it 'should_clear_event_transitions' do
1675
+ assert_nil @object.send(:state_event_transition)
1676
+ assert_nil @object.send(:status_event_transition)
1677
+ end
1678
+ end
1679
+
1680
+ context 'AttributeTransitionCollectionWithActionFailed' do
1681
+ before(:each) do
1682
+ @klass = Class.new
1683
+
1684
+ @state = StateMachines::Machine.new(@klass, :initial => :parked, :action => :save)
1685
+ @state.state :idling
1686
+ @state.event :ignite
1687
+
1688
+ @status = StateMachines::Machine.new(@klass, :status, :initial => :first_gear, :action => :save)
1689
+ @status.state :second_gear
1690
+ @status.event :shift_up
1691
+
1692
+ @object = @klass.new
1693
+ @object.state_event = 'ignite'
1694
+ @object.status_event = 'shift_up'
1695
+
1696
+ @transitions = StateMachines::AttributeTransitionCollection.new([
1697
+ @state_transition = StateMachines::Transition.new(@object, @state, :ignite, :parked, :idling),
1698
+ @status_transition = StateMachines::Transition.new(@object, @status, :shift_up, :first_gear, :second_gear)
1699
+ ])
1700
+ @result = @transitions.perform { false }
1701
+ end
1702
+
1703
+ it 'should_not_succeed' do
1704
+ assert_equal false, @result
1705
+ end
1706
+
1707
+ it 'should_not_persist_states' do
1708
+ assert_equal 'parked', @object.state
1709
+ assert_equal 'first_gear', @object.status
1710
+ end
1711
+
1712
+ it 'should_not_clear_events' do
1713
+ assert_equal :ignite, @object.state_event
1714
+ assert_equal :shift_up, @object.status_event
1715
+ end
1716
+
1717
+ it 'should_not_write_event_transitions' do
1718
+ assert_nil @object.send(:state_event_transition)
1719
+ assert_nil @object.send(:status_event_transition)
1720
+ end
1721
+ end
1722
+
1723
+ context 'AttributeTransitionCollectionWithActionError' do
1724
+ before(:each) do
1725
+ @klass = Class.new
1726
+
1727
+ @state = StateMachines::Machine.new(@klass, :initial => :parked, :action => :save)
1728
+ @state.state :idling
1729
+ @state.event :ignite
1730
+
1731
+ @status = StateMachines::Machine.new(@klass, :status, :initial => :first_gear, :action => :save)
1732
+ @status.state :second_gear
1733
+ @status.event :shift_up
1734
+
1735
+ @object = @klass.new
1736
+ @object.state_event = 'ignite'
1737
+ @object.status_event = 'shift_up'
1738
+
1739
+ @transitions = StateMachines::AttributeTransitionCollection.new([
1740
+ @state_transition = StateMachines::Transition.new(@object, @state, :ignite, :parked, :idling),
1741
+ @status_transition = StateMachines::Transition.new(@object, @status, :shift_up, :first_gear, :second_gear)
1742
+ ])
1743
+
1744
+ begin
1745
+ ; @transitions.perform { raise ArgumentError };
1746
+ rescue;
1747
+ end
1748
+ end
1749
+
1750
+ it 'should_not_persist_states' do
1751
+ assert_equal 'parked', @object.state
1752
+ assert_equal 'first_gear', @object.status
1753
+ end
1754
+
1755
+ it 'should_not_clear_events' do
1756
+ assert_equal :ignite, @object.state_event
1757
+ assert_equal :shift_up, @object.status_event
1758
+ end
1759
+
1760
+ it 'should_not_write_event_transitions' do
1761
+ assert_nil @object.send(:state_event_transition)
1762
+ assert_nil @object.send(:status_event_transition)
1763
+ end
1764
+ end
1765
+
1766
+ context 'AttributeTransitionCollectionWithCallbacks' do
1767
+ before(:each) do
1768
+ @klass = Class.new
1769
+
1770
+ @state = StateMachines::Machine.new(@klass, :initial => :parked, :action => :save)
1771
+ @state.state :idling
1772
+ @state.event :ignite
1773
+
1774
+ @status = StateMachines::Machine.new(@klass, :status, :initial => :first_gear, :action => :save)
1775
+ @status.state :second_gear
1776
+ @status.event :shift_up
1777
+
1778
+ @object = @klass.new
1779
+
1780
+ @transitions = StateMachines::AttributeTransitionCollection.new([
1781
+ @state_transition = StateMachines::Transition.new(@object, @state, :ignite, :parked, :idling),
1782
+ @status_transition = StateMachines::Transition.new(@object, @status, :shift_up, :first_gear, :second_gear)
1783
+ ])
1784
+ end
1785
+
1786
+ it 'should_not_have_events_during_before_callbacks' do
1787
+ @state.before_transition { |object, transition| @before_state_event = object.state_event }
1788
+ @state.around_transition { |object, transition, block| @around_state_event = object.state_event; block.call }
1789
+ @transitions.perform
1790
+
1791
+ assert_nil @before_state_event
1792
+ assert_nil @around_state_event
1793
+ end
1794
+
1795
+ it 'should_not_have_events_during_action' do
1796
+ @transitions.perform { @state_event = @object.state_event }
1797
+
1798
+ assert_nil @state_event
1799
+ end
1800
+
1801
+ it 'should_not_have_events_during_after_callbacks' do
1802
+ @state.after_transition { |object, transition| @after_state_event = object.state_event }
1803
+ @state.around_transition { |object, transition, block| block.call; @around_state_event = object.state_event }
1804
+ @transitions.perform
1805
+
1806
+ assert_nil @after_state_event
1807
+ assert_nil @around_state_event
1808
+ end
1809
+
1810
+ it 'should_not_have_event_transitions_during_before_callbacks' do
1811
+ @state.before_transition { |object, transition| @state_event_transition = object.send(:state_event_transition) }
1812
+ @transitions.perform
1813
+
1814
+ assert_nil @state_event_transition
1815
+ end
1816
+
1817
+ it 'should_not_have_event_transitions_during_action' do
1818
+ @transitions.perform { @state_event_transition = @object.send(:state_event_transition) }
1819
+
1820
+ assert_nil @state_event_transition
1821
+ end
1822
+
1823
+ it 'should_not_have_event_transitions_during_after_callbacks' do
1824
+ @state.after_transition { |object, transition| @after_state_event_transition = object.send(:state_event_transition) }
1825
+ @state.around_transition { |object, transition, block| block.call; @around_state_event_transition = object.send(:state_event_transition) }
1826
+ @transitions.perform
1827
+
1828
+ assert_nil @after_state_event_transition
1829
+ assert_nil @around_state_event_transition
1830
+ end
1831
+ end
1832
+
1833
+ context 'AttributeTransitionCollectionWithBeforeCallbackHalt' do
1834
+ before(:each) do
1835
+ @klass = Class.new
1836
+
1837
+ @machine = StateMachines::Machine.new(@klass, :initial => :parked, :action => :save)
1838
+ @machine.state :idling
1839
+ @machine.event :ignite
1840
+
1841
+ @machine.before_transition { throw :halt }
1842
+
1843
+ @object = @klass.new
1844
+ @object.state_event = 'ignite'
1845
+
1846
+ @transitions = StateMachines::AttributeTransitionCollection.new([
1847
+ StateMachines::Transition.new(@object, @machine, :ignite, :parked, :idling)
1848
+ ])
1849
+ @result = @transitions.perform
1850
+ end
1851
+
1852
+ it 'should_not_succeed' do
1853
+ assert_equal false, @result
1854
+ end
1855
+
1856
+ it 'should_not_clear_event' do
1857
+ assert_equal :ignite, @object.state_event
1858
+ end
1859
+
1860
+ it 'should_not_write_event_transition' do
1861
+ assert_nil @object.send(:state_event_transition)
1862
+ end
1863
+ end
1864
+
1865
+ context 'AttributeTransitionCollectionWithBeforeCallbackError' do
1866
+ before(:each) do
1867
+ @klass = Class.new
1868
+
1869
+ @machine = StateMachines::Machine.new(@klass, :initial => :parked, :action => :save)
1870
+ @machine.state :idling
1871
+ @machine.event :ignite
1872
+
1873
+ @machine.before_transition { raise ArgumentError }
1874
+
1875
+ @object = @klass.new
1876
+ @object.state_event = 'ignite'
1877
+
1878
+ @transitions = StateMachines::AttributeTransitionCollection.new([
1879
+ StateMachines::Transition.new(@object, @machine, :ignite, :parked, :idling)
1880
+ ])
1881
+ begin
1882
+ ; @transitions.perform;
1883
+ rescue;
1884
+ end
1885
+ end
1886
+
1887
+ it 'should_not_clear_event' do
1888
+ assert_equal :ignite, @object.state_event
1889
+ end
1890
+
1891
+ it 'should_not_write_event_transition' do
1892
+ assert_nil @object.send(:state_event_transition)
1893
+ end
1894
+ end
1895
+
1896
+ context 'AttributeTransitionCollectionWithAroundCallbackBeforeYieldHalt' do
1897
+ before(:each) do
1898
+ @klass = Class.new
1899
+
1900
+ @machine = StateMachines::Machine.new(@klass, :initial => :parked, :action => :save)
1901
+ @machine.state :idling
1902
+ @machine.event :ignite
1903
+
1904
+ @machine.around_transition { throw :halt }
1905
+
1906
+ @object = @klass.new
1907
+ @object.state_event = 'ignite'
1908
+
1909
+ @transitions = StateMachines::AttributeTransitionCollection.new([
1910
+ StateMachines::Transition.new(@object, @machine, :ignite, :parked, :idling)
1911
+ ])
1912
+ @result = @transitions.perform
1913
+ end
1914
+
1915
+ it 'should_not_succeed' do
1916
+ assert_equal false, @result
1917
+ end
1918
+
1919
+ it 'should_not_clear_event' do
1920
+ assert_equal :ignite, @object.state_event
1921
+ end
1922
+
1923
+ it 'should_not_write_event_transition' do
1924
+ assert_nil @object.send(:state_event_transition)
1925
+ end
1926
+ end
1927
+
1928
+ context 'AttributeTransitionCollectionWithAroundAfterYieldCallbackError' do
1929
+ before(:each) do
1930
+ @klass = Class.new
1931
+
1932
+ @machine = StateMachines::Machine.new(@klass, :initial => :parked, :action => :save)
1933
+ @machine.state :idling
1934
+ @machine.event :ignite
1935
+
1936
+ @machine.before_transition { raise ArgumentError }
1937
+
1938
+ @object = @klass.new
1939
+ @object.state_event = 'ignite'
1940
+
1941
+ @transitions = StateMachines::AttributeTransitionCollection.new([
1942
+ StateMachines::Transition.new(@object, @machine, :ignite, :parked, :idling)
1943
+ ])
1944
+ begin
1945
+ ; @transitions.perform;
1946
+ rescue;
1947
+ end
1948
+ end
1949
+
1950
+ it 'should_not_clear_event' do
1951
+ assert_equal :ignite, @object.state_event
1952
+ end
1953
+
1954
+ it 'should_not_write_event_transition' do
1955
+ assert_nil @object.send(:state_event_transition)
1956
+ end
1957
+ end
1958
+
1959
+ context 'AttributeTransitionCollectionWithSkippedAfterCallbacks' do
1960
+ before(:each) do
1961
+ @klass = Class.new
1962
+
1963
+ @state = StateMachines::Machine.new(@klass, :initial => :parked, :action => :save)
1964
+ @state.state :idling
1965
+ @state.event :ignite
1966
+
1967
+ @status = StateMachines::Machine.new(@klass, :status, :initial => :first_gear, :action => :save)
1968
+ @status.state :second_gear
1969
+ @status.event :shift_up
1970
+
1971
+ @object = @klass.new
1972
+ @object.state_event = 'ignite'
1973
+ @object.status_event = 'shift_up'
1974
+
1975
+ @transitions = StateMachines::AttributeTransitionCollection.new([
1976
+ @state_transition = StateMachines::Transition.new(@object, @state, :ignite, :parked, :idling),
1977
+ @status_transition = StateMachines::Transition.new(@object, @status, :shift_up, :first_gear, :second_gear)
1978
+ ], :after => false)
1979
+ end
1980
+
1981
+ it 'should_clear_events' do
1982
+ @transitions.perform
1983
+ assert_nil @object.state_event
1984
+ assert_nil @object.status_event
1985
+ end
1986
+
1987
+ it 'should_write_event_transitions_if_success' do
1988
+ @transitions.perform { true }
1989
+ assert_equal @state_transition, @object.send(:state_event_transition)
1990
+ assert_equal @status_transition, @object.send(:status_event_transition)
1991
+ end
1992
+
1993
+ it 'should_not_write_event_transitions_if_failed' do
1994
+ @transitions.perform { false }
1995
+ assert_nil @object.send(:state_event_transition)
1996
+ assert_nil @object.send(:status_event_transition)
1997
+ end
1998
+ end
1999
+
2000
+ context 'AttributeTransitionCollectionWithAfterCallbackHalt' do
2001
+ before(:each) do
2002
+ @klass = Class.new
2003
+
2004
+ @machine = StateMachines::Machine.new(@klass, :initial => :parked, :action => :save)
2005
+ @machine.state :idling
2006
+ @machine.event :ignite
2007
+
2008
+ @machine.after_transition { throw :halt }
2009
+
2010
+ @object = @klass.new
2011
+ @object.state_event = 'ignite'
2012
+
2013
+ @transitions = StateMachines::AttributeTransitionCollection.new([
2014
+ StateMachines::Transition.new(@object, @machine, :ignite, :parked, :idling)
2015
+ ])
2016
+ @result = @transitions.perform
2017
+ end
2018
+
2019
+ it 'should_succeed' do
2020
+ assert_equal true, @result
2021
+ end
2022
+
2023
+ it 'should_clear_event' do
2024
+ assert_nil @object.state_event
2025
+ end
2026
+
2027
+ it 'should_not_write_event_transition' do
2028
+ assert_nil @object.send(:state_event_transition)
2029
+ end
2030
+ end
2031
+
2032
+ context 'AttributeTransitionCollectionWithAfterCallbackError' do
2033
+ before(:each) do
2034
+ @klass = Class.new
2035
+
2036
+ @machine = StateMachines::Machine.new(@klass, :initial => :parked, :action => :save)
2037
+ @machine.state :idling
2038
+ @machine.event :ignite
2039
+
2040
+ @machine.after_transition { raise ArgumentError }
2041
+
2042
+ @object = @klass.new
2043
+ @object.state_event = 'ignite'
2044
+
2045
+ @transitions = StateMachines::AttributeTransitionCollection.new([
2046
+ StateMachines::Transition.new(@object, @machine, :ignite, :parked, :idling)
2047
+ ])
2048
+ begin
2049
+ ; @transitions.perform;
2050
+ rescue;
2051
+ end
2052
+ end
2053
+
2054
+ it 'should_clear_event' do
2055
+ assert_nil @object.state_event
2056
+ end
2057
+
2058
+ it 'should_not_write_event_transition' do
2059
+ assert_nil @object.send(:state_event_transition)
2060
+ end
2061
+ end
2062
+
2063
+ context 'AttributeTransitionCollectionWithAroundCallbackAfterYieldHalt' do
2064
+ before(:each) do
2065
+ @klass = Class.new
2066
+
2067
+ @machine = StateMachines::Machine.new(@klass, :initial => :parked, :action => :save)
2068
+ @machine.state :idling
2069
+ @machine.event :ignite
2070
+
2071
+ @machine.around_transition { |block| block.call; throw :halt }
2072
+
2073
+ @object = @klass.new
2074
+ @object.state_event = 'ignite'
2075
+
2076
+ @transitions = StateMachines::AttributeTransitionCollection.new([
2077
+ StateMachines::Transition.new(@object, @machine, :ignite, :parked, :idling)
2078
+ ])
2079
+ @result = @transitions.perform
2080
+ end
2081
+
2082
+ it 'should_succeed' do
2083
+ assert_equal true, @result
2084
+ end
2085
+
2086
+ it 'should_clear_event' do
2087
+ assert_nil @object.state_event
2088
+ end
2089
+
2090
+ it 'should_not_write_event_transition' do
2091
+ assert_nil @object.send(:state_event_transition)
2092
+ end
2093
+ end
2094
+
2095
+ context 'AttributeTransitionCollectionWithAroundCallbackAfterYieldError' do
2096
+ before(:each) do
2097
+ @klass = Class.new
2098
+
2099
+ @machine = StateMachines::Machine.new(@klass, :initial => :parked, :action => :save)
2100
+ @machine.state :idling
2101
+ @machine.event :ignite
2102
+
2103
+ @machine.around_transition { |block| block.call; raise ArgumentError }
2104
+
2105
+ @object = @klass.new
2106
+ @object.state_event = 'ignite'
2107
+
2108
+ @transitions = StateMachines::AttributeTransitionCollection.new([
2109
+ StateMachines::Transition.new(@object, @machine, :ignite, :parked, :idling)
2110
+ ])
2111
+ begin
2112
+ ; @transitions.perform;
2113
+ rescue;
2114
+ end
2115
+ end
2116
+
2117
+ it 'should_clear_event' do
2118
+ assert_nil @object.state_event
2119
+ end
2120
+
2121
+ it 'should_not_write_event_transition' do
2122
+ assert_nil @object.send(:state_event_transition)
2123
+ end
2124
+ end
2125
+
2126
+ context 'AttributeTransitionCollectionMarshalling' do
2127
+ before(:each) do
2128
+ @klass = Class.new
2129
+ self.class.const_set('Example', @klass)
2130
+
2131
+ @machine = StateMachines::Machine.new(@klass, :initial => :parked, :action => :save)
2132
+ @machine.state :idling
2133
+ @machine.event :ignite
2134
+
2135
+ @object = @klass.new
2136
+ @object.state_event = 'ignite'
2137
+ end
2138
+
2139
+ it 'should_marshal_during_before_callbacks' do
2140
+ @machine.before_transition { |object, transition| Marshal.dump(object) }
2141
+ assert_nothing_raised do
2142
+ transitions(:after => false).perform { true }
2143
+ transitions.perform { true }
2144
+ end
2145
+ end
2146
+
2147
+ it 'should_marshal_during_action' do
2148
+ assert_nothing_raised do
2149
+ transitions(:after => false).perform do
2150
+ Marshal.dump(@object)
2151
+ true
2152
+ end
2153
+
2154
+ transitions.perform do
2155
+ Marshal.dump(@object)
2156
+ true
2157
+ end
2158
+ end
2159
+ end
2160
+
2161
+ it 'should_marshal_during_after_callbacks' do
2162
+ @machine.after_transition { |object, transition| Marshal.dump(object) }
2163
+ assert_nothing_raised do
2164
+ transitions(:after => false).perform { true }
2165
+ transitions.perform { true }
2166
+ end
2167
+ end
2168
+
2169
+ if StateMachines::Transition.pause_supported?
2170
+ it 'should_marshal_during_around_callbacks_before_yield' do
2171
+ @machine.around_transition { |object, transition, block| Marshal.dump(object); block.call }
2172
+ assert_nothing_raised do
2173
+ transitions(:after => false).perform { true }
2174
+ transitions.perform { true }
2175
+ end
2176
+ end
2177
+
2178
+ it 'should_marshal_during_around_callbacks_after_yield' do
2179
+ @machine.around_transition { |object, transition, block| block.call; Marshal.dump(object) }
2180
+ assert_nothing_raised do
2181
+ transitions(:after => false).perform { true }
2182
+ transitions.perform { true }
2183
+ end
2184
+ end
2185
+ end
2186
+
2187
+ after(:each) do
2188
+ self.class.send(:remove_const, 'Example')
2189
+ end
2190
+
2191
+ private
2192
+ def transitions(options = {})
2193
+ StateMachines::AttributeTransitionCollection.new([
2194
+ StateMachines::Transition.new(@object, @machine, :ignite, :parked, :idling)
2195
+ ], options)
2196
+ end
2197
+ end
2198
+ end
2199
+ end