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