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
#define BOOST_TEST_MODULE MyTest
16
#include <boost/test/unit_test.hpp>
17
// include headers that implement a archive in simple text format
18
#include <boost/archive/text_oarchive.hpp>
19
#include <boost/archive/text_iarchive.hpp>
20
#include <boost/serialization/tracking.hpp>
25
using namespace boost::msm::front::euml;
26
namespace msm = boost::msm;
30
// A "complicated" event type that carries some data.
37
BOOST_MSM_EUML_EVENT(play)
38
BOOST_MSM_EUML_EVENT(end_pause)
39
BOOST_MSM_EUML_EVENT(stop)
40
BOOST_MSM_EUML_EVENT(pause)
41
BOOST_MSM_EUML_EVENT(open_close)
42
// A "complicated" event type that carries some data.
43
BOOST_MSM_EUML_DECLARE_ATTRIBUTE(std::string,cd_name)
44
BOOST_MSM_EUML_DECLARE_ATTRIBUTE(DiskTypeEnum,cd_type)
45
BOOST_MSM_EUML_ATTRIBUTES((attributes_ << cd_name << cd_type ), cd_detected_attributes)
46
BOOST_MSM_EUML_EVENT_WITH_ATTRIBUTES(cd_detected,cd_detected_attributes)
49
BOOST_MSM_EUML_DECLARE_ATTRIBUTE(unsigned int,entry_counter)
50
BOOST_MSM_EUML_DECLARE_ATTRIBUTE(unsigned int,exit_counter)
52
BOOST_MSM_EUML_STATE(( ++state_(entry_counter),++state_(exit_counter),attributes_ << entry_counter << exit_counter),Empty)
53
BOOST_MSM_EUML_STATE(( ++state_(entry_counter),++state_(exit_counter),attributes_ << entry_counter << exit_counter),Open)
54
BOOST_MSM_EUML_STATE(( ++state_(entry_counter),++state_(exit_counter),attributes_ << entry_counter << exit_counter),Stopped)
55
BOOST_MSM_EUML_STATE(( ++state_(entry_counter),++state_(exit_counter),attributes_ << entry_counter << exit_counter),Playing)
56
BOOST_MSM_EUML_STATE(( ++state_(entry_counter),++state_(exit_counter),attributes_ << entry_counter << exit_counter),Paused)
59
BOOST_MSM_EUML_DECLARE_ATTRIBUTE(unsigned int,start_playback_counter)
60
BOOST_MSM_EUML_DECLARE_ATTRIBUTE(unsigned int,can_close_drawer_counter)
61
BOOST_MSM_EUML_DECLARE_ATTRIBUTE(unsigned int,test_fct_counter)
62
BOOST_MSM_EUML_ACTION(No_Transition)
64
template <class FSM,class Event>
65
void operator()(Event const&,FSM&,int)
67
BOOST_FAIL("no_transition called!");
70
BOOST_MSM_EUML_ACTION(good_disk_format)
72
template <class FSM,class EVT,class SourceState,class TargetState>
73
bool operator()(EVT const& evt,FSM&,SourceState& ,TargetState& )
75
if (evt.get_attribute(cd_type)!=DISK_CD)
82
BOOST_MSM_EUML_TRANSITION_TABLE((
83
Playing == Stopped + play / (++fsm_(start_playback_counter),++fsm_(test_fct_counter) ),
84
Playing == Paused + end_pause ,
85
// +------------------------------------------------------------------------------+
86
Empty == Open + open_close / ++fsm_(can_close_drawer_counter),
87
// +------------------------------------------------------------------------------+
88
Open == Empty + open_close ,
89
Open == Paused + open_close ,
90
Open == Stopped + open_close ,
91
Open == Playing + open_close ,
92
// +------------------------------------------------------------------------------+
93
Paused == Playing + pause ,
94
// +------------------------------------------------------------------------------+
95
Stopped == Playing + stop ,
96
Stopped == Paused + stop ,
97
Stopped == Empty + cd_detected [good_disk_format ||
98
(event_(cd_type)==Int_<DISK_CD>())] / process_(play) ,
99
Stopped == Stopped + stop
100
// +------------------------------------------------------------------------------+
103
BOOST_MSM_EUML_DECLARE_STATE_MACHINE(( transition_table, //STT
104
init_ << Empty, // Init State
107
attributes_ << start_playback_counter
108
<< can_close_drawer_counter << test_fct_counter, // Attributes
109
configure_ << no_configure_, // configuration
110
No_Transition // no_transition handler
114
typedef msm::back::state_machine<player_> player;
116
// static char const* const state_names[] = { "Stopped", "Paused", "Open", "Empty", "Playing" };
119
BOOST_AUTO_TEST_CASE( my_test )
124
BOOST_CHECK_MESSAGE(p2.get_state<BOOST_MSM_EUML_STATE_NAME(Empty)&>().get_attribute(entry_counter) == 1,
125
"Empty entry not called correctly");
127
p2.process_event(open_close());
128
BOOST_CHECK_MESSAGE(p2.current_state()[0] == 2,"Open should be active"); //Open
129
BOOST_CHECK_MESSAGE(p2.get_state<BOOST_MSM_EUML_STATE_NAME(Empty)&>().get_attribute(exit_counter) == 1,
130
"Empty exit not called correctly");
131
BOOST_CHECK_MESSAGE(p2.get_state<BOOST_MSM_EUML_STATE_NAME(Open)&>().get_attribute(entry_counter) == 1,
132
"Open entry not called correctly");
134
// test the serialization
135
std::ofstream ofs("fsm.txt");
136
// save fsm to archive (current state is Open)
138
boost::archive::text_oarchive oa(ofs);
139
// write class instance to archive
142
// reload fsm in state Open
145
// create and open an archive for input
146
std::ifstream ifs("fsm.txt");
147
boost::archive::text_iarchive ia(ifs);
148
// read class state from archive
152
p.process_event(open_close());
153
BOOST_CHECK_MESSAGE(p.current_state()[0] == 3,"Empty should be active"); //Empty
156
cd_detected("louie, louie",DISK_DVD));
157
BOOST_CHECK_MESSAGE(p.current_state()[0] == 3,"Empty should be active"); //Empty
158
BOOST_CHECK_MESSAGE(p.get_state<BOOST_MSM_EUML_STATE_NAME(Open)&>().get_attribute(exit_counter) == 1,
159
"Open exit not called correctly");
162
cd_detected("louie, louie",DISK_CD));
163
BOOST_CHECK_MESSAGE(p.current_state()[0] == 4,"Playing should be active"); //Playing
164
BOOST_CHECK_MESSAGE(p.get_state<BOOST_MSM_EUML_STATE_NAME(Stopped)&>().get_attribute(entry_counter) == 1,
165
"Stopped entry not called correctly");
166
BOOST_CHECK_MESSAGE(p.get_state<BOOST_MSM_EUML_STATE_NAME(Stopped)&>().get_attribute(exit_counter) == 1,
167
"Stopped exit not called correctly");
168
BOOST_CHECK_MESSAGE(p.get_state<BOOST_MSM_EUML_STATE_NAME(Playing)&>().get_attribute(entry_counter) == 1,
169
"Playing entry not called correctly");
170
BOOST_CHECK_MESSAGE(p.get_attribute(start_playback_counter) == 1,"action not called correctly");
171
BOOST_CHECK_MESSAGE(p.get_attribute(test_fct_counter) == 1,"action not called correctly");
173
p.process_event(pause());
174
BOOST_CHECK_MESSAGE(p.current_state()[0] == 1,"Paused should be active"); //Paused
175
BOOST_CHECK_MESSAGE(p.get_state<BOOST_MSM_EUML_STATE_NAME(Playing)&>().get_attribute(exit_counter) == 1,
176
"Playing exit not called correctly");
177
BOOST_CHECK_MESSAGE(p.get_state<BOOST_MSM_EUML_STATE_NAME(Paused)&>().get_attribute(entry_counter) == 1,
178
"Paused entry not called correctly");
180
// go back to Playing
181
p.process_event(end_pause());
182
BOOST_CHECK_MESSAGE(p.current_state()[0] == 4,"Playing should be active"); //Playing
183
BOOST_CHECK_MESSAGE(p.get_state<BOOST_MSM_EUML_STATE_NAME(Paused)&>().get_attribute(exit_counter) == 1,
184
"Paused exit not called correctly");
185
BOOST_CHECK_MESSAGE(p.get_state<BOOST_MSM_EUML_STATE_NAME(Playing)&>().get_attribute(entry_counter) == 2,
186
"Playing entry not called correctly");
188
p.process_event(pause());
189
BOOST_CHECK_MESSAGE(p.current_state()[0] == 1,"Paused should be active"); //Paused
190
BOOST_CHECK_MESSAGE(p.get_state<BOOST_MSM_EUML_STATE_NAME(Playing)&>().get_attribute(exit_counter) == 2,
191
"Playing exit not called correctly");
192
BOOST_CHECK_MESSAGE(p.get_state<BOOST_MSM_EUML_STATE_NAME(Paused)&>().get_attribute(entry_counter) == 2,
193
"Paused entry not called correctly");
195
p.process_event(stop());
196
BOOST_CHECK_MESSAGE(p.current_state()[0] == 0,"Stopped should be active"); //Stopped
197
BOOST_CHECK_MESSAGE(p.get_state<BOOST_MSM_EUML_STATE_NAME(Paused)&>().get_attribute(exit_counter) == 2,
198
"Paused exit not called correctly");
199
BOOST_CHECK_MESSAGE(p.get_state<BOOST_MSM_EUML_STATE_NAME(Stopped)&>().get_attribute(entry_counter) == 2,
200
"Stopped entry not called correctly");
202
p.process_event(stop());
203
BOOST_CHECK_MESSAGE(p.current_state()[0] == 0,"Stopped should be active"); //Stopped
204
BOOST_CHECK_MESSAGE(p.get_state<BOOST_MSM_EUML_STATE_NAME(Stopped)&>().get_attribute(exit_counter) == 2,
205
"Stopped exit not called correctly");
206
BOOST_CHECK_MESSAGE(p.get_state<BOOST_MSM_EUML_STATE_NAME(Stopped)&>().get_attribute(entry_counter) == 3,
207
"Stopped entry not called correctly");
211
// eliminate object tracking (even if serialized through a pointer)
212
// at the risk of a programming error creating duplicate objects.
213
// this is to get rid of warning because p is not const
214
BOOST_CLASS_TRACKING(player, boost::serialization::track_never)