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
24namespace sc = boost::statechart;
25namespace mpl = boost::mpl;
26
27
28
29struct EvTerminateA : sc::event< EvTerminateA > {};
30struct EvTerminateB : sc::event< EvTerminateB > {};
31struct EvTerminateC : sc::event< EvTerminateC > {};
32struct EvTerminateD : sc::event< EvTerminateD > {};
33struct EvTerminateE : sc::event< EvTerminateE > {};
34struct EvTerminateF : sc::event< EvTerminateF > {};
35struct EvTerminateG : sc::event< EvTerminateG > {};
36
37struct A;
38struct TerminationTest : sc::state_machine< TerminationTest, A >
39{
40 public:
41 //////////////////////////////////////////////////////////////////////////
42 TerminationTest();
43
44 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( stateType: currentState->dynamic_type() );
52
53 const state_base_type * outerState = currentState->outer_state_ptr();
54
55 while ( outerState != 0 )
56 {
57 AddName( stateType: 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 //////////////////////////////////////////////////////////////////////////
76 void AddName( state_base_type::id_type stateType ) const
77 {
78 const StateNamesMap::const_iterator found =
79 stateNamesMap_.find( x: stateType );
80 BOOST_REQUIRE( found != stateNamesMap_.end() );
81 stateNamesCache_.insert( x: 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
91template<
92 class MostDerived,
93 class Context,
94 class InnerInitial = mpl::list<> >
95struct MyState : sc::simple_state< MostDerived, Context, InnerInitial >
96{
97 public:
98 MyState() : exitCalled_( false ) {}
99
100 ~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
108 void exit()
109 {
110 exitCalled_ = true;
111 }
112
113 private:
114 bool exitCalled_;
115};
116
117
118struct B;
119struct C;
120struct 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
159TerminationTest::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
173struct X;
174struct TerminationEventBaseTest :
175 sc::state_machine< TerminationEventBaseTest, X > {};
176
177struct X : sc::simple_state< X, TerminationEventBaseTest >
178{
179 typedef sc::termination< sc::event_base > reactions;
180};
181
182
183int test_main( int, char* [] )
184{
185 TerminationTest machine;
186 machine.AssertInState( stateNames: "" );
187
188 machine.initiate();
189 machine.AssertInState( stateNames: "ABCDEFG" );
190 machine.process_event( evt: EvTerminateE() );
191 machine.AssertInState( stateNames: "ABCD" );
192 machine.process_event( evt: EvTerminateE() );
193 machine.AssertInState( stateNames: "ABCD" );
194
195 machine.initiate();
196 machine.AssertInState( stateNames: "ABCDEFG" );
197 machine.process_event( evt: EvTerminateC() );
198 machine.AssertInState( stateNames: "AB" );
199 machine.process_event( evt: EvTerminateC() );
200 machine.AssertInState( stateNames: "AB" );
201
202 machine.initiate();
203 machine.AssertInState( stateNames: "ABCDEFG" );
204 machine.process_event( evt: EvTerminateA() );
205 machine.AssertInState( stateNames: "" );
206 machine.process_event( evt: EvTerminateA() );
207 machine.AssertInState( stateNames: "" );
208
209 machine.initiate();
210 machine.AssertInState( stateNames: "ABCDEFG" );
211 machine.process_event( evt: EvTerminateG() );
212 machine.AssertInState( stateNames: "ABCDEF" );
213 machine.process_event( evt: EvTerminateG() );
214 machine.AssertInState( stateNames: "ABCDEF" );
215 machine.process_event( evt: EvTerminateF() );
216 machine.AssertInState( stateNames: "ABCD" );
217 machine.process_event( evt: EvTerminateF() );
218 machine.AssertInState( stateNames: "ABCD" );
219 machine.process_event( evt: EvTerminateD() );
220 machine.AssertInState( stateNames: "AB" );
221 machine.process_event( evt: EvTerminateD() );
222 machine.AssertInState( stateNames: "AB" );
223 machine.process_event( evt: EvTerminateB() );
224 machine.AssertInState( stateNames: "" );
225 machine.process_event( evt: EvTerminateB() );
226 machine.AssertInState( stateNames: "" );
227
228 machine.initiate();
229 machine.AssertInState( stateNames: "ABCDEFG" );
230 machine.process_event( evt: EvTerminateB() );
231 machine.AssertInState( stateNames: "ACDEFG" );
232 machine.process_event( evt: EvTerminateB() );
233 machine.AssertInState( stateNames: "ACDEFG" );
234 machine.process_event( evt: EvTerminateD() );
235 machine.AssertInState( stateNames: "ACEFG" );
236 machine.process_event( evt: EvTerminateD() );
237 machine.AssertInState( stateNames: "ACEFG" );
238 machine.process_event( evt: EvTerminateF() );
239 machine.AssertInState( stateNames: "ACEG" );
240 machine.process_event( evt: EvTerminateF() );
241 machine.AssertInState( stateNames: "ACEG" );
242 machine.process_event( evt: EvTerminateG() );
243 machine.AssertInState( stateNames: "" );
244 machine.process_event( evt: EvTerminateG() );
245 machine.AssertInState( stateNames: "" );
246
247 machine.initiate();
248 machine.AssertInState( stateNames: "ABCDEFG" );
249 machine.process_event( evt: EvTerminateE() );
250 machine.AssertInState( stateNames: "ABCD" );
251 machine.process_event( evt: EvTerminateE() );
252 machine.AssertInState( stateNames: "ABCD" );
253 machine.process_event( evt: EvTerminateC() );
254 machine.AssertInState( stateNames: "AB" );
255 machine.process_event( evt: EvTerminateC() );
256 machine.AssertInState( stateNames: "AB" );
257 machine.process_event( evt: EvTerminateA() );
258 machine.AssertInState( stateNames: "" );
259 machine.process_event( evt: EvTerminateA() );
260 machine.AssertInState( stateNames: "" );
261
262 machine.initiate();
263 machine.AssertInState( stateNames: "ABCDEFG" );
264 machine.initiate();
265 machine.AssertInState( stateNames: "ABCDEFG" );
266 machine.terminate();
267 machine.AssertInState( stateNames: "" );
268 machine.terminate();
269 machine.AssertInState( stateNames: "" );
270
271
272 TerminationEventBaseTest eventBaseMachine;
273 eventBaseMachine.initiate();
274 BOOST_REQUIRE( !eventBaseMachine.terminated() );
275 eventBaseMachine.process_event( evt: EvTerminateA() );
276 BOOST_REQUIRE( eventBaseMachine.terminated() );
277 eventBaseMachine.initiate();
278 BOOST_REQUIRE( !eventBaseMachine.terminated() );
279 eventBaseMachine.process_event( evt: EvTerminateB() );
280 BOOST_REQUIRE( eventBaseMachine.terminated() );
281
282 return 0;
283}
284

source code of boost/libs/statechart/test/TerminationTest.cpp