tests/test_tree.c

Mon, 19 Feb 2024 22:12:13 +0100

author
Mike Becker <universe@uap-core.de>
date
Mon, 19 Feb 2024 22:12:13 +0100
changeset 837
7c15fea5cbea
parent 836
2672a2f79484
child 838
1ce90ab4fab9
permissions
-rw-r--r--

add depth assertion to basic tree iterator test

     1 /*
     2  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
     3  *
     4  * Copyright 2023 Mike Becker, Olaf Wintermann All rights reserved.
     5  *
     6  * Redistribution and use in source and binary forms, with or without
     7  * modification, are permitted provided that the following conditions are met:
     8  *
     9  *   1. Redistributions of source code must retain the above copyright
    10  *      notice, this list of conditions and the following disclaimer.
    11  *
    12  *   2. Redistributions in binary form must reproduce the above copyright
    13  *      notice, this list of conditions and the following disclaimer in the
    14  *      documentation and/or other materials provided with the distribution.
    15  *
    16  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
    17  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
    18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
    19  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
    20  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
    21  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
    22  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
    23  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
    24  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
    25  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
    26  * POSSIBILITY OF SUCH DAMAGE.
    27  */
    29 #include "cx/tree.h"
    31 #include "cx/test.h"
    33 typedef struct tree_node {
    34     struct tree_node *parent;
    35     struct tree_node *next;
    36     struct tree_node *prev;
    37     struct tree_node *children;
    38     int data;
    39 } tree_node;
    41 #define tree_node_layout \
    42     offsetof(tree_node, parent), offsetof(tree_node, children), \
    43     offsetof(tree_node, prev), offsetof(tree_node, next)
    45 #define tree_child_list offsetof(tree_node, children),offsetof(tree_node, next)
    47 CX_TEST(test_tree_link_new_child) {
    48     tree_node parent = {0};
    49     tree_node child = {0};
    51     CX_TEST_DO {
    52         cx_tree_link(&parent, &child, tree_node_layout);
    53         CX_TEST_ASSERT(parent.next == NULL);
    54         CX_TEST_ASSERT(parent.prev == NULL);
    55         CX_TEST_ASSERT(parent.parent == NULL);
    56         CX_TEST_ASSERT(parent.children == &child);
    57         CX_TEST_ASSERT(child.parent == &parent);
    58         CX_TEST_ASSERT(child.next == NULL);
    59         CX_TEST_ASSERT(child.prev == NULL);
    60         CX_TEST_ASSERT(child.children == NULL);
    61     }
    62 }
    64 CX_TEST(test_tree_link_add_child) {
    65     tree_node parent = {0};
    66     tree_node child1 = {0};
    67     tree_node child2 = {0};
    68     tree_node child3 = {0};
    70     CX_TEST_DO {
    71         cx_tree_link(&parent, &child1, tree_node_layout);
    72         cx_tree_link(&parent, &child2, tree_node_layout);
    73         cx_tree_link(&parent, &child3, tree_node_layout);
    74         CX_TEST_ASSERT(parent.next == NULL);
    75         CX_TEST_ASSERT(parent.prev == NULL);
    76         CX_TEST_ASSERT(parent.parent == NULL);
    77         CX_TEST_ASSERT(parent.children == &child3);
    79         CX_TEST_ASSERT(child1.parent == &parent);
    80         CX_TEST_ASSERT(child2.parent == &parent);
    81         CX_TEST_ASSERT(child3.parent == &parent);
    82         CX_TEST_ASSERT(child1.children == NULL);
    83         CX_TEST_ASSERT(child2.children == NULL);
    84         CX_TEST_ASSERT(child3.children == NULL);
    86         CX_TEST_ASSERT(child3.prev == NULL);
    87         CX_TEST_ASSERT(child3.next == &child2);
    88         CX_TEST_ASSERT(child2.prev == &child3);
    89         CX_TEST_ASSERT(child2.next == &child1);
    90         CX_TEST_ASSERT(child1.prev == &child2);
    91         CX_TEST_ASSERT(child1.next == NULL);
    92     }
    93 }
    95 CX_TEST(test_tree_link_move_to_other_parent) {
    96     tree_node parent = {0};
    97     tree_node child1 = {0};
    98     tree_node child2 = {0};
    99     tree_node child3 = {0};
   100     cx_tree_link(&parent, &child1, tree_node_layout);
   101     cx_tree_link(&parent, &child2, tree_node_layout);
   102     cx_tree_link(&parent, &child3, tree_node_layout);
   104     CX_TEST_DO {
   105         cx_tree_link(&child3, &child2, tree_node_layout);
   107         CX_TEST_ASSERT(parent.next == NULL);
   108         CX_TEST_ASSERT(parent.prev == NULL);
   109         CX_TEST_ASSERT(parent.parent == NULL);
   110         CX_TEST_ASSERT(parent.children == &child3);
   112         CX_TEST_ASSERT(child1.parent == &parent);
   113         CX_TEST_ASSERT(child2.parent == &child3);
   114         CX_TEST_ASSERT(child3.parent == &parent);
   115         CX_TEST_ASSERT(child1.children == NULL);
   116         CX_TEST_ASSERT(child2.children == NULL);
   117         CX_TEST_ASSERT(child3.children == &child2);
   119         CX_TEST_ASSERT(child3.prev == NULL);
   120         CX_TEST_ASSERT(child3.next == &child1);
   121         CX_TEST_ASSERT(child1.prev == &child3);
   122         CX_TEST_ASSERT(child1.next == NULL);
   124         CX_TEST_ASSERT(child2.prev == NULL);
   125         CX_TEST_ASSERT(child2.next == NULL);
   126     }
   127 }
   129 CX_TEST(test_tree_unlink) {
   130     tree_node parent = {0};
   131     tree_node child1 = {0};
   132     tree_node child2 = {0};
   133     tree_node child3 = {0};
   134     cx_tree_link(&parent, &child1, tree_node_layout);
   135     cx_tree_link(&parent, &child3, tree_node_layout);
   136     cx_tree_link(&child3, &child2, tree_node_layout);
   138     CX_TEST_DO {
   139         cx_tree_unlink(&child3, tree_node_layout);
   141         CX_TEST_ASSERT(parent.next == NULL);
   142         CX_TEST_ASSERT(parent.prev == NULL);
   143         CX_TEST_ASSERT(parent.parent == NULL);
   144         CX_TEST_ASSERT(parent.children == &child1);
   146         CX_TEST_ASSERT(child1.parent == &parent);
   147         CX_TEST_ASSERT(child1.children == NULL);
   148         CX_TEST_ASSERT(child1.prev == NULL);
   149         CX_TEST_ASSERT(child1.next == NULL);
   151         // child 3 is unlinked
   152         CX_TEST_ASSERT(child3.parent == NULL);
   153         CX_TEST_ASSERT(child3.prev == NULL);
   154         CX_TEST_ASSERT(child3.next == NULL);
   156         // child 2 is still child of the unlinked child 3
   157         CX_TEST_ASSERT(child3.children == &child2);
   158         CX_TEST_ASSERT(child2.parent == &child3);
   159         CX_TEST_ASSERT(child2.children == NULL);
   160         CX_TEST_ASSERT(child2.prev == NULL);
   161         CX_TEST_ASSERT(child2.next == NULL);
   162     }
   163 }
   165 static int test_tree_search_function(void const *n, void const *d) {
   166     tree_node const *node = n;
   167     int data = *((int const*)d);
   169     if (data < node->data) return -1;
   170     else if (data == node->data) return 0;
   171     else return data - node->data;
   172 }
   174 CX_TEST(test_tree_search) {
   175     tree_node root = {0};
   176     tree_node a = {0};
   177     tree_node b = {0};
   178     tree_node c = {0};
   179     tree_node aa = {0};
   180     tree_node ab = {0};
   181     tree_node ba = {0};
   182     tree_node ca = {0};
   183     tree_node cb = {0};
   184     tree_node cc = {0};
   185     tree_node cba = {0};
   187     int testdata[] = {0, 10, 14, 18, 20, 25, 30, 32, 34, 36, 40};
   188     tree_node* testnodes[] = {&root, &a, &aa, &ab, &b, &ba, &c, &ca, &cb, &cba, &cc};
   190     for (unsigned i = 0 ; i <= 10 ; i++) {
   191         testnodes[i]->data = testdata[i];
   192     }
   194     cx_tree_link(&root, &a, tree_node_layout);
   195     cx_tree_link(&root, &b, tree_node_layout);
   196     cx_tree_link(&root, &c, tree_node_layout);
   198     cx_tree_link(&a, &aa, tree_node_layout);
   199     cx_tree_link(&a, &ab, tree_node_layout);
   201     cx_tree_link(&b, &ba, tree_node_layout);
   203     cx_tree_link(&c, &ca, tree_node_layout);
   204     cx_tree_link(&c, &cb, tree_node_layout);
   205     cx_tree_link(&c, &cc, tree_node_layout);
   207     cx_tree_link(&cb, &cba, tree_node_layout);
   209     int s;
   210     int r;
   211     tree_node *n;
   212     CX_TEST_DO {
   213         for (unsigned i = 0 ; i <= 10 ; i++) {
   214             s = testdata[i];
   215             r = cx_tree_search(&root, &s, test_tree_search_function,
   216                                (void **) &n, tree_child_list);
   217             CX_TEST_ASSERT(r == 0);
   218             CX_TEST_ASSERT(n == testnodes[i]);
   219         }
   221         s = -5;
   222         r = cx_tree_search(&root, &s, test_tree_search_function,
   223                            (void **) &n, tree_child_list);
   224         CX_TEST_ASSERT(r < 0);
   225         CX_TEST_ASSERT(n == NULL);
   227         s = 26;
   228         r = cx_tree_search(&root, &s, test_tree_search_function,
   229                            (void **) &n, tree_child_list);
   230         CX_TEST_ASSERT(r > 0);
   231         CX_TEST_ASSERT(n == &ba);
   233         s = 35;
   234         r = cx_tree_search(&root, &s, test_tree_search_function,
   235                            (void **) &n, tree_child_list);
   236         CX_TEST_ASSERT(r > 0);
   237         CX_TEST_ASSERT(n == &cb);
   239         s = 38;
   240         r = cx_tree_search(&root, &s, test_tree_search_function,
   241                            (void **) &n, tree_child_list);
   242         CX_TEST_ASSERT(r > 0);
   243         CX_TEST_ASSERT(n == &cba);
   245         s = 42;
   246         r = cx_tree_search(&root, &s, test_tree_search_function,
   247                            (void **) &n, tree_child_list);
   248         CX_TEST_ASSERT(r > 0);
   249         CX_TEST_ASSERT(n == &cc);
   250     }
   251 }
   253 CX_TEST(test_tree_iterator_create_and_dispose) {
   254     tree_node root;
   255     CX_TEST_DO {
   256         CxTreeIterator iter = cx_tree_iterator(&root, false, tree_child_list);
   257         CX_TEST_ASSERT(!iter.visit_on_exit);
   258         CX_TEST_ASSERT(!iter.exiting);
   259         CX_TEST_ASSERT(iter.counter == 1);
   260         CX_TEST_ASSERT(iter.node == &root);
   261         CX_TEST_ASSERT(!iter.base.mutating);
   262         CX_TEST_ASSERT(!iter.base.remove);
   263         CX_TEST_ASSERT(iter.stack != NULL);
   264         CX_TEST_ASSERT(iter.stack_capacity > 0);
   265         CX_TEST_ASSERT(iter.stack_size == 1);
   266         CX_TEST_ASSERT(iter.depth == 1);
   267         CX_TEST_ASSERT(iter.loc_next == offsetof(tree_node, next));
   268         CX_TEST_ASSERT(iter.loc_children == offsetof(tree_node, children));
   269         cxTreeIteratorDispose(&iter);
   270         CX_TEST_ASSERT(iter.stack == NULL);
   271     }
   272 }
   274 CX_TEST(test_tree_iterator_basic_test_only_enter) {
   275     tree_node root = {0};
   276     tree_node a = {0};
   277     tree_node b = {0};
   278     tree_node c = {0};
   279     tree_node aa = {0};
   280     tree_node ab = {0};
   281     tree_node ba = {0};
   282     tree_node ca = {0};
   283     tree_node cb = {0};
   284     tree_node cc = {0};
   285     tree_node cba = {0};
   287     cx_tree_link(&root, &a, tree_node_layout);
   288     cx_tree_link(&root, &b, tree_node_layout);
   289     cx_tree_link(&root, &c, tree_node_layout);
   290     cx_tree_link(&a, &aa, tree_node_layout);
   291     cx_tree_link(&a, &ab, tree_node_layout);
   292     cx_tree_link(&b, &ba, tree_node_layout);
   293     cx_tree_link(&c, &ca, tree_node_layout);
   294     cx_tree_link(&c, &cb, tree_node_layout);
   295     cx_tree_link(&c, &cc, tree_node_layout);
   296     cx_tree_link(&cb, &cba, tree_node_layout);
   297     CX_TEST_DO {
   298         CxTreeIterator iter = cx_tree_iterator(&root, false, tree_child_list);
   299         unsigned chk = 0;
   300         cx_foreach(tree_node*, node, iter) {
   301             CX_TEST_ASSERT(node->data == 0);
   302             node->data++;
   303             chk++;
   304             CX_TEST_ASSERT(node == iter.node);
   305             CX_TEST_ASSERT(!iter.exiting);
   306             if (node == &root) {
   307                 CX_TEST_ASSERT(iter.depth == 1);
   308             } else if (node == &a || node == &b || node == &c) {
   309                 CX_TEST_ASSERT(iter.depth == 2);
   310             } else if (node == &cba) {
   311                 CX_TEST_ASSERT(iter.depth == 4);
   312             } else {
   313                 CX_TEST_ASSERT(iter.depth == 3);
   314             }
   315         }
   316         CX_TEST_ASSERT(iter.counter == 11);
   317         CX_TEST_ASSERT(chk == 11);
   318         CX_TEST_ASSERT(iter.stack == NULL);
   319         CX_TEST_ASSERT(root.data == 1);
   320         CX_TEST_ASSERT(a.data == 1);
   321         CX_TEST_ASSERT(b.data == 1);
   322         CX_TEST_ASSERT(c.data == 1);
   323         CX_TEST_ASSERT(aa.data == 1);
   324         CX_TEST_ASSERT(ab.data == 1);
   325         CX_TEST_ASSERT(ba.data == 1);
   326         CX_TEST_ASSERT(ca.data == 1);
   327         CX_TEST_ASSERT(cb.data == 1);
   328         CX_TEST_ASSERT(cc.data == 1);
   329         CX_TEST_ASSERT(cba.data == 1);
   330     }
   331 }
   333 CxTestSuite *cx_test_suite_tree_low_level(void) {
   334     CxTestSuite *suite = cx_test_suite_new("tree (low level)");
   336     cx_test_register(suite, test_tree_link_new_child);
   337     cx_test_register(suite, test_tree_link_add_child);
   338     cx_test_register(suite, test_tree_link_move_to_other_parent);
   339     cx_test_register(suite, test_tree_unlink);
   340     cx_test_register(suite, test_tree_search);
   341     cx_test_register(suite, test_tree_iterator_create_and_dispose);
   342     cx_test_register(suite, test_tree_iterator_basic_test_only_enter);
   344     return suite;
   345 }

mercurial