/lib/gemcache/ruby/1.9.1/gems/state_machine-1.1.2/test/unit/machine_test.rb
Ruby | 3379 lines | 2682 code | 695 blank | 2 comment | 9 complexity | b5f4683dd6ae657df60f347e2f1333b6 MD5 | raw file
Possible License(s): BSD-3-Clause, Apache-2.0, LGPL-2.1, GPL-2.0, MIT
Large files files are truncated, but you can click here to view the full file
- require File.expand_path(File.dirname(__FILE__) + '/../test_helper')
- class MachineByDefaultTest < Test::Unit::TestCase
- def setup
- @klass = Class.new
- @machine = StateMachine::Machine.new(@klass)
- @object = @klass.new
- end
-
- def test_should_have_an_owner_class
- assert_equal @klass, @machine.owner_class
- end
-
- def test_should_have_a_name
- assert_equal :state, @machine.name
- end
-
- def test_should_have_an_attribute
- assert_equal :state, @machine.attribute
- end
-
- def test_should_prefix_custom_attributes_with_attribute
- assert_equal :state_event, @machine.attribute(:event)
- end
-
- def test_should_have_an_initial_state
- assert_not_nil @machine.initial_state(@object)
- end
-
- def test_should_have_a_nil_initial_state
- assert_nil @machine.initial_state(@object).value
- end
-
- def test_should_not_have_any_events
- assert !@machine.events.any?
- end
-
- def test_should_not_have_any_before_callbacks
- assert @machine.callbacks[:before].empty?
- end
-
- def test_should_not_have_any_after_callbacks
- assert @machine.callbacks[:after].empty?
- end
-
- def test_should_not_have_any_failure_callbacks
- assert @machine.callbacks[:failure].empty?
- end
-
- def test_should_not_have_an_action
- assert_nil @machine.action
- end
-
- def test_should_use_tranactions
- assert_equal true, @machine.use_transactions
- end
-
- def test_should_not_have_a_namespace
- assert_nil @machine.namespace
- end
-
- def test_should_have_a_nil_state
- assert_equal [nil], @machine.states.keys
- end
-
- def test_should_set_initial_on_nil_state
- assert @machine.state(nil).initial
- end
-
- def test_should_generate_default_messages
- assert_equal 'is invalid', @machine.generate_message(:invalid)
- assert_equal 'cannot transition when parked', @machine.generate_message(:invalid_event, [[:state, :parked]])
- assert_equal 'cannot transition via "park"', @machine.generate_message(:invalid_transition, [[:event, :park]])
- end
-
- def test_should_not_be_extended_by_the_base_integration
- assert !(class << @machine; ancestors; end).include?(StateMachine::Integrations::Base)
- end
-
- def test_should_not_be_extended_by_the_active_model_integration
- assert !(class << @machine; ancestors; end).include?(StateMachine::Integrations::ActiveModel)
- end
-
- def test_should_not_be_extended_by_the_active_record_integration
- assert !(class << @machine; ancestors; end).include?(StateMachine::Integrations::ActiveRecord)
- end
-
- def test_should_not_be_extended_by_the_datamapper_integration
- assert !(class << @machine; ancestors; end).include?(StateMachine::Integrations::DataMapper)
- end
-
- def test_should_not_be_extended_by_the_mongo_mapper_integration
- assert !(class << @machine; ancestors; end).include?(StateMachine::Integrations::MongoMapper)
- end
-
- def test_should_not_be_extended_by_the_sequel_integration
- assert !(class << @machine; ancestors; end).include?(StateMachine::Integrations::Sequel)
- end
-
- def test_should_define_a_reader_attribute_for_the_attribute
- assert @object.respond_to?(:state)
- end
-
- def test_should_define_a_writer_attribute_for_the_attribute
- assert @object.respond_to?(:state=)
- end
-
- def test_should_define_a_predicate_for_the_attribute
- assert @object.respond_to?(:state?)
- end
-
- def test_should_define_a_name_reader_for_the_attribute
- assert @object.respond_to?(:state_name)
- end
-
- def test_should_define_an_event_reader_for_the_attribute
- assert @object.respond_to?(:state_events)
- end
-
- def test_should_define_a_transition_reader_for_the_attribute
- assert @object.respond_to?(:state_transitions)
- end
-
- def test_should_define_a_path_reader_for_the_attribute
- assert @object.respond_to?(:state_paths)
- end
-
- def test_should_define_an_event_runner_for_the_attribute
- assert @object.respond_to?(:fire_state_event)
- end
-
- def test_should_not_define_an_event_attribute_reader
- assert !@object.respond_to?(:state_event)
- end
-
- def test_should_not_define_an_event_attribute_writer
- assert !@object.respond_to?(:state_event=)
- end
-
- def test_should_not_define_an_event_transition_attribute_reader
- assert !@object.respond_to?(:state_event_transition)
- end
-
- def test_should_not_define_an_event_transition_attribute_writer
- assert !@object.respond_to?(:state_event_transition=)
- end
-
- def test_should_define_a_human_attribute_name_reader_for_the_attribute
- assert @klass.respond_to?(:human_state_name)
- end
-
- def test_should_define_a_human_event_name_reader_for_the_attribute
- assert @klass.respond_to?(:human_state_event_name)
- end
-
- def test_should_not_define_singular_with_scope
- assert !@klass.respond_to?(:with_state)
- end
-
- def test_should_not_define_singular_without_scope
- assert !@klass.respond_to?(:without_state)
- end
-
- def test_should_not_define_plural_with_scope
- assert !@klass.respond_to?(:with_states)
- end
-
- def test_should_not_define_plural_without_scope
- assert !@klass.respond_to?(:without_states)
- end
-
- def test_should_extend_owner_class_with_class_methods
- assert (class << @klass; ancestors; end).include?(StateMachine::ClassMethods)
- end
-
- def test_should_include_instance_methods_in_owner_class
- assert @klass.included_modules.include?(StateMachine::InstanceMethods)
- end
-
- def test_should_define_state_machines_reader
- expected = {:state => @machine}
- assert_equal expected, @klass.state_machines
- end
- end
- class MachineWithCustomNameTest < Test::Unit::TestCase
- def setup
- @klass = Class.new
- @machine = StateMachine::Machine.new(@klass, :status)
- @object = @klass.new
- end
-
- def test_should_use_custom_name
- assert_equal :status, @machine.name
- end
-
- def test_should_use_custom_name_for_attribute
- assert_equal :status, @machine.attribute
- end
-
- def test_should_prefix_custom_attributes_with_custom_name
- assert_equal :status_event, @machine.attribute(:event)
- end
-
- def test_should_define_a_reader_attribute_for_the_attribute
- assert @object.respond_to?(:status)
- end
-
- def test_should_define_a_writer_attribute_for_the_attribute
- assert @object.respond_to?(:status=)
- end
-
- def test_should_define_a_predicate_for_the_attribute
- assert @object.respond_to?(:status?)
- end
-
- def test_should_define_a_name_reader_for_the_attribute
- assert @object.respond_to?(:status_name)
- end
-
- def test_should_define_an_event_reader_for_the_attribute
- assert @object.respond_to?(:status_events)
- end
-
- def test_should_define_a_transition_reader_for_the_attribute
- assert @object.respond_to?(:status_transitions)
- end
-
- def test_should_define_an_event_runner_for_the_attribute
- assert @object.respond_to?(:fire_status_event)
- end
-
- def test_should_define_a_human_attribute_name_reader_for_the_attribute
- assert @klass.respond_to?(:human_status_name)
- end
-
- def test_should_define_a_human_event_name_reader_for_the_attribute
- assert @klass.respond_to?(:human_status_event_name)
- end
- end
- class MachineWithoutInitializationTest < Test::Unit::TestCase
- def setup
- @klass = Class.new do
- def initialize(attributes = {})
- attributes.each {|attr, value| send("#{attr}=", value)}
- super()
- end
- end
-
- @machine = StateMachine::Machine.new(@klass, :initial => :parked, :initialize => false)
- end
-
- def test_should_not_have_an_initial_state
- object = @klass.new
- assert_nil object.state
- end
-
- def test_should_still_allow_manual_initialization
- @klass.class_eval do
- def initialize(attributes = {})
- attributes.each {|attr, value| send("#{attr}=", value)}
- super()
- initialize_state_machines
- end
- end
-
- object = @klass.new
- assert_equal 'parked', object.state
- end
- end
- class MachineWithStaticInitialStateTest < Test::Unit::TestCase
- def setup
- @klass = Class.new
- @machine = StateMachine::Machine.new(@klass, :initial => :parked)
- end
-
- def test_should_not_have_dynamic_initial_state
- assert !@machine.dynamic_initial_state?
- end
-
- def test_should_have_an_initial_state
- object = @klass.new
- assert_equal 'parked', @machine.initial_state(object).value
- end
-
- def test_should_write_to_attribute_when_initializing_state
- object = @klass.allocate
- @machine.initialize_state(object)
- assert_equal 'parked', object.state
- end
-
- def test_should_set_initial_on_state_object
- assert @machine.state(:parked).initial
- end
-
- def test_should_set_initial_state_on_created_object
- assert_equal 'parked', @klass.new.state
- end
-
- def test_should_still_set_initial_state_even_if_not_empty
- @klass.class_eval do
- def initialize(attributes = {})
- self.state = 'idling'
- super()
- end
- end
- object = @klass.new
- assert_equal 'parked', object.state
- end
-
- def test_should_set_initial_state_prior_to_initialization
- base = Class.new do
- attr_accessor :state_on_init
-
- def initialize
- self.state_on_init = state
- end
- end
- klass = Class.new(base)
- machine = StateMachine::Machine.new(klass, :initial => :parked)
-
- assert_equal 'parked', klass.new.state_on_init
- end
-
- def test_should_be_included_in_known_states
- assert_equal [:parked], @machine.states.keys
- end
- end
- class MachineWithDynamicInitialStateTest < Test::Unit::TestCase
- def setup
- @klass = Class.new do
- attr_accessor :initial_state
- end
- @machine = StateMachine::Machine.new(@klass, :initial => lambda {|object| object.initial_state || :default})
- @machine.state :parked, :idling, :default
- @object = @klass.new
- end
-
- def test_should_have_dynamic_initial_state
- assert @machine.dynamic_initial_state?
- end
-
- def test_should_use_the_record_for_determining_the_initial_state
- @object.initial_state = :parked
- assert_equal :parked, @machine.initial_state(@object).name
-
- @object.initial_state = :idling
- assert_equal :idling, @machine.initial_state(@object).name
- end
-
- def test_should_write_to_attribute_when_initializing_state
- object = @klass.allocate
- object.initial_state = :parked
- @machine.initialize_state(object)
- assert_equal 'parked', object.state
- end
-
- def test_should_set_initial_state_on_created_object
- assert_equal 'default', @object.state
- end
-
- def test_should_not_set_initial_state_even_if_not_empty
- @klass.class_eval do
- def initialize(attributes = {})
- self.state = 'parked'
- super()
- end
- end
- object = @klass.new
- assert_equal 'parked', object.state
- end
-
- def test_should_set_initial_state_after_initialization
- base = Class.new do
- attr_accessor :state_on_init
-
- def initialize
- self.state_on_init = state
- end
- end
- klass = Class.new(base)
- machine = StateMachine::Machine.new(klass, :initial => lambda {|object| :parked})
- machine.state :parked
-
- assert_nil klass.new.state_on_init
- end
-
- def test_should_not_be_included_in_known_states
- assert_equal [:parked, :idling, :default], @machine.states.map {|state| state.name}
- end
- end
- class MachineStateInitializationTest < Test::Unit::TestCase
- def setup
- @klass = Class.new
- @machine = StateMachine::Machine.new(@klass, :state, :initial => :parked, :initialize => false)
-
- @object = @klass.new
- @object.state = nil
- end
-
- def test_should_set_states_if_nil
- @machine.initialize_state(@object)
-
- assert_equal 'parked', @object.state
- end
-
- def test_should_set_states_if_empty
- @object.state = ''
- @machine.initialize_state(@object)
-
- assert_equal 'parked', @object.state
- end
-
- def test_should_not_set_states_if_not_empty
- @object.state = 'idling'
- @machine.initialize_state(@object)
-
- assert_equal 'idling', @object.state
- end
-
- def test_should_set_states_if_not_empty_and_forced
- @object.state = 'idling'
- @machine.initialize_state(@object, :force => true)
-
- assert_equal 'parked', @object.state
- end
-
- def test_should_not_set_state_if_nil_and_nil_is_valid_state
- @machine.state :initial, :value => nil
- @machine.initialize_state(@object)
-
- assert_nil @object.state
- end
-
- def test_should_write_to_hash_if_specified
- @machine.initialize_state(@object, :to => hash = {})
- assert_equal expected = {'state' => 'parked'}, hash
- end
-
- def test_should_not_write_to_object_if_writing_to_hash
- @machine.initialize_state(@object, :to => {})
- assert_nil @object.state
- end
- end
- class MachineWithCustomActionTest < Test::Unit::TestCase
- def setup
- @machine = StateMachine::Machine.new(Class.new, :action => :save)
- end
-
- def test_should_use_the_custom_action
- assert_equal :save, @machine.action
- end
- end
- class MachineWithNilActionTest < Test::Unit::TestCase
- def setup
- integration = Module.new do
- include StateMachine::Integrations::Base
-
- @defaults = {:action => :save}
- end
- StateMachine::Integrations.const_set('Custom', integration)
- @machine = StateMachine::Machine.new(Class.new, :action => nil, :integration => :custom)
- end
-
- def test_should_have_a_nil_action
- assert_nil @machine.action
- end
-
- def teardown
- StateMachine::Integrations.send(:remove_const, 'Custom')
- end
- end
- class MachineWithoutIntegrationTest < Test::Unit::TestCase
- def setup
- @klass = Class.new
- @machine = StateMachine::Machine.new(@klass)
- @object = @klass.new
- end
-
- def test_transaction_should_yield
- @yielded = false
- @machine.within_transaction(@object) do
- @yielded = true
- end
-
- assert @yielded
- end
-
- def test_invalidation_should_do_nothing
- assert_nil @machine.invalidate(@object, :state, :invalid_transition, [[:event, 'park']])
- end
-
- def test_reset_should_do_nothing
- assert_nil @machine.reset(@object)
- end
-
- def test_errors_for_should_be_empty
- assert_equal '', @machine.errors_for(@object)
- end
- end
- class MachineWithCustomIntegrationTest < Test::Unit::TestCase
- def setup
- integration = Module.new do
- include StateMachine::Integrations::Base
-
- def self.matching_ancestors
- ['MachineWithCustomIntegrationTest::Vehicle']
- end
- end
-
- StateMachine::Integrations.const_set('Custom', integration)
-
- superclass = Class.new
- self.class.const_set('Vehicle', superclass)
-
- @klass = Class.new(superclass)
- end
-
- def test_should_be_extended_by_the_integration_if_explicit
- machine = StateMachine::Machine.new(@klass, :integration => :custom)
- assert (class << machine; ancestors; end).include?(StateMachine::Integrations::Custom)
- end
-
- def test_should_not_be_extended_by_the_integration_if_implicit_but_not_available
- StateMachine::Integrations::Custom.class_eval do
- def self.matching_ancestors
- []
- end
- end
-
- machine = StateMachine::Machine.new(@klass)
- assert !(class << machine; ancestors; end).include?(StateMachine::Integrations::Custom)
- end
- def test_should_not_be_extended_by_the_integration_if_implicit_but_not_matched
- StateMachine::Integrations::Custom.class_eval do
- def self.matching_ancestors
- []
- end
- end
-
- machine = StateMachine::Machine.new(@klass)
- assert !(class << machine; ancestors; end).include?(StateMachine::Integrations::Custom)
- end
- def test_should_be_extended_by_the_integration_if_implicit_and_available_and_matches
- machine = StateMachine::Machine.new(@klass)
- assert (class << machine; ancestors; end).include?(StateMachine::Integrations::Custom)
- end
- def test_should_not_be_extended_by_the_integration_if_nil
- machine = StateMachine::Machine.new(@klass, :integration => nil)
- assert !(class << machine; ancestors; end).include?(StateMachine::Integrations::Custom)
- end
-
- def test_should_not_be_extended_by_the_integration_if_false
- machine = StateMachine::Machine.new(@klass, :integration => false)
- assert !(class << machine; ancestors; end).include?(StateMachine::Integrations::Custom)
- end
-
- def teardown
- self.class.send(:remove_const, 'Vehicle')
- StateMachine::Integrations.send(:remove_const, 'Custom')
- end
- end
- class MachineWithIntegrationTest < Test::Unit::TestCase
- def setup
- StateMachine::Integrations.const_set('Custom', Module.new do
- include StateMachine::Integrations::Base
-
- @defaults = {:action => :save, :use_transactions => false}
-
- attr_reader :initialized, :with_scopes, :without_scopes, :ran_transaction
-
- def after_initialize
- @initialized = true
- end
-
- def create_with_scope(name)
- (@with_scopes ||= []) << name
- lambda {}
- end
-
- def create_without_scope(name)
- (@without_scopes ||= []) << name
- lambda {}
- end
-
- def transaction(object)
- @ran_transaction = true
- yield
- end
- end)
-
- @machine = StateMachine::Machine.new(Class.new, :integration => :custom)
- end
-
- def test_should_call_after_initialize_hook
- assert @machine.initialized
- end
-
- def test_should_use_the_default_action
- assert_equal :save, @machine.action
- end
-
- def test_should_use_the_custom_action_if_specified
- machine = StateMachine::Machine.new(Class.new, :integration => :custom, :action => :save!)
- assert_equal :save!, machine.action
- end
-
- def test_should_use_the_default_use_transactions
- assert_equal false, @machine.use_transactions
- end
-
- def test_should_use_the_custom_use_transactions_if_specified
- machine = StateMachine::Machine.new(Class.new, :integration => :custom, :use_transactions => true)
- assert_equal true, machine.use_transactions
- end
-
- def test_should_define_a_singular_and_plural_with_scope
- assert_equal %w(with_state with_states), @machine.with_scopes
- end
-
- def test_should_define_a_singular_and_plural_without_scope
- assert_equal %w(without_state without_states), @machine.without_scopes
- end
-
- def teardown
- StateMachine::Integrations.send(:remove_const, 'Custom')
- end
- end
- class MachineWithActionUndefinedTest < Test::Unit::TestCase
- def setup
- @klass = Class.new
- @machine = StateMachine::Machine.new(@klass, :action => :save)
- @object = @klass.new
- end
-
- def test_should_define_an_event_attribute_reader
- assert @object.respond_to?(:state_event)
- end
-
- def test_should_define_an_event_attribute_writer
- assert @object.respond_to?(:state_event=)
- end
-
- def test_should_define_an_event_transition_attribute_reader
- assert @object.respond_to?(:state_event_transition)
- end
-
- def test_should_define_an_event_transition_attribute_writer
- assert @object.respond_to?(:state_event_transition=)
- end
-
- def test_should_not_define_action
- assert !@object.respond_to?(:save)
- end
-
- def test_should_not_mark_action_hook_as_defined
- assert !@machine.action_hook?
- end
- end
- class MachineWithActionDefinedInClassTest < Test::Unit::TestCase
- def setup
- @klass = Class.new do
- def save
- end
- end
-
- @machine = StateMachine::Machine.new(@klass, :action => :save)
- @object = @klass.new
- end
-
- def test_should_define_an_event_attribute_reader
- assert @object.respond_to?(:state_event)
- end
-
- def test_should_define_an_event_attribute_writer
- assert @object.respond_to?(:state_event=)
- end
-
- def test_should_define_an_event_transition_attribute_reader
- assert @object.respond_to?(:state_event_transition)
- end
-
- def test_should_define_an_event_transition_attribute_writer
- assert @object.respond_to?(:state_event_transition=)
- end
-
- def test_should_not_define_action
- assert !@klass.ancestors.any? {|ancestor| ancestor != @klass && ancestor.method_defined?(:save)}
- end
-
- def test_should_not_mark_action_hook_as_defined
- assert !@machine.action_hook?
- end
- end
- class MachineWithActionDefinedInIncludedModuleTest < Test::Unit::TestCase
- def setup
- @mod = mod = Module.new do
- def save
- end
- end
-
- @klass = Class.new do
- include mod
- end
-
- @machine = StateMachine::Machine.new(@klass, :action => :save)
- @object = @klass.new
- end
-
- def test_should_define_an_event_attribute_reader
- assert @object.respond_to?(:state_event)
- end
-
- def test_should_define_an_event_attribute_writer
- assert @object.respond_to?(:state_event=)
- end
-
- def test_should_define_an_event_transition_attribute_reader
- assert @object.respond_to?(:state_event_transition)
- end
-
- def test_should_define_an_event_transition_attribute_writer
- assert @object.respond_to?(:state_event_transition=)
- end
-
- def test_should_define_action
- assert @klass.ancestors.any? {|ancestor| ![@klass, @mod].include?(ancestor) && ancestor.method_defined?(:save)}
- end
-
- def test_should_keep_action_public
- assert @klass.public_method_defined?(:save)
- end
-
- def test_should_mark_action_hook_as_defined
- assert @machine.action_hook?
- end
- end
- class MachineWithActionDefinedInSuperclassTest < Test::Unit::TestCase
- def setup
- @superclass = Class.new do
- def save
- end
- end
- @klass = Class.new(@superclass)
-
- @machine = StateMachine::Machine.new(@klass, :action => :save)
- @object = @klass.new
- end
-
- def test_should_define_an_event_attribute_reader
- assert @object.respond_to?(:state_event)
- end
-
- def test_should_define_an_event_attribute_writer
- assert @object.respond_to?(:state_event=)
- end
-
- def test_should_define_an_event_transition_attribute_reader
- assert @object.respond_to?(:state_event_transition)
- end
-
- def test_should_define_an_event_transition_attribute_writer
- assert @object.respond_to?(:state_event_transition=)
- end
-
- def test_should_define_action
- assert @klass.ancestors.any? {|ancestor| ![@klass, @superclass].include?(ancestor) && ancestor.method_defined?(:save)}
- end
-
- def test_should_keep_action_public
- assert @klass.public_method_defined?(:save)
- end
-
- def test_should_mark_action_hook_as_defined
- assert @machine.action_hook?
- end
- end
- class MachineWithPrivateActionTest < Test::Unit::TestCase
- def setup
- @superclass = Class.new do
- private
- def save
- end
- end
- @klass = Class.new(@superclass)
-
- @machine = StateMachine::Machine.new(@klass, :action => :save)
- @object = @klass.new
- end
-
- def test_should_define_an_event_attribute_reader
- assert @object.respond_to?(:state_event)
- end
-
- def test_should_define_an_event_attribute_writer
- assert @object.respond_to?(:state_event=)
- end
-
- def test_should_define_an_event_transition_attribute_reader
- assert @object.respond_to?(:state_event_transition)
- end
-
- def test_should_define_an_event_transition_attribute_writer
- assert @object.respond_to?(:state_event_transition=)
- end
-
- def test_should_define_action
- assert @klass.ancestors.any? {|ancestor| ![@klass, @superclass].include?(ancestor) && ancestor.private_method_defined?(:save)}
- end
-
- def test_should_keep_action_private
- assert @klass.private_method_defined?(:save)
- end
-
- def test_should_mark_action_hook_as_defined
- assert @machine.action_hook?
- end
- end
- class MachineWithActionAlreadyOverriddenTest < Test::Unit::TestCase
- def setup
- @superclass = Class.new do
- def save
- end
- end
- @klass = Class.new(@superclass)
-
- StateMachine::Machine.new(@klass, :action => :save)
- @machine = StateMachine::Machine.new(@klass, :status, :action => :save)
- @object = @klass.new
- end
-
- def test_should_not_redefine_action
- assert_equal 1, @klass.ancestors.select {|ancestor| ![@klass, @superclass].include?(ancestor) && ancestor.method_defined?(:save)}.length
- end
-
- def test_should_mark_action_hook_as_defined
- assert @machine.action_hook?
- end
- end
- class MachineWithCustomPluralTest < Test::Unit::TestCase
- def setup
- @integration = Module.new do
- include StateMachine::Integrations::Base
-
- class << self; attr_accessor :with_scopes, :without_scopes; end
- @with_scopes = []
- @without_scopes = []
-
- def create_with_scope(name)
- StateMachine::Integrations::Custom.with_scopes << name
- lambda {}
- end
-
- def create_without_scope(name)
- StateMachine::Integrations::Custom.without_scopes << name
- lambda {}
- end
- end
-
- StateMachine::Integrations.const_set('Custom', @integration)
- @machine = StateMachine::Machine.new(Class.new, :integration => :custom, :plural => 'staties')
- end
-
- def test_should_define_a_singular_and_plural_with_scope
- assert_equal %w(with_state with_staties), @integration.with_scopes
- end
-
- def test_should_define_a_singular_and_plural_without_scope
- assert_equal %w(without_state without_staties), @integration.without_scopes
- end
-
- def teardown
- StateMachine::Integrations.send(:remove_const, 'Custom')
- end
- end
- class MachineWithCustomInvalidationTest < Test::Unit::TestCase
- def setup
- @integration = Module.new do
- include StateMachine::Integrations::Base
-
- def invalidate(object, attribute, message, values = [])
- object.error = generate_message(message, values)
- end
- end
- StateMachine::Integrations.const_set('Custom', @integration)
-
- @klass = Class.new do
- attr_accessor :error
- end
-
- @machine = StateMachine::Machine.new(@klass, :integration => :custom, :messages => {:invalid_transition => 'cannot %s'})
- @machine.state :parked
-
- @object = @klass.new
- @object.state = 'parked'
- end
-
- def test_generate_custom_message
- assert_equal 'cannot park', @machine.generate_message(:invalid_transition, [[:event, :park]])
- end
-
- def test_use_custom_message
- @machine.invalidate(@object, :state, :invalid_transition, [[:event, 'park']])
- assert_equal 'cannot park', @object.error
- end
-
- def teardown
- StateMachine::Integrations.send(:remove_const, 'Custom')
- end
- end
- class MachineTest < Test::Unit::TestCase
- def test_should_raise_exception_if_invalid_option_specified
- assert_raise(ArgumentError) {StateMachine::Machine.new(Class.new, :invalid => true)}
- end
-
- def test_should_not_raise_exception_if_custom_messages_specified
- assert_nothing_raised {StateMachine::Machine.new(Class.new, :messages => {:invalid_transition => 'custom'})}
- end
-
- def test_should_evaluate_a_block_during_initialization
- called = true
- StateMachine::Machine.new(Class.new) do
- called = respond_to?(:event)
- end
-
- assert called
- end
-
- def test_should_provide_matcher_helpers_during_initialization
- matchers = []
-
- StateMachine::Machine.new(Class.new) do
- matchers = [all, any, same]
- end
-
- assert_equal [StateMachine::AllMatcher.instance, StateMachine::AllMatcher.instance, StateMachine::LoopbackMatcher.instance], matchers
- end
- end
- class MachineAfterBeingCopiedTest < Test::Unit::TestCase
- def setup
- @machine = StateMachine::Machine.new(Class.new, :state, :initial => :parked)
- @machine.event(:ignite) {}
- @machine.before_transition(lambda {})
- @machine.after_transition(lambda {})
- @machine.around_transition(lambda {})
- @machine.after_failure(lambda {})
-
- @copied_machine = @machine.clone
- end
-
- def test_should_not_have_the_same_collection_of_states
- assert_not_same @copied_machine.states, @machine.states
- end
-
- def test_should_copy_each_state
- assert_not_same @copied_machine.states[:parked], @machine.states[:parked]
- end
-
- def test_should_update_machine_for_each_state
- assert_equal @copied_machine, @copied_machine.states[:parked].machine
- end
-
- def test_should_not_update_machine_for_original_state
- assert_equal @machine, @machine.states[:parked].machine
- end
-
- def test_should_not_have_the_same_collection_of_events
- assert_not_same @copied_machine.events, @machine.events
- end
-
- def test_should_copy_each_event
- assert_not_same @copied_machine.events[:ignite], @machine.events[:ignite]
- end
-
- def test_should_update_machine_for_each_event
- assert_equal @copied_machine, @copied_machine.events[:ignite].machine
- end
-
- def test_should_not_update_machine_for_original_event
- assert_equal @machine, @machine.events[:ignite].machine
- end
-
- def test_should_not_have_the_same_callbacks
- assert_not_same @copied_machine.callbacks, @machine.callbacks
- end
-
- def test_should_not_have_the_same_before_callbacks
- assert_not_same @copied_machine.callbacks[:before], @machine.callbacks[:before]
- end
-
- def test_should_not_have_the_same_after_callbacks
- assert_not_same @copied_machine.callbacks[:after], @machine.callbacks[:after]
- end
-
- def test_should_not_have_the_same_failure_callbacks
- assert_not_same @copied_machine.callbacks[:failure], @machine.callbacks[:failure]
- end
- end
- class MachineAfterChangingOwnerClassTest < Test::Unit::TestCase
- def setup
- @original_class = Class.new
- @machine = StateMachine::Machine.new(@original_class)
-
- @new_class = Class.new(@original_class)
- @new_machine = @machine.clone
- @new_machine.owner_class = @new_class
-
- @object = @new_class.new
- end
-
- def test_should_update_owner_class
- assert_equal @new_class, @new_machine.owner_class
- end
-
- def test_should_not_change_original_owner_class
- assert_equal @original_class, @machine.owner_class
- end
-
- def test_should_change_the_associated_machine_in_the_new_class
- assert_equal @new_machine, @new_class.state_machines[:state]
- end
-
- def test_should_not_change_the_associated_machine_in_the_original_class
- assert_equal @machine, @original_class.state_machines[:state]
- end
- end
- class MachineAfterChangingInitialState < Test::Unit::TestCase
- def setup
- @klass = Class.new
- @machine = StateMachine::Machine.new(@klass, :initial => :parked)
- @machine.initial_state = :idling
-
- @object = @klass.new
- end
-
- def test_should_change_the_initial_state
- assert_equal :idling, @machine.initial_state(@object).name
- end
-
- def test_should_include_in_known_states
- assert_equal [:parked, :idling], @machine.states.map {|state| state.name}
- end
-
- def test_should_reset_original_initial_state
- assert !@machine.state(:parked).initial
- end
-
- def test_should_set_new_state_to_initial
- assert @machine.state(:idling).initial
- end
- end
- class MachineWithHelpersTest < Test::Unit::TestCase
- def setup
- @klass = Class.new
- @machine = StateMachine::Machine.new(@klass)
- @object = @klass.new
- end
-
- def test_should_throw_exception_with_invalid_scope
- assert_raise(RUBY_VERSION < '1.9' ? IndexError : KeyError) { @machine.define_helper(:invalid, :park) {} }
- end
- end
- class MachineWithInstanceHelpersTest < Test::Unit::TestCase
- def setup
- @klass = Class.new
- @machine = StateMachine::Machine.new(@klass)
- @object = @klass.new
- end
-
- def test_should_not_redefine_existing_public_methods
- @klass.class_eval do
- def park
- true
- end
- end
-
- @machine.define_helper(:instance, :park) {}
- assert_equal true, @object.park
- end
-
- def test_should_not_redefine_existing_protected_methods
- @klass.class_eval do
- protected
- def park
- true
- end
- end
-
- @machine.define_helper(:instance, :park) {}
- assert_equal true, @object.send(:park)
- end
-
- def test_should_not_redefine_existing_private_methods
- @klass.class_eval do
- private
- def park
- true
- end
- end
-
- @machine.define_helper(:instance, :park) {}
- assert_equal true, @object.send(:park)
- end
-
- def test_should_warn_if_defined_in_superclass
- require 'stringio'
- @original_stderr, $stderr = $stderr, StringIO.new
-
- superclass = Class.new do
- def park
- end
- end
- klass = Class.new(superclass)
- machine = StateMachine::Machine.new(klass)
-
- machine.define_helper(:instance, :park) {}
- assert_equal "Instance method \"park\" is already defined in #{superclass.to_s}, use generic helper instead or set StateMachine::Machine.ignore_method_conflicts = true.\n", $stderr.string
- ensure
- $stderr = @original_stderr
- end
-
- def test_should_warn_if_defined_in_multiple_superclasses
- require 'stringio'
- @original_stderr, $stderr = $stderr, StringIO.new
-
- superclass1 = Class.new do
- def park
- end
- end
- superclass2 = Class.new(superclass1) do
- def park
- end
- end
- klass = Class.new(superclass2)
- machine = StateMachine::Machine.new(klass)
-
- machine.define_helper(:instance, :park) {}
- assert_equal "Instance method \"park\" is already defined in #{superclass1.to_s}, use generic helper instead or set StateMachine::Machine.ignore_method_conflicts = true.\n", $stderr.string
- ensure
- $stderr = @original_stderr
- end
-
- def test_should_warn_if_defined_in_module_prior_to_helper_module
- require 'stringio'
- @original_stderr, $stderr = $stderr, StringIO.new
-
- mod = Module.new do
- def park
- end
- end
- klass = Class.new do
- include mod
- end
- machine = StateMachine::Machine.new(klass)
-
- machine.define_helper(:instance, :park) {}
- assert_equal "Instance method \"park\" is already defined in #{mod.to_s}, use generic helper instead or set StateMachine::Machine.ignore_method_conflicts = true.\n", $stderr.string
- ensure
- $stderr = @original_stderr
- end
-
- def test_should_not_warn_if_defined_in_module_after_helper_module
- require 'stringio'
- @original_stderr, $stderr = $stderr, StringIO.new
-
- klass = Class.new
- machine = StateMachine::Machine.new(klass)
-
- mod = Module.new do
- def park
- end
- end
- klass.class_eval do
- include mod
- end
-
- machine.define_helper(:instance, :park) {}
- assert_equal '', $stderr.string
- ensure
- $stderr = @original_stderr
- end
-
- def test_should_define_if_ignoring_method_conflicts_and_defined_in_superclass
- require 'stringio'
- @original_stderr, $stderr = $stderr, StringIO.new
- StateMachine::Machine.ignore_method_conflicts = true
-
- superclass = Class.new do
- def park
- end
- end
- klass = Class.new(superclass)
- machine = StateMachine::Machine.new(klass)
-
- machine.define_helper(:instance, :park) {true}
- assert_equal '', $stderr.string
- assert_equal true, klass.new.park
- ensure
- StateMachine::Machine.ignore_method_conflicts = false
- $stderr = @original_stderr
- end
-
- def test_should_define_nonexistent_methods
- @machine.define_helper(:instance, :park) {false}
- assert_equal false, @object.park
- end
-
- def test_should_warn_if_defined_multiple_times
- require 'stringio'
- @original_stderr, $stderr = $stderr, StringIO.new
-
- @machine.define_helper(:instance, :park) {}
- @machine.define_helper(:instance, :park) {}
-
- assert_equal "Instance method \"park\" is already defined in #{@klass} :state instance helpers, use generic helper instead or set StateMachine::Machine.ignore_method_conflicts = true.\n", $stderr.string
- ensure
- $stderr = @original_stderr
- end
-
- def test_should_pass_context_as_arguments
- helper_args = nil
- @machine.define_helper(:instance, :park) {|*args| helper_args = args}
- @object.park
- assert_equal 2, helper_args.length
- assert_equal [@machine, @object], helper_args
- end
-
- def test_should_pass_method_arguments_through
- helper_args = nil
- @machine.define_helper(:instance, :park) {|*args| helper_args = args}
- @object.park(1, 2, 3)
- assert_equal 5, helper_args.length
- assert_equal [@machine, @object, 1, 2, 3], helper_args
- end
-
- def test_should_allow_string_evaluation
- @machine.define_helper :instance, <<-end_eval, __FILE__, __LINE__ + 1
- def park
- false
- end
- end_eval
- assert_equal false, @object.park
- end
- end
- class MachineWithClassHelpersTest < Test::Unit::TestCase
- def setup
- @klass = Class.new
- @machine = StateMachine::Machine.new(@klass)
- end
-
- def test_should_not_redefine_existing_public_methods
- class << @klass
- def states
- []
- end
- end
-
- @machine.define_helper(:class, :states) {}
- assert_equal [], @klass.states
- end
-
- def test_should_not_redefine_existing_protected_methods
- class << @klass
- protected
- def states
- []
- end
- end
-
- @machine.define_helper(:class, :states) {}
- assert_equal [], @klass.send(:states)
- end
-
- def test_should_not_redefine_existing_private_methods
- class << @klass
- private
- def states
- []
- end
- end
-
- @machine.define_helper(:class, :states) {}
- assert_equal [], @klass.send(:states)
- end
-
- def test_should_warn_if_defined_in_superclass
- require 'stringio'
- @original_stderr, $stderr = $stderr, StringIO.new
-
- superclass = Class.new do
- def self.park
- end
- end
- klass = Class.new(superclass)
- machine = StateMachine::Machine.new(klass)
-
- machine.define_helper(:class, :park) {}
- assert_equal "Class method \"park\" is already defined in #{superclass.to_s}, use generic helper instead or set StateMachine::Machine.ignore_method_conflicts = true.\n", $stderr.string
- ensure
- $stderr = @original_stderr
- end
-
- def test_should_warn_if_defined_in_multiple_superclasses
- require 'stringio'
- @original_stderr, $stderr = $stderr, StringIO.new
-
- superclass1 = Class.new do
- def self.park
- end
- end
- superclass2 = Class.new(superclass1) do
- def self.park
- end
- end
- klass = Class.new(superclass2)
- machine = StateMachine::Machine.new(klass)
-
- machine.define_helper(:class, :park) {}
- assert_equal "Class method \"park\" is already defined in #{superclass1.to_s}, use generic helper instead or set StateMachine::Machine.ignore_method_conflicts = true.\n", $stderr.string
- ensure
- $stderr = @original_stderr
- end
-
- def test_should_warn_if_defined_in_module_prior_to_helper_module
- require 'stringio'
- @original_stderr, $stderr = $stderr, StringIO.new
-
- mod = Module.new do
- def park
- end
- end
- klass = Class.new do
- extend mod
- end
- machine = StateMachine::Machine.new(klass)
-
- machine.define_helper(:class, :park) {}
- assert_equal "Class method \"park\" is already defined in #{mod.to_s}, use generic helper instead or set StateMachine::Machine.ignore_method_conflicts = true.\n", $stderr.string
- ensure
- $stderr = @original_stderr
- end
-
- def test_should_not_warn_if_defined_in_module_after_helper_module
- require 'stringio'
- @original_stderr, $stderr = $stderr, StringIO.new
-
- klass = Class.new
- machine = StateMachine::Machine.new(klass)
-
- mod = Module.new do
- def park
- end
- end
- klass.class_eval do
- extend mod
- end
-
- machine.define_helper(:class, :park) {}
- assert_equal '', $stderr.string
- ensure
- $stderr = @original_stderr
- end
-
- def test_should_define_if_ignoring_method_conflicts_and_defined_in_superclass
- require 'stringio'
- @original_stderr, $stderr = $stderr, StringIO.new
- StateMachine::Machine.ignore_method_conflicts = true
-
- superclass = Class.new do
- def self.park
- end
- end
- klass = Class.new(superclass)
- machine = StateMachine::Machine.new(klass)
-
- machine.define_helper(:class, :park) {true}
- assert_equal '', $stderr.string
- assert_equal true, klass.park
- ensure
- StateMachine::Machine.ignore_method_conflicts = false
- $stderr = @original_stderr
- end
-
- def test_should_define_nonexistent_methods
- @machine.define_helper(:class, :states) {[]}
- assert_equal [], @klass.states
- end
-
- def test_should_warn_if_defined_multiple_times
- require 'stringio'
- @original_stderr, $stderr = $stderr, StringIO.new
-
- @machine.define_helper(:class, :states) {}
- @machine.define_helper(:class, :states) {}
-
- assert_equal "Class method \"states\" is already defined in #{@klass} :state class helpers, use generic helper instead or set StateMachine::Machine.ignore_method_conflicts = true.\n", $stderr.string
- ensure
- $stderr = @original_stderr
- end
-
- def test_should_pass_context_as_arguments
- helper_args = nil
- @machine.define_helper(:class, :states) {|*args| helper_args = args}
- @klass.states
- assert_equal 2, helper_args.length
- assert_equal [@machine, @klass], helper_args
- end
-
- def test_should_pass_method_arguments_through
- helper_args = nil
- @machine.define_helper(:class, :states) {|*args| helper_args = args}
- @klass.states(1, 2, 3)
- assert_equal 5, helper_args.length
- assert_equal [@machine, @klass, 1, 2, 3], helper_args
- end
-
- def test_should_allow_string_evaluation
- @machine.define_helper :class, <<-end_eval, __FILE__, __LINE__ + 1
- def states
- []
- end
- end_eval
- assert_equal [], @klass.states
- end
- end
- class MachineWithConflictingHelpersBeforeDefinitionTest < Test::Unit::TestCase
- def setup
- require 'stringio'
- @original_stderr, $stderr = $stderr, StringIO.new
-
- @superclass = Class.new do
- def self.with_state
- :with_state
- end
-
- def self.with_states
- :with_states
- end
-
- def self.without_state
- :without_state
- end
-
- def self.without_states
- :without_states
- end
-
- def self.human_state_name
- :human_state_name
- end
-
- def self.human_state_event_name
- :human_state_event_name
- end
-
- attr_accessor :status
-
- def state
- 'parked'
- end
-
- def state=(value)
- self.status = value
- end
-
- def state?
- true
- end
-
- def state_name
- :parked
- end
-
- def human_state_name
- 'parked'
- end
-
- def state_events
- [:ignite]
- end
-
- def state_transitions
- [{:parked => :idling}]
- end
-
- def state_paths
- [[{:parked => :idling}]]
- end
-
- def fire_state_event
- true
- end
- end
- @klass = Class.new(@superclass)
-
- StateMachine::Integrations.const_set('Custom', Module.new do
- include StateMachine::Integrations::Base
-
- def create_with_scope(name)
- lambda {|klass, values| []}
- end
-
- def create_without_scope(name)
- lambda {|klass, values| []}
- end
- end)
-
- @machine = StateMachine::Machine.new(@klass, :integration => :custom)
- @machine.state :parked, :idling
- @machine.event :ignite
- @object = @klass.new
- end
-
- def test_should_not_redefine_singular_with_scope
- assert_equal :with_state, @klass.with_state
- end
-
- def test_should_not_redefine_plural_with_scope
- assert_equal :with_states, @klass.with_states
- end
-
- def test_should_not_redefine_singular_without_scope
- assert_equal :without_state, @klass.without_state
- end
-
- def test_should_not_redefine_plural_without_scope
- assert_equal :without_states, @klass.without_states
- end
-
- def test_should_not_redefine_human_attribute_name_reader
- assert_equal :human_state_name, @klass.human_state_name
- end
-
- def test_should_not_redefine_human_event_name_reader
- assert_equal :human_state_event_name, @klass.human_state_event_name
- end
-
- def test_should_not_redefine_attribute_writer
- assert_equal 'parked', @object.state
- end
-
- def test_should_not_redefine_attribute_writer
- @object.state = 'parked'
- assert_equal 'parked', @object.status
- end
-
- def test_should_not_define_attribute_predicate
- assert @object.state?
- end
-
- def test_should_not_redefine_attribute_name_reader
- assert_equal :parked, @object.state_name
- end
-
- def test_should_not_redefine_attribute_human_name_reader
- assert_equal 'parked', @object.human_state_name
- end
-
- def test_should_not_redefine_attribute_events_reader
- assert_equal [:ignite], @object.state_events
- end
-
- def test_should_not_redefine_attribute_transitions_reader
- assert_equal [{:parked => :idling}], @object.state_transitions
- end
-
- def test_should_not_redefine_attribute_paths_reader
- assert_equal [[{:parked => :idling}]], @object.state_paths
- end
-
- def test_should_not_redefine_event_runner
- assert_equal true, @object.fire_state_event
- end
-
- def test_should_output_warning
- expected = [
- 'Instance method "state_events"',
- 'Instance method "state_transitions"',
- 'Instance method "fire_state_event"',
- 'Instance method "state_paths"',
- 'Class method "human_state_name"',
- 'Class method "human_state_event_name"',
- 'Instance method "state_name"',
- 'Instance method "human_state_name"',
- 'Class method "with_state"',
- 'Class method "without_state"',
- 'Class method "with_states"',
- 'Class method "without_states"'
- ].map {|method| "#{method} is already defined in #{@superclass.to_s}, use generic helper instead or set StateMachine::Machine.ignore_method_conflicts = true.\n"}.join
-
- assert_equal expected, $stderr.string
- end
-
- def teardown
- $stderr = @original_stderr
- StateMachine::Integrations.send(:remove_const, 'Custom')
- end
- end
- class MachineWithConflictingHelpersAfterDefinitionTest < Test::Unit::TestCase
- def setup
- require 'stringio'
- @original_stderr, $stderr = $stderr, StringIO.new
-
- @klass = Class.new do
- def self.with_state
- :with_state
- end
-
- def self.with_states
- :with_states
- end
-
- def self.without_state
- :without_state
- end
-
- def self.without_states
- :without_states
- end
-
- def self.human_state_name
- :human_state_name
- end
-
- def self.human_state_event_name
- :human_state_event_name
- end
-
- attr_accessor :status
-
- def state
- 'parked'
- end
-
- def state=(value)
- self.status = value
- end
-
- def state?
- true
- end
-
- def state_name
- :parked
- end
-
- def human_state_name
- 'parked'
- end
-
- def state_events
- [:ignite]
- end
-
- def state_transitions
- [{:parked => :idling}]
- end
-
- def state_paths
- [[{:parked => :idling}]]
- end
-
- def fire_state_event
- true
- end
- end
-
- StateMachine::Integrations.const_set('Custom', Module.new do
- include StateMachine::Integrations::Base
-
- def create_with_scope(name)
- lambda {|klass, values| []}
- end
-
- def create_without_scope(name)
- lambda {|klass, values| []}
- end
- end)
-
- @machine = StateMachine::Machine.new(@klass, :integration => :custom)
- @machine.state :parked, :idling
- @machine.event :ignite
- @object = @klass.new
- end
-
- def test_should_not_redefine_singular_with_scope
- assert_equal :with_state, @klass.with_state
- end
-
- def test_should_not_redefine_plural_with_scope
- assert_equal :with_states, @klass.with_states
- end
-
- def test_should_not_redefine_singular_without_scope
- assert_equal :without_state, @klass.without_state
- end
-
- def test_should_not_redefine_plural_without_scope
- assert_equal :without_states, @klass.without_states
- end
-
- def test_should_not_redefine_human_attribute_name_reader
- assert_equal :human_state_name, @klass.human_state_name
- end
-
- def test_should_not_redefine_human_event_name_reader
- assert_equal :human_state_event_name, @klass.human_state_event_name
- end
-
- def test_should_not_redefine_attribute_writer
- assert_equal 'parked', @object.state
- end
-
- def test_should_not_redefine_attribute_writer
- @object.state = 'parked'
- assert_equal 'parked', @object.status
- end
-
- def test_should_not_define_attribute_predicate
- assert @object.state?
- end
-
- def test_should_not_redefine_attribute_name_reader
- assert_equal :parked, @object.state_name
- end
-
- def test_should_not_redefine_attribute_human_name_reader
- assert_equal 'parked', @object.human_state_name
- end
-
- def test_should_not_redefine_attribute_events_reader
- assert_equal [:ignite], @object.state_events
- end
-
- def test_should_not_redefine_attribute_transitions_reader
- assert_equal [{:parked => :idling}], @object.state_transitions
- end
-
- def test_should_not_redefine_attribute_paths_reader
- assert_equal [[{:parked => :idling}]], @object.state_paths
- end
-
- def test_should_not_redefine_event_runner
- assert_equal true, @object.fire_state_event
- end
-
- def test_should_allow_super_chaining
- @klass.class_eval do
- def self.with_state(*states)
- super
- end
-
- def self.with_states(*states)
- super
- end
-
- def self.without_state(*states)
- super
- end
-
- def self.without_states(*states)
- super
- end
-
- def self.human_state_name(state)
- super
- end
-
- def self.human_state_event_name(event)
- super
- end
-
- attr_accessor :status
-
- def state
- super
- end
-
- def state=(value)
- super
- end
-
- def state?(state)
- super
- end
-
- def state_name
- super
- end
-
- def human_state_name
- super
- end
-
- def state_events
- super
- end
-
- def state_transitions
- super
- end
-
- def state_paths
- super
- end
-
- def fire_state_event(event)
- super
- end
- end
-
- assert_equal [], @klass.with_state
- assert_equal [], @klass.with_states
- assert_equal [], @klass.without_state
- assert_equal [], @klas…
Large files files are truncated, but you can click here to view the full file