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/back11/state_machine.hpp>
13//front-end
14#include <boost/msm/front/state_machine_def.hpp>
15#include <boost/msm/front/functor_row.hpp>
16#ifndef BOOST_MSM_NONSTANDALONE_TEST
17#define BOOST_TEST_MODULE Back11TestDeferIn2Regions
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 struct event2 {};
30 struct event3 {};
31 struct eventd {};
32
33
34 // front-end: define the FSM structure
35 struct player_ : public msm::front::state_machine_def<player_>
36 {
37 // The list of FSM states
38 struct State11 : public msm::front::state<>
39 {
40 template <class Event,class FSM>
41 void on_entry(Event const&,FSM& ) {++entry_counter;}
42 template <class Event,class FSM>
43 void on_exit(Event const&,FSM& ) {++exit_counter;}
44 int entry_counter;
45 int exit_counter;
46 };
47 struct State12 : public msm::front::state<>
48 {
49 typedef boost::fusion::vector<eventd> deferred_events;
50 template <class Event,class FSM>
51 void on_entry(Event const&,FSM& ) {++entry_counter;}
52 template <class Event,class FSM>
53 void on_exit(Event const&,FSM& ) {++exit_counter;}
54 int entry_counter;
55 int exit_counter;
56 };
57 struct State13 : public msm::front::state<>
58 {
59 template <class Event,class FSM>
60 void on_entry(Event const&,FSM& ) {++entry_counter;}
61 template <class Event,class FSM>
62 void on_exit(Event const&,FSM& ) {++exit_counter;}
63 int entry_counter;
64 int exit_counter;
65 };
66 struct State21 : 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 struct State22 : public msm::front::state<>
76 {
77 template <class Event,class FSM>
78 void on_entry(Event const&,FSM& ) {++entry_counter;}
79 template <class Event,class FSM>
80 void on_exit(Event const&,FSM& ) {++exit_counter;}
81 int entry_counter;
82 int exit_counter;
83 };
84 // the initial state of the player SM. Must be defined
85 typedef boost::fusion::vector<State11,State21> initial_state;
86
87
88 // Transition table for player
89 struct transition_table : boost::fusion::vector<
90 // Start Event Next Action Guard
91 // +---------+-------------+---------+---------------------+----------------------+
92 Row < State11 , event1 , State12 >,
93 Row < State12 , event2 , State13 >,
94
95 Row < State21 , event3 , State22 >,
96 Row < State22 , eventd , State21 >
97 // +---------+-------------+---------+---------------------+----------------------+
98 > {};
99
100 // Replaces the default no-transition response.
101 template <class FSM,class Event>
102 void no_transition(Event const& , FSM&,int )
103 {
104 BOOST_FAIL("no_transition called!");
105 }
106 // init counters
107 template <class Event,class FSM>
108 void on_entry(Event const&,FSM& fsm)
109 {
110 fsm.template get_state<player_::State11&>().entry_counter=0;
111 fsm.template get_state<player_::State11&>().exit_counter=0;
112 fsm.template get_state<player_::State12&>().entry_counter=0;
113 fsm.template get_state<player_::State12&>().exit_counter=0;
114 fsm.template get_state<player_::State13&>().entry_counter=0;
115 fsm.template get_state<player_::State13&>().exit_counter=0;
116 fsm.template get_state<player_::State21&>().entry_counter=0;
117 fsm.template get_state<player_::State22&>().exit_counter=0;
118 }
119 };
120 // Pick a back-end
121 typedef msm::back11::state_machine<player_> player;
122
123 BOOST_AUTO_TEST_CASE( Back11TestDeferIn2Regions )
124 {
125 player p;
126 // needed to start the highest-level SM. This will call on_entry and mark the start of the SM
127 p.start();
128
129 p.process_event(evt: event1());
130 BOOST_CHECK_MESSAGE(p.current_state()[0] == 1,"State12 should be active");
131 BOOST_CHECK_MESSAGE(p.current_state()[1] == 2,"State21 should be active");
132 BOOST_CHECK_MESSAGE(p.get_state<player_::State11&>().exit_counter == 1,"State11 exit not called correctly");
133 BOOST_CHECK_MESSAGE(p.get_state<player_::State11&>().entry_counter == 1,"State11 entry not called correctly");
134 BOOST_CHECK_MESSAGE(p.get_state<player_::State12&>().entry_counter == 1,"State12 entry not called correctly");
135
136 // deferred
137 p.process_event(evt: eventd());
138 BOOST_CHECK_MESSAGE(p.current_state()[0] == 1,"State12 should be active");
139 BOOST_CHECK_MESSAGE(p.current_state()[1] == 2,"State21 should be active");
140 BOOST_CHECK_MESSAGE(p.get_state<player_::State11&>().exit_counter == 1,"State11 exit not called correctly");
141 BOOST_CHECK_MESSAGE(p.get_state<player_::State11&>().entry_counter == 1,"State11 entry not called correctly");
142 BOOST_CHECK_MESSAGE(p.get_state<player_::State12&>().entry_counter == 1,"State12 entry not called correctly");
143 BOOST_CHECK_MESSAGE(p.get_state<player_::State12&>().exit_counter == 0,"State12 exit not called correctly");
144 BOOST_CHECK_MESSAGE(p.get_state<player_::State21&>().exit_counter == 0,"State21 exit not called correctly");
145 BOOST_CHECK_MESSAGE(p.get_state<player_::State21&>().entry_counter == 1,"State21 entry not called correctly");
146 BOOST_CHECK_MESSAGE(p.get_state<player_::State22&>().exit_counter == 0,"State22 exit not called correctly");
147 BOOST_CHECK_MESSAGE(p.get_state<player_::State22&>().entry_counter == 0,"State22 entry not called correctly");
148
149 p.process_event(evt: event3());
150 BOOST_CHECK_MESSAGE(p.current_state()[0] == 1,"State12 should be active");
151 BOOST_CHECK_MESSAGE(p.current_state()[1] == 2,"State21 should be active");
152 BOOST_CHECK_MESSAGE(p.get_state<player_::State21&>().exit_counter == 1,"State21 exit not called correctly");
153 BOOST_CHECK_MESSAGE(p.get_state<player_::State21&>().entry_counter == 2,"State21 entry not called correctly");
154 BOOST_CHECK_MESSAGE(p.get_state<player_::State22&>().exit_counter == 1,"State22 exit not called correctly");
155 BOOST_CHECK_MESSAGE(p.get_state<player_::State22&>().entry_counter == 1,"State22 entry not called correctly");
156 BOOST_CHECK_MESSAGE(p.get_deferred_queue().size() == 1,"Deferred queue should have one element");
157 p.clear_deferred_queue();
158
159 p.process_event(evt: event2());
160 BOOST_CHECK_MESSAGE(p.current_state()[0] == 4,"State13 should be active");
161 BOOST_CHECK_MESSAGE(p.current_state()[1] == 2,"State21 should be active");
162 BOOST_CHECK_MESSAGE(p.get_state<player_::State21&>().exit_counter == 1,"State21 exit not called correctly");
163 BOOST_CHECK_MESSAGE(p.get_state<player_::State21&>().entry_counter == 2,"State21 entry not called correctly");
164 BOOST_CHECK_MESSAGE(p.get_state<player_::State22&>().exit_counter == 1,"State22 exit not called correctly");
165 BOOST_CHECK_MESSAGE(p.get_state<player_::State22&>().entry_counter == 1,"State22 entry not called correctly");
166 BOOST_CHECK_MESSAGE(p.get_deferred_queue().size() == 0,"Deferred queue should have no element");
167 }
168}
169
170
171

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