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

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