diff options
author | Sven Fuchs <svenfuchs@artweb-design.de> | 2008-07-16 03:41:11 +0200 |
---|---|---|
committer | Sven Fuchs <svenfuchs@artweb-design.de> | 2008-07-16 03:41:11 +0200 |
commit | 931f366ffcacc0444fcca2fb2e2b44644db9642f (patch) | |
tree | 4c056de1273d23e2b8494cfe452caaeb98ade820 /activemodel/test/state_machine_test.rb | |
parent | 8691e255402b27eae594530001227fc05416a00c (diff) | |
parent | fbef982e4b906b879240a35a1ecff447007da6b2 (diff) | |
download | rails-931f366ffcacc0444fcca2fb2e2b44644db9642f.tar.gz rails-931f366ffcacc0444fcca2fb2e2b44644db9642f.tar.bz2 rails-931f366ffcacc0444fcca2fb2e2b44644db9642f.zip |
merge forward to current rails/master
Diffstat (limited to 'activemodel/test/state_machine_test.rb')
-rw-r--r-- | activemodel/test/state_machine_test.rb | 324 |
1 files changed, 324 insertions, 0 deletions
diff --git a/activemodel/test/state_machine_test.rb b/activemodel/test/state_machine_test.rb new file mode 100644 index 0000000000..b2f0fc4ec0 --- /dev/null +++ b/activemodel/test/state_machine_test.rb @@ -0,0 +1,324 @@ +require File.expand_path(File.join(File.dirname(__FILE__), 'test_helper')) + +class StateMachineSubject + include ActiveModel::StateMachine + + state_machine do + state :open, :exit => :exit + state :closed, :enter => :enter + + event :close, :success => :success_callback do + transitions :to => :closed, :from => [:open] + end + + event :null do + transitions :to => :closed, :from => [:open], :guard => :always_false + end + end + + state_machine :bar do + state :read + state :ended + + event :foo do + transitions :to => :ended, :from => [:read] + end + end + + def always_false + false + end + + def success_callback + end + + def enter + end + def exit + end +end + +class StateMachineSubjectSubclass < StateMachineSubject +end + +class StateMachineClassLevelTest < ActiveModel::TestCase + test 'defines a class level #state_machine method on its including class' do + assert StateMachineSubject.respond_to?(:state_machine) + end + + test 'defines a class level #state_machines method on its including class' do + assert StateMachineSubject.respond_to?(:state_machines) + end + + test 'class level #state_machine returns machine instance' do + assert_kind_of ActiveModel::StateMachine::Machine, StateMachineSubject.state_machine + end + + test 'class level #state_machine returns machine instance with given name' do + assert_kind_of ActiveModel::StateMachine::Machine, StateMachineSubject.state_machine(:default) + end + + test 'class level #state_machines returns hash of machine instances' do + assert_kind_of ActiveModel::StateMachine::Machine, StateMachineSubject.state_machines[:default] + end + + test "should return a select friendly array of states in the form of [['Friendly name', 'state_name']]" do + assert_equal [['Open', 'open'], ['Closed', 'closed']], StateMachineSubject.state_machine.states_for_select + end +end + +class StateMachineInstanceLevelTest < ActiveModel::TestCase + def setup + @foo = StateMachineSubject.new + end + + test 'defines an accessor for the current state' do + assert @foo.respond_to?(:current_state) + end + + test 'defines a state querying instance method on including class' do + assert @foo.respond_to?(:open?) + end + + test 'defines an event! instance method' do + assert @foo.respond_to?(:close!) + end + + test 'defines an event instance method' do + assert @foo.respond_to?(:close) + end +end + +class StateMachineInitialStatesTest < ActiveModel::TestCase + def setup + @foo = StateMachineSubject.new + end + + test 'sets the initial state' do + assert_equal :open, @foo.current_state + end + + test '#open? should be initially true' do + assert @foo.open? + end + + test '#closed? should be initially false' do + assert !@foo.closed? + end + + test 'uses the first state defined if no initial state is given' do + assert_equal :read, @foo.current_state(:bar) + end +end + +class StateMachineEventFiringWithPersistenceTest < ActiveModel::TestCase + def setup + @subj = StateMachineSubject.new + end + + test 'updates the current state' do + @subj.close! + + assert_equal :closed, @subj.current_state + end + + uses_mocha "StateMachineEventFiringWithPersistenceTest with callbacks" do + test 'fires the Event' do + @subj.class.state_machine.events[:close].expects(:fire).with(@subj) + @subj.close! + end + + test 'calls the success callback if one was provided' do + @subj.expects(:success_callback) + @subj.close! + end + + test 'attempts to persist if write_state is defined' do + def @subj.write_state + end + + @subj.expects(:write_state) + @subj.close! + end + end +end + +class StateMachineEventFiringWithoutPersistence < ActiveModel::TestCase + test 'updates the current state' do + subj = StateMachineSubject.new + assert_equal :open, subj.current_state + subj.close + assert_equal :closed, subj.current_state + end + + uses_mocha 'StateMachineEventFiringWithoutPersistence' do + test 'fires the Event' do + subj = StateMachineSubject.new + + StateMachineSubject.state_machine.events[:close].expects(:fire).with(subj) + subj.close + end + + test 'attempts to persist if write_state is defined' do + subj = StateMachineSubject.new + + def subj.write_state + end + + subj.expects(:write_state_without_persistence) + + subj.close + end + end +end + +uses_mocha 'StateMachinePersistenceTest' do + class StateMachinePersistenceTest < ActiveModel::TestCase + test 'reads the state if it has not been set and read_state is defined' do + subj = StateMachineSubject.new + def subj.read_state + end + + subj.expects(:read_state).with(StateMachineSubject.state_machine) + + subj.current_state + end + end +end + +uses_mocha 'StateMachineEventCallbacksTest' do + class StateMachineEventCallbacksTest < ActiveModel::TestCase + test 'should call aasm_event_fired if defined and successful for bang fire' do + subj = StateMachineSubject.new + def subj.aasm_event_fired(from, to) + end + + subj.expects(:event_fired) + + subj.close! + end + + test 'should call aasm_event_fired if defined and successful for non-bang fire' do + subj = StateMachineSubject.new + def subj.aasm_event_fired(from, to) + end + + subj.expects(:event_fired) + + subj.close + end + + test 'should call aasm_event_failed if defined and transition failed for bang fire' do + subj = StateMachineSubject.new + def subj.event_failed(event) + end + + subj.expects(:event_failed) + + subj.null! + end + + test 'should call aasm_event_failed if defined and transition failed for non-bang fire' do + subj = StateMachineSubject.new + def subj.aasm_event_failed(event) + end + + subj.expects(:event_failed) + + subj.null + end + end +end + +uses_mocha 'StateMachineStateActionsTest' do + class StateMachineStateActionsTest < ActiveModel::TestCase + test "calls enter when entering state" do + subj = StateMachineSubject.new + subj.expects(:enter) + subj.close + end + + test "calls exit when exiting state" do + subj = StateMachineSubject.new + subj.expects(:exit) + subj.close + end + end +end + +class StateMachineInheritanceTest < ActiveModel::TestCase + test "has the same states as its parent" do + assert_equal StateMachineSubject.state_machine.states, StateMachineSubjectSubclass.state_machine.states + end + + test "has the same events as its parent" do + assert_equal StateMachineSubject.state_machine.events, StateMachineSubjectSubclass.state_machine.events + end +end + +class StateMachineSubject + state_machine :chetan_patil, :initial => :sleeping do + state :sleeping + state :showering + state :working + state :dating + + event :wakeup do + transitions :from => :sleeping, :to => [:showering, :working] + end + + 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) } + end + end + + def wear_clothes(shirt_color, trouser_type) + end +end + +class StateMachineWithComplexTransitionsTest < ActiveModel::TestCase + def setup + @subj = StateMachineSubject.new + end + + test 'transitions to specified next state (sleeping to showering)' do + @subj.wakeup! :showering + + assert_equal :showering, @subj.current_state(:chetan_patil) + end + + test 'transitions to specified next state (sleeping to working)' do + @subj.wakeup! :working + + assert_equal :working, @subj.current_state(:chetan_patil) + end + + test 'transitions to default (first or showering) state' do + @subj.wakeup! + + assert_equal :showering, @subj.current_state(:chetan_patil) + end + + test 'transitions to default state when on_transition invoked' do + @subj.dress!(nil, 'purple', 'dressy') + + assert_equal :working, @subj.current_state(:chetan_patil) + end + + uses_mocha "StateMachineWithComplexTransitionsTest on_transition tests" do + test 'calls on_transition method with args' do + @subj.wakeup! :showering + + @subj.expects(:wear_clothes).with('blue', 'jeans') + @subj.dress! :working, 'blue', 'jeans' + end + + test 'calls on_transition proc' do + @subj.wakeup! :showering + + @subj.expects(:wear_clothes).with('purple', 'slacks') + @subj.dress!(:dating, 'purple', 'slacks') + end + end +end
\ No newline at end of file |