verborghs-state_machine 0.9.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (89) hide show
  1. data/CHANGELOG.rdoc +360 -0
  2. data/LICENSE +20 -0
  3. data/README.rdoc +635 -0
  4. data/Rakefile +77 -0
  5. data/examples/AutoShop_state.png +0 -0
  6. data/examples/Car_state.png +0 -0
  7. data/examples/TrafficLight_state.png +0 -0
  8. data/examples/Vehicle_state.png +0 -0
  9. data/examples/auto_shop.rb +11 -0
  10. data/examples/car.rb +19 -0
  11. data/examples/merb-rest/controller.rb +51 -0
  12. data/examples/merb-rest/model.rb +28 -0
  13. data/examples/merb-rest/view_edit.html.erb +24 -0
  14. data/examples/merb-rest/view_index.html.erb +23 -0
  15. data/examples/merb-rest/view_new.html.erb +13 -0
  16. data/examples/merb-rest/view_show.html.erb +17 -0
  17. data/examples/rails-rest/controller.rb +43 -0
  18. data/examples/rails-rest/migration.rb +11 -0
  19. data/examples/rails-rest/model.rb +23 -0
  20. data/examples/rails-rest/view_edit.html.erb +25 -0
  21. data/examples/rails-rest/view_index.html.erb +23 -0
  22. data/examples/rails-rest/view_new.html.erb +14 -0
  23. data/examples/rails-rest/view_show.html.erb +17 -0
  24. data/examples/traffic_light.rb +7 -0
  25. data/examples/vehicle.rb +31 -0
  26. data/init.rb +1 -0
  27. data/lib/state_machine/assertions.rb +36 -0
  28. data/lib/state_machine/callback.rb +241 -0
  29. data/lib/state_machine/condition_proxy.rb +106 -0
  30. data/lib/state_machine/eval_helpers.rb +83 -0
  31. data/lib/state_machine/event.rb +267 -0
  32. data/lib/state_machine/event_collection.rb +122 -0
  33. data/lib/state_machine/extensions.rb +149 -0
  34. data/lib/state_machine/guard.rb +230 -0
  35. data/lib/state_machine/initializers/merb.rb +1 -0
  36. data/lib/state_machine/initializers/rails.rb +5 -0
  37. data/lib/state_machine/initializers.rb +4 -0
  38. data/lib/state_machine/integrations/active_model/locale.rb +11 -0
  39. data/lib/state_machine/integrations/active_model/observer.rb +45 -0
  40. data/lib/state_machine/integrations/active_model.rb +445 -0
  41. data/lib/state_machine/integrations/active_record/locale.rb +20 -0
  42. data/lib/state_machine/integrations/active_record.rb +522 -0
  43. data/lib/state_machine/integrations/data_mapper/observer.rb +175 -0
  44. data/lib/state_machine/integrations/data_mapper.rb +379 -0
  45. data/lib/state_machine/integrations/mongo_mapper.rb +309 -0
  46. data/lib/state_machine/integrations/sequel.rb +356 -0
  47. data/lib/state_machine/integrations.rb +83 -0
  48. data/lib/state_machine/machine.rb +1645 -0
  49. data/lib/state_machine/machine_collection.rb +64 -0
  50. data/lib/state_machine/matcher.rb +123 -0
  51. data/lib/state_machine/matcher_helpers.rb +54 -0
  52. data/lib/state_machine/node_collection.rb +152 -0
  53. data/lib/state_machine/state.rb +260 -0
  54. data/lib/state_machine/state_collection.rb +112 -0
  55. data/lib/state_machine/transition.rb +399 -0
  56. data/lib/state_machine/transition_collection.rb +244 -0
  57. data/lib/state_machine.rb +421 -0
  58. data/lib/tasks/state_machine.rake +1 -0
  59. data/lib/tasks/state_machine.rb +27 -0
  60. data/test/files/en.yml +9 -0
  61. data/test/files/switch.rb +11 -0
  62. data/test/functional/state_machine_test.rb +980 -0
  63. data/test/test_helper.rb +4 -0
  64. data/test/unit/assertions_test.rb +40 -0
  65. data/test/unit/callback_test.rb +728 -0
  66. data/test/unit/condition_proxy_test.rb +328 -0
  67. data/test/unit/eval_helpers_test.rb +222 -0
  68. data/test/unit/event_collection_test.rb +324 -0
  69. data/test/unit/event_test.rb +795 -0
  70. data/test/unit/guard_test.rb +909 -0
  71. data/test/unit/integrations/active_model_test.rb +956 -0
  72. data/test/unit/integrations/active_record_test.rb +1918 -0
  73. data/test/unit/integrations/data_mapper_test.rb +1814 -0
  74. data/test/unit/integrations/mongo_mapper_test.rb +1382 -0
  75. data/test/unit/integrations/sequel_test.rb +1492 -0
  76. data/test/unit/integrations_test.rb +50 -0
  77. data/test/unit/invalid_event_test.rb +7 -0
  78. data/test/unit/invalid_transition_test.rb +7 -0
  79. data/test/unit/machine_collection_test.rb +565 -0
  80. data/test/unit/machine_test.rb +2349 -0
  81. data/test/unit/matcher_helpers_test.rb +37 -0
  82. data/test/unit/matcher_test.rb +155 -0
  83. data/test/unit/node_collection_test.rb +207 -0
  84. data/test/unit/state_collection_test.rb +280 -0
  85. data/test/unit/state_machine_test.rb +31 -0
  86. data/test/unit/state_test.rb +848 -0
  87. data/test/unit/transition_collection_test.rb +2098 -0
  88. data/test/unit/transition_test.rb +1384 -0
  89. metadata +176 -0
@@ -0,0 +1,980 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../test_helper')
2
+
3
+ class AutoShop
4
+ attr_accessor :num_customers
5
+
6
+ def initialize
7
+ @num_customers = 0
8
+ super
9
+ end
10
+
11
+ state_machine :initial => :available do
12
+ after_transition :available => any, :do => :increment_customers
13
+ after_transition :busy => any, :do => :decrement_customers
14
+
15
+ event :tow_vehicle do
16
+ transition :available => :busy
17
+ end
18
+
19
+ event :fix_vehicle do
20
+ transition :busy => :available
21
+ end
22
+ end
23
+
24
+ # Increments the number of customers in service
25
+ def increment_customers
26
+ self.num_customers += 1
27
+ end
28
+
29
+ # Decrements the number of customers in service
30
+ def decrement_customers
31
+ self.num_customers -= 1
32
+ end
33
+ end
34
+
35
+ class ModelBase
36
+ def save
37
+ @saved = true
38
+ self
39
+ end
40
+ end
41
+
42
+ class Vehicle < ModelBase
43
+ attr_accessor :auto_shop, :seatbelt_on, :insurance_premium, :force_idle, :callbacks, :saved, :time_elapsed
44
+
45
+ def initialize(attributes = {})
46
+ attributes = {
47
+ :auto_shop => AutoShop.new,
48
+ :seatbelt_on => false,
49
+ :insurance_premium => 50,
50
+ :force_idle => false,
51
+ :callbacks => [],
52
+ :saved => false
53
+ }.merge(attributes)
54
+
55
+ attributes.each {|attr, value| send("#{attr}=", value)}
56
+ super()
57
+ end
58
+
59
+ # Defines the state machine for the state of the vehicled
60
+ state_machine :initial => lambda {|vehicle| vehicle.force_idle ? :idling : :parked}, :action => :save do
61
+ before_transition :parked => any, :do => :put_on_seatbelt
62
+ before_transition any => :stalled, :do => :increase_insurance_premium
63
+ after_transition any => :parked, :do => lambda {|vehicle| vehicle.seatbelt_on = false}
64
+ after_transition :on => :crash, :do => :tow
65
+ after_transition :on => :repair, :do => :fix
66
+
67
+ # Callback tracking for initial state callbacks
68
+ after_transition any => :parked, :do => lambda {|vehicle| vehicle.callbacks << 'before_enter_parked'}
69
+ before_transition any => :idling, :do => lambda {|vehicle| vehicle.callbacks << 'before_enter_idling'}
70
+
71
+ around_transition do |vehicle, transition, block|
72
+ time = Time.now
73
+ block.call
74
+ vehicle.time_elapsed = Time.now - time
75
+ end
76
+
77
+ event :park do
78
+ transition [:idling, :first_gear] => :parked
79
+ end
80
+
81
+ event :ignite do
82
+ transition :stalled => :stalled
83
+ transition :parked => :idling
84
+ end
85
+
86
+ event :idle do
87
+ transition :first_gear => :idling
88
+ end
89
+
90
+ event :shift_up do
91
+ transition :idling => :first_gear, :first_gear => :second_gear, :second_gear => :third_gear
92
+ end
93
+
94
+ event :shift_down do
95
+ transition :third_gear => :second_gear
96
+ transition :second_gear => :first_gear
97
+ end
98
+
99
+ event :crash do
100
+ transition [:first_gear, :second_gear, :third_gear] => :stalled, :if => lambda {|vehicle| vehicle.auto_shop.available?}
101
+ end
102
+
103
+ event :repair do
104
+ transition :stalled => :parked, :if => :auto_shop_busy?
105
+ end
106
+ end
107
+
108
+ state_machine :insurance_state, :initial => :inactive, :namespace => 'insurance' do
109
+ event :buy do
110
+ transition :inactive => :active
111
+ end
112
+
113
+ event :cancel do
114
+ transition :active => :inactive
115
+ end
116
+ end
117
+
118
+ def save
119
+ super
120
+ end
121
+
122
+ def new_record?
123
+ @saved == false
124
+ end
125
+
126
+ def park
127
+ super
128
+ end
129
+
130
+ # Tows the vehicle to the auto shop
131
+ def tow
132
+ auto_shop.tow_vehicle
133
+ end
134
+
135
+ # Fixes the vehicle; it will no longer be in the auto shop
136
+ def fix
137
+ auto_shop.fix_vehicle
138
+ end
139
+
140
+ def decibels
141
+ 0.0
142
+ end
143
+
144
+ private
145
+ # Safety first! Puts on our seatbelt
146
+ def put_on_seatbelt
147
+ self.seatbelt_on = true
148
+ end
149
+
150
+ # We crashed! Increase the insurance premium on the vehicle
151
+ def increase_insurance_premium
152
+ self.insurance_premium += 100
153
+ end
154
+
155
+ # Is the auto shop currently servicing another customer?
156
+ def auto_shop_busy?
157
+ auto_shop.busy?
158
+ end
159
+ end
160
+
161
+ class Car < Vehicle
162
+ state_machine do
163
+ event :reverse do
164
+ transition [:parked, :idling, :first_gear] => :backing_up
165
+ end
166
+
167
+ event :park do
168
+ transition :backing_up => :parked
169
+ end
170
+
171
+ event :idle do
172
+ transition :backing_up => :idling
173
+ end
174
+
175
+ event :shift_up do
176
+ transition :backing_up => :first_gear
177
+ end
178
+ end
179
+ end
180
+
181
+ class Motorcycle < Vehicle
182
+ state_machine :initial => :idling do
183
+ state :first_gear do
184
+ def decibels
185
+ 1.0
186
+ end
187
+ end
188
+ end
189
+ end
190
+
191
+ class TrafficLight
192
+ state_machine :initial => :stop do
193
+ event :cycle do
194
+ transition :stop => :proceed, :proceed=> :caution, :caution => :stop
195
+ end
196
+
197
+ state :stop do
198
+ def color(transform)
199
+ value = 'red'
200
+
201
+ if block_given?
202
+ yield value
203
+ else
204
+ value.send(transform)
205
+ end
206
+
207
+ value
208
+ end
209
+ end
210
+
211
+ state :proceed do
212
+ def color(transform)
213
+ 'green'
214
+ end
215
+ end
216
+
217
+ state :caution do
218
+ def color(transform)
219
+ 'yellow'
220
+ end
221
+ end
222
+ end
223
+
224
+ def color(transform = :to_s)
225
+ super
226
+ end
227
+ end
228
+
229
+ class VehicleTest < Test::Unit::TestCase
230
+ def setup
231
+ @vehicle = Vehicle.new
232
+ end
233
+
234
+ def test_should_not_allow_access_to_subclass_events
235
+ assert !@vehicle.respond_to?(:reverse)
236
+ end
237
+
238
+ def test_should_have_human_state_names
239
+ assert_equal 'parked', Vehicle.human_state_name(:parked)
240
+ end
241
+
242
+ def test_should_have_human_state_event_names
243
+ assert_equal 'park', Vehicle.human_state_event_name(:park)
244
+ end
245
+ end
246
+
247
+ class VehicleUnsavedTest < Test::Unit::TestCase
248
+ def setup
249
+ @vehicle = Vehicle.new
250
+ end
251
+
252
+ def test_should_be_in_parked_state
253
+ assert_equal 'parked', @vehicle.state
254
+ end
255
+
256
+ def test_should_raise_exception_if_checking_invalid_state
257
+ assert_raise(IndexError) { @vehicle.state?(:invalid) }
258
+ end
259
+
260
+ def test_should_raise_exception_if_getting_name_of_invalid_state
261
+ @vehicle.state = 'invalid'
262
+ assert_raise(ArgumentError) { @vehicle.state_name }
263
+ end
264
+
265
+ def test_should_be_parked
266
+ assert @vehicle.parked?
267
+ assert @vehicle.state?(:parked)
268
+ assert_equal :parked, @vehicle.state_name
269
+ assert_equal 'parked', @vehicle.human_state_name
270
+ end
271
+
272
+ def test_should_not_be_idling
273
+ assert !@vehicle.idling?
274
+ end
275
+
276
+ def test_should_not_be_first_gear
277
+ assert !@vehicle.first_gear?
278
+ end
279
+
280
+ def test_should_not_be_second_gear
281
+ assert !@vehicle.second_gear?
282
+ end
283
+
284
+ def test_should_not_be_stalled
285
+ assert !@vehicle.stalled?
286
+ end
287
+
288
+ def test_should_not_be_able_to_park
289
+ assert !@vehicle.can_park?
290
+ end
291
+
292
+ def test_should_not_have_a_transition_for_park
293
+ assert_nil @vehicle.park_transition
294
+ end
295
+
296
+ def test_should_not_allow_park
297
+ assert !@vehicle.park
298
+ end
299
+
300
+ def test_should_be_able_to_ignite
301
+ assert @vehicle.can_ignite?
302
+ end
303
+
304
+ def test_should_have_a_transition_for_ignite
305
+ transition = @vehicle.ignite_transition
306
+ assert_not_nil transition
307
+ assert_equal 'parked', transition.from
308
+ assert_equal 'idling', transition.to
309
+ assert_equal :ignite, transition.event
310
+ assert_equal :state, transition.attribute
311
+ assert_equal @vehicle, transition.object
312
+ end
313
+
314
+ def test_should_have_a_list_of_possible_events
315
+ assert_equal [:ignite], @vehicle.state_events
316
+ end
317
+
318
+ def test_should_have_a_list_of_possible_transitions
319
+ assert_equal [{:object => @vehicle, :attribute => :state, :event => :ignite, :from => 'parked', :to => 'idling'}], @vehicle.state_transitions.map {|transition| transition.attributes}
320
+ end
321
+
322
+ def test_should_allow_ignite
323
+ assert @vehicle.ignite
324
+ assert_equal 'idling', @vehicle.state
325
+ end
326
+
327
+ def test_should_allow_ignite_with_skipped_action
328
+ assert @vehicle.ignite(false)
329
+ assert @vehicle.new_record?
330
+ end
331
+
332
+ def test_should_allow_ignite_bang
333
+ assert @vehicle.ignite!
334
+ end
335
+
336
+ def test_should_allow_ignite_bang_with_skipped_action
337
+ assert @vehicle.ignite!(false)
338
+ assert @vehicle.new_record?
339
+ end
340
+
341
+ def test_should_be_saved_after_successful_event
342
+ @vehicle.ignite
343
+ assert !@vehicle.new_record?
344
+ end
345
+
346
+ def test_should_not_allow_idle
347
+ assert !@vehicle.idle
348
+ end
349
+
350
+ def test_should_not_allow_shift_up
351
+ assert !@vehicle.shift_up
352
+ end
353
+
354
+ def test_should_not_allow_shift_down
355
+ assert !@vehicle.shift_down
356
+ end
357
+
358
+ def test_should_not_allow_crash
359
+ assert !@vehicle.crash
360
+ end
361
+
362
+ def test_should_not_allow_repair
363
+ assert !@vehicle.repair
364
+ end
365
+
366
+ def test_should_be_insurance_inactive
367
+ assert @vehicle.insurance_inactive?
368
+ end
369
+
370
+ def test_should_be_able_to_buy
371
+ assert @vehicle.can_buy_insurance?
372
+ end
373
+
374
+ def test_should_allow_buying_insurance
375
+ assert @vehicle.buy_insurance
376
+ end
377
+
378
+ def test_should_allow_buying_insurance_bang
379
+ assert @vehicle.buy_insurance!
380
+ end
381
+
382
+ def test_should_allow_ignite_buying_insurance_with_skipped_action
383
+ assert @vehicle.buy_insurance!(false)
384
+ assert @vehicle.new_record?
385
+ end
386
+
387
+ def test_should_not_be_insurance_active
388
+ assert !@vehicle.insurance_active?
389
+ end
390
+
391
+ def test_should_not_be_able_to_cancel
392
+ assert !@vehicle.can_cancel_insurance?
393
+ end
394
+
395
+ def test_should_not_allow_cancelling_insurance
396
+ assert !@vehicle.cancel_insurance
397
+ end
398
+ end
399
+
400
+ class VehicleParkedTest < Test::Unit::TestCase
401
+ def setup
402
+ @vehicle = Vehicle.new
403
+ end
404
+
405
+ def test_should_be_in_parked_state
406
+ assert_equal 'parked', @vehicle.state
407
+ end
408
+
409
+ def test_should_not_have_the_seatbelt_on
410
+ assert !@vehicle.seatbelt_on
411
+ end
412
+
413
+ def test_should_not_allow_park
414
+ assert !@vehicle.park
415
+ end
416
+
417
+ def test_should_allow_ignite
418
+ assert @vehicle.ignite
419
+ assert_equal 'idling', @vehicle.state
420
+ end
421
+
422
+ def test_should_not_allow_idle
423
+ assert !@vehicle.idle
424
+ end
425
+
426
+ def test_should_not_allow_shift_up
427
+ assert !@vehicle.shift_up
428
+ end
429
+
430
+ def test_should_not_allow_shift_down
431
+ assert !@vehicle.shift_down
432
+ end
433
+
434
+ def test_should_not_allow_crash
435
+ assert !@vehicle.crash
436
+ end
437
+
438
+ def test_should_not_allow_repair
439
+ assert !@vehicle.repair
440
+ end
441
+
442
+ def test_should_raise_exception_if_repair_not_allowed!
443
+ assert_raise(StateMachine::InvalidTransition) {@vehicle.repair!}
444
+ end
445
+ end
446
+
447
+ class VehicleIdlingTest < Test::Unit::TestCase
448
+ def setup
449
+ @vehicle = Vehicle.new
450
+ @vehicle.ignite
451
+ end
452
+
453
+ def test_should_be_in_idling_state
454
+ assert_equal 'idling', @vehicle.state
455
+ end
456
+
457
+ def test_should_be_idling
458
+ assert @vehicle.idling?
459
+ end
460
+
461
+ def test_should_have_seatbelt_on
462
+ assert @vehicle.seatbelt_on
463
+ end
464
+
465
+ def test_should_track_time_elapsed
466
+ assert_not_nil @vehicle.time_elapsed
467
+ end
468
+
469
+ def test_should_allow_park
470
+ assert @vehicle.park
471
+ end
472
+
473
+ def test_should_call_park_with_bang_action
474
+ class << @vehicle
475
+ def park
476
+ super && 1
477
+ end
478
+ end
479
+
480
+ assert_equal 1, @vehicle.park!
481
+ end
482
+
483
+ def test_should_not_allow_idle
484
+ assert !@vehicle.idle
485
+ end
486
+
487
+ def test_should_allow_shift_up
488
+ assert @vehicle.shift_up
489
+ end
490
+
491
+ def test_should_not_allow_shift_down
492
+ assert !@vehicle.shift_down
493
+ end
494
+
495
+ def test_should_not_allow_crash
496
+ assert !@vehicle.crash
497
+ end
498
+
499
+ def test_should_not_allow_repair
500
+ assert !@vehicle.repair
501
+ end
502
+ end
503
+
504
+ class VehicleFirstGearTest < Test::Unit::TestCase
505
+ def setup
506
+ @vehicle = Vehicle.new
507
+ @vehicle.ignite
508
+ @vehicle.shift_up
509
+ end
510
+
511
+ def test_should_be_in_first_gear_state
512
+ assert_equal 'first_gear', @vehicle.state
513
+ end
514
+
515
+ def test_should_be_first_gear
516
+ assert @vehicle.first_gear?
517
+ end
518
+
519
+ def test_should_allow_park
520
+ assert @vehicle.park
521
+ end
522
+
523
+ def test_should_allow_idle
524
+ assert @vehicle.idle
525
+ end
526
+
527
+ def test_should_allow_shift_up
528
+ assert @vehicle.shift_up
529
+ end
530
+
531
+ def test_should_not_allow_shift_down
532
+ assert !@vehicle.shift_down
533
+ end
534
+
535
+ def test_should_allow_crash
536
+ assert @vehicle.crash
537
+ end
538
+
539
+ def test_should_not_allow_repair
540
+ assert !@vehicle.repair
541
+ end
542
+ end
543
+
544
+ class VehicleSecondGearTest < Test::Unit::TestCase
545
+ def setup
546
+ @vehicle = Vehicle.new
547
+ @vehicle.ignite
548
+ 2.times {@vehicle.shift_up}
549
+ end
550
+
551
+ def test_should_be_in_second_gear_state
552
+ assert_equal 'second_gear', @vehicle.state
553
+ end
554
+
555
+ def test_should_be_second_gear
556
+ assert @vehicle.second_gear?
557
+ end
558
+
559
+ def test_should_not_allow_park
560
+ assert !@vehicle.park
561
+ end
562
+
563
+ def test_should_not_allow_idle
564
+ assert !@vehicle.idle
565
+ end
566
+
567
+ def test_should_allow_shift_up
568
+ assert @vehicle.shift_up
569
+ end
570
+
571
+ def test_should_allow_shift_down
572
+ assert @vehicle.shift_down
573
+ end
574
+
575
+ def test_should_allow_crash
576
+ assert @vehicle.crash
577
+ end
578
+
579
+ def test_should_not_allow_repair
580
+ assert !@vehicle.repair
581
+ end
582
+ end
583
+
584
+ class VehicleThirdGearTest < Test::Unit::TestCase
585
+ def setup
586
+ @vehicle = Vehicle.new
587
+ @vehicle.ignite
588
+ 3.times {@vehicle.shift_up}
589
+ end
590
+
591
+ def test_should_be_in_third_gear_state
592
+ assert_equal 'third_gear', @vehicle.state
593
+ end
594
+
595
+ def test_should_be_third_gear
596
+ assert @vehicle.third_gear?
597
+ end
598
+
599
+ def test_should_not_allow_park
600
+ assert !@vehicle.park
601
+ end
602
+
603
+ def test_should_not_allow_idle
604
+ assert !@vehicle.idle
605
+ end
606
+
607
+ def test_should_not_allow_shift_up
608
+ assert !@vehicle.shift_up
609
+ end
610
+
611
+ def test_should_allow_shift_down
612
+ assert @vehicle.shift_down
613
+ end
614
+
615
+ def test_should_allow_crash
616
+ assert @vehicle.crash
617
+ end
618
+
619
+ def test_should_not_allow_repair
620
+ assert !@vehicle.repair
621
+ end
622
+ end
623
+
624
+ class VehicleStalledTest < Test::Unit::TestCase
625
+ def setup
626
+ @vehicle = Vehicle.new
627
+ @vehicle.ignite
628
+ @vehicle.shift_up
629
+ @vehicle.crash
630
+ end
631
+
632
+ def test_should_be_in_stalled_state
633
+ assert_equal 'stalled', @vehicle.state
634
+ end
635
+
636
+ def test_should_be_stalled
637
+ assert @vehicle.stalled?
638
+ end
639
+
640
+ def test_should_be_towed
641
+ assert @vehicle.auto_shop.busy?
642
+ assert_equal 1, @vehicle.auto_shop.num_customers
643
+ end
644
+
645
+ def test_should_have_an_increased_insurance_premium
646
+ assert_equal 150, @vehicle.insurance_premium
647
+ end
648
+
649
+ def test_should_not_allow_park
650
+ assert !@vehicle.park
651
+ end
652
+
653
+ def test_should_allow_ignite
654
+ assert @vehicle.ignite
655
+ end
656
+
657
+ def test_should_not_change_state_when_ignited
658
+ assert_equal 'stalled', @vehicle.state
659
+ end
660
+
661
+ def test_should_not_allow_idle
662
+ assert !@vehicle.idle
663
+ end
664
+
665
+ def test_should_now_allow_shift_up
666
+ assert !@vehicle.shift_up
667
+ end
668
+
669
+ def test_should_not_allow_shift_down
670
+ assert !@vehicle.shift_down
671
+ end
672
+
673
+ def test_should_not_allow_crash
674
+ assert !@vehicle.crash
675
+ end
676
+
677
+ def test_should_allow_repair_if_auto_shop_is_busy
678
+ assert @vehicle.repair
679
+ end
680
+
681
+ def test_should_not_allow_repair_if_auto_shop_is_available
682
+ @vehicle.auto_shop.fix_vehicle
683
+ assert !@vehicle.repair
684
+ end
685
+ end
686
+
687
+ class VehicleRepairedTest < Test::Unit::TestCase
688
+ def setup
689
+ @vehicle = Vehicle.new
690
+ @vehicle.ignite
691
+ @vehicle.shift_up
692
+ @vehicle.crash
693
+ @vehicle.repair
694
+ end
695
+
696
+ def test_should_be_in_parked_state
697
+ assert_equal 'parked', @vehicle.state
698
+ end
699
+
700
+ def test_should_not_have_a_busy_auto_shop
701
+ assert @vehicle.auto_shop.available?
702
+ end
703
+ end
704
+
705
+ class VehicleWithParallelEventsTest < Test::Unit::TestCase
706
+ def setup
707
+ @vehicle = Vehicle.new
708
+ end
709
+
710
+ def test_should_fail_if_any_event_cannot_transition
711
+ assert !@vehicle.fire_events(:ignite, :cancel_insurance)
712
+ end
713
+
714
+ def test_should_be_successful_if_all_events_transition
715
+ assert @vehicle.fire_events(:ignite, :buy_insurance)
716
+ end
717
+
718
+ def test_should_not_save_if_skipping_action
719
+ assert @vehicle.fire_events(:ignite, :buy_insurance, false)
720
+ assert !@vehicle.saved
721
+ end
722
+
723
+ def test_should_raise_exception_if_any_event_cannot_transition_on_bang
724
+ assert_raise(StateMachine::InvalidTransition) { @vehicle.fire_events!(:ignite, :cancel_insurance) }
725
+ end
726
+
727
+ def test_should_not_raise_exception_if_all_events_transition_on_bang
728
+ assert @vehicle.fire_events!(:ignite, :buy_insurance)
729
+ end
730
+
731
+ def test_should_not_save_if_skipping_action_on_bang
732
+ assert @vehicle.fire_events!(:ignite, :buy_insurance, false)
733
+ assert !@vehicle.saved
734
+ end
735
+ end
736
+
737
+ class VehicleWithEventAttributesTest < Test::Unit::TestCase
738
+ def setup
739
+ @vehicle = Vehicle.new
740
+ @vehicle.state_event = 'ignite'
741
+ end
742
+
743
+ def test_should_fail_if_event_is_invalid
744
+ @vehicle.state_event = 'invalid'
745
+ assert !@vehicle.save
746
+ assert_equal 'parked', @vehicle.state
747
+ end
748
+
749
+ def test_should_fail_if_event_has_no_transition
750
+ @vehicle.state_event = 'park'
751
+ assert !@vehicle.save
752
+ assert_equal 'parked', @vehicle.state
753
+ end
754
+
755
+ def test_should_return_original_action_value_on_success
756
+ assert_equal @vehicle, @vehicle.save
757
+ end
758
+
759
+ def test_should_transition_state_on_success
760
+ @vehicle.save
761
+ assert_equal 'idling', @vehicle.state
762
+ end
763
+ end
764
+
765
+ class MotorcycleTest < Test::Unit::TestCase
766
+ def setup
767
+ @motorcycle = Motorcycle.new
768
+ end
769
+
770
+ def test_should_be_in_idling_state
771
+ assert_equal 'idling', @motorcycle.state
772
+ end
773
+
774
+ def test_should_allow_park
775
+ assert @motorcycle.park
776
+ end
777
+
778
+ def test_should_not_allow_ignite
779
+ assert !@motorcycle.ignite
780
+ end
781
+
782
+ def test_should_allow_shift_up
783
+ assert @motorcycle.shift_up
784
+ end
785
+
786
+ def test_should_not_allow_shift_down
787
+ assert !@motorcycle.shift_down
788
+ end
789
+
790
+ def test_should_not_allow_crash
791
+ assert !@motorcycle.crash
792
+ end
793
+
794
+ def test_should_not_allow_repair
795
+ assert !@motorcycle.repair
796
+ end
797
+
798
+ def test_should_inherit_decibels_from_superclass
799
+ @motorcycle.park
800
+ assert_equal 0.0, @motorcycle.decibels
801
+ end
802
+
803
+ def test_should_use_decibels_defined_in_state
804
+ @motorcycle.shift_up
805
+ assert_equal 1.0, @motorcycle.decibels
806
+ end
807
+ end
808
+
809
+ class CarTest < Test::Unit::TestCase
810
+ def setup
811
+ @car = Car.new
812
+ end
813
+
814
+ def test_should_be_in_parked_state
815
+ assert_equal 'parked', @car.state
816
+ end
817
+
818
+ def test_should_not_have_the_seatbelt_on
819
+ assert !@car.seatbelt_on
820
+ end
821
+
822
+ def test_should_not_allow_park
823
+ assert !@car.park
824
+ end
825
+
826
+ def test_should_allow_ignite
827
+ assert @car.ignite
828
+ assert_equal 'idling', @car.state
829
+ end
830
+
831
+ def test_should_not_allow_idle
832
+ assert !@car.idle
833
+ end
834
+
835
+ def test_should_not_allow_shift_up
836
+ assert !@car.shift_up
837
+ end
838
+
839
+ def test_should_not_allow_shift_down
840
+ assert !@car.shift_down
841
+ end
842
+
843
+ def test_should_not_allow_crash
844
+ assert !@car.crash
845
+ end
846
+
847
+ def test_should_not_allow_repair
848
+ assert !@car.repair
849
+ end
850
+
851
+ def test_should_allow_reverse
852
+ assert @car.reverse
853
+ end
854
+ end
855
+
856
+ class CarBackingUpTest < Test::Unit::TestCase
857
+ def setup
858
+ @car = Car.new
859
+ @car.reverse
860
+ end
861
+
862
+ def test_should_be_in_backing_up_state
863
+ assert_equal 'backing_up', @car.state
864
+ end
865
+
866
+ def test_should_allow_park
867
+ assert @car.park
868
+ end
869
+
870
+ def test_should_not_allow_ignite
871
+ assert !@car.ignite
872
+ end
873
+
874
+ def test_should_allow_idle
875
+ assert @car.idle
876
+ end
877
+
878
+ def test_should_allow_shift_up
879
+ assert @car.shift_up
880
+ end
881
+
882
+ def test_should_not_allow_shift_down
883
+ assert !@car.shift_down
884
+ end
885
+
886
+ def test_should_not_allow_crash
887
+ assert !@car.crash
888
+ end
889
+
890
+ def test_should_not_allow_repair
891
+ assert !@car.repair
892
+ end
893
+
894
+ def test_should_not_allow_reverse
895
+ assert !@car.reverse
896
+ end
897
+ end
898
+
899
+ class AutoShopAvailableTest < Test::Unit::TestCase
900
+ def setup
901
+ @auto_shop = AutoShop.new
902
+ end
903
+
904
+ def test_should_be_in_available_state
905
+ assert_equal 'available', @auto_shop.state
906
+ end
907
+
908
+ def test_should_allow_tow_vehicle
909
+ assert @auto_shop.tow_vehicle
910
+ end
911
+
912
+ def test_should_not_allow_fix_vehicle
913
+ assert !@auto_shop.fix_vehicle
914
+ end
915
+ end
916
+
917
+ class AutoShopBusyTest < Test::Unit::TestCase
918
+ def setup
919
+ @auto_shop = AutoShop.new
920
+ @auto_shop.tow_vehicle
921
+ end
922
+
923
+ def test_should_be_in_busy_state
924
+ assert_equal 'busy', @auto_shop.state
925
+ end
926
+
927
+ def test_should_have_incremented_number_of_customers
928
+ assert_equal 1, @auto_shop.num_customers
929
+ end
930
+
931
+ def test_should_not_allow_tow_vehicle
932
+ assert !@auto_shop.tow_vehicle
933
+ end
934
+
935
+ def test_should_allow_fix_vehicle
936
+ assert @auto_shop.fix_vehicle
937
+ end
938
+ end
939
+
940
+ class TrafficLightStopTest < Test::Unit::TestCase
941
+ def setup
942
+ @light = TrafficLight.new
943
+ @light.state = 'stop'
944
+ end
945
+
946
+ def test_should_use_stop_color
947
+ assert_equal 'red', @light.color
948
+ end
949
+
950
+ def test_should_pass_arguments_through
951
+ assert_equal 'RED', @light.color(:upcase!)
952
+ end
953
+
954
+ def test_should_pass_block_through
955
+ color = @light.color {|value| value.upcase!}
956
+ assert_equal 'RED', color
957
+ end
958
+ end
959
+
960
+ class TrafficLightProceedTest < Test::Unit::TestCase
961
+ def setup
962
+ @light = TrafficLight.new
963
+ @light.state = 'proceed'
964
+ end
965
+
966
+ def test_should_use_proceed_color
967
+ assert_equal 'green', @light.color
968
+ end
969
+ end
970
+
971
+ class TrafficLightCautionTest < Test::Unit::TestCase
972
+ def setup
973
+ @light = TrafficLight.new
974
+ @light.state = 'caution'
975
+ end
976
+
977
+ def test_should_use_caution_color
978
+ assert_equal 'yellow', @light.color
979
+ end
980
+ end