ScriptCanvasTestFixture.h 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417
  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. #pragma once
  9. #include <AzCore/Asset/AssetManagerComponent.h>
  10. #include <AzCore/Component/ComponentApplicationBus.h>
  11. #include <AzCore/Driller/Driller.h>
  12. #include <AzCore/IO/FileIO.h>
  13. #include <AzCore/Memory/MemoryComponent.h>
  14. #include <AzCore/Memory/MemoryDriller.h>
  15. #include <AzCore/Serialization/EditContext.h>
  16. #include <AzCore/Serialization/SerializeContext.h>
  17. #include <AzCore/UnitTest/TestTypes.h>
  18. #include <AzCore/UserSettings/UserSettingsComponent.h>
  19. #include <AzCore/std/containers/vector.h>
  20. #include <AzFramework/IO/LocalFileIO.h>
  21. #include <AzTest/AzTest.h>
  22. #include <Nodes/BehaviorContextObjectTestNode.h>
  23. #include <Nodes/Nodeables/SharedDataSlotExample.h>
  24. #include <Nodes/Nodeables/ValuePointerReferenceExample.h>
  25. #include <ScriptCanvas/Core/Graph.h>
  26. #include <ScriptCanvas/Core/SlotConfigurationDefaults.h>
  27. #include <ScriptCanvas/ScriptCanvasGem.h>
  28. #include <ScriptCanvas/SystemComponent.h>
  29. #include "EntityRefTests.h"
  30. #include "ScriptCanvasTestApplication.h"
  31. #include "ScriptCanvasTestBus.h"
  32. #include "ScriptCanvasTestNodes.h"
  33. #include "ScriptCanvasTestUtilities.h"
  34. #define SC_EXPECT_DOUBLE_EQ(candidate, reference) EXPECT_NEAR(candidate, reference, 0.001)
  35. #define SC_EXPECT_FLOAT_EQ(candidate, reference) EXPECT_NEAR(candidate, reference, 0.001f)
  36. namespace ScriptCanvasTests
  37. {
  38. class ScriptCanvasTestFixture
  39. : public ::testing::Test
  40. //, protected NodeAccessor
  41. {
  42. public:
  43. static AZStd::atomic_bool s_asyncOperationActive;
  44. protected:
  45. static ScriptCanvasTests::Application* s_application;
  46. static void SetUpTestCase()
  47. {
  48. s_allocatorSetup.SetupAllocator();
  49. s_asyncOperationActive = false;
  50. if (s_application == nullptr)
  51. {
  52. AZ::ComponentApplication::StartupParameters appStartup;
  53. s_application = aznew ScriptCanvasTests::Application();
  54. {
  55. ScriptCanvasEditor::TraceSuppressionBus::Broadcast(&ScriptCanvasEditor::TraceSuppressionRequests::SuppressPrintf, true);
  56. AZ::ComponentApplication::Descriptor descriptor;
  57. descriptor.m_enableDrilling = false;
  58. descriptor.m_useExistingAllocator = true;
  59. AZ::DynamicModuleDescriptor dynamicModuleDescriptor;
  60. dynamicModuleDescriptor.m_dynamicLibraryPath = "GraphCanvas.Editor";
  61. descriptor.m_modules.push_back(dynamicModuleDescriptor);
  62. dynamicModuleDescriptor.m_dynamicLibraryPath = "ScriptCanvas.Editor";
  63. descriptor.m_modules.push_back(dynamicModuleDescriptor);
  64. dynamicModuleDescriptor.m_dynamicLibraryPath = "ExpressionEvaluation";
  65. descriptor.m_modules.push_back(dynamicModuleDescriptor);
  66. dynamicModuleDescriptor.m_dynamicLibraryPath = "ScriptEvents";
  67. descriptor.m_modules.push_back(dynamicModuleDescriptor);
  68. s_application->Start(descriptor, appStartup);
  69. // Without this, the user settings component would attempt to save on finalize/shutdown. Since the file is
  70. // shared across the whole engine, if multiple tests are run in parallel, the saving could cause a crash
  71. // in the unit tests.
  72. AZ::UserSettingsComponentRequestBus::Broadcast(&AZ::UserSettingsComponentRequests::DisableSaveOnFinalize);
  73. ScriptCanvasEditor::TraceSuppressionBus::Broadcast(&ScriptCanvasEditor::TraceSuppressionRequests::SuppressPrintf, false);
  74. }
  75. }
  76. AZ::IO::FileIOBase* fileIO = AZ::IO::FileIOBase::GetInstance();
  77. AZ_Assert(fileIO, "SC unit tests require filehandling");
  78. s_setupSucceeded = fileIO->GetAlias("@engroot@") != nullptr;
  79. AZ::TickBus::AllowFunctionQueuing(true);
  80. auto m_serializeContext = s_application->GetSerializeContext();
  81. auto m_behaviorContext = s_application->GetBehaviorContext();
  82. ScriptCanvasTesting::Reflect(m_serializeContext);
  83. ScriptCanvasTesting::Reflect(m_behaviorContext);
  84. ScriptCanvasTestingNodes::BehaviorContextObjectTest::Reflect(m_serializeContext);
  85. ScriptCanvasTestingNodes::BehaviorContextObjectTest::Reflect(m_behaviorContext);
  86. ::Nodes::InputMethodSharedDataSlotExampleNode::Reflect(m_serializeContext);
  87. ::Nodes::InputMethodSharedDataSlotExampleNode::Reflect(m_behaviorContext);
  88. ::Nodes::BranchMethodSharedDataSlotExampleNode::Reflect(m_serializeContext);
  89. ::Nodes::BranchMethodSharedDataSlotExampleNode::Reflect(m_behaviorContext);
  90. ::Nodes::ReturnTypeExampleNode::Reflect(m_serializeContext);
  91. ::Nodes::ReturnTypeExampleNode::Reflect(m_behaviorContext);
  92. ::Nodes::InputTypeExampleNode::Reflect(m_serializeContext);
  93. ::Nodes::InputTypeExampleNode::Reflect(m_behaviorContext);
  94. ::Nodes::BranchInputTypeExampleNode::Reflect(m_serializeContext);
  95. ::Nodes::BranchInputTypeExampleNode::Reflect(m_behaviorContext);
  96. ::Nodes::PropertyExampleNode::Reflect(m_serializeContext);
  97. ::Nodes::PropertyExampleNode::Reflect(m_behaviorContext);
  98. TestNodeableObject::Reflect(m_serializeContext);
  99. TestNodeableObject::Reflect(m_behaviorContext);
  100. ScriptUnitTestEventHandler::Reflect(m_serializeContext);
  101. ScriptUnitTestEventHandler::Reflect(m_behaviorContext);
  102. }
  103. static void TearDownTestCase()
  104. {
  105. // don't hang on to dangling assets
  106. AZ::Data::AssetManager::Instance().DispatchEvents();
  107. if (s_application)
  108. {
  109. s_application->Stop();
  110. delete s_application;
  111. s_application = nullptr;
  112. }
  113. s_allocatorSetup.TeardownAllocator();
  114. }
  115. template<class T>
  116. void RegisterComponentDescriptor()
  117. {
  118. AZ::ComponentDescriptor* descriptor = T::CreateDescriptor();
  119. auto insertResult = m_descriptors.insert(descriptor);
  120. if (insertResult.second)
  121. {
  122. GetApplication()->RegisterComponentDescriptor(descriptor);
  123. }
  124. }
  125. void SetUp() override
  126. {
  127. ASSERT_TRUE(s_setupSucceeded) << "ScriptCanvasTestFixture set up failed, unit tests can't work properly";
  128. m_serializeContext = s_application->GetSerializeContext();
  129. m_behaviorContext = s_application->GetBehaviorContext();
  130. AZ_Assert(AZ::IO::FileIOBase::GetInstance(), "File IO was not properly installed");
  131. RegisterComponentDescriptor<TestNodes::TestResult>();
  132. RegisterComponentDescriptor<TestNodes::ConfigurableUnitTestNode>();
  133. m_numericVectorType = ScriptCanvas::Data::Type::BehaviorContextObject(azrtti_typeid<AZStd::vector<ScriptCanvas::Data::NumberType>>());
  134. m_stringToNumberMapType = ScriptCanvas::Data::Type::BehaviorContextObject(azrtti_typeid<AZStd::unordered_map<ScriptCanvas::Data::StringType, ScriptCanvas::Data::NumberType>>());
  135. m_dataSlotConfigurationType = ScriptCanvas::Data::Type::BehaviorContextObject(azrtti_typeid<ScriptCanvas::DataSlotConfiguration>());
  136. }
  137. void TearDown() override
  138. {
  139. delete m_graph;
  140. m_graph = nullptr;
  141. ASSERT_TRUE(s_setupSucceeded) << "ScriptCanvasTestFixture set up failed, unit tests can't work properly";
  142. for (AZ::ComponentDescriptor* componentDescriptor : m_descriptors)
  143. {
  144. GetApplication()->UnregisterComponentDescriptor(componentDescriptor);
  145. }
  146. m_descriptors.clear();
  147. }
  148. ScriptCanvas::Graph* CreateGraph()
  149. {
  150. if (m_graph == nullptr)
  151. {
  152. m_graph = aznew ScriptCanvas::Graph();
  153. m_graph->Init();
  154. }
  155. return m_graph;
  156. }
  157. TestNodes::ConfigurableUnitTestNode* CreateConfigurableNode(AZStd::string entityName = "ConfigurableNodeEntity")
  158. {
  159. AZ::Entity* configurableNodeEntity = new AZ::Entity(entityName.c_str());
  160. auto configurableNode = configurableNodeEntity->CreateComponent<TestNodes::ConfigurableUnitTestNode>();
  161. if (m_graph == nullptr)
  162. {
  163. CreateGraph();
  164. }
  165. configurableNodeEntity->Init();
  166. m_graph->AddNode(configurableNodeEntity->GetId());
  167. return configurableNode;
  168. }
  169. void ReportErrors(ScriptCanvas::Graph* graph, bool expectErrors = false, bool expectIrrecoverableErrors = false)
  170. {
  171. AZ_UNUSED(graph);
  172. AZ_UNUSED(expectErrors);
  173. AZ_UNUSED(expectIrrecoverableErrors);
  174. }
  175. void TestConnectionBetween(ScriptCanvas::Endpoint sourceEndpoint, ScriptCanvas::Endpoint targetEndpoint, bool isValid = true)
  176. {
  177. EXPECT_EQ(m_graph->CanConnectionExistBetween(sourceEndpoint, targetEndpoint).IsSuccess(), isValid);
  178. EXPECT_EQ(m_graph->CanConnectionExistBetween(targetEndpoint, sourceEndpoint).IsSuccess(), isValid);
  179. EXPECT_EQ(m_graph->CanCreateConnectionBetween(sourceEndpoint, targetEndpoint).IsSuccess(), isValid);
  180. EXPECT_EQ(m_graph->CanCreateConnectionBetween(targetEndpoint, sourceEndpoint).IsSuccess(), isValid);
  181. if (isValid)
  182. {
  183. EXPECT_TRUE(m_graph->ConnectByEndpoint(sourceEndpoint, targetEndpoint));
  184. }
  185. }
  186. void TestIsConnectionPossible(ScriptCanvas::Endpoint sourceEndpoint, ScriptCanvas::Endpoint targetEndpoint, bool isValid = true)
  187. {
  188. EXPECT_EQ(m_graph->CanConnectionExistBetween(sourceEndpoint, targetEndpoint).IsSuccess(), isValid);
  189. EXPECT_EQ(m_graph->CanConnectionExistBetween(targetEndpoint, sourceEndpoint).IsSuccess(), isValid);
  190. EXPECT_EQ(m_graph->CanCreateConnectionBetween(sourceEndpoint, targetEndpoint).IsSuccess(), isValid);
  191. EXPECT_EQ(m_graph->CanCreateConnectionBetween(targetEndpoint, sourceEndpoint).IsSuccess(), isValid);
  192. }
  193. void CreateExecutionFlowBetween(AZStd::vector<TestNodes::ConfigurableUnitTestNode*> unitTestNodes)
  194. {
  195. ScriptCanvas::Slot* previousOutSlot = nullptr;
  196. for (TestNodes::ConfigurableUnitTestNode* testNode : unitTestNodes)
  197. {
  198. {
  199. ScriptCanvas::ExecutionSlotConfiguration inputSlot = ScriptCanvas::CommonSlots::GeneralInSlot();
  200. ScriptCanvas::Slot* slot = testNode->AddTestingSlot(inputSlot);
  201. if (slot && previousOutSlot)
  202. {
  203. TestConnectionBetween(previousOutSlot->GetEndpoint(), slot->GetEndpoint());
  204. }
  205. }
  206. {
  207. ScriptCanvas::ExecutionSlotConfiguration outputSlot = ScriptCanvas::CommonSlots::GeneralOutSlot();
  208. previousOutSlot = testNode->AddTestingSlot(outputSlot);
  209. }
  210. }
  211. }
  212. AZStd::vector< ScriptCanvas::Data::Type > GetContainerDataTypes() const
  213. {
  214. return { m_numericVectorType, m_stringToNumberMapType };
  215. }
  216. ScriptCanvas::Data::Type GetRandomContainerType() const
  217. {
  218. AZStd::vector< ScriptCanvas::Data::Type > containerTypes = GetContainerDataTypes();
  219. // We have no types to randomize. Just return.
  220. if (containerTypes.empty())
  221. {
  222. return m_numericVectorType;
  223. }
  224. int randomIndex = rand() % containerTypes.size();
  225. ScriptCanvas::Data::Type randomType = containerTypes[randomIndex];
  226. AZ_TracePrintf("ScriptCanvasTestFixture", "RandomContainerType: %s\n", randomType.GetAZType().ToString<AZStd::string>().c_str());
  227. return randomType;
  228. }
  229. AZStd::vector< ScriptCanvas::Data::Type > GetPrimitiveTypes() const
  230. {
  231. return{
  232. ScriptCanvas::Data::Type::AABB(),
  233. ScriptCanvas::Data::Type::Boolean(),
  234. ScriptCanvas::Data::Type::Color(),
  235. ScriptCanvas::Data::Type::CRC(),
  236. ScriptCanvas::Data::Type::EntityID(),
  237. ScriptCanvas::Data::Type::Matrix3x3(),
  238. ScriptCanvas::Data::Type::Matrix4x4(),
  239. ScriptCanvas::Data::Type::Number(),
  240. ScriptCanvas::Data::Type::OBB(),
  241. ScriptCanvas::Data::Type::Plane(),
  242. ScriptCanvas::Data::Type::Quaternion(),
  243. ScriptCanvas::Data::Type::String(),
  244. ScriptCanvas::Data::Type::Transform(),
  245. ScriptCanvas::Data::Type::Vector2(),
  246. ScriptCanvas::Data::Type::Vector3(),
  247. ScriptCanvas::Data::Type::Vector4()
  248. };
  249. }
  250. ScriptCanvas::Data::Type GetRandomPrimitiveType() const
  251. {
  252. AZStd::vector< ScriptCanvas::Data::Type > primitiveTypes = GetPrimitiveTypes();
  253. // We have no types to randomize. Just return.
  254. if (primitiveTypes.empty())
  255. {
  256. return ScriptCanvas::Data::Type::Number();
  257. }
  258. int randomIndex = rand() % primitiveTypes.size();
  259. ScriptCanvas::Data::Type randomType = primitiveTypes[randomIndex];
  260. AZ_TracePrintf("ScriptCanvasTestFixture", "RandomPrimitiveType: %s\n", randomType.GetAZType().ToString<AZStd::string>().c_str());
  261. return randomType;
  262. }
  263. AZStd::vector< ScriptCanvas::Data::Type > GetBehaviorObjectTypes() const
  264. {
  265. return {
  266. m_dataSlotConfigurationType
  267. };
  268. }
  269. ScriptCanvas::Data::Type GetRandomObjectType() const
  270. {
  271. AZStd::vector< ScriptCanvas::Data::Type > objectTypes = GetBehaviorObjectTypes();
  272. // We have no types to randomize. Just return.
  273. if (objectTypes.empty())
  274. {
  275. return m_dataSlotConfigurationType;
  276. }
  277. int randomIndex = rand() % objectTypes.size();
  278. ScriptCanvas::Data::Type randomType = objectTypes[randomIndex];
  279. AZ_TracePrintf("ScriptCanvasTestFixture", "RandomObjectType: %s\n", randomType.GetAZType().ToString<AZStd::string>().c_str());
  280. return randomType;
  281. }
  282. AZStd::vector< ScriptCanvas::Data::Type > GetTypes() const
  283. {
  284. auto primitives = GetPrimitiveTypes();
  285. auto containers = GetContainerDataTypes();
  286. auto objects = GetBehaviorObjectTypes();
  287. primitives.reserve(containers.size() + objects.size());
  288. primitives.insert(primitives.end(), containers.begin(), containers.end());
  289. primitives.insert(primitives.end(), objects.begin(), objects.end());
  290. return primitives;
  291. }
  292. ScriptCanvas::Data::Type GetRandomType() const
  293. {
  294. AZStd::vector< ScriptCanvas::Data::Type > types = GetTypes();
  295. // We have no types to randomize. Just return.
  296. if (types.empty())
  297. {
  298. return m_dataSlotConfigurationType;
  299. }
  300. int randomIndex = rand() % types.size();
  301. ScriptCanvas::Data::Type randomType = types[randomIndex];
  302. AZ_TracePrintf("ScriptCanvasTestFixture", "RandomType: %s\n", randomType.GetAZType().ToString<AZStd::string>().c_str());
  303. return randomType;
  304. }
  305. AZStd::string GenerateSlotName()
  306. {
  307. AZStd::string slotName = AZStd::string::format("Slot %i", m_slotCounter);
  308. ++m_slotCounter;
  309. return slotName;
  310. }
  311. AZ::SerializeContext* m_serializeContext;
  312. AZ::BehaviorContext* m_behaviorContext;
  313. UnitTestEntityContext m_entityContext;
  314. // Really big(visually) data types just storing here for ease of use in situations.
  315. ScriptCanvas::Data::Type m_numericVectorType;
  316. ScriptCanvas::Data::Type m_stringToNumberMapType;
  317. ScriptCanvas::Data::Type m_dataSlotConfigurationType;
  318. ScriptCanvas::Graph* m_graph = nullptr;
  319. int m_slotCounter = 0;
  320. AZStd::unordered_map< AZ::EntityId, AZ::Entity* > m_entityMap;
  321. protected:
  322. static ScriptCanvasTests::Application* GetApplication() { return s_application; }
  323. private:
  324. static UnitTest::AllocatorsBase s_allocatorSetup;
  325. static bool s_setupSucceeded;
  326. AZStd::unordered_set< AZ::ComponentDescriptor* > m_descriptors;
  327. };
  328. }