EditorAutomationTest.cpp 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352
  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 <ScriptCanvasDeveloperEditor/EditorAutomation/EditorAutomationTest.h>
  9. namespace ScriptCanvas::Developer
  10. {
  11. /////////////////////////////////
  12. // EditorAutomationActionRunner
  13. /////////////////////////////////
  14. EditorAutomationActionRunner::~EditorAutomationActionRunner()
  15. {
  16. Reset();
  17. }
  18. void EditorAutomationActionRunner::Reset()
  19. {
  20. for (EditorAutomationAction* deleteAction : m_actionsToDelete)
  21. {
  22. delete deleteAction;
  23. }
  24. m_actionsToDelete.clear();
  25. while (!m_executionStack.empty())
  26. {
  27. m_executionStack.erase(m_executionStack.begin());
  28. }
  29. m_errorReports.clear();
  30. m_currentAction = nullptr;
  31. }
  32. bool EditorAutomationActionRunner::Tick()
  33. {
  34. if (m_currentAction == nullptr)
  35. {
  36. if (m_executionStack.empty())
  37. {
  38. return true;
  39. }
  40. else
  41. {
  42. m_currentAction = m_executionStack.front();
  43. while (m_currentAction->IsMissingPrecondition())
  44. {
  45. if (m_currentAction->IsAtPreconditionLimit())
  46. {
  47. ActionReport failureReport;
  48. failureReport = AZ::Failure<AZStd::string>("Action failed to setup its preconditions in a reasonable amount of iterations. Exiting test.");
  49. m_errorReports.emplace_back(failureReport);
  50. m_currentAction->ResetPreconditionAttempts();
  51. // Leak elements, then we'll just exit through normal paths next tick.
  52. m_executionStack.clear();
  53. return false;
  54. }
  55. else
  56. {
  57. EditorAutomationAction* newAction = m_currentAction->GenerationPreconditionActions();
  58. m_actionsToDelete.emplace(newAction);
  59. if (newAction)
  60. {
  61. m_currentAction = newAction;
  62. m_executionStack.insert(m_executionStack.begin(), newAction);
  63. }
  64. }
  65. }
  66. // Erase our current front of stack, as that is our current action.
  67. m_executionStack.erase(m_executionStack.begin());
  68. AZ_Assert(m_currentAction, "Current Action should not be null at this point.");
  69. if (m_currentAction == nullptr)
  70. {
  71. // Leak all the memory. We'll just exit through the normal path next tick.
  72. m_executionStack.clear();
  73. return true;
  74. }
  75. else
  76. {
  77. m_currentAction->SignalActionBegin();
  78. }
  79. }
  80. }
  81. if (m_currentAction)
  82. {
  83. if (m_currentAction->Tick())
  84. {
  85. ActionReport errorReport = m_currentAction->GenerateReport();
  86. if (!errorReport.IsSuccess())
  87. {
  88. m_errorReports.emplace_back(errorReport);
  89. }
  90. m_currentAction = nullptr;
  91. }
  92. }
  93. return false;
  94. }
  95. void EditorAutomationActionRunner::AddAction(EditorAutomationAction* actionToRun)
  96. {
  97. m_executionStack.emplace_back(actionToRun);
  98. }
  99. bool EditorAutomationActionRunner::HasActions() const
  100. {
  101. return !m_executionStack.empty();
  102. }
  103. bool EditorAutomationActionRunner::HasErrors() const
  104. {
  105. return !m_errorReports.empty();
  106. }
  107. const AZStd::vector< ActionReport >& EditorAutomationActionRunner::GetErrors() const
  108. {
  109. return m_errorReports;
  110. }
  111. ///////////////
  112. // StateModel
  113. ///////////////
  114. const AZStd::any* StateModel::FindStateData(const DataKey& dataId) const
  115. {
  116. auto dataIter = m_stateData.find(dataId);
  117. if (dataIter != m_stateData.end())
  118. {
  119. return &dataIter->second;
  120. }
  121. return nullptr;
  122. }
  123. void StateModel::ClearModelData()
  124. {
  125. m_stateData.clear();
  126. }
  127. /////////////////////////
  128. // EditorAutomationTest
  129. /////////////////////////
  130. EditorAutomationTest::EditorAutomationTest(QString testName)
  131. : m_testName(testName)
  132. {
  133. }
  134. EditorAutomationTest::~EditorAutomationTest()
  135. {
  136. for (const auto& statePair : m_states)
  137. {
  138. delete statePair.second;
  139. }
  140. m_states.clear();
  141. }
  142. void EditorAutomationTest::StartTest()
  143. {
  144. m_hasRun = true;
  145. m_testErrors.clear();
  146. OnTestStarting();
  147. m_stateId = m_initialStateId;
  148. m_actionRunner.Reset();
  149. if (SetupState(m_stateId))
  150. {
  151. AZ::SystemTickBus::Handler::BusConnect();
  152. }
  153. else
  154. {
  155. OnTestComplete();
  156. }
  157. }
  158. void EditorAutomationTest::OnSystemTick()
  159. {
  160. if (m_actionRunner.Tick())
  161. {
  162. if (!HasErrors())
  163. {
  164. if (m_actionRunner.HasErrors())
  165. {
  166. const AZStd::vector<ActionReport>& actionErrors = m_actionRunner.GetErrors();
  167. for (const ActionReport& actionErrorReport : actionErrors)
  168. {
  169. AddError(actionErrorReport.GetError());
  170. }
  171. }
  172. else
  173. {
  174. m_currentState->StateActionsComplete();
  175. if (m_currentState->HasErrors())
  176. {
  177. AddError(m_currentState->GetError());
  178. }
  179. m_currentState = nullptr;
  180. }
  181. //++m_state;
  182. m_actionRunner.Reset();
  183. if (!HasErrors())
  184. {
  185. OnStateComplete(m_stateId);
  186. int nextStateId = FindNextState(m_stateId);
  187. if (!SetupState(nextStateId))
  188. {
  189. AZ::SystemTickBus::Handler::BusDisconnect();
  190. OnTestComplete();
  191. }
  192. }
  193. else
  194. {
  195. AZ::SystemTickBus::Handler::BusDisconnect();
  196. OnTestComplete();
  197. }
  198. }
  199. else
  200. {
  201. AZ::SystemTickBus::Handler::BusDisconnect();
  202. OnTestComplete();
  203. }
  204. }
  205. }
  206. void EditorAutomationTest::AddState(EditorAutomationState* newState)
  207. {
  208. int stateId = newState->GetStateId();
  209. if (stateId == EditorAutomationState::EXIT_STATE_ID)
  210. {
  211. AZ_Error("EditorAutomationTest", false, "Trying to use reserved exit state id");
  212. delete newState;
  213. return;
  214. }
  215. auto stateIter = m_states.find(stateId);
  216. if (stateIter != m_states.end())
  217. {
  218. AZ_Error("EditorAutomationTest", false, "Collision on StateId %i found. Maintaining first state with id", stateId);
  219. delete newState;
  220. return;
  221. }
  222. m_registrationOrder.emplace_back(stateId);
  223. m_states[stateId] = newState;
  224. newState->SetStateModel(this);
  225. if (m_initialStateId == EditorAutomationState::EXIT_STATE_ID)
  226. {
  227. m_initialStateId = stateId;
  228. }
  229. }
  230. void EditorAutomationTest::SetHasCustomTransitions(bool hasCustomTransition)
  231. {
  232. m_hasCustomTransitions = hasCustomTransition;
  233. }
  234. bool EditorAutomationTest::HasRun() const
  235. {
  236. return m_hasRun;
  237. }
  238. bool EditorAutomationTest::IsRunning() const
  239. {
  240. return AZ::SystemTickBus::Handler::BusIsConnected();
  241. }
  242. bool EditorAutomationTest::SetupState(int stateId)
  243. {
  244. m_stateId = EditorAutomationState::EXIT_STATE_ID;
  245. m_currentState = nullptr;
  246. auto stateIter = m_states.find(stateId);
  247. if (stateIter != m_states.end())
  248. {
  249. m_currentState = stateIter->second;
  250. }
  251. if (m_currentState)
  252. {
  253. m_stateId = stateId;
  254. m_actionRunner.Reset();
  255. m_currentState->SetupStateActions(m_actionRunner);
  256. }
  257. return m_currentState != nullptr;
  258. }
  259. int EditorAutomationTest::FindNextState(int stateId)
  260. {
  261. int nextStateId = EditorAutomationState::EXIT_STATE_ID;
  262. if (m_hasCustomTransitions)
  263. {
  264. nextStateId = EvaluateTransition(stateId);
  265. }
  266. else
  267. {
  268. // Do a minus one here, so we can just blindly add 1 instead of needing to safety check it.
  269. // We default to EXIT so the result is the same.
  270. for (int i = 0; i < m_registrationOrder.size() - 1; ++i)
  271. {
  272. if (m_registrationOrder[i] == stateId)
  273. {
  274. nextStateId = m_registrationOrder[i + 1];
  275. }
  276. }
  277. }
  278. return nextStateId;
  279. }
  280. void EditorAutomationTest::AddError(AZStd::string error)
  281. {
  282. AZ_TracePrintf("EditorAutomationTestDialog", "Error in %s :: %s", m_testName.toUtf8().data(), error.c_str());
  283. m_testErrors.emplace_back(error);
  284. }
  285. }