pluginaweek-state_machine 0.7.6

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 (78) hide show
  1. data/CHANGELOG.rdoc +273 -0
  2. data/LICENSE +20 -0
  3. data/README.rdoc +466 -0
  4. data/Rakefile +98 -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.rb +429 -0
  28. data/lib/state_machine/assertions.rb +36 -0
  29. data/lib/state_machine/callback.rb +189 -0
  30. data/lib/state_machine/condition_proxy.rb +94 -0
  31. data/lib/state_machine/eval_helpers.rb +67 -0
  32. data/lib/state_machine/event.rb +251 -0
  33. data/lib/state_machine/event_collection.rb +113 -0
  34. data/lib/state_machine/extensions.rb +158 -0
  35. data/lib/state_machine/guard.rb +219 -0
  36. data/lib/state_machine/integrations.rb +68 -0
  37. data/lib/state_machine/integrations/active_record.rb +444 -0
  38. data/lib/state_machine/integrations/active_record/locale.rb +10 -0
  39. data/lib/state_machine/integrations/active_record/observer.rb +41 -0
  40. data/lib/state_machine/integrations/data_mapper.rb +325 -0
  41. data/lib/state_machine/integrations/data_mapper/observer.rb +139 -0
  42. data/lib/state_machine/integrations/sequel.rb +292 -0
  43. data/lib/state_machine/machine.rb +1431 -0
  44. data/lib/state_machine/machine_collection.rb +146 -0
  45. data/lib/state_machine/matcher.rb +123 -0
  46. data/lib/state_machine/matcher_helpers.rb +54 -0
  47. data/lib/state_machine/node_collection.rb +152 -0
  48. data/lib/state_machine/state.rb +249 -0
  49. data/lib/state_machine/state_collection.rb +112 -0
  50. data/lib/state_machine/transition.rb +367 -0
  51. data/tasks/state_machine.rake +1 -0
  52. data/tasks/state_machine.rb +30 -0
  53. data/test/classes/switch.rb +11 -0
  54. data/test/functional/state_machine_test.rb +941 -0
  55. data/test/test_helper.rb +4 -0
  56. data/test/unit/assertions_test.rb +40 -0
  57. data/test/unit/callback_test.rb +455 -0
  58. data/test/unit/condition_proxy_test.rb +328 -0
  59. data/test/unit/eval_helpers_test.rb +129 -0
  60. data/test/unit/event_collection_test.rb +293 -0
  61. data/test/unit/event_test.rb +605 -0
  62. data/test/unit/guard_test.rb +862 -0
  63. data/test/unit/integrations/active_record_test.rb +1001 -0
  64. data/test/unit/integrations/data_mapper_test.rb +694 -0
  65. data/test/unit/integrations/sequel_test.rb +486 -0
  66. data/test/unit/integrations_test.rb +42 -0
  67. data/test/unit/invalid_event_test.rb +7 -0
  68. data/test/unit/invalid_transition_test.rb +7 -0
  69. data/test/unit/machine_collection_test.rb +710 -0
  70. data/test/unit/machine_test.rb +1910 -0
  71. data/test/unit/matcher_helpers_test.rb +37 -0
  72. data/test/unit/matcher_test.rb +155 -0
  73. data/test/unit/node_collection_test.rb +207 -0
  74. data/test/unit/state_collection_test.rb +280 -0
  75. data/test/unit/state_machine_test.rb +31 -0
  76. data/test/unit/state_test.rb +795 -0
  77. data/test/unit/transition_test.rb +1113 -0
  78. metadata +161 -0
@@ -0,0 +1,31 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../test_helper')
2
+
3
+ class StateMachineByDefaultTest < Test::Unit::TestCase
4
+ def setup
5
+ @klass = Class.new
6
+ @machine = @klass.state_machine
7
+ end
8
+
9
+ def test_should_use_state_attribute
10
+ assert_equal :state, @machine.attribute
11
+ end
12
+ end
13
+
14
+ class StateMachineTest < Test::Unit::TestCase
15
+ def setup
16
+ @klass = Class.new
17
+ end
18
+
19
+ def test_should_allow_state_machines_on_any_class
20
+ assert @klass.respond_to?(:state_machine)
21
+ end
22
+
23
+ def test_should_evaluate_block_within_machine_context
24
+ responded = false
25
+ @klass.state_machine(:state) do
26
+ responded = respond_to?(:event)
27
+ end
28
+
29
+ assert responded
30
+ end
31
+ end
@@ -0,0 +1,795 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../test_helper')
2
+
3
+ class StateByDefaultTest < Test::Unit::TestCase
4
+ def setup
5
+ @machine = StateMachine::Machine.new(Class.new)
6
+ @state = StateMachine::State.new(@machine, :parked)
7
+ end
8
+
9
+ def test_should_have_a_machine
10
+ assert_equal @machine, @state.machine
11
+ end
12
+
13
+ def test_should_have_a_name
14
+ assert_equal :parked, @state.name
15
+ end
16
+
17
+ def test_should_have_a_qualified_name
18
+ assert_equal :parked, @state.name
19
+ end
20
+
21
+ def test_should_use_stringify_the_name_as_the_value
22
+ assert_equal 'parked', @state.value
23
+ end
24
+
25
+ def test_should_not_be_initial
26
+ assert !@state.initial
27
+ end
28
+
29
+ def test_should_not_have_a_matcher
30
+ assert_nil @state.matcher
31
+ end
32
+
33
+ def test_should_not_have_any_methods
34
+ expected = {}
35
+ assert_equal expected, @state.methods
36
+ end
37
+ end
38
+
39
+ class StateTest < Test::Unit::TestCase
40
+ def setup
41
+ @machine = StateMachine::Machine.new(Class.new)
42
+ @state = StateMachine::State.new(@machine, :parked)
43
+ end
44
+
45
+ def test_should_raise_exception_if_invalid_option_specified
46
+ exception = assert_raise(ArgumentError) {StateMachine::State.new(@machine, :parked, :invalid => true)}
47
+ assert_equal 'Invalid key(s): invalid', exception.message
48
+ end
49
+
50
+ def test_should_allow_changing_machine
51
+ new_machine = StateMachine::Machine.new(Class.new)
52
+ @state.machine = new_machine
53
+ assert_equal new_machine, @state.machine
54
+ end
55
+
56
+ def test_should_allow_changing_value
57
+ @state.value = 1
58
+ assert_equal 1, @state.value
59
+ end
60
+
61
+ def test_should_allow_changing_initial
62
+ @state.initial = true
63
+ assert @state.initial
64
+ end
65
+
66
+ def test_should_allow_changing_matcher
67
+ matcher = lambda {}
68
+ @state.matcher = matcher
69
+ assert_equal matcher, @state.matcher
70
+ end
71
+
72
+ def test_should_use_pretty_inspect
73
+ assert_equal '#<StateMachine::State name=:parked value="parked" initial=false context=[]>', @state.inspect
74
+ end
75
+ end
76
+
77
+ class StateWithoutNameTest < Test::Unit::TestCase
78
+ def setup
79
+ @klass = Class.new
80
+ @machine = StateMachine::Machine.new(@klass)
81
+ @state = StateMachine::State.new(@machine, nil)
82
+ end
83
+
84
+ def test_should_have_a_nil_name
85
+ assert_nil @state.name
86
+ end
87
+
88
+ def test_should_have_a_nil_qualified_name
89
+ assert_nil @state.qualified_name
90
+ end
91
+
92
+ def test_should_have_a_nil_value
93
+ assert_nil @state.value
94
+ end
95
+
96
+ def test_should_not_redefine_nil_predicate
97
+ object = @klass.new
98
+ assert !object.nil?
99
+ assert !object.respond_to?('?')
100
+ end
101
+
102
+ def test_should_have_a_description
103
+ assert_equal 'nil', @state.description
104
+ end
105
+ end
106
+
107
+ class StateWithNameTest < Test::Unit::TestCase
108
+ def setup
109
+ @klass = Class.new
110
+ @machine = StateMachine::Machine.new(@klass)
111
+ @state = StateMachine::State.new(@machine, :parked)
112
+ end
113
+
114
+ def test_should_have_a_name
115
+ assert_equal :parked, @state.name
116
+ end
117
+
118
+ def test_should_have_a_qualified_name
119
+ assert_equal :parked, @state.name
120
+ end
121
+
122
+ def test_should_use_stringify_the_name_as_the_value
123
+ assert_equal 'parked', @state.value
124
+ end
125
+
126
+ def test_should_match_stringified_name
127
+ assert @state.matches?('parked')
128
+ assert !@state.matches?('idling')
129
+ end
130
+
131
+ def test_should_not_include_value_in_description
132
+ assert_equal 'parked', @state.description
133
+ end
134
+
135
+ def test_should_define_predicate
136
+ assert @klass.new.respond_to?(:parked?)
137
+ end
138
+ end
139
+
140
+ class StateWithNilValueTest < Test::Unit::TestCase
141
+ def setup
142
+ @klass = Class.new
143
+ @machine = StateMachine::Machine.new(@klass)
144
+ @state = StateMachine::State.new(@machine, :parked, :value => nil)
145
+ end
146
+
147
+ def test_should_have_a_name
148
+ assert_equal :parked, @state.name
149
+ end
150
+
151
+ def test_should_have_a_nil_value
152
+ assert_nil @state.value
153
+ end
154
+
155
+ def test_should_match_nil_values
156
+ assert @state.matches?(nil)
157
+ end
158
+
159
+ def test_should_have_a_description
160
+ assert_equal 'parked (nil)', @state.description
161
+ end
162
+
163
+ def test_should_define_predicate
164
+ object = @klass.new
165
+ assert object.respond_to?(:parked?)
166
+ end
167
+ end
168
+
169
+ class StateWithSymbolicValueTest < Test::Unit::TestCase
170
+ def setup
171
+ @klass = Class.new
172
+ @machine = StateMachine::Machine.new(@klass)
173
+ @state = StateMachine::State.new(@machine, :parked, :value => :parked)
174
+ end
175
+
176
+ def test_should_use_custom_value
177
+ assert_equal :parked, @state.value
178
+ end
179
+
180
+ def test_should_not_include_value_in_description
181
+ assert_equal 'parked', @state.description
182
+ end
183
+
184
+ def test_should_match_symbolic_value
185
+ assert @state.matches?(:parked)
186
+ assert !@state.matches?('parked')
187
+ end
188
+
189
+ def test_should_define_predicate
190
+ object = @klass.new
191
+ assert object.respond_to?(:parked?)
192
+ end
193
+ end
194
+
195
+ class StateWithIntegerValueTest < Test::Unit::TestCase
196
+ def setup
197
+ @klass = Class.new
198
+ @machine = StateMachine::Machine.new(@klass)
199
+ @state = StateMachine::State.new(@machine, :parked, :value => 1)
200
+ end
201
+
202
+ def test_should_use_custom_value
203
+ assert_equal 1, @state.value
204
+ end
205
+
206
+ def test_should_include_value_in_description
207
+ assert_equal 'parked (1)', @state.description
208
+ end
209
+
210
+ def test_should_match_integer_value
211
+ assert @state.matches?(1)
212
+ assert !@state.matches?(2)
213
+ end
214
+
215
+ def test_should_define_predicate
216
+ object = @klass.new
217
+ assert object.respond_to?(:parked?)
218
+ end
219
+ end
220
+
221
+ class StateWithLambdaValueTest < Test::Unit::TestCase
222
+ def setup
223
+ @klass = Class.new
224
+ @args = nil
225
+ @machine = StateMachine::Machine.new(@klass)
226
+ @value = lambda {|*args| @args = args; :parked}
227
+ @state = StateMachine::State.new(@machine, :parked, :value => @value)
228
+ end
229
+
230
+ def test_should_use_evaluated_value_by_default
231
+ assert_equal :parked, @state.value
232
+ end
233
+
234
+ def test_should_allow_access_to_original_value
235
+ assert_equal @value, @state.value(false)
236
+ end
237
+
238
+ def test_should_include_masked_value_in_description
239
+ assert_equal 'parked (*)', @state.description
240
+ end
241
+
242
+ def test_should_not_pass_in_any_arguments
243
+ @state.value
244
+ assert_equal [], @args
245
+ end
246
+
247
+ def test_should_define_predicate
248
+ object = @klass.new
249
+ assert object.respond_to?(:parked?)
250
+ end
251
+
252
+ def test_should_match_evaluated_value
253
+ assert @state.matches?(:parked)
254
+ end
255
+ end
256
+
257
+ class StateWithCachedLambdaValueTest < Test::Unit::TestCase
258
+ def setup
259
+ @klass = Class.new
260
+ @machine = StateMachine::Machine.new(@klass)
261
+ @dynamic_value = lambda {'value'}
262
+ @machine.states << @state = StateMachine::State.new(@machine, :parked, :value => @dynamic_value, :cache => true)
263
+ end
264
+
265
+ def test_should_be_caching
266
+ assert @state.cache
267
+ end
268
+
269
+ def test_should_evaluate_value
270
+ assert_equal 'value', @state.value
271
+ end
272
+
273
+ def test_should_only_evaluate_value_once
274
+ value = @state.value
275
+ assert_same value, @state.value
276
+ end
277
+
278
+ def test_should_update_value_index_for_state_collection
279
+ @state.value
280
+ assert_equal @state, @machine.states['value', :value]
281
+ assert_nil @machine.states[@dynamic_value, :value]
282
+ end
283
+ end
284
+
285
+ class StateWithoutCachedLambdaValueTest < Test::Unit::TestCase
286
+ def setup
287
+ @klass = Class.new
288
+ @machine = StateMachine::Machine.new(@klass)
289
+ @dynamic_value = lambda {'value'}
290
+ @machine.states << @state = StateMachine::State.new(@machine, :parked, :value => @dynamic_value)
291
+ end
292
+
293
+ def test_should_not_be_caching
294
+ assert !@state.cache
295
+ end
296
+
297
+ def test_should_evaluate_value_each_time
298
+ value = @state.value
299
+ assert_not_same value, @state.value
300
+ end
301
+
302
+ def test_should_not_update_value_index_for_state_collection
303
+ @state.value
304
+ assert_nil @machine.states['value', :value]
305
+ assert_equal @state, @machine.states[@dynamic_value, :value]
306
+ end
307
+ end
308
+
309
+ class StateWithMatcherTest < Test::Unit::TestCase
310
+ def setup
311
+ @klass = Class.new
312
+ @args = nil
313
+ @machine = StateMachine::Machine.new(@klass)
314
+ @state = StateMachine::State.new(@machine, :parked, :if => lambda {|value| value == 1})
315
+ end
316
+
317
+ def test_should_not_match_actual_value
318
+ assert !@state.matches?('parked')
319
+ end
320
+
321
+ def test_should_match_evaluated_block
322
+ assert @state.matches?(1)
323
+ end
324
+ end
325
+
326
+ class StateInitialTest < Test::Unit::TestCase
327
+ def setup
328
+ @machine = StateMachine::Machine.new(Class.new)
329
+ @state = StateMachine::State.new(@machine, :parked, :initial => true)
330
+ end
331
+
332
+ def test_should_be_initial
333
+ assert @state.initial
334
+ assert @state.initial?
335
+ end
336
+ end
337
+
338
+ class StateNotInitialTest < Test::Unit::TestCase
339
+ def setup
340
+ @machine = StateMachine::Machine.new(Class.new)
341
+ @state = StateMachine::State.new(@machine, :parked, :initial => false)
342
+ end
343
+
344
+ def test_should_not_be_initial
345
+ assert !@state.initial
346
+ assert !@state.initial?
347
+ end
348
+ end
349
+
350
+ class StateFinalTest < Test::Unit::TestCase
351
+ def setup
352
+ @machine = StateMachine::Machine.new(Class.new)
353
+ @state = StateMachine::State.new(@machine, :parked)
354
+ end
355
+
356
+ def test_should_be_final_without_input_transitions
357
+ assert @state.final?
358
+ end
359
+
360
+ def test_should_be_final_with_input_transitions
361
+ @machine.event :park do
362
+ transition :idling => :parked
363
+ end
364
+
365
+ assert @state.final?
366
+ end
367
+
368
+ def test_should_be_final_with_loopback
369
+ @machine.event :ignite do
370
+ transition :parked => same
371
+ end
372
+
373
+ assert @state.final?
374
+ end
375
+ end
376
+
377
+ class StateNotFinalTest < Test::Unit::TestCase
378
+ def setup
379
+ @machine = StateMachine::Machine.new(Class.new)
380
+ @state = StateMachine::State.new(@machine, :parked)
381
+ end
382
+
383
+ def test_should_not_be_final_with_outgoing_whitelist_transitions
384
+ @machine.event :ignite do
385
+ transition :parked => :idling
386
+ end
387
+
388
+ assert !@state.final?
389
+ end
390
+
391
+ def test_should_not_be_final_with_outgoing_all_transitions
392
+ @machine.event :ignite do
393
+ transition all => :idling
394
+ end
395
+
396
+ assert !@state.final?
397
+ end
398
+
399
+ def test_should_not_be_final_with_outgoing_blacklist_transitions
400
+ @machine.event :ignite do
401
+ transition all - :first_gear => :idling
402
+ end
403
+
404
+ assert !@state.final?
405
+ end
406
+ end
407
+
408
+ class StateWithConflictingHelpersTest < Test::Unit::TestCase
409
+ def setup
410
+ @klass = Class.new do
411
+ def parked?
412
+ 0
413
+ end
414
+ end
415
+ @machine = StateMachine::Machine.new(@klass)
416
+ @machine.state :parked
417
+ @object = @klass.new
418
+ end
419
+
420
+ def test_should_not_redefine_state_predicate
421
+ assert_equal 0, @object.parked?
422
+ end
423
+
424
+ def test_should_allow_super_chaining
425
+ @klass.class_eval do
426
+ def parked?
427
+ super ? 1 : 0
428
+ end
429
+ end
430
+
431
+ assert_equal 0, @object.parked?
432
+ end
433
+ end
434
+
435
+ class StateWithNamespaceTest < Test::Unit::TestCase
436
+ def setup
437
+ @klass = Class.new
438
+ @machine = StateMachine::Machine.new(@klass, :namespace => 'alarm')
439
+ @state = StateMachine::State.new(@machine, :active)
440
+ @object = @klass.new
441
+ end
442
+
443
+ def test_should_have_a_name
444
+ assert_equal :active, @state.name
445
+ end
446
+
447
+ def test_should_have_a_qualified_name
448
+ assert_equal :alarm_active, @state.qualified_name
449
+ end
450
+
451
+ def test_should_namespace_predicate
452
+ assert @object.respond_to?(:alarm_active?)
453
+ end
454
+ end
455
+
456
+ class StateAfterBeingCopiedTest < Test::Unit::TestCase
457
+ def setup
458
+ @machine = StateMachine::Machine.new(Class.new)
459
+ @state = StateMachine::State.new(@machine, :parked)
460
+ @copied_state = @state.dup
461
+ end
462
+
463
+ def test_should_not_have_the_same_collection_of_methods
464
+ assert_not_same @state.methods, @copied_state.methods
465
+ end
466
+ end
467
+
468
+ class StateWithContextTest < Test::Unit::TestCase
469
+ def setup
470
+ @klass = Class.new
471
+ @machine = StateMachine::Machine.new(@klass)
472
+ @ancestors = @klass.ancestors
473
+ @state = StateMachine::State.new(@machine, :idling)
474
+
475
+ speed_method = nil
476
+ rpm_method = nil
477
+ @state.context do
478
+ def speed
479
+ 0
480
+ end
481
+ speed_method = instance_method(:speed)
482
+
483
+ def rpm
484
+ 1000
485
+ end
486
+ rpm_method = instance_method(:rpm)
487
+ end
488
+
489
+ @speed_method = speed_method
490
+ @rpm_method = rpm_method
491
+ end
492
+
493
+ def test_should_include_new_module_in_owner_class
494
+ assert_not_equal @ancestors, @klass.ancestors
495
+ assert_equal 1, @klass.ancestors.size - @ancestors.size
496
+ end
497
+
498
+ def test_should_define_each_context_method_in_owner_class
499
+ %w(speed rpm).each {|method| assert @klass.method_defined?(method)}
500
+ end
501
+
502
+ def test_should_not_use_context_methods_as_owner_class_methods
503
+ assert_not_equal @speed_method, @klass.instance_method(:speed)
504
+ assert_not_equal @rpm_method, @klass.instance_method(:rpm)
505
+ end
506
+
507
+ def test_should_include_context_methods_in_state_methods
508
+ assert_equal @speed_method, @state.methods[:speed]
509
+ assert_equal @rpm_method, @state.methods[:rpm]
510
+ end
511
+ end
512
+
513
+ class StateWithMultipleContextsTest < Test::Unit::TestCase
514
+ def setup
515
+ @klass = Class.new
516
+ @machine = StateMachine::Machine.new(@klass)
517
+ @ancestors = @klass.ancestors
518
+ @state = StateMachine::State.new(@machine, :idling)
519
+
520
+ speed_method = nil
521
+ @state.context do
522
+ def speed
523
+ 0
524
+ end
525
+
526
+ speed_method = instance_method(:speed)
527
+ end
528
+ @speed_method = speed_method
529
+
530
+ rpm_method = nil
531
+ @state.context do
532
+ def rpm
533
+ 1000
534
+ end
535
+
536
+ rpm_method = instance_method(:rpm)
537
+ end
538
+ @rpm_method = rpm_method
539
+ end
540
+
541
+ def test_should_include_new_module_in_owner_class
542
+ assert_not_equal @ancestors, @klass.ancestors
543
+ assert_equal 2, @klass.ancestors.size - @ancestors.size
544
+ end
545
+
546
+ def test_should_define_each_context_method_in_owner_class
547
+ %w(speed rpm).each {|method| assert @klass.method_defined?(method)}
548
+ end
549
+
550
+ def test_should_not_use_context_methods_as_owner_class_methods
551
+ assert_not_equal @speed_method, @klass.instance_method(:speed)
552
+ assert_not_equal @rpm_method, @klass.instance_method(:rpm)
553
+ end
554
+
555
+ def test_should_include_context_methods_in_state_methods
556
+ assert_equal @speed_method, @state.methods[:speed]
557
+ assert_equal @rpm_method, @state.methods[:rpm]
558
+ end
559
+ end
560
+
561
+ class StateWithExistingContextMethodTest < Test::Unit::TestCase
562
+ def setup
563
+ @klass = Class.new do
564
+ def speed
565
+ 60
566
+ end
567
+ end
568
+ @original_speed_method = @klass.instance_method(:speed)
569
+
570
+ @machine = StateMachine::Machine.new(@klass)
571
+ @state = StateMachine::State.new(@machine, :idling)
572
+ @state.context do
573
+ def speed
574
+ 0
575
+ end
576
+ end
577
+ end
578
+
579
+ def test_should_not_override_method
580
+ assert_equal @original_speed_method, @klass.instance_method(:speed)
581
+ end
582
+ end
583
+
584
+ class StateWithRedefinedContextMethodTest < Test::Unit::TestCase
585
+ def setup
586
+ @klass = Class.new
587
+ @machine = StateMachine::Machine.new(@klass)
588
+ @state = StateMachine::State.new(@machine, 'on')
589
+
590
+ old_speed_method = nil
591
+ @state.context do
592
+ def speed
593
+ 0
594
+ end
595
+ old_speed_method = instance_method(:speed)
596
+ end
597
+ @old_speed_method = old_speed_method
598
+
599
+ current_speed_method = nil
600
+ @state.context do
601
+ def speed
602
+ 'green'
603
+ end
604
+ current_speed_method = instance_method(:speed)
605
+ end
606
+ @current_speed_method = current_speed_method
607
+ end
608
+
609
+ def test_should_track_latest_defined_method
610
+ assert_equal @current_speed_method, @state.methods[:speed]
611
+ end
612
+ end
613
+
614
+ class StateWithInvalidMethodCallTest < Test::Unit::TestCase
615
+ def setup
616
+ @klass = Class.new
617
+ @machine = StateMachine::Machine.new(@klass)
618
+ @ancestors = @klass.ancestors
619
+ @state = StateMachine::State.new(@machine, :idling)
620
+ @state.context do
621
+ def speed
622
+ 0
623
+ end
624
+ end
625
+
626
+ @object = @klass.new
627
+ end
628
+
629
+ def test_should_raise_an_exception
630
+ exception = assert_raise(NoMethodError) { @state.call(@object, :invalid) }
631
+ assert_equal "undefined method 'invalid' for #{@object} in state nil", exception.message
632
+ end
633
+ end
634
+
635
+ class StateWithValidMethodCallTest < Test::Unit::TestCase
636
+ def setup
637
+ @klass = Class.new
638
+ @machine = StateMachine::Machine.new(@klass)
639
+ @ancestors = @klass.ancestors
640
+ @state = StateMachine::State.new(@machine, :idling)
641
+ @state.context do
642
+ def speed(arg = nil)
643
+ block_given? ? [arg, yield] : arg
644
+ end
645
+ end
646
+
647
+ @object = @klass.new
648
+ end
649
+
650
+ def test_should_not_raise_an_exception
651
+ assert_nothing_raised { @state.call(@object, :speed) }
652
+ end
653
+
654
+ def test_should_pass_arguments_through
655
+ assert_equal 1, @state.call(@object, :speed, 1)
656
+ end
657
+
658
+ def test_should_pass_blocks_through
659
+ assert_equal [nil, 1], @state.call(@object, :speed) {1}
660
+ end
661
+
662
+ def test_should_pass_both_arguments_and_blocks_through
663
+ assert_equal [1, 2], @state.call(@object, :speed, 1) {2}
664
+ end
665
+ end
666
+
667
+ begin
668
+ # Load library
669
+ require 'rubygems'
670
+ require 'graphviz'
671
+
672
+ class StateDrawingTest < Test::Unit::TestCase
673
+ def setup
674
+ @machine = StateMachine::Machine.new(Class.new)
675
+ @machine.event :ignite do
676
+ transition :parked => :idling
677
+ end
678
+ @state = StateMachine::State.new(@machine, :parked, :value => 1)
679
+
680
+ graph = GraphViz.new('G')
681
+ @node = @state.draw(graph)
682
+ end
683
+
684
+ def test_should_use_ellipse_shape
685
+ assert_equal 'ellipse', @node['shape']
686
+ end
687
+
688
+ def test_should_set_width_to_one
689
+ assert_equal '1', @node['width']
690
+ end
691
+
692
+ def test_should_set_height_to_one
693
+ assert_equal '1', @node['height']
694
+ end
695
+
696
+ def test_should_use_stringified_name_as_name
697
+ assert_equal 'parked', @node.name
698
+ end
699
+
700
+ def test_should_use_description_as_label
701
+ assert_equal 'parked (1)', @node['label']
702
+ end
703
+ end
704
+
705
+ class StateDrawingInitialTest < Test::Unit::TestCase
706
+ def setup
707
+ @machine = StateMachine::Machine.new(Class.new)
708
+ @machine.event :ignite do
709
+ transition :parked => :idling
710
+ end
711
+ @state = StateMachine::State.new(@machine, :parked, :initial => true)
712
+
713
+ @graph = GraphViz.new('G')
714
+ @node = @state.draw(@graph)
715
+ end
716
+
717
+ def test_should_use_ellipse_as_shape
718
+ assert_equal 'ellipse', @node['shape']
719
+ end
720
+
721
+ def test_should_draw_edge_between_point_and_state
722
+ assert_equal 2, @graph.node_count
723
+ assert_equal 1, @graph.edge_count
724
+ end
725
+ end
726
+
727
+ class StateDrawingNilNameTest < Test::Unit::TestCase
728
+ def setup
729
+ @machine = StateMachine::Machine.new(Class.new)
730
+ @state = StateMachine::State.new(@machine, nil)
731
+
732
+ graph = GraphViz.new('G')
733
+ @node = @state.draw(graph)
734
+ end
735
+
736
+ def test_should_use_stringified_nil_as_name
737
+ assert_equal 'nil', @node.name
738
+ end
739
+
740
+ def test_should_use_description_as_label
741
+ assert_equal 'nil', @node['label']
742
+ end
743
+ end
744
+
745
+ class StateDrawingLambdaValueTest < Test::Unit::TestCase
746
+ def setup
747
+ @machine = StateMachine::Machine.new(Class.new)
748
+ @state = StateMachine::State.new(@machine, :parked, :value => lambda {})
749
+
750
+ graph = GraphViz.new('G')
751
+ @node = @state.draw(graph)
752
+ end
753
+
754
+ def test_should_use_stringified_name_as_name
755
+ assert_equal 'parked', @node.name
756
+ end
757
+
758
+ def test_should_use_description_as_label
759
+ assert_equal 'parked (*)', @node['label']
760
+ end
761
+ end
762
+
763
+ class StateDrawingNonFinalTest < Test::Unit::TestCase
764
+ def setup
765
+ @machine = StateMachine::Machine.new(Class.new)
766
+ @machine.event :ignite do
767
+ transition :parked => :idling
768
+ end
769
+ @state = StateMachine::State.new(@machine, :parked)
770
+
771
+ graph = GraphViz.new('G')
772
+ @node = @state.draw(graph)
773
+ end
774
+
775
+ def test_should_use_ellipse_as_shape
776
+ assert_equal 'ellipse', @node['shape']
777
+ end
778
+ end
779
+
780
+ class StateDrawingFinalTest < Test::Unit::TestCase
781
+ def setup
782
+ @machine = StateMachine::Machine.new(Class.new)
783
+ @state = StateMachine::State.new(@machine, :parked)
784
+
785
+ graph = GraphViz.new('G')
786
+ @node = @state.draw(graph)
787
+ end
788
+
789
+ def test_should_use_doublecircle_as_shape
790
+ assert_equal 'doublecircle', @node['shape']
791
+ end
792
+ end
793
+ rescue LoadError
794
+ $stderr.puts 'Skipping GraphViz StateMachine::State tests. `gem install ruby-graphviz` and try again.'
795
+ end