1 /* Copyright (c) 2008 The NetBSD Foundation, Inc. 2 * All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 1. Redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer. 9 * 2. Redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution. 12 * 13 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND 14 * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, 15 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 16 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 17 * IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY 18 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 20 * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 21 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER 22 * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 23 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN 24 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ 25 26 #include "atf-c/tc.h" 27 28 #include <sys/types.h> 29 #include <sys/stat.h> 30 #include <sys/uio.h> 31 32 #include <errno.h> 33 #include <fcntl.h> 34 #include <stdarg.h> 35 #include <stdbool.h> 36 #include <stdio.h> 37 #include <stdlib.h> 38 #include <string.h> 39 #include <unistd.h> 40 41 #include "atf-c/defs.h" 42 #include "atf-c/detail/env.h" 43 #include "atf-c/detail/fs.h" 44 #include "atf-c/detail/map.h" 45 #include "atf-c/detail/sanity.h" 46 #include "atf-c/detail/text.h" 47 #include "atf-c/error.h" 48 49 /* --------------------------------------------------------------------- 50 * Auxiliary functions. 51 * --------------------------------------------------------------------- */ 52 53 enum expect_type { 54 EXPECT_PASS, 55 EXPECT_FAIL, 56 EXPECT_EXIT, 57 EXPECT_SIGNAL, 58 EXPECT_DEATH, 59 EXPECT_TIMEOUT, 60 }; 61 62 struct context { 63 const atf_tc_t *tc; 64 const char *resfile; 65 size_t fail_count; 66 67 enum expect_type expect; 68 atf_dynstr_t expect_reason; 69 size_t expect_previous_fail_count; 70 size_t expect_fail_count; 71 int expect_exitcode; 72 int expect_signo; 73 }; 74 75 static void context_init(struct context *, const atf_tc_t *, const char *); 76 static void check_fatal_error(atf_error_t); 77 static void report_fatal_error(const char *, ...) 78 ATF_DEFS_ATTRIBUTE_NORETURN; 79 static atf_error_t write_resfile(const int, const char *, const int, 80 const atf_dynstr_t *); 81 static void create_resfile(const char *, const char *, const int, 82 atf_dynstr_t *); 83 static void error_in_expect(struct context *, const char *, ...) 84 ATF_DEFS_ATTRIBUTE_NORETURN; 85 static void validate_expect(struct context *); 86 static void expected_failure(struct context *, atf_dynstr_t *) 87 ATF_DEFS_ATTRIBUTE_NORETURN; 88 static void fail_requirement(struct context *, atf_dynstr_t *) 89 ATF_DEFS_ATTRIBUTE_NORETURN; 90 static void fail_check(struct context *, atf_dynstr_t *); 91 static void pass(struct context *) 92 ATF_DEFS_ATTRIBUTE_NORETURN; 93 static void skip(struct context *, atf_dynstr_t *) 94 ATF_DEFS_ATTRIBUTE_NORETURN; 95 static void format_reason_ap(atf_dynstr_t *, const char *, const size_t, 96 const char *, va_list); 97 static void format_reason_fmt(atf_dynstr_t *, const char *, const size_t, 98 const char *, ...); 99 static void errno_test(struct context *, const char *, const size_t, 100 const int, const char *, const bool, 101 void (*)(struct context *, atf_dynstr_t *)); 102 static atf_error_t check_prog_in_dir(const char *, void *); 103 static atf_error_t check_prog(struct context *, const char *); 104 105 static void 106 context_init(struct context *ctx, const atf_tc_t *tc, const char *resfile) 107 { 108 ctx->tc = tc; 109 ctx->resfile = resfile; 110 ctx->fail_count = 0; 111 ctx->expect = EXPECT_PASS; 112 check_fatal_error(atf_dynstr_init(&ctx->expect_reason)); 113 ctx->expect_previous_fail_count = 0; 114 ctx->expect_fail_count = 0; 115 ctx->expect_exitcode = 0; 116 ctx->expect_signo = 0; 117 } 118 119 static void 120 check_fatal_error(atf_error_t err) 121 { 122 if (atf_is_error(err)) { 123 char buf[1024]; 124 atf_error_format(err, buf, sizeof(buf)); 125 fprintf(stderr, "FATAL ERROR: %s\n", buf); 126 atf_error_free(err); 127 abort(); 128 } 129 } 130 131 static void 132 report_fatal_error(const char *msg, ...) 133 { 134 va_list ap; 135 fprintf(stderr, "FATAL ERROR: "); 136 137 va_start(ap, msg); 138 vfprintf(stderr, msg, ap); 139 va_end(ap); 140 141 fprintf(stderr, "\n"); 142 abort(); 143 } 144 145 /** Writes to a results file. 146 * 147 * The results file is supposed to be already open. 148 * 149 * This function returns an error code instead of exiting in case of error 150 * because the caller needs to clean up the reason object before terminating. 151 */ 152 static atf_error_t 153 write_resfile(const int fd, const char *result, const int arg, 154 const atf_dynstr_t *reason) 155 { 156 static char NL[] = "\n", CS[] = ": "; 157 char buf[64]; 158 const char *r; 159 struct iovec iov[5]; 160 ssize_t ret; 161 int count = 0; 162 163 INV(arg == -1 || reason != NULL); 164 165 #define UNCONST(a) ((void *)(unsigned long)(const void *)(a)) 166 iov[count].iov_base = UNCONST(result); 167 iov[count++].iov_len = strlen(result); 168 169 if (reason != NULL) { 170 if (arg != -1) { 171 iov[count].iov_base = buf; 172 iov[count++].iov_len = snprintf(buf, sizeof(buf), "(%d)", arg); 173 } 174 175 iov[count].iov_base = CS; 176 iov[count++].iov_len = sizeof(CS) - 1; 177 178 r = atf_dynstr_cstring(reason); 179 iov[count].iov_base = UNCONST(r); 180 iov[count++].iov_len = strlen(r); 181 } 182 #undef UNCONST 183 184 iov[count].iov_base = NL; 185 iov[count++].iov_len = sizeof(NL) - 1; 186 187 while ((ret = writev(fd, iov, count)) == -1 && errno == EINTR) 188 continue; /* Retry. */ 189 if (ret != -1) 190 return atf_no_error(); 191 192 return atf_libc_error( 193 errno, "Failed to write results file; result %s, reason %s", result, 194 reason == NULL ? "null" : atf_dynstr_cstring(reason)); 195 } 196 197 /** Creates a results file. 198 * 199 * The input reason is released in all cases. 200 * 201 * An error in this function is considered to be fatal, hence why it does 202 * not return any error code. 203 */ 204 static void 205 create_resfile(const char *resfile, const char *result, const int arg, 206 atf_dynstr_t *reason) 207 { 208 atf_error_t err; 209 210 if (strcmp("/dev/stdout", resfile) == 0) { 211 err = write_resfile(STDOUT_FILENO, result, arg, reason); 212 } else if (strcmp("/dev/stderr", resfile) == 0) { 213 err = write_resfile(STDERR_FILENO, result, arg, reason); 214 } else { 215 const int fd = open(resfile, O_WRONLY | O_CREAT | O_TRUNC, 216 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); 217 if (fd == -1) { 218 err = atf_libc_error(errno, "Cannot create results file '%s'", 219 resfile); 220 } else { 221 err = write_resfile(fd, result, arg, reason); 222 close(fd); 223 } 224 } 225 226 if (reason != NULL) 227 atf_dynstr_fini(reason); 228 229 check_fatal_error(err); 230 } 231 232 /** Fails a test case if validate_expect fails. */ 233 static void 234 error_in_expect(struct context *ctx, const char *fmt, ...) 235 { 236 atf_dynstr_t reason; 237 va_list ap; 238 239 va_start(ap, fmt); 240 format_reason_ap(&reason, NULL, 0, fmt, ap); 241 va_end(ap); 242 243 ctx->expect = EXPECT_PASS; /* Ensure fail_requirement really fails. */ 244 fail_requirement(ctx, &reason); 245 } 246 247 /** Ensures that the "expect" state is correct. 248 * 249 * Call this function before modifying the current value of expect. 250 */ 251 static void 252 validate_expect(struct context *ctx) 253 { 254 if (ctx->expect == EXPECT_DEATH) { 255 error_in_expect(ctx, "Test case was expected to terminate abruptly " 256 "but it continued execution"); 257 } else if (ctx->expect == EXPECT_EXIT) { 258 error_in_expect(ctx, "Test case was expected to exit cleanly but it " 259 "continued execution"); 260 } else if (ctx->expect == EXPECT_FAIL) { 261 if (ctx->expect_fail_count == ctx->expect_previous_fail_count) 262 error_in_expect(ctx, "Test case was expecting a failure but none " 263 "were raised"); 264 else 265 INV(ctx->expect_fail_count > ctx->expect_previous_fail_count); 266 } else if (ctx->expect == EXPECT_PASS) { 267 /* Nothing to validate. */ 268 } else if (ctx->expect == EXPECT_SIGNAL) { 269 error_in_expect(ctx, "Test case was expected to receive a termination " 270 "signal but it continued execution"); 271 } else if (ctx->expect == EXPECT_TIMEOUT) { 272 error_in_expect(ctx, "Test case was expected to hang but it continued " 273 "execution"); 274 } else 275 UNREACHABLE; 276 } 277 278 static void 279 expected_failure(struct context *ctx, atf_dynstr_t *reason) 280 { 281 check_fatal_error(atf_dynstr_prepend_fmt(reason, "%s: ", 282 atf_dynstr_cstring(&ctx->expect_reason))); 283 create_resfile(ctx->resfile, "expected_failure", -1, reason); 284 exit(EXIT_SUCCESS); 285 } 286 287 static void 288 fail_requirement(struct context *ctx, atf_dynstr_t *reason) 289 { 290 if (ctx->expect == EXPECT_FAIL) { 291 expected_failure(ctx, reason); 292 } else if (ctx->expect == EXPECT_PASS) { 293 create_resfile(ctx->resfile, "failed", -1, reason); 294 exit(EXIT_FAILURE); 295 } else { 296 error_in_expect(ctx, "Test case raised a failure but was not " 297 "expecting one; reason was %s", atf_dynstr_cstring(reason)); 298 } 299 UNREACHABLE; 300 } 301 302 static void 303 fail_check(struct context *ctx, atf_dynstr_t *reason) 304 { 305 if (ctx->expect == EXPECT_FAIL) { 306 fprintf(stderr, "*** Expected check failure: %s: %s\n", 307 atf_dynstr_cstring(&ctx->expect_reason), 308 atf_dynstr_cstring(reason)); 309 ctx->expect_fail_count++; 310 } else if (ctx->expect == EXPECT_PASS) { 311 fprintf(stderr, "*** Check failed: %s\n", atf_dynstr_cstring(reason)); 312 ctx->fail_count++; 313 } else { 314 error_in_expect(ctx, "Test case raised a failure but was not " 315 "expecting one; reason was %s", atf_dynstr_cstring(reason)); 316 } 317 318 atf_dynstr_fini(reason); 319 } 320 321 static void 322 pass(struct context *ctx) 323 { 324 if (ctx->expect == EXPECT_FAIL) { 325 error_in_expect(ctx, "Test case was expecting a failure but got " 326 "a pass instead"); 327 } else if (ctx->expect == EXPECT_PASS) { 328 create_resfile(ctx->resfile, "passed", -1, NULL); 329 exit(EXIT_SUCCESS); 330 } else { 331 error_in_expect(ctx, "Test case asked to explicitly pass but was " 332 "not expecting such condition"); 333 } 334 UNREACHABLE; 335 } 336 337 static void 338 skip(struct context *ctx, atf_dynstr_t *reason) 339 { 340 if (ctx->expect == EXPECT_PASS) { 341 create_resfile(ctx->resfile, "skipped", -1, reason); 342 exit(EXIT_SUCCESS); 343 } else { 344 error_in_expect(ctx, "Can only skip a test case when running in " 345 "expect pass mode"); 346 } 347 UNREACHABLE; 348 } 349 350 /** Formats a failure/skip reason message. 351 * 352 * The formatted reason is stored in out_reason. out_reason is initialized 353 * in this function and is supposed to be released by the caller. In general, 354 * the reason will eventually be fed to create_resfile, which will release 355 * it. 356 * 357 * Errors in this function are fatal. Rationale being: reasons are used to 358 * create results files; if we can't format the reason correctly, the result 359 * of the test program will be bogus. So it's better to just exit with a 360 * fatal error. 361 */ 362 static void 363 format_reason_ap(atf_dynstr_t *out_reason, 364 const char *source_file, const size_t source_line, 365 const char *reason, va_list ap) 366 { 367 atf_error_t err; 368 369 if (source_file != NULL) { 370 err = atf_dynstr_init_fmt(out_reason, "%s:%zd: ", source_file, 371 source_line); 372 } else { 373 PRE(source_line == 0); 374 err = atf_dynstr_init(out_reason); 375 } 376 377 if (!atf_is_error(err)) { 378 va_list ap2; 379 va_copy(ap2, ap); 380 err = atf_dynstr_append_ap(out_reason, reason, ap2); 381 va_end(ap2); 382 } 383 384 check_fatal_error(err); 385 } 386 387 static void 388 format_reason_fmt(atf_dynstr_t *out_reason, 389 const char *source_file, const size_t source_line, 390 const char *reason, ...) 391 { 392 va_list ap; 393 394 va_start(ap, reason); 395 format_reason_ap(out_reason, source_file, source_line, reason, ap); 396 va_end(ap); 397 } 398 399 static void 400 errno_test(struct context *ctx, const char *file, const size_t line, 401 const int exp_errno, const char *expr_str, 402 const bool expr_result, 403 void (*fail_func)(struct context *, atf_dynstr_t *)) 404 { 405 const int actual_errno = errno; 406 407 if (expr_result) { 408 if (exp_errno != actual_errno) { 409 atf_dynstr_t reason; 410 411 format_reason_fmt(&reason, file, line, "Expected errno %d, got %d, " 412 "in %s", exp_errno, actual_errno, expr_str); 413 fail_func(ctx, &reason); 414 } 415 } else { 416 atf_dynstr_t reason; 417 418 format_reason_fmt(&reason, file, line, "Expected true value in %s", 419 expr_str); 420 fail_func(ctx, &reason); 421 } 422 } 423 424 struct prog_found_pair { 425 const char *prog; 426 bool found; 427 }; 428 429 static atf_error_t 430 check_prog_in_dir(const char *dir, void *data) 431 { 432 struct prog_found_pair *pf = data; 433 atf_error_t err; 434 435 if (pf->found) 436 err = atf_no_error(); 437 else { 438 atf_fs_path_t p; 439 440 err = atf_fs_path_init_fmt(&p, "%s/%s", dir, pf->prog); 441 if (atf_is_error(err)) 442 goto out_p; 443 444 err = atf_fs_eaccess(&p, atf_fs_access_x); 445 if (!atf_is_error(err)) 446 pf->found = true; 447 else { 448 atf_error_free(err); 449 INV(!pf->found); 450 err = atf_no_error(); 451 } 452 453 out_p: 454 atf_fs_path_fini(&p); 455 } 456 457 return err; 458 } 459 460 static atf_error_t 461 check_prog(struct context *ctx, const char *prog) 462 { 463 atf_error_t err; 464 atf_fs_path_t p; 465 466 err = atf_fs_path_init_fmt(&p, "%s", prog); 467 if (atf_is_error(err)) 468 goto out; 469 470 if (atf_fs_path_is_absolute(&p)) { 471 err = atf_fs_eaccess(&p, atf_fs_access_x); 472 if (atf_is_error(err)) { 473 atf_dynstr_t reason; 474 475 atf_error_free(err); 476 atf_fs_path_fini(&p); 477 format_reason_fmt(&reason, NULL, 0, "The required program %s could " 478 "not be found", prog); 479 skip(ctx, &reason); 480 } 481 } else { 482 const char *path = atf_env_get("PATH"); 483 struct prog_found_pair pf; 484 atf_fs_path_t bp; 485 486 err = atf_fs_path_branch_path(&p, &bp); 487 if (atf_is_error(err)) 488 goto out_p; 489 490 if (strcmp(atf_fs_path_cstring(&bp), ".") != 0) { 491 atf_fs_path_fini(&bp); 492 atf_fs_path_fini(&p); 493 494 report_fatal_error("Relative paths are not allowed when searching " 495 "for a program (%s)", prog); 496 UNREACHABLE; 497 } 498 499 pf.prog = prog; 500 pf.found = false; 501 err = atf_text_for_each_word(path, ":", check_prog_in_dir, &pf); 502 if (atf_is_error(err)) 503 goto out_bp; 504 505 if (!pf.found) { 506 atf_dynstr_t reason; 507 508 atf_fs_path_fini(&bp); 509 atf_fs_path_fini(&p); 510 format_reason_fmt(&reason, NULL, 0, "The required program %s could " 511 "not be found in the PATH", prog); 512 fail_requirement(ctx, &reason); 513 } 514 515 out_bp: 516 atf_fs_path_fini(&bp); 517 } 518 519 out_p: 520 atf_fs_path_fini(&p); 521 out: 522 return err; 523 } 524 525 /* --------------------------------------------------------------------- 526 * The "atf_tc" type. 527 * --------------------------------------------------------------------- */ 528 529 struct atf_tc_impl { 530 const char *m_ident; 531 532 atf_map_t m_vars; 533 atf_map_t m_config; 534 535 atf_tc_head_t m_head; 536 atf_tc_body_t m_body; 537 atf_tc_cleanup_t m_cleanup; 538 }; 539 540 /* 541 * Constructors/destructors. 542 */ 543 544 atf_error_t 545 atf_tc_init(atf_tc_t *tc, const char *ident, atf_tc_head_t head, 546 atf_tc_body_t body, atf_tc_cleanup_t cleanup, 547 const char *const *config) 548 { 549 atf_error_t err; 550 551 tc->pimpl = malloc(sizeof(struct atf_tc_impl)); 552 if (tc->pimpl == NULL) { 553 err = atf_no_memory_error(); 554 goto err; 555 } 556 557 tc->pimpl->m_ident = ident; 558 tc->pimpl->m_head = head; 559 tc->pimpl->m_body = body; 560 tc->pimpl->m_cleanup = cleanup; 561 562 err = atf_map_init_charpp(&tc->pimpl->m_config, config); 563 if (atf_is_error(err)) 564 goto err; 565 566 err = atf_map_init(&tc->pimpl->m_vars); 567 if (atf_is_error(err)) 568 goto err_vars; 569 570 err = atf_tc_set_md_var(tc, "ident", ident); 571 if (atf_is_error(err)) 572 goto err_map; 573 574 if (cleanup != NULL) { 575 err = atf_tc_set_md_var(tc, "has.cleanup", "true"); 576 if (atf_is_error(err)) 577 goto err_map; 578 } 579 580 /* XXX Should the head be able to return error codes? */ 581 if (tc->pimpl->m_head != NULL) 582 tc->pimpl->m_head(tc); 583 584 if (strcmp(atf_tc_get_md_var(tc, "ident"), ident) != 0) { 585 report_fatal_error("Test case head modified the read-only 'ident' " 586 "property"); 587 UNREACHABLE; 588 } 589 590 INV(!atf_is_error(err)); 591 return err; 592 593 err_map: 594 atf_map_fini(&tc->pimpl->m_vars); 595 err_vars: 596 atf_map_fini(&tc->pimpl->m_config); 597 err: 598 return err; 599 } 600 601 atf_error_t 602 atf_tc_init_pack(atf_tc_t *tc, const atf_tc_pack_t *pack, 603 const char *const *config) 604 { 605 return atf_tc_init(tc, pack->m_ident, pack->m_head, pack->m_body, 606 pack->m_cleanup, config); 607 } 608 609 void 610 atf_tc_fini(atf_tc_t *tc) 611 { 612 atf_map_fini(&tc->pimpl->m_vars); 613 free(tc->pimpl); 614 } 615 616 /* 617 * Getters. 618 */ 619 620 const char * 621 atf_tc_get_ident(const atf_tc_t *tc) 622 { 623 return tc->pimpl->m_ident; 624 } 625 626 const char * 627 atf_tc_get_config_var(const atf_tc_t *tc, const char *name) 628 { 629 const char *val; 630 atf_map_citer_t iter; 631 632 PRE(atf_tc_has_config_var(tc, name)); 633 iter = atf_map_find_c(&tc->pimpl->m_config, name); 634 val = atf_map_citer_data(iter); 635 INV(val != NULL); 636 637 return val; 638 } 639 640 const char * 641 atf_tc_get_config_var_wd(const atf_tc_t *tc, const char *name, 642 const char *defval) 643 { 644 const char *val; 645 646 if (!atf_tc_has_config_var(tc, name)) 647 val = defval; 648 else 649 val = atf_tc_get_config_var(tc, name); 650 651 return val; 652 } 653 654 bool 655 atf_tc_get_config_var_as_bool(const atf_tc_t *tc, const char *name) 656 { 657 bool val; 658 const char *strval; 659 atf_error_t err; 660 661 strval = atf_tc_get_config_var(tc, name); 662 err = atf_text_to_bool(strval, &val); 663 if (atf_is_error(err)) { 664 atf_error_free(err); 665 atf_tc_fail("Configuration variable %s does not have a valid " 666 "boolean value; found %s", name, strval); 667 } 668 669 return val; 670 } 671 672 bool 673 atf_tc_get_config_var_as_bool_wd(const atf_tc_t *tc, const char *name, 674 const bool defval) 675 { 676 bool val; 677 678 if (!atf_tc_has_config_var(tc, name)) 679 val = defval; 680 else 681 val = atf_tc_get_config_var_as_bool(tc, name); 682 683 return val; 684 } 685 686 long 687 atf_tc_get_config_var_as_long(const atf_tc_t *tc, const char *name) 688 { 689 long val; 690 const char *strval; 691 atf_error_t err; 692 693 strval = atf_tc_get_config_var(tc, name); 694 err = atf_text_to_long(strval, &val); 695 if (atf_is_error(err)) { 696 atf_error_free(err); 697 atf_tc_fail("Configuration variable %s does not have a valid " 698 "long value; found %s", name, strval); 699 } 700 701 return val; 702 } 703 704 long 705 atf_tc_get_config_var_as_long_wd(const atf_tc_t *tc, const char *name, 706 const long defval) 707 { 708 long val; 709 710 if (!atf_tc_has_config_var(tc, name)) 711 val = defval; 712 else 713 val = atf_tc_get_config_var_as_long(tc, name); 714 715 return val; 716 } 717 718 const char * 719 atf_tc_get_md_var(const atf_tc_t *tc, const char *name) 720 { 721 const char *val; 722 atf_map_citer_t iter; 723 724 PRE(atf_tc_has_md_var(tc, name)); 725 iter = atf_map_find_c(&tc->pimpl->m_vars, name); 726 val = atf_map_citer_data(iter); 727 INV(val != NULL); 728 729 return val; 730 } 731 732 char ** 733 atf_tc_get_md_vars(const atf_tc_t *tc) 734 { 735 return atf_map_to_charpp(&tc->pimpl->m_vars); 736 } 737 738 bool 739 atf_tc_has_config_var(const atf_tc_t *tc, const char *name) 740 { 741 atf_map_citer_t end, iter; 742 743 iter = atf_map_find_c(&tc->pimpl->m_config, name); 744 end = atf_map_end_c(&tc->pimpl->m_config); 745 return !atf_equal_map_citer_map_citer(iter, end); 746 } 747 748 bool 749 atf_tc_has_md_var(const atf_tc_t *tc, const char *name) 750 { 751 atf_map_citer_t end, iter; 752 753 iter = atf_map_find_c(&tc->pimpl->m_vars, name); 754 end = atf_map_end_c(&tc->pimpl->m_vars); 755 return !atf_equal_map_citer_map_citer(iter, end); 756 } 757 758 /* 759 * Modifiers. 760 */ 761 762 atf_error_t 763 atf_tc_set_md_var(atf_tc_t *tc, const char *name, const char *fmt, ...) 764 { 765 atf_error_t err; 766 char *value; 767 va_list ap; 768 769 va_start(ap, fmt); 770 err = atf_text_format_ap(&value, fmt, ap); 771 va_end(ap); 772 773 if (!atf_is_error(err)) 774 err = atf_map_insert(&tc->pimpl->m_vars, name, value, true); 775 else 776 free(value); 777 778 return err; 779 } 780 781 /* --------------------------------------------------------------------- 782 * Free functions, as they should be publicly but they can't. 783 * --------------------------------------------------------------------- */ 784 785 static void _atf_tc_fail(struct context *, const char *, va_list) 786 ATF_DEFS_ATTRIBUTE_NORETURN; 787 static void _atf_tc_fail_nonfatal(struct context *, const char *, va_list); 788 static void _atf_tc_fail_check(struct context *, const char *, const size_t, 789 const char *, va_list); 790 static void _atf_tc_fail_requirement(struct context *, const char *, 791 const size_t, const char *, va_list) ATF_DEFS_ATTRIBUTE_NORETURN; 792 static void _atf_tc_pass(struct context *) ATF_DEFS_ATTRIBUTE_NORETURN; 793 static void _atf_tc_require_prog(struct context *, const char *); 794 static void _atf_tc_skip(struct context *, const char *, va_list) 795 ATF_DEFS_ATTRIBUTE_NORETURN; 796 static void _atf_tc_check_errno(struct context *, const char *, const size_t, 797 const int, const char *, const bool); 798 static void _atf_tc_require_errno(struct context *, const char *, const size_t, 799 const int, const char *, const bool); 800 static void _atf_tc_expect_pass(struct context *); 801 static void _atf_tc_expect_fail(struct context *, const char *, va_list); 802 static void _atf_tc_expect_exit(struct context *, const int, const char *, 803 va_list); 804 static void _atf_tc_expect_signal(struct context *, const int, const char *, 805 va_list); 806 static void _atf_tc_expect_death(struct context *, const char *, 807 va_list); 808 809 static void 810 _atf_tc_fail(struct context *ctx, const char *fmt, va_list ap) 811 { 812 va_list ap2; 813 atf_dynstr_t reason; 814 815 va_copy(ap2, ap); 816 format_reason_ap(&reason, NULL, 0, fmt, ap2); 817 va_end(ap2); 818 819 fail_requirement(ctx, &reason); 820 UNREACHABLE; 821 } 822 823 static void 824 _atf_tc_fail_nonfatal(struct context *ctx, const char *fmt, va_list ap) 825 { 826 va_list ap2; 827 atf_dynstr_t reason; 828 829 va_copy(ap2, ap); 830 format_reason_ap(&reason, NULL, 0, fmt, ap2); 831 va_end(ap2); 832 833 fail_check(ctx, &reason); 834 } 835 836 static void 837 _atf_tc_fail_check(struct context *ctx, const char *file, const size_t line, 838 const char *fmt, va_list ap) 839 { 840 va_list ap2; 841 atf_dynstr_t reason; 842 843 va_copy(ap2, ap); 844 format_reason_ap(&reason, file, line, fmt, ap2); 845 va_end(ap2); 846 847 fail_check(ctx, &reason); 848 } 849 850 static void 851 _atf_tc_fail_requirement(struct context *ctx, const char *file, 852 const size_t line, const char *fmt, va_list ap) 853 { 854 va_list ap2; 855 atf_dynstr_t reason; 856 857 va_copy(ap2, ap); 858 format_reason_ap(&reason, file, line, fmt, ap2); 859 va_end(ap2); 860 861 fail_requirement(ctx, &reason); 862 UNREACHABLE; 863 } 864 865 static void 866 _atf_tc_pass(struct context *ctx) 867 { 868 pass(ctx); 869 UNREACHABLE; 870 } 871 872 static void 873 _atf_tc_require_prog(struct context *ctx, const char *prog) 874 { 875 check_fatal_error(check_prog(ctx, prog)); 876 } 877 878 static void 879 _atf_tc_skip(struct context *ctx, const char *fmt, va_list ap) 880 { 881 atf_dynstr_t reason; 882 va_list ap2; 883 884 va_copy(ap2, ap); 885 format_reason_ap(&reason, NULL, 0, fmt, ap2); 886 va_end(ap2); 887 888 skip(ctx, &reason); 889 } 890 891 static void 892 _atf_tc_check_errno(struct context *ctx, const char *file, const size_t line, 893 const int exp_errno, const char *expr_str, 894 const bool expr_result) 895 { 896 errno_test(ctx, file, line, exp_errno, expr_str, expr_result, fail_check); 897 } 898 899 static void 900 _atf_tc_require_errno(struct context *ctx, const char *file, const size_t line, 901 const int exp_errno, const char *expr_str, 902 const bool expr_result) 903 { 904 errno_test(ctx, file, line, exp_errno, expr_str, expr_result, 905 fail_requirement); 906 } 907 908 static void 909 _atf_tc_expect_pass(struct context *ctx) 910 { 911 validate_expect(ctx); 912 913 ctx->expect = EXPECT_PASS; 914 } 915 916 static void 917 _atf_tc_expect_fail(struct context *ctx, const char *reason, va_list ap) 918 { 919 va_list ap2; 920 921 validate_expect(ctx); 922 923 ctx->expect = EXPECT_FAIL; 924 atf_dynstr_fini(&ctx->expect_reason); 925 va_copy(ap2, ap); 926 check_fatal_error(atf_dynstr_init_ap(&ctx->expect_reason, reason, ap2)); 927 va_end(ap2); 928 ctx->expect_previous_fail_count = ctx->expect_fail_count; 929 } 930 931 static void 932 _atf_tc_expect_exit(struct context *ctx, const int exitcode, const char *reason, 933 va_list ap) 934 { 935 va_list ap2; 936 atf_dynstr_t formatted; 937 938 validate_expect(ctx); 939 940 ctx->expect = EXPECT_EXIT; 941 va_copy(ap2, ap); 942 check_fatal_error(atf_dynstr_init_ap(&formatted, reason, ap2)); 943 va_end(ap2); 944 945 create_resfile(ctx->resfile, "expected_exit", exitcode, &formatted); 946 } 947 948 static void 949 _atf_tc_expect_signal(struct context *ctx, const int signo, const char *reason, 950 va_list ap) 951 { 952 va_list ap2; 953 atf_dynstr_t formatted; 954 955 validate_expect(ctx); 956 957 ctx->expect = EXPECT_SIGNAL; 958 va_copy(ap2, ap); 959 check_fatal_error(atf_dynstr_init_ap(&formatted, reason, ap2)); 960 va_end(ap2); 961 962 create_resfile(ctx->resfile, "expected_signal", signo, &formatted); 963 } 964 965 static void 966 _atf_tc_expect_death(struct context *ctx, const char *reason, va_list ap) 967 { 968 va_list ap2; 969 atf_dynstr_t formatted; 970 971 validate_expect(ctx); 972 973 ctx->expect = EXPECT_DEATH; 974 va_copy(ap2, ap); 975 check_fatal_error(atf_dynstr_init_ap(&formatted, reason, ap2)); 976 va_end(ap2); 977 978 create_resfile(ctx->resfile, "expected_death", -1, &formatted); 979 } 980 981 static void 982 _atf_tc_expect_timeout(struct context *ctx, const char *reason, va_list ap) 983 { 984 va_list ap2; 985 atf_dynstr_t formatted; 986 987 validate_expect(ctx); 988 989 ctx->expect = EXPECT_TIMEOUT; 990 va_copy(ap2, ap); 991 check_fatal_error(atf_dynstr_init_ap(&formatted, reason, ap2)); 992 va_end(ap2); 993 994 create_resfile(ctx->resfile, "expected_timeout", -1, &formatted); 995 } 996 997 /* --------------------------------------------------------------------- 998 * Free functions. 999 * --------------------------------------------------------------------- */ 1000 1001 static struct context Current; 1002 1003 atf_error_t 1004 atf_tc_run(const atf_tc_t *tc, const char *resfile) 1005 { 1006 context_init(&Current, tc, resfile); 1007 1008 tc->pimpl->m_body(tc); 1009 1010 validate_expect(&Current); 1011 1012 if (Current.fail_count > 0) { 1013 atf_dynstr_t reason; 1014 1015 format_reason_fmt(&reason, NULL, 0, "%d checks failed; see output for " 1016 "more details", Current.fail_count); 1017 fail_requirement(&Current, &reason); 1018 } else if (Current.expect_fail_count > 0) { 1019 atf_dynstr_t reason; 1020 1021 format_reason_fmt(&reason, NULL, 0, "%d checks failed as expected; " 1022 "see output for more details", Current.expect_fail_count); 1023 expected_failure(&Current, &reason); 1024 } else { 1025 pass(&Current); 1026 } 1027 UNREACHABLE; 1028 return atf_no_error(); 1029 } 1030 1031 atf_error_t 1032 atf_tc_cleanup(const atf_tc_t *tc) 1033 { 1034 if (tc->pimpl->m_cleanup != NULL) 1035 tc->pimpl->m_cleanup(tc); 1036 return atf_no_error(); /* XXX */ 1037 } 1038 1039 /* --------------------------------------------------------------------- 1040 * Free functions that depend on Current. 1041 * --------------------------------------------------------------------- */ 1042 1043 /* 1044 * All the functions below provide delegates to other internal functions 1045 * (prefixed by _) that take the current test case as an argument to 1046 * prevent them from accessing global state. This is to keep the side- 1047 * effects of the internal functions clearer and easier to understand. 1048 * 1049 * The public API should never have hid the fact that it needs access to 1050 * the current test case (other than maybe in the macros), but changing it 1051 * is hard. TODO: Revisit in the future. 1052 */ 1053 1054 void 1055 atf_tc_fail(const char *fmt, ...) 1056 { 1057 va_list ap; 1058 1059 PRE(Current.tc != NULL); 1060 1061 va_start(ap, fmt); 1062 _atf_tc_fail(&Current, fmt, ap); 1063 va_end(ap); 1064 } 1065 1066 void 1067 atf_tc_fail_nonfatal(const char *fmt, ...) 1068 { 1069 va_list ap; 1070 1071 PRE(Current.tc != NULL); 1072 1073 va_start(ap, fmt); 1074 _atf_tc_fail_nonfatal(&Current, fmt, ap); 1075 va_end(ap); 1076 } 1077 1078 void 1079 atf_tc_fail_check(const char *file, const size_t line, const char *fmt, ...) 1080 { 1081 va_list ap; 1082 1083 PRE(Current.tc != NULL); 1084 1085 va_start(ap, fmt); 1086 _atf_tc_fail_check(&Current, file, line, fmt, ap); 1087 va_end(ap); 1088 } 1089 1090 void 1091 atf_tc_fail_requirement(const char *file, const size_t line, 1092 const char *fmt, ...) 1093 { 1094 va_list ap; 1095 1096 PRE(Current.tc != NULL); 1097 1098 va_start(ap, fmt); 1099 _atf_tc_fail_requirement(&Current, file, line, fmt, ap); 1100 va_end(ap); 1101 } 1102 1103 void 1104 atf_tc_pass(void) 1105 { 1106 PRE(Current.tc != NULL); 1107 1108 _atf_tc_pass(&Current); 1109 } 1110 1111 void 1112 atf_tc_require_prog(const char *prog) 1113 { 1114 PRE(Current.tc != NULL); 1115 1116 _atf_tc_require_prog(&Current, prog); 1117 } 1118 1119 void 1120 atf_tc_skip(const char *fmt, ...) 1121 { 1122 va_list ap; 1123 1124 PRE(Current.tc != NULL); 1125 1126 va_start(ap, fmt); 1127 _atf_tc_skip(&Current, fmt, ap); 1128 va_end(ap); 1129 } 1130 1131 void 1132 atf_tc_check_errno(const char *file, const size_t line, const int exp_errno, 1133 const char *expr_str, const bool expr_result) 1134 { 1135 PRE(Current.tc != NULL); 1136 1137 _atf_tc_check_errno(&Current, file, line, exp_errno, expr_str, 1138 expr_result); 1139 } 1140 1141 void 1142 atf_tc_require_errno(const char *file, const size_t line, const int exp_errno, 1143 const char *expr_str, const bool expr_result) 1144 { 1145 PRE(Current.tc != NULL); 1146 1147 _atf_tc_require_errno(&Current, file, line, exp_errno, expr_str, 1148 expr_result); 1149 } 1150 1151 void 1152 atf_tc_expect_pass(void) 1153 { 1154 PRE(Current.tc != NULL); 1155 1156 _atf_tc_expect_pass(&Current); 1157 } 1158 1159 void 1160 atf_tc_expect_fail(const char *reason, ...) 1161 { 1162 va_list ap; 1163 1164 PRE(Current.tc != NULL); 1165 1166 va_start(ap, reason); 1167 _atf_tc_expect_fail(&Current, reason, ap); 1168 va_end(ap); 1169 } 1170 1171 void 1172 atf_tc_expect_exit(const int exitcode, const char *reason, ...) 1173 { 1174 va_list ap; 1175 1176 PRE(Current.tc != NULL); 1177 1178 va_start(ap, reason); 1179 _atf_tc_expect_exit(&Current, exitcode, reason, ap); 1180 va_end(ap); 1181 } 1182 1183 void 1184 atf_tc_expect_signal(const int signo, const char *reason, ...) 1185 { 1186 va_list ap; 1187 1188 PRE(Current.tc != NULL); 1189 1190 va_start(ap, reason); 1191 _atf_tc_expect_signal(&Current, signo, reason, ap); 1192 va_end(ap); 1193 } 1194 1195 void 1196 atf_tc_expect_death(const char *reason, ...) 1197 { 1198 va_list ap; 1199 1200 PRE(Current.tc != NULL); 1201 1202 va_start(ap, reason); 1203 _atf_tc_expect_death(&Current, reason, ap); 1204 va_end(ap); 1205 } 1206 1207 void 1208 atf_tc_expect_timeout(const char *reason, ...) 1209 { 1210 va_list ap; 1211 1212 PRE(Current.tc != NULL); 1213 1214 va_start(ap, reason); 1215 _atf_tc_expect_timeout(&Current, reason, ap); 1216 va_end(ap); 1217 } 1218