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 #include <boost/msm/front/functor_row.hpp> 17 18 #include <boost/test/unit_test.hpp> 19 20 namespace msm = boost::msm; 21 namespace mpl = boost::mpl; 22 using namespace boost::msm::front; 23 24 namespace 25 { 26 // events 27 struct event1 {}; 28 struct event2 {}; 29 struct event3 {}; 30 struct eventd {}; 31 32 33 // front-end: define the FSM structure 34 struct player_ : public msm::front::state_machine_def<player_> 35 { 36 // The list of FSM states 37 struct State11 : public msm::front::state<> 38 { 39 template <class Event,class FSM> on_entry__anon38161e740111::player_::State1140 void on_entry(Event const&,FSM& ) {++entry_counter;} 41 template <class Event,class FSM> on_exit__anon38161e740111::player_::State1142 void on_exit(Event const&,FSM& ) {++exit_counter;} 43 int entry_counter; 44 int exit_counter; 45 }; 46 struct State12 : public msm::front::state<> 47 { 48 typedef mpl::vector<eventd> deferred_events; 49 template <class Event,class FSM> on_entry__anon38161e740111::player_::State1250 void on_entry(Event const&,FSM& ) {++entry_counter;} 51 template <class Event,class FSM> on_exit__anon38161e740111::player_::State1252 void on_exit(Event const&,FSM& ) {++exit_counter;} 53 int entry_counter; 54 int exit_counter; 55 }; 56 struct State13 : public msm::front::state<> 57 { 58 template <class Event,class FSM> on_entry__anon38161e740111::player_::State1359 void on_entry(Event const&,FSM& ) {++entry_counter;} 60 template <class Event,class FSM> on_exit__anon38161e740111::player_::State1361 void on_exit(Event const&,FSM& ) {++exit_counter;} 62 int entry_counter; 63 int exit_counter; 64 }; 65 struct State21 : public msm::front::state<> 66 { 67 template <class Event,class FSM> on_entry__anon38161e740111::player_::State2168 void on_entry(Event const&,FSM& ) {++entry_counter;} 69 template <class Event,class FSM> on_exit__anon38161e740111::player_::State2170 void on_exit(Event const&,FSM& ) {++exit_counter;} 71 int entry_counter; 72 int exit_counter; 73 }; 74 struct State22 : public msm::front::state<> 75 { 76 template <class Event,class FSM> on_entry__anon38161e740111::player_::State2277 void on_entry(Event const&,FSM& ) {++entry_counter;} 78 template <class Event,class FSM> on_exit__anon38161e740111::player_::State2279 void on_exit(Event const&,FSM& ) {++exit_counter;} 80 int entry_counter; 81 int exit_counter; 82 }; 83 // the initial state of the player SM. Must be defined 84 typedef mpl::vector<State11,State21> initial_state; 85 86 87 // Transition table for player 88 struct transition_table : mpl::vector< 89 // Start Event Next Action Guard 90 // +---------+-------------+---------+---------------------+----------------------+ 91 Row < State11 , event1 , State12 >, 92 Row < State12 , event2 , State13 >, 93 94 Row < State21 , event3 , State22 >, 95 Row < State22 , eventd , State21 > 96 // +---------+-------------+---------+---------------------+----------------------+ 97 > {}; 98 99 // Replaces the default no-transition response. 100 template <class FSM,class Event> no_transition__anon38161e740111::player_101 void no_transition(Event const& , FSM&,int ) 102 { 103 BOOST_FAIL("no_transition called!"); 104 } 105 // init counters 106 template <class Event,class FSM> on_entry__anon38161e740111::player_107 void on_entry(Event const&,FSM& fsm) 108 { 109 fsm.template get_state<player_::State11&>().entry_counter=0; 110 fsm.template get_state<player_::State11&>().exit_counter=0; 111 fsm.template get_state<player_::State12&>().entry_counter=0; 112 fsm.template get_state<player_::State12&>().exit_counter=0; 113 fsm.template get_state<player_::State13&>().entry_counter=0; 114 fsm.template get_state<player_::State13&>().exit_counter=0; 115 fsm.template get_state<player_::State21&>().entry_counter=0; 116 fsm.template get_state<player_::State22&>().exit_counter=0; 117 } 118 }; 119 // Pick a back-end 120 typedef msm::back::state_machine<player_> player; 121 BOOST_AUTO_TEST_CASE(TestDeferIn2Regions)122 BOOST_AUTO_TEST_CASE( TestDeferIn2Regions ) 123 { 124 player p; 125 // needed to start the highest-level SM. This will call on_entry and mark the start of the SM 126 p.start(); 127 128 p.process_event(event1()); 129 BOOST_CHECK_MESSAGE(p.current_state()[0] == 1,"State12 should be active"); 130 BOOST_CHECK_MESSAGE(p.current_state()[1] == 2,"State21 should be active"); 131 BOOST_CHECK_MESSAGE(p.get_state<player_::State11&>().exit_counter == 1,"State11 exit not called correctly"); 132 BOOST_CHECK_MESSAGE(p.get_state<player_::State11&>().entry_counter == 1,"State11 entry not called correctly"); 133 BOOST_CHECK_MESSAGE(p.get_state<player_::State12&>().entry_counter == 1,"State12 entry not called correctly"); 134 135 // deferred 136 p.process_event(eventd()); 137 BOOST_CHECK_MESSAGE(p.current_state()[0] == 1,"State12 should be active"); 138 BOOST_CHECK_MESSAGE(p.current_state()[1] == 2,"State21 should be active"); 139 BOOST_CHECK_MESSAGE(p.get_state<player_::State11&>().exit_counter == 1,"State11 exit not called correctly"); 140 BOOST_CHECK_MESSAGE(p.get_state<player_::State11&>().entry_counter == 1,"State11 entry not called correctly"); 141 BOOST_CHECK_MESSAGE(p.get_state<player_::State12&>().entry_counter == 1,"State12 entry not called correctly"); 142 BOOST_CHECK_MESSAGE(p.get_state<player_::State12&>().exit_counter == 0,"State12 exit not called correctly"); 143 BOOST_CHECK_MESSAGE(p.get_state<player_::State21&>().exit_counter == 0,"State21 exit not called correctly"); 144 BOOST_CHECK_MESSAGE(p.get_state<player_::State21&>().entry_counter == 1,"State21 entry not called correctly"); 145 BOOST_CHECK_MESSAGE(p.get_state<player_::State22&>().exit_counter == 0,"State22 exit not called correctly"); 146 BOOST_CHECK_MESSAGE(p.get_state<player_::State22&>().entry_counter == 0,"State22 entry not called correctly"); 147 148 p.process_event(event3()); 149 BOOST_CHECK_MESSAGE(p.current_state()[0] == 1,"State12 should be active"); 150 BOOST_CHECK_MESSAGE(p.current_state()[1] == 2,"State21 should be active"); 151 BOOST_CHECK_MESSAGE(p.get_state<player_::State21&>().exit_counter == 1,"State21 exit not called correctly"); 152 BOOST_CHECK_MESSAGE(p.get_state<player_::State21&>().entry_counter == 2,"State21 entry not called correctly"); 153 BOOST_CHECK_MESSAGE(p.get_state<player_::State22&>().exit_counter == 1,"State22 exit not called correctly"); 154 BOOST_CHECK_MESSAGE(p.get_state<player_::State22&>().entry_counter == 1,"State22 entry not called correctly"); 155 BOOST_CHECK_MESSAGE(p.get_deferred_queue().size() == 1,"Deferred queue should have one element"); 156 p.clear_deferred_queue(); 157 158 p.process_event(event2()); 159 BOOST_CHECK_MESSAGE(p.current_state()[0] == 4,"State13 should be active"); 160 BOOST_CHECK_MESSAGE(p.current_state()[1] == 2,"State21 should be active"); 161 BOOST_CHECK_MESSAGE(p.get_state<player_::State21&>().exit_counter == 1,"State21 exit not called correctly"); 162 BOOST_CHECK_MESSAGE(p.get_state<player_::State21&>().entry_counter == 2,"State21 entry not called correctly"); 163 BOOST_CHECK_MESSAGE(p.get_state<player_::State22&>().exit_counter == 1,"State22 exit not called correctly"); 164 BOOST_CHECK_MESSAGE(p.get_state<player_::State22&>().entry_counter == 1,"State22 entry not called correctly"); 165 BOOST_CHECK_MESSAGE(p.get_deferred_queue().size() == 0,"Deferred queue should have no element"); 166 } 167 } 168 169 170