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 | } | ||
