627012840d
* Fixed the return value of the ConvertToAbsolutePath function Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> * Added the generated cmake_dependencies.*.setreg files to engine.pak (#5073) * Copied the generated cmake_dependencies.*.setreg file to the Cache directory Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> * Removed the platform name from the bootstrap.game.*.setreg Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> * Update how the project related file paths are determined when not supplied. The project-path determination now goes back to only detecting a "project.json" file. It no longer attempts to detect a "Cache" directory The project-cache-path determination now in addition to checking the project_cache_path key searches for a "Cache" directory. The project-path defaults to executable folder if it cannot be detected. The copying of generated executable folder Registry directory contents to the product cache is now removed after the archive step. Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> * Updated the invocation of the AssetProcessor in Jenkins to supply an absolute path to the project. The project-path is no longer treated as relative to the engine root, but instead relative to the current working directory at application startup. Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> * Added constant for the storing the name of Cache directory Fixed typos and grammatical errors in the SettingsRegistryMergeUtils.cpp Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> * Updated UnitTest prepend the EngineRoot path to "AutomatedTesting" when setting the project path. This is needed now that the project-path isn't treated relative to the EngineRoot if it is not absolute. Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> * Fix AssetSeedManagerTest and PlatformAddressedAssetCatalogManagerTest Instead of trying to used the AutomatedTesting directory as the project root, the temp directory created during the test is used as the project root. Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> * Moved the setting of the project cache root folder and project asset platform root folder into the `if (!projectCachePath.empty())` block Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> * Removing the scan up logic for the "Cache" directory. This is no longer needed to locate the project cache path in a Project Game Release Layout. Because the project path defaults to the executable directory if, it is not found, the Cache directory will be set to the "Cache" directory within the executable directory. Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com>
883 lines
41 KiB
C++
883 lines
41 KiB
C++
/*
|
|
* 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 <AzCore/Console/IConsole.h>
|
|
#include <AzCore/UnitTest/TestTypes.h>
|
|
#include <AzCore/UnitTest/UnitTest.h>
|
|
|
|
#include <AzCore/IO/SystemFile.h> // for max path decl
|
|
#include <AzCore/Settings/SettingsRegistryMergeUtils.h>
|
|
#include <AzCore/std/parallel/thread.h>
|
|
#include <AzCore/std/parallel/semaphore.h>
|
|
#include <AzCore/std/functional.h> // for function<> in the find files callback.
|
|
#include <AzCore/UserSettings/UserSettingsComponent.h>
|
|
#include <AzFramework/Application/Application.h>
|
|
#include <AzFramework/IO/LocalFileIO.h>
|
|
#include <AzFramework/Archive/ArchiveFileIO.h>
|
|
#include <AzFramework/Archive/Archive.h>
|
|
#include <AzFramework/Archive/ArchiveVars.h>
|
|
#include <AzFramework/Archive/INestedArchive.h>
|
|
|
|
namespace UnitTest
|
|
{
|
|
class ArchiveTestFixture
|
|
: public ScopedAllocatorSetupFixture
|
|
{
|
|
public:
|
|
// Use an Immediately invoked function to initlaize the m_stackRecordLevels value of the AZ::SystemAllocator::Descriptor class
|
|
ArchiveTestFixture()
|
|
: ScopedAllocatorSetupFixture(
|
|
[]() { AZ::SystemAllocator::Descriptor desc; desc.m_stackRecordLevels = 30; return desc; }()
|
|
)
|
|
, m_application{ AZStd::make_unique<AzFramework::Application>() }
|
|
{
|
|
}
|
|
|
|
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);
|
|
|
|
m_application->Start({});
|
|
// 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);
|
|
}
|
|
|
|
void TearDown() override
|
|
{
|
|
m_application->Stop();
|
|
}
|
|
|
|
protected:
|
|
bool IsPackValid(const char* path)
|
|
{
|
|
AZ::IO::IArchive* archive = AZ::Interface<AZ::IO::IArchive>::Get();
|
|
if (!archive)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
return archive->OpenPack(path) && archive->ClosePack(path);
|
|
}
|
|
|
|
template <class Function>
|
|
void RunConcurrentUnitTest(AZ::u32 numIterations, AZ::u32 numThreads, Function testFunction)
|
|
{
|
|
AZStd::atomic_int successCount{};
|
|
constexpr size_t maxTestThreads = 16;
|
|
|
|
for (AZ::u32 testIteration = 0; testIteration < numIterations; ++testIteration)
|
|
{
|
|
AZStd::fixed_vector<AZStd::thread, maxTestThreads> testThreads;
|
|
successCount = 0;
|
|
|
|
for (AZ::u32 threadIdx = 0; threadIdx < numThreads; ++threadIdx)
|
|
{
|
|
auto threadFunctor = [&testFunction, &successCount]()
|
|
{
|
|
// Add some variability to thread timing by yielding each thread
|
|
AZStd::this_thread::yield();
|
|
|
|
if (testFunction())
|
|
{
|
|
++successCount;
|
|
}
|
|
};
|
|
testThreads.emplace_back(threadFunctor);
|
|
}
|
|
|
|
for (AZStd::thread& testThread : testThreads)
|
|
{
|
|
testThread.join();
|
|
}
|
|
|
|
EXPECT_EQ(numThreads, successCount);
|
|
}
|
|
}
|
|
|
|
void TestFGetCachedFileData(const char* testFilePath, size_t dataLen, const char* testData)
|
|
{
|
|
AZ::IO::IArchive* archive = AZ::Interface<AZ::IO::IArchive>::Get();
|
|
ASSERT_NE(nullptr, archive);
|
|
|
|
constexpr uint32_t numThreadedIterations = 1;
|
|
constexpr uint32_t numTestThreads = 5;
|
|
|
|
{
|
|
// Canary tests first
|
|
AZ::IO::HandleType fileHandle = archive->FOpen(testFilePath, "rb");
|
|
|
|
ASSERT_NE(AZ::IO::InvalidHandle, fileHandle);
|
|
|
|
size_t fileSize = 0;
|
|
char* pFileBuffer = (char*)archive->FGetCachedFileData(fileHandle, fileSize);
|
|
ASSERT_NE(nullptr, pFileBuffer);
|
|
EXPECT_EQ(dataLen, fileSize);
|
|
EXPECT_EQ(0, memcmp(pFileBuffer, testData, dataLen));
|
|
|
|
// 2nd call to FGetCachedFileData, same file handle
|
|
fileSize = 0;
|
|
char* pFileBuffer2 = (char*)archive->FGetCachedFileData(fileHandle, fileSize);
|
|
EXPECT_NE(nullptr, pFileBuffer2);
|
|
EXPECT_EQ(pFileBuffer, pFileBuffer2);
|
|
EXPECT_EQ(dataLen, fileSize);
|
|
|
|
// open already open file and call FGetCachedFileData
|
|
fileSize = 0;
|
|
{
|
|
AZ::IO::HandleType fileHandle2 = archive->FOpen(testFilePath, "rb");
|
|
char* pFileBuffer3 = (char*)archive->FGetCachedFileData(fileHandle2, fileSize);
|
|
ASSERT_NE(nullptr, pFileBuffer3);
|
|
EXPECT_EQ(dataLen, fileSize);
|
|
EXPECT_EQ(0, memcmp(pFileBuffer3, testData, dataLen));
|
|
archive->FClose(fileHandle2);
|
|
}
|
|
|
|
// Multithreaded test #1 reading from the same file handle in parallel
|
|
auto parallelArchiveFileReadFunc = [archive, fileHandle, pFileBuffer, dataLen, testFilePath]()
|
|
{
|
|
size_t fileSize = 0;
|
|
auto pFileBufferThread = reinterpret_cast<const char*>(archive->FGetCachedFileData(fileHandle, fileSize));
|
|
if (pFileBufferThread == nullptr)
|
|
{
|
|
EXPECT_NE(nullptr, pFileBufferThread) << "FGetCachedFileData returned nullptr for file " << testFilePath;
|
|
return false;
|
|
}
|
|
if (pFileBuffer != pFileBufferThread)
|
|
{
|
|
EXPECT_EQ(pFileBufferThread, pFileBuffer) << "Read file data for file " << testFilePath << "Does not match expected file data";
|
|
return false;
|
|
}
|
|
if (fileSize != dataLen)
|
|
{
|
|
EXPECT_EQ(dataLen, fileSize) << "Read filesize does not match expected filesize for file " << testFilePath;
|
|
return false;
|
|
}
|
|
return true;
|
|
};
|
|
RunConcurrentUnitTest(numThreadedIterations, numTestThreads, parallelArchiveFileReadFunc);
|
|
|
|
archive->FClose(fileHandle);
|
|
}
|
|
|
|
// Multithreaded Test #2 reading from the same file concurrently
|
|
auto concurrentArchiveFileReadFunc = [archive, testFilePath, dataLen, testData]()
|
|
{
|
|
AZ::IO::HandleType threadFileHandle = archive->FOpen(testFilePath, "rb");
|
|
|
|
if (threadFileHandle == AZ::IO::InvalidHandle)
|
|
{
|
|
EXPECT_NE(AZ::IO::InvalidHandle, threadFileHandle) << "Failed to open file handle " << testFilePath;
|
|
return false;
|
|
}
|
|
size_t fileSize = 0;
|
|
auto pFileBufferThread = reinterpret_cast<const char*>(archive->FGetCachedFileData(threadFileHandle, fileSize));
|
|
if (pFileBufferThread == nullptr)
|
|
{
|
|
EXPECT_NE(nullptr, pFileBufferThread) << "FGetCachedFileData returned nullptr for file " << testFilePath;
|
|
return false;
|
|
}
|
|
if (fileSize != dataLen)
|
|
{
|
|
EXPECT_EQ(dataLen, fileSize) << "Read filesize does not match expected filesize for file " << testFilePath;
|
|
return false;
|
|
}
|
|
if (memcmp(pFileBufferThread, testData, dataLen) != 0)
|
|
{
|
|
ADD_FAILURE() << "Read file data for file " << testFilePath << "Does not match expected file data";
|
|
}
|
|
archive->FClose(threadFileHandle);
|
|
return true;
|
|
};
|
|
RunConcurrentUnitTest(numThreadedIterations, numTestThreads, concurrentArchiveFileReadFunc);
|
|
}
|
|
|
|
AZStd::unique_ptr<AzFramework::Application> m_application;
|
|
};
|
|
|
|
struct CVarIntValueScope
|
|
{
|
|
CVarIntValueScope(AZ::IConsole& console, const char* cvarName)
|
|
: m_console{ console }
|
|
, m_cvarName{ cvarName }
|
|
{
|
|
// Store current CVar value
|
|
m_valueStored = m_cvarName != nullptr && m_console.GetCvarValue(cvarName, m_oldValue) == AZ::GetValueResult::Success;
|
|
}
|
|
~CVarIntValueScope()
|
|
{
|
|
// Restore the old value if it was successfully stored
|
|
if (m_valueStored)
|
|
{
|
|
m_console.PerformCommand(m_cvarName, { AZ::CVarFixedString::format("%d", m_oldValue) });
|
|
}
|
|
}
|
|
AZ::IConsole& m_console;
|
|
const char* m_cvarName{};
|
|
int32_t m_oldValue{};
|
|
bool m_valueStored{};
|
|
};
|
|
|
|
TEST_F(ArchiveTestFixture, TestArchiveFGetCachedFileData_PakFile)
|
|
{
|
|
// Test setup - from Archive
|
|
constexpr const char* fileInArchiveFile = "levels\\mylevel\\levelinfo.xml";
|
|
constexpr AZStd::string_view dataString = "HELLO WORLD"; // other unit tests make sure writing and reading is working, so don't test that here
|
|
|
|
AZ::IO::IArchive* archive = AZ::Interface<AZ::IO::IArchive>::Get();
|
|
ASSERT_NE(nullptr, archive);
|
|
|
|
AZ::IO::FileIOBase* fileIo = AZ::IO::FileIOBase::GetInstance();
|
|
ASSERT_NE(nullptr, fileIo);
|
|
|
|
auto console = AZ::Interface<AZ::IConsole>::Get();
|
|
ASSERT_NE(nullptr, console);
|
|
|
|
{
|
|
AZStd::string testArchivePath_withSubfolders = "@usercache@/immediate.pak";
|
|
AZStd::string testArchivePath_withMountPoint = "@usercache@/levels/test/flatarchive.pak";
|
|
|
|
// delete test files in case they already exist
|
|
archive->ClosePack(testArchivePath_withSubfolders.c_str());
|
|
fileIo->Remove(testArchivePath_withSubfolders.c_str());
|
|
fileIo->Remove(testArchivePath_withMountPoint.c_str());
|
|
fileIo->CreatePath("@usercache@/levels/test");
|
|
|
|
// setup test archive and file
|
|
AZStd::intrusive_ptr<AZ::IO::INestedArchive> pArchive = archive->OpenArchive(testArchivePath_withSubfolders.c_str(), {}, AZ::IO::INestedArchive::FLAGS_CREATE_NEW);
|
|
EXPECT_NE(nullptr, pArchive);
|
|
EXPECT_EQ(0, pArchive->UpdateFile(fileInArchiveFile, dataString.data(), dataString.size(), AZ::IO::INestedArchive::METHOD_COMPRESS, AZ::IO::INestedArchive::LEVEL_FASTEST));
|
|
pArchive.reset();
|
|
EXPECT_TRUE(IsPackValid(testArchivePath_withSubfolders.c_str()));
|
|
|
|
EXPECT_TRUE(archive->OpenPack("@products@", testArchivePath_withSubfolders.c_str()));
|
|
|
|
EXPECT_TRUE(archive->IsFileExist(fileInArchiveFile));
|
|
}
|
|
|
|
// Prevent Archive file searches from using the OS filesystem
|
|
// Also enable extra verbosity in the AZ::IO::Archive code
|
|
CVarIntValueScope previousLocationPriority{ *console, "sys_pakPriority" };
|
|
CVarIntValueScope oldArchiveVerbosity{ *console, "az_archive_verbosity" };
|
|
console->PerformCommand("sys_PakPriority", { AZ::CVarFixedString::format("%d", aznumeric_cast<int>(AZ::IO::ArchiveLocationPriority::ePakPriorityPakOnly)) });
|
|
console->PerformCommand("az_archive_verbosity", { "1" });
|
|
|
|
// ---- Archive FGetCachedFileDataTests (these leverage Archive CachedFile mechanism for caching data ---
|
|
TestFGetCachedFileData(fileInArchiveFile, dataString.size(), dataString.data());
|
|
}
|
|
|
|
TEST_F(ArchiveTestFixture, TestArchiveOpenPacks_FindsMultiplePaks_Works)
|
|
{
|
|
AZ::IO::IArchive* archive = AZ::Interface<AZ::IO::IArchive>::Get();
|
|
ASSERT_NE(nullptr, archive);
|
|
|
|
AZ::IO::FileIOBase* fileIo = AZ::IO::FileIOBase::GetInstance();
|
|
ASSERT_NE(nullptr, fileIo);
|
|
|
|
auto resetArchiveFile = [archive, fileIo](const AZStd::string& filePath)
|
|
{
|
|
archive->ClosePack(filePath.c_str());
|
|
fileIo->Remove(filePath.c_str());
|
|
|
|
auto pArchive = archive->OpenArchive(filePath.c_str(), {}, AZ::IO::INestedArchive::FLAGS_CREATE_NEW);
|
|
EXPECT_NE(nullptr, pArchive);
|
|
pArchive.reset();
|
|
archive->ClosePack(filePath.c_str());
|
|
};
|
|
|
|
AZStd::string testArchivePath_pakOne = "@usercache@/one.pak";
|
|
AZStd::string testArchivePath_pakTwo = "@usercache@/two.pak";
|
|
|
|
// reset test files in case they already exist
|
|
resetArchiveFile(testArchivePath_pakOne);
|
|
resetArchiveFile(testArchivePath_pakTwo);
|
|
|
|
// open and fetch the opened pak file using a *.pak
|
|
AZStd::vector<AZ::IO::FixedMaxPathString> fullPaths;
|
|
archive->OpenPacks("@usercache@/*.pak", &fullPaths);
|
|
EXPECT_TRUE(AZStd::any_of(fullPaths.cbegin(), fullPaths.cend(), [](auto& path) { return path.ends_with("one.pak"); }));
|
|
EXPECT_TRUE(AZStd::any_of(fullPaths.cbegin(), fullPaths.cend(), [](auto& path) { return path.ends_with("two.pak"); }));
|
|
}
|
|
|
|
TEST_F(ArchiveTestFixture, TestArchiveFGetCachedFileData_LooseFile)
|
|
{
|
|
// ------setup loose file FGetCachedFileData tests -------------------------
|
|
|
|
constexpr AZStd::string_view dataString = "HELLO WORLD";
|
|
|
|
AZ::IO::IArchive* archive = AZ::Interface<AZ::IO::IArchive>::Get();
|
|
ASSERT_NE(nullptr, archive);
|
|
const char* testRootPath = "@log@/unittesttemp";
|
|
const char* looseTestFilePath = "@log@/unittesttemp/realfileforunittest.txt";
|
|
AZ::IO::ArchiveFileIO cpfio(archive);
|
|
|
|
// remove existing
|
|
EXPECT_EQ(AZ::IO::ResultCode::Success, cpfio.DestroyPath(testRootPath));
|
|
|
|
// create test file
|
|
EXPECT_EQ(AZ::IO::ResultCode::Success, cpfio.CreatePath(testRootPath));
|
|
|
|
AZ::IO::HandleType normalFileHandle;
|
|
EXPECT_EQ(AZ::IO::ResultCode::Success, cpfio.Open(looseTestFilePath, AZ::IO::OpenMode::ModeWrite | AZ::IO::OpenMode::ModeBinary, normalFileHandle));
|
|
|
|
AZ::u64 bytesWritten = 0;
|
|
EXPECT_EQ(AZ::IO::ResultCode::Success, cpfio.Write(normalFileHandle, dataString.data(), dataString.size(), &bytesWritten));
|
|
EXPECT_EQ(dataString.size(), bytesWritten);
|
|
|
|
EXPECT_EQ(AZ::IO::ResultCode::Success, cpfio.Close(normalFileHandle));
|
|
EXPECT_TRUE(cpfio.Exists(looseTestFilePath));
|
|
|
|
TestFGetCachedFileData(looseTestFilePath, dataString.size(), dataString.data());
|
|
}
|
|
|
|
// a bug was found that causes problems reading data from packs if they are immediately mounted after writing.
|
|
// this unit test adjusts for that.
|
|
TEST_F(ArchiveTestFixture, TestArchivePackImmediateReading)
|
|
{
|
|
// the strategy is to create a archive file similar to how the level system does
|
|
// one which contains subfolders
|
|
// and a file inside that subfolder
|
|
// to be successful, it must be possible to write that pack, close it, then open it via Archive
|
|
// and be able to IMMEDIATELY
|
|
// * read the file in the subfolder
|
|
// * enumerate the folders (including that subfolder) even though they are 'virtual', not real folders on physical media
|
|
// * all of the above even though the mount point for the archive is @products@ wheras the physical pack lives in @usercache@
|
|
// finally, we're going to repeat the above test but with files mounted with subfolders
|
|
// so for example, the pack will contain levelinfo.xml at the root of it
|
|
// but it will be mounted at a subfolder (levels/mylevel).
|
|
// this must cause FindNext and Open to work for levels/mylevel/levelinfo.xml.
|
|
|
|
constexpr const char* testArchivePath_withSubfolders = "@usercache@/immediate.pak";
|
|
constexpr const char* testArchivePath_withMountPoint = "@usercache@/levels/test/flatarchive.pak";
|
|
|
|
AZ::IO::FileIOBase* fileIo = AZ::IO::FileIOBase::GetInstance();
|
|
ASSERT_NE(nullptr, fileIo);
|
|
|
|
AZ::IO::IArchive* archive = AZ::Interface<AZ::IO::IArchive>::Get();
|
|
ASSERT_NE(nullptr, archive);
|
|
|
|
auto console = AZ::Interface<AZ::IConsole>::Get();
|
|
ASSERT_NE(nullptr, console);
|
|
|
|
constexpr AZStd::string_view dataString = "HELLO WORLD"; // other unit tests make sure writing and reading is working, so don't test that here
|
|
|
|
|
|
// delete test files in case they already exist
|
|
archive->ClosePack(testArchivePath_withSubfolders);
|
|
archive->ClosePack(testArchivePath_withMountPoint);
|
|
fileIo->Remove(testArchivePath_withSubfolders);
|
|
fileIo->Remove(testArchivePath_withMountPoint);
|
|
fileIo->CreatePath("@usercache@/levels/test");
|
|
|
|
|
|
AZStd::intrusive_ptr<AZ::IO::INestedArchive> pArchive = archive->OpenArchive(testArchivePath_withSubfolders, {}, AZ::IO::INestedArchive::FLAGS_CREATE_NEW);
|
|
EXPECT_NE(nullptr, pArchive);
|
|
EXPECT_EQ(0, pArchive->UpdateFile("levels\\mylevel\\levelinfo.xml", dataString.data(), dataString.size(), AZ::IO::INestedArchive::METHOD_COMPRESS, AZ::IO::INestedArchive::LEVEL_FASTEST));
|
|
pArchive.reset();
|
|
EXPECT_TRUE(IsPackValid(testArchivePath_withSubfolders));
|
|
|
|
EXPECT_TRUE(archive->OpenPack("@products@", testArchivePath_withSubfolders));
|
|
// ---- BARRAGE OF TESTS
|
|
EXPECT_TRUE(archive->IsFileExist("levels\\mylevel\\levelinfo.xml"));
|
|
EXPECT_TRUE(archive->IsFileExist("levels//mylevel//levelinfo.xml"));
|
|
|
|
bool found_mylevel_folder = false;
|
|
AZ::IO::ArchiveFileIterator handle = archive->FindFirst("levels\\*");
|
|
|
|
EXPECT_TRUE(static_cast<bool>(handle));
|
|
if (handle)
|
|
{
|
|
do
|
|
{
|
|
if ((handle.m_fileDesc.nAttrib & AZ::IO::FileDesc::Attribute::Subdirectory) == AZ::IO::FileDesc::Attribute::Subdirectory)
|
|
{
|
|
if (azstricmp(handle.m_filename.data(), "mylevel") == 0)
|
|
{
|
|
found_mylevel_folder = true;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
EXPECT_STRCASENE("levelinfo.xml", handle.m_filename.data()); // you may not find files inside the archive in this folder.
|
|
}
|
|
} while (handle = archive->FindNext(handle));
|
|
|
|
archive->FindClose(handle);
|
|
}
|
|
|
|
EXPECT_TRUE(found_mylevel_folder);
|
|
|
|
bool found_mylevel_file = false;
|
|
|
|
handle = archive->FindFirst("levels\\mylevel\\*");
|
|
|
|
EXPECT_TRUE(static_cast<bool>(handle));
|
|
if (handle)
|
|
{
|
|
do
|
|
{
|
|
if ((handle.m_fileDesc.nAttrib & AZ::IO::FileDesc::Attribute::Subdirectory) != AZ::IO::FileDesc::Attribute::Subdirectory)
|
|
{
|
|
if (azstricmp(handle.m_filename.data(), "levelinfo.xml") == 0)
|
|
{
|
|
found_mylevel_file = true;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
EXPECT_STRCASENE("mylevel", handle.m_filename.data()); // you may not find the level subfolder here since we're in the subfolder already
|
|
EXPECT_STRCASENE("levels\\mylevel", handle.m_filename.data());
|
|
EXPECT_STRCASENE("levels//mylevel", handle.m_filename.data());
|
|
}
|
|
} while (handle = archive->FindNext(handle));
|
|
|
|
archive->FindClose(handle);
|
|
}
|
|
|
|
EXPECT_TRUE(found_mylevel_file);
|
|
|
|
// now test clean-up
|
|
archive->ClosePack(testArchivePath_withSubfolders);
|
|
fileIo->Remove(testArchivePath_withSubfolders);
|
|
|
|
EXPECT_FALSE(archive->IsFileExist("levels\\mylevel\\levelinfo.xml"));
|
|
EXPECT_FALSE(archive->IsFileExist("levels//mylevel//levelinfo.xml"));
|
|
|
|
// Once the archive has been deleted it should no longer be searched
|
|
CVarIntValueScope previousLocationPriority{ *console, "sys_pakPriority" };
|
|
console->PerformCommand("sys_PakPriority", { AZ::CVarFixedString::format("%d", aznumeric_cast<int>(AZ::IO::ArchiveLocationPriority::ePakPriorityPakOnly)) });
|
|
|
|
handle = archive->FindFirst("levels\\*");
|
|
EXPECT_FALSE(static_cast<bool>(handle));
|
|
}
|
|
TEST_F(ArchiveTestFixture, FilesInArchive_AreSearchable)
|
|
{
|
|
// ----------- SECOND TEST. File in levels/mylevel/ showing up as searchable.
|
|
// note that the actual file's folder has nothing to do with the mount point.
|
|
|
|
AZ::IO::FileIOBase* fileIo = AZ::IO::FileIOBase::GetInstance();
|
|
ASSERT_NE(nullptr, fileIo);
|
|
|
|
AZ::IO::IArchive* archive = AZ::Interface<AZ::IO::IArchive>::Get();
|
|
ASSERT_NE(nullptr, archive);
|
|
|
|
constexpr AZStd::string_view dataString = "HELLO WORLD";
|
|
constexpr const char* testArchivePath_withMountPoint = "@usercache@/levels/test/flatarchive.pak";
|
|
bool found_mylevel_file{};
|
|
bool found_mylevel_folder{};
|
|
|
|
AZStd::intrusive_ptr<AZ::IO::INestedArchive> pArchive = archive->OpenArchive(testArchivePath_withMountPoint, {}, AZ::IO::INestedArchive::FLAGS_CREATE_NEW);
|
|
EXPECT_NE(nullptr, pArchive);
|
|
EXPECT_EQ(0, pArchive->UpdateFile("levelinfo.xml", dataString.data(), dataString.size(), AZ::IO::INestedArchive::METHOD_COMPRESS, AZ::IO::INestedArchive::LEVEL_FASTEST));
|
|
pArchive.reset();
|
|
EXPECT_TRUE(IsPackValid(testArchivePath_withMountPoint));
|
|
|
|
EXPECT_TRUE(archive->OpenPack("@products@\\uniquename\\mylevel2", testArchivePath_withMountPoint));
|
|
|
|
// ---- BARRAGE OF TESTS
|
|
EXPECT_TRUE(archive->IsFileExist("uniquename\\mylevel2\\levelinfo.xml"));
|
|
EXPECT_TRUE(archive->IsFileExist("uniquename//mylevel2//levelinfo.xml"));
|
|
|
|
EXPECT_TRUE(!archive->IsFileExist("uniquename\\mylevel\\levelinfo.xml"));
|
|
EXPECT_TRUE(!archive->IsFileExist("uniquename//mylevel//levelinfo.xml"));
|
|
EXPECT_TRUE(!archive->IsFileExist("uniquename\\test\\levelinfo.xml"));
|
|
EXPECT_TRUE(!archive->IsFileExist("uniquename//test//levelinfo.xml"));
|
|
|
|
found_mylevel_folder = false;
|
|
AZ::IO::ArchiveFileIterator handle = archive->FindFirst("uniquename\\*");
|
|
|
|
EXPECT_TRUE(static_cast<bool>(handle));
|
|
if (handle)
|
|
{
|
|
do
|
|
{
|
|
if ((handle.m_fileDesc.nAttrib & AZ::IO::FileDesc::Attribute::Subdirectory) == AZ::IO::FileDesc::Attribute::Subdirectory)
|
|
{
|
|
if (azstricmp(handle.m_filename.data(), "mylevel2") == 0)
|
|
{
|
|
found_mylevel_folder = true;
|
|
}
|
|
}
|
|
} while (handle = archive->FindNext(handle));
|
|
|
|
archive->FindClose(handle);
|
|
}
|
|
|
|
EXPECT_TRUE(found_mylevel_folder);
|
|
|
|
found_mylevel_file = false;
|
|
|
|
handle = archive->FindFirst("uniquename\\mylevel2\\*");
|
|
|
|
EXPECT_TRUE(static_cast<bool>(handle));
|
|
if (handle)
|
|
{
|
|
do
|
|
{
|
|
if ((handle.m_fileDesc.nAttrib & AZ::IO::FileDesc::Attribute::Subdirectory) != AZ::IO::FileDesc::Attribute::Subdirectory)
|
|
{
|
|
if (azstricmp(handle.m_filename.data(), "levelinfo.xml") == 0)
|
|
{
|
|
found_mylevel_file = true;
|
|
}
|
|
}
|
|
} while (handle = archive->FindNext(handle));
|
|
|
|
archive->FindClose(handle);
|
|
}
|
|
|
|
EXPECT_TRUE(found_mylevel_file);
|
|
|
|
archive->ClosePack(testArchivePath_withMountPoint);
|
|
|
|
// --- test to make sure that when you iterate only the first component is found, so bury it deep and ask for the root
|
|
EXPECT_TRUE(archive->OpenPack("@products@\\uniquename\\mylevel2\\mylevel3\\mylevel4", testArchivePath_withMountPoint));
|
|
|
|
found_mylevel_folder = false;
|
|
handle = archive->FindFirst("uniquename\\*");
|
|
|
|
int numFound = 0;
|
|
EXPECT_TRUE(static_cast<bool>(handle));
|
|
if (handle)
|
|
{
|
|
do
|
|
{
|
|
if ((handle.m_fileDesc.nAttrib & AZ::IO::FileDesc::Attribute::Subdirectory) == AZ::IO::FileDesc::Attribute::Subdirectory)
|
|
{
|
|
++numFound;
|
|
if (azstricmp(handle.m_filename.data(), "mylevel2") == 0)
|
|
{
|
|
found_mylevel_folder = true;
|
|
}
|
|
}
|
|
} while (handle = archive->FindNext(handle));
|
|
|
|
archive->FindClose(handle);
|
|
}
|
|
|
|
EXPECT_EQ(1, numFound);
|
|
EXPECT_TRUE(found_mylevel_folder);
|
|
|
|
numFound = 0;
|
|
found_mylevel_folder = false;
|
|
|
|
// now make sure no red herrings appear
|
|
// for example, if a file is mounted at "@products@\\uniquename\\mylevel2\\mylevel3\\mylevel4"
|
|
// and the file "@products@\\somethingelse" is requested it should not be found
|
|
// in addition if the file "@products@\\uniquename\\mylevel3" is requested it should not be found
|
|
handle = archive->FindFirst("somethingelse\\*");
|
|
EXPECT_FALSE(static_cast<bool>(handle));
|
|
|
|
handle = archive->FindFirst("uniquename\\mylevel3*");
|
|
EXPECT_FALSE(static_cast<bool>(handle));
|
|
|
|
archive->ClosePack(testArchivePath_withMountPoint);
|
|
fileIo->Remove(testArchivePath_withMountPoint);
|
|
}
|
|
|
|
// test that ArchiveFileIO class works as expected
|
|
TEST_F(ArchiveTestFixture, TestArchiveViaFileIO)
|
|
{
|
|
// strategy:
|
|
// create a loose file and a packed file
|
|
// mount the pack
|
|
// make sure that the pack and loose file both appear when the PaKFileIO interface is used.
|
|
using namespace AZ::IO;
|
|
AZ::IO::IArchive* archive = AZ::Interface<AZ::IO::IArchive>::Get();
|
|
AZ::IO::ArchiveFileIO cpfio(archive);
|
|
|
|
constexpr const char* genericArchiveFileName = "@usercache@/testarchiveio.pak";
|
|
ASSERT_NE(nullptr, archive);
|
|
const char* dataString = "HELLO WORLD"; // other unit tests make sure writing and reading is working, so don't test that here
|
|
size_t dataLen = strlen(dataString);
|
|
AZStd::vector<char> dataBuffer;
|
|
dataBuffer.resize(dataLen);
|
|
|
|
// delete test files in case they already exist
|
|
archive->ClosePack(genericArchiveFileName);
|
|
cpfio.Remove(genericArchiveFileName);
|
|
|
|
// create the asset alias directory
|
|
cpfio.CreatePath("@products@");
|
|
|
|
// create generic file
|
|
|
|
HandleType normalFileHandle;
|
|
AZ::u64 bytesWritten = 0;
|
|
EXPECT_EQ(ResultCode::Success, cpfio.DestroyPath("@log@/unittesttemp"));
|
|
EXPECT_TRUE(!cpfio.Exists("@log@/unittesttemp"));
|
|
EXPECT_TRUE(!cpfio.IsDirectory("@log@/unittesttemp"));
|
|
EXPECT_EQ(ResultCode::Success, cpfio.CreatePath("@log@/unittesttemp"));
|
|
EXPECT_TRUE(cpfio.Exists("@log@/unittesttemp"));
|
|
EXPECT_TRUE(cpfio.IsDirectory("@log@/unittesttemp"));
|
|
EXPECT_EQ(ResultCode::Success, cpfio.Open("@log@/unittesttemp/realfileforunittest.xml", OpenMode::ModeWrite | OpenMode::ModeBinary, normalFileHandle));
|
|
EXPECT_EQ(ResultCode::Success, cpfio.Write(normalFileHandle, dataString, dataLen, &bytesWritten));
|
|
EXPECT_EQ(dataLen, bytesWritten);
|
|
EXPECT_EQ(ResultCode::Success, cpfio.Close(normalFileHandle));
|
|
normalFileHandle = InvalidHandle;
|
|
EXPECT_TRUE(cpfio.Exists("@log@/unittesttemp/realfileforunittest.xml"));
|
|
|
|
AZStd::intrusive_ptr<AZ::IO::INestedArchive> pArchive = archive->OpenArchive(genericArchiveFileName, {}, AZ::IO::INestedArchive::FLAGS_CREATE_NEW);
|
|
EXPECT_NE(nullptr, pArchive);
|
|
EXPECT_EQ(0, pArchive->UpdateFile("testfile.xml", dataString, aznumeric_cast<uint32_t>(dataLen), AZ::IO::INestedArchive::METHOD_COMPRESS, AZ::IO::INestedArchive::LEVEL_FASTEST));
|
|
pArchive.reset();
|
|
EXPECT_TRUE(IsPackValid(genericArchiveFileName));
|
|
|
|
EXPECT_TRUE(archive->OpenPack("@products@", genericArchiveFileName));
|
|
|
|
// ---- BARRAGE OF TESTS
|
|
EXPECT_TRUE(cpfio.Exists("testfile.xml"));
|
|
EXPECT_TRUE(cpfio.Exists("@products@/testfile.xml")); // this should be hte same file
|
|
EXPECT_TRUE(!cpfio.Exists("@log@/testfile.xml"));
|
|
EXPECT_TRUE(!cpfio.Exists("@usercache@/testfile.xml"));
|
|
EXPECT_TRUE(cpfio.Exists("@log@/unittesttemp/realfileforunittest.xml"));
|
|
|
|
// --- Coverage test ----
|
|
AZ::u64 fileSize = 0;
|
|
AZ::u64 bytesRead = 0;
|
|
AZ::u64 currentOffset = 0;
|
|
char fileNameBuffer[AZ_MAX_PATH_LEN] = { 0 };
|
|
EXPECT_EQ(ResultCode::Success, cpfio.Size("testfile.xml", fileSize));
|
|
EXPECT_EQ(dataLen, fileSize);
|
|
EXPECT_EQ(ResultCode::Success, cpfio.Open("testfile.xml", OpenMode::ModeRead | OpenMode::ModeBinary, normalFileHandle));
|
|
EXPECT_NE(InvalidHandle, normalFileHandle);
|
|
EXPECT_EQ(ResultCode::Success, cpfio.Size(normalFileHandle, fileSize));
|
|
EXPECT_EQ(dataLen, fileSize);
|
|
EXPECT_EQ(ResultCode::Success, cpfio.Read(normalFileHandle, dataBuffer.data(), 2, true, &bytesRead));
|
|
EXPECT_EQ(2, bytesRead);
|
|
EXPECT_EQ('H', dataBuffer[0]);
|
|
EXPECT_EQ('E', dataBuffer[1]);
|
|
EXPECT_EQ(ResultCode::Success, cpfio.Tell(normalFileHandle, currentOffset));
|
|
EXPECT_EQ(2, currentOffset);
|
|
EXPECT_EQ(ResultCode::Success, cpfio.Seek(normalFileHandle, 2, SeekType::SeekFromCurrent));
|
|
EXPECT_EQ(ResultCode::Success, cpfio.Tell(normalFileHandle, currentOffset));
|
|
EXPECT_EQ(4, currentOffset);
|
|
EXPECT_TRUE(!cpfio.Eof(normalFileHandle));
|
|
EXPECT_EQ(ResultCode::Success, cpfio.Seek(normalFileHandle, 2, SeekType::SeekFromStart));
|
|
EXPECT_EQ(ResultCode::Success, cpfio.Tell(normalFileHandle, currentOffset));
|
|
EXPECT_EQ(2, currentOffset);
|
|
EXPECT_EQ(ResultCode::Success, cpfio.Seek(normalFileHandle, -2, SeekType::SeekFromEnd));
|
|
EXPECT_EQ(ResultCode::Success, cpfio.Tell(normalFileHandle, currentOffset));
|
|
EXPECT_EQ(dataLen - 2, currentOffset);
|
|
EXPECT_NE(ResultCode::Success, cpfio.Read(normalFileHandle, dataBuffer.data(), 4, true, &bytesRead));
|
|
EXPECT_EQ(2, bytesRead);
|
|
EXPECT_TRUE(cpfio.Eof(normalFileHandle));
|
|
EXPECT_TRUE(cpfio.GetFilename(normalFileHandle, fileNameBuffer, AZ_MAX_PATH_LEN));
|
|
EXPECT_NE(AZStd::string_view::npos, AZStd::string_view(fileNameBuffer).find("testfile.xml"));
|
|
// just coverage-call this function:
|
|
EXPECT_EQ(archive->GetModificationTime(normalFileHandle), cpfio.ModificationTime(normalFileHandle));
|
|
EXPECT_EQ(archive->GetModificationTime(normalFileHandle), cpfio.ModificationTime("testfile.xml"));
|
|
EXPECT_NE(0, cpfio.ModificationTime("testfile.xml"));
|
|
EXPECT_NE(0, cpfio.ModificationTime("@log@/unittesttemp/realfileforunittest.xml"));
|
|
|
|
EXPECT_EQ(ResultCode::Success, cpfio.Close(normalFileHandle));
|
|
|
|
EXPECT_TRUE(!cpfio.IsDirectory("testfile.xml"));
|
|
EXPECT_TRUE(cpfio.IsDirectory("@products@"));
|
|
EXPECT_TRUE(cpfio.IsReadOnly("testfile.xml"));
|
|
EXPECT_TRUE(cpfio.IsReadOnly("@products@/testfile.xml"));
|
|
EXPECT_TRUE(!cpfio.IsReadOnly("@log@/unittesttemp/realfileforunittest.xml"));
|
|
|
|
|
|
// copy file from inside archive:
|
|
EXPECT_EQ(ResultCode::Success, cpfio.Copy("testfile.xml", "@log@/unittesttemp/copiedfile.xml"));
|
|
EXPECT_TRUE(cpfio.Exists("@log@/unittesttemp/copiedfile.xml"));
|
|
|
|
// make sure copy is ok
|
|
|
|
EXPECT_EQ(ResultCode::Success, cpfio.Open("@log@/unittesttemp/copiedfile.xml", OpenMode::ModeRead | OpenMode::ModeBinary, normalFileHandle));
|
|
EXPECT_EQ(ResultCode::Success, cpfio.Size(normalFileHandle, fileSize));
|
|
EXPECT_EQ(dataLen, fileSize);
|
|
EXPECT_EQ(ResultCode::Success, cpfio.Read(normalFileHandle, dataBuffer.data(), dataLen + 10, false, &bytesRead)); // allowed to read less
|
|
EXPECT_EQ(dataLen, bytesRead);
|
|
EXPECT_EQ(0, memcmp(dataBuffer.data(), dataString, dataLen));
|
|
EXPECT_EQ(ResultCode::Success, cpfio.Close(normalFileHandle));
|
|
|
|
// make sure file does not exist, since copy will NOT overwrite:
|
|
cpfio.Remove("@log@/unittesttemp/copiedfile2.xml");
|
|
|
|
EXPECT_EQ(ResultCode::Success, cpfio.Rename("@log@/unittesttemp/copiedfile.xml", "@log@/unittesttemp/copiedfile2.xml"));
|
|
EXPECT_TRUE(!cpfio.Exists("@log@/unittesttemp/copiedfile.xml"));
|
|
EXPECT_TRUE(cpfio.Exists("@log@/unittesttemp/copiedfile2.xml"));
|
|
|
|
// find files test.
|
|
AZ::IO::FixedMaxPath resolvedTestFilePath;
|
|
EXPECT_TRUE(cpfio.ResolvePath(resolvedTestFilePath, AZ::IO::PathView("@products@/testfile.xml")));
|
|
bool foundIt = false;
|
|
// note that this file exists only in the archive.
|
|
cpfio.FindFiles("@products@", "*.xml", [&foundIt, &cpfio, &resolvedTestFilePath](const char* foundName)
|
|
{
|
|
AZ::IO::FixedMaxPath resolvedFoundPath;
|
|
EXPECT_TRUE(cpfio.ResolvePath(resolvedFoundPath, AZ::IO::PathView(foundName)));
|
|
// according to the contract stated in the FileIO.h file, we expect full paths. (Aliases are full paths)
|
|
if (resolvedTestFilePath == resolvedFoundPath)
|
|
{
|
|
foundIt = true;
|
|
return false;
|
|
}
|
|
return true;
|
|
});
|
|
|
|
EXPECT_TRUE(foundIt);
|
|
|
|
|
|
// The following test is disabled because it will trigger an AZ_ERROR which will affect the outcome of this entire test
|
|
// EXPECT_NE(ResultCode::Success, cpfio.Remove("@products@/testfile.xml")); // may not delete archive files
|
|
|
|
// make sure it works with and without alias:
|
|
EXPECT_TRUE(cpfio.Exists("@products@/testfile.xml"));
|
|
EXPECT_TRUE(cpfio.Exists("testfile.xml"));
|
|
|
|
EXPECT_TRUE(cpfio.Exists("@log@/unittesttemp/realfileforunittest.xml"));
|
|
EXPECT_EQ(ResultCode::Success, cpfio.Remove("@log@/unittesttemp/realfileforunittest.xml"));
|
|
EXPECT_TRUE(!cpfio.Exists("@log@/unittesttemp/realfileforunittest.xml"));
|
|
|
|
// now test clean-up
|
|
archive->ClosePack(genericArchiveFileName);
|
|
cpfio.Remove(genericArchiveFileName);
|
|
|
|
EXPECT_EQ(ResultCode::Success, cpfio.DestroyPath("@log@/unittesttemp"));
|
|
EXPECT_TRUE(!cpfio.Exists("@log@/unittesttemp/realfileforunittest.xml"));
|
|
EXPECT_TRUE(!cpfio.Exists("@log@/unittesttemp"));
|
|
EXPECT_TRUE(!archive->IsFileExist("testfile.xml"));
|
|
}
|
|
|
|
TEST_F(ArchiveTestFixture, TestArchiveFolderAliases)
|
|
{
|
|
AZ::IO::FileIOBase* fileIo = AZ::IO::FileIOBase::GetInstance();
|
|
ASSERT_NE(nullptr, fileIo);
|
|
|
|
// test whether aliasing works as expected. We'll create a archive in the cache, but we'll map it to a bunch of folders
|
|
constexpr const char* testArchivePath = "@usercache@/archivetest.pak";
|
|
|
|
char realNameBuf[AZ_MAX_PATH_LEN] = { 0 };
|
|
EXPECT_TRUE(fileIo->ResolvePath(testArchivePath, realNameBuf, AZ_MAX_PATH_LEN));
|
|
|
|
AZ::IO::IArchive* archive = AZ::Interface<AZ::IO::IArchive>::Get();
|
|
ASSERT_NE(nullptr, archive);
|
|
|
|
// delete test files in case they already exist
|
|
archive->ClosePack(testArchivePath);
|
|
fileIo->Remove(testArchivePath);
|
|
|
|
// ------------ BASIC TEST: Create and read Empty Archive ------------
|
|
AZStd::intrusive_ptr<AZ::IO::INestedArchive> pArchive = archive->OpenArchive(testArchivePath, {}, AZ::IO::INestedArchive::FLAGS_CREATE_NEW);
|
|
EXPECT_NE(nullptr, pArchive);
|
|
|
|
EXPECT_EQ(0, pArchive->UpdateFile("foundit.dat", const_cast<char*>("test"), 4, AZ::IO::INestedArchive::METHOD_COMPRESS, AZ::IO::INestedArchive::LEVEL_BEST));
|
|
|
|
pArchive.reset();
|
|
EXPECT_TRUE(IsPackValid(testArchivePath));
|
|
|
|
EXPECT_TRUE(archive->OpenPack("@usercache@", realNameBuf));
|
|
EXPECT_TRUE(archive->IsFileExist("@usercache@/foundit.dat"));
|
|
EXPECT_FALSE(archive->IsFileExist("@usercache@/foundit.dat", AZ::IO::IArchive::eFileLocation_OnDisk));
|
|
EXPECT_FALSE(archive->IsFileExist("@usercache@/notfoundit.dat"));
|
|
EXPECT_TRUE(archive->ClosePack(realNameBuf));
|
|
|
|
// change its actual location:
|
|
EXPECT_TRUE(archive->OpenPack("@products@", realNameBuf));
|
|
EXPECT_TRUE(archive->IsFileExist("@products@/foundit.dat"));
|
|
EXPECT_FALSE(archive->IsFileExist("@usercache@/foundit.dat")); // do not find it in the previous location!
|
|
EXPECT_FALSE(archive->IsFileExist("@products@/foundit.dat", AZ::IO::IArchive::eFileLocation_OnDisk));
|
|
EXPECT_FALSE(archive->IsFileExist("@products@/notfoundit.dat"));
|
|
EXPECT_TRUE(archive->ClosePack(realNameBuf));
|
|
|
|
// try sub-folders
|
|
EXPECT_TRUE(archive->OpenPack("@products@/mystuff", realNameBuf));
|
|
EXPECT_TRUE(archive->IsFileExist("@products@/mystuff/foundit.dat"));
|
|
EXPECT_FALSE(archive->IsFileExist("@products@/foundit.dat")); // do not find it in the previous locations!
|
|
EXPECT_FALSE(archive->IsFileExist("@usercache@/foundit.dat")); // do not find it in the previous locations!
|
|
EXPECT_FALSE(archive->IsFileExist("@products@/foundit.dat", AZ::IO::IArchive::eFileLocation_OnDisk));
|
|
EXPECT_FALSE(archive->IsFileExist("@products@/mystuff/foundit.dat", AZ::IO::IArchive::eFileLocation_OnDisk));
|
|
EXPECT_FALSE(archive->IsFileExist("@products@/notfoundit.dat")); // non-existent file
|
|
EXPECT_FALSE(archive->IsFileExist("@products@/mystuff/notfoundit.dat")); // non-existent file
|
|
EXPECT_TRUE(archive->ClosePack(realNameBuf));
|
|
}
|
|
|
|
TEST_F(ArchiveTestFixture, IResourceList_Add_EmptyFileName_DoesNotInsert)
|
|
{
|
|
AZ::IO::IResourceList* reslist = AZ::Interface<AZ::IO::IArchive>::Get()->GetResourceList(AZ::IO::IArchive::RFOM_EngineStartup);
|
|
ASSERT_NE(nullptr, reslist);
|
|
|
|
reslist->Clear();
|
|
reslist->Add("");
|
|
EXPECT_EQ(nullptr, reslist->GetFirst());
|
|
}
|
|
|
|
TEST_F(ArchiveTestFixture, IResourceList_Add_RegularFileName_ResolvesAppropriately)
|
|
{
|
|
AZ::IO::IResourceList* reslist = AZ::Interface<AZ::IO::IArchive>::Get()->GetResourceList(AZ::IO::IArchive::RFOM_EngineStartup);
|
|
ASSERT_NE(nullptr, reslist);
|
|
|
|
AZ::IO::FileIOBase* ioBase = AZ::IO::FileIOBase::GetInstance();
|
|
ASSERT_NE(nullptr, ioBase);
|
|
AZ::IO::FixedMaxPath resolvedTestPath;
|
|
EXPECT_TRUE(ioBase->ResolvePath(resolvedTestPath, "blah/blah/abcde"));
|
|
|
|
reslist->Clear();
|
|
reslist->Add("blah\\blah/AbCDE");
|
|
AZ::IO::FixedMaxPath resolvedAddedPath;
|
|
EXPECT_TRUE(ioBase->ResolvePath(resolvedAddedPath, reslist->GetFirst()));
|
|
EXPECT_EQ(resolvedTestPath, resolvedAddedPath);
|
|
reslist->Clear();
|
|
}
|
|
|
|
TEST_F(ArchiveTestFixture, IResourceList_Add_ReallyShortFileName_ResolvesAppropriately)
|
|
{
|
|
AZ::IO::IResourceList* reslist = AZ::Interface<AZ::IO::IArchive>::Get()->GetResourceList(AZ::IO::IArchive::RFOM_EngineStartup);
|
|
ASSERT_NE(nullptr, reslist);
|
|
|
|
AZ::IO::FileIOBase* ioBase = AZ::IO::FileIOBase::GetInstance();
|
|
ASSERT_NE(nullptr, ioBase);
|
|
AZ::IO::FixedMaxPath resolvedTestPath;
|
|
EXPECT_TRUE(ioBase->ResolvePath(resolvedTestPath, "a"));
|
|
|
|
reslist->Clear();
|
|
reslist->Add("A");
|
|
AZ::IO::FixedMaxPath resolvedAddedPath;
|
|
EXPECT_TRUE(ioBase->ResolvePath(resolvedAddedPath, reslist->GetFirst()));
|
|
EXPECT_EQ(resolvedTestPath, resolvedAddedPath);
|
|
reslist->Clear();
|
|
}
|
|
|
|
TEST_F(ArchiveTestFixture, IResourceList_Add_AbsolutePath_RemovesAndReplacesWithAlias)
|
|
{
|
|
AZ::IO::IResourceList* reslist = AZ::Interface<AZ::IO::IArchive>::Get()->GetResourceList(AZ::IO::IArchive::RFOM_EngineStartup);
|
|
ASSERT_NE(nullptr, reslist);
|
|
|
|
AZ::IO::FileIOBase* ioBase = AZ::IO::FileIOBase::GetInstance();
|
|
ASSERT_NE(nullptr, ioBase);
|
|
|
|
const char* assetsPath = ioBase->GetAlias("@products@");
|
|
ASSERT_NE(nullptr, assetsPath);
|
|
|
|
auto stringToAdd = AZ::IO::Path(assetsPath) / "textures" / "test.dds";
|
|
|
|
reslist->Clear();
|
|
reslist->Add(stringToAdd.Native());
|
|
|
|
// it normalizes the string, so the slashes flip and everything is lowercased.
|
|
AZ::IO::FixedMaxPath resolvedAddedPath;
|
|
AZ::IO::FixedMaxPath resolvedResourcePath;
|
|
EXPECT_TRUE(ioBase->ReplaceAlias(resolvedAddedPath, "@products@/textures/test.dds"));
|
|
EXPECT_TRUE(ioBase->ReplaceAlias(resolvedResourcePath, reslist->GetFirst()));
|
|
EXPECT_EQ(resolvedAddedPath, resolvedResourcePath);
|
|
reslist->Clear();
|
|
}
|
|
}
|