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