Integrating latest 47acbe8

This commit is contained in:
alexpete
2021-03-25 13:57:57 -07:00
parent 448c549698
commit 75dc720198
10312 changed files with 2711566 additions and 671451 deletions
@@ -128,7 +128,11 @@ namespace UnitTest
QTemporaryDir m_tempDir {QDir(QStandardPaths::writableLocation(QStandardPaths::TempLocation)).filePath("ArchiveTests-")};
};
#if AZ_TRAIT_DISABLE_FAILED_ARCHIVE_TESTS
TEST_F(ArchiveTest, DISABLED_CreateArchiveBlocking_FilesAtThreeDepths_ArchiveCreated)
#else
TEST_F(ArchiveTest, CreateArchiveBlocking_FilesAtThreeDepths_ArchiveCreated)
#endif // AZ_TRAIT_DISABLE_FAILED_ARCHIVE_TESTS
{
EXPECT_TRUE(m_tempDir.isValid());
CreateArchiveFolder();
@@ -138,7 +142,11 @@ namespace UnitTest
EXPECT_EQ(createResult, true);
}
#if AZ_TRAIT_DISABLE_FAILED_ARCHIVE_TESTS
TEST_F(ArchiveTest, DISABLED_ListFilesInArchiveBlocking_FilesAtThreeDepths_FilesFound)
#else
TEST_F(ArchiveTest, ListFilesInArchiveBlocking_FilesAtThreeDepths_FilesFound)
#endif // AZ_TRAIT_DISABLE_FAILED_ARCHIVE_TESTS
{
EXPECT_TRUE(m_tempDir.isValid());
CreateArchiveFolder();
@@ -152,7 +160,11 @@ namespace UnitTest
EXPECT_EQ(fileList.size(), 6);
}
#if AZ_TRAIT_DISABLE_FAILED_ARCHIVE_TESTS
TEST_F(ArchiveTest, DISABLED_CreateDeltaCatalog_AssetsNotRegistered_Failure)
#else
TEST_F(ArchiveTest, CreateDeltaCatalog_AssetsNotRegistered_Failure)
#endif // AZ_TRAIT_DISABLE_FAILED_ARCHIVE_TESTS
{
QStringList fileList = CreateArchiveFileList();
@@ -169,7 +181,11 @@ namespace UnitTest
EXPECT_EQ(catalogCreated, false);
}
#if AZ_TRAIT_DISABLE_FAILED_ARCHIVE_TESTS
TEST_F(ArchiveTest, DISABLED_CreateDeltaCatalog_ArchiveWithoutCatalogAssetsRegistered_Success)
#else
TEST_F(ArchiveTest, CreateDeltaCatalog_ArchiveWithoutCatalogAssetsRegistered_Success)
#endif // AZ_TRAIT_DISABLE_FAILED_ARCHIVE_TESTS
{
QStringList fileList = CreateArchiveFileList();
@@ -69,9 +69,6 @@ namespace //anonymous
"executable_name": "DummyProjectLauncher",
"modules" : [],
"project_id": "{91FB81A1-072C-4A80-8FCC-7E2C4C767B4D}",
"xenia_settings" : {
},
"android_settings" : {
"package_name" : "com.lumberyard.yourgame",
@@ -0,0 +1,51 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and 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.
*
*/
#if defined(HAVE_BENCHMARK)
#include <Prefab/Benchmark/PrefabBenchmarkFixture.h>
#include <AzToolsFramework/Prefab/Spawnable/SpawnableUtils.h>
namespace Benchmark
{
using BM_SpawnableCreate = BM_Prefab;
using namespace AzToolsFramework::Prefab;
BENCHMARK_DEFINE_F(BM_SpawnableCreate, CreateSpawnable_SingleEntityInstance)(::benchmark::State& state)
{
const unsigned int numSpawnables = state.range();
AZStd::unique_ptr<Instance> instance(m_prefabSystemComponent->CreatePrefab(
{ CreateEntity("Entity1") },
{},
m_pathString));
auto& prefabDom = m_prefabSystemComponent->FindTemplateDom(instance->GetTemplateId());
for (auto _ : state)
{
state.PauseTiming();
auto spawnable = ::AzToolsFramework::Prefab::SpawnableUtils::CreateSpawnable(prefabDom);
state.ResumeTiming();
}
state.SetComplexityN(numSpawnables);
}
BENCHMARK_REGISTER_F(BM_SpawnableCreate, CreateSpawnable_SingleEntityInstance)
->RangeMultiplier(10)
->Range(100, 10000)
->Unit(benchmark::kMillisecond)
->Complexity();
}
#endif
@@ -0,0 +1,273 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and 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 <Prefab/PrefabTestDomUtils.h>
#include <Prefab/PrefabTestComponent.h>
#include <Prefab/PrefabTestFixture.h>
namespace UnitTest
{
using PrefabEntityAliasTests = PrefabTestFixture;
TEST_F(PrefabEntityAliasTests, PrefabEntityAlias_ReferenceEntityWithinSameInstance_ReferencePersists)
{
// Make a new entity with a test component
AZ::Entity* newEntity = CreateEntity("New Entity", false);
PrefabTestComponent* newComponent = newEntity->CreateComponent<PrefabTestComponent>();
ASSERT_TRUE(newComponent);
// Generate a second entity that will be referenced by the first
AZ::Entity* referencedEntity = CreateEntity("Referenced Entity");
newComponent->m_entityIdProperty = referencedEntity->GetId();
// Place both entities in the same prefab
AZStd::unique_ptr<Instance> newInstance =
m_prefabSystemComponent->CreatePrefab({ newEntity, referencedEntity }, {}, "test/path");
ASSERT_TRUE(newInstance);
// Grab the alias of both entities so they can be found in a new instantiation
EntityAliasOptionalReference newEntityAliasRef = newInstance->GetEntityAlias(newEntity->GetId());
ASSERT_TRUE(newEntityAliasRef);
EntityAliasOptionalReference referencedEntityAliasRef = newInstance->GetEntityAlias(referencedEntity->GetId());
ASSERT_TRUE(referencedEntityAliasRef);
EntityAlias newEntityAlias = newEntityAliasRef.value();
EntityAlias referencedEntityAlias = referencedEntityAliasRef.value();
// A new instance should maintain the entity reference while also having unique entity ids
AZStd::unique_ptr<Instance> secondInstance =
m_prefabSystemComponent->InstantiatePrefab(newInstance->GetTemplateId());
// Activate the entities so that we can find them via the component application bus
secondInstance->InitializeEntities();
secondInstance->ActivateEntities();
AZ::Entity* secondNewEntity = nullptr;
AZ::ComponentApplicationBus::BroadcastResult(secondNewEntity,
&AZ::ComponentApplicationBus::Events::FindEntity, secondInstance->GetEntityId(newEntityAlias));
ASSERT_TRUE(secondNewEntity);
PrefabTestComponent* secondComponent = secondNewEntity->FindComponent<PrefabTestComponent>();
ASSERT_TRUE(secondComponent);
// Validate that the entity reference is preserved in the second instance
ASSERT_TRUE(secondComponent->m_entityIdProperty.IsValid());
ASSERT_EQ(secondComponent->m_entityIdProperty, secondInstance->GetEntityId(referencedEntityAlias));
}
TEST_F(PrefabEntityAliasTests, PrefabEntityAlias_ReferenceNotInSameHierarchy_ReferenceGoesToNull)
{
// Make a new entity with a test component
AZ::Entity* newEntity = CreateEntity("New Entity", false);
PrefabTestComponent* newComponent = newEntity->CreateComponent<PrefabTestComponent>();
ASSERT_TRUE(newComponent);
// Generate a second entity that will be referenced by the first
// however we won't add both to the same prefab hierarchy
AZ::Entity* referencedEntity = CreateEntity("Referenced Entity");
newComponent->m_entityIdProperty = referencedEntity->GetId();
AZStd::unique_ptr<Instance> unrelatedInstance =
m_prefabSystemComponent->CreatePrefab({ referencedEntity }, {}, "test/path/0");
AZStd::unique_ptr<Instance> firstInstance =
m_prefabSystemComponent->CreatePrefab({ newEntity }, {}, "test/path/1");
ASSERT_TRUE(firstInstance);
// Grab the alias of newEntity so it can be found in a new instantiation
EntityAliasOptionalReference newEntityAliasRef = firstInstance->GetEntityAlias(newEntity->GetId());
ASSERT_TRUE(newEntityAliasRef);
EntityAlias newEntityAlias = newEntityAliasRef.value();
// On instantiation the referenced entity should be invalid
AZStd::unique_ptr<Instance> secondInstance =
m_prefabSystemComponent->InstantiatePrefab(firstInstance->GetTemplateId());
// Activate the entities so that we can find them via the component application bus
secondInstance->InitializeEntities();
secondInstance->ActivateEntities();
AZ::Entity* secondNewEntity = nullptr;
AZ::ComponentApplicationBus::BroadcastResult(secondNewEntity,
&AZ::ComponentApplicationBus::Events::FindEntity, secondInstance->GetEntityId(newEntityAlias));
ASSERT_TRUE(secondNewEntity);
PrefabTestComponent* secondComponent = secondNewEntity->FindComponent<PrefabTestComponent>();
ASSERT_TRUE(secondComponent);
ASSERT_FALSE(secondComponent->m_entityIdProperty.IsValid());
}
TEST_F(PrefabEntityAliasTests, PrefabEntityAlias_ReferenceEntityFoundInNestedInstance_ReferencePersists)
{
// Make a new entity with a test component
AZ::Entity* newEntity = CreateEntity("New Entity", false);
PrefabTestComponent* newComponent = newEntity->CreateComponent<PrefabTestComponent>();
ASSERT_TRUE(newComponent);
// Generate a second entity that will be referenced by the first
AZ::Entity* referencedEntity = CreateEntity("Referenced Entity");
newComponent->m_entityIdProperty = referencedEntity->GetId();
// Build out a prefab holding the referenced entity
AZStd::unique_ptr<Instance> nestedInstance =
m_prefabSystemComponent->CreatePrefab({ referencedEntity }, {}, "Test/Path/0");
// Grab the alias of the nested instance
EntityAliasOptionalReference referencedEntityAliasRef =
nestedInstance->GetEntityAlias(referencedEntity->GetId());
ASSERT_TRUE(referencedEntityAliasRef);
EntityAlias referencedEntityAlias = referencedEntityAliasRef.value();
TemplateId nestedTemplateId = nestedInstance->GetTemplateId();
// Create our root instance and nest our first instance under it
AZStd::unique_ptr<Instance> rootInstance =
m_prefabSystemComponent->CreatePrefab({ newEntity },
PrefabTestUtils::MakeInstanceList(AZStd::move(nestedInstance)), "Test/Path/1");
// Acquire the alias name of our entity so we can look it up in future instances
EntityAliasOptionalReference newEntityAliasRef =
rootInstance->GetEntityAlias(newEntity->GetId());
ASSERT_TRUE(newEntityAliasRef);
EntityAlias newEntityAlias = newEntityAliasRef.value();
// Acquire the nested instance alias so we can look it up in future instances
AZStd::vector<InstanceAlias> nestedInstanceAliases = rootInstance->GetNestedInstanceAliases(nestedTemplateId);
ASSERT_EQ(nestedInstanceAliases.size(), 1);
InstanceAlias nestedAlias = nestedInstanceAliases[0];
// Make a new instance of root
// Entity references should be preserved among its unique entities
AZStd::unique_ptr<Instance> secondRootInstance =
m_prefabSystemComponent->InstantiatePrefab(rootInstance->GetTemplateId());
ASSERT_TRUE(secondRootInstance);
// Activate the entities so that we can find them via the component application bus
secondRootInstance->InitializeNestedEntities();
secondRootInstance->ActivateNestedEntities();
// Find the new instances versions of the new and referenced entities using the aliases we saved
AZ::EntityId secondNewEntityId = secondRootInstance->GetEntityId(newEntityAlias);
InstanceOptionalReference secondNestedInstance = secondRootInstance->FindNestedInstance(nestedAlias);
ASSERT_TRUE(secondNestedInstance);
AZ::EntityId secondReferencedEntityId = secondNestedInstance->get().GetEntityId(referencedEntityAlias);
AZ::Entity* secondNewEntity = nullptr;
AZ::ComponentApplicationBus::BroadcastResult(secondNewEntity,
&AZ::ComponentApplicationBus::Events::FindEntity, secondNewEntityId);
ASSERT_TRUE(secondNewEntity);
PrefabTestComponent* secondComponent = secondNewEntity->FindComponent<PrefabTestComponent>();
ASSERT_TRUE(secondComponent);
EXPECT_TRUE(secondComponent->m_entityIdProperty.IsValid());
EXPECT_EQ(secondComponent->m_entityIdProperty, secondReferencedEntityId);
}
TEST_F(PrefabEntityAliasTests, PrefabEntityAlias_ReferenceEntityFoundInParentInstance_ReferencePersists)
{
// Make a new entity with a test component
AZ::Entity* newEntity = CreateEntity("New Entity", false);
PrefabTestComponent* newComponent = newEntity->CreateComponent<PrefabTestComponent>();
ASSERT_TRUE(newComponent);
// Generate a second entity that will be referenced by the first
AZ::Entity* referencedEntity = CreateEntity("Referenced Entity");
// Make our first instance to be nested under the prefab containing the entity we reference
AZStd::unique_ptr<Instance> nestedInstance =
m_prefabSystemComponent->CreatePrefab({ newEntity }, {}, "Test/Path/0");
// Save off the entity alias so we can find it in future instances
EntityAliasOptionalReference newEntityAliasRef = nestedInstance->GetEntityAlias(newEntity->GetId());
ASSERT_TRUE(newEntityAliasRef);
EntityAlias entityAlias = newEntityAliasRef.value();
TemplateId nestedTemplateId = nestedInstance->GetTemplateId();
// Make our root instance which contains the entity being referenced
AZStd::unique_ptr<Instance> rootInstance =
m_prefabSystemComponent->CreatePrefab({ referencedEntity },
PrefabTestUtils::MakeInstanceList(AZStd::move(nestedInstance)), "Test/Path/1");
// Acquire the nested instance alias so we can look it up in future instances
AZStd::vector<InstanceAlias> nestedInstanceAliases = rootInstance->GetNestedInstanceAliases(nestedTemplateId);
ASSERT_EQ(nestedInstanceAliases.size(), 1);
InstanceAlias nestedAlias = nestedInstanceAliases[0];
// Save off the referenced entity alias
EntityAliasOptionalReference referencedEntityAliasRef =
rootInstance->GetEntityAlias(referencedEntity->GetId());
ASSERT_TRUE(referencedEntityAliasRef);
EntityAlias referencedEntityAlias = referencedEntityAliasRef.value();
// Capture the before and after for setting the reference property
PrefabDom entityDomBeforeUpdate;
m_instanceToTemplateInterface->GenerateDomForEntity(entityDomBeforeUpdate, *newEntity);
newComponent->m_entityIdProperty = referencedEntity->GetId();
PrefabDom entityDomAfterUpdate;
m_instanceToTemplateInterface->GenerateDomForEntity(entityDomAfterUpdate, *newEntity);
PrefabDom patch;
m_instanceToTemplateInterface->GeneratePatch(patch, entityDomBeforeUpdate, entityDomAfterUpdate);
// Patch the nested prefab to reference an entity in its parent
m_instanceToTemplateInterface->PatchEntityInTemplate(patch, newEntity->GetId());
// Using the aliases we saved grab the updated entities so we can verify the entity reference is still preserved
InstanceOptionalReference updatedNestedInstance = rootInstance->FindNestedInstance(nestedAlias);
ASSERT_TRUE(updatedNestedInstance);
AZ::EntityId updatedNewEntityId = updatedNestedInstance->get().GetEntityId(entityAlias);
AZ::Entity* updatedNewEntity = nullptr;
// Activate the entities so that we can find them via the component application bus
rootInstance->InitializeNestedEntities();
rootInstance->ActivateNestedEntities();
AZ::ComponentApplicationBus::BroadcastResult(updatedNewEntity,
&AZ::ComponentApplicationBus::Events::FindEntity, updatedNewEntityId);
ASSERT_TRUE(updatedNewEntity);
PrefabTestComponent* updatedComponent = updatedNewEntity->FindComponent<PrefabTestComponent>();
ASSERT_TRUE(updatedComponent);
AZ::EntityId updatedReferencedEntityId = rootInstance->GetEntityId(referencedEntityAlias);
EXPECT_TRUE(updatedComponent->m_entityIdProperty.IsValid());
EXPECT_EQ(updatedComponent->m_entityIdProperty, updatedReferencedEntityId);
}
}
@@ -38,6 +38,11 @@ namespace UnitTest
AZStd::unique_ptr<Instance> firstInstance = m_prefabSystemComponent->CreatePrefab({ newEntity }, {}, "test/path");
ASSERT_TRUE(firstInstance);
EntityAliasOptionalReference newEntityAliasReference = firstInstance->GetEntityAlias(entityId);
ASSERT_TRUE(newEntityAliasReference);
EntityAlias newEntityAlias = newEntityAliasReference.value();
//get template id
TemplateId templateId = firstInstance->GetTemplateId();
@@ -69,22 +74,14 @@ namespace UnitTest
secondInstance->ActivateNestedEntities();
//get the entity id
AZStd::vector<AZ::EntityId> entityIdVector;
secondInstance->GetEntityIds([&entityIdVector](const AZ::EntityId& entityId)
{
entityIdVector.push_back(entityId);
return true;
});
EXPECT_EQ(entityIdVector.size(), 1);
AZStd::optional<AZ::EntityId> secondEntityId = entityIdVector[0];
AZ::EntityId secondEntityId = secondInstance->GetEntityId(newEntityAlias);
ASSERT_TRUE(secondEntityId.IsValid());
//verify template updated correctly
//get the values from the transform on the entity
float confirmXValue = 0.0f;
AZ::TransformBus::EventResult(confirmXValue, entityId, &AZ::TransformInterface::GetWorldX);
AZ::TransformBus::EventResult(confirmXValue, secondEntityId.value(), &AZ::TransformInterface::GetWorldX);
AZ::TransformBus::EventResult(confirmXValue, secondEntityId, &AZ::TransformInterface::GetWorldX);
ASSERT_TRUE(confirmXValue == updatedXValue);
}
@@ -128,20 +125,21 @@ namespace UnitTest
//get the entity id
AZStd::vector<AZ::EntityId> entityIdVector;
secondInstance->GetEntityIds([&entityIdVector](const AZ::EntityId& entityId)
secondInstance->GetEntityIds([&entityIdVector](AZ::EntityId entityId)
{
entityIdVector.push_back(entityId);
return true;
});
EXPECT_EQ(entityIdVector.size(), 1);
// There should be 2 entities in the instance, the container entity and the one we added
EXPECT_EQ(entityIdVector.size(), 2);
}
TEST_F(PrefabInstanceToTemplateTests, PrefabUpdateTemplate_RemoveEntityFromInstance)
{
//create template with single entity
const char* newEntityName = "New Entity";
AZ::Entity* newEntity = CreateEntity(newEntityName, false);
AZ::Entity* newEntity = CreateEntity("New Entity", false);
ASSERT_TRUE(newEntity);
AZ::EntityId entityId = newEntity->GetId();
@@ -177,13 +175,14 @@ namespace UnitTest
//get the entity id
AZStd::vector<AZ::EntityId> entityIdVector;
secondInstance->GetEntityIds([&entityIdVector](const AZ::EntityId& entityId)
secondInstance->GetEntityIds([&entityIdVector](AZ::EntityId entityId)
{
entityIdVector.push_back(entityId);
return true;
});
EXPECT_EQ(entityIdVector.size(), 0);
// There should be 1 entity, the container and no others since we removed the other
EXPECT_EQ(entityIdVector.size(), 1);
}
TEST_F(PrefabInstanceToTemplateTests, PrefabUpdateTemplate_AddInstanceToInstance)
@@ -207,8 +206,8 @@ namespace UnitTest
AZStd::unique_ptr<Instance> addedInstance = m_prefabSystemComponent->CreatePrefab({}, {}, "test/pathtest");
//add instance to instance
InstanceOptionalConstReference addedInstanceRef { firstInstance->AddInstance(AZStd::move(addedInstance)) };
const AzToolsFramework::Prefab::InstanceAlias addedAlias = addedInstanceRef->get().GetInstanceAlias();
Instance& addedInstanceRef = firstInstance->AddInstance(AZStd::move(addedInstance));
const AzToolsFramework::Prefab::InstanceAlias addedAlias = addedInstanceRef.GetInstanceAlias();
//create document with after change snapshot
PrefabDom instanceDomAfterUpdate;
@@ -21,7 +21,8 @@ namespace UnitTest
if (serializeContext)
{
serializeContext->Class<PrefabTestComponent, AzToolsFramework::Components::EditorComponentBase>()->
Field("BoolProperty", &PrefabTestComponent::m_boolProperty);
Field("BoolProperty", &PrefabTestComponent::m_boolProperty)->
Field("EntityReferenceProperty", &PrefabTestComponent::m_entityIdProperty);
}
}
@@ -28,5 +28,6 @@ namespace UnitTest
static void Reflect(AZ::ReflectContext* reflection);
bool m_boolProperty = false;
AZ::EntityId m_entityIdProperty;
};
}
@@ -32,7 +32,8 @@ namespace UnitTest
using namespace PrefabTestUtils;
class PrefabTestFixture
: public ToolsApplicationFixture
: public ToolsApplicationFixture,
public UnitTest::TraceBusRedirector
{
protected:
@@ -0,0 +1,38 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and 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 <Prefab/PrefabTestUndoFixture.h>
namespace UnitTest
{
void PrefabTestUndoFixture::SetupInstances(
AZStd::unique_ptr<Instance>& firstInstance,
AZStd::unique_ptr<Instance>& secondInstance,
TemplateId& ownerId,
TemplateId& referenceId)
{
//create two prefabs for test
//create prefab 1
firstInstance = AZStd::move(m_prefabSystemComponent->CreatePrefab({ }, {}, "test/path0"));
ASSERT_TRUE(firstInstance);
//get template id
ownerId = firstInstance->GetTemplateId();
//create prefab 2
secondInstance = AZStd::move(m_prefabSystemComponent->CreatePrefab({ }, {}, "test/path1"));
ASSERT_TRUE(secondInstance);
//get template id
referenceId = secondInstance->GetTemplateId();
}
}
@@ -0,0 +1,28 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and 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.
*
*/
#pragma once
#include <Prefab/PrefabTestFixture.h>
namespace UnitTest
{
class PrefabTestUndoFixture
: public PrefabTestFixture
{
protected:
void SetupInstances(
AZStd::unique_ptr<Instance>& firstInstance,
AZStd::unique_ptr<Instance>& secondInstance,
TemplateId& ownerId,
TemplateId& referenceId);
};
}
@@ -0,0 +1,62 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and 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 <Prefab/PrefabTestDomUtils.h>
#include <Prefab/PrefabTestUndoFixture.h>
#include <Prefab/PrefabUndo.h>
namespace UnitTest
{
using PrefabUndoLinkTests = PrefabTestUndoFixture;
TEST_F(PrefabUndoLinkTests, PrefabUndoLinkAdd)
{
AZStd::unique_ptr<Instance> firstInstance = nullptr;
AZStd::unique_ptr<Instance> secondInstance = nullptr;
TemplateId firstTemplateId = InvalidTemplateId;
TemplateId secondTemplateId = InvalidTemplateId;
SetupInstances(firstInstance, secondInstance, firstTemplateId, secondTemplateId);
firstInstance->AddInstance(AZStd::move(secondInstance));
AZStd::vector<InstanceAlias> aliases = firstInstance->GetNestedInstanceAliases(secondTemplateId);
//parent prefab2 to prefab 1 by creating a link
//capture the link addition in undo node
PrefabUndoInstanceLink undoLink("Undo Link Add Node");
undoLink.Capture(firstTemplateId, secondTemplateId, aliases[0]);
undoLink.Redo();
AZStd::unique_ptr<Instance> newInstance = m_prefabSystemComponent->InstantiatePrefab(firstTemplateId);
AZStd::vector<InstanceAlias> instances = newInstance->GetNestedInstanceAliases(secondTemplateId);
ASSERT_TRUE(instances.size() > 0);
instances.clear();
//undo the parenting
undoLink.Undo();
newInstance = m_prefabSystemComponent->InstantiatePrefab(firstTemplateId);
instances = newInstance->GetNestedInstanceAliases(secondTemplateId);
ASSERT_TRUE(instances.size() == 0);
//undo the parenting
undoLink.Redo();
newInstance = m_prefabSystemComponent->InstantiatePrefab(firstTemplateId);
instances = newInstance->GetNestedInstanceAliases(secondTemplateId);
ASSERT_TRUE(instances.size() == 1);
}
} // namespace UnitTest
@@ -0,0 +1,204 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and 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 <Prefab/PrefabTestDomUtils.h>
#include <Prefab/PrefabTestFixture.h>
#include <AzCore/Component/TransformBus.h>
#include <AzCore/Component/ComponentApplicationBus.h>
#include <AzFramework/Components/TransformComponent.h>
#include <Prefab/PrefabUndo.h>
namespace UnitTest
{
using PrefabUndoTests = PrefabTestFixture;
TEST_F(PrefabUndoTests, PrefabUndoEntityUpdate)
{
//create template with single entity
AZ::Entity* newEntity = CreateEntity("New Entity", false);
ASSERT_TRUE(newEntity);
AZ::EntityId entityId = newEntity->GetId();
//add a transform component for testing purposes
newEntity->CreateComponent(AZ::EditorTransformComponentTypeId);
newEntity->Init();
newEntity->Activate();
AZStd::unique_ptr<Instance> testInstance = m_prefabSystemComponent->CreatePrefab({ newEntity }, {}, "test/path");
ASSERT_TRUE(testInstance);
//get template id
TemplateId templateId = testInstance->GetTemplateId();
//create document with before change snapshot
PrefabDom entityDomBeforeUpdate;
m_instanceToTemplateInterface->GenerateDomForEntity(entityDomBeforeUpdate, *newEntity);
float checkXValue = 0.0f;
AZ::TransformBus::EventResult(checkXValue, entityId, &AZ::TransformInterface::GetWorldX);
ASSERT_TRUE(0.0f == checkXValue);
//update values on entity
const float updatedXValue = 5.0f;
AZ::TransformBus::Event(entityId, &AZ::TransformInterface::SetWorldX, updatedXValue);
AZ::TransformBus::EventResult(checkXValue, entityId, &AZ::TransformInterface::GetWorldX);
ASSERT_TRUE(updatedXValue == checkXValue);
//create document with after change snapshot
PrefabDom entityDomAfterUpdate;
m_instanceToTemplateInterface->GenerateDomForEntity(entityDomAfterUpdate, *newEntity);
//generate patch
PrefabDom patch;
m_instanceToTemplateInterface->GeneratePatch(patch, entityDomBeforeUpdate, entityDomAfterUpdate);
//create undo node
PrefabUndoEntityUpdate instanceEntityUndo("Entity Update Undo Node");
instanceEntityUndo.Capture(entityDomBeforeUpdate, entityDomAfterUpdate, entityId);
EntityAliasOptionalReference entityAliasRef = testInstance->GetEntityAlias(entityId);
ASSERT_TRUE(entityAliasRef);
EntityAlias entityAlias = entityAliasRef.value();
//update template
m_instanceToTemplateInterface->PatchEntityInTemplate(patch, entityAlias, templateId);
//undo change
instanceEntityUndo.Undo();
// verify template updated correctly
//instantiate second instance for checking if propogation works
AZStd::unique_ptr<Instance> secondInstance = m_prefabSystemComponent->InstantiatePrefab(templateId);
ASSERT_TRUE(secondInstance);
secondInstance->InitializeNestedEntities();
secondInstance->ActivateNestedEntities();
//get the values from the transform on the entity
AZ::EntityId secondNewEntity = secondInstance->GetEntityId(entityAlias);
const float confirmXValue = 0.0f;
float value = 10.0f;
AZ::TransformBus::EventResult(value, secondNewEntity, &AZ::TransformInterface::GetWorldX);
ASSERT_TRUE(confirmXValue == value);
}
TEST_F(PrefabUndoTests, PrefabUndoInstanceUpdate_AddEntity)
{
//create single entity
AZ::Entity* newEntity = CreateEntity("New Entity", false);
ASSERT_TRUE(newEntity);
AZ::EntityId entityId = newEntity->GetId();
//create a first instance where the entity will be added
AZStd::unique_ptr<Instance> testInstance = m_prefabSystemComponent->CreatePrefab({}, {}, "test/path");
ASSERT_TRUE(testInstance);
//get template id
TemplateId templateId = testInstance->GetTemplateId();
//create document with before change snapshot
PrefabDom instanceDomBeforeUpdate;
m_instanceToTemplateInterface->GenerateDomForInstance(instanceDomBeforeUpdate, *testInstance);
//add entity to instance
testInstance->AddEntity(*newEntity);
//create document with after change snapshot
PrefabDom instanceDomAfterUpdate;
m_instanceToTemplateInterface->GenerateDomForInstance(instanceDomAfterUpdate, *testInstance);
//generate patch
PrefabDom patch;
m_instanceToTemplateInterface->GeneratePatch(patch, instanceDomBeforeUpdate, instanceDomAfterUpdate);
//create undo node
PrefabUndoInstance instanceEntityAddUndo("Entity Update Undo Node");
instanceEntityAddUndo.Capture(instanceDomBeforeUpdate, instanceDomAfterUpdate, templateId);
//update template
m_instanceToTemplateInterface->PatchTemplate(patch, templateId);
//undo change
instanceEntityAddUndo.Undo();
//get the entity id
AZStd::vector<AZ::EntityId> entityIdVector;
testInstance->GetEntityIds([&entityIdVector](const AZ::EntityId& entityId)
{
entityIdVector.push_back(entityId);
return true;
});
// Entity count minimum is 1 due to container entity
EXPECT_EQ(entityIdVector.size(), 1);
}
TEST_F(PrefabUndoTests, PrefabUndoInstanceUpdate_RemoveEntity)
{
//create single entity
AZ::Entity* newEntity = CreateEntity("New Entity", false);
ASSERT_TRUE(newEntity);
AZ::EntityId entityId = newEntity->GetId();
//create a first instance where the entity will be added
AZStd::unique_ptr<Instance> testInstance = m_prefabSystemComponent->CreatePrefab({newEntity}, {}, "test/path");
ASSERT_TRUE(testInstance);
//get template id
TemplateId templateId = testInstance->GetTemplateId();
//create document with before change snapshot
PrefabDom instanceDomBeforeUpdate;
m_instanceToTemplateInterface->GenerateDomForInstance(instanceDomBeforeUpdate, *testInstance);
//detach entity from instance
testInstance->DetachEntity(entityId);
//create document with after change snapshot
PrefabDom instanceDomAfterUpdate;
m_instanceToTemplateInterface->GenerateDomForInstance(instanceDomAfterUpdate, *testInstance);
//generate patch
PrefabDom patch;
m_instanceToTemplateInterface->GeneratePatch(patch, instanceDomBeforeUpdate, instanceDomAfterUpdate);
//create undo node
PrefabUndoInstance instanceEntityRemoveUndo("Entity Update Undo Node");
instanceEntityRemoveUndo.Capture(instanceDomBeforeUpdate, instanceDomAfterUpdate, templateId);
//update template
m_instanceToTemplateInterface->PatchTemplate(patch, templateId);
//undo change
instanceEntityRemoveUndo.Undo();
//get the entity id
AZStd::vector<AZ::EntityId> entityIdVector;
testInstance->GetEntityIds([&entityIdVector](const AZ::EntityId& entityId)
{
entityIdVector.push_back(entityId);
return true;
});
// Entity count is container entity + our entity restored via the undo
EXPECT_EQ(entityIdVector.size(), 2);
}
}
@@ -46,9 +46,9 @@ namespace UnitTest
ASSERT_EQ(wheelTemplateEntityAliases.size(), 1);
// Validate that the wheel entity has 1 component under it.
AZStd::string entityAlias = wheelTemplateEntityAliases.front();
EntityAlias wheelEntityAlias = wheelTemplateEntityAliases.front();
PrefabDomValue* wheelEntityComponents =
PrefabTestDomUtils::GetPrefabDomComponentsPath(entityAlias).Get(wheelTemplateDom);
PrefabTestDomUtils::GetPrefabDomComponentsPath(wheelEntityAlias).Get(wheelTemplateDom);
ASSERT_TRUE(wheelEntityComponents != nullptr && wheelEntityComponents->IsArray());
EXPECT_EQ(wheelEntityComponents->GetArray().Size(), 1);
@@ -66,6 +66,7 @@ namespace UnitTest
const TemplateId axleTemplateId = axleInstance->GetTemplateId();
PrefabDom& axleTemplateDom = m_prefabSystemComponent->FindTemplateDom(axleTemplateId);
const AZStd::vector<InstanceAlias> wheelInstanceAliasesUnderAxle = axleInstance->GetNestedInstanceAliases(wheelTemplateId);
ASSERT_EQ(wheelInstanceAliasesUnderAxle.size(), 1);
// Create a car with 0 entities and 1 axle instance.
@@ -80,16 +81,19 @@ namespace UnitTest
axleInstance->InitializeNestedEntities();
axleInstance->ActivateNestedEntities();
InstanceOptionalReference nestedWheelInstanceRef = axleInstance->FindNestedInstance(wheelInstanceAliasesUnderAxle[0]);
ASSERT_TRUE(nestedWheelInstanceRef);
//get the entity id
AZStd::vector<AZ::EntityId> entityIdVector;
axleInstance->GetNestedEntityIds([&entityIdVector](const AZ::EntityId& entityId)
axleInstance->GetNestedEntityIds([&entityIdVector](AZ::EntityId entityId)
{
entityIdVector.push_back(entityId);
return true;
});
EXPECT_EQ(entityIdVector.size(), 1);
AZ::EntityId wheelEntityIdUnderAxle = entityIdVector.front();
ASSERT_EQ(entityIdVector.size(), 3);
AZ::EntityId wheelEntityIdUnderAxle = nestedWheelInstanceRef->get().GetEntityId(wheelEntityAlias);
// Retrieve the entity pointer from the component application bus.
AZ::Entity* wheelEntityUnderAxle = nullptr;
@@ -118,7 +122,7 @@ namespace UnitTest
// Even though we changed the property to false, it won't be serialized out because it's a default value.
PrefabDomValue* wheelInstanceDomUnderAxle =
PrefabTestDomUtils::GetPrefabDomInstancePath(wheelInstanceAliasesUnderAxle.front()).Get(axleTemplateDom);
wheelEntityComponents = PrefabTestDomUtils::GetPrefabDomComponentsPath(entityAlias).Get(*wheelInstanceDomUnderAxle);
wheelEntityComponents = PrefabTestDomUtils::GetPrefabDomComponentsPath(wheelEntityAlias).Get(*wheelInstanceDomUnderAxle);
ASSERT_TRUE(wheelEntityComponents != nullptr);
PrefabDomValueReference wheelEntityComponentBoolPropertyValue =
PrefabDomUtils::FindPrefabDomValue(*wheelEntityComponents->Begin(), PrefabTestDomUtils::BoolPropertyName);
@@ -0,0 +1,436 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and 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 <AzCore/UnitTest/TestTypes.h>
#include <AzToolsFramework/Prefab/Spawnable/SpawnableMetaDataBuilder.h>
namespace UnitTest
{
class SpawnableMetaDataTests
: public AllocatorsFixture
{
};
template<typename T>
class TypedSpawnableMetaDataTests
: public SpawnableMetaDataTests
{
public:
using SetType = T;
using GetType = AZStd::conditional_t<AZStd::is_same_v<T, AZStd::string>, AZStd::string_view, T>;
SetType GetValue()
{
if constexpr (AZStd::is_same_v<SetType, bool>)
{
return true;
}
else if constexpr(AZStd::is_same_v<SetType, uint64_t>)
{
return 42;
}
else if constexpr(AZStd::is_same_v<SetType, int64_t>)
{
return -42;
}
else if constexpr(AZStd::is_same_v<SetType, double>)
{
return 42.0;
}
else if constexpr(AZStd::is_same_v<SetType, AZStd::string>)
{
return AZStd::string("The number 42");
}
}
AzFramework::SpawnableMetaData::ValueType GetValueType()
{
if constexpr (AZStd::is_same_v<SetType, bool>)
{
return AzFramework::SpawnableMetaData::ValueType::Boolean;
}
else if constexpr (AZStd::is_same_v<SetType, uint64_t>)
{
return AzFramework::SpawnableMetaData::ValueType::UnsignedInteger;
}
else if constexpr (AZStd::is_same_v<SetType, int64_t>)
{
return AzFramework::SpawnableMetaData::ValueType::SignedInteger;
}
else if constexpr (AZStd::is_same_v<SetType, double>)
{
return AzFramework::SpawnableMetaData::ValueType::FloatingPoint;
}
else if constexpr (AZStd::is_same_v<SetType, AZStd::string>)
{
return AzFramework::SpawnableMetaData::ValueType::String;
}
}
template<typename LT, typename RT>
void ExpectEq(const LT& lhs, const RT& rhs)
{
if constexpr (AZStd::is_same_v<LT, AZStd::string> || AZStd::is_same_v<RT, AZStd::string>)
{
EXPECT_STREQ(lhs.data(), rhs.data());
}
else
{
EXPECT_EQ(lhs, rhs);
}
}
};
TYPED_TEST_CASE_P(TypedSpawnableMetaDataTests);
TYPED_TEST_P(TypedSpawnableMetaDataTests, Add_AddValueToMetaData_NoCrash)
{
AzToolsFramework::Prefab::PrefabConversionUtils::SpawnableMetaDataBuilder builder;
builder.Add("RandomKey", this->GetValue());
}
TYPED_TEST_P(TypedSpawnableMetaDataTests, Add_ChainAdds_NoCrash)
{
AzToolsFramework::Prefab::PrefabConversionUtils::SpawnableMetaDataBuilder builder;
builder.Add("RandomKey1", this->GetValue()).Add("RandomKey2", this->GetValue());
}
TYPED_TEST_P(TypedSpawnableMetaDataTests, Add_AddThenRetrieveValue_StoredIsSameAsRetrieved)
{
using GetType = typename TypedSpawnableMetaDataTests<TypeParam>::GetType;
auto value = this->GetValue();
AzToolsFramework::Prefab::PrefabConversionUtils::SpawnableMetaDataBuilder builder;
builder.Add("RandomKey", value);
AzFramework::SpawnableMetaData metaData(builder.BuildMetaData());
GetType stored{};
EXPECT_TRUE(metaData.Get("RandomKey", stored));
this->ExpectEq(stored, value);
}
TYPED_TEST_P(TypedSpawnableMetaDataTests, Add_OverwritingValue_OriginalReplacedWithNewValue)
{
using GetType = typename TypedSpawnableMetaDataTests<TypeParam>::GetType;
AzToolsFramework::Prefab::PrefabConversionUtils::SpawnableMetaDataBuilder builder;
if constexpr (AZStd::is_same_v<GetType, bool>)
{
builder.Add("RandomKey", 42.0);
}
else
{
builder.Add("RandomKey", true);
}
builder.Add("RandomKey", this->GetValue());
AzFramework::SpawnableMetaData metaData(builder.BuildMetaData());
GetType stored{};
EXPECT_EQ(this->GetValueType(), metaData.GetType("RandomKey"));
}
TYPED_TEST_P(TypedSpawnableMetaDataTests, Add_OverwritingArray_ArrayElementsAreRemoved)
{
AzToolsFramework::Prefab::PrefabConversionUtils::SpawnableMetaDataBuilder builder;
builder.AppendArray("RandomKey", true);
builder.AppendArray("RandomKey", uint64_t{ 42 });
builder.AppendArray("RandomKey", int64_t{ -42 });
builder.AppendArray("RandomKey", 42.0);
builder.AppendArray("RandomKey", "Hello");
ASSERT_EQ(6, builder.GetEntryCount()); // 5 entries plus the entry that holds the array size.
auto value = this->GetValue();
builder.Add("RandomKey", value);
EXPECT_EQ(1, builder.GetEntryCount());
}
TYPED_TEST_P(TypedSpawnableMetaDataTests, GetType_RetrieveTypeOfValue_ValueTypeMatches)
{
auto value = this->GetValue();
AzToolsFramework::Prefab::PrefabConversionUtils::SpawnableMetaDataBuilder builder;
builder.Add("RandomKey", value);
AzFramework::SpawnableMetaData metaData(builder.BuildMetaData());
AzFramework::SpawnableMetaData::ValueType type = metaData.GetType("RandomKey");
EXPECT_EQ(this->GetValueType(), type);
}
TYPED_TEST_P(TypedSpawnableMetaDataTests, GetType_RetrieveTypeOfArrayEntry_ValueTypeMatches)
{
auto value = this->GetValue();
AzToolsFramework::Prefab::PrefabConversionUtils::SpawnableMetaDataBuilder builder;
builder.AppendArray("RandomKey", value);
AzFramework::SpawnableMetaData metaData(builder.BuildMetaData());
AzFramework::SpawnableMetaData::ValueType type = metaData.GetType("RandomKey", 0);
EXPECT_EQ(this->GetValueType(), type);
}
TYPED_TEST_P(TypedSpawnableMetaDataTests, AppendArray_AddValueToMetaDataArray_NoCrash)
{
AzToolsFramework::Prefab::PrefabConversionUtils::SpawnableMetaDataBuilder builder;
builder.AppendArray("RandomKey", this->GetValue());
}
TYPED_TEST_P(TypedSpawnableMetaDataTests, AppendArray_AppendThenRetrieveValue_StoredIsSameAsRetrieved)
{
using GetType = typename TypedSpawnableMetaDataTests<TypeParam>::GetType;
auto value = this->GetValue();
AzToolsFramework::Prefab::PrefabConversionUtils::SpawnableMetaDataBuilder builder;
builder.AppendArray("RandomKey", value);
AzFramework::SpawnableMetaData metaData(builder.BuildMetaData());
GetType stored{};
EXPECT_TRUE(metaData.Get("RandomKey", 0, stored));
this->ExpectEq(stored, value);
}
TYPED_TEST_P(TypedSpawnableMetaDataTests, AppendArray_ReplaceExistingValue_ArraySizeReplacesOriginalEntry)
{
auto value = this->GetValue();
AzToolsFramework::Prefab::PrefabConversionUtils::SpawnableMetaDataBuilder builder;
builder.Add("RandomKey", value);
builder.AppendArray("RandomKey", value);
AzFramework::SpawnableMetaData metaData(builder.BuildMetaData());
EXPECT_EQ(AzFramework::SpawnableMetaData::ValueType::ArraySize, metaData.GetType("RandomKey"));
}
TYPED_TEST_P(TypedSpawnableMetaDataTests, Get_WrongType_ReturnsFalse)
{
using GetType = typename TypedSpawnableMetaDataTests<TypeParam>::GetType;
auto value = this->GetValue();
AzToolsFramework::Prefab::PrefabConversionUtils::SpawnableMetaDataBuilder builder;
builder.AppendArray("RandomKey", value);
AzFramework::SpawnableMetaData metaData(builder.BuildMetaData());
if constexpr (AZStd::is_same_v<GetType, bool>)
{
double stored{};
EXPECT_FALSE(metaData.Get("RandomKey", stored));
}
else
{
bool stored{};
EXPECT_FALSE(metaData.Get("RandomKey", stored));
}
}
REGISTER_TYPED_TEST_CASE_P(TypedSpawnableMetaDataTests,
Add_AddValueToMetaData_NoCrash,
Add_ChainAdds_NoCrash,
Add_AddThenRetrieveValue_StoredIsSameAsRetrieved,
Add_OverwritingValue_OriginalReplacedWithNewValue,
Add_OverwritingArray_ArrayElementsAreRemoved,
GetType_RetrieveTypeOfValue_ValueTypeMatches,
GetType_RetrieveTypeOfArrayEntry_ValueTypeMatches,
AppendArray_AddValueToMetaDataArray_NoCrash,
AppendArray_AppendThenRetrieveValue_StoredIsSameAsRetrieved,
AppendArray_ReplaceExistingValue_ArraySizeReplacesOriginalEntry,
Get_WrongType_ReturnsFalse);
using SpawnableMetaDataTestTypes = ::testing::Types<bool, uint64_t, int64_t, double, AZStd::string>;
INSTANTIATE_TYPED_TEST_CASE_P(SpawnableMetaDataTests, TypedSpawnableMetaDataTests, SpawnableMetaDataTestTypes);
TEST_F(SpawnableMetaDataTests, Get_UnknownKey_ReturnsFalse)
{
AzToolsFramework::Prefab::PrefabConversionUtils::SpawnableMetaDataBuilder builder;
builder.Add("RandomKey", uint64_t{ 42 });
AzFramework::SpawnableMetaData metaData(builder.BuildMetaData());
uint64_t stored{};
EXPECT_FALSE(metaData.Get("UnknownKey", stored));
}
TEST_F(SpawnableMetaDataTests, Get_ArraySize_ReturnsNumberOfEntries)
{
AzToolsFramework::Prefab::PrefabConversionUtils::SpawnableMetaDataBuilder builder;
builder.AppendArray("RandomKey", true);
builder.AppendArray("RandomKey", uint64_t{ 42 });
builder.AppendArray("RandomKey", int64_t{ -42 });
builder.AppendArray("RandomKey", 42.0);
builder.AppendArray("RandomKey", "Hello");
AzFramework::SpawnableMetaData metaData(builder.BuildMetaData());
AzFramework::SpawnableMetaDataArraySize stored{};
EXPECT_TRUE(metaData.Get("RandomKey", stored));
EXPECT_EQ(AzFramework::SpawnableMetaDataArraySize{ 5 }, stored);
}
TEST_F(SpawnableMetaDataTests, Get_ArrayElementsAtVariousIndices_ReturnsValues)
{
AzToolsFramework::Prefab::PrefabConversionUtils::SpawnableMetaDataBuilder builder;
for (uint64_t i = 42; i < 88; ++i)
{
builder.AppendArray("RandomKey", i);
}
AzFramework::SpawnableMetaData metaData(builder.BuildMetaData());
for (size_t i = 0; i < 88 - 42; ++i)
{
uint64_t stored;
EXPECT_TRUE(metaData.Get("RandomKey", i, stored));
EXPECT_EQ(42 + i, stored);
}
}
TEST_F(SpawnableMetaDataTests, Get_ArrayIndexOutOfBounds_ReturnsFalse)
{
AzToolsFramework::Prefab::PrefabConversionUtils::SpawnableMetaDataBuilder builder;
builder.AppendArray("RandomKey", true);
builder.AppendArray("RandomKey", uint64_t{ 42 });
builder.AppendArray("RandomKey", int64_t{ -42 });
builder.AppendArray("RandomKey", 42.0);
builder.AppendArray("RandomKey", "Hello");
AzFramework::SpawnableMetaData metaData(builder.BuildMetaData());
uint64_t stored{};
EXPECT_FALSE(metaData.Get("RandomKey", 5, stored));
}
TEST_F(SpawnableMetaDataTests, Get_RetrieveArrayType_ReturnArrayType)
{
AzToolsFramework::Prefab::PrefabConversionUtils::SpawnableMetaDataBuilder builder;
builder.AppendArray("RandomKey", true);
builder.AppendArray("RandomKey", uint64_t{ 42 });
builder.AppendArray("RandomKey", int64_t{ -42 });
builder.AppendArray("RandomKey", 42.0);
builder.AppendArray("RandomKey", "Hello");
AzFramework::SpawnableMetaData metaData(builder.BuildMetaData());
EXPECT_EQ(AzFramework::SpawnableMetaData::ValueType::ArraySize, metaData.GetType("RandomKey"));
}
TEST_F(SpawnableMetaDataTests, Get_RetrieveNonExistingValue_ReturnUnavailable)
{
AzFramework::SpawnableMetaData metaData;
EXPECT_EQ(AzFramework::SpawnableMetaData::ValueType::Unavailable, metaData.GetType("RandomKey"));
}
TEST_F(SpawnableMetaDataTests, Get_RetrieveNonExistingArrayIndex_ReturnUnavailable)
{
AzToolsFramework::Prefab::PrefabConversionUtils::SpawnableMetaDataBuilder builder;
builder.AppendArray("RandomKey", true);
builder.AppendArray("RandomKey", uint64_t{ 42 });
builder.AppendArray("RandomKey", int64_t{ -42 });
builder.AppendArray("RandomKey", 42.0);
builder.AppendArray("RandomKey", "Hello");
AzFramework::SpawnableMetaData metaData(builder.BuildMetaData());
EXPECT_EQ(AzFramework::SpawnableMetaData::ValueType::Unavailable, metaData.GetType("RandomKey", 42));
}
TEST_F(SpawnableMetaDataTests, Remove_RemoveExistingEntry_EntryNotFound)
{
AzToolsFramework::Prefab::PrefabConversionUtils::SpawnableMetaDataBuilder builder;
builder.Add("RandomKey", uint64_t{ 42 });
ASSERT_TRUE(builder.Remove("RandomKey"));
AzFramework::SpawnableMetaData metaData(builder.BuildMetaData());
uint64_t stored{};
EXPECT_FALSE(metaData.Get("RandomKey", stored));
}
TEST_F(SpawnableMetaDataTests, Remove_RemoveNonExistingEntry_ReturnsFalse)
{
AzToolsFramework::Prefab::PrefabConversionUtils::SpawnableMetaDataBuilder builder;
EXPECT_FALSE(builder.Remove("UnknownKey"));
}
TEST_F(SpawnableMetaDataTests, Remove_RemoveArray_AllArrayEntriesAreRemovedAsWell)
{
AzToolsFramework::Prefab::PrefabConversionUtils::SpawnableMetaDataBuilder builder;
builder.AppendArray("RandomKey", uint64_t{ 10 });
builder.AppendArray("RandomKey", uint64_t{ 11 });
builder.AppendArray("RandomKey", uint64_t{ 12 });
builder.AppendArray("RandomKey", uint64_t{ 13 });
builder.AppendArray("RandomKey", uint64_t{ 14 });
builder.AppendArray("RandomKey", uint64_t{ 15 });
EXPECT_TRUE(builder.Remove("RandomKey"));
EXPECT_EQ(0, builder.GetEntryCount());
}
TEST_F(SpawnableMetaDataTests, RemoveArrayEntry_RemoveExistingEntry_EntryNotFound)
{
AzToolsFramework::Prefab::PrefabConversionUtils::SpawnableMetaDataBuilder builder;
builder.AppendArray("RandomKey", uint64_t{ 10 });
builder.AppendArray("RandomKey", uint64_t{ 11 });
builder.AppendArray("RandomKey", uint64_t{ 12 });
builder.AppendArray("RandomKey", uint64_t{ 13 });
builder.AppendArray("RandomKey", uint64_t{ 14 });
builder.AppendArray("RandomKey", uint64_t{ 15 });
ASSERT_TRUE(builder.RemoveArrayEntry("RandomKey", 3));
AzFramework::SpawnableMetaData metaData(builder.BuildMetaData());
AzFramework::SpawnableMetaDataArraySize stored{};
EXPECT_TRUE(metaData.Get("RandomKey", stored));
EXPECT_EQ(stored, AzFramework::SpawnableMetaDataArraySize{ 5 });
uint64_t storedValue;
EXPECT_TRUE(metaData.Get("RandomKey", 0, storedValue));
EXPECT_EQ(10, storedValue);
EXPECT_TRUE(metaData.Get("RandomKey", 1, storedValue));
EXPECT_EQ(11, storedValue);
EXPECT_TRUE(metaData.Get("RandomKey", 2, storedValue));
EXPECT_EQ(12, storedValue);
EXPECT_TRUE(metaData.Get("RandomKey", 3, storedValue));
EXPECT_EQ(14, storedValue);
EXPECT_TRUE(metaData.Get("RandomKey", 4, storedValue));
EXPECT_EQ(15, storedValue);
EXPECT_FALSE(metaData.Get("RandomKey", 5, storedValue));
}
TEST_F(SpawnableMetaDataTests, RemoveArrayEntry_RemoveNonExistingKey_ReturnFalse)
{
AzToolsFramework::Prefab::PrefabConversionUtils::SpawnableMetaDataBuilder builder;
ASSERT_FALSE(builder.RemoveArrayEntry("RandomKey", 0));
}
TEST_F(SpawnableMetaDataTests, RemoveArrayEntry_RemoveNonExistingEntry_ReturnFalse)
{
AzToolsFramework::Prefab::PrefabConversionUtils::SpawnableMetaDataBuilder builder;
builder.AppendArray("RandomKey", uint64_t{ 0 });
builder.AppendArray("RandomKey", uint64_t{ 1 });
builder.AppendArray("RandomKey", uint64_t{ 2 });
builder.AppendArray("RandomKey", uint64_t{ 3 });
builder.AppendArray("RandomKey", uint64_t{ 4 });
builder.AppendArray("RandomKey", uint64_t{ 5 });
ASSERT_FALSE(builder.RemoveArrayEntry("RandomKey", 42));
}
}
@@ -0,0 +1,90 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and 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 <Prefab/PrefabTestFixture.h>
#include <AzCore/std/containers/unordered_set.h>
#include <AzToolsFramework/Prefab/Spawnable/SpawnableUtils.h>
namespace UnitTest
{
using SpawnableCreateTest = PrefabTestFixture;
TEST_F(SpawnableCreateTest, SpawnableCreate_NoNestingPrefabDom_CreateSucceeds)
{
AZStd::vector<AZ::Entity*> entitiesCreated;
AZStd::unordered_set<AZStd::string> expectedEntityNameSet;
for (int i = 0; i < 3; i++)
{
entitiesCreated.push_back(CreateEntity(AZStd::string::format("Entity_%i", i).c_str()));
expectedEntityNameSet.insert(entitiesCreated.back()->GetName());
}
AZStd::unique_ptr<AzToolsFramework::Prefab::Instance> instance(
m_prefabSystemComponent->CreatePrefab(entitiesCreated, {}, "test/path"));
ASSERT_TRUE(instance);
//Create Spawnable
auto& prefabDom = m_prefabSystemComponent->FindTemplateDom(instance->GetTemplateId());
auto spawnable = ::AzToolsFramework::Prefab::SpawnableUtils::CreateSpawnable(prefabDom);
EXPECT_EQ(spawnable.GetEntities().size(), 3);
const auto& spawnableEntities = spawnable.GetEntities();
AZStd::unordered_set<AZStd::string> actualEntityNameSet;
for (int i = 0; i < 3; i++)
{
actualEntityNameSet.insert(spawnableEntities[i]->GetName());
}
EXPECT_EQ(expectedEntityNameSet, actualEntityNameSet);
}
TEST_F(SpawnableCreateTest, SpawnableCreate_TripleNestingPrefabDom_CreateSucceeds)
{
AZStd::vector<AZ::Entity*> entitiesCreated;
AZStd::unordered_set<AZStd::string> expectedEntityNameSet;
for (int i = 0; i < 3; i++)
{
entitiesCreated.push_back(CreateEntity(AZStd::string::format("Entity_%i", i).c_str()));
expectedEntityNameSet.insert(entitiesCreated.back()->GetName());
}
// Build a 3 level deep nested Template
AZStd::unique_ptr<AzToolsFramework::Prefab::Instance> firstInstance(
m_prefabSystemComponent->CreatePrefab({ entitiesCreated[0] }, {}, "test/path1"));
ASSERT_TRUE(firstInstance);
AZStd::unique_ptr<AzToolsFramework::Prefab::Instance> secondInstance(
m_prefabSystemComponent->CreatePrefab({ entitiesCreated[1] }, MakeInstanceList(AZStd::move(firstInstance)), "test/path2"));
ASSERT_TRUE(secondInstance);
AZStd::unique_ptr<AzToolsFramework::Prefab::Instance> thirdInstance(
m_prefabSystemComponent->CreatePrefab({ entitiesCreated[2] }, MakeInstanceList(AZStd::move(secondInstance)), "test/path3"));
ASSERT_TRUE(thirdInstance);
//Create Spawnable
auto& prefabDom = m_prefabSystemComponent->FindTemplateDom(thirdInstance->GetTemplateId());
auto spawnable = ::AzToolsFramework::Prefab::SpawnableUtils::CreateSpawnable(prefabDom);
EXPECT_EQ(spawnable.GetEntities().size(), 3);
const auto& spawnableEntities = spawnable.GetEntities();
AZStd::unordered_set<AZStd::string> actualEntityNameSet;
for (int i = 0; i < 3; i++)
{
actualEntityNameSet.insert(spawnableEntities[i]->GetName());
}
EXPECT_EQ(expectedEntityNameSet, actualEntityNameSet);
}
}
@@ -0,0 +1,223 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and 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 <Prefab/SpawnableRemoveEditorInfoTestFixture.h>
#include <AzToolsFramework/Prefab/PrefabDomUtils.h>
#include <AzToolsFramework/ToolsComponents/EditorOnlyEntityComponent.h>
#include <AzToolsFramework/ToolsComponents/EditorOnlyEntityComponentBus.h>
#include <AzToolsFramework/ToolsComponents/TransformComponent.h>
namespace UnitTest
{
TestExportRuntimeComponentWithCallback::TestExportRuntimeComponentWithCallback(bool returnPointerToSelf, bool exportHandled)
: m_returnPointerToSelf(returnPointerToSelf)
, m_exportHandled(exportHandled)
{}
void TestExportRuntimeComponentWithCallback::Reflect(AZ::ReflectContext* context)
{
if (AZ::SerializeContext* serializeContext = azrtti_cast<AZ::SerializeContext*>(context))
{
serializeContext->Class<TestExportRuntimeComponentWithCallback, AZ::Component>()->Version(1)
->Field("ExportHandled", &TestExportRuntimeComponentWithCallback::m_exportHandled)
->Field("ReturnPointerToSelf", &TestExportRuntimeComponentWithCallback::m_returnPointerToSelf);
if (AZ::EditContext* editContext = serializeContext->GetEditContext())
{
editContext->Class<TestExportRuntimeComponentWithCallback>(
"Test Export Runtime Component", "Validate different options for exporting runtime components")
->ClassElement(AZ::Edit::ClassElements::EditorData, "")
->Attribute(AZ::Edit::Attributes::RuntimeExportCallback, &TestExportRuntimeComponentWithCallback::ExportComponent)
;
}
}
}
AZ::ExportedComponent TestExportRuntimeComponentWithCallback::ExportComponent(AZ::Component* thisComponent, const AZ::PlatformTagSet& /*platformTags*/)
{
return AZ::ExportedComponent(m_returnPointerToSelf? thisComponent : nullptr, false, m_exportHandled);
}
void TestExportRuntimeComponentWithoutCallback::Reflect(AZ::ReflectContext* context)
{
auto* serialize = azrtti_cast<AZ::SerializeContext*>(context);
if (serialize)
{
serialize->Class<TestExportRuntimeComponentWithoutCallback, AZ::Component>()
;
}
}
TestExportEditorComponent::TestExportEditorComponent(
TestExportEditorComponent::ExportComponentType exportType, bool exportHandled)
: m_exportType(exportType)
, m_exportHandled(exportHandled)
{}
void TestExportEditorComponent::Reflect(AZ::ReflectContext* context)
{
if (AZ::SerializeContext* serializeContext = azrtti_cast<AZ::SerializeContext*>(context))
{
serializeContext->Class<TestExportEditorComponent, AzToolsFramework::Components::EditorComponentBase>()
->Version(1)
->Field("ExportHandled", &TestExportEditorComponent::m_exportHandled)
->Field("ExportType", &TestExportEditorComponent::m_exportType)
;
if (AZ::EditContext* editContext = serializeContext->GetEditContext())
{
editContext->Class<TestExportEditorComponent>(
"Test Export Editor Component", "Validate different options for exporting editor components")
->ClassElement(AZ::Edit::ClassElements::EditorData, "")
->Attribute(AZ::Edit::Attributes::RuntimeExportCallback, &TestExportEditorComponent::ExportComponent)
;
}
}
}
AZ::ExportedComponent TestExportEditorComponent::ExportComponent(
AZ::Component* thisComponent, const AZ::PlatformTagSet& /*platformTags*/)
{
switch (m_exportType)
{
case ExportComponentType::ExportEditorComponent:
return AZ::ExportedComponent(thisComponent, false, m_exportHandled);
case ExportComponentType::ExportRuntimeComponentWithCallBack:
return AZ::ExportedComponent(aznew TestExportRuntimeComponentWithCallback(true, true), true, m_exportHandled);
case ExportComponentType::ExportRuntimeComponentWithoutCallBack:
return AZ::ExportedComponent(aznew TestExportRuntimeComponentWithoutCallback, true, m_exportHandled);
case ExportComponentType::ExportNullComponent:
return AZ::ExportedComponent(nullptr, false, m_exportHandled);
default:
return AZ::ExportedComponent();
}
}
void TestExportEditorComponent::BuildGameEntity(AZ::Entity* gameEntity)
{
gameEntity->CreateComponent<TestExportRuntimeComponentWithCallback>(true, true);
}
void SpawnableRemoveEditorInfoTestFixture::SetUpEditorFixtureImpl()
{
auto* app = GetApplication();
// Acquire the system entity
AZ::Entity* systemEntity = app->FindEntity(AZ::SystemEntityId);
EXPECT_TRUE(systemEntity);
// Acquire the prefab system component to gain access to its APIs for testing
m_prefabSystemComponent = systemEntity->FindComponent<AzToolsFramework::Prefab::PrefabSystemComponent>();
EXPECT_TRUE(m_prefabSystemComponent);
m_serializeContext = app->GetSerializeContext();
EXPECT_TRUE(m_serializeContext);
app->RegisterComponentDescriptor(TestExportRuntimeComponentWithCallback::CreateDescriptor());
app->RegisterComponentDescriptor(TestExportRuntimeComponentWithoutCallback::CreateDescriptor());
app->RegisterComponentDescriptor(TestExportEditorComponent::CreateDescriptor());
}
void SpawnableRemoveEditorInfoTestFixture::TearDownEditorFixtureImpl()
{
for (AZ::Entity* entity : m_runtimeEntities)
{
delete entity;
}
m_sourceEntities.clear();
m_runtimeEntities.clear();
}
void SpawnableRemoveEditorInfoTestFixture::CreateSourceEntity(const char* name, bool editorOnly)
{
AZ::Entity* entity = aznew AZ::Entity(name);
entity->CreateComponent<AzToolsFramework::Components::TransformComponent>();
entity->CreateComponent<AzToolsFramework::Components::EditorOnlyEntityComponent>();
m_sourceEntities.push_back(entity);
entity->Init();
EXPECT_EQ(AZ::Entity::State::Init, entity->GetState());
entity->Activate();
EXPECT_EQ(AZ::Entity::State::Active, entity->GetState());
AzToolsFramework::EditorOnlyEntityComponentRequestBus::Event(
entity->GetId(),
&AzToolsFramework::EditorOnlyEntityComponentRequests::SetIsEditorOnlyEntity,
editorOnly);
}
void SpawnableRemoveEditorInfoTestFixture::CreateSourceTestExportRuntimeEntity(
const char* name, bool returnPointerToSelf, bool exportHandled)
{
AZ::Entity* entity = aznew AZ::Entity(name);
entity->CreateComponent<AzToolsFramework::Components::TransformComponent>();
entity->CreateComponent<TestExportRuntimeComponentWithCallback>(returnPointerToSelf, exportHandled);
m_sourceEntities.push_back(entity);
}
void SpawnableRemoveEditorInfoTestFixture::CreateSourceTestExportEditorEntity(
const char* name,
TestExportEditorComponent::ExportComponentType exportType,
bool exportHandled)
{
AZ::Entity* entity = aznew AZ::Entity(name);
entity->CreateComponent<AzToolsFramework::Components::TransformComponent>();
entity->CreateComponent<TestExportEditorComponent>(exportType, exportHandled);
m_sourceEntities.push_back(entity);
}
AZ::Entity* SpawnableRemoveEditorInfoTestFixture::GetRuntimeEntity(const char* entityName)
{
for (AZ::Entity* entity : m_runtimeEntities)
{
const AZStd::string& name = entity->GetName();
if (name == entityName)
{
return entity;
}
}
return nullptr;
}
void SpawnableRemoveEditorInfoTestFixture::ConvertSourceEntitiesToPrefab()
{
AZStd::unique_ptr<AzToolsFramework::Prefab::Instance> sourceInstance(
m_prefabSystemComponent->CreatePrefab(m_sourceEntities, {}, "test/path"));
ASSERT_TRUE(sourceInstance);
auto& prefabTemplateDom = m_prefabSystemComponent->FindTemplateDom(sourceInstance->GetTemplateId());
m_prefabDom.CopyFrom(prefabTemplateDom, m_prefabDom.GetAllocator());
}
void SpawnableRemoveEditorInfoTestFixture::ConvertRuntimePrefab(bool expectedResult)
{
ConvertSourceEntitiesToPrefab();
const bool actualResult =
m_editorInfoRemover.RemoveEditorInfo(m_prefabDom, m_serializeContext, m_prefabProcessorContext).IsSuccess();
EXPECT_EQ(expectedResult, actualResult);
AZStd::unique_ptr<Instance> convertedInstance(aznew Instance());
ASSERT_TRUE(AzToolsFramework::Prefab::PrefabDomUtils::LoadInstanceFromPrefabDom(*convertedInstance, m_prefabDom, false));
convertedInstance->DetachNestedEntities(
[this](AZStd::unique_ptr<AZ::Entity> entity)
{
m_runtimeEntities.emplace_back(entity.release());
}
);
}
}
@@ -0,0 +1,123 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and 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.
*
*/
#pragma once
#include <AzCore/Component/Entity.h>
#include <AzToolsFramework/ToolsComponents/EditorComponentBase.h>
#include <AzToolsFramework/UnitTest/AzToolsFrameworkTestHelpers.h>
#include <Prefab/Spawnable/EditorInfoRemover.h>
#include <Prefab/Spawnable/PrefabProcessorContext.h>
#include <Prefab/PrefabSystemComponent.h>
#include <Prefab/PrefabDomTypes.h>
namespace UnitTest
{
using namespace AzToolsFramework::Prefab;
class TestExportRuntimeComponentWithCallback
: public AZ::Component
{
public:
AZ_COMPONENT(TestExportRuntimeComponentWithCallback, "{BD30EBBB-74DA-473C-9C68-7077AAE8C0B1}", AZ::Component);
TestExportRuntimeComponentWithCallback() = default;
TestExportRuntimeComponentWithCallback(bool returnPointerToSelf, bool exportHandled);
void Activate() override {}
void Deactivate() override {}
static void Reflect(AZ::ReflectContext* context);
AZ::ExportedComponent ExportComponent(AZ::Component* thisComponent, const AZ::PlatformTagSet& /*platformTags*/);
const bool m_exportHandled{ false };
const bool m_returnPointerToSelf{ false };
};
class TestExportRuntimeComponentWithoutCallback
: public AZ::Component
{
public:
AZ_COMPONENT(TestExportRuntimeComponentWithoutCallback, "{44216269-2BAB-48E4-864F-F8D4CCFF60BB}", AZ::Component);
void Activate() override {}
void Deactivate() override {}
static void Reflect(AZ::ReflectContext* context);
};
class TestExportEditorComponent
: public AzToolsFramework::Components::EditorComponentBase
{
public:
AZ_COMPONENT(TestExportEditorComponent, "{60EE7F0E-1C89-433A-AA7C-20F64BA1F470}", AzToolsFramework::Components::EditorComponentBase);
enum class ExportComponentType
{
ExportEditorComponent,
ExportRuntimeComponentWithCallBack,
ExportRuntimeComponentWithoutCallBack,
ExportNullComponent,
};
TestExportEditorComponent() = default;
TestExportEditorComponent(ExportComponentType exportType, bool exportHandled);
void Activate() override {}
void Deactivate() override {}
static void Reflect(AZ::ReflectContext* context);
AZ::ExportedComponent ExportComponent(AZ::Component* thisComponent, const AZ::PlatformTagSet& /*platformTags*/);
void BuildGameEntity(AZ::Entity* gameEntity) override;
ExportComponentType m_exportType{ ExportComponentType::ExportNullComponent };
bool m_exportHandled{ false };
};
class SpawnableRemoveEditorInfoTestFixture
: public ToolsApplicationFixture
{
protected:
void SetUpEditorFixtureImpl() override;
void TearDownEditorFixtureImpl() override;
// create entity containing the EditorOnly component to be processed
void CreateSourceEntity(const char* name, bool editorOnly);
// create entity containing the non editor-only component to be processed
void CreateSourceTestExportRuntimeEntity(const char* name, bool returnPointerToSelf, bool exportHandled);
// create entity containing the editor-only component to be processed
void CreateSourceTestExportEditorEntity(
const char* name,
TestExportEditorComponent::ExportComponentType exportType,
bool exportHandled);
// Locate and return an entity from the exported entities
AZ::Entity* GetRuntimeEntity(const char* entityName);
void ConvertSourceEntitiesToPrefab();
void ConvertRuntimePrefab(bool expectedResult = true);
AZStd::vector<AZ::Entity*> m_sourceEntities;
AZStd::vector<AZ::Entity*> m_runtimeEntities;
AZ::SerializeContext* m_serializeContext{ nullptr };
PrefabSystemComponent* m_prefabSystemComponent{ nullptr };
PrefabConversionUtils::EditorInfoRemover m_editorInfoRemover;
PrefabConversionUtils::PrefabProcessorContext m_prefabProcessorContext;
PrefabDom m_prefabDom;
};
}
@@ -0,0 +1,171 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and 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 <Prefab/SpawnableRemoveEditorInfoTestFixture.h>
namespace UnitTest
{
using SpawnableRemoveEditorInfoTests = SpawnableRemoveEditorInfoTestFixture;
TEST_F(SpawnableRemoveEditorInfoTests, SpawnableRemoveEditorInfo_OnlyRuntimeEntityExported)
{
// Create one entity that's flagged as Editor-Only, and one that's enabled for runtime.
CreateSourceEntity("EditorOnly", true);
CreateSourceEntity("EditorAndRuntime", false);
ConvertRuntimePrefab();
// Only the runtime entity exists in the converted Prefab DOM.
EXPECT_FALSE(GetRuntimeEntity("EditorOnly"));
EXPECT_TRUE(GetRuntimeEntity("EditorAndRuntime"));
}
TEST_F(SpawnableRemoveEditorInfoTests, SpawnableRemoveEditorInfo_RuntimeComponentExportedSuccessfully)
{
// Create a component with RuntimeExportCallback and successfully exports itself.
CreateSourceTestExportRuntimeEntity("EntityWithRuntimeComponent", true, true);
ConvertRuntimePrefab();
// Expected result: processed entity contains the component.
AZ::Entity* entity = GetRuntimeEntity("EntityWithRuntimeComponent");
EXPECT_TRUE(entity);
EXPECT_TRUE(entity->FindComponent<TestExportRuntimeComponentWithCallback>());
}
TEST_F(SpawnableRemoveEditorInfoTests, RuntimeExportCallback_RuntimeComponentExportRemoved)
{
// Create a component with RuntimeExportCallback and successfully removes itself from exporting.
CreateSourceTestExportRuntimeEntity("EntityWithRuntimeComponent", false, true);
ConvertRuntimePrefab();
// Expected result: processed entity does NOT contain the component.
AZ::Entity* entity = GetRuntimeEntity("EntityWithRuntimeComponent");
EXPECT_TRUE(entity);
EXPECT_FALSE(entity->FindComponent<TestExportRuntimeComponentWithCallback>());
}
TEST_F(SpawnableRemoveEditorInfoTests, RuntimeExportCallback_RuntimeComponentExportUnhandled)
{
// Create a component with RuntimeExportCallback, returns a pointer to itself, but says it wasn't handled.
CreateSourceTestExportRuntimeEntity("EntityWithRuntimeComponent", true, false);
ConvertRuntimePrefab();
// Expected result: processed entity contains the component, because the default behavior is "clone/add" for
// runtime components.
AZ::Entity* entity = GetRuntimeEntity("EntityWithRuntimeComponent");
EXPECT_TRUE(entity);
EXPECT_TRUE(entity->FindComponent<TestExportRuntimeComponentWithCallback>());
}
TEST_F(SpawnableRemoveEditorInfoTests, RuntimeExportCallback_RuntimeComponentExportRemovedAndUnhandled)
{
// Create a component with RuntimeExportCallback and removes itself from exporting, but says it wasn't handled.
CreateSourceTestExportRuntimeEntity("EntityWithRuntimeComponent", false, false);
ConvertRuntimePrefab();
// Expected result: processed entity contains the component, because by saying it wasn't handled, it
// should fall back on the default behavior of "clone/add" for runtime components.
AZ::Entity* entity = GetRuntimeEntity("EntityWithRuntimeComponent");
EXPECT_TRUE(entity);
EXPECT_TRUE(entity->FindComponent<TestExportRuntimeComponentWithCallback>());
}
TEST_F(SpawnableRemoveEditorInfoTests, RuntimeExportCallback_EditorComponentExportedSuccessfully)
{
// Create an editor component that has a RuntimeExportCallback and successfully exports itself.
CreateSourceTestExportEditorEntity(
"EntityWithEditorComponent",
TestExportEditorComponent::ExportComponentType::ExportRuntimeComponentWithoutCallBack,
true);
ConvertRuntimePrefab();
// Expected result: processed entity contains the runtime component, exported from RuntimeExportCallback.
AZ::Entity* entity = GetRuntimeEntity("EntityWithEditorComponent");
EXPECT_TRUE(entity);
EXPECT_FALSE(entity->FindComponent<TestExportEditorComponent>());
EXPECT_FALSE(entity->FindComponent<TestExportRuntimeComponentWithCallback>());
EXPECT_TRUE(entity->FindComponent<TestExportRuntimeComponentWithoutCallback>());
}
TEST_F(SpawnableRemoveEditorInfoTests, RuntimeExportCallback_EditorComponentExportRemoved)
{
// Create an editor component that has a RuntimeExportCallback and successfully removes itself from exporting.
CreateSourceTestExportEditorEntity(
"EntityWithEditorComponent",
TestExportEditorComponent::ExportComponentType::ExportNullComponent,
true);
ConvertRuntimePrefab();
// Expected result: processed entity does NOT contain either component.
AZ::Entity* entity = GetRuntimeEntity("EntityWithEditorComponent");
EXPECT_TRUE(entity);
EXPECT_FALSE(entity->FindComponent<TestExportEditorComponent>());
EXPECT_FALSE(entity->FindComponent<TestExportRuntimeComponentWithCallback>());
EXPECT_FALSE(entity->FindComponent<TestExportRuntimeComponentWithoutCallback>());
}
TEST_F(SpawnableRemoveEditorInfoTests, RuntimeExportCallback_EditorComponentExportUnhandledFallBackToBuildGameEntity)
{
// Create an editor component that has a RuntimeExportCallback, returns a pointer to itself, but says it wasn't handled.
CreateSourceTestExportEditorEntity(
"EntityWithEditorComponent",
TestExportEditorComponent::ExportComponentType::ExportEditorComponent,
false);
ConvertRuntimePrefab();
// Expected result: processed entity contains the runtime component, because the fallback to BuildGameEntity()
// produced a runtime component.
AZ::Entity* entity = GetRuntimeEntity("EntityWithEditorComponent");
EXPECT_TRUE(entity);
EXPECT_FALSE(entity->FindComponent<TestExportEditorComponent>());
EXPECT_TRUE(entity->FindComponent<TestExportRuntimeComponentWithCallback>());
EXPECT_FALSE(entity->FindComponent<TestExportRuntimeComponentWithoutCallback>());
}
TEST_F(SpawnableRemoveEditorInfoTests, RuntimeExportCallback_EditorComponentExportRemovedAndUnhandledFallBackToBuildGameEntity)
{
// Create an editor component that has a RuntimeExportCallback and removes itself from exporting, but says it wasn't handled.
CreateSourceTestExportEditorEntity(
"EntityWithEditorComponent",
TestExportEditorComponent::ExportComponentType::ExportNullComponent,
false);
ConvertRuntimePrefab();
// Expected result: processed entity contains the runtime component, because the fallback to BuildGameEntity()
// produced a runtime component.
AZ::Entity* entity = GetRuntimeEntity("EntityWithEditorComponent");
EXPECT_TRUE(entity);
EXPECT_FALSE(entity->FindComponent<TestExportEditorComponent>());
EXPECT_TRUE(entity->FindComponent<TestExportRuntimeComponentWithCallback>());
EXPECT_FALSE(entity->FindComponent<TestExportRuntimeComponentWithoutCallback>());
}
TEST_F(SpawnableRemoveEditorInfoTests, RuntimeExportCallback_EditorComponentFailsToExportItself)
{
// Create an editor component that has a RuntimeExportCallback and removes itself from exporting, but says it wasn't handled.
CreateSourceTestExportEditorEntity(
"EntityWithEditorComponent",
TestExportEditorComponent::ExportComponentType::ExportEditorComponent,
true);
// We expect the exporting to fail, since an editor component is being exported as a game component.
ConvertRuntimePrefab(false);
}
}
@@ -0,0 +1,115 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and 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 <Prefab/SpawnableSortEntitiesTestFixture.h>
#include <AzCore/std/algorithm.h>
#include <AzToolsFramework/ToolsComponents/TransformComponent.h>
#include <Prefab/Spawnable/SpawnableUtils.h>
namespace UnitTest
{
void SpawnableSortEntitiesTestFixture::TearDownEditorFixtureImpl()
{
for (AZ::Entity* entity : m_sorted)
{
delete entity;
}
m_unsorted.clear();
m_sorted.clear();
m_expectedEntities.clear();
m_actualEntities.clear();
}
void SpawnableSortEntitiesTestFixture::AddEntity(AZ::EntityId id, AZ::EntityId parentId, bool expectedInSorted)
{
auto* newEntity = aznew AZ::Entity(id);
newEntity->CreateComponent<AzFramework::TransformComponent>()->SetParent(parentId);
m_unsorted.push_back(newEntity);
if (expectedInSorted)
{
m_expectedEntities.insert(newEntity);
}
}
void SpawnableSortEntitiesTestFixture::AddEntity(AZ::Entity* entity, bool expectedInSorted)
{
m_unsorted.push_back(entity);
if (expectedInSorted)
{
m_expectedEntities.insert(entity);
}
}
void SpawnableSortEntitiesTestFixture::ConvertEntitiesToSpawnable(const AZStd::vector<AZ::Entity*>& rawEntities)
{
auto& entities = m_spawnable.GetEntities();
entities.clear();
entities.reserve(rawEntities.size());
AZStd::for_each(rawEntities.begin(), rawEntities.end(),
[&entities](auto& rawEntity)
{
entities.emplace_back(AZStd::unique_ptr<AZ::Entity>(rawEntity));
}
);
}
void SpawnableSortEntitiesTestFixture::ConvertoSpawnableToEntities(AZStd::vector<AZ::Entity*>& rawEntities)
{
auto& entities = m_spawnable.GetEntities();
rawEntities.clear();
rawEntities.reserve(entities.size());
AZStd::for_each(entities.begin(), entities.end(),
[this, &rawEntities](auto& entity)
{
auto* rawEntity = entity.release();
m_actualEntities.insert(rawEntity);
rawEntities.emplace_back(rawEntity);
}
);
}
void SpawnableSortEntitiesTestFixture::SortAndSanityCheck()
{
ConvertEntitiesToSpawnable(m_unsorted);
AzToolsFramework::Prefab::SpawnableUtils::SortEntitiesByTransformHierarchy(m_spawnable);
ConvertoSpawnableToEntities(m_sorted);
// sanity check that all entries are still there
EXPECT_EQ(m_expectedEntities, m_actualEntities);
}
bool SpawnableSortEntitiesTestFixture::IsChildAfterParent(AZ::EntityId childId, AZ::EntityId parentId)
{
int parentIndex = -1;
int childIndex = -1;
for (int i = 0; i < m_sorted.size(); ++i)
{
if (m_sorted[i] && (m_sorted[i]->GetId() == parentId) && (parentIndex == -1))
{
parentIndex = i;
}
if (m_sorted[i] && (m_sorted[i]->GetId() == childId) && (childIndex == -1))
{
childIndex = i;
}
}
EXPECT_NE(childIndex, -1);
EXPECT_NE(parentIndex, -1);
return childIndex > parentIndex;
}
}
@@ -0,0 +1,55 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and 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.
*
*/
#pragma once
#include <AzCore/Component/Entity.h>
#include <AzCore/std/containers/set.h>
#include <AzToolsFramework/UnitTest/AzToolsFrameworkTestHelpers.h>
#include <AzFramework/Spawnable/Spawnable.h>
namespace UnitTest
{
class SpawnableSortEntitiesTestFixture
: public ToolsApplicationFixture
{
protected:
AZStd::vector<AZ::Entity*> m_unsorted;
AZStd::vector<AZ::Entity*> m_sorted;
AZStd::multiset<AZ::Entity*> m_expectedEntities;
AZStd::multiset<AZ::Entity*> m_actualEntities;
AzFramework::Spawnable m_spawnable;
// Entity IDs to use in tests
AZ::EntityId E1 = AZ::EntityId(1);
AZ::EntityId E2 = AZ::EntityId(2);
AZ::EntityId E3 = AZ::EntityId(3);
AZ::EntityId E4 = AZ::EntityId(4);
AZ::EntityId E5 = AZ::EntityId(5);
AZ::EntityId E6 = AZ::EntityId(6);
AZ::EntityId MissingNo = AZ::EntityId(999);
void TearDownEditorFixtureImpl() override;
// add entity to m_unsorted
void AddEntity(AZ::EntityId id, AZ::EntityId parentId = AZ::EntityId(), bool expectedInSorted = true);
void AddEntity(AZ::Entity* entity, bool expectedInSorted = true);
void ConvertEntitiesToSpawnable(const AZStd::vector<AZ::Entity*>& rawEntities);
void ConvertoSpawnableToEntities(AZStd::vector<AZ::Entity*>& rawEntities);
void SortAndSanityCheck();
bool IsChildAfterParent(AZ::EntityId childId, AZ::EntityId parentId);
};
}
@@ -0,0 +1,160 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and 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 <Prefab/SpawnableSortEntitiesTestFixture.h>
namespace UnitTest
{
using SpawnableSortEntitiesTests = SpawnableSortEntitiesTestFixture;
TEST_F(SpawnableSortEntitiesTests, SpawnableSortEntities_0Entities_IsOk)
{
SortAndSanityCheck();
}
TEST_F(SpawnableSortEntitiesTests, SpawnableSortEntities_1Entity_IsOk)
{
AddEntity(E1);
SortAndSanityCheck();
}
TEST_F(SpawnableSortEntitiesTests, SpawnableSortEntities_ParentAndChild_SortsCorrectly)
{
AddEntity(E2, E1);
AddEntity(E1);
SortAndSanityCheck();
EXPECT_TRUE(IsChildAfterParent(E2, E1));
}
TEST_F(SpawnableSortEntitiesTests, SpawnableSortEntities_6EntitiesWith2Roots_SortsCorrectly)
{
// Hierarchy looks like:
// 1
// + 2
// + 3
// 4
// + 5
// + 6
// The entities are added in "random-ish" order on purpose
AddEntity(E3, E2);
AddEntity(E1);
AddEntity(E6, E4);
AddEntity(E5, E4);
AddEntity(E2, E1);
AddEntity(E4);
SortAndSanityCheck();
EXPECT_TRUE(IsChildAfterParent(E2, E1));
EXPECT_TRUE(IsChildAfterParent(E3, E2));
EXPECT_TRUE(IsChildAfterParent(E5, E4));
EXPECT_TRUE(IsChildAfterParent(E6, E4));
}
TEST_F(SpawnableSortEntitiesTests, SpawnableSortEntities_ParentNotFound_ChildTreatedAsRoot)
{
AddEntity(E1);
AddEntity(E2, E1);
AddEntity(E3, MissingNo); // E3's parent not found
AddEntity(E4, E3);
SortAndSanityCheck();
EXPECT_TRUE(IsChildAfterParent(E2, E1));
EXPECT_TRUE(IsChildAfterParent(E4, E2));
}
TEST_F(SpawnableSortEntitiesTests, SpawnableSortEntities_NullptrEntry_RemovedFromSorted)
{
AddEntity(E2, E1);
AddEntity(nullptr, false);
AddEntity(E1);
SortAndSanityCheck();
EXPECT_TRUE(IsChildAfterParent(E2, E1));
}
TEST_F(SpawnableSortEntitiesTests, SpawnableSortEntities_DuplicateEntityId_RemovedFromSorted)
{
AddEntity(E2, E1);
AddEntity(E1);
AddEntity(E1, AZ::EntityId(), false); // duplicate EntityId
SortAndSanityCheck();
EXPECT_TRUE(IsChildAfterParent(E2, E1));
}
TEST_F(SpawnableSortEntitiesTests, SpawnableSortEntities_LoopingHierarchy_PicksAnyParentAsRoot)
{
// loop: E1 -> E2 -> E3 -> E1 -> ...
AddEntity(E2, E1);
AddEntity(E3, E2);
AddEntity(E1, E3);
SortAndSanityCheck();
AZ::EntityId first = m_sorted.front()->GetId();
if (first == E1)
{
EXPECT_TRUE(IsChildAfterParent(E2, E1));
EXPECT_TRUE(IsChildAfterParent(E3, E2));
}
else if (first == E2)
{
EXPECT_TRUE(IsChildAfterParent(E3, E2));
EXPECT_TRUE(IsChildAfterParent(E1, E3));
}
else // if (first == E3)
{
EXPECT_TRUE(IsChildAfterParent(E1, E3));
EXPECT_TRUE(IsChildAfterParent(E2, E1));
}
}
TEST_F(SpawnableSortEntitiesTests, SpawnableSortEntities_EntityLackingTransformComponent_IsTreatedLikeItHasNoParent)
{
AddEntity(E2, E1);
AddEntity(aznew AZ::Entity(E1));
SortAndSanityCheck();
EXPECT_TRUE(IsChildAfterParent(E2, E1));
}
TEST_F(SpawnableSortEntitiesTests, SpawnableSortEntities_EntityParentedToSelf_IsTreatedLikeItHasNoParent)
{
AddEntity(E2, E1);
AddEntity(E1, E1); // parented to self
SortAndSanityCheck();
EXPECT_TRUE(IsChildAfterParent(E2, E1));
}
TEST_F(SpawnableSortEntitiesTests, SpawnableSortEntities_EntityWithInvalidId_RemovedFromSorted)
{
AddEntity(E2, E1);
AddEntity(E1);
AddEntity(AZ::EntityId(), AZ::EntityId(), false); // entity using invalid ID as its own ID
SortAndSanityCheck();
EXPECT_TRUE(IsChildAfterParent(E2, E1));
}
}
@@ -50,8 +50,11 @@ set(FILES
Prefab/Benchmark/PrefabInstantiateBenchmarks.cpp
Prefab/Benchmark/PrefabLoadBenchmarks.cpp
Prefab/Benchmark/PrefabUpdateInstancesBenchmarks.cpp
Prefab/Benchmark/SpawnableCreateBenchmarks.cpp
Prefab/Spawnable/SpawnableMetaDataTests.cpp
Prefab/MockPrefabFileIOActionValidator.cpp
Prefab/MockPrefabFileIOActionValidator.h
Prefab/PrefabEntityAliasTests.cpp
Prefab/PrefabInstanceToTemplatePropagatorTests.cpp
Prefab/PrefabInstantiateTests.cpp
Prefab/PrefabLoadTemplateTests.cpp
@@ -65,11 +68,22 @@ set(FILES
Prefab/PrefabTestDomUtils.h
Prefab/PrefabTestFixture.cpp
Prefab/PrefabTestFixture.h
Prefab/PrefabTestUndoFixture.cpp
Prefab/PrefabTestUndoFixture.h
Prefab/PrefabUndoLinkTests.cpp
Prefab/PrefabUndoTests.cpp
Prefab/PrefabTestUtils.h
Prefab/PrefabUpdateInstancesTests.cpp
Prefab/PrefabUpdateTemplateTests.cpp
Prefab/PrefabUpdateWithPatchesTests.cpp
Prefab/PrefabInstantiateTests.cpp
Prefab/SpawnableCreateTests.cpp
Prefab/SpawnableRemoveEditorInfoTests.cpp
Prefab/SpawnableRemoveEditorInfoTestFixture.cpp
Prefab/SpawnableRemoveEditorInfoTestFixture.h
Prefab/SpawnableSortEntitiesTests.cpp
Prefab/SpawnableSortEntitiesTestFixture.cpp
Prefab/SpawnableSortEntitiesTestFixture.h
Entity/EditorEntityContextComponentTests.cpp
Entity/EditorEntitySearchComponentTests.cpp
SliceStabilityTests/SliceStabilityTestFramework.h