1275988Sngie/* Copyright (c) 2008 The NetBSD Foundation, Inc. 2240116Smarcel * All rights reserved. 3240116Smarcel * 4240116Smarcel * Redistribution and use in source and binary forms, with or without 5240116Smarcel * modification, are permitted provided that the following conditions 6240116Smarcel * are met: 7240116Smarcel * 1. Redistributions of source code must retain the above copyright 8240116Smarcel * notice, this list of conditions and the following disclaimer. 9240116Smarcel * 2. Redistributions in binary form must reproduce the above copyright 10240116Smarcel * notice, this list of conditions and the following disclaimer in the 11240116Smarcel * documentation and/or other materials provided with the distribution. 12240116Smarcel * 13240116Smarcel * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND 14240116Smarcel * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, 15240116Smarcel * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 16240116Smarcel * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 17240116Smarcel * IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY 18240116Smarcel * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19240116Smarcel * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 20240116Smarcel * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 21240116Smarcel * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER 22240116Smarcel * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 23240116Smarcel * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN 24275988Sngie * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ 25240116Smarcel 26275988Sngie#include "atf-c/tc.h" 27275988Sngie 28240116Smarcel#include <sys/types.h> 29240116Smarcel#include <sys/stat.h> 30240116Smarcel#include <sys/uio.h> 31240116Smarcel 32240116Smarcel#include <errno.h> 33240116Smarcel#include <fcntl.h> 34240116Smarcel#include <stdarg.h> 35240116Smarcel#include <stdbool.h> 36240116Smarcel#include <stdio.h> 37240116Smarcel#include <stdlib.h> 38240116Smarcel#include <string.h> 39240116Smarcel#include <unistd.h> 40240116Smarcel 41240116Smarcel#include "atf-c/defs.h" 42275988Sngie#include "atf-c/detail/env.h" 43275988Sngie#include "atf-c/detail/fs.h" 44275988Sngie#include "atf-c/detail/map.h" 45275988Sngie#include "atf-c/detail/sanity.h" 46275988Sngie#include "atf-c/detail/text.h" 47240116Smarcel#include "atf-c/error.h" 48240116Smarcel 49240116Smarcel/* --------------------------------------------------------------------- 50240116Smarcel * Auxiliary functions. 51240116Smarcel * --------------------------------------------------------------------- */ 52240116Smarcel 53240116Smarcelenum expect_type { 54240116Smarcel EXPECT_PASS, 55240116Smarcel EXPECT_FAIL, 56240116Smarcel EXPECT_EXIT, 57240116Smarcel EXPECT_SIGNAL, 58240116Smarcel EXPECT_DEATH, 59240116Smarcel EXPECT_TIMEOUT, 60240116Smarcel}; 61240116Smarcel 62240116Smarcelstruct context { 63240116Smarcel const atf_tc_t *tc; 64240116Smarcel const char *resfile; 65240116Smarcel size_t fail_count; 66240116Smarcel 67240116Smarcel enum expect_type expect; 68240116Smarcel atf_dynstr_t expect_reason; 69240116Smarcel size_t expect_previous_fail_count; 70240116Smarcel size_t expect_fail_count; 71240116Smarcel int expect_exitcode; 72240116Smarcel int expect_signo; 73240116Smarcel}; 74240116Smarcel 75240116Smarcelstatic void context_init(struct context *, const atf_tc_t *, const char *); 76240116Smarcelstatic void check_fatal_error(atf_error_t); 77240116Smarcelstatic void report_fatal_error(const char *, ...) 78240116Smarcel ATF_DEFS_ATTRIBUTE_NORETURN; 79240116Smarcelstatic atf_error_t write_resfile(const int, const char *, const int, 80240116Smarcel const atf_dynstr_t *); 81240116Smarcelstatic void create_resfile(const char *, const char *, const int, 82240116Smarcel atf_dynstr_t *); 83240116Smarcelstatic void error_in_expect(struct context *, const char *, ...) 84240116Smarcel ATF_DEFS_ATTRIBUTE_NORETURN; 85240116Smarcelstatic void validate_expect(struct context *); 86240116Smarcelstatic void expected_failure(struct context *, atf_dynstr_t *) 87240116Smarcel ATF_DEFS_ATTRIBUTE_NORETURN; 88240116Smarcelstatic void fail_requirement(struct context *, atf_dynstr_t *) 89240116Smarcel ATF_DEFS_ATTRIBUTE_NORETURN; 90240116Smarcelstatic void fail_check(struct context *, atf_dynstr_t *); 91240116Smarcelstatic void pass(struct context *) 92240116Smarcel ATF_DEFS_ATTRIBUTE_NORETURN; 93240116Smarcelstatic void skip(struct context *, atf_dynstr_t *) 94240116Smarcel ATF_DEFS_ATTRIBUTE_NORETURN; 95240116Smarcelstatic void format_reason_ap(atf_dynstr_t *, const char *, const size_t, 96240116Smarcel const char *, va_list); 97240116Smarcelstatic void format_reason_fmt(atf_dynstr_t *, const char *, const size_t, 98240116Smarcel const char *, ...); 99240116Smarcelstatic void errno_test(struct context *, const char *, const size_t, 100240116Smarcel const int, const char *, const bool, 101240116Smarcel void (*)(struct context *, atf_dynstr_t *)); 102240116Smarcelstatic atf_error_t check_prog_in_dir(const char *, void *); 103240116Smarcelstatic atf_error_t check_prog(struct context *, const char *); 104240116Smarcel 105240116Smarcelstatic void 106240116Smarcelcontext_init(struct context *ctx, const atf_tc_t *tc, const char *resfile) 107240116Smarcel{ 108240116Smarcel ctx->tc = tc; 109240116Smarcel ctx->resfile = resfile; 110240116Smarcel ctx->fail_count = 0; 111240116Smarcel ctx->expect = EXPECT_PASS; 112240116Smarcel check_fatal_error(atf_dynstr_init(&ctx->expect_reason)); 113240116Smarcel ctx->expect_previous_fail_count = 0; 114240116Smarcel ctx->expect_fail_count = 0; 115240116Smarcel ctx->expect_exitcode = 0; 116240116Smarcel ctx->expect_signo = 0; 117240116Smarcel} 118240116Smarcel 119240116Smarcelstatic void 120240116Smarcelcheck_fatal_error(atf_error_t err) 121240116Smarcel{ 122240116Smarcel if (atf_is_error(err)) { 123240116Smarcel char buf[1024]; 124240116Smarcel atf_error_format(err, buf, sizeof(buf)); 125240116Smarcel fprintf(stderr, "FATAL ERROR: %s\n", buf); 126240116Smarcel atf_error_free(err); 127240116Smarcel abort(); 128240116Smarcel } 129240116Smarcel} 130240116Smarcel 131240116Smarcelstatic void 132240116Smarcelreport_fatal_error(const char *msg, ...) 133240116Smarcel{ 134240116Smarcel va_list ap; 135240116Smarcel fprintf(stderr, "FATAL ERROR: "); 136240116Smarcel 137240116Smarcel va_start(ap, msg); 138240116Smarcel vfprintf(stderr, msg, ap); 139240116Smarcel va_end(ap); 140240116Smarcel 141240116Smarcel fprintf(stderr, "\n"); 142240116Smarcel abort(); 143240116Smarcel} 144240116Smarcel 145240116Smarcel/** Writes to a results file. 146240116Smarcel * 147240116Smarcel * The results file is supposed to be already open. 148240116Smarcel * 149240116Smarcel * This function returns an error code instead of exiting in case of error 150240116Smarcel * because the caller needs to clean up the reason object before terminating. 151240116Smarcel */ 152240116Smarcelstatic atf_error_t 153240116Smarcelwrite_resfile(const int fd, const char *result, const int arg, 154240116Smarcel const atf_dynstr_t *reason) 155240116Smarcel{ 156240116Smarcel static char NL[] = "\n", CS[] = ": "; 157240116Smarcel char buf[64]; 158240116Smarcel const char *r; 159240116Smarcel struct iovec iov[5]; 160240116Smarcel ssize_t ret; 161240116Smarcel int count = 0; 162240116Smarcel 163240116Smarcel INV(arg == -1 || reason != NULL); 164240116Smarcel 165240116Smarcel#define UNCONST(a) ((void *)(unsigned long)(const void *)(a)) 166240116Smarcel iov[count].iov_base = UNCONST(result); 167240116Smarcel iov[count++].iov_len = strlen(result); 168240116Smarcel 169240116Smarcel if (reason != NULL) { 170240116Smarcel if (arg != -1) { 171240116Smarcel iov[count].iov_base = buf; 172240116Smarcel iov[count++].iov_len = snprintf(buf, sizeof(buf), "(%d)", arg); 173240116Smarcel } 174240116Smarcel 175240116Smarcel iov[count].iov_base = CS; 176240116Smarcel iov[count++].iov_len = sizeof(CS) - 1; 177240116Smarcel 178240116Smarcel r = atf_dynstr_cstring(reason); 179240116Smarcel iov[count].iov_base = UNCONST(r); 180240116Smarcel iov[count++].iov_len = strlen(r); 181240116Smarcel } 182240116Smarcel#undef UNCONST 183240116Smarcel 184240116Smarcel iov[count].iov_base = NL; 185240116Smarcel iov[count++].iov_len = sizeof(NL) - 1; 186240116Smarcel 187240116Smarcel while ((ret = writev(fd, iov, count)) == -1 && errno == EINTR) 188240116Smarcel continue; /* Retry. */ 189240116Smarcel if (ret != -1) 190240116Smarcel return atf_no_error(); 191240116Smarcel 192240116Smarcel return atf_libc_error( 193240116Smarcel errno, "Failed to write results file; result %s, reason %s", result, 194240116Smarcel reason == NULL ? "null" : atf_dynstr_cstring(reason)); 195240116Smarcel} 196240116Smarcel 197240116Smarcel/** Creates a results file. 198240116Smarcel * 199240116Smarcel * The input reason is released in all cases. 200240116Smarcel * 201240116Smarcel * An error in this function is considered to be fatal, hence why it does 202240116Smarcel * not return any error code. 203240116Smarcel */ 204240116Smarcelstatic void 205240116Smarcelcreate_resfile(const char *resfile, const char *result, const int arg, 206240116Smarcel atf_dynstr_t *reason) 207240116Smarcel{ 208240116Smarcel atf_error_t err; 209240116Smarcel 210240116Smarcel if (strcmp("/dev/stdout", resfile) == 0) { 211240116Smarcel err = write_resfile(STDOUT_FILENO, result, arg, reason); 212240116Smarcel } else if (strcmp("/dev/stderr", resfile) == 0) { 213240116Smarcel err = write_resfile(STDERR_FILENO, result, arg, reason); 214240116Smarcel } else { 215240116Smarcel const int fd = open(resfile, O_WRONLY | O_CREAT | O_TRUNC, 216240116Smarcel S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); 217240116Smarcel if (fd == -1) { 218240116Smarcel err = atf_libc_error(errno, "Cannot create results file '%s'", 219240116Smarcel resfile); 220240116Smarcel } else { 221240116Smarcel err = write_resfile(fd, result, arg, reason); 222240116Smarcel close(fd); 223240116Smarcel } 224240116Smarcel } 225240116Smarcel 226240116Smarcel if (reason != NULL) 227240116Smarcel atf_dynstr_fini(reason); 228240116Smarcel 229240116Smarcel check_fatal_error(err); 230240116Smarcel} 231240116Smarcel 232240116Smarcel/** Fails a test case if validate_expect fails. */ 233240116Smarcelstatic void 234240116Smarcelerror_in_expect(struct context *ctx, const char *fmt, ...) 235240116Smarcel{ 236240116Smarcel atf_dynstr_t reason; 237240116Smarcel va_list ap; 238240116Smarcel 239240116Smarcel va_start(ap, fmt); 240240116Smarcel format_reason_ap(&reason, NULL, 0, fmt, ap); 241240116Smarcel va_end(ap); 242240116Smarcel 243240116Smarcel ctx->expect = EXPECT_PASS; /* Ensure fail_requirement really fails. */ 244240116Smarcel fail_requirement(ctx, &reason); 245240116Smarcel} 246240116Smarcel 247240116Smarcel/** Ensures that the "expect" state is correct. 248240116Smarcel * 249240116Smarcel * Call this function before modifying the current value of expect. 250240116Smarcel */ 251240116Smarcelstatic void 252240116Smarcelvalidate_expect(struct context *ctx) 253240116Smarcel{ 254240116Smarcel if (ctx->expect == EXPECT_DEATH) { 255240116Smarcel error_in_expect(ctx, "Test case was expected to terminate abruptly " 256240116Smarcel "but it continued execution"); 257240116Smarcel } else if (ctx->expect == EXPECT_EXIT) { 258240116Smarcel error_in_expect(ctx, "Test case was expected to exit cleanly but it " 259240116Smarcel "continued execution"); 260240116Smarcel } else if (ctx->expect == EXPECT_FAIL) { 261240116Smarcel if (ctx->expect_fail_count == ctx->expect_previous_fail_count) 262240116Smarcel error_in_expect(ctx, "Test case was expecting a failure but none " 263240116Smarcel "were raised"); 264240116Smarcel else 265240116Smarcel INV(ctx->expect_fail_count > ctx->expect_previous_fail_count); 266240116Smarcel } else if (ctx->expect == EXPECT_PASS) { 267240116Smarcel /* Nothing to validate. */ 268240116Smarcel } else if (ctx->expect == EXPECT_SIGNAL) { 269240116Smarcel error_in_expect(ctx, "Test case was expected to receive a termination " 270240116Smarcel "signal but it continued execution"); 271240116Smarcel } else if (ctx->expect == EXPECT_TIMEOUT) { 272240116Smarcel error_in_expect(ctx, "Test case was expected to hang but it continued " 273240116Smarcel "execution"); 274240116Smarcel } else 275240116Smarcel UNREACHABLE; 276240116Smarcel} 277240116Smarcel 278240116Smarcelstatic void 279240116Smarcelexpected_failure(struct context *ctx, atf_dynstr_t *reason) 280240116Smarcel{ 281240116Smarcel check_fatal_error(atf_dynstr_prepend_fmt(reason, "%s: ", 282240116Smarcel atf_dynstr_cstring(&ctx->expect_reason))); 283240116Smarcel create_resfile(ctx->resfile, "expected_failure", -1, reason); 284240116Smarcel exit(EXIT_SUCCESS); 285240116Smarcel} 286240116Smarcel 287240116Smarcelstatic void 288240116Smarcelfail_requirement(struct context *ctx, atf_dynstr_t *reason) 289240116Smarcel{ 290240116Smarcel if (ctx->expect == EXPECT_FAIL) { 291240116Smarcel expected_failure(ctx, reason); 292240116Smarcel } else if (ctx->expect == EXPECT_PASS) { 293240116Smarcel create_resfile(ctx->resfile, "failed", -1, reason); 294240116Smarcel exit(EXIT_FAILURE); 295240116Smarcel } else { 296240116Smarcel error_in_expect(ctx, "Test case raised a failure but was not " 297240116Smarcel "expecting one; reason was %s", atf_dynstr_cstring(reason)); 298240116Smarcel } 299240116Smarcel UNREACHABLE; 300240116Smarcel} 301240116Smarcel 302240116Smarcelstatic void 303240116Smarcelfail_check(struct context *ctx, atf_dynstr_t *reason) 304240116Smarcel{ 305240116Smarcel if (ctx->expect == EXPECT_FAIL) { 306240116Smarcel fprintf(stderr, "*** Expected check failure: %s: %s\n", 307240116Smarcel atf_dynstr_cstring(&ctx->expect_reason), 308240116Smarcel atf_dynstr_cstring(reason)); 309240116Smarcel ctx->expect_fail_count++; 310240116Smarcel } else if (ctx->expect == EXPECT_PASS) { 311240116Smarcel fprintf(stderr, "*** Check failed: %s\n", atf_dynstr_cstring(reason)); 312240116Smarcel ctx->fail_count++; 313240116Smarcel } else { 314240116Smarcel error_in_expect(ctx, "Test case raised a failure but was not " 315240116Smarcel "expecting one; reason was %s", atf_dynstr_cstring(reason)); 316240116Smarcel } 317240116Smarcel 318240116Smarcel atf_dynstr_fini(reason); 319240116Smarcel} 320240116Smarcel 321240116Smarcelstatic void 322240116Smarcelpass(struct context *ctx) 323240116Smarcel{ 324240116Smarcel if (ctx->expect == EXPECT_FAIL) { 325240116Smarcel error_in_expect(ctx, "Test case was expecting a failure but got " 326240116Smarcel "a pass instead"); 327240116Smarcel } else if (ctx->expect == EXPECT_PASS) { 328240116Smarcel create_resfile(ctx->resfile, "passed", -1, NULL); 329240116Smarcel exit(EXIT_SUCCESS); 330240116Smarcel } else { 331240116Smarcel error_in_expect(ctx, "Test case asked to explicitly pass but was " 332240116Smarcel "not expecting such condition"); 333240116Smarcel } 334240116Smarcel UNREACHABLE; 335240116Smarcel} 336240116Smarcel 337240116Smarcelstatic void 338240116Smarcelskip(struct context *ctx, atf_dynstr_t *reason) 339240116Smarcel{ 340240116Smarcel if (ctx->expect == EXPECT_PASS) { 341240116Smarcel create_resfile(ctx->resfile, "skipped", -1, reason); 342240116Smarcel exit(EXIT_SUCCESS); 343240116Smarcel } else { 344240116Smarcel error_in_expect(ctx, "Can only skip a test case when running in " 345240116Smarcel "expect pass mode"); 346240116Smarcel } 347240116Smarcel UNREACHABLE; 348240116Smarcel} 349240116Smarcel 350240116Smarcel/** Formats a failure/skip reason message. 351240116Smarcel * 352240116Smarcel * The formatted reason is stored in out_reason. out_reason is initialized 353240116Smarcel * in this function and is supposed to be released by the caller. In general, 354240116Smarcel * the reason will eventually be fed to create_resfile, which will release 355240116Smarcel * it. 356240116Smarcel * 357240116Smarcel * Errors in this function are fatal. Rationale being: reasons are used to 358240116Smarcel * create results files; if we can't format the reason correctly, the result 359240116Smarcel * of the test program will be bogus. So it's better to just exit with a 360240116Smarcel * fatal error. 361240116Smarcel */ 362240116Smarcelstatic void 363240116Smarcelformat_reason_ap(atf_dynstr_t *out_reason, 364240116Smarcel const char *source_file, const size_t source_line, 365240116Smarcel const char *reason, va_list ap) 366240116Smarcel{ 367240116Smarcel atf_error_t err; 368240116Smarcel 369240116Smarcel if (source_file != NULL) { 370240116Smarcel err = atf_dynstr_init_fmt(out_reason, "%s:%zd: ", source_file, 371240116Smarcel source_line); 372240116Smarcel } else { 373240116Smarcel PRE(source_line == 0); 374240116Smarcel err = atf_dynstr_init(out_reason); 375240116Smarcel } 376240116Smarcel 377240116Smarcel if (!atf_is_error(err)) { 378240116Smarcel va_list ap2; 379240116Smarcel va_copy(ap2, ap); 380240116Smarcel err = atf_dynstr_append_ap(out_reason, reason, ap2); 381240116Smarcel va_end(ap2); 382240116Smarcel } 383240116Smarcel 384240116Smarcel check_fatal_error(err); 385240116Smarcel} 386240116Smarcel 387240116Smarcelstatic void 388240116Smarcelformat_reason_fmt(atf_dynstr_t *out_reason, 389240116Smarcel const char *source_file, const size_t source_line, 390240116Smarcel const char *reason, ...) 391240116Smarcel{ 392240116Smarcel va_list ap; 393240116Smarcel 394240116Smarcel va_start(ap, reason); 395240116Smarcel format_reason_ap(out_reason, source_file, source_line, reason, ap); 396240116Smarcel va_end(ap); 397240116Smarcel} 398240116Smarcel 399240116Smarcelstatic void 400240116Smarcelerrno_test(struct context *ctx, const char *file, const size_t line, 401240116Smarcel const int exp_errno, const char *expr_str, 402240116Smarcel const bool expr_result, 403240116Smarcel void (*fail_func)(struct context *, atf_dynstr_t *)) 404240116Smarcel{ 405240116Smarcel const int actual_errno = errno; 406240116Smarcel 407240116Smarcel if (expr_result) { 408240116Smarcel if (exp_errno != actual_errno) { 409240116Smarcel atf_dynstr_t reason; 410240116Smarcel 411240116Smarcel format_reason_fmt(&reason, file, line, "Expected errno %d, got %d, " 412240116Smarcel "in %s", exp_errno, actual_errno, expr_str); 413240116Smarcel fail_func(ctx, &reason); 414240116Smarcel } 415240116Smarcel } else { 416240116Smarcel atf_dynstr_t reason; 417240116Smarcel 418240116Smarcel format_reason_fmt(&reason, file, line, "Expected true value in %s", 419240116Smarcel expr_str); 420240116Smarcel fail_func(ctx, &reason); 421240116Smarcel } 422240116Smarcel} 423240116Smarcel 424240116Smarcelstruct prog_found_pair { 425240116Smarcel const char *prog; 426240116Smarcel bool found; 427240116Smarcel}; 428240116Smarcel 429240116Smarcelstatic atf_error_t 430240116Smarcelcheck_prog_in_dir(const char *dir, void *data) 431240116Smarcel{ 432240116Smarcel struct prog_found_pair *pf = data; 433240116Smarcel atf_error_t err; 434240116Smarcel 435240116Smarcel if (pf->found) 436240116Smarcel err = atf_no_error(); 437240116Smarcel else { 438240116Smarcel atf_fs_path_t p; 439240116Smarcel 440240116Smarcel err = atf_fs_path_init_fmt(&p, "%s/%s", dir, pf->prog); 441240116Smarcel if (atf_is_error(err)) 442240116Smarcel goto out_p; 443240116Smarcel 444240116Smarcel err = atf_fs_eaccess(&p, atf_fs_access_x); 445240116Smarcel if (!atf_is_error(err)) 446240116Smarcel pf->found = true; 447240116Smarcel else { 448240116Smarcel atf_error_free(err); 449240116Smarcel INV(!pf->found); 450240116Smarcel err = atf_no_error(); 451240116Smarcel } 452240116Smarcel 453240116Smarcelout_p: 454240116Smarcel atf_fs_path_fini(&p); 455240116Smarcel } 456240116Smarcel 457240116Smarcel return err; 458240116Smarcel} 459240116Smarcel 460240116Smarcelstatic atf_error_t 461240116Smarcelcheck_prog(struct context *ctx, const char *prog) 462240116Smarcel{ 463240116Smarcel atf_error_t err; 464240116Smarcel atf_fs_path_t p; 465240116Smarcel 466240116Smarcel err = atf_fs_path_init_fmt(&p, "%s", prog); 467240116Smarcel if (atf_is_error(err)) 468240116Smarcel goto out; 469240116Smarcel 470240116Smarcel if (atf_fs_path_is_absolute(&p)) { 471240116Smarcel err = atf_fs_eaccess(&p, atf_fs_access_x); 472240116Smarcel if (atf_is_error(err)) { 473240116Smarcel atf_dynstr_t reason; 474240116Smarcel 475240116Smarcel atf_error_free(err); 476240116Smarcel atf_fs_path_fini(&p); 477240116Smarcel format_reason_fmt(&reason, NULL, 0, "The required program %s could " 478240116Smarcel "not be found", prog); 479240116Smarcel skip(ctx, &reason); 480240116Smarcel } 481240116Smarcel } else { 482240116Smarcel const char *path = atf_env_get("PATH"); 483240116Smarcel struct prog_found_pair pf; 484240116Smarcel atf_fs_path_t bp; 485240116Smarcel 486240116Smarcel err = atf_fs_path_branch_path(&p, &bp); 487240116Smarcel if (atf_is_error(err)) 488240116Smarcel goto out_p; 489240116Smarcel 490240116Smarcel if (strcmp(atf_fs_path_cstring(&bp), ".") != 0) { 491240116Smarcel atf_fs_path_fini(&bp); 492240116Smarcel atf_fs_path_fini(&p); 493240116Smarcel 494240116Smarcel report_fatal_error("Relative paths are not allowed when searching " 495240116Smarcel "for a program (%s)", prog); 496240116Smarcel UNREACHABLE; 497240116Smarcel } 498240116Smarcel 499240116Smarcel pf.prog = prog; 500240116Smarcel pf.found = false; 501240116Smarcel err = atf_text_for_each_word(path, ":", check_prog_in_dir, &pf); 502240116Smarcel if (atf_is_error(err)) 503240116Smarcel goto out_bp; 504240116Smarcel 505240116Smarcel if (!pf.found) { 506240116Smarcel atf_dynstr_t reason; 507240116Smarcel 508240116Smarcel atf_fs_path_fini(&bp); 509240116Smarcel atf_fs_path_fini(&p); 510240116Smarcel format_reason_fmt(&reason, NULL, 0, "The required program %s could " 511240116Smarcel "not be found in the PATH", prog); 512240116Smarcel fail_requirement(ctx, &reason); 513240116Smarcel } 514240116Smarcel 515240116Smarcelout_bp: 516240116Smarcel atf_fs_path_fini(&bp); 517240116Smarcel } 518240116Smarcel 519240116Smarcelout_p: 520240116Smarcel atf_fs_path_fini(&p); 521240116Smarcelout: 522240116Smarcel return err; 523240116Smarcel} 524240116Smarcel 525240116Smarcel/* --------------------------------------------------------------------- 526240116Smarcel * The "atf_tc" type. 527240116Smarcel * --------------------------------------------------------------------- */ 528240116Smarcel 529240116Smarcelstruct atf_tc_impl { 530240116Smarcel const char *m_ident; 531240116Smarcel 532240116Smarcel atf_map_t m_vars; 533240116Smarcel atf_map_t m_config; 534240116Smarcel 535240116Smarcel atf_tc_head_t m_head; 536240116Smarcel atf_tc_body_t m_body; 537240116Smarcel atf_tc_cleanup_t m_cleanup; 538240116Smarcel}; 539240116Smarcel 540240116Smarcel/* 541240116Smarcel * Constructors/destructors. 542240116Smarcel */ 543240116Smarcel 544240116Smarcelatf_error_t 545240116Smarcelatf_tc_init(atf_tc_t *tc, const char *ident, atf_tc_head_t head, 546240116Smarcel atf_tc_body_t body, atf_tc_cleanup_t cleanup, 547240116Smarcel const char *const *config) 548240116Smarcel{ 549240116Smarcel atf_error_t err; 550240116Smarcel 551240116Smarcel tc->pimpl = malloc(sizeof(struct atf_tc_impl)); 552240116Smarcel if (tc->pimpl == NULL) { 553240116Smarcel err = atf_no_memory_error(); 554240116Smarcel goto err; 555240116Smarcel } 556240116Smarcel 557240116Smarcel tc->pimpl->m_ident = ident; 558240116Smarcel tc->pimpl->m_head = head; 559240116Smarcel tc->pimpl->m_body = body; 560240116Smarcel tc->pimpl->m_cleanup = cleanup; 561240116Smarcel 562240116Smarcel err = atf_map_init_charpp(&tc->pimpl->m_config, config); 563240116Smarcel if (atf_is_error(err)) 564240116Smarcel goto err; 565240116Smarcel 566240116Smarcel err = atf_map_init(&tc->pimpl->m_vars); 567240116Smarcel if (atf_is_error(err)) 568240116Smarcel goto err_vars; 569240116Smarcel 570240116Smarcel err = atf_tc_set_md_var(tc, "ident", ident); 571240116Smarcel if (atf_is_error(err)) 572240116Smarcel goto err_map; 573240116Smarcel 574240116Smarcel if (cleanup != NULL) { 575240116Smarcel err = atf_tc_set_md_var(tc, "has.cleanup", "true"); 576240116Smarcel if (atf_is_error(err)) 577240116Smarcel goto err_map; 578240116Smarcel } 579240116Smarcel 580240116Smarcel /* XXX Should the head be able to return error codes? */ 581240116Smarcel if (tc->pimpl->m_head != NULL) 582240116Smarcel tc->pimpl->m_head(tc); 583240116Smarcel 584240116Smarcel if (strcmp(atf_tc_get_md_var(tc, "ident"), ident) != 0) { 585240116Smarcel report_fatal_error("Test case head modified the read-only 'ident' " 586240116Smarcel "property"); 587240116Smarcel UNREACHABLE; 588240116Smarcel } 589240116Smarcel 590240116Smarcel INV(!atf_is_error(err)); 591240116Smarcel return err; 592240116Smarcel 593240116Smarcelerr_map: 594240116Smarcel atf_map_fini(&tc->pimpl->m_vars); 595240116Smarcelerr_vars: 596240116Smarcel atf_map_fini(&tc->pimpl->m_config); 597240116Smarcelerr: 598240116Smarcel return err; 599240116Smarcel} 600240116Smarcel 601240116Smarcelatf_error_t 602240116Smarcelatf_tc_init_pack(atf_tc_t *tc, const atf_tc_pack_t *pack, 603240116Smarcel const char *const *config) 604240116Smarcel{ 605240116Smarcel return atf_tc_init(tc, pack->m_ident, pack->m_head, pack->m_body, 606240116Smarcel pack->m_cleanup, config); 607240116Smarcel} 608240116Smarcel 609240116Smarcelvoid 610240116Smarcelatf_tc_fini(atf_tc_t *tc) 611240116Smarcel{ 612240116Smarcel atf_map_fini(&tc->pimpl->m_vars); 613240116Smarcel free(tc->pimpl); 614240116Smarcel} 615240116Smarcel 616240116Smarcel/* 617240116Smarcel * Getters. 618240116Smarcel */ 619240116Smarcel 620240116Smarcelconst char * 621240116Smarcelatf_tc_get_ident(const atf_tc_t *tc) 622240116Smarcel{ 623240116Smarcel return tc->pimpl->m_ident; 624240116Smarcel} 625240116Smarcel 626240116Smarcelconst char * 627240116Smarcelatf_tc_get_config_var(const atf_tc_t *tc, const char *name) 628240116Smarcel{ 629240116Smarcel const char *val; 630240116Smarcel atf_map_citer_t iter; 631240116Smarcel 632240116Smarcel PRE(atf_tc_has_config_var(tc, name)); 633240116Smarcel iter = atf_map_find_c(&tc->pimpl->m_config, name); 634240116Smarcel val = atf_map_citer_data(iter); 635240116Smarcel INV(val != NULL); 636240116Smarcel 637240116Smarcel return val; 638240116Smarcel} 639240116Smarcel 640240116Smarcelconst char * 641240116Smarcelatf_tc_get_config_var_wd(const atf_tc_t *tc, const char *name, 642240116Smarcel const char *defval) 643240116Smarcel{ 644240116Smarcel const char *val; 645240116Smarcel 646240116Smarcel if (!atf_tc_has_config_var(tc, name)) 647240116Smarcel val = defval; 648240116Smarcel else 649240116Smarcel val = atf_tc_get_config_var(tc, name); 650240116Smarcel 651240116Smarcel return val; 652240116Smarcel} 653240116Smarcel 654240116Smarcelbool 655240116Smarcelatf_tc_get_config_var_as_bool(const atf_tc_t *tc, const char *name) 656240116Smarcel{ 657240116Smarcel bool val; 658240116Smarcel const char *strval; 659240116Smarcel atf_error_t err; 660240116Smarcel 661240116Smarcel strval = atf_tc_get_config_var(tc, name); 662240116Smarcel err = atf_text_to_bool(strval, &val); 663240116Smarcel if (atf_is_error(err)) { 664240116Smarcel atf_error_free(err); 665240116Smarcel atf_tc_fail("Configuration variable %s does not have a valid " 666240116Smarcel "boolean value; found %s", name, strval); 667240116Smarcel } 668240116Smarcel 669240116Smarcel return val; 670240116Smarcel} 671240116Smarcel 672240116Smarcelbool 673240116Smarcelatf_tc_get_config_var_as_bool_wd(const atf_tc_t *tc, const char *name, 674240116Smarcel const bool defval) 675240116Smarcel{ 676240116Smarcel bool val; 677240116Smarcel 678240116Smarcel if (!atf_tc_has_config_var(tc, name)) 679240116Smarcel val = defval; 680240116Smarcel else 681240116Smarcel val = atf_tc_get_config_var_as_bool(tc, name); 682240116Smarcel 683240116Smarcel return val; 684240116Smarcel} 685240116Smarcel 686240116Smarcellong 687240116Smarcelatf_tc_get_config_var_as_long(const atf_tc_t *tc, const char *name) 688240116Smarcel{ 689240116Smarcel long val; 690240116Smarcel const char *strval; 691240116Smarcel atf_error_t err; 692240116Smarcel 693240116Smarcel strval = atf_tc_get_config_var(tc, name); 694240116Smarcel err = atf_text_to_long(strval, &val); 695240116Smarcel if (atf_is_error(err)) { 696240116Smarcel atf_error_free(err); 697240116Smarcel atf_tc_fail("Configuration variable %s does not have a valid " 698240116Smarcel "long value; found %s", name, strval); 699240116Smarcel } 700240116Smarcel 701240116Smarcel return val; 702240116Smarcel} 703240116Smarcel 704240116Smarcellong 705240116Smarcelatf_tc_get_config_var_as_long_wd(const atf_tc_t *tc, const char *name, 706240116Smarcel const long defval) 707240116Smarcel{ 708240116Smarcel long val; 709240116Smarcel 710240116Smarcel if (!atf_tc_has_config_var(tc, name)) 711240116Smarcel val = defval; 712240116Smarcel else 713240116Smarcel val = atf_tc_get_config_var_as_long(tc, name); 714240116Smarcel 715240116Smarcel return val; 716240116Smarcel} 717240116Smarcel 718240116Smarcelconst char * 719240116Smarcelatf_tc_get_md_var(const atf_tc_t *tc, const char *name) 720240116Smarcel{ 721240116Smarcel const char *val; 722240116Smarcel atf_map_citer_t iter; 723240116Smarcel 724240116Smarcel PRE(atf_tc_has_md_var(tc, name)); 725240116Smarcel iter = atf_map_find_c(&tc->pimpl->m_vars, name); 726240116Smarcel val = atf_map_citer_data(iter); 727240116Smarcel INV(val != NULL); 728240116Smarcel 729240116Smarcel return val; 730240116Smarcel} 731240116Smarcel 732240116Smarcelchar ** 733240116Smarcelatf_tc_get_md_vars(const atf_tc_t *tc) 734240116Smarcel{ 735240116Smarcel return atf_map_to_charpp(&tc->pimpl->m_vars); 736240116Smarcel} 737240116Smarcel 738240116Smarcelbool 739240116Smarcelatf_tc_has_config_var(const atf_tc_t *tc, const char *name) 740240116Smarcel{ 741240116Smarcel atf_map_citer_t end, iter; 742240116Smarcel 743240116Smarcel iter = atf_map_find_c(&tc->pimpl->m_config, name); 744240116Smarcel end = atf_map_end_c(&tc->pimpl->m_config); 745240116Smarcel return !atf_equal_map_citer_map_citer(iter, end); 746240116Smarcel} 747240116Smarcel 748240116Smarcelbool 749240116Smarcelatf_tc_has_md_var(const atf_tc_t *tc, const char *name) 750240116Smarcel{ 751240116Smarcel atf_map_citer_t end, iter; 752240116Smarcel 753240116Smarcel iter = atf_map_find_c(&tc->pimpl->m_vars, name); 754240116Smarcel end = atf_map_end_c(&tc->pimpl->m_vars); 755240116Smarcel return !atf_equal_map_citer_map_citer(iter, end); 756240116Smarcel} 757240116Smarcel 758240116Smarcel/* 759240116Smarcel * Modifiers. 760240116Smarcel */ 761240116Smarcel 762240116Smarcelatf_error_t 763240116Smarcelatf_tc_set_md_var(atf_tc_t *tc, const char *name, const char *fmt, ...) 764240116Smarcel{ 765240116Smarcel atf_error_t err; 766240116Smarcel char *value; 767240116Smarcel va_list ap; 768240116Smarcel 769240116Smarcel va_start(ap, fmt); 770240116Smarcel err = atf_text_format_ap(&value, fmt, ap); 771240116Smarcel va_end(ap); 772240116Smarcel 773240116Smarcel if (!atf_is_error(err)) 774240116Smarcel err = atf_map_insert(&tc->pimpl->m_vars, name, value, true); 775240116Smarcel else 776240116Smarcel free(value); 777240116Smarcel 778240116Smarcel return err; 779240116Smarcel} 780240116Smarcel 781240116Smarcel/* --------------------------------------------------------------------- 782240116Smarcel * Free functions, as they should be publicly but they can't. 783240116Smarcel * --------------------------------------------------------------------- */ 784240116Smarcel 785240116Smarcelstatic void _atf_tc_fail(struct context *, const char *, va_list) 786240116Smarcel ATF_DEFS_ATTRIBUTE_NORETURN; 787240116Smarcelstatic void _atf_tc_fail_nonfatal(struct context *, const char *, va_list); 788240116Smarcelstatic void _atf_tc_fail_check(struct context *, const char *, const size_t, 789240116Smarcel const char *, va_list); 790240116Smarcelstatic void _atf_tc_fail_requirement(struct context *, const char *, 791240116Smarcel const size_t, const char *, va_list) ATF_DEFS_ATTRIBUTE_NORETURN; 792240116Smarcelstatic void _atf_tc_pass(struct context *) ATF_DEFS_ATTRIBUTE_NORETURN; 793240116Smarcelstatic void _atf_tc_require_prog(struct context *, const char *); 794240116Smarcelstatic void _atf_tc_skip(struct context *, const char *, va_list) 795240116Smarcel ATF_DEFS_ATTRIBUTE_NORETURN; 796240116Smarcelstatic void _atf_tc_check_errno(struct context *, const char *, const size_t, 797240116Smarcel const int, const char *, const bool); 798240116Smarcelstatic void _atf_tc_require_errno(struct context *, const char *, const size_t, 799240116Smarcel const int, const char *, const bool); 800240116Smarcelstatic void _atf_tc_expect_pass(struct context *); 801240116Smarcelstatic void _atf_tc_expect_fail(struct context *, const char *, va_list); 802240116Smarcelstatic void _atf_tc_expect_exit(struct context *, const int, const char *, 803240116Smarcel va_list); 804240116Smarcelstatic void _atf_tc_expect_signal(struct context *, const int, const char *, 805240116Smarcel va_list); 806240116Smarcelstatic void _atf_tc_expect_death(struct context *, const char *, 807240116Smarcel va_list); 808240116Smarcel 809240116Smarcelstatic void 810240116Smarcel_atf_tc_fail(struct context *ctx, const char *fmt, va_list ap) 811240116Smarcel{ 812240116Smarcel va_list ap2; 813240116Smarcel atf_dynstr_t reason; 814240116Smarcel 815240116Smarcel va_copy(ap2, ap); 816240116Smarcel format_reason_ap(&reason, NULL, 0, fmt, ap2); 817240116Smarcel va_end(ap2); 818240116Smarcel 819240116Smarcel fail_requirement(ctx, &reason); 820240116Smarcel UNREACHABLE; 821240116Smarcel} 822240116Smarcel 823240116Smarcelstatic void 824240116Smarcel_atf_tc_fail_nonfatal(struct context *ctx, const char *fmt, va_list ap) 825240116Smarcel{ 826240116Smarcel va_list ap2; 827240116Smarcel atf_dynstr_t reason; 828240116Smarcel 829240116Smarcel va_copy(ap2, ap); 830240116Smarcel format_reason_ap(&reason, NULL, 0, fmt, ap2); 831240116Smarcel va_end(ap2); 832240116Smarcel 833240116Smarcel fail_check(ctx, &reason); 834240116Smarcel} 835240116Smarcel 836240116Smarcelstatic void 837240116Smarcel_atf_tc_fail_check(struct context *ctx, const char *file, const size_t line, 838240116Smarcel const char *fmt, va_list ap) 839240116Smarcel{ 840240116Smarcel va_list ap2; 841240116Smarcel atf_dynstr_t reason; 842240116Smarcel 843240116Smarcel va_copy(ap2, ap); 844240116Smarcel format_reason_ap(&reason, file, line, fmt, ap2); 845240116Smarcel va_end(ap2); 846240116Smarcel 847240116Smarcel fail_check(ctx, &reason); 848240116Smarcel} 849240116Smarcel 850240116Smarcelstatic void 851240116Smarcel_atf_tc_fail_requirement(struct context *ctx, const char *file, 852240116Smarcel const size_t line, const char *fmt, va_list ap) 853240116Smarcel{ 854240116Smarcel va_list ap2; 855240116Smarcel atf_dynstr_t reason; 856240116Smarcel 857240116Smarcel va_copy(ap2, ap); 858240116Smarcel format_reason_ap(&reason, file, line, fmt, ap2); 859240116Smarcel va_end(ap2); 860240116Smarcel 861240116Smarcel fail_requirement(ctx, &reason); 862240116Smarcel UNREACHABLE; 863240116Smarcel} 864240116Smarcel 865240116Smarcelstatic void 866240116Smarcel_atf_tc_pass(struct context *ctx) 867240116Smarcel{ 868240116Smarcel pass(ctx); 869240116Smarcel UNREACHABLE; 870240116Smarcel} 871240116Smarcel 872240116Smarcelstatic void 873240116Smarcel_atf_tc_require_prog(struct context *ctx, const char *prog) 874240116Smarcel{ 875240116Smarcel check_fatal_error(check_prog(ctx, prog)); 876240116Smarcel} 877240116Smarcel 878240116Smarcelstatic void 879240116Smarcel_atf_tc_skip(struct context *ctx, const char *fmt, va_list ap) 880240116Smarcel{ 881240116Smarcel atf_dynstr_t reason; 882240116Smarcel va_list ap2; 883240116Smarcel 884240116Smarcel va_copy(ap2, ap); 885240116Smarcel format_reason_ap(&reason, NULL, 0, fmt, ap2); 886240116Smarcel va_end(ap2); 887240116Smarcel 888240116Smarcel skip(ctx, &reason); 889240116Smarcel} 890240116Smarcel 891240116Smarcelstatic void 892240116Smarcel_atf_tc_check_errno(struct context *ctx, const char *file, const size_t line, 893240116Smarcel const int exp_errno, const char *expr_str, 894240116Smarcel const bool expr_result) 895240116Smarcel{ 896240116Smarcel errno_test(ctx, file, line, exp_errno, expr_str, expr_result, fail_check); 897240116Smarcel} 898240116Smarcel 899240116Smarcelstatic void 900240116Smarcel_atf_tc_require_errno(struct context *ctx, const char *file, const size_t line, 901240116Smarcel const int exp_errno, const char *expr_str, 902240116Smarcel const bool expr_result) 903240116Smarcel{ 904240116Smarcel errno_test(ctx, file, line, exp_errno, expr_str, expr_result, 905240116Smarcel fail_requirement); 906240116Smarcel} 907240116Smarcel 908240116Smarcelstatic void 909240116Smarcel_atf_tc_expect_pass(struct context *ctx) 910240116Smarcel{ 911240116Smarcel validate_expect(ctx); 912240116Smarcel 913240116Smarcel ctx->expect = EXPECT_PASS; 914240116Smarcel} 915240116Smarcel 916240116Smarcelstatic void 917240116Smarcel_atf_tc_expect_fail(struct context *ctx, const char *reason, va_list ap) 918240116Smarcel{ 919240116Smarcel va_list ap2; 920240116Smarcel 921240116Smarcel validate_expect(ctx); 922240116Smarcel 923240116Smarcel ctx->expect = EXPECT_FAIL; 924240116Smarcel atf_dynstr_fini(&ctx->expect_reason); 925240116Smarcel va_copy(ap2, ap); 926240116Smarcel check_fatal_error(atf_dynstr_init_ap(&ctx->expect_reason, reason, ap2)); 927240116Smarcel va_end(ap2); 928240116Smarcel ctx->expect_previous_fail_count = ctx->expect_fail_count; 929240116Smarcel} 930240116Smarcel 931240116Smarcelstatic void 932240116Smarcel_atf_tc_expect_exit(struct context *ctx, const int exitcode, const char *reason, 933240116Smarcel va_list ap) 934240116Smarcel{ 935240116Smarcel va_list ap2; 936240116Smarcel atf_dynstr_t formatted; 937240116Smarcel 938240116Smarcel validate_expect(ctx); 939240116Smarcel 940240116Smarcel ctx->expect = EXPECT_EXIT; 941240116Smarcel va_copy(ap2, ap); 942240116Smarcel check_fatal_error(atf_dynstr_init_ap(&formatted, reason, ap2)); 943240116Smarcel va_end(ap2); 944240116Smarcel 945240116Smarcel create_resfile(ctx->resfile, "expected_exit", exitcode, &formatted); 946240116Smarcel} 947240116Smarcel 948240116Smarcelstatic void 949240116Smarcel_atf_tc_expect_signal(struct context *ctx, const int signo, const char *reason, 950240116Smarcel va_list ap) 951240116Smarcel{ 952240116Smarcel va_list ap2; 953240116Smarcel atf_dynstr_t formatted; 954240116Smarcel 955240116Smarcel validate_expect(ctx); 956240116Smarcel 957240116Smarcel ctx->expect = EXPECT_SIGNAL; 958240116Smarcel va_copy(ap2, ap); 959240116Smarcel check_fatal_error(atf_dynstr_init_ap(&formatted, reason, ap2)); 960240116Smarcel va_end(ap2); 961240116Smarcel 962240116Smarcel create_resfile(ctx->resfile, "expected_signal", signo, &formatted); 963240116Smarcel} 964240116Smarcel 965240116Smarcelstatic void 966240116Smarcel_atf_tc_expect_death(struct context *ctx, const char *reason, va_list ap) 967240116Smarcel{ 968240116Smarcel va_list ap2; 969240116Smarcel atf_dynstr_t formatted; 970240116Smarcel 971240116Smarcel validate_expect(ctx); 972240116Smarcel 973240116Smarcel ctx->expect = EXPECT_DEATH; 974240116Smarcel va_copy(ap2, ap); 975240116Smarcel check_fatal_error(atf_dynstr_init_ap(&formatted, reason, ap2)); 976240116Smarcel va_end(ap2); 977240116Smarcel 978240116Smarcel create_resfile(ctx->resfile, "expected_death", -1, &formatted); 979240116Smarcel} 980240116Smarcel 981240116Smarcelstatic void 982240116Smarcel_atf_tc_expect_timeout(struct context *ctx, const char *reason, va_list ap) 983240116Smarcel{ 984240116Smarcel va_list ap2; 985240116Smarcel atf_dynstr_t formatted; 986240116Smarcel 987240116Smarcel validate_expect(ctx); 988240116Smarcel 989240116Smarcel ctx->expect = EXPECT_TIMEOUT; 990240116Smarcel va_copy(ap2, ap); 991240116Smarcel check_fatal_error(atf_dynstr_init_ap(&formatted, reason, ap2)); 992240116Smarcel va_end(ap2); 993240116Smarcel 994240116Smarcel create_resfile(ctx->resfile, "expected_timeout", -1, &formatted); 995240116Smarcel} 996240116Smarcel 997240116Smarcel/* --------------------------------------------------------------------- 998240116Smarcel * Free functions. 999240116Smarcel * --------------------------------------------------------------------- */ 1000240116Smarcel 1001240116Smarcelstatic struct context Current; 1002240116Smarcel 1003240116Smarcelatf_error_t 1004240116Smarcelatf_tc_run(const atf_tc_t *tc, const char *resfile) 1005240116Smarcel{ 1006240116Smarcel context_init(&Current, tc, resfile); 1007240116Smarcel 1008240116Smarcel tc->pimpl->m_body(tc); 1009240116Smarcel 1010240116Smarcel validate_expect(&Current); 1011240116Smarcel 1012240116Smarcel if (Current.fail_count > 0) { 1013240116Smarcel atf_dynstr_t reason; 1014240116Smarcel 1015240116Smarcel format_reason_fmt(&reason, NULL, 0, "%d checks failed; see output for " 1016240116Smarcel "more details", Current.fail_count); 1017240116Smarcel fail_requirement(&Current, &reason); 1018240116Smarcel } else if (Current.expect_fail_count > 0) { 1019240116Smarcel atf_dynstr_t reason; 1020240116Smarcel 1021240116Smarcel format_reason_fmt(&reason, NULL, 0, "%d checks failed as expected; " 1022240116Smarcel "see output for more details", Current.expect_fail_count); 1023240116Smarcel expected_failure(&Current, &reason); 1024240116Smarcel } else { 1025240116Smarcel pass(&Current); 1026240116Smarcel } 1027240116Smarcel UNREACHABLE; 1028240116Smarcel return atf_no_error(); 1029240116Smarcel} 1030240116Smarcel 1031240116Smarcelatf_error_t 1032240116Smarcelatf_tc_cleanup(const atf_tc_t *tc) 1033240116Smarcel{ 1034240116Smarcel if (tc->pimpl->m_cleanup != NULL) 1035240116Smarcel tc->pimpl->m_cleanup(tc); 1036240116Smarcel return atf_no_error(); /* XXX */ 1037240116Smarcel} 1038240116Smarcel 1039240116Smarcel/* --------------------------------------------------------------------- 1040240116Smarcel * Free functions that depend on Current. 1041240116Smarcel * --------------------------------------------------------------------- */ 1042240116Smarcel 1043240116Smarcel/* 1044240116Smarcel * All the functions below provide delegates to other internal functions 1045240116Smarcel * (prefixed by _) that take the current test case as an argument to 1046240116Smarcel * prevent them from accessing global state. This is to keep the side- 1047240116Smarcel * effects of the internal functions clearer and easier to understand. 1048240116Smarcel * 1049240116Smarcel * The public API should never have hid the fact that it needs access to 1050240116Smarcel * the current test case (other than maybe in the macros), but changing it 1051240116Smarcel * is hard. TODO: Revisit in the future. 1052240116Smarcel */ 1053240116Smarcel 1054240116Smarcelvoid 1055240116Smarcelatf_tc_fail(const char *fmt, ...) 1056240116Smarcel{ 1057240116Smarcel va_list ap; 1058240116Smarcel 1059240116Smarcel PRE(Current.tc != NULL); 1060240116Smarcel 1061240116Smarcel va_start(ap, fmt); 1062240116Smarcel _atf_tc_fail(&Current, fmt, ap); 1063240116Smarcel va_end(ap); 1064240116Smarcel} 1065240116Smarcel 1066240116Smarcelvoid 1067240116Smarcelatf_tc_fail_nonfatal(const char *fmt, ...) 1068240116Smarcel{ 1069240116Smarcel va_list ap; 1070240116Smarcel 1071240116Smarcel PRE(Current.tc != NULL); 1072240116Smarcel 1073240116Smarcel va_start(ap, fmt); 1074240116Smarcel _atf_tc_fail_nonfatal(&Current, fmt, ap); 1075240116Smarcel va_end(ap); 1076240116Smarcel} 1077240116Smarcel 1078240116Smarcelvoid 1079240116Smarcelatf_tc_fail_check(const char *file, const size_t line, const char *fmt, ...) 1080240116Smarcel{ 1081240116Smarcel va_list ap; 1082240116Smarcel 1083240116Smarcel PRE(Current.tc != NULL); 1084240116Smarcel 1085240116Smarcel va_start(ap, fmt); 1086240116Smarcel _atf_tc_fail_check(&Current, file, line, fmt, ap); 1087240116Smarcel va_end(ap); 1088240116Smarcel} 1089240116Smarcel 1090240116Smarcelvoid 1091240116Smarcelatf_tc_fail_requirement(const char *file, const size_t line, 1092240116Smarcel const char *fmt, ...) 1093240116Smarcel{ 1094240116Smarcel va_list ap; 1095240116Smarcel 1096240116Smarcel PRE(Current.tc != NULL); 1097240116Smarcel 1098240116Smarcel va_start(ap, fmt); 1099240116Smarcel _atf_tc_fail_requirement(&Current, file, line, fmt, ap); 1100240116Smarcel va_end(ap); 1101240116Smarcel} 1102240116Smarcel 1103240116Smarcelvoid 1104240116Smarcelatf_tc_pass(void) 1105240116Smarcel{ 1106240116Smarcel PRE(Current.tc != NULL); 1107240116Smarcel 1108240116Smarcel _atf_tc_pass(&Current); 1109240116Smarcel} 1110240116Smarcel 1111240116Smarcelvoid 1112240116Smarcelatf_tc_require_prog(const char *prog) 1113240116Smarcel{ 1114240116Smarcel PRE(Current.tc != NULL); 1115240116Smarcel 1116240116Smarcel _atf_tc_require_prog(&Current, prog); 1117240116Smarcel} 1118240116Smarcel 1119240116Smarcelvoid 1120240116Smarcelatf_tc_skip(const char *fmt, ...) 1121240116Smarcel{ 1122240116Smarcel va_list ap; 1123240116Smarcel 1124240116Smarcel PRE(Current.tc != NULL); 1125240116Smarcel 1126240116Smarcel va_start(ap, fmt); 1127240116Smarcel _atf_tc_skip(&Current, fmt, ap); 1128240116Smarcel va_end(ap); 1129240116Smarcel} 1130240116Smarcel 1131240116Smarcelvoid 1132240116Smarcelatf_tc_check_errno(const char *file, const size_t line, const int exp_errno, 1133240116Smarcel const char *expr_str, const bool expr_result) 1134240116Smarcel{ 1135240116Smarcel PRE(Current.tc != NULL); 1136240116Smarcel 1137240116Smarcel _atf_tc_check_errno(&Current, file, line, exp_errno, expr_str, 1138240116Smarcel expr_result); 1139240116Smarcel} 1140240116Smarcel 1141240116Smarcelvoid 1142240116Smarcelatf_tc_require_errno(const char *file, const size_t line, const int exp_errno, 1143240116Smarcel const char *expr_str, const bool expr_result) 1144240116Smarcel{ 1145240116Smarcel PRE(Current.tc != NULL); 1146240116Smarcel 1147240116Smarcel _atf_tc_require_errno(&Current, file, line, exp_errno, expr_str, 1148240116Smarcel expr_result); 1149240116Smarcel} 1150240116Smarcel 1151240116Smarcelvoid 1152240116Smarcelatf_tc_expect_pass(void) 1153240116Smarcel{ 1154240116Smarcel PRE(Current.tc != NULL); 1155240116Smarcel 1156240116Smarcel _atf_tc_expect_pass(&Current); 1157240116Smarcel} 1158240116Smarcel 1159240116Smarcelvoid 1160240116Smarcelatf_tc_expect_fail(const char *reason, ...) 1161240116Smarcel{ 1162240116Smarcel va_list ap; 1163240116Smarcel 1164240116Smarcel PRE(Current.tc != NULL); 1165240116Smarcel 1166240116Smarcel va_start(ap, reason); 1167240116Smarcel _atf_tc_expect_fail(&Current, reason, ap); 1168240116Smarcel va_end(ap); 1169240116Smarcel} 1170240116Smarcel 1171240116Smarcelvoid 1172240116Smarcelatf_tc_expect_exit(const int exitcode, const char *reason, ...) 1173240116Smarcel{ 1174240116Smarcel va_list ap; 1175240116Smarcel 1176240116Smarcel PRE(Current.tc != NULL); 1177240116Smarcel 1178240116Smarcel va_start(ap, reason); 1179240116Smarcel _atf_tc_expect_exit(&Current, exitcode, reason, ap); 1180240116Smarcel va_end(ap); 1181240116Smarcel} 1182240116Smarcel 1183240116Smarcelvoid 1184240116Smarcelatf_tc_expect_signal(const int signo, const char *reason, ...) 1185240116Smarcel{ 1186240116Smarcel va_list ap; 1187240116Smarcel 1188240116Smarcel PRE(Current.tc != NULL); 1189240116Smarcel 1190240116Smarcel va_start(ap, reason); 1191240116Smarcel _atf_tc_expect_signal(&Current, signo, reason, ap); 1192240116Smarcel va_end(ap); 1193240116Smarcel} 1194240116Smarcel 1195240116Smarcelvoid 1196240116Smarcelatf_tc_expect_death(const char *reason, ...) 1197240116Smarcel{ 1198240116Smarcel va_list ap; 1199240116Smarcel 1200240116Smarcel PRE(Current.tc != NULL); 1201240116Smarcel 1202240116Smarcel va_start(ap, reason); 1203240116Smarcel _atf_tc_expect_death(&Current, reason, ap); 1204240116Smarcel va_end(ap); 1205240116Smarcel} 1206240116Smarcel 1207240116Smarcelvoid 1208240116Smarcelatf_tc_expect_timeout(const char *reason, ...) 1209240116Smarcel{ 1210240116Smarcel va_list ap; 1211240116Smarcel 1212240116Smarcel PRE(Current.tc != NULL); 1213240116Smarcel 1214240116Smarcel va_start(ap, reason); 1215240116Smarcel _atf_tc_expect_timeout(&Current, reason, ap); 1216240116Smarcel va_end(ap); 1217240116Smarcel} 1218