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__anonb318d93e0111::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___anonb318d93e0111::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__anonb318d93e0111::player_::Empty78 void on_entry(Event const&,FSM& ) {++entry_counter;} 79 template <class Event,class FSM> on_exit__anonb318d93e0111::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__anonb318d93e0111::player_::Open89 void on_entry(Event const&,FSM& ) {++entry_counter;} 90 template <class Event,class FSM> on_exit__anonb318d93e0111::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__anonb318d93e0111::player_::Stopped101 void on_entry(Event const&,FSM& ) {++entry_counter;} 102 template <class Event,class FSM> on_exit__anonb318d93e0111::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__anonb318d93e0111::player_::Playing_117 void on_entry(Event const&,FSM& ) {++entry_counter;} 118 template <class Event,class FSM> on_exit__anonb318d93e0111::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___anonb318d93e0111::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__anonb318d93e0111::player_::Playing_::Song1136 void on_entry(Event const&,FSM& ) {++entry_counter;} 137 template <class Event,class FSM> on_exit__anonb318d93e0111::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__anonb318d93e0111::player_::Playing_::Song2145 void on_entry(Event const&,FSM& ) {++entry_counter;} 146 template <class Event,class FSM> on_exit__anonb318d93e0111::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__anonb318d93e0111::player_::Playing_::Song3154 void on_entry(Event const&,FSM& ) {++entry_counter;} 155 template <class Event,class FSM> on_exit__anonb318d93e0111::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__anonb318d93e0111::player_::Playing_163 void start_next_song(NextSong const&) {++start_next_song_counter; } start_prev_song__anonb318d93e0111::player_::Playing_164 void start_prev_song(PreviousSong const&) { } 165 // guard conditions start_prev_song_guard__anonb318d93e0111::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__anonb318d93e0111::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__anonb318d93e0111::player_::Paused195 void on_entry(Event const&,FSM& ) {++entry_counter;} 196 template <class Event,class FSM> on_exit__anonb318d93e0111::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__anonb318d93e0111::player_::AllOk204 void on_entry(Event const&,FSM& ) {++entry_counter;} 205 template <class Event,class FSM> on_exit__anonb318d93e0111::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__anonb318d93e0111::player_::ErrorMode216 void on_entry(Event const&,FSM& ) {++entry_counter;} 217 template <class Event,class FSM> on_exit__anonb318d93e0111::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__anonb318d93e0111::player_::ErrorTerminate225 void on_entry(Event const&,FSM& ) {++entry_counter;} 226 template <class Event,class FSM> on_exit__anonb318d93e0111::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__anonb318d93e0111::player_235 void start_playback(play const&) {++start_playback_counter; } open_drawer__anonb318d93e0111::player_236 void open_drawer(open_close const&) { } store_cd_info__anonb318d93e0111::player_237 void store_cd_info(cd_detected const&) { } stop_playback__anonb318d93e0111::player_238 void stop_playback(stop const&) { } pause_playback__anonb318d93e0111::player_239 void pause_playback(pause const&) { } resume_playback__anonb318d93e0111::player_240 void resume_playback(end_pause const&) { } stop_and_open__anonb318d93e0111::player_241 void stop_and_open(open_close const&) { } stopped_again__anonb318d93e0111::player_242 void stopped_again(stop const&){} report_error__anonb318d93e0111::player_243 void report_error(error_found const&) {++report_error_counter;} report_end_error__anonb318d93e0111::player_244 void report_end_error(end_error const&) {++report_end_error_counter;} 245 246 //guards can_close_drawer__anonb318d93e0111::player_247 bool can_close_drawer(open_close const&) 248 { 249 ++can_close_drawer_counter; 250 return true; 251 } 252 struct is_play_event 253 { 254 template <class EVT,class FSM,class SourceState,class TargetState> operator ()__anonb318d93e0111::player_::is_play_event255 bool operator()(EVT const& evt,FSM&,SourceState& ,TargetState& ) 256 { 257 bool is_play = boost::any_cast<play>(&evt) != 0; 258 return is_play; 259 } 260 }; 261 struct MyDefer 262 { 263 // mark as deferring to avoid stack overflows in certain conditions 264 typedef int deferring_action; 265 template <class EVT,class FSM,class SourceState,class TargetState> operator ()__anonb318d93e0111::player_::MyDefer266 void operator()(EVT const& ,FSM& fsm,SourceState& ,TargetState& ) const 267 { 268 fsm.defer_event(play()); 269 } 270 }; 271 typedef player_ p; // makes transition table cleaner 272 273 // Transition table for player 274 struct transition_table : mpl::vector< 275 // Start Event Next Action Guard 276 // +---------+-------------+---------+---------------------+----------------------+ 277 a_row < Stopped , play , Playing , &p::start_playback >, 278 a_row < Stopped , open_close , Open , &p::open_drawer >, 279 _row < Stopped , stop , Stopped >, 280 // +---------+-------------+---------+---------------------+----------------------+ 281 g_row < Open , open_close , Empty , &p::can_close_drawer >, 282 Row < Open , play , none , Defer , none >, 283 // +---------+-------------+---------+---------------------+----------------------+ 284 a_row < Empty , open_close , Open , &p::open_drawer >, 285 a_row < Empty , cd_detected , Stopped , &p::store_cd_info >, 286 Row < Empty , boost::any , none , MyDefer , is_play_event >, 287 // +---------+-------------+---------+---------------------+----------------------+ 288 a_row < Playing , stop , Stopped , &p::stop_playback >, 289 a_row < Playing , pause , Paused , &p::pause_playback >, 290 a_row < Playing , open_close , Open , &p::stop_and_open >, 291 // +---------+-------------+---------+---------------------+----------------------+ 292 a_row < Paused , end_pause , Playing , &p::resume_playback >, 293 a_row < Paused , stop , Stopped , &p::stop_playback >, 294 a_row < Paused , open_close , Open , &p::stop_and_open >, 295 // +---------+-------------+---------+---------------------+----------------------+ 296 a_row < AllOk , error_found ,ErrorMode, &p::report_error >, 297 a_row <ErrorMode, end_error ,AllOk , &p::report_end_error >, 298 _row < AllOk , do_terminate,ErrorTerminate > 299 // +---------+-------------+---------+---------------------+----------------------+ 300 > {}; 301 302 // Replaces the default no-transition response. 303 template <class FSM,class Event> no_transition__anonb318d93e0111::player_304 void no_transition(Event const& , FSM&,int) 305 { 306 BOOST_ERROR("no_transition called!"); 307 } 308 // init counters 309 template <class Event,class FSM> on_entry__anonb318d93e0111::player_310 void on_entry(Event const&,FSM& fsm) 311 { 312 fsm.template get_state<player_::Stopped&>().entry_counter=0; 313 fsm.template get_state<player_::Stopped&>().exit_counter=0; 314 fsm.template get_state<player_::Open&>().entry_counter=0; 315 fsm.template get_state<player_::Open&>().exit_counter=0; 316 fsm.template get_state<player_::Empty&>().entry_counter=0; 317 fsm.template get_state<player_::Empty&>().exit_counter=0; 318 fsm.template get_state<player_::Playing&>().entry_counter=0; 319 fsm.template get_state<player_::Playing&>().exit_counter=0; 320 fsm.template get_state<player_::Playing&>().template get_state<player_::Playing::Song1&>().entry_counter=0; 321 fsm.template get_state<player_::Playing&>().template get_state<player_::Playing::Song1&>().exit_counter=0; 322 fsm.template get_state<player_::Playing&>().template get_state<player_::Playing::Song2&>().entry_counter=0; 323 fsm.template get_state<player_::Playing&>().template get_state<player_::Playing::Song2&>().exit_counter=0; 324 fsm.template get_state<player_::Playing&>().template get_state<player_::Playing::Song3&>().entry_counter=0; 325 fsm.template get_state<player_::Playing&>().template get_state<player_::Playing::Song3&>().exit_counter=0; 326 fsm.template get_state<player_::Paused&>().entry_counter=0; 327 fsm.template get_state<player_::Paused&>().exit_counter=0; 328 fsm.template get_state<player_::AllOk&>().entry_counter=0; 329 fsm.template get_state<player_::AllOk&>().exit_counter=0; 330 fsm.template get_state<player_::ErrorMode&>().entry_counter=0; 331 fsm.template get_state<player_::ErrorMode&>().exit_counter=0; 332 fsm.template get_state<player_::ErrorTerminate&>().entry_counter=0; 333 fsm.template get_state<player_::ErrorTerminate&>().exit_counter=0; 334 } 335 }; 336 // Pick a back-end 337 typedef msm::back::state_machine<player_> player; 338 339 //static char const* const state_names[] = { "Stopped", "Open", "Empty", "Playing", "Paused","AllOk","ErrorMode" }; 340 BOOST_AUTO_TEST_CASE(my_test)341 BOOST_AUTO_TEST_CASE( my_test ) 342 { 343 player p; 344 // needed to start the highest-level SM. This will call on_entry and mark the start of the SM 345 p.start(); 346 // test deferred event 347 // deferred in Empty and Open, will be handled only after event cd_detected 348 p.process_event(play()); 349 BOOST_CHECK_MESSAGE(p.current_state()[0] == 2,"Empty should be active"); //Empty 350 BOOST_CHECK_MESSAGE(p.get_state<player_::Open&>().exit_counter == 0,"Open exit not called correctly"); 351 BOOST_CHECK_MESSAGE(p.get_state<player_::Playing&>().entry_counter == 0,"Playing entry not called correctly"); 352 BOOST_CHECK_MESSAGE(p.get_state<player_::Empty&>().entry_counter == 1,"Empty entry not called correctly"); 353 //flags 354 BOOST_CHECK_MESSAGE(p.is_flag_active<CDLoaded>() == false,"CDLoaded should not be active"); 355 p.process_event(open_close()); 356 BOOST_CHECK_MESSAGE(p.current_state()[0] == 1,"Open should be active"); //Open 357 BOOST_CHECK_MESSAGE(p.get_state<player_::Empty&>().exit_counter == 1,"Empty exit not called correctly"); 358 BOOST_CHECK_MESSAGE(p.get_state<player_::Open&>().entry_counter == 1,"Open entry not called correctly"); 359 p.process_event(open_close()); 360 BOOST_CHECK_MESSAGE(p.current_state()[0] == 2,"Empty should be active"); //Empty 361 BOOST_CHECK_MESSAGE(p.get_state<player_::Open&>().exit_counter == 1,"Open exit not called correctly"); 362 BOOST_CHECK_MESSAGE(p.get_state<player_::Empty&>().entry_counter == 2,"Empty entry not called correctly"); 363 BOOST_CHECK_MESSAGE(p.can_close_drawer_counter == 1,"guard not called correctly"); 364 //deferred event should have been processed 365 p.process_event(cd_detected("louie, louie")); 366 BOOST_CHECK_MESSAGE(p.current_state()[0] == 3,"Playing should be active"); //Playing 367 BOOST_CHECK_MESSAGE(p.get_state<player_::Empty&>().exit_counter == 2,"Empty exit not called correctly"); 368 BOOST_CHECK_MESSAGE(p.get_state<player_::Stopped&>().entry_counter == 1,"Stopped entry not called correctly"); 369 BOOST_CHECK_MESSAGE(p.get_state<player_::Stopped&>().exit_counter == 1,"Stopped exit not called correctly"); 370 BOOST_CHECK_MESSAGE(p.get_state<player_::Playing&>().entry_counter == 1,"Playing entry not called correctly"); 371 BOOST_CHECK_MESSAGE(p.start_playback_counter == 1,"action not called correctly"); 372 BOOST_CHECK_MESSAGE(p.get_state<player_::Playing&>().current_state()[0] == 0,"Song1 should be active"); 373 BOOST_CHECK_MESSAGE( 374 p.get_state<player_::Playing&>().get_state<player_::Playing::Song1&>().entry_counter == 1, 375 "Song1 entry not called correctly"); 376 377 //flags 378 BOOST_CHECK_MESSAGE(p.is_flag_active<PlayingPaused>() == true,"PlayingPaused should be active"); 379 BOOST_CHECK_MESSAGE(p.is_flag_active<FirstSongPlaying>() == true,"FirstSongPlaying should be active"); 380 381 382 p.process_event(NextSong()); 383 BOOST_CHECK_MESSAGE(p.current_state()[0] == 3,"Playing should be active"); //Playing 384 BOOST_CHECK_MESSAGE(p.get_state<player_::Playing&>().current_state()[0] == 1,"Song2 should be active"); 385 BOOST_CHECK_MESSAGE( 386 p.get_state<player_::Playing&>().get_state<player_::Playing::Song2&>().entry_counter == 1, 387 "Song2 entry not called correctly"); 388 BOOST_CHECK_MESSAGE( 389 p.get_state<player_::Playing&>().get_state<player_::Playing::Song1&>().exit_counter == 1, 390 "Song1 exit not called correctly"); 391 BOOST_CHECK_MESSAGE( 392 p.get_state<player_::Playing&>().start_next_song_counter == 0, 393 "submachine action not called correctly"); 394 395 p.process_event(NextSong()); 396 BOOST_CHECK_MESSAGE(p.current_state()[0] == 3,"Playing should be active"); //Playing 397 BOOST_CHECK_MESSAGE(p.get_state<player_::Playing&>().current_state()[0] == 2,"Song3 should be active"); 398 BOOST_CHECK_MESSAGE( 399 p.get_state<player_::Playing&>().get_state<player_::Playing::Song3&>().entry_counter == 1, 400 "Song3 entry not called correctly"); 401 BOOST_CHECK_MESSAGE( 402 p.get_state<player_::Playing&>().get_state<player_::Playing::Song2&>().exit_counter == 1, 403 "Song2 exit not called correctly"); 404 BOOST_CHECK_MESSAGE( 405 p.get_state<player_::Playing&>().start_next_song_counter == 1, 406 "submachine action not called correctly"); 407 408 p.process_event(PreviousSong()); 409 BOOST_CHECK_MESSAGE(p.current_state()[0] == 3,"Playing should be active"); //Playing 410 BOOST_CHECK_MESSAGE(p.get_state<player_::Playing&>().current_state()[0] == 1,"Song2 should be active"); 411 BOOST_CHECK_MESSAGE( 412 p.get_state<player_::Playing&>().get_state<player_::Playing::Song2&>().entry_counter == 2, 413 "Song2 entry not called correctly"); 414 BOOST_CHECK_MESSAGE( 415 p.get_state<player_::Playing&>().get_state<player_::Playing::Song3&>().exit_counter == 1, 416 "Song3 exit not called correctly"); 417 BOOST_CHECK_MESSAGE( 418 p.get_state<player_::Playing&>().start_prev_song_guard_counter == 1, 419 "submachine guard not called correctly"); 420 //flags 421 BOOST_CHECK_MESSAGE(p.is_flag_active<PlayingPaused>() == true,"PlayingPaused should be active"); 422 BOOST_CHECK_MESSAGE(p.is_flag_active<FirstSongPlaying>() == false,"FirstSongPlaying should not be active"); 423 424 p.process_event(pause()); 425 BOOST_CHECK_MESSAGE(p.current_state()[0] == 4,"Paused should be active"); //Paused 426 BOOST_CHECK_MESSAGE(p.get_state<player_::Playing&>().exit_counter == 1,"Playing exit not called correctly"); 427 BOOST_CHECK_MESSAGE(p.get_state<player_::Paused&>().entry_counter == 1,"Paused entry not called correctly"); 428 //flags 429 BOOST_CHECK_MESSAGE(p.is_flag_active<PlayingPaused>() == true,"PlayingPaused should be active"); 430 431 // go back to Playing 432 p.process_event(end_pause()); 433 BOOST_CHECK_MESSAGE(p.current_state()[0] == 3,"Playing should be active"); //Playing 434 BOOST_CHECK_MESSAGE(p.get_state<player_::Paused&>().exit_counter == 1,"Paused exit not called correctly"); 435 BOOST_CHECK_MESSAGE(p.get_state<player_::Playing&>().entry_counter == 2,"Playing entry not called correctly"); 436 437 p.process_event(pause()); 438 BOOST_CHECK_MESSAGE(p.current_state()[0] == 4,"Paused should be active"); //Paused 439 BOOST_CHECK_MESSAGE(p.get_state<player_::Playing&>().exit_counter == 2,"Playing exit not called correctly"); 440 BOOST_CHECK_MESSAGE(p.get_state<player_::Paused&>().entry_counter == 2,"Paused entry not called correctly"); 441 442 p.process_event(stop()); 443 BOOST_CHECK_MESSAGE(p.current_state()[0] == 0,"Stopped should be active"); //Stopped 444 BOOST_CHECK_MESSAGE(p.get_state<player_::Paused&>().exit_counter == 2,"Paused exit not called correctly"); 445 BOOST_CHECK_MESSAGE(p.get_state<player_::Stopped&>().entry_counter == 2,"Stopped entry not called correctly"); 446 //flags 447 BOOST_CHECK_MESSAGE(p.is_flag_active<PlayingPaused>() == false,"PlayingPaused should not be active"); 448 BOOST_CHECK_MESSAGE(p.is_flag_active<CDLoaded>() == true,"CDLoaded should be active"); 449 //BOOST_CHECK_MESSAGE(p.is_flag_active<CDLoaded,player::Flag_AND>() == false,"CDLoaded with AND should not be active"); 450 451 p.process_event(stop()); 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 //test interrupt 457 BOOST_CHECK_MESSAGE(p.current_state()[1] == 5,"AllOk should be active"); //AllOk 458 p.process_event(error_found()); 459 BOOST_CHECK_MESSAGE(p.current_state()[1] == 6,"ErrorMode should be active"); //ErrorMode 460 BOOST_CHECK_MESSAGE(p.get_state<player_::AllOk&>().exit_counter == 1,"AllOk exit not called correctly"); 461 BOOST_CHECK_MESSAGE(p.get_state<player_::ErrorMode&>().entry_counter == 1,"ErrorMode entry not called correctly"); 462 463 // try generating more events 464 p.process_event(play()); 465 BOOST_CHECK_MESSAGE(p.current_state()[1] == 6,"ErrorMode should be active"); //ErrorMode 466 BOOST_CHECK_MESSAGE(p.get_state<player_::AllOk&>().exit_counter == 1,"AllOk exit not called correctly"); 467 BOOST_CHECK_MESSAGE(p.get_state<player_::ErrorMode&>().entry_counter == 1,"ErrorMode entry not called correctly"); 468 BOOST_CHECK_MESSAGE(p.current_state()[0] == 0,"Stopped should be active"); //Stopped 469 BOOST_CHECK_MESSAGE(p.get_state<player_::Stopped&>().exit_counter == 2,"Stopped exit not called correctly"); 470 BOOST_CHECK_MESSAGE(p.get_state<player_::Stopped&>().entry_counter == 3,"Stopped entry not called correctly"); 471 472 p.process_event(end_error()); 473 BOOST_CHECK_MESSAGE(p.current_state()[1] == 5,"AllOk should be active"); //AllOk 474 BOOST_CHECK_MESSAGE(p.get_state<player_::ErrorMode&>().exit_counter == 1,"ErrorMode exit not called correctly"); 475 BOOST_CHECK_MESSAGE(p.get_state<player_::AllOk&>().entry_counter == 2,"AllOk entry not called correctly"); 476 477 p.process_event(play()); 478 BOOST_CHECK_MESSAGE(p.current_state()[0] == 3,"Playing should be active"); //Playing 479 BOOST_CHECK_MESSAGE(p.get_state<player_::Stopped&>().exit_counter == 3,"Stopped exit not called correctly"); 480 BOOST_CHECK_MESSAGE(p.get_state<player_::Playing&>().entry_counter == 3,"Playing entry not called correctly"); 481 482 //test terminate 483 BOOST_CHECK_MESSAGE(p.current_state()[1] == 5,"AllOk should be active"); //AllOk 484 p.process_event(do_terminate()); 485 BOOST_CHECK_MESSAGE(p.current_state()[1] == 7,"ErrorTerminate should be active"); //ErrorTerminate 486 BOOST_CHECK_MESSAGE(p.get_state<player_::AllOk&>().exit_counter == 2,"AllOk exit not called correctly"); 487 BOOST_CHECK_MESSAGE(p.get_state<player_::ErrorTerminate&>().entry_counter == 1,"ErrorTerminate entry not called correctly"); 488 489 // try generating more events 490 p.process_event(stop()); 491 BOOST_CHECK_MESSAGE(p.current_state()[1] == 7,"ErrorTerminate should be active"); //ErrorTerminate 492 BOOST_CHECK_MESSAGE(p.get_state<player_::ErrorTerminate&>().exit_counter == 0,"ErrorTerminate exit not called correctly"); 493 BOOST_CHECK_MESSAGE(p.current_state()[0] == 3,"Playing should be active"); //Playing 494 BOOST_CHECK_MESSAGE(p.get_state<player_::Playing&>().exit_counter == 2,"Playing exit not called correctly"); 495 BOOST_CHECK_MESSAGE(p.get_state<player_::Stopped&>().entry_counter == 3,"Stopped entry not called correctly"); 496 497 p.process_event(end_error()); 498 BOOST_CHECK_MESSAGE(p.current_state()[1] == 7,"ErrorTerminate should be active"); //ErrorTerminate 499 BOOST_CHECK_MESSAGE(p.current_state()[0] == 3,"Playing should be active"); //Playing 500 BOOST_CHECK_MESSAGE(p.get_state<player_::Playing&>().exit_counter == 2,"Playing exit not called correctly"); 501 BOOST_CHECK_MESSAGE(p.get_state<player_::Stopped&>().entry_counter == 3,"Stopped entry not called correctly"); 502 503 p.process_event(stop()); 504 BOOST_CHECK_MESSAGE(p.current_state()[1] == 7,"ErrorTerminate should be active"); //ErrorTerminate 505 BOOST_CHECK_MESSAGE(p.current_state()[0] == 3,"Playing should be active"); //Playing 506 BOOST_CHECK_MESSAGE(p.get_state<player_::Playing&>().exit_counter == 2,"Playing exit not called correctly"); 507 BOOST_CHECK_MESSAGE(p.get_state<player_::Stopped&>().entry_counter == 3,"Stopped entry not called correctly"); 508 509 } 510 } 511 512