123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150 |
- /*
- * 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 <Prefab/PrefabDomUtils.h>
- #include <Prefab/PrefabTestComponent.h>
- #include <Prefab/PrefabTestDomUtils.h>
- #include <Prefab/PrefabTestFixture.h>
- #include <AzCore/Component/ComponentApplicationBus.h>
- #include <AzToolsFramework/Entity/EditorEntityContextBus.h>
- namespace UnitTest
- {
- using PrefabUpdateWithPatchesTest = PrefabTestFixture;
- /*
- The below tests use an example of car->axle->wheel templates to test that change propagation works correctly within templates.
- The car template will have axle templates nested under it and the axle template will have wheel templates nested under it.
- Because of the complexity that arises from multiple levels of prefab nesting, it's easier to write tests using an example scenario
- than use generic nesting terminology.
- */
- TEST_F(PrefabUpdateWithPatchesTest, ApplyPatchesToInstance_ComponentUpdated_PatchAppliedCorrectly)
- {
- // Create a single entity wheel instance with a PrefabTestComponent and create a template out of it.
- AZ::Entity* wheelEntity = CreateEntity("WheelEntity1");
- AddRequiredEditorComponents({ wheelEntity->GetId() });
- wheelEntity->Deactivate();
- PrefabTestComponent* prefabTestComponent = aznew PrefabTestComponent(true);
- wheelEntity->AddComponent(prefabTestComponent);
- AZ::ComponentId prefabTestComponentId = prefabTestComponent->GetId();
- const int expectedComponentCount = 10; // 9 of them are from AddRequiredEditorComponents.
- wheelEntity->Activate();
- AZStd::unique_ptr<Instance> wheelIsolatedInstance = m_prefabSystemComponent->CreatePrefab({ wheelEntity },
- {}, WheelPrefabMockFilePath);
- const TemplateId wheelTemplateId = wheelIsolatedInstance->GetTemplateId();
- PrefabDom& wheelTemplateDom = m_prefabSystemComponent->FindTemplateDom(wheelTemplateId);
- AZStd::vector<EntityAlias> wheelTemplateEntityAliases = wheelIsolatedInstance->GetEntityAliases();
- // Validate that the wheel template has the same entities(1) as the instance it was created from.
- ASSERT_EQ(wheelTemplateEntityAliases.size(), 1);
- // Validate that the wheel entity has 2 components. One of them is added through HandleEntitiesAdded() in EditorEntityContext.
- EntityAlias wheelEntityAlias = wheelTemplateEntityAliases.front();
- PrefabDomValue* wheelEntityComponents =
- PrefabTestDomUtils::GetPrefabDomComponentsPath(wheelEntityAlias).Get(wheelTemplateDom);
- ASSERT_TRUE(wheelEntityComponents != nullptr && wheelEntityComponents->IsObject());
- EXPECT_EQ(wheelEntityComponents->MemberCount(), expectedComponentCount);
- // Extract the component id of the entity in wheel template and verify that it matches with the component id of the wheel instance.
- PrefabTestDomUtils::ValidateComponentsDomHasId(
- *wheelEntityComponents, prefabTestComponent->RTTI_GetTypeName(), prefabTestComponentId);
- // Create an axle with 0 entities and 1 wheel instance.
- AZStd::unique_ptr<Instance> wheel1UnderAxle = m_prefabSystemComponent->InstantiatePrefab(wheelTemplateId);
- const AZStd::vector<EntityAlias> wheelEntityAliasesUnderAxle = wheel1UnderAxle->GetEntityAliases();
- AZStd::unique_ptr<Instance> axleInstance = m_prefabSystemComponent->CreatePrefab({},
- MakeInstanceList(AZStd::move(wheel1UnderAxle)), AxlePrefabMockFilePath);
- 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.
- AZStd::unique_ptr<Instance> axleUnderCar = m_prefabSystemComponent->InstantiatePrefab(axleTemplateId);
- AZStd::unique_ptr<Instance> carInstance = m_prefabSystemComponent->CreatePrefab({},
- MakeInstanceList(AZStd::move(axleUnderCar)), CarPrefabMockFilePath);
- const TemplateId carTemplateId = carInstance->GetTemplateId();
- const AZStd::vector<InstanceAlias> axleInstanceAliasesUnderCar = carInstance->GetNestedInstanceAliases(axleTemplateId);
- PrefabDom& carTemplateDom = m_prefabSystemComponent->FindTemplateDom(carTemplateId);
- InstanceOptionalReference nestedWheelInstanceRef = axleInstance->FindNestedInstance(wheelInstanceAliasesUnderAxle[0]);
- ASSERT_TRUE(nestedWheelInstanceRef);
- //get the entity id
- AZStd::vector<AZ::EntityId> entityIdVector;
- axleInstance->GetAllEntityIdsInHierarchy([&entityIdVector](AZ::EntityId entityId)
- {
- entityIdVector.push_back(entityId);
- return true;
- });
- 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;
- axleInstance->GetAllEntitiesInHierarchy([&wheelEntityUnderAxle, wheelEntityIdUnderAxle](AZStd::unique_ptr<AZ::Entity>& entity)
- {
- if (entity->GetId() == wheelEntityIdUnderAxle)
- {
- wheelEntityUnderAxle = entity.get();
- return false;
- }
- else
- {
- return true;
- }
- });
- ASSERT_NE(nullptr, wheelEntityUnderAxle);
- //create document with before change snapshot
- PrefabDom entityDomBefore;
- m_instanceToTemplateInterface->GenerateEntityDomBySerializing(entityDomBefore, *wheelEntityUnderAxle);
- PrefabTestComponent* axlewheelComponent = wheelEntityUnderAxle->FindComponent<PrefabTestComponent>();
- // Change the bool property of the component from Wheel instance and use it to update the wheel template.
- axlewheelComponent->m_boolProperty = false;
- //create document with after change snapshot
- PrefabDom entityDomAfter;
- m_instanceToTemplateInterface->GenerateEntityDomBySerializing(entityDomAfter, *wheelEntityUnderAxle);
- InstanceOptionalReference topMostInstanceInHierarchy = m_instanceToTemplateInterface->GetTopMostInstanceInHierarchy(wheelEntityIdUnderAxle);
- ASSERT_TRUE(topMostInstanceInHierarchy);
- PrefabDom patches;
- InstanceOptionalReference wheelInstanceUnderAxle = axleInstance->FindNestedInstance(wheelInstanceAliasesUnderAxle.front());
- m_instanceToTemplateInterface->GeneratePatchForLink(patches, entityDomBefore, entityDomAfter, wheelInstanceUnderAxle->get().GetLinkId());
- m_instanceToTemplateInterface->ApplyPatchesToInstance(wheelEntityIdUnderAxle, patches, topMostInstanceInHierarchy->get());
- m_instanceUpdateExecutorInterface->UpdateTemplateInstancesInQueue();
- // Validate that the prefabTestComponent in the wheel instance under axle doesn't have a BoolProperty.
- // 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(wheelEntityAlias).Get(*wheelInstanceDomUnderAxle);
- ASSERT_TRUE(wheelEntityComponents != nullptr);
- PrefabDomValueReference wheelEntityComponentValue = PrefabDomUtils::FindPrefabDomValue(*wheelEntityComponents, prefabTestComponent->RTTI_GetTypeName());
- ASSERT_TRUE(wheelEntityComponentValue);
- PrefabDomValueReference wheelEntityComponentBoolPropertyValue =
- PrefabDomUtils::FindPrefabDomValue(wheelEntityComponentValue->get(), PrefabTestDomUtils::BoolPropertyName);
- ASSERT_TRUE(wheelEntityComponentBoolPropertyValue.has_value());
- ASSERT_TRUE(wheelEntityComponentBoolPropertyValue->get().IsBool());
- ASSERT_FALSE(wheelEntityComponentBoolPropertyValue->get().GetBool());
- // Validate that the axles under the car have the same DOM as the axle template.
- PrefabTestDomUtils::ValidatePrefabDomInstances(axleInstanceAliasesUnderCar, carTemplateDom, axleTemplateDom);
- }
- }
|