////////////////////////////////////////////////////////////////////////////// // (c) Copyright Andreas Huber Doenni 2005 // 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 fsm = boost::fsm; namespace mpl = boost::mpl; struct EvTerminateA : fsm::event< EvTerminateA > {}; struct EvTerminateB : fsm::event< EvTerminateB > {}; struct EvTerminateC : fsm::event< EvTerminateC > {}; struct EvTerminateD : fsm::event< EvTerminateD > {}; struct EvTerminateE : fsm::event< EvTerminateE > {}; struct EvTerminateF : fsm::event< EvTerminateF > {}; struct EvTerminateG : fsm::event< EvTerminateG > {}; struct A; struct TerminationTest : fsm::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 Reactions, class InnerInitial = mpl::list<> > struct MyState : fsm::simple_state< MostDerived, Context, Reactions, 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, fsm::termination< EvTerminateA >, mpl::list< B, C > > {}; struct B : MyState< B, A::orthogonal< 0 >, fsm::termination< EvTerminateB > > {}; struct D; struct E; struct C : MyState< C, A::orthogonal< 1 >, fsm::termination< EvTerminateC >, mpl::list< D, E > > {}; struct D : MyState< D, C::orthogonal< 0 >, fsm::termination< EvTerminateD > > {}; struct F; struct G; struct E : MyState< E, C::orthogonal< 1 >, fsm::termination< EvTerminateE >, mpl::list< F, G > > {}; struct F : MyState< F, E::orthogonal< 0 >, fsm::termination< EvTerminateF > > {}; struct G : MyState< G, E::orthogonal< 1 >, fsm::termination< EvTerminateG > > {}; TerminationTest::TerminationTest() { // We're not using custom type information to make this test work even when // BOOST_FSM_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"; } 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( "" ); return 0; }