// 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 #include // back-end #include "BackCommon.hpp" //front-end #include // functors #include // for And_ operator #include #ifndef BOOST_MSM_NONSTANDALONE_TEST #define BOOST_TEST_MODULE kleene_deferred_test #endif #include 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 { // 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 void on_entry(Event const&,FSM& ) {++entry_counter;} template void on_exit(Event const&,FSM& ) {++exit_counter;} int entry_counter=0; int exit_counter = 0; }; struct StateB : public msm::front::state<> { template void on_entry(Event const&,FSM& ) {++entry_counter;} template 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 bool operator()(EVT const& evt, FSM&, SourceState&, TargetState&) { bool is_deferred = boost::any_cast(&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 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, #endif // BOOST_MSM_TEST_SKIP_BACKMP11 boost::msm::back::state_machine, boost::msm::back11::state_machine > Fsms; BOOST_AUTO_TEST_CASE_TEMPLATE(kleene_deferred_test, Fsm, Fsms) { Fsm fsm; fsm.start(); BOOST_CHECK_MESSAGE(fsm.template get_state().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().exit_counter == 1,"StateA exit not called correctly"); BOOST_CHECK_MESSAGE(fsm.template get_state().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().exit_counter == 1, "StateA exit not called correctly"); BOOST_CHECK_MESSAGE(fsm.template get_state().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().exit_counter == 2, "StateA exit not called correctly"); BOOST_CHECK_MESSAGE(fsm.template get_state().entry_counter == 2, "StateB entry not called correctly"); } }