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