1 // Copyright 2010 Christophe Henry 2 // henry UNDERSCORE christophe AT hotmail DOT com 3 // This is an extended version of the state machine available in the boost::mpl library 4 // Distributed under the same license as the original. 5 // Copyright for the original version: 6 // Copyright 2005 David Abrahams and Aleksey Gurtovoy. Distributed 7 // under the Boost Software License, Version 1.0. (See accompanying 8 // file LICENSE_1_0.txt or copy at 9 // http://www.boost.org/LICENSE_1_0.txt) 10 11 #include <iostream> 12 // back-end 13 #include <boost/msm/back/state_machine.hpp> 14 #include <boost/msm/front/euml/euml.hpp> 15 16 #ifndef BOOST_MSM_NONSTANDALONE_TEST 17 #define BOOST_TEST_MODULE MyTest 18 #endif 19 #include <boost/test/unit_test.hpp> 20 21 namespace msm = boost::msm; 22 using namespace boost::msm::front::euml; 23 24 namespace 25 { 26 // events 27 BOOST_MSM_EUML_EVENT(event1) 28 29 // The list of FSM states BOOST_MSM_EUML_DECLARE_ATTRIBUTE(unsigned int,entry_counter)30 BOOST_MSM_EUML_DECLARE_ATTRIBUTE(unsigned int,entry_counter) 31 BOOST_MSM_EUML_DECLARE_ATTRIBUTE(unsigned int,exit_counter) 32 33 BOOST_MSM_EUML_STATE(( ++state_(entry_counter),++state_(exit_counter),attributes_ << entry_counter << exit_counter),State1) 34 BOOST_MSM_EUML_STATE(( ++state_(entry_counter),++state_(exit_counter),attributes_ << entry_counter << exit_counter),State2) 35 BOOST_MSM_EUML_STATE(( ++state_(entry_counter),++state_(exit_counter),attributes_ << entry_counter << exit_counter),State3) 36 BOOST_MSM_EUML_STATE(( ++state_(entry_counter),++state_(exit_counter),attributes_ << entry_counter << exit_counter),State4) 37 38 BOOST_MSM_EUML_DECLARE_ATTRIBUTE(unsigned int,state2_to_state3_counter) 39 BOOST_MSM_EUML_DECLARE_ATTRIBUTE(unsigned int,state3_to_state4_counter) 40 BOOST_MSM_EUML_DECLARE_ATTRIBUTE(unsigned int,always_true_counter) 41 BOOST_MSM_EUML_DECLARE_ATTRIBUTE(unsigned int,always_false_counter) 42 43 // transition actions 44 BOOST_MSM_EUML_ACTION(State2ToState3) 45 { 46 template <class FSM,class EVT,class SourceState,class TargetState> 47 void operator()(EVT const& ,FSM& fsm,SourceState& ,TargetState& ) 48 { 49 ++fsm.get_attribute(state2_to_state3_counter); 50 } 51 }; BOOST_MSM_EUML_ACTION(State3ToState4)52 BOOST_MSM_EUML_ACTION(State3ToState4) 53 { 54 template <class FSM,class EVT,class SourceState,class TargetState> 55 void operator()(EVT const& ,FSM& fsm,SourceState& ,TargetState& ) 56 { 57 ++fsm.get_attribute(state3_to_state4_counter); 58 } 59 }; 60 // guard conditions BOOST_MSM_EUML_ACTION(always_true)61 BOOST_MSM_EUML_ACTION(always_true) 62 { 63 template <class FSM,class EVT,class SourceState,class TargetState> 64 bool operator()(EVT const&,FSM& fsm,SourceState& ,TargetState& ) 65 { 66 ++fsm.get_attribute(always_true_counter); 67 return true; 68 } 69 }; BOOST_MSM_EUML_ACTION(always_false)70 BOOST_MSM_EUML_ACTION(always_false) 71 { 72 template <class FSM,class EVT,class SourceState,class TargetState> 73 bool operator()(EVT const&,FSM& fsm,SourceState& ,TargetState& ) 74 { 75 ++fsm.get_attribute(always_false_counter); 76 return false; 77 } 78 }; 79 BOOST_MSM_EUML_ACTION(No_Transition)80 BOOST_MSM_EUML_ACTION(No_Transition) 81 { 82 template <class FSM,class Event> 83 void operator()(Event const&,FSM&,int) 84 { 85 BOOST_FAIL("no_transition called!"); 86 } 87 }; 88 89 BOOST_MSM_EUML_TRANSITION_TABLE(( 90 State2 == State1 , 91 State3 == State2 / State2ToState3, 92 State4 == State3 [always_true] / State3ToState4, 93 State4 == State3 [always_false], 94 State1 == State4 + event1 95 // +------------------------------------------------------------------------------+ 96 ),transition_table) 97 98 // create a state machine "on the fly" 99 BOOST_MSM_EUML_DECLARE_STATE_MACHINE(( transition_table, //STT 100 init_ << State1, // Init State 101 no_action, // Entry 102 no_action, // Exit 103 attributes_ << state2_to_state3_counter << state3_to_state4_counter 104 << always_true_counter << always_false_counter, // Attributes 105 configure_ << no_configure_, // configuration 106 No_Transition // no_transition handler 107 ), 108 my_machine_) //fsm name 109 110 // Pick a back-end 111 typedef msm::back::state_machine<my_machine_> my_machine; 112 113 //static char const* const state_names[] = { "State1", "State2", "State3", "State4" }; 114 BOOST_AUTO_TEST_CASE(my_test)115 BOOST_AUTO_TEST_CASE( my_test ) 116 { 117 my_machine p; 118 119 // needed to start the highest-level SM. This will call on_entry and mark the start of the SM 120 // in this case it will also immediately trigger all anonymous transitions 121 p.start(); 122 BOOST_CHECK_MESSAGE(p.current_state()[0] == 3,"State4 should be active"); //State4 123 BOOST_CHECK_MESSAGE(p.get_state<BOOST_MSM_EUML_STATE_NAME(State1)&>().get_attribute(exit_counter) == 1, 124 "State1 exit not called correctly"); 125 BOOST_CHECK_MESSAGE(p.get_state<BOOST_MSM_EUML_STATE_NAME(State1)&>().get_attribute(entry_counter) == 1, 126 "State1 entry not called correctly"); 127 BOOST_CHECK_MESSAGE(p.get_state<BOOST_MSM_EUML_STATE_NAME(State2)&>().get_attribute(exit_counter) == 1, 128 "State2 exit not called correctly"); 129 BOOST_CHECK_MESSAGE(p.get_state<BOOST_MSM_EUML_STATE_NAME(State2)&>().get_attribute(entry_counter) == 1, 130 "State2 entry not called correctly"); 131 BOOST_CHECK_MESSAGE(p.get_state<BOOST_MSM_EUML_STATE_NAME(State3)&>().get_attribute(exit_counter) == 1, 132 "State3 exit not called correctly"); 133 BOOST_CHECK_MESSAGE(p.get_state<BOOST_MSM_EUML_STATE_NAME(State3)&>().get_attribute(entry_counter) == 1, 134 "State3 entry not called correctly"); 135 BOOST_CHECK_MESSAGE(p.get_state<BOOST_MSM_EUML_STATE_NAME(State4)&>().get_attribute(entry_counter)== 1, 136 "State4 entry not called correctly"); 137 BOOST_CHECK_MESSAGE(p.get_attribute(always_true_counter) == 1,"guard not called correctly"); 138 BOOST_CHECK_MESSAGE(p.get_attribute(always_false_counter) == 1,"guard not called correctly"); 139 BOOST_CHECK_MESSAGE(p.get_attribute(state2_to_state3_counter) == 1,"action not called correctly"); 140 BOOST_CHECK_MESSAGE(p.get_attribute(state3_to_state4_counter) == 1,"action not called correctly"); 141 142 143 // this event will bring us back to the initial state and thus, a new "loop" will be started 144 p.process_event(event1); 145 BOOST_CHECK_MESSAGE(p.current_state()[0] == 3,"State4 should be active"); //State4 146 BOOST_CHECK_MESSAGE(p.get_state<BOOST_MSM_EUML_STATE_NAME(State1)&>().get_attribute(exit_counter) == 2, 147 "State1 exit not called correctly"); 148 BOOST_CHECK_MESSAGE(p.get_state<BOOST_MSM_EUML_STATE_NAME(State1)&>().get_attribute(entry_counter) == 2, 149 "State1 entry not called correctly"); 150 BOOST_CHECK_MESSAGE(p.get_state<BOOST_MSM_EUML_STATE_NAME(State2)&>().get_attribute(exit_counter) == 2, 151 "State2 exit not called correctly"); 152 BOOST_CHECK_MESSAGE(p.get_state<BOOST_MSM_EUML_STATE_NAME(State2)&>().get_attribute(entry_counter) == 2, 153 "State2 entry not called correctly"); 154 BOOST_CHECK_MESSAGE(p.get_state<BOOST_MSM_EUML_STATE_NAME(State3)&>().get_attribute(exit_counter) == 2, 155 "State3 exit not called correctly"); 156 BOOST_CHECK_MESSAGE(p.get_state<BOOST_MSM_EUML_STATE_NAME(State3)&>().get_attribute(entry_counter) == 2, 157 "State3 entry not called correctly"); 158 BOOST_CHECK_MESSAGE(p.get_state<BOOST_MSM_EUML_STATE_NAME(State4)&>().get_attribute(entry_counter)== 2, 159 "State4 entry not called correctly"); 160 BOOST_CHECK_MESSAGE(p.get_attribute(always_true_counter) == 2,"guard not called correctly"); 161 BOOST_CHECK_MESSAGE(p.get_attribute(always_false_counter) == 2,"guard not called correctly"); 162 BOOST_CHECK_MESSAGE(p.get_attribute(state2_to_state3_counter) == 2,"action not called correctly"); 163 BOOST_CHECK_MESSAGE(p.get_attribute(state3_to_state4_counter) == 2,"action not called correctly"); 164 165 } 166 } 167 168