state_machine 0.9.4 → 0.10.0

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