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