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