xref: /freebsd/crypto/openssl/test/ossl_rbtree_test.c (revision f9bc005b8ef3b507a5ecbc2d7fe4411ef70eff38)
1*f9bc005bSEnji Cooper /*
2*f9bc005bSEnji Cooper  * Copyright 2026 The OpenSSL Project Authors. All Rights Reserved.
3*f9bc005bSEnji Cooper  *
4*f9bc005bSEnji Cooper  * Licensed under the Apache License 2.0 (the "License").  You may not use
5*f9bc005bSEnji Cooper  * this file except in compliance with the License.  You can obtain a copy
6*f9bc005bSEnji Cooper  * in the file LICENSE in the source distribution or at
7*f9bc005bSEnji Cooper  * https://www.openssl.org/source/license.html
8*f9bc005bSEnji Cooper  */
9*f9bc005bSEnji Cooper 
10*f9bc005bSEnji Cooper #include <string.h>
11*f9bc005bSEnji Cooper 
12*f9bc005bSEnji Cooper #include "testutil.h"
13*f9bc005bSEnji Cooper #include "internal/nelem.h"
14*f9bc005bSEnji Cooper #include "internal/ossl_rbtree.h"
15*f9bc005bSEnji Cooper 
16*f9bc005bSEnji Cooper static const char *test_data[] = {
17*f9bc005bSEnji Cooper     "alpha",
18*f9bc005bSEnji Cooper     "bravo",
19*f9bc005bSEnji Cooper     "charlie",
20*f9bc005bSEnji Cooper     "delta",
21*f9bc005bSEnji Cooper     "echo",
22*f9bc005bSEnji Cooper     "foxtrot",
23*f9bc005bSEnji Cooper     "golf",
24*f9bc005bSEnji Cooper     "hotel",
25*f9bc005bSEnji Cooper     "india",
26*f9bc005bSEnji Cooper     "juliet",
27*f9bc005bSEnji Cooper     "kilo",
28*f9bc005bSEnji Cooper     "lima",
29*f9bc005bSEnji Cooper     "mike",
30*f9bc005bSEnji Cooper     "november",
31*f9bc005bSEnji Cooper     "oscar",
32*f9bc005bSEnji Cooper     "papa",
33*f9bc005bSEnji Cooper     "quebec",
34*f9bc005bSEnji Cooper     "romeo",
35*f9bc005bSEnji Cooper     "sierra",
36*f9bc005bSEnji Cooper     "tango",
37*f9bc005bSEnji Cooper     "uniform",
38*f9bc005bSEnji Cooper     "victor",
39*f9bc005bSEnji Cooper     "whiskey",
40*f9bc005bSEnji Cooper     "x-ray",
41*f9bc005bSEnji Cooper     "yankey",
42*f9bc005bSEnji Cooper     "zulu",
43*f9bc005bSEnji Cooper };
44*f9bc005bSEnji Cooper 
45*f9bc005bSEnji Cooper typedef struct test_rbt {
46*f9bc005bSEnji Cooper     OSSL_RBT_ENTRY(test_rbt)
47*f9bc005bSEnji Cooper     rbt_entry;
48*f9bc005bSEnji Cooper     const char *rbt_data;
49*f9bc005bSEnji Cooper } TEST_RBT_T;
50*f9bc005bSEnji Cooper 
51*f9bc005bSEnji Cooper static OSSL_RBT_HEAD(ossl_rbt, test_rbt)
52*f9bc005bSEnji Cooper     rbt_head;
53*f9bc005bSEnji Cooper 
54*f9bc005bSEnji Cooper static TEST_RBT_T nodes_rbt[26];
55*f9bc005bSEnji Cooper 
56*f9bc005bSEnji Cooper static int cmp(const TEST_RBT_T *a, const TEST_RBT_T *b);
57*f9bc005bSEnji Cooper 
58*f9bc005bSEnji Cooper OSSL_RBT_PROTOTYPE(ossl_rbt, test_rbt, rbt_entry, cmp)
59*f9bc005bSEnji Cooper 
60*f9bc005bSEnji Cooper OSSL_RBT_GENERATE(ossl_rbt, test_rbt, rbt_entry, cmp);
61*f9bc005bSEnji Cooper 
62*f9bc005bSEnji Cooper static int cmp(const TEST_RBT_T *a_rbt, const TEST_RBT_T *b_rbt)
63*f9bc005bSEnji Cooper {
64*f9bc005bSEnji Cooper     return strcmp(a_rbt->rbt_data, b_rbt->rbt_data);
65*f9bc005bSEnji Cooper }
66*f9bc005bSEnji Cooper 
67*f9bc005bSEnji Cooper static int test_rbt_insert(void)
68*f9bc005bSEnji Cooper {
69*f9bc005bSEnji Cooper     unsigned int i;
70*f9bc005bSEnji Cooper     TEST_RBT_T *found_rbt, *node_rbt;
71*f9bc005bSEnji Cooper 
72*f9bc005bSEnji Cooper     OSSL_RBT_INIT(ossl_rbt, &rbt_head);
73*f9bc005bSEnji Cooper 
74*f9bc005bSEnji Cooper     for (i = OSSL_NELEM(test_data); i != 0; i--) {
75*f9bc005bSEnji Cooper         node_rbt = &nodes_rbt[i - 1];
76*f9bc005bSEnji Cooper         OSSL_RBT_INIT_RBE(ossl_rbt, node_rbt);
77*f9bc005bSEnji Cooper         node_rbt->rbt_data = test_data[i - 1];
78*f9bc005bSEnji Cooper         found_rbt = OSSL_RBT_INSERT(ossl_rbt, &rbt_head, node_rbt);
79*f9bc005bSEnji Cooper         if (!TEST_ptr_eq(found_rbt, NULL)) {
80*f9bc005bSEnji Cooper             TEST_info("%s %p(%s) found already %p(%s) @ %u\n", OPENSSL_FUNC,
81*f9bc005bSEnji Cooper                 (void *)node_rbt, node_rbt->rbt_data,
82*f9bc005bSEnji Cooper                 (void *)found_rbt, found_rbt->rbt_data, i);
83*f9bc005bSEnji Cooper             return 0;
84*f9bc005bSEnji Cooper         }
85*f9bc005bSEnji Cooper     }
86*f9bc005bSEnji Cooper 
87*f9bc005bSEnji Cooper     return 1;
88*f9bc005bSEnji Cooper }
89*f9bc005bSEnji Cooper 
90*f9bc005bSEnji Cooper static int test_rbt_min(void)
91*f9bc005bSEnji Cooper {
92*f9bc005bSEnji Cooper     unsigned int i;
93*f9bc005bSEnji Cooper     int match;
94*f9bc005bSEnji Cooper     TEST_RBT_T *node_rbt;
95*f9bc005bSEnji Cooper 
96*f9bc005bSEnji Cooper     if (test_rbt_insert() == 0)
97*f9bc005bSEnji Cooper         return 0;
98*f9bc005bSEnji Cooper 
99*f9bc005bSEnji Cooper     node_rbt = OSSL_RBT_MIN(ossl_rbt, &rbt_head);
100*f9bc005bSEnji Cooper     if (!TEST_ptr(node_rbt)) {
101*f9bc005bSEnji Cooper         TEST_info("%s OSSL_RBT_MIN() returns NULL", OPENSSL_FUNC);
102*f9bc005bSEnji Cooper         return 0;
103*f9bc005bSEnji Cooper     }
104*f9bc005bSEnji Cooper 
105*f9bc005bSEnji Cooper     for (i = 0; i < OSSL_NELEM(test_data); i++) {
106*f9bc005bSEnji Cooper         match = strcmp(node_rbt->rbt_data, test_data[i]);
107*f9bc005bSEnji Cooper         if (!TEST_int_eq(match, 0)) {
108*f9bc005bSEnji Cooper             TEST_info("%s %s != %s @ %u", OPENSSL_FUNC,
109*f9bc005bSEnji Cooper                 node_rbt->rbt_data, test_data[i], i);
110*f9bc005bSEnji Cooper             return 0;
111*f9bc005bSEnji Cooper         }
112*f9bc005bSEnji Cooper         node_rbt = OSSL_RBT_NEXT(ossl_rbt, node_rbt);
113*f9bc005bSEnji Cooper     }
114*f9bc005bSEnji Cooper 
115*f9bc005bSEnji Cooper     if (!TEST_ptr_eq(node_rbt, NULL)) {
116*f9bc005bSEnji Cooper         TEST_info("%s OSSL_RBT_NEXT() is not NULL", OPENSSL_FUNC);
117*f9bc005bSEnji Cooper         return 0;
118*f9bc005bSEnji Cooper     }
119*f9bc005bSEnji Cooper 
120*f9bc005bSEnji Cooper     return 1;
121*f9bc005bSEnji Cooper }
122*f9bc005bSEnji Cooper 
123*f9bc005bSEnji Cooper static int test_rbt_max(void)
124*f9bc005bSEnji Cooper {
125*f9bc005bSEnji Cooper     unsigned int i;
126*f9bc005bSEnji Cooper     int match;
127*f9bc005bSEnji Cooper     TEST_RBT_T *node_rbt;
128*f9bc005bSEnji Cooper 
129*f9bc005bSEnji Cooper     if (test_rbt_insert() == 0)
130*f9bc005bSEnji Cooper         return 0;
131*f9bc005bSEnji Cooper 
132*f9bc005bSEnji Cooper     node_rbt = OSSL_RBT_MAX(ossl_rbt, &rbt_head);
133*f9bc005bSEnji Cooper     if (!TEST_ptr(node_rbt)) {
134*f9bc005bSEnji Cooper         TEST_info("%s OSSL_RBT_MIN() returns NULL", OPENSSL_FUNC);
135*f9bc005bSEnji Cooper         return 0;
136*f9bc005bSEnji Cooper     }
137*f9bc005bSEnji Cooper 
138*f9bc005bSEnji Cooper     for (i = OSSL_NELEM(test_data); i > 0; i--) {
139*f9bc005bSEnji Cooper         match = strcmp(node_rbt->rbt_data, test_data[i - 1]);
140*f9bc005bSEnji Cooper         if (!TEST_int_eq(match, 0)) {
141*f9bc005bSEnji Cooper             TEST_info("%s %s != %s @ %u", OPENSSL_FUNC,
142*f9bc005bSEnji Cooper                 node_rbt->rbt_data, test_data[i - 1], i);
143*f9bc005bSEnji Cooper             return 0;
144*f9bc005bSEnji Cooper         }
145*f9bc005bSEnji Cooper         node_rbt = OSSL_RBT_PREV(ossl_rbt, node_rbt);
146*f9bc005bSEnji Cooper     }
147*f9bc005bSEnji Cooper 
148*f9bc005bSEnji Cooper     if (!TEST_ptr_eq(node_rbt, NULL)) {
149*f9bc005bSEnji Cooper         TEST_info("%s OSSL_RBT_PREV() is not NULL", OPENSSL_FUNC);
150*f9bc005bSEnji Cooper         return 0;
151*f9bc005bSEnji Cooper     }
152*f9bc005bSEnji Cooper 
153*f9bc005bSEnji Cooper     return 1;
154*f9bc005bSEnji Cooper }
155*f9bc005bSEnji Cooper 
156*f9bc005bSEnji Cooper static int test_rbt_find_remove(void)
157*f9bc005bSEnji Cooper {
158*f9bc005bSEnji Cooper     unsigned int i;
159*f9bc005bSEnji Cooper     TEST_RBT_T *node_rbt, *removed_rbt;
160*f9bc005bSEnji Cooper     TEST_RBT_T key_rbt;
161*f9bc005bSEnji Cooper 
162*f9bc005bSEnji Cooper     if (test_rbt_insert() == 0)
163*f9bc005bSEnji Cooper         return 0;
164*f9bc005bSEnji Cooper 
165*f9bc005bSEnji Cooper     for (i = 0; i < OSSL_NELEM(test_data); i++) {
166*f9bc005bSEnji Cooper         key_rbt.rbt_data = test_data[i];
167*f9bc005bSEnji Cooper         node_rbt = OSSL_RBT_FIND(ossl_rbt, &rbt_head, &key_rbt);
168*f9bc005bSEnji Cooper         if (!TEST_ptr(node_rbt)) {
169*f9bc005bSEnji Cooper             TEST_info("%s %s not found in tree @ %u", OPENSSL_FUNC,
170*f9bc005bSEnji Cooper                 key_rbt.rbt_data, i);
171*f9bc005bSEnji Cooper             return 0;
172*f9bc005bSEnji Cooper         }
173*f9bc005bSEnji Cooper         removed_rbt = OSSL_RBT_REMOVE(ossl_rbt, &rbt_head, node_rbt);
174*f9bc005bSEnji Cooper         if (!TEST_ptr_eq(node_rbt, removed_rbt)) {
175*f9bc005bSEnji Cooper             TEST_info("%s node_rbt(%p) != removed_rbt(%p) @ %u",
176*f9bc005bSEnji Cooper                 OPENSSL_FUNC, (void *)node_rbt, (void *)removed_rbt, i);
177*f9bc005bSEnji Cooper             return 0;
178*f9bc005bSEnji Cooper         }
179*f9bc005bSEnji Cooper 
180*f9bc005bSEnji Cooper         node_rbt = OSSL_RBT_FIND(ossl_rbt, &rbt_head, &key_rbt);
181*f9bc005bSEnji Cooper         if (!TEST_ptr_eq(node_rbt, NULL)) {
182*f9bc005bSEnji Cooper             TEST_info("%s %s(%p) still found after being removed @ %u",
183*f9bc005bSEnji Cooper                 OPENSSL_FUNC, node_rbt->rbt_data, (void *)node_rbt, i);
184*f9bc005bSEnji Cooper             return 0;
185*f9bc005bSEnji Cooper         }
186*f9bc005bSEnji Cooper     }
187*f9bc005bSEnji Cooper 
188*f9bc005bSEnji Cooper     if (!TEST_int_ne(OSSL_RBT_EMPTY(ossl_rbt, &rbt_head), 0)) {
189*f9bc005bSEnji Cooper         TEST_info("%s rbt is not empty", OPENSSL_FUNC);
190*f9bc005bSEnji Cooper         return 0;
191*f9bc005bSEnji Cooper     }
192*f9bc005bSEnji Cooper 
193*f9bc005bSEnji Cooper     return 1;
194*f9bc005bSEnji Cooper }
195*f9bc005bSEnji Cooper 
196*f9bc005bSEnji Cooper static int test_rbt_dup_insert(void)
197*f9bc005bSEnji Cooper {
198*f9bc005bSEnji Cooper     unsigned int i;
199*f9bc005bSEnji Cooper     int match;
200*f9bc005bSEnji Cooper     TEST_RBT_T *conflict_rbt;
201*f9bc005bSEnji Cooper     TEST_RBT_T insert_rbt;
202*f9bc005bSEnji Cooper 
203*f9bc005bSEnji Cooper     if (test_rbt_insert() == 0)
204*f9bc005bSEnji Cooper         return 0;
205*f9bc005bSEnji Cooper 
206*f9bc005bSEnji Cooper     for (i = 0; i < OSSL_NELEM(test_data); i++) {
207*f9bc005bSEnji Cooper         OSSL_RBT_INIT_RBE(ossl_rbt, &insert_rbt);
208*f9bc005bSEnji Cooper         insert_rbt.rbt_data = test_data[i];
209*f9bc005bSEnji Cooper         conflict_rbt = OSSL_RBT_INSERT(ossl_rbt, &rbt_head, &insert_rbt);
210*f9bc005bSEnji Cooper         if (!TEST_ptr(conflict_rbt)) {
211*f9bc005bSEnji Cooper             TEST_info("%s %s not found in tree @ %u", OPENSSL_FUNC,
212*f9bc005bSEnji Cooper                 insert_rbt.rbt_data, i);
213*f9bc005bSEnji Cooper             return 0;
214*f9bc005bSEnji Cooper         }
215*f9bc005bSEnji Cooper         match = strcmp(conflict_rbt->rbt_data, insert_rbt.rbt_data);
216*f9bc005bSEnji Cooper         if (!TEST_int_eq(match, 0)) {
217*f9bc005bSEnji Cooper             TEST_info("%s insert(%s) != conflict(%s) @ %u",
218*f9bc005bSEnji Cooper                 OPENSSL_FUNC, insert_rbt.rbt_data, conflict_rbt->rbt_data, i);
219*f9bc005bSEnji Cooper             return 0;
220*f9bc005bSEnji Cooper         }
221*f9bc005bSEnji Cooper     }
222*f9bc005bSEnji Cooper 
223*f9bc005bSEnji Cooper     return 1;
224*f9bc005bSEnji Cooper }
225*f9bc005bSEnji Cooper 
226*f9bc005bSEnji Cooper static int test_rbt_foreach(void)
227*f9bc005bSEnji Cooper {
228*f9bc005bSEnji Cooper     unsigned int i;
229*f9bc005bSEnji Cooper     int match;
230*f9bc005bSEnji Cooper     TEST_RBT_T *walk_rbt, *save_rbt;
231*f9bc005bSEnji Cooper 
232*f9bc005bSEnji Cooper     if (test_rbt_insert() == 0)
233*f9bc005bSEnji Cooper         return 0;
234*f9bc005bSEnji Cooper 
235*f9bc005bSEnji Cooper     i = 0;
236*f9bc005bSEnji Cooper     OSSL_RBT_FOREACH (walk_rbt, ossl_rbt, &rbt_head) {
237*f9bc005bSEnji Cooper         match = strcmp(walk_rbt->rbt_data, test_data[i]);
238*f9bc005bSEnji Cooper         if (!TEST_int_eq(match, 0)) {
239*f9bc005bSEnji Cooper             TEST_info("%s expected: %s got: %s @ %u",
240*f9bc005bSEnji Cooper                 OPENSSL_FUNC, walk_rbt->rbt_data, test_data[i], i);
241*f9bc005bSEnji Cooper             return 0;
242*f9bc005bSEnji Cooper         }
243*f9bc005bSEnji Cooper         i++;
244*f9bc005bSEnji Cooper     }
245*f9bc005bSEnji Cooper 
246*f9bc005bSEnji Cooper     i = 0;
247*f9bc005bSEnji Cooper     OSSL_RBT_FOREACH_SAFE (walk_rbt, ossl_rbt, &rbt_head, save_rbt) {
248*f9bc005bSEnji Cooper         match = strcmp(walk_rbt->rbt_data, test_data[i]);
249*f9bc005bSEnji Cooper         if (!TEST_int_eq(match, 0)) {
250*f9bc005bSEnji Cooper             TEST_info("%s expected: %s got: %s @ %u",
251*f9bc005bSEnji Cooper                 OPENSSL_FUNC, walk_rbt->rbt_data, test_data[i], i);
252*f9bc005bSEnji Cooper             return 0;
253*f9bc005bSEnji Cooper         }
254*f9bc005bSEnji Cooper         OSSL_RBT_REMOVE(ossl_rbt, &rbt_head, walk_rbt);
255*f9bc005bSEnji Cooper         i++;
256*f9bc005bSEnji Cooper     }
257*f9bc005bSEnji Cooper 
258*f9bc005bSEnji Cooper     if (!TEST_int_ne(OSSL_RBT_EMPTY(ossl_rbt, &rbt_head), 0)) {
259*f9bc005bSEnji Cooper         TEST_info("%s rbt is not empty", OPENSSL_FUNC);
260*f9bc005bSEnji Cooper         return 0;
261*f9bc005bSEnji Cooper     }
262*f9bc005bSEnji Cooper 
263*f9bc005bSEnji Cooper     return 1;
264*f9bc005bSEnji Cooper }
265*f9bc005bSEnji Cooper 
266*f9bc005bSEnji Cooper int setup_tests(void)
267*f9bc005bSEnji Cooper {
268*f9bc005bSEnji Cooper     ADD_TEST(test_rbt_insert);
269*f9bc005bSEnji Cooper     ADD_TEST(test_rbt_min);
270*f9bc005bSEnji Cooper     ADD_TEST(test_rbt_max);
271*f9bc005bSEnji Cooper     ADD_TEST(test_rbt_find_remove);
272*f9bc005bSEnji Cooper     ADD_TEST(test_rbt_dup_insert);
273*f9bc005bSEnji Cooper     ADD_TEST(test_rbt_foreach);
274*f9bc005bSEnji Cooper 
275*f9bc005bSEnji Cooper     return 1;
276*f9bc005bSEnji Cooper }
277