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 eventResolve {}; 28 struct eventConnect {}; 29 struct eventResolved {}; 30 struct eventRead {}; 31 struct eventd {}; 32 33 34 // front-end: define the FSM structure 35 struct player_ : public msm::front::state_machine_def<player_> 36 { player___anonf5300ff00111::player_37 player_() 38 :expected_action_counter(0) 39 {} 40 41 struct enqueue_action1 42 { 43 template <class EVT,class FSM,class SourceState,class TargetState> operator ()__anonf5300ff00111::player_::enqueue_action144 void operator()(EVT const& ,FSM& fsm,SourceState& ,TargetState& ) 45 { 46 fsm.template process_event(eventResolve()); 47 } 48 }; 49 struct enqueue_action2 50 { 51 template <class EVT,class FSM,class SourceState,class TargetState> operator ()__anonf5300ff00111::player_::enqueue_action252 void operator()(EVT const& ,FSM& fsm,SourceState& ,TargetState& ) 53 { 54 fsm.template process_event(eventConnect()); 55 } 56 }; 57 struct expected_action 58 { 59 template <class EVT,class FSM,class SourceState,class TargetState> operator ()__anonf5300ff00111::player_::expected_action60 void operator()(EVT const& ,FSM& fsm,SourceState& ,TargetState& ) 61 { 62 ++fsm.expected_action_counter; 63 //std::cout << "expected action called" << std::endl; 64 } 65 }; 66 struct unexpected_action 67 { 68 template <class EVT,class FSM,class SourceState,class TargetState> operator ()__anonf5300ff00111::player_::unexpected_action69 void operator()(EVT const& ,FSM& fsm,SourceState& ,TargetState& ) 70 { 71 std::cout << "unexpected action called" << std::endl; 72 } 73 }; 74 75 // The list of FSM states 76 struct Unresolved : public msm::front::state<> 77 { 78 typedef mpl::vector<eventRead > deferred_events; 79 template <class Event,class FSM> on_entry__anonf5300ff00111::player_::Unresolved80 void on_entry(Event const&,FSM& ) {++entry_counter;} 81 template <class Event,class FSM> on_exit__anonf5300ff00111::player_::Unresolved82 void on_exit(Event const&,FSM& ) {++exit_counter;} 83 int entry_counter; 84 int exit_counter; 85 // Transition table for Empty 86 struct internal_transition_table : mpl::vector< 87 // Start Event Next Action Guard 88 Internal < eventConnect , msm::front::ActionSequence_<mpl::vector<enqueue_action1,enqueue_action2>> > 89 // +---------+-------------+---------+---------------------+----------------------+ 90 > {}; 91 }; 92 struct Resolving : public msm::front::state<> 93 { 94 typedef mpl::vector<eventConnect > deferred_events; 95 template <class Event,class FSM> on_entry__anonf5300ff00111::player_::Resolving96 void on_entry(Event const&,FSM& ) {++entry_counter;} 97 template <class Event,class FSM> on_exit__anonf5300ff00111::player_::Resolving98 void on_exit(Event const&,FSM& ) {++exit_counter;} 99 int entry_counter; 100 int exit_counter; 101 }; 102 struct Resolved : public msm::front::state<> 103 { 104 template <class Event,class FSM> on_entry__anonf5300ff00111::player_::Resolved105 void on_entry(Event const&,FSM& ) {++entry_counter;} 106 template <class Event,class FSM> on_exit__anonf5300ff00111::player_::Resolved107 void on_exit(Event const&,FSM& ) {++exit_counter;} 108 int entry_counter; 109 int exit_counter; 110 }; 111 struct Connecting : public msm::front::state<> 112 { 113 template <class Event,class FSM> on_entry__anonf5300ff00111::player_::Connecting114 void on_entry(Event const&,FSM& ) {++entry_counter;} 115 template <class Event,class FSM> on_exit__anonf5300ff00111::player_::Connecting116 void on_exit(Event const&,FSM& ) {++exit_counter;} 117 int entry_counter; 118 int exit_counter; 119 }; 120 struct State22 : public msm::front::state<> 121 { 122 template <class Event,class FSM> on_entry__anonf5300ff00111::player_::State22123 void on_entry(Event const&,FSM& ) {++entry_counter;} 124 template <class Event,class FSM> on_exit__anonf5300ff00111::player_::State22125 void on_exit(Event const&,FSM& ) {++exit_counter;} 126 int entry_counter; 127 int exit_counter; 128 }; 129 // the initial state of the player SM. Must be defined 130 typedef mpl::vector<Unresolved,State22> initial_state; 131 132 133 // Transition table for player 134 struct transition_table : mpl::vector< 135 // Start Event Next Action Guard 136 // +---------+-------------+---------+---------------------+----------------------+ 137 Row < Unresolved , eventResolve , Resolving >, 138 Row < Resolving , eventResolved , Resolved >, 139 Row < Resolved , eventConnect , Connecting , expected_action >, 140 Row < State22 , eventd , State22 > 141 // +---------+-------------+---------+---------------------+----------------------+ 142 > {}; 143 144 // Replaces the default no-transition response. 145 template <class FSM,class Event> no_transition__anonf5300ff00111::player_146 void no_transition(Event const& , FSM&,int ) 147 { 148 BOOST_FAIL("no_transition called!"); 149 } 150 // init counters 151 template <class Event,class FSM> on_entry__anonf5300ff00111::player_152 void on_entry(Event const&,FSM& fsm) 153 { 154 fsm.template get_state<player_::Unresolved&>().entry_counter=0; 155 fsm.template get_state<player_::Unresolved&>().exit_counter=0; 156 fsm.template get_state<player_::Resolving&>().entry_counter=0; 157 fsm.template get_state<player_::Resolving&>().exit_counter=0; 158 fsm.template get_state<player_::Resolved&>().entry_counter=0; 159 fsm.template get_state<player_::Resolved&>().exit_counter=0; 160 fsm.template get_state<player_::Connecting&>().entry_counter=0; 161 fsm.template get_state<player_::Connecting&>().exit_counter=0; 162 } 163 int expected_action_counter; 164 }; 165 // Pick a back-end 166 typedef msm::back::state_machine<player_> player; 167 BOOST_AUTO_TEST_CASE(TestDeferAndMessageQueue)168 BOOST_AUTO_TEST_CASE( TestDeferAndMessageQueue ) 169 { 170 player p; 171 // needed to start the highest-level SM. This will call on_entry and mark the start of the SM 172 p.start(); 173 174 p.process_event(eventConnect()); 175 BOOST_CHECK_MESSAGE(p.current_state()[0] == 1,"Resolving should be active"); 176 BOOST_CHECK_MESSAGE(p.current_state()[1] == 3,"State22 should be active"); 177 BOOST_CHECK_MESSAGE(p.get_state<player_::Unresolved&>().exit_counter == 1,"Unresolved exit not called correctly"); 178 BOOST_CHECK_MESSAGE(p.get_state<player_::Unresolved&>().entry_counter == 1,"Unresolved entry not called correctly"); 179 BOOST_CHECK_MESSAGE(p.get_state<player_::Resolving&>().entry_counter == 1,"Resolving entry not called correctly"); 180 181 p.process_event(eventResolved()); 182 BOOST_CHECK_MESSAGE(p.current_state()[0] == 4,"Connecting should be active"); 183 BOOST_CHECK_MESSAGE(p.current_state()[1] == 3,"State22 should be active"); 184 BOOST_CHECK_MESSAGE(p.get_state<player_::Resolved&>().exit_counter == 1,"Resolved exit not called correctly"); 185 BOOST_CHECK_MESSAGE(p.get_state<player_::Resolved&>().entry_counter == 1,"Resolved entry not called correctly"); 186 BOOST_CHECK_MESSAGE(p.get_state<player_::Resolving&>().exit_counter == 1,"Resolving exit not called correctly"); 187 BOOST_CHECK_MESSAGE(p.get_state<player_::Connecting&>().entry_counter == 1,"Connecting entry not called correctly"); 188 189 BOOST_CHECK_MESSAGE(p.expected_action_counter == 1,"expected_action should have been called"); 190 191 } 192 } 193 194 195