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 play {};
28     struct end_pause {};
29     struct stop {};
30     struct pause {};
31     struct open_close {};
32     struct NextSong {};
33     struct PreviousSong {};
34     struct error_found {};
35     struct end_error {};
36     struct do_terminate {};
37 
38     // Flags. Allow information about a property of the current state
39     struct PlayingPaused{};
40     struct CDLoaded {};
41     struct FirstSongPlaying {};
42 
43     // A "complicated" event type that carries some data.
44     struct cd_detected
45     {
cd_detected__anon8a172adb0111::cd_detected46         cd_detected(std::string name)
47             : name(name)
48         {}
49 
50         std::string name;
51     };
52 
53     // front-end: define the FSM structure
54     struct player_ : public msm::front::state_machine_def<player_>
55     {
56         unsigned int start_playback_counter;
57         unsigned int can_close_drawer_counter;
58         unsigned int report_error_counter;
59         unsigned int report_end_error_counter;
60 
player___anon8a172adb0111::player_61         player_():
62         start_playback_counter(0),
63         can_close_drawer_counter(0),
64         report_error_counter(0),
65         report_end_error_counter(0)
66         {}
67         // The list of FSM states
68         struct Empty : public msm::front::state<>
69         {
70             typedef mpl::vector<play> deferred_events;
71             template <class Event,class FSM>
on_entry__anon8a172adb0111::player_::Empty72             void on_entry(Event const&,FSM& ) {++entry_counter;}
73             template <class Event,class FSM>
on_exit__anon8a172adb0111::player_::Empty74             void on_exit(Event const&,FSM& ) {++exit_counter;}
75             int entry_counter;
76             int exit_counter;
77         };
78         struct Open : public msm::front::state<>
79         {
80             typedef mpl::vector<play> deferred_events;
81             typedef mpl::vector1<CDLoaded>      flag_list;
82 
83             template <class Event,class FSM>
on_entry__anon8a172adb0111::player_::Open84             void on_entry(Event const&,FSM& ) {++entry_counter;}
85             template <class Event,class FSM>
on_exit__anon8a172adb0111::player_::Open86             void on_exit(Event const&,FSM& ) {++exit_counter;}
87             int entry_counter;
88             int exit_counter;
89         };
90 
91         struct Stopped : public msm::front::state<>
92         {
93             typedef mpl::vector1<CDLoaded>      flag_list;
94 
95             template <class Event,class FSM>
on_entry__anon8a172adb0111::player_::Stopped96             void on_entry(Event const&,FSM& ) {++entry_counter;}
97             template <class Event,class FSM>
on_exit__anon8a172adb0111::player_::Stopped98             void on_exit(Event const&,FSM& ) {++exit_counter;}
99             int entry_counter;
100             int exit_counter;
101         };
102 
103         // the player state machine contains a state which is himself a state machine
104         // as you see, no need to declare it anywhere so Playing can be developed separately
105         // by another team in another module. For simplicity I just declare it inside player
106         struct Playing_ : public msm::front::state_machine_def<Playing_>
107         {
108             // when playing, the CD is loaded and we are in either pause or playing (duh)
109             typedef mpl::vector2<PlayingPaused,CDLoaded>        flag_list;
110 
111             template <class Event,class FSM>
on_entry__anon8a172adb0111::player_::Playing_112             void on_entry(Event const&,FSM& ) {++entry_counter;}
113             template <class Event,class FSM>
on_exit__anon8a172adb0111::player_::Playing_114             void on_exit(Event const&,FSM& ) {++exit_counter;}
115             int entry_counter;
116             int exit_counter;
117             unsigned int start_next_song_counter;
118             unsigned int start_prev_song_guard_counter;
119 
Playing___anon8a172adb0111::player_::Playing_120             Playing_():
121             start_next_song_counter(0),
122             start_prev_song_guard_counter(0)
123             {}
124 
125             // The list of FSM states
126             struct Song1 : public msm::front::state<>
127             {
128                 typedef mpl::vector1<FirstSongPlaying>      flag_list;
129 
130                 template <class Event,class FSM>
on_entry__anon8a172adb0111::player_::Playing_::Song1131                 void on_entry(Event const&,FSM& ) {++entry_counter;}
132                 template <class Event,class FSM>
on_exit__anon8a172adb0111::player_::Playing_::Song1133                 void on_exit(Event const&,FSM& ) {++exit_counter;}
134                 int entry_counter;
135                 int exit_counter;
136             };
137             struct Song2 : public msm::front::state<>
138             {
139                 template <class Event,class FSM>
on_entry__anon8a172adb0111::player_::Playing_::Song2140                 void on_entry(Event const&,FSM& ) {++entry_counter;}
141                 template <class Event,class FSM>
on_exit__anon8a172adb0111::player_::Playing_::Song2142                 void on_exit(Event const&,FSM& ) {++exit_counter;}
143                 int entry_counter;
144                 int exit_counter;
145             };
146             struct Song3 : public msm::front::state<>
147             {
148                 template <class Event,class FSM>
on_entry__anon8a172adb0111::player_::Playing_::Song3149                 void on_entry(Event const&,FSM& ) {++entry_counter;}
150                 template <class Event,class FSM>
on_exit__anon8a172adb0111::player_::Playing_::Song3151                 void on_exit(Event const&,FSM& ) {++exit_counter;}
152                 int entry_counter;
153                 int exit_counter;
154             };
155             // the initial state. Must be defined
156             typedef Song1 initial_state;
157             // transition actions
start_next_song__anon8a172adb0111::player_::Playing_158             void start_next_song(NextSong const&)       {++start_next_song_counter; }
start_prev_song__anon8a172adb0111::player_::Playing_159             void start_prev_song(PreviousSong const&)       {  }
160             // guard conditions
start_prev_song_guard__anon8a172adb0111::player_::Playing_161             bool start_prev_song_guard(PreviousSong const&)       {++start_prev_song_guard_counter;return true; }
162 
163             typedef Playing_ pl; // makes transition table cleaner
164             // Transition table for Playing
165             struct transition_table : mpl::vector4<
166                 //      Start     Event         Next      Action               Guard
167                 //    +---------+-------------+---------+---------------------+----------------------+
168                  _row < Song1   , NextSong    , Song2                                                >,
169                   row < Song2   , PreviousSong, Song1   , &pl::start_prev_song,&pl::start_prev_song_guard>,
170                 a_row < Song2   , NextSong    , Song3   , &pl::start_next_song                       >,
171                 g_row < Song3   , PreviousSong, Song2                         ,&pl::start_prev_song_guard>
172                 //    +---------+-------------+---------+---------------------+----------------------+
173             > {};
174             // Replaces the default no-transition response.
175             template <class FSM,class Event>
no_transition__anon8a172adb0111::player_::Playing_176             void no_transition(Event const&, FSM&,int)
177             {
178                 BOOST_FAIL("no_transition called!");
179             }
180         };
181         // back-end
182         typedef msm::back::state_machine<Playing_> Playing;
183 
184         // state not defining any entry or exit
185         struct Paused : public msm::front::state<>
186         {
187             typedef mpl::vector2<PlayingPaused,CDLoaded>        flag_list;
188 
189             template <class Event,class FSM>
on_entry__anon8a172adb0111::player_::Paused190             void on_entry(Event const&,FSM& ) {++entry_counter;}
191             template <class Event,class FSM>
on_exit__anon8a172adb0111::player_::Paused192             void on_exit(Event const&,FSM& ) {++exit_counter;}
193             int entry_counter;
194             int exit_counter;
195         };
196         struct AllOk : public msm::front::state<>
197         {
198             template <class Event,class FSM>
on_entry__anon8a172adb0111::player_::AllOk199             void on_entry(Event const&,FSM& ) {++entry_counter;}
200             template <class Event,class FSM>
on_exit__anon8a172adb0111::player_::AllOk201             void on_exit(Event const&,FSM& ) {++exit_counter;}
202             int entry_counter;
203             int exit_counter;
204         };
205         // this state is also made terminal so that all the events are blocked
206         struct ErrorMode :  //public msm::front::terminate_state<> // ErrorMode terminates the state machine
207             public msm::front::interrupt_state<end_error>   // ErroMode just interrupts. Will resume if
208                                                             // the event end_error is generated
209         {
210             template <class Event,class FSM>
on_entry__anon8a172adb0111::player_::ErrorMode211             void on_entry(Event const&,FSM& ) {++entry_counter;}
212             template <class Event,class FSM>
on_exit__anon8a172adb0111::player_::ErrorMode213             void on_exit(Event const&,FSM& ) {++exit_counter;}
214             int entry_counter;
215             int exit_counter;
216         };
217         struct ErrorTerminate :  public msm::front::terminate_state<> // terminates the state machine
218         {
219             template <class Event,class FSM>
on_entry__anon8a172adb0111::player_::ErrorTerminate220             void on_entry(Event const&,FSM& ) {++entry_counter;}
221             template <class Event,class FSM>
on_exit__anon8a172adb0111::player_::ErrorTerminate222             void on_exit(Event const&,FSM& ) {++exit_counter;}
223             int entry_counter;
224             int exit_counter;
225         };
226         // the initial state of the player SM. Must be defined
227         typedef mpl::vector<Empty,AllOk> initial_state;
228 
229         // transition actions
start_playback__anon8a172adb0111::player_230         void start_playback(play const&)       {++start_playback_counter; }
open_drawer__anon8a172adb0111::player_231         void open_drawer(open_close const&)    {  }
store_cd_info__anon8a172adb0111::player_232         void store_cd_info(cd_detected const&) {  }
stop_playback__anon8a172adb0111::player_233         void stop_playback(stop const&)        {  }
pause_playback__anon8a172adb0111::player_234         void pause_playback(pause const&)      {  }
resume_playback__anon8a172adb0111::player_235         void resume_playback(end_pause const&)      {  }
stop_and_open__anon8a172adb0111::player_236         void stop_and_open(open_close const&)  {  }
stopped_again__anon8a172adb0111::player_237         void stopped_again(stop const&){}
report_error__anon8a172adb0111::player_238         void report_error(error_found const&) {++report_error_counter;}
report_end_error__anon8a172adb0111::player_239         void report_end_error(end_error const&) {++report_end_error_counter;}
240 
241         //guards
can_close_drawer__anon8a172adb0111::player_242         bool can_close_drawer(open_close const&)
243         {
244             ++can_close_drawer_counter;
245             return true;
246         }
247         typedef player_ p; // makes transition table cleaner
248 
249         // Transition table for player
250         struct transition_table : mpl::vector<
251             //      Start     Event         Next      Action               Guard
252             //    +---------+-------------+---------+---------------------+----------------------+
253             a_row < Stopped , play        , Playing , &p::start_playback                         >,
254             a_row < Stopped , open_close  , Open    , &p::open_drawer                            >,
255              _row < Stopped , stop        , Stopped                                              >,
256             //  +---------+-------------+---------+---------------------+----------------------+
257             g_row < Open    , open_close  , Empty   ,                      &p::can_close_drawer  >,
258             //  +---------+-------------+---------+---------------------+----------------------+
259             a_row < Empty   , open_close  , Open    , &p::open_drawer                            >,
260             a_row < Empty   , cd_detected , Stopped , &p::store_cd_info                          >,
261             //  +---------+-------------+---------+---------------------+----------------------+
262             a_row < Playing , stop        , Stopped , &p::stop_playback                          >,
263             a_row < Playing , pause       , Paused  , &p::pause_playback                         >,
264             a_row < Playing , open_close  , Open    , &p::stop_and_open                          >,
265             //  +---------+-------------+---------+---------------------+----------------------+
266             a_row < Paused  , end_pause   , Playing , &p::resume_playback                        >,
267             a_row < Paused  , stop        , Stopped , &p::stop_playback                          >,
268             a_row < Paused  , open_close  , Open    , &p::stop_and_open                          >,
269             //    +---------+-------------+---------+---------------------+----------------------+
270             a_row < AllOk   , error_found ,ErrorMode, &p::report_error                           >,
271             a_row <ErrorMode, end_error   ,AllOk    , &p::report_end_error                       >,
272              _row < AllOk   , do_terminate,ErrorTerminate                                        >
273             //    +---------+-------------+---------+---------------------+----------------------+
274         > {};
275 
276         // Replaces the default no-transition response.
277         template <class FSM,class Event>
no_transition__anon8a172adb0111::player_278         void no_transition(Event const& , FSM&,int )
279         {
280             BOOST_FAIL("no_transition called!");
281         }
282         // init counters
283         template <class Event,class FSM>
on_entry__anon8a172adb0111::player_284         void on_entry(Event const&,FSM& fsm)
285         {
286             fsm.template get_state<player_::Stopped&>().entry_counter=0;
287             fsm.template get_state<player_::Stopped&>().exit_counter=0;
288             fsm.template get_state<player_::Open&>().entry_counter=0;
289             fsm.template get_state<player_::Open&>().exit_counter=0;
290             fsm.template get_state<player_::Empty&>().entry_counter=0;
291             fsm.template get_state<player_::Empty&>().exit_counter=0;
292             fsm.template get_state<player_::Playing&>().entry_counter=0;
293             fsm.template get_state<player_::Playing&>().exit_counter=0;
294             fsm.template get_state<player_::Playing&>().template get_state<player_::Playing::Song1&>().entry_counter=0;
295             fsm.template get_state<player_::Playing&>().template get_state<player_::Playing::Song1&>().exit_counter=0;
296             fsm.template get_state<player_::Playing&>().template get_state<player_::Playing::Song2&>().entry_counter=0;
297             fsm.template get_state<player_::Playing&>().template get_state<player_::Playing::Song2&>().exit_counter=0;
298             fsm.template get_state<player_::Playing&>().template get_state<player_::Playing::Song3&>().entry_counter=0;
299             fsm.template get_state<player_::Playing&>().template get_state<player_::Playing::Song3&>().exit_counter=0;
300             fsm.template get_state<player_::Paused&>().entry_counter=0;
301             fsm.template get_state<player_::Paused&>().exit_counter=0;
302             fsm.template get_state<player_::AllOk&>().entry_counter=0;
303             fsm.template get_state<player_::AllOk&>().exit_counter=0;
304             fsm.template get_state<player_::ErrorMode&>().entry_counter=0;
305             fsm.template get_state<player_::ErrorMode&>().exit_counter=0;
306             fsm.template get_state<player_::ErrorTerminate&>().entry_counter=0;
307             fsm.template get_state<player_::ErrorTerminate&>().exit_counter=0;
308         }
309     };
310     // Pick a back-end
311     typedef msm::back::state_machine<player_> player;
312 
313     //static char const* const state_names[] = { "Stopped", "Open", "Empty", "Playing", "Paused","AllOk","ErrorMode" };
314 
BOOST_AUTO_TEST_CASE(my_test)315     BOOST_AUTO_TEST_CASE( my_test )
316     {
317         player p;
318         // needed to start the highest-level SM. This will call on_entry and mark the start of the SM
319         p.start();
320         // test deferred event
321         // deferred in Empty and Open, will be handled only after event cd_detected
322         p.process_event(play());
323         BOOST_CHECK_MESSAGE(p.current_state()[0] == 2,"Empty should be active"); //Empty
324         BOOST_CHECK_MESSAGE(p.get_state<player_::Open&>().exit_counter == 0,"Open exit not called correctly");
325         BOOST_CHECK_MESSAGE(p.get_state<player_::Playing&>().entry_counter == 0,"Playing entry not called correctly");
326         BOOST_CHECK_MESSAGE(p.get_state<player_::Empty&>().entry_counter == 1,"Empty entry not called correctly");
327         //flags
328         BOOST_CHECK_MESSAGE(p.is_flag_active<CDLoaded>() == false,"CDLoaded should not be active");
329 
330         p.process_event(open_close());
331         BOOST_CHECK_MESSAGE(p.current_state()[0] == 1,"Open should be active"); //Open
332         BOOST_CHECK_MESSAGE(p.get_state<player_::Empty&>().exit_counter == 1,"Empty exit not called correctly");
333         BOOST_CHECK_MESSAGE(p.get_state<player_::Open&>().entry_counter == 1,"Open entry not called correctly");
334 
335         p.process_event(open_close());
336         BOOST_CHECK_MESSAGE(p.current_state()[0] == 2,"Empty should be active"); //Empty
337         BOOST_CHECK_MESSAGE(p.get_state<player_::Open&>().exit_counter == 1,"Open exit not called correctly");
338         BOOST_CHECK_MESSAGE(p.get_state<player_::Empty&>().entry_counter == 2,"Empty entry not called correctly");
339         BOOST_CHECK_MESSAGE(p.can_close_drawer_counter == 1,"guard not called correctly");
340 
341         //deferred event should have been processed
342         p.process_event(cd_detected("louie, louie"));
343         BOOST_CHECK_MESSAGE(p.current_state()[0] == 3,"Playing should be active"); //Playing
344         BOOST_CHECK_MESSAGE(p.get_state<player_::Empty&>().exit_counter == 2,"Empty exit not called correctly");
345         BOOST_CHECK_MESSAGE(p.get_state<player_::Stopped&>().entry_counter == 1,"Stopped entry not called correctly");
346         BOOST_CHECK_MESSAGE(p.get_state<player_::Stopped&>().exit_counter == 1,"Stopped exit not called correctly");
347         BOOST_CHECK_MESSAGE(p.get_state<player_::Playing&>().entry_counter == 1,"Playing entry not called correctly");
348         BOOST_CHECK_MESSAGE(p.start_playback_counter == 1,"action not called correctly");
349         BOOST_CHECK_MESSAGE(p.get_state<player_::Playing&>().current_state()[0] == 0,"Song1 should be active");
350         BOOST_CHECK_MESSAGE(
351             p.get_state<player_::Playing&>().get_state<player_::Playing::Song1&>().entry_counter == 1,
352             "Song1 entry not called correctly");
353 
354         //flags
355         BOOST_CHECK_MESSAGE(p.is_flag_active<PlayingPaused>() == true,"PlayingPaused should be active");
356         BOOST_CHECK_MESSAGE(p.is_flag_active<FirstSongPlaying>() == true,"FirstSongPlaying should be active");
357 
358 
359         p.process_event(NextSong());
360         BOOST_CHECK_MESSAGE(p.current_state()[0] == 3,"Playing should be active"); //Playing
361         BOOST_CHECK_MESSAGE(p.get_state<player_::Playing&>().current_state()[0] == 1,"Song2 should be active");
362         BOOST_CHECK_MESSAGE(
363             p.get_state<player_::Playing&>().get_state<player_::Playing::Song2&>().entry_counter == 1,
364             "Song2 entry not called correctly");
365         BOOST_CHECK_MESSAGE(
366             p.get_state<player_::Playing&>().get_state<player_::Playing::Song1&>().exit_counter == 1,
367             "Song1 exit not called correctly");
368         BOOST_CHECK_MESSAGE(
369             p.get_state<player_::Playing&>().start_next_song_counter == 0,
370             "submachine action not called correctly");
371 
372         p.process_event(NextSong());
373         BOOST_CHECK_MESSAGE(p.current_state()[0] == 3,"Playing should be active"); //Playing
374         BOOST_CHECK_MESSAGE(p.get_state<player_::Playing&>().current_state()[0] == 2,"Song3 should be active");
375         BOOST_CHECK_MESSAGE(
376             p.get_state<player_::Playing&>().get_state<player_::Playing::Song3&>().entry_counter == 1,
377             "Song3 entry not called correctly");
378         BOOST_CHECK_MESSAGE(
379             p.get_state<player_::Playing&>().get_state<player_::Playing::Song2&>().exit_counter == 1,
380             "Song2 exit not called correctly");
381         BOOST_CHECK_MESSAGE(
382             p.get_state<player_::Playing&>().start_next_song_counter == 1,
383             "submachine action not called correctly");
384 
385         p.process_event(PreviousSong());
386         BOOST_CHECK_MESSAGE(p.current_state()[0] == 3,"Playing should be active"); //Playing
387         BOOST_CHECK_MESSAGE(p.get_state<player_::Playing&>().current_state()[0] == 1,"Song2 should be active");
388         BOOST_CHECK_MESSAGE(
389             p.get_state<player_::Playing&>().get_state<player_::Playing::Song2&>().entry_counter == 2,
390             "Song2 entry not called correctly");
391         BOOST_CHECK_MESSAGE(
392             p.get_state<player_::Playing&>().get_state<player_::Playing::Song3&>().exit_counter == 1,
393             "Song3 exit not called correctly");
394         BOOST_CHECK_MESSAGE(
395             p.get_state<player_::Playing&>().start_prev_song_guard_counter == 1,
396             "submachine guard not called correctly");
397         //flags
398         BOOST_CHECK_MESSAGE(p.is_flag_active<PlayingPaused>() == true,"PlayingPaused should be active");
399         BOOST_CHECK_MESSAGE(p.is_flag_active<FirstSongPlaying>() == false,"FirstSongPlaying should not be active");
400 
401         p.process_event(pause());
402         BOOST_CHECK_MESSAGE(p.current_state()[0] == 4,"Paused should be active"); //Paused
403         BOOST_CHECK_MESSAGE(p.get_state<player_::Playing&>().exit_counter == 1,"Playing exit not called correctly");
404         BOOST_CHECK_MESSAGE(p.get_state<player_::Paused&>().entry_counter == 1,"Paused entry not called correctly");
405         //flags
406         BOOST_CHECK_MESSAGE(p.is_flag_active<PlayingPaused>() == true,"PlayingPaused should be active");
407 
408         // go back to Playing
409         p.process_event(end_pause());
410         BOOST_CHECK_MESSAGE(p.current_state()[0] == 3,"Playing should be active"); //Playing
411         BOOST_CHECK_MESSAGE(p.get_state<player_::Paused&>().exit_counter == 1,"Paused exit not called correctly");
412         BOOST_CHECK_MESSAGE(p.get_state<player_::Playing&>().entry_counter == 2,"Playing entry not called correctly");
413 
414         p.process_event(pause());
415         BOOST_CHECK_MESSAGE(p.current_state()[0] == 4,"Paused should be active"); //Paused
416         BOOST_CHECK_MESSAGE(p.get_state<player_::Playing&>().exit_counter == 2,"Playing exit not called correctly");
417         BOOST_CHECK_MESSAGE(p.get_state<player_::Paused&>().entry_counter == 2,"Paused entry not called correctly");
418 
419         p.process_event(stop());
420         BOOST_CHECK_MESSAGE(p.current_state()[0] == 0,"Stopped should be active"); //Stopped
421         BOOST_CHECK_MESSAGE(p.get_state<player_::Paused&>().exit_counter == 2,"Paused exit not called correctly");
422         BOOST_CHECK_MESSAGE(p.get_state<player_::Stopped&>().entry_counter == 2,"Stopped entry not called correctly");
423         //flags
424         BOOST_CHECK_MESSAGE(p.is_flag_active<PlayingPaused>() == false,"PlayingPaused should not be active");
425         BOOST_CHECK_MESSAGE(p.is_flag_active<CDLoaded>() == true,"CDLoaded should be active");
426         //BOOST_CHECK_MESSAGE(p.is_flag_active<CDLoaded,player::Flag_AND>() == false,"CDLoaded with AND should not be active");
427 
428         p.process_event(stop());
429         BOOST_CHECK_MESSAGE(p.current_state()[0] == 0,"Stopped should be active"); //Stopped
430         BOOST_CHECK_MESSAGE(p.get_state<player_::Stopped&>().exit_counter == 2,"Stopped exit not called correctly");
431         BOOST_CHECK_MESSAGE(p.get_state<player_::Stopped&>().entry_counter == 3,"Stopped entry not called correctly");
432 
433         //test interrupt
434         BOOST_CHECK_MESSAGE(p.current_state()[1] == 5,"AllOk should be active"); //AllOk
435         p.process_event(error_found());
436         BOOST_CHECK_MESSAGE(p.current_state()[1] == 6,"ErrorMode should be active"); //ErrorMode
437         BOOST_CHECK_MESSAGE(p.get_state<player_::AllOk&>().exit_counter == 1,"AllOk exit not called correctly");
438         BOOST_CHECK_MESSAGE(p.get_state<player_::ErrorMode&>().entry_counter == 1,"ErrorMode entry not called correctly");
439 
440         // try generating more events
441         p.process_event(play());
442         BOOST_CHECK_MESSAGE(p.current_state()[1] == 6,"ErrorMode should be active"); //ErrorMode
443         BOOST_CHECK_MESSAGE(p.get_state<player_::AllOk&>().exit_counter == 1,"AllOk exit not called correctly");
444         BOOST_CHECK_MESSAGE(p.get_state<player_::ErrorMode&>().entry_counter == 1,"ErrorMode entry not called correctly");
445         BOOST_CHECK_MESSAGE(p.current_state()[0] == 0,"Stopped should be active"); //Stopped
446         BOOST_CHECK_MESSAGE(p.get_state<player_::Stopped&>().exit_counter == 2,"Stopped exit not called correctly");
447         BOOST_CHECK_MESSAGE(p.get_state<player_::Stopped&>().entry_counter == 3,"Stopped entry not called correctly");
448 
449         p.process_event(end_error());
450         BOOST_CHECK_MESSAGE(p.current_state()[1] == 5,"AllOk should be active"); //AllOk
451         BOOST_CHECK_MESSAGE(p.get_state<player_::ErrorMode&>().exit_counter == 1,"ErrorMode exit not called correctly");
452         BOOST_CHECK_MESSAGE(p.get_state<player_::AllOk&>().entry_counter == 2,"AllOk entry not called correctly");
453 
454         p.process_event(play());
455         BOOST_CHECK_MESSAGE(p.current_state()[0] == 3,"Playing should be active"); //Playing
456         BOOST_CHECK_MESSAGE(p.get_state<player_::Stopped&>().exit_counter == 3,"Stopped exit not called correctly");
457         BOOST_CHECK_MESSAGE(p.get_state<player_::Playing&>().entry_counter == 3,"Playing entry not called correctly");
458 
459         //test terminate
460         BOOST_CHECK_MESSAGE(p.current_state()[1] == 5,"AllOk should be active"); //AllOk
461         p.process_event(do_terminate());
462         BOOST_CHECK_MESSAGE(p.current_state()[1] == 7,"ErrorTerminate should be active"); //ErrorTerminate
463         BOOST_CHECK_MESSAGE(p.get_state<player_::AllOk&>().exit_counter == 2,"AllOk exit not called correctly");
464         BOOST_CHECK_MESSAGE(p.get_state<player_::ErrorTerminate&>().entry_counter == 1,"ErrorTerminate entry not called correctly");
465 
466         // try generating more events
467         p.process_event(stop());
468         BOOST_CHECK_MESSAGE(p.current_state()[1] == 7,"ErrorTerminate should be active"); //ErrorTerminate
469         BOOST_CHECK_MESSAGE(p.get_state<player_::ErrorTerminate&>().exit_counter == 0,"ErrorTerminate exit not called correctly");
470         BOOST_CHECK_MESSAGE(p.current_state()[0] == 3,"Playing should be active"); //Playing
471         BOOST_CHECK_MESSAGE(p.get_state<player_::Playing&>().exit_counter == 2,"Playing exit not called correctly");
472         BOOST_CHECK_MESSAGE(p.get_state<player_::Stopped&>().entry_counter == 3,"Stopped entry not called correctly");
473 
474         p.process_event(end_error());
475         BOOST_CHECK_MESSAGE(p.current_state()[1] == 7,"ErrorTerminate should be active"); //ErrorTerminate
476         BOOST_CHECK_MESSAGE(p.current_state()[0] == 3,"Playing should be active"); //Playing
477         BOOST_CHECK_MESSAGE(p.get_state<player_::Playing&>().exit_counter == 2,"Playing exit not called correctly");
478         BOOST_CHECK_MESSAGE(p.get_state<player_::Stopped&>().entry_counter == 3,"Stopped entry not called correctly");
479 
480         p.process_event(stop());
481         BOOST_CHECK_MESSAGE(p.current_state()[1] == 7,"ErrorTerminate should be active"); //ErrorTerminate
482         BOOST_CHECK_MESSAGE(p.current_state()[0] == 3,"Playing should be active"); //Playing
483         BOOST_CHECK_MESSAGE(p.get_state<player_::Playing&>().exit_counter == 2,"Playing exit not called correctly");
484         BOOST_CHECK_MESSAGE(p.get_state<player_::Stopped&>().entry_counter == 3,"Stopped entry not called correctly");
485 
486     }
487 }
488 
489