GLib test: test GTree "lower bound" and "upper bound" operations

"lower bound" and "upper bound" operations have been recently added to
GTree.
Let's add some tests for them where other GTree tests live.

Since adding keys in-order doesn't exercise the GTree insertion code very
well let's make sure they are inserted in a random order instead.

Signed-off-by: Maciej S. Szmigiero <maciej.szmigiero@oracle.com>
This commit is contained in:
Maciej S. Szmigiero 2020-05-26 23:09:13 +02:00 committed by Philip Withnall
parent 2e7931c760
commit 6569529e18

View File

@ -397,9 +397,139 @@ my_traverse (gpointer key,
return FALSE;
}
static void
binary_tree_bound (GTree *tree,
char c,
char expected,
int lower)
{
GTreeNode *node;
if (lower)
node = g_tree_lower_bound (tree, &c);
else
node = g_tree_upper_bound (tree, &c);
if (g_test_verbose ())
g_printerr ("%c %s: ", c, lower ? "lower" : "upper");
if (!node)
{
if (!g_tree_nnodes (tree))
{
if (g_test_verbose ())
g_printerr ("empty tree");
}
else
{
GTreeNode *last = g_tree_node_last (tree);
g_assert (last);
if (g_test_verbose ())
g_printerr ("past end last %c",
*(char *) g_tree_node_key (last));
}
g_assert (expected == '\x00');
}
else
{
GTreeNode *begin = g_tree_node_first (tree);
GTreeNode *last = g_tree_node_last (tree);
GTreeNode *prev = g_tree_node_previous (node);
GTreeNode *next = g_tree_node_next (node);
g_assert (expected != '\x00');
g_assert (expected == *(char *) g_tree_node_key (node));
if (g_test_verbose ())
g_printerr ("%c", *(char *) g_tree_node_key (node));
if (node != begin)
{
g_assert (prev);
if (g_test_verbose ())
g_printerr (" prev %c", *(char *) g_tree_node_key (prev));
}
else
{
g_assert (!prev);
if (g_test_verbose ())
g_printerr (" no prev, it's the first one");
}
if (node != last)
{
g_assert (next);
if (g_test_verbose ())
g_printerr (" next %c", *(char *) g_tree_node_key (next));
}
else
{
g_assert (!next);
if (g_test_verbose ())
g_printerr (" no next, it's the last one");
}
}
if (g_test_verbose ())
g_printerr ("\n");
}
static void
binary_tree_bounds (GTree *tree,
char c,
int mode)
{
char expectedl, expectedu;
char first = mode == 0 ? '0' : mode == 1 ? 'A' : 'z';
g_assert (mode >= 0 && mode <= 3);
if (c < first)
expectedl = first;
else if (c > 'z')
expectedl = '\x00';
else
expectedl = c;
if (c < first)
expectedu = first;
else if (c >= 'z')
expectedu = '\x00';
else
expectedu = c == '9' ? 'A' : c == 'Z' ? 'a' : c + 1;
if (mode == 3)
{
expectedl = '\x00';
expectedu = '\x00';
}
binary_tree_bound (tree, c, expectedl, 1);
binary_tree_bound (tree, c, expectedu, 0);
}
static void
binary_tree_bounds_test (GTree *tree,
int mode)
{
binary_tree_bounds (tree, 'a', mode);
binary_tree_bounds (tree, 'A', mode);
binary_tree_bounds (tree, 'z', mode);
binary_tree_bounds (tree, 'Z', mode);
binary_tree_bounds (tree, 'Y', mode);
binary_tree_bounds (tree, '0', mode);
binary_tree_bounds (tree, '9', mode);
binary_tree_bounds (tree, '0' - 1, mode);
binary_tree_bounds (tree, 'z' + 1, mode);
binary_tree_bounds (tree, '0' - 2, mode);
binary_tree_bounds (tree, 'z' + 2, mode);
}
static void
binary_tree_test (void)
{
GQueue queue = G_QUEUE_INIT;
GTree *tree;
char chars[62];
guint i, j;
@ -409,42 +539,85 @@ binary_tree_test (void)
for (j = 0; j < 10; j++, i++)
{
chars[i] = '0' + j;
g_tree_insert (tree, &chars[i], &chars[i]);
g_queue_push_tail (&queue, &chars[i]);
}
for (j = 0; j < 26; j++, i++)
{
chars[i] = 'A' + j;
g_tree_insert (tree, &chars[i], &chars[i]);
g_queue_push_tail (&queue, &chars[i]);
}
for (j = 0; j < 26; j++, i++)
{
chars[i] = 'a' + j;
g_tree_insert (tree, &chars[i], &chars[i]);
g_queue_push_tail (&queue, &chars[i]);
}
g_assert_cmpint (g_tree_nnodes (tree), ==, 10 + 26 + 26);
g_assert_cmpint (g_tree_height (tree), ==, 6);
if (g_test_verbose ())
g_printerr ("tree insert: ");
while (!g_queue_is_empty (&queue))
{
gint32 which = g_random_int_range (0, g_queue_get_length (&queue));
gpointer elem = g_queue_pop_nth (&queue, which);
GTreeNode *node;
if (g_test_verbose())
if (g_test_verbose ())
g_printerr ("%c ", *(char *) elem);
node = g_tree_insert_node (tree, elem, elem);
g_assert (g_tree_node_key (node) == elem);
g_assert (g_tree_node_value (node) == elem);
}
if (g_test_verbose ())
g_printerr ("\n");
g_assert_cmpint (g_tree_nnodes (tree), ==, 10 + 26 + 26);
g_assert_cmpint (g_tree_height (tree), >=, 6);
g_assert_cmpint (g_tree_height (tree), <=, 8);
if (g_test_verbose ())
{
g_printerr ("tree: ");
g_tree_foreach (tree, my_traverse, NULL);
g_printerr ("\n");
}
binary_tree_bounds_test (tree, 0);
for (i = 0; i < 10; i++)
g_tree_remove (tree, &chars[i]);
g_assert_cmpint (g_tree_nnodes (tree), ==, 26 + 26);
g_assert_cmpint (g_tree_height (tree), ==, 6);
g_assert_cmpint (g_tree_height (tree), >=, 6);
g_assert_cmpint (g_tree_height (tree), <=, 8);
if (g_test_verbose())
if (g_test_verbose ())
{
g_printerr ("tree: ");
g_tree_foreach (tree, my_traverse, NULL);
g_printerr ("\n");
}
binary_tree_bounds_test (tree, 1);
for (i = 10; i < 10 + 26 + 26 - 1; i++)
g_tree_remove (tree, &chars[i]);
if (g_test_verbose ())
{
g_printerr ("tree: ");
g_tree_foreach (tree, my_traverse, NULL);
g_printerr ("\n");
}
binary_tree_bounds_test (tree, 2);
g_tree_remove (tree, &chars[10 + 26 + 26 - 1]);
if (g_test_verbose ())
g_printerr ("empty tree\n");
binary_tree_bounds_test (tree, 3);
g_tree_unref (tree);
}