summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/regress/lib/libcrypto/test/test.c225
-rw-r--r--src/regress/lib/libcrypto/test/test.h132
-rw-r--r--src/regress/lib/libcrypto/test/test_util.c51
3 files changed, 408 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}
diff --git a/src/regress/lib/libcrypto/test/test.h b/src/regress/lib/libcrypto/test/test.h
new file mode 100644
index 0000000000..e6cfec80ea
--- /dev/null
+++ b/src/regress/lib/libcrypto/test/test.h
@@ -0,0 +1,132 @@
1/* $OpenBSD: test.h,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#ifndef HEADER_TEST_H
19#define HEADER_TEST_H
20
21#include <stdint.h>
22
23struct test;
24
25/*
26 * test_init creates a new root test struct.
27 *
28 * Additional tests may be run under the root test struct by calling test_run.
29 *
30 * If the TEST_VERBOSE environment variable is set and not equal to "0", then
31 * verbose mode will be enabled and all test logs will be written to stderr.
32 */
33struct test *test_init(void);
34
35/*
36 * test_result cleans up after all tests have completed and returns an
37 * appropriate exit code indicating the result of the tests.
38 */
39int test_result(struct test *_t);
40
41/*
42 * test_run_func is an individual test function. It is passed the test struct
43 * and an arbitrary argument which may be passed when test_run is called.
44 */
45typedef void (test_run_func)(struct test *_t, const void *_arg);
46
47/*
48 * test_fail marks the test and its parents as failed.
49 */
50void test_fail(struct test *_t);
51
52/*
53 * test_printf prints a test log message. When in verbose mode, the log message
54 * will be written to stderr, otherwise it will be buffered and only written to
55 * stderr if the test fails.
56 *
57 * This printf will write directly, without any additional formatting.
58 */
59void test_printf(struct test *_t, const char *_fmt, ...);
60 __attribute__((__format__ (printf, 2, 3)))
61 __attribute__((__nonnull__ (2)));
62
63/*
64 * test_logf_internal prints a test log message. When in verbose mode, the
65 * log message will be written to stderr, otherwise it will be buffered and
66 * only written to stderr if the test fails.
67 *
68 * label is an optional label indicating the severity of the log.
69 * func, file and line are used to show where the log comes from and are
70 * automatically set in the test log macros.
71 *
72 * This function should never be called directly.
73 */
74void test_logf_internal(struct test *_t, const char *_label, const char *_func,
75 const char *_file, int _line, const char *_fmt, ...);
76 __attribute__((__format__ (printf, 6, 7)))
77 __attribute__((__nonnull__ (6)));
78
79/*
80 * test_logf prints an informational log message. When in verbose mode, the log
81 * will be written to stderr, otherwise it will be buffered and only written to
82 * stderr if the test fails.
83 */
84#define test_logf(t, fmt, ...) \
85 test_logf_internal(t, NULL, __func__, __FILE__, __LINE__, fmt, ##__VA_ARGS__)
86
87/*
88 * test_errorf prints an error message. It will also cause the test to fail.
89 * If the test cannot proceed, it is recommended to return or goto a cleanup
90 * label.
91 *
92 * Tests should not fail-fast if continuing will provide more detailed
93 * information about what is broken.
94 */
95#define test_errorf(t, fmt, ...) \
96 test_logf_internal(t, "ERROR", __func__, __FILE__, __LINE__, fmt, ##__VA_ARGS__); \
97 test_fail(t)
98
99/*
100 * test_skip marks the test as skipped. Once called, the test should return.
101 */
102void test_skip(struct test *_t, const char *_reason);
103
104/*
105 * test_skipf marks the test as skipped with a formatted reason. Once called,
106 * the test should return.
107 */
108void test_skipf(struct test *_t, const char *_fmt, ...);
109 __attribute__((__format__ (printf, 2, 3)))
110 __attribute__((__nonnull__ (2)));
111
112/*
113 * test_run runs a test function. It will create a new test struct with the
114 * given test as the parent. An argument may be provided to pass data to the
115 * test function, otherwise NULL should be passed.
116 *
117 * Each test should have a unique and informational name.
118 */
119void test_run(struct test *_t, const char *_name, test_run_func *_fn, const void *_arg);
120
121/*
122 * test_hexdump prints the given data as hexadecimal.
123 */
124void test_hexdump(struct test *_t, const unsigned char *_buf, size_t _len);
125
126/*
127 * test_hexdiff prints the given data as hexadecimal. If a second comparison
128 * buffer is not NULL, any differing bytes will be marked with an astrix.
129 */
130void test_hexdiff(struct test *_t, const uint8_t *_buf, size_t _len, const uint8_t *_compare);
131
132#endif /* HEADER_TEST_H */
diff --git a/src/regress/lib/libcrypto/test/test_util.c b/src/regress/lib/libcrypto/test/test_util.c
new file mode 100644
index 0000000000..6ecb574788
--- /dev/null
+++ b/src/regress/lib/libcrypto/test/test_util.c
@@ -0,0 +1,51 @@
1/* $OpenBSD: test_util.c,v 1.1 2025/05/21 08:57:13 joshua Exp $ */
2/*
3 * Copyright (c) 2017 Joel Sing <jsing@openbsd.org>
4 * Copyright (c) 2024 Theo Buehler <tb@openbsd.org>
5 *
6 * Permission to use, copy, modify, and distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
9 *
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 */
18
19#include <stdio.h>
20#include <stdint.h>
21
22#include "test.h"
23
24void
25test_hexdump(struct test *t, const unsigned char *buf, size_t len)
26{
27 size_t i;
28
29 for (i = 1; i <= len; i++)
30 test_printf(t, " 0x%02x,%s", buf[i - 1], i % 8 ? "" : "\n");
31
32 if ((len % 8) != 0)
33 test_printf(t, "\n");
34}
35
36void
37test_hexdiff(struct test *t, const uint8_t *buf, size_t len, const uint8_t *compare)
38{
39 const char *mark = "", *newline;
40 size_t i;
41
42 for (i = 1; i <= len; i++) {
43 if (compare != NULL)
44 mark = (buf[i - 1] != compare[i - 1]) ? "*" : " ";
45 newline = i % 8 ? "" : "\n";
46 test_printf(t, " %s0x%02x,%s", mark, buf[i - 1], newline);
47 }
48
49 if ((len % 8) != 0)
50 test_printf(t, "\n");
51}