glib/gio/tests/gdbus-test-codegen.c
David Zeuthen 05448a6bef gdbus-codegen: Rework C property getters
Rework property getters to use a vfunc so we can take the fast path
and avoid allocating memory for both the skeleton and the proxy
cases. This requires some special case because of how GVariant expects
you to free memory in some cases, see #657100. Add test cases for
this.

Document the _get_ functions as not being thread-safe and also
generate _dup_ C getters (which are thread-safe).

Mark all the generated _get_, _dup_ and _set_ as (skip) as non-C
languages should just use GObject properties and not the (socalled)
"C binding".

Signed-off-by: David Zeuthen <davidz@redhat.com>
2011-08-23 12:54:27 -04:00

2222 lines
82 KiB
C

/* GLib testing framework examples and tests
*
* Copyright (C) 2008-2011 Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* 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.
*
* Author: David Zeuthen <davidz@redhat.com>
*/
#include <gio/gio.h>
#include <unistd.h>
#include <string.h>
#include <stdio.h>
#include "gdbus-tests.h"
#include "gdbus-test-codegen-generated.h"
/* ---------------------------------------------------------------------------------------------------- */
static guint
count_annotations (GDBusAnnotationInfo **annotations)
{
guint ret;
ret = 0;
while (annotations != NULL && annotations[ret] != NULL)
ret++;
return ret;
}
/* checks that
*
* - non-internal annotations are written out correctly; and
* - injection via --annotation --key --value works
*/
static void
test_annotations (void)
{
GDBusInterfaceInfo *iface;
GDBusMethodInfo *method;
GDBusSignalInfo *signal;
GDBusPropertyInfo *property;
iface = foo_bar_interface_info ();
g_assert (iface != NULL);
/* see Makefile.am for where these annotations are injected */
g_assert_cmpint (count_annotations (iface->annotations), ==, 1);
g_assert_cmpstr (g_dbus_annotation_info_lookup (iface->annotations, "Key1"), ==, "Value1");
method = g_dbus_interface_info_lookup_method (iface, "HelloWorld");
g_assert (method != NULL);
g_assert_cmpint (count_annotations (method->annotations), ==, 2);
g_assert_cmpstr (g_dbus_annotation_info_lookup (method->annotations, "ExistingAnnotation"), ==, "blah");
g_assert_cmpstr (g_dbus_annotation_info_lookup (method->annotations, "Key3"), ==, "Value3");
signal = g_dbus_interface_info_lookup_signal (iface, "TestSignal");
g_assert (signal != NULL);
g_assert_cmpint (count_annotations (signal->annotations), ==, 1);
g_assert_cmpstr (g_dbus_annotation_info_lookup (signal->annotations, "Key4"), ==, "Value4");
g_assert_cmpstr (g_dbus_annotation_info_lookup (signal->args[1]->annotations, "Key8"), ==, "Value8");
property = g_dbus_interface_info_lookup_property (iface, "ay");
g_assert (property != NULL);
g_assert_cmpint (count_annotations (property->annotations), ==, 1);
g_assert_cmpstr (g_dbus_annotation_info_lookup (property->annotations, "Key5"), ==, "Value5");
method = g_dbus_interface_info_lookup_method (iface, "TestPrimitiveTypes");
g_assert (method != NULL);
g_assert_cmpstr (g_dbus_annotation_info_lookup (method->in_args[4]->annotations, "Key6"), ==, "Value6");
g_assert_cmpstr (g_dbus_annotation_info_lookup (method->out_args[5]->annotations, "Key7"), ==, "Value7");
}
/* ---------------------------------------------------------------------------------------------------- */
static gboolean
on_handle_hello_world (FooBar *object,
GDBusMethodInvocation *invocation,
const gchar *greeting,
gpointer user_data)
{
gchar *response;
response = g_strdup_printf ("Word! You said `%s'. I'm Skeleton, btw!", greeting);
foo_bar_complete_hello_world (object, invocation, response);
g_free (response);
return TRUE;
}
static gboolean
on_handle_test_primitive_types (FooBar *object,
GDBusMethodInvocation *invocation,
guchar val_byte,
gboolean val_boolean,
gint16 val_int16,
guint16 val_uint16,
gint val_int32,
guint val_uint32,
gint64 val_int64,
guint64 val_uint64,
gdouble val_double,
const gchar *val_string,
const gchar *val_objpath,
const gchar *val_signature,
const gchar *val_bytestring,
gpointer user_data)
{
gchar *s1;
gchar *s2;
gchar *s3;
s1 = g_strdup_printf ("Word! You said `%s'. Rock'n'roll!", val_string);
s2 = g_strdup_printf ("/modified%s", val_objpath);
s3 = g_strdup_printf ("assgit%s", val_signature);
foo_bar_complete_test_primitive_types (object,
invocation,
10 + val_byte,
!val_boolean,
100 + val_int16,
1000 + val_uint16,
10000 + val_int32,
100000 + val_uint32,
1000000 + val_int64,
10000000 + val_uint64,
val_double / G_PI,
s1,
s2,
s3,
"bytestring!\xff");
g_free (s1);
g_free (s2);
g_free (s3);
return TRUE;
}
static gboolean
on_handle_test_non_primitive_types (FooBar *object,
GDBusMethodInvocation *invocation,
GVariant *dict_s_to_s,
GVariant *dict_s_to_pairs,
GVariant *a_struct,
const gchar* const *array_of_strings,
const gchar* const *array_of_objpaths,
GVariant *array_of_signatures,
const gchar* const *array_of_bytestrings,
gpointer user_data)
{
gchar *s;
GString *str;
str = g_string_new (NULL);
s = g_variant_print (dict_s_to_s, TRUE); g_string_append (str, s); g_free (s);
s = g_variant_print (dict_s_to_pairs, TRUE); g_string_append (str, s); g_free (s);
s = g_variant_print (a_struct, TRUE); g_string_append (str, s); g_free (s);
s = g_strjoinv (", ", (gchar **) array_of_strings);
g_string_append_printf (str, "array_of_strings: [%s] ", s);
g_free (s);
s = g_strjoinv (", ", (gchar **) array_of_objpaths);
g_string_append_printf (str, "array_of_objpaths: [%s] ", s);
g_free (s);
s = g_variant_print (array_of_signatures, TRUE);
g_string_append_printf (str, "array_of_signatures: %s ", s);
g_free (s);
s = g_strjoinv (", ", (gchar **) array_of_bytestrings);
g_string_append_printf (str, "array_of_bytestrings: [%s] ", s);
g_free (s);
foo_bar_complete_test_non_primitive_types (object, invocation, str->str);
g_string_free (str, TRUE);
return TRUE;
}
static gboolean
on_handle_request_signal_emission (FooBar *object,
GDBusMethodInvocation *invocation,
gint which_one,
gpointer user_data)
{
if (which_one == 0)
{
const gchar *a_strv[] = {"foo", "bar", NULL};
const gchar *a_bytestring_array[] = {"foo\xff", "bar\xff", NULL};
GVariant *a_variant = g_variant_new_parsed ("{'first': (42, 42), 'second': (43, 43)}");
foo_bar_emit_test_signal (object, 43, a_strv, a_bytestring_array, a_variant); /* consumes a_variant */
foo_bar_complete_request_signal_emission (object, invocation);
}
return TRUE;
}
static gboolean
on_handle_request_multi_property_mods (FooBar *object,
GDBusMethodInvocation *invocation,
gpointer user_data)
{
foo_bar_set_y (object, foo_bar_get_y (object) + 1);
foo_bar_set_i (object, foo_bar_get_i (object) + 1);
foo_bar_set_y (object, foo_bar_get_y (object) + 1);
foo_bar_set_i (object, foo_bar_get_i (object) + 1);
g_dbus_interface_skeleton_flush (G_DBUS_INTERFACE_SKELETON (object));
foo_bar_set_y (object, foo_bar_get_y (object) + 1);
foo_bar_set_i (object, foo_bar_get_i (object) + 1);
foo_bar_complete_request_multi_property_mods (object, invocation);
return TRUE;
}
static gboolean
on_handle_property_cancellation (FooBar *object,
GDBusMethodInvocation *invocation,
gpointer user_data)
{
guint n;
n = foo_bar_get_n (object);
/* This queues up a PropertiesChange event */
foo_bar_set_n (object, n + 1);
/* this modifies the queued up event */
foo_bar_set_n (object, n);
/* this flushes all PropertiesChanges event (sends the D-Bus message right
* away, if any - there should not be any)
*/
g_dbus_interface_skeleton_flush (G_DBUS_INTERFACE_SKELETON (object));
/* this makes us return the reply D-Bus method */
foo_bar_complete_property_cancellation (object, invocation);
return TRUE;
}
/* ---------------------------------------------------------------------------------------------------- */
static gboolean
on_handle_force_method (FooBat *object,
GDBusMethodInvocation *invocation,
GVariant *force_in_i,
GVariant *force_in_s,
GVariant *force_in_ay,
GVariant *force_in_struct,
gpointer user_data)
{
GVariant *ret_i;
GVariant *ret_s;
GVariant *ret_ay;
GVariant *ret_struct;
gint32 val;
gchar *s;
ret_i = g_variant_new_int32 (g_variant_get_int32 (force_in_i) + 10);
s = g_strdup_printf ("%s_foo", g_variant_get_string (force_in_s, NULL));
ret_s = g_variant_new_string (s);
g_free (s);
s = g_strdup_printf ("%s_foo\xff", g_variant_get_bytestring (force_in_ay));
ret_ay = g_variant_new_bytestring (s);
g_free (s);
g_variant_get (force_in_struct, "(i)", &val);
ret_struct = g_variant_new ("(i)", val + 10);
g_variant_ref_sink (ret_i);
g_variant_ref_sink (ret_s);
g_variant_ref_sink (ret_ay);
g_variant_ref_sink (ret_struct);
foo_bat_emit_force_signal (object,
ret_i,
ret_s,
ret_ay,
ret_struct);
foo_bat_complete_force_method (object,
invocation,
ret_i,
ret_s,
ret_ay,
ret_struct);
g_variant_unref (ret_i);
g_variant_unref (ret_s);
g_variant_unref (ret_ay);
g_variant_unref (ret_struct);
return TRUE;
}
/* ---------------------------------------------------------------------------------------------------- */
static gboolean
my_g_authorize_method_handler (GDBusInterfaceSkeleton *interface,
GDBusMethodInvocation *invocation,
gpointer user_data)
{
const gchar *method_name;
gboolean authorized;
authorized = FALSE;
method_name = g_dbus_method_invocation_get_method_name (invocation);
if (g_strcmp0 (method_name, "CheckNotAuthorized") == 0)
{
authorized = FALSE;
}
else if (g_strcmp0 (method_name, "CheckAuthorized") == 0)
{
authorized = TRUE;
}
else if (g_strcmp0 (method_name, "CheckNotAuthorizedFromObject") == 0)
{
authorized = TRUE;
}
else
{
g_assert_not_reached ();
}
if (!authorized)
{
g_dbus_method_invocation_return_error (invocation,
G_IO_ERROR,
G_IO_ERROR_PERMISSION_DENIED,
"not authorized...");
}
return authorized;
}
static gboolean
my_object_authorize_method_handler (GDBusObjectSkeleton *object,
GDBusInterfaceSkeleton *interface,
GDBusMethodInvocation *invocation,
gpointer user_data)
{
const gchar *method_name;
gboolean authorized;
authorized = FALSE;
method_name = g_dbus_method_invocation_get_method_name (invocation);
if (g_strcmp0 (method_name, "CheckNotAuthorized") == 0)
{
authorized = TRUE;
}
else if (g_strcmp0 (method_name, "CheckAuthorized") == 0)
{
authorized = TRUE;
}
else if (g_strcmp0 (method_name, "CheckNotAuthorizedFromObject") == 0)
{
authorized = FALSE;
}
else
{
g_assert_not_reached ();
}
if (!authorized)
{
g_dbus_method_invocation_return_error (invocation,
G_IO_ERROR,
G_IO_ERROR_PENDING,
"not authorized (from object)...");
}
return authorized;
}
static gboolean
on_handle_check_not_authorized (FooAuthorize *object,
GDBusMethodInvocation *invocation,
gpointer user_data)
{
foo_authorize_complete_check_not_authorized (object, invocation);
return TRUE;
}
static gboolean
on_handle_check_authorized (FooAuthorize *object,
GDBusMethodInvocation *invocation,
gpointer user_data)
{
foo_authorize_complete_check_authorized (object, invocation);
return TRUE;
}
static gboolean
on_handle_check_not_authorized_from_object (FooAuthorize *object,
GDBusMethodInvocation *invocation,
gpointer user_data)
{
foo_authorize_complete_check_not_authorized_from_object (object, invocation);
return TRUE;
}
/* ---------------------------------------------------------------------------------------------------- */
static gboolean
on_handle_get_self (FooMethodThreads *object,
GDBusMethodInvocation *invocation,
gpointer user_data)
{
gchar *s;
s = g_strdup_printf ("%p", g_thread_self ());
foo_method_threads_complete_get_self (object, invocation, s);
g_free (s);
return TRUE;
}
/* ---------------------------------------------------------------------------------------------------- */
static GThread *method_handler_thread = NULL;
static FooBar *exported_bar_object = NULL;
static FooBat *exported_bat_object = NULL;
static FooAuthorize *exported_authorize_object = NULL;
static GDBusObjectSkeleton *authorize_enclosing_object = NULL;
static FooMethodThreads *exported_thread_object_1 = NULL;
static FooMethodThreads *exported_thread_object_2 = NULL;
static void
on_bus_acquired (GDBusConnection *connection,
const gchar *name,
gpointer user_data)
{
GError *error;
/* Test that we can export an object using the generated
* FooBarSkeleton subclass. Notes:
*
* 1. We handle methods by simply connecting to the appropriate
* GObject signal.
*
* 2. Property storage is taken care of by the class; we can
* use g_object_get()/g_object_set() (and the generated
* C bindings at will)
*/
error = NULL;
exported_bar_object = foo_bar_skeleton_new ();
foo_bar_set_ay (exported_bar_object, "ABCabc");
foo_bar_set_y (exported_bar_object, 42);
foo_bar_set_d (exported_bar_object, 43.0);
foo_bar_set_finally_normal_name (exported_bar_object, "There aint no place like home");
foo_bar_set_writeonly_property (exported_bar_object, "Mr. Burns");
/* The following works because it's on the Skeleton object - it will
* fail (at run-time) on a Proxy (see on_proxy_appeared() below)
*/
foo_bar_set_readonly_property (exported_bar_object, "blah");
g_assert_cmpstr (foo_bar_get_writeonly_property (exported_bar_object), ==, "Mr. Burns");
g_dbus_interface_skeleton_export (G_DBUS_INTERFACE_SKELETON (exported_bar_object),
connection,
"/bar",
&error);
g_assert_no_error (error);
g_signal_connect (exported_bar_object,
"handle-hello-world",
G_CALLBACK (on_handle_hello_world),
NULL);
g_signal_connect (exported_bar_object,
"handle-test-primitive-types",
G_CALLBACK (on_handle_test_primitive_types),
NULL);
g_signal_connect (exported_bar_object,
"handle-test-non-primitive-types",
G_CALLBACK (on_handle_test_non_primitive_types),
NULL);
g_signal_connect (exported_bar_object,
"handle-request-signal-emission",
G_CALLBACK (on_handle_request_signal_emission),
NULL);
g_signal_connect (exported_bar_object,
"handle-request-multi-property-mods",
G_CALLBACK (on_handle_request_multi_property_mods),
NULL);
g_signal_connect (exported_bar_object,
"handle-property-cancellation",
G_CALLBACK (on_handle_property_cancellation),
NULL);
exported_bat_object = foo_bat_skeleton_new ();
g_dbus_interface_skeleton_export (G_DBUS_INTERFACE_SKELETON (exported_bat_object),
connection,
"/bat",
&error);
g_assert_no_error (error);
g_signal_connect (exported_bat_object,
"handle-force-method",
G_CALLBACK (on_handle_force_method),
NULL);
g_object_set (exported_bat_object,
"force-i", g_variant_new_int32 (43),
"force-s", g_variant_new_string ("prop string"),
"force-ay", g_variant_new_bytestring ("prop bytestring\xff"),
"force-struct", g_variant_new ("(i)", 4300),
NULL);
authorize_enclosing_object = g_dbus_object_skeleton_new ("/authorize");
g_signal_connect (authorize_enclosing_object,
"authorize-method",
G_CALLBACK (my_object_authorize_method_handler),
NULL);
exported_authorize_object = foo_authorize_skeleton_new ();
g_dbus_object_skeleton_add_interface (authorize_enclosing_object,
G_DBUS_INTERFACE_SKELETON (exported_authorize_object));
g_dbus_interface_skeleton_export (G_DBUS_INTERFACE_SKELETON (exported_authorize_object),
connection,
"/authorize",
&error);
g_assert_no_error (error);
g_signal_connect (exported_authorize_object,
"g-authorize-method",
G_CALLBACK (my_g_authorize_method_handler),
NULL);
g_signal_connect (exported_authorize_object,
"handle-check-not-authorized",
G_CALLBACK (on_handle_check_not_authorized),
NULL);
g_signal_connect (exported_authorize_object,
"handle-check-authorized",
G_CALLBACK (on_handle_check_authorized),
NULL);
g_signal_connect (exported_authorize_object,
"handle-check-not-authorized-from-object",
G_CALLBACK (on_handle_check_not_authorized_from_object),
NULL);
/* only object 1 has the G_DBUS_INTERFACE_SKELETON_FLAGS_HANDLE_METHOD_INVOCATIONS_IN_THREAD flag set */
exported_thread_object_1 = foo_method_threads_skeleton_new ();
g_dbus_interface_skeleton_set_flags (G_DBUS_INTERFACE_SKELETON (exported_thread_object_1),
G_DBUS_INTERFACE_SKELETON_FLAGS_HANDLE_METHOD_INVOCATIONS_IN_THREAD);
g_dbus_interface_skeleton_export (G_DBUS_INTERFACE_SKELETON (exported_thread_object_1),
connection,
"/method_threads_1",
&error);
g_assert_no_error (error);
g_signal_connect (exported_thread_object_1,
"handle-get-self",
G_CALLBACK (on_handle_get_self),
NULL);
exported_thread_object_2 = foo_method_threads_skeleton_new ();
g_dbus_interface_skeleton_export (G_DBUS_INTERFACE_SKELETON (exported_thread_object_2),
connection,
"/method_threads_2",
&error);
g_assert_no_error (error);
g_signal_connect (exported_thread_object_2,
"handle-get-self",
G_CALLBACK (on_handle_get_self),
NULL);
method_handler_thread = g_thread_self ();
}
static gpointer check_proxies_in_thread (gpointer user_data);
static void
on_name_acquired (GDBusConnection *connection,
const gchar *name,
gpointer user_data)
{
GMainLoop *loop = user_data;
g_thread_create (check_proxies_in_thread,
loop,
TRUE,
NULL);
}
static void
on_name_lost (GDBusConnection *connection,
const gchar *name,
gpointer user_data)
{
g_assert_not_reached ();
}
/* ---------------------------------------------------------------------------------------------------- */
typedef struct
{
GMainLoop *thread_loop;
gint initial_y;
gint initial_i;
guint num_g_properties_changed;
gboolean received_test_signal;
guint num_notify_u;
guint num_notify_n;
} ClientData;
static void
on_notify_u (GObject *object,
GParamSpec *pspec,
gpointer user_data)
{
ClientData *data = user_data;
g_assert_cmpstr (pspec->name, ==, "u");
data->num_notify_u += 1;
}
static void
on_notify_n (GObject *object,
GParamSpec *pspec,
gpointer user_data)
{
ClientData *data = user_data;
g_assert_cmpstr (pspec->name, ==, "n");
data->num_notify_n += 1;
}
static void
on_g_properties_changed (GDBusProxy *_proxy,
GVariant *changed_properties,
const gchar* const *invalidated_properties,
gpointer user_data)
{
ClientData *data = user_data;
FooBar *proxy = FOO_BAR (_proxy);
g_assert_cmpint (g_variant_n_children (changed_properties), ==, 2);
if (data->num_g_properties_changed == 0)
{
g_assert_cmpint (data->initial_y, ==, foo_bar_get_y (proxy) - 2);
g_assert_cmpint (data->initial_i, ==, foo_bar_get_i (proxy) - 2);
}
else if (data->num_g_properties_changed == 1)
{
g_assert_cmpint (data->initial_y, ==, foo_bar_get_y (proxy) - 3);
g_assert_cmpint (data->initial_i, ==, foo_bar_get_i (proxy) - 3);
}
else
g_assert_not_reached ();
data->num_g_properties_changed++;
if (data->num_g_properties_changed == 2)
g_main_loop_quit (data->thread_loop);
}
static void
on_test_signal (FooBar *proxy,
gint val_int32,
const gchar* const *array_of_strings,
const gchar* const *array_of_bytestrings,
GVariant *dict_s_to_pairs,
gpointer user_data)
{
ClientData *data = user_data;
g_assert_cmpint (val_int32, ==, 43);
g_assert_cmpstr (array_of_strings[0], ==, "foo");
g_assert_cmpstr (array_of_strings[1], ==, "bar");
g_assert (array_of_strings[2] == NULL);
g_assert_cmpstr (array_of_bytestrings[0], ==, "foo\xff");
g_assert_cmpstr (array_of_bytestrings[1], ==, "bar\xff");
g_assert (array_of_bytestrings[2] == NULL);
data->received_test_signal = TRUE;
g_main_loop_quit (data->thread_loop);
}
static void
on_property_cancellation_cb (FooBar *proxy,
GAsyncResult *res,
gpointer user_data)
{
ClientData *data = user_data;
gboolean ret;
GError *error = NULL;
error = NULL;
ret = foo_bar_call_property_cancellation_finish (proxy, res, &error);
g_assert_no_error (error);
g_assert (ret);
g_main_loop_quit (data->thread_loop);
}
static void
check_bar_proxy (FooBar *proxy,
GMainLoop *thread_loop)
{
guchar ret_val_byte;
gboolean ret_val_boolean;
gint16 ret_val_int16;
guint16 ret_val_uint16;
gint ret_val_int32;
guint ret_val_uint32;
gint64 ret_val_int64;
guint64 ret_val_uint64;
gdouble ret_val_double;
gchar *ret_val_string;
gchar *ret_val_objpath;
gchar *ret_val_signature;
gchar *ret_val_bytestring;
gboolean ret;
GError *error;
ClientData *data;
guchar val_y;
gboolean val_b;
gint val_n;
guint val_q;
gint val_i;
guint val_u;
gint64 val_x;
guint64 val_t;
gdouble val_d;
gchar *val_s;
gchar *val_o;
gchar *val_g;
gchar *val_ay;
gchar **val_as;
gchar **val_ao;
GVariant *val_ag;
gint32 val_unset_i;
gdouble val_unset_d;
gchar *val_unset_s;
gchar *val_unset_o;
gchar *val_unset_g;
gchar *val_unset_ay;
gchar **val_unset_as;
gchar **val_unset_ao;
GVariant *val_unset_ag;
GVariant *val_unset_struct;
gchar *val_finally_normal_name;
GVariant *v;
gchar *s;
data = g_new0 (ClientData, 1);
data->thread_loop = thread_loop;
v = g_dbus_proxy_get_cached_property (G_DBUS_PROXY (proxy), "y");
g_assert (v != NULL);
g_variant_unref (v);
/* set empty values to non-empty */
val_unset_i = 42;
val_unset_d = 42.0;
val_unset_s = "42";
val_unset_o = "42";
val_unset_g = "42";
val_unset_ay = NULL;
val_unset_as = NULL;
val_unset_ao = NULL;
val_unset_ag = NULL;
val_unset_struct = NULL;
/* check properties */
g_object_get (proxy,
"y", &val_y,
"b", &val_b,
"n", &val_n,
"q", &val_q,
"i", &val_i,
"u", &val_u,
"x", &val_x,
"t", &val_t,
"d", &val_d,
"s", &val_s,
"o", &val_o,
"g", &val_g,
"ay", &val_ay,
"as", &val_as,
"ao", &val_ao,
"ag", &val_ag,
"unset_i", &val_unset_i,
"unset_d", &val_unset_d,
"unset_s", &val_unset_s,
"unset_o", &val_unset_o,
"unset_g", &val_unset_g,
"unset_ay", &val_unset_ay,
"unset_as", &val_unset_as,
"unset_ao", &val_unset_ao,
"unset_ag", &val_unset_ag,
"unset_struct", &val_unset_struct,
"finally-normal-name", &val_finally_normal_name,
NULL);
g_assert_cmpint (val_y, ==, 42);
g_assert_cmpstr (val_finally_normal_name, ==, "There aint no place like home");
g_free (val_s);
g_free (val_o);
g_free (val_g);
g_assert_cmpstr (val_ay, ==, "ABCabc");
g_free (val_ay);
g_strfreev (val_as);
g_strfreev (val_ao);
g_variant_unref (val_ag);
g_free (val_finally_normal_name);
/* check empty values */
g_assert_cmpint (val_unset_i, ==, 0);
g_assert_cmpfloat (val_unset_d, ==, 0.0);
g_assert_cmpstr (val_unset_s, ==, "");
g_assert_cmpstr (val_unset_o, ==, "/");
g_assert_cmpstr (val_unset_g, ==, "");
g_free (val_unset_s);
g_free (val_unset_o);
g_free (val_unset_g);
g_assert_cmpstr (val_unset_ay, ==, "");
g_assert (val_unset_as[0] == NULL);
g_assert (val_unset_ao[0] == NULL);
g_assert (g_variant_is_of_type (val_unset_ag, G_VARIANT_TYPE ("ag")));
g_assert (g_variant_is_of_type (val_unset_struct, G_VARIANT_TYPE ("(idsogayasaoag)")));
s = g_variant_print (val_unset_struct, TRUE);
g_assert_cmpstr (s, ==, "(0, 0.0, '', objectpath '/', signature '', @ay [], @as [], @ao [], @ag [])");
g_free (s);
g_free (val_unset_ay);
g_strfreev (val_unset_as);
g_strfreev (val_unset_ao);
g_variant_unref (val_unset_ag);
g_variant_unref (val_unset_struct);
/* Try setting a property. This causes the generated glue to invoke
* the org.fd.DBus.Properties.Set() method asynchronously. So we
* have to wait for properties-changed...
*/
foo_bar_set_finally_normal_name (proxy, "foo!");
_g_assert_property_notify (proxy, "finally-normal-name");
g_assert_cmpstr (foo_bar_get_finally_normal_name (proxy), ==, "foo!");
/* Try setting properties that requires memory management. This
* is to exercise the paths that frees the references.
*/
const gchar *array_of_strings[3] = {"one", "two", NULL};
const gchar *array_of_strings_2[3] = {"one2", "two2", NULL};
const gchar *array_of_objpaths[3] = {"/one", "/one/two", NULL};
const gchar *array_of_bytestrings[3] = {"one\xff", "two\xff", NULL};
g_object_set (proxy,
"s", "a string",
"o", "/a/path",
"g", "asig",
"ay", g_variant_new_parsed ("[byte 0x65, 0x67]"),
"as", array_of_strings,
"ao", array_of_objpaths,
"ag", g_variant_new_parsed ("[@g 'ass', 'git']"),
NULL);
error = NULL;
ret = foo_bar_call_test_primitive_types_sync (proxy,
10,
TRUE,
11,
12,
13,
14,
15,
16,
17,
"a string",
"/a/path",
"asig",
"bytestring\xff",
&ret_val_byte,
&ret_val_boolean,
&ret_val_int16,
&ret_val_uint16,
&ret_val_int32,
&ret_val_uint32,
&ret_val_int64,
&ret_val_uint64,
&ret_val_double,
&ret_val_string,
&ret_val_objpath,
&ret_val_signature,
&ret_val_bytestring,
NULL, /* GCancellable */
&error);
g_assert_no_error (error);
g_assert (ret);
error = NULL;
ret = foo_bar_call_test_non_primitive_types_sync (proxy,
g_variant_new_parsed ("{'one': 'red',"
" 'two': 'blue'}"),
g_variant_new_parsed ("{'first': (42, 42), "
"'second': (43, 43)}"),
g_variant_new_parsed ("(42, 'foo', 'bar')"),
array_of_strings,
array_of_objpaths,
g_variant_new_parsed ("[@g 'ass', 'git']"),
array_of_bytestrings,
&s,
NULL, /* GCancellable */
&error);
g_assert_no_error (error);
g_assert (ret);
/* Check that org.freedesktop.DBus.Error.UnknownMethod is returned on
* unimplemented methods.
*/
error = NULL;
ret = foo_bar_call_unimplemented_method_sync (proxy, NULL /* GCancellable */, &error);
g_assert_error (error, G_DBUS_ERROR, G_DBUS_ERROR_UNKNOWN_METHOD);
g_error_free (error);
error = NULL;
g_assert (!ret);
g_signal_connect (proxy,
"test-signal",
G_CALLBACK (on_test_signal),
data);
error = NULL;
ret = foo_bar_call_request_signal_emission_sync (proxy, 0, NULL, &error);
g_assert_no_error (error);
g_assert (ret);
g_assert (!data->received_test_signal);
g_main_loop_run (thread_loop);
g_assert (data->received_test_signal);
/* Try setting a property. This causes the generated glue to invoke
* the org.fd.DBus.Properties.Set() method asynchronously. So we
* have to wait for properties-changed...
*/
foo_bar_set_finally_normal_name (proxy, "hey back!");
_g_assert_property_notify (proxy, "finally-normal-name");
g_assert_cmpstr (foo_bar_get_finally_normal_name (proxy), ==, "hey back!");
/* Check that multiple calls to a strv getter works... and that
* updates on them works as well (See comment for "property vfuncs"
* in gio/gdbus-codegen/codegen.py for details)
*/
const gchar *const *read_as;
const gchar *const *read_as2;
const gchar *const *read_as3;
read_as = foo_bar_get_as (proxy);
read_as2 = foo_bar_get_as (proxy);
g_assert_cmpint (g_strv_length ((gchar **) read_as), ==, 2);
g_assert_cmpstr (read_as[0], ==, "one");
g_assert_cmpstr (read_as[1], ==, "two");
g_assert (read_as == read_as2); /* this is more testing an implementation detail */
g_object_set (proxy,
"as", array_of_strings_2,
NULL);
_g_assert_property_notify (proxy, "as");
read_as3 = foo_bar_get_as (proxy);
g_assert_cmpint (g_strv_length ((gchar **) read_as3), ==, 2);
g_assert_cmpstr (read_as3[0], ==, "one2");
g_assert_cmpstr (read_as3[1], ==, "two2");
/* Check that grouping changes in idle works.
*
* See on_handle_request_multi_property_mods(). The server should
* emit exactly two PropertiesChanged signals each containing two
* properties.
*
* On the first reception, y and i should both be increased by
* two. On the the second reception, only by one. The signal handler
* checks this.
*
* This also checks that _drain_notify() works.
*/
data->initial_y = foo_bar_get_y (proxy);
data->initial_i = foo_bar_get_i (proxy);
g_signal_connect (proxy,
"g-properties-changed",
G_CALLBACK (on_g_properties_changed),
data);
error = NULL;
ret = foo_bar_call_request_multi_property_mods_sync (proxy, NULL, &error);
g_assert_no_error (error);
g_assert (ret);
g_main_loop_run (thread_loop);
g_assert_cmpint (data->num_g_properties_changed, ==, 2);
g_signal_handlers_disconnect_by_func (proxy,
G_CALLBACK (on_g_properties_changed),
data);
/* Check that we don't emit PropertiesChanged() if the property
* didn't change... we actually get two notifies.. one for the
* local set (without a value change) and one when receiving
* the PropertiesChanged() signal generated from the remote end.
*/
g_assert_cmpint (data->num_notify_u, ==, 0);
g_signal_connect (proxy,
"notify::u",
G_CALLBACK (on_notify_u),
data);
foo_bar_set_u (proxy, 1042);
g_assert_cmpint (data->num_notify_u, ==, 1);
g_assert_cmpint (foo_bar_get_u (proxy), ==, 0);
_g_assert_property_notify (proxy, "u");
g_assert_cmpint (foo_bar_get_u (proxy), ==, 1042);
g_assert_cmpint (data->num_notify_u, ==, 2);
/* Now change u again to the same value.. this will cause a
* local notify:: notify and the usual Properties.Set() call
*
* (Btw, why also the Set() call if the value in the cache is
* the same? Because someone else might have changed it
* in the mean time and we're just waiting to receive the
* PropertiesChanged() signal...)
*
* More tricky - how do we check for the *absence* of the
* notification that u changed? Simple: we change another
* property and wait for that PropertiesChanged() message
* to arrive.
*/
foo_bar_set_u (proxy, 1042);
g_assert_cmpint (data->num_notify_u, ==, 3);
g_assert_cmpint (data->num_notify_n, ==, 0);
g_signal_connect (proxy,
"notify::n",
G_CALLBACK (on_notify_n),
data);
foo_bar_set_n (proxy, 10042);
g_assert_cmpint (data->num_notify_n, ==, 1);
g_assert_cmpint (foo_bar_get_n (proxy), ==, 0);
_g_assert_property_notify (proxy, "n");
g_assert_cmpint (foo_bar_get_n (proxy), ==, 10042);
g_assert_cmpint (data->num_notify_n, ==, 2);
/* Checks that u didn't change at all */
g_assert_cmpint (data->num_notify_u, ==, 3);
/* Now we check that if the service does
*
* guint n = foo_bar_get_n (foo);
* foo_bar_set_n (foo, n + 1);
* foo_bar_set_n (foo, n);
*
* then no PropertiesChanged() signal is emitted!
*/
error = NULL;
foo_bar_call_property_cancellation (proxy,
NULL, /* GCancellable */
(GAsyncReadyCallback) on_property_cancellation_cb,
data);
g_main_loop_run (thread_loop);
/* Checks that n didn't change at all */
g_assert_cmpint (data->num_notify_n, ==, 2);
/* cleanup */
g_free (data);
}
/* ---------------------------------------------------------------------------------------------------- */
static void
on_force_signal (FooBat *proxy,
GVariant *force_i,
GVariant *force_s,
GVariant *force_ay,
GVariant *force_struct,
gpointer user_data)
{
gboolean *signal_received = user_data;
gint val;
g_assert (!(*signal_received));
g_assert_cmpint (g_variant_get_int32 (force_i), ==, 42 + 10);
g_assert_cmpstr (g_variant_get_string (force_s, NULL), ==, "a string_foo");
g_assert_cmpstr (g_variant_get_bytestring (force_ay), ==, "a bytestring\xff_foo\xff");
g_variant_get (force_struct, "(i)", &val);
g_assert_cmpint (val, ==, 4200 + 10);
*signal_received = TRUE;
}
static void
check_bat_proxy (FooBat *proxy,
GMainLoop *thread_loop)
{
GError *error;
GVariant *ret_i;
GVariant *ret_s;
GVariant *ret_ay;
GVariant *ret_struct;
gint val;
gboolean force_signal_received;
/* --------------------------------------------------- */
/* Check type-mapping where we force use of a GVariant */
/* --------------------------------------------------- */
/* check properties */
g_object_get (proxy,
"force-i", &ret_i,
"force-s", &ret_s,
"force-ay", &ret_ay,
"force-struct", &ret_struct,
NULL);
g_assert_cmpint (g_variant_get_int32 (ret_i), ==, 43);
g_assert_cmpstr (g_variant_get_string (ret_s, NULL), ==, "prop string");
g_assert_cmpstr (g_variant_get_bytestring (ret_ay), ==, "prop bytestring\xff");
g_variant_get (ret_struct, "(i)", &val);
g_assert_cmpint (val, ==, 4300);
g_variant_unref (ret_i);
g_variant_unref (ret_s);
g_variant_unref (ret_ay);
g_variant_unref (ret_struct);
/* check method and signal */
force_signal_received = FALSE;
g_signal_connect (proxy,
"force-signal",
G_CALLBACK (on_force_signal),
&force_signal_received);
error = NULL;
foo_bat_call_force_method_sync (proxy,
g_variant_new_int32 (42),
g_variant_new_string ("a string"),
g_variant_new_bytestring ("a bytestring\xff"),
g_variant_new ("(i)", 4200),
&ret_i,
&ret_s,
&ret_ay,
&ret_struct,
NULL, /* GCancellable* */
&error);
g_assert_no_error (error);
g_assert_cmpint (g_variant_get_int32 (ret_i), ==, 42 + 10);
g_assert_cmpstr (g_variant_get_string (ret_s, NULL), ==, "a string_foo");
g_assert_cmpstr (g_variant_get_bytestring (ret_ay), ==, "a bytestring\xff_foo\xff");
g_variant_get (ret_struct, "(i)", &val);
g_assert_cmpint (val, ==, 4200 + 10);
g_variant_unref (ret_i);
g_variant_unref (ret_s);
g_variant_unref (ret_ay);
g_variant_unref (ret_struct);
_g_assert_signal_received (proxy, "force-signal");
g_assert (force_signal_received);
}
/* ---------------------------------------------------------------------------------------------------- */
static void
check_authorize_proxy (FooAuthorize *proxy,
GMainLoop *thread_loop)
{
GError *error;
gboolean ret;
/* Check that g-authorize-method works as intended */
error = NULL;
ret = foo_authorize_call_check_not_authorized_sync (proxy, NULL, &error);
g_assert_error (error, G_IO_ERROR, G_IO_ERROR_PERMISSION_DENIED);
g_error_free (error);
g_assert (!ret);
error = NULL;
ret = foo_authorize_call_check_authorized_sync (proxy, NULL, &error);
g_assert_no_error (error);
g_assert (ret);
error = NULL;
ret = foo_authorize_call_check_not_authorized_from_object_sync (proxy, NULL, &error);
g_assert_error (error, G_IO_ERROR, G_IO_ERROR_PENDING);
g_error_free (error);
g_assert (!ret);
}
/* ---------------------------------------------------------------------------------------------------- */
static GThread *
get_self_via_proxy (FooMethodThreads *proxy_1)
{
GError *error;
gchar *self_str;
gboolean ret;
gpointer self;
error = NULL;
ret = foo_method_threads_call_get_self_sync (proxy_1, &self_str, NULL, &error);
g_assert_no_error (error);
g_assert (ret);
g_assert_cmpint (sscanf (self_str, "%p", &self), ==, 1);
g_free (self_str);
return self;
}
static void
check_thread_proxies (FooMethodThreads *proxy_1,
FooMethodThreads *proxy_2,
GMainLoop *thread_loop)
{
/* proxy_1 is indeed using threads so should never get the handler thread */
g_assert (get_self_via_proxy (proxy_1) != method_handler_thread);
/* proxy_2 is not using threads so should get the handler thread */
g_assert (get_self_via_proxy (proxy_2) == method_handler_thread);
}
/* ---------------------------------------------------------------------------------------------------- */
static gpointer
check_proxies_in_thread (gpointer user_data)
{
GMainLoop *loop = user_data;
GMainContext *thread_context;
GMainLoop *thread_loop;
GError *error;
FooBar *bar_proxy;
FooBat *bat_proxy;
FooAuthorize *authorize_proxy;
FooMethodThreads *thread_proxy_1;
FooMethodThreads *thread_proxy_2;
thread_context = g_main_context_new ();
thread_loop = g_main_loop_new (thread_context, FALSE);
g_main_context_push_thread_default (thread_context);
/* Check the object */
error = NULL;
bar_proxy = foo_bar_proxy_new_for_bus_sync (G_BUS_TYPE_SESSION,
G_DBUS_PROXY_FLAGS_NONE,
"org.gtk.GDBus.BindingsTool.Test",
"/bar",
NULL, /* GCancellable* */
&error);
check_bar_proxy (bar_proxy, thread_loop);
g_assert_no_error (error);
g_object_unref (bar_proxy);
error = NULL;
bat_proxy = foo_bat_proxy_new_for_bus_sync (G_BUS_TYPE_SESSION,
G_DBUS_PROXY_FLAGS_NONE,
"org.gtk.GDBus.BindingsTool.Test",
"/bat",
NULL, /* GCancellable* */
&error);
check_bat_proxy (bat_proxy, thread_loop);
g_assert_no_error (error);
g_object_unref (bat_proxy);
error = NULL;
authorize_proxy = foo_authorize_proxy_new_for_bus_sync (G_BUS_TYPE_SESSION,
G_DBUS_PROXY_FLAGS_NONE,
"org.gtk.GDBus.BindingsTool.Test",
"/authorize",
NULL, /* GCancellable* */
&error);
check_authorize_proxy (authorize_proxy, thread_loop);
g_assert_no_error (error);
g_object_unref (authorize_proxy);
error = NULL;
thread_proxy_1 = foo_method_threads_proxy_new_for_bus_sync (G_BUS_TYPE_SESSION,
G_DBUS_PROXY_FLAGS_NONE,
"org.gtk.GDBus.BindingsTool.Test",
"/method_threads_1",
NULL, /* GCancellable* */
&error);
g_assert_no_error (error);
thread_proxy_2 = foo_method_threads_proxy_new_for_bus_sync (G_BUS_TYPE_SESSION,
G_DBUS_PROXY_FLAGS_NONE,
"org.gtk.GDBus.BindingsTool.Test",
"/method_threads_2",
NULL, /* GCancellable* */
&error);
g_assert_no_error (error);
check_thread_proxies (thread_proxy_1, thread_proxy_2, thread_loop);
g_object_unref (thread_proxy_1);
g_object_unref (thread_proxy_2);
g_main_loop_unref (thread_loop);
g_main_context_unref (thread_context);
/* this breaks out of the loop in main() (below) */
g_main_loop_quit (loop);
return NULL;
}
/* ---------------------------------------------------------------------------------------------------- */
typedef struct
{
gchar *xml;
GMainLoop *loop;
} IntrospectData;
static void
introspect_cb (GDBusConnection *connection,
GAsyncResult *res,
gpointer user_data)
{
IntrospectData *data = user_data;
GVariant *result;
GError *error;
error = NULL;
result = g_dbus_connection_call_finish (connection,
res,
&error);
g_assert_no_error (error);
g_assert (result != NULL);
g_variant_get (result, "(s)", &data->xml);
g_variant_unref (result);
g_main_loop_quit (data->loop);
}
static GDBusNodeInfo *
introspect (GDBusConnection *connection,
const gchar *name,
const gchar *object_path,
GMainLoop *loop)
{
GError *error;
GDBusNodeInfo *node_info;
IntrospectData *data;
data = g_new0 (IntrospectData, 1);
data->xml = NULL;
data->loop = loop;
/* do this async to avoid deadlocks */
g_dbus_connection_call (connection,
name,
object_path,
"org.freedesktop.DBus.Introspectable",
"Introspect",
NULL, /* params */
G_VARIANT_TYPE ("(s)"),
G_DBUS_CALL_FLAGS_NONE,
-1,
NULL,
(GAsyncReadyCallback) introspect_cb,
data);
g_main_loop_run (loop);
g_assert (data->xml != NULL);
error = NULL;
node_info = g_dbus_node_info_new_for_xml (data->xml, &error);
g_assert_no_error (error);
g_assert (node_info != NULL);
g_free (data->xml);
g_free (data);
return node_info;
}
static guint
count_interfaces (GDBusNodeInfo *info)
{
guint n;
for (n = 0; info->interfaces != NULL && info->interfaces[n] != NULL; n++)
;
return n;
}
static guint
count_nodes (GDBusNodeInfo *info)
{
guint n;
for (n = 0; info->nodes != NULL && info->nodes[n] != NULL; n++)
;
return n;
}
static guint
has_interface (GDBusNodeInfo *info,
const gchar *name)
{
guint n;
for (n = 0; info->interfaces != NULL && info->interfaces[n] != NULL; n++)
{
if (g_strcmp0 (info->interfaces[n]->name, name) == 0)
return TRUE;
}
return FALSE;
}
/* ---------------------------------------------------------------------------------------------------- */
typedef struct {
GMainLoop *loop;
GVariant *result;
} OMGetManagedObjectsData;
static void
om_get_all_cb (GDBusConnection *connection,
GAsyncResult *res,
gpointer user_data)
{
OMGetManagedObjectsData *data = user_data;
GError *error;
error = NULL;
data->result = g_dbus_connection_call_finish (connection,
res,
&error);
g_assert_no_error (error);
g_assert (data->result != NULL);
g_main_loop_quit (data->loop);
}
static void
om_check_get_all (GDBusConnection *c,
GMainLoop *loop,
const gchar *str)
{
OMGetManagedObjectsData data;
gchar *s;
data.loop = loop;
data.result = NULL;
/* do this async to avoid deadlocks */
g_dbus_connection_call (c,
g_dbus_connection_get_unique_name (c),
"/managed",
"org.freedesktop.DBus.ObjectManager",
"GetManagedObjects",
NULL, /* params */
G_VARIANT_TYPE ("(a{oa{sa{sv}}})"),
G_DBUS_CALL_FLAGS_NONE,
-1,
NULL,
(GAsyncReadyCallback) om_get_all_cb,
&data);
g_main_loop_run (loop);
g_assert (data.result != NULL);
s = g_variant_print (data.result, TRUE);
g_assert_cmpstr (s, ==, str);
g_free (s);
g_variant_unref (data.result);
}
typedef struct
{
GMainLoop *loop;
guint state;
guint num_object_proxy_added_signals;
guint num_object_proxy_removed_signals;
guint num_interface_added_signals;
guint num_interface_removed_signals;
} OMData;
static gint
my_pstrcmp (const gchar **a, const gchar **b)
{
return g_strcmp0 (*a, *b);
}
static void
om_check_interfaces_added (const gchar *signal_name,
GVariant *parameters,
const gchar *object_path,
const gchar *first_interface_name,
...)
{
const gchar *path;
GVariant *array;
guint n;
GPtrArray *interfaces;
GPtrArray *interfaces_in_message;
va_list var_args;
const gchar *str;
interfaces = g_ptr_array_new ();
g_ptr_array_add (interfaces, (gpointer) first_interface_name);
va_start (var_args, first_interface_name);
do
{
str = va_arg (var_args, const gchar *);
if (str == NULL)
break;
g_ptr_array_add (interfaces, (gpointer) str);
}
while (TRUE);
va_end (var_args);
g_variant_get (parameters, "(&o*)", &path, &array);
g_assert_cmpstr (signal_name, ==, "InterfacesAdded");
g_assert_cmpstr (path, ==, object_path);
g_assert_cmpint (g_variant_n_children (array), ==, interfaces->len);
interfaces_in_message = g_ptr_array_new ();
for (n = 0; n < interfaces->len; n++)
{
const gchar *iface_name;
g_variant_get_child (array, n, "{&sa{sv}}", &iface_name, NULL);
g_ptr_array_add (interfaces_in_message, (gpointer) iface_name);
}
g_assert_cmpint (interfaces_in_message->len, ==, interfaces->len);
g_ptr_array_sort (interfaces, (GCompareFunc) my_pstrcmp);
g_ptr_array_sort (interfaces_in_message, (GCompareFunc) my_pstrcmp);
for (n = 0; n < interfaces->len; n++)
g_assert_cmpstr (interfaces->pdata[n], ==, interfaces_in_message->pdata[n]);
g_ptr_array_unref (interfaces_in_message);
g_ptr_array_unref (interfaces);
g_variant_unref (array);
}
static void
om_check_interfaces_removed (const gchar *signal_name,
GVariant *parameters,
const gchar *object_path,
const gchar *first_interface_name,
...)
{
const gchar *path;
GVariant *array;
guint n;
GPtrArray *interfaces;
GPtrArray *interfaces_in_message;
va_list var_args;
const gchar *str;
interfaces = g_ptr_array_new ();
g_ptr_array_add (interfaces, (gpointer) first_interface_name);
va_start (var_args, first_interface_name);
do
{
str = va_arg (var_args, const gchar *);
if (str == NULL)
break;
g_ptr_array_add (interfaces, (gpointer) str);
}
while (TRUE);
va_end (var_args);
g_variant_get (parameters, "(&o*)", &path, &array);
g_assert_cmpstr (signal_name, ==, "InterfacesRemoved");
g_assert_cmpstr (path, ==, object_path);
g_assert_cmpint (g_variant_n_children (array), ==, interfaces->len);
interfaces_in_message = g_ptr_array_new ();
for (n = 0; n < interfaces->len; n++)
{
const gchar *iface_name;
g_variant_get_child (array, n, "&s", &iface_name, NULL);
g_ptr_array_add (interfaces_in_message, (gpointer) iface_name);
}
g_assert_cmpint (interfaces_in_message->len, ==, interfaces->len);
g_ptr_array_sort (interfaces, (GCompareFunc) my_pstrcmp);
g_ptr_array_sort (interfaces_in_message, (GCompareFunc) my_pstrcmp);
for (n = 0; n < interfaces->len; n++)
g_assert_cmpstr (interfaces->pdata[n], ==, interfaces_in_message->pdata[n]);
g_ptr_array_unref (interfaces_in_message);
g_ptr_array_unref (interfaces);
g_variant_unref (array);
}
static void
om_on_signal (GDBusConnection *connection,
const gchar *sender_name,
const gchar *object_path,
const gchar *interface_name,
const gchar *signal_name,
GVariant *parameters,
gpointer user_data)
{
OMData *om_data = user_data;
//g_debug ("foo: %s", g_variant_print (parameters, TRUE));
switch (om_data->state)
{
default:
case 0:
g_print ("failing and om_data->state=%d on signal %s, params=%s\n",
om_data->state,
signal_name,
g_variant_print (parameters, TRUE));
g_assert_not_reached ();
break;
case 1:
om_check_interfaces_added (signal_name, parameters, "/managed/first",
"org.project.Bar", NULL);
om_data->state = 2;
g_main_loop_quit (om_data->loop);
break;
case 3:
om_check_interfaces_removed (signal_name, parameters, "/managed/first",
"org.project.Bar", NULL);
om_data->state = 5;
/* keep running the loop */
break;
case 5:
om_check_interfaces_added (signal_name, parameters, "/managed/first",
"org.project.Bar", NULL);
om_data->state = 6;
g_main_loop_quit (om_data->loop);
break;
case 7:
om_check_interfaces_removed (signal_name, parameters, "/managed/first",
"org.project.Bar", NULL);
om_data->state = 9;
/* keep running the loop */
break;
case 9:
om_check_interfaces_added (signal_name, parameters, "/managed/first",
"org.project.Bar", NULL);
om_data->state = 10;
g_main_loop_quit (om_data->loop);
break;
case 11:
om_check_interfaces_added (signal_name, parameters, "/managed/first",
"org.project.Bat", NULL);
om_data->state = 12;
g_main_loop_quit (om_data->loop);
break;
case 13:
om_check_interfaces_removed (signal_name, parameters, "/managed/first",
"org.project.Bar", NULL);
om_data->state = 14;
g_main_loop_quit (om_data->loop);
break;
case 15:
om_check_interfaces_removed (signal_name, parameters, "/managed/first",
"org.project.Bat", NULL);
om_data->state = 16;
g_main_loop_quit (om_data->loop);
break;
case 17:
om_check_interfaces_added (signal_name, parameters, "/managed/first",
"com.acme.Coyote", NULL);
om_data->state = 18;
g_main_loop_quit (om_data->loop);
break;
case 101:
om_check_interfaces_added (signal_name, parameters, "/managed/second",
"org.project.Bat", "org.project.Bar", NULL);
om_data->state = 102;
g_main_loop_quit (om_data->loop);
break;
case 103:
om_check_interfaces_removed (signal_name, parameters, "/managed/second",
"org.project.Bat", "org.project.Bar", NULL);
om_data->state = 104;
g_main_loop_quit (om_data->loop);
break;
}
}
static GAsyncResult *om_res = NULL;
static void
om_pm_start_cb (FooObjectManagerClient *manager,
GAsyncResult *res,
gpointer user_data)
{
GMainLoop *loop = user_data;
om_res = g_object_ref (res);
g_main_loop_quit (loop);
}
static void
on_interface_added (GDBusObject *object,
GDBusInterface *interface,
gpointer user_data)
{
OMData *om_data = user_data;
om_data->num_interface_added_signals += 1;
}
static void
on_interface_removed (GDBusObject *object,
GDBusInterface *interface,
gpointer user_data)
{
OMData *om_data = user_data;
om_data->num_interface_removed_signals += 1;
}
static void
on_object_proxy_added (GDBusObjectManagerClient *manager,
GDBusObjectProxy *object_proxy,
gpointer user_data)
{
OMData *om_data = user_data;
om_data->num_object_proxy_added_signals += 1;
g_signal_connect (object_proxy,
"interface-added",
G_CALLBACK (on_interface_added),
om_data);
g_signal_connect (object_proxy,
"interface-removed",
G_CALLBACK (on_interface_removed),
om_data);
}
static void
on_object_proxy_removed (GDBusObjectManagerClient *manager,
GDBusObjectProxy *object_proxy,
gpointer user_data)
{
OMData *om_data = user_data;
om_data->num_object_proxy_removed_signals += 1;
g_assert_cmpint (g_signal_handlers_disconnect_by_func (object_proxy,
G_CALLBACK (on_interface_added),
om_data), ==, 1);
g_assert_cmpint (g_signal_handlers_disconnect_by_func (object_proxy,
G_CALLBACK (on_interface_removed),
om_data), ==, 1);
}
static void
om_check_property_and_signal_emission (GMainLoop *loop,
FooBar *skeleton,
FooBar *proxy)
{
/* First PropertiesChanged */
g_assert_cmpint (foo_bar_get_i (skeleton), ==, 0);
g_assert_cmpint (foo_bar_get_i (proxy), ==, 0);
foo_bar_set_i (skeleton, 1);
_g_assert_property_notify (proxy, "i");
g_assert_cmpint (foo_bar_get_i (skeleton), ==, 1);
g_assert_cmpint (foo_bar_get_i (proxy), ==, 1);
/* Then just a regular signal */
foo_bar_emit_another_signal (skeleton, "word");
_g_assert_signal_received (proxy, "another-signal");
}
static void
check_object_manager (void)
{
FooObjectSkeleton *o;
FooObjectSkeleton *o2;
GDBusInterfaceSkeleton *i;
GDBusConnection *c;
GDBusObjectManagerServer *manager;
GDBusNodeInfo *info;
GError *error;
GMainLoop *loop;
OMData *om_data;
guint om_signal_id;
GDBusObjectManager *pm;
GList *object_proxies;
GList *proxies;
GDBusObject *op;
GDBusProxy *p;
FooBar *bar_skeleton;
loop = g_main_loop_new (NULL, FALSE);
om_data = g_new0 (OMData, 1);
om_data->loop = loop;
om_data->state = 0;
error = NULL;
c = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, &error);
g_assert_no_error (error);
g_assert (c != NULL);
om_signal_id = g_dbus_connection_signal_subscribe (c,
NULL, /* sender */
"org.freedesktop.DBus.ObjectManager",
NULL, /* member */
NULL, /* object_path */
NULL, /* arg0 */
G_DBUS_SIGNAL_FLAGS_NONE,
om_on_signal,
om_data,
NULL); /* user_data_free_func */
/* Our GDBusObjectManagerClient tests are simple - we basically just count the
* number of times the various signals have been emitted (we don't check
* that the right objects/interfaces are passed though - that's checked
* in the lower-level tests in om_on_signal()...)
*
* Note that these tests rely on the D-Bus signal handlers used by
* GDBusObjectManagerClient firing before om_on_signal().
*/
error = NULL;
pm = foo_object_manager_client_new_sync (c,
G_DBUS_OBJECT_MANAGER_CLIENT_FLAGS_NONE,
g_dbus_connection_get_unique_name (c),
"/managed",
NULL, /* GCancellable */
&error);
g_assert_error (error, G_DBUS_ERROR, G_DBUS_ERROR_UNKNOWN_METHOD);
g_error_free (error);
g_assert (pm == NULL);
manager = g_dbus_object_manager_server_new ("/managed");
g_dbus_object_manager_server_set_connection (manager, c);
/* Check that the manager object is visible */
info = introspect (c, g_dbus_connection_get_unique_name (c), "/managed", loop);
g_assert_cmpint (count_interfaces (info), ==, 4); /* ObjectManager + Properties,Introspectable,Peer */
g_assert (has_interface (info, "org.freedesktop.DBus.ObjectManager"));
g_assert_cmpint (count_nodes (info), ==, 0);
g_dbus_node_info_unref (info);
/* Check GetManagedObjects() - should be empty since we have no objects */
om_check_get_all (c, loop,
"(@a{oa{sa{sv}}} {},)");
/* Now try to create the the proxy manager again - this time it should work */
error = NULL;
foo_object_manager_client_new (c,
G_DBUS_OBJECT_MANAGER_CLIENT_FLAGS_NONE,
g_dbus_connection_get_unique_name (c),
"/managed",
NULL, /* GCancellable */
(GAsyncReadyCallback) om_pm_start_cb,
loop);
g_main_loop_run (loop);
error = NULL;
pm = foo_object_manager_client_new_finish (om_res, &error);
g_object_unref (om_res);
g_assert_no_error (error);
g_assert (pm != NULL);
g_signal_connect (pm,
"object-added",
G_CALLBACK (on_object_proxy_added),
om_data);
g_signal_connect (pm,
"object-removed",
G_CALLBACK (on_object_proxy_removed),
om_data);
/* ... check there are no object proxies yet */
object_proxies = g_dbus_object_manager_get_objects (pm);
g_assert (object_proxies == NULL);
/* First, export an object with a single interface (also check that
* g_dbus_interface_get_object() works and that the object isn't reffed)
*/
o = foo_object_skeleton_new ("/managed/first");
i = G_DBUS_INTERFACE_SKELETON (foo_bar_skeleton_new ());
g_assert (g_dbus_interface_get_object (G_DBUS_INTERFACE (i)) == NULL);
g_assert_cmpint (G_OBJECT (o)->ref_count, ==, 1);
foo_object_skeleton_set_bar (o, FOO_BAR (i));
g_assert_cmpint (G_OBJECT (o)->ref_count, ==, 1);
g_assert (g_dbus_interface_get_object (G_DBUS_INTERFACE (i)) == G_DBUS_OBJECT (o));
g_assert_cmpint (G_OBJECT (o)->ref_count, ==, 1);
g_assert_cmpint (G_OBJECT (o)->ref_count, ==, 1);
foo_object_skeleton_set_bar (o, NULL);
g_assert (g_dbus_interface_get_object (G_DBUS_INTERFACE (i)) == NULL);
g_assert_cmpint (G_OBJECT (o)->ref_count, ==, 1);
foo_object_skeleton_set_bar (o, FOO_BAR (i));
g_assert (g_dbus_interface_get_object (G_DBUS_INTERFACE (i)) == G_DBUS_OBJECT (o));
g_assert_cmpint (G_OBJECT (o)->ref_count, ==, 1);
g_dbus_object_manager_server_export (manager, G_DBUS_OBJECT_SKELETON (o));
/* ... check we get the InterfacesAdded signal */
om_data->state = 1;
g_main_loop_run (om_data->loop);
g_assert_cmpint (om_data->state, ==, 2);
g_assert_cmpint (om_data->num_object_proxy_added_signals, ==, 1);
g_assert_cmpint (om_data->num_object_proxy_removed_signals, ==, 0);
g_assert_cmpint (om_data->num_interface_added_signals, ==, 0);
g_assert_cmpint (om_data->num_interface_removed_signals, ==, 0);
/* ... check there's one non-standard interfaces */
info = introspect (c, g_dbus_connection_get_unique_name (c), "/managed/first", loop);
g_assert_cmpint (count_interfaces (info), ==, 4); /* Bar + Properties,Introspectable,Peer */
g_assert (has_interface (info, "org.project.Bar"));
g_dbus_node_info_unref (info);
/* Now, check adding the same interface replaces the existing one */
foo_object_skeleton_set_bar (o, FOO_BAR (i));
/* ... check we get the InterfacesRemoved */
om_data->state = 3;
g_main_loop_run (om_data->loop);
/* ... and then check we get the InterfacesAdded */
g_assert_cmpint (om_data->state, ==, 6);
g_assert_cmpint (om_data->num_object_proxy_added_signals, ==, 2);
g_assert_cmpint (om_data->num_object_proxy_removed_signals, ==, 1);
g_assert_cmpint (om_data->num_interface_added_signals, ==, 0);
g_assert_cmpint (om_data->num_interface_removed_signals, ==, 0);
/* ... check introspection data */
info = introspect (c, g_dbus_connection_get_unique_name (c), "/managed/first", loop);
g_assert_cmpint (count_interfaces (info), ==, 4); /* Bar + Properties,Introspectable,Peer */
g_assert (has_interface (info, "org.project.Bar"));
g_dbus_node_info_unref (info);
g_object_unref (i);
/* check adding an interface of same type (but not same object) replaces the existing one */
i = G_DBUS_INTERFACE_SKELETON (foo_bar_skeleton_new ());
foo_object_skeleton_set_bar (o, FOO_BAR (i));
/* ... check we get the InterfacesRemoved and then InterfacesAdded */
om_data->state = 7;
g_main_loop_run (om_data->loop);
g_assert_cmpint (om_data->state, ==, 10);
g_assert_cmpint (om_data->num_object_proxy_added_signals, ==, 3);
g_assert_cmpint (om_data->num_object_proxy_removed_signals, ==, 2);
g_assert_cmpint (om_data->num_interface_added_signals, ==, 0);
g_assert_cmpint (om_data->num_interface_removed_signals, ==, 0);
/* ... check introspection data */
info = introspect (c, g_dbus_connection_get_unique_name (c), "/managed/first", loop);
g_assert_cmpint (count_interfaces (info), ==, 4); /* Bar + Properties,Introspectable,Peer */
g_assert (has_interface (info, "org.project.Bar"));
g_dbus_node_info_unref (info);
g_object_unref (i);
/* check adding an interface of another type doesn't replace the existing one */
i = G_DBUS_INTERFACE_SKELETON (foo_bat_skeleton_new ());
foo_object_skeleton_set_bat (o, FOO_BAT (i));
g_object_unref (i);
/* ... check we get the InterfacesAdded */
om_data->state = 11;
g_main_loop_run (om_data->loop);
g_assert_cmpint (om_data->state, ==, 12);
g_assert_cmpint (om_data->num_object_proxy_added_signals, ==, 3);
g_assert_cmpint (om_data->num_object_proxy_removed_signals, ==, 2);
g_assert_cmpint (om_data->num_interface_added_signals, ==, 1);
g_assert_cmpint (om_data->num_interface_removed_signals, ==, 0);
/* ... check introspection data */
info = introspect (c, g_dbus_connection_get_unique_name (c), "/managed/first", loop);
g_assert_cmpint (count_interfaces (info), ==, 5); /* Bar,Bat + Properties,Introspectable,Peer */
g_assert (has_interface (info, "org.project.Bar"));
g_assert (has_interface (info, "org.project.Bat"));
g_dbus_node_info_unref (info);
/* check we can remove an interface */
foo_object_skeleton_set_bar (o, NULL);
/* ... check we get the InterfacesRemoved */
om_data->state = 13;
g_main_loop_run (om_data->loop);
g_assert_cmpint (om_data->state, ==, 14);
g_assert_cmpint (om_data->num_object_proxy_added_signals, ==, 3);
g_assert_cmpint (om_data->num_object_proxy_removed_signals, ==, 2);
g_assert_cmpint (om_data->num_interface_added_signals, ==, 1);
g_assert_cmpint (om_data->num_interface_removed_signals, ==, 1);
/* ... check introspection data */
info = introspect (c, g_dbus_connection_get_unique_name (c), "/managed/first", loop);
g_assert_cmpint (count_interfaces (info), ==, 4); /* Bat + Properties,Introspectable,Peer */
g_assert (has_interface (info, "org.project.Bat"));
g_dbus_node_info_unref (info);
/* also and that the call only has effect if the interface actually exists
*
* (Note: if a signal was emitted we'd assert in the signal handler
* because we're in state 14)
*/
foo_object_skeleton_set_bar (o, NULL);
/* ... check introspection data */
info = introspect (c, g_dbus_connection_get_unique_name (c), "/managed/first", loop);
g_assert_cmpint (count_interfaces (info), ==, 4); /* Bat + Properties,Introspectable,Peer */
g_assert (has_interface (info, "org.project.Bat"));
g_dbus_node_info_unref (info);
/* remove the last interface */
foo_object_skeleton_set_bat (o, NULL);
/* ... check we get the InterfacesRemoved */
om_data->state = 15;
g_main_loop_run (om_data->loop);
g_assert_cmpint (om_data->state, ==, 16);
g_assert_cmpint (om_data->num_object_proxy_added_signals, ==, 3);
g_assert_cmpint (om_data->num_object_proxy_removed_signals, ==, 3);
g_assert_cmpint (om_data->num_interface_added_signals, ==, 1);
g_assert_cmpint (om_data->num_interface_removed_signals, ==, 1);
/* ... check introspection data */
info = introspect (c, g_dbus_connection_get_unique_name (c), "/managed/first", loop);
g_assert_cmpint (count_interfaces (info), ==, 0); /* nothing */
g_dbus_node_info_unref (info);
/* and add an interface again */
i = G_DBUS_INTERFACE_SKELETON (foo_com_acme_coyote_skeleton_new ());
foo_object_skeleton_set_com_acme_coyote (o, FOO_COM_ACME_COYOTE (i));
g_object_unref (i);
/* ... check we get the InterfacesAdded */
om_data->state = 17;
g_main_loop_run (om_data->loop);
g_assert_cmpint (om_data->state, ==, 18);
g_assert_cmpint (om_data->num_object_proxy_added_signals, ==, 4);
g_assert_cmpint (om_data->num_object_proxy_removed_signals, ==, 3);
g_assert_cmpint (om_data->num_interface_added_signals, ==, 1);
g_assert_cmpint (om_data->num_interface_removed_signals, ==, 1);
/* ... check introspection data */
info = introspect (c, g_dbus_connection_get_unique_name (c), "/managed/first", loop);
g_assert_cmpint (count_interfaces (info), ==, 4); /* com.acme.Coyote + Properties,Introspectable,Peer */
g_assert (has_interface (info, "com.acme.Coyote"));
g_dbus_node_info_unref (info);
/* Check GetManagedObjects() - should be just the Coyote */
om_check_get_all (c, loop,
"({objectpath '/managed/first': {'com.acme.Coyote': {'Mood': <''>}}},)");
/* -------------------------------------------------- */
/* create a new object with two interfaces */
o2 = foo_object_skeleton_new ("/managed/second");
i = G_DBUS_INTERFACE_SKELETON (foo_bar_skeleton_new ());
bar_skeleton = FOO_BAR (i); /* save for later test */
foo_object_skeleton_set_bar (o2, FOO_BAR (i));
g_object_unref (i);
i = G_DBUS_INTERFACE_SKELETON (foo_bat_skeleton_new ());
foo_object_skeleton_set_bat (o2, FOO_BAT (i));
g_object_unref (i);
/* ... add it */
g_dbus_object_manager_server_export (manager, G_DBUS_OBJECT_SKELETON (o2));
/* ... check we get the InterfacesAdded with _two_ interfaces */
om_data->state = 101;
g_main_loop_run (om_data->loop);
g_assert_cmpint (om_data->state, ==, 102);
g_assert_cmpint (om_data->num_object_proxy_added_signals, ==, 5);
g_assert_cmpint (om_data->num_object_proxy_removed_signals, ==, 3);
g_assert_cmpint (om_data->num_interface_added_signals, ==, 1);
g_assert_cmpint (om_data->num_interface_removed_signals, ==, 1);
/* -------------------------------------------------- */
/* Now that we have a couple of objects with interfaces, check
* that ObjectManager.GetManagedObjects() works
*/
om_check_get_all (c, loop,
"({objectpath '/managed/first': {'com.acme.Coyote': {'Mood': <''>}}, '/managed/second': {'org.project.Bar': {'y': <byte 0x00>, 'b': <false>, 'n': <int16 0>, 'q': <uint16 0>, 'i': <0>, 'u': <uint32 0>, 'x': <int64 0>, 't': <uint64 0>, 'd': <0.0>, 's': <''>, 'o': <objectpath '/'>, 'g': <signature ''>, 'ay': <b''>, 'as': <@as []>, 'aay': <@aay []>, 'ao': <@ao []>, 'ag': <@ag []>, 'FinallyNormalName': <''>, 'ReadonlyProperty': <''>, 'unset_i': <0>, 'unset_d': <0.0>, 'unset_s': <''>, 'unset_o': <objectpath '/'>, 'unset_g': <signature ''>, 'unset_ay': <b''>, 'unset_as': <@as []>, 'unset_ao': <@ao []>, 'unset_ag': <@ag []>, 'unset_struct': <(0, 0.0, '', objectpath '/', signature '', @ay [], @as [], @ao [], @ag [])>}, 'org.project.Bat': {'force_i': <0>, 'force_s': <''>, 'force_ay': <@ay []>, 'force_struct': <(0,)>}}},)");
/* Set connection to NULL, causing everything to be unexported.. verify this.. and
* then set the connection back.. and then check things still work
*/
g_dbus_object_manager_server_set_connection (manager, NULL);
info = introspect (c, g_dbus_connection_get_unique_name (c), "/managed", loop);
g_assert_cmpint (count_interfaces (info), ==, 0); /* nothing */
g_dbus_node_info_unref (info);
g_dbus_object_manager_server_set_connection (manager, c);
om_check_get_all (c, loop,
"({objectpath '/managed/first': {'com.acme.Coyote': {'Mood': <''>}}, '/managed/second': {'org.project.Bar': {'y': <byte 0x00>, 'b': <false>, 'n': <int16 0>, 'q': <uint16 0>, 'i': <0>, 'u': <uint32 0>, 'x': <int64 0>, 't': <uint64 0>, 'd': <0.0>, 's': <''>, 'o': <objectpath '/'>, 'g': <signature ''>, 'ay': <b''>, 'as': <@as []>, 'aay': <@aay []>, 'ao': <@ao []>, 'ag': <@ag []>, 'FinallyNormalName': <''>, 'ReadonlyProperty': <''>, 'unset_i': <0>, 'unset_d': <0.0>, 'unset_s': <''>, 'unset_o': <objectpath '/'>, 'unset_g': <signature ''>, 'unset_ay': <b''>, 'unset_as': <@as []>, 'unset_ao': <@ao []>, 'unset_ag': <@ag []>, 'unset_struct': <(0, 0.0, '', objectpath '/', signature '', @ay [], @as [], @ao [], @ag [])>}, 'org.project.Bat': {'force_i': <0>, 'force_s': <''>, 'force_ay': <@ay []>, 'force_struct': <(0,)>}}},)");
/* Also check that the ObjectManagerClient returns these objects - and
* that they are of the right GType cf. what was requested via
* the generated ::get-proxy-type signal handler
*/
object_proxies = g_dbus_object_manager_get_objects (pm);
g_assert (g_list_length (object_proxies) == 2);
g_list_foreach (object_proxies, (GFunc) g_object_unref, NULL);
g_list_free (object_proxies);
op = g_dbus_object_manager_get_object (pm, "/managed/first");
g_assert (op != NULL);
g_assert (FOO_IS_OBJECT_PROXY (op));
g_assert_cmpstr (g_dbus_object_get_object_path (op), ==, "/managed/first");
proxies = g_dbus_object_get_interfaces (op);
g_assert (g_list_length (proxies) == 1);
g_list_foreach (proxies, (GFunc) g_object_unref, NULL);
g_list_free (proxies);
p = G_DBUS_PROXY (foo_object_get_com_acme_coyote (FOO_OBJECT (op)));
g_assert (p != NULL);
g_assert_cmpint (G_TYPE_FROM_INSTANCE (p), ==, FOO_TYPE_COM_ACME_COYOTE_PROXY);
g_assert (g_type_is_a (G_TYPE_FROM_INSTANCE (p), FOO_TYPE_COM_ACME_COYOTE));
g_object_unref (p);
p = (GDBusProxy *) g_dbus_object_get_interface (op, "org.project.NonExisting");
g_assert (p == NULL);
g_object_unref (op);
/* -- */
op = g_dbus_object_manager_get_object (pm, "/managed/second");
g_assert (op != NULL);
g_assert (FOO_IS_OBJECT_PROXY (op));
g_assert_cmpstr (g_dbus_object_get_object_path (op), ==, "/managed/second");
proxies = g_dbus_object_get_interfaces (op);
g_assert (g_list_length (proxies) == 2);
g_list_foreach (proxies, (GFunc) g_object_unref, NULL);
g_list_free (proxies);
p = G_DBUS_PROXY (foo_object_get_bat (FOO_OBJECT (op)));
g_assert (p != NULL);
g_assert_cmpint (G_TYPE_FROM_INSTANCE (p), ==, FOO_TYPE_BAT_PROXY);
g_assert (g_type_is_a (G_TYPE_FROM_INSTANCE (p), FOO_TYPE_BAT));
g_object_unref (p);
p = G_DBUS_PROXY (foo_object_get_bar (FOO_OBJECT (op)));
g_assert (p != NULL);
g_assert_cmpint (G_TYPE_FROM_INSTANCE (p), ==, FOO_TYPE_BAR_PROXY);
g_assert (g_type_is_a (G_TYPE_FROM_INSTANCE (p), FOO_TYPE_BAR));
/* ... now that we have a Bar instance around, also check that we get signals
* and property changes...
*/
om_check_property_and_signal_emission (loop, bar_skeleton, FOO_BAR (p));
g_object_unref (p);
p = (GDBusProxy *) g_dbus_object_get_interface (op, "org.project.NonExisting");
g_assert (p == NULL);
g_object_unref (op);
/* -------------------------------------------------- */
/* Now remove the second object added above */
g_dbus_object_manager_server_unexport (manager, "/managed/second");
/* ... check we get InterfacesRemoved with both interfaces */
om_data->state = 103;
g_main_loop_run (om_data->loop);
g_assert_cmpint (om_data->state, ==, 104);
g_assert_cmpint (om_data->num_object_proxy_added_signals, ==, 5);
g_assert_cmpint (om_data->num_object_proxy_removed_signals, ==, 4);
g_assert_cmpint (om_data->num_interface_added_signals, ==, 1);
g_assert_cmpint (om_data->num_interface_removed_signals, ==, 1);
/* ... check introspection data (there should be nothing) */
info = introspect (c, g_dbus_connection_get_unique_name (c), "/managed/second", loop);
g_assert_cmpint (count_nodes (info), ==, 0);
g_assert_cmpint (count_interfaces (info), ==, 0);
g_dbus_node_info_unref (info);
/* Check GetManagedObjects() again */
om_check_get_all (c, loop,
"({objectpath '/managed/first': {'com.acme.Coyote': {'Mood': <''>}}},)");
//g_main_loop_run (loop); /* TODO: tmp */
g_main_loop_unref (loop);
g_dbus_connection_signal_unsubscribe (c, om_signal_id);
g_object_unref (o2);
g_object_unref (o);
g_object_unref (manager);
g_assert_cmpint (g_signal_handlers_disconnect_by_func (pm,
G_CALLBACK (on_object_proxy_added),
om_data), ==, 1);
g_assert_cmpint (g_signal_handlers_disconnect_by_func (pm,
G_CALLBACK (on_object_proxy_removed),
om_data), ==, 1);
g_object_unref (pm);
g_object_unref (c);
g_free (om_data);
}
/* ---------------------------------------------------------------------------------------------------- */
static void
test_object_manager (void)
{
GMainLoop *loop;
guint id;
loop = g_main_loop_new (NULL, FALSE);
id = g_bus_own_name (G_BUS_TYPE_SESSION,
"org.gtk.GDBus.BindingsTool.Test",
G_BUS_NAME_OWNER_FLAGS_NONE,
on_bus_acquired,
on_name_acquired,
on_name_lost,
loop,
NULL);
g_main_loop_run (loop);
check_object_manager ();
/* uncomment to keep the service around (to e.g. introspect it) */
/* g_main_loop_run (loop); */
g_bus_unown_name (id);
g_main_loop_unref (loop);
}
/* ---------------------------------------------------------------------------------------------------- */
/* This checks that forcing names via org.gtk.GDBus.Name works (see test-codegen.xml) */
extern gpointer name_forcing_1;
extern gpointer name_forcing_2;
extern gpointer name_forcing_3;
extern gpointer name_forcing_4;
extern gpointer name_forcing_5;
extern gpointer name_forcing_6;
extern gpointer name_forcing_7;
gpointer name_forcing_1 = foo_rocket123_get_type;
gpointer name_forcing_2 = foo_rocket123_call_ignite_xyz;
gpointer name_forcing_3 = foo_rocket123_emit_exploded_xyz;
gpointer name_forcing_4 = foo_rocket123_get_speed_xyz;
gpointer name_forcing_5 = foo_test_ugly_case_interface_call_get_iscsi_servers;
gpointer name_forcing_6 = foo_test_ugly_case_interface_emit_servers_updated_now;
gpointer name_forcing_7 = foo_test_ugly_case_interface_get_ugly_name;
/* ---------------------------------------------------------------------------------------------------- */
/* See https://bugzilla.gnome.org/show_bug.cgi?id=647577#c5 for details */
#define CHECK_FIELD(name, v1, v2) g_assert_cmpint (G_STRUCT_OFFSET (FooChangingInterface##v1##Iface, name), ==, G_STRUCT_OFFSET (FooChangingInterface##v2##Iface, name));
static void
test_interface_stability (void)
{
CHECK_FIELD(handle_foo_method, V1, V2);
CHECK_FIELD(handle_bar_method, V1, V2);
CHECK_FIELD(handle_baz_method, V1, V2);
CHECK_FIELD(foo_signal, V1, V2);
CHECK_FIELD(bar_signal, V1, V2);
CHECK_FIELD(baz_signal, V1, V2);
CHECK_FIELD(handle_new_method_in2, V2, V10);
CHECK_FIELD(new_signal_in2, V2, V10);
}
#undef CHECK_FIELD
/* ---------------------------------------------------------------------------------------------------- */
int
main (int argc,
char *argv[])
{
gint ret;
g_type_init ();
g_test_init (&argc, &argv, NULL);
/* 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/codegen/annotations", test_annotations);
g_test_add_func ("/gdbus/codegen/interface_stability", test_interface_stability);
g_test_add_func ("/gdbus/codegen/object-manager", test_object_manager);
ret = g_test_run();
/* tear down bus */
session_bus_down ();
return ret;
}