• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #include <boost/msm/front/functor_row.hpp>
17 
18 #include <boost/test/unit_test.hpp>
19 
20 namespace msm = boost::msm;
21 namespace mpl = boost::mpl;
22 using namespace boost::msm::front;
23 
24 namespace
25 {
26     // events
27     struct eventResolve {};
28     struct eventConnect {};
29     struct eventResolved {};
30     struct eventRead {};
31     struct eventd {};
32 
33 
34     // front-end: define the FSM structure
35     struct player_ : public msm::front::state_machine_def<player_>
36     {
player___anonf5300ff00111::player_37         player_()
38             :expected_action_counter(0)
39         {}
40 
41         struct enqueue_action1
42         {
43             template <class EVT,class FSM,class SourceState,class TargetState>
operator ()__anonf5300ff00111::player_::enqueue_action144             void operator()(EVT const& ,FSM& fsm,SourceState& ,TargetState& )
45             {
46                 fsm.template process_event(eventResolve());
47             }
48         };
49         struct enqueue_action2
50         {
51             template <class EVT,class FSM,class SourceState,class TargetState>
operator ()__anonf5300ff00111::player_::enqueue_action252             void operator()(EVT const& ,FSM& fsm,SourceState& ,TargetState& )
53             {
54                 fsm.template process_event(eventConnect());
55             }
56         };
57         struct expected_action
58         {
59             template <class EVT,class FSM,class SourceState,class TargetState>
operator ()__anonf5300ff00111::player_::expected_action60             void operator()(EVT const& ,FSM& fsm,SourceState& ,TargetState& )
61             {
62                 ++fsm.expected_action_counter;
63                 //std::cout << "expected action called" << std::endl;
64             }
65         };
66         struct unexpected_action
67         {
68             template <class EVT,class FSM,class SourceState,class TargetState>
operator ()__anonf5300ff00111::player_::unexpected_action69             void operator()(EVT const& ,FSM& fsm,SourceState& ,TargetState& )
70             {
71                 std::cout << "unexpected action called" << std::endl;
72             }
73         };
74 
75         // The list of FSM states
76         struct Unresolved : public msm::front::state<>
77         {
78             typedef mpl::vector<eventRead > deferred_events;
79             template <class Event,class FSM>
on_entry__anonf5300ff00111::player_::Unresolved80             void on_entry(Event const&,FSM& ) {++entry_counter;}
81             template <class Event,class FSM>
on_exit__anonf5300ff00111::player_::Unresolved82             void on_exit(Event const&,FSM& ) {++exit_counter;}
83             int entry_counter;
84             int exit_counter;
85             // Transition table for Empty
86             struct internal_transition_table : mpl::vector<
87                 //    Start     Event         Next      Action               Guard
88            Internal <           eventConnect          , msm::front::ActionSequence_<mpl::vector<enqueue_action1,enqueue_action2>>    >
89                 //  +---------+-------------+---------+---------------------+----------------------+
90             > {};
91         };
92         struct Resolving : public msm::front::state<>
93         {
94             typedef mpl::vector<eventConnect > deferred_events;
95             template <class Event,class FSM>
on_entry__anonf5300ff00111::player_::Resolving96             void on_entry(Event const&,FSM& ) {++entry_counter;}
97             template <class Event,class FSM>
on_exit__anonf5300ff00111::player_::Resolving98             void on_exit(Event const&,FSM& ) {++exit_counter;}
99             int entry_counter;
100             int exit_counter;
101         };
102         struct Resolved : public msm::front::state<>
103         {
104             template <class Event,class FSM>
on_entry__anonf5300ff00111::player_::Resolved105             void on_entry(Event const&,FSM& ) {++entry_counter;}
106             template <class Event,class FSM>
on_exit__anonf5300ff00111::player_::Resolved107             void on_exit(Event const&,FSM& ) {++exit_counter;}
108             int entry_counter;
109             int exit_counter;
110         };
111         struct Connecting : public msm::front::state<>
112         {
113             template <class Event,class FSM>
on_entry__anonf5300ff00111::player_::Connecting114             void on_entry(Event const&,FSM& ) {++entry_counter;}
115             template <class Event,class FSM>
on_exit__anonf5300ff00111::player_::Connecting116             void on_exit(Event const&,FSM& ) {++exit_counter;}
117             int entry_counter;
118             int exit_counter;
119         };
120         struct State22 : public msm::front::state<>
121         {
122             template <class Event,class FSM>
on_entry__anonf5300ff00111::player_::State22123             void on_entry(Event const&,FSM& ) {++entry_counter;}
124             template <class Event,class FSM>
on_exit__anonf5300ff00111::player_::State22125             void on_exit(Event const&,FSM& ) {++exit_counter;}
126             int entry_counter;
127             int exit_counter;
128         };
129         // the initial state of the player SM. Must be defined
130         typedef mpl::vector<Unresolved,State22> initial_state;
131 
132 
133         // Transition table for player
134         struct transition_table : mpl::vector<
135             //      Start     Event         Next      Action               Guard
136             //    +---------+-------------+---------+---------------------+----------------------+
137             Row < Unresolved , eventResolve         , Resolving                                  >,
138             Row < Resolving  , eventResolved        , Resolved                                   >,
139             Row < Resolved   , eventConnect         , Connecting , expected_action               >,
140             Row < State22    , eventd               , State22                                    >
141             //    +---------+-------------+---------+---------------------+----------------------+
142         > {};
143 
144         // Replaces the default no-transition response.
145         template <class FSM,class Event>
no_transition__anonf5300ff00111::player_146         void no_transition(Event const& , FSM&,int )
147         {
148             BOOST_FAIL("no_transition called!");
149         }
150         // init counters
151         template <class Event,class FSM>
on_entry__anonf5300ff00111::player_152         void on_entry(Event const&,FSM& fsm)
153         {
154             fsm.template get_state<player_::Unresolved&>().entry_counter=0;
155             fsm.template get_state<player_::Unresolved&>().exit_counter=0;
156             fsm.template get_state<player_::Resolving&>().entry_counter=0;
157             fsm.template get_state<player_::Resolving&>().exit_counter=0;
158             fsm.template get_state<player_::Resolved&>().entry_counter=0;
159             fsm.template get_state<player_::Resolved&>().exit_counter=0;
160             fsm.template get_state<player_::Connecting&>().entry_counter=0;
161             fsm.template get_state<player_::Connecting&>().exit_counter=0;
162         }
163         int expected_action_counter;
164     };
165     // Pick a back-end
166     typedef msm::back::state_machine<player_> player;
167 
BOOST_AUTO_TEST_CASE(TestDeferAndMessageQueue)168     BOOST_AUTO_TEST_CASE( TestDeferAndMessageQueue )
169     {
170         player p;
171         // needed to start the highest-level SM. This will call on_entry and mark the start of the SM
172         p.start();
173 
174         p.process_event(eventConnect());
175         BOOST_CHECK_MESSAGE(p.current_state()[0] == 1,"Resolving should be active");
176         BOOST_CHECK_MESSAGE(p.current_state()[1] == 3,"State22 should be active");
177         BOOST_CHECK_MESSAGE(p.get_state<player_::Unresolved&>().exit_counter == 1,"Unresolved exit not called correctly");
178         BOOST_CHECK_MESSAGE(p.get_state<player_::Unresolved&>().entry_counter == 1,"Unresolved entry not called correctly");
179         BOOST_CHECK_MESSAGE(p.get_state<player_::Resolving&>().entry_counter == 1,"Resolving entry not called correctly");
180 
181         p.process_event(eventResolved());
182         BOOST_CHECK_MESSAGE(p.current_state()[0] == 4,"Connecting should be active");
183         BOOST_CHECK_MESSAGE(p.current_state()[1] == 3,"State22 should be active");
184         BOOST_CHECK_MESSAGE(p.get_state<player_::Resolved&>().exit_counter == 1,"Resolved exit not called correctly");
185         BOOST_CHECK_MESSAGE(p.get_state<player_::Resolved&>().entry_counter == 1,"Resolved entry not called correctly");
186         BOOST_CHECK_MESSAGE(p.get_state<player_::Resolving&>().exit_counter == 1,"Resolving exit not called correctly");
187         BOOST_CHECK_MESSAGE(p.get_state<player_::Connecting&>().entry_counter == 1,"Connecting entry not called correctly");
188 
189         BOOST_CHECK_MESSAGE(p.expected_action_counter == 1,"expected_action should have been called");
190 
191     }
192 }
193 
194 
195