You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
o3de/Gems/ScriptCanvasTesting/Code/Tests/ScriptCanvas_Core.cpp

484 lines
19 KiB
C++

/*
* Copyright (c) Contributors to the Open 3D Engine Project.
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
*
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
*/
#include <Source/Framework/ScriptCanvasTestFixture.h>
#include <Source/Framework/ScriptCanvasTestUtilities.h>
#include <Source/Framework/ScriptCanvasTestNodes.h>
#include <AzCore/Serialization/IdUtils.h>
#include <ScriptCanvas/Asset/RuntimeAsset.h>
#include <ScriptCanvas/Asset/RuntimeAssetHandler.h>
#include <ScriptCanvas/Execution/RuntimeComponent.h>
#include <ScriptCanvas/Variable/GraphVariableManagerComponent.h>
#include <AzCore/Math/Vector3.h>
#include <AzCore/Math/Color.h>
using namespace ScriptCanvasTests;
using namespace TestNodes;
TEST_F(ScriptCanvasTestFixture, CoreNodeFunction_OwningGraphCheck)
{
using namespace ScriptCanvas;
ScriptCanvas::Graph* graph = CreateGraph();
ConfigurableUnitTestNode* groupedNode = CreateConfigurableNode();
EXPECT_EQ(graph, groupedNode->GetGraph());
}
TEST_F(ScriptCanvasTestFixture, AddRemoveSlotNotifications)
{
RegisterComponentDescriptor<AddNodeWithRemoveSlot>();
using namespace ScriptCanvas;
AZStd::unique_ptr<AZ::Entity> numberAddEntity = AZStd::make_unique<AZ::Entity>("numberAddEntity");
auto numberAddNode = numberAddEntity->CreateComponent<AddNodeWithRemoveSlot>();
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, false);
EXPECT_EQ(2U, nodeNotifications.GetSlotsRemoved());
numberAddEntity.reset();
}
TEST_F(ScriptCanvasTestFixture, InsertSlot_Basic)
{
using namespace ScriptCanvas;
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<float>((*firstSlot->FindDatum()->GetAs<Data::NumberType>())), 0.0f);
}
{
const Slot* secondSlot = slotList[1];
EXPECT_EQ(secondSlot->GetId(), thirdSlotAdded);
EXPECT_EQ(secondSlot->GetName(), "B");
EXPECT_FLOAT_EQ(static_cast<float>((*secondSlot->FindDatum()->GetAs<Data::NumberType>())), 1.0f);
}
{
const Slot* thirdSlot = slotList[2];
EXPECT_EQ(thirdSlot->GetId(), secondSlotAdded);
EXPECT_EQ(thirdSlot->GetName(), "C");
EXPECT_FLOAT_EQ(static_cast<float>((*thirdSlot->FindDatum()->GetAs<Data::NumberType>())), 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<float>((*firstSlot->FindDatum()->GetAs<Data::NumberType>())), 0.0f);
}
{
const Slot* secondSlot = slotList[1];
EXPECT_EQ(secondSlot->GetId(), thirdSlotAdded);
EXPECT_EQ(secondSlot->GetName(), "B");
EXPECT_FLOAT_EQ(static_cast<float>((*secondSlot->FindDatum()->GetAs<Data::NumberType>())), 1.0f);
}
{
const Slot* thirdSlot = slotList[2];
EXPECT_EQ(thirdSlot->GetId(), secondSlotAdded);
EXPECT_EQ(thirdSlot->GetName(), "C");
EXPECT_FLOAT_EQ(static_cast<float>((*thirdSlot->FindDatum()->GetAs<Data::NumberType>())), 2.0f);
}
}
graph->Deactivate();
{
const 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<float>((*firstSlot->FindDatum()->GetAs<Data::NumberType>())), 0.0f);
}
{
const Slot* secondSlot = slotList[1];
EXPECT_EQ(secondSlot->GetId(), thirdSlotAdded);
EXPECT_EQ(secondSlot->GetName(), "B");
EXPECT_FLOAT_EQ(static_cast<float>((*secondSlot->FindDatum()->GetAs<Data::NumberType>())), 1.0f);
}
{
const Slot* thirdSlot = slotList[2];
EXPECT_EQ(thirdSlot->GetId(), secondSlotAdded);
EXPECT_EQ(thirdSlot->GetName(), "C");
EXPECT_FLOAT_EQ(static_cast<float>((*thirdSlot->FindDatum()->GetAs<Data::NumberType>())), 2.0f);
}
}
}
TEST_F(ScriptCanvasTestFixture, InsertSlot_FrontPadded)
{
using namespace ScriptCanvas;
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<float>((*firstSlot->FindDatum()->GetAs<Data::NumberType>())), 0.0f);
}
{
const Slot* secondSlot = slotList[1];
EXPECT_EQ(secondSlot->GetId(), thirdSlotAdded);
EXPECT_EQ(secondSlot->GetName(), "B");
EXPECT_FLOAT_EQ(static_cast<float>((*secondSlot->FindDatum()->GetAs<Data::NumberType>())), 1.0f);
}
{
const Slot* thirdSlot = slotList[2];
EXPECT_EQ(thirdSlot->GetId(), secondSlotAdded);
EXPECT_EQ(thirdSlot->GetName(), "C");
EXPECT_FLOAT_EQ(static_cast<float>((*thirdSlot->FindDatum()->GetAs<Data::NumberType>())), 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<float>((*firstSlot->FindDatum()->GetAs<Data::NumberType>())), 0.0f);
}
{
const Slot* secondSlot = slotList[1];
EXPECT_EQ(secondSlot->GetId(), thirdSlotAdded);
EXPECT_EQ(secondSlot->GetName(), "B");
EXPECT_FLOAT_EQ(static_cast<float>((*secondSlot->FindDatum()->GetAs<Data::NumberType>())), 1.0f);
}
{
const Slot* thirdSlot = slotList[2];
EXPECT_EQ(thirdSlot->GetId(), secondSlotAdded);
EXPECT_EQ(thirdSlot->GetName(), "C");
EXPECT_FLOAT_EQ(static_cast<float>((*thirdSlot->FindDatum()->GetAs<Data::NumberType>())), 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<float>((*firstSlot->FindDatum()->GetAs<Data::NumberType>())), 0.0f);
}
{
const Slot* secondSlot = slotList[1];
EXPECT_EQ(secondSlot->GetId(), thirdSlotAdded);
EXPECT_EQ(secondSlot->GetName(), "B");
EXPECT_FLOAT_EQ(static_cast<float>((*secondSlot->FindDatum()->GetAs<Data::NumberType>())), 1.0f);
}
{
const Slot* thirdSlot = slotList[2];
EXPECT_EQ(thirdSlot->GetId(), secondSlotAdded);
EXPECT_EQ(thirdSlot->GetName(), "C");
EXPECT_FLOAT_EQ(static_cast<float>((*thirdSlot->FindDatum()->GetAs<Data::NumberType>())), 2.0f);
}
}
}
TEST_F(ScriptCanvasTestFixture, ValueTypes)
{
using namespace ScriptCanvas;
Datum number0(Datum(0));
int number0Value = *number0.GetAs<int>();
Datum number1(Datum(1));
int number1Value = *number1.GetAs<int>();
Datum numberFloat(Datum(2.f));
float numberFloatValue = *numberFloat.GetAs<float>();
Datum numberDouble(Datum(3.0));
double numberDoubleValue = *numberDouble.GetAs<double>();
Datum numberHex(Datum(0xff));
[[maybe_unused]] int numberHexValue = *numberHex.GetAs<int>();
Datum numberPi(Datum(3.14f));
float numberPiValue = *numberPi.GetAs<float>();
Datum numberSigned(Datum(-100));
[[maybe_unused]] int numberSignedValue = *numberSigned.GetAs<int>();
Datum numberUnsigned(Datum(100u));
[[maybe_unused]] unsigned int numberUnsignedValue = *numberUnsigned.GetAs<unsigned int>();
Datum numberDoublePi(Datum(6.28));
double numberDoublePiValue = *numberDoublePi.GetAs<double>();
EXPECT_EQ(number0Value, 0);
EXPECT_EQ(number1Value, 1);
EXPECT_TRUE(AZ::IsClose(numberFloatValue, 2.f, std::numeric_limits<float>::epsilon()));
EXPECT_TRUE(AZ::IsClose(numberDoubleValue, 3.0, std::numeric_limits<double>::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<bool>());
Datum boolFalse(Datum(false));
EXPECT_FALSE(*boolFalse.GetAs<bool>());
boolFalse = boolTrue;
EXPECT_TRUE(*boolFalse.GetAs<bool>());
Datum boolFalse2(Datum(false));
boolTrue = boolFalse2;
EXPECT_FALSE(*boolTrue.GetAs<bool>());
{
const int k_count(10000);
AZStd::vector<Datum> objects;
for (int i = 0; i < k_count; ++i)
{
objects.push_back(Datum("Vector3", Datum::eOriginality::Original));
}
}
GTEST_SUCCEED();
}
TEST_F(ScriptCanvasTestFixture, Contracts)
{
using namespace ScriptCanvas;
RegisterComponentDescriptor<ContractNode>();
//////////////////////////////////////////////////////////////////////////
// Make the graph.
ScriptCanvas::Graph* graph = nullptr;
SystemRequestBus::BroadcastResult(graph, &SystemRequests::MakeGraph);
EXPECT_TRUE(graph != nullptr);
graph->GetEntity()->Init();
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, ScriptCanvas::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<Node>(startEntity)->GetSlotId("Out"), contract0Node, AZ::EntityUtils::FindFirstDerivedComponent<Node>(contract0Entity)->GetSlotId("Out")));
EXPECT_FALSE(graph->Connect(startNode, AZ::EntityUtils::FindFirstDerivedComponent<Node>(startEntity)->GetSlotId("In"), contract0Node, AZ::EntityUtils::FindFirstDerivedComponent<Node>(contract0Entity)->GetSlotId("In")));
EXPECT_FALSE(graph->Connect(startNode, AZ::EntityUtils::FindFirstDerivedComponent<Node>(startEntity)->GetSlotId("In"), contract0Node, AZ::EntityUtils::FindFirstDerivedComponent<Node>(contract0Entity)->GetSlotId("Get String")));
EXPECT_FALSE(graph->Connect(startNode, AZ::EntityUtils::FindFirstDerivedComponent<Node>(startEntity)->GetSlotId("Out"), contract0Node, AZ::EntityUtils::FindFirstDerivedComponent<Node>(contract0Entity)->GetSlotId("Get String")));
EXPECT_FALSE(graph->Connect(startNode, AZ::EntityUtils::FindFirstDerivedComponent<Node>(startEntity)->GetSlotId("In"), contract0Node, AZ::EntityUtils::FindFirstDerivedComponent<Node>(contract0Entity)->GetSlotId("Set String")));
EXPECT_FALSE(graph->Connect(startNode, AZ::EntityUtils::FindFirstDerivedComponent<Node>(startEntity)->GetSlotId("Out"), contract0Node, AZ::EntityUtils::FindFirstDerivedComponent<Node>(contract0Entity)->GetSlotId("Set String")));
EXPECT_FALSE(graph->Connect(contract0Node, AZ::EntityUtils::FindFirstDerivedComponent<Node>(contract0Entity)->GetSlotId("Set String"), contract1Node, AZ::EntityUtils::FindFirstDerivedComponent<Node>(contract1Entity)->GetSlotId("Set String")));
EXPECT_FALSE(graph->Connect(contract0Node, AZ::EntityUtils::FindFirstDerivedComponent<Node>(contract0Entity)->GetSlotId("Set String"), contract1Node, AZ::EntityUtils::FindFirstDerivedComponent<Node>(contract1Entity)->GetSlotId("Set Number")));
EXPECT_FALSE(graph->Connect(contract0Node, AZ::EntityUtils::FindFirstDerivedComponent<Node>(contract0Entity)->GetSlotId("Get String"), contract1Node, AZ::EntityUtils::FindFirstDerivedComponent<Node>(contract1Entity)->GetSlotId("Set Number")));
EXPECT_FALSE(graph->Connect(contract0Node, AZ::EntityUtils::FindFirstDerivedComponent<Node>(contract0Entity)->GetSlotId("Set String"), contract1Node, AZ::EntityUtils::FindFirstDerivedComponent<Node>(contract1Entity)->GetSlotId("Set String")));
EXPECT_FALSE(graph->Connect(contract0Node, AZ::EntityUtils::FindFirstDerivedComponent<Node>(contract0Entity)->GetSlotId("Out"), contract0Node, AZ::EntityUtils::FindFirstDerivedComponent<Node>(contract0Entity)->GetSlotId("In")));
}
// valid
EXPECT_TRUE(graph->Connect(startNode, AZ::EntityUtils::FindFirstDerivedComponent<Node>(startEntity)->GetSlotId("Out"), contract0Node, AZ::EntityUtils::FindFirstDerivedComponent<Node>(contract0Entity)->GetSlotId("In")));
EXPECT_TRUE(graph->Connect(contract0Node, AZ::EntityUtils::FindFirstDerivedComponent<Node>(contract0Entity)->GetSlotId("Set String"), contract1Node, AZ::EntityUtils::FindFirstDerivedComponent<Node>(contract1Entity)->GetSlotId("Get String")));
EXPECT_TRUE(graph->Connect(contract0Node, AZ::EntityUtils::FindFirstDerivedComponent<Node>(contract0Entity)->GetSlotId("In"), contract1Node, AZ::EntityUtils::FindFirstDerivedComponent<Node>(contract1Entity)->GetSlotId("Out")));
EXPECT_TRUE(graph->Connect(contract0Node, AZ::EntityUtils::FindFirstDerivedComponent<Node>(contract0Entity)->GetSlotId("Set Number"), contract1Node, AZ::EntityUtils::FindFirstDerivedComponent<Node>(contract1Entity)->GetSlotId("Get Number")));
// Execute it
graph->GetEntity()->Activate();
ReportErrors(graph);
graph->GetEntity()->Deactivate();
delete graph->GetEntity();
}
TEST_F(ScriptCanvasTestFixture, While)
{
RunUnitTestGraph("LY_SC_UnitTest_While", ScriptCanvas::ExecutionMode::Interpreted);
}
TEST_F(ScriptCanvasTestFixture, WhileBreak)
{
RunUnitTestGraph("LY_SC_UnitTest_WhileBreak", ScriptCanvas::ExecutionMode::Interpreted);
}