1 //////////////////////////////////////////////////////////////////////////////
2 // Copyright 2004-2007 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 "OuterOrthogonal.hpp"
10 #include "InnermostDefault.hpp"
11 
12 #include <boost/statechart/state_machine.hpp>
13 #include <boost/statechart/null_exception_translator.hpp>
14 #include <boost/statechart/exception_translator.hpp>
15 #include <boost/statechart/event.hpp>
16 #include <boost/statechart/transition.hpp>
17 #include <boost/statechart/custom_reaction.hpp>
18 
19 #include <boost/mpl/list.hpp>
20 
21 #include <boost/test/test_tools.hpp>
22 
23 #include <typeinfo>
24 #include <string>
25 #include <vector>
26 #include <iostream>
27 #include <algorithm>
28 #include <stdexcept>
29 
30 
31 
32 namespace sc = boost::statechart;
33 namespace mpl = boost::mpl;
34 
35 
36 
37 typedef std::string ActionDescription();
38 typedef ActionDescription * ActionDescriptionPtr;
39 typedef std::vector< ActionDescriptionPtr > ActionDescriptionSequence;
40 typedef ActionDescriptionSequence::const_iterator SequenceIterator;
41 typedef void Action( ActionDescriptionSequence & );
42 typedef Action * ActionPtr;
43 
44 template< class State >
EntryDescription()45 std::string EntryDescription()
46 {
47   static const std::string entry = "Entry: ";
48   return entry + typeid( State ).name() + "\n";
49 }
50 
51 template< class State >
ExitFnDescription()52 std::string ExitFnDescription()
53 {
54   static const std::string exitFunction = "exit(): ";
55   return exitFunction + typeid( State ).name() + "\n";
56 }
57 
58 template< class State >
DtorDescription()59 std::string DtorDescription()
60 {
61   static const std::string destructor = "Destructor: ";
62   return destructor + typeid( State ).name() + "\n";
63 }
64 
65 template< class Context, class Event >
TransDescription()66 std::string TransDescription()
67 {
68   static const std::string transition = "Transition: ";
69   static const std::string event = " with Event: ";
70   return transition + typeid( Context ).name() +
71     event + typeid( Event ).name() + "\n";
72 }
73 
74 template< ActionPtr pAction >
ThrowDescription()75 std::string ThrowDescription()
76 {
77   static const std::string throwing = "Throwing exception in ";
78   ActionDescriptionSequence sequence;
79   pAction( sequence );
80   return throwing + sequence.front()();
81 }
82 
83 
84 template< class State >
Entry(ActionDescriptionSequence & sequence)85 void Entry( ActionDescriptionSequence & sequence )
86 {
87   sequence.push_back( &EntryDescription< State > );
88 }
89 
90 template< class State >
ExitFn(ActionDescriptionSequence & sequence)91 void ExitFn( ActionDescriptionSequence & sequence )
92 {
93   sequence.push_back( &ExitFnDescription< State > );
94 }
95 
96 template< class State >
Dtor(ActionDescriptionSequence & sequence)97 void Dtor( ActionDescriptionSequence & sequence )
98 {
99   sequence.push_back( &DtorDescription< State > );
100 }
101 
102 template< class State >
Exit(ActionDescriptionSequence & sequence)103 void Exit( ActionDescriptionSequence & sequence )
104 {
105   ExitFn< State >( sequence );
106   Dtor< State >( sequence );
107 }
108 
109 template< class Context, class Event >
Trans(ActionDescriptionSequence & sequence)110 void Trans( ActionDescriptionSequence & sequence )
111 {
112   sequence.push_back( &TransDescription< Context, Event > );
113 }
114 
115 template< ActionPtr pAction >
Throw(ActionDescriptionSequence & sequence)116 void Throw( ActionDescriptionSequence & sequence )
117 {
118   sequence.push_back( &ThrowDescription< pAction > );
119 }
120 
121 const int arrayLength = 30;
122 typedef ActionPtr ActionArray[ arrayLength ];
123 
124 
125 class TransitionTestException : public std::runtime_error
126 {
127   public:
TransitionTestException()128     TransitionTestException() : std::runtime_error( "Oh la la!" ) {}
129 };
130 
131 
132 // This test state machine is a beefed-up version of the one presented in
133 // "Practical Statecharts in C/C++" by Miro Samek, CMP Books 2002
134 struct A : sc::event< A > {};
135 struct B : sc::event< B > {};
136 struct C : sc::event< C > {};
137 struct D : sc::event< D > {};
138 struct E : sc::event< E > {};
139 struct F : sc::event< F > {};
140 struct G : sc::event< G > {};
141 struct H : sc::event< H > {};
142 
143 
144 template< class M > struct S0;
145 template< class Translator >
146 struct TransitionTest : sc::state_machine<
147   TransitionTest< Translator >, S0< TransitionTest< Translator > >,
148   std::allocator< sc::none >, Translator >
149 {
150   public:
151     //////////////////////////////////////////////////////////////////////////
TransitionTestTransitionTest152     TransitionTest() : pThrowAction_( 0 ), unconsumedEventCount_( 0 ) {}
153 
~TransitionTestTransitionTest154     ~TransitionTest()
155     {
156       // Since state destructors access the state machine object, we need to
157       // make sure that all states are destructed before this subtype
158       // portion is destructed.
159       this->terminate();
160     }
161 
CompareToExpectedActionSequenceTransitionTest162     void CompareToExpectedActionSequence( ActionArray & actions )
163     {
164       expectedSequence_.clear();
165 
166       // Copy all non-null pointers in actions into expectedSequence_
167       for ( ActionPtr * pCurrent = &actions[ 0 ];
168         ( pCurrent != &actions[ arrayLength ] ) && ( *pCurrent != 0 );
169         ++pCurrent )
170       {
171         ( *pCurrent )( expectedSequence_ );
172       }
173 
174       if ( ( expectedSequence_.size() != actualSequence_.size() ) ||
175         !std::equal( expectedSequence_.begin(),
176           expectedSequence_.end(), actualSequence_.begin() ) )
177       {
178         std::string message = "\nExpected action sequence:\n";
179 
180         for ( SequenceIterator pExpected = expectedSequence_.begin();
181           pExpected != expectedSequence_.end(); ++pExpected )
182         {
183           message += ( *pExpected )();
184         }
185 
186         message += "\nActual action sequence:\n";
187 
188         for ( SequenceIterator pActual = actualSequence_.begin();
189           pActual != actualSequence_.end(); ++pActual )
190         {
191           message += ( *pActual )();
192         }
193 
194         BOOST_FAIL( message.c_str() );
195       }
196 
197       actualSequence_.clear();
198     }
199 
ClearActualSequenceTransitionTest200     void ClearActualSequence()
201     {
202       actualSequence_.clear();
203     }
204 
ThrowActionTransitionTest205     void ThrowAction( ActionPtr pThrowAction )
206     {
207       pThrowAction_ = pThrowAction;
208     }
209 
210     template< class State >
ActualEntryTransitionTest211     void ActualEntry()
212     {
213       StoreActualAction< &Entry< State > >();
214     }
215 
216     template< class State >
ActualExitFunctionTransitionTest217     void ActualExitFunction()
218     {
219       StoreActualAction< &ExitFn< State > >();
220     }
221 
222     template< class State >
ActualDestructorTransitionTest223     void ActualDestructor()
224     {
225       StoreActualAction< &Dtor< State > >();
226     }
227 
228     template< class Context, class Event >
ActualTransitionTransitionTest229     void ActualTransition()
230     {
231       StoreActualAction< &Trans< Context, Event > >();
232     }
233 
unconsumed_eventTransitionTest234     void unconsumed_event( const sc::event_base & )
235     {
236       ++unconsumedEventCount_;
237     }
238 
GetUnconsumedEventCountTransitionTest239     unsigned int GetUnconsumedEventCount() const
240     {
241       return unconsumedEventCount_;
242     }
243 
244   private:
245     //////////////////////////////////////////////////////////////////////////
246     template< ActionPtr pAction >
StoreActualActionTransitionTest247     void StoreActualAction()
248     {
249       if ( pAction == pThrowAction_ )
250       {
251         Throw< pAction >( actualSequence_ );
252         throw TransitionTestException();
253       }
254       else
255       {
256         pAction( actualSequence_ );
257       }
258     }
259 
260     ActionPtr pThrowAction_;
261     ActionDescriptionSequence actualSequence_;
262     ActionDescriptionSequence expectedSequence_;
263     unsigned int unconsumedEventCount_;
264 };
265 
266 template< class M > struct S1;
267 template< class M > struct S211;
268 template< class M >
269 struct S0 : Orthogonal0< S0< M >, M, S1< M > >
270 {
271   typedef Orthogonal0< S0< M >, M, S1< M > > my_base;
272   public:
273     typedef sc::transition< E, S211< M > > reactions;
274 
S0S0275     S0( typename my_base::my_context ctx ) : my_base( ctx ) {}
276 
TransitS0277     void Transit( const A & evt ) { TransitImpl( evt ); }
TransitS0278     void Transit( const B & evt ) { TransitImpl( evt ); }
TransitS0279     void Transit( const C & evt ) { TransitImpl( evt ); }
TransitS0280     void Transit( const D & evt ) { TransitImpl( evt ); }
TransitS0281     void Transit( const F & evt ) { TransitImpl( evt ); }
TransitS0282     void Transit( const G & evt ) { TransitImpl( evt ); }
TransitS0283     void Transit( const H & evt ) { TransitImpl( evt ); }
284 
285   private:
286     template< class Event >
TransitImplS0287     void TransitImpl( const Event & )
288     {
289       this->outermost_context().template ActualTransition< S0< M >, Event >();
290     }
291 };
292 
293   template< class M > struct S11;
294   template< class M > struct S21;
295   template< class M >
296   struct S2 : Orthogonal2< S2< M >, S0< M >, S21< M > >
297   {
298     typedef Orthogonal2< S2< M >, S0< M >, S21< M > > my_base;
299     typedef mpl::list<
300       sc::transition< C, S1< M >, S0< M >, &S0< M >::Transit >,
301       sc::transition< F, S11< M >, S0< M >, &S0< M >::Transit >
302     > reactions;
303 
S2S2304     S2( typename my_base::my_context ctx ) : my_base( ctx ) {}
305   };
306 
307     template< class M >
308     struct S21 : Orthogonal1<
309       S21< M >, typename S2< M >::template orthogonal< 2 >, S211< M > >
310     {
311       typedef Orthogonal1<
312         S21< M >, typename S2< M >::template orthogonal< 2 >, S211< M >
313       > my_base;
314       typedef mpl::list<
315         sc::transition< H, S21< M >, S0< M >, &S0< M >::Transit >,
316         sc::transition< B, S211< M >, S0< M >, &S0< M >::Transit >
317       > reactions;
318 
S21S21319       S21( typename my_base::my_context ctx ) : my_base( ctx ) {}
320     };
321 
322       template< class M >
323       struct S211 : InnermostDefault<
324         S211< M >, typename S21< M >::template orthogonal< 1 > >
325       {
326         typedef InnermostDefault<
327           S211< M >, typename S21< M >::template orthogonal< 1 > > my_base;
328         typedef mpl::list<
329           sc::transition< D, S21< M >, S0< M >, &S0< M >::Transit >,
330           sc::transition< G, S0< M > >
331         > reactions;
332 
S211S211333         S211( typename my_base::my_context ctx ) : my_base( ctx ) {}
334       };
335 
336   template< class M >
337   struct S1 : Orthogonal1< S1< M >, S0< M >, S11< M > >
338   {
339     typedef Orthogonal1< S1< M >, S0< M >, S11< M > > my_base;
340     typedef mpl::list<
341       sc::transition< A, S1< M >, S0< M >, &S0< M >::Transit >,
342       sc::transition< B, S11< M >, S0< M >, &S0< M >::Transit >,
343       sc::transition< C, S2< M >, S0< M >, &S0< M >::Transit >,
344       sc::transition< D, S0< M > >,
345       sc::transition< F, S211< M >, S0< M >, &S0< M >::Transit >
346     > reactions;
347 
S1S1348     S1( typename my_base::my_context ctx ) : my_base( ctx ) {}
349   };
350 
351     template< class M >
352     struct S11 : InnermostDefault<
353       S11< M >, typename S1< M >::template orthogonal< 1 > >
354     {
355       typedef InnermostDefault<
356         S11< M >, typename S1< M >::template orthogonal< 1 > > my_base;
357       typedef mpl::list<
358         sc::transition< G, S211< M >, S0< M >, &S0< M >::Transit >,
359         sc::custom_reaction< H >
360       > reactions;
361 
S11S11362       S11( typename my_base::my_context ctx ) : my_base( ctx ) {}
363 
reactS11364       sc::result react( const H & )
365       {
366         this->outermost_context().template ActualTransition< S11< M >, H >();
367         return this->discard_event();
368       }
369     };
370 
371 
372 struct X1;
373 struct TransitionEventBaseTest :
374   sc::state_machine< TransitionEventBaseTest, X1 >
375 {
376   public:
TransitionEventBaseTestTransitionEventBaseTest377     TransitionEventBaseTest() : actionCallCounter_( 0 ) {}
378 
TransitTransitionEventBaseTest379     void Transit( const sc::event_base & eventBase )
380     {
381       BOOST_REQUIRE(
382         ( dynamic_cast< const B * >( &eventBase ) != 0 ) ||
383         ( dynamic_cast< const D * >( &eventBase ) != 0 ) );
384       ++actionCallCounter_;
385     }
386 
GetActionCallCounterTransitionEventBaseTest387     unsigned int GetActionCallCounter() const
388     {
389       return actionCallCounter_;
390     }
391 
392   private:
393     unsigned int actionCallCounter_;
394 };
395 
396 struct X2 : sc::simple_state< X2, TransitionEventBaseTest >
397 {
398   typedef sc::transition< sc::event_base, X1,
399     TransitionEventBaseTest, &TransitionEventBaseTest::Transit > reactions;
400 };
401 
402 struct X1 : sc::simple_state< X1, TransitionEventBaseTest >
403 {
404   typedef sc::transition< sc::event_base, X2 > reactions;
405 };
406 
407 template< class M >
TestTransitions(M & machine)408 void TestTransitions( M & machine )
409 {
410   machine.initiate();
411   ActionArray init =
412   {
413     Entry< S0< M > >,
414     Entry< S1< M > >,
415     Entry< Default0< S1< M > > >,
416     Entry< S11< M > >,
417     Entry< Default2< S1< M > > >,
418     Entry< Default1< S0< M > > >,
419     Entry< Default2< S0< M > > >
420   };
421   machine.CompareToExpectedActionSequence( init );
422 
423   machine.process_event( A() );
424   ActionArray a1 =
425   {
426     Exit< Default2< S1< M > > >,
427     Exit< S11< M > >,
428     Exit< Default0< S1< M > > >,
429     Exit< S1< M > >,
430     Trans< S0< M >, A >,
431     Entry< S1< M > >,
432     Entry< Default0< S1< M > > >,
433     Entry< S11< M > >,
434     Entry< Default2< S1< M > > >
435   };
436   machine.CompareToExpectedActionSequence( a1 );
437 
438   machine.process_event( B() );
439   ActionArray b1 =
440   {
441     Exit< Default2< S1< M > > >,
442     Exit< S11< M > >,
443     Exit< Default0< S1< M > > >,
444     Exit< S1< M > >,
445     Trans< S0< M >, B >,
446     Entry< S1< M > >,
447     Entry< Default0< S1< M > > >,
448     Entry< S11< M > >,
449     Entry< Default2< S1< M > > >
450   };
451   machine.CompareToExpectedActionSequence( b1 );
452 
453   machine.process_event( C() );
454   ActionArray c1 =
455   {
456     Exit< Default2< S1< M > > >,
457     Exit< S11< M > >,
458     Exit< Default0< S1< M > > >,
459     Exit< S1< M > >,
460     Trans< S0< M >, C >,
461     Entry< S2< M > >,
462     Entry< Default0< S2< M > > >,
463     Entry< Default1< S2< M > > >,
464     Entry< S21< M > >,
465     Entry< Default0< S21< M > > >,
466     Entry< S211< M > >,
467     Entry< Default2< S21< M > > >
468   };
469   machine.CompareToExpectedActionSequence( c1 );
470 
471   machine.process_event( D() );
472   ActionArray d2 =
473   {
474     Exit< Default2< S21< M > > >,
475     Exit< S211< M > >,
476     Exit< Default0< S21< M > > >,
477     Exit< S21< M > >,
478     Trans< S0< M >, D >,
479     Entry< S21< M > >,
480     Entry< Default0< S21< M > > >,
481     Entry< S211< M > >,
482     Entry< Default2< S21< M > > >
483   };
484   machine.CompareToExpectedActionSequence( d2 );
485 
486   machine.process_event( E() );
487   ActionArray e2 =
488   {
489     Exit< Default2< S0< M > > >,
490     Exit< Default1< S0< M > > >,
491     Exit< Default2< S21< M > > >,
492     Exit< S211< M > >,
493     Exit< Default0< S21< M > > >,
494     Exit< S21< M > >,
495     Exit< Default1< S2< M > > >,
496     Exit< Default0< S2< M > > >,
497     Exit< S2< M > >,
498     Exit< S0< M > >,
499     Entry< S0< M > >,
500     Entry< S2< M > >,
501     Entry< Default0< S2< M > > >,
502     Entry< Default1< S2< M > > >,
503     Entry< S21< M > >,
504     Entry< Default0< S21< M > > >,
505     Entry< S211< M > >,
506     Entry< Default2< S21< M > > >,
507     Entry< Default1< S0< M > > >,
508     Entry< Default2< S0< M > > >
509   };
510   machine.CompareToExpectedActionSequence( e2 );
511 
512   machine.process_event( F() );
513   ActionArray f2 =
514   {
515     Exit< Default2< S21< M > > >,
516     Exit< S211< M > >,
517     Exit< Default0< S21< M > > >,
518     Exit< S21< M > >,
519     Exit< Default1< S2< M > > >,
520     Exit< Default0< S2< M > > >,
521     Exit< S2< M > >,
522     Trans< S0< M >, F >,
523     Entry< S1< M > >,
524     Entry< Default0< S1< M > > >,
525     Entry< S11< M > >,
526     Entry< Default2< S1< M > > >
527   };
528   machine.CompareToExpectedActionSequence( f2 );
529 
530   machine.process_event( G() );
531   ActionArray g1 =
532   {
533     Exit< Default2< S1< M > > >,
534     Exit< S11< M > >,
535     Exit< Default0< S1< M > > >,
536     Exit< S1< M > >,
537     Trans< S0< M >, G >,
538     Entry< S2< M > >,
539     Entry< Default0< S2< M > > >,
540     Entry< Default1< S2< M > > >,
541     Entry< S21< M > >,
542     Entry< Default0< S21< M > > >,
543     Entry< S211< M > >,
544     Entry< Default2< S21< M > > >
545   };
546   machine.CompareToExpectedActionSequence( g1 );
547 
548   machine.process_event( H() );
549   ActionArray h2 =
550   {
551     Exit< Default2< S21< M > > >,
552     Exit< S211< M > >,
553     Exit< Default0< S21< M > > >,
554     Exit< S21< M > >,
555     Trans< S0< M >, H >,
556     Entry< S21< M > >,
557     Entry< Default0< S21< M > > >,
558     Entry< S211< M > >,
559     Entry< Default2< S21< M > > >
560   };
561   machine.CompareToExpectedActionSequence( h2 );
562 
563   BOOST_REQUIRE( machine.GetUnconsumedEventCount() == 0 );
564   machine.process_event( A() );
565   BOOST_REQUIRE( machine.GetUnconsumedEventCount() == 1 );
566   ActionArray a2 =
567   {
568   };
569   machine.CompareToExpectedActionSequence( a2 );
570 
571   machine.process_event( B() );
572   ActionArray b2 =
573   {
574     Exit< Default2< S21< M > > >,
575     Exit< S211< M > >,
576     Exit< Default0< S21< M > > >,
577     Exit< S21< M > >,
578     Trans< S0< M >, B >,
579     Entry< S21< M > >,
580     Entry< Default0< S21< M > > >,
581     Entry< S211< M > >,
582     Entry< Default2< S21< M > > >
583   };
584   machine.CompareToExpectedActionSequence( b2 );
585 
586   machine.process_event( C() );
587   ActionArray c2 =
588   {
589     Exit< Default2< S21< M > > >,
590     Exit< S211< M > >,
591     Exit< Default0< S21< M > > >,
592     Exit< S21< M > >,
593     Exit< Default1< S2< M > > >,
594     Exit< Default0< S2< M > > >,
595     Exit< S2< M > >,
596     Trans< S0< M >, C >,
597     Entry< S1< M > >,
598     Entry< Default0< S1< M > > >,
599     Entry< S11< M > >,
600     Entry< Default2< S1< M > > >
601   };
602   machine.CompareToExpectedActionSequence( c2 );
603 
604   machine.process_event( D() );
605   ActionArray d1 =
606   {
607     Exit< Default2< S0< M > > >,
608     Exit< Default1< S0< M > > >,
609     Exit< Default2< S1< M > > >,
610     Exit< S11< M > >,
611     Exit< Default0< S1< M > > >,
612     Exit< S1< M > >,
613     Exit< S0< M > >,
614     Entry< S0< M > >,
615     Entry< S1< M > >,
616     Entry< Default0< S1< M > > >,
617     Entry< S11< M > >,
618     Entry< Default2< S1< M > > >,
619     Entry< Default1< S0< M > > >,
620     Entry< Default2< S0< M > > >
621   };
622   machine.CompareToExpectedActionSequence( d1 );
623 
624   machine.process_event( F() );
625   ActionArray f1 =
626   {
627     Exit< Default2< S1< M > > >,
628     Exit< S11< M > >,
629     Exit< Default0< S1< M > > >,
630     Exit< S1< M > >,
631     Trans< S0< M >, F >,
632     Entry< S2< M > >,
633     Entry< Default0< S2< M > > >,
634     Entry< Default1< S2< M > > >,
635     Entry< S21< M > >,
636     Entry< Default0< S21< M > > >,
637     Entry< S211< M > >,
638     Entry< Default2< S21< M > > >
639   };
640   machine.CompareToExpectedActionSequence( f1 );
641 
642   machine.process_event( G() );
643   ActionArray g2 =
644   {
645     Exit< Default2< S0< M > > >,
646     Exit< Default1< S0< M > > >,
647     Exit< Default2< S21< M > > >,
648     Exit< S211< M > >,
649     Exit< Default0< S21< M > > >,
650     Exit< S21< M > >,
651     Exit< Default1< S2< M > > >,
652     Exit< Default0< S2< M > > >,
653     Exit< S2< M > >,
654     Exit< S0< M > >,
655     Entry< S0< M > >,
656     Entry< S1< M > >,
657     Entry< Default0< S1< M > > >,
658     Entry< S11< M > >,
659     Entry< Default2< S1< M > > >,
660     Entry< Default1< S0< M > > >,
661     Entry< Default2< S0< M > > >
662   };
663   machine.CompareToExpectedActionSequence( g2 );
664 
665   machine.process_event( H() );
666   ActionArray h1 =
667   {
668     Trans< S11< M >, H >
669   };
670   machine.CompareToExpectedActionSequence( h1 );
671 
672   machine.process_event( E() );
673   ActionArray e1 =
674   {
675     Exit< Default2< S0< M > > >,
676     Exit< Default1< S0< M > > >,
677     Exit< Default2< S1< M > > >,
678     Exit< S11< M > >,
679     Exit< Default0< S1< M > > >,
680     Exit< S1< M > >,
681     Exit< S0< M > >,
682     Entry< S0< M > >,
683     Entry< S2< M > >,
684     Entry< Default0< S2< M > > >,
685     Entry< Default1< S2< M > > >,
686     Entry< S21< M > >,
687     Entry< Default0< S21< M > > >,
688     Entry< S211< M > >,
689     Entry< Default2< S21< M > > >,
690     Entry< Default1< S0< M > > >,
691     Entry< Default2< S0< M > > >
692   };
693   machine.CompareToExpectedActionSequence( e1 );
694 
695   machine.terminate();
696   ActionArray term =
697   {
698     Exit< Default2< S0< M > > >,
699     Exit< Default1< S0< M > > >,
700     Exit< Default2< S21< M > > >,
701     Exit< S211< M > >,
702     Exit< Default0< S21< M > > >,
703     Exit< S21< M > >,
704     Exit< Default1< S2< M > > >,
705     Exit< Default0< S2< M > > >,
706     Exit< S2< M > >,
707     Exit< S0< M > >
708   };
709   machine.CompareToExpectedActionSequence( term );
710 
711   machine.ThrowAction( &Entry< Default0< S1< M > > > );
712   BOOST_REQUIRE_THROW( machine.initiate(), TransitionTestException );
713   ActionArray initThrow1 =
714   {
715     Entry< S0< M > >,
716     Entry< S1< M > >,
717     &::Throw< &::Entry< Default0< S1< M > > > >,
718     Dtor< S1< M > >,
719     Dtor< S0< M > >
720   };
721   machine.CompareToExpectedActionSequence( initThrow1 );
722   BOOST_REQUIRE( machine.terminated() );
723 
724   machine.ThrowAction( &Entry< S11< M > > );
725   BOOST_REQUIRE_THROW( machine.initiate(), TransitionTestException );
726   ActionArray initThrow2 =
727   {
728     Entry< S0< M > >,
729     Entry< S1< M > >,
730     Entry< Default0< S1< M > > >,
731     &::Throw< &::Entry< S11< M > > >,
732     Dtor< Default0< S1< M > > >,
733     Dtor< S1< M > >,
734     Dtor< S0< M > >
735   };
736   machine.CompareToExpectedActionSequence( initThrow2 );
737   BOOST_REQUIRE( machine.terminated() );
738 
739   machine.ThrowAction( &Trans< S0< M >, A > );
740   machine.initiate();
741   BOOST_REQUIRE_THROW( machine.process_event( A() ), TransitionTestException );
742   ActionArray a1Throw1 =
743   {
744     Entry< S0< M > >,
745     Entry< S1< M > >,
746     Entry< Default0< S1< M > > >,
747     Entry< S11< M > >,
748     Entry< Default2< S1< M > > >,
749     Entry< Default1< S0< M > > >,
750     Entry< Default2< S0< M > > >,
751     Exit< Default2< S1< M > > >,
752     Exit< S11< M > >,
753     Exit< Default0< S1< M > > >,
754     Exit< S1< M > >,
755     &::Throw< &::Trans< S0< M >, A > >,
756     Dtor< Default2< S0< M > > >,
757     Dtor< Default1< S0< M > > >,
758     Dtor< S0< M > >
759   };
760   machine.CompareToExpectedActionSequence( a1Throw1 );
761   BOOST_REQUIRE( machine.terminated() );
762 
763   machine.ThrowAction( &Entry< S211< M > > );
764   machine.initiate();
765   BOOST_REQUIRE_THROW( machine.process_event( C() ), TransitionTestException );
766   ActionArray c1Throw1 =
767   {
768     Entry< S0< M > >,
769     Entry< S1< M > >,
770     Entry< Default0< S1< M > > >,
771     Entry< S11< M > >,
772     Entry< Default2< S1< M > > >,
773     Entry< Default1< S0< M > > >,
774     Entry< Default2< S0< M > > >,
775     Exit< Default2< S1< M > > >,
776     Exit< S11< M > >,
777     Exit< Default0< S1< M > > >,
778     Exit< S1< M > >,
779     Trans< S0< M >, C >,
780     Entry< S2< M > >,
781     Entry< Default0< S2< M > > >,
782     Entry< Default1< S2< M > > >,
783     Entry< S21< M > >,
784     Entry< Default0< S21< M > > >,
785     &::Throw< &::Entry< S211< M > > >,
786     Dtor< Default2< S0< M > > >,
787     Dtor< Default1< S0< M > > >,
788     Dtor< Default0< S21< M > > >,
789     Dtor< S21< M > >,
790     Dtor< Default1< S2< M > > >,
791     Dtor< Default0< S2< M > > >,
792     Dtor< S2< M > >,
793     Dtor< S0< M > >
794   };
795   machine.CompareToExpectedActionSequence( c1Throw1 );
796   BOOST_REQUIRE( machine.terminated() );
797 
798   machine.ThrowAction( &ExitFn< S11< M > > );
799   machine.initiate();
800   BOOST_REQUIRE_THROW( machine.process_event( C() ), TransitionTestException );
801   ActionArray c1Throw2 =
802   {
803     Entry< S0< M > >,
804     Entry< S1< M > >,
805     Entry< Default0< S1< M > > >,
806     Entry< S11< M > >,
807     Entry< Default2< S1< M > > >,
808     Entry< Default1< S0< M > > >,
809     Entry< Default2< S0< M > > >,
810     Exit< Default2< S1< M > > >,
811     &::Throw< &::ExitFn< S11< M > > >,
812     Dtor< S11< M > >,
813     Dtor< Default2< S0< M > > >,
814     Dtor< Default1< S0< M > > >,
815     Dtor< Default0< S1< M > > >,
816     Dtor< S1< M > >,
817     Dtor< S0< M > >
818   };
819   machine.CompareToExpectedActionSequence( c1Throw2 );
820   BOOST_REQUIRE( machine.terminated() );
821   BOOST_REQUIRE( machine.GetUnconsumedEventCount() == 1 );
822 }
823 
824 
test_main(int,char * [])825 int test_main( int, char* [] )
826 {
827   TransitionTest< sc::null_exception_translator > null_machine;
828   TestTransitions( null_machine );
829   TransitionTest< sc::exception_translator<> > machine;
830   TestTransitions( machine );
831 
832   TransitionEventBaseTest eventBaseMachine;
833   eventBaseMachine.initiate();
834   BOOST_REQUIRE_NO_THROW( eventBaseMachine.state_cast< const X1 & >() );
835   eventBaseMachine.process_event( A() );
836   BOOST_REQUIRE_NO_THROW( eventBaseMachine.state_cast< const X2 & >() );
837   BOOST_REQUIRE( eventBaseMachine.GetActionCallCounter() == 0 );
838   eventBaseMachine.process_event( B() );
839   BOOST_REQUIRE_NO_THROW( eventBaseMachine.state_cast< const X1 & >() );
840   BOOST_REQUIRE( eventBaseMachine.GetActionCallCounter() == 1 );
841   eventBaseMachine.process_event( C() );
842   BOOST_REQUIRE_NO_THROW( eventBaseMachine.state_cast< const X2 & >() );
843   BOOST_REQUIRE( eventBaseMachine.GetActionCallCounter() == 1 );
844   eventBaseMachine.process_event( D() );
845   BOOST_REQUIRE_NO_THROW( eventBaseMachine.state_cast< const X1 & >() );
846   BOOST_REQUIRE( eventBaseMachine.GetActionCallCounter() == 2 );
847 
848   return 0;
849 }
850