state_machine 0.4.1 → 0.4.2
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 +8 -0
- data/README.rdoc +55 -1
- data/Rakefile +1 -1
- 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/lib/state_machine.rb +146 -9
- data/lib/state_machine/assertions.rb +1 -1
- data/lib/state_machine/callback.rb +3 -2
- data/lib/state_machine/event.rb +21 -10
- data/lib/state_machine/extensions.rb +14 -56
- data/lib/state_machine/guard.rb +36 -1
- data/lib/state_machine/integrations/active_record.rb +2 -1
- data/lib/state_machine/integrations/data_mapper/observer.rb +14 -0
- data/lib/state_machine/machine.rb +215 -108
- data/lib/state_machine/state.rb +175 -0
- data/test/active_record.log +35152 -0
- data/test/data_mapper.log +9296 -0
- data/test/functional/state_machine_test.rb +106 -0
- data/test/sequel.log +5208 -0
- data/test/unit/event_test.rb +35 -0
- data/test/unit/guard_test.rb +140 -0
- data/test/unit/integrations/active_record_test.rb +34 -1
- data/test/unit/machine_test.rb +273 -72
- data/test/unit/state_test.rb +583 -0
- metadata +7 -3
- data/examples/Car_state.jpg +0 -0
data/test/unit/event_test.rb
CHANGED
|
@@ -400,3 +400,38 @@ class EventWithMultipleTransitionsTest < Test::Unit::TestCase
|
|
|
400
400
|
assert_equal 'on', @object.state
|
|
401
401
|
end
|
|
402
402
|
end
|
|
403
|
+
|
|
404
|
+
begin
|
|
405
|
+
# Load library
|
|
406
|
+
require 'rubygems'
|
|
407
|
+
require 'graphviz'
|
|
408
|
+
|
|
409
|
+
class EventDrawingTest < Test::Unit::TestCase
|
|
410
|
+
def setup
|
|
411
|
+
states = %w(parked idling first_gear)
|
|
412
|
+
|
|
413
|
+
@machine = StateMachine::Machine.new(Class.new, :initial => 'parked')
|
|
414
|
+
@machine.other_states(states)
|
|
415
|
+
|
|
416
|
+
graph = GraphViz.new('G')
|
|
417
|
+
states.each {|state| graph.add_node(state)}
|
|
418
|
+
|
|
419
|
+
@event = StateMachine::Event.new(@machine , 'park')
|
|
420
|
+
@event.transition :from => 'idling', :to => 'parked'
|
|
421
|
+
@event.transition :from => 'first_gear', :to => 'parked'
|
|
422
|
+
@event.transition :except_from => 'parked', :to => 'parked'
|
|
423
|
+
|
|
424
|
+
@edges = @event.draw(graph)
|
|
425
|
+
end
|
|
426
|
+
|
|
427
|
+
def test_should_generate_edges_for_each_transition
|
|
428
|
+
assert_equal 4, @edges.size
|
|
429
|
+
end
|
|
430
|
+
|
|
431
|
+
def test_should_use_event_name_for_edge_label
|
|
432
|
+
assert_equal 'park', @edges.first['label']
|
|
433
|
+
end
|
|
434
|
+
end
|
|
435
|
+
rescue LoadError
|
|
436
|
+
$stderr.puts 'Skipping GraphViz StateMachine::Guard tests. `gem install ruby-graphviz` and try again.'
|
|
437
|
+
end
|
data/test/unit/guard_test.rb
CHANGED
|
@@ -481,3 +481,143 @@ class GuardWithConflictingConditionalsTest < Test::Unit::TestCase
|
|
|
481
481
|
assert !guard.matches?(@object)
|
|
482
482
|
end
|
|
483
483
|
end
|
|
484
|
+
|
|
485
|
+
begin
|
|
486
|
+
# Load library
|
|
487
|
+
require 'rubygems'
|
|
488
|
+
require 'graphviz'
|
|
489
|
+
|
|
490
|
+
class GuardDrawingTest < Test::Unit::TestCase
|
|
491
|
+
def setup
|
|
492
|
+
@machine = StateMachine::Machine.new(Class.new)
|
|
493
|
+
states = %w(parked idling)
|
|
494
|
+
|
|
495
|
+
graph = GraphViz.new('G')
|
|
496
|
+
states.each {|state| graph.add_node(state)}
|
|
497
|
+
|
|
498
|
+
@guard = StateMachine::Guard.new(:from => 'idling', :to => 'parked')
|
|
499
|
+
@edges = @guard.draw(graph, 'park', states)
|
|
500
|
+
end
|
|
501
|
+
|
|
502
|
+
def test_should_create_edges
|
|
503
|
+
assert_equal 1, @edges.size
|
|
504
|
+
end
|
|
505
|
+
|
|
506
|
+
def test_should_use_from_state_from_start_node
|
|
507
|
+
assert_equal 'idling', @edges.first.instance_variable_get('@xNodeOne')
|
|
508
|
+
end
|
|
509
|
+
|
|
510
|
+
def test_should_use_to_state_for_end_node
|
|
511
|
+
assert_equal 'parked', @edges.first.instance_variable_get('@xNodeTwo')
|
|
512
|
+
end
|
|
513
|
+
|
|
514
|
+
def test_should_use_event_name_as_label
|
|
515
|
+
assert_equal 'park', @edges.first['label']
|
|
516
|
+
end
|
|
517
|
+
end
|
|
518
|
+
|
|
519
|
+
class GuardDrawingWithFromRequirementTest < Test::Unit::TestCase
|
|
520
|
+
def setup
|
|
521
|
+
@machine = StateMachine::Machine.new(Class.new)
|
|
522
|
+
states = %w(parked idling first_gear)
|
|
523
|
+
|
|
524
|
+
graph = GraphViz.new('G')
|
|
525
|
+
states.each {|state| graph.add_node(state)}
|
|
526
|
+
|
|
527
|
+
@guard = StateMachine::Guard.new(:from => %w(idling first_gear), :to => 'parked')
|
|
528
|
+
@edges = @guard.draw(graph, 'park', states)
|
|
529
|
+
end
|
|
530
|
+
|
|
531
|
+
def test_should_generate_edges_for_each_valid_from_state
|
|
532
|
+
%w(idling first_gear).each_with_index do |from_state, index|
|
|
533
|
+
edge = @edges[index]
|
|
534
|
+
assert_equal from_state, edge.instance_variable_get('@xNodeOne')
|
|
535
|
+
assert_equal 'parked', edge.instance_variable_get('@xNodeTwo')
|
|
536
|
+
end
|
|
537
|
+
end
|
|
538
|
+
end
|
|
539
|
+
|
|
540
|
+
class GuardDrawingWithExceptFromRequirementTest < Test::Unit::TestCase
|
|
541
|
+
def setup
|
|
542
|
+
@machine = StateMachine::Machine.new(Class.new)
|
|
543
|
+
states = %w(parked idling first_gear)
|
|
544
|
+
|
|
545
|
+
graph = GraphViz.new('G')
|
|
546
|
+
states.each {|state| graph.add_node(state)}
|
|
547
|
+
|
|
548
|
+
@guard = StateMachine::Guard.new(:except_from => 'parked', :to => 'parked')
|
|
549
|
+
@edges = @guard.draw(graph, 'park', states)
|
|
550
|
+
end
|
|
551
|
+
|
|
552
|
+
def test_should_generate_edges_for_each_valid_from_state
|
|
553
|
+
%w(idling first_gear).each_with_index do |from_state, index|
|
|
554
|
+
edge = @edges[index]
|
|
555
|
+
assert_equal from_state, edge.instance_variable_get('@xNodeOne')
|
|
556
|
+
assert_equal 'parked', edge.instance_variable_get('@xNodeTwo')
|
|
557
|
+
end
|
|
558
|
+
end
|
|
559
|
+
end
|
|
560
|
+
|
|
561
|
+
class GuardDrawingWithoutFromRequirementTest < Test::Unit::TestCase
|
|
562
|
+
def setup
|
|
563
|
+
@machine = StateMachine::Machine.new(Class.new)
|
|
564
|
+
states = %w(parked idling first_gear)
|
|
565
|
+
|
|
566
|
+
graph = GraphViz.new('G')
|
|
567
|
+
states.each {|state| graph.add_node(state)}
|
|
568
|
+
|
|
569
|
+
@guard = StateMachine::Guard.new(:to => 'parked')
|
|
570
|
+
@edges = @guard.draw(graph, 'park', states)
|
|
571
|
+
end
|
|
572
|
+
|
|
573
|
+
def test_should_generate_edges_for_each_valid_from_state
|
|
574
|
+
%w(parked idling first_gear).each_with_index do |from_state, index|
|
|
575
|
+
edge = @edges[index]
|
|
576
|
+
assert_equal from_state, edge.instance_variable_get('@xNodeOne')
|
|
577
|
+
assert_equal 'parked', edge.instance_variable_get('@xNodeTwo')
|
|
578
|
+
end
|
|
579
|
+
end
|
|
580
|
+
end
|
|
581
|
+
|
|
582
|
+
class GuardDrawingWithoutToRequirementTest < Test::Unit::TestCase
|
|
583
|
+
def setup
|
|
584
|
+
@machine = StateMachine::Machine.new(Class.new)
|
|
585
|
+
|
|
586
|
+
graph = GraphViz.new('G')
|
|
587
|
+
graph.add_node('parked')
|
|
588
|
+
|
|
589
|
+
@guard = StateMachine::Guard.new(:from => 'parked')
|
|
590
|
+
@edges = @guard.draw(graph, 'park', ['parked'])
|
|
591
|
+
end
|
|
592
|
+
|
|
593
|
+
def test_should_create_loopback_edge
|
|
594
|
+
assert_equal 'parked', @edges.first.instance_variable_get('@xNodeOne')
|
|
595
|
+
assert_equal 'parked', @edges.first.instance_variable_get('@xNodeTwo')
|
|
596
|
+
end
|
|
597
|
+
end
|
|
598
|
+
|
|
599
|
+
class GuardWithProcStatesTest < Test::Unit::TestCase
|
|
600
|
+
def setup
|
|
601
|
+
@machine = StateMachine::Machine.new(Class.new)
|
|
602
|
+
@from_state = lambda {}
|
|
603
|
+
@to_state = lambda {}
|
|
604
|
+
states = [@from_state, @to_state]
|
|
605
|
+
|
|
606
|
+
graph = GraphViz.new('G')
|
|
607
|
+
states.each {|state| graph.add_node("lambda#{state.object_id.abs}")}
|
|
608
|
+
|
|
609
|
+
@guard = StateMachine::Guard.new(:from => @from_state, :to => @to_state)
|
|
610
|
+
@edges = @guard.draw(graph, 'park', states)
|
|
611
|
+
end
|
|
612
|
+
|
|
613
|
+
def test_should_use_state_id_for_from_state
|
|
614
|
+
assert_equal "lambda#{@from_state.object_id.abs}", @edges.first.instance_variable_get('@xNodeOne')
|
|
615
|
+
end
|
|
616
|
+
|
|
617
|
+
def test_should_use_state_id_for_to_state
|
|
618
|
+
assert_equal "lambda#{@to_state.object_id.abs}", @edges.first.instance_variable_get('@xNodeTwo')
|
|
619
|
+
end
|
|
620
|
+
end
|
|
621
|
+
rescue LoadError
|
|
622
|
+
$stderr.puts 'Skipping GraphViz StateMachine::Guard tests. `gem install ruby-graphviz` and try again.'
|
|
623
|
+
end
|
|
@@ -341,7 +341,7 @@ begin
|
|
|
341
341
|
def test_should_include_transition_states_in_known_states
|
|
342
342
|
@machine.before_transition :to => 'error', :do => lambda {}
|
|
343
343
|
|
|
344
|
-
assert_equal %w(error off), @machine.states.sort
|
|
344
|
+
assert_equal %w(error off), @machine.states.keys.sort
|
|
345
345
|
end
|
|
346
346
|
end
|
|
347
347
|
|
|
@@ -515,6 +515,39 @@ begin
|
|
|
515
515
|
end
|
|
516
516
|
end
|
|
517
517
|
|
|
518
|
+
class MachineWithNamespacedObserversTest < ActiveRecord::TestCase
|
|
519
|
+
def setup
|
|
520
|
+
@model = new_model
|
|
521
|
+
@machine = StateMachine::Machine.new(@model, :namespace => 'switch')
|
|
522
|
+
@record = @model.new(:state => 'off')
|
|
523
|
+
@transition = StateMachine::Transition.new(@record, @machine, 'turn_on', 'off', 'on')
|
|
524
|
+
end
|
|
525
|
+
|
|
526
|
+
def test_should_call_namespaced_before_event_method
|
|
527
|
+
observer = new_observer(@model) do
|
|
528
|
+
def before_turn_on_switch(*args)
|
|
529
|
+
notifications << args
|
|
530
|
+
end
|
|
531
|
+
end
|
|
532
|
+
instance = observer.instance
|
|
533
|
+
|
|
534
|
+
@transition.perform
|
|
535
|
+
assert_equal [[@record, @transition]], instance.notifications
|
|
536
|
+
end
|
|
537
|
+
|
|
538
|
+
def test_should_call_namespaced_after_event_method
|
|
539
|
+
observer = new_observer(@model) do
|
|
540
|
+
def after_turn_on_switch(*args)
|
|
541
|
+
notifications << args
|
|
542
|
+
end
|
|
543
|
+
end
|
|
544
|
+
instance = observer.instance
|
|
545
|
+
|
|
546
|
+
@transition.perform
|
|
547
|
+
assert_equal [[@record, @transition]], instance.notifications
|
|
548
|
+
end
|
|
549
|
+
end
|
|
550
|
+
|
|
518
551
|
class MachineWithMixedCallbacksTest < ActiveRecord::TestCase
|
|
519
552
|
def setup
|
|
520
553
|
@model = new_model
|
data/test/unit/machine_test.rb
CHANGED
|
@@ -36,7 +36,11 @@ class MachineByDefaultTest < Test::Unit::TestCase
|
|
|
36
36
|
end
|
|
37
37
|
|
|
38
38
|
def test_should_have_a_nil_state
|
|
39
|
-
assert_equal [nil], @machine.states
|
|
39
|
+
assert_equal [nil], @machine.states.keys
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def test_should_set_initial_on_nil_state
|
|
43
|
+
assert @machine.state(nil).initial
|
|
40
44
|
end
|
|
41
45
|
|
|
42
46
|
def test_should_not_be_extended_by_the_active_record_integration
|
|
@@ -122,6 +126,7 @@ class MachineWithStaticInitialStateTest < Test::Unit::TestCase
|
|
|
122
126
|
@klass = Class.new do
|
|
123
127
|
def initialize(attributes = {})
|
|
124
128
|
attributes.each {|attr, value| send("#{attr}=", value)}
|
|
129
|
+
super()
|
|
125
130
|
end
|
|
126
131
|
end
|
|
127
132
|
|
|
@@ -133,6 +138,10 @@ class MachineWithStaticInitialStateTest < Test::Unit::TestCase
|
|
|
133
138
|
assert_equal 'off', @machine.initial_state(object)
|
|
134
139
|
end
|
|
135
140
|
|
|
141
|
+
def test_should_set_initial_on_state_object
|
|
142
|
+
assert @machine.state('off').initial
|
|
143
|
+
end
|
|
144
|
+
|
|
136
145
|
def test_should_set_initial_state_if_existing_is_nil
|
|
137
146
|
object = @klass.new(:state => nil)
|
|
138
147
|
assert_equal 'off', object.state
|
|
@@ -149,7 +158,33 @@ class MachineWithStaticInitialStateTest < Test::Unit::TestCase
|
|
|
149
158
|
end
|
|
150
159
|
|
|
151
160
|
def test_should_be_included_in_known_states
|
|
152
|
-
assert_equal %w(off), @machine.states
|
|
161
|
+
assert_equal %w(off), @machine.states.keys
|
|
162
|
+
end
|
|
163
|
+
|
|
164
|
+
def test_should_order_state_before_transition_states
|
|
165
|
+
@machine.event :turn_on do
|
|
166
|
+
transition :from => 'off', :to => 'on'
|
|
167
|
+
end
|
|
168
|
+
assert_equal %w(off on), @machine.states_order
|
|
169
|
+
end
|
|
170
|
+
|
|
171
|
+
def test_should_order_state_before_states_with_behaviors
|
|
172
|
+
@machine.state 'error' do
|
|
173
|
+
def color
|
|
174
|
+
'red'
|
|
175
|
+
end
|
|
176
|
+
end
|
|
177
|
+
assert_equal %w(off error), @machine.states_order
|
|
178
|
+
end
|
|
179
|
+
|
|
180
|
+
def test_should_order_state_before_other_states
|
|
181
|
+
@machine.other_states 'on'
|
|
182
|
+
assert_equal %w(off on), @machine.states_order
|
|
183
|
+
end
|
|
184
|
+
|
|
185
|
+
def test_should_order_state_before_callback_states
|
|
186
|
+
@machine.before_transition :from => 'on', :do => lambda {}
|
|
187
|
+
assert_equal %w(off on), @machine.states_order
|
|
153
188
|
end
|
|
154
189
|
end
|
|
155
190
|
|
|
@@ -176,7 +211,7 @@ class MachineWithDynamicInitialStateTest < Test::Unit::TestCase
|
|
|
176
211
|
end
|
|
177
212
|
|
|
178
213
|
def test_should_be_included_in_known_states
|
|
179
|
-
assert_equal [@initial_state], @machine.states
|
|
214
|
+
assert_equal [@initial_state], @machine.states.keys
|
|
180
215
|
end
|
|
181
216
|
end
|
|
182
217
|
|
|
@@ -314,7 +349,7 @@ end
|
|
|
314
349
|
|
|
315
350
|
class MachineAfterBeingCopiedTest < Test::Unit::TestCase
|
|
316
351
|
def setup
|
|
317
|
-
@machine = StateMachine::Machine.new(Class.new, 'state')
|
|
352
|
+
@machine = StateMachine::Machine.new(Class.new, 'state', :initial => 'off')
|
|
318
353
|
@machine.event(:turn_on) {}
|
|
319
354
|
@machine.before_transition(lambda {})
|
|
320
355
|
@machine.after_transition(lambda {})
|
|
@@ -327,6 +362,18 @@ class MachineAfterBeingCopiedTest < Test::Unit::TestCase
|
|
|
327
362
|
assert_not_same @copied_machine.states, @machine.states
|
|
328
363
|
end
|
|
329
364
|
|
|
365
|
+
def test_should_copy_each_state
|
|
366
|
+
assert_not_same @copied_machine.states['off'], @machine.states['off']
|
|
367
|
+
end
|
|
368
|
+
|
|
369
|
+
def test_should_update_machine_for_each_state
|
|
370
|
+
assert_equal @copied_machine, @copied_machine.states['off'].machine
|
|
371
|
+
end
|
|
372
|
+
|
|
373
|
+
def test_should_not_update_machine_for_original_state
|
|
374
|
+
assert_equal @machine, @machine.states['off'].machine
|
|
375
|
+
end
|
|
376
|
+
|
|
330
377
|
def test_should_not_have_the_same_collection_of_events
|
|
331
378
|
assert_not_same @copied_machine.events, @machine.events
|
|
332
379
|
end
|
|
@@ -343,6 +390,10 @@ class MachineAfterBeingCopiedTest < Test::Unit::TestCase
|
|
|
343
390
|
assert_equal @machine, @machine.events['turn_on'].machine
|
|
344
391
|
end
|
|
345
392
|
|
|
393
|
+
def test_should_not_have_the_same_events_order
|
|
394
|
+
assert_not_same @copied_machine.events_order, @machine.events_order
|
|
395
|
+
end
|
|
396
|
+
|
|
346
397
|
def test_should_not_have_the_same_callbacks
|
|
347
398
|
assert_not_same @copied_machine.callbacks, @machine.callbacks
|
|
348
399
|
end
|
|
@@ -379,9 +430,16 @@ class MachineAfterChangingContextTest < Test::Unit::TestCase
|
|
|
379
430
|
assert_equal @original_class, @machine.owner_class
|
|
380
431
|
end
|
|
381
432
|
|
|
433
|
+
def test_should_still_have_an_initial_state
|
|
434
|
+
assert @new_machine.states[nil].initial
|
|
435
|
+
end
|
|
436
|
+
|
|
382
437
|
def test_should_allow_changing_the_initial_state
|
|
383
438
|
new_machine = @machine.within_context(@new_class, :initial => 'off')
|
|
439
|
+
|
|
384
440
|
assert_equal 'off', new_machine.initial_state(@object)
|
|
441
|
+
assert new_machine.state('off').initial
|
|
442
|
+
assert !new_machine.state(nil).initial
|
|
385
443
|
end
|
|
386
444
|
|
|
387
445
|
def test_should_not_change_original_initial_state_if_updated
|
|
@@ -495,28 +553,6 @@ class MachineWithConflictingPrivateAttributeAccessorsTest < Test::Unit::TestCase
|
|
|
495
553
|
end
|
|
496
554
|
end
|
|
497
555
|
|
|
498
|
-
class MachineWithConflictingStatePredicatesTest < Test::Unit::TestCase
|
|
499
|
-
def setup
|
|
500
|
-
@klass = Class.new do
|
|
501
|
-
def on?
|
|
502
|
-
true
|
|
503
|
-
end
|
|
504
|
-
|
|
505
|
-
def off?
|
|
506
|
-
true
|
|
507
|
-
end
|
|
508
|
-
end
|
|
509
|
-
@machine = StateMachine::Machine.new(@klass)
|
|
510
|
-
@machine.before_transition :to => 'on', :from => 'off', :do => lambda {}
|
|
511
|
-
@object = @klass.new
|
|
512
|
-
end
|
|
513
|
-
|
|
514
|
-
def test_should_not_define_state_predicates
|
|
515
|
-
assert @object.on?
|
|
516
|
-
assert @object.off?
|
|
517
|
-
end
|
|
518
|
-
end
|
|
519
|
-
|
|
520
556
|
class MachineWithConflictingScopesTest < Test::Unit::TestCase
|
|
521
557
|
def setup
|
|
522
558
|
@klass = Class.new do
|
|
@@ -591,9 +627,13 @@ class MachineWithEventsTest < Test::Unit::TestCase
|
|
|
591
627
|
end
|
|
592
628
|
|
|
593
629
|
def test_should_have_events
|
|
594
|
-
@machine.event(:turn_on)
|
|
630
|
+
@machine.event(:turn_on)
|
|
595
631
|
assert_equal %w(turn_on), @machine.events.keys
|
|
596
632
|
end
|
|
633
|
+
|
|
634
|
+
def test_should_return_the_created_event
|
|
635
|
+
assert_instance_of StateMachine::Event, @machine.event(:turn_on)
|
|
636
|
+
end
|
|
597
637
|
end
|
|
598
638
|
|
|
599
639
|
class MachineWithConflictingPredefinedInitializeTest < Test::Unit::TestCase
|
|
@@ -605,6 +645,7 @@ class MachineWithConflictingPredefinedInitializeTest < Test::Unit::TestCase
|
|
|
605
645
|
def initialize
|
|
606
646
|
@initialized = true
|
|
607
647
|
@block_given = block_given?
|
|
648
|
+
super()
|
|
608
649
|
end
|
|
609
650
|
end
|
|
610
651
|
|
|
@@ -640,6 +681,7 @@ class MachineWithConflictingPostdefinedInitializeTest < Test::Unit::TestCase
|
|
|
640
681
|
def initialize
|
|
641
682
|
@initialized = true
|
|
642
683
|
@block_given = block_given?
|
|
684
|
+
super()
|
|
643
685
|
end
|
|
644
686
|
end
|
|
645
687
|
|
|
@@ -776,6 +818,23 @@ class MachineWithConflictingPostdefinedAndSuperclassInitializeTest < Test::Unit:
|
|
|
776
818
|
end
|
|
777
819
|
end
|
|
778
820
|
|
|
821
|
+
class MachineWithCustomStateMachineInitializationTest < Test::Unit::TestCase
|
|
822
|
+
def setup
|
|
823
|
+
@superclass = Class.new do
|
|
824
|
+
def initialize
|
|
825
|
+
initialize_state_machines
|
|
826
|
+
end
|
|
827
|
+
end
|
|
828
|
+
@klass = Class.new(@superclass)
|
|
829
|
+
@machine = StateMachine::Machine.new(@klass, :initial => 'off')
|
|
830
|
+
@object = @klass.new {}
|
|
831
|
+
end
|
|
832
|
+
|
|
833
|
+
def test_should_still_initialize_state
|
|
834
|
+
assert_equal 'off', @object.state
|
|
835
|
+
end
|
|
836
|
+
end
|
|
837
|
+
|
|
779
838
|
class MachineWithConflictingMethodAddedTest < Test::Unit::TestCase
|
|
780
839
|
def setup
|
|
781
840
|
@klass = Class.new do
|
|
@@ -817,16 +876,52 @@ class MachineWithExistingAttributeValue < Test::Unit::TestCase
|
|
|
817
876
|
end
|
|
818
877
|
end
|
|
819
878
|
|
|
879
|
+
class MachineWithStateDrivenBehaviorsTest < Test::Unit::TestCase
|
|
880
|
+
def setup
|
|
881
|
+
@machine = StateMachine::Machine.new(Class.new, :initial => 'off')
|
|
882
|
+
@machine.state 'on' do
|
|
883
|
+
def color
|
|
884
|
+
'green'
|
|
885
|
+
end
|
|
886
|
+
end
|
|
887
|
+
end
|
|
888
|
+
|
|
889
|
+
def test_should_order_states_after_initial_state
|
|
890
|
+
assert_equal %w(off on), @machine.states_order
|
|
891
|
+
end
|
|
892
|
+
|
|
893
|
+
def test_should_order_states_after_transition_states
|
|
894
|
+
@machine.event :turn_on do
|
|
895
|
+
transition :to => 'error'
|
|
896
|
+
end
|
|
897
|
+
assert_equal %w(off error on), @machine.states_order
|
|
898
|
+
end
|
|
899
|
+
|
|
900
|
+
def test_should_order_states_before_other_states
|
|
901
|
+
@machine.other_states 'error'
|
|
902
|
+
assert_equal %w(off on error), @machine.states_order
|
|
903
|
+
end
|
|
904
|
+
|
|
905
|
+
def test_should_order_state_before_callback_states
|
|
906
|
+
@machine.before_transition :to => 'error', :do => lambda {}
|
|
907
|
+
assert_equal %w(off on error), @machine.states_order
|
|
908
|
+
end
|
|
909
|
+
end
|
|
910
|
+
|
|
820
911
|
class MachineWithExistingEventTest < Test::Unit::TestCase
|
|
821
912
|
def setup
|
|
822
913
|
@machine = StateMachine::Machine.new(Class.new)
|
|
823
|
-
@event = @machine.event(:turn_on)
|
|
824
|
-
@same_event = @machine.event(:turn_on)
|
|
914
|
+
@event = @machine.event(:turn_on)
|
|
915
|
+
@same_event = @machine.event(:turn_on)
|
|
825
916
|
end
|
|
826
917
|
|
|
827
918
|
def test_should_not_create_new_event
|
|
828
919
|
assert_same @event, @same_event
|
|
829
920
|
end
|
|
921
|
+
|
|
922
|
+
def test_should_allow_accessing_event_without_block
|
|
923
|
+
assert_equal @event, @machine.event(:turn_on)
|
|
924
|
+
end
|
|
830
925
|
end
|
|
831
926
|
|
|
832
927
|
class MachineWithEventsWithTransitionsTest < Test::Unit::TestCase
|
|
@@ -844,7 +939,7 @@ class MachineWithEventsWithTransitionsTest < Test::Unit::TestCase
|
|
|
844
939
|
end
|
|
845
940
|
|
|
846
941
|
def test_should_track_states_defined_in_event_transitions
|
|
847
|
-
assert_equal %w(error off on unknown), @machine.states.sort
|
|
942
|
+
assert_equal %w(error off on unknown), @machine.states.keys.sort
|
|
848
943
|
end
|
|
849
944
|
|
|
850
945
|
def test_should_not_duplicate_states_defined_in_multiple_event_transitions
|
|
@@ -852,7 +947,7 @@ class MachineWithEventsWithTransitionsTest < Test::Unit::TestCase
|
|
|
852
947
|
transition :to => 'off', :from => 'on'
|
|
853
948
|
end
|
|
854
949
|
|
|
855
|
-
assert_equal %w(error off on unknown), @machine.states.sort
|
|
950
|
+
assert_equal %w(error off on unknown), @machine.states.keys.sort
|
|
856
951
|
end
|
|
857
952
|
|
|
858
953
|
def test_should_track_state_from_new_events
|
|
@@ -861,61 +956,67 @@ class MachineWithEventsWithTransitionsTest < Test::Unit::TestCase
|
|
|
861
956
|
transition :to => 'maybe'
|
|
862
957
|
end
|
|
863
958
|
|
|
864
|
-
assert_equal %w(error maybe off on unknown), @machine.states.sort
|
|
959
|
+
assert_equal %w(error maybe off on unknown), @machine.states.keys.sort
|
|
865
960
|
end
|
|
866
961
|
|
|
867
|
-
def
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
[:on?, :off?, :error?, :unknown?].each {|predicate| assert object.respond_to?(predicate)}
|
|
962
|
+
def test_should_order_states_after_initial_state
|
|
963
|
+
assert_equal %w(off on error unknown), @machine.states_order
|
|
871
964
|
end
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
@machine.event(:turn_on) do
|
|
879
|
-
transition :to => :on, :from => :off
|
|
965
|
+
|
|
966
|
+
def test_should_order_states_before_states_with_behaviors
|
|
967
|
+
@machine.state 'tripped' do
|
|
968
|
+
def color
|
|
969
|
+
'red'
|
|
970
|
+
end
|
|
880
971
|
end
|
|
972
|
+
assert_equal %w(off on error unknown tripped), @machine.states_order
|
|
881
973
|
end
|
|
882
974
|
|
|
883
|
-
def
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
975
|
+
def test_should_order_states_before_other_states
|
|
976
|
+
@machine.other_states 'tripped'
|
|
977
|
+
assert_equal %w(off on error unknown tripped), @machine.states_order
|
|
978
|
+
end
|
|
979
|
+
|
|
980
|
+
def test_should_order_state_before_callback_states
|
|
981
|
+
@machine.before_transition :to => 'tripped', :do => lambda {}
|
|
982
|
+
assert_equal %w(off on error unknown tripped), @machine.states_order
|
|
887
983
|
end
|
|
888
984
|
end
|
|
889
985
|
|
|
890
|
-
class
|
|
986
|
+
class MachineWithMultipleEventsTest < Test::Unit::TestCase
|
|
891
987
|
def setup
|
|
892
988
|
@klass = Class.new
|
|
893
|
-
@machine = StateMachine::Machine.new(@klass)
|
|
894
|
-
@machine.event(:turn_on) do
|
|
895
|
-
transition :to =>
|
|
989
|
+
@machine = StateMachine::Machine.new(@klass, :initial => 'off')
|
|
990
|
+
@result = @machine.event(:turn_on, :activate) do
|
|
991
|
+
transition :to => 'on', :from => 'off'
|
|
896
992
|
end
|
|
897
993
|
end
|
|
898
994
|
|
|
899
|
-
def
|
|
995
|
+
def test_should_have_events
|
|
996
|
+
assert_equal %w(activate turn_on), @machine.events.keys.sort
|
|
997
|
+
end
|
|
998
|
+
|
|
999
|
+
def test_should_define_transitions_for_each_event
|
|
1000
|
+
[:turn_on, :activate].each {|event| assert_equal 1, @machine.event(event).guards.size}
|
|
1001
|
+
end
|
|
1002
|
+
|
|
1003
|
+
def test_should_transition_the_same_for_each_event
|
|
900
1004
|
object = @klass.new
|
|
1005
|
+
object.turn_on
|
|
1006
|
+
assert_equal 'on', object.state
|
|
901
1007
|
|
|
902
|
-
|
|
1008
|
+
object = @klass.new
|
|
1009
|
+
object.activate
|
|
1010
|
+
assert_equal 'on', object.state
|
|
903
1011
|
end
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
@klass = Class.new
|
|
909
|
-
@machine = StateMachine::Machine.new(@klass)
|
|
910
|
-
@machine.event(:turn_on) do
|
|
911
|
-
transition :to => 'on', :from => nil
|
|
912
|
-
end
|
|
1012
|
+
|
|
1013
|
+
def test_should_return_all_created_events
|
|
1014
|
+
assert_instance_of Array, @result
|
|
1015
|
+
assert_equal 2, @result.size
|
|
913
1016
|
end
|
|
914
1017
|
|
|
915
|
-
def
|
|
916
|
-
|
|
917
|
-
assert !object.nil?
|
|
918
|
-
assert !object.respond_to?('?')
|
|
1018
|
+
def test_should_track_events_order
|
|
1019
|
+
assert_equal %w(turn_on activate), @machine.events_order
|
|
919
1020
|
end
|
|
920
1021
|
end
|
|
921
1022
|
|
|
@@ -1002,7 +1103,7 @@ class MachineWithTransitionCallbacksTest < Test::Unit::TestCase
|
|
|
1002
1103
|
@machine.before_transition :from => 'off', :to => 'on', :do => lambda {}
|
|
1003
1104
|
@machine.after_transition :from => 'unknown', :to => 'error', :do => lambda {}
|
|
1004
1105
|
|
|
1005
|
-
assert_equal %w(error off on unknown), @machine.states.sort
|
|
1106
|
+
assert_equal %w(error off on unknown), @machine.states.keys.sort
|
|
1006
1107
|
end
|
|
1007
1108
|
|
|
1008
1109
|
def test_should_not_duplicate_states_defined_in_multiple_event_transitions
|
|
@@ -1010,23 +1111,52 @@ class MachineWithTransitionCallbacksTest < Test::Unit::TestCase
|
|
|
1010
1111
|
@machine.after_transition :from => 'unknown', :to => 'error', :do => lambda {}
|
|
1011
1112
|
@machine.after_transition :from => 'off', :to => 'on', :do => lambda {}
|
|
1012
1113
|
|
|
1013
|
-
assert_equal %w(error off on unknown), @machine.states.sort
|
|
1114
|
+
assert_equal %w(error off on unknown), @machine.states.keys.sort
|
|
1014
1115
|
end
|
|
1015
1116
|
|
|
1016
1117
|
def test_should_define_predicates_for_each_state
|
|
1017
1118
|
[:on?, :off?].each {|predicate| assert @object.respond_to?(predicate)}
|
|
1018
1119
|
end
|
|
1120
|
+
|
|
1121
|
+
def test_should_order_states_after_initial_state
|
|
1122
|
+
@machine.before_transition :to => 'unknown', :do => lambda {}
|
|
1123
|
+
assert_equal %w(off on unknown), @machine.states_order
|
|
1124
|
+
end
|
|
1125
|
+
|
|
1126
|
+
def test_should_order_states_after_transition_states
|
|
1127
|
+
@machine.before_transition :to => 'unknown', :do => lambda {}
|
|
1128
|
+
@machine.event :turn_on do
|
|
1129
|
+
transition :to => 'error'
|
|
1130
|
+
end
|
|
1131
|
+
assert_equal %w(off on error unknown), @machine.states_order
|
|
1132
|
+
end
|
|
1133
|
+
|
|
1134
|
+
def test_should_order_states_after_states_with_behaviors
|
|
1135
|
+
@machine.before_transition :to => 'unknown', :do => lambda {}
|
|
1136
|
+
@machine.state 'error' do
|
|
1137
|
+
def color
|
|
1138
|
+
'red'
|
|
1139
|
+
end
|
|
1140
|
+
end
|
|
1141
|
+
assert_equal %w(off on error unknown), @machine.states_order
|
|
1142
|
+
end
|
|
1143
|
+
|
|
1144
|
+
def test_should_order_states_after_other_states
|
|
1145
|
+
@machine.before_transition :to => 'unknown', :do => lambda {}
|
|
1146
|
+
@machine.other_states 'error'
|
|
1147
|
+
assert_equal %w(off on error unknown), @machine.states_order
|
|
1148
|
+
end
|
|
1019
1149
|
end
|
|
1020
1150
|
|
|
1021
1151
|
class MachineWithOtherStates < Test::Unit::TestCase
|
|
1022
1152
|
def setup
|
|
1023
1153
|
@klass = Class.new
|
|
1024
|
-
@machine = StateMachine::Machine.new(@klass, :initial => '
|
|
1025
|
-
@machine.other_states('
|
|
1154
|
+
@machine = StateMachine::Machine.new(@klass, :initial => 'off')
|
|
1155
|
+
@machine.other_states('off', 'on')
|
|
1026
1156
|
end
|
|
1027
1157
|
|
|
1028
1158
|
def test_should_include_other_states_in_known_states
|
|
1029
|
-
assert_equal %w(off on), @machine.states.sort
|
|
1159
|
+
assert_equal %w(off on), @machine.states.keys.sort
|
|
1030
1160
|
end
|
|
1031
1161
|
|
|
1032
1162
|
def test_should_define_predicates_for_each_state
|
|
@@ -1034,6 +1164,31 @@ class MachineWithOtherStates < Test::Unit::TestCase
|
|
|
1034
1164
|
|
|
1035
1165
|
[:on?, :off?].each {|predicate| assert object.respond_to?(predicate)}
|
|
1036
1166
|
end
|
|
1167
|
+
|
|
1168
|
+
def test_should_order_states_after_initial_state
|
|
1169
|
+
assert_equal %w(off on), @machine.states_order
|
|
1170
|
+
end
|
|
1171
|
+
|
|
1172
|
+
def test_should_order_states_after_transition_states
|
|
1173
|
+
@machine.event :turn_on do
|
|
1174
|
+
transition :to => 'error'
|
|
1175
|
+
end
|
|
1176
|
+
assert_equal %w(off error on), @machine.states_order
|
|
1177
|
+
end
|
|
1178
|
+
|
|
1179
|
+
def test_should_order_states_after_states_with_behaviors
|
|
1180
|
+
@machine.state 'error' do
|
|
1181
|
+
def color
|
|
1182
|
+
'red'
|
|
1183
|
+
end
|
|
1184
|
+
end
|
|
1185
|
+
assert_equal %w(off error on), @machine.states_order
|
|
1186
|
+
end
|
|
1187
|
+
|
|
1188
|
+
def test_should_order_state_before_callback_states
|
|
1189
|
+
@machine.before_transition :to => 'error', :do => lambda {}
|
|
1190
|
+
assert_equal %w(off on error), @machine.states_order
|
|
1191
|
+
end
|
|
1037
1192
|
end
|
|
1038
1193
|
|
|
1039
1194
|
class MachineWithOwnerSubclassTest < Test::Unit::TestCase
|
|
@@ -1071,6 +1226,52 @@ class MachineWithExistingMachinesOnOwnerClassTest < Test::Unit::TestCase
|
|
|
1071
1226
|
end
|
|
1072
1227
|
end
|
|
1073
1228
|
|
|
1229
|
+
class MachineWithNamespaceTest < Test::Unit::TestCase
|
|
1230
|
+
def setup
|
|
1231
|
+
@klass = Class.new
|
|
1232
|
+
@machine = StateMachine::Machine.new(@klass, :namespace => 'switch', :initial => 'off') do
|
|
1233
|
+
event :turn_on do
|
|
1234
|
+
transition :to => 'on', :from => 'off'
|
|
1235
|
+
end
|
|
1236
|
+
|
|
1237
|
+
event :turn_off do
|
|
1238
|
+
transition :to => 'off', :from => 'on'
|
|
1239
|
+
end
|
|
1240
|
+
end
|
|
1241
|
+
@object = @klass.new
|
|
1242
|
+
end
|
|
1243
|
+
|
|
1244
|
+
def test_should_namespace_state_predicates
|
|
1245
|
+
[:switch_off?, :switch_on?].each do |name|
|
|
1246
|
+
assert @object.respond_to?(name)
|
|
1247
|
+
end
|
|
1248
|
+
end
|
|
1249
|
+
|
|
1250
|
+
def test_should_namespace_event_checks
|
|
1251
|
+
[:can_turn_on_switch?, :can_turn_off_switch?].each do |name|
|
|
1252
|
+
assert @object.respond_to?(name)
|
|
1253
|
+
end
|
|
1254
|
+
end
|
|
1255
|
+
|
|
1256
|
+
def test_should_namespace_event_transition_readers
|
|
1257
|
+
[:next_turn_on_switch_transition, :next_turn_off_switch_transition].each do |name|
|
|
1258
|
+
assert @object.respond_to?(name)
|
|
1259
|
+
end
|
|
1260
|
+
end
|
|
1261
|
+
|
|
1262
|
+
def test_should_namespace_events
|
|
1263
|
+
[:turn_on_switch, :turn_off_switch].each do |name|
|
|
1264
|
+
assert @object.respond_to?(name)
|
|
1265
|
+
end
|
|
1266
|
+
end
|
|
1267
|
+
|
|
1268
|
+
def test_should_namespace_bang_events
|
|
1269
|
+
[:turn_on_switch!, :turn_off_switch!].each do |name|
|
|
1270
|
+
assert @object.respond_to?(name)
|
|
1271
|
+
end
|
|
1272
|
+
end
|
|
1273
|
+
end
|
|
1274
|
+
|
|
1074
1275
|
class MachineFinderWithoutExistingMachineTest < Test::Unit::TestCase
|
|
1075
1276
|
def setup
|
|
1076
1277
|
@klass = Class.new
|