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,310 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/../test_helper')
|
2
|
+
|
3
|
+
class StateCollectionByDefaultTest < Test::Unit::TestCase
|
4
|
+
def setup
|
5
|
+
@machine = StateMachine::Machine.new(Class.new)
|
6
|
+
@states = StateMachine::StateCollection.new(@machine)
|
7
|
+
end
|
8
|
+
|
9
|
+
def test_should_not_have_any_nodes
|
10
|
+
assert_equal 0, @states.length
|
11
|
+
end
|
12
|
+
|
13
|
+
def test_should_have_a_machine
|
14
|
+
assert_equal @machine, @states.machine
|
15
|
+
end
|
16
|
+
|
17
|
+
def test_should_be_empty_by_priority
|
18
|
+
assert_equal [], @states.by_priority
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
class StateCollectionTest < Test::Unit::TestCase
|
23
|
+
def setup
|
24
|
+
@klass = Class.new
|
25
|
+
@machine = StateMachine::Machine.new(@klass)
|
26
|
+
@states = StateMachine::StateCollection.new(@machine)
|
27
|
+
|
28
|
+
@states << @nil = StateMachine::State.new(@machine, nil)
|
29
|
+
@states << @parked = StateMachine::State.new(@machine, :parked)
|
30
|
+
@states << @idling = StateMachine::State.new(@machine, :idling)
|
31
|
+
@machine.states.concat(@states)
|
32
|
+
|
33
|
+
@object = @klass.new
|
34
|
+
end
|
35
|
+
|
36
|
+
def test_should_index_by_name
|
37
|
+
assert_equal @parked, @states[:parked, :name]
|
38
|
+
end
|
39
|
+
|
40
|
+
def test_should_index_by_name_by_default
|
41
|
+
assert_equal @parked, @states[:parked]
|
42
|
+
end
|
43
|
+
|
44
|
+
def test_should_index_by_qualified_name
|
45
|
+
assert_equal @parked, @states[:parked, :qualified_name]
|
46
|
+
end
|
47
|
+
|
48
|
+
def test_should_index_by_value
|
49
|
+
assert_equal @parked, @states['parked', :value]
|
50
|
+
end
|
51
|
+
|
52
|
+
def test_should_not_match_if_value_does_not_match
|
53
|
+
assert !@states.matches?(@object, :parked)
|
54
|
+
assert !@states.matches?(@object, :idling)
|
55
|
+
end
|
56
|
+
|
57
|
+
def test_should_match_if_value_matches
|
58
|
+
assert @states.matches?(@object, nil)
|
59
|
+
end
|
60
|
+
|
61
|
+
def test_raise_exception_if_matching_invalid_state
|
62
|
+
assert_raise(IndexError) { @states.matches?(@object, :invalid) }
|
63
|
+
end
|
64
|
+
|
65
|
+
def test_should_find_state_for_object_if_value_is_known
|
66
|
+
@object.state = 'parked'
|
67
|
+
assert_equal @parked, @states.match(@object)
|
68
|
+
end
|
69
|
+
|
70
|
+
def test_should_find_bang_state_for_object_if_value_is_known
|
71
|
+
@object.state = 'parked'
|
72
|
+
assert_equal @parked, @states.match!(@object)
|
73
|
+
end
|
74
|
+
|
75
|
+
def test_should_not_find_state_for_object_with_unknown_value
|
76
|
+
@object.state = 'invalid'
|
77
|
+
assert_nil @states.match(@object)
|
78
|
+
end
|
79
|
+
|
80
|
+
def test_should_raise_exception_if_finding_bang_state_for_object_with_unknown_value
|
81
|
+
@object.state = 'invalid'
|
82
|
+
exception = assert_raise(ArgumentError) { @states.match!(@object) }
|
83
|
+
assert_equal '"invalid" is not a known state value', exception.message
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
class StateCollectionWithNamespaceTest < Test::Unit::TestCase
|
88
|
+
def setup
|
89
|
+
@klass = Class.new
|
90
|
+
@machine = StateMachine::Machine.new(@klass, :namespace => 'vehicle')
|
91
|
+
@states = StateMachine::StateCollection.new(@machine)
|
92
|
+
|
93
|
+
@states << @state = StateMachine::State.new(@machine, :parked)
|
94
|
+
@machine.states.concat(@states)
|
95
|
+
end
|
96
|
+
|
97
|
+
def test_should_index_by_name
|
98
|
+
assert_equal @state, @states[:parked, :name]
|
99
|
+
end
|
100
|
+
|
101
|
+
def test_should_index_by_qualified_name
|
102
|
+
assert_equal @state, @states[:vehicle_parked, :qualified_name]
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
class StateCollectionWithCustomStateValuesTest < Test::Unit::TestCase
|
107
|
+
def setup
|
108
|
+
@klass = Class.new
|
109
|
+
@machine = StateMachine::Machine.new(@klass)
|
110
|
+
@states = StateMachine::StateCollection.new(@machine)
|
111
|
+
|
112
|
+
@states << @state = StateMachine::State.new(@machine, :parked, :value => 1)
|
113
|
+
@machine.states.concat(@states)
|
114
|
+
|
115
|
+
@object = @klass.new
|
116
|
+
@object.state = 1
|
117
|
+
end
|
118
|
+
|
119
|
+
def test_should_match_if_value_matches
|
120
|
+
assert @states.matches?(@object, :parked)
|
121
|
+
end
|
122
|
+
|
123
|
+
def test_should_not_match_if_value_does_not_match
|
124
|
+
@object.state = 2
|
125
|
+
assert !@states.matches?(@object, :parked)
|
126
|
+
end
|
127
|
+
|
128
|
+
def test_should_find_state_for_object_if_value_is_known
|
129
|
+
assert_equal @state, @states.match(@object)
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
class StateCollectionWithStateMatchersTest < Test::Unit::TestCase
|
134
|
+
def setup
|
135
|
+
@klass = Class.new
|
136
|
+
@machine = StateMachine::Machine.new(@klass)
|
137
|
+
@states = StateMachine::StateCollection.new(@machine)
|
138
|
+
|
139
|
+
@states << @state = StateMachine::State.new(@machine, :parked, :if => lambda {|value| !value.nil?})
|
140
|
+
@machine.states.concat(@states)
|
141
|
+
|
142
|
+
@object = @klass.new
|
143
|
+
@object.state = 1
|
144
|
+
end
|
145
|
+
|
146
|
+
def test_should_match_if_value_matches
|
147
|
+
assert @states.matches?(@object, :parked)
|
148
|
+
end
|
149
|
+
|
150
|
+
def test_should_not_match_if_value_does_not_match
|
151
|
+
@object.state = nil
|
152
|
+
assert !@states.matches?(@object, :parked)
|
153
|
+
end
|
154
|
+
|
155
|
+
def test_should_find_state_for_object_if_value_is_known
|
156
|
+
assert_equal @state, @states.match(@object)
|
157
|
+
end
|
158
|
+
end
|
159
|
+
|
160
|
+
class StateCollectionWithInitialStateTest < Test::Unit::TestCase
|
161
|
+
def setup
|
162
|
+
@machine = StateMachine::Machine.new(Class.new)
|
163
|
+
@states = StateMachine::StateCollection.new(@machine)
|
164
|
+
|
165
|
+
@states << @parked = StateMachine::State.new(@machine, :parked)
|
166
|
+
@states << @idling = StateMachine::State.new(@machine, :idling)
|
167
|
+
@machine.states.concat(@states)
|
168
|
+
|
169
|
+
@parked.initial = true
|
170
|
+
end
|
171
|
+
|
172
|
+
def test_should_order_state_before_transition_states
|
173
|
+
@machine.event :ignite do
|
174
|
+
transition :to => :idling
|
175
|
+
end
|
176
|
+
assert_equal [@parked, @idling], @states.by_priority
|
177
|
+
end
|
178
|
+
|
179
|
+
def test_should_order_state_before_states_with_behaviors
|
180
|
+
@idling.context do
|
181
|
+
def speed
|
182
|
+
0
|
183
|
+
end
|
184
|
+
end
|
185
|
+
assert_equal [@parked, @idling], @states.by_priority
|
186
|
+
end
|
187
|
+
|
188
|
+
def test_should_order_state_before_other_states
|
189
|
+
assert_equal [@parked, @idling], @states.by_priority
|
190
|
+
end
|
191
|
+
|
192
|
+
def test_should_order_state_before_callback_states
|
193
|
+
@machine.before_transition :from => :idling, :do => lambda {}
|
194
|
+
assert_equal [@parked, @idling], @states.by_priority
|
195
|
+
end
|
196
|
+
end
|
197
|
+
|
198
|
+
class StateCollectionWithStateBehaviorsTest < Test::Unit::TestCase
|
199
|
+
def setup
|
200
|
+
@machine = StateMachine::Machine.new(Class.new)
|
201
|
+
@states = StateMachine::StateCollection.new(@machine)
|
202
|
+
|
203
|
+
@states << @parked = StateMachine::State.new(@machine, :parked)
|
204
|
+
@states << @idling = StateMachine::State.new(@machine, :idling)
|
205
|
+
@machine.states.concat(@states)
|
206
|
+
|
207
|
+
@idling.context do
|
208
|
+
def speed
|
209
|
+
0
|
210
|
+
end
|
211
|
+
end
|
212
|
+
end
|
213
|
+
|
214
|
+
def test_should_order_states_after_initial_state
|
215
|
+
@parked.initial = true
|
216
|
+
assert_equal [@parked, @idling], @states.by_priority
|
217
|
+
end
|
218
|
+
|
219
|
+
def test_should_order_states_after_transition_states
|
220
|
+
@machine.event :ignite do
|
221
|
+
transition :from => :parked
|
222
|
+
end
|
223
|
+
assert_equal [@parked, @idling], @states.by_priority
|
224
|
+
end
|
225
|
+
|
226
|
+
def test_should_order_states_before_other_states
|
227
|
+
assert_equal [@idling, @parked], @states.by_priority
|
228
|
+
end
|
229
|
+
|
230
|
+
def test_should_order_state_before_callback_states
|
231
|
+
@machine.before_transition :from => :parked, :do => lambda {}
|
232
|
+
assert_equal [@idling, @parked], @states.by_priority
|
233
|
+
end
|
234
|
+
end
|
235
|
+
|
236
|
+
class StateCollectionWithEventTransitionsTest < Test::Unit::TestCase
|
237
|
+
def setup
|
238
|
+
@machine = StateMachine::Machine.new(Class.new)
|
239
|
+
@states = StateMachine::StateCollection.new(@machine)
|
240
|
+
|
241
|
+
@states << @parked = StateMachine::State.new(@machine, :parked)
|
242
|
+
@states << @idling = StateMachine::State.new(@machine, :idling)
|
243
|
+
@machine.states.concat(@states)
|
244
|
+
|
245
|
+
@machine.event :ignite do
|
246
|
+
transition :to => :idling
|
247
|
+
end
|
248
|
+
end
|
249
|
+
|
250
|
+
def test_should_order_states_after_initial_state
|
251
|
+
@parked.initial = true
|
252
|
+
assert_equal [@parked, @idling], @states.by_priority
|
253
|
+
end
|
254
|
+
|
255
|
+
def test_should_order_states_before_states_with_behaviors
|
256
|
+
@parked.context do
|
257
|
+
def speed
|
258
|
+
0
|
259
|
+
end
|
260
|
+
end
|
261
|
+
assert_equal [@idling, @parked], @states.by_priority
|
262
|
+
end
|
263
|
+
|
264
|
+
def test_should_order_states_before_other_states
|
265
|
+
assert_equal [@idling, @parked], @states.by_priority
|
266
|
+
end
|
267
|
+
|
268
|
+
def test_should_order_state_before_callback_states
|
269
|
+
@machine.before_transition :from => :parked, :do => lambda {}
|
270
|
+
assert_equal [@idling, @parked], @states.by_priority
|
271
|
+
end
|
272
|
+
end
|
273
|
+
|
274
|
+
class StateCollectionWithTransitionCallbacksTest < Test::Unit::TestCase
|
275
|
+
def setup
|
276
|
+
@machine = StateMachine::Machine.new(Class.new)
|
277
|
+
@states = StateMachine::StateCollection.new(@machine)
|
278
|
+
|
279
|
+
@states << @parked = StateMachine::State.new(@machine, :parked)
|
280
|
+
@states << @idling = StateMachine::State.new(@machine, :idling)
|
281
|
+
@machine.states.concat(@states)
|
282
|
+
|
283
|
+
@machine.before_transition :to => :idling, :do => lambda {}
|
284
|
+
end
|
285
|
+
|
286
|
+
def test_should_order_states_after_initial_state
|
287
|
+
@parked.initial = true
|
288
|
+
assert_equal [@parked, @idling], @states.by_priority
|
289
|
+
end
|
290
|
+
|
291
|
+
def test_should_order_states_after_transition_states
|
292
|
+
@machine.event :ignite do
|
293
|
+
transition :from => :parked
|
294
|
+
end
|
295
|
+
assert_equal [@parked, @idling], @states.by_priority
|
296
|
+
end
|
297
|
+
|
298
|
+
def test_should_order_states_after_states_with_behaviors
|
299
|
+
@parked.context do
|
300
|
+
def speed
|
301
|
+
0
|
302
|
+
end
|
303
|
+
end
|
304
|
+
assert_equal [@parked, @idling], @states.by_priority
|
305
|
+
end
|
306
|
+
|
307
|
+
def test_should_order_states_after_other_states
|
308
|
+
assert_equal [@parked, @idling], @states.by_priority
|
309
|
+
end
|
310
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/../test_helper')
|
2
|
+
|
3
|
+
class StateMachineByDefaultTest < Test::Unit::TestCase
|
4
|
+
def setup
|
5
|
+
@klass = Class.new
|
6
|
+
@machine = @klass.state_machine
|
7
|
+
end
|
8
|
+
|
9
|
+
def test_should_use_state_attribute
|
10
|
+
assert_equal :state, @machine.attribute
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
class StateMachineTest < Test::Unit::TestCase
|
15
|
+
def setup
|
16
|
+
@klass = Class.new
|
17
|
+
end
|
18
|
+
|
19
|
+
def test_should_allow_state_machines_on_any_class
|
20
|
+
assert @klass.respond_to?(:state_machine)
|
21
|
+
end
|
22
|
+
|
23
|
+
def test_should_evaluate_block_within_machine_context
|
24
|
+
responded = false
|
25
|
+
@klass.state_machine(:state) do
|
26
|
+
responded = respond_to?(:event)
|
27
|
+
end
|
28
|
+
|
29
|
+
assert responded
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,924 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/../test_helper')
|
2
|
+
|
3
|
+
class StateByDefaultTest < Test::Unit::TestCase
|
4
|
+
def setup
|
5
|
+
@machine = StateMachine::Machine.new(Class.new)
|
6
|
+
@machine.states << @state = StateMachine::State.new(@machine, :parked)
|
7
|
+
end
|
8
|
+
|
9
|
+
def test_should_have_a_machine
|
10
|
+
assert_equal @machine, @state.machine
|
11
|
+
end
|
12
|
+
|
13
|
+
def test_should_have_a_name
|
14
|
+
assert_equal :parked, @state.name
|
15
|
+
end
|
16
|
+
|
17
|
+
def test_should_have_a_qualified_name
|
18
|
+
assert_equal :parked, @state.name
|
19
|
+
end
|
20
|
+
|
21
|
+
def test_should_have_a_human_name
|
22
|
+
assert_equal 'parked', @state.human_name
|
23
|
+
end
|
24
|
+
|
25
|
+
def test_should_use_stringify_the_name_as_the_value
|
26
|
+
assert_equal 'parked', @state.value
|
27
|
+
end
|
28
|
+
|
29
|
+
def test_should_not_be_initial
|
30
|
+
assert !@state.initial
|
31
|
+
end
|
32
|
+
|
33
|
+
def test_should_not_have_a_matcher
|
34
|
+
assert_nil @state.matcher
|
35
|
+
end
|
36
|
+
|
37
|
+
def test_should_not_have_any_methods
|
38
|
+
expected = {}
|
39
|
+
assert_equal expected, @state.methods
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
class StateTest < Test::Unit::TestCase
|
44
|
+
def setup
|
45
|
+
@machine = StateMachine::Machine.new(Class.new)
|
46
|
+
@machine.states << @state = StateMachine::State.new(@machine, :parked)
|
47
|
+
end
|
48
|
+
|
49
|
+
def test_should_raise_exception_if_invalid_option_specified
|
50
|
+
exception = assert_raise(ArgumentError) {StateMachine::State.new(@machine, :parked, :invalid => true)}
|
51
|
+
assert_equal 'Invalid key(s): invalid', exception.message
|
52
|
+
end
|
53
|
+
|
54
|
+
def test_should_allow_changing_machine
|
55
|
+
new_machine = StateMachine::Machine.new(Class.new)
|
56
|
+
@state.machine = new_machine
|
57
|
+
assert_equal new_machine, @state.machine
|
58
|
+
end
|
59
|
+
|
60
|
+
def test_should_allow_changing_value
|
61
|
+
@state.value = 1
|
62
|
+
assert_equal 1, @state.value
|
63
|
+
end
|
64
|
+
|
65
|
+
def test_should_allow_changing_initial
|
66
|
+
@state.initial = true
|
67
|
+
assert @state.initial
|
68
|
+
end
|
69
|
+
|
70
|
+
def test_should_allow_changing_matcher
|
71
|
+
matcher = lambda {}
|
72
|
+
@state.matcher = matcher
|
73
|
+
assert_equal matcher, @state.matcher
|
74
|
+
end
|
75
|
+
|
76
|
+
def test_should_allow_changing_human_name
|
77
|
+
@state.human_name = 'stopped'
|
78
|
+
assert_equal 'stopped', @state.human_name
|
79
|
+
end
|
80
|
+
|
81
|
+
def test_should_use_pretty_inspect
|
82
|
+
assert_equal '#<StateMachine::State name=:parked value="parked" initial=false context=[]>', @state.inspect
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
class StateWithoutNameTest < Test::Unit::TestCase
|
87
|
+
def setup
|
88
|
+
@klass = Class.new
|
89
|
+
@machine = StateMachine::Machine.new(@klass)
|
90
|
+
@machine.states << @state = StateMachine::State.new(@machine, nil)
|
91
|
+
end
|
92
|
+
|
93
|
+
def test_should_have_a_nil_name
|
94
|
+
assert_nil @state.name
|
95
|
+
end
|
96
|
+
|
97
|
+
def test_should_have_a_nil_qualified_name
|
98
|
+
assert_nil @state.qualified_name
|
99
|
+
end
|
100
|
+
|
101
|
+
def test_should_have_an_empty_human_name
|
102
|
+
assert_equal 'nil', @state.human_name
|
103
|
+
end
|
104
|
+
|
105
|
+
def test_should_have_a_nil_value
|
106
|
+
assert_nil @state.value
|
107
|
+
end
|
108
|
+
|
109
|
+
def test_should_not_redefine_nil_predicate
|
110
|
+
object = @klass.new
|
111
|
+
assert !object.nil?
|
112
|
+
assert !object.respond_to?('?')
|
113
|
+
end
|
114
|
+
|
115
|
+
def test_should_have_a_description
|
116
|
+
assert_equal 'nil', @state.description
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
class StateWithNameTest < Test::Unit::TestCase
|
121
|
+
def setup
|
122
|
+
@klass = Class.new
|
123
|
+
@machine = StateMachine::Machine.new(@klass)
|
124
|
+
@machine.states << @state = StateMachine::State.new(@machine, :parked)
|
125
|
+
end
|
126
|
+
|
127
|
+
def test_should_have_a_name
|
128
|
+
assert_equal :parked, @state.name
|
129
|
+
end
|
130
|
+
|
131
|
+
def test_should_have_a_qualified_name
|
132
|
+
assert_equal :parked, @state.name
|
133
|
+
end
|
134
|
+
|
135
|
+
def test_should_have_a_human_name
|
136
|
+
assert_equal 'parked', @state.human_name
|
137
|
+
end
|
138
|
+
|
139
|
+
def test_should_use_stringify_the_name_as_the_value
|
140
|
+
assert_equal 'parked', @state.value
|
141
|
+
end
|
142
|
+
|
143
|
+
def test_should_match_stringified_name
|
144
|
+
assert @state.matches?('parked')
|
145
|
+
assert !@state.matches?('idling')
|
146
|
+
end
|
147
|
+
|
148
|
+
def test_should_not_include_value_in_description
|
149
|
+
assert_equal 'parked', @state.description
|
150
|
+
end
|
151
|
+
|
152
|
+
def test_should_define_predicate
|
153
|
+
assert @klass.new.respond_to?(:parked?)
|
154
|
+
end
|
155
|
+
end
|
156
|
+
|
157
|
+
class StateWithNilValueTest < Test::Unit::TestCase
|
158
|
+
def setup
|
159
|
+
@klass = Class.new
|
160
|
+
@machine = StateMachine::Machine.new(@klass)
|
161
|
+
@machine.states << @state = StateMachine::State.new(@machine, :parked, :value => nil)
|
162
|
+
end
|
163
|
+
|
164
|
+
def test_should_have_a_name
|
165
|
+
assert_equal :parked, @state.name
|
166
|
+
end
|
167
|
+
|
168
|
+
def test_should_have_a_nil_value
|
169
|
+
assert_nil @state.value
|
170
|
+
end
|
171
|
+
|
172
|
+
def test_should_match_nil_values
|
173
|
+
assert @state.matches?(nil)
|
174
|
+
end
|
175
|
+
|
176
|
+
def test_should_have_a_description
|
177
|
+
assert_equal 'parked (nil)', @state.description
|
178
|
+
end
|
179
|
+
|
180
|
+
def test_should_define_predicate
|
181
|
+
object = @klass.new
|
182
|
+
assert object.respond_to?(:parked?)
|
183
|
+
end
|
184
|
+
end
|
185
|
+
|
186
|
+
class StateWithSymbolicValueTest < Test::Unit::TestCase
|
187
|
+
def setup
|
188
|
+
@klass = Class.new
|
189
|
+
@machine = StateMachine::Machine.new(@klass)
|
190
|
+
@machine.states << @state = StateMachine::State.new(@machine, :parked, :value => :parked)
|
191
|
+
end
|
192
|
+
|
193
|
+
def test_should_use_custom_value
|
194
|
+
assert_equal :parked, @state.value
|
195
|
+
end
|
196
|
+
|
197
|
+
def test_should_not_include_value_in_description
|
198
|
+
assert_equal 'parked', @state.description
|
199
|
+
end
|
200
|
+
|
201
|
+
def test_should_match_symbolic_value
|
202
|
+
assert @state.matches?(:parked)
|
203
|
+
assert !@state.matches?('parked')
|
204
|
+
end
|
205
|
+
|
206
|
+
def test_should_define_predicate
|
207
|
+
object = @klass.new
|
208
|
+
assert object.respond_to?(:parked?)
|
209
|
+
end
|
210
|
+
end
|
211
|
+
|
212
|
+
class StateWithIntegerValueTest < Test::Unit::TestCase
|
213
|
+
def setup
|
214
|
+
@klass = Class.new
|
215
|
+
@machine = StateMachine::Machine.new(@klass)
|
216
|
+
@machine.states << @state = StateMachine::State.new(@machine, :parked, :value => 1)
|
217
|
+
end
|
218
|
+
|
219
|
+
def test_should_use_custom_value
|
220
|
+
assert_equal 1, @state.value
|
221
|
+
end
|
222
|
+
|
223
|
+
def test_should_include_value_in_description
|
224
|
+
assert_equal 'parked (1)', @state.description
|
225
|
+
end
|
226
|
+
|
227
|
+
def test_should_match_integer_value
|
228
|
+
assert @state.matches?(1)
|
229
|
+
assert !@state.matches?(2)
|
230
|
+
end
|
231
|
+
|
232
|
+
def test_should_define_predicate
|
233
|
+
object = @klass.new
|
234
|
+
assert object.respond_to?(:parked?)
|
235
|
+
end
|
236
|
+
end
|
237
|
+
|
238
|
+
class StateWithLambdaValueTest < Test::Unit::TestCase
|
239
|
+
def setup
|
240
|
+
@klass = Class.new
|
241
|
+
@args = nil
|
242
|
+
@machine = StateMachine::Machine.new(@klass)
|
243
|
+
@value = lambda {|*args| @args = args; :parked}
|
244
|
+
@machine.states << @state = StateMachine::State.new(@machine, :parked, :value => @value)
|
245
|
+
end
|
246
|
+
|
247
|
+
def test_should_use_evaluated_value_by_default
|
248
|
+
assert_equal :parked, @state.value
|
249
|
+
end
|
250
|
+
|
251
|
+
def test_should_allow_access_to_original_value
|
252
|
+
assert_equal @value, @state.value(false)
|
253
|
+
end
|
254
|
+
|
255
|
+
def test_should_include_masked_value_in_description
|
256
|
+
assert_equal 'parked (*)', @state.description
|
257
|
+
end
|
258
|
+
|
259
|
+
def test_should_not_pass_in_any_arguments
|
260
|
+
@state.value
|
261
|
+
assert_equal [], @args
|
262
|
+
end
|
263
|
+
|
264
|
+
def test_should_define_predicate
|
265
|
+
object = @klass.new
|
266
|
+
assert object.respond_to?(:parked?)
|
267
|
+
end
|
268
|
+
|
269
|
+
def test_should_match_evaluated_value
|
270
|
+
assert @state.matches?(:parked)
|
271
|
+
end
|
272
|
+
end
|
273
|
+
|
274
|
+
class StateWithCachedLambdaValueTest < Test::Unit::TestCase
|
275
|
+
def setup
|
276
|
+
@klass = Class.new
|
277
|
+
@machine = StateMachine::Machine.new(@klass)
|
278
|
+
@dynamic_value = lambda {'value'}
|
279
|
+
@machine.states << @state = StateMachine::State.new(@machine, :parked, :value => @dynamic_value, :cache => true)
|
280
|
+
end
|
281
|
+
|
282
|
+
def test_should_be_caching
|
283
|
+
assert @state.cache
|
284
|
+
end
|
285
|
+
|
286
|
+
def test_should_evaluate_value
|
287
|
+
assert_equal 'value', @state.value
|
288
|
+
end
|
289
|
+
|
290
|
+
def test_should_only_evaluate_value_once
|
291
|
+
value = @state.value
|
292
|
+
assert_same value, @state.value
|
293
|
+
end
|
294
|
+
|
295
|
+
def test_should_update_value_index_for_state_collection
|
296
|
+
@state.value
|
297
|
+
assert_equal @state, @machine.states['value', :value]
|
298
|
+
assert_nil @machine.states[@dynamic_value, :value]
|
299
|
+
end
|
300
|
+
end
|
301
|
+
|
302
|
+
class StateWithoutCachedLambdaValueTest < Test::Unit::TestCase
|
303
|
+
def setup
|
304
|
+
@klass = Class.new
|
305
|
+
@machine = StateMachine::Machine.new(@klass)
|
306
|
+
@dynamic_value = lambda {'value'}
|
307
|
+
@machine.states << @state = StateMachine::State.new(@machine, :parked, :value => @dynamic_value)
|
308
|
+
end
|
309
|
+
|
310
|
+
def test_should_not_be_caching
|
311
|
+
assert !@state.cache
|
312
|
+
end
|
313
|
+
|
314
|
+
def test_should_evaluate_value_each_time
|
315
|
+
value = @state.value
|
316
|
+
assert_not_same value, @state.value
|
317
|
+
end
|
318
|
+
|
319
|
+
def test_should_not_update_value_index_for_state_collection
|
320
|
+
@state.value
|
321
|
+
assert_nil @machine.states['value', :value]
|
322
|
+
assert_equal @state, @machine.states[@dynamic_value, :value]
|
323
|
+
end
|
324
|
+
end
|
325
|
+
|
326
|
+
class StateWithMatcherTest < Test::Unit::TestCase
|
327
|
+
def setup
|
328
|
+
@klass = Class.new
|
329
|
+
@args = nil
|
330
|
+
@machine = StateMachine::Machine.new(@klass)
|
331
|
+
@machine.states << @state = StateMachine::State.new(@machine, :parked, :if => lambda {|value| value == 1})
|
332
|
+
end
|
333
|
+
|
334
|
+
def test_should_not_match_actual_value
|
335
|
+
assert !@state.matches?('parked')
|
336
|
+
end
|
337
|
+
|
338
|
+
def test_should_match_evaluated_block
|
339
|
+
assert @state.matches?(1)
|
340
|
+
end
|
341
|
+
end
|
342
|
+
|
343
|
+
class StateWithHumanNameTest < Test::Unit::TestCase
|
344
|
+
def setup
|
345
|
+
@klass = Class.new
|
346
|
+
@machine = StateMachine::Machine.new(@klass)
|
347
|
+
@machine.states << @state = StateMachine::State.new(@machine, :parked, :human_name => 'stopped')
|
348
|
+
end
|
349
|
+
|
350
|
+
def test_should_use_custom_human_name
|
351
|
+
assert_equal 'stopped', @state.human_name
|
352
|
+
end
|
353
|
+
end
|
354
|
+
|
355
|
+
class StateWithDynamicHumanNameTest < Test::Unit::TestCase
|
356
|
+
def setup
|
357
|
+
@klass = Class.new
|
358
|
+
@machine = StateMachine::Machine.new(@klass)
|
359
|
+
@machine.states << @state = StateMachine::State.new(@machine, :parked, :human_name => lambda {|state, object| ['stopped', object]})
|
360
|
+
end
|
361
|
+
|
362
|
+
def test_should_use_custom_human_name
|
363
|
+
human_name, klass = @state.human_name
|
364
|
+
assert_equal 'stopped', human_name
|
365
|
+
assert_equal @klass, klass
|
366
|
+
end
|
367
|
+
|
368
|
+
def test_should_allow_custom_class_to_be_passed_through
|
369
|
+
human_name, klass = @state.human_name(1)
|
370
|
+
assert_equal 'stopped', human_name
|
371
|
+
assert_equal 1, klass
|
372
|
+
end
|
373
|
+
|
374
|
+
def test_should_not_cache_value
|
375
|
+
assert_not_same @state.human_name, @state.human_name
|
376
|
+
end
|
377
|
+
end
|
378
|
+
|
379
|
+
class StateInitialTest < Test::Unit::TestCase
|
380
|
+
def setup
|
381
|
+
@machine = StateMachine::Machine.new(Class.new)
|
382
|
+
@machine.states << @state = StateMachine::State.new(@machine, :parked, :initial => true)
|
383
|
+
end
|
384
|
+
|
385
|
+
def test_should_be_initial
|
386
|
+
assert @state.initial
|
387
|
+
assert @state.initial?
|
388
|
+
end
|
389
|
+
end
|
390
|
+
|
391
|
+
class StateNotInitialTest < Test::Unit::TestCase
|
392
|
+
def setup
|
393
|
+
@machine = StateMachine::Machine.new(Class.new)
|
394
|
+
@machine.states << @state = StateMachine::State.new(@machine, :parked, :initial => false)
|
395
|
+
end
|
396
|
+
|
397
|
+
def test_should_not_be_initial
|
398
|
+
assert !@state.initial
|
399
|
+
assert !@state.initial?
|
400
|
+
end
|
401
|
+
end
|
402
|
+
|
403
|
+
class StateFinalTest < Test::Unit::TestCase
|
404
|
+
def setup
|
405
|
+
@machine = StateMachine::Machine.new(Class.new)
|
406
|
+
@machine.states << @state = StateMachine::State.new(@machine, :parked)
|
407
|
+
end
|
408
|
+
|
409
|
+
def test_should_be_final_without_input_transitions
|
410
|
+
assert @state.final?
|
411
|
+
end
|
412
|
+
|
413
|
+
def test_should_be_final_with_input_transitions
|
414
|
+
@machine.event :park do
|
415
|
+
transition :idling => :parked
|
416
|
+
end
|
417
|
+
|
418
|
+
assert @state.final?
|
419
|
+
end
|
420
|
+
|
421
|
+
def test_should_be_final_with_loopback
|
422
|
+
@machine.event :ignite do
|
423
|
+
transition :parked => same
|
424
|
+
end
|
425
|
+
|
426
|
+
assert @state.final?
|
427
|
+
end
|
428
|
+
end
|
429
|
+
|
430
|
+
class StateNotFinalTest < Test::Unit::TestCase
|
431
|
+
def setup
|
432
|
+
@machine = StateMachine::Machine.new(Class.new)
|
433
|
+
@machine.states << @state = StateMachine::State.new(@machine, :parked)
|
434
|
+
end
|
435
|
+
|
436
|
+
def test_should_not_be_final_with_outgoing_whitelist_transitions
|
437
|
+
@machine.event :ignite do
|
438
|
+
transition :parked => :idling
|
439
|
+
end
|
440
|
+
|
441
|
+
assert !@state.final?
|
442
|
+
end
|
443
|
+
|
444
|
+
def test_should_not_be_final_with_outgoing_all_transitions
|
445
|
+
@machine.event :ignite do
|
446
|
+
transition all => :idling
|
447
|
+
end
|
448
|
+
|
449
|
+
assert !@state.final?
|
450
|
+
end
|
451
|
+
|
452
|
+
def test_should_not_be_final_with_outgoing_blacklist_transitions
|
453
|
+
@machine.event :ignite do
|
454
|
+
transition all - :first_gear => :idling
|
455
|
+
end
|
456
|
+
|
457
|
+
assert !@state.final?
|
458
|
+
end
|
459
|
+
end
|
460
|
+
|
461
|
+
class StateWithConflictingHelpersBeforeDefinitionTest < Test::Unit::TestCase
|
462
|
+
def setup
|
463
|
+
require 'stringio'
|
464
|
+
@original_stderr, $stderr = $stderr, StringIO.new
|
465
|
+
|
466
|
+
@superclass = Class.new do
|
467
|
+
def parked?
|
468
|
+
0
|
469
|
+
end
|
470
|
+
end
|
471
|
+
@klass = Class.new(@superclass)
|
472
|
+
@machine = StateMachine::Machine.new(@klass)
|
473
|
+
@machine.state :parked
|
474
|
+
@object = @klass.new
|
475
|
+
end
|
476
|
+
|
477
|
+
def test_should_not_override_state_predicate
|
478
|
+
assert_equal 0, @object.parked?
|
479
|
+
end
|
480
|
+
|
481
|
+
def test_should_output_warning
|
482
|
+
assert_equal "Instance method \"parked?\" is already defined in #{@superclass.to_s}, use generic helper instead.\n", $stderr.string
|
483
|
+
end
|
484
|
+
|
485
|
+
def teardown
|
486
|
+
$stderr = @original_stderr
|
487
|
+
end
|
488
|
+
end
|
489
|
+
|
490
|
+
class StateWithConflictingHelpersAfterDefinitionTest < Test::Unit::TestCase
|
491
|
+
def setup
|
492
|
+
require 'stringio'
|
493
|
+
@original_stderr, $stderr = $stderr, StringIO.new
|
494
|
+
|
495
|
+
@klass = Class.new do
|
496
|
+
def parked?
|
497
|
+
0
|
498
|
+
end
|
499
|
+
end
|
500
|
+
@machine = StateMachine::Machine.new(@klass)
|
501
|
+
@machine.state :parked
|
502
|
+
@object = @klass.new
|
503
|
+
end
|
504
|
+
|
505
|
+
def test_should_not_override_state_predicate
|
506
|
+
assert_equal 0, @object.parked?
|
507
|
+
end
|
508
|
+
|
509
|
+
def test_should_still_allow_super_chaining
|
510
|
+
@klass.class_eval do
|
511
|
+
def parked?
|
512
|
+
super
|
513
|
+
end
|
514
|
+
end
|
515
|
+
|
516
|
+
assert_equal false, @object.parked?
|
517
|
+
end
|
518
|
+
|
519
|
+
def test_should_not_output_warning
|
520
|
+
assert_equal '', $stderr.string
|
521
|
+
end
|
522
|
+
|
523
|
+
def teardown
|
524
|
+
$stderr = @original_stderr
|
525
|
+
end
|
526
|
+
end
|
527
|
+
|
528
|
+
class StateWithConflictingMachineTest < Test::Unit::TestCase
|
529
|
+
def setup
|
530
|
+
require 'stringio'
|
531
|
+
@original_stderr, $stderr = $stderr, StringIO.new
|
532
|
+
|
533
|
+
@klass = Class.new
|
534
|
+
@state_machine = StateMachine::Machine.new(@klass, :state)
|
535
|
+
@state_machine.states << @state = StateMachine::State.new(@state_machine, :parked)
|
536
|
+
end
|
537
|
+
|
538
|
+
def test_should_output_warning_if_using_different_attribute
|
539
|
+
@status_machine = StateMachine::Machine.new(@klass, :status)
|
540
|
+
@status_machine.states << @state = StateMachine::State.new(@status_machine, :parked)
|
541
|
+
|
542
|
+
assert_equal "State :parked for :status is already defined in :state\n", $stderr.string
|
543
|
+
end
|
544
|
+
|
545
|
+
def test_should_not_output_warning_if_using_same_attribute
|
546
|
+
@status_machine = StateMachine::Machine.new(@klass, :status, :attribute => :state)
|
547
|
+
@status_machine.states << @state = StateMachine::State.new(@status_machine, :parked)
|
548
|
+
|
549
|
+
assert_equal '', $stderr.string
|
550
|
+
end
|
551
|
+
|
552
|
+
def test_should_not_output_warning_if_using_different_namespace
|
553
|
+
@status_machine = StateMachine::Machine.new(@klass, :status, :namespace => 'alarm')
|
554
|
+
@status_machine.states << @state = StateMachine::State.new(@status_machine, :parked)
|
555
|
+
|
556
|
+
assert_equal '', $stderr.string
|
557
|
+
end
|
558
|
+
|
559
|
+
def teardown
|
560
|
+
$stderr = @original_stderr
|
561
|
+
end
|
562
|
+
end
|
563
|
+
|
564
|
+
class StateWithNamespaceTest < Test::Unit::TestCase
|
565
|
+
def setup
|
566
|
+
@klass = Class.new
|
567
|
+
@machine = StateMachine::Machine.new(@klass, :namespace => 'alarm')
|
568
|
+
@machine.states << @state = StateMachine::State.new(@machine, :active)
|
569
|
+
@object = @klass.new
|
570
|
+
end
|
571
|
+
|
572
|
+
def test_should_have_a_name
|
573
|
+
assert_equal :active, @state.name
|
574
|
+
end
|
575
|
+
|
576
|
+
def test_should_have_a_qualified_name
|
577
|
+
assert_equal :alarm_active, @state.qualified_name
|
578
|
+
end
|
579
|
+
|
580
|
+
def test_should_namespace_predicate
|
581
|
+
assert @object.respond_to?(:alarm_active?)
|
582
|
+
end
|
583
|
+
end
|
584
|
+
|
585
|
+
class StateAfterBeingCopiedTest < Test::Unit::TestCase
|
586
|
+
def setup
|
587
|
+
@machine = StateMachine::Machine.new(Class.new)
|
588
|
+
@machine.states << @state = StateMachine::State.new(@machine, :parked)
|
589
|
+
@copied_state = @state.dup
|
590
|
+
end
|
591
|
+
|
592
|
+
def test_should_not_have_the_same_collection_of_methods
|
593
|
+
assert_not_same @state.methods, @copied_state.methods
|
594
|
+
end
|
595
|
+
end
|
596
|
+
|
597
|
+
class StateWithContextTest < Test::Unit::TestCase
|
598
|
+
def setup
|
599
|
+
@klass = Class.new
|
600
|
+
@machine = StateMachine::Machine.new(@klass)
|
601
|
+
@ancestors = @klass.ancestors
|
602
|
+
@machine.states << @state = StateMachine::State.new(@machine, :idling)
|
603
|
+
|
604
|
+
speed_method = nil
|
605
|
+
rpm_method = nil
|
606
|
+
@state.context do
|
607
|
+
def speed
|
608
|
+
0
|
609
|
+
end
|
610
|
+
speed_method = instance_method(:speed)
|
611
|
+
|
612
|
+
def rpm
|
613
|
+
1000
|
614
|
+
end
|
615
|
+
rpm_method = instance_method(:rpm)
|
616
|
+
end
|
617
|
+
|
618
|
+
@speed_method = speed_method
|
619
|
+
@rpm_method = rpm_method
|
620
|
+
end
|
621
|
+
|
622
|
+
def test_should_include_new_module_in_owner_class
|
623
|
+
assert_not_equal @ancestors, @klass.ancestors
|
624
|
+
assert_equal 1, @klass.ancestors.size - @ancestors.size
|
625
|
+
end
|
626
|
+
|
627
|
+
def test_should_define_each_context_method_in_owner_class
|
628
|
+
%w(speed rpm).each {|method| assert @klass.method_defined?(method)}
|
629
|
+
end
|
630
|
+
|
631
|
+
def test_should_not_use_context_methods_as_owner_class_methods
|
632
|
+
assert_not_equal @speed_method, @klass.instance_method(:speed)
|
633
|
+
assert_not_equal @rpm_method, @klass.instance_method(:rpm)
|
634
|
+
end
|
635
|
+
|
636
|
+
def test_should_include_context_methods_in_state_methods
|
637
|
+
assert_equal @speed_method, @state.methods[:speed]
|
638
|
+
assert_equal @rpm_method, @state.methods[:rpm]
|
639
|
+
end
|
640
|
+
end
|
641
|
+
|
642
|
+
class StateWithMultipleContextsTest < Test::Unit::TestCase
|
643
|
+
def setup
|
644
|
+
@klass = Class.new
|
645
|
+
@machine = StateMachine::Machine.new(@klass)
|
646
|
+
@ancestors = @klass.ancestors
|
647
|
+
@machine.states << @state = StateMachine::State.new(@machine, :idling)
|
648
|
+
|
649
|
+
speed_method = nil
|
650
|
+
@state.context do
|
651
|
+
def speed
|
652
|
+
0
|
653
|
+
end
|
654
|
+
|
655
|
+
speed_method = instance_method(:speed)
|
656
|
+
end
|
657
|
+
@speed_method = speed_method
|
658
|
+
|
659
|
+
rpm_method = nil
|
660
|
+
@state.context do
|
661
|
+
def rpm
|
662
|
+
1000
|
663
|
+
end
|
664
|
+
|
665
|
+
rpm_method = instance_method(:rpm)
|
666
|
+
end
|
667
|
+
@rpm_method = rpm_method
|
668
|
+
end
|
669
|
+
|
670
|
+
def test_should_include_new_module_in_owner_class
|
671
|
+
assert_not_equal @ancestors, @klass.ancestors
|
672
|
+
assert_equal 2, @klass.ancestors.size - @ancestors.size
|
673
|
+
end
|
674
|
+
|
675
|
+
def test_should_define_each_context_method_in_owner_class
|
676
|
+
%w(speed rpm).each {|method| assert @klass.method_defined?(method)}
|
677
|
+
end
|
678
|
+
|
679
|
+
def test_should_not_use_context_methods_as_owner_class_methods
|
680
|
+
assert_not_equal @speed_method, @klass.instance_method(:speed)
|
681
|
+
assert_not_equal @rpm_method, @klass.instance_method(:rpm)
|
682
|
+
end
|
683
|
+
|
684
|
+
def test_should_include_context_methods_in_state_methods
|
685
|
+
assert_equal @speed_method, @state.methods[:speed]
|
686
|
+
assert_equal @rpm_method, @state.methods[:rpm]
|
687
|
+
end
|
688
|
+
end
|
689
|
+
|
690
|
+
class StateWithExistingContextMethodTest < Test::Unit::TestCase
|
691
|
+
def setup
|
692
|
+
@klass = Class.new do
|
693
|
+
def speed
|
694
|
+
60
|
695
|
+
end
|
696
|
+
end
|
697
|
+
@original_speed_method = @klass.instance_method(:speed)
|
698
|
+
|
699
|
+
@machine = StateMachine::Machine.new(@klass)
|
700
|
+
@machine.states << @state = StateMachine::State.new(@machine, :idling)
|
701
|
+
@state.context do
|
702
|
+
def speed
|
703
|
+
0
|
704
|
+
end
|
705
|
+
end
|
706
|
+
end
|
707
|
+
|
708
|
+
def test_should_not_override_method
|
709
|
+
assert_equal @original_speed_method, @klass.instance_method(:speed)
|
710
|
+
end
|
711
|
+
end
|
712
|
+
|
713
|
+
class StateWithRedefinedContextMethodTest < Test::Unit::TestCase
|
714
|
+
def setup
|
715
|
+
@klass = Class.new
|
716
|
+
@machine = StateMachine::Machine.new(@klass)
|
717
|
+
@machine.states << @state = StateMachine::State.new(@machine, 'on')
|
718
|
+
|
719
|
+
old_speed_method = nil
|
720
|
+
@state.context do
|
721
|
+
def speed
|
722
|
+
0
|
723
|
+
end
|
724
|
+
old_speed_method = instance_method(:speed)
|
725
|
+
end
|
726
|
+
@old_speed_method = old_speed_method
|
727
|
+
|
728
|
+
current_speed_method = nil
|
729
|
+
@state.context do
|
730
|
+
def speed
|
731
|
+
'green'
|
732
|
+
end
|
733
|
+
current_speed_method = instance_method(:speed)
|
734
|
+
end
|
735
|
+
@current_speed_method = current_speed_method
|
736
|
+
end
|
737
|
+
|
738
|
+
def test_should_track_latest_defined_method
|
739
|
+
assert_equal @current_speed_method, @state.methods[:speed]
|
740
|
+
end
|
741
|
+
end
|
742
|
+
|
743
|
+
class StateWithInvalidMethodCallTest < Test::Unit::TestCase
|
744
|
+
def setup
|
745
|
+
@klass = Class.new
|
746
|
+
@machine = StateMachine::Machine.new(@klass)
|
747
|
+
@ancestors = @klass.ancestors
|
748
|
+
@machine.states << @state = StateMachine::State.new(@machine, :idling)
|
749
|
+
@state.context do
|
750
|
+
def speed
|
751
|
+
0
|
752
|
+
end
|
753
|
+
end
|
754
|
+
|
755
|
+
@object = @klass.new
|
756
|
+
end
|
757
|
+
|
758
|
+
def test_should_call_method_missing_arg
|
759
|
+
assert_equal 1, @state.call(@object, :invalid, lambda {1})
|
760
|
+
end
|
761
|
+
end
|
762
|
+
|
763
|
+
class StateWithValidMethodCallTest < Test::Unit::TestCase
|
764
|
+
def setup
|
765
|
+
@klass = Class.new
|
766
|
+
@machine = StateMachine::Machine.new(@klass)
|
767
|
+
@ancestors = @klass.ancestors
|
768
|
+
@machine.states << @state = StateMachine::State.new(@machine, :idling)
|
769
|
+
@state.context do
|
770
|
+
def speed(arg = nil)
|
771
|
+
block_given? ? [arg, yield] : arg
|
772
|
+
end
|
773
|
+
end
|
774
|
+
|
775
|
+
@object = @klass.new
|
776
|
+
end
|
777
|
+
|
778
|
+
def test_should_not_raise_an_exception
|
779
|
+
assert_nothing_raised { @state.call(@object, :speed, lambda {raise}) }
|
780
|
+
end
|
781
|
+
|
782
|
+
def test_should_pass_arguments_through
|
783
|
+
assert_equal 1, @state.call(@object, :speed, lambda {}, 1)
|
784
|
+
end
|
785
|
+
|
786
|
+
def test_should_pass_blocks_through
|
787
|
+
assert_equal [nil, 1], @state.call(@object, :speed) {1}
|
788
|
+
end
|
789
|
+
|
790
|
+
def test_should_pass_both_arguments_and_blocks_through
|
791
|
+
assert_equal [1, 2], @state.call(@object, :speed, lambda {}, 1) {2}
|
792
|
+
end
|
793
|
+
end
|
794
|
+
|
795
|
+
begin
|
796
|
+
# Load library
|
797
|
+
require 'rubygems'
|
798
|
+
gem 'ruby-graphviz', '>=0.9.0'
|
799
|
+
require 'graphviz'
|
800
|
+
|
801
|
+
class StateDrawingTest < Test::Unit::TestCase
|
802
|
+
def setup
|
803
|
+
@machine = StateMachine::Machine.new(Class.new)
|
804
|
+
@machine.states << @state = StateMachine::State.new(@machine, :parked, :value => 1)
|
805
|
+
@machine.event :ignite do
|
806
|
+
transition :parked => :idling
|
807
|
+
end
|
808
|
+
|
809
|
+
graph = GraphViz.new('G')
|
810
|
+
@node = @state.draw(graph)
|
811
|
+
end
|
812
|
+
|
813
|
+
def test_should_use_ellipse_shape
|
814
|
+
assert_equal 'ellipse', @node['shape'].to_s.gsub('"', '')
|
815
|
+
end
|
816
|
+
|
817
|
+
def test_should_set_width_to_one
|
818
|
+
assert_equal '1', @node['width'].to_s.gsub('"', '')
|
819
|
+
end
|
820
|
+
|
821
|
+
def test_should_set_height_to_one
|
822
|
+
assert_equal '1', @node['height'].to_s.gsub('"', '')
|
823
|
+
end
|
824
|
+
|
825
|
+
def test_should_use_stringified_name_as_name
|
826
|
+
assert_equal 'parked', Gem::Version.new(Constants::RGV_VERSION) <= Gem::Version.new('0.9.11') ? @node.name : @node.id
|
827
|
+
end
|
828
|
+
|
829
|
+
def test_should_use_description_as_label
|
830
|
+
assert_equal 'parked (1)', @node['label'].to_s.gsub('"', '')
|
831
|
+
end
|
832
|
+
end
|
833
|
+
|
834
|
+
class StateDrawingInitialTest < Test::Unit::TestCase
|
835
|
+
def setup
|
836
|
+
@machine = StateMachine::Machine.new(Class.new)
|
837
|
+
@machine.states << @state = StateMachine::State.new(@machine, :parked, :initial => true)
|
838
|
+
@machine.event :ignite do
|
839
|
+
transition :parked => :idling
|
840
|
+
end
|
841
|
+
|
842
|
+
@graph = GraphViz.new('G')
|
843
|
+
@node = @state.draw(@graph)
|
844
|
+
end
|
845
|
+
|
846
|
+
def test_should_use_ellipse_as_shape
|
847
|
+
assert_equal 'ellipse', @node['shape'].to_s.gsub('"', '')
|
848
|
+
end
|
849
|
+
|
850
|
+
def test_should_draw_edge_between_point_and_state
|
851
|
+
assert_equal 2, @graph.node_count
|
852
|
+
assert_equal 1, @graph.edge_count
|
853
|
+
end
|
854
|
+
end
|
855
|
+
|
856
|
+
class StateDrawingNilNameTest < Test::Unit::TestCase
|
857
|
+
def setup
|
858
|
+
@machine = StateMachine::Machine.new(Class.new)
|
859
|
+
@machine.states << @state = StateMachine::State.new(@machine, nil)
|
860
|
+
|
861
|
+
graph = GraphViz.new('G')
|
862
|
+
@node = @state.draw(graph)
|
863
|
+
end
|
864
|
+
|
865
|
+
def test_should_use_stringified_nil_as_name
|
866
|
+
assert_equal 'nil', Gem::Version.new(Constants::RGV_VERSION) <= Gem::Version.new('0.9.11') ? @node.name : @node.id
|
867
|
+
end
|
868
|
+
|
869
|
+
def test_should_use_description_as_label
|
870
|
+
assert_equal 'nil', @node['label'].to_s.gsub('"', '')
|
871
|
+
end
|
872
|
+
end
|
873
|
+
|
874
|
+
class StateDrawingLambdaValueTest < Test::Unit::TestCase
|
875
|
+
def setup
|
876
|
+
@machine = StateMachine::Machine.new(Class.new)
|
877
|
+
@machine.states << @state = StateMachine::State.new(@machine, :parked, :value => lambda {})
|
878
|
+
|
879
|
+
graph = GraphViz.new('G')
|
880
|
+
@node = @state.draw(graph)
|
881
|
+
end
|
882
|
+
|
883
|
+
def test_should_use_stringified_name_as_name
|
884
|
+
assert_equal 'parked', Gem::Version.new(Constants::RGV_VERSION) <= Gem::Version.new('0.9.11') ? @node.name : @node.id
|
885
|
+
end
|
886
|
+
|
887
|
+
def test_should_use_description_as_label
|
888
|
+
assert_equal 'parked (*)', @node['label'].to_s.gsub('"', '')
|
889
|
+
end
|
890
|
+
end
|
891
|
+
|
892
|
+
class StateDrawingNonFinalTest < Test::Unit::TestCase
|
893
|
+
def setup
|
894
|
+
@machine = StateMachine::Machine.new(Class.new)
|
895
|
+
@machine.states << @state = StateMachine::State.new(@machine, :parked)
|
896
|
+
@machine.event :ignite do
|
897
|
+
transition :parked => :idling
|
898
|
+
end
|
899
|
+
|
900
|
+
graph = GraphViz.new('G')
|
901
|
+
@node = @state.draw(graph)
|
902
|
+
end
|
903
|
+
|
904
|
+
def test_should_use_ellipse_as_shape
|
905
|
+
assert_equal 'ellipse', @node['shape'].to_s.gsub('"', '')
|
906
|
+
end
|
907
|
+
end
|
908
|
+
|
909
|
+
class StateDrawingFinalTest < Test::Unit::TestCase
|
910
|
+
def setup
|
911
|
+
@machine = StateMachine::Machine.new(Class.new)
|
912
|
+
@machine.states << @state = StateMachine::State.new(@machine, :parked)
|
913
|
+
|
914
|
+
graph = GraphViz.new('G')
|
915
|
+
@node = @state.draw(graph)
|
916
|
+
end
|
917
|
+
|
918
|
+
def test_should_use_doublecircle_as_shape
|
919
|
+
assert_equal 'doublecircle', @node['shape'].to_s.gsub('"', '')
|
920
|
+
end
|
921
|
+
end
|
922
|
+
rescue LoadError
|
923
|
+
$stderr.puts 'Skipping GraphViz StateMachine::State tests. `gem install ruby-graphviz` >= v0.9.0 and try again.'
|
924
|
+
end
|