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
20namespace msm = boost::msm;
21namespace mpl = boost::mpl;
22
23namespace
24{
25 // events
26 struct event1 {};
27 struct event2 {};
28 struct event3 {};
29 struct event4 {};
30 struct event5 {};
31 struct event6
32 {
33 event6(){}
34 template <class Event>
35 event6(Event const&){}
36 };
37 // front-end: define the FSM structure
38 struct Fsm_ : public msm::front::state_machine_def<Fsm_>
39 {
40 // The list of FSM states
41 struct State1 : public msm::front::state<>
42 {
43 template <class Event,class FSM>
44 void on_entry(Event const&,FSM& ) {++entry_counter;}
45 template <class Event,class FSM>
46 void on_exit(Event const&,FSM& ) {++exit_counter;}
47 int entry_counter;
48 int exit_counter;
49 };
50 struct State2 : public msm::front::state<>
51 {
52 template <class Event,class FSM>
53 void on_entry(Event const&,FSM& ) {++entry_counter;}
54 template <class Event,class FSM>
55 void on_exit(Event const&,FSM& ) {++exit_counter;}
56 int entry_counter;
57 int exit_counter;
58 };
59 struct SubFsm2_ : public msm::front::state_machine_def<SubFsm2_>
60 {
61 typedef msm::back::state_machine<SubFsm2_> SubFsm2;
62
63 unsigned int entry_action_counter;
64
65 template <class Event,class FSM>
66 void on_entry(Event const&,FSM& ) {++entry_counter;}
67 template <class Event,class FSM>
68 void on_exit(Event const&,FSM& ) {++exit_counter;}
69 int entry_counter;
70 int exit_counter;
71
72 struct SubState1 : public msm::front::state<>
73 {
74 template <class Event,class FSM>
75 void on_entry(Event const&,FSM& ) {++entry_counter;}
76 template <class Event,class FSM>
77 void on_exit(Event const&,FSM& ) {++exit_counter;}
78 int entry_counter;
79 int exit_counter;
80 };
81 struct SubState1b : public msm::front::state<>
82 {
83 template <class Event,class FSM>
84 void on_entry(Event const&,FSM& ) {++entry_counter;}
85 template <class Event,class FSM>
86 void on_exit(Event const&,FSM& ) {++exit_counter;}
87 int entry_counter;
88 int exit_counter;
89 };
90 struct SubState2 : public msm::front::state<> , public msm::front::explicit_entry<0>
91 {
92 template <class Event,class FSM>
93 void on_entry(Event const&,FSM& ) {++entry_counter;}
94 template <class Event,class FSM>
95 void on_exit(Event const&,FSM& ) {++exit_counter;}
96 int entry_counter;
97 int exit_counter;
98 };
99 struct SubState2b : public msm::front::state<> , public msm::front::explicit_entry<1>
100 {
101 template <class Event,class FSM>
102 void on_entry(Event const&,FSM& ) {++entry_counter;}
103 template <class Event,class FSM>
104 void on_exit(Event const&,FSM& ) {++exit_counter;}
105 int entry_counter;
106 int exit_counter;
107 };
108 // test with a pseudo entry
109 struct PseudoEntry1 : public msm::front::entry_pseudo_state<0>
110 {
111 template <class Event,class FSM>
112 void on_entry(Event const&,FSM& ) {++entry_counter;}
113 template <class Event,class FSM>
114 void on_exit(Event const&,FSM& ) {++exit_counter;}
115 int entry_counter;
116 int exit_counter;
117 };
118 struct SubState3 : public msm::front::state<>
119 {
120 template <class Event,class FSM>
121 void on_entry(Event const&,FSM& ) {++entry_counter;}
122 template <class Event,class FSM>
123 void on_exit(Event const&,FSM& ) {++exit_counter;}
124 int entry_counter;
125 int exit_counter;
126 };
127 struct PseudoExit1 : public msm::front::exit_pseudo_state<event6>
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 // action methods
137 void entry_action(event4 const&)
138 {
139 ++entry_action_counter;
140 }
141 // the initial state. Must be defined
142 typedef mpl::vector<SubState1,SubState1b> initial_state;
143
144 typedef mpl::vector<SubState2b> explicit_creation;
145
146 // Transition table for SubFsm2
147 struct transition_table : mpl::vector<
148 // Start Event Next Action Guard
149 // +--------------+-------------+------------+------------------------+----------------------+
150 a_row < PseudoEntry1 , event4 , SubState3 ,&SubFsm2_::entry_action >,
151 _row < SubState2 , event6 , SubState1 >,
152 _row < SubState3 , event5 , PseudoExit1 >
153 // +--------------+-------------+------------+------------------------+----------------------+
154 > {};
155 // Replaces the default no-transition response.
156 template <class FSM,class Event>
157 void no_transition(Event const& , FSM&,int)
158 {
159 BOOST_FAIL("no_transition called!");
160 }
161 };
162 typedef msm::back::state_machine<SubFsm2_> SubFsm2;
163
164 // the initial state of the player SM. Must be defined
165 typedef State1 initial_state;
166
167 // transition actions
168 // guard conditions
169
170 // Transition table for Fsm
171 struct transition_table : mpl::vector<
172 // Start Event Next Action Guard
173 // +---------------------+--------+------------------------------------+-------+--------+
174 _row < State1 , event1 , SubFsm2 >,
175 _row < State1 , event2 , SubFsm2::direct<SubFsm2_::SubState2> >,
176 _row < State1 , event3 , mpl::vector<SubFsm2::direct<SubFsm2_::SubState2>,
177 SubFsm2::direct<SubFsm2_::SubState2b> > >,
178 _row < State1 , event4 , SubFsm2::entry_pt
179 <SubFsm2_::PseudoEntry1> >,
180 // +---------------------+--------+------------------------------------+-------+--------+
181 _row < SubFsm2 , event1 , State1 >,
182 _row < SubFsm2::exit_pt
183 <SubFsm2_::PseudoExit1>, event6 , State2 >
184 // +---------------------+--------+------------------------------------+-------+--------+
185 > {};
186
187 // Replaces the default no-transition response.
188 template <class FSM,class Event>
189 void no_transition(Event const& , FSM&,int )
190 {
191 BOOST_FAIL("no_transition called!");
192 }
193 // init counters
194 template <class Event,class FSM>
195 void on_entry(Event const&,FSM& fsm)
196 {
197 fsm.template get_state<Fsm_::State1&>().entry_counter=0;
198 fsm.template get_state<Fsm_::State1&>().exit_counter=0;
199 fsm.template get_state<Fsm_::State2&>().entry_counter=0;
200 fsm.template get_state<Fsm_::State2&>().exit_counter=0;
201 fsm.template get_state<Fsm_::SubFsm2&>().entry_counter=0;
202 fsm.template get_state<Fsm_::SubFsm2&>().exit_counter=0;
203 fsm.template get_state<Fsm_::SubFsm2&>().entry_action_counter=0;
204 fsm.template get_state<Fsm_::SubFsm2&>().template get_state<Fsm_::SubFsm2::SubState1&>().entry_counter=0;
205 fsm.template get_state<Fsm_::SubFsm2&>().template get_state<Fsm_::SubFsm2::SubState1&>().exit_counter=0;
206 fsm.template get_state<Fsm_::SubFsm2&>().template get_state<Fsm_::SubFsm2::SubState1b&>().entry_counter=0;
207 fsm.template get_state<Fsm_::SubFsm2&>().template get_state<Fsm_::SubFsm2::SubState1b&>().exit_counter=0;
208 fsm.template get_state<Fsm_::SubFsm2&>().template get_state<Fsm_::SubFsm2::SubState2&>().entry_counter=0;
209 fsm.template get_state<Fsm_::SubFsm2&>().template get_state<Fsm_::SubFsm2::SubState2&>().exit_counter=0;
210 fsm.template get_state<Fsm_::SubFsm2&>().template get_state<Fsm_::SubFsm2::SubState2b&>().entry_counter=0;
211 fsm.template get_state<Fsm_::SubFsm2&>().template get_state<Fsm_::SubFsm2::SubState2b&>().exit_counter=0;
212 fsm.template get_state<Fsm_::SubFsm2&>().template get_state<Fsm_::SubFsm2::SubState3&>().entry_counter=0;
213 fsm.template get_state<Fsm_::SubFsm2&>().template get_state<Fsm_::SubFsm2::SubState3&>().exit_counter=0;
214 fsm.template get_state<Fsm_::SubFsm2&>().template get_state<Fsm_::SubFsm2::PseudoEntry1&>().entry_counter=0;
215 fsm.template get_state<Fsm_::SubFsm2&>().template get_state<Fsm_::SubFsm2::PseudoEntry1&>().exit_counter=0;
216 fsm.template get_state<Fsm_::SubFsm2&>().template get_state<Fsm_::SubFsm2::exit_pt<SubFsm2_::PseudoExit1>&>().entry_counter=0;
217 fsm.template get_state<Fsm_::SubFsm2&>().template get_state<Fsm_::SubFsm2::exit_pt<SubFsm2_::PseudoExit1>&>().exit_counter=0;
218
219 }
220 };
221 typedef msm::back::state_machine<Fsm_> Fsm;
222// static char const* const state_names[] = { "State1", "SubFsm2","State2" };
223
224
225 BOOST_AUTO_TEST_CASE( entries_test )
226 {
227 Fsm p;
228
229 p.start();
230 BOOST_CHECK_MESSAGE(p.get_state<Fsm_::State1&>().entry_counter == 1,"State1 entry not called correctly");
231
232 p.process_event(evt: event1());
233 p.process_event(evt: event1());
234 BOOST_CHECK_MESSAGE(p.current_state()[0] == 0,"State1 should be active");
235 BOOST_CHECK_MESSAGE(p.get_state<Fsm_::State1&>().exit_counter == 1,"State1 exit not called correctly");
236 BOOST_CHECK_MESSAGE(p.get_state<Fsm_::State1&>().entry_counter == 2,"State1 entry not called correctly");
237 BOOST_CHECK_MESSAGE(p.get_state<Fsm_::SubFsm2&>().exit_counter == 1,"SubFsm2 exit not called correctly");
238 BOOST_CHECK_MESSAGE(p.get_state<Fsm_::SubFsm2&>().entry_counter == 1,"SubFsm2 entry not called correctly");
239
240 p.process_event(evt: event2());
241 p.process_event(evt: event6());
242 p.process_event(evt: event1());
243 BOOST_CHECK_MESSAGE(p.current_state()[0] == 0,"State1 should be active");
244 BOOST_CHECK_MESSAGE(p.get_state<Fsm_::State1&>().exit_counter == 2,"State1 exit not called correctly");
245 BOOST_CHECK_MESSAGE(p.get_state<Fsm_::State1&>().entry_counter == 3,"State1 entry not called correctly");
246 BOOST_CHECK_MESSAGE(p.get_state<Fsm_::SubFsm2&>().exit_counter == 2,"SubFsm2 exit not called correctly");
247 BOOST_CHECK_MESSAGE(p.get_state<Fsm_::SubFsm2&>().entry_counter == 2,"SubFsm2 entry not called correctly");
248 BOOST_CHECK_MESSAGE(p.get_state<Fsm_::SubFsm2&>().get_state<Fsm_::SubFsm2_::SubState2&>().entry_counter == 1,
249 "SubFsm2::SubState2 entry not called correctly");
250 BOOST_CHECK_MESSAGE(p.get_state<Fsm_::SubFsm2&>().get_state<Fsm_::SubFsm2_::SubState2&>().exit_counter == 1,
251 "SubFsm2::SubState2 exit not called correctly");
252 BOOST_CHECK_MESSAGE(p.get_state<Fsm_::SubFsm2&>().get_state<Fsm_::SubFsm2_::SubState1&>().entry_counter == 2,
253 "SubFsm2::SubState1 entry not called correctly");
254 BOOST_CHECK_MESSAGE(p.get_state<Fsm_::SubFsm2&>().get_state<Fsm_::SubFsm2_::SubState1&>().exit_counter == 2,
255 "SubFsm2::SubState1 exit not called correctly");
256
257 p.process_event(evt: event3());
258 p.process_event(evt: event1());
259 BOOST_CHECK_MESSAGE(p.current_state()[0] == 0,"State1 should be active");
260 BOOST_CHECK_MESSAGE(p.get_state<Fsm_::State1&>().exit_counter == 3,"State1 exit not called correctly");
261 BOOST_CHECK_MESSAGE(p.get_state<Fsm_::State1&>().entry_counter == 4,"State1 entry not called correctly");
262 BOOST_CHECK_MESSAGE(p.get_state<Fsm_::SubFsm2&>().exit_counter == 3,"SubFsm2 exit not called correctly");
263 BOOST_CHECK_MESSAGE(p.get_state<Fsm_::SubFsm2&>().entry_counter == 3,"SubFsm2 entry not called correctly");
264 BOOST_CHECK_MESSAGE(p.get_state<Fsm_::SubFsm2&>().get_state<Fsm_::SubFsm2_::SubState2&>().entry_counter == 2,
265 "SubFsm2::SubState2 entry not called correctly");
266 BOOST_CHECK_MESSAGE(p.get_state<Fsm_::SubFsm2&>().get_state<Fsm_::SubFsm2_::SubState2&>().exit_counter == 2,
267 "SubFsm2::SubState2 exit not called correctly");
268 BOOST_CHECK_MESSAGE(p.get_state<Fsm_::SubFsm2&>().get_state<Fsm_::SubFsm2_::SubState2b&>().entry_counter == 1,
269 "SubFsm2::SubState2b entry not called correctly");
270 BOOST_CHECK_MESSAGE(p.get_state<Fsm_::SubFsm2&>().get_state<Fsm_::SubFsm2_::SubState2b&>().exit_counter == 1,
271 "SubFsm2::SubState2b exit not called correctly");
272
273 p.process_event(evt: event4());
274 p.process_event(evt: event5());
275 BOOST_CHECK_MESSAGE(p.current_state()[0] == 2,"State2 should be active");
276 BOOST_CHECK_MESSAGE(p.get_state<Fsm_::State1&>().exit_counter == 4,"State1 exit not called correctly");
277 BOOST_CHECK_MESSAGE(p.get_state<Fsm_::State2&>().entry_counter == 1,"State2 entry not called correctly");
278 BOOST_CHECK_MESSAGE(p.get_state<Fsm_::SubFsm2&>().exit_counter == 4,"SubFsm2 exit not called correctly");
279 BOOST_CHECK_MESSAGE(p.get_state<Fsm_::SubFsm2&>().entry_counter == 4,"SubFsm2 entry not called correctly");
280 BOOST_CHECK_MESSAGE(p.get_state<Fsm_::SubFsm2&>().get_state<Fsm_::SubFsm2_::PseudoEntry1&>().entry_counter == 1,
281 "SubFsm2::PseudoEntry1 entry not called correctly");
282 BOOST_CHECK_MESSAGE(p.get_state<Fsm_::SubFsm2&>().get_state<Fsm_::SubFsm2_::PseudoEntry1&>().exit_counter == 1,
283 "SubFsm2::PseudoEntry1 exit not called correctly");
284 BOOST_CHECK_MESSAGE(p.get_state<Fsm_::SubFsm2&>().get_state<Fsm_::SubFsm2_::SubState3&>().entry_counter == 1,
285 "SubFsm2::SubState3 entry not called correctly");
286 BOOST_CHECK_MESSAGE(p.get_state<Fsm_::SubFsm2&>().get_state<Fsm_::SubFsm2_::SubState3&>().exit_counter == 1,
287 "SubFsm2::SubState3 exit not called correctly");
288 BOOST_CHECK_MESSAGE(p.get_state<Fsm_::SubFsm2&>().get_state<Fsm_::SubFsm2::exit_pt<Fsm_::SubFsm2_::PseudoExit1>&>().entry_counter == 1,
289 "SubFsm2::PseudoExit1 entry not called correctly");
290 BOOST_CHECK_MESSAGE(p.get_state<Fsm_::SubFsm2&>().get_state<Fsm_::SubFsm2::exit_pt<Fsm_::SubFsm2_::PseudoExit1>&>().exit_counter == 1,
291 "SubFsm2::PseudoExit1 exit not called correctly");
292 BOOST_CHECK_MESSAGE(p.get_state<Fsm_::SubFsm2&>().entry_action_counter == 1,"Action not called correctly");
293
294 }
295}
296
297

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