Files
o3de/Gems/ScriptCanvasTesting/Code/Source/Framework/ScriptCanvasTestFixture.h
T
lumberyard-employee-dm 5fc4551ac0 [LYN-8041] Enable relocation of the Project Game Release Layout (#5380)
* Enable relocation of the Project Game Release Layout

Relocating the Project Game Release Layout to another directory on the file system failed due to the querying of the engine root failing due to the ComponentApplication::m_engineRoot not using the project path stored in the SettingsRegisry if the engine root cannot be detected

Removed the ApplicationRequestBus GetEngineRoot function.
The ComponentApplicationRequestBus has a function of the same name that returns the same path.

Removed the deprecated GetAppRoot function.
The path it returns has no defined value. It was not the engine root or the project root.
Removed unused CFileUtil and CFileUtil_impl functions that were invoking the ApplicationREquestBus GetEngineRoot function.
On the way to update the functions it was discovered that they aren't called

Added a CalculateBranchToken overload that can populate a fixed_string to avoid heap allocations

Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com>

* Protect against an empty list of artifacts to remove when generating the
engine.pak

Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com>
2021-11-09 12:03:52 -06:00

418 lines
17 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
*
*/
#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;
};
}