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 --- */
3643struct 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
4352static int parse_jobs_count (const char * key , const char * value , struct Args * out );
4453static 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" */
126160static 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
252294int 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