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 | #include <boost/core/ignore_unused.hpp> |
12 | |
13 | #include <boost/msm/front/puml/puml.hpp> |
14 | |
15 | #ifndef BOOST_MSM_NONSTANDALONE_TEST |
16 | #define BOOST_TEST_MODULE puml_test |
17 | #endif |
18 | #include <boost/test/unit_test.hpp> |
19 | |
20 | using namespace boost::msm::front; |
21 | using namespace boost::msm::front::puml; |
22 | |
23 | namespace |
24 | { |
25 | |
26 | BOOST_AUTO_TEST_CASE( puml_test ) |
27 | { |
28 | constexpr auto stt_ = R"([*]-> StateA |
29 | StateA -> StateB: evt1/ A2 [G1] |
30 | StateB -> StateB : evt1/ A1,A2 [G1] |
31 | |
32 | StateB -> StateA: evt1)" ; |
33 | auto stt = |
34 | boost::msm::front::puml::create_transition_table([&]() {return stt_; }); |
35 | static_assert(std::is_same_v< |
36 | decltype(stt), |
37 | boost::fusion::vector< |
38 | Row<State <by_name("StateA" )>, Event <by_name("evt1" )>, State <by_name("StateB" )>, Action <by_name("A2" )>, Guard <by_name("G1" )> >, |
39 | Row<State <by_name("StateB" )>, Event <by_name("evt1" )>, State <by_name("StateB" )>, ActionSequence_<boost::fusion::vector< Action<by_name("A1" )>, Action<by_name("A2" )>>>, Guard <by_name("G1" )> >, |
40 | Row<State <by_name("StateB" )>, Event <by_name("evt1" )>, State <by_name("StateA" )>, none, none > |
41 | > |
42 | >); |
43 | |
44 | constexpr auto stt2_ = R"([*]->StateA |
45 | StateA -> StateB: evt1/ A2 [G1&&G2] |
46 | StateB -> StateB : evt1/ A1, defer [G1] |
47 | |
48 | StateB -> StateA: evt1)" ; |
49 | auto stt2 = |
50 | boost::msm::front::puml::create_transition_table([&]() {return stt2_; }); |
51 | static_assert(std::is_same_v< |
52 | decltype(stt2), |
53 | boost::fusion::vector< |
54 | Row<State <by_name("StateA" )>, Event <by_name("evt1" )>, State <by_name("StateB" )>, Action <by_name("A2" )>, And_<Guard <by_name("G1" )>, Guard <by_name("G2" )>> >, |
55 | Row<State <by_name("StateB" )>, Event <by_name("evt1" )>, State <by_name("StateB" )>, ActionSequence_<boost::fusion::vector< Action<by_name("A1" )>, Defer>>, Guard <by_name("G1" )> >, |
56 | Row<State <by_name("StateB" )>, Event <by_name("evt1" )>, State <by_name("StateA" )>, none, none > |
57 | > |
58 | >); |
59 | |
60 | constexpr auto stt3_ = R"(StateA -> StateB: evt1/ A2 [G1 && G2 && G3])" ; |
61 | auto stt3 = |
62 | boost::msm::front::puml::create_transition_table([&]() {return stt3_; }); |
63 | static_assert(std::is_same_v< |
64 | decltype(stt3), |
65 | boost::fusion::vector< |
66 | Row<State <by_name("StateA" )>, Event <by_name("evt1" )>, State <by_name("StateB" )>, Action <by_name("A2" )>, And_<Guard <by_name("G1" )>, And_<Guard <by_name("G2" )>, Guard <by_name("G3" )>>> > |
67 | > |
68 | >); |
69 | |
70 | constexpr auto stt4_ = R"(StateA -> StateB: evt1/ A2 [G1 || G2])" ; |
71 | auto stt4 = |
72 | boost::msm::front::puml::create_transition_table([&]() {return stt4_; }); |
73 | static_assert(std::is_same_v< |
74 | decltype(stt4), |
75 | boost::fusion::vector< |
76 | Row<State <by_name("StateA" )>, Event <by_name("evt1" )>, State <by_name("StateB" )>, Action <by_name("A2" )>, Or_<Guard <by_name("G1" )>, Guard <by_name("G2" )>> > |
77 | > |
78 | >); |
79 | |
80 | constexpr auto stt5_ = R"(StateA -> StateB: evt1/ A2 [G1 && G2 || G3])" ; |
81 | auto stt5 = |
82 | boost::msm::front::puml::create_transition_table([&]() {return stt5_; }); |
83 | static_assert(std::is_same_v< |
84 | decltype(stt5), |
85 | boost::fusion::vector< |
86 | Row<State <by_name("StateA" )>, Event <by_name("evt1" )>, State <by_name("StateB" )>, Action <by_name("A2" )>, Or_<And_<Guard <by_name("G1" )>, Guard <by_name("G2" )>>, Guard <by_name("G3" )>> > |
87 | > |
88 | >); |
89 | |
90 | constexpr auto stt6_ = R"(StateA ---> StateB: evt1/ A2 [!G1])" ; |
91 | auto stt6 = |
92 | boost::msm::front::puml::create_transition_table([&]() {return stt6_; }); |
93 | static_assert(std::is_same_v< |
94 | decltype(stt6), |
95 | boost::fusion::vector< |
96 | Row<State <by_name("StateA" )>, Event <by_name("evt1" )>, State <by_name("StateB" )>, Action <by_name("A2" )>, Not_<Guard <by_name("G1" )>> > |
97 | > |
98 | >); |
99 | |
100 | constexpr auto stt7_ = R"(StateA -> StateB: evt1/ A2 [G1 || !G2])" ; |
101 | auto stt7 = |
102 | boost::msm::front::puml::create_transition_table([&]() {return stt7_; }); |
103 | static_assert(std::is_same_v< |
104 | decltype(stt7), |
105 | boost::fusion::vector< |
106 | Row<State <by_name("StateA" )>, Event <by_name("evt1" )>, State <by_name("StateB" )>, Action <by_name("A2" )>, Or_<Guard <by_name("G1" )>, Not_<Guard <by_name("G2" )>>> > |
107 | > |
108 | >); |
109 | |
110 | constexpr auto stt8_ = R"(StateA -> StateB: evt1/ A2 [Or(G1,Not(G2))])" ; |
111 | auto stt8 = |
112 | boost::msm::front::puml::create_transition_table([&]() {return stt8_; }); |
113 | static_assert(std::is_same_v< |
114 | decltype(stt8), |
115 | boost::fusion::vector< |
116 | Row<State <by_name("StateA" )>, Event <by_name("evt1" )>, State <by_name("StateB" )>, Action <by_name("A2" )>, Or_<Guard <by_name("G1" )>, Not_<Guard <by_name("G2" )>>> > |
117 | > |
118 | >); |
119 | |
120 | auto stt9 = |
121 | boost::msm::front::puml::create_transition_table([]() {return R"(StateA -> StateB: evt1/ A2 [(G1 || G2) && G3])" ; }); |
122 | static_assert(std::is_same_v< |
123 | decltype(stt9), |
124 | boost::fusion::vector< |
125 | Row<State <by_name("StateA" )>, Event <by_name("evt1" )>, State <by_name("StateB" )>, Action <by_name("A2" )>, And_<Or_<Guard <by_name("G1" )>, Guard <by_name("G2" )>>, Guard <by_name("G3" )>> > |
126 | > |
127 | >); |
128 | |
129 | auto stt10 = |
130 | boost::msm::front::puml::create_transition_table([]() {return R"(StateA -> StateB: evt1/ A2 [(G1 && G2) || G3])" ; }); |
131 | static_assert(std::is_same_v< |
132 | decltype(stt10), |
133 | boost::fusion::vector< |
134 | Row<State <by_name("StateA" )>, Event <by_name("evt1" )>, State <by_name("StateB" )>, Action <by_name("A2" )>, Or_<And_<Guard <by_name("G1" )>, Guard <by_name("G2" )>>, Guard <by_name("G3" )>> > |
135 | > |
136 | >); |
137 | |
138 | auto stt11 = |
139 | boost::msm::front::puml::create_transition_table([]() {return R"(StateA -> StateB: evt1/ A2 [G3 && ( G1 || G2 )])" ; }); |
140 | static_assert(std::is_same_v< |
141 | decltype(stt11), |
142 | boost::fusion::vector< |
143 | Row<State <by_name("StateA" )>, Event <by_name("evt1" )>, State <by_name("StateB" )>, Action <by_name("A2" )>, And_<Guard <by_name("G3" )>, Or_<Guard <by_name("G1" )>, Guard <by_name("G2" )>>> > |
144 | > |
145 | >); |
146 | |
147 | auto stt12 = |
148 | boost::msm::front::puml::create_transition_table([]() {return R"(StateA -> StateB: evt1/ A2 [G3 || ( G1 && G2 )])" ; }); |
149 | static_assert(std::is_same_v< |
150 | decltype(stt12), |
151 | boost::fusion::vector< |
152 | Row<State <by_name("StateA" )>, Event <by_name("evt1" )>, State <by_name("StateB" )>, Action <by_name("A2" )>, Or_<Guard <by_name("G3" )>, And_<Guard <by_name("G1" )>, Guard <by_name("G2" )>>> > |
153 | > |
154 | >); |
155 | |
156 | auto stt13 = |
157 | boost::msm::front::puml::create_transition_table([]() {return R"(StateA -> StateB: evt1/ A2 [!( G1 && G2 )])" ; }); |
158 | static_assert(std::is_same_v< |
159 | decltype(stt13), |
160 | boost::fusion::vector< |
161 | Row<State <by_name("StateA" )>, Event <by_name("evt1" )>, State <by_name("StateB" )>, Action <by_name("A2" )>, Not_<And_<Guard <by_name("G1" )>, Guard <by_name("G2" )>>> > |
162 | > |
163 | >); |
164 | |
165 | auto stt14 = |
166 | boost::msm::front::puml::create_transition_table([]() {return R"(StateA -> StateB: evt1/ A2 [G3 || !( G1 && G2 )])" ; }); |
167 | static_assert(std::is_same_v< |
168 | decltype(stt14), |
169 | boost::fusion::vector< |
170 | Row<State <by_name("StateA" )>, Event <by_name("evt1" )>, State <by_name("StateB" )>, Action <by_name("A2" )>, Or_<Guard <by_name("G3" )>, Not_<And_<Guard <by_name("G1" )>, Guard <by_name("G2" )>>>> > |
171 | > |
172 | >); |
173 | |
174 | auto stt15 = |
175 | boost::msm::front::puml::create_transition_table([]() {return R"(StateA -> StateB: evt1/ A2 [(G3 && G1) || ( G1 && G2 )])" ; }); |
176 | static_assert(std::is_same_v< |
177 | decltype(stt15), |
178 | boost::fusion::vector< |
179 | Row<State <by_name("StateA" )>, Event <by_name("evt1" )>, State <by_name("StateB" )>, Action <by_name("A2" )>, |
180 | Or_<And_<Guard <by_name("G3" )>, Guard <by_name("G1" )>>, And_<Guard <by_name("G1" )>, Guard <by_name("G2" )>>> > |
181 | > |
182 | >); |
183 | |
184 | auto stt16 = |
185 | boost::msm::front::puml::create_transition_table([]() {return R"(StateA -> StateB: evt1/ A2 [(G3 && G1) || !(G1 && G2)])" ; }); |
186 | static_assert(std::is_same_v< |
187 | decltype(stt16), |
188 | boost::fusion::vector< |
189 | Row<State <by_name("StateA" )>, Event <by_name("evt1" )>, State <by_name("StateB" )>, Action <by_name("A2" )>, |
190 | Or_<And_<Guard <by_name("G3" )>, Guard <by_name("G1" )>>, Not_<And_<Guard <by_name("G1" )>, Guard <by_name("G2" )>>>> > |
191 | > |
192 | >); |
193 | |
194 | // internal detail::Transition |
195 | auto stt17 = |
196 | boost::msm::front::puml::create_transition_table([]() {return R"(StateA -> StateA: -evt1/ A2 [G1])" ; }); |
197 | static_assert(std::is_same_v< |
198 | decltype(stt17), |
199 | boost::fusion::vector< |
200 | Row<State <by_name("StateA" )>, Event <by_name("evt1" )>, none, Action <by_name("A2" )>, Guard <by_name("G1" )>> |
201 | > |
202 | >); |
203 | |
204 | // kleene |
205 | auto stt18 = |
206 | boost::msm::front::puml::create_transition_table([]() {return R"(StateA -> StateA: * / A2 [G1])" ; }); |
207 | static_assert(std::is_same_v< |
208 | decltype(stt18), |
209 | boost::fusion::vector< |
210 | Row<State <by_name("StateA" )>, boost::any, State <by_name("StateA" )>, Action <by_name("A2" )>, Guard <by_name("G1" )>> |
211 | > |
212 | >); |
213 | |
214 | // internal + kleene |
215 | auto stt19 = |
216 | boost::msm::front::puml::create_transition_table([]() {return R"(StateA -> StateA: -* / A2 [G1])" ; }); |
217 | static_assert(std::is_same_v< |
218 | decltype(stt19), |
219 | boost::fusion::vector< |
220 | Row<State <by_name("StateA" )>, boost::any, none, Action <by_name("A2" )>, Guard <by_name("G1" )>> |
221 | > |
222 | >); |
223 | |
224 | // test init states |
225 | static_assert(std::is_same_v< |
226 | decltype(boost::msm::front::puml::create_transition_table([]() {return R"([*] -> StateA |
227 | StateA --> StateA: evt1 / defer)" ; })), |
228 | boost::fusion::vector< |
229 | Row<State <by_name("StateA" )>, Event <by_name("evt1" )>, State <by_name("StateA" )>, Defer, none > |
230 | > |
231 | > ); |
232 | |
233 | |
234 | State< by_name(str: "StateXXX" )> s1; |
235 | boost::ignore_unused(s1); |
236 | |
237 | // initial states |
238 | constexpr auto stt9_ = R"( |
239 | [*] --> StateA |
240 | StateA -> StateB: evt1 [G1] |
241 | StateB -> StateB : evt1 / A1 [G1] |
242 | -- |
243 | [*]->StateC |
244 | StateC -> StateD: -*)" ; |
245 | auto inits = |
246 | create_initial_states(stt_func: [&]() {return stt9_; }); |
247 | static_assert(std::is_same_v< |
248 | decltype(inits), |
249 | boost::fusion::vector< State <by_name(str: "StateA" )>, State <by_name(str: "StateC" )>> |
250 | >); |
251 | |
252 | //constexpr auto name_ = "StateA"; |
253 | //std::cout << typeid(boost::msm::front::puml::detail::parse_flags(stt_, name_)).name() << std::endl; |
254 | } |
255 | } |
256 | |
257 | |