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 create_resfile(ctx, "skipped", -1, reason); 385 context_close_resfile(ctx); 386 exit(EXIT_SUCCESS); 387 } 388 389 /** Formats a failure/skip reason message. 390 * 391 * The formatted reason is stored in out_reason. out_reason is initialized 392 * in this function and is supposed to be released by the caller. In general, 393 * the reason will eventually be fed to create_resfile, which will release 394 * it. 395 * 396 * Errors in this function are fatal. Rationale being: reasons are used to 397 * create results files; if we can't format the reason correctly, the result 398 * of the test program will be bogus. So it's better to just exit with a 399 * fatal error. 400 */ 401 static void 402 format_reason_ap(atf_dynstr_t *out_reason, 403 const char *source_file, const size_t source_line, 404 const char *reason, va_list ap) 405 { 406 atf_error_t err; 407 408 if (source_file != NULL) { 409 err = atf_dynstr_init_fmt(out_reason, "%s:%zd: ", source_file, 410 source_line); 411 } else { 412 PRE(source_line == 0); 413 err = atf_dynstr_init(out_reason); 414 } 415 416 if (!atf_is_error(err)) { 417 va_list ap2; 418 va_copy(ap2, ap); 419 err = atf_dynstr_append_ap(out_reason, reason, ap2); 420 va_end(ap2); 421 } 422 423 check_fatal_error(err); 424 } 425 426 static void 427 format_reason_fmt(atf_dynstr_t *out_reason, 428 const char *source_file, const size_t source_line, 429 const char *reason, ...) 430 { 431 va_list ap; 432 433 va_start(ap, reason); 434 format_reason_ap(out_reason, source_file, source_line, reason, ap); 435 va_end(ap); 436 } 437 438 static void 439 errno_test(struct context *ctx, const char *file, const size_t line, 440 const int exp_errno, const char *expr_str, 441 const bool expr_result, 442 void (*fail_func)(struct context *, atf_dynstr_t *)) 443 { 444 const int actual_errno = errno; 445 446 if (expr_result) { 447 if (exp_errno != actual_errno) { 448 atf_dynstr_t reason; 449 450 format_reason_fmt(&reason, file, line, "Expected errno %d, got %d, " 451 "in %s", exp_errno, actual_errno, expr_str); 452 fail_func(ctx, &reason); 453 } 454 } else { 455 atf_dynstr_t reason; 456 457 format_reason_fmt(&reason, file, line, "Expected true value in %s", 458 expr_str); 459 fail_func(ctx, &reason); 460 } 461 } 462 463 struct prog_found_pair { 464 const char *prog; 465 bool found; 466 }; 467 468 static atf_error_t 469 check_prog_in_dir(const char *dir, void *data) 470 { 471 struct prog_found_pair *pf = data; 472 atf_error_t err; 473 474 if (pf->found) 475 err = atf_no_error(); 476 else { 477 atf_fs_path_t p; 478 479 err = atf_fs_path_init_fmt(&p, "%s/%s", dir, pf->prog); 480 if (atf_is_error(err)) 481 goto out_p; 482 483 err = atf_fs_eaccess(&p, atf_fs_access_x); 484 if (!atf_is_error(err)) 485 pf->found = true; 486 else { 487 atf_error_free(err); 488 INV(!pf->found); 489 err = atf_no_error(); 490 } 491 492 out_p: 493 atf_fs_path_fini(&p); 494 } 495 496 return err; 497 } 498 499 static atf_error_t 500 check_prog(struct context *ctx, const char *prog) 501 { 502 atf_error_t err; 503 atf_fs_path_t p; 504 505 err = atf_fs_path_init_fmt(&p, "%s", prog); 506 if (atf_is_error(err)) 507 goto out; 508 509 if (atf_fs_path_is_absolute(&p)) { 510 err = atf_fs_eaccess(&p, atf_fs_access_x); 511 if (atf_is_error(err)) { 512 atf_dynstr_t reason; 513 514 atf_error_free(err); 515 atf_fs_path_fini(&p); 516 format_reason_fmt(&reason, NULL, 0, "The required program %s could " 517 "not be found", prog); 518 skip(ctx, &reason); 519 } 520 } else { 521 const char *path = atf_env_get("PATH"); 522 struct prog_found_pair pf; 523 atf_fs_path_t bp; 524 525 err = atf_fs_path_branch_path(&p, &bp); 526 if (atf_is_error(err)) 527 goto out_p; 528 529 if (strcmp(atf_fs_path_cstring(&bp), ".") != 0) { 530 atf_fs_path_fini(&bp); 531 atf_fs_path_fini(&p); 532 533 report_fatal_error("Relative paths are not allowed when searching " 534 "for a program (%s)", prog); 535 UNREACHABLE; 536 } 537 538 pf.prog = prog; 539 pf.found = false; 540 err = atf_text_for_each_word(path, ":", check_prog_in_dir, &pf); 541 if (atf_is_error(err)) 542 goto out_bp; 543 544 if (!pf.found) { 545 atf_dynstr_t reason; 546 547 atf_fs_path_fini(&bp); 548 atf_fs_path_fini(&p); 549 format_reason_fmt(&reason, NULL, 0, "The required program %s could " 550 "not be found in the PATH", prog); 551 fail_requirement(ctx, &reason); 552 } 553 554 out_bp: 555 atf_fs_path_fini(&bp); 556 } 557 558 out_p: 559 atf_fs_path_fini(&p); 560 out: 561 return err; 562 } 563 564 /* --------------------------------------------------------------------- 565 * The "atf_tc" type. 566 * --------------------------------------------------------------------- */ 567 568 struct atf_tc_impl { 569 const char *m_ident; 570 571 atf_map_t m_vars; 572 atf_map_t m_config; 573 574 atf_tc_head_t m_head; 575 atf_tc_body_t m_body; 576 atf_tc_cleanup_t m_cleanup; 577 }; 578 579 /* 580 * Constructors/destructors. 581 */ 582 583 atf_error_t 584 atf_tc_init(atf_tc_t *tc, const char *ident, atf_tc_head_t head, 585 atf_tc_body_t body, atf_tc_cleanup_t cleanup, 586 const char *const *config) 587 { 588 atf_error_t err; 589 590 tc->pimpl = malloc(sizeof(struct atf_tc_impl)); 591 if (tc->pimpl == NULL) { 592 err = atf_no_memory_error(); 593 goto err; 594 } 595 596 tc->pimpl->m_ident = ident; 597 tc->pimpl->m_head = head; 598 tc->pimpl->m_body = body; 599 tc->pimpl->m_cleanup = cleanup; 600 601 err = atf_map_init_charpp(&tc->pimpl->m_config, config); 602 if (atf_is_error(err)) 603 goto err; 604 605 err = atf_map_init(&tc->pimpl->m_vars); 606 if (atf_is_error(err)) 607 goto err_vars; 608 609 err = atf_tc_set_md_var(tc, "ident", ident); 610 if (atf_is_error(err)) 611 goto err_map; 612 613 if (cleanup != NULL) { 614 err = atf_tc_set_md_var(tc, "has.cleanup", "true"); 615 if (atf_is_error(err)) 616 goto err_map; 617 } 618 619 /* XXX Should the head be able to return error codes? */ 620 if (tc->pimpl->m_head != NULL) 621 tc->pimpl->m_head(tc); 622 623 if (strcmp(atf_tc_get_md_var(tc, "ident"), ident) != 0) { 624 report_fatal_error("Test case head modified the read-only 'ident' " 625 "property"); 626 UNREACHABLE; 627 } 628 629 INV(!atf_is_error(err)); 630 return err; 631 632 err_map: 633 atf_map_fini(&tc->pimpl->m_vars); 634 err_vars: 635 atf_map_fini(&tc->pimpl->m_config); 636 err: 637 return err; 638 } 639 640 atf_error_t 641 atf_tc_init_pack(atf_tc_t *tc, const atf_tc_pack_t *pack, 642 const char *const *config) 643 { 644 return atf_tc_init(tc, pack->m_ident, pack->m_head, pack->m_body, 645 pack->m_cleanup, config); 646 } 647 648 void 649 atf_tc_fini(atf_tc_t *tc) 650 { 651 atf_map_fini(&tc->pimpl->m_vars); 652 free(tc->pimpl); 653 } 654 655 /* 656 * Getters. 657 */ 658 659 const char * 660 atf_tc_get_ident(const atf_tc_t *tc) 661 { 662 return tc->pimpl->m_ident; 663 } 664 665 const char * 666 atf_tc_get_config_var(const atf_tc_t *tc, const char *name) 667 { 668 const char *val; 669 atf_map_citer_t iter; 670 671 PRE(atf_tc_has_config_var(tc, name)); 672 iter = atf_map_find_c(&tc->pimpl->m_config, name); 673 val = atf_map_citer_data(iter); 674 INV(val != NULL); 675 676 return val; 677 } 678 679 const char * 680 atf_tc_get_config_var_wd(const atf_tc_t *tc, const char *name, 681 const char *defval) 682 { 683 const char *val; 684 685 if (!atf_tc_has_config_var(tc, name)) 686 val = defval; 687 else 688 val = atf_tc_get_config_var(tc, name); 689 690 return val; 691 } 692 693 bool 694 atf_tc_get_config_var_as_bool(const atf_tc_t *tc, const char *name) 695 { 696 bool val; 697 const char *strval; 698 atf_error_t err; 699 700 strval = atf_tc_get_config_var(tc, name); 701 err = atf_text_to_bool(strval, &val); 702 if (atf_is_error(err)) { 703 atf_error_free(err); 704 atf_tc_fail("Configuration variable %s does not have a valid " 705 "boolean value; found %s", name, strval); 706 } 707 708 return val; 709 } 710 711 bool 712 atf_tc_get_config_var_as_bool_wd(const atf_tc_t *tc, const char *name, 713 const bool defval) 714 { 715 bool val; 716 717 if (!atf_tc_has_config_var(tc, name)) 718 val = defval; 719 else 720 val = atf_tc_get_config_var_as_bool(tc, name); 721 722 return val; 723 } 724 725 long 726 atf_tc_get_config_var_as_long(const atf_tc_t *tc, const char *name) 727 { 728 long val; 729 const char *strval; 730 atf_error_t err; 731 732 strval = atf_tc_get_config_var(tc, name); 733 err = atf_text_to_long(strval, &val); 734 if (atf_is_error(err)) { 735 atf_error_free(err); 736 atf_tc_fail("Configuration variable %s does not have a valid " 737 "long value; found %s", name, strval); 738 } 739 740 return val; 741 } 742 743 long 744 atf_tc_get_config_var_as_long_wd(const atf_tc_t *tc, const char *name, 745 const long defval) 746 { 747 long val; 748 749 if (!atf_tc_has_config_var(tc, name)) 750 val = defval; 751 else 752 val = atf_tc_get_config_var_as_long(tc, name); 753 754 return val; 755 } 756 757 const char * 758 atf_tc_get_md_var(const atf_tc_t *tc, const char *name) 759 { 760 const char *val; 761 atf_map_citer_t iter; 762 763 PRE(atf_tc_has_md_var(tc, name)); 764 iter = atf_map_find_c(&tc->pimpl->m_vars, name); 765 val = atf_map_citer_data(iter); 766 INV(val != NULL); 767 768 return val; 769 } 770 771 char ** 772 atf_tc_get_md_vars(const atf_tc_t *tc) 773 { 774 return atf_map_to_charpp(&tc->pimpl->m_vars); 775 } 776 777 bool 778 atf_tc_has_config_var(const atf_tc_t *tc, const char *name) 779 { 780 atf_map_citer_t end, iter; 781 782 iter = atf_map_find_c(&tc->pimpl->m_config, name); 783 end = atf_map_end_c(&tc->pimpl->m_config); 784 return !atf_equal_map_citer_map_citer(iter, end); 785 } 786 787 bool 788 atf_tc_has_md_var(const atf_tc_t *tc, const char *name) 789 { 790 atf_map_citer_t end, iter; 791 792 iter = atf_map_find_c(&tc->pimpl->m_vars, name); 793 end = atf_map_end_c(&tc->pimpl->m_vars); 794 return !atf_equal_map_citer_map_citer(iter, end); 795 } 796 797 /* 798 * Modifiers. 799 */ 800 801 atf_error_t 802 atf_tc_set_md_var(atf_tc_t *tc, const char *name, const char *fmt, ...) 803 { 804 atf_error_t err; 805 char *value; 806 va_list ap; 807 808 va_start(ap, fmt); 809 err = atf_text_format_ap(&value, fmt, ap); 810 va_end(ap); 811 812 if (!atf_is_error(err)) 813 err = atf_map_insert(&tc->pimpl->m_vars, name, value, true); 814 else 815 free(value); 816 817 return err; 818 } 819 820 /* --------------------------------------------------------------------- 821 * Free functions, as they should be publicly but they can't. 822 * --------------------------------------------------------------------- */ 823 824 static void _atf_tc_fail(struct context *, const char *, va_list) 825 ATF_DEFS_ATTRIBUTE_NORETURN; 826 static void _atf_tc_fail_nonfatal(struct context *, const char *, va_list); 827 static void _atf_tc_fail_check(struct context *, const char *, const size_t, 828 const char *, va_list); 829 static void _atf_tc_fail_requirement(struct context *, const char *, 830 const size_t, const char *, va_list) ATF_DEFS_ATTRIBUTE_NORETURN; 831 static void _atf_tc_pass(struct context *) ATF_DEFS_ATTRIBUTE_NORETURN; 832 static void _atf_tc_require_prog(struct context *, const char *); 833 static void _atf_tc_skip(struct context *, const char *, va_list) 834 ATF_DEFS_ATTRIBUTE_NORETURN; 835 static void _atf_tc_check_errno(struct context *, const char *, const size_t, 836 const int, const char *, const bool); 837 static void _atf_tc_require_errno(struct context *, const char *, const size_t, 838 const int, const char *, const bool); 839 static void _atf_tc_expect_pass(struct context *); 840 static void _atf_tc_expect_fail(struct context *, const char *, va_list); 841 static void _atf_tc_expect_exit(struct context *, const int, const char *, 842 va_list); 843 static void _atf_tc_expect_signal(struct context *, const int, const char *, 844 va_list); 845 static void _atf_tc_expect_death(struct context *, const char *, 846 va_list); 847 848 static void 849 _atf_tc_fail(struct context *ctx, const char *fmt, va_list ap) 850 { 851 va_list ap2; 852 atf_dynstr_t reason; 853 854 va_copy(ap2, ap); 855 format_reason_ap(&reason, NULL, 0, fmt, ap2); 856 va_end(ap2); 857 858 fail_requirement(ctx, &reason); 859 UNREACHABLE; 860 } 861 862 static void 863 _atf_tc_fail_nonfatal(struct context *ctx, const char *fmt, va_list ap) 864 { 865 va_list ap2; 866 atf_dynstr_t reason; 867 868 va_copy(ap2, ap); 869 format_reason_ap(&reason, NULL, 0, fmt, ap2); 870 va_end(ap2); 871 872 fail_check(ctx, &reason); 873 } 874 875 static void 876 _atf_tc_fail_check(struct context *ctx, const char *file, const size_t line, 877 const char *fmt, va_list ap) 878 { 879 va_list ap2; 880 atf_dynstr_t reason; 881 882 va_copy(ap2, ap); 883 format_reason_ap(&reason, file, line, fmt, ap2); 884 va_end(ap2); 885 886 fail_check(ctx, &reason); 887 } 888 889 static void 890 _atf_tc_fail_requirement(struct context *ctx, const char *file, 891 const size_t line, const char *fmt, va_list ap) 892 { 893 va_list ap2; 894 atf_dynstr_t reason; 895 896 va_copy(ap2, ap); 897 format_reason_ap(&reason, file, line, fmt, ap2); 898 va_end(ap2); 899 900 fail_requirement(ctx, &reason); 901 UNREACHABLE; 902 } 903 904 static void 905 _atf_tc_pass(struct context *ctx) 906 { 907 pass(ctx); 908 UNREACHABLE; 909 } 910 911 static void 912 _atf_tc_require_prog(struct context *ctx, const char *prog) 913 { 914 check_fatal_error(check_prog(ctx, prog)); 915 } 916 917 static void 918 _atf_tc_skip(struct context *ctx, const char *fmt, va_list ap) 919 { 920 atf_dynstr_t reason; 921 va_list ap2; 922 923 va_copy(ap2, ap); 924 format_reason_ap(&reason, NULL, 0, fmt, ap2); 925 va_end(ap2); 926 927 skip(ctx, &reason); 928 } 929 930 static void 931 _atf_tc_check_errno(struct context *ctx, const char *file, const size_t line, 932 const int exp_errno, const char *expr_str, 933 const bool expr_result) 934 { 935 errno_test(ctx, file, line, exp_errno, expr_str, expr_result, fail_check); 936 } 937 938 static void 939 _atf_tc_require_errno(struct context *ctx, const char *file, const size_t line, 940 const int exp_errno, const char *expr_str, 941 const bool expr_result) 942 { 943 errno_test(ctx, file, line, exp_errno, expr_str, expr_result, 944 fail_requirement); 945 } 946 947 static void 948 _atf_tc_expect_pass(struct context *ctx) 949 { 950 validate_expect(ctx); 951 952 ctx->expect = EXPECT_PASS; 953 } 954 955 static void 956 _atf_tc_expect_fail(struct context *ctx, const char *reason, va_list ap) 957 { 958 va_list ap2; 959 960 validate_expect(ctx); 961 962 ctx->expect = EXPECT_FAIL; 963 atf_dynstr_fini(&ctx->expect_reason); 964 va_copy(ap2, ap); 965 check_fatal_error(atf_dynstr_init_ap(&ctx->expect_reason, reason, ap2)); 966 va_end(ap2); 967 ctx->expect_previous_fail_count = ctx->expect_fail_count; 968 } 969 970 static void 971 _atf_tc_expect_exit(struct context *ctx, const int exitcode, const char *reason, 972 va_list ap) 973 { 974 va_list ap2; 975 atf_dynstr_t formatted; 976 977 validate_expect(ctx); 978 979 ctx->expect = EXPECT_EXIT; 980 va_copy(ap2, ap); 981 check_fatal_error(atf_dynstr_init_ap(&formatted, reason, ap2)); 982 va_end(ap2); 983 984 create_resfile(ctx, "expected_exit", exitcode, &formatted); 985 } 986 987 static void 988 _atf_tc_expect_signal(struct context *ctx, const int signo, const char *reason, 989 va_list ap) 990 { 991 va_list ap2; 992 atf_dynstr_t formatted; 993 994 validate_expect(ctx); 995 996 ctx->expect = EXPECT_SIGNAL; 997 va_copy(ap2, ap); 998 check_fatal_error(atf_dynstr_init_ap(&formatted, reason, ap2)); 999 va_end(ap2); 1000 1001 create_resfile(ctx, "expected_signal", signo, &formatted); 1002 } 1003 1004 static void 1005 _atf_tc_expect_death(struct context *ctx, const char *reason, va_list ap) 1006 { 1007 va_list ap2; 1008 atf_dynstr_t formatted; 1009 1010 validate_expect(ctx); 1011 1012 ctx->expect = EXPECT_DEATH; 1013 va_copy(ap2, ap); 1014 check_fatal_error(atf_dynstr_init_ap(&formatted, reason, ap2)); 1015 va_end(ap2); 1016 1017 create_resfile(ctx, "expected_death", -1, &formatted); 1018 } 1019 1020 static void 1021 _atf_tc_expect_timeout(struct context *ctx, const char *reason, va_list ap) 1022 { 1023 va_list ap2; 1024 atf_dynstr_t formatted; 1025 1026 validate_expect(ctx); 1027 1028 ctx->expect = EXPECT_TIMEOUT; 1029 va_copy(ap2, ap); 1030 check_fatal_error(atf_dynstr_init_ap(&formatted, reason, ap2)); 1031 va_end(ap2); 1032 1033 create_resfile(ctx, "expected_timeout", -1, &formatted); 1034 } 1035 1036 static void 1037 _atf_tc_set_resultsfile(struct context *ctx, const char *file) 1038 { 1039 1040 context_set_resfile(ctx, file); 1041 } 1042 1043 /* --------------------------------------------------------------------- 1044 * Free functions. 1045 * --------------------------------------------------------------------- */ 1046 1047 static struct context Current; 1048 1049 atf_error_t 1050 atf_tc_run(const atf_tc_t *tc, const char *resfile) 1051 { 1052 context_init(&Current, tc, resfile); 1053 1054 tc->pimpl->m_body(tc); 1055 1056 validate_expect(&Current); 1057 1058 if (Current.fail_count > 0) { 1059 atf_dynstr_t reason; 1060 1061 format_reason_fmt(&reason, NULL, 0, "%d checks failed; see output for " 1062 "more details", Current.fail_count); 1063 fail_requirement(&Current, &reason); 1064 } else if (Current.expect_fail_count > 0) { 1065 atf_dynstr_t reason; 1066 1067 format_reason_fmt(&reason, NULL, 0, "%d checks failed as expected; " 1068 "see output for more details", Current.expect_fail_count); 1069 expected_failure(&Current, &reason); 1070 } else { 1071 pass(&Current); 1072 } 1073 UNREACHABLE; 1074 return atf_no_error(); 1075 } 1076 1077 atf_error_t 1078 atf_tc_cleanup(const atf_tc_t *tc) 1079 { 1080 if (tc->pimpl->m_cleanup != NULL) 1081 tc->pimpl->m_cleanup(tc); 1082 return atf_no_error(); /* XXX */ 1083 } 1084 1085 /* --------------------------------------------------------------------- 1086 * Free functions that depend on Current. 1087 * --------------------------------------------------------------------- */ 1088 1089 /* 1090 * All the functions below provide delegates to other internal functions 1091 * (prefixed by _) that take the current test case as an argument to 1092 * prevent them from accessing global state. This is to keep the side- 1093 * effects of the internal functions clearer and easier to understand. 1094 * 1095 * The public API should never have hid the fact that it needs access to 1096 * the current test case (other than maybe in the macros), but changing it 1097 * is hard. TODO: Revisit in the future. 1098 */ 1099 1100 void 1101 atf_tc_fail(const char *fmt, ...) 1102 { 1103 va_list ap; 1104 1105 PRE(Current.tc != NULL); 1106 1107 va_start(ap, fmt); 1108 _atf_tc_fail(&Current, fmt, ap); 1109 va_end(ap); 1110 } 1111 1112 void 1113 atf_tc_fail_nonfatal(const char *fmt, ...) 1114 { 1115 va_list ap; 1116 1117 PRE(Current.tc != NULL); 1118 1119 va_start(ap, fmt); 1120 _atf_tc_fail_nonfatal(&Current, fmt, ap); 1121 va_end(ap); 1122 } 1123 1124 void 1125 atf_tc_fail_check(const char *file, const size_t line, const char *fmt, ...) 1126 { 1127 va_list ap; 1128 1129 PRE(Current.tc != NULL); 1130 1131 va_start(ap, fmt); 1132 _atf_tc_fail_check(&Current, file, line, fmt, ap); 1133 va_end(ap); 1134 } 1135 1136 void 1137 atf_tc_fail_requirement(const char *file, const size_t line, 1138 const char *fmt, ...) 1139 { 1140 va_list ap; 1141 1142 PRE(Current.tc != NULL); 1143 1144 va_start(ap, fmt); 1145 _atf_tc_fail_requirement(&Current, file, line, fmt, ap); 1146 va_end(ap); 1147 } 1148 1149 void 1150 atf_tc_pass(void) 1151 { 1152 PRE(Current.tc != NULL); 1153 1154 _atf_tc_pass(&Current); 1155 } 1156 1157 void 1158 atf_tc_require_prog(const char *prog) 1159 { 1160 PRE(Current.tc != NULL); 1161 1162 _atf_tc_require_prog(&Current, prog); 1163 } 1164 1165 void 1166 atf_tc_skip(const char *fmt, ...) 1167 { 1168 va_list ap; 1169 1170 PRE(Current.tc != NULL); 1171 1172 va_start(ap, fmt); 1173 _atf_tc_skip(&Current, fmt, ap); 1174 va_end(ap); 1175 } 1176 1177 void 1178 atf_tc_check_errno(const char *file, const size_t line, const int exp_errno, 1179 const char *expr_str, const bool expr_result) 1180 { 1181 PRE(Current.tc != NULL); 1182 1183 _atf_tc_check_errno(&Current, file, line, exp_errno, expr_str, 1184 expr_result); 1185 } 1186 1187 void 1188 atf_tc_require_errno(const char *file, const size_t line, const int exp_errno, 1189 const char *expr_str, const bool expr_result) 1190 { 1191 PRE(Current.tc != NULL); 1192 1193 _atf_tc_require_errno(&Current, file, line, exp_errno, expr_str, 1194 expr_result); 1195 } 1196 1197 void 1198 atf_tc_expect_pass(void) 1199 { 1200 PRE(Current.tc != NULL); 1201 1202 _atf_tc_expect_pass(&Current); 1203 } 1204 1205 void 1206 atf_tc_expect_fail(const char *reason, ...) 1207 { 1208 va_list ap; 1209 1210 PRE(Current.tc != NULL); 1211 1212 va_start(ap, reason); 1213 _atf_tc_expect_fail(&Current, reason, ap); 1214 va_end(ap); 1215 } 1216 1217 void 1218 atf_tc_expect_exit(const int exitcode, const char *reason, ...) 1219 { 1220 va_list ap; 1221 1222 PRE(Current.tc != NULL); 1223 1224 va_start(ap, reason); 1225 _atf_tc_expect_exit(&Current, exitcode, reason, ap); 1226 va_end(ap); 1227 } 1228 1229 void 1230 atf_tc_expect_signal(const int signo, const char *reason, ...) 1231 { 1232 va_list ap; 1233 1234 PRE(Current.tc != NULL); 1235 1236 va_start(ap, reason); 1237 _atf_tc_expect_signal(&Current, signo, reason, ap); 1238 va_end(ap); 1239 } 1240 1241 void 1242 atf_tc_expect_death(const char *reason, ...) 1243 { 1244 va_list ap; 1245 1246 PRE(Current.tc != NULL); 1247 1248 va_start(ap, reason); 1249 _atf_tc_expect_death(&Current, reason, ap); 1250 va_end(ap); 1251 } 1252 1253 void 1254 atf_tc_expect_timeout(const char *reason, ...) 1255 { 1256 va_list ap; 1257 1258 PRE(Current.tc != NULL); 1259 1260 va_start(ap, reason); 1261 _atf_tc_expect_timeout(&Current, reason, ap); 1262 va_end(ap); 1263 } 1264 1265 /* Internal! */ 1266 void 1267 atf_tc_set_resultsfile(const char *file) 1268 { 1269 1270 PRE(Current.tc != NULL); 1271 1272 _atf_tc_set_resultsfile(&Current, file); 1273 } 1274