1 /* GLib testing framework examples and tests
3 * Copyright (C) 2008-2010 Red Hat, Inc.
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General
16 * Public License along with this library; if not, see <http://www.gnu.org/licenses/>.
18 * Author: David Zeuthen <davidz@redhat.com>
25 #include "gdbus-tests.h"
27 /* all tests rely on a shared mainloop */
28 static GMainLoop
*loop
= NULL
;
30 static GDBusConnection
*c
= NULL
;
32 /* ---------------------------------------------------------------------------------------------------- */
33 /* Test that we can export objects, the hierarchy is correct and the right handlers are invoked */
34 /* ---------------------------------------------------------------------------------------------------- */
36 static const GDBusArgInfo foo_method1_in_args
=
43 static const GDBusArgInfo
* const foo_method1_in_arg_pointers
[] = {&foo_method1_in_args
, NULL
};
45 static const GDBusArgInfo foo_method1_out_args
=
52 static const GDBusArgInfo
* const foo_method1_out_arg_pointers
[] = {&foo_method1_out_args
, NULL
};
54 static const GDBusMethodInfo foo_method_info_method1
=
58 (GDBusArgInfo
**) &foo_method1_in_arg_pointers
,
59 (GDBusArgInfo
**) &foo_method1_out_arg_pointers
,
62 static const GDBusMethodInfo foo_method_info_method2
=
70 static const GDBusMethodInfo
* const foo_method_info_pointers
[] = {&foo_method_info_method1
, &foo_method_info_method2
, NULL
};
72 static const GDBusSignalInfo foo_signal_info
=
79 static const GDBusSignalInfo
* const foo_signal_info_pointers
[] = {&foo_signal_info
, NULL
};
81 static const GDBusPropertyInfo foo_property_info
[] =
87 G_DBUS_PROPERTY_INFO_FLAGS_READABLE
| G_DBUS_PROPERTY_INFO_FLAGS_WRITABLE
,
94 G_DBUS_PROPERTY_INFO_FLAGS_READABLE
,
101 G_DBUS_PROPERTY_INFO_FLAGS_WRITABLE
,
105 static const GDBusPropertyInfo
* const foo_property_info_pointers
[] =
107 &foo_property_info
[0],
108 &foo_property_info
[1],
109 &foo_property_info
[2],
113 static const GDBusInterfaceInfo foo_interface_info
=
117 (GDBusMethodInfo
**) &foo_method_info_pointers
,
118 (GDBusSignalInfo
**) &foo_signal_info_pointers
,
119 (GDBusPropertyInfo
**)&foo_property_info_pointers
,
123 /* Foo2 is just Foo without the properties */
124 static const GDBusInterfaceInfo foo2_interface_info
=
128 (GDBusMethodInfo
**) &foo_method_info_pointers
,
129 (GDBusSignalInfo
**) &foo_signal_info_pointers
,
133 foo_method_call (GDBusConnection
*connection
,
135 const gchar
*object_path
,
136 const gchar
*interface_name
,
137 const gchar
*method_name
,
138 GVariant
*parameters
,
139 GDBusMethodInvocation
*invocation
,
142 if (g_strcmp0 (method_name
, "Method1") == 0)
146 g_variant_get (parameters
, "(&s)", &input
);
147 output
= g_strdup_printf ("You passed the string '%s'. Jolly good!", input
);
148 g_dbus_method_invocation_return_value (invocation
, g_variant_new ("(s)", output
));
153 g_dbus_method_invocation_return_dbus_error (invocation
,
154 "org.example.SomeError",
155 "How do you like them apples, buddy!");
160 foo_get_property (GDBusConnection
*connection
,
162 const gchar
*object_path
,
163 const gchar
*interface_name
,
164 const gchar
*property_name
,
170 s
= g_strdup_printf ("Property '%s' Is What It Is!", property_name
);
171 ret
= g_variant_new_string (s
);
177 foo_set_property (GDBusConnection
*connection
,
179 const gchar
*object_path
,
180 const gchar
*interface_name
,
181 const gchar
*property_name
,
187 s
= g_variant_print (value
, TRUE
);
190 G_DBUS_ERROR_SPAWN_FILE_INVALID
,
191 "Returning some error instead of writing the value '%s' to the property '%s'",
197 static const GDBusInterfaceVTable foo_vtable
=
204 /* -------------------- */
206 static const GDBusMethodInfo bar_method_info
[] =
223 static const GDBusMethodInfo
* const bar_method_info_pointers
[] = {&bar_method_info
[0], &bar_method_info
[1], NULL
};
225 static const GDBusSignalInfo bar_signal_info
[] =
234 static const GDBusSignalInfo
* const bar_signal_info_pointers
[] = {&bar_signal_info
[0], NULL
};
236 static const GDBusPropertyInfo bar_property_info
[] =
242 G_DBUS_PROPERTY_INFO_FLAGS_READABLE
,
246 static const GDBusPropertyInfo
* const bar_property_info_pointers
[] = {&bar_property_info
[0], NULL
};
248 static const GDBusInterfaceInfo bar_interface_info
=
252 (GDBusMethodInfo
**) bar_method_info_pointers
,
253 (GDBusSignalInfo
**) bar_signal_info_pointers
,
254 (GDBusPropertyInfo
**) bar_property_info_pointers
,
258 /* -------------------- */
260 static const GDBusMethodInfo dyna_method_info
[] =
270 static const GDBusMethodInfo
* const dyna_method_info_pointers
[] = {&dyna_method_info
[0], NULL
};
272 static const GDBusInterfaceInfo dyna_interface_info
=
276 (GDBusMethodInfo
**) dyna_method_info_pointers
,
277 NULL
, /* no signals */
278 NULL
, /* no properties */
283 dyna_cyber (GDBusConnection
*connection
,
285 const gchar
*object_path
,
286 const gchar
*interface_name
,
287 const gchar
*method_name
,
288 GVariant
*parameters
,
289 GDBusMethodInvocation
*invocation
,
292 GPtrArray
*data
= user_data
;
296 node_name
= strrchr (object_path
, '/') + 1;
298 /* Add new node if it is not already known */
299 for (n
= 0; n
< data
->len
; n
++)
301 if (g_strcmp0 (g_ptr_array_index (data
, n
), node_name
) == 0)
304 g_ptr_array_add (data
, g_strdup(node_name
));
307 g_dbus_method_invocation_return_value (invocation
, NULL
);
310 static const GDBusInterfaceVTable dyna_interface_vtable
=
317 /* ---------------------------------------------------------------------------------------------------- */
320 introspect_callback (GDBusProxy
*proxy
,
324 gchar
**xml_data
= user_data
;
329 result
= g_dbus_proxy_call_finish (proxy
,
332 g_assert_no_error (error
);
333 g_assert (result
!= NULL
);
334 g_variant_get (result
, "(s)", xml_data
);
335 g_variant_unref (result
);
337 g_main_loop_quit (loop
);
341 get_nodes_at (GDBusConnection
*c
,
342 const gchar
*object_path
)
348 GDBusNodeInfo
*node_info
;
352 proxy
= g_dbus_proxy_new_sync (c
,
353 G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES
|
354 G_DBUS_PROXY_FLAGS_DO_NOT_CONNECT_SIGNALS
,
356 g_dbus_connection_get_unique_name (c
),
358 "org.freedesktop.DBus.Introspectable",
361 g_assert_no_error (error
);
362 g_assert (proxy
!= NULL
);
364 /* do this async to avoid libdbus-1 deadlocks */
366 g_dbus_proxy_call (proxy
,
369 G_DBUS_CALL_FLAGS_NONE
,
372 (GAsyncReadyCallback
) introspect_callback
,
374 g_main_loop_run (loop
);
375 g_assert (xml_data
!= NULL
);
377 node_info
= g_dbus_node_info_new_for_xml (xml_data
, &error
);
378 g_assert_no_error (error
);
379 g_assert (node_info
!= NULL
);
381 p
= g_ptr_array_new ();
382 for (n
= 0; node_info
->nodes
!= NULL
&& node_info
->nodes
[n
] != NULL
; n
++)
384 const GDBusNodeInfo
*sub_node_info
= node_info
->nodes
[n
];
385 g_ptr_array_add (p
, g_strdup (sub_node_info
->path
));
387 g_ptr_array_add (p
, NULL
);
389 g_object_unref (proxy
);
391 g_dbus_node_info_unref (node_info
);
393 return (gchar
**) g_ptr_array_free (p
, FALSE
);
397 has_interface (GDBusConnection
*c
,
398 const gchar
*object_path
,
399 const gchar
*interface_name
)
404 GDBusNodeInfo
*node_info
;
408 proxy
= g_dbus_proxy_new_sync (c
,
409 G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES
|
410 G_DBUS_PROXY_FLAGS_DO_NOT_CONNECT_SIGNALS
,
412 g_dbus_connection_get_unique_name (c
),
414 "org.freedesktop.DBus.Introspectable",
417 g_assert_no_error (error
);
418 g_assert (proxy
!= NULL
);
420 /* do this async to avoid libdbus-1 deadlocks */
422 g_dbus_proxy_call (proxy
,
425 G_DBUS_CALL_FLAGS_NONE
,
428 (GAsyncReadyCallback
) introspect_callback
,
430 g_main_loop_run (loop
);
431 g_assert (xml_data
!= NULL
);
433 node_info
= g_dbus_node_info_new_for_xml (xml_data
, &error
);
434 g_assert_no_error (error
);
435 g_assert (node_info
!= NULL
);
437 ret
= (g_dbus_node_info_lookup_interface (node_info
, interface_name
) != NULL
);
439 g_object_unref (proxy
);
441 g_dbus_node_info_unref (node_info
);
447 count_interfaces (GDBusConnection
*c
,
448 const gchar
*object_path
)
453 GDBusNodeInfo
*node_info
;
457 proxy
= g_dbus_proxy_new_sync (c
,
458 G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES
|
459 G_DBUS_PROXY_FLAGS_DO_NOT_CONNECT_SIGNALS
,
461 g_dbus_connection_get_unique_name (c
),
463 "org.freedesktop.DBus.Introspectable",
466 g_assert_no_error (error
);
467 g_assert (proxy
!= NULL
);
469 /* do this async to avoid libdbus-1 deadlocks */
471 g_dbus_proxy_call (proxy
,
474 G_DBUS_CALL_FLAGS_NONE
,
477 (GAsyncReadyCallback
) introspect_callback
,
479 g_main_loop_run (loop
);
480 g_assert (xml_data
!= NULL
);
482 node_info
= g_dbus_node_info_new_for_xml (xml_data
, &error
);
483 g_assert_no_error (error
);
484 g_assert (node_info
!= NULL
);
487 while (node_info
->interfaces
!= NULL
&& node_info
->interfaces
[ret
] != NULL
)
490 g_object_unref (proxy
);
492 g_dbus_node_info_unref (node_info
);
498 dyna_create_callback (GDBusProxy
*proxy
,
506 result
= g_dbus_proxy_call_finish (proxy
,
509 g_assert_no_error (error
);
510 g_assert (result
!= NULL
);
511 g_variant_unref (result
);
513 g_main_loop_quit (loop
);
516 /* Dynamically create @object_name under /foo/dyna */
518 dyna_create (GDBusConnection
*c
,
519 const gchar
*object_name
)
525 object_path
= g_strconcat ("/foo/dyna/", object_name
, NULL
);
528 proxy
= g_dbus_proxy_new_sync (c
,
529 G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES
|
530 G_DBUS_PROXY_FLAGS_DO_NOT_CONNECT_SIGNALS
,
532 g_dbus_connection_get_unique_name (c
),
537 g_assert_no_error (error
);
538 g_assert (proxy
!= NULL
);
540 /* do this async to avoid libdbus-1 deadlocks */
541 g_dbus_proxy_call (proxy
,
543 g_variant_new ("()"),
544 G_DBUS_CALL_FLAGS_NONE
,
547 (GAsyncReadyCallback
) dyna_create_callback
,
549 g_main_loop_run (loop
);
551 g_assert_no_error (error
);
553 g_object_unref (proxy
);
554 g_free (object_path
);
561 guint num_unregistered_calls
;
562 guint num_unregistered_subtree_calls
;
563 guint num_subtree_nodes
;
564 } ObjectRegistrationData
;
567 on_object_unregistered (gpointer user_data
)
569 ObjectRegistrationData
*data
= user_data
;
571 data
->num_unregistered_calls
++;
575 on_subtree_unregistered (gpointer user_data
)
577 ObjectRegistrationData
*data
= user_data
;
579 data
->num_unregistered_subtree_calls
++;
583 _g_strv_has_string (const gchar
* const * haystack
,
588 for (n
= 0; haystack
!= NULL
&& haystack
[n
] != NULL
; n
++)
590 if (g_strcmp0 (haystack
[n
], needle
) == 0)
596 /* -------------------- */
599 subtree_enumerate (GDBusConnection
*connection
,
601 const gchar
*object_path
,
604 ObjectRegistrationData
*data
= user_data
;
609 p
= g_ptr_array_new ();
611 for (n
= 0; n
< data
->num_subtree_nodes
; n
++)
613 g_ptr_array_add (p
, g_strdup_printf ("vp%d", n
));
614 g_ptr_array_add (p
, g_strdup_printf ("evp%d", n
));
616 g_ptr_array_add (p
, NULL
);
618 nodes
= (gchar
**) g_ptr_array_free (p
, FALSE
);
623 /* Only allows certain objects, and aborts on unknowns */
624 static GDBusInterfaceInfo
**
625 subtree_introspect (GDBusConnection
*connection
,
627 const gchar
*object_path
,
631 const GDBusInterfaceInfo
*interfaces
[2] = {
632 NULL
/* filled in below */, NULL
635 /* VPs implement the Foo interface, EVPs implement the Bar interface. The root
636 * does not implement any interfaces
642 else if (g_str_has_prefix (node
, "vp"))
644 interfaces
[0] = &foo_interface_info
;
646 else if (g_str_has_prefix (node
, "evp"))
648 interfaces
[0] = &bar_interface_info
;
652 g_assert_not_reached ();
655 return g_memdup (interfaces
, 2 * sizeof (void *));
658 static const GDBusInterfaceVTable
*
659 subtree_dispatch (GDBusConnection
*connection
,
661 const gchar
*object_path
,
662 const gchar
*interface_name
,
664 gpointer
*out_user_data
,
667 if (g_strcmp0 (interface_name
, "org.example.Foo") == 0)
673 static const GDBusSubtreeVTable subtree_vtable
=
680 /* -------------------- */
683 dynamic_subtree_enumerate (GDBusConnection
*connection
,
685 const gchar
*object_path
,
688 GPtrArray
*data
= user_data
;
689 gchar
**nodes
= g_new (gchar
*, data
->len
+ 1);
692 for (n
= 0; n
< data
->len
; n
++)
694 nodes
[n
] = g_strdup (g_ptr_array_index (data
, n
));
696 nodes
[data
->len
] = NULL
;
701 /* Allow all objects to be introspected */
702 static GDBusInterfaceInfo
**
703 dynamic_subtree_introspect (GDBusConnection
*connection
,
705 const gchar
*object_path
,
709 const GDBusInterfaceInfo
*interfaces
[2] = { &dyna_interface_info
, NULL
};
711 return g_memdup (interfaces
, 2 * sizeof (void *));
714 static const GDBusInterfaceVTable
*
715 dynamic_subtree_dispatch (GDBusConnection
*connection
,
717 const gchar
*object_path
,
718 const gchar
*interface_name
,
720 gpointer
*out_user_data
,
723 *out_user_data
= user_data
;
724 return &dyna_interface_vtable
;
727 static const GDBusSubtreeVTable dynamic_subtree_vtable
=
729 dynamic_subtree_enumerate
,
730 dynamic_subtree_introspect
,
731 dynamic_subtree_dispatch
734 /* -------------------- */
738 const gchar
*object_path
;
739 gboolean check_remote_errors
;
740 } TestDispatchThreadFuncArgs
;
743 test_dispatch_thread_func (gpointer user_data
)
745 TestDispatchThreadFuncArgs
*args
= user_data
;
746 const gchar
*object_path
= args
->object_path
;
747 GDBusProxy
*foo_proxy
;
752 const gchar
*value_str
;
754 foo_proxy
= g_dbus_proxy_new_sync (c
,
755 G_DBUS_PROXY_FLAGS_DO_NOT_CONNECT_SIGNALS
|
756 G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES
,
758 g_dbus_connection_get_unique_name (c
),
763 g_assert (foo_proxy
!= NULL
);
765 /* generic interfaces */
767 value
= g_dbus_proxy_call_sync (foo_proxy
,
768 "org.freedesktop.DBus.Peer.Ping",
770 G_DBUS_CALL_FLAGS_NONE
,
774 g_assert_no_error (error
);
775 g_assert (value
!= NULL
);
776 g_variant_unref (value
);
780 value
= g_dbus_proxy_call_sync (foo_proxy
,
782 g_variant_new ("(s)", "winwinwin"),
783 G_DBUS_CALL_FLAGS_NONE
,
787 g_assert_no_error (error
);
788 g_assert (value
!= NULL
);
789 g_assert (g_variant_is_of_type (value
, G_VARIANT_TYPE ("(s)")));
790 g_variant_get (value
, "(&s)", &value_str
);
791 g_assert_cmpstr (value_str
, ==, "You passed the string 'winwinwin'. Jolly good!");
792 g_variant_unref (value
);
795 value
= g_dbus_proxy_call_sync (foo_proxy
,
798 G_DBUS_CALL_FLAGS_NONE
,
802 g_assert_error (error
, G_IO_ERROR
, G_IO_ERROR_DBUS_ERROR
);
803 g_assert_cmpstr (error
->message
, ==, "GDBus.Error:org.example.SomeError: How do you like them apples, buddy!");
804 g_error_free (error
);
805 g_assert (value
== NULL
);
808 value
= g_dbus_proxy_call_sync (foo_proxy
,
810 g_variant_new ("(s)", "failfailfail"),
811 G_DBUS_CALL_FLAGS_NONE
,
815 g_assert_error (error
, G_DBUS_ERROR
, G_DBUS_ERROR_INVALID_ARGS
);
816 g_assert_cmpstr (error
->message
, ==, "GDBus.Error:org.freedesktop.DBus.Error.InvalidArgs: Type of message, '(s)', does not match expected type '()'");
817 g_error_free (error
);
818 g_assert (value
== NULL
);
821 value
= g_dbus_proxy_call_sync (foo_proxy
,
824 G_DBUS_CALL_FLAGS_NONE
,
828 g_assert_error (error
, G_DBUS_ERROR
, G_DBUS_ERROR_UNKNOWN_METHOD
);
829 g_assert_cmpstr (error
->message
, ==, "GDBus.Error:org.freedesktop.DBus.Error.UnknownMethod: No such method 'NonExistantMethod'");
830 g_error_free (error
);
831 g_assert (value
== NULL
);
834 value
= g_dbus_proxy_call_sync (foo_proxy
,
835 "org.example.FooXYZ.NonExistant",
837 G_DBUS_CALL_FLAGS_NONE
,
841 g_assert_error (error
, G_DBUS_ERROR
, G_DBUS_ERROR_UNKNOWN_METHOD
);
842 g_error_free (error
);
843 g_assert (value
== NULL
);
845 /* user properties */
847 value
= g_dbus_proxy_call_sync (foo_proxy
,
848 "org.freedesktop.DBus.Properties.Get",
849 g_variant_new ("(ss)",
852 G_DBUS_CALL_FLAGS_NONE
,
856 g_assert_no_error (error
);
857 g_assert (value
!= NULL
);
858 g_assert (g_variant_is_of_type (value
, G_VARIANT_TYPE ("(v)")));
859 g_variant_get (value
, "(v)", &inner
);
860 g_assert (g_variant_is_of_type (inner
, G_VARIANT_TYPE_STRING
));
861 g_assert_cmpstr (g_variant_get_string (inner
, NULL
), ==, "Property 'PropertyUno' Is What It Is!");
862 g_variant_unref (value
);
863 g_variant_unref (inner
);
866 value
= g_dbus_proxy_call_sync (foo_proxy
,
867 "org.freedesktop.DBus.Properties.Get",
868 g_variant_new ("(ss)",
871 G_DBUS_CALL_FLAGS_NONE
,
875 g_assert (value
== NULL
);
876 g_assert_error (error
, G_DBUS_ERROR
, G_DBUS_ERROR_INVALID_ARGS
);
877 g_assert_cmpstr (error
->message
, ==, "GDBus.Error:org.freedesktop.DBus.Error.InvalidArgs: No such property 'ThisDoesntExist'");
878 g_error_free (error
);
881 value
= g_dbus_proxy_call_sync (foo_proxy
,
882 "org.freedesktop.DBus.Properties.Get",
883 g_variant_new ("(ss)",
886 G_DBUS_CALL_FLAGS_NONE
,
890 g_assert (value
== NULL
);
891 g_assert_error (error
, G_DBUS_ERROR
, G_DBUS_ERROR_INVALID_ARGS
);
892 g_assert_cmpstr (error
->message
, ==, "GDBus.Error:org.freedesktop.DBus.Error.InvalidArgs: Property 'NotReadable' is not readable");
893 g_error_free (error
);
896 value
= g_dbus_proxy_call_sync (foo_proxy
,
897 "org.freedesktop.DBus.Properties.Set",
898 g_variant_new ("(ssv)",
901 g_variant_new_string ("But Writable you are!")),
902 G_DBUS_CALL_FLAGS_NONE
,
906 g_assert (value
== NULL
);
907 if (args
->check_remote_errors
)
909 /* _with_closures variant doesn't support customizing error data. */
910 g_assert_error (error
, G_DBUS_ERROR
, G_DBUS_ERROR_SPAWN_FILE_INVALID
);
911 g_assert_cmpstr (error
->message
, ==, "GDBus.Error:org.freedesktop.DBus.Error.Spawn.FileInvalid: Returning some error instead of writing the value 'NotReadable' to the property ''But Writable you are!''");
913 g_assert (error
!= NULL
&& error
->domain
== G_DBUS_ERROR
);
914 g_error_free (error
);
917 value
= g_dbus_proxy_call_sync (foo_proxy
,
918 "org.freedesktop.DBus.Properties.Set",
919 g_variant_new ("(ssv)",
922 g_variant_new_uint32 (42)),
923 G_DBUS_CALL_FLAGS_NONE
,
927 g_assert (value
== NULL
);
928 g_assert_error (error
, G_DBUS_ERROR
, G_DBUS_ERROR_INVALID_ARGS
);
929 g_assert_cmpstr (error
->message
, ==, "GDBus.Error:org.freedesktop.DBus.Error.InvalidArgs: Property 'NotWritable' is not writable");
930 g_error_free (error
);
933 value
= g_dbus_proxy_call_sync (foo_proxy
,
934 "org.freedesktop.DBus.Properties.GetAll",
935 g_variant_new ("(s)",
937 G_DBUS_CALL_FLAGS_NONE
,
941 g_assert_no_error (error
);
942 g_assert (value
!= NULL
);
943 g_assert (g_variant_is_of_type (value
, G_VARIANT_TYPE ("(a{sv})")));
944 s
= g_variant_print (value
, TRUE
);
945 g_assert_cmpstr (s
, ==, "({'PropertyUno': <\"Property 'PropertyUno' Is What It Is!\">, 'NotWritable': <\"Property 'NotWritable' Is What It Is!\">},)");
947 g_variant_unref (value
);
949 g_object_unref (foo_proxy
);
951 g_main_loop_quit (loop
);
956 test_dispatch (const gchar
*object_path
,
957 gboolean check_remote_errors
)
961 TestDispatchThreadFuncArgs args
= {object_path
, check_remote_errors
};
963 /* run this in a thread to avoid deadlocks */
964 thread
= g_thread_new ("test_dispatch",
965 test_dispatch_thread_func
,
967 g_main_loop_run (loop
);
968 g_thread_join (thread
);
972 test_object_registration (void)
975 ObjectRegistrationData data
;
976 GPtrArray
*dyna_data
;
978 guint boss_foo_reg_id
;
979 guint boss_bar_reg_id
;
980 guint worker1_foo_reg_id
;
981 guint worker1p1_foo_reg_id
;
982 guint worker2_bar_reg_id
;
983 guint intern1_foo_reg_id
;
984 guint intern2_bar_reg_id
;
985 guint intern2_foo_reg_id
;
986 guint intern3_bar_reg_id
;
987 guint registration_id
;
988 guint subtree_registration_id
;
989 guint non_subtree_object_path_foo_reg_id
;
990 guint non_subtree_object_path_bar_reg_id
;
991 guint dyna_subtree_registration_id
;
992 guint num_successful_registrations
;
994 data
.num_unregistered_calls
= 0;
995 data
.num_unregistered_subtree_calls
= 0;
996 data
.num_subtree_nodes
= 0;
998 num_successful_registrations
= 0;
1001 c
= g_bus_get_sync (G_BUS_TYPE_SESSION
, NULL
, &error
);
1002 g_assert_no_error (error
);
1003 g_assert (c
!= NULL
);
1005 registration_id
= g_dbus_connection_register_object (c
,
1007 (GDBusInterfaceInfo
*) &foo_interface_info
,
1010 on_object_unregistered
,
1012 g_assert_no_error (error
);
1013 g_assert (registration_id
> 0);
1014 boss_foo_reg_id
= registration_id
;
1015 num_successful_registrations
++;
1017 registration_id
= g_dbus_connection_register_object (c
,
1019 (GDBusInterfaceInfo
*) &bar_interface_info
,
1022 on_object_unregistered
,
1024 g_assert_no_error (error
);
1025 g_assert (registration_id
> 0);
1026 boss_bar_reg_id
= registration_id
;
1027 num_successful_registrations
++;
1029 registration_id
= g_dbus_connection_register_object (c
,
1030 "/foo/boss/worker1",
1031 (GDBusInterfaceInfo
*) &foo_interface_info
,
1034 on_object_unregistered
,
1036 g_assert_no_error (error
);
1037 g_assert (registration_id
> 0);
1038 worker1_foo_reg_id
= registration_id
;
1039 num_successful_registrations
++;
1041 registration_id
= g_dbus_connection_register_object (c
,
1042 "/foo/boss/worker1p1",
1043 (GDBusInterfaceInfo
*) &foo_interface_info
,
1046 on_object_unregistered
,
1048 g_assert_no_error (error
);
1049 g_assert (registration_id
> 0);
1050 worker1p1_foo_reg_id
= registration_id
;
1051 num_successful_registrations
++;
1053 registration_id
= g_dbus_connection_register_object (c
,
1054 "/foo/boss/worker2",
1055 (GDBusInterfaceInfo
*) &bar_interface_info
,
1058 on_object_unregistered
,
1060 g_assert_no_error (error
);
1061 g_assert (registration_id
> 0);
1062 worker2_bar_reg_id
= registration_id
;
1063 num_successful_registrations
++;
1065 registration_id
= g_dbus_connection_register_object (c
,
1066 "/foo/boss/interns/intern1",
1067 (GDBusInterfaceInfo
*) &foo_interface_info
,
1070 on_object_unregistered
,
1072 g_assert_no_error (error
);
1073 g_assert (registration_id
> 0);
1074 intern1_foo_reg_id
= registration_id
;
1075 num_successful_registrations
++;
1077 /* ... and try again at another path */
1078 registration_id
= g_dbus_connection_register_object (c
,
1079 "/foo/boss/interns/intern2",
1080 (GDBusInterfaceInfo
*) &bar_interface_info
,
1083 on_object_unregistered
,
1085 g_assert_no_error (error
);
1086 g_assert (registration_id
> 0);
1087 intern2_bar_reg_id
= registration_id
;
1088 num_successful_registrations
++;
1090 /* register at the same path/interface - this should fail */
1091 registration_id
= g_dbus_connection_register_object (c
,
1092 "/foo/boss/interns/intern2",
1093 (GDBusInterfaceInfo
*) &bar_interface_info
,
1096 on_object_unregistered
,
1098 g_assert_error (error
, G_IO_ERROR
, G_IO_ERROR_EXISTS
);
1099 g_assert (!g_dbus_error_is_remote_error (error
));
1100 g_error_free (error
);
1102 g_assert (registration_id
== 0);
1104 /* register at different interface - shouldn't fail */
1105 registration_id
= g_dbus_connection_register_object (c
,
1106 "/foo/boss/interns/intern2",
1107 (GDBusInterfaceInfo
*) &foo_interface_info
,
1110 on_object_unregistered
,
1112 g_assert_no_error (error
);
1113 g_assert (registration_id
> 0);
1114 intern2_foo_reg_id
= registration_id
;
1115 num_successful_registrations
++;
1117 /* unregister it via the id */
1118 g_assert (g_dbus_connection_unregister_object (c
, registration_id
));
1119 g_main_context_iteration (NULL
, FALSE
);
1120 g_assert_cmpint (data
.num_unregistered_calls
, ==, 1);
1121 intern2_foo_reg_id
= 0;
1123 /* register it back */
1124 registration_id
= g_dbus_connection_register_object (c
,
1125 "/foo/boss/interns/intern2",
1126 (GDBusInterfaceInfo
*) &foo_interface_info
,
1129 on_object_unregistered
,
1131 g_assert_no_error (error
);
1132 g_assert (registration_id
> 0);
1133 intern2_foo_reg_id
= registration_id
;
1134 num_successful_registrations
++;
1136 registration_id
= g_dbus_connection_register_object (c
,
1137 "/foo/boss/interns/intern3",
1138 (GDBusInterfaceInfo
*) &bar_interface_info
,
1141 on_object_unregistered
,
1143 g_assert_no_error (error
);
1144 g_assert (registration_id
> 0);
1145 intern3_bar_reg_id
= registration_id
;
1146 num_successful_registrations
++;
1148 /* now register a whole subtree at /foo/boss/executives */
1149 subtree_registration_id
= g_dbus_connection_register_subtree (c
,
1150 "/foo/boss/executives",
1152 G_DBUS_SUBTREE_FLAGS_NONE
,
1154 on_subtree_unregistered
,
1156 g_assert_no_error (error
);
1157 g_assert (subtree_registration_id
> 0);
1158 /* try registering it again.. this should fail */
1159 registration_id
= g_dbus_connection_register_subtree (c
,
1160 "/foo/boss/executives",
1162 G_DBUS_SUBTREE_FLAGS_NONE
,
1164 on_subtree_unregistered
,
1166 g_assert_error (error
, G_IO_ERROR
, G_IO_ERROR_EXISTS
);
1167 g_assert (!g_dbus_error_is_remote_error (error
));
1168 g_error_free (error
);
1170 g_assert (registration_id
== 0);
1172 /* unregister it, then register it again */
1173 g_assert_cmpint (data
.num_unregistered_subtree_calls
, ==, 0);
1174 g_assert (g_dbus_connection_unregister_subtree (c
, subtree_registration_id
));
1175 g_main_context_iteration (NULL
, FALSE
);
1176 g_assert_cmpint (data
.num_unregistered_subtree_calls
, ==, 1);
1177 subtree_registration_id
= g_dbus_connection_register_subtree (c
,
1178 "/foo/boss/executives",
1180 G_DBUS_SUBTREE_FLAGS_NONE
,
1182 on_subtree_unregistered
,
1184 g_assert_no_error (error
);
1185 g_assert (subtree_registration_id
> 0);
1187 /* try to register something under /foo/boss/executives - this should work
1188 * because registered subtrees and registered objects can coexist.
1190 * Make the exported object implement *two* interfaces so we can check
1191 * that the right introspection handler is invoked.
1193 registration_id
= g_dbus_connection_register_object (c
,
1194 "/foo/boss/executives/non_subtree_object",
1195 (GDBusInterfaceInfo
*) &bar_interface_info
,
1198 on_object_unregistered
,
1200 g_assert_no_error (error
);
1201 g_assert (registration_id
> 0);
1202 non_subtree_object_path_bar_reg_id
= registration_id
;
1203 num_successful_registrations
++;
1204 registration_id
= g_dbus_connection_register_object (c
,
1205 "/foo/boss/executives/non_subtree_object",
1206 (GDBusInterfaceInfo
*) &foo_interface_info
,
1209 on_object_unregistered
,
1211 g_assert_no_error (error
);
1212 g_assert (registration_id
> 0);
1213 non_subtree_object_path_foo_reg_id
= registration_id
;
1214 num_successful_registrations
++;
1216 /* now register a dynamic subtree, spawning objects as they are called */
1217 dyna_data
= g_ptr_array_new_with_free_func (g_free
);
1218 dyna_subtree_registration_id
= g_dbus_connection_register_subtree (c
,
1220 &dynamic_subtree_vtable
,
1221 G_DBUS_SUBTREE_FLAGS_DISPATCH_TO_UNENUMERATED_NODES
,
1223 (GDestroyNotify
)g_ptr_array_unref
,
1225 g_assert_no_error (error
);
1226 g_assert (dyna_subtree_registration_id
> 0);
1228 /* First assert that we have no nodes in the dynamic subtree */
1229 nodes
= get_nodes_at (c
, "/foo/dyna");
1230 g_assert (nodes
!= NULL
);
1231 g_assert_cmpint (g_strv_length (nodes
), ==, 0);
1233 g_assert_cmpint (count_interfaces (c
, "/foo/dyna"), ==, 4);
1235 /* Install three nodes in the dynamic subtree via the dyna_data backdoor and
1236 * assert that they show up correctly in the introspection data */
1237 g_ptr_array_add (dyna_data
, g_strdup ("lol"));
1238 g_ptr_array_add (dyna_data
, g_strdup ("cat"));
1239 g_ptr_array_add (dyna_data
, g_strdup ("cheezburger"));
1240 nodes
= get_nodes_at (c
, "/foo/dyna");
1241 g_assert (nodes
!= NULL
);
1242 g_assert_cmpint (g_strv_length (nodes
), ==, 3);
1243 g_assert_cmpstr (nodes
[0], ==, "lol");
1244 g_assert_cmpstr (nodes
[1], ==, "cat");
1245 g_assert_cmpstr (nodes
[2], ==, "cheezburger");
1247 g_assert_cmpint (count_interfaces (c
, "/foo/dyna/lol"), ==, 4);
1248 g_assert_cmpint (count_interfaces (c
, "/foo/dyna/cat"), ==, 4);
1249 g_assert_cmpint (count_interfaces (c
, "/foo/dyna/cheezburger"), ==, 4);
1251 /* Call a non-existing object path and assert that it has been created */
1252 dyna_create (c
, "dynamicallycreated");
1253 nodes
= get_nodes_at (c
, "/foo/dyna");
1254 g_assert (nodes
!= NULL
);
1255 g_assert_cmpint (g_strv_length (nodes
), ==, 4);
1256 g_assert_cmpstr (nodes
[0], ==, "lol");
1257 g_assert_cmpstr (nodes
[1], ==, "cat");
1258 g_assert_cmpstr (nodes
[2], ==, "cheezburger");
1259 g_assert_cmpstr (nodes
[3], ==, "dynamicallycreated");
1261 g_assert_cmpint (count_interfaces (c
, "/foo/dyna/dynamicallycreated"), ==, 4);
1263 /* now check that the object hierarachy is properly generated... yes, it's a bit
1264 * perverse that we round-trip to the bus to introspect ourselves ;-)
1266 nodes
= get_nodes_at (c
, "/");
1267 g_assert (nodes
!= NULL
);
1268 g_assert_cmpint (g_strv_length (nodes
), ==, 1);
1269 g_assert_cmpstr (nodes
[0], ==, "foo");
1271 g_assert_cmpint (count_interfaces (c
, "/"), ==, 0);
1273 nodes
= get_nodes_at (c
, "/foo");
1274 g_assert (nodes
!= NULL
);
1275 g_assert_cmpint (g_strv_length (nodes
), ==, 2);
1276 g_assert_cmpstr (nodes
[0], ==, "boss");
1277 g_assert_cmpstr (nodes
[1], ==, "dyna");
1279 g_assert_cmpint (count_interfaces (c
, "/foo"), ==, 0);
1281 nodes
= get_nodes_at (c
, "/foo/boss");
1282 g_assert (nodes
!= NULL
);
1283 g_assert_cmpint (g_strv_length (nodes
), ==, 5);
1284 g_assert (_g_strv_has_string ((const gchar
* const *) nodes
, "worker1"));
1285 g_assert (_g_strv_has_string ((const gchar
* const *) nodes
, "worker1p1"));
1286 g_assert (_g_strv_has_string ((const gchar
* const *) nodes
, "worker2"));
1287 g_assert (_g_strv_has_string ((const gchar
* const *) nodes
, "interns"));
1288 g_assert (_g_strv_has_string ((const gchar
* const *) nodes
, "executives"));
1290 /* any registered object always implement org.freedesktop.DBus.[Peer,Introspectable,Properties] */
1291 g_assert_cmpint (count_interfaces (c
, "/foo/boss"), ==, 5);
1292 g_assert (has_interface (c
, "/foo/boss", foo_interface_info
.name
));
1293 g_assert (has_interface (c
, "/foo/boss", bar_interface_info
.name
));
1295 /* check subtree nodes - we should have only non_subtree_object in /foo/boss/executives
1296 * because data.num_subtree_nodes is 0
1298 nodes
= get_nodes_at (c
, "/foo/boss/executives");
1299 g_assert (nodes
!= NULL
);
1300 g_assert (_g_strv_has_string ((const gchar
* const *) nodes
, "non_subtree_object"));
1301 g_assert_cmpint (g_strv_length (nodes
), ==, 1);
1303 g_assert_cmpint (count_interfaces (c
, "/foo/boss/executives"), ==, 0);
1305 /* now change data.num_subtree_nodes and check */
1306 data
.num_subtree_nodes
= 2;
1307 nodes
= get_nodes_at (c
, "/foo/boss/executives");
1308 g_assert (nodes
!= NULL
);
1309 g_assert_cmpint (g_strv_length (nodes
), ==, 5);
1310 g_assert (_g_strv_has_string ((const gchar
* const *) nodes
, "non_subtree_object"));
1311 g_assert (_g_strv_has_string ((const gchar
* const *) nodes
, "vp0"));
1312 g_assert (_g_strv_has_string ((const gchar
* const *) nodes
, "vp1"));
1313 g_assert (_g_strv_has_string ((const gchar
* const *) nodes
, "evp0"));
1314 g_assert (_g_strv_has_string ((const gchar
* const *) nodes
, "evp1"));
1315 /* check that /foo/boss/executives/non_subtree_object is not handled by the
1316 * subtree handlers - we can do this because objects from subtree handlers
1317 * has exactly one interface and non_subtree_object has two
1319 g_assert_cmpint (count_interfaces (c
, "/foo/boss/executives/non_subtree_object"), ==, 5);
1320 g_assert (has_interface (c
, "/foo/boss/executives/non_subtree_object", foo_interface_info
.name
));
1321 g_assert (has_interface (c
, "/foo/boss/executives/non_subtree_object", bar_interface_info
.name
));
1322 /* check that the vp and evp objects are handled by the subtree handlers */
1323 g_assert_cmpint (count_interfaces (c
, "/foo/boss/executives/vp0"), ==, 4);
1324 g_assert_cmpint (count_interfaces (c
, "/foo/boss/executives/vp1"), ==, 4);
1325 g_assert_cmpint (count_interfaces (c
, "/foo/boss/executives/evp0"), ==, 4);
1326 g_assert_cmpint (count_interfaces (c
, "/foo/boss/executives/evp1"), ==, 4);
1327 g_assert (has_interface (c
, "/foo/boss/executives/vp0", foo_interface_info
.name
));
1328 g_assert (has_interface (c
, "/foo/boss/executives/vp1", foo_interface_info
.name
));
1329 g_assert (has_interface (c
, "/foo/boss/executives/evp0", bar_interface_info
.name
));
1330 g_assert (has_interface (c
, "/foo/boss/executives/evp1", bar_interface_info
.name
));
1332 data
.num_subtree_nodes
= 3;
1333 nodes
= get_nodes_at (c
, "/foo/boss/executives");
1334 g_assert (nodes
!= NULL
);
1335 g_assert_cmpint (g_strv_length (nodes
), ==, 7);
1336 g_assert (_g_strv_has_string ((const gchar
* const *) nodes
, "non_subtree_object"));
1337 g_assert (_g_strv_has_string ((const gchar
* const *) nodes
, "vp0"));
1338 g_assert (_g_strv_has_string ((const gchar
* const *) nodes
, "vp1"));
1339 g_assert (_g_strv_has_string ((const gchar
* const *) nodes
, "vp2"));
1340 g_assert (_g_strv_has_string ((const gchar
* const *) nodes
, "evp0"));
1341 g_assert (_g_strv_has_string ((const gchar
* const *) nodes
, "evp1"));
1342 g_assert (_g_strv_has_string ((const gchar
* const *) nodes
, "evp2"));
1345 /* This is to check that a bug (rather, class of bugs) in gdbusconnection.c's
1347 * g_dbus_connection_list_registered_unlocked()
1349 * where /foo/boss/worker1 reported a child '1', is now fixed.
1351 nodes
= get_nodes_at (c
, "/foo/boss/worker1");
1352 g_assert (nodes
!= NULL
);
1353 g_assert_cmpint (g_strv_length (nodes
), ==, 0);
1356 /* check that calls are properly dispatched to the functions in foo_vtable for objects
1357 * implementing the org.example.Foo interface
1359 * We do this for both a regular registered object (/foo/boss) and also for an object
1360 * registered through the subtree mechanism.
1362 test_dispatch ("/foo/boss", TRUE
);
1363 test_dispatch ("/foo/boss/executives/vp0", TRUE
);
1365 /* To prevent from exiting and attaching a D-Bus tool like D-Feet; uncomment: */
1367 g_debug ("Point D-feet or other tool at: %s", g_test_dbus_get_temporary_address());
1368 g_main_loop_run (loop
);
1371 /* check that unregistering the subtree handler works */
1372 g_assert_cmpint (data
.num_unregistered_subtree_calls
, ==, 1);
1373 g_assert (g_dbus_connection_unregister_subtree (c
, subtree_registration_id
));
1374 g_main_context_iteration (NULL
, FALSE
);
1375 g_assert_cmpint (data
.num_unregistered_subtree_calls
, ==, 2);
1376 nodes
= get_nodes_at (c
, "/foo/boss/executives");
1377 g_assert (nodes
!= NULL
);
1378 g_assert_cmpint (g_strv_length (nodes
), ==, 1);
1379 g_assert (_g_strv_has_string ((const gchar
* const *) nodes
, "non_subtree_object"));
1382 g_assert (g_dbus_connection_unregister_object (c
, boss_foo_reg_id
));
1383 g_assert (g_dbus_connection_unregister_object (c
, boss_bar_reg_id
));
1384 g_assert (g_dbus_connection_unregister_object (c
, worker1_foo_reg_id
));
1385 g_assert (g_dbus_connection_unregister_object (c
, worker1p1_foo_reg_id
));
1386 g_assert (g_dbus_connection_unregister_object (c
, worker2_bar_reg_id
));
1387 g_assert (g_dbus_connection_unregister_object (c
, intern1_foo_reg_id
));
1388 g_assert (g_dbus_connection_unregister_object (c
, intern2_bar_reg_id
));
1389 g_assert (g_dbus_connection_unregister_object (c
, intern2_foo_reg_id
));
1390 g_assert (g_dbus_connection_unregister_object (c
, intern3_bar_reg_id
));
1391 g_assert (g_dbus_connection_unregister_object (c
, non_subtree_object_path_bar_reg_id
));
1392 g_assert (g_dbus_connection_unregister_object (c
, non_subtree_object_path_foo_reg_id
));
1394 g_main_context_iteration (NULL
, FALSE
);
1395 g_assert_cmpint (data
.num_unregistered_calls
, ==, num_successful_registrations
);
1397 /* check that we no longer export any objects - TODO: it looks like there's a bug in
1398 * libdbus-1 here: libdbus still reports the '/foo' object; so disable the test for now
1401 nodes
= get_nodes_at (c
, "/");
1402 g_assert (nodes
!= NULL
);
1403 g_assert_cmpint (g_strv_length (nodes
), ==, 0);
1411 test_object_registration_with_closures (void)
1414 guint registration_id
;
1417 c
= g_bus_get_sync (G_BUS_TYPE_SESSION
, NULL
, &error
);
1418 g_assert_no_error (error
);
1419 g_assert (c
!= NULL
);
1421 registration_id
= g_dbus_connection_register_object_with_closures (c
,
1423 (GDBusInterfaceInfo
*) &foo_interface_info
,
1424 g_cclosure_new (G_CALLBACK (foo_method_call
), NULL
, NULL
),
1425 g_cclosure_new (G_CALLBACK (foo_get_property
), NULL
, NULL
),
1426 g_cclosure_new (G_CALLBACK (foo_set_property
), NULL
, NULL
),
1428 g_assert_no_error (error
);
1429 g_assert (registration_id
> 0);
1431 test_dispatch ("/foo/boss", FALSE
);
1433 g_assert (g_dbus_connection_unregister_object (c
, registration_id
));
1438 static const GDBusInterfaceInfo test_interface_info1
=
1442 (GDBusMethodInfo
**) NULL
,
1443 (GDBusSignalInfo
**) NULL
,
1444 (GDBusPropertyInfo
**) NULL
,
1448 static const GDBusInterfaceInfo test_interface_info2
=
1451 "org.freedesktop.DBus.Properties",
1452 (GDBusMethodInfo
**) NULL
,
1453 (GDBusSignalInfo
**) NULL
,
1454 (GDBusPropertyInfo
**) NULL
,
1459 check_interfaces (GDBusConnection
*c
,
1460 const gchar
*object_path
,
1461 const gchar
**interfaces
)
1466 GDBusNodeInfo
*node_info
;
1470 proxy
= g_dbus_proxy_new_sync (c
,
1471 G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES
|
1472 G_DBUS_PROXY_FLAGS_DO_NOT_CONNECT_SIGNALS
,
1474 g_dbus_connection_get_unique_name (c
),
1476 "org.freedesktop.DBus.Introspectable",
1479 g_assert_no_error (error
);
1480 g_assert (proxy
!= NULL
);
1482 /* do this async to avoid libdbus-1 deadlocks */
1484 g_dbus_proxy_call (proxy
,
1487 G_DBUS_CALL_FLAGS_NONE
,
1490 (GAsyncReadyCallback
) introspect_callback
,
1492 g_main_loop_run (loop
);
1493 g_assert (xml_data
!= NULL
);
1495 node_info
= g_dbus_node_info_new_for_xml (xml_data
, &error
);
1496 g_assert_no_error (error
);
1497 g_assert (node_info
!= NULL
);
1499 g_assert (node_info
->interfaces
!= NULL
);
1500 for (i
= 0; node_info
->interfaces
[i
]; i
++) ;
1502 if (g_strv_length ((gchar
**)interfaces
) != i
- 1)
1504 g_printerr ("expected ");
1505 for (i
= 0; interfaces
[i
]; i
++)
1506 g_printerr ("%s ", interfaces
[i
]);
1507 g_printerr ("\ngot ");
1508 for (i
= 0; node_info
->interfaces
[i
]; i
++)
1509 g_printerr ("%s ", node_info
->interfaces
[i
]->name
);
1513 g_assert_cmpint (g_strv_length ((gchar
**)interfaces
), ==, i
- 1);
1515 for (i
= 0; interfaces
[i
]; i
++)
1517 for (j
= 0; node_info
->interfaces
[j
]; j
++)
1519 if (strcmp (interfaces
[i
], node_info
->interfaces
[j
]->name
) == 0)
1523 g_assert_not_reached ();
1528 g_object_unref (proxy
);
1530 g_dbus_node_info_unref (node_info
);
1534 test_registered_interfaces (void)
1538 const gchar
*interfaces
[] = {
1540 "org.freedesktop.DBus.Properties",
1541 "org.freedesktop.DBus.Introspectable",
1546 c
= g_bus_get_sync (G_BUS_TYPE_SESSION
, NULL
, &error
);
1547 g_assert_no_error (error
);
1548 g_assert (c
!= NULL
);
1550 id1
= g_dbus_connection_register_object (c
,
1552 (GDBusInterfaceInfo
*) &test_interface_info1
,
1557 g_assert_no_error (error
);
1559 id2
= g_dbus_connection_register_object (c
,
1561 (GDBusInterfaceInfo
*) &test_interface_info2
,
1566 g_assert_no_error (error
);
1569 check_interfaces (c
, "/test", interfaces
);
1571 g_assert (g_dbus_connection_unregister_object (c
, id1
));
1572 g_assert (g_dbus_connection_unregister_object (c
, id2
));
1577 /* ---------------------------------------------------------------------------------------------------- */
1580 test_async_method_call (GDBusConnection
*connection
,
1581 const gchar
*sender
,
1582 const gchar
*object_path
,
1583 const gchar
*interface_name
,
1584 const gchar
*method_name
,
1585 GVariant
*parameters
,
1586 GDBusMethodInvocation
*invocation
,
1589 const GDBusPropertyInfo
*property
;
1591 /* Strictly speaking, this function should also expect to receive
1592 * method calls not on the org.freedesktop.DBus.Properties interface,
1593 * but we don't do any during this testcase, so assert that.
1595 g_assert_cmpstr (interface_name
, ==, "org.freedesktop.DBus.Properties");
1596 g_assert (g_dbus_method_invocation_get_method_info (invocation
) == NULL
);
1598 property
= g_dbus_method_invocation_get_property_info (invocation
);
1600 /* We should never be seeing any property calls on the com.example.Bar
1601 * interface because it doesn't export any properties.
1603 * In each case below make sure the interface is org.example.Foo.
1606 /* Do a whole lot of asserts to make sure that invalid calls are still
1607 * getting properly rejected by GDBusConnection and that our
1608 * environment is as we expect it to be.
1610 if (g_str_equal (method_name
, "Get"))
1612 const gchar
*iface_name
, *prop_name
;
1614 g_variant_get (parameters
, "(&s&s)", &iface_name
, &prop_name
);
1615 g_assert_cmpstr (iface_name
, ==, "org.example.Foo");
1616 g_assert (property
!= NULL
);
1617 g_assert_cmpstr (prop_name
, ==, property
->name
);
1618 g_assert (property
->flags
& G_DBUS_PROPERTY_INFO_FLAGS_READABLE
);
1619 g_dbus_method_invocation_return_value (invocation
, g_variant_new ("(v)", g_variant_new_string (prop_name
)));
1622 else if (g_str_equal (method_name
, "Set"))
1624 const gchar
*iface_name
, *prop_name
;
1627 g_variant_get (parameters
, "(&s&sv)", &iface_name
, &prop_name
, &value
);
1628 g_assert_cmpstr (iface_name
, ==, "org.example.Foo");
1629 g_assert (property
!= NULL
);
1630 g_assert_cmpstr (prop_name
, ==, property
->name
);
1631 g_assert (property
->flags
& G_DBUS_PROPERTY_INFO_FLAGS_WRITABLE
);
1632 g_assert (g_variant_is_of_type (value
, G_VARIANT_TYPE (property
->signature
)));
1633 g_dbus_method_invocation_return_value (invocation
, g_variant_new ("()"));
1634 g_variant_unref (value
);
1637 else if (g_str_equal (method_name
, "GetAll"))
1639 const gchar
*iface_name
;
1641 g_variant_get (parameters
, "(&s)", &iface_name
);
1642 g_assert_cmpstr (iface_name
, ==, "org.example.Foo");
1643 g_assert (property
== NULL
);
1644 g_dbus_method_invocation_return_value (invocation
,
1645 g_variant_new_parsed ("({ 'PropertyUno': < 'uno' >,"
1646 " 'NotWritable': < 'notwrite' > },)"));
1650 g_assert_not_reached ();
1653 static gint outstanding_cases
;
1656 ensure_result_cb (GObject
*source
,
1657 GAsyncResult
*result
,
1660 GDBusConnection
*connection
= G_DBUS_CONNECTION (source
);
1663 reply
= g_dbus_connection_call_finish (connection
, result
, NULL
);
1665 if (user_data
== NULL
)
1667 /* Expected an error */
1668 g_assert (reply
== NULL
);
1672 /* Expected a reply of a particular format. */
1675 g_assert (reply
!= NULL
);
1676 str
= g_variant_print (reply
, TRUE
);
1677 g_assert_cmpstr (str
, ==, (const gchar
*) user_data
);
1680 g_variant_unref (reply
);
1683 g_assert_cmpint (outstanding_cases
, >, 0);
1684 outstanding_cases
--;
1688 test_async_case (GDBusConnection
*connection
,
1689 const gchar
*expected_reply
,
1690 const gchar
*method
,
1691 const gchar
*format_string
,
1696 va_start (ap
, format_string
);
1698 g_dbus_connection_call (connection
, g_dbus_connection_get_unique_name (connection
), "/foo",
1699 "org.freedesktop.DBus.Properties", method
, g_variant_new_va (format_string
, NULL
, &ap
),
1700 NULL
, G_DBUS_CALL_FLAGS_NONE
, -1, NULL
, ensure_result_cb
, (gpointer
) expected_reply
);
1704 outstanding_cases
++;
1708 test_async_properties (void)
1710 GError
*error
= NULL
;
1711 guint registration_id
, registration_id2
;
1712 static const GDBusInterfaceVTable vtable
= {
1713 test_async_method_call
, NULL
, NULL
1716 c
= g_bus_get_sync (G_BUS_TYPE_SESSION
, NULL
, &error
);
1717 g_assert_no_error (error
);
1718 g_assert (c
!= NULL
);
1720 registration_id
= g_dbus_connection_register_object (c
,
1722 (GDBusInterfaceInfo
*) &foo_interface_info
,
1723 &vtable
, NULL
, NULL
, &error
);
1724 g_assert_no_error (error
);
1725 g_assert (registration_id
);
1726 registration_id2
= g_dbus_connection_register_object (c
,
1728 (GDBusInterfaceInfo
*) &foo2_interface_info
,
1729 &vtable
, NULL
, NULL
, &error
);
1730 g_assert_no_error (error
);
1731 g_assert (registration_id
);
1733 test_async_case (c
, NULL
, "random", "()");
1735 /* Test a variety of error cases */
1736 test_async_case (c
, NULL
, "Get", "(si)", "wrong signature", 5);
1737 test_async_case (c
, NULL
, "Get", "(ss)", "org.example.WrongInterface", "zzz");
1738 test_async_case (c
, NULL
, "Get", "(ss)", "org.example.Foo", "NoSuchProperty");
1739 test_async_case (c
, NULL
, "Get", "(ss)", "org.example.Foo", "NotReadable");
1741 test_async_case (c
, NULL
, "Set", "(si)", "wrong signature", 5);
1742 test_async_case (c
, NULL
, "Set", "(ssv)", "org.example.WrongInterface", "zzz", g_variant_new_string (""));
1743 test_async_case (c
, NULL
, "Set", "(ssv)", "org.example.Foo", "NoSuchProperty", g_variant_new_string (""));
1744 test_async_case (c
, NULL
, "Set", "(ssv)", "org.example.Foo", "NotWritable", g_variant_new_string (""));
1745 test_async_case (c
, NULL
, "Set", "(ssv)", "org.example.Foo", "PropertyUno", g_variant_new_object_path ("/wrong"));
1747 test_async_case (c
, NULL
, "GetAll", "(si)", "wrong signature", 5);
1748 test_async_case (c
, NULL
, "GetAll", "(s)", "org.example.WrongInterface");
1750 /* Make sure that we get no unexpected async property calls for com.example.Foo2 */
1751 test_async_case (c
, NULL
, "Get", "(ss)", "org.example.Foo2", "zzz");
1752 test_async_case (c
, NULL
, "Set", "(ssv)", "org.example.Foo2", "zzz", g_variant_new_string (""));
1753 test_async_case (c
, "(@a{sv} {},)", "GetAll", "(s)", "org.example.Foo2");
1755 /* Now do the proper things */
1756 test_async_case (c
, "(<'PropertyUno'>,)", "Get", "(ss)", "org.example.Foo", "PropertyUno");
1757 test_async_case (c
, "(<'NotWritable'>,)", "Get", "(ss)", "org.example.Foo", "NotWritable");
1758 test_async_case (c
, "()", "Set", "(ssv)", "org.example.Foo", "PropertyUno", g_variant_new_string (""));
1759 test_async_case (c
, "()", "Set", "(ssv)", "org.example.Foo", "NotReadable", g_variant_new_string (""));
1760 test_async_case (c
, "({'PropertyUno': <'uno'>, 'NotWritable': <'notwrite'>},)", "GetAll", "(s)", "org.example.Foo");
1762 while (outstanding_cases
)
1763 g_main_context_iteration (NULL
, TRUE
);
1765 g_dbus_connection_unregister_object (c
, registration_id
);
1766 g_dbus_connection_unregister_object (c
, registration_id2
);
1770 /* ---------------------------------------------------------------------------------------------------- */
1778 g_test_init (&argc
, &argv
, NULL
);
1780 /* all the tests rely on a shared main loop */
1781 loop
= g_main_loop_new (NULL
, FALSE
);
1783 g_test_add_func ("/gdbus/object-registration", test_object_registration
);
1784 g_test_add_func ("/gdbus/object-registration-with-closures", test_object_registration_with_closures
);
1785 g_test_add_func ("/gdbus/registered-interfaces", test_registered_interfaces
);
1786 g_test_add_func ("/gdbus/async-properties", test_async_properties
);
1788 /* TODO: check that we spit out correct introspection data */
1789 /* TODO: check that registering a whole subtree works */
1791 ret
= session_bus_run ();
1793 g_main_loop_unref (loop
);