summaryrefslogtreecommitdiff
path: root/src/regress/lib/libcrypto/test/test.c
diff options
context:
space:
mode:
authorjoshua <>2025-05-21 08:57:13 +0000
committerjoshua <>2025-05-21 08:57:13 +0000
commitc149f5ceaf380116e82c4ff7b1292c52e6bf5b07 (patch)
tree1fd293c8abe2b36faafb9680953c04e06ca524c7 /src/regress/lib/libcrypto/test/test.c
parent90e88c12b98a159dbce4ca3352ec5a9d8ddabed9 (diff)
downloadopenbsd-c149f5ceaf380116e82c4ff7b1292c52e6bf5b07.tar.gz
openbsd-c149f5ceaf380116e82c4ff7b1292c52e6bf5b07.tar.bz2
openbsd-c149f5ceaf380116e82c4ff7b1292c52e6bf5b07.zip
Add initial regress test framework
Add a test framework for use in LibreSSL regression tests. This test framework aims to be as lightweight and as simple to use as possible. The design is mostly inspired by Go's test system, and aims to be a drop-in utility in most existing regress tests. ok jsing tb beck
Diffstat (limited to 'src/regress/lib/libcrypto/test/test.c')
-rw-r--r--src/regress/lib/libcrypto/test/test.c225
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
28struct test {
29 struct test *parent;
30 char *name;
31 FILE *out;
32 int skipped;
33 int failed;
34};
35
36static struct test *
37test_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
55struct test *
56test_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
82static void
83test_cleanup(struct test *t)
84{
85 free(t->name);
86 free(t);
87}
88
89int
90test_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
102void
103test_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
112static void
113test_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
119void
120test_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
129static void
130test_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
156void
157test_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
167void
168test_skip(struct test *t, const char *reason)
169{
170 t->skipped = 1;
171 test_printf(t, "%s\n", reason);
172}
173
174void
175test_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
188void
189test_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}