GraphModelIntegrationTest.cpp 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339
  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. // AZ
  9. #include <AzCore/Debug/StackTracer.h>
  10. #include <AzCore/std/smart_ptr/unique_ptr.h>
  11. #include <AzCore/UnitTest/TestTypes.h>
  12. #include <AzTest/AzTest.h>
  13. // Graph Canvas
  14. #include <GraphCanvas/Components/Nodes/NodeBus.h>
  15. #include <GraphCanvas/Components/Slots/SlotBus.h>
  16. #include <GraphCanvas/Components/Slots/Data/DataSlotBus.h>
  17. #include <GraphCanvas/Editor/EditorTypes.h>
  18. #include <GraphCanvas/GraphCanvasBus.h>
  19. // GraphModel
  20. #include <GraphModel/GraphModelBus.h>
  21. // GraphModel test harness and minimum setup for a custom GraphModel instance
  22. #include <Tests/TestEnvironment.h>
  23. // These tests rely on this test environment to setup the necessary
  24. // mocked GraphCanvas buses and system components
  25. AZ_UNIT_TEST_HOOK(new GraphModelIntegrationTest::GraphModelTestEnvironment);
  26. namespace GraphModelIntegrationTest
  27. {
  28. /**
  29. * Used for testing the GraphModelIntegration namespace, which relies on GraphCanvasWidgets and Qt.
  30. * NOTE: These tests rely on being run in the GraphModelTestEnvironment, which sets up the
  31. * necessary mocked GraphCanvas buses and system components.
  32. */
  33. class GraphModelIntegrationTests
  34. : public ::testing::Test
  35. , public UnitTest::TraceBusRedirector
  36. {
  37. protected:
  38. void SetUp() override
  39. {
  40. AZ::Debug::TraceMessageBus::Handler::BusConnect();
  41. // Create our test graph context
  42. m_graphContext = AZStd::make_shared<TestGraphContext>();
  43. // Create a new node graph
  44. m_graph = AZStd::make_shared<GraphModel::Graph>(m_graphContext);
  45. // Create a new scene for the graph
  46. AZ::Entity* scene = nullptr;
  47. GraphModelIntegration::GraphManagerRequestBus::BroadcastResult(scene, &GraphModelIntegration::GraphManagerRequests::CreateScene, m_graph, NODE_GRAPH_TEST_EDITOR_ID);
  48. m_scene.reset(scene);
  49. m_sceneId = m_scene->GetId();
  50. }
  51. void TearDown() override
  52. {
  53. // Release shared pointers that were setup
  54. m_graphContext.reset();
  55. m_graph.reset();
  56. m_scene.reset();
  57. AZ::Debug::TraceMessageBus::Handler::BusDisconnect();
  58. }
  59. AZStd::shared_ptr<TestGraphContext> m_graphContext = nullptr;
  60. GraphModel::GraphPtr m_graph = nullptr;
  61. AZStd::unique_ptr<AZ::Entity> m_scene = nullptr;
  62. AZ::EntityId m_sceneId;
  63. };
  64. TEST_F(GraphModelIntegrationTests, NodeAddedToScene)
  65. {
  66. // Create our test node
  67. GraphModel::NodePtr testNode = AZStd::make_shared<TestNode>(m_graph, m_graphContext);
  68. EXPECT_TRUE(testNode != nullptr);
  69. // Add our test node to the scene
  70. AZ::Vector2 offset;
  71. GraphCanvas::NodeId nodeId;
  72. GraphModelIntegration::GraphControllerRequestBus::EventResult(nodeId, m_sceneId, &GraphModelIntegration::GraphControllerRequests::AddNode, testNode, offset);
  73. // Make sure the correct node was added to the scene
  74. GraphModel::NodePtrList nodeList;
  75. GraphModelIntegration::GraphControllerRequestBus::EventResult(nodeList, m_sceneId, &GraphModelIntegration::GraphControllerRequests::GetNodes);
  76. EXPECT_EQ(nodeList.size(), 1);
  77. EXPECT_EQ(nodeList[0], testNode);
  78. }
  79. /**
  80. * Make sure the data type of the slot on a node is set properly. There was a new DataSlotConfiguration added
  81. * in GraphCanvas, which the GraphModel implementation hadn't previously accounted for, resulting in all data slots on
  82. * GraphModel nodes having an invalid data type.
  83. */
  84. TEST_F(GraphModelIntegrationTests, NodeWithDataSlotHasProperDataType)
  85. {
  86. // Create our test node
  87. GraphModel::NodePtr testNode = AZStd::make_shared<TestNode>(m_graph, m_graphContext);
  88. EXPECT_TRUE(testNode != nullptr);
  89. // Add our test node to the scene
  90. AZ::Vector2 offset;
  91. GraphCanvas::NodeId nodeId;
  92. GraphModelIntegration::GraphControllerRequestBus::EventResult(nodeId, m_sceneId, &GraphModelIntegration::GraphControllerRequests::AddNode, testNode, offset);
  93. // Retrieve the data type (string) for the string input slot on our test node
  94. GraphModel::SlotPtr testNodeStringInputSlot = testNode->GetSlot(TEST_STRING_INPUT_ID);
  95. EXPECT_TRUE(testNodeStringInputSlot != nullptr);
  96. GraphModel::DataTypePtr stringDataType = testNodeStringInputSlot->GetDataType();
  97. AZ::Uuid stringDataTypeId = stringDataType->GetTypeUuid();
  98. // Make sure our node has the expected slots
  99. AZStd::vector<AZ::EntityId> slotIds;
  100. GraphCanvas::NodeRequestBus::EventResult(slotIds, nodeId, &GraphCanvas::NodeRequests::GetSlotIds);
  101. EXPECT_EQ(slotIds.size(), 4);
  102. // Make sure the data type of the input string slot on our test node matches the expected data type
  103. AZ::EntityId slotId = slotIds[0];
  104. AZ::Uuid slotDataTypeId;
  105. GraphCanvas::DataSlotRequestBus::EventResult(slotDataTypeId, slotId, &GraphCanvas::DataSlotRequests::GetDataTypeId);
  106. EXPECT_EQ(stringDataTypeId, slotDataTypeId);
  107. }
  108. TEST_F(GraphModelIntegrationTests, GetNodeById)
  109. {
  110. // Create our test node
  111. GraphModel::NodePtr testNode = AZStd::make_shared<TestNode>(m_graph, m_graphContext);
  112. EXPECT_TRUE(testNode != nullptr);
  113. // Add our test node to the scene
  114. AZ::Vector2 offset;
  115. GraphCanvas::NodeId nodeId;
  116. GraphModelIntegration::GraphControllerRequestBus::EventResult(nodeId, m_sceneId, &GraphModelIntegration::GraphControllerRequests::AddNode, testNode, offset);
  117. // Test that we can retrieve the expected node by NodeId
  118. GraphModel::NodePtr retrievedNode = nullptr;
  119. GraphModelIntegration::GraphControllerRequestBus::EventResult(retrievedNode, m_sceneId, &GraphModelIntegration::GraphControllerRequests::GetNodeById, nodeId);
  120. EXPECT_EQ(retrievedNode, testNode);
  121. // Test requesting an invalid NodeId returns nullptr
  122. retrievedNode = nullptr;
  123. GraphModelIntegration::GraphControllerRequestBus::EventResult(retrievedNode, m_sceneId, &GraphModelIntegration::GraphControllerRequests::GetNodeById, GraphCanvas::NodeId());
  124. EXPECT_EQ(retrievedNode, nullptr);
  125. // Test requesting a valid NodeId but one that doesn't exist in the scene returns nullptr
  126. retrievedNode = nullptr;
  127. GraphModelIntegration::GraphControllerRequestBus::EventResult(retrievedNode, m_sceneId, &GraphModelIntegration::GraphControllerRequests::GetNodeById, GraphCanvas::NodeId(1234));
  128. EXPECT_EQ(retrievedNode, nullptr);
  129. }
  130. TEST_F(GraphModelIntegrationTests, GetNodesFromGraphNodeIds)
  131. {
  132. // Create a test node
  133. GraphModel::NodePtr testNode = AZStd::make_shared<TestNode>(m_graph, m_graphContext);
  134. EXPECT_TRUE(testNode != nullptr);
  135. // Add our test node to the scene
  136. AZ::Vector2 offset;
  137. GraphCanvas::NodeId nodeId;
  138. GraphModelIntegration::GraphControllerRequestBus::EventResult(nodeId, m_sceneId, &GraphModelIntegration::GraphControllerRequests::AddNode, testNode, offset);
  139. // Retrieve Nodes by their NodeId
  140. AZStd::vector<GraphCanvas::NodeId> nodeIds = {
  141. nodeId, // Valid NodeId for a node in the scene
  142. GraphCanvas::NodeId(), // Invalid NodeId
  143. GraphCanvas::NodeId(1234) // Valid NodeId but not in the scene
  144. };
  145. GraphModel::NodePtrList retrievedNodes;
  146. GraphModelIntegration::GraphControllerRequestBus::EventResult(retrievedNodes, m_sceneId, &GraphModelIntegration::GraphControllerRequests::GetNodesFromGraphNodeIds, nodeIds);
  147. // Test that only one node was found.
  148. EXPECT_EQ(retrievedNodes.size(), 1);
  149. // Test the first node in the list should be our valid test node
  150. EXPECT_EQ(retrievedNodes[0], testNode);
  151. }
  152. TEST_F(GraphModelIntegrationTests, ExtendableSlotsWithDifferentMinimumValues)
  153. {
  154. // Create a node with extendable slots
  155. GraphModel::NodePtr testNode = AZStd::make_shared<ExtendableSlotsNode>(m_graph, m_graphContext);
  156. EXPECT_TRUE(testNode != nullptr);
  157. // Add our test node to the scene
  158. AZ::Vector2 offset;
  159. GraphCanvas::NodeId nodeId;
  160. GraphModelIntegration::GraphControllerRequestBus::EventResult(nodeId, m_sceneId, &GraphModelIntegration::GraphControllerRequests::AddNode, testNode, offset);
  161. // The input string extendable slot has a minimum of 0 slots, so there should be none
  162. auto extendableSlots = testNode->GetExtendableSlots(TEST_STRING_INPUT_ID);
  163. int numExtendableSlots = testNode->GetExtendableSlotCount(TEST_STRING_INPUT_ID);
  164. EXPECT_EQ(extendableSlots.size(), 0);
  165. EXPECT_EQ(numExtendableSlots, 0);
  166. // The output string and input event extendable slots both use the default minimum (1)
  167. extendableSlots = testNode->GetExtendableSlots(TEST_STRING_OUTPUT_ID);
  168. numExtendableSlots = testNode->GetExtendableSlotCount(TEST_STRING_OUTPUT_ID);
  169. EXPECT_EQ(extendableSlots.size(), 1);
  170. EXPECT_EQ(numExtendableSlots, 1);
  171. extendableSlots = testNode->GetExtendableSlots(TEST_EVENT_INPUT_ID);
  172. numExtendableSlots = testNode->GetExtendableSlotCount(TEST_EVENT_INPUT_ID);
  173. EXPECT_EQ(extendableSlots.size(), 1);
  174. EXPECT_EQ(numExtendableSlots, 1);
  175. // The output event extendable slot has a minimum of 3 slots
  176. extendableSlots = testNode->GetExtendableSlots(TEST_EVENT_OUTPUT_ID);
  177. EXPECT_EQ(extendableSlots.size(), 3);
  178. }
  179. TEST_F(GraphModelIntegrationTests, AddingExtendableSlotsPastMaximum)
  180. {
  181. // Create a node with extendable slots
  182. GraphModel::NodePtr testNode = AZStd::make_shared<ExtendableSlotsNode>(m_graph, m_graphContext);
  183. EXPECT_TRUE(testNode != nullptr);
  184. // Add our test node to the scene
  185. AZ::Vector2 offset;
  186. GraphCanvas::NodeId nodeId;
  187. GraphModelIntegration::GraphControllerRequestBus::EventResult(nodeId, m_sceneId, &GraphModelIntegration::GraphControllerRequests::AddNode, testNode, offset);
  188. // The input string extendable slot has a minimum of 0 slots, so it starts with 0
  189. auto extendableSlots = testNode->GetExtendableSlots(TEST_STRING_INPUT_ID);
  190. int numExtendableSlots = testNode->GetExtendableSlotCount(TEST_STRING_INPUT_ID);
  191. EXPECT_EQ(extendableSlots.size(), 0);
  192. EXPECT_EQ(numExtendableSlots, 0);
  193. // The input string extendable slot has a maximum of 2 slots, so the first add should succeed
  194. GraphModel::SlotPtr firstSlot = testNode->AddExtendedSlot(TEST_STRING_INPUT_ID);
  195. extendableSlots = testNode->GetExtendableSlots(TEST_STRING_INPUT_ID);
  196. numExtendableSlots = testNode->GetExtendableSlotCount(TEST_STRING_INPUT_ID);
  197. EXPECT_TRUE(firstSlot != nullptr);
  198. EXPECT_EQ(firstSlot->GetName(), TEST_STRING_INPUT_ID);
  199. EXPECT_EQ(extendableSlots.size(), 1);
  200. EXPECT_EQ(numExtendableSlots, 1);
  201. // The input string extendable slot has a maximum of 2 slots, so the second add should also succeed
  202. GraphModel::SlotPtr secondSlot = testNode->AddExtendedSlot(TEST_STRING_INPUT_ID);
  203. extendableSlots = testNode->GetExtendableSlots(TEST_STRING_INPUT_ID);
  204. numExtendableSlots = testNode->GetExtendableSlotCount(TEST_STRING_INPUT_ID);
  205. EXPECT_TRUE(secondSlot != nullptr);
  206. EXPECT_EQ(secondSlot->GetName(), TEST_STRING_INPUT_ID);
  207. EXPECT_EQ(extendableSlots.size(), 2);
  208. EXPECT_EQ(numExtendableSlots, 2);
  209. // The input string extendable slot has a maximum of 2 slots, so the third add should fail
  210. GraphModel::SlotPtr thirdSlot = testNode->AddExtendedSlot(TEST_STRING_INPUT_ID);
  211. extendableSlots = testNode->GetExtendableSlots(TEST_STRING_INPUT_ID);
  212. numExtendableSlots = testNode->GetExtendableSlotCount(TEST_STRING_INPUT_ID);
  213. EXPECT_TRUE(thirdSlot == nullptr);
  214. EXPECT_EQ(extendableSlots.size(), 2);
  215. EXPECT_EQ(numExtendableSlots, 2);
  216. }
  217. TEST_F(GraphModelIntegrationTests, RemovingExtendableSlotsBelowMinimum)
  218. {
  219. // Create a node with extendable slots
  220. GraphModel::NodePtr testNode = AZStd::make_shared<ExtendableSlotsNode>(m_graph, m_graphContext);
  221. EXPECT_TRUE(testNode != nullptr);
  222. // Add our test node to the scene
  223. AZ::Vector2 offset;
  224. GraphCanvas::NodeId nodeId;
  225. GraphModelIntegration::GraphControllerRequestBus::EventResult(nodeId, m_sceneId, &GraphModelIntegration::GraphControllerRequests::AddNode, testNode, offset);
  226. // The output string extendable slot has a minimum of 1 slot, so it starts with 1
  227. auto extendableSlots = testNode->GetExtendableSlots(TEST_STRING_OUTPUT_ID);
  228. int numExtendableSlots = testNode->GetExtendableSlotCount(TEST_STRING_OUTPUT_ID);
  229. EXPECT_EQ(extendableSlots.size(), 1);
  230. EXPECT_EQ(numExtendableSlots, 1);
  231. // The output string extendable slot has the default maximum (100), so we can add one
  232. GraphModel::SlotPtr firstSlot = testNode->AddExtendedSlot(TEST_STRING_OUTPUT_ID);
  233. extendableSlots = testNode->GetExtendableSlots(TEST_STRING_OUTPUT_ID);
  234. numExtendableSlots = testNode->GetExtendableSlotCount(TEST_STRING_OUTPUT_ID);
  235. EXPECT_TRUE(firstSlot != nullptr);
  236. EXPECT_EQ(firstSlot->GetName(), TEST_STRING_OUTPUT_ID);
  237. EXPECT_EQ(extendableSlots.size(), 2);
  238. EXPECT_EQ(numExtendableSlots, 2);
  239. // The output string extednable slot has a minimum of 1, so we can remove 1
  240. testNode->DeleteSlot(firstSlot);
  241. extendableSlots = testNode->GetExtendableSlots(TEST_STRING_OUTPUT_ID);
  242. numExtendableSlots = testNode->GetExtendableSlotCount(TEST_STRING_OUTPUT_ID);
  243. EXPECT_EQ(extendableSlots.size(), 1);
  244. EXPECT_EQ(numExtendableSlots, 1);
  245. // The output string extednable slot has a minimum of 1, so attempting to remove one
  246. // when there is only one left will fail
  247. GraphModel::SlotPtr lastSlot = *extendableSlots.begin();
  248. testNode->DeleteSlot(lastSlot);
  249. extendableSlots = testNode->GetExtendableSlots(TEST_STRING_OUTPUT_ID);
  250. numExtendableSlots = testNode->GetExtendableSlotCount(TEST_STRING_OUTPUT_ID);
  251. EXPECT_EQ(extendableSlots.size(), 1);
  252. EXPECT_EQ(numExtendableSlots, 1);
  253. }
  254. TEST_F(GraphModelIntegrationTests, CannotAddNonExtendableSlot)
  255. {
  256. // Create a test node
  257. GraphModel::NodePtr testNode = AZStd::make_shared<TestNode>(m_graph, m_graphContext);
  258. EXPECT_TRUE(testNode != nullptr);
  259. // Add our test node to the scene
  260. AZ::Vector2 offset;
  261. GraphCanvas::NodeId nodeId;
  262. GraphModelIntegration::GraphControllerRequestBus::EventResult(nodeId, m_sceneId, &GraphModelIntegration::GraphControllerRequests::AddNode, testNode, offset);
  263. // Can't add a non-extendable slot, so adding a non-extendable slot will fail
  264. AZ_TEST_START_TRACE_SUPPRESSION;
  265. GraphModel::SlotPtr newSlot = testNode->AddExtendedSlot(TEST_STRING_INPUT_ID);
  266. AZ_TEST_STOP_TRACE_SUPPRESSION(1);
  267. EXPECT_EQ(newSlot, nullptr);
  268. }
  269. TEST_F(GraphModelIntegrationTests, CannotDeleteNonExtendableSlot)
  270. {
  271. // Create a test node
  272. GraphModel::NodePtr testNode = AZStd::make_shared<TestNode>(m_graph, m_graphContext);
  273. EXPECT_TRUE(testNode != nullptr);
  274. // Add our test node to the scene
  275. AZ::Vector2 offset;
  276. GraphCanvas::NodeId nodeId;
  277. GraphModelIntegration::GraphControllerRequestBus::EventResult(nodeId, m_sceneId, &GraphModelIntegration::GraphControllerRequests::AddNode, testNode, offset);
  278. // Can't delete a non-extendable slot, so deleting a non-extendable slot will fail
  279. auto beforeSlots = testNode->GetSlots();
  280. GraphModel::SlotPtr inputSlot = testNode->GetSlot(TEST_STRING_INPUT_ID);
  281. testNode->DeleteSlot(inputSlot);
  282. auto afterSlots = testNode->GetSlots();
  283. EXPECT_EQ(beforeSlots.size(), afterSlots.size());
  284. }
  285. }