1 // Copyright 2010 Christophe Henry
2 // henry UNDERSCORE christophe AT hotmail DOT com
3 // This is an extended version of the state machine available in the boost::mpl library
4 // Distributed under the same license as the original.
5 // Copyright for the original version:
6 // Copyright 2005 David Abrahams and Aleksey Gurtovoy. Distributed
7 // under the Boost Software License, Version 1.0. (See accompanying
8 // file LICENSE_1_0.txt or copy at
9 // http://www.boost.org/LICENSE_1_0.txt)
10 
11 #include <iostream>
12 // back-end
13 #include <boost/msm/back/state_machine.hpp>
14 //front-end
15 #include <boost/msm/front/state_machine_def.hpp>
16 // functors
17 #include <boost/msm/front/functor_row.hpp>
18 #include <boost/msm/front/euml/common.hpp>
19 // for And_ operator
20 #include <boost/msm/front/euml/operator.hpp>
21 
22 #include <boost/test/unit_test.hpp>
23 
24 using namespace std;
25 namespace msm = boost::msm;
26 namespace mpl = boost::mpl;
27 using namespace msm::front;
28 // for And_ operator
29 using namespace msm::front::euml;
30 
31 namespace
32 {
33     // events
34     struct event1 {};
35     struct event2 {};
36 
37     // front-end: define the FSM structure
38     struct my_machine_ : public msm::front::state_machine_def<my_machine_>
39     {
40 
41         // The list of FSM states
42         struct State1 : public msm::front::state<>
43         {
44             template <class Event,class FSM>
on_entry__anon400d0afa0111::my_machine_::State145             void on_entry(Event const&,FSM& ) {++entry_counter;}
46             template <class Event,class FSM>
on_exit__anon400d0afa0111::my_machine_::State147             void on_exit(Event const&,FSM& ) {++exit_counter;}
48             int entry_counter;
49             int exit_counter;
50         };
51         struct State2 : public msm::front::state<>
52         {
53             template <class Event,class FSM>
on_entry__anon400d0afa0111::my_machine_::State254             void on_entry(Event const&,FSM& ) {++entry_counter;}
55             template <class Event,class FSM>
on_exit__anon400d0afa0111::my_machine_::State256             void on_exit(Event const&,FSM& ) {++exit_counter;}
57             int entry_counter;
58             int exit_counter;
59         };
60 
61         struct State3 : public msm::front::state<>
62         {
63             template <class Event,class FSM>
on_entry__anon400d0afa0111::my_machine_::State364             void on_entry(Event const&,FSM& ) {++entry_counter;}
65             template <class Event,class FSM>
on_exit__anon400d0afa0111::my_machine_::State366             void on_exit(Event const&,FSM& ) {++exit_counter;}
67             int entry_counter;
68             int exit_counter;
69         };
70 
71         struct State1b : public msm::front::state<>
72         {
73             template <class Event,class FSM>
on_entry__anon400d0afa0111::my_machine_::State1b74             void on_entry(Event const&,FSM& ) {++entry_counter;}
75             template <class Event,class FSM>
on_exit__anon400d0afa0111::my_machine_::State1b76             void on_exit(Event const&,FSM& ) {++exit_counter;}
77             int entry_counter;
78             int exit_counter;
79         };
80         struct State2b : public msm::front::state<>
81         {
82             template <class Event,class FSM>
on_entry__anon400d0afa0111::my_machine_::State2b83             void on_entry(Event const&,FSM& ) {++entry_counter;}
84             template <class Event,class FSM>
on_exit__anon400d0afa0111::my_machine_::State2b85             void on_exit(Event const&,FSM& ) {++exit_counter;}
86             int entry_counter;
87             int exit_counter;
88         };
89 
90         struct always_true
91         {
92             template <class EVT,class FSM,class SourceState,class TargetState>
operator ()__anon400d0afa0111::my_machine_::always_true93             bool operator()(EVT const&  ,FSM&,SourceState& ,TargetState& )
94             {
95                 return true;
96             }
97         };
98         struct always_false
99         {
100             template <class EVT,class FSM,class SourceState,class TargetState>
operator ()__anon400d0afa0111::my_machine_::always_false101             bool operator()(EVT const&  ,FSM&,SourceState& ,TargetState& )
102             {
103                 return false;
104             }
105         };
106 
107         // the initial state of the player SM. Must be defined
108         typedef boost::mpl::vector2<State1,State1b> initial_state;
109 
110         // Transition table for player
111         struct transition_table : boost::mpl::vector<
112             //    Start     Event         Next      Action               Guard
113             //  +---------+-------------+---------+---------------------+----------------------+
114             Row < State1  , event1      , State2  , none                , always_true          >,
115             Row < State2  , none        , State3                                               >,
116             //  +---------+-------------+---------+---------------------+----------------------+
117             Row < State1b , event1      , State2b , none                , always_false         >
118             //  +---------+-------------+---------+---------------------+----------------------+
119         > {};
120         // Replaces the default no-transition response.
121         template <class FSM,class Event>
no_transition__anon400d0afa0111::my_machine_122         void no_transition(Event const&, FSM&,int)
123         {
124             BOOST_FAIL("no_transition called!");
125         }
126         // init counters
127         template <class Event,class FSM>
on_entry__anon400d0afa0111::my_machine_128         void on_entry(Event const&,FSM& fsm)
129         {
130             fsm.template get_state<my_machine_::State1&>().entry_counter=0;
131             fsm.template get_state<my_machine_::State1&>().exit_counter=0;
132             fsm.template get_state<my_machine_::State2&>().entry_counter=0;
133             fsm.template get_state<my_machine_::State2&>().exit_counter=0;
134             fsm.template get_state<my_machine_::State3&>().entry_counter=0;
135             fsm.template get_state<my_machine_::State3&>().exit_counter=0;
136             fsm.template get_state<my_machine_::State1b&>().entry_counter=0;
137             fsm.template get_state<my_machine_::State1b&>().exit_counter=0;
138             fsm.template get_state<my_machine_::State2b&>().entry_counter=0;
139             fsm.template get_state<my_machine_::State2b&>().exit_counter=0;
140         }
141     };
142     // Pick a back-end
143     typedef msm::back::state_machine<my_machine_> my_machine;
144 
BOOST_AUTO_TEST_CASE(my_test)145     BOOST_AUTO_TEST_CASE( my_test )
146     {
147         my_machine p;
148 
149         p.start();
150         BOOST_CHECK_MESSAGE(p.current_state()[0] == 0,"State1 should be active");
151         BOOST_CHECK_MESSAGE(p.current_state()[1] == 2,"State1b should be active");
152 
153         p.process_event(event1());
154         BOOST_CHECK_MESSAGE(p.current_state()[0] == 3,"State3 should be active");
155         BOOST_CHECK_MESSAGE(p.current_state()[1] == 2,"State1b should be active");
156 
157         BOOST_CHECK_MESSAGE(p.get_state<my_machine_::State1&>().exit_counter == 1,"State1 exit not called correctly");
158         BOOST_CHECK_MESSAGE(p.get_state<my_machine_::State1&>().entry_counter == 1,"State1 entry not called correctly");
159         BOOST_CHECK_MESSAGE(p.get_state<my_machine_::State2&>().exit_counter == 1,"State2 exit not called correctly");
160         BOOST_CHECK_MESSAGE(p.get_state<my_machine_::State2&>().entry_counter == 1,"State2 entry not called correctly");
161         BOOST_CHECK_MESSAGE(p.get_state<my_machine_::State3&>().exit_counter == 0,"State3 exit not called correctly");
162         BOOST_CHECK_MESSAGE(p.get_state<my_machine_::State3&>().entry_counter == 1,"State3 entry not called correctly");
163         BOOST_CHECK_MESSAGE(p.get_state<my_machine_::State1b&>().entry_counter == 1,"State1b entry not called correctly");
164         BOOST_CHECK_MESSAGE(p.get_state<my_machine_::State1b&>().exit_counter == 0,"State1b exit not called correctly");
165         BOOST_CHECK_MESSAGE(p.get_state<my_machine_::State2b&>().entry_counter == 0,"State2b entry not called correctly");
166         BOOST_CHECK_MESSAGE(p.get_state<my_machine_::State2b&>().exit_counter == 0,"State2b exit not called correctly");
167 
168 
169     }
170 }
171 
172 
173