state_machine 0.6.3 → 0.7.0
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 +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.'
|