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