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

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