1//////////////////////////////////////////////////////////////////////////////
2// Copyright 2005-2008 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/test/test_tools.hpp>
10
11#include <boost/statechart/asynchronous_state_machine.hpp>
12#include <boost/statechart/fifo_scheduler.hpp>
13#include <boost/statechart/event.hpp>
14#include <boost/statechart/simple_state.hpp>
15#include <boost/statechart/termination.hpp>
16#include <boost/statechart/custom_reaction.hpp>
17
18#include <boost/mpl/list.hpp>
19
20#include <boost/bind.hpp>
21#include <boost/ref.hpp>
22
23#include <stdexcept>
24
25
26
27namespace sc = boost::statechart;
28namespace mpl = boost::mpl;
29
30
31
32struct EvCheckCtorArgs : sc::event< EvCheckCtorArgs >
33{
34 public:
35 EvCheckCtorArgs( int expectedArgs ) : expectedArgs_( expectedArgs ) {}
36 const int expectedArgs_;
37
38 private:
39 // avoids C4512 (assignment operator could not be generated)
40 EvCheckCtorArgs & operator=( const EvCheckCtorArgs & );
41};
42
43struct EvTerminate : sc::event< EvTerminate > {};
44struct EvFail : sc::event< EvFail > {};
45
46
47struct Initial;
48struct FifoSchedulerTest :
49 sc::asynchronous_state_machine< FifoSchedulerTest, Initial >
50{
51 public:
52 //////////////////////////////////////////////////////////////////////////
53 FifoSchedulerTest( my_context ctx ) :
54 my_base( ctx ),
55 ctorArgs_( 0 )
56 {
57 }
58
59 FifoSchedulerTest( my_context ctx, int arg1 ) :
60 my_base( ctx ),
61 ctorArgs_( arg1 )
62 {
63 }
64
65 FifoSchedulerTest( my_context ctx, int arg1, int arg2 ) :
66 my_base( ctx ),
67 ctorArgs_( arg1 * 10 + arg2 )
68 {
69 }
70
71 FifoSchedulerTest( my_context ctx, int arg1, int arg2, int arg3 ) :
72 my_base( ctx ),
73 ctorArgs_( ( arg1 * 10 + arg2 ) * 10 + arg3 )
74 {
75 }
76
77 FifoSchedulerTest(
78 my_context ctx,
79 int arg1, int arg2, int arg3, int arg4
80 ) :
81 my_base( ctx ),
82 ctorArgs_( ( ( arg1 * 10 + arg2 ) * 10 + arg3 ) * 10 + arg4 )
83 {
84 }
85
86 FifoSchedulerTest(
87 my_context ctx,
88 int arg1, int arg2, int arg3, int arg4, int arg5
89 ) :
90 my_base( ctx ),
91 ctorArgs_( ( ( ( arg1 * 10 + arg2 ) * 10 +
92 arg3 ) * 10 + arg4 ) * 10 + arg5 )
93 {
94 }
95
96 FifoSchedulerTest(
97 my_context ctx,
98 int arg1, int arg2, int arg3, int arg4, int arg5, int arg6
99 ) :
100 my_base( ctx ),
101 ctorArgs_( ( ( ( ( arg1 * 10 + arg2 ) * 10 +
102 arg3 ) * 10 + arg4 ) * 10 + arg5 ) * 10 + arg6 )
103 {
104 }
105
106 int CtorArgs()
107 {
108 return ctorArgs_;
109 }
110
111 private:
112 //////////////////////////////////////////////////////////////////////////
113 const int ctorArgs_;
114};
115
116boost::intrusive_ptr< const sc::event_base > MakeEvent(
117 const sc::event_base * pEvent )
118{
119 return boost::intrusive_ptr< const sc::event_base >( pEvent );
120}
121
122struct Initial : sc::simple_state< Initial, FifoSchedulerTest >
123{
124 typedef mpl::list<
125 sc::custom_reaction< EvCheckCtorArgs >,
126 sc::termination< EvTerminate >,
127 sc::custom_reaction< EvFail >
128 > reactions;
129
130 sc::result react( const EvCheckCtorArgs & ev )
131 {
132 BOOST_REQUIRE( ev.expectedArgs_ == outermost_context().CtorArgs() );
133 outermost_context_type & machine = outermost_context();
134 machine.my_scheduler().queue_event(
135 processor: machine.my_handle(), pEvent: MakeEvent( pEvent: new EvTerminate() ) );
136 return discard_event();
137 }
138
139 sc::result react( const EvFail & )
140 {
141 BOOST_FAIL( "State machine is unexpectedly still running." );
142 return discard_event();
143 }
144};
145
146
147struct UnexpectedEventCount : public std::runtime_error
148{
149 UnexpectedEventCount() : std::runtime_error( "" ) {}
150};
151
152void RunScheduler(
153 sc::fifo_scheduler<> & scheduler, unsigned long expectedEventCount )
154{
155 // Workaround: For some reason MSVC has a problem with BOOST_REQUIRE here
156 // (C1055: compiler limit: out of keys)
157 if ( scheduler() != expectedEventCount )
158 {
159 throw UnexpectedEventCount();
160 }
161}
162
163static int refArg1;
164static int refArg2;
165static int refArg3;
166static int refArg4;
167static int refArg5;
168static int refArg6;
169
170void Check(
171 sc::fifo_scheduler<> & scheduler,
172 const sc::fifo_scheduler<>::processor_handle & processor,
173 int ctorArgs )
174{
175 refArg1 = 6;
176 refArg2 = 5;
177 refArg3 = 4;
178 refArg4 = 3;
179 refArg5 = 2;
180 refArg6 = 1;
181
182 // Make sure the processor has been created
183 RunScheduler( scheduler, expectedEventCount: 1UL );
184
185 refArg1 = refArg2 = refArg3 = refArg4 = refArg5 = refArg6 = 0;
186
187 scheduler.initiate_processor( processor );
188 // This event triggers the queueing of another event, which itself
189 // terminates the machine ...
190 scheduler.queue_event(
191 processor, pEvent: MakeEvent( pEvent: new EvCheckCtorArgs( ctorArgs ) ) );
192 // ... that's why 3 instead of two events must have been processed
193 RunScheduler( scheduler, expectedEventCount: 3UL );
194
195 // Since the machine has been terminated, this event will be ignored
196 scheduler.queue_event( processor, pEvent: MakeEvent( pEvent: new EvFail() ) );
197 RunScheduler( scheduler, expectedEventCount: 1UL );
198
199 // Check that we can reinitiate the machine
200 scheduler.initiate_processor( processor );
201 scheduler.queue_event(
202 processor, pEvent: MakeEvent( pEvent: new EvCheckCtorArgs( ctorArgs ) ) );
203 RunScheduler( scheduler, expectedEventCount: 3UL );
204
205 // Check that we are terminated again
206 scheduler.queue_event( processor, pEvent: MakeEvent( pEvent: new EvFail() ) );
207 RunScheduler( scheduler, expectedEventCount: 1UL );
208
209 scheduler.destroy_processor( processor );
210 // The following will simply be ignored because the processor has already
211 // be destroyed
212 scheduler.initiate_processor( processor );
213 scheduler.queue_event(
214 processor, pEvent: MakeEvent( pEvent: new EvCheckCtorArgs( ctorArgs ) ) );
215 RunScheduler( scheduler, expectedEventCount: 3UL );
216}
217
218void SetToTrue( bool & value )
219{
220 value = true;
221}
222
223int test_main( int, char* [] )
224{
225 try
226 {
227 sc::fifo_scheduler<> scheduler;
228 Check( scheduler, processor: scheduler.create_processor< FifoSchedulerTest >(), ctorArgs: 0 );
229
230 Check(
231 scheduler, processor: scheduler.create_processor< FifoSchedulerTest >( arg1: 1 ), ctorArgs: 1 );
232
233 Check(
234 scheduler,
235 processor: scheduler.create_processor< FifoSchedulerTest >(
236 arg1: boost::cref( t: refArg1 ) ),
237 ctorArgs: 6 );
238
239 Check(
240 scheduler,
241 processor: scheduler.create_processor< FifoSchedulerTest >( arg1: 1, arg2: 2 ),
242 ctorArgs: 12 );
243
244 Check(
245 scheduler,
246 processor: scheduler.create_processor< FifoSchedulerTest >(
247 arg1: boost::cref( t: refArg1 ), arg2: boost::cref( t: refArg2 ) ),
248 ctorArgs: 65 );
249
250 Check(
251 scheduler,
252 processor: scheduler.create_processor< FifoSchedulerTest >( arg1: 1, arg2: 2, arg3: 3 ),
253 ctorArgs: 123 );
254
255 Check(
256 scheduler,
257 processor: scheduler.create_processor< FifoSchedulerTest >(
258 arg1: boost::cref( t: refArg1 ), arg2: boost::cref( t: refArg2 ),
259 arg3: boost::cref( t: refArg3 ) ),
260 ctorArgs: 654 );
261
262 Check(
263 scheduler,
264 processor: scheduler.create_processor< FifoSchedulerTest >( arg1: 1, arg2: 2, arg3: 3, arg4: 4 ),
265 ctorArgs: 1234 );
266
267 Check(
268 scheduler,
269 processor: scheduler.create_processor< FifoSchedulerTest >(
270 arg1: boost::cref( t: refArg1 ), arg2: boost::cref( t: refArg2 ),
271 arg3: boost::cref( t: refArg3 ), arg4: boost::cref( t: refArg4 ) ),
272 ctorArgs: 6543 );
273
274 Check(
275 scheduler,
276 processor: scheduler.create_processor< FifoSchedulerTest >( arg1: 1, arg2: 2, arg3: 3, arg4: 4, arg5: 5 ),
277 ctorArgs: 12345 );
278
279 Check(
280 scheduler,
281 processor: scheduler.create_processor< FifoSchedulerTest >(
282 arg1: boost::cref( t: refArg1 ), arg2: boost::cref( t: refArg2 ),
283 arg3: boost::cref( t: refArg3 ), arg4: boost::cref( t: refArg4 ),
284 arg5: boost::cref( t: refArg5 ) ),
285 ctorArgs: 65432 );
286
287 Check(
288 scheduler,
289 processor: scheduler.create_processor< FifoSchedulerTest >( arg1: 1, arg2: 2, arg3: 3, arg4: 4, arg5: 5, arg6: 6 ),
290 ctorArgs: 123456 );
291
292 Check(
293 scheduler,
294 processor: scheduler.create_processor< FifoSchedulerTest >(
295 arg1: boost::cref( t: refArg1 ), arg2: boost::cref( t: refArg2 ),
296 arg3: boost::cref( t: refArg3 ), arg4: boost::cref( t: refArg4 ),
297 arg5: boost::cref( t: refArg5 ), arg6: boost::cref( t: refArg6 ) ),
298 ctorArgs: 654321 );
299
300 RunScheduler( scheduler, expectedEventCount: 0UL );
301 bool workItem1Processed = false;
302 scheduler.queue_work_item(
303 item: boost::bind( f: &SetToTrue, a1: boost::ref( t&: workItem1Processed ) ) );
304 RunScheduler( scheduler, expectedEventCount: 1UL );
305 BOOST_REQUIRE( workItem1Processed );
306
307 scheduler.terminate();
308 RunScheduler( scheduler, expectedEventCount: 1UL );
309 BOOST_REQUIRE( scheduler.terminated() );
310
311 RunScheduler( scheduler, expectedEventCount: 0UL );
312 bool workItem2Processed = false;
313 scheduler.queue_work_item(
314 item: boost::bind( f: &SetToTrue, a1: boost::ref( t&: workItem2Processed ) ) );
315 // After being terminated, a call to operator() must not process any more
316 // events
317 RunScheduler( scheduler, expectedEventCount: 0UL );
318 BOOST_REQUIRE( !workItem2Processed );
319 }
320 catch ( const UnexpectedEventCount & )
321 {
322 BOOST_FAIL( "Unexpected event count." );
323 }
324
325 return 0;
326}
327

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