verborghs-state_machine 0.9.4

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