mattscilipoti-state_machine 0.8.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (78) hide show
  1. data/CHANGELOG.rdoc +298 -0
  2. data/LICENSE +20 -0
  3. data/README.rdoc +474 -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 +388 -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 +252 -0
  33. data/lib/state_machine/event_collection.rb +122 -0
  34. data/lib/state_machine/extensions.rb +149 -0
  35. data/lib/state_machine/guard.rb +230 -0
  36. data/lib/state_machine/integrations.rb +68 -0
  37. data/lib/state_machine/integrations/active_record.rb +492 -0
  38. data/lib/state_machine/integrations/active_record/locale.rb +11 -0
  39. data/lib/state_machine/integrations/active_record/observer.rb +41 -0
  40. data/lib/state_machine/integrations/data_mapper.rb +351 -0
  41. data/lib/state_machine/integrations/data_mapper/observer.rb +139 -0
  42. data/lib/state_machine/integrations/sequel.rb +322 -0
  43. data/lib/state_machine/machine.rb +1467 -0
  44. data/lib/state_machine/machine_collection.rb +155 -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/tasks.rb +30 -0
  51. data/lib/state_machine/transition.rb +394 -0
  52. data/tasks/state_machine.rake +1 -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 +120 -0
  60. data/test/unit/event_collection_test.rb +326 -0
  61. data/test/unit/event_test.rb +743 -0
  62. data/test/unit/guard_test.rb +908 -0
  63. data/test/unit/integrations/active_record_test.rb +1367 -0
  64. data/test/unit/integrations/data_mapper_test.rb +962 -0
  65. data/test/unit/integrations/sequel_test.rb +859 -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 +938 -0
  70. data/test/unit/machine_test.rb +2004 -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 +1212 -0
  78. metadata +155 -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} with idling state", 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