hsume2-state_machine 1.0.1

Sign up to get free protection for your applications and to get access to all the features.
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