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 | #include <boost/fusion/adapted/std_tuple.hpp> |
12 | #include <boost/fusion/include/std_tuple.hpp> |
13 | |
14 | // back-end |
15 | #include <boost/msm/back11/state_machine.hpp> |
16 | //front-end |
17 | #include <boost/msm/front/state_machine_def.hpp> |
18 | // functors |
19 | #include <boost/msm/front/functor_row.hpp> |
20 | // for And_ operator |
21 | #include <boost/msm/front/operator.hpp> |
22 | #ifndef BOOST_MSM_NONSTANDALONE_TEST |
23 | #define BOOST_TEST_MODULE back11_kleene_deferred_test |
24 | #endif |
25 | #include <boost/test/unit_test.hpp> |
26 | |
27 | using namespace std; |
28 | namespace msm = boost::msm; |
29 | namespace mpl = boost::mpl; |
30 | using namespace msm::front; |
31 | |
32 | namespace |
33 | { |
34 | // events |
35 | struct event1 {}; |
36 | struct event2 {}; |
37 | |
38 | |
39 | // front-end: define the FSM structure |
40 | struct fsm_ : public msm::front::state_machine_def<fsm_> |
41 | { |
42 | // we want deferred events and no state requires deferred events (only the fsm in the |
43 | // transition table), so the fsm does. |
44 | typedef int activate_deferred_events; |
45 | |
46 | // The list of FSM states |
47 | struct StateA : 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=0; |
54 | int exit_counter = 0; |
55 | }; |
56 | struct StateB : 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 = 0; |
63 | int exit_counter = 0; |
64 | }; |
65 | |
66 | |
67 | // the initial state of the player SM. Must be defined |
68 | typedef StateA initial_state; |
69 | |
70 | struct is_event1 |
71 | { |
72 | template <class EVT, class FSM, class SourceState, class TargetState> |
73 | bool operator()(EVT const& evt, FSM&, SourceState&, TargetState&) |
74 | { |
75 | bool is_deferred = boost::any_cast<event1>(&evt) != 0; |
76 | return is_deferred; |
77 | } |
78 | }; |
79 | |
80 | typedef fsm_ p; // makes transition table cleaner |
81 | |
82 | // Transition table for player |
83 | struct transition_table : boost::fusion::vector< |
84 | // Start Event Next Action Guard |
85 | // +---------+-------------+---------+---------------------+----------------------+ |
86 | Row < StateA , event1 , StateB , none , none >, |
87 | Row < StateB , boost::any , none , Defer , is_event1 >, |
88 | Row < StateB , event2 , StateA , none , none > |
89 | // +---------+-------------+---------+---------------------+----------------------+ |
90 | >/*>::type*/ {}; |
91 | // Replaces the default no-transition response. |
92 | template <class FSM,class Event> |
93 | void no_transition(Event const&, FSM&,int) |
94 | { |
95 | BOOST_FAIL("no_transition called!" ); |
96 | } |
97 | |
98 | }; |
99 | // Pick a back-end |
100 | typedef msm::back11::state_machine<fsm_> Fsm; |
101 | |
102 | BOOST_AUTO_TEST_CASE(back11_kleene_deferred_test) |
103 | { |
104 | Fsm fsm; |
105 | |
106 | fsm.start(); |
107 | BOOST_CHECK_MESSAGE(fsm.get_state<fsm_::StateA&>().entry_counter == 1,"StateA entry not called correctly" ); |
108 | |
109 | fsm.process_event(evt: event1()); |
110 | BOOST_CHECK_MESSAGE(fsm.current_state()[0] == 1,"StateB should be active" ); |
111 | BOOST_CHECK_MESSAGE(fsm.get_state<fsm_::StateA&>().exit_counter == 1,"StateA exit not called correctly" ); |
112 | BOOST_CHECK_MESSAGE(fsm.get_state<fsm_::StateB&>().entry_counter == 1,"StateB entry not called correctly" ); |
113 | |
114 | fsm.process_event(evt: event1()); |
115 | BOOST_CHECK_MESSAGE(fsm.current_state()[0] == 1, "StateB should be active" ); |
116 | BOOST_CHECK_MESSAGE(fsm.get_state<fsm_::StateA&>().exit_counter == 1, "StateA exit not called correctly" ); |
117 | BOOST_CHECK_MESSAGE(fsm.get_state<fsm_::StateB&>().entry_counter == 1, "StateB entry not called correctly" ); |
118 | |
119 | fsm.process_event(evt: event2()); |
120 | BOOST_CHECK_MESSAGE(fsm.current_state()[0] == 1, "StateB should be active" ); |
121 | BOOST_CHECK_MESSAGE(fsm.get_state<fsm_::StateA&>().exit_counter == 2, "StateA exit not called correctly" ); |
122 | BOOST_CHECK_MESSAGE(fsm.get_state<fsm_::StateB&>().entry_counter == 2, "StateB entry not called correctly" ); |
123 | |
124 | } |
125 | } |
126 | |
127 | |