/test/unit/transition_test.rb
Ruby | 1558 lines | 1230 code | 328 blank | 0 comment | 1 complexity | 7b7ce05570b849a2aac4e6daa6dff887 MD5 | raw file
- require File.expand_path(File.dirname(__FILE__) + '/../test_helper')
- class TransitionTest < Test::Unit::TestCase
- def setup
- @klass = Class.new
- @machine = StateMachine::Machine.new(@klass)
- @machine.state :parked, :idling
- @machine.event :ignite
-
- @object = @klass.new
- @object.state = 'parked'
-
- @transition = StateMachine::Transition.new(@object, @machine, :ignite, :parked, :idling)
- end
-
- def test_should_have_an_object
- assert_equal @object, @transition.object
- end
-
- def test_should_have_a_machine
- assert_equal @machine, @transition.machine
- end
-
- def test_should_have_an_event
- assert_equal :ignite, @transition.event
- end
-
- def test_should_have_a_qualified_event
- assert_equal :ignite, @transition.qualified_event
- end
-
- def test_should_have_a_human_event
- assert_equal 'ignite', @transition.human_event
- end
-
- def test_should_have_a_from_value
- assert_equal 'parked', @transition.from
- end
-
- def test_should_have_a_from_name
- assert_equal :parked, @transition.from_name
- end
-
- def test_should_have_a_qualified_from_name
- assert_equal :parked, @transition.qualified_from_name
- end
-
- def test_should_have_a_human_from_name
- assert_equal 'parked', @transition.human_from_name
- end
-
- def test_should_have_a_to_value
- assert_equal 'idling', @transition.to
- end
-
- def test_should_have_a_to_name
- assert_equal :idling, @transition.to_name
- end
-
- def test_should_have_a_qualified_to_name
- assert_equal :idling, @transition.qualified_to_name
- end
-
- def test_should_have_a_human_to_name
- assert_equal 'idling', @transition.human_to_name
- end
-
- def test_should_have_an_attribute
- assert_equal :state, @transition.attribute
- end
-
- def test_should_not_have_an_action
- assert_nil @transition.action
- end
-
- def test_should_not_be_transient
- assert_equal false, @transition.transient?
- end
-
- def test_should_generate_attributes
- expected = {:object => @object, :attribute => :state, :event => :ignite, :from => 'parked', :to => 'idling'}
- assert_equal expected, @transition.attributes
- end
-
- def test_should_have_empty_args
- assert_equal [], @transition.args
- end
-
- def test_should_not_have_a_result
- assert_nil @transition.result
- end
-
- def test_should_use_pretty_inspect
- assert_equal '#<StateMachine::Transition attribute=:state event=:ignite from="parked" from_name=:parked to="idling" to_name=:idling>', @transition.inspect
- end
- end
- class TransitionWithInvalidNodesTest < Test::Unit::TestCase
- def setup
- @klass = Class.new
- @machine = StateMachine::Machine.new(@klass)
- @machine.state :parked, :idling
- @machine.event :ignite
-
- @object = @klass.new
- @object.state = 'parked'
- end
-
- def test_should_raise_exception_without_event
- assert_raise(IndexError) { StateMachine::Transition.new(@object, @machine, nil, :parked, :idling) }
- end
-
- def test_should_raise_exception_with_invalid_event
- assert_raise(IndexError) { StateMachine::Transition.new(@object, @machine, :invalid, :parked, :idling) }
- end
-
- def test_should_raise_exception_with_invalid_from_state
- assert_raise(IndexError) { StateMachine::Transition.new(@object, @machine, :ignite, :invalid, :idling) }
- end
-
- def test_should_raise_exception_with_invalid_to_state
- assert_raise(IndexError) { StateMachine::Transition.new(@object, @machine, :ignite, :parked, :invalid) }
- end
- end
- class TransitionWithDynamicToValueTest < Test::Unit::TestCase
- def setup
- @klass = Class.new
- @machine = StateMachine::Machine.new(@klass)
- @machine.state :parked
- @machine.state :idling, :value => lambda {1}
- @machine.event :ignite
-
- @object = @klass.new
- @object.state = 'parked'
- @transition = StateMachine::Transition.new(@object, @machine, :ignite, :parked, :idling)
- end
-
- def test_should_evaluate_to_value
- assert_equal 1, @transition.to
- end
- end
- class TransitionLoopbackTest < Test::Unit::TestCase
- def setup
- @klass = Class.new
- @machine = StateMachine::Machine.new(@klass)
- @machine.state :parked
- @machine.event :park
-
- @object = @klass.new
- @object.state = 'parked'
- @transition = StateMachine::Transition.new(@object, @machine, :park, :parked, :parked)
- end
-
- def test_should_be_loopback
- assert @transition.loopback?
- end
- end
- class TransitionWithDifferentStatesTest < Test::Unit::TestCase
- def setup
- @klass = Class.new
- @machine = StateMachine::Machine.new(@klass)
- @machine.state :parked, :idling
- @machine.event :ignite
-
- @object = @klass.new
- @object.state = 'parked'
- @transition = StateMachine::Transition.new(@object, @machine, :ignite, :parked, :idling)
- end
-
- def test_should_not_be_loopback
- assert !@transition.loopback?
- end
- end
- class TransitionWithNamespaceTest < Test::Unit::TestCase
- def setup
- @klass = Class.new
- @machine = StateMachine::Machine.new(@klass, :namespace => 'alarm')
- @machine.state :off, :active
- @machine.event :activate
-
- @object = @klass.new
- @object.state = 'off'
-
- @transition = StateMachine::Transition.new(@object, @machine, :activate, :off, :active)
- end
-
- def test_should_have_an_event
- assert_equal :activate, @transition.event
- end
-
- def test_should_have_a_qualified_event
- assert_equal :activate_alarm, @transition.qualified_event
- end
-
- def test_should_have_a_from_name
- assert_equal :off, @transition.from_name
- end
-
- def test_should_have_a_qualified_from_name
- assert_equal :alarm_off, @transition.qualified_from_name
- end
-
- def test_should_have_a_human_from_name
- assert_equal 'off', @transition.human_from_name
- end
-
- def test_should_have_a_to_name
- assert_equal :active, @transition.to_name
- end
-
- def test_should_have_a_qualified_to_name
- assert_equal :alarm_active, @transition.qualified_to_name
- end
-
- def test_should_have_a_human_to_name
- assert_equal 'active', @transition.human_to_name
- end
- end
- class TransitionWithCustomMachineAttributeTest < Test::Unit::TestCase
- def setup
- @klass = Class.new
- @machine = StateMachine::Machine.new(@klass, :state, :attribute => :state_id)
- @machine.state :off, :value => 1
- @machine.state :active, :value => 2
- @machine.event :activate
-
- @object = @klass.new
- @object.state_id = 1
-
- @transition = StateMachine::Transition.new(@object, @machine, :activate, :off, :active)
- end
-
- def test_should_persist
- @transition.persist
- assert_equal 2, @object.state_id
- end
-
- def test_should_rollback
- @object.state_id = 2
- @transition.rollback
-
- assert_equal 1, @object.state_id
- end
- end
- class TransitionWithoutReadingStateTest < Test::Unit::TestCase
- def setup
- @klass = Class.new
- @machine = StateMachine::Machine.new(@klass)
- @machine.state :parked, :idling
- @machine.event :ignite
-
- @object = @klass.new
- @object.state = 'idling'
- @transition = StateMachine::Transition.new(@object, @machine, :ignite, :parked, :idling, false)
- end
-
- def test_should_not_read_from_value_from_object
- assert_equal 'parked', @transition.from
- end
-
- def test_should_have_to_value
- assert_equal 'idling', @transition.to
- end
- end
- class TransitionWithActionTest < Test::Unit::TestCase
- def setup
- @klass = Class.new do
- def save
- end
- end
-
- @machine = StateMachine::Machine.new(@klass, :action => :save)
- @machine.state :parked, :idling
- @machine.event :ignite
-
- @object = @klass.new
- @object.state = 'parked'
-
- @transition = StateMachine::Transition.new(@object, @machine, :ignite, :parked, :idling)
- end
-
- def test_should_have_an_action
- assert_equal :save, @transition.action
- end
-
- def test_should_not_have_a_result
- assert_nil @transition.result
- end
- end
- class TransitionAfterBeingPersistedTest < Test::Unit::TestCase
- def setup
- @klass = Class.new
- @machine = StateMachine::Machine.new(@klass, :action => :save)
- @machine.state :parked, :idling
- @machine.event :ignite
-
- @object = @klass.new
- @object.state = 'parked'
-
- @transition = StateMachine::Transition.new(@object, @machine, :ignite, :parked, :idling)
- @transition.persist
- end
-
- def test_should_update_state_value
- assert_equal 'idling', @object.state
- end
-
- def test_should_not_change_from_state
- assert_equal 'parked', @transition.from
- end
-
- def test_should_not_change_to_state
- assert_equal 'idling', @transition.to
- end
-
- def test_should_not_be_able_to_persist_twice
- @object.state = 'parked'
- @transition.persist
- assert_equal 'parked', @object.state
- end
-
- def test_should_be_able_to_persist_again_after_resetting
- @object.state = 'parked'
- @transition.reset
- @transition.persist
- assert_equal 'idling', @object.state
- end
-
- def test_should_revert_to_from_state_on_rollback
- @transition.rollback
- assert_equal 'parked', @object.state
- end
- end
- class TransitionAfterBeingRolledBackTest < Test::Unit::TestCase
- def setup
- @klass = Class.new
- @machine = StateMachine::Machine.new(@klass, :action => :save)
- @machine.state :parked, :idling
- @machine.event :ignite
-
- @object = @klass.new
- @object.state = 'parked'
-
- @transition = StateMachine::Transition.new(@object, @machine, :ignite, :parked, :idling)
- @object.state = 'idling'
-
- @transition.rollback
- end
-
- def test_should_update_state_value_to_from_state
- assert_equal 'parked', @object.state
- end
-
- def test_should_not_change_from_state
- assert_equal 'parked', @transition.from
- end
-
- def test_should_not_change_to_state
- assert_equal 'idling', @transition.to
- end
-
- def test_should_still_be_able_to_persist
- @transition.persist
- assert_equal 'idling', @object.state
- end
- end
- class TransitionWithoutCallbacksTest < Test::Unit::TestCase
- def setup
- @klass = Class.new
-
- @machine = StateMachine::Machine.new(@klass)
- @machine.state :parked, :idling
- @machine.event :ignite
-
- @object = @klass.new
- @object.state = 'parked'
- @transition = StateMachine::Transition.new(@object, @machine, :ignite, :parked, :idling)
- end
-
- def test_should_succeed
- assert_equal true, @transition.run_callbacks
- end
-
- def test_should_succeed_if_after_callbacks_skipped
- assert_equal true, @transition.run_callbacks(:after => false)
- end
-
- def test_should_call_block_if_provided
- @transition.run_callbacks { @ran_block = true; {} }
- assert @ran_block
- end
-
- def test_should_track_block_result
- @transition.run_callbacks {{:result => 1}}
- assert_equal 1, @transition.result
- end
- end
- class TransitionWithBeforeCallbacksTest < Test::Unit::TestCase
- def setup
- @klass = Class.new
-
- @machine = StateMachine::Machine.new(@klass)
- @machine.state :parked, :idling
- @machine.event :ignite
-
- @object = @klass.new
- @object.state = 'parked'
- @transition = StateMachine::Transition.new(@object, @machine, :ignite, :parked, :idling)
- end
-
- def test_should_run_before_callbacks
- @machine.before_transition {@run = true}
- result = @transition.run_callbacks
-
- assert_equal true, result
- assert_equal true, @run
- end
-
- def test_should_only_run_those_that_match_transition_context
- @count = 0
- callback = lambda {@count += 1}
-
- @machine.before_transition :from => :parked, :to => :idling, :on => :park, :do => callback
- @machine.before_transition :from => :parked, :to => :parked, :on => :park, :do => callback
- @machine.before_transition :from => :parked, :to => :idling, :on => :ignite, :do => callback
- @machine.before_transition :from => :idling, :to => :idling, :on => :park, :do => callback
- @transition.run_callbacks
-
- assert_equal 1, @count
- end
-
- def test_should_pass_transition_as_argument
- @machine.before_transition {|*args| @args = args}
- @transition.run_callbacks
-
- assert_equal [@object, @transition], @args
- end
-
- def test_should_catch_halts
- @machine.before_transition {throw :halt}
-
- result = nil
- assert_nothing_thrown { result = @transition.run_callbacks }
- assert_equal false, result
- end
-
- def test_should_not_catch_exceptions
- @machine.before_transition {raise ArgumentError}
- assert_raise(ArgumentError) { @transition.run_callbacks }
- end
-
- def test_should_not_be_able_to_run_twice
- @count = 0
- @machine.before_transition {@count += 1}
- @transition.run_callbacks
- @transition.run_callbacks
- assert_equal 1, @count
- end
-
- def test_should_be_able_to_run_again_after_halt
- @count = 0
- @machine.before_transition {@count += 1; throw :halt}
- @transition.run_callbacks
- @transition.run_callbacks
- assert_equal 2, @count
- end
-
- def test_should_be_able_to_run_again_after_resetting
- @count = 0
- @machine.before_transition {@count += 1}
- @transition.run_callbacks
- @transition.reset
- @transition.run_callbacks
- assert_equal 2, @count
- end
-
- def test_should_succeed_if_block_result_is_false
- @machine.before_transition {@run = true}
- assert_equal true, @transition.run_callbacks {{:result => false}}
- assert @run
- end
-
- def test_should_succeed_if_block_result_is_true
- @machine.before_transition {@run = true}
- assert_equal true, @transition.run_callbacks {{:result => true}}
- assert @run
- end
-
- def test_should_succeed_if_block_success_is_false
- @machine.before_transition {@run = true}
- assert_equal true, @transition.run_callbacks {{:success => false}}
- assert @run
- end
-
- def test_should_succeed_if_block_success_is_true
- @machine.before_transition {@run = true}
- assert_equal true, @transition.run_callbacks {{:success => true}}
- assert @run
- end
- end
- class TransitionWithMultipleBeforeCallbacksTest < Test::Unit::TestCase
- def setup
- @klass = Class.new
-
- @machine = StateMachine::Machine.new(@klass)
- @machine.state :parked, :idling
- @machine.event :ignite
-
- @object = @klass.new
- @object.state = 'parked'
- @transition = StateMachine::Transition.new(@object, @machine, :ignite, :parked, :idling)
- end
-
- def test_should_run_in_the_order_they_were_defined
- @callbacks = []
- @machine.before_transition {@callbacks << 1}
- @machine.before_transition {@callbacks << 2}
- @transition.run_callbacks
-
- assert_equal [1, 2], @callbacks
- end
-
- def test_should_not_run_further_callbacks_if_halted
- @callbacks = []
- @machine.before_transition {@callbacks << 1; throw :halt}
- @machine.before_transition {@callbacks << 2}
-
- assert_equal false, @transition.run_callbacks
- assert_equal [1], @callbacks
- end
-
- def test_should_fail_if_any_callback_halted
- @machine.before_transition {true}
- @machine.before_transition {throw :halt}
-
- assert_equal false, @transition.run_callbacks
- end
- end
- class TransitionWithAfterCallbacksTest < Test::Unit::TestCase
- def setup
- @klass = Class.new
-
- @machine = StateMachine::Machine.new(@klass)
- @machine.state :parked, :idling
- @machine.event :ignite
-
- @object = @klass.new
- @object.state = 'parked'
- @transition = StateMachine::Transition.new(@object, @machine, :ignite, :parked, :idling)
- end
-
- def test_should_run_after_callbacks
- @machine.after_transition {|object| @run = true}
- result = @transition.run_callbacks
-
- assert_equal true, result
- assert_equal true, @run
- end
-
- def test_should_only_run_those_that_match_transition_context
- @count = 0
- callback = lambda {@count += 1}
-
- @machine.after_transition :from => :parked, :to => :idling, :on => :park, :do => callback
- @machine.after_transition :from => :parked, :to => :parked, :on => :park, :do => callback
- @machine.after_transition :from => :parked, :to => :idling, :on => :ignite, :do => callback
- @machine.after_transition :from => :idling, :to => :idling, :on => :park, :do => callback
- @transition.run_callbacks
-
- assert_equal 1, @count
- end
-
- def test_should_not_run_if_not_successful
- @run = false
- @machine.after_transition {|object| @run = true}
- @transition.run_callbacks {{:success => false}}
- assert !@run
- end
-
- def test_should_run_if_successful
- @machine.after_transition {|object| @run = true}
- @transition.run_callbacks {{:success => true}}
- assert @run
- end
-
- def test_should_pass_transition_as_argument
- @machine.after_transition {|*args| @args = args}
-
- @transition.run_callbacks
- assert_equal [@object, @transition], @args
- end
-
- def test_should_catch_halts
- @machine.after_transition {throw :halt}
-
- result = nil
- assert_nothing_thrown { result = @transition.run_callbacks }
- assert_equal true, result
- end
-
- def test_should_not_catch_exceptions
- @machine.after_transition {raise ArgumentError}
- assert_raise(ArgumentError) { @transition.run_callbacks }
- end
-
- def test_should_not_be_able_to_run_twice
- @count = 0
- @machine.after_transition {@count += 1}
- @transition.run_callbacks
- @transition.run_callbacks
- assert_equal 1, @count
- end
-
- def test_should_not_be_able_to_run_twice_if_halted
- @count = 0
- @machine.after_transition {@count += 1; throw :halt}
- @transition.run_callbacks
- @transition.run_callbacks
- assert_equal 1, @count
- end
-
- def test_should_be_able_to_run_again_after_resetting
- @count = 0
- @machine.after_transition {@count += 1}
- @transition.run_callbacks
- @transition.reset
- @transition.run_callbacks
- assert_equal 2, @count
- end
- end
- class TransitionWithMultipleAfterCallbacksTest < Test::Unit::TestCase
- def setup
- @klass = Class.new
-
- @machine = StateMachine::Machine.new(@klass)
- @machine.state :parked, :idling
- @machine.event :ignite
-
- @object = @klass.new
- @object.state = 'parked'
- @transition = StateMachine::Transition.new(@object, @machine, :ignite, :parked, :idling)
- end
-
- def test_should_run_in_the_order_they_were_defined
- @callbacks = []
- @machine.after_transition {@callbacks << 1}
- @machine.after_transition {@callbacks << 2}
- @transition.run_callbacks
-
- assert_equal [1, 2], @callbacks
- end
-
- def test_should_not_run_further_callbacks_if_halted
- @callbacks = []
- @machine.after_transition {@callbacks << 1; throw :halt}
- @machine.after_transition {@callbacks << 2}
-
- assert_equal true, @transition.run_callbacks
- assert_equal [1], @callbacks
- end
-
- def test_should_fail_if_any_callback_halted
- @machine.after_transition {true}
- @machine.after_transition {throw :halt}
-
- assert_equal true, @transition.run_callbacks
- end
- end
- class TransitionWithAroundCallbacksTest < Test::Unit::TestCase
- def setup
- @klass = Class.new
-
- @machine = StateMachine::Machine.new(@klass)
- @machine.state :parked, :idling
- @machine.event :ignite
-
- @object = @klass.new
- @object.state = 'parked'
- @transition = StateMachine::Transition.new(@object, @machine, :ignite, :parked, :idling)
- end
-
- def test_should_run_around_callbacks
- @machine.around_transition {|object, transition, block| @run_before = true; block.call; @run_after = true}
- result = @transition.run_callbacks
-
- assert_equal true, result
- assert_equal true, @run_before
- assert_equal true, @run_after
- end
-
- def test_should_only_run_those_that_match_transition_context
- @count = 0
- callback = lambda {|object, transition, block| @count += 1; block.call}
-
- @machine.around_transition :from => :parked, :to => :idling, :on => :park, :do => callback
- @machine.around_transition :from => :parked, :to => :parked, :on => :park, :do => callback
- @machine.around_transition :from => :parked, :to => :idling, :on => :ignite, :do => callback
- @machine.around_transition :from => :idling, :to => :idling, :on => :park, :do => callback
- @transition.run_callbacks
-
- assert_equal 1, @count
- end
-
- def test_should_pass_transition_as_argument
- @machine.around_transition {|*args| block = args.pop; @args = args; block.call}
- @transition.run_callbacks
-
- assert_equal [@object, @transition], @args
- end
-
- def test_should_run_block_between_callback
- @callbacks = []
- @machine.around_transition {|block| @callbacks << :before; block.call; @callbacks << :after}
- @transition.run_callbacks { @callbacks << :within; {:success => true} }
-
- assert_equal [:before, :within, :after], @callbacks
- end
-
- def test_should_have_access_to_result_after_yield
- @machine.around_transition {|block| @before_result = @transition.result; block.call; @after_result = @transition.result}
- @transition.run_callbacks {{:result => 1, :success => true}}
-
- assert_nil @before_result
- assert_equal 1, @after_result
- end
-
- def test_should_catch_before_yield_halts
- @machine.around_transition {throw :halt}
-
- result = nil
- assert_nothing_thrown { result = @transition.run_callbacks }
- assert_equal false, result
- end
-
- def test_should_catch_after_yield_halts
- @machine.around_transition {|block| block.call; throw :halt}
-
- result = nil
- assert_nothing_thrown { result = @transition.run_callbacks }
- assert_equal true, result
- end
-
- def test_should_not_catch_before_yield
- @machine.around_transition {raise ArgumentError}
- assert_raise(ArgumentError) { @transition.run_callbacks }
- end
-
- def test_should_not_catch_after_yield
- @machine.around_transition {|block| block.call; raise ArgumentError}
- assert_raise(ArgumentError) { @transition.run_callbacks }
- end
-
- def test_should_fail_if_not_yielded
- @machine.around_transition {}
-
- result = nil
- assert_nothing_thrown { result = @transition.run_callbacks }
- assert_equal false, result
- end
-
- def test_should_not_be_able_to_run_twice
- @before_count = 0
- @after_count = 0
- @machine.around_transition {|block| @before_count += 1; block.call; @after_count += 1}
- @transition.run_callbacks
- @transition.run_callbacks
- assert_equal 1, @before_count
- assert_equal 1, @after_count
- end
-
- def test_should_be_able_to_run_again_after_resetting
- @before_count = 0
- @after_count = 0
- @machine.around_transition {|block| @before_count += 1; block.call; @after_count += 1}
- @transition.run_callbacks
- @transition.reset
- @transition.run_callbacks
- assert_equal 2, @before_count
- assert_equal 2, @after_count
- end
-
- def test_should_succeed_if_block_result_is_false
- @machine.around_transition {|block| @before_run = true; block.call; @after_run = true}
- assert_equal true, @transition.run_callbacks {{:success => true, :result => false}}
- assert @before_run
- assert @after_run
- end
-
- def test_should_succeed_if_block_result_is_true
- @machine.around_transition {|block| @before_run = true; block.call; @after_run = true}
- assert_equal true, @transition.run_callbacks {{:success => true, :result => true}}
- assert @before_run
- assert @after_run
- end
-
- def test_should_only_run_before_if_block_success_is_false
- @after_run = false
- @machine.around_transition {|block| @before_run = true; block.call; @after_run = true}
- assert_equal true, @transition.run_callbacks {{:success => false}}
- assert @before_run
- assert !@after_run
- end
-
- def test_should_succeed_if_block_success_is_false
- @machine.around_transition {|block| @before_run = true; block.call; @after_run = true}
- assert_equal true, @transition.run_callbacks {{:success => true}}
- assert @before_run
- assert @after_run
- end
- end
- class TransitionWithMultipleAroundCallbacksTest < Test::Unit::TestCase
- def setup
- @klass = Class.new
-
- @machine = StateMachine::Machine.new(@klass)
- @machine.state :parked, :idling
- @machine.event :ignite
-
- @object = @klass.new
- @object.state = 'parked'
- @transition = StateMachine::Transition.new(@object, @machine, :ignite, :parked, :idling)
- end
-
- def test_should_before_yield_in_the_order_they_were_defined
- @callbacks = []
- @machine.around_transition {|block| @callbacks << 1; block.call}
- @machine.around_transition {|block| @callbacks << 2; block.call}
- @transition.run_callbacks
-
- assert_equal [1, 2], @callbacks
- end
-
- def test_should_before_yield_multiple_methods_in_the_order_they_were_defined
- @callbacks = []
- @machine.around_transition(lambda {|block| @callbacks << 1; block.call}, lambda {|block| @callbacks << 2; block.call})
- @machine.around_transition(lambda {|block| @callbacks << 3; block.call}, lambda {|block| @callbacks << 4; block.call})
- @transition.run_callbacks
-
- assert_equal [1, 2, 3, 4], @callbacks
- end
-
- def test_should_after_yield_in_the_reverse_order_they_were_defined
- @callbacks = []
- @machine.around_transition {|block| block.call; @callbacks << 1}
- @machine.around_transition {|block| block.call; @callbacks << 2}
- @transition.run_callbacks
-
- assert_equal [2, 1], @callbacks
- end
-
- def test_should_after_yield_multiple_methods_in_the_reverse_order_they_were_defined
- @callbacks = []
- @machine.around_transition(lambda {|block| block.call; @callbacks << 1}) {|block| block.call; @callbacks << 2}
- @machine.around_transition(lambda {|block| block.call; @callbacks << 3}) {|block| block.call; @callbacks << 4}
- @transition.run_callbacks
-
- assert_equal [4, 3, 2, 1], @callbacks
- end
-
- def test_should_run_block_between_callback
- @callbacks = []
- @machine.around_transition {|block| @callbacks << :before_1; block.call; @callbacks << :after_1}
- @machine.around_transition {|block| @callbacks << :before_2; block.call; @callbacks << :after_2}
- @transition.run_callbacks { @callbacks << :within; {:success => true} }
-
- assert_equal [:before_1, :before_2, :within, :after_2, :after_1], @callbacks
- end
-
- def test_should_have_access_to_result_after_yield
- @machine.around_transition {|block| @before_result_1 = @transition.result; block.call; @after_result_1 = @transition.result}
- @machine.around_transition {|block| @before_result_2 = @transition.result; block.call; @after_result_2 = @transition.result}
- @transition.run_callbacks {{:result => 1, :success => true}}
-
- assert_nil @before_result_1
- assert_nil @before_result_2
- assert_equal 1, @after_result_1
- assert_equal 1, @after_result_2
- end
-
- def test_should_fail_if_any_before_yield_halted
- @machine.around_transition {|block| block.call}
- @machine.around_transition {throw :halt}
-
- assert_equal false, @transition.run_callbacks
- end
-
- def test_should_not_continue_around_callbacks_if_before_yield_halted
- @callbacks = []
- @machine.around_transition {@callbacks << 1; throw :halt}
- @machine.around_transition {|block| @callbacks << 2; block.call; @callbacks << 3}
-
- assert_equal false, @transition.run_callbacks
- assert_equal [1], @callbacks
- end
-
- def test_should_not_continue_around_callbacks_if_later_before_yield_halted
- @callbacks = []
- @machine.around_transition {|block| block.call; @callbacks << 1}
- @machine.around_transition {throw :halt}
-
- @transition.run_callbacks
- assert_equal [], @callbacks
- end
-
- def test_should_not_run_further_callbacks_if_after_yield_halted
- @callbacks = []
- @machine.around_transition {|block| block.call; @callbacks << 1}
- @machine.around_transition {|block| block.call; throw :halt}
-
- assert_equal true, @transition.run_callbacks
- assert_equal [], @callbacks
- end
-
- def test_should_fail_if_any_fail_to_yield
- @callbacks = []
- @machine.around_transition {@callbacks << 1}
- @machine.around_transition {|block| @callbacks << 2; block.call; @callbacks << 3}
-
- assert_equal false, @transition.run_callbacks
- assert_equal [1], @callbacks
- end
- end
- class TransitionWithFailureCallbacksTest < Test::Unit::TestCase
- def setup
- @klass = Class.new
-
- @machine = StateMachine::Machine.new(@klass)
- @machine.state :parked, :idling
- @machine.event :ignite
-
- @object = @klass.new
- @object.state = 'parked'
- @transition = StateMachine::Transition.new(@object, @machine, :ignite, :parked, :idling)
- end
-
- def test_should_only_run_those_that_match_transition_context
- @count = 0
- callback = lambda {@count += 1}
-
- @machine.after_failure :do => callback
- @machine.after_failure :on => :park, :do => callback
- @machine.after_failure :on => :ignite, :do => callback
- @transition.run_callbacks {{:success => false}}
-
- assert_equal 2, @count
- end
-
- def test_should_run_if_not_successful
- @machine.after_failure {|object| @run = true}
- @transition.run_callbacks {{:success => false}}
- assert @run
- end
-
- def test_should_not_run_if_successful
- @run = false
- @machine.after_failure {|object| @run = true}
- @transition.run_callbacks {{:success => true}}
- assert !@run
- end
-
- def test_should_pass_transition_as_argument
- @machine.after_failure {|*args| @args = args}
-
- @transition.run_callbacks {{:success => false}}
- assert_equal [@object, @transition], @args
- end
-
- def test_should_catch_halts
- @machine.after_failure {throw :halt}
-
- result = nil
- assert_nothing_thrown { result = @transition.run_callbacks {{:success => false}} }
- assert_equal true, result
- end
-
- def test_should_not_catch_exceptions
- @machine.after_failure {raise ArgumentError}
- assert_raise(ArgumentError) { @transition.run_callbacks {{:success => false}} }
- end
-
- def test_should_not_be_able_to_run_twice
- @count = 0
- @machine.after_failure {@count += 1}
- @transition.run_callbacks {{:success => false}}
- @transition.run_callbacks {{:success => false}}
- assert_equal 1, @count
- end
-
- def test_should_not_be_able_to_run_twice_if_halted
- @count = 0
- @machine.after_failure {@count += 1; throw :halt}
- @transition.run_callbacks {{:success => false}}
- @transition.run_callbacks {{:success => false}}
- assert_equal 1, @count
- end
-
- def test_should_be_able_to_run_again_after_resetting
- @count = 0
- @machine.after_failure {@count += 1}
- @transition.run_callbacks {{:success => false}}
- @transition.reset
- @transition.run_callbacks {{:success => false}}
- assert_equal 2, @count
- end
- end
- class TransitionWithMultipleFailureCallbacksTest < Test::Unit::TestCase
- def setup
- @klass = Class.new
-
- @machine = StateMachine::Machine.new(@klass)
- @machine.state :parked, :idling
- @machine.event :ignite
-
- @object = @klass.new
- @object.state = 'parked'
- @transition = StateMachine::Transition.new(@object, @machine, :ignite, :parked, :idling)
- end
-
- def test_should_run_in_the_order_they_were_defined
- @callbacks = []
- @machine.after_failure {@callbacks << 1}
- @machine.after_failure {@callbacks << 2}
- @transition.run_callbacks {{:success => false}}
-
- assert_equal [1, 2], @callbacks
- end
-
- def test_should_not_run_further_callbacks_if_halted
- @callbacks = []
- @machine.after_failure {@callbacks << 1; throw :halt}
- @machine.after_failure {@callbacks << 2}
-
- assert_equal true, @transition.run_callbacks {{:success => false}}
- assert_equal [1], @callbacks
- end
-
- def test_should_fail_if_any_callback_halted
- @machine.after_failure {true}
- @machine.after_failure {throw :halt}
-
- assert_equal true, @transition.run_callbacks {{:success => false}}
- end
- end
- class TransitionWithMixedCallbacksTest < Test::Unit::TestCase
- def setup
- @klass = Class.new
-
- @machine = StateMachine::Machine.new(@klass)
- @machine.state :parked, :idling
- @machine.event :ignite
-
- @object = @klass.new
- @object.state = 'parked'
- @transition = StateMachine::Transition.new(@object, @machine, :ignite, :parked, :idling)
- end
-
- def test_should_before_and_around_callbacks_in_order_defined
- @callbacks = []
- @machine.before_transition {@callbacks << :before_1}
- @machine.around_transition {|block| @callbacks << :around; block.call}
- @machine.before_transition {@callbacks << :before_2}
-
- assert_equal true, @transition.run_callbacks
- assert_equal [:before_1, :around, :before_2], @callbacks
- end
-
- def test_should_run_around_callbacks_before_after_callbacks
- @callbacks = []
- @machine.after_transition {@callbacks << :after_1}
- @machine.around_transition {|block| block.call; @callbacks << :after_2}
- @machine.after_transition {@callbacks << :after_3}
-
- assert_equal true, @transition.run_callbacks
- assert_equal [:after_2, :after_1, :after_3], @callbacks
- end
-
- def test_should_have_access_to_result_for_both_after_and_around_callbacks
- @machine.after_transition {@after_result = @transition.result}
- @machine.around_transition {|block| block.call; @around_result = @transition.result}
-
- @transition.run_callbacks {{:result => 1, :success => true}}
- assert_equal 1, @after_result
- assert_equal 1, @around_result
- end
-
- def test_should_not_run_further_callbacks_if_before_callback_halts
- @callbacks = []
- @machine.before_transition {@callbacks << :before_1}
- @machine.around_transition {|block| @callbacks << :before_around_1; block.call; @callbacks << :after_around_1}
- @machine.before_transition {@callbacks << :before_2; throw :halt}
- @machine.around_transition {|block| @callbacks << :before_around_2; block.call; @callbacks << :after_around_2}
- @machine.after_transition {@callbacks << :after}
-
- assert_equal false, @transition.run_callbacks
- assert_equal [:before_1, :before_around_1, :before_2], @callbacks
- end
-
- def test_should_not_run_further_callbacks_if_before_yield_halts
- @callbacks = []
- @machine.before_transition {@callbacks << :before_1}
- @machine.around_transition {|block| @callbacks << :before_around_1; throw :halt}
- @machine.before_transition {@callbacks << :before_2; throw :halt}
- @machine.around_transition {|block| @callbacks << :before_around_2; block.call; @callbacks << :after_around_2}
- @machine.after_transition {@callbacks << :after}
-
- assert_equal false, @transition.run_callbacks
- assert_equal [:before_1, :before_around_1], @callbacks
- end
-
- def test_should_not_run_further_callbacks_if_around_callback_fails_to_yield
- @callbacks = []
- @machine.before_transition {@callbacks << :before_1}
- @machine.around_transition {|block| @callbacks << :before_around_1}
- @machine.before_transition {@callbacks << :before_2; throw :halt}
- @machine.around_transition {|block| @callbacks << :before_around_2; block.call; @callbacks << :after_around_2}
- @machine.after_transition {@callbacks << :after}
-
- assert_equal false, @transition.run_callbacks
- assert_equal [:before_1, :before_around_1], @callbacks
- end
-
- def test_should_not_run_further_callbacks_if_after_yield_halts
- @callbacks = []
- @machine.before_transition {@callbacks << :before_1}
- @machine.around_transition {|block| @callbacks << :before_around_1; block.call; @callbacks << :after_around_1; throw :halt}
- @machine.before_transition {@callbacks << :before_2}
- @machine.around_transition {|block| @callbacks << :before_around_2; block.call; @callbacks << :after_around_2}
- @machine.after_transition {@callbacks << :after}
-
- assert_equal true, @transition.run_callbacks
- assert_equal [:before_1, :before_around_1, :before_2, :before_around_2, :after_around_2, :after_around_1], @callbacks
- end
-
- def test_should_not_run_further_callbacks_if_after_callback_halts
- @callbacks = []
- @machine.before_transition {@callbacks << :before_1}
- @machine.around_transition {|block| @callbacks << :before_around_1; block.call; @callbacks << :after_around_1}
- @machine.before_transition {@callbacks << :before_2}
- @machine.around_transition {|block| @callbacks << :before_around_2; block.call; @callbacks << :after_around_2}
- @machine.after_transition {@callbacks << :after_1; throw :halt}
- @machine.after_transition {@callbacks << :after_2}
-
- assert_equal true, @transition.run_callbacks
- assert_equal [:before_1, :before_around_1, :before_2, :before_around_2, :after_around_2, :after_around_1, :after_1], @callbacks
- end
- end
- class TransitionWithBeforeCallbacksSkippedTest < Test::Unit::TestCase
- def setup
- @klass = Class.new
-
- @machine = StateMachine::Machine.new(@klass)
- @machine.state :parked, :idling
- @machine.event :ignite
-
- @object = @klass.new
- @object.state = 'parked'
- @transition = StateMachine::Transition.new(@object, @machine, :ignite, :parked, :idling)
- end
-
- def test_should_not_run_before_callbacks
- @run = false
- @machine.before_transition {@run = true}
-
- assert_equal false, @transition.run_callbacks(:before => false)
- assert !@run
- end
-
- def test_should_run_failure_callbacks
- @machine.after_failure {@run = true}
-
- assert_equal false, @transition.run_callbacks(:before => false)
- assert @run
- end
- end
- class TransitionWithAfterCallbacksSkippedTest < Test::Unit::TestCase
- def setup
- @klass = Class.new
-
- @machine = StateMachine::Machine.new(@klass)
- @machine.state :parked, :idling
- @machine.event :ignite
-
- @object = @klass.new
- @object.state = 'parked'
- @transition = StateMachine::Transition.new(@object, @machine, :ignite, :parked, :idling)
- end
-
- def test_should_run_before_callbacks
- @machine.before_transition {@run = true}
-
- assert_equal true, @transition.run_callbacks(:after => false)
- assert @run
- end
-
- def test_should_not_run_after_callbacks
- @run = false
- @machine.after_transition {@run = true}
-
- assert_equal true, @transition.run_callbacks(:after => false)
- assert !@run
- end
-
- if StateMachine::Transition.pause_supported?
- def test_should_run_around_callbacks_before_yield
- @machine.around_transition {|block| @run = true; block.call}
-
- assert_equal true, @transition.run_callbacks(:after => false)
- assert @run
- end
-
- def test_should_not_run_around_callbacks_after_yield
- @run = false
- @machine.around_transition {|block| block.call; @run = true}
-
- assert_equal true, @transition.run_callbacks(:after => false)
- assert !@run
- end
-
- def test_should_continue_around_transition_execution_on_second_call
- @callbacks = []
- @machine.around_transition {|block| @callbacks << :before_around_1; block.call; @callbacks << :after_around_1}
- @machine.around_transition {|block| @callbacks << :before_around_2; block.call; @callbacks << :after_around_2}
- @machine.after_transition {@callbacks << :after}
-
- assert_equal true, @transition.run_callbacks(:after => false)
- assert_equal [:before_around_1, :before_around_2], @callbacks
-
- assert_equal true, @transition.run_callbacks
- assert_equal [:before_around_1, :before_around_2, :after_around_2, :after_around_1, :after], @callbacks
- end
-
- def test_should_not_run_further_callbacks_if_halted_during_continue_around_transition
- @callbacks = []
- @machine.around_transition {|block| @callbacks << :before_around_1; block.call; @callbacks << :after_around_1}
- @machine.around_transition {|block| @callbacks << :before_around_2; block.call; @callbacks << :after_around_2; throw :halt}
- @machine.after_transition {@callbacks << :after}
-
- assert_equal true, @transition.run_callbacks(:after => false)
- assert_equal [:before_around_1, :before_around_2], @callbacks
-
- assert_equal true, @transition.run_callbacks
- assert_equal [:before_around_1, :before_around_2, :after_around_2], @callbacks
- end
-
- def test_should_not_be_able_to_continue_twice
- @count = 0
- @machine.around_transition {|block| block.call; @count += 1}
- @machine.after_transition {@count += 1}
-
- @transition.run_callbacks(:after => false)
-
- 2.times do
- assert_equal true, @transition.run_callbacks
- assert_equal 2, @count
- end
- end
-
- def test_should_not_be_able_to_continue_again_after_halted
- @count = 0
- @machine.around_transition {|block| block.call; @count += 1; throw :halt}
- @machine.after_transition {@count += 1}
-
- @transition.run_callbacks(:after => false)
-
- 2.times do
- assert_equal true, @transition.run_callbacks
- assert_equal 1, @count
- end
- end
-
- def test_should_have_access_to_result_after_continued
- @machine.around_transition {|block| @around_before_result = @transition.result; block.call; @around_after_result = @transition.result}
- @machine.after_transition {@after_result = @transition.result}
-
- @transition.run_callbacks(:after => false)
- @transition.run_callbacks {{:result => 1}}
-
- assert_nil @around_before_result
- assert_equal 1, @around_after_result
- assert_equal 1, @after_result
- end
-
- def test_should_raise_exceptions_during_around_callbacks_after_yield_in_second_execution
- @machine.around_transition {|block| block.call; raise ArgumentError}
-
- assert_nothing_raised { @transition.run_callbacks(:after => false) }
- assert_raise(ArgumentError) { @transition.run_callbacks }
- end
- else
- def test_should_raise_exception_on_second_call
- @callbacks = []
- @machine.around_transition {|block| @callbacks << :before_around_1; block.call; @callbacks << :after_around_1}
- @machine.around_transition {|block| @callbacks << :before_around_2; block.call; @callbacks << :after_around_2}
- @machine.after_transition {@callbacks << :after}
-
- assert_raise(ArgumentError) { @transition.run_callbacks(:after => false) }
- end
- end
- end
- class TransitionAfterBeingPerformedTest < Test::Unit::TestCase
- def setup
- @klass = Class.new do
- attr_reader :saved, :save_state
-
- def save
- @save_state = state
- @saved = true
- 1
- end
- end
-
- @machine = StateMachine::Machine.new(@klass, :action => :save)
- @machine.state :parked, :idling
- @machine.event :ignite
-
- @object = @klass.new
- @object.state = 'parked'
- @transition = StateMachine::Transition.new(@object, @machine, :ignite, :parked, :idling)
- @result = @transition.perform
- end
-
- def test_should_have_empty_args
- assert_equal [], @transition.args
- end
-
- def test_should_have_a_result
- assert_equal 1, @transition.result
- end
-
- def test_should_be_successful
- assert_equal true, @result
- end
-
- def test_should_change_the_current_state
- assert_equal 'idling', @object.state
- end
-
- def test_should_run_the_action
- assert @object.saved
- end
-
- def test_should_run_the_action_after_saving_the_state
- assert_equal 'idling', @object.save_state
- end
- end
- class TransitionWithPerformArgumentsTest < Test::Unit::TestCase
- def setup
- @klass = Class.new do
- attr_reader :saved
-
- def save
- @saved = true
- end
- end
-
- @machine = StateMachine::Machine.new(@klass, :action => :save)
- @machine.state :parked, :idling
- @machine.event :ignite
-
- @object = @klass.new
- @object.state = 'parked'
- @transition = StateMachine::Transition.new(@object, @machine, :ignite, :parked, :idling)
- end
-
- def test_should_have_arguments
- @transition.perform(1, 2)
-
- assert_equal [1, 2], @transition.args
- assert @object.saved
- end
-
- def test_should_not_include_run_action_in_arguments
- @transition.perform(1, 2, false)
-
- assert_equal [1, 2], @transition.args
- assert !@object.saved
- end
- end
- class TransitionWithoutRunningActionTest < Test::Unit::TestCase
- def setup
- @klass = Class.new do
- attr_reader :saved
-
- def save
- @saved = true
- end
- end
-
- @machine = StateMachine::Machine.new(@klass, :action => :save)
- @machine.state :parked, :idling
- @machine.event :ignite
- @machine.after_transition {|object| @run_after = true}
-
- @object = @klass.new
- @object.state = 'parked'
- @transition = StateMachine::Transition.new(@object, @machine, :ignite, :parked, :idling)
- @result = @transition.perform(false)
- end
-
- def test_should_have_empty_args
- assert_equal [], @transition.args
- end
-
- def test_should_not_have_a_result
- assert_nil @transition.result
- end
-
- def test_should_be_successful
- assert_equal true, @result
- end
-
- def test_should_change_the_current_state
- assert_equal 'idling', @object.state
- end
-
- def test_should_not_run_the_action
- assert !@object.saved
- end
-
- def test_should_run_after_callbacks
- assert @run_after
- end
- end
- class TransitionWithTransactionsTest < Test::Unit::TestCase
- def setup
- @klass = Class.new do
- class << self
- attr_accessor :running_transaction
- end
-
- attr_accessor :result
-
- def save
- @result = self.class.running_transaction
- true
- end
- end
-
- @machine = StateMachine::Machine.new(@klass, :action => :save)
- @machine.state :parked, :idling
- @machine.event :ignite
-
- @object = @klass.new
- @object.state = 'parked'
- @transition = StateMachine::Transition.new(@object, @machine, :ignite, :parked, :idling)
-
- class << @machine
- def within_transaction(object)
- owner_class.running_transaction = object
- yield
- owner_class.running_transaction = false
- end
- end
- end
-
- def test_should_run_blocks_within_transaction_for_object
- @transition.within_transaction do
- @result = @klass.running_transaction
- end
-
- assert_equal @object, @result
- end
- end
- class TransitionTransientTest < Test::Unit::TestCase
- def setup
- @klass = Class.new
-
- @machine = StateMachine::Machine.new(@klass)
- @machine.state :parked, :idling
- @machine.event :ignite
-
- @object = @klass.new
- @object.state = 'parked'
- @transition = StateMachine::Transition.new(@object, @machine, :ignite, :parked, :idling)
- @transition.transient = true
- end
-
- def test_should_be_transient
- assert @transition.transient?
- end
- end
- class TransitionEqualityTest < Test::Unit::TestCase
- def setup
- @klass = Class.new
-
- @machine = StateMachine::Machine.new(@klass)
- @machine.state :parked, :idling
- @machine.event :ignite
-
- @object = @klass.new
- @object.state = 'parked'
- @transition = StateMachine::Transition.new(@object, @machine, :ignite, :parked, :idling)
- end
-
- def test_should_be_equal_with_same_properties
- transition = StateMachine::Transition.new(@object, @machine, :ignite, :parked, :idling)
- assert_equal transition, @transition
- end
-
- def test_should_not_be_equal_with_different_machines
- machine = StateMachine::Machine.new(@klass, :status, :namespace => :other)
- machine.state :parked, :idling
- machine.event :ignite
- transition = StateMachine::Transition.new(@object, machine, :ignite, :parked, :idling)
-
- assert_not_equal transition, @transition
- end
-
- def test_should_not_be_equal_with_different_objects
- transition = StateMachine::Transition.new(@klass.new, @machine, :ignite, :parked, :idling)
- assert_not_equal transition, @transition
- end
-
- def test_should_not_be_equal_with_different_event_names
- @machine.event :park
- transition = StateMachine::Transition.new(@object, @machine, :park, :parked, :idling)
- assert_not_equal transition, @transition
- end
-
- def test_should_not_be_equal_with_different_from_state_names
- @machine.state :first_gear
- transition = StateMachine::Transition.new(@object, @machine, :ignite, :first_gear, :idling)
- assert_not_equal transition, @transition
- end
-
- def test_should_not_be_equal_with_different_to_state_names
- @machine.state :first_gear
- transition = StateMachine::Transition.new(@object, @machine, :ignite, :idling, :first_gear)
- assert_not_equal transition, @transition
- end
- end