mirror of
				https://github.com/aasm/aasm
				synced 2023-03-27 23:22:41 -04:00 
			
		
		
		
	unified test and spec (using spec only now)
This commit is contained in:
		
							parent
							
								
									04a71b89d7
								
							
						
					
					
						commit
						31258e7636
					
				
					 16 changed files with 462 additions and 715 deletions
				
			
		
							
								
								
									
										4
									
								
								Rakefile
									
										
									
									
									
								
							
							
						
						
									
										4
									
								
								Rakefile
									
										
									
									
									
								
							| 
						 | 
				
			
			@ -13,8 +13,6 @@ Rake::TestTask.new(:test) do |test|
 | 
			
		|||
  test.verbose = true
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
task :default => :test
 | 
			
		||||
 | 
			
		||||
require 'rdoc/task'
 | 
			
		||||
require 'aasm/version'
 | 
			
		||||
require 'sdoc'
 | 
			
		||||
| 
						 | 
				
			
			@ -25,3 +23,5 @@ Rake::RDocTask.new do |rdoc|
 | 
			
		|||
  rdoc.rdoc_files.include('README*')
 | 
			
		||||
  rdoc.rdoc_files.include('lib/**/*.rb')
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
task :default => :spec
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -16,3 +16,4 @@ module Models
 | 
			
		|||
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1,3 +1,5 @@
 | 
			
		|||
Dir[File.dirname(__FILE__) + "/models/**/*.rb"].each { |f| require File.expand_path(f) }
 | 
			
		||||
 | 
			
		||||
class Foo
 | 
			
		||||
  include AASM
 | 
			
		||||
  aasm_initial_state :open
 | 
			
		||||
| 
						 | 
				
			
			@ -65,3 +67,118 @@ class Argument
 | 
			
		|||
    transitions :to => :valid, :from => [:invalid]
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
class AuthMachine
 | 
			
		||||
  include AASM
 | 
			
		||||
 | 
			
		||||
  attr_accessor :activation_code, :activated_at, :deleted_at
 | 
			
		||||
 | 
			
		||||
  aasm_initial_state :pending
 | 
			
		||||
 | 
			
		||||
  aasm_state :passive
 | 
			
		||||
  aasm_state :pending, :enter => :make_activation_code
 | 
			
		||||
  aasm_state :active,  :enter => :do_activate
 | 
			
		||||
  aasm_state :suspended
 | 
			
		||||
  aasm_state :deleted, :enter => :do_delete, :exit => :do_undelete
 | 
			
		||||
 | 
			
		||||
  aasm_event :register do
 | 
			
		||||
    transitions :from => :passive, :to => :pending, :guard => Proc.new {|u| u.can_register? }
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  aasm_event :activate do
 | 
			
		||||
    transitions :from => :pending, :to => :active
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  aasm_event :suspend do
 | 
			
		||||
    transitions :from => [:passive, :pending, :active], :to => :suspended
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  aasm_event :delete do
 | 
			
		||||
    transitions :from => [:passive, :pending, :active, :suspended], :to => :deleted
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  # a dummy event that can never happen
 | 
			
		||||
  aasm_event :unpassify do
 | 
			
		||||
    transitions :from => :passive, :to => :active, :guard => Proc.new {|u| false }
 | 
			
		||||
  end
 | 
			
		||||
  
 | 
			
		||||
  aasm_event :unsuspend do
 | 
			
		||||
    transitions :from => :suspended, :to => :active,  :guard => Proc.new {|u| u.has_activated? }
 | 
			
		||||
    transitions :from => :suspended, :to => :pending, :guard => Proc.new {|u| u.has_activation_code? }
 | 
			
		||||
    transitions :from => :suspended, :to => :passive
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def initialize
 | 
			
		||||
    # the AR backend uses a before_validate_on_create :aasm_ensure_initial_state
 | 
			
		||||
    # lets do something similar here for testing purposes.
 | 
			
		||||
    aasm_enter_initial_state
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def make_activation_code
 | 
			
		||||
    @activation_code = 'moo'
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def do_activate
 | 
			
		||||
    @activated_at = Time.now
 | 
			
		||||
    @activation_code = nil
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def do_delete
 | 
			
		||||
    @deleted_at = Time.now
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def do_undelete
 | 
			
		||||
    @deleted_at = false
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def can_register?
 | 
			
		||||
    true
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def has_activated?
 | 
			
		||||
    !!@activated_at
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def has_activation_code?
 | 
			
		||||
    !!@activation_code
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
class ThisNameBetterNotBeInUse
 | 
			
		||||
  include AASM
 | 
			
		||||
 | 
			
		||||
  aasm_state :initial
 | 
			
		||||
  aasm_state :symbol
 | 
			
		||||
  aasm_state :string
 | 
			
		||||
  aasm_state :array
 | 
			
		||||
  aasm_state :proc
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
class ChetanPatil
 | 
			
		||||
  include AASM
 | 
			
		||||
  aasm_initial_state :sleeping
 | 
			
		||||
  aasm_state :sleeping
 | 
			
		||||
  aasm_state :showering
 | 
			
		||||
  aasm_state :working
 | 
			
		||||
  aasm_state :dating
 | 
			
		||||
  aasm_state :prettying_up
 | 
			
		||||
 | 
			
		||||
  aasm_event :wakeup do
 | 
			
		||||
    transitions :from => :sleeping, :to => [:showering, :working]
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  aasm_event :dress do
 | 
			
		||||
    transitions :from => :sleeping, :to => :working, :on_transition => :wear_clothes
 | 
			
		||||
    transitions :from => :showering, :to => [:working, :dating], :on_transition => Proc.new { |obj, *args| obj.wear_clothes(*args) }
 | 
			
		||||
    transitions :from => :showering, :to => :prettying_up, :on_transition => [:condition_hair, :fix_hair]
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def wear_clothes(shirt_color, trouser_type)
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def condition_hair
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def fix_hair
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -333,35 +333,6 @@ describe Baz do
 | 
			
		|||
end
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class ChetanPatil
 | 
			
		||||
  include AASM
 | 
			
		||||
  aasm_initial_state :sleeping
 | 
			
		||||
  aasm_state :sleeping
 | 
			
		||||
  aasm_state :showering
 | 
			
		||||
  aasm_state :working
 | 
			
		||||
  aasm_state :dating
 | 
			
		||||
  aasm_state :prettying_up
 | 
			
		||||
 | 
			
		||||
  aasm_event :wakeup do
 | 
			
		||||
    transitions :from => :sleeping, :to => [:showering, :working]
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  aasm_event :dress do
 | 
			
		||||
    transitions :from => :sleeping, :to => :working, :on_transition => :wear_clothes
 | 
			
		||||
    transitions :from => :showering, :to => [:working, :dating], :on_transition => Proc.new { |obj, *args| obj.wear_clothes(*args) }
 | 
			
		||||
    transitions :from => :showering, :to => :prettying_up, :on_transition => [:condition_hair, :fix_hair]
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def wear_clothes(shirt_color, trouser_type)
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def condition_hair
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def fix_hair
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
describe ChetanPatil do
 | 
			
		||||
  it 'should transition to specified next state (sleeping to showering)' do
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,246 +1,237 @@
 | 
			
		|||
begin
 | 
			
		||||
  require 'rubygems'
 | 
			
		||||
  require 'active_record'
 | 
			
		||||
  require 'logger'
 | 
			
		||||
require 'rubygems'
 | 
			
		||||
require 'active_record'
 | 
			
		||||
require 'logger'
 | 
			
		||||
 | 
			
		||||
  load_schema
 | 
			
		||||
load_schema
 | 
			
		||||
 | 
			
		||||
  ActiveRecord::Base.logger = Logger.new(STDERR)
 | 
			
		||||
ActiveRecord::Base.logger = Logger.new(STDERR)
 | 
			
		||||
 | 
			
		||||
  class Gate < ActiveRecord::Base
 | 
			
		||||
    include AASM
 | 
			
		||||
class Gate < ActiveRecord::Base
 | 
			
		||||
  include AASM
 | 
			
		||||
 | 
			
		||||
    # Fake this column for testing purposes
 | 
			
		||||
    attr_accessor :aasm_state
 | 
			
		||||
  # Fake this column for testing purposes
 | 
			
		||||
  attr_accessor :aasm_state
 | 
			
		||||
 | 
			
		||||
    aasm_state :opened
 | 
			
		||||
    aasm_state :closed
 | 
			
		||||
  aasm_state :opened
 | 
			
		||||
  aasm_state :closed
 | 
			
		||||
 | 
			
		||||
    aasm_event :view do
 | 
			
		||||
      transitions :to => :read, :from => [:needs_attention]
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  class Reader < ActiveRecord::Base
 | 
			
		||||
    def aasm_read_state
 | 
			
		||||
      "fi"
 | 
			
		||||
    end
 | 
			
		||||
    include AASM
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  class Writer < ActiveRecord::Base
 | 
			
		||||
    def aasm_write_state(state)
 | 
			
		||||
      "fo"
 | 
			
		||||
    end
 | 
			
		||||
    include AASM
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  class Transient < ActiveRecord::Base
 | 
			
		||||
    def aasm_write_state_without_persistence(state)
 | 
			
		||||
      "fum"
 | 
			
		||||
    end
 | 
			
		||||
    include AASM
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  class Simple < ActiveRecord::Base
 | 
			
		||||
    include AASM
 | 
			
		||||
    aasm_column :status
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  class Derivate < Simple
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  class Thief < ActiveRecord::Base
 | 
			
		||||
    set_table_name "thieves"
 | 
			
		||||
    include AASM
 | 
			
		||||
    aasm_initial_state  Proc.new { |thief| thief.skilled ? :rich : :jailed }
 | 
			
		||||
    aasm_state          :rich
 | 
			
		||||
    aasm_state          :jailed
 | 
			
		||||
    attr_accessor :skilled, :aasm_state
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  shared_examples_for "aasm model" do
 | 
			
		||||
    it "should include AASM::Persistence::ActiveRecordPersistence" do
 | 
			
		||||
      @klass.included_modules.should be_include(AASM::Persistence::ActiveRecordPersistence)
 | 
			
		||||
    end
 | 
			
		||||
    it "should include AASM::Persistence::ActiveRecordPersistence::InstanceMethods" do
 | 
			
		||||
      @klass.included_modules.should be_include(AASM::Persistence::ActiveRecordPersistence::InstanceMethods)
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  describe Gate, "class methods" do
 | 
			
		||||
    before(:each) do
 | 
			
		||||
      @klass = Gate
 | 
			
		||||
    end
 | 
			
		||||
    it_should_behave_like "aasm model"
 | 
			
		||||
    it "should include AASM::Persistence::ActiveRecordPersistence::ReadState" do
 | 
			
		||||
      @klass.included_modules.should be_include(AASM::Persistence::ActiveRecordPersistence::ReadState)
 | 
			
		||||
    end
 | 
			
		||||
    it "should include AASM::Persistence::ActiveRecordPersistence::WriteState" do
 | 
			
		||||
      @klass.included_modules.should be_include(AASM::Persistence::ActiveRecordPersistence::WriteState)
 | 
			
		||||
    end
 | 
			
		||||
    it "should include AASM::Persistence::ActiveRecordPersistence::WriteStateWithoutPersistence" do
 | 
			
		||||
      @klass.included_modules.should be_include(AASM::Persistence::ActiveRecordPersistence::WriteStateWithoutPersistence)
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  describe Reader, "class methods" do
 | 
			
		||||
    before(:each) do
 | 
			
		||||
      @klass = Reader
 | 
			
		||||
    end
 | 
			
		||||
    it_should_behave_like "aasm model"
 | 
			
		||||
    it "should not include AASM::Persistence::ActiveRecordPersistence::ReadState" do
 | 
			
		||||
      @klass.included_modules.should_not be_include(AASM::Persistence::ActiveRecordPersistence::ReadState)
 | 
			
		||||
    end
 | 
			
		||||
    it "should include AASM::Persistence::ActiveRecordPersistence::WriteState" do
 | 
			
		||||
      @klass.included_modules.should be_include(AASM::Persistence::ActiveRecordPersistence::WriteState)
 | 
			
		||||
    end
 | 
			
		||||
    it "should include AASM::Persistence::ActiveRecordPersistence::WriteStateWithoutPersistence" do
 | 
			
		||||
      @klass.included_modules.should be_include(AASM::Persistence::ActiveRecordPersistence::WriteStateWithoutPersistence)
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  describe Writer, "class methods" do
 | 
			
		||||
    before(:each) do
 | 
			
		||||
      @klass = Writer
 | 
			
		||||
    end
 | 
			
		||||
    it_should_behave_like "aasm model"
 | 
			
		||||
    it "should include AASM::Persistence::ActiveRecordPersistence::ReadState" do
 | 
			
		||||
      @klass.included_modules.should be_include(AASM::Persistence::ActiveRecordPersistence::ReadState)
 | 
			
		||||
    end
 | 
			
		||||
    it "should not include AASM::Persistence::ActiveRecordPersistence::WriteState" do
 | 
			
		||||
      @klass.included_modules.should_not be_include(AASM::Persistence::ActiveRecordPersistence::WriteState)
 | 
			
		||||
    end
 | 
			
		||||
    it "should include AASM::Persistence::ActiveRecordPersistence::WriteStateWithoutPersistence" do
 | 
			
		||||
      @klass.included_modules.should be_include(AASM::Persistence::ActiveRecordPersistence::WriteStateWithoutPersistence)
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  describe Transient, "class methods" do
 | 
			
		||||
    before(:each) do
 | 
			
		||||
      @klass = Transient
 | 
			
		||||
    end
 | 
			
		||||
    it_should_behave_like "aasm model"
 | 
			
		||||
    it "should include AASM::Persistence::ActiveRecordPersistence::ReadState" do
 | 
			
		||||
      @klass.included_modules.should be_include(AASM::Persistence::ActiveRecordPersistence::ReadState)
 | 
			
		||||
    end
 | 
			
		||||
    it "should include AASM::Persistence::ActiveRecordPersistence::WriteState" do
 | 
			
		||||
      @klass.included_modules.should be_include(AASM::Persistence::ActiveRecordPersistence::WriteState)
 | 
			
		||||
    end
 | 
			
		||||
    it "should not include AASM::Persistence::ActiveRecordPersistence::WriteStateWithoutPersistence" do
 | 
			
		||||
      @klass.included_modules.should_not be_include(AASM::Persistence::ActiveRecordPersistence::WriteStateWithoutPersistence)
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  describe Gate, "instance methods" do
 | 
			
		||||
 | 
			
		||||
    it "should respond to aasm read state when not previously defined" do
 | 
			
		||||
      Gate.new.should respond_to(:aasm_read_state)
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    it "should respond to aasm write state when not previously defined" do
 | 
			
		||||
      Gate.new.should respond_to(:aasm_write_state)
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    it "should respond to aasm write state without persistence when not previously defined" do
 | 
			
		||||
      Gate.new.should respond_to(:aasm_write_state_without_persistence)
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    it "should return the initial state when new and the aasm field is nil" do
 | 
			
		||||
      Gate.new.aasm_current_state.should == :opened
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    it "should return the aasm column when new and the aasm field is not nil" do
 | 
			
		||||
      foo = Gate.new
 | 
			
		||||
      foo.aasm_state = "closed"
 | 
			
		||||
      foo.aasm_current_state.should == :closed
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    it "should return the aasm column when not new and the aasm_column is not nil" do
 | 
			
		||||
      foo = Gate.new
 | 
			
		||||
      foo.stub!(:new_record?).and_return(false)
 | 
			
		||||
      foo.aasm_state = "state"
 | 
			
		||||
      foo.aasm_current_state.should == :state
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    it "should allow a nil state" do
 | 
			
		||||
      foo = Gate.new
 | 
			
		||||
      foo.stub!(:new_record?).and_return(false)
 | 
			
		||||
      foo.aasm_state = nil
 | 
			
		||||
      foo.aasm_current_state.should be_nil
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    it "should have aasm_ensure_initial_state" do
 | 
			
		||||
      foo = Gate.new
 | 
			
		||||
      foo.send :aasm_ensure_initial_state
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    it "should call aasm_ensure_initial_state on validation before create" do
 | 
			
		||||
      foo = Gate.new
 | 
			
		||||
      foo.should_receive(:aasm_ensure_initial_state).and_return(true)
 | 
			
		||||
      foo.valid?
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    it "should call aasm_ensure_initial_state on validation before create" do
 | 
			
		||||
      foo = Gate.new
 | 
			
		||||
      foo.stub!(:new_record?).and_return(false)
 | 
			
		||||
      foo.should_not_receive(:aasm_ensure_initial_state)
 | 
			
		||||
      foo.valid?
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  describe 'Derivates' do
 | 
			
		||||
    it "should have the same states as it's parent" do
 | 
			
		||||
      Derivate.aasm_states.should == Simple.aasm_states
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    it "should have the same events as it's parent" do
 | 
			
		||||
      Derivate.aasm_events.should == Simple.aasm_events
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    it "should have the same column as it's parent" do
 | 
			
		||||
      Derivate.aasm_column.should == :status
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  describe AASM::Persistence::ActiveRecordPersistence::NamedScopeMethods do
 | 
			
		||||
 | 
			
		||||
    context "Does not already respond_to? the scope name" do
 | 
			
		||||
      it "should add a scope" do
 | 
			
		||||
        Simple.should_not respond_to(:unknown_scope)
 | 
			
		||||
        Simple.aasm_state :unknown_scope
 | 
			
		||||
        Simple.should respond_to(:unknown_scope)
 | 
			
		||||
        Simple.unknown_scope.class.should == ActiveRecord::Relation
 | 
			
		||||
      end
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    context "Already respond_to? the scope name" do
 | 
			
		||||
      it "should not add a scope" do
 | 
			
		||||
        Simple.aasm_state :new
 | 
			
		||||
        Simple.should respond_to(:new)
 | 
			
		||||
        Simple.new.class.should == Simple
 | 
			
		||||
      end
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  describe 'Thieves' do
 | 
			
		||||
 | 
			
		||||
    it 'should be rich if they\'re skilled' do
 | 
			
		||||
      Thief.new(:skilled => true).aasm_current_state.should == :rich
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    it 'should be jailed if they\'re unskilled' do
 | 
			
		||||
      Thief.new(:skilled => false).aasm_current_state.should == :jailed
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  # TODO: figure out how to test ActiveRecord reload! without a database
 | 
			
		||||
 | 
			
		||||
rescue LoadError => e
 | 
			
		||||
  if e.message == "no such file to load -- active_record"
 | 
			
		||||
    puts "You must install active record to run this spec.  Install with sudo gem install activerecord"
 | 
			
		||||
  else
 | 
			
		||||
    raise
 | 
			
		||||
  aasm_event :view do
 | 
			
		||||
    transitions :to => :read, :from => [:needs_attention]
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
class Reader < ActiveRecord::Base
 | 
			
		||||
  def aasm_read_state
 | 
			
		||||
    "fi"
 | 
			
		||||
  end
 | 
			
		||||
  include AASM
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
class Writer < ActiveRecord::Base
 | 
			
		||||
  def aasm_write_state(state)
 | 
			
		||||
    "fo"
 | 
			
		||||
  end
 | 
			
		||||
  include AASM
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
class Transient < ActiveRecord::Base
 | 
			
		||||
  def aasm_write_state_without_persistence(state)
 | 
			
		||||
    "fum"
 | 
			
		||||
  end
 | 
			
		||||
  include AASM
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
class Simple < ActiveRecord::Base
 | 
			
		||||
  include AASM
 | 
			
		||||
  aasm_column :status
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
class Derivate < Simple
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
class Thief < ActiveRecord::Base
 | 
			
		||||
  set_table_name "thieves"
 | 
			
		||||
  include AASM
 | 
			
		||||
  aasm_initial_state  Proc.new { |thief| thief.skilled ? :rich : :jailed }
 | 
			
		||||
  aasm_state          :rich
 | 
			
		||||
  aasm_state          :jailed
 | 
			
		||||
  attr_accessor :skilled, :aasm_state
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
shared_examples_for "aasm model" do
 | 
			
		||||
  it "should include AASM::Persistence::ActiveRecordPersistence" do
 | 
			
		||||
    @klass.included_modules.should be_include(AASM::Persistence::ActiveRecordPersistence)
 | 
			
		||||
  end
 | 
			
		||||
  it "should include AASM::Persistence::ActiveRecordPersistence::InstanceMethods" do
 | 
			
		||||
    @klass.included_modules.should be_include(AASM::Persistence::ActiveRecordPersistence::InstanceMethods)
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
describe Gate, "class methods" do
 | 
			
		||||
  before(:each) do
 | 
			
		||||
    @klass = Gate
 | 
			
		||||
  end
 | 
			
		||||
  it_should_behave_like "aasm model"
 | 
			
		||||
  it "should include AASM::Persistence::ActiveRecordPersistence::ReadState" do
 | 
			
		||||
    @klass.included_modules.should be_include(AASM::Persistence::ActiveRecordPersistence::ReadState)
 | 
			
		||||
  end
 | 
			
		||||
  it "should include AASM::Persistence::ActiveRecordPersistence::WriteState" do
 | 
			
		||||
    @klass.included_modules.should be_include(AASM::Persistence::ActiveRecordPersistence::WriteState)
 | 
			
		||||
  end
 | 
			
		||||
  it "should include AASM::Persistence::ActiveRecordPersistence::WriteStateWithoutPersistence" do
 | 
			
		||||
    @klass.included_modules.should be_include(AASM::Persistence::ActiveRecordPersistence::WriteStateWithoutPersistence)
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
describe Reader, "class methods" do
 | 
			
		||||
  before(:each) do
 | 
			
		||||
    @klass = Reader
 | 
			
		||||
  end
 | 
			
		||||
  it_should_behave_like "aasm model"
 | 
			
		||||
  it "should not include AASM::Persistence::ActiveRecordPersistence::ReadState" do
 | 
			
		||||
    @klass.included_modules.should_not be_include(AASM::Persistence::ActiveRecordPersistence::ReadState)
 | 
			
		||||
  end
 | 
			
		||||
  it "should include AASM::Persistence::ActiveRecordPersistence::WriteState" do
 | 
			
		||||
    @klass.included_modules.should be_include(AASM::Persistence::ActiveRecordPersistence::WriteState)
 | 
			
		||||
  end
 | 
			
		||||
  it "should include AASM::Persistence::ActiveRecordPersistence::WriteStateWithoutPersistence" do
 | 
			
		||||
    @klass.included_modules.should be_include(AASM::Persistence::ActiveRecordPersistence::WriteStateWithoutPersistence)
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
describe Writer, "class methods" do
 | 
			
		||||
  before(:each) do
 | 
			
		||||
    @klass = Writer
 | 
			
		||||
  end
 | 
			
		||||
  it_should_behave_like "aasm model"
 | 
			
		||||
  it "should include AASM::Persistence::ActiveRecordPersistence::ReadState" do
 | 
			
		||||
    @klass.included_modules.should be_include(AASM::Persistence::ActiveRecordPersistence::ReadState)
 | 
			
		||||
  end
 | 
			
		||||
  it "should not include AASM::Persistence::ActiveRecordPersistence::WriteState" do
 | 
			
		||||
    @klass.included_modules.should_not be_include(AASM::Persistence::ActiveRecordPersistence::WriteState)
 | 
			
		||||
  end
 | 
			
		||||
  it "should include AASM::Persistence::ActiveRecordPersistence::WriteStateWithoutPersistence" do
 | 
			
		||||
    @klass.included_modules.should be_include(AASM::Persistence::ActiveRecordPersistence::WriteStateWithoutPersistence)
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
describe Transient, "class methods" do
 | 
			
		||||
  before(:each) do
 | 
			
		||||
    @klass = Transient
 | 
			
		||||
  end
 | 
			
		||||
  it_should_behave_like "aasm model"
 | 
			
		||||
  it "should include AASM::Persistence::ActiveRecordPersistence::ReadState" do
 | 
			
		||||
    @klass.included_modules.should be_include(AASM::Persistence::ActiveRecordPersistence::ReadState)
 | 
			
		||||
  end
 | 
			
		||||
  it "should include AASM::Persistence::ActiveRecordPersistence::WriteState" do
 | 
			
		||||
    @klass.included_modules.should be_include(AASM::Persistence::ActiveRecordPersistence::WriteState)
 | 
			
		||||
  end
 | 
			
		||||
  it "should not include AASM::Persistence::ActiveRecordPersistence::WriteStateWithoutPersistence" do
 | 
			
		||||
    @klass.included_modules.should_not be_include(AASM::Persistence::ActiveRecordPersistence::WriteStateWithoutPersistence)
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
describe Gate, "instance methods" do
 | 
			
		||||
 | 
			
		||||
  it "should respond to aasm read state when not previously defined" do
 | 
			
		||||
    Gate.new.should respond_to(:aasm_read_state)
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  it "should respond to aasm write state when not previously defined" do
 | 
			
		||||
    Gate.new.should respond_to(:aasm_write_state)
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  it "should respond to aasm write state without persistence when not previously defined" do
 | 
			
		||||
    Gate.new.should respond_to(:aasm_write_state_without_persistence)
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  it "should return the initial state when new and the aasm field is nil" do
 | 
			
		||||
    Gate.new.aasm_current_state.should == :opened
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  it "should return the aasm column when new and the aasm field is not nil" do
 | 
			
		||||
    foo = Gate.new
 | 
			
		||||
    foo.aasm_state = "closed"
 | 
			
		||||
    foo.aasm_current_state.should == :closed
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  it "should return the aasm column when not new and the aasm_column is not nil" do
 | 
			
		||||
    foo = Gate.new
 | 
			
		||||
    foo.stub!(:new_record?).and_return(false)
 | 
			
		||||
    foo.aasm_state = "state"
 | 
			
		||||
    foo.aasm_current_state.should == :state
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  it "should allow a nil state" do
 | 
			
		||||
    foo = Gate.new
 | 
			
		||||
    foo.stub!(:new_record?).and_return(false)
 | 
			
		||||
    foo.aasm_state = nil
 | 
			
		||||
    foo.aasm_current_state.should be_nil
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  it "should have aasm_ensure_initial_state" do
 | 
			
		||||
    foo = Gate.new
 | 
			
		||||
    foo.send :aasm_ensure_initial_state
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  it "should call aasm_ensure_initial_state on validation before create" do
 | 
			
		||||
    foo = Gate.new
 | 
			
		||||
    foo.should_receive(:aasm_ensure_initial_state).and_return(true)
 | 
			
		||||
    foo.valid?
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  it "should call aasm_ensure_initial_state on validation before create" do
 | 
			
		||||
    foo = Gate.new
 | 
			
		||||
    foo.stub!(:new_record?).and_return(false)
 | 
			
		||||
    foo.should_not_receive(:aasm_ensure_initial_state)
 | 
			
		||||
    foo.valid?
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
describe 'Derivates' do
 | 
			
		||||
  it "should have the same states as it's parent" do
 | 
			
		||||
    Derivate.aasm_states.should == Simple.aasm_states
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  it "should have the same events as it's parent" do
 | 
			
		||||
    Derivate.aasm_events.should == Simple.aasm_events
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  it "should have the same column as it's parent" do
 | 
			
		||||
    Derivate.aasm_column.should == :status
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
describe AASM::Persistence::ActiveRecordPersistence::NamedScopeMethods do
 | 
			
		||||
 | 
			
		||||
  context "Does not already respond_to? the scope name" do
 | 
			
		||||
    it "should add a scope" do
 | 
			
		||||
      Simple.should_not respond_to(:unknown_scope)
 | 
			
		||||
      Simple.aasm_state :unknown_scope
 | 
			
		||||
      Simple.should respond_to(:unknown_scope)
 | 
			
		||||
      Simple.unknown_scope.class.should == ActiveRecord::Relation
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  context "Already respond_to? the scope name" do
 | 
			
		||||
    it "should not add a scope" do
 | 
			
		||||
      Simple.aasm_state :new
 | 
			
		||||
      Simple.should respond_to(:new)
 | 
			
		||||
      Simple.new.class.should == Simple
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
describe 'Thieves' do
 | 
			
		||||
 | 
			
		||||
  it 'should be rich if they\'re skilled' do
 | 
			
		||||
    Thief.new(:skilled => true).aasm_current_state.should == :rich
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  it 'should be jailed if they\'re unskilled' do
 | 
			
		||||
    Thief.new(:skilled => false).aasm_current_state.should == :jailed
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
# TODO: figure out how to test ActiveRecord reload! without a database
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										66
									
								
								spec/unit/auth_machine_spec.rb
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										66
									
								
								spec/unit/auth_machine_spec.rb
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,66 @@
 | 
			
		|||
require File.expand_path(File.join(File.dirname(__FILE__), '..', 'spec_helper'))
 | 
			
		||||
 | 
			
		||||
describe 'AuthMachine on initialization' do
 | 
			
		||||
  before(:each) do
 | 
			
		||||
    @auth = AuthMachine.new
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  it 'should be in the pending state' do
 | 
			
		||||
    @auth.aasm_current_state.should == :pending
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  it 'should have an activation code' do
 | 
			
		||||
    @auth.has_activation_code?.should be_true
 | 
			
		||||
    @auth.activation_code.should_not be_nil
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
describe 'AuthMachine when being unsuspended' do
 | 
			
		||||
  it 'should be able to be unsuspended' do
 | 
			
		||||
    @auth = AuthMachine.new
 | 
			
		||||
    @auth.activate!
 | 
			
		||||
    @auth.suspend!
 | 
			
		||||
    @auth.may_unsuspend?.should be_true
 | 
			
		||||
  end
 | 
			
		||||
  
 | 
			
		||||
  it 'should not be able to be unsuspended into active' do
 | 
			
		||||
    @auth = AuthMachine.new
 | 
			
		||||
    @auth.suspend!
 | 
			
		||||
    @auth.may_unsuspend?(:active).should_not be_true
 | 
			
		||||
  end
 | 
			
		||||
  
 | 
			
		||||
  it 'should not be able to be unpassified' do
 | 
			
		||||
    @auth = AuthMachine.new
 | 
			
		||||
    @auth.activate!
 | 
			
		||||
    @auth.suspend!
 | 
			
		||||
    @auth.unsuspend!
 | 
			
		||||
    
 | 
			
		||||
    @auth.may_unpassify?.should_not be_true
 | 
			
		||||
  end
 | 
			
		||||
  
 | 
			
		||||
  it 'should be active if previously activated' do
 | 
			
		||||
    @auth = AuthMachine.new
 | 
			
		||||
    @auth.activate!
 | 
			
		||||
    @auth.suspend!
 | 
			
		||||
    @auth.unsuspend!
 | 
			
		||||
 | 
			
		||||
    @auth.aasm_current_state.should == :active
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  it 'should be pending if not previously activated, but an activation code is present' do
 | 
			
		||||
    @auth = AuthMachine.new
 | 
			
		||||
    @auth.suspend!
 | 
			
		||||
    @auth.unsuspend!
 | 
			
		||||
 | 
			
		||||
    @auth.aasm_current_state.should == :pending
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  it 'should be passive if not previously activated and there is no activation code' do
 | 
			
		||||
    @auth = AuthMachine.new
 | 
			
		||||
    @auth.activation_code = nil
 | 
			
		||||
    @auth.suspend!
 | 
			
		||||
    @auth.unsuspend!
 | 
			
		||||
 | 
			
		||||
    @auth.aasm_current_state.should == :passive
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
| 
						 | 
				
			
			@ -65,15 +65,6 @@ describe AASM::SupportingClasses::Event, 'when firing an event' do
 | 
			
		|||
end
 | 
			
		||||
 | 
			
		||||
describe AASM::SupportingClasses::Event, 'when executing the success callback' do
 | 
			
		||||
  class ThisNameBetterNotBeInUse
 | 
			
		||||
    include AASM
 | 
			
		||||
 | 
			
		||||
    aasm_state :initial
 | 
			
		||||
    aasm_state :symbol
 | 
			
		||||
    aasm_state :string
 | 
			
		||||
    aasm_state :array
 | 
			
		||||
    aasm_state :proc
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  it "should send the success callback if it's a symbol" do
 | 
			
		||||
    ThisNameBetterNotBeInUse.instance_eval {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										34
									
								
								spec/unit/state_machine_spec.rb
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										34
									
								
								spec/unit/state_machine_spec.rb
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,34 @@
 | 
			
		|||
require File.expand_path(File.join(File.dirname(__FILE__), '..', 'spec_helper'))
 | 
			
		||||
 | 
			
		||||
describe "state machines" do
 | 
			
		||||
 | 
			
		||||
  def number_of_objects(clazz)
 | 
			
		||||
    ObjectSpace.each_object(clazz) {}
 | 
			
		||||
  end
 | 
			
		||||
  
 | 
			
		||||
  def machines
 | 
			
		||||
    AASM::StateMachine.instance_variable_get("@machines")
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  it "should be created without memory leak" do
 | 
			
		||||
    machines_count = machines.size
 | 
			
		||||
    state_count = number_of_objects(AASM::SupportingClasses::State)
 | 
			
		||||
    event_count = number_of_objects(AASM::SupportingClasses::Event)
 | 
			
		||||
    transition_count = number_of_objects(AASM::SupportingClasses::StateTransition)
 | 
			
		||||
 | 
			
		||||
    load File.expand_path(File.dirname(__FILE__) + '/../models/process.rb')
 | 
			
		||||
    machines.size.should == machines_count + 1                                                  # + Process
 | 
			
		||||
    number_of_objects(Models::Process).should == 0
 | 
			
		||||
    number_of_objects(AASM::SupportingClasses::State).should == state_count + 3                 # + Process
 | 
			
		||||
    number_of_objects(AASM::SupportingClasses::Event).should == event_count + 2                 # + Process
 | 
			
		||||
    number_of_objects(AASM::SupportingClasses::StateTransition).should == transition_count + 2  # + Process
 | 
			
		||||
 | 
			
		||||
    Models.send(:remove_const, "Process") if Models.const_defined?("Process")
 | 
			
		||||
    load File.expand_path(File.dirname(__FILE__) + '/../models/process.rb')
 | 
			
		||||
    machines.size.should == machines_count + 1                                                  # + Process
 | 
			
		||||
    number_of_objects(AASM::SupportingClasses::State).should == state_count + 3                 # + Process
 | 
			
		||||
    number_of_objects(AASM::SupportingClasses::Event).should == event_count + 2                 # + Process
 | 
			
		||||
    number_of_objects(AASM::SupportingClasses::StateTransition).should == transition_count + 2  # + Process
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
end
 | 
			
		||||
| 
						 | 
				
			
			@ -1,6 +1,5 @@
 | 
			
		|||
require File.expand_path(File.join(File.dirname(__FILE__), '..', 'spec_helper'))
 | 
			
		||||
 | 
			
		||||
# TODO These are specs ported from original aasm
 | 
			
		||||
describe AASM::SupportingClasses::State do
 | 
			
		||||
  before(:each) do
 | 
			
		||||
    @name    = :astate
 | 
			
		||||
| 
						 | 
				
			
			@ -13,20 +12,23 @@ describe AASM::SupportingClasses::State do
 | 
			
		|||
 | 
			
		||||
  it 'should set the name' do
 | 
			
		||||
    state = new_state
 | 
			
		||||
 | 
			
		||||
    state.name.should == :astate
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  it 'should set the options and expose them as options' do
 | 
			
		||||
    state = new_state
 | 
			
		||||
  it 'should set the display_name from name' do
 | 
			
		||||
    new_state.display_name.should == 'Astate'
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
    state.options.should == @options
 | 
			
		||||
  it 'should set the display_name from options' do
 | 
			
		||||
    new_state(:display => "A State").display_name.should == 'A State'
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  it 'should set the options and expose them as options' do
 | 
			
		||||
    new_state.options.should == @options
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  it 'should be equal to a symbol of the same name' do
 | 
			
		||||
    state = new_state
 | 
			
		||||
 | 
			
		||||
    state.should == :astate
 | 
			
		||||
    new_state.should == :astate
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  it 'should be equal to a State of the same name' do
 | 
			
		||||
| 
						 | 
				
			
			@ -50,16 +52,16 @@ describe AASM::SupportingClasses::State do
 | 
			
		|||
 | 
			
		||||
    state.call_action(:entering, record)
 | 
			
		||||
  end
 | 
			
		||||
  
 | 
			
		||||
 | 
			
		||||
  it 'should send a message to the record for each action' do
 | 
			
		||||
    state = new_state(:entering => [:a, :b, "c", lambda {|r| r.foobar }])
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    record = mock('record')
 | 
			
		||||
    record.should_receive(:a)
 | 
			
		||||
    record.should_receive(:b)
 | 
			
		||||
    record.should_receive(:c)
 | 
			
		||||
    record.should_receive(:foobar)
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    state.call_action(:entering, record)
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,148 +0,0 @@
 | 
			
		|||
require 'test_helper'
 | 
			
		||||
 | 
			
		||||
class AuthMachine
 | 
			
		||||
  include AASM
 | 
			
		||||
 | 
			
		||||
  attr_accessor :activation_code, :activated_at, :deleted_at
 | 
			
		||||
 | 
			
		||||
  aasm_initial_state :pending
 | 
			
		||||
 | 
			
		||||
  aasm_state :passive
 | 
			
		||||
  aasm_state :pending, :enter => :make_activation_code
 | 
			
		||||
  aasm_state :active,  :enter => :do_activate
 | 
			
		||||
  aasm_state :suspended
 | 
			
		||||
  aasm_state :deleted, :enter => :do_delete, :exit => :do_undelete
 | 
			
		||||
 | 
			
		||||
  aasm_event :register do
 | 
			
		||||
    transitions :from => :passive, :to => :pending, :guard => Proc.new {|u| u.can_register? }
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  aasm_event :activate do
 | 
			
		||||
    transitions :from => :pending, :to => :active
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  aasm_event :suspend do
 | 
			
		||||
    transitions :from => [:passive, :pending, :active], :to => :suspended
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  aasm_event :delete do
 | 
			
		||||
    transitions :from => [:passive, :pending, :active, :suspended], :to => :deleted
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  # a dummy event that can never happen
 | 
			
		||||
  aasm_event :unpassify do
 | 
			
		||||
    transitions :from => :passive, :to => :active, :guard => Proc.new {|u| false }
 | 
			
		||||
  end
 | 
			
		||||
  
 | 
			
		||||
  aasm_event :unsuspend do
 | 
			
		||||
    transitions :from => :suspended, :to => :active,  :guard => Proc.new {|u| u.has_activated? }
 | 
			
		||||
    transitions :from => :suspended, :to => :pending, :guard => Proc.new {|u| u.has_activation_code? }
 | 
			
		||||
    transitions :from => :suspended, :to => :passive
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def initialize
 | 
			
		||||
    # the AR backend uses a before_validate_on_create :aasm_ensure_initial_state
 | 
			
		||||
    # lets do something similar here for testing purposes.
 | 
			
		||||
    aasm_enter_initial_state
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def make_activation_code
 | 
			
		||||
    @activation_code = 'moo'
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def do_activate
 | 
			
		||||
    @activated_at = Time.now
 | 
			
		||||
    @activation_code = nil
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def do_delete
 | 
			
		||||
    @deleted_at = Time.now
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def do_undelete
 | 
			
		||||
    @deleted_at = false
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def can_register?
 | 
			
		||||
    true
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def has_activated?
 | 
			
		||||
    !!@activated_at
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def has_activation_code?
 | 
			
		||||
    !!@activation_code
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
class AuthMachineTest < Test::Unit::TestCase
 | 
			
		||||
  context 'authentication state machine' do
 | 
			
		||||
    context 'on initialization' do
 | 
			
		||||
      setup do
 | 
			
		||||
        @auth = AuthMachine.new
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
      should 'be in the pending state' do
 | 
			
		||||
        assert_equal :pending, @auth.aasm_current_state
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
      should 'have an activation code' do
 | 
			
		||||
        assert @auth.has_activation_code?
 | 
			
		||||
        assert_not_nil @auth.activation_code
 | 
			
		||||
      end
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    context 'when being unsuspended' do
 | 
			
		||||
      
 | 
			
		||||
      should 'be able to be unsuspended' do
 | 
			
		||||
        @auth = AuthMachine.new
 | 
			
		||||
        @auth.activate!
 | 
			
		||||
        @auth.suspend!
 | 
			
		||||
        assert @auth.may_unsuspend?
 | 
			
		||||
      end
 | 
			
		||||
      
 | 
			
		||||
      should 'not be able to be unsuspended into active' do
 | 
			
		||||
        @auth = AuthMachine.new
 | 
			
		||||
        @auth.suspend!
 | 
			
		||||
        assert_equal false, @auth.may_unsuspend?(:active)
 | 
			
		||||
      end
 | 
			
		||||
      
 | 
			
		||||
      should 'not be able to be unpassified' do
 | 
			
		||||
        @auth = AuthMachine.new
 | 
			
		||||
        @auth.activate!
 | 
			
		||||
        @auth.suspend!
 | 
			
		||||
        @auth.unsuspend!
 | 
			
		||||
        
 | 
			
		||||
        assert_equal false, @auth.may_unpassify?
 | 
			
		||||
      end
 | 
			
		||||
      
 | 
			
		||||
      should 'be active if previously activated' do
 | 
			
		||||
        @auth = AuthMachine.new
 | 
			
		||||
        @auth.activate!
 | 
			
		||||
        @auth.suspend!
 | 
			
		||||
        @auth.unsuspend!
 | 
			
		||||
 | 
			
		||||
        assert_equal :active, @auth.aasm_current_state
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
      should 'be pending if not previously activated, but an activation code is present' do
 | 
			
		||||
        @auth = AuthMachine.new
 | 
			
		||||
        @auth.suspend!
 | 
			
		||||
        @auth.unsuspend!
 | 
			
		||||
 | 
			
		||||
        assert_equal :pending, @auth.aasm_current_state
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
      should 'be passive if not previously activated and there is no activation code' do
 | 
			
		||||
        @auth = AuthMachine.new
 | 
			
		||||
        @auth.activation_code = nil
 | 
			
		||||
        @auth.suspend!
 | 
			
		||||
        @auth.unsuspend!
 | 
			
		||||
 | 
			
		||||
        assert_equal :passive, @auth.aasm_current_state
 | 
			
		||||
      end
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
| 
						 | 
				
			
			@ -1,43 +0,0 @@
 | 
			
		|||
require 'rubygems'
 | 
			
		||||
require 'bundler'
 | 
			
		||||
begin
 | 
			
		||||
  Bundler.setup(:default, :development)
 | 
			
		||||
rescue Bundler::BundlerError => e
 | 
			
		||||
  $stderr.puts e.message
 | 
			
		||||
  $stderr.puts "Run `bundle install` to install missing gems"
 | 
			
		||||
  exit e.status_code
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
require 'ostruct'
 | 
			
		||||
require 'rubygems'
 | 
			
		||||
 | 
			
		||||
begin
 | 
			
		||||
  gem 'minitest'
 | 
			
		||||
rescue Gem::LoadError
 | 
			
		||||
  puts 'minitest gem not found'
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
begin
 | 
			
		||||
  require 'minitest/autorun'
 | 
			
		||||
  puts 'using minitest'
 | 
			
		||||
rescue LoadError
 | 
			
		||||
  require 'test/unit'
 | 
			
		||||
  puts 'using test/unit'
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
require 'rr'
 | 
			
		||||
require 'shoulda'
 | 
			
		||||
 | 
			
		||||
class Test::Unit::TestCase
 | 
			
		||||
  include RR::Adapters::TestUnit
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
begin
 | 
			
		||||
  require 'ruby-debug'; Debugger.settings[:autoeval] = true; debugger; rubys_debugger = 'annoying'
 | 
			
		||||
  require 'ruby-debug/completion'
 | 
			
		||||
rescue LoadError
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
 | 
			
		||||
$LOAD_PATH.unshift(File.dirname(__FILE__))
 | 
			
		||||
require 'aasm'
 | 
			
		||||
| 
						 | 
				
			
			@ -1,54 +0,0 @@
 | 
			
		|||
require 'test_helper'
 | 
			
		||||
 | 
			
		||||
class EventTest < Test::Unit::TestCase
 | 
			
		||||
  def new_event
 | 
			
		||||
    @event = AASM::SupportingClasses::Event.new(@name, {:success => @success}) do
 | 
			
		||||
      transitions :to => :closed, :from => [:open, :received]
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
  
 | 
			
		||||
  context 'event' do
 | 
			
		||||
    setup do
 | 
			
		||||
      @name = :close_order
 | 
			
		||||
      @success = :success_callback
 | 
			
		||||
    end
 | 
			
		||||
    
 | 
			
		||||
    should 'set the name' do
 | 
			
		||||
      assert_equal @name, new_event.name
 | 
			
		||||
    end
 | 
			
		||||
    
 | 
			
		||||
    should 'set the success option' do
 | 
			
		||||
      assert_equal @success, new_event.success
 | 
			
		||||
    end
 | 
			
		||||
    
 | 
			
		||||
    should 'create StateTransitions' do
 | 
			
		||||
      mock(AASM::SupportingClasses::StateTransition).new({:to => :closed, :from => :open})
 | 
			
		||||
      mock(AASM::SupportingClasses::StateTransition).new({:to => :closed, :from => :received})
 | 
			
		||||
      new_event
 | 
			
		||||
    end
 | 
			
		||||
    
 | 
			
		||||
    context 'when firing' do
 | 
			
		||||
      should 'raise an AASM::InvalidTransition error if the transitions are empty' do
 | 
			
		||||
        event = AASM::SupportingClasses::Event.new(:event)
 | 
			
		||||
        
 | 
			
		||||
        obj = OpenStruct.new
 | 
			
		||||
        obj.aasm_current_state = :open
 | 
			
		||||
        
 | 
			
		||||
        assert_raise AASM::InvalidTransition do
 | 
			
		||||
          event.fire(obj)
 | 
			
		||||
        end
 | 
			
		||||
      end
 | 
			
		||||
      
 | 
			
		||||
      should 'return the state of the first matching transition it finds' do
 | 
			
		||||
        event = AASM::SupportingClasses::Event.new(:event) do
 | 
			
		||||
          transitions :to => :closed, :from => [:open, :received]
 | 
			
		||||
        end
 | 
			
		||||
 | 
			
		||||
        obj = OpenStruct.new
 | 
			
		||||
        obj.aasm_current_state = :open
 | 
			
		||||
 | 
			
		||||
        assert_equal :closed, event.fire(obj)
 | 
			
		||||
      end
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
| 
						 | 
				
			
			@ -1,37 +0,0 @@
 | 
			
		|||
require File.expand_path(File.dirname(__FILE__) + '/../test_helper')
 | 
			
		||||
 | 
			
		||||
class StateMachineTest < Test::Unit::TestCase
 | 
			
		||||
  
 | 
			
		||||
  context "state machines" do
 | 
			
		||||
    
 | 
			
		||||
    should "be created without memory leak" do
 | 
			
		||||
      assert_equal 1, AASM::StateMachine.instance_variable_get("@machines").size  # AuthMachine      
 | 
			
		||||
      assert_number_of_objects AASM::SupportingClasses::State, 5                  # AuthMachine
 | 
			
		||||
      assert_number_of_objects AASM::SupportingClasses::Event, 11                 # AuthMachine
 | 
			
		||||
      assert_number_of_objects AASM::SupportingClasses::StateTransition, 19       # AuthMachine
 | 
			
		||||
      
 | 
			
		||||
      load File.expand_path(File.dirname(__FILE__) + '/../models/process.rb')
 | 
			
		||||
      assert_equal 2, AASM::StateMachine.instance_variable_get("@machines").size  # AuthMachine + Process
 | 
			
		||||
      assert_number_of_objects Models::Process, 0
 | 
			
		||||
      assert_number_of_objects AASM::SupportingClasses::State, 8                  # AuthMachine + Process
 | 
			
		||||
      assert_number_of_objects AASM::SupportingClasses::Event, 13                 # AuthMachine + Process
 | 
			
		||||
      assert_number_of_objects AASM::SupportingClasses::StateTransition, 21       # AuthMachine + Process
 | 
			
		||||
      
 | 
			
		||||
      Models.send(:remove_const, "Process") if Models.const_defined?("Process")
 | 
			
		||||
      load File.expand_path(File.dirname(__FILE__) + '/../models/process.rb')
 | 
			
		||||
      assert_equal 2, AASM::StateMachine.instance_variable_get("@machines").size  # AuthMachine + Process
 | 
			
		||||
      assert_number_of_objects AASM::SupportingClasses::State, 8                  # AuthMachine + Process
 | 
			
		||||
      assert_number_of_objects AASM::SupportingClasses::Event, 13                 # AuthMachine + Process
 | 
			
		||||
      assert_number_of_objects AASM::SupportingClasses::StateTransition, 21       # AuthMachine + Process
 | 
			
		||||
    end
 | 
			
		||||
    
 | 
			
		||||
  end
 | 
			
		||||
  
 | 
			
		||||
  private
 | 
			
		||||
  
 | 
			
		||||
    def assert_number_of_objects(clazz, num)
 | 
			
		||||
      count = ObjectSpace.each_object(clazz) {}
 | 
			
		||||
      assert_equal num, count, "#{num} expected, but we had #{count} #{clazz}"
 | 
			
		||||
    end
 | 
			
		||||
  
 | 
			
		||||
end
 | 
			
		||||
| 
						 | 
				
			
			@ -1,69 +0,0 @@
 | 
			
		|||
require 'test_helper'
 | 
			
		||||
 | 
			
		||||
class StateTest < Test::Unit::TestCase
 | 
			
		||||
  def new_state(options={})
 | 
			
		||||
    AASM::SupportingClasses::State.new(@name, @options.merge(options))
 | 
			
		||||
  end
 | 
			
		||||
  
 | 
			
		||||
  context 'state' do
 | 
			
		||||
    setup do
 | 
			
		||||
      @name = :astate
 | 
			
		||||
      @options = { :crazy_custom_key => 'key' }
 | 
			
		||||
    end
 | 
			
		||||
    
 | 
			
		||||
    should 'set the name' do
 | 
			
		||||
      assert_equal :astate, new_state.name
 | 
			
		||||
    end
 | 
			
		||||
    
 | 
			
		||||
    should 'set the display_name from name' do
 | 
			
		||||
      assert_equal "Astate", new_state.display_name
 | 
			
		||||
    end
 | 
			
		||||
    
 | 
			
		||||
    should 'set the display_name from options' do
 | 
			
		||||
      assert_equal "A State", new_state(:display => "A State").display_name
 | 
			
		||||
    end
 | 
			
		||||
    
 | 
			
		||||
    should 'set the options and expose them as options' do
 | 
			
		||||
      assert_equal @options, new_state.options
 | 
			
		||||
    end
 | 
			
		||||
    
 | 
			
		||||
    should 'equal a symbol of the same name' do
 | 
			
		||||
      assert_equal new_state, :astate
 | 
			
		||||
    end
 | 
			
		||||
    
 | 
			
		||||
    should 'equal a state of the same name' do
 | 
			
		||||
      assert_equal new_state, new_state
 | 
			
		||||
    end
 | 
			
		||||
    
 | 
			
		||||
    should 'send a message to the record for an action if the action is present as a symbol' do
 | 
			
		||||
      state = new_state(:entering => :foo)
 | 
			
		||||
      mock(record = Object.new).foo
 | 
			
		||||
      state.call_action(:entering, record)
 | 
			
		||||
    end
 | 
			
		||||
    
 | 
			
		||||
    should 'send a message to the record for an action if the action is present as a string' do
 | 
			
		||||
      state = new_state(:entering => 'foo')
 | 
			
		||||
      mock(record = Object.new).foo
 | 
			
		||||
      state.call_action(:entering, record)
 | 
			
		||||
    end
 | 
			
		||||
    
 | 
			
		||||
    should 'call a proc with the record as its argument for an action if the action is present as a proc' do
 | 
			
		||||
      state = new_state(:entering => Proc.new {|r| r.foobar})
 | 
			
		||||
      mock(record = Object.new).foobar
 | 
			
		||||
      state.call_action(:entering, record)
 | 
			
		||||
    end
 | 
			
		||||
    
 | 
			
		||||
    should 'send a message to the record for each action if the action is present as an array' do
 | 
			
		||||
      state = new_state(:entering => [:a, :b, 'c', lambda {|r| r.foobar}])
 | 
			
		||||
      
 | 
			
		||||
      record = Object.new
 | 
			
		||||
      mock(record).a
 | 
			
		||||
      mock(record).b
 | 
			
		||||
      mock(record).c
 | 
			
		||||
      mock(record).foobar
 | 
			
		||||
      
 | 
			
		||||
      state.call_action(:entering, record)
 | 
			
		||||
    end
 | 
			
		||||
    
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
| 
						 | 
				
			
			@ -1,75 +0,0 @@
 | 
			
		|||
require 'test_helper'
 | 
			
		||||
 | 
			
		||||
class StateTransitionTest < Test::Unit::TestCase
 | 
			
		||||
  context 'state transition' do
 | 
			
		||||
    setup do
 | 
			
		||||
      @opts = {:from => 'foo', :to => 'bar', :guard => 'g'}
 | 
			
		||||
      @st = AASM::SupportingClasses::StateTransition.new(@opts)
 | 
			
		||||
    end
 | 
			
		||||
    
 | 
			
		||||
    should 'set from, to, and opts attr readers' do
 | 
			
		||||
      assert_equal @opts[:from], @st.from
 | 
			
		||||
      assert_equal @opts[:to], @st.to
 | 
			
		||||
      assert_equal @opts, @st.options
 | 
			
		||||
    end
 | 
			
		||||
    
 | 
			
		||||
    should 'pass equality check if from and to are the same' do
 | 
			
		||||
      obj = OpenStruct.new
 | 
			
		||||
      obj.from = @opts[:from]
 | 
			
		||||
      obj.to = @opts[:to]
 | 
			
		||||
      
 | 
			
		||||
      assert_equal @st, obj
 | 
			
		||||
    end
 | 
			
		||||
    
 | 
			
		||||
    should 'fail equality check if from is not the same' do
 | 
			
		||||
      obj = OpenStruct.new
 | 
			
		||||
      obj.from = 'blah'
 | 
			
		||||
      obj.to = @opts[:to]
 | 
			
		||||
      
 | 
			
		||||
      assert_not_equal @st, obj
 | 
			
		||||
    end
 | 
			
		||||
    
 | 
			
		||||
    should 'fail equality check if to is not the same' do
 | 
			
		||||
      obj = OpenStruct.new
 | 
			
		||||
      obj.from = @opts[:from]
 | 
			
		||||
      obj.to = 'blah'
 | 
			
		||||
      
 | 
			
		||||
      assert_not_equal @st, obj
 | 
			
		||||
    end
 | 
			
		||||
    
 | 
			
		||||
    context 'when performing guard checks' do
 | 
			
		||||
      should 'return true if there is no guard' do
 | 
			
		||||
        opts = {:from => 'foo', :to => 'bar'}
 | 
			
		||||
        st = AASM::SupportingClasses::StateTransition.new(opts)
 | 
			
		||||
        assert st.perform(nil)
 | 
			
		||||
      end
 | 
			
		||||
      
 | 
			
		||||
      should 'call the method on the object if guard is a symbol' do
 | 
			
		||||
        opts = {:from => 'foo', :to => 'bar', :guard => :test_guard}
 | 
			
		||||
        st = AASM::SupportingClasses::StateTransition.new(opts)
 | 
			
		||||
 | 
			
		||||
        mock(obj = Object.new).test_guard
 | 
			
		||||
 | 
			
		||||
        st.perform(obj)
 | 
			
		||||
      end
 | 
			
		||||
      
 | 
			
		||||
      should 'call the method on the object if guard is a string' do
 | 
			
		||||
        opts = {:from => 'foo', :to => 'bar', :guard => 'test_guard'}
 | 
			
		||||
        st = AASM::SupportingClasses::StateTransition.new(opts)
 | 
			
		||||
 | 
			
		||||
        mock(obj = Object.new).test_guard
 | 
			
		||||
 | 
			
		||||
        st.perform(obj)
 | 
			
		||||
      end
 | 
			
		||||
      
 | 
			
		||||
      should 'call the proc passing the object if guard is a proc' do
 | 
			
		||||
        opts = {:from => 'foo', :to => 'bar', :guard => Proc.new {|o| o.test_guard}}
 | 
			
		||||
        st = AASM::SupportingClasses::StateTransition.new(opts)
 | 
			
		||||
 | 
			
		||||
        mock(obj = Object.new).test_guard
 | 
			
		||||
 | 
			
		||||
        st.perform(obj)
 | 
			
		||||
      end 
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue