[gtk+] tests: improve gtkmenu testcase
- From: Ryan Lortie <ryanl src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gtk+] tests: improve gtkmenu testcase
- Date: Mon, 1 Apr 2013 20:45:38 +0000 (UTC)
commit 45a94ccc88b843b1301671b9919a31e5d76be57a
Author: Ryan Lortie <desrt desrt ca>
Date: Sat Mar 23 16:15:04 2013 -0400
tests: improve gtkmenu testcase
Don't just create a menushell and populate it with random data -- verify that
the resulting menu layout is actually correct.
This is introduced in a separate commit because the old code was failing this
part of the test.
https://bugzilla.gnome.org/show_bug.cgi?id=696468
gtk/tests/gtkmenu.c | 186 ++++++++++++++++++++++++++++++++++++++++++++++++++-
1 files changed, 184 insertions(+), 2 deletions(-)
---
diff --git a/gtk/tests/gtkmenu.c b/gtk/tests/gtkmenu.c
index fc97843..35bb434 100644
--- a/gtk/tests/gtkmenu.c
+++ b/gtk/tests/gtkmenu.c
@@ -213,6 +213,188 @@ random_menu_new (GRand *rand,
}
/* Test cases {{{1 */
+
+static void assert_menu_equality (GtkContainer *container, GMenuModel *model);
+
+/* a bit complicated with the separators...
+ *
+ * with_separators are if subsections of this GMenuModel should have
+ * separators inserted between them (ie: in the same sense as the
+ * 'with_separators' argument to gtk_menu_shell_bind_model().
+ *
+ * needs_separator is true if this particular section needs to have a
+ * separator before it in the case that it is non-empty. this will be
+ * defined for all subsections of a with_separators menu (except the
+ * first) or in case section_header is non-%NULL.
+ *
+ * section_header is the label that must be inside that separator, if it
+ * exists. section_header is only non-%NULL if needs_separator is also
+ * TRUE.
+ */
+static void
+assert_section_equality (GSList **children,
+ gboolean with_separators,
+ gboolean needs_separator,
+ const gchar *section_header,
+ GMenuModel *model)
+{
+ gboolean has_separator;
+ GSList *our_children;
+ gint i, n;
+
+ /* Assuming that we have the possibility of showing a separator, there
+ * are two valid situations:
+ *
+ * - we have a separator and we have other children
+ *
+ * - we have no separator and no children
+ *
+ * If we see a separator, we suppose that it is ours and that we will
+ * encounter children. In the case that we have no children, the
+ * separator may not be ours but may rather belong to a later section.
+ *
+ * We therefore keep our own copy of the children GSList. If we
+ * encounter children, we will delete the links that this section is
+ * responsible for and update the pass-by-reference value. Otherwise,
+ * we will leave everything alone and let the separator be accounted
+ * for by a following section.
+ */
+ our_children = *children;
+ if (needs_separator && GTK_IS_SEPARATOR_MENU_ITEM (our_children->data))
+ {
+ /* We accounted for the separator, at least for now, so remove it
+ * from the list.
+ *
+ * We will check later if we should have actually had a separator
+ * and compare the result to has_separator.
+ */
+ our_children = our_children->next;
+ has_separator = TRUE;
+ }
+ else
+ has_separator = FALSE;
+
+ /* Now, iterate the model checking that the items in the GSList line
+ * up with our expectations. */
+ n = g_menu_model_get_n_items (model);
+ for (i = 0; i < n; i++)
+ {
+ GMenuModel *subsection;
+ GMenuModel *submenu;
+ gchar *label = NULL;
+
+ subsection = g_menu_model_get_item_link (model, i, G_MENU_LINK_SECTION);
+ submenu = g_menu_model_get_item_link (model, i, G_MENU_LINK_SUBMENU);
+ g_menu_model_get_item_attribute (model, i, G_MENU_ATTRIBUTE_LABEL, "s", &label);
+
+ if (subsection)
+ {
+ g_assert (!submenu);
+ assert_section_equality (&our_children,
+ FALSE, /* with_separators */
+ label || (with_separators && i > 0), /* needs_separator */
+ label, /* section_header */
+ subsection);
+ g_object_unref (subsection);
+ }
+ else
+ {
+ GtkWidget *submenu_widget;
+ GtkMenuItem *item;
+
+ /* This is a normal item. Make sure the label is right. */
+ item = our_children->data;
+ our_children = g_slist_remove (our_children, item);
+
+ /* get_label() returns "" when it ought to return NULL */
+ g_assert_cmpstr (gtk_menu_item_get_label (item), ==, label ? label : "");
+ submenu_widget = gtk_menu_item_get_submenu (item);
+
+ if (submenu)
+ {
+ g_assert (submenu_widget != NULL);
+ assert_menu_equality (GTK_CONTAINER (submenu_widget), submenu);
+ g_object_unref (submenu);
+ }
+ else
+ g_assert (!submenu_widget);
+ }
+
+ g_free (label);
+ }
+
+ /* If we found a separator but visited no children then the separator
+ * was not for us. Patch that up.
+ */
+ if (has_separator && our_children == (*children)->next)
+ {
+ /* Rewind our_children to put the separator we tentatively
+ * consumed back into the list.
+ */
+ our_children = *children;
+ has_separator = FALSE;
+ }
+
+ if (our_children == *children)
+ /* If we had no children then we didn't really need a separator. */
+ needs_separator = FALSE;
+
+ g_assert (needs_separator == has_separator);
+
+ if (has_separator)
+ {
+ GtkWidget *contents;
+ const gchar *label;
+
+ /* We needed and had a separator and we visited a child.
+ *
+ * Make sure that separator was valid.
+ */
+ contents = gtk_bin_get_child ((*children)->data);
+ if (GTK_IS_LABEL (contents))
+ label = gtk_label_get_label (GTK_LABEL (contents));
+ else
+ label = "";
+
+ /* get_label() returns "" when it ought to return NULL */
+ g_assert_cmpstr (label, ==, section_header ? section_header : "");
+
+ /* our_children has already gone (possibly far) past *children, so
+ * we need to free up the link that we left behind for the
+ * separator in case we wanted to rewind.
+ */
+ g_slist_free_1 (*children);
+ }
+
+ *children = our_children;
+}
+
+/* We want to use a GSList here instead of a GList because the ->prev
+ * pointer updates cause trouble with the way we speculatively deal with
+ * separators by skipping over them and coming back to clean up later.
+ */
+static void
+get_children_into_slist (GtkWidget *widget,
+ gpointer user_data)
+{
+ GSList **list_ptr = user_data;
+
+ *list_ptr = g_slist_prepend (*list_ptr, widget);
+}
+
+static void
+assert_menu_equality (GtkContainer *container,
+ GMenuModel *model)
+{
+ GSList *children = NULL;
+
+ gtk_container_foreach (container, get_children_into_slist, &children);
+ children = g_slist_reverse (children);
+
+ assert_section_equality (&children, TRUE, FALSE, NULL, model);
+ g_assert (children == NULL);
+}
+
static void
test_bind_menu (void)
{
@@ -227,14 +409,14 @@ test_bind_menu (void)
model = random_menu_new (rand, TOP_ORDER);
menu = gtk_menu_new_from_model (G_MENU_MODEL (model));
g_object_ref_sink (menu);
+ assert_menu_equality (GTK_CONTAINER (menu), G_MENU_MODEL (model));
for (i = 0; i < 100; i++)
{
random_menu_change (model, rand);
while (g_main_context_iteration (NULL, FALSE));
- g_print (".");
+ assert_menu_equality (GTK_CONTAINER (menu), G_MENU_MODEL (model));
}
g_object_unref (model);
- gtk_widget_destroy (menu);
g_object_unref (menu);
g_rand_free (rand);
}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]