diff options
Diffstat (limited to 'src/regress/lib/libcrypto/test/test.c')
-rw-r--r-- | src/regress/lib/libcrypto/test/test.c | 225 |
1 files changed, 225 insertions, 0 deletions
diff --git a/src/regress/lib/libcrypto/test/test.c b/src/regress/lib/libcrypto/test/test.c new file mode 100644 index 0000000000..b48711919d --- /dev/null +++ b/src/regress/lib/libcrypto/test/test.c | |||
@@ -0,0 +1,225 @@ | |||
1 | /* $OpenBSD: test.c,v 1.1 2025/05/21 08:57:13 joshua Exp $ */ | ||
2 | /* | ||
3 | * Copyright (c) 2025 Joshua Sing <joshua@joshuasing.dev> | ||
4 | * | ||
5 | * Permission to use, copy, modify, and distribute this software for any | ||
6 | * purpose with or without fee is hereby granted, provided that the above | ||
7 | * copyright notice and this permission notice appear in all copies. | ||
8 | * | ||
9 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | ||
10 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | ||
11 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | ||
12 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | ||
13 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | ||
14 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | ||
15 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | ||
16 | */ | ||
17 | |||
18 | #include <err.h> | ||
19 | #include <libgen.h> | ||
20 | #include <stdarg.h> | ||
21 | #include <stdio.h> | ||
22 | #include <stdlib.h> | ||
23 | #include <string.h> | ||
24 | #include <unistd.h> | ||
25 | |||
26 | #include "test.h" | ||
27 | |||
28 | struct test { | ||
29 | struct test *parent; | ||
30 | char *name; | ||
31 | FILE *out; | ||
32 | int skipped; | ||
33 | int failed; | ||
34 | }; | ||
35 | |||
36 | static struct test * | ||
37 | test_new(struct test *pt, const char *name) | ||
38 | { | ||
39 | struct test *t; | ||
40 | |||
41 | if ((t = calloc(1, sizeof(*t))) == NULL) | ||
42 | err(1, "calloc"); | ||
43 | |||
44 | if (name != NULL) { | ||
45 | if ((t->name = strdup(name)) == NULL) | ||
46 | err(1, "strdup"); | ||
47 | } | ||
48 | |||
49 | t->out = pt->out; | ||
50 | t->parent = pt; | ||
51 | |||
52 | return t; | ||
53 | } | ||
54 | |||
55 | struct test * | ||
56 | test_init(void) | ||
57 | { | ||
58 | struct test *t; | ||
59 | char *tmp_file; | ||
60 | int out_fd; | ||
61 | char *v; | ||
62 | |||
63 | t = test_new(NULL, NULL); | ||
64 | t->out = stderr; | ||
65 | |||
66 | if (((v = getenv("TEST_VERBOSE")) != NULL) && strcmp(v, "0") != 0) | ||
67 | return t; | ||
68 | |||
69 | /* Create a temporary file for logging in non-verbose mode */ | ||
70 | if ((tmp_file = strdup("/tmp/libressl-test.XXXXXXXX")) == NULL) | ||
71 | err(1, "strdup"); | ||
72 | if ((out_fd = mkstemp(tmp_file)) == -1) | ||
73 | err(1, "mkstemp"); | ||
74 | |||
75 | unlink(tmp_file); | ||
76 | if ((t->out = fdopen(out_fd, "w+")) == NULL) | ||
77 | err(1, "fdopen"); | ||
78 | |||
79 | return t; | ||
80 | } | ||
81 | |||
82 | static void | ||
83 | test_cleanup(struct test *t) | ||
84 | { | ||
85 | free(t->name); | ||
86 | free(t); | ||
87 | } | ||
88 | |||
89 | int | ||
90 | test_result(struct test *t) | ||
91 | { | ||
92 | int failed = t->failed; | ||
93 | |||
94 | if (t->parent == NULL && t->out != stderr) | ||
95 | fclose(t->out); | ||
96 | |||
97 | test_cleanup(t); | ||
98 | |||
99 | return failed; | ||
100 | } | ||
101 | |||
102 | void | ||
103 | test_fail(struct test *t) | ||
104 | { | ||
105 | t->failed = 1; | ||
106 | |||
107 | /* Also fail parent. */ | ||
108 | if (t->parent != NULL) | ||
109 | test_fail(t->parent); | ||
110 | } | ||
111 | |||
112 | static void | ||
113 | test_vprintf(struct test *t, const char *fmt, va_list ap) | ||
114 | { | ||
115 | if (vfprintf(t->out, fmt, ap) == -1) | ||
116 | err(1, "vfprintf"); | ||
117 | } | ||
118 | |||
119 | void | ||
120 | test_printf(struct test *t, const char *fmt, ...) | ||
121 | { | ||
122 | va_list ap; | ||
123 | |||
124 | va_start(ap, fmt); | ||
125 | test_vprintf(t, fmt, ap); | ||
126 | va_end(ap); | ||
127 | } | ||
128 | |||
129 | static void | ||
130 | test_vlogf_internal(struct test *t, const char *label, const char *func, | ||
131 | const char *file, int line, const char *fmt, va_list ap) | ||
132 | { | ||
133 | char *msg = NULL; | ||
134 | char *l = ": "; | ||
135 | const char *filename; | ||
136 | |||
137 | if (label == NULL) { | ||
138 | label = ""; | ||
139 | l = ""; | ||
140 | } | ||
141 | |||
142 | if (vasprintf(&msg, fmt, ap) == -1) | ||
143 | err(1, "vasprintf"); | ||
144 | |||
145 | if ((filename = strrchr(file, '/')) != NULL) | ||
146 | filename++; | ||
147 | else | ||
148 | filename = file; | ||
149 | |||
150 | test_printf(t, "%s [%s:%d]%s%s: %s\n", | ||
151 | func, filename, line, l, label, msg); | ||
152 | |||
153 | free(msg); | ||
154 | } | ||
155 | |||
156 | void | ||
157 | test_logf_internal(struct test *t, const char *label, const char *func, | ||
158 | const char *file, int line, const char *fmt, ...) | ||
159 | { | ||
160 | va_list ap; | ||
161 | |||
162 | va_start(ap, fmt); | ||
163 | test_vlogf_internal(t, label, func, file, line, fmt, ap); | ||
164 | va_end(ap); | ||
165 | } | ||
166 | |||
167 | void | ||
168 | test_skip(struct test *t, const char *reason) | ||
169 | { | ||
170 | t->skipped = 1; | ||
171 | test_printf(t, "%s\n", reason); | ||
172 | } | ||
173 | |||
174 | void | ||
175 | test_skipf(struct test *t, const char *fmt, ...) | ||
176 | { | ||
177 | va_list ap; | ||
178 | |||
179 | t->skipped = 1; | ||
180 | |||
181 | va_start(ap, fmt); | ||
182 | test_vprintf(t, fmt, ap); | ||
183 | if (fputc('\n', t->out) == EOF) | ||
184 | err(1, "fputc"); | ||
185 | va_end(ap); | ||
186 | } | ||
187 | |||
188 | void | ||
189 | test_run(struct test *pt, const char *name, test_run_func *fn, const void *arg) | ||
190 | { | ||
191 | struct test *t = test_new(pt, name); | ||
192 | char *status = "PASS"; | ||
193 | char buf[1024]; | ||
194 | size_t buflen; | ||
195 | int ferr; | ||
196 | |||
197 | /* Run test */ | ||
198 | test_printf(t, "=== RUN %s\n", t->name); | ||
199 | fn(t, arg); | ||
200 | |||
201 | if (t->skipped) | ||
202 | status = "SKIP"; | ||
203 | if (t->failed) | ||
204 | status = "FAIL"; | ||
205 | |||
206 | test_printf(t, "--- %s: %s\n\n", status, t->name); | ||
207 | |||
208 | /* Print result of test */ | ||
209 | if (t->failed && t->out != stderr) { | ||
210 | /* Copy logs to stderr */ | ||
211 | rewind(t->out); | ||
212 | while ((buflen = fread(buf, 1, sizeof(buf), t->out)) > 0) | ||
213 | fwrite(buf, 1, buflen, stderr); | ||
214 | if ((ferr = ferror(t->out)) != 0) | ||
215 | errx(1, "ferror: %d", ferr); | ||
216 | } | ||
217 | |||
218 | if (t->out != NULL && t->out != stderr) { | ||
219 | /* Reset output file */ | ||
220 | rewind(t->out); | ||
221 | ftruncate(fileno(t->out), 0); | ||
222 | } | ||
223 | |||
224 | test_cleanup(t); | ||
225 | } | ||