123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391 |
- /*
- * 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 <AssetBuilderSDK/AssetBuilderSDK.h>
- #include <AzCore/IO/FileIO.h>
- #include <AzCore/IO/Path/Path.h>
- #include <AzCore/Serialization/Json/JsonSerializationSettings.h>
- #include <AzCore/Settings/SettingsRegistryMergeUtils.h>
- #include <AzCore/UnitTest/TestTypes.h>
- #include <AzCore/UnitTest/Mocks/MockFileIOBase.h>
- #include <AzCore/UnitTest/Mocks/MockSettingsRegistry.h>
- #include <AzCore/UserSettings/UserSettingsComponent.h>
- #include <AzFramework/StringFunc/StringFunc.h>
- #include <AzToolsFramework/Application/ToolsApplication.h>
- #include <SceneAPI/SceneCore/Events/AssetImportRequest.h>
- #include <SceneBuilder/SceneBuilderWorker.h>
- #include <SceneAPI/SceneCore/Events/ExportProductList.h>
- #include <Tests/FileIOBaseTestTypes.h>
- using namespace AZ;
- using namespace SceneBuilder;
- class SceneBuilderTests
- : public UnitTest::LeakDetectionFixture
- , public UnitTest::TraceBusRedirector
- {
- protected:
- void SetUp() override
- {
- 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::StartupParameters startupParameters;
- startupParameters.m_loadSettingsRegistry = false;
- m_app.Start(AZ::ComponentApplication::Descriptor(), startupParameters);
- AZ::Debug::TraceMessageBus::Handler::BusConnect();
- // 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);
- m_workingDirectory = m_app.GetExecutableFolder();
- AZ::IO::FileIOBase::GetInstance()->SetAlias("@products@", m_workingDirectory);
- }
- void TearDown() override
- {
- AZ::Debug::TraceMessageBus::Handler::BusDisconnect();
- m_app.Stop();
- }
- void TestSuccessCase(const SceneAPI::Events::ExportProduct& exportProduct,
- const AssetBuilderSDK::ProductPathDependencySet& expectedPathDependencies,
- const AZStd::vector<AZ::Uuid>& expectedProductDependencies)
- {
- SceneBuilderWorker worker;
- AssetBuilderSDK::JobProduct jobProduct(exportProduct.m_filename, exportProduct.m_assetType, 0);
- worker.PopulateProductDependencies(exportProduct, m_workingDirectory, jobProduct);
- ASSERT_EQ(expectedPathDependencies.size(), jobProduct.m_pathDependencies.size());
- if (expectedPathDependencies.size() > 0)
- {
- for (const AssetBuilderSDK::ProductPathDependency& dependency : expectedPathDependencies)
- {
- ASSERT_TRUE(jobProduct.m_pathDependencies.find(dependency) != jobProduct.m_pathDependencies.end());
- }
- }
- ASSERT_EQ(expectedProductDependencies.size(), jobProduct.m_dependencies.size());
- if (expectedProductDependencies.size() > 0)
- {
- for (const AssetBuilderSDK::ProductDependency& dependency : jobProduct.m_dependencies)
- {
- ASSERT_TRUE(AZStd::find(expectedProductDependencies.begin(), expectedProductDependencies.end(), dependency.m_dependencyId.m_guid) != expectedProductDependencies.end());
- }
- }
- }
- void TestSuccessCase(const SceneAPI::Events::ExportProduct& exportProduct,
- const AssetBuilderSDK::ProductPathDependency* expectedPathDependency = nullptr,
- const AZ::Uuid* expectedProductDependency = nullptr)
- {
- AssetBuilderSDK::ProductPathDependencySet expectedPathDependencies;
- if (expectedPathDependency)
- {
- expectedPathDependencies.emplace(*expectedPathDependency);
- }
- AZStd::vector<AZ::Uuid> expectedProductDependencies;
- if (expectedProductDependency)
- {
- expectedProductDependencies.push_back(*expectedProductDependency);
- }
- TestSuccessCase(exportProduct, expectedPathDependencies, expectedProductDependencies);
- }
- void TestSuccessCaseNoDependencies(const SceneAPI::Events::ExportProduct& exportProduct)
- {
- AssetBuilderSDK::ProductPathDependencySet expectedPathDependencies;
- AZStd::vector<AZ::Uuid> expectedProductDependencies;
- TestSuccessCase(exportProduct, expectedPathDependencies, expectedProductDependencies);
- }
- AzToolsFramework::ToolsApplication m_app;
- const char* m_workingDirectory = nullptr;
- };
- TEST_F(SceneBuilderTests, SceneBuilderWorker_ExportProductDependencies_NoDependencies)
- {
- SceneAPI::Events::ExportProduct exportProduct("testExportFile", AZ::Uuid::CreateRandom(), AZ::Data::AssetType::CreateNull(), u8(0), AZStd::nullopt);
- TestSuccessCaseNoDependencies(exportProduct);
- }
- TEST_F(SceneBuilderTests, SceneBuilderWorker_ExportProductDependencies_PathDependencyOnSourceAsset)
- {
- #if AZ_TRAIT_OS_USE_WINDOWS_FILE_PATHS
- const char* absolutePathToFile = "C:/some/test/file.mtl";
- #else
- const char* absolutePathToFile = "/some/test/file.mtl";
- #endif // AZ_TRAIT_OS_USE_WINDOWS_FILE_PATHS
- AssetBuilderSDK::ProductPathDependency expectedPathDependency(absolutePathToFile, AssetBuilderSDK::ProductPathDependencyType::SourceFile);
- SceneAPI::Events::ExportProduct product("testExportFile", AZ::Uuid::CreateRandom(), AZ::Data::AssetType::CreateNull(), u8(0), AZStd::nullopt);
- product.m_legacyPathDependencies.push_back(absolutePathToFile);
- TestSuccessCase(product, &expectedPathDependency);
- }
- TEST_F(SceneBuilderTests, SceneBuilderWorker_ExportProductDependencies_PathDependencyOnProductAsset)
- {
- const char* relativeDependencyPathToFile = "some/test/file.mtl";
- AssetBuilderSDK::ProductPathDependency expectedPathDependency(relativeDependencyPathToFile, AssetBuilderSDK::ProductPathDependencyType::ProductFile);
- SceneAPI::Events::ExportProduct product("testExportFile", AZ::Uuid::CreateRandom(), AZ::Data::AssetType::CreateNull(), u8(0), AZStd::nullopt);
- product.m_legacyPathDependencies.push_back(relativeDependencyPathToFile);
- TestSuccessCase(product, &expectedPathDependency);
- }
- TEST_F(SceneBuilderTests, SceneBuilderWorker_ExportProductDependencies_PathDependencyOnSourceAndProductAsset)
- {
- const char* relativeDependencyPathToFile = "some/test/file.mtl";
- #if AZ_TRAIT_OS_USE_WINDOWS_FILE_PATHS
- const char* absolutePathToFile = "C:/some/test/file.mtl";
- #else
- const char* absolutePathToFile = "/some/test/file.mtl";
- #endif // AZ_TRAIT_OS_USE_WINDOWS_FILE_PATHS
- SceneAPI::Events::ExportProduct exportProduct("testExportFile", AZ::Uuid::CreateRandom(), AZ::Data::AssetType::CreateNull(), u8(0), AZStd::nullopt);
- exportProduct.m_legacyPathDependencies.push_back(absolutePathToFile);
- exportProduct.m_legacyPathDependencies.push_back(relativeDependencyPathToFile);
- AssetBuilderSDK::ProductPathDependencySet expectedPathDependencies = {
- {absolutePathToFile, AssetBuilderSDK::ProductPathDependencyType::SourceFile},
- {relativeDependencyPathToFile, AssetBuilderSDK::ProductPathDependencyType::ProductFile}
- };
- TestSuccessCase(exportProduct, expectedPathDependencies, {});
- }
- TEST_F(SceneBuilderTests, SceneBuilderWorker_ExportProductDependencies_ProductDependency)
- {
- AZ::Uuid dependencyId = AZ::Uuid::CreateRandom();
- SceneAPI::Events::ExportProduct exportProduct("testExportFile", AZ::Uuid::CreateRandom(), AZ::Data::AssetType::CreateNull(), AZ::u8(0), AZStd::nullopt);
- exportProduct.m_productDependencies.push_back(SceneAPI::Events::ExportProduct("testDependencyFile", dependencyId, AZ::Data::AssetType::CreateNull(), AZ::u8(0), AZStd::nullopt));
- TestSuccessCase(exportProduct, nullptr, &dependencyId);
- }
- TEST_F(SceneBuilderTests, SceneBuilderWorker_ExportProductDependencies_ProductAndPathDependencies)
- {
- AZ::Uuid dependencyId = AZ::Uuid::CreateRandom();
- SceneAPI::Events::ExportProduct exportProduct("testExportFile", AZ::Uuid::CreateRandom(), AZ::Data::AssetType::CreateNull(), AZ::u8(0), AZStd::nullopt);
- exportProduct.m_productDependencies.push_back(SceneAPI::Events::ExportProduct("testDependencyFile", dependencyId, AZ::Data::AssetType::CreateNull(), AZ::u8(0), AZStd::nullopt));
- const char* relativeDependencyPathToFile = "some/test/file.mtl";
- #if AZ_TRAIT_OS_USE_WINDOWS_FILE_PATHS
- const char* absolutePathToFile = "C:/some/test/file.mtl";
- #else
- const char* absolutePathToFile = "/some/test/file.mtl";
- #endif // AZ_TRAIT_OS_USE_WINDOWS_FILE_PATHS
- exportProduct.m_legacyPathDependencies.push_back(absolutePathToFile);
- exportProduct.m_legacyPathDependencies.push_back(relativeDependencyPathToFile);
- AssetBuilderSDK::ProductPathDependencySet expectedPathDependencies = {
- {absolutePathToFile, AssetBuilderSDK::ProductPathDependencyType::SourceFile},
- {relativeDependencyPathToFile, AssetBuilderSDK::ProductPathDependencyType::ProductFile}
- };
- TestSuccessCase(exportProduct, expectedPathDependencies, { dependencyId });
- }
- struct ImportHandler
- : SceneAPI::Events::AssetImportRequestBus::Handler
- {
- ImportHandler()
- {
- BusConnect();
- }
- ~ImportHandler() override
- {
- BusDisconnect();
- }
- void GetManifestDependencyPaths(AZStd::vector<AZStd::string>& paths) override
- {
- paths.emplace_back("/scriptFilename");
- paths.emplace_back("/layer1/layer2/0/target");
- }
- void GetManifestExtension(AZStd::string& result) override
- {
- result = ".test";
- }
- void GetGeneratedManifestExtension(AZStd::string& result) override
- {
- result = ".test.gen";
- }
- };
- using SourceDependencyTests = UnitTest::LeakDetectionFixture;
- namespace SourceDependencyJson
- {
- constexpr const char* TestJson = R"JSON(
- {
- "values": [
- {
- "$type": "Test1",
- "scriptFilename": "a/test/path.png"
- },
- {
- "$type": "Test2",
- "layer1" : {
- "layer2" : [
- {
- "target": "value.png",
- "otherData": "value2.png"
- },
- {
- "target" : "wrong.png"
- }
- ]
- }
- }
- ]
- }
- )JSON";
- }
- TEST_F(SourceDependencyTests, SourceDependencyTest)
- {
- ImportHandler handler;
- AZStd::vector<AssetBuilderSDK::SourceFileDependency> dependencies;
- SceneBuilderWorker::PopulateSourceDependencies(SourceDependencyJson::TestJson, dependencies);
- ASSERT_EQ(dependencies.size(), 2);
- ASSERT_STREQ(dependencies[0].m_sourceFileDependencyPath.c_str(), "a/test/path.png");
- ASSERT_STREQ(dependencies[1].m_sourceFileDependencyPath.c_str(), "value.png");
- }
- TEST_F(SourceDependencyTests, PopulateSourceDependencies_WithEmptyManifest_ShouldFailWithNoException)
- {
- ImportHandler handler;
- AZStd::vector<AssetBuilderSDK::SourceFileDependency> dependencies;
- SceneBuilderWorker::PopulateSourceDependencies("{}", dependencies);
- ASSERT_EQ(dependencies.size(), 0);
- }
- struct SourceDependencyMockedIOTests : UnitTest::LeakDetectionFixture
- , UnitTest::SetRestoreFileIOBaseRAII
- {
- SourceDependencyMockedIOTests()
- : UnitTest::SetRestoreFileIOBaseRAII(m_ioMock)
- {
-
- }
- void SetUp() override
- {
- using namespace ::testing;
- ON_CALL(m_ioMock, Open(_, _, _))
- .WillByDefault(Invoke(
- [](auto, auto, IO::HandleType& handle)
- {
- handle = 1234;
- return AZ::IO::Result(AZ::IO::ResultCode::Success);
- }));
- ON_CALL(m_ioMock, Size(An<AZ::IO::HandleType>(), _)).WillByDefault(Invoke([](auto, AZ::u64& size)
- {
- size = strlen(SourceDependencyJson::TestJson);
- return AZ::IO::ResultCode::Success;
- }));
- EXPECT_CALL(m_ioMock, Read(_, _, _, _, _))
- .WillRepeatedly(Invoke(
- [](auto, void* buffer, auto, auto, AZ::u64* bytesRead)
- {
- memcpy(buffer, SourceDependencyJson::TestJson, strlen(SourceDependencyJson::TestJson));
- *bytesRead = strlen(SourceDependencyJson::TestJson);
- return AZ::IO::ResultCode::Success;
- }));
- EXPECT_CALL(m_ioMock, Close(_)).WillRepeatedly(Return(AZ::IO::ResultCode::Success));
- }
- IO::NiceFileIOBaseMock m_ioMock;
- };
- TEST_F(SourceDependencyMockedIOTests, RegularManifestHasPriority)
- {
- ImportHandler handler;
- MockSettingsRegistry settingsRegistry;
- SettingsRegistry::Register(&settingsRegistry);
- using FixedValueString = AZ::SettingsRegistryInterface::FixedValueString;
- auto MockGetFixedStringCall = [](FixedValueString& result, AZStd::string_view) -> bool
- {
- result = "cache";
- return true;
- };
- ON_CALL(settingsRegistry, Get(::testing::An<FixedValueString&>(), ::testing::_)).WillByDefault(MockGetFixedStringCall);
- AssetBuilderSDK::CreateJobsRequest request;
- AssetBuilderSDK::CreateJobsResponse response;
- request.m_sourceFile = "file.fbx";
- using namespace ::testing;
- AZStd::string genPath = AZStd::string("cache").append(1, AZ_TRAIT_OS_PATH_SEPARATOR).append("file.fbx.test.gen");
- EXPECT_CALL(m_ioMock, Exists(StrEq("file.fbx.test"))).WillRepeatedly(Return(true));
- EXPECT_CALL(m_ioMock, Exists(StrEq(genPath.c_str()))).Times(Exactly(0));
- EXPECT_CALL(settingsRegistry, Get(::testing::An<FixedValueString&>(), ::testing::_)).Times(1);
-
- ASSERT_TRUE(SceneBuilderWorker::ManifestDependencyCheck(request, response));
- ASSERT_EQ(response.m_sourceFileDependencyList.size(), 2);
- SettingsRegistry::Unregister(&settingsRegistry);
- }
- TEST_F(SourceDependencyMockedIOTests, GeneratedManifestTest)
- {
- ImportHandler handler;
- MockSettingsRegistry settingsRegistry;
- SettingsRegistry::Register(&settingsRegistry);
- using FixedValueString = AZ::SettingsRegistryInterface::FixedValueString;
- auto MockGetFixedStringCall = [](FixedValueString& result, AZStd::string_view) -> bool
- {
- result = "cache";
- return true;
- };
- ON_CALL(settingsRegistry, Get(::testing::An<FixedValueString&>(), ::testing::_)).WillByDefault(MockGetFixedStringCall);
- AssetBuilderSDK::CreateJobsRequest request;
- AssetBuilderSDK::CreateJobsResponse response;
- request.m_sourceFile = "file.fbx";
- using namespace ::testing;
- AZStd::string genPath = AZStd::string("cache").append(1, AZ_TRAIT_OS_PATH_SEPARATOR).append("file.fbx.test.gen");
- EXPECT_CALL(m_ioMock, Exists(StrEq("file.fbx.test"))).WillRepeatedly(Return(false));
- EXPECT_CALL(m_ioMock, Exists(StrEq(genPath.c_str()))).WillRepeatedly(Return(true));
- EXPECT_CALL(settingsRegistry, Get(::testing::An<FixedValueString&>(), ::testing::_)).Times(1);
- ASSERT_TRUE(SceneBuilderWorker::ManifestDependencyCheck(request, response));
- ASSERT_EQ(response.m_sourceFileDependencyList.size(), 2);
- SettingsRegistry::Unregister(&settingsRegistry);
- }
|