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 #ifndef BOOST_MSM_NONSTANDALONE_TEST 19 #define BOOST_TEST_MODULE MyTest 20 #endif 21 #include <boost/test/unit_test.hpp> 22 23 namespace msm = boost::msm; 24 namespace mpl = boost::mpl; 25 using namespace boost::msm::front; 26 27 namespace 28 { 29 // events 30 struct play {}; 31 struct end_pause {}; 32 struct stop {}; 33 struct pause {}; 34 struct open_close {}; 35 struct NextSong {}; 36 struct PreviousSong {}; 37 struct error_found {}; 38 struct end_error {}; 39 struct do_terminate {}; 40 41 // Flags. Allow information about a property of the current state 42 struct PlayingPaused{}; 43 struct CDLoaded {}; 44 struct FirstSongPlaying {}; 45 46 // A "complicated" event type that carries some data. 47 struct cd_detected 48 { cd_detected__anona38648be0111::cd_detected49 cd_detected(std::string name) 50 : name(name) 51 {} 52 53 std::string name; 54 }; 55 56 // front-end: define the FSM structure 57 struct player_ : public msm::front::state_machine_def<player_> 58 { 59 // we want deferred events and no state requires deferred events (only the fsm in the 60 // transition table), so the fsm does. 61 typedef int activate_deferred_events; 62 63 unsigned int start_playback_counter; 64 unsigned int can_close_drawer_counter; 65 unsigned int report_error_counter; 66 unsigned int report_end_error_counter; 67 player___anona38648be0111::player_68 player_(): 69 start_playback_counter(0), 70 can_close_drawer_counter(0), 71 report_error_counter(0), 72 report_end_error_counter(0) 73 {} 74 // The list of FSM states 75 struct Empty : public msm::front::state<> 76 { 77 template <class Event,class FSM> on_entry__anona38648be0111::player_::Empty78 void on_entry(Event const&,FSM& ) {++entry_counter;} 79 template <class Event,class FSM> on_exit__anona38648be0111::player_::Empty80 void on_exit(Event const&,FSM& ) {++exit_counter;} 81 int entry_counter; 82 int exit_counter; 83 }; 84 struct Open : public msm::front::state<> 85 { 86 typedef mpl::vector1<CDLoaded> flag_list; 87 88 template <class Event,class FSM> on_entry__anona38648be0111::player_::Open89 void on_entry(Event const&,FSM& ) {++entry_counter;} 90 template <class Event,class FSM> on_exit__anona38648be0111::player_::Open91 void on_exit(Event const&,FSM& ) {++exit_counter;} 92 int entry_counter; 93 int exit_counter; 94 }; 95 96 struct Stopped : public msm::front::state<> 97 { 98 typedef mpl::vector1<CDLoaded> flag_list; 99 100 template <class Event,class FSM> on_entry__anona38648be0111::player_::Stopped101 void on_entry(Event const&,FSM& ) {++entry_counter;} 102 template <class Event,class FSM> on_exit__anona38648be0111::player_::Stopped103 void on_exit(Event const&,FSM& ) {++exit_counter;} 104 int entry_counter; 105 int exit_counter; 106 }; 107 108 // the player state machine contains a state which is himself a state machine 109 // as you see, no need to declare it anywhere so Playing can be developed separately 110 // by another team in another module. For simplicity I just declare it inside player 111 struct Playing_ : public msm::front::state_machine_def<Playing_> 112 { 113 // when playing, the CD is loaded and we are in either pause or playing (duh) 114 typedef mpl::vector2<PlayingPaused,CDLoaded> flag_list; 115 116 template <class Event,class FSM> on_entry__anona38648be0111::player_::Playing_117 void on_entry(Event const&,FSM& ) {++entry_counter;} 118 template <class Event,class FSM> on_exit__anona38648be0111::player_::Playing_119 void on_exit(Event const&,FSM& ) {++exit_counter;} 120 int entry_counter; 121 int exit_counter; 122 unsigned int start_next_song_counter; 123 unsigned int start_prev_song_guard_counter; 124 Playing___anona38648be0111::player_::Playing_125 Playing_(): 126 start_next_song_counter(0), 127 start_prev_song_guard_counter(0) 128 {} 129 130 // The list of FSM states 131 struct Song1 : public msm::front::state<> 132 { 133 typedef mpl::vector1<FirstSongPlaying> flag_list; 134 135 template <class Event,class FSM> on_entry__anona38648be0111::player_::Playing_::Song1136 void on_entry(Event const&,FSM& ) {++entry_counter;} 137 template <class Event,class FSM> on_exit__anona38648be0111::player_::Playing_::Song1138 void on_exit(Event const&,FSM& ) {++exit_counter;} 139 int entry_counter; 140 int exit_counter; 141 }; 142 struct Song2 : public msm::front::state<> 143 { 144 template <class Event,class FSM> on_entry__anona38648be0111::player_::Playing_::Song2145 void on_entry(Event const&,FSM& ) {++entry_counter;} 146 template <class Event,class FSM> on_exit__anona38648be0111::player_::Playing_::Song2147 void on_exit(Event const&,FSM& ) {++exit_counter;} 148 int entry_counter; 149 int exit_counter; 150 }; 151 struct Song3 : public msm::front::state<> 152 { 153 template <class Event,class FSM> on_entry__anona38648be0111::player_::Playing_::Song3154 void on_entry(Event const&,FSM& ) {++entry_counter;} 155 template <class Event,class FSM> on_exit__anona38648be0111::player_::Playing_::Song3156 void on_exit(Event const&,FSM& ) {++exit_counter;} 157 int entry_counter; 158 int exit_counter; 159 }; 160 // the initial state. Must be defined 161 typedef Song1 initial_state; 162 // transition actions start_next_song__anona38648be0111::player_::Playing_163 void start_next_song(NextSong const&) {++start_next_song_counter; } start_prev_song__anona38648be0111::player_::Playing_164 void start_prev_song(PreviousSong const&) { } 165 // guard conditions start_prev_song_guard__anona38648be0111::player_::Playing_166 bool start_prev_song_guard(PreviousSong const&) {++start_prev_song_guard_counter;return true; } 167 168 typedef Playing_ pl; // makes transition table cleaner 169 // Transition table for Playing 170 struct transition_table : mpl::vector4< 171 // Start Event Next Action Guard 172 // +---------+-------------+---------+---------------------+----------------------+ 173 _row < Song1 , NextSong , Song2 >, 174 row < Song2 , PreviousSong, Song1 , &pl::start_prev_song,&pl::start_prev_song_guard>, 175 a_row < Song2 , NextSong , Song3 , &pl::start_next_song >, 176 g_row < Song3 , PreviousSong, Song2 ,&pl::start_prev_song_guard> 177 // +---------+-------------+---------+---------------------+----------------------+ 178 > {}; 179 // Replaces the default no-transition response. 180 template <class FSM,class Event> no_transition__anona38648be0111::player_::Playing_181 void no_transition(Event const&, FSM&,int) 182 { 183 BOOST_FAIL("no_transition called!"); 184 } 185 }; 186 // back-end 187 typedef msm::back::state_machine<Playing_> Playing; 188 189 // state not defining any entry or exit 190 struct Paused : public msm::front::state<> 191 { 192 typedef mpl::vector2<PlayingPaused,CDLoaded> flag_list; 193 194 template <class Event,class FSM> on_entry__anona38648be0111::player_::Paused195 void on_entry(Event const&,FSM& ) {++entry_counter;} 196 template <class Event,class FSM> on_exit__anona38648be0111::player_::Paused197 void on_exit(Event const&,FSM& ) {++exit_counter;} 198 int entry_counter; 199 int exit_counter; 200 }; 201 struct AllOk : public msm::front::state<> 202 { 203 template <class Event,class FSM> on_entry__anona38648be0111::player_::AllOk204 void on_entry(Event const&,FSM& ) {++entry_counter;} 205 template <class Event,class FSM> on_exit__anona38648be0111::player_::AllOk206 void on_exit(Event const&,FSM& ) {++exit_counter;} 207 int entry_counter; 208 int exit_counter; 209 }; 210 // this state is also made terminal so that all the events are blocked 211 struct ErrorMode : //public msm::front::terminate_state<> // ErrorMode terminates the state machine 212 public msm::front::interrupt_state<end_error> // ErroMode just interrupts. Will resume if 213 // the event end_error is generated 214 { 215 template <class Event,class FSM> on_entry__anona38648be0111::player_::ErrorMode216 void on_entry(Event const&,FSM& ) {++entry_counter;} 217 template <class Event,class FSM> on_exit__anona38648be0111::player_::ErrorMode218 void on_exit(Event const&,FSM& ) {++exit_counter;} 219 int entry_counter; 220 int exit_counter; 221 }; 222 struct ErrorTerminate : public msm::front::terminate_state<> // terminates the state machine 223 { 224 template <class Event,class FSM> on_entry__anona38648be0111::player_::ErrorTerminate225 void on_entry(Event const&,FSM& ) {++entry_counter;} 226 template <class Event,class FSM> on_exit__anona38648be0111::player_::ErrorTerminate227 void on_exit(Event const&,FSM& ) {++exit_counter;} 228 int entry_counter; 229 int exit_counter; 230 }; 231 // the initial state of the player SM. Must be defined 232 typedef mpl::vector<Empty,AllOk> initial_state; 233 234 // transition actions start_playback__anona38648be0111::player_235 void start_playback(play const&) {++start_playback_counter; } open_drawer__anona38648be0111::player_236 void open_drawer(open_close const&) { } store_cd_info__anona38648be0111::player_237 void store_cd_info(cd_detected const&) { } stop_playback__anona38648be0111::player_238 void stop_playback(stop const&) { } pause_playback__anona38648be0111::player_239 void pause_playback(pause const&) { } resume_playback__anona38648be0111::player_240 void resume_playback(end_pause const&) { } stop_and_open__anona38648be0111::player_241 void stop_and_open(open_close const&) { } stopped_again__anona38648be0111::player_242 void stopped_again(stop const&){} report_error__anona38648be0111::player_243 void report_error(error_found const&) {++report_error_counter;} report_end_error__anona38648be0111::player_244 void report_end_error(end_error const&) {++report_end_error_counter;} 245 246 //guards can_close_drawer__anona38648be0111::player_247 bool can_close_drawer(open_close const&) 248 { 249 ++can_close_drawer_counter; 250 return true; 251 } 252 typedef player_ p; // makes transition table cleaner 253 254 // Transition table for player 255 struct transition_table : mpl::vector< 256 // Start Event Next Action Guard 257 // +---------+-------------+---------+---------------------+----------------------+ 258 a_row < Stopped , play , Playing , &p::start_playback >, 259 a_row < Stopped , open_close , Open , &p::open_drawer >, 260 _row < Stopped , stop , Stopped >, 261 // +---------+-------------+---------+---------------------+----------------------+ 262 g_row < Open , open_close , Empty , &p::can_close_drawer >, 263 Row < Open , play , none , Defer , none >, 264 // +---------+-------------+---------+---------------------+----------------------+ 265 a_row < Empty , open_close , Open , &p::open_drawer >, 266 a_row < Empty , cd_detected , Stopped , &p::store_cd_info >, 267 Row < Empty , play , none , Defer , none >, 268 // +---------+-------------+---------+---------------------+----------------------+ 269 a_row < Playing , stop , Stopped , &p::stop_playback >, 270 a_row < Playing , pause , Paused , &p::pause_playback >, 271 a_row < Playing , open_close , Open , &p::stop_and_open >, 272 // +---------+-------------+---------+---------------------+----------------------+ 273 a_row < Paused , end_pause , Playing , &p::resume_playback >, 274 a_row < Paused , stop , Stopped , &p::stop_playback >, 275 a_row < Paused , open_close , Open , &p::stop_and_open >, 276 // +---------+-------------+---------+---------------------+----------------------+ 277 a_row < AllOk , error_found ,ErrorMode, &p::report_error >, 278 a_row <ErrorMode, end_error ,AllOk , &p::report_end_error >, 279 _row < AllOk , do_terminate,ErrorTerminate > 280 // +---------+-------------+---------+---------------------+----------------------+ 281 > {}; 282 283 // Replaces the default no-transition response. 284 template <class FSM,class Event> no_transition__anona38648be0111::player_285 void no_transition(Event const& , FSM&,int) 286 { 287 BOOST_FAIL("no_transition called!"); 288 } 289 // init counters 290 template <class Event,class FSM> on_entry__anona38648be0111::player_291 void on_entry(Event const&,FSM& fsm) 292 { 293 fsm.template get_state<player_::Stopped&>().entry_counter=0; 294 fsm.template get_state<player_::Stopped&>().exit_counter=0; 295 fsm.template get_state<player_::Open&>().entry_counter=0; 296 fsm.template get_state<player_::Open&>().exit_counter=0; 297 fsm.template get_state<player_::Empty&>().entry_counter=0; 298 fsm.template get_state<player_::Empty&>().exit_counter=0; 299 fsm.template get_state<player_::Playing&>().entry_counter=0; 300 fsm.template get_state<player_::Playing&>().exit_counter=0; 301 fsm.template get_state<player_::Playing&>().template get_state<player_::Playing::Song1&>().entry_counter=0; 302 fsm.template get_state<player_::Playing&>().template get_state<player_::Playing::Song1&>().exit_counter=0; 303 fsm.template get_state<player_::Playing&>().template get_state<player_::Playing::Song2&>().entry_counter=0; 304 fsm.template get_state<player_::Playing&>().template get_state<player_::Playing::Song2&>().exit_counter=0; 305 fsm.template get_state<player_::Playing&>().template get_state<player_::Playing::Song3&>().entry_counter=0; 306 fsm.template get_state<player_::Playing&>().template get_state<player_::Playing::Song3&>().exit_counter=0; 307 fsm.template get_state<player_::Paused&>().entry_counter=0; 308 fsm.template get_state<player_::Paused&>().exit_counter=0; 309 fsm.template get_state<player_::AllOk&>().entry_counter=0; 310 fsm.template get_state<player_::AllOk&>().exit_counter=0; 311 fsm.template get_state<player_::ErrorMode&>().entry_counter=0; 312 fsm.template get_state<player_::ErrorMode&>().exit_counter=0; 313 fsm.template get_state<player_::ErrorTerminate&>().entry_counter=0; 314 fsm.template get_state<player_::ErrorTerminate&>().exit_counter=0; 315 } 316 }; 317 // Pick a back-end 318 typedef msm::back::state_machine<player_> player; 319 320 //static char const* const state_names[] = { "Stopped", "Open", "Empty", "Playing", "Paused","AllOk","ErrorMode" }; 321 BOOST_AUTO_TEST_CASE(my_test)322 BOOST_AUTO_TEST_CASE( my_test ) 323 { 324 player p; 325 // needed to start the highest-level SM. This will call on_entry and mark the start of the SM 326 p.start(); 327 // test deferred event 328 // deferred in Empty and Open, will be handled only after event cd_detected 329 p.process_event(play()); 330 BOOST_CHECK_MESSAGE(p.current_state()[0] == 2,"Empty should be active"); //Empty 331 BOOST_CHECK_MESSAGE(p.get_state<player_::Open&>().exit_counter == 0,"Open exit not called correctly"); 332 BOOST_CHECK_MESSAGE(p.get_state<player_::Playing&>().entry_counter == 0,"Playing entry not called correctly"); 333 BOOST_CHECK_MESSAGE(p.get_state<player_::Empty&>().entry_counter == 1,"Empty entry not called correctly"); 334 //flags 335 BOOST_CHECK_MESSAGE(p.is_flag_active<CDLoaded>() == false,"CDLoaded should not be active"); 336 337 p.process_event(open_close()); 338 BOOST_CHECK_MESSAGE(p.current_state()[0] == 1,"Open should be active"); //Open 339 BOOST_CHECK_MESSAGE(p.get_state<player_::Empty&>().exit_counter == 1,"Empty exit not called correctly"); 340 BOOST_CHECK_MESSAGE(p.get_state<player_::Open&>().entry_counter == 1,"Open entry not called correctly"); 341 342 p.process_event(open_close()); 343 BOOST_CHECK_MESSAGE(p.current_state()[0] == 2,"Empty should be active"); //Empty 344 BOOST_CHECK_MESSAGE(p.get_state<player_::Open&>().exit_counter == 1,"Open exit not called correctly"); 345 BOOST_CHECK_MESSAGE(p.get_state<player_::Empty&>().entry_counter == 2,"Empty entry not called correctly"); 346 BOOST_CHECK_MESSAGE(p.can_close_drawer_counter == 1,"guard not called correctly"); 347 348 //deferred event should have been processed 349 p.process_event(cd_detected("louie, louie")); 350 BOOST_CHECK_MESSAGE(p.current_state()[0] == 3,"Playing should be active"); //Playing 351 BOOST_CHECK_MESSAGE(p.get_state<player_::Empty&>().exit_counter == 2,"Empty exit not called correctly"); 352 BOOST_CHECK_MESSAGE(p.get_state<player_::Stopped&>().entry_counter == 1,"Stopped entry not called correctly"); 353 BOOST_CHECK_MESSAGE(p.get_state<player_::Stopped&>().exit_counter == 1,"Stopped exit not called correctly"); 354 BOOST_CHECK_MESSAGE(p.get_state<player_::Playing&>().entry_counter == 1,"Playing entry not called correctly"); 355 BOOST_CHECK_MESSAGE(p.start_playback_counter == 1,"action not called correctly"); 356 BOOST_CHECK_MESSAGE(p.get_state<player_::Playing&>().current_state()[0] == 0,"Song1 should be active"); 357 BOOST_CHECK_MESSAGE( 358 p.get_state<player_::Playing&>().get_state<player_::Playing::Song1&>().entry_counter == 1, 359 "Song1 entry not called correctly"); 360 361 //flags 362 BOOST_CHECK_MESSAGE(p.is_flag_active<PlayingPaused>() == true,"PlayingPaused should be active"); 363 BOOST_CHECK_MESSAGE(p.is_flag_active<FirstSongPlaying>() == true,"FirstSongPlaying should be active"); 364 365 366 p.process_event(NextSong()); 367 BOOST_CHECK_MESSAGE(p.current_state()[0] == 3,"Playing should be active"); //Playing 368 BOOST_CHECK_MESSAGE(p.get_state<player_::Playing&>().current_state()[0] == 1,"Song2 should be active"); 369 BOOST_CHECK_MESSAGE( 370 p.get_state<player_::Playing&>().get_state<player_::Playing::Song2&>().entry_counter == 1, 371 "Song2 entry not called correctly"); 372 BOOST_CHECK_MESSAGE( 373 p.get_state<player_::Playing&>().get_state<player_::Playing::Song1&>().exit_counter == 1, 374 "Song1 exit not called correctly"); 375 BOOST_CHECK_MESSAGE( 376 p.get_state<player_::Playing&>().start_next_song_counter == 0, 377 "submachine action not called correctly"); 378 379 p.process_event(NextSong()); 380 BOOST_CHECK_MESSAGE(p.current_state()[0] == 3,"Playing should be active"); //Playing 381 BOOST_CHECK_MESSAGE(p.get_state<player_::Playing&>().current_state()[0] == 2,"Song3 should be active"); 382 BOOST_CHECK_MESSAGE( 383 p.get_state<player_::Playing&>().get_state<player_::Playing::Song3&>().entry_counter == 1, 384 "Song3 entry not called correctly"); 385 BOOST_CHECK_MESSAGE( 386 p.get_state<player_::Playing&>().get_state<player_::Playing::Song2&>().exit_counter == 1, 387 "Song2 exit not called correctly"); 388 BOOST_CHECK_MESSAGE( 389 p.get_state<player_::Playing&>().start_next_song_counter == 1, 390 "submachine action not called correctly"); 391 392 p.process_event(PreviousSong()); 393 BOOST_CHECK_MESSAGE(p.current_state()[0] == 3,"Playing should be active"); //Playing 394 BOOST_CHECK_MESSAGE(p.get_state<player_::Playing&>().current_state()[0] == 1,"Song2 should be active"); 395 BOOST_CHECK_MESSAGE( 396 p.get_state<player_::Playing&>().get_state<player_::Playing::Song2&>().entry_counter == 2, 397 "Song2 entry not called correctly"); 398 BOOST_CHECK_MESSAGE( 399 p.get_state<player_::Playing&>().get_state<player_::Playing::Song3&>().exit_counter == 1, 400 "Song3 exit not called correctly"); 401 BOOST_CHECK_MESSAGE( 402 p.get_state<player_::Playing&>().start_prev_song_guard_counter == 1, 403 "submachine guard not called correctly"); 404 //flags 405 BOOST_CHECK_MESSAGE(p.is_flag_active<PlayingPaused>() == true,"PlayingPaused should be active"); 406 BOOST_CHECK_MESSAGE(p.is_flag_active<FirstSongPlaying>() == false,"FirstSongPlaying should not be active"); 407 408 p.process_event(pause()); 409 BOOST_CHECK_MESSAGE(p.current_state()[0] == 4,"Paused should be active"); //Paused 410 BOOST_CHECK_MESSAGE(p.get_state<player_::Playing&>().exit_counter == 1,"Playing exit not called correctly"); 411 BOOST_CHECK_MESSAGE(p.get_state<player_::Paused&>().entry_counter == 1,"Paused entry not called correctly"); 412 //flags 413 BOOST_CHECK_MESSAGE(p.is_flag_active<PlayingPaused>() == true,"PlayingPaused should be active"); 414 415 // go back to Playing 416 p.process_event(end_pause()); 417 BOOST_CHECK_MESSAGE(p.current_state()[0] == 3,"Playing should be active"); //Playing 418 BOOST_CHECK_MESSAGE(p.get_state<player_::Paused&>().exit_counter == 1,"Paused exit not called correctly"); 419 BOOST_CHECK_MESSAGE(p.get_state<player_::Playing&>().entry_counter == 2,"Playing entry not called correctly"); 420 421 p.process_event(pause()); 422 BOOST_CHECK_MESSAGE(p.current_state()[0] == 4,"Paused should be active"); //Paused 423 BOOST_CHECK_MESSAGE(p.get_state<player_::Playing&>().exit_counter == 2,"Playing exit not called correctly"); 424 BOOST_CHECK_MESSAGE(p.get_state<player_::Paused&>().entry_counter == 2,"Paused entry not called correctly"); 425 426 p.process_event(stop()); 427 BOOST_CHECK_MESSAGE(p.current_state()[0] == 0,"Stopped should be active"); //Stopped 428 BOOST_CHECK_MESSAGE(p.get_state<player_::Paused&>().exit_counter == 2,"Paused exit not called correctly"); 429 BOOST_CHECK_MESSAGE(p.get_state<player_::Stopped&>().entry_counter == 2,"Stopped entry not called correctly"); 430 //flags 431 BOOST_CHECK_MESSAGE(p.is_flag_active<PlayingPaused>() == false,"PlayingPaused should not be active"); 432 BOOST_CHECK_MESSAGE(p.is_flag_active<CDLoaded>() == true,"CDLoaded should be active"); 433 //BOOST_CHECK_MESSAGE(p.is_flag_active<CDLoaded,player::Flag_AND>() == false,"CDLoaded with AND should not be active"); 434 435 p.process_event(stop()); 436 BOOST_CHECK_MESSAGE(p.current_state()[0] == 0,"Stopped should be active"); //Stopped 437 BOOST_CHECK_MESSAGE(p.get_state<player_::Stopped&>().exit_counter == 2,"Stopped exit not called correctly"); 438 BOOST_CHECK_MESSAGE(p.get_state<player_::Stopped&>().entry_counter == 3,"Stopped entry not called correctly"); 439 440 //test interrupt 441 BOOST_CHECK_MESSAGE(p.current_state()[1] == 5,"AllOk should be active"); //AllOk 442 p.process_event(error_found()); 443 BOOST_CHECK_MESSAGE(p.current_state()[1] == 6,"ErrorMode should be active"); //ErrorMode 444 BOOST_CHECK_MESSAGE(p.get_state<player_::AllOk&>().exit_counter == 1,"AllOk exit not called correctly"); 445 BOOST_CHECK_MESSAGE(p.get_state<player_::ErrorMode&>().entry_counter == 1,"ErrorMode entry not called correctly"); 446 447 // try generating more events 448 p.process_event(play()); 449 BOOST_CHECK_MESSAGE(p.current_state()[1] == 6,"ErrorMode should be active"); //ErrorMode 450 BOOST_CHECK_MESSAGE(p.get_state<player_::AllOk&>().exit_counter == 1,"AllOk exit not called correctly"); 451 BOOST_CHECK_MESSAGE(p.get_state<player_::ErrorMode&>().entry_counter == 1,"ErrorMode entry not called correctly"); 452 BOOST_CHECK_MESSAGE(p.current_state()[0] == 0,"Stopped should be active"); //Stopped 453 BOOST_CHECK_MESSAGE(p.get_state<player_::Stopped&>().exit_counter == 2,"Stopped exit not called correctly"); 454 BOOST_CHECK_MESSAGE(p.get_state<player_::Stopped&>().entry_counter == 3,"Stopped entry not called correctly"); 455 456 p.process_event(end_error()); 457 BOOST_CHECK_MESSAGE(p.current_state()[1] == 5,"AllOk should be active"); //AllOk 458 BOOST_CHECK_MESSAGE(p.get_state<player_::ErrorMode&>().exit_counter == 1,"ErrorMode exit not called correctly"); 459 BOOST_CHECK_MESSAGE(p.get_state<player_::AllOk&>().entry_counter == 2,"AllOk entry not called correctly"); 460 461 p.process_event(play()); 462 BOOST_CHECK_MESSAGE(p.current_state()[0] == 3,"Playing should be active"); //Playing 463 BOOST_CHECK_MESSAGE(p.get_state<player_::Stopped&>().exit_counter == 3,"Stopped exit not called correctly"); 464 BOOST_CHECK_MESSAGE(p.get_state<player_::Playing&>().entry_counter == 3,"Playing entry not called correctly"); 465 466 //test terminate 467 BOOST_CHECK_MESSAGE(p.current_state()[1] == 5,"AllOk should be active"); //AllOk 468 p.process_event(do_terminate()); 469 BOOST_CHECK_MESSAGE(p.current_state()[1] == 7,"ErrorTerminate should be active"); //ErrorTerminate 470 BOOST_CHECK_MESSAGE(p.get_state<player_::AllOk&>().exit_counter == 2,"AllOk exit not called correctly"); 471 BOOST_CHECK_MESSAGE(p.get_state<player_::ErrorTerminate&>().entry_counter == 1,"ErrorTerminate entry not called correctly"); 472 473 // try generating more events 474 p.process_event(stop()); 475 BOOST_CHECK_MESSAGE(p.current_state()[1] == 7,"ErrorTerminate should be active"); //ErrorTerminate 476 BOOST_CHECK_MESSAGE(p.get_state<player_::ErrorTerminate&>().exit_counter == 0,"ErrorTerminate exit not called correctly"); 477 BOOST_CHECK_MESSAGE(p.current_state()[0] == 3,"Playing should be active"); //Playing 478 BOOST_CHECK_MESSAGE(p.get_state<player_::Playing&>().exit_counter == 2,"Playing exit not called correctly"); 479 BOOST_CHECK_MESSAGE(p.get_state<player_::Stopped&>().entry_counter == 3,"Stopped entry not called correctly"); 480 481 p.process_event(end_error()); 482 BOOST_CHECK_MESSAGE(p.current_state()[1] == 7,"ErrorTerminate should be active"); //ErrorTerminate 483 BOOST_CHECK_MESSAGE(p.current_state()[0] == 3,"Playing should be active"); //Playing 484 BOOST_CHECK_MESSAGE(p.get_state<player_::Playing&>().exit_counter == 2,"Playing exit not called correctly"); 485 BOOST_CHECK_MESSAGE(p.get_state<player_::Stopped&>().entry_counter == 3,"Stopped entry not called correctly"); 486 487 p.process_event(stop()); 488 BOOST_CHECK_MESSAGE(p.current_state()[1] == 7,"ErrorTerminate should be active"); //ErrorTerminate 489 BOOST_CHECK_MESSAGE(p.current_state()[0] == 3,"Playing should be active"); //Playing 490 BOOST_CHECK_MESSAGE(p.get_state<player_::Playing&>().exit_counter == 2,"Playing exit not called correctly"); 491 BOOST_CHECK_MESSAGE(p.get_state<player_::Stopped&>().entry_counter == 3,"Stopped entry not called correctly"); 492 493 } 494 } 495 496