Skip to content

Commit f4b3645

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 d40b97b commit f4b3645

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,13 +274,15 @@ 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-
if (write(pipes[worker_idx][1], &it, sizeof(it)) == -1) {
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+
if (write(pipes[worker_idx][1], &idx, sizeof(idx)) == -1) {
239282
perror("Error during workload distribution");
240283
return EXIT_FAILURE;
241284
}
242-
worker_idx++;
243-
if (worker_idx >= args->num_processes) worker_idx = 0;
285+
if (++worker_idx >= args->num_processes) worker_idx = 0;
244286
}
245287

246288
/* Close all pipes to signal workers to exit */
@@ -253,8 +295,9 @@ static int run_concurrent(struct Args* args) {
253295
#endif
254296

255297
int main(int argc, char** argv) {
298+
int run_all = 1;
256299
/* Command-line args */
257-
struct Args args = {/*num_processes=*/0, /*custom_seed=*/NULL};
300+
struct Args args = {/*num_processes=*/0, /*custom_seed=*/NULL, /*targets=*/{{0}, 0}};
258301
/* Test entry iterator */
259302
struct test_entry* t;
260303
/* Process exit status */
@@ -295,14 +338,18 @@ int main(int argc, char** argv) {
295338
if (read_args(argc, argv, named_arg_start, &args) != 0) {
296339
_exit(EXIT_FAILURE);
297340
}
341+
342+
/* Disable run_all if there are specific targets */
343+
if (args.targets.size != 0) run_all = 0;
298344
}
299345

300346
/* run test RNG tests (must run before we really initialize the test RNG) */
301-
/* Note: currently, these tests are executed sequentially */
347+
/* Note: currently, these tests are executed sequentially because there */
348+
/* is really only one test. */
302349
for (t = tests_no_ctx; t->name; t++) {
303-
printf("Running %s..\n", t->name);
304-
t->func();
305-
printf("%s PASSED\n", t->name);
350+
if (run_all) { /* future: support filtering */
351+
run_test(t);
352+
}
306353
}
307354

308355
/* Initialize test RNG and library contexts */
@@ -311,10 +358,10 @@ int main(int argc, char** argv) {
311358

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

0 commit comments

Comments
 (0)