3
0

tests_main.cpp 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311
  1. /*
  2. * Copyright (c) Contributors to the Open 3D Engine Project.
  3. * For complete copyright and license terms please see the LICENSE at the root of this distribution.
  4. *
  5. * SPDX-License-Identifier: Apache-2.0 OR MIT
  6. *
  7. */
  8. #include <AzFramework/API/ApplicationAPI.h>
  9. #include <AzFramework/FileFunc/FileFunc.h>
  10. #include <AzFramework/IO/LocalFileIO.h>
  11. #include <AzToolsFramework/Application/ToolsApplication.h>
  12. #include <AzToolsFramework/Asset/AssetBundler.h>
  13. #include <AzFramework/Platform/PlatformDefaults.h>
  14. #include <source/utils/utils.h>
  15. #include <AzCore/IO/Path/Path.h>
  16. #include <AzCore/std/smart_ptr/make_shared.h>
  17. #include <AzCore/UnitTest/TestTypes.h>
  18. #include <AzCore/Settings/SettingsRegistryImpl.h>
  19. #include <AzCore/Settings/SettingsRegistryMergeUtils.h>
  20. #include <AzCore/UserSettings/UserSettingsComponent.h>
  21. #include <tests/main.h>
  22. #include <source/utils/applicationManager.h>
  23. #include <QApplication>
  24. extern char g_cachedEngineRoot[AZ_MAX_PATH_LEN];
  25. namespace AssetBundler
  26. {
  27. class AssetBundlerBatchUtilsTest
  28. : public UnitTest::LeakDetectionFixture
  29. {
  30. };
  31. TEST_F(AssetBundlerBatchUtilsTest, SplitFilename_MacFile_OutputBaseNameAndPlatform)
  32. {
  33. AZStd::string filePath = "assetInfoFile_mac.xml";
  34. AZStd::string baseFilename;
  35. AZStd::string platformIdentifier;
  36. AzToolsFramework::SplitFilename(filePath, baseFilename, platformIdentifier);
  37. ASSERT_EQ(baseFilename, "assetInfoFile");
  38. ASSERT_EQ(platformIdentifier, "mac");
  39. }
  40. TEST_F(AssetBundlerBatchUtilsTest, SplitFilename_PcFile_OutputBaseNameAndPlatform)
  41. {
  42. AZStd::string filePath = "assetInfoFile_pc.xml";
  43. AZStd::string baseFilename;
  44. AZStd::string platformIdentifier;
  45. AzToolsFramework::SplitFilename(filePath, baseFilename, platformIdentifier);
  46. ASSERT_EQ(baseFilename, "assetInfoFile");
  47. ASSERT_EQ(platformIdentifier, "pc");
  48. }
  49. TEST_F(AssetBundlerBatchUtilsTest, SplitFilename_MacFileWithUnderScoreInFileName_OutputBaseNameAndPlatform)
  50. {
  51. AZStd::string filePath = "assetInfoFile_test_mac.xml";
  52. AZStd::string baseFilename;
  53. AZStd::string platformIdentifier;
  54. AzToolsFramework::SplitFilename(filePath, baseFilename, platformIdentifier);
  55. ASSERT_EQ(baseFilename, "assetInfoFile_test");
  56. ASSERT_EQ(platformIdentifier, "mac");
  57. }
  58. TEST_F(AssetBundlerBatchUtilsTest, SplitFilename_PcFileWithUnderScoreInFileName_OutputBaseNameAndPlatform)
  59. {
  60. AZStd::string filePath = "assetInfoFile_test_pc.xml";
  61. AZStd::string baseFilename;
  62. AZStd::string platformIdentifier;
  63. AzToolsFramework::SplitFilename(filePath, baseFilename, platformIdentifier);
  64. ASSERT_EQ(baseFilename, "assetInfoFile_test");
  65. ASSERT_EQ(platformIdentifier, "pc");
  66. }
  67. const char RelativeTestFolder[] = "AssetBundler.Tests.dir";
  68. const char GemsFolder[] = "Gems";
  69. constexpr auto EngineFolder = AZ::IO::FixedMaxPath("Assets") / "Engine";
  70. const char PlatformsFolder[] = "Platforms";
  71. const char DummyProjectFolder[] = "DummyProject";
  72. class AssetBundlerGemsUtilTest
  73. : public UnitTest::LeakDetectionFixture
  74. {
  75. public:
  76. void SetUp() override
  77. {
  78. AZ::SettingsRegistryInterface* registry = nullptr;
  79. if (!AZ::SettingsRegistry::Get())
  80. {
  81. AZ::SettingsRegistry::Register(&m_registry);
  82. registry = &m_registry;
  83. }
  84. else
  85. {
  86. registry = AZ::SettingsRegistry::Get();
  87. }
  88. auto projectPathKey = AZ::SettingsRegistryInterface::FixedValueString(AZ::SettingsRegistryMergeUtils::BootstrapSettingsRootKey)
  89. + "/project_path";
  90. AZ::IO::FixedMaxPath enginePath = AZ::SettingsRegistryMergeUtils::FindEngineRoot(*registry);
  91. registry->Set(projectPathKey, (enginePath / "AutomatedTesting").Native());
  92. AZ::SettingsRegistryMergeUtils::MergeSettingsToRegistry_AddRuntimeFilePaths(*registry);
  93. AZ::IO::FixedMaxPath executableDirectory = AZ::Utils::GetExecutableDirectory();
  94. if (executableDirectory.empty())
  95. {
  96. GTEST_FATAL_FAILURE_(AZStd::string::format("Unable to locate executable.\n").c_str());
  97. }
  98. m_data = AZStd::make_unique<StaticData>();
  99. m_data->m_application.reset(aznew AzToolsFramework::ToolsApplication());
  100. m_data->m_application.get()->Start(AzFramework::Application::Descriptor());
  101. // Without this, the user settings component would attempt to save on finalize/shutdown. Since the file is
  102. // shared across the whole engine, if multiple tests are run in parallel, the saving could cause a crash
  103. // in the unit tests.
  104. AZ::UserSettingsComponentRequestBus::Broadcast(&AZ::UserSettingsComponentRequests::DisableSaveOnFinalize);
  105. // Set the test engine root to be the executable directory
  106. m_data->m_testEngineRoot = (executableDirectory / RelativeTestFolder).LexicallyNormal().String();
  107. m_data->m_localFileIO = aznew AZ::IO::LocalFileIO();
  108. m_data->m_priorFileIO = AZ::IO::FileIOBase::GetInstance();
  109. // we need to set it to nullptr first because otherwise the
  110. // underneath code assumes that we might be leaking the previous instance
  111. AZ::IO::FileIOBase::SetInstance(nullptr);
  112. AZ::IO::FileIOBase::SetInstance(m_data->m_localFileIO);
  113. AddGemData(m_data->m_testEngineRoot.c_str(), "GemA");
  114. AddGemData(m_data->m_testEngineRoot.c_str(), "GemB");
  115. auto absoluteEngineSeedFilePath = m_data->m_testEngineRoot / EngineFolder / "SeedAssetList";
  116. absoluteEngineSeedFilePath.ReplaceExtension(AzToolsFramework::AssetSeedManager::GetSeedFileExtension());
  117. m_data->m_gemSeedFilePairList.push_back({ absoluteEngineSeedFilePath.Native(), true});
  118. AddGemData(m_data->m_testEngineRoot.c_str(), "GemC", false);
  119. auto absoluteProjectJsonSeedFilePath = AZ::IO::Path(m_data->m_testEngineRoot) / DummyProjectFolder / "SeedAssetList";
  120. absoluteProjectJsonSeedFilePath.ReplaceExtension(AzToolsFramework::AssetSeedManager::GetSeedFileExtension());
  121. m_data->m_gemSeedFilePairList.push_back({ absoluteProjectJsonSeedFilePath.Native(), true });
  122. // Add an explicit ObjectStream format XML seed file to validate that it loads successfully
  123. auto absoluteProjectObjectStreamSeedFilePath = AZ::IO::Path(m_data->m_testEngineRoot) / DummyProjectFolder / "SeedAssetListObjectStreamXML";
  124. absoluteProjectObjectStreamSeedFilePath.ReplaceExtension(AzToolsFramework::AssetSeedManager::GetSeedFileExtension());
  125. m_data->m_gemSeedFilePairList.push_back({ absoluteProjectObjectStreamSeedFilePath.Native(), true });
  126. }
  127. void TearDown() override
  128. {
  129. if (m_data)
  130. {
  131. AZ::IO::FileIOBase::SetInstance(nullptr);
  132. delete m_data->m_localFileIO;
  133. AZ::IO::FileIOBase::SetInstance(m_data->m_priorFileIO);
  134. m_data->m_gemInfoList.set_capacity(0);
  135. m_data->m_gemSeedFilePairList.set_capacity(0);
  136. m_data->m_application.get()->Stop();
  137. m_data->m_application.reset();
  138. }
  139. if(auto settingsRegistry = AZ::SettingsRegistry::Get();
  140. settingsRegistry == &m_registry)
  141. {
  142. AZ::SettingsRegistry::Unregister(settingsRegistry);
  143. }
  144. }
  145. void AddGemData(const char* engineRoot, const char* gemName, bool seedFileExists = true)
  146. {
  147. AZ::IO::Path relativeGemPath{ GemsFolder };
  148. relativeGemPath /= gemName;
  149. AZ::IO::Path absoluteGemPath{ engineRoot };
  150. absoluteGemPath /= relativeGemPath;
  151. AZ::IO::Path absoluteGemSeedFilePath = absoluteGemPath;
  152. absoluteGemSeedFilePath /= "Assets/seedList";
  153. absoluteGemSeedFilePath.ReplaceExtension(AZ::IO::PathView{ AzToolsFramework::AssetSeedManager::GetSeedFileExtension() });
  154. absoluteGemSeedFilePath = absoluteGemSeedFilePath.LexicallyNormal();
  155. m_data->m_gemSeedFilePairList.emplace_back(absoluteGemSeedFilePath, seedFileExists);
  156. m_data->m_gemInfoList.emplace_back(gemName);
  157. m_data->m_gemInfoList.back().m_absoluteSourcePaths.push_back(absoluteGemPath.Native());
  158. AZ::IO::Path platformsDirectory = absoluteGemPath / "Assets" / PlatformsFolder;
  159. if (m_data->m_localFileIO->Exists(platformsDirectory.c_str()))
  160. {
  161. m_data->m_localFileIO->FindFiles(platformsDirectory.c_str(),
  162. AZStd::string::format("*.%s", AzToolsFramework::AssetSeedManager::GetSeedFileExtension()).c_str(),
  163. [&](const char* fileName)
  164. {
  165. m_data->m_gemSeedFilePairList.push_back({ AZ::IO::PathView(fileName).LexicallyNormal().String(), seedFileExists });
  166. return true;
  167. });
  168. }
  169. AZ::IO::Path iosDirectory = platformsDirectory / AzFramework::PlatformIOS;
  170. if (m_data->m_localFileIO->Exists(iosDirectory.c_str()))
  171. {
  172. bool recurse = true;
  173. AZ::Outcome<AZStd::list<AZStd::string>, AZStd::string> result = AzFramework::FileFunc::FindFileList(iosDirectory.Native(),
  174. AZStd::string::format("*.%s", AzToolsFramework::AssetSeedManager::GetSeedFileExtension()).c_str(), recurse);
  175. if (result.IsSuccess())
  176. {
  177. AZStd::list<AZStd::string> seedFiles = result.TakeValue();
  178. for (AZStd::string& seedFile : seedFiles)
  179. {
  180. m_data->m_gemSeedFilePairList.push_back({ AZ::IO::PathView(seedFile).LexicallyNormal().String(), seedFileExists });
  181. }
  182. }
  183. }
  184. }
  185. struct StaticData
  186. {
  187. AZStd::vector<AzFramework::GemInfo> m_gemInfoList;
  188. AZStd::vector<AZStd::pair<AZStd::string, bool>> m_gemSeedFilePairList;
  189. AZStd::unique_ptr<AzToolsFramework::ToolsApplication> m_application = {};
  190. AZ::IO::FileIOBase* m_priorFileIO = nullptr;
  191. AZ::IO::FileIOBase* m_localFileIO = nullptr;
  192. AZ::IO::Path m_testEngineRoot;
  193. };
  194. const int GemAIndex = 0;
  195. const int GemBIndex = 1;
  196. const int GemBSharedFileIndex = 2;
  197. const int GemBIosFileIndex = 3;
  198. const int EngineIndex = 4;
  199. const int GemCIndex = 5;
  200. const int ProjectIndex = 6;
  201. AZStd::unique_ptr<StaticData> m_data;
  202. AZ::SettingsRegistryImpl m_registry;
  203. };
  204. TEST_F(AssetBundlerGemsUtilTest, GetDefaultSeedFiles_AllSeedFiles_Found)
  205. {
  206. // DummyProject and fake Engine/Gem structure lives at dev/Code/Tools/AssetBundler/tests/
  207. auto dummyProjectPath = AZ::IO::Path(m_data->m_testEngineRoot) / DummyProjectFolder;
  208. auto defaultSeedList = AssetBundler::GetDefaultSeedListFiles(m_data->m_testEngineRoot.Native(), dummyProjectPath.Native(), m_data->m_gemInfoList, AzFramework::PlatformFlags::Platform_PC);
  209. ASSERT_EQ(defaultSeedList.size(), 5); //adding one for the engine seed file and one for the project file
  210. // Validate whether both GemA and GemB seed file are present
  211. EXPECT_NE(defaultSeedList.find(m_data->m_gemSeedFilePairList[GemAIndex].first), defaultSeedList.end());
  212. EXPECT_NE(defaultSeedList.find(m_data->m_gemSeedFilePairList[GemBIndex].first), defaultSeedList.end());
  213. EXPECT_NE(defaultSeedList.find(m_data->m_gemSeedFilePairList[GemBSharedFileIndex].first), defaultSeedList.end());
  214. // Validate that the engine seed file is present
  215. EXPECT_NE(defaultSeedList.find(m_data->m_gemSeedFilePairList[EngineIndex].first), defaultSeedList.end());
  216. EXPECT_NE(defaultSeedList.find(m_data->m_gemSeedFilePairList[ProjectIndex].first), defaultSeedList.end());
  217. }
  218. TEST_F(AssetBundlerGemsUtilTest, GetDefaultSeedFilesForMultiplePlatforms_AllSeedFiles_Found)
  219. {
  220. // DummyProject and fake Engine/Gem structure lives at dev/Code/Tools/AssetBundler/tests/
  221. auto dummyProjectPath = AZ::IO::Path(m_data->m_testEngineRoot) / DummyProjectFolder;
  222. auto defaultSeedList = AssetBundler::GetDefaultSeedListFiles(m_data->m_testEngineRoot.Native(), dummyProjectPath.Native(), m_data->m_gemInfoList, AzFramework::PlatformFlags::Platform_PC | AzFramework::PlatformFlags::Platform_IOS);
  223. ASSERT_EQ(defaultSeedList.size(), 6); //adding one for the engine seed file and one for the project file
  224. // Validate whether both GemA and GemB seed file are present
  225. EXPECT_NE(defaultSeedList.find(m_data->m_gemSeedFilePairList[GemAIndex].first), defaultSeedList.end());
  226. EXPECT_NE(defaultSeedList.find(m_data->m_gemSeedFilePairList[GemBIndex].first), defaultSeedList.end());
  227. EXPECT_NE(defaultSeedList.find(m_data->m_gemSeedFilePairList[GemBSharedFileIndex].first), defaultSeedList.end());
  228. EXPECT_NE(defaultSeedList.find(m_data->m_gemSeedFilePairList[GemBIosFileIndex].first), defaultSeedList.end());
  229. // Validate that the engine seed file is present
  230. EXPECT_NE(defaultSeedList.find(m_data->m_gemSeedFilePairList[EngineIndex].first), defaultSeedList.end());
  231. EXPECT_NE(defaultSeedList.find(m_data->m_gemSeedFilePairList[ProjectIndex].first), defaultSeedList.end());
  232. }
  233. TEST_F(AssetBundlerGemsUtilTest, IsSeedFileValid_Ok)
  234. {
  235. for (const auto& pair : m_data->m_gemSeedFilePairList)
  236. {
  237. bool result = IsGemSeedFilePathValid(m_data->m_testEngineRoot.c_str(), pair.first, m_data->m_gemInfoList, AzFramework::PlatformFlags::Platform_PC | AzFramework::PlatformFlags::Platform_IOS);
  238. EXPECT_EQ(result, pair.second);
  239. }
  240. }
  241. }
  242. int main(int argc, char* argv[])
  243. {
  244. AZ::Debug::Trace::HandleExceptions(true);
  245. QApplication app(argc, argv);
  246. AZ::Test::ApplyGlobalParameters(&argc, argv);
  247. INVOKE_AZ_UNIT_TEST_MAIN();
  248. int runSuccess = 0;
  249. {
  250. AssetBundler::ApplicationManager applicationManger(&argc, &argv);
  251. applicationManger.Init();
  252. runSuccess = applicationManger.Run() ? 0 : 1;
  253. }
  254. return runSuccess;
  255. }