diff options
Diffstat (limited to 'tools/slang-unit-test/unit-test-file-system.cpp')
| -rw-r--r-- | tools/slang-unit-test/unit-test-file-system.cpp | 246 |
1 files changed, 210 insertions, 36 deletions
diff --git a/tools/slang-unit-test/unit-test-file-system.cpp b/tools/slang-unit-test/unit-test-file-system.cpp index e3e2bb3cf..1575f4dfd 100644 --- a/tools/slang-unit-test/unit-test-file-system.cpp +++ b/tools/slang-unit-test/unit-test-file-system.cpp @@ -10,11 +10,15 @@ #include "../../source/core/slang-deflate-compression-system.h" #include "../../source/core/slang-lz4-compression-system.h" +#include "../../source/core/slang-destroyable.h" + +#include "../../source/core/slang-io.h" + #include "tools/unit-test/slang-unit-test.h" using namespace Slang; -namespace { +namespace { // anonymous enum class FileSystemType { @@ -31,22 +35,18 @@ struct Entry { typedef Entry ThisType; - bool operator<(const ThisType& rhs) const { return name < rhs.name; } - bool operator==(const ThisType& rhs) const { return name == rhs.name && type == rhs.type; } + bool operator<(const ThisType& rhs) const { return path < rhs.path; } + bool operator==(const ThisType& rhs) const { return path == rhs.path && type == rhs.type; } bool operator!=(const ThisType& rhs) const { return !(*this == rhs); } SlangPathType type; - String name; + String path; }; -} // +} // anonymous -static SlangResult _createAndCheckFile(ISlangMutableFileSystem* fileSystem, const char* path, const char* contents) +static SlangResult _checkFile(ISlangFileSystemExt* fileSystem, const char* path, const UnownedStringSlice& contentsSlice) { - UnownedStringSlice contentsSlice(contents); - - SLANG_RETURN_ON_FAIL(fileSystem->saveFile(path, contentsSlice.begin(), contentsSlice.getLength())); - SlangPathType pathType; SLANG_RETURN_ON_FAIL(fileSystem->getPathType(path, &pathType)); @@ -66,6 +66,31 @@ static SlangResult _createAndCheckFile(ISlangMutableFileSystem* fileSystem, cons { return SLANG_FAIL; } + return SLANG_OK; +} + +static SlangResult _createAndCheckFile(ISlangMutableFileSystem* fileSystem, const char* path, const char* contents) +{ + UnownedStringSlice contentsSlice(contents); + + SLANG_RETURN_ON_FAIL(fileSystem->saveFile(path, contentsSlice.begin(), contentsSlice.getLength())); + SLANG_RETURN_ON_FAIL(_checkFile(fileSystem, path, contentsSlice)); + + // Delete it + SLANG_RETURN_ON_FAIL(fileSystem->remove(path)); + + // Check it's gone + SlangPathType pathType; + if (SLANG_SUCCEEDED(fileSystem->getPathType(path, &pathType))) + { + return SLANG_FAIL; + } + + // Save as a blob + ComPtr<ISlangBlob> blob = RawBlob::create(contentsSlice.begin(), contentsSlice.getLength()); + + SLANG_RETURN_ON_FAIL(fileSystem->saveFileBlob(path, blob)); + SLANG_RETURN_ON_FAIL(_checkFile(fileSystem, path, contentsSlice)); return SLANG_OK; } @@ -91,7 +116,7 @@ static void _entryCallback(SlangPathType pathType, const char* name, void* userD out.add(Entry{pathType, name}); } -static SlangResult _enumeratePath(ISlangMutableFileSystem* fileSystem, const char* path, const ConstArrayView<Entry>& entries) +static SlangResult _enumeratePath(ISlangFileSystemExt* fileSystem, const char* path, const ConstArrayView<Entry>& entries) { List<Entry> contents; @@ -107,10 +132,10 @@ static SlangResult _enumeratePath(ISlangMutableFileSystem* fileSystem, const cha return SLANG_OK; } -static SlangResult _checkSimplifiedPath(ISlangMutableFileSystem* fileSystem, const char* path, const char* normalPath) +static SlangResult _checkSimplifiedPath(ISlangFileSystemExt* fileSystem, const char* path, const char* normalPath) { ComPtr<ISlangBlob> simplifiedPathBlob; - SLANG_RETURN_ON_FAIL(fileSystem->getSimplifiedPath(path, simplifiedPathBlob.writeRef())); + SLANG_RETURN_ON_FAIL(fileSystem->getPath(PathKind::Simplified, path, simplifiedPathBlob.writeRef())); auto simplifiedPath = StringUtil::getString(simplifiedPathBlob); @@ -122,47 +147,168 @@ static SlangResult _checkSimplifiedPath(ISlangMutableFileSystem* fileSystem, con return SLANG_OK; } -static SlangResult _test(FileSystemType type) +SlangResult _appendPathEntries(ISlangFileSystemExt* fileSystem, const char* inBasePath, List<Entry>& outEntries) { - ComPtr<ISlangMutableFileSystem> fileSystem; - - switch (type) + const UnownedStringSlice basePath(inBasePath); + if (basePath == toSlice(".") || basePath.getLength() == 0) { - case FileSystemType::Zip: + // We don't need to append path prefixes if we are at the root. + SLANG_RETURN_ON_FAIL(fileSystem->enumeratePathContents(inBasePath, _entryCallback, (void*)&outEntries)); + } + else + { + const Index startIndex = outEntries.getCount(); + SLANG_RETURN_ON_FAIL(fileSystem->enumeratePathContents(inBasePath, _entryCallback, (void*)&outEntries)); + + const String basePathString(basePath); + + // we need to fix all of the added paths to make absolute + const Count count = outEntries.getCount(); + for (Index i = startIndex; i < count; ++i) { - SLANG_RETURN_ON_FAIL(ZipFileSystem::create(fileSystem)); - break; + auto& entry = outEntries[i]; + entry.path = Path::combine(basePathString, entry.path); } - case FileSystemType::RiffUncompressed: + } + + return SLANG_OK; +} + +static SlangResult _getAllEntries(ISlangFileSystemExt* fileSystem, const char* inBasePath, List<Entry>& outEntries) +{ + outEntries.clear(); + + // Simplify the base + auto basePath = Path::simplify(inBasePath); + + _appendPathEntries(fileSystem, basePath.getBuffer(), outEntries); + + for (Index i = 0; i < outEntries.getCount(); ++i) + { + // We need to make a copy as outEntries is mutated + const Entry entry = outEntries[i]; + if (entry.type == SLANG_PATH_TYPE_DIRECTORY) { - fileSystem = new RiffFileSystem(nullptr); - break; + _appendPathEntries(fileSystem, entry.path.getBuffer(), outEntries); } - case FileSystemType::RiffDeflate: + } + + // Sort to remove issues with traversal ordering + outEntries.sort(); + return SLANG_OK; +} + +static SlangResult _checkEqual(ISlangFileSystemExt* a, ISlangFileSystemExt* b) +{ + List<Entry> aEntries, bEntries; + + SLANG_RETURN_ON_FAIL(_getAllEntries(a, ".", aEntries)); + SLANG_RETURN_ON_FAIL(_getAllEntries(b, ".", bEntries)); + + if (aEntries != bEntries) + { + return SLANG_FAIL; + } + + // For all the files check the contents is the same + + for (const auto& entry : aEntries) + { + if (entry.type != SLANG_PATH_TYPE_FILE) { - fileSystem = new RiffFileSystem(DeflateCompressionSystem::getSingleton()); - break; + continue; } - case FileSystemType::RiffLZ4: + + ComPtr<ISlangBlob> blobA, blobB; + + SLANG_RETURN_ON_FAIL(a->loadFile(entry.path.getBuffer(), blobA.writeRef())); + SLANG_RETURN_ON_FAIL(b->loadFile(entry.path.getBuffer(), blobB.writeRef())); + + if (blobA->getBufferSize() != blobB->getBufferSize()) { - fileSystem = new RiffFileSystem(LZ4CompressionSystem::getSingleton()); - break; + return SLANG_FAIL; } - case FileSystemType::Memory: + + if (::memcmp(blobA->getBufferPointer(), blobB->getBufferPointer(), blobA->getBufferSize()) != 0) { - fileSystem = new MemoryFileSystem; - break; + return SLANG_FAIL; } + } + + return SLANG_OK; +} + +static SlangResult _createFileSystem(FileSystemType type, ComPtr<ISlangMutableFileSystem>& outFileSystem) +{ + outFileSystem.setNull(); + switch (type) + { + case FileSystemType::Zip: return ZipFileSystem::create(outFileSystem); + case FileSystemType::RiffUncompressed: outFileSystem = new RiffFileSystem(nullptr); break; + case FileSystemType::RiffDeflate: outFileSystem = new RiffFileSystem(DeflateCompressionSystem::getSingleton()); break; + case FileSystemType::RiffLZ4: outFileSystem = new RiffFileSystem(LZ4CompressionSystem::getSingleton()); break; + case FileSystemType::Memory: outFileSystem = new MemoryFileSystem; break; case FileSystemType::Relative: { ComPtr<ISlangMutableFileSystem> memoryFileSystem(new MemoryFileSystem); memoryFileSystem->createDirectory("base"); - fileSystem = new RelativeFileSystem(memoryFileSystem, "base"); + outFileSystem = new RelativeFileSystem(memoryFileSystem, "base"); break; } } + return outFileSystem ? SLANG_OK : SLANG_FAIL; +} + +static SlangResult _testImplicitDirectory(FileSystemType type) +{ + ComPtr<ISlangMutableFileSystem> fileSystem; + SLANG_RETURN_ON_FAIL(_createFileSystem(type, fileSystem)); + + const char contents3[] = "Some text...."; + + SLANG_RETURN_ON_FAIL(fileSystem->saveFile("implicit-path/file2.txt", contents3, SLANG_COUNT_OF(contents3))); + + { + SlangPathType pathType; + SLANG_RETURN_ON_FAIL(fileSystem->getPathType("implicit-path", &pathType)); + + SLANG_CHECK(pathType == SLANG_PATH_TYPE_DIRECTORY); + + auto checkEntries = [&]() -> SlangResult + { + List<Entry> entries; + SLANG_RETURN_ON_FAIL(_getAllEntries(fileSystem, "implicit-path", entries)); + + // It contains a file + SLANG_CHECK(entries.getCount() == 1); + + for (const auto& entry : entries) + { + // All of these should exist + SlangPathType pathType; + SLANG_RETURN_ON_FAIL(fileSystem->getPathType(entry.path.getBuffer(), &pathType)); + } + return SLANG_OK; + }; + + SLANG_RETURN_ON_FAIL(checkEntries()); + + // Make an explicit path, and see whe have the same results + fileSystem->createDirectory("implicit-path"); + + SLANG_RETURN_ON_FAIL(checkEntries()); + } + + return SLANG_OK; +} + +static SlangResult _test(FileSystemType type) +{ + ComPtr<ISlangMutableFileSystem> fileSystem; + SLANG_RETURN_ON_FAIL(_createFileSystem(type, fileSystem)); + SLANG_RETURN_ON_FAIL(_createAndCheckFile(fileSystem, "a", "someText")); SLANG_RETURN_ON_FAIL(_createAndCheckFile(fileSystem, "b", "A longer bit of text....")); @@ -186,6 +332,22 @@ static SlangResult _test(FileSystemType type) SLANG_RETURN_ON_FAIL(_checkSimplifiedPath(fileSystem, "d/../a", "a")); } + + // If we have an archive file system check out it's behavior + if (IArchiveFileSystem* archiveFileSystem = as<IArchiveFileSystem>(fileSystem)) + { + // Load and check its okay + + ComPtr<ISlangBlob> archiveBlob; + SLANG_RETURN_ON_FAIL(archiveFileSystem->storeArchive(false, archiveBlob.writeRef())); + + ComPtr<ISlangFileSystemExt> loadedFileSystem; + SLANG_RETURN_ON_FAIL(loadArchiveFileSystem(archiveBlob->getBufferPointer(), archiveBlob->getBufferSize(), loadedFileSystem)); + + // Check the file systems contents are the same + SLANG_RETURN_ON_FAIL(_checkEqual(loadedFileSystem, fileSystem)); + } + SLANG_RETURN_ON_FAIL(fileSystem->remove("d/a")); { const Entry entries[] = { {SLANG_PATH_TYPE_FILE, "b" } }; @@ -216,9 +378,21 @@ SLANG_UNIT_TEST(fileSystem) { const auto type = FileSystemType(i); - auto const res = _test(type); - - SLANG_CHECK(SLANG_SUCCEEDED(res)); + SLANG_CHECK(SLANG_SUCCEEDED(_test(type))); + + // Some file system types support 'implicit directories'. + // This means that if a file is created with a path, the directories + // required to make that path valid are 'implicitly' created. + // + // Currently this behavior is supported by zip, and this test checks + // that it is working correctly, as we require the file system to + // behave correctly in other ways irrespectively of if the directory is + // implicit or not. + const bool hasImplicitDirectory = (type == FileSystemType::Zip); + if (hasImplicitDirectory) + { + SLANG_CHECK(SLANG_SUCCEEDED(_testImplicitDirectory(type))); + } } } |
