/* * All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or * its licensors. * * For complete copyright EntityRef license terms please see the LICENSE at the root of this * distribution (the "License"). All use of this software is governed by the License, * or, if provided, by the license below or the license accompanying this file. Do not * remove or modify any license notices. This file is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * */ #include #include #include #include #include #include #include #include #include using namespace ScriptCanvasTests; using namespace TestNodes; TEST_F(ScriptCanvasTestFixture, CoreNodeFunction_OwningGraphCheck) { using namespace ScriptCanvas; Graph* graph = CreateGraph(); ConfigurableUnitTestNode* groupedNode = CreateConfigurableNode(); EXPECT_EQ(graph, groupedNode->GetGraph()); } TEST_F(ScriptCanvasTestFixture, AddRemoveSlot) { RegisterComponentDescriptor(); using namespace ScriptCanvas; using namespace Nodes; AZStd::unique_ptr graphEntity = AZStd::make_unique("RemoveSlotGraph"); graphEntity->Init(); Graph* graph{}; SystemRequestBus::BroadcastResult(graph, &SystemRequests::CreateGraphOnEntity, graphEntity.get()); ScriptCanvasId graphUniqueId = graph->GetScriptCanvasId(); AZ::EntityId outID; auto startNode = CreateTestNode(graphUniqueId, outID); auto numberAddNode = CreateTestNode(graphUniqueId, outID); auto number1Node = CreateDataNode(graphUniqueId, 1.0, outID); auto number2Node = CreateDataNode(graphUniqueId, 2.0, outID); auto number3Node = CreateDataNode(graphUniqueId, 4.0, outID); auto numberResultNode = CreateDataNode(graphUniqueId, 0.0, outID); // data EXPECT_TRUE(Connect(*graph, number1Node->GetEntityId(), "Get", numberAddNode->GetEntityId(), "A")); EXPECT_TRUE(Connect(*graph, number2Node->GetEntityId(), "Get", numberAddNode->GetEntityId(), "B")); EXPECT_TRUE(Connect(*graph, number3Node->GetEntityId(), "Get", numberAddNode->GetEntityId(), "C")); EXPECT_TRUE(Connect(*graph, numberAddNode->GetEntityId(), "Result", numberResultNode->GetEntityId(), "Set")); // logic EXPECT_TRUE(Connect(*graph, startNode->GetEntityId(), "Out", numberAddNode->GetEntityId(), "In")); // execute pre remove graphEntity->Activate(); ReportErrors(graph); graphEntity->Deactivate(); if (auto result = GetInput_UNIT_TEST(numberResultNode, "Set")) { SC_EXPECT_DOUBLE_EQ(7.0, *result); } else { ADD_FAILURE(); } // Remove the second number slot from the AddNodeWithRemoveSlot node(the one that contains value = 2.0) numberAddNode->RemoveSlot(numberAddNode->GetSlotId("B")); EXPECT_FALSE(numberAddNode->GetSlotId("B").IsValid()); // execute post-remove graphEntity->Activate(); ReportErrors(graph); graphEntity->Deactivate(); if (auto result = GetInput_UNIT_TEST(numberResultNode, "Set")) { SC_EXPECT_DOUBLE_EQ(5.0, *result); } else { ADD_FAILURE(); } // Add two more slots and set there values to 8.0 and 16.0 EXPECT_TRUE(numberAddNode->AddSlot("D").IsValid()); EXPECT_TRUE(numberAddNode->AddSlot("B").IsValid()); auto number4Node = CreateDataNode(graphUniqueId, 8.0, outID); auto number5Node = CreateDataNode(graphUniqueId, 16.0, outID); EXPECT_TRUE(Connect(*graph, number4Node->GetEntityId(), "Get", numberAddNode->GetEntityId(), "D")); EXPECT_TRUE(Connect(*graph, number5Node->GetEntityId(), "Get", numberAddNode->GetEntityId(), "B")); // execute post-add of slot "D" and re-add of slot "A" graphEntity->Activate(); ReportErrors(graph); graphEntity->Deactivate(); if (auto result = GetInput_UNIT_TEST(numberResultNode, "Set")) { SC_EXPECT_DOUBLE_EQ(1.0 + 4.0 + 8.0 + 16.0, *result); } else { ADD_FAILURE(); } // Remove the first number slot from the AddNodeWithRemoveSlot node(the one that contains value = 1.0 numberAddNode->RemoveSlot(numberAddNode->GetSlotId("A")); EXPECT_FALSE(numberAddNode->GetSlotId("A").IsValid()); // execute post-remove of "A" slot graphEntity->Activate(); ReportErrors(graph); graphEntity->Deactivate(); if (auto result = GetInput_UNIT_TEST(numberResultNode, "Set")) { SC_EXPECT_DOUBLE_EQ(4.0 + 8.0 + 16.0, *result); } else { ADD_FAILURE(); } graphEntity.reset(); } TEST_F(ScriptCanvasTestFixture, AddRemoveSlotNotifications) { RegisterComponentDescriptor(); using namespace ScriptCanvas; using namespace Nodes; AZStd::unique_ptr numberAddEntity = AZStd::make_unique("numberAddEntity"); auto numberAddNode = numberAddEntity->CreateComponent(); numberAddEntity->Init(); ScriptUnitTestNodeNotificationHandler nodeNotifications(numberAddNode->GetEntityId()); SlotId testSlotId = numberAddNode->AddSlot("test"); EXPECT_EQ(1U, nodeNotifications.GetSlotsAdded()); numberAddNode->RemoveSlot(testSlotId); EXPECT_EQ(1U, nodeNotifications.GetSlotsRemoved()); testSlotId = numberAddNode->AddSlot("duplicate"); EXPECT_EQ(2U, nodeNotifications.GetSlotsAdded()); // This should not signal the NodeNotification::OnSlotAdded event as the slot already exist on the node SlotId duplicateSlotId = numberAddNode->AddSlot("duplicate"); EXPECT_EQ(2U, nodeNotifications.GetSlotsAdded()); EXPECT_EQ(testSlotId, duplicateSlotId); numberAddNode->RemoveSlot(testSlotId); EXPECT_EQ(2U, nodeNotifications.GetSlotsRemoved()); // This should not signal the NodeNotification::OnSlotRemoved event as the slot no longer exist on the node numberAddNode->RemoveSlot(testSlotId); EXPECT_EQ(2U, nodeNotifications.GetSlotsRemoved()); numberAddEntity.reset(); } TEST_F(ScriptCanvasTestFixture, InsertSlot_Basic) { using namespace ScriptCanvas; Graph* graph = CreateGraph(); ConfigurableUnitTestNode* basicNode = CreateConfigurableNode(); SlotId firstSlotAdded; SlotId secondSlotAdded; SlotId thirdSlotAdded; { DataSlotConfiguration slotConfiguration; slotConfiguration.m_name = "A"; slotConfiguration.SetDefaultValue(0); slotConfiguration.SetConnectionType(ConnectionType::Input); Slot* slot = basicNode->AddTestingSlot(slotConfiguration); firstSlotAdded = slot->GetId(); } { DataSlotConfiguration slotConfiguration; slotConfiguration.m_name = "C"; slotConfiguration.SetDefaultValue(2); slotConfiguration.SetConnectionType(ConnectionType::Input); Slot* slot = basicNode->AddTestingSlot(slotConfiguration); secondSlotAdded = slot->GetId(); } { DataSlotConfiguration slotConfiguration; slotConfiguration.m_name = "B"; slotConfiguration.SetDefaultValue(1); slotConfiguration.SetConnectionType(ConnectionType::Input); auto index = basicNode->FindSlotIndex(secondSlotAdded); EXPECT_EQ(index, 1); Slot* slot = basicNode->InsertTestingSlot(index, slotConfiguration); thirdSlotAdded = slot->GetId(); } { AZStd::vector< const Slot* > slotList = basicNode->GetAllSlots(); EXPECT_EQ(slotList.size(), 3); { const Slot* firstSlot = slotList[0]; EXPECT_EQ(firstSlot->GetId(), firstSlotAdded); EXPECT_EQ(firstSlot->GetName(), "A"); EXPECT_FLOAT_EQ(static_cast((*firstSlot->FindDatum()->GetAs())), 0.0f); } { const Slot* secondSlot = slotList[1]; EXPECT_EQ(secondSlot->GetId(), thirdSlotAdded); EXPECT_EQ(secondSlot->GetName(), "B"); EXPECT_FLOAT_EQ(static_cast((*secondSlot->FindDatum()->GetAs())), 1.0f); } { const Slot* thirdSlot = slotList[2]; EXPECT_EQ(thirdSlot->GetId(), secondSlotAdded); EXPECT_EQ(thirdSlot->GetName(), "C"); EXPECT_FLOAT_EQ(static_cast((*thirdSlot->FindDatum()->GetAs())), 2.0f); } } graph->Activate(); { AZStd::vector< const Slot* > slotList = basicNode->GetAllSlots(); EXPECT_EQ(slotList.size(), 3); { const Slot* firstSlot = slotList[0]; EXPECT_EQ(firstSlot->GetId(), firstSlotAdded); EXPECT_EQ(firstSlot->GetName(), "A"); EXPECT_FLOAT_EQ(static_cast((*firstSlot->FindDatum()->GetAs())), 0.0f); } { const Slot* secondSlot = slotList[1]; EXPECT_EQ(secondSlot->GetId(), thirdSlotAdded); EXPECT_EQ(secondSlot->GetName(), "B"); EXPECT_FLOAT_EQ(static_cast((*secondSlot->FindDatum()->GetAs())), 1.0f); } { const Slot* thirdSlot = slotList[2]; EXPECT_EQ(thirdSlot->GetId(), secondSlotAdded); EXPECT_EQ(thirdSlot->GetName(), "C"); EXPECT_FLOAT_EQ(static_cast((*thirdSlot->FindDatum()->GetAs())), 2.0f); } } graph->Deactivate(); { AZStd::vector< const Slot* > slotList = basicNode->GetAllSlots(); EXPECT_EQ(slotList.size(), 3); { const Slot* firstSlot = slotList[0]; EXPECT_EQ(firstSlot->GetId(), firstSlotAdded); EXPECT_EQ(firstSlot->GetName(), "A"); EXPECT_FLOAT_EQ(static_cast((*firstSlot->FindDatum()->GetAs())), 0.0f); } { const Slot* secondSlot = slotList[1]; EXPECT_EQ(secondSlot->GetId(), thirdSlotAdded); EXPECT_EQ(secondSlot->GetName(), "B"); EXPECT_FLOAT_EQ(static_cast((*secondSlot->FindDatum()->GetAs())), 1.0f); } { const Slot* thirdSlot = slotList[2]; EXPECT_EQ(thirdSlot->GetId(), secondSlotAdded); EXPECT_EQ(thirdSlot->GetName(), "C"); EXPECT_FLOAT_EQ(static_cast((*thirdSlot->FindDatum()->GetAs())), 2.0f); } } } TEST_F(ScriptCanvasTestFixture, InsertSlot_FrontPadded) { using namespace ScriptCanvas; Graph* graph = CreateGraph(); ConfigurableUnitTestNode* basicNode = CreateConfigurableNode(); basicNode->AddTestingSlot(ExecutionSlotConfiguration("Input", ConnectionType::Input)); basicNode->AddTestingSlot(ExecutionSlotConfiguration("Input-1", ConnectionType::Input)); basicNode->AddTestingSlot(ExecutionSlotConfiguration("Input-2", ConnectionType::Input)); basicNode->AddTestingSlot(ExecutionSlotConfiguration("Input-3", ConnectionType::Input)); SlotId firstSlotAdded; SlotId secondSlotAdded; SlotId thirdSlotAdded; { DataSlotConfiguration slotConfiguration; slotConfiguration.m_name = "A"; slotConfiguration.SetDefaultValue(0); slotConfiguration.SetConnectionType(ConnectionType::Input); Slot* slot = basicNode->AddTestingSlot(slotConfiguration); firstSlotAdded = slot->GetId(); } { DataSlotConfiguration slotConfiguration; slotConfiguration.m_name = "C"; slotConfiguration.SetDefaultValue(2); slotConfiguration.SetConnectionType(ConnectionType::Input); Slot* slot = basicNode->AddTestingSlot(slotConfiguration); secondSlotAdded = slot->GetId(); } { DataSlotConfiguration slotConfiguration; slotConfiguration.m_name = "B"; slotConfiguration.SetDefaultValue(1); slotConfiguration.SetConnectionType(ConnectionType::Input); auto index = basicNode->FindSlotIndex(secondSlotAdded); Slot* slot = basicNode->InsertTestingSlot(index, slotConfiguration); thirdSlotAdded = slot->GetId(); } { AZStd::vector< const Slot* > slotList = basicNode->FindSlotsByDescriptor(SlotDescriptors::DataIn()); EXPECT_EQ(slotList.size(), 3); { const Slot* firstSlot = slotList[0]; EXPECT_EQ(firstSlot->GetId(), firstSlotAdded); EXPECT_EQ(firstSlot->GetName(), "A"); EXPECT_FLOAT_EQ(static_cast((*firstSlot->FindDatum()->GetAs())), 0.0f); } { const Slot* secondSlot = slotList[1]; EXPECT_EQ(secondSlot->GetId(), thirdSlotAdded); EXPECT_EQ(secondSlot->GetName(), "B"); EXPECT_FLOAT_EQ(static_cast((*secondSlot->FindDatum()->GetAs())), 1.0f); } { const Slot* thirdSlot = slotList[2]; EXPECT_EQ(thirdSlot->GetId(), secondSlotAdded); EXPECT_EQ(thirdSlot->GetName(), "C"); EXPECT_FLOAT_EQ(static_cast((*thirdSlot->FindDatum()->GetAs())), 2.0f); } } graph->Activate(); { AZStd::vector< const Slot* > slotList = basicNode->FindSlotsByDescriptor(SlotDescriptors::DataIn()); EXPECT_EQ(slotList.size(), 3); { const Slot* firstSlot = slotList[0]; EXPECT_EQ(firstSlot->GetId(), firstSlotAdded); EXPECT_EQ(firstSlot->GetName(), "A"); EXPECT_FLOAT_EQ(static_cast((*firstSlot->FindDatum()->GetAs())), 0.0f); } { const Slot* secondSlot = slotList[1]; EXPECT_EQ(secondSlot->GetId(), thirdSlotAdded); EXPECT_EQ(secondSlot->GetName(), "B"); EXPECT_FLOAT_EQ(static_cast((*secondSlot->FindDatum()->GetAs())), 1.0f); } { const Slot* thirdSlot = slotList[2]; EXPECT_EQ(thirdSlot->GetId(), secondSlotAdded); EXPECT_EQ(thirdSlot->GetName(), "C"); EXPECT_FLOAT_EQ(static_cast((*thirdSlot->FindDatum()->GetAs())), 2.0f); } } graph->Deactivate(); { AZStd::vector< const Slot* > slotList = basicNode->FindSlotsByDescriptor(SlotDescriptors::DataIn()); EXPECT_EQ(slotList.size(), 3); { const Slot* firstSlot = slotList[0]; EXPECT_EQ(firstSlot->GetId(), firstSlotAdded); EXPECT_EQ(firstSlot->GetName(), "A"); EXPECT_FLOAT_EQ(static_cast((*firstSlot->FindDatum()->GetAs())), 0.0f); } { const Slot* secondSlot = slotList[1]; EXPECT_EQ(secondSlot->GetId(), thirdSlotAdded); EXPECT_EQ(secondSlot->GetName(), "B"); EXPECT_FLOAT_EQ(static_cast((*secondSlot->FindDatum()->GetAs())), 1.0f); } { const Slot* thirdSlot = slotList[2]; EXPECT_EQ(thirdSlot->GetId(), secondSlotAdded); EXPECT_EQ(thirdSlot->GetName(), "C"); EXPECT_FLOAT_EQ(static_cast((*thirdSlot->FindDatum()->GetAs())), 2.0f); } } } TEST_F(ScriptCanvasTestFixture, InsertSlot) { RegisterComponentDescriptor(); using namespace ScriptCanvas; using namespace Nodes; AZStd::unique_ptr graphEntity = AZStd::make_unique("RemoveSlotGraph"); graphEntity->Init(); SystemRequestBus::Broadcast(&SystemRequests::CreateEngineComponentsOnEntity, graphEntity.get()); Graph* graph = AZ::EntityUtils::FindFirstDerivedComponent(graphEntity.get()); ScriptCanvasId graphUniqueId = graph->GetScriptCanvasId(); AZ::EntityId outId; auto startNode = CreateTestNode(graphUniqueId, outId); auto insertSlotConcatNode = CreateTestNode(graphUniqueId, outId); auto setVariableNode = CreateTestNode(graphUniqueId, outId); VariableId resultVarId = CreateVariable(graphUniqueId, Data::StringType(), "result"); setVariableNode->SetId(resultVarId); EXPECT_TRUE(setVariableNode->GetDataInSlotId().IsValid()); //logic connections EXPECT_TRUE(Connect(*graph, startNode->GetEntityId(), "Out", insertSlotConcatNode->GetEntityId(), "In")); EXPECT_TRUE(Connect(*graph, insertSlotConcatNode->GetEntityId(), "Out", setVariableNode->GetEntityId(), "In")); // insert slots auto concatSlotId = insertSlotConcatNode->InsertSlot(-1, "A"); auto slotAId = concatSlotId; SetInput_UNIT_TEST(insertSlotConcatNode, concatSlotId, Data::StringType("Hello")); concatSlotId = insertSlotConcatNode->InsertSlot(-1, "B"); auto slotBId = concatSlotId; SetInput_UNIT_TEST(insertSlotConcatNode, concatSlotId, Data::StringType(" World")); // data connections EXPECT_TRUE(graph->Connect(insertSlotConcatNode->GetEntityId(), insertSlotConcatNode->GetSlotId("Result"), setVariableNode->GetEntityId(), setVariableNode->GetDataInSlotId())); graphEntity->Activate(); ReportErrors(graph); graphEntity->Deactivate(); const GraphVariable* resultDatum{}; VariableRequestBus::EventResult(resultDatum, GraphScopedVariableId(graphUniqueId, resultVarId), &VariableRequests::GetVariableConst); ASSERT_NE(nullptr, resultDatum); EXPECT_EQ("Hello World", resultDatum->GetDatum()->ToString()); // insert additional slot between A and B auto slotIndex = insertSlotConcatNode->FindSlotIndex(slotBId); EXPECT_GE(slotIndex, 0); concatSlotId = insertSlotConcatNode->InsertSlot(slotIndex, "Alpha"); SetInput_UNIT_TEST(insertSlotConcatNode, concatSlotId, Data::StringType(" Ice Cream")); // re-execute the graph graphEntity->Activate(); ReportErrors(graph); graphEntity->Deactivate(); // the new concatenated string should be in the middle EXPECT_EQ("Hello Ice Cream World", resultDatum->GetDatum()->ToString()); graphEntity.reset(); } TEST_F(ScriptCanvasTestFixture, NativeProperties) { using namespace ScriptCanvas; using namespace Nodes; AZ::Entity* graphEntity = aznew AZ::Entity("Graph"); graphEntity->Init(); SystemRequestBus::Broadcast(&SystemRequests::CreateGraphOnEntity, graphEntity); auto graph = graphEntity->FindComponent(); EXPECT_NE(nullptr, graph); const AZ::EntityId& graphEntityId = graph->GetEntityId(); const ScriptCanvasId& graphUniqueId = graph->GetScriptCanvasId(); AZ::EntityId startID; CreateTestNode(graphUniqueId, startID); AZ::EntityId addId; CreateTestNode(graphUniqueId, addId); AZ::EntityId vector3IdA, vector3IdB, vector3IdC; auto vector3NodeA = CreateTestNode(graphUniqueId, vector3IdA); auto vector3NodeB = CreateTestNode(graphUniqueId, vector3IdB); auto vector3NodeC = CreateTestNode(graphUniqueId, vector3IdC); AZ::EntityId number1Id, number2Id, number3Id, number4Id, number5Id, number6Id, number7Id, number8Id, number9Id; Node* number1Node = CreateDataNode(graphUniqueId, 1, number1Id); Node* number2Node = CreateDataNode(graphUniqueId, 2, number2Id); Node* number3Node = CreateDataNode(graphUniqueId, 3, number3Id); Node* number4Node = CreateDataNode(graphUniqueId, 4, number4Id); Node* number5Node = CreateDataNode(graphUniqueId, 5, number5Id); Node* number6Node = CreateDataNode(graphUniqueId, 6, number6Id); Node* number7Node = CreateDataNode(graphUniqueId, 7, number7Id); Node* number8Node = CreateDataNode(graphUniqueId, 8, number8Id); Node* number9Node = CreateDataNode(graphUniqueId, 0, number9Id); // data EXPECT_TRUE(Connect(*graph, number1Id, "Get", vector3IdA, "Number: x")); EXPECT_TRUE(Connect(*graph, number2Id, "Get", vector3IdA, "Number: y")); EXPECT_TRUE(Connect(*graph, number3Id, "Get", vector3IdA, "Number: z")); EXPECT_TRUE(Connect(*graph, number4Id, "Get", vector3IdB, "Number: x")); EXPECT_TRUE(Connect(*graph, number5Id, "Get", vector3IdB, "Number: y")); EXPECT_TRUE(Connect(*graph, number6Id, "Get", vector3IdB, "Number: z")); EXPECT_TRUE(Connect(*graph, vector3IdA, "Get", addId, "Vector3: A")); EXPECT_TRUE(Connect(*graph, vector3IdB, "Get", addId, "Vector3: B")); EXPECT_TRUE(Connect(*graph, addId, "Result: Vector3", vector3IdC, "Set")); EXPECT_TRUE(Connect(*graph, vector3IdC, "x: Number", number7Id, "Set")); EXPECT_TRUE(Connect(*graph, vector3IdC, "y: Number", number8Id, "Set")); EXPECT_TRUE(Connect(*graph, vector3IdC, "z: Number", number9Id, "Set")); // code EXPECT_TRUE(Connect(*graph, startID, "Out", addId, "In")); graphEntity->Activate(); ReportErrors(graph); if (auto result = GetInput_UNIT_TEST(vector3NodeC, "Set")) { EXPECT_EQ(AZ::Vector3(5, 7, 9), *result); } else { ADD_FAILURE(); } if (auto result = GetInput_UNIT_TEST(number7Node, "Set")) { EXPECT_EQ(5, *result); } else { ADD_FAILURE(); } if (auto result = GetInput_UNIT_TEST(number8Node, "Set")) { EXPECT_EQ(7, *result); } else { ADD_FAILURE(); } if (auto result = GetInput_UNIT_TEST(number9Node, "Set")) { EXPECT_EQ(9, *result); } else { ADD_FAILURE(); } graphEntity->Deactivate(); delete graphEntity; } TEST_F(ScriptCanvasTestFixture, ExtractPropertiesNativeType) { // TODO: Add Extract test for all Native Types using namespace ScriptCanvas; using namespace Nodes; AZStd::unique_ptr graphEntity = AZStd::make_unique("PropertyGraph"); Graph* graph{}; SystemRequestBus::BroadcastResult(graph, &SystemRequests::CreateGraphOnEntity, graphEntity.get()); ASSERT_NE(nullptr, graph); AZ::EntityId propertyEntityId = graphEntity->GetId(); ScriptCanvasId graphUniqueId = graph->GetScriptCanvasId(); graphEntity->Init(); // Create Extract Property Node AZ::EntityId outID; auto startNode = CreateTestNode(graphUniqueId, outID); auto extractPropertyNode = CreateTestNode(graphUniqueId, outID); auto printNode = CreateTestNode(graphUniqueId, outID); // Test Native Vector3 Properties auto vector3Node = CreateDataNode(graphUniqueId, Data::Vector3Type(10.0f, 23.3f, 77.45f), outID); auto numberResultNode1 = CreateDataNode(graphUniqueId, 0.0f, outID); auto numberResultNode2 = CreateDataNode(graphUniqueId, 0.0f, outID); auto numberResultNode3 = CreateDataNode(graphUniqueId, 0.0f, outID); // data EXPECT_EQ(0, extractPropertyNode->GetPropertyFields().size()); EXPECT_FALSE(extractPropertyNode->GetSourceSlotDataType().IsValid()); EXPECT_TRUE(Connect(*graph, vector3Node->GetEntityId(), "Get", extractPropertyNode->GetEntityId(), "Source")); auto propertyFields = extractPropertyNode->GetPropertyFields(); EXPECT_EQ(3, propertyFields.size()); EXPECT_TRUE(extractPropertyNode->GetSourceSlotDataType().IS_A(Data::Type::Vector3())); // Vector3::x auto propIt = AZStd::find_if(propertyFields.begin(), propertyFields.end(), [](const AZStd::pair propertyField) { return propertyField.first == "x"; }); ASSERT_NE(propIt, propertyFields.end()); EXPECT_TRUE(graph->Connect(extractPropertyNode->GetEntityId(), propIt->second, numberResultNode1->GetEntityId(), numberResultNode1->GetSlotId("Set"))); // Vector3::y propIt = AZStd::find_if(propertyFields.begin(), propertyFields.end(), [](const AZStd::pair propertyField) { return propertyField.first == "y"; }); ASSERT_NE(propIt, propertyFields.end()); EXPECT_TRUE(graph->Connect(extractPropertyNode->GetEntityId(), propIt->second, numberResultNode2->GetEntityId(), numberResultNode2->GetSlotId("Set"))); // Vector3::z propIt = AZStd::find_if(propertyFields.begin(), propertyFields.end(), [](const AZStd::pair propertyField) { return propertyField.first == "z"; }); ASSERT_NE(propIt, propertyFields.end()); EXPECT_TRUE(graph->Connect(extractPropertyNode->GetEntityId(), propIt->second, numberResultNode3->GetEntityId(), numberResultNode3->GetSlotId("Set"))); // Print the z value to console EXPECT_TRUE(graph->Connect(numberResultNode3->GetEntityId(), numberResultNode3->GetSlotId("Get"), printNode->GetEntityId(), printNode->GetSlotId("Value"))); // logic EXPECT_TRUE(Connect(*graph, startNode->GetEntityId(), "Out", extractPropertyNode->GetEntityId(), "In")); EXPECT_TRUE(Connect(*graph, extractPropertyNode->GetEntityId(), "Out", printNode->GetEntityId(), "In")); // execute { ScriptCanvasEditor::ScopedOutputSuppression suppressOutput; graphEntity->Activate(); } ReportErrors(graph); graphEntity->Deactivate(); AZ::Entity* connectionEntity{}; EXPECT_TRUE(graph->FindConnection(connectionEntity, { vector3Node->GetEntityId(), vector3Node->GetSlotId("Get") }, { extractPropertyNode->GetEntityId(), extractPropertyNode->GetSlotId("Source") })); EXPECT_TRUE(graph->DisconnectById(connectionEntity->GetId())); const float tolerance = 0.001f; // x result auto vectorElementResult = GetInput_UNIT_TEST(numberResultNode1, "Set"); ASSERT_NE(nullptr, vectorElementResult); EXPECT_NEAR(10.0f, *vectorElementResult, tolerance); // y result vectorElementResult = GetInput_UNIT_TEST(numberResultNode2, "Set"); ASSERT_NE(nullptr, vectorElementResult); EXPECT_NEAR(23.3f, *vectorElementResult, tolerance); // z result vectorElementResult = GetInput_UNIT_TEST(numberResultNode3, "Set"); ASSERT_NE(nullptr, vectorElementResult); EXPECT_NEAR(77.45f, *vectorElementResult, tolerance); graphEntity.reset(); } TEST_F(ScriptCanvasTestFixture, ExtractPropertiesBehaviorType) { TestBehaviorContextProperties::Reflect(m_serializeContext); TestBehaviorContextProperties::Reflect(m_behaviorContext); using namespace ScriptCanvas; using namespace Nodes; AZStd::unique_ptr graphEntity = AZStd::make_unique("PropertyGraph"); Graph* graph{}; SystemRequestBus::BroadcastResult(graph, &SystemRequests::CreateGraphOnEntity, graphEntity.get()); ASSERT_NE(nullptr, graph); AZ::EntityId propertyEntityId = graphEntity->GetId(); ScriptCanvasId graphUniqueId = graph->GetScriptCanvasId(); graphEntity->Init(); // Create Extract Property Node AZ::EntityId outID; auto startNode = CreateTestNode(graphUniqueId, outID); auto extractPropertyNode = CreateTestNode(graphUniqueId, outID); auto printNode = CreateTestNode(graphUniqueId, outID); // Test BehaviorContext Properties TestBehaviorContextProperties behaviorContextProperties; behaviorContextProperties.m_booleanProp = true; behaviorContextProperties.m_numberProp = 11.90f; behaviorContextProperties.m_stringProp = "String Property"; auto behaviorContextPropertyNode = CreateDataNode(graphUniqueId, behaviorContextProperties, outID); auto booleanResultNode = CreateDataNode(graphUniqueId, false, outID); auto numberResultNode = CreateDataNode(graphUniqueId, 0.0f, outID); auto stringResultNode = CreateDataNode(graphUniqueId, Data::StringType("Uninitialized"), outID); // data EXPECT_EQ(0, extractPropertyNode->GetPropertyFields().size()); EXPECT_FALSE(extractPropertyNode->GetSourceSlotDataType().IsValid()); EXPECT_TRUE(Connect(*graph, behaviorContextPropertyNode->GetEntityId(), "Get", extractPropertyNode->GetEntityId(), "Source")); auto propertyFields = extractPropertyNode->GetPropertyFields(); EXPECT_EQ(4, propertyFields.size()); EXPECT_TRUE(extractPropertyNode->GetSourceSlotDataType().IS_A(Data::FromAZType())); // TestBehaviorContextProperties::boolean auto propIt = AZStd::find_if(propertyFields.begin(), propertyFields.end(), [](const AZStd::pair propertyField) { return propertyField.first == "boolean"; }); ASSERT_NE(propIt, propertyFields.end()); EXPECT_TRUE(graph->Connect(extractPropertyNode->GetEntityId(), propIt->second, booleanResultNode->GetEntityId(), booleanResultNode->GetSlotId("Set"))); // TestBehaviorContextProperties::number propIt = AZStd::find_if(propertyFields.begin(), propertyFields.end(), [](const AZStd::pair propertyField) { return propertyField.first == "number"; }); ASSERT_NE(propIt, propertyFields.end()); EXPECT_TRUE(graph->Connect(extractPropertyNode->GetEntityId(), propIt->second, numberResultNode->GetEntityId(), numberResultNode->GetSlotId("Set"))); // TestBehaviorContextProperties::string propIt = AZStd::find_if(propertyFields.begin(), propertyFields.end(), [](const AZStd::pair propertyField) { return propertyField.first == "string"; }); ASSERT_NE(propIt, propertyFields.end()); EXPECT_TRUE(graph->Connect(extractPropertyNode->GetEntityId(), propIt->second, stringResultNode->GetEntityId(), stringResultNode->GetSlotId("Set"))); // Print the string value to console EXPECT_TRUE(graph->Connect(stringResultNode->GetEntityId(), stringResultNode->GetSlotId("Get"), printNode->GetEntityId(), printNode->GetSlotId("Value"))); // logic EXPECT_TRUE(Connect(*graph, startNode->GetEntityId(), "Out", extractPropertyNode->GetEntityId(), "In")); EXPECT_TRUE(Connect(*graph, extractPropertyNode->GetEntityId(), "Out", printNode->GetEntityId(), "In")); // execute { ScriptCanvasEditor::ScopedOutputSuppression suppressOutput; graphEntity->Activate(); } ReportErrors(graph); graphEntity->Deactivate(); AZ::Entity* connectionEntity{}; EXPECT_TRUE(graph->FindConnection(connectionEntity, { behaviorContextPropertyNode->GetEntityId(), behaviorContextPropertyNode->GetSlotId("Get") }, { extractPropertyNode->GetEntityId(), extractPropertyNode->GetSlotId("Source") })); EXPECT_TRUE(graph->DisconnectById(connectionEntity->GetId())); // boolean result auto booleanResult = GetInput_UNIT_TEST(booleanResultNode, "Set"); ASSERT_NE(nullptr, booleanResult); EXPECT_TRUE(booleanResult); // number result const float tolerance = 0.001f; auto numberResult = GetInput_UNIT_TEST(numberResultNode, "Set"); ASSERT_NE(nullptr, numberResult); EXPECT_NEAR(11.90f, *numberResult, tolerance); // string result auto stringResult = GetInput_UNIT_TEST(stringResultNode, "Set"); ASSERT_NE(nullptr, stringResult); EXPECT_EQ("String Property", *stringResult); graphEntity.reset(); m_serializeContext->EnableRemoveReflection(); TestBehaviorContextProperties::Reflect(m_serializeContext); m_serializeContext->DisableRemoveReflection(); m_behaviorContext->EnableRemoveReflection(); TestBehaviorContextProperties::Reflect(m_behaviorContext); m_behaviorContext->DisableRemoveReflection(); } TEST_F(ScriptCanvasTestFixture, IsNullCheck) { using namespace ScriptCanvas; EventTestHandler::Reflect(m_serializeContext); EventTestHandler::Reflect(m_behaviorContext); TestBehaviorContextObject::Reflect(m_serializeContext); TestBehaviorContextObject::Reflect(m_behaviorContext); Graph* graph(nullptr); SystemRequestBus::BroadcastResult(graph, &SystemRequests::MakeGraph); EXPECT_TRUE(graph != nullptr); graph->GetEntity()->Init(); const AZ::EntityId& graphEntityID = graph->GetEntityId(); const ScriptCanvasId& graphUniqueId = graph->GetScriptCanvasId(); AZ::EntityId startID; CreateTestNode(graphUniqueId, startID); AZ::EntityId isNullFalseID; CreateTestNode(graphUniqueId, isNullFalseID); AZ::EntityId isNullTrueID; CreateTestNode(graphUniqueId, isNullTrueID); AZ::EntityId isNullResultFalseID; auto isNullResultFalse = CreateDataNode(graphUniqueId, true, isNullResultFalseID); AZ::EntityId isNullResultTrueID; auto isNullResultTrue = CreateDataNode(graphUniqueId, false, isNullResultTrueID); AZ::EntityId normalizeID; Nodes::Core::Method* normalize = CreateTestNode(graphUniqueId, normalizeID); Namespaces empty; normalize->InitializeClass(empty, "TestBehaviorContextObject", "Normalize"); AZ::EntityId vectorID; Nodes::Core::BehaviorContextObjectNode* vector = CreateTestNode(graphUniqueId, vectorID); const AZStd::string vector3("TestBehaviorContextObject"); vector->InitializeObject(vector3); if (auto vector3_2 = ModInput_UNIT_TEST(vector, "Set")) { EXPECT_FALSE(vector3_2->IsNormalized()); } else { ADD_FAILURE(); } // test the reference type contract { ScriptCanvasEditor::ScopedOutputSuppression suppressOutput; EXPECT_FALSE(Connect(*graph, isNullResultFalseID, "Get", isNullTrueID, "Reference")); } // data EXPECT_TRUE(Connect(*graph, vectorID, "Get", normalizeID, "TestBehaviorContextObject: 0")); EXPECT_TRUE(Connect(*graph, vectorID, "Get", isNullFalseID, "Reference")); EXPECT_TRUE(Connect(*graph, isNullTrueID, "Is Null", isNullResultTrueID, "Set")); EXPECT_TRUE(Connect(*graph, isNullFalseID, "Is Null", isNullResultFalseID, "Set")); // execution EXPECT_TRUE(Connect(*graph, startID, "Out", isNullTrueID, "In")); EXPECT_TRUE(Connect(*graph, isNullTrueID, "True", isNullFalseID, "In")); EXPECT_TRUE(Connect(*graph, isNullFalseID, "False", normalizeID, "In")); AZ::Entity* graphEntity = graph->GetEntity(); { ScriptCanvasEditor::ScopedOutputSuppression suppressOutput; graphEntity->Activate(); } ReportErrors(graph); if (auto vector3_2 = GetInput_UNIT_TEST(vector, "Set")) { EXPECT_TRUE(vector3_2->IsNormalized()); } else { ADD_FAILURE(); } if (auto shouldBeFalse = GetInput_UNIT_TEST(isNullResultFalse, "Set")) { EXPECT_FALSE(*shouldBeFalse); } else { ADD_FAILURE(); } if (auto shouldBeTrue = GetInput_UNIT_TEST(isNullResultTrue, "Set")) { EXPECT_TRUE(*shouldBeTrue); } else { ADD_FAILURE(); } graphEntity->Deactivate(); delete graphEntity; m_serializeContext->EnableRemoveReflection(); m_behaviorContext->EnableRemoveReflection(); EventTestHandler::Reflect(m_serializeContext); EventTestHandler::Reflect(m_behaviorContext); TestBehaviorContextObject::Reflect(m_serializeContext); TestBehaviorContextObject::Reflect(m_behaviorContext); m_serializeContext->DisableRemoveReflection(); m_behaviorContext->DisableRemoveReflection(); } TEST_F(ScriptCanvasTestFixture, NullThisPointerDoesNotCrash) { using namespace ScriptCanvas; EventTestHandler::Reflect(m_serializeContext); EventTestHandler::Reflect(m_behaviorContext); TestBehaviorContextObject::Reflect(m_serializeContext); TestBehaviorContextObject::Reflect(m_behaviorContext); Graph* graph(nullptr); SystemRequestBus::BroadcastResult(graph, &SystemRequests::MakeGraph); EXPECT_TRUE(graph != nullptr); graph->GetEntity()->Init(); const AZ::EntityId& graphEntityID = graph->GetEntityId(); const ScriptCanvasId& graphUniqueId = graph->GetScriptCanvasId(); AZ::EntityId startID; CreateTestNode(graphUniqueId, startID); AZ::EntityId normalizeID; Nodes::Core::Method* normalize = CreateTestNode(graphUniqueId, normalizeID); Namespaces empty; normalize->InitializeClass(empty, "TestBehaviorContextObject", "Normalize"); EXPECT_TRUE(Connect(*graph, startID, "Out", normalizeID, "In")); AZ::Entity* graphEntity = graph->GetEntity(); { ScriptCanvasEditor::ScopedOutputSuppression suppressOutput; graphEntity->Activate(); } // just don't crash, but be in error const bool expectError = true; const bool expectIrrecoverableError = true; ReportErrors(graph, expectError, expectIrrecoverableError); graphEntity->Deactivate(); delete graphEntity; m_serializeContext->EnableRemoveReflection(); m_behaviorContext->EnableRemoveReflection(); EventTestHandler::Reflect(m_serializeContext); EventTestHandler::Reflect(m_behaviorContext); TestBehaviorContextObject::Reflect(m_serializeContext); TestBehaviorContextObject::Reflect(m_behaviorContext); m_serializeContext->DisableRemoveReflection(); m_behaviorContext->DisableRemoveReflection(); } TEST_F(ScriptCanvasTestFixture, ValueTypes) { using namespace ScriptCanvas; Datum number0(Datum(0)); int number0Value = *number0.GetAs(); Datum number1(Datum(1)); int number1Value = *number1.GetAs(); Datum numberFloat(Datum(2.f)); float numberFloatValue = *numberFloat.GetAs(); Datum numberDouble(Datum(3.0)); double numberDoubleValue = *numberDouble.GetAs(); Datum numberHex(Datum(0xff)); int numberHexValue = *numberHex.GetAs(); Datum numberPi(Datum(3.14f)); float numberPiValue = *numberPi.GetAs(); Datum numberSigned(Datum(-100)); int numberSignedValue = *numberSigned.GetAs(); Datum numberUnsigned(Datum(100u)); unsigned int numberUnsignedValue = *numberUnsigned.GetAs(); Datum numberDoublePi(Datum(6.28)); double numberDoublePiValue = *numberDoublePi.GetAs(); EXPECT_EQ(number0Value, 0); EXPECT_EQ(number1Value, 1); EXPECT_TRUE(AZ::IsClose(numberFloatValue, 2.f, std::numeric_limits::epsilon())); EXPECT_TRUE(AZ::IsClose(numberDoubleValue, 3.0, std::numeric_limits::epsilon())); EXPECT_NE(number0Value, number1Value); SC_EXPECT_FLOAT_EQ(numberPiValue, 3.14f); EXPECT_NE(number0Value, numberPiValue); EXPECT_NE(numberPiValue, numberDoublePiValue); Datum boolTrue(Datum(true)); EXPECT_TRUE(*boolTrue.GetAs()); Datum boolFalse(Datum(false)); EXPECT_FALSE(*boolFalse.GetAs()); boolFalse = boolTrue; EXPECT_TRUE(*boolFalse.GetAs()); Datum boolFalse2(Datum(false)); boolTrue = boolFalse2; EXPECT_FALSE(*boolTrue.GetAs()); { const int k_count(10000); AZStd::vector objects; for (int i = 0; i < k_count; ++i) { objects.push_back(Datum("Vector3", Datum::eOriginality::Original)); } } GTEST_SUCCEED(); } namespace { using namespace ScriptCanvas; using namespace ScriptCanvas::Nodes; bool GraphHasVectorWithValue(const Graph& graph, const AZ::Vector3& vector) { for (auto nodeId : graph.GetNodes()) { AZ::Entity* entity{}; AZ::ComponentApplicationBus::BroadcastResult(entity, &AZ::ComponentApplicationRequests::FindEntity, nodeId); if (entity) { if (auto node = AZ::EntityUtils::FindFirstDerivedComponent(entity)) { if (auto candidate = NodeAccessor::GetInput_UNIT_TEST(node, "Set")) { if (*candidate == vector) { return true; } } } } } return false; } } TEST_F(ScriptCanvasTestFixture, SerializationSaveTest) { using namespace ScriptCanvas; using namespace ScriptCanvas::Nodes; ////////////////////////////////////////////////////////////////////////// // Make the graph. Graph* graph = nullptr; SystemRequestBus::BroadcastResult(graph, &SystemRequests::MakeGraph); EXPECT_TRUE(graph != nullptr); graph->GetEntity()->Init(); const AZ::EntityId& graphEntityId = graph->GetEntityId(); const ScriptCanvasId& graphUniqueId = graph->GetScriptCanvasId(); // Make the nodes. // Start AZ::Entity* startEntity{ aznew AZ::Entity }; startEntity->Init(); AZ::EntityId startNode{ startEntity->GetId() }; SystemRequestBus::Broadcast(&SystemRequests::CreateNodeOnEntity, startNode, graphUniqueId, Nodes::Core::Start::TYPEINFO_Uuid()); // Constant 0 AZ::Entity* constant0Entity{ aznew AZ::Entity }; constant0Entity->Init(); AZ::EntityId constant0Node{ constant0Entity->GetId() }; SystemRequestBus::Broadcast(&SystemRequests::CreateNodeOnEntity, constant0Node, graphUniqueId, Nodes::Math::Number::TYPEINFO_Uuid()); // Get the node and set the value Nodes::Math::Number* constant0NodePtr = nullptr; SystemRequestBus::BroadcastResult(constant0NodePtr, &SystemRequests::GetNode, constant0Node); EXPECT_TRUE(constant0NodePtr != nullptr); if (constant0NodePtr) { SetInput_UNIT_TEST(constant0NodePtr, "Set", 4); } // Constant 1 AZ::Entity* constant1Entity{ aznew AZ::Entity }; constant1Entity->Init(); AZ::EntityId constant1Node{ constant1Entity->GetId() }; SystemRequestBus::Broadcast(&SystemRequests::CreateNodeOnEntity, constant1Node, graphUniqueId, Nodes::Math::Number::TYPEINFO_Uuid()); // Get the node and set the value Nodes::Math::Number* constant1NodePtr = nullptr; SystemRequestBus::BroadcastResult(constant1NodePtr, &SystemRequests::GetNode, constant1Node); EXPECT_TRUE(constant1NodePtr != nullptr); if (constant1NodePtr) { SetInput_UNIT_TEST(constant1NodePtr, "Set", 12); } // Sum AZ::Entity* sumEntity{ aznew AZ::Entity }; sumEntity->Init(); AZ::EntityId sumNode{ sumEntity->GetId() }; SystemRequestBus::Broadcast(&SystemRequests::CreateNodeOnEntity, sumNode, graphUniqueId, Nodes::Math::Sum::TYPEINFO_Uuid()); AZ::EntityId printID; auto printNode = CreateTestNode(graphUniqueId, printID); // Connect, disconnect and reconnect to validate disconnection graph->Connect(sumNode, AZ::EntityUtils::FindFirstDerivedComponent(sumEntity)->GetSlotId(BinaryOperator::k_lhsName), constant0Node, AZ::EntityUtils::FindFirstDerivedComponent(constant0Entity)->GetSlotId("Get")); graph->Disconnect(sumNode, AZ::EntityUtils::FindFirstDerivedComponent(sumEntity)->GetSlotId(BinaryOperator::k_lhsName), constant0Node, AZ::EntityUtils::FindFirstDerivedComponent(constant0Entity)->GetSlotId("Get")); graph->Connect(sumNode, AZ::EntityUtils::FindFirstDerivedComponent(sumEntity)->GetSlotId(BinaryOperator::k_lhsName), constant0Node, AZ::EntityUtils::FindFirstDerivedComponent(constant0Entity)->GetSlotId("Get")); { auto* sumNodePtr = AZ::EntityUtils::FindFirstDerivedComponent(sumEntity); EXPECT_NE(nullptr, sumNodePtr); EXPECT_EQ(1, graph->GetConnectedEndpoints({ sumNode, sumNodePtr->GetSlotId(BinaryOperator::k_lhsName) }).size()); } graph->Connect(sumNode, AZ::EntityUtils::FindFirstDerivedComponent(sumEntity)->GetSlotId(BinaryOperator::k_rhsName), constant1Node, AZ::EntityUtils::FindFirstDerivedComponent(constant1Entity)->GetSlotId("Get")); EXPECT_TRUE(Connect(*graph, sumNode, "Result", printID, "Value")); EXPECT_TRUE(Connect(*graph, startNode, "Out", sumNode, Nodes::BinaryOperator::k_evaluateName)); EXPECT_TRUE(Connect(*graph, sumNode, Nodes::BinaryOperator::k_outName, printID, "In")); AZ::EntityId vector3IdA, vector3IdB, vector3IdC; const AZ::Vector3 allOne(1, 1, 1); const AZ::Vector3 allTwo(2, 2, 2); const AZ::Vector3 allThree(3, 3, 3); const AZ::Vector3 allFour(4, 4, 4); Core::BehaviorContextObjectNode* vector3NodeA = CreateTestNode(graphUniqueId, vector3IdA); vector3NodeA->InitializeObject(azrtti_typeid()); *ModInput_UNIT_TEST(vector3NodeA, "Set") = allOne; Core::BehaviorContextObjectNode* vector3NodeB = CreateTestNode(graphUniqueId, vector3IdB); vector3NodeB->InitializeObject(azrtti_typeid()); *ModInput_UNIT_TEST(vector3NodeB, "Set") = allTwo; Core::BehaviorContextObjectNode* vector3NodeC = CreateTestNode(graphUniqueId, vector3IdC); vector3NodeC->InitializeObject(azrtti_typeid()); *ModInput_UNIT_TEST(vector3NodeC, "Set") = allFour; AZ::EntityId add3IdA; CreateTestNode(graphUniqueId, add3IdA); EXPECT_TRUE(Connect(*graph, printID, "Out", add3IdA, "In")); EXPECT_TRUE(Connect(*graph, vector3IdA, "Get", add3IdA, "Vector3: A")); EXPECT_TRUE(Connect(*graph, vector3IdB, "Get", add3IdA, "Vector3: B")); EXPECT_TRUE(Connect(*graph, vector3IdC, "Set", add3IdA, "Result: Vector3")); AZStd::unique_ptr graphEntity{ graph->GetEntity() }; EXPECT_EQ(allOne, *GetInput_UNIT_TEST(vector3NodeA, "Set")); EXPECT_EQ(allTwo, *GetInput_UNIT_TEST(vector3NodeB, "Set")); auto vector3C = *GetInput_UNIT_TEST(vector3NodeC, "Set"); EXPECT_EQ(allFour, vector3C); auto nodeIDs = graph->GetNodes(); EXPECT_EQ(9, nodeIDs.size()); ScriptCanvasEditor::TraceSuppressionBus::Broadcast(&ScriptCanvasEditor::TraceSuppressionRequests::SuppressPrintf, true); graphEntity->Activate(); ScriptCanvasEditor::TraceSuppressionBus::Broadcast(&ScriptCanvasEditor::TraceSuppressionRequests::SuppressPrintf, false); ReportErrors(graph); vector3C = *GetInput_UNIT_TEST(vector3NodeC, "Set"); EXPECT_EQ(allThree, vector3C); if (auto result = GetInput_UNIT_TEST(printNode, "Value")) { SC_EXPECT_FLOAT_EQ(*result, 16.0f); } else { ADD_FAILURE(); } graphEntity->Deactivate(); auto* fileIO = AZ::IO::LocalFileIO::GetInstance(); EXPECT_TRUE(fileIO != nullptr); auto pathResult = fileIO->CreatePath(k_tempCoreAssetDir);; EXPECT_EQ(pathResult.GetResultCode(), AZ::IO::ResultCode::Success) << "Path failed to create"; // Save it bool result = false; AZ::IO::FileIOStream outFileStream(k_tempCoreAssetPath, AZ::IO::OpenMode::ModeWrite); if (outFileStream.IsOpen()) { RuntimeAssetHandler runtimeAssetHandler; AZ::Data::Asset runtimeAsset = CreateRuntimeAsset(graph); EXPECT_TRUE(runtimeAssetHandler.SaveAssetData(runtimeAsset, &outFileStream)) << "Asset failed to save"; EXPECT_TRUE(fileIO->Exists(k_tempCoreAssetPath)); } else { ADD_FAILURE() << "File stream not open"; } outFileStream.Close(); } TEST_F(ScriptCanvasTestFixture, SerializationLoadTest_Graph) { using namespace ScriptCanvas; ////////////////////////////////////////////////////////////////////////// // Make the graph. Graph* graph = nullptr; AZStd::unique_ptr graphEntity = AZStd::make_unique("Loaded Graph"); SystemRequestBus::BroadcastResult(graph, &SystemRequests::CreateGraphOnEntity, graphEntity.get()); auto* fileIO = AZ::IO::LocalFileIO::GetInstance(); ASSERT_NE(nullptr, fileIO); EXPECT_TRUE(fileIO->Exists(k_tempCoreAssetPath)); // Load it AZ::Data::Asset runtimeAsset; runtimeAsset.Create(AZ::Uuid::CreateRandom()); AZ::u64 fileLength = 0; AZ::IO::FileIOBase::GetInstance()->Size(k_tempCoreAssetPath, fileLength); AZStd::shared_ptr stream = AZStd::make_shared(); stream->Open(k_tempCoreAssetPath, 0, fileLength); stream->BlockUntilLoadComplete(); // Serialize the graph entity back in. RuntimeAssetHandler runtimeAssetHandler; EXPECT_EQ(runtimeAssetHandler.LoadAssetData(runtimeAsset, stream, {}), AZ::Data::AssetHandler::LoadResult::LoadComplete); GraphData& assetGraphData = runtimeAsset.Get()->GetData().m_graphData; AZStd::unordered_map idRemap; AZ::IdUtils::Remapper::GenerateNewIdsAndFixRefs(&assetGraphData, idRemap, m_serializeContext); graph->AddGraphData(assetGraphData); // Clear GraphData on asset to prevent it from deleting the graph data, the Graph component takes care of cleaning it up assetGraphData.Clear(); // Initialize the entity graphEntity->Init(); ScriptCanvasEditor::TraceSuppressionBus::Broadcast(&ScriptCanvasEditor::TraceSuppressionRequests::SuppressPrintf, true); graphEntity->Activate(); ScriptCanvasEditor::TraceSuppressionBus::Broadcast(&ScriptCanvasEditor::TraceSuppressionRequests::SuppressPrintf, false); // Run the graph component graph = graphEntity->FindComponent(); EXPECT_TRUE(graph != nullptr); // "Graph entity did not have the graph component."); ReportErrors(graph); const AZ::Vector3 allOne(1, 1, 1); const AZ::Vector3 allTwo(2, 2, 2); const AZ::Vector3 allThree(3, 3, 3); const AZ::Vector3 allFour(4, 4, 4); auto nodeIDs = graph->GetNodes(); EXPECT_EQ(9, nodeIDs.size()); // Graph result should be still 16 // Serialized graph has new remapped entity ids auto nodes = graph->GetNodes(); auto sumNodeIt = AZStd::find_if(nodes.begin(), nodes.end(), [](const AZ::EntityId& nodeId) -> bool { AZ::Entity* entity{}; AZ::ComponentApplicationBus::BroadcastResult(entity, &AZ::ComponentApplicationRequests::FindEntity, nodeId); return entity ? AZ::EntityUtils::FindFirstDerivedComponent(entity) ? true : false : false; }); EXPECT_NE(nodes.end(), sumNodeIt); TestResult* printNode = nullptr; SystemRequestBus::BroadcastResult(printNode, &SystemRequests::GetNode, *sumNodeIt); EXPECT_TRUE(printNode != nullptr); if (auto result = GetInput_UNIT_TEST(printNode, "Value")) { SC_EXPECT_FLOAT_EQ(*result, 16.0f); } else { ADD_FAILURE(); } EXPECT_TRUE(GraphHasVectorWithValue(*graph, allOne)); EXPECT_TRUE(GraphHasVectorWithValue(*graph, allTwo)); EXPECT_TRUE(GraphHasVectorWithValue(*graph, allThree)); EXPECT_FALSE(GraphHasVectorWithValue(*graph, allFour)); } TEST_F(ScriptCanvasTestFixture, SerializationLoadTest_RuntimeComponent) { using namespace ScriptCanvas; ////////////////////////////////////////////////////////////////////////// // Make the graph. AZStd::unique_ptr executionEntity = AZStd::make_unique("Loaded Graph"); auto executionComponent = executionEntity->CreateComponent(); auto* fileIO = AZ::IO::LocalFileIO::GetInstance(); EXPECT_NE(nullptr, fileIO); EXPECT_TRUE(fileIO->Exists(k_tempCoreAssetPath)); // Load it AZ::Data::Asset runtimeAsset; runtimeAsset.Create(AZ::Uuid::CreateRandom()); AZ::u64 fileLength = 0; AZ::IO::FileIOBase::GetInstance()->Size(k_tempCoreAssetPath, fileLength); AZStd::shared_ptr stream = AZStd::make_shared(); stream->Open(k_tempCoreAssetPath, 0, fileLength); stream->BlockUntilLoadComplete(); // Serialize the runtime asset back in. RuntimeAssetHandler runtimeAssetHandler; EXPECT_EQ(runtimeAssetHandler.LoadAssetData(runtimeAsset, stream, {}), AZ::Data::AssetHandler::LoadResult::LoadComplete); runtimeAssetHandler.InitAsset(runtimeAsset, true, false); // Initialize the entity executionComponent->SetRuntimeAsset(runtimeAsset); executionEntity->Init(); { ScriptCanvasEditor::ScopedOutputSuppression suppressOutput; executionEntity->Activate(); // Dispatch the AssetBus events to force onAssetReady event AZ::Data::AssetManager::Instance().DispatchEvents(); } EXPECT_FALSE(executionComponent->IsInErrorState()); const AZ::Vector3 allOne(1, 1, 1); const AZ::Vector3 allTwo(2, 2, 2); const AZ::Vector3 allThree(3, 3, 3); const AZ::Vector3 allFour(4, 4, 4); auto nodeIds = executionComponent->GetNodes(); EXPECT_EQ(9, nodeIds.size()); // Graph result should be still 16 // Serialized graph has new remapped entity ids auto sumNodeIt = AZStd::find_if(nodeIds.begin(), nodeIds.end(), [](const AZ::EntityId& nodeId) -> bool { AZ::Entity* entity{}; AZ::ComponentApplicationBus::BroadcastResult(entity, &AZ::ComponentApplicationRequests::FindEntity, nodeId); return entity ? AZ::EntityUtils::FindFirstDerivedComponent(entity) ? true : false : false; }); EXPECT_NE(nodeIds.end(), sumNodeIt); TestResult* printNode = nullptr; SystemRequestBus::BroadcastResult(printNode, &SystemRequests::GetNode, *sumNodeIt); EXPECT_TRUE(printNode != nullptr); if (auto result = GetInput_UNIT_TEST(printNode, "Value")) { SC_EXPECT_FLOAT_EQ(*result, 16.0f); } else { ADD_FAILURE(); } AZStd::vector vector3Results; for (auto nodeId : nodeIds) { AZ::Entity* entity{}; AZ::ComponentApplicationBus::BroadcastResult(entity, &AZ::ComponentApplicationRequests::FindEntity, nodeId); auto behaviorContextNode = entity ? AZ::EntityUtils::FindFirstDerivedComponent(entity) : nullptr; auto rawVector3 = behaviorContextNode ? GetInput_UNIT_TEST(behaviorContextNode, PureData::k_setThis) : nullptr; if (rawVector3) { vector3Results.push_back(*rawVector3); } } auto allOneFound = AZStd::any_of(vector3Results.begin(), vector3Results.end(), [allOne](const AZ::Vector3& vector3Result) { return allOne == vector3Result; }); auto allTwoFound = AZStd::any_of(vector3Results.begin(), vector3Results.end(), [allTwo](const AZ::Vector3& vector3Result) { return allTwo == vector3Result; }); auto allThreeFound = AZStd::any_of(vector3Results.begin(), vector3Results.end(), [allThree](const AZ::Vector3& vector3Result) { return allThree == vector3Result; }); auto allFourFound = AZStd::any_of(vector3Results.begin(), vector3Results.end(), [allFour](const AZ::Vector3& vector3Result) { return allFour == vector3Result; }); EXPECT_TRUE(allOneFound); EXPECT_TRUE(allTwoFound); EXPECT_TRUE(allThreeFound); EXPECT_FALSE(allFourFound); } TEST_F(ScriptCanvasTestFixture, Contracts) { using namespace ScriptCanvas; RegisterComponentDescriptor(); ////////////////////////////////////////////////////////////////////////// // Make the graph. Graph* graph = nullptr; SystemRequestBus::BroadcastResult(graph, &SystemRequests::MakeGraph); EXPECT_TRUE(graph != nullptr); graph->GetEntity()->Init(); const AZ::EntityId& graphEntityId = graph->GetEntityId(); const ScriptCanvasId& graphUniqueId = graph->GetScriptCanvasId(); // Make the nodes. // Start AZ::Entity* startEntity{ aznew AZ::Entity("Start") }; startEntity->Init(); AZ::EntityId startNode{ startEntity->GetId() }; SystemRequestBus::Broadcast(&SystemRequests::CreateNodeOnEntity, startNode, graphUniqueId, Nodes::Core::Start::TYPEINFO_Uuid()); // ContractNode 0 AZ::Entity* contract0Entity{ aznew AZ::Entity("Contract 0") }; contract0Entity->Init(); AZ::EntityId contract0Node{ contract0Entity->GetId() }; SystemRequestBus::Broadcast(&SystemRequests::CreateNodeOnEntity, contract0Node, graphUniqueId, ContractNode::TYPEINFO_Uuid()); // ContractNode 1 AZ::Entity* contract1Entity{ aznew AZ::Entity("Contract 1") }; contract1Entity->Init(); AZ::EntityId contract1Node{ contract1Entity->GetId() }; SystemRequestBus::Broadcast(&SystemRequests::CreateNodeOnEntity, contract1Node, graphUniqueId, ContractNode::TYPEINFO_Uuid()); // invalid { ScriptCanvasEditor::ScopedOutputSuppression suppressOutput; EXPECT_FALSE(graph->Connect(startNode, AZ::EntityUtils::FindFirstDerivedComponent(startEntity)->GetSlotId("Out"), contract0Node, AZ::EntityUtils::FindFirstDerivedComponent(contract0Entity)->GetSlotId("Out"))); EXPECT_FALSE(graph->Connect(startNode, AZ::EntityUtils::FindFirstDerivedComponent(startEntity)->GetSlotId("In"), contract0Node, AZ::EntityUtils::FindFirstDerivedComponent(contract0Entity)->GetSlotId("In"))); EXPECT_FALSE(graph->Connect(startNode, AZ::EntityUtils::FindFirstDerivedComponent(startEntity)->GetSlotId("In"), contract0Node, AZ::EntityUtils::FindFirstDerivedComponent(contract0Entity)->GetSlotId("Get String"))); EXPECT_FALSE(graph->Connect(startNode, AZ::EntityUtils::FindFirstDerivedComponent(startEntity)->GetSlotId("Out"), contract0Node, AZ::EntityUtils::FindFirstDerivedComponent(contract0Entity)->GetSlotId("Get String"))); EXPECT_FALSE(graph->Connect(startNode, AZ::EntityUtils::FindFirstDerivedComponent(startEntity)->GetSlotId("In"), contract0Node, AZ::EntityUtils::FindFirstDerivedComponent(contract0Entity)->GetSlotId("Set String"))); EXPECT_FALSE(graph->Connect(startNode, AZ::EntityUtils::FindFirstDerivedComponent(startEntity)->GetSlotId("Out"), contract0Node, AZ::EntityUtils::FindFirstDerivedComponent(contract0Entity)->GetSlotId("Set String"))); EXPECT_FALSE(graph->Connect(contract0Node, AZ::EntityUtils::FindFirstDerivedComponent(contract0Entity)->GetSlotId("Set String"), contract1Node, AZ::EntityUtils::FindFirstDerivedComponent(contract1Entity)->GetSlotId("Set String"))); EXPECT_FALSE(graph->Connect(contract0Node, AZ::EntityUtils::FindFirstDerivedComponent(contract0Entity)->GetSlotId("Set String"), contract1Node, AZ::EntityUtils::FindFirstDerivedComponent(contract1Entity)->GetSlotId("Set Number"))); EXPECT_FALSE(graph->Connect(contract0Node, AZ::EntityUtils::FindFirstDerivedComponent(contract0Entity)->GetSlotId("Set String"), contract1Node, AZ::EntityUtils::FindFirstDerivedComponent(contract1Entity)->GetSlotId("Get Number"))); EXPECT_FALSE(graph->Connect(contract0Node, AZ::EntityUtils::FindFirstDerivedComponent(contract0Entity)->GetSlotId("Set String"), contract1Node, AZ::EntityUtils::FindFirstDerivedComponent(contract1Entity)->GetSlotId("Set String"))); EXPECT_FALSE(graph->Connect(contract0Node, AZ::EntityUtils::FindFirstDerivedComponent(contract0Entity)->GetSlotId("Out"), contract0Node, AZ::EntityUtils::FindFirstDerivedComponent(contract0Entity)->GetSlotId("In"))); } // valid EXPECT_TRUE(graph->Connect(startNode, AZ::EntityUtils::FindFirstDerivedComponent(startEntity)->GetSlotId("Out"), contract0Node, AZ::EntityUtils::FindFirstDerivedComponent(contract0Entity)->GetSlotId("In"))); EXPECT_TRUE(graph->Connect(contract0Node, AZ::EntityUtils::FindFirstDerivedComponent(contract0Entity)->GetSlotId("Set String"), contract1Node, AZ::EntityUtils::FindFirstDerivedComponent(contract1Entity)->GetSlotId("Get String"))); EXPECT_TRUE(graph->Connect(contract0Node, AZ::EntityUtils::FindFirstDerivedComponent(contract0Entity)->GetSlotId("In"), contract1Node, AZ::EntityUtils::FindFirstDerivedComponent(contract1Entity)->GetSlotId("Out"))); EXPECT_TRUE(graph->Connect(contract0Node, AZ::EntityUtils::FindFirstDerivedComponent(contract0Entity)->GetSlotId("Set Number"), contract1Node, AZ::EntityUtils::FindFirstDerivedComponent(contract1Entity)->GetSlotId("Get Number"))); // Execute it graph->GetEntity()->Activate(); ReportErrors(graph); graph->GetEntity()->Deactivate(); delete graph->GetEntity(); } #if defined (SCRIPTCANVAS_ERRORS_ENABLED) TEST_F(ScriptCanvasTestFixture, Error) { using namespace ScriptCanvas; RegisterComponentDescriptor(); RegisterComponentDescriptor(); Graph* graph = nullptr; SystemRequestBus::BroadcastResult(graph, &SystemRequests::MakeGraph); EXPECT_TRUE(graph != nullptr); graph->GetEntity()->Init(); const AZ::EntityId& graphEntityId = graph->GetEntityId(); const ScriptCanvasId& graphUniqueId = graph->GetScriptCanvasId(); UnitTestEventsHandler unitTestHandler; unitTestHandler.BusConnect(); AZ::EntityId startID; CreateTestNode(graphUniqueId, startID); AZStd::string description = "Unit test error!"; AZ::EntityId stringNodeID; CreateDataNode(graphUniqueId, description, stringNodeID); AZStd::string sideFX1 = "Side FX 1"; AZ::EntityId sideFX1NodeID; CreateDataNode(graphUniqueId, sideFX1, sideFX1NodeID); AZ::EntityId errorNodeID; CreateTestNode(graphUniqueId, errorNodeID); AZ::EntityId sideEffectID = CreateClassFunctionNode(graphUniqueId, "UnitTestEventsBus", "SideEffect"); EXPECT_TRUE(Connect(*graph, sideFX1NodeID, "Get", sideEffectID, "String: 0")); EXPECT_TRUE(Connect(*graph, startID, "Out", errorNodeID, "In")); EXPECT_TRUE(Connect(*graph, errorNodeID, "Out", sideEffectID, "In")); // test to make sure the graph received an error { ScriptCanvasEditor::ScopedOutputSuppression suppressOutput; graph->GetEntity()->Activate(); } const bool expectErrors = true; const bool expectIrrecoverableErrors = true; ReportErrors(graph, expectErrors, expectIrrecoverableErrors); EXPECT_EQ(unitTestHandler.SideEffectCount(sideFX1), 0); graph->GetEntity()->Deactivate(); delete graph->GetEntity(); } TEST_F(ScriptCanvasTestFixture, ErrorNode) { using namespace ScriptCanvas; Graph* graph = nullptr; SystemRequestBus::BroadcastResult(graph, &SystemRequests::MakeGraph); EXPECT_TRUE(graph != nullptr); graph->GetEntity()->Init(); const AZ::EntityId& graphEntityId = graph->GetEntityId(); const ScriptCanvasId& graphUniqueId = graph->GetScriptCanvasId(); UnitTestEventsHandler unitTestHandler; unitTestHandler.BusConnect(); // Start AZ::EntityId startID; CreateTestNode(graphUniqueId, startID); AZStd::string description = "Test Error Report"; AZ::EntityId stringNodeID; CreateDataNode(graphUniqueId, description, stringNodeID); AZStd::string sideFX1 = "Side FX 1"; AZ::EntityId sideFX1NodeID; CreateDataNode(graphUniqueId, sideFX1, sideFX1NodeID); AZ::EntityId errorNodeID; CreateTestNode(graphUniqueId, errorNodeID); AZ::EntityId sideEffectID = CreateClassFunctionNode(graphUniqueId, "UnitTestEventsBus", "SideEffect"); EXPECT_TRUE(Connect(*graph, startID, "Out", sideEffectID, "In")); EXPECT_TRUE(Connect(*graph, sideFX1NodeID, "Get", sideEffectID, "String: 0")); EXPECT_TRUE(Connect(*graph, sideEffectID, "Out", errorNodeID, "In")); EXPECT_TRUE(Connect(*graph, stringNodeID, "Get", errorNodeID, "Description")); // test to make sure the graph received an error { ScriptCanvasEditor::ScopedOutputSuppression suppressOutput; graph->GetEntity()->Activate(); } const bool expectErrors = true; const bool expectIrrecoverableErrors = true; ReportErrors(graph, expectErrors, expectIrrecoverableErrors); EXPECT_EQ(unitTestHandler.SideEffectCount(sideFX1), 1); graph->GetEntity()->Deactivate(); // test to make sure the graph did to retry execution graph->GetEntity()->Activate(); ReportErrors(graph, expectErrors, expectIrrecoverableErrors); // if the graph was allowed to execute, the side effect counter should be higher EXPECT_EQ(unitTestHandler.SideEffectCount(sideFX1), 1); delete graph->GetEntity(); } TEST_F(ScriptCanvasTestFixture, InfiniteLoopDetected) { using namespace ScriptCanvas; RegisterComponentDescriptor(); Graph* graph = nullptr; SystemRequestBus::BroadcastResult(graph, &SystemRequests::MakeGraph); EXPECT_TRUE(graph != nullptr); graph->GetEntity()->Init(); const AZ::EntityId& graphEntityId = graph->GetEntityId(); const ScriptCanvasId& graphUniqueId = graph->GetScriptCanvasId(); UnitTestEventsHandler unitTestHandler; unitTestHandler.BusConnect(); AZStd::string sideFXpass = "Side FX Infinite Loop Error Handled"; AZ::EntityId sideFXpassNodeID; CreateDataNode(graphUniqueId, sideFXpass, sideFXpassNodeID); AZStd::string sideFXfail = "Side FX Infinite Loop Node Failed"; AZ::EntityId sideFXfailNodeID; CreateDataNode(graphUniqueId, sideFXfail, sideFXfailNodeID); AZ::EntityId startID; CreateTestNode(graphUniqueId, startID); AZ::EntityId infiniteLoopNodeID; CreateTestNode(graphUniqueId, infiniteLoopNodeID); AZ::EntityId errorHandlerID; CreateTestNode(graphUniqueId, errorHandlerID); AZ::EntityId sideEffectPassID = CreateClassFunctionNode(graphUniqueId, "UnitTestEventsBus", "SideEffect"); AZ::EntityId sideEffectFailID = CreateClassFunctionNode(graphUniqueId, "UnitTestEventsBus", "SideEffect"); EXPECT_TRUE(Connect(*graph, sideFXpassNodeID, "Get", sideEffectPassID, "String: 0")); EXPECT_TRUE(Connect(*graph, sideFXfailNodeID, "Get", sideEffectFailID, "String: 0")); EXPECT_TRUE(Connect(*graph, startID, "Out", infiniteLoopNodeID, "In")); EXPECT_TRUE(Connect(*graph, infiniteLoopNodeID, "In", infiniteLoopNodeID, "Before Infinity")); EXPECT_TRUE(Connect(*graph, infiniteLoopNodeID, "After Infinity", sideEffectFailID, "In")); EXPECT_TRUE(Connect(*graph, errorHandlerID, "Out", sideEffectPassID, "In")); { ScriptCanvasEditor::ScopedOutputSuppression suppressOutput; graph->GetEntity()->Activate(); } const bool expectError = true; const bool expectIrrecoverableError = true; ReportErrors(graph, expectError, expectIrrecoverableError); EXPECT_EQ(0, unitTestHandler.SideEffectCount(sideFXpass)); EXPECT_EQ(0, unitTestHandler.SideEffectCount(sideFXfail)); graph->GetEntity()->Deactivate(); graph->GetEntity()->Activate(); ReportErrors(graph, expectError, expectIrrecoverableError); EXPECT_EQ(0, unitTestHandler.SideEffectCount(sideFXpass)); EXPECT_EQ(0, unitTestHandler.SideEffectCount(sideFXfail)); delete graph->GetEntity(); } #endif // SCRIPTCANAS_ERRORS_ENABLED TEST_F(ScriptCanvasTestFixture, BinaryOperationTest) { using namespace ScriptCanvas::Nodes; using namespace ScriptCanvas::Nodes::Comparison; TestBehaviorContextObject::Reflect(m_serializeContext); TestBehaviorContextObject::Reflect(m_behaviorContext); BinaryOpTest(1, 1, true); BinaryOpTest(1, 0, false); BinaryOpTest(0, 1, false); BinaryOpTest(0, 0, true); BinaryOpTest(1, 1, false); BinaryOpTest(1, 0, true); BinaryOpTest(0, 1, true); BinaryOpTest(0, 0, false); BinaryOpTest(1, 1, false); BinaryOpTest(1, 0, true); BinaryOpTest(0, 1, false); BinaryOpTest(0, 0, false); BinaryOpTest(1, 1, true); BinaryOpTest(1, 0, true); BinaryOpTest(0, 1, false); BinaryOpTest(0, 0, true); BinaryOpTest(1, 1, false); BinaryOpTest(1, 0, false); BinaryOpTest(0, 1, true); BinaryOpTest(0, 0, false); BinaryOpTest(1, 1, true); BinaryOpTest(1, 0, false); BinaryOpTest(0, 1, true); BinaryOpTest(0, 0, true); BinaryOpTest(true, true, true); BinaryOpTest(true, false, false); BinaryOpTest(false, true, false); BinaryOpTest(false, false, true); BinaryOpTest(true, true, false); BinaryOpTest(true, false, true); BinaryOpTest(false, true, true); BinaryOpTest(false, false, false); AZStd::string string0("a string"); AZStd::string string1("b string"); BinaryOpTest(string1, string1, true); BinaryOpTest(string1, string0, false); BinaryOpTest(string0, string1, false); BinaryOpTest(string0, string0, true); BinaryOpTest(string1, string1, false); BinaryOpTest(string1, string0, true); BinaryOpTest(string0, string1, true); BinaryOpTest(string0, string0, false); BinaryOpTest(string1, string1, false); BinaryOpTest(string1, string0, true); BinaryOpTest(string0, string1, false); BinaryOpTest(string0, string0, false); BinaryOpTest(string1, string1, true); BinaryOpTest(string1, string0, true); BinaryOpTest(string0, string1, false); BinaryOpTest(string0, string0, true); BinaryOpTest(string1, string1, false); BinaryOpTest(string1, string0, false); BinaryOpTest(string0, string1, true); BinaryOpTest(string0, string0, false); BinaryOpTest(string1, string1, true); BinaryOpTest(string1, string0, false); BinaryOpTest(string0, string1, true); BinaryOpTest(string0, string0, true); const AZ::Vector3 vectorOne(1.0f, 1.0f, 1.0f); const AZ::Vector3 vectorZero(0.0f, 0.0f, 0.0f); BinaryOpTest(vectorOne, vectorOne, true); BinaryOpTest(vectorOne, vectorZero, false); BinaryOpTest(vectorZero, vectorOne, false); BinaryOpTest(vectorZero, vectorZero, true); BinaryOpTest(vectorOne, vectorOne, false); BinaryOpTest(vectorOne, vectorZero, true); BinaryOpTest(vectorZero, vectorOne, true); BinaryOpTest(vectorZero, vectorZero, false); const TestBehaviorContextObject zero(0); const TestBehaviorContextObject one(1); const TestBehaviorContextObject otherOne(1); BinaryOpTest(one, one, true); BinaryOpTest(one, zero, false); BinaryOpTest(zero, one, false); BinaryOpTest(zero, zero, true); BinaryOpTest(one, one, false); BinaryOpTest(one, zero, true); BinaryOpTest(zero, one, true); BinaryOpTest(zero, zero, false); BinaryOpTest(one, one, false); BinaryOpTest(one, zero, true); BinaryOpTest(zero, one, false); BinaryOpTest(zero, zero, false); BinaryOpTest(one, one, true); BinaryOpTest(one, zero, true); BinaryOpTest(zero, one, false); BinaryOpTest(zero, zero, true); BinaryOpTest(one, one, false); BinaryOpTest(one, zero, false); BinaryOpTest(zero, one, true); BinaryOpTest(zero, zero, false); BinaryOpTest(one, one, true); BinaryOpTest(one, zero, false); BinaryOpTest(zero, one, true); BinaryOpTest(zero, zero, true); BinaryOpTest(one, otherOne, true); BinaryOpTest(otherOne, one, true); BinaryOpTest(one, otherOne, false); BinaryOpTest(otherOne, one, false); BinaryOpTest(one, otherOne, false); BinaryOpTest(otherOne, one, false); BinaryOpTest(one, otherOne, true); BinaryOpTest(otherOne, one, true); BinaryOpTest(one, otherOne, false); BinaryOpTest(otherOne, one, false); BinaryOpTest(one, otherOne, true); BinaryOpTest(otherOne, one, true); // force failures, to verify crash proofiness BinaryOpTest(one, zero, false, true); BinaryOpTest(one, zero, true, true); BinaryOpTest(one, zero, true, true); BinaryOpTest(one, zero, true, true); BinaryOpTest(one, zero, false, true); BinaryOpTest(one, zero, false, true); m_serializeContext->EnableRemoveReflection(); m_behaviorContext->EnableRemoveReflection(); TestBehaviorContextObject::Reflect(m_serializeContext); TestBehaviorContextObject::Reflect(m_behaviorContext); m_serializeContext->DisableRemoveReflection(); m_behaviorContext->DisableRemoveReflection(); } TEST_F(ScriptCanvasTestFixture, EntityRefTest) { using namespace ScriptCanvas; using namespace ScriptCanvas::Nodes; // Fake "world" entities AZ::Entity first("First"); first.CreateComponent(); first.Init(); first.Activate(); AZ::Entity second("Second"); second.CreateComponent(); second.Init(); second.Activate(); // Script Canvas Graph Graph* graph = nullptr; SystemRequestBus::BroadcastResult(graph, &SystemRequests::MakeGraph); EXPECT_TRUE(graph != nullptr); m_entityContext.AddEntity(first.GetId()); m_entityContext.AddEntity(second.GetId()); m_entityContext.AddEntity(graph->GetEntityId()); graph->GetEntity()->SetName("Graph Owner Entity"); graph->GetEntity()->CreateComponent(); graph->GetEntity()->Init(); const AZ::EntityId& graphEntityId = graph->GetEntityId(); const ScriptCanvasId& graphUniqueId = graph->GetScriptCanvasId(); AZ::EntityId startID; CreateTestNode(graphUniqueId, startID); // EntityRef node to some specific entity #1 AZ::EntityId selfEntityIdNode; auto selfEntityRef = CreateTestNode(graphUniqueId, selfEntityIdNode); selfEntityRef->SetEntityRef(first.GetId()); // EntityRef node to some specific entity #2 AZ::EntityId otherEntityIdNode; auto otherEntityRef = CreateTestNode(graphUniqueId, otherEntityIdNode); otherEntityRef->SetEntityRef(second.GetId()); // Explicitly set an EntityRef node with this graph's entity Id. AZ::EntityId graphEntityIdNode; auto graphEntityRef = CreateTestNode(graphUniqueId, graphEntityIdNode); graphEntityRef->SetEntityRef(graph->GetEntity()->GetId()); // First test: directly set an entity Id on the EntityID: 0 slot AZ::EntityId eventAid; Nodes::Core::Method* nodeA = CreateTestNode(graphUniqueId, eventAid); nodeA->InitializeEvent({ {} }, "EntityRefTestEventBus", "TestEvent"); if (auto entityId = ModInput_UNIT_TEST(nodeA, "EntityID: 0")) { *entityId = first.GetId(); } // Second test: Will connect the slot to an EntityRef node AZ::EntityId eventBid; Nodes::Core::Method* nodeB = CreateTestNode(graphUniqueId, eventBid); nodeB->InitializeEvent({ {} }, "EntityRefTestEventBus", "TestEvent"); // Third test: Set the slot's EntityId: 0 to GraphOwnerId, this should result in the same Id as graph->GetEntityId() AZ::EntityId eventCid; Nodes::Core::Method* nodeC = CreateTestNode(graphUniqueId, eventCid); nodeC->InitializeEvent({ {} }, "EntityRefTestEventBus", "TestEvent"); if (auto entityId = ModInput_UNIT_TEST(nodeC, "EntityID: 0")) { *entityId = ScriptCanvas::GraphOwnerId; } // True AZ::EntityId trueNodeId; CreateDataNode(graphUniqueId, true, trueNodeId); // False AZ::EntityId falseNodeId; CreateDataNode(graphUniqueId, false, falseNodeId); // Start -> TestEvent // O EntityId: 0 (not connected, it was set directly on the slot) // EntityRef: first -O EntityId: 1 // False -O Boolean: 2 EXPECT_TRUE(Connect(*graph, startID, "Out", eventAid, "In")); EXPECT_TRUE(Connect(*graph, eventAid, "EntityID: 1", selfEntityIdNode, "Get")); EXPECT_TRUE(Connect(*graph, eventAid, "Boolean: 2", falseNodeId, "Get")); // Start -> TestEvent // EntityRef: second -O EntityId: 0 // EntityRef: second -O EntityId: 1 // False -O Boolean: 2 EXPECT_TRUE(Connect(*graph, startID, "Out", eventBid, "In")); EXPECT_TRUE(Connect(*graph, eventBid, "EntityID: 0", otherEntityIdNode, "Get")); EXPECT_TRUE(Connect(*graph, eventBid, "EntityID: 1", otherEntityIdNode, "Get")); EXPECT_TRUE(Connect(*graph, eventBid, "Boolean: 2", falseNodeId, "Get")); // Start -> TestEvent // -O EntityId: 0 (not connected, slot is set to GraphOwnerId) // graphEntityIdNode -O EntityId: 1 // True -O Boolean: 2 EXPECT_TRUE(Connect(*graph, startID, "Out", eventCid, "In")); EXPECT_TRUE(Connect(*graph, eventCid, "EntityID: 1", graphEntityIdNode, "Get")); EXPECT_TRUE(Connect(*graph, eventCid, "Boolean: 2", trueNodeId, "Get")); // Execute the graph { ScriptCanvasEditor::ScopedOutputSuppression suppressOutput; graph->GetEntity()->Activate(); } ReportErrors(graph); delete graph->GetEntity(); } const int k_executionCount = 998; TEST_F(ScriptCanvasTestFixture, ExecutionLength) { using namespace ScriptCanvas; Graph* graph(nullptr); SystemRequestBus::BroadcastResult(graph, &SystemRequests::MakeGraph); EXPECT_TRUE(graph != nullptr); graph->GetEntity()->Init(); const AZ::EntityId& graphEntityID = graph->GetEntityId(); const ScriptCanvasId& graphUniqueId = graph->GetScriptCanvasId(); AZ::EntityId startID; CreateTestNode(graphUniqueId, startID); AZ::EntityId previousID = startID; for (int i = 0; i < k_executionCount; ++i) { AZ::EntityId printNodeID; TestResult* printNode = CreateTestNode(graphUniqueId, printNodeID); SetInput_UNIT_TEST(printNode, "Value", i); EXPECT_TRUE(Connect(*graph, previousID, "Out", printNodeID, "In")); previousID = printNodeID; } AZ::Entity* graphEntity = graph->GetEntity(); { ScriptCanvasEditor::ScopedOutputSuppression suppressOutput; graphEntity->Activate(); } ReportErrors(graph); graphEntity->Deactivate(); delete graphEntity; } TEST_F(ScriptCanvasTestFixture, AnyNode) { RunUnitTestGraph("LY_SC_UnitTest_Any"); }