diff options
Diffstat (limited to 'src/regress/lib/libcrypto/test')
-rw-r--r-- | src/regress/lib/libcrypto/test/test.c | 226 | ||||
-rw-r--r-- | src/regress/lib/libcrypto/test/test.h | 137 | ||||
-rw-r--r-- | src/regress/lib/libcrypto/test/test_util.c | 51 |
3 files changed, 414 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..1188ec34ef --- /dev/null +++ b/src/regress/lib/libcrypto/test/test.c | |||
@@ -0,0 +1,226 @@ | |||
1 | /* $OpenBSD: test.c,v 1.4 2025/05/31 11:36:48 tb 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 <stdarg.h> | ||
20 | #include <stdio.h> | ||
21 | #include <stdlib.h> | ||
22 | #include <string.h> | ||
23 | #include <unistd.h> | ||
24 | |||
25 | #include "test.h" | ||
26 | |||
27 | struct test { | ||
28 | struct test *parent; | ||
29 | char *name; | ||
30 | FILE *out; | ||
31 | int skipped; | ||
32 | int failed; | ||
33 | }; | ||
34 | |||
35 | static struct test * | ||
36 | test_new(struct test *pt, const char *name) | ||
37 | { | ||
38 | struct test *t; | ||
39 | |||
40 | if ((t = calloc(1, sizeof(*t))) == NULL) | ||
41 | err(1, "calloc"); | ||
42 | |||
43 | if (name != NULL) { | ||
44 | if ((t->name = strdup(name)) == NULL) | ||
45 | err(1, "strdup"); | ||
46 | } | ||
47 | |||
48 | if (pt != NULL) | ||
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 | free(tmp_file); | ||
77 | if ((t->out = fdopen(out_fd, "w+")) == NULL) | ||
78 | err(1, "fdopen"); | ||
79 | |||
80 | return t; | ||
81 | } | ||
82 | |||
83 | static void | ||
84 | test_cleanup(struct test *t) | ||
85 | { | ||
86 | free(t->name); | ||
87 | free(t); | ||
88 | } | ||
89 | |||
90 | int | ||
91 | test_result(struct test *t) | ||
92 | { | ||
93 | int failed = t->failed; | ||
94 | |||
95 | if (t->parent == NULL && t->out != stderr) | ||
96 | fclose(t->out); | ||
97 | |||
98 | test_cleanup(t); | ||
99 | |||
100 | return failed; | ||
101 | } | ||
102 | |||
103 | void | ||
104 | test_fail(struct test *t) | ||
105 | { | ||
106 | t->failed = 1; | ||
107 | |||
108 | /* Also fail parent. */ | ||
109 | if (t->parent != NULL) | ||
110 | test_fail(t->parent); | ||
111 | } | ||
112 | |||
113 | static void | ||
114 | test_vprintf(struct test *t, const char *fmt, va_list ap) | ||
115 | { | ||
116 | if (vfprintf(t->out, fmt, ap) == -1) | ||
117 | err(1, "vfprintf"); | ||
118 | } | ||
119 | |||
120 | void | ||
121 | test_printf(struct test *t, const char *fmt, ...) | ||
122 | { | ||
123 | va_list ap; | ||
124 | |||
125 | va_start(ap, fmt); | ||
126 | test_vprintf(t, fmt, ap); | ||
127 | va_end(ap); | ||
128 | } | ||
129 | |||
130 | static void | ||
131 | test_vlogf_internal(struct test *t, const char *label, const char *func, | ||
132 | const char *file, int line, const char *fmt, va_list ap) | ||
133 | { | ||
134 | char *msg = NULL; | ||
135 | char *l = ": "; | ||
136 | const char *filename; | ||
137 | |||
138 | if (label == NULL) { | ||
139 | label = ""; | ||
140 | l = ""; | ||
141 | } | ||
142 | |||
143 | if (vasprintf(&msg, fmt, ap) == -1) | ||
144 | err(1, "vasprintf"); | ||
145 | |||
146 | if ((filename = strrchr(file, '/')) != NULL) | ||
147 | filename++; | ||
148 | else | ||
149 | filename = file; | ||
150 | |||
151 | test_printf(t, "%s [%s:%d]%s%s: %s\n", | ||
152 | func, filename, line, l, label, msg); | ||
153 | |||
154 | free(msg); | ||
155 | } | ||
156 | |||
157 | void | ||
158 | test_logf_internal(struct test *t, const char *label, const char *func, | ||
159 | const char *file, int line, const char *fmt, ...) | ||
160 | { | ||
161 | va_list ap; | ||
162 | |||
163 | va_start(ap, fmt); | ||
164 | test_vlogf_internal(t, label, func, file, line, fmt, ap); | ||
165 | va_end(ap); | ||
166 | } | ||
167 | |||
168 | void | ||
169 | test_skip(struct test *t, const char *reason) | ||
170 | { | ||
171 | t->skipped = 1; | ||
172 | test_printf(t, "%s\n", reason); | ||
173 | } | ||
174 | |||
175 | void | ||
176 | test_skipf(struct test *t, const char *fmt, ...) | ||
177 | { | ||
178 | va_list ap; | ||
179 | |||
180 | t->skipped = 1; | ||
181 | |||
182 | va_start(ap, fmt); | ||
183 | test_vprintf(t, fmt, ap); | ||
184 | if (fputc('\n', t->out) == EOF) | ||
185 | err(1, "fputc"); | ||
186 | va_end(ap); | ||
187 | } | ||
188 | |||
189 | void | ||
190 | test_run(struct test *pt, const char *name, test_run_func *fn, const void *arg) | ||
191 | { | ||
192 | struct test *t = test_new(pt, name); | ||
193 | char *status = "PASS"; | ||
194 | char buf[1024]; | ||
195 | size_t buflen; | ||
196 | int ferr; | ||
197 | |||
198 | /* Run test */ | ||
199 | test_printf(t, "=== RUN %s\n", t->name); | ||
200 | fn(t, arg); | ||
201 | |||
202 | if (t->skipped) | ||
203 | status = "SKIP"; | ||
204 | if (t->failed) | ||
205 | status = "FAIL"; | ||
206 | |||
207 | test_printf(t, "--- %s: %s\n\n", status, t->name); | ||
208 | |||
209 | /* Print result of test */ | ||
210 | if (t->failed && t->out != stderr) { | ||
211 | /* Copy logs to stderr */ | ||
212 | rewind(t->out); | ||
213 | while ((buflen = fread(buf, 1, sizeof(buf), t->out)) > 0) | ||
214 | fwrite(buf, 1, buflen, stderr); | ||
215 | if ((ferr = ferror(t->out)) != 0) | ||
216 | errx(1, "ferror: %d", ferr); | ||
217 | } | ||
218 | |||
219 | if (t->out != NULL && t->out != stderr) { | ||
220 | /* Reset output file */ | ||
221 | rewind(t->out); | ||
222 | ftruncate(fileno(t->out), 0); | ||
223 | } | ||
224 | |||
225 | test_cleanup(t); | ||
226 | } | ||
diff --git a/src/regress/lib/libcrypto/test/test.h b/src/regress/lib/libcrypto/test/test.h new file mode 100644 index 0000000000..1c8391d4ec --- /dev/null +++ b/src/regress/lib/libcrypto/test/test.h | |||
@@ -0,0 +1,137 @@ | |||
1 | /* $OpenBSD: test.h,v 1.4 2025/05/31 11:37:18 tb 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 <stddef.h> | ||
22 | #include <stdint.h> | ||
23 | |||
24 | struct test; | ||
25 | |||
26 | /* | ||
27 | * test_init creates a new root test struct. | ||
28 | * | ||
29 | * Additional tests may be run under the root test struct by calling test_run. | ||
30 | * | ||
31 | * If the TEST_VERBOSE environment variable is set and not equal to "0", then | ||
32 | * verbose mode will be enabled and all test logs will be written to stderr. | ||
33 | */ | ||
34 | struct test *test_init(void); | ||
35 | |||
36 | /* | ||
37 | * test_result cleans up after all tests have completed and returns an | ||
38 | * appropriate exit code indicating the result of the tests. | ||
39 | */ | ||
40 | int test_result(struct test *_t); | ||
41 | |||
42 | /* | ||
43 | * test_run_func is an individual test function. It is passed the test struct | ||
44 | * and an arbitrary argument which may be passed when test_run is called. | ||
45 | */ | ||
46 | typedef void (test_run_func)(struct test *_t, const void *_arg); | ||
47 | |||
48 | /* | ||
49 | * test_fail marks the test and its parents as failed. | ||
50 | */ | ||
51 | void test_fail(struct test *_t); | ||
52 | |||
53 | /* | ||
54 | * test_printf prints a test log message. When in verbose mode, the log message | ||
55 | * will be written to stderr, otherwise it will be buffered and only written to | ||
56 | * stderr if the test fails. | ||
57 | * | ||
58 | * This printf will write directly, without any additional formatting. | ||
59 | */ | ||
60 | void test_printf(struct test *_t, const char *_fmt, ...) | ||
61 | __attribute__((__format__ (printf, 2, 3))) | ||
62 | __attribute__((__nonnull__ (2))); | ||
63 | |||
64 | /* | ||
65 | * test_logf_internal prints a test log message. When in verbose mode, the | ||
66 | * log message will be written to stderr, otherwise it will be buffered and | ||
67 | * only written to stderr if the test fails. | ||
68 | * | ||
69 | * label is an optional label indicating the severity of the log. | ||
70 | * func, file and line are used to show where the log comes from and are | ||
71 | * automatically set in the test log macros. | ||
72 | * | ||
73 | * This function should never be called directly. | ||
74 | */ | ||
75 | void test_logf_internal(struct test *_t, const char *_label, const char *_func, | ||
76 | const char *_file, int _line, const char *_fmt, ...) | ||
77 | __attribute__((__format__ (printf, 6, 7))) | ||
78 | __attribute__((__nonnull__ (6))); | ||
79 | |||
80 | /* | ||
81 | * test_logf prints an informational log message. When in verbose mode, the log | ||
82 | * will be written to stderr, otherwise it will be buffered and only written to | ||
83 | * stderr if the test fails. | ||
84 | */ | ||
85 | #define test_logf(t, fmt, ...) \ | ||
86 | do { \ | ||
87 | test_logf_internal(t, NULL, __func__, __FILE__, __LINE__, fmt, ##__VA_ARGS__); \ | ||
88 | } while (0) | ||
89 | |||
90 | /* | ||
91 | * test_errorf prints an error message. It will also cause the test to fail. | ||
92 | * If the test cannot proceed, it is recommended to return or goto a cleanup | ||
93 | * label. | ||
94 | * | ||
95 | * Tests should not fail-fast if continuing will provide more detailed | ||
96 | * information about what is broken. | ||
97 | */ | ||
98 | #define test_errorf(t, fmt, ...) \ | ||
99 | do { \ | ||
100 | test_logf_internal(t, "ERROR", __func__, __FILE__, __LINE__, fmt, ##__VA_ARGS__); \ | ||
101 | test_fail(t); \ | ||
102 | } while (0) | ||
103 | |||
104 | /* | ||
105 | * test_skip marks the test as skipped. Once called, the test should return. | ||
106 | */ | ||
107 | void test_skip(struct test *_t, const char *_reason); | ||
108 | |||
109 | /* | ||
110 | * test_skipf marks the test as skipped with a formatted reason. Once called, | ||
111 | * the test should return. | ||
112 | */ | ||
113 | void test_skipf(struct test *_t, const char *_fmt, ...) | ||
114 | __attribute__((__format__ (printf, 2, 3))) | ||
115 | __attribute__((__nonnull__ (2))); | ||
116 | |||
117 | /* | ||
118 | * test_run runs a test function. It will create a new test struct with the | ||
119 | * given test as the parent. An argument may be provided to pass data to the | ||
120 | * test function, otherwise NULL should be passed. | ||
121 | * | ||
122 | * Each test should have a unique and informational name. | ||
123 | */ | ||
124 | void test_run(struct test *_t, const char *_name, test_run_func *_fn, const void *_arg); | ||
125 | |||
126 | /* | ||
127 | * test_hexdump prints the given data as hexadecimal. | ||
128 | */ | ||
129 | void test_hexdump(struct test *_t, const unsigned char *_buf, size_t _len); | ||
130 | |||
131 | /* | ||
132 | * test_hexdiff prints the given data as hexadecimal. If a second comparison | ||
133 | * buffer is not NULL, any differing bytes will be marked with an astrix. | ||
134 | */ | ||
135 | void test_hexdiff(struct test *_t, const uint8_t *_buf, size_t _len, const uint8_t *_compare); | ||
136 | |||
137 | #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 | } | ||