1 | ////////////////////////////////////////////////////////////////////////////// |
2 | // Copyright 2005-2006 Andreas Huber Doenni |
3 | // Distributed under the Boost Software License, Version 1.0. (See accompany- |
4 | // ing file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) |
5 | ////////////////////////////////////////////////////////////////////////////// |
6 | |
7 | |
8 | |
9 | #include <boost/statechart/state_machine.hpp> |
10 | #include <boost/statechart/event.hpp> |
11 | #include <boost/statechart/simple_state.hpp> |
12 | #include <boost/statechart/termination.hpp> |
13 | |
14 | #include <boost/mpl/list.hpp> |
15 | |
16 | #include <boost/test/test_tools.hpp> |
17 | |
18 | #include <set> |
19 | #include <map> |
20 | #include <string> |
21 | |
22 | |
23 | |
24 | namespace sc = boost::statechart; |
25 | namespace mpl = boost::mpl; |
26 | |
27 | |
28 | |
29 | struct EvTerminateA : sc::event< EvTerminateA > {}; |
30 | struct EvTerminateB : sc::event< EvTerminateB > {}; |
31 | struct EvTerminateC : sc::event< EvTerminateC > {}; |
32 | struct EvTerminateD : sc::event< EvTerminateD > {}; |
33 | struct EvTerminateE : sc::event< EvTerminateE > {}; |
34 | struct EvTerminateF : sc::event< EvTerminateF > {}; |
35 | struct EvTerminateG : sc::event< EvTerminateG > {}; |
36 | |
37 | struct A; |
38 | struct TerminationTest : sc::state_machine< TerminationTest, A > |
39 | { |
40 | public: |
41 | ////////////////////////////////////////////////////////////////////////// |
42 | TerminationTest(); |
43 | |
44 | void AssertInState( const std::string & stateNames ) const |
45 | { |
46 | stateNamesCache_.clear(); |
47 | |
48 | for ( state_iterator currentState = state_begin(); |
49 | currentState != state_end(); ++currentState ) |
50 | { |
51 | AddName( stateType: currentState->dynamic_type() ); |
52 | |
53 | const state_base_type * outerState = currentState->outer_state_ptr(); |
54 | |
55 | while ( outerState != 0 ) |
56 | { |
57 | AddName( stateType: outerState->dynamic_type() ); |
58 | outerState = outerState->outer_state_ptr(); |
59 | } |
60 | } |
61 | |
62 | std::string::const_iterator expectedName = stateNames.begin(); |
63 | |
64 | BOOST_REQUIRE( stateNames.size() == stateNamesCache_.size() ); |
65 | |
66 | for ( StateNamesCache::const_iterator actualName = |
67 | stateNamesCache_.begin(); actualName != stateNamesCache_.end(); |
68 | ++actualName, ++expectedName ) |
69 | { |
70 | BOOST_REQUIRE( ( *actualName )[ 0 ] == *expectedName ); |
71 | } |
72 | } |
73 | |
74 | private: |
75 | ////////////////////////////////////////////////////////////////////////// |
76 | void AddName( state_base_type::id_type stateType ) const |
77 | { |
78 | const StateNamesMap::const_iterator found = |
79 | stateNamesMap_.find( x: stateType ); |
80 | BOOST_REQUIRE( found != stateNamesMap_.end() ); |
81 | stateNamesCache_.insert( x: found->second ); |
82 | } |
83 | |
84 | typedef std::map< state_base_type::id_type, std::string > StateNamesMap; |
85 | typedef std::set< std::string > StateNamesCache; |
86 | |
87 | StateNamesMap stateNamesMap_; |
88 | mutable StateNamesCache stateNamesCache_; |
89 | }; |
90 | |
91 | template< |
92 | class MostDerived, |
93 | class Context, |
94 | class InnerInitial = mpl::list<> > |
95 | struct MyState : sc::simple_state< MostDerived, Context, InnerInitial > |
96 | { |
97 | public: |
98 | MyState() : exitCalled_( false ) {} |
99 | |
100 | ~MyState() |
101 | { |
102 | // BOOST_REQUIRE throws an exception when the test fails. If the state |
103 | // is destructed as part of a stack unwind, abort() is called what is |
104 | // presumably also detected by the test monitor. |
105 | BOOST_REQUIRE( exitCalled_ ); |
106 | } |
107 | |
108 | void exit() |
109 | { |
110 | exitCalled_ = true; |
111 | } |
112 | |
113 | private: |
114 | bool exitCalled_; |
115 | }; |
116 | |
117 | |
118 | struct B; |
119 | struct C; |
120 | struct A : MyState< A, TerminationTest, mpl::list< B, C > > |
121 | { |
122 | typedef sc::termination< EvTerminateA > reactions; |
123 | }; |
124 | |
125 | struct B : MyState< B, A::orthogonal< 0 > > |
126 | { |
127 | typedef sc::termination< EvTerminateB > reactions; |
128 | }; |
129 | |
130 | struct D; |
131 | struct E; |
132 | struct C : MyState< C, A::orthogonal< 1 >, mpl::list< D, E > > |
133 | { |
134 | typedef sc::termination< EvTerminateC > reactions; |
135 | }; |
136 | |
137 | struct D : MyState< D, C::orthogonal< 0 > > |
138 | { |
139 | typedef sc::termination< EvTerminateD > reactions; |
140 | }; |
141 | |
142 | struct F; |
143 | struct G; |
144 | struct E : MyState< E, C::orthogonal< 1 >, mpl::list< F, G > > |
145 | { |
146 | typedef sc::termination< EvTerminateE > reactions; |
147 | }; |
148 | |
149 | struct F : MyState< F, E::orthogonal< 0 > > |
150 | { |
151 | typedef sc::termination< EvTerminateF > reactions; |
152 | }; |
153 | |
154 | struct G : MyState< G, E::orthogonal< 1 > > |
155 | { |
156 | typedef sc::termination< EvTerminateG > reactions; |
157 | }; |
158 | |
159 | TerminationTest::TerminationTest() |
160 | { |
161 | // We're not using custom type information to make this test work even when |
162 | // BOOST_STATECHART_USE_NATIVE_RTTI is defined |
163 | stateNamesMap_[ A::static_type() ] = "A" ; |
164 | stateNamesMap_[ B::static_type() ] = "B" ; |
165 | stateNamesMap_[ C::static_type() ] = "C" ; |
166 | stateNamesMap_[ D::static_type() ] = "D" ; |
167 | stateNamesMap_[ E::static_type() ] = "E" ; |
168 | stateNamesMap_[ F::static_type() ] = "F" ; |
169 | stateNamesMap_[ G::static_type() ] = "G" ; |
170 | } |
171 | |
172 | |
173 | struct X; |
174 | struct TerminationEventBaseTest : |
175 | sc::state_machine< TerminationEventBaseTest, X > {}; |
176 | |
177 | struct X : sc::simple_state< X, TerminationEventBaseTest > |
178 | { |
179 | typedef sc::termination< sc::event_base > reactions; |
180 | }; |
181 | |
182 | |
183 | int test_main( int, char* [] ) |
184 | { |
185 | TerminationTest machine; |
186 | machine.AssertInState( stateNames: "" ); |
187 | |
188 | machine.initiate(); |
189 | machine.AssertInState( stateNames: "ABCDEFG" ); |
190 | machine.process_event( evt: EvTerminateE() ); |
191 | machine.AssertInState( stateNames: "ABCD" ); |
192 | machine.process_event( evt: EvTerminateE() ); |
193 | machine.AssertInState( stateNames: "ABCD" ); |
194 | |
195 | machine.initiate(); |
196 | machine.AssertInState( stateNames: "ABCDEFG" ); |
197 | machine.process_event( evt: EvTerminateC() ); |
198 | machine.AssertInState( stateNames: "AB" ); |
199 | machine.process_event( evt: EvTerminateC() ); |
200 | machine.AssertInState( stateNames: "AB" ); |
201 | |
202 | machine.initiate(); |
203 | machine.AssertInState( stateNames: "ABCDEFG" ); |
204 | machine.process_event( evt: EvTerminateA() ); |
205 | machine.AssertInState( stateNames: "" ); |
206 | machine.process_event( evt: EvTerminateA() ); |
207 | machine.AssertInState( stateNames: "" ); |
208 | |
209 | machine.initiate(); |
210 | machine.AssertInState( stateNames: "ABCDEFG" ); |
211 | machine.process_event( evt: EvTerminateG() ); |
212 | machine.AssertInState( stateNames: "ABCDEF" ); |
213 | machine.process_event( evt: EvTerminateG() ); |
214 | machine.AssertInState( stateNames: "ABCDEF" ); |
215 | machine.process_event( evt: EvTerminateF() ); |
216 | machine.AssertInState( stateNames: "ABCD" ); |
217 | machine.process_event( evt: EvTerminateF() ); |
218 | machine.AssertInState( stateNames: "ABCD" ); |
219 | machine.process_event( evt: EvTerminateD() ); |
220 | machine.AssertInState( stateNames: "AB" ); |
221 | machine.process_event( evt: EvTerminateD() ); |
222 | machine.AssertInState( stateNames: "AB" ); |
223 | machine.process_event( evt: EvTerminateB() ); |
224 | machine.AssertInState( stateNames: "" ); |
225 | machine.process_event( evt: EvTerminateB() ); |
226 | machine.AssertInState( stateNames: "" ); |
227 | |
228 | machine.initiate(); |
229 | machine.AssertInState( stateNames: "ABCDEFG" ); |
230 | machine.process_event( evt: EvTerminateB() ); |
231 | machine.AssertInState( stateNames: "ACDEFG" ); |
232 | machine.process_event( evt: EvTerminateB() ); |
233 | machine.AssertInState( stateNames: "ACDEFG" ); |
234 | machine.process_event( evt: EvTerminateD() ); |
235 | machine.AssertInState( stateNames: "ACEFG" ); |
236 | machine.process_event( evt: EvTerminateD() ); |
237 | machine.AssertInState( stateNames: "ACEFG" ); |
238 | machine.process_event( evt: EvTerminateF() ); |
239 | machine.AssertInState( stateNames: "ACEG" ); |
240 | machine.process_event( evt: EvTerminateF() ); |
241 | machine.AssertInState( stateNames: "ACEG" ); |
242 | machine.process_event( evt: EvTerminateG() ); |
243 | machine.AssertInState( stateNames: "" ); |
244 | machine.process_event( evt: EvTerminateG() ); |
245 | machine.AssertInState( stateNames: "" ); |
246 | |
247 | machine.initiate(); |
248 | machine.AssertInState( stateNames: "ABCDEFG" ); |
249 | machine.process_event( evt: EvTerminateE() ); |
250 | machine.AssertInState( stateNames: "ABCD" ); |
251 | machine.process_event( evt: EvTerminateE() ); |
252 | machine.AssertInState( stateNames: "ABCD" ); |
253 | machine.process_event( evt: EvTerminateC() ); |
254 | machine.AssertInState( stateNames: "AB" ); |
255 | machine.process_event( evt: EvTerminateC() ); |
256 | machine.AssertInState( stateNames: "AB" ); |
257 | machine.process_event( evt: EvTerminateA() ); |
258 | machine.AssertInState( stateNames: "" ); |
259 | machine.process_event( evt: EvTerminateA() ); |
260 | machine.AssertInState( stateNames: "" ); |
261 | |
262 | machine.initiate(); |
263 | machine.AssertInState( stateNames: "ABCDEFG" ); |
264 | machine.initiate(); |
265 | machine.AssertInState( stateNames: "ABCDEFG" ); |
266 | machine.terminate(); |
267 | machine.AssertInState( stateNames: "" ); |
268 | machine.terminate(); |
269 | machine.AssertInState( stateNames: "" ); |
270 | |
271 | |
272 | TerminationEventBaseTest eventBaseMachine; |
273 | eventBaseMachine.initiate(); |
274 | BOOST_REQUIRE( !eventBaseMachine.terminated() ); |
275 | eventBaseMachine.process_event( evt: EvTerminateA() ); |
276 | BOOST_REQUIRE( eventBaseMachine.terminated() ); |
277 | eventBaseMachine.initiate(); |
278 | BOOST_REQUIRE( !eventBaseMachine.terminated() ); |
279 | eventBaseMachine.process_event( evt: EvTerminateB() ); |
280 | BOOST_REQUIRE( eventBaseMachine.terminated() ); |
281 | |
282 | return 0; |
283 | } |
284 | |