Blame libs/statechart/test/FifoSchedulerTest.cpp

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