Skip to content

Commit 16822f5

Browse files
committed
test: support running specific test targets
Add support for specifying tests to run via the "-target" or "-t" command-line option. Multiple test names can be provided; only those will run instead of the full suite.
1 parent 2a9e160 commit 16822f5

File tree

2 files changed

+71
-22
lines changed

2 files changed

+71
-22
lines changed

src/tests.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7811,4 +7811,6 @@ static struct test_entry tests[] = {
78117811
{NULL, NULL}
78127812
};
78137813

7814+
#define NUM_TESTS (sizeof(tests) / sizeof(tests[0]) - 1)
7815+
78147816
#endif /* SECP256K1_TESTS_C */

src/unit_test.c

Lines changed: 69 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -32,16 +32,26 @@
3232
#define MAX_ARGS 20
3333
#define MAX_SUBPROCESSES 16
3434

35+
struct Targets {
36+
/* Target tests indexes */
37+
int slots[NUM_TESTS];
38+
/* Next available slot */
39+
int size;
40+
};
41+
3542
/* --- Command-line args --- */
3643
struct Args {
3744
/* 0 => sequential; 1..MAX_SUBPROCESSES => parallel workers */
3845
int num_processes;
3946
/* Specific RNG seed */
4047
const char* custom_seed;
48+
/* Target tests indexes */
49+
struct Targets targets;
4150
};
4251

4352
static int parse_jobs_count(const char* key, const char* value, struct Args* out);
4453
static int parse_iterations(const char* arg);
54+
static int parse_target(const char* value, struct Args* out);
4555

4656
/*
4757
* Main entry point for handling command-line arguments.
@@ -67,6 +77,10 @@ static int parse_arg(const char* key, const char* value, struct Args* out) {
6777
out->custom_seed = (!value || strcmp(value, "NULL") == 0) ? NULL : value;
6878
return 0;
6979
}
80+
/* Test target */
81+
if (strcmp(key, "t") == 0 || strcmp(key, "target") == 0) {
82+
return parse_target(value, out);
83+
}
7084

7185
/* Unknown key: report just so typos don’t silently pass. */
7286
printf("Unknown argument '-%s=%s'\n", key, value);
@@ -81,6 +95,7 @@ static void help(void) {
8195
printf(" -j=<num>, -jobs=<num> Number of parallel worker processes (default: 0 = sequential)\n");
8296
printf(" -iter=<num>, -iterations=<num> Number of iterations for each test (default: 64)\n");
8397
printf(" -seed=<hex> Set a specific RNG seed (default: random)\n");
98+
printf(" -target=<test name>, -t=<name> Run a specific test (can be provided multiple times)\n");
8499
printf("\n");
85100
printf("Notes:\n");
86101
printf(" - All arguments must be provided in the form '-key=value'.\n");
@@ -122,6 +137,25 @@ static int parse_iterations(const char* arg) {
122137
return 0;
123138
}
124139

140+
static int parse_target(const char* value, struct Args* out) {
141+
int idx_test;
142+
if (out->targets.size > (int) NUM_TESTS) {
143+
printf("Too many -target arguments (max: %d)\n", (int) NUM_TESTS);
144+
return -1;
145+
}
146+
/* Find test index in the registry */
147+
for (idx_test = 0; idx_test < (int) NUM_TESTS; idx_test++) {
148+
if (strcmp(value, tests[idx_test].name) == 0) break;
149+
}
150+
if (idx_test == (int) NUM_TESTS) {
151+
printf("Target test not found '%s'\n", value);
152+
return -1;
153+
}
154+
out->targets.slots[out->targets.size] = idx_test;
155+
out->targets.size++;
156+
return 0;
157+
}
158+
125159
/* Read args; all must be "-key=value" */
126160
static int read_args(int argc, char** argv, int start, struct Args* out) {
127161
int i;
@@ -177,20 +211,29 @@ static void teardown(void) {
177211
testrand_finish();
178212
}
179213

214+
static void run_test(const struct test_entry* t) {
215+
printf("Running %s..\n", t->name);
216+
t->func();
217+
printf("%s PASSED\n", t->name);
218+
}
219+
180220
/* Process tests in sequential order */
181-
static int run_sequential(void) {
221+
static int run_sequential(struct Args* args, int run_all) {
182222
struct test_entry* t;
183-
for (t = tests; t->name; t++) {
184-
printf("Running %s..\n", t->name);
185-
t->func();
186-
printf("%s PASSED\n", t->name);
223+
if (run_all) for (t = tests; t->name; t++) run_test(t);
224+
else {
225+
/* Run specific targets */
226+
int it;
227+
for (it = 0; it < args->targets.size; it++) {
228+
run_test(&tests[args->targets.slots[it]]);
229+
}
187230
}
188231
return EXIT_SUCCESS;
189232
}
190233

191234
#if SUPPORTS_CONCURRENCY
192235
/* Process tests in parallel */
193-
static int run_concurrent(struct Args* args) {
236+
static int run_concurrent(struct Args* args, int run_all) {
194237
/* Sub-processes info */
195238
pid_t workers[MAX_SUBPROCESSES];
196239
int pipes[MAX_SUBPROCESSES][2];
@@ -199,7 +242,7 @@ static int run_concurrent(struct Args* args) {
199242
/* Parent process exit status */
200243
int status;
201244
/* Loop iterator */
202-
int it;
245+
int it, it_end;
203246
/* Launch worker processes */
204247
for (it = 0; it < args->num_processes; it++) {
205248
pid_t pid;
@@ -219,10 +262,7 @@ static int run_concurrent(struct Args* args) {
219262
int idx;
220263
close(pipes[it][1]); /* Close write end */
221264
while (read(pipes[it][0], &idx, sizeof(idx)) == sizeof(idx)) {
222-
const char* name = tests[idx].name;
223-
printf("Running %s..\n", name);
224-
tests[idx].func();
225-
printf("%s PASSED\n", name);
265+
run_test(&tests[idx]);
226266
}
227267
_exit(EXIT_SUCCESS); /* finish child process */
228268
} else {
@@ -234,10 +274,12 @@ static int run_concurrent(struct Args* args) {
234274

235275
/* Now that we have all sub-processes, distribute workload in round-robin */
236276
worker_idx = 0;
237-
for (it = 0; tests[it].name != NULL; it++) {
238-
write(pipes[worker_idx][1], &it, sizeof(it));
239-
worker_idx++;
240-
if (worker_idx >= args->num_processes) worker_idx = 0;
277+
it_end = run_all ? (int) NUM_TESTS : args->targets.size;
278+
for (it = 0; it < it_end; it++) {
279+
/* If not run_all, take the test from the specified targets */
280+
int idx = run_all ? it : args->targets.slots[it];
281+
write(pipes[worker_idx][1], &idx, sizeof(idx));
282+
if (++worker_idx >= args->num_processes) worker_idx = 0;
241283
}
242284

243285
/* Close all pipes to signal workers to exit */
@@ -250,8 +292,9 @@ static int run_concurrent(struct Args* args) {
250292
#endif
251293

252294
int main(int argc, char** argv) {
295+
int run_all = 1;
253296
/* Command-line args */
254-
struct Args args = {/*num_processes=*/0, /*custom_seed=*/NULL};
297+
struct Args args = {/*num_processes=*/0, /*custom_seed=*/NULL, /*targets=*/{{0}, 0}};
255298
/* Test entry iterator */
256299
struct test_entry* t;
257300
/* Process exit status */
@@ -292,14 +335,18 @@ int main(int argc, char** argv) {
292335
if (read_args(argc, argv, named_arg_start, &args) != 0) {
293336
_exit(EXIT_FAILURE);
294337
}
338+
339+
/* Disable run_all if there are specific targets */
340+
if (args.targets.size != 0) run_all = 0;
295341
}
296342

297343
/* run test RNG tests (must run before we really initialize the test RNG) */
298-
/* Note: currently, these tests are executed sequentially */
344+
/* Note: currently, these tests are executed sequentially because there */
345+
/* is really only one test. */
299346
for (t = tests_no_ctx; t->name; t++) {
300-
printf("Running %s..\n", t->name);
301-
t->func();
302-
printf("%s PASSED\n", t->name);
347+
if (run_all) { /* future: support filtering */
348+
run_test(t);
349+
}
303350
}
304351

305352
/* Initialize test RNG and library contexts */
@@ -308,10 +355,10 @@ int main(int argc, char** argv) {
308355

309356
/* Check whether to process tests sequentially or concurrently */
310357
if (args.num_processes == 0) {
311-
status = run_sequential();
358+
status = run_sequential(&args, run_all);
312359
} else {
313360
#if SUPPORTS_CONCURRENCY
314-
status = run_concurrent(&args);
361+
status = run_concurrent(&args, run_all);
315362
#else
316363
fputs("Parallel execution not supported on your system. Running sequentially..\n", stderr);
317364
status = run_sequential(&args, run_all);

0 commit comments

Comments
 (0)