1 1.1 christos /* 2 1.1 christos * SPDX-License-Identifier: BSD-2-Clause 3 1.1 christos * 4 1.1 christos * Copyright (C) 2004 Nik Clayton 5 1.1 christos * Copyright (C) 2017 Jrmie Galarneau 6 1.1 christos */ 7 1.1 christos 8 1.1 christos #include <ctype.h> 9 1.1 christos #include <stdarg.h> 10 1.1 christos #include <stdio.h> 11 1.1 christos #include <stdlib.h> 12 1.1 christos #include <string.h> 13 1.1 christos #include <limits.h> 14 1.1 christos #include <assert.h> 15 1.1 christos 16 1.1 christos #include "tap.h" 17 1.1 christos 18 1.1 christos static int no_plan = 0; 19 1.1 christos static int skip_all = 0; 20 1.1 christos static int have_plan = 0; 21 1.1 christos static unsigned int test_count = 0; /* Number of tests that have been run */ 22 1.1 christos static unsigned int e_tests = 0; /* Expected number of tests to run */ 23 1.1 christos static unsigned int failures = 0; /* Number of tests that failed */ 24 1.1 christos static char *todo_msg = NULL; 25 1.1 christos static const char *todo_msg_fixed = "libtap malloc issue"; 26 1.1 christos static int todo = 0; 27 1.1 christos static int test_died = 0; 28 1.1 christos static int tap_is_disabled = 0; 29 1.1 christos 30 1.1 christos /* Encapsulate the pthread code in a conditional. In the absence of 31 1.1 christos libpthread the code does nothing */ 32 1.1 christos #ifdef HAVE_LIBPTHREAD 33 1.1 christos #include <pthread.h> 34 1.1 christos static pthread_mutex_t M = PTHREAD_MUTEX_INITIALIZER; 35 1.1 christos # define LOCK pthread_mutex_lock(&M); 36 1.1 christos # define UNLOCK pthread_mutex_unlock(&M); 37 1.1 christos #else 38 1.1 christos # define LOCK 39 1.1 christos # define UNLOCK 40 1.1 christos #endif 41 1.1 christos 42 1.1 christos static void _expected_tests(unsigned int); 43 1.1 christos static void _tap_init(void); 44 1.1 christos static void _cleanup(void); 45 1.1 christos 46 1.1 christos #ifdef __MINGW32__ 47 1.1 christos static inline 48 1.1 christos void flockfile (FILE * filehandle) { 49 1.1 christos return; 50 1.1 christos } 51 1.1 christos 52 1.1 christos static inline 53 1.1 christos void funlockfile(FILE * filehandle) { 54 1.1 christos return; 55 1.1 christos } 56 1.1 christos #endif 57 1.1 christos 58 1.1 christos /* 59 1.1 christos * Generate a test result. 60 1.1 christos * 61 1.1 christos * ok -- boolean, indicates whether or not the test passed. 62 1.1 christos * test_name -- the name of the test, may be NULL 63 1.1 christos * test_comment -- a comment to print afterwards, may be NULL 64 1.1 christos */ 65 1.1 christos unsigned int 66 1.1 christos _gen_result(int ok, const char *func, const char *file, unsigned int line, 67 1.1 christos const char *test_name, ...) 68 1.1 christos { 69 1.1 christos va_list ap; 70 1.1 christos char *local_test_name = NULL; 71 1.1 christos char *c; 72 1.1 christos int name_is_digits; 73 1.1 christos 74 1.1 christos LOCK; 75 1.1 christos 76 1.1 christos test_count++; 77 1.1 christos 78 1.1 christos /* Start by taking the test name and performing any printf() 79 1.1 christos expansions on it */ 80 1.1 christos if(test_name != NULL) { 81 1.1 christos va_start(ap, test_name); 82 1.1 christos if (vasprintf(&local_test_name, test_name, ap) == -1) { 83 1.1 christos local_test_name = NULL; 84 1.1 christos } 85 1.1 christos va_end(ap); 86 1.1 christos 87 1.1 christos /* Make sure the test name contains more than digits 88 1.1 christos and spaces. Emit an error message and exit if it 89 1.1 christos does */ 90 1.1 christos if(local_test_name) { 91 1.1 christos name_is_digits = 1; 92 1.1 christos for(c = local_test_name; *c != '\0'; c++) { 93 1.1 christos if(!isdigit((unsigned char) *c) && !isspace((unsigned char) *c)) { 94 1.1 christos name_is_digits = 0; 95 1.1 christos break; 96 1.1 christos } 97 1.1 christos } 98 1.1 christos 99 1.1 christos if(name_is_digits) { 100 1.1 christos diag(" You named your test '%s'. You shouldn't use numbers for your test names.", local_test_name); 101 1.1 christos diag(" Very confusing."); 102 1.1 christos } 103 1.1 christos } 104 1.1 christos } 105 1.1 christos 106 1.1 christos if(!ok) { 107 1.1 christos printf("not "); 108 1.1 christos failures++; 109 1.1 christos } 110 1.1 christos 111 1.1 christos printf("ok %d", test_count); 112 1.1 christos 113 1.1 christos if(test_name != NULL) { 114 1.1 christos printf(" - "); 115 1.1 christos 116 1.1 christos /* Print the test name, escaping any '#' characters it 117 1.1 christos might contain */ 118 1.1 christos if(local_test_name != NULL) { 119 1.1 christos flockfile(stdout); 120 1.1 christos for(c = local_test_name; *c != '\0'; c++) { 121 1.1 christos if(*c == '#') 122 1.1 christos fputc('\\', stdout); 123 1.1 christos fputc((int)*c, stdout); 124 1.1 christos } 125 1.1 christos funlockfile(stdout); 126 1.1 christos } else { /* vasprintf() failed, use a fixed message */ 127 1.1 christos printf("%s", todo_msg_fixed); 128 1.1 christos } 129 1.1 christos } 130 1.1 christos 131 1.1 christos /* If we're in a todo_start() block then flag the test as being 132 1.1 christos TODO. todo_msg should contain the message to print at this 133 1.1 christos point. If it's NULL then asprintf() failed, and we should 134 1.1 christos use the fixed message. 135 1.1 christos 136 1.1 christos This is not counted as a failure, so decrement the counter if 137 1.1 christos the test failed. */ 138 1.1 christos if(todo) { 139 1.1 christos printf(" # TODO %s", todo_msg ? todo_msg : todo_msg_fixed); 140 1.1 christos if(!ok) 141 1.1 christos failures--; 142 1.1 christos } 143 1.1 christos 144 1.1 christos printf("\n"); 145 1.1 christos 146 1.1 christos if(!ok) { 147 1.1 christos if(getenv("HARNESS_ACTIVE") != NULL) 148 1.1 christos fputs("\n", stderr); 149 1.1 christos 150 1.1 christos diag(" Failed %stest (%s:%s() at line %d)", 151 1.1 christos todo ? "(TODO) " : "", file, func, line); 152 1.1 christos } 153 1.1 christos free(local_test_name); 154 1.1 christos 155 1.1 christos UNLOCK; 156 1.1 christos 157 1.1 christos /* We only care (when testing) that ok is positive, but here we 158 1.1 christos specifically only want to return 1 or 0 */ 159 1.1 christos return ok ? 1 : 0; 160 1.1 christos } 161 1.1 christos 162 1.1 christos /* 163 1.1 christos * Initialise the TAP library. Will only do so once, however many times it's 164 1.1 christos * called. 165 1.1 christos */ 166 1.1 christos void 167 1.1 christos _tap_init(void) 168 1.1 christos { 169 1.1 christos static int run_once = 0; 170 1.1 christos 171 1.1 christos if(!run_once) { 172 1.1 christos atexit(_cleanup); 173 1.1 christos 174 1.1 christos /* stdout needs to be unbuffered so that the output appears 175 1.1 christos in the same place relative to stderr output as it does 176 1.1 christos with Test::Harness */ 177 1.1 christos setbuf(stdout, 0); 178 1.1 christos run_once = 1; 179 1.1 christos } 180 1.1 christos } 181 1.1 christos 182 1.1 christos /* 183 1.1 christos * Note that there's no plan. 184 1.1 christos */ 185 1.1 christos int 186 1.1 christos plan_no_plan(void) 187 1.1 christos { 188 1.1 christos 189 1.1 christos LOCK; 190 1.1 christos 191 1.1 christos _tap_init(); 192 1.1 christos 193 1.1 christos if(have_plan != 0) { 194 1.1 christos fprintf(stderr, "You tried to plan twice!\n"); 195 1.1 christos test_died = 1; 196 1.1 christos UNLOCK; 197 1.1 christos exit(255); 198 1.1 christos } 199 1.1 christos 200 1.1 christos have_plan = 1; 201 1.1 christos no_plan = 1; 202 1.1 christos 203 1.1 christos UNLOCK; 204 1.1 christos 205 1.1 christos return 1; 206 1.1 christos } 207 1.1 christos 208 1.1 christos /* 209 1.1 christos * Note that the plan is to skip all tests 210 1.1 christos */ 211 1.1 christos int 212 1.1 christos plan_skip_all(const char *reason) 213 1.1 christos { 214 1.1 christos 215 1.1 christos LOCK; 216 1.1 christos 217 1.1 christos _tap_init(); 218 1.1 christos 219 1.1 christos skip_all = 1; 220 1.1 christos 221 1.1 christos printf("1..0"); 222 1.1 christos 223 1.1 christos if(reason != NULL) 224 1.1 christos printf(" # Skip %s", reason); 225 1.1 christos 226 1.1 christos printf("\n"); 227 1.1 christos 228 1.1 christos UNLOCK; 229 1.1 christos 230 1.1 christos exit(0); 231 1.1 christos } 232 1.1 christos 233 1.1 christos /* 234 1.1 christos * Note the number of tests that will be run. 235 1.1 christos */ 236 1.1 christos int 237 1.1 christos plan_tests(unsigned int tests) 238 1.1 christos { 239 1.1 christos 240 1.1 christos LOCK; 241 1.1 christos 242 1.1 christos _tap_init(); 243 1.1 christos 244 1.1 christos if(have_plan != 0) { 245 1.1 christos fprintf(stderr, "You tried to plan twice!\n"); 246 1.1 christos test_died = 1; 247 1.1 christos UNLOCK; 248 1.1 christos exit(255); 249 1.1 christos } 250 1.1 christos 251 1.1 christos if(tests == 0) { 252 1.1 christos fprintf(stderr, "You said to run 0 tests! You've got to run something.\n"); 253 1.1 christos test_died = 1; 254 1.1 christos UNLOCK; 255 1.1 christos exit(255); 256 1.1 christos } 257 1.1 christos 258 1.1 christos have_plan = 1; 259 1.1 christos 260 1.1 christos _expected_tests(tests); 261 1.1 christos 262 1.1 christos UNLOCK; 263 1.1 christos 264 1.1 christos return e_tests; 265 1.1 christos } 266 1.1 christos 267 1.1 christos unsigned int 268 1.1 christos diag(const char *fmt, ...) 269 1.1 christos { 270 1.1 christos va_list ap; 271 1.1 christos 272 1.1 christos fputs("# ", stderr); 273 1.1 christos 274 1.1 christos va_start(ap, fmt); 275 1.1 christos vfprintf(stderr, fmt, ap); 276 1.1 christos va_end(ap); 277 1.1 christos 278 1.1 christos fputs("\n", stderr); 279 1.1 christos 280 1.1 christos return 0; 281 1.1 christos } 282 1.1 christos 283 1.1 christos unsigned int 284 1.1 christos rdiag_start(void) 285 1.1 christos { 286 1.1 christos fputs("# ", stderr); 287 1.1 christos return 0; 288 1.1 christos } 289 1.1 christos 290 1.1 christos unsigned int 291 1.1 christos rdiag(const char *fmt, ...) 292 1.1 christos { 293 1.1 christos va_list ap; 294 1.1 christos 295 1.1 christos va_start(ap, fmt); 296 1.1 christos vfprintf(stderr, fmt, ap); 297 1.1 christos va_end(ap); 298 1.1 christos 299 1.1 christos return 0; 300 1.1 christos } 301 1.1 christos 302 1.1 christos unsigned int 303 1.1 christos rdiag_end(void) 304 1.1 christos { 305 1.1 christos fputs("\n", stderr); 306 1.1 christos return 0; 307 1.1 christos } 308 1.1 christos 309 1.1 christos void 310 1.1 christos diag_multiline(const char *val) 311 1.1 christos { 312 1.1 christos size_t len, i, line_start_idx = 0; 313 1.1 christos 314 1.1 christos assert(val); 315 1.1 christos len = strlen(val); 316 1.1 christos 317 1.1 christos for (i = 0; i < len; i++) { 318 1.1 christos int line_length; 319 1.1 christos 320 1.1 christos if (val[i] != '\n') { 321 1.1 christos continue; 322 1.1 christos } 323 1.1 christos 324 1.1 christos assert((i - line_start_idx + 1) <= INT_MAX); 325 1.1 christos line_length = i - line_start_idx + 1; 326 1.1 christos fprintf(stderr, "# %.*s", line_length, &val[line_start_idx]); 327 1.1 christos line_start_idx = i + 1; 328 1.1 christos } 329 1.1 christos } 330 1.1 christos 331 1.1 christos void 332 1.1 christos _expected_tests(unsigned int tests) 333 1.1 christos { 334 1.1 christos 335 1.1 christos printf("1..%d\n", tests); 336 1.1 christos e_tests = tests; 337 1.1 christos } 338 1.1 christos 339 1.1 christos int 340 1.1 christos skip(unsigned int n, const char *fmt, ...) 341 1.1 christos { 342 1.1 christos va_list ap; 343 1.1 christos char *skip_msg = NULL; 344 1.1 christos 345 1.1 christos LOCK; 346 1.1 christos 347 1.1 christos va_start(ap, fmt); 348 1.1 christos if (vasprintf(&skip_msg, fmt, ap) == -1) { 349 1.1 christos skip_msg = NULL; 350 1.1 christos } 351 1.1 christos va_end(ap); 352 1.1 christos 353 1.1 christos while(n-- > 0) { 354 1.1 christos test_count++; 355 1.1 christos printf("ok %d # skip %s\n", test_count, 356 1.1 christos skip_msg != NULL ? 357 1.1 christos skip_msg : "libtap():malloc() failed"); 358 1.1 christos } 359 1.1 christos 360 1.1 christos free(skip_msg); 361 1.1 christos 362 1.1 christos UNLOCK; 363 1.1 christos 364 1.1 christos return 1; 365 1.1 christos } 366 1.1 christos 367 1.1 christos void 368 1.1 christos todo_start(const char *fmt, ...) 369 1.1 christos { 370 1.1 christos va_list ap; 371 1.1 christos 372 1.1 christos LOCK; 373 1.1 christos 374 1.1 christos va_start(ap, fmt); 375 1.1 christos if (vasprintf(&todo_msg, fmt, ap) == -1) { 376 1.1 christos todo_msg = NULL; 377 1.1 christos } 378 1.1 christos va_end(ap); 379 1.1 christos 380 1.1 christos todo = 1; 381 1.1 christos 382 1.1 christos UNLOCK; 383 1.1 christos } 384 1.1 christos 385 1.1 christos void 386 1.1 christos todo_end(void) 387 1.1 christos { 388 1.1 christos 389 1.1 christos LOCK; 390 1.1 christos 391 1.1 christos todo = 0; 392 1.1 christos free(todo_msg); 393 1.1 christos 394 1.1 christos UNLOCK; 395 1.1 christos } 396 1.1 christos 397 1.1 christos int 398 1.1 christos exit_status(void) 399 1.1 christos { 400 1.1 christos int r; 401 1.1 christos 402 1.1 christos LOCK; 403 1.1 christos 404 1.1 christos /* If there's no plan, just return the number of failures */ 405 1.1 christos if(no_plan || !have_plan) { 406 1.1 christos UNLOCK; 407 1.1 christos return failures; 408 1.1 christos } 409 1.1 christos 410 1.1 christos /* Ran too many tests? Return the number of tests that were run 411 1.1 christos that shouldn't have been */ 412 1.1 christos if(e_tests < test_count) { 413 1.1 christos r = test_count - e_tests; 414 1.1 christos UNLOCK; 415 1.1 christos return r; 416 1.1 christos } 417 1.1 christos 418 1.1 christos /* Return the number of tests that failed + the number of tests 419 1.1 christos that weren't run */ 420 1.1 christos r = failures + e_tests - test_count; 421 1.1 christos UNLOCK; 422 1.1 christos 423 1.1 christos return r; 424 1.1 christos } 425 1.1 christos 426 1.1 christos /* 427 1.1 christos * Cleanup at the end of the run, produce any final output that might be 428 1.1 christos * required. 429 1.1 christos */ 430 1.1 christos void 431 1.1 christos _cleanup(void) 432 1.1 christos { 433 1.1 christos 434 1.1 christos LOCK; 435 1.1 christos 436 1.1 christos if (tap_is_disabled) { 437 1.1 christos UNLOCK; 438 1.1 christos return; 439 1.1 christos } 440 1.1 christos 441 1.1 christos /* If plan_no_plan() wasn't called, and we don't have a plan, 442 1.1 christos and we're not skipping everything, then something happened 443 1.1 christos before we could produce any output */ 444 1.1 christos if(!no_plan && !have_plan && !skip_all) { 445 1.1 christos diag("Looks like your test died before it could output anything."); 446 1.1 christos UNLOCK; 447 1.1 christos return; 448 1.1 christos } 449 1.1 christos 450 1.1 christos if(test_died) { 451 1.1 christos diag("Looks like your test died just after %d.", test_count); 452 1.1 christos UNLOCK; 453 1.1 christos return; 454 1.1 christos } 455 1.1 christos 456 1.1 christos 457 1.1 christos /* No plan provided, but now we know how many tests were run, and can 458 1.1 christos print the header at the end */ 459 1.1 christos if(!skip_all && (no_plan || !have_plan)) { 460 1.1 christos printf("1..%d\n", test_count); 461 1.1 christos } 462 1.1 christos 463 1.1 christos if((have_plan && !no_plan) && e_tests < test_count) { 464 1.1 christos diag("Looks like you planned %d %s but ran %d extra.", 465 1.1 christos e_tests, e_tests == 1 ? "test" : "tests", test_count - e_tests); 466 1.1 christos UNLOCK; 467 1.1 christos return; 468 1.1 christos } 469 1.1 christos 470 1.1 christos if((have_plan || !no_plan) && e_tests > test_count) { 471 1.1 christos diag("Looks like you planned %d %s but only ran %d.", 472 1.1 christos e_tests, e_tests == 1 ? "test" : "tests", test_count); 473 1.1 christos UNLOCK; 474 1.1 christos return; 475 1.1 christos } 476 1.1 christos 477 1.1 christos if(failures) 478 1.1 christos diag("Looks like you failed %d %s of %d.", 479 1.1 christos failures, failures == 1 ? "test" : "tests", test_count); 480 1.1 christos 481 1.1 christos UNLOCK; 482 1.1 christos } 483 1.1 christos 484 1.1 christos /* Disable tap for this process. */ 485 1.1 christos void 486 1.1 christos tap_disable(void) 487 1.1 christos { 488 1.1 christos LOCK; 489 1.1 christos tap_is_disabled = 1; 490 1.1 christos UNLOCK; 491 1.1 christos } 492