• 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 #include <boost/msm/back/state_machine.hpp>
13 #include <boost/msm/front/euml/euml.hpp>
14 
15 #ifndef BOOST_MSM_NONSTANDALONE_TEST
16 #define BOOST_TEST_MODULE MyTest
17 #endif
18 #include <boost/test/unit_test.hpp>
19 
20 using namespace std;
21 using namespace boost::msm::front::euml;
22 namespace msm = boost::msm;
23 
24 namespace
25 {
26     // A "complicated" event type that carries some data.
27     enum DiskTypeEnum
28     {
29         DISK_CD=0,
30         DISK_DVD=1
31     };
32     // events
33     BOOST_MSM_EUML_EVENT(play)
BOOST_MSM_EUML_EVENT(end_pause)34     BOOST_MSM_EUML_EVENT(end_pause)
35     BOOST_MSM_EUML_EVENT(stop)
36     BOOST_MSM_EUML_EVENT(pause)
37     BOOST_MSM_EUML_EVENT(open_close)
38     BOOST_MSM_EUML_EVENT(internal_evt)
39     BOOST_MSM_EUML_EVENT(to_ignore)
40     // A "complicated" event type that carries some data.
41     BOOST_MSM_EUML_DECLARE_ATTRIBUTE(std::string,cd_name)
42     BOOST_MSM_EUML_DECLARE_ATTRIBUTE(DiskTypeEnum,cd_type)
43     BOOST_MSM_EUML_ATTRIBUTES((attributes_ << cd_name << cd_type ), cd_detected_attributes)
44     BOOST_MSM_EUML_EVENT_WITH_ATTRIBUTES(cd_detected,cd_detected_attributes)
45 
46     //states
47     BOOST_MSM_EUML_DECLARE_ATTRIBUTE(unsigned int,entry_counter)
48     BOOST_MSM_EUML_DECLARE_ATTRIBUTE(unsigned int,exit_counter)
49 
50     BOOST_MSM_EUML_STATE(( ++state_(entry_counter),++state_(exit_counter),attributes_ << entry_counter << exit_counter),Open)
51     BOOST_MSM_EUML_STATE(( ++state_(entry_counter),++state_(exit_counter),attributes_ << entry_counter << exit_counter),Stopped)
52     BOOST_MSM_EUML_STATE(( ++state_(entry_counter),++state_(exit_counter),attributes_ << entry_counter << exit_counter),Playing)
53     BOOST_MSM_EUML_STATE(( ++state_(entry_counter),++state_(exit_counter),attributes_ << entry_counter << exit_counter),Paused)
54 
55     BOOST_MSM_EUML_DECLARE_ATTRIBUTE(unsigned int,empty_internal_guard_counter)
56     BOOST_MSM_EUML_DECLARE_ATTRIBUTE(unsigned int,empty_internal_action_counter)
57 
58     BOOST_MSM_EUML_ACTION(internal_guard_fct)
59     {
60         template <class FSM,class EVT,class SourceState,class TargetState>
61         bool operator()(EVT const&, FSM& ,SourceState& src,TargetState& )
62         {
63             ++src.get_attribute(empty_internal_guard_counter);
64             return false;
65         }
66     };
67     BOOST_MSM_EUML_DECLARE_STATE((++state_(entry_counter),++state_(exit_counter),
68                                   attributes_ << entry_counter << exit_counter
69                                               << empty_internal_guard_counter << empty_internal_action_counter),Empty_def)
70     // derive to be able to add an internal transition table
71     struct Empty_impl : public Empty_def
72     {
Empty_impl__anond06873e90111::Empty_impl73         Empty_impl(){}
74         BOOST_MSM_EUML_DECLARE_INTERNAL_TRANSITION_TABLE((
75             internal_evt [internal_guard_fct] / ++source_(empty_internal_action_counter)
76             ))
77     };
78     // declare an instance for the stt as we are manually declaring a state
79     Empty_impl const Empty;
80 
81     //fsm
BOOST_MSM_EUML_DECLARE_ATTRIBUTE(unsigned int,start_playback_counter)82     BOOST_MSM_EUML_DECLARE_ATTRIBUTE(unsigned int,start_playback_counter)
83     BOOST_MSM_EUML_DECLARE_ATTRIBUTE(unsigned int,can_close_drawer_counter)
84     BOOST_MSM_EUML_DECLARE_ATTRIBUTE(unsigned int,internal_action_counter)
85     BOOST_MSM_EUML_DECLARE_ATTRIBUTE(unsigned int,internal_guard_counter)
86     BOOST_MSM_EUML_ACTION(No_Transition)
87     {
88         template <class FSM,class Event>
89         void operator()(Event const&,FSM&,int)
90         {
91             BOOST_FAIL("no_transition called!");
92         }
93     };
BOOST_MSM_EUML_ACTION(good_disk_format)94     BOOST_MSM_EUML_ACTION(good_disk_format)
95     {
96         template <class FSM,class EVT,class SourceState,class TargetState>
97         bool operator()(EVT const& evt,FSM&,SourceState& ,TargetState& )
98         {
99             if (evt.get_attribute(cd_type)!=DISK_CD)
100             {
101                 return false;
102             }
103             return true;
104         }
105     };
BOOST_MSM_EUML_ACTION(internal_guard)106     BOOST_MSM_EUML_ACTION(internal_guard)
107     {
108         template <class FSM,class EVT,class SourceState,class TargetState>
109         bool operator()(EVT const&,FSM& fsm,SourceState& ,TargetState& )
110         {
111             ++fsm.get_attribute(internal_guard_counter);
112             return false;
113         }
114     };
BOOST_MSM_EUML_ACTION(internal_guard2)115     BOOST_MSM_EUML_ACTION(internal_guard2)
116     {
117         template <class FSM,class EVT,class SourceState,class TargetState>
118         bool operator()(EVT const&,FSM& fsm,SourceState& ,TargetState& )
119         {
120             ++fsm.get_attribute(internal_guard_counter);
121             return true;
122         }
123     };
124     BOOST_MSM_EUML_TRANSITION_TABLE((
125           Playing   == Stopped  + play        / ++fsm_(start_playback_counter)                      ,
126           Playing   == Paused   + end_pause   ,
127           //  +------------------------------------------------------------------------------+
128           Empty     == Open     + open_close  / ++fsm_(can_close_drawer_counter),
129           Empty                 + to_ignore                                                         ,
130           Empty                 + internal_evt [internal_guard2] / ++fsm_(internal_action_counter)  ,
131           Empty                 + cd_detected [internal_guard]                                      ,
132           //  +------------------------------------------------------------------------------+
133           Open      == Empty    + open_close  ,
134           Open      == Paused   + open_close  ,
135           Open      == Stopped  + open_close  ,
136           Open      == Playing  + open_close  ,
137           //  +------------------------------------------------------------------------------+
138           Paused    == Playing  + pause       ,
139           //  +------------------------------------------------------------------------------+
140           Stopped   == Playing  + stop        ,
141           Stopped   == Paused   + stop        ,
142           Stopped   == Empty    + cd_detected [good_disk_format]                                    ,
143           Stopped   == Stopped  + stop
144           //  +------------------------------------------------------------------------------+
145          ),transition_table)
146 
147     BOOST_MSM_EUML_DECLARE_STATE_MACHINE(( transition_table, //STT
148                                         init_ << Empty, // Init State
149                                         no_action, // Entry
150                                         no_action, // Exit
151                                         attributes_ << start_playback_counter << can_close_drawer_counter
152                                                     << internal_action_counter << internal_guard_counter, // Attributes
153                                         configure_ << no_configure_, // configuration
154                                         No_Transition // no_transition handler
155                                         ),
156                                       player_) //fsm name
157 
158     typedef msm::back::state_machine<player_> player;
159 
160 //    static char const* const state_names[] = { "Stopped", "Paused", "Open", "Empty", "Playing" };
161 
162 
BOOST_AUTO_TEST_CASE(my_test)163     BOOST_AUTO_TEST_CASE( my_test )
164     {
165         player p;
166 
167         p.start();
168         BOOST_CHECK_MESSAGE(p.get_state<Empty_impl&>().get_attribute(entry_counter) == 1,
169                             "Empty entry not called correctly");
170 
171         // internal events
172         p.process_event(to_ignore);
173         p.process_event(internal_evt);
174         BOOST_CHECK_MESSAGE(p.get_attribute(internal_action_counter) == 1,"Internal action not called correctly");
175         BOOST_CHECK_MESSAGE(p.get_attribute(internal_guard_counter) == 1,"Internal guard not called correctly");
176         BOOST_CHECK_MESSAGE(p.get_state<Empty_impl&>().get_attribute(empty_internal_action_counter) == 0,
177                             "Empty internal action not called correctly");
178         BOOST_CHECK_MESSAGE(p.get_state<Empty_impl&>().get_attribute(empty_internal_guard_counter) == 1,
179                             "Empty internal guard not called correctly");
180 
181         p.process_event(open_close());
182         BOOST_CHECK_MESSAGE(p.current_state()[0] == 2,"Open should be active"); //Open
183         BOOST_CHECK_MESSAGE(p.get_state<Empty_impl&>().get_attribute(exit_counter) == 1,
184                             "Empty exit not called correctly");
185         BOOST_CHECK_MESSAGE(p.get_state<Empty_impl&>().get_attribute(entry_counter) == 1,
186                             "Open entry not called correctly");
187 
188         p.process_event(open_close());
189         BOOST_CHECK_MESSAGE(p.current_state()[0] == 3,"Empty should be active"); //Empty
190         BOOST_CHECK_MESSAGE(p.get_state<BOOST_MSM_EUML_STATE_NAME(Open)&>().get_attribute(exit_counter) == 1,
191                             "Open exit not called correctly");
192         BOOST_CHECK_MESSAGE(p.get_state<Empty_impl&>().get_attribute(entry_counter) == 2,
193                             "Empty entry not called correctly");
194         BOOST_CHECK_MESSAGE(p.get_attribute(can_close_drawer_counter) == 1,"guard not called correctly");
195 
196         p.process_event(
197             cd_detected("louie, louie",DISK_DVD));
198         BOOST_CHECK_MESSAGE(p.current_state()[0] == 3,"Empty should be active"); //Empty
199         BOOST_CHECK_MESSAGE(p.get_state<BOOST_MSM_EUML_STATE_NAME(Open)&>().get_attribute(exit_counter) == 1,
200                             "Open exit not called correctly");
201         BOOST_CHECK_MESSAGE(p.get_state<Empty_impl&>().get_attribute(entry_counter) == 2,
202                             "Empty entry not called correctly");
203 
204         p.process_event(
205             cd_detected("louie, louie",DISK_CD));
206         p.process_event(play);
207         BOOST_CHECK_MESSAGE(p.current_state()[0] == 4,"Playing should be active"); //Playing
208         BOOST_CHECK_MESSAGE(p.get_state<Empty_impl&>().get_attribute(exit_counter) == 2,
209                             "Empty exit not called correctly");
210         BOOST_CHECK_MESSAGE(p.get_state<BOOST_MSM_EUML_STATE_NAME(Stopped)&>().get_attribute(entry_counter) == 1,
211                             "Stopped entry not called correctly");
212         BOOST_CHECK_MESSAGE(p.get_state<BOOST_MSM_EUML_STATE_NAME(Stopped)&>().get_attribute(exit_counter) == 1,
213                             "Stopped exit not called correctly");
214         BOOST_CHECK_MESSAGE(p.get_state<BOOST_MSM_EUML_STATE_NAME(Playing)&>().get_attribute(entry_counter) == 1,
215                             "Playing entry not called correctly");
216         BOOST_CHECK_MESSAGE(p.get_attribute(start_playback_counter) == 1,"action not called correctly");
217 
218         p.process_event(pause());
219         BOOST_CHECK_MESSAGE(p.current_state()[0] == 1,"Paused should be active"); //Paused
220         BOOST_CHECK_MESSAGE(p.get_state<BOOST_MSM_EUML_STATE_NAME(Playing)&>().get_attribute(exit_counter) == 1,
221                             "Playing exit not called correctly");
222         BOOST_CHECK_MESSAGE(p.get_state<BOOST_MSM_EUML_STATE_NAME(Paused)&>().get_attribute(entry_counter) == 1,
223                             "Paused entry not called correctly");
224 
225         // go back to Playing
226         p.process_event(end_pause());
227         BOOST_CHECK_MESSAGE(p.current_state()[0] == 4,"Playing should be active"); //Playing
228         BOOST_CHECK_MESSAGE(p.get_state<BOOST_MSM_EUML_STATE_NAME(Paused)&>().get_attribute(exit_counter) == 1,
229                             "Paused exit not called correctly");
230         BOOST_CHECK_MESSAGE(p.get_state<BOOST_MSM_EUML_STATE_NAME(Playing)&>().get_attribute(entry_counter) == 2,
231                             "Playing entry not called correctly");
232 
233         p.process_event(pause());
234         BOOST_CHECK_MESSAGE(p.current_state()[0] == 1,"Paused should be active"); //Paused
235         BOOST_CHECK_MESSAGE(p.get_state<BOOST_MSM_EUML_STATE_NAME(Playing)&>().get_attribute(exit_counter) == 2,
236                             "Playing exit not called correctly");
237         BOOST_CHECK_MESSAGE(p.get_state<BOOST_MSM_EUML_STATE_NAME(Paused)&>().get_attribute(entry_counter) == 2,
238                             "Paused entry not called correctly");
239 
240         p.process_event(stop());
241         BOOST_CHECK_MESSAGE(p.current_state()[0] == 0,"Stopped should be active"); //Stopped
242         BOOST_CHECK_MESSAGE(p.get_state<BOOST_MSM_EUML_STATE_NAME(Paused)&>().get_attribute(exit_counter) == 2,
243                             "Paused exit not called correctly");
244         BOOST_CHECK_MESSAGE(p.get_state<BOOST_MSM_EUML_STATE_NAME(Stopped)&>().get_attribute(entry_counter) == 2,
245                             "Stopped entry not called correctly");
246 
247         p.process_event(stop());
248         BOOST_CHECK_MESSAGE(p.current_state()[0] == 0,"Stopped should be active"); //Stopped
249         BOOST_CHECK_MESSAGE(p.get_state<BOOST_MSM_EUML_STATE_NAME(Stopped)&>().get_attribute(exit_counter) == 2,
250                             "Stopped exit not called correctly");
251         BOOST_CHECK_MESSAGE(p.get_state<BOOST_MSM_EUML_STATE_NAME(Stopped)&>().get_attribute(entry_counter) == 3,
252                             "Stopped entry not called correctly");
253     }
254 }
255 
256