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