[glib/wip/menus] Add some GMenuModel testcases
- From: Ryan Lortie <ryanl src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [glib/wip/menus] Add some GMenuModel testcases
- Date: Sat, 22 Oct 2011 03:53:05 +0000 (UTC)
commit b81252e5d3d911217bacba1d041303a5852dedc6
Author: Ryan Lortie <desrt desrt ca>
Date: Fri Oct 21 23:51:48 2011 -0400
Add some GMenuModel testcases
gio/tests/.gitignore | 1 +
gio/tests/Makefile.am | 3 +
gio/tests/gmenumodel.c | 564 ++++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 568 insertions(+), 0 deletions(-)
---
diff --git a/gio/tests/.gitignore b/gio/tests/.gitignore
index 8fdd74f..a345bb4 100644
--- a/gio/tests/.gitignore
+++ b/gio/tests/.gitignore
@@ -57,6 +57,7 @@ gdbus-serialization
gdbus-test-codegen
gdbus-test-codegen-generated*
gdbus-threading
+gmenumodel
g-file
g-file-info
g-icon
diff --git a/gio/tests/Makefile.am b/gio/tests/Makefile.am
index 2091366..16b4b6a 100644
--- a/gio/tests/Makefile.am
+++ b/gio/tests/Makefile.am
@@ -56,6 +56,7 @@ TEST_PROGS += \
tls-interaction \
cancellable \
vfs \
+ gmenumodel \
$(NULL)
if OS_UNIX
@@ -406,6 +407,8 @@ gapplication_example_cmdline3_LDADD = $(progs_ldadd)
gapplication_example_actions_SOURCES = gapplication-example-actions.c
gapplication_example_actions_LDADD = $(progs_ldadd)
+gmenumodel_LDADD = $(progs_ldadd)
+
schema_tests = \
schema-tests/array-default-not-in-choices.gschema.xml \
schema-tests/bad-choice.gschema.xml \
diff --git a/gio/tests/gmenumodel.c b/gio/tests/gmenumodel.c
new file mode 100644
index 0000000..b8b5245
--- /dev/null
+++ b/gio/tests/gmenumodel.c
@@ -0,0 +1,564 @@
+#include <gio/gio.h>
+
+/* TestItem {{{1 */
+
+/* This utility struct is used by both the RandomMenu and MirrorMenu
+ * class implementations below.
+ */
+typedef struct {
+ GVariant *attributes;
+ GHashTable *links;
+} TestItem;
+
+static TestItem *
+test_item_new (GVariant *attributes,
+ GHashTable *links)
+{
+ TestItem *item;
+
+ item = g_slice_new (TestItem);
+ item->attributes = g_variant_ref_sink (attributes);
+ item->links = g_hash_table_ref (links);
+
+ return item;
+}
+
+static void
+test_item_free (gpointer data)
+{
+ TestItem *item = data;
+
+ g_variant_unref (item->attributes);
+ g_hash_table_unref (item->links);
+
+ g_slice_free (TestItem, item);
+}
+
+/* RandomMenu {{{1 */
+#define MAX_ITEMS 5
+#define TOP_ORDER 4
+
+typedef struct {
+ GMenuModel parent_instance;
+
+ GSequence *items;
+ gint order;
+} RandomMenu;
+
+typedef GMenuModelClass RandomMenuClass;
+
+static GType random_menu_get_type (void);
+G_DEFINE_TYPE (RandomMenu, random_menu, G_TYPE_MENU_MODEL);
+
+static gboolean
+random_menu_is_mutable (GMenuModel *model)
+{
+ return TRUE;
+}
+
+static gint
+random_menu_get_n_items (GMenuModel *model)
+{
+ RandomMenu *menu = (RandomMenu *) model;
+
+ return g_sequence_get_length (menu->items);
+}
+
+static void
+random_menu_get_item_attributes (GMenuModel *model,
+ gint position,
+ GHashTable **quark_table,
+ GHashTable **string_table,
+ GVariant **dictionary)
+{
+ RandomMenu *menu = (RandomMenu *) model;
+ TestItem *item;
+
+ item = g_sequence_get (g_sequence_get_iter_at_pos (menu->items, position));
+ *dictionary = g_variant_ref (item->attributes);
+}
+
+static void
+random_menu_get_item_links (GMenuModel *model,
+ gint position,
+ GHashTable **quark_table,
+ GHashTable **string_table)
+{
+ RandomMenu *menu = (RandomMenu *) model;
+ TestItem *item;
+
+ item = g_sequence_get (g_sequence_get_iter_at_pos (menu->items, position));
+ *quark_table = g_hash_table_ref (item->links);
+}
+
+static void
+random_menu_finalize (GObject *object)
+{
+ RandomMenu *menu = (RandomMenu *) object;
+
+ g_sequence_free (menu->items);
+
+ G_OBJECT_CLASS (random_menu_parent_class)
+ ->finalize (object);
+}
+
+static void
+random_menu_init (RandomMenu *menu)
+{
+}
+
+static void
+random_menu_class_init (GMenuModelClass *class)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (class);
+
+ class->is_mutable = random_menu_is_mutable;
+ class->get_n_items = random_menu_get_n_items;
+ class->get_item_attributes = random_menu_get_item_attributes;
+ class->get_item_links = random_menu_get_item_links;
+
+ object_class->finalize = random_menu_finalize;
+}
+
+static RandomMenu * random_menu_new (GRand *rand, gint order);
+
+static void
+random_menu_change (RandomMenu *menu,
+ GRand *rand)
+{
+ gint position, removes, adds;
+ GSequenceIter *point;
+ gint n_items;
+ gint i;
+
+ n_items = g_sequence_get_length (menu->items);
+
+ do
+ {
+ position = g_rand_int_range (rand, 0, n_items + 1);
+ removes = g_rand_int_range (rand, 0, n_items - position + 1);
+ adds = g_rand_int_range (rand, 0, MAX_ITEMS - (n_items - removes) + 1);
+ }
+ while (removes == 0 && adds == 0);
+
+ point = g_sequence_get_iter_at_pos (menu->items, position + removes);
+
+ if (removes)
+ {
+ GSequenceIter *start;
+
+ start = g_sequence_get_iter_at_pos (menu->items, position);
+ g_sequence_remove_range (start, point);
+ }
+
+ for (i = 0; i < adds; i++)
+ {
+ GVariantBuilder builder;
+ const gchar *label;
+ GHashTable *links;
+
+ g_variant_builder_init (&builder, G_VARIANT_TYPE_VARDICT);
+ links = g_hash_table_new_full (NULL, NULL, NULL, g_object_unref);
+
+ if (menu->order > 0 && g_rand_boolean (rand))
+ {
+ RandomMenu *child;
+ GQuark subtype;
+
+ child = random_menu_new (rand, menu->order - 1);
+
+ if (g_rand_boolean (rand))
+ {
+ subtype = G_MENU_LINK_SECTION;
+ /* label some section headers */
+ if (g_rand_boolean (rand))
+ label = "Section";
+ else
+ label = NULL;
+ }
+ else
+ {
+ /* label all submenus */
+ subtype = G_MENU_LINK_SUBMENU;
+ label = "Submenu";
+ }
+
+ g_hash_table_insert (links, GINT_TO_POINTER (subtype), child);
+ }
+ else
+ /* label all terminals */
+ label = "Menu Item";
+
+ if (label)
+ g_variant_builder_add (&builder, "{sv}", "label", g_variant_new_string (label));
+
+ g_sequence_insert_before (point, test_item_new (g_variant_builder_end (&builder), links));
+ g_hash_table_unref (links);
+ }
+
+ g_menu_model_items_changed (G_MENU_MODEL (menu), position, removes, adds);
+}
+
+static RandomMenu *
+random_menu_new (GRand *rand,
+ gint order)
+{
+ RandomMenu *menu;
+
+ menu = g_object_new (random_menu_get_type (), NULL);
+ menu->items = g_sequence_new (test_item_free);
+ menu->order = order;
+
+ random_menu_change (menu, rand);
+
+ return menu;
+}
+
+/* MirrorMenu {{{1 */
+typedef struct {
+ GMenuModel parent_instance;
+
+ GMenuModel *clone_of;
+ GSequence *items;
+ gulong handler_id;
+} MirrorMenu;
+
+typedef GMenuModelClass MirrorMenuClass;
+
+static GType mirror_menu_get_type (void);
+G_DEFINE_TYPE (MirrorMenu, mirror_menu, G_TYPE_MENU_MODEL);
+
+static gboolean
+mirror_menu_is_mutable (GMenuModel *model)
+{
+ MirrorMenu *menu = (MirrorMenu *) model;
+
+ return menu->handler_id != 0;
+}
+
+static gint
+mirror_menu_get_n_items (GMenuModel *model)
+{
+ MirrorMenu *menu = (MirrorMenu *) model;
+
+ return g_sequence_get_length (menu->items);
+}
+
+static void
+mirror_menu_get_item_attributes (GMenuModel *model,
+ gint position,
+ GHashTable **quark_table,
+ GHashTable **string_table,
+ GVariant **dictionary)
+{
+ MirrorMenu *menu = (MirrorMenu *) model;
+ TestItem *item;
+
+ item = g_sequence_get (g_sequence_get_iter_at_pos (menu->items, position));
+ *dictionary = g_variant_ref (item->attributes);
+}
+
+static void
+mirror_menu_get_item_links (GMenuModel *model,
+ gint position,
+ GHashTable **quark_table,
+ GHashTable **string_table)
+{
+ MirrorMenu *menu = (MirrorMenu *) model;
+ TestItem *item;
+
+ item = g_sequence_get (g_sequence_get_iter_at_pos (menu->items, position));
+ *string_table = g_hash_table_ref (item->links);
+}
+
+static void
+mirror_menu_finalize (GObject *object)
+{
+ MirrorMenu *menu = (MirrorMenu *) object;
+
+ if (menu->handler_id)
+ g_signal_handler_disconnect (menu->clone_of, menu->handler_id);
+
+ g_sequence_free (menu->items);
+ g_object_unref (menu->clone_of);
+
+ G_OBJECT_CLASS (mirror_menu_parent_class)
+ ->finalize (object);
+}
+
+static void
+mirror_menu_init (MirrorMenu *menu)
+{
+}
+
+static void
+mirror_menu_class_init (GMenuModelClass *class)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (class);
+
+ class->is_mutable = mirror_menu_is_mutable;
+ class->get_n_items = mirror_menu_get_n_items;
+ class->get_item_attributes = mirror_menu_get_item_attributes;
+ class->get_item_links = mirror_menu_get_item_links;
+
+ object_class->finalize = mirror_menu_finalize;
+}
+
+static MirrorMenu * mirror_menu_new (GMenuModel *clone_of);
+
+static void
+mirror_menu_changed (GMenuModel *model,
+ gint position,
+ gint removed,
+ gint added,
+ gpointer user_data)
+{
+ MirrorMenu *menu = user_data;
+ GSequenceIter *point;
+ gint i;
+
+ g_assert (model == menu->clone_of);
+
+ point = g_sequence_get_iter_at_pos (menu->items, position + removed);
+
+ if (removed)
+ {
+ GSequenceIter *start;
+
+ start = g_sequence_get_iter_at_pos (menu->items, position);
+ g_sequence_remove_range (start, point);
+ }
+
+ for (i = position; i < position + added; i++)
+ {
+ GMenuAttributeIter *attr_iter;
+ GMenuLinkIter *link_iter;
+ GVariantBuilder builder;
+ GHashTable *links;
+ const gchar *name;
+ GMenuModel *child;
+ GVariant *value;
+
+ g_variant_builder_init (&builder, G_VARIANT_TYPE_VARDICT);
+ links = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_object_unref);
+
+ attr_iter = g_menu_model_iterate_item_attributes (model, i);
+ while (g_menu_attribute_iter_get_next (attr_iter, &name, &value))
+ {
+ g_variant_builder_add (&builder, "{sv}", name, value);
+ g_variant_unref (value);
+ }
+ g_object_unref (attr_iter);
+
+ link_iter = g_menu_model_iterate_item_links (model, i);
+ while (g_menu_link_iter_get_next (link_iter, &name, &child))
+ {
+ g_hash_table_insert (links, g_strdup (name), mirror_menu_new (child));
+ g_object_unref (child);
+ }
+ g_object_unref (link_iter);
+
+ g_sequence_insert_before (point, test_item_new (g_variant_builder_end (&builder), links));
+ g_hash_table_unref (links);
+ }
+
+ g_menu_model_items_changed (G_MENU_MODEL (menu), position, removed, added);
+}
+
+static MirrorMenu *
+mirror_menu_new (GMenuModel *clone_of)
+{
+ MirrorMenu *menu;
+
+ menu = g_object_new (mirror_menu_get_type (), NULL);
+ menu->items = g_sequence_new (test_item_free);
+ menu->clone_of = g_object_ref (clone_of);
+
+ if (g_menu_model_is_mutable (clone_of))
+ menu->handler_id = g_signal_connect (clone_of, "items-changed", G_CALLBACK (mirror_menu_changed), menu);
+ mirror_menu_changed (clone_of, 0, 0, g_menu_model_get_n_items (clone_of), menu);
+
+ return menu;
+}
+
+/* check_menus_equal(), assert_menus_equal() {{{1 */
+static gboolean
+check_menus_equal (GMenuModel *a,
+ GMenuModel *b)
+{
+ gboolean equal = TRUE;
+ gint a_n, b_n;
+ gint i;
+
+ a_n = g_menu_model_get_n_items (a);
+ b_n = g_menu_model_get_n_items (b);
+
+ if (a_n != b_n)
+ return FALSE;
+
+ for (i = 0; i < a_n; i++)
+ {
+ GMenuAttributeIter *attr_iter;
+ GVariant *a_value, *b_value;
+ GMenuLinkIter *link_iter;
+ GMenuModel *a_menu, *b_menu;
+ const gchar *name;
+
+ attr_iter = g_menu_model_iterate_item_attributes (a, i);
+ while (g_menu_attribute_iter_get_next (attr_iter, &name, &a_value))
+ {
+ b_value = g_menu_model_get_item_attribute_value (b, i, g_quark_from_string (name), NULL);
+ equal &= b_value && g_variant_equal (a_value, b_value);
+ if (b_value)
+ g_variant_unref (b_value);
+ g_variant_unref (a_value);
+ }
+ g_object_unref (attr_iter);
+
+ attr_iter = g_menu_model_iterate_item_attributes (b, i);
+ while (g_menu_attribute_iter_get_next (attr_iter, &name, &b_value))
+ {
+ a_value = g_menu_model_get_item_attribute_value (a, i, g_quark_from_string (name), NULL);
+ equal &= a_value && g_variant_equal (a_value, b_value);
+ if (a_value)
+ g_variant_unref (a_value);
+ g_variant_unref (b_value);
+ }
+ g_object_unref (attr_iter);
+
+ link_iter = g_menu_model_iterate_item_links (a, i);
+ while (g_menu_link_iter_get_next (link_iter, &name, &a_menu))
+ {
+ b_menu = g_menu_model_get_item_link (b, i, g_quark_from_string (name));
+ equal &= b_menu && check_menus_equal (a_menu, b_menu);
+ if (b_menu)
+ g_object_unref (b_menu);
+ g_object_unref (a_menu);
+ }
+ g_object_unref (link_iter);
+
+ link_iter = g_menu_model_iterate_item_links (b, i);
+ while (g_menu_link_iter_get_next (link_iter, &name, &b_menu))
+ {
+ a_menu = g_menu_model_get_item_link (a, i, g_quark_from_string (name));
+ equal &= a_menu && check_menus_equal (a_menu, b_menu);
+ if (a_menu)
+ g_object_unref (a_menu);
+ g_object_unref (b_menu);
+ }
+ g_object_unref (link_iter);
+ }
+
+ return equal;
+}
+
+static void
+assert_menus_equal (GMenuModel *a,
+ GMenuModel *b)
+{
+ if (!check_menus_equal (a, b))
+ {
+ GString *string;
+
+ string = g_string_new ("\n <a>\n");
+ g_menu_markup_print_string (string, G_MENU_MODEL (a), 4, 2);
+ g_string_append (string, " </a>\n\n-------------\n <b>\n");
+ g_menu_markup_print_string (string, G_MENU_MODEL (b), 4, 2);
+ g_string_append (string, " </b>\n");
+ g_error ("%s", string->str);
+ }
+}
+
+/* Test cases {{{1 */
+static void
+test_equality (void)
+{
+ GRand *randa, *randb;
+ guint32 seed;
+ gint i;
+
+ seed = g_test_rand_int ();
+
+ randa = g_rand_new_with_seed (seed);
+ randb = g_rand_new_with_seed (seed);
+
+ for (i = 0; i < 500; i++)
+ {
+ RandomMenu *a, *b;
+
+ a = random_menu_new (randa, TOP_ORDER);
+ b = random_menu_new (randb, TOP_ORDER);
+ assert_menus_equal (G_MENU_MODEL (a), G_MENU_MODEL (b));
+ g_object_unref (b);
+ g_object_unref (a);
+ }
+
+ g_rand_int (randa);
+
+ for (i = 0; i < 500;)
+ {
+ RandomMenu *a, *b;
+
+ a = random_menu_new (randa, TOP_ORDER);
+ b = random_menu_new (randb, TOP_ORDER);
+ if (check_menus_equal (G_MENU_MODEL (a), G_MENU_MODEL (b)))
+ {
+ /* by chance, they may really be equal. double check. */
+ GString *as, *bs;
+
+ as = g_menu_markup_print_string (NULL, G_MENU_MODEL (a), 4, 2);
+ bs = g_menu_markup_print_string (NULL, G_MENU_MODEL (b), 4, 2);
+ g_assert_cmpstr (as->str, ==, bs->str);
+ g_string_free (bs, TRUE);
+ g_string_free (as, TRUE);
+ }
+ else
+ /* make sure we get enough unequals (ie: no GRand failure) */
+ i++;
+
+ g_object_unref (b);
+ g_object_unref (a);
+ }
+
+ g_rand_free (randb);
+ g_rand_free (randa);
+}
+
+static void
+test_random (void)
+{
+ RandomMenu *random;
+ MirrorMenu *mirror;
+ GRand *rand;
+ gint i;
+
+ rand = g_rand_new_with_seed (g_test_rand_int ());
+ random = random_menu_new (rand, TOP_ORDER);
+ mirror = mirror_menu_new (G_MENU_MODEL (random));
+
+ for (i = 0; i < 500; i++)
+ {
+ assert_menus_equal (G_MENU_MODEL (random), G_MENU_MODEL (mirror));
+ random_menu_change (random, rand);
+ }
+
+ g_object_unref (mirror);
+ g_object_unref (random);
+
+ g_rand_free (rand);
+}
+
+/* Epilogue {{{1 */
+int
+main (int argc, char **argv)
+{
+ g_test_init (&argc, &argv, NULL);
+
+ g_type_init ();
+
+ g_test_add_func ("/gmenu/equality", test_equality);
+ g_test_add_func ("/gmenu/random", test_random);
+
+ return g_test_run ();
+}
+/* vim:set foldmethod=marker: */
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]