xref: /openbmc/qemu/tests/unit/test-qtree.c (revision f00506aeca2f6d92318967693f8da8c713c163f3)
1*e3feb2ccSEmilio Cota /*
2*e3feb2ccSEmilio Cota  * SPDX-License-Identifier: LGPL-2.1-or-later
3*e3feb2ccSEmilio Cota  *
4*e3feb2ccSEmilio Cota  * Tests for QTree.
5*e3feb2ccSEmilio Cota  * Original source: glib
6*e3feb2ccSEmilio Cota  *   https://gitlab.gnome.org/GNOME/glib/-/blob/main/glib/tests/tree.c
7*e3feb2ccSEmilio Cota  *   LGPL license.
8*e3feb2ccSEmilio Cota  *   Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
9*e3feb2ccSEmilio Cota  */
10*e3feb2ccSEmilio Cota 
11*e3feb2ccSEmilio Cota #include "qemu/osdep.h"
12*e3feb2ccSEmilio Cota #include "qemu/qtree.h"
13*e3feb2ccSEmilio Cota 
my_compare(gconstpointer a,gconstpointer b)14*e3feb2ccSEmilio Cota static gint my_compare(gconstpointer a, gconstpointer b)
15*e3feb2ccSEmilio Cota {
16*e3feb2ccSEmilio Cota     const char *cha = a;
17*e3feb2ccSEmilio Cota     const char *chb = b;
18*e3feb2ccSEmilio Cota 
19*e3feb2ccSEmilio Cota     return *cha - *chb;
20*e3feb2ccSEmilio Cota }
21*e3feb2ccSEmilio Cota 
my_compare_with_data(gconstpointer a,gconstpointer b,gpointer user_data)22*e3feb2ccSEmilio Cota static gint my_compare_with_data(gconstpointer a,
23*e3feb2ccSEmilio Cota                                  gconstpointer b,
24*e3feb2ccSEmilio Cota                                  gpointer user_data)
25*e3feb2ccSEmilio Cota {
26*e3feb2ccSEmilio Cota     const char *cha = a;
27*e3feb2ccSEmilio Cota     const char *chb = b;
28*e3feb2ccSEmilio Cota 
29*e3feb2ccSEmilio Cota     /* just check that we got the right data */
30*e3feb2ccSEmilio Cota     g_assert(GPOINTER_TO_INT(user_data) == 123);
31*e3feb2ccSEmilio Cota 
32*e3feb2ccSEmilio Cota     return *cha - *chb;
33*e3feb2ccSEmilio Cota }
34*e3feb2ccSEmilio Cota 
my_search(gconstpointer a,gconstpointer b)35*e3feb2ccSEmilio Cota static gint my_search(gconstpointer a, gconstpointer b)
36*e3feb2ccSEmilio Cota {
37*e3feb2ccSEmilio Cota     return my_compare(b, a);
38*e3feb2ccSEmilio Cota }
39*e3feb2ccSEmilio Cota 
40*e3feb2ccSEmilio Cota static gpointer destroyed_key;
41*e3feb2ccSEmilio Cota static gpointer destroyed_value;
42*e3feb2ccSEmilio Cota static guint destroyed_key_count;
43*e3feb2ccSEmilio Cota static guint destroyed_value_count;
44*e3feb2ccSEmilio Cota 
my_key_destroy(gpointer key)45*e3feb2ccSEmilio Cota static void my_key_destroy(gpointer key)
46*e3feb2ccSEmilio Cota {
47*e3feb2ccSEmilio Cota     destroyed_key = key;
48*e3feb2ccSEmilio Cota     destroyed_key_count++;
49*e3feb2ccSEmilio Cota }
50*e3feb2ccSEmilio Cota 
my_value_destroy(gpointer value)51*e3feb2ccSEmilio Cota static void my_value_destroy(gpointer value)
52*e3feb2ccSEmilio Cota {
53*e3feb2ccSEmilio Cota     destroyed_value = value;
54*e3feb2ccSEmilio Cota     destroyed_value_count++;
55*e3feb2ccSEmilio Cota }
56*e3feb2ccSEmilio Cota 
my_traverse(gpointer key,gpointer value,gpointer data)57*e3feb2ccSEmilio Cota static gint my_traverse(gpointer key, gpointer value, gpointer data)
58*e3feb2ccSEmilio Cota {
59*e3feb2ccSEmilio Cota     char *ch = key;
60*e3feb2ccSEmilio Cota 
61*e3feb2ccSEmilio Cota     g_assert((*ch) > 0);
62*e3feb2ccSEmilio Cota 
63*e3feb2ccSEmilio Cota     if (*ch == 'd') {
64*e3feb2ccSEmilio Cota         return TRUE;
65*e3feb2ccSEmilio Cota     }
66*e3feb2ccSEmilio Cota 
67*e3feb2ccSEmilio Cota     return FALSE;
68*e3feb2ccSEmilio Cota }
69*e3feb2ccSEmilio Cota 
70*e3feb2ccSEmilio Cota char chars[] =
71*e3feb2ccSEmilio Cota     "0123456789"
72*e3feb2ccSEmilio Cota     "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
73*e3feb2ccSEmilio Cota     "abcdefghijklmnopqrstuvwxyz";
74*e3feb2ccSEmilio Cota 
75*e3feb2ccSEmilio Cota char chars2[] =
76*e3feb2ccSEmilio Cota     "0123456789"
77*e3feb2ccSEmilio Cota     "abcdefghijklmnopqrstuvwxyz";
78*e3feb2ccSEmilio Cota 
check_order(gpointer key,gpointer value,gpointer data)79*e3feb2ccSEmilio Cota static gint check_order(gpointer key, gpointer value, gpointer data)
80*e3feb2ccSEmilio Cota {
81*e3feb2ccSEmilio Cota     char **p = data;
82*e3feb2ccSEmilio Cota     char *ch = key;
83*e3feb2ccSEmilio Cota 
84*e3feb2ccSEmilio Cota     g_assert(**p == *ch);
85*e3feb2ccSEmilio Cota 
86*e3feb2ccSEmilio Cota     (*p)++;
87*e3feb2ccSEmilio Cota 
88*e3feb2ccSEmilio Cota     return FALSE;
89*e3feb2ccSEmilio Cota }
90*e3feb2ccSEmilio Cota 
test_tree_search(void)91*e3feb2ccSEmilio Cota static void test_tree_search(void)
92*e3feb2ccSEmilio Cota {
93*e3feb2ccSEmilio Cota     gint i;
94*e3feb2ccSEmilio Cota     QTree *tree;
95*e3feb2ccSEmilio Cota     gboolean removed;
96*e3feb2ccSEmilio Cota     gchar c;
97*e3feb2ccSEmilio Cota     gchar *p, *d;
98*e3feb2ccSEmilio Cota 
99*e3feb2ccSEmilio Cota     tree = q_tree_new_with_data(my_compare_with_data, GINT_TO_POINTER(123));
100*e3feb2ccSEmilio Cota 
101*e3feb2ccSEmilio Cota     for (i = 0; chars[i]; i++) {
102*e3feb2ccSEmilio Cota         q_tree_insert(tree, &chars[i], &chars[i]);
103*e3feb2ccSEmilio Cota     }
104*e3feb2ccSEmilio Cota 
105*e3feb2ccSEmilio Cota     q_tree_foreach(tree, my_traverse, NULL);
106*e3feb2ccSEmilio Cota 
107*e3feb2ccSEmilio Cota     g_assert(q_tree_nnodes(tree) == strlen(chars));
108*e3feb2ccSEmilio Cota     g_assert(q_tree_height(tree) == 6);
109*e3feb2ccSEmilio Cota 
110*e3feb2ccSEmilio Cota     p = chars;
111*e3feb2ccSEmilio Cota     q_tree_foreach(tree, check_order, &p);
112*e3feb2ccSEmilio Cota 
113*e3feb2ccSEmilio Cota     for (i = 0; i < 26; i++) {
114*e3feb2ccSEmilio Cota         removed = q_tree_remove(tree, &chars[i + 10]);
115*e3feb2ccSEmilio Cota         g_assert(removed);
116*e3feb2ccSEmilio Cota     }
117*e3feb2ccSEmilio Cota 
118*e3feb2ccSEmilio Cota     c = '\0';
119*e3feb2ccSEmilio Cota     removed = q_tree_remove(tree, &c);
120*e3feb2ccSEmilio Cota     g_assert(!removed);
121*e3feb2ccSEmilio Cota 
122*e3feb2ccSEmilio Cota     q_tree_foreach(tree, my_traverse, NULL);
123*e3feb2ccSEmilio Cota 
124*e3feb2ccSEmilio Cota     g_assert(q_tree_nnodes(tree) == strlen(chars2));
125*e3feb2ccSEmilio Cota     g_assert(q_tree_height(tree) == 6);
126*e3feb2ccSEmilio Cota 
127*e3feb2ccSEmilio Cota     p = chars2;
128*e3feb2ccSEmilio Cota     q_tree_foreach(tree, check_order, &p);
129*e3feb2ccSEmilio Cota 
130*e3feb2ccSEmilio Cota     for (i = 25; i >= 0; i--) {
131*e3feb2ccSEmilio Cota         q_tree_insert(tree, &chars[i + 10], &chars[i + 10]);
132*e3feb2ccSEmilio Cota     }
133*e3feb2ccSEmilio Cota 
134*e3feb2ccSEmilio Cota     p = chars;
135*e3feb2ccSEmilio Cota     q_tree_foreach(tree, check_order, &p);
136*e3feb2ccSEmilio Cota 
137*e3feb2ccSEmilio Cota     c = '0';
138*e3feb2ccSEmilio Cota     p = q_tree_lookup(tree, &c);
139*e3feb2ccSEmilio Cota     g_assert(p && *p == c);
140*e3feb2ccSEmilio Cota     g_assert(q_tree_lookup_extended(tree, &c, (gpointer *)&d, (gpointer *)&p));
141*e3feb2ccSEmilio Cota     g_assert(c == *d && c == *p);
142*e3feb2ccSEmilio Cota 
143*e3feb2ccSEmilio Cota     c = 'A';
144*e3feb2ccSEmilio Cota     p = q_tree_lookup(tree, &c);
145*e3feb2ccSEmilio Cota     g_assert(p && *p == c);
146*e3feb2ccSEmilio Cota 
147*e3feb2ccSEmilio Cota     c = 'a';
148*e3feb2ccSEmilio Cota     p = q_tree_lookup(tree, &c);
149*e3feb2ccSEmilio Cota     g_assert(p && *p == c);
150*e3feb2ccSEmilio Cota 
151*e3feb2ccSEmilio Cota     c = 'z';
152*e3feb2ccSEmilio Cota     p = q_tree_lookup(tree, &c);
153*e3feb2ccSEmilio Cota     g_assert(p && *p == c);
154*e3feb2ccSEmilio Cota 
155*e3feb2ccSEmilio Cota     c = '!';
156*e3feb2ccSEmilio Cota     p = q_tree_lookup(tree, &c);
157*e3feb2ccSEmilio Cota     g_assert(p == NULL);
158*e3feb2ccSEmilio Cota 
159*e3feb2ccSEmilio Cota     c = '=';
160*e3feb2ccSEmilio Cota     p = q_tree_lookup(tree, &c);
161*e3feb2ccSEmilio Cota     g_assert(p == NULL);
162*e3feb2ccSEmilio Cota 
163*e3feb2ccSEmilio Cota     c = '|';
164*e3feb2ccSEmilio Cota     p = q_tree_lookup(tree, &c);
165*e3feb2ccSEmilio Cota     g_assert(p == NULL);
166*e3feb2ccSEmilio Cota 
167*e3feb2ccSEmilio Cota     c = '0';
168*e3feb2ccSEmilio Cota     p = q_tree_search(tree, my_search, &c);
169*e3feb2ccSEmilio Cota     g_assert(p && *p == c);
170*e3feb2ccSEmilio Cota 
171*e3feb2ccSEmilio Cota     c = 'A';
172*e3feb2ccSEmilio Cota     p = q_tree_search(tree, my_search, &c);
173*e3feb2ccSEmilio Cota     g_assert(p && *p == c);
174*e3feb2ccSEmilio Cota 
175*e3feb2ccSEmilio Cota     c = 'a';
176*e3feb2ccSEmilio Cota     p = q_tree_search(tree, my_search, &c);
177*e3feb2ccSEmilio Cota     g_assert(p && *p == c);
178*e3feb2ccSEmilio Cota 
179*e3feb2ccSEmilio Cota     c = 'z';
180*e3feb2ccSEmilio Cota     p = q_tree_search(tree, my_search, &c);
181*e3feb2ccSEmilio Cota     g_assert(p && *p == c);
182*e3feb2ccSEmilio Cota 
183*e3feb2ccSEmilio Cota     c = '!';
184*e3feb2ccSEmilio Cota     p = q_tree_search(tree, my_search, &c);
185*e3feb2ccSEmilio Cota     g_assert(p == NULL);
186*e3feb2ccSEmilio Cota 
187*e3feb2ccSEmilio Cota     c = '=';
188*e3feb2ccSEmilio Cota     p = q_tree_search(tree, my_search, &c);
189*e3feb2ccSEmilio Cota     g_assert(p == NULL);
190*e3feb2ccSEmilio Cota 
191*e3feb2ccSEmilio Cota     c = '|';
192*e3feb2ccSEmilio Cota     p = q_tree_search(tree, my_search, &c);
193*e3feb2ccSEmilio Cota     g_assert(p == NULL);
194*e3feb2ccSEmilio Cota 
195*e3feb2ccSEmilio Cota     q_tree_destroy(tree);
196*e3feb2ccSEmilio Cota }
197*e3feb2ccSEmilio Cota 
test_tree_remove(void)198*e3feb2ccSEmilio Cota static void test_tree_remove(void)
199*e3feb2ccSEmilio Cota {
200*e3feb2ccSEmilio Cota     QTree *tree;
201*e3feb2ccSEmilio Cota     char c, d;
202*e3feb2ccSEmilio Cota     gint i;
203*e3feb2ccSEmilio Cota     gboolean removed;
204*e3feb2ccSEmilio Cota 
205*e3feb2ccSEmilio Cota     tree = q_tree_new_full((GCompareDataFunc)my_compare, NULL,
206*e3feb2ccSEmilio Cota                            my_key_destroy,
207*e3feb2ccSEmilio Cota                            my_value_destroy);
208*e3feb2ccSEmilio Cota 
209*e3feb2ccSEmilio Cota     for (i = 0; chars[i]; i++) {
210*e3feb2ccSEmilio Cota         q_tree_insert(tree, &chars[i], &chars[i]);
211*e3feb2ccSEmilio Cota     }
212*e3feb2ccSEmilio Cota 
213*e3feb2ccSEmilio Cota     c = '0';
214*e3feb2ccSEmilio Cota     q_tree_insert(tree, &c, &c);
215*e3feb2ccSEmilio Cota     g_assert(destroyed_key == &c);
216*e3feb2ccSEmilio Cota     g_assert(destroyed_value == &chars[0]);
217*e3feb2ccSEmilio Cota     destroyed_key = NULL;
218*e3feb2ccSEmilio Cota     destroyed_value = NULL;
219*e3feb2ccSEmilio Cota 
220*e3feb2ccSEmilio Cota     d = '1';
221*e3feb2ccSEmilio Cota     q_tree_replace(tree, &d, &d);
222*e3feb2ccSEmilio Cota     g_assert(destroyed_key == &chars[1]);
223*e3feb2ccSEmilio Cota     g_assert(destroyed_value == &chars[1]);
224*e3feb2ccSEmilio Cota     destroyed_key = NULL;
225*e3feb2ccSEmilio Cota     destroyed_value = NULL;
226*e3feb2ccSEmilio Cota 
227*e3feb2ccSEmilio Cota     c = '2';
228*e3feb2ccSEmilio Cota     removed = q_tree_remove(tree, &c);
229*e3feb2ccSEmilio Cota     g_assert(removed);
230*e3feb2ccSEmilio Cota     g_assert(destroyed_key == &chars[2]);
231*e3feb2ccSEmilio Cota     g_assert(destroyed_value == &chars[2]);
232*e3feb2ccSEmilio Cota     destroyed_key = NULL;
233*e3feb2ccSEmilio Cota     destroyed_value = NULL;
234*e3feb2ccSEmilio Cota 
235*e3feb2ccSEmilio Cota     c = '3';
236*e3feb2ccSEmilio Cota     removed = q_tree_steal(tree, &c);
237*e3feb2ccSEmilio Cota     g_assert(removed);
238*e3feb2ccSEmilio Cota     g_assert(destroyed_key == NULL);
239*e3feb2ccSEmilio Cota     g_assert(destroyed_value == NULL);
240*e3feb2ccSEmilio Cota 
241*e3feb2ccSEmilio Cota     const gchar *remove = "omkjigfedba";
242*e3feb2ccSEmilio Cota     for (i = 0; remove[i]; i++) {
243*e3feb2ccSEmilio Cota         removed = q_tree_remove(tree, &remove[i]);
244*e3feb2ccSEmilio Cota         g_assert(removed);
245*e3feb2ccSEmilio Cota     }
246*e3feb2ccSEmilio Cota 
247*e3feb2ccSEmilio Cota     q_tree_destroy(tree);
248*e3feb2ccSEmilio Cota }
249*e3feb2ccSEmilio Cota 
test_tree_destroy(void)250*e3feb2ccSEmilio Cota static void test_tree_destroy(void)
251*e3feb2ccSEmilio Cota {
252*e3feb2ccSEmilio Cota     QTree *tree;
253*e3feb2ccSEmilio Cota     gint i;
254*e3feb2ccSEmilio Cota 
255*e3feb2ccSEmilio Cota     tree = q_tree_new(my_compare);
256*e3feb2ccSEmilio Cota 
257*e3feb2ccSEmilio Cota     for (i = 0; chars[i]; i++) {
258*e3feb2ccSEmilio Cota         q_tree_insert(tree, &chars[i], &chars[i]);
259*e3feb2ccSEmilio Cota     }
260*e3feb2ccSEmilio Cota 
261*e3feb2ccSEmilio Cota     g_assert(q_tree_nnodes(tree) == strlen(chars));
262*e3feb2ccSEmilio Cota 
263*e3feb2ccSEmilio Cota     g_test_message("nnodes: %d", q_tree_nnodes(tree));
264*e3feb2ccSEmilio Cota     q_tree_ref(tree);
265*e3feb2ccSEmilio Cota     q_tree_destroy(tree);
266*e3feb2ccSEmilio Cota 
267*e3feb2ccSEmilio Cota     g_test_message("nnodes: %d", q_tree_nnodes(tree));
268*e3feb2ccSEmilio Cota     g_assert(q_tree_nnodes(tree) == 0);
269*e3feb2ccSEmilio Cota 
270*e3feb2ccSEmilio Cota     q_tree_unref(tree);
271*e3feb2ccSEmilio Cota }
272*e3feb2ccSEmilio Cota 
test_tree_insert(void)273*e3feb2ccSEmilio Cota static void test_tree_insert(void)
274*e3feb2ccSEmilio Cota {
275*e3feb2ccSEmilio Cota     QTree *tree;
276*e3feb2ccSEmilio Cota     gchar *p;
277*e3feb2ccSEmilio Cota     gint i;
278*e3feb2ccSEmilio Cota     gchar *scrambled;
279*e3feb2ccSEmilio Cota 
280*e3feb2ccSEmilio Cota     tree = q_tree_new(my_compare);
281*e3feb2ccSEmilio Cota 
282*e3feb2ccSEmilio Cota     for (i = 0; chars[i]; i++) {
283*e3feb2ccSEmilio Cota         q_tree_insert(tree, &chars[i], &chars[i]);
284*e3feb2ccSEmilio Cota     }
285*e3feb2ccSEmilio Cota     p = chars;
286*e3feb2ccSEmilio Cota     q_tree_foreach(tree, check_order, &p);
287*e3feb2ccSEmilio Cota 
288*e3feb2ccSEmilio Cota     q_tree_unref(tree);
289*e3feb2ccSEmilio Cota     tree = q_tree_new(my_compare);
290*e3feb2ccSEmilio Cota 
291*e3feb2ccSEmilio Cota     for (i = strlen(chars) - 1; i >= 0; i--) {
292*e3feb2ccSEmilio Cota         q_tree_insert(tree, &chars[i], &chars[i]);
293*e3feb2ccSEmilio Cota     }
294*e3feb2ccSEmilio Cota     p = chars;
295*e3feb2ccSEmilio Cota     q_tree_foreach(tree, check_order, &p);
296*e3feb2ccSEmilio Cota 
297*e3feb2ccSEmilio Cota     q_tree_unref(tree);
298*e3feb2ccSEmilio Cota     tree = q_tree_new(my_compare);
299*e3feb2ccSEmilio Cota 
300*e3feb2ccSEmilio Cota     scrambled = g_strdup(chars);
301*e3feb2ccSEmilio Cota 
302*e3feb2ccSEmilio Cota     for (i = 0; i < 30; i++) {
303*e3feb2ccSEmilio Cota         gchar tmp;
304*e3feb2ccSEmilio Cota         gint a, b;
305*e3feb2ccSEmilio Cota 
306*e3feb2ccSEmilio Cota         a = g_random_int_range(0, strlen(scrambled));
307*e3feb2ccSEmilio Cota         b = g_random_int_range(0, strlen(scrambled));
308*e3feb2ccSEmilio Cota         tmp = scrambled[a];
309*e3feb2ccSEmilio Cota         scrambled[a] = scrambled[b];
310*e3feb2ccSEmilio Cota         scrambled[b] = tmp;
311*e3feb2ccSEmilio Cota     }
312*e3feb2ccSEmilio Cota 
313*e3feb2ccSEmilio Cota     for (i = 0; scrambled[i]; i++) {
314*e3feb2ccSEmilio Cota         q_tree_insert(tree, &scrambled[i], &scrambled[i]);
315*e3feb2ccSEmilio Cota     }
316*e3feb2ccSEmilio Cota     p = chars;
317*e3feb2ccSEmilio Cota     q_tree_foreach(tree, check_order, &p);
318*e3feb2ccSEmilio Cota 
319*e3feb2ccSEmilio Cota     g_free(scrambled);
320*e3feb2ccSEmilio Cota     q_tree_unref(tree);
321*e3feb2ccSEmilio Cota }
322*e3feb2ccSEmilio Cota 
main(int argc,char * argv[])323*e3feb2ccSEmilio Cota int main(int argc, char *argv[])
324*e3feb2ccSEmilio Cota {
325*e3feb2ccSEmilio Cota     g_test_init(&argc, &argv, NULL);
326*e3feb2ccSEmilio Cota 
327*e3feb2ccSEmilio Cota     g_test_add_func("/qtree/search", test_tree_search);
328*e3feb2ccSEmilio Cota     g_test_add_func("/qtree/remove", test_tree_remove);
329*e3feb2ccSEmilio Cota     g_test_add_func("/qtree/destroy", test_tree_destroy);
330*e3feb2ccSEmilio Cota     g_test_add_func("/qtree/insert", test_tree_insert);
331*e3feb2ccSEmilio Cota 
332*e3feb2ccSEmilio Cota     return g_test_run();
333*e3feb2ccSEmilio Cota }
334