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 eventResolve {};
27 struct eventConnect {};
28 struct eventResolved {};
29 struct eventRead {};
30 struct eventd {};
31
32
33 // front-end: define the FSM structure
34 struct player_ : public msm::front::state_machine_def<player_>
35 {
36 player_()
37 :expected_action_counter(0)
38 {}
39
40 struct enqueue_action1
41 {
42 template <class EVT,class FSM,class SourceState,class TargetState>
43 void operator()(EVT const& ,FSM& fsm,SourceState& ,TargetState& )
44 {
45 fsm.template process_event(eventResolve());
46 }
47 };
48 struct enqueue_action2
49 {
50 template <class EVT,class FSM,class SourceState,class TargetState>
51 void operator()(EVT const& ,FSM& fsm,SourceState& ,TargetState& )
52 {
53 fsm.template process_event(eventConnect());
54 }
55 };
56 struct expected_action
57 {
58 template <class EVT,class FSM,class SourceState,class TargetState>
59 void operator()(EVT const& ,FSM& fsm,SourceState& ,TargetState& )
60 {
61 ++fsm.expected_action_counter;
62 //std::cout << "expected action called" << std::endl;
63 }
64 };
65 struct unexpected_action
66 {
67 template <class EVT,class FSM,class SourceState,class TargetState>
68 void operator()(EVT const& ,FSM& fsm,SourceState& ,TargetState& )
69 {
70 std::cout << "unexpected action called" << std::endl;
71 }
72 };
73
74 // The list of FSM states
75 struct Unresolved : public msm::front::state<>
76 {
77 typedef mpl::vector<eventRead > deferred_events;
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 // Transition table for Empty
85 struct internal_transition_table : mpl::vector<
86 // Start Event Next Action Guard
87 Internal < eventConnect , msm::front::ActionSequence_<mpl::vector<enqueue_action1,enqueue_action2>> >
88 // +---------+-------------+---------+---------------------+----------------------+
89 > {};
90 };
91 struct Resolving : public msm::front::state<>
92 {
93 typedef mpl::vector<eventConnect > deferred_events;
94 template <class Event,class FSM>
95 void on_entry(Event const&,FSM& ) {++entry_counter;}
96 template <class Event,class FSM>
97 void on_exit(Event const&,FSM& ) {++exit_counter;}
98 int entry_counter;
99 int exit_counter;
100 };
101 struct Resolved : public msm::front::state<>
102 {
103 template <class Event,class FSM>
104 void on_entry(Event const&,FSM& ) {++entry_counter;}
105 template <class Event,class FSM>
106 void on_exit(Event const&,FSM& ) {++exit_counter;}
107 int entry_counter;
108 int exit_counter;
109 };
110 struct Connecting : public msm::front::state<>
111 {
112 template <class Event,class FSM>
113 void on_entry(Event const&,FSM& ) {++entry_counter;}
114 template <class Event,class FSM>
115 void on_exit(Event const&,FSM& ) {++exit_counter;}
116 int entry_counter;
117 int exit_counter;
118 };
119 struct State22 : public msm::front::state<>
120 {
121 template <class Event,class FSM>
122 void on_entry(Event const&,FSM& ) {++entry_counter;}
123 template <class Event,class FSM>
124 void on_exit(Event const&,FSM& ) {++exit_counter;}
125 int entry_counter;
126 int exit_counter;
127 };
128 // the initial state of the player SM. Must be defined
129 typedef mpl::vector<Unresolved,State22> initial_state;
130
131
132 // Transition table for player
133 struct transition_table : mpl::vector<
134 // Start Event Next Action Guard
135 // +---------+-------------+---------+---------------------+----------------------+
136 Row < Unresolved , eventResolve , Resolving >,
137 Row < Resolving , eventResolved , Resolved >,
138 Row < Resolved , eventConnect , Connecting , expected_action >,
139 Row < State22 , eventd , State22 >
140 // +---------+-------------+---------+---------------------+----------------------+
141 > {};
142
143 // Replaces the default no-transition response.
144 template <class FSM,class Event>
145 void no_transition(Event const& , FSM&,int )
146 {
147 BOOST_FAIL("no_transition called!");
148 }
149 // init counters
150 template <class Event,class FSM>
151 void on_entry(Event const&,FSM& fsm)
152 {
153 fsm.template get_state<player_::Unresolved&>().entry_counter=0;
154 fsm.template get_state<player_::Unresolved&>().exit_counter=0;
155 fsm.template get_state<player_::Resolving&>().entry_counter=0;
156 fsm.template get_state<player_::Resolving&>().exit_counter=0;
157 fsm.template get_state<player_::Resolved&>().entry_counter=0;
158 fsm.template get_state<player_::Resolved&>().exit_counter=0;
159 fsm.template get_state<player_::Connecting&>().entry_counter=0;
160 fsm.template get_state<player_::Connecting&>().exit_counter=0;
161 }
162 int expected_action_counter;
163 };
164 // Pick a back-end
165 typedef msm::back::state_machine<player_> player;
166
167 BOOST_AUTO_TEST_CASE( TestDeferAndMessageQueue )
168 {
169 player p;
170 // needed to start the highest-level SM. This will call on_entry and mark the start of the SM
171 p.start();
172
173 p.process_event(evt: eventConnect());
174 BOOST_CHECK_MESSAGE(p.current_state()[0] == 1,"Resolving should be active");
175 BOOST_CHECK_MESSAGE(p.current_state()[1] == 3,"State22 should be active");
176 BOOST_CHECK_MESSAGE(p.get_state<player_::Unresolved&>().exit_counter == 1,"Unresolved exit not called correctly");
177 BOOST_CHECK_MESSAGE(p.get_state<player_::Unresolved&>().entry_counter == 1,"Unresolved entry not called correctly");
178 BOOST_CHECK_MESSAGE(p.get_state<player_::Resolving&>().entry_counter == 1,"Resolving entry not called correctly");
179
180 p.process_event(evt: eventResolved());
181 BOOST_CHECK_MESSAGE(p.current_state()[0] == 4,"Connecting should be active");
182 BOOST_CHECK_MESSAGE(p.current_state()[1] == 3,"State22 should be active");
183 BOOST_CHECK_MESSAGE(p.get_state<player_::Resolved&>().exit_counter == 1,"Resolved exit not called correctly");
184 BOOST_CHECK_MESSAGE(p.get_state<player_::Resolved&>().entry_counter == 1,"Resolved entry not called correctly");
185 BOOST_CHECK_MESSAGE(p.get_state<player_::Resolving&>().exit_counter == 1,"Resolving exit not called correctly");
186 BOOST_CHECK_MESSAGE(p.get_state<player_::Connecting&>().entry_counter == 1,"Connecting entry not called correctly");
187
188 BOOST_CHECK_MESSAGE(p.expected_action_counter == 1,"expected_action should have been called");
189
190 }
191}
192
193
194

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