2 #include <gio/gunixsocketaddress.h>
3 #include <glib/gstdio.h>
6 #include "gdbus-sessionbus.h"
9 time_out (gpointer unused G_GNUC_UNUSED
)
11 g_error ("Timed out");
17 add_timeout (guint seconds
)
20 /* Safety-catch against the main loop having blocked */
23 return g_timeout_add_seconds (seconds
, time_out
, NULL
);
27 cancel_timeout (guint timeout_id
)
32 g_source_remove (timeout_id
);
35 /* Markup printing {{{1 */
37 /* This used to be part of GLib, but it was removed before the stable
38 * release because it wasn't generally useful. We want it here, though.
41 indent_string (GString
*string
,
45 g_string_append_c (string
, ' ');
49 g_menu_markup_print_string (GString
*string
,
54 gboolean need_nl
= FALSE
;
57 if G_UNLIKELY (string
== NULL
)
58 string
= g_string_new (NULL
);
60 n
= g_menu_model_get_n_items (model
);
62 for (i
= 0; i
< n
; i
++)
64 GMenuAttributeIter
*attr_iter
;
65 GMenuLinkIter
*link_iter
;
69 attr_iter
= g_menu_model_iterate_item_attributes (model
, i
);
70 link_iter
= g_menu_model_iterate_item_links (model
, i
);
71 contents
= g_string_new (NULL
);
72 attrs
= g_string_new (NULL
);
74 while (g_menu_attribute_iter_next (attr_iter
))
76 const char *name
= g_menu_attribute_iter_get_name (attr_iter
);
77 GVariant
*value
= g_menu_attribute_iter_get_value (attr_iter
);
79 if (g_variant_is_of_type (value
, G_VARIANT_TYPE_STRING
))
82 str
= g_markup_printf_escaped (" %s='%s'", name
, g_variant_get_string (value
, NULL
));
83 g_string_append (attrs
, str
);
93 printed
= g_variant_print (value
, TRUE
);
94 type
= g_variant_type_peek_string (g_variant_get_type (value
));
95 str
= g_markup_printf_escaped ("<attribute name='%s' type='%s'>%s</attribute>\n", name
, type
, printed
);
96 indent_string (contents
, indent
+ tabstop
);
97 g_string_append (contents
, str
);
102 g_variant_unref (value
);
104 g_object_unref (attr_iter
);
106 while (g_menu_link_iter_next (link_iter
))
108 const gchar
*name
= g_menu_link_iter_get_name (link_iter
);
109 GMenuModel
*menu
= g_menu_link_iter_get_value (link_iter
);
112 if (contents
->str
[0])
113 g_string_append_c (contents
, '\n');
115 str
= g_markup_printf_escaped ("<link name='%s'>\n", name
);
116 indent_string (contents
, indent
+ tabstop
);
117 g_string_append (contents
, str
);
120 g_menu_markup_print_string (contents
, menu
, indent
+ 2 * tabstop
, tabstop
);
122 indent_string (contents
, indent
+ tabstop
);
123 g_string_append (contents
, "</link>\n");
124 g_object_unref (menu
);
126 g_object_unref (link_iter
);
128 if (contents
->str
[0])
130 indent_string (string
, indent
);
131 g_string_append_printf (string
, "<item%s>\n", attrs
->str
);
132 g_string_append (string
, contents
->str
);
133 indent_string (string
, indent
);
134 g_string_append (string
, "</item>\n");
141 g_string_append_c (string
, '\n');
143 indent_string (string
, indent
);
144 g_string_append_printf (string
, "<item%s/>\n", attrs
->str
);
148 g_string_free (contents
, TRUE
);
149 g_string_free (attrs
, TRUE
);
157 /* This utility struct is used by both the RandomMenu and MirrorMenu
158 * class implementations below.
161 GHashTable
*attributes
;
166 test_item_new (GHashTable
*attributes
,
171 item
= g_slice_new (TestItem
);
172 item
->attributes
= g_hash_table_ref (attributes
);
173 item
->links
= g_hash_table_ref (links
);
179 test_item_free (gpointer data
)
181 TestItem
*item
= data
;
183 g_hash_table_unref (item
->attributes
);
184 g_hash_table_unref (item
->links
);
186 g_slice_free (TestItem
, item
);
189 /* RandomMenu {{{1 */
194 GMenuModel parent_instance
;
200 typedef GMenuModelClass RandomMenuClass
;
202 static GType
random_menu_get_type (void);
203 G_DEFINE_TYPE (RandomMenu
, random_menu
, G_TYPE_MENU_MODEL
)
206 random_menu_is_mutable (GMenuModel
*model
)
212 random_menu_get_n_items (GMenuModel
*model
)
214 RandomMenu
*menu
= (RandomMenu
*) model
;
216 return g_sequence_get_length (menu
->items
);
220 random_menu_get_item_attributes (GMenuModel
*model
,
224 RandomMenu
*menu
= (RandomMenu
*) model
;
227 item
= g_sequence_get (g_sequence_get_iter_at_pos (menu
->items
, position
));
228 *table
= g_hash_table_ref (item
->attributes
);
232 random_menu_get_item_links (GMenuModel
*model
,
236 RandomMenu
*menu
= (RandomMenu
*) model
;
239 item
= g_sequence_get (g_sequence_get_iter_at_pos (menu
->items
, position
));
240 *table
= g_hash_table_ref (item
->links
);
244 random_menu_finalize (GObject
*object
)
246 RandomMenu
*menu
= (RandomMenu
*) object
;
248 g_sequence_free (menu
->items
);
250 G_OBJECT_CLASS (random_menu_parent_class
)
255 random_menu_init (RandomMenu
*menu
)
260 random_menu_class_init (GMenuModelClass
*class)
262 GObjectClass
*object_class
= G_OBJECT_CLASS (class);
264 class->is_mutable
= random_menu_is_mutable
;
265 class->get_n_items
= random_menu_get_n_items
;
266 class->get_item_attributes
= random_menu_get_item_attributes
;
267 class->get_item_links
= random_menu_get_item_links
;
269 object_class
->finalize
= random_menu_finalize
;
272 static RandomMenu
* random_menu_new (GRand
*rand
, gint order
);
275 random_menu_change (RandomMenu
*menu
,
278 gint position
, removes
, adds
;
279 GSequenceIter
*point
;
283 n_items
= g_sequence_get_length (menu
->items
);
287 position
= g_rand_int_range (rand
, 0, n_items
+ 1);
288 removes
= g_rand_int_range (rand
, 0, n_items
- position
+ 1);
289 adds
= g_rand_int_range (rand
, 0, MAX_ITEMS
- (n_items
- removes
) + 1);
291 while (removes
== 0 && adds
== 0);
293 point
= g_sequence_get_iter_at_pos (menu
->items
, position
+ removes
);
297 GSequenceIter
*start
;
299 start
= g_sequence_get_iter_at_pos (menu
->items
, position
);
300 g_sequence_remove_range (start
, point
);
303 for (i
= 0; i
< adds
; i
++)
307 GHashTable
*attributes
;
309 attributes
= g_hash_table_new_full (g_str_hash
, g_str_equal
, g_free
, (GDestroyNotify
) g_variant_unref
);
310 links
= g_hash_table_new_full (g_str_hash
, g_str_equal
, g_free
, (GDestroyNotify
) g_object_unref
);
312 if (menu
->order
> 0 && g_rand_boolean (rand
))
315 const gchar
*subtype
;
317 child
= random_menu_new (rand
, menu
->order
- 1);
319 if (g_rand_boolean (rand
))
321 subtype
= G_MENU_LINK_SECTION
;
322 /* label some section headers */
323 if (g_rand_boolean (rand
))
330 /* label all submenus */
331 subtype
= G_MENU_LINK_SUBMENU
;
335 g_hash_table_insert (links
, g_strdup (subtype
), child
);
338 /* label all terminals */
342 g_hash_table_insert (attributes
, g_strdup ("label"), g_variant_ref_sink (g_variant_new_string (label
)));
344 g_sequence_insert_before (point
, test_item_new (attributes
, links
));
345 g_hash_table_unref (links
);
346 g_hash_table_unref (attributes
);
349 g_menu_model_items_changed (G_MENU_MODEL (menu
), position
, removes
, adds
);
353 random_menu_new (GRand
*rand
,
358 menu
= g_object_new (random_menu_get_type (), NULL
);
359 menu
->items
= g_sequence_new (test_item_free
);
362 random_menu_change (menu
, rand
);
367 /* MirrorMenu {{{1 */
369 GMenuModel parent_instance
;
371 GMenuModel
*clone_of
;
376 typedef GMenuModelClass MirrorMenuClass
;
378 static GType
mirror_menu_get_type (void);
379 G_DEFINE_TYPE (MirrorMenu
, mirror_menu
, G_TYPE_MENU_MODEL
)
382 mirror_menu_is_mutable (GMenuModel
*model
)
384 MirrorMenu
*menu
= (MirrorMenu
*) model
;
386 return menu
->handler_id
!= 0;
390 mirror_menu_get_n_items (GMenuModel
*model
)
392 MirrorMenu
*menu
= (MirrorMenu
*) model
;
394 return g_sequence_get_length (menu
->items
);
398 mirror_menu_get_item_attributes (GMenuModel
*model
,
402 MirrorMenu
*menu
= (MirrorMenu
*) model
;
405 item
= g_sequence_get (g_sequence_get_iter_at_pos (menu
->items
, position
));
406 *table
= g_hash_table_ref (item
->attributes
);
410 mirror_menu_get_item_links (GMenuModel
*model
,
414 MirrorMenu
*menu
= (MirrorMenu
*) model
;
417 item
= g_sequence_get (g_sequence_get_iter_at_pos (menu
->items
, position
));
418 *table
= g_hash_table_ref (item
->links
);
422 mirror_menu_finalize (GObject
*object
)
424 MirrorMenu
*menu
= (MirrorMenu
*) object
;
426 if (menu
->handler_id
)
427 g_signal_handler_disconnect (menu
->clone_of
, menu
->handler_id
);
429 g_sequence_free (menu
->items
);
430 g_object_unref (menu
->clone_of
);
432 G_OBJECT_CLASS (mirror_menu_parent_class
)
437 mirror_menu_init (MirrorMenu
*menu
)
442 mirror_menu_class_init (GMenuModelClass
*class)
444 GObjectClass
*object_class
= G_OBJECT_CLASS (class);
446 class->is_mutable
= mirror_menu_is_mutable
;
447 class->get_n_items
= mirror_menu_get_n_items
;
448 class->get_item_attributes
= mirror_menu_get_item_attributes
;
449 class->get_item_links
= mirror_menu_get_item_links
;
451 object_class
->finalize
= mirror_menu_finalize
;
454 static MirrorMenu
* mirror_menu_new (GMenuModel
*clone_of
);
457 mirror_menu_changed (GMenuModel
*model
,
463 MirrorMenu
*menu
= user_data
;
464 GSequenceIter
*point
;
467 g_assert (model
== menu
->clone_of
);
469 point
= g_sequence_get_iter_at_pos (menu
->items
, position
+ removed
);
473 GSequenceIter
*start
;
475 start
= g_sequence_get_iter_at_pos (menu
->items
, position
);
476 g_sequence_remove_range (start
, point
);
479 for (i
= position
; i
< position
+ added
; i
++)
481 GMenuAttributeIter
*attr_iter
;
482 GMenuLinkIter
*link_iter
;
484 GHashTable
*attributes
;
489 attributes
= g_hash_table_new_full (g_str_hash
, g_str_equal
, g_free
, (GDestroyNotify
) g_variant_unref
);
490 links
= g_hash_table_new_full (g_str_hash
, g_str_equal
, g_free
, (GDestroyNotify
) g_object_unref
);
492 attr_iter
= g_menu_model_iterate_item_attributes (model
, i
);
493 while (g_menu_attribute_iter_get_next (attr_iter
, &name
, &value
))
495 g_hash_table_insert (attributes
, g_strdup (name
), value
);
497 g_object_unref (attr_iter
);
499 link_iter
= g_menu_model_iterate_item_links (model
, i
);
500 while (g_menu_link_iter_get_next (link_iter
, &name
, &child
))
502 g_hash_table_insert (links
, g_strdup (name
), mirror_menu_new (child
));
503 g_object_unref (child
);
505 g_object_unref (link_iter
);
507 g_sequence_insert_before (point
, test_item_new (attributes
, links
));
508 g_hash_table_unref (attributes
);
509 g_hash_table_unref (links
);
512 g_menu_model_items_changed (G_MENU_MODEL (menu
), position
, removed
, added
);
516 mirror_menu_new (GMenuModel
*clone_of
)
520 menu
= g_object_new (mirror_menu_get_type (), NULL
);
521 menu
->items
= g_sequence_new (test_item_free
);
522 menu
->clone_of
= g_object_ref (clone_of
);
524 if (g_menu_model_is_mutable (clone_of
))
525 menu
->handler_id
= g_signal_connect (clone_of
, "items-changed", G_CALLBACK (mirror_menu_changed
), menu
);
526 mirror_menu_changed (clone_of
, 0, 0, g_menu_model_get_n_items (clone_of
), menu
);
531 /* check_menus_equal(), assert_menus_equal() {{{1 */
533 check_menus_equal (GMenuModel
*a
,
536 gboolean equal
= TRUE
;
540 a_n
= g_menu_model_get_n_items (a
);
541 b_n
= g_menu_model_get_n_items (b
);
546 for (i
= 0; i
< a_n
; i
++)
548 GMenuAttributeIter
*attr_iter
;
549 GVariant
*a_value
, *b_value
;
550 GMenuLinkIter
*link_iter
;
551 GMenuModel
*a_menu
, *b_menu
;
554 attr_iter
= g_menu_model_iterate_item_attributes (a
, i
);
555 while (g_menu_attribute_iter_get_next (attr_iter
, &name
, &a_value
))
557 b_value
= g_menu_model_get_item_attribute_value (b
, i
, name
, NULL
);
558 equal
&= b_value
&& g_variant_equal (a_value
, b_value
);
560 g_variant_unref (b_value
);
561 g_variant_unref (a_value
);
563 g_object_unref (attr_iter
);
565 attr_iter
= g_menu_model_iterate_item_attributes (b
, i
);
566 while (g_menu_attribute_iter_get_next (attr_iter
, &name
, &b_value
))
568 a_value
= g_menu_model_get_item_attribute_value (a
, i
, name
, NULL
);
569 equal
&= a_value
&& g_variant_equal (a_value
, b_value
);
571 g_variant_unref (a_value
);
572 g_variant_unref (b_value
);
574 g_object_unref (attr_iter
);
576 link_iter
= g_menu_model_iterate_item_links (a
, i
);
577 while (g_menu_link_iter_get_next (link_iter
, &name
, &a_menu
))
579 b_menu
= g_menu_model_get_item_link (b
, i
, name
);
580 equal
&= b_menu
&& check_menus_equal (a_menu
, b_menu
);
582 g_object_unref (b_menu
);
583 g_object_unref (a_menu
);
585 g_object_unref (link_iter
);
587 link_iter
= g_menu_model_iterate_item_links (b
, i
);
588 while (g_menu_link_iter_get_next (link_iter
, &name
, &b_menu
))
590 a_menu
= g_menu_model_get_item_link (a
, i
, name
);
591 equal
&= a_menu
&& check_menus_equal (a_menu
, b_menu
);
593 g_object_unref (a_menu
);
594 g_object_unref (b_menu
);
596 g_object_unref (link_iter
);
603 assert_menus_equal (GMenuModel
*a
,
606 if (!check_menus_equal (a
, b
))
610 string
= g_string_new ("\n <a>\n");
611 g_menu_markup_print_string (string
, G_MENU_MODEL (a
), 4, 2);
612 g_string_append (string
, " </a>\n\n-------------\n <b>\n");
613 g_menu_markup_print_string (string
, G_MENU_MODEL (b
), 4, 2);
614 g_string_append (string
, " </b>\n");
615 g_error ("%s", string
->str
);
620 assert_menuitem_equal (GMenuItem
*item
,
624 GMenuAttributeIter
*attr_iter
;
625 GMenuLinkIter
*link_iter
;
628 GMenuModel
*linked_model
;
630 /* NOTE we can't yet test whether item has attributes or links that
631 * are not in the model, because there's no iterator API for menu
634 attr_iter
= g_menu_model_iterate_item_attributes (model
, index
);
635 while (g_menu_attribute_iter_get_next (attr_iter
, &name
, &value
))
637 GVariant
*item_value
;
639 item_value
= g_menu_item_get_attribute_value (item
, name
, g_variant_get_type (value
));
640 g_assert (item_value
&& g_variant_equal (item_value
, value
));
642 g_variant_unref (item_value
);
643 g_variant_unref (value
);
646 link_iter
= g_menu_model_iterate_item_links (model
, index
);
647 while (g_menu_link_iter_get_next (link_iter
, &name
, &linked_model
))
649 GMenuModel
*item_linked_model
;
651 item_linked_model
= g_menu_item_get_link (item
, name
);
652 g_assert (linked_model
== item_linked_model
);
654 g_object_unref (item_linked_model
);
655 g_object_unref (linked_model
);
658 g_object_unref (attr_iter
);
659 g_object_unref (link_iter
);
662 /* Test cases {{{1 */
666 GRand
*randa
, *randb
;
670 seed
= g_test_rand_int ();
672 randa
= g_rand_new_with_seed (seed
);
673 randb
= g_rand_new_with_seed (seed
);
675 for (i
= 0; i
< 500; i
++)
679 a
= random_menu_new (randa
, TOP_ORDER
);
680 b
= random_menu_new (randb
, TOP_ORDER
);
681 assert_menus_equal (G_MENU_MODEL (a
), G_MENU_MODEL (b
));
688 for (i
= 0; i
< 500;)
692 a
= random_menu_new (randa
, TOP_ORDER
);
693 b
= random_menu_new (randb
, TOP_ORDER
);
694 if (check_menus_equal (G_MENU_MODEL (a
), G_MENU_MODEL (b
)))
696 /* by chance, they may really be equal. double check. */
699 as
= g_menu_markup_print_string (NULL
, G_MENU_MODEL (a
), 4, 2);
700 bs
= g_menu_markup_print_string (NULL
, G_MENU_MODEL (b
), 4, 2);
701 g_assert_cmpstr (as
->str
, ==, bs
->str
);
702 g_string_free (bs
, TRUE
);
703 g_string_free (as
, TRUE
);
705 /* we're here because randa and randb just generated equal
706 * menus. they may do it again, so throw away randb and make
710 randb
= g_rand_new_with_seed (g_rand_int (randa
));
713 /* make sure we get enough unequals (ie: no GRand failure) */
732 rand
= g_rand_new_with_seed (g_test_rand_int ());
733 random
= random_menu_new (rand
, TOP_ORDER
);
734 mirror
= mirror_menu_new (G_MENU_MODEL (random
));
736 for (i
= 0; i
< 500; i
++)
738 assert_menus_equal (G_MENU_MODEL (random
), G_MENU_MODEL (mirror
));
739 random_menu_change (random
, rand
);
742 g_object_unref (mirror
);
743 g_object_unref (random
);
750 GDBusConnection
*client_connection
;
751 GDBusConnection
*server_connection
;
754 GThread
*service_thread
;
755 GMutex service_loop_lock
;
756 GCond service_loop_cond
;
758 GMainLoop
*service_loop
;
763 on_new_connection (GDBusServer
*server
,
764 GDBusConnection
*connection
,
767 PeerConnection
*data
= user_data
;
769 data
->server_connection
= g_object_ref (connection
);
771 g_main_loop_quit (data
->loop
);
777 create_service_loop (GMainContext
*service_context
,
778 PeerConnection
*data
)
780 g_assert (data
->service_loop
== NULL
);
781 g_mutex_lock (&data
->service_loop_lock
);
782 data
->service_loop
= g_main_loop_new (service_context
, FALSE
);
783 g_cond_broadcast (&data
->service_loop_cond
);
784 g_mutex_unlock (&data
->service_loop_lock
);
788 teardown_service_loop (PeerConnection
*data
)
790 g_mutex_lock (&data
->service_loop_lock
);
791 g_clear_pointer (&data
->service_loop
, g_main_loop_unref
);
792 g_mutex_unlock (&data
->service_loop_lock
);
796 await_service_loop (PeerConnection
*data
)
798 g_mutex_lock (&data
->service_loop_lock
);
799 while (data
->service_loop
== NULL
)
800 g_cond_wait (&data
->service_loop_cond
, &data
->service_loop_lock
);
801 g_mutex_unlock (&data
->service_loop_lock
);
805 service_thread_func (gpointer user_data
)
807 PeerConnection
*data
= user_data
;
808 GMainContext
*service_context
;
812 GDBusServerFlags flags
;
815 service_context
= g_main_context_new ();
816 g_main_context_push_thread_default (service_context
);
819 flags
= G_DBUS_SERVER_FLAGS_NONE
;
822 if (g_unix_socket_address_abstract_names_supported ())
823 address
= g_strdup ("unix:tmpdir=/tmp/test-dbus-peer");
826 tmpdir
= g_dir_make_tmp ("test-dbus-peer-XXXXXX", NULL
);
827 address
= g_strdup_printf ("unix:tmpdir=%s", tmpdir
);
830 address
= g_strdup ("nonce-tcp:");
831 flags
|= G_DBUS_SERVER_FLAGS_AUTHENTICATION_ALLOW_ANONYMOUS
;
834 guid
= g_dbus_generate_guid ();
837 data
->server
= g_dbus_server_new_sync (address
,
843 g_assert_no_error (error
);
847 g_signal_connect (data
->server
,
849 G_CALLBACK (on_new_connection
),
852 g_dbus_server_start (data
->server
);
854 create_service_loop (service_context
, data
);
855 g_main_loop_run (data
->service_loop
);
857 g_main_context_pop_thread_default (service_context
);
859 teardown_service_loop (data
);
860 g_main_context_unref (service_context
);
872 peer_connection_up (PeerConnection
*data
)
876 memset (data
, '\0', sizeof (PeerConnection
));
877 data
->loop
= g_main_loop_new (NULL
, FALSE
);
879 g_mutex_init (&data
->service_loop_lock
);
880 g_cond_init (&data
->service_loop_cond
);
882 /* bring up a server - we run the server in a different thread to
884 data
->service_thread
= g_thread_new ("test_dbus_peer",
887 await_service_loop (data
);
888 g_assert (data
->server
!= NULL
);
890 /* bring up a connection and accept it */
892 data
->client_connection
=
893 g_dbus_connection_new_for_address_sync (g_dbus_server_get_client_address (data
->server
),
894 G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_CLIENT
,
895 NULL
, /* GDBusAuthObserver */
896 NULL
, /* cancellable */
898 g_assert_no_error (error
);
899 g_assert (data
->client_connection
!= NULL
);
900 while (data
->server_connection
== NULL
)
901 g_main_loop_run (data
->loop
);
905 peer_connection_down (PeerConnection
*data
)
907 g_object_unref (data
->client_connection
);
908 g_object_unref (data
->server_connection
);
910 g_dbus_server_stop (data
->server
);
911 g_object_unref (data
->server
);
913 g_main_loop_quit (data
->service_loop
);
914 g_thread_join (data
->service_thread
);
916 g_mutex_clear (&data
->service_loop_lock
);
917 g_cond_clear (&data
->service_loop_cond
);
919 g_main_loop_unref (data
->loop
);
922 struct roundtrip_state
925 MirrorMenu
*proxy_mirror
;
926 GDBusMenuModel
*proxy
;
934 roundtrip_step (gpointer data
)
936 struct roundtrip_state
*state
= data
;
938 if (check_menus_equal (G_MENU_MODEL (state
->random
), G_MENU_MODEL (state
->proxy
)) &&
939 check_menus_equal (G_MENU_MODEL (state
->random
), G_MENU_MODEL (state
->proxy_mirror
)))
944 if (state
->success
< 100)
945 random_menu_change (state
->random
, state
->rand
);
947 g_main_loop_quit (state
->loop
);
949 else if (state
->count
== 100)
951 assert_menus_equal (G_MENU_MODEL (state
->random
), G_MENU_MODEL (state
->proxy
));
952 g_assert_not_reached ();
957 return G_SOURCE_CONTINUE
;
961 do_roundtrip (GDBusConnection
*exporter_connection
,
962 GDBusConnection
*proxy_connection
)
964 struct roundtrip_state state
;
968 state
.rand
= g_rand_new_with_seed (g_test_rand_int ());
970 state
.random
= random_menu_new (state
.rand
, 2);
971 export_id
= g_dbus_connection_export_menu_model (exporter_connection
,
973 G_MENU_MODEL (state
.random
),
975 state
.proxy
= g_dbus_menu_model_get (proxy_connection
,
976 g_dbus_connection_get_unique_name (proxy_connection
),
978 state
.proxy_mirror
= mirror_menu_new (G_MENU_MODEL (state
.proxy
));
982 id
= g_timeout_add (10, roundtrip_step
, &state
);
984 state
.loop
= g_main_loop_new (NULL
, FALSE
);
985 g_main_loop_run (state
.loop
);
987 g_main_loop_unref (state
.loop
);
988 g_source_remove (id
);
989 g_object_unref (state
.proxy
);
990 g_dbus_connection_unexport_menu_model (exporter_connection
, export_id
);
991 g_object_unref (state
.random
);
992 g_object_unref (state
.proxy_mirror
);
993 g_rand_free (state
.rand
);
997 test_dbus_roundtrip (void)
999 GDBusConnection
*bus
;
1001 bus
= g_bus_get_sync (G_BUS_TYPE_SESSION
, NULL
, NULL
);
1002 do_roundtrip (bus
, bus
);
1003 g_object_unref (bus
);
1007 test_dbus_peer_roundtrip (void)
1009 PeerConnection peer
;
1011 peer_connection_up (&peer
);
1012 do_roundtrip (peer
.server_connection
, peer
.client_connection
);
1013 peer_connection_down (&peer
);
1016 static gint items_changed_count
;
1019 items_changed (GMenuModel
*model
,
1025 items_changed_count
++;
1029 stop_loop (gpointer data
)
1031 GMainLoop
*loop
= data
;
1033 g_main_loop_quit (loop
);
1035 return G_SOURCE_REMOVE
;
1039 do_subscriptions (GDBusConnection
*exporter_connection
,
1040 GDBusConnection
*proxy_connection
)
1043 GDBusMenuModel
*proxy
;
1045 GError
*error
= NULL
;
1049 timeout_id
= add_timeout (60);
1050 loop
= g_main_loop_new (NULL
, FALSE
);
1052 menu
= g_menu_new ();
1054 export_id
= g_dbus_connection_export_menu_model (exporter_connection
,
1056 G_MENU_MODEL (menu
),
1058 g_assert_no_error (error
);
1060 proxy
= g_dbus_menu_model_get (proxy_connection
,
1061 g_dbus_connection_get_unique_name (proxy_connection
),
1063 items_changed_count
= 0;
1064 g_signal_connect (proxy
, "items-changed",
1065 G_CALLBACK (items_changed
), NULL
);
1067 g_menu_append (menu
, "item1", NULL
);
1068 g_menu_append (menu
, "item2", NULL
);
1069 g_menu_append (menu
, "item3", NULL
);
1071 g_assert_cmpint (items_changed_count
, ==, 0);
1073 /* We don't subscribe to change-notification until we look at the items */
1074 g_timeout_add (100, stop_loop
, loop
);
1075 g_main_loop_run (loop
);
1077 /* Looking at the items triggers subscription */
1078 g_menu_model_get_n_items (G_MENU_MODEL (proxy
));
1080 while (items_changed_count
< 1)
1081 g_main_context_iteration (NULL
, TRUE
);
1083 /* We get all three items in one batch */
1084 g_assert_cmpint (items_changed_count
, ==, 1);
1085 g_assert_cmpint (g_menu_model_get_n_items (G_MENU_MODEL (proxy
)), ==, 3);
1087 /* If we wait, we don't get any more */
1088 g_timeout_add (100, stop_loop
, loop
);
1089 g_main_loop_run (loop
);
1090 g_assert_cmpint (items_changed_count
, ==, 1);
1091 g_assert_cmpint (g_menu_model_get_n_items (G_MENU_MODEL (proxy
)), ==, 3);
1093 /* Now we're subscribed, we get changes individually */
1094 g_menu_append (menu
, "item4", NULL
);
1095 g_menu_append (menu
, "item5", NULL
);
1096 g_menu_append (menu
, "item6", NULL
);
1097 g_menu_remove (menu
, 0);
1098 g_menu_remove (menu
, 0);
1100 while (items_changed_count
< 6)
1101 g_main_context_iteration (NULL
, TRUE
);
1103 g_assert_cmpint (items_changed_count
, ==, 6);
1105 g_assert_cmpint (g_menu_model_get_n_items (G_MENU_MODEL (proxy
)), ==, 4);
1107 /* After destroying the proxy and waiting a bit, we don't get any more
1108 * items-changed signals */
1109 g_object_unref (proxy
);
1111 g_timeout_add (100, stop_loop
, loop
);
1112 g_main_loop_run (loop
);
1114 g_menu_remove (menu
, 0);
1115 g_menu_remove (menu
, 0);
1117 g_timeout_add (100, stop_loop
, loop
);
1118 g_main_loop_run (loop
);
1120 g_assert_cmpint (items_changed_count
, ==, 6);
1122 g_dbus_connection_unexport_menu_model (exporter_connection
, export_id
);
1123 g_object_unref (menu
);
1125 g_main_loop_unref (loop
);
1126 cancel_timeout (timeout_id
);
1130 test_dbus_subscriptions (void)
1132 GDBusConnection
*bus
;
1134 bus
= g_bus_get_sync (G_BUS_TYPE_SESSION
, NULL
, NULL
);
1135 do_subscriptions (bus
, bus
);
1136 g_object_unref (bus
);
1140 test_dbus_peer_subscriptions (void)
1142 PeerConnection peer
;
1144 peer_connection_up (&peer
);
1145 do_subscriptions (peer
.server_connection
, peer
.client_connection
);
1146 peer_connection_down (&peer
);
1150 do_modify (gpointer data
)
1152 RandomMenu
*menu
= data
;
1156 rand
= g_rand_new_with_seed (g_test_rand_int ());
1158 for (i
= 0; i
< 10000; i
++)
1160 random_menu_change (menu
, rand
);
1167 do_export (gpointer data
)
1169 GMenuModel
*menu
= data
;
1171 GDBusConnection
*bus
;
1173 GError
*error
= NULL
;
1176 bus
= g_bus_get_sync (G_BUS_TYPE_SESSION
, NULL
, NULL
);
1177 path
= g_strdup_printf ("/%p", data
);
1179 for (i
= 0; i
< 10000; i
++)
1181 id
= g_dbus_connection_export_menu_model (bus
, path
, menu
, &error
);
1182 g_assert_no_error (error
);
1183 g_dbus_connection_unexport_menu_model (bus
, id
);
1184 while (g_main_context_iteration (NULL
, FALSE
));
1189 g_object_unref (bus
);
1195 test_dbus_threaded (void)
1197 RandomMenu
*menu
[10];
1199 GThread
*export
[10];
1202 for (i
= 0; i
< 10; i
++)
1204 menu
[i
] = random_menu_new (g_rand_new_with_seed (g_test_rand_int ()), 2);
1205 call
[i
] = g_thread_new ("call", do_modify
, menu
[i
]);
1206 export
[i
] = g_thread_new ("export", do_export
, menu
[i
]);
1209 for (i
= 0; i
< 10; i
++)
1211 g_thread_join (call
[i
]);
1212 g_thread_join (export
[i
]);
1215 for (i
= 0; i
< 10; i
++)
1216 g_object_unref (menu
[i
]);
1220 test_attributes (void)
1226 menu
= g_menu_new ();
1228 item
= g_menu_item_new ("test", NULL
);
1229 g_menu_item_set_attribute_value (item
, "boolean", g_variant_new_boolean (FALSE
));
1230 g_menu_item_set_attribute_value (item
, "string", g_variant_new_string ("bla"));
1232 g_menu_item_set_attribute (item
, "double", "d", 1.5);
1233 v
= g_variant_new_parsed ("[('one', 1), ('two', %i), (%s, 3)]", 2, "three");
1234 g_menu_item_set_attribute_value (item
, "complex", v
);
1235 g_menu_item_set_attribute_value (item
, "test-123", g_variant_new_string ("test-123"));
1237 g_menu_append_item (menu
, item
);
1239 g_menu_item_set_attribute (item
, "double", "d", G_PI
);
1241 g_assert_cmpint (g_menu_model_get_n_items (G_MENU_MODEL (menu
)), ==, 1);
1243 v
= g_menu_model_get_item_attribute_value (G_MENU_MODEL (menu
), 0, "boolean", NULL
);
1244 g_assert (g_variant_is_of_type (v
, G_VARIANT_TYPE_BOOLEAN
));
1245 g_variant_unref (v
);
1247 v
= g_menu_model_get_item_attribute_value (G_MENU_MODEL (menu
), 0, "string", NULL
);
1248 g_assert (g_variant_is_of_type (v
, G_VARIANT_TYPE_STRING
));
1249 g_variant_unref (v
);
1251 v
= g_menu_model_get_item_attribute_value (G_MENU_MODEL (menu
), 0, "double", NULL
);
1252 g_assert (g_variant_is_of_type (v
, G_VARIANT_TYPE_DOUBLE
));
1253 g_variant_unref (v
);
1255 v
= g_menu_model_get_item_attribute_value (G_MENU_MODEL (menu
), 0, "complex", NULL
);
1256 g_assert (g_variant_is_of_type (v
, G_VARIANT_TYPE("a(si)")));
1257 g_variant_unref (v
);
1259 g_menu_remove_all (menu
);
1261 g_object_unref (menu
);
1262 g_object_unref (item
);
1266 test_attribute_iter (void)
1272 GMenuAttributeIter
*iter
;
1275 menu
= g_menu_new ();
1277 item
= g_menu_item_new ("test", NULL
);
1278 g_menu_item_set_attribute_value (item
, "boolean", g_variant_new_boolean (FALSE
));
1279 g_menu_item_set_attribute_value (item
, "string", g_variant_new_string ("bla"));
1281 g_menu_item_set_attribute (item
, "double", "d", 1.5);
1282 v
= g_variant_new_parsed ("[('one', 1), ('two', %i), (%s, 3)]", 2, "three");
1283 g_menu_item_set_attribute_value (item
, "complex", v
);
1284 g_menu_item_set_attribute_value (item
, "test-123", g_variant_new_string ("test-123"));
1286 g_menu_append_item (menu
, item
);
1288 g_menu_item_set_attribute (item
, "double", "d", G_PI
);
1290 g_assert_cmpint (g_menu_model_get_n_items (G_MENU_MODEL (menu
)), ==, 1);
1292 found
= g_hash_table_new_full (g_str_hash
, g_str_equal
, g_free
, (GDestroyNotify
)g_variant_unref
);
1294 iter
= g_menu_model_iterate_item_attributes (G_MENU_MODEL (menu
), 0);
1295 while (g_menu_attribute_iter_get_next (iter
, &name
, &v
))
1296 g_hash_table_insert (found
, g_strdup (name
), v
);
1298 g_assert_cmpint (g_hash_table_size (found
), ==, 6);
1300 v
= g_hash_table_lookup (found
, "label");
1301 g_assert (g_variant_is_of_type (v
, G_VARIANT_TYPE_STRING
));
1303 v
= g_hash_table_lookup (found
, "boolean");
1304 g_assert (g_variant_is_of_type (v
, G_VARIANT_TYPE_BOOLEAN
));
1306 v
= g_hash_table_lookup (found
, "string");
1307 g_assert (g_variant_is_of_type (v
, G_VARIANT_TYPE_STRING
));
1309 v
= g_hash_table_lookup (found
, "double");
1310 g_assert (g_variant_is_of_type (v
, G_VARIANT_TYPE_DOUBLE
));
1312 v
= g_hash_table_lookup (found
, "complex");
1313 g_assert (g_variant_is_of_type (v
, G_VARIANT_TYPE("a(si)")));
1315 v
= g_hash_table_lookup (found
, "test-123");
1316 g_assert (g_variant_is_of_type (v
, G_VARIANT_TYPE_STRING
));
1318 g_hash_table_unref (found
);
1320 g_menu_remove_all (menu
);
1322 g_object_unref (menu
);
1323 g_object_unref (item
);
1334 m
= G_MENU_MODEL (g_menu_new ());
1335 g_menu_append (G_MENU (m
), "test", NULL
);
1337 menu
= g_menu_new ();
1339 item
= g_menu_item_new ("test2", NULL
);
1340 g_menu_item_set_link (item
, "submenu", m
);
1341 g_menu_prepend_item (menu
, item
);
1343 item
= g_menu_item_new ("test1", NULL
);
1344 g_menu_item_set_link (item
, "section", m
);
1345 g_menu_insert_item (menu
, 0, item
);
1347 item
= g_menu_item_new ("test3", NULL
);
1348 g_menu_item_set_link (item
, "wallet", m
);
1349 g_menu_insert_item (menu
, 1000, item
);
1351 item
= g_menu_item_new ("test4", NULL
);
1352 g_menu_item_set_link (item
, "purse", m
);
1353 g_menu_item_set_link (item
, "purse", NULL
);
1354 g_menu_append_item (menu
, item
);
1356 g_assert_cmpint (g_menu_model_get_n_items (G_MENU_MODEL (menu
)), ==, 4);
1358 x
= g_menu_model_get_item_link (G_MENU_MODEL (menu
), 0, "section");
1362 x
= g_menu_model_get_item_link (G_MENU_MODEL (menu
), 1, "submenu");
1366 x
= g_menu_model_get_item_link (G_MENU_MODEL (menu
), 2, "wallet");
1370 x
= g_menu_model_get_item_link (G_MENU_MODEL (menu
), 3, "purse");
1371 g_assert (x
== NULL
);
1374 g_object_unref (menu
);
1382 menu
= g_menu_new ();
1383 g_menu_append (menu
, "test", "test");
1385 g_assert (g_menu_model_is_mutable (G_MENU_MODEL (menu
)));
1386 g_menu_freeze (menu
);
1387 g_assert (!g_menu_model_is_mutable (G_MENU_MODEL (menu
)));
1389 g_object_unref (menu
);
1393 test_convenience (void)
1401 sub
= g_menu_new ();
1403 g_menu_prepend (m1
, "label1", "do::something");
1404 g_menu_insert (m2
, 0, "label1", "do::something");
1406 g_menu_append (m1
, "label2", "do::somethingelse");
1407 g_menu_insert (m2
, -1, "label2", "do::somethingelse");
1409 g_menu_insert_section (m1
, 10, "label3", G_MENU_MODEL (sub
));
1410 item
= g_menu_item_new_section ("label3", G_MENU_MODEL (sub
));
1411 g_menu_insert_item (m2
, 10, item
);
1412 g_object_unref (item
);
1414 g_menu_prepend_section (m1
, "label4", G_MENU_MODEL (sub
));
1415 g_menu_insert_section (m2
, 0, "label4", G_MENU_MODEL (sub
));
1417 g_menu_append_section (m1
, "label5", G_MENU_MODEL (sub
));
1418 g_menu_insert_section (m2
, -1, "label5", G_MENU_MODEL (sub
));
1420 g_menu_insert_submenu (m1
, 5, "label6", G_MENU_MODEL (sub
));
1421 item
= g_menu_item_new_submenu ("label6", G_MENU_MODEL (sub
));
1422 g_menu_insert_item (m2
, 5, item
);
1423 g_object_unref (item
);
1425 g_menu_prepend_submenu (m1
, "label7", G_MENU_MODEL (sub
));
1426 g_menu_insert_submenu (m2
, 0, "label7", G_MENU_MODEL (sub
));
1428 g_menu_append_submenu (m1
, "label8", G_MENU_MODEL (sub
));
1429 g_menu_insert_submenu (m2
, -1, "label8", G_MENU_MODEL (sub
));
1431 assert_menus_equal (G_MENU_MODEL (m1
), G_MENU_MODEL (m2
));
1433 g_object_unref (m1
);
1434 g_object_unref (m2
);
1438 test_menuitem (void)
1447 menu
= g_menu_new ();
1448 submenu
= g_menu_new ();
1450 item
= g_menu_item_new ("label", "action");
1451 g_menu_item_set_attribute (item
, "attribute", "b", TRUE
);
1452 g_menu_item_set_link (item
, G_MENU_LINK_SUBMENU
, G_MENU_MODEL (submenu
));
1453 g_menu_append_item (menu
, item
);
1455 icon
= g_themed_icon_new ("bla");
1456 g_menu_item_set_icon (item
, icon
);
1457 g_object_unref (icon
);
1459 g_assert (g_menu_item_get_attribute (item
, "attribute", "b", &b
));
1462 g_menu_item_set_action_and_target (item
, "action", "(bs)", TRUE
, "string");
1463 g_assert (g_menu_item_get_attribute (item
, "target", "(bs)", &b
, &s
));
1465 g_assert_cmpstr (s
, ==, "string");
1468 g_object_unref (item
);
1470 item
= g_menu_item_new_from_model (G_MENU_MODEL (menu
), 0);
1471 assert_menuitem_equal (item
, G_MENU_MODEL (menu
), 0);
1472 g_object_unref (item
);
1474 g_object_unref (menu
);
1475 g_object_unref (submenu
);
1480 main (int argc
, char **argv
)
1484 g_test_init (&argc
, &argv
, NULL
);
1488 g_test_add_func ("/gmenu/equality", test_equality
);
1489 g_test_add_func ("/gmenu/random", test_random
);
1490 g_test_add_func ("/gmenu/dbus/roundtrip", test_dbus_roundtrip
);
1491 g_test_add_func ("/gmenu/dbus/subscriptions", test_dbus_subscriptions
);
1492 g_test_add_func ("/gmenu/dbus/threaded", test_dbus_threaded
);
1493 g_test_add_func ("/gmenu/dbus/peer/roundtrip", test_dbus_peer_roundtrip
);
1494 g_test_add_func ("/gmenu/dbus/peer/subscriptions", test_dbus_peer_subscriptions
);
1495 g_test_add_func ("/gmenu/attributes", test_attributes
);
1496 g_test_add_func ("/gmenu/attributes/iterate", test_attribute_iter
);
1497 g_test_add_func ("/gmenu/links", test_links
);
1498 g_test_add_func ("/gmenu/mutable", test_mutable
);
1499 g_test_add_func ("/gmenu/convenience", test_convenience
);
1500 g_test_add_func ("/gmenu/menuitem", test_menuitem
);
1502 ret
= g_test_run ();
1504 session_bus_down ();
1508 /* vim:set foldmethod=marker: */