summaryrefslogtreecommitdiffstats
path: root/src/boost/libs/msm/test
diff options
context:
space:
mode:
Diffstat (limited to 'src/boost/libs/msm/test')
-rw-r--r--src/boost/libs/msm/test/Anonymous.cpp184
-rw-r--r--src/boost/libs/msm/test/AnonymousEuml.cpp167
-rw-r--r--src/boost/libs/msm/test/CompositeEuml.cpp280
-rw-r--r--src/boost/libs/msm/test/CompositeMachine.cpp345
-rw-r--r--src/boost/libs/msm/test/Constructor.cpp210
-rw-r--r--src/boost/libs/msm/test/Entries.cpp297
-rw-r--r--src/boost/libs/msm/test/EventQueue.cpp360
-rw-r--r--src/boost/libs/msm/test/History.cpp356
-rw-r--r--src/boost/libs/msm/test/Jamfile.v250
-rw-r--r--src/boost/libs/msm/test/OrthogonalDeferred.cpp488
-rw-r--r--src/boost/libs/msm/test/OrthogonalDeferred2.cpp495
-rw-r--r--src/boost/libs/msm/test/OrthogonalDeferred3.cpp511
-rw-r--r--src/boost/libs/msm/test/OrthogonalDeferredEuml.cpp359
-rw-r--r--src/boost/libs/msm/test/Serialize.cpp311
-rw-r--r--src/boost/libs/msm/test/SerializeSimpleEuml.cpp216
-rw-r--r--src/boost/libs/msm/test/SerializeWithHistory.cpp367
-rw-r--r--src/boost/libs/msm/test/SimpleEuml.cpp197
-rw-r--r--src/boost/libs/msm/test/SimpleEuml2.cpp197
-rw-r--r--src/boost/libs/msm/test/SimpleInternal.cpp276
-rw-r--r--src/boost/libs/msm/test/SimpleInternalEuml.cpp255
-rw-r--r--src/boost/libs/msm/test/SimpleInternalFunctors.cpp333
-rw-r--r--src/boost/libs/msm/test/SimpleMachine.cpp257
-rw-r--r--src/boost/libs/msm/test/SimpleWithFunctors.cpp361
-rw-r--r--src/boost/libs/msm/test/Test2RegionsAnonymous.cpp172
-rw-r--r--src/boost/libs/msm/test/TestConstructor.cpp269
-rw-r--r--src/boost/libs/msm/test/TestConstructorMovableOnlyTypes.cpp118
-rw-r--r--src/boost/libs/msm/test/TestDeferAndMessageQueue.cpp194
-rw-r--r--src/boost/libs/msm/test/TestDeferAndMessageQueue2.cpp155
-rw-r--r--src/boost/libs/msm/test/TestDeferAndMessageQueue3.cpp158
-rw-r--r--src/boost/libs/msm/test/TestDeferIn2Regions.cpp169
30 files changed, 8107 insertions, 0 deletions
diff --git a/src/boost/libs/msm/test/Anonymous.cpp b/src/boost/libs/msm/test/Anonymous.cpp
new file mode 100644
index 000000000..0055bb5db
--- /dev/null
+++ b/src/boost/libs/msm/test/Anonymous.cpp
@@ -0,0 +1,184 @@
+// 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 <iostream>
+// back-end
+#include <boost/msm/back/state_machine.hpp>
+//front-end
+#include <boost/msm/front/state_machine_def.hpp>
+
+#ifndef BOOST_MSM_NONSTANDALONE_TEST
+#define BOOST_TEST_MODULE MyTest
+#endif
+#include <boost/test/unit_test.hpp>
+
+namespace msm = boost::msm;
+namespace mpl = boost::mpl;
+using namespace boost::msm::front;
+
+namespace
+{
+ // events
+ struct event1 {};
+
+
+ // front-end: define the FSM structure
+ struct my_machine_ : public msm::front::state_machine_def<my_machine_>
+ {
+ unsigned int state2_to_state3_counter;
+ unsigned int state3_to_state4_counter;
+ unsigned int always_true_counter;
+ unsigned int always_false_counter;
+
+ my_machine_():
+ state2_to_state3_counter(0),
+ state3_to_state4_counter(0),
+ always_true_counter(0),
+ always_false_counter(0)
+ {}
+
+ // The list of FSM states
+ struct State1 : 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;
+ int exit_counter;
+ };
+ struct State2 : 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;
+ int exit_counter;
+ };
+
+ struct State3 : 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;
+ int exit_counter;
+ };
+
+ struct State4 : 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;
+ int exit_counter;
+ };
+
+ // the initial state of the player SM. Must be defined
+ typedef State1 initial_state;
+
+ // transition actions
+ void State2ToState3(none const&) { ++state2_to_state3_counter; }
+ void State3ToState4(none const&) { ++state3_to_state4_counter; }
+ // guard conditions
+ bool always_true(none const& )
+ {
+ ++always_true_counter;
+ return true;
+ }
+ bool always_false(none const& )
+ {
+ ++always_false_counter;
+ return false;
+ }
+
+ typedef my_machine_ p; // makes transition table cleaner
+
+ // Transition table for player
+ struct transition_table : mpl::vector<
+ // Start Event Next Action Guard
+ // +---------+-------------+---------+---------------------+----------------------+
+ _row < State1 , none , State2 >,
+ a_row < State2 , none , State3 , &p::State2ToState3 >,
+ // +---------+-------------+---------+---------------------+----------------------+
+ row < State3 , none , State4 , &p::State3ToState4 , &p::always_true >,
+ g_row < State3 , none , State4 , &p::always_false >,
+ _row < State4 , event1 , State1 >
+ // +---------+-------------+---------+---------------------+----------------------+
+ > {};
+ // Replaces the default no-transition response.
+ template <class FSM,class Event>
+ void no_transition(Event const&, FSM&,int)
+ {
+ BOOST_FAIL("no_transition called!");
+ }
+ // init counters
+ template <class Event,class FSM>
+ void on_entry(Event const&,FSM& fsm)
+ {
+ fsm.template get_state<my_machine_::State1&>().entry_counter=0;
+ fsm.template get_state<my_machine_::State1&>().exit_counter=0;
+ fsm.template get_state<my_machine_::State2&>().entry_counter=0;
+ fsm.template get_state<my_machine_::State2&>().exit_counter=0;
+ fsm.template get_state<my_machine_::State3&>().entry_counter=0;
+ fsm.template get_state<my_machine_::State3&>().exit_counter=0;
+ fsm.template get_state<my_machine_::State4&>().entry_counter=0;
+ fsm.template get_state<my_machine_::State4&>().exit_counter=0;
+ }
+ };
+ // Pick a back-end
+ typedef msm::back::state_machine<my_machine_> my_machine;
+
+ //static char const* const state_names[] = { "State1", "State2", "State3", "State4" };
+
+
+ BOOST_AUTO_TEST_CASE( my_test )
+ {
+ my_machine p;
+
+ // needed to start the highest-level SM. This will call on_entry and mark the start of the SM
+ // in this case it will also immediately trigger all anonymous transitions
+ p.start();
+ BOOST_CHECK_MESSAGE(p.current_state()[0] == 3,"State4 should be active"); //State4
+ BOOST_CHECK_MESSAGE(p.get_state<my_machine_::State1&>().exit_counter == 1,"State1 exit not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<my_machine_::State1&>().entry_counter == 1,"State1 entry not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<my_machine_::State2&>().exit_counter == 1,"State2 exit not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<my_machine_::State2&>().entry_counter == 1,"State2 entry not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<my_machine_::State3&>().exit_counter == 1,"State3 exit not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<my_machine_::State3&>().entry_counter == 1,"State3 entry not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<my_machine_::State4&>().entry_counter == 1,"State4 entry not called correctly");
+ BOOST_CHECK_MESSAGE(p.always_true_counter == 1,"guard not called correctly");
+ BOOST_CHECK_MESSAGE(p.always_false_counter == 1,"guard not called correctly");
+ BOOST_CHECK_MESSAGE(p.state2_to_state3_counter == 1,"action not called correctly");
+ BOOST_CHECK_MESSAGE(p.state3_to_state4_counter == 1,"action not called correctly");
+
+
+ // this event will bring us back to the initial state and thus, a new "loop" will be started
+ p.process_event(event1());
+ BOOST_CHECK_MESSAGE(p.current_state()[0] == 3,"State4 should be active"); //State4
+ BOOST_CHECK_MESSAGE(p.get_state<my_machine_::State1&>().exit_counter == 2,"State1 exit not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<my_machine_::State1&>().entry_counter == 2,"State1 entry not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<my_machine_::State2&>().exit_counter == 2,"State2 exit not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<my_machine_::State2&>().entry_counter == 2,"State2 entry not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<my_machine_::State3&>().exit_counter == 2,"State3 exit not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<my_machine_::State3&>().entry_counter == 2,"State3 entry not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<my_machine_::State4&>().entry_counter == 2,"State4 entry not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<my_machine_::State4&>().exit_counter == 1,"State4 exit not called correctly");
+ BOOST_CHECK_MESSAGE(p.always_true_counter == 2,"guard not called correctly");
+ BOOST_CHECK_MESSAGE(p.always_false_counter == 2,"guard not called correctly");
+ BOOST_CHECK_MESSAGE(p.state2_to_state3_counter == 2,"action not called correctly");
+ BOOST_CHECK_MESSAGE(p.state3_to_state4_counter == 2,"action not called correctly");
+
+ }
+}
+
diff --git a/src/boost/libs/msm/test/AnonymousEuml.cpp b/src/boost/libs/msm/test/AnonymousEuml.cpp
new file mode 100644
index 000000000..f4643dd35
--- /dev/null
+++ b/src/boost/libs/msm/test/AnonymousEuml.cpp
@@ -0,0 +1,167 @@
+// 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 <iostream>
+// back-end
+#include <boost/msm/back/state_machine.hpp>
+#include <boost/msm/front/euml/euml.hpp>
+
+#ifndef BOOST_MSM_NONSTANDALONE_TEST
+#define BOOST_TEST_MODULE MyTest
+#endif
+#include <boost/test/unit_test.hpp>
+
+namespace msm = boost::msm;
+using namespace boost::msm::front::euml;
+
+namespace
+{
+ // events
+ BOOST_MSM_EUML_EVENT(event1)
+
+ // The list of FSM states
+ BOOST_MSM_EUML_DECLARE_ATTRIBUTE(unsigned int,entry_counter)
+ BOOST_MSM_EUML_DECLARE_ATTRIBUTE(unsigned int,exit_counter)
+
+ BOOST_MSM_EUML_STATE(( ++state_(entry_counter),++state_(exit_counter),attributes_ << entry_counter << exit_counter),State1)
+ BOOST_MSM_EUML_STATE(( ++state_(entry_counter),++state_(exit_counter),attributes_ << entry_counter << exit_counter),State2)
+ BOOST_MSM_EUML_STATE(( ++state_(entry_counter),++state_(exit_counter),attributes_ << entry_counter << exit_counter),State3)
+ BOOST_MSM_EUML_STATE(( ++state_(entry_counter),++state_(exit_counter),attributes_ << entry_counter << exit_counter),State4)
+
+ BOOST_MSM_EUML_DECLARE_ATTRIBUTE(unsigned int,state2_to_state3_counter)
+ BOOST_MSM_EUML_DECLARE_ATTRIBUTE(unsigned int,state3_to_state4_counter)
+ BOOST_MSM_EUML_DECLARE_ATTRIBUTE(unsigned int,always_true_counter)
+ BOOST_MSM_EUML_DECLARE_ATTRIBUTE(unsigned int,always_false_counter)
+
+ // transition actions
+ BOOST_MSM_EUML_ACTION(State2ToState3)
+ {
+ template <class FSM,class EVT,class SourceState,class TargetState>
+ void operator()(EVT const& ,FSM& fsm,SourceState& ,TargetState& )
+ {
+ ++fsm.get_attribute(state2_to_state3_counter);
+ }
+ };
+ BOOST_MSM_EUML_ACTION(State3ToState4)
+ {
+ template <class FSM,class EVT,class SourceState,class TargetState>
+ void operator()(EVT const& ,FSM& fsm,SourceState& ,TargetState& )
+ {
+ ++fsm.get_attribute(state3_to_state4_counter);
+ }
+ };
+ // guard conditions
+ BOOST_MSM_EUML_ACTION(always_true)
+ {
+ template <class FSM,class EVT,class SourceState,class TargetState>
+ bool operator()(EVT const&,FSM& fsm,SourceState& ,TargetState& )
+ {
+ ++fsm.get_attribute(always_true_counter);
+ return true;
+ }
+ };
+ BOOST_MSM_EUML_ACTION(always_false)
+ {
+ template <class FSM,class EVT,class SourceState,class TargetState>
+ bool operator()(EVT const&,FSM& fsm,SourceState& ,TargetState& )
+ {
+ ++fsm.get_attribute(always_false_counter);
+ return false;
+ }
+ };
+
+ BOOST_MSM_EUML_ACTION(No_Transition)
+ {
+ template <class FSM,class Event>
+ void operator()(Event const&,FSM&,int)
+ {
+ BOOST_FAIL("no_transition called!");
+ }
+ };
+
+ BOOST_MSM_EUML_TRANSITION_TABLE((
+ State2 == State1 ,
+ State3 == State2 / State2ToState3,
+ State4 == State3 [always_true] / State3ToState4,
+ State4 == State3 [always_false],
+ State1 == State4 + event1
+ // +------------------------------------------------------------------------------+
+ ),transition_table)
+
+ // create a state machine "on the fly"
+ BOOST_MSM_EUML_DECLARE_STATE_MACHINE(( transition_table, //STT
+ init_ << State1, // Init State
+ no_action, // Entry
+ no_action, // Exit
+ attributes_ << state2_to_state3_counter << state3_to_state4_counter
+ << always_true_counter << always_false_counter, // Attributes
+ configure_ << no_configure_, // configuration
+ No_Transition // no_transition handler
+ ),
+ my_machine_) //fsm name
+
+ // Pick a back-end
+ typedef msm::back::state_machine<my_machine_> my_machine;
+
+ //static char const* const state_names[] = { "State1", "State2", "State3", "State4" };
+
+ BOOST_AUTO_TEST_CASE( my_test )
+ {
+ my_machine p;
+
+ // needed to start the highest-level SM. This will call on_entry and mark the start of the SM
+ // in this case it will also immediately trigger all anonymous transitions
+ p.start();
+ BOOST_CHECK_MESSAGE(p.current_state()[0] == 3,"State4 should be active"); //State4
+ BOOST_CHECK_MESSAGE(p.get_state<BOOST_MSM_EUML_STATE_NAME(State1)&>().get_attribute(exit_counter) == 1,
+ "State1 exit not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<BOOST_MSM_EUML_STATE_NAME(State1)&>().get_attribute(entry_counter) == 1,
+ "State1 entry not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<BOOST_MSM_EUML_STATE_NAME(State2)&>().get_attribute(exit_counter) == 1,
+ "State2 exit not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<BOOST_MSM_EUML_STATE_NAME(State2)&>().get_attribute(entry_counter) == 1,
+ "State2 entry not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<BOOST_MSM_EUML_STATE_NAME(State3)&>().get_attribute(exit_counter) == 1,
+ "State3 exit not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<BOOST_MSM_EUML_STATE_NAME(State3)&>().get_attribute(entry_counter) == 1,
+ "State3 entry not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<BOOST_MSM_EUML_STATE_NAME(State4)&>().get_attribute(entry_counter)== 1,
+ "State4 entry not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_attribute(always_true_counter) == 1,"guard not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_attribute(always_false_counter) == 1,"guard not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_attribute(state2_to_state3_counter) == 1,"action not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_attribute(state3_to_state4_counter) == 1,"action not called correctly");
+
+
+ // this event will bring us back to the initial state and thus, a new "loop" will be started
+ p.process_event(event1);
+ BOOST_CHECK_MESSAGE(p.current_state()[0] == 3,"State4 should be active"); //State4
+ BOOST_CHECK_MESSAGE(p.get_state<BOOST_MSM_EUML_STATE_NAME(State1)&>().get_attribute(exit_counter) == 2,
+ "State1 exit not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<BOOST_MSM_EUML_STATE_NAME(State1)&>().get_attribute(entry_counter) == 2,
+ "State1 entry not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<BOOST_MSM_EUML_STATE_NAME(State2)&>().get_attribute(exit_counter) == 2,
+ "State2 exit not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<BOOST_MSM_EUML_STATE_NAME(State2)&>().get_attribute(entry_counter) == 2,
+ "State2 entry not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<BOOST_MSM_EUML_STATE_NAME(State3)&>().get_attribute(exit_counter) == 2,
+ "State3 exit not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<BOOST_MSM_EUML_STATE_NAME(State3)&>().get_attribute(entry_counter) == 2,
+ "State3 entry not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<BOOST_MSM_EUML_STATE_NAME(State4)&>().get_attribute(entry_counter)== 2,
+ "State4 entry not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_attribute(always_true_counter) == 2,"guard not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_attribute(always_false_counter) == 2,"guard not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_attribute(state2_to_state3_counter) == 2,"action not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_attribute(state3_to_state4_counter) == 2,"action not called correctly");
+
+ }
+}
+
diff --git a/src/boost/libs/msm/test/CompositeEuml.cpp b/src/boost/libs/msm/test/CompositeEuml.cpp
new file mode 100644
index 000000000..34ada4e95
--- /dev/null
+++ b/src/boost/libs/msm/test/CompositeEuml.cpp
@@ -0,0 +1,280 @@
+// 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 <iostream>
+#include <boost/msm/back/state_machine.hpp>
+#include <boost/msm/front/euml/euml.hpp>
+
+#ifndef BOOST_MSM_NONSTANDALONE_TEST
+#define BOOST_TEST_MODULE MyTest
+#endif
+#include <boost/test/unit_test.hpp>
+
+using namespace std;
+using namespace boost::msm::front::euml;
+namespace msm = boost::msm;
+
+namespace
+{
+ // A "complicated" event type that carries some data.
+ enum DiskTypeEnum
+ {
+ DISK_CD=0,
+ DISK_DVD=1
+ };
+ // events
+ BOOST_MSM_EUML_EVENT(play)
+ BOOST_MSM_EUML_EVENT(end_pause)
+ BOOST_MSM_EUML_EVENT(stop)
+ BOOST_MSM_EUML_EVENT(pause)
+ BOOST_MSM_EUML_EVENT(open_close)
+ BOOST_MSM_EUML_EVENT(next_song)
+ BOOST_MSM_EUML_EVENT(previous_song)
+ BOOST_MSM_EUML_EVENT(region2_evt)
+ // A "complicated" event type that carries some data.
+ BOOST_MSM_EUML_DECLARE_ATTRIBUTE(std::string,cd_name)
+ BOOST_MSM_EUML_DECLARE_ATTRIBUTE(DiskTypeEnum,cd_type)
+ BOOST_MSM_EUML_ATTRIBUTES((attributes_ << cd_name << cd_type ), cd_detected_attributes)
+ BOOST_MSM_EUML_EVENT_WITH_ATTRIBUTES(cd_detected,cd_detected_attributes)
+
+ //states
+ BOOST_MSM_EUML_DECLARE_ATTRIBUTE(unsigned int,entry_counter)
+ BOOST_MSM_EUML_DECLARE_ATTRIBUTE(unsigned int,exit_counter)
+
+ BOOST_MSM_EUML_STATE(( ++state_(entry_counter),++state_(exit_counter),attributes_ << entry_counter << exit_counter),Empty)
+ BOOST_MSM_EUML_STATE(( ++state_(entry_counter),++state_(exit_counter),attributes_ << entry_counter << exit_counter),Open)
+ BOOST_MSM_EUML_STATE(( ++state_(entry_counter),++state_(exit_counter),attributes_ << entry_counter << exit_counter),Stopped)
+ BOOST_MSM_EUML_STATE(( ++state_(entry_counter),++state_(exit_counter),attributes_ << entry_counter << exit_counter),Paused)
+
+ // Playing is now a state machine itself.
+ BOOST_MSM_EUML_DECLARE_ATTRIBUTE(unsigned int,start_next_song_counter)
+ BOOST_MSM_EUML_DECLARE_ATTRIBUTE(unsigned int,start_prev_song_guard_counter)
+ // It has 5 substates
+ BOOST_MSM_EUML_STATE(( ++state_(entry_counter),++state_(exit_counter),attributes_ << entry_counter << exit_counter),Song1)
+ BOOST_MSM_EUML_STATE(( ++state_(entry_counter),++state_(exit_counter),attributes_ << entry_counter << exit_counter),Song2)
+ BOOST_MSM_EUML_STATE(( ++state_(entry_counter),++state_(exit_counter),attributes_ << entry_counter << exit_counter),Song3)
+ BOOST_MSM_EUML_STATE(( ++state_(entry_counter),++state_(exit_counter),attributes_ << entry_counter << exit_counter),Region2State1)
+ BOOST_MSM_EUML_STATE(( ++state_(entry_counter),++state_(exit_counter),attributes_ << entry_counter << exit_counter),Region2State2)
+
+ // Playing has a transition table
+ BOOST_MSM_EUML_TRANSITION_TABLE((
+ // +------------------------------------------------------------------------------+
+ Song2 == Song1 + next_song ,
+ Song1 == Song2 + previous_song [True_()] / ++fsm_(start_prev_song_guard_counter) ,
+ Song3 == Song2 + next_song / ++fsm_(start_next_song_counter) ,
+ Song2 == Song3 + previous_song [True_()] / ++fsm_(start_prev_song_guard_counter) ,
+ Region2State2 == Region2State1 + region2_evt
+ // +------------------------------------------------------------------------------+
+ ),playing_transition_table )
+
+ BOOST_MSM_EUML_DECLARE_STATE_MACHINE( (playing_transition_table, //STT
+ init_ << Song1 << Region2State1, // Init State
+ ++state_(entry_counter), // Entry
+ ++state_(exit_counter), // Exit
+ attributes_ << entry_counter << exit_counter
+ << start_next_song_counter
+ << start_prev_song_guard_counter // Attributes
+ ),Playing_)
+ // choice of back-end
+ typedef msm::back::state_machine<Playing_> Playing_type;
+ Playing_type const Playing;
+
+
+ //fsm
+ BOOST_MSM_EUML_DECLARE_ATTRIBUTE(unsigned int,start_playback_counter)
+ BOOST_MSM_EUML_DECLARE_ATTRIBUTE(unsigned int,can_close_drawer_counter)
+ BOOST_MSM_EUML_DECLARE_ATTRIBUTE(unsigned int,test_fct_counter)
+ BOOST_MSM_EUML_ACTION(No_Transition)
+ {
+ template <class FSM,class Event>
+ void operator()(Event const&,FSM&,int)
+ {
+ BOOST_FAIL("no_transition called!");
+ }
+ };
+ BOOST_MSM_EUML_ACTION(good_disk_format)
+ {
+ template <class FSM,class EVT,class SourceState,class TargetState>
+ bool operator()(EVT const& evt,FSM&,SourceState& ,TargetState& )
+ {
+ if (evt.get_attribute(cd_type)!=DISK_CD)
+ {
+ return false;
+ }
+ return true;
+ }
+ };
+ BOOST_MSM_EUML_TRANSITION_TABLE((
+ Playing == Stopped + play / (++fsm_(start_playback_counter),++fsm_(test_fct_counter) ),
+ Playing == Paused + end_pause ,
+ // +------------------------------------------------------------------------------+
+ Empty == Open + open_close / ++fsm_(can_close_drawer_counter),
+ // +------------------------------------------------------------------------------+
+ Open == Empty + open_close ,
+ Open == Paused + open_close ,
+ Open == Stopped + open_close ,
+ Open == Playing + open_close ,
+ // +------------------------------------------------------------------------------+
+ Paused == Playing + pause ,
+ // +------------------------------------------------------------------------------+
+ Stopped == Playing + stop ,
+ Stopped == Paused + stop ,
+ Stopped == Empty + cd_detected [good_disk_format ||
+ (event_(cd_type)==Int_<DISK_CD>())] / process_(play) ,
+ Stopped == Stopped + stop
+ // +------------------------------------------------------------------------------+
+ ),transition_table)
+
+ BOOST_MSM_EUML_DECLARE_STATE_MACHINE(( transition_table, //STT
+ init_ << Empty, // Init State
+ no_action, // Entry
+ no_action, // Exit
+ attributes_ << start_playback_counter
+ << can_close_drawer_counter << test_fct_counter, // Attributes
+ configure_ << no_configure_, // configuration
+ No_Transition // no_transition handler
+ ),
+ player_) //fsm name
+
+ typedef msm::back::state_machine<player_> player;
+
+// static char const* const state_names[] = { "Stopped", "Paused", "Open", "Empty", "Playing" };
+
+
+ BOOST_AUTO_TEST_CASE( my_test )
+ {
+ player p;
+
+ p.start();
+ BOOST_CHECK_MESSAGE(p.get_state<BOOST_MSM_EUML_STATE_NAME(Empty)&>().get_attribute(entry_counter) == 1,
+ "Empty entry not called correctly");
+
+ p.process_event(open_close());
+ BOOST_CHECK_MESSAGE(p.current_state()[0] == 2,"Open should be active"); //Open
+ BOOST_CHECK_MESSAGE(p.get_state<BOOST_MSM_EUML_STATE_NAME(Empty)&>().get_attribute(exit_counter) == 1,
+ "Empty exit not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<BOOST_MSM_EUML_STATE_NAME(Open)&>().get_attribute(entry_counter) == 1,
+ "Open entry not called correctly");
+
+ p.process_event(open_close());
+ BOOST_CHECK_MESSAGE(p.current_state()[0] == 3,"Empty should be active"); //Empty
+ BOOST_CHECK_MESSAGE(p.get_state<BOOST_MSM_EUML_STATE_NAME(Open)&>().get_attribute(exit_counter) == 1,
+ "Open exit not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<BOOST_MSM_EUML_STATE_NAME(Empty)&>().get_attribute(entry_counter) == 2,
+ "Empty entry not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_attribute(can_close_drawer_counter) == 1,"guard not called correctly");
+
+ p.process_event(
+ cd_detected("louie, louie",DISK_DVD));
+ BOOST_CHECK_MESSAGE(p.current_state()[0] == 3,"Empty should be active"); //Empty
+ BOOST_CHECK_MESSAGE(p.get_state<BOOST_MSM_EUML_STATE_NAME(Open)&>().get_attribute(exit_counter) == 1,
+ "Open exit not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<BOOST_MSM_EUML_STATE_NAME(Empty)&>().get_attribute(entry_counter) == 2,
+ "Empty entry not called correctly");
+
+ p.process_event(
+ cd_detected("louie, louie",DISK_CD));
+ BOOST_CHECK_MESSAGE(p.current_state()[0] == 4,"Playing should be active"); //Playing
+ BOOST_CHECK_MESSAGE(p.get_state<BOOST_MSM_EUML_STATE_NAME(Empty)&>().get_attribute(exit_counter) == 2,
+ "Empty exit not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<BOOST_MSM_EUML_STATE_NAME(Stopped)&>().get_attribute(entry_counter) == 1,
+ "Stopped entry not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<BOOST_MSM_EUML_STATE_NAME(Stopped)&>().get_attribute(exit_counter) == 1,
+ "Stopped exit not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<Playing_type&>().get_attribute(entry_counter) == 1,
+ "Playing entry not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_attribute(start_playback_counter) == 1,"action not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_attribute(test_fct_counter) == 1,"action not called correctly");
+
+ p.process_event(next_song);
+ BOOST_CHECK_MESSAGE(p.current_state()[0] == 4,"Playing should be active"); //Playing
+ BOOST_CHECK_MESSAGE(p.get_state<Playing_type&>().current_state()[0] == 1,"Song2 should be active");
+ BOOST_CHECK_MESSAGE(p.get_state<Playing_type&>().current_state()[1] == 3,"Region2State1 should be active");
+ BOOST_CHECK_MESSAGE(
+ p.get_state<Playing_type&>().get_state<BOOST_MSM_EUML_STATE_NAME(Region2State1)&>().get_attribute(entry_counter) == 1,
+ "Region2State1 entry not called correctly");
+ BOOST_CHECK_MESSAGE(
+ p.get_state<Playing_type&>().get_state<BOOST_MSM_EUML_STATE_NAME(Song2)&>().get_attribute(entry_counter) == 1,
+ "Song2 entry not called correctly");
+ BOOST_CHECK_MESSAGE(
+ p.get_state<Playing_type&>().get_state<BOOST_MSM_EUML_STATE_NAME(Song1)&>().get_attribute(exit_counter) == 1,
+ "Song1 exit not called correctly");
+ BOOST_CHECK_MESSAGE(
+ p.get_state<Playing_type&>().get_attribute(start_next_song_counter) == 0,
+ "submachine action not called correctly");
+
+ p.process_event(next_song);
+ BOOST_CHECK_MESSAGE(p.current_state()[0] == 4,"Playing should be active"); //Playing
+ BOOST_CHECK_MESSAGE(p.get_state<Playing_type&>().current_state()[0] == 2,"Song3 should be active");
+ BOOST_CHECK_MESSAGE(
+ p.get_state<Playing_type&>().get_state<BOOST_MSM_EUML_STATE_NAME(Song3)&>().get_attribute(entry_counter) == 1,
+ "Song3 entry not called correctly");
+ BOOST_CHECK_MESSAGE(
+ p.get_state<Playing_type&>().get_state<BOOST_MSM_EUML_STATE_NAME(Song2)&>().get_attribute(exit_counter) == 1,
+ "Song2 exit not called correctly");
+ BOOST_CHECK_MESSAGE(
+ p.get_state<Playing_type&>().get_attribute(start_next_song_counter) == 1,
+ "submachine action not called correctly");
+
+ p.process_event(previous_song);
+ BOOST_CHECK_MESSAGE(p.current_state()[0] == 4,"Playing should be active"); //Playing
+ BOOST_CHECK_MESSAGE(p.get_state<Playing_type&>().current_state()[0] == 1,"Song2 should be active");
+ BOOST_CHECK_MESSAGE(
+ p.get_state<Playing_type&>().get_state<BOOST_MSM_EUML_STATE_NAME(Song2)&>().get_attribute(entry_counter) == 2,
+ "Song2 entry not called correctly");
+ BOOST_CHECK_MESSAGE(
+ p.get_state<Playing_type&>().get_state<BOOST_MSM_EUML_STATE_NAME(Song3)&>().get_attribute(exit_counter) == 1,
+ "Song3 exit not called correctly");
+ BOOST_CHECK_MESSAGE(
+ p.get_state<Playing_type&>().get_attribute(start_prev_song_guard_counter) == 1,
+ "submachine guard not called correctly");
+ BOOST_CHECK_MESSAGE(
+ p.get_state<Playing_type&>().get_state<BOOST_MSM_EUML_STATE_NAME(Region2State2)&>().get_attribute(entry_counter) == 0,
+ "Region2State2 entry not called correctly");
+
+
+ p.process_event(pause());
+ BOOST_CHECK_MESSAGE(p.current_state()[0] == 1,"Paused should be active"); //Paused
+ BOOST_CHECK_MESSAGE(p.get_state<Playing_type&>().get_attribute(exit_counter) == 1,
+ "Playing exit not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<BOOST_MSM_EUML_STATE_NAME(Paused)&>().get_attribute(entry_counter) == 1,
+ "Paused entry not called correctly");
+
+ // go back to Playing
+ p.process_event(end_pause());
+ BOOST_CHECK_MESSAGE(p.current_state()[0] == 4,"Playing should be active"); //Playing
+ BOOST_CHECK_MESSAGE(p.get_state<BOOST_MSM_EUML_STATE_NAME(Paused)&>().get_attribute(exit_counter) == 1,
+ "Paused exit not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<Playing_type&>().get_attribute(entry_counter) == 2,
+ "Playing entry not called correctly");
+
+ p.process_event(pause());
+ BOOST_CHECK_MESSAGE(p.current_state()[0] == 1,"Paused should be active"); //Paused
+ BOOST_CHECK_MESSAGE(p.get_state<Playing_type&>().get_attribute(exit_counter) == 2,
+ "Playing exit not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<BOOST_MSM_EUML_STATE_NAME(Paused)&>().get_attribute(entry_counter) == 2,
+ "Paused entry not called correctly");
+
+ p.process_event(stop());
+ BOOST_CHECK_MESSAGE(p.current_state()[0] == 0,"Stopped should be active"); //Stopped
+ BOOST_CHECK_MESSAGE(p.get_state<BOOST_MSM_EUML_STATE_NAME(Paused)&>().get_attribute(exit_counter) == 2,
+ "Paused exit not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<BOOST_MSM_EUML_STATE_NAME(Stopped)&>().get_attribute(entry_counter) == 2,
+ "Stopped entry not called correctly");
+
+ p.process_event(stop());
+ BOOST_CHECK_MESSAGE(p.current_state()[0] == 0,"Stopped should be active"); //Stopped
+ BOOST_CHECK_MESSAGE(p.get_state<BOOST_MSM_EUML_STATE_NAME(Stopped)&>().get_attribute(exit_counter) == 2,
+ "Stopped exit not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<BOOST_MSM_EUML_STATE_NAME(Stopped)&>().get_attribute(entry_counter) == 3,
+ "Stopped entry not called correctly");
+ }
+}
+
diff --git a/src/boost/libs/msm/test/CompositeMachine.cpp b/src/boost/libs/msm/test/CompositeMachine.cpp
new file mode 100644
index 000000000..674f316b4
--- /dev/null
+++ b/src/boost/libs/msm/test/CompositeMachine.cpp
@@ -0,0 +1,345 @@
+// 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 <iostream>
+// back-end
+#include <boost/msm/back/state_machine.hpp>
+//front-end
+#include <boost/msm/front/state_machine_def.hpp>
+#ifndef BOOST_MSM_NONSTANDALONE_TEST
+#define BOOST_TEST_MODULE MyTest
+#endif
+#include <boost/test/unit_test.hpp>
+
+namespace msm = boost::msm;
+namespace mpl = boost::mpl;
+
+namespace
+{
+ // events
+ struct play {};
+ struct end_pause {};
+ struct stop {};
+ struct pause {};
+ struct open_close {};
+ struct NextSong {};
+ struct PreviousSong {};
+ struct cd_detected
+ {
+ cd_detected(std::string name)
+ : name(name)
+ {}
+ std::string name;
+ };
+
+ // front-end: define the FSM structure
+ struct player_ : public msm::front::state_machine_def<player_>
+ {
+ unsigned int start_playback_counter;
+ unsigned int can_close_drawer_counter;
+
+ player_():
+ start_playback_counter(0),
+ can_close_drawer_counter(0)
+ {}
+ // The list of FSM states
+ struct Empty : 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;
+ int exit_counter;
+ };
+ struct Open : 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;
+ int exit_counter;
+ };
+
+ // sm_ptr still supported but deprecated as functors are a much better way to do the same thing
+ struct Stopped : 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;
+ int exit_counter;
+ };
+
+ struct Playing_ : public msm::front::state_machine_def<Playing_>
+ {
+ 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;
+ int exit_counter;
+ unsigned int start_next_song_counter;
+ unsigned int start_prev_song_guard_counter;
+
+ Playing_():
+ start_next_song_counter(0),
+ start_prev_song_guard_counter(0)
+ {}
+
+ // The list of FSM states
+ struct Song1 : 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;
+ int exit_counter;
+ };
+ struct Song2 : 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;
+ int exit_counter;
+ };
+ struct Song3 : 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;
+ int exit_counter;
+ };
+ // the initial state. Must be defined
+ typedef Song1 initial_state;
+ // transition actions
+ void start_next_song(NextSong const&) {++start_next_song_counter; }
+ void start_prev_song(PreviousSong const&) { }
+ // guard conditions
+ bool start_prev_song_guard(PreviousSong const&) {++start_prev_song_guard_counter;return true; }
+
+ typedef Playing_ pl; // makes transition table cleaner
+ // Transition table for Playing
+ struct transition_table : mpl::vector4<
+ // Start Event Next Action Guard
+ // +---------+-------------+---------+---------------------+----------------------+
+ _row < Song1 , NextSong , Song2 >,
+ row < Song2 , PreviousSong, Song1 , &pl::start_prev_song,&pl::start_prev_song_guard>,
+ a_row < Song2 , NextSong , Song3 , &pl::start_next_song >,
+ g_row < Song3 , PreviousSong, Song2 ,&pl::start_prev_song_guard>
+ // +---------+-------------+---------+---------------------+----------------------+
+ > {};
+ // Replaces the default no-transition response.
+ template <class FSM,class Event>
+ void no_transition(Event const&, FSM&,int)
+ {
+ BOOST_FAIL("no_transition called!");
+ }
+ };
+ // back-end
+ typedef msm::back::state_machine<Playing_> Playing;
+
+ // state not defining any entry or exit
+ struct Paused : 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;
+ int exit_counter;
+ };
+
+ // the initial state of the player SM. Must be defined
+ typedef Empty initial_state;
+
+ // transition actions
+ void start_playback(play const&) {++start_playback_counter; }
+ void open_drawer(open_close const&) { }
+ void store_cd_info(cd_detected const&) { }
+ void stop_playback(stop const&) { }
+ void pause_playback(pause const&) { }
+ void resume_playback(end_pause const&) { }
+ void stop_and_open(open_close const&) { }
+ void stopped_again(stop const&){}
+ //guards
+ bool can_close_drawer(open_close const&)
+ {
+ ++can_close_drawer_counter;
+ return true;
+ }
+
+
+ typedef player_ p; // makes transition table cleaner
+
+ // Transition table for player
+ struct transition_table : mpl::vector<
+ // Start Event Next Action Guard
+ // +---------+-------------+---------+---------------------+----------------------+
+ a_row < Stopped , play , Playing , &p::start_playback >,
+ a_row < Stopped , open_close , Open , &p::open_drawer >,
+ _row < Stopped , stop , Stopped >,
+ // +---------+-------------+---------+---------------------+----------------------+
+ g_row < Open , open_close , Empty , &p::can_close_drawer >,
+ // +---------+-------------+---------+---------------------+----------------------+
+ a_row < Empty , open_close , Open , &p::open_drawer >,
+ a_row < Empty , cd_detected , Stopped , &p::store_cd_info >,
+ // +---------+-------------+---------+---------------------+----------------------+
+ a_row < Playing , stop , Stopped , &p::stop_playback >,
+ a_row < Playing , pause , Paused , &p::pause_playback >,
+ a_row < Playing , open_close , Open , &p::stop_and_open >,
+ // +---------+-------------+---------+---------------------+----------------------+
+ a_row < Paused , end_pause , Playing , &p::resume_playback >,
+ a_row < Paused , stop , Stopped , &p::stop_playback >,
+ a_row < Paused , open_close , Open , &p::stop_and_open >
+ // +---------+-------------+---------+---------------------+----------------------+
+ > {};
+ // Replaces the default no-transition response.
+ template <class FSM,class Event>
+ void no_transition(Event const&, FSM&,int)
+ {
+ BOOST_FAIL("no_transition called!");
+ }
+ // init counters
+ template <class Event,class FSM>
+ void on_entry(Event const&,FSM& fsm)
+ {
+ fsm.template get_state<player_::Stopped&>().entry_counter=0;
+ fsm.template get_state<player_::Stopped&>().exit_counter=0;
+ fsm.template get_state<player_::Open&>().entry_counter=0;
+ fsm.template get_state<player_::Open&>().exit_counter=0;
+ fsm.template get_state<player_::Empty&>().entry_counter=0;
+ fsm.template get_state<player_::Empty&>().exit_counter=0;
+ fsm.template get_state<player_::Playing&>().entry_counter=0;
+ fsm.template get_state<player_::Playing&>().exit_counter=0;
+ fsm.template get_state<player_::Playing&>().template get_state<player_::Playing::Song1&>().entry_counter=0;
+ fsm.template get_state<player_::Playing&>().template get_state<player_::Playing::Song1&>().exit_counter=0;
+ fsm.template get_state<player_::Playing&>().template get_state<player_::Playing::Song2&>().entry_counter=0;
+ fsm.template get_state<player_::Playing&>().template get_state<player_::Playing::Song2&>().exit_counter=0;
+ fsm.template get_state<player_::Playing&>().template get_state<player_::Playing::Song3&>().entry_counter=0;
+ fsm.template get_state<player_::Playing&>().template get_state<player_::Playing::Song3&>().exit_counter=0;
+ fsm.template get_state<player_::Paused&>().entry_counter=0;
+ fsm.template get_state<player_::Paused&>().exit_counter=0;
+ }
+
+ };
+ // Pick a back-end
+ typedef msm::back::state_machine<player_> player;
+
+// static char const* const state_names[] = { "Stopped", "Open", "Empty", "Playing", "Paused" };
+
+
+ BOOST_AUTO_TEST_CASE( my_test )
+ {
+ player p;
+
+ p.start();
+ BOOST_CHECK_MESSAGE(p.get_state<player_::Empty&>().entry_counter == 1,"Empty entry not called correctly");
+
+ p.process_event(open_close());
+ BOOST_CHECK_MESSAGE(p.current_state()[0] == 1,"Open should be active"); //Open
+ BOOST_CHECK_MESSAGE(p.get_state<player_::Empty&>().exit_counter == 1,"Empty exit not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<player_::Open&>().entry_counter == 1,"Open entry not called correctly");
+
+ p.process_event(open_close());
+ BOOST_CHECK_MESSAGE(p.current_state()[0] == 2,"Empty should be active"); //Empty
+ BOOST_CHECK_MESSAGE(p.get_state<player_::Open&>().exit_counter == 1,"Open exit not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<player_::Empty&>().entry_counter == 2,"Empty entry not called correctly");
+ BOOST_CHECK_MESSAGE(p.can_close_drawer_counter == 1,"guard not called correctly");
+
+ p.process_event(cd_detected("louie, louie"));
+ BOOST_CHECK_MESSAGE(p.current_state()[0] == 0,"Stopped should be active"); //Stopped
+ BOOST_CHECK_MESSAGE(p.get_state<player_::Empty&>().exit_counter == 2,"Empty exit not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<player_::Stopped&>().entry_counter == 1,"Stopped entry not called correctly");
+
+ p.process_event(play());
+ BOOST_CHECK_MESSAGE(p.current_state()[0] == 3,"Playing should be active"); //Playing
+ BOOST_CHECK_MESSAGE(p.get_state<player_::Stopped&>().exit_counter == 1,"Stopped exit not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<player_::Playing&>().entry_counter == 1,"Playing entry not called correctly");
+ BOOST_CHECK_MESSAGE(p.start_playback_counter == 1,"action not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<player_::Playing&>().current_state()[0] == 0,"Song1 should be active");
+ BOOST_CHECK_MESSAGE(
+ p.get_state<player_::Playing&>().get_state<player_::Playing::Song1&>().entry_counter == 1,
+ "Song1 entry not called correctly");
+
+ p.process_event(NextSong());
+ BOOST_CHECK_MESSAGE(p.current_state()[0] == 3,"Playing should be active"); //Playing
+ BOOST_CHECK_MESSAGE(p.get_state<player_::Playing&>().current_state()[0] == 1,"Song2 should be active");
+ BOOST_CHECK_MESSAGE(
+ p.get_state<player_::Playing&>().get_state<player_::Playing::Song2&>().entry_counter == 1,
+ "Song2 entry not called correctly");
+ BOOST_CHECK_MESSAGE(
+ p.get_state<player_::Playing&>().get_state<player_::Playing::Song1&>().exit_counter == 1,
+ "Song1 exit not called correctly");
+ BOOST_CHECK_MESSAGE(
+ p.get_state<player_::Playing&>().start_next_song_counter == 0,
+ "submachine action not called correctly");
+
+ p.process_event(NextSong());
+ BOOST_CHECK_MESSAGE(p.current_state()[0] == 3,"Playing should be active"); //Playing
+ BOOST_CHECK_MESSAGE(p.get_state<player_::Playing&>().current_state()[0] == 2,"Song3 should be active");
+ BOOST_CHECK_MESSAGE(
+ p.get_state<player_::Playing&>().get_state<player_::Playing::Song3&>().entry_counter == 1,
+ "Song3 entry not called correctly");
+ BOOST_CHECK_MESSAGE(
+ p.get_state<player_::Playing&>().get_state<player_::Playing::Song2&>().exit_counter == 1,
+ "Song2 exit not called correctly");
+ BOOST_CHECK_MESSAGE(
+ p.get_state<player_::Playing&>().start_next_song_counter == 1,
+ "submachine action not called correctly");
+
+ p.process_event(PreviousSong());
+ BOOST_CHECK_MESSAGE(p.current_state()[0] == 3,"Playing should be active"); //Playing
+ BOOST_CHECK_MESSAGE(p.get_state<player_::Playing&>().current_state()[0] == 1,"Song2 should be active");
+ BOOST_CHECK_MESSAGE(
+ p.get_state<player_::Playing&>().get_state<player_::Playing::Song2&>().entry_counter == 2,
+ "Song2 entry not called correctly");
+ BOOST_CHECK_MESSAGE(
+ p.get_state<player_::Playing&>().get_state<player_::Playing::Song3&>().exit_counter == 1,
+ "Song3 exit not called correctly");
+ BOOST_CHECK_MESSAGE(
+ p.get_state<player_::Playing&>().start_prev_song_guard_counter == 1,
+ "submachine guard not called correctly");
+
+ p.process_event(pause());
+ BOOST_CHECK_MESSAGE(p.current_state()[0] == 4,"Paused should be active"); //Paused
+ BOOST_CHECK_MESSAGE(p.get_state<player_::Playing&>().exit_counter == 1,"Playing exit not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<player_::Paused&>().entry_counter == 1,"Paused entry not called correctly");
+
+ // go back to Playing
+ p.process_event(end_pause());
+ BOOST_CHECK_MESSAGE(p.current_state()[0] == 3,"Playing should be active"); //Playing
+ BOOST_CHECK_MESSAGE(p.get_state<player_::Paused&>().exit_counter == 1,"Paused exit not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<player_::Playing&>().entry_counter == 2,"Playing entry not called correctly");
+
+ p.process_event(pause());
+ BOOST_CHECK_MESSAGE(p.current_state()[0] == 4,"Paused should be active"); //Paused
+ BOOST_CHECK_MESSAGE(p.get_state<player_::Playing&>().exit_counter == 2,"Playing exit not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<player_::Paused&>().entry_counter == 2,"Paused entry not called correctly");
+
+ p.process_event(stop());
+ BOOST_CHECK_MESSAGE(p.current_state()[0] == 0,"Stopped should be active"); //Stopped
+ BOOST_CHECK_MESSAGE(p.get_state<player_::Paused&>().exit_counter == 2,"Paused exit not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<player_::Stopped&>().entry_counter == 2,"Stopped entry not called correctly");
+
+ p.process_event(stop());
+ BOOST_CHECK_MESSAGE(p.current_state()[0] == 0,"Stopped should be active"); //Stopped
+ BOOST_CHECK_MESSAGE(p.get_state<player_::Stopped&>().exit_counter == 2,"Stopped exit not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<player_::Stopped&>().entry_counter == 3,"Stopped entry not called correctly");
+ }
+}
+
diff --git a/src/boost/libs/msm/test/Constructor.cpp b/src/boost/libs/msm/test/Constructor.cpp
new file mode 100644
index 000000000..86ae978be
--- /dev/null
+++ b/src/boost/libs/msm/test/Constructor.cpp
@@ -0,0 +1,210 @@
+// 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 <iostream>
+// back-end
+#include <boost/msm/back/state_machine.hpp>
+//front-end
+#include <boost/msm/front/state_machine_def.hpp>
+#ifndef BOOST_MSM_NONSTANDALONE_TEST
+#define BOOST_TEST_MODULE MyTest
+#endif
+#include <boost/test/unit_test.hpp>
+
+namespace msm = boost::msm;
+namespace mpl = boost::mpl;
+
+namespace
+{
+ // events
+ struct play {};
+ struct end_pause {};
+ struct stop {};
+ struct pause {};
+ struct open_close {};
+
+ // A "complicated" event type that carries some data.
+ enum DiskTypeEnum
+ {
+ DISK_CD=0,
+ DISK_DVD=1
+ };
+ struct cd_detected
+ {
+ cd_detected(std::string name, DiskTypeEnum diskType)
+ : name(name),
+ disc_type(diskType)
+ {}
+
+ std::string name;
+ DiskTypeEnum disc_type;
+ };
+ struct SomeExternalContext
+ {
+ SomeExternalContext(int b):bla(b){}
+ int bla;
+ };
+ // front-end: define the FSM structure
+ struct player_ : public msm::front::state_machine_def<player_>
+ {
+ player_(SomeExternalContext& context,int someint):
+ context_(context),
+ someint_(someint)
+ {}
+
+ SomeExternalContext& context_;
+ int someint_;
+
+ // The list of FSM states
+ struct Empty : 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;
+ int exit_counter;
+ };
+ struct Open : 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;
+ int exit_counter;
+ };
+
+ // sm_ptr still supported but deprecated as functors are a much better way to do the same thing
+ struct Stopped : 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;
+ int exit_counter;
+ };
+
+ struct Playing : 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;
+ int exit_counter;
+ };
+
+ // state not defining any entry or exit
+ struct Paused : 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;
+ int exit_counter;
+ };
+
+ // the initial state of the player SM. Must be defined
+ typedef Empty initial_state;
+
+ // transition actions
+ void start_playback(play const&) {}
+ void open_drawer(open_close const&) { }
+ void store_cd_info(cd_detected const&) { }
+ void stop_playback(stop const&) { }
+ void pause_playback(pause const&) { }
+ void resume_playback(end_pause const&) { }
+ void stop_and_open(open_close const&) { }
+ void stopped_again(stop const&){}
+ // guard conditions
+ bool good_disk_format(cd_detected const& evt)
+ {
+ // to test a guard condition, let's say we understand only CDs, not DVD
+ if (evt.disc_type != DISK_CD)
+ {
+ return false;
+ }
+ return true;
+ }
+ bool can_close_drawer(open_close const&)
+ {
+ return true;
+ }
+
+ typedef player_ p; // makes transition table cleaner
+
+ // Transition table for player
+ struct transition_table : mpl::vector<
+ // Start Event Next Action Guard
+ // +---------+-------------+---------+---------------------+----------------------+
+ a_row < Stopped , play , Playing , &p::start_playback >,
+ a_row < Stopped , open_close , Open , &p::open_drawer >,
+ _row < Stopped , stop , Stopped >,
+ // +---------+-------------+---------+---------------------+----------------------+
+ g_row < Open , open_close , Empty , &p::can_close_drawer >,
+ // +---------+-------------+---------+---------------------+----------------------+
+ a_row < Empty , open_close , Open , &p::open_drawer >,
+ row < Empty , cd_detected , Stopped , &p::store_cd_info ,&p::good_disk_format >,
+ // +---------+-------------+---------+---------------------+----------------------+
+ a_row < Playing , stop , Stopped , &p::stop_playback >,
+ a_row < Playing , pause , Paused , &p::pause_playback >,
+ a_row < Playing , open_close , Open , &p::stop_and_open >,
+ // +---------+-------------+---------+---------------------+----------------------+
+ a_row < Paused , end_pause , Playing , &p::resume_playback >,
+ a_row < Paused , stop , Stopped , &p::stop_playback >,
+ a_row < Paused , open_close , Open , &p::stop_and_open >
+ // +---------+-------------+---------+---------------------+----------------------+
+ > {};
+ // Replaces the default no-transition response.
+ template <class FSM,class Event>
+ void no_transition(Event const&, FSM&,int)
+ {
+ BOOST_FAIL("no_transition called!");
+ }
+ // init counters
+ template <class Event,class FSM>
+ void on_entry(Event const&,FSM& fsm)
+ {
+ fsm.template get_state<player_::Stopped&>().entry_counter=0;
+ fsm.template get_state<player_::Stopped&>().exit_counter=0;
+ fsm.template get_state<player_::Open&>().entry_counter=0;
+ fsm.template get_state<player_::Open&>().exit_counter=0;
+ fsm.template get_state<player_::Empty&>().entry_counter=0;
+ fsm.template get_state<player_::Empty&>().exit_counter=0;
+ fsm.template get_state<player_::Playing&>().entry_counter=0;
+ fsm.template get_state<player_::Playing&>().exit_counter=0;
+ fsm.template get_state<player_::Paused&>().entry_counter=0;
+ fsm.template get_state<player_::Paused&>().exit_counter=0;
+ fsm.context_ = 20;
+ }
+
+ };
+ // Pick a back-end
+ typedef msm::back::state_machine<player_> player;
+
+// static char const* const state_names[] = { "Stopped", "Open", "Empty", "Playing", "Paused" };
+
+
+ BOOST_AUTO_TEST_CASE( my_test )
+ {
+ SomeExternalContext ctx(3);
+ player p(boost::ref(ctx),5);
+ BOOST_CHECK_MESSAGE(p.context_.bla == 3,"wrong value passed");
+ BOOST_CHECK_MESSAGE(p.someint_ == 5,"wrong value passed");
+ ctx.bla = 10;
+ BOOST_CHECK_MESSAGE(p.context_.bla == 10,"error with reference");
+ p.start();
+ BOOST_CHECK_MESSAGE(p.context_.bla == 20,"error with fsm entry behavior");
+ }
+}
+
diff --git a/src/boost/libs/msm/test/Entries.cpp b/src/boost/libs/msm/test/Entries.cpp
new file mode 100644
index 000000000..7f746d0f8
--- /dev/null
+++ b/src/boost/libs/msm/test/Entries.cpp
@@ -0,0 +1,297 @@
+// 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 <iostream>
+// back-end
+#include <boost/msm/back/state_machine.hpp>
+//front-end
+#include <boost/msm/front/state_machine_def.hpp>
+#ifndef BOOST_MSM_NONSTANDALONE_TEST
+#define BOOST_TEST_MODULE MyTest
+#endif
+#include <boost/test/unit_test.hpp>
+
+namespace msm = boost::msm;
+namespace mpl = boost::mpl;
+
+namespace
+{
+ // events
+ struct event1 {};
+ struct event2 {};
+ struct event3 {};
+ struct event4 {};
+ struct event5 {};
+ struct event6
+ {
+ event6(){}
+ template <class Event>
+ event6(Event const&){}
+ };
+ // front-end: define the FSM structure
+ struct Fsm_ : public msm::front::state_machine_def<Fsm_>
+ {
+ // The list of FSM states
+ struct State1 : 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;
+ int exit_counter;
+ };
+ struct State2 : 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;
+ int exit_counter;
+ };
+ struct SubFsm2_ : public msm::front::state_machine_def<SubFsm2_>
+ {
+ typedef msm::back::state_machine<SubFsm2_> SubFsm2;
+
+ unsigned int entry_action_counter;
+
+ 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;
+ int exit_counter;
+
+ struct SubState1 : 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;
+ int exit_counter;
+ };
+ struct SubState1b : 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;
+ int exit_counter;
+ };
+ struct SubState2 : public msm::front::state<> , public msm::front::explicit_entry<0>
+ {
+ 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;
+ int exit_counter;
+ };
+ struct SubState2b : public msm::front::state<> , public msm::front::explicit_entry<1>
+ {
+ 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;
+ int exit_counter;
+ };
+ // test with a pseudo entry
+ struct PseudoEntry1 : public msm::front::entry_pseudo_state<0>
+ {
+ 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;
+ int exit_counter;
+ };
+ struct SubState3 : 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;
+ int exit_counter;
+ };
+ struct PseudoExit1 : public msm::front::exit_pseudo_state<event6>
+ {
+ 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;
+ int exit_counter;
+ };
+ // action methods
+ void entry_action(event4 const&)
+ {
+ ++entry_action_counter;
+ }
+ // the initial state. Must be defined
+ typedef mpl::vector<SubState1,SubState1b> initial_state;
+
+ typedef mpl::vector<SubState2b> explicit_creation;
+
+ // Transition table for SubFsm2
+ struct transition_table : mpl::vector<
+ // Start Event Next Action Guard
+ // +--------------+-------------+------------+------------------------+----------------------+
+ a_row < PseudoEntry1 , event4 , SubState3 ,&SubFsm2_::entry_action >,
+ _row < SubState2 , event6 , SubState1 >,
+ _row < SubState3 , event5 , PseudoExit1 >
+ // +--------------+-------------+------------+------------------------+----------------------+
+ > {};
+ // Replaces the default no-transition response.
+ template <class FSM,class Event>
+ void no_transition(Event const& , FSM&,int)
+ {
+ BOOST_FAIL("no_transition called!");
+ }
+ };
+ typedef msm::back::state_machine<SubFsm2_> SubFsm2;
+
+ // the initial state of the player SM. Must be defined
+ typedef State1 initial_state;
+
+ // transition actions
+ // guard conditions
+
+ // Transition table for Fsm
+ struct transition_table : mpl::vector<
+ // Start Event Next Action Guard
+ // +---------------------+--------+------------------------------------+-------+--------+
+ _row < State1 , event1 , SubFsm2 >,
+ _row < State1 , event2 , SubFsm2::direct<SubFsm2_::SubState2> >,
+ _row < State1 , event3 , mpl::vector<SubFsm2::direct<SubFsm2_::SubState2>,
+ SubFsm2::direct<SubFsm2_::SubState2b> > >,
+ _row < State1 , event4 , SubFsm2::entry_pt
+ <SubFsm2_::PseudoEntry1> >,
+ // +---------------------+--------+------------------------------------+-------+--------+
+ _row < SubFsm2 , event1 , State1 >,
+ _row < SubFsm2::exit_pt
+ <SubFsm2_::PseudoExit1>, event6 , State2 >
+ // +---------------------+--------+------------------------------------+-------+--------+
+ > {};
+
+ // Replaces the default no-transition response.
+ template <class FSM,class Event>
+ void no_transition(Event const& , FSM&,int )
+ {
+ BOOST_FAIL("no_transition called!");
+ }
+ // init counters
+ template <class Event,class FSM>
+ void on_entry(Event const&,FSM& fsm)
+ {
+ fsm.template get_state<Fsm_::State1&>().entry_counter=0;
+ fsm.template get_state<Fsm_::State1&>().exit_counter=0;
+ fsm.template get_state<Fsm_::State2&>().entry_counter=0;
+ fsm.template get_state<Fsm_::State2&>().exit_counter=0;
+ fsm.template get_state<Fsm_::SubFsm2&>().entry_counter=0;
+ fsm.template get_state<Fsm_::SubFsm2&>().exit_counter=0;
+ fsm.template get_state<Fsm_::SubFsm2&>().entry_action_counter=0;
+ fsm.template get_state<Fsm_::SubFsm2&>().template get_state<Fsm_::SubFsm2::SubState1&>().entry_counter=0;
+ fsm.template get_state<Fsm_::SubFsm2&>().template get_state<Fsm_::SubFsm2::SubState1&>().exit_counter=0;
+ fsm.template get_state<Fsm_::SubFsm2&>().template get_state<Fsm_::SubFsm2::SubState1b&>().entry_counter=0;
+ fsm.template get_state<Fsm_::SubFsm2&>().template get_state<Fsm_::SubFsm2::SubState1b&>().exit_counter=0;
+ fsm.template get_state<Fsm_::SubFsm2&>().template get_state<Fsm_::SubFsm2::SubState2&>().entry_counter=0;
+ fsm.template get_state<Fsm_::SubFsm2&>().template get_state<Fsm_::SubFsm2::SubState2&>().exit_counter=0;
+ fsm.template get_state<Fsm_::SubFsm2&>().template get_state<Fsm_::SubFsm2::SubState2b&>().entry_counter=0;
+ fsm.template get_state<Fsm_::SubFsm2&>().template get_state<Fsm_::SubFsm2::SubState2b&>().exit_counter=0;
+ fsm.template get_state<Fsm_::SubFsm2&>().template get_state<Fsm_::SubFsm2::SubState3&>().entry_counter=0;
+ fsm.template get_state<Fsm_::SubFsm2&>().template get_state<Fsm_::SubFsm2::SubState3&>().exit_counter=0;
+ fsm.template get_state<Fsm_::SubFsm2&>().template get_state<Fsm_::SubFsm2::PseudoEntry1&>().entry_counter=0;
+ fsm.template get_state<Fsm_::SubFsm2&>().template get_state<Fsm_::SubFsm2::PseudoEntry1&>().exit_counter=0;
+ fsm.template get_state<Fsm_::SubFsm2&>().template get_state<Fsm_::SubFsm2::exit_pt<SubFsm2_::PseudoExit1>&>().entry_counter=0;
+ fsm.template get_state<Fsm_::SubFsm2&>().template get_state<Fsm_::SubFsm2::exit_pt<SubFsm2_::PseudoExit1>&>().exit_counter=0;
+
+ }
+ };
+ typedef msm::back::state_machine<Fsm_> Fsm;
+// static char const* const state_names[] = { "State1", "SubFsm2","State2" };
+
+
+ BOOST_AUTO_TEST_CASE( my_test )
+ {
+ Fsm p;
+
+ p.start();
+ BOOST_CHECK_MESSAGE(p.get_state<Fsm_::State1&>().entry_counter == 1,"State1 entry not called correctly");
+
+ p.process_event(event1());
+ p.process_event(event1());
+ BOOST_CHECK_MESSAGE(p.current_state()[0] == 0,"State1 should be active");
+ BOOST_CHECK_MESSAGE(p.get_state<Fsm_::State1&>().exit_counter == 1,"State1 exit not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<Fsm_::State1&>().entry_counter == 2,"State1 entry not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<Fsm_::SubFsm2&>().exit_counter == 1,"SubFsm2 exit not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<Fsm_::SubFsm2&>().entry_counter == 1,"SubFsm2 entry not called correctly");
+
+ p.process_event(event2());
+ p.process_event(event6());
+ p.process_event(event1());
+ BOOST_CHECK_MESSAGE(p.current_state()[0] == 0,"State1 should be active");
+ BOOST_CHECK_MESSAGE(p.get_state<Fsm_::State1&>().exit_counter == 2,"State1 exit not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<Fsm_::State1&>().entry_counter == 3,"State1 entry not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<Fsm_::SubFsm2&>().exit_counter == 2,"SubFsm2 exit not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<Fsm_::SubFsm2&>().entry_counter == 2,"SubFsm2 entry not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<Fsm_::SubFsm2&>().get_state<Fsm_::SubFsm2_::SubState2&>().entry_counter == 1,
+ "SubFsm2::SubState2 entry not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<Fsm_::SubFsm2&>().get_state<Fsm_::SubFsm2_::SubState2&>().exit_counter == 1,
+ "SubFsm2::SubState2 exit not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<Fsm_::SubFsm2&>().get_state<Fsm_::SubFsm2_::SubState1&>().entry_counter == 2,
+ "SubFsm2::SubState1 entry not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<Fsm_::SubFsm2&>().get_state<Fsm_::SubFsm2_::SubState1&>().exit_counter == 2,
+ "SubFsm2::SubState1 exit not called correctly");
+
+ p.process_event(event3());
+ p.process_event(event1());
+ BOOST_CHECK_MESSAGE(p.current_state()[0] == 0,"State1 should be active");
+ BOOST_CHECK_MESSAGE(p.get_state<Fsm_::State1&>().exit_counter == 3,"State1 exit not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<Fsm_::State1&>().entry_counter == 4,"State1 entry not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<Fsm_::SubFsm2&>().exit_counter == 3,"SubFsm2 exit not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<Fsm_::SubFsm2&>().entry_counter == 3,"SubFsm2 entry not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<Fsm_::SubFsm2&>().get_state<Fsm_::SubFsm2_::SubState2&>().entry_counter == 2,
+ "SubFsm2::SubState2 entry not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<Fsm_::SubFsm2&>().get_state<Fsm_::SubFsm2_::SubState2&>().exit_counter == 2,
+ "SubFsm2::SubState2 exit not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<Fsm_::SubFsm2&>().get_state<Fsm_::SubFsm2_::SubState2b&>().entry_counter == 1,
+ "SubFsm2::SubState2b entry not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<Fsm_::SubFsm2&>().get_state<Fsm_::SubFsm2_::SubState2b&>().exit_counter == 1,
+ "SubFsm2::SubState2b exit not called correctly");
+
+ p.process_event(event4());
+ p.process_event(event5());
+ BOOST_CHECK_MESSAGE(p.current_state()[0] == 2,"State2 should be active");
+ BOOST_CHECK_MESSAGE(p.get_state<Fsm_::State1&>().exit_counter == 4,"State1 exit not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<Fsm_::State2&>().entry_counter == 1,"State2 entry not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<Fsm_::SubFsm2&>().exit_counter == 4,"SubFsm2 exit not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<Fsm_::SubFsm2&>().entry_counter == 4,"SubFsm2 entry not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<Fsm_::SubFsm2&>().get_state<Fsm_::SubFsm2_::PseudoEntry1&>().entry_counter == 1,
+ "SubFsm2::PseudoEntry1 entry not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<Fsm_::SubFsm2&>().get_state<Fsm_::SubFsm2_::PseudoEntry1&>().exit_counter == 1,
+ "SubFsm2::PseudoEntry1 exit not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<Fsm_::SubFsm2&>().get_state<Fsm_::SubFsm2_::SubState3&>().entry_counter == 1,
+ "SubFsm2::SubState3 entry not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<Fsm_::SubFsm2&>().get_state<Fsm_::SubFsm2_::SubState3&>().exit_counter == 1,
+ "SubFsm2::SubState3 exit not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<Fsm_::SubFsm2&>().get_state<Fsm_::SubFsm2::exit_pt<Fsm_::SubFsm2_::PseudoExit1>&>().entry_counter == 1,
+ "SubFsm2::PseudoExit1 entry not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<Fsm_::SubFsm2&>().get_state<Fsm_::SubFsm2::exit_pt<Fsm_::SubFsm2_::PseudoExit1>&>().exit_counter == 1,
+ "SubFsm2::PseudoExit1 exit not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<Fsm_::SubFsm2&>().entry_action_counter == 1,"Action not called correctly");
+
+ }
+}
+
diff --git a/src/boost/libs/msm/test/EventQueue.cpp b/src/boost/libs/msm/test/EventQueue.cpp
new file mode 100644
index 000000000..a9e451b7e
--- /dev/null
+++ b/src/boost/libs/msm/test/EventQueue.cpp
@@ -0,0 +1,360 @@
+// 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 <iostream>
+// back-end
+#include <boost/msm/back/state_machine.hpp>
+//front-end
+#include <boost/msm/front/state_machine_def.hpp>
+// functors
+#include <boost/msm/front/functor_row.hpp>
+#include <boost/msm/front/euml/common.hpp>
+// for And_ operator
+#include <boost/msm/front/euml/operator.hpp>
+
+#ifndef BOOST_MSM_NONSTANDALONE_TEST
+#define BOOST_TEST_MODULE MyTest
+#endif
+#include <boost/test/unit_test.hpp>
+
+using namespace std;
+namespace msm = boost::msm;
+namespace mpl = boost::mpl;
+using namespace msm::front;
+// for And_ operator
+using namespace msm::front::euml;
+
+namespace
+{
+ // events
+ struct play {};
+ struct end_pause {};
+ struct stop {};
+ struct pause {};
+ struct open_close {};
+
+ // A "complicated" event type that carries some data.
+ enum DiskTypeEnum
+ {
+ DISK_CD=0,
+ DISK_DVD=1
+ };
+ struct cd_detected
+ {
+ cd_detected(std::string name, DiskTypeEnum diskType)
+ : name(name),
+ disc_type(diskType)
+ {}
+
+ std::string name;
+ DiskTypeEnum disc_type;
+ };
+
+ // front-end: define the FSM structure
+ struct player_ : public msm::front::state_machine_def<player_>
+ {
+ unsigned int start_playback_counter;
+ unsigned int can_close_drawer_counter;
+ unsigned int test_fct_counter;
+
+ player_():
+ start_playback_counter(0),
+ can_close_drawer_counter(0),
+ test_fct_counter(0)
+ {}
+
+ // The list of FSM states
+ struct Empty : 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;
+ int exit_counter;
+ };
+ struct Open : 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;
+ int exit_counter;
+ };
+
+ // sm_ptr still supported but deprecated as functors are a much better way to do the same thing
+ struct Stopped : 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;
+ int exit_counter;
+ };
+
+ struct Playing : 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;
+ int exit_counter;
+ };
+
+ // state not defining any entry or exit
+ struct Paused : 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;
+ int exit_counter;
+ };
+
+ // the initial state of the player SM. Must be defined
+ typedef Empty initial_state;
+
+ // transition actions
+ struct TestFct
+ {
+ template <class EVT,class FSM,class SourceState,class TargetState>
+ void operator()(EVT const&, FSM& fsm,SourceState& ,TargetState& )
+ {
+ ++fsm.test_fct_counter;
+ }
+ };
+ struct start_playback
+ {
+ template <class EVT,class FSM,class SourceState,class TargetState>
+ void operator()(EVT const& ,FSM& fsm,SourceState& ,TargetState& )
+ {
+ ++fsm.start_playback_counter;
+ }
+ };
+ struct open_drawer
+ {
+ template <class EVT,class FSM,class SourceState,class TargetState>
+ void operator()(EVT const& ,FSM& ,SourceState& ,TargetState& )
+ {
+ }
+ };
+ struct close_drawer
+ {
+ template <class EVT,class FSM,class SourceState,class TargetState>
+ void operator()(EVT const& ,FSM& ,SourceState& ,TargetState& )
+ {
+ }
+ };
+ struct store_cd_info
+ {
+ template <class EVT,class FSM,class SourceState,class TargetState>
+ void operator()(EVT const&,FSM& fsm ,SourceState& ,TargetState& )
+ {
+ fsm.process_event(play());
+ }
+ };
+ struct stop_playback
+ {
+ template <class EVT,class FSM,class SourceState,class TargetState>
+ void operator()(EVT const& ,FSM& ,SourceState& ,TargetState& )
+ {
+ }
+ };
+ struct pause_playback
+ {
+ template <class EVT,class FSM,class SourceState,class TargetState>
+ void operator()(EVT const& ,FSM& ,SourceState& ,TargetState& )
+ {
+ }
+ };
+ struct resume_playback
+ {
+ template <class EVT,class FSM,class SourceState,class TargetState>
+ void operator()(EVT const& ,FSM& ,SourceState& ,TargetState& )
+ {
+ }
+ };
+ struct stop_and_open
+ {
+ template <class EVT,class FSM,class SourceState,class TargetState>
+ void operator()(EVT const& ,FSM& ,SourceState& ,TargetState& )
+ {
+ }
+ };
+ struct stopped_again
+ {
+ template <class EVT,class FSM,class SourceState,class TargetState>
+ void operator()(EVT const& ,FSM& ,SourceState& ,TargetState& )
+ {
+ }
+ };
+ // guard conditions
+ struct DummyGuard
+ {
+ template <class EVT,class FSM,class SourceState,class TargetState>
+ bool operator()(EVT const& ,FSM& ,SourceState& ,TargetState& )
+ {
+ return true;
+ }
+ };
+ struct good_disk_format
+ {
+ template <class EVT,class FSM,class SourceState,class TargetState>
+ bool operator()(EVT const& evt ,FSM&,SourceState& ,TargetState& )
+ {
+ // to test a guard condition, let's say we understand only CDs, not DVD
+ if (evt.disc_type != DISK_CD)
+ {
+ return false;
+ }
+ return true;
+ }
+ };
+ struct always_true
+ {
+ template <class EVT,class FSM,class SourceState,class TargetState>
+ bool operator()(EVT const& ,FSM&,SourceState& ,TargetState& )
+ {
+ return true;
+ }
+ };
+ struct can_close_drawer
+ {
+ template <class EVT,class FSM,class SourceState,class TargetState>
+ bool operator()(EVT const& ,FSM& fsm,SourceState& ,TargetState& )
+ {
+ ++fsm.can_close_drawer_counter;
+ return true;
+ }
+ };
+
+ typedef player_ p; // makes transition table cleaner
+
+ // Transition table for player
+ struct transition_table : mpl::vector<
+ // Start Event Next Action Guard
+ // +---------+-------------+---------+---------------------+----------------------+
+ Row < Stopped , play , Playing , ActionSequence_
+ <mpl::vector<
+ TestFct,start_playback> >
+ , DummyGuard >,
+ Row < Stopped , open_close , Open , open_drawer , none >,
+ Row < Stopped , stop , Stopped , none , none >,
+ // +---------+-------------+---------+---------------------------+----------------------+
+ Row < Open , open_close , Empty , close_drawer , can_close_drawer >,
+ // +---------+-------------+---------+---------------------------+----------------------+
+ Row < Empty , open_close , Open , open_drawer , none >,
+ Row < Empty , cd_detected , Stopped , store_cd_info , And_<good_disk_format,
+ always_true> >,
+ // +---------+-------------+---------+---------------------------+----------------------+
+ Row < Playing , stop , Stopped , stop_playback , none >,
+ Row < Playing , pause , Paused , pause_playback , none >,
+ Row < Playing , open_close , Open , stop_and_open , none >,
+ // +---------+-------------+---------+---------------------------+----------------------+
+ Row < Paused , end_pause , Playing , resume_playback , none >,
+ Row < Paused , stop , Stopped , stop_playback , none >,
+ Row < Paused , open_close , Open , stop_and_open , none >
+
+ // +---------+-------------+---------+---------------------+----------------------+
+ > {};
+ // Replaces the default no-transition response.
+ template <class FSM,class Event>
+ void no_transition(Event const&, FSM&,int)
+ {
+ BOOST_FAIL("no_transition called!");
+ }
+ // init counters
+ template <class Event,class FSM>
+ void on_entry(Event const&,FSM& fsm)
+ {
+ fsm.template get_state<player_::Stopped&>().entry_counter=0;
+ fsm.template get_state<player_::Stopped&>().exit_counter=0;
+ fsm.template get_state<player_::Open&>().entry_counter=0;
+ fsm.template get_state<player_::Open&>().exit_counter=0;
+ fsm.template get_state<player_::Empty&>().entry_counter=0;
+ fsm.template get_state<player_::Empty&>().exit_counter=0;
+ fsm.template get_state<player_::Playing&>().entry_counter=0;
+ fsm.template get_state<player_::Playing&>().exit_counter=0;
+ fsm.template get_state<player_::Paused&>().entry_counter=0;
+ fsm.template get_state<player_::Paused&>().exit_counter=0;
+ }
+
+ };
+ // Pick a back-end
+ typedef msm::back::state_machine<player_> player;
+
+// static char const* const state_names[] = { "Stopped", "Open", "Empty", "Playing", "Paused" };
+
+
+ BOOST_AUTO_TEST_CASE( test_event_queue )
+ {
+ player p;
+
+ p.start();
+ BOOST_CHECK_MESSAGE(p.get_state<player_::Empty&>().entry_counter == 1,"Empty entry not called correctly");
+
+ p.enqueue_event(open_close());
+ p.execute_single_queued_event();
+ BOOST_CHECK_MESSAGE(p.current_state()[0] == 1,"Open should be active"); //Open
+ BOOST_CHECK_MESSAGE(p.get_state<player_::Empty&>().exit_counter == 1,"Empty exit not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<player_::Open&>().entry_counter == 1,"Open entry not called correctly");
+
+ p.enqueue_event(open_close());
+ p.enqueue_event(
+ cd_detected("louie, louie",DISK_DVD));
+ p.enqueue_event(
+ cd_detected("louie, louie",DISK_CD));
+ p.execute_queued_events();
+
+ BOOST_CHECK_MESSAGE(p.can_close_drawer_counter == 1,"guard not called correctly");
+
+ BOOST_CHECK_MESSAGE(p.get_state<player_::Open&>().exit_counter == 1,"Open exit not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<player_::Empty&>().entry_counter == 2,"Empty entry not called correctly");
+
+ BOOST_CHECK_MESSAGE(p.current_state()[0] == 3,"Playing should be active"); //Playing
+ BOOST_CHECK_MESSAGE(p.get_state<player_::Empty&>().exit_counter == 2,"Empty exit not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<player_::Stopped&>().entry_counter == 1,"Stopped entry not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<player_::Stopped&>().exit_counter == 1,"Stopped exit not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<player_::Playing&>().entry_counter == 1,"Playing entry not called correctly");
+ BOOST_CHECK_MESSAGE(p.start_playback_counter == 1,"action not called correctly");
+ BOOST_CHECK_MESSAGE(p.test_fct_counter == 1,"action not called correctly");
+
+ p.process_event(pause());
+ BOOST_CHECK_MESSAGE(p.current_state()[0] == 4,"Paused should be active"); //Paused
+ BOOST_CHECK_MESSAGE(p.get_state<player_::Playing&>().exit_counter == 1,"Playing exit not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<player_::Paused&>().entry_counter == 1,"Paused entry not called correctly");
+
+ // go back to Playing
+ p.enqueue_event(end_pause());
+ p.execute_queued_events();
+ BOOST_CHECK_MESSAGE(p.current_state()[0] == 3,"Playing should be active"); //Playing
+ BOOST_CHECK_MESSAGE(p.get_state<player_::Paused&>().exit_counter == 1,"Paused exit not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<player_::Playing&>().entry_counter == 2,"Playing entry not called correctly");
+
+ p.enqueue_event(pause());
+ p.enqueue_event(stop());
+ p.enqueue_event(stop());
+ p.execute_queued_events();
+
+ BOOST_CHECK_MESSAGE(p.get_state<player_::Playing&>().exit_counter == 2,"Playing exit not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<player_::Paused&>().entry_counter == 2,"Paused entry not called correctly");
+
+ BOOST_CHECK_MESSAGE(p.get_state<player_::Paused&>().exit_counter == 2,"Paused exit not called correctly");
+
+ BOOST_CHECK_MESSAGE(p.current_state()[0] == 0,"Stopped should be active"); //Stopped
+ BOOST_CHECK_MESSAGE(p.get_state<player_::Stopped&>().exit_counter == 2,"Stopped exit not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<player_::Stopped&>().entry_counter == 3,"Stopped entry not called correctly");
+ }
+}
+
diff --git a/src/boost/libs/msm/test/History.cpp b/src/boost/libs/msm/test/History.cpp
new file mode 100644
index 000000000..b12890706
--- /dev/null
+++ b/src/boost/libs/msm/test/History.cpp
@@ -0,0 +1,356 @@
+// 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 <iostream>
+// back-end
+#include <boost/msm/back/state_machine.hpp>
+//front-end
+#include <boost/msm/front/state_machine_def.hpp>
+#ifndef BOOST_MSM_NONSTANDALONE_TEST
+#define BOOST_TEST_MODULE MyTest
+#endif
+#include <boost/test/unit_test.hpp>
+
+namespace msm = boost::msm;
+namespace mpl = boost::mpl;
+
+namespace
+{
+ // events
+ struct play {};
+ struct end_pause {};
+ struct stop {};
+ struct pause {};
+ struct open_close {};
+ struct NextSong {};
+ struct PreviousSong {};
+ struct cd_detected
+ {
+ cd_detected(std::string name)
+ : name(name)
+ {}
+ std::string name;
+ };
+
+ // front-end: define the FSM structure
+ struct player_ : public msm::front::state_machine_def<player_>
+ {
+ unsigned int start_playback_counter;
+ unsigned int can_close_drawer_counter;
+
+ player_():
+ start_playback_counter(0),
+ can_close_drawer_counter(0)
+ {}
+ // The list of FSM states
+ struct Empty : 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;
+ int exit_counter;
+ };
+ struct Open : 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;
+ int exit_counter;
+ };
+
+ // sm_ptr still supported but deprecated as functors are a much better way to do the same thing
+ struct Stopped : 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;
+ int exit_counter;
+ };
+
+ struct Playing_ : public msm::front::state_machine_def<Playing_>
+ {
+ 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;
+ int exit_counter;
+ unsigned int start_next_song_counter;
+ unsigned int start_prev_song_guard_counter;
+
+ Playing_():
+ start_next_song_counter(0),
+ start_prev_song_guard_counter(0)
+ {}
+
+ // The list of FSM states
+ struct Song1 : 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;
+ int exit_counter;
+ };
+ struct Song2 : 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;
+ int exit_counter;
+ };
+ struct Song3 : 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;
+ int exit_counter;
+ };
+ // the initial state. Must be defined
+ typedef Song1 initial_state;
+ // transition actions
+ void start_next_song(NextSong const&) {++start_next_song_counter; }
+ void start_prev_song(PreviousSong const&) { }
+ // guard conditions
+ bool start_prev_song_guard(PreviousSong const&) {++start_prev_song_guard_counter;return true; }
+
+ typedef Playing_ pl; // makes transition table cleaner
+ // Transition table for Playing
+ struct transition_table : mpl::vector4<
+ // Start Event Next Action Guard
+ // +---------+-------------+---------+---------------------+----------------------+
+ _row < Song1 , NextSong , Song2 >,
+ row < Song2 , PreviousSong, Song1 , &pl::start_prev_song,&pl::start_prev_song_guard>,
+ a_row < Song2 , NextSong , Song3 , &pl::start_next_song >,
+ g_row < Song3 , PreviousSong, Song2 ,&pl::start_prev_song_guard>
+ // +---------+-------------+---------+---------------------+----------------------+
+ > {};
+ // Replaces the default no-transition response.
+ template <class FSM,class Event>
+ void no_transition(Event const&, FSM&,int)
+ {
+ BOOST_FAIL("no_transition called!");
+ }
+ };
+ // back-end
+ typedef msm::back::state_machine<Playing_,msm::back::ShallowHistory<mpl::vector<end_pause> > > Playing;
+
+ // state not defining any entry or exit
+ struct Paused : 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;
+ int exit_counter;
+ };
+
+ // the initial state of the player SM. Must be defined
+ typedef Empty initial_state;
+
+ // transition actions
+ void start_playback(play const&) {++start_playback_counter; }
+ void open_drawer(open_close const&) { }
+ void store_cd_info(cd_detected const&) { }
+ void stop_playback(stop const&) { }
+ void pause_playback(pause const&) { }
+ void resume_playback(end_pause const&) { }
+ void stop_and_open(open_close const&) { }
+ void stopped_again(stop const&){}
+ //guards
+ bool can_close_drawer(open_close const&)
+ {
+ ++can_close_drawer_counter;
+ return true;
+ }
+
+
+ typedef player_ p; // makes transition table cleaner
+
+ // Transition table for player
+ struct transition_table : mpl::vector<
+ // Start Event Next Action Guard
+ // +---------+-------------+---------+---------------------+----------------------+
+ a_row < Stopped , play , Playing , &p::start_playback >,
+ a_row < Stopped , open_close , Open , &p::open_drawer >,
+ _row < Stopped , stop , Stopped >,
+ // +---------+-------------+---------+---------------------+----------------------+
+ g_row < Open , open_close , Empty , &p::can_close_drawer >,
+ // +---------+-------------+---------+---------------------+----------------------+
+ a_row < Empty , open_close , Open , &p::open_drawer >,
+ a_row < Empty , cd_detected , Stopped , &p::store_cd_info >,
+ // +---------+-------------+---------+---------------------+----------------------+
+ a_row < Playing , stop , Stopped , &p::stop_playback >,
+ a_row < Playing , pause , Paused , &p::pause_playback >,
+ a_row < Playing , open_close , Open , &p::stop_and_open >,
+ // +---------+-------------+---------+---------------------+----------------------+
+ a_row < Paused , end_pause , Playing , &p::resume_playback >,
+ a_row < Paused , stop , Stopped , &p::stop_playback >,
+ a_row < Paused , open_close , Open , &p::stop_and_open >
+ // +---------+-------------+---------+---------------------+----------------------+
+ > {};
+ // Replaces the default no-transition response.
+ template <class FSM,class Event>
+ void no_transition(Event const& , FSM&,int )
+ {
+ BOOST_FAIL("no_transition called!");
+ }
+ // init counters
+ template <class Event,class FSM>
+ void on_entry(Event const&,FSM& fsm)
+ {
+ fsm.template get_state<player_::Stopped&>().entry_counter=0;
+ fsm.template get_state<player_::Stopped&>().exit_counter=0;
+ fsm.template get_state<player_::Open&>().entry_counter=0;
+ fsm.template get_state<player_::Open&>().exit_counter=0;
+ fsm.template get_state<player_::Empty&>().entry_counter=0;
+ fsm.template get_state<player_::Empty&>().exit_counter=0;
+ fsm.template get_state<player_::Playing&>().entry_counter=0;
+ fsm.template get_state<player_::Playing&>().exit_counter=0;
+ fsm.template get_state<player_::Playing&>().template get_state<player_::Playing::Song1&>().entry_counter=0;
+ fsm.template get_state<player_::Playing&>().template get_state<player_::Playing::Song1&>().exit_counter=0;
+ fsm.template get_state<player_::Playing&>().template get_state<player_::Playing::Song2&>().entry_counter=0;
+ fsm.template get_state<player_::Playing&>().template get_state<player_::Playing::Song2&>().exit_counter=0;
+ fsm.template get_state<player_::Playing&>().template get_state<player_::Playing::Song3&>().entry_counter=0;
+ fsm.template get_state<player_::Playing&>().template get_state<player_::Playing::Song3&>().exit_counter=0;
+ fsm.template get_state<player_::Paused&>().entry_counter=0;
+ fsm.template get_state<player_::Paused&>().exit_counter=0;
+ }
+
+ };
+ // Pick a back-end
+ typedef msm::back::state_machine<player_> player;
+
+// static char const* const state_names[] = { "Stopped", "Open", "Empty", "Playing", "Paused" };
+
+
+ BOOST_AUTO_TEST_CASE( my_test )
+ {
+ player p;
+
+ p.start();
+ BOOST_CHECK_MESSAGE(p.get_state<player_::Empty&>().entry_counter == 1,"Empty entry not called correctly");
+
+ p.process_event(open_close());
+ BOOST_CHECK_MESSAGE(p.current_state()[0] == 1,"Open should be active"); //Open
+ BOOST_CHECK_MESSAGE(p.get_state<player_::Empty&>().exit_counter == 1,"Empty exit not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<player_::Open&>().entry_counter == 1,"Open entry not called correctly");
+
+ p.process_event(open_close());
+ BOOST_CHECK_MESSAGE(p.current_state()[0] == 2,"Empty should be active"); //Empty
+ BOOST_CHECK_MESSAGE(p.get_state<player_::Open&>().exit_counter == 1,"Open exit not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<player_::Empty&>().entry_counter == 2,"Empty entry not called correctly");
+ BOOST_CHECK_MESSAGE(p.can_close_drawer_counter == 1,"guard not called correctly");
+
+ p.process_event(cd_detected("louie, louie"));
+ BOOST_CHECK_MESSAGE(p.current_state()[0] == 0,"Stopped should be active"); //Stopped
+ BOOST_CHECK_MESSAGE(p.get_state<player_::Empty&>().exit_counter == 2,"Empty exit not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<player_::Stopped&>().entry_counter == 1,"Stopped entry not called correctly");
+
+ p.process_event(play());
+ BOOST_CHECK_MESSAGE(p.current_state()[0] == 3,"Playing should be active"); //Playing
+ BOOST_CHECK_MESSAGE(p.get_state<player_::Stopped&>().exit_counter == 1,"Stopped exit not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<player_::Playing&>().entry_counter == 1,"Playing entry not called correctly");
+ BOOST_CHECK_MESSAGE(p.start_playback_counter == 1,"action not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<player_::Playing&>().current_state()[0] == 0,"Song1 should be active");
+ BOOST_CHECK_MESSAGE(
+ p.get_state<player_::Playing&>().get_state<player_::Playing::Song1&>().entry_counter == 1,
+ "Song1 entry not called correctly");
+
+ p.process_event(NextSong());
+ BOOST_CHECK_MESSAGE(p.current_state()[0] == 3,"Playing should be active"); //Playing
+ BOOST_CHECK_MESSAGE(p.get_state<player_::Playing&>().current_state()[0] == 1,"Song2 should be active");
+ BOOST_CHECK_MESSAGE(
+ p.get_state<player_::Playing&>().get_state<player_::Playing::Song2&>().entry_counter == 1,
+ "Song2 entry not called correctly");
+ BOOST_CHECK_MESSAGE(
+ p.get_state<player_::Playing&>().get_state<player_::Playing::Song1&>().exit_counter == 1,
+ "Song1 exit not called correctly");
+ BOOST_CHECK_MESSAGE(
+ p.get_state<player_::Playing&>().start_next_song_counter == 0,
+ "submachine action not called correctly");
+
+ p.process_event(NextSong());
+ BOOST_CHECK_MESSAGE(p.current_state()[0] == 3,"Playing should be active"); //Playing
+ BOOST_CHECK_MESSAGE(p.get_state<player_::Playing&>().current_state()[0] == 2,"Song3 should be active");
+ BOOST_CHECK_MESSAGE(
+ p.get_state<player_::Playing&>().get_state<player_::Playing::Song3&>().entry_counter == 1,
+ "Song3 entry not called correctly");
+ BOOST_CHECK_MESSAGE(
+ p.get_state<player_::Playing&>().get_state<player_::Playing::Song2&>().exit_counter == 1,
+ "Song2 exit not called correctly");
+ BOOST_CHECK_MESSAGE(
+ p.get_state<player_::Playing&>().start_next_song_counter == 1,
+ "submachine action not called correctly");
+
+ p.process_event(PreviousSong());
+ BOOST_CHECK_MESSAGE(p.current_state()[0] == 3,"Playing should be active"); //Playing
+ BOOST_CHECK_MESSAGE(p.get_state<player_::Playing&>().current_state()[0] == 1,"Song2 should be active");
+ BOOST_CHECK_MESSAGE(
+ p.get_state<player_::Playing&>().get_state<player_::Playing::Song2&>().entry_counter == 2,
+ "Song2 entry not called correctly");
+ BOOST_CHECK_MESSAGE(
+ p.get_state<player_::Playing&>().get_state<player_::Playing::Song3&>().exit_counter == 1,
+ "Song3 exit not called correctly");
+ BOOST_CHECK_MESSAGE(
+ p.get_state<player_::Playing&>().start_prev_song_guard_counter == 1,
+ "submachine guard not called correctly");
+
+ p.process_event(pause());
+ BOOST_CHECK_MESSAGE(p.current_state()[0] == 4,"Paused should be active"); //Paused
+ BOOST_CHECK_MESSAGE(p.get_state<player_::Playing&>().exit_counter == 1,"Playing exit not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<player_::Paused&>().entry_counter == 1,"Paused entry not called correctly");
+
+ // go back to Playing
+ p.process_event(end_pause());
+ BOOST_CHECK_MESSAGE(p.current_state()[0] == 3,"Playing should be active"); //Playing
+ BOOST_CHECK_MESSAGE(p.get_state<player_::Paused&>().exit_counter == 1,"Paused exit not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<player_::Playing&>().entry_counter == 2,"Playing entry not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<player_::Playing&>().current_state()[0] == 1,"Song2 should be active");
+ BOOST_CHECK_MESSAGE(
+ p.get_state<player_::Playing&>().get_state<player_::Playing::Song2&>().entry_counter == 3,
+ "Song2 entry not called correctly");
+
+ p.process_event(pause());
+ BOOST_CHECK_MESSAGE(p.current_state()[0] == 4,"Paused should be active"); //Paused
+ BOOST_CHECK_MESSAGE(p.get_state<player_::Playing&>().exit_counter == 2,"Playing exit not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<player_::Paused&>().entry_counter == 2,"Paused entry not called correctly");
+
+ p.process_event(stop());
+ BOOST_CHECK_MESSAGE(p.current_state()[0] == 0,"Stopped should be active"); //Stopped
+ BOOST_CHECK_MESSAGE(p.get_state<player_::Paused&>().exit_counter == 2,"Paused exit not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<player_::Stopped&>().entry_counter == 2,"Stopped entry not called correctly");
+
+ p.process_event(stop());
+ BOOST_CHECK_MESSAGE(p.current_state()[0] == 0,"Stopped should be active"); //Stopped
+ BOOST_CHECK_MESSAGE(p.get_state<player_::Stopped&>().exit_counter == 2,"Stopped exit not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<player_::Stopped&>().entry_counter == 3,"Stopped entry not called correctly");
+
+ p.process_event(play());
+ BOOST_CHECK_MESSAGE(p.get_state<player_::Playing&>().current_state()[0] == 0,"Song1 should be active");
+ BOOST_CHECK_MESSAGE(
+ p.get_state<player_::Playing&>().get_state<player_::Playing::Song1&>().entry_counter == 2,
+ "Song1 entry not called correctly");
+
+ }
+}
+
diff --git a/src/boost/libs/msm/test/Jamfile.v2 b/src/boost/libs/msm/test/Jamfile.v2
new file mode 100644
index 000000000..a00c2cec8
--- /dev/null
+++ b/src/boost/libs/msm/test/Jamfile.v2
@@ -0,0 +1,50 @@
+# test/Jamfile.v2 controls building of MSM Library unit tests
+#
+# Copyright (c) 2010 Christophe Henry
+#
+# Use, modification and distribution is subject to 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)
+
+import testing ;
+
+project msm
+ :
+ requirements
+ <include>.
+ <toolset>gcc:<cxxflags>"-ftemplate-depth-300 -g0"
+ <toolset>darwin:<cxxflags>"-ftemplate-depth-300 -g0"
+ <toolset>intel:<cxxflags>"-g0"
+ <toolset>gcc:<optimization>off
+ <toolset>darwin:<optimization>off
+ <toolset>intel:<optimization>off
+ <library>/boost/test//boost_unit_test_framework/<link>static
+ <library>/boost/serialization//boost_serialization/<link>static
+ ;
+
+test-suite msm-unit-tests
+ :
+ [ run Anonymous.cpp ]
+ [ run AnonymousEuml.cpp ]
+ [ run CompositeEuml.cpp ]
+ [ run CompositeMachine.cpp ]
+ [ run Constructor.cpp ]
+ [ run Entries.cpp ]
+ [ run History.cpp ]
+ [ run OrthogonalDeferred.cpp ]
+ [ run OrthogonalDeferred2.cpp ]
+ [ run OrthogonalDeferred3.cpp ]
+ [ run OrthogonalDeferredEuml.cpp ]
+ [ run SimpleEuml.cpp ]
+ [ run SimpleEuml2.cpp ]
+ [ run SimpleInternal.cpp ]
+ [ run SimpleInternalEuml.cpp ]
+ [ run SimpleInternalFunctors.cpp ]
+ [ run SimpleMachine.cpp ]
+ [ run SimpleWithFunctors.cpp ]
+ [ run Serialize.cpp ]
+ [ run SerializeWithHistory.cpp ]
+ [ run SerializeSimpleEuml.cpp ]
+ [ run TestConstructor.cpp ]
+ ;
+
diff --git a/src/boost/libs/msm/test/OrthogonalDeferred.cpp b/src/boost/libs/msm/test/OrthogonalDeferred.cpp
new file mode 100644
index 000000000..a5da22368
--- /dev/null
+++ b/src/boost/libs/msm/test/OrthogonalDeferred.cpp
@@ -0,0 +1,488 @@
+// 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 <iostream>
+// back-end
+#include <boost/msm/back/state_machine.hpp>
+//front-end
+#include <boost/msm/front/state_machine_def.hpp>
+#ifndef BOOST_MSM_NONSTANDALONE_TEST
+#define BOOST_TEST_MODULE MyTest
+#endif
+#include <boost/test/unit_test.hpp>
+
+namespace msm = boost::msm;
+namespace mpl = boost::mpl;
+
+namespace
+{
+ // events
+ struct play {};
+ struct end_pause {};
+ struct stop {};
+ struct pause {};
+ struct open_close {};
+ struct NextSong {};
+ struct PreviousSong {};
+ struct error_found {};
+ struct end_error {};
+ struct do_terminate {};
+
+ // Flags. Allow information about a property of the current state
+ struct PlayingPaused{};
+ struct CDLoaded {};
+ struct FirstSongPlaying {};
+
+ // A "complicated" event type that carries some data.
+ struct cd_detected
+ {
+ cd_detected(std::string name)
+ : name(name)
+ {}
+
+ std::string name;
+ };
+
+ // front-end: define the FSM structure
+ struct player_ : public msm::front::state_machine_def<player_>
+ {
+ unsigned int start_playback_counter;
+ unsigned int can_close_drawer_counter;
+ unsigned int report_error_counter;
+ unsigned int report_end_error_counter;
+
+ player_():
+ start_playback_counter(0),
+ can_close_drawer_counter(0),
+ report_error_counter(0),
+ report_end_error_counter(0)
+ {}
+ // The list of FSM states
+ struct Empty : public msm::front::state<>
+ {
+ typedef mpl::vector<play> deferred_events;
+ 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;
+ int exit_counter;
+ };
+ struct Open : public msm::front::state<>
+ {
+ typedef mpl::vector<play> deferred_events;
+ typedef mpl::vector1<CDLoaded> flag_list;
+
+ 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;
+ int exit_counter;
+ };
+
+ struct Stopped : public msm::front::state<>
+ {
+ typedef mpl::vector1<CDLoaded> flag_list;
+
+ 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;
+ int exit_counter;
+ };
+
+ // the player state machine contains a state which is himself a state machine
+ // as you see, no need to declare it anywhere so Playing can be developed separately
+ // by another team in another module. For simplicity I just declare it inside player
+ struct Playing_ : public msm::front::state_machine_def<Playing_>
+ {
+ // when playing, the CD is loaded and we are in either pause or playing (duh)
+ typedef mpl::vector2<PlayingPaused,CDLoaded> flag_list;
+
+ 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;
+ int exit_counter;
+ unsigned int start_next_song_counter;
+ unsigned int start_prev_song_guard_counter;
+
+ Playing_():
+ start_next_song_counter(0),
+ start_prev_song_guard_counter(0)
+ {}
+
+ // The list of FSM states
+ struct Song1 : public msm::front::state<>
+ {
+ typedef mpl::vector1<FirstSongPlaying> flag_list;
+
+ 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;
+ int exit_counter;
+ };
+ struct Song2 : 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;
+ int exit_counter;
+ };
+ struct Song3 : 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;
+ int exit_counter;
+ };
+ // the initial state. Must be defined
+ typedef Song1 initial_state;
+ // transition actions
+ void start_next_song(NextSong const&) {++start_next_song_counter; }
+ void start_prev_song(PreviousSong const&) { }
+ // guard conditions
+ bool start_prev_song_guard(PreviousSong const&) {++start_prev_song_guard_counter;return true; }
+
+ typedef Playing_ pl; // makes transition table cleaner
+ // Transition table for Playing
+ struct transition_table : mpl::vector4<
+ // Start Event Next Action Guard
+ // +---------+-------------+---------+---------------------+----------------------+
+ _row < Song1 , NextSong , Song2 >,
+ row < Song2 , PreviousSong, Song1 , &pl::start_prev_song,&pl::start_prev_song_guard>,
+ a_row < Song2 , NextSong , Song3 , &pl::start_next_song >,
+ g_row < Song3 , PreviousSong, Song2 ,&pl::start_prev_song_guard>
+ // +---------+-------------+---------+---------------------+----------------------+
+ > {};
+ // Replaces the default no-transition response.
+ template <class FSM,class Event>
+ void no_transition(Event const&, FSM&,int)
+ {
+ BOOST_FAIL("no_transition called!");
+ }
+ };
+ // back-end
+ typedef msm::back::state_machine<Playing_> Playing;
+
+ // state not defining any entry or exit
+ struct Paused : public msm::front::state<>
+ {
+ typedef mpl::vector2<PlayingPaused,CDLoaded> flag_list;
+
+ 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;
+ int exit_counter;
+ };
+ struct AllOk : 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;
+ int exit_counter;
+ };
+ // this state is also made terminal so that all the events are blocked
+ struct ErrorMode : //public msm::front::terminate_state<> // ErrorMode terminates the state machine
+ public msm::front::interrupt_state<end_error> // ErroMode just interrupts. Will resume if
+ // the event end_error is generated
+ {
+ 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;
+ int exit_counter;
+ };
+ struct ErrorTerminate : public msm::front::terminate_state<> // terminates the state machine
+ {
+ 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;
+ int exit_counter;
+ };
+ // the initial state of the player SM. Must be defined
+ typedef mpl::vector<Empty,AllOk> initial_state;
+
+ // transition actions
+ void start_playback(play const&) {++start_playback_counter; }
+ void open_drawer(open_close const&) { }
+ void store_cd_info(cd_detected const&) { }
+ void stop_playback(stop const&) { }
+ void pause_playback(pause const&) { }
+ void resume_playback(end_pause const&) { }
+ void stop_and_open(open_close const&) { }
+ void stopped_again(stop const&){}
+ void report_error(error_found const&) {++report_error_counter;}
+ void report_end_error(end_error const&) {++report_end_error_counter;}
+
+ //guards
+ bool can_close_drawer(open_close const&)
+ {
+ ++can_close_drawer_counter;
+ return true;
+ }
+ typedef player_ p; // makes transition table cleaner
+
+ // Transition table for player
+ struct transition_table : mpl::vector<
+ // Start Event Next Action Guard
+ // +---------+-------------+---------+---------------------+----------------------+
+ a_row < Stopped , play , Playing , &p::start_playback >,
+ a_row < Stopped , open_close , Open , &p::open_drawer >,
+ _row < Stopped , stop , Stopped >,
+ // +---------+-------------+---------+---------------------+----------------------+
+ g_row < Open , open_close , Empty , &p::can_close_drawer >,
+ // +---------+-------------+---------+---------------------+----------------------+
+ a_row < Empty , open_close , Open , &p::open_drawer >,
+ a_row < Empty , cd_detected , Stopped , &p::store_cd_info >,
+ // +---------+-------------+---------+---------------------+----------------------+
+ a_row < Playing , stop , Stopped , &p::stop_playback >,
+ a_row < Playing , pause , Paused , &p::pause_playback >,
+ a_row < Playing , open_close , Open , &p::stop_and_open >,
+ // +---------+-------------+---------+---------------------+----------------------+
+ a_row < Paused , end_pause , Playing , &p::resume_playback >,
+ a_row < Paused , stop , Stopped , &p::stop_playback >,
+ a_row < Paused , open_close , Open , &p::stop_and_open >,
+ // +---------+-------------+---------+---------------------+----------------------+
+ a_row < AllOk , error_found ,ErrorMode, &p::report_error >,
+ a_row <ErrorMode, end_error ,AllOk , &p::report_end_error >,
+ _row < AllOk , do_terminate,ErrorTerminate >
+ // +---------+-------------+---------+---------------------+----------------------+
+ > {};
+
+ // Replaces the default no-transition response.
+ template <class FSM,class Event>
+ void no_transition(Event const& , FSM&,int )
+ {
+ BOOST_FAIL("no_transition called!");
+ }
+ // init counters
+ template <class Event,class FSM>
+ void on_entry(Event const&,FSM& fsm)
+ {
+ fsm.template get_state<player_::Stopped&>().entry_counter=0;
+ fsm.template get_state<player_::Stopped&>().exit_counter=0;
+ fsm.template get_state<player_::Open&>().entry_counter=0;
+ fsm.template get_state<player_::Open&>().exit_counter=0;
+ fsm.template get_state<player_::Empty&>().entry_counter=0;
+ fsm.template get_state<player_::Empty&>().exit_counter=0;
+ fsm.template get_state<player_::Playing&>().entry_counter=0;
+ fsm.template get_state<player_::Playing&>().exit_counter=0;
+ fsm.template get_state<player_::Playing&>().template get_state<player_::Playing::Song1&>().entry_counter=0;
+ fsm.template get_state<player_::Playing&>().template get_state<player_::Playing::Song1&>().exit_counter=0;
+ fsm.template get_state<player_::Playing&>().template get_state<player_::Playing::Song2&>().entry_counter=0;
+ fsm.template get_state<player_::Playing&>().template get_state<player_::Playing::Song2&>().exit_counter=0;
+ fsm.template get_state<player_::Playing&>().template get_state<player_::Playing::Song3&>().entry_counter=0;
+ fsm.template get_state<player_::Playing&>().template get_state<player_::Playing::Song3&>().exit_counter=0;
+ fsm.template get_state<player_::Paused&>().entry_counter=0;
+ fsm.template get_state<player_::Paused&>().exit_counter=0;
+ fsm.template get_state<player_::AllOk&>().entry_counter=0;
+ fsm.template get_state<player_::AllOk&>().exit_counter=0;
+ fsm.template get_state<player_::ErrorMode&>().entry_counter=0;
+ fsm.template get_state<player_::ErrorMode&>().exit_counter=0;
+ fsm.template get_state<player_::ErrorTerminate&>().entry_counter=0;
+ fsm.template get_state<player_::ErrorTerminate&>().exit_counter=0;
+ }
+ };
+ // Pick a back-end
+ typedef msm::back::state_machine<player_> player;
+
+ //static char const* const state_names[] = { "Stopped", "Open", "Empty", "Playing", "Paused","AllOk","ErrorMode" };
+
+ BOOST_AUTO_TEST_CASE( my_test )
+ {
+ player p;
+ // needed to start the highest-level SM. This will call on_entry and mark the start of the SM
+ p.start();
+ // test deferred event
+ // deferred in Empty and Open, will be handled only after event cd_detected
+ p.process_event(play());
+ BOOST_CHECK_MESSAGE(p.current_state()[0] == 2,"Empty should be active"); //Empty
+ BOOST_CHECK_MESSAGE(p.get_state<player_::Open&>().exit_counter == 0,"Open exit not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<player_::Playing&>().entry_counter == 0,"Playing entry not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<player_::Empty&>().entry_counter == 1,"Empty entry not called correctly");
+ //flags
+ BOOST_CHECK_MESSAGE(p.is_flag_active<CDLoaded>() == false,"CDLoaded should not be active");
+
+ p.process_event(open_close());
+ BOOST_CHECK_MESSAGE(p.current_state()[0] == 1,"Open should be active"); //Open
+ BOOST_CHECK_MESSAGE(p.get_state<player_::Empty&>().exit_counter == 1,"Empty exit not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<player_::Open&>().entry_counter == 1,"Open entry not called correctly");
+
+ p.process_event(open_close());
+ BOOST_CHECK_MESSAGE(p.current_state()[0] == 2,"Empty should be active"); //Empty
+ BOOST_CHECK_MESSAGE(p.get_state<player_::Open&>().exit_counter == 1,"Open exit not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<player_::Empty&>().entry_counter == 2,"Empty entry not called correctly");
+ BOOST_CHECK_MESSAGE(p.can_close_drawer_counter == 1,"guard not called correctly");
+
+ //deferred event should have been processed
+ p.process_event(cd_detected("louie, louie"));
+ BOOST_CHECK_MESSAGE(p.current_state()[0] == 3,"Playing should be active"); //Playing
+ BOOST_CHECK_MESSAGE(p.get_state<player_::Empty&>().exit_counter == 2,"Empty exit not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<player_::Stopped&>().entry_counter == 1,"Stopped entry not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<player_::Stopped&>().exit_counter == 1,"Stopped exit not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<player_::Playing&>().entry_counter == 1,"Playing entry not called correctly");
+ BOOST_CHECK_MESSAGE(p.start_playback_counter == 1,"action not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<player_::Playing&>().current_state()[0] == 0,"Song1 should be active");
+ BOOST_CHECK_MESSAGE(
+ p.get_state<player_::Playing&>().get_state<player_::Playing::Song1&>().entry_counter == 1,
+ "Song1 entry not called correctly");
+
+ //flags
+ BOOST_CHECK_MESSAGE(p.is_flag_active<PlayingPaused>() == true,"PlayingPaused should be active");
+ BOOST_CHECK_MESSAGE(p.is_flag_active<FirstSongPlaying>() == true,"FirstSongPlaying should be active");
+
+
+ p.process_event(NextSong());
+ BOOST_CHECK_MESSAGE(p.current_state()[0] == 3,"Playing should be active"); //Playing
+ BOOST_CHECK_MESSAGE(p.get_state<player_::Playing&>().current_state()[0] == 1,"Song2 should be active");
+ BOOST_CHECK_MESSAGE(
+ p.get_state<player_::Playing&>().get_state<player_::Playing::Song2&>().entry_counter == 1,
+ "Song2 entry not called correctly");
+ BOOST_CHECK_MESSAGE(
+ p.get_state<player_::Playing&>().get_state<player_::Playing::Song1&>().exit_counter == 1,
+ "Song1 exit not called correctly");
+ BOOST_CHECK_MESSAGE(
+ p.get_state<player_::Playing&>().start_next_song_counter == 0,
+ "submachine action not called correctly");
+
+ p.process_event(NextSong());
+ BOOST_CHECK_MESSAGE(p.current_state()[0] == 3,"Playing should be active"); //Playing
+ BOOST_CHECK_MESSAGE(p.get_state<player_::Playing&>().current_state()[0] == 2,"Song3 should be active");
+ BOOST_CHECK_MESSAGE(
+ p.get_state<player_::Playing&>().get_state<player_::Playing::Song3&>().entry_counter == 1,
+ "Song3 entry not called correctly");
+ BOOST_CHECK_MESSAGE(
+ p.get_state<player_::Playing&>().get_state<player_::Playing::Song2&>().exit_counter == 1,
+ "Song2 exit not called correctly");
+ BOOST_CHECK_MESSAGE(
+ p.get_state<player_::Playing&>().start_next_song_counter == 1,
+ "submachine action not called correctly");
+
+ p.process_event(PreviousSong());
+ BOOST_CHECK_MESSAGE(p.current_state()[0] == 3,"Playing should be active"); //Playing
+ BOOST_CHECK_MESSAGE(p.get_state<player_::Playing&>().current_state()[0] == 1,"Song2 should be active");
+ BOOST_CHECK_MESSAGE(
+ p.get_state<player_::Playing&>().get_state<player_::Playing::Song2&>().entry_counter == 2,
+ "Song2 entry not called correctly");
+ BOOST_CHECK_MESSAGE(
+ p.get_state<player_::Playing&>().get_state<player_::Playing::Song3&>().exit_counter == 1,
+ "Song3 exit not called correctly");
+ BOOST_CHECK_MESSAGE(
+ p.get_state<player_::Playing&>().start_prev_song_guard_counter == 1,
+ "submachine guard not called correctly");
+ //flags
+ BOOST_CHECK_MESSAGE(p.is_flag_active<PlayingPaused>() == true,"PlayingPaused should be active");
+ BOOST_CHECK_MESSAGE(p.is_flag_active<FirstSongPlaying>() == false,"FirstSongPlaying should not be active");
+
+ p.process_event(pause());
+ BOOST_CHECK_MESSAGE(p.current_state()[0] == 4,"Paused should be active"); //Paused
+ BOOST_CHECK_MESSAGE(p.get_state<player_::Playing&>().exit_counter == 1,"Playing exit not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<player_::Paused&>().entry_counter == 1,"Paused entry not called correctly");
+ //flags
+ BOOST_CHECK_MESSAGE(p.is_flag_active<PlayingPaused>() == true,"PlayingPaused should be active");
+
+ // go back to Playing
+ p.process_event(end_pause());
+ BOOST_CHECK_MESSAGE(p.current_state()[0] == 3,"Playing should be active"); //Playing
+ BOOST_CHECK_MESSAGE(p.get_state<player_::Paused&>().exit_counter == 1,"Paused exit not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<player_::Playing&>().entry_counter == 2,"Playing entry not called correctly");
+
+ p.process_event(pause());
+ BOOST_CHECK_MESSAGE(p.current_state()[0] == 4,"Paused should be active"); //Paused
+ BOOST_CHECK_MESSAGE(p.get_state<player_::Playing&>().exit_counter == 2,"Playing exit not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<player_::Paused&>().entry_counter == 2,"Paused entry not called correctly");
+
+ p.process_event(stop());
+ BOOST_CHECK_MESSAGE(p.current_state()[0] == 0,"Stopped should be active"); //Stopped
+ BOOST_CHECK_MESSAGE(p.get_state<player_::Paused&>().exit_counter == 2,"Paused exit not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<player_::Stopped&>().entry_counter == 2,"Stopped entry not called correctly");
+ //flags
+ BOOST_CHECK_MESSAGE(p.is_flag_active<PlayingPaused>() == false,"PlayingPaused should not be active");
+ BOOST_CHECK_MESSAGE(p.is_flag_active<CDLoaded>() == true,"CDLoaded should be active");
+ //BOOST_CHECK_MESSAGE(p.is_flag_active<CDLoaded,player::Flag_AND>() == false,"CDLoaded with AND should not be active");
+
+ p.process_event(stop());
+ BOOST_CHECK_MESSAGE(p.current_state()[0] == 0,"Stopped should be active"); //Stopped
+ BOOST_CHECK_MESSAGE(p.get_state<player_::Stopped&>().exit_counter == 2,"Stopped exit not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<player_::Stopped&>().entry_counter == 3,"Stopped entry not called correctly");
+
+ //test interrupt
+ BOOST_CHECK_MESSAGE(p.current_state()[1] == 5,"AllOk should be active"); //AllOk
+ p.process_event(error_found());
+ BOOST_CHECK_MESSAGE(p.current_state()[1] == 6,"ErrorMode should be active"); //ErrorMode
+ BOOST_CHECK_MESSAGE(p.get_state<player_::AllOk&>().exit_counter == 1,"AllOk exit not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<player_::ErrorMode&>().entry_counter == 1,"ErrorMode entry not called correctly");
+
+ // try generating more events
+ p.process_event(play());
+ BOOST_CHECK_MESSAGE(p.current_state()[1] == 6,"ErrorMode should be active"); //ErrorMode
+ BOOST_CHECK_MESSAGE(p.get_state<player_::AllOk&>().exit_counter == 1,"AllOk exit not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<player_::ErrorMode&>().entry_counter == 1,"ErrorMode entry not called correctly");
+ BOOST_CHECK_MESSAGE(p.current_state()[0] == 0,"Stopped should be active"); //Stopped
+ BOOST_CHECK_MESSAGE(p.get_state<player_::Stopped&>().exit_counter == 2,"Stopped exit not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<player_::Stopped&>().entry_counter == 3,"Stopped entry not called correctly");
+
+ p.process_event(end_error());
+ BOOST_CHECK_MESSAGE(p.current_state()[1] == 5,"AllOk should be active"); //AllOk
+ BOOST_CHECK_MESSAGE(p.get_state<player_::ErrorMode&>().exit_counter == 1,"ErrorMode exit not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<player_::AllOk&>().entry_counter == 2,"AllOk entry not called correctly");
+
+ p.process_event(play());
+ BOOST_CHECK_MESSAGE(p.current_state()[0] == 3,"Playing should be active"); //Playing
+ BOOST_CHECK_MESSAGE(p.get_state<player_::Stopped&>().exit_counter == 3,"Stopped exit not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<player_::Playing&>().entry_counter == 3,"Playing entry not called correctly");
+
+ //test terminate
+ BOOST_CHECK_MESSAGE(p.current_state()[1] == 5,"AllOk should be active"); //AllOk
+ p.process_event(do_terminate());
+ BOOST_CHECK_MESSAGE(p.current_state()[1] == 7,"ErrorTerminate should be active"); //ErrorTerminate
+ BOOST_CHECK_MESSAGE(p.get_state<player_::AllOk&>().exit_counter == 2,"AllOk exit not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<player_::ErrorTerminate&>().entry_counter == 1,"ErrorTerminate entry not called correctly");
+
+ // try generating more events
+ p.process_event(stop());
+ BOOST_CHECK_MESSAGE(p.current_state()[1] == 7,"ErrorTerminate should be active"); //ErrorTerminate
+ BOOST_CHECK_MESSAGE(p.get_state<player_::ErrorTerminate&>().exit_counter == 0,"ErrorTerminate exit not called correctly");
+ BOOST_CHECK_MESSAGE(p.current_state()[0] == 3,"Playing should be active"); //Playing
+ BOOST_CHECK_MESSAGE(p.get_state<player_::Playing&>().exit_counter == 2,"Playing exit not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<player_::Stopped&>().entry_counter == 3,"Stopped entry not called correctly");
+
+ p.process_event(end_error());
+ BOOST_CHECK_MESSAGE(p.current_state()[1] == 7,"ErrorTerminate should be active"); //ErrorTerminate
+ BOOST_CHECK_MESSAGE(p.current_state()[0] == 3,"Playing should be active"); //Playing
+ BOOST_CHECK_MESSAGE(p.get_state<player_::Playing&>().exit_counter == 2,"Playing exit not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<player_::Stopped&>().entry_counter == 3,"Stopped entry not called correctly");
+
+ p.process_event(stop());
+ BOOST_CHECK_MESSAGE(p.current_state()[1] == 7,"ErrorTerminate should be active"); //ErrorTerminate
+ BOOST_CHECK_MESSAGE(p.current_state()[0] == 3,"Playing should be active"); //Playing
+ BOOST_CHECK_MESSAGE(p.get_state<player_::Playing&>().exit_counter == 2,"Playing exit not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<player_::Stopped&>().entry_counter == 3,"Stopped entry not called correctly");
+
+ }
+}
+
diff --git a/src/boost/libs/msm/test/OrthogonalDeferred2.cpp b/src/boost/libs/msm/test/OrthogonalDeferred2.cpp
new file mode 100644
index 000000000..9e630cca3
--- /dev/null
+++ b/src/boost/libs/msm/test/OrthogonalDeferred2.cpp
@@ -0,0 +1,495 @@
+// 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 <iostream>
+// back-end
+#include <boost/msm/back/state_machine.hpp>
+//front-end
+#include <boost/msm/front/state_machine_def.hpp>
+#include <boost/msm/front/functor_row.hpp>
+
+#ifndef BOOST_MSM_NONSTANDALONE_TEST
+#define BOOST_TEST_MODULE MyTest
+#endif
+#include <boost/test/unit_test.hpp>
+
+namespace msm = boost::msm;
+namespace mpl = boost::mpl;
+using namespace boost::msm::front;
+
+namespace
+{
+ // events
+ struct play {};
+ struct end_pause {};
+ struct stop {};
+ struct pause {};
+ struct open_close {};
+ struct NextSong {};
+ struct PreviousSong {};
+ struct error_found {};
+ struct end_error {};
+ struct do_terminate {};
+
+ // Flags. Allow information about a property of the current state
+ struct PlayingPaused{};
+ struct CDLoaded {};
+ struct FirstSongPlaying {};
+
+ // A "complicated" event type that carries some data.
+ struct cd_detected
+ {
+ cd_detected(std::string name)
+ : name(name)
+ {}
+
+ std::string name;
+ };
+
+ // front-end: define the FSM structure
+ struct player_ : public msm::front::state_machine_def<player_>
+ {
+ // 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;
+
+ unsigned int start_playback_counter;
+ unsigned int can_close_drawer_counter;
+ unsigned int report_error_counter;
+ unsigned int report_end_error_counter;
+
+ player_():
+ start_playback_counter(0),
+ can_close_drawer_counter(0),
+ report_error_counter(0),
+ report_end_error_counter(0)
+ {}
+ // The list of FSM states
+ struct Empty : 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;
+ int exit_counter;
+ };
+ struct Open : public msm::front::state<>
+ {
+ typedef mpl::vector1<CDLoaded> flag_list;
+
+ 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;
+ int exit_counter;
+ };
+
+ struct Stopped : public msm::front::state<>
+ {
+ typedef mpl::vector1<CDLoaded> flag_list;
+
+ 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;
+ int exit_counter;
+ };
+
+ // the player state machine contains a state which is himself a state machine
+ // as you see, no need to declare it anywhere so Playing can be developed separately
+ // by another team in another module. For simplicity I just declare it inside player
+ struct Playing_ : public msm::front::state_machine_def<Playing_>
+ {
+ // when playing, the CD is loaded and we are in either pause or playing (duh)
+ typedef mpl::vector2<PlayingPaused,CDLoaded> flag_list;
+
+ 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;
+ int exit_counter;
+ unsigned int start_next_song_counter;
+ unsigned int start_prev_song_guard_counter;
+
+ Playing_():
+ start_next_song_counter(0),
+ start_prev_song_guard_counter(0)
+ {}
+
+ // The list of FSM states
+ struct Song1 : public msm::front::state<>
+ {
+ typedef mpl::vector1<FirstSongPlaying> flag_list;
+
+ 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;
+ int exit_counter;
+ };
+ struct Song2 : 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;
+ int exit_counter;
+ };
+ struct Song3 : 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;
+ int exit_counter;
+ };
+ // the initial state. Must be defined
+ typedef Song1 initial_state;
+ // transition actions
+ void start_next_song(NextSong const&) {++start_next_song_counter; }
+ void start_prev_song(PreviousSong const&) { }
+ // guard conditions
+ bool start_prev_song_guard(PreviousSong const&) {++start_prev_song_guard_counter;return true; }
+
+ typedef Playing_ pl; // makes transition table cleaner
+ // Transition table for Playing
+ struct transition_table : mpl::vector4<
+ // Start Event Next Action Guard
+ // +---------+-------------+---------+---------------------+----------------------+
+ _row < Song1 , NextSong , Song2 >,
+ row < Song2 , PreviousSong, Song1 , &pl::start_prev_song,&pl::start_prev_song_guard>,
+ a_row < Song2 , NextSong , Song3 , &pl::start_next_song >,
+ g_row < Song3 , PreviousSong, Song2 ,&pl::start_prev_song_guard>
+ // +---------+-------------+---------+---------------------+----------------------+
+ > {};
+ // Replaces the default no-transition response.
+ template <class FSM,class Event>
+ void no_transition(Event const&, FSM&,int)
+ {
+ BOOST_FAIL("no_transition called!");
+ }
+ };
+ // back-end
+ typedef msm::back::state_machine<Playing_> Playing;
+
+ // state not defining any entry or exit
+ struct Paused : public msm::front::state<>
+ {
+ typedef mpl::vector2<PlayingPaused,CDLoaded> flag_list;
+
+ 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;
+ int exit_counter;
+ };
+ struct AllOk : 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;
+ int exit_counter;
+ };
+ // this state is also made terminal so that all the events are blocked
+ struct ErrorMode : //public msm::front::terminate_state<> // ErrorMode terminates the state machine
+ public msm::front::interrupt_state<end_error> // ErroMode just interrupts. Will resume if
+ // the event end_error is generated
+ {
+ 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;
+ int exit_counter;
+ };
+ struct ErrorTerminate : public msm::front::terminate_state<> // terminates the state machine
+ {
+ 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;
+ int exit_counter;
+ };
+ // the initial state of the player SM. Must be defined
+ typedef mpl::vector<Empty,AllOk> initial_state;
+
+ // transition actions
+ void start_playback(play const&) {++start_playback_counter; }
+ void open_drawer(open_close const&) { }
+ void store_cd_info(cd_detected const&) { }
+ void stop_playback(stop const&) { }
+ void pause_playback(pause const&) { }
+ void resume_playback(end_pause const&) { }
+ void stop_and_open(open_close const&) { }
+ void stopped_again(stop const&){}
+ void report_error(error_found const&) {++report_error_counter;}
+ void report_end_error(end_error const&) {++report_end_error_counter;}
+
+ //guards
+ bool can_close_drawer(open_close const&)
+ {
+ ++can_close_drawer_counter;
+ return true;
+ }
+ typedef player_ p; // makes transition table cleaner
+
+ // Transition table for player
+ struct transition_table : mpl::vector<
+ // Start Event Next Action Guard
+ // +---------+-------------+---------+---------------------+----------------------+
+ a_row < Stopped , play , Playing , &p::start_playback >,
+ a_row < Stopped , open_close , Open , &p::open_drawer >,
+ _row < Stopped , stop , Stopped >,
+ // +---------+-------------+---------+---------------------+----------------------+
+ g_row < Open , open_close , Empty , &p::can_close_drawer >,
+ Row < Open , play , none , Defer , none >,
+ // +---------+-------------+---------+---------------------+----------------------+
+ a_row < Empty , open_close , Open , &p::open_drawer >,
+ a_row < Empty , cd_detected , Stopped , &p::store_cd_info >,
+ Row < Empty , play , none , Defer , none >,
+ // +---------+-------------+---------+---------------------+----------------------+
+ a_row < Playing , stop , Stopped , &p::stop_playback >,
+ a_row < Playing , pause , Paused , &p::pause_playback >,
+ a_row < Playing , open_close , Open , &p::stop_and_open >,
+ // +---------+-------------+---------+---------------------+----------------------+
+ a_row < Paused , end_pause , Playing , &p::resume_playback >,
+ a_row < Paused , stop , Stopped , &p::stop_playback >,
+ a_row < Paused , open_close , Open , &p::stop_and_open >,
+ // +---------+-------------+---------+---------------------+----------------------+
+ a_row < AllOk , error_found ,ErrorMode, &p::report_error >,
+ a_row <ErrorMode, end_error ,AllOk , &p::report_end_error >,
+ _row < AllOk , do_terminate,ErrorTerminate >
+ // +---------+-------------+---------+---------------------+----------------------+
+ > {};
+
+ // Replaces the default no-transition response.
+ template <class FSM,class Event>
+ void no_transition(Event const& , FSM&,int)
+ {
+ BOOST_FAIL("no_transition called!");
+ }
+ // init counters
+ template <class Event,class FSM>
+ void on_entry(Event const&,FSM& fsm)
+ {
+ fsm.template get_state<player_::Stopped&>().entry_counter=0;
+ fsm.template get_state<player_::Stopped&>().exit_counter=0;
+ fsm.template get_state<player_::Open&>().entry_counter=0;
+ fsm.template get_state<player_::Open&>().exit_counter=0;
+ fsm.template get_state<player_::Empty&>().entry_counter=0;
+ fsm.template get_state<player_::Empty&>().exit_counter=0;
+ fsm.template get_state<player_::Playing&>().entry_counter=0;
+ fsm.template get_state<player_::Playing&>().exit_counter=0;
+ fsm.template get_state<player_::Playing&>().template get_state<player_::Playing::Song1&>().entry_counter=0;
+ fsm.template get_state<player_::Playing&>().template get_state<player_::Playing::Song1&>().exit_counter=0;
+ fsm.template get_state<player_::Playing&>().template get_state<player_::Playing::Song2&>().entry_counter=0;
+ fsm.template get_state<player_::Playing&>().template get_state<player_::Playing::Song2&>().exit_counter=0;
+ fsm.template get_state<player_::Playing&>().template get_state<player_::Playing::Song3&>().entry_counter=0;
+ fsm.template get_state<player_::Playing&>().template get_state<player_::Playing::Song3&>().exit_counter=0;
+ fsm.template get_state<player_::Paused&>().entry_counter=0;
+ fsm.template get_state<player_::Paused&>().exit_counter=0;
+ fsm.template get_state<player_::AllOk&>().entry_counter=0;
+ fsm.template get_state<player_::AllOk&>().exit_counter=0;
+ fsm.template get_state<player_::ErrorMode&>().entry_counter=0;
+ fsm.template get_state<player_::ErrorMode&>().exit_counter=0;
+ fsm.template get_state<player_::ErrorTerminate&>().entry_counter=0;
+ fsm.template get_state<player_::ErrorTerminate&>().exit_counter=0;
+ }
+ };
+ // Pick a back-end
+ typedef msm::back::state_machine<player_> player;
+
+ //static char const* const state_names[] = { "Stopped", "Open", "Empty", "Playing", "Paused","AllOk","ErrorMode" };
+
+ BOOST_AUTO_TEST_CASE( my_test )
+ {
+ player p;
+ // needed to start the highest-level SM. This will call on_entry and mark the start of the SM
+ p.start();
+ // test deferred event
+ // deferred in Empty and Open, will be handled only after event cd_detected
+ p.process_event(play());
+ BOOST_CHECK_MESSAGE(p.current_state()[0] == 2,"Empty should be active"); //Empty
+ BOOST_CHECK_MESSAGE(p.get_state<player_::Open&>().exit_counter == 0,"Open exit not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<player_::Playing&>().entry_counter == 0,"Playing entry not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<player_::Empty&>().entry_counter == 1,"Empty entry not called correctly");
+ //flags
+ BOOST_CHECK_MESSAGE(p.is_flag_active<CDLoaded>() == false,"CDLoaded should not be active");
+
+ p.process_event(open_close());
+ BOOST_CHECK_MESSAGE(p.current_state()[0] == 1,"Open should be active"); //Open
+ BOOST_CHECK_MESSAGE(p.get_state<player_::Empty&>().exit_counter == 1,"Empty exit not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<player_::Open&>().entry_counter == 1,"Open entry not called correctly");
+
+ p.process_event(open_close());
+ BOOST_CHECK_MESSAGE(p.current_state()[0] == 2,"Empty should be active"); //Empty
+ BOOST_CHECK_MESSAGE(p.get_state<player_::Open&>().exit_counter == 1,"Open exit not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<player_::Empty&>().entry_counter == 2,"Empty entry not called correctly");
+ BOOST_CHECK_MESSAGE(p.can_close_drawer_counter == 1,"guard not called correctly");
+
+ //deferred event should have been processed
+ p.process_event(cd_detected("louie, louie"));
+ BOOST_CHECK_MESSAGE(p.current_state()[0] == 3,"Playing should be active"); //Playing
+ BOOST_CHECK_MESSAGE(p.get_state<player_::Empty&>().exit_counter == 2,"Empty exit not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<player_::Stopped&>().entry_counter == 1,"Stopped entry not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<player_::Stopped&>().exit_counter == 1,"Stopped exit not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<player_::Playing&>().entry_counter == 1,"Playing entry not called correctly");
+ BOOST_CHECK_MESSAGE(p.start_playback_counter == 1,"action not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<player_::Playing&>().current_state()[0] == 0,"Song1 should be active");
+ BOOST_CHECK_MESSAGE(
+ p.get_state<player_::Playing&>().get_state<player_::Playing::Song1&>().entry_counter == 1,
+ "Song1 entry not called correctly");
+
+ //flags
+ BOOST_CHECK_MESSAGE(p.is_flag_active<PlayingPaused>() == true,"PlayingPaused should be active");
+ BOOST_CHECK_MESSAGE(p.is_flag_active<FirstSongPlaying>() == true,"FirstSongPlaying should be active");
+
+
+ p.process_event(NextSong());
+ BOOST_CHECK_MESSAGE(p.current_state()[0] == 3,"Playing should be active"); //Playing
+ BOOST_CHECK_MESSAGE(p.get_state<player_::Playing&>().current_state()[0] == 1,"Song2 should be active");
+ BOOST_CHECK_MESSAGE(
+ p.get_state<player_::Playing&>().get_state<player_::Playing::Song2&>().entry_counter == 1,
+ "Song2 entry not called correctly");
+ BOOST_CHECK_MESSAGE(
+ p.get_state<player_::Playing&>().get_state<player_::Playing::Song1&>().exit_counter == 1,
+ "Song1 exit not called correctly");
+ BOOST_CHECK_MESSAGE(
+ p.get_state<player_::Playing&>().start_next_song_counter == 0,
+ "submachine action not called correctly");
+
+ p.process_event(NextSong());
+ BOOST_CHECK_MESSAGE(p.current_state()[0] == 3,"Playing should be active"); //Playing
+ BOOST_CHECK_MESSAGE(p.get_state<player_::Playing&>().current_state()[0] == 2,"Song3 should be active");
+ BOOST_CHECK_MESSAGE(
+ p.get_state<player_::Playing&>().get_state<player_::Playing::Song3&>().entry_counter == 1,
+ "Song3 entry not called correctly");
+ BOOST_CHECK_MESSAGE(
+ p.get_state<player_::Playing&>().get_state<player_::Playing::Song2&>().exit_counter == 1,
+ "Song2 exit not called correctly");
+ BOOST_CHECK_MESSAGE(
+ p.get_state<player_::Playing&>().start_next_song_counter == 1,
+ "submachine action not called correctly");
+
+ p.process_event(PreviousSong());
+ BOOST_CHECK_MESSAGE(p.current_state()[0] == 3,"Playing should be active"); //Playing
+ BOOST_CHECK_MESSAGE(p.get_state<player_::Playing&>().current_state()[0] == 1,"Song2 should be active");
+ BOOST_CHECK_MESSAGE(
+ p.get_state<player_::Playing&>().get_state<player_::Playing::Song2&>().entry_counter == 2,
+ "Song2 entry not called correctly");
+ BOOST_CHECK_MESSAGE(
+ p.get_state<player_::Playing&>().get_state<player_::Playing::Song3&>().exit_counter == 1,
+ "Song3 exit not called correctly");
+ BOOST_CHECK_MESSAGE(
+ p.get_state<player_::Playing&>().start_prev_song_guard_counter == 1,
+ "submachine guard not called correctly");
+ //flags
+ BOOST_CHECK_MESSAGE(p.is_flag_active<PlayingPaused>() == true,"PlayingPaused should be active");
+ BOOST_CHECK_MESSAGE(p.is_flag_active<FirstSongPlaying>() == false,"FirstSongPlaying should not be active");
+
+ p.process_event(pause());
+ BOOST_CHECK_MESSAGE(p.current_state()[0] == 4,"Paused should be active"); //Paused
+ BOOST_CHECK_MESSAGE(p.get_state<player_::Playing&>().exit_counter == 1,"Playing exit not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<player_::Paused&>().entry_counter == 1,"Paused entry not called correctly");
+ //flags
+ BOOST_CHECK_MESSAGE(p.is_flag_active<PlayingPaused>() == true,"PlayingPaused should be active");
+
+ // go back to Playing
+ p.process_event(end_pause());
+ BOOST_CHECK_MESSAGE(p.current_state()[0] == 3,"Playing should be active"); //Playing
+ BOOST_CHECK_MESSAGE(p.get_state<player_::Paused&>().exit_counter == 1,"Paused exit not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<player_::Playing&>().entry_counter == 2,"Playing entry not called correctly");
+
+ p.process_event(pause());
+ BOOST_CHECK_MESSAGE(p.current_state()[0] == 4,"Paused should be active"); //Paused
+ BOOST_CHECK_MESSAGE(p.get_state<player_::Playing&>().exit_counter == 2,"Playing exit not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<player_::Paused&>().entry_counter == 2,"Paused entry not called correctly");
+
+ p.process_event(stop());
+ BOOST_CHECK_MESSAGE(p.current_state()[0] == 0,"Stopped should be active"); //Stopped
+ BOOST_CHECK_MESSAGE(p.get_state<player_::Paused&>().exit_counter == 2,"Paused exit not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<player_::Stopped&>().entry_counter == 2,"Stopped entry not called correctly");
+ //flags
+ BOOST_CHECK_MESSAGE(p.is_flag_active<PlayingPaused>() == false,"PlayingPaused should not be active");
+ BOOST_CHECK_MESSAGE(p.is_flag_active<CDLoaded>() == true,"CDLoaded should be active");
+ //BOOST_CHECK_MESSAGE(p.is_flag_active<CDLoaded,player::Flag_AND>() == false,"CDLoaded with AND should not be active");
+
+ p.process_event(stop());
+ BOOST_CHECK_MESSAGE(p.current_state()[0] == 0,"Stopped should be active"); //Stopped
+ BOOST_CHECK_MESSAGE(p.get_state<player_::Stopped&>().exit_counter == 2,"Stopped exit not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<player_::Stopped&>().entry_counter == 3,"Stopped entry not called correctly");
+
+ //test interrupt
+ BOOST_CHECK_MESSAGE(p.current_state()[1] == 5,"AllOk should be active"); //AllOk
+ p.process_event(error_found());
+ BOOST_CHECK_MESSAGE(p.current_state()[1] == 6,"ErrorMode should be active"); //ErrorMode
+ BOOST_CHECK_MESSAGE(p.get_state<player_::AllOk&>().exit_counter == 1,"AllOk exit not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<player_::ErrorMode&>().entry_counter == 1,"ErrorMode entry not called correctly");
+
+ // try generating more events
+ p.process_event(play());
+ BOOST_CHECK_MESSAGE(p.current_state()[1] == 6,"ErrorMode should be active"); //ErrorMode
+ BOOST_CHECK_MESSAGE(p.get_state<player_::AllOk&>().exit_counter == 1,"AllOk exit not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<player_::ErrorMode&>().entry_counter == 1,"ErrorMode entry not called correctly");
+ BOOST_CHECK_MESSAGE(p.current_state()[0] == 0,"Stopped should be active"); //Stopped
+ BOOST_CHECK_MESSAGE(p.get_state<player_::Stopped&>().exit_counter == 2,"Stopped exit not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<player_::Stopped&>().entry_counter == 3,"Stopped entry not called correctly");
+
+ p.process_event(end_error());
+ BOOST_CHECK_MESSAGE(p.current_state()[1] == 5,"AllOk should be active"); //AllOk
+ BOOST_CHECK_MESSAGE(p.get_state<player_::ErrorMode&>().exit_counter == 1,"ErrorMode exit not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<player_::AllOk&>().entry_counter == 2,"AllOk entry not called correctly");
+
+ p.process_event(play());
+ BOOST_CHECK_MESSAGE(p.current_state()[0] == 3,"Playing should be active"); //Playing
+ BOOST_CHECK_MESSAGE(p.get_state<player_::Stopped&>().exit_counter == 3,"Stopped exit not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<player_::Playing&>().entry_counter == 3,"Playing entry not called correctly");
+
+ //test terminate
+ BOOST_CHECK_MESSAGE(p.current_state()[1] == 5,"AllOk should be active"); //AllOk
+ p.process_event(do_terminate());
+ BOOST_CHECK_MESSAGE(p.current_state()[1] == 7,"ErrorTerminate should be active"); //ErrorTerminate
+ BOOST_CHECK_MESSAGE(p.get_state<player_::AllOk&>().exit_counter == 2,"AllOk exit not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<player_::ErrorTerminate&>().entry_counter == 1,"ErrorTerminate entry not called correctly");
+
+ // try generating more events
+ p.process_event(stop());
+ BOOST_CHECK_MESSAGE(p.current_state()[1] == 7,"ErrorTerminate should be active"); //ErrorTerminate
+ BOOST_CHECK_MESSAGE(p.get_state<player_::ErrorTerminate&>().exit_counter == 0,"ErrorTerminate exit not called correctly");
+ BOOST_CHECK_MESSAGE(p.current_state()[0] == 3,"Playing should be active"); //Playing
+ BOOST_CHECK_MESSAGE(p.get_state<player_::Playing&>().exit_counter == 2,"Playing exit not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<player_::Stopped&>().entry_counter == 3,"Stopped entry not called correctly");
+
+ p.process_event(end_error());
+ BOOST_CHECK_MESSAGE(p.current_state()[1] == 7,"ErrorTerminate should be active"); //ErrorTerminate
+ BOOST_CHECK_MESSAGE(p.current_state()[0] == 3,"Playing should be active"); //Playing
+ BOOST_CHECK_MESSAGE(p.get_state<player_::Playing&>().exit_counter == 2,"Playing exit not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<player_::Stopped&>().entry_counter == 3,"Stopped entry not called correctly");
+
+ p.process_event(stop());
+ BOOST_CHECK_MESSAGE(p.current_state()[1] == 7,"ErrorTerminate should be active"); //ErrorTerminate
+ BOOST_CHECK_MESSAGE(p.current_state()[0] == 3,"Playing should be active"); //Playing
+ BOOST_CHECK_MESSAGE(p.get_state<player_::Playing&>().exit_counter == 2,"Playing exit not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<player_::Stopped&>().entry_counter == 3,"Stopped entry not called correctly");
+
+ }
+}
+
diff --git a/src/boost/libs/msm/test/OrthogonalDeferred3.cpp b/src/boost/libs/msm/test/OrthogonalDeferred3.cpp
new file mode 100644
index 000000000..3ba684487
--- /dev/null
+++ b/src/boost/libs/msm/test/OrthogonalDeferred3.cpp
@@ -0,0 +1,511 @@
+// 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 <iostream>
+// back-end
+#include <boost/msm/back/state_machine.hpp>
+//front-end
+#include <boost/msm/front/state_machine_def.hpp>
+#include <boost/msm/front/functor_row.hpp>
+
+#ifndef BOOST_MSM_NONSTANDALONE_TEST
+#define BOOST_TEST_MODULE MyTest
+#endif
+#include <boost/test/unit_test.hpp>
+
+namespace msm = boost::msm;
+namespace mpl = boost::mpl;
+using namespace boost::msm::front;
+
+namespace
+{
+ // events
+ struct play {};
+ struct end_pause {};
+ struct stop {};
+ struct pause {};
+ struct open_close {};
+ struct NextSong {};
+ struct PreviousSong {};
+ struct error_found {};
+ struct end_error {};
+ struct do_terminate {};
+
+ // Flags. Allow information about a property of the current state
+ struct PlayingPaused{};
+ struct CDLoaded {};
+ struct FirstSongPlaying {};
+
+ // A "complicated" event type that carries some data.
+ struct cd_detected
+ {
+ cd_detected(std::string name)
+ : name(name)
+ {}
+
+ std::string name;
+ };
+
+ // front-end: define the FSM structure
+ struct player_ : public msm::front::state_machine_def<player_>
+ {
+ // 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;
+
+ unsigned int start_playback_counter;
+ unsigned int can_close_drawer_counter;
+ unsigned int report_error_counter;
+ unsigned int report_end_error_counter;
+
+ player_():
+ start_playback_counter(0),
+ can_close_drawer_counter(0),
+ report_error_counter(0),
+ report_end_error_counter(0)
+ {}
+ // The list of FSM states
+ struct Empty : 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;
+ int exit_counter;
+ };
+ struct Open : public msm::front::state<>
+ {
+ typedef mpl::vector1<CDLoaded> flag_list;
+
+ 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;
+ int exit_counter;
+ };
+
+ struct Stopped : public msm::front::state<>
+ {
+ typedef mpl::vector1<CDLoaded> flag_list;
+
+ 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;
+ int exit_counter;
+ };
+
+ // the player state machine contains a state which is himself a state machine
+ // as you see, no need to declare it anywhere so Playing can be developed separately
+ // by another team in another module. For simplicity I just declare it inside player
+ struct Playing_ : public msm::front::state_machine_def<Playing_>
+ {
+ // when playing, the CD is loaded and we are in either pause or playing (duh)
+ typedef mpl::vector2<PlayingPaused,CDLoaded> flag_list;
+
+ 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;
+ int exit_counter;
+ unsigned int start_next_song_counter;
+ unsigned int start_prev_song_guard_counter;
+
+ Playing_():
+ start_next_song_counter(0),
+ start_prev_song_guard_counter(0)
+ {}
+
+ // The list of FSM states
+ struct Song1 : public msm::front::state<>
+ {
+ typedef mpl::vector1<FirstSongPlaying> flag_list;
+
+ 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;
+ int exit_counter;
+ };
+ struct Song2 : 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;
+ int exit_counter;
+ };
+ struct Song3 : 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;
+ int exit_counter;
+ };
+ // the initial state. Must be defined
+ typedef Song1 initial_state;
+ // transition actions
+ void start_next_song(NextSong const&) {++start_next_song_counter; }
+ void start_prev_song(PreviousSong const&) { }
+ // guard conditions
+ bool start_prev_song_guard(PreviousSong const&) {++start_prev_song_guard_counter;return true; }
+
+ typedef Playing_ pl; // makes transition table cleaner
+ // Transition table for Playing
+ struct transition_table : mpl::vector4<
+ // Start Event Next Action Guard
+ // +---------+-------------+---------+---------------------+----------------------+
+ _row < Song1 , NextSong , Song2 >,
+ row < Song2 , PreviousSong, Song1 , &pl::start_prev_song,&pl::start_prev_song_guard>,
+ a_row < Song2 , NextSong , Song3 , &pl::start_next_song >,
+ g_row < Song3 , PreviousSong, Song2 ,&pl::start_prev_song_guard>
+ // +---------+-------------+---------+---------------------+----------------------+
+ > {};
+ // Replaces the default no-transition response.
+ template <class FSM,class Event>
+ void no_transition(Event const&, FSM&,int)
+ {
+ BOOST_FAIL("no_transition called!");
+ }
+ };
+ // back-end
+ typedef msm::back::state_machine<Playing_> Playing;
+
+ // state not defining any entry or exit
+ struct Paused : public msm::front::state<>
+ {
+ typedef mpl::vector2<PlayingPaused,CDLoaded> flag_list;
+
+ 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;
+ int exit_counter;
+ };
+ struct AllOk : 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;
+ int exit_counter;
+ };
+ // this state is also made terminal so that all the events are blocked
+ struct ErrorMode : //public msm::front::terminate_state<> // ErrorMode terminates the state machine
+ public msm::front::interrupt_state<end_error> // ErroMode just interrupts. Will resume if
+ // the event end_error is generated
+ {
+ 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;
+ int exit_counter;
+ };
+ struct ErrorTerminate : public msm::front::terminate_state<> // terminates the state machine
+ {
+ 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;
+ int exit_counter;
+ };
+ // the initial state of the player SM. Must be defined
+ typedef mpl::vector<Empty,AllOk> initial_state;
+
+ // transition actions
+ void start_playback(play const&) {++start_playback_counter; }
+ void open_drawer(open_close const&) { }
+ void store_cd_info(cd_detected const&) { }
+ void stop_playback(stop const&) { }
+ void pause_playback(pause const&) { }
+ void resume_playback(end_pause const&) { }
+ void stop_and_open(open_close const&) { }
+ void stopped_again(stop const&){}
+ void report_error(error_found const&) {++report_error_counter;}
+ void report_end_error(end_error const&) {++report_end_error_counter;}
+
+ //guards
+ bool can_close_drawer(open_close const&)
+ {
+ ++can_close_drawer_counter;
+ return true;
+ }
+ struct is_play_event
+ {
+ template <class EVT,class FSM,class SourceState,class TargetState>
+ bool operator()(EVT const& evt,FSM&,SourceState& ,TargetState& )
+ {
+ bool is_play = boost::any_cast<play>(&evt) != 0;
+ return is_play;
+ }
+ };
+ struct MyDefer
+ {
+ // mark as deferring to avoid stack overflows in certain conditions
+ typedef int deferring_action;
+ template <class EVT,class FSM,class SourceState,class TargetState>
+ void operator()(EVT const& ,FSM& fsm,SourceState& ,TargetState& ) const
+ {
+ fsm.defer_event(play());
+ }
+ };
+ typedef player_ p; // makes transition table cleaner
+
+ // Transition table for player
+ struct transition_table : mpl::vector<
+ // Start Event Next Action Guard
+ // +---------+-------------+---------+---------------------+----------------------+
+ a_row < Stopped , play , Playing , &p::start_playback >,
+ a_row < Stopped , open_close , Open , &p::open_drawer >,
+ _row < Stopped , stop , Stopped >,
+ // +---------+-------------+---------+---------------------+----------------------+
+ g_row < Open , open_close , Empty , &p::can_close_drawer >,
+ Row < Open , play , none , Defer , none >,
+ // +---------+-------------+---------+---------------------+----------------------+
+ a_row < Empty , open_close , Open , &p::open_drawer >,
+ a_row < Empty , cd_detected , Stopped , &p::store_cd_info >,
+ Row < Empty , boost::any , none , MyDefer , is_play_event >,
+ // +---------+-------------+---------+---------------------+----------------------+
+ a_row < Playing , stop , Stopped , &p::stop_playback >,
+ a_row < Playing , pause , Paused , &p::pause_playback >,
+ a_row < Playing , open_close , Open , &p::stop_and_open >,
+ // +---------+-------------+---------+---------------------+----------------------+
+ a_row < Paused , end_pause , Playing , &p::resume_playback >,
+ a_row < Paused , stop , Stopped , &p::stop_playback >,
+ a_row < Paused , open_close , Open , &p::stop_and_open >,
+ // +---------+-------------+---------+---------------------+----------------------+
+ a_row < AllOk , error_found ,ErrorMode, &p::report_error >,
+ a_row <ErrorMode, end_error ,AllOk , &p::report_end_error >,
+ _row < AllOk , do_terminate,ErrorTerminate >
+ // +---------+-------------+---------+---------------------+----------------------+
+ > {};
+
+ // Replaces the default no-transition response.
+ template <class FSM,class Event>
+ void no_transition(Event const& , FSM&,int)
+ {
+ BOOST_ERROR("no_transition called!");
+ }
+ // init counters
+ template <class Event,class FSM>
+ void on_entry(Event const&,FSM& fsm)
+ {
+ fsm.template get_state<player_::Stopped&>().entry_counter=0;
+ fsm.template get_state<player_::Stopped&>().exit_counter=0;
+ fsm.template get_state<player_::Open&>().entry_counter=0;
+ fsm.template get_state<player_::Open&>().exit_counter=0;
+ fsm.template get_state<player_::Empty&>().entry_counter=0;
+ fsm.template get_state<player_::Empty&>().exit_counter=0;
+ fsm.template get_state<player_::Playing&>().entry_counter=0;
+ fsm.template get_state<player_::Playing&>().exit_counter=0;
+ fsm.template get_state<player_::Playing&>().template get_state<player_::Playing::Song1&>().entry_counter=0;
+ fsm.template get_state<player_::Playing&>().template get_state<player_::Playing::Song1&>().exit_counter=0;
+ fsm.template get_state<player_::Playing&>().template get_state<player_::Playing::Song2&>().entry_counter=0;
+ fsm.template get_state<player_::Playing&>().template get_state<player_::Playing::Song2&>().exit_counter=0;
+ fsm.template get_state<player_::Playing&>().template get_state<player_::Playing::Song3&>().entry_counter=0;
+ fsm.template get_state<player_::Playing&>().template get_state<player_::Playing::Song3&>().exit_counter=0;
+ fsm.template get_state<player_::Paused&>().entry_counter=0;
+ fsm.template get_state<player_::Paused&>().exit_counter=0;
+ fsm.template get_state<player_::AllOk&>().entry_counter=0;
+ fsm.template get_state<player_::AllOk&>().exit_counter=0;
+ fsm.template get_state<player_::ErrorMode&>().entry_counter=0;
+ fsm.template get_state<player_::ErrorMode&>().exit_counter=0;
+ fsm.template get_state<player_::ErrorTerminate&>().entry_counter=0;
+ fsm.template get_state<player_::ErrorTerminate&>().exit_counter=0;
+ }
+ };
+ // Pick a back-end
+ typedef msm::back::state_machine<player_> player;
+
+ //static char const* const state_names[] = { "Stopped", "Open", "Empty", "Playing", "Paused","AllOk","ErrorMode" };
+
+ BOOST_AUTO_TEST_CASE( my_test )
+ {
+ player p;
+ // needed to start the highest-level SM. This will call on_entry and mark the start of the SM
+ p.start();
+ // test deferred event
+ // deferred in Empty and Open, will be handled only after event cd_detected
+ p.process_event(play());
+ BOOST_CHECK_MESSAGE(p.current_state()[0] == 2,"Empty should be active"); //Empty
+ BOOST_CHECK_MESSAGE(p.get_state<player_::Open&>().exit_counter == 0,"Open exit not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<player_::Playing&>().entry_counter == 0,"Playing entry not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<player_::Empty&>().entry_counter == 1,"Empty entry not called correctly");
+ //flags
+ BOOST_CHECK_MESSAGE(p.is_flag_active<CDLoaded>() == false,"CDLoaded should not be active");
+ p.process_event(open_close());
+ BOOST_CHECK_MESSAGE(p.current_state()[0] == 1,"Open should be active"); //Open
+ BOOST_CHECK_MESSAGE(p.get_state<player_::Empty&>().exit_counter == 1,"Empty exit not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<player_::Open&>().entry_counter == 1,"Open entry not called correctly");
+ p.process_event(open_close());
+ BOOST_CHECK_MESSAGE(p.current_state()[0] == 2,"Empty should be active"); //Empty
+ BOOST_CHECK_MESSAGE(p.get_state<player_::Open&>().exit_counter == 1,"Open exit not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<player_::Empty&>().entry_counter == 2,"Empty entry not called correctly");
+ BOOST_CHECK_MESSAGE(p.can_close_drawer_counter == 1,"guard not called correctly");
+ //deferred event should have been processed
+ p.process_event(cd_detected("louie, louie"));
+ BOOST_CHECK_MESSAGE(p.current_state()[0] == 3,"Playing should be active"); //Playing
+ BOOST_CHECK_MESSAGE(p.get_state<player_::Empty&>().exit_counter == 2,"Empty exit not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<player_::Stopped&>().entry_counter == 1,"Stopped entry not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<player_::Stopped&>().exit_counter == 1,"Stopped exit not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<player_::Playing&>().entry_counter == 1,"Playing entry not called correctly");
+ BOOST_CHECK_MESSAGE(p.start_playback_counter == 1,"action not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<player_::Playing&>().current_state()[0] == 0,"Song1 should be active");
+ BOOST_CHECK_MESSAGE(
+ p.get_state<player_::Playing&>().get_state<player_::Playing::Song1&>().entry_counter == 1,
+ "Song1 entry not called correctly");
+
+ //flags
+ BOOST_CHECK_MESSAGE(p.is_flag_active<PlayingPaused>() == true,"PlayingPaused should be active");
+ BOOST_CHECK_MESSAGE(p.is_flag_active<FirstSongPlaying>() == true,"FirstSongPlaying should be active");
+
+
+ p.process_event(NextSong());
+ BOOST_CHECK_MESSAGE(p.current_state()[0] == 3,"Playing should be active"); //Playing
+ BOOST_CHECK_MESSAGE(p.get_state<player_::Playing&>().current_state()[0] == 1,"Song2 should be active");
+ BOOST_CHECK_MESSAGE(
+ p.get_state<player_::Playing&>().get_state<player_::Playing::Song2&>().entry_counter == 1,
+ "Song2 entry not called correctly");
+ BOOST_CHECK_MESSAGE(
+ p.get_state<player_::Playing&>().get_state<player_::Playing::Song1&>().exit_counter == 1,
+ "Song1 exit not called correctly");
+ BOOST_CHECK_MESSAGE(
+ p.get_state<player_::Playing&>().start_next_song_counter == 0,
+ "submachine action not called correctly");
+
+ p.process_event(NextSong());
+ BOOST_CHECK_MESSAGE(p.current_state()[0] == 3,"Playing should be active"); //Playing
+ BOOST_CHECK_MESSAGE(p.get_state<player_::Playing&>().current_state()[0] == 2,"Song3 should be active");
+ BOOST_CHECK_MESSAGE(
+ p.get_state<player_::Playing&>().get_state<player_::Playing::Song3&>().entry_counter == 1,
+ "Song3 entry not called correctly");
+ BOOST_CHECK_MESSAGE(
+ p.get_state<player_::Playing&>().get_state<player_::Playing::Song2&>().exit_counter == 1,
+ "Song2 exit not called correctly");
+ BOOST_CHECK_MESSAGE(
+ p.get_state<player_::Playing&>().start_next_song_counter == 1,
+ "submachine action not called correctly");
+
+ p.process_event(PreviousSong());
+ BOOST_CHECK_MESSAGE(p.current_state()[0] == 3,"Playing should be active"); //Playing
+ BOOST_CHECK_MESSAGE(p.get_state<player_::Playing&>().current_state()[0] == 1,"Song2 should be active");
+ BOOST_CHECK_MESSAGE(
+ p.get_state<player_::Playing&>().get_state<player_::Playing::Song2&>().entry_counter == 2,
+ "Song2 entry not called correctly");
+ BOOST_CHECK_MESSAGE(
+ p.get_state<player_::Playing&>().get_state<player_::Playing::Song3&>().exit_counter == 1,
+ "Song3 exit not called correctly");
+ BOOST_CHECK_MESSAGE(
+ p.get_state<player_::Playing&>().start_prev_song_guard_counter == 1,
+ "submachine guard not called correctly");
+ //flags
+ BOOST_CHECK_MESSAGE(p.is_flag_active<PlayingPaused>() == true,"PlayingPaused should be active");
+ BOOST_CHECK_MESSAGE(p.is_flag_active<FirstSongPlaying>() == false,"FirstSongPlaying should not be active");
+
+ p.process_event(pause());
+ BOOST_CHECK_MESSAGE(p.current_state()[0] == 4,"Paused should be active"); //Paused
+ BOOST_CHECK_MESSAGE(p.get_state<player_::Playing&>().exit_counter == 1,"Playing exit not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<player_::Paused&>().entry_counter == 1,"Paused entry not called correctly");
+ //flags
+ BOOST_CHECK_MESSAGE(p.is_flag_active<PlayingPaused>() == true,"PlayingPaused should be active");
+
+ // go back to Playing
+ p.process_event(end_pause());
+ BOOST_CHECK_MESSAGE(p.current_state()[0] == 3,"Playing should be active"); //Playing
+ BOOST_CHECK_MESSAGE(p.get_state<player_::Paused&>().exit_counter == 1,"Paused exit not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<player_::Playing&>().entry_counter == 2,"Playing entry not called correctly");
+
+ p.process_event(pause());
+ BOOST_CHECK_MESSAGE(p.current_state()[0] == 4,"Paused should be active"); //Paused
+ BOOST_CHECK_MESSAGE(p.get_state<player_::Playing&>().exit_counter == 2,"Playing exit not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<player_::Paused&>().entry_counter == 2,"Paused entry not called correctly");
+
+ p.process_event(stop());
+ BOOST_CHECK_MESSAGE(p.current_state()[0] == 0,"Stopped should be active"); //Stopped
+ BOOST_CHECK_MESSAGE(p.get_state<player_::Paused&>().exit_counter == 2,"Paused exit not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<player_::Stopped&>().entry_counter == 2,"Stopped entry not called correctly");
+ //flags
+ BOOST_CHECK_MESSAGE(p.is_flag_active<PlayingPaused>() == false,"PlayingPaused should not be active");
+ BOOST_CHECK_MESSAGE(p.is_flag_active<CDLoaded>() == true,"CDLoaded should be active");
+ //BOOST_CHECK_MESSAGE(p.is_flag_active<CDLoaded,player::Flag_AND>() == false,"CDLoaded with AND should not be active");
+
+ p.process_event(stop());
+ BOOST_CHECK_MESSAGE(p.current_state()[0] == 0,"Stopped should be active"); //Stopped
+ BOOST_CHECK_MESSAGE(p.get_state<player_::Stopped&>().exit_counter == 2,"Stopped exit not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<player_::Stopped&>().entry_counter == 3,"Stopped entry not called correctly");
+
+ //test interrupt
+ BOOST_CHECK_MESSAGE(p.current_state()[1] == 5,"AllOk should be active"); //AllOk
+ p.process_event(error_found());
+ BOOST_CHECK_MESSAGE(p.current_state()[1] == 6,"ErrorMode should be active"); //ErrorMode
+ BOOST_CHECK_MESSAGE(p.get_state<player_::AllOk&>().exit_counter == 1,"AllOk exit not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<player_::ErrorMode&>().entry_counter == 1,"ErrorMode entry not called correctly");
+
+ // try generating more events
+ p.process_event(play());
+ BOOST_CHECK_MESSAGE(p.current_state()[1] == 6,"ErrorMode should be active"); //ErrorMode
+ BOOST_CHECK_MESSAGE(p.get_state<player_::AllOk&>().exit_counter == 1,"AllOk exit not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<player_::ErrorMode&>().entry_counter == 1,"ErrorMode entry not called correctly");
+ BOOST_CHECK_MESSAGE(p.current_state()[0] == 0,"Stopped should be active"); //Stopped
+ BOOST_CHECK_MESSAGE(p.get_state<player_::Stopped&>().exit_counter == 2,"Stopped exit not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<player_::Stopped&>().entry_counter == 3,"Stopped entry not called correctly");
+
+ p.process_event(end_error());
+ BOOST_CHECK_MESSAGE(p.current_state()[1] == 5,"AllOk should be active"); //AllOk
+ BOOST_CHECK_MESSAGE(p.get_state<player_::ErrorMode&>().exit_counter == 1,"ErrorMode exit not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<player_::AllOk&>().entry_counter == 2,"AllOk entry not called correctly");
+
+ p.process_event(play());
+ BOOST_CHECK_MESSAGE(p.current_state()[0] == 3,"Playing should be active"); //Playing
+ BOOST_CHECK_MESSAGE(p.get_state<player_::Stopped&>().exit_counter == 3,"Stopped exit not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<player_::Playing&>().entry_counter == 3,"Playing entry not called correctly");
+
+ //test terminate
+ BOOST_CHECK_MESSAGE(p.current_state()[1] == 5,"AllOk should be active"); //AllOk
+ p.process_event(do_terminate());
+ BOOST_CHECK_MESSAGE(p.current_state()[1] == 7,"ErrorTerminate should be active"); //ErrorTerminate
+ BOOST_CHECK_MESSAGE(p.get_state<player_::AllOk&>().exit_counter == 2,"AllOk exit not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<player_::ErrorTerminate&>().entry_counter == 1,"ErrorTerminate entry not called correctly");
+
+ // try generating more events
+ p.process_event(stop());
+ BOOST_CHECK_MESSAGE(p.current_state()[1] == 7,"ErrorTerminate should be active"); //ErrorTerminate
+ BOOST_CHECK_MESSAGE(p.get_state<player_::ErrorTerminate&>().exit_counter == 0,"ErrorTerminate exit not called correctly");
+ BOOST_CHECK_MESSAGE(p.current_state()[0] == 3,"Playing should be active"); //Playing
+ BOOST_CHECK_MESSAGE(p.get_state<player_::Playing&>().exit_counter == 2,"Playing exit not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<player_::Stopped&>().entry_counter == 3,"Stopped entry not called correctly");
+
+ p.process_event(end_error());
+ BOOST_CHECK_MESSAGE(p.current_state()[1] == 7,"ErrorTerminate should be active"); //ErrorTerminate
+ BOOST_CHECK_MESSAGE(p.current_state()[0] == 3,"Playing should be active"); //Playing
+ BOOST_CHECK_MESSAGE(p.get_state<player_::Playing&>().exit_counter == 2,"Playing exit not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<player_::Stopped&>().entry_counter == 3,"Stopped entry not called correctly");
+
+ p.process_event(stop());
+ BOOST_CHECK_MESSAGE(p.current_state()[1] == 7,"ErrorTerminate should be active"); //ErrorTerminate
+ BOOST_CHECK_MESSAGE(p.current_state()[0] == 3,"Playing should be active"); //Playing
+ BOOST_CHECK_MESSAGE(p.get_state<player_::Playing&>().exit_counter == 2,"Playing exit not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<player_::Stopped&>().entry_counter == 3,"Stopped entry not called correctly");
+
+ }
+}
+
diff --git a/src/boost/libs/msm/test/OrthogonalDeferredEuml.cpp b/src/boost/libs/msm/test/OrthogonalDeferredEuml.cpp
new file mode 100644
index 000000000..272d954fd
--- /dev/null
+++ b/src/boost/libs/msm/test/OrthogonalDeferredEuml.cpp
@@ -0,0 +1,359 @@
+// 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 <iostream>
+// back-end
+#include <boost/msm/back/state_machine.hpp>
+//front-end
+#include <boost/msm/front/state_machine_def.hpp>
+#include <boost/msm/front/euml/euml.hpp>
+#ifndef BOOST_MSM_NONSTANDALONE_TEST
+#define BOOST_TEST_MODULE MyTest
+#endif
+#include <boost/test/unit_test.hpp>
+
+namespace msm = boost::msm;
+namespace mpl = boost::mpl;
+using namespace boost::msm::front::euml;
+
+namespace
+{
+ // events
+ BOOST_MSM_EUML_EVENT(play)
+ BOOST_MSM_EUML_EVENT(end_pause)
+ BOOST_MSM_EUML_EVENT(stop)
+ BOOST_MSM_EUML_EVENT(pause)
+ BOOST_MSM_EUML_EVENT(open_close)
+ BOOST_MSM_EUML_EVENT(next_song)
+ BOOST_MSM_EUML_EVENT(previous_song)
+ BOOST_MSM_EUML_EVENT(error_found)
+ BOOST_MSM_EUML_EVENT(end_error)
+ BOOST_MSM_EUML_EVENT(do_terminate)
+
+ // Flags. Allow information about a property of the current state
+ BOOST_MSM_EUML_FLAG(PlayingPaused)
+ BOOST_MSM_EUML_FLAG(CDLoaded)
+ BOOST_MSM_EUML_FLAG(FirstSongPlaying)
+
+ // A "complicated" event type that carries some data.
+ BOOST_MSM_EUML_DECLARE_ATTRIBUTE(std::string,cd_name)
+ BOOST_MSM_EUML_ATTRIBUTES((attributes_ << cd_name ), cd_detected_attributes)
+ BOOST_MSM_EUML_EVENT_WITH_ATTRIBUTES(cd_detected,cd_detected_attributes)
+
+ //states
+ BOOST_MSM_EUML_DECLARE_ATTRIBUTE(unsigned int,entry_counter)
+ BOOST_MSM_EUML_DECLARE_ATTRIBUTE(unsigned int,exit_counter)
+
+ BOOST_MSM_EUML_STATE(( ++state_(entry_counter),++state_(exit_counter),
+ attributes_ << entry_counter << exit_counter, configure_ << play),Empty)
+ BOOST_MSM_EUML_STATE(( ++state_(entry_counter),++state_(exit_counter),
+ attributes_ << entry_counter << exit_counter, configure_<< CDLoaded << play),Open)
+ BOOST_MSM_EUML_STATE(( ++state_(entry_counter),++state_(exit_counter),
+ attributes_ << entry_counter << exit_counter, configure_<< CDLoaded),Stopped)
+ BOOST_MSM_EUML_STATE(( ++state_(entry_counter),++state_(exit_counter),
+ attributes_ << entry_counter << exit_counter, configure_<< CDLoaded << PlayingPaused),Paused)
+
+ BOOST_MSM_EUML_STATE(( ++state_(entry_counter),++state_(exit_counter),attributes_ << entry_counter << exit_counter),AllOk)
+ BOOST_MSM_EUML_TERMINATE_STATE(( ++state_(entry_counter),++state_(exit_counter),attributes_ << entry_counter << exit_counter),
+ ErrorTerminate)
+ BOOST_MSM_EUML_INTERRUPT_STATE(( end_error,++state_(entry_counter),++state_(exit_counter),attributes_ << entry_counter << exit_counter),
+ ErrorMode)
+
+ // Playing is now a state machine itself.
+ BOOST_MSM_EUML_DECLARE_ATTRIBUTE(unsigned int,start_next_song_counter)
+ BOOST_MSM_EUML_DECLARE_ATTRIBUTE(unsigned int,start_prev_song_guard_counter)
+
+ BOOST_MSM_EUML_STATE(( ++state_(entry_counter),++state_(exit_counter),
+ attributes_ << entry_counter << exit_counter, configure_<< FirstSongPlaying ),Song1)
+ BOOST_MSM_EUML_STATE(( ++state_(entry_counter),++state_(exit_counter),attributes_ << entry_counter << exit_counter),Song2)
+ BOOST_MSM_EUML_STATE(( ++state_(entry_counter),++state_(exit_counter),attributes_ << entry_counter << exit_counter),Song3)
+
+ // Playing has a transition table
+ BOOST_MSM_EUML_TRANSITION_TABLE((
+ // +------------------------------------------------------------------------------+
+ Song2 == Song1 + next_song ,
+ Song1 == Song2 + previous_song [True_()] / ++fsm_(start_prev_song_guard_counter) ,
+ Song3 == Song2 + next_song / ++fsm_(start_next_song_counter) ,
+ Song2 == Song3 + previous_song [True_()] / ++fsm_(start_prev_song_guard_counter)
+ // +------------------------------------------------------------------------------+
+ ),playing_transition_table )
+
+ BOOST_MSM_EUML_DECLARE_STATE_MACHINE( (playing_transition_table, //STT
+ init_ << Song1, // Init State
+ ++state_(entry_counter), // Entry
+ ++state_(exit_counter), // Exit
+ attributes_ << entry_counter << exit_counter
+ << start_next_song_counter
+ << start_prev_song_guard_counter, // Attributes
+ configure_<< PlayingPaused << CDLoaded //flags
+ ),Playing_)
+
+ // back-end
+ typedef msm::back::state_machine<Playing_> Playing_type;
+ Playing_type const Playing;
+
+ //fsm
+ BOOST_MSM_EUML_DECLARE_ATTRIBUTE(unsigned int,start_playback_counter)
+ BOOST_MSM_EUML_DECLARE_ATTRIBUTE(unsigned int,can_close_drawer_counter)
+ BOOST_MSM_EUML_DECLARE_ATTRIBUTE(unsigned int,report_error_counter)
+ BOOST_MSM_EUML_DECLARE_ATTRIBUTE(unsigned int,report_end_error_counter)
+ BOOST_MSM_EUML_ACTION(No_Transition)
+ {
+ template <class FSM,class Event>
+ void operator()(Event const&,FSM&,int)
+ {
+ BOOST_FAIL("no_transition called!");
+ }
+ };
+
+ BOOST_MSM_EUML_TRANSITION_TABLE((
+ Playing == Stopped + play / ++fsm_(start_playback_counter),
+ Playing == Paused + end_pause ,
+ // +------------------------------------------------------------------------------+
+ Empty == Open + open_close / ++fsm_(can_close_drawer_counter),
+ // +------------------------------------------------------------------------------+
+ Open == Empty + open_close ,
+ Open == Paused + open_close ,
+ Open == Stopped + open_close ,
+ Open == Playing + open_close ,
+ // +------------------------------------------------------------------------------+
+ Paused == Playing + pause ,
+ // +------------------------------------------------------------------------------+
+ Stopped == Playing + stop ,
+ Stopped == Paused + stop ,
+ Stopped == Empty + cd_detected ,
+ Stopped == Stopped + stop ,
+ ErrorMode == AllOk + error_found / ++fsm_(report_error_counter),
+ AllOk == ErrorMode+ end_error / ++fsm_(report_end_error_counter),
+ ErrorTerminate== AllOk +do_terminate
+ // +------------------------------------------------------------------------------+
+ ),transition_table)
+
+ BOOST_MSM_EUML_DECLARE_STATE_MACHINE(( transition_table, //STT
+ init_ << Empty << AllOk, // Init State
+ no_action, // Entry
+ no_action, // Exit
+ attributes_ << start_playback_counter << can_close_drawer_counter
+ << report_error_counter << report_end_error_counter, // Attributes
+ configure_ << no_configure_, // configuration
+ No_Transition // no_transition handler
+ ),
+ player_) //fsm name
+
+ // Pick a back-end
+ typedef msm::back::state_machine<player_> player;
+
+ //static char const* const state_names[] = { "Stopped", "Paused","Open", "Empty", "Playing" ,"AllOk","ErrorMode","ErrorTerminate" };
+
+ BOOST_AUTO_TEST_CASE( my_test )
+ {
+ player p;
+ // needed to start the highest-level SM. This will call on_entry and mark the start of the SM
+ p.start();
+ // test deferred event
+ // deferred in Empty and Open, will be handled only after event cd_detected
+ p.process_event(play);
+ BOOST_CHECK_MESSAGE(p.current_state()[0] == 3,"Empty should be active"); //Empty
+ BOOST_CHECK_MESSAGE(p.get_state<BOOST_MSM_EUML_STATE_NAME(Open)&>().get_attribute(exit_counter) == 0,
+ "Open exit not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<Playing_type&>().get_attribute(entry_counter) == 0,"Playing entry not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<BOOST_MSM_EUML_STATE_NAME(Empty)&>().get_attribute(entry_counter) == 1,
+ "Empty entry not called correctly");
+ //flags
+ BOOST_CHECK_MESSAGE(p.is_flag_active<BOOST_MSM_EUML_FLAG_NAME(CDLoaded)>() == false,"CDLoaded should not be active");
+
+ p.process_event(open_close);
+ BOOST_CHECK_MESSAGE(p.current_state()[0] == 2,"Open should be active"); //Open
+ BOOST_CHECK_MESSAGE(p.get_state<BOOST_MSM_EUML_STATE_NAME(Empty)&>().get_attribute(exit_counter) == 1,
+ "Empty exit not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<BOOST_MSM_EUML_STATE_NAME(Open)&>().get_attribute(entry_counter) == 1,
+ "Open entry not called correctly");
+
+ p.process_event(open_close);
+ BOOST_CHECK_MESSAGE(p.current_state()[0] == 3,"Empty should be active"); //Empty
+ BOOST_CHECK_MESSAGE(p.get_state<BOOST_MSM_EUML_STATE_NAME(Open)&>().get_attribute(exit_counter) == 1,
+ "Open exit not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<BOOST_MSM_EUML_STATE_NAME(Empty)&>().get_attribute(entry_counter) == 2,
+ "Empty entry not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_attribute(can_close_drawer_counter) == 1,"guard not called correctly");
+
+ //deferred event should have been processed
+ p.process_event(cd_detected("louie, louie"));
+ BOOST_CHECK_MESSAGE(p.current_state()[0] == 4,"Playing should be active"); //Playing
+ BOOST_CHECK_MESSAGE(p.get_state<BOOST_MSM_EUML_STATE_NAME(Empty)&>().get_attribute(exit_counter) == 2,
+ "Empty exit not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<BOOST_MSM_EUML_STATE_NAME(Stopped)&>().get_attribute(entry_counter) == 1,
+ "Stopped entry not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<BOOST_MSM_EUML_STATE_NAME(Stopped)&>().get_attribute(exit_counter) == 1,
+ "Stopped exit not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<Playing_type&>().get_attribute(entry_counter) == 1,"Playing entry not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_attribute(start_playback_counter) == 1,"action not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<Playing_type&>().current_state()[0] == 0,"Song1 should be active");
+ BOOST_CHECK_MESSAGE(
+ p.get_state<Playing_type&>().get_state<BOOST_MSM_EUML_STATE_NAME(Song1)&>().get_attribute(entry_counter) == 1,
+ "Song1 entry not called correctly");
+
+ //flags
+ BOOST_CHECK_MESSAGE(p.is_flag_active<BOOST_MSM_EUML_FLAG_NAME(PlayingPaused)>() == true,"PlayingPaused should be active");
+ BOOST_CHECK_MESSAGE(p.is_flag_active<BOOST_MSM_EUML_FLAG_NAME(FirstSongPlaying)>() == true,"FirstSongPlaying should be active");
+
+
+ p.process_event(next_song);
+ BOOST_CHECK_MESSAGE(p.current_state()[0] == 4,"Playing should be active"); //Playing
+ BOOST_CHECK_MESSAGE(p.get_state<Playing_type&>().current_state()[0] == 1,"Song2 should be active");
+ BOOST_CHECK_MESSAGE(
+ p.get_state<Playing_type&>().get_state<BOOST_MSM_EUML_STATE_NAME(Song2)&>().get_attribute(entry_counter) == 1,
+ "Song2 entry not called correctly");
+ BOOST_CHECK_MESSAGE(
+ p.get_state<Playing_type&>().get_state<BOOST_MSM_EUML_STATE_NAME(Song1)&>().get_attribute(exit_counter) == 1,
+ "Song1 exit not called correctly");
+ BOOST_CHECK_MESSAGE(
+ p.get_state<Playing_type&>().get_attribute(start_next_song_counter) == 0,
+ "submachine action not called correctly");
+
+ p.process_event(next_song);
+ BOOST_CHECK_MESSAGE(p.current_state()[0] == 4,"Playing should be active"); //Playing
+ BOOST_CHECK_MESSAGE(p.get_state<Playing_type&>().current_state()[0] == 2,"Song3 should be active");
+ BOOST_CHECK_MESSAGE(
+ p.get_state<Playing_type&>().get_state<BOOST_MSM_EUML_STATE_NAME(Song3)&>().get_attribute(entry_counter) == 1,
+ "Song3 entry not called correctly");
+ BOOST_CHECK_MESSAGE(
+ p.get_state<Playing_type&>().get_state<BOOST_MSM_EUML_STATE_NAME(Song2)&>().get_attribute(exit_counter) == 1,
+ "Song2 exit not called correctly");
+ BOOST_CHECK_MESSAGE(
+ p.get_state<Playing_type&>().get_attribute(start_next_song_counter) == 1,
+ "submachine action not called correctly");
+
+ p.process_event(previous_song);
+ BOOST_CHECK_MESSAGE(p.current_state()[0] == 4,"Playing should be active"); //Playing
+ BOOST_CHECK_MESSAGE(p.get_state<Playing_type&>().current_state()[0] == 1,"Song2 should be active");
+ BOOST_CHECK_MESSAGE(
+ p.get_state<Playing_type&>().get_state<BOOST_MSM_EUML_STATE_NAME(Song2)&>().get_attribute(entry_counter) == 2,
+ "Song2 entry not called correctly");
+ BOOST_CHECK_MESSAGE(
+ p.get_state<Playing_type&>().get_state<BOOST_MSM_EUML_STATE_NAME(Song3)&>().get_attribute(exit_counter) == 1,
+ "Song3 exit not called correctly");
+ BOOST_CHECK_MESSAGE(
+ p.get_state<Playing_type&>().get_attribute(start_prev_song_guard_counter) == 1,
+ "submachine guard not called correctly");
+ //flags
+ BOOST_CHECK_MESSAGE(p.is_flag_active<BOOST_MSM_EUML_FLAG_NAME(PlayingPaused)>() == true,"PlayingPaused should be active");
+ BOOST_CHECK_MESSAGE(p.is_flag_active<BOOST_MSM_EUML_FLAG_NAME(FirstSongPlaying)>() == false,"FirstSongPlaying should not be active");
+
+ p.process_event(pause());
+ BOOST_CHECK_MESSAGE(p.current_state()[0] == 1,"Paused should be active"); //Paused
+ BOOST_CHECK_MESSAGE(p.get_state<Playing_type&>().get_attribute(exit_counter) == 1,"Playing exit not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<BOOST_MSM_EUML_STATE_NAME(Paused)&>().get_attribute(entry_counter) == 1,
+ "Paused entry not called correctly");
+ //flags
+ BOOST_CHECK_MESSAGE(p.is_flag_active<BOOST_MSM_EUML_FLAG_NAME(PlayingPaused)>() == true,"PlayingPaused should be active");
+
+ // go back to Playing
+ p.process_event(end_pause);
+ BOOST_CHECK_MESSAGE(p.current_state()[0] == 4,"Playing should be active"); //Playing
+ BOOST_CHECK_MESSAGE(p.get_state<BOOST_MSM_EUML_STATE_NAME(Paused)&>().get_attribute(exit_counter) == 1,
+ "Paused exit not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<Playing_type&>().get_attribute(entry_counter) == 2,"Playing entry not called correctly");
+
+ p.process_event(pause);
+ BOOST_CHECK_MESSAGE(p.current_state()[0] == 1,"Paused should be active"); //Paused
+ BOOST_CHECK_MESSAGE(p.get_state<Playing_type&>().get_attribute(exit_counter) == 2,"Playing exit not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<BOOST_MSM_EUML_STATE_NAME(Paused)&>().get_attribute(entry_counter) == 2,
+ "Paused entry not called correctly");
+
+ p.process_event(stop);
+ BOOST_CHECK_MESSAGE(p.current_state()[0] == 0,"Stopped should be active"); //Stopped
+ BOOST_CHECK_MESSAGE(p.get_state<BOOST_MSM_EUML_STATE_NAME(Paused)&>().get_attribute(exit_counter) == 2,
+ "Paused exit not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<BOOST_MSM_EUML_STATE_NAME(Stopped)&>().get_attribute(entry_counter) == 2,
+ "Stopped entry not called correctly");
+ //flags
+ BOOST_CHECK_MESSAGE(p.is_flag_active<BOOST_MSM_EUML_FLAG_NAME(PlayingPaused)>() == false,"PlayingPaused should not be active");
+ BOOST_CHECK_MESSAGE(p.is_flag_active<BOOST_MSM_EUML_FLAG_NAME(CDLoaded)>() == true,"CDLoaded should be active");
+ //BOOST_CHECK_MESSAGE(p.is_flag_active<BOOST_MSM_EUML_FLAG_NAME(CDLoaded),player::Flag_AND>() == false,"CDLoaded with AND should not be active");
+
+ p.process_event(stop);
+ BOOST_CHECK_MESSAGE(p.current_state()[0] == 0,"Stopped should be active"); //Stopped
+ BOOST_CHECK_MESSAGE(p.get_state<BOOST_MSM_EUML_STATE_NAME(Stopped)&>().get_attribute(exit_counter) == 2,
+ "Stopped exit not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<BOOST_MSM_EUML_STATE_NAME(Stopped)&>().get_attribute(entry_counter) == 3,
+ "Stopped entry not called correctly");
+
+ //test interrupt
+ BOOST_CHECK_MESSAGE(p.current_state()[1] == 5,"AllOk should be active"); //AllOk
+ p.process_event(error_found);
+ BOOST_CHECK_MESSAGE(p.current_state()[1] == 6,"ErrorMode should be active"); //ErrorMode
+ BOOST_CHECK_MESSAGE(p.get_state<BOOST_MSM_EUML_STATE_NAME(AllOk)&>().get_attribute(exit_counter) == 1,
+ "AllOk exit not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<BOOST_MSM_EUML_STATE_NAME(ErrorMode)&>().get_attribute(entry_counter) == 1,
+ "ErrorMode entry not called correctly");
+
+ // try generating more events
+ p.process_event(play);
+ BOOST_CHECK_MESSAGE(p.current_state()[1] == 6,"ErrorMode should be active"); //ErrorMode
+ BOOST_CHECK_MESSAGE(p.get_state<BOOST_MSM_EUML_STATE_NAME(AllOk)&>().get_attribute(exit_counter) == 1,
+ "AllOk exit not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<BOOST_MSM_EUML_STATE_NAME(ErrorMode)&>().get_attribute(entry_counter) == 1,
+ "ErrorMode entry not called correctly");
+ BOOST_CHECK_MESSAGE(p.current_state()[0] == 0,"Stopped should be active"); //Stopped
+ BOOST_CHECK_MESSAGE(p.get_state<BOOST_MSM_EUML_STATE_NAME(Stopped)&>().get_attribute(exit_counter) == 2,
+ "Stopped exit not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<BOOST_MSM_EUML_STATE_NAME(Stopped)&>().get_attribute(entry_counter) == 3,
+ "Stopped entry not called correctly");
+
+ p.process_event(end_error);
+ BOOST_CHECK_MESSAGE(p.current_state()[1] == 5,"AllOk should be active"); //AllOk
+ BOOST_CHECK_MESSAGE(p.get_state<BOOST_MSM_EUML_STATE_NAME(ErrorMode)&>().get_attribute(exit_counter) == 1,
+ "ErrorMode exit not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<BOOST_MSM_EUML_STATE_NAME(AllOk)&>().get_attribute(entry_counter) == 2,
+ "AllOk entry not called correctly");
+
+ p.process_event(play);
+ BOOST_CHECK_MESSAGE(p.current_state()[0] == 4,"Playing should be active"); //Playing
+ BOOST_CHECK_MESSAGE(p.get_state<BOOST_MSM_EUML_STATE_NAME(Stopped)&>().get_attribute(exit_counter) == 3,
+ "Stopped exit not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<Playing_type&>().get_attribute(entry_counter) == 3,"Playing entry not called correctly");
+
+ //test terminate
+ BOOST_CHECK_MESSAGE(p.current_state()[1] == 5,"AllOk should be active"); //AllOk
+ p.process_event(do_terminate);
+ BOOST_CHECK_MESSAGE(p.current_state()[1] == 7,"ErrorTerminate should be active"); //ErrorTerminate
+ BOOST_CHECK_MESSAGE(p.get_state<BOOST_MSM_EUML_STATE_NAME(AllOk)&>().get_attribute(exit_counter) == 2,
+ "AllOk exit not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<BOOST_MSM_EUML_STATE_NAME(ErrorTerminate)&>().get_attribute(entry_counter) == 1,
+ "ErrorTerminate entry not called correctly");
+
+ // try generating more events
+ p.process_event(stop);
+ BOOST_CHECK_MESSAGE(p.current_state()[1] == 7,"ErrorTerminate should be active"); //ErrorTerminate
+ BOOST_CHECK_MESSAGE(p.get_state<BOOST_MSM_EUML_STATE_NAME(ErrorTerminate)&>().get_attribute(exit_counter) == 0,
+ "ErrorTerminate exit not called correctly");
+ BOOST_CHECK_MESSAGE(p.current_state()[0] == 4,"Playing should be active"); //Playing
+ BOOST_CHECK_MESSAGE(p.get_state<Playing_type&>().get_attribute(exit_counter) == 2,"Playing exit not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<BOOST_MSM_EUML_STATE_NAME(Stopped)&>().get_attribute(entry_counter) == 3,
+ "Stopped entry not called correctly");
+
+ p.process_event(end_error());
+ BOOST_CHECK_MESSAGE(p.current_state()[1] == 7,"ErrorTerminate should be active"); //ErrorTerminate
+ BOOST_CHECK_MESSAGE(p.current_state()[0] == 4,"Playing should be active"); //Playing
+ BOOST_CHECK_MESSAGE(p.get_state<Playing_type&>().get_attribute(exit_counter) == 2,"Playing exit not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<BOOST_MSM_EUML_STATE_NAME(Stopped)&>().get_attribute(entry_counter) == 3,
+ "Stopped entry not called correctly");
+
+ p.process_event(stop());
+ BOOST_CHECK_MESSAGE(p.current_state()[1] == 7,"ErrorTerminate should be active"); //ErrorTerminate
+ BOOST_CHECK_MESSAGE(p.current_state()[0] == 4,"Playing should be active"); //Playing
+ BOOST_CHECK_MESSAGE(p.get_state<Playing_type&>().get_attribute(exit_counter) == 2,"Playing exit not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<BOOST_MSM_EUML_STATE_NAME(Stopped)&>().get_attribute(entry_counter) == 3,
+ "Stopped entry not called correctly");
+
+ }
+}
+
diff --git a/src/boost/libs/msm/test/Serialize.cpp b/src/boost/libs/msm/test/Serialize.cpp
new file mode 100644
index 000000000..ed3035099
--- /dev/null
+++ b/src/boost/libs/msm/test/Serialize.cpp
@@ -0,0 +1,311 @@
+// 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 <iostream>
+// back-end
+#include <boost/msm/back/state_machine.hpp>
+//front-end
+#include <boost/msm/front/state_machine_def.hpp>
+#ifndef BOOST_MSM_NONSTANDALONE_TEST
+#define BOOST_TEST_MODULE MyTest
+#endif
+#include <boost/test/unit_test.hpp>
+// include headers that implement a archive in simple text format
+#include <boost/archive/text_oarchive.hpp>
+#include <boost/archive/text_iarchive.hpp>
+#include <boost/serialization/tracking.hpp>
+
+#include <fstream>
+
+namespace msm = boost::msm;
+namespace mpl = boost::mpl;
+
+namespace
+{
+ // events
+ struct play {};
+ struct end_pause {};
+ struct stop {};
+ struct pause {};
+ struct open_close {};
+
+ // A "complicated" event type that carries some data.
+ enum DiskTypeEnum
+ {
+ DISK_CD=0,
+ DISK_DVD=1
+ };
+ struct cd_detected
+ {
+ cd_detected(std::string name, DiskTypeEnum diskType)
+ : name(name),
+ disc_type(diskType)
+ {}
+
+ std::string name;
+ DiskTypeEnum disc_type;
+ };
+
+ // front-end: define the FSM structure
+ struct player_ : public msm::front::state_machine_def<player_>
+ {
+ unsigned int start_playback_counter;
+ unsigned int can_close_drawer_counter;
+ int front_end_data;
+
+ player_():
+ start_playback_counter(0),
+ can_close_drawer_counter(0),
+ front_end_data(4)
+ {}
+
+ //we want to serialize some data contained by the front-end
+ // to achieve this, ask for it
+ typedef int do_serialize;
+ // and provide a serialize
+ template<class Archive>
+ void serialize(Archive & ar, const unsigned int )
+ {
+ ar & front_end_data;
+ }
+
+ // The list of FSM states
+ struct Empty : 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;
+ int exit_counter;
+ int some_dummy_data;
+ // we want Empty to be serialized
+ typedef int do_serialize;
+ template<class Archive>
+ void serialize(Archive & ar, const unsigned int )
+ {
+ ar & some_dummy_data;
+ }
+
+ };
+ struct Open : 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;
+ int exit_counter;
+ };
+
+ // sm_ptr still supported but deprecated as functors are a much better way to do the same thing
+ struct Stopped : 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;
+ int exit_counter;
+ };
+
+ struct Playing : 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;
+ int exit_counter;
+ };
+
+ // state not defining any entry or exit
+ struct Paused : 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;
+ int exit_counter;
+ };
+
+ // the initial state of the player SM. Must be defined
+ typedef Empty initial_state;
+
+ // transition actions
+ void start_playback(play const&) {++start_playback_counter; }
+ void open_drawer(open_close const&) { }
+ void store_cd_info(cd_detected const&) { }
+ void stop_playback(stop const&) { }
+ void pause_playback(pause const&) { }
+ void resume_playback(end_pause const&) { }
+ void stop_and_open(open_close const&) { }
+ void stopped_again(stop const&){}
+ // guard conditions
+ bool good_disk_format(cd_detected const& evt)
+ {
+ // to test a guard condition, let's say we understand only CDs, not DVD
+ if (evt.disc_type != DISK_CD)
+ {
+ return false;
+ }
+ return true;
+ }
+ bool can_close_drawer(open_close const&)
+ {
+ ++can_close_drawer_counter;
+ return true;
+ }
+
+ typedef player_ p; // makes transition table cleaner
+
+ // Transition table for player
+ struct transition_table : mpl::vector<
+ // Start Event Next Action Guard
+ // +---------+-------------+---------+---------------------+----------------------+
+ a_row < Stopped , play , Playing , &p::start_playback >,
+ a_row < Stopped , open_close , Open , &p::open_drawer >,
+ _row < Stopped , stop , Stopped >,
+ // +---------+-------------+---------+---------------------+----------------------+
+ g_row < Open , open_close , Empty , &p::can_close_drawer >,
+ // +---------+-------------+---------+---------------------+----------------------+
+ a_row < Empty , open_close , Open , &p::open_drawer >,
+ row < Empty , cd_detected , Stopped , &p::store_cd_info ,&p::good_disk_format >,
+ // +---------+-------------+---------+---------------------+----------------------+
+ a_row < Playing , stop , Stopped , &p::stop_playback >,
+ a_row < Playing , pause , Paused , &p::pause_playback >,
+ a_row < Playing , open_close , Open , &p::stop_and_open >,
+ // +---------+-------------+---------+---------------------+----------------------+
+ a_row < Paused , end_pause , Playing , &p::resume_playback >,
+ a_row < Paused , stop , Stopped , &p::stop_playback >,
+ a_row < Paused , open_close , Open , &p::stop_and_open >
+ // +---------+-------------+---------+---------------------+----------------------+
+ > {};
+ // Replaces the default no-transition response.
+ template <class FSM,class Event>
+ void no_transition(Event const& , FSM&,int)
+ {
+ BOOST_FAIL("no_transition called!");
+ }
+ // init counters
+ template <class Event,class FSM>
+ void on_entry(Event const&,FSM& fsm)
+ {
+ fsm.template get_state<player_::Stopped&>().entry_counter=0;
+ fsm.template get_state<player_::Stopped&>().exit_counter=0;
+ fsm.template get_state<player_::Open&>().entry_counter=0;
+ fsm.template get_state<player_::Open&>().exit_counter=0;
+ fsm.template get_state<player_::Empty&>().entry_counter=0;
+ fsm.template get_state<player_::Empty&>().exit_counter=0;
+ fsm.template get_state<player_::Empty&>().some_dummy_data=3;
+ fsm.template get_state<player_::Playing&>().entry_counter=0;
+ fsm.template get_state<player_::Playing&>().exit_counter=0;
+ fsm.template get_state<player_::Paused&>().entry_counter=0;
+ fsm.template get_state<player_::Paused&>().exit_counter=0;
+ }
+
+ };
+ // Pick a back-end
+ typedef msm::back::state_machine<player_> player;
+
+// static char const* const state_names[] = { "Stopped", "Open", "Empty", "Playing", "Paused" };
+
+
+ BOOST_AUTO_TEST_CASE( my_test )
+ {
+ player p;
+
+ p.start();
+ BOOST_CHECK_MESSAGE(p.get_state<player_::Empty&>().entry_counter == 1,"Empty entry not called correctly");
+
+ p.process_event(open_close());
+ BOOST_CHECK_MESSAGE(p.current_state()[0] == 1,"Open should be active"); //Open
+ BOOST_CHECK_MESSAGE(p.get_state<player_::Empty&>().exit_counter == 1,"Empty exit not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<player_::Open&>().entry_counter == 1,"Open entry not called correctly");
+
+ // test the serialization
+ std::ofstream ofs("fsm.txt");
+ // save fsm to archive (current state is Open)
+ {
+ boost::archive::text_oarchive oa(ofs);
+ // write class instance to archive
+ oa << p;
+ }
+ // reload fsm in state Open
+ player p2;
+ {
+ // create and open an archive for input
+ std::ifstream ifs("fsm.txt");
+ boost::archive::text_iarchive ia(ifs);
+ // read class state from archive
+ ia >> p2;
+ }
+ // we now use p2 as it was loaded
+ // check that we kept Empty's data value
+ BOOST_CHECK_MESSAGE(p2.get_state<player_::Empty&>().some_dummy_data == 3,"Empty not deserialized correctly");
+ BOOST_CHECK_MESSAGE(p2.front_end_data == 4,"Front-end not deserialized correctly");
+
+ p.process_event(open_close());
+ BOOST_CHECK_MESSAGE(p.current_state()[0] == 2,"Empty should be active"); //Empty
+ BOOST_CHECK_MESSAGE(p.get_state<player_::Open&>().exit_counter == 1,"Open exit not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<player_::Empty&>().entry_counter == 2,"Empty entry not called correctly");
+ BOOST_CHECK_MESSAGE(p.can_close_drawer_counter == 1,"guard not called correctly");
+
+ p.process_event(
+ cd_detected("louie, louie",DISK_DVD));
+ BOOST_CHECK_MESSAGE(p.current_state()[0] == 2,"Empty should be active"); //Empty
+ BOOST_CHECK_MESSAGE(p.get_state<player_::Open&>().exit_counter == 1,"Open exit not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<player_::Empty&>().entry_counter == 2,"Empty entry not called correctly");
+
+ p.process_event(
+ cd_detected("louie, louie",DISK_CD));
+ BOOST_CHECK_MESSAGE(p.current_state()[0] == 0,"Stopped should be active"); //Stopped
+ BOOST_CHECK_MESSAGE(p.get_state<player_::Empty&>().exit_counter == 2,"Empty exit not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<player_::Stopped&>().entry_counter == 1,"Stopped entry not called correctly");
+
+ p.process_event(play());
+ BOOST_CHECK_MESSAGE(p.current_state()[0] == 3,"Playing should be active"); //Playing
+ BOOST_CHECK_MESSAGE(p.get_state<player_::Stopped&>().exit_counter == 1,"Stopped exit not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<player_::Playing&>().entry_counter == 1,"Playing entry not called correctly");
+ BOOST_CHECK_MESSAGE(p.start_playback_counter == 1,"action not called correctly");
+
+ p.process_event(pause());
+ BOOST_CHECK_MESSAGE(p.current_state()[0] == 4,"Paused should be active"); //Paused
+ BOOST_CHECK_MESSAGE(p.get_state<player_::Playing&>().exit_counter == 1,"Playing exit not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<player_::Paused&>().entry_counter == 1,"Paused entry not called correctly");
+
+ // go back to Playing
+ p.process_event(end_pause());
+ BOOST_CHECK_MESSAGE(p.current_state()[0] == 3,"Playing should be active"); //Playing
+ BOOST_CHECK_MESSAGE(p.get_state<player_::Paused&>().exit_counter == 1,"Paused exit not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<player_::Playing&>().entry_counter == 2,"Playing entry not called correctly");
+
+ p.process_event(pause());
+ BOOST_CHECK_MESSAGE(p.current_state()[0] == 4,"Paused should be active"); //Paused
+ BOOST_CHECK_MESSAGE(p.get_state<player_::Playing&>().exit_counter == 2,"Playing exit not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<player_::Paused&>().entry_counter == 2,"Paused entry not called correctly");
+
+ p.process_event(stop());
+ BOOST_CHECK_MESSAGE(p.current_state()[0] == 0,"Stopped should be active"); //Stopped
+ BOOST_CHECK_MESSAGE(p.get_state<player_::Paused&>().exit_counter == 2,"Paused exit not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<player_::Stopped&>().entry_counter == 2,"Stopped entry not called correctly");
+
+ p.process_event(stop());
+ BOOST_CHECK_MESSAGE(p.current_state()[0] == 0,"Stopped should be active"); //Stopped
+ BOOST_CHECK_MESSAGE(p.get_state<player_::Stopped&>().exit_counter == 2,"Stopped exit not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<player_::Stopped&>().entry_counter == 3,"Stopped entry not called correctly");
+ }
+}
+// eliminate object tracking (even if serialized through a pointer)
+// at the risk of a programming error creating duplicate objects.
+// this is to get rid of warning because p is not const
+BOOST_CLASS_TRACKING(player, boost::serialization::track_never)
+
diff --git a/src/boost/libs/msm/test/SerializeSimpleEuml.cpp b/src/boost/libs/msm/test/SerializeSimpleEuml.cpp
new file mode 100644
index 000000000..2a5769b9c
--- /dev/null
+++ b/src/boost/libs/msm/test/SerializeSimpleEuml.cpp
@@ -0,0 +1,216 @@
+// 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 <iostream>
+#include <boost/msm/back/state_machine.hpp>
+#include <boost/msm/front/euml/euml.hpp>
+
+#ifndef BOOST_MSM_NONSTANDALONE_TEST
+#define BOOST_TEST_MODULE MyTest
+#endif
+#include <boost/test/unit_test.hpp>
+// include headers that implement a archive in simple text format
+#include <boost/archive/text_oarchive.hpp>
+#include <boost/archive/text_iarchive.hpp>
+#include <boost/serialization/tracking.hpp>
+
+#include <fstream>
+
+using namespace std;
+using namespace boost::msm::front::euml;
+namespace msm = boost::msm;
+
+namespace
+{
+ // A "complicated" event type that carries some data.
+ enum DiskTypeEnum
+ {
+ DISK_CD=0,
+ DISK_DVD=1
+ };
+ // events
+ BOOST_MSM_EUML_EVENT(play)
+ BOOST_MSM_EUML_EVENT(end_pause)
+ BOOST_MSM_EUML_EVENT(stop)
+ BOOST_MSM_EUML_EVENT(pause)
+ BOOST_MSM_EUML_EVENT(open_close)
+ // A "complicated" event type that carries some data.
+ BOOST_MSM_EUML_DECLARE_ATTRIBUTE(std::string,cd_name)
+ BOOST_MSM_EUML_DECLARE_ATTRIBUTE(DiskTypeEnum,cd_type)
+ BOOST_MSM_EUML_ATTRIBUTES((attributes_ << cd_name << cd_type ), cd_detected_attributes)
+ BOOST_MSM_EUML_EVENT_WITH_ATTRIBUTES(cd_detected,cd_detected_attributes)
+
+ //states
+ BOOST_MSM_EUML_DECLARE_ATTRIBUTE(unsigned int,entry_counter)
+ BOOST_MSM_EUML_DECLARE_ATTRIBUTE(unsigned int,exit_counter)
+
+ BOOST_MSM_EUML_STATE(( ++state_(entry_counter),++state_(exit_counter),attributes_ << entry_counter << exit_counter),Empty)
+ BOOST_MSM_EUML_STATE(( ++state_(entry_counter),++state_(exit_counter),attributes_ << entry_counter << exit_counter),Open)
+ BOOST_MSM_EUML_STATE(( ++state_(entry_counter),++state_(exit_counter),attributes_ << entry_counter << exit_counter),Stopped)
+ BOOST_MSM_EUML_STATE(( ++state_(entry_counter),++state_(exit_counter),attributes_ << entry_counter << exit_counter),Playing)
+ BOOST_MSM_EUML_STATE(( ++state_(entry_counter),++state_(exit_counter),attributes_ << entry_counter << exit_counter),Paused)
+
+ //fsm
+ BOOST_MSM_EUML_DECLARE_ATTRIBUTE(unsigned int,start_playback_counter)
+ BOOST_MSM_EUML_DECLARE_ATTRIBUTE(unsigned int,can_close_drawer_counter)
+ BOOST_MSM_EUML_DECLARE_ATTRIBUTE(unsigned int,test_fct_counter)
+ BOOST_MSM_EUML_ACTION(No_Transition)
+ {
+ template <class FSM,class Event>
+ void operator()(Event const&,FSM&,int)
+ {
+ BOOST_FAIL("no_transition called!");
+ }
+ };
+ BOOST_MSM_EUML_ACTION(good_disk_format)
+ {
+ template <class FSM,class EVT,class SourceState,class TargetState>
+ bool operator()(EVT const& evt,FSM&,SourceState& ,TargetState& )
+ {
+ if (evt.get_attribute(cd_type)!=DISK_CD)
+ {
+ return false;
+ }
+ return true;
+ }
+ };
+ BOOST_MSM_EUML_TRANSITION_TABLE((
+ Playing == Stopped + play / (++fsm_(start_playback_counter),++fsm_(test_fct_counter) ),
+ Playing == Paused + end_pause ,
+ // +------------------------------------------------------------------------------+
+ Empty == Open + open_close / ++fsm_(can_close_drawer_counter),
+ // +------------------------------------------------------------------------------+
+ Open == Empty + open_close ,
+ Open == Paused + open_close ,
+ Open == Stopped + open_close ,
+ Open == Playing + open_close ,
+ // +------------------------------------------------------------------------------+
+ Paused == Playing + pause ,
+ // +------------------------------------------------------------------------------+
+ Stopped == Playing + stop ,
+ Stopped == Paused + stop ,
+ Stopped == Empty + cd_detected [good_disk_format ||
+ (event_(cd_type)==Int_<DISK_CD>())] / process_(play) ,
+ Stopped == Stopped + stop
+ // +------------------------------------------------------------------------------+
+ ),transition_table)
+
+ BOOST_MSM_EUML_DECLARE_STATE_MACHINE(( transition_table, //STT
+ init_ << Empty, // Init State
+ no_action, // Entry
+ no_action, // Exit
+ attributes_ << start_playback_counter
+ << can_close_drawer_counter << test_fct_counter, // Attributes
+ configure_ << no_configure_, // configuration
+ No_Transition // no_transition handler
+ ),
+ player_) //fsm name
+
+ typedef msm::back::state_machine<player_> player;
+
+// static char const* const state_names[] = { "Stopped", "Paused", "Open", "Empty", "Playing" };
+
+
+ BOOST_AUTO_TEST_CASE( my_test )
+ {
+ player p2;
+
+ p2.start();
+ BOOST_CHECK_MESSAGE(p2.get_state<BOOST_MSM_EUML_STATE_NAME(Empty)&>().get_attribute(entry_counter) == 1,
+ "Empty entry not called correctly");
+
+ p2.process_event(open_close());
+ BOOST_CHECK_MESSAGE(p2.current_state()[0] == 2,"Open should be active"); //Open
+ BOOST_CHECK_MESSAGE(p2.get_state<BOOST_MSM_EUML_STATE_NAME(Empty)&>().get_attribute(exit_counter) == 1,
+ "Empty exit not called correctly");
+ BOOST_CHECK_MESSAGE(p2.get_state<BOOST_MSM_EUML_STATE_NAME(Open)&>().get_attribute(entry_counter) == 1,
+ "Open entry not called correctly");
+
+ // test the serialization
+ std::ofstream ofs("fsm.txt");
+ // save fsm to archive (current state is Open)
+ {
+ boost::archive::text_oarchive oa(ofs);
+ // write class instance to archive
+ oa << p2;
+ }
+ // reload fsm in state Open
+ player p;
+ {
+ // create and open an archive for input
+ std::ifstream ifs("fsm.txt");
+ boost::archive::text_iarchive ia(ifs);
+ // read class state from archive
+ ia >> p;
+ }
+
+ p.process_event(open_close());
+ BOOST_CHECK_MESSAGE(p.current_state()[0] == 3,"Empty should be active"); //Empty
+
+ p.process_event(
+ cd_detected("louie, louie",DISK_DVD));
+ BOOST_CHECK_MESSAGE(p.current_state()[0] == 3,"Empty should be active"); //Empty
+ BOOST_CHECK_MESSAGE(p.get_state<BOOST_MSM_EUML_STATE_NAME(Open)&>().get_attribute(exit_counter) == 1,
+ "Open exit not called correctly");
+
+ p.process_event(
+ cd_detected("louie, louie",DISK_CD));
+ BOOST_CHECK_MESSAGE(p.current_state()[0] == 4,"Playing should be active"); //Playing
+ BOOST_CHECK_MESSAGE(p.get_state<BOOST_MSM_EUML_STATE_NAME(Stopped)&>().get_attribute(entry_counter) == 1,
+ "Stopped entry not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<BOOST_MSM_EUML_STATE_NAME(Stopped)&>().get_attribute(exit_counter) == 1,
+ "Stopped exit not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<BOOST_MSM_EUML_STATE_NAME(Playing)&>().get_attribute(entry_counter) == 1,
+ "Playing entry not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_attribute(start_playback_counter) == 1,"action not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_attribute(test_fct_counter) == 1,"action not called correctly");
+
+ p.process_event(pause());
+ BOOST_CHECK_MESSAGE(p.current_state()[0] == 1,"Paused should be active"); //Paused
+ BOOST_CHECK_MESSAGE(p.get_state<BOOST_MSM_EUML_STATE_NAME(Playing)&>().get_attribute(exit_counter) == 1,
+ "Playing exit not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<BOOST_MSM_EUML_STATE_NAME(Paused)&>().get_attribute(entry_counter) == 1,
+ "Paused entry not called correctly");
+
+ // go back to Playing
+ p.process_event(end_pause());
+ BOOST_CHECK_MESSAGE(p.current_state()[0] == 4,"Playing should be active"); //Playing
+ BOOST_CHECK_MESSAGE(p.get_state<BOOST_MSM_EUML_STATE_NAME(Paused)&>().get_attribute(exit_counter) == 1,
+ "Paused exit not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<BOOST_MSM_EUML_STATE_NAME(Playing)&>().get_attribute(entry_counter) == 2,
+ "Playing entry not called correctly");
+
+ p.process_event(pause());
+ BOOST_CHECK_MESSAGE(p.current_state()[0] == 1,"Paused should be active"); //Paused
+ BOOST_CHECK_MESSAGE(p.get_state<BOOST_MSM_EUML_STATE_NAME(Playing)&>().get_attribute(exit_counter) == 2,
+ "Playing exit not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<BOOST_MSM_EUML_STATE_NAME(Paused)&>().get_attribute(entry_counter) == 2,
+ "Paused entry not called correctly");
+
+ p.process_event(stop());
+ BOOST_CHECK_MESSAGE(p.current_state()[0] == 0,"Stopped should be active"); //Stopped
+ BOOST_CHECK_MESSAGE(p.get_state<BOOST_MSM_EUML_STATE_NAME(Paused)&>().get_attribute(exit_counter) == 2,
+ "Paused exit not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<BOOST_MSM_EUML_STATE_NAME(Stopped)&>().get_attribute(entry_counter) == 2,
+ "Stopped entry not called correctly");
+
+ p.process_event(stop());
+ BOOST_CHECK_MESSAGE(p.current_state()[0] == 0,"Stopped should be active"); //Stopped
+ BOOST_CHECK_MESSAGE(p.get_state<BOOST_MSM_EUML_STATE_NAME(Stopped)&>().get_attribute(exit_counter) == 2,
+ "Stopped exit not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<BOOST_MSM_EUML_STATE_NAME(Stopped)&>().get_attribute(entry_counter) == 3,
+ "Stopped entry not called correctly");
+ }
+}
+
+// eliminate object tracking (even if serialized through a pointer)
+// at the risk of a programming error creating duplicate objects.
+// this is to get rid of warning because p is not const
+BOOST_CLASS_TRACKING(player, boost::serialization::track_never)
diff --git a/src/boost/libs/msm/test/SerializeWithHistory.cpp b/src/boost/libs/msm/test/SerializeWithHistory.cpp
new file mode 100644
index 000000000..cf1e11d6c
--- /dev/null
+++ b/src/boost/libs/msm/test/SerializeWithHistory.cpp
@@ -0,0 +1,367 @@
+// 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 <iostream>
+// back-end
+#include <boost/msm/back/state_machine.hpp>
+//front-end
+#include <boost/msm/front/state_machine_def.hpp>
+#ifndef BOOST_MSM_NONSTANDALONE_TEST
+#define BOOST_TEST_MODULE MyTest
+#endif
+#include <boost/test/unit_test.hpp>
+// include headers that implement a archive in simple text format
+#include <boost/archive/text_oarchive.hpp>
+#include <boost/archive/text_iarchive.hpp>
+#include <boost/serialization/tracking.hpp>
+
+#include <fstream>
+
+namespace msm = boost::msm;
+namespace mpl = boost::mpl;
+
+namespace
+{
+ // events
+ struct play {};
+ struct end_pause {};
+ struct stop {};
+ struct pause {};
+ struct open_close {};
+ struct NextSong {};
+ struct PreviousSong {};
+ struct cd_detected
+ {
+ cd_detected(std::string name)
+ : name(name)
+ {}
+ std::string name;
+ };
+
+ // front-end: define the FSM structure
+ struct player_ : public msm::front::state_machine_def<player_>
+ {
+ unsigned int start_playback_counter;
+ unsigned int can_close_drawer_counter;
+
+ player_():
+ start_playback_counter(0),
+ can_close_drawer_counter(0)
+ {}
+ // The list of FSM states
+ struct Empty : 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;
+ int exit_counter;
+ };
+ struct Open : 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;
+ int exit_counter;
+ };
+
+ // sm_ptr still supported but deprecated as functors are a much better way to do the same thing
+ struct Stopped : 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;
+ int exit_counter;
+ };
+
+ struct Playing_ : public msm::front::state_machine_def<Playing_>
+ {
+ 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;
+ int exit_counter;
+ unsigned int start_next_song_counter;
+ unsigned int start_prev_song_guard_counter;
+
+ Playing_():
+ start_next_song_counter(0),
+ start_prev_song_guard_counter(0)
+ {}
+
+ // The list of FSM states
+ struct Song1 : 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;
+ int exit_counter;
+ };
+ struct Song2 : 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;
+ int exit_counter;
+ };
+ struct Song3 : 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;
+ int exit_counter;
+ };
+ // the initial state. Must be defined
+ typedef Song1 initial_state;
+ // transition actions
+ void start_next_song(NextSong const&) {++start_next_song_counter; }
+ void start_prev_song(PreviousSong const&) { }
+ // guard conditions
+ bool start_prev_song_guard(PreviousSong const&) {++start_prev_song_guard_counter;return true; }
+
+ typedef Playing_ pl; // makes transition table cleaner
+ // Transition table for Playing
+ struct transition_table : mpl::vector4<
+ // Start Event Next Action Guard
+ // +---------+-------------+---------+---------------------+----------------------+
+ _row < Song1 , NextSong , Song2 >,
+ row < Song2 , PreviousSong, Song1 , &pl::start_prev_song,&pl::start_prev_song_guard>,
+ a_row < Song2 , NextSong , Song3 , &pl::start_next_song >,
+ g_row < Song3 , PreviousSong, Song2 ,&pl::start_prev_song_guard>
+ // +---------+-------------+---------+---------------------+----------------------+
+ > {};
+ // Replaces the default no-transition response.
+ template <class FSM,class Event>
+ void no_transition(Event const&, FSM&,int)
+ {
+ BOOST_FAIL("no_transition called!");
+ }
+ };
+ // back-end
+ typedef msm::back::state_machine<Playing_,msm::back::ShallowHistory<mpl::vector<end_pause> > > Playing;
+
+ // state not defining any entry or exit
+ struct Paused : 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;
+ int exit_counter;
+ };
+
+ // the initial state of the player SM. Must be defined
+ typedef Empty initial_state;
+
+ // transition actions
+ void start_playback(play const&) {++start_playback_counter; }
+ void open_drawer(open_close const&) { }
+ void store_cd_info(cd_detected const&) { }
+ void stop_playback(stop const&) { }
+ void pause_playback(pause const&) { }
+ void resume_playback(end_pause const&) { }
+ void stop_and_open(open_close const&) { }
+ void stopped_again(stop const&) {}
+ //guards
+ bool can_close_drawer(open_close const&)
+ {
+ ++can_close_drawer_counter;
+ return true;
+ }
+
+
+ typedef player_ p; // makes transition table cleaner
+
+ // Transition table for player
+ struct transition_table : mpl::vector<
+ // Start Event Next Action Guard
+ // +---------+-------------+---------+---------------------+----------------------+
+ a_row < Stopped , play , Playing , &p::start_playback >,
+ a_row < Stopped , open_close , Open , &p::open_drawer >,
+ _row < Stopped , stop , Stopped >,
+ // +---------+-------------+---------+---------------------+----------------------+
+ g_row < Open , open_close , Empty , &p::can_close_drawer >,
+ // +---------+-------------+---------+---------------------+----------------------+
+ a_row < Empty , open_close , Open , &p::open_drawer >,
+ a_row < Empty , cd_detected , Stopped , &p::store_cd_info >,
+ // +---------+-------------+---------+---------------------+----------------------+
+ a_row < Playing , stop , Stopped , &p::stop_playback >,
+ a_row < Playing , pause , Paused , &p::pause_playback >,
+ a_row < Playing , open_close , Open , &p::stop_and_open >,
+ // +---------+-------------+---------+---------------------+----------------------+
+ a_row < Paused , end_pause , Playing , &p::resume_playback >,
+ a_row < Paused , stop , Stopped , &p::stop_playback >,
+ a_row < Paused , open_close , Open , &p::stop_and_open >
+ // +---------+-------------+---------+---------------------+----------------------+
+ > {};
+ // Replaces the default no-transition response.
+ template <class FSM,class Event>
+ void no_transition(Event const& e, FSM&,int state)
+ {
+ BOOST_FAIL("no_transition called!");
+ }
+ // init counters
+ template <class Event,class FSM>
+ void on_entry(Event const&,FSM& fsm)
+ {
+ fsm.template get_state<player_::Stopped&>().entry_counter=0;
+ fsm.template get_state<player_::Stopped&>().exit_counter=0;
+ fsm.template get_state<player_::Open&>().entry_counter=0;
+ fsm.template get_state<player_::Open&>().exit_counter=0;
+ fsm.template get_state<player_::Empty&>().entry_counter=0;
+ fsm.template get_state<player_::Empty&>().exit_counter=0;
+ fsm.template get_state<player_::Playing&>().entry_counter=0;
+ fsm.template get_state<player_::Playing&>().exit_counter=0;
+ fsm.template get_state<player_::Playing&>().template get_state<player_::Playing::Song1&>().entry_counter=0;
+ fsm.template get_state<player_::Playing&>().template get_state<player_::Playing::Song1&>().exit_counter=0;
+ fsm.template get_state<player_::Playing&>().template get_state<player_::Playing::Song2&>().entry_counter=0;
+ fsm.template get_state<player_::Playing&>().template get_state<player_::Playing::Song2&>().exit_counter=0;
+ fsm.template get_state<player_::Playing&>().template get_state<player_::Playing::Song3&>().entry_counter=0;
+ fsm.template get_state<player_::Playing&>().template get_state<player_::Playing::Song3&>().exit_counter=0;
+ fsm.template get_state<player_::Paused&>().entry_counter=0;
+ fsm.template get_state<player_::Paused&>().exit_counter=0;
+ }
+
+ };
+ // Pick a back-end
+ typedef msm::back::state_machine<player_> player;
+
+// static char const* const state_names[] = { "Stopped", "Open", "Empty", "Playing", "Paused" };
+
+
+ BOOST_AUTO_TEST_CASE( my_test )
+ {
+ player p;
+
+ p.start();
+ BOOST_CHECK_MESSAGE(p.get_state<player_::Empty&>().entry_counter == 1,"Empty entry not called correctly");
+
+ p.process_event(open_close());
+ BOOST_CHECK_MESSAGE(p.current_state()[0] == 1,"Open should be active"); //Open
+ BOOST_CHECK_MESSAGE(p.get_state<player_::Empty&>().exit_counter == 1,"Empty exit not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<player_::Open&>().entry_counter == 1,"Open entry not called correctly");
+
+ p.process_event(open_close());
+ BOOST_CHECK_MESSAGE(p.current_state()[0] == 2,"Empty should be active"); //Empty
+ BOOST_CHECK_MESSAGE(p.get_state<player_::Open&>().exit_counter == 1,"Open exit not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<player_::Empty&>().entry_counter == 2,"Empty entry not called correctly");
+ BOOST_CHECK_MESSAGE(p.can_close_drawer_counter == 1,"guard not called correctly");
+
+ p.process_event(cd_detected("louie, louie"));
+ BOOST_CHECK_MESSAGE(p.current_state()[0] == 0,"Stopped should be active"); //Stopped
+ BOOST_CHECK_MESSAGE(p.get_state<player_::Empty&>().exit_counter == 2,"Empty exit not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<player_::Stopped&>().entry_counter == 1,"Stopped entry not called correctly");
+
+ p.process_event(play());
+ BOOST_CHECK_MESSAGE(p.current_state()[0] == 3,"Playing should be active"); //Playing
+ BOOST_CHECK_MESSAGE(p.get_state<player_::Stopped&>().exit_counter == 1,"Stopped exit not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<player_::Playing&>().entry_counter == 1,"Playing entry not called correctly");
+ BOOST_CHECK_MESSAGE(p.start_playback_counter == 1,"action not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<player_::Playing&>().current_state()[0] == 0,"Song1 should be active");
+ BOOST_CHECK_MESSAGE(
+ p.get_state<player_::Playing&>().get_state<player_::Playing::Song1&>().entry_counter == 1,
+ "Song1 entry not called correctly");
+
+ p.process_event(NextSong());
+ BOOST_CHECK_MESSAGE(p.current_state()[0] == 3,"Playing should be active"); //Playing
+ BOOST_CHECK_MESSAGE(p.get_state<player_::Playing&>().current_state()[0] == 1,"Song2 should be active");
+ BOOST_CHECK_MESSAGE(
+ p.get_state<player_::Playing&>().get_state<player_::Playing::Song2&>().entry_counter == 1,
+ "Song2 entry not called correctly");
+ BOOST_CHECK_MESSAGE(
+ p.get_state<player_::Playing&>().get_state<player_::Playing::Song1&>().exit_counter == 1,
+ "Song1 exit not called correctly");
+ BOOST_CHECK_MESSAGE(
+ p.get_state<player_::Playing&>().start_next_song_counter == 0,
+ "submachine action not called correctly");
+
+ p.process_event(NextSong());
+ BOOST_CHECK_MESSAGE(p.current_state()[0] == 3,"Playing should be active"); //Playing
+ BOOST_CHECK_MESSAGE(p.get_state<player_::Playing&>().current_state()[0] == 2,"Song3 should be active");
+ BOOST_CHECK_MESSAGE(
+ p.get_state<player_::Playing&>().get_state<player_::Playing::Song3&>().entry_counter == 1,
+ "Song3 entry not called correctly");
+ BOOST_CHECK_MESSAGE(
+ p.get_state<player_::Playing&>().get_state<player_::Playing::Song2&>().exit_counter == 1,
+ "Song2 exit not called correctly");
+ BOOST_CHECK_MESSAGE(
+ p.get_state<player_::Playing&>().start_next_song_counter == 1,
+ "submachine action not called correctly");
+
+ p.process_event(PreviousSong());
+ BOOST_CHECK_MESSAGE(p.current_state()[0] == 3,"Playing should be active"); //Playing
+ BOOST_CHECK_MESSAGE(p.get_state<player_::Playing&>().current_state()[0] == 1,"Song2 should be active");
+ BOOST_CHECK_MESSAGE(
+ p.get_state<player_::Playing&>().get_state<player_::Playing::Song2&>().entry_counter == 2,
+ "Song2 entry not called correctly");
+ BOOST_CHECK_MESSAGE(
+ p.get_state<player_::Playing&>().get_state<player_::Playing::Song3&>().exit_counter == 1,
+ "Song3 exit not called correctly");
+ BOOST_CHECK_MESSAGE(
+ p.get_state<player_::Playing&>().start_prev_song_guard_counter == 1,
+ "submachine guard not called correctly");
+
+ p.process_event(pause());
+ BOOST_CHECK_MESSAGE(p.current_state()[0] == 4,"Paused should be active"); //Paused
+ BOOST_CHECK_MESSAGE(p.get_state<player_::Playing&>().exit_counter == 1,"Playing exit not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<player_::Paused&>().entry_counter == 1,"Paused entry not called correctly");
+
+ std::ofstream ofs("fsm.txt");
+ // save fsm to archive (current state is Pause, Playing is in Song2)
+ {
+ boost::archive::text_oarchive oa(ofs);
+ // write class instance to archive
+ oa << p;
+ }
+ // reload fsm in state Open
+ player p2;
+ {
+ // create and open an archive for input
+ std::ifstream ifs("fsm.txt");
+ boost::archive::text_iarchive ia(ifs);
+ // read class state from archive
+ ia >> p2;
+ }
+ // go back to Playing
+ p2.process_event(end_pause());
+ BOOST_CHECK_MESSAGE(p2.current_state()[0] == 3,"Playing should be active"); //Playing
+ BOOST_CHECK_MESSAGE(p2.get_state<player_::Playing&>().current_state()[0] == 1,"Song2 should be active");
+
+ p2.process_event(pause());
+ BOOST_CHECK_MESSAGE(p2.current_state()[0] == 4,"Paused should be active"); //Paused
+
+ p2.process_event(stop());
+ BOOST_CHECK_MESSAGE(p2.current_state()[0] == 0,"Stopped should be active"); //Stopped
+
+ p2.process_event(stop());
+ BOOST_CHECK_MESSAGE(p2.current_state()[0] == 0,"Stopped should be active"); //Stopped
+
+ p2.process_event(play());
+ BOOST_CHECK_MESSAGE(p2.get_state<player_::Playing&>().current_state()[0] == 0,"Song1 should be active");
+ }
+}
+// eliminate object tracking (even if serialized through a pointer)
+// at the risk of a programming error creating duplicate objects.
+// this is to get rid of warning because p is not const
+BOOST_CLASS_TRACKING(player, boost::serialization::track_never)
+
diff --git a/src/boost/libs/msm/test/SimpleEuml.cpp b/src/boost/libs/msm/test/SimpleEuml.cpp
new file mode 100644
index 000000000..8d66e9eac
--- /dev/null
+++ b/src/boost/libs/msm/test/SimpleEuml.cpp
@@ -0,0 +1,197 @@
+// 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 <iostream>
+#include <boost/msm/back/state_machine.hpp>
+#include <boost/msm/front/euml/euml.hpp>
+
+#ifndef BOOST_MSM_NONSTANDALONE_TEST
+#define BOOST_TEST_MODULE MyTest
+#endif
+#include <boost/test/unit_test.hpp>
+
+using namespace std;
+using namespace boost::msm::front::euml;
+namespace msm = boost::msm;
+
+namespace
+{
+ // A "complicated" event type that carries some data.
+ enum DiskTypeEnum
+ {
+ DISK_CD=0,
+ DISK_DVD=1
+ };
+ // events
+ BOOST_MSM_EUML_EVENT(play)
+ BOOST_MSM_EUML_EVENT(end_pause)
+ BOOST_MSM_EUML_EVENT(stop)
+ BOOST_MSM_EUML_EVENT(pause)
+ BOOST_MSM_EUML_EVENT(open_close)
+ // A "complicated" event type that carries some data.
+ BOOST_MSM_EUML_DECLARE_ATTRIBUTE(std::string,cd_name)
+ BOOST_MSM_EUML_DECLARE_ATTRIBUTE(DiskTypeEnum,cd_type)
+ BOOST_MSM_EUML_ATTRIBUTES((attributes_ << cd_name << cd_type ), cd_detected_attributes)
+ BOOST_MSM_EUML_EVENT_WITH_ATTRIBUTES(cd_detected,cd_detected_attributes)
+
+ //states
+ BOOST_MSM_EUML_DECLARE_ATTRIBUTE(unsigned int,entry_counter)
+ BOOST_MSM_EUML_DECLARE_ATTRIBUTE(unsigned int,exit_counter)
+
+ BOOST_MSM_EUML_STATE(( ++state_(entry_counter),++state_(exit_counter),attributes_ << entry_counter << exit_counter),Empty)
+ BOOST_MSM_EUML_STATE(( ++state_(entry_counter),++state_(exit_counter),attributes_ << entry_counter << exit_counter),Open)
+ BOOST_MSM_EUML_STATE(( ++state_(entry_counter),++state_(exit_counter),attributes_ << entry_counter << exit_counter),Stopped)
+ BOOST_MSM_EUML_STATE(( ++state_(entry_counter),++state_(exit_counter),attributes_ << entry_counter << exit_counter),Playing)
+ BOOST_MSM_EUML_STATE(( ++state_(entry_counter),++state_(exit_counter),attributes_ << entry_counter << exit_counter),Paused)
+
+ //fsm
+ BOOST_MSM_EUML_DECLARE_ATTRIBUTE(unsigned int,start_playback_counter)
+ BOOST_MSM_EUML_DECLARE_ATTRIBUTE(unsigned int,can_close_drawer_counter)
+ BOOST_MSM_EUML_DECLARE_ATTRIBUTE(unsigned int,test_fct_counter)
+ BOOST_MSM_EUML_ACTION(No_Transition)
+ {
+ template <class FSM,class Event>
+ void operator()(Event const&,FSM&,int)
+ {
+ BOOST_FAIL("no_transition called!");
+ }
+ };
+ BOOST_MSM_EUML_ACTION(good_disk_format)
+ {
+ template <class FSM,class EVT,class SourceState,class TargetState>
+ bool operator()(EVT const& evt,FSM&,SourceState& ,TargetState& )
+ {
+ if (evt.get_attribute(cd_type)!=DISK_CD)
+ {
+ return false;
+ }
+ return true;
+ }
+ };
+ BOOST_MSM_EUML_TRANSITION_TABLE((
+ Playing == Stopped + play / (++fsm_(start_playback_counter),++fsm_(test_fct_counter) ),
+ Playing == Paused + end_pause ,
+ // +------------------------------------------------------------------------------+
+ Empty == Open + open_close / ++fsm_(can_close_drawer_counter),
+ // +------------------------------------------------------------------------------+
+ Open == Empty + open_close ,
+ Open == Paused + open_close ,
+ Open == Stopped + open_close ,
+ Open == Playing + open_close ,
+ // +------------------------------------------------------------------------------+
+ Paused == Playing + pause ,
+ // +------------------------------------------------------------------------------+
+ Stopped == Playing + stop ,
+ Stopped == Paused + stop ,
+ Stopped == Empty + cd_detected [good_disk_format ||
+ (event_(cd_type)==Int_<DISK_CD>())] / process_(play) ,
+ Stopped == Stopped + stop
+ // +------------------------------------------------------------------------------+
+ ),transition_table)
+
+ BOOST_MSM_EUML_DECLARE_STATE_MACHINE(( transition_table, //STT
+ init_ << Empty, // Init State
+ no_action, // Entry
+ no_action, // Exit
+ attributes_ << start_playback_counter
+ << can_close_drawer_counter << test_fct_counter, // Attributes
+ configure_ << no_configure_, // configuration
+ No_Transition // no_transition handler
+ ),
+ player_) //fsm name
+
+ typedef msm::back::state_machine<player_> player;
+
+// static char const* const state_names[] = { "Stopped", "Paused", "Open", "Empty", "Playing" };
+
+
+ BOOST_AUTO_TEST_CASE( my_test )
+ {
+ player p;
+
+ p.start();
+ BOOST_CHECK_MESSAGE(p.get_state<BOOST_MSM_EUML_STATE_NAME(Empty)&>().get_attribute(entry_counter) == 1,
+ "Empty entry not called correctly");
+
+ p.process_event(open_close());
+ BOOST_CHECK_MESSAGE(p.current_state()[0] == 2,"Open should be active"); //Open
+ BOOST_CHECK_MESSAGE(p.get_state<BOOST_MSM_EUML_STATE_NAME(Empty)&>().get_attribute(exit_counter) == 1,
+ "Empty exit not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<BOOST_MSM_EUML_STATE_NAME(Open)&>().get_attribute(entry_counter) == 1,
+ "Open entry not called correctly");
+
+ p.process_event(open_close());
+ BOOST_CHECK_MESSAGE(p.current_state()[0] == 3,"Empty should be active"); //Empty
+ BOOST_CHECK_MESSAGE(p.get_state<BOOST_MSM_EUML_STATE_NAME(Open)&>().get_attribute(exit_counter) == 1,
+ "Open exit not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<BOOST_MSM_EUML_STATE_NAME(Empty)&>().get_attribute(entry_counter) == 2,
+ "Empty entry not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_attribute(can_close_drawer_counter) == 1,"guard not called correctly");
+
+ p.process_event(
+ cd_detected("louie, louie",DISK_DVD));
+ BOOST_CHECK_MESSAGE(p.current_state()[0] == 3,"Empty should be active"); //Empty
+ BOOST_CHECK_MESSAGE(p.get_state<BOOST_MSM_EUML_STATE_NAME(Open)&>().get_attribute(exit_counter) == 1,
+ "Open exit not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<BOOST_MSM_EUML_STATE_NAME(Empty)&>().get_attribute(entry_counter) == 2,
+ "Empty entry not called correctly");
+
+ p.process_event(
+ cd_detected("louie, louie",DISK_CD));
+ BOOST_CHECK_MESSAGE(p.current_state()[0] == 4,"Playing should be active"); //Playing
+ BOOST_CHECK_MESSAGE(p.get_state<BOOST_MSM_EUML_STATE_NAME(Empty)&>().get_attribute(exit_counter) == 2,
+ "Empty exit not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<BOOST_MSM_EUML_STATE_NAME(Stopped)&>().get_attribute(entry_counter) == 1,
+ "Stopped entry not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<BOOST_MSM_EUML_STATE_NAME(Stopped)&>().get_attribute(exit_counter) == 1,
+ "Stopped exit not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<BOOST_MSM_EUML_STATE_NAME(Playing)&>().get_attribute(entry_counter) == 1,
+ "Playing entry not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_attribute(start_playback_counter) == 1,"action not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_attribute(test_fct_counter) == 1,"action not called correctly");
+
+ p.process_event(pause());
+ BOOST_CHECK_MESSAGE(p.current_state()[0] == 1,"Paused should be active"); //Paused
+ BOOST_CHECK_MESSAGE(p.get_state<BOOST_MSM_EUML_STATE_NAME(Playing)&>().get_attribute(exit_counter) == 1,
+ "Playing exit not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<BOOST_MSM_EUML_STATE_NAME(Paused)&>().get_attribute(entry_counter) == 1,
+ "Paused entry not called correctly");
+
+ // go back to Playing
+ p.process_event(end_pause());
+ BOOST_CHECK_MESSAGE(p.current_state()[0] == 4,"Playing should be active"); //Playing
+ BOOST_CHECK_MESSAGE(p.get_state<BOOST_MSM_EUML_STATE_NAME(Paused)&>().get_attribute(exit_counter) == 1,
+ "Paused exit not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<BOOST_MSM_EUML_STATE_NAME(Playing)&>().get_attribute(entry_counter) == 2,
+ "Playing entry not called correctly");
+
+ p.process_event(pause());
+ BOOST_CHECK_MESSAGE(p.current_state()[0] == 1,"Paused should be active"); //Paused
+ BOOST_CHECK_MESSAGE(p.get_state<BOOST_MSM_EUML_STATE_NAME(Playing)&>().get_attribute(exit_counter) == 2,
+ "Playing exit not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<BOOST_MSM_EUML_STATE_NAME(Paused)&>().get_attribute(entry_counter) == 2,
+ "Paused entry not called correctly");
+
+ p.process_event(stop());
+ BOOST_CHECK_MESSAGE(p.current_state()[0] == 0,"Stopped should be active"); //Stopped
+ BOOST_CHECK_MESSAGE(p.get_state<BOOST_MSM_EUML_STATE_NAME(Paused)&>().get_attribute(exit_counter) == 2,
+ "Paused exit not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<BOOST_MSM_EUML_STATE_NAME(Stopped)&>().get_attribute(entry_counter) == 2,
+ "Stopped entry not called correctly");
+
+ p.process_event(stop());
+ BOOST_CHECK_MESSAGE(p.current_state()[0] == 0,"Stopped should be active"); //Stopped
+ BOOST_CHECK_MESSAGE(p.get_state<BOOST_MSM_EUML_STATE_NAME(Stopped)&>().get_attribute(exit_counter) == 2,
+ "Stopped exit not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<BOOST_MSM_EUML_STATE_NAME(Stopped)&>().get_attribute(entry_counter) == 3,
+ "Stopped entry not called correctly");
+ }
+}
+
diff --git a/src/boost/libs/msm/test/SimpleEuml2.cpp b/src/boost/libs/msm/test/SimpleEuml2.cpp
new file mode 100644
index 000000000..e30b84aac
--- /dev/null
+++ b/src/boost/libs/msm/test/SimpleEuml2.cpp
@@ -0,0 +1,197 @@
+// 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 <iostream>
+#include <boost/msm/back/state_machine.hpp>
+#include <boost/msm/front/euml/euml.hpp>
+
+#ifndef BOOST_MSM_NONSTANDALONE_TEST
+#define BOOST_TEST_MODULE MyTest
+#endif
+#include <boost/test/unit_test.hpp>
+
+using namespace std;
+using namespace boost::msm::front::euml;
+namespace msm = boost::msm;
+
+namespace
+{
+ // A "complicated" event type that carries some data.
+ enum DiskTypeEnum
+ {
+ DISK_CD=0,
+ DISK_DVD=1
+ };
+ // events
+ BOOST_MSM_EUML_EVENT(play)
+ BOOST_MSM_EUML_EVENT(end_pause)
+ BOOST_MSM_EUML_EVENT(stop)
+ BOOST_MSM_EUML_EVENT(pause)
+ BOOST_MSM_EUML_EVENT(open_close)
+ // A "complicated" event type that carries some data.
+ BOOST_MSM_EUML_DECLARE_ATTRIBUTE(std::string,cd_name)
+ BOOST_MSM_EUML_DECLARE_ATTRIBUTE(DiskTypeEnum,cd_type)
+ BOOST_MSM_EUML_ATTRIBUTES((attributes_ << cd_name << cd_type ), cd_detected_attributes)
+ BOOST_MSM_EUML_EVENT_WITH_ATTRIBUTES(cd_detected,cd_detected_attributes)
+
+ //states
+ BOOST_MSM_EUML_DECLARE_ATTRIBUTE(unsigned int,entry_counter)
+ BOOST_MSM_EUML_DECLARE_ATTRIBUTE(unsigned int,exit_counter)
+
+ BOOST_MSM_EUML_STATE(( ++state_(entry_counter),++state_(exit_counter),attributes_ << entry_counter << exit_counter),Empty)
+ BOOST_MSM_EUML_STATE(( ++state_(entry_counter),++state_(exit_counter),attributes_ << entry_counter << exit_counter),Open)
+ BOOST_MSM_EUML_STATE(( ++state_(entry_counter),++state_(exit_counter),attributes_ << entry_counter << exit_counter),Stopped)
+ BOOST_MSM_EUML_STATE(( ++state_(entry_counter),++state_(exit_counter),attributes_ << entry_counter << exit_counter),Playing)
+ BOOST_MSM_EUML_STATE(( ++state_(entry_counter),++state_(exit_counter),attributes_ << entry_counter << exit_counter),Paused)
+
+ //fsm
+ BOOST_MSM_EUML_DECLARE_ATTRIBUTE(unsigned int,start_playback_counter)
+ BOOST_MSM_EUML_DECLARE_ATTRIBUTE(unsigned int,can_close_drawer_counter)
+ BOOST_MSM_EUML_DECLARE_ATTRIBUTE(unsigned int,test_fct_counter)
+ BOOST_MSM_EUML_ACTION(No_Transition)
+ {
+ template <class FSM,class Event>
+ void operator()(Event const&,FSM&,int)
+ {
+ BOOST_FAIL("no_transition called!");
+ }
+ };
+ BOOST_MSM_EUML_ACTION(good_disk_format)
+ {
+ template <class FSM,class EVT,class SourceState,class TargetState>
+ bool operator()(EVT const& evt,FSM&,SourceState& ,TargetState& )
+ {
+ if (evt.get_attribute(cd_type)!=DISK_CD)
+ {
+ return false;
+ }
+ return true;
+ }
+ };
+ BOOST_MSM_EUML_TRANSITION_TABLE((
+ Stopped + play / (++fsm_(start_playback_counter),++fsm_(test_fct_counter)) == Playing,
+ Paused + end_pause == Playing,
+ // +------------------------------------------------------------------------------+
+ Open + open_close / ++fsm_(can_close_drawer_counter) == Empty,
+ // +------------------------------------------------------------------------------+
+ Empty + open_close == Open,
+ Paused + open_close == Open,
+ Stopped + open_close == Open,
+ Playing + open_close == Open,
+ // +------------------------------------------------------------------------------+
+ Playing + pause == Paused,
+ // +------------------------------------------------------------------------------+
+ Playing + stop == Stopped,
+ Paused + stop == Stopped,
+ Empty + cd_detected [good_disk_format ||
+ (event_(cd_type)==Int_<DISK_CD>())] / process_(play) == Stopped,
+ Stopped + stop == Stopped
+ // +------------------------------------------------------------------------------+
+ ),transition_table)
+
+ BOOST_MSM_EUML_DECLARE_STATE_MACHINE(( transition_table, //STT
+ init_ << Empty, // Init State
+ no_action, // Entry
+ no_action, // Exit
+ attributes_ << start_playback_counter
+ << can_close_drawer_counter << test_fct_counter, // Attributes
+ configure_ << no_configure_, // configuration
+ No_Transition // no_transition handler
+ ),
+ player_) //fsm name
+
+ typedef msm::back::state_machine<player_> player;
+
+// static char const* const state_names[] = { "Stopped", "Paused", "Open", "Empty", "Playing" };
+
+
+ BOOST_AUTO_TEST_CASE( my_test )
+ {
+ player p;
+
+ p.start();
+ BOOST_CHECK_MESSAGE(p.get_state<BOOST_MSM_EUML_STATE_NAME(Empty)&>().get_attribute(entry_counter) == 1,
+ "Empty entry not called correctly");
+
+ p.process_event(open_close());
+ BOOST_CHECK_MESSAGE(p.current_state()[0] == 2,"Open should be active"); //Open
+ BOOST_CHECK_MESSAGE(p.get_state<BOOST_MSM_EUML_STATE_NAME(Empty)&>().get_attribute(exit_counter) == 1,
+ "Empty exit not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<BOOST_MSM_EUML_STATE_NAME(Open)&>().get_attribute(entry_counter) == 1,
+ "Open entry not called correctly");
+
+ p.process_event(open_close());
+ BOOST_CHECK_MESSAGE(p.current_state()[0] == 3,"Empty should be active"); //Empty
+ BOOST_CHECK_MESSAGE(p.get_state<BOOST_MSM_EUML_STATE_NAME(Open)&>().get_attribute(exit_counter) == 1,
+ "Open exit not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<BOOST_MSM_EUML_STATE_NAME(Empty)&>().get_attribute(entry_counter) == 2,
+ "Empty entry not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_attribute(can_close_drawer_counter) == 1,"guard not called correctly");
+
+ p.process_event(
+ cd_detected("louie, louie",DISK_DVD));
+ BOOST_CHECK_MESSAGE(p.current_state()[0] == 3,"Empty should be active"); //Empty
+ BOOST_CHECK_MESSAGE(p.get_state<BOOST_MSM_EUML_STATE_NAME(Open)&>().get_attribute(exit_counter) == 1,
+ "Open exit not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<BOOST_MSM_EUML_STATE_NAME(Empty)&>().get_attribute(entry_counter) == 2,
+ "Empty entry not called correctly");
+
+ p.process_event(
+ cd_detected("louie, louie",DISK_CD));
+ BOOST_CHECK_MESSAGE(p.current_state()[0] == 4,"Playing should be active"); //Playing
+ BOOST_CHECK_MESSAGE(p.get_state<BOOST_MSM_EUML_STATE_NAME(Empty)&>().get_attribute(exit_counter) == 2,
+ "Empty exit not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<BOOST_MSM_EUML_STATE_NAME(Stopped)&>().get_attribute(entry_counter) == 1,
+ "Stopped entry not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<BOOST_MSM_EUML_STATE_NAME(Stopped)&>().get_attribute(exit_counter) == 1,
+ "Stopped exit not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<BOOST_MSM_EUML_STATE_NAME(Playing)&>().get_attribute(entry_counter) == 1,
+ "Playing entry not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_attribute(start_playback_counter) == 1,"action not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_attribute(test_fct_counter) == 1,"action not called correctly");
+
+ p.process_event(pause());
+ BOOST_CHECK_MESSAGE(p.current_state()[0] == 1,"Paused should be active"); //Paused
+ BOOST_CHECK_MESSAGE(p.get_state<BOOST_MSM_EUML_STATE_NAME(Playing)&>().get_attribute(exit_counter) == 1,
+ "Playing exit not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<BOOST_MSM_EUML_STATE_NAME(Paused)&>().get_attribute(entry_counter) == 1,
+ "Paused entry not called correctly");
+
+ // go back to Playing
+ p.process_event(end_pause());
+ BOOST_CHECK_MESSAGE(p.current_state()[0] == 4,"Playing should be active"); //Playing
+ BOOST_CHECK_MESSAGE(p.get_state<BOOST_MSM_EUML_STATE_NAME(Paused)&>().get_attribute(exit_counter) == 1,
+ "Paused exit not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<BOOST_MSM_EUML_STATE_NAME(Playing)&>().get_attribute(entry_counter) == 2,
+ "Playing entry not called correctly");
+
+ p.process_event(pause());
+ BOOST_CHECK_MESSAGE(p.current_state()[0] == 1,"Paused should be active"); //Paused
+ BOOST_CHECK_MESSAGE(p.get_state<BOOST_MSM_EUML_STATE_NAME(Playing)&>().get_attribute(exit_counter) == 2,
+ "Playing exit not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<BOOST_MSM_EUML_STATE_NAME(Paused)&>().get_attribute(entry_counter) == 2,
+ "Paused entry not called correctly");
+
+ p.process_event(stop());
+ BOOST_CHECK_MESSAGE(p.current_state()[0] == 0,"Stopped should be active"); //Stopped
+ BOOST_CHECK_MESSAGE(p.get_state<BOOST_MSM_EUML_STATE_NAME(Paused)&>().get_attribute(exit_counter) == 2,
+ "Paused exit not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<BOOST_MSM_EUML_STATE_NAME(Stopped)&>().get_attribute(entry_counter) == 2,
+ "Stopped entry not called correctly");
+
+ p.process_event(stop());
+ BOOST_CHECK_MESSAGE(p.current_state()[0] == 0,"Stopped should be active"); //Stopped
+ BOOST_CHECK_MESSAGE(p.get_state<BOOST_MSM_EUML_STATE_NAME(Stopped)&>().get_attribute(exit_counter) == 2,
+ "Stopped exit not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<BOOST_MSM_EUML_STATE_NAME(Stopped)&>().get_attribute(entry_counter) == 3,
+ "Stopped entry not called correctly");
+ }
+}
+
diff --git a/src/boost/libs/msm/test/SimpleInternal.cpp b/src/boost/libs/msm/test/SimpleInternal.cpp
new file mode 100644
index 000000000..544e02132
--- /dev/null
+++ b/src/boost/libs/msm/test/SimpleInternal.cpp
@@ -0,0 +1,276 @@
+// 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 <iostream>
+// back-end
+#include <boost/msm/back/state_machine.hpp>
+//front-end
+#include <boost/msm/front/state_machine_def.hpp>
+#ifndef BOOST_MSM_NONSTANDALONE_TEST
+#define BOOST_TEST_MODULE MyTest
+#endif
+#include <boost/test/unit_test.hpp>
+
+namespace msm = boost::msm;
+namespace mpl = boost::mpl;
+
+namespace
+{
+ // events
+ struct play {};
+ struct end_pause {};
+ struct stop {};
+ struct pause {};
+ struct open_close {};
+ struct internal_evt {};
+ struct to_ignore {};
+
+ // A "complicated" event type that carries some data.
+ enum DiskTypeEnum
+ {
+ DISK_CD=0,
+ DISK_DVD=1
+ };
+ struct cd_detected
+ {
+ cd_detected(std::string name, DiskTypeEnum diskType)
+ : name(name),
+ disc_type(diskType)
+ {}
+
+ std::string name;
+ DiskTypeEnum disc_type;
+ };
+
+ // front-end: define the FSM structure
+ struct player_ : public msm::front::state_machine_def<player_>
+ {
+ unsigned int start_playback_counter;
+ unsigned int can_close_drawer_counter;
+ unsigned int internal_action_counter;
+ unsigned int internal_guard_counter;
+
+ player_():
+ start_playback_counter(0),
+ can_close_drawer_counter(0),
+ internal_action_counter(0),
+ internal_guard_counter(0)
+ {}
+
+ // The list of FSM states
+ struct Empty : 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;
+ int exit_counter;
+ };
+ struct Open : 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;
+ int exit_counter;
+ };
+
+ // sm_ptr still supported but deprecated as functors are a much better way to do the same thing
+ struct Stopped : 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;
+ int exit_counter;
+ };
+
+ struct Playing : 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;
+ int exit_counter;
+ };
+
+ // state not defining any entry or exit
+ struct Paused : 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;
+ int exit_counter;
+ };
+
+ // the initial state of the player SM. Must be defined
+ typedef Empty initial_state;
+
+ // transition actions
+ void start_playback(play const&) {++start_playback_counter; }
+ void open_drawer(open_close const&) { }
+ void store_cd_info(cd_detected const&) { }
+ void stop_playback(stop const&) { }
+ void pause_playback(pause const&) { }
+ void resume_playback(end_pause const&) { }
+ void stop_and_open(open_close const&) { }
+ void stopped_again(stop const&){}
+ void internal_action(internal_evt const&){++internal_action_counter; }
+ bool internal_guard(cd_detected const&){++internal_guard_counter;return false;}
+ bool internal_guard2(internal_evt const&){++internal_guard_counter;return true;}
+ // guard conditions
+ bool good_disk_format(cd_detected const& evt)
+ {
+ // to test a guard condition, let's say we understand only CDs, not DVD
+ if (evt.disc_type != DISK_CD)
+ {
+ return false;
+ }
+ return true;
+ }
+ bool can_close_drawer(open_close const&)
+ {
+ ++can_close_drawer_counter;
+ return true;
+ }
+
+ typedef player_ p; // makes transition table cleaner
+
+ // Transition table for player
+ struct transition_table : mpl::vector<
+ // Start Event Next Action Guard
+ // +---------+-------------+---------+---------------------+----------------------+
+ a_row < Stopped , play , Playing , &p::start_playback >,
+ a_row < Stopped , open_close , Open , &p::open_drawer >,
+ _row < Stopped , stop , Stopped >,
+ // +---------+-------------+---------+---------------------+----------------------+
+ g_row < Open , open_close , Empty , &p::can_close_drawer >,
+ // +---------+-------------+---------+---------------------+----------------------+
+ a_row < Empty , open_close , Open , &p::open_drawer >,
+ row < Empty , cd_detected , Stopped , &p::store_cd_info ,&p::good_disk_format >,
+ irow < Empty , internal_evt, &p::internal_action ,&p::internal_guard2 >,
+ _irow < Empty , to_ignore >,
+ g_irow < Empty , cd_detected ,&p::internal_guard >,
+ // +---------+-------------+---------+---------------------+----------------------+
+ a_row < Playing , stop , Stopped , &p::stop_playback >,
+ a_row < Playing , pause , Paused , &p::pause_playback >,
+ a_row < Playing , open_close , Open , &p::stop_and_open >,
+ // +---------+-------------+---------+---------------------+----------------------+
+ a_row < Paused , end_pause , Playing , &p::resume_playback >,
+ a_row < Paused , stop , Stopped , &p::stop_playback >,
+ a_row < Paused , open_close , Open , &p::stop_and_open >
+ // +---------+-------------+---------+---------------------+----------------------+
+ > {};
+ // Replaces the default no-transition response.
+ template <class FSM,class Event>
+ void no_transition(Event const&, FSM&,int)
+ {
+ BOOST_FAIL("no_transition called!");
+ }
+ // init counters
+ template <class Event,class FSM>
+ void on_entry(Event const&,FSM& fsm)
+ {
+ fsm.template get_state<player_::Stopped&>().entry_counter=0;
+ fsm.template get_state<player_::Stopped&>().exit_counter=0;
+ fsm.template get_state<player_::Open&>().entry_counter=0;
+ fsm.template get_state<player_::Open&>().exit_counter=0;
+ fsm.template get_state<player_::Empty&>().entry_counter=0;
+ fsm.template get_state<player_::Empty&>().exit_counter=0;
+ fsm.template get_state<player_::Playing&>().entry_counter=0;
+ fsm.template get_state<player_::Playing&>().exit_counter=0;
+ fsm.template get_state<player_::Paused&>().entry_counter=0;
+ fsm.template get_state<player_::Paused&>().exit_counter=0;
+ }
+
+ };
+ // Pick a back-end
+ typedef msm::back::state_machine<player_> player;
+
+// static char const* const state_names[] = { "Stopped", "Open", "Empty", "Playing", "Paused" };
+
+
+ BOOST_AUTO_TEST_CASE( my_test )
+ {
+ player p;
+
+ p.start();
+ BOOST_CHECK_MESSAGE(p.get_state<player_::Empty&>().entry_counter == 1,"Empty entry not called correctly");
+ // internal events
+ p.process_event(to_ignore());
+ p.process_event(internal_evt());
+ BOOST_CHECK_MESSAGE(p.internal_action_counter == 1,"Internal action not called correctly");
+ BOOST_CHECK_MESSAGE(p.internal_guard_counter == 1,"Internal guard not called correctly");
+
+ p.process_event(open_close());
+ BOOST_CHECK_MESSAGE(p.current_state()[0] == 1,"Open should be active"); //Open
+ BOOST_CHECK_MESSAGE(p.get_state<player_::Empty&>().exit_counter == 1,"Empty exit not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<player_::Open&>().entry_counter == 1,"Open entry not called correctly");
+
+ p.process_event(open_close());
+ BOOST_CHECK_MESSAGE(p.current_state()[0] == 2,"Empty should be active"); //Empty
+ BOOST_CHECK_MESSAGE(p.get_state<player_::Open&>().exit_counter == 1,"Open exit not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<player_::Empty&>().entry_counter == 2,"Empty entry not called correctly");
+ BOOST_CHECK_MESSAGE(p.can_close_drawer_counter == 1,"guard not called correctly");
+
+ p.process_event(
+ cd_detected("louie, louie",DISK_DVD));
+ BOOST_CHECK_MESSAGE(p.current_state()[0] == 2,"Empty should be active"); //Empty
+ BOOST_CHECK_MESSAGE(p.get_state<player_::Open&>().exit_counter == 1,"Open exit not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<player_::Empty&>().entry_counter == 2,"Empty entry not called correctly");
+ BOOST_CHECK_MESSAGE(p.internal_guard_counter == 2,"Internal guard not called correctly");
+
+ p.process_event(
+ cd_detected("louie, louie",DISK_CD));
+ BOOST_CHECK_MESSAGE(p.current_state()[0] == 0,"Stopped should be active"); //Stopped
+ BOOST_CHECK_MESSAGE(p.get_state<player_::Empty&>().exit_counter == 2,"Empty exit not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<player_::Stopped&>().entry_counter == 1,"Stopped entry not called correctly");
+ BOOST_CHECK_MESSAGE(p.internal_guard_counter == 3,"Internal guard not called correctly");
+
+ p.process_event(play());
+ BOOST_CHECK_MESSAGE(p.current_state()[0] == 3,"Playing should be active"); //Playing
+ BOOST_CHECK_MESSAGE(p.get_state<player_::Stopped&>().exit_counter == 1,"Stopped exit not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<player_::Playing&>().entry_counter == 1,"Playing entry not called correctly");
+ BOOST_CHECK_MESSAGE(p.start_playback_counter == 1,"action not called correctly");
+
+ p.process_event(pause());
+ BOOST_CHECK_MESSAGE(p.current_state()[0] == 4,"Paused should be active"); //Paused
+ BOOST_CHECK_MESSAGE(p.get_state<player_::Playing&>().exit_counter == 1,"Playing exit not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<player_::Paused&>().entry_counter == 1,"Paused entry not called correctly");
+
+ // go back to Playing
+ p.process_event(end_pause());
+ BOOST_CHECK_MESSAGE(p.current_state()[0] == 3,"Playing should be active"); //Playing
+ BOOST_CHECK_MESSAGE(p.get_state<player_::Paused&>().exit_counter == 1,"Paused exit not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<player_::Playing&>().entry_counter == 2,"Playing entry not called correctly");
+
+ p.process_event(pause());
+ BOOST_CHECK_MESSAGE(p.current_state()[0] == 4,"Paused should be active"); //Paused
+ BOOST_CHECK_MESSAGE(p.get_state<player_::Playing&>().exit_counter == 2,"Playing exit not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<player_::Paused&>().entry_counter == 2,"Paused entry not called correctly");
+
+ p.process_event(stop());
+ BOOST_CHECK_MESSAGE(p.current_state()[0] == 0,"Stopped should be active"); //Stopped
+ BOOST_CHECK_MESSAGE(p.get_state<player_::Paused&>().exit_counter == 2,"Paused exit not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<player_::Stopped&>().entry_counter == 2,"Stopped entry not called correctly");
+
+ p.process_event(stop());
+ BOOST_CHECK_MESSAGE(p.current_state()[0] == 0,"Stopped should be active"); //Stopped
+ BOOST_CHECK_MESSAGE(p.get_state<player_::Stopped&>().exit_counter == 2,"Stopped exit not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<player_::Stopped&>().entry_counter == 3,"Stopped entry not called correctly");
+ }
+}
+
diff --git a/src/boost/libs/msm/test/SimpleInternalEuml.cpp b/src/boost/libs/msm/test/SimpleInternalEuml.cpp
new file mode 100644
index 000000000..f02ad501b
--- /dev/null
+++ b/src/boost/libs/msm/test/SimpleInternalEuml.cpp
@@ -0,0 +1,255 @@
+// 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 <iostream>
+#include <boost/msm/back/state_machine.hpp>
+#include <boost/msm/front/euml/euml.hpp>
+
+#ifndef BOOST_MSM_NONSTANDALONE_TEST
+#define BOOST_TEST_MODULE MyTest
+#endif
+#include <boost/test/unit_test.hpp>
+
+using namespace std;
+using namespace boost::msm::front::euml;
+namespace msm = boost::msm;
+
+namespace
+{
+ // A "complicated" event type that carries some data.
+ enum DiskTypeEnum
+ {
+ DISK_CD=0,
+ DISK_DVD=1
+ };
+ // events
+ BOOST_MSM_EUML_EVENT(play)
+ BOOST_MSM_EUML_EVENT(end_pause)
+ BOOST_MSM_EUML_EVENT(stop)
+ BOOST_MSM_EUML_EVENT(pause)
+ BOOST_MSM_EUML_EVENT(open_close)
+ BOOST_MSM_EUML_EVENT(internal_evt)
+ BOOST_MSM_EUML_EVENT(to_ignore)
+ // A "complicated" event type that carries some data.
+ BOOST_MSM_EUML_DECLARE_ATTRIBUTE(std::string,cd_name)
+ BOOST_MSM_EUML_DECLARE_ATTRIBUTE(DiskTypeEnum,cd_type)
+ BOOST_MSM_EUML_ATTRIBUTES((attributes_ << cd_name << cd_type ), cd_detected_attributes)
+ BOOST_MSM_EUML_EVENT_WITH_ATTRIBUTES(cd_detected,cd_detected_attributes)
+
+ //states
+ BOOST_MSM_EUML_DECLARE_ATTRIBUTE(unsigned int,entry_counter)
+ BOOST_MSM_EUML_DECLARE_ATTRIBUTE(unsigned int,exit_counter)
+
+ BOOST_MSM_EUML_STATE(( ++state_(entry_counter),++state_(exit_counter),attributes_ << entry_counter << exit_counter),Open)
+ BOOST_MSM_EUML_STATE(( ++state_(entry_counter),++state_(exit_counter),attributes_ << entry_counter << exit_counter),Stopped)
+ BOOST_MSM_EUML_STATE(( ++state_(entry_counter),++state_(exit_counter),attributes_ << entry_counter << exit_counter),Playing)
+ BOOST_MSM_EUML_STATE(( ++state_(entry_counter),++state_(exit_counter),attributes_ << entry_counter << exit_counter),Paused)
+
+ BOOST_MSM_EUML_DECLARE_ATTRIBUTE(unsigned int,empty_internal_guard_counter)
+ BOOST_MSM_EUML_DECLARE_ATTRIBUTE(unsigned int,empty_internal_action_counter)
+
+ BOOST_MSM_EUML_ACTION(internal_guard_fct)
+ {
+ template <class FSM,class EVT,class SourceState,class TargetState>
+ bool operator()(EVT const&, FSM& ,SourceState& src,TargetState& )
+ {
+ ++src.get_attribute(empty_internal_guard_counter);
+ return false;
+ }
+ };
+ BOOST_MSM_EUML_DECLARE_STATE((++state_(entry_counter),++state_(exit_counter),
+ attributes_ << entry_counter << exit_counter
+ << empty_internal_guard_counter << empty_internal_action_counter),Empty_def)
+ // derive to be able to add an internal transition table
+ struct Empty_impl : public Empty_def
+ {
+ Empty_impl(){}
+ BOOST_MSM_EUML_DECLARE_INTERNAL_TRANSITION_TABLE((
+ internal_evt [internal_guard_fct] / ++source_(empty_internal_action_counter)
+ ))
+ };
+ // declare an instance for the stt as we are manually declaring a state
+ Empty_impl const Empty;
+
+ //fsm
+ BOOST_MSM_EUML_DECLARE_ATTRIBUTE(unsigned int,start_playback_counter)
+ BOOST_MSM_EUML_DECLARE_ATTRIBUTE(unsigned int,can_close_drawer_counter)
+ BOOST_MSM_EUML_DECLARE_ATTRIBUTE(unsigned int,internal_action_counter)
+ BOOST_MSM_EUML_DECLARE_ATTRIBUTE(unsigned int,internal_guard_counter)
+ BOOST_MSM_EUML_ACTION(No_Transition)
+ {
+ template <class FSM,class Event>
+ void operator()(Event const&,FSM&,int)
+ {
+ BOOST_FAIL("no_transition called!");
+ }
+ };
+ BOOST_MSM_EUML_ACTION(good_disk_format)
+ {
+ template <class FSM,class EVT,class SourceState,class TargetState>
+ bool operator()(EVT const& evt,FSM&,SourceState& ,TargetState& )
+ {
+ if (evt.get_attribute(cd_type)!=DISK_CD)
+ {
+ return false;
+ }
+ return true;
+ }
+ };
+ BOOST_MSM_EUML_ACTION(internal_guard)
+ {
+ template <class FSM,class EVT,class SourceState,class TargetState>
+ bool operator()(EVT const&,FSM& fsm,SourceState& ,TargetState& )
+ {
+ ++fsm.get_attribute(internal_guard_counter);
+ return false;
+ }
+ };
+ BOOST_MSM_EUML_ACTION(internal_guard2)
+ {
+ template <class FSM,class EVT,class SourceState,class TargetState>
+ bool operator()(EVT const&,FSM& fsm,SourceState& ,TargetState& )
+ {
+ ++fsm.get_attribute(internal_guard_counter);
+ return true;
+ }
+ };
+ BOOST_MSM_EUML_TRANSITION_TABLE((
+ Playing == Stopped + play / ++fsm_(start_playback_counter) ,
+ Playing == Paused + end_pause ,
+ // +------------------------------------------------------------------------------+
+ Empty == Open + open_close / ++fsm_(can_close_drawer_counter),
+ Empty + to_ignore ,
+ Empty + internal_evt [internal_guard2] / ++fsm_(internal_action_counter) ,
+ Empty + cd_detected [internal_guard] ,
+ // +------------------------------------------------------------------------------+
+ Open == Empty + open_close ,
+ Open == Paused + open_close ,
+ Open == Stopped + open_close ,
+ Open == Playing + open_close ,
+ // +------------------------------------------------------------------------------+
+ Paused == Playing + pause ,
+ // +------------------------------------------------------------------------------+
+ Stopped == Playing + stop ,
+ Stopped == Paused + stop ,
+ Stopped == Empty + cd_detected [good_disk_format] ,
+ Stopped == Stopped + stop
+ // +------------------------------------------------------------------------------+
+ ),transition_table)
+
+ BOOST_MSM_EUML_DECLARE_STATE_MACHINE(( transition_table, //STT
+ init_ << Empty, // Init State
+ no_action, // Entry
+ no_action, // Exit
+ attributes_ << start_playback_counter << can_close_drawer_counter
+ << internal_action_counter << internal_guard_counter, // Attributes
+ configure_ << no_configure_, // configuration
+ No_Transition // no_transition handler
+ ),
+ player_) //fsm name
+
+ typedef msm::back::state_machine<player_> player;
+
+// static char const* const state_names[] = { "Stopped", "Paused", "Open", "Empty", "Playing" };
+
+
+ BOOST_AUTO_TEST_CASE( my_test )
+ {
+ player p;
+
+ p.start();
+ BOOST_CHECK_MESSAGE(p.get_state<Empty_impl&>().get_attribute(entry_counter) == 1,
+ "Empty entry not called correctly");
+
+ // internal events
+ p.process_event(to_ignore);
+ p.process_event(internal_evt);
+ BOOST_CHECK_MESSAGE(p.get_attribute(internal_action_counter) == 1,"Internal action not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_attribute(internal_guard_counter) == 1,"Internal guard not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<Empty_impl&>().get_attribute(empty_internal_action_counter) == 0,
+ "Empty internal action not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<Empty_impl&>().get_attribute(empty_internal_guard_counter) == 1,
+ "Empty internal guard not called correctly");
+
+ p.process_event(open_close());
+ BOOST_CHECK_MESSAGE(p.current_state()[0] == 2,"Open should be active"); //Open
+ BOOST_CHECK_MESSAGE(p.get_state<Empty_impl&>().get_attribute(exit_counter) == 1,
+ "Empty exit not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<Empty_impl&>().get_attribute(entry_counter) == 1,
+ "Open entry not called correctly");
+
+ p.process_event(open_close());
+ BOOST_CHECK_MESSAGE(p.current_state()[0] == 3,"Empty should be active"); //Empty
+ BOOST_CHECK_MESSAGE(p.get_state<BOOST_MSM_EUML_STATE_NAME(Open)&>().get_attribute(exit_counter) == 1,
+ "Open exit not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<Empty_impl&>().get_attribute(entry_counter) == 2,
+ "Empty entry not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_attribute(can_close_drawer_counter) == 1,"guard not called correctly");
+
+ p.process_event(
+ cd_detected("louie, louie",DISK_DVD));
+ BOOST_CHECK_MESSAGE(p.current_state()[0] == 3,"Empty should be active"); //Empty
+ BOOST_CHECK_MESSAGE(p.get_state<BOOST_MSM_EUML_STATE_NAME(Open)&>().get_attribute(exit_counter) == 1,
+ "Open exit not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<Empty_impl&>().get_attribute(entry_counter) == 2,
+ "Empty entry not called correctly");
+
+ p.process_event(
+ cd_detected("louie, louie",DISK_CD));
+ p.process_event(play);
+ BOOST_CHECK_MESSAGE(p.current_state()[0] == 4,"Playing should be active"); //Playing
+ BOOST_CHECK_MESSAGE(p.get_state<Empty_impl&>().get_attribute(exit_counter) == 2,
+ "Empty exit not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<BOOST_MSM_EUML_STATE_NAME(Stopped)&>().get_attribute(entry_counter) == 1,
+ "Stopped entry not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<BOOST_MSM_EUML_STATE_NAME(Stopped)&>().get_attribute(exit_counter) == 1,
+ "Stopped exit not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<BOOST_MSM_EUML_STATE_NAME(Playing)&>().get_attribute(entry_counter) == 1,
+ "Playing entry not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_attribute(start_playback_counter) == 1,"action not called correctly");
+
+ p.process_event(pause());
+ BOOST_CHECK_MESSAGE(p.current_state()[0] == 1,"Paused should be active"); //Paused
+ BOOST_CHECK_MESSAGE(p.get_state<BOOST_MSM_EUML_STATE_NAME(Playing)&>().get_attribute(exit_counter) == 1,
+ "Playing exit not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<BOOST_MSM_EUML_STATE_NAME(Paused)&>().get_attribute(entry_counter) == 1,
+ "Paused entry not called correctly");
+
+ // go back to Playing
+ p.process_event(end_pause());
+ BOOST_CHECK_MESSAGE(p.current_state()[0] == 4,"Playing should be active"); //Playing
+ BOOST_CHECK_MESSAGE(p.get_state<BOOST_MSM_EUML_STATE_NAME(Paused)&>().get_attribute(exit_counter) == 1,
+ "Paused exit not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<BOOST_MSM_EUML_STATE_NAME(Playing)&>().get_attribute(entry_counter) == 2,
+ "Playing entry not called correctly");
+
+ p.process_event(pause());
+ BOOST_CHECK_MESSAGE(p.current_state()[0] == 1,"Paused should be active"); //Paused
+ BOOST_CHECK_MESSAGE(p.get_state<BOOST_MSM_EUML_STATE_NAME(Playing)&>().get_attribute(exit_counter) == 2,
+ "Playing exit not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<BOOST_MSM_EUML_STATE_NAME(Paused)&>().get_attribute(entry_counter) == 2,
+ "Paused entry not called correctly");
+
+ p.process_event(stop());
+ BOOST_CHECK_MESSAGE(p.current_state()[0] == 0,"Stopped should be active"); //Stopped
+ BOOST_CHECK_MESSAGE(p.get_state<BOOST_MSM_EUML_STATE_NAME(Paused)&>().get_attribute(exit_counter) == 2,
+ "Paused exit not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<BOOST_MSM_EUML_STATE_NAME(Stopped)&>().get_attribute(entry_counter) == 2,
+ "Stopped entry not called correctly");
+
+ p.process_event(stop());
+ BOOST_CHECK_MESSAGE(p.current_state()[0] == 0,"Stopped should be active"); //Stopped
+ BOOST_CHECK_MESSAGE(p.get_state<BOOST_MSM_EUML_STATE_NAME(Stopped)&>().get_attribute(exit_counter) == 2,
+ "Stopped exit not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<BOOST_MSM_EUML_STATE_NAME(Stopped)&>().get_attribute(entry_counter) == 3,
+ "Stopped entry not called correctly");
+ }
+}
+
diff --git a/src/boost/libs/msm/test/SimpleInternalFunctors.cpp b/src/boost/libs/msm/test/SimpleInternalFunctors.cpp
new file mode 100644
index 000000000..ebc659f2c
--- /dev/null
+++ b/src/boost/libs/msm/test/SimpleInternalFunctors.cpp
@@ -0,0 +1,333 @@
+// 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 <iostream>
+// back-end
+#include <boost/msm/back/state_machine.hpp>
+//front-end
+#include <boost/msm/front/state_machine_def.hpp>
+#include <boost/msm/front/functor_row.hpp>
+#include <boost/msm/front/euml/common.hpp>
+
+#ifndef BOOST_MSM_NONSTANDALONE_TEST
+#define BOOST_TEST_MODULE MyTest
+#endif
+#include <boost/test/unit_test.hpp>
+
+using namespace std;
+namespace msm = boost::msm;
+using namespace msm::front;
+namespace mpl = boost::mpl;
+
+namespace
+{
+ // events
+ struct play {};
+ struct end_pause {};
+ struct stop {};
+ struct pause {};
+ struct open_close {};
+ struct internal_evt {};
+ struct to_ignore {};
+
+ // A "complicated" event type that carries some data.
+ enum DiskTypeEnum
+ {
+ DISK_CD=0,
+ DISK_DVD=1
+ };
+ struct cd_detected
+ {
+ cd_detected(std::string name, DiskTypeEnum diskType)
+ : name(name),
+ disc_type(diskType)
+ {}
+
+ std::string name;
+ DiskTypeEnum disc_type;
+ };
+
+ // front-end: define the FSM structure
+ struct player_ : public msm::front::state_machine_def<player_>
+ {
+ unsigned int start_playback_counter;
+ unsigned int can_close_drawer_counter;
+ unsigned int internal_action_counter;
+ unsigned int internal_guard_counter;
+
+ player_():
+ start_playback_counter(0),
+ can_close_drawer_counter(0),
+ internal_action_counter(0),
+ internal_guard_counter(0)
+ {}
+
+ // The list of FSM states
+ struct Empty : 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;
+ int exit_counter;
+ unsigned int empty_internal_guard_counter;
+ unsigned int empty_internal_action_counter;
+ struct internal_guard_fct
+ {
+ template <class EVT,class FSM,class SourceState,class TargetState>
+ bool operator()(EVT const& ,FSM&,SourceState& src,TargetState& )
+ {
+ ++src.empty_internal_guard_counter;
+ return false;
+ }
+ };
+ struct internal_action_fct
+ {
+ template <class EVT,class FSM,class SourceState,class TargetState>
+ void operator()(EVT const& ,FSM& ,SourceState& src,TargetState& )
+ {
+ ++src.empty_internal_action_counter;
+ }
+ };
+ // Transition table for Empty
+ struct internal_transition_table : mpl::vector<
+ // Start Event Next Action Guard
+ Internal < internal_evt , internal_action_fct ,internal_guard_fct >
+ // +---------+-------------+---------+---------------------+----------------------+
+ > {};
+ };
+ struct Open : 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;
+ int exit_counter;
+ };
+
+ // sm_ptr still supported but deprecated as functors are a much better way to do the same thing
+ struct Stopped : 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;
+ int exit_counter;
+ };
+
+ struct Playing : 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;
+ int exit_counter;
+ };
+
+ // state not defining any entry or exit
+ struct Paused : 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;
+ int exit_counter;
+ };
+
+ // the initial state of the player SM. Must be defined
+ typedef Empty initial_state;
+
+ // transition actions
+ void start_playback(play const&) {++start_playback_counter; }
+ void open_drawer(open_close const&) { }
+ void store_cd_info(cd_detected const&) { }
+ void stop_playback(stop const&) { }
+ void pause_playback(pause const&) { }
+ void resume_playback(end_pause const&) { }
+ void stop_and_open(open_close const&) { }
+ void stopped_again(stop const&){}
+ struct internal_action
+ {
+ template <class EVT,class FSM,class SourceState,class TargetState>
+ void operator()(EVT const& ,FSM& fsm,SourceState& ,TargetState& )
+ {
+ ++fsm.internal_action_counter;
+ }
+ };
+ struct internal_guard
+ {
+ template <class EVT,class FSM,class SourceState,class TargetState>
+ bool operator()(EVT const& ,FSM& fsm,SourceState& ,TargetState& )
+ {
+ ++fsm.internal_guard_counter;
+ return false;
+ }
+ };
+ struct internal_guard2
+ {
+ template <class EVT,class FSM,class SourceState,class TargetState>
+ bool operator()(EVT const& ,FSM& fsm,SourceState& ,TargetState& )
+ {
+ ++fsm.internal_guard_counter;
+ return true;
+ }
+ };
+ // guard conditions
+ bool good_disk_format(cd_detected const& evt)
+ {
+ // to test a guard condition, let's say we understand only CDs, not DVD
+ if (evt.disc_type != DISK_CD)
+ {
+ return false;
+ }
+ return true;
+ }
+ bool can_close_drawer(open_close const&)
+ {
+ ++can_close_drawer_counter;
+ return true;
+ }
+
+ typedef player_ p; // makes transition table cleaner
+
+ // Transition table for player
+ struct transition_table : mpl::vector<
+ // Start Event Next Action Guard
+ // +---------+-------------+---------+---------------------+----------------------+
+ a_row < Stopped , play , Playing , &p::start_playback >,
+ a_row < Stopped , open_close , Open , &p::open_drawer >,
+ _row < Stopped , stop , Stopped >,
+ // +---------+-------------+---------+---------------------+----------------------+
+ g_row < Open , open_close , Empty , &p::can_close_drawer >,
+ // +---------+-------------+---------+---------------------+----------------------+
+ a_row < Empty , open_close , Open , &p::open_drawer >,
+ row < Empty , cd_detected , Stopped , &p::store_cd_info ,&p::good_disk_format >,
+ Row < Empty , internal_evt, none , internal_action ,internal_guard2 >,
+ Row < Empty , to_ignore , none , none , none >,
+ Row < Empty , cd_detected , none , none ,internal_guard >,
+ // +---------+-------------+---------+---------------------+----------------------+
+ a_row < Playing , stop , Stopped , &p::stop_playback >,
+ a_row < Playing , pause , Paused , &p::pause_playback >,
+ a_row < Playing , open_close , Open , &p::stop_and_open >,
+ // +---------+-------------+---------+---------------------+----------------------+
+ a_row < Paused , end_pause , Playing , &p::resume_playback >,
+ a_row < Paused , stop , Stopped , &p::stop_playback >,
+ a_row < Paused , open_close , Open , &p::stop_and_open >
+ // +---------+-------------+---------+---------------------+----------------------+
+ > {};
+ // Replaces the default no-transition response.
+ template <class FSM,class Event>
+ void no_transition(Event const&, FSM&,int)
+ {
+ BOOST_FAIL("no_transition called!");
+ }
+ // init counters
+ template <class Event,class FSM>
+ void on_entry(Event const&,FSM& fsm)
+ {
+ fsm.template get_state<player_::Stopped&>().entry_counter=0;
+ fsm.template get_state<player_::Stopped&>().exit_counter=0;
+ fsm.template get_state<player_::Open&>().entry_counter=0;
+ fsm.template get_state<player_::Open&>().exit_counter=0;
+ fsm.template get_state<player_::Empty&>().entry_counter=0;
+ fsm.template get_state<player_::Empty&>().exit_counter=0;
+ fsm.template get_state<player_::Empty&>().empty_internal_guard_counter=0;
+ fsm.template get_state<player_::Empty&>().empty_internal_action_counter=0;
+ fsm.template get_state<player_::Playing&>().entry_counter=0;
+ fsm.template get_state<player_::Playing&>().exit_counter=0;
+ fsm.template get_state<player_::Paused&>().entry_counter=0;
+ fsm.template get_state<player_::Paused&>().exit_counter=0;
+ }
+
+ };
+ // Pick a back-end
+ typedef msm::back::state_machine<player_> player;
+
+// static char const* const state_names[] = { "Stopped", "Open", "Empty", "Playing", "Paused" };
+
+
+ BOOST_AUTO_TEST_CASE( my_test )
+ {
+ player p;
+
+ p.start();
+ BOOST_CHECK_MESSAGE(p.get_state<player_::Empty&>().entry_counter == 1,"Empty entry not called correctly");
+ // internal events
+ p.process_event(to_ignore());
+ p.process_event(internal_evt());
+ BOOST_CHECK_MESSAGE(p.internal_action_counter == 1,"Internal action not called correctly");
+ BOOST_CHECK_MESSAGE(p.internal_guard_counter == 1,"Internal guard not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<player_::Empty&>().empty_internal_action_counter == 0,"Empty internal action not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<player_::Empty&>().empty_internal_guard_counter == 1,"Empty internal guard not called correctly");
+
+ p.process_event(open_close());
+ BOOST_CHECK_MESSAGE(p.current_state()[0] == 1,"Open should be active"); //Open
+ BOOST_CHECK_MESSAGE(p.get_state<player_::Empty&>().exit_counter == 1,"Empty exit not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<player_::Open&>().entry_counter == 1,"Open entry not called correctly");
+
+ p.process_event(open_close());
+ BOOST_CHECK_MESSAGE(p.current_state()[0] == 2,"Empty should be active"); //Empty
+ BOOST_CHECK_MESSAGE(p.get_state<player_::Open&>().exit_counter == 1,"Open exit not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<player_::Empty&>().entry_counter == 2,"Empty entry not called correctly");
+ BOOST_CHECK_MESSAGE(p.can_close_drawer_counter == 1,"guard not called correctly");
+
+ p.process_event(
+ cd_detected("louie, louie",DISK_DVD));
+ BOOST_CHECK_MESSAGE(p.current_state()[0] == 2,"Empty should be active"); //Empty
+ BOOST_CHECK_MESSAGE(p.get_state<player_::Open&>().exit_counter == 1,"Open exit not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<player_::Empty&>().entry_counter == 2,"Empty entry not called correctly");
+ BOOST_CHECK_MESSAGE(p.internal_guard_counter == 2,"Internal guard not called correctly");
+
+ p.process_event(
+ cd_detected("louie, louie",DISK_CD));
+ BOOST_CHECK_MESSAGE(p.current_state()[0] == 0,"Stopped should be active"); //Stopped
+ BOOST_CHECK_MESSAGE(p.get_state<player_::Empty&>().exit_counter == 2,"Empty exit not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<player_::Stopped&>().entry_counter == 1,"Stopped entry not called correctly");
+ BOOST_CHECK_MESSAGE(p.internal_guard_counter == 3,"Internal guard not called correctly");
+
+ p.process_event(play());
+ BOOST_CHECK_MESSAGE(p.current_state()[0] == 3,"Playing should be active"); //Playing
+ BOOST_CHECK_MESSAGE(p.get_state<player_::Stopped&>().exit_counter == 1,"Stopped exit not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<player_::Playing&>().entry_counter == 1,"Playing entry not called correctly");
+ BOOST_CHECK_MESSAGE(p.start_playback_counter == 1,"action not called correctly");
+
+ p.process_event(pause());
+ BOOST_CHECK_MESSAGE(p.current_state()[0] == 4,"Paused should be active"); //Paused
+ BOOST_CHECK_MESSAGE(p.get_state<player_::Playing&>().exit_counter == 1,"Playing exit not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<player_::Paused&>().entry_counter == 1,"Paused entry not called correctly");
+
+ // go back to Playing
+ p.process_event(end_pause());
+ BOOST_CHECK_MESSAGE(p.current_state()[0] == 3,"Playing should be active"); //Playing
+ BOOST_CHECK_MESSAGE(p.get_state<player_::Paused&>().exit_counter == 1,"Paused exit not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<player_::Playing&>().entry_counter == 2,"Playing entry not called correctly");
+
+ p.process_event(pause());
+ BOOST_CHECK_MESSAGE(p.current_state()[0] == 4,"Paused should be active"); //Paused
+ BOOST_CHECK_MESSAGE(p.get_state<player_::Playing&>().exit_counter == 2,"Playing exit not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<player_::Paused&>().entry_counter == 2,"Paused entry not called correctly");
+
+ p.process_event(stop());
+ BOOST_CHECK_MESSAGE(p.current_state()[0] == 0,"Stopped should be active"); //Stopped
+ BOOST_CHECK_MESSAGE(p.get_state<player_::Paused&>().exit_counter == 2,"Paused exit not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<player_::Stopped&>().entry_counter == 2,"Stopped entry not called correctly");
+
+ p.process_event(stop());
+ BOOST_CHECK_MESSAGE(p.current_state()[0] == 0,"Stopped should be active"); //Stopped
+ BOOST_CHECK_MESSAGE(p.get_state<player_::Stopped&>().exit_counter == 2,"Stopped exit not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<player_::Stopped&>().entry_counter == 3,"Stopped entry not called correctly");
+ }
+}
+
diff --git a/src/boost/libs/msm/test/SimpleMachine.cpp b/src/boost/libs/msm/test/SimpleMachine.cpp
new file mode 100644
index 000000000..5f61ac7b8
--- /dev/null
+++ b/src/boost/libs/msm/test/SimpleMachine.cpp
@@ -0,0 +1,257 @@
+// 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 <iostream>
+// back-end
+#include <boost/msm/back/state_machine.hpp>
+//front-end
+#include <boost/msm/front/state_machine_def.hpp>
+#ifndef BOOST_MSM_NONSTANDALONE_TEST
+#define BOOST_TEST_MODULE MyTest
+#endif
+#include <boost/test/unit_test.hpp>
+
+namespace msm = boost::msm;
+namespace mpl = boost::mpl;
+
+namespace
+{
+ // events
+ struct play {};
+ struct end_pause {};
+ struct stop {};
+ struct pause {};
+ struct open_close {};
+
+ // A "complicated" event type that carries some data.
+ enum DiskTypeEnum
+ {
+ DISK_CD=0,
+ DISK_DVD=1
+ };
+ struct cd_detected
+ {
+ cd_detected(std::string name, DiskTypeEnum diskType)
+ : name(name),
+ disc_type(diskType)
+ {}
+
+ std::string name;
+ DiskTypeEnum disc_type;
+ };
+
+ // front-end: define the FSM structure
+ struct player_ : public msm::front::state_machine_def<player_>
+ {
+ unsigned int start_playback_counter;
+ unsigned int can_close_drawer_counter;
+
+ player_():
+ start_playback_counter(0),
+ can_close_drawer_counter(0)
+ {}
+
+ // The list of FSM states
+ struct Empty : 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;
+ int exit_counter;
+ };
+ struct Open : 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;
+ int exit_counter;
+ };
+
+ // sm_ptr still supported but deprecated as functors are a much better way to do the same thing
+ struct Stopped : 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;
+ int exit_counter;
+ };
+
+ struct Playing : 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;
+ int exit_counter;
+ };
+
+ // state not defining any entry or exit
+ struct Paused : 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;
+ int exit_counter;
+ };
+
+ // the initial state of the player SM. Must be defined
+ typedef Empty initial_state;
+
+ // transition actions
+ void start_playback(play const&) {++start_playback_counter; }
+ void open_drawer(open_close const&) { }
+ void store_cd_info(cd_detected const&) { }
+ void stop_playback(stop const&) { }
+ void pause_playback(pause const&) { }
+ void resume_playback(end_pause const&) { }
+ void stop_and_open(open_close const&) { }
+ void stopped_again(stop const&){}
+ // guard conditions
+ bool good_disk_format(cd_detected const& evt)
+ {
+ // to test a guard condition, let's say we understand only CDs, not DVD
+ if (evt.disc_type != DISK_CD)
+ {
+ return false;
+ }
+ return true;
+ }
+ bool can_close_drawer(open_close const&)
+ {
+ ++can_close_drawer_counter;
+ return true;
+ }
+
+ typedef player_ p; // makes transition table cleaner
+
+ // Transition table for player
+ struct transition_table : mpl::vector<
+ // Start Event Next Action Guard
+ // +---------+-------------+---------+---------------------+----------------------+
+ a_row < Stopped , play , Playing , &p::start_playback >,
+ a_row < Stopped , open_close , Open , &p::open_drawer >,
+ _row < Stopped , stop , Stopped >,
+ // +---------+-------------+---------+---------------------+----------------------+
+ g_row < Open , open_close , Empty , &p::can_close_drawer >,
+ // +---------+-------------+---------+---------------------+----------------------+
+ a_row < Empty , open_close , Open , &p::open_drawer >,
+ row < Empty , cd_detected , Stopped , &p::store_cd_info ,&p::good_disk_format >,
+ // +---------+-------------+---------+---------------------+----------------------+
+ a_row < Playing , stop , Stopped , &p::stop_playback >,
+ a_row < Playing , pause , Paused , &p::pause_playback >,
+ a_row < Playing , open_close , Open , &p::stop_and_open >,
+ // +---------+-------------+---------+---------------------+----------------------+
+ a_row < Paused , end_pause , Playing , &p::resume_playback >,
+ a_row < Paused , stop , Stopped , &p::stop_playback >,
+ a_row < Paused , open_close , Open , &p::stop_and_open >
+ // +---------+-------------+---------+---------------------+----------------------+
+ > {};
+ // Replaces the default no-transition response.
+ template <class FSM,class Event>
+ void no_transition(Event const& , FSM&,int)
+ {
+ BOOST_FAIL("no_transition called!");
+ }
+ // init counters
+ template <class Event,class FSM>
+ void on_entry(Event const&,FSM& fsm)
+ {
+ fsm.template get_state<player_::Stopped&>().entry_counter=0;
+ fsm.template get_state<player_::Stopped&>().exit_counter=0;
+ fsm.template get_state<player_::Open&>().entry_counter=0;
+ fsm.template get_state<player_::Open&>().exit_counter=0;
+ fsm.template get_state<player_::Empty&>().entry_counter=0;
+ fsm.template get_state<player_::Empty&>().exit_counter=0;
+ fsm.template get_state<player_::Playing&>().entry_counter=0;
+ fsm.template get_state<player_::Playing&>().exit_counter=0;
+ fsm.template get_state<player_::Paused&>().entry_counter=0;
+ fsm.template get_state<player_::Paused&>().exit_counter=0;
+ }
+
+ };
+ // Pick a back-end
+ typedef msm::back::state_machine<player_> player;
+
+// static char const* const state_names[] = { "Stopped", "Open", "Empty", "Playing", "Paused" };
+
+
+ BOOST_AUTO_TEST_CASE( my_test )
+ {
+ player p;
+
+ p.start();
+ BOOST_CHECK_MESSAGE(p.get_state<player_::Empty&>().entry_counter == 1,"Empty entry not called correctly");
+
+ p.process_event(open_close());
+ BOOST_CHECK_MESSAGE(p.current_state()[0] == 1,"Open should be active"); //Open
+ BOOST_CHECK_MESSAGE(p.get_state<player_::Empty&>().exit_counter == 1,"Empty exit not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<player_::Open&>().entry_counter == 1,"Open entry not called correctly");
+
+ p.process_event(open_close());
+ BOOST_CHECK_MESSAGE(p.current_state()[0] == 2,"Empty should be active"); //Empty
+ BOOST_CHECK_MESSAGE(p.get_state<player_::Open&>().exit_counter == 1,"Open exit not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<player_::Empty&>().entry_counter == 2,"Empty entry not called correctly");
+ BOOST_CHECK_MESSAGE(p.can_close_drawer_counter == 1,"guard not called correctly");
+
+ p.process_event(
+ cd_detected("louie, louie",DISK_DVD));
+ BOOST_CHECK_MESSAGE(p.current_state()[0] == 2,"Empty should be active"); //Empty
+ BOOST_CHECK_MESSAGE(p.get_state<player_::Open&>().exit_counter == 1,"Open exit not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<player_::Empty&>().entry_counter == 2,"Empty entry not called correctly");
+
+ p.process_event(
+ cd_detected("louie, louie",DISK_CD));
+ BOOST_CHECK_MESSAGE(p.current_state()[0] == 0,"Stopped should be active"); //Stopped
+ BOOST_CHECK_MESSAGE(p.get_state<player_::Empty&>().exit_counter == 2,"Empty exit not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<player_::Stopped&>().entry_counter == 1,"Stopped entry not called correctly");
+
+ p.process_event(play());
+ BOOST_CHECK_MESSAGE(p.current_state()[0] == 3,"Playing should be active"); //Playing
+ BOOST_CHECK_MESSAGE(p.get_state<player_::Stopped&>().exit_counter == 1,"Stopped exit not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<player_::Playing&>().entry_counter == 1,"Playing entry not called correctly");
+ BOOST_CHECK_MESSAGE(p.start_playback_counter == 1,"action not called correctly");
+
+ p.process_event(pause());
+ BOOST_CHECK_MESSAGE(p.current_state()[0] == 4,"Paused should be active"); //Paused
+ BOOST_CHECK_MESSAGE(p.get_state<player_::Playing&>().exit_counter == 1,"Playing exit not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<player_::Paused&>().entry_counter == 1,"Paused entry not called correctly");
+
+ // go back to Playing
+ p.process_event(end_pause());
+ BOOST_CHECK_MESSAGE(p.current_state()[0] == 3,"Playing should be active"); //Playing
+ BOOST_CHECK_MESSAGE(p.get_state<player_::Paused&>().exit_counter == 1,"Paused exit not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<player_::Playing&>().entry_counter == 2,"Playing entry not called correctly");
+
+ p.process_event(pause());
+ BOOST_CHECK_MESSAGE(p.current_state()[0] == 4,"Paused should be active"); //Paused
+ BOOST_CHECK_MESSAGE(p.get_state<player_::Playing&>().exit_counter == 2,"Playing exit not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<player_::Paused&>().entry_counter == 2,"Paused entry not called correctly");
+
+ p.process_event(stop());
+ BOOST_CHECK_MESSAGE(p.current_state()[0] == 0,"Stopped should be active"); //Stopped
+ BOOST_CHECK_MESSAGE(p.get_state<player_::Paused&>().exit_counter == 2,"Paused exit not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<player_::Stopped&>().entry_counter == 2,"Stopped entry not called correctly");
+
+ p.process_event(stop());
+ BOOST_CHECK_MESSAGE(p.current_state()[0] == 0,"Stopped should be active"); //Stopped
+ BOOST_CHECK_MESSAGE(p.get_state<player_::Stopped&>().exit_counter == 2,"Stopped exit not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<player_::Stopped&>().entry_counter == 3,"Stopped entry not called correctly");
+ }
+}
+
diff --git a/src/boost/libs/msm/test/SimpleWithFunctors.cpp b/src/boost/libs/msm/test/SimpleWithFunctors.cpp
new file mode 100644
index 000000000..8f12bfba7
--- /dev/null
+++ b/src/boost/libs/msm/test/SimpleWithFunctors.cpp
@@ -0,0 +1,361 @@
+// 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 <iostream>
+// back-end
+#include <boost/msm/back/state_machine.hpp>
+//front-end
+#include <boost/msm/front/state_machine_def.hpp>
+// functors
+#include <boost/msm/front/functor_row.hpp>
+#include <boost/msm/front/euml/common.hpp>
+// for And_ operator
+#include <boost/msm/front/euml/operator.hpp>
+
+#ifndef BOOST_MSM_NONSTANDALONE_TEST
+#define BOOST_TEST_MODULE MyTest
+#endif
+#include <boost/test/unit_test.hpp>
+
+using namespace std;
+namespace msm = boost::msm;
+namespace mpl = boost::mpl;
+using namespace msm::front;
+// for And_ operator
+using namespace msm::front::euml;
+
+namespace
+{
+ // events
+ struct play {};
+ struct end_pause {};
+ struct stop {};
+ struct pause {};
+ struct open_close {};
+
+ // A "complicated" event type that carries some data.
+ enum DiskTypeEnum
+ {
+ DISK_CD=0,
+ DISK_DVD=1
+ };
+ struct cd_detected
+ {
+ cd_detected(std::string name, DiskTypeEnum diskType)
+ : name(name),
+ disc_type(diskType)
+ {}
+
+ std::string name;
+ DiskTypeEnum disc_type;
+ };
+
+ // front-end: define the FSM structure
+ struct player_ : public msm::front::state_machine_def<player_>
+ {
+ unsigned int start_playback_counter;
+ unsigned int can_close_drawer_counter;
+ unsigned int test_fct_counter;
+
+ player_():
+ start_playback_counter(0),
+ can_close_drawer_counter(0),
+ test_fct_counter(0)
+ {}
+
+ // The list of FSM states
+ struct Empty : 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;
+ int exit_counter;
+ };
+ struct Open : 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;
+ int exit_counter;
+ };
+
+ // sm_ptr still supported but deprecated as functors are a much better way to do the same thing
+ struct Stopped : 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;
+ int exit_counter;
+ };
+
+ struct Playing : 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;
+ int exit_counter;
+ };
+
+ // state not defining any entry or exit
+ struct Paused : 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;
+ int exit_counter;
+ };
+
+ // the initial state of the player SM. Must be defined
+ typedef Empty initial_state;
+
+ // transition actions
+ struct TestFct
+ {
+ template <class EVT,class FSM,class SourceState,class TargetState>
+ void operator()(EVT const&, FSM& fsm,SourceState& ,TargetState& )
+ {
+ ++fsm.test_fct_counter;
+ }
+ };
+ struct start_playback
+ {
+ template <class EVT,class FSM,class SourceState,class TargetState>
+ void operator()(EVT const& ,FSM& fsm,SourceState& ,TargetState& )
+ {
+ ++fsm.start_playback_counter;
+ }
+ };
+ struct open_drawer
+ {
+ template <class EVT,class FSM,class SourceState,class TargetState>
+ void operator()(EVT const& ,FSM& ,SourceState& ,TargetState& )
+ {
+ }
+ };
+ struct close_drawer
+ {
+ template <class EVT,class FSM,class SourceState,class TargetState>
+ void operator()(EVT const& ,FSM& ,SourceState& ,TargetState& )
+ {
+ }
+ };
+ struct store_cd_info
+ {
+ template <class EVT,class FSM,class SourceState,class TargetState>
+ void operator()(EVT const&,FSM& fsm ,SourceState& ,TargetState& )
+ {
+ fsm.process_event(play());
+ }
+ };
+ struct stop_playback
+ {
+ template <class EVT,class FSM,class SourceState,class TargetState>
+ void operator()(EVT const& ,FSM& ,SourceState& ,TargetState& )
+ {
+ }
+ };
+ struct pause_playback
+ {
+ template <class EVT,class FSM,class SourceState,class TargetState>
+ void operator()(EVT const& ,FSM& ,SourceState& ,TargetState& )
+ {
+ }
+ };
+ struct resume_playback
+ {
+ template <class EVT,class FSM,class SourceState,class TargetState>
+ void operator()(EVT const& ,FSM& ,SourceState& ,TargetState& )
+ {
+ }
+ };
+ struct stop_and_open
+ {
+ template <class EVT,class FSM,class SourceState,class TargetState>
+ void operator()(EVT const& ,FSM& ,SourceState& ,TargetState& )
+ {
+ }
+ };
+ struct stopped_again
+ {
+ template <class EVT,class FSM,class SourceState,class TargetState>
+ void operator()(EVT const& ,FSM& ,SourceState& ,TargetState& )
+ {
+ }
+ };
+ // guard conditions
+ struct DummyGuard
+ {
+ template <class EVT,class FSM,class SourceState,class TargetState>
+ bool operator()(EVT const&,FSM&,SourceState&,TargetState&)
+ {
+ return true;
+ }
+ };
+ struct good_disk_format
+ {
+ template <class EVT,class FSM,class SourceState,class TargetState>
+ bool operator()(EVT const& evt ,FSM&,SourceState& ,TargetState& )
+ {
+ // to test a guard condition, let's say we understand only CDs, not DVD
+ if (evt.disc_type != DISK_CD)
+ {
+ return false;
+ }
+ return true;
+ }
+ };
+ struct always_true
+ {
+ template <class EVT,class FSM,class SourceState,class TargetState>
+ bool operator()(EVT const& ,FSM&,SourceState& ,TargetState& )
+ {
+ return true;
+ }
+ };
+ struct can_close_drawer
+ {
+ template <class EVT,class FSM,class SourceState,class TargetState>
+ bool operator()(EVT const& ,FSM& fsm,SourceState& ,TargetState& )
+ {
+ ++fsm.can_close_drawer_counter;
+ return true;
+ }
+ };
+
+ typedef player_ p; // makes transition table cleaner
+
+ // Transition table for player
+ struct transition_table : mpl::vector<
+ // Start Event Next Action Guard
+ // +---------+-------------+---------+---------------------+----------------------+
+ Row < Stopped , play , Playing , ActionSequence_
+ <mpl::vector<
+ TestFct,start_playback> >
+ , DummyGuard >,
+ Row < Stopped , open_close , Open , open_drawer , none >,
+ Row < Stopped , stop , Stopped , none , none >,
+ // +---------+-------------+---------+---------------------------+----------------------+
+ Row < Open , open_close , Empty , close_drawer , can_close_drawer >,
+ // +---------+-------------+---------+---------------------------+----------------------+
+ Row < Empty , open_close , Open , open_drawer , none >,
+ Row < Empty , cd_detected , Stopped , store_cd_info , And_<good_disk_format,
+ always_true> >,
+ // +---------+-------------+---------+---------------------------+----------------------+
+ Row < Playing , stop , Stopped , stop_playback , none >,
+ Row < Playing , pause , Paused , pause_playback , none >,
+ Row < Playing , open_close , Open , stop_and_open , none >,
+ // +---------+-------------+---------+---------------------------+----------------------+
+ Row < Paused , end_pause , Playing , resume_playback , none >,
+ Row < Paused , stop , Stopped , stop_playback , none >,
+ Row < Paused , open_close , Open , stop_and_open , none >
+
+ // +---------+-------------+---------+---------------------+----------------------+
+ > {};
+ // Replaces the default no-transition response.
+ template <class FSM,class Event>
+ void no_transition(Event const&, FSM&,int)
+ {
+ BOOST_FAIL("no_transition called!");
+ }
+ // init counters
+ template <class Event,class FSM>
+ void on_entry(Event const&,FSM& fsm)
+ {
+ fsm.template get_state<player_::Stopped&>().entry_counter=0;
+ fsm.template get_state<player_::Stopped&>().exit_counter=0;
+ fsm.template get_state<player_::Open&>().entry_counter=0;
+ fsm.template get_state<player_::Open&>().exit_counter=0;
+ fsm.template get_state<player_::Empty&>().entry_counter=0;
+ fsm.template get_state<player_::Empty&>().exit_counter=0;
+ fsm.template get_state<player_::Playing&>().entry_counter=0;
+ fsm.template get_state<player_::Playing&>().exit_counter=0;
+ fsm.template get_state<player_::Paused&>().entry_counter=0;
+ fsm.template get_state<player_::Paused&>().exit_counter=0;
+ }
+
+ };
+ // Pick a back-end
+ typedef msm::back::state_machine<player_> player;
+
+// static char const* const state_names[] = { "Stopped", "Open", "Empty", "Playing", "Paused" };
+
+
+ BOOST_AUTO_TEST_CASE( my_test )
+ {
+ player p;
+
+ p.start();
+ BOOST_CHECK_MESSAGE(p.get_state<player_::Empty&>().entry_counter == 1,"Empty entry not called correctly");
+
+ p.process_event(open_close());
+ BOOST_CHECK_MESSAGE(p.current_state()[0] == 1,"Open should be active"); //Open
+ BOOST_CHECK_MESSAGE(p.get_state<player_::Empty&>().exit_counter == 1,"Empty exit not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<player_::Open&>().entry_counter == 1,"Open entry not called correctly");
+
+ p.process_event(open_close());
+ BOOST_CHECK_MESSAGE(p.current_state()[0] == 2,"Empty should be active"); //Empty
+ BOOST_CHECK_MESSAGE(p.get_state<player_::Open&>().exit_counter == 1,"Open exit not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<player_::Empty&>().entry_counter == 2,"Empty entry not called correctly");
+ BOOST_CHECK_MESSAGE(p.can_close_drawer_counter == 1,"guard not called correctly");
+
+ p.process_event(
+ cd_detected("louie, louie",DISK_DVD));
+ BOOST_CHECK_MESSAGE(p.current_state()[0] == 2,"Empty should be active"); //Empty
+ BOOST_CHECK_MESSAGE(p.get_state<player_::Open&>().exit_counter == 1,"Open exit not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<player_::Empty&>().entry_counter == 2,"Empty entry not called correctly");
+
+ p.process_event(
+ cd_detected("louie, louie",DISK_CD));
+ BOOST_CHECK_MESSAGE(p.current_state()[0] == 3,"Playing should be active"); //Playing
+ BOOST_CHECK_MESSAGE(p.get_state<player_::Empty&>().exit_counter == 2,"Empty exit not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<player_::Stopped&>().entry_counter == 1,"Stopped entry not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<player_::Stopped&>().exit_counter == 1,"Stopped exit not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<player_::Playing&>().entry_counter == 1,"Playing entry not called correctly");
+ BOOST_CHECK_MESSAGE(p.start_playback_counter == 1,"action not called correctly");
+ BOOST_CHECK_MESSAGE(p.test_fct_counter == 1,"action not called correctly");
+
+ p.process_event(pause());
+ BOOST_CHECK_MESSAGE(p.current_state()[0] == 4,"Paused should be active"); //Paused
+ BOOST_CHECK_MESSAGE(p.get_state<player_::Playing&>().exit_counter == 1,"Playing exit not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<player_::Paused&>().entry_counter == 1,"Paused entry not called correctly");
+
+ // go back to Playing
+ p.process_event(end_pause());
+ BOOST_CHECK_MESSAGE(p.current_state()[0] == 3,"Playing should be active"); //Playing
+ BOOST_CHECK_MESSAGE(p.get_state<player_::Paused&>().exit_counter == 1,"Paused exit not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<player_::Playing&>().entry_counter == 2,"Playing entry not called correctly");
+
+ p.process_event(pause());
+ BOOST_CHECK_MESSAGE(p.current_state()[0] == 4,"Paused should be active"); //Paused
+ BOOST_CHECK_MESSAGE(p.get_state<player_::Playing&>().exit_counter == 2,"Playing exit not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<player_::Paused&>().entry_counter == 2,"Paused entry not called correctly");
+
+ p.process_event(stop());
+ BOOST_CHECK_MESSAGE(p.current_state()[0] == 0,"Stopped should be active"); //Stopped
+ BOOST_CHECK_MESSAGE(p.get_state<player_::Paused&>().exit_counter == 2,"Paused exit not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<player_::Stopped&>().entry_counter == 2,"Stopped entry not called correctly");
+
+ p.process_event(stop());
+ BOOST_CHECK_MESSAGE(p.current_state()[0] == 0,"Stopped should be active"); //Stopped
+ BOOST_CHECK_MESSAGE(p.get_state<player_::Stopped&>().exit_counter == 2,"Stopped exit not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<player_::Stopped&>().entry_counter == 3,"Stopped entry not called correctly");
+ }
+}
+
diff --git a/src/boost/libs/msm/test/Test2RegionsAnonymous.cpp b/src/boost/libs/msm/test/Test2RegionsAnonymous.cpp
new file mode 100644
index 000000000..69d6137b0
--- /dev/null
+++ b/src/boost/libs/msm/test/Test2RegionsAnonymous.cpp
@@ -0,0 +1,172 @@
+// 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 <iostream>
+// back-end
+#include <boost/msm/back/state_machine.hpp>
+//front-end
+#include <boost/msm/front/state_machine_def.hpp>
+// functors
+#include <boost/msm/front/functor_row.hpp>
+#include <boost/msm/front/euml/common.hpp>
+// for And_ operator
+#include <boost/msm/front/euml/operator.hpp>
+
+#include <boost/test/unit_test.hpp>
+
+using namespace std;
+namespace msm = boost::msm;
+namespace mpl = boost::mpl;
+using namespace msm::front;
+// for And_ operator
+using namespace msm::front::euml;
+
+namespace
+{
+ // events
+ struct event1 {};
+ struct event2 {};
+
+ // front-end: define the FSM structure
+ struct my_machine_ : public msm::front::state_machine_def<my_machine_>
+ {
+
+ // The list of FSM states
+ struct State1 : 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;
+ int exit_counter;
+ };
+ struct State2 : 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;
+ int exit_counter;
+ };
+
+ struct State3 : 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;
+ int exit_counter;
+ };
+
+ struct State1b : 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;
+ int exit_counter;
+ };
+ struct State2b : 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;
+ int exit_counter;
+ };
+
+ struct always_true
+ {
+ template <class EVT,class FSM,class SourceState,class TargetState>
+ bool operator()(EVT const& ,FSM&,SourceState& ,TargetState& )
+ {
+ return true;
+ }
+ };
+ struct always_false
+ {
+ template <class EVT,class FSM,class SourceState,class TargetState>
+ bool operator()(EVT const& ,FSM&,SourceState& ,TargetState& )
+ {
+ return false;
+ }
+ };
+
+ // the initial state of the player SM. Must be defined
+ typedef boost::mpl::vector2<State1,State1b> initial_state;
+
+ // Transition table for player
+ struct transition_table : boost::mpl::vector<
+ // Start Event Next Action Guard
+ // +---------+-------------+---------+---------------------+----------------------+
+ Row < State1 , event1 , State2 , none , always_true >,
+ Row < State2 , none , State3 >,
+ // +---------+-------------+---------+---------------------+----------------------+
+ Row < State1b , event1 , State2b , none , always_false >
+ // +---------+-------------+---------+---------------------+----------------------+
+ > {};
+ // Replaces the default no-transition response.
+ template <class FSM,class Event>
+ void no_transition(Event const&, FSM&,int)
+ {
+ BOOST_FAIL("no_transition called!");
+ }
+ // init counters
+ template <class Event,class FSM>
+ void on_entry(Event const&,FSM& fsm)
+ {
+ fsm.template get_state<my_machine_::State1&>().entry_counter=0;
+ fsm.template get_state<my_machine_::State1&>().exit_counter=0;
+ fsm.template get_state<my_machine_::State2&>().entry_counter=0;
+ fsm.template get_state<my_machine_::State2&>().exit_counter=0;
+ fsm.template get_state<my_machine_::State3&>().entry_counter=0;
+ fsm.template get_state<my_machine_::State3&>().exit_counter=0;
+ fsm.template get_state<my_machine_::State1b&>().entry_counter=0;
+ fsm.template get_state<my_machine_::State1b&>().exit_counter=0;
+ fsm.template get_state<my_machine_::State2b&>().entry_counter=0;
+ fsm.template get_state<my_machine_::State2b&>().exit_counter=0;
+ }
+ };
+ // Pick a back-end
+ typedef msm::back::state_machine<my_machine_> my_machine;
+
+ BOOST_AUTO_TEST_CASE( my_test )
+ {
+ my_machine p;
+
+ p.start();
+ BOOST_CHECK_MESSAGE(p.current_state()[0] == 0,"State1 should be active");
+ BOOST_CHECK_MESSAGE(p.current_state()[1] == 2,"State1b should be active");
+
+ p.process_event(event1());
+ BOOST_CHECK_MESSAGE(p.current_state()[0] == 3,"State3 should be active");
+ BOOST_CHECK_MESSAGE(p.current_state()[1] == 2,"State1b should be active");
+
+ BOOST_CHECK_MESSAGE(p.get_state<my_machine_::State1&>().exit_counter == 1,"State1 exit not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<my_machine_::State1&>().entry_counter == 1,"State1 entry not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<my_machine_::State2&>().exit_counter == 1,"State2 exit not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<my_machine_::State2&>().entry_counter == 1,"State2 entry not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<my_machine_::State3&>().exit_counter == 0,"State3 exit not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<my_machine_::State3&>().entry_counter == 1,"State3 entry not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<my_machine_::State1b&>().entry_counter == 1,"State1b entry not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<my_machine_::State1b&>().exit_counter == 0,"State1b exit not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<my_machine_::State2b&>().entry_counter == 0,"State2b entry not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<my_machine_::State2b&>().exit_counter == 0,"State2b exit not called correctly");
+
+
+ }
+}
+
+
diff --git a/src/boost/libs/msm/test/TestConstructor.cpp b/src/boost/libs/msm/test/TestConstructor.cpp
new file mode 100644
index 000000000..060d11b6c
--- /dev/null
+++ b/src/boost/libs/msm/test/TestConstructor.cpp
@@ -0,0 +1,269 @@
+// 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 <iostream>
+// back-end
+#include <boost/msm/back/state_machine.hpp>
+//front-end
+#include <boost/msm/front/state_machine_def.hpp>
+#ifndef BOOST_MSM_NONSTANDALONE_TEST
+#define BOOST_TEST_MODULE MyTest
+#endif
+#include <boost/test/unit_test.hpp>
+
+namespace msm = boost::msm;
+namespace mpl = boost::mpl;
+
+
+namespace
+{
+ struct SomeExternalContext
+ {
+ SomeExternalContext(int b):bla(b){}
+ int bla;
+ };
+ // events
+ struct play {};
+ struct end_pause {};
+ struct stop {};
+ struct pause {};
+ struct open_close {};
+ struct NextSong {};
+ struct PreviousSong {};
+
+ // A "complicated" event type that carries some data.
+ enum DiskTypeEnum
+ {
+ DISK_CD=0,
+ DISK_DVD=1
+ };
+ struct cd_detected
+ {
+ cd_detected(std::string name, DiskTypeEnum diskType)
+ : name(name),
+ disc_type(diskType)
+ {}
+
+ std::string name;
+ DiskTypeEnum disc_type;
+ };
+
+ // front-end: define the FSM structure
+ struct player_ : public msm::front::state_machine_def<player_>
+ {
+ player_(SomeExternalContext& context,int someint)
+ :context_(context)
+ {
+ BOOST_CHECK_MESSAGE(context_.bla == 3,"Wrong context value");
+ BOOST_CHECK_MESSAGE(someint == 5,"Wrong int value");
+ context.bla = 10;
+ }
+
+ SomeExternalContext& context_;
+
+ // The list of FSM states
+ struct Empty : public msm::front::state<>
+ {
+ int data_;
+ Empty():data_(0){}
+ Empty(int i):data_(i){}
+ // every (optional) entry/exit methods get the event passed.
+ template <class Event,class FSM>
+ void on_entry(Event const&,FSM& ) {std::cout << "entering: Empty" << std::endl;}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {std::cout << "leaving: Empty" << std::endl;}
+ };
+ struct Open : public msm::front::state<>
+ {
+ int data_;
+ Open():data_(0){}
+ Open(int i):data_(i){}
+
+ template <class Event,class FSM>
+ void on_entry(Event const& ,FSM&) {std::cout << "entering: Open" << std::endl;}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {std::cout << "leaving: Open" << std::endl;}
+ };
+
+ // sm_ptr still supported but deprecated as functors are a much better way to do the same thing
+ struct Stopped : public msm::front::state<msm::front::default_base_state,msm::front::sm_ptr>
+ {
+ template <class Event,class FSM>
+ void on_entry(Event const& ,FSM&) {std::cout << "entering: Stopped" << std::endl;}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {std::cout << "leaving: Stopped" << std::endl;}
+ void set_sm_ptr(player_* pl)
+ {
+ m_player=pl;
+ }
+ player_* m_player;
+ };
+
+ struct Playing_ : public msm::front::state_machine_def<Playing_>
+ {
+ // when playing, the CD is loaded and we are in either pause or playing (duh)
+ template <class Event,class FSM>
+ void on_entry(Event const&,FSM& ) {std::cout << "entering: Playing" << std::endl;}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {std::cout << "leaving: Playing" << std::endl;}
+
+ // The list of FSM states
+ struct Song1 : public msm::front::state<>
+ {
+ int data_;
+ Song1():data_(0){}
+ Song1(int i):data_(i){}
+
+ template <class Event,class FSM>
+ void on_entry(Event const&,FSM& ) {std::cout << "starting: First song" << std::endl;}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {std::cout << "finishing: First Song" << std::endl;}
+
+ };
+ struct Song2 : public msm::front::state<>
+ {
+ template <class Event,class FSM>
+ void on_entry(Event const&,FSM& ) {std::cout << "starting: Second song" << std::endl;}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {std::cout << "finishing: Second Song" << std::endl;}
+ };
+ struct Song3 : public msm::front::state<>
+ {
+ template <class Event,class FSM>
+ void on_entry(Event const&,FSM& ) {std::cout << "starting: Third song" << std::endl;}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {std::cout << "finishing: Third Song" << std::endl;}
+ };
+ // the initial state. Must be defined
+ typedef Song1 initial_state;
+ // transition actions
+ void start_next_song(NextSong const&) { std::cout << "Playing::start_next_song\n"; }
+ void start_prev_song(PreviousSong const&) { std::cout << "Playing::start_prev_song\n"; }
+ // guard conditions
+
+ typedef Playing_ pl; // makes transition table cleaner
+ // Transition table for Playing
+ struct transition_table : mpl::vector4<
+ // Start Event Next Action Guard
+ // +---------+-------------+---------+---------------------+----------------------+
+ a_row < Song1 , NextSong , Song2 , &pl::start_next_song >,
+ a_row < Song2 , PreviousSong, Song1 , &pl::start_prev_song >,
+ a_row < Song2 , NextSong , Song3 , &pl::start_next_song >,
+ a_row < Song3 , PreviousSong, Song2 , &pl::start_prev_song >
+ // +---------+-------------+---------+---------------------+----------------------+
+ > {};
+ // Replaces the default no-transition response.
+ template <class FSM,class Event>
+ void no_transition(Event const& e, FSM&,int state)
+ {
+ std::cout << "no transition from state " << state
+ << " on event " << typeid(e).name() << std::endl;
+ }
+ };
+ // back-end
+ typedef msm::back::state_machine<Playing_> Playing;
+
+ // state not defining any entry or exit
+ struct Paused : public msm::front::state<>
+ {
+ };
+
+ // the initial state of the player SM. Must be defined
+ typedef Empty initial_state;
+
+ // transition actions
+ void start_playback(play const&) { std::cout << "player::start_playback\n"; }
+ void open_drawer(open_close const&) { std::cout << "player::open_drawer\n"; }
+ void close_drawer(open_close const&) { std::cout << "player::close_drawer\n"; }
+ void store_cd_info(cd_detected const&) { std::cout << "player::store_cd_info\n"; }
+ void stop_playback(stop const&) { std::cout << "player::stop_playback\n"; }
+ void pause_playback(pause const&) { std::cout << "player::pause_playback\n"; }
+ void resume_playback(end_pause const&) { std::cout << "player::resume_playback\n"; }
+ void stop_and_open(open_close const&) { std::cout << "player::stop_and_open\n"; }
+ void stopped_again(stop const&) {std::cout << "player::stopped_again\n";}
+ // guard conditions
+ bool good_disk_format(cd_detected const& evt)
+ {
+ // to test a guard condition, let's say we understand only CDs, not DVD
+ if (evt.disc_type != DISK_CD)
+ {
+ std::cout << "wrong disk, sorry" << std::endl;
+ return false;
+ }
+ return true;
+ }
+ // used to show a transition conflict. This guard will simply deactivate one transition and thus
+ // solve the conflict
+ bool auto_start(cd_detected const&)
+ {
+ return false;
+ }
+
+ typedef player_ p; // makes transition table cleaner
+
+ // Transition table for player
+ struct transition_table : mpl::vector<
+ // Start Event Next Action Guard
+ // +---------+-------------+---------+---------------------+----------------------+
+ a_row < Stopped , play , Playing , &p::start_playback >,
+ a_row < Stopped , open_close , Open , &p::open_drawer >,
+ _row < Stopped , stop , Stopped >,
+ // +---------+-------------+---------+---------------------+----------------------+
+ a_row < Open , open_close , Empty , &p::close_drawer >,
+ // +---------+-------------+---------+---------------------+----------------------+
+ a_row < Empty , open_close , Open , &p::open_drawer >,
+ row < Empty , cd_detected , Stopped , &p::store_cd_info ,&p::good_disk_format >,
+ row < Empty , cd_detected , Playing , &p::store_cd_info ,&p::auto_start >,
+ // +---------+-------------+---------+---------------------+----------------------+
+ a_row < Playing , stop , Stopped , &p::stop_playback >,
+ a_row < Playing , pause , Paused , &p::pause_playback >,
+ a_row < Playing , open_close , Open , &p::stop_and_open >,
+ // +---------+-------------+---------+---------------------+----------------------+
+ a_row < Paused , end_pause , Playing , &p::resume_playback >,
+ a_row < Paused , stop , Stopped , &p::stop_playback >,
+ a_row < Paused , open_close , Open , &p::stop_and_open >
+ // +---------+-------------+---------+---------------------+----------------------+
+ > {};
+ // 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 msm::back::state_machine<player_> player;
+
+
+ BOOST_AUTO_TEST_CASE( my_test )
+ {
+ SomeExternalContext ctx(3);
+ player p1(boost::ref(ctx),5);
+ BOOST_CHECK_MESSAGE(p1.context_.bla == 10,"Wrong returned context value");
+
+ ctx.bla = 3;
+ player p2(msm::back::states_ << player_::Empty(1),boost::ref(ctx),5);
+ BOOST_CHECK_MESSAGE(p2.get_state<player_::Empty&>().data_ == 1,"Wrong Empty value");
+
+ p2.set_states(msm::back::states_ << player_::Empty(5));
+ BOOST_CHECK_MESSAGE(p2.get_state<player_::Empty&>().data_ == 5,"Wrong Empty value");
+
+ p2.set_states(msm::back::states_ << player_::Empty(7) << player_::Open(2));
+ BOOST_CHECK_MESSAGE(p2.get_state<player_::Empty&>().data_ == 7,"Wrong Empty value");
+ BOOST_CHECK_MESSAGE(p2.get_state<player_::Open&>().data_ == 2,"Wrong Open value");
+
+ ctx.bla = 3;
+ player p(msm::back::states_ << player_::Empty(1)
+ << player_::Playing(msm::back::states_ << player_::Playing_::Song1(8)),
+ boost::ref(ctx),5);
+ BOOST_CHECK_MESSAGE(p.get_state<player_::Playing&>().get_state<player_::Playing_::Song1&>().data_ == 8,"Wrong Open value");
+ }
+}
+
diff --git a/src/boost/libs/msm/test/TestConstructorMovableOnlyTypes.cpp b/src/boost/libs/msm/test/TestConstructorMovableOnlyTypes.cpp
new file mode 100644
index 000000000..5f8e1d5a6
--- /dev/null
+++ b/src/boost/libs/msm/test/TestConstructorMovableOnlyTypes.cpp
@@ -0,0 +1,118 @@
+// Copyright 2016 BogumiƂ Chojnowski
+// bogumil DOT chojnowski AT gmail DOT com
+// This is 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 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 <iostream>
+#include <memory>
+// back-end
+#include <boost/msm/back/state_machine.hpp>
+//front-end
+#include <boost/msm/front/state_machine_def.hpp>
+#ifndef BOOST_MSM_NONSTANDALONE_TEST
+#define BOOST_TEST_MODULE MyTest
+#endif
+#include <boost/test/unit_test.hpp>
+
+namespace msm = boost::msm;
+namespace mpl = boost::mpl;
+
+
+namespace
+{
+ struct Lightbulp
+ {
+ Lightbulp(int c) : current(c) {}
+ int current;
+ };
+
+ // events
+ struct ev_toggle {};
+
+ // front-end: define the FSM structure
+ struct bistable_switch_ : public msm::front::state_machine_def<bistable_switch_>
+ {
+ bistable_switch_(std::unique_ptr<Lightbulp> bulp, int load)
+ : bulp_(std::move(bulp))
+ {
+ BOOST_CHECK_MESSAGE(bulp_->current == 3, "Wrong current value");
+ BOOST_CHECK_MESSAGE(load == 5, "Wrong load value");
+ bulp_->current = 10;
+ }
+
+ std::unique_ptr<Lightbulp> bulp_;
+
+ // The list of FSM states
+ struct Off : public msm::front::state<>
+ {
+ template <typename Event, typename FSM>
+ void on_entry(Event const&, FSM& ) { }
+ template <typename Event, typename FSM>
+ void on_exit(Event const&, FSM&) { }
+ };
+
+ struct On : public msm::front::state<>
+ {
+ template <typename Event, typename FSM>
+ void on_entry(Event const&, FSM& ) { }
+ template <typename Event, typename FSM>
+ void on_exit(Event const&, FSM&) { }
+ };
+
+ // the initial state of the player SM. Must be defined
+ typedef Off initial_state;
+
+ void turn_on(ev_toggle const&) { bulp_->current = 11; }
+ void turn_off(ev_toggle const&) { bulp_->current = 9; }
+
+ typedef bistable_switch_ bs_; // makes transition table cleaner
+
+ // Transition table for player
+ struct transition_table : mpl::vector<
+ // Start Event Next Action Guard
+ // +---------+-------------+---------+---------------------+----------------------+
+ a_row < Off , ev_toggle , On , &bs_::turn_on >,
+ a_row < On , ev_toggle , Off , &bs_::turn_off >
+ // +---------+-------------+---------+---------------------+----------------------+
+ > {};
+ // Replaces the default no-transition response.
+
+ template <typename Event, typename FSM>
+ void no_transition(Event const&, FSM&, int)
+ {
+ BOOST_FAIL("no_transition called!");
+ }
+ };
+
+ // Pick a back-end
+ typedef msm::back::state_machine<bistable_switch_> bistable_switch;
+
+ BOOST_AUTO_TEST_CASE(my_test)
+ {
+ auto bulp = std::make_unique<Lightbulp>(3);
+
+ bistable_switch bs(std::move(bulp), 5);
+ BOOST_CHECK_MESSAGE(bs.bulp_->current == 10, "Wrong returned current value");
+
+ bs.start();
+
+ bs.process_event(ev_toggle());
+ BOOST_CHECK_MESSAGE(bs.bulp_->current == 11, "Wrong returned current value");
+
+ bs.process_event(ev_toggle());
+ BOOST_CHECK_MESSAGE(bs.bulp_->current == 9, "Wrong returned current value");
+
+ bs.stop();
+ }
+}
+
diff --git a/src/boost/libs/msm/test/TestDeferAndMessageQueue.cpp b/src/boost/libs/msm/test/TestDeferAndMessageQueue.cpp
new file mode 100644
index 000000000..767f5883a
--- /dev/null
+++ b/src/boost/libs/msm/test/TestDeferAndMessageQueue.cpp
@@ -0,0 +1,194 @@
+// 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 <iostream>
+// back-end
+#include <boost/msm/back/state_machine.hpp>
+//front-end
+#include <boost/msm/front/state_machine_def.hpp>
+#include <boost/msm/front/functor_row.hpp>
+
+#include <boost/test/unit_test.hpp>
+
+namespace msm = boost::msm;
+namespace mpl = boost::mpl;
+using namespace boost::msm::front;
+
+namespace
+{
+ // events
+ struct eventResolve {};
+ struct eventConnect {};
+ struct eventResolved {};
+ struct eventRead {};
+ struct eventd {};
+
+
+ // front-end: define the FSM structure
+ struct player_ : public msm::front::state_machine_def<player_>
+ {
+ player_()
+ :expected_action_counter(0)
+ {}
+
+ struct enqueue_action1
+ {
+ template <class EVT,class FSM,class SourceState,class TargetState>
+ void operator()(EVT const& ,FSM& fsm,SourceState& ,TargetState& )
+ {
+ fsm.template process_event(eventResolve());
+ }
+ };
+ struct enqueue_action2
+ {
+ template <class EVT,class FSM,class SourceState,class TargetState>
+ void operator()(EVT const& ,FSM& fsm,SourceState& ,TargetState& )
+ {
+ fsm.template process_event(eventConnect());
+ }
+ };
+ struct expected_action
+ {
+ template <class EVT,class FSM,class SourceState,class TargetState>
+ void operator()(EVT const& ,FSM& fsm,SourceState& ,TargetState& )
+ {
+ ++fsm.expected_action_counter;
+ //std::cout << "expected action called" << std::endl;
+ }
+ };
+ struct unexpected_action
+ {
+ template <class EVT,class FSM,class SourceState,class TargetState>
+ void operator()(EVT const& ,FSM& fsm,SourceState& ,TargetState& )
+ {
+ std::cout << "unexpected action called" << std::endl;
+ }
+ };
+
+ // The list of FSM states
+ struct Unresolved : public msm::front::state<>
+ {
+ typedef mpl::vector<eventRead > deferred_events;
+ 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;
+ int exit_counter;
+ // Transition table for Empty
+ struct internal_transition_table : mpl::vector<
+ // Start Event Next Action Guard
+ Internal < eventConnect , msm::front::ActionSequence_<mpl::vector<enqueue_action1,enqueue_action2>> >
+ // +---------+-------------+---------+---------------------+----------------------+
+ > {};
+ };
+ struct Resolving : public msm::front::state<>
+ {
+ typedef mpl::vector<eventConnect > deferred_events;
+ 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;
+ int exit_counter;
+ };
+ struct Resolved : 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;
+ int exit_counter;
+ };
+ struct Connecting : 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;
+ int exit_counter;
+ };
+ struct State22 : 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;
+ int exit_counter;
+ };
+ // the initial state of the player SM. Must be defined
+ typedef mpl::vector<Unresolved,State22> initial_state;
+
+
+ // Transition table for player
+ struct transition_table : mpl::vector<
+ // Start Event Next Action Guard
+ // +---------+-------------+---------+---------------------+----------------------+
+ Row < Unresolved , eventResolve , Resolving >,
+ Row < Resolving , eventResolved , Resolved >,
+ Row < Resolved , eventConnect , Connecting , expected_action >,
+ Row < State22 , eventd , State22 >
+ // +---------+-------------+---------+---------------------+----------------------+
+ > {};
+
+ // Replaces the default no-transition response.
+ template <class FSM,class Event>
+ void no_transition(Event const& , FSM&,int )
+ {
+ BOOST_FAIL("no_transition called!");
+ }
+ // init counters
+ template <class Event,class FSM>
+ void on_entry(Event const&,FSM& fsm)
+ {
+ fsm.template get_state<player_::Unresolved&>().entry_counter=0;
+ fsm.template get_state<player_::Unresolved&>().exit_counter=0;
+ fsm.template get_state<player_::Resolving&>().entry_counter=0;
+ fsm.template get_state<player_::Resolving&>().exit_counter=0;
+ fsm.template get_state<player_::Resolved&>().entry_counter=0;
+ fsm.template get_state<player_::Resolved&>().exit_counter=0;
+ fsm.template get_state<player_::Connecting&>().entry_counter=0;
+ fsm.template get_state<player_::Connecting&>().exit_counter=0;
+ }
+ int expected_action_counter;
+ };
+ // Pick a back-end
+ typedef msm::back::state_machine<player_> player;
+
+ BOOST_AUTO_TEST_CASE( TestDeferAndMessageQueue )
+ {
+ player p;
+ // needed to start the highest-level SM. This will call on_entry and mark the start of the SM
+ p.start();
+
+ p.process_event(eventConnect());
+ BOOST_CHECK_MESSAGE(p.current_state()[0] == 1,"Resolving should be active");
+ BOOST_CHECK_MESSAGE(p.current_state()[1] == 3,"State22 should be active");
+ BOOST_CHECK_MESSAGE(p.get_state<player_::Unresolved&>().exit_counter == 1,"Unresolved exit not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<player_::Unresolved&>().entry_counter == 1,"Unresolved entry not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<player_::Resolving&>().entry_counter == 1,"Resolving entry not called correctly");
+
+ p.process_event(eventResolved());
+ BOOST_CHECK_MESSAGE(p.current_state()[0] == 4,"Connecting should be active");
+ BOOST_CHECK_MESSAGE(p.current_state()[1] == 3,"State22 should be active");
+ BOOST_CHECK_MESSAGE(p.get_state<player_::Resolved&>().exit_counter == 1,"Resolved exit not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<player_::Resolved&>().entry_counter == 1,"Resolved entry not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<player_::Resolving&>().exit_counter == 1,"Resolving exit not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<player_::Connecting&>().entry_counter == 1,"Connecting entry not called correctly");
+
+ BOOST_CHECK_MESSAGE(p.expected_action_counter == 1,"expected_action should have been called");
+
+ }
+}
+
+
diff --git a/src/boost/libs/msm/test/TestDeferAndMessageQueue2.cpp b/src/boost/libs/msm/test/TestDeferAndMessageQueue2.cpp
new file mode 100644
index 000000000..f4c209912
--- /dev/null
+++ b/src/boost/libs/msm/test/TestDeferAndMessageQueue2.cpp
@@ -0,0 +1,155 @@
+// Copyright 2017 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 <iostream>
+// back-end
+#include <boost/msm/back/state_machine.hpp>
+//front-end
+#include <boost/msm/front/state_machine_def.hpp>
+#include <boost/msm/front/functor_row.hpp>
+
+#include <boost/test/unit_test.hpp>
+
+namespace msm = boost::msm;
+namespace mpl = boost::mpl;
+using namespace boost::msm::front;
+
+namespace
+{
+ // events
+ struct event1 {};
+ struct event2 {};
+ struct event3 {};
+ struct eventd {};
+
+
+ // front-end: define the FSM structure
+ struct player_ : public msm::front::state_machine_def<player_>
+ {
+ player_()
+ :expected_action_counter(0),expected_action2_counter(0)
+ {}
+ // The list of FSM states
+ struct State11 : public msm::front::state<>
+ {
+ typedef mpl::vector<eventd> deferred_events;
+
+ 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;
+ int exit_counter;
+ };
+ struct State12 : 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;
+ int exit_counter;
+ };
+ struct State13 : 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;
+ int exit_counter;
+ };
+ struct enqueue_action
+ {
+ template <class EVT,class FSM,class SourceState,class TargetState>
+ void operator()(EVT const& ,FSM& fsm,SourceState& ,TargetState& )
+ {
+ fsm.template process_event(event2());
+ }
+ };
+ struct expected_action
+ {
+ template <class EVT,class FSM,class SourceState,class TargetState>
+ void operator()(EVT const& ,FSM& fsm,SourceState& ,TargetState& )
+ {
+ ++fsm.expected_action_counter;
+ }
+ };
+ struct expected_action2
+ {
+ template <class EVT,class FSM,class SourceState,class TargetState>
+ void operator()(EVT const& ,FSM& fsm,SourceState& ,TargetState& )
+ {
+ ++fsm.expected_action2_counter;
+ }
+ };
+ // the initial state of the player SM. Must be defined
+ typedef mpl::vector<State11> initial_state;
+
+
+ // Transition table for player
+ struct transition_table : mpl::vector<
+ // Start Event Next Action Guard
+ // +---------+-------------+---------+---------------------+----------------------+
+ Row < State11 , event1 , State12 , enqueue_action >,
+ Row < State12 , event2 , State13 , expected_action2 >,
+ Row < State12 , eventd , State13 , expected_action >,
+ Row < State13 , event2 , State11 >,
+ Row < State13 , eventd , State11 >
+ // +---------+-------------+---------+---------------------+----------------------+
+ > {};
+
+ // Replaces the default no-transition response.
+ template <class FSM,class Event>
+ void no_transition(Event const& , FSM&,int )
+ {
+ BOOST_FAIL("no_transition called!");
+ }
+ // init counters
+ template <class Event,class FSM>
+ void on_entry(Event const&,FSM& fsm)
+ {
+ fsm.template get_state<player_::State11&>().entry_counter=0;
+ fsm.template get_state<player_::State11&>().exit_counter=0;
+ fsm.template get_state<player_::State12&>().entry_counter=0;
+ fsm.template get_state<player_::State12&>().exit_counter=0;
+ fsm.template get_state<player_::State13&>().entry_counter=0;
+ fsm.template get_state<player_::State13&>().exit_counter=0;
+ }
+ int expected_action_counter;
+ int expected_action2_counter;
+ };
+ // Pick a back-end
+ typedef msm::back::state_machine<player_> player;
+
+ BOOST_AUTO_TEST_CASE( TestDeferAndMessageQueue2 )
+ {
+ player p;
+ // needed to start the highest-level SM. This will call on_entry and mark the start of the SM
+ p.start();
+
+ p.process_event(eventd());
+ BOOST_CHECK_MESSAGE(p.current_state()[0] == 0,"State11 should be active");
+ BOOST_CHECK_MESSAGE(p.get_state<player_::State11&>().entry_counter == 1,"State11 entry not called correctly");
+
+ p.process_event(event1());
+ BOOST_CHECK_MESSAGE(p.current_state()[0] == 0,"State11 should be active");
+ BOOST_CHECK_MESSAGE(p.get_state<player_::State11&>().exit_counter == 1,"State11 exit not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<player_::State12&>().entry_counter == 1,"State12 entry not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<player_::State12&>().exit_counter == 1,"State12 exit not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<player_::State11&>().entry_counter == 2,"State11 entry not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<player_::State13&>().exit_counter == 1,"State13 exit not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<player_::State13&>().entry_counter == 1,"State13 entry not called correctly");
+ BOOST_CHECK_MESSAGE(p.expected_action_counter == 1,"expected_action should have been called");
+ BOOST_CHECK_MESSAGE(p.expected_action2_counter == 0,"expected_action2 should not have been called");
+ }
+}
+
+
diff --git a/src/boost/libs/msm/test/TestDeferAndMessageQueue3.cpp b/src/boost/libs/msm/test/TestDeferAndMessageQueue3.cpp
new file mode 100644
index 000000000..ed4e63427
--- /dev/null
+++ b/src/boost/libs/msm/test/TestDeferAndMessageQueue3.cpp
@@ -0,0 +1,158 @@
+// Copyright 2017 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 <iostream>
+// back-end
+#include <boost/msm/back/state_machine.hpp>
+//front-end
+#include <boost/msm/front/state_machine_def.hpp>
+#include <boost/msm/front/functor_row.hpp>
+
+#include <boost/test/unit_test.hpp>
+
+namespace msm = boost::msm;
+namespace mpl = boost::mpl;
+using namespace boost::msm::front;
+
+namespace
+{
+ // events
+ struct event1 {};
+ struct event2 {};
+ struct event3 {};
+ struct eventd {};
+
+
+ // front-end: define the FSM structure
+ struct player_ : public msm::front::state_machine_def<player_>
+ {
+ // in this test, we inverse the order deferred queue / event queue
+ typedef int event_queue_before_deferred_queue;
+
+ player_()
+ :expected_action_counter(0),expected_action2_counter(0)
+ {}
+ // The list of FSM states
+ struct State11 : public msm::front::state<>
+ {
+ typedef mpl::vector<eventd> deferred_events;
+
+ 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;
+ int exit_counter;
+ };
+ struct State12 : 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;
+ int exit_counter;
+ };
+ struct State13 : 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;
+ int exit_counter;
+ };
+ struct enqueue_action
+ {
+ template <class EVT,class FSM,class SourceState,class TargetState>
+ void operator()(EVT const& ,FSM& fsm,SourceState& ,TargetState& )
+ {
+ fsm.template process_event(event2());
+ }
+ };
+ struct expected_action
+ {
+ template <class EVT,class FSM,class SourceState,class TargetState>
+ void operator()(EVT const& ,FSM& fsm,SourceState& ,TargetState& )
+ {
+ ++fsm.expected_action_counter;
+ }
+ };
+ struct expected_action2
+ {
+ template <class EVT,class FSM,class SourceState,class TargetState>
+ void operator()(EVT const& ,FSM& fsm,SourceState& ,TargetState& )
+ {
+ ++fsm.expected_action2_counter;
+ }
+ };
+ // the initial state of the player SM. Must be defined
+ typedef mpl::vector<State11> initial_state;
+
+
+ // Transition table for player
+ struct transition_table : mpl::vector<
+ // Start Event Next Action Guard
+ // +---------+-------------+---------+---------------------+----------------------+
+ Row < State11 , event1 , State12 , enqueue_action >,
+ Row < State12 , event2 , State13 , expected_action2 >,
+ Row < State12 , eventd , State13 , expected_action >,
+ Row < State13 , event2 , State11 >,
+ Row < State13 , eventd , State11 >
+ // +---------+-------------+---------+---------------------+----------------------+
+ > {};
+
+ // Replaces the default no-transition response.
+ template <class FSM,class Event>
+ void no_transition(Event const& , FSM&,int )
+ {
+ BOOST_FAIL("no_transition called!");
+ }
+ // init counters
+ template <class Event,class FSM>
+ void on_entry(Event const&,FSM& fsm)
+ {
+ fsm.template get_state<player_::State11&>().entry_counter=0;
+ fsm.template get_state<player_::State11&>().exit_counter=0;
+ fsm.template get_state<player_::State12&>().entry_counter=0;
+ fsm.template get_state<player_::State12&>().exit_counter=0;
+ fsm.template get_state<player_::State13&>().entry_counter=0;
+ fsm.template get_state<player_::State13&>().exit_counter=0;
+ }
+ int expected_action_counter;
+ int expected_action2_counter;
+ };
+ // Pick a back-end
+ typedef msm::back::state_machine<player_> player;
+
+ BOOST_AUTO_TEST_CASE( TestDeferAndMessageQueue2 )
+ {
+ player p;
+ // needed to start the highest-level SM. This will call on_entry and mark the start of the SM
+ p.start();
+
+ p.process_event(eventd());
+ BOOST_CHECK_MESSAGE(p.current_state()[0] == 0,"State11 should be active");
+ BOOST_CHECK_MESSAGE(p.get_state<player_::State11&>().entry_counter == 1,"State11 entry not called correctly");
+
+ p.process_event(event1());
+ BOOST_CHECK_MESSAGE(p.current_state()[0] == 0,"State11 should be active");
+ BOOST_CHECK_MESSAGE(p.get_state<player_::State11&>().exit_counter == 1,"State11 exit not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<player_::State12&>().entry_counter == 1,"State12 entry not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<player_::State12&>().exit_counter == 1,"State12 exit not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<player_::State11&>().entry_counter == 2,"State11 entry not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<player_::State13&>().exit_counter == 1,"State13 exit not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<player_::State13&>().entry_counter == 1,"State13 entry not called correctly");
+ BOOST_CHECK_MESSAGE(p.expected_action_counter == 0,"expected_action should have been called");
+ BOOST_CHECK_MESSAGE(p.expected_action2_counter == 1,"expected_action2 should not have been called");
+ }
+}
+
+
diff --git a/src/boost/libs/msm/test/TestDeferIn2Regions.cpp b/src/boost/libs/msm/test/TestDeferIn2Regions.cpp
new file mode 100644
index 000000000..ff822f290
--- /dev/null
+++ b/src/boost/libs/msm/test/TestDeferIn2Regions.cpp
@@ -0,0 +1,169 @@
+// 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 <iostream>
+// back-end
+#include <boost/msm/back/state_machine.hpp>
+//front-end
+#include <boost/msm/front/state_machine_def.hpp>
+#include <boost/msm/front/functor_row.hpp>
+
+#include <boost/test/unit_test.hpp>
+
+namespace msm = boost::msm;
+namespace mpl = boost::mpl;
+using namespace boost::msm::front;
+
+namespace
+{
+ // events
+ struct event1 {};
+ struct event2 {};
+ struct event3 {};
+ struct eventd {};
+
+
+ // front-end: define the FSM structure
+ struct player_ : public msm::front::state_machine_def<player_>
+ {
+ // The list of FSM states
+ struct State11 : 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;
+ int exit_counter;
+ };
+ struct State12 : public msm::front::state<>
+ {
+ typedef mpl::vector<eventd> deferred_events;
+ 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;
+ int exit_counter;
+ };
+ struct State13 : 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;
+ int exit_counter;
+ };
+ struct State21 : 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;
+ int exit_counter;
+ };
+ struct State22 : 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;
+ int exit_counter;
+ };
+ // the initial state of the player SM. Must be defined
+ typedef mpl::vector<State11,State21> initial_state;
+
+
+ // Transition table for player
+ struct transition_table : mpl::vector<
+ // Start Event Next Action Guard
+ // +---------+-------------+---------+---------------------+----------------------+
+ Row < State11 , event1 , State12 >,
+ Row < State12 , event2 , State13 >,
+
+ Row < State21 , event3 , State22 >,
+ Row < State22 , eventd , State21 >
+ // +---------+-------------+---------+---------------------+----------------------+
+ > {};
+
+ // Replaces the default no-transition response.
+ template <class FSM,class Event>
+ void no_transition(Event const& , FSM&,int )
+ {
+ BOOST_FAIL("no_transition called!");
+ }
+ // init counters
+ template <class Event,class FSM>
+ void on_entry(Event const&,FSM& fsm)
+ {
+ fsm.template get_state<player_::State11&>().entry_counter=0;
+ fsm.template get_state<player_::State11&>().exit_counter=0;
+ fsm.template get_state<player_::State12&>().entry_counter=0;
+ fsm.template get_state<player_::State12&>().exit_counter=0;
+ fsm.template get_state<player_::State13&>().entry_counter=0;
+ fsm.template get_state<player_::State13&>().exit_counter=0;
+ fsm.template get_state<player_::State21&>().entry_counter=0;
+ fsm.template get_state<player_::State22&>().exit_counter=0;
+ }
+ };
+ // Pick a back-end
+ typedef msm::back::state_machine<player_> player;
+
+ BOOST_AUTO_TEST_CASE( TestDeferIn2Regions )
+ {
+ player p;
+ // needed to start the highest-level SM. This will call on_entry and mark the start of the SM
+ p.start();
+
+ p.process_event(event1());
+ BOOST_CHECK_MESSAGE(p.current_state()[0] == 1,"State12 should be active");
+ BOOST_CHECK_MESSAGE(p.current_state()[1] == 2,"State21 should be active");
+ BOOST_CHECK_MESSAGE(p.get_state<player_::State11&>().exit_counter == 1,"State11 exit not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<player_::State11&>().entry_counter == 1,"State11 entry not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<player_::State12&>().entry_counter == 1,"State12 entry not called correctly");
+
+ // deferred
+ p.process_event(eventd());
+ BOOST_CHECK_MESSAGE(p.current_state()[0] == 1,"State12 should be active");
+ BOOST_CHECK_MESSAGE(p.current_state()[1] == 2,"State21 should be active");
+ BOOST_CHECK_MESSAGE(p.get_state<player_::State11&>().exit_counter == 1,"State11 exit not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<player_::State11&>().entry_counter == 1,"State11 entry not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<player_::State12&>().entry_counter == 1,"State12 entry not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<player_::State12&>().exit_counter == 0,"State12 exit not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<player_::State21&>().exit_counter == 0,"State21 exit not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<player_::State21&>().entry_counter == 1,"State21 entry not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<player_::State22&>().exit_counter == 0,"State22 exit not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<player_::State22&>().entry_counter == 0,"State22 entry not called correctly");
+
+ p.process_event(event3());
+ BOOST_CHECK_MESSAGE(p.current_state()[0] == 1,"State12 should be active");
+ BOOST_CHECK_MESSAGE(p.current_state()[1] == 2,"State21 should be active");
+ BOOST_CHECK_MESSAGE(p.get_state<player_::State21&>().exit_counter == 1,"State21 exit not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<player_::State21&>().entry_counter == 2,"State21 entry not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<player_::State22&>().exit_counter == 1,"State22 exit not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<player_::State22&>().entry_counter == 1,"State22 entry not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_deferred_queue().size() == 1,"Deferred queue should have one element");
+ p.clear_deferred_queue();
+
+ p.process_event(event2());
+ BOOST_CHECK_MESSAGE(p.current_state()[0] == 4,"State13 should be active");
+ BOOST_CHECK_MESSAGE(p.current_state()[1] == 2,"State21 should be active");
+ BOOST_CHECK_MESSAGE(p.get_state<player_::State21&>().exit_counter == 1,"State21 exit not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<player_::State21&>().entry_counter == 2,"State21 entry not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<player_::State22&>().exit_counter == 1,"State22 exit not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_state<player_::State22&>().entry_counter == 1,"State22 entry not called correctly");
+ BOOST_CHECK_MESSAGE(p.get_deferred_queue().size() == 0,"Deferred queue should have no element");
+ }
+}
+
+