1 //////////////////////////////////////////////////////////////////////////////
2 // Copyright 2005-2006 Andreas Huber Doenni
3 // Distributed under the Boost Software License, Version 1.0. (See accompany-
4 // ing file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
5 //////////////////////////////////////////////////////////////////////////////
6 
7 
8 
9 #include <boost/statechart/state_machine.hpp>
10 #include <boost/statechart/simple_state.hpp>
11 #include <boost/statechart/event.hpp>
12 #include <boost/statechart/transition.hpp>
13 #include <boost/statechart/shallow_history.hpp>
14 #include <boost/statechart/deep_history.hpp>
15 
16 #include <boost/mpl/list.hpp>
17 #include <boost/shared_ptr.hpp>
18 
19 #include <boost/test/test_tools.hpp>
20 
21 #include <stdexcept>
22 
23 
24 namespace sc = boost::statechart;
25 namespace mpl = boost::mpl;
26 
27 
28 
29 struct EvToB : sc::event< EvToB > {};
30 
31 struct EvToD : sc::event< EvToD > {};
32 struct EvToDShallow : sc::event< EvToDShallow > {};
33 struct EvToDDeep : sc::event< EvToDDeep > {};
34 struct EvToDShallowLocal : sc::event< EvToDShallowLocal > {};
35 struct EvToDDeepLocal : sc::event< EvToDDeepLocal > {};
36 
37 struct EvToF : sc::event< EvToF > {};
38 struct EvToFShallow : sc::event< EvToFShallow > {};
39 struct EvToFDeep : sc::event< EvToFDeep > {};
40 
41 struct EvToH : sc::event< EvToH > {};
42 struct EvToI : sc::event< EvToI > {};
43 
44 struct EvToM : sc::event< EvToM > {};
45 struct EvToQ : sc::event< EvToQ > {};
46 
47 struct EvWhatever : sc::event< EvWhatever > {};
48 
49 struct A;
50 struct HistoryTest : sc::state_machine< HistoryTest, A >
51 {
unconsumed_eventHistoryTest52   void unconsumed_event( const sc::event_base & )
53   {
54     throw std::runtime_error( "Event was not consumed!" );
55   }
56 };
57 
58 struct B;
59 struct D;
60 struct F;
61 struct H;
62 struct I;
63 struct M;
64 struct Q;
65 struct A : sc::simple_state< A, HistoryTest, B >
66 {
67   typedef mpl::list<
68     sc::transition< EvToB, B >,
69     sc::transition< EvToD, D >,
70     sc::transition< EvToDShallow, sc::shallow_history< D > >,
71     sc::transition< EvToDDeep, sc::deep_history< D > >,
72     sc::transition< EvToF, F >,
73     sc::transition< EvToFShallow, sc::shallow_history< F > >,
74     sc::transition< EvToFDeep, sc::deep_history< F > >,
75     sc::transition< EvToH, H >,
76     sc::transition< EvToI, I >,
77     sc::transition< EvToM, M >,
78     sc::transition< EvToQ, Q >
79   > reactions;
80 };
81 
82   struct J;
83   struct N;
84   struct B : sc::simple_state<
85     B, A, mpl::list< sc::shallow_history< J >, sc::deep_history< N > >,
86     sc::has_full_history > {};
87 
88     struct J : sc::simple_state< J, B::orthogonal< 0 > > {};
89     struct L;
90     struct K : sc::simple_state< K, B::orthogonal< 0 >, L > {};
91 
92       struct L : sc::simple_state< L, K > {};
93       struct M : sc::simple_state< M, K > {};
94 
95     struct N : sc::simple_state< N, B::orthogonal< 1 > > {};
96     struct P;
97     struct O : sc::simple_state< O, B::orthogonal< 1 >, P > {};
98 
99       struct P : sc::simple_state< P, O > {};
100       struct Q : sc::simple_state< Q, O > {};
101 
102   struct C : sc::simple_state< C, A, D, sc::has_full_history > {};
103 
104     struct D : sc::simple_state< D, C > {};
105     struct E : sc::simple_state< E, C, F, sc::has_full_history > {};
106 
107       struct F : sc::simple_state< F, E > {};
108       struct G : sc::simple_state< G, E, H >
109       {
110         typedef mpl::list<
111           sc::transition< EvToDShallowLocal, sc::shallow_history< D > >,
112           sc::transition< EvToDDeepLocal, sc::deep_history< D > >
113         > reactions;
114       };
115 
116         struct H : sc::simple_state< H, G > {};
117         struct I : sc::simple_state< I, G > {};
118 
119 
test_main(int,char * [])120 int test_main( int, char* [] )
121 {
122   boost::shared_ptr< HistoryTest > pM =
123     boost::shared_ptr< HistoryTest >( new HistoryTest() );
124 
125   // state_downcast sanity check
126   BOOST_REQUIRE_THROW( pM->state_downcast< const B & >(), std::bad_cast );
127   pM->initiate();
128   BOOST_REQUIRE_THROW( pM->state_downcast< const D & >(), std::bad_cast );
129 
130   BOOST_REQUIRE_NO_THROW( pM->state_downcast< const B & >() );
131 
132   // No history has been saved yet -> default state
133   pM->process_event( EvToDShallow() );
134   BOOST_REQUIRE_NO_THROW( pM->state_downcast< const D & >() );
135   pM->process_event( EvToDShallow() );
136   BOOST_REQUIRE_NO_THROW( pM->state_downcast< const D & >() );
137 
138   pM->process_event( EvToI() );
139   BOOST_REQUIRE_NO_THROW( pM->state_downcast< const I & >() );
140   // Direct inner is E when history is saved -> F
141   pM->process_event( EvToDShallow() );
142   BOOST_REQUIRE_NO_THROW( pM->state_downcast< const F & >() );
143 
144   pM->process_event( EvToH() );
145   BOOST_REQUIRE_NO_THROW( pM->state_downcast< const H & >() );
146   // Direct inner is E when history is saved -> F
147   pM->process_event( EvToDShallow() );
148   BOOST_REQUIRE_NO_THROW( pM->state_downcast< const F & >() );
149 
150   pM->process_event( EvToF() );
151   BOOST_REQUIRE_NO_THROW( pM->state_downcast< const F & >() );
152   pM->process_event( EvToB() );
153   BOOST_REQUIRE_NO_THROW( pM->state_downcast< const B & >() );
154   // Direct inner was E when history was saved -> F
155   pM->process_event( EvToDShallow() );
156   BOOST_REQUIRE_NO_THROW( pM->state_downcast< const F & >() );
157 
158   pM->initiate();
159   // History was cleared in termination -> default state
160   pM->process_event( EvToDShallow() );
161   BOOST_REQUIRE_NO_THROW( pM->state_downcast< const D & >() );
162 
163   pM->process_event( EvToI() );
164   BOOST_REQUIRE_NO_THROW( pM->state_downcast< const I & >() );
165   pM->process_event( EvToB() );
166   BOOST_REQUIRE_NO_THROW( pM->state_downcast< const B & >() );
167   pM->clear_shallow_history< C, 0 >();
168   // History was cleared -> default state
169   pM->process_event( EvToDShallow() );
170   BOOST_REQUIRE_NO_THROW( pM->state_downcast< const D & >() );
171 
172   pM = boost::shared_ptr< HistoryTest >( new HistoryTest() );
173   pM->initiate();
174   BOOST_REQUIRE_NO_THROW( pM->state_downcast< const B & >() );
175 
176   // No history has been saved yet -> default state
177   pM->process_event( EvToDDeep() );
178   BOOST_REQUIRE_NO_THROW( pM->state_downcast< const D & >() );
179   pM->process_event( EvToDDeep() );
180   BOOST_REQUIRE_NO_THROW( pM->state_downcast< const D & >() );
181 
182   pM->process_event( EvToI() );
183   BOOST_REQUIRE_NO_THROW( pM->state_downcast< const I & >() );
184   pM->process_event( EvToB() );
185   BOOST_REQUIRE_NO_THROW( pM->state_downcast< const B & >() );
186   pM->process_event( EvToDDeep() );
187   BOOST_REQUIRE_NO_THROW( pM->state_downcast< const I & >() );
188 
189   pM->process_event( EvToH() );
190   BOOST_REQUIRE_NO_THROW( pM->state_downcast< const H & >() );
191   pM->process_event( EvToB() );
192   BOOST_REQUIRE_NO_THROW( pM->state_downcast< const B & >() );
193   pM->process_event( EvToDDeep() );
194   BOOST_REQUIRE_NO_THROW( pM->state_downcast< const H & >() );
195 
196   pM->process_event( EvToF() );
197   BOOST_REQUIRE_NO_THROW( pM->state_downcast< const F & >() );
198   pM->process_event( EvToB() );
199   BOOST_REQUIRE_NO_THROW( pM->state_downcast< const B & >() );
200   pM->process_event( EvToDDeep() );
201   BOOST_REQUIRE_NO_THROW( pM->state_downcast< const F & >() );
202 
203   pM->initiate();
204   // History was cleared in termination -> default state
205   pM->process_event( EvToDDeep() );
206   BOOST_REQUIRE_NO_THROW( pM->state_downcast< const D & >() );
207 
208   pM->process_event( EvToI() );
209   BOOST_REQUIRE_NO_THROW( pM->state_downcast< const I & >() );
210   pM->process_event( EvToB() );
211   BOOST_REQUIRE_NO_THROW( pM->state_downcast< const B & >() );
212   pM->clear_deep_history< C, 0 >();
213   // History was cleared -> default state
214   pM->process_event( EvToDDeep() );
215   BOOST_REQUIRE_NO_THROW( pM->state_downcast< const D & >() );
216 
217 
218   pM = boost::shared_ptr< HistoryTest >( new HistoryTest() );
219   pM->initiate();
220   BOOST_REQUIRE_NO_THROW( pM->state_downcast< const B & >() );
221 
222   // No history has been saved yet -> default state
223   pM->process_event( EvToFShallow() );
224   BOOST_REQUIRE_NO_THROW( pM->state_downcast< const F & >() );
225   pM->process_event( EvToFShallow() );
226   BOOST_REQUIRE_NO_THROW( pM->state_downcast< const F & >() );
227 
228   pM->process_event( EvToI() );
229   BOOST_REQUIRE_NO_THROW( pM->state_downcast< const I & >() );
230   // Direct inner is G when history is saved -> H
231   pM->process_event( EvToFShallow() );
232   BOOST_REQUIRE_NO_THROW( pM->state_downcast< const H & >() );
233 
234   pM->process_event( EvToH() );
235   BOOST_REQUIRE_NO_THROW( pM->state_downcast< const H & >() );
236   pM->process_event( EvToB() );
237   BOOST_REQUIRE_NO_THROW( pM->state_downcast< const B & >() );
238   // Direct inner was G when history was saved -> H
239   pM->process_event( EvToFShallow() );
240   BOOST_REQUIRE_NO_THROW( pM->state_downcast< const H & >() );
241 
242   pM->process_event( EvToI() );
243   BOOST_REQUIRE_NO_THROW( pM->state_downcast< const I & >() );
244   pM->initiate();
245   // History was cleared in termination -> default state
246   pM->process_event( EvToFShallow() );
247   BOOST_REQUIRE_NO_THROW( pM->state_downcast< const F & >() );
248 
249   pM->process_event( EvToI() );
250   BOOST_REQUIRE_NO_THROW( pM->state_downcast< const I & >() );
251   pM->process_event( EvToB() );
252   BOOST_REQUIRE_NO_THROW( pM->state_downcast< const B & >() );
253   pM->clear_shallow_history< E, 0 >();
254   // History was cleared -> default state
255   pM->process_event( EvToFShallow() );
256   BOOST_REQUIRE_NO_THROW( pM->state_downcast< const F & >() );
257 
258   pM = boost::shared_ptr< HistoryTest >( new HistoryTest() );
259   pM->initiate();
260   BOOST_REQUIRE_NO_THROW( pM->state_downcast< const B & >() );
261 
262   // No history has been saved yet -> default state
263   pM->process_event( EvToFDeep() );
264   BOOST_REQUIRE_NO_THROW( pM->state_downcast< const F & >() );
265   pM->process_event( EvToFDeep() );
266   BOOST_REQUIRE_NO_THROW( pM->state_downcast< const F & >() );
267 
268   pM->process_event( EvToI() );
269   BOOST_REQUIRE_NO_THROW( pM->state_downcast< const I & >() );
270   pM->process_event( EvToB() );
271   BOOST_REQUIRE_NO_THROW( pM->state_downcast< const B & >() );
272   pM->process_event( EvToFDeep() );
273   BOOST_REQUIRE_NO_THROW( pM->state_downcast< const I & >() );
274 
275   pM->process_event( EvToH() );
276   BOOST_REQUIRE_NO_THROW( pM->state_downcast< const H & >() );
277   pM->process_event( EvToB() );
278   BOOST_REQUIRE_NO_THROW( pM->state_downcast< const B & >() );
279   pM->process_event( EvToFDeep() );
280   BOOST_REQUIRE_NO_THROW( pM->state_downcast< const H & >() );
281 
282   pM->process_event( EvToF() );
283   BOOST_REQUIRE_NO_THROW( pM->state_downcast< const F & >() );
284   pM->process_event( EvToB() );
285   BOOST_REQUIRE_NO_THROW( pM->state_downcast< const B & >() );
286   pM->process_event( EvToFDeep() );
287   BOOST_REQUIRE_NO_THROW( pM->state_downcast< const F & >() );
288 
289   pM->initiate();
290   // History was cleared in termination -> default state
291   pM->process_event( EvToFDeep() );
292   BOOST_REQUIRE_NO_THROW( pM->state_downcast< const F & >() );
293 
294   pM->process_event( EvToI() );
295   BOOST_REQUIRE_NO_THROW( pM->state_downcast< const I & >() );
296   pM->process_event( EvToB() );
297   BOOST_REQUIRE_NO_THROW( pM->state_downcast< const B & >() );
298   pM->clear_deep_history< E, 0 >();
299   // History was cleared -> default state
300   pM->process_event( EvToFDeep() );
301   BOOST_REQUIRE_NO_THROW( pM->state_downcast< const F & >() );
302 
303   // Test local history (new with UML 2.0)
304   pM->initiate();
305   // unconsumed_event sanity check
306   BOOST_REQUIRE_THROW( pM->process_event( EvWhatever() ), std::runtime_error );
307   pM->process_event( EvToI() );
308   BOOST_REQUIRE_NO_THROW( pM->state_downcast< const I & >() );
309   pM->process_event( EvToDShallowLocal() );
310   BOOST_REQUIRE_NO_THROW( pM->state_downcast< const F & >() );
311   pM->process_event( EvToI() );
312   pM->process_event( EvToDDeepLocal() );
313   BOOST_REQUIRE_NO_THROW( pM->state_downcast< const I & >() );
314 
315   // Given that history transitions and history initial states are implemented
316   // with the same code we just make a few sanity checks and trust that the
317   // rest will work just like we tested above.
318   pM->process_event( EvToB() );
319   BOOST_REQUIRE_NO_THROW( pM->state_downcast< const J & >() );
320   BOOST_REQUIRE_NO_THROW( pM->state_downcast< const N & >() );
321   pM->process_event( EvToM() );
322   BOOST_REQUIRE_NO_THROW( pM->state_downcast< const M & >() );
323   // Direct inner is K when history is saved -> L
324   pM->process_event( EvToB() );
325   BOOST_REQUIRE_NO_THROW( pM->state_downcast< const L & >() );
326 
327   BOOST_REQUIRE_NO_THROW( pM->state_downcast< const N & >() );
328   pM->process_event( EvToQ() );
329   BOOST_REQUIRE_NO_THROW( pM->state_downcast< const Q & >() );
330   pM->process_event( EvToB() );
331   BOOST_REQUIRE_NO_THROW( pM->state_downcast< const Q & >() );
332 
333   return 0;
334 }
335