/test/unit/integrations/mongoid_test.rb
Ruby | 2309 lines | 1813 code | 488 blank | 8 comment | 21 complexity | bee31ce6161738201ee4966e87460580 MD5 | raw file
Large files files are truncated, but you can click here to view the full file
- require File.expand_path(File.dirname(__FILE__) + '/../../test_helper')
- require 'mongoid'
- require 'mongoid/version'
- # Establish database connection
- Mongoid.configure do |config|
- if Mongoid::VERSION =~ /^2\./
- connection = Mongo::Connection.new('127.0.0.1', 27017, :slave_ok => true, :logger => Logger.new("#{File.dirname(__FILE__)}/../../mongoid.log"))
- config.master = connection.db('test')
- else
- Mongoid.logger = Moped.logger = Logger.new("#{File.dirname(__FILE__)}/../../mongoid.log")
- config.connect_to('test')
- end
- end
- module MongoidTest
- class BaseTestCase < Test::Unit::TestCase
- def default_test
- end
-
- def teardown
- if @table_names
- db = Mongoid::VERSION =~ /^2\./ ? Mongoid.master : Mongoid::Sessions.default
- db.collections.each {|c| c.drop if @table_names.include?(c.name)}
- end
- end
-
- protected
- # Creates a new Mongoid model (and the associated table)
- def new_model(name = :foo, &block)
- table_name = "#{name}_#{rand(1000000)}"
- @table_names ||= []
- @table_names << table_name
-
- model = Class.new do
- (class << self; self; end).class_eval do
- define_method(:name) { "MongoidTest::#{name.to_s.capitalize}" }
- define_method(:to_s) { self.name }
- end
- end
-
- model.class_eval do
- include Mongoid::Document
- if Mongoid::VERSION =~ /^2\./
- self.collection_name = table_name
- else
- self.default_collection_name = table_name
- end
-
- field :state, :type => String
- end
- model.class_eval(&block) if block_given?
- model
- end
-
- # Creates a new Mongoid observer
- def new_observer(model, &block)
- observer = Class.new(Mongoid::Observer) do
- attr_accessor :notifications
-
- def initialize
- super
- @notifications = []
- end
- end
-
- (class << observer; self; end).class_eval do
- define_method(:name) do
- "#{model.name}Observer"
- end
- end
-
- observer.observe(model)
- observer.class_eval(&block) if block_given?
- observer
- end
- end
-
- class IntegrationTest < BaseTestCase
- def test_should_have_an_integration_name
- assert_equal :mongoid, StateMachine::Integrations::Mongoid.integration_name
- end
-
- def test_should_be_available
- assert StateMachine::Integrations::Mongoid.available?
- end
-
- def test_should_match_if_class_includes_mongoid
- assert StateMachine::Integrations::Mongoid.matches?(new_model)
- end
-
- def test_should_not_match_if_class_does_not_include_mongoid
- assert !StateMachine::Integrations::Mongoid.matches?(Class.new)
- end
-
- def test_should_have_defaults
- assert_equal({:action => :save}, StateMachine::Integrations::Mongoid.defaults)
- end
-
- def test_should_have_a_locale_path
- assert_not_nil StateMachine::Integrations::Mongoid.locale_path
- end
- end
-
- class MachineWithoutFieldTest < BaseTestCase
- def setup
- @model = new_model
- StateMachine::Machine.new(@model, :status)
- end
-
- def test_should_define_field_with_string_type
- field = @model.fields['status']
- assert_not_nil field
- assert_equal String, field.type
- end
- end
-
- class MachineWithFieldTest < BaseTestCase
- def setup
- @model = new_model do
- field :status, :type => Integer
- end
- StateMachine::Machine.new(@model, :status)
- end
-
- def test_should_not_redefine_field
- field = @model.fields['status']
- assert_not_nil field
- assert_equal Integer, field.type
- end
- end
-
- class MachineByDefaultTest < BaseTestCase
- def setup
- @model = new_model
- @machine = StateMachine::Machine.new(@model)
- end
-
- def test_should_use_save_as_action
- assert_equal :save, @machine.action
- end
-
- def test_should_create_notifier_before_callback
- assert_equal 1, @machine.callbacks[:before].size
- end
-
- def test_should_create_notifier_after_callback
- assert_equal 1, @machine.callbacks[:after].size
- end
- end
-
- class MachineWithStatesTest < BaseTestCase
- def setup
- @model = new_model
- @machine = StateMachine::Machine.new(@model)
- @machine.state :first_gear
- end
-
- def test_should_humanize_name
- assert_equal 'first gear', @machine.state(:first_gear).human_name
- end
- end
-
- class MachineWithStaticInitialStateTest < BaseTestCase
- def setup
- @model = new_model(:vehicle) do
- attr_accessor :value
- end
- @machine = StateMachine::Machine.new(@model, :initial => :parked)
- end
-
- def test_should_set_initial_state_on_created_object
- record = @model.new
- assert_equal 'parked', record.state
- end
-
- def test_should_set_initial_state_with_nil_attributes
- record = @model.new(nil)
- assert_equal 'parked', record.state
- end
-
- def test_should_still_set_attributes
- record = @model.new(:value => 1)
- assert_equal 1, record.value
- end
-
- def test_should_still_allow_initialize_blocks
- block_args = nil
- record = @model.new do |*args|
- block_args = args
- end
-
- assert_equal [record], block_args
- end
-
- def test_should_set_attributes_prior_to_initialize_block
- state = nil
- @model.new do |record|
- state = record.state
- end
-
- assert_equal 'parked', state
- end
-
- def test_should_set_attributes_prior_to_after_initialize_hook
- state = nil
- @model.after_initialize do |record|
- state = record.state
- end
- @model.new
- assert_equal 'parked', state
- end
-
- def test_should_persist_initial_state
- record = @model.new
- record.save
- record.reload
- assert_equal 'parked', record.state
- end
-
- def test_should_persist_initial_state_on_dup
- record = @model.create.dup
- record.save
- record.reload
- assert_equal 'parked', record.state
- end
-
- def test_should_set_initial_state_before_setting_attributes
- @model.class_eval do
- attr_accessor :state_during_setter
-
- remove_method :value=
- define_method(:value=) do |value|
- self.state_during_setter = state
- end
- end
-
- record = @model.new(:value => 1)
- assert_equal 'parked', record.state_during_setter
- end
-
- def test_should_not_set_initial_state_after_already_initialized
- record = @model.new(:value => 1)
- assert_equal 'parked', record.state
-
- record.state = 'idling'
- record.attributes = {}
- assert_equal 'idling', record.state
- end
-
- def test_should_use_stored_values_when_loading_from_database
- @machine.state :idling
-
- record = @model.find(@model.create(:state => 'idling').id)
- assert_equal 'idling', record.state
- end
-
- def test_should_use_stored_values_when_loading_from_database_with_nil_state
- @machine.state nil
-
- record = @model.find(@model.create(:state => nil).id)
- assert_nil record.state
- end
-
- if Mongoid::VERSION >= '2.1.0'
- def test_should_use_stored_values_when_loading_for_many_association
- @machine.state :idling
-
- @model.belongs_to :owner, :class_name => 'MongoidTest::Owner'
- MongoidTest.const_set('Vehicle', @model)
-
- owner_model = new_model(:owner) do
- has_many :vehicles, :class_name => 'MongoidTest::Vehicle'
- end
- MongoidTest.const_set('Owner', owner_model)
-
- owner = owner_model.create
- record = @model.create(:state => 'idling', :owner_id => owner.id)
- assert_equal 'idling', owner.vehicles[0].state
- end
-
- def test_should_use_stored_values_when_loading_for_one_association
- @machine.state :idling
-
- @model.belongs_to :owner, :class_name => 'MongoidTest::Owner'
- MongoidTest.const_set('Vehicle', @model)
-
- owner_model = new_model(:owner) do
- has_one :vehicle, :class_name => 'MongoidTest::Vehicle'
- end
- MongoidTest.const_set('Owner', owner_model)
-
- owner = owner_model.create
- record = @model.create(:state => 'idling', :owner_id => owner.id)
- owner.reload
- assert_equal 'idling', owner.vehicle.state
- end
-
- def test_should_use_stored_values_when_loading_for_belongs_to_association
- @machine.state :idling
-
- MongoidTest.const_set('Vehicle', @model)
-
- driver_model = new_model(:driver) do
- belongs_to :vehicle, :class_name => 'MongoidTest::Vehicle'
- end
- MongoidTest.const_set('Driver', driver_model)
-
- record = @model.create(:state => 'idling')
- driver = driver_model.create(:vehicle_id => record.id)
- assert_equal 'idling', driver.vehicle.state
- end
- end
-
- def teardown
- MongoidTest.class_eval do
- remove_const('Vehicle') if defined?(MongoidTest::Vehicle)
- remove_const('Owner') if defined?(MongoidTest::Owner)
- remove_const('Driver') if defined?(MongoidTest::Driver)
- end
- super
- end
- end
-
- class MachineWithDynamicInitialStateTest < BaseTestCase
- def setup
- @model = new_model do
- attr_accessor :value
- end
- @machine = StateMachine::Machine.new(@model, :initial => lambda {|object| :parked})
- @machine.state :parked
- end
-
- def test_should_set_initial_state_on_created_object
- record = @model.new
- assert_equal 'parked', record.state
- end
-
- def test_should_still_set_attributes
- record = @model.new(:value => 1)
- assert_equal 1, record.value
- end
-
- def test_should_still_allow_initialize_blocks
- block_args = nil
- record = @model.new do |*args|
- block_args = args
- end
-
- assert_equal [record], block_args
- end
-
- def test_should_set_attributes_prior_to_initialize_block
- state = nil
- @model.new do |record|
- state = record.state
- end
-
- assert_equal 'parked', state
- end
-
- def test_should_set_attributes_prior_to_after_initialize_hook
- state = nil
- @model.after_initialize do |record|
- state = record.state
- end
- @model.new
- assert_equal 'parked', state
- end
-
- def test_should_set_initial_state_after_setting_attributes
- @model.class_eval do
- attr_accessor :state_during_setter
-
- remove_method :value=
- define_method(:value=) do |value|
- self.state_during_setter = state || 'nil'
- end
- end
-
- record = @model.new(:value => 1)
- assert_equal 'nil', record.state_during_setter
- end
-
- def test_should_not_set_initial_state_after_already_initialized
- record = @model.new(:value => 1)
- assert_equal 'parked', record.state
-
- record.state = 'idling'
- record.attributes = {}
- assert_equal 'idling', record.state
- end
-
- def test_should_persist_initial_state
- record = @model.new
- record.save
- record.reload
- assert_equal 'parked', record.state
- end
-
- def test_should_persist_initial_state_on_dup
- record = @model.create.dup
- record.save
- record.reload
- assert_equal 'parked', record.state
- end
-
- def test_should_use_stored_values_when_loading_from_database
- @machine.state :idling
-
- record = @model.find(@model.create(:state => 'idling').id)
- assert_equal 'idling', record.state
- end
-
- def test_should_use_stored_values_when_loading_from_database_with_nil_state
- @machine.state nil
-
- record = @model.find(@model.create(:state => nil).id)
- assert_nil record.state
- end
- end
-
- class MachineWithEventsTest < BaseTestCase
- def setup
- @model = new_model
- @machine = StateMachine::Machine.new(@model)
- @machine.event :shift_up
- end
-
- def test_should_humanize_name
- assert_equal 'shift up', @machine.event(:shift_up).human_name
- end
- end
-
- class MachineWithDifferentSameDefaultTest < BaseTestCase
- def setup
- @original_stderr, $stderr = $stderr, StringIO.new
-
- @model = new_model do
- field :status, :type => String, :default => 'parked'
- end
- @machine = StateMachine::Machine.new(@model, :status, :initial => :parked)
- @record = @model.new
- end
-
- def test_should_use_machine_default
- assert_equal 'parked', @record.status
- end
-
- def test_should_not_generate_a_warning
- assert_no_match(/have defined a different default/, $stderr.string)
- end
-
- def teardown
- $stderr = @original_stderr
- super
- end
- end
-
- class MachineWithDifferentColumnDefaultTest < BaseTestCase
- def setup
- @original_stderr, $stderr = $stderr, StringIO.new
-
- @model = new_model do
- field :status, :type => String, :default => 'idling'
- end
- @machine = StateMachine::Machine.new(@model, :status, :initial => :parked)
- @record = @model.new
- end
-
- def test_should_use_machine_default
- assert_equal 'parked', @record.status
- end
-
- def test_should_generate_a_warning
- assert_match(/Both MongoidTest::Foo and its :status machine have defined a different default for "status". Use only one or the other for defining defaults to avoid unexpected behaviors\./, $stderr.string)
- end
-
- def teardown
- $stderr = @original_stderr
- super
- end
- end
-
- class MachineWithDifferentIntegerColumnDefaultTest < BaseTestCase
- def setup
- @original_stderr, $stderr = $stderr, StringIO.new
-
- @model = new_model do
- field :status, :type => Integer, :default => 0
- end
- @machine = StateMachine::Machine.new(@model, :status, :initial => :parked)
- @machine.state :parked, :value => 1
- @record = @model.new
- end
-
- def test_should_use_machine_default
- assert_equal 1, @record.status
- end
-
- def test_should_generate_a_warning
- assert_match(/Both MongoidTest::Foo and its :status machine have defined a different default for "status". Use only one or the other for defining defaults to avoid unexpected behaviors\./, $stderr.string)
- end
-
- def teardown
- $stderr = @original_stderr
- super
- end
- end
-
- class MachineWithConflictingPredicateTest < BaseTestCase
- def setup
- @model = new_model do
- def state?(*args)
- true
- end
- end
-
- @machine = StateMachine::Machine.new(@model)
- @record = @model.new
- end
-
- def test_should_not_define_attribute_predicate
- assert @record.state?
- end
- end
-
- class MachineWithConflictingStateNameTest < BaseTestCase
- def setup
- require 'stringio'
- @original_stderr, $stderr = $stderr, StringIO.new
-
- @model = new_model
- end
-
- def test_should_output_warning_with_same_machine_name
- @machine = StateMachine::Machine.new(@model)
- @machine.state :state
-
- assert_match(/^Instance method "state\?" is already defined in .*, use generic helper instead.*\n$/, $stderr.string)
- end
-
- def test_should_output_warning_with_same_machine_attribute
- @machine = StateMachine::Machine.new(@model, :public_state, :attribute => :state)
- @machine.state :state
-
- assert_match(/^Instance method "state\?" is already defined in .*, use generic helper instead.*\n$/, $stderr.string)
- end
-
- def teardown
- $stderr = @original_stderr
- super
- end
- end
-
- class MachineWithColumnStateAttributeTest < BaseTestCase
- def setup
- @model = new_model
- @machine = StateMachine::Machine.new(@model, :initial => :parked)
- @machine.other_states(:idling)
-
- @record = @model.new
- end
-
- def test_should_not_override_the_column_reader
- @record[:state] = 'parked'
- assert_equal 'parked', @record.state
- end
-
- def test_should_not_override_the_column_writer
- @record.state = 'parked'
- assert_equal 'parked', @record[:state]
- end
-
- def test_should_have_an_attribute_predicate
- assert @record.respond_to?(:state?)
- end
-
- def test_should_test_for_existence_on_predicate_without_parameters
- assert @record.state?
-
- @record.state = nil
- assert !@record.state?
- end
-
- def test_should_return_false_for_predicate_if_does_not_match_current_value
- assert !@record.state?(:idling)
- end
-
- def test_should_return_true_for_predicate_if_matches_current_value
- assert @record.state?(:parked)
- end
-
- def test_should_raise_exception_for_predicate_if_invalid_state_specified
- assert_raise(IndexError) { @record.state?(:invalid) }
- end
- end
-
- class MachineWithNonColumnStateAttributeUndefinedTest < BaseTestCase
- def setup
- @model = new_model do
- def initialize
- # Skip attribute initialization
- @initialized_state_machines = true
- super
- end
- end
-
- @machine = StateMachine::Machine.new(@model, :status, :initial => :parked)
- @machine.other_states(:idling)
- @record = @model.new
- end
-
- def test_should_define_a_new_key_for_the_attribute
- assert_not_nil @model.fields['status']
- end
-
- def test_should_define_a_reader_attribute_for_the_attribute
- assert @record.respond_to?(:status)
- end
-
- def test_should_define_a_writer_attribute_for_the_attribute
- assert @record.respond_to?(:status=)
- end
-
- def test_should_define_an_attribute_predicate
- assert @record.respond_to?(:status?)
- end
- end
-
- class MachineWithNonColumnStateAttributeDefinedTest < BaseTestCase
- def setup
- @model = new_model do
- def status
- self['status']
- end
-
- def status=(value)
- self['status'] = value
- end
- end
-
- @machine = StateMachine::Machine.new(@model, :status, :initial => :parked)
- @machine.other_states(:idling)
- @record = @model.new
- end
-
- def test_should_return_false_for_predicate_if_does_not_match_current_value
- assert !@record.status?(:idling)
- end
-
- def test_should_return_true_for_predicate_if_matches_current_value
- assert @record.status?(:parked)
- end
-
- def test_should_raise_exception_for_predicate_if_invalid_state_specified
- assert_raise(IndexError) { @record.status?(:invalid) }
- end
-
- def test_should_set_initial_state_on_created_object
- assert_equal 'parked', @record.status
- end
- end
-
- class MachineWithAliasedAttributeTest < BaseTestCase
- def setup
- @model = new_model do
- alias_attribute :vehicle_status, :state
- end
-
- @machine = StateMachine::Machine.new(@model, :status, :attribute => :vehicle_status)
- @machine.state :parked
-
- @record = @model.new
- end
-
- def test_should_check_custom_attribute_for_predicate
- @record.vehicle_status = nil
- assert !@record.status?(:parked)
-
- @record.vehicle_status = 'parked'
- assert @record.status?(:parked)
- end
- end
-
- class MachineWithAliasedFieldTest < BaseTestCase
- def setup
- @model = new_model do
- field :status, :as => :vehicle_status
- end
-
- @machine = StateMachine::Machine.new(@model, :vehicle_status)
- @machine.state :parked
-
- @record = @model.new
- end
-
- def test_should_check_custom_attribute_for_predicate
- @record.vehicle_status = nil
- assert !@record.vehicle_status?(:parked)
-
- @record.vehicle_status = 'parked'
- assert @record.vehicle_status?(:parked)
- end
- end
-
- class MachineWithCustomAttributeTest < BaseTestCase
- def setup
- require 'stringio'
- @original_stderr, $stderr = $stderr, StringIO.new
-
- @model = new_model
- @machine = StateMachine::Machine.new(@model, :public_state, :attribute => :state)
- @record = @model.new
- end
-
- def test_should_not_delegate_attribute_predicate_with_different_attribute
- assert_raise(ArgumentError) { @record.public_state? }
- end
-
- def teardown
- $stderr = @original_stderr
- super
- end
- end
-
- class MachineWithInitializedStateTest < BaseTestCase
- def setup
- @model = new_model
- @machine = StateMachine::Machine.new(@model, :initial => :parked)
- @machine.state :idling
- end
-
- def test_should_allow_nil_initial_state_when_static
- @machine.state nil
-
- record = @model.new(:state => nil)
- assert_nil record.state
- end
-
- def test_should_allow_nil_initial_state_when_dynamic
- @machine.state nil
-
- @machine.initial_state = lambda {:parked}
- record = @model.new(:state => nil)
- assert_nil record.state
- end
-
- def test_should_allow_different_initial_state_when_static
- record = @model.new(:state => 'idling')
- assert_equal 'idling', record.state
- end
-
- def test_should_allow_different_initial_state_when_dynamic
- @machine.initial_state = lambda {:parked}
- record = silence_warnings { @model.new(:state => 'idling') }
- assert_equal 'idling', record.state
- end
-
- def test_should_use_default_state_if_protected
- Mongoid.logger = nil
- @model.class_eval do
- attr_protected :state
- end
-
- record = @model.new(:state => 'idling')
- assert_equal 'parked', record.state
- end
- end
-
- class MachineMultipleTest < BaseTestCase
- def setup
- @model = new_model do
- field :status, :type => String
- end
- @state_machine = StateMachine::Machine.new(@model, :initial => :parked)
- @status_machine = StateMachine::Machine.new(@model, :status, :initial => :idling)
- end
-
- def test_should_should_initialize_each_state
- record = @model.new
- assert_equal 'parked', record.state
- assert_equal 'idling', record.status
- end
- end
-
- class MachineWithLoopbackTest < BaseTestCase
- def setup
- @model = new_model do
- field :updated_at, :type => Time
-
- before_update do |record|
- record.updated_at = Time.now
- end
- end
-
- @machine = StateMachine::Machine.new(@model, :initial => :parked)
- @machine.event :park
-
- @record = @model.create(:updated_at => Time.now - 1)
- @transition = StateMachine::Transition.new(@record, @machine, :park, :parked, :parked)
-
- @timestamp = @record.updated_at
- @transition.perform
- end
-
- def test_should_update_record
- assert_not_equal @timestamp, @record.updated_at
- end
- end
-
- class MachineWithDirtyAttributesTest < BaseTestCase
- def setup
- @model = new_model
- @machine = StateMachine::Machine.new(@model, :initial => :parked)
- @machine.event :ignite
- @machine.state :idling
-
- @record = @model.create
-
- @transition = StateMachine::Transition.new(@record, @machine, :ignite, :parked, :idling)
- @transition.perform(false)
- end
-
- def test_should_include_state_in_changed_attributes
- assert_equal %w(state), @record.changed
- end
-
- def test_should_track_attribute_change
- assert_equal %w(parked idling), @record.changes['state']
- end
-
- def test_should_not_reset_changes_on_multiple_transitions
- transition = StateMachine::Transition.new(@record, @machine, :ignite, :idling, :idling)
- transition.perform(false)
-
- assert_equal %w(parked idling), @record.changes['state']
- end
-
- def test_should_not_have_changes_when_loaded_from_database
- record = @model.find(@record.id)
- assert !record.changed?
- end
- end
-
- class MachineWithDirtyAttributesDuringLoopbackTest < BaseTestCase
- def setup
- @model = new_model
- @machine = StateMachine::Machine.new(@model, :initial => :parked)
- @machine.event :park
-
- @record = @model.create
-
- @transition = StateMachine::Transition.new(@record, @machine, :park, :parked, :parked)
- @transition.perform(false)
- end
-
- def test_should_not_include_state_in_changed_attributes
- assert_equal [], @record.changed
- end
-
- def test_should_not_track_attribute_changes
- assert_equal nil, @record.send(:attribute_change, 'state')
- end
- end
-
- class MachineWithDirtyAttributesAndCustomAttributeTest < BaseTestCase
- def setup
- @model = new_model do
- field :status, :type => String
- end
- @machine = StateMachine::Machine.new(@model, :status, :initial => :parked)
- @machine.event :ignite
- @machine.state :idling
-
- @record = @model.create
-
- @transition = StateMachine::Transition.new(@record, @machine, :ignite, :parked, :idling)
- @transition.perform(false)
- end
-
- def test_should_include_state_in_changed_attributes
- assert_equal %w(status), @record.changed
- end
-
- def test_should_track_attribute_change
- assert_equal %w(parked idling), @record.changes['status']
- end
-
- def test_should_not_reset_changes_on_multiple_transitions
- transition = StateMachine::Transition.new(@record, @machine, :ignite, :idling, :idling)
- transition.perform(false)
-
- assert_equal %w(parked idling), @record.changes['status']
- end
- end
-
- class MachineWithDirtyAttributeAndCustomAttributesDuringLoopbackTest < BaseTestCase
- def setup
- @model = new_model do
- field :status, :type => String
- end
- @machine = StateMachine::Machine.new(@model, :status, :initial => :parked)
- @machine.event :park
-
- @record = @model.create
-
- @transition = StateMachine::Transition.new(@record, @machine, :park, :parked, :parked)
- @transition.perform(false)
- end
-
- def test_should_include_state_in_changed_attributes
- assert_equal [], @record.changed
- end
-
- def test_should_track_attribute_changes
- assert_equal nil, @record.send(:attribute_change, 'status')
- end
- end
-
- class MachineWithDirtyAttributeAndStateEventsTest < BaseTestCase
- def setup
- @model = new_model
- @machine = StateMachine::Machine.new(@model, :initial => :parked)
- @machine.event :ignite
-
- @record = @model.create
- @record.state_event = 'ignite'
- end
-
- def test_should_not_include_state_in_changed_attributes
- assert_equal [], @record.changed
- end
-
- def test_should_not_track_attribute_change
- assert_equal nil, @record.send(:attribute_change, 'state')
- end
- end
-
- class MachineWithCallbacksTest < BaseTestCase
- def setup
- @model = new_model
- @machine = StateMachine::Machine.new(@model, :initial => :parked)
- @machine.other_states :idling
- @machine.event :ignite
-
- @record = @model.new(:state => 'parked')
- @transition = StateMachine::Transition.new(@record, @machine, :ignite, :parked, :idling)
- end
-
- def test_should_run_before_callbacks
- called = false
- @machine.before_transition {called = true}
-
- @transition.perform
- assert called
- end
-
- def test_should_pass_record_to_before_callbacks_with_one_argument
- record = nil
- @machine.before_transition {|arg| record = arg}
-
- @transition.perform
- assert_equal @record, record
- end
-
- def test_should_pass_record_and_transition_to_before_callbacks_with_multiple_arguments
- callback_args = nil
- @machine.before_transition {|*args| callback_args = args}
-
- @transition.perform
- assert_equal [@record, @transition], callback_args
- end
-
- def test_should_run_before_callbacks_outside_the_context_of_the_record
- context = nil
- @machine.before_transition {context = self}
-
- @transition.perform
- assert_equal self, context
- end
-
- def test_should_run_after_callbacks
- called = false
- @machine.after_transition {called = true}
-
- @transition.perform
- assert called
- end
-
- def test_should_pass_record_to_after_callbacks_with_one_argument
- record = nil
- @machine.after_transition {|arg| record = arg}
-
- @transition.perform
- assert_equal @record, record
- end
-
- def test_should_pass_record_and_transition_to_after_callbacks_with_multiple_arguments
- callback_args = nil
- @machine.after_transition {|*args| callback_args = args}
-
- @transition.perform
- assert_equal [@record, @transition], callback_args
- end
-
- def test_should_run_after_callbacks_outside_the_context_of_the_record
- context = nil
- @machine.after_transition {context = self}
-
- @transition.perform
- assert_equal self, context
- end
-
- def test_should_run_after_callbacks_if_model_callback_added_prior_to_state_machine_definition
- model = new_model do
- after_save { nil }
- end
- machine = StateMachine::Machine.new(model, :initial => :parked)
- machine.other_states :idling
- machine.event :ignite
- after_called = false
- machine.after_transition {after_called = true}
-
- record = model.new(:state => 'parked')
- transition = StateMachine::Transition.new(record, machine, :ignite, :parked, :idling)
- transition.perform
- assert_equal true, after_called
- end
-
- def test_should_run_around_callbacks
- before_called = false
- after_called = false
- ensure_called = 0
- @machine.around_transition do |block|
- before_called = true
- begin
- block.call
- ensure
- ensure_called += 1
- end
- after_called = true
- end
-
- @transition.perform
- assert before_called
- assert after_called
- assert_equal ensure_called, 1
- end
-
- def test_should_include_transition_states_in_known_states
- @machine.before_transition :to => :first_gear, :do => lambda {}
-
- assert_equal [:parked, :idling, :first_gear], @machine.states.map {|state| state.name}
- end
-
- def test_should_allow_symbolic_callbacks
- callback_args = nil
-
- klass = class << @record; self; end
- klass.send(:define_method, :after_ignite) do |*args|
- callback_args = args
- end
-
- @machine.before_transition(:after_ignite)
-
- @transition.perform
- assert_equal [@transition], callback_args
- end
-
- def test_should_allow_string_callbacks
- class << @record
- attr_reader :callback_result
- end
-
- @machine.before_transition('@callback_result = [1, 2, 3]')
- @transition.perform
-
- assert_equal [1, 2, 3], @record.callback_result
- end
-
- def test_should_run_in_expected_order
- expected = [
- :before_transition, :before_validation, :after_validation,
- :before_save, :before_create, :after_create, :after_save,
- :after_transition
- ]
-
- callbacks = []
- @model.before_validation { callbacks << :before_validation }
- @model.after_validation { callbacks << :after_validation }
- @model.before_save { callbacks << :before_save }
- @model.before_create { callbacks << :before_create }
- @model.after_create { callbacks << :after_create }
- @model.after_save { callbacks << :after_save }
-
- @machine.before_transition { callbacks << :before_transition }
- @machine.after_transition { callbacks << :after_transition }
-
- @transition.perform
-
- assert_equal expected, callbacks
- end
- end
-
- class MachineWithFailedBeforeCallbacksTest < BaseTestCase
- def setup
- @callbacks = []
-
- @model = new_model
- @machine = StateMachine::Machine.new(@model)
- @machine.state :parked, :idling
- @machine.event :ignite
- @machine.before_transition {@callbacks << :before_1; false}
- @machine.before_transition {@callbacks << :before_2}
- @machine.after_transition {@callbacks << :after}
- @machine.around_transition {|block| @callbacks << :around_before; block.call; @callbacks << :around_after}
-
- @record = @model.new(:state => 'parked')
- @transition = StateMachine::Transition.new(@record, @machine, :ignite, :parked, :idling)
- @result = @transition.perform
- end
-
- def test_should_not_be_successful
- assert !@result
- end
-
- def test_should_not_change_current_state
- assert_equal 'parked', @record.state
- end
-
- def test_should_not_run_action
- assert @record.new_record?
- end
-
- def test_should_not_run_further_callbacks
- assert_equal [:before_1], @callbacks
- end
- end
-
- class MachineNestedActionTest < BaseTestCase
- def setup
- @callbacks = []
-
- @model = new_model
- @machine = StateMachine::Machine.new(@model)
- @machine.event :ignite do
- transition :parked => :idling
- end
-
- @record = @model.new(:state => 'parked')
- end
-
- def test_should_allow_transition_prior_to_creation_if_skipping_action
- record = @record
- @model.before_create { record.ignite(false) }
- result = @record.save
-
- assert_equal true, result
- assert_equal "idling", @record.state
- @record.reload
- assert_equal "idling", @record.state
- end
-
- if Mongoid::VERSION !~ /^2\.1\./
- def test_should_allow_transition_after_creation
- record = @record
- @model.after_create { record.ignite }
- result = @record.save
-
- assert_equal true, result
- assert_equal "idling", @record.state
- @record.reload
- assert_equal "idling", @record.state
- end
- end
- end
-
- class MachineWithFailedActionTest < BaseTestCase
- def setup
- @model = new_model do
- validates_numericality_of :state
- end
-
- @machine = StateMachine::Machine.new(@model)
- @machine.state :parked, :idling
- @machine.event :ignite
-
- @callbacks = []
- @machine.before_transition {@callbacks << :before}
- @machine.after_transition {@callbacks << :after}
- @machine.after_failure {@callbacks << :after_failure}
- @machine.around_transition {|block| @callbacks << :around_before; block.call; @callbacks << :around_after}
-
- @record = @model.new(:state => 'parked')
- @transition = StateMachine::Transition.new(@record, @machine, :ignite, :parked, :idling)
- @result = @transition.perform
- end
-
- def test_should_not_be_successful
- assert !@result
- end
-
- def test_should_not_change_current_state
- assert_equal 'parked', @record.state
- end
-
- def test_should_not_save_record
- assert @record.new_record?
- end
-
- def test_should_run_before_callbacks_and_after_callbacks_with_failures
- assert_equal [:before, :around_before, :after_failure], @callbacks
- end
- end
-
- class MachineWithFailedAfterCallbacksTest < BaseTestCase
- def setup
- @callbacks = []
-
- @model = new_model
- @machine = StateMachine::Machine.new(@model)
- @machine.state :parked, :idling
- @machine.event :ignite
- @machine.after_transition {@callbacks << :after_1; false}
- @machine.after_transition {@callbacks << :after_2}
- @machine.around_transition {|block| @callbacks << :around_before; block.call; @callbacks << :around_after}
-
- @record = @model.new(:state => 'parked')
- @transition = StateMachine::Transition.new(@record, @machine, :ignite, :parked, :idling)
- @result = @transition.perform
- end
-
- def test_should_be_successful
- assert @result
- end
-
- def test_should_change_current_state
- assert_equal 'idling', @record.state
- end
-
- def test_should_save_record
- assert !@record.new_record?
- end
-
- def test_should_not_run_further_after_callbacks
- assert_equal [:around_before, :around_after, :after_1], @callbacks
- end
- end
-
- class MachineWithValidationsTest < BaseTestCase
- def setup
- @model = new_model
- @machine = StateMachine::Machine.new(@model)
- @machine.state :parked
-
- @record = @model.new
- end
-
- def test_should_invalidate_using_errors
- I18n.backend = I18n::Backend::Simple.new if Object.const_defined?(:ActiveModel)
- @record.state = 'parked'
-
- @machine.invalidate(@record, :state, :invalid_transition, [[:event, 'park']])
- assert_equal ['State cannot transition via "park"'], @record.errors.full_messages
- end
-
- def test_should_auto_prefix_custom_attributes_on_invalidation
- @machine.invalidate(@record, :event, :invalid)
-
- assert_equal ['State event is invalid'], @record.errors.full_messages
- end
-
- def test_should_clear_errors_on_reset
- @record.state = 'parked'
- @record.errors.add(:state, 'is invalid')
-
- @machine.reset(@record)
- assert_equal [], @record.errors.full_messages
- end
-
- def test_should_be_valid_if_state_is_known
- @record.state = 'parked'
-
- assert @record.valid?
- end
-
- def test_should_not_be_valid_if_state_is_unknown
- @record.state = 'invalid'
-
- assert !@record.valid?
- assert_equal ['State is invalid'], @record.errors.full_messages
- end
- end
-
- class MachineWithValidationsAndCustomAttributeTest < BaseTestCase
- def setup
- @model = new_model
- @machine = StateMachine::Machine.new(@model, :status, :attribute => :state)
- @machine.state :parked
-
- @record = @model.new
- end
-
- def test_should_add_validation_errors_to_custom_attribute
- @record.state = 'invalid'
-
- assert !@record.valid?
- assert_equal ['State is invalid'], @record.errors.full_messages
-
- @record.state = 'parked'
- assert @record.valid?
- end
- end
-
- class MachineErrorsTest < BaseTestCase
- def setup
- @model = new_model
- @machine = StateMachine::Machine.new(@model)
- @record = @model.new
- end
-
- def test_should_be_able_to_describe_current_errors
- @record.errors.add(:id, 'cannot be blank')
- @record.errors.add(:state, 'is invalid')
- assert_equal ['Id cannot be blank', 'State is invalid'], @machine.errors_for(@record).split(', ').sort
- end
-
- def test_should_describe_as_halted_with_no_errors
- assert_equal 'Transition halted', @machine.errors_for(@record)
- end
- end
-
- class MachineWithStateDrivenValidationsTest < BaseTestCase
- def setup
- @model = new_model do
- attr_accessor :seatbealt
- end
-
- @machine = StateMachine::Machine.new(@model)
- @machine.state :first_gear do
- validates_presence_of :seatbelt, :key => :first_gear
- end
- @machine.state :second_gear do
- validates_presence_of :seatbelt, :key => :second_gear
- end
- @machine.other_states :parked
- end
-
- def test_should_be_valid_if_validation_fails_outside_state_scope
- record = @model.new(:state => 'parked', :seatbelt => nil)
- assert record.valid?
- end
-
- def test_should_be_invalid_if_validation_fails_within_state_scope
- record = @model.new(:state => 'first_gear', :seatbelt => nil)
- assert !record.valid?
- end
-
- def test_should_be_valid_if_validation_succeeds_within_state_scope
- record = @model.new(:state => 'second_gear', :seatbelt => true)
- assert record.valid?
- end
- end
-
- class MachineWithEventAttributesOnValidationTest < BaseTestCase
- def setup
- @model = new_model
- @machine = StateMachine::Machine.new(@model)
- @machine.event :ignite do
- transition :parked => :idling
- end
-
- @record = @model.new
- @record.state = 'parked'
- @record.state_event = 'ignite'
- end
-
- def test_should_fail_if_event_is_invalid
- @record.state_event = 'invalid'
- assert !@record.valid?
- assert_equal ['State event is invalid'], @record.errors.full_messages
- end
-
- def test_should_fail_if_event_has_no_transition
- @record.state = 'idling'
- assert !@record.valid?
- assert_equal ['State event cannot transition when idling'], @record.errors.full_messages
- end
-
- def test_should_be_successful_if_event_has_transition
- assert @record.valid?
- end
-
- def test_should_run_before_callbacks
- ran_callback = false
- @machine.before_transition { ran_callback = true }
-
- @record.valid?
- assert ran_callback
- end
-
- def test_should_run_around_callbacks_before_yield
- ran_callback = false
- @machine.around_transition {|block| ran_callback = true; block.call }
-
- begin
- @record.valid?
- rescue ArgumentError
- raise if StateMachine::Transition.pause_supported?
- end
- assert ran_callback
- end
-
- def test_should_persist_new_state
- @record.valid?
- assert_equal 'idling', @record.state
- end
-
- def test_should_not_run_after_callbacks
- ran_callback = false
- @machine.after_transition { ran_callback = true }
-
- @record.valid?
- assert !ran_callback
- end
-
- def test_should_not_run_after_callbacks_with_failures_disabled_if_validation_fails
- @model.class_eval do
- attr_accessor :seatbelt
- validates_presence_of :seatbelt
- end
-
- ran_callback = false
- @machine.after_transition { ran_callback = true }
-
- @record.valid?
- assert !ran_callback
- end
-
- def test_should_not_run_around_callbacks_after_yield
- ran_callback = false
- @machine.around_transition {|block| block.call; ran_callback = true }
-
- begin
- @record.valid?
- rescue ArgumentError
- raise if StateMachine::Transition.pause_supported?
- end
- assert !ran_callback
- end
-
- def test_should_not_run_around_callbacks_after_yield_with_failures_disabled_if_validation_fails
- @model.class_eval do
- attr_accessor :seatbelt
- validates_presence_of :seatbelt
- end
-
- ran_callback = false
- @machine.around_transition {|block| block.call; ran_callback = true }
-
- @record.valid?
- assert !ran_callback
- end
-
- def test_should_run_failure_callbacks_if_validation_fails
- @model.class_eval do
- attr_accessor :seatbelt
- validates_presence_of :seatbelt
- end
-
- ran_callback = false
- @machine.after_failure { ran_callback = true }
-
- @record.valid?
- assert ran_callback
- end
- end
-
- class MachineWithEventAttributesOnSaveTest < BaseTestCase
- def setup
- @model = new_model
- @machine = StateMachine::Machine.new(@model)
- @machine.event :ignite do
- transition :parked => :idling
- end
-
- @record = @model.new
- @record.state = 'parked'
- @record.state_event = 'ignite'
- end
-
- def test_should_fail_if_event_is_invalid
- @record.state_event = 'invalid'
- assert_equal false, @record.save
- end
-
- def test_should_fail_if_event_has_no_transition
- @record.state = 'idling'
- assert_equal false, @record.save
- end
-
- def test_should_be_successful_if_event_has_transition
- assert_equal true, @record.save
- end
-
- def test_should_run_before_callbacks
- ran_callback = false
- @machine.before_transition { ran_callback = true }
-
- @record.save
- assert ran_callback
- end
-
- def test_should_run_before_callbacks_once
- before_count = 0
- @machine.before_transition { before_count += 1 }
-
- @record.save
- assert_equal 1, before_count
- end
-
- def test_should_run_around_callbacks_before_yield
- ran_callback = false
- @machine.around_transition {|block| ran_callback = true; block.call }
-
- @record.save
- assert ran_callback
- end
-
- def test_should_run_around_callbacks_before_yield_once
- around_before_count = 0
- @machine.around_transition {|block| around_before_count += 1; block.call }
-
- @record.save
- assert_equal 1, around_before_count
- end
-
- def test_should_persist_new_state
- @record.save
- assert_equal 'idling', @record.state
- end
-
- def test_should_run_after_callbacks
- ran_callback = false
- @machine.after_transition { ran_callback = true }
-
- @record.save
- assert ran_callback
- end
-
- def test_should_not_run_after_callbacks_with_failures_disabled_if_fails
- @model.class_eval do
- validates_numericality_of :state
- end
-
- ran_callback = false
- @machine.after_transition { ran_callback = true }
-
- begin; @record.save; rescue; end
- assert !ran_callback
- end
-
- def test_should_run_failure_callbacks__if_fails
- @model.class_eval do
- validates_numericality_of :state
- end
-
- ran_callback = false
- @machine.after_failure { ran_callback = true }
-
- begin; @record.save; rescue; end
- assert ran_callback
- end
-
- def test_should_not_run_around_callbacks_with_failures_disabled_if_fails
- @model.class_eval do
- validates_numericality_of :state
- end
-
- ran_callback = false
- @machine.around_transition {|block| block.call; ran_callback = true }
-
- begin; @record.save; rescue; end
- assert !ran_callback
- end
-
- def test_should_run_around_callbacks_after_yield
- ran_callback = false
- @machine.around_transition {|block| block.call; ran_callback = true }
-
- @record.save
- assert ran_callback
- end
-
- def test_should_allow_additional_transitions_to_new_state_in_after_transitions
- @machine.event :park do
- transition :idling => :parked
- end
-
- @machine.after_transition(:on => :ignite) { @record.park }
-
- @record.save
- assert_equal 'parked', @record.state
-
- @record.reload
- assert_equal 'parked', @record.state
- end
-
- def test_should_allow_additional_transitions_to_previous_state_in_after_transitions
- @machine.event :shift_up do
- transition :idling => :first_gear
- end
-
- @machine.after_transition(:on => :ignite) { @record.shift_up }
-
- @record.save
- assert_equal 'first_gear', @record.state
-
- @record.reload
- assert_equal 'first_gear', @record.state
- end
- end
-
- if Mongoid::VERSION >= '2.1.0'
- class MachineWithEventAttributesOnAutosaveTest < BaseTestCase
- def setup
- @vehicle_model = new_model(:vehicle) do
- belongs_to :owner, :class_name => 'MongoidTest::Owner'
- end
- MongoidTest.const_set('Vehicle', @vehicle_model)
-
- @owner_model = new_model(:owner)
- MongoidTest.const_set('Owner', @owner_model)
-
- machine = StateMachine::Machine.new(@vehicle_model)
- machine.event :ignite do
- transition :parked => :idling
- end
-
- @owner = @owner_model.create
- end
-
- def test_should_persist_many_association
- @owner_model.has_many :vehicles, :class_name => 'MongoidTest::Vehicle', :autosave => true
- @vehicle = @vehicle_model.create(:state => 'parked', :owner_id => @owner.id)
-
- @owner.vehicles[0].state_event = 'ignite'
- @owner.save
-
- @vehicle.reload
- assert_equal 'idling', @vehicle.state
- end
-
- def test_should_persist_one_association
- @owner_model.has_one :vehicle, :class_name => 'MongoidTest::Vehicle', :autosave => true
- @vehicle = @vehicle_model.create(:state => 'parked', :owner_id => @owner.id)
-
- @owner.vehicle.state_event = 'ignite'
- @owner.save
-
- @vehicle.reload
- assert_equal 'idling', @vehicle.state
- end
-
- def teardown
- MongoidTest.class_eval do
- remove_const('Vehicle')
- remove_const('Owner')
- end
- super
- end
- end
- end
-
- class MachineWithEventAttributesOnSaveBangTest < BaseTestCase
- def setup
- @model = new_model
- @machine = StateMachine::Machine.new(@model)
- @machine.event :ignite do
- transition :parked => :idling
- end
-
- @record = @model.new
- @record.state = 'parked'
- @record.state_event = 'ignite'
- end
-
- def test_should_fail_if_event_is_invalid
- @record.state_event = 'invalid'
- assert_raise(Mongoid::Errors::Validations) { @record.save! }
- end
-
- def test_should_fail_if_event_has_no_transition
- @record.state = 'idling'
- assert_raise(Mongoid::Errors::Validations) { @record.save! }
- end
-
- def test_should_be_successful_if_event_has_transition
- assert_equal true, @record.save!
- end
-
- def test_should_run_before_callbacks
- ran_callback = false
- @machine.before_transition { ran_callback = true }
-
- @record.save!
- assert ran_callback
- end
-
- def test_should_run_before_callbacks_once
- before_count = 0
- @machine.before_transition { before_count += 1 }
-
- @record.save!
- assert_equal 1, before_count
- end
-
- def test_should_run_around_callbacks_before_yield
- ran_callback = false
- @machine.around_transition {|block| ran_callback = true; block.call }
-
- @record.save!
- assert ran_callback
- end
-
- def test_should_run_around_callbacks_before_yield_once
- around_before_count = 0
- @machine.around_transition {|block| around_before_count += 1; block.call }
-
- @record.save!
- assert_equal 1, around_before_count
- end
- …
Large files files are truncated, but you can click here to view the full file