state_machines 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (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