joelind-state_machine 0.8.1

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 +297 -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 +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/transition.rb +394 -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 +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 +1374 -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 +163 -0
@@ -0,0 +1,908 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../test_helper')
2
+
3
+ class GuardTest < Test::Unit::TestCase
4
+ def setup
5
+ @guard = StateMachine::Guard.new(:from => :parked, :to => :idling)
6
+ end
7
+
8
+ def test_should_not_raise_exception_if_implicit_option_specified
9
+ assert_nothing_raised { StateMachine::Guard.new(:invalid => :valid) }
10
+ end
11
+
12
+ def test_should_not_have_an_if_condition
13
+ assert_nil @guard.if_condition
14
+ end
15
+
16
+ def test_should_not_have_an_unless_condition
17
+ assert_nil @guard.unless_condition
18
+ end
19
+
20
+ def test_should_have_a_state_requirement
21
+ assert_equal 1, @guard.state_requirements.length
22
+ end
23
+ end
24
+
25
+ class GuardWithNoRequirementsTest < Test::Unit::TestCase
26
+ def setup
27
+ @object = Object.new
28
+ @guard = StateMachine::Guard.new
29
+ end
30
+
31
+ def test_should_use_all_matcher_for_event_requirement
32
+ assert_equal StateMachine::AllMatcher.instance, @guard.event_requirement
33
+ end
34
+
35
+ def test_should_use_all_matcher_for_from_state_requirement
36
+ assert_equal StateMachine::AllMatcher.instance, @guard.state_requirements.first[:from]
37
+ end
38
+
39
+ def test_should_use_all_matcher_for_to_state_requirement
40
+ assert_equal StateMachine::AllMatcher.instance, @guard.state_requirements.first[:to]
41
+ end
42
+
43
+ def test_should_match_nil_query
44
+ assert @guard.matches?(@object, nil)
45
+ end
46
+
47
+ def test_should_match_empty_query
48
+ assert @guard.matches?(@object, {})
49
+ end
50
+
51
+ def test_should_match_non_empty_query
52
+ assert @guard.matches?(@object, :to => :idling, :from => :parked, :on => :ignite)
53
+ end
54
+
55
+ def test_should_include_all_requirements_in_match
56
+ match = @guard.match(@object, nil)
57
+
58
+ assert_equal @guard.state_requirements.first[:from], match[:from]
59
+ assert_equal @guard.state_requirements.first[:to], match[:to]
60
+ assert_equal @guard.event_requirement, match[:on]
61
+ end
62
+ end
63
+
64
+ class GuardWithFromRequirementTest < Test::Unit::TestCase
65
+ def setup
66
+ @object = Object.new
67
+ @guard = StateMachine::Guard.new(:from => :parked)
68
+ end
69
+
70
+ def test_should_use_a_whitelist_matcher
71
+ assert_instance_of StateMachine::WhitelistMatcher, @guard.state_requirements.first[:from]
72
+ end
73
+
74
+ def test_should_match_if_not_specified
75
+ assert @guard.matches?(@object, :to => :idling)
76
+ end
77
+
78
+ def test_should_match_if_included
79
+ assert @guard.matches?(@object, :from => :parked)
80
+ end
81
+
82
+ def test_should_not_match_if_not_included
83
+ assert !@guard.matches?(@object, :from => :idling)
84
+ end
85
+
86
+ def test_should_not_match_if_nil
87
+ assert !@guard.matches?(@object, :from => nil)
88
+ end
89
+
90
+ def test_should_ignore_to
91
+ assert @guard.matches?(@object, :from => :parked, :to => :idling)
92
+ end
93
+
94
+ def test_should_ignore_on
95
+ assert @guard.matches?(@object, :from => :parked, :on => :ignite)
96
+ end
97
+
98
+ def test_should_be_included_in_known_states
99
+ assert_equal [:parked], @guard.known_states
100
+ end
101
+
102
+ def test_should_include_requirement_in_match
103
+ match = @guard.match(@object, :from => :parked)
104
+ assert_equal @guard.state_requirements.first[:from], match[:from]
105
+ end
106
+ end
107
+
108
+ class GuardWithMultipleFromRequirementsTest < Test::Unit::TestCase
109
+ def setup
110
+ @object = Object.new
111
+ @guard = StateMachine::Guard.new(:from => [:idling, :parked])
112
+ end
113
+
114
+ def test_should_match_if_included
115
+ assert @guard.matches?(@object, :from => :idling)
116
+ end
117
+
118
+ def test_should_not_match_if_not_included
119
+ assert !@guard.matches?(@object, :from => :first_gear)
120
+ end
121
+
122
+ def test_should_be_included_in_known_states
123
+ assert_equal [:idling, :parked], @guard.known_states
124
+ end
125
+ end
126
+
127
+ class GuardWithToRequirementTest < Test::Unit::TestCase
128
+ def setup
129
+ @object = Object.new
130
+ @guard = StateMachine::Guard.new(:to => :idling)
131
+ end
132
+
133
+ def test_should_use_a_whitelist_matcher
134
+ assert_instance_of StateMachine::WhitelistMatcher, @guard.state_requirements.first[:to]
135
+ end
136
+
137
+ def test_should_match_if_not_specified
138
+ assert @guard.matches?(@object, :from => :parked)
139
+ end
140
+
141
+ def test_should_match_if_included
142
+ assert @guard.matches?(@object, :to => :idling)
143
+ end
144
+
145
+ def test_should_not_match_if_not_included
146
+ assert !@guard.matches?(@object, :to => :parked)
147
+ end
148
+
149
+ def test_should_not_match_if_nil
150
+ assert !@guard.matches?(@object, :to => nil)
151
+ end
152
+
153
+ def test_should_ignore_from
154
+ assert @guard.matches?(@object, :to => :idling, :from => :parked)
155
+ end
156
+
157
+ def test_should_ignore_on
158
+ assert @guard.matches?(@object, :to => :idling, :on => :ignite)
159
+ end
160
+
161
+ def test_should_be_included_in_known_states
162
+ assert_equal [:idling], @guard.known_states
163
+ end
164
+
165
+ def test_should_include_requirement_in_match
166
+ match = @guard.match(@object, :to => :idling)
167
+ assert_equal @guard.state_requirements.first[:to], match[:to]
168
+ end
169
+ end
170
+
171
+ class GuardWithMultipleToRequirementsTest < Test::Unit::TestCase
172
+ def setup
173
+ @object = Object.new
174
+ @guard = StateMachine::Guard.new(:to => [:idling, :parked])
175
+ end
176
+
177
+ def test_should_match_if_included
178
+ assert @guard.matches?(@object, :to => :idling)
179
+ end
180
+
181
+ def test_should_not_match_if_not_included
182
+ assert !@guard.matches?(@object, :to => :first_gear)
183
+ end
184
+
185
+ def test_should_be_included_in_known_states
186
+ assert_equal [:idling, :parked], @guard.known_states
187
+ end
188
+ end
189
+
190
+ class GuardWithOnRequirementTest < Test::Unit::TestCase
191
+ def setup
192
+ @object = Object.new
193
+ @guard = StateMachine::Guard.new(:on => :ignite)
194
+ end
195
+
196
+ def test_should_use_a_whitelist_matcher
197
+ assert_instance_of StateMachine::WhitelistMatcher, @guard.event_requirement
198
+ end
199
+
200
+ def test_should_match_if_not_specified
201
+ assert @guard.matches?(@object, :from => :parked)
202
+ end
203
+
204
+ def test_should_match_if_included
205
+ assert @guard.matches?(@object, :on => :ignite)
206
+ end
207
+
208
+ def test_should_not_match_if_not_included
209
+ assert !@guard.matches?(@object, :on => :park)
210
+ end
211
+
212
+ def test_should_not_match_if_nil
213
+ assert !@guard.matches?(@object, :on => nil)
214
+ end
215
+
216
+ def test_should_ignore_to
217
+ assert @guard.matches?(@object, :on => :ignite, :to => :parked)
218
+ end
219
+
220
+ def test_should_ignore_from
221
+ assert @guard.matches?(@object, :on => :ignite, :from => :parked)
222
+ end
223
+
224
+ def test_should_not_be_included_in_known_states
225
+ assert_equal [], @guard.known_states
226
+ end
227
+
228
+ def test_should_include_requirement_in_match
229
+ match = @guard.match(@object, :on => :ignite)
230
+ assert_equal @guard.event_requirement, match[:on]
231
+ end
232
+ end
233
+
234
+ class GuardWithMultipleOnRequirementsTest < Test::Unit::TestCase
235
+ def setup
236
+ @object = Object.new
237
+ @guard = StateMachine::Guard.new(:on => [:ignite, :park])
238
+ end
239
+
240
+ def test_should_match_if_included
241
+ assert @guard.matches?(@object, :on => :ignite)
242
+ end
243
+
244
+ def test_should_not_match_if_not_included
245
+ assert !@guard.matches?(@object, :on => :shift_up)
246
+ end
247
+ end
248
+
249
+ class GuardWithExceptFromRequirementTest < Test::Unit::TestCase
250
+ def setup
251
+ @object = Object.new
252
+ @guard = StateMachine::Guard.new(:except_from => :parked)
253
+ end
254
+
255
+ def test_should_use_a_blacklist_matcher
256
+ assert_instance_of StateMachine::BlacklistMatcher, @guard.state_requirements.first[:from]
257
+ end
258
+
259
+ def test_should_match_if_not_included
260
+ assert @guard.matches?(@object, :from => :idling)
261
+ end
262
+
263
+ def test_should_not_match_if_included
264
+ assert !@guard.matches?(@object, :from => :parked)
265
+ end
266
+
267
+ def test_should_match_if_nil
268
+ assert @guard.matches?(@object, :from => nil)
269
+ end
270
+
271
+ def test_should_ignore_to
272
+ assert @guard.matches?(@object, :from => :idling, :to => :parked)
273
+ end
274
+
275
+ def test_should_ignore_on
276
+ assert @guard.matches?(@object, :from => :idling, :on => :ignite)
277
+ end
278
+
279
+ def test_should_be_included_in_known_states
280
+ assert_equal [:parked], @guard.known_states
281
+ end
282
+ end
283
+
284
+ class GuardWithMultipleExceptFromRequirementsTest < Test::Unit::TestCase
285
+ def setup
286
+ @object = Object.new
287
+ @guard = StateMachine::Guard.new(:except_from => [:idling, :parked])
288
+ end
289
+
290
+ def test_should_match_if_not_included
291
+ assert @guard.matches?(@object, :from => :first_gear)
292
+ end
293
+
294
+ def test_should_not_match_if_included
295
+ assert !@guard.matches?(@object, :from => :idling)
296
+ end
297
+
298
+ def test_should_be_included_in_known_states
299
+ assert_equal [:idling, :parked], @guard.known_states
300
+ end
301
+ end
302
+
303
+ class GuardWithExceptToRequirementTest < Test::Unit::TestCase
304
+ def setup
305
+ @object = Object.new
306
+ @guard = StateMachine::Guard.new(:except_to => :idling)
307
+ end
308
+
309
+ def test_should_use_a_blacklist_matcher
310
+ assert_instance_of StateMachine::BlacklistMatcher, @guard.state_requirements.first[:to]
311
+ end
312
+
313
+ def test_should_match_if_not_included
314
+ assert @guard.matches?(@object, :to => :parked)
315
+ end
316
+
317
+ def test_should_not_match_if_included
318
+ assert !@guard.matches?(@object, :to => :idling)
319
+ end
320
+
321
+ def test_should_match_if_nil
322
+ assert @guard.matches?(@object, :to => nil)
323
+ end
324
+
325
+ def test_should_ignore_from
326
+ assert @guard.matches?(@object, :to => :parked, :from => :idling)
327
+ end
328
+
329
+ def test_should_ignore_on
330
+ assert @guard.matches?(@object, :to => :parked, :on => :ignite)
331
+ end
332
+
333
+ def test_should_be_included_in_known_states
334
+ assert_equal [:idling], @guard.known_states
335
+ end
336
+ end
337
+
338
+ class GuardWithMultipleExceptToRequirementsTest < Test::Unit::TestCase
339
+ def setup
340
+ @object = Object.new
341
+ @guard = StateMachine::Guard.new(:except_to => [:idling, :parked])
342
+ end
343
+
344
+ def test_should_match_if_not_included
345
+ assert @guard.matches?(@object, :to => :first_gear)
346
+ end
347
+
348
+ def test_should_not_match_if_included
349
+ assert !@guard.matches?(@object, :to => :idling)
350
+ end
351
+
352
+ def test_should_be_included_in_known_states
353
+ assert_equal [:idling, :parked], @guard.known_states
354
+ end
355
+ end
356
+
357
+ class GuardWithExceptOnRequirementTest < Test::Unit::TestCase
358
+ def setup
359
+ @object = Object.new
360
+ @guard = StateMachine::Guard.new(:except_on => :ignite)
361
+ end
362
+
363
+ def test_should_use_a_blacklist_matcher
364
+ assert_instance_of StateMachine::BlacklistMatcher, @guard.event_requirement
365
+ end
366
+
367
+ def test_should_match_if_not_included
368
+ assert @guard.matches?(@object, :on => :park)
369
+ end
370
+
371
+ def test_should_not_match_if_included
372
+ assert !@guard.matches?(@object, :on => :ignite)
373
+ end
374
+
375
+ def test_should_match_if_nil
376
+ assert @guard.matches?(@object, :on => nil)
377
+ end
378
+
379
+ def test_should_ignore_to
380
+ assert @guard.matches?(@object, :on => :park, :to => :idling)
381
+ end
382
+
383
+ def test_should_ignore_from
384
+ assert @guard.matches?(@object, :on => :park, :from => :parked)
385
+ end
386
+
387
+ def test_should_not_be_included_in_known_states
388
+ assert_equal [], @guard.known_states
389
+ end
390
+ end
391
+
392
+ class GuardWithMultipleExceptOnRequirementsTest < Test::Unit::TestCase
393
+ def setup
394
+ @object = Object.new
395
+ @guard = StateMachine::Guard.new(:except_on => [:ignite, :park])
396
+ end
397
+
398
+ def test_should_match_if_not_included
399
+ assert @guard.matches?(@object, :on => :shift_up)
400
+ end
401
+
402
+ def test_should_not_match_if_included
403
+ assert !@guard.matches?(@object, :on => :ignite)
404
+ end
405
+ end
406
+
407
+ class GuardWithFailuresExcludedTest < Test::Unit::TestCase
408
+ def setup
409
+ @object = Object.new
410
+ @guard = StateMachine::Guard.new(:include_failures => false)
411
+ end
412
+
413
+ def test_should_use_a_blacklist_matcher
414
+ assert_instance_of StateMachine::WhitelistMatcher, @guard.success_requirement
415
+ end
416
+
417
+ def test_should_match_if_not_specified
418
+ assert @guard.matches?(@object)
419
+ end
420
+
421
+ def test_should_match_if_true
422
+ assert @guard.matches?(@object, :success => true)
423
+ end
424
+
425
+ def test_should_not_match_if_false
426
+ assert !@guard.matches?(@object, :success => false)
427
+ end
428
+ end
429
+
430
+ class GuardWithFailuresIncludedTest < Test::Unit::TestCase
431
+ def setup
432
+ @object = Object.new
433
+ @guard = StateMachine::Guard.new(:include_failures => true)
434
+ end
435
+
436
+ def test_should_use_all_matcher
437
+ assert_equal StateMachine::AllMatcher.instance, @guard.success_requirement
438
+ end
439
+
440
+ def test_should_match_if_not_specified
441
+ assert @guard.matches?(@object)
442
+ end
443
+
444
+ def test_should_match_if_true
445
+ assert @guard.matches?(@object, :success => true)
446
+ end
447
+
448
+ def test_should_match_if_false
449
+ assert @guard.matches?(@object, :success => false)
450
+ end
451
+ end
452
+
453
+ class GuardWithConflictingFromRequirementsTest < Test::Unit::TestCase
454
+ def test_should_raise_an_exception
455
+ exception = assert_raise(ArgumentError) { StateMachine::Guard.new(:from => :parked, :except_from => :parked) }
456
+ assert_equal 'Conflicting keys: from, except_from', exception.message
457
+ end
458
+ end
459
+
460
+ class GuardWithConflictingToRequirementsTest < Test::Unit::TestCase
461
+ def test_should_raise_an_exception
462
+ exception = assert_raise(ArgumentError) { StateMachine::Guard.new(:to => :idling, :except_to => :idling) }
463
+ assert_equal 'Conflicting keys: to, except_to', exception.message
464
+ end
465
+ end
466
+
467
+ class GuardWithConflictingOnRequirementsTest < Test::Unit::TestCase
468
+ def test_should_raise_an_exception
469
+ exception = assert_raise(ArgumentError) { StateMachine::Guard.new(:on => :ignite, :except_on => :ignite) }
470
+ assert_equal 'Conflicting keys: on, except_on', exception.message
471
+ end
472
+ end
473
+
474
+ class GuardWithDifferentRequirementsTest < Test::Unit::TestCase
475
+ def setup
476
+ @object = Object.new
477
+ @guard = StateMachine::Guard.new(:from => :parked, :to => :idling, :on => :ignite)
478
+ end
479
+
480
+ def test_should_match_empty_query
481
+ assert @guard.matches?(@object)
482
+ end
483
+
484
+ def test_should_match_if_all_requirements_match
485
+ assert @guard.matches?(@object, :from => :parked, :to => :idling, :on => :ignite)
486
+ end
487
+
488
+ def test_should_not_match_if_from_not_included
489
+ assert !@guard.matches?(@object, :from => :idling)
490
+ end
491
+
492
+ def test_should_not_match_if_to_not_included
493
+ assert !@guard.matches?(@object, :to => :parked)
494
+ end
495
+
496
+ def test_should_not_match_if_on_not_included
497
+ assert !@guard.matches?(@object, :on => :park)
498
+ end
499
+
500
+ def test_should_be_nil_if_unmatched
501
+ assert_nil @guard.match(@object, :from => :parked, :to => :idling, :on => :park)
502
+ end
503
+
504
+ def test_should_include_all_known_states
505
+ assert_equal [:parked, :idling], @guard.known_states
506
+ end
507
+
508
+ def test_should_not_duplicate_known_statse
509
+ guard = StateMachine::Guard.new(:except_from => :idling, :to => :idling, :on => :ignite)
510
+ assert_equal [:idling], guard.known_states
511
+ end
512
+ end
513
+
514
+ class GuardWithNilRequirementsTest < Test::Unit::TestCase
515
+ def setup
516
+ @object = Object.new
517
+ @guard = StateMachine::Guard.new(:from => nil, :to => nil)
518
+ end
519
+
520
+ def test_should_match_empty_query
521
+ assert @guard.matches?(@object)
522
+ end
523
+
524
+ def test_should_match_if_all_requirements_match
525
+ assert @guard.matches?(@object, :from => nil, :to => nil)
526
+ end
527
+
528
+ def test_should_not_match_if_from_not_included
529
+ assert !@guard.matches?(@object, :from => :parked)
530
+ end
531
+
532
+ def test_should_not_match_if_to_not_included
533
+ assert !@guard.matches?(@object, :to => :idling)
534
+ end
535
+
536
+ def test_should_include_all_known_states
537
+ assert_equal [nil], @guard.known_states
538
+ end
539
+ end
540
+
541
+ class GuardWithImplicitRequirementTest < Test::Unit::TestCase
542
+ def setup
543
+ @guard = StateMachine::Guard.new(:parked => :idling, :on => :ignite)
544
+ end
545
+
546
+ def test_should_create_an_event_requirement
547
+ assert_instance_of StateMachine::WhitelistMatcher, @guard.event_requirement
548
+ assert_equal [:ignite], @guard.event_requirement.values
549
+ end
550
+
551
+ def test_should_use_a_whitelist_from_matcher
552
+ assert_instance_of StateMachine::WhitelistMatcher, @guard.state_requirements.first[:from]
553
+ end
554
+
555
+ def test_should_use_a_whitelist_to_matcher
556
+ assert_instance_of StateMachine::WhitelistMatcher, @guard.state_requirements.first[:to]
557
+ end
558
+ end
559
+
560
+ class GuardWithMultipleImplicitRequirementsTest < Test::Unit::TestCase
561
+ def setup
562
+ @object = Object.new
563
+ @guard = StateMachine::Guard.new(:parked => :idling, :idling => :first_gear, :on => :ignite)
564
+ end
565
+
566
+ def test_should_create_multiple_state_requirements
567
+ assert_equal 2, @guard.state_requirements.length
568
+ end
569
+
570
+ def test_should_not_match_event_as_state_requirement
571
+ assert !@guard.matches?(@object, :from => :on, :to => :ignite)
572
+ end
573
+
574
+ def test_should_match_if_from_included_in_any
575
+ assert @guard.matches?(@object, :from => :parked)
576
+ assert @guard.matches?(@object, :from => :idling)
577
+ end
578
+
579
+ def test_should_not_match_if_from_not_included_in_any
580
+ assert !@guard.matches?(@object, :from => :first_gear)
581
+ end
582
+
583
+ def test_should_match_if_to_included_in_any
584
+ assert @guard.matches?(@object, :to => :idling)
585
+ assert @guard.matches?(@object, :to => :first_gear)
586
+ end
587
+
588
+ def test_should_not_match_if_to_not_included_in_any
589
+ assert !@guard.matches?(@object, :to => :parked)
590
+ end
591
+
592
+ def test_should_match_if_all_options_match
593
+ assert @guard.matches?(@object, :from => :parked, :to => :idling, :on => :ignite)
594
+ assert @guard.matches?(@object, :from => :idling, :to => :first_gear, :on => :ignite)
595
+ end
596
+
597
+ def test_should_not_match_if_any_options_do_not_match
598
+ assert !@guard.matches?(@object, :from => :parked, :to => :idling, :on => :park)
599
+ assert !@guard.matches?(@object, :from => :parked, :to => :first_gear, :on => :park)
600
+ end
601
+
602
+ def test_should_include_all_known_states
603
+ assert_equal [:first_gear, :idling, :parked], @guard.known_states.sort_by {|state| state.to_s}
604
+ end
605
+
606
+ def test_should_not_duplicate_known_statse
607
+ guard = StateMachine::Guard.new(:parked => :idling, :first_gear => :idling)
608
+ assert_equal [:first_gear, :idling, :parked], guard.known_states.sort_by {|state| state.to_s}
609
+ end
610
+ end
611
+
612
+ class GuardWithImplicitFromRequirementMatcherTest < Test::Unit::TestCase
613
+ def setup
614
+ @matcher = StateMachine::BlacklistMatcher.new(:parked)
615
+ @guard = StateMachine::Guard.new(@matcher => :idling)
616
+ end
617
+
618
+ def test_should_not_convert_from_to_whitelist_matcher
619
+ assert_equal @matcher, @guard.state_requirements.first[:from]
620
+ end
621
+
622
+ def test_should_convert_to_to_whitelist_matcher
623
+ assert_instance_of StateMachine::WhitelistMatcher, @guard.state_requirements.first[:to]
624
+ end
625
+ end
626
+
627
+ class GuardWithImplicitToRequirementMatcherTest < Test::Unit::TestCase
628
+ def setup
629
+ @matcher = StateMachine::BlacklistMatcher.new(:idling)
630
+ @guard = StateMachine::Guard.new(:parked => @matcher)
631
+ end
632
+
633
+ def test_should_convert_from_to_whitelist_matcher
634
+ assert_instance_of StateMachine::WhitelistMatcher, @guard.state_requirements.first[:from]
635
+ end
636
+
637
+ def test_should_not_convert_to_to_whitelist_matcher
638
+ assert_equal @matcher, @guard.state_requirements.first[:to]
639
+ end
640
+ end
641
+
642
+ class GuardWithImplicitAndExplicitRequirementsTest < Test::Unit::TestCase
643
+ def setup
644
+ @guard = StateMachine::Guard.new(:parked => :idling, :from => :parked)
645
+ end
646
+
647
+ def test_should_create_multiple_requirements
648
+ assert_equal 2, @guard.state_requirements.length
649
+ end
650
+
651
+ def test_should_create_implicit_requirements_for_implicit_options
652
+ assert(@guard.state_requirements.any? do |state_requirement|
653
+ state_requirement[:from].values == [:parked] && state_requirement[:to].values == [:idling]
654
+ end)
655
+ end
656
+
657
+ def test_should_create_implicit_requirements_for_explicit_options
658
+ assert(@guard.state_requirements.any? do |state_requirement|
659
+ state_requirement[:from].values == [:from] && state_requirement[:to].values == [:parked]
660
+ end)
661
+ end
662
+ end
663
+
664
+ class GuardWithIfConditionalTest < Test::Unit::TestCase
665
+ def setup
666
+ @object = Object.new
667
+ end
668
+
669
+ def test_should_have_an_if_condition
670
+ guard = StateMachine::Guard.new(:if => lambda {true})
671
+ assert_not_nil guard.if_condition
672
+ end
673
+
674
+ def test_should_match_if_true
675
+ guard = StateMachine::Guard.new(:if => lambda {true})
676
+ assert guard.matches?(@object)
677
+ end
678
+
679
+ def test_should_not_match_if_false
680
+ guard = StateMachine::Guard.new(:if => lambda {false})
681
+ assert !guard.matches?(@object)
682
+ end
683
+
684
+ def test_should_be_nil_if_unmatched
685
+ guard = StateMachine::Guard.new(:if => lambda {false})
686
+ assert_nil guard.match(@object)
687
+ end
688
+ end
689
+
690
+ class GuardWithMultipleIfConditionalsTest < Test::Unit::TestCase
691
+ def setup
692
+ @object = Object.new
693
+ end
694
+
695
+ def test_should_match_if_all_are_true
696
+ guard = StateMachine::Guard.new(:if => [lambda {true}, lambda {true}])
697
+ assert guard.match(@object)
698
+ end
699
+
700
+ def test_should_not_match_if_any_are_false
701
+ guard = StateMachine::Guard.new(:if => [lambda {true}, lambda {false}])
702
+ assert !guard.match(@object)
703
+
704
+ guard = StateMachine::Guard.new(:if => [lambda {false}, lambda {true}])
705
+ assert !guard.match(@object)
706
+ end
707
+ end
708
+
709
+ class GuardWithUnlessConditionalTest < Test::Unit::TestCase
710
+ def setup
711
+ @object = Object.new
712
+ end
713
+
714
+ def test_should_have_an_unless_condition
715
+ guard = StateMachine::Guard.new(:unless => lambda {true})
716
+ assert_not_nil guard.unless_condition
717
+ end
718
+
719
+ def test_should_match_if_false
720
+ guard = StateMachine::Guard.new(:unless => lambda {false})
721
+ assert guard.matches?(@object)
722
+ end
723
+
724
+ def test_should_not_match_if_true
725
+ guard = StateMachine::Guard.new(:unless => lambda {true})
726
+ assert !guard.matches?(@object)
727
+ end
728
+
729
+ def test_should_be_nil_if_unmatched
730
+ guard = StateMachine::Guard.new(:unless => lambda {true})
731
+ assert_nil guard.match(@object)
732
+ end
733
+ end
734
+
735
+ class GuardWithMultipleUnlessConditionalsTest < Test::Unit::TestCase
736
+ def setup
737
+ @object = Object.new
738
+ end
739
+
740
+ def test_should_match_if_all_are_false
741
+ guard = StateMachine::Guard.new(:unless => [lambda {false}, lambda {false}])
742
+ assert guard.match(@object)
743
+ end
744
+
745
+ def test_should_not_match_if_any_are_true
746
+ guard = StateMachine::Guard.new(:unless => [lambda {true}, lambda {false}])
747
+ assert !guard.match(@object)
748
+
749
+ guard = StateMachine::Guard.new(:unless => [lambda {false}, lambda {true}])
750
+ assert !guard.match(@object)
751
+ end
752
+ end
753
+
754
+ class GuardWithConflictingConditionalsTest < Test::Unit::TestCase
755
+ def test_should_match_if_if_is_true_and_unless_is_false
756
+ guard = StateMachine::Guard.new(:if => lambda {true}, :unless => lambda {false})
757
+ assert guard.match(@object)
758
+ end
759
+
760
+ def test_should_not_match_if_if_is_false_and_unless_is_true
761
+ guard = StateMachine::Guard.new(:if => lambda {false}, :unless => lambda {true})
762
+ assert !guard.match(@object)
763
+ end
764
+
765
+ def test_should_not_match_if_if_is_false_and_unless_is_false
766
+ guard = StateMachine::Guard.new(:if => lambda {false}, :unless => lambda {false})
767
+ assert !guard.match(@object)
768
+ end
769
+
770
+ def test_should_not_match_if_if_is_true_and_unless_is_true
771
+ guard = StateMachine::Guard.new(:if => lambda {true}, :unless => lambda {true})
772
+ assert !guard.match(@object)
773
+ end
774
+ end
775
+
776
+ begin
777
+ # Load library
778
+ require 'rubygems'
779
+ require 'graphviz'
780
+
781
+ class GuardDrawingTest < Test::Unit::TestCase
782
+ def setup
783
+ @machine = StateMachine::Machine.new(Class.new)
784
+ states = [:parked, :idling]
785
+
786
+ graph = GraphViz.new('G')
787
+ states.each {|state| graph.add_node(state.to_s)}
788
+
789
+ @guard = StateMachine::Guard.new(:from => :idling, :to => :parked)
790
+ @edges = @guard.draw(graph, :park, states)
791
+ end
792
+
793
+ def test_should_create_edges
794
+ assert_equal 1, @edges.size
795
+ end
796
+
797
+ def test_should_use_from_state_from_start_node
798
+ assert_equal 'idling', @edges.first.instance_variable_get('@xNodeOne')
799
+ end
800
+
801
+ def test_should_use_to_state_for_end_node
802
+ assert_equal 'parked', @edges.first.instance_variable_get('@xNodeTwo')
803
+ end
804
+
805
+ def test_should_use_event_name_as_label
806
+ assert_equal 'park', @edges.first['label']
807
+ end
808
+ end
809
+
810
+ class GuardDrawingWithFromRequirementTest < Test::Unit::TestCase
811
+ def setup
812
+ @machine = StateMachine::Machine.new(Class.new)
813
+ states = [:parked, :idling, :first_gear]
814
+
815
+ graph = GraphViz.new('G')
816
+ states.each {|state| graph.add_node(state.to_s)}
817
+
818
+ @guard = StateMachine::Guard.new(:from => [:idling, :first_gear], :to => :parked)
819
+ @edges = @guard.draw(graph, :park, states)
820
+ end
821
+
822
+ def test_should_generate_edges_for_each_valid_from_state
823
+ [:idling, :first_gear].each_with_index do |from_state, index|
824
+ edge = @edges[index]
825
+ assert_equal from_state.to_s, edge.instance_variable_get('@xNodeOne')
826
+ assert_equal 'parked', edge.instance_variable_get('@xNodeTwo')
827
+ end
828
+ end
829
+ end
830
+
831
+ class GuardDrawingWithExceptFromRequirementTest < Test::Unit::TestCase
832
+ def setup
833
+ @machine = StateMachine::Machine.new(Class.new)
834
+ states = [:parked, :idling, :first_gear]
835
+
836
+ graph = GraphViz.new('G')
837
+ states.each {|state| graph.add_node(state.to_s)}
838
+
839
+ @guard = StateMachine::Guard.new(:except_from => :parked, :to => :parked)
840
+ @edges = @guard.draw(graph, :park, states)
841
+ end
842
+
843
+ def test_should_generate_edges_for_each_valid_from_state
844
+ %w(idling first_gear).each_with_index do |from_state, index|
845
+ edge = @edges[index]
846
+ assert_equal from_state, edge.instance_variable_get('@xNodeOne')
847
+ assert_equal 'parked', edge.instance_variable_get('@xNodeTwo')
848
+ end
849
+ end
850
+ end
851
+
852
+ class GuardDrawingWithoutFromRequirementTest < Test::Unit::TestCase
853
+ def setup
854
+ @machine = StateMachine::Machine.new(Class.new)
855
+ states = [:parked, :idling, :first_gear]
856
+
857
+ graph = GraphViz.new('G')
858
+ states.each {|state| graph.add_node(state.to_s)}
859
+
860
+ @guard = StateMachine::Guard.new(:to => :parked)
861
+ @edges = @guard.draw(graph, :park, states)
862
+ end
863
+
864
+ def test_should_generate_edges_for_each_valid_from_state
865
+ %w(parked idling first_gear).each_with_index do |from_state, index|
866
+ edge = @edges[index]
867
+ assert_equal from_state, edge.instance_variable_get('@xNodeOne')
868
+ assert_equal 'parked', edge.instance_variable_get('@xNodeTwo')
869
+ end
870
+ end
871
+ end
872
+
873
+ class GuardDrawingWithoutToRequirementTest < Test::Unit::TestCase
874
+ def setup
875
+ @machine = StateMachine::Machine.new(Class.new)
876
+
877
+ graph = GraphViz.new('G')
878
+ graph.add_node('parked')
879
+
880
+ @guard = StateMachine::Guard.new(:from => :parked)
881
+ @edges = @guard.draw(graph, :park, [:parked])
882
+ end
883
+
884
+ def test_should_create_loopback_edge
885
+ assert_equal 'parked', @edges.first.instance_variable_get('@xNodeOne')
886
+ assert_equal 'parked', @edges.first.instance_variable_get('@xNodeTwo')
887
+ end
888
+ end
889
+
890
+ class GuardDrawingWithNilStateTest < Test::Unit::TestCase
891
+ def setup
892
+ @machine = StateMachine::Machine.new(Class.new)
893
+
894
+ graph = GraphViz.new('G')
895
+ graph.add_node('parked')
896
+
897
+ @guard = StateMachine::Guard.new(:from => :idling, :to => nil)
898
+ @edges = @guard.draw(graph, :park, [nil, :idling])
899
+ end
900
+
901
+ def test_should_generate_edges_for_each_valid_from_state
902
+ assert_equal 'idling', @edges.first.instance_variable_get('@xNodeOne')
903
+ assert_equal 'nil', @edges.first.instance_variable_get('@xNodeTwo')
904
+ end
905
+ end
906
+ rescue LoadError
907
+ $stderr.puts 'Skipping GraphViz StateMachine::Guard tests. `gem install ruby-graphviz` and try again.'
908
+ end