CustomReactionTest.cpp 9.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381
  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. #include <boost/statechart/state_machine.hpp>
  7. #include <boost/statechart/event.hpp>
  8. #include <boost/statechart/simple_state.hpp>
  9. #include <boost/statechart/transition.hpp>
  10. #include <boost/statechart/custom_reaction.hpp>
  11. #include <boost/mpl/list.hpp>
  12. #include <boost/test/test_tools.hpp>
  13. #include <set>
  14. #include <map>
  15. #include <string>
  16. #include <cstddef> // size_t
  17. namespace sc = boost::statechart;
  18. namespace mpl = boost::mpl;
  19. struct EvToC : sc::event< EvToC > {};
  20. struct EvToD : sc::event< EvToD > {};
  21. struct EvDiscardNever : sc::event< EvDiscardNever > {};
  22. struct EvDiscardInB : sc::event< EvDiscardInB > {};
  23. struct EvDiscardInD : sc::event< EvDiscardInD > {};
  24. struct EvTransit : sc::event< EvTransit > {};
  25. struct EvTransitWithAction : sc::event< EvTransitWithAction > {};
  26. struct EvDefer : sc::event< EvDefer > {};
  27. struct EvTerminate : sc::event< EvTerminate > {};
  28. struct A;
  29. struct CustomReactionTest : sc::state_machine< CustomReactionTest, A >
  30. {
  31. public:
  32. //////////////////////////////////////////////////////////////////////////
  33. CustomReactionTest();
  34. void Visited( const state_base_type & stt )
  35. {
  36. const StateNamesMap::const_iterator found =
  37. stateNamesMap_.find( stt.dynamic_type() );
  38. BOOST_REQUIRE( found != stateNamesMap_.end() );
  39. visitedStates_.insert( found->second );
  40. }
  41. void ClearVisited()
  42. {
  43. visitedStates_.clear();
  44. }
  45. void AssertVisitedAll( const std::string & stateNames ) const
  46. {
  47. for ( std::string::const_iterator expectedName = stateNames.begin();
  48. expectedName != stateNames.end(); ++expectedName )
  49. {
  50. BOOST_REQUIRE( visitedStates_.find(
  51. std::string( 1, *expectedName ) ) != visitedStates_.end() );
  52. }
  53. }
  54. void AssertVisitedOne( const std::string & stateNames ) const
  55. {
  56. std::size_t found = 0;
  57. for ( std::string::const_iterator actualName = stateNames.begin();
  58. actualName != stateNames.end(); ++actualName )
  59. {
  60. found = found + ( visitedStates_.find(
  61. std::string( 1, *actualName ) ) != visitedStates_.end() ) ? 1 : 0;
  62. }
  63. BOOST_REQUIRE( found == 1 );
  64. }
  65. void TransitionAction( const EvTransitWithAction & ) {}
  66. private:
  67. //////////////////////////////////////////////////////////////////////////
  68. typedef std::map< state_base_type::id_type, std::string > StateNamesMap;
  69. typedef std::set< std::string > VisitedStates;
  70. StateNamesMap stateNamesMap_;
  71. VisitedStates visitedStates_;
  72. };
  73. struct B;
  74. struct A : sc::simple_state< A, CustomReactionTest, B >
  75. {
  76. typedef mpl::list<
  77. sc::custom_reaction< EvDiscardNever >,
  78. sc::custom_reaction< EvDiscardInB >,
  79. sc::custom_reaction< EvDiscardInD >,
  80. sc::custom_reaction< EvDefer >,
  81. sc::custom_reaction< EvTerminate >,
  82. sc::custom_reaction< EvTransitWithAction >,
  83. sc::custom_reaction< EvTransit >
  84. > reactions;
  85. sc::result react( const EvDiscardNever & )
  86. {
  87. outermost_context().Visited( *this );
  88. return forward_event();
  89. }
  90. sc::result react( const EvDiscardInB & )
  91. {
  92. BOOST_FAIL( "An event discarded in B must never reach A" );
  93. return discard_event();
  94. }
  95. sc::result react( const EvDiscardInD & )
  96. {
  97. BOOST_FAIL( "An event discarded in D must never reach B" );
  98. return discard_event();
  99. }
  100. // The following code is here just to make sure that calls to the transit<>,
  101. // defer_event and terminate functions actually compile.
  102. // Their functionality is tested extensively in TransitionTest,
  103. // DeferralTest and TerminationTest with appropriate reactions. Internally,
  104. // these reactions call exactly the same functions as the following custom
  105. // reactions call.
  106. sc::result react( const EvDefer & )
  107. {
  108. return defer_event();
  109. }
  110. sc::result react( const EvTerminate & )
  111. {
  112. return terminate();
  113. }
  114. sc::result react( const EvTransit & )
  115. {
  116. return transit< A >();
  117. }
  118. sc::result react( const EvTransitWithAction & evt )
  119. {
  120. return transit< A >( &CustomReactionTest::TransitionAction, evt );
  121. }
  122. };
  123. struct C;
  124. struct B : sc::simple_state< B, A, C >
  125. {
  126. typedef mpl::list<
  127. sc::custom_reaction< EvDiscardNever >,
  128. sc::custom_reaction< EvDiscardInB >,
  129. sc::custom_reaction< EvDiscardInD >
  130. > reactions;
  131. sc::result react( const EvDiscardNever & )
  132. {
  133. outermost_context().Visited( *this );
  134. return forward_event();
  135. }
  136. sc::result react( const EvDiscardInB & )
  137. {
  138. outermost_context().Visited( *this );
  139. return discard_event();
  140. }
  141. sc::result react( const EvDiscardInD & )
  142. {
  143. BOOST_FAIL( "An event discarded in D must never reach B" );
  144. return discard_event();
  145. }
  146. };
  147. struct E;
  148. struct F;
  149. struct D : sc::simple_state< D, B, mpl::list< E, F > >
  150. {
  151. typedef mpl::list<
  152. sc::transition< EvToC, C >,
  153. sc::custom_reaction< EvDiscardNever >,
  154. sc::custom_reaction< EvDiscardInB >,
  155. sc::custom_reaction< EvDiscardInD >
  156. > reactions;
  157. sc::result react( const EvDiscardNever & )
  158. {
  159. outermost_context().Visited( *this );
  160. return forward_event();
  161. }
  162. sc::result react( const EvDiscardInB & )
  163. {
  164. outermost_context().Visited( *this );
  165. return forward_event();
  166. }
  167. sc::result react( const EvDiscardInD & )
  168. {
  169. outermost_context().Visited( *this );
  170. return discard_event();
  171. }
  172. };
  173. struct E : sc::simple_state< E, D::orthogonal< 0 > >
  174. {
  175. typedef mpl::list<
  176. sc::custom_reaction< EvDiscardNever >,
  177. sc::custom_reaction< EvDiscardInB >,
  178. sc::custom_reaction< EvDiscardInD >
  179. > reactions;
  180. sc::result react( const EvDiscardNever & )
  181. {
  182. outermost_context().Visited( *this );
  183. return forward_event();
  184. }
  185. sc::result react( const EvDiscardInB & )
  186. {
  187. outermost_context().Visited( *this );
  188. return forward_event();
  189. }
  190. sc::result react( const EvDiscardInD & )
  191. {
  192. outermost_context().Visited( *this );
  193. return forward_event();
  194. }
  195. };
  196. struct F : sc::simple_state< F, D::orthogonal< 1 > >
  197. {
  198. typedef mpl::list<
  199. sc::custom_reaction< EvDiscardNever >,
  200. sc::custom_reaction< EvDiscardInB >,
  201. sc::custom_reaction< EvDiscardInD >
  202. > reactions;
  203. sc::result react( const EvDiscardNever & )
  204. {
  205. outermost_context().Visited( *this );
  206. return forward_event();
  207. }
  208. sc::result react( const EvDiscardInB & )
  209. {
  210. outermost_context().Visited( *this );
  211. return forward_event();
  212. }
  213. sc::result react( const EvDiscardInD & )
  214. {
  215. outermost_context().Visited( *this );
  216. return forward_event();
  217. }
  218. };
  219. struct C : sc::simple_state< C, B >
  220. {
  221. typedef mpl::list<
  222. sc::transition< EvToD, D >,
  223. sc::custom_reaction< EvDiscardNever >,
  224. sc::custom_reaction< EvDiscardInB >,
  225. sc::custom_reaction< EvDiscardInD >
  226. > reactions;
  227. sc::result react( const EvDiscardNever & )
  228. {
  229. outermost_context().Visited( *this );
  230. return forward_event();
  231. }
  232. sc::result react( const EvDiscardInB & )
  233. {
  234. outermost_context().Visited( *this );
  235. return forward_event();
  236. }
  237. sc::result react( const EvDiscardInD & )
  238. {
  239. outermost_context().Visited( *this );
  240. return forward_event();
  241. }
  242. };
  243. CustomReactionTest::CustomReactionTest()
  244. {
  245. // We're not using custom type information to make this test work even when
  246. // BOOST_STATECHART_USE_NATIVE_RTTI is defined
  247. stateNamesMap_[ A::static_type() ] = "A";
  248. stateNamesMap_[ B::static_type() ] = "B";
  249. stateNamesMap_[ C::static_type() ] = "C";
  250. stateNamesMap_[ D::static_type() ] = "D";
  251. stateNamesMap_[ E::static_type() ] = "E";
  252. stateNamesMap_[ F::static_type() ] = "F";
  253. }
  254. struct X1;
  255. struct CustomReactionEventBaseTest : sc::state_machine< CustomReactionEventBaseTest, X1 >
  256. {
  257. public:
  258. CustomReactionEventBaseTest() : reactionCount_( 0 ) {}
  259. void IncrementReactionCount()
  260. {
  261. ++reactionCount_;
  262. }
  263. unsigned int GetReactionCount() const
  264. {
  265. return reactionCount_;
  266. }
  267. private:
  268. unsigned int reactionCount_;
  269. };
  270. struct X1 : sc::simple_state< X1, CustomReactionEventBaseTest >
  271. {
  272. typedef sc::custom_reaction< sc::event_base > reactions;
  273. sc::result react( const sc::event_base & )
  274. {
  275. outermost_context().IncrementReactionCount();
  276. return discard_event();
  277. }
  278. };
  279. int test_main( int, char* [] )
  280. {
  281. CustomReactionTest machine;
  282. machine.initiate();
  283. machine.process_event( EvDiscardNever() );
  284. machine.AssertVisitedAll( "ABC" );
  285. machine.ClearVisited();
  286. machine.process_event( EvDiscardInB() );
  287. machine.AssertVisitedAll( "BC" );
  288. machine.process_event( EvToD() );
  289. machine.ClearVisited();
  290. machine.process_event( EvDiscardNever() );
  291. machine.AssertVisitedAll( "ABDEF" );
  292. machine.ClearVisited();
  293. machine.process_event( EvDiscardInD() );
  294. machine.AssertVisitedAll( "D" );
  295. machine.AssertVisitedOne( "EF" );
  296. machine.ClearVisited();
  297. machine.process_event( EvDiscardInB() );
  298. machine.AssertVisitedAll( "BD" );
  299. machine.AssertVisitedOne( "EF" );
  300. machine.ClearVisited();
  301. CustomReactionEventBaseTest eventBaseMachine;
  302. eventBaseMachine.initiate();
  303. BOOST_REQUIRE( eventBaseMachine.GetReactionCount() == 0 );
  304. eventBaseMachine.process_event( EvToC() );
  305. BOOST_REQUIRE( eventBaseMachine.GetReactionCount() == 1 );
  306. eventBaseMachine.process_event( EvToD() );
  307. BOOST_REQUIRE( eventBaseMachine.GetReactionCount() == 2 );
  308. return 0;
  309. }