@@ -26,6 +26,7 @@ static int parse_jobs_count(const char* key, const char* value, struct tf_framew
2626static int parse_iterations (const char * key , const char * value , struct tf_framework * tf );
2727static int parse_seed (const char * key , const char * value , struct tf_framework * tf );
2828static int parse_target (const char * key , const char * value , struct tf_framework * tf );
29+ static int parse_logging (const char * key , const char * value , struct tf_framework * tf );
2930
3031/* Mapping table: key -> handler */
3132typedef int (* ArgHandler )(const char * key , const char * value , struct tf_framework * tf );
@@ -46,6 +47,7 @@ static struct ArgMap arg_map[] = {
4647 { "j" , parse_jobs_count }, { "jobs" , parse_jobs_count },
4748 { "i" , parse_iterations }, { "iterations" , parse_iterations },
4849 { "seed" , parse_seed },
50+ { "log" , parse_logging },
4951 { NULL , NULL } /* sentinel */
5052};
5153
@@ -87,6 +89,7 @@ static void help(void) {
8789 printf (" --seed=<hex> Set a specific RNG seed (default: random)\n" );
8890 printf (" --target=<test name>, -t=<name> Run a specific test (can be provided multiple times)\n" );
8991 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" );
9093 printf ("\n" );
9194 printf ("Notes:\n" );
9295 printf (" - All arguments must be provided in the form '--key=value', '-key=value' or '-k=value'.\n" );
@@ -146,6 +149,12 @@ static int parse_seed(const char* key, const char* value, struct tf_framework* t
146149 return 0 ;
147150}
148151
152+ static int parse_logging (const char * key , const char * value , struct tf_framework * tf ) {
153+ UNUSED (key );
154+ tf -> args .logging = value && strcmp (value , "1" ) == 0 ;
155+ return 0 ;
156+ }
157+
149158/* Strip up to two leading dashes */
150159static const char * normalize_key (const char * arg , const char * * err_msg ) {
151160 const char * key ;
@@ -248,18 +257,21 @@ static int read_args(int argc, char** argv, int start, struct tf_framework* tf)
248257 return 0 ;
249258}
250259
251- static void run_test (const struct tf_test_entry * t ) {
260+ static void run_test_log (const struct tf_test_entry * t ) {
261+ int64_t start_time = gettime_i64 ();
252262 printf ("Running %s..\n" , t -> name );
253263 t -> func ();
254- printf ("%s PASSED\n" , t -> name );
264+ printf ("Test %s PASSED (%.3f sec) \n" , t -> name , ( double )( gettime_i64 () - start_time ) / 1000000 );
255265}
256266
267+ static void run_test (const struct tf_test_entry * t ) { t -> func (); }
268+
257269/* Process tests in sequential order */
258270static int run_sequential (struct tf_framework * tf ) {
259271 int it ;
260272 for (it = 0 ; it < tf -> args .targets .size ; it ++ ) {
261273 const TestRef * index = & tf -> args .targets .slots [it ];
262- run_test (& tf -> registry_modules [index -> group ].data [index -> idx ]);
274+ tf -> fn_run_test (& tf -> registry_modules [index -> group ].data [index -> idx ]);
263275 }
264276 return EXIT_SUCCESS ;
265277}
@@ -297,7 +309,7 @@ static int run_concurrent(struct tf_framework* tf) {
297309 TestRef tref ;
298310 close (pipes [it ][1 ]); /* Close write end */
299311 while (read (pipes [it ][0 ], & tref , sizeof (tref )) == sizeof (tref )) {
300- run_test (& tf -> registry_modules [tref .group ].data [tref .idx ]);
312+ tf -> fn_run_test (& tf -> registry_modules [tref .group ].data [tref .idx ]);
301313 }
302314 _exit (EXIT_SUCCESS ); /* finish child process */
303315 } else {
@@ -346,6 +358,7 @@ static int tf_init(struct tf_framework* tf, int argc, char** argv)
346358 tf -> args .help = 0 ;
347359 tf -> args .targets .size = 0 ;
348360 tf -> args .list_tests = 0 ;
361+ tf -> args .logging = 0 ;
349362
350363 /* Disable buffering for stdout to improve reliability of getting
351364 * diagnostic information. Happens right at the start of main because
@@ -389,6 +402,7 @@ static int tf_init(struct tf_framework* tf, int argc, char** argv)
389402 }
390403 }
391404
405+ tf -> fn_run_test = tf -> args .logging ? run_test_log : run_test ;
392406 return EXIT_SUCCESS ;
393407}
394408
@@ -401,6 +415,12 @@ static int tf_run(struct tf_framework* tf) {
401415 int it ;
402416 /* Initial test time */
403417 int64_t start_time = gettime_i64 ();
418+ /* Verify 'tf_init' has been called */
419+ if (!tf -> fn_run_test ) {
420+ fprintf (stderr , "Error: No test runner set. You must call 'tf_init' first to initialize the framework "
421+ "or manually assign 'fn_run_test' before calling 'tf_run'.\n" );
422+ return EXIT_FAILURE ;
423+ }
404424
405425 /* Populate targets with all tests if none were explicitly specified */
406426 run_all = tf -> args .targets .size == 0 ;
@@ -419,6 +439,8 @@ static int tf_run(struct tf_framework* tf) {
419439 }
420440 }
421441
442+ if (!tf -> args .logging ) printf ("Tests running silently. Use '-log=1' to enable detailed logging\n" );
443+
422444 /* Log configuration */
423445 print_args (& tf -> args );
424446
@@ -427,7 +449,7 @@ static int tf_run(struct tf_framework* tf) {
427449 /* is really only one test. */
428450 for (it = 0 ; tf -> registry_no_rng && it < tf -> registry_no_rng -> size ; it ++ ) {
429451 if (run_all ) { /* future: support filtering */
430- run_test (& tf -> registry_no_rng -> data [it ]);
452+ tf -> fn_run_test (& tf -> registry_no_rng -> data [it ]);
431453 }
432454 }
433455
0 commit comments