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 //front-end 15 #include <boost/msm/front/state_machine_def.hpp> 16 17 #ifndef BOOST_MSM_NONSTANDALONE_TEST 18 #define BOOST_TEST_MODULE MyTest 19 #endif 20 #include <boost/test/unit_test.hpp> 21 22 namespace msm = boost::msm; 23 namespace mpl = boost::mpl; 24 using namespace boost::msm::front; 25 26 namespace 27 { 28 // events 29 struct event1 {}; 30 31 32 // front-end: define the FSM structure 33 struct my_machine_ : public msm::front::state_machine_def<my_machine_> 34 { 35 unsigned int state2_to_state3_counter; 36 unsigned int state3_to_state4_counter; 37 unsigned int always_true_counter; 38 unsigned int always_false_counter; 39 my_machine___anon26599a780111::my_machine_40 my_machine_(): 41 state2_to_state3_counter(0), 42 state3_to_state4_counter(0), 43 always_true_counter(0), 44 always_false_counter(0) 45 {} 46 47 // The list of FSM states 48 struct State1 : public msm::front::state<> 49 { 50 template <class Event,class FSM> on_entry__anon26599a780111::my_machine_::State151 void on_entry(Event const&,FSM& ) {++entry_counter;} 52 template <class Event,class FSM> on_exit__anon26599a780111::my_machine_::State153 void on_exit(Event const&,FSM& ) {++exit_counter;} 54 int entry_counter; 55 int exit_counter; 56 }; 57 struct State2 : public msm::front::state<> 58 { 59 template <class Event,class FSM> on_entry__anon26599a780111::my_machine_::State260 void on_entry(Event const&,FSM& ) {++entry_counter;} 61 template <class Event,class FSM> on_exit__anon26599a780111::my_machine_::State262 void on_exit(Event const&,FSM& ) {++exit_counter;} 63 int entry_counter; 64 int exit_counter; 65 }; 66 67 struct State3 : public msm::front::state<> 68 { 69 template <class Event,class FSM> on_entry__anon26599a780111::my_machine_::State370 void on_entry(Event const&,FSM& ) {++entry_counter;} 71 template <class Event,class FSM> on_exit__anon26599a780111::my_machine_::State372 void on_exit(Event const&,FSM& ) {++exit_counter;} 73 int entry_counter; 74 int exit_counter; 75 }; 76 77 struct State4 : public msm::front::state<> 78 { 79 template <class Event,class FSM> on_entry__anon26599a780111::my_machine_::State480 void on_entry(Event const&,FSM& ) {++entry_counter;} 81 template <class Event,class FSM> on_exit__anon26599a780111::my_machine_::State482 void on_exit(Event const&,FSM& ) {++exit_counter;} 83 int entry_counter; 84 int exit_counter; 85 }; 86 87 // the initial state of the player SM. Must be defined 88 typedef State1 initial_state; 89 90 // transition actions State2ToState3__anon26599a780111::my_machine_91 void State2ToState3(none const&) { ++state2_to_state3_counter; } State3ToState4__anon26599a780111::my_machine_92 void State3ToState4(none const&) { ++state3_to_state4_counter; } 93 // guard conditions always_true__anon26599a780111::my_machine_94 bool always_true(none const& ) 95 { 96 ++always_true_counter; 97 return true; 98 } always_false__anon26599a780111::my_machine_99 bool always_false(none const& ) 100 { 101 ++always_false_counter; 102 return false; 103 } 104 105 typedef my_machine_ p; // makes transition table cleaner 106 107 // Transition table for player 108 struct transition_table : mpl::vector< 109 // Start Event Next Action Guard 110 // +---------+-------------+---------+---------------------+----------------------+ 111 _row < State1 , none , State2 >, 112 a_row < State2 , none , State3 , &p::State2ToState3 >, 113 // +---------+-------------+---------+---------------------+----------------------+ 114 row < State3 , none , State4 , &p::State3ToState4 , &p::always_true >, 115 g_row < State3 , none , State4 , &p::always_false >, 116 _row < State4 , event1 , State1 > 117 // +---------+-------------+---------+---------------------+----------------------+ 118 > {}; 119 // Replaces the default no-transition response. 120 template <class FSM,class Event> no_transition__anon26599a780111::my_machine_121 void no_transition(Event const&, FSM&,int) 122 { 123 BOOST_FAIL("no_transition called!"); 124 } 125 // init counters 126 template <class Event,class FSM> on_entry__anon26599a780111::my_machine_127 void on_entry(Event const&,FSM& fsm) 128 { 129 fsm.template get_state<my_machine_::State1&>().entry_counter=0; 130 fsm.template get_state<my_machine_::State1&>().exit_counter=0; 131 fsm.template get_state<my_machine_::State2&>().entry_counter=0; 132 fsm.template get_state<my_machine_::State2&>().exit_counter=0; 133 fsm.template get_state<my_machine_::State3&>().entry_counter=0; 134 fsm.template get_state<my_machine_::State3&>().exit_counter=0; 135 fsm.template get_state<my_machine_::State4&>().entry_counter=0; 136 fsm.template get_state<my_machine_::State4&>().exit_counter=0; 137 } 138 }; 139 // Pick a back-end 140 typedef msm::back::state_machine<my_machine_> my_machine; 141 142 //static char const* const state_names[] = { "State1", "State2", "State3", "State4" }; 143 144 BOOST_AUTO_TEST_CASE(my_test)145 BOOST_AUTO_TEST_CASE( my_test ) 146 { 147 my_machine p; 148 149 // needed to start the highest-level SM. This will call on_entry and mark the start of the SM 150 // in this case it will also immediately trigger all anonymous transitions 151 p.start(); 152 BOOST_CHECK_MESSAGE(p.current_state()[0] == 3,"State4 should be active"); //State4 153 BOOST_CHECK_MESSAGE(p.get_state<my_machine_::State1&>().exit_counter == 1,"State1 exit not called correctly"); 154 BOOST_CHECK_MESSAGE(p.get_state<my_machine_::State1&>().entry_counter == 1,"State1 entry not called correctly"); 155 BOOST_CHECK_MESSAGE(p.get_state<my_machine_::State2&>().exit_counter == 1,"State2 exit not called correctly"); 156 BOOST_CHECK_MESSAGE(p.get_state<my_machine_::State2&>().entry_counter == 1,"State2 entry not called correctly"); 157 BOOST_CHECK_MESSAGE(p.get_state<my_machine_::State3&>().exit_counter == 1,"State3 exit not called correctly"); 158 BOOST_CHECK_MESSAGE(p.get_state<my_machine_::State3&>().entry_counter == 1,"State3 entry not called correctly"); 159 BOOST_CHECK_MESSAGE(p.get_state<my_machine_::State4&>().entry_counter == 1,"State4 entry not called correctly"); 160 BOOST_CHECK_MESSAGE(p.always_true_counter == 1,"guard not called correctly"); 161 BOOST_CHECK_MESSAGE(p.always_false_counter == 1,"guard not called correctly"); 162 BOOST_CHECK_MESSAGE(p.state2_to_state3_counter == 1,"action not called correctly"); 163 BOOST_CHECK_MESSAGE(p.state3_to_state4_counter == 1,"action not called correctly"); 164 165 166 // this event will bring us back to the initial state and thus, a new "loop" will be started 167 p.process_event(event1()); 168 BOOST_CHECK_MESSAGE(p.current_state()[0] == 3,"State4 should be active"); //State4 169 BOOST_CHECK_MESSAGE(p.get_state<my_machine_::State1&>().exit_counter == 2,"State1 exit not called correctly"); 170 BOOST_CHECK_MESSAGE(p.get_state<my_machine_::State1&>().entry_counter == 2,"State1 entry not called correctly"); 171 BOOST_CHECK_MESSAGE(p.get_state<my_machine_::State2&>().exit_counter == 2,"State2 exit not called correctly"); 172 BOOST_CHECK_MESSAGE(p.get_state<my_machine_::State2&>().entry_counter == 2,"State2 entry not called correctly"); 173 BOOST_CHECK_MESSAGE(p.get_state<my_machine_::State3&>().exit_counter == 2,"State3 exit not called correctly"); 174 BOOST_CHECK_MESSAGE(p.get_state<my_machine_::State3&>().entry_counter == 2,"State3 entry not called correctly"); 175 BOOST_CHECK_MESSAGE(p.get_state<my_machine_::State4&>().entry_counter == 2,"State4 entry not called correctly"); 176 BOOST_CHECK_MESSAGE(p.get_state<my_machine_::State4&>().exit_counter == 1,"State4 exit not called correctly"); 177 BOOST_CHECK_MESSAGE(p.always_true_counter == 2,"guard not called correctly"); 178 BOOST_CHECK_MESSAGE(p.always_false_counter == 2,"guard not called correctly"); 179 BOOST_CHECK_MESSAGE(p.state2_to_state3_counter == 2,"action not called correctly"); 180 BOOST_CHECK_MESSAGE(p.state3_to_state4_counter == 2,"action not called correctly"); 181 182 } 183 } 184 185