mirror of
https://github.com/aasm/aasm
synced 2023-03-27 23:22:41 -04:00
more tests
This commit is contained in:
parent
719dadf1ff
commit
206b1991bc
18 changed files with 750 additions and 152 deletions
|
@ -3,7 +3,23 @@
|
|||
## version 4.3
|
||||
|
||||
* add support for multiple state machines per class
|
||||
* check all tests
|
||||
* what happen's if someone accesses `aasm`, but has defined a
|
||||
state machine for `aasm(:my_name)`?
|
||||
* persistence
|
||||
* _ActiveRecord_
|
||||
* _Mongoid_
|
||||
* _MongoMapper_
|
||||
* _Sequel_
|
||||
* documentation
|
||||
* events are chained
|
||||
* :default state machine won't be provided, if state machine name is used
|
||||
* if used raise an error
|
||||
* silence warnings?
|
||||
|
||||
# Changes so far
|
||||
|
||||
## version 4.3
|
||||
|
||||
* add support for multiple state machines per class
|
||||
* class- and instance-level `aasm` methods accept a state machine selector
|
||||
(aka the state machine _name_)
|
||||
* if no selector/name is provided, `:default` will be used
|
||||
* duplicate definitions of states and events will issue warnings
|
||||
|
|
|
@ -67,7 +67,7 @@ module AASM
|
|||
@state_machine.add_state(name, @klass, options)
|
||||
|
||||
if @klass.instance_methods.include?("#{name}?")
|
||||
warn "The state name #{name} is already used!"
|
||||
warn "#{@klass.name}: The state name #{name} is already used!"
|
||||
end
|
||||
|
||||
@klass.class_eval <<-EORUBY, __FILE__, __LINE__ + 1
|
||||
|
@ -86,7 +86,7 @@ module AASM
|
|||
@state_machine.add_event(name, options, &block)
|
||||
|
||||
if @klass.instance_methods.include?("may_#{name}?".to_sym)
|
||||
warn "The event name #{name} is already used!"
|
||||
warn "#{@klass.name}: The event name #{name} is already used!"
|
||||
end
|
||||
|
||||
# an addition over standard aasm so that, before firing an event, you can ask
|
||||
|
|
|
@ -86,3 +86,137 @@ class ComplexExample
|
|||
phrase == :please
|
||||
end
|
||||
end
|
||||
|
||||
class ComplexExampleMultiple
|
||||
include AASM
|
||||
|
||||
attr_accessor :activation_code, :activated_at, :deleted_at
|
||||
|
||||
aasm(:left) do
|
||||
state :passive
|
||||
state :pending, :initial => true, :before_enter => :make_activation_code
|
||||
state :active, :before_enter => :do_activate
|
||||
state :suspended
|
||||
state :deleted, :before_enter => :do_delete#, :exit => :do_undelete
|
||||
state :waiting
|
||||
|
||||
event :left_register do
|
||||
transitions :from => :passive, :to => :pending do
|
||||
guard do
|
||||
can_register?
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
event :left_activate do
|
||||
transitions :from => :pending, :to => :active
|
||||
end
|
||||
|
||||
event :left_suspend do
|
||||
transitions :from => [:passive, :pending, :active], :to => :suspended
|
||||
end
|
||||
|
||||
event :left_delete do
|
||||
transitions :from => [:passive, :pending, :active, :suspended], :to => :deleted
|
||||
end
|
||||
|
||||
# a dummy event that can never happen
|
||||
event :left_unpassify do
|
||||
transitions :from => :passive, :to => :active, :guard => Proc.new {|u| false }
|
||||
end
|
||||
|
||||
event :left_unsuspend do
|
||||
transitions :from => :suspended, :to => :active, :guard => Proc.new { has_activated? }
|
||||
transitions :from => :suspended, :to => :pending, :guard => :has_activation_code?
|
||||
transitions :from => :suspended, :to => :passive
|
||||
end
|
||||
|
||||
event :left_wait do
|
||||
transitions :from => :suspended, :to => :waiting, :guard => :if_polite?
|
||||
end
|
||||
end
|
||||
|
||||
aasm(:right) do
|
||||
state :passive
|
||||
state :pending, :initial => true, :before_enter => :make_activation_code
|
||||
state :active, :before_enter => :do_activate
|
||||
state :suspended
|
||||
state :deleted, :before_enter => :do_delete#, :exit => :do_undelete
|
||||
state :waiting
|
||||
|
||||
event :right_register do
|
||||
transitions :from => :passive, :to => :pending do
|
||||
guard do
|
||||
can_register?
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
event :right_activate do
|
||||
transitions :from => :pending, :to => :active
|
||||
end
|
||||
|
||||
event :right_suspend do
|
||||
transitions :from => [:passive, :pending, :active], :to => :suspended
|
||||
end
|
||||
|
||||
event :right_delete do
|
||||
transitions :from => [:passive, :pending, :active, :suspended], :to => :deleted
|
||||
end
|
||||
|
||||
# a dummy event that can never happen
|
||||
event :right_unpassify do
|
||||
transitions :from => :passive, :to => :active, :guard => Proc.new {|u| false }
|
||||
end
|
||||
|
||||
event :right_unsuspend do
|
||||
transitions :from => :suspended, :to => :active, :guard => Proc.new { has_activated? }
|
||||
transitions :from => :suspended, :to => :pending, :guard => :has_activation_code?
|
||||
transitions :from => :suspended, :to => :passive
|
||||
end
|
||||
|
||||
event :right_wait do
|
||||
transitions :from => :suspended, :to => :waiting, :guard => :if_polite?
|
||||
end
|
||||
end # right
|
||||
|
||||
def initialize
|
||||
# the AR backend uses a before_validate_on_create :aasm_ensure_initial_state
|
||||
# lets do something similar here for testing purposes.
|
||||
aasm(:left).enter_initial_state
|
||||
aasm(:right).enter_initial_state
|
||||
end
|
||||
|
||||
def make_activation_code
|
||||
@activation_code = @activation_code ? @activation_code + '2' : '1'
|
||||
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
|
||||
|
||||
def if_polite?(phrase = nil)
|
||||
phrase == :please
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,133 +0,0 @@
|
|||
class ComplexMultipleExample
|
||||
include AASM
|
||||
|
||||
attr_accessor :activation_code, :activated_at, :deleted_at
|
||||
|
||||
aasm(:left) do
|
||||
state :passive
|
||||
state :pending, :initial => true, :before_enter => :make_activation_code
|
||||
state :active, :before_enter => :do_activate
|
||||
state :suspended
|
||||
state :deleted, :before_enter => :do_delete#, :exit => :do_undelete
|
||||
state :waiting
|
||||
|
||||
event :left_register do
|
||||
transitions :from => :passive, :to => :pending do
|
||||
guard do
|
||||
can_register?
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
event :left_activate do
|
||||
transitions :from => :pending, :to => :active
|
||||
end
|
||||
|
||||
event :left_suspend do
|
||||
transitions :from => [:passive, :pending, :active], :to => :suspended
|
||||
end
|
||||
|
||||
event :left_delete do
|
||||
transitions :from => [:passive, :pending, :active, :suspended], :to => :deleted
|
||||
end
|
||||
|
||||
# a dummy event that can never happen
|
||||
event :left_unpassify do
|
||||
transitions :from => :passive, :to => :active, :guard => Proc.new {|u| false }
|
||||
end
|
||||
|
||||
event :left_unsuspend do
|
||||
transitions :from => :suspended, :to => :active, :guard => Proc.new { has_activated? }
|
||||
transitions :from => :suspended, :to => :pending, :guard => :has_activation_code?
|
||||
transitions :from => :suspended, :to => :passive
|
||||
end
|
||||
|
||||
event :left_wait do
|
||||
transitions :from => :suspended, :to => :waiting, :guard => :if_polite?
|
||||
end
|
||||
end
|
||||
|
||||
aasm(:right) do
|
||||
state :passive
|
||||
state :pending, :initial => true, :before_enter => :make_activation_code
|
||||
state :active, :before_enter => :do_activate
|
||||
state :suspended
|
||||
state :deleted, :before_enter => :do_delete#, :exit => :do_undelete
|
||||
state :waiting
|
||||
|
||||
event :right_register do
|
||||
transitions :from => :passive, :to => :pending do
|
||||
guard do
|
||||
can_register?
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
event :right_activate do
|
||||
transitions :from => :pending, :to => :active
|
||||
end
|
||||
|
||||
event :right_suspend do
|
||||
transitions :from => [:passive, :pending, :active], :to => :suspended
|
||||
end
|
||||
|
||||
event :right_delete do
|
||||
transitions :from => [:passive, :pending, :active, :suspended], :to => :deleted
|
||||
end
|
||||
|
||||
# a dummy event that can never happen
|
||||
event :right_unpassify do
|
||||
transitions :from => :passive, :to => :active, :guard => Proc.new {|u| false }
|
||||
end
|
||||
|
||||
event :right_unsuspend do
|
||||
transitions :from => :suspended, :to => :active, :guard => Proc.new { has_activated? }
|
||||
transitions :from => :suspended, :to => :pending, :guard => :has_activation_code?
|
||||
transitions :from => :suspended, :to => :passive
|
||||
end
|
||||
|
||||
event :right_wait do
|
||||
transitions :from => :suspended, :to => :waiting, :guard => :if_polite?
|
||||
end
|
||||
end # right
|
||||
|
||||
def initialize
|
||||
# the AR backend uses a before_validate_on_create :aasm_ensure_initial_state
|
||||
# lets do something similar here for testing purposes.
|
||||
aasm(:left).enter_initial_state
|
||||
aasm(:right).enter_initial_state
|
||||
end
|
||||
|
||||
def make_activation_code
|
||||
@activation_code = @activation_code ? @activation_code + '2' : '1'
|
||||
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
|
||||
|
||||
def if_polite?(phrase = nil)
|
||||
phrase == :please
|
||||
end
|
||||
end
|
|
@ -34,8 +34,55 @@ class Conversation
|
|||
@persister = persister
|
||||
end
|
||||
|
||||
|
||||
private
|
||||
|
||||
def aasm_read_state
|
||||
@persister.read_state
|
||||
end
|
||||
|
||||
def aasm_write_state(state)
|
||||
@persister.write_state(state)
|
||||
end
|
||||
end
|
||||
|
||||
class ConversationMultiple
|
||||
include AASM
|
||||
|
||||
aasm(:left) do
|
||||
state :needs_attention, :initial => true
|
||||
state :read
|
||||
state :closed
|
||||
state :awaiting_response
|
||||
state :junk
|
||||
|
||||
event :new_message do
|
||||
end
|
||||
|
||||
event :view do
|
||||
transitions :to => :read, :from => [:needs_attention]
|
||||
end
|
||||
|
||||
event :reply do
|
||||
end
|
||||
|
||||
event :close do
|
||||
transitions :to => :closed, :from => [:read, :awaiting_response]
|
||||
end
|
||||
|
||||
event :junk do
|
||||
transitions :to => :junk, :from => [:read]
|
||||
end
|
||||
|
||||
event :unjunk do
|
||||
end
|
||||
end
|
||||
|
||||
def initialize(persister)
|
||||
@persister = persister
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def aasm_read_state
|
||||
@persister.read_state
|
||||
end
|
||||
|
@ -43,5 +90,4 @@ class Conversation
|
|||
def aasm_write_state(state)
|
||||
@persister.write_state(state)
|
||||
end
|
||||
|
||||
end
|
||||
|
|
|
@ -33,3 +33,60 @@ class FooTwo < Foo
|
|||
state :foo
|
||||
end
|
||||
end
|
||||
|
||||
class FooMultiple
|
||||
include AASM
|
||||
|
||||
aasm(:left) do
|
||||
state :open, :initial => true, :before_exit => :before_exit
|
||||
state :closed, :before_enter => :before_enter
|
||||
state :final
|
||||
|
||||
event :close, :success => :success_callback do
|
||||
transitions :from => [:open], :to => [:closed]
|
||||
end
|
||||
|
||||
event :null do
|
||||
transitions :from => [:open], :to => [:closed, :final], :guard => :always_false
|
||||
end
|
||||
end
|
||||
|
||||
aasm(:right, :column => :right) do
|
||||
state :green, :initial => true
|
||||
state :yellow
|
||||
state :red
|
||||
|
||||
event :green do
|
||||
transitions :from => [:yellow], :to => :green
|
||||
end
|
||||
event :yellow do
|
||||
transitions :from => [:green, :red], :to => :yellow
|
||||
end
|
||||
event :red do
|
||||
transitions :from => [:yellow], :to => :red
|
||||
end
|
||||
end
|
||||
|
||||
def always_false
|
||||
false
|
||||
end
|
||||
|
||||
def success_callback
|
||||
end
|
||||
|
||||
def before_enter
|
||||
end
|
||||
def before_exit
|
||||
end
|
||||
end
|
||||
|
||||
class FooTwoMultiple < FooMultiple
|
||||
include AASM
|
||||
aasm(:left) do
|
||||
state :foo
|
||||
end
|
||||
|
||||
aasm(:right) do
|
||||
state :bar
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
class FooMultiple
|
||||
class FooCallbackMultiple
|
||||
include AASM
|
||||
|
||||
aasm(:left) do
|
||||
state :open, :initial => true, :before_exit => :before_exit
|
||||
state :closed, :before_enter => :before_enter
|
||||
|
@ -14,6 +15,22 @@ class FooMultiple
|
|||
end
|
||||
end
|
||||
|
||||
aasm(:right, :column => :right) do
|
||||
state :green, :initial => true
|
||||
state :yellow
|
||||
state :red
|
||||
|
||||
event :green do
|
||||
transitions :from => [:yellow], :to => :green
|
||||
end
|
||||
event :yellow do
|
||||
transitions :from => [:green, :red], :to => :yellow
|
||||
end
|
||||
event :red do
|
||||
transitions :from => [:yellow], :to => :red
|
||||
end
|
||||
end
|
||||
|
||||
def always_false
|
||||
false
|
||||
end
|
||||
|
@ -26,10 +43,3 @@ class FooMultiple
|
|||
def before_exit
|
||||
end
|
||||
end
|
||||
|
||||
class FooTwoMultiple < FooMultiple
|
||||
include AASM
|
||||
aasm(:left) do
|
||||
state :foo
|
||||
end
|
||||
end
|
48
spec/models/guardian_multiple.rb
Normal file
48
spec/models/guardian_multiple.rb
Normal file
|
@ -0,0 +1,48 @@
|
|||
class GuardianMultiple
|
||||
include AASM
|
||||
|
||||
aasm(:left) do
|
||||
state :alpha, :initial => true
|
||||
state :beta
|
||||
|
||||
event :use_one_guard_that_succeeds do
|
||||
transitions :from => :alpha, :to => :beta, :guard => :succeed
|
||||
end
|
||||
event :use_one_guard_that_fails do
|
||||
transitions :from => :alpha, :to => :beta, :guard => :fail
|
||||
end
|
||||
|
||||
event :use_guards_that_succeed do
|
||||
transitions :from => :alpha, :to => :beta, :guards => [:succeed, :another_succeed]
|
||||
end
|
||||
event :use_guards_where_the_first_fails do
|
||||
transitions :from => :alpha, :to => :beta, :guards => [:succeed, :fail]
|
||||
end
|
||||
event :use_guards_where_the_second_fails do
|
||||
transitions :from => :alpha, :to => :beta, :guards => [:fail, :succeed]
|
||||
end
|
||||
|
||||
event :use_event_guards_that_succeed, :guards => [:succeed, :another_succeed] do
|
||||
transitions :from => :alpha, :to => :beta
|
||||
end
|
||||
event :use_event_and_transition_guards_that_succeed, :guards => [:succeed, :another_succeed] do
|
||||
transitions :from => :alpha, :to => :beta, :guards => [:more_succeed]
|
||||
end
|
||||
event :use_event_guards_where_the_first_fails, :guards => [:succeed, :fail] do
|
||||
transitions :from => :alpha, :to => :beta
|
||||
end
|
||||
event :use_event_guards_where_the_second_fails, :guards => [:fail, :succeed] do
|
||||
transitions :from => :alpha, :to => :beta, :guard => :another_succeed
|
||||
end
|
||||
event :use_event_and_transition_guards_where_third_fails, :guards => [:succeed, :another_succeed] do
|
||||
transitions :from => :alpha, :to => :beta, :guards => [:fail]
|
||||
end
|
||||
end
|
||||
|
||||
def fail; false; end
|
||||
|
||||
def succeed; true; end
|
||||
def another_succeed; true; end
|
||||
def more_succeed; true; end
|
||||
|
||||
end
|
|
@ -13,3 +13,19 @@ class InitialStateProc
|
|||
def initialize(balance = 0); self.balance = balance; end
|
||||
def rich?; self.balance >= RICH; end
|
||||
end
|
||||
|
||||
class InitialStateProcMultiple
|
||||
RICH = 1_000_000
|
||||
|
||||
attr_accessor :balance
|
||||
|
||||
include AASM
|
||||
aasm(:left) do
|
||||
state :retired
|
||||
state :selling_bad_mortgages
|
||||
initial_state Proc.new { |banker| banker.rich? ? :retired : :selling_bad_mortgages }
|
||||
end
|
||||
|
||||
def initialize(balance = 0); self.balance = balance; end
|
||||
def rich?; self.balance >= RICH; end
|
||||
end
|
||||
|
|
|
@ -10,3 +10,16 @@ class NoInitialState
|
|||
end
|
||||
end
|
||||
end
|
||||
|
||||
class NoInitialStateMultiple
|
||||
include AASM
|
||||
|
||||
aasm(:left) do
|
||||
state :read
|
||||
state :ended
|
||||
|
||||
event :foo do
|
||||
transitions :to => :ended, :from => [:read]
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
29
spec/models/parametrised_event_multiple.rb
Normal file
29
spec/models/parametrised_event_multiple.rb
Normal file
|
@ -0,0 +1,29 @@
|
|||
class ParametrisedEventMultiple
|
||||
include AASM
|
||||
aasm(:left) do
|
||||
state :sleeping, :initial => true
|
||||
state :showering
|
||||
state :working
|
||||
state :dating
|
||||
state :prettying_up
|
||||
|
||||
event :wakeup do
|
||||
transitions :from => :sleeping, :to => [:showering, :working]
|
||||
end
|
||||
|
||||
event :dress do
|
||||
transitions :from => :sleeping, :to => :working, :after => :wear_clothes
|
||||
transitions :from => :showering, :to => [:working, :dating], :after => Proc.new { |*args| wear_clothes(*args) }
|
||||
transitions :from => :showering, :to => :prettying_up, :after => [:condition_hair, :fix_hair]
|
||||
end
|
||||
end
|
||||
|
||||
def wear_clothes(shirt_color, trouser_type=nil)
|
||||
end
|
||||
|
||||
def condition_hair
|
||||
end
|
||||
|
||||
def fix_hair
|
||||
end
|
||||
end
|
|
@ -9,3 +9,15 @@ class ValidStateName
|
|||
end
|
||||
end
|
||||
end
|
||||
|
||||
class ValidStateNameMultiple
|
||||
include AASM
|
||||
aasm(:left) do
|
||||
state :invalid, :initial => true
|
||||
state :valid
|
||||
|
||||
event :valid do
|
||||
transitions :to => :valid, :from => [:invalid]
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -185,7 +185,7 @@ end # callbacks for the new DSL
|
|||
describe 'event callbacks' do
|
||||
describe "with an error callback defined" do
|
||||
before do
|
||||
class FooMultiple
|
||||
class FooCallbackMultiple
|
||||
# this hack is needed to allow testing of parameters, since RSpec
|
||||
# destroys a method's arity when mocked
|
||||
attr_accessor :data
|
||||
|
@ -197,7 +197,7 @@ describe 'event callbacks' do
|
|||
end
|
||||
end
|
||||
|
||||
@foo = FooMultiple.new
|
||||
@foo = FooCallbackMultiple.new
|
||||
end
|
||||
|
||||
context "error_callback defined" do
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
require 'spec_helper'
|
||||
|
||||
describe 'on initialization' do
|
||||
let(:auth) {ComplexMultipleExample.new}
|
||||
let(:auth) {ComplexExampleMultiple.new}
|
||||
|
||||
it 'should be in the pending state' do
|
||||
expect(auth.aasm(:left).current_state).to eq(:pending)
|
||||
|
@ -15,7 +15,7 @@ describe 'on initialization' do
|
|||
end
|
||||
|
||||
describe 'when being unsuspended' do
|
||||
let(:auth) {ComplexMultipleExample.new}
|
||||
let(:auth) {ComplexExampleMultiple.new}
|
||||
|
||||
it 'should be able to unsuspend' do
|
||||
auth.left_activate!
|
||||
|
|
73
spec/unit/event_multiple_spec.rb
Normal file
73
spec/unit/event_multiple_spec.rb
Normal file
|
@ -0,0 +1,73 @@
|
|||
require 'spec_helper'
|
||||
|
||||
describe 'current event' do
|
||||
let(:pe) {ParametrisedEventMultiple.new}
|
||||
|
||||
it 'if no event has been triggered' do
|
||||
expect(pe.aasm(:left).current_event).to be_nil
|
||||
end
|
||||
|
||||
it 'if a event has been triggered' do
|
||||
pe.wakeup
|
||||
expect(pe.aasm(:left).current_event).to eql :wakeup
|
||||
end
|
||||
|
||||
it 'if no event has been triggered' do
|
||||
pe.wakeup!
|
||||
expect(pe.aasm(:left).current_event).to eql :wakeup!
|
||||
end
|
||||
end
|
||||
|
||||
describe 'parametrised events' do
|
||||
let(:pe) {ParametrisedEventMultiple.new}
|
||||
|
||||
it 'should transition to specified next state (sleeping to showering)' do
|
||||
pe.wakeup!(:showering)
|
||||
expect(pe.aasm(:left).current_state).to eq(:showering)
|
||||
end
|
||||
|
||||
it 'should transition to specified next state (sleeping to working)' do
|
||||
pe.wakeup!(:working)
|
||||
expect(pe.aasm(:left).current_state).to eq(:working)
|
||||
end
|
||||
|
||||
it 'should transition to default (first or showering) state' do
|
||||
pe.wakeup!
|
||||
expect(pe.aasm(:left).current_state).to eq(:showering)
|
||||
end
|
||||
|
||||
it 'should transition to default state when :after transition invoked' do
|
||||
pe.dress!(nil, 'purple', 'dressy')
|
||||
expect(pe.aasm(:left).current_state).to eq(:working)
|
||||
end
|
||||
|
||||
it 'should call :after transition method with args' do
|
||||
pe.wakeup!(:showering)
|
||||
expect(pe).to receive(:wear_clothes).with('blue', 'jeans')
|
||||
pe.dress!(:working, 'blue', 'jeans')
|
||||
end
|
||||
|
||||
it 'should call :after transition proc' do
|
||||
pe.wakeup!(:showering)
|
||||
expect(pe).to receive(:wear_clothes).with('purple', 'slacks')
|
||||
pe.dress!(:dating, 'purple', 'slacks')
|
||||
end
|
||||
|
||||
it 'should call :after transition with an array of methods' do
|
||||
pe.wakeup!(:showering)
|
||||
expect(pe).to receive(:condition_hair)
|
||||
expect(pe).to receive(:fix_hair)
|
||||
pe.dress!(:prettying_up)
|
||||
end
|
||||
end
|
||||
|
||||
describe 'event firing without persistence' do
|
||||
it 'should attempt to persist if aasm_write_state is defined' do
|
||||
foo = Foo.new
|
||||
def foo.aasm_write_state; end
|
||||
expect(foo).to be_open
|
||||
|
||||
expect(foo).to receive(:aasm_write_state_without_persistence)
|
||||
foo.close
|
||||
end
|
||||
end
|
60
spec/unit/guard_multiple_spec.rb
Normal file
60
spec/unit/guard_multiple_spec.rb
Normal file
|
@ -0,0 +1,60 @@
|
|||
require 'spec_helper'
|
||||
|
||||
describe "per-transition guards" do
|
||||
let(:guardian) { GuardianMultiple.new }
|
||||
|
||||
it "allows the transition if the guard succeeds" do
|
||||
expect { guardian.use_one_guard_that_succeeds! }.to_not raise_error
|
||||
expect(guardian).to be_beta
|
||||
end
|
||||
|
||||
it "stops the transition if the guard fails" do
|
||||
expect { guardian.use_one_guard_that_fails! }.to raise_error(AASM::InvalidTransition)
|
||||
expect(guardian).to be_alpha
|
||||
end
|
||||
|
||||
it "allows the transition if all guards succeeds" do
|
||||
expect { guardian.use_guards_that_succeed! }.to_not raise_error
|
||||
expect(guardian).to be_beta
|
||||
end
|
||||
|
||||
it "stops the transition if the first guard fails" do
|
||||
expect { guardian.use_guards_where_the_first_fails! }.to raise_error(AASM::InvalidTransition)
|
||||
expect(guardian).to be_alpha
|
||||
end
|
||||
|
||||
it "stops the transition if the second guard fails" do
|
||||
expect { guardian.use_guards_where_the_second_fails! }.to raise_error(AASM::InvalidTransition)
|
||||
expect(guardian).to be_alpha
|
||||
end
|
||||
end
|
||||
|
||||
describe "event guards" do
|
||||
let(:guardian) { GuardianMultiple.new }
|
||||
|
||||
it "allows the transition if the event guards succeed" do
|
||||
expect { guardian.use_event_guards_that_succeed! }.to_not raise_error
|
||||
expect(guardian).to be_beta
|
||||
end
|
||||
|
||||
it "allows the transition if the event and transition guards succeed" do
|
||||
expect { guardian.use_event_and_transition_guards_that_succeed! }.to_not raise_error
|
||||
expect(guardian).to be_beta
|
||||
end
|
||||
|
||||
it "stops the transition if the first event guard fails" do
|
||||
expect { guardian.use_event_guards_where_the_first_fails! }.to raise_error(AASM::InvalidTransition)
|
||||
expect(guardian).to be_alpha
|
||||
end
|
||||
|
||||
it "stops the transition if the second event guard fails" do
|
||||
expect { guardian.use_event_guards_where_the_second_fails! }.to raise_error(AASM::InvalidTransition)
|
||||
expect(guardian).to be_alpha
|
||||
end
|
||||
|
||||
it "stops the transition if the transition guard fails" do
|
||||
expect { guardian.use_event_and_transition_guards_where_third_fails! }.to raise_error(AASM::InvalidTransition)
|
||||
expect(guardian).to be_alpha
|
||||
end
|
||||
|
||||
end
|
15
spec/unit/initial_state_multiple_spec.rb
Normal file
15
spec/unit/initial_state_multiple_spec.rb
Normal file
|
@ -0,0 +1,15 @@
|
|||
require 'spec_helper'
|
||||
|
||||
describe 'initial states' do
|
||||
it 'should use the first state defined if no initial state is given' do
|
||||
expect(NoInitialStateMultiple.new.aasm(:left).current_state).to eq(:read)
|
||||
end
|
||||
|
||||
it 'should determine initial state from the Proc results' do
|
||||
balance = InitialStateProcMultiple::RICH - 1
|
||||
expect(InitialStateProcMultiple.new(balance).aasm(:left).current_state).to eq(:selling_bad_mortgages)
|
||||
|
||||
balance = InitialStateProcMultiple::RICH + 1
|
||||
expect(InitialStateProcMultiple.new(balance).aasm(:left).current_state).to eq(:retired)
|
||||
end
|
||||
end
|
202
spec/unit/inspection_multiple_spec.rb
Normal file
202
spec/unit/inspection_multiple_spec.rb
Normal file
|
@ -0,0 +1,202 @@
|
|||
require 'spec_helper'
|
||||
|
||||
describe 'inspection for common cases' do
|
||||
it 'should support the new DSL' do
|
||||
# 1st state machine
|
||||
expect(FooMultiple.aasm(:left)).to respond_to(:states)
|
||||
expect(FooMultiple.aasm(:left).states.size).to eql 3
|
||||
expect(FooMultiple.aasm(:left).states).to include(:open)
|
||||
expect(FooMultiple.aasm(:left).states).to include(:closed)
|
||||
expect(FooMultiple.aasm(:left).states).to include(:final)
|
||||
|
||||
expect(FooMultiple.aasm(:left)).to respond_to(:initial_state)
|
||||
expect(FooMultiple.aasm(:left).initial_state).to eq(:open)
|
||||
|
||||
expect(FooMultiple.aasm(:left)).to respond_to(:events)
|
||||
puts FooMultiple.aasm(:left).events.map(&:name).inspect
|
||||
expect(FooMultiple.aasm(:left).events.size).to eql 2
|
||||
expect(FooMultiple.aasm(:left).events).to include(:close)
|
||||
expect(FooMultiple.aasm(:left).events).to include(:null)
|
||||
|
||||
# 2nd state machine
|
||||
expect(FooMultiple.aasm(:right)).to respond_to(:states)
|
||||
expect(FooMultiple.aasm(:right).states.size).to eql 3
|
||||
expect(FooMultiple.aasm(:right).states).to include(:green)
|
||||
expect(FooMultiple.aasm(:right).states).to include(:yellow)
|
||||
expect(FooMultiple.aasm(:right).states).to include(:red)
|
||||
|
||||
expect(FooMultiple.aasm(:right)).to respond_to(:initial_state)
|
||||
expect(FooMultiple.aasm(:right).initial_state).to eq(:green)
|
||||
|
||||
expect(FooMultiple.aasm(:right)).to respond_to(:events)
|
||||
expect(FooMultiple.aasm(:right).events.size).to eql 3
|
||||
expect(FooMultiple.aasm(:right).events).to include(:green)
|
||||
expect(FooMultiple.aasm(:right).events).to include(:yellow)
|
||||
expect(FooMultiple.aasm(:right).events).to include(:red)
|
||||
end
|
||||
|
||||
context "instance level inspection" do
|
||||
let(:foo) { FooMultiple.new }
|
||||
let(:two) { FooTwoMultiple.new }
|
||||
|
||||
it "delivers all states" do
|
||||
# 1st state machine
|
||||
states = foo.aasm(:left).states
|
||||
expect(states.size).to eql 3
|
||||
expect(states).to include(:open)
|
||||
expect(states).to include(:closed)
|
||||
expect(states).to include(:final)
|
||||
|
||||
states = foo.aasm(:left).states(:permitted => true)
|
||||
expect(states.size).to eql 1
|
||||
expect(states).to include(:closed)
|
||||
expect(states).not_to include(:open)
|
||||
expect(states).not_to include(:final)
|
||||
|
||||
foo.close
|
||||
expect(foo.aasm(:left).states(:permitted => true)).to be_empty
|
||||
|
||||
# 2nd state machine
|
||||
states = foo.aasm(:right).states
|
||||
expect(states.size).to eql 3
|
||||
expect(states).to include(:green)
|
||||
expect(states).to include(:yellow)
|
||||
expect(states).to include(:red)
|
||||
|
||||
states = foo.aasm(:right).states(:permitted => true)
|
||||
expect(states.size).to eql 1
|
||||
expect(states).to include(:yellow)
|
||||
expect(states).not_to include(:green)
|
||||
expect(states).not_to include(:red)
|
||||
|
||||
foo.yellow
|
||||
states = foo.aasm(:right).states(:permitted => true)
|
||||
expect(states.size).to eql 2
|
||||
expect(states).to include(:red)
|
||||
expect(states).to include(:green)
|
||||
expect(states).not_to include(:yellow)
|
||||
end
|
||||
|
||||
it "delivers all states for subclasses" do
|
||||
# 1st state machine
|
||||
states = two.aasm(:left).states
|
||||
expect(states.size).to eql 4
|
||||
expect(states).to include(:open)
|
||||
expect(states).to include(:closed)
|
||||
expect(states).to include(:final)
|
||||
expect(states).to include(:foo)
|
||||
|
||||
states = two.aasm(:left).states(:permitted => true)
|
||||
expect(states.size).to eql 1
|
||||
expect(states).to include(:closed)
|
||||
expect(states).not_to include(:open)
|
||||
|
||||
two.close
|
||||
expect(two.aasm(:left).states(:permitted => true)).to be_empty
|
||||
|
||||
# 2nd state machine
|
||||
states = two.aasm(:right).states
|
||||
expect(states.size).to eql 4
|
||||
expect(states).to include(:green)
|
||||
expect(states).to include(:yellow)
|
||||
expect(states).to include(:red)
|
||||
expect(states).to include(:bar)
|
||||
|
||||
states = two.aasm(:right).states(:permitted => true)
|
||||
expect(states.size).to eql 1
|
||||
expect(states).to include(:yellow)
|
||||
expect(states).not_to include(:red)
|
||||
expect(states).not_to include(:green)
|
||||
expect(states).not_to include(:bar)
|
||||
|
||||
two.yellow
|
||||
states = two.aasm(:right).states(:permitted => true)
|
||||
expect(states.size).to eql 2
|
||||
expect(states).to include(:green)
|
||||
expect(states).to include(:red)
|
||||
expect(states).not_to include(:yellow)
|
||||
expect(states).not_to include(:bar)
|
||||
end
|
||||
|
||||
it "delivers all events" do
|
||||
# 1st state machine
|
||||
events = foo.aasm(:left).events
|
||||
expect(events.size).to eql 2
|
||||
expect(events).to include(:close)
|
||||
expect(events).to include(:null)
|
||||
|
||||
foo.close
|
||||
expect(foo.aasm(:left).events).to be_empty
|
||||
|
||||
# 2nd state machine
|
||||
events = foo.aasm(:right).events
|
||||
expect(events.size).to eql 1
|
||||
expect(events).to include(:yellow)
|
||||
expect(events).not_to include(:green)
|
||||
expect(events).not_to include(:red)
|
||||
|
||||
foo.yellow
|
||||
events = foo.aasm(:right).events
|
||||
expect(events.size).to eql 2
|
||||
expect(events).to include(:green)
|
||||
expect(events).to include(:red)
|
||||
expect(events).not_to include(:yellow)
|
||||
end
|
||||
end
|
||||
|
||||
it 'should list states in the order they have been defined' do
|
||||
expect(ConversationMultiple.aasm(:left).states).to eq([
|
||||
:needs_attention, :read, :closed, :awaiting_response, :junk
|
||||
])
|
||||
end
|
||||
end
|
||||
|
||||
describe "special cases" do
|
||||
it "should support valid as state name" do
|
||||
expect(ValidStateNameMultiple.aasm(:left).states).to include(:invalid)
|
||||
expect(ValidStateNameMultiple.aasm(:left).states).to include(:valid)
|
||||
|
||||
argument = ValidStateNameMultiple.new
|
||||
expect(argument.invalid?).to be_truthy
|
||||
expect(argument.aasm(:left).current_state).to eq(:invalid)
|
||||
|
||||
argument.valid!
|
||||
expect(argument.valid?).to be_truthy
|
||||
expect(argument.aasm(:left).current_state).to eq(:valid)
|
||||
end
|
||||
end
|
||||
|
||||
describe 'aasm.states_for_select' do
|
||||
it "should return a select friendly array of states" do
|
||||
expect(FooMultiple.aasm(:left)).to respond_to(:states_for_select)
|
||||
expect(FooMultiple.aasm(:left).states_for_select).to eq(
|
||||
[['Open', 'open'], ['Closed', 'closed'], ['Final', 'final']]
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
describe 'aasm.from_states_for_state' do
|
||||
it "should return all from states for a state" do
|
||||
expect(ComplexExampleMultiple.aasm(:left)).to respond_to(:from_states_for_state)
|
||||
froms = ComplexExampleMultiple.aasm(:left).from_states_for_state(:active)
|
||||
[:pending, :passive, :suspended].each {|from| expect(froms).to include(from)}
|
||||
end
|
||||
|
||||
it "should return from states for a state for a particular transition only" do
|
||||
froms = ComplexExampleMultiple.aasm(:left).from_states_for_state(:active, :transition => :left_unsuspend)
|
||||
[:suspended].each {|from| expect(froms).to include(from)}
|
||||
end
|
||||
end
|
||||
|
||||
describe 'permitted events' do
|
||||
let(:foo) {FooMultiple.new}
|
||||
|
||||
it 'work' do
|
||||
expect(foo.aasm(:left).events(:permitted => true)).to include(:close)
|
||||
expect(foo.aasm(:left).events(:permitted => true)).not_to include(:null)
|
||||
|
||||
expect(foo.aasm(:right).events(:permitted => true)).to include(:yellow)
|
||||
expect(foo.aasm(:right).events(:permitted => true)).not_to include(:green)
|
||||
expect(foo.aasm(:right).events(:permitted => true)).not_to include(:red)
|
||||
end
|
||||
end
|
Loading…
Add table
Reference in a new issue