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