Sun, 07 Jul 2024 14:56:44 +0200
change cx_tree_link() from prepending to appending children - fixes #391
src/cx/tree.h | file | annotate | diff | comparison | revisions | |
src/tree.c | file | annotate | diff | comparison | revisions | |
tests/test_tree.c | file | annotate | diff | comparison | revisions |
--- a/src/cx/tree.h Sun Jul 07 14:20:28 2024 +0200 +++ b/src/cx/tree.h Sun Jul 07 14:56:44 2024 +0200 @@ -249,23 +249,26 @@ * Links a node to a (new) parent. * * If the node has already a parent, it is unlinked, first. - * If the parent has children already, the node is \em prepended to the list + * If the parent has children already, the node is \em appended to the list * of all currently existing children. * * @param parent the parent node * @param node the node that shall be linked * @param loc_parent offset in the node struct for the parent pointer * @param loc_children offset in the node struct for the children linked list + * @param loc_last_child optional offset in the node struct for the pointer to + * the last child in the linked list (negative if there is no such pointer) * @param loc_prev offset in the node struct for the prev pointer * @param loc_next offset in the node struct for the next pointer * @see cx_tree_unlink() */ __attribute__((__nonnull__)) void cx_tree_link( - void * restrict parent, - void * restrict node, + void *restrict parent, + void *restrict node, ptrdiff_t loc_parent, ptrdiff_t loc_children, + ptrdiff_t loc_last_child, ptrdiff_t loc_prev, ptrdiff_t loc_next ); @@ -278,6 +281,8 @@ * @param node the node that shall be unlinked from its parent * @param loc_parent offset in the node struct for the parent pointer * @param loc_children offset in the node struct for the children linked list + * @param loc_last_child optional offset in the node struct for the pointer to + * the last child in the linked list (negative if there is no such pointer) * @param loc_prev offset in the node struct for the prev pointer * @param loc_next offset in the node struct for the next pointer * @see cx_tree_link() @@ -287,6 +292,7 @@ void *node, ptrdiff_t loc_parent, ptrdiff_t loc_children, + ptrdiff_t loc_last_child, ptrdiff_t loc_prev, ptrdiff_t loc_next );
--- a/src/tree.c Sun Jul 07 14:20:28 2024 +0200 +++ b/src/tree.c Sun Jul 07 14:56:44 2024 +0200 @@ -36,6 +36,7 @@ #define CX_TREE_PTR(cur, off) (*(void**)(((char*)(cur))+(off))) #define tree_parent(node) CX_TREE_PTR(node, loc_parent) #define tree_children(node) CX_TREE_PTR(node, loc_children) +#define tree_last_child(node) CX_TREE_PTR(node, loc_last_child) #define tree_prev(node) CX_TREE_PTR(node, loc_prev) #define tree_next(node) CX_TREE_PTR(node, loc_next) @@ -44,23 +45,37 @@ void *restrict node, ptrdiff_t loc_parent, ptrdiff_t loc_children, + ptrdiff_t loc_last_child, ptrdiff_t loc_prev, ptrdiff_t loc_next ) { void *current_parent = tree_parent(node); if (current_parent == parent) return; if (current_parent != NULL) { - cx_tree_unlink(node, loc_parent, loc_children, + cx_tree_unlink(node, loc_parent, loc_children, loc_last_child, loc_prev, loc_next); } if (tree_children(parent) == NULL) { tree_children(parent) = node; + if (loc_last_child >= 0) { + tree_last_child(parent) = node; + } } else { - void *children = tree_children(parent); - tree_prev(children) = node; - tree_next(node) = children; - tree_children(parent) = node; + if (loc_last_child >= 0) { + void *child = tree_last_child(parent); + tree_prev(node) = child; + tree_next(child) = node; + tree_last_child(parent) = node; + } else { + void *child = tree_children(parent); + void *next; + while ((next = tree_next(child)) != NULL) { + child = next; + } + tree_prev(node) = child; + tree_next(child) = node; + } } tree_parent(node) = parent; } @@ -69,6 +84,7 @@ void *node, ptrdiff_t loc_parent, ptrdiff_t loc_children, + ptrdiff_t loc_last_child, ptrdiff_t loc_prev, ptrdiff_t loc_next ) { @@ -76,13 +92,24 @@ void *left = tree_prev(node); void *right = tree_next(node); - assert(left == NULL || tree_children(tree_parent(node)) != node); + void *parent = tree_parent(node); + assert(left == NULL || tree_children(parent) != node); + assert(right == NULL || loc_last_child < 0 || + tree_last_child(parent) != node); + if (left == NULL) { - tree_children(tree_parent(node)) = right; + tree_children(parent) = right; } else { tree_next(left) = right; } - if (right != NULL) tree_prev(right) = left; + if (right == NULL) { + if (loc_last_child >= 0) { + tree_last_child(parent) = left; + } + } else { + tree_prev(right) = left; + } + tree_parent(node) = NULL; tree_prev(node) = NULL; tree_next(node) = NULL;
--- a/tests/test_tree.c Sun Jul 07 14:20:28 2024 +0200 +++ b/tests/test_tree.c Sun Jul 07 14:56:44 2024 +0200 @@ -40,11 +40,24 @@ int data; } tree_node; +typedef struct tree_node2 { + struct tree_node2 *parent; + struct tree_node2 *next; + struct tree_node2 *prev; + struct tree_node2 *children; + struct tree_node2 *last_child; + int data; +} tree_node2; + #define tree_node_layout \ - offsetof(tree_node, parent), offsetof(tree_node, children), \ + offsetof(tree_node, parent), offsetof(tree_node, children), -1, \ offsetof(tree_node, prev), offsetof(tree_node, next) +#define tree_node2_layout \ + offsetof(tree_node2, parent), offsetof(tree_node2, children),\ + offsetof(tree_node2, last_child), \ + offsetof(tree_node2, prev), offsetof(tree_node2, next) -#define tree_child_list offsetof(tree_node, children),offsetof(tree_node, next) +#define tree_children(type) offsetof(type, children), offsetof(type, next) CX_TEST(test_tree_link_new_child) { tree_node parent = {0}; @@ -76,7 +89,7 @@ CX_TEST_ASSERT(parent.next == NULL); CX_TEST_ASSERT(parent.prev == NULL); CX_TEST_ASSERT(parent.parent == NULL); - CX_TEST_ASSERT(parent.children == &child3); + CX_TEST_ASSERT(parent.children == &child1); CX_TEST_ASSERT(child1.parent == &parent); CX_TEST_ASSERT(child2.parent == &parent); @@ -85,12 +98,12 @@ CX_TEST_ASSERT(child2.children == NULL); CX_TEST_ASSERT(child3.children == NULL); - CX_TEST_ASSERT(child3.prev == NULL); - CX_TEST_ASSERT(child3.next == &child2); - CX_TEST_ASSERT(child2.prev == &child3); - CX_TEST_ASSERT(child2.next == &child1); - CX_TEST_ASSERT(child1.prev == &child2); - CX_TEST_ASSERT(child1.next == NULL); + CX_TEST_ASSERT(child1.prev == NULL); + CX_TEST_ASSERT(child1.next == &child2); + CX_TEST_ASSERT(child2.prev == &child1); + CX_TEST_ASSERT(child2.next == &child3); + CX_TEST_ASSERT(child3.prev == &child2); + CX_TEST_ASSERT(child3.next == NULL); } } @@ -109,7 +122,7 @@ CX_TEST_ASSERT(parent.next == NULL); CX_TEST_ASSERT(parent.prev == NULL); CX_TEST_ASSERT(parent.parent == NULL); - CX_TEST_ASSERT(parent.children == &child3); + CX_TEST_ASSERT(parent.children == &child1); CX_TEST_ASSERT(child1.parent == &parent); CX_TEST_ASSERT(child2.parent == &child3); @@ -118,10 +131,10 @@ CX_TEST_ASSERT(child2.children == NULL); CX_TEST_ASSERT(child3.children == &child2); - CX_TEST_ASSERT(child3.prev == NULL); - CX_TEST_ASSERT(child3.next == &child1); - CX_TEST_ASSERT(child1.prev == &child3); - CX_TEST_ASSERT(child1.next == NULL); + CX_TEST_ASSERT(child1.prev == NULL); + CX_TEST_ASSERT(child1.next == &child3); + CX_TEST_ASSERT(child3.prev == &child1); + CX_TEST_ASSERT(child3.next == NULL); CX_TEST_ASSERT(child2.prev == NULL); CX_TEST_ASSERT(child2.next == NULL); @@ -161,6 +174,155 @@ CX_TEST_ASSERT(child2.children == NULL); CX_TEST_ASSERT(child2.prev == NULL); CX_TEST_ASSERT(child2.next == NULL); + + // unlink last child from parent + cx_tree_unlink(&child1, tree_node_layout); + CX_TEST_ASSERT(parent.next == NULL); + CX_TEST_ASSERT(parent.prev == NULL); + CX_TEST_ASSERT(parent.parent == NULL); + CX_TEST_ASSERT(parent.children == NULL); + CX_TEST_ASSERT(child1.parent == NULL); + } +} + +CX_TEST(test_tree2_link_new_child) { + tree_node2 parent = {0}; + tree_node2 child = {0}; + + CX_TEST_DO { + cx_tree_link(&parent, &child, tree_node2_layout); + CX_TEST_ASSERT(parent.next == NULL); + CX_TEST_ASSERT(parent.prev == NULL); + CX_TEST_ASSERT(parent.parent == NULL); + CX_TEST_ASSERT(parent.children == &child); + CX_TEST_ASSERT(parent.last_child == &child); + CX_TEST_ASSERT(child.parent == &parent); + CX_TEST_ASSERT(child.next == NULL); + CX_TEST_ASSERT(child.prev == NULL); + CX_TEST_ASSERT(child.children == NULL); + CX_TEST_ASSERT(child.last_child == NULL); + } +} + +CX_TEST(test_tree2_link_add_child) { + tree_node2 parent = {0}; + tree_node2 child1 = {0}; + tree_node2 child2 = {0}; + tree_node2 child3 = {0}; + + CX_TEST_DO { + cx_tree_link(&parent, &child1, tree_node2_layout); + cx_tree_link(&parent, &child2, tree_node2_layout); + cx_tree_link(&parent, &child3, tree_node2_layout); + CX_TEST_ASSERT(parent.next == NULL); + CX_TEST_ASSERT(parent.prev == NULL); + CX_TEST_ASSERT(parent.parent == NULL); + CX_TEST_ASSERT(parent.children == &child1); + CX_TEST_ASSERT(parent.last_child == &child3); + + CX_TEST_ASSERT(child1.parent == &parent); + CX_TEST_ASSERT(child2.parent == &parent); + CX_TEST_ASSERT(child3.parent == &parent); + CX_TEST_ASSERT(child1.children == NULL); + CX_TEST_ASSERT(child2.children == NULL); + CX_TEST_ASSERT(child3.children == NULL); + CX_TEST_ASSERT(child1.last_child == NULL); + CX_TEST_ASSERT(child2.last_child == NULL); + CX_TEST_ASSERT(child3.last_child == NULL); + + CX_TEST_ASSERT(child1.prev == NULL); + CX_TEST_ASSERT(child1.next == &child2); + CX_TEST_ASSERT(child2.prev == &child1); + CX_TEST_ASSERT(child2.next == &child3); + CX_TEST_ASSERT(child3.prev == &child2); + CX_TEST_ASSERT(child3.next == NULL); + } +} + +CX_TEST(test_tree2_link_move_to_other_parent) { + tree_node2 parent = {0}; + tree_node2 child1 = {0}; + tree_node2 child2 = {0}; + tree_node2 child3 = {0}; + cx_tree_link(&parent, &child1, tree_node2_layout); + cx_tree_link(&parent, &child2, tree_node2_layout); + cx_tree_link(&parent, &child3, tree_node2_layout); + + CX_TEST_DO { + cx_tree_link(&child3, &child2, tree_node2_layout); + + CX_TEST_ASSERT(parent.next == NULL); + CX_TEST_ASSERT(parent.prev == NULL); + CX_TEST_ASSERT(parent.parent == NULL); + CX_TEST_ASSERT(parent.children == &child1); + CX_TEST_ASSERT(parent.last_child == &child3); + + CX_TEST_ASSERT(child1.parent == &parent); + CX_TEST_ASSERT(child2.parent == &child3); + CX_TEST_ASSERT(child3.parent == &parent); + CX_TEST_ASSERT(child1.children == NULL); + CX_TEST_ASSERT(child2.children == NULL); + CX_TEST_ASSERT(child3.children == &child2); + CX_TEST_ASSERT(child1.last_child == NULL); + CX_TEST_ASSERT(child2.last_child == NULL); + CX_TEST_ASSERT(child3.last_child == &child2); + + CX_TEST_ASSERT(child1.prev == NULL); + CX_TEST_ASSERT(child1.next == &child3); + CX_TEST_ASSERT(child3.prev == &child1); + CX_TEST_ASSERT(child3.next == NULL); + + CX_TEST_ASSERT(child2.prev == NULL); + CX_TEST_ASSERT(child2.next == NULL); + } +} + +CX_TEST(test_tree2_unlink) { + tree_node2 parent = {0}; + tree_node2 child1 = {0}; + tree_node2 child2 = {0}; + tree_node2 child3 = {0}; + cx_tree_link(&parent, &child1, tree_node2_layout); + cx_tree_link(&parent, &child3, tree_node2_layout); + cx_tree_link(&child3, &child2, tree_node2_layout); + + CX_TEST_DO { + cx_tree_unlink(&child3, tree_node2_layout); + + CX_TEST_ASSERT(parent.next == NULL); + CX_TEST_ASSERT(parent.prev == NULL); + CX_TEST_ASSERT(parent.parent == NULL); + CX_TEST_ASSERT(parent.children == &child1); + CX_TEST_ASSERT(parent.last_child == &child1); + + CX_TEST_ASSERT(child1.parent == &parent); + CX_TEST_ASSERT(child1.children == NULL); + CX_TEST_ASSERT(child1.last_child == NULL); + CX_TEST_ASSERT(child1.prev == NULL); + CX_TEST_ASSERT(child1.next == NULL); + + // child 3 is unlinked + CX_TEST_ASSERT(child3.parent == NULL); + CX_TEST_ASSERT(child3.prev == NULL); + CX_TEST_ASSERT(child3.next == NULL); + + // child 2 is still child of the unlinked child 3 + CX_TEST_ASSERT(child3.children == &child2); + CX_TEST_ASSERT(child3.last_child == &child2); + CX_TEST_ASSERT(child2.parent == &child3); + CX_TEST_ASSERT(child2.children == NULL); + CX_TEST_ASSERT(child2.last_child == NULL); + CX_TEST_ASSERT(child2.prev == NULL); + CX_TEST_ASSERT(child2.next == NULL); + + // unlink last child from parent + cx_tree_unlink(&child1, tree_node2_layout); + CX_TEST_ASSERT(parent.next == NULL); + CX_TEST_ASSERT(parent.prev == NULL); + CX_TEST_ASSERT(parent.parent == NULL); + CX_TEST_ASSERT(parent.children == NULL); + CX_TEST_ASSERT(parent.last_child == NULL); + CX_TEST_ASSERT(child1.parent == NULL); } } @@ -215,38 +377,38 @@ for (unsigned i = 0 ; i <= 10 ; i++) { s = testdata[i]; r = cx_tree_search(&root, &s, test_tree_search_function, - (void **) &n, tree_child_list); + (void **) &n, tree_children(tree_node)); CX_TEST_ASSERT(r == 0); CX_TEST_ASSERT(n == testnodes[i]); } s = -5; r = cx_tree_search(&root, &s, test_tree_search_function, - (void **) &n, tree_child_list); + (void **) &n, tree_children(tree_node)); CX_TEST_ASSERT(r < 0); CX_TEST_ASSERT(n == NULL); s = 26; r = cx_tree_search(&root, &s, test_tree_search_function, - (void **) &n, tree_child_list); + (void **) &n, tree_children(tree_node)); CX_TEST_ASSERT(r > 0); CX_TEST_ASSERT(n == &ba); s = 35; r = cx_tree_search(&root, &s, test_tree_search_function, - (void **) &n, tree_child_list); + (void **) &n, tree_children(tree_node)); CX_TEST_ASSERT(r > 0); CX_TEST_ASSERT(n == &cb); s = 38; r = cx_tree_search(&root, &s, test_tree_search_function, - (void **) &n, tree_child_list); + (void **) &n, tree_children(tree_node)); CX_TEST_ASSERT(r > 0); CX_TEST_ASSERT(n == &cba); s = 42; r = cx_tree_search(&root, &s, test_tree_search_function, - (void **) &n, tree_child_list); + (void **) &n, tree_children(tree_node)); CX_TEST_ASSERT(r > 0); CX_TEST_ASSERT(n == &cc); } @@ -255,7 +417,7 @@ CX_TEST(test_tree_iterator_create_and_dispose) { tree_node root; CX_TEST_DO { - CxTreeIterator iter = cx_tree_iterator(&root, false, tree_child_list); + CxTreeIterator iter = cx_tree_iterator(&root, false, tree_children(tree_node)); CX_TEST_ASSERT(!iter.visit_on_exit); CX_TEST_ASSERT(!iter.exiting); CX_TEST_ASSERT(iter.counter == 1); @@ -288,9 +450,9 @@ tree_node* expected_order[] = { &root, - &c, &cc,&cb, &cba,&ca, + &a, &aa, &ab, &b, &ba, - &a, &ab, &aa, + &c, &ca, &cb, &cba, &cc, }; tree_node* actual_order[16]; // reserve more space in case s.t. goes wrong @@ -305,7 +467,7 @@ cx_tree_link(&c, &cc, tree_node_layout); cx_tree_link(&cb, &cba, tree_node_layout); CX_TEST_DO { - CxTreeIterator iter = cx_tree_iterator(&root, false, tree_child_list); + CxTreeIterator iter = cx_tree_iterator(&root, false, tree_children(tree_node)); unsigned chk = 0; cx_foreach(tree_node*, node, iter) { CX_TEST_ASSERT(node->data == 0); @@ -358,7 +520,7 @@ cx_tree_link(&c, &cc, tree_node_layout); cx_tree_link(&cb, &cba, tree_node_layout); CX_TEST_DO { - CxTreeIterator iter = cx_tree_iterator(&root, true, tree_child_list); + CxTreeIterator iter = cx_tree_iterator(&root, true, tree_children(tree_node)); unsigned chk = 0; cx_foreach(tree_node*, node, iter) { CX_TEST_ASSERT(iter.exiting || node->data == 0); @@ -393,10 +555,7 @@ } typedef struct test_xml_node { - struct test_xml_node *parent; - struct test_xml_node *next; - struct test_xml_node *prev; - struct test_xml_node *children; + struct tree_node base; char const* name; } test_xml_node; @@ -431,18 +590,18 @@ target_dependencies.name = "dependencies"; target_feature_dependencies.name = "dependencies"; - cx_tree_link(&project, &target, tree_node_layout); - cx_tree_link(&project, &dependency2, tree_node_layout); + cx_tree_link(&project, &config, tree_node_layout); cx_tree_link(&project, &dependency1, tree_node_layout); - cx_tree_link(&project, &config, tree_node_layout); - cx_tree_link(&config, &var3, tree_node_layout); + cx_tree_link(&project, &dependency2, tree_node_layout); + cx_tree_link(&project, &target, tree_node_layout); + cx_tree_link(&config, &var1, tree_node_layout); cx_tree_link(&config, &var2, tree_node_layout); - cx_tree_link(&config, &var1, tree_node_layout); + cx_tree_link(&config, &var3, tree_node_layout); cx_tree_link(&dependency1, &dependency1make, tree_node_layout); + cx_tree_link(&dependency2, &dependency2lang, tree_node_layout); cx_tree_link(&dependency2, &dependency2make, tree_node_layout); - cx_tree_link(&dependency2, &dependency2lang, tree_node_layout); + cx_tree_link(&target, &target_feature, tree_node_layout); cx_tree_link(&target, &target_dependencies, tree_node_layout); - cx_tree_link(&target, &target_feature, tree_node_layout); cx_tree_link(&target_feature, &target_feature_dependencies, tree_node_layout); char const *expected = @@ -451,7 +610,7 @@ "<target><feature><dependencies></dependencies></feature><dependencies></dependencies></target></project>"; char *actual = malloc(512); CX_TEST_DO { - CxTreeIterator iter = cx_tree_iterator(&project, true, tree_child_list); + CxTreeIterator iter = cx_tree_iterator(&project, true, tree_children(tree_node)); size_t i = 0; cx_foreach(test_xml_node*, node, iter) { size_t len = strlen(node->name); @@ -497,7 +656,7 @@ cx_tree_link(c, cc, tree_node_layout); cx_tree_link(cb, cba, tree_node_layout); - CxTreeIterator iter = cx_tree_iterator(root, true, tree_child_list); + CxTreeIterator iter = cx_tree_iterator(root, true, tree_children(tree_node)); cx_foreach(tree_node *, node, iter) { if (iter.exiting) { cxFree(alloc,node); @@ -514,7 +673,7 @@ tree_node child; cx_tree_link(&root, &child, tree_node_layout); CX_TEST_DO { - CxTreeVisitor iter = cx_tree_visitor(&root, tree_child_list); + CxTreeVisitor iter = cx_tree_visitor(&root, tree_children(tree_node)); CX_TEST_ASSERT(iter.counter == 1); CX_TEST_ASSERT(iter.node == &root); CX_TEST_ASSERT(!iter.base.mutating); @@ -545,8 +704,8 @@ tree_node* expected_order[] = { &root, - &c, &b, &a, - &cc, &cb, &ca, &ba, &ab, &aa, + &a, &b, &c, + &aa, &ab, &ba, &ca, &cb, &cc, &cba }; tree_node* actual_order[16]; // reserve more space in case s.t. goes wrong @@ -562,7 +721,7 @@ cx_tree_link(&c, &cc, tree_node_layout); cx_tree_link(&cb, &cba, tree_node_layout); CX_TEST_DO { - CxTreeVisitor iter = cx_tree_visitor(&root, tree_child_list); + CxTreeVisitor iter = cx_tree_visitor(&root, tree_children(tree_node)); unsigned chk = 0; cx_foreach(tree_node*, node, iter) { CX_TEST_ASSERT(node->data == 0); @@ -595,7 +754,7 @@ tree_node root = {0}; CX_TEST_DO { - CxTreeVisitor iter = cx_tree_visitor(&root, tree_child_list); + CxTreeVisitor iter = cx_tree_visitor(&root, tree_children(tree_node)); unsigned chk = 0; cx_foreach(tree_node*, node, iter) { CX_TEST_ASSERT(node == iter.node); @@ -624,7 +783,7 @@ cx_tree_link(&b, &c, tree_node_layout); CX_TEST_DO { - CxTreeVisitor iter = cx_tree_visitor(&root, tree_child_list); + CxTreeVisitor iter = cx_tree_visitor(&root, tree_children(tree_node)); unsigned chk = 0; cx_foreach(tree_node*, node, iter) { CX_TEST_ASSERT(node == iter.node); @@ -659,8 +818,8 @@ tree_node* expected_order[] = { &root, - &c, &b, &a, - &ba, &ab, &aa + &a, &b, &c, + &aa, &ab, &ba }; tree_node* actual_order[16]; // reserve more space in case s.t. goes wrong @@ -675,7 +834,7 @@ cx_tree_link(&c, &cc, tree_node_layout); cx_tree_link(&cb, &cba, tree_node_layout); CX_TEST_DO { - CxTreeVisitor iter = cx_tree_visitor(&root, tree_child_list); + CxTreeVisitor iter = cx_tree_visitor(&root, tree_children(tree_node)); unsigned chk = 0; cx_foreach(tree_node*, node, iter) { CX_TEST_ASSERT(node->data == 0); @@ -722,11 +881,11 @@ tree_node cc = {0}; tree_node cba = {0}; - tree_node* expected_order[] = { + tree_node *expected_order[] = { &root, + &a, &aa, &ab, + &b, &ba, &c, - &b, &ba, - &a, &ab, &aa, }; tree_node* actual_order[16]; // reserve more space in case s.t. goes wrong @@ -741,7 +900,7 @@ cx_tree_link(&c, &cc, tree_node_layout); cx_tree_link(&cb, &cba, tree_node_layout); CX_TEST_DO { - CxTreeIterator iter = cx_tree_iterator(&root, false, tree_child_list); + CxTreeIterator iter = cx_tree_iterator(&root, false, tree_children(tree_node)); unsigned chk = 0; cx_foreach(tree_node*, node, iter) { CX_TEST_ASSERT(node->data == 0); @@ -799,7 +958,7 @@ cx_tree_link(&c, &cc, tree_node_layout); cx_tree_link(&cb, &cba, tree_node_layout); CX_TEST_DO { - CxTreeIterator iter = cx_tree_iterator(&root, true, tree_child_list); + CxTreeIterator iter = cx_tree_iterator(&root, true, tree_children(tree_node)); unsigned chk = 0; cx_foreach(tree_node*, node, iter) { CX_TEST_ASSERT(iter.exiting || node->data == 0); @@ -841,6 +1000,10 @@ cx_test_register(suite, test_tree_link_add_child); cx_test_register(suite, test_tree_link_move_to_other_parent); cx_test_register(suite, test_tree_unlink); + cx_test_register(suite, test_tree2_link_new_child); + cx_test_register(suite, test_tree2_link_add_child); + cx_test_register(suite, test_tree2_link_move_to_other_parent); + cx_test_register(suite, test_tree2_unlink); cx_test_register(suite, test_tree_search); cx_test_register(suite, test_tree_iterator_create_and_dispose); cx_test_register(suite, test_tree_iterator_basic_only_enter);