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
24namespace sc = boost::statechart;
25namespace mpl = boost::mpl;
26
27
28
29struct EvToB : sc::event< EvToB > {};
30
31struct EvToD : sc::event< EvToD > {};
32struct EvToDShallow : sc::event< EvToDShallow > {};
33struct EvToDDeep : sc::event< EvToDDeep > {};
34struct EvToDShallowLocal : sc::event< EvToDShallowLocal > {};
35struct EvToDDeepLocal : sc::event< EvToDDeepLocal > {};
36
37struct EvToF : sc::event< EvToF > {};
38struct EvToFShallow : sc::event< EvToFShallow > {};
39struct EvToFDeep : sc::event< EvToFDeep > {};
40
41struct EvToH : sc::event< EvToH > {};
42struct EvToI : sc::event< EvToI > {};
43
44struct EvToM : sc::event< EvToM > {};
45struct EvToQ : sc::event< EvToQ > {};
46
47struct EvWhatever : sc::event< EvWhatever > {};
48
49struct A;
50struct HistoryTest : sc::state_machine< HistoryTest, A >
51{
52 void unconsumed_event( const sc::event_base & )
53 {
54 throw std::runtime_error( "Event was not consumed!" );
55 }
56};
57
58struct B;
59struct D;
60struct F;
61struct H;
62struct I;
63struct M;
64struct Q;
65struct 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
120int 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( evt: EvToDShallow() );
134 BOOST_REQUIRE_NO_THROW( pM->state_downcast< const D & >() );
135 pM->process_event( evt: EvToDShallow() );
136 BOOST_REQUIRE_NO_THROW( pM->state_downcast< const D & >() );
137
138 pM->process_event( evt: 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( evt: EvToDShallow() );
142 BOOST_REQUIRE_NO_THROW( pM->state_downcast< const F & >() );
143
144 pM->process_event( evt: 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( evt: EvToDShallow() );
148 BOOST_REQUIRE_NO_THROW( pM->state_downcast< const F & >() );
149
150 pM->process_event( evt: EvToF() );
151 BOOST_REQUIRE_NO_THROW( pM->state_downcast< const F & >() );
152 pM->process_event( evt: 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( evt: 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( evt: EvToDShallow() );
161 BOOST_REQUIRE_NO_THROW( pM->state_downcast< const D & >() );
162
163 pM->process_event( evt: EvToI() );
164 BOOST_REQUIRE_NO_THROW( pM->state_downcast< const I & >() );
165 pM->process_event( evt: 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( evt: 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( evt: EvToDDeep() );
178 BOOST_REQUIRE_NO_THROW( pM->state_downcast< const D & >() );
179 pM->process_event( evt: EvToDDeep() );
180 BOOST_REQUIRE_NO_THROW( pM->state_downcast< const D & >() );
181
182 pM->process_event( evt: EvToI() );
183 BOOST_REQUIRE_NO_THROW( pM->state_downcast< const I & >() );
184 pM->process_event( evt: EvToB() );
185 BOOST_REQUIRE_NO_THROW( pM->state_downcast< const B & >() );
186 pM->process_event( evt: EvToDDeep() );
187 BOOST_REQUIRE_NO_THROW( pM->state_downcast< const I & >() );
188
189 pM->process_event( evt: EvToH() );
190 BOOST_REQUIRE_NO_THROW( pM->state_downcast< const H & >() );
191 pM->process_event( evt: EvToB() );
192 BOOST_REQUIRE_NO_THROW( pM->state_downcast< const B & >() );
193 pM->process_event( evt: EvToDDeep() );
194 BOOST_REQUIRE_NO_THROW( pM->state_downcast< const H & >() );
195
196 pM->process_event( evt: EvToF() );
197 BOOST_REQUIRE_NO_THROW( pM->state_downcast< const F & >() );
198 pM->process_event( evt: EvToB() );
199 BOOST_REQUIRE_NO_THROW( pM->state_downcast< const B & >() );
200 pM->process_event( evt: 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( evt: EvToDDeep() );
206 BOOST_REQUIRE_NO_THROW( pM->state_downcast< const D & >() );
207
208 pM->process_event( evt: EvToI() );
209 BOOST_REQUIRE_NO_THROW( pM->state_downcast< const I & >() );
210 pM->process_event( evt: 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( evt: 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( evt: EvToFShallow() );
224 BOOST_REQUIRE_NO_THROW( pM->state_downcast< const F & >() );
225 pM->process_event( evt: EvToFShallow() );
226 BOOST_REQUIRE_NO_THROW( pM->state_downcast< const F & >() );
227
228 pM->process_event( evt: 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( evt: EvToFShallow() );
232 BOOST_REQUIRE_NO_THROW( pM->state_downcast< const H & >() );
233
234 pM->process_event( evt: EvToH() );
235 BOOST_REQUIRE_NO_THROW( pM->state_downcast< const H & >() );
236 pM->process_event( evt: 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( evt: EvToFShallow() );
240 BOOST_REQUIRE_NO_THROW( pM->state_downcast< const H & >() );
241
242 pM->process_event( evt: 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( evt: EvToFShallow() );
247 BOOST_REQUIRE_NO_THROW( pM->state_downcast< const F & >() );
248
249 pM->process_event( evt: EvToI() );
250 BOOST_REQUIRE_NO_THROW( pM->state_downcast< const I & >() );
251 pM->process_event( evt: 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( evt: 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( evt: EvToFDeep() );
264 BOOST_REQUIRE_NO_THROW( pM->state_downcast< const F & >() );
265 pM->process_event( evt: EvToFDeep() );
266 BOOST_REQUIRE_NO_THROW( pM->state_downcast< const F & >() );
267
268 pM->process_event( evt: EvToI() );
269 BOOST_REQUIRE_NO_THROW( pM->state_downcast< const I & >() );
270 pM->process_event( evt: EvToB() );
271 BOOST_REQUIRE_NO_THROW( pM->state_downcast< const B & >() );
272 pM->process_event( evt: EvToFDeep() );
273 BOOST_REQUIRE_NO_THROW( pM->state_downcast< const I & >() );
274
275 pM->process_event( evt: EvToH() );
276 BOOST_REQUIRE_NO_THROW( pM->state_downcast< const H & >() );
277 pM->process_event( evt: EvToB() );
278 BOOST_REQUIRE_NO_THROW( pM->state_downcast< const B & >() );
279 pM->process_event( evt: EvToFDeep() );
280 BOOST_REQUIRE_NO_THROW( pM->state_downcast< const H & >() );
281
282 pM->process_event( evt: EvToF() );
283 BOOST_REQUIRE_NO_THROW( pM->state_downcast< const F & >() );
284 pM->process_event( evt: EvToB() );
285 BOOST_REQUIRE_NO_THROW( pM->state_downcast< const B & >() );
286 pM->process_event( evt: 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( evt: EvToFDeep() );
292 BOOST_REQUIRE_NO_THROW( pM->state_downcast< const F & >() );
293
294 pM->process_event( evt: EvToI() );
295 BOOST_REQUIRE_NO_THROW( pM->state_downcast< const I & >() );
296 pM->process_event( evt: 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( evt: 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( evt: EvToI() );
308 BOOST_REQUIRE_NO_THROW( pM->state_downcast< const I & >() );
309 pM->process_event( evt: EvToDShallowLocal() );
310 BOOST_REQUIRE_NO_THROW( pM->state_downcast< const F & >() );
311 pM->process_event( evt: EvToI() );
312 pM->process_event( evt: 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( evt: 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( evt: 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( evt: 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( evt: EvToQ() );
329 BOOST_REQUIRE_NO_THROW( pM->state_downcast< const Q & >() );
330 pM->process_event( evt: EvToB() );
331 BOOST_REQUIRE_NO_THROW( pM->state_downcast< const Q & >() );
332
333 return 0;
334}
335

source code of boost/libs/statechart/test/HistoryTest.cpp