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 <boost/msm/back/state_machine.hpp>
12#include <boost/msm/front/euml/euml.hpp>
13
14#ifndef BOOST_MSM_NONSTANDALONE_TEST
15#define BOOST_TEST_MODULE MySimpleEuml2Test
16#endif
17#include <boost/test/unit_test.hpp>
18
19using namespace std;
20using namespace boost::msm::front::euml;
21namespace msm = boost::msm;
22
23namespace
24{
25 // A "complicated" event type that carries some data.
26 enum DiskTypeEnum
27 {
28 DISK_CD=0,
29 DISK_DVD=1
30 };
31 // events
32 BOOST_MSM_EUML_EVENT(play)
33 BOOST_MSM_EUML_EVENT(end_pause)
34 BOOST_MSM_EUML_EVENT(stop)
35 BOOST_MSM_EUML_EVENT(pause)
36 BOOST_MSM_EUML_EVENT(open_close)
37 // A "complicated" event type that carries some data.
38 BOOST_MSM_EUML_DECLARE_ATTRIBUTE(std::string,cd_name)
39 BOOST_MSM_EUML_DECLARE_ATTRIBUTE(DiskTypeEnum,cd_type)
40 BOOST_MSM_EUML_ATTRIBUTES((attributes_ << cd_name << cd_type ), cd_detected_attributes)
41 BOOST_MSM_EUML_EVENT_WITH_ATTRIBUTES(cd_detected,cd_detected_attributes)
42
43 //states
44 BOOST_MSM_EUML_DECLARE_ATTRIBUTE(unsigned int,entry_counter)
45 BOOST_MSM_EUML_DECLARE_ATTRIBUTE(unsigned int,exit_counter)
46
47 BOOST_MSM_EUML_STATE(( ++state_(entry_counter),++state_(exit_counter),attributes_ << entry_counter << exit_counter),Empty)
48 BOOST_MSM_EUML_STATE(( ++state_(entry_counter),++state_(exit_counter),attributes_ << entry_counter << exit_counter),Open)
49 BOOST_MSM_EUML_STATE(( ++state_(entry_counter),++state_(exit_counter),attributes_ << entry_counter << exit_counter),Stopped)
50 BOOST_MSM_EUML_STATE(( ++state_(entry_counter),++state_(exit_counter),attributes_ << entry_counter << exit_counter),Playing)
51 BOOST_MSM_EUML_STATE(( ++state_(entry_counter),++state_(exit_counter),attributes_ << entry_counter << exit_counter),Paused)
52
53 //fsm
54 BOOST_MSM_EUML_DECLARE_ATTRIBUTE(unsigned int,start_playback_counter)
55 BOOST_MSM_EUML_DECLARE_ATTRIBUTE(unsigned int,can_close_drawer_counter)
56 BOOST_MSM_EUML_DECLARE_ATTRIBUTE(unsigned int,test_fct_counter)
57 BOOST_MSM_EUML_ACTION(No_Transition)
58 {
59 template <class FSM,class Event>
60 void operator()(Event const&,FSM&,int)
61 {
62 BOOST_FAIL("no_transition called!");
63 }
64 };
65 BOOST_MSM_EUML_ACTION(good_disk_format)
66 {
67 template <class FSM,class EVT,class SourceState,class TargetState>
68 bool operator()(EVT const& evt,FSM&,SourceState& ,TargetState& )
69 {
70 if (evt.get_attribute(cd_type)!=DISK_CD)
71 {
72 return false;
73 }
74 return true;
75 }
76 };
77 BOOST_MSM_EUML_TRANSITION_TABLE((
78 Stopped + play / (++fsm_(start_playback_counter),++fsm_(test_fct_counter)) == Playing,
79 Paused + end_pause == Playing,
80 // +------------------------------------------------------------------------------+
81 Open + open_close / ++fsm_(can_close_drawer_counter) == Empty,
82 // +------------------------------------------------------------------------------+
83 Empty + open_close == Open,
84 Paused + open_close == Open,
85 Stopped + open_close == Open,
86 Playing + open_close == Open,
87 // +------------------------------------------------------------------------------+
88 Playing + pause == Paused,
89 // +------------------------------------------------------------------------------+
90 Playing + stop == Stopped,
91 Paused + stop == Stopped,
92 Empty + cd_detected [good_disk_format ||
93 (event_(cd_type)==Int_<DISK_CD>())] / process_(play) == Stopped,
94 Stopped + stop == Stopped
95 // +------------------------------------------------------------------------------+
96 ),transition_table)
97
98 BOOST_MSM_EUML_DECLARE_STATE_MACHINE(( transition_table, //STT
99 init_ << Empty, // Init State
100 no_action, // Entry
101 no_action, // Exit
102 attributes_ << start_playback_counter
103 << can_close_drawer_counter << test_fct_counter, // Attributes
104 configure_ << no_configure_, // configuration
105 No_Transition // no_transition handler
106 ),
107 player_) //fsm name
108
109 typedef msm::back::state_machine<player_> player;
110
111// static char const* const state_names[] = { "Stopped", "Paused", "Open", "Empty", "Playing" };
112
113
114 BOOST_AUTO_TEST_CASE(MySimpleEuml2Test)
115 {
116 player p;
117
118 p.start();
119 BOOST_CHECK_MESSAGE(p.get_state<BOOST_MSM_EUML_STATE_NAME(Empty)&>().get_attribute(entry_counter) == 1,
120 "Empty entry not called correctly");
121
122 p.process_event(evt: open_close());
123 BOOST_CHECK_MESSAGE(p.current_state()[0] == 2,"Open should be active"); //Open
124 BOOST_CHECK_MESSAGE(p.get_state<BOOST_MSM_EUML_STATE_NAME(Empty)&>().get_attribute(exit_counter) == 1,
125 "Empty exit not called correctly");
126 BOOST_CHECK_MESSAGE(p.get_state<BOOST_MSM_EUML_STATE_NAME(Open)&>().get_attribute(entry_counter) == 1,
127 "Open entry not called correctly");
128
129 p.process_event(evt: open_close());
130 BOOST_CHECK_MESSAGE(p.current_state()[0] == 3,"Empty should be active"); //Empty
131 BOOST_CHECK_MESSAGE(p.get_state<BOOST_MSM_EUML_STATE_NAME(Open)&>().get_attribute(exit_counter) == 1,
132 "Open exit not called correctly");
133 BOOST_CHECK_MESSAGE(p.get_state<BOOST_MSM_EUML_STATE_NAME(Empty)&>().get_attribute(entry_counter) == 2,
134 "Empty entry not called correctly");
135 BOOST_CHECK_MESSAGE(p.get_attribute(can_close_drawer_counter) == 1,"guard not called correctly");
136
137 p.process_event(
138 evt: cd_detected("louie, louie",DISK_DVD));
139 BOOST_CHECK_MESSAGE(p.current_state()[0] == 3,"Empty should be active"); //Empty
140 BOOST_CHECK_MESSAGE(p.get_state<BOOST_MSM_EUML_STATE_NAME(Open)&>().get_attribute(exit_counter) == 1,
141 "Open exit not called correctly");
142 BOOST_CHECK_MESSAGE(p.get_state<BOOST_MSM_EUML_STATE_NAME(Empty)&>().get_attribute(entry_counter) == 2,
143 "Empty entry not called correctly");
144
145 p.process_event(
146 evt: cd_detected("louie, louie",DISK_CD));
147 BOOST_CHECK_MESSAGE(p.current_state()[0] == 4,"Playing should be active"); //Playing
148 BOOST_CHECK_MESSAGE(p.get_state<BOOST_MSM_EUML_STATE_NAME(Empty)&>().get_attribute(exit_counter) == 2,
149 "Empty exit not called correctly");
150 BOOST_CHECK_MESSAGE(p.get_state<BOOST_MSM_EUML_STATE_NAME(Stopped)&>().get_attribute(entry_counter) == 1,
151 "Stopped entry not called correctly");
152 BOOST_CHECK_MESSAGE(p.get_state<BOOST_MSM_EUML_STATE_NAME(Stopped)&>().get_attribute(exit_counter) == 1,
153 "Stopped exit not called correctly");
154 BOOST_CHECK_MESSAGE(p.get_state<BOOST_MSM_EUML_STATE_NAME(Playing)&>().get_attribute(entry_counter) == 1,
155 "Playing entry not called correctly");
156 BOOST_CHECK_MESSAGE(p.get_attribute(start_playback_counter) == 1,"action not called correctly");
157 BOOST_CHECK_MESSAGE(p.get_attribute(test_fct_counter) == 1,"action not called correctly");
158
159 p.process_event(evt: pause());
160 BOOST_CHECK_MESSAGE(p.current_state()[0] == 1,"Paused should be active"); //Paused
161 BOOST_CHECK_MESSAGE(p.get_state<BOOST_MSM_EUML_STATE_NAME(Playing)&>().get_attribute(exit_counter) == 1,
162 "Playing exit not called correctly");
163 BOOST_CHECK_MESSAGE(p.get_state<BOOST_MSM_EUML_STATE_NAME(Paused)&>().get_attribute(entry_counter) == 1,
164 "Paused entry not called correctly");
165
166 // go back to Playing
167 p.process_event(evt: end_pause());
168 BOOST_CHECK_MESSAGE(p.current_state()[0] == 4,"Playing should be active"); //Playing
169 BOOST_CHECK_MESSAGE(p.get_state<BOOST_MSM_EUML_STATE_NAME(Paused)&>().get_attribute(exit_counter) == 1,
170 "Paused exit not called correctly");
171 BOOST_CHECK_MESSAGE(p.get_state<BOOST_MSM_EUML_STATE_NAME(Playing)&>().get_attribute(entry_counter) == 2,
172 "Playing entry not called correctly");
173
174 p.process_event(evt: pause());
175 BOOST_CHECK_MESSAGE(p.current_state()[0] == 1,"Paused should be active"); //Paused
176 BOOST_CHECK_MESSAGE(p.get_state<BOOST_MSM_EUML_STATE_NAME(Playing)&>().get_attribute(exit_counter) == 2,
177 "Playing exit not called correctly");
178 BOOST_CHECK_MESSAGE(p.get_state<BOOST_MSM_EUML_STATE_NAME(Paused)&>().get_attribute(entry_counter) == 2,
179 "Paused entry not called correctly");
180
181 p.process_event(evt: stop());
182 BOOST_CHECK_MESSAGE(p.current_state()[0] == 0,"Stopped should be active"); //Stopped
183 BOOST_CHECK_MESSAGE(p.get_state<BOOST_MSM_EUML_STATE_NAME(Paused)&>().get_attribute(exit_counter) == 2,
184 "Paused exit not called correctly");
185 BOOST_CHECK_MESSAGE(p.get_state<BOOST_MSM_EUML_STATE_NAME(Stopped)&>().get_attribute(entry_counter) == 2,
186 "Stopped entry not called correctly");
187
188 p.process_event(evt: stop());
189 BOOST_CHECK_MESSAGE(p.current_state()[0] == 0,"Stopped should be active"); //Stopped
190 BOOST_CHECK_MESSAGE(p.get_state<BOOST_MSM_EUML_STATE_NAME(Stopped)&>().get_attribute(exit_counter) == 2,
191 "Stopped exit not called correctly");
192 BOOST_CHECK_MESSAGE(p.get_state<BOOST_MSM_EUML_STATE_NAME(Stopped)&>().get_attribute(entry_counter) == 3,
193 "Stopped entry not called correctly");
194 }
195}
196
197

source code of boost/libs/msm/test/SimpleEuml2.cpp