1// Copyright 2017 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 player_()
36 :expected_action_counter(0),expected_action2_counter(0)
37 {}
38 // The list of FSM states
39 struct State11 : public msm::front::state<>
40 {
41 typedef mpl::vector<eventd> deferred_events;
42
43 template <class Event,class FSM>
44 void on_entry(Event const&,FSM& ) {++entry_counter;}
45 template <class Event,class FSM>
46 void on_exit(Event const&,FSM& ) {++exit_counter;}
47 int entry_counter;
48 int exit_counter;
49 };
50 struct State12 : public msm::front::state<>
51 {
52 template <class Event,class FSM>
53 void on_entry(Event const&,FSM& ) {++entry_counter;}
54 template <class Event,class FSM>
55 void on_exit(Event const&,FSM& ) {++exit_counter;}
56 int entry_counter;
57 int exit_counter;
58 };
59 struct State13 : public msm::front::state<>
60 {
61 template <class Event,class FSM>
62 void on_entry(Event const&,FSM& ) {++entry_counter;}
63 template <class Event,class FSM>
64 void on_exit(Event const&,FSM& ) {++exit_counter;}
65 int entry_counter;
66 int exit_counter;
67 };
68 struct enqueue_action
69 {
70 template <class EVT,class FSM,class SourceState,class TargetState>
71 void operator()(EVT const& ,FSM& fsm,SourceState& ,TargetState& )
72 {
73 fsm.template process_event(event2());
74 }
75 };
76 struct expected_action
77 {
78 template <class EVT,class FSM,class SourceState,class TargetState>
79 void operator()(EVT const& ,FSM& fsm,SourceState& ,TargetState& )
80 {
81 ++fsm.expected_action_counter;
82 }
83 };
84 struct expected_action2
85 {
86 template <class EVT,class FSM,class SourceState,class TargetState>
87 void operator()(EVT const& ,FSM& fsm,SourceState& ,TargetState& )
88 {
89 ++fsm.expected_action2_counter;
90 }
91 };
92 // the initial state of the player SM. Must be defined
93 typedef mpl::vector<State11> initial_state;
94
95
96 // Transition table for player
97 struct transition_table : mpl::vector<
98 // Start Event Next Action Guard
99 // +---------+-------------+---------+---------------------+----------------------+
100 Row < State11 , event1 , State12 , enqueue_action >,
101 Row < State12 , event2 , State13 , expected_action2 >,
102 Row < State12 , eventd , State13 , expected_action >,
103 Row < State13 , event2 , State11 >,
104 Row < State13 , eventd , State11 >
105 // +---------+-------------+---------+---------------------+----------------------+
106 > {};
107
108 // Replaces the default no-transition response.
109 template <class FSM,class Event>
110 void no_transition(Event const& , FSM&,int )
111 {
112 BOOST_FAIL("no_transition called!");
113 }
114 // init counters
115 template <class Event,class FSM>
116 void on_entry(Event const&,FSM& fsm)
117 {
118 fsm.template get_state<player_::State11&>().entry_counter=0;
119 fsm.template get_state<player_::State11&>().exit_counter=0;
120 fsm.template get_state<player_::State12&>().entry_counter=0;
121 fsm.template get_state<player_::State12&>().exit_counter=0;
122 fsm.template get_state<player_::State13&>().entry_counter=0;
123 fsm.template get_state<player_::State13&>().exit_counter=0;
124 }
125 int expected_action_counter;
126 int expected_action2_counter;
127 };
128 // Pick a back-end
129 typedef msm::back::state_machine<player_> player;
130
131 BOOST_AUTO_TEST_CASE( TestDeferAndMessageQueue2 )
132 {
133 player p;
134 // needed to start the highest-level SM. This will call on_entry and mark the start of the SM
135 p.start();
136
137 p.process_event(evt: eventd());
138 BOOST_CHECK_MESSAGE(p.current_state()[0] == 0,"State11 should be active");
139 BOOST_CHECK_MESSAGE(p.get_state<player_::State11&>().entry_counter == 1,"State11 entry not called correctly");
140
141 p.process_event(evt: event1());
142 BOOST_CHECK_MESSAGE(p.current_state()[0] == 0,"State11 should be active");
143 BOOST_CHECK_MESSAGE(p.get_state<player_::State11&>().exit_counter == 1,"State11 exit not called correctly");
144 BOOST_CHECK_MESSAGE(p.get_state<player_::State12&>().entry_counter == 1,"State12 entry not called correctly");
145 BOOST_CHECK_MESSAGE(p.get_state<player_::State12&>().exit_counter == 1,"State12 exit not called correctly");
146 BOOST_CHECK_MESSAGE(p.get_state<player_::State11&>().entry_counter == 2,"State11 entry not called correctly");
147 BOOST_CHECK_MESSAGE(p.get_state<player_::State13&>().exit_counter == 1,"State13 exit not called correctly");
148 BOOST_CHECK_MESSAGE(p.get_state<player_::State13&>().entry_counter == 1,"State13 entry not called correctly");
149 BOOST_CHECK_MESSAGE(p.expected_action_counter == 1,"expected_action should have been called");
150 BOOST_CHECK_MESSAGE(p.expected_action2_counter == 0,"expected_action2 should not have been called");
151 }
152}
153
154
155

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