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,1558 @@
1
+ require 'spec_helper'
2
+
3
+ context '' do
4
+ before(:each) do
5
+ @klass = Class.new
6
+ @machine = StateMachines::Machine.new(@klass)
7
+ @machine.state :parked, :idling
8
+ @machine.event :ignite
9
+
10
+ @object = @klass.new
11
+ @object.state = 'parked'
12
+
13
+ @transition = StateMachines::Transition.new(@object, @machine, :ignite, :parked, :idling)
14
+ end
15
+
16
+ it 'should_have_an_object' do
17
+ assert_equal @object, @transition.object
18
+ end
19
+
20
+ it 'should_have_a_machine' do
21
+ assert_equal @machine, @transition.machine
22
+ end
23
+
24
+ it 'should_have_an_event' do
25
+ assert_equal :ignite, @transition.event
26
+ end
27
+
28
+ it 'should_have_a_qualified_event' do
29
+ assert_equal :ignite, @transition.qualified_event
30
+ end
31
+
32
+ it 'should_have_a_human_event' do
33
+ assert_equal 'ignite', @transition.human_event
34
+ end
35
+
36
+ it 'should_have_a_from_value' do
37
+ assert_equal 'parked', @transition.from
38
+ end
39
+
40
+ it 'should_have_a_from_name' do
41
+ assert_equal :parked, @transition.from_name
42
+ end
43
+
44
+ it 'should_have_a_qualified_from_name' do
45
+ assert_equal :parked, @transition.qualified_from_name
46
+ end
47
+
48
+ it 'should_have_a_human_from_name' do
49
+ assert_equal 'parked', @transition.human_from_name
50
+ end
51
+
52
+ it 'should_have_a_to_value' do
53
+ assert_equal 'idling', @transition.to
54
+ end
55
+
56
+ it 'should_have_a_to_name' do
57
+ assert_equal :idling, @transition.to_name
58
+ end
59
+
60
+ it 'should_have_a_qualified_to_name' do
61
+ assert_equal :idling, @transition.qualified_to_name
62
+ end
63
+
64
+ it 'should_have_a_human_to_name' do
65
+ assert_equal 'idling', @transition.human_to_name
66
+ end
67
+
68
+ it 'should_have_an_attribute' do
69
+ assert_equal :state, @transition.attribute
70
+ end
71
+
72
+ it 'should_not_have_an_action' do
73
+ assert_nil @transition.action
74
+ end
75
+
76
+ it 'should_not_be_transient' do
77
+ assert_equal false, @transition.transient?
78
+ end
79
+
80
+ it 'should_generate_attributes' do
81
+ expected = {:object => @object, :attribute => :state, :event => :ignite, :from => 'parked', :to => 'idling'}
82
+ assert_equal expected, @transition.attributes
83
+ end
84
+
85
+ it 'should_have_empty_args' do
86
+ assert_equal [], @transition.args
87
+ end
88
+
89
+ it 'should_not_have_a_result' do
90
+ assert_nil @transition.result
91
+ end
92
+
93
+ it 'should_use_pretty_inspect' do
94
+ assert_equal '#<StateMachines::Transition attribute=:state event=:ignite from="parked" from_name=:parked to="idling" to_name=:idling>', @transition.inspect
95
+ end
96
+ end
97
+
98
+ context 'WithInvalidNodes' do
99
+ before(:each) do
100
+ @klass = Class.new
101
+ @machine = StateMachines::Machine.new(@klass)
102
+ @machine.state :parked, :idling
103
+ @machine.event :ignite
104
+
105
+ @object = @klass.new
106
+ @object.state = 'parked'
107
+ end
108
+
109
+ it 'should_raise_exception_without_event' do
110
+ assert_raise(IndexError) { StateMachines::Transition.new(@object, @machine, nil, :parked, :idling) }
111
+ end
112
+
113
+ it 'should_raise_exception_with_invalid_event' do
114
+ assert_raise(IndexError) { StateMachines::Transition.new(@object, @machine, :invalid, :parked, :idling) }
115
+ end
116
+
117
+ it 'should_raise_exception_with_invalid_from_state' do
118
+ assert_raise(IndexError) { StateMachines::Transition.new(@object, @machine, :ignite, :invalid, :idling) }
119
+ end
120
+
121
+ it 'should_raise_exception_with_invalid_to_state' do
122
+ assert_raise(IndexError) { StateMachines::Transition.new(@object, @machine, :ignite, :parked, :invalid) }
123
+ end
124
+ end
125
+
126
+ context 'WithDynamicToValue' do
127
+ before(:each) do
128
+ @klass = Class.new
129
+ @machine = StateMachines::Machine.new(@klass)
130
+ @machine.state :parked
131
+ @machine.state :idling, :value => lambda {1}
132
+ @machine.event :ignite
133
+
134
+ @object = @klass.new
135
+ @object.state = 'parked'
136
+ @transition = StateMachines::Transition.new(@object, @machine, :ignite, :parked, :idling)
137
+ end
138
+
139
+ it 'should_evaluate_to_value' do
140
+ assert_equal 1, @transition.to
141
+ end
142
+ end
143
+
144
+ context 'Loopback' do
145
+ before(:each) do
146
+ @klass = Class.new
147
+ @machine = StateMachines::Machine.new(@klass)
148
+ @machine.state :parked
149
+ @machine.event :park
150
+
151
+ @object = @klass.new
152
+ @object.state = 'parked'
153
+ @transition = StateMachines::Transition.new(@object, @machine, :park, :parked, :parked)
154
+ end
155
+
156
+ it 'should_be_loopback' do
157
+ assert @transition.loopback?
158
+ end
159
+ end
160
+
161
+ context 'WithDifferentStates' do
162
+ before(:each) do
163
+ @klass = Class.new
164
+ @machine = StateMachines::Machine.new(@klass)
165
+ @machine.state :parked, :idling
166
+ @machine.event :ignite
167
+
168
+ @object = @klass.new
169
+ @object.state = 'parked'
170
+ @transition = StateMachines::Transition.new(@object, @machine, :ignite, :parked, :idling)
171
+ end
172
+
173
+ it 'should_not_be_loopback' do
174
+ assert !@transition.loopback?
175
+ end
176
+ end
177
+
178
+ context 'WithNamespace' do
179
+ before(:each) do
180
+ @klass = Class.new
181
+ @machine = StateMachines::Machine.new(@klass, :namespace => 'alarm')
182
+ @machine.state :off, :active
183
+ @machine.event :activate
184
+
185
+ @object = @klass.new
186
+ @object.state = 'off'
187
+
188
+ @transition = StateMachines::Transition.new(@object, @machine, :activate, :off, :active)
189
+ end
190
+
191
+ it 'should_have_an_event' do
192
+ assert_equal :activate, @transition.event
193
+ end
194
+
195
+ it 'should_have_a_qualified_event' do
196
+ assert_equal :activate_alarm, @transition.qualified_event
197
+ end
198
+
199
+ it 'should_have_a_from_name' do
200
+ assert_equal :off, @transition.from_name
201
+ end
202
+
203
+ it 'should_have_a_qualified_from_name' do
204
+ assert_equal :alarm_off, @transition.qualified_from_name
205
+ end
206
+
207
+ it 'should_have_a_human_from_name' do
208
+ assert_equal 'off', @transition.human_from_name
209
+ end
210
+
211
+ it 'should_have_a_to_name' do
212
+ assert_equal :active, @transition.to_name
213
+ end
214
+
215
+ it 'should_have_a_qualified_to_name' do
216
+ assert_equal :alarm_active, @transition.qualified_to_name
217
+ end
218
+
219
+ it 'should_have_a_human_to_name' do
220
+ assert_equal 'active', @transition.human_to_name
221
+ end
222
+ end
223
+
224
+ context 'WithCustomMachineAttribute' do
225
+ before(:each) do
226
+ @klass = Class.new
227
+ @machine = StateMachines::Machine.new(@klass, :state, :attribute => :state_id)
228
+ @machine.state :off, :value => 1
229
+ @machine.state :active, :value => 2
230
+ @machine.event :activate
231
+
232
+ @object = @klass.new
233
+ @object.state_id = 1
234
+
235
+ @transition = StateMachines::Transition.new(@object, @machine, :activate, :off, :active)
236
+ end
237
+
238
+ it 'should_persist' do
239
+ @transition.persist
240
+ assert_equal 2, @object.state_id
241
+ end
242
+
243
+ it 'should_rollback' do
244
+ @object.state_id = 2
245
+ @transition.rollback
246
+
247
+ assert_equal 1, @object.state_id
248
+ end
249
+ end
250
+
251
+ context 'WithoutReadingState' do
252
+ before(:each) do
253
+ @klass = Class.new
254
+ @machine = StateMachines::Machine.new(@klass)
255
+ @machine.state :parked, :idling
256
+ @machine.event :ignite
257
+
258
+ @object = @klass.new
259
+ @object.state = 'idling'
260
+ @transition = StateMachines::Transition.new(@object, @machine, :ignite, :parked, :idling, false)
261
+ end
262
+
263
+ it 'should_not_read_from_value_from_object' do
264
+ assert_equal 'parked', @transition.from
265
+ end
266
+
267
+ it 'should_have_to_value' do
268
+ assert_equal 'idling', @transition.to
269
+ end
270
+ end
271
+
272
+ context 'WithAction' do
273
+ before(:each) do
274
+ @klass = Class.new do
275
+ def save
276
+ end
277
+ end
278
+
279
+ @machine = StateMachines::Machine.new(@klass, :action => :save)
280
+ @machine.state :parked, :idling
281
+ @machine.event :ignite
282
+
283
+ @object = @klass.new
284
+ @object.state = 'parked'
285
+
286
+ @transition = StateMachines::Transition.new(@object, @machine, :ignite, :parked, :idling)
287
+ end
288
+
289
+ it 'should_have_an_action' do
290
+ assert_equal :save, @transition.action
291
+ end
292
+
293
+ it 'should_not_have_a_result' do
294
+ assert_nil @transition.result
295
+ end
296
+ end
297
+
298
+ context 'AfterBeingPersisted' do
299
+ before(:each) do
300
+ @klass = Class.new
301
+ @machine = StateMachines::Machine.new(@klass, :action => :save)
302
+ @machine.state :parked, :idling
303
+ @machine.event :ignite
304
+
305
+ @object = @klass.new
306
+ @object.state = 'parked'
307
+
308
+ @transition = StateMachines::Transition.new(@object, @machine, :ignite, :parked, :idling)
309
+ @transition.persist
310
+ end
311
+
312
+ it 'should_update_state_value' do
313
+ assert_equal 'idling', @object.state
314
+ end
315
+
316
+ it 'should_not_change_from_state' do
317
+ assert_equal 'parked', @transition.from
318
+ end
319
+
320
+ it 'should_not_change_to_state' do
321
+ assert_equal 'idling', @transition.to
322
+ end
323
+
324
+ it 'should_not_be_able_to_persist_twice' do
325
+ @object.state = 'parked'
326
+ @transition.persist
327
+ assert_equal 'parked', @object.state
328
+ end
329
+
330
+ it 'should_be_able_to_persist_again_after_resetting' do
331
+ @object.state = 'parked'
332
+ @transition.reset
333
+ @transition.persist
334
+ assert_equal 'idling', @object.state
335
+ end
336
+
337
+ it 'should_revert_to_from_state_on_rollback' do
338
+ @transition.rollback
339
+ assert_equal 'parked', @object.state
340
+ end
341
+ end
342
+
343
+ context 'AfterBeingRolledBack' do
344
+ before(:each) do
345
+ @klass = Class.new
346
+ @machine = StateMachines::Machine.new(@klass, :action => :save)
347
+ @machine.state :parked, :idling
348
+ @machine.event :ignite
349
+
350
+ @object = @klass.new
351
+ @object.state = 'parked'
352
+
353
+ @transition = StateMachines::Transition.new(@object, @machine, :ignite, :parked, :idling)
354
+ @object.state = 'idling'
355
+
356
+ @transition.rollback
357
+ end
358
+
359
+ it 'should_update_state_value_to_from_state' do
360
+ assert_equal 'parked', @object.state
361
+ end
362
+
363
+ it 'should_not_change_from_state' do
364
+ assert_equal 'parked', @transition.from
365
+ end
366
+
367
+ it 'should_not_change_to_state' do
368
+ assert_equal 'idling', @transition.to
369
+ end
370
+
371
+ it 'should_still_be_able_to_persist' do
372
+ @transition.persist
373
+ assert_equal 'idling', @object.state
374
+ end
375
+ end
376
+
377
+ context 'WithoutCallbacks' do
378
+ before(:each) do
379
+ @klass = Class.new
380
+
381
+ @machine = StateMachines::Machine.new(@klass)
382
+ @machine.state :parked, :idling
383
+ @machine.event :ignite
384
+
385
+ @object = @klass.new
386
+ @object.state = 'parked'
387
+ @transition = StateMachines::Transition.new(@object, @machine, :ignite, :parked, :idling)
388
+ end
389
+
390
+ it 'should_succeed' do
391
+ assert_equal true, @transition.run_callbacks
392
+ end
393
+
394
+ it 'should_succeed_if_after_callbacks_skipped' do
395
+ assert_equal true, @transition.run_callbacks(:after => false)
396
+ end
397
+
398
+ it 'should_call_block_if_provided' do
399
+ @transition.run_callbacks { @ran_block = true; {} }
400
+ assert @ran_block
401
+ end
402
+
403
+ it 'should_track_block_result' do
404
+ @transition.run_callbacks {{:result => 1}}
405
+ assert_equal 1, @transition.result
406
+ end
407
+ end
408
+
409
+ context 'WithBeforeCallbacks' do
410
+ before(:each) do
411
+ @klass = Class.new
412
+
413
+ @machine = StateMachines::Machine.new(@klass)
414
+ @machine.state :parked, :idling
415
+ @machine.event :ignite
416
+
417
+ @object = @klass.new
418
+ @object.state = 'parked'
419
+ @transition = StateMachines::Transition.new(@object, @machine, :ignite, :parked, :idling)
420
+ end
421
+
422
+ it 'should_run_before_callbacks' do
423
+ @machine.before_transition {@run = true}
424
+ result = @transition.run_callbacks
425
+
426
+ assert_equal true, result
427
+ assert_equal true, @run
428
+ end
429
+
430
+ it 'should_only_run_those_that_match_transition_context' do
431
+ @count = 0
432
+ callback = lambda {@count += 1}
433
+
434
+ @machine.before_transition :from => :parked, :to => :idling, :on => :park, :do => callback
435
+ @machine.before_transition :from => :parked, :to => :parked, :on => :park, :do => callback
436
+ @machine.before_transition :from => :parked, :to => :idling, :on => :ignite, :do => callback
437
+ @machine.before_transition :from => :idling, :to => :idling, :on => :park, :do => callback
438
+ @transition.run_callbacks
439
+
440
+ assert_equal 1, @count
441
+ end
442
+
443
+ it 'should_pass_transition_as_argument' do
444
+ @machine.before_transition {|*args| @args = args}
445
+ @transition.run_callbacks
446
+
447
+ assert_equal [@object, @transition], @args
448
+ end
449
+
450
+ it 'should_catch_halts' do
451
+ @machine.before_transition {throw :halt}
452
+
453
+ result = nil
454
+ assert_nothing_thrown { result = @transition.run_callbacks }
455
+ assert_equal false, result
456
+ end
457
+
458
+ it 'should_not_catch_exceptions' do
459
+ @machine.before_transition {raise ArgumentError}
460
+ assert_raise(ArgumentError) { @transition.run_callbacks }
461
+ end
462
+
463
+ it 'should_not_be_able_to_run_twice' do
464
+ @count = 0
465
+ @machine.before_transition {@count += 1}
466
+ @transition.run_callbacks
467
+ @transition.run_callbacks
468
+ assert_equal 1, @count
469
+ end
470
+
471
+ it 'should_be_able_to_run_again_after_halt' do
472
+ @count = 0
473
+ @machine.before_transition {@count += 1; throw :halt}
474
+ @transition.run_callbacks
475
+ @transition.run_callbacks
476
+ assert_equal 2, @count
477
+ end
478
+
479
+ it 'should_be_able_to_run_again_after_resetting' do
480
+ @count = 0
481
+ @machine.before_transition {@count += 1}
482
+ @transition.run_callbacks
483
+ @transition.reset
484
+ @transition.run_callbacks
485
+ assert_equal 2, @count
486
+ end
487
+
488
+ it 'should_succeed_if_block_result_is_false' do
489
+ @machine.before_transition {@run = true}
490
+ assert_equal true, @transition.run_callbacks {{:result => false}}
491
+ assert @run
492
+ end
493
+
494
+ it 'should_succeed_if_block_result_is_true' do
495
+ @machine.before_transition {@run = true}
496
+ assert_equal true, @transition.run_callbacks {{:result => true}}
497
+ assert @run
498
+ end
499
+
500
+ it 'should_succeed_if_block_success_is_false' do
501
+ @machine.before_transition {@run = true}
502
+ assert_equal true, @transition.run_callbacks {{:success => false}}
503
+ assert @run
504
+ end
505
+
506
+ it 'should_succeed_if_block_success_is_true' do
507
+ @machine.before_transition {@run = true}
508
+ assert_equal true, @transition.run_callbacks {{:success => true}}
509
+ assert @run
510
+ end
511
+ end
512
+
513
+ context 'WithMultipleBeforeCallbacks' do
514
+ before(:each) do
515
+ @klass = Class.new
516
+
517
+ @machine = StateMachines::Machine.new(@klass)
518
+ @machine.state :parked, :idling
519
+ @machine.event :ignite
520
+
521
+ @object = @klass.new
522
+ @object.state = 'parked'
523
+ @transition = StateMachines::Transition.new(@object, @machine, :ignite, :parked, :idling)
524
+ end
525
+
526
+ it 'should_run_in_the_order_they_were_defined' do
527
+ @callbacks = []
528
+ @machine.before_transition {@callbacks << 1}
529
+ @machine.before_transition {@callbacks << 2}
530
+ @transition.run_callbacks
531
+
532
+ assert_equal [1, 2], @callbacks
533
+ end
534
+
535
+ it 'should_not_run_further_callbacks_if_halted' do
536
+ @callbacks = []
537
+ @machine.before_transition {@callbacks << 1; throw :halt}
538
+ @machine.before_transition {@callbacks << 2}
539
+
540
+ assert_equal false, @transition.run_callbacks
541
+ assert_equal [1], @callbacks
542
+ end
543
+
544
+ it 'should_fail_if_any_callback_halted' do
545
+ @machine.before_transition {true}
546
+ @machine.before_transition {throw :halt}
547
+
548
+ assert_equal false, @transition.run_callbacks
549
+ end
550
+ end
551
+
552
+ context 'WithAfterCallbacks' do
553
+ before(:each) do
554
+ @klass = Class.new
555
+
556
+ @machine = StateMachines::Machine.new(@klass)
557
+ @machine.state :parked, :idling
558
+ @machine.event :ignite
559
+
560
+ @object = @klass.new
561
+ @object.state = 'parked'
562
+ @transition = StateMachines::Transition.new(@object, @machine, :ignite, :parked, :idling)
563
+ end
564
+
565
+ it 'should_run_after_callbacks' do
566
+ @machine.after_transition {|object| @run = true}
567
+ result = @transition.run_callbacks
568
+
569
+ assert_equal true, result
570
+ assert_equal true, @run
571
+ end
572
+
573
+ it 'should_only_run_those_that_match_transition_context' do
574
+ @count = 0
575
+ callback = lambda {@count += 1}
576
+
577
+ @machine.after_transition :from => :parked, :to => :idling, :on => :park, :do => callback
578
+ @machine.after_transition :from => :parked, :to => :parked, :on => :park, :do => callback
579
+ @machine.after_transition :from => :parked, :to => :idling, :on => :ignite, :do => callback
580
+ @machine.after_transition :from => :idling, :to => :idling, :on => :park, :do => callback
581
+ @transition.run_callbacks
582
+
583
+ assert_equal 1, @count
584
+ end
585
+
586
+ it 'should_not_run_if_not_successful' do
587
+ @run = false
588
+ @machine.after_transition {|object| @run = true}
589
+ @transition.run_callbacks {{:success => false}}
590
+ assert !@run
591
+ end
592
+
593
+ it 'should_run_if_successful' do
594
+ @machine.after_transition {|object| @run = true}
595
+ @transition.run_callbacks {{:success => true}}
596
+ assert @run
597
+ end
598
+
599
+ it 'should_pass_transition_as_argument' do
600
+ @machine.after_transition {|*args| @args = args}
601
+
602
+ @transition.run_callbacks
603
+ assert_equal [@object, @transition], @args
604
+ end
605
+
606
+ it 'should_catch_halts' do
607
+ @machine.after_transition {throw :halt}
608
+
609
+ result = nil
610
+ assert_nothing_thrown { result = @transition.run_callbacks }
611
+ assert_equal true, result
612
+ end
613
+
614
+ it 'should_not_catch_exceptions' do
615
+ @machine.after_transition {raise ArgumentError}
616
+ assert_raise(ArgumentError) { @transition.run_callbacks }
617
+ end
618
+
619
+ it 'should_not_be_able_to_run_twice' do
620
+ @count = 0
621
+ @machine.after_transition {@count += 1}
622
+ @transition.run_callbacks
623
+ @transition.run_callbacks
624
+ assert_equal 1, @count
625
+ end
626
+
627
+ it 'should_not_be_able_to_run_twice_if_halted' do
628
+ @count = 0
629
+ @machine.after_transition {@count += 1; throw :halt}
630
+ @transition.run_callbacks
631
+ @transition.run_callbacks
632
+ assert_equal 1, @count
633
+ end
634
+
635
+ it 'should_be_able_to_run_again_after_resetting' do
636
+ @count = 0
637
+ @machine.after_transition {@count += 1}
638
+ @transition.run_callbacks
639
+ @transition.reset
640
+ @transition.run_callbacks
641
+ assert_equal 2, @count
642
+ end
643
+ end
644
+
645
+ context 'WithMultipleAfterCallbacks' do
646
+ before(:each) do
647
+ @klass = Class.new
648
+
649
+ @machine = StateMachines::Machine.new(@klass)
650
+ @machine.state :parked, :idling
651
+ @machine.event :ignite
652
+
653
+ @object = @klass.new
654
+ @object.state = 'parked'
655
+ @transition = StateMachines::Transition.new(@object, @machine, :ignite, :parked, :idling)
656
+ end
657
+
658
+ it 'should_run_in_the_order_they_were_defined' do
659
+ @callbacks = []
660
+ @machine.after_transition {@callbacks << 1}
661
+ @machine.after_transition {@callbacks << 2}
662
+ @transition.run_callbacks
663
+
664
+ assert_equal [1, 2], @callbacks
665
+ end
666
+
667
+ it 'should_not_run_further_callbacks_if_halted' do
668
+ @callbacks = []
669
+ @machine.after_transition {@callbacks << 1; throw :halt}
670
+ @machine.after_transition {@callbacks << 2}
671
+
672
+ assert_equal true, @transition.run_callbacks
673
+ assert_equal [1], @callbacks
674
+ end
675
+
676
+ it 'should_fail_if_any_callback_halted' do
677
+ @machine.after_transition {true}
678
+ @machine.after_transition {throw :halt}
679
+
680
+ assert_equal true, @transition.run_callbacks
681
+ end
682
+ end
683
+
684
+ context 'WithAroundCallbacks' do
685
+ before(:each) do
686
+ @klass = Class.new
687
+
688
+ @machine = StateMachines::Machine.new(@klass)
689
+ @machine.state :parked, :idling
690
+ @machine.event :ignite
691
+
692
+ @object = @klass.new
693
+ @object.state = 'parked'
694
+ @transition = StateMachines::Transition.new(@object, @machine, :ignite, :parked, :idling)
695
+ end
696
+
697
+ it 'should_run_around_callbacks' do
698
+ @machine.around_transition {|object, transition, block| @run_before = true; block.call; @run_after = true}
699
+ result = @transition.run_callbacks
700
+
701
+ assert_equal true, result
702
+ assert_equal true, @run_before
703
+ assert_equal true, @run_after
704
+ end
705
+
706
+ it 'should_only_run_those_that_match_transition_context' do
707
+ @count = 0
708
+ callback = lambda {|object, transition, block| @count += 1; block.call}
709
+
710
+ @machine.around_transition :from => :parked, :to => :idling, :on => :park, :do => callback
711
+ @machine.around_transition :from => :parked, :to => :parked, :on => :park, :do => callback
712
+ @machine.around_transition :from => :parked, :to => :idling, :on => :ignite, :do => callback
713
+ @machine.around_transition :from => :idling, :to => :idling, :on => :park, :do => callback
714
+ @transition.run_callbacks
715
+
716
+ assert_equal 1, @count
717
+ end
718
+
719
+ it 'should_pass_transition_as_argument' do
720
+ @machine.around_transition {|*args| block = args.pop; @args = args; block.call}
721
+ @transition.run_callbacks
722
+
723
+ assert_equal [@object, @transition], @args
724
+ end
725
+
726
+ it 'should_run_block_between_callback' do
727
+ @callbacks = []
728
+ @machine.around_transition {|block| @callbacks << :before; block.call; @callbacks << :after}
729
+ @transition.run_callbacks { @callbacks << :within; {:success => true} }
730
+
731
+ assert_equal [:before, :within, :after], @callbacks
732
+ end
733
+
734
+ it 'should_have_access_to_result_after_yield' do
735
+ @machine.around_transition {|block| @before_result = @transition.result; block.call; @after_result = @transition.result}
736
+ @transition.run_callbacks {{:result => 1, :success => true}}
737
+
738
+ assert_nil @before_result
739
+ assert_equal 1, @after_result
740
+ end
741
+
742
+ it 'should_catch_before_yield_halts' do
743
+ @machine.around_transition {throw :halt}
744
+
745
+ result = nil
746
+ assert_nothing_thrown { result = @transition.run_callbacks }
747
+ assert_equal false, result
748
+ end
749
+
750
+ it 'should_catch_after_yield_halts' do
751
+ @machine.around_transition {|block| block.call; throw :halt}
752
+
753
+ result = nil
754
+ assert_nothing_thrown { result = @transition.run_callbacks }
755
+ assert_equal true, result
756
+ end
757
+
758
+ it 'should_not_catch_before_yield' do
759
+ @machine.around_transition {raise ArgumentError}
760
+ assert_raise(ArgumentError) { @transition.run_callbacks }
761
+ end
762
+
763
+ it 'should_not_catch_after_yield' do
764
+ @machine.around_transition {|block| block.call; raise ArgumentError}
765
+ assert_raise(ArgumentError) { @transition.run_callbacks }
766
+ end
767
+
768
+ it 'should_fail_if_not_yielded' do
769
+ @machine.around_transition {}
770
+
771
+ result = nil
772
+ assert_nothing_thrown { result = @transition.run_callbacks }
773
+ assert_equal false, result
774
+ end
775
+
776
+ it 'should_not_be_able_to_run_twice' do
777
+ @before_count = 0
778
+ @after_count = 0
779
+ @machine.around_transition {|block| @before_count += 1; block.call; @after_count += 1}
780
+ @transition.run_callbacks
781
+ @transition.run_callbacks
782
+ assert_equal 1, @before_count
783
+ assert_equal 1, @after_count
784
+ end
785
+
786
+ it 'should_be_able_to_run_again_after_resetting' do
787
+ @before_count = 0
788
+ @after_count = 0
789
+ @machine.around_transition {|block| @before_count += 1; block.call; @after_count += 1}
790
+ @transition.run_callbacks
791
+ @transition.reset
792
+ @transition.run_callbacks
793
+ assert_equal 2, @before_count
794
+ assert_equal 2, @after_count
795
+ end
796
+
797
+ it 'should_succeed_if_block_result_is_false' do
798
+ @machine.around_transition {|block| @before_run = true; block.call; @after_run = true}
799
+ assert_equal true, @transition.run_callbacks {{:success => true, :result => false}}
800
+ assert @before_run
801
+ assert @after_run
802
+ end
803
+
804
+ it 'should_succeed_if_block_result_is_true' do
805
+ @machine.around_transition {|block| @before_run = true; block.call; @after_run = true}
806
+ assert_equal true, @transition.run_callbacks {{:success => true, :result => true}}
807
+ assert @before_run
808
+ assert @after_run
809
+ end
810
+
811
+ it 'should_only_run_before_if_block_success_is_false' do
812
+ @after_run = false
813
+ @machine.around_transition {|block| @before_run = true; block.call; @after_run = true}
814
+ assert_equal true, @transition.run_callbacks {{:success => false}}
815
+ assert @before_run
816
+ assert !@after_run
817
+ end
818
+
819
+ it 'should_succeed_if_block_success_is_false' do
820
+ @machine.around_transition {|block| @before_run = true; block.call; @after_run = true}
821
+ assert_equal true, @transition.run_callbacks {{:success => true}}
822
+ assert @before_run
823
+ assert @after_run
824
+ end
825
+ end
826
+
827
+ context 'WithMultipleAroundCallbacks' do
828
+ before(:each) do
829
+ @klass = Class.new
830
+
831
+ @machine = StateMachines::Machine.new(@klass)
832
+ @machine.state :parked, :idling
833
+ @machine.event :ignite
834
+
835
+ @object = @klass.new
836
+ @object.state = 'parked'
837
+ @transition = StateMachines::Transition.new(@object, @machine, :ignite, :parked, :idling)
838
+ end
839
+
840
+ it 'should_before_yield_in_the_order_they_were_defined' do
841
+ @callbacks = []
842
+ @machine.around_transition {|block| @callbacks << 1; block.call}
843
+ @machine.around_transition {|block| @callbacks << 2; block.call}
844
+ @transition.run_callbacks
845
+
846
+ assert_equal [1, 2], @callbacks
847
+ end
848
+
849
+ it 'should_before_yield_multiple_methods_in_the_order_they_were_defined' do
850
+ @callbacks = []
851
+ @machine.around_transition(lambda {|block| @callbacks << 1; block.call}, lambda {|block| @callbacks << 2; block.call})
852
+ @machine.around_transition(lambda {|block| @callbacks << 3; block.call}, lambda {|block| @callbacks << 4; block.call})
853
+ @transition.run_callbacks
854
+
855
+ assert_equal [1, 2, 3, 4], @callbacks
856
+ end
857
+
858
+ it 'should_after_yield_in_the_reverse_order_they_were_defined' do
859
+ @callbacks = []
860
+ @machine.around_transition {|block| block.call; @callbacks << 1}
861
+ @machine.around_transition {|block| block.call; @callbacks << 2}
862
+ @transition.run_callbacks
863
+
864
+ assert_equal [2, 1], @callbacks
865
+ end
866
+
867
+ it 'should_after_yield_multiple_methods_in_the_reverse_order_they_were_defined' do
868
+ @callbacks = []
869
+ @machine.around_transition(lambda {|block| block.call; @callbacks << 1}) {|block| block.call; @callbacks << 2}
870
+ @machine.around_transition(lambda {|block| block.call; @callbacks << 3}) {|block| block.call; @callbacks << 4}
871
+ @transition.run_callbacks
872
+
873
+ assert_equal [4, 3, 2, 1], @callbacks
874
+ end
875
+
876
+ it 'should_run_block_between_callback' do
877
+ @callbacks = []
878
+ @machine.around_transition {|block| @callbacks << :before_1; block.call; @callbacks << :after_1}
879
+ @machine.around_transition {|block| @callbacks << :before_2; block.call; @callbacks << :after_2}
880
+ @transition.run_callbacks { @callbacks << :within; {:success => true} }
881
+
882
+ assert_equal [:before_1, :before_2, :within, :after_2, :after_1], @callbacks
883
+ end
884
+
885
+ it 'should_have_access_to_result_after_yield' do
886
+ @machine.around_transition {|block| @before_result_1 = @transition.result; block.call; @after_result_1 = @transition.result}
887
+ @machine.around_transition {|block| @before_result_2 = @transition.result; block.call; @after_result_2 = @transition.result}
888
+ @transition.run_callbacks {{:result => 1, :success => true}}
889
+
890
+ assert_nil @before_result_1
891
+ assert_nil @before_result_2
892
+ assert_equal 1, @after_result_1
893
+ assert_equal 1, @after_result_2
894
+ end
895
+
896
+ it 'should_fail_if_any_before_yield_halted' do
897
+ @machine.around_transition {|block| block.call}
898
+ @machine.around_transition {throw :halt}
899
+
900
+ assert_equal false, @transition.run_callbacks
901
+ end
902
+
903
+ it 'should_not_continue_around_callbacks_if_before_yield_halted' do
904
+ @callbacks = []
905
+ @machine.around_transition {@callbacks << 1; throw :halt}
906
+ @machine.around_transition {|block| @callbacks << 2; block.call; @callbacks << 3}
907
+
908
+ assert_equal false, @transition.run_callbacks
909
+ assert_equal [1], @callbacks
910
+ end
911
+
912
+ it 'should_not_continue_around_callbacks_if_later_before_yield_halted' do
913
+ @callbacks = []
914
+ @machine.around_transition {|block| block.call; @callbacks << 1}
915
+ @machine.around_transition {throw :halt}
916
+
917
+ @transition.run_callbacks
918
+ assert_equal [], @callbacks
919
+ end
920
+
921
+ it 'should_not_run_further_callbacks_if_after_yield_halted' do
922
+ @callbacks = []
923
+ @machine.around_transition {|block| block.call; @callbacks << 1}
924
+ @machine.around_transition {|block| block.call; throw :halt}
925
+
926
+ assert_equal true, @transition.run_callbacks
927
+ assert_equal [], @callbacks
928
+ end
929
+
930
+ it 'should_fail_if_any_fail_to_yield' do
931
+ @callbacks = []
932
+ @machine.around_transition {@callbacks << 1}
933
+ @machine.around_transition {|block| @callbacks << 2; block.call; @callbacks << 3}
934
+
935
+ assert_equal false, @transition.run_callbacks
936
+ assert_equal [1], @callbacks
937
+ end
938
+ end
939
+
940
+ context 'WithFailureCallbacks' do
941
+ before(:each) do
942
+ @klass = Class.new
943
+
944
+ @machine = StateMachines::Machine.new(@klass)
945
+ @machine.state :parked, :idling
946
+ @machine.event :ignite
947
+
948
+ @object = @klass.new
949
+ @object.state = 'parked'
950
+ @transition = StateMachines::Transition.new(@object, @machine, :ignite, :parked, :idling)
951
+ end
952
+
953
+ it 'should_only_run_those_that_match_transition_context' do
954
+ @count = 0
955
+ callback = lambda {@count += 1}
956
+
957
+ @machine.after_failure :do => callback
958
+ @machine.after_failure :on => :park, :do => callback
959
+ @machine.after_failure :on => :ignite, :do => callback
960
+ @transition.run_callbacks {{:success => false}}
961
+
962
+ assert_equal 2, @count
963
+ end
964
+
965
+ it 'should_run_if_not_successful' do
966
+ @machine.after_failure {|object| @run = true}
967
+ @transition.run_callbacks {{:success => false}}
968
+ assert @run
969
+ end
970
+
971
+ it 'should_not_run_if_successful' do
972
+ @run = false
973
+ @machine.after_failure {|object| @run = true}
974
+ @transition.run_callbacks {{:success => true}}
975
+ assert !@run
976
+ end
977
+
978
+ it 'should_pass_transition_as_argument' do
979
+ @machine.after_failure {|*args| @args = args}
980
+
981
+ @transition.run_callbacks {{:success => false}}
982
+ assert_equal [@object, @transition], @args
983
+ end
984
+
985
+ it 'should_catch_halts' do
986
+ @machine.after_failure {throw :halt}
987
+
988
+ result = nil
989
+ assert_nothing_thrown { result = @transition.run_callbacks {{:success => false}} }
990
+ assert_equal true, result
991
+ end
992
+
993
+ it 'should_not_catch_exceptions' do
994
+ @machine.after_failure {raise ArgumentError}
995
+ assert_raise(ArgumentError) { @transition.run_callbacks {{:success => false}} }
996
+ end
997
+
998
+ it 'should_not_be_able_to_run_twice' do
999
+ @count = 0
1000
+ @machine.after_failure {@count += 1}
1001
+ @transition.run_callbacks {{:success => false}}
1002
+ @transition.run_callbacks {{:success => false}}
1003
+ assert_equal 1, @count
1004
+ end
1005
+
1006
+ it 'should_not_be_able_to_run_twice_if_halted' do
1007
+ @count = 0
1008
+ @machine.after_failure {@count += 1; throw :halt}
1009
+ @transition.run_callbacks {{:success => false}}
1010
+ @transition.run_callbacks {{:success => false}}
1011
+ assert_equal 1, @count
1012
+ end
1013
+
1014
+ it 'should_be_able_to_run_again_after_resetting' do
1015
+ @count = 0
1016
+ @machine.after_failure {@count += 1}
1017
+ @transition.run_callbacks {{:success => false}}
1018
+ @transition.reset
1019
+ @transition.run_callbacks {{:success => false}}
1020
+ assert_equal 2, @count
1021
+ end
1022
+ end
1023
+
1024
+ context 'WithMultipleFailureCallbacks' do
1025
+ before(:each) do
1026
+ @klass = Class.new
1027
+
1028
+ @machine = StateMachines::Machine.new(@klass)
1029
+ @machine.state :parked, :idling
1030
+ @machine.event :ignite
1031
+
1032
+ @object = @klass.new
1033
+ @object.state = 'parked'
1034
+ @transition = StateMachines::Transition.new(@object, @machine, :ignite, :parked, :idling)
1035
+ end
1036
+
1037
+ it 'should_run_in_the_order_they_were_defined' do
1038
+ @callbacks = []
1039
+ @machine.after_failure {@callbacks << 1}
1040
+ @machine.after_failure {@callbacks << 2}
1041
+ @transition.run_callbacks {{:success => false}}
1042
+
1043
+ assert_equal [1, 2], @callbacks
1044
+ end
1045
+
1046
+ it 'should_not_run_further_callbacks_if_halted' do
1047
+ @callbacks = []
1048
+ @machine.after_failure {@callbacks << 1; throw :halt}
1049
+ @machine.after_failure {@callbacks << 2}
1050
+
1051
+ assert_equal true, @transition.run_callbacks {{:success => false}}
1052
+ assert_equal [1], @callbacks
1053
+ end
1054
+
1055
+ it 'should_fail_if_any_callback_halted' do
1056
+ @machine.after_failure {true}
1057
+ @machine.after_failure {throw :halt}
1058
+
1059
+ assert_equal true, @transition.run_callbacks {{:success => false}}
1060
+ end
1061
+ end
1062
+
1063
+ context 'WithMixedCallbacks' do
1064
+ before(:each) do
1065
+ @klass = Class.new
1066
+
1067
+ @machine = StateMachines::Machine.new(@klass)
1068
+ @machine.state :parked, :idling
1069
+ @machine.event :ignite
1070
+
1071
+ @object = @klass.new
1072
+ @object.state = 'parked'
1073
+ @transition = StateMachines::Transition.new(@object, @machine, :ignite, :parked, :idling)
1074
+ end
1075
+
1076
+ it 'should_before_and_around_callbacks_in_order_defined' do
1077
+ @callbacks = []
1078
+ @machine.before_transition {@callbacks << :before_1}
1079
+ @machine.around_transition {|block| @callbacks << :around; block.call}
1080
+ @machine.before_transition {@callbacks << :before_2}
1081
+
1082
+ assert_equal true, @transition.run_callbacks
1083
+ assert_equal [:before_1, :around, :before_2], @callbacks
1084
+ end
1085
+
1086
+ it 'should_run_around_callbacks_before_after_callbacks' do
1087
+ @callbacks = []
1088
+ @machine.after_transition {@callbacks << :after_1}
1089
+ @machine.around_transition {|block| block.call; @callbacks << :after_2}
1090
+ @machine.after_transition {@callbacks << :after_3}
1091
+
1092
+ assert_equal true, @transition.run_callbacks
1093
+ assert_equal [:after_2, :after_1, :after_3], @callbacks
1094
+ end
1095
+
1096
+ it 'should_have_access_to_result_for_both_after_and_around_callbacks' do
1097
+ @machine.after_transition {@after_result = @transition.result}
1098
+ @machine.around_transition {|block| block.call; @around_result = @transition.result}
1099
+
1100
+ @transition.run_callbacks {{:result => 1, :success => true}}
1101
+ assert_equal 1, @after_result
1102
+ assert_equal 1, @around_result
1103
+ end
1104
+
1105
+ it 'should_not_run_further_callbacks_if_before_callback_halts' do
1106
+ @callbacks = []
1107
+ @machine.before_transition {@callbacks << :before_1}
1108
+ @machine.around_transition {|block| @callbacks << :before_around_1; block.call; @callbacks << :after_around_1}
1109
+ @machine.before_transition {@callbacks << :before_2; throw :halt}
1110
+ @machine.around_transition {|block| @callbacks << :before_around_2; block.call; @callbacks << :after_around_2}
1111
+ @machine.after_transition {@callbacks << :after}
1112
+
1113
+ assert_equal false, @transition.run_callbacks
1114
+ assert_equal [:before_1, :before_around_1, :before_2], @callbacks
1115
+ end
1116
+
1117
+ it 'should_not_run_further_callbacks_if_before_yield_halts' do
1118
+ @callbacks = []
1119
+ @machine.before_transition {@callbacks << :before_1}
1120
+ @machine.around_transition {|block| @callbacks << :before_around_1; throw :halt}
1121
+ @machine.before_transition {@callbacks << :before_2; throw :halt}
1122
+ @machine.around_transition {|block| @callbacks << :before_around_2; block.call; @callbacks << :after_around_2}
1123
+ @machine.after_transition {@callbacks << :after}
1124
+
1125
+ assert_equal false, @transition.run_callbacks
1126
+ assert_equal [:before_1, :before_around_1], @callbacks
1127
+ end
1128
+
1129
+ it 'should_not_run_further_callbacks_if_around_callback_fails_to_yield' do
1130
+ @callbacks = []
1131
+ @machine.before_transition {@callbacks << :before_1}
1132
+ @machine.around_transition {|block| @callbacks << :before_around_1}
1133
+ @machine.before_transition {@callbacks << :before_2; throw :halt}
1134
+ @machine.around_transition {|block| @callbacks << :before_around_2; block.call; @callbacks << :after_around_2}
1135
+ @machine.after_transition {@callbacks << :after}
1136
+
1137
+ assert_equal false, @transition.run_callbacks
1138
+ assert_equal [:before_1, :before_around_1], @callbacks
1139
+ end
1140
+
1141
+ it 'should_not_run_further_callbacks_if_after_yield_halts' do
1142
+ @callbacks = []
1143
+ @machine.before_transition {@callbacks << :before_1}
1144
+ @machine.around_transition {|block| @callbacks << :before_around_1; block.call; @callbacks << :after_around_1; throw :halt}
1145
+ @machine.before_transition {@callbacks << :before_2}
1146
+ @machine.around_transition {|block| @callbacks << :before_around_2; block.call; @callbacks << :after_around_2}
1147
+ @machine.after_transition {@callbacks << :after}
1148
+
1149
+ assert_equal true, @transition.run_callbacks
1150
+ assert_equal [:before_1, :before_around_1, :before_2, :before_around_2, :after_around_2, :after_around_1], @callbacks
1151
+ end
1152
+
1153
+ it 'should_not_run_further_callbacks_if_after_callback_halts' do
1154
+ @callbacks = []
1155
+ @machine.before_transition {@callbacks << :before_1}
1156
+ @machine.around_transition {|block| @callbacks << :before_around_1; block.call; @callbacks << :after_around_1}
1157
+ @machine.before_transition {@callbacks << :before_2}
1158
+ @machine.around_transition {|block| @callbacks << :before_around_2; block.call; @callbacks << :after_around_2}
1159
+ @machine.after_transition {@callbacks << :after_1; throw :halt}
1160
+ @machine.after_transition {@callbacks << :after_2}
1161
+
1162
+ assert_equal true, @transition.run_callbacks
1163
+ assert_equal [:before_1, :before_around_1, :before_2, :before_around_2, :after_around_2, :after_around_1, :after_1], @callbacks
1164
+ end
1165
+ end
1166
+
1167
+ context 'WithBeforeCallbacksSkipped' do
1168
+ before(:each) do
1169
+ @klass = Class.new
1170
+
1171
+ @machine = StateMachines::Machine.new(@klass)
1172
+ @machine.state :parked, :idling
1173
+ @machine.event :ignite
1174
+
1175
+ @object = @klass.new
1176
+ @object.state = 'parked'
1177
+ @transition = StateMachines::Transition.new(@object, @machine, :ignite, :parked, :idling)
1178
+ end
1179
+
1180
+ it 'should_not_run_before_callbacks' do
1181
+ @run = false
1182
+ @machine.before_transition {@run = true}
1183
+
1184
+ assert_equal false, @transition.run_callbacks(:before => false)
1185
+ assert !@run
1186
+ end
1187
+
1188
+ it 'should_run_failure_callbacks' do
1189
+ @machine.after_failure {@run = true}
1190
+
1191
+ assert_equal false, @transition.run_callbacks(:before => false)
1192
+ assert @run
1193
+ end
1194
+ end
1195
+
1196
+ context 'WithAfterCallbacksSkipped' do
1197
+ before(:each) do
1198
+ @klass = Class.new
1199
+
1200
+ @machine = StateMachines::Machine.new(@klass)
1201
+ @machine.state :parked, :idling
1202
+ @machine.event :ignite
1203
+
1204
+ @object = @klass.new
1205
+ @object.state = 'parked'
1206
+ @transition = StateMachines::Transition.new(@object, @machine, :ignite, :parked, :idling)
1207
+ end
1208
+
1209
+ it 'should_run_before_callbacks' do
1210
+ @machine.before_transition {@run = true}
1211
+
1212
+ assert_equal true, @transition.run_callbacks(:after => false)
1213
+ assert @run
1214
+ end
1215
+
1216
+ it 'should_not_run_after_callbacks' do
1217
+ @run = false
1218
+ @machine.after_transition {@run = true}
1219
+
1220
+ assert_equal true, @transition.run_callbacks(:after => false)
1221
+ assert !@run
1222
+ end
1223
+
1224
+ if StateMachines::Transition.pause_supported?
1225
+ it 'should_run_around_callbacks_before_yield' do
1226
+ @machine.around_transition {|block| @run = true; block.call}
1227
+
1228
+ assert_equal true, @transition.run_callbacks(:after => false)
1229
+ assert @run
1230
+ end
1231
+
1232
+ it 'should_not_run_around_callbacks_after_yield' do
1233
+ @run = false
1234
+ @machine.around_transition {|block| block.call; @run = true}
1235
+
1236
+ assert_equal true, @transition.run_callbacks(:after => false)
1237
+ assert !@run
1238
+ end
1239
+
1240
+ it 'should_continue_around_transition_execution_on_second_call' do
1241
+ @callbacks = []
1242
+ @machine.around_transition {|block| @callbacks << :before_around_1; block.call; @callbacks << :after_around_1}
1243
+ @machine.around_transition {|block| @callbacks << :before_around_2; block.call; @callbacks << :after_around_2}
1244
+ @machine.after_transition {@callbacks << :after}
1245
+
1246
+ assert_equal true, @transition.run_callbacks(:after => false)
1247
+ assert_equal [:before_around_1, :before_around_2], @callbacks
1248
+
1249
+ assert_equal true, @transition.run_callbacks
1250
+ assert_equal [:before_around_1, :before_around_2, :after_around_2, :after_around_1, :after], @callbacks
1251
+ end
1252
+
1253
+ it 'should_not_run_further_callbacks_if_halted_during_continue_around_transition' do
1254
+ @callbacks = []
1255
+ @machine.around_transition {|block| @callbacks << :before_around_1; block.call; @callbacks << :after_around_1}
1256
+ @machine.around_transition {|block| @callbacks << :before_around_2; block.call; @callbacks << :after_around_2; throw :halt}
1257
+ @machine.after_transition {@callbacks << :after}
1258
+
1259
+ assert_equal true, @transition.run_callbacks(:after => false)
1260
+ assert_equal [:before_around_1, :before_around_2], @callbacks
1261
+
1262
+ assert_equal true, @transition.run_callbacks
1263
+ assert_equal [:before_around_1, :before_around_2, :after_around_2], @callbacks
1264
+ end
1265
+
1266
+ it 'should_not_be_able_to_continue_twice' do
1267
+ @count = 0
1268
+ @machine.around_transition {|block| block.call; @count += 1}
1269
+ @machine.after_transition {@count += 1}
1270
+
1271
+ @transition.run_callbacks(:after => false)
1272
+
1273
+ 2.times do
1274
+ assert_equal true, @transition.run_callbacks
1275
+ assert_equal 2, @count
1276
+ end
1277
+ end
1278
+
1279
+ it 'should_not_be_able_to_continue_again_after_halted' do
1280
+ @count = 0
1281
+ @machine.around_transition {|block| block.call; @count += 1; throw :halt}
1282
+ @machine.after_transition {@count += 1}
1283
+
1284
+ @transition.run_callbacks(:after => false)
1285
+
1286
+ 2.times do
1287
+ assert_equal true, @transition.run_callbacks
1288
+ assert_equal 1, @count
1289
+ end
1290
+ end
1291
+
1292
+ it 'should_have_access_to_result_after_continued' do
1293
+ @machine.around_transition {|block| @around_before_result = @transition.result; block.call; @around_after_result = @transition.result}
1294
+ @machine.after_transition {@after_result = @transition.result}
1295
+
1296
+ @transition.run_callbacks(:after => false)
1297
+ @transition.run_callbacks {{:result => 1}}
1298
+
1299
+ assert_nil @around_before_result
1300
+ assert_equal 1, @around_after_result
1301
+ assert_equal 1, @after_result
1302
+ end
1303
+
1304
+ it 'should_raise_exceptions_during_around_callbacks_after_yield_in_second_execution' do
1305
+ @machine.around_transition {|block| block.call; raise ArgumentError}
1306
+
1307
+ assert_nothing_raised { @transition.run_callbacks(:after => false) }
1308
+ assert_raise(ArgumentError) { @transition.run_callbacks }
1309
+ end
1310
+ else
1311
+ it 'should_raise_exception_on_second_call' do
1312
+ @callbacks = []
1313
+ @machine.around_transition {|block| @callbacks << :before_around_1; block.call; @callbacks << :after_around_1}
1314
+ @machine.around_transition {|block| @callbacks << :before_around_2; block.call; @callbacks << :after_around_2}
1315
+ @machine.after_transition {@callbacks << :after}
1316
+
1317
+ assert_raise(ArgumentError) { @transition.run_callbacks(:after => false) }
1318
+ end
1319
+ end
1320
+ end
1321
+
1322
+ context 'AfterBeingPerformed' do
1323
+ before(:each) do
1324
+ @klass = Class.new do
1325
+ attr_reader :saved, :save_state
1326
+
1327
+ def save
1328
+ @save_state = state
1329
+ @saved = true
1330
+ 1
1331
+ end
1332
+ end
1333
+
1334
+ @machine = StateMachines::Machine.new(@klass, :action => :save)
1335
+ @machine.state :parked, :idling
1336
+ @machine.event :ignite
1337
+
1338
+ @object = @klass.new
1339
+ @object.state = 'parked'
1340
+ @transition = StateMachines::Transition.new(@object, @machine, :ignite, :parked, :idling)
1341
+ @result = @transition.perform
1342
+ end
1343
+
1344
+ it 'should_have_empty_args' do
1345
+ assert_equal [], @transition.args
1346
+ end
1347
+
1348
+ it 'should_have_a_result' do
1349
+ assert_equal 1, @transition.result
1350
+ end
1351
+
1352
+ it 'should_be_successful' do
1353
+ assert_equal true, @result
1354
+ end
1355
+
1356
+ it 'should_change_the_current_state' do
1357
+ assert_equal 'idling', @object.state
1358
+ end
1359
+
1360
+ it 'should_run_the_action' do
1361
+ assert @object.saved
1362
+ end
1363
+
1364
+ it 'should_run_the_action_after_saving_the_state' do
1365
+ assert_equal 'idling', @object.save_state
1366
+ end
1367
+ end
1368
+
1369
+ context 'WithPerformArguments' do
1370
+ before(:each) do
1371
+ @klass = Class.new do
1372
+ attr_reader :saved
1373
+
1374
+ def save
1375
+ @saved = true
1376
+ end
1377
+ end
1378
+
1379
+ @machine = StateMachines::Machine.new(@klass, :action => :save)
1380
+ @machine.state :parked, :idling
1381
+ @machine.event :ignite
1382
+
1383
+ @object = @klass.new
1384
+ @object.state = 'parked'
1385
+ @transition = StateMachines::Transition.new(@object, @machine, :ignite, :parked, :idling)
1386
+ end
1387
+
1388
+ it 'should_have_arguments' do
1389
+ @transition.perform(1, 2)
1390
+
1391
+ assert_equal [1, 2], @transition.args
1392
+ assert @object.saved
1393
+ end
1394
+
1395
+ it 'should_not_include_run_action_in_arguments' do
1396
+ @transition.perform(1, 2, false)
1397
+
1398
+ assert_equal [1, 2], @transition.args
1399
+ assert !@object.saved
1400
+ end
1401
+ end
1402
+
1403
+ context 'WithoutRunningAction' do
1404
+ before(:each) do
1405
+ @klass = Class.new do
1406
+ attr_reader :saved
1407
+
1408
+ def save
1409
+ @saved = true
1410
+ end
1411
+ end
1412
+
1413
+ @machine = StateMachines::Machine.new(@klass, :action => :save)
1414
+ @machine.state :parked, :idling
1415
+ @machine.event :ignite
1416
+ @machine.after_transition {|object| @run_after = true}
1417
+
1418
+ @object = @klass.new
1419
+ @object.state = 'parked'
1420
+ @transition = StateMachines::Transition.new(@object, @machine, :ignite, :parked, :idling)
1421
+ @result = @transition.perform(false)
1422
+ end
1423
+
1424
+ it 'should_have_empty_args' do
1425
+ assert_equal [], @transition.args
1426
+ end
1427
+
1428
+ it 'should_not_have_a_result' do
1429
+ assert_nil @transition.result
1430
+ end
1431
+
1432
+ it 'should_be_successful' do
1433
+ assert_equal true, @result
1434
+ end
1435
+
1436
+ it 'should_change_the_current_state' do
1437
+ assert_equal 'idling', @object.state
1438
+ end
1439
+
1440
+ it 'should_not_run_the_action' do
1441
+ assert !@object.saved
1442
+ end
1443
+
1444
+ it 'should_run_after_callbacks' do
1445
+ assert @run_after
1446
+ end
1447
+ end
1448
+
1449
+ context 'WithTransactions' do
1450
+ before(:each) do
1451
+ @klass = Class.new do
1452
+ class << self
1453
+ attr_accessor :running_transaction
1454
+ end
1455
+
1456
+ attr_accessor :result
1457
+
1458
+ def save
1459
+ @result = self.class.running_transaction
1460
+ true
1461
+ end
1462
+ end
1463
+
1464
+ @machine = StateMachines::Machine.new(@klass, :action => :save)
1465
+ @machine.state :parked, :idling
1466
+ @machine.event :ignite
1467
+
1468
+ @object = @klass.new
1469
+ @object.state = 'parked'
1470
+ @transition = StateMachines::Transition.new(@object, @machine, :ignite, :parked, :idling)
1471
+
1472
+ class << @machine
1473
+ def within_transaction(object)
1474
+ owner_class.running_transaction = object
1475
+ yield
1476
+ owner_class.running_transaction = false
1477
+ end
1478
+ end
1479
+ end
1480
+
1481
+ it 'should_run_blocks_within_transaction_for_object' do
1482
+ @transition.within_transaction do
1483
+ @result = @klass.running_transaction
1484
+ end
1485
+
1486
+ assert_equal @object, @result
1487
+ end
1488
+ end
1489
+
1490
+ context 'Transient' do
1491
+ before(:each) do
1492
+ @klass = Class.new
1493
+
1494
+ @machine = StateMachines::Machine.new(@klass)
1495
+ @machine.state :parked, :idling
1496
+ @machine.event :ignite
1497
+
1498
+ @object = @klass.new
1499
+ @object.state = 'parked'
1500
+ @transition = StateMachines::Transition.new(@object, @machine, :ignite, :parked, :idling)
1501
+ @transition.transient = true
1502
+ end
1503
+
1504
+ it 'should_be_transient' do
1505
+ assert @transition.transient?
1506
+ end
1507
+ end
1508
+
1509
+ context 'Equality' do
1510
+ before(:each) do
1511
+ @klass = Class.new
1512
+
1513
+ @machine = StateMachines::Machine.new(@klass)
1514
+ @machine.state :parked, :idling
1515
+ @machine.event :ignite
1516
+
1517
+ @object = @klass.new
1518
+ @object.state = 'parked'
1519
+ @transition = StateMachines::Transition.new(@object, @machine, :ignite, :parked, :idling)
1520
+ end
1521
+
1522
+ it 'should_be_equal_with_same_properties' do
1523
+ transition = StateMachines::Transition.new(@object, @machine, :ignite, :parked, :idling)
1524
+ assert_equal transition, @transition
1525
+ end
1526
+
1527
+ it 'should_not_be_equal_with_different_machines' do
1528
+ machine = StateMachines::Machine.new(@klass, :status, :namespace => :other)
1529
+ machine.state :parked, :idling
1530
+ machine.event :ignite
1531
+ transition = StateMachines::Transition.new(@object, machine, :ignite, :parked, :idling)
1532
+
1533
+ assert_not_equal transition, @transition
1534
+ end
1535
+
1536
+ it 'should_not_be_equal_with_different_objects' do
1537
+ transition = StateMachines::Transition.new(@klass.new, @machine, :ignite, :parked, :idling)
1538
+ assert_not_equal transition, @transition
1539
+ end
1540
+
1541
+ it 'should_not_be_equal_with_different_event_names' do
1542
+ @machine.event :park
1543
+ transition = StateMachines::Transition.new(@object, @machine, :park, :parked, :idling)
1544
+ assert_not_equal transition, @transition
1545
+ end
1546
+
1547
+ it 'should_not_be_equal_with_different_from_state_names' do
1548
+ @machine.state :first_gear
1549
+ transition = StateMachines::Transition.new(@object, @machine, :ignite, :first_gear, :idling)
1550
+ assert_not_equal transition, @transition
1551
+ end
1552
+
1553
+ it 'should_not_be_equal_with_different_to_state_names' do
1554
+ @machine.state :first_gear
1555
+ transition = StateMachines::Transition.new(@object, @machine, :ignite, :idling, :first_gear)
1556
+ assert_not_equal transition, @transition
1557
+ end
1558
+ end