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

source code of boost/libs/msm/test/Back11OrthogonalDeferred3WithPuml.cpp