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 #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 namespace mpl = boost::mpl; 23 24 namespace 25 { 26 // events 27 struct event1 {}; 28 struct event2 {}; 29 struct event3 {}; 30 struct event4 {}; 31 struct event5 {}; 32 struct event6 33 { event6__anon0e70cca70111::event634 event6(){} 35 template <class Event> event6__anon0e70cca70111::event636 event6(Event const&){} 37 }; 38 // front-end: define the FSM structure 39 struct Fsm_ : public msm::front::state_machine_def<Fsm_> 40 { 41 // The list of FSM states 42 struct State1 : public msm::front::state<> 43 { 44 template <class Event,class FSM> on_entry__anon0e70cca70111::Fsm_::State145 void on_entry(Event const&,FSM& ) {++entry_counter;} 46 template <class Event,class FSM> on_exit__anon0e70cca70111::Fsm_::State147 void on_exit(Event const&,FSM& ) {++exit_counter;} 48 int entry_counter; 49 int exit_counter; 50 }; 51 struct State2 : public msm::front::state<> 52 { 53 template <class Event,class FSM> on_entry__anon0e70cca70111::Fsm_::State254 void on_entry(Event const&,FSM& ) {++entry_counter;} 55 template <class Event,class FSM> on_exit__anon0e70cca70111::Fsm_::State256 void on_exit(Event const&,FSM& ) {++exit_counter;} 57 int entry_counter; 58 int exit_counter; 59 }; 60 struct SubFsm2_ : public msm::front::state_machine_def<SubFsm2_> 61 { 62 typedef msm::back::state_machine<SubFsm2_> SubFsm2; 63 64 unsigned int entry_action_counter; 65 66 template <class Event,class FSM> on_entry__anon0e70cca70111::Fsm_::SubFsm2_67 void on_entry(Event const&,FSM& ) {++entry_counter;} 68 template <class Event,class FSM> on_exit__anon0e70cca70111::Fsm_::SubFsm2_69 void on_exit(Event const&,FSM& ) {++exit_counter;} 70 int entry_counter; 71 int exit_counter; 72 73 struct SubState1 : public msm::front::state<> 74 { 75 template <class Event,class FSM> on_entry__anon0e70cca70111::Fsm_::SubFsm2_::SubState176 void on_entry(Event const&,FSM& ) {++entry_counter;} 77 template <class Event,class FSM> on_exit__anon0e70cca70111::Fsm_::SubFsm2_::SubState178 void on_exit(Event const&,FSM& ) {++exit_counter;} 79 int entry_counter; 80 int exit_counter; 81 }; 82 struct SubState1b : public msm::front::state<> 83 { 84 template <class Event,class FSM> on_entry__anon0e70cca70111::Fsm_::SubFsm2_::SubState1b85 void on_entry(Event const&,FSM& ) {++entry_counter;} 86 template <class Event,class FSM> on_exit__anon0e70cca70111::Fsm_::SubFsm2_::SubState1b87 void on_exit(Event const&,FSM& ) {++exit_counter;} 88 int entry_counter; 89 int exit_counter; 90 }; 91 struct SubState2 : public msm::front::state<> , public msm::front::explicit_entry<0> 92 { 93 template <class Event,class FSM> on_entry__anon0e70cca70111::Fsm_::SubFsm2_::SubState294 void on_entry(Event const&,FSM& ) {++entry_counter;} 95 template <class Event,class FSM> on_exit__anon0e70cca70111::Fsm_::SubFsm2_::SubState296 void on_exit(Event const&,FSM& ) {++exit_counter;} 97 int entry_counter; 98 int exit_counter; 99 }; 100 struct SubState2b : public msm::front::state<> , public msm::front::explicit_entry<1> 101 { 102 template <class Event,class FSM> on_entry__anon0e70cca70111::Fsm_::SubFsm2_::SubState2b103 void on_entry(Event const&,FSM& ) {++entry_counter;} 104 template <class Event,class FSM> on_exit__anon0e70cca70111::Fsm_::SubFsm2_::SubState2b105 void on_exit(Event const&,FSM& ) {++exit_counter;} 106 int entry_counter; 107 int exit_counter; 108 }; 109 // test with a pseudo entry 110 struct PseudoEntry1 : public msm::front::entry_pseudo_state<0> 111 { 112 template <class Event,class FSM> on_entry__anon0e70cca70111::Fsm_::SubFsm2_::PseudoEntry1113 void on_entry(Event const&,FSM& ) {++entry_counter;} 114 template <class Event,class FSM> on_exit__anon0e70cca70111::Fsm_::SubFsm2_::PseudoEntry1115 void on_exit(Event const&,FSM& ) {++exit_counter;} 116 int entry_counter; 117 int exit_counter; 118 }; 119 struct SubState3 : public msm::front::state<> 120 { 121 template <class Event,class FSM> on_entry__anon0e70cca70111::Fsm_::SubFsm2_::SubState3122 void on_entry(Event const&,FSM& ) {++entry_counter;} 123 template <class Event,class FSM> on_exit__anon0e70cca70111::Fsm_::SubFsm2_::SubState3124 void on_exit(Event const&,FSM& ) {++exit_counter;} 125 int entry_counter; 126 int exit_counter; 127 }; 128 struct PseudoExit1 : public msm::front::exit_pseudo_state<event6> 129 { 130 template <class Event,class FSM> on_entry__anon0e70cca70111::Fsm_::SubFsm2_::PseudoExit1131 void on_entry(Event const&,FSM& ) {++entry_counter;} 132 template <class Event,class FSM> on_exit__anon0e70cca70111::Fsm_::SubFsm2_::PseudoExit1133 void on_exit(Event const&,FSM& ) {++exit_counter;} 134 int entry_counter; 135 int exit_counter; 136 }; 137 // action methods entry_action__anon0e70cca70111::Fsm_::SubFsm2_138 void entry_action(event4 const&) 139 { 140 ++entry_action_counter; 141 } 142 // the initial state. Must be defined 143 typedef mpl::vector<SubState1,SubState1b> initial_state; 144 145 typedef mpl::vector<SubState2b> explicit_creation; 146 147 // Transition table for SubFsm2 148 struct transition_table : mpl::vector< 149 // Start Event Next Action Guard 150 // +--------------+-------------+------------+------------------------+----------------------+ 151 a_row < PseudoEntry1 , event4 , SubState3 ,&SubFsm2_::entry_action >, 152 _row < SubState2 , event6 , SubState1 >, 153 _row < SubState3 , event5 , PseudoExit1 > 154 // +--------------+-------------+------------+------------------------+----------------------+ 155 > {}; 156 // Replaces the default no-transition response. 157 template <class FSM,class Event> no_transition__anon0e70cca70111::Fsm_::SubFsm2_158 void no_transition(Event const& , FSM&,int) 159 { 160 BOOST_FAIL("no_transition called!"); 161 } 162 }; 163 typedef msm::back::state_machine<SubFsm2_> SubFsm2; 164 165 // the initial state of the player SM. Must be defined 166 typedef State1 initial_state; 167 168 // transition actions 169 // guard conditions 170 171 // Transition table for Fsm 172 struct transition_table : mpl::vector< 173 // Start Event Next Action Guard 174 // +---------------------+--------+------------------------------------+-------+--------+ 175 _row < State1 , event1 , SubFsm2 >, 176 _row < State1 , event2 , SubFsm2::direct<SubFsm2_::SubState2> >, 177 _row < State1 , event3 , mpl::vector<SubFsm2::direct<SubFsm2_::SubState2>, 178 SubFsm2::direct<SubFsm2_::SubState2b> > >, 179 _row < State1 , event4 , SubFsm2::entry_pt 180 <SubFsm2_::PseudoEntry1> >, 181 // +---------------------+--------+------------------------------------+-------+--------+ 182 _row < SubFsm2 , event1 , State1 >, 183 _row < SubFsm2::exit_pt 184 <SubFsm2_::PseudoExit1>, event6 , State2 > 185 // +---------------------+--------+------------------------------------+-------+--------+ 186 > {}; 187 188 // Replaces the default no-transition response. 189 template <class FSM,class Event> no_transition__anon0e70cca70111::Fsm_190 void no_transition(Event const& , FSM&,int ) 191 { 192 BOOST_FAIL("no_transition called!"); 193 } 194 // init counters 195 template <class Event,class FSM> on_entry__anon0e70cca70111::Fsm_196 void on_entry(Event const&,FSM& fsm) 197 { 198 fsm.template get_state<Fsm_::State1&>().entry_counter=0; 199 fsm.template get_state<Fsm_::State1&>().exit_counter=0; 200 fsm.template get_state<Fsm_::State2&>().entry_counter=0; 201 fsm.template get_state<Fsm_::State2&>().exit_counter=0; 202 fsm.template get_state<Fsm_::SubFsm2&>().entry_counter=0; 203 fsm.template get_state<Fsm_::SubFsm2&>().exit_counter=0; 204 fsm.template get_state<Fsm_::SubFsm2&>().entry_action_counter=0; 205 fsm.template get_state<Fsm_::SubFsm2&>().template get_state<Fsm_::SubFsm2::SubState1&>().entry_counter=0; 206 fsm.template get_state<Fsm_::SubFsm2&>().template get_state<Fsm_::SubFsm2::SubState1&>().exit_counter=0; 207 fsm.template get_state<Fsm_::SubFsm2&>().template get_state<Fsm_::SubFsm2::SubState1b&>().entry_counter=0; 208 fsm.template get_state<Fsm_::SubFsm2&>().template get_state<Fsm_::SubFsm2::SubState1b&>().exit_counter=0; 209 fsm.template get_state<Fsm_::SubFsm2&>().template get_state<Fsm_::SubFsm2::SubState2&>().entry_counter=0; 210 fsm.template get_state<Fsm_::SubFsm2&>().template get_state<Fsm_::SubFsm2::SubState2&>().exit_counter=0; 211 fsm.template get_state<Fsm_::SubFsm2&>().template get_state<Fsm_::SubFsm2::SubState2b&>().entry_counter=0; 212 fsm.template get_state<Fsm_::SubFsm2&>().template get_state<Fsm_::SubFsm2::SubState2b&>().exit_counter=0; 213 fsm.template get_state<Fsm_::SubFsm2&>().template get_state<Fsm_::SubFsm2::SubState3&>().entry_counter=0; 214 fsm.template get_state<Fsm_::SubFsm2&>().template get_state<Fsm_::SubFsm2::SubState3&>().exit_counter=0; 215 fsm.template get_state<Fsm_::SubFsm2&>().template get_state<Fsm_::SubFsm2::PseudoEntry1&>().entry_counter=0; 216 fsm.template get_state<Fsm_::SubFsm2&>().template get_state<Fsm_::SubFsm2::PseudoEntry1&>().exit_counter=0; 217 fsm.template get_state<Fsm_::SubFsm2&>().template get_state<Fsm_::SubFsm2::exit_pt<SubFsm2_::PseudoExit1>&>().entry_counter=0; 218 fsm.template get_state<Fsm_::SubFsm2&>().template get_state<Fsm_::SubFsm2::exit_pt<SubFsm2_::PseudoExit1>&>().exit_counter=0; 219 220 } 221 }; 222 typedef msm::back::state_machine<Fsm_> Fsm; 223 // static char const* const state_names[] = { "State1", "SubFsm2","State2" }; 224 225 BOOST_AUTO_TEST_CASE(my_test)226 BOOST_AUTO_TEST_CASE( my_test ) 227 { 228 Fsm p; 229 230 p.start(); 231 BOOST_CHECK_MESSAGE(p.get_state<Fsm_::State1&>().entry_counter == 1,"State1 entry not called correctly"); 232 233 p.process_event(event1()); 234 p.process_event(event1()); 235 BOOST_CHECK_MESSAGE(p.current_state()[0] == 0,"State1 should be active"); 236 BOOST_CHECK_MESSAGE(p.get_state<Fsm_::State1&>().exit_counter == 1,"State1 exit not called correctly"); 237 BOOST_CHECK_MESSAGE(p.get_state<Fsm_::State1&>().entry_counter == 2,"State1 entry not called correctly"); 238 BOOST_CHECK_MESSAGE(p.get_state<Fsm_::SubFsm2&>().exit_counter == 1,"SubFsm2 exit not called correctly"); 239 BOOST_CHECK_MESSAGE(p.get_state<Fsm_::SubFsm2&>().entry_counter == 1,"SubFsm2 entry not called correctly"); 240 241 p.process_event(event2()); 242 p.process_event(event6()); 243 p.process_event(event1()); 244 BOOST_CHECK_MESSAGE(p.current_state()[0] == 0,"State1 should be active"); 245 BOOST_CHECK_MESSAGE(p.get_state<Fsm_::State1&>().exit_counter == 2,"State1 exit not called correctly"); 246 BOOST_CHECK_MESSAGE(p.get_state<Fsm_::State1&>().entry_counter == 3,"State1 entry not called correctly"); 247 BOOST_CHECK_MESSAGE(p.get_state<Fsm_::SubFsm2&>().exit_counter == 2,"SubFsm2 exit not called correctly"); 248 BOOST_CHECK_MESSAGE(p.get_state<Fsm_::SubFsm2&>().entry_counter == 2,"SubFsm2 entry not called correctly"); 249 BOOST_CHECK_MESSAGE(p.get_state<Fsm_::SubFsm2&>().get_state<Fsm_::SubFsm2_::SubState2&>().entry_counter == 1, 250 "SubFsm2::SubState2 entry not called correctly"); 251 BOOST_CHECK_MESSAGE(p.get_state<Fsm_::SubFsm2&>().get_state<Fsm_::SubFsm2_::SubState2&>().exit_counter == 1, 252 "SubFsm2::SubState2 exit not called correctly"); 253 BOOST_CHECK_MESSAGE(p.get_state<Fsm_::SubFsm2&>().get_state<Fsm_::SubFsm2_::SubState1&>().entry_counter == 2, 254 "SubFsm2::SubState1 entry not called correctly"); 255 BOOST_CHECK_MESSAGE(p.get_state<Fsm_::SubFsm2&>().get_state<Fsm_::SubFsm2_::SubState1&>().exit_counter == 2, 256 "SubFsm2::SubState1 exit not called correctly"); 257 258 p.process_event(event3()); 259 p.process_event(event1()); 260 BOOST_CHECK_MESSAGE(p.current_state()[0] == 0,"State1 should be active"); 261 BOOST_CHECK_MESSAGE(p.get_state<Fsm_::State1&>().exit_counter == 3,"State1 exit not called correctly"); 262 BOOST_CHECK_MESSAGE(p.get_state<Fsm_::State1&>().entry_counter == 4,"State1 entry not called correctly"); 263 BOOST_CHECK_MESSAGE(p.get_state<Fsm_::SubFsm2&>().exit_counter == 3,"SubFsm2 exit not called correctly"); 264 BOOST_CHECK_MESSAGE(p.get_state<Fsm_::SubFsm2&>().entry_counter == 3,"SubFsm2 entry not called correctly"); 265 BOOST_CHECK_MESSAGE(p.get_state<Fsm_::SubFsm2&>().get_state<Fsm_::SubFsm2_::SubState2&>().entry_counter == 2, 266 "SubFsm2::SubState2 entry not called correctly"); 267 BOOST_CHECK_MESSAGE(p.get_state<Fsm_::SubFsm2&>().get_state<Fsm_::SubFsm2_::SubState2&>().exit_counter == 2, 268 "SubFsm2::SubState2 exit not called correctly"); 269 BOOST_CHECK_MESSAGE(p.get_state<Fsm_::SubFsm2&>().get_state<Fsm_::SubFsm2_::SubState2b&>().entry_counter == 1, 270 "SubFsm2::SubState2b entry not called correctly"); 271 BOOST_CHECK_MESSAGE(p.get_state<Fsm_::SubFsm2&>().get_state<Fsm_::SubFsm2_::SubState2b&>().exit_counter == 1, 272 "SubFsm2::SubState2b exit not called correctly"); 273 274 p.process_event(event4()); 275 p.process_event(event5()); 276 BOOST_CHECK_MESSAGE(p.current_state()[0] == 2,"State2 should be active"); 277 BOOST_CHECK_MESSAGE(p.get_state<Fsm_::State1&>().exit_counter == 4,"State1 exit not called correctly"); 278 BOOST_CHECK_MESSAGE(p.get_state<Fsm_::State2&>().entry_counter == 1,"State2 entry not called correctly"); 279 BOOST_CHECK_MESSAGE(p.get_state<Fsm_::SubFsm2&>().exit_counter == 4,"SubFsm2 exit not called correctly"); 280 BOOST_CHECK_MESSAGE(p.get_state<Fsm_::SubFsm2&>().entry_counter == 4,"SubFsm2 entry not called correctly"); 281 BOOST_CHECK_MESSAGE(p.get_state<Fsm_::SubFsm2&>().get_state<Fsm_::SubFsm2_::PseudoEntry1&>().entry_counter == 1, 282 "SubFsm2::PseudoEntry1 entry not called correctly"); 283 BOOST_CHECK_MESSAGE(p.get_state<Fsm_::SubFsm2&>().get_state<Fsm_::SubFsm2_::PseudoEntry1&>().exit_counter == 1, 284 "SubFsm2::PseudoEntry1 exit not called correctly"); 285 BOOST_CHECK_MESSAGE(p.get_state<Fsm_::SubFsm2&>().get_state<Fsm_::SubFsm2_::SubState3&>().entry_counter == 1, 286 "SubFsm2::SubState3 entry not called correctly"); 287 BOOST_CHECK_MESSAGE(p.get_state<Fsm_::SubFsm2&>().get_state<Fsm_::SubFsm2_::SubState3&>().exit_counter == 1, 288 "SubFsm2::SubState3 exit not called correctly"); 289 BOOST_CHECK_MESSAGE(p.get_state<Fsm_::SubFsm2&>().get_state<Fsm_::SubFsm2::exit_pt<Fsm_::SubFsm2_::PseudoExit1>&>().entry_counter == 1, 290 "SubFsm2::PseudoExit1 entry not called correctly"); 291 BOOST_CHECK_MESSAGE(p.get_state<Fsm_::SubFsm2&>().get_state<Fsm_::SubFsm2::exit_pt<Fsm_::SubFsm2_::PseudoExit1>&>().exit_counter == 1, 292 "SubFsm2::PseudoExit1 exit not called correctly"); 293 BOOST_CHECK_MESSAGE(p.get_state<Fsm_::SubFsm2&>().entry_action_counter == 1,"Action not called correctly"); 294 295 } 296 } 297 298