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)
13 #include <boost/msm/back/state_machine.hpp>
15 #include <boost/msm/front/state_machine_def.hpp>
16 #include <boost/msm/front/functor_row.hpp>
18 #include <boost/test/unit_test.hpp>
20 namespace msm = boost::msm;
21 namespace mpl = boost::mpl;
22 using namespace boost::msm::front;
27 struct eventResolve {};
28 struct eventConnect {};
29 struct eventResolved {};
34 // front-end: define the FSM structure
35 struct player_ : public msm::front::state_machine_def<player_>
38 :expected_action_counter(0)
41 struct enqueue_action1
43 template <class EVT,class FSM,class SourceState,class TargetState>
44 void operator()(EVT const& ,FSM& fsm,SourceState& ,TargetState& )
46 fsm.template process_event(eventResolve());
49 struct enqueue_action2
51 template <class EVT,class FSM,class SourceState,class TargetState>
52 void operator()(EVT const& ,FSM& fsm,SourceState& ,TargetState& )
54 fsm.template process_event(eventConnect());
57 struct expected_action
59 template <class EVT,class FSM,class SourceState,class TargetState>
60 void operator()(EVT const& ,FSM& fsm,SourceState& ,TargetState& )
62 ++fsm.expected_action_counter;
63 //std::cout << "expected action called" << std::endl;
66 struct unexpected_action
68 template <class EVT,class FSM,class SourceState,class TargetState>
69 void operator()(EVT const& ,FSM& fsm,SourceState& ,TargetState& )
71 std::cout << "unexpected action called" << std::endl;
75 // The list of FSM states
76 struct Unresolved : public msm::front::state<>
78 typedef mpl::vector<eventRead > deferred_events;
79 template <class Event,class FSM>
80 void on_entry(Event const&,FSM& ) {++entry_counter;}
81 template <class Event,class FSM>
82 void on_exit(Event const&,FSM& ) {++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 // +---------+-------------+---------+---------------------+----------------------+
92 struct Resolving : public msm::front::state<>
94 typedef mpl::vector<eventConnect > deferred_events;
95 template <class Event,class FSM>
96 void on_entry(Event const&,FSM& ) {++entry_counter;}
97 template <class Event,class FSM>
98 void on_exit(Event const&,FSM& ) {++exit_counter;}
102 struct Resolved : public msm::front::state<>
104 template <class Event,class FSM>
105 void on_entry(Event const&,FSM& ) {++entry_counter;}
106 template <class Event,class FSM>
107 void on_exit(Event const&,FSM& ) {++exit_counter;}
111 struct Connecting : public msm::front::state<>
113 template <class Event,class FSM>
114 void on_entry(Event const&,FSM& ) {++entry_counter;}
115 template <class Event,class FSM>
116 void on_exit(Event const&,FSM& ) {++exit_counter;}
120 struct State22 : public msm::front::state<>
122 template <class Event,class FSM>
123 void on_entry(Event const&,FSM& ) {++entry_counter;}
124 template <class Event,class FSM>
125 void on_exit(Event const&,FSM& ) {++exit_counter;}
129 // the initial state of the player SM. Must be defined
130 typedef mpl::vector<Unresolved,State22> initial_state;
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 // +---------+-------------+---------+---------------------+----------------------+
144 // Replaces the default no-transition response.
145 template <class FSM,class Event>
146 void no_transition(Event const& , FSM&,int )
148 BOOST_FAIL("no_transition called!");
151 template <class Event,class FSM>
152 void on_entry(Event const&,FSM& fsm)
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;
163 int expected_action_counter;
166 typedef msm::back::state_machine<player_> player;
168 BOOST_AUTO_TEST_CASE( TestDeferAndMessageQueue )
171 // needed to start the highest-level SM. This will call on_entry and mark the start of the SM
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");
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");
189 BOOST_CHECK_MESSAGE(p.expected_action_counter == 1,"expected_action should have been called");