require File.expand_path(File.dirname(__FILE__) + '/../test_helper') class EventByDefaultTest < Test::Unit::TestCase def setup @klass = Class.new @machine = EnumStateMachine::Machine.new(@klass) @machine.events << @event = EnumStateMachine::Event.new(@machine, :ignite) @object = @klass.new end def test_should_have_a_machine assert_equal @machine, @event.machine end def test_should_have_a_name assert_equal :ignite, @event.name end def test_should_have_a_qualified_name assert_equal :ignite, @event.qualified_name end def test_should_have_a_human_name assert_equal 'ignite', @event.human_name end def test_should_not_have_any_branches assert @event.branches.empty? end def test_should_have_no_known_states assert @event.known_states.empty? end def test_should_not_be_able_to_fire assert !@event.can_fire?(@object) end def test_should_not_have_a_transition assert_nil @event.transition_for(@object) end def test_should_define_a_predicate assert @object.respond_to?(:can_ignite?) end def test_should_define_a_transition_accessor assert @object.respond_to?(:ignite_transition) end def test_should_define_an_action assert @object.respond_to?(:ignite) end def test_should_define_a_bang_action assert @object.respond_to?(:ignite!) end end class EventTest < Test::Unit::TestCase def setup @machine = EnumStateMachine::Machine.new(Class.new) @machine.events << @event = EnumStateMachine::Event.new(@machine, :ignite) @event.transition :parked => :idling end def test_should_allow_changing_machine new_machine = EnumStateMachine::Machine.new(Class.new) @event.machine = new_machine assert_equal new_machine, @event.machine end def test_should_allow_changing_human_name @event.human_name = 'Stop' assert_equal 'Stop', @event.human_name end def test_should_provide_matcher_helpers_during_initialization matchers = [] @event.instance_eval do matchers = [all, any, same] end assert_equal [EnumStateMachine::AllMatcher.instance, EnumStateMachine::AllMatcher.instance, EnumStateMachine::LoopbackMatcher.instance], matchers end def test_should_use_pretty_inspect assert_match "# :idling]>", @event.inspect end end class EventWithHumanNameTest < Test::Unit::TestCase def setup @klass = Class.new @machine = EnumStateMachine::Machine.new(@klass) @machine.events << @event = EnumStateMachine::Event.new(@machine, :ignite, :human_name => 'start') end def test_should_use_custom_human_name assert_equal 'start', @event.human_name end end class EventWithDynamicHumanNameTest < Test::Unit::TestCase def setup @klass = Class.new @machine = EnumStateMachine::Machine.new(@klass) @machine.events << @event = EnumStateMachine::Event.new(@machine, :ignite, :human_name => lambda {|event, object| ['start', object]}) end def test_should_use_custom_human_name human_name, klass = @event.human_name assert_equal 'start', human_name assert_equal @klass, klass end def test_should_allow_custom_class_to_be_passed_through human_name, klass = @event.human_name(1) assert_equal 'start', human_name assert_equal 1, klass end def test_should_not_cache_value assert_not_same @event.human_name, @event.human_name end end class EventWithConflictingHelpersBeforeDefinitionTest < Test::Unit::TestCase def setup require 'stringio' @original_stderr, $stderr = $stderr, StringIO.new @superclass = Class.new do def can_ignite? 0 end def ignite_transition 0 end def ignite 0 end def ignite! 0 end end @klass = Class.new(@superclass) @machine = EnumStateMachine::Machine.new(@klass) @machine.events << @event = EnumStateMachine::Event.new(@machine, :ignite) @object = @klass.new end def test_should_not_redefine_predicate assert_equal 0, @object.can_ignite? end def test_should_not_redefine_transition_accessor assert_equal 0, @object.ignite_transition end def test_should_not_redefine_action assert_equal 0, @object.ignite end def test_should_not_redefine_bang_action assert_equal 0, @object.ignite! end def test_should_output_warning expected = %w(can_ignite? ignite_transition ignite ignite!).map do |method| "Instance method \"#{method}\" is already defined in #{@superclass.to_s}, use generic helper instead or set EnumStateMachine::Machine.ignore_method_conflicts = true.\n" end.join assert_equal expected, $stderr.string end def teardown $stderr = @original_stderr end end class EventWithConflictingHelpersAfterDefinitionTest < Test::Unit::TestCase def setup require 'stringio' @original_stderr, $stderr = $stderr, StringIO.new @klass = Class.new do def can_ignite? 0 end def ignite_transition 0 end def ignite 0 end def ignite! 0 end end @machine = EnumStateMachine::Machine.new(@klass) @machine.events << @event = EnumStateMachine::Event.new(@machine, :ignite) @object = @klass.new end def test_should_not_redefine_predicate assert_equal 0, @object.can_ignite? end def test_should_not_redefine_transition_accessor assert_equal 0, @object.ignite_transition end def test_should_not_redefine_action assert_equal 0, @object.ignite end def test_should_not_redefine_bang_action assert_equal 0, @object.ignite! end def test_should_allow_super_chaining @klass.class_eval do def can_ignite? super end def ignite_transition super end def ignite super end def ignite! super end end assert_equal false, @object.can_ignite? assert_equal nil, @object.ignite_transition assert_equal false, @object.ignite assert_raise(EnumStateMachine::InvalidTransition) { @object.ignite! } end def test_should_not_output_warning assert_equal '', $stderr.string end def teardown $stderr = @original_stderr end end class EventWithConflictingMachineTest < Test::Unit::TestCase def setup require 'stringio' @original_stderr, $stderr = $stderr, StringIO.new @klass = Class.new @state_machine = EnumStateMachine::Machine.new(@klass, :state) @state_machine.state :parked, :idling @state_machine.events << @state_event = EnumStateMachine::Event.new(@state_machine, :ignite) end def test_should_not_overwrite_first_event @status_machine = EnumStateMachine::Machine.new(@klass, :status) @status_machine.state :first_gear, :second_gear @status_machine.events << @status_event = EnumStateMachine::Event.new(@status_machine, :ignite) @object = @klass.new @object.state = 'parked' @object.status = 'first_gear' @state_event.transition(:parked => :idling) @status_event.transition(:parked => :first_gear) @object.ignite assert_equal 'idling', @object.state assert_equal 'first_gear', @object.status end def test_should_output_warning @status_machine = EnumStateMachine::Machine.new(@klass, :status) @status_machine.events << @status_event = EnumStateMachine::Event.new(@status_machine, :ignite) assert_equal "Event :ignite for :status is already defined in :state\n", $stderr.string end def test_should_not_output_warning_if_using_different_namespace @status_machine = EnumStateMachine::Machine.new(@klass, :status, :namespace => 'alarm') @status_machine.events << @status_event = EnumStateMachine::Event.new(@status_machine, :ignite) assert_equal '', $stderr.string end def teardown $stderr = @original_stderr end end class EventWithNamespaceTest < Test::Unit::TestCase def setup @klass = Class.new @machine = EnumStateMachine::Machine.new(@klass, :namespace => 'alarm') @machine.events << @event = EnumStateMachine::Event.new(@machine, :enable) @object = @klass.new end def test_should_have_a_name assert_equal :enable, @event.name end def test_should_have_a_qualified_name assert_equal :enable_alarm, @event.qualified_name end def test_should_namespace_predicate assert @object.respond_to?(:can_enable_alarm?) end def test_should_namespace_transition_accessor assert @object.respond_to?(:enable_alarm_transition) end def test_should_namespace_action assert @object.respond_to?(:enable_alarm) end def test_should_namespace_bang_action assert @object.respond_to?(:enable_alarm!) end end class EventContextTest < Test::Unit::TestCase def setup @klass = Class.new @machine = EnumStateMachine::Machine.new(@klass) @machine.events << @event = EnumStateMachine::Event.new(@machine, :ignite, :human_name => 'start') end def test_should_evaluate_within_the_event scope = nil @event.context { scope = self } assert_equal @event, scope end end class EventTransitionsTest < Test::Unit::TestCase def setup @machine = EnumStateMachine::Machine.new(Class.new) @machine.events << @event = EnumStateMachine::Event.new(@machine, :ignite) end def test_should_not_raise_exception_if_implicit_option_specified assert_nothing_raised {@event.transition(:invalid => :valid)} end def test_should_not_allow_on_option exception = assert_raise(ArgumentError) {@event.transition(:on => :ignite)} assert_equal 'Invalid key(s): on', exception.message end def test_should_automatically_set_on_option branch = @event.transition(:to => :idling) assert_instance_of EnumStateMachine::WhitelistMatcher, branch.event_requirement assert_equal [:ignite], branch.event_requirement.values end def test_should_not_allow_except_on_option exception = assert_raise(ArgumentError) {@event.transition(:except_on => :ignite)} assert_equal 'Invalid key(s): except_on', exception.message end def test_should_allow_transitioning_without_a_to_state assert_nothing_raised {@event.transition(:from => :parked)} end def test_should_allow_transitioning_without_a_from_state assert_nothing_raised {@event.transition(:to => :idling)} end def test_should_allow_except_from_option assert_nothing_raised {@event.transition(:except_from => :idling)} end def test_should_allow_except_to_option assert_nothing_raised {@event.transition(:except_to => :idling)} end def test_should_allow_transitioning_from_a_single_state assert @event.transition(:parked => :idling) end def test_should_allow_transitioning_from_multiple_states assert @event.transition([:parked, :idling] => :idling) end def test_should_allow_transitions_to_multiple_states assert @event.transition(:parked => [:parked, :idling]) end def test_should_have_transitions branch = @event.transition(:to => :idling) assert_equal [branch], @event.branches end end class EventAfterBeingCopiedTest < Test::Unit::TestCase def setup @machine = EnumStateMachine::Machine.new(Class.new) @machine.events << @event = EnumStateMachine::Event.new(@machine, :ignite) @copied_event = @event.dup end def test_should_not_have_the_same_collection_of_branches assert_not_same @event.branches, @copied_event.branches end def test_should_not_have_the_same_collection_of_known_states assert_not_same @event.known_states, @copied_event.known_states end end class EventWithoutTransitionsTest < Test::Unit::TestCase def setup @klass = Class.new @machine = EnumStateMachine::Machine.new(@klass) @machine.events << @event = EnumStateMachine::Event.new(@machine, :ignite) @object = @klass.new end def test_should_not_be_able_to_fire assert !@event.can_fire?(@object) end def test_should_not_have_a_transition assert_nil @event.transition_for(@object) end def test_should_not_fire assert !@event.fire(@object) end def test_should_not_change_the_current_state @event.fire(@object) assert_nil @object.state end end class EventWithTransitionsTest < Test::Unit::TestCase def setup @klass = Class.new @machine = EnumStateMachine::Machine.new(@klass) @machine.events << @event = EnumStateMachine::Event.new(@machine, :ignite) @event.transition(:parked => :idling) @event.transition(:first_gear => :idling) end def test_should_include_all_transition_states_in_known_states assert_equal [:parked, :idling, :first_gear], @event.known_states end def test_should_include_new_transition_states_after_calling_known_states @event.known_states @event.transition(:stalled => :idling) assert_equal [:parked, :idling, :first_gear, :stalled], @event.known_states end def test_should_clear_known_states_on_reset @event.reset assert_equal [], @event.known_states end def test_should_use_pretty_inspect assert_match "# :idling, :first_gear => :idling]>", @event.inspect end end class EventWithoutMatchingTransitionsTest < Test::Unit::TestCase def setup @klass = Class.new @machine = EnumStateMachine::Machine.new(@klass) @machine.state :parked, :idling @machine.events << @event = EnumStateMachine::Event.new(@machine, :ignite) @event.transition(:parked => :idling) @object = @klass.new @object.state = 'idling' end def test_should_not_be_able_to_fire assert !@event.can_fire?(@object) end def test_should_be_able_to_fire_with_custom_from_state assert @event.can_fire?(@object, :from => :parked) end def test_should_not_have_a_transition assert_nil @event.transition_for(@object) end def test_should_have_a_transition_with_custom_from_state assert_not_nil @event.transition_for(@object, :from => :parked) end def test_should_not_fire assert !@event.fire(@object) end def test_should_not_change_the_current_state @event.fire(@object) assert_equal 'idling', @object.state end end class EventWithMatchingDisabledTransitionsTest < Test::Unit::TestCase def setup EnumStateMachine::Integrations.const_set('Custom', Module.new do include EnumStateMachine::Integrations::Base def invalidate(object, attribute, message, values = []) (object.errors ||= []) << generate_message(message, values) end def reset(object) object.errors = [] end end) @klass = Class.new do attr_accessor :errors end @machine = EnumStateMachine::Machine.new(@klass, :integration => :custom) @machine.state :parked, :idling @machine.events << @event = EnumStateMachine::Event.new(@machine, :ignite) @event.transition(:parked => :idling, :if => lambda {false}) @object = @klass.new @object.state = 'parked' end def test_should_not_be_able_to_fire assert !@event.can_fire?(@object) end def test_should_be_able_to_fire_with_disabled_guards assert @event.can_fire?(@object, :guard => false) end def test_should_not_have_a_transition assert_nil @event.transition_for(@object) end def test_should_have_a_transition_with_disabled_guards assert_not_nil @event.transition_for(@object, :guard => false) end def test_should_not_fire assert !@event.fire(@object) end def test_should_not_change_the_current_state @event.fire(@object) assert_equal 'parked', @object.state end def test_should_invalidate_the_state @event.fire(@object) assert_equal ['cannot transition via "ignite"'], @object.errors end def test_should_invalidate_with_human_event_name @event.human_name = 'start' @event.fire(@object) assert_equal ['cannot transition via "start"'], @object.errors end def test_should_invalid_with_human_state_name_if_specified klass = Class.new do attr_accessor :errors end machine = EnumStateMachine::Machine.new(klass, :integration => :custom, :messages => {:invalid_transition => 'cannot transition via "%s" from "%s"'}) parked, idling = machine.state :parked, :idling parked.human_name = 'stopped' machine.events << event = EnumStateMachine::Event.new(machine, :ignite) event.transition(:parked => :idling, :if => lambda {false}) object = @klass.new object.state = 'parked' event.fire(object) assert_equal ['cannot transition via "ignite" from "stopped"'], object.errors end def test_should_reset_existing_error @object.errors = ['invalid'] @event.fire(@object) assert_equal ['cannot transition via "ignite"'], @object.errors end def test_should_run_failure_callbacks callback_args = nil @machine.after_failure {|*args| callback_args = args} @event.fire(@object) object, transition = callback_args assert_equal @object, object assert_not_nil transition assert_equal @object, transition.object assert_equal @machine, transition.machine assert_equal :ignite, transition.event assert_equal :parked, transition.from_name assert_equal :parked, transition.to_name end def teardown EnumStateMachine::Integrations.send(:remove_const, 'Custom') end end class EventWithMatchingEnabledTransitionsTest < Test::Unit::TestCase def setup EnumStateMachine::Integrations.const_set('Custom', Module.new do include EnumStateMachine::Integrations::Base def invalidate(object, attribute, message, values = []) (object.errors ||= []) << generate_message(message, values) end def reset(object) object.errors = [] end end) @klass = Class.new do attr_accessor :errors end @machine = EnumStateMachine::Machine.new(@klass, :integration => :custom) @machine.state :parked, :idling @machine.events << @event = EnumStateMachine::Event.new(@machine, :ignite) @event.transition(:parked => :idling) @object = @klass.new @object.state = 'parked' end def test_should_be_able_to_fire assert @event.can_fire?(@object) end def test_should_have_a_transition transition = @event.transition_for(@object) assert_not_nil transition assert_equal 'parked', transition.from assert_equal 'idling', transition.to assert_equal :ignite, transition.event end def test_should_fire assert @event.fire(@object) end def test_should_change_the_current_state @event.fire(@object) assert_equal 'idling', @object.state end def test_should_reset_existing_error @object.errors = ['invalid'] @event.fire(@object) assert_equal [], @object.errors end def test_should_not_invalidate_the_state @event.fire(@object) assert_equal [], @object.errors end def test_should_not_be_able_to_fire_on_reset @event.reset assert !@event.can_fire?(@object) end def teardown EnumStateMachine::Integrations.send(:remove_const, 'Custom') end end class EventWithTransitionWithoutToStateTest < Test::Unit::TestCase def setup @klass = Class.new @machine = EnumStateMachine::Machine.new(@klass) @machine.state :parked @machine.events << @event = EnumStateMachine::Event.new(@machine, :park) @event.transition(:from => :parked) @object = @klass.new @object.state = 'parked' end def test_should_be_able_to_fire assert @event.can_fire?(@object) end def test_should_have_a_transition transition = @event.transition_for(@object) assert_not_nil transition assert_equal 'parked', transition.from assert_equal 'parked', transition.to assert_equal :park, transition.event end def test_should_fire assert @event.fire(@object) end def test_should_not_change_the_current_state @event.fire(@object) assert_equal 'parked', @object.state end end class EventWithTransitionWithNilToStateTest < Test::Unit::TestCase def setup @klass = Class.new @machine = EnumStateMachine::Machine.new(@klass) @machine.state nil, :idling @machine.events << @event = EnumStateMachine::Event.new(@machine, :park) @event.transition(:idling => nil) @object = @klass.new @object.state = 'idling' end def test_should_be_able_to_fire assert @event.can_fire?(@object) end def test_should_have_a_transition transition = @event.transition_for(@object) assert_not_nil transition assert_equal 'idling', transition.from assert_equal nil, transition.to assert_equal :park, transition.event end def test_should_fire assert @event.fire(@object) end def test_should_not_change_the_current_state @event.fire(@object) assert_equal nil, @object.state end end class EventWithTransitionWithLoopbackStateTest < Test::Unit::TestCase def setup @klass = Class.new @machine = EnumStateMachine::Machine.new(@klass) @machine.state :parked @machine.events << @event = EnumStateMachine::Event.new(@machine, :park) @event.transition(:from => :parked, :to => EnumStateMachine::LoopbackMatcher.instance) @object = @klass.new @object.state = 'parked' end def test_should_be_able_to_fire assert @event.can_fire?(@object) end def test_should_have_a_transition transition = @event.transition_for(@object) assert_not_nil transition assert_equal 'parked', transition.from assert_equal 'parked', transition.to assert_equal :park, transition.event end def test_should_fire assert @event.fire(@object) end def test_should_not_change_the_current_state @event.fire(@object) assert_equal 'parked', @object.state end end class EventWithTransitionWithBlacklistedToStateTest < Test::Unit::TestCase def setup @klass = Class.new @machine = EnumStateMachine::Machine.new(@klass, :initial => :parked) @machine.state :parked, :idling, :first_gear, :second_gear @machine.events << @event = EnumStateMachine::Event.new(@machine, :ignite) @event.transition(:from => :parked, :to => EnumStateMachine::BlacklistMatcher.new([:parked, :idling])) @object = @klass.new @object.state = 'parked' end def test_should_be_able_to_fire assert @event.can_fire?(@object) end def test_should_have_a_transition transition = @event.transition_for(@object) assert_not_nil transition assert_equal 'parked', transition.from assert_equal 'first_gear', transition.to assert_equal :ignite, transition.event end def test_should_allow_loopback_first_when_possible @event.transition(:from => :second_gear, :to => EnumStateMachine::BlacklistMatcher.new([:parked, :idling])) @object.state = 'second_gear' transition = @event.transition_for(@object) assert_not_nil transition assert_equal 'second_gear', transition.from assert_equal 'second_gear', transition.to assert_equal :ignite, transition.event end def test_should_allow_specific_transition_selection_using_to transition = @event.transition_for(@object, :from => :parked, :to => :second_gear) assert_not_nil transition assert_equal 'parked', transition.from assert_equal 'second_gear', transition.to assert_equal :ignite, transition.event end def test_should_not_allow_transition_selection_if_not_matching transition = @event.transition_for(@object, :from => :parked, :to => :parked) assert_nil transition end def test_should_fire assert @event.fire(@object) end def test_should_change_the_current_state @event.fire(@object) assert_equal 'first_gear', @object.state end end class EventWithTransitionWithWhitelistedToStateTest < Test::Unit::TestCase def setup @klass = Class.new @machine = EnumStateMachine::Machine.new(@klass, :initial => :parked) @machine.state :parked, :idling, :first_gear, :second_gear @machine.events << @event = EnumStateMachine::Event.new(@machine, :ignite) @event.transition(:from => :parked, :to => EnumStateMachine::WhitelistMatcher.new([:first_gear, :second_gear])) @object = @klass.new @object.state = 'parked' end def test_should_be_able_to_fire assert @event.can_fire?(@object) end def test_should_have_a_transition transition = @event.transition_for(@object) assert_not_nil transition assert_equal 'parked', transition.from assert_equal 'first_gear', transition.to assert_equal :ignite, transition.event end def test_should_allow_specific_transition_selection_using_to transition = @event.transition_for(@object, :from => :parked, :to => :second_gear) assert_not_nil transition assert_equal 'parked', transition.from assert_equal 'second_gear', transition.to assert_equal :ignite, transition.event end def test_should_not_allow_transition_selection_if_not_matching transition = @event.transition_for(@object, :from => :parked, :to => :parked) assert_nil transition end def test_should_fire assert @event.fire(@object) end def test_should_change_the_current_state @event.fire(@object) assert_equal 'first_gear', @object.state end end class EventWithMultipleTransitionsTest < Test::Unit::TestCase def setup @klass = Class.new @machine = EnumStateMachine::Machine.new(@klass) @machine.state :parked, :idling @machine.events << @event = EnumStateMachine::Event.new(@machine, :ignite) @event.transition(:idling => :idling) @event.transition(:parked => :idling) @event.transition(:parked => :parked) @object = @klass.new @object.state = 'parked' end def test_should_be_able_to_fire assert @event.can_fire?(@object) end def test_should_have_a_transition transition = @event.transition_for(@object) assert_not_nil transition assert_equal 'parked', transition.from assert_equal 'idling', transition.to assert_equal :ignite, transition.event end def test_should_allow_specific_transition_selection_using_from transition = @event.transition_for(@object, :from => :idling) assert_not_nil transition assert_equal 'idling', transition.from assert_equal 'idling', transition.to assert_equal :ignite, transition.event end def test_should_allow_specific_transition_selection_using_to transition = @event.transition_for(@object, :from => :parked, :to => :parked) assert_not_nil transition assert_equal 'parked', transition.from assert_equal 'parked', transition.to assert_equal :ignite, transition.event end def test_should_not_allow_specific_transition_selection_using_on exception = assert_raise(ArgumentError) { @event.transition_for(@object, :on => :park) } assert_equal 'Invalid key(s): on', exception.message end def test_should_fire assert @event.fire(@object) end def test_should_change_the_current_state @event.fire(@object) assert_equal 'idling', @object.state end end class EventWithMachineActionTest < Test::Unit::TestCase def setup @klass = Class.new do attr_reader :saved def save @saved = true end end @machine = EnumStateMachine::Machine.new(@klass, :action => :save) @machine.state :parked, :idling @machine.events << @event = EnumStateMachine::Event.new(@machine, :ignite) @event.transition(:parked => :idling) @object = @klass.new @object.state = 'parked' end def test_should_run_action_on_fire @event.fire(@object) assert @object.saved end def test_should_not_run_action_if_configured_to_skip @event.fire(@object, false) assert !@object.saved end end class EventWithInvalidCurrentStateTest < Test::Unit::TestCase def setup @klass = Class.new @machine = EnumStateMachine::Machine.new(@klass) @machine.state :parked, :idling @machine.events << @event = EnumStateMachine::Event.new(@machine, :ignite) @event.transition(:parked => :idling) @object = @klass.new @object.state = 'invalid' end def test_should_raise_exception_when_checking_availability exception = assert_raise(ArgumentError) { @event.can_fire?(@object) } assert_equal '"invalid" is not a known state value', exception.message end def test_should_raise_exception_when_finding_transition exception = assert_raise(ArgumentError) { @event.transition_for(@object) } assert_equal '"invalid" is not a known state value', exception.message end def test_should_raise_exception_when_firing exception = assert_raise(ArgumentError) { @event.fire(@object) } assert_equal '"invalid" is not a known state value', exception.message end end class EventOnFailureTest < Test::Unit::TestCase def setup EnumStateMachine::Integrations.const_set('Custom', Module.new do include EnumStateMachine::Integrations::Base def invalidate(object, attribute, message, values = []) (object.errors ||= []) << generate_message(message, values) end def reset(object) object.errors = [] end end) @klass = Class.new do attr_accessor :errors end @machine = EnumStateMachine::Machine.new(@klass, :integration => :custom) @machine.state :parked @machine.events << @event = EnumStateMachine::Event.new(@machine, :ignite) @object = @klass.new @object.state = 'parked' end def test_should_invalidate_the_state @event.fire(@object) assert_equal ['cannot transition via "ignite"'], @object.errors end def test_should_run_failure_callbacks callback_args = nil @machine.after_failure {|*args| callback_args = args} @event.fire(@object) object, transition = callback_args assert_equal @object, object assert_not_nil transition assert_equal @object, transition.object assert_equal @machine, transition.machine assert_equal :ignite, transition.event assert_equal :parked, transition.from_name assert_equal :parked, transition.to_name end def teardown EnumStateMachine::Integrations.send(:remove_const, 'Custom') end end class EventWithMarshallingTest < Test::Unit::TestCase def setup @klass = Class.new do def save true end end self.class.const_set('Example', @klass) @machine = EnumStateMachine::Machine.new(@klass, :action => :save) @machine.state :parked, :idling @machine.events << @event = EnumStateMachine::Event.new(@machine, :ignite) @event.transition(:parked => :idling) @object = @klass.new @object.state = 'parked' end def test_should_marshal_during_before_callbacks @machine.before_transition {|object, transition| Marshal.dump(object)} assert_nothing_raised { @event.fire(@object) } end def test_should_marshal_during_action @klass.class_eval do remove_method :save def save Marshal.dump(self) end end assert_nothing_raised { @event.fire(@object) } end def test_should_marshal_during_after_callbacks @machine.after_transition {|object, transition| Marshal.dump(object)} assert_nothing_raised { @event.fire(@object) } end def teardown self.class.send(:remove_const, 'Example') end end begin # Load library require 'graphviz' class EventDrawingTest < Test::Unit::TestCase def setup states = [:parked, :idling, :first_gear] @machine = EnumStateMachine::Machine.new(Class.new, :initial => :parked) @machine.other_states(*states) @graph = EnumStateMachine::Graph.new('test') states.each {|state| @graph.add_nodes(state.to_s)} @machine.events << @event = EnumStateMachine::Event.new(@machine , :park) @event.transition :parked => :idling @event.transition :first_gear => :parked @event.transition :except_from => :parked, :to => :parked @event.draw(@graph) end def test_should_generate_edges_for_each_transition assert_equal 4, @graph.edge_count end def test_should_use_event_name_for_edge_label assert_equal 'park', @graph.get_edge_at_index(0)['label'].to_s.gsub('"', '') end end class EventDrawingWithHumanNameTest < Test::Unit::TestCase def setup states = [:parked, :idling] @machine = EnumStateMachine::Machine.new(Class.new, :initial => :parked) @machine.other_states(*states) graph = EnumStateMachine::Graph.new('test') states.each {|state| graph.add_nodes(state.to_s)} @machine.events << @event = EnumStateMachine::Event.new(@machine , :park, :human_name => 'Park') @event.transition :parked => :idling @event.draw(graph, :human_name => true) @edge = graph.get_edge_at_index(0) end def test_should_use_event_human_name_for_edge_label assert_equal 'Park', @edge['label'].to_s.gsub('"', '') end end rescue LoadError $stderr.puts 'Skipping GraphViz EnumStateMachine::Event tests. `gem install ruby-graphviz` >= v0.9.17 and try again.' end unless ENV['TRAVIS']