aboutsummaryrefslogtreecommitdiff
path: root/tests/unit/test-qtree.c
diff options
context:
space:
mode:
Diffstat (limited to 'tests/unit/test-qtree.c')
-rw-r--r--tests/unit/test-qtree.c333
1 files changed, 333 insertions, 0 deletions
diff --git a/tests/unit/test-qtree.c b/tests/unit/test-qtree.c
new file mode 100644
index 0000000..4d836d2
--- /dev/null
+++ b/tests/unit/test-qtree.c
@@ -0,0 +1,333 @@
+/*
+ * SPDX-License-Identifier: LGPL-2.1-or-later
+ *
+ * Tests for QTree.
+ * Original source: glib
+ * https://gitlab.gnome.org/GNOME/glib/-/blob/main/glib/tests/tree.c
+ * LGPL license.
+ * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
+ */
+
+#include "qemu/osdep.h"
+#include "qemu/qtree.h"
+
+static gint my_compare(gconstpointer a, gconstpointer b)
+{
+ const char *cha = a;
+ const char *chb = b;
+
+ return *cha - *chb;
+}
+
+static gint my_compare_with_data(gconstpointer a,
+ gconstpointer b,
+ gpointer user_data)
+{
+ const char *cha = a;
+ const char *chb = b;
+
+ /* just check that we got the right data */
+ g_assert(GPOINTER_TO_INT(user_data) == 123);
+
+ return *cha - *chb;
+}
+
+static gint my_search(gconstpointer a, gconstpointer b)
+{
+ return my_compare(b, a);
+}
+
+static gpointer destroyed_key;
+static gpointer destroyed_value;
+static guint destroyed_key_count;
+static guint destroyed_value_count;
+
+static void my_key_destroy(gpointer key)
+{
+ destroyed_key = key;
+ destroyed_key_count++;
+}
+
+static void my_value_destroy(gpointer value)
+{
+ destroyed_value = value;
+ destroyed_value_count++;
+}
+
+static gint my_traverse(gpointer key, gpointer value, gpointer data)
+{
+ char *ch = key;
+
+ g_assert((*ch) > 0);
+
+ if (*ch == 'd') {
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+char chars[] =
+ "0123456789"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+ "abcdefghijklmnopqrstuvwxyz";
+
+char chars2[] =
+ "0123456789"
+ "abcdefghijklmnopqrstuvwxyz";
+
+static gint check_order(gpointer key, gpointer value, gpointer data)
+{
+ char **p = data;
+ char *ch = key;
+
+ g_assert(**p == *ch);
+
+ (*p)++;
+
+ return FALSE;
+}
+
+static void test_tree_search(void)
+{
+ gint i;
+ QTree *tree;
+ gboolean removed;
+ gchar c;
+ gchar *p, *d;
+
+ tree = q_tree_new_with_data(my_compare_with_data, GINT_TO_POINTER(123));
+
+ for (i = 0; chars[i]; i++) {
+ q_tree_insert(tree, &chars[i], &chars[i]);
+ }
+
+ q_tree_foreach(tree, my_traverse, NULL);
+
+ g_assert(q_tree_nnodes(tree) == strlen(chars));
+ g_assert(q_tree_height(tree) == 6);
+
+ p = chars;
+ q_tree_foreach(tree, check_order, &p);
+
+ for (i = 0; i < 26; i++) {
+ removed = q_tree_remove(tree, &chars[i + 10]);
+ g_assert(removed);
+ }
+
+ c = '\0';
+ removed = q_tree_remove(tree, &c);
+ g_assert(!removed);
+
+ q_tree_foreach(tree, my_traverse, NULL);
+
+ g_assert(q_tree_nnodes(tree) == strlen(chars2));
+ g_assert(q_tree_height(tree) == 6);
+
+ p = chars2;
+ q_tree_foreach(tree, check_order, &p);
+
+ for (i = 25; i >= 0; i--) {
+ q_tree_insert(tree, &chars[i + 10], &chars[i + 10]);
+ }
+
+ p = chars;
+ q_tree_foreach(tree, check_order, &p);
+
+ c = '0';
+ p = q_tree_lookup(tree, &c);
+ g_assert(p && *p == c);
+ g_assert(q_tree_lookup_extended(tree, &c, (gpointer *)&d, (gpointer *)&p));
+ g_assert(c == *d && c == *p);
+
+ c = 'A';
+ p = q_tree_lookup(tree, &c);
+ g_assert(p && *p == c);
+
+ c = 'a';
+ p = q_tree_lookup(tree, &c);
+ g_assert(p && *p == c);
+
+ c = 'z';
+ p = q_tree_lookup(tree, &c);
+ g_assert(p && *p == c);
+
+ c = '!';
+ p = q_tree_lookup(tree, &c);
+ g_assert(p == NULL);
+
+ c = '=';
+ p = q_tree_lookup(tree, &c);
+ g_assert(p == NULL);
+
+ c = '|';
+ p = q_tree_lookup(tree, &c);
+ g_assert(p == NULL);
+
+ c = '0';
+ p = q_tree_search(tree, my_search, &c);
+ g_assert(p && *p == c);
+
+ c = 'A';
+ p = q_tree_search(tree, my_search, &c);
+ g_assert(p && *p == c);
+
+ c = 'a';
+ p = q_tree_search(tree, my_search, &c);
+ g_assert(p && *p == c);
+
+ c = 'z';
+ p = q_tree_search(tree, my_search, &c);
+ g_assert(p && *p == c);
+
+ c = '!';
+ p = q_tree_search(tree, my_search, &c);
+ g_assert(p == NULL);
+
+ c = '=';
+ p = q_tree_search(tree, my_search, &c);
+ g_assert(p == NULL);
+
+ c = '|';
+ p = q_tree_search(tree, my_search, &c);
+ g_assert(p == NULL);
+
+ q_tree_destroy(tree);
+}
+
+static void test_tree_remove(void)
+{
+ QTree *tree;
+ char c, d;
+ gint i;
+ gboolean removed;
+
+ tree = q_tree_new_full((GCompareDataFunc)my_compare, NULL,
+ my_key_destroy,
+ my_value_destroy);
+
+ for (i = 0; chars[i]; i++) {
+ q_tree_insert(tree, &chars[i], &chars[i]);
+ }
+
+ c = '0';
+ q_tree_insert(tree, &c, &c);
+ g_assert(destroyed_key == &c);
+ g_assert(destroyed_value == &chars[0]);
+ destroyed_key = NULL;
+ destroyed_value = NULL;
+
+ d = '1';
+ q_tree_replace(tree, &d, &d);
+ g_assert(destroyed_key == &chars[1]);
+ g_assert(destroyed_value == &chars[1]);
+ destroyed_key = NULL;
+ destroyed_value = NULL;
+
+ c = '2';
+ removed = q_tree_remove(tree, &c);
+ g_assert(removed);
+ g_assert(destroyed_key == &chars[2]);
+ g_assert(destroyed_value == &chars[2]);
+ destroyed_key = NULL;
+ destroyed_value = NULL;
+
+ c = '3';
+ removed = q_tree_steal(tree, &c);
+ g_assert(removed);
+ g_assert(destroyed_key == NULL);
+ g_assert(destroyed_value == NULL);
+
+ const gchar *remove = "omkjigfedba";
+ for (i = 0; remove[i]; i++) {
+ removed = q_tree_remove(tree, &remove[i]);
+ g_assert(removed);
+ }
+
+ q_tree_destroy(tree);
+}
+
+static void test_tree_destroy(void)
+{
+ QTree *tree;
+ gint i;
+
+ tree = q_tree_new(my_compare);
+
+ for (i = 0; chars[i]; i++) {
+ q_tree_insert(tree, &chars[i], &chars[i]);
+ }
+
+ g_assert(q_tree_nnodes(tree) == strlen(chars));
+
+ g_test_message("nnodes: %d", q_tree_nnodes(tree));
+ q_tree_ref(tree);
+ q_tree_destroy(tree);
+
+ g_test_message("nnodes: %d", q_tree_nnodes(tree));
+ g_assert(q_tree_nnodes(tree) == 0);
+
+ q_tree_unref(tree);
+}
+
+static void test_tree_insert(void)
+{
+ QTree *tree;
+ gchar *p;
+ gint i;
+ gchar *scrambled;
+
+ tree = q_tree_new(my_compare);
+
+ for (i = 0; chars[i]; i++) {
+ q_tree_insert(tree, &chars[i], &chars[i]);
+ }
+ p = chars;
+ q_tree_foreach(tree, check_order, &p);
+
+ q_tree_unref(tree);
+ tree = q_tree_new(my_compare);
+
+ for (i = strlen(chars) - 1; i >= 0; i--) {
+ q_tree_insert(tree, &chars[i], &chars[i]);
+ }
+ p = chars;
+ q_tree_foreach(tree, check_order, &p);
+
+ q_tree_unref(tree);
+ tree = q_tree_new(my_compare);
+
+ scrambled = g_strdup(chars);
+
+ for (i = 0; i < 30; i++) {
+ gchar tmp;
+ gint a, b;
+
+ a = g_random_int_range(0, strlen(scrambled));
+ b = g_random_int_range(0, strlen(scrambled));
+ tmp = scrambled[a];
+ scrambled[a] = scrambled[b];
+ scrambled[b] = tmp;
+ }
+
+ for (i = 0; scrambled[i]; i++) {
+ q_tree_insert(tree, &scrambled[i], &scrambled[i]);
+ }
+ p = chars;
+ q_tree_foreach(tree, check_order, &p);
+
+ g_free(scrambled);
+ q_tree_unref(tree);
+}
+
+int main(int argc, char *argv[])
+{
+ g_test_init(&argc, &argv, NULL);
+
+ g_test_add_func("/qtree/search", test_tree_search);
+ g_test_add_func("/qtree/remove", test_tree_remove);
+ g_test_add_func("/qtree/destroy", test_tree_destroy);
+ g_test_add_func("/qtree/insert", test_tree_insert);
+
+ return g_test_run();
+}