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 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 */ 407static void 408format_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 432static void 433format_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 444static void 445errno_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 469struct prog_found_pair { 470 const char *prog; 471 bool found; 472}; 473 474static atf_error_t 475check_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 498out_p: 499 atf_fs_path_fini(&p); 500 } 501 502 return err; 503} 504 505static atf_error_t 506check_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 560out_bp: 561 atf_fs_path_fini(&bp); 562 } 563 564out_p: 565 atf_fs_path_fini(&p); 566out: 567 return err; 568} 569 570/* --------------------------------------------------------------------- 571 * The "atf_tc" type. 572 * --------------------------------------------------------------------- */ 573 574struct 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 589atf_error_t 590atf_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 638err_map: 639 atf_map_fini(&tc->pimpl->m_vars); 640err_vars: 641 atf_map_fini(&tc->pimpl->m_config); 642err: 643 return err; 644} 645 646atf_error_t 647atf_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 654void 655atf_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 665const char * 666atf_tc_get_ident(const atf_tc_t *tc) 667{ 668 return tc->pimpl->m_ident; 669} 670 671const char * 672atf_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 685const char * 686atf_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 699bool 700atf_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 717bool 718atf_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 731long 732atf_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 749long 750atf_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 763const char * 764atf_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 777char ** 778atf_tc_get_md_vars(const atf_tc_t *tc) 779{ 780 return atf_map_to_charpp(&tc->pimpl->m_vars); 781} 782 783bool 784atf_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 793bool 794atf_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 807atf_error_t 808atf_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 830static void _atf_tc_fail(struct context *, const char *, va_list) 831 ATF_DEFS_ATTRIBUTE_NORETURN; 832static void _atf_tc_fail_nonfatal(struct context *, const char *, va_list); 833static void _atf_tc_fail_check(struct context *, const char *, const size_t, 834 const char *, va_list); 835static void _atf_tc_fail_requirement(struct context *, const char *, 836 const size_t, const char *, va_list) ATF_DEFS_ATTRIBUTE_NORETURN; 837static void _atf_tc_pass(struct context *) ATF_DEFS_ATTRIBUTE_NORETURN; 838static void _atf_tc_require_prog(struct context *, const char *); 839static void _atf_tc_skip(struct context *, const char *, va_list) 840 ATF_DEFS_ATTRIBUTE_NORETURN; 841static void _atf_tc_check_errno(struct context *, const char *, const size_t, 842 const int, const char *, const bool); 843static void _atf_tc_require_errno(struct context *, const char *, const size_t, 844 const int, const char *, const bool); 845static void _atf_tc_expect_pass(struct context *); 846static void _atf_tc_expect_fail(struct context *, const char *, va_list); 847static void _atf_tc_expect_exit(struct context *, const int, const char *, 848 va_list); 849static void _atf_tc_expect_signal(struct context *, const int, const char *, 850 va_list); 851static void _atf_tc_expect_death(struct context *, const char *, 852 va_list); 853 854static 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 868static 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 881static 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 895static 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 910static void 911_atf_tc_pass(struct context *ctx) 912{ 913 pass(ctx); 914 UNREACHABLE; 915} 916 917static void 918_atf_tc_require_prog(struct context *ctx, const char *prog) 919{ 920 check_fatal_error(check_prog(ctx, prog)); 921} 922 923static 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 936static 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 944static 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 953static void 954_atf_tc_expect_pass(struct context *ctx) 955{ 956 validate_expect(ctx); 957 958 ctx->expect = EXPECT_PASS; 959} 960 961static 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 976static 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 993static 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 1010static 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 1026static 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 1042static 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 1053static struct context Current; 1054 1055atf_error_t 1056atf_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 1083atf_error_t 1084atf_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 1106void 1107atf_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 1118void 1119atf_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 1130void 1131atf_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 1142void 1143atf_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 1155void 1156atf_tc_pass(void) 1157{ 1158 PRE(Current.tc != NULL); 1159 1160 _atf_tc_pass(&Current); 1161} 1162 1163void 1164atf_tc_require_prog(const char *prog) 1165{ 1166 PRE(Current.tc != NULL); 1167 1168 _atf_tc_require_prog(&Current, prog); 1169} 1170 1171void 1172atf_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 1183void 1184atf_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 1193void 1194atf_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 1203void 1204atf_tc_expect_pass(void) 1205{ 1206 PRE(Current.tc != NULL); 1207 1208 _atf_tc_expect_pass(&Current); 1209} 1210 1211void 1212atf_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 1223void 1224atf_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 1235void 1236atf_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 1247void 1248atf_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 1259void 1260atf_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! */ 1272void 1273atf_tc_set_resultsfile(const char *file) 1274{ 1275 1276 PRE(Current.tc != NULL); 1277 1278 _atf_tc_set_resultsfile(&Current, file); 1279} 1280