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//////////////////////////////////////////////////////////////////////////////
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/transition.hpp>
13#include <boost/statechart/deferral.hpp>
14#include <boost/statechart/custom_reaction.hpp>
15
16#include <boost/mpl/list.hpp>
17#include <boost/intrusive_ptr.hpp>
18
19#include <boost/test/test_tools.hpp>
20
21
22
23namespace sc = boost::statechart;
24namespace mpl = boost::mpl;
25
26
27
28template< class T >
29boost::intrusive_ptr< T > MakeIntrusive( T * pT )
30{
31 return boost::intrusive_ptr< T >( pT );
32}
33
34struct EvLeafDeferred : sc::event< EvLeafDeferred > {};
35struct EvNodeDeferred : sc::event< EvNodeDeferred > {};
36struct EvSwitch : sc::event< EvSwitch > {};
37struct EvDestroy : sc::event< EvDestroy > {};
38
39struct Active;
40struct DeferralTest : sc::state_machine< DeferralTest, Active >
41{
42 //////////////////////////////////////////////////////////////////////////
43 DeferralTest() : processedCount_( 0 ) {}
44
45 void IncrementProcessedCount()
46 {
47 ++processedCount_;
48 }
49
50 unsigned int ProcessedCount() const
51 {
52 return processedCount_;
53 }
54
55 private:
56 //////////////////////////////////////////////////////////////////////////
57 unsigned int processedCount_;
58};
59
60struct Dead : sc::simple_state< Dead, DeferralTest >
61{
62 typedef sc::custom_reaction< EvNodeDeferred > reactions;
63
64 sc::result react( const EvNodeDeferred & )
65 {
66 outermost_context().IncrementProcessedCount();
67 return discard_event();
68 }
69};
70
71struct Idle;
72struct Active : sc::simple_state< Active, DeferralTest, Idle >
73{
74 typedef mpl::list<
75 sc::custom_reaction< EvLeafDeferred >,
76 sc::deferral< EvNodeDeferred >,
77 sc::transition< EvDestroy, Dead >
78 > reactions;
79
80 sc::result react( const EvLeafDeferred & )
81 {
82 outermost_context().IncrementProcessedCount();
83 return discard_event();
84 }
85};
86
87 struct Running : sc::simple_state< Running, Active >
88 {
89 typedef sc::transition< EvSwitch, Idle > reactions;
90 };
91
92 struct Idle : sc::simple_state< Idle, Active >
93 {
94 typedef mpl::list<
95 sc::transition< EvSwitch, Running >,
96 sc::deferral< EvLeafDeferred >
97 > reactions;
98 };
99
100
101struct EvToX2 : sc::event< EvToX2 > {};
102struct EvToX3 : sc::event< EvToX3 > {};
103
104struct X1;
105struct DeferralEventBaseTest : sc::state_machine< DeferralEventBaseTest, X1 >
106{
107};
108
109struct X3 : sc::simple_state< X3, DeferralEventBaseTest > {};
110
111struct X2 : sc::simple_state< X2, DeferralEventBaseTest >
112{
113 typedef sc::transition< EvToX3, X3 > reactions;
114};
115
116struct X1 : sc::simple_state< X1, DeferralEventBaseTest >
117{
118 typedef mpl::list<
119 sc::transition< EvToX2, X2 >,
120 sc::deferral< sc::event_base >
121 > reactions;
122};
123
124
125int test_main( int, char* [] )
126{
127 DeferralTest machine;
128 machine.initiate();
129 machine.process_event( evt: *MakeIntrusive( pT: new EvSwitch() ) );
130 BOOST_REQUIRE( machine.ProcessedCount() == 0 );
131 machine.process_event( evt: *MakeIntrusive( pT: new EvSwitch() ) );
132 BOOST_REQUIRE( machine.ProcessedCount() == 0 );
133 machine.process_event( evt: *MakeIntrusive( pT: new EvLeafDeferred() ) );
134 BOOST_REQUIRE( machine.ProcessedCount() == 0 );
135 machine.process_event( evt: *MakeIntrusive( pT: new EvSwitch() ) );
136 BOOST_REQUIRE( machine.ProcessedCount() == 1 );
137 machine.process_event( evt: *MakeIntrusive( pT: new EvSwitch() ) );
138 BOOST_REQUIRE( machine.ProcessedCount() == 1 );
139 machine.process_event( evt: *MakeIntrusive( pT: new EvLeafDeferred() ) );
140 machine.process_event( evt: *MakeIntrusive( pT: new EvLeafDeferred() ) );
141 BOOST_REQUIRE( machine.ProcessedCount() == 1 );
142 machine.process_event( evt: *MakeIntrusive( pT: new EvSwitch() ) );
143 BOOST_REQUIRE( machine.ProcessedCount() == 3 );
144 machine.process_event( evt: *MakeIntrusive( pT: new EvSwitch() ) );
145 BOOST_REQUIRE( machine.ProcessedCount() == 3 );
146 machine.process_event( evt: *MakeIntrusive( pT: new EvNodeDeferred() ) );
147 BOOST_REQUIRE( machine.ProcessedCount() == 3 );
148 machine.process_event( evt: *MakeIntrusive( pT: new EvSwitch() ) );
149 BOOST_REQUIRE( machine.ProcessedCount() == 3 );
150 machine.process_event( evt: EvNodeDeferred() );
151 BOOST_REQUIRE( machine.ProcessedCount() == 3 );
152 machine.process_event( evt: *MakeIntrusive( pT: new EvDestroy() ) );
153 BOOST_REQUIRE( machine.ProcessedCount() == 5 );
154
155
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( evt: EvToX3() );
163 BOOST_REQUIRE_NO_THROW( eventBaseMachine.state_cast< const X1 & >() );
164 eventBaseMachine.process_event( evt: 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( evt: EvToX2() );
169 BOOST_REQUIRE_NO_THROW( eventBaseMachine.state_cast< const X2 & >() );
170
171 return 0;
172}
173

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