Serenity Operating System
at master 251 lines 7.3 kB view raw
1/* 2 * Copyright (c) 2021, Tim Schumacher <timschumi@gmx.de> 3 * 4 * SPDX-License-Identifier: BSD-2-Clause 5 */ 6 7#include <LibTest/TestCase.h> 8 9#include <bits/search.h> 10#include <search.h> 11#include <string.h> 12 13#define NODE(node) static_cast<struct search_tree_node*>(node) 14#define ROOTP(root) reinterpret_cast<void**>(root) 15#define COMP(func) reinterpret_cast<int (*)(void const*, void const*)>(func) 16#define U8(value) static_cast<u8>(value) 17 18struct twalk_test_entry { 19 void const* node; 20 VISIT order; 21 int depth; 22}; 23 24#define TWALK_SET_DATA (-2) 25#define TWALK_CHECK_END (-3) 26#define TWALK_END_MARKER (-4) 27 28TEST_CASE(tsearch) 29{ 30 struct search_tree_node* root = nullptr; 31 void* ret; 32 char const* key; 33 char* search; 34 35 // Try a nullptr rootp. 36 ret = tsearch("buggie", nullptr, COMP(strcmp)); 37 EXPECT_EQ(ret, nullptr); 38 39 // Try creating a new tree. 40 key = "5"; 41 ret = tsearch(key, ROOTP(&root), COMP(strcmp)); 42 EXPECT_EQ(ret, root); 43 EXPECT_EQ(NODE(ret)->key, key); 44 45 // Insert an element on the left side. 46 key = "3"; 47 ret = tsearch(key, ROOTP(&root), COMP(strcmp)); 48 EXPECT_EQ(ret, root->left); 49 EXPECT_EQ(NODE(ret)->key, key); 50 51 // Insert an element on the right side. 52 key = "7"; 53 ret = tsearch(key, ROOTP(&root), COMP(strcmp)); 54 EXPECT_EQ(ret, root->right); 55 EXPECT_EQ(NODE(ret)->key, key); 56 57 // Add another layer for testing. 58 ret = tsearch("2", ROOTP(&root), COMP(strcmp)); 59 EXPECT_EQ(ret, root->left->left); 60 ret = tsearch("4", ROOTP(&root), COMP(strcmp)); 61 EXPECT_EQ(ret, root->left->right); 62 ret = tsearch("6", ROOTP(&root), COMP(strcmp)); 63 EXPECT_EQ(ret, root->right->left); 64 ret = tsearch("8", ROOTP(&root), COMP(strcmp)); 65 EXPECT_EQ(ret, root->right->right); 66 67 // Find the root element. 68 // strdup ensures that we are using the comparator. 69 search = strdup("5"); 70 ret = tsearch(search, ROOTP(&root), COMP(strcmp)); 71 EXPECT_EQ(ret, root); 72 free(search); 73 74 // Find the lowest-level elements. 75 search = strdup("2"); 76 ret = tsearch(search, ROOTP(&root), COMP(strcmp)); 77 EXPECT_EQ(ret, root->left->left); 78 free(search); 79 80 search = strdup("4"); 81 ret = tsearch(search, ROOTP(&root), COMP(strcmp)); 82 EXPECT_EQ(ret, root->left->right); 83 free(search); 84 85 search = strdup("6"); 86 ret = tsearch(search, ROOTP(&root), COMP(strcmp)); 87 EXPECT_EQ(ret, root->right->left); 88 free(search); 89 90 search = strdup("8"); 91 ret = tsearch(search, ROOTP(&root), COMP(strcmp)); 92 EXPECT_EQ(ret, root->right->right); 93 free(search); 94 95 delete_node_recursive(root); 96} 97 98TEST_CASE(tfind) 99{ 100 struct search_tree_node* root = nullptr; 101 void* ret; 102 char* search; 103 104 // Try a nullptr rootp. 105 ret = tfind("buggie", nullptr, COMP(strcmp)); 106 EXPECT_EQ(ret, nullptr); 107 108 // Search for something that doesn't exist. 109 ret = tfind("buggie", ROOTP(&root), COMP(strcmp)); 110 EXPECT_EQ(ret, nullptr); 111 112 // Construct a tree for testing. 113 root = new_tree_node("5"); 114 root->left = new_tree_node("3"); 115 root->right = new_tree_node("7"); 116 root->left->left = new_tree_node("2"); 117 root->left->right = new_tree_node("4"); 118 root->right->left = new_tree_node("6"); 119 root->right->right = new_tree_node("8"); 120 121 // Find the root element. 122 // strdup ensures that we are using the comparator. 123 search = strdup("5"); 124 ret = tfind(search, ROOTP(&root), COMP(strcmp)); 125 EXPECT_EQ(ret, root); 126 free(search); 127 128 // Find the lowest-level elements. 129 search = strdup("2"); 130 ret = tfind(search, ROOTP(&root), COMP(strcmp)); 131 EXPECT_EQ(ret, root->left->left); 132 free(search); 133 134 search = strdup("4"); 135 ret = tfind(search, ROOTP(&root), COMP(strcmp)); 136 EXPECT_EQ(ret, root->left->right); 137 free(search); 138 139 search = strdup("6"); 140 ret = tfind(search, ROOTP(&root), COMP(strcmp)); 141 EXPECT_EQ(ret, root->right->left); 142 free(search); 143 144 search = strdup("8"); 145 ret = tfind(search, ROOTP(&root), COMP(strcmp)); 146 EXPECT_EQ(ret, root->right->right); 147 free(search); 148 149 delete_node_recursive(root); 150} 151 152void twalk_action(void const* node, VISIT order, int depth); 153void twalk_action(void const* node, VISIT order, int depth) 154{ 155 static int count = 0; 156 static const struct twalk_test_entry* tests = nullptr; 157 158 // Special case: Set test data. 159 if (depth == TWALK_SET_DATA) { 160 count = 0; 161 tests = static_cast<const struct twalk_test_entry*>(node); 162 return; 163 } 164 165 // Special case: End signaled by tester. 166 if (depth == TWALK_CHECK_END) { 167 if (tests[count].depth != TWALK_END_MARKER) { 168 FAIL(DeprecatedString::formatted("Expected action (node={:#x}, order={}, depth={}), but twalk ended early.", 169 tests[count].node, U8(tests[count].order), tests[count].depth)); 170 } 171 return; 172 } 173 174 // Special case: End marker reached. 175 if (tests[count].depth == TWALK_END_MARKER) { 176 FAIL(DeprecatedString::formatted("Expected end, but twalk sent another action (node={:#x}, order={}, depth={}).", 177 node, U8(order), depth)); 178 return; 179 } 180 181 EXPECT_EQ(node, tests[count].node); 182 EXPECT_EQ(U8(order), U8(tests[count].order)); 183 EXPECT_EQ(depth, tests[count].depth); 184 185 count++; 186} 187 188TEST_CASE(twalk) 189{ 190 struct search_tree_node* root = nullptr; 191 192 // Try an empty tree. 193 struct twalk_test_entry tests1[] = { 194 { nullptr, leaf, TWALK_END_MARKER }, 195 }; 196 twalk_action(tests1, leaf, TWALK_SET_DATA); 197 twalk(nullptr, twalk_action); 198 twalk_action(nullptr, leaf, TWALK_CHECK_END); 199 200 // Try a single node. 201 root = new_tree_node("5"); 202 struct twalk_test_entry tests2[] = { 203 { root, leaf, 0 }, 204 { nullptr, leaf, TWALK_END_MARKER }, 205 }; 206 twalk_action(tests2, leaf, TWALK_SET_DATA); 207 twalk(root, twalk_action); 208 twalk_action(nullptr, leaf, TWALK_CHECK_END); 209 210 // Try two layers of nodes. 211 root->left = new_tree_node("3"); 212 root->right = new_tree_node("7"); 213 struct twalk_test_entry tests3[] = { 214 { root, preorder, 0 }, 215 { root->left, leaf, 1 }, 216 { root, postorder, 0 }, 217 { root->right, leaf, 1 }, 218 { root, endorder, 0 }, 219 { nullptr, leaf, TWALK_END_MARKER }, 220 }; 221 twalk_action(tests3, leaf, TWALK_SET_DATA); 222 twalk(root, twalk_action); 223 twalk_action(nullptr, leaf, TWALK_CHECK_END); 224 225 // Try three layers of nodes. 226 root->left->left = new_tree_node("2"); 227 root->left->right = new_tree_node("4"); 228 root->right->left = new_tree_node("6"); 229 root->right->right = new_tree_node("8"); 230 struct twalk_test_entry tests4[] = { 231 { root, preorder, 0 }, 232 { root->left, preorder, 1 }, 233 { root->left->left, leaf, 2 }, 234 { root->left, postorder, 1 }, 235 { root->left->right, leaf, 2 }, 236 { root->left, endorder, 1 }, 237 { root, postorder, 0 }, 238 { root->right, preorder, 1 }, 239 { root->right->left, leaf, 2 }, 240 { root->right, postorder, 1 }, 241 { root->right->right, leaf, 2 }, 242 { root->right, endorder, 1 }, 243 { root, endorder, 0 }, 244 { nullptr, leaf, TWALK_END_MARKER }, 245 }; 246 twalk_action(tests4, leaf, TWALK_SET_DATA); 247 twalk(root, twalk_action); 248 twalk_action(nullptr, leaf, TWALK_CHECK_END); 249 250 delete_node_recursive(root); 251}