1 //////////////////////////////////////////////////////////////////////////////
2 // Copyright 2004-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 //////////////////////////////////////////////////////////////////////////////
9 #include <boost/statechart/state_machine.hpp>
10 #include <boost/statechart/event.hpp>
11 #include <boost/statechart/simple_state.hpp>
12 #include <boost/statechart/transition.hpp>
13 #include <boost/statechart/deferral.hpp>
14 #include <boost/statechart/custom_reaction.hpp>
16 #include <boost/mpl/list.hpp>
17 #include <boost/intrusive_ptr.hpp>
19 #include <boost/test/test_tools.hpp>
23 namespace sc
= boost::statechart
;
24 namespace mpl
= boost::mpl
;
29 boost::intrusive_ptr
< T
> MakeIntrusive( T
* pT
)
31 return boost::intrusive_ptr
< T
>( pT
);
34 struct EvLeafDeferred
: sc::event
< EvLeafDeferred
> {};
35 struct EvNodeDeferred
: sc::event
< EvNodeDeferred
> {};
36 struct EvSwitch
: sc::event
< EvSwitch
> {};
37 struct EvDestroy
: sc::event
< EvDestroy
> {};
40 struct DeferralTest
: sc::state_machine
< DeferralTest
, Active
>
42 //////////////////////////////////////////////////////////////////////////
43 DeferralTest() : processedCount_( 0 ) {}
45 void IncrementProcessedCount()
50 unsigned int ProcessedCount() const
52 return processedCount_
;
56 //////////////////////////////////////////////////////////////////////////
57 unsigned int processedCount_
;
60 struct Dead
: sc::simple_state
< Dead
, DeferralTest
>
62 typedef sc::custom_reaction
< EvNodeDeferred
> reactions
;
64 sc::result
react( const EvNodeDeferred
& )
66 outermost_context().IncrementProcessedCount();
67 return discard_event();
72 struct Active
: sc::simple_state
< Active
, DeferralTest
, Idle
>
75 sc::custom_reaction
< EvLeafDeferred
>,
76 sc::deferral
< EvNodeDeferred
>,
77 sc::transition
< EvDestroy
, Dead
>
80 sc::result
react( const EvLeafDeferred
& )
82 outermost_context().IncrementProcessedCount();
83 return discard_event();
87 struct Running
: sc::simple_state
< Running
, Active
>
89 typedef sc::transition
< EvSwitch
, Idle
> reactions
;
92 struct Idle
: sc::simple_state
< Idle
, Active
>
95 sc::transition
< EvSwitch
, Running
>,
96 sc::deferral
< EvLeafDeferred
>
101 struct EvToX2
: sc::event
< EvToX2
> {};
102 struct EvToX3
: sc::event
< EvToX3
> {};
105 struct DeferralEventBaseTest
: sc::state_machine
< DeferralEventBaseTest
, X1
>
109 struct X3
: sc::simple_state
< X3
, DeferralEventBaseTest
> {};
111 struct X2
: sc::simple_state
< X2
, DeferralEventBaseTest
>
113 typedef sc::transition
< EvToX3
, X3
> reactions
;
116 struct X1
: sc::simple_state
< X1
, DeferralEventBaseTest
>
119 sc::transition
< EvToX2
, X2
>,
120 sc::deferral
< sc::event_base
>
125 int test_main( int, char* [] )
127 DeferralTest machine
;
129 machine
.process_event( *MakeIntrusive( new EvSwitch() ) );
130 BOOST_REQUIRE( machine
.ProcessedCount() == 0 );
131 machine
.process_event( *MakeIntrusive( new EvSwitch() ) );
132 BOOST_REQUIRE( machine
.ProcessedCount() == 0 );
133 machine
.process_event( *MakeIntrusive( new EvLeafDeferred() ) );
134 BOOST_REQUIRE( machine
.ProcessedCount() == 0 );
135 machine
.process_event( *MakeIntrusive( new EvSwitch() ) );
136 BOOST_REQUIRE( machine
.ProcessedCount() == 1 );
137 machine
.process_event( *MakeIntrusive( new EvSwitch() ) );
138 BOOST_REQUIRE( machine
.ProcessedCount() == 1 );
139 machine
.process_event( *MakeIntrusive( new EvLeafDeferred() ) );
140 machine
.process_event( *MakeIntrusive( new EvLeafDeferred() ) );
141 BOOST_REQUIRE( machine
.ProcessedCount() == 1 );
142 machine
.process_event( *MakeIntrusive( new EvSwitch() ) );
143 BOOST_REQUIRE( machine
.ProcessedCount() == 3 );
144 machine
.process_event( *MakeIntrusive( new EvSwitch() ) );
145 BOOST_REQUIRE( machine
.ProcessedCount() == 3 );
146 machine
.process_event( *MakeIntrusive( new EvNodeDeferred() ) );
147 BOOST_REQUIRE( machine
.ProcessedCount() == 3 );
148 machine
.process_event( *MakeIntrusive( new EvSwitch() ) );
149 BOOST_REQUIRE( machine
.ProcessedCount() == 3 );
150 machine
.process_event( EvNodeDeferred() );
151 BOOST_REQUIRE( machine
.ProcessedCount() == 3 );
152 machine
.process_event( *MakeIntrusive( new EvDestroy() ) );
153 BOOST_REQUIRE( machine
.ProcessedCount() == 5 );
156 DeferralEventBaseTest eventBaseMachine
;
157 // state_cast sanity check
158 BOOST_REQUIRE_THROW( eventBaseMachine
.state_cast
< const X1
& >(), std::bad_cast
);
159 eventBaseMachine
.initiate();
160 BOOST_REQUIRE_NO_THROW( eventBaseMachine
.state_cast
< const X1
& >() );
161 // Deferral must work with heap-allocated and stack-allocated events
162 eventBaseMachine
.process_event( EvToX3() );
163 BOOST_REQUIRE_NO_THROW( eventBaseMachine
.state_cast
< const X1
& >() );
164 eventBaseMachine
.process_event( EvToX2() );
165 BOOST_REQUIRE_NO_THROW( eventBaseMachine
.state_cast
< const X3
& >() );
166 eventBaseMachine
.initiate();
167 BOOST_REQUIRE_NO_THROW( eventBaseMachine
.state_cast
< const X1
& >() );
168 eventBaseMachine
.process_event( EvToX2() );
169 BOOST_REQUIRE_NO_THROW( eventBaseMachine
.state_cast
< const X2
& >() );