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.
- data/CHANGELOG.rdoc +413 -0
- data/LICENSE +20 -0
- data/README.rdoc +717 -0
- data/Rakefile +77 -0
- data/examples/AutoShop_state.png +0 -0
- data/examples/Car_state.png +0 -0
- data/examples/TrafficLight_state.png +0 -0
- data/examples/Vehicle_state.png +0 -0
- data/examples/auto_shop.rb +11 -0
- data/examples/car.rb +19 -0
- data/examples/merb-rest/controller.rb +51 -0
- data/examples/merb-rest/model.rb +28 -0
- data/examples/merb-rest/view_edit.html.erb +24 -0
- data/examples/merb-rest/view_index.html.erb +23 -0
- data/examples/merb-rest/view_new.html.erb +13 -0
- data/examples/merb-rest/view_show.html.erb +17 -0
- data/examples/rails-rest/controller.rb +43 -0
- data/examples/rails-rest/migration.rb +11 -0
- data/examples/rails-rest/model.rb +23 -0
- data/examples/rails-rest/view_edit.html.erb +25 -0
- data/examples/rails-rest/view_index.html.erb +23 -0
- data/examples/rails-rest/view_new.html.erb +14 -0
- data/examples/rails-rest/view_show.html.erb +17 -0
- data/examples/traffic_light.rb +7 -0
- data/examples/vehicle.rb +31 -0
- data/init.rb +1 -0
- data/lib/state_machine.rb +448 -0
- data/lib/state_machine/alternate_machine.rb +79 -0
- data/lib/state_machine/assertions.rb +36 -0
- data/lib/state_machine/branch.rb +224 -0
- data/lib/state_machine/callback.rb +236 -0
- data/lib/state_machine/condition_proxy.rb +94 -0
- data/lib/state_machine/error.rb +13 -0
- data/lib/state_machine/eval_helpers.rb +86 -0
- data/lib/state_machine/event.rb +304 -0
- data/lib/state_machine/event_collection.rb +139 -0
- data/lib/state_machine/extensions.rb +149 -0
- data/lib/state_machine/initializers.rb +4 -0
- data/lib/state_machine/initializers/merb.rb +1 -0
- data/lib/state_machine/initializers/rails.rb +25 -0
- data/lib/state_machine/integrations.rb +110 -0
- data/lib/state_machine/integrations/active_model.rb +502 -0
- data/lib/state_machine/integrations/active_model/locale.rb +11 -0
- data/lib/state_machine/integrations/active_model/observer.rb +45 -0
- data/lib/state_machine/integrations/active_model/versions.rb +31 -0
- data/lib/state_machine/integrations/active_record.rb +424 -0
- data/lib/state_machine/integrations/active_record/locale.rb +20 -0
- data/lib/state_machine/integrations/active_record/versions.rb +143 -0
- data/lib/state_machine/integrations/base.rb +91 -0
- data/lib/state_machine/integrations/data_mapper.rb +392 -0
- data/lib/state_machine/integrations/data_mapper/observer.rb +210 -0
- data/lib/state_machine/integrations/data_mapper/versions.rb +62 -0
- data/lib/state_machine/integrations/mongo_mapper.rb +272 -0
- data/lib/state_machine/integrations/mongo_mapper/locale.rb +4 -0
- data/lib/state_machine/integrations/mongo_mapper/versions.rb +110 -0
- data/lib/state_machine/integrations/mongoid.rb +357 -0
- data/lib/state_machine/integrations/mongoid/locale.rb +4 -0
- data/lib/state_machine/integrations/mongoid/versions.rb +18 -0
- data/lib/state_machine/integrations/sequel.rb +428 -0
- data/lib/state_machine/integrations/sequel/versions.rb +36 -0
- data/lib/state_machine/machine.rb +1873 -0
- data/lib/state_machine/machine_collection.rb +87 -0
- data/lib/state_machine/matcher.rb +123 -0
- data/lib/state_machine/matcher_helpers.rb +54 -0
- data/lib/state_machine/node_collection.rb +157 -0
- data/lib/state_machine/path.rb +120 -0
- data/lib/state_machine/path_collection.rb +90 -0
- data/lib/state_machine/state.rb +271 -0
- data/lib/state_machine/state_collection.rb +112 -0
- data/lib/state_machine/transition.rb +458 -0
- data/lib/state_machine/transition_collection.rb +244 -0
- data/lib/tasks/state_machine.rake +1 -0
- data/lib/tasks/state_machine.rb +27 -0
- data/test/files/en.yml +17 -0
- data/test/files/switch.rb +11 -0
- data/test/functional/alternate_state_machine_test.rb +122 -0
- data/test/functional/state_machine_test.rb +993 -0
- data/test/test_helper.rb +4 -0
- data/test/unit/assertions_test.rb +40 -0
- data/test/unit/branch_test.rb +890 -0
- data/test/unit/callback_test.rb +701 -0
- data/test/unit/condition_proxy_test.rb +328 -0
- data/test/unit/error_test.rb +43 -0
- data/test/unit/eval_helpers_test.rb +222 -0
- data/test/unit/event_collection_test.rb +358 -0
- data/test/unit/event_test.rb +985 -0
- data/test/unit/integrations/active_model_test.rb +1097 -0
- data/test/unit/integrations/active_record_test.rb +2021 -0
- data/test/unit/integrations/base_test.rb +99 -0
- data/test/unit/integrations/data_mapper_test.rb +1909 -0
- data/test/unit/integrations/mongo_mapper_test.rb +1611 -0
- data/test/unit/integrations/mongoid_test.rb +1591 -0
- data/test/unit/integrations/sequel_test.rb +1523 -0
- data/test/unit/integrations_test.rb +61 -0
- data/test/unit/invalid_event_test.rb +20 -0
- data/test/unit/invalid_parallel_transition_test.rb +18 -0
- data/test/unit/invalid_transition_test.rb +77 -0
- data/test/unit/machine_collection_test.rb +599 -0
- data/test/unit/machine_test.rb +3043 -0
- data/test/unit/matcher_helpers_test.rb +37 -0
- data/test/unit/matcher_test.rb +155 -0
- data/test/unit/node_collection_test.rb +217 -0
- data/test/unit/path_collection_test.rb +266 -0
- data/test/unit/path_test.rb +485 -0
- data/test/unit/state_collection_test.rb +310 -0
- data/test/unit/state_machine_test.rb +31 -0
- data/test/unit/state_test.rb +924 -0
- data/test/unit/transition_collection_test.rb +2102 -0
- data/test/unit/transition_test.rb +1541 -0
- 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
|