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 //////////////////////////////////////////////////////////////////////////////
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>
14 #include <boost/mpl/list.hpp>
16 #include <boost/test/test_tools.hpp>
24 namespace sc
= boost::statechart
;
25 namespace mpl
= boost::mpl
;
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
> {};
38 struct TerminationTest
: sc::state_machine
< TerminationTest
, A
>
41 //////////////////////////////////////////////////////////////////////////
44 void AssertInState( const std::string
& stateNames
) const
46 stateNamesCache_
.clear();
48 for ( state_iterator currentState
= state_begin();
49 currentState
!= state_end(); ++currentState
)
51 AddName( currentState
->dynamic_type() );
53 const state_base_type
* outerState
= currentState
->outer_state_ptr();
55 while ( outerState
!= 0 )
57 AddName( outerState
->dynamic_type() );
58 outerState
= outerState
->outer_state_ptr();
62 std::string::const_iterator expectedName
= stateNames
.begin();
64 BOOST_REQUIRE( stateNames
.size() == stateNamesCache_
.size() );
66 for ( StateNamesCache::const_iterator actualName
=
67 stateNamesCache_
.begin(); actualName
!= stateNamesCache_
.end();
68 ++actualName
, ++expectedName
)
70 BOOST_REQUIRE( ( *actualName
)[ 0 ] == *expectedName
);
75 //////////////////////////////////////////////////////////////////////////
76 void AddName( state_base_type::id_type stateType
) const
78 const StateNamesMap::const_iterator found
=
79 stateNamesMap_
.find( stateType
);
80 BOOST_REQUIRE( found
!= stateNamesMap_
.end() );
81 stateNamesCache_
.insert( found
->second
);
84 typedef std::map
< state_base_type::id_type
, std::string
> StateNamesMap
;
85 typedef std::set
< std::string
> StateNamesCache
;
87 StateNamesMap stateNamesMap_
;
88 mutable StateNamesCache stateNamesCache_
;
94 class InnerInitial
= mpl::list
<> >
95 struct MyState
: sc::simple_state
< MostDerived
, Context
, InnerInitial
>
98 MyState() : exitCalled_( false ) {}
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_
);
120 struct A
: MyState
< A
, TerminationTest
, mpl::list
< B
, C
> >
122 typedef sc::termination
< EvTerminateA
> reactions
;
125 struct B
: MyState
< B
, A::orthogonal
< 0 > >
127 typedef sc::termination
< EvTerminateB
> reactions
;
132 struct C
: MyState
< C
, A::orthogonal
< 1 >, mpl::list
< D
, E
> >
134 typedef sc::termination
< EvTerminateC
> reactions
;
137 struct D
: MyState
< D
, C::orthogonal
< 0 > >
139 typedef sc::termination
< EvTerminateD
> reactions
;
144 struct E
: MyState
< E
, C::orthogonal
< 1 >, mpl::list
< F
, G
> >
146 typedef sc::termination
< EvTerminateE
> reactions
;
149 struct F
: MyState
< F
, E::orthogonal
< 0 > >
151 typedef sc::termination
< EvTerminateF
> reactions
;
154 struct G
: MyState
< G
, E::orthogonal
< 1 > >
156 typedef sc::termination
< EvTerminateG
> reactions
;
159 TerminationTest::TerminationTest()
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";
174 struct TerminationEventBaseTest
:
175 sc::state_machine
< TerminationEventBaseTest
, X
> {};
177 struct X
: sc::simple_state
< X
, TerminationEventBaseTest
>
179 typedef sc::termination
< sc::event_base
> reactions
;
183 int test_main( int, char* [] )
185 TerminationTest machine
;
186 machine
.AssertInState( "" );
189 machine
.AssertInState( "ABCDEFG" );
190 machine
.process_event( EvTerminateE() );
191 machine
.AssertInState( "ABCD" );
192 machine
.process_event( EvTerminateE() );
193 machine
.AssertInState( "ABCD" );
196 machine
.AssertInState( "ABCDEFG" );
197 machine
.process_event( EvTerminateC() );
198 machine
.AssertInState( "AB" );
199 machine
.process_event( EvTerminateC() );
200 machine
.AssertInState( "AB" );
203 machine
.AssertInState( "ABCDEFG" );
204 machine
.process_event( EvTerminateA() );
205 machine
.AssertInState( "" );
206 machine
.process_event( EvTerminateA() );
207 machine
.AssertInState( "" );
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( "" );
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( "" );
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( "" );
263 machine
.AssertInState( "ABCDEFG" );
265 machine
.AssertInState( "ABCDEFG" );
267 machine
.AssertInState( "" );
269 machine
.AssertInState( "" );
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() );