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