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