enum_state_machine 0.0.1

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