refactor(audit): batch 3 — decompose App::update() + collapse acrylic fork
Three P1 structural refactors from the audit; no behavior change. 1. Extract the ~180-line daemon-stdout rescan/witness parser out of the ~790-line App::update() into a pure, static, unit-testable NetworkRefreshService::parseDaemonRescanOutput() returning a DaemonRescanScan result struct (sits next to the existing static parse* siblings). The scanning half moved verbatim; App::update() keeps the state-application half, now reading scan.* fields. Adds testParseDaemonRescanOutput() covering all six daemon signals + edge cases against fixture log snippets — previously untestable without a live daemon. 2. Extract the ~95-line global keyboard-shortcut block (Ctrl+, / theme cycle / F5 / low-spec / effects / gradient / wizard) out of App::update() into App::handleGlobalShortcuts(). 3. Collapse the ImGuiAcrylic frontend fork: the GLAD and DX11 namespaces were ~375 lines of semantically-identical code (the frontend makes zero direct GL/DX calls — all backend work delegates to AcrylicMaterial, which has a backend per API). Extended the single frontend's guard to #if defined(DRAGONX_HAS_GLAD) || defined(DRAGONX_USE_DX11) and deleted the DX11 duplicate, leaving the no-backend stub. Kills the Windows/DX11 drift hazard (acrylic frontend changes now made once). Verified: full-node + Lite build clean; ctest 1/1 (incl. the new parser tests); source-hygiene clean; and the collapsed acrylic path was compile-verified under DX11 via the mingw-w64 Windows cross-build (ObsidianDragon.exe links). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -1051,6 +1051,99 @@ void testNetworkRefreshSnapshotHelpers()
|
||||
EXPECT_EQ(snapshot.sendTxids.count("pending-send"), static_cast<size_t>(1));
|
||||
}
|
||||
|
||||
void testParseDaemonRescanOutput()
|
||||
{
|
||||
using dragonx::services::NetworkRefreshService;
|
||||
|
||||
// "Still rescanning ... Progress=<frac>" — fraction scaled to a percentage.
|
||||
{
|
||||
auto scan = NetworkRefreshService::parseDaemonRescanOutput(
|
||||
"2026-07-01 Still rescanning at height 500000. Progress=0.42 tip=600000\n");
|
||||
EXPECT_TRUE(scan.foundRescan);
|
||||
EXPECT_NEAR(scan.rescanPct, 42.0f, 0.01f);
|
||||
}
|
||||
|
||||
// "Rescanning... <n>%" — percentage read directly (already 0..100).
|
||||
{
|
||||
auto scan = NetworkRefreshService::parseDaemonRescanOutput(
|
||||
"Rescanning... 37% done\n");
|
||||
EXPECT_TRUE(scan.foundRescan);
|
||||
EXPECT_NEAR(scan.rescanPct, 37.0f, 0.01f);
|
||||
}
|
||||
|
||||
// Explicit completion line marks finished.
|
||||
{
|
||||
auto scan = NetworkRefreshService::parseDaemonRescanOutput("Done rescanning\n");
|
||||
EXPECT_TRUE(scan.finished);
|
||||
}
|
||||
|
||||
// The daemon that prints no "Done rescanning" logs a rescan benchmark ending in "<digits>ms".
|
||||
{
|
||||
auto scan = NetworkRefreshService::parseDaemonRescanOutput(
|
||||
" rescan 16760577ms\n");
|
||||
EXPECT_TRUE(scan.finished);
|
||||
}
|
||||
|
||||
// "Building Witnesses for block <h> <frac> complete, <n> remaining".
|
||||
{
|
||||
auto scan = NetworkRefreshService::parseDaemonRescanOutput(
|
||||
"Building Witnesses for block 123 0.5 complete, 40 remaining\n");
|
||||
EXPECT_TRUE(scan.foundWitness);
|
||||
EXPECT_NEAR(scan.witnessPct, 50.0f, 0.01f);
|
||||
EXPECT_EQ(scan.witnessRemaining, 40);
|
||||
}
|
||||
|
||||
// "Reading blocks for witness rebuild: <done> / <total>" — captures total and remaining.
|
||||
{
|
||||
auto scan = NetworkRefreshService::parseDaemonRescanOutput(
|
||||
"Reading blocks for witness rebuild: 10 / 200\n");
|
||||
EXPECT_TRUE(scan.foundWitness);
|
||||
EXPECT_EQ(scan.witnessReadTotal, 200);
|
||||
EXPECT_EQ(scan.witnessRemaining, 190); // total - done
|
||||
}
|
||||
|
||||
// Parallel-rebuild completion line snaps witnessRebuilt=true.
|
||||
{
|
||||
auto scan = NetworkRefreshService::parseDaemonRescanOutput(
|
||||
"rebuilt 3 note witness cache(s) to height 99 in 12ms using 4 thread(s)\n");
|
||||
EXPECT_TRUE(scan.foundWitness);
|
||||
EXPECT_TRUE(scan.witnessRebuilt);
|
||||
}
|
||||
|
||||
// "Setting Initial Sapling Witness for tx <hash>, <i> of <N>" — distinct hashes, max N.
|
||||
{
|
||||
auto scan = NetworkRefreshService::parseDaemonRescanOutput(
|
||||
"Setting Initial Sapling Witness for tx abc123, 2 of 7\n"
|
||||
"Setting Initial Sapling Witness for tx def456, 3 of 7\n"
|
||||
"Setting Initial Sapling Witness for tx abc123, 5 of 7\n");
|
||||
EXPECT_TRUE(scan.foundWitness);
|
||||
// The parser collects every occurrence (dedup happens in the apply step's set), so the
|
||||
// vector has all three keys but only two distinct values.
|
||||
EXPECT_EQ(scan.witnessTxids.size(), static_cast<size_t>(3));
|
||||
std::set<std::string> distinct(scan.witnessTxids.begin(), scan.witnessTxids.end());
|
||||
EXPECT_EQ(distinct.size(), static_cast<size_t>(2));
|
||||
EXPECT_EQ(distinct.count("abc123"), static_cast<size_t>(1));
|
||||
EXPECT_EQ(distinct.count("def456"), static_cast<size_t>(1));
|
||||
EXPECT_EQ(scan.witnessTotalTxs, 7);
|
||||
}
|
||||
|
||||
// Empty input yields all defaults.
|
||||
{
|
||||
auto scan = NetworkRefreshService::parseDaemonRescanOutput("");
|
||||
EXPECT_FALSE(scan.foundRescan);
|
||||
EXPECT_FALSE(scan.finished);
|
||||
EXPECT_NEAR(scan.rescanPct, 0.0f, 0.0001f);
|
||||
EXPECT_TRUE(scan.lastStatus.empty());
|
||||
EXPECT_FALSE(scan.foundWitness);
|
||||
EXPECT_NEAR(scan.witnessPct, -1.0f, 0.0001f);
|
||||
EXPECT_EQ(scan.witnessRemaining, -1);
|
||||
EXPECT_EQ(scan.witnessReadTotal, -1);
|
||||
EXPECT_FALSE(scan.witnessRebuilt);
|
||||
EXPECT_TRUE(scan.witnessTxids.empty());
|
||||
EXPECT_EQ(scan.witnessTotalTxs, -1);
|
||||
}
|
||||
}
|
||||
|
||||
void testNetworkRefreshRpcCollectors()
|
||||
{
|
||||
using Refresh = dragonx::services::NetworkRefreshService;
|
||||
@@ -5381,6 +5474,7 @@ int main()
|
||||
testRefreshScheduler();
|
||||
testNetworkRefreshService();
|
||||
testNetworkRefreshSnapshotHelpers();
|
||||
testParseDaemonRescanOutput();
|
||||
testNetworkRefreshRpcCollectors();
|
||||
testNetworkRefreshResultModels();
|
||||
testOperationStatusPollParsing();
|
||||
|
||||
Reference in New Issue
Block a user