Files
o3de/Code/Framework/AzToolsFramework/Tests/Prefab/PrefabFocus/PrefabFocusTests.cpp
T
Danilo Aimini daeab4bbb1 Focus Mode | Switch instance referencing in Prefab Focus Handler to use more reliable Instance handles (#7304)
* Add function to Prefab Instances allowing to get a reference to a nested instance by alias.

Signed-off-by: Danilo Aimini <82231674+AMZN-daimini@users.noreply.github.com>

* Refactor the Prefab Focus Handler to use RootAliasPaths to store the reference to the currently focused prefab instance instead of the previous method (entityId of the prefab container).

Signed-off-by: Danilo Aimini <82231674+AMZN-daimini@users.noreply.github.com>

* Use existing FindNestedInstance method instead of adding new one.

Signed-off-by: Danilo Aimini <82231674+AMZN-daimini@users.noreply.github.com>

* Minor fixes to style and comments

Signed-off-by: Danilo Aimini <82231674+AMZN-daimini@users.noreply.github.com>

* Removing indexing in GetInstanceReferenceFromRootAliasPath, turn variables into constants where possible.

Signed-off-by: Danilo Aimini <82231674+AMZN-daimini@users.noreply.github.com>

* Modified the Prefab Focus test fixture to ensure the entity hierarchy is generated under the Prefab EOS, allowing tests to work with the new implementation of the focus mode handler.

Signed-off-by: Danilo Aimini <82231674+AMZN-daimini@users.noreply.github.com>

* Ensure RootAliasPath is iterated by reference in GetInstanceReferenceFromRootAliasPath

Signed-off-by: Danilo Aimini <82231674+AMZN-daimini@users.noreply.github.com>
2022-02-02 09:17:59 -08:00

238 lines
12 KiB
C++

/*
* Copyright (c) Contributors to the Open 3D Engine Project.
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
*
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
*/
#include <AzCore/Component/EntityId.h>
#include <AzToolsFramework/Entity/EditorEntityHelpers.h>
#include <AzToolsFramework/Entity/PrefabEditorEntityOwnershipInterface.h>
#include <AzToolsFramework/Prefab/PrefabFocusInterface.h>
#include <AzToolsFramework/Prefab/PrefabFocusPublicInterface.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
*/
// Create loose entities
m_entityMap[Passenger1EntityName] = CreateEntity(Passenger1EntityName);
m_entityMap[Passenger2EntityName] = CreateEntity(Passenger2EntityName);
m_entityMap[CityEntityName] = CreateEntity(CityEntityName);
// Call HandleEntitiesAdded to the loose entities to register them with the Prefab EOS
AzToolsFramework::EditorEntityContextRequestBus::Broadcast(
&AzToolsFramework::EditorEntityContextRequests::HandleEntitiesAdded,
AzToolsFramework::EntityList{ m_entityMap[Passenger1EntityName], m_entityMap[Passenger2EntityName], m_entityMap[CityEntityName] });
// Initialize Prefab EOS Interface
AzToolsFramework::PrefabEditorEntityOwnershipInterface* prefabEditorEntityOwnershipInterface =
AZ::Interface<AzToolsFramework::PrefabEditorEntityOwnershipInterface>::Get();
ASSERT_TRUE(prefabEditorEntityOwnershipInterface);
// Create a car prefab from the passenger1 entity. The container entity will be created as part of the process.
AZStd::unique_ptr<AzToolsFramework::Prefab::Instance> carInstance =
m_prefabSystemComponent->CreatePrefab({ m_entityMap[Passenger1EntityName] }, {}, "test/car");
ASSERT_TRUE(carInstance);
m_instanceMap[CarEntityName] = carInstance.get();
// Create a sportscar prefab from the passenger2 entity. The container entity will be created as part of the process.
AZStd::unique_ptr<AzToolsFramework::Prefab::Instance> sportsCarInstance =
m_prefabSystemComponent->CreatePrefab({ m_entityMap[Passenger2EntityName] }, {}, "test/sportsCar");
ASSERT_TRUE(sportsCarInstance);
m_instanceMap[SportsCarEntityName] = sportsCarInstance.get();
// Create a street prefab that nests the car and sportscar instances created above. The container entity will be created as part of the process.
AZStd::unique_ptr<AzToolsFramework::Prefab::Instance> streetInstance =
m_prefabSystemComponent->CreatePrefab({}, MakeInstanceList(AZStd::move(carInstance), AZStd::move(sportsCarInstance)), "test/street");
ASSERT_TRUE(streetInstance);
m_instanceMap[StreetEntityName] = streetInstance.get();
// Use the Prefab EOS root instance as the City instance. This will ensure functions that go through the EOS work in these tests too.
m_rootInstance = prefabEditorEntityOwnershipInterface->GetRootPrefabInstance();
ASSERT_TRUE(m_rootInstance.has_value());
m_rootInstance->get().AddEntity(*m_entityMap[CityEntityName]);
m_rootInstance->get().AddInstance(AZStd::move(streetInstance));
m_instanceMap[CityEntityName] = &m_rootInstance->get();
}
void SetUpEditorFixtureImpl() override
{
PrefabTestFixture::SetUpEditorFixtureImpl();
m_prefabFocusInterface = AZ::Interface<PrefabFocusInterface>::Get();
ASSERT_TRUE(m_prefabFocusInterface != nullptr);
m_prefabFocusPublicInterface = AZ::Interface<PrefabFocusPublicInterface>::Get();
ASSERT_TRUE(m_prefabFocusPublicInterface != nullptr);
AzToolsFramework::EditorEntityContextRequestBus::BroadcastResult(
m_editorEntityContextId, &AzToolsFramework::EditorEntityContextRequestBus::Events::GetEditorEntityContextId);
GenerateTestHierarchy();
}
void TearDownEditorFixtureImpl() override
{
m_rootInstance->get().Reset();
PrefabTestFixture::TearDownEditorFixtureImpl();
}
AZStd::unordered_map<AZStd::string, AZ::Entity*> m_entityMap;
AZStd::unordered_map<AZStd::string, Instance*> m_instanceMap;
InstanceOptionalReference m_rootInstance;
PrefabFocusInterface* m_prefabFocusInterface = nullptr;
PrefabFocusPublicInterface* m_prefabFocusPublicInterface = nullptr;
AzFramework::EntityContextId m_editorEntityContextId = AzFramework::EntityContextId::CreateNull();
inline static const char* CityEntityName = "City";
inline static const char* StreetEntityName = "Street";
inline static const char* CarEntityName = "Car";
inline static const char* SportsCarEntityName = "SportsCar";
inline static const char* Passenger1EntityName = "Passenger1";
inline static const char* Passenger2EntityName = "Passenger2";
};
// Test was disabled because the implementation of GetFocusedPrefabInstance now relies on the Prefab EOS,
// which is not used by our test environment. This can be restored once Instance handles are implemented.
TEST_F(PrefabFocusTests, DISABLED_PrefabFocus_FocusOnOwningPrefab_RootContainer)
{
// Verify FocusOnOwningPrefab works when passing the container entity of the root prefab.
{
m_prefabFocusPublicInterface->FocusOnOwningPrefab(m_instanceMap[CityEntityName]->GetContainerEntityId());
EXPECT_EQ(
m_prefabFocusInterface->GetFocusedPrefabTemplateId(m_editorEntityContextId),
m_instanceMap[CityEntityName]->GetTemplateId());
auto instance = m_prefabFocusInterface->GetFocusedPrefabInstance(m_editorEntityContextId);
EXPECT_TRUE(instance.has_value());
EXPECT_EQ(&instance->get(), m_instanceMap[CityEntityName]);
}
}
// Test was disabled because the implementation of GetFocusedPrefabInstance now relies on the Prefab EOS,
// which is not used by our test environment. This can be restored once Instance handles are implemented.
TEST_F(PrefabFocusTests, DISABLED_PrefabFocus_FocusOnOwningPrefab_RootEntity)
{
// Verify FocusOnOwningPrefab works when passing a nested entity of the root prefab.
{
m_prefabFocusPublicInterface->FocusOnOwningPrefab(m_entityMap[CityEntityName]->GetId());
EXPECT_EQ(
m_prefabFocusInterface->GetFocusedPrefabTemplateId(m_editorEntityContextId),
m_instanceMap[CityEntityName]->GetTemplateId());
auto instance = m_prefabFocusInterface->GetFocusedPrefabInstance(m_editorEntityContextId);
EXPECT_TRUE(instance.has_value());
EXPECT_EQ(&instance->get(), m_instanceMap[CityEntityName]);
}
}
TEST_F(PrefabFocusTests, PrefabFocus_FocusOnOwningPrefab_NestedContainer)
{
// Verify FocusOnOwningPrefab works when passing the container entity of a nested prefab.
{
m_prefabFocusPublicInterface->FocusOnOwningPrefab(m_instanceMap[CarEntityName]->GetContainerEntityId());
EXPECT_EQ(
m_prefabFocusInterface->GetFocusedPrefabTemplateId(m_editorEntityContextId), m_instanceMap[CarEntityName]->GetTemplateId());
auto instance = m_prefabFocusInterface->GetFocusedPrefabInstance(m_editorEntityContextId);
EXPECT_TRUE(instance.has_value());
EXPECT_EQ(&instance->get(), m_instanceMap[CarEntityName]);
}
}
TEST_F(PrefabFocusTests, PrefabFocus_FocusOnOwningPrefab_NestedEntity)
{
// Verify FocusOnOwningPrefab works when passing a nested entity of the a nested prefab.
{
m_prefabFocusPublicInterface->FocusOnOwningPrefab(m_entityMap[Passenger1EntityName]->GetId());
EXPECT_EQ(
m_prefabFocusInterface->GetFocusedPrefabTemplateId(m_editorEntityContextId), m_instanceMap[CarEntityName]->GetTemplateId());
auto instance = m_prefabFocusInterface->GetFocusedPrefabInstance(m_editorEntityContextId);
EXPECT_TRUE(instance.has_value());
EXPECT_EQ(&instance->get(), m_instanceMap[CarEntityName]);
}
}
TEST_F(PrefabFocusTests, PrefabFocus_FocusOnOwningPrefab_Clear)
{
// 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());
m_prefabFocusPublicInterface->FocusOnOwningPrefab(AZ::EntityId());
EXPECT_EQ(
m_prefabFocusInterface->GetFocusedPrefabTemplateId(m_editorEntityContextId), rootPrefabInstance->get().GetTemplateId());
auto instance = m_prefabFocusInterface->GetFocusedPrefabInstance(m_editorEntityContextId);
EXPECT_TRUE(instance.has_value());
EXPECT_EQ(&instance->get(), &rootPrefabInstance->get());
}
}
TEST_F(PrefabFocusTests, PrefabFocus_IsOwningPrefabBeingFocused_Content)
{
// Verify IsOwningPrefabBeingFocused returns true for all entities in a focused prefab (container/nested)
{
m_prefabFocusPublicInterface->FocusOnOwningPrefab(m_instanceMap[CityEntityName]->GetContainerEntityId());
EXPECT_TRUE(m_prefabFocusPublicInterface->IsOwningPrefabBeingFocused(m_instanceMap[CityEntityName]->GetContainerEntityId()));
EXPECT_TRUE(m_prefabFocusPublicInterface->IsOwningPrefabBeingFocused(m_entityMap[CityEntityName]->GetId()));
}
}
TEST_F(PrefabFocusTests, PrefabFocus_IsOwningPrefabBeingFocused_AncestorsDescendants)
{
// Verify IsOwningPrefabBeingFocused returns false for all entities not in a focused prefab (ancestors/descendants)
{
m_prefabFocusPublicInterface->FocusOnOwningPrefab(m_instanceMap[StreetEntityName]->GetContainerEntityId());
EXPECT_TRUE(m_prefabFocusPublicInterface->IsOwningPrefabBeingFocused(m_instanceMap[StreetEntityName]->GetContainerEntityId()));
EXPECT_FALSE(m_prefabFocusPublicInterface->IsOwningPrefabBeingFocused(m_instanceMap[CityEntityName]->GetContainerEntityId()));
EXPECT_FALSE(m_prefabFocusPublicInterface->IsOwningPrefabBeingFocused(m_entityMap[CityEntityName]->GetId()));
EXPECT_FALSE(m_prefabFocusPublicInterface->IsOwningPrefabBeingFocused(m_instanceMap[CarEntityName]->GetContainerEntityId()));
EXPECT_FALSE(m_prefabFocusPublicInterface->IsOwningPrefabBeingFocused(m_entityMap[Passenger1EntityName]->GetId()));
}
}
TEST_F(PrefabFocusTests, PrefabFocus_IsOwningPrefabBeingFocused_Siblings)
{
// Verify IsOwningPrefabBeingFocused returns false for all entities not in a focused prefab (siblings)
{
m_prefabFocusPublicInterface->FocusOnOwningPrefab(m_instanceMap[SportsCarEntityName]->GetContainerEntityId());
EXPECT_TRUE(m_prefabFocusPublicInterface->IsOwningPrefabBeingFocused(m_instanceMap[SportsCarEntityName]->GetContainerEntityId()));
EXPECT_TRUE(m_prefabFocusPublicInterface->IsOwningPrefabBeingFocused(m_entityMap[Passenger2EntityName]->GetId()));
EXPECT_FALSE(m_prefabFocusPublicInterface->IsOwningPrefabBeingFocused(m_instanceMap[CarEntityName]->GetContainerEntityId()));
EXPECT_FALSE(m_prefabFocusPublicInterface->IsOwningPrefabBeingFocused(m_entityMap[Passenger1EntityName]->GetId()));
}
}
}