pluginaweek-state_machine 0.7.6
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 +273 -0
- data/LICENSE +20 -0
- data/README.rdoc +466 -0
- data/Rakefile +98 -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 +429 -0
- data/lib/state_machine/assertions.rb +36 -0
- data/lib/state_machine/callback.rb +189 -0
- data/lib/state_machine/condition_proxy.rb +94 -0
- data/lib/state_machine/eval_helpers.rb +67 -0
- data/lib/state_machine/event.rb +251 -0
- data/lib/state_machine/event_collection.rb +113 -0
- data/lib/state_machine/extensions.rb +158 -0
- data/lib/state_machine/guard.rb +219 -0
- data/lib/state_machine/integrations.rb +68 -0
- data/lib/state_machine/integrations/active_record.rb +444 -0
- data/lib/state_machine/integrations/active_record/locale.rb +10 -0
- data/lib/state_machine/integrations/active_record/observer.rb +41 -0
- data/lib/state_machine/integrations/data_mapper.rb +325 -0
- data/lib/state_machine/integrations/data_mapper/observer.rb +139 -0
- data/lib/state_machine/integrations/sequel.rb +292 -0
- data/lib/state_machine/machine.rb +1431 -0
- data/lib/state_machine/machine_collection.rb +146 -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 +249 -0
- data/lib/state_machine/state_collection.rb +112 -0
- data/lib/state_machine/transition.rb +367 -0
- data/tasks/state_machine.rake +1 -0
- data/tasks/state_machine.rb +30 -0
- data/test/classes/switch.rb +11 -0
- data/test/functional/state_machine_test.rb +941 -0
- data/test/test_helper.rb +4 -0
- data/test/unit/assertions_test.rb +40 -0
- data/test/unit/callback_test.rb +455 -0
- data/test/unit/condition_proxy_test.rb +328 -0
- data/test/unit/eval_helpers_test.rb +129 -0
- data/test/unit/event_collection_test.rb +293 -0
- data/test/unit/event_test.rb +605 -0
- data/test/unit/guard_test.rb +862 -0
- data/test/unit/integrations/active_record_test.rb +1001 -0
- data/test/unit/integrations/data_mapper_test.rb +694 -0
- data/test/unit/integrations/sequel_test.rb +486 -0
- data/test/unit/integrations_test.rb +42 -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 +710 -0
- data/test/unit/machine_test.rb +1910 -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 +795 -0
- data/test/unit/transition_test.rb +1113 -0
- metadata +161 -0
@@ -0,0 +1,42 @@
|
|
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_record
|
28
|
+
assert_equal StateMachine::Integrations::ActiveRecord, StateMachine::Integrations.find(:active_record)
|
29
|
+
end
|
30
|
+
|
31
|
+
def test_should_find_data_mapper
|
32
|
+
assert_equal StateMachine::Integrations::DataMapper, StateMachine::Integrations.find(:data_mapper)
|
33
|
+
end
|
34
|
+
|
35
|
+
def test_should_find_sequel
|
36
|
+
assert_equal StateMachine::Integrations::Sequel, StateMachine::Integrations.find(:sequel)
|
37
|
+
end
|
38
|
+
|
39
|
+
def test_should_raise_an_exception_if_invalid
|
40
|
+
assert_raise(NameError) { StateMachine::Integrations.find(:invalid) }
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,710 @@
|
|
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 do
|
18
|
+
def initialize(attributes = {})
|
19
|
+
attributes.each do |attribute, value|
|
20
|
+
self.send("#{attribute}=", value)
|
21
|
+
end
|
22
|
+
|
23
|
+
super()
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
@machines[:state] = StateMachine::Machine.new(@klass, :state, :initial => :parked)
|
28
|
+
@machines[:alarm_state] = StateMachine::Machine.new(@klass, :alarm_state, :initial => :active)
|
29
|
+
@machines[:alarm_state].state :active, :value => lambda {'active'}
|
30
|
+
end
|
31
|
+
|
32
|
+
def test_should_set_states_if_nil
|
33
|
+
object = @klass.new
|
34
|
+
assert_equal 'parked', object.state
|
35
|
+
assert_equal 'active', object.alarm_state
|
36
|
+
end
|
37
|
+
|
38
|
+
def test_should_set_states_if_empty
|
39
|
+
object = @klass.new(:state => '', :alarm_state => '')
|
40
|
+
assert_equal 'parked', object.state
|
41
|
+
assert_equal 'active', object.alarm_state
|
42
|
+
end
|
43
|
+
|
44
|
+
def test_should_not_set_states_if_not_empty
|
45
|
+
object = @klass.new(:state => 'idling', :alarm_state => 'off')
|
46
|
+
assert_equal 'idling', object.state
|
47
|
+
assert_equal 'off', object.alarm_state
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
class MachineCollectionFireExplicitTest < Test::Unit::TestCase
|
52
|
+
def setup
|
53
|
+
@machines = StateMachine::MachineCollection.new
|
54
|
+
|
55
|
+
@klass = Class.new do
|
56
|
+
attr_reader :saved
|
57
|
+
|
58
|
+
def save
|
59
|
+
@saved = true
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
# First machine
|
64
|
+
@machines[:state] = @state = StateMachine::Machine.new(@klass, :state, :initial => :parked, :action => :save)
|
65
|
+
@state.event :ignite do
|
66
|
+
transition :parked => :idling
|
67
|
+
end
|
68
|
+
@state.event :park do
|
69
|
+
transition :idling => :parked
|
70
|
+
end
|
71
|
+
|
72
|
+
# Second machine
|
73
|
+
@machines[:alarm_state] = @alarm_state = StateMachine::Machine.new(@klass, :alarm_state, :initial => :active, :action => :save, :namespace => 'alarm')
|
74
|
+
@alarm_state.event :enable do
|
75
|
+
transition :off => :active
|
76
|
+
end
|
77
|
+
@alarm_state.event :disable do
|
78
|
+
transition :active => :off
|
79
|
+
end
|
80
|
+
|
81
|
+
@object = @klass.new
|
82
|
+
end
|
83
|
+
|
84
|
+
def test_should_raise_exception_if_invalid_event_specified
|
85
|
+
exception = assert_raise(StateMachine::InvalidEvent) { @machines.fire_events(@object, :invalid) }
|
86
|
+
assert_equal ':invalid is an unknown state machine event', exception.message
|
87
|
+
|
88
|
+
exception = assert_raise(StateMachine::InvalidEvent) { @machines.fire_events(@object, :ignite, :invalid) }
|
89
|
+
assert_equal ':invalid is an unknown state machine event', exception.message
|
90
|
+
end
|
91
|
+
|
92
|
+
def test_should_fail_if_any_event_cannot_transition
|
93
|
+
assert !@machines.fire_events(@object, :park, :disable_alarm)
|
94
|
+
assert_equal 'parked', @object.state
|
95
|
+
assert_equal 'active', @object.alarm_state
|
96
|
+
assert !@object.saved
|
97
|
+
|
98
|
+
assert !@machines.fire_events(@object, :ignite, :enable_alarm)
|
99
|
+
assert_equal 'parked', @object.state
|
100
|
+
assert_equal 'active', @object.alarm_state
|
101
|
+
assert !@object.saved
|
102
|
+
end
|
103
|
+
|
104
|
+
def test_should_be_successful_if_all_events_transition
|
105
|
+
assert @machines.fire_events(@object, :ignite, :disable_alarm)
|
106
|
+
assert_equal 'idling', @object.state
|
107
|
+
assert_equal 'off', @object.alarm_state
|
108
|
+
assert @object.saved
|
109
|
+
end
|
110
|
+
|
111
|
+
def test_should_not_save_if_skipping_action
|
112
|
+
assert @machines.fire_events(@object, :ignite, :disable_alarm, false)
|
113
|
+
assert_equal 'idling', @object.state
|
114
|
+
assert_equal 'off', @object.alarm_state
|
115
|
+
assert !@object.saved
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
class MachineCollectionFireExplicitWithTransactionsTest < Test::Unit::TestCase
|
120
|
+
def setup
|
121
|
+
@machines = StateMachine::MachineCollection.new
|
122
|
+
|
123
|
+
@klass = Class.new do
|
124
|
+
attr_accessor :allow_save
|
125
|
+
|
126
|
+
def save
|
127
|
+
@allow_save
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
StateMachine::Integrations.const_set('Custom', Module.new do
|
132
|
+
attr_reader :rolled_back
|
133
|
+
|
134
|
+
def transaction(object)
|
135
|
+
@rolled_back = yield
|
136
|
+
end
|
137
|
+
end)
|
138
|
+
|
139
|
+
# First machine
|
140
|
+
@machines[:state] = @state = StateMachine::Machine.new(@klass, :state, :initial => :parked, :action => :save, :integration => :custom)
|
141
|
+
@state.event :ignite do
|
142
|
+
transition :parked => :idling
|
143
|
+
end
|
144
|
+
|
145
|
+
# Second machine
|
146
|
+
@machines[:alarm_state] = @alarm_state = StateMachine::Machine.new(@klass, :alarm_state, :initial => :active, :action => :save, :namespace => 'alarm', :integration => :custom)
|
147
|
+
@alarm_state.event :disable do
|
148
|
+
transition :active => :off
|
149
|
+
end
|
150
|
+
|
151
|
+
@object = @klass.new
|
152
|
+
end
|
153
|
+
|
154
|
+
def test_should_not_rollback_if_successful
|
155
|
+
@object.allow_save = true
|
156
|
+
|
157
|
+
assert @machines.fire_events(@object, :ignite, :disable_alarm)
|
158
|
+
assert_equal true, @state.rolled_back
|
159
|
+
assert_nil @alarm_state.rolled_back
|
160
|
+
assert_equal 'idling', @object.state
|
161
|
+
assert_equal 'off', @object.alarm_state
|
162
|
+
end
|
163
|
+
|
164
|
+
def test_should_rollback_if_not_successful
|
165
|
+
@object.allow_save = false
|
166
|
+
|
167
|
+
assert !@machines.fire_events(@object, :ignite, :disable_alarm)
|
168
|
+
assert_equal false, @state.rolled_back
|
169
|
+
assert_nil @alarm_state.rolled_back
|
170
|
+
assert_equal 'parked', @object.state
|
171
|
+
assert_equal 'active', @object.alarm_state
|
172
|
+
end
|
173
|
+
|
174
|
+
def teardown
|
175
|
+
StateMachine::Integrations.send(:remove_const, 'Custom')
|
176
|
+
end
|
177
|
+
end
|
178
|
+
|
179
|
+
class MachineCollectionFireExplicitWithValidationsTest < Test::Unit::TestCase
|
180
|
+
def setup
|
181
|
+
StateMachine::Integrations.const_set('Custom', Module.new do
|
182
|
+
def invalidate(object, attribute, message, values = [])
|
183
|
+
(object.errors ||= []) << generate_message(message, values)
|
184
|
+
end
|
185
|
+
|
186
|
+
def reset(object)
|
187
|
+
object.errors = []
|
188
|
+
end
|
189
|
+
end)
|
190
|
+
|
191
|
+
@klass = Class.new do
|
192
|
+
attr_accessor :errors
|
193
|
+
|
194
|
+
def initialize
|
195
|
+
@errors = []
|
196
|
+
super
|
197
|
+
end
|
198
|
+
end
|
199
|
+
|
200
|
+
@machines = StateMachine::MachineCollection.new
|
201
|
+
@machines[:state] = @state = StateMachine::Machine.new(@klass, :state, :initial => :parked, :integration => :custom)
|
202
|
+
@state.event :ignite do
|
203
|
+
transition :parked => :idling
|
204
|
+
end
|
205
|
+
|
206
|
+
@machines[:alarm_state] = @alarm_state = StateMachine::Machine.new(@klass, :alarm_state, :initial => :active, :namespace => 'alarm', :integration => :custom)
|
207
|
+
@alarm_state.event :disable do
|
208
|
+
transition :active => :off
|
209
|
+
end
|
210
|
+
|
211
|
+
@object = @klass.new
|
212
|
+
end
|
213
|
+
|
214
|
+
def test_should_not_invalidate_if_transitions_exist
|
215
|
+
assert @machines.fire_events(@object, :ignite, :disable_alarm)
|
216
|
+
assert_equal [], @object.errors
|
217
|
+
end
|
218
|
+
|
219
|
+
def test_should_invalidate_if_no_transitions_exist
|
220
|
+
@object.state = 'idling'
|
221
|
+
@object.alarm_state = 'off'
|
222
|
+
|
223
|
+
assert !@machines.fire_events(@object, :ignite, :disable_alarm)
|
224
|
+
assert_equal ['cannot transition via "ignite"', 'cannot transition via "disable_alarm"'], @object.errors
|
225
|
+
end
|
226
|
+
|
227
|
+
def teardown
|
228
|
+
StateMachine::Integrations.send(:remove_const, 'Custom')
|
229
|
+
end
|
230
|
+
end
|
231
|
+
|
232
|
+
class MachineCollectionFireImplicitTest < Test::Unit::TestCase
|
233
|
+
def setup
|
234
|
+
@klass = Class.new
|
235
|
+
|
236
|
+
@machines = StateMachine::MachineCollection.new
|
237
|
+
@machines[:state] = @machine = StateMachine::Machine.new(@klass, :state, :initial => :parked, :action => :save)
|
238
|
+
@machine.event :ignite do
|
239
|
+
transition :parked => :idling
|
240
|
+
end
|
241
|
+
|
242
|
+
@saved = false
|
243
|
+
@object = @klass.new
|
244
|
+
end
|
245
|
+
|
246
|
+
def default_test
|
247
|
+
end
|
248
|
+
end
|
249
|
+
|
250
|
+
class MachineCollectionFireImplicitWithoutEventTest < MachineCollectionFireImplicitTest
|
251
|
+
def setup
|
252
|
+
super
|
253
|
+
|
254
|
+
@object.state_event = nil
|
255
|
+
@result = @machines.fire_event_attributes(@object, :save) { @saved = true }
|
256
|
+
end
|
257
|
+
|
258
|
+
def test_should_be_successful
|
259
|
+
assert_equal true, @result
|
260
|
+
end
|
261
|
+
|
262
|
+
def test_should_run_action
|
263
|
+
assert @saved
|
264
|
+
end
|
265
|
+
|
266
|
+
def test_should_not_transition_state
|
267
|
+
assert_equal 'parked', @object.state
|
268
|
+
end
|
269
|
+
|
270
|
+
def test_should_not_change_event_attribute
|
271
|
+
assert_nil @object.state_event
|
272
|
+
end
|
273
|
+
end
|
274
|
+
|
275
|
+
class MachineCollectionFireImplicitWithBlankEventTest < MachineCollectionFireImplicitTest
|
276
|
+
def setup
|
277
|
+
super
|
278
|
+
|
279
|
+
@object.state_event = ''
|
280
|
+
@result = @machines.fire_event_attributes(@object, :save) { @saved = true }
|
281
|
+
end
|
282
|
+
|
283
|
+
def test_should_be_successful
|
284
|
+
assert_equal true, @result
|
285
|
+
end
|
286
|
+
|
287
|
+
def test_should_run_action
|
288
|
+
assert @saved
|
289
|
+
end
|
290
|
+
|
291
|
+
def test_should_not_transition_state
|
292
|
+
assert_equal 'parked', @object.state
|
293
|
+
end
|
294
|
+
|
295
|
+
def test_should_not_change_event_attribute
|
296
|
+
assert_nil @object.state_event
|
297
|
+
end
|
298
|
+
end
|
299
|
+
|
300
|
+
class MachineCollectionFireImplicitWithInvalidEventTest < MachineCollectionFireImplicitTest
|
301
|
+
def setup
|
302
|
+
super
|
303
|
+
|
304
|
+
@object.state_event = 'invalid'
|
305
|
+
@result = @machines.fire_event_attributes(@object, :save) { @saved = true }
|
306
|
+
end
|
307
|
+
|
308
|
+
def test_should_not_be_successful
|
309
|
+
assert_equal false, @result
|
310
|
+
end
|
311
|
+
|
312
|
+
def test_should_not_run_action
|
313
|
+
assert !@saved
|
314
|
+
end
|
315
|
+
|
316
|
+
def test_should_not_transition_state
|
317
|
+
assert_equal 'parked', @object.state
|
318
|
+
end
|
319
|
+
|
320
|
+
def test_should_not_reset_event_attribute
|
321
|
+
assert_equal :invalid, @object.state_event
|
322
|
+
end
|
323
|
+
end
|
324
|
+
|
325
|
+
class MachineCollectionFireImplicitWithoutTransitionTest < MachineCollectionFireImplicitTest
|
326
|
+
def setup
|
327
|
+
super
|
328
|
+
|
329
|
+
@object.state = 'idling'
|
330
|
+
@object.state_event = 'ignite'
|
331
|
+
@result = @machines.fire_event_attributes(@object, :save) { @saved = true }
|
332
|
+
end
|
333
|
+
|
334
|
+
def test_should_not_be_successful
|
335
|
+
assert_equal false, @result
|
336
|
+
end
|
337
|
+
|
338
|
+
def test_should_not_run_action
|
339
|
+
assert !@saved
|
340
|
+
end
|
341
|
+
|
342
|
+
def test_should_not_transition_state
|
343
|
+
assert_equal 'idling', @object.state
|
344
|
+
end
|
345
|
+
|
346
|
+
def test_should_not_reset_event_attribute
|
347
|
+
assert_equal :ignite, @object.state_event
|
348
|
+
end
|
349
|
+
end
|
350
|
+
|
351
|
+
class MachineCollectionFireImplicitWithTransitionTest < MachineCollectionFireImplicitTest
|
352
|
+
def setup
|
353
|
+
super
|
354
|
+
|
355
|
+
@state_event = nil
|
356
|
+
|
357
|
+
@object.state_event = 'ignite'
|
358
|
+
@result = @machines.fire_event_attributes(@object, :save) do
|
359
|
+
@state_event = @object.state_event
|
360
|
+
@saved = true
|
361
|
+
end
|
362
|
+
end
|
363
|
+
|
364
|
+
def test_should_be_successful
|
365
|
+
assert_equal true, @result
|
366
|
+
end
|
367
|
+
|
368
|
+
def test_should_run_action
|
369
|
+
assert @saved
|
370
|
+
end
|
371
|
+
|
372
|
+
def test_should_not_have_event_while_running_action
|
373
|
+
assert_nil @state_event
|
374
|
+
end
|
375
|
+
|
376
|
+
def test_should_transition_state
|
377
|
+
assert_equal 'idling', @object.state
|
378
|
+
end
|
379
|
+
|
380
|
+
def test_should_reset_event_attribute
|
381
|
+
assert_nil @object.state_event
|
382
|
+
end
|
383
|
+
|
384
|
+
def test_should_not_be_successful_if_fired_again
|
385
|
+
@object.state_event = 'ignite'
|
386
|
+
assert !@machines.fire_event_attributes(@object, :save) { true }
|
387
|
+
end
|
388
|
+
end
|
389
|
+
|
390
|
+
class MachineCollectionFireImplicitWithNonBooleanResultTest < MachineCollectionFireImplicitTest
|
391
|
+
def setup
|
392
|
+
super
|
393
|
+
|
394
|
+
@action_value = Object.new
|
395
|
+
|
396
|
+
@object.state_event = 'ignite'
|
397
|
+
@result = @machines.fire_event_attributes(@object, :save) do
|
398
|
+
@saved = true
|
399
|
+
@action_value
|
400
|
+
end
|
401
|
+
end
|
402
|
+
|
403
|
+
def test_should_be_successful
|
404
|
+
assert_equal @action_value, @result
|
405
|
+
end
|
406
|
+
|
407
|
+
def test_should_run_action
|
408
|
+
assert @saved
|
409
|
+
end
|
410
|
+
|
411
|
+
def test_should_transition_state
|
412
|
+
assert_equal 'idling', @object.state
|
413
|
+
end
|
414
|
+
end
|
415
|
+
|
416
|
+
class MachineCollectionFireImplicitWithActionFailureTest < MachineCollectionFireImplicitTest
|
417
|
+
def setup
|
418
|
+
super
|
419
|
+
|
420
|
+
@object.state_event = 'ignite'
|
421
|
+
@result = @machines.fire_event_attributes(@object, :save) { false }
|
422
|
+
end
|
423
|
+
|
424
|
+
def test_should_not_be_successful
|
425
|
+
assert_equal false, @result
|
426
|
+
end
|
427
|
+
|
428
|
+
def test_should_not_transition_state
|
429
|
+
assert_equal 'parked', @object.state
|
430
|
+
end
|
431
|
+
|
432
|
+
def test_should_not_reset_event_attribute
|
433
|
+
assert_equal :ignite, @object.state_event
|
434
|
+
end
|
435
|
+
end
|
436
|
+
|
437
|
+
class MachineCollectionFireImplicitWithActionErrorTest < MachineCollectionFireImplicitTest
|
438
|
+
def setup
|
439
|
+
super
|
440
|
+
|
441
|
+
@object.state_event = 'ignite'
|
442
|
+
assert_raise(ArgumentError) { @machines.fire_event_attributes(@object, :save) { raise ArgumentError } }
|
443
|
+
end
|
444
|
+
|
445
|
+
def test_should_not_transition_state
|
446
|
+
assert_equal 'parked', @object.state
|
447
|
+
end
|
448
|
+
|
449
|
+
def test_should_not_reset_event_attribute
|
450
|
+
assert_equal :ignite, @object.state_event
|
451
|
+
end
|
452
|
+
end
|
453
|
+
|
454
|
+
class MachineCollectionFireImplicitPartialTest < MachineCollectionFireImplicitTest
|
455
|
+
def setup
|
456
|
+
super
|
457
|
+
|
458
|
+
@ran_before_callback = false
|
459
|
+
@ran_after_callback = false
|
460
|
+
@machine.before_transition { @ran_before_callback = true }
|
461
|
+
@machine.after_transition { @ran_after_callback = true }
|
462
|
+
|
463
|
+
@state_event = nil
|
464
|
+
|
465
|
+
@object.state_event = 'ignite'
|
466
|
+
@result = @machines.fire_event_attributes(@object, :save, false) do
|
467
|
+
@state_event = @object.state_event
|
468
|
+
true
|
469
|
+
end
|
470
|
+
end
|
471
|
+
|
472
|
+
def test_should_run_before_callbacks
|
473
|
+
assert @ran_before_callback
|
474
|
+
end
|
475
|
+
|
476
|
+
def test_should_not_run_after_callbacks
|
477
|
+
assert !@ran_after_callback
|
478
|
+
end
|
479
|
+
|
480
|
+
def test_should_be_successful
|
481
|
+
assert @result
|
482
|
+
end
|
483
|
+
|
484
|
+
def test_should_not_have_event_while_running_action
|
485
|
+
assert_nil @state_event
|
486
|
+
end
|
487
|
+
|
488
|
+
def test_should_transition_state
|
489
|
+
assert_equal 'idling', @object.state
|
490
|
+
end
|
491
|
+
|
492
|
+
def test_should_not_reset_event_attribute
|
493
|
+
assert_equal :ignite, @object.state_event
|
494
|
+
end
|
495
|
+
|
496
|
+
def test_should_reset_event_attributes_after_next_fire_on_success
|
497
|
+
assert @machines.fire_event_attributes(@object, :save) { true }
|
498
|
+
assert_equal 'idling', @object.state
|
499
|
+
assert_nil @object.state_event
|
500
|
+
end
|
501
|
+
|
502
|
+
def test_should_guard_transition_after_next_fire_on_success
|
503
|
+
@machines.fire_event_attributes(@object, :save) { true }
|
504
|
+
|
505
|
+
@object.state = 'idling'
|
506
|
+
@object.state_event = 'ignite'
|
507
|
+
assert !@machines.fire_event_attributes(@object, :save) { true }
|
508
|
+
end
|
509
|
+
|
510
|
+
def test_should_rollback_all_attributes_after_next_fire_on_failure
|
511
|
+
assert !@machines.fire_event_attributes(@object, :save) { false }
|
512
|
+
assert_equal 'parked', @object.state
|
513
|
+
assert_equal :ignite, @object.state_event
|
514
|
+
|
515
|
+
@object.state = 'idling'
|
516
|
+
assert !@machines.fire_event_attributes(@object, :save) { false }
|
517
|
+
end
|
518
|
+
|
519
|
+
def test_should_guard_transition_after_next_fire_on_failure
|
520
|
+
@machines.fire_event_attributes(@object, :save) { false }
|
521
|
+
|
522
|
+
@object.state = 'idling'
|
523
|
+
assert !@machines.fire_event_attributes(@object, :save) { true }
|
524
|
+
end
|
525
|
+
|
526
|
+
def test_should_rollback_all_attributes_after_next_fire_on_error
|
527
|
+
assert_raise(ArgumentError) { @machines.fire_event_attributes(@object, :save) { raise ArgumentError } }
|
528
|
+
assert_equal 'parked', @object.state
|
529
|
+
assert_equal :ignite, @object.state_event
|
530
|
+
end
|
531
|
+
|
532
|
+
def test_should_guard_transition_after_next_fire_on_error
|
533
|
+
begin
|
534
|
+
@machines.fire_event_attributes(@object, :save) { raise ArgumentError }
|
535
|
+
rescue ArgumentError
|
536
|
+
end
|
537
|
+
|
538
|
+
@object.state = 'idling'
|
539
|
+
assert !@machines.fire_event_attributes(@object, :save) { true }
|
540
|
+
end
|
541
|
+
end
|
542
|
+
|
543
|
+
class MachineCollectionFireImplicitNestedPartialTest < MachineCollectionFireImplicitTest
|
544
|
+
def setup
|
545
|
+
super
|
546
|
+
|
547
|
+
@partial_result = nil
|
548
|
+
|
549
|
+
@object.state_event = 'ignite'
|
550
|
+
@result = @machines.fire_event_attributes(@object, :save) do
|
551
|
+
@partial_result = @machines.fire_event_attributes(@object, :save, false) { true }
|
552
|
+
true
|
553
|
+
end
|
554
|
+
end
|
555
|
+
|
556
|
+
def test_should_be_successful
|
557
|
+
assert @result
|
558
|
+
end
|
559
|
+
|
560
|
+
def test_should_have_successful_partial_fire
|
561
|
+
assert @partial_result
|
562
|
+
end
|
563
|
+
|
564
|
+
def test_should_transition_state
|
565
|
+
assert_equal 'idling', @object.state
|
566
|
+
end
|
567
|
+
|
568
|
+
def test_should_reset_event_attribute
|
569
|
+
assert_nil @object.state_event
|
570
|
+
end
|
571
|
+
end
|
572
|
+
|
573
|
+
class MachineCollectionFireImplicitWithDifferentActionsTest < MachineCollectionFireImplicitTest
|
574
|
+
def setup
|
575
|
+
super
|
576
|
+
|
577
|
+
@machines[:alarm_state] = @alarm_machine = StateMachine::Machine.new(@klass, :alarm_state, :initial => :active, :action => :save_alarm)
|
578
|
+
@alarm_machine.event :disable do
|
579
|
+
transition :active => :off
|
580
|
+
end
|
581
|
+
|
582
|
+
@saved = false
|
583
|
+
@object = @klass.new
|
584
|
+
@object.state_event = 'ignite'
|
585
|
+
@object.alarm_state_event = 'disable'
|
586
|
+
|
587
|
+
@machines.fire_event_attributes(@object, :save) { true }
|
588
|
+
end
|
589
|
+
|
590
|
+
def test_should_transition_states_for_action
|
591
|
+
assert_equal 'idling', @object.state
|
592
|
+
end
|
593
|
+
|
594
|
+
def test_should_reset_event_attributes_for_action
|
595
|
+
assert_nil @object.state_event
|
596
|
+
end
|
597
|
+
|
598
|
+
def test_should_not_transition_states_for_other_actions
|
599
|
+
assert_equal 'active', @object.alarm_state
|
600
|
+
end
|
601
|
+
|
602
|
+
def test_should_not_reset_event_attributes_for_other_actions
|
603
|
+
assert_equal :disable, @object.alarm_state_event
|
604
|
+
end
|
605
|
+
end
|
606
|
+
|
607
|
+
class MachineCollectionFireImplicitWithSameActionsTest < MachineCollectionFireImplicitTest
|
608
|
+
def setup
|
609
|
+
super
|
610
|
+
|
611
|
+
@machines[:alarm_state] = @alarm_machine = StateMachine::Machine.new(@klass, :alarm_state, :initial => :active, :action => :save)
|
612
|
+
@alarm_machine.event :disable do
|
613
|
+
transition :active => :off
|
614
|
+
end
|
615
|
+
|
616
|
+
@saved = false
|
617
|
+
@object = @klass.new
|
618
|
+
@object.state_event = 'ignite'
|
619
|
+
@object.alarm_state_event = 'disable'
|
620
|
+
|
621
|
+
@machines.fire_event_attributes(@object, :save) { true }
|
622
|
+
end
|
623
|
+
|
624
|
+
def test_should_transition_all_states_for_action
|
625
|
+
assert_equal 'idling', @object.state
|
626
|
+
assert_equal 'off', @object.alarm_state
|
627
|
+
end
|
628
|
+
|
629
|
+
def test_should_reset_all_event_attributes_for_action
|
630
|
+
assert_nil @object.state_event
|
631
|
+
assert_nil @object.alarm_state_event
|
632
|
+
end
|
633
|
+
end
|
634
|
+
|
635
|
+
class MachineCollectionFireImplicitWithValidationsTest < Test::Unit::TestCase
|
636
|
+
def setup
|
637
|
+
StateMachine::Integrations.const_set('Custom', Module.new do
|
638
|
+
def invalidate(object, attribute, message, values = [])
|
639
|
+
(object.errors ||= []) << generate_message(message, values)
|
640
|
+
end
|
641
|
+
|
642
|
+
def reset(object)
|
643
|
+
object.errors = []
|
644
|
+
end
|
645
|
+
end)
|
646
|
+
|
647
|
+
@klass = Class.new do
|
648
|
+
attr_accessor :errors
|
649
|
+
|
650
|
+
def initialize
|
651
|
+
@errors = []
|
652
|
+
super
|
653
|
+
end
|
654
|
+
end
|
655
|
+
|
656
|
+
@machines = StateMachine::MachineCollection.new
|
657
|
+
@machines[:state] = @machine = StateMachine::Machine.new(@klass, :state, :initial => :parked, :action => :save, :integration => :custom)
|
658
|
+
@machine.event :ignite do
|
659
|
+
transition :parked => :idling
|
660
|
+
end
|
661
|
+
|
662
|
+
@object = @klass.new
|
663
|
+
end
|
664
|
+
|
665
|
+
def test_should_invalidate_if_event_is_invalid
|
666
|
+
@object.state_event = 'invalid'
|
667
|
+
@machines.fire_event_attributes(@object, :save) { true }
|
668
|
+
|
669
|
+
assert !@object.errors.empty?
|
670
|
+
end
|
671
|
+
|
672
|
+
def test_should_invalidate_if_no_transition_exists
|
673
|
+
@object.state = 'idling'
|
674
|
+
@object.state_event = 'ignite'
|
675
|
+
@machines.fire_event_attributes(@object, :save) { true }
|
676
|
+
|
677
|
+
assert !@object.errors.empty?
|
678
|
+
end
|
679
|
+
|
680
|
+
def test_should_not_invalidate_if_transition_exists
|
681
|
+
@object.state_event = 'ignite'
|
682
|
+
@machines.fire_event_attributes(@object, :save) { true }
|
683
|
+
|
684
|
+
assert @object.errors.empty?
|
685
|
+
end
|
686
|
+
|
687
|
+
def teardown
|
688
|
+
StateMachine::Integrations.send(:remove_const, 'Custom')
|
689
|
+
end
|
690
|
+
end
|
691
|
+
|
692
|
+
class MachineCollectionFireImplicitWithCustomMachineNameTest < MachineCollectionFireImplicitTest
|
693
|
+
def setup
|
694
|
+
super
|
695
|
+
|
696
|
+
@object.state_event = 'ignite'
|
697
|
+
end
|
698
|
+
|
699
|
+
def test_should_be_successful_on_complete_file
|
700
|
+
assert @machines.fire_event_attributes(@object, :save) { true }
|
701
|
+
assert_equal 'idling', @object.state
|
702
|
+
assert_nil @object.state_event
|
703
|
+
end
|
704
|
+
|
705
|
+
def test_should_be_successful_on_partial_fire
|
706
|
+
@machines.fire_event_attributes(@object, :save, false) { true }
|
707
|
+
assert_equal 'idling', @object.state
|
708
|
+
assert_equal :ignite, @object.state_event
|
709
|
+
end
|
710
|
+
end
|