ScriptCanvasTestUtilities.cpp 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748
  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 <Asset/EditorAssetSystemComponent.h>
  9. #include <AzCore/Asset/AssetManagerBus.h>
  10. #include <AzCore/Component/TickBus.h>
  11. #include <AzCore/IO/FileIO.h>
  12. #include <AzCore/IO/IOUtils.h>
  13. #include <AzCore/UnitTest/UnitTest.h>
  14. #include <AzFramework/API/ApplicationAPI.h>
  15. #include <Editor/Framework/ScriptCanvasGraphUtilities.h>
  16. #include <Editor/Framework/ScriptCanvasTraceUtilities.h>
  17. #include <Framework/ScriptCanvasTestNodes.h>
  18. #include <Framework/ScriptCanvasTestUtilities.h>
  19. #include <ScriptCanvas/Asset/RuntimeAsset.h>
  20. #include <ScriptCanvas/Asset/RuntimeAssetHandler.h>
  21. #include <ScriptCanvas/Execution/RuntimeComponent.h>
  22. #include <ScriptCanvas/Libraries/Core/Method.h>
  23. namespace ScriptCanvasTestUtilitiesCPP
  24. {
  25. const char* k_defaultExtension = "scriptcanvas";
  26. const char* k_scriptEventExtension = "scriptevents";
  27. const char* k_unitTestDirPathRelative = "@gemroot:ScriptCanvasTesting@/Assets/ScriptCanvas/UnitTests";
  28. }
  29. namespace ScriptCanvasTests
  30. {
  31. const char* GetUnitTestDirPathRelative()
  32. {
  33. return ScriptCanvasTestUtilitiesCPP::k_unitTestDirPathRelative;
  34. }
  35. void ExpectParse(AZStd::string_view graphPath)
  36. {
  37. using namespace ScriptCanvas;
  38. AZ_TEST_START_TRACE_SUPPRESSION;
  39. const AZStd::string filePath = AZStd::string::format("%s/%s.%s", ScriptCanvasTestUtilitiesCPP::k_unitTestDirPathRelative, graphPath.data(), ScriptCanvasTestUtilitiesCPP::k_defaultExtension);
  40. ScriptCanvasEditor::RunGraphSpec runGraphSpec;
  41. runGraphSpec.graphPath = filePath;
  42. runGraphSpec.dirPath = ScriptCanvasTestUtilitiesCPP::k_unitTestDirPathRelative;
  43. runGraphSpec.runSpec.processOnly = true;
  44. runGraphSpec.runSpec.execution = ExecutionMode::Interpreted;
  45. auto reporters = ScriptCanvasEditor::RunGraph(runGraphSpec);
  46. ScriptCanvasTests::VerifyReporter(reporters.front());
  47. AZ_TEST_STOP_TRACE_SUPPRESSION_NO_COUNT;
  48. }
  49. void ExpectParseError(AZStd::string_view graphPath)
  50. {
  51. using namespace ScriptCanvas;
  52. AZ_TEST_START_TRACE_SUPPRESSION;
  53. const AZStd::string filePath = AZStd::string::format("%s/%s.%s", ScriptCanvasTestUtilitiesCPP::k_unitTestDirPathRelative, graphPath.data(), ScriptCanvasTestUtilitiesCPP::k_defaultExtension);
  54. ScriptCanvasEditor::RunGraphSpec runGraphSpec;
  55. runGraphSpec.runSpec.processOnly = true;
  56. runGraphSpec.graphPath = filePath;
  57. runGraphSpec.dirPath = ScriptCanvasTestUtilitiesCPP::k_unitTestDirPathRelative;
  58. runGraphSpec.runSpec.execution = ExecutionMode::Interpreted;
  59. auto reporters = ScriptCanvasEditor::RunGraph(runGraphSpec);
  60. reporters.front().MarkExpectParseError();
  61. ScriptCanvasTests::VerifyReporter(reporters.front());
  62. AZ_TEST_STOP_TRACE_SUPPRESSION_NO_COUNT;
  63. }
  64. AZStd::string_view GetGraphNameFromPath(AZStd::string_view graphPath)
  65. {
  66. graphPath.remove_prefix(AZStd::min(graphPath.find_last_of("\\/") + 1, graphPath.size()));
  67. return graphPath;
  68. }
  69. void VerifyReporter(const ScriptCanvasEditor::Reporter& reporter)
  70. {
  71. using namespace ScriptCanvas;
  72. if (!reporter.IsGraphLoaded())
  73. {
  74. ADD_FAILURE() << "Graph was not successfully loaded.\n" << reporter.GetFilePath().c_str();
  75. }
  76. else if (reporter.ExpectsParseError())
  77. {
  78. if (!reporter.IsParseAttemptMade())
  79. {
  80. ADD_FAILURE() << "Expected a parse error but the graph never attempted to be parsed\n" << reporter.GetFilePath().c_str();
  81. }
  82. else if (reporter.IsCompiled())
  83. {
  84. ADD_FAILURE() << "Expected a parse error but graph compiled successfully\n" << reporter.GetFilePath().c_str();
  85. }
  86. }
  87. else if (!reporter.IsCompiled())
  88. {
  89. ADD_FAILURE() << "Graph failed to compile\n" << reporter.GetFilePath().c_str();
  90. }
  91. else if (reporter.IsReportFinished())
  92. {
  93. bool reportCheckpoints = false;
  94. if (!reporter.IsProcessOnly())
  95. {
  96. const auto& successes = reporter.GetSuccess();
  97. for (const auto& success : successes)
  98. {
  99. SUCCEED() << success.c_str();
  100. }
  101. if (!reporter.IsActivated())
  102. {
  103. ADD_FAILURE() << "Graph did not activate\n" << reporter.GetFilePath().c_str();
  104. }
  105. if (!reporter.IsDeactivated())
  106. {
  107. ADD_FAILURE() << "Graph did not deactivate\n" << reporter.GetFilePath().c_str();
  108. reportCheckpoints = true;
  109. }
  110. if (!reporter.ExpectsRuntimeFailure())
  111. {
  112. if (!reporter.IsComplete())
  113. {
  114. ADD_FAILURE() << "Graph was not marked complete\n" << reporter.GetFilePath().c_str();
  115. reportCheckpoints = true;
  116. }
  117. if (!reporter.IsErrorFree())
  118. {
  119. ADD_FAILURE() << "Graph execution had errors\n" << reporter.GetFilePath().c_str();
  120. reportCheckpoints = true;
  121. const auto& failures = reporter.GetFailure();
  122. for (const auto& failure : failures)
  123. {
  124. ADD_FAILURE() << failure.c_str();
  125. }
  126. }
  127. }
  128. else
  129. {
  130. if (reporter.IsErrorFree())
  131. {
  132. ADD_FAILURE() << "Graph expected error, but didn't report any\n" << reporter.GetFilePath().c_str();
  133. reportCheckpoints = true;
  134. }
  135. }
  136. }
  137. if (reportCheckpoints && !reporter.IsProcessOnly())
  138. {
  139. const auto& checkpoints = reporter.GetCheckpoints();
  140. if (checkpoints.empty())
  141. {
  142. ADD_FAILURE() << "No checkpoints or other unit test nodes found, using them can help parse graph test failures\n" << reporter.GetFilePath().c_str();
  143. }
  144. else
  145. {
  146. AZStd::string checkpointPath = "Checkpoint Path:\n";
  147. int i = 0;
  148. for (const auto& checkpoint : checkpoints)
  149. {
  150. checkpointPath += AZStd::string::format("%2d: %s\n", ++i, checkpoint.c_str()).c_str();
  151. }
  152. ADD_FAILURE() << checkpointPath.c_str();
  153. }
  154. }
  155. else
  156. {
  157. const Execution::PerformanceTrackingReport& performance = reporter.GetPerformanceReport();
  158. if (reporter.GetExecutionMode() == ExecutionMode::Interpreted)
  159. {
  160. std::cerr << "[INTERPRETED] ";
  161. }
  162. else
  163. {
  164. std::cerr << "[ NATIVE] ";
  165. }
  166. std::cerr << AZStd::string::format
  167. (" Parse: %4.2f ms, Translate: %4.2f ms\n"
  168. , reporter.GetParseDuration() / 1000.0
  169. , reporter.GetTranslateDuration() / 1000.0).c_str();
  170. double ready = aznumeric_caster(performance.timing.initializationTime);
  171. double instant = aznumeric_caster(performance.timing.executionTime);
  172. double latent = aznumeric_caster(performance.timing.latentTime);
  173. double total = aznumeric_caster(performance.timing.totalTime);
  174. std::cerr << "[ INITIALIZE] " << AZStd::string::format("%7.3f ms \n", ready / 1000.0).c_str();
  175. std::cerr << "[ EXECUTION] " << AZStd::string::format("%7.3f ms \n", instant / 1000.0).c_str();
  176. std::cerr << "[ LATENT] " << AZStd::string::format("%7.3f ms \n", latent / 1000.0).c_str();
  177. std::cerr << "[ TOTAL] " << AZStd::string::format("%7.3f ms ", total / 1000.0).c_str();
  178. switch (reporter.GetExecutionConfiguration())
  179. {
  180. case ScriptCanvasEditor::ExecutionConfiguration::Debug:
  181. std::cerr << "[ DEBUG] ";
  182. break;
  183. case ScriptCanvasEditor::ExecutionConfiguration::Performance:
  184. std::cerr << "[PERFORM] ";
  185. break;
  186. case ScriptCanvasEditor::ExecutionConfiguration::Release:
  187. std::cerr << "[RELEASE] ";
  188. break;
  189. case ScriptCanvasEditor::ExecutionConfiguration::Traced:
  190. std::cerr << "[ TRACED] ";
  191. break;
  192. }
  193. std::cerr << "\n";
  194. }
  195. }
  196. else
  197. {
  198. ADD_FAILURE() << "Graph report did not finish\n" << reporter.GetFilePath().c_str();
  199. }
  200. }
  201. void RunUnitTestGraph(AZStd::string_view graphPath)
  202. {
  203. ScriptCanvasTests::RunUnitTestGraph(graphPath, ScriptCanvasEditor::RunSpec());
  204. }
  205. void RunUnitTestGraph(AZStd::string_view graphPath, ScriptCanvas::ExecutionMode execution)
  206. {
  207. ScriptCanvasEditor::RunSpec spec;
  208. spec.execution = execution;
  209. ScriptCanvasTests::RunUnitTestGraph(graphPath, spec);
  210. }
  211. void RunUnitTestGraph(AZStd::string_view graphPath, ScriptCanvas::ExecutionMode execution, const ScriptCanvasEditor::DurationSpec& duration)
  212. {
  213. ScriptCanvasEditor::RunSpec runSpec;
  214. runSpec.execution = execution;
  215. runSpec.duration = duration;
  216. RunUnitTestGraph(graphPath, runSpec);
  217. }
  218. void RunUnitTestGraph(AZStd::string_view graphPath, ScriptCanvas::ExecutionMode execution, AZStd::string_view dependentScriptEvent)
  219. {
  220. AZ::Data::AssetType assetType(azrtti_typeid<ScriptEvents::ScriptEventsAsset>());
  221. if (auto scriptEventAssetHandler = AZ::Data::AssetManager::Instance().GetHandler(assetType))
  222. {
  223. const AZStd::string fullPath = AZStd::string::format("%s/%s.%s", ScriptCanvasTestUtilitiesCPP::k_unitTestDirPathRelative, dependentScriptEvent.data(), ScriptCanvasTestUtilitiesCPP::k_scriptEventExtension);
  224. // Preload dependent scriptevent asset for testing
  225. AZStd::shared_ptr<AZ::Data::AssetDataStream> assetDataStream = AZStd::make_shared<AZ::Data::AssetDataStream>();
  226. // Read in the data from a file to a buffer, then hand ownership of the buffer over to the assetDataStream
  227. {
  228. AZ::IO::FileIOStream stream(fullPath.c_str(), AZ::IO::OpenMode::ModeRead);
  229. if (!AZ::IO::RetryOpenStream(stream))
  230. {
  231. ADD_FAILURE() << AZStd::string::format("CreateJobs for \"%s\" failed because the source file could not be opened.", fullPath.c_str()).data();
  232. return;
  233. }
  234. AZStd::vector<AZ::u8> fileBuffer(stream.GetLength());
  235. size_t bytesRead = stream.Read(fileBuffer.size(), fileBuffer.data());
  236. if (bytesRead != stream.GetLength())
  237. {
  238. ADD_FAILURE() << AZStd::string::format("CreateJobs for \"%s\" failed because the source file could not be read.", fullPath.c_str()).data();
  239. return;
  240. }
  241. assetDataStream->Open(AZStd::move(fileBuffer));
  242. }
  243. AZ::Data::Asset<ScriptEvents::ScriptEventsAsset> asset;
  244. const AZStd::string hintPath = AZStd::string::format("scriptcanvas/unittests/%s.%s", dependentScriptEvent.data(), ScriptCanvasTestUtilitiesCPP::k_scriptEventExtension);
  245. asset.Create(AZ::Data::AssetId(AZ::Uuid::CreateName(hintPath.data())));
  246. if (scriptEventAssetHandler->LoadAssetDataFromStream(asset, assetDataStream, nullptr) != AZ::Data::AssetHandler::LoadResult::LoadComplete)
  247. {
  248. ADD_FAILURE() << AZStd::string::format("Failed to load ScriptEvent asset: %s", fullPath.data()).data();
  249. return;
  250. }
  251. scriptEventAssetHandler->InitAsset(asset, true, false);
  252. ScriptCanvasEditor::RunSpec spec;
  253. spec.execution = execution;
  254. ScriptCanvasTests::RunUnitTestGraph(graphPath, spec);
  255. }
  256. else
  257. {
  258. ADD_FAILURE() << "ScriptEvent asset handler is missing.";
  259. }
  260. }
  261. void RunUnitTestGraph(AZStd::string_view graphPath, const ScriptCanvasEditor::DurationSpec& duration)
  262. {
  263. ScriptCanvasEditor::RunSpec spec;
  264. spec.duration = duration;
  265. ScriptCanvasTests::RunUnitTestGraph(graphPath, ScriptCanvas::ExecutionMode::Interpreted, duration);
  266. }
  267. void RunUnitTestGraph(AZStd::string_view graphPath, const ScriptCanvasEditor::RunSpec& runSpec)
  268. {
  269. const AZStd::string filePath = AZStd::string::format("%s/%s.%s", ScriptCanvasTestUtilitiesCPP::k_unitTestDirPathRelative, graphPath.data(), ScriptCanvasTestUtilitiesCPP::k_defaultExtension);
  270. ScriptCanvasEditor::RunGraphSpec runGraphSpec;
  271. runGraphSpec.graphPath = filePath;
  272. runGraphSpec.dirPath = ScriptCanvasTestUtilitiesCPP::k_unitTestDirPathRelative;
  273. runGraphSpec.runSpec = runSpec;
  274. AZ_TEST_START_TRACE_SUPPRESSION;
  275. const ScriptCanvasEditor::Reporters reporters = ScriptCanvasEditor::RunGraph(runGraphSpec);
  276. for (const auto& reporter : reporters)
  277. {
  278. ScriptCanvasTests::VerifyReporter(reporter);
  279. }
  280. if (reporters.size() == 2)
  281. {
  282. EXPECT_EQ(reporters.front(), reporters.back());
  283. }
  284. else if (reporters.size() > 2)
  285. {
  286. for (size_t lhs(0), rhs(1); rhs != reporters.size(); ++lhs, ++rhs)
  287. {
  288. EXPECT_EQ(reporters[lhs], reporters[rhs]);
  289. }
  290. }
  291. AZ_TEST_STOP_TRACE_SUPPRESSION_NO_COUNT;
  292. }
  293. void RunUnitTestGraphMixed(AZStd::string_view graphPath, const ScriptCanvasEditor::DurationSpec& duration)
  294. {
  295. using namespace ScriptCanvas;
  296. AZ_TEST_START_TRACE_SUPPRESSION;
  297. ScriptCanvasEditor::RunGraphSpec runGraphSpec;
  298. runGraphSpec.graphPath = graphPath;
  299. runGraphSpec.dirPath = ScriptCanvasTestUtilitiesCPP::k_unitTestDirPathRelative;
  300. runGraphSpec.runSpec.duration = duration;
  301. runGraphSpec.runSpec.execution = ExecutionMode::Interpreted;
  302. const ScriptCanvasEditor::Reporter reporterIterpreted0 = RunGraph(runGraphSpec).front();
  303. runGraphSpec.runSpec.execution = ExecutionMode::Native;
  304. const ScriptCanvasEditor::Reporter reporterNative0 = RunGraph(runGraphSpec).front();
  305. runGraphSpec.runSpec.execution = ExecutionMode::Interpreted;
  306. const ScriptCanvasEditor::Reporter reporterIterpreted1 = RunGraph(runGraphSpec).front();
  307. runGraphSpec.runSpec.execution = ExecutionMode::Native;
  308. const ScriptCanvasEditor::Reporter reporterNative1 = RunGraph(runGraphSpec).front();
  309. VerifyReporter(reporterIterpreted0);
  310. VerifyReporter(reporterNative0);
  311. EXPECT_TRUE(reporterIterpreted0.IsActivated());
  312. EXPECT_TRUE(reporterIterpreted1.IsComplete());
  313. EXPECT_TRUE(reporterIterpreted0.IsErrorFree());
  314. EXPECT_EQ(reporterNative0, reporterIterpreted0);
  315. EXPECT_EQ(reporterNative0, reporterIterpreted1);
  316. EXPECT_EQ(reporterNative1, reporterIterpreted0);
  317. EXPECT_EQ(reporterNative1, reporterIterpreted1);
  318. EXPECT_EQ(reporterNative0, reporterNative1);
  319. EXPECT_EQ(reporterIterpreted0, reporterIterpreted1);
  320. AZ_TEST_STOP_TRACE_SUPPRESSION_NO_COUNT;
  321. }
  322. void RunUnitTestGraphMixed(AZStd::string_view graphPath)
  323. {
  324. RunUnitTestGraphMixed(graphPath, ScriptCanvasEditor::DurationSpec());
  325. }
  326. TestBehaviorContextObject TestBehaviorContextObject::MaxReturnByValue(TestBehaviorContextObject lhs, TestBehaviorContextObject rhs)
  327. {
  328. return lhs.GetValue() >= rhs.GetValue() ? lhs : rhs;
  329. }
  330. const TestBehaviorContextObject* TestBehaviorContextObject::MaxReturnByPointer(const TestBehaviorContextObject* lhs, const TestBehaviorContextObject* rhs)
  331. {
  332. return (lhs && rhs && lhs->GetValue() >= rhs->GetValue()) ? lhs : rhs;
  333. }
  334. const TestBehaviorContextObject& TestBehaviorContextObject::MaxReturnByReference(const TestBehaviorContextObject& lhs, const TestBehaviorContextObject& rhs)
  335. {
  336. return lhs.GetValue() >= rhs.GetValue() ? lhs : rhs;
  337. }
  338. int TestBehaviorContextObject::MaxReturnByValueInteger(int lhs, int rhs)
  339. {
  340. return lhs >= rhs ? lhs : rhs;
  341. }
  342. const int* TestBehaviorContextObject::MaxReturnByPointerInteger(const int* lhs, const int* rhs)
  343. {
  344. return (lhs && rhs && (*lhs) >= (*rhs)) ? lhs : rhs;
  345. }
  346. const int& TestBehaviorContextObject::MaxReturnByReferenceInteger(const int& lhs, const int& rhs)
  347. {
  348. return lhs >= rhs ? lhs : rhs;
  349. }
  350. static void TestBehaviorContextObjectGenericConstructor(TestBehaviorContextObject* thisPtr)
  351. {
  352. new (thisPtr) TestBehaviorContextObject();
  353. thisPtr->SetValue(0);
  354. }
  355. void TestBehaviorContextObject::Reflect(AZ::ReflectContext* reflectContext)
  356. {
  357. if (AZ::SerializeContext* serializeContext = azrtti_cast<AZ::SerializeContext*>(reflectContext))
  358. {
  359. serializeContext->Class<TestBehaviorContextObject>()
  360. ->Version(0)
  361. ->Field("m_value", &TestBehaviorContextObject::m_value)
  362. ->Field("isNormalized", &TestBehaviorContextObject::m_isNormalized)
  363. ;
  364. }
  365. if (AZ::BehaviorContext* behaviorContext = azrtti_cast<AZ::BehaviorContext*>(reflectContext))
  366. {
  367. behaviorContext->Class<TestBehaviorContextObject>("TestBehaviorContextObject")
  368. ->Attribute(AZ::Script::Attributes::ConstructorOverride, &TestBehaviorContextObjectGenericConstructor)
  369. ->Attribute(AZ::Script::Attributes::GenericConstructorOverride, &TestBehaviorContextObjectGenericConstructor)
  370. ->Method("In", &TestBehaviorContextObject::GetValue)
  371. ->Method("Out", &TestBehaviorContextObject::SetValue)
  372. ->Method("Normalize", &TestBehaviorContextObject::Normalize)
  373. ->Method("IsNormalized", &TestBehaviorContextObject::IsNormalized)
  374. ->Method("Denormalize", &TestBehaviorContextObject::Denormalize)
  375. ->Method("MaxReturnByValue", &TestBehaviorContextObject::MaxReturnByValue)
  376. ->Method("MaxReturnByPointer", &TestBehaviorContextObject::MaxReturnByPointer)
  377. ->Method("MaxReturnByReference", &TestBehaviorContextObject::MaxReturnByReference)
  378. ->Method("MaxReturnByValueInteger", &TestBehaviorContextObject::MaxReturnByValueInteger)
  379. ->Method("MaxReturnByPointerInteger", &TestBehaviorContextObject::MaxReturnByPointerInteger)
  380. ->Method("MaxReturnByReferenceInteger", &TestBehaviorContextObject::MaxReturnByReferenceInteger)
  381. ->Method<bool (TestBehaviorContextObject::*)(const TestBehaviorContextObject&) const>("LessThan", &TestBehaviorContextObject::operator<)
  382. ->Attribute(AZ::Script::Attributes::Operator, AZ::Script::Attributes::OperatorType::LessThan)
  383. ->Method<bool (TestBehaviorContextObject::*)(const TestBehaviorContextObject&) const>("LessEqualThan", &TestBehaviorContextObject::operator<=)
  384. ->Attribute(AZ::Script::Attributes::Operator, AZ::Script::Attributes::OperatorType::LessEqualThan)
  385. ->Method<bool (TestBehaviorContextObject::*)(const TestBehaviorContextObject&) const>("Equal", &TestBehaviorContextObject::operator==)
  386. ->Attribute(AZ::Script::Attributes::Operator, AZ::Script::Attributes::OperatorType::Equal)
  387. ;
  388. }
  389. }
  390. TestBehaviorContextObject MaxReturnByValue(TestBehaviorContextObject lhs, TestBehaviorContextObject rhs)
  391. {
  392. return lhs.GetValue() >= rhs.GetValue() ? lhs : rhs;
  393. }
  394. const TestBehaviorContextObject* MaxReturnByPointer(const TestBehaviorContextObject* lhs, const TestBehaviorContextObject* rhs)
  395. {
  396. return (lhs && rhs && (lhs->GetValue() >= rhs->GetValue())) ? lhs : rhs;
  397. }
  398. const TestBehaviorContextObject& MaxReturnByReference(const TestBehaviorContextObject& lhs, const TestBehaviorContextObject& rhs)
  399. {
  400. return lhs.GetValue() >= rhs.GetValue() ? lhs : rhs;
  401. }
  402. AZ::u32 TestBehaviorContextObject::s_createdCount = 0;
  403. AZ::u32 TestBehaviorContextObject::s_destroyedCount = 0;
  404. AZ::EntityId CreateClassFunctionNode(const ScriptCanvas::ScriptCanvasId& scriptCanvasId, AZStd::string_view className, AZStd::string_view methodName)
  405. {
  406. using namespace ScriptCanvas;
  407. ScriptCanvas::NamespacePath emptyNamespaces;
  408. AZ::Entity* splitEntity{ aznew AZ::Entity };
  409. splitEntity->Init();
  410. AZ::EntityId methodNodeID{ splitEntity->GetId() };
  411. SystemRequestBus::Broadcast(&SystemRequests::CreateNodeOnEntity, methodNodeID, scriptCanvasId, ScriptCanvas::Nodes::Core::Method::RTTI_Type());
  412. ScriptCanvas::Nodes::Core::Method* methodNode(nullptr);
  413. SystemRequestBus::BroadcastResult(methodNode, &SystemRequests::GetNode<ScriptCanvas::Nodes::Core::Method>, methodNodeID);
  414. EXPECT_TRUE(methodNode != nullptr);
  415. methodNode->InitializeBehaviorMethod(emptyNamespaces, className, methodName, ScriptCanvas::PropertyStatus::None);
  416. return methodNodeID;
  417. }
  418. AZStd::string SlotDescriptorToString(ScriptCanvas::SlotDescriptor descriptor)
  419. {
  420. using namespace ScriptCanvas;
  421. AZStd::string name;
  422. switch (descriptor.m_slotType)
  423. {
  424. case SlotTypeDescriptor::Data:
  425. name.append("Data");
  426. break;
  427. case SlotTypeDescriptor::Execution:
  428. name.append("Execution");
  429. break;
  430. default:
  431. break;
  432. }
  433. switch (descriptor.m_connectionType)
  434. {
  435. case ConnectionType::Input:
  436. name.append("In");
  437. break;
  438. case ConnectionType::Output:
  439. name.append("Out");
  440. break;
  441. default:
  442. break;
  443. }
  444. return name;
  445. }
  446. void DumpSlots([[maybe_unused]] const ScriptCanvas::Node& node)
  447. {
  448. #if defined(AZ_ENABLE_TRACING)
  449. const auto& nodeslots = node.GetSlots();
  450. for (const auto& nodeslot : nodeslots)
  451. {
  452. AZ_TracePrintf("ScriptCanvasTest", "'%s':%s\n", nodeslot.GetName().data(), SlotDescriptorToString(nodeslot.GetDescriptor()).c_str());
  453. }
  454. #endif
  455. }
  456. bool Connect(ScriptCanvas::Graph& graph, const AZ::EntityId& fromNodeID, const char* fromSlotName, const AZ::EntityId& toNodeID, const char* toSlotName, bool dumpSlotsOnFailure /*= true*/)
  457. {
  458. using namespace ScriptCanvas;
  459. AZ::Entity* fromNode{};
  460. AZ::ComponentApplicationBus::BroadcastResult(fromNode, &AZ::ComponentApplicationBus::Events::FindEntity, fromNodeID);
  461. AZ::Entity* toNode{};
  462. AZ::ComponentApplicationBus::BroadcastResult(toNode, &AZ::ComponentApplicationBus::Events::FindEntity, toNodeID);
  463. if (fromNode && toNode)
  464. {
  465. Node* from = AZ::EntityUtils::FindFirstDerivedComponent<Node>(fromNode);
  466. Node* to = AZ::EntityUtils::FindFirstDerivedComponent<Node>(toNode);
  467. auto fromSlotId = from->GetSlotId(fromSlotName);
  468. auto toSlotId = to->GetSlotId(toSlotName);
  469. if (graph.Connect(fromNodeID, fromSlotId, toNodeID, toSlotId))
  470. {
  471. return true;
  472. }
  473. else if (dumpSlotsOnFailure)
  474. {
  475. AZ_TracePrintf("ScriptCanvasTest", "Slots from:\n");
  476. DumpSlots(*from);
  477. AZ_TracePrintf("ScriptCanvasTest", "\nSlots to:\n");
  478. DumpSlots(*to);
  479. }
  480. }
  481. return false;
  482. }
  483. AZ::Entity* UnitTestEntityContext::CreateEntity(const char* name)
  484. {
  485. auto entity = aznew AZ::Entity(name);
  486. AddEntity(entity);
  487. return entity;
  488. }
  489. void UnitTestEntityContext::AddEntity(AZ::Entity* entity)
  490. {
  491. AddEntity(entity->GetId());
  492. }
  493. void UnitTestEntityContext::AddEntity(AZ::EntityId entityId)
  494. {
  495. AZ_Assert(!AzFramework::EntityIdContextQueryBus::FindFirstHandler(entityId), "Entity already belongs to a context.");
  496. m_unitTestEntityIdMap.emplace(entityId, entityId);
  497. AzFramework::EntityIdContextQueryBus::MultiHandler::BusConnect(entityId);
  498. }
  499. void UnitTestEntityContext::RemoveEntity(AZ::EntityId entityId)
  500. {
  501. auto foundIt = m_unitTestEntityIdMap.find(entityId);
  502. if (foundIt != m_unitTestEntityIdMap.end())
  503. {
  504. AzFramework::EntityIdContextQueryBus::MultiHandler::BusDisconnect(entityId);
  505. m_unitTestEntityIdMap.erase(foundIt);
  506. }
  507. }
  508. void UnitTestEntityContext::ActivateEntity(AZ::EntityId entityId)
  509. {
  510. if (IsOwnedByThisContext(entityId))
  511. {
  512. AZ::Entity* entity{};
  513. AZ::ComponentApplicationBus::BroadcastResult(entity, &AZ::ComponentApplicationRequests::FindEntity, entityId);
  514. if (entity)
  515. {
  516. if (entity->GetState() == AZ::Entity::State::Constructed)
  517. {
  518. entity->Init();
  519. }
  520. if (entity->GetState() == AZ::Entity::State::Init)
  521. {
  522. entity->Activate();
  523. }
  524. }
  525. }
  526. }
  527. void UnitTestEntityContext::DeactivateEntity(AZ::EntityId entityId)
  528. {
  529. if (IsOwnedByThisContext(entityId))
  530. {
  531. AZ::Entity* entity{};
  532. AZ::ComponentApplicationBus::BroadcastResult(entity, &AZ::ComponentApplicationRequests::FindEntity, entityId);
  533. if (entity)
  534. {
  535. if (entity->GetState() == AZ::Entity::State::Active)
  536. {
  537. entity->Deactivate();
  538. }
  539. else if (entity->GetState() == AZ::Entity::State::Activating)
  540. {
  541. // Queue Deactivation to next frame
  542. AZ::SystemTickBus::QueueFunction(&AZ::Entity::Activate, entity);
  543. }
  544. }
  545. }
  546. }
  547. bool UnitTestEntityContext::DestroyEntity(AZ::Entity* entity)
  548. {
  549. if (entity)
  550. {
  551. auto foundIt = m_unitTestEntityIdMap.find(entity->GetId());
  552. if (foundIt != m_unitTestEntityIdMap.end())
  553. {
  554. AzFramework::EntityIdContextQueryBus::MultiHandler::BusDisconnect(entity->GetId());
  555. m_unitTestEntityIdMap.erase(foundIt);
  556. delete entity;
  557. return true;
  558. }
  559. }
  560. return false;
  561. }
  562. bool UnitTestEntityContext::DestroyEntityById(AZ::EntityId entityId)
  563. {
  564. AZ::Entity* entity{};
  565. AZ::ComponentApplicationBus::BroadcastResult(entity, &AZ::ComponentApplicationRequests::FindEntity, entityId);
  566. return DestroyEntity(entity);
  567. }
  568. void UnitTestEntityContext::ResetContext()
  569. {
  570. AzFramework::EntityIdContextQueryBus::MultiHandler::BusDisconnect();
  571. m_unitTestEntityIdMap.clear();
  572. }
  573. AZ::EntityId UnitTestEntityContext::FindLoadedEntityIdMapping(const AZ::EntityId& staticId) const
  574. {
  575. auto idIter = m_unitTestEntityIdMap.find(staticId);
  576. if (idIter != m_unitTestEntityIdMap.end())
  577. {
  578. return idIter->second;
  579. }
  580. return AZ::EntityId();
  581. }
  582. AZ::Entity* UnitTestEntityContext::CloneEntity(const AZ::Entity& sourceEntity)
  583. {
  584. if (!IsOwnedByThisContext(sourceEntity.GetId()))
  585. {
  586. AZ_Warning("Script Canvas", false, "Entity %s does not belong to the unit test entity context.", sourceEntity.GetName().data());
  587. return {};
  588. }
  589. AZ::SerializeContext* serializeContext{};
  590. AZ::ComponentApplicationBus::BroadcastResult(serializeContext, &AZ::ComponentApplicationRequests::GetSerializeContext);
  591. AZ::Entity* cloneEntity = serializeContext->CloneObject(&sourceEntity);
  592. if (cloneEntity)
  593. {
  594. cloneEntity->SetId(AZ::Entity::MakeId());
  595. AddEntity(cloneEntity);
  596. }
  597. return cloneEntity;
  598. }
  599. //AZ::Data::AssetId UnitTestEntityContext::CurrentlyInstantiatingSlice()
  600. //{
  601. // return AZ::Data::AssetId();
  602. //}
  603. //bool UnitTestEntityContext::HandleRootEntityReloadedFromStream(AZ::Entity*, bool, AZ::SliceComponent::EntityIdToEntityIdMap*)
  604. //{
  605. // return true;
  606. //}
  607. //AZ::SliceComponent* UnitTestEntityContext::GetRootSlice()
  608. //{
  609. // return {};
  610. //}
  611. //const AZStd::unordered_map<AZ::EntityId, AZ::EntityId>& UnitTestEntityContext::GetLoadedEntityIdMap()
  612. //{
  613. // return m_unitTestEntityIdMap;
  614. //}
  615. //AzFramework::SliceInstantiationTicket UnitTestEntityContext::InstantiateSlice(const AZ::Data::Asset<AZ::Data::AssetData>&,
  616. // const AZ::IdUtils::Remapper<AZ::EntityId>::IdMapper&, const AZ::Data::AssetFilterCB&)
  617. //{
  618. // return AzFramework::SliceInstantiationTicket();
  619. //}
  620. //AZ::SliceComponent::SliceInstanceAddress UnitTestEntityContext::CloneSliceInstance(
  621. // AZ::SliceComponent::SliceInstanceAddress, AZ::SliceComponent::EntityIdToEntityIdMap&)
  622. //{
  623. // return AZ::SliceComponent::SliceInstanceAddress();
  624. //}
  625. //void UnitTestEntityContext::CancelSliceInstantiation(const AzFramework::SliceInstantiationTicket&)
  626. //{
  627. //}
  628. //AzFramework::SliceInstantiationTicket UnitTestEntityContext::GenerateSliceInstantiationTicket()
  629. //{
  630. // return AzFramework::SliceInstantiationTicket();
  631. //}
  632. //void UnitTestEntityContext::SetIsDynamic(bool)
  633. //{
  634. //}
  635. //const AzFramework::RootSliceAsset& UnitTestEntityContext::GetRootAsset() const
  636. //{
  637. // return m_unitTestRootAsset;
  638. //}
  639. } // ScriptCanvasTests