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
AssertInStateTerminationTest44 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 //////////////////////////////////////////////////////////////////////////
AddNameTerminationTest76 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:
MyStateMyState98 MyState() : exitCalled_( false ) {}
99
~MyStateMyState100 ~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
exitMyState108 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
TerminationTest()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
test_main(int,char * [])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 }
284