10#if defined(SUPPORTS_CONCURRENCY)
20#define UNUSED(x) (void)(x)
57 printf(
"jobs = %d. %s execution.\n",
args->num_processes,
args->num_processes > 1 ?
"Parallel" :
"Sequential");
62 const char* env_iter = getenv(
"SECP256K1_TEST_ITERS");
63 if (env_iter && strlen(env_iter) > 0) {
77 fprintf(stderr,
"Unknown argument '-%s=%s'\n",
key, value);
82 printf(
"Usage: ./tests [options]\n\n");
83 printf(
"Run the test suite for the project with optional configuration.\n\n");
85 printf(
" --help, -h Show this help message\n");
86 printf(
" --list_tests, -l Display list of all available tests and modules\n");
87 printf(
" --jobs=<num>, -j=<num> Number of parallel worker processes (default: 0 = sequential)\n");
88 printf(
" --iterations=<num>, -i=<num> Number of iterations for each test (default: 16)\n");
89 printf(
" --seed=<hex> Set a specific RNG seed (default: random)\n");
90 printf(
" --target=<test name>, -t=<name> Run a specific test (can be provided multiple times)\n");
91 printf(
" --target=<module name>, -t=<module> Run all tests within a specific module (can be provided multiple times)\n");
92 printf(
" --log=<0|1> Enable or disable test execution logging (default: 0 = disabled)\n");
95 printf(
" - All arguments must be provided in the form '--key=value', '-key=value' or '-k=value'.\n");
96 printf(
" - Single or double dashes are allowed for multi character options.\n");
97 printf(
" - Unknown arguments are reported but ignored.\n");
98 printf(
" - Sequential execution occurs if -jobs=0 or unspecified.\n");
99 printf(
" - Iterations and seed can also be passed as positional arguments before any other argument for backward compatibility.\n");
106 printf(
"========================================\n");
110 for (
t = 0;
t < mod->
size;
t++) {
114 printf(
"----------------------------------------\n");
116 printf(
"\nRun specific module: ./tests -t=<module_name>\n");
117 printf(
"Run specific test: ./tests -t=<test_name>\n\n");
122 long val = strtol(value, &ptr_val, 10);
123 if (*ptr_val !=
'\0') {
124 fprintf(stderr,
"Invalid number for -%s=%s\n", key, value);
128 fprintf(stderr,
"Arg '-%s' out of range: '%ld'. Range: 0..%d\n", key, val,
MAX_SUBPROCESSES);
137 if (!value)
return 0;
138 COUNT = (int) strtol(value, NULL, 0);
140 fputs(
"An iteration count of 0 or less is not allowed.\n", stderr);
148 tf->
args.
custom_seed = (!value || strcmp(value,
"NULL") == 0) ? NULL : value;
154 tf->
args.
logging = value && strcmp(value,
"1") == 0;
161 if (!arg || arg[0] !=
'-') {
162 *err_msg =
"missing initial dash";
166 if (arg[1] !=
'-')
return arg + 1;
169 if (arg[2] ==
'\0') {
170 *err_msg =
"missing option name after double dash";
175 *err_msg =
"too many leading dashes";
180 if (key[1] ==
'\0') {
181 *err_msg =
"short option cannot use double dash";
194 int add_all = strcmp(value, module->
name) == 0;
195 for (idx = 0; idx < module->
size; idx++) {
196 entry = &module->
data[idx];
197 if (add_all || strcmp(value, entry->
name) == 0) {
199 fprintf(stderr,
"Too many -target args (max: %d)\n",
MAX_ARGS);
204 if (!add_all)
return 0;
208 if (add_all)
return 0;
210 fprintf(stderr,
"Error: target '%s' not found (missing or module disabled).\n"
211 "Run program with -list_tests option to display available tests and modules.\n", value);
221 const char* err_msg =
"unknown error";
222 for (i = start; i < argc; i++) {
223 char* raw_arg = argv[i];
224 if (!raw_arg || raw_arg[0] !=
'-') {
225 fprintf(stderr,
"Invalid arg '%s': must start with '-'\n", raw_arg ? raw_arg :
"(null)");
230 if (!key || *key ==
'\0') {
231 fprintf(stderr,
"Invalid arg '%s': %s. Must be -k=value or --key=value\n", raw_arg, err_msg);
235 eq = strchr(raw_arg,
'=');
236 if (!eq || eq == raw_arg + 1) {
238 if (strcmp(key,
"h") == 0 || strcmp(key,
"help") == 0) {
242 if (strcmp(key,
"l") == 0 || strcmp(key,
"list_tests") == 0) {
246 fprintf(stderr,
"Invalid arg '%s': must be -k=value or --key=value\n", raw_arg);
252 if (!value || *value ==
'\0') {
253 fprintf(stderr,
"Invalid arg '%s': value cannot be empty\n", raw_arg);
257 if (
parse_arg(key, value, tf) != 0)
return -1;
264 printf(
"Running %s..\n",
t->name);
266 printf(
"Test %s PASSED (%.3f sec)\n",
t->name, (
double)(
gettime_i64() - start_time) / 1000000);
280#if defined(SUPPORTS_CONCURRENCY)
281static const int MAX_TARGETS = 255;
293 fprintf(stderr,
"Internal Error: the number of targets (%d) exceeds the maximum supported (%d). "
294 "If you need more, extend 'run_concurrent()' to handle additional targets.\n",
300 if (pipe(pipefd) != 0) {
301 perror(
"Error during pipe setup");
309 perror(
"Error during process fork");
315 while (read(pipefd[0], &idx,
sizeof(idx)) ==
sizeof(idx)) {
328 idx = (
unsigned char)it;
329 if (write(pipefd[1], &idx,
sizeof(idx)) == -1) {
330 perror(
"Error during workload distribution");
340 if (waitpid(workers[it], &
ret, 0) == -1 ||
ret != 0) {
341 status = EXIT_FAILURE;
353 fprintf(stderr,
"Error: tests registry not provided or empty\n");
368 setbuf(stdout, NULL);
371 setbuf(stderr, NULL);
374 if (
read_env(tf) != 0)
return EXIT_FAILURE;
378 int named_arg_start = 1;
380 fprintf(stderr,
"Too many command-line arguments (max: %d)\n",
MAX_ARGS);
386 if (argv[1][0] !=
'-') {
387 int has_seed = argc > 2 && argv[2][0] !=
'-';
389 if (has_seed)
parse_seed(
"seed", argv[2], tf);
390 named_arg_start = has_seed ? 3 : 2;
392 if (
read_args(argc, argv, named_arg_start, tf) != 0) {
422 fprintf(stderr,
"Error: No test runner set. You must call 'tf_init' first to initialize the framework "
423 "or manually assign 'fn_run_test' before calling 'tf_run'.\n");
433 for (idx = 0; idx < module->
size; idx++) {
435 fprintf(stderr,
"Internal Error: Number of tests (%d) exceeds MAX_ARGS (%d). "
444 if (!tf->
args.
logging)
printf(
"Tests running silently. Use '-log=1' to enable detailed logging\n");
466#if defined(SUPPORTS_CONCURRENCY)
467 status = run_concurrent(tf);
469 fputs(
"Parallel execution not supported on your system. Running sequentially...\n", stderr);
475 printf(
"Total execution time: %.3f seconds\n", (
double)(
gettime_i64() - start_time) / 1000000);
struct tf_targets targets
const struct tf_test_module * registry_no_rng
const struct tf_test_module * registry_modules
const struct tf_test_entry * slots[MAX_ARGS]
const struct tf_test_entry * data
static void testrand_init(const char *hexseed)
Initialize the test RNG using (hex encoded) array up to 16 bytes, or randomly if hexseed is NULL.
static int64_t gettime_i64(void)
static struct ArgMap arg_map[]
static const char * normalize_key(const char *arg, const char **err_msg)
static void run_test_log(const struct tf_test_entry *t)
static int parse_arg(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 void run_test(const struct tf_test_entry *t)
static int tf_init(struct tf_framework *tf, int argc, char **argv)
static int parse_iterations(const char *key, const char *value, struct tf_framework *tf)
static int parse_logging(const char *key, const char *value, struct tf_framework *tf)
int(* ArgHandler)(const char *key, const char *value, struct tf_framework *tf)
static int run_sequential(struct tf_framework *tf)
static int parse_target(const char *key, const char *value, struct tf_framework *tf)
static int read_env(struct tf_framework *tf)
static int read_args(int argc, char **argv, int start, struct tf_framework *tf)
static void print_test_list(struct tf_framework *tf)
static int tf_run(struct tf_framework *tf)
static int parse_jobs_count(const char *key, const char *value, struct tf_framework *tf)
static void print_args(const struct tf_args *args)