(root)/
glib-2.79.0/
glib/
tests/
node.c
       1  /* GLIB - Library of useful routines for C programming
       2   * Copyright (C) 1995-1997  Peter Mattis, Spencer Kimball and Josh MacDonald
       3   *
       4   * SPDX-License-Identifier: LGPL-2.1-or-later
       5   *
       6   * This library is free software; you can redistribute it and/or
       7   * modify it under the terms of the GNU Lesser General Public
       8   * License as published by the Free Software Foundation; either
       9   * version 2.1 of the License, or (at your option) any later version.
      10   *
      11   * This library is distributed in the hope that it will be useful,
      12   * but WITHOUT ANY WARRANTY; without even the implied warranty of
      13   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      14   * Lesser General Public License for more details.
      15   *
      16   * You should have received a copy of the GNU Lesser General Public
      17   * License along with this library; if not, see <http://www.gnu.org/licenses/>.
      18   */
      19  
      20  /*
      21   * Modified by the GLib Team and others 1997-2000.  See the AUTHORS
      22   * file for a list of people on the GLib Team.  See the ChangeLog
      23   * files for a list of changes.  These files are distributed with
      24   * GLib at ftp://ftp.gtk.org/pub/gtk/. 
      25   */
      26  
      27  #undef G_DISABLE_ASSERT
      28  #undef G_LOG_DOMAIN
      29  
      30  #include <stdio.h>
      31  #include <string.h>
      32  #include <stdlib.h>
      33  
      34  #include "glib.h"
      35  
      36  typedef struct {
      37    GString *s;
      38    gint count;
      39  } CallbackData;
      40  
      41  static gboolean
      42  node_build_string (GNode    *node,
      43                     gpointer  data)
      44  {
      45    CallbackData *d = data;
      46  
      47    g_string_append_c (d->s, GPOINTER_TO_INT (node->data));
      48  
      49    d->count--;
      50  
      51    if (d->count == 0)
      52      return TRUE;
      53  
      54    return FALSE;
      55  }
      56  
      57  typedef struct {
      58      GTraverseType   traverse;
      59      GTraverseFlags  flags;
      60      gint            depth;
      61      gint            limit;
      62      const gchar    *expected;
      63  } TraverseData;
      64  
      65  static void
      66  traversal_test (void)
      67  {
      68    GNode *root;
      69    GNode *node_B;
      70    GNode *node_C;
      71    GNode *node_D;
      72    GNode *node_E;
      73    GNode *node_F;
      74    GNode *node_G;
      75    GNode *node_J;
      76    GNode *n;
      77    TraverseData orders[] = {
      78      { G_PRE_ORDER,   G_TRAVERSE_ALL,       -1, -1, "ABCDEFGHIJK" },
      79      { G_PRE_ORDER,   G_TRAVERSE_ALL,        1, -1, "A"           },
      80      { G_PRE_ORDER,   G_TRAVERSE_ALL,        2, -1, "ABF"         },
      81      { G_PRE_ORDER,   G_TRAVERSE_ALL,        3, -1, "ABCDEFG"     },
      82      { G_PRE_ORDER,   G_TRAVERSE_ALL,        3, -1, "ABCDEFG"     },
      83      { G_POST_ORDER,  G_TRAVERSE_ALL,       -1, -1, "CDEBHIJKGFA" },
      84      { G_POST_ORDER,  G_TRAVERSE_ALL,        1, -1, "A"           },
      85      { G_POST_ORDER,  G_TRAVERSE_ALL,        2, -1, "BFA"         },
      86      { G_POST_ORDER,  G_TRAVERSE_ALL,        3, -1, "CDEBGFA"     },
      87      { G_IN_ORDER,    G_TRAVERSE_ALL,       -1, -1, "CBDEAHGIJKF" },
      88      { G_IN_ORDER,    G_TRAVERSE_ALL,        1, -1, "A"           },
      89      { G_IN_ORDER,    G_TRAVERSE_ALL,        2, -1, "BAF"         },
      90      { G_IN_ORDER,    G_TRAVERSE_ALL,        3, -1, "CBDEAGF"     },
      91      { G_LEVEL_ORDER, G_TRAVERSE_ALL,       -1, -1, "ABFCDEGHIJK" },
      92      { G_LEVEL_ORDER, G_TRAVERSE_ALL,        1, -1, "A"           },
      93      { G_LEVEL_ORDER, G_TRAVERSE_ALL,        2, -1, "ABF"         },
      94      { G_LEVEL_ORDER, G_TRAVERSE_ALL,        3, -1, "ABFCDEG"     },
      95      { G_LEVEL_ORDER, G_TRAVERSE_LEAFS,     -1, -1, "CDEHIJK"     },
      96      { G_LEVEL_ORDER, G_TRAVERSE_NON_LEAFS, -1, -1, "ABFG"        },
      97      { G_PRE_ORDER,   G_TRAVERSE_ALL,       -1,  1, "A"           },
      98      { G_PRE_ORDER,   G_TRAVERSE_ALL,       -1,  2, "AB"          },
      99      { G_PRE_ORDER,   G_TRAVERSE_ALL,       -1,  3, "ABC"         },
     100      { G_PRE_ORDER,   G_TRAVERSE_ALL,       -1,  4, "ABCD"        },
     101      { G_PRE_ORDER,   G_TRAVERSE_ALL,       -1,  5, "ABCDE"       },
     102      { G_PRE_ORDER,   G_TRAVERSE_ALL,       -1,  6, "ABCDEF"      },
     103      { G_PRE_ORDER,   G_TRAVERSE_ALL,       -1,  7, "ABCDEFG"     },
     104      { G_PRE_ORDER,   G_TRAVERSE_ALL,       -1,  8, "ABCDEFGH"    },
     105      { G_PRE_ORDER,   G_TRAVERSE_ALL,       -1,  9, "ABCDEFGHI"   },
     106      { G_PRE_ORDER,   G_TRAVERSE_ALL,       -1, 10, "ABCDEFGHIJ"  },
     107      { G_PRE_ORDER,   G_TRAVERSE_ALL,        3,  1, "A"           },
     108      { G_PRE_ORDER,   G_TRAVERSE_ALL,        3,  2, "AB"          },
     109      { G_PRE_ORDER,   G_TRAVERSE_ALL,        3,  3, "ABC"         },
     110      { G_PRE_ORDER,   G_TRAVERSE_ALL,        3,  4, "ABCD"        },
     111      { G_PRE_ORDER,   G_TRAVERSE_ALL,        3,  5, "ABCDE"       },
     112      { G_PRE_ORDER,   G_TRAVERSE_ALL,        3,  6, "ABCDEF"      },
     113      { G_PRE_ORDER,   G_TRAVERSE_ALL,        3,  7, "ABCDEFG"     },
     114      { G_PRE_ORDER,   G_TRAVERSE_ALL,        3,  8, "ABCDEFG"     },
     115      { G_POST_ORDER,  G_TRAVERSE_ALL,       -1,  1, "C"           },
     116      { G_POST_ORDER,  G_TRAVERSE_ALL,       -1,  2, "CD"          },
     117      { G_POST_ORDER,  G_TRAVERSE_ALL,       -1,  3, "CDE"         },
     118      { G_POST_ORDER,  G_TRAVERSE_ALL,       -1,  4, "CDEB"        },
     119      { G_POST_ORDER,  G_TRAVERSE_ALL,       -1,  5, "CDEBH"       },
     120      { G_POST_ORDER,  G_TRAVERSE_ALL,       -1,  6, "CDEBHI"      },
     121      { G_POST_ORDER,  G_TRAVERSE_ALL,       -1,  7, "CDEBHIJ"     },
     122      { G_POST_ORDER,  G_TRAVERSE_ALL,       -1,  8, "CDEBHIJK"    },
     123      { G_POST_ORDER,  G_TRAVERSE_ALL,       -1,  9, "CDEBHIJKG"   },
     124      { G_POST_ORDER,  G_TRAVERSE_ALL,       -1, 10, "CDEBHIJKGF"  },
     125      { G_POST_ORDER,  G_TRAVERSE_ALL,        3,  1, "C"           },
     126      { G_POST_ORDER,  G_TRAVERSE_ALL,        3,  2, "CD"          },
     127      { G_POST_ORDER,  G_TRAVERSE_ALL,        3,  3, "CDE"         },
     128      { G_POST_ORDER,  G_TRAVERSE_ALL,        3,  4, "CDEB"        },
     129      { G_POST_ORDER,  G_TRAVERSE_ALL,        3,  5, "CDEBG"       },
     130      { G_POST_ORDER,  G_TRAVERSE_ALL,        3,  6, "CDEBGF"      },
     131      { G_POST_ORDER,  G_TRAVERSE_ALL,        3,  7, "CDEBGFA"     },
     132      { G_POST_ORDER,  G_TRAVERSE_ALL,        3,  8, "CDEBGFA"     },
     133      { G_IN_ORDER,    G_TRAVERSE_ALL,       -1,  1, "C"           },
     134      { G_IN_ORDER,    G_TRAVERSE_ALL,       -1,  2, "CB"          },
     135      { G_IN_ORDER,    G_TRAVERSE_ALL,       -1,  3, "CBD"         },
     136      { G_IN_ORDER,    G_TRAVERSE_ALL,       -1,  4, "CBDE"        },
     137      { G_IN_ORDER,    G_TRAVERSE_ALL,       -1,  5, "CBDEA"       },
     138      { G_IN_ORDER,    G_TRAVERSE_ALL,       -1,  6, "CBDEAH"      },
     139      { G_IN_ORDER,    G_TRAVERSE_ALL,       -1,  7, "CBDEAHG"     },
     140      { G_IN_ORDER,    G_TRAVERSE_ALL,       -1,  8, "CBDEAHGI"    },
     141      { G_IN_ORDER,    G_TRAVERSE_ALL,       -1,  9, "CBDEAHGIJ"   },
     142      { G_IN_ORDER,    G_TRAVERSE_ALL,       -1, 10, "CBDEAHGIJK"  },
     143      { G_IN_ORDER,    G_TRAVERSE_ALL,        3,  1, "C"           },
     144      { G_IN_ORDER,    G_TRAVERSE_ALL,        3,  2, "CB"          },
     145      { G_IN_ORDER,    G_TRAVERSE_ALL,        3,  3, "CBD"         },
     146      { G_IN_ORDER,    G_TRAVERSE_ALL,        3,  4, "CBDE"        },
     147      { G_IN_ORDER,    G_TRAVERSE_ALL,        3,  5, "CBDEA"       },
     148      { G_IN_ORDER,    G_TRAVERSE_ALL,        3,  6, "CBDEAG"      },
     149      { G_IN_ORDER,    G_TRAVERSE_ALL,        3,  7, "CBDEAGF"     },
     150      { G_IN_ORDER,    G_TRAVERSE_ALL,        3,  8, "CBDEAGF"     },
     151      { G_LEVEL_ORDER, G_TRAVERSE_ALL,       -1,  1, "A"           },
     152      { G_LEVEL_ORDER, G_TRAVERSE_ALL,       -1,  2, "AB"          },
     153      { G_LEVEL_ORDER, G_TRAVERSE_ALL,       -1,  3, "ABF"         },
     154      { G_LEVEL_ORDER, G_TRAVERSE_ALL,       -1,  4, "ABFC"        },
     155      { G_LEVEL_ORDER, G_TRAVERSE_ALL,       -1,  5, "ABFCD"       },
     156      { G_LEVEL_ORDER, G_TRAVERSE_ALL,       -1,  6, "ABFCDE"      },
     157      { G_LEVEL_ORDER, G_TRAVERSE_ALL,       -1,  7, "ABFCDEG"     },
     158      { G_LEVEL_ORDER, G_TRAVERSE_ALL,       -1,  8, "ABFCDEGH"    },
     159      { G_LEVEL_ORDER, G_TRAVERSE_ALL,       -1,  9, "ABFCDEGHI"   },
     160      { G_LEVEL_ORDER, G_TRAVERSE_ALL,       -1, 10, "ABFCDEGHIJ"  },
     161      { G_LEVEL_ORDER, G_TRAVERSE_ALL,        3,  1, "A"           },
     162      { G_LEVEL_ORDER, G_TRAVERSE_ALL,        3,  2, "AB"          },
     163      { G_LEVEL_ORDER, G_TRAVERSE_ALL,        3,  3, "ABF"         },
     164      { G_LEVEL_ORDER, G_TRAVERSE_ALL,        3,  4, "ABFC"        },
     165      { G_LEVEL_ORDER, G_TRAVERSE_ALL,        3,  5, "ABFCD"       },
     166      { G_LEVEL_ORDER, G_TRAVERSE_ALL,        3,  6, "ABFCDE"      },
     167      { G_LEVEL_ORDER, G_TRAVERSE_ALL,        3,  7, "ABFCDEG"     },
     168      { G_LEVEL_ORDER, G_TRAVERSE_ALL,        3,  8, "ABFCDEG"     },
     169    };
     170    gsize i;
     171    CallbackData data;
     172  
     173    root = g_node_new (GINT_TO_POINTER ('A'));
     174    node_B = g_node_new (GINT_TO_POINTER ('B'));
     175    g_node_append (root, node_B);
     176    g_node_append_data (node_B, GINT_TO_POINTER ('E'));
     177    g_node_prepend_data (node_B, GINT_TO_POINTER ('C'));
     178    node_D = g_node_new (GINT_TO_POINTER ('D'));
     179    g_node_insert (node_B, 1, node_D);
     180    node_F = g_node_new (GINT_TO_POINTER ('F'));
     181    g_node_append (root, node_F);
     182    node_G = g_node_new (GINT_TO_POINTER ('G'));
     183    g_node_append (node_F, node_G);
     184    node_J = g_node_new (GINT_TO_POINTER ('J'));
     185    g_node_prepend (node_G, node_J);
     186    g_node_insert (node_G, 42, g_node_new (GINT_TO_POINTER ('K')));
     187    g_node_insert_data (node_G, 0, GINT_TO_POINTER ('H'));
     188    g_node_insert (node_G, 1, g_node_new (GINT_TO_POINTER ('I')));
     189  
     190    /* we have built:                    A
     191     *                                 /   \
     192     *                               B       F
     193     *                             / | \       \
     194     *                           C   D   E       G
     195     *                                         / /\ \
     196     *                                        H I J  K
     197     *
     198     * for in-order traversal, 'G' is considered to be the "left"
     199     * child of 'F', which will cause 'F' to be the last node visited.
     200     */
     201  
     202    node_C = node_B->children;
     203    node_E = node_D->next;
     204  
     205    n = g_node_last_sibling (node_C);
     206    g_assert (n == node_E);
     207    n = g_node_last_sibling (node_D);
     208    g_assert (n == node_E);
     209    n = g_node_last_sibling (node_E);
     210    g_assert (n == node_E);
     211  
     212    data.s = g_string_new ("");  
     213    for (i = 0; i < G_N_ELEMENTS (orders); i++)
     214      {
     215        g_string_set_size (data.s, 0);
     216        data.count = orders[i].limit;
     217        g_node_traverse (root, orders[i].traverse, orders[i].flags, orders[i].depth, node_build_string, &data);
     218        g_assert_cmpstr (data.s->str, ==,  orders[i].expected);
     219      }
     220  
     221    g_node_reverse_children (node_B);
     222    g_node_reverse_children (node_G);
     223  
     224    g_string_set_size (data.s, 0);
     225    data.count = -1;
     226    g_node_traverse (root, G_LEVEL_ORDER, G_TRAVERSE_ALL, -1, node_build_string, &data);
     227    g_assert_cmpstr (data.s->str, ==, "ABFEDCGKJIH");
     228    
     229    g_node_append (node_D, g_node_new (GINT_TO_POINTER ('L')));
     230    g_node_insert (node_D, -1, g_node_new (GINT_TO_POINTER ('M')));
     231  
     232    g_string_set_size (data.s, 0);
     233    data.count = -1;
     234    g_node_traverse (root, G_LEVEL_ORDER, G_TRAVERSE_ALL, -1, node_build_string, &data);
     235    g_assert_cmpstr (data.s->str, ==, "ABFEDCGLMKJIH");
     236  
     237    g_string_set_size (data.s, 0);
     238    data.count = -1;
     239    g_node_traverse (root, G_PRE_ORDER, G_TRAVERSE_LEAFS, -1, node_build_string, &data);
     240    g_assert_cmpstr (data.s->str, ==, "ELMCKJIH");
     241  
     242    g_string_set_size (data.s, 0);
     243    data.count = -1;
     244    g_node_traverse (root, G_PRE_ORDER, G_TRAVERSE_NON_LEAFS, -1, node_build_string, &data);
     245    g_assert_cmpstr (data.s->str, ==, "ABDFG");
     246  
     247    g_node_destroy (root);
     248    g_string_free (data.s, TRUE);
     249  }
     250  
     251  static void
     252  construct_test (void)
     253  {
     254    GNode *root;
     255    GNode *node;
     256    GNode *node_B;
     257    GNode *node_D;
     258    GNode *node_F;
     259    GNode *node_G;
     260    GNode *node_J;
     261    GNode *node_H;
     262    guint i;
     263  
     264    root = g_node_new (GINT_TO_POINTER ('A'));
     265    g_assert_cmpint (g_node_depth (root), ==, 1);
     266    g_assert_cmpint (g_node_max_height (root), ==, 1);
     267  
     268    node_B = g_node_new (GINT_TO_POINTER ('B'));
     269    g_node_append (root, node_B);
     270    g_assert (root->children == node_B);
     271  
     272    g_node_append_data (node_B, GINT_TO_POINTER ('E'));
     273    g_node_prepend_data (node_B, GINT_TO_POINTER ('C'));
     274    node_D = g_node_new (GINT_TO_POINTER ('D'));
     275    g_node_insert (node_B, 1, node_D);
     276  
     277    node_F = g_node_new (GINT_TO_POINTER ('F'));
     278    g_node_append (root, node_F);
     279    g_assert (root->children->next == node_F);
     280  
     281    node_G = g_node_new (GINT_TO_POINTER ('G'));
     282    g_node_append (node_F, node_G);
     283    node_J = g_node_new (GINT_TO_POINTER ('J'));
     284    g_node_insert_after (node_G, NULL, node_J);
     285    g_node_insert (node_G, 42, g_node_new (GINT_TO_POINTER ('K')));
     286    node_H = g_node_new (GINT_TO_POINTER ('H'));
     287    g_node_insert_after (node_G, NULL, node_H);
     288    g_node_insert (node_G, 1, g_node_new (GINT_TO_POINTER ('I')));
     289  
     290    /* we have built:                    A
     291     *                                 /   \
     292     *                               B       F
     293     *                             / | \       \
     294     *                           C   D   E       G
     295     *                                         / /\ \
     296     *                                       H  I  J  K
     297     */
     298    g_assert_cmpint (g_node_depth (root), ==, 1);
     299    g_assert_cmpint (g_node_max_height (root), ==, 4);
     300    g_assert_cmpint (g_node_depth (node_G->children->next), ==, 4);
     301    g_assert_cmpint (g_node_n_nodes (root, G_TRAVERSE_LEAFS), ==, 7);
     302    g_assert_cmpint (g_node_n_nodes (root, G_TRAVERSE_NON_LEAFS), ==, 4);
     303    g_assert_cmpint (g_node_n_nodes (root, G_TRAVERSE_ALL), ==, 11);
     304    g_assert_cmpint (g_node_max_height (node_F), ==, 3);
     305    g_assert_cmpint (g_node_n_children (node_G), ==, 4);
     306    g_assert (g_node_find_child (root, G_TRAVERSE_ALL, GINT_TO_POINTER ('F')) == node_F);
     307    g_assert (g_node_find_child (node_G, G_TRAVERSE_LEAFS, GINT_TO_POINTER ('H')) == node_H);
     308    g_assert (g_node_find_child (root, G_TRAVERSE_ALL, GINT_TO_POINTER ('H')) == NULL);
     309    g_assert (g_node_find (root, G_LEVEL_ORDER, G_TRAVERSE_NON_LEAFS, GINT_TO_POINTER ('I')) == NULL);
     310    g_assert (g_node_find (root, G_IN_ORDER, G_TRAVERSE_LEAFS, GINT_TO_POINTER ('J')) == node_J);
     311  
     312    for (i = 0; i < g_node_n_children (node_B); i++)
     313      {
     314        node = g_node_nth_child (node_B, i);
     315        g_assert_cmpint (GPOINTER_TO_INT (node->data), ==, ('C' + i));
     316      }
     317  
     318    for (i = 0; i < g_node_n_children (node_G); i++)
     319      g_assert_cmpint (g_node_child_position (node_G, g_node_nth_child (node_G, i)), ==, i);
     320  
     321    g_node_destroy (root);
     322  }
     323  
     324  static void
     325  allocation_test (void)
     326  {
     327    GNode *root;
     328    GNode *node;
     329    gint i;
     330  
     331    root = g_node_new (NULL);
     332    node = root;
     333  
     334    for (i = 0; i < 2048; i++)
     335      {
     336        g_node_append (node, g_node_new (NULL));
     337        if ((i % 5) == 4)
     338          node = node->children->next;
     339      }
     340    g_assert_cmpint (g_node_max_height (root), >, 100);
     341    g_assert_cmpint (g_node_n_nodes (root, G_TRAVERSE_ALL), ==, 1 + 2048);
     342  
     343    g_node_destroy (root);
     344  }
     345  
     346  
     347  static void
     348  misc_test (void)
     349  {
     350    GNode *root;
     351    GNode *node_B;
     352    GNode *node_C;
     353    GNode *node_D;
     354    GNode *node_E;
     355    CallbackData data;
     356  
     357    root = g_node_new (GINT_TO_POINTER ('A'));
     358    node_B = g_node_new (GINT_TO_POINTER ('B'));
     359    g_node_append (root, node_B);
     360    node_D = g_node_new (GINT_TO_POINTER ('D'));
     361    g_node_append (root, node_D);
     362    node_C = g_node_new (GINT_TO_POINTER ('C'));
     363    g_node_insert_after (root, node_B, node_C);
     364    node_E = g_node_new (GINT_TO_POINTER ('E'));
     365    g_node_append (node_C, node_E);
     366  
     367    g_assert (g_node_get_root (node_E) == root);
     368    g_assert (g_node_is_ancestor (root, node_B));
     369    g_assert (g_node_is_ancestor (root, node_E));
     370    g_assert (!g_node_is_ancestor (node_B, node_D));
     371    g_assert (g_node_first_sibling (node_D) == node_B);
     372    g_assert (g_node_first_sibling (node_E) == node_E);
     373    g_assert (g_node_first_sibling (root) == root);
     374    g_assert_cmpint (g_node_child_index (root, GINT_TO_POINTER ('B')), ==, 0);
     375    g_assert_cmpint (g_node_child_index (root, GINT_TO_POINTER ('C')), ==, 1);
     376    g_assert_cmpint (g_node_child_index (root, GINT_TO_POINTER ('D')), ==, 2);
     377    g_assert_cmpint (g_node_child_index (root, GINT_TO_POINTER ('E')), ==, -1);
     378  
     379    data.s = g_string_new ("");
     380    data.count = -1;
     381    g_node_children_foreach (root, G_TRAVERSE_ALL, (GNodeForeachFunc)node_build_string, &data);
     382    g_assert_cmpstr (data.s->str, ==, "BCD");
     383  
     384    g_string_set_size (data.s, 0);
     385    data.count = -1;
     386    g_node_children_foreach (root, G_TRAVERSE_LEAVES, (GNodeForeachFunc)node_build_string, &data);
     387    g_assert_cmpstr (data.s->str, ==, "BD");
     388  
     389    g_string_set_size (data.s, 0);
     390    data.count = -1;
     391    g_node_children_foreach (root, G_TRAVERSE_NON_LEAVES, (GNodeForeachFunc)node_build_string, &data);
     392    g_assert_cmpstr (data.s->str, ==, "C");
     393    g_string_free (data.s, TRUE);
     394  
     395    g_node_destroy (root);
     396  }
     397  
     398  static gboolean
     399  check_order (GNode    *node,
     400               gpointer  data)
     401  {
     402    gchar **expected = data;
     403    gchar d;
     404  
     405    d = GPOINTER_TO_INT (node->data);
     406    g_assert_cmpint (d, ==, **expected);
     407    (*expected)++;
     408  
     409    return FALSE;
     410  }
     411  
     412  static void
     413  unlink_test (void)
     414  {
     415    GNode *root;
     416    GNode *node;
     417    GNode *bnode;
     418    GNode *cnode;
     419    gchar *expected;
     420  
     421    /*
     422     *        -------- a --------
     423     *       /         |          \
     424     *     b           c           d
     425     *   / | \       / | \       / | \
     426     * e   f   g   h   i   j   k   l   m
     427     *
     428     */
     429  
     430    root = g_node_new (GINT_TO_POINTER ('a'));
     431    node = bnode = g_node_append_data (root, GINT_TO_POINTER ('b'));
     432    g_node_append_data (node, GINT_TO_POINTER ('e'));
     433    g_node_append_data (node, GINT_TO_POINTER ('f'));
     434    g_node_append_data (node, GINT_TO_POINTER ('g'));
     435  
     436    node = cnode = g_node_append_data (root, GINT_TO_POINTER ('c'));
     437    g_node_append_data (node, GINT_TO_POINTER ('h'));
     438    g_node_append_data (node, GINT_TO_POINTER ('i'));
     439    g_node_append_data (node, GINT_TO_POINTER ('j'));
     440  
     441    node = g_node_append_data (root, GINT_TO_POINTER ('d'));
     442    g_node_append_data (node, GINT_TO_POINTER ('k'));
     443    g_node_append_data (node, GINT_TO_POINTER ('l'));
     444    g_node_append_data (node, GINT_TO_POINTER ('m'));
     445  
     446    g_node_unlink (cnode);
     447  
     448    expected = "abdefgklm";
     449    g_node_traverse (root, G_LEVEL_ORDER, G_TRAVERSE_ALL, -1, check_order, &expected);
     450  
     451    expected = "abd";
     452    g_node_traverse (root, G_LEVEL_ORDER, G_TRAVERSE_ALL, 1, check_order, &expected);
     453  
     454    expected = "chij";
     455    g_node_traverse (cnode, G_LEVEL_ORDER, G_TRAVERSE_ALL, -1, check_order, &expected);
     456  
     457    g_node_destroy (bnode);
     458  
     459    expected = "adklm";
     460    g_node_traverse (root, G_LEVEL_ORDER, G_TRAVERSE_ALL, -1, check_order, &expected);
     461  
     462    g_node_destroy (root);
     463    g_node_destroy (cnode);
     464  }
     465  
     466  static gpointer
     467  copy_up (gconstpointer src,
     468           gpointer      data)
     469  {
     470    gchar l, u;
     471  
     472    l = GPOINTER_TO_INT (src);
     473    u = g_ascii_toupper (l);
     474  
     475    return GINT_TO_POINTER ((int)u);
     476  }
     477  
     478  static void
     479  copy_test (void)
     480  {
     481    GNode *root;
     482    GNode *copy;
     483    gchar *expected;
     484  
     485    root = g_node_new (GINT_TO_POINTER ('a'));
     486    g_node_append_data (root, GINT_TO_POINTER ('b'));
     487    g_node_append_data (root, GINT_TO_POINTER ('c'));
     488    g_node_append_data (root, GINT_TO_POINTER ('d'));
     489  
     490    expected = "abcd";
     491    g_node_traverse (root, G_LEVEL_ORDER, G_TRAVERSE_ALL, -1, check_order, &expected);
     492  
     493    copy = g_node_copy (root);
     494  
     495    expected = "abcd";
     496    g_node_traverse (copy, G_LEVEL_ORDER, G_TRAVERSE_ALL, -1, check_order, &expected);
     497  
     498    g_node_destroy (copy);
     499  
     500    copy = g_node_copy_deep (root, copy_up, NULL);
     501  
     502    expected = "ABCD";
     503    g_node_traverse (copy, G_LEVEL_ORDER, G_TRAVERSE_ALL, -1, check_order, &expected);
     504  
     505    g_node_destroy (copy);
     506  
     507    g_node_destroy (root);
     508  }
     509  
     510  int
     511  main (int   argc,
     512        char *argv[])
     513  {
     514    g_test_init (&argc, &argv, NULL);
     515  
     516    g_test_add_func ("/node/allocation", allocation_test);
     517    g_test_add_func ("/node/construction", construct_test);
     518    g_test_add_func ("/node/traversal", traversal_test);
     519    g_test_add_func ("/node/misc", misc_test);
     520    g_test_add_func ("/node/unlink", unlink_test);
     521    g_test_add_func ("/node/copy", copy_test);
     522  
     523    return g_test_run ();
     524  }