Entries.cpp 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297
  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. #include <iostream>
  11. // back-end
  12. #include <boost/msm/back/state_machine.hpp>
  13. //front-end
  14. #include <boost/msm/front/state_machine_def.hpp>
  15. #ifndef BOOST_MSM_NONSTANDALONE_TEST
  16. #define BOOST_TEST_MODULE MyTest
  17. #endif
  18. #include <boost/test/unit_test.hpp>
  19. namespace msm = boost::msm;
  20. namespace mpl = boost::mpl;
  21. namespace
  22. {
  23. // events
  24. struct event1 {};
  25. struct event2 {};
  26. struct event3 {};
  27. struct event4 {};
  28. struct event5 {};
  29. struct event6
  30. {
  31. event6(){}
  32. template <class Event>
  33. event6(Event const&){}
  34. };
  35. // front-end: define the FSM structure
  36. struct Fsm_ : public msm::front::state_machine_def<Fsm_>
  37. {
  38. // The list of FSM states
  39. struct State1 : public msm::front::state<>
  40. {
  41. template <class Event,class FSM>
  42. void on_entry(Event const&,FSM& ) {++entry_counter;}
  43. template <class Event,class FSM>
  44. void on_exit(Event const&,FSM& ) {++exit_counter;}
  45. int entry_counter;
  46. int exit_counter;
  47. };
  48. struct State2 : public msm::front::state<>
  49. {
  50. template <class Event,class FSM>
  51. void on_entry(Event const&,FSM& ) {++entry_counter;}
  52. template <class Event,class FSM>
  53. void on_exit(Event const&,FSM& ) {++exit_counter;}
  54. int entry_counter;
  55. int exit_counter;
  56. };
  57. struct SubFsm2_ : public msm::front::state_machine_def<SubFsm2_>
  58. {
  59. typedef msm::back::state_machine<SubFsm2_> SubFsm2;
  60. unsigned int entry_action_counter;
  61. template <class Event,class FSM>
  62. void on_entry(Event const&,FSM& ) {++entry_counter;}
  63. template <class Event,class FSM>
  64. void on_exit(Event const&,FSM& ) {++exit_counter;}
  65. int entry_counter;
  66. int exit_counter;
  67. struct SubState1 : public msm::front::state<>
  68. {
  69. template <class Event,class FSM>
  70. void on_entry(Event const&,FSM& ) {++entry_counter;}
  71. template <class Event,class FSM>
  72. void on_exit(Event const&,FSM& ) {++exit_counter;}
  73. int entry_counter;
  74. int exit_counter;
  75. };
  76. struct SubState1b : public msm::front::state<>
  77. {
  78. template <class Event,class FSM>
  79. void on_entry(Event const&,FSM& ) {++entry_counter;}
  80. template <class Event,class FSM>
  81. void on_exit(Event const&,FSM& ) {++exit_counter;}
  82. int entry_counter;
  83. int exit_counter;
  84. };
  85. struct SubState2 : public msm::front::state<> , public msm::front::explicit_entry<0>
  86. {
  87. template <class Event,class FSM>
  88. void on_entry(Event const&,FSM& ) {++entry_counter;}
  89. template <class Event,class FSM>
  90. void on_exit(Event const&,FSM& ) {++exit_counter;}
  91. int entry_counter;
  92. int exit_counter;
  93. };
  94. struct SubState2b : public msm::front::state<> , public msm::front::explicit_entry<1>
  95. {
  96. template <class Event,class FSM>
  97. void on_entry(Event const&,FSM& ) {++entry_counter;}
  98. template <class Event,class FSM>
  99. void on_exit(Event const&,FSM& ) {++exit_counter;}
  100. int entry_counter;
  101. int exit_counter;
  102. };
  103. // test with a pseudo entry
  104. struct PseudoEntry1 : public msm::front::entry_pseudo_state<0>
  105. {
  106. template <class Event,class FSM>
  107. void on_entry(Event const&,FSM& ) {++entry_counter;}
  108. template <class Event,class FSM>
  109. void on_exit(Event const&,FSM& ) {++exit_counter;}
  110. int entry_counter;
  111. int exit_counter;
  112. };
  113. struct SubState3 : public msm::front::state<>
  114. {
  115. template <class Event,class FSM>
  116. void on_entry(Event const&,FSM& ) {++entry_counter;}
  117. template <class Event,class FSM>
  118. void on_exit(Event const&,FSM& ) {++exit_counter;}
  119. int entry_counter;
  120. int exit_counter;
  121. };
  122. struct PseudoExit1 : public msm::front::exit_pseudo_state<event6>
  123. {
  124. template <class Event,class FSM>
  125. void on_entry(Event const&,FSM& ) {++entry_counter;}
  126. template <class Event,class FSM>
  127. void on_exit(Event const&,FSM& ) {++exit_counter;}
  128. int entry_counter;
  129. int exit_counter;
  130. };
  131. // action methods
  132. void entry_action(event4 const&)
  133. {
  134. ++entry_action_counter;
  135. }
  136. // the initial state. Must be defined
  137. typedef mpl::vector<SubState1,SubState1b> initial_state;
  138. typedef mpl::vector<SubState2b> explicit_creation;
  139. // Transition table for SubFsm2
  140. struct transition_table : mpl::vector<
  141. // Start Event Next Action Guard
  142. // +--------------+-------------+------------+------------------------+----------------------+
  143. a_row < PseudoEntry1 , event4 , SubState3 ,&SubFsm2_::entry_action >,
  144. _row < SubState2 , event6 , SubState1 >,
  145. _row < SubState3 , event5 , PseudoExit1 >
  146. // +--------------+-------------+------------+------------------------+----------------------+
  147. > {};
  148. // Replaces the default no-transition response.
  149. template <class FSM,class Event>
  150. void no_transition(Event const& , FSM&,int)
  151. {
  152. BOOST_FAIL("no_transition called!");
  153. }
  154. };
  155. typedef msm::back::state_machine<SubFsm2_> SubFsm2;
  156. // the initial state of the player SM. Must be defined
  157. typedef State1 initial_state;
  158. // transition actions
  159. // guard conditions
  160. // Transition table for Fsm
  161. struct transition_table : mpl::vector<
  162. // Start Event Next Action Guard
  163. // +---------------------+--------+------------------------------------+-------+--------+
  164. _row < State1 , event1 , SubFsm2 >,
  165. _row < State1 , event2 , SubFsm2::direct<SubFsm2_::SubState2> >,
  166. _row < State1 , event3 , mpl::vector<SubFsm2::direct<SubFsm2_::SubState2>,
  167. SubFsm2::direct<SubFsm2_::SubState2b> > >,
  168. _row < State1 , event4 , SubFsm2::entry_pt
  169. <SubFsm2_::PseudoEntry1> >,
  170. // +---------------------+--------+------------------------------------+-------+--------+
  171. _row < SubFsm2 , event1 , State1 >,
  172. _row < SubFsm2::exit_pt
  173. <SubFsm2_::PseudoExit1>, event6 , State2 >
  174. // +---------------------+--------+------------------------------------+-------+--------+
  175. > {};
  176. // Replaces the default no-transition response.
  177. template <class FSM,class Event>
  178. void no_transition(Event const& , FSM&,int )
  179. {
  180. BOOST_FAIL("no_transition called!");
  181. }
  182. // init counters
  183. template <class Event,class FSM>
  184. void on_entry(Event const&,FSM& fsm)
  185. {
  186. fsm.template get_state<Fsm_::State1&>().entry_counter=0;
  187. fsm.template get_state<Fsm_::State1&>().exit_counter=0;
  188. fsm.template get_state<Fsm_::State2&>().entry_counter=0;
  189. fsm.template get_state<Fsm_::State2&>().exit_counter=0;
  190. fsm.template get_state<Fsm_::SubFsm2&>().entry_counter=0;
  191. fsm.template get_state<Fsm_::SubFsm2&>().exit_counter=0;
  192. fsm.template get_state<Fsm_::SubFsm2&>().entry_action_counter=0;
  193. fsm.template get_state<Fsm_::SubFsm2&>().template get_state<Fsm_::SubFsm2::SubState1&>().entry_counter=0;
  194. fsm.template get_state<Fsm_::SubFsm2&>().template get_state<Fsm_::SubFsm2::SubState1&>().exit_counter=0;
  195. fsm.template get_state<Fsm_::SubFsm2&>().template get_state<Fsm_::SubFsm2::SubState1b&>().entry_counter=0;
  196. fsm.template get_state<Fsm_::SubFsm2&>().template get_state<Fsm_::SubFsm2::SubState1b&>().exit_counter=0;
  197. fsm.template get_state<Fsm_::SubFsm2&>().template get_state<Fsm_::SubFsm2::SubState2&>().entry_counter=0;
  198. fsm.template get_state<Fsm_::SubFsm2&>().template get_state<Fsm_::SubFsm2::SubState2&>().exit_counter=0;
  199. fsm.template get_state<Fsm_::SubFsm2&>().template get_state<Fsm_::SubFsm2::SubState2b&>().entry_counter=0;
  200. fsm.template get_state<Fsm_::SubFsm2&>().template get_state<Fsm_::SubFsm2::SubState2b&>().exit_counter=0;
  201. fsm.template get_state<Fsm_::SubFsm2&>().template get_state<Fsm_::SubFsm2::SubState3&>().entry_counter=0;
  202. fsm.template get_state<Fsm_::SubFsm2&>().template get_state<Fsm_::SubFsm2::SubState3&>().exit_counter=0;
  203. fsm.template get_state<Fsm_::SubFsm2&>().template get_state<Fsm_::SubFsm2::PseudoEntry1&>().entry_counter=0;
  204. fsm.template get_state<Fsm_::SubFsm2&>().template get_state<Fsm_::SubFsm2::PseudoEntry1&>().exit_counter=0;
  205. fsm.template get_state<Fsm_::SubFsm2&>().template get_state<Fsm_::SubFsm2::exit_pt<SubFsm2_::PseudoExit1>&>().entry_counter=0;
  206. fsm.template get_state<Fsm_::SubFsm2&>().template get_state<Fsm_::SubFsm2::exit_pt<SubFsm2_::PseudoExit1>&>().exit_counter=0;
  207. }
  208. };
  209. typedef msm::back::state_machine<Fsm_> Fsm;
  210. // static char const* const state_names[] = { "State1", "SubFsm2","State2" };
  211. BOOST_AUTO_TEST_CASE( my_test )
  212. {
  213. Fsm p;
  214. p.start();
  215. BOOST_CHECK_MESSAGE(p.get_state<Fsm_::State1&>().entry_counter == 1,"State1 entry not called correctly");
  216. p.process_event(event1());
  217. p.process_event(event1());
  218. BOOST_CHECK_MESSAGE(p.current_state()[0] == 0,"State1 should be active");
  219. BOOST_CHECK_MESSAGE(p.get_state<Fsm_::State1&>().exit_counter == 1,"State1 exit not called correctly");
  220. BOOST_CHECK_MESSAGE(p.get_state<Fsm_::State1&>().entry_counter == 2,"State1 entry not called correctly");
  221. BOOST_CHECK_MESSAGE(p.get_state<Fsm_::SubFsm2&>().exit_counter == 1,"SubFsm2 exit not called correctly");
  222. BOOST_CHECK_MESSAGE(p.get_state<Fsm_::SubFsm2&>().entry_counter == 1,"SubFsm2 entry not called correctly");
  223. p.process_event(event2());
  224. p.process_event(event6());
  225. p.process_event(event1());
  226. BOOST_CHECK_MESSAGE(p.current_state()[0] == 0,"State1 should be active");
  227. BOOST_CHECK_MESSAGE(p.get_state<Fsm_::State1&>().exit_counter == 2,"State1 exit not called correctly");
  228. BOOST_CHECK_MESSAGE(p.get_state<Fsm_::State1&>().entry_counter == 3,"State1 entry not called correctly");
  229. BOOST_CHECK_MESSAGE(p.get_state<Fsm_::SubFsm2&>().exit_counter == 2,"SubFsm2 exit not called correctly");
  230. BOOST_CHECK_MESSAGE(p.get_state<Fsm_::SubFsm2&>().entry_counter == 2,"SubFsm2 entry not called correctly");
  231. BOOST_CHECK_MESSAGE(p.get_state<Fsm_::SubFsm2&>().get_state<Fsm_::SubFsm2_::SubState2&>().entry_counter == 1,
  232. "SubFsm2::SubState2 entry not called correctly");
  233. BOOST_CHECK_MESSAGE(p.get_state<Fsm_::SubFsm2&>().get_state<Fsm_::SubFsm2_::SubState2&>().exit_counter == 1,
  234. "SubFsm2::SubState2 exit not called correctly");
  235. BOOST_CHECK_MESSAGE(p.get_state<Fsm_::SubFsm2&>().get_state<Fsm_::SubFsm2_::SubState1&>().entry_counter == 2,
  236. "SubFsm2::SubState1 entry not called correctly");
  237. BOOST_CHECK_MESSAGE(p.get_state<Fsm_::SubFsm2&>().get_state<Fsm_::SubFsm2_::SubState1&>().exit_counter == 2,
  238. "SubFsm2::SubState1 exit not called correctly");
  239. p.process_event(event3());
  240. p.process_event(event1());
  241. BOOST_CHECK_MESSAGE(p.current_state()[0] == 0,"State1 should be active");
  242. BOOST_CHECK_MESSAGE(p.get_state<Fsm_::State1&>().exit_counter == 3,"State1 exit not called correctly");
  243. BOOST_CHECK_MESSAGE(p.get_state<Fsm_::State1&>().entry_counter == 4,"State1 entry not called correctly");
  244. BOOST_CHECK_MESSAGE(p.get_state<Fsm_::SubFsm2&>().exit_counter == 3,"SubFsm2 exit not called correctly");
  245. BOOST_CHECK_MESSAGE(p.get_state<Fsm_::SubFsm2&>().entry_counter == 3,"SubFsm2 entry not called correctly");
  246. BOOST_CHECK_MESSAGE(p.get_state<Fsm_::SubFsm2&>().get_state<Fsm_::SubFsm2_::SubState2&>().entry_counter == 2,
  247. "SubFsm2::SubState2 entry not called correctly");
  248. BOOST_CHECK_MESSAGE(p.get_state<Fsm_::SubFsm2&>().get_state<Fsm_::SubFsm2_::SubState2&>().exit_counter == 2,
  249. "SubFsm2::SubState2 exit not called correctly");
  250. BOOST_CHECK_MESSAGE(p.get_state<Fsm_::SubFsm2&>().get_state<Fsm_::SubFsm2_::SubState2b&>().entry_counter == 1,
  251. "SubFsm2::SubState2b entry not called correctly");
  252. BOOST_CHECK_MESSAGE(p.get_state<Fsm_::SubFsm2&>().get_state<Fsm_::SubFsm2_::SubState2b&>().exit_counter == 1,
  253. "SubFsm2::SubState2b exit not called correctly");
  254. p.process_event(event4());
  255. p.process_event(event5());
  256. BOOST_CHECK_MESSAGE(p.current_state()[0] == 2,"State2 should be active");
  257. BOOST_CHECK_MESSAGE(p.get_state<Fsm_::State1&>().exit_counter == 4,"State1 exit not called correctly");
  258. BOOST_CHECK_MESSAGE(p.get_state<Fsm_::State2&>().entry_counter == 1,"State2 entry not called correctly");
  259. BOOST_CHECK_MESSAGE(p.get_state<Fsm_::SubFsm2&>().exit_counter == 4,"SubFsm2 exit not called correctly");
  260. BOOST_CHECK_MESSAGE(p.get_state<Fsm_::SubFsm2&>().entry_counter == 4,"SubFsm2 entry not called correctly");
  261. BOOST_CHECK_MESSAGE(p.get_state<Fsm_::SubFsm2&>().get_state<Fsm_::SubFsm2_::PseudoEntry1&>().entry_counter == 1,
  262. "SubFsm2::PseudoEntry1 entry not called correctly");
  263. BOOST_CHECK_MESSAGE(p.get_state<Fsm_::SubFsm2&>().get_state<Fsm_::SubFsm2_::PseudoEntry1&>().exit_counter == 1,
  264. "SubFsm2::PseudoEntry1 exit not called correctly");
  265. BOOST_CHECK_MESSAGE(p.get_state<Fsm_::SubFsm2&>().get_state<Fsm_::SubFsm2_::SubState3&>().entry_counter == 1,
  266. "SubFsm2::SubState3 entry not called correctly");
  267. BOOST_CHECK_MESSAGE(p.get_state<Fsm_::SubFsm2&>().get_state<Fsm_::SubFsm2_::SubState3&>().exit_counter == 1,
  268. "SubFsm2::SubState3 exit not called correctly");
  269. BOOST_CHECK_MESSAGE(p.get_state<Fsm_::SubFsm2&>().get_state<Fsm_::SubFsm2::exit_pt<Fsm_::SubFsm2_::PseudoExit1>&>().entry_counter == 1,
  270. "SubFsm2::PseudoExit1 entry not called correctly");
  271. BOOST_CHECK_MESSAGE(p.get_state<Fsm_::SubFsm2&>().get_state<Fsm_::SubFsm2::exit_pt<Fsm_::SubFsm2_::PseudoExit1>&>().exit_counter == 1,
  272. "SubFsm2::PseudoExit1 exit not called correctly");
  273. BOOST_CHECK_MESSAGE(p.get_state<Fsm_::SubFsm2&>().entry_action_counter == 1,"Action not called correctly");
  274. }
  275. }