Drop the GMenu markup functions
[glib.git] / gio / tests / gmenumodel.c
blobd8eb567f828a253ba694bdc6f80dc77dc28b6ae4
1 #include <gio/gio.h>
3 /* Markup printing {{{1 */
5 /* This used to be part of GLib, but it was removed before the stable
6 * release because it wasn't generally useful. We want it here, though.
7 */
8 static void
9 indent_string (GString *string,
10 gint indent)
12 while (indent--)
13 g_string_append_c (string, ' ');
16 static GString *
17 g_menu_markup_print_string (GString *string,
18 GMenuModel *model,
19 gint indent,
20 gint tabstop)
22 gboolean need_nl = FALSE;
23 gint i, n;
25 if G_UNLIKELY (string == NULL)
26 string = g_string_new (NULL);
28 n = g_menu_model_get_n_items (model);
30 for (i = 0; i < n; i++)
32 GMenuAttributeIter *attr_iter;
33 GMenuLinkIter *link_iter;
34 GString *contents;
35 GString *attrs;
37 attr_iter = g_menu_model_iterate_item_attributes (model, i);
38 link_iter = g_menu_model_iterate_item_links (model, i);
39 contents = g_string_new (NULL);
40 attrs = g_string_new (NULL);
42 while (g_menu_attribute_iter_next (attr_iter))
44 const char *name = g_menu_attribute_iter_get_name (attr_iter);
45 GVariant *value = g_menu_attribute_iter_get_value (attr_iter);
47 if (g_variant_is_of_type (value, G_VARIANT_TYPE_STRING))
49 gchar *str;
50 str = g_markup_printf_escaped (" %s='%s'", name, g_variant_get_string (value, NULL));
51 g_string_append (attrs, str);
52 g_free (str);
55 else
57 gchar *printed;
58 gchar *str;
59 const gchar *type;
61 printed = g_variant_print (value, TRUE);
62 type = g_variant_type_peek_string (g_variant_get_type (value));
63 str = g_markup_printf_escaped ("<attribute name='%s' type='%s'>%s</attribute>\n", name, type, printed);
64 indent_string (contents, indent + tabstop);
65 g_string_append (contents, str);
66 g_free (printed);
67 g_free (str);
70 g_variant_unref (value);
72 g_object_unref (attr_iter);
74 while (g_menu_link_iter_next (link_iter))
76 const gchar *name = g_menu_link_iter_get_name (link_iter);
77 GMenuModel *menu = g_menu_link_iter_get_value (link_iter);
78 gchar *str;
80 if (contents->str[0])
81 g_string_append_c (contents, '\n');
83 str = g_markup_printf_escaped ("<link name='%s'>\n", name);
84 indent_string (contents, indent + tabstop);
85 g_string_append (contents, str);
86 g_free (str);
88 g_menu_markup_print_string (contents, menu, indent + 2 * tabstop, tabstop);
90 indent_string (contents, indent + tabstop);
91 g_string_append (contents, "</link>\n");
92 g_object_unref (menu);
94 g_object_unref (link_iter);
96 if (contents->str[0])
98 indent_string (string, indent);
99 g_string_append_printf (string, "<item%s>\n", attrs->str);
100 g_string_append (string, contents->str);
101 indent_string (string, indent);
102 g_string_append (string, "</item>\n");
103 need_nl = TRUE;
106 else
108 if (need_nl)
109 g_string_append_c (string, '\n');
111 indent_string (string, indent);
112 g_string_append_printf (string, "<item%s/>\n", attrs->str);
113 need_nl = FALSE;
116 g_string_free (contents, TRUE);
117 g_string_free (attrs, TRUE);
120 return string;
123 /* TestItem {{{1 */
125 /* This utility struct is used by both the RandomMenu and MirrorMenu
126 * class implementations below.
128 typedef struct {
129 GHashTable *attributes;
130 GHashTable *links;
131 } TestItem;
133 static TestItem *
134 test_item_new (GHashTable *attributes,
135 GHashTable *links)
137 TestItem *item;
139 item = g_slice_new (TestItem);
140 item->attributes = g_hash_table_ref (attributes);
141 item->links = g_hash_table_ref (links);
143 return item;
146 static void
147 test_item_free (gpointer data)
149 TestItem *item = data;
151 g_hash_table_unref (item->attributes);
152 g_hash_table_unref (item->links);
154 g_slice_free (TestItem, item);
157 /* RandomMenu {{{1 */
158 #define MAX_ITEMS 5
159 #define TOP_ORDER 4
161 typedef struct {
162 GMenuModel parent_instance;
164 GSequence *items;
165 gint order;
166 } RandomMenu;
168 typedef GMenuModelClass RandomMenuClass;
170 static GType random_menu_get_type (void);
171 G_DEFINE_TYPE (RandomMenu, random_menu, G_TYPE_MENU_MODEL);
173 static gboolean
174 random_menu_is_mutable (GMenuModel *model)
176 return TRUE;
179 static gint
180 random_menu_get_n_items (GMenuModel *model)
182 RandomMenu *menu = (RandomMenu *) model;
184 return g_sequence_get_length (menu->items);
187 static void
188 random_menu_get_item_attributes (GMenuModel *model,
189 gint position,
190 GHashTable **table)
192 RandomMenu *menu = (RandomMenu *) model;
193 TestItem *item;
195 item = g_sequence_get (g_sequence_get_iter_at_pos (menu->items, position));
196 *table = g_hash_table_ref (item->attributes);
199 static void
200 random_menu_get_item_links (GMenuModel *model,
201 gint position,
202 GHashTable **table)
204 RandomMenu *menu = (RandomMenu *) model;
205 TestItem *item;
207 item = g_sequence_get (g_sequence_get_iter_at_pos (menu->items, position));
208 *table = g_hash_table_ref (item->links);
211 static void
212 random_menu_finalize (GObject *object)
214 RandomMenu *menu = (RandomMenu *) object;
216 g_sequence_free (menu->items);
218 G_OBJECT_CLASS (random_menu_parent_class)
219 ->finalize (object);
222 static void
223 random_menu_init (RandomMenu *menu)
227 static void
228 random_menu_class_init (GMenuModelClass *class)
230 GObjectClass *object_class = G_OBJECT_CLASS (class);
232 class->is_mutable = random_menu_is_mutable;
233 class->get_n_items = random_menu_get_n_items;
234 class->get_item_attributes = random_menu_get_item_attributes;
235 class->get_item_links = random_menu_get_item_links;
237 object_class->finalize = random_menu_finalize;
240 static RandomMenu * random_menu_new (GRand *rand, gint order);
242 static void
243 random_menu_change (RandomMenu *menu,
244 GRand *rand)
246 gint position, removes, adds;
247 GSequenceIter *point;
248 gint n_items;
249 gint i;
251 n_items = g_sequence_get_length (menu->items);
255 position = g_rand_int_range (rand, 0, n_items + 1);
256 removes = g_rand_int_range (rand, 0, n_items - position + 1);
257 adds = g_rand_int_range (rand, 0, MAX_ITEMS - (n_items - removes) + 1);
259 while (removes == 0 && adds == 0);
261 point = g_sequence_get_iter_at_pos (menu->items, position + removes);
263 if (removes)
265 GSequenceIter *start;
267 start = g_sequence_get_iter_at_pos (menu->items, position);
268 g_sequence_remove_range (start, point);
271 for (i = 0; i < adds; i++)
273 const gchar *label;
274 GHashTable *links;
275 GHashTable *attributes;
277 attributes = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, (GDestroyNotify) g_variant_unref);
278 links = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, (GDestroyNotify) g_object_unref);
280 if (menu->order > 0 && g_rand_boolean (rand))
282 RandomMenu *child;
283 const gchar *subtype;
285 child = random_menu_new (rand, menu->order - 1);
287 if (g_rand_boolean (rand))
289 subtype = G_MENU_LINK_SECTION;
290 /* label some section headers */
291 if (g_rand_boolean (rand))
292 label = "Section";
293 else
294 label = NULL;
296 else
298 /* label all submenus */
299 subtype = G_MENU_LINK_SUBMENU;
300 label = "Submenu";
303 g_hash_table_insert (links, g_strdup (subtype), child);
305 else
306 /* label all terminals */
307 label = "Menu Item";
309 if (label)
310 g_hash_table_insert (attributes, g_strdup ("label"), g_variant_ref_sink (g_variant_new_string (label)));
312 g_sequence_insert_before (point, test_item_new (attributes, links));
313 g_hash_table_unref (links);
314 g_hash_table_unref (attributes);
317 g_menu_model_items_changed (G_MENU_MODEL (menu), position, removes, adds);
320 static RandomMenu *
321 random_menu_new (GRand *rand,
322 gint order)
324 RandomMenu *menu;
326 menu = g_object_new (random_menu_get_type (), NULL);
327 menu->items = g_sequence_new (test_item_free);
328 menu->order = order;
330 random_menu_change (menu, rand);
332 return menu;
335 /* MirrorMenu {{{1 */
336 typedef struct {
337 GMenuModel parent_instance;
339 GMenuModel *clone_of;
340 GSequence *items;
341 gulong handler_id;
342 } MirrorMenu;
344 typedef GMenuModelClass MirrorMenuClass;
346 static GType mirror_menu_get_type (void);
347 G_DEFINE_TYPE (MirrorMenu, mirror_menu, G_TYPE_MENU_MODEL);
349 static gboolean
350 mirror_menu_is_mutable (GMenuModel *model)
352 MirrorMenu *menu = (MirrorMenu *) model;
354 return menu->handler_id != 0;
357 static gint
358 mirror_menu_get_n_items (GMenuModel *model)
360 MirrorMenu *menu = (MirrorMenu *) model;
362 return g_sequence_get_length (menu->items);
365 static void
366 mirror_menu_get_item_attributes (GMenuModel *model,
367 gint position,
368 GHashTable **table)
370 MirrorMenu *menu = (MirrorMenu *) model;
371 TestItem *item;
373 item = g_sequence_get (g_sequence_get_iter_at_pos (menu->items, position));
374 *table = g_hash_table_ref (item->attributes);
377 static void
378 mirror_menu_get_item_links (GMenuModel *model,
379 gint position,
380 GHashTable **table)
382 MirrorMenu *menu = (MirrorMenu *) model;
383 TestItem *item;
385 item = g_sequence_get (g_sequence_get_iter_at_pos (menu->items, position));
386 *table = g_hash_table_ref (item->links);
389 static void
390 mirror_menu_finalize (GObject *object)
392 MirrorMenu *menu = (MirrorMenu *) object;
394 if (menu->handler_id)
395 g_signal_handler_disconnect (menu->clone_of, menu->handler_id);
397 g_sequence_free (menu->items);
398 g_object_unref (menu->clone_of);
400 G_OBJECT_CLASS (mirror_menu_parent_class)
401 ->finalize (object);
404 static void
405 mirror_menu_init (MirrorMenu *menu)
409 static void
410 mirror_menu_class_init (GMenuModelClass *class)
412 GObjectClass *object_class = G_OBJECT_CLASS (class);
414 class->is_mutable = mirror_menu_is_mutable;
415 class->get_n_items = mirror_menu_get_n_items;
416 class->get_item_attributes = mirror_menu_get_item_attributes;
417 class->get_item_links = mirror_menu_get_item_links;
419 object_class->finalize = mirror_menu_finalize;
422 static MirrorMenu * mirror_menu_new (GMenuModel *clone_of);
424 static void
425 mirror_menu_changed (GMenuModel *model,
426 gint position,
427 gint removed,
428 gint added,
429 gpointer user_data)
431 MirrorMenu *menu = user_data;
432 GSequenceIter *point;
433 gint i;
435 g_assert (model == menu->clone_of);
437 point = g_sequence_get_iter_at_pos (menu->items, position + removed);
439 if (removed)
441 GSequenceIter *start;
443 start = g_sequence_get_iter_at_pos (menu->items, position);
444 g_sequence_remove_range (start, point);
447 for (i = position; i < position + added; i++)
449 GMenuAttributeIter *attr_iter;
450 GMenuLinkIter *link_iter;
451 GHashTable *links;
452 GHashTable *attributes;
453 const gchar *name;
454 GMenuModel *child;
455 GVariant *value;
457 attributes = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, (GDestroyNotify) g_variant_unref);
458 links = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, (GDestroyNotify) g_object_unref);
460 attr_iter = g_menu_model_iterate_item_attributes (model, i);
461 while (g_menu_attribute_iter_get_next (attr_iter, &name, &value))
463 g_hash_table_insert (attributes, g_strdup (name), value);
465 g_object_unref (attr_iter);
467 link_iter = g_menu_model_iterate_item_links (model, i);
468 while (g_menu_link_iter_get_next (link_iter, &name, &child))
470 g_hash_table_insert (links, g_strdup (name), mirror_menu_new (child));
471 g_object_unref (child);
473 g_object_unref (link_iter);
475 g_sequence_insert_before (point, test_item_new (attributes, links));
476 g_hash_table_unref (attributes);
477 g_hash_table_unref (links);
480 g_menu_model_items_changed (G_MENU_MODEL (menu), position, removed, added);
483 static MirrorMenu *
484 mirror_menu_new (GMenuModel *clone_of)
486 MirrorMenu *menu;
488 menu = g_object_new (mirror_menu_get_type (), NULL);
489 menu->items = g_sequence_new (test_item_free);
490 menu->clone_of = g_object_ref (clone_of);
492 if (g_menu_model_is_mutable (clone_of))
493 menu->handler_id = g_signal_connect (clone_of, "items-changed", G_CALLBACK (mirror_menu_changed), menu);
494 mirror_menu_changed (clone_of, 0, 0, g_menu_model_get_n_items (clone_of), menu);
496 return menu;
499 /* check_menus_equal(), assert_menus_equal() {{{1 */
500 static gboolean
501 check_menus_equal (GMenuModel *a,
502 GMenuModel *b)
504 gboolean equal = TRUE;
505 gint a_n, b_n;
506 gint i;
508 a_n = g_menu_model_get_n_items (a);
509 b_n = g_menu_model_get_n_items (b);
511 if (a_n != b_n)
512 return FALSE;
514 for (i = 0; i < a_n; i++)
516 GMenuAttributeIter *attr_iter;
517 GVariant *a_value, *b_value;
518 GMenuLinkIter *link_iter;
519 GMenuModel *a_menu, *b_menu;
520 const gchar *name;
522 attr_iter = g_menu_model_iterate_item_attributes (a, i);
523 while (g_menu_attribute_iter_get_next (attr_iter, &name, &a_value))
525 b_value = g_menu_model_get_item_attribute_value (b, i, name, NULL);
526 equal &= b_value && g_variant_equal (a_value, b_value);
527 if (b_value)
528 g_variant_unref (b_value);
529 g_variant_unref (a_value);
531 g_object_unref (attr_iter);
533 attr_iter = g_menu_model_iterate_item_attributes (b, i);
534 while (g_menu_attribute_iter_get_next (attr_iter, &name, &b_value))
536 a_value = g_menu_model_get_item_attribute_value (a, i, name, NULL);
537 equal &= a_value && g_variant_equal (a_value, b_value);
538 if (a_value)
539 g_variant_unref (a_value);
540 g_variant_unref (b_value);
542 g_object_unref (attr_iter);
544 link_iter = g_menu_model_iterate_item_links (a, i);
545 while (g_menu_link_iter_get_next (link_iter, &name, &a_menu))
547 b_menu = g_menu_model_get_item_link (b, i, name);
548 equal &= b_menu && check_menus_equal (a_menu, b_menu);
549 if (b_menu)
550 g_object_unref (b_menu);
551 g_object_unref (a_menu);
553 g_object_unref (link_iter);
555 link_iter = g_menu_model_iterate_item_links (b, i);
556 while (g_menu_link_iter_get_next (link_iter, &name, &b_menu))
558 a_menu = g_menu_model_get_item_link (a, i, name);
559 equal &= a_menu && check_menus_equal (a_menu, b_menu);
560 if (a_menu)
561 g_object_unref (a_menu);
562 g_object_unref (b_menu);
564 g_object_unref (link_iter);
567 return equal;
570 static void
571 assert_menus_equal (GMenuModel *a,
572 GMenuModel *b)
574 if (!check_menus_equal (a, b))
576 GString *string;
578 string = g_string_new ("\n <a>\n");
579 g_menu_markup_print_string (string, G_MENU_MODEL (a), 4, 2);
580 g_string_append (string, " </a>\n\n-------------\n <b>\n");
581 g_menu_markup_print_string (string, G_MENU_MODEL (b), 4, 2);
582 g_string_append (string, " </b>\n");
583 g_error ("%s", string->str);
587 /* Test cases {{{1 */
588 static void
589 test_equality (void)
591 GRand *randa, *randb;
592 guint32 seed;
593 gint i;
595 seed = g_test_rand_int ();
597 randa = g_rand_new_with_seed (seed);
598 randb = g_rand_new_with_seed (seed);
600 for (i = 0; i < 500; i++)
602 RandomMenu *a, *b;
604 a = random_menu_new (randa, TOP_ORDER);
605 b = random_menu_new (randb, TOP_ORDER);
606 assert_menus_equal (G_MENU_MODEL (a), G_MENU_MODEL (b));
607 g_object_unref (b);
608 g_object_unref (a);
611 g_rand_int (randa);
613 for (i = 0; i < 500;)
615 RandomMenu *a, *b;
617 a = random_menu_new (randa, TOP_ORDER);
618 b = random_menu_new (randb, TOP_ORDER);
619 if (check_menus_equal (G_MENU_MODEL (a), G_MENU_MODEL (b)))
621 /* by chance, they may really be equal. double check. */
622 GString *as, *bs;
624 as = g_menu_markup_print_string (NULL, G_MENU_MODEL (a), 4, 2);
625 bs = g_menu_markup_print_string (NULL, G_MENU_MODEL (b), 4, 2);
626 g_assert_cmpstr (as->str, ==, bs->str);
627 g_string_free (bs, TRUE);
628 g_string_free (as, TRUE);
630 /* we're here because randa and randb just generated equal
631 * menus. they may do it again, so throw away randb and make
632 * a fresh one.
634 g_rand_free (randb);
635 randb = g_rand_new_with_seed (g_rand_int (randa));
637 else
638 /* make sure we get enough unequals (ie: no GRand failure) */
639 i++;
641 g_object_unref (b);
642 g_object_unref (a);
645 g_rand_free (randb);
646 g_rand_free (randa);
649 static void
650 test_random (void)
652 RandomMenu *random;
653 MirrorMenu *mirror;
654 GRand *rand;
655 gint i;
657 rand = g_rand_new_with_seed (g_test_rand_int ());
658 random = random_menu_new (rand, TOP_ORDER);
659 mirror = mirror_menu_new (G_MENU_MODEL (random));
661 for (i = 0; i < 500; i++)
663 assert_menus_equal (G_MENU_MODEL (random), G_MENU_MODEL (mirror));
664 random_menu_change (random, rand);
667 g_object_unref (mirror);
668 g_object_unref (random);
670 g_rand_free (rand);
673 struct roundtrip_state
675 RandomMenu *random;
676 MirrorMenu *proxy_mirror;
677 GDBusMenuModel *proxy;
678 GMainLoop *loop;
679 GRand *rand;
680 gint success;
681 gint count;
684 static gboolean
685 roundtrip_step (gpointer data)
687 struct roundtrip_state *state = data;
689 if (check_menus_equal (G_MENU_MODEL (state->random), G_MENU_MODEL (state->proxy)) &&
690 check_menus_equal (G_MENU_MODEL (state->random), G_MENU_MODEL (state->proxy_mirror)))
692 state->success++;
693 state->count = 0;
695 if (state->success < 100)
696 random_menu_change (state->random, state->rand);
697 else
698 g_main_loop_quit (state->loop);
700 else if (state->count == 100)
702 assert_menus_equal (G_MENU_MODEL (state->random), G_MENU_MODEL (state->proxy));
703 g_assert_not_reached ();
705 else
706 state->count++;
708 return G_SOURCE_CONTINUE;
711 static void
712 test_dbus_roundtrip (void)
714 struct roundtrip_state state;
715 GDBusConnection *bus;
716 guint export_id;
717 guint id;
719 bus = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, NULL);
721 state.rand = g_rand_new_with_seed (g_test_rand_int ());
723 state.random = random_menu_new (state.rand, 2);
724 export_id = g_dbus_connection_export_menu_model (bus, "/", G_MENU_MODEL (state.random), NULL);
725 state.proxy = g_dbus_menu_model_get (bus, g_dbus_connection_get_unique_name (bus), "/");
726 state.proxy_mirror = mirror_menu_new (G_MENU_MODEL (state.proxy));
727 state.count = 0;
728 state.success = 0;
730 id = g_timeout_add (10, roundtrip_step, &state);
732 state.loop = g_main_loop_new (NULL, FALSE);
733 g_main_loop_run (state.loop);
735 g_main_loop_unref (state.loop);
736 g_source_remove (id);
737 g_object_unref (state.proxy);
738 g_dbus_connection_unexport_menu_model (bus, export_id);
739 g_object_unref (state.random);
740 g_object_unref (state.proxy_mirror);
741 g_rand_free (state.rand);
742 g_object_unref (bus);
745 static gint items_changed_count;
747 static void
748 items_changed (GMenuModel *model,
749 gint position,
750 gint removed,
751 gint added,
752 gpointer data)
754 items_changed_count++;
757 static gboolean
758 stop_loop (gpointer data)
760 GMainLoop *loop = data;
762 g_main_loop_quit (loop);
764 return G_SOURCE_REMOVE;
767 static void
768 test_dbus_subscriptions (void)
770 GDBusConnection *bus;
771 GMenu *menu;
772 GDBusMenuModel *proxy;
773 GMainLoop *loop;
774 GError *error = NULL;
775 guint export_id;
777 loop = g_main_loop_new (NULL, FALSE);
779 bus = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, NULL);
781 menu = g_menu_new ();
783 export_id = g_dbus_connection_export_menu_model (bus, "/", G_MENU_MODEL (menu), &error);
784 g_assert_no_error (error);
786 proxy = g_dbus_menu_model_get (bus, g_dbus_connection_get_unique_name (bus), "/");
787 items_changed_count = 0;
788 g_signal_connect (proxy, "items-changed",
789 G_CALLBACK (items_changed), NULL);
791 g_menu_append (menu, "item1", NULL);
792 g_menu_append (menu, "item2", NULL);
793 g_menu_append (menu, "item3", NULL);
795 g_assert_cmpint (items_changed_count, ==, 0);
797 g_timeout_add (100, stop_loop, loop);
798 g_main_loop_run (loop);
800 g_menu_model_get_n_items (G_MENU_MODEL (proxy));
802 g_timeout_add (100, stop_loop, loop);
803 g_main_loop_run (loop);
805 g_assert_cmpint (items_changed_count, ==, 1);
806 g_assert_cmpint (g_menu_model_get_n_items (G_MENU_MODEL (proxy)), ==, 3);
808 g_timeout_add (100, stop_loop, loop);
809 g_main_loop_run (loop);
811 g_menu_append (menu, "item4", NULL);
812 g_menu_append (menu, "item5", NULL);
813 g_menu_append (menu, "item6", NULL);
814 g_menu_remove (menu, 0);
815 g_menu_remove (menu, 0);
817 g_timeout_add (200, stop_loop, loop);
818 g_main_loop_run (loop);
820 g_assert_cmpint (items_changed_count, ==, 6);
822 g_assert_cmpint (g_menu_model_get_n_items (G_MENU_MODEL (proxy)), ==, 4);
823 g_object_unref (proxy);
825 g_timeout_add (100, stop_loop, loop);
826 g_main_loop_run (loop);
828 g_menu_remove (menu, 0);
829 g_menu_remove (menu, 0);
831 g_timeout_add (100, stop_loop, loop);
832 g_main_loop_run (loop);
834 g_assert_cmpint (items_changed_count, ==, 6);
836 g_dbus_connection_unexport_menu_model (bus, export_id);
837 g_object_unref (menu);
839 g_main_loop_unref (loop);
842 static gpointer
843 do_modify (gpointer data)
845 RandomMenu *menu = data;
846 GRand *rand;
847 gint i;
849 rand = g_rand_new_with_seed (g_test_rand_int ());
851 for (i = 0; i < 10000; i++)
853 random_menu_change (menu, rand);
856 return NULL;
859 static gpointer
860 do_export (gpointer data)
862 GMenuModel *menu = data;
863 gint i;
864 GDBusConnection *bus;
865 gchar *path;
866 GError *error = NULL;
867 guint id;
869 bus = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, NULL);
870 path = g_strdup_printf ("/%p", data);
872 for (i = 0; i < 10000; i++)
874 id = g_dbus_connection_export_menu_model (bus, path, menu, &error);
875 g_assert_no_error (error);
876 g_dbus_connection_unexport_menu_model (bus, id);
877 while (g_main_context_iteration (NULL, FALSE));
880 g_free (path);
882 g_object_unref (bus);
884 return NULL;
887 static void
888 test_dbus_threaded (void)
890 RandomMenu *menu[10];
891 GThread *call[10];
892 GThread *export[10];
893 gint i;
895 for (i = 0; i < 10; i++)
897 menu[i] = random_menu_new (g_rand_new_with_seed (g_test_rand_int ()), 2);
898 call[i] = g_thread_new ("call", do_modify, menu[i]);
899 export[i] = g_thread_new ("export", do_export, menu[i]);
902 for (i = 0; i < 10; i++)
904 g_thread_join (call[i]);
905 g_thread_join (export[i]);
908 for (i = 0; i < 10; i++)
909 g_object_unref (menu[i]);
912 static void
913 test_attributes (void)
915 GMenu *menu;
916 GMenuItem *item;
917 GVariant *v;
919 menu = g_menu_new ();
921 item = g_menu_item_new ("test", NULL);
922 g_menu_item_set_attribute_value (item, "boolean", g_variant_new_boolean (FALSE));
923 g_menu_item_set_attribute_value (item, "string", g_variant_new_string ("bla"));
924 g_menu_item_set_attribute_value (item, "double", g_variant_new_double (1.5));
925 v = g_variant_new_parsed ("[('one', 1), ('two', %i), (%s, 3)]", 2, "three");
926 g_menu_item_set_attribute_value (item, "complex", v);
927 g_menu_item_set_attribute_value (item, "test-123", g_variant_new_string ("test-123"));
929 g_menu_append_item (menu, item);
931 g_assert_cmpint (g_menu_model_get_n_items (G_MENU_MODEL (menu)), ==, 1);
933 v = g_menu_model_get_item_attribute_value (G_MENU_MODEL (menu), 0, "boolean", NULL);
934 g_assert (g_variant_is_of_type (v, G_VARIANT_TYPE_BOOLEAN));
935 g_variant_unref (v);
937 v = g_menu_model_get_item_attribute_value (G_MENU_MODEL (menu), 0, "string", NULL);
938 g_assert (g_variant_is_of_type (v, G_VARIANT_TYPE_STRING));
939 g_variant_unref (v);
941 v = g_menu_model_get_item_attribute_value (G_MENU_MODEL (menu), 0, "double", NULL);
942 g_assert (g_variant_is_of_type (v, G_VARIANT_TYPE_DOUBLE));
943 g_variant_unref (v);
945 v = g_menu_model_get_item_attribute_value (G_MENU_MODEL (menu), 0, "complex", NULL);
946 g_assert (g_variant_is_of_type (v, G_VARIANT_TYPE("a(si)")));
947 g_variant_unref (v);
949 g_object_unref (menu);
952 static void
953 test_links (void)
955 GMenu *menu;
956 GMenuModel *m;
957 GMenuModel *x;
958 GMenuItem *item;
960 m = G_MENU_MODEL (g_menu_new ());
961 g_menu_append (G_MENU (m), "test", NULL);
963 menu = g_menu_new ();
965 item = g_menu_item_new ("test1", NULL);
966 g_menu_item_set_link (item, "section", m);
967 g_menu_append_item (menu, item);
969 item = g_menu_item_new ("test2", NULL);
970 g_menu_item_set_link (item, "submenu", m);
971 g_menu_append_item (menu, item);
973 item = g_menu_item_new ("test3", NULL);
974 g_menu_item_set_link (item, "wallet", m);
975 g_menu_append_item (menu, item);
977 item = g_menu_item_new ("test4", NULL);
978 g_menu_item_set_link (item, "purse", m);
979 g_menu_item_set_link (item, "purse", NULL);
980 g_menu_append_item (menu, item);
982 g_assert_cmpint (g_menu_model_get_n_items (G_MENU_MODEL (menu)), ==, 4);
984 x = g_menu_model_get_item_link (G_MENU_MODEL (menu), 0, "section");
985 g_assert (x == m);
986 g_object_unref (x);
988 x = g_menu_model_get_item_link (G_MENU_MODEL (menu), 1, "submenu");
989 g_assert (x == m);
990 g_object_unref (x);
992 x = g_menu_model_get_item_link (G_MENU_MODEL (menu), 2, "wallet");
993 g_assert (x == m);
994 g_object_unref (x);
996 x = g_menu_model_get_item_link (G_MENU_MODEL (menu), 3, "purse");
997 g_assert (x == NULL);
999 g_object_unref (m);
1000 g_object_unref (menu);
1003 static void
1004 test_mutable (void)
1006 GMenu *menu;
1008 menu = g_menu_new ();
1009 g_menu_append (menu, "test", "test");
1011 g_assert (g_menu_model_is_mutable (G_MENU_MODEL (menu)));
1012 g_menu_freeze (menu);
1013 g_assert (!g_menu_model_is_mutable (G_MENU_MODEL (menu)));
1015 g_object_unref (menu);
1018 /* Epilogue {{{1 */
1020 main (int argc, char **argv)
1022 g_test_init (&argc, &argv, NULL);
1024 g_type_init ();
1026 g_test_add_func ("/gmenu/equality", test_equality);
1027 g_test_add_func ("/gmenu/random", test_random);
1028 g_test_add_func ("/gmenu/dbus/roundtrip", test_dbus_roundtrip);
1029 g_test_add_func ("/gmenu/dbus/subscriptions", test_dbus_subscriptions);
1030 g_test_add_func ("/gmenu/dbus/threaded", test_dbus_threaded);
1031 g_test_add_func ("/gmenu/attributes", test_attributes);
1032 g_test_add_func ("/gmenu/links", test_links);
1033 g_test_add_func ("/gmenu/mutable", test_mutable);
1035 return g_test_run ();
1037 /* vim:set foldmethod=marker: */