test: add --log option to display tests execution
What changed, and why it matters
This commit adds a new optional '--log=1' command-line flag to the project's internal test runner so users can see when each test starts, finishes, and how long it took. It also adds a small safety check to make sure the test framework is initialized before tests are run. There is no change to cryptographic code, no network code, and no behavior that affects normal users of the library.
No security action required. This is a test-framework usability improvement.
Security signals we found
No strong security signals were identified.
Evidence from the diff
The patch modifies src/unit_test.c and src/unit_test.h only. It introduces a ‘logging’ argument, a parse_logging handler, a run_test_log wrapper that prints timing information, and stores the chosen runner in tf->fn_run_test. A guard in tf_run checks that fn_run_test is non-NULL. The default behavior remains silent. No cryptographic, parsing, or consensus-critical code is touched.
Changed components
src/unit_test.csrc/unit_test.hInspect captured patch +32 / −5
diff --git a/src/unit_test.c b/src/unit_test.c
index 4eace52..a1858a1 100644
--- a/src/unit_test.c
+++ b/src/unit_test.c
@@ -26,6 +26,7 @@ static int parse_jobs_count(const char* key, const char* value, struct tf_framew
static int parse_iterations(const char* key, const char* value, struct tf_framework* tf);
static int parse_seed(const char* key, const char* value, struct tf_framework* tf);
static int parse_target(const char* key, const char* value, struct tf_framework* tf);
+static int parse_logging(const char* key, const char* value, struct tf_framework* tf);
/* Mapping table: key -> handler */
typedef int (*ArgHandler)(const char* key, const char* value, struct tf_framework* tf);
@@ -46,6 +47,7 @@ static struct ArgMap arg_map[] = {
{ "j", parse_jobs_count }, { "jobs", parse_jobs_count },
{ "i", parse_iterations }, { "iterations", parse_iterations },
{ "seed", parse_seed },
+ { "log", parse_logging },
{ NULL, NULL } /* sentinel */
};
@@ -87,6 +89,7 @@ static void help(void) {
printf(" --seed=<hex> Set a specific RNG seed (default: random)\n");
printf(" --target=<test name>, -t=<name> Run a specific test (can be provided multiple times)\n");
printf(" --target=<module name>, -t=<module> Run all tests within a specific module (can be provided multiple times)\n");
+ printf(" --log=<0|1> Enable or disable test execution logging (default: 0 = disabled)\n");
printf("\n");
printf("Notes:\n");
printf(" - All arguments must be provided in the form '--key=value', '-key=value' or '-k=value'.\n");
@@ -146,6 +149,12 @@ static int parse_seed(const char* key, const char* value, struct tf_framework* t
return 0;
}
+static int parse_logging(const char* key, const char* value, struct tf_framework* tf) {
+ UNUSED(key);
+ tf->args.logging = value && strcmp(value, "1") == 0;
+ return 0;
+}
+
/* Strip up to two leading dashes */
static const char* normalize_key(const char* arg, const char** err_msg) {
const char* key;
@@ -250,17 +259,20 @@ static int read_args(int argc, char** argv, int start, struct tf_framework* tf)
return 0;
}
-static void run_test(const struct tf_test_entry* t) {
+static void run_test_log(const struct tf_test_entry* t) {
+ int64_t start_time = gettime_i64();
printf("Running %s..\n", t->name);
t->func();
- printf("%s PASSED\n", t->name);
+ printf("Test %s PASSED (%.3f sec)\n", t->name, (double)(gettime_i64() - start_time) / 1000000);
}
+static void run_test(const struct tf_test_entry* t) { t->func(); }
+
/* Process tests in sequential order */
static int run_sequential(struct tf_framework* tf) {
int it;
for (it = 0; it < tf->args.targets.size; it++) {
- run_test(tf->args.targets.slots[it]);
+ tf->fn_run_test(tf->args.targets.slots[it]);
}
return EXIT_SUCCESS;
}
@@ -301,7 +313,7 @@ static int run_concurrent(struct tf_framework* tf) {
/* Child worker: read jobs from the shared pipe */
close(pipefd[1]); /* children never write */
while (read(pipefd[0], &idx, sizeof(idx)) == sizeof(idx)) {
- run_test(tf->args.targets.slots[(int)idx]);
+ tf->fn_run_test(tf->args.targets.slots[(int)idx]);
}
_exit(EXIT_SUCCESS); /* finish child process */
} else {
@@ -348,6 +360,7 @@ static int tf_init(struct tf_framework* tf, int argc, char** argv)
tf->args.help = 0;
tf->args.targets.size = 0;
tf->args.list_tests = 0;
+ tf->args.logging = 0;
/* Disable buffering for stdout to improve reliability of getting
* diagnostic information. Happens right at the start of main because
@@ -391,6 +404,7 @@ static int tf_init(struct tf_framework* tf, int argc, char** argv)
}
}
+ tf->fn_run_test = tf->args.logging ? run_test_log : run_test;
return EXIT_SUCCESS;
}
@@ -403,6 +417,12 @@ static int tf_run(struct tf_framework* tf) {
int it;
/* Initial test time */
int64_t start_time = gettime_i64();
+ /* Verify 'tf_init' has been called */
+ if (!tf->fn_run_test) {
+ fprintf(stderr, "Error: No test runner set. You must call 'tf_init' first to initialize the framework "
+ "or manually assign 'fn_run_test' before calling 'tf_run'.\n");
+ return EXIT_FAILURE;
+ }
/* Populate targets with all tests if none were explicitly specified */
run_all = tf->args.targets.size == 0;
@@ -421,6 +441,8 @@ static int tf_run(struct tf_framework* tf) {
}
}
+ if (!tf->args.logging) printf("Tests running silently. Use '-log=1' to enable detailed logging\n");
+
/* Log configuration */
print_args(&tf->args);
@@ -429,7 +451,7 @@ static int tf_run(struct tf_framework* tf) {
/* is really only one test. */
for (it = 0; tf->registry_no_rng && it < tf->registry_no_rng->size; it++) {
if (run_all) { /* future: support filtering */
- run_test(&tf->registry_no_rng->data[it]);
+ tf->fn_run_test(&tf->registry_no_rng->data[it]);
}
}
diff --git a/src/unit_test.h b/src/unit_test.h
index b41e9f7..bf301e5 100644
--- a/src/unit_test.h
+++ b/src/unit_test.h
@@ -61,6 +61,7 @@ struct tf_test_module {
typedef int (*setup_ctx_fn)(void);
typedef int (*teardown_fn)(void);
+typedef void (*run_test_fn)(const struct tf_test_entry*);
struct tf_targets {
/* Target tests indexes */
@@ -81,6 +82,8 @@ struct tf_args {
int list_tests;
/* Target tests indexes */
struct tf_targets targets;
+ /* Enable test execution logging */
+ int logging;
};
/* --------------------------------------------------------- */
@@ -99,6 +102,8 @@ struct tf_framework {
/* Specific context setup and teardown functions */
setup_ctx_fn fn_setup;
teardown_fn fn_teardown;
+ /* Test runner function (can be customized) */
+ run_test_fn fn_run_test;
};
/*
Why this scored 15/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.