aboutsummaryrefslogtreecommitdiff
path: root/libs/usvfs/test/usvfs_global_test_runner
diff options
context:
space:
mode:
Diffstat (limited to 'libs/usvfs/test/usvfs_global_test_runner')
-rw-r--r--libs/usvfs/test/usvfs_global_test_runner/CMakeLists.txt23
-rw-r--r--libs/usvfs/test/usvfs_global_test_runner/usvfs_global_test/usvfs_global_test.cpp216
-rw-r--r--libs/usvfs/test/usvfs_global_test_runner/usvfs_global_test_fixture.cpp205
-rw-r--r--libs/usvfs/test/usvfs_global_test_runner/usvfs_global_test_fixture.h82
-rw-r--r--libs/usvfs/test/usvfs_global_test_runner/usvfs_global_test_runner.cpp58
5 files changed, 0 insertions, 584 deletions
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();
-}