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_only_string_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 // note in the puml tests will be non-specialized types marked with _
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 unsigned int entry_counter = 0;
40 unsigned int exit_counter = 0;
41
42 BOOST_MSM_PUML_DECLARE_TABLE(
43 R"(
44 @startuml Player
45 skinparam linetype polyline
46 state Player{
47 [*]-> Empty_
48 Stopped_ -> Playing_ : play / TestFct,start_playback [DummyGuard]
49 Stopped_ -> Open_ : open_close_ / open_drawer
50 Stopped_ -> Stopped_ : stop_
51
52 Open_ -> Empty_ : open_close_ / close_drawer [can_close_drawer]
53 Empty_ --> Open_ : open_close_ / open_drawer
54 Empty_ ---> Stopped_ : cd_detected / store_cd_info2 [good_disk_format && always_true]
55 Playing_ --> Stopped_ : stop_ / stop_playback
56 Playing_ -> Paused_ : pause_ / pause_playback
57 Playing_ --> Open_ : open_close_ / stop_and_open
58 Paused_ -> Playing_ : end_pause / resume_playback2
59 Paused_ --> Stopped_ : stop_ / stop_playback
60 Paused_ --> Open_ : open_close_ / stop_and_open
61 Playing_ : flag CDLoaded
62 Playing_ : entry increment_entry [always_true]
63 Playing_ : exit increment_exit [always_true]
64 Paused_ : flag CDLoaded
65 Stopped_ : flag CDLoaded
66 }
67 @enduml
68 )"
69 )
70
71 // Replaces the default no-transition response.
72 template <class FSM,class Event>
73 void no_transition(Event const&, FSM&,int)
74 {
75 BOOST_FAIL("no_transition called!");
76 }
77 };
78 // Pick a back-end
79 typedef msm::back11::state_machine<player_> player;
80
81
82 BOOST_AUTO_TEST_CASE(back11_only_string_puml_test)
83 {
84 player p;
85 static_assert(msm::back11::get_number_of_regions<typename player::initial_state>::type::value == 1);
86 static_assert(::boost::mpl::size<typename player::transition_table>::type::value == 12);
87
88 p.start();
89
90 p.process_event(Event<by_name(str: "open_close_")>{});
91 BOOST_CHECK_MESSAGE(p.current_state()[0] == 1,"Open should be active"); //Open
92 BOOST_CHECK_MESSAGE(p.is_flag_active<Flag<by_name("CDLoaded")>>() == false, "CDLoaded should not be active");
93
94 p.process_event(Event<by_name(str: "open_close_")>{});
95 BOOST_CHECK_MESSAGE(p.current_state()[0] == 2,"Empty should be active"); //Empty
96 BOOST_CHECK_MESSAGE(p.can_close_drawer_counter == 1,"guard not called correctly");
97
98 p.process_event(Event<by_name(str: "cd_detected")>{"louie, louie", DISK_DVD});
99 BOOST_CHECK_MESSAGE(p.current_state()[0] == 2,"Empty should be active"); //Empty
100
101 BOOST_CHECK_MESSAGE(p.entry_counter == 0, "Playing entry not called correctly");
102 BOOST_CHECK_MESSAGE(p.exit_counter == 0, "Playing exit not called correctly");
103
104 p.process_event(Event<by_name(str: "cd_detected")>{"louie, louie", DISK_CD});
105 BOOST_CHECK_MESSAGE(p.current_state()[0] == 3,"Playing should be active"); //Playing
106 BOOST_CHECK_MESSAGE(p.start_playback_counter == 1,"action not called correctly");
107 BOOST_CHECK_MESSAGE(p.test_fct_counter == 1,"action not called correctly");
108 BOOST_CHECK_MESSAGE(p.is_flag_active < Flag<by_name("CDLoaded")>>() == true, "CDLoaded should be active");
109 BOOST_CHECK_MESSAGE(p.entry_counter == 1, "Playing entry not called correctly");
110 BOOST_CHECK_MESSAGE(p.exit_counter == 0, "Playing exit not called correctly");
111
112 p.process_event(Event<by_name(str: "pause_")>{});
113 BOOST_CHECK_MESSAGE(p.current_state()[0] == 4,"Paused should be active"); //Paused
114 BOOST_CHECK_MESSAGE(p.is_flag_active < Flag<by_name("CDLoaded")>>() == true, "CDLoaded should be active");
115 BOOST_CHECK_MESSAGE(p.entry_counter == 1, "Playing entry not called correctly");
116 BOOST_CHECK_MESSAGE(p.exit_counter == 1, "Playing exit not called correctly");
117
118 // go back to Playing
119 p.process_event(Event<by_name(str: "end_pause")>{});
120 BOOST_CHECK_MESSAGE(p.current_state()[0] == 3,"Playing should be active"); //Playing
121 BOOST_CHECK_MESSAGE(p.entry_counter == 2, "Playing entry not called correctly");
122 BOOST_CHECK_MESSAGE(p.exit_counter == 1, "Playing exit not called correctly");
123
124 p.process_event(Event<by_name(str: "pause_")>{});
125 BOOST_CHECK_MESSAGE(p.current_state()[0] == 4,"Paused should be active"); //Paused
126 BOOST_CHECK_MESSAGE(p.entry_counter == 2, "Playing entry not called correctly");
127 BOOST_CHECK_MESSAGE(p.exit_counter == 2, "Playing exit 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.is_flag_active < Flag<by_name("CDLoaded")>>() == true, "CDLoaded should be active");
132
133 p.process_event(Event<by_name(str: "stop_")>{});
134 BOOST_CHECK_MESSAGE(p.current_state()[0] == 0,"Stopped should be active"); //Stopped
135
136 }
137}
138
139

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