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)
12 #include <boost/msm/back/state_machine.hpp>
13 #include <boost/msm/front/euml/euml.hpp>
15 #ifndef BOOST_MSM_NONSTANDALONE_TEST
16 #define BOOST_TEST_MODULE MyTest
18 #include <boost/test/unit_test.hpp>
21 using namespace boost::msm::front::euml;
22 namespace msm = boost::msm;
26 // A "complicated" event type that carries some data.
33 BOOST_MSM_EUML_EVENT(play)
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)
47 BOOST_MSM_EUML_DECLARE_ATTRIBUTE(unsigned int,entry_counter)
48 BOOST_MSM_EUML_DECLARE_ATTRIBUTE(unsigned int,exit_counter)
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)
55 BOOST_MSM_EUML_DECLARE_ATTRIBUTE(unsigned int,empty_internal_guard_counter)
56 BOOST_MSM_EUML_DECLARE_ATTRIBUTE(unsigned int,empty_internal_action_counter)
58 BOOST_MSM_EUML_ACTION(internal_guard_fct)
60 template <class FSM,class EVT,class SourceState,class TargetState>
61 bool operator()(EVT const&, FSM& ,SourceState& src,TargetState& )
63 ++src.get_attribute(empty_internal_guard_counter);
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
74 BOOST_MSM_EUML_DECLARE_INTERNAL_TRANSITION_TABLE((
75 internal_evt [internal_guard_fct] / ++source_(empty_internal_action_counter)
78 // declare an instance for the stt as we are manually declaring a state
79 Empty_impl const Empty;
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)
88 template <class FSM,class Event>
89 void operator()(Event const&,FSM&,int)
91 BOOST_FAIL("no_transition called!");
94 BOOST_MSM_EUML_ACTION(good_disk_format)
96 template <class FSM,class EVT,class SourceState,class TargetState>
97 bool operator()(EVT const& evt,FSM&,SourceState& ,TargetState& )
99 if (evt.get_attribute(cd_type)!=DISK_CD)
106 BOOST_MSM_EUML_ACTION(internal_guard)
108 template <class FSM,class EVT,class SourceState,class TargetState>
109 bool operator()(EVT const&,FSM& fsm,SourceState& ,TargetState& )
111 ++fsm.get_attribute(internal_guard_counter);
115 BOOST_MSM_EUML_ACTION(internal_guard2)
117 template <class FSM,class EVT,class SourceState,class TargetState>
118 bool operator()(EVT const&,FSM& fsm,SourceState& ,TargetState& )
120 ++fsm.get_attribute(internal_guard_counter);
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),
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 // +------------------------------------------------------------------------------+
147 BOOST_MSM_EUML_DECLARE_STATE_MACHINE(( transition_table, //STT
148 init_ << Empty, // Init State
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
158 typedef msm::back::state_machine<player_> player;
160 // static char const* const state_names[] = { "Stopped", "Paused", "Open", "Empty", "Playing" };
163 BOOST_AUTO_TEST_CASE( my_test )
168 BOOST_CHECK_MESSAGE(p.get_state<Empty_impl&>().get_attribute(entry_counter) == 1,
169 "Empty entry not called correctly");
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");
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");
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");
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");
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");
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");
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");
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");
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");
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");