diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/regress/lib/libcrypto/test/test.c | 225 | ||||
-rw-r--r-- | src/regress/lib/libcrypto/test/test.h | 132 | ||||
-rw-r--r-- | src/regress/lib/libcrypto/test/test_util.c | 51 |
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 | |||
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 | } | ||
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 | |||
23 | struct 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 | */ | ||
33 | struct 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 | */ | ||
39 | int 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 | */ | ||
45 | typedef void (test_run_func)(struct test *_t, const void *_arg); | ||
46 | |||
47 | /* | ||
48 | * test_fail marks the test and its parents as failed. | ||
49 | */ | ||
50 | void 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 | */ | ||
59 | void 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 | */ | ||
74 | void 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 | */ | ||
102 | void 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 | */ | ||
108 | void 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 | */ | ||
119 | void 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 | */ | ||
124 | void 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 | */ | ||
130 | void 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 | |||
24 | void | ||
25 | test_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 | |||
36 | void | ||
37 | test_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 | } | ||