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.
740 lines
29 KiB
C++
740 lines
29 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 <ScriptCanvas/Assets/ScriptCanvasAssetHandler.h>
|
|
#include <Asset/EditorAssetSystemComponent.h>
|
|
#include <AzCore/Asset/AssetManagerBus.h>
|
|
#include <AzCore/Component/TickBus.h>
|
|
#include <AzCore/IO/FileIO.h>
|
|
#include <AzCore/IO/IOUtils.h>
|
|
#include <AzCore/IO/FileIOEventBus.h>
|
|
#include <AzCore/UnitTest/UnitTest.h>
|
|
#include <AzFramework/API/ApplicationAPI.h>
|
|
#include <Editor/Framework/ScriptCanvasGraphUtilities.h>
|
|
#include <Editor/Framework/ScriptCanvasTraceUtilities.h>
|
|
#include <Framework/ScriptCanvasTestNodes.h>
|
|
#include <Framework/ScriptCanvasTestUtilities.h>
|
|
#include <ScriptCanvas/Asset/RuntimeAsset.h>
|
|
#include <ScriptCanvas/Asset/RuntimeAssetHandler.h>
|
|
#include <ScriptCanvas/Execution/RuntimeComponent.h>
|
|
|
|
namespace ScriptCanvasTestUtilitiesCPP
|
|
{
|
|
const char* k_defaultExtension = "scriptcanvas";
|
|
const char* k_scriptEventExtension = "scriptevents";
|
|
const char* k_unitTestDirPathRelative = "@engroot@/Gems/ScriptCanvasTesting/Assets/ScriptCanvas/UnitTests";
|
|
}
|
|
|
|
namespace ScriptCanvasTests
|
|
{
|
|
using namespace ScriptCanvas;
|
|
|
|
void ExpectParse(AZStd::string_view graphPath)
|
|
{
|
|
AZ_TEST_START_TRACE_SUPPRESSION;
|
|
const AZStd::string filePath = AZStd::string::format("%s/%s.%s", ScriptCanvasTestUtilitiesCPP::k_unitTestDirPathRelative, graphPath.data(), ScriptCanvasTestUtilitiesCPP::k_defaultExtension);
|
|
|
|
ScriptCanvasEditor::RunGraphSpec runGraphSpec;
|
|
runGraphSpec.graphPath = filePath;
|
|
runGraphSpec.dirPath = ScriptCanvasTestUtilitiesCPP::k_unitTestDirPathRelative;
|
|
runGraphSpec.runSpec.processOnly = true;
|
|
runGraphSpec.runSpec.execution = ExecutionMode::Interpreted;
|
|
auto reporters = ScriptCanvasEditor::RunGraph(runGraphSpec);
|
|
ScriptCanvasTests::VerifyReporter(reporters.front());
|
|
AZ_TEST_STOP_TRACE_SUPPRESSION_NO_COUNT;
|
|
}
|
|
|
|
void ExpectParseError(AZStd::string_view graphPath)
|
|
{
|
|
AZ_TEST_START_TRACE_SUPPRESSION;
|
|
const AZStd::string filePath = AZStd::string::format("%s/%s.%s", ScriptCanvasTestUtilitiesCPP::k_unitTestDirPathRelative, graphPath.data(), ScriptCanvasTestUtilitiesCPP::k_defaultExtension);
|
|
ScriptCanvasEditor::RunGraphSpec runGraphSpec;
|
|
runGraphSpec.runSpec.processOnly = true;
|
|
runGraphSpec.graphPath = filePath;
|
|
runGraphSpec.dirPath = ScriptCanvasTestUtilitiesCPP::k_unitTestDirPathRelative;
|
|
runGraphSpec.runSpec.execution = ExecutionMode::Interpreted;
|
|
auto reporters = ScriptCanvasEditor::RunGraph(runGraphSpec);
|
|
reporters.front().MarkExpectParseError();
|
|
ScriptCanvasTests::VerifyReporter(reporters.front());
|
|
AZ_TEST_STOP_TRACE_SUPPRESSION_NO_COUNT;
|
|
}
|
|
|
|
AZStd::string_view GetGraphNameFromPath(AZStd::string_view graphPath)
|
|
{
|
|
graphPath.remove_prefix(AZStd::min(graphPath.find_last_of("\\/") + 1, graphPath.size()));
|
|
return graphPath;
|
|
}
|
|
|
|
void VerifyReporter(const ScriptCanvasEditor::Reporter& reporter)
|
|
{
|
|
if (!reporter.IsGraphLoaded())
|
|
{
|
|
ADD_FAILURE() << "Graph was not successfully loaded.";
|
|
}
|
|
else if (reporter.ExpectsParseError())
|
|
{
|
|
if (!reporter.IsParseAttemptMade())
|
|
{
|
|
ADD_FAILURE() << "Expected a parse error but the graph never attempted to be parsed";
|
|
}
|
|
else if (reporter.IsCompiled())
|
|
{
|
|
ADD_FAILURE() << "Expected a parse error but graph compiled successfully";
|
|
}
|
|
}
|
|
else if (!reporter.IsCompiled())
|
|
{
|
|
ADD_FAILURE() << "Graph failed to compile";
|
|
}
|
|
else if (!reporter.GetScriptCanvasId().IsValid())
|
|
{
|
|
ADD_FAILURE() << "Graph is not valid, wasn't assigned properly to an entity";
|
|
}
|
|
else if (reporter.IsReportFinished())
|
|
{
|
|
bool reportCheckpoints = false;
|
|
|
|
if (!reporter.IsProcessOnly())
|
|
{
|
|
const auto& successes = reporter.GetSuccess();
|
|
for (const auto& success : successes)
|
|
{
|
|
SUCCEED() << success.c_str();
|
|
}
|
|
|
|
if (!reporter.IsActivated())
|
|
{
|
|
ADD_FAILURE() << "Graph did not activate";
|
|
}
|
|
|
|
if (!reporter.IsDeactivated())
|
|
{
|
|
ADD_FAILURE() << "Graph did not deactivate";
|
|
reportCheckpoints = true;
|
|
}
|
|
|
|
if (!reporter.ExpectsRuntimeFailure())
|
|
{
|
|
if (!reporter.IsComplete())
|
|
{
|
|
ADD_FAILURE() << "Graph was not marked complete";
|
|
reportCheckpoints = true;
|
|
}
|
|
|
|
if (!reporter.IsErrorFree())
|
|
{
|
|
ADD_FAILURE() << "Graph execution had errors";
|
|
reportCheckpoints = true;
|
|
|
|
const auto& failures = reporter.GetFailure();
|
|
for (const auto& failure : failures)
|
|
{
|
|
ADD_FAILURE() << failure.c_str();
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (reporter.IsErrorFree())
|
|
{
|
|
ADD_FAILURE() << "Graph expected error, but didn't report any";
|
|
reportCheckpoints = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (reportCheckpoints && !reporter.IsProcessOnly())
|
|
{
|
|
const auto& checkpoints = reporter.GetCheckpoints();
|
|
if (checkpoints.empty())
|
|
{
|
|
ADD_FAILURE() << "No checkpoints or other unit test nodes found, using them can help parse graph test failures";
|
|
}
|
|
else
|
|
{
|
|
AZStd::string checkpointPath = "Checkpoint Path:\n";
|
|
int i = 0;
|
|
|
|
for (const auto& checkpoint : checkpoints)
|
|
{
|
|
checkpointPath += AZStd::string::format("%2d: %s\n", ++i, checkpoint.c_str()).c_str();
|
|
}
|
|
|
|
ADD_FAILURE() << checkpointPath.c_str();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
const Execution::PerformanceTrackingReport& performance = reporter.GetPerformanceReport();
|
|
|
|
if (reporter.GetExecutionMode() == ExecutionMode::Interpreted)
|
|
{
|
|
std::cerr << "[INTERPRETED] ";
|
|
}
|
|
else
|
|
{
|
|
std::cerr << "[ NATIVE] ";
|
|
}
|
|
|
|
std::cerr << AZStd::string::format
|
|
(" Parse: %4.2f ms, Translate: %4.2f ms\n"
|
|
, reporter.GetParseDuration() / 1000.0
|
|
, reporter.GetTranslateDuration() / 1000.0).c_str();
|
|
|
|
double ready = aznumeric_caster(performance.timing.initializationTime);
|
|
double instant = aznumeric_caster(performance.timing.executionTime);
|
|
double latent = aznumeric_caster(performance.timing.latentTime);
|
|
double total = aznumeric_caster(performance.timing.totalTime);
|
|
|
|
std::cerr << "[ INITIALIZE] " << AZStd::string::format("%7.3f ms \n", ready / 1000.0).c_str();
|
|
|
|
std::cerr << "[ EXECUTION] " << AZStd::string::format("%7.3f ms \n", instant / 1000.0).c_str();
|
|
|
|
std::cerr << "[ LATENT] " << AZStd::string::format("%7.3f ms \n", latent / 1000.0).c_str();
|
|
|
|
std::cerr << "[ TOTAL] " << AZStd::string::format("%7.3f ms ", total / 1000.0).c_str();
|
|
|
|
switch (reporter.GetExecutionConfiguration())
|
|
{
|
|
case ScriptCanvasEditor::ExecutionConfiguration::Debug:
|
|
std::cerr << "[ DEBUG] ";
|
|
break;
|
|
case ScriptCanvasEditor::ExecutionConfiguration::Performance:
|
|
std::cerr << "[PERFORM] ";
|
|
break;
|
|
case ScriptCanvasEditor::ExecutionConfiguration::Release:
|
|
std::cerr << "[RELEASE] ";
|
|
break;
|
|
case ScriptCanvasEditor::ExecutionConfiguration::Traced:
|
|
std::cerr << "[ TRACED] ";
|
|
break;
|
|
}
|
|
std::cerr << "\n";
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ADD_FAILURE() << "Graph report did not finish";
|
|
}
|
|
}
|
|
|
|
void RunUnitTestGraph(AZStd::string_view graphPath)
|
|
{
|
|
ScriptCanvasTests::RunUnitTestGraph(graphPath, ScriptCanvasEditor::RunSpec());
|
|
}
|
|
|
|
void RunUnitTestGraph(AZStd::string_view graphPath, ExecutionMode execution)
|
|
{
|
|
ScriptCanvasEditor::RunSpec spec;
|
|
spec.execution = execution;
|
|
ScriptCanvasTests::RunUnitTestGraph(graphPath, spec);
|
|
}
|
|
|
|
void RunUnitTestGraph(AZStd::string_view graphPath, ExecutionMode execution, const ScriptCanvasEditor::DurationSpec& duration)
|
|
{
|
|
ScriptCanvasEditor::RunSpec runSpec;
|
|
runSpec.execution = execution;
|
|
runSpec.duration = duration;
|
|
RunUnitTestGraph(graphPath, runSpec);
|
|
}
|
|
|
|
void RunUnitTestGraph(AZStd::string_view graphPath, ExecutionMode execution, AZStd::string_view dependentScriptEvent)
|
|
{
|
|
AZ::Data::AssetType assetType(azrtti_typeid<ScriptEvents::ScriptEventsAsset>());
|
|
if (auto scriptEventAssetHandler = AZ::Data::AssetManager::Instance().GetHandler(assetType))
|
|
{
|
|
const AZStd::string fullPath = AZStd::string::format("%s/%s.%s", ScriptCanvasTestUtilitiesCPP::k_unitTestDirPathRelative, dependentScriptEvent.data(), ScriptCanvasTestUtilitiesCPP::k_scriptEventExtension);
|
|
|
|
// Preload dependent scriptevent asset for testing
|
|
AZStd::shared_ptr<AZ::Data::AssetDataStream> assetDataStream = AZStd::make_shared<AZ::Data::AssetDataStream>();
|
|
// Read in the data from a file to a buffer, then hand ownership of the buffer over to the assetDataStream
|
|
{
|
|
AZ::IO::FileIOStream stream(fullPath.c_str(), AZ::IO::OpenMode::ModeRead);
|
|
if (!AZ::IO::RetryOpenStream(stream))
|
|
{
|
|
ADD_FAILURE() << AZStd::string::format("CreateJobs for \"%s\" failed because the source file could not be opened.", fullPath.c_str()).data();
|
|
return;
|
|
}
|
|
AZStd::vector<AZ::u8> fileBuffer(stream.GetLength());
|
|
size_t bytesRead = stream.Read(fileBuffer.size(), fileBuffer.data());
|
|
if (bytesRead != stream.GetLength())
|
|
{
|
|
ADD_FAILURE() << AZStd::string::format("CreateJobs for \"%s\" failed because the source file could not be read.", fullPath.c_str()).data();
|
|
return;
|
|
}
|
|
assetDataStream->Open(AZStd::move(fileBuffer));
|
|
}
|
|
|
|
AZ::Data::Asset<ScriptEvents::ScriptEventsAsset> asset;
|
|
const AZStd::string hintPath = AZStd::string::format("scriptcanvas/unittests/%s.%s", dependentScriptEvent.data(), ScriptCanvasTestUtilitiesCPP::k_scriptEventExtension);
|
|
asset.Create(AZ::Data::AssetId(AZ::Uuid::CreateName(hintPath.data())));
|
|
|
|
if (scriptEventAssetHandler->LoadAssetDataFromStream(asset, assetDataStream, nullptr) != AZ::Data::AssetHandler::LoadResult::LoadComplete)
|
|
{
|
|
ADD_FAILURE() << AZStd::string::format("Failed to load ScriptEvent asset: %s", fullPath.data()).data();
|
|
return;
|
|
}
|
|
scriptEventAssetHandler->InitAsset(asset, true, false);
|
|
|
|
ScriptCanvasEditor::RunSpec spec;
|
|
spec.execution = execution;
|
|
ScriptCanvasTests::RunUnitTestGraph(graphPath, spec);
|
|
}
|
|
else
|
|
{
|
|
ADD_FAILURE() << "ScriptEvent asset handler is missing.";
|
|
}
|
|
}
|
|
|
|
void RunUnitTestGraph(AZStd::string_view graphPath, const ScriptCanvasEditor::DurationSpec& duration)
|
|
{
|
|
ScriptCanvasEditor::RunSpec spec;
|
|
spec.duration = duration;
|
|
ScriptCanvasTests::RunUnitTestGraph(graphPath, ExecutionMode::Interpreted, duration);
|
|
}
|
|
|
|
void RunUnitTestGraph(AZStd::string_view graphPath, const ScriptCanvasEditor::RunSpec& runSpec)
|
|
{
|
|
const AZStd::string filePath = AZStd::string::format("%s/%s.%s", ScriptCanvasTestUtilitiesCPP::k_unitTestDirPathRelative, graphPath.data(), ScriptCanvasTestUtilitiesCPP::k_defaultExtension);
|
|
|
|
ScriptCanvasEditor::RunGraphSpec runGraphSpec;
|
|
runGraphSpec.graphPath = filePath;
|
|
runGraphSpec.dirPath = ScriptCanvasTestUtilitiesCPP::k_unitTestDirPathRelative;
|
|
runGraphSpec.runSpec = runSpec;
|
|
|
|
AZ_TEST_START_TRACE_SUPPRESSION;
|
|
|
|
const ScriptCanvasEditor::Reporters reporters = ScriptCanvasEditor::RunGraph(runGraphSpec);
|
|
|
|
for (const auto& reporter : reporters)
|
|
{
|
|
ScriptCanvasTests::VerifyReporter(reporter);
|
|
}
|
|
|
|
if (reporters.size() == 2)
|
|
{
|
|
EXPECT_EQ(reporters.front(), reporters.back());
|
|
}
|
|
else if (reporters.size() > 2)
|
|
{
|
|
for (size_t lhs(0), rhs(1); rhs != reporters.size(); ++lhs, ++rhs)
|
|
{
|
|
EXPECT_EQ(reporters[lhs], reporters[rhs]);
|
|
}
|
|
}
|
|
|
|
AZ_TEST_STOP_TRACE_SUPPRESSION_NO_COUNT;
|
|
}
|
|
|
|
void RunUnitTestGraphMixed(AZStd::string_view graphPath, const ScriptCanvasEditor::DurationSpec& duration)
|
|
{
|
|
AZ_TEST_START_TRACE_SUPPRESSION;
|
|
|
|
ScriptCanvasEditor::RunGraphSpec runGraphSpec;
|
|
runGraphSpec.graphPath = graphPath;
|
|
runGraphSpec.dirPath = ScriptCanvasTestUtilitiesCPP::k_unitTestDirPathRelative;
|
|
runGraphSpec.runSpec.duration = duration;
|
|
|
|
runGraphSpec.runSpec.execution = ExecutionMode::Interpreted;
|
|
const ScriptCanvasEditor::Reporter reporterIterpreted0 = RunGraph(runGraphSpec).front();
|
|
runGraphSpec.runSpec.execution = ExecutionMode::Native;
|
|
const ScriptCanvasEditor::Reporter reporterNative0 = RunGraph(runGraphSpec).front();
|
|
runGraphSpec.runSpec.execution = ExecutionMode::Interpreted;
|
|
const ScriptCanvasEditor::Reporter reporterIterpreted1 = RunGraph(runGraphSpec).front();
|
|
runGraphSpec.runSpec.execution = ExecutionMode::Native;
|
|
const ScriptCanvasEditor::Reporter reporterNative1 = RunGraph(runGraphSpec).front();
|
|
|
|
VerifyReporter(reporterIterpreted0);
|
|
VerifyReporter(reporterNative0);
|
|
|
|
EXPECT_TRUE(reporterIterpreted0.IsActivated());
|
|
EXPECT_TRUE(reporterIterpreted1.IsComplete());
|
|
EXPECT_TRUE(reporterIterpreted0.IsErrorFree());
|
|
|
|
EXPECT_EQ(reporterNative0, reporterIterpreted0);
|
|
EXPECT_EQ(reporterNative0, reporterIterpreted1);
|
|
EXPECT_EQ(reporterNative1, reporterIterpreted0);
|
|
EXPECT_EQ(reporterNative1, reporterIterpreted1);
|
|
|
|
EXPECT_EQ(reporterNative0, reporterNative1);
|
|
EXPECT_EQ(reporterIterpreted0, reporterIterpreted1);
|
|
|
|
AZ_TEST_STOP_TRACE_SUPPRESSION_NO_COUNT;
|
|
}
|
|
|
|
void RunUnitTestGraphMixed(AZStd::string_view graphPath)
|
|
{
|
|
RunUnitTestGraphMixed(graphPath, ScriptCanvasEditor::DurationSpec());
|
|
}
|
|
|
|
TestBehaviorContextObject TestBehaviorContextObject::MaxReturnByValue(TestBehaviorContextObject lhs, TestBehaviorContextObject rhs)
|
|
{
|
|
return lhs.GetValue() >= rhs.GetValue() ? lhs : rhs;
|
|
}
|
|
|
|
const TestBehaviorContextObject* TestBehaviorContextObject::MaxReturnByPointer(const TestBehaviorContextObject* lhs, const TestBehaviorContextObject* rhs)
|
|
{
|
|
return (lhs && rhs && lhs->GetValue() >= rhs->GetValue()) ? lhs : rhs;
|
|
}
|
|
|
|
const TestBehaviorContextObject& TestBehaviorContextObject::MaxReturnByReference(const TestBehaviorContextObject& lhs, const TestBehaviorContextObject& rhs)
|
|
{
|
|
return lhs.GetValue() >= rhs.GetValue() ? lhs : rhs;
|
|
}
|
|
|
|
int TestBehaviorContextObject::MaxReturnByValueInteger(int lhs, int rhs)
|
|
{
|
|
return lhs >= rhs ? lhs : rhs;
|
|
}
|
|
|
|
const int* TestBehaviorContextObject::MaxReturnByPointerInteger(const int* lhs, const int* rhs)
|
|
{
|
|
return (lhs && rhs && (*lhs) >= (*rhs)) ? lhs : rhs;
|
|
}
|
|
|
|
const int& TestBehaviorContextObject::MaxReturnByReferenceInteger(const int& lhs, const int& rhs)
|
|
{
|
|
return lhs >= rhs ? lhs : rhs;
|
|
}
|
|
|
|
static void TestBehaviorContextObjectGenericConstructor(TestBehaviorContextObject* thisPtr)
|
|
{
|
|
new (thisPtr) TestBehaviorContextObject();
|
|
thisPtr->SetValue(0);
|
|
}
|
|
|
|
void TestBehaviorContextObject::Reflect(AZ::ReflectContext* reflectContext)
|
|
{
|
|
if (AZ::SerializeContext* serializeContext = azrtti_cast<AZ::SerializeContext*>(reflectContext))
|
|
{
|
|
serializeContext->Class<TestBehaviorContextObject>()
|
|
->Version(0)
|
|
->Field("m_value", &TestBehaviorContextObject::m_value)
|
|
->Field("isNormalized", &TestBehaviorContextObject::m_isNormalized)
|
|
;
|
|
}
|
|
|
|
if (AZ::BehaviorContext* behaviorContext = azrtti_cast<AZ::BehaviorContext*>(reflectContext))
|
|
{
|
|
behaviorContext->Class<TestBehaviorContextObject>("TestBehaviorContextObject")
|
|
->Attribute(AZ::Script::Attributes::ConstructorOverride, &TestBehaviorContextObjectGenericConstructor)
|
|
->Attribute(AZ::Script::Attributes::GenericConstructorOverride, &TestBehaviorContextObjectGenericConstructor)
|
|
->Method("In", &TestBehaviorContextObject::GetValue)
|
|
->Method("Out", &TestBehaviorContextObject::SetValue)
|
|
->Method("Normalize", &TestBehaviorContextObject::Normalize)
|
|
->Method("IsNormalized", &TestBehaviorContextObject::IsNormalized)
|
|
->Method("Denormalize", &TestBehaviorContextObject::Denormalize)
|
|
->Method("MaxReturnByValue", &TestBehaviorContextObject::MaxReturnByValue)
|
|
->Method("MaxReturnByPointer", &TestBehaviorContextObject::MaxReturnByPointer)
|
|
->Method("MaxReturnByReference", &TestBehaviorContextObject::MaxReturnByReference)
|
|
->Method("MaxReturnByValueInteger", &TestBehaviorContextObject::MaxReturnByValueInteger)
|
|
->Method("MaxReturnByPointerInteger", &TestBehaviorContextObject::MaxReturnByPointerInteger)
|
|
->Method("MaxReturnByReferenceInteger", &TestBehaviorContextObject::MaxReturnByReferenceInteger)
|
|
->Method<bool (TestBehaviorContextObject::*)(const TestBehaviorContextObject&) const>("LessThan", &TestBehaviorContextObject::operator<)
|
|
->Attribute(AZ::Script::Attributes::Operator, AZ::Script::Attributes::OperatorType::LessThan)
|
|
->Method<bool (TestBehaviorContextObject::*)(const TestBehaviorContextObject&) const>("LessEqualThan", &TestBehaviorContextObject::operator<=)
|
|
->Attribute(AZ::Script::Attributes::Operator, AZ::Script::Attributes::OperatorType::LessEqualThan)
|
|
->Method<bool (TestBehaviorContextObject::*)(const TestBehaviorContextObject&) const>("Equal", &TestBehaviorContextObject::operator==)
|
|
->Attribute(AZ::Script::Attributes::Operator, AZ::Script::Attributes::OperatorType::Equal)
|
|
;
|
|
}
|
|
}
|
|
|
|
TestBehaviorContextObject MaxReturnByValue(TestBehaviorContextObject lhs, TestBehaviorContextObject rhs)
|
|
{
|
|
return lhs.GetValue() >= rhs.GetValue() ? lhs : rhs;
|
|
}
|
|
|
|
const TestBehaviorContextObject* MaxReturnByPointer(const TestBehaviorContextObject* lhs, const TestBehaviorContextObject* rhs)
|
|
{
|
|
return (lhs && rhs && (lhs->GetValue() >= rhs->GetValue())) ? lhs : rhs;
|
|
}
|
|
|
|
const TestBehaviorContextObject& MaxReturnByReference(const TestBehaviorContextObject& lhs, const TestBehaviorContextObject& rhs)
|
|
{
|
|
return lhs.GetValue() >= rhs.GetValue() ? lhs : rhs;
|
|
}
|
|
|
|
AZ::u32 TestBehaviorContextObject::s_createdCount = 0;
|
|
AZ::u32 TestBehaviorContextObject::s_destroyedCount = 0;
|
|
|
|
AZ::EntityId CreateClassFunctionNode(const ScriptCanvasId& scriptCanvasId, AZStd::string_view className, AZStd::string_view methodName)
|
|
{
|
|
using namespace ScriptCanvas;
|
|
|
|
ScriptCanvas::NamespacePath emptyNamespaces;
|
|
|
|
AZ::Entity* splitEntity{ aznew AZ::Entity };
|
|
splitEntity->Init();
|
|
AZ::EntityId methodNodeID{ splitEntity->GetId() };
|
|
SystemRequestBus::Broadcast(&SystemRequests::CreateNodeOnEntity, methodNodeID, scriptCanvasId, ScriptCanvas::Nodes::Core::Method::RTTI_Type());
|
|
ScriptCanvas::Nodes::Core::Method* methodNode(nullptr);
|
|
SystemRequestBus::BroadcastResult(methodNode, &SystemRequests::GetNode<ScriptCanvas::Nodes::Core::Method>, methodNodeID);
|
|
EXPECT_TRUE(methodNode != nullptr);
|
|
methodNode->InitializeBehaviorMethod(emptyNamespaces, className, methodName, ScriptCanvas::PropertyStatus::None);
|
|
return methodNodeID;
|
|
}
|
|
|
|
AZStd::string SlotDescriptorToString(ScriptCanvas::SlotDescriptor descriptor)
|
|
{
|
|
AZStd::string name;
|
|
|
|
switch (descriptor.m_slotType)
|
|
{
|
|
case SlotTypeDescriptor::Data:
|
|
name.append("Data");
|
|
break;
|
|
case SlotTypeDescriptor::Execution:
|
|
name.append("Execution");
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
switch (descriptor.m_connectionType)
|
|
{
|
|
case ConnectionType::Input:
|
|
name.append("In");
|
|
break;
|
|
case ConnectionType::Output:
|
|
name.append("Out");
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return name;
|
|
}
|
|
|
|
void DumpSlots([[maybe_unused]] const ScriptCanvas::Node& node)
|
|
{
|
|
#if defined(AZ_ENABLE_TRACING)
|
|
const auto& nodeslots = node.GetSlots();
|
|
|
|
for (const auto& nodeslot : nodeslots)
|
|
{
|
|
AZ_TracePrintf("ScriptCanvasTest", "'%s':%s\n", nodeslot.GetName().data(), SlotDescriptorToString(nodeslot.GetDescriptor()).c_str());
|
|
}
|
|
#endif
|
|
}
|
|
|
|
bool Connect(ScriptCanvas::Graph& graph, const AZ::EntityId& fromNodeID, const char* fromSlotName, const AZ::EntityId& toNodeID, const char* toSlotName, bool dumpSlotsOnFailure /*= true*/)
|
|
{
|
|
using namespace ScriptCanvas;
|
|
AZ::Entity* fromNode{};
|
|
AZ::ComponentApplicationBus::BroadcastResult(fromNode, &AZ::ComponentApplicationBus::Events::FindEntity, fromNodeID);
|
|
AZ::Entity* toNode{};
|
|
AZ::ComponentApplicationBus::BroadcastResult(toNode, &AZ::ComponentApplicationBus::Events::FindEntity, toNodeID);
|
|
if (fromNode && toNode)
|
|
{
|
|
Node* from = AZ::EntityUtils::FindFirstDerivedComponent<Node>(fromNode);
|
|
Node* to = AZ::EntityUtils::FindFirstDerivedComponent<Node>(toNode);
|
|
|
|
auto fromSlotId = from->GetSlotId(fromSlotName);
|
|
auto toSlotId = to->GetSlotId(toSlotName);
|
|
|
|
if (graph.Connect(fromNodeID, fromSlotId, toNodeID, toSlotId))
|
|
{
|
|
return true;
|
|
}
|
|
else if (dumpSlotsOnFailure)
|
|
{
|
|
AZ_TracePrintf("ScriptCanvasTest", "Slots from:\n");
|
|
DumpSlots(*from);
|
|
AZ_TracePrintf("ScriptCanvasTest", "\nSlots to:\n");
|
|
DumpSlots(*to);
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
AZ::Entity* UnitTestEntityContext::CreateEntity(const char* name)
|
|
{
|
|
auto entity = aznew AZ::Entity(name);
|
|
AddEntity(entity);
|
|
return entity;
|
|
}
|
|
|
|
void UnitTestEntityContext::AddEntity(AZ::Entity* entity)
|
|
{
|
|
AddEntity(entity->GetId());
|
|
}
|
|
|
|
void UnitTestEntityContext::AddEntity(AZ::EntityId entityId)
|
|
{
|
|
AZ_Assert(!AzFramework::EntityIdContextQueryBus::FindFirstHandler(entityId), "Entity already belongs to a context.");
|
|
m_unitTestEntityIdMap.emplace(entityId, entityId);
|
|
AzFramework::EntityIdContextQueryBus::MultiHandler::BusConnect(entityId);
|
|
}
|
|
|
|
void UnitTestEntityContext::RemoveEntity(AZ::EntityId entityId)
|
|
{
|
|
auto foundIt = m_unitTestEntityIdMap.find(entityId);
|
|
if (foundIt != m_unitTestEntityIdMap.end())
|
|
{
|
|
AzFramework::EntityIdContextQueryBus::MultiHandler::BusDisconnect(entityId);
|
|
m_unitTestEntityIdMap.erase(foundIt);
|
|
}
|
|
}
|
|
|
|
void UnitTestEntityContext::ActivateEntity(AZ::EntityId entityId)
|
|
{
|
|
if (IsOwnedByThisContext(entityId))
|
|
{
|
|
AZ::Entity* entity{};
|
|
AZ::ComponentApplicationBus::BroadcastResult(entity, &AZ::ComponentApplicationRequests::FindEntity, entityId);
|
|
if (entity)
|
|
{
|
|
if (entity->GetState() == AZ::Entity::State::Constructed)
|
|
{
|
|
entity->Init();
|
|
}
|
|
if (entity->GetState() == AZ::Entity::State::Init)
|
|
{
|
|
entity->Activate();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void UnitTestEntityContext::DeactivateEntity(AZ::EntityId entityId)
|
|
{
|
|
if (IsOwnedByThisContext(entityId))
|
|
{
|
|
AZ::Entity* entity{};
|
|
AZ::ComponentApplicationBus::BroadcastResult(entity, &AZ::ComponentApplicationRequests::FindEntity, entityId);
|
|
if (entity)
|
|
{
|
|
if (entity->GetState() == AZ::Entity::State::Active)
|
|
{
|
|
entity->Deactivate();
|
|
}
|
|
else if (entity->GetState() == AZ::Entity::State::Activating)
|
|
{
|
|
// Queue Deactivation to next frame
|
|
AZ::SystemTickBus::QueueFunction(&AZ::Entity::Activate, entity);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
bool UnitTestEntityContext::DestroyEntity(AZ::Entity* entity)
|
|
{
|
|
if (entity)
|
|
{
|
|
auto foundIt = m_unitTestEntityIdMap.find(entity->GetId());
|
|
if (foundIt != m_unitTestEntityIdMap.end())
|
|
{
|
|
AzFramework::EntityIdContextQueryBus::MultiHandler::BusDisconnect(entity->GetId());
|
|
m_unitTestEntityIdMap.erase(foundIt);
|
|
delete entity;
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
bool UnitTestEntityContext::DestroyEntityById(AZ::EntityId entityId)
|
|
{
|
|
AZ::Entity* entity{};
|
|
AZ::ComponentApplicationBus::BroadcastResult(entity, &AZ::ComponentApplicationRequests::FindEntity, entityId);
|
|
return DestroyEntity(entity);
|
|
}
|
|
|
|
void UnitTestEntityContext::ResetContext()
|
|
{
|
|
AzFramework::EntityIdContextQueryBus::MultiHandler::BusDisconnect();
|
|
m_unitTestEntityIdMap.clear();
|
|
}
|
|
|
|
AZ::EntityId UnitTestEntityContext::FindLoadedEntityIdMapping(const AZ::EntityId& staticId) const
|
|
{
|
|
auto idIter = m_unitTestEntityIdMap.find(staticId);
|
|
|
|
if (idIter != m_unitTestEntityIdMap.end())
|
|
{
|
|
return idIter->second;
|
|
}
|
|
|
|
return AZ::EntityId();
|
|
}
|
|
|
|
AZ::Entity* UnitTestEntityContext::CloneEntity(const AZ::Entity& sourceEntity)
|
|
{
|
|
if (!IsOwnedByThisContext(sourceEntity.GetId()))
|
|
{
|
|
AZ_Warning("Script Canvas", false, "Entity %s does not belong to the unit test entity context.", sourceEntity.GetName().data());
|
|
return {};
|
|
}
|
|
|
|
AZ::SerializeContext* serializeContext{};
|
|
AZ::ComponentApplicationBus::BroadcastResult(serializeContext, &AZ::ComponentApplicationRequests::GetSerializeContext);
|
|
AZ::Entity* cloneEntity = serializeContext->CloneObject(&sourceEntity);
|
|
if (cloneEntity)
|
|
{
|
|
cloneEntity->SetId(AZ::Entity::MakeId());
|
|
AddEntity(cloneEntity);
|
|
}
|
|
|
|
return cloneEntity;
|
|
}
|
|
|
|
//AZ::Data::AssetId UnitTestEntityContext::CurrentlyInstantiatingSlice()
|
|
//{
|
|
// return AZ::Data::AssetId();
|
|
//}
|
|
|
|
//bool UnitTestEntityContext::HandleRootEntityReloadedFromStream(AZ::Entity*, bool, AZ::SliceComponent::EntityIdToEntityIdMap*)
|
|
//{
|
|
// return true;
|
|
//}
|
|
|
|
//AZ::SliceComponent* UnitTestEntityContext::GetRootSlice()
|
|
//{
|
|
// return {};
|
|
//}
|
|
|
|
//const AZStd::unordered_map<AZ::EntityId, AZ::EntityId>& UnitTestEntityContext::GetLoadedEntityIdMap()
|
|
//{
|
|
// return m_unitTestEntityIdMap;
|
|
//}
|
|
|
|
//AzFramework::SliceInstantiationTicket UnitTestEntityContext::InstantiateSlice(const AZ::Data::Asset<AZ::Data::AssetData>&,
|
|
// const AZ::IdUtils::Remapper<AZ::EntityId>::IdMapper&, const AZ::Data::AssetFilterCB&)
|
|
//{
|
|
// return AzFramework::SliceInstantiationTicket();
|
|
//}
|
|
|
|
//AZ::SliceComponent::SliceInstanceAddress UnitTestEntityContext::CloneSliceInstance(
|
|
// AZ::SliceComponent::SliceInstanceAddress, AZ::SliceComponent::EntityIdToEntityIdMap&)
|
|
//{
|
|
// return AZ::SliceComponent::SliceInstanceAddress();
|
|
//}
|
|
|
|
//void UnitTestEntityContext::CancelSliceInstantiation(const AzFramework::SliceInstantiationTicket&)
|
|
//{
|
|
//}
|
|
|
|
//AzFramework::SliceInstantiationTicket UnitTestEntityContext::GenerateSliceInstantiationTicket()
|
|
//{
|
|
// return AzFramework::SliceInstantiationTicket();
|
|
//}
|
|
|
|
//void UnitTestEntityContext::SetIsDynamic(bool)
|
|
//{
|
|
//}
|
|
|
|
//const AzFramework::RootSliceAsset& UnitTestEntityContext::GetRootAsset() const
|
|
//{
|
|
// return m_unitTestRootAsset;
|
|
//}
|
|
|
|
} // ScriptCanvasTests
|