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_big_with_functors_test |
17 | #endif |
18 | #include <boost/test/unit_test.hpp> |
19 | |
20 | namespace msm = boost::msm; |
21 | namespace mpl = boost::mpl; |
22 | using namespace boost::msm::front; |
23 | |
24 | namespace |
25 | { |
26 | // events |
27 | struct event1 {}; |
28 | struct event2 {}; |
29 | |
30 | |
31 | // front-end: define the FSM structure |
32 | struct my_machine_ : public msm::front::state_machine_def<my_machine_> |
33 | { |
34 | |
35 | my_machine_() |
36 | {} |
37 | |
38 | // The list of FSM states |
39 | struct State1 : public msm::front::state<> |
40 | { |
41 | template <class Event,class FSM> |
42 | void on_entry(Event const&,FSM& ) {++entry_counter;} |
43 | template <class Event,class FSM> |
44 | void on_exit(Event const&,FSM& ) {++exit_counter;} |
45 | int entry_counter=0; |
46 | int exit_counter=0; |
47 | }; |
48 | struct State2 : public msm::front::state<> |
49 | { |
50 | template <class Event,class FSM> |
51 | void on_entry(Event const&,FSM& ) {++entry_counter;} |
52 | template <class Event,class FSM> |
53 | void on_exit(Event const&,FSM& ) {++exit_counter;} |
54 | int entry_counter=0; |
55 | int exit_counter=0; |
56 | }; |
57 | struct State3 : public msm::front::state<> |
58 | { |
59 | template <class Event,class FSM> |
60 | void on_entry(Event const&,FSM& ) {++entry_counter;} |
61 | template <class Event,class FSM> |
62 | void on_exit(Event const&,FSM& ) {++exit_counter;} |
63 | int entry_counter=0; |
64 | int exit_counter=0; |
65 | }; |
66 | struct State4 : public msm::front::state<> |
67 | { |
68 | template <class Event,class FSM> |
69 | void on_entry(Event const&,FSM& ) {++entry_counter;} |
70 | template <class Event,class FSM> |
71 | void on_exit(Event const&,FSM& ) {++exit_counter;} |
72 | int entry_counter=0; |
73 | int exit_counter=0; |
74 | }; |
75 | struct State5 : public msm::front::state<> |
76 | { |
77 | template <class Event,class FSM> |
78 | void on_entry(Event const&,FSM& ) {++entry_counter;} |
79 | template <class Event,class FSM> |
80 | void on_exit(Event const&,FSM& ) {++exit_counter;} |
81 | int entry_counter=0; |
82 | int exit_counter=0; |
83 | }; |
84 | struct State6 : public msm::front::state<> |
85 | { |
86 | template <class Event,class FSM> |
87 | void on_entry(Event const&,FSM& ) {++entry_counter;} |
88 | template <class Event,class FSM> |
89 | void on_exit(Event const&,FSM& ) {++exit_counter;} |
90 | int entry_counter=0; |
91 | int exit_counter=0; |
92 | }; |
93 | struct State7 : public msm::front::state<> |
94 | { |
95 | template <class Event,class FSM> |
96 | void on_entry(Event const&,FSM& ) {++entry_counter;} |
97 | template <class Event,class FSM> |
98 | void on_exit(Event const&,FSM& ) {++exit_counter;} |
99 | int entry_counter=0; |
100 | int exit_counter=0; |
101 | }; |
102 | struct State8 : public msm::front::state<> |
103 | { |
104 | template <class Event,class FSM> |
105 | void on_entry(Event const&,FSM& ) {++entry_counter;} |
106 | template <class Event,class FSM> |
107 | void on_exit(Event const&,FSM& ) {++exit_counter;} |
108 | int entry_counter=0; |
109 | int exit_counter=0; |
110 | }; |
111 | struct State9 : public msm::front::state<> |
112 | { |
113 | template <class Event,class FSM> |
114 | void on_entry(Event const&,FSM& ) {++entry_counter;} |
115 | template <class Event,class FSM> |
116 | void on_exit(Event const&,FSM& ) {++exit_counter;} |
117 | int entry_counter=0; |
118 | int exit_counter=0; |
119 | }; |
120 | struct State10 : public msm::front::state<> |
121 | { |
122 | template <class Event,class FSM> |
123 | void on_entry(Event const&,FSM& ) {++entry_counter;} |
124 | template <class Event,class FSM> |
125 | void on_exit(Event const&,FSM& ) {++exit_counter;} |
126 | int entry_counter=0; |
127 | int exit_counter=0; |
128 | }; |
129 | struct State11 : public msm::front::state<> |
130 | { |
131 | template <class Event,class FSM> |
132 | void on_entry(Event const&,FSM& ) {++entry_counter;} |
133 | template <class Event,class FSM> |
134 | void on_exit(Event const&,FSM& ) {++exit_counter;} |
135 | int entry_counter=0; |
136 | int exit_counter=0; |
137 | }; |
138 | struct State12 : public msm::front::state<> |
139 | { |
140 | template <class Event,class FSM> |
141 | void on_entry(Event const&,FSM& ) {++entry_counter;} |
142 | template <class Event,class FSM> |
143 | void on_exit(Event const&,FSM& ) {++exit_counter;} |
144 | int entry_counter=0; |
145 | int exit_counter=0; |
146 | }; |
147 | |
148 | // the initial state of the player SM. Must be defined |
149 | typedef State1 initial_state; |
150 | |
151 | // transition actions |
152 | |
153 | // guard conditions |
154 | |
155 | typedef my_machine_ p; // makes transition table cleaner |
156 | |
157 | // Transition table for player |
158 | struct transition_table : boost::fusion::vector< |
159 | // Start Event Next Action Guard |
160 | // +---------+-------------+---------+---------------------+----------------------+ |
161 | _row < State1 , event1 , State2 >, |
162 | _row < State2 , event1 , State3 >, |
163 | _row < State3 , event1 , State4 >, |
164 | _row < State4 , event1 , State5 >, |
165 | _row < State5 , event1 , State6 >, |
166 | _row < State6 , event1 , State7 >, |
167 | _row < State7 , event1 , State8 >, |
168 | _row < State8 , event1 , State9 >, |
169 | _row < State9 , event1 , State10 >, |
170 | _row < State10 , event1 , State11 >, |
171 | _row < State11 , event1 , State12 >, |
172 | |
173 | _row < State12 , event2 , State11 >, |
174 | _row < State11 , event2 , State10 >, |
175 | _row < State10 , event2 , State9 >, |
176 | _row < State9 , event2 , State8 >, |
177 | _row < State8 , event2 , State7 >, |
178 | _row < State7 , event2 , State6 >, |
179 | _row < State6 , event2 , State5 >, |
180 | _row < State5 , event2 , State4 >, |
181 | _row < State4 , event2 , State3 >, |
182 | _row < State3 , event2 , State2 >, |
183 | _row < State2 , event2 , State1 > |
184 | // +---------+-------------+---------+---------------------+----------------------+ |
185 | > {}; |
186 | // Replaces the default no-transition response. |
187 | template <class FSM,class Event> |
188 | void no_transition(Event const&, FSM&,int) |
189 | { |
190 | BOOST_FAIL("no_transition called!" ); |
191 | } |
192 | // init counters |
193 | template <class Event,class FSM> |
194 | void on_entry(Event const&,FSM&) |
195 | { |
196 | |
197 | } |
198 | }; |
199 | // Pick a back-end |
200 | typedef msm::back11::state_machine<my_machine_> my_machine; |
201 | |
202 | |
203 | BOOST_AUTO_TEST_CASE( back11_big_with_functors_test ) |
204 | { |
205 | my_machine p; |
206 | |
207 | // needed to start the highest-level SM. |
208 | p.start(); |
209 | BOOST_CHECK_MESSAGE(p.current_state()[0] == 0,"State1 should be active" ); //State1 |
210 | BOOST_CHECK_MESSAGE(p.get_state<my_machine_::State1&>().exit_counter == 0,"State1 exit not called correctly" ); |
211 | BOOST_CHECK_MESSAGE(p.get_state<my_machine_::State1&>().entry_counter == 1,"State1 entry not called correctly" ); |
212 | BOOST_CHECK_MESSAGE(p.get_state<my_machine_::State5&>().exit_counter == 0,"State5 exit not called correctly" ); |
213 | BOOST_CHECK_MESSAGE(p.get_state<my_machine_::State5&>().entry_counter == 0,"State5 entry not called correctly" ); |
214 | |
215 | p.process_event(evt: event1()); |
216 | p.process_event(evt: event1()); |
217 | p.process_event(evt: event1()); |
218 | p.process_event(evt: event1()); |
219 | p.process_event(evt: event1()); |
220 | p.process_event(evt: event1()); |
221 | p.process_event(evt: event1()); |
222 | p.process_event(evt: event1()); |
223 | p.process_event(evt: event1()); |
224 | p.process_event(evt: event1()); |
225 | p.process_event(evt: event1()); |
226 | |
227 | BOOST_CHECK_MESSAGE(p.current_state()[0] == 11,"State12 should be active" ); //State12 |
228 | BOOST_CHECK_MESSAGE(p.get_state<my_machine_::State12&>().exit_counter == 0,"State12 exit not called correctly" ); |
229 | BOOST_CHECK_MESSAGE(p.get_state<my_machine_::State12&>().entry_counter == 1,"State12 entry not called correctly" ); |
230 | BOOST_CHECK_MESSAGE(p.get_state<my_machine_::State2&>().exit_counter == 1,"State2 exit not called correctly" ); |
231 | BOOST_CHECK_MESSAGE(p.get_state<my_machine_::State2&>().entry_counter == 1,"State2 entry not called correctly" ); |
232 | BOOST_CHECK_MESSAGE(p.get_state<my_machine_::State7&>().exit_counter == 1,"State7 exit not called correctly" ); |
233 | BOOST_CHECK_MESSAGE(p.get_state<my_machine_::State7&>().entry_counter == 1,"State7 entry not called correctly" ); |
234 | BOOST_CHECK_MESSAGE(p.get_state<my_machine_::State10&>().exit_counter == 1,"State10 exit not called correctly" ); |
235 | BOOST_CHECK_MESSAGE(p.get_state<my_machine_::State10&>().entry_counter == 1,"State10 entry not called correctly" ); |
236 | |
237 | |
238 | p.process_event(evt: event2()); |
239 | p.process_event(evt: event2()); |
240 | p.process_event(evt: event2()); |
241 | p.process_event(evt: event2()); |
242 | p.process_event(evt: event2()); |
243 | p.process_event(evt: event2()); |
244 | p.process_event(evt: event2()); |
245 | p.process_event(evt: event2()); |
246 | p.process_event(evt: event2()); |
247 | p.process_event(evt: event2()); |
248 | p.process_event(evt: event2()); |
249 | |
250 | BOOST_CHECK_MESSAGE(p.current_state()[0] == 0,"State1 should be active" ); //State1 |
251 | BOOST_CHECK_MESSAGE(p.get_state<my_machine_::State1&>().exit_counter == 1,"State1 exit not called correctly" ); |
252 | BOOST_CHECK_MESSAGE(p.get_state<my_machine_::State1&>().entry_counter == 2,"State1 entry not called correctly" ); |
253 | BOOST_CHECK_MESSAGE(p.get_state<my_machine_::State2&>().exit_counter == 2,"State2 exit not called correctly" ); |
254 | BOOST_CHECK_MESSAGE(p.get_state<my_machine_::State2&>().entry_counter == 2,"State2 entry not called correctly" ); |
255 | BOOST_CHECK_MESSAGE(p.get_state<my_machine_::State7&>().exit_counter == 2,"State7 exit not called correctly" ); |
256 | BOOST_CHECK_MESSAGE(p.get_state<my_machine_::State7&>().entry_counter == 2,"State7 entry not called correctly" ); |
257 | BOOST_CHECK_MESSAGE(p.get_state<my_machine_::State10&>().exit_counter == 2,"State10 exit not called correctly" ); |
258 | BOOST_CHECK_MESSAGE(p.get_state<my_machine_::State10&>().entry_counter == 2,"State10 entry not called correctly" ); |
259 | |
260 | } |
261 | } |
262 | |
263 | |