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