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