State.cpp 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239
  1. /*
  2. * Copyright (c) Contributors to the Open 3D Engine Project.
  3. * For complete copyright and license terms please see the LICENSE at the root of this distribution.
  4. *
  5. * SPDX-License-Identifier: Apache-2.0 OR MIT
  6. *
  7. */
  8. #include <AzCore/State/HSM.h>
  9. #include <AzCore/std/string/string.h>
  10. #include <AzCore/UnitTest/TestTypes.h>
  11. #include <AzCore/std/allocator_static.h>
  12. #include <AzCore/std/allocator_ref.h>
  13. using namespace AZ;
  14. namespace
  15. {
  16. class HSMTest
  17. : public ::testing::Test
  18. {
  19. int myFoo;
  20. HSM m_hsm;
  21. // we are not allowed to use dynamic memory in this lib (although we can for test, we use it to check if the actual lib leaks)
  22. AZStd::basic_string<char, AZStd::char_traits<char>, AZStd::static_buffer_allocator<256, 4> > result;
  23. enum HsmTestEvents
  24. {
  25. A_SIG, B_SIG, C_SIG, D_SIG, E_SIG, F_SIG, G_SIG, H_SIG
  26. };
  27. enum HsmTestStates
  28. {
  29. TOP, S1, S11, S2, S21, S211
  30. };
  31. bool topHndlr(HSM& sm, const HSM::Event& e)
  32. {
  33. switch (e.id)
  34. {
  35. case HSM::EnterEventId:
  36. result += "top-ENTRY;";
  37. return true;
  38. case HSM::ExitEventId:
  39. result += "top-EXIT;";
  40. return true;
  41. case E_SIG:
  42. result += "top-E;";
  43. sm.Transition(S211);
  44. return true;
  45. }
  46. return false;
  47. }
  48. bool s1Hndlr(HSM& sm, const HSM::Event& e)
  49. {
  50. switch (e.id)
  51. {
  52. case HSM::EnterEventId:
  53. result += "s1-ENTRY;";
  54. return true;
  55. case HSM::ExitEventId:
  56. result += "s1-EXIT;";
  57. return true;
  58. case A_SIG:
  59. result += "s1-A;";
  60. sm.Transition(S1);
  61. return true;
  62. case B_SIG:
  63. result += "s1-B;";
  64. sm.Transition(S11);
  65. return true;
  66. case C_SIG:
  67. result += "s1-C;";
  68. sm.Transition(S2);
  69. return true;
  70. case D_SIG:
  71. result += "s1-D;";
  72. sm.Transition(TOP);
  73. return true;
  74. case F_SIG:
  75. result += "s1-F;";
  76. sm.Transition(S211);
  77. return true;
  78. }
  79. return false;
  80. }
  81. bool s11Hndlr(HSM& sm, const HSM::Event& e)
  82. {
  83. switch (e.id)
  84. {
  85. case HSM::EnterEventId:
  86. result += "s11-ENTRY;";
  87. return true;
  88. case HSM::ExitEventId:
  89. result += "s11-EXIT;";
  90. return true;
  91. case G_SIG:
  92. result += "s11-G;";
  93. sm.Transition(S211);
  94. return true;
  95. case H_SIG:
  96. if (myFoo)
  97. {
  98. result += "s11-H;";
  99. myFoo = 0;
  100. return true;
  101. }
  102. break;
  103. }
  104. return false;
  105. }
  106. bool s2Hndlr(HSM& sm, const HSM::Event& e)
  107. {
  108. switch (e.id)
  109. {
  110. case HSM::EnterEventId:
  111. result += "s2-ENTRY;";
  112. return true;
  113. case HSM::ExitEventId:
  114. result += "s2-EXIT;";
  115. return true;
  116. case C_SIG:
  117. result += "s2-C;";
  118. sm.Transition(S1);
  119. return true;
  120. case F_SIG:
  121. result += "s2-F;";
  122. sm.Transition(S11);
  123. return true;
  124. }
  125. return false;
  126. }
  127. bool s21Hndlr(HSM& sm, const HSM::Event& e)
  128. {
  129. switch (e.id)
  130. {
  131. case HSM::EnterEventId:
  132. result += "s21-ENTRY;";
  133. return true;
  134. case HSM::ExitEventId:
  135. result += "s21-EXIT;";
  136. return true;
  137. case B_SIG:
  138. result += "s21-B;";
  139. sm.Transition(S211);
  140. return true;
  141. case H_SIG:
  142. if (!myFoo)
  143. {
  144. result += "s21-H;";
  145. myFoo = 1;
  146. sm.Transition(S21);
  147. return true;
  148. }
  149. break;
  150. }
  151. return false;
  152. }
  153. bool s211Hndlr(HSM& sm, const HSM::Event& e)
  154. {
  155. switch (e.id)
  156. {
  157. case HSM::EnterEventId:
  158. result += "s211-ENTRY;";
  159. return true;
  160. case HSM::ExitEventId:
  161. result += "s211-EXIT;";
  162. return true;
  163. case D_SIG:
  164. result += "s211-D;";
  165. sm.Transition(S21);
  166. return true;
  167. case G_SIG:
  168. result += "s211-G;";
  169. sm.Transition(TOP);
  170. return true;
  171. }
  172. return false;
  173. }
  174. public:
  175. void run()
  176. {
  177. myFoo = 0;
  178. m_hsm.SetStateHandler(TOP, "TOP", HSM::StateHandler(this, &HSMTest::topHndlr), HSM::InvalidStateId, S1);
  179. m_hsm.SetStateHandler(S1, "S1", HSM::StateHandler(this, &HSMTest::s1Hndlr), TOP, S11);
  180. m_hsm.SetStateHandler(AZ_HSM_STATE_NAME(S11), HSM::StateHandler(this, &HSMTest::s11Hndlr), S1);
  181. m_hsm.SetStateHandler(AZ_HSM_STATE_NAME(S2), HSM::StateHandler(this, &HSMTest::s2Hndlr), TOP, S21);
  182. m_hsm.SetStateHandler(AZ_HSM_STATE_NAME(S21), HSM::StateHandler(this, &HSMTest::s21Hndlr), S2, S211);
  183. m_hsm.SetStateHandler(AZ_HSM_STATE_NAME(S211), HSM::StateHandler(this, &HSMTest::s211Hndlr), S21);
  184. result.clear();
  185. bool processed;
  186. m_hsm.Start();
  187. AZ_TEST_ASSERT(result == "top-ENTRY;s1-ENTRY;s11-ENTRY;");
  188. result.clear();
  189. processed = m_hsm.Dispatch(A_SIG);
  190. AZ_TEST_ASSERT(processed == true);
  191. AZ_TEST_ASSERT(result == "s1-A;s11-EXIT;s1-EXIT;s1-ENTRY;s11-ENTRY;");
  192. result.clear();
  193. processed = m_hsm.Dispatch(E_SIG);
  194. AZ_TEST_ASSERT(processed == true);
  195. AZ_TEST_ASSERT(result == "top-E;s11-EXIT;s1-EXIT;s2-ENTRY;s21-ENTRY;s211-ENTRY;");
  196. result.clear();
  197. processed = m_hsm.Dispatch(E_SIG);
  198. AZ_TEST_ASSERT(processed == true);
  199. AZ_TEST_ASSERT(result == "top-E;s211-EXIT;s21-EXIT;s2-EXIT;s2-ENTRY;s21-ENTRY;s211-ENTRY;");
  200. result.clear();
  201. processed = m_hsm.Dispatch(A_SIG);
  202. AZ_TEST_ASSERT(processed == false);
  203. AZ_TEST_ASSERT(result == "");
  204. result.clear();
  205. processed = m_hsm.Dispatch(H_SIG);
  206. AZ_TEST_ASSERT(processed == true);
  207. AZ_TEST_ASSERT(result == "s21-H;s211-EXIT;s21-EXIT;s21-ENTRY;s211-ENTRY;");
  208. result.clear();
  209. processed = m_hsm.Dispatch(H_SIG);
  210. AZ_TEST_ASSERT(processed == false);
  211. AZ_TEST_ASSERT(result == "");
  212. }
  213. };
  214. TEST_F(HSMTest, Test)
  215. {
  216. run();
  217. }
  218. }