1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132
|
// Copyright 2010 Christophe Henry
// henry UNDERSCORE christophe AT hotmail DOT com
// This is an extended version of the state machine available in the boost::mpl library
// Distributed under the same license as the original.
// Copyright for the original version:
// Copyright 2005 David Abrahams and Aleksey Gurtovoy. Distributed
// under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#include <boost/fusion/adapted/std_tuple.hpp>
#include <boost/fusion/include/std_tuple.hpp>
// back-end
#include "BackCommon.hpp"
//front-end
#include <boost/msm/front/state_machine_def.hpp>
// functors
#include <boost/msm/front/functor_row.hpp>
// for And_ operator
#include <boost/msm/front/operator.hpp>
#ifndef BOOST_MSM_NONSTANDALONE_TEST
#define BOOST_TEST_MODULE kleene_deferred_test
#endif
#include <boost/test/unit_test.hpp>
using namespace std;
namespace msm = boost::msm;
namespace mpl = boost::mpl;
using namespace msm::front;
namespace
{
// events
struct event1 {};
struct event2 {};
// front-end: define the FSM structure
struct fsm_ : public msm::front::state_machine_def<fsm_>
{
// we want deferred events and no state requires deferred events (only the fsm in the
// transition table), so the fsm does.
typedef int activate_deferred_events;
// The list of FSM states
struct StateA : public msm::front::state<>
{
template <class Event,class FSM>
void on_entry(Event const&,FSM& ) {++entry_counter;}
template <class Event,class FSM>
void on_exit(Event const&,FSM& ) {++exit_counter;}
int entry_counter=0;
int exit_counter = 0;
};
struct StateB : public msm::front::state<>
{
template <class Event,class FSM>
void on_entry(Event const&,FSM& ) {++entry_counter;}
template <class Event,class FSM>
void on_exit(Event const&,FSM& ) {++exit_counter;}
int entry_counter = 0;
int exit_counter = 0;
};
// the initial state of the player SM. Must be defined
typedef StateA initial_state;
struct is_event1
{
template <class EVT, class FSM, class SourceState, class TargetState>
bool operator()(EVT const& evt, FSM&, SourceState&, TargetState&)
{
bool is_deferred = boost::any_cast<event1>(&evt) != 0;
return is_deferred;
}
};
typedef fsm_ p; // makes transition table cleaner
// Transition table for player
struct transition_table : boost::fusion::vector<
// Start Event Next Action Guard
// +---------+-------------+---------+---------------------+----------------------+
Row < StateA , event1 , StateB , none , none >,
Row < StateB , boost::any , none , Defer , is_event1 >,
Row < StateB , event2 , StateA , none , none >
// +---------+-------------+---------+---------------------+----------------------+
>/*>::type*/ {};
// Replaces the default no-transition response.
template <class FSM,class Event>
void no_transition(Event const&, FSM&,int)
{
BOOST_FAIL("no_transition called!");
}
};
// Pick a back-end
typedef mpl::vector<
#ifndef BOOST_MSM_TEST_SKIP_BACKMP11
boost::msm::backmp11::state_machine_adapter<fsm_>,
#endif // BOOST_MSM_TEST_SKIP_BACKMP11
boost::msm::back::state_machine<fsm_>,
boost::msm::back11::state_machine<fsm_>
> Fsms;
BOOST_AUTO_TEST_CASE_TEMPLATE(kleene_deferred_test, Fsm, Fsms)
{
Fsm fsm;
fsm.start();
BOOST_CHECK_MESSAGE(fsm.template get_state<fsm_::StateA&>().entry_counter == 1,"StateA entry not called correctly");
fsm.process_event(event1());
BOOST_CHECK_MESSAGE(fsm.current_state()[0] == 1,"StateB should be active");
BOOST_CHECK_MESSAGE(fsm.template get_state<fsm_::StateA&>().exit_counter == 1,"StateA exit not called correctly");
BOOST_CHECK_MESSAGE(fsm.template get_state<fsm_::StateB&>().entry_counter == 1,"StateB entry not called correctly");
fsm.process_event(event1());
BOOST_CHECK_MESSAGE(fsm.current_state()[0] == 1, "StateB should be active");
BOOST_CHECK_MESSAGE(fsm.template get_state<fsm_::StateA&>().exit_counter == 1, "StateA exit not called correctly");
BOOST_CHECK_MESSAGE(fsm.template get_state<fsm_::StateB&>().entry_counter == 1, "StateB entry not called correctly");
fsm.process_event(event2());
BOOST_CHECK_MESSAGE(fsm.current_state()[0] == 1, "StateB should be active");
BOOST_CHECK_MESSAGE(fsm.template get_state<fsm_::StateA&>().exit_counter == 2, "StateA exit not called correctly");
BOOST_CHECK_MESSAGE(fsm.template get_state<fsm_::StateB&>().entry_counter == 2, "StateB entry not called correctly");
}
}
|