• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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