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