state_machine 0.6.3 → 0.7.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (56) hide show
  1. data/CHANGELOG.rdoc +31 -1
  2. data/README.rdoc +33 -21
  3. data/Rakefile +2 -2
  4. data/examples/merb-rest/controller.rb +51 -0
  5. data/examples/merb-rest/model.rb +28 -0
  6. data/examples/merb-rest/view_edit.html.erb +24 -0
  7. data/examples/merb-rest/view_index.html.erb +23 -0
  8. data/examples/merb-rest/view_new.html.erb +13 -0
  9. data/examples/merb-rest/view_show.html.erb +17 -0
  10. data/examples/rails-rest/controller.rb +43 -0
  11. data/examples/rails-rest/migration.rb +11 -0
  12. data/examples/rails-rest/model.rb +23 -0
  13. data/examples/rails-rest/view_edit.html.erb +25 -0
  14. data/examples/rails-rest/view_index.html.erb +23 -0
  15. data/examples/rails-rest/view_new.html.erb +14 -0
  16. data/examples/rails-rest/view_show.html.erb +17 -0
  17. data/lib/state_machine/assertions.rb +2 -2
  18. data/lib/state_machine/callback.rb +14 -8
  19. data/lib/state_machine/condition_proxy.rb +3 -3
  20. data/lib/state_machine/event.rb +19 -21
  21. data/lib/state_machine/event_collection.rb +114 -0
  22. data/lib/state_machine/extensions.rb +127 -11
  23. data/lib/state_machine/guard.rb +1 -1
  24. data/lib/state_machine/integrations/active_record/locale.rb +2 -1
  25. data/lib/state_machine/integrations/active_record.rb +117 -39
  26. data/lib/state_machine/integrations/data_mapper/observer.rb +20 -64
  27. data/lib/state_machine/integrations/data_mapper.rb +71 -26
  28. data/lib/state_machine/integrations/sequel.rb +69 -21
  29. data/lib/state_machine/machine.rb +267 -139
  30. data/lib/state_machine/machine_collection.rb +145 -0
  31. data/lib/state_machine/matcher.rb +2 -2
  32. data/lib/state_machine/node_collection.rb +9 -4
  33. data/lib/state_machine/state.rb +22 -32
  34. data/lib/state_machine/state_collection.rb +66 -17
  35. data/lib/state_machine/transition.rb +259 -28
  36. data/lib/state_machine.rb +121 -56
  37. data/tasks/state_machine.rake +1 -0
  38. data/tasks/state_machine.rb +26 -0
  39. data/test/active_record.log +116877 -0
  40. data/test/functional/state_machine_test.rb +118 -12
  41. data/test/sequel.log +28542 -0
  42. data/test/unit/callback_test.rb +46 -1
  43. data/test/unit/condition_proxy_test.rb +55 -28
  44. data/test/unit/event_collection_test.rb +228 -0
  45. data/test/unit/event_test.rb +51 -46
  46. data/test/unit/integrations/active_record_test.rb +128 -70
  47. data/test/unit/integrations/data_mapper_test.rb +150 -58
  48. data/test/unit/integrations/sequel_test.rb +63 -6
  49. data/test/unit/invalid_event_test.rb +7 -0
  50. data/test/unit/machine_collection_test.rb +678 -0
  51. data/test/unit/machine_test.rb +198 -91
  52. data/test/unit/node_collection_test.rb +33 -30
  53. data/test/unit/state_collection_test.rb +112 -5
  54. data/test/unit/state_test.rb +23 -3
  55. data/test/unit/transition_test.rb +750 -89
  56. metadata +28 -3
@@ -0,0 +1,678 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../test_helper')
2
+
3
+ class MachineCollectionByDefaultTest < Test::Unit::TestCase
4
+ def setup
5
+ @machines = StateMachine::MachineCollection.new
6
+ end
7
+
8
+ def test_should_not_have_any_machines
9
+ assert @machines.empty?
10
+ end
11
+ end
12
+
13
+ class MachineCollectionStateInitializationTest < Test::Unit::TestCase
14
+ def setup
15
+ @machines = StateMachine::MachineCollection.new
16
+
17
+ @klass = Class.new do
18
+ def initialize(attributes = {})
19
+ attributes.each do |attribute, value|
20
+ self.send("#{attribute}=", value)
21
+ end
22
+
23
+ super()
24
+ end
25
+ end
26
+
27
+ @machines[:state] = StateMachine::Machine.new(@klass, :state, :initial => :parked)
28
+ @machines[:alarm_state] = StateMachine::Machine.new(@klass, :alarm_state, :initial => :active)
29
+ end
30
+
31
+ def test_should_set_states_if_nil
32
+ object = @klass.new
33
+ assert_equal 'parked', object.state
34
+ assert_equal 'active', object.alarm_state
35
+ end
36
+
37
+ def test_should_set_states_if_empty
38
+ object = @klass.new(:state => '', :alarm_state => '')
39
+ assert_equal 'parked', object.state
40
+ assert_equal 'active', object.alarm_state
41
+ end
42
+
43
+ def test_should_not_set_states_if_not_empty
44
+ object = @klass.new(:state => 'idling', :alarm_state => 'off')
45
+ assert_equal 'idling', object.state
46
+ assert_equal 'off', object.alarm_state
47
+ end
48
+ end
49
+
50
+ class MachineCollectionFireExplicitTest < Test::Unit::TestCase
51
+ def setup
52
+ @machines = StateMachine::MachineCollection.new
53
+
54
+ @klass = Class.new do
55
+ attr_reader :saved
56
+
57
+ def save
58
+ @saved = true
59
+ end
60
+ end
61
+
62
+ # First machine
63
+ @machines[:state] = @state = StateMachine::Machine.new(@klass, :state, :initial => :parked, :action => :save)
64
+ @state.event :ignite do
65
+ transition :parked => :idling
66
+ end
67
+ @state.event :park do
68
+ transition :idling => :parked
69
+ end
70
+
71
+ # Second machine
72
+ @machines[:alarm_state] = @alarm_state = StateMachine::Machine.new(@klass, :alarm_state, :initial => :active, :action => :save, :namespace => 'alarm')
73
+ @alarm_state.event :enable do
74
+ transition :off => :active
75
+ end
76
+ @alarm_state.event :disable do
77
+ transition :active => :off
78
+ end
79
+
80
+ @object = @klass.new
81
+ end
82
+
83
+ def test_should_raise_exception_if_invalid_event_specified
84
+ exception = assert_raise(StateMachine::InvalidEvent) { @machines.fire_events(@object, :invalid) }
85
+ assert_equal ':invalid is an unknown state machine event', exception.message
86
+
87
+ exception = assert_raise(StateMachine::InvalidEvent) { @machines.fire_events(@object, :ignite, :invalid) }
88
+ assert_equal ':invalid is an unknown state machine event', exception.message
89
+ end
90
+
91
+ def test_should_fail_if_any_event_cannot_transition
92
+ assert !@machines.fire_events(@object, :park, :disable_alarm)
93
+ assert_equal 'parked', @object.state
94
+ assert_equal 'active', @object.alarm_state
95
+ assert !@object.saved
96
+
97
+ assert !@machines.fire_events(@object, :ignite, :enable_alarm)
98
+ assert_equal 'parked', @object.state
99
+ assert_equal 'active', @object.alarm_state
100
+ assert !@object.saved
101
+ end
102
+
103
+ def test_should_be_successful_if_all_events_transition
104
+ assert @machines.fire_events(@object, :ignite, :disable_alarm)
105
+ assert_equal 'idling', @object.state
106
+ assert_equal 'off', @object.alarm_state
107
+ assert @object.saved
108
+ end
109
+
110
+ def test_should_not_save_if_skipping_action
111
+ assert @machines.fire_events(@object, :ignite, :disable_alarm, false)
112
+ assert_equal 'idling', @object.state
113
+ assert_equal 'off', @object.alarm_state
114
+ assert !@object.saved
115
+ end
116
+ end
117
+
118
+ class MachineCollectionFireExplicitWithTransactionsTest < Test::Unit::TestCase
119
+ def setup
120
+ @machines = StateMachine::MachineCollection.new
121
+
122
+ @klass = Class.new do
123
+ attr_accessor :allow_save
124
+
125
+ def save
126
+ @allow_save
127
+ end
128
+ end
129
+
130
+ StateMachine::Integrations.const_set('Custom', Module.new do
131
+ attr_reader :rolled_back
132
+
133
+ def transaction(object)
134
+ @rolled_back = yield
135
+ end
136
+ end)
137
+
138
+ # First machine
139
+ @machines[:state] = @state = StateMachine::Machine.new(@klass, :state, :initial => :parked, :action => :save, :integration => :custom)
140
+ @state.event :ignite do
141
+ transition :parked => :idling
142
+ end
143
+
144
+ # Second machine
145
+ @machines[:alarm_state] = @alarm_state = StateMachine::Machine.new(@klass, :alarm_state, :initial => :active, :action => :save, :namespace => 'alarm', :integration => :custom)
146
+ @alarm_state.event :disable do
147
+ transition :active => :off
148
+ end
149
+
150
+ @object = @klass.new
151
+ end
152
+
153
+ def test_should_not_rollback_if_successful
154
+ @object.allow_save = true
155
+
156
+ assert @machines.fire_events(@object, :ignite, :disable_alarm)
157
+ assert_equal true, @state.rolled_back
158
+ assert_nil @alarm_state.rolled_back
159
+ assert_equal 'idling', @object.state
160
+ assert_equal 'off', @object.alarm_state
161
+ end
162
+
163
+ def test_should_rollback_if_not_successful
164
+ @object.allow_save = false
165
+
166
+ assert !@machines.fire_events(@object, :ignite, :disable_alarm)
167
+ assert_equal false, @state.rolled_back
168
+ assert_nil @alarm_state.rolled_back
169
+ assert_equal 'parked', @object.state
170
+ assert_equal 'active', @object.alarm_state
171
+ end
172
+
173
+ def teardown
174
+ StateMachine::Integrations.send(:remove_const, 'Custom')
175
+ end
176
+ end
177
+
178
+ class MachineCollectionFireExplicitWithValidationsTest < Test::Unit::TestCase
179
+ def setup
180
+ StateMachine::Integrations.const_set('Custom', Module.new do
181
+ def invalidate(object, attribute, message, values = [])
182
+ (object.errors ||= []) << generate_message(message, values)
183
+ end
184
+
185
+ def reset(object)
186
+ object.errors = []
187
+ end
188
+ end)
189
+
190
+ @klass = Class.new do
191
+ attr_accessor :errors
192
+
193
+ def initialize
194
+ @errors = []
195
+ super
196
+ end
197
+ end
198
+
199
+ @machines = StateMachine::MachineCollection.new
200
+ @machines[:state] = @state = StateMachine::Machine.new(@klass, :state, :initial => :parked, :integration => :custom)
201
+ @state.event :ignite do
202
+ transition :parked => :idling
203
+ end
204
+
205
+ @machines[:alarm_state] = @alarm_state = StateMachine::Machine.new(@klass, :alarm_state, :initial => :active, :namespace => 'alarm', :integration => :custom)
206
+ @alarm_state.event :disable do
207
+ transition :active => :off
208
+ end
209
+
210
+ @object = @klass.new
211
+ end
212
+
213
+ def test_should_not_invalidate_if_transitions_exist
214
+ assert @machines.fire_events(@object, :ignite, :disable_alarm)
215
+ assert_equal [], @object.errors
216
+ end
217
+
218
+ def test_should_invalidate_if_no_transitions_exist
219
+ @object.state = 'idling'
220
+ @object.alarm_state = 'off'
221
+
222
+ assert !@machines.fire_events(@object, :ignite, :disable_alarm)
223
+ assert_equal ['cannot transition via "ignite"', 'cannot transition via "disable_alarm"'], @object.errors
224
+ end
225
+
226
+ def teardown
227
+ StateMachine::Integrations.send(:remove_const, 'Custom')
228
+ end
229
+ end
230
+
231
+ class MachineCollectionFireImplicitTest < Test::Unit::TestCase
232
+ def setup
233
+ @klass = Class.new
234
+
235
+ @machines = StateMachine::MachineCollection.new
236
+ @machines[:state] = @machine = StateMachine::Machine.new(@klass, :state, :initial => :parked, :action => :save)
237
+ @machine.event :ignite do
238
+ transition :parked => :idling
239
+ end
240
+
241
+ @saved = false
242
+ @object = @klass.new
243
+ end
244
+
245
+ def default_test
246
+ end
247
+ end
248
+
249
+ class MachineCollectionFireImplicitWithoutEventTest < MachineCollectionFireImplicitTest
250
+ def setup
251
+ super
252
+
253
+ @object.state_event = nil
254
+ @result = @machines.fire_attribute_events(@object, :save) { @saved = true }
255
+ end
256
+
257
+ def test_should_be_successful
258
+ assert_equal true, @result
259
+ end
260
+
261
+ def test_should_run_action
262
+ assert @saved
263
+ end
264
+
265
+ def test_should_not_transition_state
266
+ assert_equal 'parked', @object.state
267
+ end
268
+
269
+ def test_should_not_change_event_attribute
270
+ assert_nil @object.state_event
271
+ end
272
+ end
273
+
274
+ class MachineCollectionFireImplicitWithBlankEventTest < MachineCollectionFireImplicitTest
275
+ def setup
276
+ super
277
+
278
+ @object.state_event = ''
279
+ @result = @machines.fire_attribute_events(@object, :save) { @saved = true }
280
+ end
281
+
282
+ def test_should_be_successful
283
+ assert_equal true, @result
284
+ end
285
+
286
+ def test_should_run_action
287
+ assert @saved
288
+ end
289
+
290
+ def test_should_not_transition_state
291
+ assert_equal 'parked', @object.state
292
+ end
293
+
294
+ def test_should_not_change_event_attribute
295
+ assert_nil @object.state_event
296
+ end
297
+ end
298
+
299
+ class MachineCollectionFireImplicitWithInvalidEventTest < MachineCollectionFireImplicitTest
300
+ def setup
301
+ super
302
+
303
+ @object.state_event = 'invalid'
304
+ @result = @machines.fire_attribute_events(@object, :save) { @saved = true }
305
+ end
306
+
307
+ def test_should_not_be_successful
308
+ assert_equal false, @result
309
+ end
310
+
311
+ def test_should_not_run_action
312
+ assert !@saved
313
+ end
314
+
315
+ def test_should_not_transition_state
316
+ assert_equal 'parked', @object.state
317
+ end
318
+
319
+ def test_should_not_reset_event_attribute
320
+ assert_equal :invalid, @object.state_event
321
+ end
322
+
323
+ def test_should_not_have_event_transition
324
+ assert_nil @object.state_event_transition
325
+ end
326
+ end
327
+
328
+ class MachineCollectionFireImplicitWithoutTransitionTest < MachineCollectionFireImplicitTest
329
+ def setup
330
+ super
331
+
332
+ @object.state = 'idling'
333
+ @object.state_event = 'ignite'
334
+ @result = @machines.fire_attribute_events(@object, :save) { @saved = true }
335
+ end
336
+
337
+ def test_should_not_be_successful
338
+ assert_equal false, @result
339
+ end
340
+
341
+ def test_should_not_run_action
342
+ assert !@saved
343
+ end
344
+
345
+ def test_should_not_transition_state
346
+ assert_equal 'idling', @object.state
347
+ end
348
+
349
+ def test_should_not_reset_event_attribute
350
+ assert_equal :ignite, @object.state_event
351
+ end
352
+
353
+ def test_should_not_have_event_transition
354
+ assert_nil @object.state_event_transition
355
+ end
356
+ end
357
+
358
+ class MachineCollectionFireImplicitWithTransitionTest < MachineCollectionFireImplicitTest
359
+ def setup
360
+ super
361
+
362
+ @state_event = nil
363
+ @state_event_transition = nil
364
+
365
+ @object.state_event = 'ignite'
366
+ @result = @machines.fire_attribute_events(@object, :save) do
367
+ @state_event = @object.state_event
368
+ @state_event_transition = @object.state_event_transition
369
+ @saved = true
370
+ end
371
+ end
372
+
373
+ def test_should_be_successful
374
+ assert_equal true, @result
375
+ end
376
+
377
+ def test_should_run_action
378
+ assert @saved
379
+ end
380
+
381
+ def test_should_not_have_event_while_running_action
382
+ assert_nil @state_event
383
+ end
384
+
385
+ def test_should_not_have_event_transition_while_running_action
386
+ assert_nil @state_event_transition
387
+ end
388
+
389
+ def test_should_transition_state
390
+ assert_equal 'idling', @object.state
391
+ end
392
+
393
+ def test_should_reset_event_attribute
394
+ assert_nil @object.state_event
395
+ end
396
+
397
+ def test_should_reset_event_transition
398
+ assert_nil @object.state_event_transition
399
+ end
400
+ end
401
+
402
+ class MachineCollectionFireImplicitWithActionFailureTest < MachineCollectionFireImplicitTest
403
+ def setup
404
+ super
405
+
406
+ @object.state_event = 'ignite'
407
+ @result = @machines.fire_attribute_events(@object, :save) { false }
408
+ end
409
+
410
+ def test_should_not_be_successful
411
+ assert_equal false, @result
412
+ end
413
+
414
+ def test_should_not_transition_state
415
+ assert_equal 'parked', @object.state
416
+ end
417
+
418
+ def test_should_not_reset_event_attribute
419
+ assert_equal :ignite, @object.state_event
420
+ end
421
+
422
+ def test_should_not_have_event_transition
423
+ assert_nil @object.state_event_transition
424
+ end
425
+ end
426
+
427
+ class MachineCollectionFireImplicitWithActionErrorTest < MachineCollectionFireImplicitTest
428
+ def setup
429
+ super
430
+
431
+ @object.state_event = 'ignite'
432
+ assert_raise(ArgumentError) { @machines.fire_attribute_events(@object, :save) { raise ArgumentError } }
433
+ end
434
+
435
+ def test_should_not_transition_state
436
+ assert_equal 'parked', @object.state
437
+ end
438
+
439
+ def test_should_not_reset_event_attribute
440
+ assert_equal :ignite, @object.state_event
441
+ end
442
+
443
+ def test_should_not_have_event_transition
444
+ assert_nil @object.state_event_transition
445
+ end
446
+ end
447
+
448
+ class MachineCollectionFireImplicitPartialTest < MachineCollectionFireImplicitTest
449
+ def setup
450
+ super
451
+
452
+ @ran_before_callback = false
453
+ @ran_after_callback = false
454
+ @machine.before_transition { @ran_before_callback = true }
455
+ @machine.after_transition { @ran_after_callback = true }
456
+
457
+ @state_event = nil
458
+ @state_event_transition = nil
459
+
460
+ @object.state_event = 'ignite'
461
+ @result = @machines.fire_attribute_events(@object, :save, false) do
462
+ @state_event = @object.state_event
463
+ @state_event_transition = @object.state_event_transition
464
+ true
465
+ end
466
+ end
467
+
468
+ def test_should_run_before_callbacks
469
+ assert @ran_before_callback
470
+ end
471
+
472
+ def test_should_not_run_after_callbacks
473
+ assert !@ran_after_callback
474
+ end
475
+
476
+ def test_should_be_successful
477
+ assert @result
478
+ end
479
+
480
+ def test_should_not_have_event_while_running_action
481
+ assert_nil @state_event
482
+ end
483
+
484
+ def test_should_not_have_event_transition_while_running_action
485
+ assert_nil @state_event_transition
486
+ end
487
+
488
+ def test_should_transition_state
489
+ assert_equal 'idling', @object.state
490
+ end
491
+
492
+ def test_should_not_reset_event_attribute
493
+ assert_equal :ignite, @object.state_event
494
+ end
495
+
496
+ def test_should_have_event_transition
497
+ assert_not_nil @object.state_event_transition
498
+ end
499
+
500
+ def test_should_reset_event_attributes_after_next_fire_on_success
501
+ assert @machines.fire_attribute_events(@object, :save) { true }
502
+ assert_equal 'idling', @object.state
503
+ assert_nil @object.state_event
504
+ assert_nil @object.state_event_transition
505
+ end
506
+
507
+ def test_should_rollback_all_attributes_after_next_fire_on_failure
508
+ assert !@machines.fire_attribute_events(@object, :save) { false }
509
+ assert_equal 'parked', @object.state
510
+ assert_equal :ignite, @object.state_event
511
+ assert_nil @object.state_event_transition
512
+ end
513
+
514
+ def test_should_rollback_all_attributes_after_next_fire_on_error
515
+ assert_raise(ArgumentError) { @machines.fire_attribute_events(@object, :save) { raise ArgumentError } }
516
+ assert_equal 'parked', @object.state
517
+ assert_equal :ignite, @object.state_event
518
+ assert_nil @object.state_event_transition
519
+ end
520
+ end
521
+
522
+ class MachineCollectionFireImplicitNestedPartialTest < MachineCollectionFireImplicitTest
523
+ def setup
524
+ super
525
+
526
+ @partial_result = nil
527
+
528
+ @object.state_event = 'ignite'
529
+ @result = @machines.fire_attribute_events(@object, :save) do
530
+ @partial_result = @machines.fire_attribute_events(@object, :save, false) { true }
531
+ true
532
+ end
533
+ end
534
+
535
+ def test_should_be_successful
536
+ assert @result
537
+ end
538
+
539
+ def test_should_have_successful_partial_fire
540
+ assert @partial_result
541
+ end
542
+
543
+ def test_should_transition_state
544
+ assert_equal 'idling', @object.state
545
+ end
546
+
547
+ def test_should_reset_event_attribute
548
+ assert_nil @object.state_event
549
+ end
550
+
551
+ def test_should_not_have_event_transition
552
+ assert_nil @object.state_event_transition
553
+ end
554
+ end
555
+
556
+ class MachineCollectionFireImplicitWithDifferentActionsTest < MachineCollectionFireImplicitTest
557
+ def setup
558
+ super
559
+
560
+ @machines[:alarm_state] = @alarm_machine = StateMachine::Machine.new(@klass, :alarm_state, :initial => :active, :action => :save_alarm)
561
+ @alarm_machine.event :disable do
562
+ transition :active => :off
563
+ end
564
+
565
+ @saved = false
566
+ @object = @klass.new
567
+ @object.state_event = 'ignite'
568
+ @object.alarm_state_event = 'disable'
569
+
570
+ @machines.fire_attribute_events(@object, :save) { true }
571
+ end
572
+
573
+ def test_should_transition_states_for_action
574
+ assert_equal 'idling', @object.state
575
+ end
576
+
577
+ def test_should_reset_event_attributes_for_action
578
+ assert_nil @object.state_event
579
+ end
580
+
581
+ def test_should_not_transition_states_for_other_actions
582
+ assert_equal 'active', @object.alarm_state
583
+ end
584
+
585
+ def test_should_not_reset_event_attributes_for_other_actions
586
+ assert_equal :disable, @object.alarm_state_event
587
+ end
588
+ end
589
+
590
+ class MachineCollectionFireImplicitWithSameActionsTest < MachineCollectionFireImplicitTest
591
+ def setup
592
+ super
593
+
594
+ @machines[:alarm_state] = @alarm_machine = StateMachine::Machine.new(@klass, :alarm_state, :initial => :active, :action => :save)
595
+ @alarm_machine.event :disable do
596
+ transition :active => :off
597
+ end
598
+
599
+ @saved = false
600
+ @object = @klass.new
601
+ @object.state_event = 'ignite'
602
+ @object.alarm_state_event = 'disable'
603
+
604
+ @machines.fire_attribute_events(@object, :save) { true }
605
+ end
606
+
607
+ def test_should_transition_all_states_for_action
608
+ assert_equal 'idling', @object.state
609
+ assert_equal 'off', @object.alarm_state
610
+ end
611
+
612
+ def test_should_reset_all_event_attributes_for_action
613
+ assert_nil @object.state_event
614
+ assert_nil @object.alarm_state_event
615
+ end
616
+
617
+ def test_should_reset_all_event_transitions_for_action
618
+ assert_nil @object.state_event_transition
619
+ assert_nil @object.alarm_state_event_transition
620
+ end
621
+ end
622
+
623
+ class MachineCollectionFireImplicitWithValidationsTest < Test::Unit::TestCase
624
+ def setup
625
+ StateMachine::Integrations.const_set('Custom', Module.new do
626
+ def invalidate(object, attribute, message, values = [])
627
+ (object.errors ||= []) << generate_message(message, values)
628
+ end
629
+
630
+ def reset(object)
631
+ object.errors = []
632
+ end
633
+ end)
634
+
635
+ @klass = Class.new do
636
+ attr_accessor :errors
637
+
638
+ def initialize
639
+ @errors = []
640
+ super
641
+ end
642
+ end
643
+
644
+ @machines = StateMachine::MachineCollection.new
645
+ @machines[:state] = @machine = StateMachine::Machine.new(@klass, :state, :initial => :parked, :action => :save, :integration => :custom)
646
+ @machine.event :ignite do
647
+ transition :parked => :idling
648
+ end
649
+
650
+ @object = @klass.new
651
+ end
652
+
653
+ def test_should_invalidate_if_event_is_invalid
654
+ @object.state_event = 'invalid'
655
+ @machines.fire_attribute_events(@object, :save) { true }
656
+
657
+ assert !@object.errors.empty?
658
+ end
659
+
660
+ def test_should_invalidate_if_no_transition_exists
661
+ @object.state = 'idling'
662
+ @object.state_event = 'ignite'
663
+ @machines.fire_attribute_events(@object, :save) { true }
664
+
665
+ assert !@object.errors.empty?
666
+ end
667
+
668
+ def test_should_not_invalidate_if_transition_exists
669
+ @object.state_event = 'ignite'
670
+ @machines.fire_attribute_events(@object, :save) { true }
671
+
672
+ assert @object.errors.empty?
673
+ end
674
+
675
+ def teardown
676
+ StateMachine::Integrations.send(:remove_const, 'Custom')
677
+ end
678
+ end