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 | #include <boost/msm/front/functor_row.hpp> |
16 | #ifndef BOOST_MSM_NONSTANDALONE_TEST |
17 | #define BOOST_TEST_MODULE Back11TestDeferIn2Regions |
18 | #endif |
19 | #include <boost/test/unit_test.hpp> |
20 | |
21 | namespace msm = boost::msm; |
22 | namespace mpl = boost::mpl; |
23 | using namespace boost::msm::front; |
24 | |
25 | namespace |
26 | { |
27 | // events |
28 | struct event1 {}; |
29 | struct event2 {}; |
30 | struct event3 {}; |
31 | struct eventd {}; |
32 | |
33 | |
34 | // front-end: define the FSM structure |
35 | struct player_ : public msm::front::state_machine_def<player_> |
36 | { |
37 | // The list of FSM states |
38 | struct State11 : public msm::front::state<> |
39 | { |
40 | template <class Event,class FSM> |
41 | void on_entry(Event const&,FSM& ) {++entry_counter;} |
42 | template <class Event,class FSM> |
43 | void on_exit(Event const&,FSM& ) {++exit_counter;} |
44 | int entry_counter; |
45 | int exit_counter; |
46 | }; |
47 | struct State12 : public msm::front::state<> |
48 | { |
49 | typedef boost::fusion::vector<eventd> deferred_events; |
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; |
55 | int exit_counter; |
56 | }; |
57 | struct State13 : 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; |
64 | int exit_counter; |
65 | }; |
66 | struct State21 : 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; |
73 | int exit_counter; |
74 | }; |
75 | struct State22 : 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; |
82 | int exit_counter; |
83 | }; |
84 | // the initial state of the player SM. Must be defined |
85 | typedef boost::fusion::vector<State11,State21> initial_state; |
86 | |
87 | |
88 | // Transition table for player |
89 | struct transition_table : boost::fusion::vector< |
90 | // Start Event Next Action Guard |
91 | // +---------+-------------+---------+---------------------+----------------------+ |
92 | Row < State11 , event1 , State12 >, |
93 | Row < State12 , event2 , State13 >, |
94 | |
95 | Row < State21 , event3 , State22 >, |
96 | Row < State22 , eventd , State21 > |
97 | // +---------+-------------+---------+---------------------+----------------------+ |
98 | > {}; |
99 | |
100 | // Replaces the default no-transition response. |
101 | template <class FSM,class Event> |
102 | void no_transition(Event const& , FSM&,int ) |
103 | { |
104 | BOOST_FAIL("no_transition called!" ); |
105 | } |
106 | // init counters |
107 | template <class Event,class FSM> |
108 | void on_entry(Event const&,FSM& fsm) |
109 | { |
110 | fsm.template get_state<player_::State11&>().entry_counter=0; |
111 | fsm.template get_state<player_::State11&>().exit_counter=0; |
112 | fsm.template get_state<player_::State12&>().entry_counter=0; |
113 | fsm.template get_state<player_::State12&>().exit_counter=0; |
114 | fsm.template get_state<player_::State13&>().entry_counter=0; |
115 | fsm.template get_state<player_::State13&>().exit_counter=0; |
116 | fsm.template get_state<player_::State21&>().entry_counter=0; |
117 | fsm.template get_state<player_::State22&>().exit_counter=0; |
118 | } |
119 | }; |
120 | // Pick a back-end |
121 | typedef msm::back11::state_machine<player_> player; |
122 | |
123 | BOOST_AUTO_TEST_CASE( Back11TestDeferIn2Regions ) |
124 | { |
125 | player p; |
126 | // needed to start the highest-level SM. This will call on_entry and mark the start of the SM |
127 | p.start(); |
128 | |
129 | p.process_event(evt: event1()); |
130 | BOOST_CHECK_MESSAGE(p.current_state()[0] == 1,"State12 should be active" ); |
131 | BOOST_CHECK_MESSAGE(p.current_state()[1] == 2,"State21 should be active" ); |
132 | BOOST_CHECK_MESSAGE(p.get_state<player_::State11&>().exit_counter == 1,"State11 exit not called correctly" ); |
133 | BOOST_CHECK_MESSAGE(p.get_state<player_::State11&>().entry_counter == 1,"State11 entry not called correctly" ); |
134 | BOOST_CHECK_MESSAGE(p.get_state<player_::State12&>().entry_counter == 1,"State12 entry not called correctly" ); |
135 | |
136 | // deferred |
137 | p.process_event(evt: eventd()); |
138 | BOOST_CHECK_MESSAGE(p.current_state()[0] == 1,"State12 should be active" ); |
139 | BOOST_CHECK_MESSAGE(p.current_state()[1] == 2,"State21 should be active" ); |
140 | BOOST_CHECK_MESSAGE(p.get_state<player_::State11&>().exit_counter == 1,"State11 exit not called correctly" ); |
141 | BOOST_CHECK_MESSAGE(p.get_state<player_::State11&>().entry_counter == 1,"State11 entry not called correctly" ); |
142 | BOOST_CHECK_MESSAGE(p.get_state<player_::State12&>().entry_counter == 1,"State12 entry not called correctly" ); |
143 | BOOST_CHECK_MESSAGE(p.get_state<player_::State12&>().exit_counter == 0,"State12 exit not called correctly" ); |
144 | BOOST_CHECK_MESSAGE(p.get_state<player_::State21&>().exit_counter == 0,"State21 exit not called correctly" ); |
145 | BOOST_CHECK_MESSAGE(p.get_state<player_::State21&>().entry_counter == 1,"State21 entry not called correctly" ); |
146 | BOOST_CHECK_MESSAGE(p.get_state<player_::State22&>().exit_counter == 0,"State22 exit not called correctly" ); |
147 | BOOST_CHECK_MESSAGE(p.get_state<player_::State22&>().entry_counter == 0,"State22 entry not called correctly" ); |
148 | |
149 | p.process_event(evt: event3()); |
150 | BOOST_CHECK_MESSAGE(p.current_state()[0] == 1,"State12 should be active" ); |
151 | BOOST_CHECK_MESSAGE(p.current_state()[1] == 2,"State21 should be active" ); |
152 | BOOST_CHECK_MESSAGE(p.get_state<player_::State21&>().exit_counter == 1,"State21 exit not called correctly" ); |
153 | BOOST_CHECK_MESSAGE(p.get_state<player_::State21&>().entry_counter == 2,"State21 entry not called correctly" ); |
154 | BOOST_CHECK_MESSAGE(p.get_state<player_::State22&>().exit_counter == 1,"State22 exit not called correctly" ); |
155 | BOOST_CHECK_MESSAGE(p.get_state<player_::State22&>().entry_counter == 1,"State22 entry not called correctly" ); |
156 | BOOST_CHECK_MESSAGE(p.get_deferred_queue().size() == 1,"Deferred queue should have one element" ); |
157 | p.clear_deferred_queue(); |
158 | |
159 | p.process_event(evt: event2()); |
160 | BOOST_CHECK_MESSAGE(p.current_state()[0] == 4,"State13 should be active" ); |
161 | BOOST_CHECK_MESSAGE(p.current_state()[1] == 2,"State21 should be active" ); |
162 | BOOST_CHECK_MESSAGE(p.get_state<player_::State21&>().exit_counter == 1,"State21 exit not called correctly" ); |
163 | BOOST_CHECK_MESSAGE(p.get_state<player_::State21&>().entry_counter == 2,"State21 entry not called correctly" ); |
164 | BOOST_CHECK_MESSAGE(p.get_state<player_::State22&>().exit_counter == 1,"State22 exit not called correctly" ); |
165 | BOOST_CHECK_MESSAGE(p.get_state<player_::State22&>().entry_counter == 1,"State22 entry not called correctly" ); |
166 | BOOST_CHECK_MESSAGE(p.get_deferred_queue().size() == 0,"Deferred queue should have no element" ); |
167 | } |
168 | } |
169 | |
170 | |
171 | |