10#if defined(SUPPORTS_CONCURRENCY)
21# pragma GCC diagnostic push
22# pragma GCC diagnostic warning "-Wunused-function"
25#define UNUSED(x) (void)(x)
62 printf(
"jobs = %d. %s execution.\n",
args->num_processes,
args->num_processes > 1 ?
"Parallel" :
"Sequential");
67 const char* env_iter = getenv(
"SECP256K1_TEST_ITERS");
68 if (env_iter && strlen(env_iter) > 0) {
82 fprintf(stderr,
"Unknown argument '-%s=%s'\n",
key, value);
87 printf(
"Usage: ./tests [options]\n\n");
88 printf(
"Run the test suite for the project with optional configuration.\n\n");
90 printf(
" --help, -h Show this help message\n");
91 printf(
" --list_tests, -l Display list of all available tests and modules\n");
92 printf(
" --jobs=<num>, -j=<num> Number of parallel worker processes (default: 0 = sequential)\n");
93 printf(
" --iterations=<num>, -i=<num> Number of iterations for each test (default: 16)\n");
94 printf(
" --seed=<hex> Set a specific RNG seed (default: random)\n");
95 printf(
" --target=<test name>, -t=<name> Run a specific test (can be provided multiple times)\n");
96 printf(
" --target=<module name>, -t=<module> Run all tests within a specific module (can be provided multiple times)\n");
97 printf(
" --log=<0|1> Enable or disable test execution logging (default: 0 = disabled)\n");
100 printf(
" - All arguments must be provided in the form '--key=value', '-key=value' or '-k=value'.\n");
101 printf(
" - Single or double dashes are allowed for multi character options.\n");
102 printf(
" - Unknown arguments are reported but ignored.\n");
103 printf(
" - Sequential execution occurs if -jobs=0 or unspecified.\n");
104 printf(
" - Iterations and seed can also be passed as positional arguments before any other argument for backward compatibility.\n");
111 printf(
"========================================\n");
115 for (
t = 0;
t < mod->
size;
t++) {
119 printf(
"----------------------------------------\n");
121 printf(
"\nRun specific module: ./tests -t=<module_name>\n");
122 printf(
"Run specific test: ./tests -t=<test_name>\n\n");
127 long val = strtol(value, &ptr_val, 10);
128 if (*ptr_val !=
'\0') {
129 fprintf(stderr,
"Invalid number for -%s=%s\n", key, value);
133 fprintf(stderr,
"Arg '-%s' out of range: '%ld'. Range: 0..%d\n", key, val,
MAX_SUBPROCESSES);
142 if (!value)
return 0;
143 COUNT = (int) strtol(value, NULL, 0);
145 fputs(
"An iteration count of 0 or less is not allowed.\n", stderr);
153 tf->
args.
custom_seed = (!value || strcmp(value,
"NULL") == 0) ? NULL : value;
159 tf->
args.
logging = value && strcmp(value,
"1") == 0;
166 if (!arg || arg[0] !=
'-') {
167 *err_msg =
"missing initial dash";
171 if (arg[1] !=
'-')
return arg + 1;
174 if (arg[2] ==
'\0') {
175 *err_msg =
"missing option name after double dash";
180 *err_msg =
"too many leading dashes";
185 if (key[1] ==
'\0') {
186 *err_msg =
"short option cannot use double dash";
199 int add_all = strcmp(value, module->
name) == 0;
200 for (idx = 0; idx < module->
size; idx++) {
201 entry = &module->
data[idx];
202 if (add_all || strcmp(value, entry->
name) == 0) {
204 fprintf(stderr,
"Too many -target args (max: %d)\n",
MAX_ARGS);
209 if (!add_all)
return 0;
213 if (add_all)
return 0;
215 fprintf(stderr,
"Error: target '%s' not found (missing or module disabled).\n"
216 "Run program with -list_tests option to display available tests and modules.\n", value);
226 const char* err_msg =
"unknown error";
227 for (i = start; i < argc; i++) {
228 char* raw_arg = argv[i];
229 if (!raw_arg || raw_arg[0] !=
'-') {
230 fprintf(stderr,
"Invalid arg '%s': must start with '-'\n", raw_arg ? raw_arg :
"(null)");
235 if (!key || *key ==
'\0') {
236 fprintf(stderr,
"Invalid arg '%s': %s. Must be -k=value or --key=value\n", raw_arg, err_msg);
240 eq = strchr(raw_arg,
'=');
241 if (!eq || eq == raw_arg + 1) {
243 if (strcmp(key,
"h") == 0 || strcmp(key,
"help") == 0) {
247 if (strcmp(key,
"l") == 0 || strcmp(key,
"list_tests") == 0) {
251 fprintf(stderr,
"Invalid arg '%s': must be -k=value or --key=value\n", raw_arg);
257 if (!value || *value ==
'\0') {
258 fprintf(stderr,
"Invalid arg '%s': value cannot be empty\n", raw_arg);
262 if (
parse_arg(key, value, tf) != 0)
return -1;
269 printf(
"Running %s..\n",
t->name);
271 printf(
"Test %s PASSED (%.3f sec)\n",
t->name, (
double)(
gettime_i64() - start_time) / 1000000);
285#if defined(SUPPORTS_CONCURRENCY)
286static const int MAX_TARGETS = 255;
298 fprintf(stderr,
"Internal Error: the number of targets (%d) exceeds the maximum supported (%d). "
299 "If you need more, extend 'run_concurrent()' to handle additional targets.\n",
305 if (pipe(pipefd) != 0) {
306 perror(
"Error during pipe setup");
314 perror(
"Error during process fork");
320 while (read(pipefd[0], &idx,
sizeof(idx)) ==
sizeof(idx)) {
333 idx = (
unsigned char)it;
334 if (write(pipefd[1], &idx,
sizeof(idx)) == -1) {
335 perror(
"Error during workload distribution");
345 if (waitpid(workers[it], &
ret, 0) == -1 ||
ret != 0) {
346 status = EXIT_FAILURE;
358 fprintf(stderr,
"Error: tests registry not provided or empty\n");
373 setbuf(stdout, NULL);
376 setbuf(stderr, NULL);
379 if (
read_env(tf) != 0)
return EXIT_FAILURE;
383 int named_arg_start = 1;
385 fprintf(stderr,
"Too many command-line arguments (max: %d)\n",
MAX_ARGS);
391 if (argv[1][0] !=
'-') {
392 int has_seed = argc > 2 && argv[2][0] !=
'-';
394 if (has_seed)
parse_seed(
"seed", argv[2], tf);
395 named_arg_start = has_seed ? 3 : 2;
397 if (
read_args(argc, argv, named_arg_start, tf) != 0) {
427 fprintf(stderr,
"Error: No test runner set. You must call 'tf_init' first to initialize the framework "
428 "or manually assign 'fn_run_test' before calling 'tf_run'.\n");
438 for (idx = 0; idx < module->
size; idx++) {
440 fprintf(stderr,
"Internal Error: Number of tests (%d) exceeds MAX_ARGS (%d). "
449 if (!tf->
args.
logging)
printf(
"Tests running silently. Use '-log=1' to enable detailed logging\n");
471#if defined(SUPPORTS_CONCURRENCY)
472 status = run_concurrent(tf);
474 fputs(
"Parallel execution not supported on your system. Running sequentially...\n", stderr);
480 printf(
"Total execution time: %.3f seconds\n", (
double)(
gettime_i64() - start_time) / 1000000);
487# pragma GCC diagnostic pop
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)