upleb.uk

Public git repos — served from a NIP-34 GRASP relay at git.upleb.uk

summaryrefslogtreecommitdiff
path: root/src/selftest.cpp
diff options
context:
space:
mode:
authorBitflash <btf01@proton.me>2026-08-01 15:24:34 -0300
committerGitHub <noreply@github.com>2026-08-01 15:24:34 -0300
commit224c2dd1d1b2bfb9fd3e089d23fd4e739e49a106 (patch)
tree2d83947ed77389a1d9e9764fe2321b55d50485a6 /src/selftest.cpp
parenta2726cad9e9e11c73ae341ec627a696cdeb63edc (diff)
diag: make the self-test report where the person running it can see (#92)
On Windows the self-test from #91 printed nothing. printf in this tree is OutputDebugStringF, which writes to the data directory debug.log, and the Windows binary is linked -mwindows with no console. A failure was still caught, since a non-zero return stops make, but it arrived with no way to tell which check failed. And because the first line printed before strSetDataDir pointed at the temporary directory, every line was appended to the real debug.log -- the file users are asked to paste into issues. The file now gets the real printf, the data directory is set before anything prints, and on Windows a console is borrowed only when stdout has nowhere to go. That last condition matters: the first version reopened stdout unconditionally and took the output away from `make tests > log`, which is the case that counts.
Diffstat (limited to 'src/selftest.cpp')
-rw-r--r--src/selftest.cpp52
1 files changed, 52 insertions, 0 deletions
diff --git a/src/selftest.cpp b/src/selftest.cpp
index d649b23..abe1d15 100644
--- a/src/selftest.cpp
+++ b/src/selftest.cpp
@@ -8,6 +8,23 @@
8#include "headers_core.h" 8#include "headers_core.h"
9#include "selftest.h" 9#include "selftest.h"
10 10
11// Test results go to the terminal, not to debug.log.
12//
13// printf in this tree is OutputDebugStringF, which writes into the data
14// directory's debug.log and binds that path, once, on its first call. For a
15// self-test that produced two bad outcomes at the same time. On Windows the
16// binary is linked -mwindows and has no console, so `make tests` printed the
17// bip32 results, echoed the self-test command, and then showed nothing at all --
18// a failure was still caught, because a non-zero return stops make, but it
19// arrived with no way to tell which check failed. And because the first line
20// printed before strSetDataDir was pointed at the temporary directory, every
21// line landed in the developer's real debug.log: the same file users are asked
22// to paste into issues.
23//
24// Undefining the macro here gives this file the real printf, so results reach
25// stdout. Nothing else in the tree is affected.
26#undef printf
27
11#include <mutex> 28#include <mutex>
12#include <stdexcept> 29#include <stdexcept>
13#include <thread> 30#include <thread>
@@ -163,6 +180,7 @@ static bool Check(bool condition, const char* message)
163 180
164static int RunWalletKeyPoolSelfTest() 181static int RunWalletKeyPoolSelfTest()
165{ 182{
183 fflush(stdout);
166 printf("wallet-keypool self-test\n"); 184 printf("wallet-keypool self-test\n");
167 185
168 std::string tmp; 186 std::string tmp;
@@ -180,6 +198,9 @@ static int RunWalletKeyPoolSelfTest()
180 } 198 }
181 199
182 int nFail = 0; 200 int nFail = 0;
201 // Before anything can open the database or resolve the log path: what the
202 // node itself prints during the test belongs in the temporary directory,
203 // and dies with it. The test's own results are on stdout, above.
183 strSetDataDir = tmp; 204 strSetDataDir = tmp;
184 printf(" temp datadir: %s\n", tmp.c_str()); 205 printf(" temp datadir: %s\n", tmp.c_str());
185 206
@@ -261,11 +282,42 @@ static int RunWalletKeyPoolSelfTest()
261 RemoveTree(tmp); 282 RemoveTree(tmp);
262 printf("%s (%d failure%s)\n", nFail == 0 ? "ALL TESTS PASSED" : "TESTS FAILED", 283 printf("%s (%d failure%s)\n", nFail == 0 ? "ALL TESTS PASSED" : "TESTS FAILED",
263 nFail, nFail == 1 ? "" : "s"); 284 nFail, nFail == 1 ? "" : "s");
285 fflush(stdout);
264 return nFail == 0 ? 0 : 1; 286 return nFail == 0 ? 0 : 1;
265} 287}
266 288
289// A -mwindows binary starts with no console attached, so stdout goes nowhere
290// even when it was launched from a terminal. Borrow the caller's console for
291// the duration of the self-test. Nothing to do on Linux, where stdout is
292// already connected.
293static void AttachTerminal()
294{
295#ifdef _WIN32
296 // Only when there is nowhere for stdout to go. If the caller redirected it
297 // to a file or a pipe -- which is what `make tests > log` and any CI does --
298 // that handle is inherited and already works, and reopening it on CONOUT$
299 // would take the output away from the file and put it on the screen. That
300 // was the first version of this fix, and it broke the one case that
301 // mattered.
302 HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE);
303 if (hOut != NULL && hOut != INVALID_HANDLE_VALUE)
304 return;
305
306 if (AttachConsole(ATTACH_PARENT_PROCESS))
307 {
308 // Return values ignored on purpose: if the reopen fails there is
309 // nowhere left to report it, and the exit status still carries the
310 // result.
311 freopen("CONOUT$", "w", stdout);
312 freopen("CONOUT$", "w", stderr);
313 }
314#endif
315}
316
267int RunSelfTest(const std::string& name) 317int RunSelfTest(const std::string& name)
268{ 318{
319 AttachTerminal();
320
269 if (name == "wallet-keypool") 321 if (name == "wallet-keypool")
270 return RunWalletKeyPoolSelfTest(); 322 return RunWalletKeyPoolSelfTest();
271 323