AssetScannerUnitTests.cpp 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153
  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 "AssetScannerUnitTests.h"
  9. #include <AzCore/std/chrono/chrono.h>
  10. #include <AzTest/Utils.h>
  11. #include <native/AssetManager/assetScanner.h>
  12. #include <native/utilities/PlatformConfiguration.h>
  13. #include <native/unittests/UnitTestUtils.h> // for CreateDummyFile
  14. #include <QApplication>
  15. #include <QElapsedTimer>
  16. #include <QTemporaryDir>
  17. namespace UnitTest
  18. {
  19. TEST_F(AssetScannerUnitTest, AssetScanner_ScanMultipleFolders_ExpectedFilesAndFoldersFound)
  20. {
  21. using namespace AssetProcessor;
  22. AZStd::unique_ptr<QCoreApplication> m_qApp;
  23. // Qt documentation claims QCoreApplication's constructor requires a greater than zero argC
  24. // and a valid argV, however the version of Qt in use works fine with 0 and nullptr.
  25. int argC = 0;
  26. m_qApp.reset(new QApplication(argC, nullptr));
  27. qRegisterMetaType<AssetProcessor::AssetScanningStatus>("AssetScanningStatus");
  28. qRegisterMetaType<QSet<AssetProcessor::AssetFileInfo>>("QSet<AssetFileInfo>");
  29. AZ::Test::ScopedAutoTempDirectory tempEngineRoot;
  30. AZStd::set<AZ::IO::Path> expectedFiles;
  31. // set up some interesting files:
  32. expectedFiles.insert(tempEngineRoot.Resolve("rootfile2.txt"));
  33. expectedFiles.insert(tempEngineRoot.Resolve("subfolder1/basefile.txt"));
  34. expectedFiles.insert(tempEngineRoot.Resolve("subfolder2/basefile.txt"));
  35. expectedFiles.insert(tempEngineRoot.Resolve("subfolder2/aaa/basefile.txt"));
  36. expectedFiles.insert(tempEngineRoot.Resolve("subfolder2/aaa/bbb/basefile.txt"));
  37. expectedFiles.insert(tempEngineRoot.Resolve("subfolder2/aaa/bbb/ccc/basefile.txt"));
  38. expectedFiles.insert(tempEngineRoot.Resolve("subfolder2/aaa/bbb/ccc/ddd/basefile.txt"));
  39. expectedFiles.insert(tempEngineRoot.Resolve(
  40. "subfolder2/aaa/bbb/ccc/ddd/eee.fff.ggg/basefile.txt")); // adding a folder name containing dots
  41. expectedFiles.insert(tempEngineRoot.Resolve("subfolder2/aaa/bbb/ccc/ddd/eee.fff.ggg/basefile1.txt"));
  42. expectedFiles.insert(tempEngineRoot.Resolve("subfolder3/basefile.txt"));
  43. expectedFiles.insert(tempEngineRoot.Resolve("subfolder3/aaa/basefile.txt"));
  44. expectedFiles.insert(tempEngineRoot.Resolve("subfolder3/aaa/bbb/basefile.txt"));
  45. expectedFiles.insert(tempEngineRoot.Resolve("subfolder3/aaa/bbb/ccc/basefile.txt"));
  46. expectedFiles.insert(tempEngineRoot.Resolve("rootfile1.txt"));
  47. for (const AZ::IO::Path& expect : expectedFiles)
  48. {
  49. EXPECT_TRUE(UnitTestUtils::CreateDummyFile(expect.c_str()));
  50. }
  51. // but we're going to not watch subfolder3 recursively, so... remove these files (even though they're on disk)
  52. // if this causes a failure it means that its ignoring the "do not recurse" flag:
  53. expectedFiles.erase(tempEngineRoot.Resolve("subfolder3/aaa/basefile.txt"));
  54. expectedFiles.erase(tempEngineRoot.Resolve("subfolder3/aaa/bbb/basefile.txt"));
  55. expectedFiles.erase(tempEngineRoot.Resolve("subfolder3/aaa/bbb/ccc/basefile.txt"));
  56. AZStd::set<AZ::IO::Path> expectedFolders;
  57. expectedFolders.insert(tempEngineRoot.Resolve("subfolder2/aaa"));
  58. expectedFolders.insert(tempEngineRoot.Resolve("subfolder2/aaa/bbb"));
  59. expectedFolders.insert(tempEngineRoot.Resolve("subfolder2/aaa/bbb/ccc"));
  60. expectedFolders.insert(tempEngineRoot.Resolve("subfolder2/aaa/bbb/ccc/ddd"));
  61. expectedFolders.insert(tempEngineRoot.Resolve("subfolder2/aaa/bbb/ccc/ddd/eee.fff.ggg"));
  62. PlatformConfiguration config;
  63. AZStd::vector<AssetBuilderSDK::PlatformInfo> platforms;
  64. config.PopulatePlatformsForScanFolder(platforms);
  65. // PATH, DisplayName, PortKey, outputfolder, root, recurse, platforms
  66. config.AddScanFolder(
  67. ScanFolderInfo(tempEngineRoot.GetDirectory(), "temp", "ap1", true, false, platforms)); // note: "Recurse" set to false.
  68. config.AddScanFolder(ScanFolderInfo(tempEngineRoot.Resolve("subfolder1").c_str(), "", "ap2", false, true, platforms));
  69. config.AddScanFolder(ScanFolderInfo(tempEngineRoot.Resolve("subfolder2").c_str(), "", "ap3", false, true, platforms));
  70. config.AddScanFolder(
  71. ScanFolderInfo(tempEngineRoot.Resolve("subfolder3").c_str(), "", "ap4", false, false, platforms)); // note: "Recurse" set to false.
  72. AssetScanner scanner(&config);
  73. AZStd::list<AssetFileInfo> filesFound;
  74. AZStd::list<AssetFileInfo> foldersFound;
  75. bool doneScan = false;
  76. connect(
  77. &scanner, &AssetScanner::FilesFound, this,
  78. [&filesFound](QSet<AssetFileInfo> fileList)
  79. {
  80. for (AssetFileInfo foundFile : fileList)
  81. {
  82. filesFound.push_back(foundFile);
  83. }
  84. });
  85. connect(
  86. &scanner, &AssetScanner::FoldersFound, this,
  87. [&foldersFound](QSet<AssetFileInfo> folderList)
  88. {
  89. for (AssetFileInfo foundFolder : folderList)
  90. {
  91. foldersFound.push_back(foundFolder);
  92. }
  93. });
  94. connect(
  95. &scanner, &AssetScanner::AssetScanningStatusChanged, this,
  96. [&doneScan](AssetProcessor::AssetScanningStatus status)
  97. {
  98. if ((status == AssetProcessor::AssetScanningStatus::Completed) || (status == AssetProcessor::AssetScanningStatus::Stopped))
  99. {
  100. doneScan = true;
  101. }
  102. });
  103. // this test makes sure that no files that should be missed were actually missed.
  104. // it makes sure that if a folder is added recursively, child files and folders are found
  105. // it makes sure that if a folder is added NON-recursively, child folder files are not found.
  106. scanner.StartScan();
  107. auto startTime = AZStd::chrono::steady_clock::now();
  108. while (!doneScan)
  109. {
  110. QCoreApplication::processEvents(QEventLoop::WaitForMoreEvents, 100);
  111. auto millisecondsSpentScanning =
  112. AZStd::chrono::duration_cast<AZStd::chrono::milliseconds>(AZStd::chrono::steady_clock::now() - startTime);
  113. if (millisecondsSpentScanning > AZStd::chrono::milliseconds(10000))
  114. {
  115. break;
  116. }
  117. }
  118. EXPECT_TRUE(doneScan);
  119. EXPECT_EQ(filesFound.size(), expectedFiles.size());
  120. for (const AssetFileInfo& file : filesFound)
  121. {
  122. EXPECT_NE(expectedFiles.find(file.m_filePath.toUtf8().constData()), expectedFiles.end());
  123. }
  124. for (const AssetFileInfo& folder : foldersFound)
  125. {
  126. EXPECT_NE(expectedFolders.find(folder.m_filePath.toUtf8().constData()), expectedFolders.end());
  127. }
  128. }
  129. }