From 5793f6a1782eb11f8df62359cfb0820ddf156c70 Mon Sep 17 00:00:00 2001 From: Andrew Kesterson Date: Sat, 27 Jun 2026 13:13:17 -0400 Subject: [PATCH] Add tree search test --- CMakeLists.txt | 4 ++ include/akstdlib.h | 2 +- src/stdlib.c | 71 ++++++++++++++++-------------- tests/test_linkedlist.c | 1 + tests/test_tree.c | 96 +++++++++++++++++++++++++++++++++++++++++ 5 files changed, 141 insertions(+), 33 deletions(-) create mode 100644 tests/test_tree.c diff --git a/CMakeLists.txt b/CMakeLists.txt index 60c1dc2..e22a829 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -79,5 +79,9 @@ add_executable(test_linkedlist tests/test_linkedlist.c) target_link_libraries(test_linkedlist PRIVATE akstdlib) add_test(NAME linkedlist COMMAND test_linkedlist) +add_executable(test_tree tests/test_tree.c) +target_link_libraries(test_tree PRIVATE akstdlib) +add_test(NAME tree COMMAND test_tree) + # pkgconfig diff --git a/include/akstdlib.h b/include/akstdlib.h index f07b606..37a1ae9 100644 --- a/include/akstdlib.h +++ b/include/akstdlib.h @@ -57,7 +57,7 @@ akerr_ErrorContext AKERR_NOIGNORE *aksl_realpath(const char *restrict path, char akerr_ErrorContext AKERR_NOIGNORE *aksl_strhash_djb2(char *str, size_t len, uint32_t *hashval); // Linked list functions -akerr_ErrorContext AKERR_NOIGNORE *aksl_list_push(aksl_ListNode *list, aksl_ListNode *obj); +akerr_ErrorContext AKERR_NOIGNORE *aksl_list_append(aksl_ListNode *list, aksl_ListNode *obj); akerr_ErrorContext AKERR_NOIGNORE *aksl_list_pop(aksl_ListNode *node); akerr_ErrorContext AKERR_NOIGNORE *aksl_list_iterate(aksl_ListNode *list, aksl_ListNodeIterator iter, void *data); diff --git a/src/stdlib.c b/src/stdlib.c index d8ddda8..c314e64 100644 --- a/src/stdlib.c +++ b/src/stdlib.c @@ -266,39 +266,46 @@ akerr_ErrorContext AKERR_NOIGNORE *aksl_tree_iterate( if ( lfree == NULL ) { lfree = &aksl_free; } - switch ( searchmode ) { - case AKSL_TREE_SEARCH_DFS_PREORDER: - PASS(e, iter(root, data)); - if ( root->left != NULL ) { - PASS(e, aksl_tree_iterate(root->left, iter, lalloc, lfree, searchmode, data, NULL)); + ATTEMPT { + switch ( searchmode ) { + case AKSL_TREE_SEARCH_DFS_PREORDER: + CATCH(e, iter(root, data)); + if ( root->left != NULL ) { + PASS(e, aksl_tree_iterate(root->left, iter, lalloc, lfree, searchmode, data, NULL)); + } + if ( root-> right != NULL ) { + PASS(e, aksl_tree_iterate(root->right, iter, lalloc, lfree, searchmode, data, NULL)); + } + break; + case AKSL_TREE_SEARCH_DFS_POSTORDER: + if ( root->left != NULL ) { + PASS(e, aksl_tree_iterate(root->left, iter, lalloc, lfree, searchmode, data, NULL)); + } + if ( root-> right != NULL ) { + PASS(e, aksl_tree_iterate(root->right, iter, lalloc, lfree, searchmode, data, NULL)); + } + CATCH(e, iter(root, data)); + break; + case AKSL_TREE_SEARCH_DFS_INORDER: + if ( root->left != NULL ) { + PASS(e, aksl_tree_iterate(root->left, iter, lalloc, lfree, searchmode, data, NULL)); + } + CATCH(e, iter(root, data)); + if ( root-> right != NULL ) { + PASS(e, aksl_tree_iterate(root->right, iter, lalloc, lfree, searchmode, data, NULL)); + } + break; + case AKSL_TREE_SEARCH_BFS: + case AKSL_TREE_SEARCH_BFS_RIGHT: + FAIL_RETURN(e, AKERR_NOT_IMPLEMENTED, "Searchmode %d", searchmode); + break; } - if ( root-> right != NULL ) { - PASS(e, aksl_tree_iterate(root->right, iter, lalloc, lfree, searchmode, data, NULL)); - } - break; - case AKSL_TREE_SEARCH_DFS_POSTORDER: - if ( root->left != NULL ) { - PASS(e, aksl_tree_iterate(root->left, iter, lalloc, lfree, searchmode, data, NULL)); - } - if ( root-> right != NULL ) { - PASS(e, aksl_tree_iterate(root->right, iter, lalloc, lfree, searchmode, data, NULL)); - } - PASS(e, iter(root, data)); - break; - case AKSL_TREE_SEARCH_DFS_INORDER: - if ( root->left != NULL ) { - PASS(e, aksl_tree_iterate(root->left, iter, lalloc, lfree, searchmode, data, NULL)); - } - PASS(e, iter(root, data)); - if ( root-> right != NULL ) { - PASS(e, aksl_tree_iterate(root->right, iter, lalloc, lfree, searchmode, data, NULL)); - } - break; - case AKSL_TREE_SEARCH_BFS: - case AKSL_TREE_SEARCH_BFS_RIGHT: - FAIL_RETURN(e, AKERR_NOT_IMPLEMENTED, "Searchmode %d", searchmode); - break; - } + } CLEANUP { + } PROCESS(e) { + } HANDLE(e, AKERR_ITERATOR_BREAK) { + // This is not an error condition, it's just telling us to stop early + SUCCEED_RETURN(e); + } FINISH(e, true); SUCCEED_RETURN(e); } diff --git a/tests/test_linkedlist.c b/tests/test_linkedlist.c index 9383de0..bc80c0c 100644 --- a/tests/test_linkedlist.c +++ b/tests/test_linkedlist.c @@ -35,6 +35,7 @@ int main(void) { PREPARE_ERROR(e); int idx = 0; + int count = 0; aksl_ListNode mylist; aksl_ListNode node1; aksl_ListNode node2; diff --git a/tests/test_tree.c b/tests/test_tree.c new file mode 100644 index 0000000..5ebb874 --- /dev/null +++ b/tests/test_tree.c @@ -0,0 +1,96 @@ +#include +#include + +#define MAX_LEAVES 7 + +typedef struct TreeSearchParams +{ + void *value; + int steps; + aksl_TreeNode *node; +} TreeSearchParams; + +// This iterator does nothing but print the node names it is visiting +akerr_ErrorContext AKERR_NOIGNORE *myiter(aksl_TreeNode *node, void *data) +{ + int count = 0; + TreeSearchParams *parms = NULL; + PREPARE_ERROR(e); + FAIL_ZERO_RETURN(e, node, AKERR_NULLPOINTER, "node"); + FAIL_ZERO_RETURN(e, data, AKERR_NULLPOINTER, "data"); + parms = (TreeSearchParams *)data; + parms->steps += 1; + if ( node->leaf == parms->value ) { + parms->node = node; + FAIL_RETURN(e, AKERR_ITERATOR_BREAK, "stop"); + } + SUCCEED_RETURN(e); +} + +int main(void) +{ + PREPARE_ERROR(e); + aksl_TreeNode tree[MAX_LEAVES]; + TreeSearchParams parms = { + .value = (void *)17336, + .steps = 0, + .node = NULL + }; + + ATTEMPT { + memset((void *)&tree, 0x00, sizeof(aksl_TreeNode) * MAX_LEAVES); + /* + * Here we build a 3 level tree + * + * LEFT RIGHT + * TREE[0] + * +--------^^---------+ + * | | + * TREE[1] TREE[2] + * +---^^---+ +---^^---+ + * | | | | + *TREE[3] TREE[4] TREE[5] TREE[6] + */ + tree[0].left = &tree[1]; + tree[0].right = &tree[2]; + tree[1].left = &tree[3]; + tree[1].right = &tree[4]; + tree[2].left = &tree[5]; + tree[2].right = &tree[6]; + + // Hide a value in tree[6] + tree[6].leaf = (void *)17336; + + // Search for the value 17336 using DFS_PREORDER + CATCH(e, aksl_tree_iterate(&tree[0], &myiter, NULL, NULL, AKSL_TREE_SEARCH_DFS_PREORDER, &parms, NULL)); + if ( parms.node != &tree[6] ) { + FAIL_BREAK(e, AKERR_API, "DFS_PREORDER_SEARCH didn't find the node"); + } + if ( parms.steps != 7 ) { + FAIL_BREAK(e, AKERR_API, "DFS_PREORDER_SEARCH should've found the node in 7 steps, instead took %d", parms.steps); + } + + // Search for the value 17336 using DFS_INORDER + CATCH(e, aksl_tree_iterate(&tree[0], &myiter, NULL, NULL, AKSL_TREE_SEARCH_DFS_INORDER, &parms, NULL)); + if ( parms.node != &tree[6] ) { + FAIL_BREAK(e, AKERR_API, "DFS_INORDER_SEARCH didn't find the node"); + } + if ( parms.steps != 7 ) { + FAIL_BREAK(e, AKERR_API, "DFS_INORDER_SEARCH should've found the node in 7 steps, instead took %d", parms.steps); + } + + // Search for the value 17336 using DFS_PREORDER + CATCH(e, aksl_tree_iterate(&tree[0], &myiter, NULL, NULL, AKSL_TREE_SEARCH_DFS_POSTORDER, &parms, NULL)); + if ( parms.node != &tree[6] ) { + FAIL_BREAK(e, AKERR_API, "DFS_POSTORDER_SEARCH didn't find the node"); + } + if ( parms.steps != 7 ) { + FAIL_BREAK(e, AKERR_API, "DFS_POSTORDER_SEARCH should've found the node in 7 steps, instead took %d", parms.steps); + } + + } CLEANUP { + } PROCESS(e) { + } FINISH_NORETURN(e); + + return 0; +}