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// back-end
12#include <boost/msm/back/state_machine.hpp>
13//front-end
14#include <boost/msm/front/state_machine_def.hpp>
15
16#ifndef BOOST_MSM_NONSTANDALONE_TEST
17#define BOOST_TEST_MODULE MyTest
18#endif
19#include <boost/test/unit_test.hpp>
20
21namespace msm = boost::msm;
22namespace mpl = boost::mpl;
23using namespace boost::msm::front;
24
25namespace
26{
27 // events
28 struct event1 {};
29
30
31 // front-end: define the FSM structure
32 struct my_machine_ : public msm::front::state_machine_def<my_machine_>
33 {
34 unsigned int state2_to_state3_counter;
35 unsigned int state3_to_state4_counter;
36 unsigned int always_true_counter;
37 unsigned int always_false_counter;
38
39 my_machine_():
40 state2_to_state3_counter(0),
41 state3_to_state4_counter(0),
42 always_true_counter(0),
43 always_false_counter(0)
44 {}
45
46 // The list of FSM states
47 struct State1 : public msm::front::state<>
48 {
49 template <class Event,class FSM>
50 void on_entry(Event const&,FSM& ) {++entry_counter;}
51 template <class Event,class FSM>
52 void on_exit(Event const&,FSM& ) {++exit_counter;}
53 int entry_counter;
54 int exit_counter;
55 };
56 struct State2 : public msm::front::state<>
57 {
58 template <class Event,class FSM>
59 void on_entry(Event const&,FSM& ) {++entry_counter;}
60 template <class Event,class FSM>
61 void on_exit(Event const&,FSM& ) {++exit_counter;}
62 int entry_counter;
63 int exit_counter;
64 };
65
66 struct State3 : public msm::front::state<>
67 {
68 template <class Event,class FSM>
69 void on_entry(Event const&,FSM& ) {++entry_counter;}
70 template <class Event,class FSM>
71 void on_exit(Event const&,FSM& ) {++exit_counter;}
72 int entry_counter;
73 int exit_counter;
74 };
75
76 struct State4 : public msm::front::state<>
77 {
78 template <class Event,class FSM>
79 void on_entry(Event const&,FSM& ) {++entry_counter;}
80 template <class Event,class FSM>
81 void on_exit(Event const&,FSM& ) {++exit_counter;}
82 int entry_counter;
83 int exit_counter;
84 };
85
86 // the initial state of the player SM. Must be defined
87 typedef State1 initial_state;
88
89 // transition actions
90 void State2ToState3(none const&) { ++state2_to_state3_counter; }
91 void State3ToState4(none const&) { ++state3_to_state4_counter; }
92 // guard conditions
93 bool always_true(none const& )
94 {
95 ++always_true_counter;
96 return true;
97 }
98 bool always_false(none const& )
99 {
100 ++always_false_counter;
101 return false;
102 }
103
104 typedef my_machine_ p; // makes transition table cleaner
105
106 // Transition table for player
107 struct transition_table : mpl::vector<
108 // Start Event Next Action Guard
109 // +---------+-------------+---------+---------------------+----------------------+
110 _row < State1 , none , State2 >,
111 a_row < State2 , none , State3 , &p::State2ToState3 >,
112 // +---------+-------------+---------+---------------------+----------------------+
113 row < State3 , none , State4 , &p::State3ToState4 , &p::always_true >,
114 g_row < State3 , none , State4 , &p::always_false >,
115 _row < State4 , event1 , State1 >
116 // +---------+-------------+---------+---------------------+----------------------+
117 > {};
118 // Replaces the default no-transition response.
119 template <class FSM,class Event>
120 void no_transition(Event const&, FSM&,int)
121 {
122 BOOST_FAIL("no_transition called!");
123 }
124 // init counters
125 template <class Event,class FSM>
126 void on_entry(Event const&,FSM& fsm)
127 {
128 fsm.template get_state<my_machine_::State1&>().entry_counter=0;
129 fsm.template get_state<my_machine_::State1&>().exit_counter=0;
130 fsm.template get_state<my_machine_::State2&>().entry_counter=0;
131 fsm.template get_state<my_machine_::State2&>().exit_counter=0;
132 fsm.template get_state<my_machine_::State3&>().entry_counter=0;
133 fsm.template get_state<my_machine_::State3&>().exit_counter=0;
134 fsm.template get_state<my_machine_::State4&>().entry_counter=0;
135 fsm.template get_state<my_machine_::State4&>().exit_counter=0;
136 }
137 };
138 // Pick a back-end
139 typedef msm::back::state_machine<my_machine_> my_machine;
140
141 //static char const* const state_names[] = { "State1", "State2", "State3", "State4" };
142
143
144 BOOST_AUTO_TEST_CASE( anonymous_test )
145 {
146 my_machine p;
147
148 // needed to start the highest-level SM. This will call on_entry and mark the start of the SM
149 // in this case it will also immediately trigger all anonymous transitions
150 p.start();
151 BOOST_CHECK_MESSAGE(p.current_state()[0] == 3,"State4 should be active"); //State4
152 BOOST_CHECK_MESSAGE(p.get_state<my_machine_::State1&>().exit_counter == 1,"State1 exit not called correctly");
153 BOOST_CHECK_MESSAGE(p.get_state<my_machine_::State1&>().entry_counter == 1,"State1 entry not called correctly");
154 BOOST_CHECK_MESSAGE(p.get_state<my_machine_::State2&>().exit_counter == 1,"State2 exit not called correctly");
155 BOOST_CHECK_MESSAGE(p.get_state<my_machine_::State2&>().entry_counter == 1,"State2 entry not called correctly");
156 BOOST_CHECK_MESSAGE(p.get_state<my_machine_::State3&>().exit_counter == 1,"State3 exit not called correctly");
157 BOOST_CHECK_MESSAGE(p.get_state<my_machine_::State3&>().entry_counter == 1,"State3 entry not called correctly");
158 BOOST_CHECK_MESSAGE(p.get_state<my_machine_::State4&>().entry_counter == 1,"State4 entry not called correctly");
159 BOOST_CHECK_MESSAGE(p.always_true_counter == 1,"guard not called correctly");
160 BOOST_CHECK_MESSAGE(p.always_false_counter == 1,"guard not called correctly");
161 BOOST_CHECK_MESSAGE(p.state2_to_state3_counter == 1,"action not called correctly");
162 BOOST_CHECK_MESSAGE(p.state3_to_state4_counter == 1,"action not called correctly");
163
164
165 // this event will bring us back to the initial state and thus, a new "loop" will be started
166 p.process_event(evt: event1());
167 BOOST_CHECK_MESSAGE(p.current_state()[0] == 3,"State4 should be active"); //State4
168 BOOST_CHECK_MESSAGE(p.get_state<my_machine_::State1&>().exit_counter == 2,"State1 exit not called correctly");
169 BOOST_CHECK_MESSAGE(p.get_state<my_machine_::State1&>().entry_counter == 2,"State1 entry not called correctly");
170 BOOST_CHECK_MESSAGE(p.get_state<my_machine_::State2&>().exit_counter == 2,"State2 exit not called correctly");
171 BOOST_CHECK_MESSAGE(p.get_state<my_machine_::State2&>().entry_counter == 2,"State2 entry not called correctly");
172 BOOST_CHECK_MESSAGE(p.get_state<my_machine_::State3&>().exit_counter == 2,"State3 exit not called correctly");
173 BOOST_CHECK_MESSAGE(p.get_state<my_machine_::State3&>().entry_counter == 2,"State3 entry not called correctly");
174 BOOST_CHECK_MESSAGE(p.get_state<my_machine_::State4&>().entry_counter == 2,"State4 entry not called correctly");
175 BOOST_CHECK_MESSAGE(p.get_state<my_machine_::State4&>().exit_counter == 1,"State4 exit not called correctly");
176 BOOST_CHECK_MESSAGE(p.always_true_counter == 2,"guard not called correctly");
177 BOOST_CHECK_MESSAGE(p.always_false_counter == 2,"guard not called correctly");
178 BOOST_CHECK_MESSAGE(p.state2_to_state3_counter == 2,"action not called correctly");
179 BOOST_CHECK_MESSAGE(p.state3_to_state4_counter == 2,"action not called correctly");
180
181 }
182}
183
184

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