verborghs-state_machine 0.9.4
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 +360 -0
- data/LICENSE +20 -0
- data/README.rdoc +635 -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/assertions.rb +36 -0
- data/lib/state_machine/callback.rb +241 -0
- data/lib/state_machine/condition_proxy.rb +106 -0
- data/lib/state_machine/eval_helpers.rb +83 -0
- data/lib/state_machine/event.rb +267 -0
- data/lib/state_machine/event_collection.rb +122 -0
- data/lib/state_machine/extensions.rb +149 -0
- data/lib/state_machine/guard.rb +230 -0
- data/lib/state_machine/initializers/merb.rb +1 -0
- data/lib/state_machine/initializers/rails.rb +5 -0
- data/lib/state_machine/initializers.rb +4 -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.rb +445 -0
- data/lib/state_machine/integrations/active_record/locale.rb +20 -0
- data/lib/state_machine/integrations/active_record.rb +522 -0
- data/lib/state_machine/integrations/data_mapper/observer.rb +175 -0
- data/lib/state_machine/integrations/data_mapper.rb +379 -0
- data/lib/state_machine/integrations/mongo_mapper.rb +309 -0
- data/lib/state_machine/integrations/sequel.rb +356 -0
- data/lib/state_machine/integrations.rb +83 -0
- data/lib/state_machine/machine.rb +1645 -0
- data/lib/state_machine/machine_collection.rb +64 -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 +152 -0
- data/lib/state_machine/state.rb +260 -0
- data/lib/state_machine/state_collection.rb +112 -0
- data/lib/state_machine/transition.rb +399 -0
- data/lib/state_machine/transition_collection.rb +244 -0
- data/lib/state_machine.rb +421 -0
- data/lib/tasks/state_machine.rake +1 -0
- data/lib/tasks/state_machine.rb +27 -0
- data/test/files/en.yml +9 -0
- data/test/files/switch.rb +11 -0
- data/test/functional/state_machine_test.rb +980 -0
- data/test/test_helper.rb +4 -0
- data/test/unit/assertions_test.rb +40 -0
- data/test/unit/callback_test.rb +728 -0
- data/test/unit/condition_proxy_test.rb +328 -0
- data/test/unit/eval_helpers_test.rb +222 -0
- data/test/unit/event_collection_test.rb +324 -0
- data/test/unit/event_test.rb +795 -0
- data/test/unit/guard_test.rb +909 -0
- data/test/unit/integrations/active_model_test.rb +956 -0
- data/test/unit/integrations/active_record_test.rb +1918 -0
- data/test/unit/integrations/data_mapper_test.rb +1814 -0
- data/test/unit/integrations/mongo_mapper_test.rb +1382 -0
- data/test/unit/integrations/sequel_test.rb +1492 -0
- data/test/unit/integrations_test.rb +50 -0
- data/test/unit/invalid_event_test.rb +7 -0
- data/test/unit/invalid_transition_test.rb +7 -0
- data/test/unit/machine_collection_test.rb +565 -0
- data/test/unit/machine_test.rb +2349 -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 +207 -0
- data/test/unit/state_collection_test.rb +280 -0
- data/test/unit/state_machine_test.rb +31 -0
- data/test/unit/state_test.rb +848 -0
- data/test/unit/transition_collection_test.rb +2098 -0
- data/test/unit/transition_test.rb +1384 -0
- metadata +176 -0
@@ -0,0 +1,50 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/../test_helper')
|
2
|
+
|
3
|
+
class IntegrationMatcherTest < Test::Unit::TestCase
|
4
|
+
def setup
|
5
|
+
@klass = Class.new
|
6
|
+
end
|
7
|
+
|
8
|
+
def test_should_return_nil_if_no_match_found
|
9
|
+
assert_nil StateMachine::Integrations.match(@klass)
|
10
|
+
end
|
11
|
+
|
12
|
+
def test_should_return_integration_class_if_match_found
|
13
|
+
integration = Module.new do
|
14
|
+
def self.matches?(klass)
|
15
|
+
true
|
16
|
+
end
|
17
|
+
end
|
18
|
+
StateMachine::Integrations.const_set('Custom', integration)
|
19
|
+
|
20
|
+
assert_equal integration, StateMachine::Integrations.match(@klass)
|
21
|
+
ensure
|
22
|
+
StateMachine::Integrations.send(:remove_const, 'Custom')
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
class IntegrationFinderTest < Test::Unit::TestCase
|
27
|
+
def test_should_find_active_model
|
28
|
+
assert_equal StateMachine::Integrations::ActiveModel, StateMachine::Integrations.find(:active_model)
|
29
|
+
end
|
30
|
+
|
31
|
+
def test_should_find_active_record
|
32
|
+
assert_equal StateMachine::Integrations::ActiveRecord, StateMachine::Integrations.find(:active_record)
|
33
|
+
end
|
34
|
+
|
35
|
+
def test_should_find_data_mapper
|
36
|
+
assert_equal StateMachine::Integrations::DataMapper, StateMachine::Integrations.find(:data_mapper)
|
37
|
+
end
|
38
|
+
|
39
|
+
def test_should_find_mongo_mapper
|
40
|
+
assert_equal StateMachine::Integrations::MongoMapper, StateMachine::Integrations.find(:mongo_mapper)
|
41
|
+
end
|
42
|
+
|
43
|
+
def test_should_find_sequel
|
44
|
+
assert_equal StateMachine::Integrations::Sequel, StateMachine::Integrations.find(:sequel)
|
45
|
+
end
|
46
|
+
|
47
|
+
def test_should_raise_an_exception_if_invalid
|
48
|
+
assert_raise(NameError) { StateMachine::Integrations.find(:invalid) }
|
49
|
+
end
|
50
|
+
end
|
@@ -0,0 +1,565 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/../test_helper')
|
2
|
+
|
3
|
+
class MachineCollectionByDefaultTest < Test::Unit::TestCase
|
4
|
+
def setup
|
5
|
+
@machines = StateMachine::MachineCollection.new
|
6
|
+
end
|
7
|
+
|
8
|
+
def test_should_not_have_any_machines
|
9
|
+
assert @machines.empty?
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
class MachineCollectionStateInitializationTest < Test::Unit::TestCase
|
14
|
+
def setup
|
15
|
+
@machines = StateMachine::MachineCollection.new
|
16
|
+
|
17
|
+
@klass = Class.new
|
18
|
+
|
19
|
+
@machines[:state] = StateMachine::Machine.new(@klass, :state, :initial => :parked)
|
20
|
+
@machines[:alarm_state] = StateMachine::Machine.new(@klass, :alarm_state, :initial => lambda {|object| :active})
|
21
|
+
@machines[:alarm_state].state :active, :value => lambda {'active'}
|
22
|
+
|
23
|
+
# Prevent the auto-initialization hook from firing
|
24
|
+
@klass.class_eval do
|
25
|
+
def initialize
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
@object = @klass.new
|
30
|
+
@object.state = nil
|
31
|
+
@object.alarm_state = nil
|
32
|
+
end
|
33
|
+
|
34
|
+
def test_should_set_states_if_nil
|
35
|
+
@machines.initialize_states(@object)
|
36
|
+
|
37
|
+
assert_equal 'parked', @object.state
|
38
|
+
assert_equal 'active', @object.alarm_state
|
39
|
+
end
|
40
|
+
|
41
|
+
def test_should_set_states_if_empty
|
42
|
+
@object.state = ''
|
43
|
+
@object.alarm_state = ''
|
44
|
+
@machines.initialize_states(@object)
|
45
|
+
|
46
|
+
assert_equal 'parked', @object.state
|
47
|
+
assert_equal 'active', @object.alarm_state
|
48
|
+
end
|
49
|
+
|
50
|
+
def test_should_not_set_states_if_not_empty
|
51
|
+
@object.state = 'idling'
|
52
|
+
@object.alarm_state = 'off'
|
53
|
+
@machines.initialize_states(@object)
|
54
|
+
|
55
|
+
assert_equal 'idling', @object.state
|
56
|
+
assert_equal 'off', @object.alarm_state
|
57
|
+
end
|
58
|
+
|
59
|
+
def test_should_only_initialize_static_states_if_dynamic_disabled
|
60
|
+
@machines.initialize_states(@object, :dynamic => false)
|
61
|
+
|
62
|
+
assert_equal 'parked', @object.state
|
63
|
+
assert_nil @object.alarm_state
|
64
|
+
end
|
65
|
+
|
66
|
+
def test_should_only_initialize_dynamic_states_if_dynamic_enabled
|
67
|
+
@machines.initialize_states(@object, :dynamic => true)
|
68
|
+
|
69
|
+
assert_nil @object.state
|
70
|
+
assert_equal 'active', @object.alarm_state
|
71
|
+
end
|
72
|
+
|
73
|
+
def test_should_not_set_states_if_ignored
|
74
|
+
@machines.initialize_states(@object, :ignore => [:state, :alarm_state])
|
75
|
+
|
76
|
+
assert_nil @object.state
|
77
|
+
assert_nil @object.alarm_state
|
78
|
+
end
|
79
|
+
|
80
|
+
def test_should_set_states_if_not_ignored_and_nil
|
81
|
+
@machines.initialize_states(@object, :ignore => [])
|
82
|
+
|
83
|
+
assert_equal 'parked', @object.state
|
84
|
+
assert_equal 'active', @object.alarm_state
|
85
|
+
end
|
86
|
+
|
87
|
+
def test_should_set_states_if_not_ignored_and_empty
|
88
|
+
@object.state = ''
|
89
|
+
@object.alarm_state = ''
|
90
|
+
@machines.initialize_states(@object, :ignore => [])
|
91
|
+
|
92
|
+
assert_equal 'parked', @object.state
|
93
|
+
assert_equal 'active', @object.alarm_state
|
94
|
+
end
|
95
|
+
|
96
|
+
def test_should_set_states_if_not_ignored_and_not_empty
|
97
|
+
@object.state = 'idling'
|
98
|
+
@object.alarm_state = 'inactive'
|
99
|
+
@machines.initialize_states(@object, :ignore => [])
|
100
|
+
|
101
|
+
assert_equal 'parked', @object.state
|
102
|
+
assert_equal 'active', @object.alarm_state
|
103
|
+
end
|
104
|
+
|
105
|
+
def test_should_not_modify_ignore_option
|
106
|
+
ignore = ['state', 'alarm_state']
|
107
|
+
@machines.initialize_states(@object, :ignore => ignore)
|
108
|
+
|
109
|
+
assert_nil @object.state
|
110
|
+
assert_nil @object.alarm_state
|
111
|
+
assert_equal ['state', 'alarm_state'], ignore
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
class MachineCollectionFireTest < Test::Unit::TestCase
|
116
|
+
def setup
|
117
|
+
@machines = StateMachine::MachineCollection.new
|
118
|
+
|
119
|
+
@klass = Class.new do
|
120
|
+
attr_reader :saved
|
121
|
+
|
122
|
+
def save
|
123
|
+
@saved = true
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
# First machine
|
128
|
+
@machines[:state] = @state = StateMachine::Machine.new(@klass, :state, :initial => :parked, :action => :save)
|
129
|
+
@state.event :ignite do
|
130
|
+
transition :parked => :idling
|
131
|
+
end
|
132
|
+
@state.event :park do
|
133
|
+
transition :idling => :parked
|
134
|
+
end
|
135
|
+
|
136
|
+
# Second machine
|
137
|
+
@machines[:alarm_state] = @alarm_state = StateMachine::Machine.new(@klass, :alarm_state, :initial => :active, :action => :save, :namespace => 'alarm')
|
138
|
+
@alarm_state.event :enable do
|
139
|
+
transition :off => :active
|
140
|
+
end
|
141
|
+
@alarm_state.event :disable do
|
142
|
+
transition :active => :off
|
143
|
+
end
|
144
|
+
|
145
|
+
@object = @klass.new
|
146
|
+
end
|
147
|
+
|
148
|
+
def test_should_raise_exception_if_invalid_event_specified
|
149
|
+
exception = assert_raise(StateMachine::InvalidEvent) { @machines.fire_events(@object, :invalid) }
|
150
|
+
assert_equal ':invalid is an unknown state machine event', exception.message
|
151
|
+
|
152
|
+
exception = assert_raise(StateMachine::InvalidEvent) { @machines.fire_events(@object, :ignite, :invalid) }
|
153
|
+
assert_equal ':invalid is an unknown state machine event', exception.message
|
154
|
+
end
|
155
|
+
|
156
|
+
def test_should_fail_if_any_event_cannot_transition
|
157
|
+
assert !@machines.fire_events(@object, :park, :disable_alarm)
|
158
|
+
assert_equal 'parked', @object.state
|
159
|
+
assert_equal 'active', @object.alarm_state
|
160
|
+
assert !@object.saved
|
161
|
+
|
162
|
+
assert !@machines.fire_events(@object, :ignite, :enable_alarm)
|
163
|
+
assert_equal 'parked', @object.state
|
164
|
+
assert_equal 'active', @object.alarm_state
|
165
|
+
assert !@object.saved
|
166
|
+
end
|
167
|
+
|
168
|
+
def test_should_be_successful_if_all_events_transition
|
169
|
+
assert @machines.fire_events(@object, :ignite, :disable_alarm)
|
170
|
+
assert_equal 'idling', @object.state
|
171
|
+
assert_equal 'off', @object.alarm_state
|
172
|
+
assert @object.saved
|
173
|
+
end
|
174
|
+
|
175
|
+
def test_should_not_save_if_skipping_action
|
176
|
+
assert @machines.fire_events(@object, :ignite, :disable_alarm, false)
|
177
|
+
assert_equal 'idling', @object.state
|
178
|
+
assert_equal 'off', @object.alarm_state
|
179
|
+
assert !@object.saved
|
180
|
+
end
|
181
|
+
end
|
182
|
+
|
183
|
+
class MachineCollectionFireWithTransactionsTest < Test::Unit::TestCase
|
184
|
+
def setup
|
185
|
+
@machines = StateMachine::MachineCollection.new
|
186
|
+
|
187
|
+
@klass = Class.new do
|
188
|
+
attr_accessor :allow_save
|
189
|
+
|
190
|
+
def save
|
191
|
+
@allow_save
|
192
|
+
end
|
193
|
+
end
|
194
|
+
|
195
|
+
StateMachine::Integrations.const_set('Custom', Module.new do
|
196
|
+
attr_reader :rolled_back
|
197
|
+
|
198
|
+
def transaction(object)
|
199
|
+
@rolled_back = yield
|
200
|
+
end
|
201
|
+
end)
|
202
|
+
|
203
|
+
# First machine
|
204
|
+
@machines[:state] = @state = StateMachine::Machine.new(@klass, :state, :initial => :parked, :action => :save, :integration => :custom)
|
205
|
+
@state.event :ignite do
|
206
|
+
transition :parked => :idling
|
207
|
+
end
|
208
|
+
|
209
|
+
# Second machine
|
210
|
+
@machines[:alarm_state] = @alarm_state = StateMachine::Machine.new(@klass, :alarm_state, :initial => :active, :action => :save, :namespace => 'alarm', :integration => :custom)
|
211
|
+
@alarm_state.event :disable do
|
212
|
+
transition :active => :off
|
213
|
+
end
|
214
|
+
|
215
|
+
@object = @klass.new
|
216
|
+
end
|
217
|
+
|
218
|
+
def test_should_not_rollback_if_successful
|
219
|
+
@object.allow_save = true
|
220
|
+
|
221
|
+
assert @machines.fire_events(@object, :ignite, :disable_alarm)
|
222
|
+
assert_equal true, @state.rolled_back
|
223
|
+
assert_nil @alarm_state.rolled_back
|
224
|
+
assert_equal 'idling', @object.state
|
225
|
+
assert_equal 'off', @object.alarm_state
|
226
|
+
end
|
227
|
+
|
228
|
+
def test_should_rollback_if_not_successful
|
229
|
+
@object.allow_save = false
|
230
|
+
|
231
|
+
assert !@machines.fire_events(@object, :ignite, :disable_alarm)
|
232
|
+
assert_equal false, @state.rolled_back
|
233
|
+
assert_nil @alarm_state.rolled_back
|
234
|
+
assert_equal 'parked', @object.state
|
235
|
+
assert_equal 'active', @object.alarm_state
|
236
|
+
end
|
237
|
+
|
238
|
+
def teardown
|
239
|
+
StateMachine::Integrations.send(:remove_const, 'Custom')
|
240
|
+
end
|
241
|
+
end
|
242
|
+
|
243
|
+
class MachineCollectionFireWithValidationsTest < Test::Unit::TestCase
|
244
|
+
def setup
|
245
|
+
StateMachine::Integrations.const_set('Custom', Module.new do
|
246
|
+
def invalidate(object, attribute, message, values = [])
|
247
|
+
(object.errors ||= []) << generate_message(message, values)
|
248
|
+
end
|
249
|
+
|
250
|
+
def reset(object)
|
251
|
+
object.errors = []
|
252
|
+
end
|
253
|
+
end)
|
254
|
+
|
255
|
+
@klass = Class.new do
|
256
|
+
attr_accessor :errors
|
257
|
+
|
258
|
+
def initialize
|
259
|
+
@errors = []
|
260
|
+
super
|
261
|
+
end
|
262
|
+
end
|
263
|
+
|
264
|
+
@machines = StateMachine::MachineCollection.new
|
265
|
+
@machines[:state] = @state = StateMachine::Machine.new(@klass, :state, :initial => :parked, :integration => :custom)
|
266
|
+
@state.event :ignite do
|
267
|
+
transition :parked => :idling
|
268
|
+
end
|
269
|
+
|
270
|
+
@machines[:alarm_state] = @alarm_state = StateMachine::Machine.new(@klass, :alarm_state, :initial => :active, :namespace => 'alarm', :integration => :custom)
|
271
|
+
@alarm_state.event :disable do
|
272
|
+
transition :active => :off
|
273
|
+
end
|
274
|
+
|
275
|
+
@object = @klass.new
|
276
|
+
end
|
277
|
+
|
278
|
+
def test_should_not_invalidate_if_transitions_exist
|
279
|
+
assert @machines.fire_events(@object, :ignite, :disable_alarm)
|
280
|
+
assert_equal [], @object.errors
|
281
|
+
end
|
282
|
+
|
283
|
+
def test_should_invalidate_if_no_transitions_exist
|
284
|
+
@object.state = 'idling'
|
285
|
+
@object.alarm_state = 'off'
|
286
|
+
|
287
|
+
assert !@machines.fire_events(@object, :ignite, :disable_alarm)
|
288
|
+
assert_equal ['cannot transition via "ignite"', 'cannot transition via "disable"'], @object.errors
|
289
|
+
end
|
290
|
+
|
291
|
+
def teardown
|
292
|
+
StateMachine::Integrations.send(:remove_const, 'Custom')
|
293
|
+
end
|
294
|
+
end
|
295
|
+
|
296
|
+
class MachineCollectionTransitionsWithoutEventsTest < Test::Unit::TestCase
|
297
|
+
def setup
|
298
|
+
@klass = Class.new
|
299
|
+
|
300
|
+
@machines = StateMachine::MachineCollection.new
|
301
|
+
@machines[:state] = @machine = StateMachine::Machine.new(@klass, :state, :initial => :parked, :action => :save)
|
302
|
+
@machine.event :ignite do
|
303
|
+
transition :parked => :idling
|
304
|
+
end
|
305
|
+
|
306
|
+
@object = @klass.new
|
307
|
+
@object.state_event = nil
|
308
|
+
@transitions = @machines.transitions(@object, :save)
|
309
|
+
end
|
310
|
+
|
311
|
+
def test_should_be_empty
|
312
|
+
assert @transitions.empty?
|
313
|
+
end
|
314
|
+
|
315
|
+
def test_should_perform
|
316
|
+
assert_equal true, @transitions.perform
|
317
|
+
end
|
318
|
+
end
|
319
|
+
|
320
|
+
class MachineCollectionTransitionsWithBlankEventsTest < Test::Unit::TestCase
|
321
|
+
def setup
|
322
|
+
@klass = Class.new
|
323
|
+
|
324
|
+
@machines = StateMachine::MachineCollection.new
|
325
|
+
@machines[:state] = @machine = StateMachine::Machine.new(@klass, :state, :initial => :parked, :action => :save)
|
326
|
+
@machine.event :ignite do
|
327
|
+
transition :parked => :idling
|
328
|
+
end
|
329
|
+
|
330
|
+
@object = @klass.new
|
331
|
+
@object.state_event = ''
|
332
|
+
@transitions = @machines.transitions(@object, :save)
|
333
|
+
end
|
334
|
+
|
335
|
+
def test_should_be_empty
|
336
|
+
assert @transitions.empty?
|
337
|
+
end
|
338
|
+
|
339
|
+
def test_should_perform
|
340
|
+
assert_equal true, @transitions.perform
|
341
|
+
end
|
342
|
+
end
|
343
|
+
|
344
|
+
class MachineCollectionTransitionsWithInvalidEventsTest < Test::Unit::TestCase
|
345
|
+
def setup
|
346
|
+
@klass = Class.new
|
347
|
+
|
348
|
+
@machines = StateMachine::MachineCollection.new
|
349
|
+
@machines[:state] = @machine = StateMachine::Machine.new(@klass, :state, :initial => :parked, :action => :save)
|
350
|
+
@machine.event :ignite do
|
351
|
+
transition :parked => :idling
|
352
|
+
end
|
353
|
+
|
354
|
+
@object = @klass.new
|
355
|
+
@object.state_event = 'invalid'
|
356
|
+
@transitions = @machines.transitions(@object, :save)
|
357
|
+
end
|
358
|
+
|
359
|
+
def test_should_be_empty
|
360
|
+
assert @transitions.empty?
|
361
|
+
end
|
362
|
+
|
363
|
+
def test_should_not_perform
|
364
|
+
assert_equal false, @transitions.perform
|
365
|
+
end
|
366
|
+
end
|
367
|
+
|
368
|
+
class MachineCollectionTransitionsWithoutTransitionTest < Test::Unit::TestCase
|
369
|
+
def setup
|
370
|
+
@klass = Class.new
|
371
|
+
|
372
|
+
@machines = StateMachine::MachineCollection.new
|
373
|
+
@machines[:state] = @machine = StateMachine::Machine.new(@klass, :state, :initial => :parked, :action => :save)
|
374
|
+
@machine.event :ignite do
|
375
|
+
transition :parked => :idling
|
376
|
+
end
|
377
|
+
|
378
|
+
@object = @klass.new
|
379
|
+
@object.state = 'idling'
|
380
|
+
@object.state_event = 'ignite'
|
381
|
+
@transitions = @machines.transitions(@object, :save)
|
382
|
+
end
|
383
|
+
|
384
|
+
def test_should_be_empty
|
385
|
+
assert @transitions.empty?
|
386
|
+
end
|
387
|
+
|
388
|
+
def test_should_not_perform
|
389
|
+
assert_equal false, @transitions.perform
|
390
|
+
end
|
391
|
+
end
|
392
|
+
|
393
|
+
class MachineCollectionTransitionsWithTransitionTest < Test::Unit::TestCase
|
394
|
+
def setup
|
395
|
+
@klass = Class.new
|
396
|
+
|
397
|
+
@machines = StateMachine::MachineCollection.new
|
398
|
+
@machines[:state] = @machine = StateMachine::Machine.new(@klass, :state, :initial => :parked, :action => :save)
|
399
|
+
@machine.event :ignite do
|
400
|
+
transition :parked => :idling
|
401
|
+
end
|
402
|
+
|
403
|
+
@object = @klass.new
|
404
|
+
@object.state_event = 'ignite'
|
405
|
+
@transitions = @machines.transitions(@object, :save)
|
406
|
+
end
|
407
|
+
|
408
|
+
def test_should_not_be_empty
|
409
|
+
assert_equal 1, @transitions.length
|
410
|
+
end
|
411
|
+
|
412
|
+
def test_should_perform
|
413
|
+
assert_equal true, @transitions.perform
|
414
|
+
end
|
415
|
+
end
|
416
|
+
|
417
|
+
class MachineCollectionTransitionsWithSameActionsTest < Test::Unit::TestCase
|
418
|
+
def setup
|
419
|
+
@klass = Class.new
|
420
|
+
|
421
|
+
@machines = StateMachine::MachineCollection.new
|
422
|
+
@machines[:state] = @machine = StateMachine::Machine.new(@klass, :state, :initial => :parked, :action => :save)
|
423
|
+
@machine.event :ignite do
|
424
|
+
transition :parked => :idling
|
425
|
+
end
|
426
|
+
@machines[:status] = @machine = StateMachine::Machine.new(@klass, :status, :initial => :first_gear, :action => :save)
|
427
|
+
@machine.event :shift_up do
|
428
|
+
transition :first_gear => :second_gear
|
429
|
+
end
|
430
|
+
|
431
|
+
@object = @klass.new
|
432
|
+
@object.state_event = 'ignite'
|
433
|
+
@object.status_event = 'shift_up'
|
434
|
+
@transitions = @machines.transitions(@object, :save)
|
435
|
+
end
|
436
|
+
|
437
|
+
def test_should_not_be_empty
|
438
|
+
assert_equal 2, @transitions.length
|
439
|
+
end
|
440
|
+
|
441
|
+
def test_should_perform
|
442
|
+
assert_equal true, @transitions.perform
|
443
|
+
end
|
444
|
+
end
|
445
|
+
|
446
|
+
class MachineCollectionTransitionsWithDifferentActionsTest < Test::Unit::TestCase
|
447
|
+
def setup
|
448
|
+
@klass = Class.new
|
449
|
+
|
450
|
+
@machines = StateMachine::MachineCollection.new
|
451
|
+
@machines[:state] = @state = StateMachine::Machine.new(@klass, :state, :initial => :parked, :action => :save)
|
452
|
+
@state.event :ignite do
|
453
|
+
transition :parked => :idling
|
454
|
+
end
|
455
|
+
@machines[:status] = @status = StateMachine::Machine.new(@klass, :status, :initial => :first_gear, :action => :persist)
|
456
|
+
@status.event :shift_up do
|
457
|
+
transition :first_gear => :second_gear
|
458
|
+
end
|
459
|
+
|
460
|
+
@object = @klass.new
|
461
|
+
@object.state_event = 'ignite'
|
462
|
+
@object.status_event = 'shift_up'
|
463
|
+
@transitions = @machines.transitions(@object, :save)
|
464
|
+
end
|
465
|
+
|
466
|
+
def test_should_only_select_matching_actions
|
467
|
+
assert_equal 1, @transitions.length
|
468
|
+
end
|
469
|
+
end
|
470
|
+
|
471
|
+
class MachineCollectionTransitionsWithExisitingTransitionsTest < Test::Unit::TestCase
|
472
|
+
def setup
|
473
|
+
@klass = Class.new
|
474
|
+
|
475
|
+
@machines = StateMachine::MachineCollection.new
|
476
|
+
@machines[:state] = @machine = StateMachine::Machine.new(@klass, :state, :initial => :parked, :action => :save)
|
477
|
+
@machine.event :ignite do
|
478
|
+
transition :parked => :idling
|
479
|
+
end
|
480
|
+
|
481
|
+
@object = @klass.new
|
482
|
+
@object.send(:state_event_transition=, StateMachine::Transition.new(@object, @machine, :ignite, :parked, :idling))
|
483
|
+
@transitions = @machines.transitions(@object, :save)
|
484
|
+
end
|
485
|
+
|
486
|
+
def test_should_not_be_empty
|
487
|
+
assert_equal 1, @transitions.length
|
488
|
+
end
|
489
|
+
|
490
|
+
def test_should_perform
|
491
|
+
assert_equal true, @transitions.perform
|
492
|
+
end
|
493
|
+
end
|
494
|
+
|
495
|
+
class MachineCollectionTransitionsWithCustomOptionsTest < Test::Unit::TestCase
|
496
|
+
def setup
|
497
|
+
@klass = Class.new
|
498
|
+
|
499
|
+
@machines = StateMachine::MachineCollection.new
|
500
|
+
@machines[:state] = @machine = StateMachine::Machine.new(@klass, :state, :initial => :parked, :action => :save)
|
501
|
+
@machine.event :ignite do
|
502
|
+
transition :parked => :idling
|
503
|
+
end
|
504
|
+
|
505
|
+
@object = @klass.new
|
506
|
+
@transitions = @machines.transitions(@object, :save, :after => false)
|
507
|
+
end
|
508
|
+
|
509
|
+
def test_should_use_custom_options
|
510
|
+
assert @transitions.skip_after
|
511
|
+
end
|
512
|
+
end
|
513
|
+
|
514
|
+
class MachineCollectionFireAttributesWithValidationsTest < Test::Unit::TestCase
|
515
|
+
def setup
|
516
|
+
@klass = Class.new do
|
517
|
+
attr_accessor :errors
|
518
|
+
|
519
|
+
def initialize
|
520
|
+
@errors = []
|
521
|
+
super
|
522
|
+
end
|
523
|
+
end
|
524
|
+
|
525
|
+
@machines = StateMachine::MachineCollection.new
|
526
|
+
@machines[:state] = @machine = StateMachine::Machine.new(@klass, :state, :initial => :parked, :action => :save)
|
527
|
+
@machine.event :ignite do
|
528
|
+
transition :parked => :idling
|
529
|
+
end
|
530
|
+
|
531
|
+
class << @machine
|
532
|
+
def invalidate(object, attribute, message, values = [])
|
533
|
+
(object.errors ||= []) << generate_message(message, values)
|
534
|
+
end
|
535
|
+
|
536
|
+
def reset(object)
|
537
|
+
object.errors = []
|
538
|
+
end
|
539
|
+
end
|
540
|
+
|
541
|
+
@object = @klass.new
|
542
|
+
end
|
543
|
+
|
544
|
+
def test_should_invalidate_if_event_is_invalid
|
545
|
+
@object.state_event = 'invalid'
|
546
|
+
@machines.transitions(@object, :save)
|
547
|
+
|
548
|
+
assert !@object.errors.empty?
|
549
|
+
end
|
550
|
+
|
551
|
+
def test_should_invalidate_if_no_transition_exists
|
552
|
+
@object.state = 'idling'
|
553
|
+
@object.state_event = 'ignite'
|
554
|
+
@machines.transitions(@object, :save)
|
555
|
+
|
556
|
+
assert !@object.errors.empty?
|
557
|
+
end
|
558
|
+
|
559
|
+
def test_should_not_invalidate_if_transition_exists
|
560
|
+
@object.state_event = 'ignite'
|
561
|
+
@machines.transitions(@object, :save)
|
562
|
+
|
563
|
+
assert @object.errors.empty?
|
564
|
+
end
|
565
|
+
end
|