TestSearch.cpp 7.2 KB

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