////////////////////////////////////////////////////////////////////////////// // Copyright 2005-2006 Andreas Huber Doenni // Distributed under the Boost Software License, Version 1.0. (See accompany- // ing file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) ////////////////////////////////////////////////////////////////////////////// #include #include #include #include #include #include #include #include #include namespace sc = boost::statechart; namespace mpl = boost::mpl; struct EvTerminateA : sc::event< EvTerminateA > {}; struct EvTerminateB : sc::event< EvTerminateB > {}; struct EvTerminateC : sc::event< EvTerminateC > {}; struct EvTerminateD : sc::event< EvTerminateD > {}; struct EvTerminateE : sc::event< EvTerminateE > {}; struct EvTerminateF : sc::event< EvTerminateF > {}; struct EvTerminateG : sc::event< EvTerminateG > {}; struct A; struct TerminationTest : sc::state_machine< TerminationTest, A > { public: ////////////////////////////////////////////////////////////////////////// TerminationTest(); void AssertInState( const std::string & stateNames ) const { stateNamesCache_.clear(); for ( state_iterator currentState = state_begin(); currentState != state_end(); ++currentState ) { AddName( currentState->dynamic_type() ); const state_base_type * outerState = currentState->outer_state_ptr(); while ( outerState != 0 ) { AddName( outerState->dynamic_type() ); outerState = outerState->outer_state_ptr(); } } std::string::const_iterator expectedName = stateNames.begin(); BOOST_REQUIRE( stateNames.size() == stateNamesCache_.size() ); for ( StateNamesCache::const_iterator actualName = stateNamesCache_.begin(); actualName != stateNamesCache_.end(); ++actualName, ++expectedName ) { BOOST_REQUIRE( ( *actualName )[ 0 ] == *expectedName ); } } private: ////////////////////////////////////////////////////////////////////////// void AddName( state_base_type::id_type stateType ) const { const StateNamesMap::const_iterator found = stateNamesMap_.find( stateType ); BOOST_REQUIRE( found != stateNamesMap_.end() ); stateNamesCache_.insert( found->second ); } typedef std::map< state_base_type::id_type, std::string > StateNamesMap; typedef std::set< std::string > StateNamesCache; StateNamesMap stateNamesMap_; mutable StateNamesCache stateNamesCache_; }; template< class MostDerived, class Context, class InnerInitial = mpl::list<> > struct MyState : sc::simple_state< MostDerived, Context, InnerInitial > { public: MyState() : exitCalled_( false ) {} ~MyState() { // BOOST_REQUIRE throws an exception when the test fails. If the state // is destructed as part of a stack unwind, abort() is called what is // presumably also detected by the test monitor. BOOST_REQUIRE( exitCalled_ ); } void exit() { exitCalled_ = true; } private: bool exitCalled_; }; struct B; struct C; struct A : MyState< A, TerminationTest, mpl::list< B, C > > { typedef sc::termination< EvTerminateA > reactions; }; struct B : MyState< B, A::orthogonal< 0 > > { typedef sc::termination< EvTerminateB > reactions; }; struct D; struct E; struct C : MyState< C, A::orthogonal< 1 >, mpl::list< D, E > > { typedef sc::termination< EvTerminateC > reactions; }; struct D : MyState< D, C::orthogonal< 0 > > { typedef sc::termination< EvTerminateD > reactions; }; struct F; struct G; struct E : MyState< E, C::orthogonal< 1 >, mpl::list< F, G > > { typedef sc::termination< EvTerminateE > reactions; }; struct F : MyState< F, E::orthogonal< 0 > > { typedef sc::termination< EvTerminateF > reactions; }; struct G : MyState< G, E::orthogonal< 1 > > { typedef sc::termination< EvTerminateG > reactions; }; TerminationTest::TerminationTest() { // We're not using custom type information to make this test work even when // BOOST_STATECHART_USE_NATIVE_RTTI is defined stateNamesMap_[ A::static_type() ] = "A"; stateNamesMap_[ B::static_type() ] = "B"; stateNamesMap_[ C::static_type() ] = "C"; stateNamesMap_[ D::static_type() ] = "D"; stateNamesMap_[ E::static_type() ] = "E"; stateNamesMap_[ F::static_type() ] = "F"; stateNamesMap_[ G::static_type() ] = "G"; } struct X; struct TerminationEventBaseTest : sc::state_machine< TerminationEventBaseTest, X > {}; struct X : sc::simple_state< X, TerminationEventBaseTest > { typedef sc::termination< sc::event_base > reactions; }; int test_main( int, char* [] ) { TerminationTest machine; machine.AssertInState( "" ); machine.initiate(); machine.AssertInState( "ABCDEFG" ); machine.process_event( EvTerminateE() ); machine.AssertInState( "ABCD" ); machine.process_event( EvTerminateE() ); machine.AssertInState( "ABCD" ); machine.initiate(); machine.AssertInState( "ABCDEFG" ); machine.process_event( EvTerminateC() ); machine.AssertInState( "AB" ); machine.process_event( EvTerminateC() ); machine.AssertInState( "AB" ); machine.initiate(); machine.AssertInState( "ABCDEFG" ); machine.process_event( EvTerminateA() ); machine.AssertInState( "" ); machine.process_event( EvTerminateA() ); machine.AssertInState( "" ); machine.initiate(); machine.AssertInState( "ABCDEFG" ); machine.process_event( EvTerminateG() ); machine.AssertInState( "ABCDEF" ); machine.process_event( EvTerminateG() ); machine.AssertInState( "ABCDEF" ); machine.process_event( EvTerminateF() ); machine.AssertInState( "ABCD" ); machine.process_event( EvTerminateF() ); machine.AssertInState( "ABCD" ); machine.process_event( EvTerminateD() ); machine.AssertInState( "AB" ); machine.process_event( EvTerminateD() ); machine.AssertInState( "AB" ); machine.process_event( EvTerminateB() ); machine.AssertInState( "" ); machine.process_event( EvTerminateB() ); machine.AssertInState( "" ); machine.initiate(); machine.AssertInState( "ABCDEFG" ); machine.process_event( EvTerminateB() ); machine.AssertInState( "ACDEFG" ); machine.process_event( EvTerminateB() ); machine.AssertInState( "ACDEFG" ); machine.process_event( EvTerminateD() ); machine.AssertInState( "ACEFG" ); machine.process_event( EvTerminateD() ); machine.AssertInState( "ACEFG" ); machine.process_event( EvTerminateF() ); machine.AssertInState( "ACEG" ); machine.process_event( EvTerminateF() ); machine.AssertInState( "ACEG" ); machine.process_event( EvTerminateG() ); machine.AssertInState( "" ); machine.process_event( EvTerminateG() ); machine.AssertInState( "" ); machine.initiate(); machine.AssertInState( "ABCDEFG" ); machine.process_event( EvTerminateE() ); machine.AssertInState( "ABCD" ); machine.process_event( EvTerminateE() ); machine.AssertInState( "ABCD" ); machine.process_event( EvTerminateC() ); machine.AssertInState( "AB" ); machine.process_event( EvTerminateC() ); machine.AssertInState( "AB" ); machine.process_event( EvTerminateA() ); machine.AssertInState( "" ); machine.process_event( EvTerminateA() ); machine.AssertInState( "" ); machine.initiate(); machine.AssertInState( "ABCDEFG" ); machine.initiate(); machine.AssertInState( "ABCDEFG" ); machine.terminate(); machine.AssertInState( "" ); machine.terminate(); machine.AssertInState( "" ); TerminationEventBaseTest eventBaseMachine; eventBaseMachine.initiate(); BOOST_REQUIRE( !eventBaseMachine.terminated() ); eventBaseMachine.process_event( EvTerminateA() ); BOOST_REQUIRE( eventBaseMachine.terminated() ); eventBaseMachine.initiate(); BOOST_REQUIRE( !eventBaseMachine.terminated() ); eventBaseMachine.process_event( EvTerminateB() ); BOOST_REQUIRE( eventBaseMachine.terminated() ); return 0; }