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