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