123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215 |
- /*
- * 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 "PrefabBuilderTests.h"
- #include <AzCore/Asset/AssetSerializer.h>
- #include <AzCore/Component/TransformBus.h>
- #include <AzCore/Memory/AllocationRecords.h>
- #include <AzCore/Serialization/Json/JsonSystemComponent.h>
- #include <AzCore/Serialization/Json/JsonUtils.h>
- #include <AzCore/Serialization/Json/RegistrationContext.h>
- #include <AzCore/Settings/SettingsRegistryMergeUtils.h>
- #include <AzCore/UserSettings/UserSettingsComponent.h>
- #include <AzToolsFramework/UnitTest/AzToolsFrameworkTestHelpers.h>
- namespace UnitTest
- {
- AZ::Entity* CreateEntity(const char* entityName, AZStd::initializer_list<AZ::Component*> componentsToAdd = {})
- {
- // Circumvent the EntityContext system and generate a new entity with a transformcomponent
- AZ::Entity* newEntity = aznew AZ::Entity(entityName);
- newEntity->CreateComponent(AZ::TransformComponentTypeId);
- newEntity->Init();
- for (auto&& component : componentsToAdd)
- {
- newEntity->AddComponent(component);
- }
- newEntity->Activate();
- return newEntity;
- }
- TEST_F(PrefabBuilderTests, SourceDependencies)
- {
- static constexpr const char* ChildPrefabPath = "child.prefab";
- using namespace AzToolsFramework::Prefab;
- AZStd::vector<AZStd::unique_ptr<Instance>> childInstances;
- auto* prefabSystemComponentInterface = AZ::Interface<PrefabSystemComponentInterface>::Get();
- auto* prefabLoaderInterface = AZ::Interface<PrefabLoaderInterface>::Get();
- ASSERT_NE(prefabSystemComponentInterface, nullptr);
- ASSERT_NE(prefabLoaderInterface, nullptr);
- // Create a child entity and a prefab containing it
- childInstances.push_back(prefabSystemComponentInterface->CreatePrefab({CreateEntity("child")}, {}, ChildPrefabPath));
- // Create a parent entity and a prefab for it, pass in the child prefab for it to reference
- auto parentInstance = prefabSystemComponentInterface->CreatePrefab({CreateEntity("parent")}, AZStd::move(childInstances), "parent.prefab");
-
- AZStd::string serializedInstance;
- // Save to a string so we can load it as a PrefabDom and so that the nested instance becomes a Source file reference
- ASSERT_TRUE(prefabLoaderInterface->SaveTemplateToString(parentInstance->GetTemplateId(), serializedInstance));
- AZ::Outcome<PrefabDom, AZStd::string> readPrefabFileResult = AZ::JsonSerializationUtils::ReadJsonString(serializedInstance);
- ASSERT_TRUE(readPrefabFileResult.IsSuccess());
- // Now that we have a PrefabDom, test extracting the Source file reference as a Source Dependency
- auto sourceFileDependencies = AZ::Prefab::PrefabBuilderComponent::GetSourceDependencies(readPrefabFileResult.TakeValue());
- ASSERT_EQ(sourceFileDependencies.size(), 1);
- EXPECT_STREQ(sourceFileDependencies[0].m_sourceFileDependencyPath.c_str(), ChildPrefabPath);
- }
- TEST_F(PrefabBuilderTests, ProductDependencies)
- {
- constexpr const char* ChildPrefabPath = "child.prefab";
- using namespace AzToolsFramework::Prefab;
- AZ::Uuid TestAssetUuid("{7725567D-D420-46C2-B481-E0F79212CD34}");
- AZ::Data::AssetId TestAssetId(TestAssetUuid, 0);
-
- AZStd::vector<AZStd::unique_ptr<Instance>> childInstances;
- auto* prefabSystemComponentInterface = AZ::Interface<PrefabSystemComponentInterface>::Get();
- ASSERT_NE(prefabSystemComponentInterface, nullptr);
- auto* component = aznew TestComponent();
- AZ::Data::Asset<AZ::Data::AssetData> asset = AZ::Data::Asset<TestAsset>(TestAssetId, azrtti_typeid<TestAsset>());
- component->m_asset = asset;
- AZ::Entity* childEntity = CreateEntity("child", {component});
- // Create a child prefab with an entity that has an Asset<T> reference on it
- childInstances.push_back(prefabSystemComponentInterface->CreatePrefab(
- {childEntity}, {}, ChildPrefabPath, AZStd::unique_ptr<AZ::Entity>(CreateEntity("Container"))));
- // Create a parent prefab that has a nested instance reference to the child prefab
- auto parentInstance =
- prefabSystemComponentInterface->CreatePrefab({CreateEntity("parent")}, AZStd::move(childInstances), "parent.prefab", AZStd::unique_ptr<AZ::Entity>(CreateEntity("Container")));
- AZStd::string serializedInstance;
-
- TestPrefabBuilderComponent prefabBuilderComponent;
- prefabBuilderComponent.Activate();
-
- AZStd::vector<AssetBuilderSDK::JobProduct> jobProducts;
- // Make a copy of the template DOM, as the prefab system still owns the existing template
- AzToolsFramework::Prefab::PrefabDom prefabDom;
- prefabDom.CopyFrom(prefabSystemComponentInterface->FindTemplateDom(parentInstance->GetTemplateId()), prefabDom.GetAllocator(), false);
- ASSERT_TRUE(prefabBuilderComponent.ProcessPrefab(
- { AZ::Crc32("pc") }, "parent.prefab", "unused", AZ::Uuid(), AZStd::move(prefabDom), jobProducts));
- ASSERT_EQ(jobProducts.size(), 1);
- ASSERT_EQ(jobProducts[0].m_dependencies.size(), 1);
- ASSERT_EQ(jobProducts[0].m_dependencies[0].m_dependencyId, TestAssetId);
- prefabBuilderComponent.Deactivate();
- }
- AZStd::pair<size_t, size_t> GetFingerprint(AzToolsFramework::Prefab::PrefabDom& dom)
- {
- TestPrefabBuilderComponent prefabBuilderComponent;
- prefabBuilderComponent.Activate();
- size_t builderFingerprint = prefabBuilderComponent.CalculateBuilderFingerprint();
- size_t fingerprint = prefabBuilderComponent.CalculatePrefabFingerprint(dom);
- prefabBuilderComponent.Deactivate();
- return {fingerprint, builderFingerprint};
- }
- TEST_F(PrefabBuilderTests, FingerprintTest)
- {
- auto* prefabSystemComponentInterface = AZ::Interface<AzToolsFramework::Prefab::PrefabSystemComponentInterface>::Get();
- ASSERT_NE(prefabSystemComponentInterface, nullptr);
-
- auto* component = aznew TestComponent();
- AZ::Entity* entity = CreateEntity("test", {component});
- auto parentInstance = prefabSystemComponentInterface->CreatePrefab(
- {entity}, {}, "test.prefab",
- AZStd::unique_ptr<AZ::Entity>(CreateEntity("Container")));
- AZStd::vector<AssetBuilderSDK::JobProduct> jobProducts;
- auto&& prefabDom = prefabSystemComponentInterface->FindTemplateDom(parentInstance->GetTemplateId());
-
- auto [v0Dom, v0Builder] = GetFingerprint(prefabDom);
- auto [sanityDom, sanityBuilder] = GetFingerprint(prefabDom);
- // Make sure the fingerprint is stable without changes
- ASSERT_EQ(v0Dom, sanityDom);
- ASSERT_EQ(v0Builder, sanityBuilder);
- AZ::SerializeContext* context = m_app.GetSerializeContext();
- // Unreflect VersionChangingData, change its version, and reflect it again
- context->EnableRemoveReflection();
- VersionChangingData::Reflect(context);
- VersionChangingData::m_version = 1;
- context->DisableRemoveReflection();
- VersionChangingData::Reflect(context);
- // Get the new fingerprint and check that it changed
- auto [v1Dom, v1Builder] = GetFingerprint(prefabDom);
- ASSERT_NE(v0Dom, v1Dom); // Verify the fingerprint for the object changed
- ASSERT_NE(v0Builder, v1Builder); // Verify the fingerprint for the entire builder changed
- }
- AZStd::unique_ptr<AZ::IO::GenericStream> TestPrefabBuilderComponent::GetOutputStream(const AZ::IO::Path&) const
- {
- return AZStd::make_unique<SelfContainedMemoryStream>();
- }
- void PrefabBuilderTests::SetUp()
- {
- AZ::SettingsRegistryInterface* registry = AZ::SettingsRegistry::Get();
- auto projectPathKey =
- AZ::SettingsRegistryInterface::FixedValueString(AZ::SettingsRegistryMergeUtils::BootstrapSettingsRootKey) + "/project_path";
- AZ::IO::FixedMaxPath enginePath;
- registry->Get(enginePath.Native(), AZ::SettingsRegistryMergeUtils::FilePathKey_EngineRootFolder);
- registry->Set(projectPathKey, (enginePath / "AutomatedTesting").Native());
- AZ::SettingsRegistryMergeUtils::MergeSettingsToRegistry_AddRuntimeFilePaths(*registry);
- AZ::ComponentApplication::Descriptor desc;
- desc.m_recordingMode = AZ::Debug::AllocationRecords::Mode::RECORD_NO_RECORDS;
- m_app.Start(desc);
- m_app.CreateReflectionManager();
- m_testComponentDescriptor = AZStd::unique_ptr<AZ::ComponentDescriptor>{TestComponent::CreateDescriptor()};
- m_testComponentDescriptor->Reflect(m_app.GetSerializeContext());
- TestAsset::Reflect(m_app.GetSerializeContext());
- VersionChangingData::Reflect(m_app.GetSerializeContext());
- // 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);
- AZ::Data::AssetManager::Instance().RegisterHandler(&m_assetHandler, azrtti_typeid<TestAsset>());
- }
- void PrefabBuilderTests::TearDown()
- {
- AZ::Data::AssetManager::Instance().UnregisterHandler(&m_assetHandler);
- m_testComponentDescriptor = nullptr;
- m_app.Stop();
- }
- }
- AZ_TOOLS_UNIT_TEST_HOOK(DEFAULT_UNIT_TEST_ENV);
|