1// Copyright 2024 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
12// back-end
13#include <boost/msm/back11/state_machine.hpp>
14//front-end
15#include <boost/msm/front/state_machine_def.hpp>
16#include <boost/msm/front/puml/puml.hpp>
17#include <PumlCommon.hpp>
18
19#ifndef BOOST_MSM_NONSTANDALONE_TEST
20#define BOOST_TEST_MODULE back11_simple_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{
31
32
33 // front-end: define the FSM structure
34 struct player_ : public msm::front::state_machine_def<player_>
35 {
36 unsigned int start_playback_counter=0;
37 unsigned int can_close_drawer_counter=0;
38 unsigned int test_fct_counter=0;
39 BOOST_MSM_PUML_DECLARE_TABLE(
40 R"(
41 @startuml Player
42 skinparam linetype polyline
43 state Player{
44 [*]-> Empty
45 Stopped -> Playing2 : play / TestFct,start_playback [DummyGuard]
46 Stopped -> Open : open_close / open_drawer
47 Stopped -> Stopped : stop
48
49 Open -> Empty : open_close / close_drawer [can_close_drawer]
50 Empty --> Open : open_close / open_drawer
51 Empty ---> Stopped : cd_detected / store_cd_info2 [good_disk_format && always_true]
52 Playing2 --> Stopped : stop / stop_playback
53 Playing2 -> Paused : pause / pause_playback
54 Playing2 --> Open : open_close / stop_and_open
55 Paused -> Playing2 : end_pause / resume_playback2
56 Paused --> Stopped : stop / stop_playback
57 Paused --> Open : open_close / stop_and_open
58 }
59 @enduml
60 )"
61 )
62
63 // Replaces the default no-transition response.
64 template <class FSM,class Event>
65 void no_transition(Event const&, FSM&,int)
66 {
67 BOOST_FAIL("no_transition called!");
68 }
69 };
70 // Pick a back-end
71 typedef msm::back11::state_machine<player_> player;
72
73
74 BOOST_AUTO_TEST_CASE( back11_simple_with_puml_test )
75 {
76 player p;
77
78 p.start();
79 BOOST_CHECK_MESSAGE(p.get_state<State<by_name("Empty")>&>().entry_counter == 1, "Empty entry not called correctly");
80
81 p.process_event(Event<by_name(str: "open_close")>{});
82 BOOST_CHECK_MESSAGE(p.current_state()[0] == 1,"Open should be active"); //Open
83 BOOST_CHECK_MESSAGE(p.get_state<State<by_name("Empty")>&>().exit_counter == 1,"Empty exit not called correctly");
84 BOOST_CHECK_MESSAGE(p.get_state<State<by_name("Open")>&>().entry_counter == 1,"Open entry not called correctly");
85
86 p.process_event(Event<by_name(str: "open_close")>{});
87 BOOST_CHECK_MESSAGE(p.current_state()[0] == 2,"Empty should be active"); //Empty
88 BOOST_CHECK_MESSAGE(p.get_state<State<by_name("Open")>&>().exit_counter == 1,"Open exit not called correctly");
89 BOOST_CHECK_MESSAGE(p.get_state<State<by_name("Empty")>&>().entry_counter == 2,"Empty entry not called correctly");
90 BOOST_CHECK_MESSAGE(p.can_close_drawer_counter == 1,"guard not called correctly");
91
92 p.process_event(Event<by_name(str: "cd_detected")>{"louie, louie", DISK_DVD});
93
94 BOOST_CHECK_MESSAGE(p.current_state()[0] == 2,"Empty should be active"); //Empty
95 BOOST_CHECK_MESSAGE(p.get_state<State<by_name("Open")>&>().exit_counter == 1,"Open exit not called correctly");
96 BOOST_CHECK_MESSAGE(p.get_state<State<by_name("Empty")>&>().entry_counter == 2,"Empty entry not called correctly");
97
98 p.process_event(Event<by_name(str: "cd_detected")>{"louie, louie", DISK_CD});
99 BOOST_CHECK_MESSAGE(p.current_state()[0] == 3,"Playing2 should be active"); //Playing2
100 BOOST_CHECK_MESSAGE(p.get_state<State<by_name("Empty")>&>().exit_counter == 2,"Empty exit not called correctly");
101 BOOST_CHECK_MESSAGE(p.get_state<State<by_name("Stopped")>&>().entry_counter == 1,"Stopped entry not called correctly");
102 BOOST_CHECK_MESSAGE(p.get_state<State<by_name("Stopped")>&>().exit_counter == 1,"Stopped exit not called correctly");
103 BOOST_CHECK_MESSAGE(p.get_state<State<by_name("Playing2")>&>().entry_counter == 1,"Playing2 entry not called correctly");
104 BOOST_CHECK_MESSAGE(p.start_playback_counter == 1,"action not called correctly");
105 BOOST_CHECK_MESSAGE(p.test_fct_counter == 1,"action not called correctly");
106
107 p.process_event(Event<by_name(str: "pause")>{});
108 BOOST_CHECK_MESSAGE(p.current_state()[0] == 4,"Paused should be active"); //Paused
109 BOOST_CHECK_MESSAGE(p.get_state<State<by_name("Playing2")>&>().exit_counter == 1,"Playing2 exit not called correctly");
110 BOOST_CHECK_MESSAGE(p.get_state<State<by_name("Paused")>&>().entry_counter == 1,"Paused entry not called correctly");
111
112 // go back to Playing2
113 p.process_event(Event<by_name(str: "end_pause")>{});
114 BOOST_CHECK_MESSAGE(p.current_state()[0] == 3,"Playing2 should be active"); //Playing2
115 BOOST_CHECK_MESSAGE(p.get_state<State<by_name("Paused")>&>().exit_counter == 1,"Paused exit not called correctly");
116 BOOST_CHECK_MESSAGE(p.get_state<State<by_name("Playing2")>&>().entry_counter == 2,"Playing2 entry not called correctly");
117 BOOST_CHECK_MESSAGE(p.get_state<State<by_name("Playing2")>&>().event_counter == 1,"Playing2 event counter incorrect");
118
119 p.process_event(Event<by_name(str: "pause")>{});
120 BOOST_CHECK_MESSAGE(p.current_state()[0] == 4,"Paused should be active"); //Paused
121 BOOST_CHECK_MESSAGE(p.get_state<State<by_name("Playing2")>&>().exit_counter == 2,"Playing2 exit not called correctly");
122 BOOST_CHECK_MESSAGE(p.get_state<State<by_name("Paused")>&>().entry_counter == 2,"Paused entry not called correctly");
123
124 p.process_event(Event<by_name(str: "stop")>{});
125 BOOST_CHECK_MESSAGE(p.current_state()[0] == 0,"Stopped should be active"); //Stopped
126 BOOST_CHECK_MESSAGE(p.get_state<State<by_name("Paused")>&>().exit_counter == 2,"Paused exit not called correctly");
127 BOOST_CHECK_MESSAGE(p.get_state<State<by_name("Stopped")>&>().entry_counter == 2,"Stopped entry not called correctly");
128
129 p.process_event(Event<by_name(str: "stop")>{});
130 BOOST_CHECK_MESSAGE(p.current_state()[0] == 0,"Stopped should be active"); //Stopped
131 BOOST_CHECK_MESSAGE(p.get_state<State<by_name("Stopped")>&>().exit_counter == 2,"Stopped exit not called correctly");
132 BOOST_CHECK_MESSAGE(p.get_state<State<by_name("Stopped")>&>().entry_counter == 3,"Stopped entry not called correctly");
133
134 }
135}
136
137

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