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__anonbbe716390111::event634         event6(){}
35         template <class Event>
event6__anonbbe716390111::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__anonbbe716390111::Fsm_::State145             void on_entry(Event const&,FSM& ) {++entry_counter;}
46             template <class Event,class FSM>
on_exit__anonbbe716390111::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__anonbbe716390111::Fsm_::State254             void on_entry(Event const&,FSM& ) {++entry_counter;}
55             template <class Event,class FSM>
on_exit__anonbbe716390111::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__anonbbe716390111::Fsm_::SubFsm2_67             void on_entry(Event const&,FSM& ) {++entry_counter;}
68             template <class Event,class FSM>
on_exit__anonbbe716390111::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__anonbbe716390111::Fsm_::SubFsm2_::SubState176                 void on_entry(Event const&,FSM& ) {++entry_counter;}
77                 template <class Event,class FSM>
on_exit__anonbbe716390111::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__anonbbe716390111::Fsm_::SubFsm2_::SubState1b85                 void on_entry(Event const&,FSM& ) {++entry_counter;}
86                 template <class Event,class FSM>
on_exit__anonbbe716390111::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__anonbbe716390111::Fsm_::SubFsm2_::SubState294                 void on_entry(Event const&,FSM& ) {++entry_counter;}
95                 template <class Event,class FSM>
on_exit__anonbbe716390111::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__anonbbe716390111::Fsm_::SubFsm2_::SubState2b103                 void on_entry(Event const&,FSM& ) {++entry_counter;}
104                 template <class Event,class FSM>
on_exit__anonbbe716390111::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__anonbbe716390111::Fsm_::SubFsm2_::PseudoEntry1113                 void on_entry(Event const&,FSM& ) {++entry_counter;}
114                 template <class Event,class FSM>
on_exit__anonbbe716390111::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__anonbbe716390111::Fsm_::SubFsm2_::SubState3122                 void on_entry(Event const&,FSM& ) {++entry_counter;}
123                 template <class Event,class FSM>
on_exit__anonbbe716390111::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__anonbbe716390111::Fsm_::SubFsm2_::PseudoExit1131                 void on_entry(Event const&,FSM& ) {++entry_counter;}
132                 template <class Event,class FSM>
on_exit__anonbbe716390111::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__anonbbe716390111::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__anonbbe716390111::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__anonbbe716390111::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__anonbbe716390111::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