From 7ee008e150bc5bcf76082d726f719ee0fdfda982 Mon Sep 17 00:00:00 2001 From: SulfurNitride Date: Wed, 11 Feb 2026 02:37:39 -0600 Subject: Fluorine Manager: full Linux port of Mod Organizer 2 Complete native Linux port with FUSE-based virtual filesystem, Proton/umu-run integration, and Flatpak packaging. Key features: - FUSE VFS replacing Windows USVFS (in-process + standalone helper for Flatpak) - Proton/GE-Proton/umu-run launcher with env var forwarding - Flatpak support (sandbox-aware VFS, NXM handler, umu-run) - Wine prefix management UI - Case-insensitive path resolution for Linux filesystems - QSettings-safe INI handling (avoids Bethesda INI corruption) - Portable instance support with auto-generated launcher scripts Co-Authored-By: Claude Opus 4.6 --- libs/usvfs/test/test_utils/test_helpers.h | 165 ++++++++++++++++++++++++++++++ 1 file changed, 165 insertions(+) create mode 100644 libs/usvfs/test/test_utils/test_helpers.h (limited to 'libs/usvfs/test/test_utils/test_helpers.h') diff --git a/libs/usvfs/test/test_utils/test_helpers.h b/libs/usvfs/test/test_utils/test_helpers.h new file mode 100644 index 0000000..7ea8950 --- /dev/null +++ b/libs/usvfs/test/test_utils/test_helpers.h @@ -0,0 +1,165 @@ +#pragma once + +#include "windows_sane.h" + +#include +#include +#include + +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 func) + { + return WinFuncFailed(std::format("{} failed : lastError={}", func, m_gle)); + } + + WinFuncFailed operator()(std::basic_string_view 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 arg1) + { + return WinFuncFailed( + std::format("{} failed : {}, lastError={}", func, arg1, m_gle)); + } + + WinFuncFailed operator()(std::string_view func, std::basic_string_view 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 +[[noreturn]] void throw_testWinFuncFailed(std::string_view func, Args&&... args) +{ + ::test::WinFuncFailedGenerator exceptionGenerator; + throw exceptionGenerator(func, std::forward(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(m_f); } + operator FILE*() const { return m_f.get(); } + +private: + std::unique_ptr 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 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 -- cgit v1.3.1