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