test(windows): build and run the test suite for Windows from WSL
scripts/test-windows.sh cross-compiles ObsidianDragonTests.exe (and the fake_dragonxd stub) with mingw into build/windows-tests, reusing the toolchain and dependency sources from build/windows, and runs it from WSL through Windows interop (or wine). All tests pass on Windows. CMake: - Windows forced BUILD_TESTING OFF in the cache to keep curl's tests out, which also removed ObsidianDragonTests from every Windows build. Hide it from curl with a scoped variable instead, and restore our cache value afterwards (curl's cmake_dependent_option FORCE-writes it). Windows still defaults to OFF, so release builds are unchanged. - ObsidianDragonTests now depends on copy_langs: i18n.cpp includes the generated embedded/lang_*.h, so a tree that builds only the tests failed (latent on Linux too). - Link the Windows system libraries the tests need. Tests: - testTmpPath/fixtureDir/removeTree helpers: no hard-coded /tmp, a runtime fixture-dir override (the compiled-in path is a Linux one), and best-effort cleanup that can't abort the suite. - Close the explorer cache before deleting its directory (Windows can't delete an open file). - Compile out the address-book and wallet-index round-trips on Windows: getConfigDir() uses SHGetFolderPath there, which no environment variable redirects, so they would overwrite the real %APPDATA%\ObsidianDragon files. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
+19
-1
@@ -155,6 +155,11 @@ if(DRAGONX_ENABLE_LITE_BACKEND)
|
|||||||
set(DRAGONX_LITE_BACKEND_READY ON)
|
set(DRAGONX_LITE_BACKEND_READY ON)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
# Windows (mingw cross) builds skip the large test target unless asked for with -DBUILD_TESTING=ON
|
||||||
|
# (scripts/test-windows.sh does that in its own build/windows-tests tree), so release builds are unchanged.
|
||||||
|
if(WIN32 AND NOT DEFINED BUILD_TESTING)
|
||||||
|
set(BUILD_TESTING OFF CACHE BOOL "Build the testing tree.")
|
||||||
|
endif()
|
||||||
include(CTest)
|
include(CTest)
|
||||||
|
|
||||||
# Output directories
|
# Output directories
|
||||||
@@ -266,7 +271,11 @@ if(WIN32)
|
|||||||
set(BUILD_CURL_EXE OFF CACHE BOOL "" FORCE)
|
set(BUILD_CURL_EXE OFF CACHE BOOL "" FORCE)
|
||||||
set(BUILD_SHARED_LIBS OFF CACHE BOOL "" FORCE)
|
set(BUILD_SHARED_LIBS OFF CACHE BOOL "" FORCE)
|
||||||
set(CURL_STATICLIB ON CACHE BOOL "" FORCE)
|
set(CURL_STATICLIB ON CACHE BOOL "" FORCE)
|
||||||
set(BUILD_TESTING OFF CACHE BOOL "" FORCE)
|
# Keep curl's own tests out, without switching off ObsidianDragonTests for every Windows build:
|
||||||
|
# hide BUILD_TESTING behind a normal variable while curl configures, then restore our cache value
|
||||||
|
# (curl's cmake_dependent_option(BUILD_TESTING ...) FORCE-writes the OFF it saw into the cache).
|
||||||
|
set(_dragonx_build_testing "${BUILD_TESTING}")
|
||||||
|
set(BUILD_TESTING OFF)
|
||||||
set(CURL_DISABLE_LDAP ON CACHE BOOL "" FORCE)
|
set(CURL_DISABLE_LDAP ON CACHE BOOL "" FORCE)
|
||||||
set(CURL_DISABLE_LDAPS ON CACHE BOOL "" FORCE)
|
set(CURL_DISABLE_LDAPS ON CACHE BOOL "" FORCE)
|
||||||
set(CURL_USE_SCHANNEL ON CACHE BOOL "" FORCE) # Use Windows native SSL
|
set(CURL_USE_SCHANNEL ON CACHE BOOL "" FORCE) # Use Windows native SSL
|
||||||
@@ -275,6 +284,8 @@ if(WIN32)
|
|||||||
set(CURL_ZLIB OFF CACHE BOOL "" FORCE)
|
set(CURL_ZLIB OFF CACHE BOOL "" FORCE)
|
||||||
set(HTTP_ONLY ON CACHE BOOL "" FORCE)
|
set(HTTP_ONLY ON CACHE BOOL "" FORCE)
|
||||||
FetchContent_MakeAvailable(curl)
|
FetchContent_MakeAvailable(curl)
|
||||||
|
unset(BUILD_TESTING)
|
||||||
|
set(BUILD_TESTING "${_dragonx_build_testing}" CACHE BOOL "Build the testing tree." FORCE)
|
||||||
set(CURL_LIBRARIES libcurl_static)
|
set(CURL_LIBRARIES libcurl_static)
|
||||||
set(CURL_INCLUDE_DIRS ${curl_SOURCE_DIR}/include ${curl_BINARY_DIR}/lib/curl)
|
set(CURL_INCLUDE_DIRS ${curl_SOURCE_DIR}/include ${curl_BINARY_DIR}/lib/curl)
|
||||||
else()
|
else()
|
||||||
@@ -1233,6 +1244,13 @@ if(BUILD_TESTING)
|
|||||||
if(UNIX)
|
if(UNIX)
|
||||||
target_link_libraries(ObsidianDragonTests PRIVATE ${CMAKE_DL_LIBS})
|
target_link_libraries(ObsidianDragonTests PRIVATE ${CMAKE_DL_LIBS})
|
||||||
endif()
|
endif()
|
||||||
|
if(WIN32)
|
||||||
|
target_link_libraries(ObsidianDragonTests PRIVATE ws2_32 crypt32 wldap32 psapi iphlpapi shell32 ole32 advapi32 bcrypt)
|
||||||
|
endif()
|
||||||
|
# i18n.cpp includes the generated embedded/lang_*.h headers; a tree that builds only this target needs them too.
|
||||||
|
if(TARGET copy_langs)
|
||||||
|
add_dependencies(ObsidianDragonTests copy_langs)
|
||||||
|
endif()
|
||||||
|
|
||||||
add_test(NAME ObsidianDragonPhase4Tests COMMAND ObsidianDragonTests)
|
add_test(NAME ObsidianDragonPhase4Tests COMMAND ObsidianDragonTests)
|
||||||
endif()
|
endif()
|
||||||
|
|||||||
Executable
+76
@@ -0,0 +1,76 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# Cross-compile the test suite (ObsidianDragonTests.exe) and the fake daemon (tools/fake_dragonxd)
|
||||||
|
# for Windows with mingw-w64, then run the tests: directly under WSL (Windows interop), else with
|
||||||
|
# wine if installed, else just build.
|
||||||
|
#
|
||||||
|
# scripts/test-windows.sh [--no-run] [--jobs N]
|
||||||
|
#
|
||||||
|
# Uses its own build/windows-tests tree (full-node config), so build/windows is left alone. Needs
|
||||||
|
# the mingw toolchain file that ./build.sh --win-release writes to build/windows/. Dependency sources
|
||||||
|
# already fetched into build/windows/_deps are reused, so nothing is downloaded twice.
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
repo="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||||
|
bd="$repo/build/windows-tests"
|
||||||
|
toolchain="$repo/build/windows/mingw-toolchain.cmake"
|
||||||
|
deps="$repo/build/windows/_deps"
|
||||||
|
run=true
|
||||||
|
jobs=8 # each test TU is large; several parallel mingw builds can exhaust RAM
|
||||||
|
|
||||||
|
while [[ $# -gt 0 ]]; do
|
||||||
|
case "$1" in
|
||||||
|
--no-run) run=false; shift ;;
|
||||||
|
--jobs) jobs="$2"; shift 2 ;;
|
||||||
|
-h|--help) sed -n '2,10p' "$0" | sed 's/^# \{0,1\}//'; exit 0 ;;
|
||||||
|
*) echo "unknown option: $1" >&2; exit 2 ;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
|
||||||
|
if [[ ! -f "$toolchain" ]]; then
|
||||||
|
echo "missing $toolchain; run ./build.sh --win-release once to create the mingw toolchain" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
src_args=()
|
||||||
|
for dep in sdl3 json tomlplusplus sqlite3 curl libwebp; do
|
||||||
|
if [[ -d "$deps/$dep-src" ]]; then
|
||||||
|
src_args+=("-DFETCHCONTENT_SOURCE_DIR_${dep^^}=$deps/$dep-src")
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
cmake -S "$repo" -B "$bd" \
|
||||||
|
-DCMAKE_TOOLCHAIN_FILE="$toolchain" \
|
||||||
|
-DCMAKE_BUILD_TYPE=Release \
|
||||||
|
-DDRAGONX_USE_SYSTEM_SDL3=OFF \
|
||||||
|
-DDRAGONX_BUILD_LITE=OFF \
|
||||||
|
-DDRAGONX_ENABLE_LITE_BACKEND=OFF \
|
||||||
|
-DBUILD_TESTING=ON \
|
||||||
|
-DDRAGONX_BUILD_FAKE_DAEMON=ON \
|
||||||
|
"${src_args[@]}"
|
||||||
|
cmake --build "$bd" --target ObsidianDragonTests fake_dragonxd -j "$jobs"
|
||||||
|
|
||||||
|
exe="$bd/bin/ObsidianDragonTests.exe"
|
||||||
|
echo "built: $exe"
|
||||||
|
echo "built: $bd/fake_dragonxd/dragonxd.exe"
|
||||||
|
$run || exit 0
|
||||||
|
|
||||||
|
# The fixture path compiled into the binary is a Linux path; hand the Windows process its own.
|
||||||
|
# APPDATA/LOCALAPPDATA point at a sandbox so anything resolving them from the environment stays out
|
||||||
|
# of the real profile. (SHGetFolderPath-based paths ignore the environment; the tests that would
|
||||||
|
# write through those are compiled out on Windows.)
|
||||||
|
export DRAGONX_TEST_FIXTURE_DIR="$repo/tests/fixtures"
|
||||||
|
sandbox="$bd/test-appdata"
|
||||||
|
mkdir -p "$sandbox"
|
||||||
|
export APPDATA="$sandbox" LOCALAPPDATA="$sandbox"
|
||||||
|
if grep -qi microsoft /proc/version 2>/dev/null && [[ -e /proc/sys/fs/binfmt_misc/WSLInterop ]]; then
|
||||||
|
# /p: translate each to a Windows path for the Windows process
|
||||||
|
export WSLENV="${WSLENV:+$WSLENV:}DRAGONX_TEST_FIXTURE_DIR/p:APPDATA/p:LOCALAPPDATA/p"
|
||||||
|
cd "$bd/bin"
|
||||||
|
exec "$exe"
|
||||||
|
elif command -v wine >/dev/null 2>&1; then
|
||||||
|
export DRAGONX_TEST_FIXTURE_DIR="$(winepath -w "$DRAGONX_TEST_FIXTURE_DIR")"
|
||||||
|
cd "$bd/bin"
|
||||||
|
exec wine "$exe"
|
||||||
|
else
|
||||||
|
echo "not on WSL and no wine: copy $exe (and tests/fixtures) to Windows to run it" >&2
|
||||||
|
fi
|
||||||
+54
-18
@@ -126,6 +126,29 @@ fs::path makeTempDir()
|
|||||||
return dir;
|
return dir;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Best-effort cleanup. Windows can't delete a file that is still open, and the throwing remove_all
|
||||||
|
// would abort the whole suite over a leftover temp file.
|
||||||
|
void removeTree(const fs::path& path)
|
||||||
|
{
|
||||||
|
std::error_code ec;
|
||||||
|
fs::remove_all(path, ec);
|
||||||
|
}
|
||||||
|
|
||||||
|
// A named path under the platform temp dir (/tmp on Linux, %TEMP% on Windows, where "/tmp/..."
|
||||||
|
// would mean C:\tmp).
|
||||||
|
fs::path testTmpPath(const std::string& name)
|
||||||
|
{
|
||||||
|
return fs::temp_directory_path() / name;
|
||||||
|
}
|
||||||
|
|
||||||
|
// The fixture root: compiled in, unless DRAGONX_TEST_FIXTURE_DIR is set at runtime. The Windows
|
||||||
|
// build runs from WSL (scripts/test-windows.sh), where the compiled-in Linux path doesn't resolve.
|
||||||
|
std::string fixtureDir()
|
||||||
|
{
|
||||||
|
const char* env = std::getenv("DRAGONX_TEST_FIXTURE_DIR");
|
||||||
|
return (env && *env) ? std::string(env) : std::string(DRAGONX_TEST_FIXTURE_DIR);
|
||||||
|
}
|
||||||
|
|
||||||
void writeTestFile(const fs::path& path, const std::string& content)
|
void writeTestFile(const fs::path& path, const std::string& content)
|
||||||
{
|
{
|
||||||
std::ofstream output(path, std::ios::binary);
|
std::ofstream output(path, std::ios::binary);
|
||||||
@@ -723,7 +746,7 @@ void testConnectionConfig()
|
|||||||
EXPECT_EQ(cookieConfig.auth_source, AuthSource::Cookie);
|
EXPECT_EQ(cookieConfig.auth_source, AuthSource::Cookie);
|
||||||
EXPECT_TRUE(cookieConfig.use_tls);
|
EXPECT_TRUE(cookieConfig.use_tls);
|
||||||
|
|
||||||
fs::remove_all(dir);
|
removeTree(dir);
|
||||||
}
|
}
|
||||||
|
|
||||||
void testPaymentUri()
|
void testPaymentUri()
|
||||||
@@ -763,7 +786,7 @@ void testWalletFileProbe()
|
|||||||
{
|
{
|
||||||
namespace fs = std::filesystem;
|
namespace fs = std::filesystem;
|
||||||
using dragonx::util::probeWalletFile;
|
using dragonx::util::probeWalletFile;
|
||||||
const fs::path dir = fs::path("/tmp/dragonx") / "probe";
|
const fs::path dir = testTmpPath("dragonx") / "probe";
|
||||||
std::error_code ec; fs::create_directories(dir, ec);
|
std::error_code ec; fs::create_directories(dir, ec);
|
||||||
auto writef = [](const fs::path& p, const std::string& d) {
|
auto writef = [](const fs::path& p, const std::string& d) {
|
||||||
std::ofstream o(p, std::ios::binary); o.write(d.data(), (std::streamsize)d.size());
|
std::ofstream o(p, std::ios::binary); o.write(d.data(), (std::streamsize)d.size());
|
||||||
@@ -3292,7 +3315,7 @@ void testDaemonLifecycleAdapters()
|
|||||||
EXPECT_FALSE(fs::exists(dataDir / "peers.dat"));
|
EXPECT_FALSE(fs::exists(dataDir / "peers.dat"));
|
||||||
EXPECT_FALSE(fs::exists(dataDir / "fee_estimates.dat"));
|
EXPECT_FALSE(fs::exists(dataDir / "fee_estimates.dat"));
|
||||||
EXPECT_TRUE(fs::exists(dataDir / "wallet.dat"));
|
EXPECT_TRUE(fs::exists(dataDir / "wallet.dat"));
|
||||||
fs::remove_all(dataDir);
|
removeTree(dataDir);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Pure console wrap layout / hit-test / selection (console_text_layout.h), driven by a
|
// Pure console wrap layout / hit-test / selection (console_text_layout.h), driven by a
|
||||||
@@ -4189,7 +4212,8 @@ void testExplorerBlockCache()
|
|||||||
file << legacy.dump(2);
|
file << legacy.dump(2);
|
||||||
}
|
}
|
||||||
|
|
||||||
ExplorerBlockCache cache(databasePath.string(), legacyPath.string());
|
auto cacheOwner = std::make_unique<ExplorerBlockCache>(databasePath.string(), legacyPath.string());
|
||||||
|
ExplorerBlockCache& cache = *cacheOwner;
|
||||||
EXPECT_TRUE(cache.ensureOpen());
|
EXPECT_TRUE(cache.ensureOpen());
|
||||||
EXPECT_EQ(cache.cachedBlockCount(), 2);
|
EXPECT_EQ(cache.cachedBlockCount(), 2);
|
||||||
|
|
||||||
@@ -4234,7 +4258,8 @@ void testExplorerBlockCache()
|
|||||||
EXPECT_EQ(reopened.cachedBlockCount(), 0);
|
EXPECT_EQ(reopened.cachedBlockCount(), 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
fs::remove_all(dir);
|
cacheOwner.reset(); // close the database first: Windows can't delete an open file
|
||||||
|
removeTree(dir);
|
||||||
}
|
}
|
||||||
|
|
||||||
void testTransactionHistoryCache()
|
void testTransactionHistoryCache()
|
||||||
@@ -4345,7 +4370,7 @@ void testTransactionHistoryCache()
|
|||||||
EXPECT_EQ(cache.snapshotCount(), 0);
|
EXPECT_EQ(cache.snapshotCount(), 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
fs::remove_all(dir);
|
removeTree(dir);
|
||||||
}
|
}
|
||||||
|
|
||||||
// GC: generating a new address changes the wallet-identity hash; the prior hash's snapshot
|
// GC: generating a new address changes the wallet-identity hash; the prior hash's snapshot
|
||||||
@@ -4377,7 +4402,7 @@ void testTransactionHistoryCachePrunesOldWallets()
|
|||||||
auto loadedB = cache.load(idB, 100, "tip-b");
|
auto loadedB = cache.load(idB, 100, "tip-b");
|
||||||
EXPECT_TRUE(loadedB.loaded);
|
EXPECT_TRUE(loadedB.loaded);
|
||||||
|
|
||||||
fs::remove_all(dir);
|
removeTree(dir);
|
||||||
}
|
}
|
||||||
|
|
||||||
void testTransactionHistoryCacheRefreshApply()
|
void testTransactionHistoryCacheRefreshApply()
|
||||||
@@ -4443,7 +4468,7 @@ void testTransactionHistoryCacheRefreshApply()
|
|||||||
EXPECT_EQ(lastTxBlock, 333);
|
EXPECT_EQ(lastTxBlock, 333);
|
||||||
EXPECT_EQ(confirmedIds.count("rpc-refreshed-send"), static_cast<size_t>(1));
|
EXPECT_EQ(confirmedIds.count("rpc-refreshed-send"), static_cast<size_t>(1));
|
||||||
|
|
||||||
fs::remove_all(dir);
|
removeTree(dir);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -4753,7 +4778,7 @@ void testGeneratedResourceBehavior()
|
|||||||
EXPECT_TRUE(dragonx::resources::getEmbeddedResource("__missing_resource__") == nullptr);
|
EXPECT_TRUE(dragonx::resources::getEmbeddedResource("__missing_resource__") == nullptr);
|
||||||
if (!dragonx::resources::hasEmbeddedResources()) {
|
if (!dragonx::resources::hasEmbeddedResources()) {
|
||||||
EXPECT_TRUE(themes[0].data == nullptr);
|
EXPECT_TRUE(themes[0].data == nullptr);
|
||||||
EXPECT_EQ(dragonx::resources::extractBundledThemes("/tmp/obsidian-dragon-empty-themes"), 0);
|
EXPECT_EQ(dragonx::resources::extractBundledThemes(testTmpPath("obsidian-dragon-empty-themes").string()), 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -6030,7 +6055,7 @@ void testLiteRolloutManifestLoader()
|
|||||||
{
|
{
|
||||||
using namespace dragonx::wallet;
|
using namespace dragonx::wallet;
|
||||||
// Missing file -> not present -> fail-open allowed.
|
// Missing file -> not present -> fail-open allowed.
|
||||||
auto missing = loadLiteRolloutManifestFromFile("/tmp/obsidian-rollout-missing-xyz.json");
|
auto missing = loadLiteRolloutManifestFromFile(testTmpPath("obsidian-rollout-missing-xyz.json").string());
|
||||||
EXPECT_FALSE(missing.present);
|
EXPECT_FALSE(missing.present);
|
||||||
{
|
{
|
||||||
LiteRolloutInputs in; in.appVersion = "1.2.0"; in.manifest = missing;
|
LiteRolloutInputs in; in.appVersion = "1.2.0"; in.manifest = missing;
|
||||||
@@ -6038,7 +6063,7 @@ void testLiteRolloutManifestLoader()
|
|||||||
}
|
}
|
||||||
|
|
||||||
// A valid manifest file parses into the expected fields.
|
// A valid manifest file parses into the expected fields.
|
||||||
const std::string path = "/tmp/obsidian-rollout-test.json";
|
const std::string path = testTmpPath("obsidian-rollout-test.json").string();
|
||||||
{
|
{
|
||||||
std::ofstream f(path);
|
std::ofstream f(path);
|
||||||
f << R"({"global_enabled":false,"min_version":"1.0.0","rollout_permille":250,"message":"hold"})";
|
f << R"({"global_enabled":false,"min_version":"1.0.0","rollout_permille":250,"message":"hold"})";
|
||||||
@@ -6053,7 +6078,7 @@ void testLiteRolloutManifestLoader()
|
|||||||
std::remove(path.c_str());
|
std::remove(path.c_str());
|
||||||
|
|
||||||
// Malformed JSON -> present but invalid -> fail-open allowed.
|
// Malformed JSON -> present but invalid -> fail-open allowed.
|
||||||
const std::string badPath = "/tmp/obsidian-rollout-bad.json";
|
const std::string badPath = testTmpPath("obsidian-rollout-bad.json").string();
|
||||||
{ std::ofstream f(badPath); f << "{ this is not json"; }
|
{ std::ofstream f(badPath); f << "{ this is not json"; }
|
||||||
auto bad = loadLiteRolloutManifestFromFile(badPath);
|
auto bad = loadLiteRolloutManifestFromFile(badPath);
|
||||||
EXPECT_TRUE(bad.present);
|
EXPECT_TRUE(bad.present);
|
||||||
@@ -6098,7 +6123,7 @@ void testLiteWalletControllerRolloutGate()
|
|||||||
// ── xmrig updater pure core (util/xmrig_updater.h) — driven by the real release fixture ──
|
// ── xmrig updater pure core (util/xmrig_updater.h) — driven by the real release fixture ──
|
||||||
static std::string readXmrigFixture()
|
static std::string readXmrigFixture()
|
||||||
{
|
{
|
||||||
const std::string path = std::string(DRAGONX_TEST_FIXTURE_DIR) + "/xmrig/release_latest.json";
|
const std::string path = fixtureDir() + "/xmrig/release_latest.json";
|
||||||
std::ifstream f(path, std::ios::binary);
|
std::ifstream f(path, std::ios::binary);
|
||||||
return std::string((std::istreambuf_iterator<char>(f)), std::istreambuf_iterator<char>());
|
return std::string((std::istreambuf_iterator<char>(f)), std::istreambuf_iterator<char>());
|
||||||
}
|
}
|
||||||
@@ -6241,7 +6266,7 @@ void testAtomicFileWrite()
|
|||||||
using dragonx::util::Platform;
|
using dragonx::util::Platform;
|
||||||
|
|
||||||
fs::path dir = fs::temp_directory_path() / "obsidian_atomic_test";
|
fs::path dir = fs::temp_directory_path() / "obsidian_atomic_test";
|
||||||
fs::remove_all(dir);
|
removeTree(dir);
|
||||||
const std::string target = (dir / "nested" / "settings.json").string();
|
const std::string target = (dir / "nested" / "settings.json").string();
|
||||||
|
|
||||||
// Creates parent dirs and writes content.
|
// Creates parent dirs and writes content.
|
||||||
@@ -6270,7 +6295,7 @@ void testAtomicFileWrite()
|
|||||||
EXPECT_TRUE((perms & (fs::perms::group_all | fs::perms::others_all)) == fs::perms::none);
|
EXPECT_TRUE((perms & (fs::perms::group_all | fs::perms::others_all)) == fs::perms::none);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
fs::remove_all(dir);
|
removeTree(dir);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Address checksum validation. Uses standard Base58Check / BIP173 Bech32 vectors — the
|
// Address checksum validation. Uses standard Base58Check / BIP173 Bech32 vectors — the
|
||||||
@@ -6562,7 +6587,7 @@ void testXmrigSignatureVerify()
|
|||||||
// Reads any fixture file by repo-relative path under tests/fixtures/.
|
// Reads any fixture file by repo-relative path under tests/fixtures/.
|
||||||
static std::string readFixtureFile(const std::string& rel)
|
static std::string readFixtureFile(const std::string& rel)
|
||||||
{
|
{
|
||||||
std::ifstream f(std::string(DRAGONX_TEST_FIXTURE_DIR) + "/" + rel, std::ios::binary);
|
std::ifstream f(fixtureDir() + "/" + rel, std::ios::binary);
|
||||||
return std::string((std::istreambuf_iterator<char>(f)), std::istreambuf_iterator<char>());
|
return std::string((std::istreambuf_iterator<char>(f)), std::istreambuf_iterator<char>());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -6761,7 +6786,7 @@ void testXmrigLiveInstall()
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
using namespace dragonx::util;
|
using namespace dragonx::util;
|
||||||
const std::string dir = "/tmp/obsidian-xmrig-live-test";
|
const std::string dir = testTmpPath("obsidian-xmrig-live-test").string();
|
||||||
std::error_code ec; std::filesystem::remove_all(dir, ec);
|
std::error_code ec; std::filesystem::remove_all(dir, ec);
|
||||||
|
|
||||||
XmrigUpdater up;
|
XmrigUpdater up;
|
||||||
@@ -7577,6 +7602,11 @@ void testAddressBookScope()
|
|||||||
EXPECT_TRUE(legacy.visibleInWallet("anything"));
|
EXPECT_TRUE(legacy.visibleInWallet("anything"));
|
||||||
|
|
||||||
// --- Round-trip + migration + scope-aware dedup, isolated under a temp $HOME ---
|
// --- Round-trip + migration + scope-aware dedup, isolated under a temp $HOME ---
|
||||||
|
#ifdef _WIN32
|
||||||
|
// getConfigDir() uses SHGetFolderPath(CSIDL_APPDATA), which no env var redirects: this would
|
||||||
|
// overwrite the real %APPDATA%\ObsidianDragon\addressbook.json.
|
||||||
|
std::printf("[skip] testAddressBookScope round-trip (Windows config dir can't be redirected)\n");
|
||||||
|
#else
|
||||||
const char* oldHome = std::getenv("HOME");
|
const char* oldHome = std::getenv("HOME");
|
||||||
std::string savedHome = oldHome ? oldHome : "";
|
std::string savedHome = oldHome ? oldHome : "";
|
||||||
fs::path tmp = fs::temp_directory_path() /
|
fs::path tmp = fs::temp_directory_path() /
|
||||||
@@ -7629,6 +7659,7 @@ void testAddressBookScope()
|
|||||||
|
|
||||||
if (!savedHome.empty()) setenv("HOME", savedHome.c_str(), 1); else unsetenv("HOME");
|
if (!savedHome.empty()) setenv("HOME", savedHome.c_str(), 1); else unsetenv("HOME");
|
||||||
std::error_code ec; fs::remove_all(tmp, ec);
|
std::error_code ec; fs::remove_all(tmp, ec);
|
||||||
|
#endif // !_WIN32
|
||||||
}
|
}
|
||||||
|
|
||||||
// Wallet-files metadata index (multi-wallet P1b): upsert change-detection, find, extra folders,
|
// Wallet-files metadata index (multi-wallet P1b): upsert change-detection, find, extra folders,
|
||||||
@@ -7658,7 +7689,11 @@ void testWalletIndex()
|
|||||||
EXPECT_TRUE(!idx.removeExtraFolder("/some/dir")); // already gone
|
EXPECT_TRUE(!idx.removeExtraFolder("/some/dir")); // already gone
|
||||||
}
|
}
|
||||||
|
|
||||||
// save + reload round-trip under a temp $HOME
|
// save + reload round-trip under a temp $HOME. Not on Windows: the config dir comes from
|
||||||
|
// SHGetFolderPath there, so this would overwrite the real %APPDATA%\ObsidianDragon\wallets.json.
|
||||||
|
#ifdef _WIN32
|
||||||
|
std::printf("[skip] testWalletIndex round-trip (Windows config dir can't be redirected)\n");
|
||||||
|
#else
|
||||||
{
|
{
|
||||||
const char* oldHome = std::getenv("HOME");
|
const char* oldHome = std::getenv("HOME");
|
||||||
std::string savedHome = oldHome ? oldHome : "";
|
std::string savedHome = oldHome ? oldHome : "";
|
||||||
@@ -7693,6 +7728,7 @@ void testWalletIndex()
|
|||||||
if (!savedHome.empty()) setenv("HOME", savedHome.c_str(), 1); else unsetenv("HOME");
|
if (!savedHome.empty()) setenv("HOME", savedHome.c_str(), 1); else unsetenv("HOME");
|
||||||
std::error_code ec2; fs::remove_all(tmp, ec2);
|
std::error_code ec2; fs::remove_all(tmp, ec2);
|
||||||
}
|
}
|
||||||
|
#endif // !_WIN32
|
||||||
}
|
}
|
||||||
|
|
||||||
int main()
|
int main()
|
||||||
|
|||||||
@@ -61,10 +61,8 @@ Everything that matters for a test is appended to `<datadir>/fake_dragonxd.event
|
|||||||
cmake -S . -B build/linux -DDRAGONX_BUILD_FAKE_DAEMON=ON
|
cmake -S . -B build/linux -DDRAGONX_BUILD_FAKE_DAEMON=ON
|
||||||
cmake --build build/linux --target fake_dragonxd # -> build/linux/fake_dragonxd/dragonxd
|
cmake --build build/linux --target fake_dragonxd # -> build/linux/fake_dragonxd/dragonxd
|
||||||
|
|
||||||
# Windows (mingw cross, from Linux/WSL), with the toolchain ./build.sh --win-release writes; own tree
|
# Windows (mingw cross, from Linux/WSL): builds it with the Windows test suite in build/windows-tests
|
||||||
cmake -S . -B build/windows-tests -DCMAKE_TOOLCHAIN_FILE=build/windows/mingw-toolchain.cmake \
|
scripts/test-windows.sh --no-run # -> build/windows-tests/fake_dragonxd/dragonxd.exe
|
||||||
-DDRAGONX_USE_SYSTEM_SDL3=OFF -DDRAGONX_BUILD_FAKE_DAEMON=ON
|
|
||||||
cmake --build build/windows-tests --target fake_dragonxd # -> build/windows-tests/fake_dragonxd/dragonxd.exe
|
|
||||||
```
|
```
|
||||||
|
|
||||||
The output goes to its own `fake_dragonxd/` directory so it never replaces the real `bin/dragonxd`.
|
The output goes to its own `fake_dragonxd/` directory so it never replaces the real `bin/dragonxd`.
|
||||||
|
|||||||
Reference in New Issue
Block a user