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( currentState->dynamic_type() ); |
---|
52 | |
---|
53 | const state_base_type * outerState = currentState->outer_state_ptr(); |
---|
54 | |
---|
55 | while ( outerState != 0 ) |
---|
56 | { |
---|
57 | AddName( 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( stateType ); |
---|
80 | BOOST_REQUIRE( found != stateNamesMap_.end() ); |
---|
81 | stateNamesCache_.insert( 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( "" ); |
---|
187 | |
---|
188 | machine.initiate(); |
---|
189 | machine.AssertInState( "ABCDEFG" ); |
---|
190 | machine.process_event( EvTerminateE() ); |
---|
191 | machine.AssertInState( "ABCD" ); |
---|
192 | machine.process_event( EvTerminateE() ); |
---|
193 | machine.AssertInState( "ABCD" ); |
---|
194 | |
---|
195 | machine.initiate(); |
---|
196 | machine.AssertInState( "ABCDEFG" ); |
---|
197 | machine.process_event( EvTerminateC() ); |
---|
198 | machine.AssertInState( "AB" ); |
---|
199 | machine.process_event( EvTerminateC() ); |
---|
200 | machine.AssertInState( "AB" ); |
---|
201 | |
---|
202 | machine.initiate(); |
---|
203 | machine.AssertInState( "ABCDEFG" ); |
---|
204 | machine.process_event( EvTerminateA() ); |
---|
205 | machine.AssertInState( "" ); |
---|
206 | machine.process_event( EvTerminateA() ); |
---|
207 | machine.AssertInState( "" ); |
---|
208 | |
---|
209 | machine.initiate(); |
---|
210 | machine.AssertInState( "ABCDEFG" ); |
---|
211 | machine.process_event( EvTerminateG() ); |
---|
212 | machine.AssertInState( "ABCDEF" ); |
---|
213 | machine.process_event( EvTerminateG() ); |
---|
214 | machine.AssertInState( "ABCDEF" ); |
---|
215 | machine.process_event( EvTerminateF() ); |
---|
216 | machine.AssertInState( "ABCD" ); |
---|
217 | machine.process_event( EvTerminateF() ); |
---|
218 | machine.AssertInState( "ABCD" ); |
---|
219 | machine.process_event( EvTerminateD() ); |
---|
220 | machine.AssertInState( "AB" ); |
---|
221 | machine.process_event( EvTerminateD() ); |
---|
222 | machine.AssertInState( "AB" ); |
---|
223 | machine.process_event( EvTerminateB() ); |
---|
224 | machine.AssertInState( "" ); |
---|
225 | machine.process_event( EvTerminateB() ); |
---|
226 | machine.AssertInState( "" ); |
---|
227 | |
---|
228 | machine.initiate(); |
---|
229 | machine.AssertInState( "ABCDEFG" ); |
---|
230 | machine.process_event( EvTerminateB() ); |
---|
231 | machine.AssertInState( "ACDEFG" ); |
---|
232 | machine.process_event( EvTerminateB() ); |
---|
233 | machine.AssertInState( "ACDEFG" ); |
---|
234 | machine.process_event( EvTerminateD() ); |
---|
235 | machine.AssertInState( "ACEFG" ); |
---|
236 | machine.process_event( EvTerminateD() ); |
---|
237 | machine.AssertInState( "ACEFG" ); |
---|
238 | machine.process_event( EvTerminateF() ); |
---|
239 | machine.AssertInState( "ACEG" ); |
---|
240 | machine.process_event( EvTerminateF() ); |
---|
241 | machine.AssertInState( "ACEG" ); |
---|
242 | machine.process_event( EvTerminateG() ); |
---|
243 | machine.AssertInState( "" ); |
---|
244 | machine.process_event( EvTerminateG() ); |
---|
245 | machine.AssertInState( "" ); |
---|
246 | |
---|
247 | machine.initiate(); |
---|
248 | machine.AssertInState( "ABCDEFG" ); |
---|
249 | machine.process_event( EvTerminateE() ); |
---|
250 | machine.AssertInState( "ABCD" ); |
---|
251 | machine.process_event( EvTerminateE() ); |
---|
252 | machine.AssertInState( "ABCD" ); |
---|
253 | machine.process_event( EvTerminateC() ); |
---|
254 | machine.AssertInState( "AB" ); |
---|
255 | machine.process_event( EvTerminateC() ); |
---|
256 | machine.AssertInState( "AB" ); |
---|
257 | machine.process_event( EvTerminateA() ); |
---|
258 | machine.AssertInState( "" ); |
---|
259 | machine.process_event( EvTerminateA() ); |
---|
260 | machine.AssertInState( "" ); |
---|
261 | |
---|
262 | machine.initiate(); |
---|
263 | machine.AssertInState( "ABCDEFG" ); |
---|
264 | machine.initiate(); |
---|
265 | machine.AssertInState( "ABCDEFG" ); |
---|
266 | machine.terminate(); |
---|
267 | machine.AssertInState( "" ); |
---|
268 | machine.terminate(); |
---|
269 | machine.AssertInState( "" ); |
---|
270 | |
---|
271 | |
---|
272 | TerminationEventBaseTest eventBaseMachine; |
---|
273 | eventBaseMachine.initiate(); |
---|
274 | BOOST_REQUIRE( !eventBaseMachine.terminated() ); |
---|
275 | eventBaseMachine.process_event( EvTerminateA() ); |
---|
276 | BOOST_REQUIRE( eventBaseMachine.terminated() ); |
---|
277 | eventBaseMachine.initiate(); |
---|
278 | BOOST_REQUIRE( !eventBaseMachine.terminated() ); |
---|
279 | eventBaseMachine.process_event( EvTerminateB() ); |
---|
280 | BOOST_REQUIRE( eventBaseMachine.terminated() ); |
---|
281 | |
---|
282 | return 0; |
---|
283 | } |
---|