1 // SPDX-License-Identifier: CDDL-1.0
2 /*
3 * This file and its contents are supplied under the terms of the
4 * Common Development and Distribution License ("CDDL"), version 1.0.
5 * You may only use this file in accordance with the terms of version
6 * 1.0 of the CDDL.
7 *
8 * A full copy of the text of the CDDL should have accompanied this
9 * source. A copy of the CDDL is also available via the Internet at
10 * https://opensource.org/license/CDDL-1.0.
11 */
12
13 /*
14 * Copyright (c) 2026 by Garth Snyder. All rights reserved.
15 */
16
17 #ifndef _ZSTREAM_SELFTEST_H
18 #define _ZSTREAM_SELFTEST_H
19
20 #ifdef __cplusplus
21 extern "C" {
22 #endif
23
24 #include <stdint.h>
25
26 /*
27 * Shared harness for "zstream selftest". Each module under test supplies a
28 * NULL-terminated array of named test cases. The harness in
29 * zstream_selftest.c handles argument parsing, test selection, seeding of
30 * pseudo-random number generators, watchdog timeouts, and status output.
31 *
32 * Test cases report failure by exiting with a nonzero exit code. Any test
33 * case that returns has passed.
34 */
35
36 typedef void test_function_f(void);
37
38 typedef struct {
39 const char *tc_name;
40 test_function_f *tc_func;
41 } test_case_t;
42
43 /*
44 * Modules with test cases to offer. Each array ends with a NULL tc_name.
45 */
46 extern const test_case_t selftest_queue_cases[];
47
48 /*
49 * The seed for this run, set by the harness before any test runs. Printed
50 * at startup and settable with -s so failures can be replayed.
51 */
52 extern uint64_t selftest_seed;
53
54 /*
55 * A small deterministic PRNG (splitmix64). Tests derive per-thread
56 * generators from selftest_seed plus a caller-chosen stream number, so
57 * workloads are reproducible for a given seed regardless of scheduling.
58 */
59 typedef struct {
60 uint64_t sr_state;
61 } selftest_rng_t;
62
63 static inline uint64_t
selftest_mix64(uint64_t z)64 selftest_mix64(uint64_t z)
65 {
66 z += 0x9e3779b97f4a7c15ULL;
67 z = (z ^ (z >> 30)) * 0xbf58476d1ce4e5b9ULL;
68 z = (z ^ (z >> 27)) * 0x94d049bb133111ebULL;
69 return (z ^ (z >> 31));
70 }
71
72 static inline void
selftest_rng_init(selftest_rng_t * rng,uint64_t stream)73 selftest_rng_init(selftest_rng_t *rng, uint64_t stream)
74 {
75 rng->sr_state = selftest_seed ^ selftest_mix64(stream);
76 }
77
78 static inline uint64_t
selftest_rng_next(selftest_rng_t * rng)79 selftest_rng_next(selftest_rng_t *rng)
80 {
81 rng->sr_state += 0x9e3779b97f4a7c15ULL;
82 return (selftest_mix64(rng->sr_state));
83 }
84
85 /* Uniform value in [0, bound); returns 0 if bound is 0 */
86 static inline uint64_t
selftest_rng_below(selftest_rng_t * rng,uint64_t bound)87 selftest_rng_below(selftest_rng_t *rng, uint64_t bound)
88 {
89 return (bound ? selftest_rng_next(rng) % bound : 0);
90 }
91
92 #ifdef __cplusplus
93 }
94 #endif
95
96 #endif /* _ZSTREAM_SELFTEST_H */
97