e57bd59f12
[SVN r54717]
327 lines
8.4 KiB
C++
327 lines
8.4 KiB
C++
//////////////////////////////////////////////////////////////////////////////
|
|
// Copyright 2005-2008 Andreas Huber Doenni
|
|
// Distributed under the Boost Software License, Version 1.0. (See accompany-
|
|
// ing file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
#include <boost/test/test_tools.hpp>
|
|
|
|
#include <boost/statechart/asynchronous_state_machine.hpp>
|
|
#include <boost/statechart/fifo_scheduler.hpp>
|
|
#include <boost/statechart/event.hpp>
|
|
#include <boost/statechart/simple_state.hpp>
|
|
#include <boost/statechart/termination.hpp>
|
|
#include <boost/statechart/custom_reaction.hpp>
|
|
|
|
#include <boost/mpl/list.hpp>
|
|
|
|
#include <boost/bind.hpp>
|
|
#include <boost/ref.hpp>
|
|
|
|
#include <stdexcept>
|
|
|
|
|
|
|
|
namespace sc = boost::statechart;
|
|
namespace mpl = boost::mpl;
|
|
|
|
|
|
|
|
struct EvCheckCtorArgs : sc::event< EvCheckCtorArgs >
|
|
{
|
|
public:
|
|
EvCheckCtorArgs( int expectedArgs ) : expectedArgs_( expectedArgs ) {}
|
|
const int expectedArgs_;
|
|
|
|
private:
|
|
// avoids C4512 (assignment operator could not be generated)
|
|
EvCheckCtorArgs & operator=( const EvCheckCtorArgs & );
|
|
};
|
|
|
|
struct EvTerminate : sc::event< EvTerminate > {};
|
|
struct EvFail : sc::event< EvFail > {};
|
|
|
|
|
|
struct Initial;
|
|
struct FifoSchedulerTest :
|
|
sc::asynchronous_state_machine< FifoSchedulerTest, Initial >
|
|
{
|
|
public:
|
|
//////////////////////////////////////////////////////////////////////////
|
|
FifoSchedulerTest( my_context ctx ) :
|
|
my_base( ctx ),
|
|
ctorArgs_( 0 )
|
|
{
|
|
}
|
|
|
|
FifoSchedulerTest( my_context ctx, int arg1 ) :
|
|
my_base( ctx ),
|
|
ctorArgs_( arg1 )
|
|
{
|
|
}
|
|
|
|
FifoSchedulerTest( my_context ctx, int arg1, int arg2 ) :
|
|
my_base( ctx ),
|
|
ctorArgs_( arg1 * 10 + arg2 )
|
|
{
|
|
}
|
|
|
|
FifoSchedulerTest( my_context ctx, int arg1, int arg2, int arg3 ) :
|
|
my_base( ctx ),
|
|
ctorArgs_( ( arg1 * 10 + arg2 ) * 10 + arg3 )
|
|
{
|
|
}
|
|
|
|
FifoSchedulerTest(
|
|
my_context ctx,
|
|
int arg1, int arg2, int arg3, int arg4
|
|
) :
|
|
my_base( ctx ),
|
|
ctorArgs_( ( ( arg1 * 10 + arg2 ) * 10 + arg3 ) * 10 + arg4 )
|
|
{
|
|
}
|
|
|
|
FifoSchedulerTest(
|
|
my_context ctx,
|
|
int arg1, int arg2, int arg3, int arg4, int arg5
|
|
) :
|
|
my_base( ctx ),
|
|
ctorArgs_( ( ( ( arg1 * 10 + arg2 ) * 10 +
|
|
arg3 ) * 10 + arg4 ) * 10 + arg5 )
|
|
{
|
|
}
|
|
|
|
FifoSchedulerTest(
|
|
my_context ctx,
|
|
int arg1, int arg2, int arg3, int arg4, int arg5, int arg6
|
|
) :
|
|
my_base( ctx ),
|
|
ctorArgs_( ( ( ( ( arg1 * 10 + arg2 ) * 10 +
|
|
arg3 ) * 10 + arg4 ) * 10 + arg5 ) * 10 + arg6 )
|
|
{
|
|
}
|
|
|
|
int CtorArgs()
|
|
{
|
|
return ctorArgs_;
|
|
}
|
|
|
|
private:
|
|
//////////////////////////////////////////////////////////////////////////
|
|
const int ctorArgs_;
|
|
};
|
|
|
|
boost::intrusive_ptr< const sc::event_base > MakeEvent(
|
|
const sc::event_base * pEvent )
|
|
{
|
|
return boost::intrusive_ptr< const sc::event_base >( pEvent );
|
|
}
|
|
|
|
struct Initial : sc::simple_state< Initial, FifoSchedulerTest >
|
|
{
|
|
typedef mpl::list<
|
|
sc::custom_reaction< EvCheckCtorArgs >,
|
|
sc::termination< EvTerminate >,
|
|
sc::custom_reaction< EvFail >
|
|
> reactions;
|
|
|
|
sc::result react( const EvCheckCtorArgs & ev )
|
|
{
|
|
BOOST_REQUIRE( ev.expectedArgs_ == outermost_context().CtorArgs() );
|
|
outermost_context_type & machine = outermost_context();
|
|
machine.my_scheduler().queue_event(
|
|
machine.my_handle(), MakeEvent( new EvTerminate() ) );
|
|
return discard_event();
|
|
}
|
|
|
|
sc::result react( const EvFail & )
|
|
{
|
|
BOOST_FAIL( "State machine is unexpectedly still running." );
|
|
return discard_event();
|
|
}
|
|
};
|
|
|
|
|
|
struct UnexpectedEventCount : public std::runtime_error
|
|
{
|
|
UnexpectedEventCount() : std::runtime_error( "" ) {}
|
|
};
|
|
|
|
void RunScheduler(
|
|
sc::fifo_scheduler<> & scheduler, unsigned long expectedEventCount )
|
|
{
|
|
// Workaround: For some reason MSVC has a problem with BOOST_REQUIRE here
|
|
// (C1055: compiler limit: out of keys)
|
|
if ( scheduler() != expectedEventCount )
|
|
{
|
|
throw UnexpectedEventCount();
|
|
}
|
|
}
|
|
|
|
static int refArg1;
|
|
static int refArg2;
|
|
static int refArg3;
|
|
static int refArg4;
|
|
static int refArg5;
|
|
static int refArg6;
|
|
|
|
void Check(
|
|
sc::fifo_scheduler<> & scheduler,
|
|
const sc::fifo_scheduler<>::processor_handle & processor,
|
|
int ctorArgs )
|
|
{
|
|
refArg1 = 6;
|
|
refArg2 = 5;
|
|
refArg3 = 4;
|
|
refArg4 = 3;
|
|
refArg5 = 2;
|
|
refArg6 = 1;
|
|
|
|
// Make sure the processor has been created
|
|
RunScheduler( scheduler, 1UL );
|
|
|
|
refArg1 = refArg2 = refArg3 = refArg4 = refArg5 = refArg6 = 0;
|
|
|
|
scheduler.initiate_processor( processor );
|
|
// This event triggers the queueing of another event, which itself
|
|
// terminates the machine ...
|
|
scheduler.queue_event(
|
|
processor, MakeEvent( new EvCheckCtorArgs( ctorArgs ) ) );
|
|
// ... that's why 3 instead of two events must have been processed
|
|
RunScheduler( scheduler, 3UL );
|
|
|
|
// Since the machine has been terminated, this event will be ignored
|
|
scheduler.queue_event( processor, MakeEvent( new EvFail() ) );
|
|
RunScheduler( scheduler, 1UL );
|
|
|
|
// Check that we can reinitiate the machine
|
|
scheduler.initiate_processor( processor );
|
|
scheduler.queue_event(
|
|
processor, MakeEvent( new EvCheckCtorArgs( ctorArgs ) ) );
|
|
RunScheduler( scheduler, 3UL );
|
|
|
|
// Check that we are terminated again
|
|
scheduler.queue_event( processor, MakeEvent( new EvFail() ) );
|
|
RunScheduler( scheduler, 1UL );
|
|
|
|
scheduler.destroy_processor( processor );
|
|
// The following will simply be ignored because the processor has already
|
|
// be destroyed
|
|
scheduler.initiate_processor( processor );
|
|
scheduler.queue_event(
|
|
processor, MakeEvent( new EvCheckCtorArgs( ctorArgs ) ) );
|
|
RunScheduler( scheduler, 3UL );
|
|
}
|
|
|
|
void SetToTrue( bool & value )
|
|
{
|
|
value = true;
|
|
}
|
|
|
|
int test_main( int, char* [] )
|
|
{
|
|
try
|
|
{
|
|
sc::fifo_scheduler<> scheduler;
|
|
Check( scheduler, scheduler.create_processor< FifoSchedulerTest >(), 0 );
|
|
|
|
Check(
|
|
scheduler, scheduler.create_processor< FifoSchedulerTest >( 1 ), 1 );
|
|
|
|
Check(
|
|
scheduler,
|
|
scheduler.create_processor< FifoSchedulerTest >(
|
|
boost::cref( refArg1 ) ),
|
|
6 );
|
|
|
|
Check(
|
|
scheduler,
|
|
scheduler.create_processor< FifoSchedulerTest >( 1, 2 ),
|
|
12 );
|
|
|
|
Check(
|
|
scheduler,
|
|
scheduler.create_processor< FifoSchedulerTest >(
|
|
boost::cref( refArg1 ), boost::cref( refArg2 ) ),
|
|
65 );
|
|
|
|
Check(
|
|
scheduler,
|
|
scheduler.create_processor< FifoSchedulerTest >( 1, 2, 3 ),
|
|
123 );
|
|
|
|
Check(
|
|
scheduler,
|
|
scheduler.create_processor< FifoSchedulerTest >(
|
|
boost::cref( refArg1 ), boost::cref( refArg2 ),
|
|
boost::cref( refArg3 ) ),
|
|
654 );
|
|
|
|
Check(
|
|
scheduler,
|
|
scheduler.create_processor< FifoSchedulerTest >( 1, 2, 3, 4 ),
|
|
1234 );
|
|
|
|
Check(
|
|
scheduler,
|
|
scheduler.create_processor< FifoSchedulerTest >(
|
|
boost::cref( refArg1 ), boost::cref( refArg2 ),
|
|
boost::cref( refArg3 ), boost::cref( refArg4 ) ),
|
|
6543 );
|
|
|
|
Check(
|
|
scheduler,
|
|
scheduler.create_processor< FifoSchedulerTest >( 1, 2, 3, 4, 5 ),
|
|
12345 );
|
|
|
|
Check(
|
|
scheduler,
|
|
scheduler.create_processor< FifoSchedulerTest >(
|
|
boost::cref( refArg1 ), boost::cref( refArg2 ),
|
|
boost::cref( refArg3 ), boost::cref( refArg4 ),
|
|
boost::cref( refArg5 ) ),
|
|
65432 );
|
|
|
|
Check(
|
|
scheduler,
|
|
scheduler.create_processor< FifoSchedulerTest >( 1, 2, 3, 4, 5, 6 ),
|
|
123456 );
|
|
|
|
Check(
|
|
scheduler,
|
|
scheduler.create_processor< FifoSchedulerTest >(
|
|
boost::cref( refArg1 ), boost::cref( refArg2 ),
|
|
boost::cref( refArg3 ), boost::cref( refArg4 ),
|
|
boost::cref( refArg5 ), boost::cref( refArg6 ) ),
|
|
654321 );
|
|
|
|
RunScheduler( scheduler, 0UL );
|
|
bool workItem1Processed = false;
|
|
scheduler.queue_work_item(
|
|
boost::bind( &SetToTrue, boost::ref( workItem1Processed ) ) );
|
|
RunScheduler( scheduler, 1UL );
|
|
BOOST_REQUIRE( workItem1Processed );
|
|
|
|
scheduler.terminate();
|
|
RunScheduler( scheduler, 1UL );
|
|
BOOST_REQUIRE( scheduler.terminated() );
|
|
|
|
RunScheduler( scheduler, 0UL );
|
|
bool workItem2Processed = false;
|
|
scheduler.queue_work_item(
|
|
boost::bind( &SetToTrue, boost::ref( workItem2Processed ) ) );
|
|
// After being terminated, a call to operator() must not process any more
|
|
// events
|
|
RunScheduler( scheduler, 0UL );
|
|
BOOST_REQUIRE( !workItem2Processed );
|
|
}
|
|
catch ( const UnexpectedEventCount & )
|
|
{
|
|
BOOST_FAIL( "Unexpected event count." );
|
|
}
|
|
|
|
return 0;
|
|
}
|