mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2024-11-11 01:06:01 +03:00
253 lines
7.2 KiB
C++
253 lines
7.2 KiB
C++
/*
|
|
* Copyright (c) 2021, Tim Schumacher <timschumi@gmx.de>
|
|
*
|
|
* SPDX-License-Identifier: BSD-2-Clause
|
|
*/
|
|
|
|
#include <LibTest/TestCase.h>
|
|
|
|
#include <AK/Format.h>
|
|
#include <bits/search.h>
|
|
#include <search.h>
|
|
#include <string.h>
|
|
|
|
#define NODE(node) static_cast<struct search_tree_node*>(node)
|
|
#define ROOTP(root) reinterpret_cast<void**>(root)
|
|
#define COMP(func) reinterpret_cast<int (*)(void const*, void const*)>(func)
|
|
#define U8(value) static_cast<u8>(value)
|
|
|
|
struct twalk_test_entry {
|
|
void const* node;
|
|
VISIT order;
|
|
int depth;
|
|
};
|
|
|
|
#define TWALK_SET_DATA (-2)
|
|
#define TWALK_CHECK_END (-3)
|
|
#define TWALK_END_MARKER (-4)
|
|
|
|
TEST_CASE(tsearch)
|
|
{
|
|
struct search_tree_node* root = nullptr;
|
|
void* ret;
|
|
char const* key;
|
|
char* search;
|
|
|
|
// Try a nullptr rootp.
|
|
ret = tsearch("buggie", nullptr, COMP(strcmp));
|
|
EXPECT_EQ(ret, nullptr);
|
|
|
|
// Try creating a new tree.
|
|
key = "5";
|
|
ret = tsearch(key, ROOTP(&root), COMP(strcmp));
|
|
EXPECT_EQ(ret, root);
|
|
EXPECT_EQ(NODE(ret)->key, key);
|
|
|
|
// Insert an element on the left side.
|
|
key = "3";
|
|
ret = tsearch(key, ROOTP(&root), COMP(strcmp));
|
|
EXPECT_EQ(ret, root->left);
|
|
EXPECT_EQ(NODE(ret)->key, key);
|
|
|
|
// Insert an element on the right side.
|
|
key = "7";
|
|
ret = tsearch(key, ROOTP(&root), COMP(strcmp));
|
|
EXPECT_EQ(ret, root->right);
|
|
EXPECT_EQ(NODE(ret)->key, key);
|
|
|
|
// Add another layer for testing.
|
|
ret = tsearch("2", ROOTP(&root), COMP(strcmp));
|
|
EXPECT_EQ(ret, root->left->left);
|
|
ret = tsearch("4", ROOTP(&root), COMP(strcmp));
|
|
EXPECT_EQ(ret, root->left->right);
|
|
ret = tsearch("6", ROOTP(&root), COMP(strcmp));
|
|
EXPECT_EQ(ret, root->right->left);
|
|
ret = tsearch("8", ROOTP(&root), COMP(strcmp));
|
|
EXPECT_EQ(ret, root->right->right);
|
|
|
|
// Find the root element.
|
|
// strdup ensures that we are using the comparator.
|
|
search = strdup("5");
|
|
ret = tsearch(search, ROOTP(&root), COMP(strcmp));
|
|
EXPECT_EQ(ret, root);
|
|
free(search);
|
|
|
|
// Find the lowest-level elements.
|
|
search = strdup("2");
|
|
ret = tsearch(search, ROOTP(&root), COMP(strcmp));
|
|
EXPECT_EQ(ret, root->left->left);
|
|
free(search);
|
|
|
|
search = strdup("4");
|
|
ret = tsearch(search, ROOTP(&root), COMP(strcmp));
|
|
EXPECT_EQ(ret, root->left->right);
|
|
free(search);
|
|
|
|
search = strdup("6");
|
|
ret = tsearch(search, ROOTP(&root), COMP(strcmp));
|
|
EXPECT_EQ(ret, root->right->left);
|
|
free(search);
|
|
|
|
search = strdup("8");
|
|
ret = tsearch(search, ROOTP(&root), COMP(strcmp));
|
|
EXPECT_EQ(ret, root->right->right);
|
|
free(search);
|
|
|
|
delete_node_recursive(root);
|
|
}
|
|
|
|
TEST_CASE(tfind)
|
|
{
|
|
struct search_tree_node* root = nullptr;
|
|
void* ret;
|
|
char* search;
|
|
|
|
// Try a nullptr rootp.
|
|
ret = tfind("buggie", nullptr, COMP(strcmp));
|
|
EXPECT_EQ(ret, nullptr);
|
|
|
|
// Search for something that doesn't exist.
|
|
ret = tfind("buggie", ROOTP(&root), COMP(strcmp));
|
|
EXPECT_EQ(ret, nullptr);
|
|
|
|
// Construct a tree for testing.
|
|
root = new_tree_node("5");
|
|
root->left = new_tree_node("3");
|
|
root->right = new_tree_node("7");
|
|
root->left->left = new_tree_node("2");
|
|
root->left->right = new_tree_node("4");
|
|
root->right->left = new_tree_node("6");
|
|
root->right->right = new_tree_node("8");
|
|
|
|
// Find the root element.
|
|
// strdup ensures that we are using the comparator.
|
|
search = strdup("5");
|
|
ret = tfind(search, ROOTP(&root), COMP(strcmp));
|
|
EXPECT_EQ(ret, root);
|
|
free(search);
|
|
|
|
// Find the lowest-level elements.
|
|
search = strdup("2");
|
|
ret = tfind(search, ROOTP(&root), COMP(strcmp));
|
|
EXPECT_EQ(ret, root->left->left);
|
|
free(search);
|
|
|
|
search = strdup("4");
|
|
ret = tfind(search, ROOTP(&root), COMP(strcmp));
|
|
EXPECT_EQ(ret, root->left->right);
|
|
free(search);
|
|
|
|
search = strdup("6");
|
|
ret = tfind(search, ROOTP(&root), COMP(strcmp));
|
|
EXPECT_EQ(ret, root->right->left);
|
|
free(search);
|
|
|
|
search = strdup("8");
|
|
ret = tfind(search, ROOTP(&root), COMP(strcmp));
|
|
EXPECT_EQ(ret, root->right->right);
|
|
free(search);
|
|
|
|
delete_node_recursive(root);
|
|
}
|
|
|
|
void twalk_action(void const* node, VISIT order, int depth);
|
|
void twalk_action(void const* node, VISIT order, int depth)
|
|
{
|
|
static int count = 0;
|
|
static const struct twalk_test_entry* tests = nullptr;
|
|
|
|
// Special case: Set test data.
|
|
if (depth == TWALK_SET_DATA) {
|
|
count = 0;
|
|
tests = static_cast<const struct twalk_test_entry*>(node);
|
|
return;
|
|
}
|
|
|
|
// Special case: End signaled by tester.
|
|
if (depth == TWALK_CHECK_END) {
|
|
if (tests[count].depth != TWALK_END_MARKER) {
|
|
FAIL(String::formatted("Expected action (node={:#x}, order={}, depth={}), but twalk ended early.",
|
|
tests[count].node, U8(tests[count].order), tests[count].depth));
|
|
}
|
|
return;
|
|
}
|
|
|
|
// Special case: End marker reached.
|
|
if (tests[count].depth == TWALK_END_MARKER) {
|
|
FAIL(String::formatted("Expected end, but twalk sent another action (node={:#x}, order={}, depth={}).",
|
|
node, U8(order), depth));
|
|
return;
|
|
}
|
|
|
|
EXPECT_EQ(node, tests[count].node);
|
|
EXPECT_EQ(U8(order), U8(tests[count].order));
|
|
EXPECT_EQ(depth, tests[count].depth);
|
|
|
|
count++;
|
|
}
|
|
|
|
TEST_CASE(twalk)
|
|
{
|
|
struct search_tree_node* root = nullptr;
|
|
|
|
// Try an empty tree.
|
|
struct twalk_test_entry tests1[] = {
|
|
{ nullptr, leaf, TWALK_END_MARKER },
|
|
};
|
|
twalk_action(tests1, leaf, TWALK_SET_DATA);
|
|
twalk(nullptr, twalk_action);
|
|
twalk_action(nullptr, leaf, TWALK_CHECK_END);
|
|
|
|
// Try a single node.
|
|
root = new_tree_node("5");
|
|
struct twalk_test_entry tests2[] = {
|
|
{ root, leaf, 0 },
|
|
{ nullptr, leaf, TWALK_END_MARKER },
|
|
};
|
|
twalk_action(tests2, leaf, TWALK_SET_DATA);
|
|
twalk(root, twalk_action);
|
|
twalk_action(nullptr, leaf, TWALK_CHECK_END);
|
|
|
|
// Try two layers of nodes.
|
|
root->left = new_tree_node("3");
|
|
root->right = new_tree_node("7");
|
|
struct twalk_test_entry tests3[] = {
|
|
{ root, preorder, 0 },
|
|
{ root->left, leaf, 1 },
|
|
{ root, postorder, 0 },
|
|
{ root->right, leaf, 1 },
|
|
{ root, endorder, 0 },
|
|
{ nullptr, leaf, TWALK_END_MARKER },
|
|
};
|
|
twalk_action(tests3, leaf, TWALK_SET_DATA);
|
|
twalk(root, twalk_action);
|
|
twalk_action(nullptr, leaf, TWALK_CHECK_END);
|
|
|
|
// Try three layers of nodes.
|
|
root->left->left = new_tree_node("2");
|
|
root->left->right = new_tree_node("4");
|
|
root->right->left = new_tree_node("6");
|
|
root->right->right = new_tree_node("8");
|
|
struct twalk_test_entry tests4[] = {
|
|
{ root, preorder, 0 },
|
|
{ root->left, preorder, 1 },
|
|
{ root->left->left, leaf, 2 },
|
|
{ root->left, postorder, 1 },
|
|
{ root->left->right, leaf, 2 },
|
|
{ root->left, endorder, 1 },
|
|
{ root, postorder, 0 },
|
|
{ root->right, preorder, 1 },
|
|
{ root->right->left, leaf, 2 },
|
|
{ root->right, postorder, 1 },
|
|
{ root->right->right, leaf, 2 },
|
|
{ root->right, endorder, 1 },
|
|
{ root, endorder, 0 },
|
|
{ nullptr, leaf, TWALK_END_MARKER },
|
|
};
|
|
twalk_action(tests4, leaf, TWALK_SET_DATA);
|
|
twalk(root, twalk_action);
|
|
twalk_action(nullptr, leaf, TWALK_CHECK_END);
|
|
|
|
delete_node_recursive(root);
|
|
}
|