state_machine 0.6.3 → 0.7.0
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG.rdoc +31 -1
- data/README.rdoc +33 -21
- data/Rakefile +2 -2
- 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/lib/state_machine/assertions.rb +2 -2
- data/lib/state_machine/callback.rb +14 -8
- data/lib/state_machine/condition_proxy.rb +3 -3
- data/lib/state_machine/event.rb +19 -21
- data/lib/state_machine/event_collection.rb +114 -0
- data/lib/state_machine/extensions.rb +127 -11
- data/lib/state_machine/guard.rb +1 -1
- data/lib/state_machine/integrations/active_record/locale.rb +2 -1
- data/lib/state_machine/integrations/active_record.rb +117 -39
- data/lib/state_machine/integrations/data_mapper/observer.rb +20 -64
- data/lib/state_machine/integrations/data_mapper.rb +71 -26
- data/lib/state_machine/integrations/sequel.rb +69 -21
- data/lib/state_machine/machine.rb +267 -139
- data/lib/state_machine/machine_collection.rb +145 -0
- data/lib/state_machine/matcher.rb +2 -2
- data/lib/state_machine/node_collection.rb +9 -4
- data/lib/state_machine/state.rb +22 -32
- data/lib/state_machine/state_collection.rb +66 -17
- data/lib/state_machine/transition.rb +259 -28
- data/lib/state_machine.rb +121 -56
- data/tasks/state_machine.rake +1 -0
- data/tasks/state_machine.rb +26 -0
- data/test/active_record.log +116877 -0
- data/test/functional/state_machine_test.rb +118 -12
- data/test/sequel.log +28542 -0
- data/test/unit/callback_test.rb +46 -1
- data/test/unit/condition_proxy_test.rb +55 -28
- data/test/unit/event_collection_test.rb +228 -0
- data/test/unit/event_test.rb +51 -46
- data/test/unit/integrations/active_record_test.rb +128 -70
- data/test/unit/integrations/data_mapper_test.rb +150 -58
- data/test/unit/integrations/sequel_test.rb +63 -6
- data/test/unit/invalid_event_test.rb +7 -0
- data/test/unit/machine_collection_test.rb +678 -0
- data/test/unit/machine_test.rb +198 -91
- data/test/unit/node_collection_test.rb +33 -30
- data/test/unit/state_collection_test.rb +112 -5
- data/test/unit/state_test.rb +23 -3
- data/test/unit/transition_test.rb +750 -89
- metadata +28 -3
data/test/unit/event_test.rb
CHANGED
@@ -17,6 +17,10 @@ class EventByDefaultTest < Test::Unit::TestCase
|
|
17
17
|
assert_equal :ignite, @event.name
|
18
18
|
end
|
19
19
|
|
20
|
+
def test_should_have_a_qualified_name
|
21
|
+
assert_equal :ignite, @event.qualified_name
|
22
|
+
end
|
23
|
+
|
20
24
|
def test_should_not_have_any_guards
|
21
25
|
assert @event.guards.empty?
|
22
26
|
end
|
@@ -29,8 +33,8 @@ class EventByDefaultTest < Test::Unit::TestCase
|
|
29
33
|
assert !@event.can_fire?(@object)
|
30
34
|
end
|
31
35
|
|
32
|
-
def
|
33
|
-
assert_nil @event.
|
36
|
+
def test_should_not_have_a_transition
|
37
|
+
assert_nil @event.transition_for(@object)
|
34
38
|
end
|
35
39
|
|
36
40
|
def test_should_define_a_predicate
|
@@ -38,7 +42,7 @@ class EventByDefaultTest < Test::Unit::TestCase
|
|
38
42
|
end
|
39
43
|
|
40
44
|
def test_should_define_a_transition_accessor
|
41
|
-
assert @object.respond_to?(:
|
45
|
+
assert @object.respond_to?(:ignite_transition)
|
42
46
|
end
|
43
47
|
|
44
48
|
def test_should_define_an_action
|
@@ -85,7 +89,7 @@ class EventWithConflictingHelpersTest < Test::Unit::TestCase
|
|
85
89
|
0
|
86
90
|
end
|
87
91
|
|
88
|
-
def
|
92
|
+
def ignite_transition
|
89
93
|
0
|
90
94
|
end
|
91
95
|
|
@@ -107,7 +111,7 @@ class EventWithConflictingHelpersTest < Test::Unit::TestCase
|
|
107
111
|
end
|
108
112
|
|
109
113
|
def test_should_not_redefine_transition_accessor
|
110
|
-
assert_equal 0, @object.
|
114
|
+
assert_equal 0, @object.ignite_transition
|
111
115
|
end
|
112
116
|
|
113
117
|
def test_should_not_redefine_action
|
@@ -124,7 +128,7 @@ class EventWithConflictingHelpersTest < Test::Unit::TestCase
|
|
124
128
|
super ? 1 : 0
|
125
129
|
end
|
126
130
|
|
127
|
-
def
|
131
|
+
def ignite_transition
|
128
132
|
super ? 1 : 0
|
129
133
|
end
|
130
134
|
|
@@ -143,34 +147,42 @@ class EventWithConflictingHelpersTest < Test::Unit::TestCase
|
|
143
147
|
end
|
144
148
|
|
145
149
|
assert_equal 0, @object.can_ignite?
|
146
|
-
assert_equal 0, @object.
|
150
|
+
assert_equal 0, @object.ignite_transition
|
147
151
|
assert_equal 0, @object.ignite
|
148
|
-
assert_equal
|
152
|
+
assert_equal 1, @object.ignite!
|
149
153
|
end
|
150
154
|
end
|
151
155
|
|
152
156
|
class EventWithNamespaceTest < Test::Unit::TestCase
|
153
157
|
def setup
|
154
158
|
@klass = Class.new
|
155
|
-
@machine = StateMachine::Machine.new(@klass, :namespace => '
|
156
|
-
@event = StateMachine::Event.new(@machine, :
|
159
|
+
@machine = StateMachine::Machine.new(@klass, :namespace => 'alarm')
|
160
|
+
@event = StateMachine::Event.new(@machine, :enable)
|
157
161
|
@object = @klass.new
|
158
162
|
end
|
159
163
|
|
164
|
+
def test_should_have_a_name
|
165
|
+
assert_equal :enable, @event.name
|
166
|
+
end
|
167
|
+
|
168
|
+
def test_should_have_a_qualified_name
|
169
|
+
assert_equal :enable_alarm, @event.qualified_name
|
170
|
+
end
|
171
|
+
|
160
172
|
def test_should_namespace_predicate
|
161
|
-
assert @object.respond_to?(:
|
173
|
+
assert @object.respond_to?(:can_enable_alarm?)
|
162
174
|
end
|
163
175
|
|
164
176
|
def test_should_namespace_transition_accessor
|
165
|
-
assert @object.respond_to?(:
|
177
|
+
assert @object.respond_to?(:enable_alarm_transition)
|
166
178
|
end
|
167
179
|
|
168
180
|
def test_should_namespace_action
|
169
|
-
assert @object.respond_to?(:
|
181
|
+
assert @object.respond_to?(:enable_alarm)
|
170
182
|
end
|
171
183
|
|
172
184
|
def test_should_namespace_bang_action
|
173
|
-
assert @object.respond_to?(:
|
185
|
+
assert @object.respond_to?(:enable_alarm!)
|
174
186
|
end
|
175
187
|
end
|
176
188
|
|
@@ -253,19 +265,14 @@ class EventWithoutTransitionsTest < Test::Unit::TestCase
|
|
253
265
|
assert !@event.can_fire?(@object)
|
254
266
|
end
|
255
267
|
|
256
|
-
def
|
257
|
-
assert_nil @event.
|
268
|
+
def test_should_not_have_a_transition
|
269
|
+
assert_nil @event.transition_for(@object)
|
258
270
|
end
|
259
271
|
|
260
272
|
def test_should_not_fire
|
261
273
|
assert !@event.fire(@object)
|
262
274
|
end
|
263
275
|
|
264
|
-
def test_should_raise_exception_on_fire!
|
265
|
-
exception = assert_raise(StateMachine::InvalidTransition) { @event.fire!(@object) }
|
266
|
-
assert_equal 'Cannot transition state via :ignite from nil', exception.message
|
267
|
-
end
|
268
|
-
|
269
276
|
def test_should_not_change_the_current_state
|
270
277
|
@event.fire(@object)
|
271
278
|
assert_nil @object.state
|
@@ -314,19 +321,14 @@ class EventWithoutMatchingTransitionsTest < Test::Unit::TestCase
|
|
314
321
|
assert !@event.can_fire?(@object)
|
315
322
|
end
|
316
323
|
|
317
|
-
def
|
318
|
-
assert_nil @event.
|
324
|
+
def test_should_not_have_a_transition
|
325
|
+
assert_nil @event.transition_for(@object)
|
319
326
|
end
|
320
327
|
|
321
328
|
def test_should_not_fire
|
322
329
|
assert !@event.fire(@object)
|
323
330
|
end
|
324
331
|
|
325
|
-
def test_should_raise_exception_on_fire!
|
326
|
-
exception = assert_raise(StateMachine::InvalidTransition) { @event.fire!(@object) }
|
327
|
-
assert_equal 'Cannot transition state via :ignite from :idling', exception.message
|
328
|
-
end
|
329
|
-
|
330
332
|
def test_should_not_change_the_current_state
|
331
333
|
@event.fire(@object)
|
332
334
|
assert_equal 'idling', @object.state
|
@@ -336,8 +338,8 @@ end
|
|
336
338
|
class EventWithMatchingDisabledTransitionsTest < Test::Unit::TestCase
|
337
339
|
def setup
|
338
340
|
StateMachine::Integrations.const_set('Custom', Module.new do
|
339
|
-
def invalidate(object,
|
340
|
-
(object.errors ||= []) <<
|
341
|
+
def invalidate(object, attribute, message, values = [])
|
342
|
+
(object.errors ||= []) << generate_message(message, values)
|
341
343
|
end
|
342
344
|
|
343
345
|
def reset(object)
|
@@ -363,8 +365,8 @@ class EventWithMatchingDisabledTransitionsTest < Test::Unit::TestCase
|
|
363
365
|
assert !@event.can_fire?(@object)
|
364
366
|
end
|
365
367
|
|
366
|
-
def
|
367
|
-
assert_nil @event.
|
368
|
+
def test_should_not_have_a_transition
|
369
|
+
assert_nil @event.transition_for(@object)
|
368
370
|
end
|
369
371
|
|
370
372
|
def test_should_not_fire
|
@@ -378,14 +380,14 @@ class EventWithMatchingDisabledTransitionsTest < Test::Unit::TestCase
|
|
378
380
|
|
379
381
|
def test_should_invalidate_the_state
|
380
382
|
@event.fire(@object)
|
381
|
-
assert_equal ['cannot
|
383
|
+
assert_equal ['cannot transition via "ignite"'], @object.errors
|
382
384
|
end
|
383
385
|
|
384
386
|
def test_should_reset_existing_error
|
385
387
|
@object.errors = ['invalid']
|
386
388
|
|
387
389
|
@event.fire(@object)
|
388
|
-
assert_equal ['cannot
|
390
|
+
assert_equal ['cannot transition via "ignite"'], @object.errors
|
389
391
|
end
|
390
392
|
|
391
393
|
def teardown
|
@@ -396,8 +398,8 @@ end
|
|
396
398
|
class EventWithMatchingEnabledTransitionsTest < Test::Unit::TestCase
|
397
399
|
def setup
|
398
400
|
StateMachine::Integrations.const_set('Custom', Module.new do
|
399
|
-
def invalidate(object,
|
400
|
-
(object.errors ||= []) <<
|
401
|
+
def invalidate(object, attribute, message, values = [])
|
402
|
+
(object.errors ||= []) << generate_message(message, values)
|
401
403
|
end
|
402
404
|
|
403
405
|
def reset(object)
|
@@ -411,6 +413,7 @@ class EventWithMatchingEnabledTransitionsTest < Test::Unit::TestCase
|
|
411
413
|
|
412
414
|
@machine = StateMachine::Machine.new(@klass, :integration => :custom)
|
413
415
|
@machine.state :parked, :idling
|
416
|
+
@machine.event :ignite
|
414
417
|
|
415
418
|
@event = StateMachine::Event.new(@machine, :ignite)
|
416
419
|
@event.transition(:parked => :idling)
|
@@ -423,8 +426,8 @@ class EventWithMatchingEnabledTransitionsTest < Test::Unit::TestCase
|
|
423
426
|
assert @event.can_fire?(@object)
|
424
427
|
end
|
425
428
|
|
426
|
-
def
|
427
|
-
transition = @event.
|
429
|
+
def test_should_have_a_transition
|
430
|
+
transition = @event.transition_for(@object)
|
428
431
|
assert_not_nil transition
|
429
432
|
assert_equal 'parked', transition.from
|
430
433
|
assert_equal 'idling', transition.to
|
@@ -462,6 +465,7 @@ class EventWithTransitionWithoutToStateTest < Test::Unit::TestCase
|
|
462
465
|
@klass = Class.new
|
463
466
|
@machine = StateMachine::Machine.new(@klass)
|
464
467
|
@machine.state :parked
|
468
|
+
@machine.event :park
|
465
469
|
|
466
470
|
@event = StateMachine::Event.new(@machine, :park)
|
467
471
|
@event.transition(:from => :parked)
|
@@ -474,8 +478,8 @@ class EventWithTransitionWithoutToStateTest < Test::Unit::TestCase
|
|
474
478
|
assert @event.can_fire?(@object)
|
475
479
|
end
|
476
480
|
|
477
|
-
def
|
478
|
-
transition = @event.
|
481
|
+
def test_should_have_a_transition
|
482
|
+
transition = @event.transition_for(@object)
|
479
483
|
assert_not_nil transition
|
480
484
|
assert_equal 'parked', transition.from
|
481
485
|
assert_equal 'parked', transition.to
|
@@ -496,8 +500,8 @@ class EventWithTransitionWithNilToStateTest < Test::Unit::TestCase
|
|
496
500
|
def setup
|
497
501
|
@klass = Class.new
|
498
502
|
@machine = StateMachine::Machine.new(@klass)
|
499
|
-
@machine.state nil
|
500
|
-
@machine.
|
503
|
+
@machine.state nil, :idling
|
504
|
+
@machine.event :park
|
501
505
|
|
502
506
|
@event = StateMachine::Event.new(@machine, :park)
|
503
507
|
@event.transition(:idling => nil)
|
@@ -510,8 +514,8 @@ class EventWithTransitionWithNilToStateTest < Test::Unit::TestCase
|
|
510
514
|
assert @event.can_fire?(@object)
|
511
515
|
end
|
512
516
|
|
513
|
-
def
|
514
|
-
transition = @event.
|
517
|
+
def test_should_have_a_transition
|
518
|
+
transition = @event.transition_for(@object)
|
515
519
|
assert_not_nil transition
|
516
520
|
assert_equal 'idling', transition.from
|
517
521
|
assert_equal nil, transition.to
|
@@ -533,6 +537,7 @@ class EventWithMultipleTransitionsTest < Test::Unit::TestCase
|
|
533
537
|
@klass = Class.new
|
534
538
|
@machine = StateMachine::Machine.new(@klass)
|
535
539
|
@machine.state :parked, :idling
|
540
|
+
@machine.event :ignite
|
536
541
|
|
537
542
|
@event = StateMachine::Event.new(@machine, :ignite)
|
538
543
|
@event.transition(:idling => :idling)
|
@@ -546,8 +551,8 @@ class EventWithMultipleTransitionsTest < Test::Unit::TestCase
|
|
546
551
|
assert @event.can_fire?(@object)
|
547
552
|
end
|
548
553
|
|
549
|
-
def
|
550
|
-
transition = @event.
|
554
|
+
def test_should_have_a_transition
|
555
|
+
transition = @event.transition_for(@object)
|
551
556
|
assert_not_nil transition
|
552
557
|
assert_equal 'parked', transition.from
|
553
558
|
assert_equal 'idling', transition.to
|
@@ -14,13 +14,6 @@ begin
|
|
14
14
|
require 'active_record/fixtures'
|
15
15
|
require 'active_record/test_case'
|
16
16
|
|
17
|
-
# Set default fixtures configuration
|
18
|
-
ActiveSupport::TestCase.class_eval do
|
19
|
-
self.fixture_path = File.dirname(__FILE__) + '/../../fixtures/'
|
20
|
-
self.use_instantiated_fixtures = false
|
21
|
-
self.use_transactional_fixtures = true
|
22
|
-
end
|
23
|
-
|
24
17
|
# Establish database connection
|
25
18
|
ActiveRecord::Base.establish_connection({'adapter' => 'sqlite3', 'database' => ':memory:'})
|
26
19
|
ActiveRecord::Base.logger = Logger.new("#{File.dirname(__FILE__)}/../../active_record.log")
|
@@ -76,6 +69,10 @@ begin
|
|
76
69
|
assert_equal :save, @machine.action
|
77
70
|
end
|
78
71
|
|
72
|
+
def test_should_use_transactions
|
73
|
+
assert_equal true, @machine.use_transactions
|
74
|
+
end
|
75
|
+
|
79
76
|
def test_should_create_notifier_before_callback
|
80
77
|
assert_equal 1, @machine.callbacks[:before].size
|
81
78
|
end
|
@@ -168,10 +165,10 @@ begin
|
|
168
165
|
record = @model.new
|
169
166
|
record.state = 'parked'
|
170
167
|
|
171
|
-
@machine.invalidate(record,
|
168
|
+
@machine.invalidate(record, :state, :invalid_transition, [[:event, :park]])
|
172
169
|
|
173
170
|
assert record.errors.invalid?(:state)
|
174
|
-
assert_equal 'cannot
|
171
|
+
assert_equal 'cannot transition via "park"', record.errors.on(:state)
|
175
172
|
end
|
176
173
|
|
177
174
|
def test_should_clear_errors_on_reset
|
@@ -236,6 +233,23 @@ begin
|
|
236
233
|
end
|
237
234
|
end
|
238
235
|
|
236
|
+
class MachineWithConflictingPredicateTest < ActiveRecord::TestCase
|
237
|
+
def setup
|
238
|
+
@model = new_model do
|
239
|
+
def state?(*args)
|
240
|
+
true
|
241
|
+
end
|
242
|
+
end
|
243
|
+
|
244
|
+
@machine = StateMachine::Machine.new(@model)
|
245
|
+
@record = @model.new
|
246
|
+
end
|
247
|
+
|
248
|
+
def test_should_not_define_attribute_predicate
|
249
|
+
assert @record.state?
|
250
|
+
end
|
251
|
+
end
|
252
|
+
|
239
253
|
class MachineWithColumnStateAttributeTest < ActiveRecord::TestCase
|
240
254
|
def setup
|
241
255
|
@model = new_model
|
@@ -265,7 +279,7 @@ begin
|
|
265
279
|
end
|
266
280
|
|
267
281
|
def test_should_raise_exception_for_predicate_if_invalid_state_specified
|
268
|
-
assert_raise(
|
282
|
+
assert_raise(IndexError) { @record.state?(:invalid) }
|
269
283
|
end
|
270
284
|
end
|
271
285
|
|
@@ -322,7 +336,7 @@ begin
|
|
322
336
|
end
|
323
337
|
|
324
338
|
def test_should_raise_exception_for_predicate_if_invalid_state_specified
|
325
|
-
assert_raise(
|
339
|
+
assert_raise(IndexError) { @record.status?(:invalid) }
|
326
340
|
end
|
327
341
|
|
328
342
|
def test_should_set_initial_state_on_created_object
|
@@ -350,6 +364,7 @@ begin
|
|
350
364
|
@model = new_model
|
351
365
|
@machine = StateMachine::Machine.new(@model, :initial => :parked)
|
352
366
|
@machine.other_states :idling
|
367
|
+
@machine.event :ignite
|
353
368
|
|
354
369
|
@record = @model.new(:state => 'parked')
|
355
370
|
@transition = StateMachine::Transition.new(@record, @machine, :ignite, :parked, :idling)
|
@@ -363,7 +378,7 @@ begin
|
|
363
378
|
assert called
|
364
379
|
end
|
365
380
|
|
366
|
-
def
|
381
|
+
def test_should_pass_record_to_before_callbacks_with_one_argument
|
367
382
|
record = nil
|
368
383
|
@machine.before_transition(lambda {|arg| record = arg})
|
369
384
|
|
@@ -371,7 +386,7 @@ begin
|
|
371
386
|
assert_equal @record, record
|
372
387
|
end
|
373
388
|
|
374
|
-
def
|
389
|
+
def test_should_pass_record_and_transition_to_before_callbacks_with_multiple_arguments
|
375
390
|
callback_args = nil
|
376
391
|
@machine.before_transition(lambda {|*args| callback_args = args})
|
377
392
|
|
@@ -395,7 +410,7 @@ begin
|
|
395
410
|
assert called
|
396
411
|
end
|
397
412
|
|
398
|
-
def
|
413
|
+
def test_should_pass_record_to_after_callbacks_with_one_argument
|
399
414
|
record = nil
|
400
415
|
@machine.after_transition(lambda {|arg| record = arg})
|
401
416
|
|
@@ -403,12 +418,12 @@ begin
|
|
403
418
|
assert_equal @record, record
|
404
419
|
end
|
405
420
|
|
406
|
-
def
|
421
|
+
def test_should_pass_record_and_transition_to_after_callbacks_with_multiple_arguments
|
407
422
|
callback_args = nil
|
408
423
|
@machine.after_transition(lambda {|*args| callback_args = args})
|
409
424
|
|
410
425
|
@transition.perform
|
411
|
-
assert_equal [@record, @transition
|
426
|
+
assert_equal [@record, @transition], callback_args
|
412
427
|
end
|
413
428
|
|
414
429
|
def test_should_run_after_callbacks_outside_the_context_of_the_record
|
@@ -458,6 +473,7 @@ begin
|
|
458
473
|
@model = new_model
|
459
474
|
@machine = StateMachine::Machine.new(@model)
|
460
475
|
@machine.state :parked, :idling
|
476
|
+
@machine.event :ignite
|
461
477
|
@machine.before_transition(lambda {@before_count += 1; false})
|
462
478
|
@machine.before_transition(lambda {@before_count += 1})
|
463
479
|
|
@@ -491,6 +507,7 @@ begin
|
|
491
507
|
|
492
508
|
@machine = StateMachine::Machine.new(@model)
|
493
509
|
@machine.state :parked, :idling
|
510
|
+
@machine.event :ignite
|
494
511
|
@record = @model.new(:state => 'parked')
|
495
512
|
@transition = StateMachine::Transition.new(@record, @machine, :ignite, :parked, :idling)
|
496
513
|
@result = @transition.perform
|
@@ -500,8 +517,8 @@ begin
|
|
500
517
|
assert !@result
|
501
518
|
end
|
502
519
|
|
503
|
-
def
|
504
|
-
assert_equal '
|
520
|
+
def test_should_not_change_current_state
|
521
|
+
assert_equal 'parked', @record.state
|
505
522
|
end
|
506
523
|
|
507
524
|
def test_should_not_save_record
|
@@ -545,6 +562,7 @@ begin
|
|
545
562
|
@model = new_model
|
546
563
|
@machine = StateMachine::Machine.new(@model)
|
547
564
|
@machine.state :parked, :idling
|
565
|
+
@machine.event :ignite
|
548
566
|
@machine.after_transition(lambda {@after_count += 1; false})
|
549
567
|
@machine.after_transition(lambda {@after_count += 1})
|
550
568
|
|
@@ -570,42 +588,98 @@ begin
|
|
570
588
|
end
|
571
589
|
end
|
572
590
|
|
591
|
+
class MachineWithEventAttributesOnValidationTest < ActiveRecord::TestCase
|
592
|
+
def setup
|
593
|
+
@model = new_model
|
594
|
+
@machine = StateMachine::Machine.new(@model)
|
595
|
+
@machine.event :ignite do
|
596
|
+
transition :parked => :idling
|
597
|
+
end
|
598
|
+
|
599
|
+
@record = @model.new
|
600
|
+
@record.state = 'parked'
|
601
|
+
@record.state_event = 'ignite'
|
602
|
+
end
|
603
|
+
|
604
|
+
def test_should_fail_if_event_is_invalid
|
605
|
+
@record.state_event = 'invalid'
|
606
|
+
assert !@record.valid?
|
607
|
+
assert_equal ['State event is invalid'], @record.errors.full_messages
|
608
|
+
end
|
609
|
+
|
610
|
+
def test_should_fail_if_event_has_no_transition
|
611
|
+
@record.state = 'idling'
|
612
|
+
assert !@record.valid?
|
613
|
+
assert_equal ['State event cannot transition when idling'], @record.errors.full_messages
|
614
|
+
end
|
615
|
+
|
616
|
+
def test_should_be_successful_if_event_has_transition
|
617
|
+
assert @record.valid?
|
618
|
+
end
|
619
|
+
|
620
|
+
def test_should_run_before_callbacks
|
621
|
+
ran_callback = false
|
622
|
+
@machine.before_transition { ran_callback = true }
|
623
|
+
|
624
|
+
@record.valid?
|
625
|
+
assert ran_callback
|
626
|
+
end
|
627
|
+
|
628
|
+
def test_should_persist_new_state
|
629
|
+
@record.valid?
|
630
|
+
assert_equal 'idling', @record.state
|
631
|
+
end
|
632
|
+
|
633
|
+
def test_should_not_run_after_callbacks
|
634
|
+
ran_callback = false
|
635
|
+
@machine.after_transition { ran_callback = true }
|
636
|
+
|
637
|
+
@record.valid?
|
638
|
+
assert !ran_callback
|
639
|
+
end
|
640
|
+
end
|
641
|
+
|
573
642
|
class MachineWithObserversTest < ActiveRecord::TestCase
|
574
643
|
def setup
|
575
644
|
@model = new_model
|
576
645
|
@machine = StateMachine::Machine.new(@model)
|
577
646
|
@machine.state :parked, :idling
|
647
|
+
@machine.event :ignite
|
578
648
|
@record = @model.new(:state => 'parked')
|
579
649
|
@transition = StateMachine::Transition.new(@record, @machine, :ignite, :parked, :idling)
|
580
650
|
end
|
581
651
|
|
582
|
-
def
|
583
|
-
|
584
|
-
|
585
|
-
|
586
|
-
|
587
|
-
|
588
|
-
|
652
|
+
def test_should_call_all_transition_callback_permutations
|
653
|
+
callbacks = [
|
654
|
+
:before_ignite_from_parked_to_idling,
|
655
|
+
:before_ignite_from_parked,
|
656
|
+
:before_ignite_to_idling,
|
657
|
+
:before_ignite,
|
658
|
+
:before_transition_state_from_parked_to_idling,
|
659
|
+
:before_transition_state_from_parked,
|
660
|
+
:before_transition_state_to_idling,
|
661
|
+
:before_transition_state,
|
662
|
+
:before_transition
|
663
|
+
]
|
589
664
|
|
590
|
-
|
591
|
-
assert_equal [[@record, @transition]], instance.notifications
|
592
|
-
end
|
593
|
-
|
594
|
-
def test_should_call_before_transition_method
|
665
|
+
notified = false
|
595
666
|
observer = new_observer(@model) do
|
596
|
-
|
597
|
-
|
667
|
+
callbacks.each do |callback|
|
668
|
+
define_method(callback) do |*args|
|
669
|
+
notifications << callback
|
670
|
+
end
|
598
671
|
end
|
599
672
|
end
|
673
|
+
|
600
674
|
instance = observer.instance
|
601
675
|
|
602
676
|
@transition.perform
|
603
|
-
assert_equal
|
677
|
+
assert_equal callbacks, instance.notifications
|
604
678
|
end
|
605
679
|
|
606
|
-
def
|
680
|
+
def test_should_pass_record_and_transition_to_before_callbacks
|
607
681
|
observer = new_observer(@model) do
|
608
|
-
def
|
682
|
+
def before_transition(*args)
|
609
683
|
notifications << args
|
610
684
|
end
|
611
685
|
end
|
@@ -615,7 +689,7 @@ begin
|
|
615
689
|
assert_equal [[@record, @transition]], instance.notifications
|
616
690
|
end
|
617
691
|
|
618
|
-
def
|
692
|
+
def test_should_pass_record_and_transition_to_after_callbacks
|
619
693
|
observer = new_observer(@model) do
|
620
694
|
def after_transition(*args)
|
621
695
|
notifications << args
|
@@ -627,22 +701,6 @@ begin
|
|
627
701
|
assert_equal [[@record, @transition]], instance.notifications
|
628
702
|
end
|
629
703
|
|
630
|
-
def test_should_call_event_method_before_transition_method
|
631
|
-
observer = new_observer(@model) do
|
632
|
-
def before_ignite(*args)
|
633
|
-
notifications << :before_ignite
|
634
|
-
end
|
635
|
-
|
636
|
-
def before_transition(*args)
|
637
|
-
notifications << :before_transition
|
638
|
-
end
|
639
|
-
end
|
640
|
-
instance = observer.instance
|
641
|
-
|
642
|
-
@transition.perform
|
643
|
-
assert_equal [:before_ignite, :before_transition], instance.notifications
|
644
|
-
end
|
645
|
-
|
646
704
|
def test_should_call_methods_outside_the_context_of_the_record
|
647
705
|
observer = new_observer(@model) do
|
648
706
|
def before_ignite(*args)
|
@@ -659,15 +717,16 @@ begin
|
|
659
717
|
class MachineWithNamespacedObserversTest < ActiveRecord::TestCase
|
660
718
|
def setup
|
661
719
|
@model = new_model
|
662
|
-
@machine = StateMachine::Machine.new(@model, :namespace => '
|
663
|
-
@machine.state :
|
664
|
-
@
|
665
|
-
@
|
720
|
+
@machine = StateMachine::Machine.new(@model, :state, :namespace => 'alarm')
|
721
|
+
@machine.state :active, :off
|
722
|
+
@machine.event :enable
|
723
|
+
@record = @model.new(:state => 'off')
|
724
|
+
@transition = StateMachine::Transition.new(@record, @machine, :enable, :off, :active)
|
666
725
|
end
|
667
726
|
|
668
727
|
def test_should_call_namespaced_before_event_method
|
669
728
|
observer = new_observer(@model) do
|
670
|
-
def
|
729
|
+
def before_enable_alarm(*args)
|
671
730
|
notifications << args
|
672
731
|
end
|
673
732
|
end
|
@@ -679,7 +738,7 @@ begin
|
|
679
738
|
|
680
739
|
def test_should_call_namespaced_after_event_method
|
681
740
|
observer = new_observer(@model) do
|
682
|
-
def
|
741
|
+
def after_enable_alarm(*args)
|
683
742
|
notifications << args
|
684
743
|
end
|
685
744
|
end
|
@@ -695,6 +754,7 @@ begin
|
|
695
754
|
@model = new_model
|
696
755
|
@machine = StateMachine::Machine.new(@model)
|
697
756
|
@machine.state :parked, :idling
|
757
|
+
@machine.event :ignite
|
698
758
|
@record = @model.new(:state => 'parked')
|
699
759
|
@transition = StateMachine::Transition.new(@record, @machine, :ignite, :parked, :idling)
|
700
760
|
|
@@ -758,7 +818,7 @@ begin
|
|
758
818
|
:activerecord => {
|
759
819
|
:errors => {
|
760
820
|
:messages => {
|
761
|
-
:invalid_transition => 'cannot {{event}}
|
821
|
+
:invalid_transition => 'cannot {{event}}'
|
762
822
|
}
|
763
823
|
}
|
764
824
|
}
|
@@ -770,8 +830,8 @@ begin
|
|
770
830
|
|
771
831
|
record = @model.new(:state => 'idling')
|
772
832
|
|
773
|
-
machine.invalidate(record, event)
|
774
|
-
assert_equal 'cannot ignite
|
833
|
+
machine.invalidate(record, :state, :invalid_transition, [[:event, :ignite]])
|
834
|
+
assert_equal 'cannot ignite', record.errors.on(:state)
|
775
835
|
end
|
776
836
|
|
777
837
|
def test_should_invalidate_using_customized_i18n_key_if_specified
|
@@ -779,32 +839,30 @@ begin
|
|
779
839
|
:activerecord => {
|
780
840
|
:errors => {
|
781
841
|
:messages => {
|
782
|
-
:bad_transition => 'cannot {{event}}
|
842
|
+
:bad_transition => 'cannot {{event}}'
|
783
843
|
}
|
784
844
|
}
|
785
845
|
}
|
786
846
|
})
|
787
847
|
|
788
|
-
machine = StateMachine::Machine.new(@model, :
|
848
|
+
machine = StateMachine::Machine.new(@model, :messages => {:invalid_transition => :bad_transition})
|
789
849
|
machine.state :parked, :idling
|
790
|
-
event = StateMachine::Event.new(machine, :ignite)
|
791
850
|
|
792
851
|
record = @model.new(:state => 'idling')
|
793
852
|
|
794
|
-
machine.invalidate(record, event)
|
795
|
-
assert_equal 'cannot ignite
|
853
|
+
machine.invalidate(record, :state, :invalid_transition, [[:event, :ignite]])
|
854
|
+
assert_equal 'cannot ignite', record.errors.on(:state)
|
796
855
|
end
|
797
856
|
end
|
798
857
|
|
799
858
|
def test_should_invalidate_using_customized_i18n_string_if_specified
|
800
|
-
machine = StateMachine::Machine.new(@model, :
|
859
|
+
machine = StateMachine::Machine.new(@model, :messages => {:invalid_transition => 'cannot {{event}}'})
|
801
860
|
machine.state :parked, :idling
|
802
|
-
event = StateMachine::Event.new(machine, :ignite)
|
803
861
|
|
804
862
|
record = @model.new(:state => 'idling')
|
805
863
|
|
806
|
-
machine.invalidate(record, event)
|
807
|
-
assert_equal 'cannot ignite
|
864
|
+
machine.invalidate(record, :state, :invalid_transition, [[:event, :ignite]])
|
865
|
+
assert_equal 'cannot ignite', record.errors.on(:state)
|
808
866
|
end
|
809
867
|
else
|
810
868
|
$stderr.puts 'Skipping ActiveRecord I18n tests. `gem install active_record` >= v2.2.0 and try again.'
|