32
32
#define MAX_ARGS 20
33
33
#define MAX_SUBPROCESSES 16
34
34
35
+ struct Targets {
36
+ /* Target tests indexes */
37
+ int slots [NUM_TESTS ];
38
+ /* Next available slot */
39
+ int size ;
40
+ };
41
+
35
42
/* --- Command-line args --- */
36
43
struct Args {
37
44
/* 0 => sequential; 1..MAX_SUBPROCESSES => parallel workers */
38
45
int num_processes ;
39
46
/* Specific RNG seed */
40
47
const char * custom_seed ;
48
+ /* Target tests indexes */
49
+ struct Targets targets ;
41
50
};
42
51
43
52
static int parse_jobs_count (const char * key , const char * value , struct Args * out );
44
53
static int parse_iterations (const char * arg );
54
+ static int parse_target (const char * value , struct Args * out );
45
55
46
56
/*
47
57
* 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) {
67
77
out -> custom_seed = (!value || strcmp (value , "NULL" ) == 0 ) ? NULL : value ;
68
78
return 0 ;
69
79
}
80
+ /* Test target */
81
+ if (strcmp (key , "t" ) == 0 || strcmp (key , "target" ) == 0 ) {
82
+ return parse_target (value , out );
83
+ }
70
84
71
85
/* Unknown key: report just so typos don’t silently pass. */
72
86
printf ("Unknown argument '-%s=%s'\n" , key , value );
@@ -81,6 +95,7 @@ static void help(void) {
81
95
printf (" -j=<num>, -jobs=<num> Number of parallel worker processes (default: 0 = sequential)\n" );
82
96
printf (" -iter=<num>, -iterations=<num> Number of iterations for each test (default: 64)\n" );
83
97
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" );
84
99
printf ("\n" );
85
100
printf ("Notes:\n" );
86
101
printf (" - All arguments must be provided in the form '-key=value'.\n" );
@@ -122,6 +137,25 @@ static int parse_iterations(const char* arg) {
122
137
return 0 ;
123
138
}
124
139
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
+
125
159
/* Read args; all must be "-key=value" */
126
160
static int read_args (int argc , char * * argv , int start , struct Args * out ) {
127
161
int i ;
@@ -177,20 +211,29 @@ static void teardown(void) {
177
211
testrand_finish ();
178
212
}
179
213
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
+
180
220
/* Process tests in sequential order */
181
- static int run_sequential (void ) {
221
+ static int run_sequential (struct Args * args , int run_all ) {
182
222
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
+ }
187
230
}
188
231
return EXIT_SUCCESS ;
189
232
}
190
233
191
234
#if SUPPORTS_CONCURRENCY
192
235
/* Process tests in parallel */
193
- static int run_concurrent (struct Args * args ) {
236
+ static int run_concurrent (struct Args * args , int run_all ) {
194
237
/* Sub-processes info */
195
238
pid_t workers [MAX_SUBPROCESSES ];
196
239
int pipes [MAX_SUBPROCESSES ][2 ];
@@ -199,7 +242,7 @@ static int run_concurrent(struct Args* args) {
199
242
/* Parent process exit status */
200
243
int status ;
201
244
/* Loop iterator */
202
- int it ;
245
+ int it , it_end ;
203
246
/* Launch worker processes */
204
247
for (it = 0 ; it < args -> num_processes ; it ++ ) {
205
248
pid_t pid ;
@@ -219,10 +262,7 @@ static int run_concurrent(struct Args* args) {
219
262
int idx ;
220
263
close (pipes [it ][1 ]); /* Close write end */
221
264
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 ]);
226
266
}
227
267
_exit (EXIT_SUCCESS ); /* finish child process */
228
268
} else {
@@ -234,10 +274,12 @@ static int run_concurrent(struct Args* args) {
234
274
235
275
/* Now that we have all sub-processes, distribute workload in round-robin */
236
276
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 ;
241
283
}
242
284
243
285
/* Close all pipes to signal workers to exit */
@@ -250,8 +292,9 @@ static int run_concurrent(struct Args* args) {
250
292
#endif
251
293
252
294
int main (int argc , char * * argv ) {
295
+ int run_all = 1 ;
253
296
/* 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 } };
255
298
/* Test entry iterator */
256
299
struct test_entry * t ;
257
300
/* Process exit status */
@@ -292,14 +335,18 @@ int main(int argc, char** argv) {
292
335
if (read_args (argc , argv , named_arg_start , & args ) != 0 ) {
293
336
_exit (EXIT_FAILURE );
294
337
}
338
+
339
+ /* Disable run_all if there are specific targets */
340
+ if (args .targets .size != 0 ) run_all = 0 ;
295
341
}
296
342
297
343
/* 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. */
299
346
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
+ }
303
350
}
304
351
305
352
/* Initialize test RNG and library contexts */
@@ -308,10 +355,10 @@ int main(int argc, char** argv) {
308
355
309
356
/* Check whether to process tests sequentially or concurrently */
310
357
if (args .num_processes == 0 ) {
311
- status = run_sequential ();
358
+ status = run_sequential (& args , run_all );
312
359
} else {
313
360
#if SUPPORTS_CONCURRENCY
314
- status = run_concurrent (& args );
361
+ status = run_concurrent (& args , run_all );
315
362
#else
316
363
fputs ("Parallel execution not supported on your system. Running sequentially..\n" , stderr );
317
364
status = run_sequential (& args , run_all );
0 commit comments