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