gkdbus: Fix underflow and unreachable code bug
[platform/upstream/glib.git] / 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 }