require 'test_helper'

class Water
  attr_accessor(:state_of_material)
  include FSM
  define_fsm do
    # now define all the states
    # you can add :enter / :exit callbacks (callback can be a String, Symbol or Proc)
    # these callbacks are triggered on any transition from/to this state and do not receive any arguments
    state(:gas)
    state(:liquid)
    state(:solid, :enter => :on_enter_solid, :exit => :on_exit_solid)
    
    # define all valid transitions (name, from, to). This will define a method with the given name.
    # you can define :event callback which is called only on this transition and receives the arguments passed to the
    # transition method
    transition(:heat_up, :solid, :liquid)
    transition(:heat_up, :liquid, :gas)
    transition(:cool_down, :gas, :liquid)
    transition(:cool_down, :liquid, :solid)
    
    # define the attribute which is used to store the state (defaults to :state)
    state_attribute(:state_of_material)
    
    # define the initial state (defaults to the first state defined - :gas in this sample)
    initial(:solid)
  end
  private
  def on_enter_solid()
  end
  def on_exit_solid()
  end
end

class WaterSampleTest < Test::Unit::TestCase
  context 'Water' do
    
    should 'cycle through material states' do
      w = Water.new
      assert_equal(:solid, w.state_of_material)
      w.heat_up
      assert_equal(:liquid, w.state_of_material)
      w.heat_up
      assert_equal(:gas, w.state_of_material)
      w.cool_down
      assert_equal(:liquid, w.state_of_material)
      w.cool_down
      assert_equal(:solid, w.state_of_material)
      
      assert_raise(FSM::InvalidStateTransition) do
        w.cool_down
      end
    end
  
  end
end