* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General
- * Public License along with this library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
- * Boston, MA 02111-1307, USA.
+ * Public License along with this library; if not, see <http://www.gnu.org/licenses/>.
*
* Author: David Zeuthen <davidz@redhat.com>
*/
NULL,
};
+/* Foo2 is just Foo without the properties */
+static const GDBusInterfaceInfo foo2_interface_info =
+{
+ -1,
+ "org.example.Foo2",
+ (GDBusMethodInfo **) &foo_method_info_pointers,
+ (GDBusSignalInfo **) &foo_signal_info_pointers,
+};
+
static void
foo_method_call (GDBusConnection *connection,
const gchar *sender,
const gchar *input;
gchar *output;
g_variant_get (parameters, "(&s)", &input);
- output = g_strdup_printf ("You passed the string `%s'. Jolly good!", input);
+ output = g_strdup_printf ("You passed the string '%s'. Jolly good!", input);
g_dbus_method_invocation_return_value (invocation, g_variant_new ("(s)", output));
g_free (output);
}
{
GVariant *ret;
gchar *s;
- s = g_strdup_printf ("Property `%s' Is What It Is!", property_name);
+ s = g_strdup_printf ("Property '%s' Is What It Is!", property_name);
ret = g_variant_new_string (s);
g_free (s);
return ret;
g_set_error (error,
G_DBUS_ERROR,
G_DBUS_ERROR_SPAWN_FILE_INVALID,
- "Returning some error instead of writing the value `%s' to the property `%s'",
+ "Returning some error instead of writing the value '%s' to the property '%s'",
property_name, s);
g_free (s);
return FALSE;
error = NULL;
proxy = g_dbus_proxy_new_sync (c,
- G_TYPE_DBUS_PROXY,
G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES |
G_DBUS_PROXY_FLAGS_DO_NOT_CONNECT_SIGNALS,
NULL,
error = NULL;
proxy = g_dbus_proxy_new_sync (c,
- G_TYPE_DBUS_PROXY,
G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES |
G_DBUS_PROXY_FLAGS_DO_NOT_CONNECT_SIGNALS,
NULL,
error = NULL;
proxy = g_dbus_proxy_new_sync (c,
- G_TYPE_DBUS_PROXY,
G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES |
G_DBUS_PROXY_FLAGS_DO_NOT_CONNECT_SIGNALS,
NULL,
error = NULL;
proxy = g_dbus_proxy_new_sync (c,
- G_TYPE_DBUS_PROXY,
G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES |
G_DBUS_PROXY_FLAGS_DO_NOT_CONNECT_SIGNALS,
NULL,
}
/* Only allows certain objects, and aborts on unknowns */
-static GPtrArray *
+static GDBusInterfaceInfo **
subtree_introspect (GDBusConnection *connection,
const gchar *sender,
const gchar *object_path,
const gchar *node,
gpointer user_data)
{
- GPtrArray *interfaces;
+ const GDBusInterfaceInfo *interfaces[2] = {
+ NULL /* filled in below */, NULL
+ };
/* VPs implement the Foo interface, EVPs implement the Bar interface. The root
* does not implement any interfaces
*/
- interfaces = g_ptr_array_new ();
- if (g_str_has_prefix (node, "vp"))
+ if (node == NULL)
{
- g_ptr_array_add (interfaces, (gpointer) &foo_interface_info);
+ return NULL;
}
- else if (g_str_has_prefix (node, "evp"))
+ else if (g_str_has_prefix (node, "vp"))
{
- g_ptr_array_add (interfaces, (gpointer) &bar_interface_info);
+ interfaces[0] = &foo_interface_info;
}
- else if (g_strcmp0 (node, "/") == 0)
+ else if (g_str_has_prefix (node, "evp"))
{
- /* do nothing */
+ interfaces[0] = &bar_interface_info;
}
else
{
g_assert_not_reached ();
}
- return interfaces;
+ return g_memdup (interfaces, 2 * sizeof (void *));
}
static const GDBusInterfaceVTable *
}
/* Allow all objects to be introspected */
-static GPtrArray *
+static GDBusInterfaceInfo **
dynamic_subtree_introspect (GDBusConnection *connection,
const gchar *sender,
const gchar *object_path,
const gchar *node,
gpointer user_data)
{
- GPtrArray *interfaces;
-
- /* All nodes (including the root node) implements the Dyna interface */
- interfaces = g_ptr_array_new ();
- g_ptr_array_add (interfaces, (gpointer) &dyna_interface_info);
+ const GDBusInterfaceInfo *interfaces[2] = { &dyna_interface_info, NULL };
- return interfaces;
+ return g_memdup (interfaces, 2 * sizeof (void *));
}
static const GDBusInterfaceVTable *
const gchar *value_str;
foo_proxy = g_dbus_proxy_new_sync (c,
- G_TYPE_DBUS_PROXY,
G_DBUS_PROXY_FLAGS_DO_NOT_CONNECT_SIGNALS |
G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES,
NULL,
g_assert (value != NULL);
g_assert (g_variant_is_of_type (value, G_VARIANT_TYPE ("(s)")));
g_variant_get (value, "(&s)", &value_str);
- g_assert_cmpstr (value_str, ==, "You passed the string `winwinwin'. Jolly good!");
+ g_assert_cmpstr (value_str, ==, "You passed the string 'winwinwin'. Jolly good!");
g_variant_unref (value);
error = NULL;
NULL,
&error);
g_assert_error (error, G_DBUS_ERROR, G_DBUS_ERROR_INVALID_ARGS);
- g_assert_cmpstr (error->message, ==, "GDBus.Error:org.freedesktop.DBus.Error.InvalidArgs: Signature of message, `s', does not match expected signature `'");
+ g_assert_cmpstr (error->message, ==, "GDBus.Error:org.freedesktop.DBus.Error.InvalidArgs: Type of message, '(s)', does not match expected type '()'");
g_error_free (error);
g_assert (value == NULL);
NULL,
&error);
g_assert_error (error, G_DBUS_ERROR, G_DBUS_ERROR_UNKNOWN_METHOD);
- g_assert_cmpstr (error->message, ==, "GDBus.Error:org.freedesktop.DBus.Error.UnknownMethod: No such method `NonExistantMethod'");
+ g_assert_cmpstr (error->message, ==, "GDBus.Error:org.freedesktop.DBus.Error.UnknownMethod: No such method 'NonExistantMethod'");
+ g_error_free (error);
+ g_assert (value == NULL);
+
+ error = NULL;
+ value = g_dbus_proxy_call_sync (foo_proxy,
+ "org.example.FooXYZ.NonExistant",
+ NULL,
+ G_DBUS_CALL_FLAGS_NONE,
+ -1,
+ NULL,
+ &error);
+ g_assert_error (error, G_DBUS_ERROR, G_DBUS_ERROR_UNKNOWN_METHOD);
g_error_free (error);
g_assert (value == NULL);
g_assert (g_variant_is_of_type (value, G_VARIANT_TYPE ("(v)")));
g_variant_get (value, "(v)", &inner);
g_assert (g_variant_is_of_type (inner, G_VARIANT_TYPE_STRING));
- g_assert_cmpstr (g_variant_get_string (inner, NULL), ==, "Property `PropertyUno' Is What It Is!");
+ g_assert_cmpstr (g_variant_get_string (inner, NULL), ==, "Property 'PropertyUno' Is What It Is!");
g_variant_unref (value);
+ g_variant_unref (inner);
error = NULL;
value = g_dbus_proxy_call_sync (foo_proxy,
&error);
g_assert (value == NULL);
g_assert_error (error, G_DBUS_ERROR, G_DBUS_ERROR_INVALID_ARGS);
- g_assert_cmpstr (error->message, ==, "GDBus.Error:org.freedesktop.DBus.Error.InvalidArgs: No such property `ThisDoesntExist'");
+ g_assert_cmpstr (error->message, ==, "GDBus.Error:org.freedesktop.DBus.Error.InvalidArgs: No such property 'ThisDoesntExist'");
g_error_free (error);
error = NULL;
&error);
g_assert (value == NULL);
g_assert_error (error, G_DBUS_ERROR, G_DBUS_ERROR_INVALID_ARGS);
- g_assert_cmpstr (error->message, ==, "GDBus.Error:org.freedesktop.DBus.Error.InvalidArgs: Property `NotReadable' is not readable");
+ g_assert_cmpstr (error->message, ==, "GDBus.Error:org.freedesktop.DBus.Error.InvalidArgs: Property 'NotReadable' is not readable");
g_error_free (error);
error = NULL;
&error);
g_assert (value == NULL);
g_assert_error (error, G_DBUS_ERROR, G_DBUS_ERROR_SPAWN_FILE_INVALID);
- 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!''");
+ 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!''");
g_error_free (error);
error = NULL;
&error);
g_assert (value == NULL);
g_assert_error (error, G_DBUS_ERROR, G_DBUS_ERROR_INVALID_ARGS);
- g_assert_cmpstr (error->message, ==, "GDBus.Error:org.freedesktop.DBus.Error.InvalidArgs: Property `NotWritable' is not writable");
+ g_assert_cmpstr (error->message, ==, "GDBus.Error:org.freedesktop.DBus.Error.InvalidArgs: Property 'NotWritable' is not writable");
g_error_free (error);
error = NULL;
g_assert (value != NULL);
g_assert (g_variant_is_of_type (value, G_VARIANT_TYPE ("(a{sv})")));
s = g_variant_print (value, TRUE);
- g_assert_cmpstr (s, ==, "({'PropertyUno': <\"Property `PropertyUno' Is What It Is!\">, 'NotWritable': <\"Property `NotWritable' Is What It Is!\">},)");
+ g_assert_cmpstr (s, ==, "({'PropertyUno': <\"Property 'PropertyUno' Is What It Is!\">, 'NotWritable': <\"Property 'NotWritable' Is What It Is!\">},)");
g_free (s);
g_variant_unref (value);
test_dispatch (const gchar *object_path)
{
GThread *thread;
- GError *error;
/* run this in a thread to avoid deadlocks */
- error = NULL;
- thread = g_thread_create (test_dispatch_thread_func,
- (gpointer) object_path,
- TRUE,
- &error);
- g_assert_no_error (error);
- g_assert (thread != NULL);
+ thread = g_thread_new ("test_dispatch",
+ test_dispatch_thread_func,
+ (gpointer) object_path);
g_main_loop_run (loop);
g_thread_join (thread);
}
guint boss_foo_reg_id;
guint boss_bar_reg_id;
guint worker1_foo_reg_id;
+ guint worker1p1_foo_reg_id;
guint worker2_bar_reg_id;
guint intern1_foo_reg_id;
guint intern2_bar_reg_id;
registration_id = g_dbus_connection_register_object (c,
"/foo/boss",
- &foo_interface_info,
+ (GDBusInterfaceInfo *) &foo_interface_info,
&foo_vtable,
&data,
on_object_unregistered,
registration_id = g_dbus_connection_register_object (c,
"/foo/boss",
- &bar_interface_info,
+ (GDBusInterfaceInfo *) &bar_interface_info,
NULL,
&data,
on_object_unregistered,
registration_id = g_dbus_connection_register_object (c,
"/foo/boss/worker1",
- &foo_interface_info,
+ (GDBusInterfaceInfo *) &foo_interface_info,
NULL,
&data,
on_object_unregistered,
num_successful_registrations++;
registration_id = g_dbus_connection_register_object (c,
+ "/foo/boss/worker1p1",
+ (GDBusInterfaceInfo *) &foo_interface_info,
+ NULL,
+ &data,
+ on_object_unregistered,
+ &error);
+ g_assert_no_error (error);
+ g_assert (registration_id > 0);
+ worker1p1_foo_reg_id = registration_id;
+ num_successful_registrations++;
+
+ registration_id = g_dbus_connection_register_object (c,
"/foo/boss/worker2",
- &bar_interface_info,
+ (GDBusInterfaceInfo *) &bar_interface_info,
NULL,
&data,
on_object_unregistered,
registration_id = g_dbus_connection_register_object (c,
"/foo/boss/interns/intern1",
- &foo_interface_info,
+ (GDBusInterfaceInfo *) &foo_interface_info,
NULL,
&data,
on_object_unregistered,
/* ... and try again at another path */
registration_id = g_dbus_connection_register_object (c,
"/foo/boss/interns/intern2",
- &bar_interface_info,
+ (GDBusInterfaceInfo *) &bar_interface_info,
NULL,
&data,
on_object_unregistered,
/* register at the same path/interface - this should fail */
registration_id = g_dbus_connection_register_object (c,
"/foo/boss/interns/intern2",
- &bar_interface_info,
+ (GDBusInterfaceInfo *) &bar_interface_info,
NULL,
&data,
on_object_unregistered,
/* register at different interface - shouldn't fail */
registration_id = g_dbus_connection_register_object (c,
"/foo/boss/interns/intern2",
- &foo_interface_info,
+ (GDBusInterfaceInfo *) &foo_interface_info,
NULL,
&data,
on_object_unregistered,
/* unregister it via the id */
g_assert (g_dbus_connection_unregister_object (c, registration_id));
+ g_main_context_iteration (NULL, FALSE);
g_assert_cmpint (data.num_unregistered_calls, ==, 1);
intern2_foo_reg_id = 0;
/* register it back */
registration_id = g_dbus_connection_register_object (c,
"/foo/boss/interns/intern2",
- &foo_interface_info,
+ (GDBusInterfaceInfo *) &foo_interface_info,
NULL,
&data,
on_object_unregistered,
registration_id = g_dbus_connection_register_object (c,
"/foo/boss/interns/intern3",
- &bar_interface_info,
+ (GDBusInterfaceInfo *) &bar_interface_info,
NULL,
&data,
on_object_unregistered,
/* unregister it, then register it again */
g_assert_cmpint (data.num_unregistered_subtree_calls, ==, 0);
g_assert (g_dbus_connection_unregister_subtree (c, subtree_registration_id));
+ g_main_context_iteration (NULL, FALSE);
g_assert_cmpint (data.num_unregistered_subtree_calls, ==, 1);
subtree_registration_id = g_dbus_connection_register_subtree (c,
"/foo/boss/executives",
*/
registration_id = g_dbus_connection_register_object (c,
"/foo/boss/executives/non_subtree_object",
- &bar_interface_info,
+ (GDBusInterfaceInfo *) &bar_interface_info,
NULL,
&data,
on_object_unregistered,
num_successful_registrations++;
registration_id = g_dbus_connection_register_object (c,
"/foo/boss/executives/non_subtree_object",
- &foo_interface_info,
+ (GDBusInterfaceInfo *) &foo_interface_info,
NULL,
&data,
on_object_unregistered,
num_successful_registrations++;
/* now register a dynamic subtree, spawning objects as they are called */
- dyna_data = g_ptr_array_new ();
+ dyna_data = g_ptr_array_new_with_free_func (g_free);
dyna_subtree_registration_id = g_dbus_connection_register_subtree (c,
"/foo/dyna",
&dynamic_subtree_vtable,
/* Install three nodes in the dynamic subtree via the dyna_data backdoor and
* assert that they show up correctly in the introspection data */
- g_ptr_array_add (dyna_data, "lol");
- g_ptr_array_add (dyna_data, "cat");
- g_ptr_array_add (dyna_data, "cheezburger");
+ g_ptr_array_add (dyna_data, g_strdup ("lol"));
+ g_ptr_array_add (dyna_data, g_strdup ("cat"));
+ g_ptr_array_add (dyna_data, g_strdup ("cheezburger"));
nodes = get_nodes_at (c, "/foo/dyna");
g_assert (nodes != NULL);
g_assert_cmpint (g_strv_length (nodes), ==, 3);
nodes = get_nodes_at (c, "/foo/boss");
g_assert (nodes != NULL);
- g_assert_cmpint (g_strv_length (nodes), ==, 4);
+ g_assert_cmpint (g_strv_length (nodes), ==, 5);
g_assert (_g_strv_has_string ((const gchar* const *) nodes, "worker1"));
+ g_assert (_g_strv_has_string ((const gchar* const *) nodes, "worker1p1"));
g_assert (_g_strv_has_string ((const gchar* const *) nodes, "worker2"));
g_assert (_g_strv_has_string ((const gchar* const *) nodes, "interns"));
g_assert (_g_strv_has_string ((const gchar* const *) nodes, "executives"));
g_assert (_g_strv_has_string ((const gchar* const *) nodes, "evp2"));
g_strfreev (nodes);
+ /* This is to check that a bug (rather, class of bugs) in gdbusconnection.c's
+ *
+ * g_dbus_connection_list_registered_unlocked()
+ *
+ * where /foo/boss/worker1 reported a child '1', is now fixed.
+ */
+ nodes = get_nodes_at (c, "/foo/boss/worker1");
+ g_assert (nodes != NULL);
+ g_assert_cmpint (g_strv_length (nodes), ==, 0);
+ g_strfreev (nodes);
+
/* check that calls are properly dispatched to the functions in foo_vtable for objects
* implementing the org.example.Foo interface
*
/* To prevent from exiting and attaching a D-Bus tool like D-Feet; uncomment: */
#if 0
- g_debug ("Point D-feet or other tool at: %s", session_bus_get_temporary_address());
+ g_debug ("Point D-feet or other tool at: %s", g_test_dbus_get_temporary_address());
g_main_loop_run (loop);
#endif
/* check that unregistering the subtree handler works */
g_assert_cmpint (data.num_unregistered_subtree_calls, ==, 1);
g_assert (g_dbus_connection_unregister_subtree (c, subtree_registration_id));
+ g_main_context_iteration (NULL, FALSE);
g_assert_cmpint (data.num_unregistered_subtree_calls, ==, 2);
nodes = get_nodes_at (c, "/foo/boss/executives");
g_assert (nodes != NULL);
g_assert (g_dbus_connection_unregister_object (c, boss_foo_reg_id));
g_assert (g_dbus_connection_unregister_object (c, boss_bar_reg_id));
g_assert (g_dbus_connection_unregister_object (c, worker1_foo_reg_id));
+ g_assert (g_dbus_connection_unregister_object (c, worker1p1_foo_reg_id));
g_assert (g_dbus_connection_unregister_object (c, worker2_bar_reg_id));
g_assert (g_dbus_connection_unregister_object (c, intern1_foo_reg_id));
g_assert (g_dbus_connection_unregister_object (c, intern2_bar_reg_id));
g_assert (g_dbus_connection_unregister_object (c, non_subtree_object_path_bar_reg_id));
g_assert (g_dbus_connection_unregister_object (c, non_subtree_object_path_foo_reg_id));
+ g_main_context_iteration (NULL, FALSE);
g_assert_cmpint (data.num_unregistered_calls, ==, num_successful_registrations);
/* check that we no longer export any objects - TODO: it looks like there's a bug in
g_object_unref (c);
}
+static const GDBusInterfaceInfo test_interface_info1 =
+{
+ -1,
+ "org.example.Foo",
+ (GDBusMethodInfo **) NULL,
+ (GDBusSignalInfo **) NULL,
+ (GDBusPropertyInfo **) NULL,
+ NULL,
+};
+
+static const GDBusInterfaceInfo test_interface_info2 =
+{
+ -1,
+ "org.freedesktop.DBus.Properties",
+ (GDBusMethodInfo **) NULL,
+ (GDBusSignalInfo **) NULL,
+ (GDBusPropertyInfo **) NULL,
+ NULL,
+};
+
+static void
+check_interfaces (GDBusConnection *c,
+ const gchar *object_path,
+ const gchar **interfaces)
+{
+ GError *error;
+ GDBusProxy *proxy;
+ gchar *xml_data;
+ GDBusNodeInfo *node_info;
+ gint i, j;
+
+ error = NULL;
+ proxy = g_dbus_proxy_new_sync (c,
+ G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES |
+ G_DBUS_PROXY_FLAGS_DO_NOT_CONNECT_SIGNALS,
+ NULL,
+ g_dbus_connection_get_unique_name (c),
+ object_path,
+ "org.freedesktop.DBus.Introspectable",
+ NULL,
+ &error);
+ g_assert_no_error (error);
+ g_assert (proxy != NULL);
+
+ /* do this async to avoid libdbus-1 deadlocks */
+ xml_data = NULL;
+ g_dbus_proxy_call (proxy,
+ "Introspect",
+ NULL,
+ G_DBUS_CALL_FLAGS_NONE,
+ -1,
+ NULL,
+ (GAsyncReadyCallback) introspect_callback,
+ &xml_data);
+ g_main_loop_run (loop);
+ g_assert (xml_data != NULL);
+
+ node_info = g_dbus_node_info_new_for_xml (xml_data, &error);
+ g_assert_no_error (error);
+ g_assert (node_info != NULL);
+
+ g_assert (node_info->interfaces != NULL);
+ for (i = 0; node_info->interfaces[i]; i++) ;
+#if 0
+ if (g_strv_length ((gchar**)interfaces) != i - 1)
+ {
+ g_print ("expected ");
+ for (i = 0; interfaces[i]; i++)
+ g_print ("%s ", interfaces[i]);
+ g_print ("\ngot ");
+ for (i = 0; node_info->interfaces[i]; i++)
+ g_print ("%s ", node_info->interfaces[i]->name);
+ g_print ("\n");
+ }
+#endif
+ g_assert_cmpint (g_strv_length ((gchar**)interfaces), ==, i - 1);
+
+ for (i = 0; interfaces[i]; i++)
+ {
+ for (j = 0; node_info->interfaces[j]; j++)
+ {
+ if (strcmp (interfaces[i], node_info->interfaces[j]->name) == 0)
+ goto found;
+ }
+
+ g_assert_not_reached ();
+
+ found: ;
+ }
+
+ g_object_unref (proxy);
+ g_free (xml_data);
+ g_dbus_node_info_unref (node_info);
+}
+
+static void
+test_registered_interfaces (void)
+{
+ GError *error;
+ guint id1, id2;
+ const gchar *interfaces[] = {
+ "org.example.Foo",
+ "org.freedesktop.DBus.Properties",
+ "org.freedesktop.DBus.Introspectable",
+ NULL,
+ };
+
+ error = NULL;
+ c = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, &error);
+ g_assert_no_error (error);
+ g_assert (c != NULL);
+
+ id1 = g_dbus_connection_register_object (c,
+ "/test",
+ (GDBusInterfaceInfo *) &test_interface_info1,
+ NULL,
+ NULL,
+ NULL,
+ &error);
+ g_assert_no_error (error);
+ g_assert (id1 > 0);
+ id2 = g_dbus_connection_register_object (c,
+ "/test",
+ (GDBusInterfaceInfo *) &test_interface_info2,
+ NULL,
+ NULL,
+ NULL,
+ &error);
+ g_assert_no_error (error);
+ g_assert (id2 > 0);
+
+ check_interfaces (c, "/test", interfaces);
+
+ g_assert (g_dbus_connection_unregister_object (c, id1));
+ g_assert (g_dbus_connection_unregister_object (c, id2));
+ g_object_unref (c);
+}
+
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+static void
+test_async_method_call (GDBusConnection *connection,
+ const gchar *sender,
+ const gchar *object_path,
+ const gchar *interface_name,
+ const gchar *method_name,
+ GVariant *parameters,
+ GDBusMethodInvocation *invocation,
+ gpointer user_data)
+{
+ const GDBusPropertyInfo *property;
+
+ /* Strictly speaking, this function should also expect to receive
+ * method calls not on the org.freedesktop.DBus.Properties interface,
+ * but we don't do any during this testcase, so assert that.
+ */
+ g_assert_cmpstr (interface_name, ==, "org.freedesktop.DBus.Properties");
+ g_assert (g_dbus_method_invocation_get_method_info (invocation) == NULL);
+
+ property = g_dbus_method_invocation_get_property_info (invocation);
+
+ /* We should never be seeing any property calls on the com.example.Bar
+ * interface because it doesn't export any properties.
+ *
+ * In each case below make sure the interface is org.example.Foo.
+ */
+
+ /* Do a whole lot of asserts to make sure that invalid calls are still
+ * getting properly rejected by GDBusConnection and that our
+ * environment is as we expect it to be.
+ */
+ if (g_str_equal (method_name, "Get"))
+ {
+ const gchar *iface_name, *prop_name;
+
+ g_variant_get (parameters, "(&s&s)", &iface_name, &prop_name);
+ g_assert_cmpstr (iface_name, ==, "org.example.Foo");
+ g_assert (property != NULL);
+ g_assert_cmpstr (prop_name, ==, property->name);
+ g_assert (property->flags & G_DBUS_PROPERTY_INFO_FLAGS_READABLE);
+ g_dbus_method_invocation_return_value (invocation, g_variant_new ("(v)", g_variant_new_string (prop_name)));
+ }
+
+ else if (g_str_equal (method_name, "Set"))
+ {
+ const gchar *iface_name, *prop_name;
+ GVariant *value;
+
+ g_variant_get (parameters, "(&s&sv)", &iface_name, &prop_name, &value);
+ g_assert_cmpstr (iface_name, ==, "org.example.Foo");
+ g_assert (property != NULL);
+ g_assert_cmpstr (prop_name, ==, property->name);
+ g_assert (property->flags & G_DBUS_PROPERTY_INFO_FLAGS_WRITABLE);
+ g_assert (g_variant_is_of_type (value, G_VARIANT_TYPE (property->signature)));
+ g_dbus_method_invocation_return_value (invocation, g_variant_new ("()"));
+ g_variant_unref (value);
+ }
+
+ else if (g_str_equal (method_name, "GetAll"))
+ {
+ const gchar *iface_name;
+
+ g_variant_get (parameters, "(&s)", &iface_name);
+ g_assert_cmpstr (iface_name, ==, "org.example.Foo");
+ g_assert (property == NULL);
+ g_dbus_method_invocation_return_value (invocation,
+ g_variant_new_parsed ("({ 'PropertyUno': < 'uno' >,"
+ " 'NotWritable': < 'notwrite' > },)"));
+ }
+
+ else
+ g_assert_not_reached ();
+}
+
+static gint outstanding_cases;
+
+static void
+ensure_result_cb (GObject *source,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ GDBusConnection *connection = G_DBUS_CONNECTION (source);
+ GVariant *reply;
+
+ reply = g_dbus_connection_call_finish (connection, result, NULL);
+
+ if (user_data == NULL)
+ {
+ /* Expected an error */
+ g_assert (reply == NULL);
+ }
+ else
+ {
+ /* Expected a reply of a particular format. */
+ gchar *str;
+
+ g_assert (reply != NULL);
+ str = g_variant_print (reply, TRUE);
+ g_assert_cmpstr (str, ==, (const gchar *) user_data);
+ g_free (str);
+
+ g_variant_unref (reply);
+ }
+
+ g_assert_cmpint (outstanding_cases, >, 0);
+ outstanding_cases--;
+}
+
+static void
+test_async_case (GDBusConnection *connection,
+ const gchar *expected_reply,
+ const gchar *method,
+ const gchar *format_string,
+ ...)
+{
+ va_list ap;
+
+ va_start (ap, format_string);
+
+ g_dbus_connection_call (connection, g_dbus_connection_get_unique_name (connection), "/foo",
+ "org.freedesktop.DBus.Properties", method, g_variant_new_va (format_string, NULL, &ap),
+ NULL, G_DBUS_CALL_FLAGS_NONE, -1, NULL, ensure_result_cb, (gpointer) expected_reply);
+
+ va_end (ap);
+
+ outstanding_cases++;
+}
+
+static void
+test_async_properties (void)
+{
+ GError *error = NULL;
+ guint registration_id, registration_id2;
+ static const GDBusInterfaceVTable vtable = {
+ test_async_method_call, NULL, NULL
+ };
+
+ c = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, &error);
+ g_assert_no_error (error);
+ g_assert (c != NULL);
+
+ registration_id = g_dbus_connection_register_object (c,
+ "/foo",
+ (GDBusInterfaceInfo *) &foo_interface_info,
+ &vtable, NULL, NULL, &error);
+ g_assert_no_error (error);
+ g_assert (registration_id);
+ registration_id2 = g_dbus_connection_register_object (c,
+ "/foo",
+ (GDBusInterfaceInfo *) &foo2_interface_info,
+ &vtable, NULL, NULL, &error);
+ g_assert_no_error (error);
+ g_assert (registration_id);
+
+ test_async_case (c, NULL, "random", "()");
+
+ /* Test a variety of error cases */
+ test_async_case (c, NULL, "Get", "(si)", "wrong signature", 5);
+ test_async_case (c, NULL, "Get", "(ss)", "org.example.WrongInterface", "zzz");
+ test_async_case (c, NULL, "Get", "(ss)", "org.example.Foo", "NoSuchProperty");
+ test_async_case (c, NULL, "Get", "(ss)", "org.example.Foo", "NotReadable");
+
+ test_async_case (c, NULL, "Set", "(si)", "wrong signature", 5);
+ test_async_case (c, NULL, "Set", "(ssv)", "org.example.WrongInterface", "zzz", g_variant_new_string (""));
+ test_async_case (c, NULL, "Set", "(ssv)", "org.example.Foo", "NoSuchProperty", g_variant_new_string (""));
+ test_async_case (c, NULL, "Set", "(ssv)", "org.example.Foo", "NotWritable", g_variant_new_string (""));
+ test_async_case (c, NULL, "Set", "(ssv)", "org.example.Foo", "PropertyUno", g_variant_new_object_path ("/wrong"));
+
+ test_async_case (c, NULL, "GetAll", "(si)", "wrong signature", 5);
+ test_async_case (c, NULL, "GetAll", "(s)", "org.example.WrongInterface");
+
+ /* Make sure that we get no unexpected async property calls for com.example.Foo2 */
+ test_async_case (c, NULL, "Get", "(ss)", "org.example.Foo2", "zzz");
+ test_async_case (c, NULL, "Set", "(ssv)", "org.example.Foo2", "zzz", g_variant_new_string (""));
+ test_async_case (c, "(@a{sv} {},)", "GetAll", "(s)", "org.example.Foo2");
+
+ /* Now do the proper things */
+ test_async_case (c, "(<'PropertyUno'>,)", "Get", "(ss)", "org.example.Foo", "PropertyUno");
+ test_async_case (c, "(<'NotWritable'>,)", "Get", "(ss)", "org.example.Foo", "NotWritable");
+ test_async_case (c, "()", "Set", "(ssv)", "org.example.Foo", "PropertyUno", g_variant_new_string (""));
+ test_async_case (c, "()", "Set", "(ssv)", "org.example.Foo", "NotReadable", g_variant_new_string (""));
+ test_async_case (c, "({'PropertyUno': <'uno'>, 'NotWritable': <'notwrite'>},)", "GetAll", "(s)", "org.example.Foo");
+
+ while (outstanding_cases)
+ g_main_context_iteration (NULL, TRUE);
+
+ g_dbus_connection_unregister_object (c, registration_id);
+ g_dbus_connection_unregister_object (c, registration_id2);
+ g_object_unref (c);
+}
/* ---------------------------------------------------------------------------------------------------- */
{
gint ret;
- g_type_init ();
g_test_init (&argc, &argv, NULL);
/* all the tests rely on a shared main loop */
loop = g_main_loop_new (NULL, FALSE);
- /* all the tests use a session bus with a well-known address that we can bring up and down
- * using session_bus_up() and session_bus_down().
- */
- g_unsetenv ("DISPLAY");
- g_setenv ("DBUS_SESSION_BUS_ADDRESS", session_bus_get_temporary_address (), TRUE);
-
- session_bus_up ();
-
- /* TODO: wait a bit for the bus to come up.. ideally session_bus_up() won't return
- * until one can connect to the bus but that's not how things work right now
- */
- usleep (500 * 1000);
-
g_test_add_func ("/gdbus/object-registration", test_object_registration);
+ g_test_add_func ("/gdbus/registered-interfaces", test_registered_interfaces);
+ g_test_add_func ("/gdbus/async-properties", test_async_properties);
+
/* TODO: check that we spit out correct introspection data */
/* TODO: check that registering a whole subtree works */
- ret = g_test_run();
+ ret = session_bus_run ();
- /* tear down bus */
- session_bus_down ();
+ g_main_loop_unref (loop);
return ret;
}