hsume2-state_machine 1.0.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 (110) hide show
  1. data/CHANGELOG.rdoc +413 -0
  2. data/LICENSE +20 -0
  3. data/README.rdoc +717 -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.rb +448 -0
  28. data/lib/state_machine/alternate_machine.rb +79 -0
  29. data/lib/state_machine/assertions.rb +36 -0
  30. data/lib/state_machine/branch.rb +224 -0
  31. data/lib/state_machine/callback.rb +236 -0
  32. data/lib/state_machine/condition_proxy.rb +94 -0
  33. data/lib/state_machine/error.rb +13 -0
  34. data/lib/state_machine/eval_helpers.rb +86 -0
  35. data/lib/state_machine/event.rb +304 -0
  36. data/lib/state_machine/event_collection.rb +139 -0
  37. data/lib/state_machine/extensions.rb +149 -0
  38. data/lib/state_machine/initializers.rb +4 -0
  39. data/lib/state_machine/initializers/merb.rb +1 -0
  40. data/lib/state_machine/initializers/rails.rb +25 -0
  41. data/lib/state_machine/integrations.rb +110 -0
  42. data/lib/state_machine/integrations/active_model.rb +502 -0
  43. data/lib/state_machine/integrations/active_model/locale.rb +11 -0
  44. data/lib/state_machine/integrations/active_model/observer.rb +45 -0
  45. data/lib/state_machine/integrations/active_model/versions.rb +31 -0
  46. data/lib/state_machine/integrations/active_record.rb +424 -0
  47. data/lib/state_machine/integrations/active_record/locale.rb +20 -0
  48. data/lib/state_machine/integrations/active_record/versions.rb +143 -0
  49. data/lib/state_machine/integrations/base.rb +91 -0
  50. data/lib/state_machine/integrations/data_mapper.rb +392 -0
  51. data/lib/state_machine/integrations/data_mapper/observer.rb +210 -0
  52. data/lib/state_machine/integrations/data_mapper/versions.rb +62 -0
  53. data/lib/state_machine/integrations/mongo_mapper.rb +272 -0
  54. data/lib/state_machine/integrations/mongo_mapper/locale.rb +4 -0
  55. data/lib/state_machine/integrations/mongo_mapper/versions.rb +110 -0
  56. data/lib/state_machine/integrations/mongoid.rb +357 -0
  57. data/lib/state_machine/integrations/mongoid/locale.rb +4 -0
  58. data/lib/state_machine/integrations/mongoid/versions.rb +18 -0
  59. data/lib/state_machine/integrations/sequel.rb +428 -0
  60. data/lib/state_machine/integrations/sequel/versions.rb +36 -0
  61. data/lib/state_machine/machine.rb +1873 -0
  62. data/lib/state_machine/machine_collection.rb +87 -0
  63. data/lib/state_machine/matcher.rb +123 -0
  64. data/lib/state_machine/matcher_helpers.rb +54 -0
  65. data/lib/state_machine/node_collection.rb +157 -0
  66. data/lib/state_machine/path.rb +120 -0
  67. data/lib/state_machine/path_collection.rb +90 -0
  68. data/lib/state_machine/state.rb +271 -0
  69. data/lib/state_machine/state_collection.rb +112 -0
  70. data/lib/state_machine/transition.rb +458 -0
  71. data/lib/state_machine/transition_collection.rb +244 -0
  72. data/lib/tasks/state_machine.rake +1 -0
  73. data/lib/tasks/state_machine.rb +27 -0
  74. data/test/files/en.yml +17 -0
  75. data/test/files/switch.rb +11 -0
  76. data/test/functional/alternate_state_machine_test.rb +122 -0
  77. data/test/functional/state_machine_test.rb +993 -0
  78. data/test/test_helper.rb +4 -0
  79. data/test/unit/assertions_test.rb +40 -0
  80. data/test/unit/branch_test.rb +890 -0
  81. data/test/unit/callback_test.rb +701 -0
  82. data/test/unit/condition_proxy_test.rb +328 -0
  83. data/test/unit/error_test.rb +43 -0
  84. data/test/unit/eval_helpers_test.rb +222 -0
  85. data/test/unit/event_collection_test.rb +358 -0
  86. data/test/unit/event_test.rb +985 -0
  87. data/test/unit/integrations/active_model_test.rb +1097 -0
  88. data/test/unit/integrations/active_record_test.rb +2021 -0
  89. data/test/unit/integrations/base_test.rb +99 -0
  90. data/test/unit/integrations/data_mapper_test.rb +1909 -0
  91. data/test/unit/integrations/mongo_mapper_test.rb +1611 -0
  92. data/test/unit/integrations/mongoid_test.rb +1591 -0
  93. data/test/unit/integrations/sequel_test.rb +1523 -0
  94. data/test/unit/integrations_test.rb +61 -0
  95. data/test/unit/invalid_event_test.rb +20 -0
  96. data/test/unit/invalid_parallel_transition_test.rb +18 -0
  97. data/test/unit/invalid_transition_test.rb +77 -0
  98. data/test/unit/machine_collection_test.rb +599 -0
  99. data/test/unit/machine_test.rb +3043 -0
  100. data/test/unit/matcher_helpers_test.rb +37 -0
  101. data/test/unit/matcher_test.rb +155 -0
  102. data/test/unit/node_collection_test.rb +217 -0
  103. data/test/unit/path_collection_test.rb +266 -0
  104. data/test/unit/path_test.rb +485 -0
  105. data/test/unit/state_collection_test.rb +310 -0
  106. data/test/unit/state_machine_test.rb +31 -0
  107. data/test/unit/state_test.rb +924 -0
  108. data/test/unit/transition_collection_test.rb +2102 -0
  109. data/test/unit/transition_test.rb +1541 -0
  110. metadata +207 -0
@@ -0,0 +1,37 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../test_helper')
2
+
3
+ class MatcherHelpersAllTest < Test::Unit::TestCase
4
+ include StateMachine::MatcherHelpers
5
+
6
+ def setup
7
+ @matcher = all
8
+ end
9
+
10
+ def test_should_build_an_all_matcher
11
+ assert_equal StateMachine::AllMatcher.instance, @matcher
12
+ end
13
+ end
14
+
15
+ class MatcherHelpersAnyTest < Test::Unit::TestCase
16
+ include StateMachine::MatcherHelpers
17
+
18
+ def setup
19
+ @matcher = any
20
+ end
21
+
22
+ def test_should_build_an_all_matcher
23
+ assert_equal StateMachine::AllMatcher.instance, @matcher
24
+ end
25
+ end
26
+
27
+ class MatcherHelpersSameTest < Test::Unit::TestCase
28
+ include StateMachine::MatcherHelpers
29
+
30
+ def setup
31
+ @matcher = same
32
+ end
33
+
34
+ def test_should_build_a_loopback_matcher
35
+ assert_equal StateMachine::LoopbackMatcher.instance, @matcher
36
+ end
37
+ end
@@ -0,0 +1,155 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../test_helper')
2
+
3
+ class MatcherByDefaultTest < Test::Unit::TestCase
4
+ def setup
5
+ @matcher = StateMachine::Matcher.new
6
+ end
7
+
8
+ def test_should_have_no_values
9
+ assert_equal [], @matcher.values
10
+ end
11
+
12
+ def test_should_filter_all_values
13
+ assert_equal [], @matcher.filter([:parked, :idling])
14
+ end
15
+ end
16
+
17
+ class MatcherWithValueTest < Test::Unit::TestCase
18
+ def setup
19
+ @matcher = StateMachine::Matcher.new(nil)
20
+ end
21
+
22
+ def test_should_have_values
23
+ assert_equal [nil], @matcher.values
24
+ end
25
+
26
+ def test_should_filter_unknown_values
27
+ assert_equal [nil], @matcher.filter([nil, :parked])
28
+ end
29
+ end
30
+
31
+ class MatcherWithMultipleValuesTest < Test::Unit::TestCase
32
+ def setup
33
+ @matcher = StateMachine::Matcher.new([:parked, :idling])
34
+ end
35
+
36
+ def test_should_have_values
37
+ assert_equal [:parked, :idling], @matcher.values
38
+ end
39
+
40
+ def test_should_filter_unknown_values
41
+ assert_equal [:parked], @matcher.filter([:parked, :first_gear])
42
+ end
43
+ end
44
+
45
+ class AllMatcherTest < Test::Unit::TestCase
46
+ def setup
47
+ @matcher = StateMachine::AllMatcher.instance
48
+ end
49
+
50
+ def test_should_have_no_values
51
+ assert_equal [], @matcher.values
52
+ end
53
+
54
+ def test_should_always_match
55
+ [nil, :parked, :idling].each {|value| assert @matcher.matches?(value)}
56
+ end
57
+
58
+ def test_should_not_filter_any_values
59
+ assert_equal [:parked, :idling], @matcher.filter([:parked, :idling])
60
+ end
61
+
62
+ def test_should_generate_blacklist_matcher_after_subtraction
63
+ matcher = @matcher - [:parked, :idling]
64
+ assert_instance_of StateMachine::BlacklistMatcher, matcher
65
+ assert_equal [:parked, :idling], matcher.values
66
+ end
67
+
68
+ def test_should_have_a_description
69
+ assert_equal 'all', @matcher.description
70
+ end
71
+ end
72
+
73
+ class WhitelistMatcherTest < Test::Unit::TestCase
74
+ def setup
75
+ @matcher = StateMachine::WhitelistMatcher.new([:parked, :idling])
76
+ end
77
+
78
+ def test_should_have_values
79
+ assert_equal [:parked, :idling], @matcher.values
80
+ end
81
+
82
+ def test_should_filter_unknown_values
83
+ assert_equal [:parked, :idling], @matcher.filter([:parked, :idling, :first_gear])
84
+ end
85
+
86
+ def test_should_match_known_values
87
+ assert @matcher.matches?(:parked)
88
+ end
89
+
90
+ def test_should_not_match_unknown_values
91
+ assert !@matcher.matches?(:first_gear)
92
+ end
93
+
94
+ def test_should_have_a_description
95
+ assert_equal '[:parked, :idling]', @matcher.description
96
+
97
+ matcher = StateMachine::WhitelistMatcher.new([:parked])
98
+ assert_equal ':parked', matcher.description
99
+ end
100
+ end
101
+
102
+ class BlacklistMatcherTest < Test::Unit::TestCase
103
+ def setup
104
+ @matcher = StateMachine::BlacklistMatcher.new([:parked, :idling])
105
+ end
106
+
107
+ def test_should_have_values
108
+ assert_equal [:parked, :idling], @matcher.values
109
+ end
110
+
111
+ def test_should_filter_known_values
112
+ assert_equal [:first_gear], @matcher.filter([:parked, :idling, :first_gear])
113
+ end
114
+
115
+ def test_should_match_unknown_values
116
+ assert @matcher.matches?(:first_gear)
117
+ end
118
+
119
+ def test_should_not_match_known_values
120
+ assert !@matcher.matches?(:parked)
121
+ end
122
+
123
+ def test_should_have_a_description
124
+ assert_equal 'all - [:parked, :idling]', @matcher.description
125
+
126
+ matcher = StateMachine::BlacklistMatcher.new([:parked])
127
+ assert_equal 'all - :parked', matcher.description
128
+ end
129
+ end
130
+
131
+ class LoopbackMatcherTest < Test::Unit::TestCase
132
+ def setup
133
+ @matcher = StateMachine::LoopbackMatcher.instance
134
+ end
135
+
136
+ def test_should_have_no_values
137
+ assert_equal [], @matcher.values
138
+ end
139
+
140
+ def test_should_filter_all_values
141
+ assert_equal [], @matcher.filter([:parked, :idling])
142
+ end
143
+
144
+ def test_should_match_if_from_context_is_same
145
+ assert @matcher.matches?(:parked, :from => :parked)
146
+ end
147
+
148
+ def test_should_not_match_if_from_context_is_different
149
+ assert !@matcher.matches?(:parked, :from => :idling)
150
+ end
151
+
152
+ def test_should_have_a_description
153
+ assert_equal 'same', @matcher.description
154
+ end
155
+ end
@@ -0,0 +1,217 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../test_helper')
2
+
3
+ class NodeCollectionByDefaultTest < Test::Unit::TestCase
4
+ def setup
5
+ @machine = StateMachine::Machine.new(Class.new)
6
+ @collection = StateMachine::NodeCollection.new(@machine)
7
+ end
8
+
9
+ def test_should_not_have_any_nodes
10
+ assert_equal 0, @collection.length
11
+ end
12
+
13
+ def test_should_have_a_machine
14
+ assert_equal @machine, @collection.machine
15
+ end
16
+
17
+ def test_should_index_by_name
18
+ @collection << object = Struct.new(:name).new(:parked)
19
+ assert_equal object, @collection[:parked]
20
+ end
21
+ end
22
+
23
+ class NodeCollectionTest < Test::Unit::TestCase
24
+ def setup
25
+ @machine = StateMachine::Machine.new(Class.new)
26
+ @collection = StateMachine::NodeCollection.new(@machine)
27
+ end
28
+
29
+ def test_should_raise_exception_if_invalid_option_specified
30
+ exception = assert_raise(ArgumentError) { StateMachine::NodeCollection.new(@machine, :invalid => true) }
31
+ assert_equal 'Invalid key(s): invalid', exception.message
32
+ end
33
+
34
+ def test_should_raise_exception_on_lookup_if_invalid_index_specified
35
+ exception = assert_raise(ArgumentError) { @collection[:something, :invalid] }
36
+ assert_equal 'Invalid index: :invalid', exception.message
37
+ end
38
+
39
+ def test_should_raise_exception_on_fetch_if_invalid_index_specified
40
+ exception = assert_raise(ArgumentError) { @collection.fetch(:something, :invalid) }
41
+ assert_equal 'Invalid index: :invalid', exception.message
42
+ end
43
+ end
44
+
45
+ class NodeCollectionAfterBeingCopiedTest < Test::Unit::TestCase
46
+ def setup
47
+ machine = StateMachine::Machine.new(Class.new)
48
+ @collection = StateMachine::NodeCollection.new(machine)
49
+ @collection << @parked = Struct.new(:name).new(:parked)
50
+
51
+ @copied_collection = @collection.dup
52
+ @copied_collection << @idling = Struct.new(:name).new(:idling)
53
+ end
54
+
55
+ def test_should_not_modify_the_original_list
56
+ assert_equal 1, @collection.length
57
+ assert_equal 2, @copied_collection.length
58
+ end
59
+
60
+ def test_should_not_modify_the_indices
61
+ assert_nil @collection[:idling]
62
+ assert_equal @idling, @copied_collection[:idling]
63
+ end
64
+
65
+ def test_should_copy_each_node
66
+ assert_not_same @parked, @copied_collection[:parked]
67
+ end
68
+ end
69
+
70
+ class NodeCollectionWithoutIndicesTest < Test::Unit::TestCase
71
+ def setup
72
+ machine = StateMachine::Machine.new(Class.new)
73
+ @collection = StateMachine::NodeCollection.new(machine, :index => {})
74
+ end
75
+
76
+ def test_should_allow_adding_node
77
+ @collection << Object.new
78
+ assert_equal 1, @collection.length
79
+ end
80
+
81
+ def test_should_not_allow_keys_retrieval
82
+ exception = assert_raise(ArgumentError) { @collection.keys }
83
+ assert_equal 'No indices configured', exception.message
84
+ end
85
+
86
+ def test_should_not_allow_lookup
87
+ @collection << object = Object.new
88
+ exception = assert_raise(ArgumentError) { @collection[0] }
89
+ assert_equal 'No indices configured', exception.message
90
+ end
91
+
92
+ def test_should_not_allow_fetching
93
+ @collection << object = Object.new
94
+ exception = assert_raise(ArgumentError) { @collection.fetch(0) }
95
+ assert_equal 'No indices configured', exception.message
96
+ end
97
+ end
98
+
99
+ class NodeCollectionWithIndicesTest < Test::Unit::TestCase
100
+ def setup
101
+ machine = StateMachine::Machine.new(Class.new)
102
+ @collection = StateMachine::NodeCollection.new(machine, :index => [:name, :value])
103
+
104
+ @object = Struct.new(:name, :value).new(:parked, 1)
105
+ @collection << @object
106
+ end
107
+
108
+ def test_should_use_first_index_by_default_on_key_retrieval
109
+ assert_equal [:parked], @collection.keys
110
+ end
111
+
112
+ def test_should_allow_customizing_index_for_key_retrieval
113
+ assert_equal [1], @collection.keys(:value)
114
+ end
115
+
116
+ def test_should_use_first_index_by_default_on_lookup
117
+ assert_equal @object, @collection[:parked]
118
+ assert_nil @collection[1]
119
+ end
120
+
121
+ def test_should_allow_customizing_index_on_lookup
122
+ assert_equal @object, @collection[1, :value]
123
+ assert_nil @collection[:parked, :value]
124
+ end
125
+
126
+ def test_should_use_first_index_by_default_on_fetch
127
+ assert_equal @object, @collection.fetch(:parked)
128
+ exception = assert_raise(IndexError) { @collection.fetch(1) }
129
+ assert_equal '1 is an invalid name', exception.message
130
+ end
131
+
132
+ def test_should_allow_customizing_index_on_fetch
133
+ assert_equal @object, @collection.fetch(1, :value)
134
+ exception = assert_raise(IndexError) { @collection.fetch(:parked, :value) }
135
+ assert_equal ':parked is an invalid value', exception.message
136
+ end
137
+ end
138
+
139
+ class NodeCollectionWithNodesTest < Test::Unit::TestCase
140
+ def setup
141
+ @machine = StateMachine::Machine.new(Class.new)
142
+ @collection = StateMachine::NodeCollection.new(@machine)
143
+
144
+ @klass = Struct.new(:name, :machine)
145
+ @parked = @klass.new(:parked, @machine)
146
+ @idling = @klass.new(:idling, @machine)
147
+
148
+ @collection << @parked
149
+ @collection << @idling
150
+ end
151
+
152
+ def test_should_be_able_to_enumerate
153
+ order = []
154
+ @collection.each {|object| order << object}
155
+
156
+ assert_equal [@parked, @idling], order
157
+ end
158
+
159
+ def test_should_be_able_to_concatenate_multiple_nodes
160
+ @first_gear = @klass.new(:first_gear, @machine)
161
+ @second_gear = @klass.new(:second_gear, @machine)
162
+ @collection.concat([@first_gear, @second_gear])
163
+
164
+ order = []
165
+ @collection.each {|object| order << object}
166
+ assert_equal [@parked, @idling, @first_gear, @second_gear], order
167
+ end
168
+
169
+ def test_should_be_able_to_access_by_index
170
+ assert_equal @parked, @collection.at(0)
171
+ assert_equal @idling, @collection.at(1)
172
+ end
173
+
174
+ def test_should_deep_copy_machine_changes
175
+ new_machine = StateMachine::Machine.new(Class.new)
176
+ @collection.machine = new_machine
177
+
178
+ assert_equal new_machine, @collection.machine
179
+ assert_equal new_machine, @parked.machine
180
+ assert_equal new_machine, @idling.machine
181
+ end
182
+ end
183
+
184
+ class NodeCollectionAfterUpdateTest < Test::Unit::TestCase
185
+ def setup
186
+ machine = StateMachine::Machine.new(Class.new)
187
+ @collection = StateMachine::NodeCollection.new(machine, :index => [:name, :value])
188
+
189
+ @klass = Struct.new(:name, :value)
190
+ @parked = @klass.new(:parked, 1)
191
+ @idling = @klass.new(:idling, 2)
192
+
193
+ @collection << @parked << @idling
194
+
195
+ @parked.name = :parking
196
+ @parked.value = 0
197
+ @collection.update(@parked)
198
+ end
199
+
200
+ def test_should_not_change_the_index
201
+ assert_equal @parked, @collection.at(0)
202
+ end
203
+
204
+ def test_should_not_duplicate_in_the_collection
205
+ assert_equal 2, @collection.length
206
+ end
207
+
208
+ def test_should_add_each_indexed_key
209
+ assert_equal @parked, @collection[:parking]
210
+ assert_equal @parked, @collection[0, :value]
211
+ end
212
+
213
+ def test_should_remove_each_old_indexed_key
214
+ assert_nil @collection[:parked]
215
+ assert_nil @collection[1, :value]
216
+ end
217
+ end
@@ -0,0 +1,266 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../test_helper')
2
+
3
+ class PathCollectionByDefaultTest < Test::Unit::TestCase
4
+ def setup
5
+ @klass = Class.new
6
+ @machine = StateMachine::Machine.new(@klass)
7
+ @machine.state :parked
8
+
9
+ @object = @klass.new
10
+ @object.state = 'parked'
11
+
12
+ @paths = StateMachine::PathCollection.new(@object, @machine)
13
+ end
14
+
15
+ def test_should_have_an_object
16
+ assert_equal @object, @paths.object
17
+ end
18
+
19
+ def test_should_have_a_machine
20
+ assert_equal @machine, @paths.machine
21
+ end
22
+
23
+ def test_should_have_a_from_name
24
+ assert_equal :parked, @paths.from_name
25
+ end
26
+
27
+ def test_should_not_have_a_to_name
28
+ assert_nil @paths.to_name
29
+ end
30
+
31
+ def test_should_have_no_from_states
32
+ assert_equal [], @paths.from_states
33
+ end
34
+
35
+ def test_should_have_no_to_states
36
+ assert_equal [], @paths.to_states
37
+ end
38
+
39
+ def test_should_have_no_events
40
+ assert_equal [], @paths.events
41
+ end
42
+
43
+ def test_should_have_no_paths
44
+ assert @paths.empty?
45
+ end
46
+ end
47
+
48
+ class PathCollectionTest < Test::Unit::TestCase
49
+ def setup
50
+ @klass = Class.new
51
+ @machine = StateMachine::Machine.new(@klass)
52
+ @object = @klass.new
53
+ end
54
+
55
+ def test_should_raise_exception_if_invalid_option_specified
56
+ exception = assert_raise(ArgumentError) {StateMachine::PathCollection.new(@object, @machine, :invalid => true)}
57
+ assert_equal 'Invalid key(s): invalid', exception.message
58
+ end
59
+
60
+ def test_should_raise_exception_if_invalid_from_state_specified
61
+ exception = assert_raise(IndexError) {StateMachine::PathCollection.new(@object, @machine, :from => :invalid)}
62
+ assert_equal ':invalid is an invalid name', exception.message
63
+ end
64
+
65
+ def test_should_raise_exception_if_invalid_to_state_specified
66
+ exception = assert_raise(IndexError) {StateMachine::PathCollection.new(@object, @machine, :to => :invalid)}
67
+ assert_equal ':invalid is an invalid name', exception.message
68
+ end
69
+ end
70
+
71
+ class PathCollectionWithPathsTest < Test::Unit::TestCase
72
+ def setup
73
+ @klass = Class.new
74
+ @machine = StateMachine::Machine.new(@klass)
75
+ @machine.state :parked, :idling, :first_gear
76
+ @machine.event :ignite do
77
+ transition :parked => :idling
78
+ end
79
+ @machine.event :shift_up do
80
+ transition :idling => :first_gear
81
+ end
82
+
83
+ @object = @klass.new
84
+ @object.state = 'parked'
85
+
86
+ @paths = StateMachine::PathCollection.new(@object, @machine)
87
+ end
88
+
89
+ def test_should_enumerate_paths
90
+ assert_equal [[
91
+ StateMachine::Transition.new(@object, @machine, :ignite, :parked, :idling),
92
+ StateMachine::Transition.new(@object, @machine, :shift_up, :idling, :first_gear)
93
+ ]], @paths
94
+ end
95
+
96
+ def test_should_have_a_from_name
97
+ assert_equal :parked, @paths.from_name
98
+ end
99
+
100
+ def test_should_not_have_a_to_name
101
+ assert_nil @paths.to_name
102
+ end
103
+
104
+ def test_should_have_from_states
105
+ assert_equal [:parked, :idling], @paths.from_states
106
+ end
107
+
108
+ def test_should_have_to_states
109
+ assert_equal [:idling, :first_gear], @paths.to_states
110
+ end
111
+
112
+ def test_should_have_no_events
113
+ assert_equal [:ignite, :shift_up], @paths.events
114
+ end
115
+ end
116
+
117
+ class PathWithGuardedPathsTest < Test::Unit::TestCase
118
+ def setup
119
+ @klass = Class.new
120
+ @machine = StateMachine::Machine.new(@klass)
121
+ @machine.state :parked, :idling, :first_gear
122
+ @machine.event :ignite do
123
+ transition :parked => :idling, :if => lambda {false}
124
+ end
125
+
126
+ @object = @klass.new
127
+ @object.state = 'parked'
128
+ end
129
+
130
+ def test_should_not_enumerate_paths_if_guard_enabled
131
+ assert_equal [], StateMachine::PathCollection.new(@object, @machine)
132
+ end
133
+
134
+ def test_should_enumerate_paths_if_guard_disabled
135
+ paths = StateMachine::PathCollection.new(@object, @machine, :guard => false)
136
+ assert_equal [[
137
+ StateMachine::Transition.new(@object, @machine, :ignite, :parked, :idling)
138
+ ]], paths
139
+ end
140
+ end
141
+
142
+ class PathCollectionWithDuplicateNodesTest < Test::Unit::TestCase
143
+ def setup
144
+ @klass = Class.new
145
+ @machine = StateMachine::Machine.new(@klass)
146
+ @machine.state :parked, :idling
147
+ @machine.event :shift_up do
148
+ transition :parked => :idling, :idling => :first_gear
149
+ end
150
+ @machine.event :park do
151
+ transition :first_gear => :idling
152
+ end
153
+ @object = @klass.new
154
+ @object.state = 'parked'
155
+
156
+ @paths = StateMachine::PathCollection.new(@object, @machine)
157
+ end
158
+
159
+ def test_should_not_include_duplicates_in_from_states
160
+ assert_equal [:parked, :idling, :first_gear], @paths.from_states
161
+ end
162
+
163
+ def test_should_not_include_duplicates_in_to_states
164
+ assert_equal [:idling, :first_gear], @paths.to_states
165
+ end
166
+
167
+ def test_should_not_include_duplicates_in_events
168
+ assert_equal [:shift_up, :park], @paths.events
169
+ end
170
+ end
171
+
172
+ class PathCollectionWithFromStateTest < Test::Unit::TestCase
173
+ def setup
174
+ @klass = Class.new
175
+ @machine = StateMachine::Machine.new(@klass)
176
+ @machine.state :parked, :idling, :first_gear
177
+ @machine.event :park do
178
+ transition :idling => :parked
179
+ end
180
+
181
+ @object = @klass.new
182
+ @object.state = 'parked'
183
+
184
+ @paths = StateMachine::PathCollection.new(@object, @machine, :from => :idling)
185
+ end
186
+
187
+ def test_should_generate_paths_from_custom_from_state
188
+ assert_equal [[
189
+ StateMachine::Transition.new(@object, @machine, :park, :idling, :parked)
190
+ ]], @paths
191
+ end
192
+
193
+ def test_should_have_a_from_name
194
+ assert_equal :idling, @paths.from_name
195
+ end
196
+ end
197
+
198
+ class PathCollectionWithToStateTest < Test::Unit::TestCase
199
+ def setup
200
+ @klass = Class.new
201
+ @machine = StateMachine::Machine.new(@klass)
202
+ @machine.state :parked, :idling
203
+ @machine.event :ignite do
204
+ transition :parked => :idling
205
+ end
206
+ @machine.event :shift_up do
207
+ transition :parked => :idling, :idling => :first_gear
208
+ end
209
+ @machine.event :shift_down do
210
+ transition :first_gear => :idling
211
+ end
212
+ @object = @klass.new
213
+ @object.state = 'parked'
214
+
215
+ @paths = StateMachine::PathCollection.new(@object, @machine, :to => :idling)
216
+ end
217
+
218
+ def test_should_stop_paths_once_target_state_reached
219
+ assert_equal [
220
+ [StateMachine::Transition.new(@object, @machine, :ignite, :parked, :idling)],
221
+ [StateMachine::Transition.new(@object, @machine, :shift_up, :parked, :idling)]
222
+ ], @paths
223
+ end
224
+ end
225
+
226
+ class PathCollectionWithDeepPathsTest < Test::Unit::TestCase
227
+ def setup
228
+ @klass = Class.new
229
+ @machine = StateMachine::Machine.new(@klass)
230
+ @machine.state :parked, :idling
231
+ @machine.event :ignite do
232
+ transition :parked => :idling
233
+ end
234
+ @machine.event :shift_up do
235
+ transition :parked => :idling, :idling => :first_gear
236
+ end
237
+ @machine.event :shift_down do
238
+ transition :first_gear => :idling
239
+ end
240
+ @object = @klass.new
241
+ @object.state = 'parked'
242
+
243
+ @paths = StateMachine::PathCollection.new(@object, @machine, :to => :idling, :deep => true)
244
+ end
245
+
246
+ def test_should_allow_target_to_be_reached_more_than_once_per_path
247
+ assert_equal [
248
+ [
249
+ StateMachine::Transition.new(@object, @machine, :ignite, :parked, :idling)
250
+ ],
251
+ [
252
+ StateMachine::Transition.new(@object, @machine, :ignite, :parked, :idling),
253
+ StateMachine::Transition.new(@object, @machine, :shift_up, :idling, :first_gear),
254
+ StateMachine::Transition.new(@object, @machine, :shift_down, :first_gear, :idling)
255
+ ],
256
+ [
257
+ StateMachine::Transition.new(@object, @machine, :shift_up, :parked, :idling)
258
+ ],
259
+ [
260
+ StateMachine::Transition.new(@object, @machine, :shift_up, :parked, :idling),
261
+ StateMachine::Transition.new(@object, @machine, :shift_up, :idling, :first_gear),
262
+ StateMachine::Transition.new(@object, @machine, :shift_down, :first_gear, :idling)
263
+ ]
264
+ ], @paths
265
+ end
266
+ end