Imported Upstream version 1.57.0
[platform/upstream/boost.git] / libs / msm / test / SimpleInternalFunctors.cpp
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 #include <boost/msm/front/euml/common.hpp>
18
19 #ifndef BOOST_MSM_NONSTANDALONE_TEST
20 #define BOOST_TEST_MODULE MyTest
21 #endif
22 #include <boost/test/unit_test.hpp>
23
24 using namespace std;
25 namespace msm = boost::msm;
26 using namespace msm::front;
27 namespace mpl = boost::mpl;
28
29 namespace
30 {
31     // events
32     struct play {};
33     struct end_pause {};
34     struct stop {};
35     struct pause {};
36     struct open_close {};
37     struct internal_evt {};
38     struct to_ignore {};
39
40     // A "complicated" event type that carries some data.
41     enum DiskTypeEnum
42     {
43         DISK_CD=0,
44         DISK_DVD=1
45     };
46     struct cd_detected
47     {
48         cd_detected(std::string name, DiskTypeEnum diskType)
49             : name(name),
50             disc_type(diskType)
51         {}
52
53         std::string name;
54         DiskTypeEnum disc_type;
55     };
56
57     // front-end: define the FSM structure 
58     struct player_ : public msm::front::state_machine_def<player_>
59     {
60         unsigned int start_playback_counter;
61         unsigned int can_close_drawer_counter;
62         unsigned int internal_action_counter;
63         unsigned int internal_guard_counter;
64
65         player_():
66         start_playback_counter(0),
67         can_close_drawer_counter(0),
68         internal_action_counter(0),
69         internal_guard_counter(0)
70         {}
71
72         // The list of FSM states
73         struct Empty : public msm::front::state<> 
74         {
75             template <class Event,class FSM>
76             void on_entry(Event const&,FSM& ) {++entry_counter;}
77             template <class Event,class FSM>
78             void on_exit(Event const&,FSM& ) {++exit_counter;}
79             int entry_counter;
80             int exit_counter;
81             unsigned int empty_internal_guard_counter;
82             unsigned int empty_internal_action_counter;
83             struct internal_guard_fct 
84             {
85                 template <class EVT,class FSM,class SourceState,class TargetState>
86                 bool operator()(EVT const& ,FSM&,SourceState& src,TargetState& )
87                 {
88                     ++src.empty_internal_guard_counter;
89                     return false;
90                 }
91             };
92             struct internal_action_fct 
93             {
94                 template <class EVT,class FSM,class SourceState,class TargetState>
95                 void operator()(EVT const& ,FSM& ,SourceState& src,TargetState& )
96                 {
97                     ++src.empty_internal_action_counter;
98                 }
99             };
100             // Transition table for Empty
101             struct internal_transition_table : mpl::vector<
102                 //    Start     Event         Next      Action               Guard
103            Internal <           internal_evt          , internal_action_fct ,internal_guard_fct    >
104                 //  +---------+-------------+---------+---------------------+----------------------+
105             > {};        
106         };
107         struct Open : public msm::front::state<> 
108         { 
109             template <class Event,class FSM>
110             void on_entry(Event const&,FSM& ) {++entry_counter;}
111             template <class Event,class FSM>
112             void on_exit(Event const&,FSM& ) {++exit_counter;}
113             int entry_counter;
114             int exit_counter;
115         };
116
117         // sm_ptr still supported but deprecated as functors are a much better way to do the same thing
118         struct Stopped : public msm::front::state<> 
119         { 
120             template <class Event,class FSM>
121             void on_entry(Event const&,FSM& ) {++entry_counter;}
122             template <class Event,class FSM>
123             void on_exit(Event const&,FSM& ) {++exit_counter;}
124             int entry_counter;
125             int exit_counter;
126         };
127
128         struct Playing : public msm::front::state<>
129         {
130             template <class Event,class FSM>
131             void on_entry(Event const&,FSM& ) {++entry_counter;}
132             template <class Event,class FSM>
133             void on_exit(Event const&,FSM& ) {++exit_counter;}
134             int entry_counter;
135             int exit_counter;
136         };
137
138         // state not defining any entry or exit
139         struct Paused : public msm::front::state<>
140         {
141             template <class Event,class FSM>
142             void on_entry(Event const&,FSM& ) {++entry_counter;}
143             template <class Event,class FSM>
144             void on_exit(Event const&,FSM& ) {++exit_counter;}
145             int entry_counter;
146             int exit_counter;
147         };
148
149         // the initial state of the player SM. Must be defined
150         typedef Empty initial_state;
151
152         // transition actions
153         void start_playback(play const&)       {++start_playback_counter; }
154         void open_drawer(open_close const&)    {  }
155         void store_cd_info(cd_detected const&) {  }
156         void stop_playback(stop const&)        {  }
157         void pause_playback(pause const&)      {  }
158         void resume_playback(end_pause const&)      {  }
159         void stop_and_open(open_close const&)  {  }
160         void stopped_again(stop const&){}
161         struct internal_action 
162         {
163             template <class EVT,class FSM,class SourceState,class TargetState>
164             void operator()(EVT const& ,FSM& fsm,SourceState& ,TargetState& )
165             {            
166                 ++fsm.internal_action_counter;
167             }
168         };
169         struct internal_guard 
170         {
171             template <class EVT,class FSM,class SourceState,class TargetState>
172             bool operator()(EVT const& ,FSM& fsm,SourceState& ,TargetState& )
173             {            
174                 ++fsm.internal_guard_counter;
175                 return false;
176             }
177         };
178         struct internal_guard2 
179         {
180             template <class EVT,class FSM,class SourceState,class TargetState>
181             bool operator()(EVT const& ,FSM& fsm,SourceState& ,TargetState& )
182             {            
183                 ++fsm.internal_guard_counter;
184                 return true;
185             }
186         };
187         // guard conditions
188         bool good_disk_format(cd_detected const& evt)
189         {
190             // to test a guard condition, let's say we understand only CDs, not DVD
191             if (evt.disc_type != DISK_CD)
192             {
193                 return false;
194             }
195             return true;
196         }
197         bool can_close_drawer(open_close const&)   
198         {
199             ++can_close_drawer_counter;
200             return true;
201         }
202
203         typedef player_ p; // makes transition table cleaner
204
205         // Transition table for player
206         struct transition_table : mpl::vector<
207             //    Start     Event         Next      Action               Guard
208             //  +---------+-------------+---------+---------------------+----------------------+
209           a_row < Stopped , play        , Playing , &p::start_playback                         >,
210           a_row < Stopped , open_close  , Open    , &p::open_drawer                            >,
211            _row < Stopped , stop        , Stopped                                              >,
212             //  +---------+-------------+---------+---------------------+----------------------+
213           g_row < Open    , open_close  , Empty   ,                      &p::can_close_drawer  >,
214             //  +---------+-------------+---------+---------------------+----------------------+
215           a_row < Empty   , open_close  , Open    , &p::open_drawer                            >,
216             row < Empty   , cd_detected , Stopped , &p::store_cd_info   ,&p::good_disk_format  >,
217             Row < Empty   , internal_evt, none    , internal_action     ,internal_guard2       >,
218             Row < Empty   , to_ignore   , none    , none                , none                 >,
219             Row < Empty   , cd_detected , none    , none                ,internal_guard        >,
220             //  +---------+-------------+---------+---------------------+----------------------+
221           a_row < Playing , stop        , Stopped , &p::stop_playback                          >,
222           a_row < Playing , pause       , Paused  , &p::pause_playback                         >,
223           a_row < Playing , open_close  , Open    , &p::stop_and_open                          >,
224             //  +---------+-------------+---------+---------------------+----------------------+
225           a_row < Paused  , end_pause   , Playing , &p::resume_playback                        >,
226           a_row < Paused  , stop        , Stopped , &p::stop_playback                          >,
227           a_row < Paused  , open_close  , Open    , &p::stop_and_open                          >
228             //  +---------+-------------+---------+---------------------+----------------------+
229         > {};
230         // Replaces the default no-transition response.
231         template <class FSM,class Event>
232         void no_transition(Event const&, FSM&,int)
233         {
234             BOOST_FAIL("no_transition called!");
235         }
236         // init counters
237         template <class Event,class FSM>
238         void on_entry(Event const&,FSM& fsm) 
239         {
240             fsm.template get_state<player_::Stopped&>().entry_counter=0;
241             fsm.template get_state<player_::Stopped&>().exit_counter=0;
242             fsm.template get_state<player_::Open&>().entry_counter=0;
243             fsm.template get_state<player_::Open&>().exit_counter=0;
244             fsm.template get_state<player_::Empty&>().entry_counter=0;
245             fsm.template get_state<player_::Empty&>().exit_counter=0;
246             fsm.template get_state<player_::Empty&>().empty_internal_guard_counter=0;
247             fsm.template get_state<player_::Empty&>().empty_internal_action_counter=0;
248             fsm.template get_state<player_::Playing&>().entry_counter=0;
249             fsm.template get_state<player_::Playing&>().exit_counter=0;
250             fsm.template get_state<player_::Paused&>().entry_counter=0;
251             fsm.template get_state<player_::Paused&>().exit_counter=0;
252         }
253
254     };
255     // Pick a back-end
256     typedef msm::back::state_machine<player_> player;
257
258 //    static char const* const state_names[] = { "Stopped", "Open", "Empty", "Playing", "Paused" };
259
260
261     BOOST_AUTO_TEST_CASE( my_test )
262     {     
263         player p;
264
265         p.start(); 
266         BOOST_CHECK_MESSAGE(p.get_state<player_::Empty&>().entry_counter == 1,"Empty entry not called correctly");
267         // internal events
268         p.process_event(to_ignore());
269         p.process_event(internal_evt());
270         BOOST_CHECK_MESSAGE(p.internal_action_counter == 1,"Internal action not called correctly");
271         BOOST_CHECK_MESSAGE(p.internal_guard_counter == 1,"Internal guard not called correctly");
272         BOOST_CHECK_MESSAGE(p.get_state<player_::Empty&>().empty_internal_action_counter == 0,"Empty internal action not called correctly");
273         BOOST_CHECK_MESSAGE(p.get_state<player_::Empty&>().empty_internal_guard_counter == 1,"Empty internal guard not called correctly");
274
275         p.process_event(open_close()); 
276         BOOST_CHECK_MESSAGE(p.current_state()[0] == 1,"Open should be active"); //Open
277         BOOST_CHECK_MESSAGE(p.get_state<player_::Empty&>().exit_counter == 1,"Empty exit not called correctly");
278         BOOST_CHECK_MESSAGE(p.get_state<player_::Open&>().entry_counter == 1,"Open entry not called correctly");
279
280         p.process_event(open_close()); 
281         BOOST_CHECK_MESSAGE(p.current_state()[0] == 2,"Empty should be active"); //Empty
282         BOOST_CHECK_MESSAGE(p.get_state<player_::Open&>().exit_counter == 1,"Open exit not called correctly");
283         BOOST_CHECK_MESSAGE(p.get_state<player_::Empty&>().entry_counter == 2,"Empty entry not called correctly");
284         BOOST_CHECK_MESSAGE(p.can_close_drawer_counter == 1,"guard not called correctly");
285
286         p.process_event(
287             cd_detected("louie, louie",DISK_DVD));
288         BOOST_CHECK_MESSAGE(p.current_state()[0] == 2,"Empty should be active"); //Empty
289         BOOST_CHECK_MESSAGE(p.get_state<player_::Open&>().exit_counter == 1,"Open exit not called correctly");
290         BOOST_CHECK_MESSAGE(p.get_state<player_::Empty&>().entry_counter == 2,"Empty entry not called correctly");
291         BOOST_CHECK_MESSAGE(p.internal_guard_counter == 2,"Internal guard not called correctly");
292
293         p.process_event(
294             cd_detected("louie, louie",DISK_CD)); 
295         BOOST_CHECK_MESSAGE(p.current_state()[0] == 0,"Stopped should be active"); //Stopped
296         BOOST_CHECK_MESSAGE(p.get_state<player_::Empty&>().exit_counter == 2,"Empty exit not called correctly");
297         BOOST_CHECK_MESSAGE(p.get_state<player_::Stopped&>().entry_counter == 1,"Stopped entry not called correctly");
298         BOOST_CHECK_MESSAGE(p.internal_guard_counter == 3,"Internal guard not called correctly");
299
300         p.process_event(play());
301         BOOST_CHECK_MESSAGE(p.current_state()[0] == 3,"Playing should be active"); //Playing
302         BOOST_CHECK_MESSAGE(p.get_state<player_::Stopped&>().exit_counter == 1,"Stopped exit not called correctly");
303         BOOST_CHECK_MESSAGE(p.get_state<player_::Playing&>().entry_counter == 1,"Playing entry not called correctly");
304         BOOST_CHECK_MESSAGE(p.start_playback_counter == 1,"action not called correctly");
305
306         p.process_event(pause());
307         BOOST_CHECK_MESSAGE(p.current_state()[0] == 4,"Paused should be active"); //Paused
308         BOOST_CHECK_MESSAGE(p.get_state<player_::Playing&>().exit_counter == 1,"Playing exit not called correctly");
309         BOOST_CHECK_MESSAGE(p.get_state<player_::Paused&>().entry_counter == 1,"Paused entry not called correctly");
310
311         // go back to Playing
312         p.process_event(end_pause());  
313         BOOST_CHECK_MESSAGE(p.current_state()[0] == 3,"Playing should be active"); //Playing
314         BOOST_CHECK_MESSAGE(p.get_state<player_::Paused&>().exit_counter == 1,"Paused exit not called correctly");
315         BOOST_CHECK_MESSAGE(p.get_state<player_::Playing&>().entry_counter == 2,"Playing entry not called correctly");
316
317         p.process_event(pause()); 
318         BOOST_CHECK_MESSAGE(p.current_state()[0] == 4,"Paused should be active"); //Paused
319         BOOST_CHECK_MESSAGE(p.get_state<player_::Playing&>().exit_counter == 2,"Playing exit not called correctly");
320         BOOST_CHECK_MESSAGE(p.get_state<player_::Paused&>().entry_counter == 2,"Paused entry not called correctly");
321
322         p.process_event(stop());  
323         BOOST_CHECK_MESSAGE(p.current_state()[0] == 0,"Stopped should be active"); //Stopped
324         BOOST_CHECK_MESSAGE(p.get_state<player_::Paused&>().exit_counter == 2,"Paused exit not called correctly");
325         BOOST_CHECK_MESSAGE(p.get_state<player_::Stopped&>().entry_counter == 2,"Stopped entry not called correctly");
326
327         p.process_event(stop());  
328         BOOST_CHECK_MESSAGE(p.current_state()[0] == 0,"Stopped should be active"); //Stopped
329         BOOST_CHECK_MESSAGE(p.get_state<player_::Stopped&>().exit_counter == 2,"Stopped exit not called correctly");
330         BOOST_CHECK_MESSAGE(p.get_state<player_::Stopped&>().entry_counter == 3,"Stopped entry not called correctly");
331     }
332 }
333