diff options
Diffstat (limited to 'libs/usvfs/test')
169 files changed, 0 insertions, 6659 deletions
diff --git a/libs/usvfs/test/CMakeLists.txt b/libs/usvfs/test/CMakeLists.txt deleted file mode 100644 index c34b31f..0000000 --- a/libs/usvfs/test/CMakeLists.txt +++ /dev/null @@ -1,74 +0,0 @@ -cmake_minimum_required(VERSION 3.16) - -include(CMakeParseArguments) - -#! usvfs_set_test_properties -# -# this function sets the following properties on the given executable or shared -# library test target: -# - OUTPUT_NAME to add arch-specific prefix -# - OUTPUT_DIRECTORY to put the test executable or shared library in the right location -# - FOLDER to organize the VS solution layout -# -# \param:FOLDER if present, specifies the subfolder to use in the solution -# -function(usvfs_set_test_properties TARGET) - cmake_parse_arguments(USVFS_TEST "" "FOLDER" "" ${ARGN}) - if (NOT DEFINED USVFS_TEST_FOLDER) - set(folder "tests") - else() - set(folder "tests/${USVFS_TEST_FOLDER}") - endif() - set_target_properties(${TARGET} - PROPERTIES - FOLDER ${folder} - RUNTIME_OUTPUT_NAME ${TARGET}${ARCH_POSTFIX} - RUNTIME_OUTPUT_DIRECTORY_DEBUG ${USVFS_TEST_BINDIR} - RUNTIME_OUTPUT_DIRECTORY_RELEASE ${USVFS_TEST_BINDIR} - RUNTIME_OUTPUT_DIRECTORY_RELWITHDEBINFO ${USVFS_TEST_BINDIR} - ) -endfunction() - -#! usvfs_target_link_usvfs -# -# add a target link between the given target and the usvfs shared library with delay -# loading -# -function(usvfs_target_link_usvfs TARGET) - target_link_libraries(${TARGET} PRIVATE usvfs_dll) - target_link_options(${TARGET} PRIVATE "/DELAYLOAD:usvfs${ARCH_POSTFIX}.dll") -endfunction() - - -file(GLOB directories LIST_DIRECTORIES true "*") - -# this goes through all the directories and -# -# 1. add them if there is a CMakeLists.txt inside -# 2. add correspondings tests (for CTest) for BOTH x86 and x64 when possible -# -foreach(directory ${directories}) - if(NOT(IS_DIRECTORY ${directory})) - continue() - endif() - - if(NOT(EXISTS ${directory}/CMakeLists.txt)) - continue() - endif() - - add_subdirectory(${directory}) - - get_filename_component(dirname ${directory} NAME) - if((dirname STREQUAL "test_utils") OR (dirname STREQUAL "gtest_utils")) - continue() - endif() - - add_test(NAME ${dirname}_x64 - COMMAND ${USVFS_TEST_BINDIR}/${dirname}_x64.exe - WORKING_DIRECTORY ${PROJECT_SOURCE_DIR} - ) - add_test(NAME ${dirname}_x86 - COMMAND ${USVFS_TEST_BINDIR}/${dirname}_x86.exe - WORKING_DIRECTORY ${PROJECT_SOURCE_DIR} - ) -endforeach() diff --git a/libs/usvfs/test/fixtures/usvfs_global_test/BasicTest/expected/data/file.txt b/libs/usvfs/test/fixtures/usvfs_global_test/BasicTest/expected/data/file.txt deleted file mode 100644 index e69de29..0000000 --- a/libs/usvfs/test/fixtures/usvfs_global_test/BasicTest/expected/data/file.txt +++ /dev/null diff --git a/libs/usvfs/test/fixtures/usvfs_global_test/BasicTest/expected/mods/mod1/docs/doc.txt b/libs/usvfs/test/fixtures/usvfs_global_test/BasicTest/expected/mods/mod1/docs/doc.txt deleted file mode 100644 index e69de29..0000000 --- a/libs/usvfs/test/fixtures/usvfs_global_test/BasicTest/expected/mods/mod1/docs/doc.txt +++ /dev/null diff --git a/libs/usvfs/test/fixtures/usvfs_global_test/BasicTest/expected/mods/mod1/empty/.gitkeep b/libs/usvfs/test/fixtures/usvfs_global_test/BasicTest/expected/mods/mod1/empty/.gitkeep deleted file mode 100644 index e69de29..0000000 --- a/libs/usvfs/test/fixtures/usvfs_global_test/BasicTest/expected/mods/mod1/empty/.gitkeep +++ /dev/null diff --git a/libs/usvfs/test/fixtures/usvfs_global_test/BasicTest/expected/mods/mod1/readme.txt b/libs/usvfs/test/fixtures/usvfs_global_test/BasicTest/expected/mods/mod1/readme.txt deleted file mode 100644 index e69de29..0000000 --- a/libs/usvfs/test/fixtures/usvfs_global_test/BasicTest/expected/mods/mod1/readme.txt +++ /dev/null diff --git a/libs/usvfs/test/fixtures/usvfs_global_test/BasicTest/source/data/file.txt b/libs/usvfs/test/fixtures/usvfs_global_test/BasicTest/source/data/file.txt deleted file mode 100644 index e69de29..0000000 --- a/libs/usvfs/test/fixtures/usvfs_global_test/BasicTest/source/data/file.txt +++ /dev/null diff --git a/libs/usvfs/test/fixtures/usvfs_global_test/BasicTest/source/mods/mod1/docs/doc.txt b/libs/usvfs/test/fixtures/usvfs_global_test/BasicTest/source/mods/mod1/docs/doc.txt deleted file mode 100644 index e69de29..0000000 --- a/libs/usvfs/test/fixtures/usvfs_global_test/BasicTest/source/mods/mod1/docs/doc.txt +++ /dev/null diff --git a/libs/usvfs/test/fixtures/usvfs_global_test/BasicTest/source/mods/mod1/empty/.gitkeep b/libs/usvfs/test/fixtures/usvfs_global_test/BasicTest/source/mods/mod1/empty/.gitkeep deleted file mode 100644 index e69de29..0000000 --- a/libs/usvfs/test/fixtures/usvfs_global_test/BasicTest/source/mods/mod1/empty/.gitkeep +++ /dev/null diff --git a/libs/usvfs/test/fixtures/usvfs_global_test/BasicTest/source/mods/mod1/info.txt b/libs/usvfs/test/fixtures/usvfs_global_test/BasicTest/source/mods/mod1/info.txt deleted file mode 100644 index e69de29..0000000 --- a/libs/usvfs/test/fixtures/usvfs_global_test/BasicTest/source/mods/mod1/info.txt +++ /dev/null diff --git a/libs/usvfs/test/fixtures/usvfs_global_test/BasicTest/source/mods/mod1/readme.txt b/libs/usvfs/test/fixtures/usvfs_global_test/BasicTest/source/mods/mod1/readme.txt deleted file mode 100644 index e69de29..0000000 --- a/libs/usvfs/test/fixtures/usvfs_global_test/BasicTest/source/mods/mod1/readme.txt +++ /dev/null diff --git a/libs/usvfs/test/fixtures/usvfs_global_test/BoostFilesystemTest/expected/data/.gitkeep b/libs/usvfs/test/fixtures/usvfs_global_test/BoostFilesystemTest/expected/data/.gitkeep deleted file mode 100644 index e69de29..0000000 --- a/libs/usvfs/test/fixtures/usvfs_global_test/BoostFilesystemTest/expected/data/.gitkeep +++ /dev/null diff --git a/libs/usvfs/test/fixtures/usvfs_global_test/BoostFilesystemTest/expected/mods/mod1/docs/doc.txt b/libs/usvfs/test/fixtures/usvfs_global_test/BoostFilesystemTest/expected/mods/mod1/docs/doc.txt deleted file mode 100644 index e69de29..0000000 --- a/libs/usvfs/test/fixtures/usvfs_global_test/BoostFilesystemTest/expected/mods/mod1/docs/doc.txt +++ /dev/null diff --git a/libs/usvfs/test/fixtures/usvfs_global_test/BoostFilesystemTest/expected/mods/mod1/docs/subdocs/.gitkeep b/libs/usvfs/test/fixtures/usvfs_global_test/BoostFilesystemTest/expected/mods/mod1/docs/subdocs/.gitkeep deleted file mode 100644 index e69de29..0000000 --- a/libs/usvfs/test/fixtures/usvfs_global_test/BoostFilesystemTest/expected/mods/mod1/docs/subdocs/.gitkeep +++ /dev/null diff --git a/libs/usvfs/test/fixtures/usvfs_global_test/BoostFilesystemTest/source/data/.gitkeep b/libs/usvfs/test/fixtures/usvfs_global_test/BoostFilesystemTest/source/data/.gitkeep deleted file mode 100644 index e69de29..0000000 --- a/libs/usvfs/test/fixtures/usvfs_global_test/BoostFilesystemTest/source/data/.gitkeep +++ /dev/null diff --git a/libs/usvfs/test/fixtures/usvfs_global_test/BoostFilesystemTest/source/mods/mod1/docs/doc.txt b/libs/usvfs/test/fixtures/usvfs_global_test/BoostFilesystemTest/source/mods/mod1/docs/doc.txt deleted file mode 100644 index e69de29..0000000 --- a/libs/usvfs/test/fixtures/usvfs_global_test/BoostFilesystemTest/source/mods/mod1/docs/doc.txt +++ /dev/null diff --git a/libs/usvfs/test/fixtures/usvfs_global_test/BoostFilesystemTest/source/mods/mod1/docs/subdocs/.gitkeep b/libs/usvfs/test/fixtures/usvfs_global_test/BoostFilesystemTest/source/mods/mod1/docs/subdocs/.gitkeep deleted file mode 100644 index e69de29..0000000 --- a/libs/usvfs/test/fixtures/usvfs_global_test/BoostFilesystemTest/source/mods/mod1/docs/subdocs/.gitkeep +++ /dev/null diff --git a/libs/usvfs/test/fixtures/usvfs_global_test/RedFileSystemTest/example.cpp b/libs/usvfs/test/fixtures/usvfs_global_test/RedFileSystemTest/example.cpp deleted file mode 100644 index 9a79d16..0000000 --- a/libs/usvfs/test/fixtures/usvfs_global_test/RedFileSystemTest/example.cpp +++ /dev/null @@ -1,139 +0,0 @@ -#include <filesystem> -#include <fstream> - -std::filesystem::path storages_path; -std::filesystem::path hudpainter_path; -bool has_mo2; - -// See below main() for implementation. -void request_directory(std::filesystem::path); -std::filesystem::path restrict_path(std::filesystem::path); -std::vector<std::filesystem::path> get_files(); -std::string read_file(std::filesystem::path); -void write_file(std::filesystem::path); - -// Expected path when not using MO2 -int main() -{ - // RedFileSystem plugin (DLL) is loaded. - has_mo2 = GetModuleHandle(TEXT("usvfs_x64.dll")) != nullptr; - - // Setup paths - auto path = std::filesystem::absolute("."); // <GAME>\bin\x64 - auto game_path = path.parent_path().parent_path(); // <GAME> - - storages_path = game_path / "r6" / "storages"; // <GAME>\r6\storages - - // Create storages directory if it is no present. - request_directory(storages_path); // <GAME>\r6\storages - - // Game is running... - - // HUD Painter request its storage endpoint. - hudpainter_path = storages_path / "HUDPainter"; - request_directory(hudpainter_path); // <GAME>\r6\storages\HUDPainter - - // HUD Painter request a file (present in archive). - auto default_path = - restrict_path("DEFAULT.json"); // <GAME>\r6\storages\HUDPainter\DEFAULT.json - - // HUD Painter read file in `default_path` with success. - auto data = read_file(default_path); // <GAME>\r6\storages\HUDPainter\DEFAULT.json - - // HUD Painter request another file. - auto test_path = - restrict_path("TEST.json"); // <GAME>\r6\storages\HUDPainter\TEST.json - - // (Bug A) HUD Painter write file in `test_path`. - write_file(test_path); // <GAME>\r6\storages\HUDPainter\TEST.json - // file is created with workaround, not created otherwise. - - // (Bug B) HUD Painter request list of files. - // TEST.json is successfully created when using workaround. - auto files = get_files(); // [0] <GAME>\r6\storages\HUDPainter\DEFAULT.json - - // files.size() == 1 - - // Expect: - // files.size() == 2 - // - // [0] <GAME>\r6\storages\HUDPainter\DEFAULT.json - // [1] <GAME>\r6\storages\HUDPainter\TEST.json -} - -// Create directory if it is no present -void request_directory(std::filesystem::path path) -{ - bool is_present = std::filesystem::exists(path); - - if (is_present) { - return; - } - std::filesystem::create_directory(path); -} - -// Resolve path for HUDPainter (security layer) -std::filesystem::path restrict_path(std::filesystem::path path) -{ - auto real_path = std::filesystem::weakly_canonical(hudpainter_path / path); - - // Workaround when using MO2 - if (has_mo2) { - return real_path; - } - // Expected implementation without MO2 - if (real_path.string().find(hudpainter_path.string() + "\\") != 0) { - // "throw" error - } - return real_path; -} - -// List files in storage of HUDPainter. -std::vector<std::filesystem::path> get_files() -{ - std::vector<std::filesystem::path> files; - auto entries = std::filesystem::directory_iterator(hudpainter_path); - - for (const auto& entry : entries) { - if (entry.is_regular_file()) { - auto file_name = entry.path().filename(); - auto file_path = - hudpainter_path / - file_name; // Culprit of bug B. When using entry.path() directly, it works. - - files.emplace_back(file_path); - } - } - return files; -} - -std::string read_file(std::filesystem::path path) -{ - std::ifstream stream; - - // With workaround: - // std::filesystem::create_directories(path.parent_path()); - stream.open(path); - if (!stream.is_open()) { - return ""; - } - std::stringstream data; - - data << stream.rdbuf(); - stream.close(); - return data.str(); -} - -void write_file(std::filesystem::path path) -{ - std::ofstream stream; - - // With workaround: - // std::filesystem::create_directories(path.parent_path()); - stream.open(path, std::ios_base::trunc); - if (!stream.is_open()) { - return; - } - stream << "<DATA>"; - stream.close(); -} diff --git a/libs/usvfs/test/fixtures/usvfs_global_test/RedFileSystemTest/expected/data/.gitkeep b/libs/usvfs/test/fixtures/usvfs_global_test/RedFileSystemTest/expected/data/.gitkeep deleted file mode 100644 index e69de29..0000000 --- a/libs/usvfs/test/fixtures/usvfs_global_test/RedFileSystemTest/expected/data/.gitkeep +++ /dev/null diff --git a/libs/usvfs/test/fixtures/usvfs_global_test/RedFileSystemTest/expected/mods/HUD Painter/r6/storages/HUDPainter/DEFAULT.json b/libs/usvfs/test/fixtures/usvfs_global_test/RedFileSystemTest/expected/mods/HUD Painter/r6/storages/HUDPainter/DEFAULT.json deleted file mode 100644 index dd85d0a..0000000 --- a/libs/usvfs/test/fixtures/usvfs_global_test/RedFileSystemTest/expected/mods/HUD Painter/r6/storages/HUDPainter/DEFAULT.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "propertiesDefault": [ - { - "name": "MainColors.Red", - "red": 1.1761, - "green": 0.3809, - "blue": 0.3476, - "alpha": 1 - } - ] -} diff --git a/libs/usvfs/test/fixtures/usvfs_global_test/RedFileSystemTest/expected/overwrite/r6/storages/HUDPainter/TEST.json b/libs/usvfs/test/fixtures/usvfs_global_test/RedFileSystemTest/expected/overwrite/r6/storages/HUDPainter/TEST.json deleted file mode 100644 index 0967ef4..0000000 --- a/libs/usvfs/test/fixtures/usvfs_global_test/RedFileSystemTest/expected/overwrite/r6/storages/HUDPainter/TEST.json +++ /dev/null @@ -1 +0,0 @@ -{} diff --git a/libs/usvfs/test/fixtures/usvfs_global_test/RedFileSystemTest/source/data/.gitkeep b/libs/usvfs/test/fixtures/usvfs_global_test/RedFileSystemTest/source/data/.gitkeep deleted file mode 100644 index e69de29..0000000 --- a/libs/usvfs/test/fixtures/usvfs_global_test/RedFileSystemTest/source/data/.gitkeep +++ /dev/null diff --git a/libs/usvfs/test/fixtures/usvfs_global_test/RedFileSystemTest/source/mods/HUD Painter/r6/storages/HUDPainter/DEFAULT.json b/libs/usvfs/test/fixtures/usvfs_global_test/RedFileSystemTest/source/mods/HUD Painter/r6/storages/HUDPainter/DEFAULT.json deleted file mode 100644 index dd85d0a..0000000 --- a/libs/usvfs/test/fixtures/usvfs_global_test/RedFileSystemTest/source/mods/HUD Painter/r6/storages/HUDPainter/DEFAULT.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "propertiesDefault": [ - { - "name": "MainColors.Red", - "red": 1.1761, - "green": 0.3809, - "blue": 0.3476, - "alpha": 1 - } - ] -} diff --git a/libs/usvfs/test/fixtures/usvfs_global_test/SkipFilesTest/expected/data/docs/doc.skip b/libs/usvfs/test/fixtures/usvfs_global_test/SkipFilesTest/expected/data/docs/doc.skip deleted file mode 100644 index 09a24fd..0000000 --- a/libs/usvfs/test/fixtures/usvfs_global_test/SkipFilesTest/expected/data/docs/doc.skip +++ /dev/null @@ -1 +0,0 @@ -doc.skip in data/docs diff --git a/libs/usvfs/test/fixtures/usvfs_global_test/SkipFilesTest/expected/data/file.txt b/libs/usvfs/test/fixtures/usvfs_global_test/SkipFilesTest/expected/data/file.txt deleted file mode 100644 index e69de29..0000000 --- a/libs/usvfs/test/fixtures/usvfs_global_test/SkipFilesTest/expected/data/file.txt +++ /dev/null diff --git a/libs/usvfs/test/fixtures/usvfs_global_test/SkipFilesTest/expected/mods/mod1/docs/doc.skip b/libs/usvfs/test/fixtures/usvfs_global_test/SkipFilesTest/expected/mods/mod1/docs/doc.skip deleted file mode 100644 index 4b8bde6..0000000 --- a/libs/usvfs/test/fixtures/usvfs_global_test/SkipFilesTest/expected/mods/mod1/docs/doc.skip +++ /dev/null @@ -1 +0,0 @@ -doc.skip in mod1/docs diff --git a/libs/usvfs/test/fixtures/usvfs_global_test/SkipFilesTest/expected/mods/mod1/docs/doc.txt b/libs/usvfs/test/fixtures/usvfs_global_test/SkipFilesTest/expected/mods/mod1/docs/doc.txt deleted file mode 100644 index e69de29..0000000 --- a/libs/usvfs/test/fixtures/usvfs_global_test/SkipFilesTest/expected/mods/mod1/docs/doc.txt +++ /dev/null diff --git a/libs/usvfs/test/fixtures/usvfs_global_test/SkipFilesTest/expected/mods/mod1/empty/.gitkeep b/libs/usvfs/test/fixtures/usvfs_global_test/SkipFilesTest/expected/mods/mod1/empty/.gitkeep deleted file mode 100644 index e69de29..0000000 --- a/libs/usvfs/test/fixtures/usvfs_global_test/SkipFilesTest/expected/mods/mod1/empty/.gitkeep +++ /dev/null diff --git a/libs/usvfs/test/fixtures/usvfs_global_test/SkipFilesTest/expected/mods/mod1/readme.skip b/libs/usvfs/test/fixtures/usvfs_global_test/SkipFilesTest/expected/mods/mod1/readme.skip deleted file mode 100644 index 1d1857a..0000000 --- a/libs/usvfs/test/fixtures/usvfs_global_test/SkipFilesTest/expected/mods/mod1/readme.skip +++ /dev/null @@ -1 +0,0 @@ -readme.skip in mod1 diff --git a/libs/usvfs/test/fixtures/usvfs_global_test/SkipFilesTest/expected/mods/mod1/readme.txt b/libs/usvfs/test/fixtures/usvfs_global_test/SkipFilesTest/expected/mods/mod1/readme.txt deleted file mode 100644 index e69de29..0000000 --- a/libs/usvfs/test/fixtures/usvfs_global_test/SkipFilesTest/expected/mods/mod1/readme.txt +++ /dev/null diff --git a/libs/usvfs/test/fixtures/usvfs_global_test/SkipFilesTest/expected/overwrite/readme.skip b/libs/usvfs/test/fixtures/usvfs_global_test/SkipFilesTest/expected/overwrite/readme.skip deleted file mode 100644 index 0062dba..0000000 --- a/libs/usvfs/test/fixtures/usvfs_global_test/SkipFilesTest/expected/overwrite/readme.skip +++ /dev/null @@ -1 +0,0 @@ -readme.skip in overwrite diff --git a/libs/usvfs/test/fixtures/usvfs_global_test/SkipFilesTest/source/data/docs/doc.skip b/libs/usvfs/test/fixtures/usvfs_global_test/SkipFilesTest/source/data/docs/doc.skip deleted file mode 100644 index 09a24fd..0000000 --- a/libs/usvfs/test/fixtures/usvfs_global_test/SkipFilesTest/source/data/docs/doc.skip +++ /dev/null @@ -1 +0,0 @@ -doc.skip in data/docs diff --git a/libs/usvfs/test/fixtures/usvfs_global_test/SkipFilesTest/source/data/file.txt b/libs/usvfs/test/fixtures/usvfs_global_test/SkipFilesTest/source/data/file.txt deleted file mode 100644 index e69de29..0000000 --- a/libs/usvfs/test/fixtures/usvfs_global_test/SkipFilesTest/source/data/file.txt +++ /dev/null diff --git a/libs/usvfs/test/fixtures/usvfs_global_test/SkipFilesTest/source/mods/mod1/docs/doc.skip b/libs/usvfs/test/fixtures/usvfs_global_test/SkipFilesTest/source/mods/mod1/docs/doc.skip deleted file mode 100644 index 4b8bde6..0000000 --- a/libs/usvfs/test/fixtures/usvfs_global_test/SkipFilesTest/source/mods/mod1/docs/doc.skip +++ /dev/null @@ -1 +0,0 @@ -doc.skip in mod1/docs diff --git a/libs/usvfs/test/fixtures/usvfs_global_test/SkipFilesTest/source/mods/mod1/docs/doc.txt b/libs/usvfs/test/fixtures/usvfs_global_test/SkipFilesTest/source/mods/mod1/docs/doc.txt deleted file mode 100644 index e69de29..0000000 --- a/libs/usvfs/test/fixtures/usvfs_global_test/SkipFilesTest/source/mods/mod1/docs/doc.txt +++ /dev/null diff --git a/libs/usvfs/test/fixtures/usvfs_global_test/SkipFilesTest/source/mods/mod1/empty/.gitkeep b/libs/usvfs/test/fixtures/usvfs_global_test/SkipFilesTest/source/mods/mod1/empty/.gitkeep deleted file mode 100644 index e69de29..0000000 --- a/libs/usvfs/test/fixtures/usvfs_global_test/SkipFilesTest/source/mods/mod1/empty/.gitkeep +++ /dev/null diff --git a/libs/usvfs/test/fixtures/usvfs_global_test/SkipFilesTest/source/mods/mod1/readme.skip b/libs/usvfs/test/fixtures/usvfs_global_test/SkipFilesTest/source/mods/mod1/readme.skip deleted file mode 100644 index 1d1857a..0000000 --- a/libs/usvfs/test/fixtures/usvfs_global_test/SkipFilesTest/source/mods/mod1/readme.skip +++ /dev/null @@ -1 +0,0 @@ -readme.skip in mod1 diff --git a/libs/usvfs/test/fixtures/usvfs_global_test/SkipFilesTest/source/mods/mod1/readme.txt b/libs/usvfs/test/fixtures/usvfs_global_test/SkipFilesTest/source/mods/mod1/readme.txt deleted file mode 100644 index e69de29..0000000 --- a/libs/usvfs/test/fixtures/usvfs_global_test/SkipFilesTest/source/mods/mod1/readme.txt +++ /dev/null diff --git a/libs/usvfs/test/fixtures/usvfs_test/basic/mount.postmortem/rfolder/rcopyme4.txt b/libs/usvfs/test/fixtures/usvfs_test/basic/mount.postmortem/rfolder/rcopyme4.txt deleted file mode 100644 index d1e44e9..0000000 --- a/libs/usvfs/test/fixtures/usvfs_test/basic/mount.postmortem/rfolder/rcopyme4.txt +++ /dev/null @@ -1 +0,0 @@ -rfolder\rcopyme4.txt original contents diff --git a/libs/usvfs/test/fixtures/usvfs_test/basic/mount.postmortem/rfolder/rfile0.txt b/libs/usvfs/test/fixtures/usvfs_test/basic/mount.postmortem/rfolder/rfile0.txt deleted file mode 100644 index 9830306..0000000 --- a/libs/usvfs/test/fixtures/usvfs_test/basic/mount.postmortem/rfolder/rfile0.txt +++ /dev/null @@ -1 +0,0 @@ -rfolder\rfile0.txt original file diff --git a/libs/usvfs/test/fixtures/usvfs_test/basic/mount.postmortem/rfolder/rfiledeletewrite.txt b/libs/usvfs/test/fixtures/usvfs_test/basic/mount.postmortem/rfolder/rfiledeletewrite.txt deleted file mode 100644 index 2743678..0000000 --- a/libs/usvfs/test/fixtures/usvfs_test/basic/mount.postmortem/rfolder/rfiledeletewrite.txt +++ /dev/null @@ -1 +0,0 @@ -rfolder\rfiledeletewrite.txt overwrite diff --git a/libs/usvfs/test/fixtures/usvfs_test/basic/mount.postmortem/rfolder/rfilerewrite.txt b/libs/usvfs/test/fixtures/usvfs_test/basic/mount.postmortem/rfolder/rfilerewrite.txt deleted file mode 100644 index bdff476..0000000 --- a/libs/usvfs/test/fixtures/usvfs_test/basic/mount.postmortem/rfolder/rfilerewrite.txt +++ /dev/null @@ -1 +0,0 @@ -rfolder\rfilerewrite.txt rewrite diff --git a/libs/usvfs/test/fixtures/usvfs_test/basic/mount.postmortem/root0.txt b/libs/usvfs/test/fixtures/usvfs_test/basic/mount.postmortem/root0.txt deleted file mode 100644 index a52b6be..0000000 --- a/libs/usvfs/test/fixtures/usvfs_test/basic/mount.postmortem/root0.txt +++ /dev/null @@ -1 +0,0 @@ -root0 original file diff --git a/libs/usvfs/test/fixtures/usvfs_test/basic/mount.postmortem/root0w.txt b/libs/usvfs/test/fixtures/usvfs_test/basic/mount.postmortem/root0w.txt deleted file mode 100644 index c177584..0000000 --- a/libs/usvfs/test/fixtures/usvfs_test/basic/mount.postmortem/root0w.txt +++ /dev/null @@ -1 +0,0 @@ -root0w original file diff --git a/libs/usvfs/test/fixtures/usvfs_test/basic/mount.postmortem/root1.txt b/libs/usvfs/test/fixtures/usvfs_test/basic/mount.postmortem/root1.txt deleted file mode 100644 index 06dc692..0000000 --- a/libs/usvfs/test/fixtures/usvfs_test/basic/mount.postmortem/root1.txt +++ /dev/null @@ -1 +0,0 @@ -root1 original file diff --git a/libs/usvfs/test/fixtures/usvfs_test/basic/mount.postmortem/root1w.txt b/libs/usvfs/test/fixtures/usvfs_test/basic/mount.postmortem/root1w.txt deleted file mode 100644 index 45172aa..0000000 --- a/libs/usvfs/test/fixtures/usvfs_test/basic/mount.postmortem/root1w.txt +++ /dev/null @@ -1 +0,0 @@ -root1w original file diff --git a/libs/usvfs/test/fixtures/usvfs_test/basic/mount/rfolder/rcopyme4.txt b/libs/usvfs/test/fixtures/usvfs_test/basic/mount/rfolder/rcopyme4.txt deleted file mode 100644 index d1e44e9..0000000 --- a/libs/usvfs/test/fixtures/usvfs_test/basic/mount/rfolder/rcopyme4.txt +++ /dev/null @@ -1 +0,0 @@ -rfolder\rcopyme4.txt original contents diff --git a/libs/usvfs/test/fixtures/usvfs_test/basic/mount/rfolder/rfile0.txt b/libs/usvfs/test/fixtures/usvfs_test/basic/mount/rfolder/rfile0.txt deleted file mode 100644 index 9830306..0000000 --- a/libs/usvfs/test/fixtures/usvfs_test/basic/mount/rfolder/rfile0.txt +++ /dev/null @@ -1 +0,0 @@ -rfolder\rfile0.txt original file diff --git a/libs/usvfs/test/fixtures/usvfs_test/basic/mount/rfolder/rfiledelete.txt b/libs/usvfs/test/fixtures/usvfs_test/basic/mount/rfolder/rfiledelete.txt deleted file mode 100644 index c19828f..0000000 --- a/libs/usvfs/test/fixtures/usvfs_test/basic/mount/rfolder/rfiledelete.txt +++ /dev/null @@ -1 +0,0 @@ -rfolder\rfiledelete.txt original file diff --git a/libs/usvfs/test/fixtures/usvfs_test/basic/mount/rfolder/rfiledeletewrite.txt b/libs/usvfs/test/fixtures/usvfs_test/basic/mount/rfolder/rfiledeletewrite.txt deleted file mode 100644 index 93861cc..0000000 --- a/libs/usvfs/test/fixtures/usvfs_test/basic/mount/rfolder/rfiledeletewrite.txt +++ /dev/null @@ -1 +0,0 @@ -rfolder\rfiledeletewrite.txt orignal file diff --git a/libs/usvfs/test/fixtures/usvfs_test/basic/mount/rfolder/rfileoldname.txt b/libs/usvfs/test/fixtures/usvfs_test/basic/mount/rfolder/rfileoldname.txt deleted file mode 100644 index 9376ea1..0000000 --- a/libs/usvfs/test/fixtures/usvfs_test/basic/mount/rfolder/rfileoldname.txt +++ /dev/null @@ -1 +0,0 @@ -rfolder\rfileoldname.txt original file diff --git a/libs/usvfs/test/fixtures/usvfs_test/basic/mount/rfolder/rfilerewrite.txt b/libs/usvfs/test/fixtures/usvfs_test/basic/mount/rfolder/rfilerewrite.txt deleted file mode 100644 index 499775d..0000000 --- a/libs/usvfs/test/fixtures/usvfs_test/basic/mount/rfolder/rfilerewrite.txt +++ /dev/null @@ -1 +0,0 @@ -rfolder\rfilerewrite.txt original file diff --git a/libs/usvfs/test/fixtures/usvfs_test/basic/mount/root0.txt b/libs/usvfs/test/fixtures/usvfs_test/basic/mount/root0.txt deleted file mode 100644 index a52b6be..0000000 --- a/libs/usvfs/test/fixtures/usvfs_test/basic/mount/root0.txt +++ /dev/null @@ -1 +0,0 @@ -root0 original file diff --git a/libs/usvfs/test/fixtures/usvfs_test/basic/mount/root0w.txt b/libs/usvfs/test/fixtures/usvfs_test/basic/mount/root0w.txt deleted file mode 100644 index c177584..0000000 --- a/libs/usvfs/test/fixtures/usvfs_test/basic/mount/root0w.txt +++ /dev/null @@ -1 +0,0 @@ -root0w original file diff --git a/libs/usvfs/test/fixtures/usvfs_test/basic/mount/root1.txt b/libs/usvfs/test/fixtures/usvfs_test/basic/mount/root1.txt deleted file mode 100644 index 06dc692..0000000 --- a/libs/usvfs/test/fixtures/usvfs_test/basic/mount/root1.txt +++ /dev/null @@ -1 +0,0 @@ -root1 original file diff --git a/libs/usvfs/test/fixtures/usvfs_test/basic/mount/root1w.txt b/libs/usvfs/test/fixtures/usvfs_test/basic/mount/root1w.txt deleted file mode 100644 index 45172aa..0000000 --- a/libs/usvfs/test/fixtures/usvfs_test/basic/mount/root1w.txt +++ /dev/null @@ -1 +0,0 @@ -root1w original file diff --git a/libs/usvfs/test/fixtures/usvfs_test/basic/source.postmortem/mod1/mfolder1/mfile.txt b/libs/usvfs/test/fixtures/usvfs_test/basic/source.postmortem/mod1/mfolder1/mfile.txt deleted file mode 100644 index 227256a..0000000 --- a/libs/usvfs/test/fixtures/usvfs_test/basic/source.postmortem/mod1/mfolder1/mfile.txt +++ /dev/null @@ -1 +0,0 @@ -mfolder1\mfile.txt by mod1 diff --git a/libs/usvfs/test/fixtures/usvfs_test/basic/source.postmortem/mod1/mfolder1/mfilew.txt b/libs/usvfs/test/fixtures/usvfs_test/basic/source.postmortem/mod1/mfolder1/mfilew.txt deleted file mode 100644 index 420589d..0000000 --- a/libs/usvfs/test/fixtures/usvfs_test/basic/source.postmortem/mod1/mfolder1/mfilew.txt +++ /dev/null @@ -1 +0,0 @@ -mfolder1\mfilew.txt by mod1 diff --git a/libs/usvfs/test/fixtures/usvfs_test/basic/source.postmortem/mod1/mfolder3/mdeep3/mfile.txt b/libs/usvfs/test/fixtures/usvfs_test/basic/source.postmortem/mod1/mfolder3/mdeep3/mfile.txt deleted file mode 100644 index 6a7a0c2..0000000 --- a/libs/usvfs/test/fixtures/usvfs_test/basic/source.postmortem/mod1/mfolder3/mdeep3/mfile.txt +++ /dev/null @@ -1 +0,0 @@ -mfolder3\mdeep3\mfile.txt by mod1 (to be hidden by mod3) diff --git a/libs/usvfs/test/fixtures/usvfs_test/basic/source.postmortem/mod1/mod1.txt b/libs/usvfs/test/fixtures/usvfs_test/basic/source.postmortem/mod1/mod1.txt deleted file mode 100644 index 7d5dc0e..0000000 --- a/libs/usvfs/test/fixtures/usvfs_test/basic/source.postmortem/mod1/mod1.txt +++ /dev/null @@ -1 +0,0 @@ -hello mod1 diff --git a/libs/usvfs/test/fixtures/usvfs_test/basic/source.postmortem/mod1/mod1w.txt b/libs/usvfs/test/fixtures/usvfs_test/basic/source.postmortem/mod1/mod1w.txt deleted file mode 100644 index 1838cdf..0000000 --- a/libs/usvfs/test/fixtures/usvfs_test/basic/source.postmortem/mod1/mod1w.txt +++ /dev/null @@ -1 +0,0 @@ -hello mod1w diff --git a/libs/usvfs/test/fixtures/usvfs_test/basic/source.postmortem/mod2/mfolder2/mfile.txt b/libs/usvfs/test/fixtures/usvfs_test/basic/source.postmortem/mod2/mfolder2/mfile.txt deleted file mode 100644 index 8ff096e..0000000 --- a/libs/usvfs/test/fixtures/usvfs_test/basic/source.postmortem/mod2/mfolder2/mfile.txt +++ /dev/null @@ -1 +0,0 @@ -mfolder2\mfile.txt by mod2 diff --git a/libs/usvfs/test/fixtures/usvfs_test/basic/source.postmortem/mod2/mfolder4/mfile.txt b/libs/usvfs/test/fixtures/usvfs_test/basic/source.postmortem/mod2/mfolder4/mfile.txt deleted file mode 100644 index c0f0f2c..0000000 --- a/libs/usvfs/test/fixtures/usvfs_test/basic/source.postmortem/mod2/mfolder4/mfile.txt +++ /dev/null @@ -1 +0,0 @@ -mfolder4\mfile.txt by mod2 (to be hidden by mod4) diff --git a/libs/usvfs/test/fixtures/usvfs_test/basic/source.postmortem/mod2/mfolder4/mfiledeletemove.txt b/libs/usvfs/test/fixtures/usvfs_test/basic/source.postmortem/mod2/mfolder4/mfiledeletemove.txt deleted file mode 100644 index e35f1f3..0000000 --- a/libs/usvfs/test/fixtures/usvfs_test/basic/source.postmortem/mod2/mfolder4/mfiledeletemove.txt +++ /dev/null @@ -1 +0,0 @@ -mfolder4/mfiledeletemove.txt by mod2 (to be hidden by mod4) diff --git a/libs/usvfs/test/fixtures/usvfs_test/basic/source.postmortem/mod2/mfolder4/mfiledeletemove2p.txt b/libs/usvfs/test/fixtures/usvfs_test/basic/source.postmortem/mod2/mfolder4/mfiledeletemove2p.txt deleted file mode 100644 index cc572dc..0000000 --- a/libs/usvfs/test/fixtures/usvfs_test/basic/source.postmortem/mod2/mfolder4/mfiledeletemove2p.txt +++ /dev/null @@ -1 +0,0 @@ -mfolder4/mfiledeletemove2p.txt by mod2 (to be hidden by mod4) diff --git a/libs/usvfs/test/fixtures/usvfs_test/basic/source.postmortem/mod2/mfolder4/mfiledeletewrite.txt b/libs/usvfs/test/fixtures/usvfs_test/basic/source.postmortem/mod2/mfolder4/mfiledeletewrite.txt deleted file mode 100644 index f699360..0000000 --- a/libs/usvfs/test/fixtures/usvfs_test/basic/source.postmortem/mod2/mfolder4/mfiledeletewrite.txt +++ /dev/null @@ -1 +0,0 @@ -mfolder4/mfiledeletewrite.txt by mod2 (to be hidden by mod4) diff --git a/libs/usvfs/test/fixtures/usvfs_test/basic/source.postmortem/mod2/mfolder4/mfiledeletewrite2p.txt b/libs/usvfs/test/fixtures/usvfs_test/basic/source.postmortem/mod2/mfolder4/mfiledeletewrite2p.txt deleted file mode 100644 index 9eae9c5..0000000 --- a/libs/usvfs/test/fixtures/usvfs_test/basic/source.postmortem/mod2/mfolder4/mfiledeletewrite2p.txt +++ /dev/null @@ -1 +0,0 @@ -mfolder4/mfiledeletewrite2p.txt by mod2 (to be hidden by mod4) diff --git a/libs/usvfs/test/fixtures/usvfs_test/basic/source.postmortem/mod2/mfolder4/mfilemoveover.txt b/libs/usvfs/test/fixtures/usvfs_test/basic/source.postmortem/mod2/mfolder4/mfilemoveover.txt deleted file mode 100644 index 88a6d08..0000000 --- a/libs/usvfs/test/fixtures/usvfs_test/basic/source.postmortem/mod2/mfolder4/mfilemoveover.txt +++ /dev/null @@ -1 +0,0 @@ -mfolder4/mfilemoveover.txt by mod2 (to be hidden by mod4) diff --git a/libs/usvfs/test/fixtures/usvfs_test/basic/source.postmortem/mod2/mfolder4/mfileoverwrite.txt b/libs/usvfs/test/fixtures/usvfs_test/basic/source.postmortem/mod2/mfolder4/mfileoverwrite.txt deleted file mode 100644 index 61b92a6..0000000 --- a/libs/usvfs/test/fixtures/usvfs_test/basic/source.postmortem/mod2/mfolder4/mfileoverwrite.txt +++ /dev/null @@ -1 +0,0 @@ -mfolder4\mfileoverwrite.txt by mod2 (to be hidden by mod4) diff --git a/libs/usvfs/test/fixtures/usvfs_test/basic/source.postmortem/mod2/mfolder4/mfilerewrite.txt b/libs/usvfs/test/fixtures/usvfs_test/basic/source.postmortem/mod2/mfolder4/mfilerewrite.txt deleted file mode 100644 index 727a48f..0000000 --- a/libs/usvfs/test/fixtures/usvfs_test/basic/source.postmortem/mod2/mfolder4/mfilerewrite.txt +++ /dev/null @@ -1 +0,0 @@ -mfolder4\mfilerewrite.txt by mod2 (to be hidden by mod4) diff --git a/libs/usvfs/test/fixtures/usvfs_test/basic/source.postmortem/mod2/mod2.txt b/libs/usvfs/test/fixtures/usvfs_test/basic/source.postmortem/mod2/mod2.txt deleted file mode 100644 index 49bbbf1..0000000 --- a/libs/usvfs/test/fixtures/usvfs_test/basic/source.postmortem/mod2/mod2.txt +++ /dev/null @@ -1 +0,0 @@ -hello mod2 diff --git a/libs/usvfs/test/fixtures/usvfs_test/basic/source.postmortem/mod3/mfolder3/mdeep3/mfile.txt b/libs/usvfs/test/fixtures/usvfs_test/basic/source.postmortem/mod3/mfolder3/mdeep3/mfile.txt deleted file mode 100644 index fac8213..0000000 --- a/libs/usvfs/test/fixtures/usvfs_test/basic/source.postmortem/mod3/mfolder3/mdeep3/mfile.txt +++ /dev/null @@ -1 +0,0 @@ -mfolder3\mdeep3\mfile.txt by mod3 diff --git a/libs/usvfs/test/fixtures/usvfs_test/basic/source.postmortem/mod3/mfolder4/mfile.txt b/libs/usvfs/test/fixtures/usvfs_test/basic/source.postmortem/mod3/mfolder4/mfile.txt deleted file mode 100644 index 5e6ca00..0000000 --- a/libs/usvfs/test/fixtures/usvfs_test/basic/source.postmortem/mod3/mfolder4/mfile.txt +++ /dev/null @@ -1 +0,0 @@ -mfolder4\mfile.txt by mod3 (to be hidden by mod4) diff --git a/libs/usvfs/test/fixtures/usvfs_test/basic/source.postmortem/mod3/mod3.txt b/libs/usvfs/test/fixtures/usvfs_test/basic/source.postmortem/mod3/mod3.txt deleted file mode 100644 index 47fbacd..0000000 --- a/libs/usvfs/test/fixtures/usvfs_test/basic/source.postmortem/mod3/mod3.txt +++ /dev/null @@ -1 +0,0 @@ -hello mod3 diff --git a/libs/usvfs/test/fixtures/usvfs_test/basic/source.postmortem/mod4/mfolder4/mfile.txt b/libs/usvfs/test/fixtures/usvfs_test/basic/source.postmortem/mod4/mfolder4/mfile.txt deleted file mode 100644 index c67ecfe..0000000 --- a/libs/usvfs/test/fixtures/usvfs_test/basic/source.postmortem/mod4/mfolder4/mfile.txt +++ /dev/null @@ -1 +0,0 @@ -mfolder4\mfile.txt by mod4 diff --git a/libs/usvfs/test/fixtures/usvfs_test/basic/source.postmortem/mod4/mfolder4/mfiledeletemove.txt b/libs/usvfs/test/fixtures/usvfs_test/basic/source.postmortem/mod4/mfolder4/mfiledeletemove.txt deleted file mode 100644 index 00cc0cd..0000000 --- a/libs/usvfs/test/fixtures/usvfs_test/basic/source.postmortem/mod4/mfolder4/mfiledeletemove.txt +++ /dev/null @@ -1 +0,0 @@ -mfolder4\mfiledeletemove.txt overwrite diff --git a/libs/usvfs/test/fixtures/usvfs_test/basic/source.postmortem/mod4/mfolder4/mfiledeletewrite.txt b/libs/usvfs/test/fixtures/usvfs_test/basic/source.postmortem/mod4/mfolder4/mfiledeletewrite.txt deleted file mode 100644 index 083a6b8..0000000 --- a/libs/usvfs/test/fixtures/usvfs_test/basic/source.postmortem/mod4/mfolder4/mfiledeletewrite.txt +++ /dev/null @@ -1 +0,0 @@ -mfolder4\mfiledeletewrite.txt overwrite diff --git a/libs/usvfs/test/fixtures/usvfs_test/basic/source.postmortem/mod4/mfolder4/mfilemoveover.txt b/libs/usvfs/test/fixtures/usvfs_test/basic/source.postmortem/mod4/mfolder4/mfilemoveover.txt deleted file mode 100644 index a8a93c2..0000000 --- a/libs/usvfs/test/fixtures/usvfs_test/basic/source.postmortem/mod4/mfolder4/mfilemoveover.txt +++ /dev/null @@ -1 +0,0 @@ -mfolder4\mfilemoveover.txt overwrite diff --git a/libs/usvfs/test/fixtures/usvfs_test/basic/source.postmortem/mod4/mfolder4/mfileoverwrite.txt b/libs/usvfs/test/fixtures/usvfs_test/basic/source.postmortem/mod4/mfolder4/mfileoverwrite.txt deleted file mode 100644 index fc6d42f..0000000 --- a/libs/usvfs/test/fixtures/usvfs_test/basic/source.postmortem/mod4/mfolder4/mfileoverwrite.txt +++ /dev/null @@ -1 +0,0 @@ -mfolder4\mfileoverwrite.txt overwrite diff --git a/libs/usvfs/test/fixtures/usvfs_test/basic/source.postmortem/mod4/mfolder4/mfilerewrite.txt b/libs/usvfs/test/fixtures/usvfs_test/basic/source.postmortem/mod4/mfolder4/mfilerewrite.txt deleted file mode 100644 index a3b8ced..0000000 --- a/libs/usvfs/test/fixtures/usvfs_test/basic/source.postmortem/mod4/mfolder4/mfilerewrite.txt +++ /dev/null @@ -1 +0,0 @@ -mfolder4\mfilerewrite.txt rewrite diff --git a/libs/usvfs/test/fixtures/usvfs_test/basic/source.postmortem/overwrite/.empty b/libs/usvfs/test/fixtures/usvfs_test/basic/source.postmortem/overwrite/.empty deleted file mode 100644 index e69de29..0000000 --- a/libs/usvfs/test/fixtures/usvfs_test/basic/source.postmortem/overwrite/.empty +++ /dev/null diff --git a/libs/usvfs/test/fixtures/usvfs_test/basic/source.postmortem/overwrite/mfolder1/newfile1.txt b/libs/usvfs/test/fixtures/usvfs_test/basic/source.postmortem/overwrite/mfolder1/newfile1.txt deleted file mode 100644 index bf76f1d..0000000 --- a/libs/usvfs/test/fixtures/usvfs_test/basic/source.postmortem/overwrite/mfolder1/newfile1.txt +++ /dev/null @@ -1 +0,0 @@ -newfile1.txt nonrecursive overwrite diff --git a/libs/usvfs/test/fixtures/usvfs_test/basic/source.postmortem/overwrite/mfolder1/newfolder1/newfile1.txt b/libs/usvfs/test/fixtures/usvfs_test/basic/source.postmortem/overwrite/mfolder1/newfolder1/newfile1.txt deleted file mode 100644 index 4802577..0000000 --- a/libs/usvfs/test/fixtures/usvfs_test/basic/source.postmortem/overwrite/mfolder1/newfolder1/newfile1.txt +++ /dev/null @@ -1 +0,0 @@ -newfile1.txt nonrecursive overwrite subfolder diff --git a/libs/usvfs/test/fixtures/usvfs_test/basic/source.postmortem/overwrite/mfolder2/newfile2.txt b/libs/usvfs/test/fixtures/usvfs_test/basic/source.postmortem/overwrite/mfolder2/newfile2.txt deleted file mode 100644 index a4fa7fc..0000000 --- a/libs/usvfs/test/fixtures/usvfs_test/basic/source.postmortem/overwrite/mfolder2/newfile2.txt +++ /dev/null @@ -1 +0,0 @@ -newfile2.txt recursive overwrite diff --git a/libs/usvfs/test/fixtures/usvfs_test/basic/source.postmortem/overwrite/mfolder3/newfolder3/newfile3.txt b/libs/usvfs/test/fixtures/usvfs_test/basic/source.postmortem/overwrite/mfolder3/newfolder3/newfile3.txt deleted file mode 100644 index 933eb0c..0000000 --- a/libs/usvfs/test/fixtures/usvfs_test/basic/source.postmortem/overwrite/mfolder3/newfolder3/newfile3.txt +++ /dev/null @@ -1 +0,0 @@ -newfile3.txt recursive overwrite diff --git a/libs/usvfs/test/fixtures/usvfs_test/basic/source.postmortem/overwrite/mfolder3/newfolder3/newfile3e.txt b/libs/usvfs/test/fixtures/usvfs_test/basic/source.postmortem/overwrite/mfolder3/newfolder3/newfile3e.txt deleted file mode 100644 index 5e5286a..0000000 --- a/libs/usvfs/test/fixtures/usvfs_test/basic/source.postmortem/overwrite/mfolder3/newfolder3/newfile3e.txt +++ /dev/null @@ -1 +0,0 @@ -newfile3e.txt recursive overwrite diff --git a/libs/usvfs/test/fixtures/usvfs_test/basic/source.postmortem/overwrite/mfolder4/mfiledeletemove2p.txt b/libs/usvfs/test/fixtures/usvfs_test/basic/source.postmortem/overwrite/mfolder4/mfiledeletemove2p.txt deleted file mode 100644 index 6b85a92..0000000 --- a/libs/usvfs/test/fixtures/usvfs_test/basic/source.postmortem/overwrite/mfolder4/mfiledeletemove2p.txt +++ /dev/null @@ -1 +0,0 @@ -mfolder4\mfiledeletemove2p.txt overwrite diff --git a/libs/usvfs/test/fixtures/usvfs_test/basic/source.postmortem/overwrite/mfolder4/mfiledeletewrite2p.txt b/libs/usvfs/test/fixtures/usvfs_test/basic/source.postmortem/overwrite/mfolder4/mfiledeletewrite2p.txt deleted file mode 100644 index 64cac84..0000000 --- a/libs/usvfs/test/fixtures/usvfs_test/basic/source.postmortem/overwrite/mfolder4/mfiledeletewrite2p.txt +++ /dev/null @@ -1 +0,0 @@ -mfolder4\mfiledeletewrite2p.txt overwrite diff --git a/libs/usvfs/test/fixtures/usvfs_test/basic/source.postmortem/overwrite/mfolder4/newfolder4/d/e/e/p/newfile4.txt b/libs/usvfs/test/fixtures/usvfs_test/basic/source.postmortem/overwrite/mfolder4/newfolder4/d/e/e/p/newfile4.txt deleted file mode 100644 index cba5361..0000000 --- a/libs/usvfs/test/fixtures/usvfs_test/basic/source.postmortem/overwrite/mfolder4/newfolder4/d/e/e/p/newfile4.txt +++ /dev/null @@ -1 +0,0 @@ -newfile4.txt recursive overwrite diff --git a/libs/usvfs/test/fixtures/usvfs_test/basic/source.postmortem/overwrite/mfolder4/newfolder4/d/e/e/p/newfile4e.txt b/libs/usvfs/test/fixtures/usvfs_test/basic/source.postmortem/overwrite/mfolder4/newfolder4/d/e/e/p/newfile4e.txt deleted file mode 100644 index eb90089..0000000 --- a/libs/usvfs/test/fixtures/usvfs_test/basic/source.postmortem/overwrite/mfolder4/newfolder4/d/e/e/p/newfile4e.txt +++ /dev/null @@ -1 +0,0 @@ -newfile4e.txt recursive overwrite diff --git a/libs/usvfs/test/fixtures/usvfs_test/basic/source.postmortem/overwrite/mfolder4/newfolder4/d/e/e/p/newfile4enr.txt b/libs/usvfs/test/fixtures/usvfs_test/basic/source.postmortem/overwrite/mfolder4/newfolder4/d/e/e/p/newfile4enr.txt deleted file mode 100644 index f8b5f9f..0000000 --- a/libs/usvfs/test/fixtures/usvfs_test/basic/source.postmortem/overwrite/mfolder4/newfolder4/d/e/e/p/newfile4enr.txt +++ /dev/null @@ -1 +0,0 @@ -newfile4enr.txt nonrecursive overwrite diff --git a/libs/usvfs/test/fixtures/usvfs_test/basic/source.postmortem/overwrite/mfolder4/newfolder4/d/e/epnewfile4.txt b/libs/usvfs/test/fixtures/usvfs_test/basic/source.postmortem/overwrite/mfolder4/newfolder4/d/e/epnewfile4.txt deleted file mode 100644 index 06edab8..0000000 --- a/libs/usvfs/test/fixtures/usvfs_test/basic/source.postmortem/overwrite/mfolder4/newfolder4/d/e/epnewfile4.txt +++ /dev/null @@ -1 +0,0 @@ -epnewfile4.txt nonrecursive overwrite diff --git a/libs/usvfs/test/fixtures/usvfs_test/basic/source.postmortem/overwrite/mfolder4/newfolder4/d/e/epnewfile4r.txt b/libs/usvfs/test/fixtures/usvfs_test/basic/source.postmortem/overwrite/mfolder4/newfolder4/d/e/epnewfile4r.txt deleted file mode 100644 index 8fd183d..0000000 --- a/libs/usvfs/test/fixtures/usvfs_test/basic/source.postmortem/overwrite/mfolder4/newfolder4/d/e/epnewfile4r.txt +++ /dev/null @@ -1 +0,0 @@ -epnewfile4r.txt recursive overwrite diff --git a/libs/usvfs/test/fixtures/usvfs_test/basic/source.postmortem/overwrite/mfolder4/newfolder4p/rcopyme4.txt b/libs/usvfs/test/fixtures/usvfs_test/basic/source.postmortem/overwrite/mfolder4/newfolder4p/rcopyme4.txt deleted file mode 100644 index d1e44e9..0000000 --- a/libs/usvfs/test/fixtures/usvfs_test/basic/source.postmortem/overwrite/mfolder4/newfolder4p/rcopyme4.txt +++ /dev/null @@ -1 +0,0 @@ -rfolder\rcopyme4.txt original contents diff --git a/libs/usvfs/test/fixtures/usvfs_test/basic/source.postmortem/overwrite/mfolder4/rcopyme4.txt b/libs/usvfs/test/fixtures/usvfs_test/basic/source.postmortem/overwrite/mfolder4/rcopyme4.txt deleted file mode 100644 index d1e44e9..0000000 --- a/libs/usvfs/test/fixtures/usvfs_test/basic/source.postmortem/overwrite/mfolder4/rcopyme4.txt +++ /dev/null @@ -1 +0,0 @@ -rfolder\rcopyme4.txt original contents diff --git a/libs/usvfs/test/fixtures/usvfs_test/basic/source.postmortem/overwrite/rfolder/rfilenewname.txt b/libs/usvfs/test/fixtures/usvfs_test/basic/source.postmortem/overwrite/rfolder/rfilenewname.txt deleted file mode 100644 index 9376ea1..0000000 --- a/libs/usvfs/test/fixtures/usvfs_test/basic/source.postmortem/overwrite/rfolder/rfilenewname.txt +++ /dev/null @@ -1 +0,0 @@ -rfolder\rfileoldname.txt original file diff --git a/libs/usvfs/test/fixtures/usvfs_test/basic/source.postmortem/root1.txt b/libs/usvfs/test/fixtures/usvfs_test/basic/source.postmortem/root1.txt deleted file mode 100644 index 5aa129b..0000000 --- a/libs/usvfs/test/fixtures/usvfs_test/basic/source.postmortem/root1.txt +++ /dev/null @@ -1 +0,0 @@ -root1 source file diff --git a/libs/usvfs/test/fixtures/usvfs_test/basic/source.postmortem/root1w.txt b/libs/usvfs/test/fixtures/usvfs_test/basic/source.postmortem/root1w.txt deleted file mode 100644 index 0c04aa5..0000000 --- a/libs/usvfs/test/fixtures/usvfs_test/basic/source.postmortem/root1w.txt +++ /dev/null @@ -1 +0,0 @@ -root1w source file diff --git a/libs/usvfs/test/fixtures/usvfs_test/basic/source.postmortem/root2.txt b/libs/usvfs/test/fixtures/usvfs_test/basic/source.postmortem/root2.txt deleted file mode 100644 index 4ac40bb..0000000 --- a/libs/usvfs/test/fixtures/usvfs_test/basic/source.postmortem/root2.txt +++ /dev/null @@ -1 +0,0 @@ -root2 source file diff --git a/libs/usvfs/test/fixtures/usvfs_test/basic/source.postmortem/root2w.txt b/libs/usvfs/test/fixtures/usvfs_test/basic/source.postmortem/root2w.txt deleted file mode 100644 index 83ddb42..0000000 --- a/libs/usvfs/test/fixtures/usvfs_test/basic/source.postmortem/root2w.txt +++ /dev/null @@ -1 +0,0 @@ -root2w source file diff --git a/libs/usvfs/test/fixtures/usvfs_test/basic/source/mod1/mfolder1/mfile.txt b/libs/usvfs/test/fixtures/usvfs_test/basic/source/mod1/mfolder1/mfile.txt deleted file mode 100644 index 227256a..0000000 --- a/libs/usvfs/test/fixtures/usvfs_test/basic/source/mod1/mfolder1/mfile.txt +++ /dev/null @@ -1 +0,0 @@ -mfolder1\mfile.txt by mod1 diff --git a/libs/usvfs/test/fixtures/usvfs_test/basic/source/mod1/mfolder1/mfilew.txt b/libs/usvfs/test/fixtures/usvfs_test/basic/source/mod1/mfolder1/mfilew.txt deleted file mode 100644 index 420589d..0000000 --- a/libs/usvfs/test/fixtures/usvfs_test/basic/source/mod1/mfolder1/mfilew.txt +++ /dev/null @@ -1 +0,0 @@ -mfolder1\mfilew.txt by mod1 diff --git a/libs/usvfs/test/fixtures/usvfs_test/basic/source/mod1/mfolder3/mdeep3/mfile.txt b/libs/usvfs/test/fixtures/usvfs_test/basic/source/mod1/mfolder3/mdeep3/mfile.txt deleted file mode 100644 index 6a7a0c2..0000000 --- a/libs/usvfs/test/fixtures/usvfs_test/basic/source/mod1/mfolder3/mdeep3/mfile.txt +++ /dev/null @@ -1 +0,0 @@ -mfolder3\mdeep3\mfile.txt by mod1 (to be hidden by mod3) diff --git a/libs/usvfs/test/fixtures/usvfs_test/basic/source/mod1/mod1.txt b/libs/usvfs/test/fixtures/usvfs_test/basic/source/mod1/mod1.txt deleted file mode 100644 index 7d5dc0e..0000000 --- a/libs/usvfs/test/fixtures/usvfs_test/basic/source/mod1/mod1.txt +++ /dev/null @@ -1 +0,0 @@ -hello mod1 diff --git a/libs/usvfs/test/fixtures/usvfs_test/basic/source/mod1/mod1w.txt b/libs/usvfs/test/fixtures/usvfs_test/basic/source/mod1/mod1w.txt deleted file mode 100644 index 1838cdf..0000000 --- a/libs/usvfs/test/fixtures/usvfs_test/basic/source/mod1/mod1w.txt +++ /dev/null @@ -1 +0,0 @@ -hello mod1w diff --git a/libs/usvfs/test/fixtures/usvfs_test/basic/source/mod2/mfolder2/mfile.txt b/libs/usvfs/test/fixtures/usvfs_test/basic/source/mod2/mfolder2/mfile.txt deleted file mode 100644 index 8ff096e..0000000 --- a/libs/usvfs/test/fixtures/usvfs_test/basic/source/mod2/mfolder2/mfile.txt +++ /dev/null @@ -1 +0,0 @@ -mfolder2\mfile.txt by mod2 diff --git a/libs/usvfs/test/fixtures/usvfs_test/basic/source/mod2/mfolder4/mfile.txt b/libs/usvfs/test/fixtures/usvfs_test/basic/source/mod2/mfolder4/mfile.txt deleted file mode 100644 index c0f0f2c..0000000 --- a/libs/usvfs/test/fixtures/usvfs_test/basic/source/mod2/mfolder4/mfile.txt +++ /dev/null @@ -1 +0,0 @@ -mfolder4\mfile.txt by mod2 (to be hidden by mod4) diff --git a/libs/usvfs/test/fixtures/usvfs_test/basic/source/mod2/mfolder4/mfiledeletemove.txt b/libs/usvfs/test/fixtures/usvfs_test/basic/source/mod2/mfolder4/mfiledeletemove.txt deleted file mode 100644 index e35f1f3..0000000 --- a/libs/usvfs/test/fixtures/usvfs_test/basic/source/mod2/mfolder4/mfiledeletemove.txt +++ /dev/null @@ -1 +0,0 @@ -mfolder4/mfiledeletemove.txt by mod2 (to be hidden by mod4) diff --git a/libs/usvfs/test/fixtures/usvfs_test/basic/source/mod2/mfolder4/mfiledeletemove2p.txt b/libs/usvfs/test/fixtures/usvfs_test/basic/source/mod2/mfolder4/mfiledeletemove2p.txt deleted file mode 100644 index cc572dc..0000000 --- a/libs/usvfs/test/fixtures/usvfs_test/basic/source/mod2/mfolder4/mfiledeletemove2p.txt +++ /dev/null @@ -1 +0,0 @@ -mfolder4/mfiledeletemove2p.txt by mod2 (to be hidden by mod4) diff --git a/libs/usvfs/test/fixtures/usvfs_test/basic/source/mod2/mfolder4/mfiledeletewrite.txt b/libs/usvfs/test/fixtures/usvfs_test/basic/source/mod2/mfolder4/mfiledeletewrite.txt deleted file mode 100644 index f699360..0000000 --- a/libs/usvfs/test/fixtures/usvfs_test/basic/source/mod2/mfolder4/mfiledeletewrite.txt +++ /dev/null @@ -1 +0,0 @@ -mfolder4/mfiledeletewrite.txt by mod2 (to be hidden by mod4) diff --git a/libs/usvfs/test/fixtures/usvfs_test/basic/source/mod2/mfolder4/mfiledeletewrite2p.txt b/libs/usvfs/test/fixtures/usvfs_test/basic/source/mod2/mfolder4/mfiledeletewrite2p.txt deleted file mode 100644 index 9eae9c5..0000000 --- a/libs/usvfs/test/fixtures/usvfs_test/basic/source/mod2/mfolder4/mfiledeletewrite2p.txt +++ /dev/null @@ -1 +0,0 @@ -mfolder4/mfiledeletewrite2p.txt by mod2 (to be hidden by mod4) diff --git a/libs/usvfs/test/fixtures/usvfs_test/basic/source/mod2/mfolder4/mfilemoveover.txt b/libs/usvfs/test/fixtures/usvfs_test/basic/source/mod2/mfolder4/mfilemoveover.txt deleted file mode 100644 index 88a6d08..0000000 --- a/libs/usvfs/test/fixtures/usvfs_test/basic/source/mod2/mfolder4/mfilemoveover.txt +++ /dev/null @@ -1 +0,0 @@ -mfolder4/mfilemoveover.txt by mod2 (to be hidden by mod4) diff --git a/libs/usvfs/test/fixtures/usvfs_test/basic/source/mod2/mfolder4/mfileoverwrite.txt b/libs/usvfs/test/fixtures/usvfs_test/basic/source/mod2/mfolder4/mfileoverwrite.txt deleted file mode 100644 index 61b92a6..0000000 --- a/libs/usvfs/test/fixtures/usvfs_test/basic/source/mod2/mfolder4/mfileoverwrite.txt +++ /dev/null @@ -1 +0,0 @@ -mfolder4\mfileoverwrite.txt by mod2 (to be hidden by mod4) diff --git a/libs/usvfs/test/fixtures/usvfs_test/basic/source/mod2/mfolder4/mfilerewrite.txt b/libs/usvfs/test/fixtures/usvfs_test/basic/source/mod2/mfolder4/mfilerewrite.txt deleted file mode 100644 index 727a48f..0000000 --- a/libs/usvfs/test/fixtures/usvfs_test/basic/source/mod2/mfolder4/mfilerewrite.txt +++ /dev/null @@ -1 +0,0 @@ -mfolder4\mfilerewrite.txt by mod2 (to be hidden by mod4) diff --git a/libs/usvfs/test/fixtures/usvfs_test/basic/source/mod2/mod2.txt b/libs/usvfs/test/fixtures/usvfs_test/basic/source/mod2/mod2.txt deleted file mode 100644 index 49bbbf1..0000000 --- a/libs/usvfs/test/fixtures/usvfs_test/basic/source/mod2/mod2.txt +++ /dev/null @@ -1 +0,0 @@ -hello mod2 diff --git a/libs/usvfs/test/fixtures/usvfs_test/basic/source/mod3/mfolder3/mdeep3/mfile.txt b/libs/usvfs/test/fixtures/usvfs_test/basic/source/mod3/mfolder3/mdeep3/mfile.txt deleted file mode 100644 index fac8213..0000000 --- a/libs/usvfs/test/fixtures/usvfs_test/basic/source/mod3/mfolder3/mdeep3/mfile.txt +++ /dev/null @@ -1 +0,0 @@ -mfolder3\mdeep3\mfile.txt by mod3 diff --git a/libs/usvfs/test/fixtures/usvfs_test/basic/source/mod3/mfolder4/mfile.txt b/libs/usvfs/test/fixtures/usvfs_test/basic/source/mod3/mfolder4/mfile.txt deleted file mode 100644 index 5e6ca00..0000000 --- a/libs/usvfs/test/fixtures/usvfs_test/basic/source/mod3/mfolder4/mfile.txt +++ /dev/null @@ -1 +0,0 @@ -mfolder4\mfile.txt by mod3 (to be hidden by mod4) diff --git a/libs/usvfs/test/fixtures/usvfs_test/basic/source/mod3/mod3.txt b/libs/usvfs/test/fixtures/usvfs_test/basic/source/mod3/mod3.txt deleted file mode 100644 index 47fbacd..0000000 --- a/libs/usvfs/test/fixtures/usvfs_test/basic/source/mod3/mod3.txt +++ /dev/null @@ -1 +0,0 @@ -hello mod3 diff --git a/libs/usvfs/test/fixtures/usvfs_test/basic/source/mod4/mfolder4/mfile.txt b/libs/usvfs/test/fixtures/usvfs_test/basic/source/mod4/mfolder4/mfile.txt deleted file mode 100644 index c67ecfe..0000000 --- a/libs/usvfs/test/fixtures/usvfs_test/basic/source/mod4/mfolder4/mfile.txt +++ /dev/null @@ -1 +0,0 @@ -mfolder4\mfile.txt by mod4 diff --git a/libs/usvfs/test/fixtures/usvfs_test/basic/source/mod4/mfolder4/mfiledeletemove.txt b/libs/usvfs/test/fixtures/usvfs_test/basic/source/mod4/mfolder4/mfiledeletemove.txt deleted file mode 100644 index 657f07d..0000000 --- a/libs/usvfs/test/fixtures/usvfs_test/basic/source/mod4/mfolder4/mfiledeletemove.txt +++ /dev/null @@ -1 +0,0 @@ -mfolder4/mfiledeletemove.txt by mod4 diff --git a/libs/usvfs/test/fixtures/usvfs_test/basic/source/mod4/mfolder4/mfiledeletemove2p.txt b/libs/usvfs/test/fixtures/usvfs_test/basic/source/mod4/mfolder4/mfiledeletemove2p.txt deleted file mode 100644 index cfd08dd..0000000 --- a/libs/usvfs/test/fixtures/usvfs_test/basic/source/mod4/mfolder4/mfiledeletemove2p.txt +++ /dev/null @@ -1 +0,0 @@ -mfolder4/mfiledeletemove2p.txt by mod4 diff --git a/libs/usvfs/test/fixtures/usvfs_test/basic/source/mod4/mfolder4/mfiledeletewrite.txt b/libs/usvfs/test/fixtures/usvfs_test/basic/source/mod4/mfolder4/mfiledeletewrite.txt deleted file mode 100644 index a17d129..0000000 --- a/libs/usvfs/test/fixtures/usvfs_test/basic/source/mod4/mfolder4/mfiledeletewrite.txt +++ /dev/null @@ -1 +0,0 @@ -mfolder4/mfiledeletewrite.txt by mod4 diff --git a/libs/usvfs/test/fixtures/usvfs_test/basic/source/mod4/mfolder4/mfiledeletewrite2p.txt b/libs/usvfs/test/fixtures/usvfs_test/basic/source/mod4/mfolder4/mfiledeletewrite2p.txt deleted file mode 100644 index b198d1c..0000000 --- a/libs/usvfs/test/fixtures/usvfs_test/basic/source/mod4/mfolder4/mfiledeletewrite2p.txt +++ /dev/null @@ -1 +0,0 @@ -mfolder4/mfiledeletewrite2p.txt by mod4 diff --git a/libs/usvfs/test/fixtures/usvfs_test/basic/source/mod4/mfolder4/mfilemoveover.txt b/libs/usvfs/test/fixtures/usvfs_test/basic/source/mod4/mfolder4/mfilemoveover.txt deleted file mode 100644 index b395908..0000000 --- a/libs/usvfs/test/fixtures/usvfs_test/basic/source/mod4/mfolder4/mfilemoveover.txt +++ /dev/null @@ -1 +0,0 @@ -mfolder4/mfilemoveover.txt by mod4 diff --git a/libs/usvfs/test/fixtures/usvfs_test/basic/source/mod4/mfolder4/mfileoverwrite.txt b/libs/usvfs/test/fixtures/usvfs_test/basic/source/mod4/mfolder4/mfileoverwrite.txt deleted file mode 100644 index 405c0c1..0000000 --- a/libs/usvfs/test/fixtures/usvfs_test/basic/source/mod4/mfolder4/mfileoverwrite.txt +++ /dev/null @@ -1 +0,0 @@ -mfolder4\mfileoverwrite.txt by mod4 diff --git a/libs/usvfs/test/fixtures/usvfs_test/basic/source/mod4/mfolder4/mfilerewrite.txt b/libs/usvfs/test/fixtures/usvfs_test/basic/source/mod4/mfolder4/mfilerewrite.txt deleted file mode 100644 index def973c..0000000 --- a/libs/usvfs/test/fixtures/usvfs_test/basic/source/mod4/mfolder4/mfilerewrite.txt +++ /dev/null @@ -1 +0,0 @@ -mfolder4\mfilerewrite.txt by mod4 diff --git a/libs/usvfs/test/fixtures/usvfs_test/basic/source/overwrite/.empty b/libs/usvfs/test/fixtures/usvfs_test/basic/source/overwrite/.empty deleted file mode 100644 index e69de29..0000000 --- a/libs/usvfs/test/fixtures/usvfs_test/basic/source/overwrite/.empty +++ /dev/null diff --git a/libs/usvfs/test/fixtures/usvfs_test/basic/source/root1.txt b/libs/usvfs/test/fixtures/usvfs_test/basic/source/root1.txt deleted file mode 100644 index 5aa129b..0000000 --- a/libs/usvfs/test/fixtures/usvfs_test/basic/source/root1.txt +++ /dev/null @@ -1 +0,0 @@ -root1 source file diff --git a/libs/usvfs/test/fixtures/usvfs_test/basic/source/root1w.txt b/libs/usvfs/test/fixtures/usvfs_test/basic/source/root1w.txt deleted file mode 100644 index 0c04aa5..0000000 --- a/libs/usvfs/test/fixtures/usvfs_test/basic/source/root1w.txt +++ /dev/null @@ -1 +0,0 @@ -root1w source file diff --git a/libs/usvfs/test/fixtures/usvfs_test/basic/source/root2.txt b/libs/usvfs/test/fixtures/usvfs_test/basic/source/root2.txt deleted file mode 100644 index 4ac40bb..0000000 --- a/libs/usvfs/test/fixtures/usvfs_test/basic/source/root2.txt +++ /dev/null @@ -1 +0,0 @@ -root2 source file diff --git a/libs/usvfs/test/fixtures/usvfs_test/basic/source/root2w.txt b/libs/usvfs/test/fixtures/usvfs_test/basic/source/root2w.txt deleted file mode 100644 index 83ddb42..0000000 --- a/libs/usvfs/test/fixtures/usvfs_test/basic/source/root2w.txt +++ /dev/null @@ -1 +0,0 @@ -root2w source file diff --git a/libs/usvfs/test/fixtures/usvfs_test/basic/vfs_mappings.txt b/libs/usvfs/test/fixtures/usvfs_test/basic/vfs_mappings.txt deleted file mode 100644 index cc755b4..0000000 --- a/libs/usvfs/test/fixtures/usvfs_test/basic/vfs_mappings.txt +++ /dev/null @@ -1,26 +0,0 @@ -# mapdir <optional relative path under mount> -# <relative path under source to mount> -# ... -mapdir - mod1 - mod2 - mod3 - mod4 - -# mapdircreate <optional relative path under mount> -# <relative path under source to mount> -# ... -mapdircreate - overwrite - -# mapfile <optional relative path under mount> -# <relative path under source to mount> -# ... -mapfile root1.txt - root1.txt -mapfile root1w.txt - root1w.txt -mapfile root2.txt - root2.txt -mapfile root2w.txt - root2w.txt diff --git a/libs/usvfs/test/gtest_utils/CMakeLists.txt b/libs/usvfs/test/gtest_utils/CMakeLists.txt deleted file mode 100644 index 8dcda70..0000000 --- a/libs/usvfs/test/gtest_utils/CMakeLists.txt +++ /dev/null @@ -1,11 +0,0 @@ -cmake_minimum_required(VERSION 3.16) - -find_package(GTest CONFIG REQUIRED) - -add_library(gtest_utils STATIC - gtest_utils.cpp - gtest_utils.h -) -set_target_properties(gtest_utils PROPERTIES FOLDER tests) -target_link_libraries(gtest_utils PUBLIC GTest::gtest) -target_include_directories(gtest_utils PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}) diff --git a/libs/usvfs/test/gtest_utils/gtest_utils.cpp b/libs/usvfs/test/gtest_utils/gtest_utils.cpp deleted file mode 100644 index f292dfd..0000000 --- a/libs/usvfs/test/gtest_utils/gtest_utils.cpp +++ /dev/null @@ -1,122 +0,0 @@ -#include "gtest_utils.h" - -// this file is shared by both usvfs_global_test and usvfs_global_test_runner -// - -#include <filesystem> -#include <format> -#include <fstream> - -#include <boost/algorithm/string.hpp> - -#include <gtest/gtest.h> - -std::string trimmed(std::string content) -{ - boost::algorithm::trim(content); - return content; -} - -// small utility to read files -std::optional<std::string> read_content(const std::filesystem::path& path, - bool trim = true) -{ - std::ifstream ifs(path, std::ios::binary | std::ios::ate); - - if (!ifs) { - return {}; - } - - const auto count = ifs.tellg(); - - std::string buffer(static_cast<std::size_t>(count), '\0'); - - ifs.seekg(0, std::ios::beg); - ifs.read(buffer.data(), count); - - if (trim) { - boost::algorithm::trim(buffer); - } - - return buffer; -} - -::testing::AssertionResult AssertDirectoryEquals(const std::filesystem::path& expected, - const std::filesystem::path& actual, - bool content) -{ - std::vector<std::string> failure_messages; - std::vector<std::filesystem::path> in_both; - - // iterate left, check on right - for (const auto& it : std::filesystem::recursive_directory_iterator{expected}) { - const auto relpath = relative(it.path(), expected); - if (!exists(actual / relpath)) { - failure_messages.push_back( - std::format("{} expected but not found", relpath.string())); - } else { - in_both.push_back(relpath); - } - } - - // iterate right, check on left - for (const auto& it : std::filesystem::recursive_directory_iterator{actual}) { - const auto relpath = relative(it.path(), actual); - if (!exists(expected / relpath)) { - failure_messages.push_back( - std::format("{} found but not expected", relpath.string())); - } - } - - // check contents - if (content) { - for (const auto& relpath : in_both) { - const auto expected_path = expected / relpath, actual_path = actual / relpath; - - if (is_directory(expected_path) != is_directory(actual_path)) { - failure_messages.push_back( - std::format("{} type mismatch, expected {} but found {}", relpath.string(), - is_directory(expected_path) ? "directory" : "file", - is_directory(expected_path) ? "file" : "directory")); - continue; - } - - if (is_directory(expected_path)) { - continue; - } - - if (read_content(expected_path) != read_content(actual_path)) { - failure_messages.push_back( - std::format("{} content mismatch", relpath.string())); - } - } - } - - if (failure_messages.empty()) { - return ::testing::AssertionSuccess(); - } - - return ::testing::AssertionFailure() - << "\n" - << boost::algorithm::join(failure_messages, "\n") << "\n"; -} - -::testing::AssertionResult AssertContentEquals(std::string_view expected, - const std::filesystem::path& path, - bool trim) -{ - const auto content = read_content(path, trim); - - if (!content) { - return ::testing::AssertionFailure() - << "failed to open path '" << path.string() << "'"; - } - - if (*content != expected) { - return ::testing::AssertionFailure() - << "mismatch content for '" << path.string() << "', expected '" << expected - << "', found '" << *content << "'"; - } - - return ::testing::AssertionSuccess(); -} diff --git a/libs/usvfs/test/gtest_utils/gtest_utils.h b/libs/usvfs/test/gtest_utils/gtest_utils.h deleted file mode 100644 index 1dba70c..0000000 --- a/libs/usvfs/test/gtest_utils/gtest_utils.h +++ /dev/null @@ -1,29 +0,0 @@ -#pragma once - -// this file is shared by both usvfs_global_test and usvfs_global_test_runner -// - -#include <filesystem> - -#include <gtest/gtest.h> - -::testing::AssertionResult AssertDirectoryEquals(const std::filesystem::path& expected, - const std::filesystem::path& actual, - bool content = true); - -::testing::AssertionResult AssertContentEquals(std::string_view expected, - const std::filesystem::path& path, - bool trim = true); - -// macro to assert that the contents of two directories are identical - directories are -// compared recursively and file contents are compared (excluding extra spaces or lines -// in file) -// -#define ASSERT_DIRECTORY_EQ(Expected, Actual) \ - ASSERT_TRUE(AssertDirectoryEquals(Expected, Actual)) - -// macro to assert that the contents of two files are identical (excluding extra space -// or lines in file) -// -#define ASSERT_CONTENT_EQ(Expected, Path) \ - ASSERT_TRUE(AssertContentEquals(Expected, Path)) diff --git a/libs/usvfs/test/shared_test/CMakeLists.txt b/libs/usvfs/test/shared_test/CMakeLists.txt deleted file mode 100644 index c5a42ea..0000000 --- a/libs/usvfs/test/shared_test/CMakeLists.txt +++ /dev/null @@ -1,7 +0,0 @@ -cmake_minimum_required(VERSION 3.16) - -find_package(GTest CONFIG REQUIRED) - -add_executable(shared_test main.cpp) -usvfs_set_test_properties(shared_test) -target_link_libraries(shared_test PRIVATE test_utils GTest::gtest GTest::gtest_main) diff --git a/libs/usvfs/test/shared_test/main.cpp b/libs/usvfs/test/shared_test/main.cpp deleted file mode 100644 index c6b5be6..0000000 --- a/libs/usvfs/test/shared_test/main.cpp +++ /dev/null @@ -1,248 +0,0 @@ -#include <boost/interprocess/containers/string.hpp> -#include <boost/interprocess/shared_memory_object.hpp> -#include <boost/predef.h> -#include <gtest/gtest.h> -#include <shared_memory.h> -#include <spdlog/sinks/stdout_sinks.h> -#include <wildcard.h> -#include <windows_sane.h> - -#define PRIVATE public -#include <directory_tree.h> -#undef PRIVATE - -#include <tree_container.h> - -using namespace usvfs::shared; - -using namespace boost::interprocess; - -static const char g_SHMName[] = "treetest_shm"; -static const char TreeName[] = "treetest_tree"; - -typedef DirectoryTree<int> TreeType; -typedef TreeContainer<TreeType> ContainerType; - -typedef boost::container::scoped_allocator_adaptor< - boost::interprocess::allocator<void, SegmentManagerT>> - VoidAllocator; -typedef VoidAllocator::rebind<char>::other CharAllocator; -typedef basic_string<char, std::char_traits<char>, CharAllocator> SHMString; -typedef DirectoryTree<SHMString> ComplexTreeType; -typedef TreeContainer<ComplexTreeType> ComplexContainerType; - -template <> -struct usvfs::shared::SHMDataCreator<int, int> -{ - static int create(int source, const VoidAllocatorT&) { return source; } -}; - -template <> -inline int usvfs::shared::createDataEmpty<int>(const typename VoidAllocatorT&) -{ - return 0; -} - -template <> -inline void usvfs::shared::dataAssign<int>(int& destination, const int& source) -{ - destination = source; -} - -template <> -inline SHMString -usvfs::shared::createDataEmpty<SHMString>(const typename VoidAllocatorT& allocator) -{ - return SHMString("", allocator); -} - -template <> -inline void usvfs::shared::dataAssign<SHMString>(SHMString& destination, - const SHMString& source) -{ - destination.assign(source.c_str()); -} - -static std::shared_ptr<spdlog::logger> logger() -{ - std::shared_ptr<spdlog::logger> result = spdlog::get("test"); - if (result.get() == nullptr) { - result = spdlog::stdout_logger_mt("test"); - } - return result; -} - -TEST(WildcardTest, MatchWildcard) -{ - EXPECT_TRUE(wildcard::Match(TEXT("abc"), TEXT("a*"))); - EXPECT_TRUE(wildcard::Match(TEXT("abc"), TEXT("a*c"))); - EXPECT_TRUE(wildcard::Match(TEXT("abc"), TEXT("a?c"))); - EXPECT_TRUE(wildcard::Match(TEXT("abc"), TEXT("abc"))); - EXPECT_TRUE(wildcard::Match(TEXT("abc"), TEXT("abc*"))); - - EXPECT_TRUE(wildcard::Match("abc", "*.*")); - EXPECT_TRUE(wildcard::Match("abc.def", "*")); - EXPECT_TRUE(wildcard::Match(TEXT("abc"), TEXT("*.*"))); - EXPECT_TRUE(wildcard::Match(TEXT("abc.def"), TEXT("*"))); - - EXPECT_NE(nullptr, wildcard::PartialMatch("abc", "*.*")); - EXPECT_NE(nullptr, wildcard::PartialMatch("abc.def", "*")); - EXPECT_EQ('\0', *wildcard::PartialMatch("abc", "*.*")); - EXPECT_EQ('\0', *wildcard::PartialMatch("abc.def", "*")); - - EXPECT_FALSE(wildcard::Match(TEXT("abc"), TEXT("b*"))); -} - -TEST(DirectoryTreeTest, SimpleTreeInit) -{ - EXPECT_NO_THROW({ - ContainerType tree(g_SHMName, 4096); - TreeType::NodePtrT p = tree.addFile(R"(C:\temp\test.txt)", 42, false); - EXPECT_NE(TreeType::NodePtrT(), p); - }); -} - -TEST(DirectoryTreeTest, FindNode) -{ - shared_memory_object::remove(g_SHMName); - ContainerType tree(g_SHMName, 64 * 1024); - EXPECT_NE(nullptr, tree.addFile(R"(C:\temp\bla)", 0x42, 0, false)); - - EXPECT_NE(nullptr, tree->findNode(R"(C:\temp)").get()); - EXPECT_EQ(nullptr, tree->findNode(R"(C:\temp\bla\blubb)").get()); -} - -struct TestVisitor -{ - TreeType::NodePtrT lastNode; - bool flag40{false}; - - void operator()(const TreeType::NodePtrT& node) - { - lastNode = node; - flag40 = node->hasFlag(0x40); - logger()->debug("{0} - {1}", lastNode->name(), flag40); - // BOOST_LOG_SEV(globalLogger::get(), LogLevel::Debug) << lastNode->name() << " - " - // << flag40; - } -}; - -TEST(DirectoryTreeTest, VisitPath) -{ - shared_memory_object::remove(g_SHMName); - ContainerType tree(g_SHMName, 64 * 1024); - EXPECT_NE(nullptr, tree.addFile(R"(C:\temp\bla)", 1, 0x40, false)); - - TestVisitor visitor; - - tree->visitPath(R"(C:\temp\bla\blubb)", - TreeType::VisitorFunction([&](const TreeType::NodePtrT& node) { - visitor(node); - })); - EXPECT_TRUE(visitor.flag40); - EXPECT_EQ("bla", visitor.lastNode->name()); -} - -TEST(DirectoryTreeTest, WildCardFind) -{ - shared_memory_object::remove(g_SHMName); - EXPECT_NO_THROW({ - ContainerType tree(g_SHMName, 64 * 1024); - - EXPECT_NE(nullptr, tree.addFile(R"(C:\temp)", 1, FLAG_DIRECTORY, false)); - EXPECT_NE(nullptr, tree.addFile(R"(C:\temp\abc)", 1, 0, false)); - EXPECT_NE(nullptr, tree.addFile(R"(C:\temp\abd)", 2, 0, false)); - EXPECT_NE(nullptr, tree.addFile(R"(C:\temp\ace)", 3, 0, false)); - - EXPECT_EQ(3, tree->find(R"(C:\temp\*)").size()); - EXPECT_NE(nullptr, tree->node("C:")); - EXPECT_EQ(1, tree->node("C:")->find("*").size()); - EXPECT_NE(nullptr, tree->node("C:")->node("temp")); - EXPECT_EQ(3, tree->node("C:")->node("temp")->find("*").size()); // alternative - // search on the top-level - EXPECT_EQ(1, tree->find("*").size()); - // * should work - EXPECT_EQ(2, tree->find(R"(C:\temp\ab*)").size()); - // * does not match directory separators - EXPECT_EQ(0, tree->find("*ab*").size()); - // matches only the directory itself - EXPECT_EQ(1, tree->find(R"(C:\temp*)").size()); - }); -} - -TEST(DirectoryTreeTest, SHMAllocation) -{ - EXPECT_NO_THROW({ - ContainerType create(g_SHMName, 64 * 1024); - - { // creation - create.addFile(R"(C:\temp\abc)", 1, false); - create.addFile(R"(C:\temp\abd)", 2, false); - create.addFile(R"(C:\temp\ace)", 3, false); - } - - { // access - ContainerType access(g_SHMName, 64 * 1024); - EXPECT_NE(nullptr, access.get()); - std::vector<TreeType::NodePtrT> res = access->find(R"(C:\temp\*)"); - EXPECT_EQ(3, res.size()); // matches the three files - EXPECT_EQ(access->m_Self.lock().get(), access->node("C:")->parent().get()); - } - }); -} - -TEST(DirectoryTreeTest, SHMAllocationError) -{ - EXPECT_NO_THROW({ - try { - ContainerType tree(g_SHMName, 4096); - int c = 0; - for (char i = 'a'; i <= 'z'; ++i) { - for (char j = 'a'; j <= 'z'; ++j) { - std::string name = std::string(R"(C:\temp\)") + i + j; - tree.addFile(name, ++c, false); - } - } - - EXPECT_EQ(1, tree->node("C:")->node("temp")->node("aa", MissingThrow)->data()); - EXPECT_EQ(26, tree->node("C:")->node("temp")->node("az", MissingThrow)->data()); - } catch (const std::exception& e) { - logger()->error("{0}", e.what()); - // BOOST_LOG_SEV(globalLogger::get(), LogLevel::Error) << e.what(); - throw; - } - }); -} - -TEST(DirectoryTreeTest, SHMAllocationErrorComplex) -{ - EXPECT_NO_THROW({ - try { - ComplexContainerType tree(g_SHMName, 4096); - SHMString str = tree.create("gaga"); - for (char i = 'a'; i <= 'z'; ++i) { - for (char j = 'a'; j <= 'z'; ++j) { - std::string name = std::string(R"(C:\temp\)") + i + j; - tree.addFile(name, str, false); - } - } - EXPECT_STREQ( - str.c_str(), - tree->node("C:")->node("temp")->node("aa", MissingThrow)->data().c_str()); - EXPECT_STREQ( - str.c_str(), - tree->node("C:")->node("temp")->node("az", MissingThrow)->data().c_str()); - } catch (const std::exception& e) { - logger()->error("{}", e.what()); - throw; - } - }); -} - -int main(int argc, char** argv) -{ - auto logger = spdlog::stdout_logger_mt("usvfs"); - logger->set_level(spdlog::level::warn); - testing::InitGoogleTest(&argc, argv); - return RUN_ALL_TESTS(); -} diff --git a/libs/usvfs/test/test_utils/CMakeLists.txt b/libs/usvfs/test/test_utils/CMakeLists.txt deleted file mode 100644 index 88c75d6..0000000 --- a/libs/usvfs/test/test_utils/CMakeLists.txt +++ /dev/null @@ -1,11 +0,0 @@ -cmake_minimum_required(VERSION 3.16) - -find_package(GTest CONFIG REQUIRED) - -add_library(test_utils STATIC - test_helpers.cpp - test_helpers.h -) -set_target_properties(test_utils PROPERTIES FOLDER tests) -target_link_libraries(test_utils PUBLIC shared) -target_include_directories(test_utils PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}) diff --git a/libs/usvfs/test/test_utils/test_helpers.cpp b/libs/usvfs/test/test_utils/test_helpers.cpp deleted file mode 100644 index 2daf3bb..0000000 --- a/libs/usvfs/test/test_utils/test_helpers.cpp +++ /dev/null @@ -1,248 +0,0 @@ -#pragma once - -#include <format> - -#include "test_helpers.h" -#include "winapi.h" - -namespace test -{ - -std::string FuncFailed::msg(std::string_view func, const char* arg1, - const unsigned long* res, const char* what) -{ - std::string buffer; - buffer.reserve(128); - - std::format_to(std::back_inserter(buffer), "{}() {}", func, what ? what : "failed"); - const char* sep = " : "; - if (arg1) { - std::format_to(std::back_inserter(buffer), "{}{}", sep, arg1); - sep = ", "; - } - if (res) { - std::format_to(std::back_inserter(buffer), "{}result = {} ({:#x})", sep, *res, - *res); - } - return buffer; -} - -ScopedFILE ScopedFILE::open(const std::filesystem::path& filepath, - std::wstring_view mode, errno_t& err) -{ - FILE* fp = nullptr; - err = _wfopen_s(&fp, filepath.c_str(), mode.data()); - if (err || !fp) { - return ScopedFILE(); - } - return ScopedFILE(fp); -} - -ScopedFILE ScopedFILE::open(const std::filesystem::path& filepath, - std::wstring_view mode) -{ - errno_t err; - auto file = open(filepath, mode, err); - if (err || !file) { - throw_testWinFuncFailed("_wfopen_s", filepath.string().c_str(), err); - } - return file; -} - -path path_of_test_bin(const path& relative) -{ - path base(winapi::wide::getModuleFileName(nullptr)); - return relative.empty() ? base.parent_path() : base.parent_path() / relative; -} - -path path_of_test_temp(const path& relative) -{ - return path_of_test_bin().parent_path() / "temp" / relative; -} - -path path_of_test_fixtures(const path& relative) -{ - return path_of_test_bin().parent_path() / "fixtures" / relative; -} - -path path_of_usvfs_lib(const path& relative) -{ - return path_of_test_bin().parent_path().parent_path() / "lib" / relative; -} - -std::string platform_dependant_executable(const char* name, const char* ext, - const char* platform) -{ - std::string res = name; - res += "_"; - if (platform) - res += platform; - else -#if _WIN64 - res += "x64"; -#else - res += "x86"; -#endif - res += "."; - res += ext; - return res; -} - -path path_as_relative(const path& base, const path& full_path) -{ - auto rel_begin = full_path.begin(); - auto base_iter = base.begin(); - while (rel_begin != full_path.end() && base_iter != base.end() && - *rel_begin == *base_iter) { - ++rel_begin; - ++base_iter; - } - - if (base_iter != base.end()) // full_path is not a sub-folder of base - return full_path; - - if (rel_begin == full_path.end()) // full_path == base - return path(L"."); - - // full_path is a sub-folder of base so take only relative path - path result; - for (; rel_begin != full_path.end(); ++rel_begin) - result /= *rel_begin; - return result; -} - -std::vector<char> read_small_file(const path& file, bool binary) -{ - using namespace std; - - const auto f = ScopedFILE::open(file, binary ? L"rb" : L"rt"); - - if (fseek(f, 0, SEEK_END)) - throw_testWinFuncFailed("fseek", (unsigned long)0); - - long size = ftell(f); - if (size < 0) - throw_testWinFuncFailed("ftell", (unsigned long)size); - if (size > 0x10000000) // sanity check limit to 256M - throw test::FuncFailed("read_small_file", "file size too large", - (unsigned long)size); - - if (fseek(f, 0, SEEK_SET)) - throw_testWinFuncFailed("fseek", (unsigned long)0); - - std::vector<char> content(static_cast<size_t>(size)); - content.resize(fread(content.data(), sizeof(char), content.size(), f)); - - return content; -} - -bool compare_files(const path& file1, const path& file2, bool binary) -{ - // TODO: if this is ever used for big file should read files in chunks - return read_small_file(file1, binary) == read_small_file(file2, binary); -} - -bool is_empty_folder(const path& dpath, bool or_doesnt_exist) -{ - bool isDir = false; - if (!winapi::ex::wide::fileExists(dpath.c_str(), &isDir)) - return or_doesnt_exist; - - if (!isDir) - return false; - - for (const auto& f : winapi::ex::wide::quickFindFiles(dpath.c_str(), L"*")) - if (f.fileName != L"." && f.fileName != L"..") - return false; - return true; -} - -void delete_file(const path& file) -{ - if (!DeleteFileW(file.c_str())) { - auto err = GetLastError(); - if (err != ERROR_FILE_NOT_FOUND && err != ERROR_PATH_NOT_FOUND) - throw_testWinFuncFailed("DeleteFile", file.string()); - } -} - -void recursive_delete_files(const path& dpath) -{ - bool isDir = false; - if (!winapi::ex::wide::fileExists(dpath.c_str(), &isDir)) - return; - if (!isDir) - delete_file(dpath); - else { - // dpath exists and its a directory: - std::vector<std::wstring> recurse; - for (const auto& f : winapi::ex::wide::quickFindFiles(dpath.c_str(), L"*")) { - if (f.fileName == L"." || f.fileName == L"..") - continue; - if (f.attributes & FILE_ATTRIBUTE_DIRECTORY) - recurse.push_back(f.fileName); - else - delete_file(dpath / f.fileName); - } - for (auto r : recurse) - recursive_delete_files(dpath / r); - if (!RemoveDirectoryW(dpath.c_str())) - throw_testWinFuncFailed("RemoveDirectory", dpath.string().c_str()); - } - if (winapi::ex::wide::fileExists(dpath.c_str())) - throw FuncFailed("delete_directory_tree", dpath.string().c_str()); -} - -void recursive_copy_files(const path& src_path, const path& dest_path, bool overwrite) -{ - bool srcIsDir = false, destIsDir = false; - if (!winapi::ex::wide::fileExists(src_path.c_str(), &srcIsDir)) - throw FuncFailed("recursive_copy", "source doesn't exist", - src_path.string().c_str()); - if (!winapi::ex::wide::fileExists(dest_path.c_str(), &destIsDir) && srcIsDir) { - winapi::ex::wide::createPath(dest_path.c_str()); - destIsDir = true; - } - - if (!srcIsDir) - if (!destIsDir) { - if (!CopyFileW(src_path.c_str(), dest_path.c_str(), overwrite)) - throw_testWinFuncFailed( - "CopyFile", (src_path.string() + " => " + dest_path.string()).c_str()); - return; - } else - throw FuncFailed("recursive_copy", - "source is a file but destination is a directory", - (src_path.string() + ", " + dest_path.string()).c_str()); - - if (!destIsDir) - throw FuncFailed("recursive_copy", - "source is a directory but destination is a file", - (src_path.string() + ", " + dest_path.string()).c_str()); - - // source and destination are both directories: - std::vector<std::wstring> recurse; - for (const auto& f : winapi::ex::wide::quickFindFiles(src_path.c_str(), L"*")) { - if (f.fileName == L"." || f.fileName == L"..") - continue; - if (f.attributes & FILE_ATTRIBUTE_DIRECTORY) - recurse.push_back(f.fileName); - else if (!CopyFileW((src_path / f.fileName).c_str(), - (dest_path / f.fileName).c_str(), overwrite)) - throw_testWinFuncFailed("CopyFile", ((src_path / f.fileName).string() + " => " + - (dest_path / f.fileName).string())); - } - for (auto r : recurse) - recursive_copy_files(src_path / r, dest_path / r, overwrite); -} - -ScopedLoadLibrary::ScopedLoadLibrary(const wchar_t* dll_path) - : m_mod(LoadLibrary(dll_path)) -{} -ScopedLoadLibrary::~ScopedLoadLibrary() -{ - if (m_mod) - FreeLibrary(m_mod); -} - -}; // namespace test diff --git a/libs/usvfs/test/test_utils/test_helpers.h b/libs/usvfs/test/test_utils/test_helpers.h deleted file mode 100644 index 7ea8950..0000000 --- a/libs/usvfs/test/test_utils/test_helpers.h +++ /dev/null @@ -1,165 +0,0 @@ -#pragma once - -#include "windows_sane.h" - -#include <filesystem> -#include <format> -#include <memory> - -namespace test -{ - -class FuncFailed : public std::runtime_error -{ -public: - FuncFailed(const char* func) : std::runtime_error(msg(func)) {} - FuncFailed(const char* func, unsigned long res) - : std::runtime_error(msg(func, nullptr, &res)) - {} - FuncFailed(const char* func, const char* arg1) : std::runtime_error(msg(func, arg1)) - {} - FuncFailed(const char* func, const char* arg1, unsigned long res) - : std::runtime_error(msg(func, arg1, &res)) - {} - FuncFailed(const char* func, const char* what, const char* arg1) - : std::runtime_error(msg(func, arg1, nullptr, what)) - {} - FuncFailed(const char* func, const char* what, const char* arg1, unsigned long res) - : std::runtime_error(msg(func, arg1, &res, what)) - {} - -private: - std::string msg(std::string_view func, const char* arg1 = nullptr, - const unsigned long* res = nullptr, const char* what = nullptr); -}; - -class WinFuncFailed : public std::runtime_error -{ -public: - using runtime_error::runtime_error; -}; - -class WinFuncFailedGenerator -{ -public: - WinFuncFailedGenerator(DWORD gle = GetLastError()) : m_gle(gle) {} - WinFuncFailedGenerator(const WinFuncFailedGenerator&) = delete; - - DWORD lastError() const { return m_gle; } - - WinFuncFailed operator()(std::basic_string_view<char> func) - { - return WinFuncFailed(std::format("{} failed : lastError={}", func, m_gle)); - } - - WinFuncFailed operator()(std::basic_string_view<char> func, unsigned long res) - { - return WinFuncFailed( - std::format("{} failed : result=({:#x}), lastError={}", func, res, m_gle)); - } - - WinFuncFailed operator()(std::string_view func, std::basic_string_view<char> arg1) - { - return WinFuncFailed( - std::format("{} failed : {}, lastError={}", func, arg1, m_gle)); - } - - WinFuncFailed operator()(std::string_view func, std::basic_string_view<char> arg1, - unsigned long res) - { - return WinFuncFailed(std::format("{} failed : {}, result=({:#x}), lastError={}", - func, arg1, res, m_gle)); - } - -private: - DWORD m_gle; -}; - -// trick to guarantee the evalutation of GetLastError() before the evalution of the -// parameters to the WinFuncFailed message generation -template <class... Args> -[[noreturn]] void throw_testWinFuncFailed(std::string_view func, Args&&... args) -{ - ::test::WinFuncFailedGenerator exceptionGenerator; - throw exceptionGenerator(func, std::forward<Args>(args)...); -} - -class ScopedFILE -{ -public: - // try to open the given filepath with the given mode, if it fails, set err to - // the return code of _wfopen_s and return a nulled scoped file - // - static ScopedFILE open(const std::filesystem::path& filepath, std::wstring_view mode, - errno_t& err); - - // same as above but throw a WinFuncFailed() exception if opening the file failed - // - static ScopedFILE open(const std::filesystem::path& filepath, std::wstring_view mode); - -public: - ScopedFILE(FILE* f = nullptr) : m_f(f, &fclose) {} - - ScopedFILE(ScopedFILE&& other) noexcept = default; - ~ScopedFILE() = default; - - ScopedFILE(const ScopedFILE&) = delete; - - void close() { m_f = nullptr; } - - operator bool() const { return static_cast<bool>(m_f); } - operator FILE*() const { return m_f.get(); } - -private: - std::unique_ptr<FILE, decltype(&fclose)> m_f; -}; - -using std::filesystem::path; - -// path functions assume they are called by a test executable -// (calculate the requested path relative to the current executable path) - -path path_of_test_bin(const path& relative = path()); -path path_of_test_temp(const path& relative = path()); -path path_of_test_fixtures(const path& relative = path()); -path path_of_usvfs_lib(const path& relative = path()); - -std::string platform_dependant_executable(const char* name, const char* ext = "exe", - const char* platform = nullptr); - -// if full_path is a subfolder of base returns only the relative path, -// if full_path and base are the same folder "." is returned, -// otherwise full_path is returned unchanged -path path_as_relative(const path& base, const path& full_path); - -std::vector<char> read_small_file(const path& file, bool binary = true); - -// true iff the the contents of the two files is exactly the same -bool compare_files(const path& file1, const path& file2, bool binary = true); - -// return true iff the given path is an empty (optionally true also if path doesn't -// exist) -bool is_empty_folder(const path& dpath, bool or_doesnt_exist = false); - -void delete_file(const path& file); - -// Recursively deletes the given path and all the files and directories under it -// Use with care!!! -void recursive_delete_files(const path& dpath); - -// Recursively copies all files and directories from srcPath to destPath -void recursive_copy_files(const path& src_path, const path& dest_path, bool overwrite); - -class ScopedLoadLibrary -{ -public: - ScopedLoadLibrary(const wchar_t* dll_path); - ~ScopedLoadLibrary(); - - // returns zero if load library failed - operator HMODULE() const { return m_mod; } - -private: - HMODULE m_mod; -}; -}; // namespace test diff --git a/libs/usvfs/test/thooklib_test/CMakeLists.txt b/libs/usvfs/test/thooklib_test/CMakeLists.txt deleted file mode 100644 index cca9e10..0000000 --- a/libs/usvfs/test/thooklib_test/CMakeLists.txt +++ /dev/null @@ -1,11 +0,0 @@ -cmake_minimum_required(VERSION 3.16) - -find_package(GTest CONFIG REQUIRED) -find_package(Boost CONFIG REQUIRED COMPONENTS thread) - -# not sure why there is a test_hooks.cpp here? -add_executable(thooklib_test main.cpp) -usvfs_set_test_properties(thooklib_test) -target_link_libraries(thooklib_test - PRIVATE test_utils shared thooklib Boost::thread - GTest::gtest GTest::gtest_main) diff --git a/libs/usvfs/test/thooklib_test/main.cpp b/libs/usvfs/test/thooklib_test/main.cpp deleted file mode 100644 index df48198..0000000 --- a/libs/usvfs/test/thooklib_test/main.cpp +++ /dev/null @@ -1,235 +0,0 @@ -#include <gtest/gtest.h> -#include <hooklib.h> -#include <iostream> -#include <ttrampolinepool.h> -#include <utility.h> -#include <windows_sane.h> -// #include <boost/thread.hpp> -#include <boost/filesystem.hpp> -#include <exceptionex.h> -#include <spdlog/sinks/stdout_sinks.h> -#include <spdlog/spdlog.h> -#include <winapi.h> - -namespace fs = boost::filesystem; - -#include <stringutils.h> - -using namespace std; -using namespace HookLib; - -class TempFile -{ -public: - TempFile(const wchar_t* relative) : wpath(winapi::wide::getModuleFileName(nullptr)) - { - size_t path_end = wpath.rfind(L'\\'); - if (path_end != std::wstring::npos) { - wpath.erase(path_end + 1); - wpath += L"..\\temp\\"; - wpath += relative; - } else - wpath = relative; - path = - usvfs::shared::string_cast<std::string>(wpath, usvfs::shared::CodePage::UTF8); - } - - const char* c_str() const { return path.c_str(); } - const wchar_t* w_str() const { return wpath.c_str(); } - -private: - std::string path; - std::wstring wpath; -}; - -static const HANDLE MARKERHANDLE = reinterpret_cast<HANDLE>(0x1CC0FFEE); -static const TempFile VALID_FILENAME{L"VALID_FILENAME"}; -static const TempFile INVALID_FILENAME{L"\\<>/"}; - -#include "test_hooks.cpp" - -static bool stubCalled = false; - -void __cdecl CreateFileStub(LPVOID) -{ - stubCalled = true; -} - -class HookingTest : public testing::Test -{ -public: - void SetUp() - { - /* typedef sinks::synchronous_sink<sinks::text_ostream_backend> text_sink; - boost::shared_ptr<text_sink> sink = boost::make_shared<text_sink>(); - - // Add a stream to write log to - sink->locked_backend()->add_stream(boost::make_shared<std::ofstream>("c:\\temp\\testing_out.log")); - - // Register the sink in the logging core - logging::core::get()->add_sink(sink); - - sink->set_filter(expr::attr<LogLevel>("Severity") >= LogLevel::Debug);*/ - } - - void TearDown() {} - -private: -}; - -TEST(GetProcAddressTest, ReturnsValidResults) -{ - HMODULE mh = GetModuleHandleA("KernelBase.dll"); - EXPECT_NE(nullptr, mh); - EXPECT_EQ(GetProcAddress(mh, "CreateFileA"), MyGetProcAddress(mh, "CreateFileA")); -} - -TEST_F(HookingTest, CanHook) -{ - HMODULE k32Mod = GetModuleHandleA("kernel32.dll"); - HOOKHANDLE hook = InstallHook(k32Mod, "CreateFileW", THCreateFileW_1); - if (hook == INVALID_HOOK) { - k32Mod = GetModuleHandleA("kernelbase.dll"); - hook = InstallHook(k32Mod, "CreateFileW", THCreateFileW_1); - } - EXPECT_NE(INVALID_HOOK, hook); - RemoveHook(hook); -} - -TEST_F(HookingTest, CanStub) -{ - HMODULE k32Mod = GetModuleHandleA("kernel32.dll"); - HOOKHANDLE hook = InstallStub(k32Mod, "CreateFileW", CreateFileStub); - if (hook == INVALID_HOOK) { - k32Mod = GetModuleHandleA("kernelbase.dll"); - hook = InstallStub(k32Mod, "CreateFileW", CreateFileStub); - } - EXPECT_NE(INVALID_HOOK, hook); - RemoveHook(hook); -} - -TEST_F(HookingTest, RemoveHook) -{ - // test that we can remove a hook - HMODULE k32Mod = GetModuleHandleA("kernel32.dll"); - HOOKHANDLE hook = InstallHook(k32Mod, "CreateFileA", THCreateFileA_1); - if (hook == INVALID_HOOK) { - k32Mod = GetModuleHandleA("kernelbase.dll"); - hook = InstallHook(k32Mod, "CreateFileA", THCreateFileA_1); - } - - EXPECT_NE(INVALID_HOOK, hook); - RemoveHook(hook); - HANDLE test = CreateFileA(INVALID_FILENAME.c_str(), GENERIC_READ, 0, nullptr, - OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr); - EXPECT_EQ(INVALID_HANDLE_VALUE, test); -} - -TEST_F(HookingTest, CreateFileStubTest) -{ - stubCalled = false; - // test if our stub works - HMODULE k32Mod = GetModuleHandleA("kernel32.dll"); - HOOKHANDLE hook = InstallStub(k32Mod, "CreateFileA", CreateFileStub); - if (hook == INVALID_HOOK) { - k32Mod = GetModuleHandleA("kernelbase.dll"); - hook = InstallStub(k32Mod, "CreateFileA", CreateFileStub); - } - EXPECT_NE(INVALID_HOOK, hook); - HANDLE test = CreateFileA(INVALID_FILENAME.c_str(), GENERIC_READ, 0, nullptr, - OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr); - RemoveHook(hook); - EXPECT_EQ(true, stubCalled); - EXPECT_EQ(INVALID_HANDLE_VALUE, test); -} - -TEST_F(HookingTest, CreateFileHook) -{ - // test if our hook works - HMODULE k32Mod = GetModuleHandleA("kernel32.dll"); - HOOKHANDLE hook = InstallHook(k32Mod, "CreateFileA", THCreateFileA_1); - if (hook == INVALID_HOOK) { - k32Mod = GetModuleHandleA("kernelbase.dll"); - hook = InstallHook(k32Mod, "CreateFileA", THCreateFileA_1); - } - HANDLE test = CreateFileA(INVALID_FILENAME.c_str(), GENERIC_READ, 0, nullptr, - OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr); - RemoveHook(hook); - EXPECT_EQ(MARKERHANDLE, test); -} - -TEST_F(HookingTest, CreateFileWHook) -{ - // test if our hook works - HMODULE k32Mod = GetModuleHandleA("kernel32.dll"); - HOOKHANDLE hook = InstallHook(k32Mod, "CreateFileW", THCreateFileW_1); - if (hook == INVALID_HOOK) { - k32Mod = GetModuleHandleA("kernelbase.dll"); - hook = InstallHook(k32Mod, "CreateFileW", THCreateFileW_1); - } - HANDLE test = CreateFileW(INVALID_FILENAME.w_str(), 0x42, 0x43, - (LPSECURITY_ATTRIBUTES)0x44, 0x45, 0x46, (HANDLE)0x47); - RemoveHook(hook); - EXPECT_EQ(MARKERHANDLE, test); -} - -TEST_F(HookingTest, CreateFileHookRecursion) -{ - // test that the trampoline works, so we can call the original function from - // within the hook - HMODULE k32Mod = GetModuleHandleA("kernel32.dll"); - HOOKHANDLE hook = InstallHook(k32Mod, "CreateFileA", THCreateFileA_1); - if (hook == INVALID_HOOK) { - k32Mod = GetModuleHandleA("kernelbase.dll"); - hook = InstallHook(k32Mod, "CreateFileA", THCreateFileA_1); - } - HANDLE test = CreateFileA(VALID_FILENAME.c_str(), GENERIC_READ, 0, nullptr, - OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr); - RemoveHook(hook); - EXPECT_NE(MARKERHANDLE, test); -} - -TEST_F(HookingTest, Threading) -{ - // test that multiple threads can concurrently call a hooked function without - // incorrect results. - // TODO: this test doesn't reliably find thread-unsafeties - // NOTE: the hooklib currently does not claim that hook installation or removal - // is thread-safe, only the hooked functions shouldn't become less thread-safe by - // being hooked! - - static const int NUM_THREADS = 100; - static const int NUM_TRIES = 1000; - - HMODULE k32Mod = GetModuleHandleA("kernel32.dll"); - HOOKHANDLE hook = InstallHook(k32Mod, "CreateFileA", THCreateFileA_1); - if (hook == INVALID_HOOK) { - k32Mod = GetModuleHandleA("kernelbase.dll"); - hook = InstallHook(k32Mod, "CreateFileA", THCreateFileA_1); - } - std::thread threads[NUM_THREADS]; - for (int i = 0; i < NUM_THREADS; ++i) { - threads[i] = std::thread([i] { - for (int count = 0; count < NUM_TRIES; ++count) { - HANDLE test = CreateFileA(INVALID_FILENAME.c_str(), GENERIC_READ, 0, nullptr, - OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr); - EXPECT_EQ(MARKERHANDLE, test); - } - }); - } - - for (int i = 0; i < NUM_THREADS; ++i) { - threads[i].join(); - } - - RemoveHook(hook); -} - -int main(int argc, char** argv) -{ - auto logger = spdlog::stdout_logger_mt("usvfs"); - logger->set_level(spdlog::level::warn); - TrampolinePool::initialize(); - testing::InitGoogleTest(&argc, argv); - return RUN_ALL_TESTS(); -} diff --git a/libs/usvfs/test/thooklib_test/test_hooks.cpp b/libs/usvfs/test/thooklib_test/test_hooks.cpp deleted file mode 100644 index edde2c8..0000000 --- a/libs/usvfs/test/thooklib_test/test_hooks.cpp +++ /dev/null @@ -1,38 +0,0 @@ -#include <Windows.h> -#include <gtest/gtest.h> - -HANDLE WINAPI THCreateFileA_1(LPCSTR lpFileName, DWORD dwDesiredAccess, - DWORD dwShareMode, - LPSECURITY_ATTRIBUTES lpSecurityAttributes, - DWORD dwCreationDisposition, DWORD dwFlagsAndAttributes, - HANDLE hTemplateFile) -{ - if (strcmp(lpFileName, INVALID_FILENAME.c_str()) == 0) { - return MARKERHANDLE; - } else { - HANDLE res = - ::CreateFileA(lpFileName, dwDesiredAccess, dwShareMode, lpSecurityAttributes, - dwCreationDisposition, dwFlagsAndAttributes, hTemplateFile); - return res; - } -} - -HANDLE WINAPI THCreateFileW_1(LPCWSTR lpFileName, DWORD dwDesiredAccess, - DWORD dwShareMode, - LPSECURITY_ATTRIBUTES lpSecurityAttributes, - DWORD dwCreationDisposition, DWORD dwFlagsAndAttributes, - HANDLE hTemplateFile) -{ - if (wcscmp(lpFileName, INVALID_FILENAME.w_str()) == 0) { - EXPECT_EQ(0x42, dwDesiredAccess); - EXPECT_EQ(0x43, dwShareMode); - EXPECT_EQ(0x44, (int)lpSecurityAttributes); - EXPECT_EQ(0x45, dwCreationDisposition); - EXPECT_EQ(0x46, dwFlagsAndAttributes); - EXPECT_EQ(0x47, (int)hTemplateFile); - return MARKERHANDLE; - } else { - return ::CreateFileW(lpFileName, dwDesiredAccess, dwShareMode, lpSecurityAttributes, - dwCreationDisposition, dwFlagsAndAttributes, hTemplateFile); - } -} diff --git a/libs/usvfs/test/tinjectlib_test/CMakeLists.txt b/libs/usvfs/test/tinjectlib_test/CMakeLists.txt deleted file mode 100644 index 9bd3f7b..0000000 --- a/libs/usvfs/test/tinjectlib_test/CMakeLists.txt +++ /dev/null @@ -1,16 +0,0 @@ -cmake_minimum_required(VERSION 3.16) - -find_package(GTest CONFIG REQUIRED) - -# binary and binary injected -add_executable(testinject_bin testinject_bin/main.cpp) -usvfs_set_test_properties(testinject_bin FOLDER tinjectlib) - -add_library(testinject_dll SHARED testinject_dll/main.cpp testinject_dll/main.h) -usvfs_set_test_properties(testinject_dll FOLDER tinjectlib) - -# actual test executable -add_executable(tinjectlib_test main.cpp) -usvfs_set_test_properties(tinjectlib_test FOLDER tinjectlib) -target_link_libraries(tinjectlib_test PRIVATE tinjectlib shared GTest::gtest GTest::gtest_main) -add_dependencies(tinjectlib_test testinject_bin testinject_dll) diff --git a/libs/usvfs/test/tinjectlib_test/main.cpp b/libs/usvfs/test/tinjectlib_test/main.cpp deleted file mode 100644 index ce48f83..0000000 --- a/libs/usvfs/test/tinjectlib_test/main.cpp +++ /dev/null @@ -1,158 +0,0 @@ -#include <boost/filesystem.hpp> -#include <boost/type_traits.hpp> -#include <gtest/gtest.h> -#include <injectlib.h> -#include <spdlog/sinks/stdout_sinks.h> -#include <spdlog/spdlog.h> -#include <winapi.h> - -using namespace usvfs::shared; -using namespace InjectLib; - -#if BOOST_ARCH_X86_64 -static const wchar_t INJECT_BIN[] = L"testinject_bin_x64.exe"; -#else -static const wchar_t INJECT_BIN[] = L"testinject_bin_x86.exe"; -#endif - -#if BOOST_ARCH_X86_64 -static const wchar_t INJECT_LIB[] = L"testinject_dll_x64.dll"; -#else -static const wchar_t INJECT_LIB[] = L"testinject_dll_x86.dll"; -#endif - -static std::shared_ptr<spdlog::logger> logger() -{ - std::shared_ptr<spdlog::logger> result = spdlog::get("test"); - if (result.get() == nullptr) { - result = spdlog::stdout_logger_mt("test"); - } - return result; -} - -bool spawn(HANDLE& processHandle, HANDLE& threadHandle) -{ - STARTUPINFO si; - ::ZeroMemory(&si, sizeof(si)); - si.cb = sizeof(si); - - PROCESS_INFORMATION pi; - BOOL success = ::CreateProcess(INJECT_BIN, nullptr, nullptr, nullptr, FALSE, - CREATE_SUSPENDED, nullptr, nullptr, &si, &pi); - - if (!success) { - throw windows_error("failed to start process"); - } - - processHandle = pi.hProcess; - threadHandle = pi.hThread; - - return true; -} - -TEST(InjectingTest, InjectionNoInit) -{ - // Verify lib can inject without a init function - - HANDLE process, thread; - spawn(process, thread); - EXPECT_NO_THROW(InjectLib::InjectDLL(process, thread, INJECT_LIB)); - ResumeThread(thread); - - DWORD res = WaitForSingleObject(process, INFINITE); - DWORD exitCode = NO_ERROR; - res = GetExitCodeProcess(process, &exitCode); - EXPECT_EQ(NOERROR, exitCode); - - CloseHandle(process); - CloseHandle(thread); -} - -TEST(InjectingTest, InjectionSimpleInit) -{ - // Verify lib can inject with a init function with null parameters - - HANDLE process, thread; - spawn(process, thread); - EXPECT_NO_THROW(InjectLib::InjectDLL(process, thread, INJECT_LIB, "InitNoParam")); - ResumeThread(thread); - - DWORD res = WaitForSingleObject(process, INFINITE); - DWORD exitCode = NO_ERROR; - res = GetExitCodeProcess(process, &exitCode); - EXPECT_EQ(10001, exitCode); // used init function exits process with this exit code - - CloseHandle(process); - CloseHandle(thread); -} - -TEST(InjectingTest, InjectionComplexInit) -{ - // Verify lib can inject with a init function with null parameters - - static const WCHAR param[] = L"magic_parameter"; - HANDLE process, thread; - spawn(process, thread); - EXPECT_NO_THROW(InjectLib::InjectDLL(process, thread, INJECT_LIB, "InitComplexParam", - reinterpret_cast<LPCVOID>(param), - wcslen(param) * sizeof(WCHAR))); - - ResumeThread(thread); - - DWORD res = WaitForSingleObject(process, INFINITE); - DWORD exitCode = NO_ERROR; - res = GetExitCodeProcess(process, &exitCode); - EXPECT_EQ(10002, exitCode); // used init function exits process with this exit code - - CloseHandle(process); - CloseHandle(thread); -} - -TEST(InjectingTest, InjectionNoQuitInit) -{ - // Verify lib can inject with a init function with null parameters - - HANDLE process, thread; - spawn(process, thread); - EXPECT_NO_THROW(InjectLib::InjectDLL(process, thread, INJECT_LIB, "InitNoQuit")); - ResumeThread(thread); - - DWORD res = WaitForSingleObject(process, INFINITE); - DWORD exitCode = NO_ERROR; - res = GetExitCodeProcess(process, &exitCode); - EXPECT_EQ(0, exitCode); // expect regular exit from process - - CloseHandle(process); - CloseHandle(thread); -} - -TEST(InjectingTest, InjectionSkipInit) -{ - // verify the skip-on-missing mechanism for init function works - - HANDLE process, thread; - spawn(process, thread); - EXPECT_NO_THROW(InjectLib::InjectDLL(process, thread, INJECT_LIB, "__InitInvalid", - nullptr, 0, true)); - ResumeThread(thread); - - DWORD res = WaitForSingleObject(process, INFINITE); - DWORD exitCode = NO_ERROR; - res = GetExitCodeProcess(process, &exitCode); - EXPECT_EQ(NOERROR, exitCode); - - CloseHandle(process); - CloseHandle(thread); -} - -int main(int argc, char** argv) -{ - auto logger = spdlog::stdout_logger_mt("usvfs"); - logger->set_level(spdlog::level::warn); - - boost::filesystem::path filePath(winapi::wide::getModuleFileName(nullptr)); - SetCurrentDirectoryW(filePath.parent_path().wstring().c_str()); - - testing::InitGoogleTest(&argc, argv); - return RUN_ALL_TESTS(); -} diff --git a/libs/usvfs/test/tinjectlib_test/testinject_bin/main.cpp b/libs/usvfs/test/tinjectlib_test/testinject_bin/main.cpp deleted file mode 100644 index f8b643a..0000000 --- a/libs/usvfs/test/tinjectlib_test/testinject_bin/main.cpp +++ /dev/null @@ -1,4 +0,0 @@ -int main() -{ - return 0; -} diff --git a/libs/usvfs/test/tinjectlib_test/testinject_dll/main.cpp b/libs/usvfs/test/tinjectlib_test/testinject_dll/main.cpp deleted file mode 100644 index 8339e97..0000000 --- a/libs/usvfs/test/tinjectlib_test/testinject_dll/main.cpp +++ /dev/null @@ -1,36 +0,0 @@ -#include "main.h" - -void __cdecl InitNoQuit(LPVOID, size_t) -{ - // nop -} - -void __cdecl InitNoParam(LPVOID, size_t) -{ - ExitProcess(10001); -} - -void __cdecl InitComplexParam(LPVOID userData, size_t) -{ - LPCWSTR string = (LPCWSTR)userData; - if (wcscmp(string, L"magic_parameter") == 0) { - ExitProcess(10002); - } else { - ExitProcess(20003); - } -} - -BOOL APIENTRY DllMain(HMODULE, DWORD reasonForCall, LPVOID) -{ - switch (reasonForCall) { - case DLL_PROCESS_ATTACH: { - } break; - case DLL_PROCESS_DETACH: { - } break; - case DLL_THREAD_ATTACH: { - } break; - case DLL_THREAD_DETACH: { - } break; - } - return TRUE; -} diff --git a/libs/usvfs/test/tinjectlib_test/testinject_dll/main.h b/libs/usvfs/test/tinjectlib_test/testinject_dll/main.h deleted file mode 100644 index 6faf800..0000000 --- a/libs/usvfs/test/tinjectlib_test/testinject_dll/main.h +++ /dev/null @@ -1,11 +0,0 @@ -#pragma once - -#define WIN32_LEAN_AND_MEAN -#include <windows.h> - -extern "C" - __declspec(dllexport) void __cdecl InitNoQuit(LPVOID userData, size_t userDataSize); -extern "C" __declspec(dllexport) void __cdecl InitNoParam(LPVOID userData, - size_t userDataSize); -extern "C" __declspec(dllexport) void __cdecl InitComplexParam(LPVOID userData, - size_t userDataSize); diff --git a/libs/usvfs/test/tvfs_test/CMakeLists.txt b/libs/usvfs/test/tvfs_test/CMakeLists.txt deleted file mode 100644 index f66a7b4..0000000 --- a/libs/usvfs/test/tvfs_test/CMakeLists.txt +++ /dev/null @@ -1,12 +0,0 @@ -cmake_minimum_required(VERSION 3.16) - -find_package(GTest CONFIG REQUIRED) - -add_executable(tvfs_test main.cpp) -usvfs_set_test_properties(tvfs_test) -target_link_libraries(tvfs_test PRIVATE test_utils usvfs_helper GTest::gtest GTest::gmock GTest::gtest_main) -usvfs_target_link_usvfs(tvfs_test) - -# tvfs_test uses a private USVFS header so we need to include it manually -get_target_property(USVFS_SOURCE_DIR usvfs_dll SOURCE_DIR) -target_include_directories(tvfs_test PRIVATE ${USVFS_SOURCE_DIR}) diff --git a/libs/usvfs/test/tvfs_test/main.cpp b/libs/usvfs/test/tvfs_test/main.cpp deleted file mode 100644 index 7c7998b..0000000 --- a/libs/usvfs/test/tvfs_test/main.cpp +++ /dev/null @@ -1,585 +0,0 @@ -/* -Userspace Virtual Filesystem - -Copyright (C) 2015 Sebastian Herbord. All rights reserved. - -This file is part of usvfs. - -usvfs is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -usvfs is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with usvfs. If not, see <http://www.gnu.org/licenses/>. -*/ - -// this file depends on so many stuff that the easiest way is to include -// pch.h from shared -#include "pch.h" - -#include <test_helpers.h> - -#include <fstream> -#include <iostream> - -#include <inject.h> -#include <stringutils.h> -#include <windows_sane.h> - -#include <spdlog/sinks/stdout_sinks.h> -#include <spdlog/spdlog.h> - -#include <hookcontext.h> -#include <hooks/kernel32.h> -#include <hooks/ntdll.h> -#include <logging.h> -#include <stringcast.h> -#include <unicodestring.h> -#include <usvfs.h> - -#include <gmock/gmock-matchers.h> -#include <gtest/gtest.h> - -namespace spd = spdlog; - -namespace ush = usvfs::shared; - -// name of a file to be created in the virtual fs. Shouldn't exist on disc but the -// directory must exist -static LPCSTR VIRTUAL_FILEA = "C:/np.exe"; -static LPCWSTR VIRTUAL_FILEW = L"C:/np.exe"; - -// a real file on disc that has to exist -static LPCSTR REAL_FILEA = "C:/windows/notepad.exe"; -static LPCWSTR REAL_FILEW = L"C:/windows/notepad.exe"; - -static LPCSTR REAL_DIRA = "C:/windows/Logs"; -static LPCWSTR REAL_DIRW = L"C:/windows/Logs"; - -static std::shared_ptr<spdlog::logger> logger() -{ - std::shared_ptr<spdlog::logger> result = spdlog::get("test"); - if (result.get() == nullptr) { - result = spdlog::stdout_logger_mt("test"); - } - return result; -} - -auto defaultUsvfsParams(const char* instanceName = "usvfs_test") -{ - std::unique_ptr<usvfsParameters, decltype(&usvfsFreeParameters)> parameters{ - usvfsCreateParameters(), &usvfsFreeParameters}; - - usvfsSetInstanceName(parameters.get(), instanceName); - usvfsSetDebugMode(parameters.get(), true); - usvfsSetLogLevel(parameters.get(), LogLevel::Debug); - usvfsSetCrashDumpType(parameters.get(), CrashDumpsType::None); - usvfsSetCrashDumpPath(parameters.get(), ""); - - return std::move(parameters); -} - -class USVFSTest : public testing::Test -{ -public: - void SetUp() - { - SHMLogger::create("usvfs"); - // need to initialize logging in the context of the dll - usvfsInitLogging(); - } - - void TearDown() - { - std::array<char, 1024> buffer; - while (SHMLogger::instance().tryGet(buffer.data(), buffer.size())) { - std::cout << buffer.data() << std::endl; - } - SHMLogger::free(); - } - -private: -}; - -class USVFSTestWithReroute : public testing::Test -{ -public: - void SetUp() - { - SHMLogger::create("usvfs"); - // need to initialize logging in the context of the dll - usvfsInitLogging(); - - auto params = defaultUsvfsParams(); - m_Context.reset(usvfsCreateHookContext(*params, ::GetModuleHandle(nullptr))); - usvfs::RedirectionTreeContainer& tree = m_Context->redirectionTable(); - tree.addFile( - ush::string_cast<std::string>(VIRTUAL_FILEW, ush::CodePage::UTF8).c_str(), - usvfs::RedirectionDataLocal(REAL_FILEA)); - } - - void TearDown() - { - std::array<char, 1024> buffer; - while (SHMLogger::instance().tryGet(buffer.data(), buffer.size())) { - std::cout << buffer.data() << std::endl; - } - m_Context.reset(); - SHMLogger::free(); - } - -private: - std::unique_ptr<usvfs::HookContext> m_Context; -}; - -class USVFSTestAuto : public testing::Test -{ -public: - void SetUp() - { - auto params = defaultUsvfsParams(); - usvfsConnectVFS(params.get()); - SHMLogger::create("usvfs"); - } - - void TearDown() - { - usvfsDisconnectVFS(); - - std::array<char, 1024> buffer; - while (SHMLogger::instance().tryGet(buffer.data(), buffer.size())) { - std::cout << buffer.data() << std::endl; - } - SHMLogger::free(); - } - -private: -}; - -TEST_F(USVFSTest, CanResizeRedirectiontree) -{ - using usvfs::shared::MissingThrow; - ASSERT_NO_THROW({ - usvfs::RedirectionTreeContainer container("treetest_shm", 1024); - for (char i = 'a'; i <= 'z'; ++i) { - for (char j = 'a'; j <= 'z'; ++j) { - std::string name = std::string(R"(C:\temp\)") + i + j; - container.addFile(name, usvfs::RedirectionDataLocal("gaga"), false); - } - } - - ASSERT_EQ("gaga", container->node("C:") - ->node("temp") - ->node("aa", MissingThrow) - ->data() - .linkTarget); - ASSERT_EQ("gaga", container->node("C:") - ->node("temp") - ->node("az", MissingThrow) - ->data() - .linkTarget); - }); -} - -/* -TEST_F(USVFSTest, CreateFileHookReportsCorrectErrorOnMissingFile) -{ - ASSERT_NO_THROW({ - USVFSParameters params; - USVFSInitParameters(¶ms, "usvfs_test", true, LogLevel::Debug, -CrashDumpsType::None, ""); std::unique_ptr<usvfs::HookContext> -ctx(CreateHookContext(params, ::GetModuleHandle(nullptr))); HANDLE res = -usvfs::hook_CreateFileW(VIRTUAL_FILEW , GENERIC_READ , FILE_SHARE_READ | -FILE_SHARE_WRITE , nullptr , OPEN_EXISTING , FILE_ATTRIBUTE_NORMAL , nullptr); - - ASSERT_EQ(INVALID_HANDLE_VALUE, res); - ASSERT_EQ(ERROR_FILE_NOT_FOUND, ::GetLastError()); - }); -} -*/ - -/* -TEST_F(USVFSTestWithReroute, CreateFileHookRedirectsFile) -{ - ASSERT_NE(INVALID_HANDLE_VALUE - , usvfs::hook_CreateFileW(VIRTUAL_FILEW - , GENERIC_READ - , FILE_SHARE_READ | FILE_SHARE_WRITE - , nullptr - , OPEN_EXISTING - , FILE_ATTRIBUTE_NORMAL - , nullptr)); -} -*/ - -TEST_F(USVFSTest, GetFileAttributesHookReportsCorrectErrorOnMissingFile) -{ - ASSERT_NO_THROW({ - try { - auto params = defaultUsvfsParams(); - std::unique_ptr<usvfs::HookContext> ctx( - usvfsCreateHookContext(*params, ::GetModuleHandle(nullptr))); - DWORD res = usvfs::hook_GetFileAttributesW(VIRTUAL_FILEW); - - ASSERT_EQ(INVALID_FILE_ATTRIBUTES, res); - ASSERT_EQ(ERROR_FILE_NOT_FOUND, ::GetLastError()); - } catch (const std::exception& e) { - logger()->error("Exception: {}", e.what()); - throw; - } - }); -} - -TEST_F(USVFSTest, GetFileAttributesHookRedirectsFile) -{ - auto params = defaultUsvfsParams(); - std::unique_ptr<usvfs::HookContext> ctx( - usvfsCreateHookContext(*params, ::GetModuleHandle(nullptr))); - usvfs::RedirectionTreeContainer& tree = ctx->redirectionTable(); - - tree.addFile( - ush::string_cast<std::string>(VIRTUAL_FILEW, ush::CodePage::UTF8).c_str(), - usvfs::RedirectionDataLocal(REAL_FILEA)); - - ASSERT_EQ(::GetFileAttributesW(REAL_FILEW), - usvfs::hook_GetFileAttributesW(VIRTUAL_FILEW)); -} -/* -TEST_F(USVFSTest, GetFullPathNameOnRegularCurrentDirectory) -{ - USVFSParameters params; - USVFSInitParameters(¶ms, "usvfs_test", true, LogLevel::Debug, -CrashDumpsType::None, ""); std::unique_ptr<usvfs::HookContext> -ctx(CreateHookContext(params, ::GetModuleHandle(nullptr))); - - std::wstring expected = winapi::wide::getCurrentDirectory() + L"\\filename.txt"; - - DWORD bufferLength = 32767; - std::unique_ptr<wchar_t[]> buffer(new wchar_t[bufferLength]); - LPWSTR filePart = nullptr; - - DWORD res = usvfs::hook_GetFullPathNameW(L"filename.txt", bufferLength, buffer.get(), -&filePart); - - ASSERT_NE(0UL, res); - ASSERT_EQ(expected, std::wstring(buffer.get())); -}*/ - -// small wrapper to call usvfs::hook_NtOpenFile with a path -// -// at some point in time, changes were made to USVFS such that calling a hooked -// function from a handle obtained from a non-hooked function would not work anymore, -// meaning that function such as CreateFileW that have no hook equivalent cannot -// be used to test hook functions -// -// this function is useful to simulate a CreateFileW by internally using the hook -// version of NtOpenFile -// -HANDLE hooked_NtOpenFile(LPCWSTR path, ACCESS_MASK accessMask, ULONG shareAccess, - ULONG openOptions) -{ - constexpr size_t BUFFER_SIZE = 2048; - IO_STATUS_BLOCK statusBlock; - OBJECT_ATTRIBUTES attributes; - attributes.SecurityDescriptor = 0; - attributes.SecurityQualityOfService = 0; - attributes.RootDirectory = 0; - attributes.Attributes = 0; - attributes.Length = sizeof(OBJECT_ATTRIBUTES); - - WCHAR stringBuffer[BUFFER_SIZE]; - UNICODE_STRING string; - string.Buffer = stringBuffer; - lstrcpyW(stringBuffer, L"\\??\\"); - lstrcatW(stringBuffer, path); - string.Length = static_cast<USHORT>(lstrlenW(stringBuffer) * 2); - string.MaximumLength = BUFFER_SIZE; - attributes.ObjectName = &string; - - HANDLE ret = INVALID_HANDLE_VALUE; - if (usvfs::hook_NtOpenFile(&ret, accessMask, &attributes, &statusBlock, shareAccess, - openOptions) != STATUS_SUCCESS) { - return INVALID_HANDLE_VALUE; - } - - return ret; -} - -TEST_F(USVFSTest, NtQueryDirectoryFileRegularFile) -{ - auto params = defaultUsvfsParams(); - std::unique_ptr<usvfs::HookContext> ctx( - usvfsCreateHookContext(*params, ::GetModuleHandle(nullptr))); - - HANDLE hdl = - hooked_NtOpenFile(L"C:\\", FILE_GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, - FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT); - ASSERT_NE(INVALID_HANDLE_VALUE, hdl); - - IO_STATUS_BLOCK status; - char buffer[1024]; - - usvfs::hook_NtQueryDirectoryFile(hdl, nullptr, nullptr, nullptr, &status, buffer, - 1024, FileDirectoryInformation, TRUE, nullptr, TRUE); - - ASSERT_EQ(STATUS_SUCCESS, status.Status); - - usvfs::hook_NtClose(hdl); -} - -TEST_F(USVFSTest, NtQueryDirectoryFileFindsVirtualFile) -{ - auto params = defaultUsvfsParams(); - std::unique_ptr<usvfs::HookContext> ctx( - usvfsCreateHookContext(*params, ::GetModuleHandle(nullptr))); - usvfs::RedirectionTreeContainer& tree = ctx->redirectionTable(); - - tree.addFile(L"C:\\np.exe", usvfs::RedirectionDataLocal(REAL_FILEA)); - - HANDLE hdl = - hooked_NtOpenFile(L"C:\\", FILE_GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, - FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT); - ASSERT_NE(INVALID_HANDLE_VALUE, hdl); - - IO_STATUS_BLOCK status; - char buffer[1024]; - - usvfs::UnicodeString fileName(L"np.exe"); - - usvfs::hook_NtQueryDirectoryFile(hdl, nullptr, nullptr, nullptr, &status, buffer, - 1024, FileDirectoryInformation, TRUE, - static_cast<PUNICODE_STRING>(fileName), TRUE); - - FILE_DIRECTORY_INFORMATION* info = - reinterpret_cast<FILE_DIRECTORY_INFORMATION*>(buffer); - ASSERT_EQ(STATUS_SUCCESS, status.Status); - ASSERT_EQ(0, wcscmp(info->FileName, L"np.exe")); - - usvfs::hook_NtClose(hdl); -} - -TEST_F(USVFSTest, NtQueryDirectoryFileExVirtualFile) -{ - auto params = defaultUsvfsParams(); - std::unique_ptr<usvfs::HookContext> ctx( - usvfsCreateHookContext(*params, ::GetModuleHandle(nullptr))); - usvfs::RedirectionTreeContainer& tree = ctx->redirectionTable(); - - tree.addFile(L"C:\\0123456789.txt", usvfs::RedirectionDataLocal(REAL_FILEA)); - tree.addFile(L"C:\\123456", usvfs::RedirectionDataLocal(REAL_FILEA)); - tree.addFile(L"C:\\abcdef", usvfs::RedirectionDataLocal(REAL_FILEA)); - tree.addFile(L"C:\\abcdefghijklmnopqrstuvwxyz.txt", - usvfs::RedirectionDataLocal(REAL_FILEA)); - - HANDLE hdl = - hooked_NtOpenFile(L"C:\\", FILE_GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, - FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT); - ASSERT_NE(INVALID_HANDLE_VALUE, hdl); - - IO_STATUS_BLOCK status; - - constexpr size_t BUFFER_SIZE = 2048; - char buffer[BUFFER_SIZE]; - - std::vector<std::wstring> foundFiles; - while (usvfs::hook_NtQueryDirectoryFileEx( - hdl, nullptr, nullptr, nullptr, &status, buffer, BUFFER_SIZE, - FileFullDirectoryInformation, 0, nullptr) == STATUS_SUCCESS) { - std::size_t offset = 0; - while (offset < BUFFER_SIZE) { - const auto* info = reinterpret_cast<FILE_FULL_DIR_INFORMATION*>(buffer + offset); - foundFiles.emplace_back(info->FileName, info->FileNameLength / sizeof(wchar_t)); - - if (info->NextEntryOffset == 0) { - break; // no more entries - } - - offset += info->NextEntryOffset; - } - } - - ASSERT_THAT(foundFiles, - ::testing::IsSupersetOf({L"0123456789.txt", L"123456", L"abcdef", - L"abcdefghijklmnopqrstuvwxyz.txt"})); - - usvfs::hook_NtClose(hdl); -} - -TEST_F(USVFSTest, NtQueryObjectVirtualFile) -{ - std::wstring c_drive_device; - { - // find the device path for C: - HANDLE hdl = ::CreateFileW( - L"C:\\", GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr, - OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_BACKUP_SEMANTICS, nullptr); - ASSERT_NE(INVALID_HANDLE_VALUE, hdl); - - char buffer[2048]; - ASSERT_EQ(STATUS_SUCCESS, ::NtQueryObject(hdl, ObjectNameInformation, buffer, - sizeof(buffer), nullptr)); - - OBJECT_NAME_INFORMATION* information = - reinterpret_cast<OBJECT_NAME_INFORMATION*>(buffer); - - c_drive_device = - std::wstring(information->Name.Buffer, information->Name.Length / 2); - - ::CloseHandle(hdl); - } - - auto params = defaultUsvfsParams(); - std::unique_ptr<usvfs::HookContext> ctx( - usvfsCreateHookContext(*params, ::GetModuleHandle(nullptr))); - usvfs::RedirectionTreeContainer& tree = ctx->redirectionTable(); - - tree.addFile(L"C:\\np.exe", usvfs::RedirectionDataLocal(REAL_FILEA)); - - HANDLE hdl = hooked_NtOpenFile(L"C:\\np.exe", FILE_GENERIC_READ, - FILE_SHARE_READ | FILE_SHARE_WRITE, - FILE_NON_DIRECTORY_FILE | FILE_OPEN_FOR_BACKUP_INTENT); - ASSERT_NE(INVALID_HANDLE_VALUE, hdl) << "last error=" << ::GetLastError(); - - { - char buffer[1024]; - IO_STATUS_BLOCK status; - const auto res = usvfs::hook_NtQueryInformationFile( - hdl, &status, buffer, sizeof(buffer), FileNameInformation); - ASSERT_EQ(STATUS_SUCCESS, res); - ASSERT_EQ(STATUS_SUCCESS, status.Status); - - FILE_NAME_INFORMATION* fileNameInfo = - reinterpret_cast<FILE_NAME_INFORMATION*>(buffer); - ASSERT_EQ(L"\\np.exe", - std::wstring(fileNameInfo->FileName, fileNameInfo->FileNameLength / 2)); - } - - { - char buffer[1024]; - IO_STATUS_BLOCK status; - const auto res = usvfs::hook_NtQueryInformationFile( - hdl, &status, buffer, sizeof(buffer), FileNormalizedNameInformation); - ASSERT_EQ(STATUS_SUCCESS, res); - ASSERT_EQ(STATUS_SUCCESS, status.Status); - ASSERT_EQ(sizeof(ULONG) + 7 * 2, status.Information); - - FILE_NAME_INFORMATION* fileNameInfo = - reinterpret_cast<FILE_NAME_INFORMATION*>(buffer); - ASSERT_EQ(L"\\np.exe", - std::wstring(fileNameInfo->FileName, fileNameInfo->FileNameLength / 2)); - } - - // buffer of size should be too small for the original path (\Windows\notepad.exe) - // but not for \np.exe - { - // the required size should be sizeof(ULONG) + 7 * 2 but apparently that is - // not enough for the CI so using 16 * 2 which should be large enough for - // the hooked version, but still too short for the non-hooked one - char buffer[sizeof(ULONG) + 7 * 2]; - IO_STATUS_BLOCK status; - NTSTATUS res; - - res = ::NtQueryInformationFile(hdl, &status, buffer, sizeof(buffer), - FileNameInformation); - ASSERT_EQ(STATUS_BUFFER_OVERFLOW, res); - ASSERT_EQ(STATUS_BUFFER_OVERFLOW, status.Status); - - res = usvfs::hook_NtQueryInformationFile(hdl, &status, buffer, sizeof(buffer), - FileNameInformation); - ASSERT_EQ(STATUS_SUCCESS, res); - ASSERT_EQ(STATUS_SUCCESS, status.Status); - ASSERT_EQ(sizeof(ULONG) + 7 * 2, status.Information); - - FILE_NAME_INFORMATION* fileNameInfo = - reinterpret_cast<FILE_NAME_INFORMATION*>(buffer); - ASSERT_EQ(L"\\np.exe", - std::wstring(fileNameInfo->FileName, fileNameInfo->FileNameLength / 2)); - } - - { - char buffer[2048]; - const auto res = usvfs::hook_NtQueryObject(hdl, ObjectNameInformation, buffer, - sizeof(buffer), nullptr); - ASSERT_EQ(STATUS_SUCCESS, res); - - OBJECT_NAME_INFORMATION* information = - reinterpret_cast<OBJECT_NAME_INFORMATION*>(buffer); - ASSERT_EQ(c_drive_device + L"np.exe", - std::wstring(information->Name.Buffer, - information->Name.Length / sizeof(wchar_t))); - } - - { - // expected length is sizeof struct + size of path (in bytes), including the - // null-character - const auto expectedLength = - sizeof(OBJECT_NAME_INFORMATION) + c_drive_device.size() * 2 + 12 + 2; - ULONG requiredLength; - NTSTATUS res; - char buffer[2048]; - - res = - usvfs::hook_NtQueryObject(hdl, ObjectNameInformation, buffer, - sizeof(OBJECT_NAME_INFORMATION) - 1, &requiredLength); - ASSERT_EQ(STATUS_INFO_LENGTH_MISMATCH, res); - ASSERT_EQ(expectedLength, requiredLength); - - res = usvfs::hook_NtQueryObject(hdl, ObjectNameInformation, buffer, - sizeof(OBJECT_NAME_INFORMATION), &requiredLength); - ASSERT_EQ(STATUS_BUFFER_OVERFLOW, res); - ASSERT_EQ(expectedLength, requiredLength); - } - - usvfs::hook_NtClose(hdl); -} - -TEST_F(USVFSTestAuto, CannotCreateLinkToFileInNonexistantDirectory) -{ - ASSERT_EQ(FALSE, usvfsVirtualLinkFile( - REAL_FILEW, L"c:/this_directory_shouldnt_exist/np.exe", FALSE)); -} - -TEST_F(USVFSTestAuto, CanCreateMultipleLinks) -{ - static LPCWSTR outFile = LR"(C:\np.exe)"; - static LPCWSTR outDir = LR"(C:\logs)"; - static LPCWSTR outDirCanonizeTest = LR"(C:\.\not/../logs\.\a\.\b\.\c\..\.\..\.\..\)"; - ASSERT_EQ(TRUE, usvfsVirtualLinkFile(REAL_FILEW, outFile, 0)); - ASSERT_EQ(TRUE, usvfsVirtualLinkDirectoryStatic(REAL_DIRW, outDir, 0)); - - // both file and dir exist and have the correct type - ASSERT_NE(INVALID_FILE_ATTRIBUTES, usvfs::hook_GetFileAttributesW(outFile)); - ASSERT_NE(INVALID_FILE_ATTRIBUTES, usvfs::hook_GetFileAttributesW(outDir)); - ASSERT_EQ(0UL, usvfs::hook_GetFileAttributesW(outFile) & FILE_ATTRIBUTE_DIRECTORY); - ASSERT_NE(0UL, usvfs::hook_GetFileAttributesW(outDir) & FILE_ATTRIBUTE_DIRECTORY); - ASSERT_NE(0UL, usvfs::hook_GetFileAttributesW(outDirCanonizeTest) & - FILE_ATTRIBUTE_DIRECTORY); -} - -int main(int argc, char** argv) -{ - using namespace test; - - auto dllPath = path_of_usvfs_lib(platform_dependant_executable("usvfs", "dll")); - ScopedLoadLibrary loadDll(dllPath.c_str()); - if (!loadDll) { - std::wcerr << L"failed to load usvfs dll: " << dllPath.c_str() << L", " - << GetLastError() << std::endl; - return 1; - } - - // note: this makes the logger available only to functions statically linked to the - // test binary, not those called in the dll - auto logger = spdlog::stdout_logger_mt("usvfs"); - logger->set_level(spdlog::level::warn); - testing::InitGoogleTest(&argc, argv); - int res = RUN_ALL_TESTS(); - - return res; -} diff --git a/libs/usvfs/test/usvfs_global_test_runner/CMakeLists.txt b/libs/usvfs/test/usvfs_global_test_runner/CMakeLists.txt deleted file mode 100644 index 88ff0c2..0000000 --- a/libs/usvfs/test/usvfs_global_test_runner/CMakeLists.txt +++ /dev/null @@ -1,23 +0,0 @@ -cmake_minimum_required(VERSION 3.16) - -find_package(GTest CONFIG REQUIRED) -find_package(Boost CONFIG REQUIRED COMPONENTS filesystem) - -# other executables -add_executable(usvfs_global_test - usvfs_global_test/usvfs_global_test.cpp -) -usvfs_set_test_properties(usvfs_global_test FOLDER usvfs_global_test) -target_link_libraries(usvfs_global_test PRIVATE gtest_utils GTest::gtest_main GTest::gmock Boost::filesystem) - -# actual test executable -add_executable(usvfs_global_test_runner - usvfs_global_test_fixture.cpp - usvfs_global_test_fixture.h - usvfs_global_test_runner.cpp -) -usvfs_set_test_properties(usvfs_global_test_runner FOLDER usvfs_global_test) -usvfs_target_link_usvfs(usvfs_global_test_runner) -target_link_libraries(usvfs_global_test_runner - PRIVATE test_utils gtest_utils GTest::gtest_main) -add_dependencies(usvfs_global_test_runner usvfs_global_test) diff --git a/libs/usvfs/test/usvfs_global_test_runner/usvfs_global_test/usvfs_global_test.cpp b/libs/usvfs/test/usvfs_global_test_runner/usvfs_global_test/usvfs_global_test.cpp deleted file mode 100644 index 79c6c4c..0000000 --- a/libs/usvfs/test/usvfs_global_test_runner/usvfs_global_test/usvfs_global_test.cpp +++ /dev/null @@ -1,216 +0,0 @@ -#include <gtest/gtest.h> - -#define WIN32_LEAN_AND_MEAN -#include <Windows.h> - -#include <filesystem> -#include <fstream> - -#include <boost/filesystem.hpp> - -#include <gmock/gmock-matchers.h> -#include <gtest_utils.h> - -// anonymous class that allow tests to access parameters (currently only where the -// virtualized data folder is) -// -class -{ - bool initialize(int argc, char* argv[]) - { - // extract the data path - if (argc != 2) { - std::cerr << "missing data path, aborting\n"; - return false; - } - m_data = std::filesystem::path{argv[1]}; - - if (!exists(m_data)) { - std::cerr << "data path '" << m_data.string() << "'does not exist\n"; - return false; - } - - return true; - } - - friend int main(int argc, char* argv[]); - std::filesystem::path m_data; - -public: - const auto& data() const { return m_data; } -} parameters; - -// simple guard for handle -class HandleGuard -{ - HANDLE m_handle = INVALID_HANDLE_VALUE; - -public: - HandleGuard() = default; - HandleGuard(HANDLE handle) : m_handle{handle} {} - - ~HandleGuard() { close(); } - - operator HANDLE() { return m_handle; } - - void close() - { - if (m_handle != INVALID_HANDLE_VALUE) { - ::CloseHandle(m_handle); - m_handle = INVALID_HANDLE_VALUE; - } - } -}; - -// simple function to write content to a specified path -void write_content(const std::filesystem::path& path, const std::string_view content) -{ - std::ofstream ofs{path}; - ofs << content; -} - -TEST(BasicTest, SimpleTest) -{ - const auto data = parameters.data(); - - ASSERT_TRUE(exists(data)); - ASSERT_TRUE(exists(data / "docs")); - ASSERT_TRUE(exists(data / "empty")); - ASSERT_TRUE(exists(data / "docs" / "doc.txt")); - ASSERT_TRUE(exists(data / "readme.txt")); - - // should remove mods/mod1/info.txt - ASSERT_TRUE(exists(data / "info.txt")); - remove(data / "info.txt"); - ASSERT_FALSE(exists(data / "info.txt")); - - { - // retrieve the path of data using GetFinalPathNameByHandleW() to - // compare later on - std::filesystem::path dataPathFromHandle; - { - HandleGuard hdl = CreateFileW(data.c_str(), GENERIC_READ, 0, nullptr, - OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, nullptr); - ASSERT_NE(INVALID_HANDLE_VALUE, (HANDLE)hdl); - - WCHAR filepath[1024]; - const auto length = GetFinalPathNameByHandleW( - hdl, filepath, sizeof(filepath) / sizeof(WCHAR), FILE_NAME_NORMALIZED); - ASSERT_NE(0, length); - - dataPathFromHandle = std::filesystem::path(std::wstring(filepath, length)); - } - - const auto doc_txt = data / "docs" / "doc.txt"; - HandleGuard hdl = CreateFileW(doc_txt.c_str(), GENERIC_READ, 0, nullptr, - OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, nullptr); - ASSERT_NE(INVALID_HANDLE_VALUE, (HANDLE)hdl); - - WCHAR filepath[1024]; - const auto length = GetFinalPathNameByHandleW( - hdl, filepath, sizeof(filepath) / sizeof(WCHAR), FILE_NAME_NORMALIZED); - ASSERT_NE(0, length); - - ASSERT_EQ(dataPathFromHandle / "docs" / "doc.txt", - std::filesystem::path(std::wstring(filepath, length))); - } - - { - // retrieve the path of data using GetFileInformationByHandleEx() to - // compare later on - std::filesystem::path dataPathFromHandle; - { - HandleGuard hdl = CreateFileW(data.c_str(), GENERIC_READ, 0, nullptr, - OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, nullptr); - ASSERT_NE(INVALID_HANDLE_VALUE, (HANDLE)hdl); - - char buffer[4096]; - ASSERT_TRUE( - GetFileInformationByHandleEx(hdl, FileNameInfo, buffer, sizeof(buffer))); - auto* info = reinterpret_cast<FILE_NAME_INFO*>(buffer); - - dataPathFromHandle = std::filesystem::path( - std::wstring_view(info->FileName, info->FileNameLength / 2)); - } - - const auto info_txt = data / "readme.txt"; - HandleGuard hdl = CreateFileW(info_txt.c_str(), GENERIC_READ, 0, nullptr, - OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, nullptr); - ASSERT_NE(INVALID_HANDLE_VALUE, (HANDLE)hdl); - - char buffer[4096]; - ASSERT_TRUE( - GetFileInformationByHandleEx(hdl, FileNameInfo, buffer, sizeof(buffer))); - - auto* info = reinterpret_cast<FILE_NAME_INFO*>(buffer); - - ASSERT_EQ(dataPathFromHandle / "readme.txt", - std::filesystem::path( - std::wstring_view(info->FileName, info->FileNameLength / 2))); - } -} - -TEST(BoostFilesystemTest, BoostFilesystemTest) -{ - using namespace boost::filesystem; - - const path data{parameters.data().native()}; - - std::vector<std::string> contents; - for (recursive_directory_iterator it{data}; it != recursive_directory_iterator{}; - ++it) { - contents.push_back(relative(it->path(), data).string()); - } - ASSERT_THAT(contents, ::testing::UnorderedElementsAre( - ".gitkeep", "docs", "docs\\doc.txt", "docs\\subdocs", - "docs\\subdocs\\.gitkeep")); -} - -// see https://github.com/ModOrganizer2/modorganizer/issues/2039 for context -// -TEST(RedFileSystemTest, RedFileSystemTest) -{ - const auto data = parameters.data(); - - const auto storages_path = data / "r6" / "storages"; - const auto hudpainter_path = storages_path / "HUDPainter"; - - ASSERT_TRUE(exists(hudpainter_path / "DEFAULT.json")); - - // TEST.json does not exist, so will be created in overwrite - this mainly check that - // weakly_canonical returns the path under data/ and not the actual path under - // overwrite/ - // - // this relies on the hook for NtQueryInformationFile - // - ASSERT_FALSE(exists(hudpainter_path / "TEST.json")); - ASSERT_EQ(hudpainter_path / "TEST.json", - weakly_canonical(hudpainter_path / "TEST.json")); - write_content(hudpainter_path / "TEST.json", "{}"); -} - -TEST(SkipFilesTest, SkipFilesTest) -{ - const auto data = parameters.data(); - - // file in mod1 should have been skipped - ASSERT_FALSE(exists(data / "readme.skip")); - - // docs/doc.skip should come from data, not mods1/docs/doc.skip - ASSERT_CONTENT_EQ("doc.skip in data/docs", data / "docs" / "doc.skip"); - - // write to readme.skip should create a file in overwrite - write_content(data / "readme.skip", "readme.skip in overwrite"); -} - -int main(int argc, char* argv[]) -{ - testing::InitGoogleTest(&argc, argv); - - // initialize parameters from remaining arguments - if (!parameters.initialize(argc, argv)) { - return -1; - } - - return RUN_ALL_TESTS(); -} diff --git a/libs/usvfs/test/usvfs_global_test_runner/usvfs_global_test_fixture.cpp b/libs/usvfs/test/usvfs_global_test_runner/usvfs_global_test_fixture.cpp deleted file mode 100644 index 4f6e672..0000000 --- a/libs/usvfs/test/usvfs_global_test_runner/usvfs_global_test_fixture.cpp +++ /dev/null @@ -1,205 +0,0 @@ -#include "usvfs_global_test_fixture.h" - -#include <filesystem> -#include <format> -#include <fstream> - -#include <gtest/gtest.h> - -#include <stringcast.h> -#include <test_helpers.h> -#include <usvfs.h> -#include <windows_sane.h> - -// find the path to the executable that contains gtest entries -// -std::filesystem::path path_to_usvfs_global_test() -{ - return test::path_of_test_bin( - test::platform_dependant_executable("usvfs_global_test", "exe")); -} - -// path to the fixture for the given test group -// -std::filesystem::path path_to_usvfs_global_test_figures(std::wstring_view group) -{ - return test::path_of_test_fixtures() / "usvfs_global_test" / group; -} - -// spawn the an hook version of the given -// -DWORD spawn_usvfs_hooked_process( - const std::filesystem::path& app, const std::vector<std::wstring>& arguments = {}, - const std::optional<std::filesystem::path>& working_directory = {}) -{ - using namespace usvfs::shared; - - std::wstring command = app; - std::filesystem::path cwd = working_directory.value_or(app.parent_path()); - std::vector<wchar_t> env; - - if (!arguments.empty()) { - command += L" " + boost::algorithm::join(arguments, L" "); - } - - STARTUPINFO si{0}; - si.cb = sizeof(si); - PROCESS_INFORMATION pi{0}; - -#pragma warning(push) -#pragma warning(disable : 6387) - - if (!usvfsCreateProcessHooked(nullptr, command.data(), nullptr, nullptr, FALSE, 0, - nullptr, cwd.c_str(), &si, &pi)) { - test::throw_testWinFuncFailed( - "CreateProcessHooked", - string_cast<std::string>(command, CodePage::UTF8).c_str()); - } - - WaitForSingleObject(pi.hProcess, INFINITE); - - DWORD exit = 99; - if (!GetExitCodeProcess(pi.hProcess, &exit)) { - test::WinFuncFailedGenerator failed; - CloseHandle(pi.hProcess); - CloseHandle(pi.hThread); - throw failed("GetExitCodeProcess"); - } - - CloseHandle(pi.hProcess); - CloseHandle(pi.hThread); - -#pragma warning(pop) - - return exit; -} - -bool UsvfsGlobalTest::m_force_usvfs_logs = false; - -void UsvfsGlobalTest::ForceUsvfsLogs() -{ - m_force_usvfs_logs = true; -} - -class UsvfsGlobalTest::UsvfsGuard -{ -public: - UsvfsGuard(std::string_view instance_name = "usvfs_test", bool logging = false) - : m_parameters(usvfsCreateParameters(), &usvfsFreeParameters) - { - usvfsSetInstanceName(m_parameters.get(), instance_name.data()); - usvfsSetDebugMode(m_parameters.get(), false); - usvfsSetLogLevel(m_parameters.get(), LogLevel::Debug); - usvfsSetCrashDumpType(m_parameters.get(), CrashDumpsType::None); - usvfsSetCrashDumpPath(m_parameters.get(), ""); - - usvfsInitLogging(logging); - usvfsCreateVFS(m_parameters.get()); - } - - ~UsvfsGuard() { usvfsDisconnectVFS(); } - -private: - std::unique_ptr<usvfsParameters, decltype(&usvfsFreeParameters)> m_parameters; -}; - -UsvfsGlobalTest::UsvfsGlobalTest() - : m_usvfs{std::make_unique<UsvfsGuard>()}, - m_temporary_folder{test::path_of_test_temp()} -{ - std::string name{testing::UnitTest::GetInstance()->current_test_info()->name()}; - m_group = {name.begin(), name.end()}; -} - -UsvfsGlobalTest::~UsvfsGlobalTest() -{ - CleanUp(); -} - -std::filesystem::path UsvfsGlobalTest::ActualFolder() const -{ - return m_temporary_folder; -} - -std::filesystem::path UsvfsGlobalTest::ExpectedFolder() const -{ - return path_to_usvfs_global_test_figures(m_group) / "expected"; -} - -void UsvfsGlobalTest::CleanUp() const -{ - if (exists(m_temporary_folder)) { - remove_all(m_temporary_folder); - } -} - -void UsvfsGlobalTest::PrepareFileSystem() const -{ - // cleanup in case a previous tests failed to delete its stuff - CleanUp(); - - // copy fixtures - const auto fixtures = path_to_usvfs_global_test_figures(m_group) / "source"; - if (exists(fixtures)) { - copy(fixtures, m_temporary_folder, std::filesystem::copy_options::recursive); - } -} - -void UsvfsGlobalTest::SetUpOverwrite(bool force) const -{ - if (force && !exists(m_overwrite_folder)) { - create_directory(m_overwrite_folder); - } - - if (exists(m_overwrite_folder)) { - usvfsVirtualLinkDirectoryStatic(m_overwrite_folder.c_str(), m_data_folder.c_str(), - LINKFLAG_CREATETARGET | LINKFLAG_RECURSIVE); - } -} - -void UsvfsGlobalTest::PrepareMapping() const -{ - // should not be needed, but just to be safe - usvfsClearVirtualMappings(); - - if (!exists(m_data_folder)) { - throw std::runtime_error{ - std::format("data path missing at {}", m_data_folder.string())}; - } - - if (exists(m_mods_folder)) { - for (const auto& mod : std::filesystem::directory_iterator(m_mods_folder)) { - if (!is_directory(mod)) { - continue; - } - usvfsVirtualLinkDirectoryStatic(mod.path().c_str(), m_data_folder.c_str(), - LINKFLAG_RECURSIVE); - } - } - - // by default, only create overwrite if present - SetUpOverwrite(false); -} - -int UsvfsGlobalTest::Run() const -{ - PrepareMapping(); - - const auto res = spawn_usvfs_hooked_process( - path_to_usvfs_global_test(), {std::format(L"--gtest_filter={}.*", m_group), - L"--gtest_brief=1", m_data_folder.native()}); - - // TODO: try to do this with gtest itself? - if (m_force_usvfs_logs || res != 0) { - const auto log_path = test::path_of_test_bin(m_group + L".log"); - std::ofstream os{log_path}; - std::string buffer(1024, '\0'); - std::cout << "process returned " << std::hex << res << ", usvfs logs dumped to " - << log_path.string() << '\n'; - while (usvfsGetLogMessages(buffer.data(), buffer.size(), false)) { - os << " " << buffer.c_str() << "\n"; - } - } - - return res; -} diff --git a/libs/usvfs/test/usvfs_global_test_runner/usvfs_global_test_fixture.h b/libs/usvfs/test/usvfs_global_test_runner/usvfs_global_test_fixture.h deleted file mode 100644 index aeafc25..0000000 --- a/libs/usvfs/test/usvfs_global_test_runner/usvfs_global_test_fixture.h +++ /dev/null @@ -1,82 +0,0 @@ -#pragma once - -#include <filesystem> -#include <memory> - -#include <gtest/gtest.h> - -class UsvfsGlobalTest : public testing::Test -{ -public: - // enable log mode - this will generate USVFS log file for all tests regardless of - // success or failure (default is to only generate for failure) - // - static void ForceUsvfsLogs(); - -public: - UsvfsGlobalTest(); - - void SetUp() override { PrepareFileSystem(); } - - void TearDown() override { CleanUp(); } - - ~UsvfsGlobalTest(); - - // setup the overwrite folder - // - // if force is true, force creation of the overwrite folder even if not present, this - // is useful when the overwrite is initially empty and thus cannot be committed to git - // but need to contain files after the run - // - void SetUpOverwrite(bool force = true) const; - - // run the test, return the exit code of the google test process - // - int Run() const; - - // return the path to the folder containing the expected results - // - std::filesystem::path ActualFolder() const; - - // return the path to the folder containing the expected results - // - std::filesystem::path ExpectedFolder() const; - -private: - class UsvfsGuard; - - // always generate usvfs logs - static bool m_force_usvfs_logs; - - // prepare the filesystem by copying files and folders from the relevant fixtures - // folder to the temporary folder - // - // after this operations, the temporary folder will contain - // - a data folder - // - [optional] a mods folder containing a set of folders that should be mounted - // - [optional] an overwrite folder that should be mounted as overwrite - // - void PrepareFileSystem() const; - - // prepare mapping using the given set of paths - // - void PrepareMapping() const; - - // cleanup the temporary path - // - void CleanUp() const; - - // usvfs_guard - std::unique_ptr<UsvfsGuard> m_usvfs; - - // name of GTest group (first argument of the TEST macro) to run - std::wstring m_group; - - // path to the folder containing temporary files - std::filesystem::path m_temporary_folder; - - // path to the subfolder inside the temporary folder - std::filesystem::path m_data_folder = m_temporary_folder / "data"; - std::filesystem::path m_mods_folder = m_temporary_folder / "mods"; - std::filesystem::path m_overwrite_folder = m_temporary_folder / "overwrite"; -}; diff --git a/libs/usvfs/test/usvfs_global_test_runner/usvfs_global_test_runner.cpp b/libs/usvfs/test/usvfs_global_test_runner/usvfs_global_test_runner.cpp deleted file mode 100644 index 2fa6cc8..0000000 --- a/libs/usvfs/test/usvfs_global_test_runner/usvfs_global_test_runner.cpp +++ /dev/null @@ -1,58 +0,0 @@ -#include <gtest/gtest.h> - -#include <gtest_utils.h> -#include <test_helpers.h> -#include <usvfs.h> - -#include "usvfs_global_test_fixture.h" - -TEST_F(UsvfsGlobalTest, BasicTest) -{ - ASSERT_EQ(0, Run()); - ASSERT_DIRECTORY_EQ(ExpectedFolder(), ActualFolder()); -} - -TEST_F(UsvfsGlobalTest, BoostFilesystemTest) -{ - ASSERT_EQ(0, Run()); - ASSERT_DIRECTORY_EQ(ExpectedFolder(), ActualFolder()); -} - -TEST_F(UsvfsGlobalTest, RedFileSystemTest) -{ - SetUpOverwrite(true); - ASSERT_EQ(0, Run()); - ASSERT_DIRECTORY_EQ(ExpectedFolder(), ActualFolder()); -} - -TEST_F(UsvfsGlobalTest, SkipFilesTest) -{ - SetUpOverwrite(true); - - usvfsAddSkipFileSuffix(L".skip"); - - ASSERT_EQ(0, Run()); - ASSERT_DIRECTORY_EQ(ExpectedFolder(), ActualFolder()); -} - -int main(int argc, char* argv[]) -{ - // load the USVFS DLL - // - const auto usvfs_dll = - test::path_of_usvfs_lib(test::platform_dependant_executable("usvfs", "dll")); - test::ScopedLoadLibrary loadDll(usvfs_dll.c_str()); - if (!loadDll) { - std::wcerr << L"ERROR: failed to load usvfs dll: " << usvfs_dll.c_str() << L", " - << GetLastError() << L"\n"; - return 3; - } - - testing::InitGoogleTest(&argc, argv); - - UsvfsGlobalTest::ForceUsvfsLogs(); - - usvfsInitLogging(false); - - return RUN_ALL_TESTS(); -} diff --git a/libs/usvfs/test/usvfs_test_runner/CMakeLists.txt b/libs/usvfs/test/usvfs_test_runner/CMakeLists.txt deleted file mode 100644 index a0a7ca9..0000000 --- a/libs/usvfs/test/usvfs_test_runner/CMakeLists.txt +++ /dev/null @@ -1,35 +0,0 @@ -cmake_minimum_required(VERSION 3.16) - -find_package(GTest CONFIG REQUIRED) - -# other executables -add_executable(test_file_operations - test_file_operations/test_file_operations.cpp - test_file_operations/test_filesystem.cpp - test_file_operations/test_filesystem.h - test_file_operations/test_ntapi.cpp - test_file_operations/test_ntapi.h - test_file_operations/test_ntdll_declarations.h - test_file_operations/test_w32api.cpp - test_file_operations/test_w32api.h -) -usvfs_set_test_properties(test_file_operations FOLDER usvfs_test_runner) -target_link_libraries(test_file_operations PRIVATE test_utils ntdll) - -add_executable(usvfs_test - usvfs_test/usvfs_basic_test.cpp - usvfs_test/usvfs_basic_test.h - usvfs_test/usvfs_test_base.cpp - usvfs_test/usvfs_test_base.h - usvfs_test/usvfs_test.cpp -) -usvfs_set_test_properties(usvfs_test FOLDER usvfs_test_runner) -usvfs_target_link_usvfs(usvfs_test) -target_link_libraries(usvfs_test PRIVATE test_utils) - -# actual test executable -add_executable(usvfs_test_runner usvfs_test_runner.cpp) -usvfs_set_test_properties(usvfs_test_runner FOLDER usvfs_test_runner) -target_link_libraries(usvfs_test_runner - PRIVATE test_utils GTest::gtest GTest::gtest_main) -add_dependencies(usvfs_test_runner usvfs_test test_file_operations) diff --git a/libs/usvfs/test/usvfs_test_runner/test_file_operations/test_file_operations.cpp b/libs/usvfs/test/usvfs_test_runner/test_file_operations/test_file_operations.cpp deleted file mode 100644 index 2135df3..0000000 --- a/libs/usvfs/test/usvfs_test_runner/test_file_operations/test_file_operations.cpp +++ /dev/null @@ -1,496 +0,0 @@ -#include <cstdio> -#include <stdexcept> - -#include <boost/filesystem.hpp> -#include <boost/type_traits.hpp> -#include <winapi.h> - -#include "test_ntapi.h" -#include "test_w32api.h" -#include <test_helpers.h> - -#define WIN32_LEAN_AND_MEAN -#include <Windows.h> - -using usvfs::shared::CodePage; -using usvfs::shared::string_cast; - -void print_usage(const char* myname) -{ - using namespace std; - fprintf(stderr, "usage: %s [<options>] <command> [<command params>] ...\n", myname); - fprintf(stderr, - "options and commands are parsed and executed in the order they appear.\n"); - fprintf(stderr, "\nsupported commands:\n"); - fprintf( - stderr, - " -list <dir> : lists the given directory and outputs the results.\n"); - fprintf(stderr, " -listcontents <dir> : lists the given directory, reading all files " - "and outputs the results.\n"); - fprintf(stderr, - " -read <file> : reads the given file and outputs the results.\n"); - fprintf(stderr, " -overwrite <file> <string> : overwrites the file at the given path " - "with the given line (creating directories if in recursive mode).\n"); - fprintf(stderr, " -deleteoverwrite <file> <string> : shorthand for -delete <file> " - "-overwrite <file> <string>\n"); - fprintf(stderr, - " -rewrite <file> <string> : rewrites the file at the given path with the " - "given line (fails if file doesn't exist; uses read/write access).\n"); - fprintf(stderr, - " -touch <file> : updates last write timestamp of specified file.\n"); - fprintf(stderr, " -touchw <file> : updates last write timestamp using full " - "write permissions.\n"); - fprintf(stderr, " -delete <file> : deletes the given file.\n"); - fprintf(stderr, " -copy <src> <dst> : copies the given file.\n"); - fprintf(stderr, " -copyover <src> <dst> : copies the given file (replacing existing " - "destination).\n"); - fprintf(stderr, " -rename <src> <dst> : renames the given file.\n"); - fprintf(stderr, " -renameover <src> <dst> : renames the given file (replacing " - "existing destination).\n"); - fprintf(stderr, " -deleterename <src> <dst> : shorthand for -delete <dst> -rename " - "<src> <dst>.\n"); - fprintf(stderr, - " -move <src> <dst> : moves the given file (not supported by ntapi).\n"); - fprintf(stderr, " -moveover <src> <dst> : moves the given file (replacing existing " - "destination; not supported by ntapi).\n"); - fprintf( - stderr, - " -deletemove <src> <dst> : shorthand for -delete <dst> -move <src> <dst>.\n"); - fprintf(stderr, " -debug : shows a message box and wait for a debugger " - "to connect.\n"); - fprintf(stderr, "\nsupported options:\n"); - fprintf(stderr, " -out <file> : file to log output to (use \"-\" for the " - "stdout; otherwise path to output should exist).\n"); - fprintf(stderr, " -out+ <file> : similar to -out but appends the file instead " - "of overwriting it.\n"); - fprintf(stderr, " -cout <file> : similar to -out but does not log PID and " - "other info which may change between runs.\n"); - fprintf(stderr, " -cout+ <file> : similar to -cout but appends the file " - "instead of overwriting it.\n"); - fprintf(stderr, " -r : recursively list/create directories.\n"); - fprintf(stderr, - " -r- : don't recursively list/create directories.\n"); - fprintf(stderr, " -basedir <dir> : any paths under the basedir will outputed in " - "a relative manner (default is current directory).\n"); - fprintf(stderr, - " -w32api : use regular Win32 API for file access (default).\n"); - fprintf(stderr, - " -ntapi : use lower level ntdll functions for file access.\n"); -} - -class CommandExecuter -{ -public: - CommandExecuter() : m_output(stdout), m_api(&w32api) - { - set_basedir(TestFileSystem::current_directory().string().c_str()); - } - - ~CommandExecuter() - { - if (m_output && m_output != stdout) - fclose(m_output); - } - - FILE* output() const { return m_output; } - - bool file_output() const { return m_output != stdout; } - - // Options: - - void set_output(const char* output_file, bool clean, bool append, const char* cmdline) - { - if (m_output && m_output != stdout) { - fprintf(m_output, "#< Output log closed.\n", output_file); - fclose(m_output); - } - - m_cleanoutput = clean; - m_output = nullptr; - errno_t err = fopen_s(&m_output, output_file, append ? "at" : "wt"); - if (err || !m_output) - test::throw_testWinFuncFailed("fopen_s", output_file, err); - else { - if (m_cleanoutput) - fprintf(m_output, "#> Output log openned for: %s\n", - clean_cmdline_heuristic(cmdline).c_str()); - else - fprintf(m_output, "#> Output log openned for (pid %d): %s\n", - GetCurrentProcessId(), cmdline); - w32api.set_output(m_output, m_cleanoutput); - ntapi.set_output(m_output, m_cleanoutput); - } - } - - bool cleanoutput() const { return m_cleanoutput; } - - void set_recursive(bool recursive) { m_recursive = recursive; } - - void set_basedir(const char* basedir) - { - w32api.set_basepath(basedir); - ntapi.set_basepath(basedir); - } - - void set_ntapi(bool enable) - { - if (enable) - m_api = &ntapi; - else - m_api = &w32api; - } - - // Commands: - - void list(const char* dir, bool read_files) - { - if (debug_pending()) - __debugbreak(); - - list_impl(m_api->real_path(dir), read_files); - } - - void read(const char* path) - { - if (debug_pending()) - __debugbreak(); - - m_api->read_file(m_api->real_path(path)); - } - - void overwrite(const char* path, const char* value) - { - if (debug_pending()) - __debugbreak(); - - const auto& real = real_path_create_if_necessary(path); - - m_api->write_file(real, value, strlen(value), true, - TestFileSystem::write_mode::overwrite); - } - - void rewrite(const char* path, const char* value) - { - if (debug_pending()) - __debugbreak(); - - const auto& real = real_path_create_if_necessary(path); - - // Use read/write access when rewriting to "simulate" the harder case where it is - // not known if the file is going to actually be changed - m_api->write_file(real, value, strlen(value), false, - TestFileSystem::write_mode::manual_truncate, true); - m_api->write_file(real, "\r\n", 2, false, TestFileSystem::write_mode::append); - } - - void touch(const char* path, bool full_write_access) - { - if (debug_pending()) - __debugbreak(); - - const auto& real = real_path_create_if_necessary(path); - - m_api->touch_file(real, full_write_access); - } - - void deletef(const char* path) - { - if (debug_pending()) - __debugbreak(); - - m_api->delete_file(m_api->real_path(path)); - } - - void rename(const char* source, const char* destination, bool replace_existing) - { - if (debug_pending()) - __debugbreak(); - - m_api->copy_file(m_api->real_path(source), m_api->real_path(destination), - replace_existing); - } - - void rename(const char* source, const char* destination, bool replace_existing, - bool allow_copy) - { - if (debug_pending()) - __debugbreak(); - - m_api->rename_file(m_api->real_path(source), m_api->real_path(destination), - replace_existing, allow_copy); - } - - void debug() { m_debug_pending = true; } - - bool debug_pending() - { - if (!m_debug_pending) - return false; - m_debug_pending = false; - if (!IsDebuggerPresent()) - MessageBoxA(NULL, "Connect a debugger and press OK to trigger a breakpoint", - "DEBUG", 0); - return IsDebuggerPresent(); - } - - // Traversal: - - void list_impl(TestFileSystem::path real, bool read_files) - { - std::vector<TestFileSystem::path> recurse; - { - auto files = m_api->list_directory(real); - fprintf(m_output, ">> Listing directory {%s}:\n", - m_api->relative_path(real).string().c_str()); - for (auto f : files) { - if (f.is_dir()) { - fprintf(m_output, "[%s] DIR (attributes 0x%x)\n", - string_cast<std::string>(f.name, CodePage::UTF8).c_str(), - f.attributes); - if (m_recursive && f.name != L"." && f.name != L"..") - recurse.push_back(real / f.name); - } else { - fprintf(m_output, "[%s] FILE (attributes 0x%x, %lld bytes)\n", - string_cast<std::string>(f.name, CodePage::UTF8).c_str(), - f.attributes, f.size); - if (read_files) - m_api->read_file(real / f.name); - } - } - } - for (auto r : recurse) - list_impl(r, read_files); - } - -private: - TestFileSystem::path real_path_create_if_necessary(const char* path) - { - auto real = m_api->real_path(path); - if (m_recursive) - try { - m_api->create_path(real.parent_path()); - } catch (const std::exception& e) { - throw std::runtime_error( - std::format("Failed to create_path [{}] : {}", - m_api->relative_path(real.parent_path()).string(), e.what())); - } - return std::move(real); - } - - std::string clean_cmdline_arg(const char* arg_start, const char* arg_end) - { - if (arg_start == arg_end) - return std::string(); - bool quoted = *arg_start == '\"' && *(arg_end - 1) == '\"'; - const char* last_sep = arg_end; - while (last_sep != arg_start && *last_sep != '\\') - --last_sep; - if (arg_end - arg_start < (quoted ? 5 : 3) || arg_start[0] == '-' || - arg_start[quoted ? 2 : 1] != ':' || last_sep == arg_start) - return std::string(arg_start, arg_end); - std::string res = quoted ? "\"" : ""; - res.append(last_sep + 1, arg_end); - return res; - } - - std::string clean_cmdline_heuristic(const char* cmdline) - { - std::string res; - bool first = true; - while (*cmdline) { - const char* end = strchr(cmdline, ' '); - if (!end) - end = cmdline + strlen(cmdline); - if (first) - first = false; - else - res.push_back(' '); - res += clean_cmdline_arg(cmdline, end); - cmdline = end; - while (*cmdline == ' ') - ++cmdline; - } - return res; - } - - FILE* m_output; - bool m_cleanoutput = false; - bool m_recursive = false; - bool m_debug_pending = false; - - TestFileSystem* m_api; - static TestW32Api w32api; - static TestNtApi ntapi; -}; - -// static -TestW32Api CommandExecuter::w32api(stdout); -TestNtApi CommandExecuter::ntapi(stdout); - -class abort_invalid_argument : std::exception -{}; - -bool verify_args_exist(const char* flag, int params, int index, int count) -{ - if (index + params >= count) { - fprintf(stderr, "ERROR: %s requires %d arguments\n", flag, params); - throw abort_invalid_argument(); - } - return true; -} - -const char* UntouchedCommandLineArguments() -{ - const char* cmd = GetCommandLineA(); - for (; *cmd && *cmd != ' '; ++cmd) { - if (*cmd == '"') { - int escaped = 0; - for (++cmd; *cmd && (*cmd != '"' || escaped % 2 != 0); ++cmd) - escaped = *cmd == '\\' ? escaped + 1 : 0; - } - } - while (*cmd == ' ') - ++cmd; - return cmd; -} - -int main(int argc, char* argv[]) -{ - bool found_commands = false; - CommandExecuter executer; - - TestFileSystem::path exe_path = argv[0]; - std::string exename = exe_path.filename().string(); - std::string cmdline = exename + " " + UntouchedCommandLineArguments(); - fprintf(stdout, "#> process %d started with commandline: %s\n", GetCurrentProcessId(), - cmdline.c_str()); - - for (int ai = 1; ai < argc; ++ai) { - try { - SetLastError(0); - - // options: - if (strcmp(argv[ai], "-out") == 0 && verify_args_exist("-out", 1, ai, argc) || - strcmp(argv[ai], "-out+") == 0 && verify_args_exist("-out+", 1, ai, argc) || - strcmp(argv[ai], "-cout") == 0 && verify_args_exist("-cout", 1, ai, argc) || - strcmp(argv[ai], "-cout+") == 0 && verify_args_exist("-cout+", 1, ai, argc)) { - bool clean = argv[ai][1] == 'c'; - bool append = argv[ai][clean ? 5 : 4] == '+'; - executer.set_output(argv[++ai], clean, append, cmdline.c_str()); - } else if (strcmp(argv[ai], "-r") == 0) - executer.set_recursive(true); - else if (strcmp(argv[ai], "-r-") == 0) - executer.set_recursive(false); - else if (strcmp(argv[ai], "-basedir") == 0 && - verify_args_exist("-basedir", 1, ai, argc)) { - executer.set_basedir(argv[++ai]); - } else if (strcmp(argv[ai], "-w32api") == 0) - executer.set_ntapi(false); - else if (strcmp(argv[ai], "-ntapi") == 0) - executer.set_ntapi(true); - // commands: - else if ((strcmp(argv[ai], "-list") == 0 || - strcmp(argv[ai], "-listcontents") == 0) && - verify_args_exist("-list", 1, ai, argc)) { - bool contents = strcmp(argv[ai], "-listcontents") == 0; - executer.list(argv[++ai], contents); - found_commands = true; - } else if (strcmp(argv[ai], "-read") == 0 && - verify_args_exist("-read", 1, ai, argc)) { - executer.read(argv[++ai]); - found_commands = true; - } else if (strcmp(argv[ai], "-overwrite") == 0 && - verify_args_exist("-overwrite", 2, ai, argc) || - strcmp(argv[ai], "-deleteoverwrite") == 0 && - verify_args_exist("-deleteoverwrite", 2, ai, argc)) { - if (argv[ai][1] == 'd') - executer.deletef(argv[ai + 1]); - executer.overwrite(argv[ai + 1], argv[ai + 2]); - ++ ++ai; - found_commands = true; - } else if (strcmp(argv[ai], "-rewrite") == 0 && - verify_args_exist("-rewrite", 2, ai, argc)) { - executer.rewrite(argv[ai + 1], argv[ai + 2]); - ++ ++ai; - found_commands = true; - } else if (strcmp(argv[ai], "-touch") == 0 && - verify_args_exist("-touch", 1, ai, argc) || - strcmp(argv[ai], "-touchw") == 0 && - verify_args_exist("-touchw", 1, ai, argc)) { - bool write_access = argv[ai][6] == 'w'; - executer.touch(argv[++ai], write_access); - found_commands = true; - } else if (strcmp(argv[ai], "-delete") == 0 && - verify_args_exist("-delete", 1, ai, argc)) { - executer.deletef(argv[++ai]); - found_commands = true; - } else if (strcmp(argv[ai], "-copy") == 0 && - verify_args_exist("-copy", 2, ai, argc) || - strcmp(argv[ai], "-copyover") == 0 && - verify_args_exist("-copyover", 2, ai, argc)) { - bool over = argv[ai][5] == 'o'; - executer.rename(argv[ai + 1], argv[ai + 2], over); - ++ ++ai; - found_commands = true; - } else if (strcmp(argv[ai], "-rename") == 0 && - verify_args_exist("-rename", 2, ai, argc) || - strcmp(argv[ai], "-renameover") == 0 && - verify_args_exist("-renameover", 2, ai, argc) || - strcmp(argv[ai], "-deleterename") == 0 && - verify_args_exist("-deleterename", 2, ai, argc) || - strcmp(argv[ai], "-move") == 0 && - verify_args_exist("-move", 2, ai, argc) || - strcmp(argv[ai], "-moveover") == 0 && - verify_args_exist("-moveover", 2, ai, argc) || - strcmp(argv[ai], "-deletemove") == 0 && - verify_args_exist("-deletemove", 2, ai, argc)) { - bool del = argv[ai][1] == 'd'; - bool move = argv[ai][del ? 7 : 1] == 'm'; - bool over = !del && argv[ai][move ? 5 : 7] == 'o'; - if (del) - executer.deletef(argv[ai + 2]); - executer.rename(argv[ai + 1], argv[ai + 2], over, move); - ++ ++ai; - found_commands = true; - } else if (strcmp(argv[ai], "-debug") == 0) { - executer.debug(); - } else { - if (executer.file_output()) - fprintf(executer.output(), "ERROR: invalid argument {%s}\n", argv[ai]); - fprintf(stderr, "ERROR: invalid argument {%s}\n", argv[ai]); - return 1; - } - } catch (const abort_invalid_argument&) { - return 1; - } -#if 1 // just a convient way to not catch exception when debugging - catch (const std::exception& e) { - if (executer.file_output()) - fprintf(executer.output(), "ERROR: %hs\n", e.what()); - fprintf(stderr, "ERROR: %hs\n", e.what()); - return 1; - } catch (...) { - if (executer.file_output()) - fprintf(executer.output(), "ERROR: unknown exception"); - fprintf(stderr, "ERROR: unknown exception\n"); - return 1; - } -#endif - } - - if (!found_commands) { - print_usage(exename.c_str()); - return 2; - } - - if (executer.file_output()) - if (executer.cleanoutput()) - fprintf(executer.output(), "#< %s ended properly.\n", exename.c_str()); - else - fprintf(executer.output(), "#< %s ended properly in process %d.\n", - exename.c_str(), GetCurrentProcessId()); - fprintf(stdout, "#< %s ended properly in process %d.\n", exename.c_str(), - GetCurrentProcessId()); - - return 0; -} diff --git a/libs/usvfs/test/usvfs_test_runner/test_file_operations/test_filesystem.cpp b/libs/usvfs/test/usvfs_test_runner/test_file_operations/test_filesystem.cpp deleted file mode 100644 index dcfd5a1..0000000 --- a/libs/usvfs/test/usvfs_test_runner/test_file_operations/test_filesystem.cpp +++ /dev/null @@ -1,159 +0,0 @@ - -#include "test_filesystem.h" -#include <test_helpers.h> -#define WIN32_LEAN_AND_MEAN -#include <Windows.h> - -using test::throw_testWinFuncFailed; - -bool TestFileSystem::FileInformation::is_dir() const -{ - return (attributes & FILE_ATTRIBUTE_DIRECTORY) != 0; -} - -bool TestFileSystem::FileInformation::is_file() const -{ - return (attributes & FILE_ATTRIBUTE_DIRECTORY) == 0; -} - -TestFileSystem::TestFileSystem(FILE* output) : m_output(output) {} - -TestFileSystem::path TestFileSystem::current_directory() -{ - DWORD res = GetCurrentDirectoryW(0, NULL); - if (!res) - throw_testWinFuncFailed("GetCurrentDirectory", res); - std::wstring buf(res + 1, '\0'); - res = GetCurrentDirectoryW(buf.length(), &buf[0]); - if (!res || res >= buf.length()) - throw_testWinFuncFailed("GetCurrentDirectory", res); - buf.resize(res); - return buf; -} - -TestFileSystem::path TestFileSystem::relative_path(path full_path) -{ - return test::path_as_relative(m_basepath, full_path); -} - -// static -const char* TestFileSystem::write_operation_name(write_mode mode) -{ - switch (mode) { - case write_mode::manual_truncate: - return "Writing file (by open & truncate)"; - case write_mode::truncate: - return "Truncating file"; - case write_mode::create: - return "Creating file"; - case write_mode::overwrite: - return "Overwriting file"; - case write_mode::opencreate: - return "Opening/Creating file"; - case write_mode::append: - return "Appending file"; - } - return "Unknown write operation?!"; -} - -// static -const char* TestFileSystem::rename_operation_name(bool replace_existing, - bool allow_copy) -{ - if (allow_copy) - return replace_existing ? "Moving file over" : "Moving file"; - else - return replace_existing ? "Renaming file over" : "Renaming file"; -} - -void TestFileSystem::print_operation(const char* operation, const path& target) -{ - if (m_output) - fprintf(m_output, "# (%s) %s {%s}\n", id(), operation, - relative_path(target).string().c_str()); -} - -void TestFileSystem::print_operation(const char* operation, const path& source, - const path& target) -{ - if (m_output) - fprintf(m_output, "# (%s) %s {%s} {%s}\n", id(), operation, - relative_path(source).string().c_str(), - relative_path(target).string().c_str()); -} - -static inline void print_op_with_result(FILE* output, const char* prefix, - const char* operation, const uint32_t* result, - DWORD* last_error, const char* opt_arg) -{ - if (output) { - fprintf(output, "%s%s", prefix, operation); - if (opt_arg) - fprintf(output, " %s", opt_arg); - if (result) - fprintf(output, " returned %u (0x%x)", *result, *result); - if (last_error) - fprintf(output, " last error %u (0x%x)", *last_error, *last_error); - fprintf(output, "\n"); - } -} - -void TestFileSystem::print_result(const char* operation, uint32_t result, - bool with_last_error, const char* opt_arg, - bool hide_result) -{ - if (m_output) { - DWORD last_error = GetLastError(); - std::string prefix = "# ("; - prefix += id(); - prefix += ") "; - print_op_with_result(m_output, prefix.c_str(), operation, - hide_result ? nullptr : &result, - with_last_error ? &last_error : nullptr, opt_arg); - SetLastError(last_error); - } -} - -void TestFileSystem::print_error(const char* operation, uint32_t result, - bool with_last_error, const char* opt_arg) -{ - DWORD last_error = with_last_error ? GetLastError() : 0; - print_op_with_result(stderr, "ERROR: ", operation, &result, - with_last_error ? &last_error : nullptr, opt_arg); - if (m_output && m_output != stdout) - print_op_with_result(m_output, "ERROR: ", operation, &result, - with_last_error ? &last_error : nullptr, opt_arg); -} - -void TestFileSystem::print_write_success(const void* data, std::size_t size, - std::size_t written) -{ - if (m_output) { - fprintf(m_output, "# Successfully written %u bytes ", - static_cast<unsigned>(written)); - // heuristics to print nicer one liners: - if (size == 1 && reinterpret_cast<const char*>(data)[0] == '\n' || - size == 2 && reinterpret_cast<const char*>(data)[0] == '\r' && - reinterpret_cast<const char*>(data)[1] == '\n') - fprintf(m_output, "<newline>"); - else { - fprintf(m_output, "{"); - if (size && reinterpret_cast<const char*>(data)[size - 1] == '\n') - --size; - if (data) - fwrite(data, 1, size, m_output); - else if (size) - fwrite("NULL?!", 1, 6, m_output); - fprintf(m_output, "}"); - } - fprintf(output(), "\n"); - } -} - -uint32_t TestFileSystem::clean_attributes(uint32_t attr) -{ - if (m_cleanoutput) - return attr & ~(FILE_ATTRIBUTE_NOT_CONTENT_INDEXED); - else - return attr; -} diff --git a/libs/usvfs/test/usvfs_test_runner/test_file_operations/test_filesystem.h b/libs/usvfs/test/usvfs_test_runner/test_file_operations/test_filesystem.h deleted file mode 100644 index 3a5f53b..0000000 --- a/libs/usvfs/test/usvfs_test_runner/test_file_operations/test_filesystem.h +++ /dev/null @@ -1,104 +0,0 @@ -#pragma once - -#include <cstdio> -#include <filesystem> -#include <string> -#include <vector> - -class TestFileSystem -{ -public: - static constexpr auto FILE_CONTENTS_PRINT_PREFIX = "== "; - - typedef std::filesystem::path path; - typedef std::FILE FILE; - - static path current_directory(); - - TestFileSystem(FILE* output); - - void set_output(FILE* output, bool clean) - { - m_output = output; - m_cleanoutput = clean; - } - - // base path used to trim outputs (which is important so we can compare tests ran at - // different base paths) - void set_basepath(const char* path) { m_basepath = real_path(path); } - - // returns the path relative to the base path - path relative_path(path full_path); - - virtual const char* id() = 0; - - virtual path real_path(const char* abs_or_rel_path) = 0; - - struct FileInformation - { - std::wstring name; - uint32_t attributes; - uint64_t size; - - FileInformation(const std::wstring& iname, uint32_t iattributes, uint64_t isize) - : name(iname), attributes(iattributes), size(isize) - {} - - bool is_dir() const; - bool is_file() const; - }; - typedef std::vector<FileInformation> FileInfoList; - - virtual FileInfoList list_directory(const path& directory_path) = 0; - - virtual void create_path(const path& directory_path) = 0; - - virtual void read_file(const path& file_path) = 0; - - enum class write_mode - { - manual_truncate, - truncate, - create, - overwrite, - opencreate, - append - }; - virtual void write_file(const path& file_path, const void* data, std::size_t size, - bool add_new_line, write_mode mode, - bool rw_access = false) = 0; - - virtual void touch_file(const path& file_path, bool full_write_access = false) = 0; - - virtual void delete_file(const path& file_path) = 0; - - virtual void copy_file(const path& source_path, const path& destination_path, - bool replace_existing) = 0; - - virtual void rename_file(const path& source_path, const path& destination_path, - bool replace_existing, bool allow_copy) = 0; - -protected: - FILE* output() { return m_output; } - bool cleanoutput() const { return m_cleanoutput; } - static const char* write_operation_name(write_mode mode); - static const char* rename_operation_name(bool replace_existing, bool allow_copy); - -public: // mainly for derived class (but also used by helper classes like SafeHandle so - // public) - void print_operation(const char* operation, const path& target); - void print_operation(const char* operation, const path& source, const path& target); - void print_result(const char* operation, uint32_t result, - bool with_last_error = false, const char* opt_arg = nullptr, - bool hide_result = false); - void print_error(const char* operation, uint32_t result, bool with_last_error = false, - const char* opt_arg = nullptr); - void print_write_success(const void* data, std::size_t size, std::size_t written); - - uint32_t clean_attributes(uint32_t attr); - -private: - FILE* m_output; - bool m_cleanoutput = false; - path m_basepath; -}; diff --git a/libs/usvfs/test/usvfs_test_runner/test_file_operations/test_ntapi.cpp b/libs/usvfs/test/usvfs_test_runner/test_file_operations/test_ntapi.cpp deleted file mode 100644 index 34966b5..0000000 --- a/libs/usvfs/test/usvfs_test_runner/test_file_operations/test_ntapi.cpp +++ /dev/null @@ -1,488 +0,0 @@ - -#include "test_ntapi.h" -#include <cstdio> -#include <cstring> -#include <test_helpers.h> -#include <vector> - -#define WIN32_LEAN_AND_MEAN -#include <Windows.h> -#include <Winternl.h> -#include <stdio.h> - -#include "test_ntdll_declarations.h" - -class TestNtApi::SafeHandle -{ -public: - SafeHandle(TestFileSystem* tfs, HANDLE handle = NULL) : m_handle(handle), m_tfs(tfs) - {} - SafeHandle(const SafeHandle&) = delete; - SafeHandle(SafeHandle&& other) : m_handle(other.m_handle), m_tfs(other.m_tfs) - { - other.m_handle = nullptr; - } - - operator HANDLE() { return m_handle; } - operator PHANDLE() { return &m_handle; } - - bool valid() const { return m_handle != NULL; } - - ~SafeHandle() - { - if (m_handle) { - NTSTATUS status = NtClose(m_handle); - if (m_tfs) - m_tfs->print_result("NtClose", status); - if (!NT_SUCCESS(status)) - if (m_tfs) - m_tfs->print_error("NtClose", status); - else - std::fprintf(stderr, "NtClose failed : 0x%lx", status); - m_handle = NULL; - } - } - -private: - HANDLE m_handle; - TestFileSystem* m_tfs; -}; - -const char* TestNtApi::id() -{ - return "Nt"; -} - -TestNtApi::path TestNtApi::real_path(const char* abs_or_rel_path) -{ - if (!abs_or_rel_path || !abs_or_rel_path[0]) - return path(); - - static constexpr char nt_path_prefix[] = "\\??\\"; - static constexpr wchar_t nt_path_prefix_w[] = L"\\??\\"; - - bool path_dos = strncmp(abs_or_rel_path, nt_path_prefix, strlen(nt_path_prefix)) == 0; - bool path_has_drive = abs_or_rel_path[1] == ':'; - bool path_unc = abs_or_rel_path[0] == '\\' && abs_or_rel_path[1] == '\\'; - bool path_absolute = path_has_drive || abs_or_rel_path[0] == '\\'; - - path result; - if (!path_dos) { - if (!path_unc) - result.assign(nt_path_prefix_w); - if (!path_absolute) - result /= current_directory(); - else if (!path_has_drive && !path_unc) - // if "absolute" path but without a drive letter (i.e. \windows) - // the take the drive from the current directory: (i.e. "C:") - result /= current_directory().root_name(); - } - - int result_size = 0; - for (auto r : result) - ++result_size; - - // now append abs_or_rel_path, handling ".." and "." properly: - path arp{abs_or_rel_path}; - int base_size = path_unc ? 3 : 4; - for (auto p : arp) { - if (p == "..") { - if (result_size > base_size) { // refuse to remove top level element (i.e. - // \??\C:\ which is 4 elements) - result.remove_filename(); - --result_size; - } - } else if (!p.empty() && p != ".") { - result /= p; - ++result_size; - } - } - - return result; -} - -TestNtApi::SafeHandle TestNtApi::open_directory(const path& directory_path, bool create, - bool allow_non_existence, long* pstatus) -{ - print_operation(create ? "Creating directory" : "Openning directory", directory_path); - - UNICODE_STRING unicode_path; - RtlInitUnicodeString(&unicode_path, directory_path.c_str()); - - OBJECT_ATTRIBUTES attributes; - InitializeObjectAttributes(&attributes, &unicode_path, OBJ_CASE_INSENSITIVE, NULL, - NULL); - - SafeHandle dir(this); - IO_STATUS_BLOCK iosb; - NTSTATUS status = NtCreateFile( - dir, FILE_LIST_DIRECTORY | FILE_TRAVERSE | SYNCHRONIZE, &attributes, &iosb, NULL, - FILE_ATTRIBUTE_DIRECTORY, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, - create ? FILE_OPEN_IF : FILE_OPEN, - FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT, NULL, 0); - - print_result("NtCreateFile", status); - - if (pstatus) - *pstatus = status; - if ((status == STATUS_OBJECT_NAME_NOT_FOUND || - status == STATUS_OBJECT_PATH_NOT_FOUND) && - allow_non_existence) - return NULL; - if (!NT_SUCCESS(status)) - throw test::FuncFailed("NtCreateFile", status); - if (!NT_SUCCESS(iosb.Status)) - throw test::FuncFailed("NtCreateFile", "bad iosb.Status", iosb.Status); - - return dir; -} - -TestFileSystem::FileInfoList TestNtApi::list_directory(const path& directory_path) -{ - SafeHandle dir = open_directory(directory_path, false); - - print_operation("Querying directory", directory_path); - - FileInfoList files; - while (true) { - char buf[4096]{0}; - IO_STATUS_BLOCK iosb; - - NTSTATUS status = - NtQueryDirectoryFile(dir, NULL, NULL, NULL, &iosb, buf, sizeof(buf), - MyFileBothDirectoryInformation, FALSE, NULL, FALSE); - print_result("NtQueryDirectoryFile", status); - - if (status == STATUS_NO_MORE_FILES) - break; - if (!NT_SUCCESS(status)) - throw test::FuncFailed("NtQueryDirectoryFile", status); - if (!NT_SUCCESS(iosb.Status)) - throw test::FuncFailed("NtQueryDirectoryFile", "bad iosb.Status", iosb.Status); - if (iosb.Information == 0) // This shouldn't happend unless the filename (not full - // path) is larger then sizeof(buf) - throw test::FuncFailed("NtQueryDirectoryFile", "buffer too small", - iosb.Information); - - PFILE_BOTH_DIR_INFORMATION info = reinterpret_cast<PFILE_BOTH_DIR_INFORMATION>(buf); - while (true) { - files.push_back(FileInformation( - std::wstring(info->FileName, - info->FileNameLength / sizeof(info->FileName[0])), - clean_attributes(info->FileAttributes), info->EndOfFile.QuadPart)); - if (info->NextEntryOffset) - info = reinterpret_cast<PFILE_BOTH_DIR_INFORMATION>( - reinterpret_cast<char*>(info) + info->NextEntryOffset); - else - break; - } - } - - return files; -} - -void TestNtApi::create_path(const path& directory_path) -{ - // sanity and guaranteed recursion end: - if (!directory_path.has_relative_path()) - throw std::runtime_error("Refusing to create non-existing top level path"); - - // if directory already exists all is good - NTSTATUS status; - if (open_directory(directory_path, false, true, &status).valid()) - return; - - if (status != STATUS_OBJECT_NAME_NOT_FOUND) // STATUS_OBJECT_NAME_NOT_FOUND means - // parent directory already exists - create_path(directory_path - .parent_path()); // otherwise create parent directory (recursively) - - open_directory(directory_path, true); -} - -void TestNtApi::read_file(const path& file_path) -{ - print_operation("Reading file", file_path); - - UNICODE_STRING unicode_path; - RtlInitUnicodeString(&unicode_path, file_path.c_str()); - - OBJECT_ATTRIBUTES attributes; - InitializeObjectAttributes(&attributes, &unicode_path, OBJ_CASE_INSENSITIVE, NULL, - NULL); - - SafeHandle file(this); - IO_STATUS_BLOCK iosb; - NTSTATUS status = NtOpenFile(file, GENERIC_READ | SYNCHRONIZE, &attributes, &iosb, - FILE_SHARE_READ, FILE_SYNCHRONOUS_IO_NONALERT); - print_result("NtOpenFile", status); - - if (!NT_SUCCESS(status)) - throw test::FuncFailed("NtOpenFile", status); - if (!NT_SUCCESS(iosb.Status)) - throw test::FuncFailed("NtOpenFile", "bad iosb.Status", iosb.Status); - - uint32_t total = 0; - bool ends_with_newline = true; - bool pending_prefix = true; - while (true) { - char buf[4096]; - - memset(&iosb, 0, sizeof(iosb)); - status = NtReadFile(file, NULL, NULL, NULL, &iosb, buf, sizeof(buf), NULL, NULL); - print_result("NtReadFile", status); - if (status == STATUS_END_OF_FILE) - break; - if (!NT_SUCCESS(status)) - throw test::FuncFailed("NtReadFile", status); - - total += iosb.Information; - char* begin = buf; - char* end = begin + iosb.Information; - while (begin != end) { - if (pending_prefix) { - if (output()) - fwrite(FILE_CONTENTS_PRINT_PREFIX, 1, strlen(FILE_CONTENTS_PRINT_PREFIX), - output()); - pending_prefix = false; - } - bool skip_newline = false; - char* print_end = reinterpret_cast<char*>(std::memchr(begin, '\n', end - begin)); - if (print_end) { - pending_prefix = true; - if (print_end > begin && *(print_end - 1) == '\r') { - // convert \r\n => \n: - *(print_end - 1) = '\n'; - skip_newline = true; - } else // only a '\n' so just print it - ++print_end; - } else { - print_end = end; - if (print_end > begin && *(print_end - 1) == '\r') { - // buffer ends with \r so skip it under the hope it will be followed with a \n - --print_end; - skip_newline = true; - } - } - if (output()) - fwrite(begin, 1, print_end - begin, output()); - ends_with_newline = print_end > begin && *(print_end - 1) == '\n'; - begin = print_end; - if (skip_newline) - ++begin; - } - if (output() && !ends_with_newline) { - fwrite("\n", 1, 1, output()); - ends_with_newline = true; - } - } - if (output()) { - fprintf(output(), "# Successfully read %u bytes.\n", total); - } -} - -void TestNtApi::write_file(const path& file_path, const void* data, std::size_t size, - bool add_new_line, write_mode mode, bool rw_access) -{ - print_operation(write_operation_name(mode), file_path); - - UNICODE_STRING unicode_path; - RtlInitUnicodeString(&unicode_path, file_path.c_str()); - - OBJECT_ATTRIBUTES attributes; - InitializeObjectAttributes(&attributes, &unicode_path, OBJ_CASE_INSENSITIVE, NULL, - NULL); - - ACCESS_MASK access = GENERIC_WRITE | SYNCHRONIZE; - ULONG disposition = FILE_OPEN; - switch (mode) { - case write_mode::truncate: - disposition = FILE_OVERWRITE; - break; - case write_mode::create: - disposition = FILE_CREATE; - break; - case write_mode::overwrite: - disposition = FILE_SUPERSEDE; - break; - case write_mode::opencreate: - disposition = FILE_OPEN_IF; - break; - case write_mode::append: - disposition = FILE_OPEN_IF; - access = FILE_APPEND_DATA | SYNCHRONIZE; - break; - } - if (rw_access) - access |= GENERIC_READ; - - SafeHandle file(this); - IO_STATUS_BLOCK iosb; - NTSTATUS status = - NtCreateFile(file, access, &attributes, &iosb, NULL, FILE_ATTRIBUTE_NORMAL, 0, - disposition, FILE_SYNCHRONOUS_IO_NONALERT, NULL, 0); - print_result("NtCreateFile", status); - - if (!NT_SUCCESS(status)) - throw test::FuncFailed("NtCreateFile", status); - if (!NT_SUCCESS(iosb.Status)) - throw test::FuncFailed("NtCreateFile", "bad iosb.Status", iosb.Status); - - if (mode == write_mode::manual_truncate) { - FILE_END_OF_FILE_INFORMATION eofinfo{0}; - status = NtSetInformationFile(file, &iosb, &eofinfo, sizeof(eofinfo), - MyFileEndOfFileInformation); - print_result("NtSetInformationFile", status, false, "EOF"); - - if (!NT_SUCCESS(status)) - throw test::FuncFailed("NtSetInformationFile", status); - if (!NT_SUCCESS(iosb.Status)) - throw test::FuncFailed("NtSetInformationFile", "bad iosb.Status", iosb.Status); - } - - // finally write the data: - size_t total = 0; - - if (data) { - status = NtWriteFile(file, NULL, NULL, NULL, &iosb, const_cast<void*>(data), - static_cast<ULONG>(size), NULL, NULL); - print_result("NtWriteFile", status); - if (!NT_SUCCESS(status)) - throw test::FuncFailed("NtWriteFile", status); - if (!NT_SUCCESS(iosb.Status)) - throw test::FuncFailed("NtWriteFile", "bad iosb.Status", iosb.Status); - total += iosb.Information; - - if (add_new_line) { - char buffer[] = "\r\n"; - status = NtWriteFile(file, NULL, NULL, NULL, &iosb, buffer, 2, NULL, NULL); - print_result("NtWriteFile", status); - if (!NT_SUCCESS(status)) - throw test::FuncFailed("NtWriteFile", status); - if (!NT_SUCCESS(iosb.Status)) - throw test::FuncFailed("NtWriteFile", "bad iosb.Status", iosb.Status); - total += iosb.Information; - } - } - - print_write_success(data, size, total); -} - -void TestNtApi::touch_file(const path& file_path, bool full_write_access) -{ - print_operation("Touching file", file_path); - - SYSTEMTIME st; - GetSystemTime(&st); - FILETIME ft; - if (!SystemTimeToFileTime(&st, &ft)) - test::throw_testWinFuncFailed("SystemTimeToFileTime"); - - UNICODE_STRING unicode_path; - RtlInitUnicodeString(&unicode_path, file_path.c_str()); - - OBJECT_ATTRIBUTES attributes; - InitializeObjectAttributes(&attributes, &unicode_path, OBJ_CASE_INSENSITIVE, NULL, - NULL); - - SafeHandle file(this); - IO_STATUS_BLOCK iosb; - auto share_all = FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE; - auto access = - (full_write_access ? GENERIC_WRITE : FILE_WRITE_ATTRIBUTES) | SYNCHRONIZE; - NTSTATUS status = - NtCreateFile(file, access, &attributes, &iosb, NULL, FILE_ATTRIBUTE_NORMAL, - share_all, FILE_OPEN_IF, FILE_SYNCHRONOUS_IO_NONALERT, NULL, 0); - print_result("NtCreateFile", status); - - if (!NT_SUCCESS(status)) - throw test::FuncFailed("NtCreateFile", status); - if (!NT_SUCCESS(iosb.Status)) - throw test::FuncFailed("NtCreateFile", "bad iosb.Status", iosb.Status); - - FILE_BASIC_INFORMATION basicinfo{0}; - basicinfo.LastWriteTime.LowPart = ft.dwLowDateTime; - basicinfo.LastWriteTime.HighPart = ft.dwHighDateTime; - status = NtSetInformationFile(file, &iosb, &basicinfo, sizeof(basicinfo), - MyFileBasicInformation); - print_result("NtSetInformationFile", status, false, "Basic"); - - if (!NT_SUCCESS(status)) - throw test::FuncFailed("NtSetInformationFile", status); - if (!NT_SUCCESS(iosb.Status)) - throw test::FuncFailed("NtSetInformationFile", "bad iosb.Status", iosb.Status); -} - -void TestNtApi::delete_file(const path& file_path) -{ - print_operation("Deleting file", file_path); - - UNICODE_STRING unicode_path; - RtlInitUnicodeString(&unicode_path, file_path.c_str()); - - OBJECT_ATTRIBUTES attributes; - InitializeObjectAttributes(&attributes, &unicode_path, OBJ_CASE_INSENSITIVE, NULL, - NULL); - - NTSTATUS status = NtDeleteFile(&attributes); - print_result("NtCreateFile", status); - - if (!NT_SUCCESS(status)) - throw test::FuncFailed("NtDeleteFile", status); -} - -void TestNtApi::copy_file(const path& source_path, const path& destination_path, - bool replace_existing) -{ - throw test::FuncFailed("copy_file", "ntapi does not support file copy"); -} - -void TestNtApi::rename_file(const path& source_path, const path& destination_path, - bool replace_existing, bool allow_copy) -{ - if (allow_copy) - throw test::FuncFailed("rename_file", "ntapi does not support file move"); - - print_operation(rename_operation_name(replace_existing, allow_copy), source_path, - destination_path); - - UNICODE_STRING unicode_path; - RtlInitUnicodeString(&unicode_path, source_path.c_str()); - - OBJECT_ATTRIBUTES attributes; - InitializeObjectAttributes(&attributes, &unicode_path, OBJ_CASE_INSENSITIVE, NULL, - NULL); - - SafeHandle file(this); - IO_STATUS_BLOCK iosb; - NTSTATUS status = NtCreateFile(file, FILE_READ_ATTRIBUTES | DELETE | SYNCHRONIZE, - &attributes, &iosb, NULL, FILE_ATTRIBUTE_NORMAL, - FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, - FILE_OPEN, FILE_SYNCHRONOUS_IO_NONALERT, NULL, 0); - print_result("NtCreateFile", status); - - if (!NT_SUCCESS(status)) - throw test::FuncFailed("NtCreateFile", status); - if (!NT_SUCCESS(iosb.Status)) - throw test::FuncFailed("NtCreateFile", "bad iosb.Status", iosb.Status); - - bool dest_full_path = source_path.parent_path() != destination_path.parent_path(); - std::wstring dest = dest_full_path ? destination_path : destination_path.filename(); - std::vector<char> buf(sizeof(FILE_RENAME_INFORMATION) + - sizeof(wchar_t) * dest.length()); - FILE_RENAME_INFORMATION* rename = - reinterpret_cast<FILE_RENAME_INFORMATION*>(buf.data()); - rename->ReplaceIfExists = replace_existing ? TRUE : FALSE; - rename->FileNameLength = sizeof(wchar_t) * dest.length(); - memcpy(&rename->FileName[0], dest.data(), sizeof(wchar_t) * dest.length()); - - status = - NtSetInformationFile(file, &iosb, rename, buf.size(), MyFileRenameInformation); - print_result("NtSetInformationFile", status, false, - dest_full_path ? "rename full path" : "rename filename"); - - if (!NT_SUCCESS(status)) - throw test::FuncFailed("NtSetInformationFile", status); - if (!NT_SUCCESS(iosb.Status)) - throw test::FuncFailed("NtSetInformationFile", "bad iosb.Status", iosb.Status); -} diff --git a/libs/usvfs/test/usvfs_test_runner/test_file_operations/test_ntapi.h b/libs/usvfs/test/usvfs_test_runner/test_file_operations/test_ntapi.h deleted file mode 100644 index fc6434e..0000000 --- a/libs/usvfs/test/usvfs_test_runner/test_file_operations/test_ntapi.h +++ /dev/null @@ -1,38 +0,0 @@ -#pragma once - -#include "test_filesystem.h" - -class TestNtApi : public TestFileSystem -{ -public: - TestNtApi(FILE* output) : TestFileSystem(output) {} - - path real_path(const char* abs_or_rel_path) override; - - FileInfoList list_directory(const path& directory_path) override; - - void create_path(const path& directory_path) override; - - void read_file(const path& file_path) override; - - void write_file(const path& file_path, const void* data, std::size_t size, - bool add_new_line, write_mode mode, bool rw_access = false) override; - - void touch_file(const path& file_path, bool full_write_access = false) override; - - void delete_file(const path& file_path) override; - - void copy_file(const path& source_path, const path& destination_path, - bool replace_existing) override; - - void rename_file(const path& source_path, const path& destination_path, - bool replace_existing, bool allow_copy) override; - - const char* id() override; - -private: - class SafeHandle; - - SafeHandle open_directory(const path& directory_path, bool create, - bool allow_non_existence = false, long* pstatus = nullptr); -}; diff --git a/libs/usvfs/test/usvfs_test_runner/test_file_operations/test_ntdll_declarations.h b/libs/usvfs/test/usvfs_test_runner/test_file_operations/test_ntdll_declarations.h deleted file mode 100644 index e3799ac..0000000 --- a/libs/usvfs/test/usvfs_test_runner/test_file_operations/test_ntdll_declarations.h +++ /dev/null @@ -1,157 +0,0 @@ -#pragma once - -#define STATUS_NO_MORE_FILES 0x80000006 -#define STATUS_END_OF_FILE 0xC0000011 -#define STATUS_OBJECT_NAME_NOT_FOUND 0xC0000034 -#define STATUS_OBJECT_PATH_NOT_FOUND 0xC000003A - -#define FILE_WRITE_TO_END_OF_FILE 0xffffffff -#define FILE_USE_FILE_POINTER_POSITION 0xfffffffe - -#define InitializeObjectAttributes(p, n, a, r, s) \ - { \ - (p)->Length = sizeof(OBJECT_ATTRIBUTES); \ - (p)->RootDirectory = r; \ - (p)->Attributes = a; \ - (p)->ObjectName = n; \ - (p)->SecurityDescriptor = s; \ - (p)->SecurityQualityOfService = NULL; \ - } - -// winternl.h of course defines a joke FILE_INFORMATION_CLASS (why?!) -// so added MY_ to avoid name collision but this is FILE_INFORMATION_CLASS - -typedef enum _MY_FILE_INFORMATION_CLASS -{ - MyFileDirectoryInformation = 1, - MyFileFullDirectoryInformation, - MyFileBothDirectoryInformation, - MyFileBasicInformation, - MyFileStandardInformation, - MyFileInternalInformation, - MyFileEaInformation, - MyFileAccessInformation, - MyFileNameInformation, - MyFileRenameInformation, - MyFileLinkInformation, - MyFileNamesInformation, - MyFileDispositionInformation, - MyFilePositionInformation, - MyFileFullEaInformation, - MyFileModeInformation, - MyFileAlignmentInformation, - MyFileAllInformation, - MyFileAllocationInformation, - MyFileEndOfFileInformation, - MyFileAlternateNameInformation, - MyFileStreamInformation, - MyFilePipeInformation, - MyFilePipeLocalInformation, - MyFilePipeRemoteInformation, - MyFileMailslotQueryInformation, - MyFileMailslotSetInformation, - MyFileCompressionInformation, - MyFileObjectIdInformation, - MyFileCompletionInformation, - MyFileMoveClusterInformation, - MyFileQuotaInformation, - MyFileReparsePointInformation, - MyFileNetworkOpenInformation, - MyFileAttributeTagInformation, - MyFileTrackingInformation, - MyFileIdBothDirectoryInformation, - MyFileIdFullDirectoryInformation, - MyFileValidDataLengthInformation, - MyFileShortNameInformation, - MyFileIoCompletionNotificationInformation, - MyFileIoStatusBlockRangeInformation, - MyFileIoPriorityHintInformation, - MyFileSfioReserveInformation, - MyFileSfioVolumeInformation, - MyFileHardLinkInformation, - MyFileProcessIdsUsingFileInformation, - MyFileNormalizedNameInformation, - MyFileNetworkPhysicalNameInformation, - MyFileIdGlobalTxDirectoryInformation, - MyFileIsRemoteDeviceInformation, - MyFileUnusedInformation, - MyFileNumaNodeInformation, - MyFileStandardLinkInformation, - MyFileRemoteProtocolInformation, - MyFileRenameInformationBypassAccessCheck, - MyFileLinkInformationBypassAccessCheck, - MyFileVolumeNameInformation, - MyFileIdInformation, - MyFileIdExtdDirectoryInformation, - MyFileReplaceCompletionInformation, - MyFileHardLinkFullIdInformation, - MyFileIdExtdBothDirectoryInformation, - MyFileDispositionInformationEx, - MyFileRenameInformationEx, - MyFileRenameInformationExBypassAccessCheck, - MyFileMaximumInformation -} MY_FILE_INFORMATION_CLASS, - *PMY_FILE_INFORMATION_CLASS; - -typedef struct _FILE_BOTH_DIR_INFORMATION -{ - ULONG NextEntryOffset; - ULONG FileIndex; - LARGE_INTEGER CreationTime; - LARGE_INTEGER LastAccessTime; - LARGE_INTEGER LastWriteTime; - LARGE_INTEGER ChangeTime; - LARGE_INTEGER EndOfFile; - LARGE_INTEGER AllocationSize; - ULONG FileAttributes; - ULONG FileNameLength; - ULONG EaSize; - CCHAR ShortNameLength; - WCHAR ShortName[12]; - WCHAR FileName[1]; -} FILE_BOTH_DIR_INFORMATION, *PFILE_BOTH_DIR_INFORMATION; - -typedef struct _FILE_BASIC_INFORMATION -{ - LARGE_INTEGER CreationTime; - LARGE_INTEGER LastAccessTime; - LARGE_INTEGER LastWriteTime; - LARGE_INTEGER ChangeTime; - ULONG FileAttributes; -} FILE_BASIC_INFORMATION, *PFILE_BASIC_INFORMATION; - -typedef struct _FILE_END_OF_FILE_INFORMATION -{ - LARGE_INTEGER EndOfFile; -} FILE_END_OF_FILE_INFORMATION, *PFILE_END_OF_FILE_INFORMATION; - -typedef struct _FILE_RENAME_INFORMATION -{ - BOOLEAN ReplaceIfExists; - HANDLE RootDirectory; - ULONG FileNameLength; - WCHAR FileName[1]; -} FILE_RENAME_INFORMATION, *PFILE_RENAME_INFORMATION; - -extern "C" __kernel_entry NTSTATUS NTAPI NtQueryDirectoryFile( - IN HANDLE FileHandle, IN HANDLE Event, IN PIO_APC_ROUTINE ApcRoutine, - IN PVOID ApcContext, OUT PIO_STATUS_BLOCK IoStatusBlock, OUT PVOID FileInformation, - IN ULONG Length, IN MY_FILE_INFORMATION_CLASS FileInformationClass, - IN BOOLEAN ReturnSingleEntry, IN PUNICODE_STRING FileName, IN BOOLEAN RestartScan); - -extern "C" __kernel_entry NTSTATUS NTAPI -NtReadFile(IN HANDLE FileHandle, IN HANDLE Event, IN PIO_APC_ROUTINE ApcRoutine, - IN PVOID ApcContext, OUT PIO_STATUS_BLOCK IoStatusBlock, OUT PVOID Buffer, - IN ULONG Length, IN PLARGE_INTEGER ByteOffset, IN PULONG Key); - -extern "C" __kernel_entry NTSTATUS NTAPI -NtWriteFile(IN HANDLE FileHandle, IN HANDLE Event, IN PIO_APC_ROUTINE ApcRoutine, - IN PVOID ApcContext, OUT PIO_STATUS_BLOCK IoStatusBlock, IN PVOID Buffer, - IN ULONG Length, IN PLARGE_INTEGER ByteOffset, IN PULONG Key); - -extern "C" __kernel_entry NTSTATUS NTAPI NtSetInformationFile( - IN HANDLE FileHandle, OUT PIO_STATUS_BLOCK IoStatusBlock, IN PVOID FileInformation, - IN ULONG Length, IN MY_FILE_INFORMATION_CLASS FileInformationClass); - -extern "C" __kernel_entry NTSTATUS NTAPI -NtDeleteFile(IN POBJECT_ATTRIBUTES ObjectAttributes); diff --git a/libs/usvfs/test/usvfs_test_runner/test_file_operations/test_w32api.cpp b/libs/usvfs/test/usvfs_test_runner/test_file_operations/test_w32api.cpp deleted file mode 100644 index 372a6f3..0000000 --- a/libs/usvfs/test/usvfs_test_runner/test_file_operations/test_w32api.cpp +++ /dev/null @@ -1,370 +0,0 @@ - -#include "test_w32api.h" -#include <cstdio> -#include <cstring> -#include <test_helpers.h> - -#define WIN32_LEAN_AND_MEAN -#include <Windows.h> - -using test::throw_testWinFuncFailed; - -class TestW32Api::SafeHandle -{ -public: - SafeHandle(TestFileSystem* tfs, HANDLE handle = NULL) : m_handle(handle), m_tfs(tfs) - {} - SafeHandle(const SafeHandle&) = delete; - SafeHandle(SafeHandle&& other) : m_handle(other.m_handle), m_tfs(other.m_tfs) - { - other.m_handle = nullptr; - } - - operator HANDLE() { return m_handle; } - operator PHANDLE() { return &m_handle; } - uint32_t result_for_print() - { - return static_cast<uint32_t>(reinterpret_cast<uintptr_t>(m_handle)); - } - - bool valid() const { return m_handle != INVALID_HANDLE_VALUE; } - - ~SafeHandle() - { - if (m_handle != INVALID_HANDLE_VALUE) { - BOOL res = CloseHandle(m_handle); - if (m_tfs) - m_tfs->print_result("CloseHandle", res, true); - if (!res) - if (m_tfs) - m_tfs->print_error("CloseHandle", res, true); - else - std::fprintf(stderr, "CloseHandle failed : %d", GetLastError()); - m_handle = NULL; - } - } - -private: - HANDLE m_handle; - TestFileSystem* m_tfs; -}; - -class TestW32Api::SafeFindHandle -{ -public: - SafeFindHandle(TestFileSystem* tfs, HANDLE handle = NULL) - : m_handle(handle), m_tfs(tfs) - {} - SafeFindHandle(const SafeFindHandle&) = delete; - SafeFindHandle(SafeFindHandle&& other) : m_handle(other.m_handle), m_tfs(other.m_tfs) - { - other.m_handle = nullptr; - } - - operator HANDLE() { return m_handle; } - operator PHANDLE() { return &m_handle; } - uint32_t result_for_print() - { - return static_cast<uint32_t>(reinterpret_cast<uintptr_t>(m_handle)); - } - - bool valid() const { return m_handle != INVALID_HANDLE_VALUE; } - - ~SafeFindHandle() - { - if (m_handle != INVALID_HANDLE_VALUE) { - BOOL res = FindClose(m_handle); - if (m_tfs) - m_tfs->print_result("CloseHandle", res, true); - if (!res) - if (m_tfs) - m_tfs->print_error("CloseHandle", res, true); - else - std::fprintf(stderr, "CloseHandle failed : %d", GetLastError()); - m_handle = NULL; - } - } - -private: - HANDLE m_handle; - TestFileSystem* m_tfs; -}; - -const char* TestW32Api::id() -{ - return "W32"; -} - -TestW32Api::path TestW32Api::real_path(const char* abs_or_rel_path) -{ - if (!abs_or_rel_path || !abs_or_rel_path[0]) - return path(); - - char buf[1024]; - size_t res = GetFullPathNameA(abs_or_rel_path, _countof(buf), buf, NULL); - if (!res || res >= _countof(buf)) - throw_testWinFuncFailed("GetFullPathNameA", res); - return buf; -} - -TestFileSystem::FileInfoList TestW32Api::list_directory(const path& directory_path) -{ - print_operation("Querying directory", directory_path); - - WIN32_FIND_DATA fd; - SafeFindHandle find(this, FindFirstFileW((directory_path / L"*").c_str(), &fd)); - print_result("FindFirstFileW", 0, true, nullptr, true); - if (!find.valid()) - throw_testWinFuncFailed("FindFirstFileW"); - - FileInfoList files; - while (true) { - files.push_back( - FileInformation(fd.cFileName, clean_attributes(fd.dwFileAttributes), - fd.nFileSizeHigh * (MAXDWORD + 1) + fd.nFileSizeLow)); - BOOL res = FindNextFileW(find, &fd); - print_result("FindNextFileW", res, true); - if (!res) - break; - } - - return files; -} - -void TestW32Api::create_path(const path& directory_path) -{ - // sanity and guaranteed recursion end: - if (!directory_path.has_relative_path()) - throw std::runtime_error("Refusing to create non-existing top level path"); - - print_operation("Checking directory", directory_path); - - DWORD attr = GetFileAttributesW(directory_path.c_str()); - DWORD err = GetLastError(); - print_result("GetFileAttributesW", clean_attributes(attr), true); - if (attr != INVALID_FILE_ATTRIBUTES) { - if (attr & FILE_ATTRIBUTE_DIRECTORY) - return; // if directory already exists all is good - else - throw std::runtime_error("path exists but not a directory"); - } - if (err != ERROR_FILE_NOT_FOUND && err != ERROR_PATH_NOT_FOUND) - throw_testWinFuncFailed("GetFileAttributesW"); - - if (err != ERROR_FILE_NOT_FOUND) // ERROR_FILE_NOT_FOUND means parent directory - // already exists - create_path(directory_path - .parent_path()); // otherwise create parent directory (recursively) - - print_operation("Creating directory", directory_path); - - BOOL res = CreateDirectoryW(directory_path.c_str(), NULL); - print_result("CreateDirectoryW", res, true); - if (!res) - throw_testWinFuncFailed("CreateDirectoryW"); -} - -void TestW32Api::read_file(const path& file_path) -{ - print_operation("Reading file", file_path); - - SafeHandle file(this, CreateFileW(file_path.c_str(), GENERIC_READ, FILE_SHARE_READ, - NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL)); - print_result("CreateFileW", 0, true, nullptr, true); - if (!file.valid()) - throw_testWinFuncFailed("CreateFileW"); - - uint32_t total = 0; - bool ends_with_newline = true; - bool pending_prefix = true; - while (true) { - char buf[4096]; - - DWORD read = 0; - BOOL res = ReadFile(file, buf, sizeof(buf), &read, NULL); - print_result("ReadFile", res, true); - if (!res) - throw_testWinFuncFailed("ReadFile"); - if (!read) // eof - break; - - total += read; - char* begin = buf; - char* end = begin + read; - while (begin != end) { - if (pending_prefix) { - if (output()) - fwrite(FILE_CONTENTS_PRINT_PREFIX, 1, strlen(FILE_CONTENTS_PRINT_PREFIX), - output()); - pending_prefix = false; - } - bool skip_newline = false; - char* print_end = reinterpret_cast<char*>(std::memchr(begin, '\n', end - begin)); - if (print_end) { - pending_prefix = true; - if (print_end > begin && *(print_end - 1) == '\r') { - // convert \r\n => \n: - *(print_end - 1) = '\n'; - skip_newline = true; - } else // only a '\n' so just print it - ++print_end; - } else { - print_end = end; - if (print_end > begin && *(print_end - 1) == '\r') { - // buffer ends with \r so skip it under the hope it will be followed with a \n - --print_end; - skip_newline = true; - } - } - if (output()) - fwrite(begin, 1, print_end - begin, output()); - ends_with_newline = print_end > begin && *(print_end - 1) == '\n'; - begin = print_end; - if (skip_newline) - ++begin; - } - if (output() && !ends_with_newline) { - fwrite("\n", 1, 1, output()); - ends_with_newline = true; - } - } - if (output()) { - fprintf(output(), "# Successfully read %u bytes.\n", total); - } -} - -void TestW32Api::write_file(const path& file_path, const void* data, std::size_t size, - bool add_new_line, write_mode mode, bool rw_access) -{ - print_operation(write_operation_name(mode), file_path); - - ACCESS_MASK access = GENERIC_WRITE; - DWORD disposition = OPEN_EXISTING; - switch (mode) { - case write_mode::truncate: - disposition = TRUNCATE_EXISTING; - break; - case write_mode::create: - disposition = CREATE_NEW; - break; - case write_mode::overwrite: - disposition = CREATE_ALWAYS; - break; - case write_mode::opencreate: - disposition = OPEN_ALWAYS; - break; - case write_mode::append: - disposition = OPEN_ALWAYS; - access = FILE_APPEND_DATA; - break; - } - if (rw_access) - access |= GENERIC_READ; - - SafeHandle file(this, CreateFile(file_path.c_str(), access, 0, NULL, disposition, - FILE_ATTRIBUTE_NORMAL, NULL)); - print_result("CreateFileW", 0, true, nullptr, true); - if (!file.valid()) - throw_testWinFuncFailed("CreateFile"); - - if (mode == write_mode::manual_truncate) { - BOOL res = SetEndOfFile(file); - print_result("SetEndOfFile", res, true); - if (!res) - throw_testWinFuncFailed("SetEndOfFile"); - } - - if (mode == write_mode::append) { - DWORD res = SetFilePointer(file, 0, NULL, FILE_END); - print_result("SetFilePointer(FILE_END)", res, true); - if (res == INVALID_SET_FILE_POINTER) - throw_testWinFuncFailed("SetEndOfFile"); - } - - size_t total = 0; - - if (data) { - // finally write the data: - DWORD written = 0; - BOOL res = WriteFile(file, data, static_cast<DWORD>(size), &written, NULL); - print_result("WriteFile", written, true); - if (!res) - throw_testWinFuncFailed("WriteFile"); - total += written; - - if (add_new_line) { - res = WriteFile(file, "\r\n", 2, &written, NULL); - print_result("WriteFile", written, true, "<new line>"); - if (!res) - throw_testWinFuncFailed("WriteFile"); - total += written; - } - } - - print_write_success(data, size, total); -} - -void TestW32Api::touch_file(const path& file_path, bool full_write_access) -{ - print_operation("Touching file", file_path); - - SYSTEMTIME st; - GetSystemTime(&st); - FILETIME ft; - if (!SystemTimeToFileTime(&st, &ft)) - throw_testWinFuncFailed("SystemTimeToFileTime"); - - auto share_all = FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE; - auto access = full_write_access ? GENERIC_WRITE : FILE_WRITE_ATTRIBUTES; - SafeHandle file(this, CreateFile(file_path.c_str(), access, share_all, NULL, - OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL)); - print_result("CreateFileW", 0, true, nullptr, true); - if (!file.valid()) - throw_testWinFuncFailed("CreateFile"); - - BOOL res = SetFileTime(file, nullptr, nullptr, &ft); - print_result("SetFileTime", res, true); - if (!res) - throw_testWinFuncFailed("SetFileTime"); -} - -void TestW32Api::delete_file(const path& file_path) -{ - print_operation("Deleting file", file_path); - - BOOL res = DeleteFileW(file_path.c_str()); - print_result("DeleteFileW", res, true); - if (!res) - throw_testWinFuncFailed("DeleteFileW"); -} - -void TestW32Api::copy_file(const path& source_path, const path& destination_path, - bool replace_existing) -{ - print_operation(replace_existing ? "Copy file over" : "Copy file", source_path, - destination_path); - - BOOL res = - CopyFileW(source_path.c_str(), destination_path.c_str(), !replace_existing); - print_result("CopyFileW", res, true); - if (!res) - throw_testWinFuncFailed("CopyFileW"); -} - -void TestW32Api::rename_file(const path& source_path, const path& destination_path, - bool replace_existing, bool allow_copy) -{ - print_operation(rename_operation_name(replace_existing, allow_copy), source_path, - destination_path); - - DWORD flags = 0; - if (replace_existing) - flags |= MOVEFILE_REPLACE_EXISTING; - if (allow_copy) - flags |= MOVEFILE_COPY_ALLOWED; - - BOOL res = MoveFileExW(source_path.c_str(), destination_path.c_str(), flags); - print_result("MoveFileExW", res, true); - if (!res) - throw_testWinFuncFailed("MoveFileExW"); -} diff --git a/libs/usvfs/test/usvfs_test_runner/test_file_operations/test_w32api.h b/libs/usvfs/test/usvfs_test_runner/test_file_operations/test_w32api.h deleted file mode 100644 index cab8e54..0000000 --- a/libs/usvfs/test/usvfs_test_runner/test_file_operations/test_w32api.h +++ /dev/null @@ -1,36 +0,0 @@ -#pragma once - -#include "test_filesystem.h" - -class TestW32Api : public TestFileSystem -{ -public: - TestW32Api(FILE* output) : TestFileSystem(output) {} - - path real_path(const char* abs_or_rel_path) override; - - FileInfoList list_directory(const path& directory_path) override; - - void create_path(const path& directory_path) override; - - void read_file(const path& file_path) override; - - void write_file(const path& file_path, const void* data, std::size_t size, - bool add_new_line, write_mode mode, bool rw_access = false) override; - - void touch_file(const path& file_path, bool full_write_access = false) override; - - void delete_file(const path& file_path) override; - - void copy_file(const path& source_path, const path& destination_path, - bool replace_existing) override; - - void rename_file(const path& source_path, const path& destination_path, - bool replace_existing, bool allow_copy) override; - - const char* id() override; - -private: - class SafeHandle; - class SafeFindHandle; -}; diff --git a/libs/usvfs/test/usvfs_test_runner/usvfs_test/usvfs_basic_test.cpp b/libs/usvfs/test/usvfs_test_runner/usvfs_test/usvfs_basic_test.cpp deleted file mode 100644 index c5fb3a1..0000000 --- a/libs/usvfs/test/usvfs_test_runner/usvfs_test/usvfs_basic_test.cpp +++ /dev/null @@ -1,402 +0,0 @@ -#include "usvfs_basic_test.h" - -const char* usvfs_basic_test::scenario_name() -{ - return SCENARIO_NAME; -} - -bool usvfs_basic_test::scenario_run() -{ - // Note: For regression purposes we don't really need to verify the results of most - // our operations as the usvfs_test_base postmortem_check will verify the final state. - // We still also verify the results here because: - // A. In some cases a later step may change the results. - // B. It is easier to understand and maintain the test when the important checks are - // together with - // their related operations. - // C. For open issues the verifications here serve as a "documentation" of the issue - // (i.e. not having - // proper copy_on_write, etc.). - - // Cases not covered by the test: - // - When a "temporary" virtualized directory is created (meaning the directory is - // created only to "shadow" - // a real directory) and is then emptied. This needs to be tested within the same - // prcoess and across different processes. - - ops_list(LR"(.)", true, true); - - // test proper path creation under overwrite when a virtualized folder is written to: - - verify_source_existance(LR"(overwrite\mfolder1)", false); - verify_source_existance(LR"(overwrite\mfolder2)", false); - verify_source_existance(LR"(overwrite\mfolder3)", false); - verify_source_existance(LR"(overwrite\mfolder4)", false); - - ops_overwrite(LR"(mfolder1\newfolder1\newfile1.txt)", - R"(newfile1.txt nonrecursive overwrite subfolder)", false); - verify_source_existance(LR"(overwrite\mfolder1\newfolder1\newfile1.txt)"); - ops_overwrite(LR"(mfolder1\newfile1.txt)", R"(newfile1.txt nonrecursive overwrite)", - false); - ops_read(LR"(mfolder1\newfile1.txt)"); - - ops_overwrite(LR"(mfolder2\newfile2.txt)", R"(newfile2.txt recursive overwrite)", - true); - ops_read(LR"(mfolder2\newfile2.txt)"); - verify_source_contents(LR"(overwrite\mfolder2\newfile2.txt)", - R"(newfile2.txt recursive overwrite)"); - ops_overwrite(LR"(mfolder2\newfile2.txt\fail)", - R"(newfile2.txt is a file so folder creation should fail)", true, - false); - verify_source_contents(LR"(overwrite\mfolder2\newfile2.txt)", - R"(newfile2.txt recursive overwrite)"); - ops_overwrite(LR"(mfolder2\mfile.txt\fail)", - R"(mfile.txt is a file so folder creation should fail)", true, false); - verify_source_existance(LR"(overwrite\mfolder2\mfile.txt)", false); - - ops_overwrite(LR"(mfolder3\newfolder3\newfile3.txt)", - R"(newfile3.txt recursive overwrite)", true); - ops_read(LR"(mfolder3\newfolder3\newfile3.txt)"); - verify_source_contents(LR"(overwrite\mfolder3\newfolder3\newfile3.txt)", - R"(newfile3.txt recursive overwrite)"); - // repeat mfolder3\newfolder3 test as that folder now exists in overwrite and that - // changes things - ops_overwrite(LR"(mfolder3\newfolder3\newfile3e.txt)", - R"(newfile3e.txt recursive overwrite)", true); - ops_read(LR"(mfolder3\newfolder3\newfile3e.txt)"); - verify_source_contents(LR"(overwrite\mfolder3\newfolder3\newfile3e.txt)", - R"(newfile3e.txt recursive overwrite)"); - - ops_overwrite(LR"(mfolder4\newfolder4\d\e\e\p\newfile4.txt)", - R"(newfile4.txt recursive overwrite)", true); - ops_read(LR"(mfolder4\newfolder4\d\e\e\p\newfile4.txt)"); - verify_source_contents(LR"(overwrite\mfolder4\newfolder4\d\e\e\p\newfile4.txt)", - R"(newfile4.txt recursive overwrite)"); - // repeat mfolder4\newfolder4\d\e\e\p test as that folder now exists in overwrite and - // that changes things - ops_overwrite(LR"(mfolder4\newfolder4\d\e\e\p\newfile4e.txt)", - R"(newfile4e.txt recursive overwrite)", true); - ops_read(LR"(mfolder4\newfolder4\d\e\e\p\newfile4e.txt)"); - verify_source_contents(LR"(overwrite\mfolder4\newfolder4\d\e\e\p\newfile4e.txt)", - R"(newfile4e.txt recursive overwrite)"); - // and finally verify also non-recursive works - ops_overwrite(LR"(mfolder4\newfolder4\d\e\e\p\newfile4enr.txt)", - R"(newfile4enr.txt nonrecursive overwrite)", false); - ops_read(LR"(mfolder4\newfolder4\d\e\e\p\newfile4enr.txt)"); - verify_source_contents(LR"(overwrite\mfolder4\newfolder4\d\e\e\p\newfile4enr.txt)", - R"(newfile4enr.txt nonrecursive overwrite)"); - // finally check an intermediate folder: - ops_overwrite(LR"(mfolder4\newfolder4\d\e\epnewfile4r.txt)", - R"(epnewfile4r.txt recursive overwrite)", true); - ops_read(LR"(mfolder4\newfolder4\d\e\epnewfile4r.txt)"); - verify_source_contents(LR"(overwrite\mfolder4\newfolder4\d\e\epnewfile4r.txt)", - R"(epnewfile4r.txt recursive overwrite)"); - ops_overwrite(LR"(mfolder4\newfolder4\d\e\epnewfile4.txt)", - R"(epnewfile4.txt nonrecursive overwrite)", false); - ops_read(LR"(mfolder4\newfolder4\d\e\epnewfile4.txt)"); - verify_source_contents(LR"(overwrite\mfolder4\newfolder4\d\e\epnewfile4.txt)", - R"(epnewfile4.txt nonrecursive overwrite)"); - - verify_mount_existance(LR"(rfolder\rcopyme4.txt)"); - verify_source_existance(LR"(overwrite\mfolder4\newfolder4p)", false); - ops_copy(LR"(rfolder\rcopyme4.txt)", LR"(mfolder4\newfolder4p\rcopyme4.txt)", true); - verify_source_existance(LR"(overwrite\mfolder4\newfolder4p\rcopyme4.txt)", true); - verify_source_existance(LR"(mod4\mfolder4\mfile.txt)"); - verify_source_existance(LR"(overwrite\mfolder4\mfile.txt)", false); - ops_copy(LR"(rfolder\rcopyme4.txt)", LR"(mfolder4\rcopyme4.txt)", false); - verify_source_existance(LR"(overwrite\mfolder4\rcopyme4.txt)"); - - verify_source_contents(LR"(overwrite\mfolder4\newfolder4\d\e\e\p\newfile4.txt)", - R"(newfile4.txt recursive overwrite)"); - // repeat mfolder4\newfolder4\d\e\e\p test as that folder now exists in overwrite and - // that changes things - ops_overwrite(LR"(mfolder4\newfolder4\d\e\e\p\newfile4e.txt)", - R"(newfile4e.txt recursive overwrite)", true); - ops_read(LR"(mfolder4\newfolder4\d\e\e\p\newfile4e.txt)"); - verify_source_contents(LR"(overwrite\mfolder4\newfolder4\d\e\e\p\newfile4e.txt)", - R"(newfile4e.txt recursive overwrite)"); - // and finally verify also non-recursive works - ops_overwrite(LR"(mfolder4\newfolder4\d\e\e\p\newfile4enr.txt)", - R"(newfile4enr.txt nonrecursive overwrite)", false); - ops_read(LR"(mfolder4\newfolder4\d\e\e\p\newfile4enr.txt)"); - verify_source_contents(LR"(overwrite\mfolder4\newfolder4\d\e\e\p\newfile4enr.txt)", - R"(newfile4enr.txt nonrecursive overwrite)"); - // finally check an intermediate folder: - ops_overwrite(LR"(mfolder4\newfolder4\d\e\epnewfile4r.txt)", - R"(epnewfile4r.txt recursive overwrite)", true); - ops_read(LR"(mfolder4\newfolder4\d\e\epnewfile4r.txt)"); - verify_source_contents(LR"(overwrite\mfolder4\newfolder4\d\e\epnewfile4r.txt)", - R"(epnewfile4r.txt recursive overwrite)"); - ops_overwrite(LR"(mfolder4\newfolder4\d\e\epnewfile4.txt)", - R"(epnewfile4.txt nonrecursive overwrite)", false); - ops_read(LR"(mfolder4\newfolder4\d\e\epnewfile4.txt)"); - verify_source_contents(LR"(overwrite\mfolder4\newfolder4\d\e\epnewfile4.txt)", - R"(epnewfile4.txt nonrecursive overwrite)"); - - // test copy on write/delete against source "mod": - - ops_touch(LR"(root0.txt)"); - verify_source_existance(LR"(overwrite\root0.txt)", false); - ops_touch(LR"(root1.txt)"); - verify_source_existance(LR"(overwrite\root1.txt)", false); - ops_touch(LR"(root2.txt)"); - verify_source_existance(LR"(overwrite\root1.txt)", false); - ops_touch(LR"(mod1.txt)"); - verify_source_existance(LR"(overwrite\mod1.txt)", false); - ops_touch(LR"(mfolder1\mfile.txt)"); - verify_source_existance(LR"(overwrite\mfolder1\mfile.txt)", false); - - ops_touch(LR"(root0w.txt)", true); - verify_source_existance(LR"(overwrite\root0w.txt)", false); - ops_touch(LR"(root1w.txt)", true); - verify_source_existance(LR"(overwrite\root1w.txt)", false); - ops_touch(LR"(root2w.txt)", true); - verify_source_existance(LR"(overwrite\root1w.txt)", false); - ops_touch(LR"(mod1w.txt)", true); - verify_source_existance(LR"(overwrite\mod1w.txt)", false); - ops_touch(LR"(mfolder1\mfilew.txt)", true); - verify_source_existance(LR"(overwrite\mfolder1\mfilew.txt)", false); - - { - const auto& old_contents = source_contents(LR"(mod4\mfolder4\mfileoverwrite.txt)"); - verify_source_contents(LR"(mod4\mfolder4\mfileoverwrite.txt)", - old_contents.c_str()); - ops_overwrite(LR"(mfolder4\mfileoverwrite.txt)", - R"(mfolder4\mfileoverwrite.txt overwrite)", false); - ops_read(LR"(mfolder4\mfileoverwrite.txt)"); - if (bool protect_virtualized = false) { - verify_source_contents(LR"(mod4\mfolder4\mfileoverwrite.txt)", - old_contents.c_str()); - verify_source_contents(LR"(overwrite\mfolder4\mfileoverwrite.txt)", - R"(mfolder4\mfileoverwrite.txt overwrite)"); - } else { - verify_source_contents(LR"(mod4\mfolder4\mfileoverwrite.txt)", - R"(mfolder4\mfileoverwrite.txt overwrite)"); - verify_source_existance(LR"(overwrite\mfolder4\mfileoverwrite.txt)", false); - } - } - - { - const auto& old_contents = source_contents(LR"(mod4\mfolder4\mfilerewrite.txt)"); - verify_source_contents(LR"(mod4\mfolder4\mfilerewrite.txt)", old_contents.c_str()); - ops_rewrite(LR"(mfolder4\mfilerewrite.txt)", - R"(mfolder4\mfilerewrite.txt rewrite)"); - ops_read(LR"(mfolder4\mfilerewrite.txt)"); - if (auto copy_on_readwrite_implemented = false) { - verify_source_contents(LR"(mod4\mfolder4\mfilerewrite.txt)", - old_contents.c_str()); - verify_source_contents(LR"(overwrite\mfolder4\mfilerewrite.txt)", - R"(mfolder4\mfilerewrite.txt rewrite)"); - } else { - verify_source_contents(LR"(mod4\mfolder4\mfilerewrite.txt)", - R"(mfolder4\mfilerewrite.txt rewrite)"); - verify_source_existance(LR"(overwrite\mfolder4\mfilerewrite.txt)", false); - } - } - - { - const auto& old_contents = source_contents(LR"(mod4\mfolder4\mfilemoveover.txt)"); - verify_source_contents(LR"(mod4\mfolder4\mfilemoveover.txt)", old_contents.c_str()); - ops_overwrite(LR"(mfolder4\temp_mfilemoveover.txt)", - R"(mfolder4\mfilemoveover.txt overwrite)", false); - verify_source_contents(LR"(overwrite\mfolder4\temp_mfilemoveover.txt)", - R"(mfolder4\mfilemoveover.txt overwrite)"); - ops_rename(LR"(mfolder4\temp_mfilemoveover.txt)", LR"(mfolder4\mfilemoveover.txt)", - true); - ops_read(LR"(mfolder4\mfilemoveover.txt)"); - verify_source_existance(LR"(overwrite\mfolder4\temp_mfilemoveover.txt)", false); - if (bool protect_virtualized = false) { - verify_source_contents(LR"(mod4\mfolder4\mfilemoveover.txt)", - old_contents.c_str()); - verify_source_contents(LR"(overwrite\mfolder4\mfilemoveover.txt)", - R"(mfolder4\mfilemoveover.txt overwrite)"); - } else { - verify_source_contents(LR"(mod4\mfolder4\mfilemoveover.txt)", - R"(mfolder4\mfilemoveover.txt overwrite)"); - verify_source_existance(LR"(overwrite\mfolder4\mfilemoveover.txt)", false); - } - } - - { - const auto& old_contents = - source_contents(LR"(mod4\mfolder4\mfiledeletewrite.txt)"); - verify_source_contents(LR"(mod4\mfolder4\mfiledeletewrite.txt)", - old_contents.c_str()); - ops_deleteoverwrite(LR"(mfolder4\mfiledeletewrite.txt)", - R"(mfolder4\mfiledeletewrite.txt overwrite)", false); - ops_read(LR"(mfolder4\mfiledeletewrite.txt)"); - if (bool protect_virtualized = false) { - verify_source_contents(LR"(overwrite\mfolder4\mfiledeletewrite.txt)", - R"(mfolder4\mfiledeletewrite.txt overwrite)"); - if (auto proper_delete_implemented = false) - verify_source_contents(LR"(mod4\mfolder4\mfiledeletewrite.txt)", - old_contents.c_str()); - else - verify_source_existance(LR"(mod4\mfolder4\mfiledeletewrite.txt)", false); - } else { - verify_source_contents(LR"(mod4\mfolder4\mfiledeletewrite.txt)", - R"(mfolder4\mfiledeletewrite.txt overwrite)"); - verify_source_existance(LR"(overwrite\mfolder4\mfiledeletewrite.txt)", false); - } - } - - { - const auto& old_contents = - source_contents(LR"(mod4\mfolder4\mfiledeletewrite2p.txt)"); - verify_source_contents(LR"(mod4\mfolder4\mfiledeletewrite2p.txt)", - old_contents.c_str()); - ops_delete(LR"(mfolder4\mfiledeletewrite2p.txt)"); - ops_overwrite(LR"(mfolder4\mfiledeletewrite2p.txt)", - R"(mfolder4\mfiledeletewrite2p.txt overwrite)", false); - ops_read(LR"(mfolder4\mfiledeletewrite2p.txt)"); - if (bool protect_virtualized_or_track_deleted_only_in_current_process = true) { - verify_source_contents(LR"(overwrite\mfolder4\mfiledeletewrite2p.txt)", - R"(mfolder4\mfiledeletewrite2p.txt overwrite)"); - if (auto proper_delete_implemented = false) - verify_source_contents(LR"(mod4\mfolder4\mfiledeletewrite2p.txt)", - old_contents.c_str()); - else - verify_source_existance(LR"(mod4\mfolder4\mfiledeletewrite2p.txt)", false); - } else { - verify_source_contents(LR"(mod4\mfolder4\mfiledeletewrite2p.txt)", - R"(mfolder4\mfiledeletewrite2p.txt overwrite)"); - verify_source_existance(LR"(overwrite\mfolder4\mfiledeletewrite2p.txt)", false); - } - } - - { - const auto& old_contents = source_contents(LR"(mod4\mfolder4\mfiledeletemove.txt)"); - verify_source_contents(LR"(mod4\mfolder4\mfiledeletemove.txt)", - old_contents.c_str()); - ops_overwrite(LR"(mfolder4\temp_mfiledeletemove.txt)", - R"(mfolder4\mfiledeletemove.txt overwrite)", false); - verify_source_contents(LR"(overwrite\mfolder4\temp_mfiledeletemove.txt)", - R"(mfolder4\mfiledeletemove.txt overwrite)"); - ops_deleterename(LR"(mfolder4\temp_mfiledeletemove.txt)", - LR"(mfolder4\mfiledeletemove.txt)"); - ops_read(LR"(mfolder4\mfiledeletemove.txt)"); - verify_source_existance(LR"(overwrite\mfolder4\temp_mfiledeletemove.txt)", false); - if (bool protect_virtualized = false) { - verify_source_contents(LR"(overwrite\mfolder4\mfiledeletemove.txt)", - R"(mfolder4\mfiledeletemove.txt overwrite)"); - if (auto proper_delete_implemented = false) - verify_source_contents(LR"(mod4\mfolder4\mfiledeletemove.txt)", - old_contents.c_str()); - else - verify_source_existance(LR"(mod4\mfolder4\mfiledeletemove.txt)", false); - } else { - verify_source_contents(LR"(mod4\mfolder4\mfiledeletemove.txt)", - R"(mfolder4\mfiledeletemove.txt overwrite)"); - verify_source_existance(LR"(overwrite\mfolder4\mfiledeletemove.txt)", false); - } - } - - { - const auto& old_contents = - source_contents(LR"(mod4\mfolder4\mfiledeletemove2p.txt)"); - verify_source_contents(LR"(mod4\mfolder4\mfiledeletemove2p.txt)", - old_contents.c_str()); - ops_delete(LR"(mfolder4\mfiledeletemove2p.txt)"); - ops_overwrite(LR"(mfolder4\temp_mfiledeletemove2p.txt)", - R"(mfolder4\mfiledeletemove2p.txt overwrite)", false); - verify_source_contents(LR"(overwrite\mfolder4\temp_mfiledeletemove2p.txt)", - R"(mfolder4\mfiledeletemove2p.txt overwrite)"); - ops_rename(LR"(mfolder4\temp_mfiledeletemove2p.txt)", - LR"(mfolder4\mfiledeletemove2p.txt)", false); - ops_read(LR"(mfolder4\mfiledeletemove2p.txt)"); - verify_source_existance(LR"(overwrite\mfolder4\temp_mfiledeletemove2p.txt)", false); - if (bool protect_virtualized_or_track_deleted_only_in_current_process = true) { - verify_source_contents(LR"(overwrite\mfolder4\mfiledeletemove2p.txt)", - R"(mfolder4\mfiledeletemove2p.txt overwrite)"); - if (auto proper_delete_implemented = false) - verify_source_contents(LR"(mod4\mfolder4\mfiledeletemove2p.txt)", - old_contents.c_str()); - else - verify_source_existance(LR"(mod4\mfolder4\mfiledeletemove2p.txt)", false); - } else { - verify_source_contents(LR"(mod4\mfolder4\mfiledeletemove2p.txt)", - R"(mfolder4\mfiledeletemove2p.txt overwrite)"); - verify_source_existance(LR"(overwrite\mfolder4\mfiledeletemove2p.txt)", false); - } - } - - // test copy on write/delete/move against original mount files: - - { - const auto& old_contents = mount_contents(LR"(rfolder\rfilerewrite.txt)"); - ops_rewrite(LR"(rfolder\rfilerewrite.txt)", R"(rfolder\rfilerewrite.txt rewrite)"); - ops_read(LR"(rfolder\rfilerewrite.txt)"); - if (auto copy_on_readwrite_implemented = false) { - verify_mount_contents(LR"(rfolder\rfilerewrite.txt)", old_contents.c_str()); - verify_source_contents(LR"(overwrite\rfolder\rfilerewrite.txt)", - R"(rfolder\rfilerewrite.txt rewrite)"); - } else { - verify_mount_contents(LR"(rfolder\rfilerewrite.txt)", - R"(rfolder\rfilerewrite.txt rewrite)"); - verify_source_existance(LR"(overwrite\rfolder\rfilerewrite.txt)", false); - } - } - ops_overwrite(LR"(rfolder\rfilerewrite.txt\fail)", - R"(rfilerewrite.txt is a file so folder creation should fail)", true, - false); - verify_mount_existance( - LR"(rfolder\rfilerewrite.txt)"); // verifies its a file and not a directory - if (auto copy_on_readwrite_implemented = false) - verify_source_existance( - LR"(overwrite\rfolder\rfilerewrite.txt)"); // verifies its a file and not a - // directory - else - verify_source_existance(LR"(overwrite\rfolder\rfilerewrite.txt)", false); - ops_overwrite(LR"(rfolder\rfile0.txt\fail)", - R"(rfile0.txt is a file so folder creation should fail)", true, false); - verify_mount_existance( - LR"(rfolder\rfile0.txt)"); // verifies its a file and not a directory - - { - const auto& old_contents = mount_contents(LR"(rfolder\rfiledeletewrite.txt)"); - ops_deleteoverwrite(LR"(rfolder\rfiledeletewrite.txt)", - R"(rfolder\rfiledeletewrite.txt overwrite)", false); - ops_read(LR"(rfolder\rfiledeletewrite.txt)"); - if (bool protect_virtualized = false) { - verify_source_contents(LR"(overwrite\rfolder\rfiledeletewrite.txt)", - R"(rfolder\rfiledeletewrite.txt overwrite)"); - if (auto proper_delete_implemented = false) - verify_mount_contents(LR"(rfolder\rfiledeletewrite.txt)", old_contents.c_str()); - else - verify_mount_existance(LR"(rfolder\rfiledeletewrite.txt)", false); - } else { - verify_mount_contents(LR"(rfolder\rfiledeletewrite.txt)", - R"(rfolder\rfiledeletewrite.txt overwrite)"); - verify_source_existance(LR"(overwrite\rfolder\rfiledeletewrite.txt)", false); - } - } - - { - const auto& old_contents = mount_contents(LR"(rfolder\rfiledelete.txt)"); - ops_delete(LR"(rfolder\rfiledelete.txt)"); - ops_read(LR"(rfolder\rfiledelete.txt)", false); - if (auto proper_delete_implemented = false) - verify_mount_contents(LR"(rfolder\rfiledelete.txt)", old_contents.c_str()); - else - verify_mount_existance(LR"(rfolder\rfiledelete.txt)", false); - } - - { - const auto& old_contents = mount_contents(LR"(rfolder\rfileoldname.txt)"); - ops_rename(LR"(rfolder\rfileoldname.txt)", LR"(rfolder\rfilenewname.txt)", false, - false); - ops_read(LR"(rfolder\rfileoldname.txt)", false); - ops_read(LR"(rfolder\rfilenewname.txt)"); - verify_source_contents(LR"(overwrite\rfolder\rfilenewname.txt)", - old_contents.c_str()); - verify_mount_existance(LR"(rfolder\rfilenewname.txt)", false); - if (auto copy_on_move_implemented = false) - verify_mount_contents(LR"(rfolder\rfileoldname.txt)", old_contents.c_str()); - else - verify_mount_existance(LR"(rfolder\rfileoldname.txt)", false); - } - - ops_list(LR"(.)", true, true); - - return true; -} diff --git a/libs/usvfs/test/usvfs_test_runner/usvfs_test/usvfs_basic_test.h b/libs/usvfs/test/usvfs_test_runner/usvfs_test/usvfs_basic_test.h deleted file mode 100644 index bec81f2..0000000 --- a/libs/usvfs/test/usvfs_test_runner/usvfs_test/usvfs_basic_test.h +++ /dev/null @@ -1,14 +0,0 @@ -#pragma once - -#include "usvfs_test_base.h" - -class usvfs_basic_test : public usvfs_test_base -{ -public: - static constexpr auto SCENARIO_NAME = "basic"; - - usvfs_basic_test(const usvfs_test_options& options) : usvfs_test_base(options) {} - - virtual const char* scenario_name(); - virtual bool scenario_run(); -}; diff --git a/libs/usvfs/test/usvfs_test_runner/usvfs_test/usvfs_test.cpp b/libs/usvfs/test/usvfs_test_runner/usvfs_test/usvfs_test.cpp deleted file mode 100644 index e6e6bb1..0000000 --- a/libs/usvfs/test/usvfs_test_runner/usvfs_test/usvfs_test.cpp +++ /dev/null @@ -1,242 +0,0 @@ - -#include <iostream> -#include <memory> - -#include <boost/filesystem.hpp> -#include <boost/type_traits.hpp> -#include <winapi.h> - -#include "usvfs_basic_test.h" -#include <stringcast.h> - -void print_usage(const std::wstring& exe_name, const std::wstring& test_name) -{ - using namespace std; - wcerr << "usage: " << exe_name << " [<options>] <scenario>[:<label>]" << endl; - wcerr << "available options:" << endl; - wcerr << " -ops32 : force 32bit file opertations process (default is same " - "bitness)." - << endl; - wcerr << " -ops64 : force 64bit file opertations process (default is same " - "bitness)." - << endl; - wcerr << " -opsexe <file> : full path to file operations executable (overrides " - "-ops32/64)." - << endl; - wcerr << " -opsarg <arg> : adds argument to the start of all file operations." - << endl; - wcerr << " -fixture <dir> : fixture dir (default is test\\fixtures\\" << test_name - << "\\<scenario>)." << endl; - wcerr << " -mapping <file> : mapping file (default is <fixture " - "dir>\\vfs_mappings.txt)." - << endl; - wcerr << " -temp <dir> : temp dir (default is test\\temp\\" << test_name - << "\\<scenario>_<label>)." << endl; - wcerr << " -mount <dir> : mount dir (default is <temp dir>\\mount)." << endl; - wcerr << " -source <dir> : source dir (default is <temp dir>\\source)." << endl; - wcerr << " -out <file> : output file (default is <temp " - "dir>\\<scenario>_<label>.log)." - << endl; - wcerr << " -usvfslog <file> : output file (default is <temp " - "dir>\\<scenario>_<label>_usvfs.log)." - << endl; - wcerr << " -forcetemprecursivedelete : decimate temp dir even if doesn't look like a " - "temp dir." - << endl; - wcerr << endl; - wcerr << "note: if <label> is ommited the current platform (x86/x64) is used." - << endl; - wcerr << "note: mount and source dirs should not exist or be empty directories. if " - "either of them" - << endl; - wcerr << "is not given, the temp dir is first recusrively deleted. to protect " - "against accidents a" - << endl; - wcerr << "heuristic is used to verify the temp dir only has entires which this test " - "creates." - << endl; - wcerr << "-forcetemprecursivedelete can be used to circumvent this heuristic." - << endl; -} - -usvfs_test_base* find_scenario(const std::string& scenario, - const usvfs_test_options& options) -{ - if (scenario == usvfs_basic_test::SCENARIO_NAME) - return new usvfs_basic_test(options); - else - return nullptr; -} - -bool verify_args_exist(const wchar_t* flag, int params, int index, int count) -{ - if (index + params >= count) { - std::wcerr << flag << L" requires " << params << L" arguments" << std::endl; - return false; - } else - return true; -} - -bool verify_file(const test::path& file) -{ - bool is_dir = false; - if (!winapi::ex::wide::fileExists(file.c_str(), &is_dir) || is_dir) { - std::wcerr << L"File does not exist: " << file << std::endl; - return false; - } else - return true; -} - -bool verify_dir(const test::path& dir) -{ - bool is_dir = false; - if (!winapi::ex::wide::fileExists(dir.c_str(), &is_dir) || !is_dir) { - std::wcerr << L"Directory does not exist: " << dir << std::endl; - return false; - } else - return true; -} - -std::wstring get_env_var(const wchar_t* var) -{ - using namespace std; - size_t size = GetEnvironmentVariableW(var, nullptr, 0); - if (size) { - std::wstring value(size, L'\0'); - size = GetEnvironmentVariableW(var, &value[0], static_cast<DWORD>(value.size())); - if (size && size < value.size()) { - value.resize(size); - return value; - } - } - wcerr << L"GetEnvironmentVariableW(" << var << L") failed result=" << size - << L" error=" << GetLastError() << endl; - return wstring(); -} - -bool set_env_var(const wchar_t* var, const std::wstring& value) -{ - if (SetEnvironmentVariableW(var, value.c_str())) - return true; - std::wcerr << L"SetEnvironmentVariableW(" << var << L"," << value - << L") failed error=" << GetLastError() << std::endl; - return false; -} - -int wmain(int argc, wchar_t* argv[]) -{ - using namespace std; - using namespace test; - - const wchar_t* label = nullptr; - wstring scenario; - path temp; - usvfs_test_options options; - - for (int ai = 1; ai < argc; ++ai) { - if (wcscmp(argv[ai], L"-ops32") == 0) - options.set_ops32(); - else if (wcscmp(argv[ai], L"-ops64") == 0) - options.set_ops64(); - else if (wcscmp(argv[ai], L"-opsexe") == 0) { - if (!verify_args_exist(L"-opsexe", 1, ai, argc)) - return 1; - options.opsexe = argv[++ai]; - if (!verify_file(options.opsexe)) - return 1; - } else if (wcscmp(argv[ai], L"-opsarg") == 0) { - if (!verify_args_exist(L"-opsarg", 1, ai, argc)) - return 1; - options.add_ops_options(argv[++ai]); - } else if (wcscmp(argv[ai], L"-fixture") == 0) { - if (!verify_args_exist(L"-fixture", 1, ai, argc)) - return 1; - options.fixture = argv[++ai]; - if (!verify_dir(options.fixture)) - return 1; - } else if (wcscmp(argv[ai], L"-mapping") == 0) { - if (!verify_args_exist(L"-mapping", 1, ai, argc)) - return 1; - options.mapping = argv[++ai]; - if (!verify_file(options.mapping)) - return 1; - } else if (wcscmp(argv[ai], L"-temp") == 0) { - if (!verify_args_exist(L"-temp", 1, ai, argc)) - return 1; - options.mount = argv[++ai]; - } else if (wcscmp(argv[ai], L"-mount") == 0) { - if (!verify_args_exist(L"-mount", 1, ai, argc)) - return 1; - options.mount = argv[++ai]; - } else if (wcscmp(argv[ai], L"-source") == 0) { - if (!verify_args_exist(L"-source", 1, ai, argc)) - return 1; - options.source = argv[++ai]; - } else if (wcscmp(argv[ai], L"-out") == 0) { - if (!verify_args_exist(L"-out", 1, ai, argc)) - return 1; - options.output = argv[++ai]; - } else if (wcscmp(argv[ai], L"-usvfslog") == 0) { - if (!verify_args_exist(L"-usvfslog", 1, ai, argc)) - return 1; - options.usvfs_log = argv[++ai]; - } else if (wcscmp(argv[ai], L"-forcetemprecursivedelete") == 0) - options.force_temp_cleanup = true; - else if (argv[ai][0] == '-') { - wcerr << L"Unknown option " << argv[ai] << endl; - return 1; - } else if (!scenario.empty()) { - wcerr << L"Multiple scenarios can not be specified: " << scenario.c_str() << L", " - << argv[ai] << endl; - return 1; - } else { - label = wcschr(argv[ai], ':'); - if (label) { - scenario = std::wstring(static_cast<const wchar_t*>(argv[ai]), label); - ++label; // skip the ':' - } else - scenario = argv[ai]; - - if (scenario.empty()) { - wcerr << L"Scenario name can not be empty!" << endl; - return 1; - } - } - } - - path test_name{"usvfs_test"}; - - if (scenario.empty()) { - print_usage(path(argv[0]).stem(), test_name); - return 1; - } - - options.fill_defaults(test_name, scenario, label); - - unique_ptr<usvfs_test_base> test{find_scenario( - usvfs::shared::string_cast<std::string>(scenario, usvfs::shared::CodePage::UTF8), - options)}; - if (!test) { - wcerr << L"ERROR: Unknown scenario specified: " << scenario.c_str() << endl; - return 2; - } - - auto dllPath = path_of_usvfs_lib(platform_dependant_executable("usvfs", "dll")); - ScopedLoadLibrary loadDll(dllPath.c_str()); - if (!loadDll) { - wcerr << L"ERROR: failed to load usvfs dll: " << dllPath.c_str() << L", " - << GetLastError() << endl; - return 3; - } - - // In order for bin\usvfs_proxy_x??.exe to find the lib\usvfs_x??.dll file we add the - // lib folder to our path: - std::wstring env_path = get_env_var(L"Path"); - if (env_path.empty() || - !set_env_var(L"Path", dllPath.parent_path().wstring() + L";" + env_path)) { - wcerr << L"ERROR: failed to add usvfs dll directory to path" << endl; - return 3; - } - - return test->run(path(argv[0]).stem()); -} diff --git a/libs/usvfs/test/usvfs_test_runner/usvfs_test/usvfs_test_base.cpp b/libs/usvfs/test/usvfs_test_runner/usvfs_test/usvfs_test_base.cpp deleted file mode 100644 index bfa391e..0000000 --- a/libs/usvfs/test/usvfs_test_runner/usvfs_test/usvfs_test_base.cpp +++ /dev/null @@ -1,1002 +0,0 @@ - -#include "usvfs_test_base.h" -#include <boost/filesystem.hpp> -#include <boost/type_traits.hpp> -#include <cctype> -#include <cerrno> -#include <chrono> -#include <future> -#include <iostream> -#include <stringcast.h> -#include <thread> -#include <unordered_set> -#include <usvfs.h> -#include <vector> -#include <winapi.h> - -using test::throw_testWinFuncFailed; - -// usvfs_test_options class: - -void usvfs_test_options::fill_defaults(const path& test_name, - const std::wstring& scenario, - const wchar_t* label) -{ - using namespace test; - - std::wstring lbl; - if (label) - lbl = label; - -#ifdef _WIN64 - set_ops64(); - if (!label) - lbl = L"x64"; -#else - set_ops32(); - if (!label) - lbl = L"x86"; -#endif - - std::wstring scenario_label = scenario; - if (!lbl.empty()) { - scenario_label += L"_"; - scenario_label += lbl; - } - - if (fixture.empty()) - fixture = path_of_test_fixtures(test_name / scenario); - - if (mapping.empty()) - mapping = fixture / DEFAULT_MAPPING; - - if (temp.empty()) { - temp = path_of_test_temp(test_name / scenario_label); - } - - if (mount.empty()) { - mount = temp / MOUNT_DIR; - temp_cleanup = true; - } - - if (source.empty()) { - source = temp / SOURCE_DIR; - temp_cleanup = true; - } - - if (output.empty()) { - output = temp / scenario_label; - output += ".log"; - } - - if (usvfs_log.empty()) { - usvfs_log = temp / scenario_label; - usvfs_log += "_usvfs.log"; - } -} - -void usvfs_test_options::set_ops32() -{ - if (opsexe.empty()) - opsexe = test::path_of_test_bin(L"test_file_operations_x86.exe"); -} - -void usvfs_test_options::set_ops64() -{ - if (opsexe.empty()) - opsexe = test::path_of_test_bin(L"test_file_operations_x64.exe"); -} - -void usvfs_test_options::add_ops_options(const std::wstring& options) -{ - if (!ops_options.empty()) - ops_options += L" "; - ops_options += options; -} - -// usvfs_connector helper class: - -class usvfs_connector -{ -public: - using path = test::path; - - usvfs_connector(const usvfs_test_options& options) - : m_usvfs_log(test::ScopedFILE::open(options.usvfs_log, L"wt")), - m_exit_future(m_exit_signal.get_future()) - { - winapi::ex::wide::createPath(options.usvfs_log.parent_path().c_str()); - - std::wcout << "Connecting VFS..." << std::endl; - - std::unique_ptr<usvfsParameters, decltype(&usvfsFreeParameters)> parameters{ - usvfsCreateParameters(), &usvfsFreeParameters}; - - usvfsSetInstanceName(parameters.get(), "usvfs_test"); - usvfsSetDebugMode(parameters.get(), false); - usvfsSetLogLevel(parameters.get(), LogLevel::Debug); - usvfsSetCrashDumpType(parameters.get(), CrashDumpsType::None); - usvfsSetCrashDumpPath(parameters.get(), ""); - - usvfsInitLogging(false); - usvfsCreateVFS(parameters.get()); - - m_log_thread = std::thread(&usvfs_connector::usvfs_logger, this); - } - - ~usvfs_connector() - { - usvfsDisconnectVFS(); - m_exit_signal.set_value(); - m_log_thread.join(); - } - - enum class map_type - { - none, // the mapping_reader uses this value but will never pass it to the - // usvfs_connector (which ignored such entries) - dir, - dircreate, - file - }; - - struct mapping - { - mapping(map_type itype, std::wstring isource, std::wstring idestination) - : type(itype), source(isource), destination(idestination) - {} - - map_type type; - path source; - path destination; - }; - - using mappings_list = std::vector<mapping>; - - void updateMapping(const mappings_list& mappings, const usvfs_test_options& options, - FILE* log) - { - using namespace std; - using namespace usvfs::shared; - - fprintf(log, "Updating VFS mappings:\n"); - - usvfsClearVirtualMappings(); - - for (const auto& map : mappings) { - const string& source = - usvfs_test_base::SOURCE_LABEL + - test::path_as_relative(options.source, map.source).string(); - const string& destination = - usvfs_test_base::MOUNT_LABEL + - test::path_as_relative(options.mount, map.destination).string(); - switch (map.type) { - case map_type::dir: - fprintf(log, " mapdir: %s => %s\n", source.c_str(), destination.c_str()); - usvfsVirtualLinkDirectoryStatic(map.source.c_str(), map.destination.c_str(), - LINKFLAG_RECURSIVE); - break; - - case map_type::dircreate: - fprintf(log, " mapdircreate: %s => %s\n", source.c_str(), destination.c_str()); - usvfsVirtualLinkDirectoryStatic(map.source.c_str(), map.destination.c_str(), - LINKFLAG_CREATETARGET | LINKFLAG_RECURSIVE); - break; - - case map_type::file: - fprintf(log, " mapfile: %s => %s\n", source.c_str(), destination.c_str()); - usvfsVirtualLinkFile(map.source.c_str(), map.destination.c_str(), - LINKFLAG_RECURSIVE); - break; - } - } - - fprintf(log, "\n"); - } - - static DWORD spawn(wchar_t* commandline) - { - using namespace usvfs::shared; - - STARTUPINFO si{0}; - si.cb = sizeof(si); - PROCESS_INFORMATION pi{0}; - - if (!usvfsCreateProcessHooked(NULL, commandline, NULL, NULL, FALSE, 0, NULL, NULL, - &si, &pi)) - throw_testWinFuncFailed( - "CreateProcessHooked", - string_cast<std::string>(commandline, CodePage::UTF8).c_str()); - - WaitForSingleObject(pi.hProcess, INFINITE); - - DWORD exit = 99; - if (!GetExitCodeProcess(pi.hProcess, &exit)) { - test::WinFuncFailedGenerator failed; - CloseHandle(pi.hProcess); - CloseHandle(pi.hThread); - throw failed("GetExitCodeProcess"); - } - - CloseHandle(pi.hProcess); - CloseHandle(pi.hThread); - - return exit; - } - - void usvfs_logger() - { - fprintf(m_usvfs_log, "usvfs_test usvfs logger started:\n"); - fflush(m_usvfs_log); - - constexpr size_t size = 1024; - char buf[size + 1]{0}; - int noLogCycles = 0; - std::chrono::milliseconds wait_for; - do { - if (usvfsGetLogMessages(buf, size, false)) { - fwrite(buf, 1, strlen(buf), m_usvfs_log); - fwrite("\n", 1, 1, m_usvfs_log); - fflush(m_usvfs_log); - noLogCycles = 0; - } else - ++noLogCycles; - if (noLogCycles) - wait_for = std::chrono::milliseconds(std::min(40, noLogCycles) * 5); - else - wait_for = std::chrono::milliseconds(0); - } while (m_exit_future.wait_for(wait_for) == std::future_status::timeout); - - while (usvfsGetLogMessages(buf, size, false)) { - fwrite(buf, 1, strlen(buf), m_usvfs_log); - fwrite("\n", 1, 1, m_usvfs_log); - } - - fprintf(m_usvfs_log, "usvfs log closed.\n"); - m_usvfs_log.close(); - } - -private: - test::ScopedFILE m_usvfs_log; - std::thread m_log_thread; - std::promise<void> m_exit_signal; - std::shared_future<void> m_exit_future; -}; - -// mappings_reader - -class mappings_reader -{ -public: - using path = test::path; - using string = std::string; - using wstring = std::wstring; - using map_type = usvfs_connector::map_type; - using mapping = usvfs_connector::mapping; - using mappings_list = usvfs_connector::mappings_list; - - mappings_reader(const path& mount_base, const path& source_base) - : m_mount_base(mount_base), m_source_base(source_base) - {} - - mappings_list read(const path& mapfile) - { - const auto map = test::ScopedFILE::open(mapfile, L"rt"); - mappings_list mappings; - - char line[1024]; - while (!feof(map)) { - // read one line: - if (!fgets(line, _countof(line), map)) - if (feof(map)) - break; - else - throw_testWinFuncFailed("fgets", "reading mappings"); - - if (empty_line(line)) - continue; - - if (start_nesting(line, "mapdir")) - m_nesting = map_type::dir; - else if (start_nesting(line, "mapdircreate")) - m_nesting = map_type::dircreate; - else if (start_nesting(line, "mapfile")) - m_nesting = map_type::file; - else if (!isspace(*line)) // mapping sources should be indented and we already - // check all the mapping directives - throw test::FuncFailed("mappings_reader::read", "invalid mappings file line", - line); - else { - const auto& source_rel = trimmed_wide_string(line); - mappings.push_back(mapping(m_nesting, m_source_base / source_rel, m_mount)); - } - } - - return mappings; - } - - bool start_nesting(const char* line, const char* directive) - { - // check if line starts with directive and if so skip it: - auto dlen = strlen(directive); - auto after = line + dlen; - if (strncmp(directive, line, dlen) == 0 && (!*after || isspace(*after))) { - m_mount = m_mount_base; - const auto& mount_rel = trimmed_wide_string(after); - if (!mount_rel.empty()) - m_mount /= mount_rel; - return true; - } else - return false; - } - - static wstring trimmed_wide_string(const char* in) - { - while (std::isspace(*in)) - ++in; - auto end = in; - end += strlen(end); - while (end > in && std::isspace(*(end - 1))) - --end; - return usvfs::shared::string_cast<wstring>(string(in, end), - usvfs::shared::CodePage::UTF8); - } - - static bool empty_line(const char* line) - { - for (; *line; ++line) { - if (*line == '#') // comment, ignore rest of line - return true; - else if (!std::isspace(*line)) - return false; - } - return true; - } - -private: - path m_mount_base; - path m_source_base; - path m_mount; - map_type m_nesting = map_type::none; -}; - -// usvfs_test_base class: - -void usvfs_test_base::cleanup_temp() -{ - using namespace test; - using namespace winapi::ex::wide; - - bool isDir = false; - if (!m_o.temp_cleanup || !fileExists(m_o.temp.c_str(), &isDir)) - return; - - if (!isDir) { - if (m_o.force_temp_cleanup) - delete_file(m_o.temp); - else - throw FuncFailed("cleanup_temp", "temp exists but is a file", - m_o.temp.string().c_str()); - } else { - std::vector<wstring> cleanfiles; - std::vector<wstring> cleandirs; - std::vector<wstring> otherdirs; - bool output_file = false; - for (auto f : quickFindFiles(m_o.temp.c_str(), L"*")) - if (f.fileName == L"." || f.fileName == L"..") - continue; - else if ((f.attributes & FILE_ATTRIBUTE_DIRECTORY) == 0) { - if (f.fileName == m_o.output.filename()) - output_file = true; - cleanfiles.push_back(f.fileName); - } else if (f.fileName == SOURCE_DIR || f.fileName == MOUNT_DIR) - cleandirs.push_back(f.fileName); - else - otherdirs.push_back(f.fileName); - if (!cleanfiles.empty() || !cleandirs.empty() || !otherdirs.empty()) { - if (!m_o.force_temp_cleanup && !otherdirs.empty()) - throw FuncFailed("cleanup_temp", - "Refusing to clean temp dir with non-mount/source directories " - "(clean manually and rerun)", - m_o.temp.string().c_str()); - if (!m_o.force_temp_cleanup && cleandirs.empty() && !output_file) - throw FuncFailed("cleanup_temp", - "Refusing to clean temp dir with no directories and no output " - "log (clean manually and rerun)", - m_o.temp.string().c_str()); - std::wcout << "Cleaning previous temp dir: " << m_o.temp.c_str() << std::endl; - for (auto f : cleanfiles) - delete_file(m_o.temp / f); - for (auto d : cleandirs) - recursive_delete_files(m_o.temp / d); - for (auto d : otherdirs) - recursive_delete_files(m_o.temp / d); - } - } -} - -void usvfs_test_base::copy_fixture() -{ - using namespace test; - using namespace winapi::ex::wide; - - path fmount = m_o.fixture / MOUNT_DIR; - path fsource = m_o.fixture / SOURCE_DIR; - - bool isDir = false; - if (!fileExists(fmount.c_str(), &isDir) || !isDir) - throw FuncFailed("copy_fixture", "fixtures dir does not exist", - fmount.string().c_str()); - if (!fileExists(fsource.c_str(), &isDir) || !isDir) - throw FuncFailed("copy_fixture", "fixtures dir does not exist", - fsource.string().c_str()); - if (fileExists(m_o.mount.c_str(), &isDir)) - throw FuncFailed("copy_fixture", "source dir already exists", - m_o.mount.string().c_str()); - if (fileExists(m_o.source.c_str(), &isDir)) - throw FuncFailed("copy_fixture", "source dir already exists", - m_o.source.string().c_str()); - - std::wcout << "Copying fixture: " << m_o.fixture << std::endl; - recursive_copy_files(fmount, m_o.mount, false); - recursive_copy_files(fsource, m_o.source, false); -} - -bool usvfs_test_base::postmortem_check() -{ - path gold_output = m_o.fixture / m_o.output.filename(); - - { - const auto& log = output(); - - path mount_gold = MOUNT_DIR; - mount_gold += POSTMORTEM_SUFFIX; - path source_gold = SOURCE_DIR; - source_gold += POSTMORTEM_SUFFIX; - - bool is_dir = false; - if (!winapi::ex::wide::fileExists(m_o.mount.c_str(), &is_dir) || !is_dir) { - fprintf(log, " ERROR: mount directory does not exist?!\n"); - return false; - } - if (!winapi::ex::wide::fileExists(m_o.source.c_str(), &is_dir) || !is_dir) { - fprintf(log, " ERROR: source directory does not exist?!\n"); - return false; - } - if (!winapi::ex::wide::fileExists((m_o.fixture / mount_gold).c_str(), &is_dir) || - !is_dir) { - fprintf(log, " ERROR: fixtures golden mount does not exist: %s\n", - mount_gold.string().c_str()); - return false; - } - if (!winapi::ex::wide::fileExists((m_o.fixture / source_gold).c_str(), &is_dir) || - !is_dir) { - fprintf(log, " ERROR: fixtures golden source does not exist: %s\n", - mount_gold.string().c_str()); - return false; - } - if (!winapi::ex::wide::fileExists(gold_output.c_str(), &is_dir) || is_dir) { - fprintf(log, " ERROR: golden scenario output does not exist: %s\n", - gold_output.filename().string().c_str()); - return false; - } - - fprintf(log, "postmortem check of %s against golden %s...\n", - m_o.mount.filename().string().c_str(), mount_gold.string().c_str()); - bool mount_check = - recursive_compare_dirs(path(), m_o.fixture / mount_gold, m_o.mount, log); - - fprintf(log, "postmortem check of %s against golden %s...\n", - m_o.source.filename().string().c_str(), source_gold.string().c_str()); - bool source_check = - recursive_compare_dirs(path(), m_o.fixture / source_gold, m_o.source, log); - - if (mount_check && source_check) - fprintf(log, "postmortem check successful.\n"); - else { - fprintf(log, "ERROR: postmortem check failed!\n"); - return false; - } - } // close output before comparing it - - // don't print anything more to the output (except maybe errors), - // so that the final output can be copied as is to the fixtures (when updating the - // golden version) - - // block remove 2024/06/07 - one would need to regenerate a gold output for this but - // I am not sure this is still relevant - // - // if (!test::compare_files(gold_output, m_o.output, false)) { - // fprintf(output(), "ERROR: output does not match gold output: %s\n", - // m_o.output.filename().string().c_str()); return false; - //} - - return true; -} - -bool usvfs_test_base::recursive_compare_dirs(path rel_path, path gold_base, - path result_base, FILE* log) -{ - path result_full = result_base / rel_path; - path gold_full = gold_base / rel_path; - - std::unordered_set<std::wstring> gold_dirs; - std::unordered_set<std::wstring> gold_files; - for (const auto& f : winapi::ex::wide::quickFindFiles(gold_full.c_str(), L"*")) { - if (f.fileName == L"." || f.fileName == L"..") - continue; - if (f.attributes & FILE_ATTRIBUTE_DIRECTORY) - gold_dirs.insert(f.fileName); - else - gold_files.insert(f.fileName); - } - - bool all_good = true; - - std::vector<std::wstring> recurse; - for (const auto& f : winapi::ex::wide::quickFindFiles(result_full.c_str(), L"*")) { - if (f.fileName == L"." || f.fileName == L"..") - continue; - if (f.attributes & FILE_ATTRIBUTE_DIRECTORY) { - const auto& find = gold_dirs.find(f.fileName); - if (find != gold_dirs.end()) { - gold_dirs.erase(find); - recurse.push_back(f.fileName); - } else { - fprintf(log, " unexpected directory found: %s%s\n", MOUNT_LABEL, - (rel_path / f.fileName).string().c_str()); - all_good = false; - } - } else { - const auto& find = gold_files.find(f.fileName); - if (find != gold_files.end()) { - gold_files.erase(find); - if (!test::compare_files(gold_full / f.fileName, result_full / f.fileName, - false)) { - fprintf(log, " file contents differs: %s%s\n", MOUNT_LABEL, - (rel_path / f.fileName).string().c_str()); - all_good = false; - } - } else { - fprintf(log, " unexpected file found: %s%s\n", MOUNT_LABEL, - (rel_path / f.fileName).string().c_str()); - all_good = false; - } - } - } - - for (auto d : gold_dirs) { - fprintf(log, " expected directory not found: %s%s\n", MOUNT_LABEL, - (rel_path / d).string().c_str()); - all_good = false; - } - - for (auto f : gold_files) { - fprintf(log, " expected file not found: %s%s\n", MOUNT_LABEL, - (rel_path / f).string().c_str()); - all_good = false; - } - - for (auto r : recurse) - all_good &= recursive_compare_dirs(rel_path / r, gold_base, result_base, log); - - return all_good; -} - -test::ScopedFILE usvfs_test_base::output() -{ - auto log = test::ScopedFILE::open(m_o.output, m_clean_output ? L"wt" : L"at"); - m_clean_output = false; - return log; -} - -void usvfs_test_base::clean_output() -{ - using namespace std; - - errno_t err; - auto in = test::ScopedFILE::open(m_o.output, L"rt", err); - if (err == ENOENT) { - wcerr << L"warning: no " << m_o.output << L" to clean." << endl; - return; - } else if (err || !in) - throw_testWinFuncFailed("_wfopen_s", m_o.output.string().c_str(), err); - - path clean = m_o.output.parent_path() / m_o.output.stem(); - clean += OUTPUT_CLEAN_SUFFIX; - clean += m_o.output.extension(); - - auto out = test::ScopedFILE::open(clean, L"wt"); - wcout << L"Cleaning " << m_o.output << " to " << clean << endl; - - char line[1024]; - while (!feof(in)) { - // read one line: - if (!fgets(line, _countof(line), in)) - if (feof(in)) - break; - else - throw_testWinFuncFailed("fgets", "reading output"); - if (*line == '#') - continue; - - // in order for the clean output to compare cleanly between run with different - // options we clean out things like the platform and the ops log name (which - // contians the scenario label): - - char* platform = line; - while (platform) { - char* platform_x86 = strstr(platform, "x86"); - char* platform_x64 = strstr(platform, "x64"); - if (platform_x86 && platform_x64) - platform = std::min(platform_x86, platform_x64); - else if (platform_x86) - platform = platform_x86; - else if (platform_x64) - platform = platform_x64; - else - platform = nullptr; - if (platform) { - platform[1] = platform[2] = '?'; - platform += 3; - } - } - - char* cout_end = strstr(line, "-cout+ "); - char* cout_log_end = nullptr; - if (cout_end) { - cout_end += strlen("-cout+ "); - cout_log_end = strchr(cout_end, ' '); - } - if (cout_log_end && cout_log_end > cout_end) { - cout_end[0] = '?'; - if (cout_log_end > cout_end + 1) - memmove(cout_end + 1, cout_log_end, strlen(cout_log_end) + 1); - } - - fputs(line, out); - } -} - -int usvfs_test_base::run(const std::wstring& exe_name) -{ - using namespace usvfs::shared; - using namespace std; - - int res = run_impl(exe_name); - try { - clean_output(); - } catch (const exception& e) { - wcerr << "CERROR: " << string_cast<wstring>(e.what(), CodePage::UTF8).c_str() - << endl; - } catch (...) { - wcerr << "CERROR: unknown exception" << endl; - } - if (!res) - wcout << "scenario " << scenario_name() << " PASSED." << endl; - else - wcerr << "scenario " << scenario_name() << " FAILED!" << endl; - return res; -} - -int usvfs_test_base::run_impl(const std::wstring& exe_name) -{ - using namespace usvfs::shared; - using namespace std; - - try { - winapi::ex::wide::createPath(m_o.output.parent_path().c_str()); - - // we read mappings first only because it is "non-destructive" but might raise an - // error if mappings invalid - auto mappings = mappings_reader(m_o.mount, m_o.source).read(m_o.mapping); - - cleanup_temp(); - log_settings(exe_name); - copy_fixture(); - - usvfs_connector usvfs(m_o); - { - const auto& log = output(); - usvfs.updateMapping(mappings, m_o, log); - - fprintf(log, "running scenario %s:\n\n", scenario_name()); - } - auto res = scenario_run(); - { - const auto& log = output(); - if (res) - fprintf(log, "\nscenario ended successfully!\n\n"); - else - fprintf(log, "\nscenario failed miserably.\n"); - } - - if (!res) - return 7; - - if (!postmortem_check()) - return 8; - - return 0; - } -#if 1 // just a convient way to not catch exception when debugging - catch (const exception& e) { - try { - wcerr << "ERROR: " << string_cast<wstring>(e.what(), CodePage::UTF8).c_str() - << endl; - fprintf(output(), "ERROR: %s\n", e.what()); - } catch (const exception& e) { - wcerr << "ERROR^2: " << string_cast<wstring>(e.what(), CodePage::UTF8).c_str() - << endl; - } catch (...) { - wcerr << "ERROR^2: unknown exception" << endl; - } - } catch (...) { - try { - wcerr << "ERROR: unknown exception" << endl; - fprintf(output(), "ERROR: unknown exception\n"); - } catch (const exception& e) { - wcerr << "ERROR^2: " << string_cast<wstring>(e.what(), CodePage::UTF8).c_str() - << endl; - } catch (...) { - wcerr << "ERROR^2: unknown exception" << endl; - } - } -#else - catch (bool) { - } -#endif - return 9; // exception -} - -void usvfs_test_base::log_settings(const std::wstring& exe_name) -{ - using namespace usvfs::shared; - fprintf(output(), "%s %s started with %s%s%s\n\n", - string_cast<std::string>(exe_name).c_str(), scenario_name(), - m_o.opsexe.filename().string().c_str(), m_o.ops_options.empty() ? "" : " ", - string_cast<std::string>(m_o.ops_options).c_str()); -} - -void usvfs_test_base::ops_list(const path& rel_path, bool recursive, bool with_contents, - bool should_succeed, const wstring& additional_args) -{ - wstring cmd = recursive ? L"-r -list" : L"-list"; - if (with_contents) - cmd += L"contents"; - run_ops(should_succeed, cmd, rel_path, additional_args); -} - -void usvfs_test_base::ops_read(const path& rel_path, bool should_succeed, - const wstring& additional_args) -{ - run_ops(should_succeed, L"-read", rel_path, additional_args); -} - -void usvfs_test_base::ops_rewrite(const path& rel_path, const char* contents, - bool should_succeed, const wstring& additional_args) -{ - using namespace usvfs::shared; - run_ops(should_succeed, L"-rewrite", rel_path, additional_args, - L"\"" + string_cast<wstring>(contents, CodePage::UTF8) + L"\""); -} - -void usvfs_test_base::ops_overwrite(const path& rel_path, const char* contents, - bool recursive, bool should_succeed, - const wstring& additional_args) -{ - using namespace usvfs::shared; - run_ops(should_succeed, recursive ? L"-r -overwrite" : L"-overwrite", rel_path, - additional_args, - L"\"" + string_cast<wstring>(contents, CodePage::UTF8) + L"\""); -} - -void usvfs_test_base::ops_touch(const path& rel_path, bool full_write_access, - bool should_succeed, const wstring& additional_args) -{ - run_ops(should_succeed, full_write_access ? L"-touchw" : L"-touch", rel_path, - additional_args); -} - -void usvfs_test_base::ops_deleteoverwrite(const path& rel_path, const char* contents, - bool recursive, bool should_succeed, - const wstring& additional_args) -{ - using namespace usvfs::shared; - run_ops(should_succeed, recursive ? L"-r -deleteoverwrite" : L"-deleteoverwrite", - rel_path, additional_args, - L"\"" + string_cast<wstring>(contents, CodePage::UTF8) + L"\""); -} - -void usvfs_test_base::ops_delete(const path& rel_path, bool should_succeed, - const wstring& additional_args) -{ - run_ops(should_succeed, L"-delete", rel_path, additional_args); -} - -void usvfs_test_base::ops_copy(const path& src_rel_path, const path& dest_rel_path, - bool replace, bool should_succeed, - const wstring& additional_args) -{ - run_ops(should_succeed, replace ? L"-copyover" : L"-copy", src_rel_path, - additional_args, wstring(), dest_rel_path); -} - -void usvfs_test_base::ops_rename(const path& src_rel_path, const path& dest_rel_path, - bool replace, bool allow_copy, bool should_succeed, - const wstring& additional_args) -{ - wstring command = allow_copy ? L"-move" : L"-rename"; - if (replace) - command += L"over"; - run_ops(should_succeed, command, src_rel_path, additional_args, wstring(), - dest_rel_path); -} - -void usvfs_test_base::ops_deleterename(const path& src_rel_path, - const path& dest_rel_path, bool allow_copy, - bool should_succeed, - const wstring& additional_args) -{ - wstring command = allow_copy ? L"-deletemove" : L"-deleterename"; - run_ops(should_succeed, command, src_rel_path, additional_args, wstring(), - dest_rel_path); -} - -void usvfs_test_base::run_ops(bool should_succeed, const wstring& preargs, - const path& rel_path, const wstring& additional_args, - const wstring& postargs, const path& rel_path2) -{ - using namespace usvfs::shared; - using string = std::string; - using wstring = wstring; - - string commandlog = test::path(m_o.opsexe).filename().string(); - wstring commandline = m_o.opsexe; - if (commandline.find(' ') != wstring::npos && - commandline.find('"') == wstring::npos) { - commandline = L"\"" + commandline + L"\""; - commandlog = "\"" + commandlog + "\""; - } - - if (!m_o.mount.empty()) { - commandline += L" -basedir "; - commandline += m_o.mount; - commandlog += " -basedir "; - commandlog += m_o.mount.filename().string(); - } - - if (!m_o.ops_options.empty()) { - commandline += L" "; - commandline += m_o.ops_options; - commandlog += " "; - commandlog += string_cast<string>(m_o.ops_options, CodePage::UTF8); - } - - commandline += L" -cout+ "; - commandline += m_o.output; - commandlog += " -cout+ "; - commandlog += m_o.output.filename().string(); - - if (!additional_args.empty()) { - commandline += L" "; - commandline += additional_args; - commandlog += " "; - commandlog += string_cast<string>(additional_args, CodePage::UTF8); - } - - if (!preargs.empty()) { - commandline += L" "; - commandline += preargs; - commandlog += " "; - commandlog += string_cast<string>(preargs, CodePage::UTF8); - } - - if (!rel_path.empty()) { - commandline += L" "; - commandline += m_o.mount / rel_path; - commandlog += " "; - commandlog += MOUNT_LABEL + rel_path.string(); - } - - if (!rel_path2.empty()) { - commandline += L" "; - commandline += m_o.mount / rel_path2; - commandlog += " "; - commandlog += MOUNT_LABEL + rel_path2.string(); - } - - if (!postargs.empty()) { - commandline += L" "; - commandline += postargs; - commandlog += " "; - commandlog += string_cast<string>(postargs, CodePage::UTF8); - } - - fprintf(output(), "Spawning: %s\n", commandlog.c_str()); - auto res = usvfs_connector::spawn(&commandline[0]); - fprintf(output(), "\n"); - - bool success = res == 0; - if (success != should_succeed) - throw test::FuncFailed("run_ops", success ? "succeeded" : "failed", - commandlog.c_str(), res); -} - -std::string usvfs_test_base::mount_contents(const path& rel_path) -{ - verify_mount_existance(rel_path); - const auto& contents = test::read_small_file(m_o.mount / rel_path); - return std::string(contents.data(), contents.size()); -} - -std::string usvfs_test_base::source_contents(const path& rel_path) -{ - verify_source_existance(rel_path); - const auto& contents = test::read_small_file(m_o.source / rel_path); - return std::string(contents.data(), contents.size()); -} - -void usvfs_test_base::verify_mount_contents(const path& rel_path, const char* contents) -{ - verify_mount_existance(rel_path); - if (verify_contents(m_o.mount / rel_path, contents)) - throw test::FuncFailed("verify_mount_contents", - (MOUNT_LABEL + rel_path.string()).c_str(), contents); -} - -void usvfs_test_base::verify_source_contents(const path& rel_path, const char* contents) -{ - verify_source_existance(rel_path); - if (verify_contents(m_o.source / rel_path, contents)) - throw test::FuncFailed("verify_source_contents", - (SOURCE_LABEL + rel_path.string()).c_str(), contents); -} - -bool usvfs_test_base::verify_contents(const path& file, const char* contents) -{ - // we allow difference in trailing whitespace (i.e. extra new line): - - size_t sz = strlen(contents); - while (sz && isspace(contents[sz - 1])) - --sz; - - const auto& real_contents = test::read_small_file(file); - size_t real_sz = real_contents.size(); - while (real_sz && isspace(real_contents[real_sz - 1])) - --real_sz; - - return sz == real_sz && memcmp(contents, real_contents.data(), sz); -} - -void usvfs_test_base::verify_mount_existance(const path& rel_path, bool exists, - bool is_dir) -{ - bool real_is_dir = false; - bool real_exists = - winapi::ex::wide::fileExists((m_o.mount / rel_path).c_str(), &real_is_dir); - if (exists != real_exists) - throw test::FuncFailed("verify_mount_existance", - real_exists ? "path exists" : "path does not exist", - (MOUNT_LABEL + rel_path.string()).c_str()); - else if (real_exists && is_dir != real_is_dir) - throw test::FuncFailed("verify_mount_existance", - real_is_dir ? "path is a directory" : "path is a file", - (MOUNT_LABEL + rel_path.string()).c_str()); -} - -void usvfs_test_base::verify_source_existance(const path& rel_path, bool exists, - bool is_dir) -{ - bool real_is_dir = false; - bool real_exists = - winapi::ex::wide::fileExists((m_o.source / rel_path).c_str(), &real_is_dir); - if (exists != real_exists) - throw test::FuncFailed("verify_source_existance", - real_exists ? "path exists" : "path does not exist", - (SOURCE_LABEL + rel_path.string()).c_str()); - else if (real_exists && is_dir != real_is_dir) - throw test::FuncFailed("verify_source_existance", - real_is_dir ? "path is a directory" : "path is a file", - (SOURCE_LABEL + rel_path.string()).c_str()); -} diff --git a/libs/usvfs/test/usvfs_test_runner/usvfs_test/usvfs_test_base.h b/libs/usvfs/test/usvfs_test_runner/usvfs_test/usvfs_test_base.h deleted file mode 100644 index 4986e3b..0000000 --- a/libs/usvfs/test/usvfs_test_runner/usvfs_test/usvfs_test_base.h +++ /dev/null @@ -1,120 +0,0 @@ -#pragma once - -#include <string> - -#include <test_helpers.h> - -class usvfs_test_options -{ -public: - static constexpr auto DEFAULT_MAPPING = L"vfs_mappings.txt"; - static constexpr auto MOUNT_DIR = L"mount"; - static constexpr auto SOURCE_DIR = L"source"; - - using path = test::path; - - // fills any values not set (or set to an empty value) to their default value - void fill_defaults(const path& test_name, const std::wstring& scenario, - const wchar_t* label); - - void set_ops32(); // sets opsexe iff opsexe is empty - void set_ops64(); // sets opsexe iff opsexe is empty - void add_ops_options(const std::wstring& options); - - path opsexe; - path fixture; - path mapping; - path temp; - path mount; - path source; - path output; - path usvfs_log; - std::wstring ops_options; - bool temp_cleanup = false; - bool force_temp_cleanup = false; -}; - -class usvfs_test_base -{ -public: - static constexpr auto MOUNT_DIR = usvfs_test_options::MOUNT_DIR; - static constexpr auto SOURCE_DIR = usvfs_test_options::SOURCE_DIR; - static constexpr auto MOUNT_LABEL = "mount:"; - static constexpr auto SOURCE_LABEL = "source:"; - static constexpr auto OUTPUT_CLEAN_SUFFIX = L"_clean"; - static constexpr auto POSTMORTEM_SUFFIX = L".postmortem"; - - using wstring = std::wstring; - using path = test::path; - - // options object should outlive this object. - usvfs_test_base(const usvfs_test_options& options) : m_o(options) {} - virtual ~usvfs_test_base() = default; - - int run(const std::wstring& exe_name); - - // function for override: - - virtual const char* scenario_name() = 0; - virtual bool scenario_run() = 0; - - // helpers for derived scenarios: - - virtual void ops_list(const path& rel_path, bool recursive, bool with_contents, - bool should_succeed = true, - const wstring& additional_args = wstring()); - virtual void ops_read(const path& rel_path, bool should_succeed = true, - const wstring& additional_args = wstring()); - virtual void ops_rewrite(const path& rel_path, const char* contents, - bool should_succeed = true, - const wstring& additional_args = wstring()); - virtual void ops_overwrite(const path& rel_path, const char* contents, bool recursive, - bool should_succeed = true, - const wstring& additional_args = wstring()); - virtual void ops_touch(const path& rel_path, bool full_write_access = false, - bool should_succeed = true, - const wstring& additional_args = wstring()); - virtual void ops_deleteoverwrite(const path& rel_path, const char* contents, - bool recursive, bool should_succeed = true, - const wstring& additional_args = wstring()); - virtual void ops_delete(const path& rel_path, bool should_succeed = true, - const wstring& additional_args = wstring()); - virtual void ops_copy(const path& src_rel_path, const path& dest_rel_path, - bool replace, bool should_succeed = true, - const wstring& additional_args = wstring()); - virtual void ops_rename(const path& src_rel_path, const path& dest_rel_path, - bool replace, bool allow_copy = false, - bool should_succeed = true, - const wstring& additional_args = wstring()); - virtual void ops_deleterename(const path& src_rel_path, const path& dest_rel_path, - bool allow_copy = false, bool should_succeed = true, - const wstring& additional_args = wstring()); - - virtual std::string mount_contents(const path& rel_path); - virtual void verify_mount_contents(const path& rel_path, const char* contents); - virtual void verify_mount_existance(const path& rel_path, bool exists = true, - bool is_dir = false); - virtual std::string source_contents(const path& rel_path); - virtual void verify_source_contents(const path& rel_path, const char* contents); - virtual void verify_source_existance(const path& rel_path, bool exists = true, - bool is_dir = false); - -private: - int run_impl(const std::wstring& exe_name); - void log_settings(const std::wstring& exe_name); - void cleanup_temp(); - void copy_fixture(); - bool postmortem_check(); - bool recursive_compare_dirs(path rel_path, path gold_base, path result_base, - FILE* log); - void clean_output(); - - test::ScopedFILE output(); - void run_ops(bool should_succeed, const wstring& preargs, const path& rel_path, - const wstring& additional_args, const wstring& postargs = wstring(), - const path& rel_path2 = path()); - bool verify_contents(const path& file, const char* contents); - - const usvfs_test_options& m_o; - bool m_clean_output = true; -}; diff --git a/libs/usvfs/test/usvfs_test_runner/usvfs_test_runner.cpp b/libs/usvfs/test/usvfs_test_runner/usvfs_test_runner.cpp deleted file mode 100644 index a70fb0f..0000000 --- a/libs/usvfs/test/usvfs_test_runner/usvfs_test_runner.cpp +++ /dev/null @@ -1,105 +0,0 @@ -#include <gtest/gtest.h> - -#include <boost/filesystem.hpp> -#include <iostream> -#include <test_helpers.h> -#include <windows_sane.h> - -static std::string usvfs_test_command(const char* scenario, const char* platform, - const char* testflag = nullptr, - const char* opsarg = nullptr) -{ - using namespace test; - std::string command = - path_of_test_bin(platform_dependant_executable("usvfs_test", "exe", platform)) - .string(); - if (testflag) { - command += " -"; - command += testflag; - } - if (opsarg) { - command += " -opsarg -"; - command += opsarg; - } - command += " "; - command += scenario; - if (testflag || opsarg) { - command += ":"; - if (testflag) { - command += testflag; - command += "_"; - } - if (opsarg) { - command += opsarg; - command += "_"; - } - command += platform; - } - return command; -} - -static DWORD spawn(std::string commandline) -{ - STARTUPINFOA si{0}; - si.cb = sizeof(si); - PROCESS_INFORMATION pi{0}; - - std::cout << "Running: [" << commandline << "]" << std::endl; - if (!CreateProcessA(NULL, commandline.data(), NULL, NULL, FALSE, 0, NULL, NULL, &si, - &pi)) { - DWORD gle = GetLastError(); - std::cerr << "CreateProcess failed error=" << gle << std::endl; - return 98; - } - - WaitForSingleObject(pi.hProcess, INFINITE); - - DWORD exit = 99; - if (!GetExitCodeProcess(pi.hProcess, &exit)) { - DWORD gle = GetLastError(); - std::cerr << "GetExitCodeProcess failed error=" << gle << std::endl; - } - - CloseHandle(pi.hProcess); - CloseHandle(pi.hThread); - - return exit; -} - -TEST(UsvfsTest, basic_x64) -{ - EXPECT_EQ(0, spawn(usvfs_test_command("basic", "x64"))); -} - -TEST(UsvfsTest, basic_x86) -{ - EXPECT_EQ(0, spawn(usvfs_test_command("basic", "x86"))); -} - -TEST(UsvfsTest, basic_ops32_x64) -{ - EXPECT_EQ(0, spawn(usvfs_test_command("basic", "x64", "ops32"))); -} - -TEST(UsvfsTest, basic_ops64_x86) -{ - EXPECT_EQ(0, spawn(usvfs_test_command("basic", "x86", "ops64"))); -} - -/* -TEST(UsvfsTest, basic_ntapi_x64) -{ - EXPECT_EQ(0, spawn(usvfs_test_command("basic", "x64", nullptr, "ntapi"))); -} - -TEST(UsvfsTest, basic_ntapi_x86) -{ - EXPECT_EQ(0, spawn(usvfs_test_command("basic", "x86", nullptr, "ntapi"))); -} -*/ - -int main(int argc, char** argv) -{ - testing::InitGoogleTest(&argc, argv); - return RUN_ALL_TESTS(); -} |
