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 54enum expect_type { 55 EXPECT_PASS, 56 EXPECT_FAIL, 57 EXPECT_EXIT, 58 EXPECT_SIGNAL, 59 EXPECT_DEATH, 60 EXPECT_TIMEOUT, 61}; 62 63struct 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 77static void context_init(struct context *, const atf_tc_t *, const char *); 78static void context_set_resfile(struct context *, const char *); 79static void context_close_resfile(struct context *); 80static void check_fatal_error(atf_error_t); 81static void report_fatal_error(const char *, ...) 82 ATF_DEFS_ATTRIBUTE_NORETURN; 83static atf_error_t write_resfile(const int, const char *, const int, 84 const atf_dynstr_t *); 85static void create_resfile(struct context *, const char *, const int, 86 atf_dynstr_t *); 87static void error_in_expect(struct context *, const char *, ...) 88 ATF_DEFS_ATTRIBUTE_NORETURN; 89static void validate_expect(struct context *); 90static void expected_failure(struct context *, atf_dynstr_t *) 91 ATF_DEFS_ATTRIBUTE_NORETURN; 92static void fail_requirement(struct context *, atf_dynstr_t *) 93 ATF_DEFS_ATTRIBUTE_NORETURN; 94static void fail_check(struct context *, atf_dynstr_t *); 95static void pass(struct context *) 96 ATF_DEFS_ATTRIBUTE_NORETURN; 97static void skip(struct context *, atf_dynstr_t *) 98 ATF_DEFS_ATTRIBUTE_NORETURN; 99static void format_reason_ap(atf_dynstr_t *, const char *, const size_t, 100 const char *, va_list); 101static void format_reason_fmt(atf_dynstr_t *, const char *, const size_t, 102 const char *, ...); 103static void errno_test(struct context *, const char *, const size_t, 104 const int, const char *, const bool, 105 void (*)(struct context *, atf_dynstr_t *)); 106static atf_error_t check_prog_in_dir(const char *, void *); 107static atf_error_t check_prog(struct context *, const char *); 108 109/* No prototype in header for this one, it's a little sketchy (internal). */ 110void atf_tc_set_resultsfile(const char *); 111 112static void 113context_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 128static void 129context_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 151static void 152context_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 163static void 164check_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 175static void 176report_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 */ 196static atf_error_t 197write_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 */ 248static void 249create_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. */ 274static void 275error_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 */ 292static void 293validate_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 319static void 320expected_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 329static void 330fail_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 345static void 346fail_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 364static void 365pass(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 381static void 382skip(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 */ 401static void 402format_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 426static void 427format_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 438static void 439errno_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 463struct prog_found_pair { 464 const char *prog; 465 bool found; 466}; 467 468static atf_error_t 469check_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 492out_p: 493 atf_fs_path_fini(&p); 494 } 495 496 return err; 497} 498 499static atf_error_t 500check_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 554out_bp: 555 atf_fs_path_fini(&bp); 556 } 557 558out_p: 559 atf_fs_path_fini(&p); 560out: 561 return err; 562} 563 564/* --------------------------------------------------------------------- 565 * The "atf_tc" type. 566 * --------------------------------------------------------------------- */ 567 568struct 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 583atf_error_t 584atf_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 632err_map: 633 atf_map_fini(&tc->pimpl->m_vars); 634err_vars: 635 atf_map_fini(&tc->pimpl->m_config); 636err: 637 return err; 638} 639 640atf_error_t 641atf_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 648void 649atf_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 659const char * 660atf_tc_get_ident(const atf_tc_t *tc) 661{ 662 return tc->pimpl->m_ident; 663} 664 665const char * 666atf_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 679const char * 680atf_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 693bool 694atf_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 711bool 712atf_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 725long 726atf_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 743long 744atf_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 757const char * 758atf_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 771char ** 772atf_tc_get_md_vars(const atf_tc_t *tc) 773{ 774 return atf_map_to_charpp(&tc->pimpl->m_vars); 775} 776 777bool 778atf_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 787bool 788atf_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 801atf_error_t 802atf_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 824static void _atf_tc_fail(struct context *, const char *, va_list) 825 ATF_DEFS_ATTRIBUTE_NORETURN; 826static void _atf_tc_fail_nonfatal(struct context *, const char *, va_list); 827static void _atf_tc_fail_check(struct context *, const char *, const size_t, 828 const char *, va_list); 829static void _atf_tc_fail_requirement(struct context *, const char *, 830 const size_t, const char *, va_list) ATF_DEFS_ATTRIBUTE_NORETURN; 831static void _atf_tc_pass(struct context *) ATF_DEFS_ATTRIBUTE_NORETURN; 832static void _atf_tc_require_prog(struct context *, const char *); 833static void _atf_tc_skip(struct context *, const char *, va_list) 834 ATF_DEFS_ATTRIBUTE_NORETURN; 835static void _atf_tc_check_errno(struct context *, const char *, const size_t, 836 const int, const char *, const bool); 837static void _atf_tc_require_errno(struct context *, const char *, const size_t, 838 const int, const char *, const bool); 839static void _atf_tc_expect_pass(struct context *); 840static void _atf_tc_expect_fail(struct context *, const char *, va_list); 841static void _atf_tc_expect_exit(struct context *, const int, const char *, 842 va_list); 843static void _atf_tc_expect_signal(struct context *, const int, const char *, 844 va_list); 845static void _atf_tc_expect_death(struct context *, const char *, 846 va_list); 847 848static 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 862static 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 875static 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 889static 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 904static void 905_atf_tc_pass(struct context *ctx) 906{ 907 pass(ctx); 908 UNREACHABLE; 909} 910 911static void 912_atf_tc_require_prog(struct context *ctx, const char *prog) 913{ 914 check_fatal_error(check_prog(ctx, prog)); 915} 916 917static 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 930static 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 938static 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 947static void 948_atf_tc_expect_pass(struct context *ctx) 949{ 950 validate_expect(ctx); 951 952 ctx->expect = EXPECT_PASS; 953} 954 955static 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 970static 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 987static 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 1004static 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 1020static 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 1036static 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 1047static struct context Current; 1048 1049atf_error_t 1050atf_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 1077atf_error_t 1078atf_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 1100void 1101atf_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 1112void 1113atf_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 1124void 1125atf_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 1136void 1137atf_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 1149void 1150atf_tc_pass(void) 1151{ 1152 PRE(Current.tc != NULL); 1153 1154 _atf_tc_pass(&Current); 1155} 1156 1157void 1158atf_tc_require_prog(const char *prog) 1159{ 1160 PRE(Current.tc != NULL); 1161 1162 _atf_tc_require_prog(&Current, prog); 1163} 1164 1165void 1166atf_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 1177void 1178atf_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 1187void 1188atf_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 1197void 1198atf_tc_expect_pass(void) 1199{ 1200 PRE(Current.tc != NULL); 1201 1202 _atf_tc_expect_pass(&Current); 1203} 1204 1205void 1206atf_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 1217void 1218atf_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 1229void 1230atf_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 1241void 1242atf_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 1253void 1254atf_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! */ 1266void 1267atf_tc_set_resultsfile(const char *file) 1268{ 1269 1270 PRE(Current.tc != NULL); 1271 1272 _atf_tc_set_resultsfile(&Current, file); 1273} 1274