Add Unit tests for EditorFocusMode and PrefabFocus. Minor change to PrefabFocusHandler to avoid instantiating a new AZ::EntityId() for checks.

Signed-off-by: Danilo Aimini <82231674+AMZN-daimini@users.noreply.github.com>
This commit is contained in:
Danilo Aimini
2021-09-24 15:05:34 -07:00
parent 66a875bf79
commit 72110e40cf
4 changed files with 317 additions and 2 deletions
@@ -35,7 +35,7 @@ namespace AzToolsFramework::Prefab
{
InstanceOptionalReference focusedInstance;
if (entityId == AZ::EntityId())
if (entityId == static_cast<AZ::EntityId>(AZ::EntityId::InvalidEntityId))
{
PrefabEditorEntityOwnershipInterface* prefabEditorEntityOwnershipInterface =
AZ::Interface<PrefabEditorEntityOwnershipInterface>::Get();
@@ -89,7 +89,7 @@ namespace AzToolsFramework::Prefab
return false;
}
if (entityId == AZ::EntityId())
if (entityId == static_cast<AZ::EntityId>(AZ::EntityId::InvalidEntityId))
{
return false;
}
@@ -0,0 +1,128 @@
/*
* 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 <AzTest/AzTest.h>
#include <AzCore/UserSettings/UserSettingsComponent.h>
#include <AzCore/Component/TransformBus.h>
#include <AzToolsFramework/FocusMode/FocusModeInterface.h>
#include <AzToolsFramework/UnitTest/AzToolsFrameworkTestHelpers.h>
namespace AzToolsFramework
{
class EditorFocusModeTests
: public ::testing::Test
{
protected:
void SetUp() override
{
m_app.Start(m_descriptor);
// Without this, the user settings component would attempt to save on finalize/shutdown. Since the file is
// shared across the whole engine, if multiple tests are run in parallel, the saving could cause a crash
// in the unit tests.
AZ::UserSettingsComponentRequestBus::Broadcast(&AZ::UserSettingsComponentRequests::DisableSaveOnFinalize);
GenerateTestHierarchy();
}
void GenerateTestHierarchy()
{
/*
* City
* |_ Street
* |_ Car
* | |_ Passenger
* |_ SportsCar
* |_ Passenger
*/
m_entityMap["cityId"] = CreateEditorEntity("City", AZ::EntityId());
m_entityMap["streetId"] = CreateEditorEntity("Street", m_entityMap["cityId"]);
m_entityMap["carId"] = CreateEditorEntity("Car", m_entityMap["streetId"]);
m_entityMap["passengerId1"] = CreateEditorEntity("Passenger", m_entityMap["carId"]);
m_entityMap["sportsCarId"] = CreateEditorEntity("SportsCar", m_entityMap["streetId"]);
m_entityMap["passengerId2"] = CreateEditorEntity("Passenger", m_entityMap["sportsCarId"]);
}
AZ::EntityId CreateEditorEntity(const char* name, AZ::EntityId parentId)
{
AZ::Entity* entity = nullptr;
UnitTest::CreateDefaultEditorEntity(name, &entity);
// Parent
AZ::TransformBus::Event(entity->GetId(), &AZ::TransformInterface::SetParent, parentId);
return entity->GetId();
}
void TearDown() override
{
m_app.Stop();
}
UnitTest::ToolsTestApplication m_app{ "EditorFocusModeTests" };
AZ::ComponentApplication::Descriptor m_descriptor;
AZStd::unordered_map<AZStd::string, AZ::EntityId> m_entityMap;
};
TEST_F(EditorFocusModeTests, EditorFocusModeTests_SetFocus)
{
FocusModeInterface* focusModeInterface = AZ::Interface<FocusModeInterface>::Get();
EXPECT_TRUE(focusModeInterface != nullptr);
focusModeInterface->SetFocusRoot(m_entityMap["carId"]);
EXPECT_EQ(focusModeInterface->GetFocusRoot(), m_entityMap["carId"]);
focusModeInterface->ClearFocusRoot();
EXPECT_EQ(focusModeInterface->GetFocusRoot(), AZ::EntityId());
}
TEST_F(EditorFocusModeTests, EditorFocusModeTests_IsInFocusSubTree)
{
FocusModeInterface* focusModeInterface = AZ::Interface<FocusModeInterface>::Get();
EXPECT_TRUE(focusModeInterface != nullptr);
focusModeInterface->ClearFocusRoot();
EXPECT_EQ(focusModeInterface->IsInFocusSubTree(m_entityMap["cityId"]), true);
EXPECT_EQ(focusModeInterface->IsInFocusSubTree(m_entityMap["streetId"]), true);
EXPECT_EQ(focusModeInterface->IsInFocusSubTree(m_entityMap["carId"]), true);
EXPECT_EQ(focusModeInterface->IsInFocusSubTree(m_entityMap["passengerId1"]), true);
EXPECT_EQ(focusModeInterface->IsInFocusSubTree(m_entityMap["sportsCarId"]), true);
EXPECT_EQ(focusModeInterface->IsInFocusSubTree(m_entityMap["passengerId2"]), true);
focusModeInterface->SetFocusRoot(m_entityMap["streetId"]);
EXPECT_EQ(focusModeInterface->IsInFocusSubTree(m_entityMap["cityId"]), false);
EXPECT_EQ(focusModeInterface->IsInFocusSubTree(m_entityMap["streetId"]), true);
EXPECT_EQ(focusModeInterface->IsInFocusSubTree(m_entityMap["carId"]), true);
EXPECT_EQ(focusModeInterface->IsInFocusSubTree(m_entityMap["passengerId1"]), true);
EXPECT_EQ(focusModeInterface->IsInFocusSubTree(m_entityMap["sportsCarId"]), true);
EXPECT_EQ(focusModeInterface->IsInFocusSubTree(m_entityMap["passengerId2"]), true);
focusModeInterface->SetFocusRoot(m_entityMap["carId"]);
EXPECT_EQ(focusModeInterface->IsInFocusSubTree(m_entityMap["cityId"]), false);
EXPECT_EQ(focusModeInterface->IsInFocusSubTree(m_entityMap["streetId"]), false);
EXPECT_EQ(focusModeInterface->IsInFocusSubTree(m_entityMap["carId"]), true);
EXPECT_EQ(focusModeInterface->IsInFocusSubTree(m_entityMap["passengerId1"]), true);
EXPECT_EQ(focusModeInterface->IsInFocusSubTree(m_entityMap["sportsCarId"]), false);
EXPECT_EQ(focusModeInterface->IsInFocusSubTree(m_entityMap["passengerId2"]), false);
focusModeInterface->SetFocusRoot(m_entityMap["passengerId2"]);
EXPECT_EQ(focusModeInterface->IsInFocusSubTree(m_entityMap["cityId"]), false);
EXPECT_EQ(focusModeInterface->IsInFocusSubTree(m_entityMap["streetId"]), false);
EXPECT_EQ(focusModeInterface->IsInFocusSubTree(m_entityMap["carId"]), false);
EXPECT_EQ(focusModeInterface->IsInFocusSubTree(m_entityMap["passengerId1"]), false);
EXPECT_EQ(focusModeInterface->IsInFocusSubTree(m_entityMap["sportsCarId"]), false);
EXPECT_EQ(focusModeInterface->IsInFocusSubTree(m_entityMap["passengerId2"]), true);
focusModeInterface->ClearFocusRoot();
}
}
@@ -0,0 +1,185 @@
/*
* 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 <AzCore/Component/EntityId.h>
#include <AzToolsFramework/Entity/EditorEntityHelpers.h>
#include <AzToolsFramework/Entity/PrefabEditorEntityOwnershipInterface.h>
#include <AzToolsFramework/Prefab/PrefabFocusInterface.h>
#include <Prefab/PrefabTestFixture.h>
namespace UnitTest
{
class PrefabFocusTests
: public PrefabTestFixture
{
protected:
void GenerateTestHierarchy()
{
/*
* City (Prefab Container)
* |_ City
* |_ Street (Prefab Container)
* |_ Car (Prefab Container)
* | |_ Passenger
* |_ SportsCar (Prefab Container)
* |_ Passenger
*/
m_entityMap["passenger1"] = CreateEntity("Passenger1");
m_entityMap["passenger2"] = CreateEntity("Passenger2");
m_entityMap["city"] = CreateEntity("City");
AzToolsFramework::EditorEntityContextRequestBus::Broadcast(
&AzToolsFramework::EditorEntityContextRequests::HandleEntitiesAdded,
AzToolsFramework::EntityList{ m_entityMap["passenger1"], m_entityMap["passenger2"], m_entityMap["city"] });
AZStd::unique_ptr<AzToolsFramework::Prefab::Instance> carInstance =
m_prefabSystemComponent->CreatePrefab({ m_entityMap["passenger1"] }, {}, "test/car");
ASSERT_TRUE(carInstance);
m_instanceMap["car"] = carInstance.get();
AZStd::unique_ptr<AzToolsFramework::Prefab::Instance> sportsCarInstance =
m_prefabSystemComponent->CreatePrefab({ m_entityMap["passenger2"] }, {}, "test/sportsCar");
ASSERT_TRUE(sportsCarInstance);
m_instanceMap["sportsCar"] = sportsCarInstance.get();
AZStd::unique_ptr<AzToolsFramework::Prefab::Instance> streetInstance =
m_prefabSystemComponent->CreatePrefab({}, MakeInstanceList( AZStd::move(carInstance), AZStd::move(sportsCarInstance) ), "test/street");
ASSERT_TRUE(streetInstance);
m_instanceMap["street"] = streetInstance.get();
m_rootInstance =
m_prefabSystemComponent->CreatePrefab({ m_entityMap["city"] }, MakeInstanceList(AZStd::move(streetInstance)), "test/city");
ASSERT_TRUE(m_rootInstance);
m_instanceMap["city"] = m_rootInstance.get();
}
AZ::EntityId CreateEditorEntity(const char* name, AZ::EntityId parentId)
{
AZ::Entity* newEntity = CreateEntity(name);
AzToolsFramework::EditorEntityContextRequestBus::Broadcast(
&AzToolsFramework::EditorEntityContextRequests::HandleEntitiesAdded, AzToolsFramework::EntityList{ newEntity });
// Parent
AZ::TransformBus::Event(newEntity->GetId(), &AZ::TransformInterface::SetParent, parentId);
return newEntity->GetId();
}
AZStd::unordered_map<AZStd::string, AZ::Entity*> m_entityMap;
AZStd::unordered_map<AZStd::string, Instance*> m_instanceMap;
AZStd::unique_ptr<AzToolsFramework::Prefab::Instance> m_rootInstance;
};
TEST_F(PrefabFocusTests, PrefabFocus_FocusOnOwningPrefab)
{
GenerateTestHierarchy();
PrefabFocusInterface* prefabFocusInterface = AZ::Interface<PrefabFocusInterface>::Get();
EXPECT_TRUE(prefabFocusInterface != nullptr);
// Verify FocusOnOwningPrefab works when passing the container entity of the root prefab.
{
prefabFocusInterface->FocusOnOwningPrefab(m_instanceMap["city"]->GetContainerEntityId());
EXPECT_EQ(prefabFocusInterface->GetFocusedPrefabTemplateId(), m_instanceMap["city"]->GetTemplateId());
auto instance = prefabFocusInterface->GetFocusedPrefabInstance();
EXPECT_TRUE(instance.has_value());
EXPECT_EQ(&instance->get(), m_instanceMap["city"]);
}
// Verify FocusOnOwningPrefab works when passing a nested entity of the root prefab.
{
prefabFocusInterface->FocusOnOwningPrefab(m_entityMap["city"]->GetId());
EXPECT_EQ(prefabFocusInterface->GetFocusedPrefabTemplateId(), m_instanceMap["city"]->GetTemplateId());
auto instance = prefabFocusInterface->GetFocusedPrefabInstance();
EXPECT_TRUE(instance.has_value());
EXPECT_EQ(&instance->get(), m_instanceMap["city"]);
}
// Verify FocusOnOwningPrefab works when passing the container entity of a nested prefab.
{
prefabFocusInterface->FocusOnOwningPrefab(m_instanceMap["car"]->GetContainerEntityId());
EXPECT_EQ(prefabFocusInterface->GetFocusedPrefabTemplateId(), m_instanceMap["car"]->GetTemplateId());
auto instance = prefabFocusInterface->GetFocusedPrefabInstance();
EXPECT_TRUE(instance.has_value());
EXPECT_EQ(&instance->get(), m_instanceMap["car"]);
}
// Verify FocusOnOwningPrefab works when passing a nested entity of the a nested prefab.
{
prefabFocusInterface->FocusOnOwningPrefab(m_entityMap["passenger1"]->GetId());
EXPECT_EQ(prefabFocusInterface->GetFocusedPrefabTemplateId(), m_instanceMap["car"]->GetTemplateId());
auto instance = prefabFocusInterface->GetFocusedPrefabInstance();
EXPECT_TRUE(instance.has_value());
EXPECT_EQ(&instance->get(), m_instanceMap["car"]);
}
// Verify FocusOnOwningPrefab points to the root prefab when the focus is cleared.
{
AzToolsFramework::PrefabEditorEntityOwnershipInterface* prefabEditorEntityOwnershipInterface =
AZ::Interface<AzToolsFramework::PrefabEditorEntityOwnershipInterface>::Get();
AzToolsFramework::Prefab::InstanceOptionalReference rootPrefabInstance =
prefabEditorEntityOwnershipInterface->GetRootPrefabInstance();
EXPECT_TRUE(rootPrefabInstance.has_value());
prefabFocusInterface->FocusOnOwningPrefab(AZ::EntityId());
EXPECT_EQ(prefabFocusInterface->GetFocusedPrefabTemplateId(), rootPrefabInstance->get().GetTemplateId());
auto instance = prefabFocusInterface->GetFocusedPrefabInstance();
EXPECT_TRUE(instance.has_value());
EXPECT_EQ(&instance->get(), &rootPrefabInstance->get());
}
m_rootInstance.release();
}
TEST_F(PrefabFocusTests, PrefabFocus_IsOwningPrefabBeingFocused)
{
GenerateTestHierarchy();
PrefabFocusInterface* prefabFocusInterface = AZ::Interface<PrefabFocusInterface>::Get();
EXPECT_TRUE(prefabFocusInterface != nullptr);
// Verify IsOwningPrefabBeingFocused returns true for all entities in a focused prefab (container/nested)
{
prefabFocusInterface->FocusOnOwningPrefab(m_instanceMap["city"]->GetContainerEntityId());
EXPECT_TRUE(prefabFocusInterface->IsOwningPrefabBeingFocused(m_instanceMap["city"]->GetContainerEntityId()));
EXPECT_TRUE(prefabFocusInterface->IsOwningPrefabBeingFocused(m_entityMap["city"]->GetId()));
}
// Verify IsOwningPrefabBeingFocused returns false for all entities not in a focused prefab (ancestors/descendants)
{
prefabFocusInterface->FocusOnOwningPrefab(m_instanceMap["street"]->GetContainerEntityId());
EXPECT_TRUE(prefabFocusInterface->IsOwningPrefabBeingFocused(m_instanceMap["street"]->GetContainerEntityId()));
EXPECT_FALSE(prefabFocusInterface->IsOwningPrefabBeingFocused(m_instanceMap["city"]->GetContainerEntityId()));
EXPECT_FALSE(prefabFocusInterface->IsOwningPrefabBeingFocused(m_entityMap["city"]->GetId()));
EXPECT_FALSE(prefabFocusInterface->IsOwningPrefabBeingFocused(m_instanceMap["car"]->GetContainerEntityId()));
EXPECT_FALSE(prefabFocusInterface->IsOwningPrefabBeingFocused(m_entityMap["passenger1"]->GetId()));
}
// Verify IsOwningPrefabBeingFocused returns false for all entities not in a focused prefab (siblings)
{
prefabFocusInterface->FocusOnOwningPrefab(m_instanceMap["sportsCar"]->GetContainerEntityId());
EXPECT_TRUE(prefabFocusInterface->IsOwningPrefabBeingFocused(m_instanceMap["sportsCar"]->GetContainerEntityId()));
EXPECT_TRUE(prefabFocusInterface->IsOwningPrefabBeingFocused(m_entityMap["passenger2"]->GetId()));
EXPECT_FALSE(prefabFocusInterface->IsOwningPrefabBeingFocused(m_instanceMap["car"]->GetContainerEntityId()));
EXPECT_FALSE(prefabFocusInterface->IsOwningPrefabBeingFocused(m_entityMap["passenger1"]->GetId()));
}
m_rootInstance.release();
}
}
@@ -34,6 +34,7 @@ set(FILES
EntityTestbed.h
FileFunc.cpp
FingerprintingTests.cpp
FocusMode/EditorFocusModeTests.cpp
GenericComponentWrapperTest.cpp
InstanceDataHierarchy.cpp
IntegerPrimtitiveTestConfig.h
@@ -50,6 +51,7 @@ set(FILES
Prefab/Benchmark/PrefabLoadBenchmarks.cpp
Prefab/Benchmark/PrefabUpdateInstancesBenchmarks.cpp
Prefab/Benchmark/SpawnableCreateBenchmarks.cpp
Prefab/PrefabFocus/PrefabFocusTests.cpp
Prefab/MockPrefabFileIOActionValidator.cpp
Prefab/MockPrefabFileIOActionValidator.h
Prefab/PrefabDuplicateTests.cpp