awtk/tests/tree_test.cc
2025-04-03 15:58:38 +08:00

436 lines
15 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include "gtest/gtest.h"
#include "tkc/tree.h"
#include "tkc/utils.h"
#include "tkc/fs.h"
TEST(Tree, create) {
tree_t* tree = tree_create(NULL, NULL);
ASSERT_EQ(tree != NULL, TRUE);
ASSERT_EQ(tree_is_empty(tree, NULL), TRUE);
ASSERT_EQ(0, tree_size(tree, NULL));
tree_destroy(tree);
}
TEST(Tree, insert_child) {
tree_t tree;
tree_node_t* node = NULL;
ASSERT_EQ(tree_init(&tree, NULL, NULL), RET_OK);
ASSERT_EQ(0, tree_size(&tree, NULL));
node = tree_node_create(tk_pointer_from_int(0));
ASSERT_EQ(node != NULL, TRUE);
ASSERT_EQ(0, tk_pointer_to_int(node->data));
ASSERT_EQ(RET_OK, tree_set_root(&tree, node));
ASSERT_EQ(tree.root == node, TRUE);
ASSERT_EQ(1, tree_size(&tree, NULL));
node = tree_node_create(tk_pointer_from_int(1));
ASSERT_EQ(node != NULL, TRUE);
ASSERT_EQ(1, tk_pointer_to_int(node->data));
ASSERT_EQ(RET_OK, tree_append_child_node(&tree, NULL, node));
ASSERT_EQ(2, tree_size(&tree, NULL));
node = tree_node_create(tk_pointer_from_int(2));
ASSERT_EQ(node != NULL, TRUE);
ASSERT_EQ(2, tk_pointer_to_int(node->data));
ASSERT_EQ(RET_OK, tree_prepend_child_node(&tree, NULL, node));
ASSERT_EQ(3, tree_size(&tree, NULL));
node = tree_node_create(tk_pointer_from_int(3));
ASSERT_EQ(node != NULL, TRUE);
ASSERT_EQ(3, tk_pointer_to_int(node->data));
ASSERT_EQ(RET_OK, tree_insert_child_node(&tree, NULL, 1, node));
ASSERT_EQ(4, tree_size(&tree, NULL));
tree_deinit(&tree);
}
TEST(Tree, insert_sibling) {
tree_t tree;
tree_node_t* node = NULL;
tree_node_t* insert_pos = NULL;
ASSERT_EQ(tree_init(&tree, NULL, NULL), RET_OK);
ASSERT_EQ(0, tree_size(&tree, NULL));
node = tree_node_create(tk_pointer_from_int(0));
ASSERT_EQ(node != NULL, TRUE);
ASSERT_EQ(RET_OK, tree_set_root(&tree, node));
ASSERT_EQ(tree.root != NULL, TRUE);
insert_pos = tree_node_create(tk_pointer_from_int(1));
ASSERT_EQ(insert_pos != NULL, TRUE);
ASSERT_EQ(RET_OK, tree_append_child_node(&tree, NULL, insert_pos));
node = tree_node_create(tk_pointer_from_int(2));
ASSERT_EQ(node != NULL, TRUE);
ASSERT_EQ(2, tk_pointer_to_int(node->data));
ASSERT_EQ(RET_OK, tree_append_sibling_node(&tree, insert_pos, node));
ASSERT_EQ(3, tree_size(&tree, NULL));
node = tree_node_create(tk_pointer_from_int(3));
ASSERT_EQ(node != NULL, TRUE);
ASSERT_EQ(3, tk_pointer_to_int(node->data));
ASSERT_EQ(RET_OK, tree_prepend_sibling_node(&tree, insert_pos, node));
ASSERT_EQ(4, tree_size(&tree, NULL));
node = tree_node_create(tk_pointer_from_int(4));
ASSERT_EQ(node != NULL, TRUE);
ASSERT_EQ(4, tk_pointer_to_int(node->data));
ASSERT_EQ(RET_OK, tree_insert_sibling_node(&tree, insert_pos, 1, node));
ASSERT_EQ(5, tree_size(&tree, NULL));
tree_deinit(&tree);
}
static ret_t build_tree_for_test(tree_t* tree) {
return_value_if_fail(tree != NULL, RET_BAD_PARAMS);
/**
* 0
* ├── 1
* │ ├── 11
* │ └── 12
* │ ├── 121
* │ ├── 122
* │ └── 123
* ├── 2
* │ ├── 21
* │ ├── 22
* │ │ └── 221
* │ │ ├── 2211
* │ │ └── 2212
* │ └── 23
* └── 3
* ├── 31
* └── 32
*/
// 创建根节点
tree_node_t* root = tree_node_create(tk_pointer_from_int(0));
tree_set_root(tree, root);
// 第一层子节点(使用节点操作接口)
tree_node_t* node1 = tree_node_create(tk_pointer_from_int(1));
tree_prepend_child_node(tree, NULL, node1);
tree_node_t* node3 = tree_node_create(tk_pointer_from_int(3));
tree_append_child_node(tree, NULL, node3);
tree_node_t* node2 = tree_node_create(tk_pointer_from_int(2));
tree_insert_child_node(tree, NULL, 1, node2);
// 第二层子节点
tree_node_t* node11 = tree_node_create(tk_pointer_from_int(11));
tree_prepend_child_node(tree, node1, node11);
tree_node_t* node12 = tree_node_create(tk_pointer_from_int(12));
tree_append_child_node(tree, node1, node12);
tree_node_t* node21 = tree_node_create(tk_pointer_from_int(21));
tree_append_child_node(tree, node2, node21);
tree_node_t* node22 = tree_node_create(tk_pointer_from_int(22));
tree_append_sibling_node(tree, node21, node22);
tree_node_t* node23 = tree_node_create(tk_pointer_from_int(23));
tree_append_sibling_node(tree, node22, node23);
tree_node_t* node31 = tree_node_create(tk_pointer_from_int(31));
tree_append_child_node(tree, node3, node31);
tree_node_t* node32 = tree_node_create(tk_pointer_from_int(32));
tree_append_child_node(tree, node3, node32);
// 第三层子节点
tree_append_child_node(tree, node12, tree_node_create(tk_pointer_from_int(121)));
tree_append_child_node(tree, node12, tree_node_create(tk_pointer_from_int(122)));
tree_append_child_node(tree, node12, tree_node_create(tk_pointer_from_int(123)));
tree_node_t* node221 = tree_node_create(tk_pointer_from_int(221));
tree_append_child_node(tree, node22, node221);
// 第四层子节点
tree_append_child_node(tree, node221, tree_node_create(tk_pointer_from_int(2211)));
tree_append_child_node(tree, node221, tree_node_create(tk_pointer_from_int(2212)));
return RET_OK;
}
static ret_t tree_node_gen_str_on_visit(void* ctx, const void* data) {
const tree_node_t* node = (const tree_node_t*)data;
str_t* str = (str_t*)ctx;
str_append_int(str, tk_pointer_to_int(node->data));
str_append_char(str, ' ');
return RET_OK;
}
TEST(Tree, foreach) {
tree_t tree;
str_t str;
str_init(&str, 1024);
ASSERT_EQ(tree_init(&tree, NULL, NULL), RET_OK);
ASSERT_EQ(build_tree_for_test(&tree), RET_OK);
str_clear(&str);
ASSERT_EQ(
tree_foreach(&tree, NULL, TREE_FOREACH_TYPE_BREADTH_FIRST, tree_node_gen_str_on_visit, &str),
RET_OK);
ASSERT_STREQ(str.str, "0 1 2 3 11 12 21 22 23 31 32 121 122 123 221 2211 2212 ");
str_clear(&str);
ASSERT_EQ(tree_foreach(&tree, NULL, TREE_FOREACH_TYPE_PREORDER, tree_node_gen_str_on_visit, &str),
RET_OK);
ASSERT_STREQ(str.str, "0 1 11 12 121 122 123 2 21 22 221 2211 2212 23 3 31 32 ");
str_clear(&str);
ASSERT_EQ(
tree_foreach(&tree, NULL, TREE_FOREACH_TYPE_POSTORDER, tree_node_gen_str_on_visit, &str),
RET_OK);
ASSERT_STREQ(str.str, "11 121 122 123 12 1 21 2211 2212 221 22 23 2 31 32 3 0 ");
tree_deinit(&tree);
str_reset(&str);
}
TEST(Tree, find) {
tree_t tree;
tree_node_t* node = NULL;
ASSERT_EQ(tree_init(&tree, NULL, NULL), RET_OK);
ASSERT_EQ(build_tree_for_test(&tree), RET_OK);
node = tree_find(&tree, NULL, TREE_FOREACH_TYPE_BREADTH_FIRST, tk_pointer_from_int(123));
ASSERT_EQ(node != NULL, TRUE);
ASSERT_EQ(123, tk_pointer_to_int(node->data));
tree_deinit(&tree);
}
static int tree_node_is_ancestor_or_self_cmp(const void* iter, const void* ctx) {
char str_ctx[32] = {'\0'};
char str_iter[32] = {'\0'};
int32_t num_ctx = tk_pointer_to_int(ctx);
int32_t num_iter = tk_pointer_to_int(iter);
return tk_str_start_with(tk_itoa(str_iter, sizeof(str_iter), num_iter),
tk_itoa(str_ctx, sizeof(str_ctx), num_ctx))
? 0
: -1;
}
TEST(Tree, remove) {
tree_t tree;
tree_node_t* node = NULL;
str_t str;
str_init(&str, 1024);
ASSERT_EQ(tree_init(&tree, NULL, NULL), RET_OK);
ASSERT_EQ(build_tree_for_test(&tree), RET_OK);
str_clear(&str);
ASSERT_EQ(tree_remove(&tree, NULL, TREE_FOREACH_TYPE_BREADTH_FIRST, tk_pointer_from_int(123)),
RET_OK);
ASSERT_EQ(
tree_foreach(&tree, NULL, TREE_FOREACH_TYPE_BREADTH_FIRST, tree_node_gen_str_on_visit, &str),
RET_OK);
ASSERT_STREQ(str.str, "0 1 2 3 11 12 21 22 23 31 32 121 122 221 2211 2212 ");
str_clear(&str);
ASSERT_EQ(tree_remove(&tree, NULL, TREE_FOREACH_TYPE_BREADTH_FIRST, tk_pointer_from_int(221)),
RET_OK);
ASSERT_EQ(
tree_foreach(&tree, NULL, TREE_FOREACH_TYPE_BREADTH_FIRST, tree_node_gen_str_on_visit, &str),
RET_OK);
ASSERT_STREQ(str.str, "0 1 2 3 11 12 21 22 23 31 32 121 122 ");
str_clear(&str);
ASSERT_EQ(tree_remove(&tree, NULL, TREE_FOREACH_TYPE_BREADTH_FIRST, tk_pointer_from_int(3)),
RET_OK);
ASSERT_EQ(
tree_foreach(&tree, NULL, TREE_FOREACH_TYPE_BREADTH_FIRST, tree_node_gen_str_on_visit, &str),
RET_OK);
ASSERT_STREQ(str.str, "0 1 2 11 12 21 22 23 121 122 ");
/* 测试节点和节点的子节点一起删除 */
str_clear(&str);
ASSERT_EQ(tree_remove_ex(&tree, NULL, TREE_FOREACH_TYPE_POSTORDER,
tree_node_is_ancestor_or_self_cmp, tk_pointer_from_int(2), -1),
RET_OK);
ASSERT_EQ(
tree_foreach(&tree, NULL, TREE_FOREACH_TYPE_BREADTH_FIRST, tree_node_gen_str_on_visit, &str),
RET_OK);
ASSERT_STREQ(str.str, "0 1 11 12 121 122 ");
tree_deinit(&tree);
str_reset(&str);
}
TEST(Tree, move) {
tree_t tree;
tree_node_t* node = NULL;
str_t str;
str_init(&str, 1024);
ASSERT_EQ(tree_init(&tree, NULL, NULL), RET_OK);
ASSERT_EQ(build_tree_for_test(&tree), RET_OK);
// 移动 221 节点到 12 的子节点末尾
tree_node_t* node221 =
tree_find(&tree, NULL, TREE_FOREACH_TYPE_BREADTH_FIRST, tk_pointer_from_int(221));
tree_node_t* node12 =
tree_find(&tree, NULL, TREE_FOREACH_TYPE_BREADTH_FIRST, tk_pointer_from_int(12));
ASSERT_EQ(tree_unlink_node(&tree, node221), RET_OK);
ASSERT_EQ(tree_append_child_node(&tree, node12, node221), RET_OK);
// 移动 22 节点到根节点的子节点末尾
tree_node_t* node22 =
tree_find(&tree, NULL, TREE_FOREACH_TYPE_BREADTH_FIRST, tk_pointer_from_int(22));
ASSERT_EQ(tree_unlink_node(&tree, node22), RET_OK);
ASSERT_EQ(tree_append_child_node(&tree, tree.root, node22), RET_OK);
// 移动 23 节点到 22 的兄弟节点末尾
tree_node_t* node23 =
tree_find(&tree, NULL, TREE_FOREACH_TYPE_BREADTH_FIRST, tk_pointer_from_int(23));
ASSERT_EQ(tree_unlink_node(&tree, node23), RET_OK);
ASSERT_EQ(tree_append_sibling_node(&tree, node22, node23), RET_OK);
str_clear(&str);
ASSERT_EQ(
tree_foreach(&tree, NULL, TREE_FOREACH_TYPE_BREADTH_FIRST, tree_node_gen_str_on_visit, &str),
RET_OK);
ASSERT_STREQ(str.str, "0 1 2 3 22 23 11 12 21 31 32 121 122 123 221 2211 2212 ");
tree_deinit(&tree);
str_reset(&str);
}
TEST(Tree, depth) {
tree_t tree;
tree_node_t* node = NULL;
ASSERT_EQ(tree_init(&tree, NULL, NULL), RET_OK);
ASSERT_EQ(build_tree_for_test(&tree), RET_OK);
node = tree_find(&tree, NULL, TREE_FOREACH_TYPE_BREADTH_FIRST, tk_pointer_from_int(123));
ASSERT_EQ(node != NULL, TRUE);
ASSERT_EQ(3, tree_depth(&tree, node));
node = tree_find(&tree, NULL, TREE_FOREACH_TYPE_BREADTH_FIRST, tk_pointer_from_int(221));
ASSERT_EQ(node != NULL, TRUE);
ASSERT_EQ(3, tree_depth(&tree, node));
node = tree_find(&tree, NULL, TREE_FOREACH_TYPE_BREADTH_FIRST, tk_pointer_from_int(3));
ASSERT_EQ(node != NULL, TRUE);
ASSERT_EQ(1, tree_depth(&tree, node));
tree_deinit(&tree);
}
TEST(Tree, height) {
tree_t tree;
ASSERT_EQ(tree_init(&tree, NULL, NULL), RET_OK);
ASSERT_EQ(build_tree_for_test(&tree), RET_OK);
tree_node_t* root = tree.root;
tree_node_t* node2 =
tree_find(&tree, NULL, TREE_FOREACH_TYPE_BREADTH_FIRST, tk_pointer_from_int(2));
tree_node_t* node22 =
tree_find(&tree, NULL, TREE_FOREACH_TYPE_BREADTH_FIRST, tk_pointer_from_int(22));
tree_node_t* node2211 =
tree_find(&tree, NULL, TREE_FOREACH_TYPE_BREADTH_FIRST, tk_pointer_from_int(2211));
// 根节点高度最长路径0→2→22→221→2211
ASSERT_EQ(tree_height(&tree, root), 4);
// 节点2的高度2→22→221→2211
ASSERT_EQ(tree_height(&tree, node2), 3);
// 节点22的高度22→221→2211
ASSERT_EQ(tree_height(&tree, node22), 2);
// 叶子节点高度为0
ASSERT_EQ(tree_height(&tree, node2211), 0);
tree_deinit(&tree);
}
TEST(Tree, degree) {
tree_t tree;
ASSERT_EQ(tree_init(&tree, NULL, NULL), RET_OK);
ASSERT_EQ(build_tree_for_test(&tree), RET_OK);
tree_node_t* root = tree.root;
tree_node_t* node1 =
tree_find(&tree, NULL, TREE_FOREACH_TYPE_BREADTH_FIRST, tk_pointer_from_int(1));
tree_node_t* node2 =
tree_find(&tree, NULL, TREE_FOREACH_TYPE_BREADTH_FIRST, tk_pointer_from_int(2));
tree_node_t* node12 =
tree_find(&tree, NULL, TREE_FOREACH_TYPE_BREADTH_FIRST, tk_pointer_from_int(12));
// 根节点的度为31/2/3三个子节点
ASSERT_EQ(tree_node_degree(root), 3);
// 节点1的度为211/12两个子节点
ASSERT_EQ(tree_node_degree(node1), 2);
// 节点11的度为0叶子节点
ASSERT_EQ(tree_node_degree(tree_node_get_child(node1, 0)), 0);
// 节点12的度为3121/122/123三个子节点
ASSERT_EQ(tree_node_degree(node12), 3);
// 树的度为3来自节点12的度
ASSERT_EQ(tree_degree(&tree), 3);
tree_deinit(&tree);
}
static ret_t tree_node_str_append(void* ctx, const void* data) {
const tree_node_t* node = (const tree_node_t*)(data);
str_t* str = (str_t*)(ctx);
return str_append_int(str, tk_pointer_to_int(node->data));
}
TEST(Tree, to_string) {
str_t str;
str_init(&str, 1024);
tree_t tree;
ASSERT_EQ(tree_init(&tree, NULL, NULL), RET_OK);
ASSERT_EQ(tree_to_string(&tree, NULL, &str, tree_node_str_append), RET_OK);
ASSERT_EQ(str.size, 0);
ASSERT_EQ(build_tree_for_test(&tree), RET_OK);
ASSERT_EQ(tree_to_string(&tree, NULL, &str, tree_node_str_append), RET_OK);
ASSERT_STREQ(str.str,
"0\n"
"├── 1\n"
"│ ├── 11\n"
"│ └── 12\n"
"│ ├── 121\n"
"│ ├── 122\n"
"│ └── 123\n"
"├── 2\n"
"│ ├── 21\n"
"│ ├── 22\n"
"│ │ └── 221\n"
"│ │ ├── 2211\n"
"│ │ └── 2212\n"
"│ └── 23\n"
"└── 3\n"
" ├── 31\n"
" └── 32");
tree_node_t* node3 = tree_find(&tree, NULL, TREE_FOREACH_TYPE_PREORDER, tk_pointer_from_int(3));
ASSERT_EQ(tree_to_string(&tree, node3, &str, tree_node_str_append), RET_OK);
ASSERT_STREQ(str.str,
"3\n"
"├── 31\n"
"└── 32");
tree_deinit(&tree);
str_reset(&str);
}