123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417 |
- /*
- * 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
- *
- */
- #pragma once
- #include <AzCore/Asset/AssetManagerComponent.h>
- #include <AzCore/Component/ComponentApplicationBus.h>
- #include <AzCore/Driller/Driller.h>
- #include <AzCore/IO/FileIO.h>
- #include <AzCore/Memory/MemoryComponent.h>
- #include <AzCore/Memory/MemoryDriller.h>
- #include <AzCore/Serialization/EditContext.h>
- #include <AzCore/Serialization/SerializeContext.h>
- #include <AzCore/UnitTest/TestTypes.h>
- #include <AzCore/UserSettings/UserSettingsComponent.h>
- #include <AzCore/std/containers/vector.h>
- #include <AzFramework/IO/LocalFileIO.h>
- #include <AzTest/AzTest.h>
- #include <Nodes/BehaviorContextObjectTestNode.h>
- #include <Nodes/Nodeables/SharedDataSlotExample.h>
- #include <Nodes/Nodeables/ValuePointerReferenceExample.h>
- #include <ScriptCanvas/Core/Graph.h>
- #include <ScriptCanvas/Core/SlotConfigurationDefaults.h>
- #include <ScriptCanvas/ScriptCanvasGem.h>
- #include <ScriptCanvas/SystemComponent.h>
- #include "EntityRefTests.h"
- #include "ScriptCanvasTestApplication.h"
- #include "ScriptCanvasTestBus.h"
- #include "ScriptCanvasTestNodes.h"
- #include "ScriptCanvasTestUtilities.h"
- #define SC_EXPECT_DOUBLE_EQ(candidate, reference) EXPECT_NEAR(candidate, reference, 0.001)
- #define SC_EXPECT_FLOAT_EQ(candidate, reference) EXPECT_NEAR(candidate, reference, 0.001f)
- namespace ScriptCanvasTests
- {
- class ScriptCanvasTestFixture
- : public ::testing::Test
- //, protected NodeAccessor
- {
- public:
- static AZStd::atomic_bool s_asyncOperationActive;
- protected:
- static ScriptCanvasTests::Application* s_application;
- static void SetUpTestCase()
- {
- s_allocatorSetup.SetupAllocator();
- s_asyncOperationActive = false;
- if (s_application == nullptr)
- {
- AZ::ComponentApplication::StartupParameters appStartup;
- s_application = aznew ScriptCanvasTests::Application();
- {
- ScriptCanvasEditor::TraceSuppressionBus::Broadcast(&ScriptCanvasEditor::TraceSuppressionRequests::SuppressPrintf, true);
- AZ::ComponentApplication::Descriptor descriptor;
- descriptor.m_enableDrilling = false;
- descriptor.m_useExistingAllocator = true;
- AZ::DynamicModuleDescriptor dynamicModuleDescriptor;
- dynamicModuleDescriptor.m_dynamicLibraryPath = "GraphCanvas.Editor";
- descriptor.m_modules.push_back(dynamicModuleDescriptor);
- dynamicModuleDescriptor.m_dynamicLibraryPath = "ScriptCanvas.Editor";
- descriptor.m_modules.push_back(dynamicModuleDescriptor);
- dynamicModuleDescriptor.m_dynamicLibraryPath = "ExpressionEvaluation";
- descriptor.m_modules.push_back(dynamicModuleDescriptor);
- dynamicModuleDescriptor.m_dynamicLibraryPath = "ScriptEvents";
- descriptor.m_modules.push_back(dynamicModuleDescriptor);
- s_application->Start(descriptor, appStartup);
- // Without this, the user settings component would attempt to save on finalize/shutdown. Since the file is
- // shared across the whole engine, if multiple tests are run in parallel, the saving could cause a crash
- // in the unit tests.
- AZ::UserSettingsComponentRequestBus::Broadcast(&AZ::UserSettingsComponentRequests::DisableSaveOnFinalize);
- ScriptCanvasEditor::TraceSuppressionBus::Broadcast(&ScriptCanvasEditor::TraceSuppressionRequests::SuppressPrintf, false);
- }
- }
- AZ::IO::FileIOBase* fileIO = AZ::IO::FileIOBase::GetInstance();
- AZ_Assert(fileIO, "SC unit tests require filehandling");
- s_setupSucceeded = fileIO->GetAlias("@engroot@") != nullptr;
-
- AZ::TickBus::AllowFunctionQueuing(true);
- auto m_serializeContext = s_application->GetSerializeContext();
- auto m_behaviorContext = s_application->GetBehaviorContext();
- ScriptCanvasTesting::Reflect(m_serializeContext);
- ScriptCanvasTesting::Reflect(m_behaviorContext);
- ScriptCanvasTestingNodes::BehaviorContextObjectTest::Reflect(m_serializeContext);
- ScriptCanvasTestingNodes::BehaviorContextObjectTest::Reflect(m_behaviorContext);
- ::Nodes::InputMethodSharedDataSlotExampleNode::Reflect(m_serializeContext);
- ::Nodes::InputMethodSharedDataSlotExampleNode::Reflect(m_behaviorContext);
- ::Nodes::BranchMethodSharedDataSlotExampleNode::Reflect(m_serializeContext);
- ::Nodes::BranchMethodSharedDataSlotExampleNode::Reflect(m_behaviorContext);
- ::Nodes::ReturnTypeExampleNode::Reflect(m_serializeContext);
- ::Nodes::ReturnTypeExampleNode::Reflect(m_behaviorContext);
- ::Nodes::InputTypeExampleNode::Reflect(m_serializeContext);
- ::Nodes::InputTypeExampleNode::Reflect(m_behaviorContext);
- ::Nodes::BranchInputTypeExampleNode::Reflect(m_serializeContext);
- ::Nodes::BranchInputTypeExampleNode::Reflect(m_behaviorContext);
- ::Nodes::PropertyExampleNode::Reflect(m_serializeContext);
- ::Nodes::PropertyExampleNode::Reflect(m_behaviorContext);
- TestNodeableObject::Reflect(m_serializeContext);
- TestNodeableObject::Reflect(m_behaviorContext);
- ScriptUnitTestEventHandler::Reflect(m_serializeContext);
- ScriptUnitTestEventHandler::Reflect(m_behaviorContext);
- }
- static void TearDownTestCase()
- {
- // don't hang on to dangling assets
- AZ::Data::AssetManager::Instance().DispatchEvents();
- if (s_application)
- {
- s_application->Stop();
- delete s_application;
- s_application = nullptr;
- }
-
- s_allocatorSetup.TeardownAllocator();
- }
- template<class T>
- void RegisterComponentDescriptor()
- {
- AZ::ComponentDescriptor* descriptor = T::CreateDescriptor();
- auto insertResult = m_descriptors.insert(descriptor);
- if (insertResult.second)
- {
- GetApplication()->RegisterComponentDescriptor(descriptor);
- }
- }
- void SetUp() override
- {
- ASSERT_TRUE(s_setupSucceeded) << "ScriptCanvasTestFixture set up failed, unit tests can't work properly";
- m_serializeContext = s_application->GetSerializeContext();
- m_behaviorContext = s_application->GetBehaviorContext();
- AZ_Assert(AZ::IO::FileIOBase::GetInstance(), "File IO was not properly installed");
- RegisterComponentDescriptor<TestNodes::TestResult>();
- RegisterComponentDescriptor<TestNodes::ConfigurableUnitTestNode>();
- m_numericVectorType = ScriptCanvas::Data::Type::BehaviorContextObject(azrtti_typeid<AZStd::vector<ScriptCanvas::Data::NumberType>>());
- m_stringToNumberMapType = ScriptCanvas::Data::Type::BehaviorContextObject(azrtti_typeid<AZStd::unordered_map<ScriptCanvas::Data::StringType, ScriptCanvas::Data::NumberType>>());
- m_dataSlotConfigurationType = ScriptCanvas::Data::Type::BehaviorContextObject(azrtti_typeid<ScriptCanvas::DataSlotConfiguration>());
- }
- void TearDown() override
- {
- delete m_graph;
- m_graph = nullptr;
- ASSERT_TRUE(s_setupSucceeded) << "ScriptCanvasTestFixture set up failed, unit tests can't work properly";
- for (AZ::ComponentDescriptor* componentDescriptor : m_descriptors)
- {
- GetApplication()->UnregisterComponentDescriptor(componentDescriptor);
- }
- m_descriptors.clear();
- }
- ScriptCanvas::Graph* CreateGraph()
- {
- if (m_graph == nullptr)
- {
- m_graph = aznew ScriptCanvas::Graph();
- m_graph->Init();
- }
- return m_graph;
- }
- TestNodes::ConfigurableUnitTestNode* CreateConfigurableNode(AZStd::string entityName = "ConfigurableNodeEntity")
- {
- AZ::Entity* configurableNodeEntity = new AZ::Entity(entityName.c_str());
- auto configurableNode = configurableNodeEntity->CreateComponent<TestNodes::ConfigurableUnitTestNode>();
- if (m_graph == nullptr)
- {
- CreateGraph();
- }
- configurableNodeEntity->Init();
- m_graph->AddNode(configurableNodeEntity->GetId());
- return configurableNode;
- }
- void ReportErrors(ScriptCanvas::Graph* graph, bool expectErrors = false, bool expectIrrecoverableErrors = false)
- {
- AZ_UNUSED(graph);
- AZ_UNUSED(expectErrors);
- AZ_UNUSED(expectIrrecoverableErrors);
- }
- void TestConnectionBetween(ScriptCanvas::Endpoint sourceEndpoint, ScriptCanvas::Endpoint targetEndpoint, bool isValid = true)
- {
- EXPECT_EQ(m_graph->CanConnectionExistBetween(sourceEndpoint, targetEndpoint).IsSuccess(), isValid);
- EXPECT_EQ(m_graph->CanConnectionExistBetween(targetEndpoint, sourceEndpoint).IsSuccess(), isValid);
- EXPECT_EQ(m_graph->CanCreateConnectionBetween(sourceEndpoint, targetEndpoint).IsSuccess(), isValid);
- EXPECT_EQ(m_graph->CanCreateConnectionBetween(targetEndpoint, sourceEndpoint).IsSuccess(), isValid);
- if (isValid)
- {
- EXPECT_TRUE(m_graph->ConnectByEndpoint(sourceEndpoint, targetEndpoint));
- }
- }
- void TestIsConnectionPossible(ScriptCanvas::Endpoint sourceEndpoint, ScriptCanvas::Endpoint targetEndpoint, bool isValid = true)
- {
- EXPECT_EQ(m_graph->CanConnectionExistBetween(sourceEndpoint, targetEndpoint).IsSuccess(), isValid);
- EXPECT_EQ(m_graph->CanConnectionExistBetween(targetEndpoint, sourceEndpoint).IsSuccess(), isValid);
- EXPECT_EQ(m_graph->CanCreateConnectionBetween(sourceEndpoint, targetEndpoint).IsSuccess(), isValid);
- EXPECT_EQ(m_graph->CanCreateConnectionBetween(targetEndpoint, sourceEndpoint).IsSuccess(), isValid);
- }
- void CreateExecutionFlowBetween(AZStd::vector<TestNodes::ConfigurableUnitTestNode*> unitTestNodes)
- {
- ScriptCanvas::Slot* previousOutSlot = nullptr;
- for (TestNodes::ConfigurableUnitTestNode* testNode : unitTestNodes)
- {
- {
- ScriptCanvas::ExecutionSlotConfiguration inputSlot = ScriptCanvas::CommonSlots::GeneralInSlot();
- ScriptCanvas::Slot* slot = testNode->AddTestingSlot(inputSlot);
- if (slot && previousOutSlot)
- {
- TestConnectionBetween(previousOutSlot->GetEndpoint(), slot->GetEndpoint());
- }
- }
- {
- ScriptCanvas::ExecutionSlotConfiguration outputSlot = ScriptCanvas::CommonSlots::GeneralOutSlot();
- previousOutSlot = testNode->AddTestingSlot(outputSlot);
- }
- }
- }
- AZStd::vector< ScriptCanvas::Data::Type > GetContainerDataTypes() const
- {
- return { m_numericVectorType, m_stringToNumberMapType };
- }
- ScriptCanvas::Data::Type GetRandomContainerType() const
- {
- AZStd::vector< ScriptCanvas::Data::Type > containerTypes = GetContainerDataTypes();
- // We have no types to randomize. Just return.
- if (containerTypes.empty())
- {
- return m_numericVectorType;
- }
- int randomIndex = rand() % containerTypes.size();
- ScriptCanvas::Data::Type randomType = containerTypes[randomIndex];
- AZ_TracePrintf("ScriptCanvasTestFixture", "RandomContainerType: %s\n", randomType.GetAZType().ToString<AZStd::string>().c_str());
- return randomType;
- }
- AZStd::vector< ScriptCanvas::Data::Type > GetPrimitiveTypes() const
- {
- return{
- ScriptCanvas::Data::Type::AABB(),
- ScriptCanvas::Data::Type::Boolean(),
- ScriptCanvas::Data::Type::Color(),
- ScriptCanvas::Data::Type::CRC(),
- ScriptCanvas::Data::Type::EntityID(),
- ScriptCanvas::Data::Type::Matrix3x3(),
- ScriptCanvas::Data::Type::Matrix4x4(),
- ScriptCanvas::Data::Type::Number(),
- ScriptCanvas::Data::Type::OBB(),
- ScriptCanvas::Data::Type::Plane(),
- ScriptCanvas::Data::Type::Quaternion(),
- ScriptCanvas::Data::Type::String(),
- ScriptCanvas::Data::Type::Transform(),
- ScriptCanvas::Data::Type::Vector2(),
- ScriptCanvas::Data::Type::Vector3(),
- ScriptCanvas::Data::Type::Vector4()
- };
- }
- ScriptCanvas::Data::Type GetRandomPrimitiveType() const
- {
- AZStd::vector< ScriptCanvas::Data::Type > primitiveTypes = GetPrimitiveTypes();
- // We have no types to randomize. Just return.
- if (primitiveTypes.empty())
- {
- return ScriptCanvas::Data::Type::Number();
- }
- int randomIndex = rand() % primitiveTypes.size();
- ScriptCanvas::Data::Type randomType = primitiveTypes[randomIndex];
- AZ_TracePrintf("ScriptCanvasTestFixture", "RandomPrimitiveType: %s\n", randomType.GetAZType().ToString<AZStd::string>().c_str());
- return randomType;
- }
- AZStd::vector< ScriptCanvas::Data::Type > GetBehaviorObjectTypes() const
- {
- return {
- m_dataSlotConfigurationType
- };
- }
- ScriptCanvas::Data::Type GetRandomObjectType() const
- {
- AZStd::vector< ScriptCanvas::Data::Type > objectTypes = GetBehaviorObjectTypes();
- // We have no types to randomize. Just return.
- if (objectTypes.empty())
- {
- return m_dataSlotConfigurationType;
- }
- int randomIndex = rand() % objectTypes.size();
- ScriptCanvas::Data::Type randomType = objectTypes[randomIndex];
- AZ_TracePrintf("ScriptCanvasTestFixture", "RandomObjectType: %s\n", randomType.GetAZType().ToString<AZStd::string>().c_str());
- return randomType;
- }
- AZStd::vector< ScriptCanvas::Data::Type > GetTypes() const
- {
- auto primitives = GetPrimitiveTypes();
- auto containers = GetContainerDataTypes();
- auto objects = GetBehaviorObjectTypes();
- primitives.reserve(containers.size() + objects.size());
- primitives.insert(primitives.end(), containers.begin(), containers.end());
- primitives.insert(primitives.end(), objects.begin(), objects.end());
- return primitives;
- }
- ScriptCanvas::Data::Type GetRandomType() const
- {
- AZStd::vector< ScriptCanvas::Data::Type > types = GetTypes();
- // We have no types to randomize. Just return.
- if (types.empty())
- {
- return m_dataSlotConfigurationType;
- }
- int randomIndex = rand() % types.size();
- ScriptCanvas::Data::Type randomType = types[randomIndex];
- AZ_TracePrintf("ScriptCanvasTestFixture", "RandomType: %s\n", randomType.GetAZType().ToString<AZStd::string>().c_str());
- return randomType;
- }
- AZStd::string GenerateSlotName()
- {
- AZStd::string slotName = AZStd::string::format("Slot %i", m_slotCounter);
- ++m_slotCounter;
- return slotName;
- }
- AZ::SerializeContext* m_serializeContext;
- AZ::BehaviorContext* m_behaviorContext;
- UnitTestEntityContext m_entityContext;
- // Really big(visually) data types just storing here for ease of use in situations.
- ScriptCanvas::Data::Type m_numericVectorType;
- ScriptCanvas::Data::Type m_stringToNumberMapType;
- ScriptCanvas::Data::Type m_dataSlotConfigurationType;
- ScriptCanvas::Graph* m_graph = nullptr;
- int m_slotCounter = 0;
- AZStd::unordered_map< AZ::EntityId, AZ::Entity* > m_entityMap;
- protected:
- static ScriptCanvasTests::Application* GetApplication() { return s_application; }
-
- private:
- static UnitTest::AllocatorsBase s_allocatorSetup;
- static bool s_setupSucceeded;
- AZStd::unordered_set< AZ::ComponentDescriptor* > m_descriptors;
-
- };
- }
|