| /* GLib testing framework examples and tests | |
| * | |
| * Copyright (C) 2008-2018 Red Hat, Inc. | |
| * | |
| * SPDX-License-Identifier: LGPL-2.1-or-later | |
| * | |
| * 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.1 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, see <http://www.gnu.org/licenses/>. | |
| * | |
| * Author: David Zeuthen <davidz@redhat.com> | |
| */ | |
| #include <gio/gio.h> | |
| #include <unistd.h> | |
| #include <string.h> | |
| #include <stdio.h> | |
| #include "gdbusprivate.h" | |
| #include "gdbus-tests.h" | |
| #include "gstdio.h" | |
| #if GLIB_VERSION_MIN_REQUIRED >= GLIB_VERSION_2_64 | |
| #include "gdbus-test-codegen-generated-min-required-2-64.h" | |
| #else | |
| #include "gdbus-test-codegen-generated.h" | |
| #endif | |
| #include "gdbus-test-codegen-generated-interface-info.h" | |
| #if GLIB_VERSION_MIN_REQUIRED < GLIB_VERSION_2_68 | |
| # undef G_DBUS_METHOD_INVOCATION_HANDLED | |
| # define G_DBUS_METHOD_INVOCATION_HANDLED TRUE | |
| #endif | |
| /* ---------------------------------------------------------------------------------------------------- */ | |
| 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_igen_bar_interface_info (); | |
| g_assert (iface != NULL); | |
| /* see meson.build 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 (FooiGenBar *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_igen_bar_complete_hello_world (object, invocation, response); | |
| g_free (response); | |
| return G_DBUS_METHOD_INVOCATION_HANDLED; | |
| } | |
| static gboolean | |
| on_handle_test_primitive_types (FooiGenBar *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_igen_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 G_DBUS_METHOD_INVOCATION_HANDLED; | |
| } | |
| static gboolean | |
| on_handle_test_non_primitive_types (FooiGenBar *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_igen_bar_complete_test_non_primitive_types (object, invocation, | |
| array_of_strings, | |
| array_of_objpaths, | |
| array_of_signatures, | |
| array_of_bytestrings, | |
| str->str); | |
| g_string_free (str, TRUE); | |
| return G_DBUS_METHOD_INVOCATION_HANDLED; | |
| } | |
| static gboolean | |
| on_handle_request_signal_emission (FooiGenBar *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_igen_bar_emit_test_signal (object, 43, a_strv, a_bytestring_array, a_variant); /* consumes a_variant */ | |
| foo_igen_bar_complete_request_signal_emission (object, invocation); | |
| } | |
| return G_DBUS_METHOD_INVOCATION_HANDLED; | |
| } | |
| static gboolean | |
| on_handle_request_multi_property_mods (FooiGenBar *object, | |
| GDBusMethodInvocation *invocation, | |
| gpointer user_data) | |
| { | |
| foo_igen_bar_set_y (object, foo_igen_bar_get_y (object) + 1); | |
| foo_igen_bar_set_i (object, foo_igen_bar_get_i (object) + 1); | |
| foo_igen_bar_set_y (object, foo_igen_bar_get_y (object) + 1); | |
| foo_igen_bar_set_i (object, foo_igen_bar_get_i (object) + 1); | |
| g_dbus_interface_skeleton_flush (G_DBUS_INTERFACE_SKELETON (object)); | |
| foo_igen_bar_set_y (object, foo_igen_bar_get_y (object) + 1); | |
| foo_igen_bar_set_i (object, foo_igen_bar_get_i (object) + 1); | |
| foo_igen_bar_complete_request_multi_property_mods (object, invocation); | |
| return G_DBUS_METHOD_INVOCATION_HANDLED; | |
| } | |
| static gboolean | |
| on_handle_property_cancellation (FooiGenBar *object, | |
| GDBusMethodInvocation *invocation, | |
| gpointer user_data) | |
| { | |
| guint n; | |
| n = foo_igen_bar_get_n (object); | |
| /* This queues up a PropertiesChange event */ | |
| foo_igen_bar_set_n (object, n + 1); | |
| /* this modifies the queued up event */ | |
| foo_igen_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_igen_bar_complete_property_cancellation (object, invocation); | |
| return G_DBUS_METHOD_INVOCATION_HANDLED; | |
| } | |
| /* ---------------------------------------------------------------------------------------------------- */ | |
| static gboolean | |
| on_handle_force_method (FooiGenBat *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_igen_bat_emit_force_signal (object, | |
| ret_i, | |
| ret_s, | |
| ret_ay, | |
| ret_struct); | |
| foo_igen_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 G_DBUS_METHOD_INVOCATION_HANDLED; | |
| } | |
| /* ---------------------------------------------------------------------------------------------------- */ | |
| 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 (FooiGenAuthorize *object, | |
| GDBusMethodInvocation *invocation, | |
| gpointer user_data) | |
| { | |
| foo_igen_authorize_complete_check_not_authorized (object, invocation); | |
| return G_DBUS_METHOD_INVOCATION_HANDLED; | |
| } | |
| static gboolean | |
| on_handle_check_authorized (FooiGenAuthorize *object, | |
| GDBusMethodInvocation *invocation, | |
| gpointer user_data) | |
| { | |
| foo_igen_authorize_complete_check_authorized (object, invocation); | |
| return G_DBUS_METHOD_INVOCATION_HANDLED; | |
| } | |
| static gboolean | |
| on_handle_check_not_authorized_from_object (FooiGenAuthorize *object, | |
| GDBusMethodInvocation *invocation, | |
| gpointer user_data) | |
| { | |
| foo_igen_authorize_complete_check_not_authorized_from_object (object, invocation); | |
| return G_DBUS_METHOD_INVOCATION_HANDLED; | |
| } | |
| static gboolean | |
| on_handle_fdpassing_hello_fd (FooiGenMethodThreads *object, | |
| GDBusMethodInvocation *invocation, | |
| GUnixFDList *fd_list, | |
| const gchar *greeting, | |
| gpointer user_data) | |
| { | |
| g_assert_true (G_IS_UNIX_FD_LIST (fd_list)); | |
| g_assert_cmpuint (g_unix_fd_list_get_length (fd_list), ==, 2); | |
| g_assert_cmpstr (greeting, ==, "Hey fd!"); | |
| foo_igen_test_fdpassing_complete_hello_fd (FOO_IGEN_TEST_FDPASSING (object), | |
| invocation, fd_list, | |
| "I love to receive fds!"); | |
| return G_DBUS_METHOD_INVOCATION_HANDLED; | |
| } | |
| /* ---------------------------------------------------------------------------------------------------- */ | |
| static gboolean | |
| on_handle_get_self (FooiGenMethodThreads *object, | |
| GDBusMethodInvocation *invocation, | |
| gpointer user_data) | |
| { | |
| gchar *s; | |
| s = g_strdup_printf ("%p", (void *)g_thread_self ()); | |
| foo_igen_method_threads_complete_get_self (object, invocation, s); | |
| g_free (s); | |
| return G_DBUS_METHOD_INVOCATION_HANDLED; | |
| } | |
| /* ---------------------------------------------------------------------------------------------------- */ | |
| static GThread *method_handler_thread = NULL; | |
| static FooiGenBar *exported_bar_object = NULL; | |
| static FooiGenBat *exported_bat_object = NULL; | |
| static FooiGenTestFDPassing *exported_fd_passing_object = NULL; | |
| static FooiGenAuthorize *exported_authorize_object = NULL; | |
| static GDBusObjectSkeleton *authorize_enclosing_object = NULL; | |
| static FooiGenMethodThreads *exported_thread_object_1 = NULL; | |
| static FooiGenMethodThreads *exported_thread_object_2 = NULL; | |
| static void | |
| unexport_objects (void) | |
| { | |
| g_dbus_interface_skeleton_unexport (G_DBUS_INTERFACE_SKELETON (exported_bar_object)); | |
| g_dbus_interface_skeleton_unexport (G_DBUS_INTERFACE_SKELETON (exported_bat_object)); | |
| g_dbus_interface_skeleton_unexport (G_DBUS_INTERFACE_SKELETON (exported_authorize_object)); | |
| g_dbus_interface_skeleton_unexport (G_DBUS_INTERFACE_SKELETON (exported_thread_object_1)); | |
| g_dbus_interface_skeleton_unexport (G_DBUS_INTERFACE_SKELETON (exported_thread_object_2)); | |
| g_dbus_interface_skeleton_unexport (G_DBUS_INTERFACE_SKELETON (exported_fd_passing_object)); | |
| } | |
| 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 | |
| * FooiGenBarSkeleton 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_igen_bar_skeleton_new (); | |
| foo_igen_bar_set_ay (exported_bar_object, "ABCabc"); | |
| foo_igen_bar_set_y (exported_bar_object, 42); | |
| foo_igen_bar_set_d (exported_bar_object, 43.0); | |
| foo_igen_bar_set_finally_normal_name (exported_bar_object, "There aint no place like home"); | |
| foo_igen_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_igen_bar_set_readonly_property (exported_bar_object, "blah"); | |
| g_assert_cmpstr (foo_igen_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_igen_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_igen_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_igen_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_assert (!g_dbus_interface_skeleton_has_connection (G_DBUS_INTERFACE_SKELETON (exported_thread_object_1), connection)); | |
| 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); | |
| g_assert_cmpint (g_dbus_interface_skeleton_get_flags (G_DBUS_INTERFACE_SKELETON (exported_thread_object_1)), ==, G_DBUS_INTERFACE_SKELETON_FLAGS_HANDLE_METHOD_INVOCATIONS_IN_THREAD); | |
| exported_thread_object_2 = foo_igen_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); | |
| g_assert_cmpint (g_dbus_interface_skeleton_get_flags (G_DBUS_INTERFACE_SKELETON (exported_thread_object_2)), ==, G_DBUS_INTERFACE_SKELETON_FLAGS_NONE); | |
| exported_fd_passing_object = foo_igen_test_fdpassing_skeleton_new (); | |
| g_dbus_interface_skeleton_export (G_DBUS_INTERFACE_SKELETON (exported_fd_passing_object), | |
| connection, | |
| "/fdpassing", | |
| &error); | |
| g_assert_no_error (error); | |
| g_signal_connect (exported_fd_passing_object, | |
| "handle-hello-fd", | |
| G_CALLBACK (on_handle_fdpassing_hello_fd), | |
| 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; | |
| GThread *thread = g_thread_new ("check-proxies", check_proxies_in_thread, loop); | |
| g_thread_unref (thread); | |
| } | |
| 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; | |
| FooiGenBar *proxy = FOO_IGEN_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_igen_bar_get_y (proxy) - 2); | |
| g_assert_cmpint (data->initial_i, ==, foo_igen_bar_get_i (proxy) - 2); | |
| } | |
| else if (data->num_g_properties_changed == 1) | |
| { | |
| g_assert_cmpint (data->initial_y, ==, foo_igen_bar_get_y (proxy) - 3); | |
| g_assert_cmpint (data->initial_i, ==, foo_igen_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 (FooiGenBar *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 (FooiGenBar *proxy, | |
| GAsyncResult *res, | |
| gpointer user_data) | |
| { | |
| ClientData *data = user_data; | |
| gboolean ret; | |
| GError *error = NULL; | |
| error = NULL; | |
| ret = foo_igen_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 (FooiGenBar *proxy, | |
| GMainLoop *thread_loop) | |
| { | |
| 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}; | |
| GVariant *array_of_signatures = NULL; | |
| const gchar *array_of_bytestrings[3] = {"one\xff", "two\xff", NULL}; | |
| gchar **ret_array_of_strings = NULL; | |
| gchar **ret_array_of_objpaths = NULL; | |
| GVariant *ret_array_of_signatures = NULL; | |
| gchar **ret_array_of_bytestrings = NULL; | |
| 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; | |
| const gchar *const *read_as; | |
| const gchar *const *read_as2; | |
| const gchar *const *read_as3; | |
| 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_igen_bar_set_finally_normal_name (proxy, "foo!"); | |
| _g_assert_property_notify (proxy, "finally-normal-name"); | |
| g_assert_cmpstr (foo_igen_bar_get_finally_normal_name (proxy), ==, "foo!"); | |
| /* Try setting properties that requires memory management. This | |
| * is to exercise the paths that frees the references. | |
| */ | |
| g_object_set (proxy, | |
| "s", "a string", | |
| "o", "/a/path", | |
| "g", "asig", | |
| "ay", "eg", | |
| "as", array_of_strings, | |
| "ao", array_of_objpaths, | |
| "ag", g_variant_new_parsed ("[@g 'ass', 'git']"), | |
| NULL); | |
| error = NULL; | |
| ret = foo_igen_bar_call_test_primitive_types_sync (proxy, | |
| 10, | |
| TRUE, | |
| 11, | |
| 12, | |
| 13, | |
| 14, | |
| 15, | |
| 16, | |
| 17, | |
| "a string", | |
| "/a/path", | |
| "asig", | |
| "bytestring\xff", | |
| #if GLIB_VERSION_MIN_REQUIRED >= GLIB_VERSION_2_64 | |
| G_DBUS_CALL_FLAGS_NONE, | |
| -1, | |
| #endif | |
| &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); | |
| g_clear_pointer (&ret_val_string, g_free); | |
| g_clear_pointer (&ret_val_objpath, g_free); | |
| g_clear_pointer (&ret_val_signature, g_free); | |
| g_clear_pointer (&ret_val_bytestring, g_free); | |
| error = NULL; | |
| array_of_signatures = g_variant_ref_sink (g_variant_new_parsed ("[@g 'ass', 'git']")); | |
| ret = foo_igen_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, | |
| array_of_signatures, | |
| array_of_bytestrings, | |
| #if GLIB_VERSION_MIN_REQUIRED >= GLIB_VERSION_2_64 | |
| G_DBUS_CALL_FLAGS_NONE, | |
| -1, | |
| #endif | |
| &ret_array_of_strings, | |
| &ret_array_of_objpaths, | |
| &ret_array_of_signatures, | |
| &ret_array_of_bytestrings, | |
| &s, | |
| NULL, /* GCancellable */ | |
| &error); | |
| g_assert_no_error (error); | |
| g_assert (ret); | |
| g_assert_nonnull (ret_array_of_strings); | |
| g_assert_cmpuint (g_strv_length ((gchar **) ret_array_of_strings), ==, | |
| g_strv_length ((gchar **) array_of_strings)); | |
| g_assert_nonnull (ret_array_of_objpaths); | |
| g_assert_cmpuint (g_strv_length ((gchar **) ret_array_of_objpaths), ==, | |
| g_strv_length ((gchar **) array_of_objpaths)); | |
| g_assert_nonnull (ret_array_of_signatures); | |
| g_assert_cmpvariant (ret_array_of_signatures, array_of_signatures); | |
| g_assert_nonnull (ret_array_of_bytestrings); | |
| g_assert_cmpuint (g_strv_length ((gchar **) ret_array_of_bytestrings), ==, | |
| g_strv_length ((gchar **) array_of_bytestrings)); | |
| g_clear_pointer (&ret_array_of_strings, g_strfreev); | |
| g_clear_pointer (&ret_array_of_objpaths, g_strfreev); | |
| g_clear_pointer (&ret_array_of_signatures, g_variant_unref); | |
| g_clear_pointer (&ret_array_of_bytestrings, g_strfreev); | |
| g_clear_pointer (&s, g_free); | |
| /* Check that org.freedesktop.DBus.Error.UnknownMethod is returned on | |
| * unimplemented methods. | |
| */ | |
| error = NULL; | |
| #if GLIB_VERSION_MIN_REQUIRED >= GLIB_VERSION_2_64 | |
| ret = foo_igen_bar_call_unimplemented_method_sync (proxy, G_DBUS_CALL_FLAGS_NONE, -1, NULL /* GCancellable */, &error); | |
| #else | |
| ret = foo_igen_bar_call_unimplemented_method_sync (proxy, NULL /* GCancellable */, &error); | |
| #endif | |
| 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; | |
| #if GLIB_VERSION_MIN_REQUIRED >= GLIB_VERSION_2_64 | |
| ret = foo_igen_bar_call_request_signal_emission_sync (proxy, 0, G_DBUS_CALL_FLAGS_NONE, -1, NULL, &error); | |
| #else | |
| ret = foo_igen_bar_call_request_signal_emission_sync (proxy, 0, NULL, &error); | |
| #endif | |
| 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_igen_bar_set_finally_normal_name (proxy, "hey back!"); | |
| _g_assert_property_notify (proxy, "finally-normal-name"); | |
| g_assert_cmpstr (foo_igen_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) | |
| */ | |
| read_as = foo_igen_bar_get_as (proxy); | |
| read_as2 = foo_igen_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_igen_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 second reception, only by one. The signal handler | |
| * checks this. | |
| * | |
| * This also checks that _drain_notify() works. | |
| */ | |
| data->initial_y = foo_igen_bar_get_y (proxy); | |
| data->initial_i = foo_igen_bar_get_i (proxy); | |
| g_signal_connect (proxy, | |
| "g-properties-changed", | |
| G_CALLBACK (on_g_properties_changed), | |
| data); | |
| error = NULL; | |
| #if GLIB_VERSION_MIN_REQUIRED >= GLIB_VERSION_2_64 | |
| ret = foo_igen_bar_call_request_multi_property_mods_sync (proxy, G_DBUS_CALL_FLAGS_NONE, -1, NULL, &error); | |
| #else | |
| ret = foo_igen_bar_call_request_multi_property_mods_sync (proxy, NULL, &error); | |
| #endif | |
| 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_igen_bar_set_u (proxy, 1042); | |
| g_assert_cmpint (data->num_notify_u, ==, 1); | |
| g_assert_cmpint (foo_igen_bar_get_u (proxy), ==, 0); | |
| _g_assert_property_notify (proxy, "u"); | |
| g_assert_cmpint (foo_igen_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_igen_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_igen_bar_set_n (proxy, 10042); | |
| g_assert_cmpint (data->num_notify_n, ==, 1); | |
| g_assert_cmpint (foo_igen_bar_get_n (proxy), ==, 0); | |
| _g_assert_property_notify (proxy, "n"); | |
| g_assert_cmpint (foo_igen_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_igen_bar_get_n (foo); | |
| * foo_igen_bar_set_n (foo, n + 1); | |
| * foo_igen_bar_set_n (foo, n); | |
| * | |
| * then no PropertiesChanged() signal is emitted! | |
| */ | |
| error = NULL; | |
| foo_igen_bar_call_property_cancellation (proxy, | |
| #if GLIB_VERSION_MIN_REQUIRED >= GLIB_VERSION_2_64 | |
| G_DBUS_CALL_FLAGS_NONE, | |
| -1, | |
| #endif | |
| 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); | |
| g_variant_unref (array_of_signatures); | |
| } | |
| static void | |
| check_fdpassing_proxy (FooiGenTestFDPassing *proxy) | |
| { | |
| GError *error = NULL; | |
| GUnixFDList *fd_list = g_unix_fd_list_new (); | |
| GUnixFDList *ret_fd_list = NULL; | |
| char *response = NULL; | |
| int fd; | |
| fd = dup (0); | |
| g_assert_cmpint (g_unix_fd_list_append (fd_list, fd, &error), ==, 0); | |
| g_assert_no_error (error); | |
| g_close (fd, &error); | |
| g_assert_no_error (error); | |
| fd = dup (0); | |
| g_assert_cmpint (g_unix_fd_list_append (fd_list, fd, &error), ==, 1); | |
| g_assert_no_error (error); | |
| g_close (fd, &error); | |
| g_assert_no_error (error); | |
| foo_igen_test_fdpassing_call_hello_fd_sync (proxy, "Hey fd!", | |
| #if GLIB_VERSION_MIN_REQUIRED >= GLIB_VERSION_2_64 | |
| G_DBUS_CALL_FLAGS_NO_AUTO_START, -1, | |
| #endif | |
| fd_list, | |
| &response, &ret_fd_list, NULL, | |
| &error); | |
| g_assert_no_error (error); | |
| g_assert_true (G_IS_UNIX_FD_LIST (ret_fd_list)); | |
| g_assert_cmpuint (g_unix_fd_list_get_length (fd_list), ==, 2); | |
| g_assert_cmpstr (response, ==, "I love to receive fds!"); | |
| g_clear_pointer (&response, g_free); | |
| g_clear_object (&fd_list); | |
| g_clear_object (&ret_fd_list); | |
| } | |
| /* ---------------------------------------------------------------------------------------------------- */ | |
| static void | |
| on_force_signal (FooiGenBat *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 (FooiGenBat *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_igen_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), | |
| #if GLIB_VERSION_MIN_REQUIRED >= GLIB_VERSION_2_64 | |
| G_DBUS_CALL_FLAGS_NONE, | |
| -1, | |
| #endif | |
| &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 (FooiGenAuthorize *proxy, | |
| GMainLoop *thread_loop) | |
| { | |
| GError *error; | |
| gboolean ret; | |
| /* Check that g-authorize-method works as intended */ | |
| error = NULL; | |
| #if GLIB_VERSION_MIN_REQUIRED >= GLIB_VERSION_2_64 | |
| ret = foo_igen_authorize_call_check_not_authorized_sync (proxy, G_DBUS_CALL_FLAGS_NONE, -1, NULL, &error); | |
| #else | |
| ret = foo_igen_authorize_call_check_not_authorized_sync (proxy, NULL, &error); | |
| #endif | |
| g_assert_error (error, G_IO_ERROR, G_IO_ERROR_PERMISSION_DENIED); | |
| g_error_free (error); | |
| g_assert (!ret); | |
| error = NULL; | |
| #if GLIB_VERSION_MIN_REQUIRED >= GLIB_VERSION_2_64 | |
| ret = foo_igen_authorize_call_check_authorized_sync (proxy, G_DBUS_CALL_FLAGS_NONE, -1, NULL, &error); | |
| #else | |
| ret = foo_igen_authorize_call_check_authorized_sync (proxy, NULL, &error); | |
| #endif | |
| g_assert_no_error (error); | |
| g_assert (ret); | |
| error = NULL; | |
| #if GLIB_VERSION_MIN_REQUIRED >= GLIB_VERSION_2_64 | |
| ret = foo_igen_authorize_call_check_not_authorized_from_object_sync (proxy, G_DBUS_CALL_FLAGS_NONE, -1, NULL, &error); | |
| #else | |
| ret = foo_igen_authorize_call_check_not_authorized_from_object_sync (proxy, NULL, &error); | |
| #endif | |
| g_assert_error (error, G_IO_ERROR, G_IO_ERROR_PENDING); | |
| g_error_free (error); | |
| g_assert (!ret); | |
| } | |
| /* ---------------------------------------------------------------------------------------------------- */ | |
| static GThread * | |
| get_self_via_proxy (FooiGenMethodThreads *proxy_1) | |
| { | |
| GError *error; | |
| gchar *self_str; | |
| gboolean ret; | |
| gpointer self; | |
| error = NULL; | |
| #if GLIB_VERSION_MIN_REQUIRED >= GLIB_VERSION_2_64 | |
| ret = foo_igen_method_threads_call_get_self_sync (proxy_1, G_DBUS_CALL_FLAGS_NONE, -1, &self_str, NULL, &error); | |
| #else | |
| ret = foo_igen_method_threads_call_get_self_sync (proxy_1, &self_str, NULL, &error); | |
| #endif | |
| 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 (FooiGenMethodThreads *proxy_1, | |
| FooiGenMethodThreads *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; | |
| FooiGenBar *bar_proxy; | |
| FooiGenBat *bat_proxy; | |
| FooiGenTestFDPassing *fd_passing_proxy; | |
| FooiGenAuthorize *authorize_proxy; | |
| FooiGenMethodThreads *thread_proxy_1; | |
| FooiGenMethodThreads *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_igen_bar_proxy_new_for_bus_sync (G_BUS_TYPE_SESSION, | |
| G_DBUS_PROXY_FLAGS_NONE, | |
| "org.gtk.GDBus.BindingsTool.Test", | |
| "/bar", | |
| NULL, /* GCancellable* */ | |
| &error); | |
| g_assert_no_error (error); | |
| check_bar_proxy (bar_proxy, thread_loop); | |
| g_object_unref (bar_proxy); | |
| error = NULL; | |
| bat_proxy = foo_igen_bat_proxy_new_for_bus_sync (G_BUS_TYPE_SESSION, | |
| G_DBUS_PROXY_FLAGS_NONE, | |
| "org.gtk.GDBus.BindingsTool.Test", | |
| "/bat", | |
| NULL, /* GCancellable* */ | |
| &error); | |
| g_assert_no_error (error); | |
| check_bat_proxy (bat_proxy, thread_loop); | |
| g_object_unref (bat_proxy); | |
| error = NULL; | |
| authorize_proxy = foo_igen_authorize_proxy_new_for_bus_sync (G_BUS_TYPE_SESSION, | |
| G_DBUS_PROXY_FLAGS_NONE, | |
| "org.gtk.GDBus.BindingsTool.Test", | |
| "/authorize", | |
| NULL, /* GCancellable* */ | |
| &error); | |
| g_assert_no_error (error); | |
| check_authorize_proxy (authorize_proxy, thread_loop); | |
| g_object_unref (authorize_proxy); | |
| error = NULL; | |
| thread_proxy_1 = foo_igen_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_igen_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); | |
| fd_passing_proxy = foo_igen_test_fdpassing_proxy_new_for_bus_sync (G_BUS_TYPE_SESSION, | |
| G_DBUS_PROXY_FLAGS_NONE, | |
| "org.gtk.GDBus.BindingsTool.Test", | |
| "/fdpassing", | |
| NULL, /* GCancellable* */ | |
| &error); | |
| g_assert_no_error (error); | |
| check_fdpassing_proxy (fd_passing_proxy); | |
| g_object_unref (fd_passing_proxy); | |
| /* Wait for the proxy signals to all be unsubscribed. */ | |
| while (g_main_context_iteration (thread_context, FALSE)) | |
| { | |
| /* Nothing needs to be done here */ | |
| } | |
| 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, | |
| DBUS_INTERFACE_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", | |
| DBUS_INTERFACE_OBJECT_MANAGER, | |
| "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 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_GNUC_BEGIN_IGNORE_DEPRECATIONS | |
| g_ptr_array_sort_values (interfaces, (GCompareFunc) g_strcmp0); | |
| g_ptr_array_sort_values (interfaces_in_message, (GCompareFunc) g_strcmp0); | |
| G_GNUC_END_IGNORE_DEPRECATIONS | |
| 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_GNUC_BEGIN_IGNORE_DEPRECATIONS | |
| g_ptr_array_sort_values (interfaces, (GCompareFunc) g_strcmp0); | |
| g_ptr_array_sort_values (interfaces_in_message, (GCompareFunc) g_strcmp0); | |
| G_GNUC_END_IGNORE_DEPRECATIONS | |
| 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_printerr ("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; | |
| case 200: | |
| om_check_interfaces_added (signal_name, parameters, "/managed/first_1", | |
| "com.acme.Coyote", NULL); | |
| om_data->state = 201; | |
| g_main_loop_quit (om_data->loop); | |
| break; | |
| } | |
| } | |
| static GAsyncResult *om_res = NULL; | |
| static void | |
| om_pm_start_cb (FooiGenObjectManagerClient *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 | |
| property_changed (GObject *object, | |
| GParamSpec *pspec, | |
| gpointer user_data) | |
| { | |
| gboolean *changed = user_data; | |
| *changed = TRUE; | |
| } | |
| static void | |
| om_check_property_and_signal_emission (GMainLoop *loop, | |
| FooiGenBar *skeleton, | |
| FooiGenBar *proxy) | |
| { | |
| gboolean d_changed = FALSE; | |
| gboolean quiet_changed = FALSE; | |
| gboolean quiet_too_changed = FALSE; | |
| guint handler; | |
| /* First PropertiesChanged */ | |
| g_assert_cmpint (foo_igen_bar_get_i (skeleton), ==, 0); | |
| g_assert_cmpint (foo_igen_bar_get_i (proxy), ==, 0); | |
| foo_igen_bar_set_i (skeleton, 1); | |
| _g_assert_property_notify (proxy, "i"); | |
| g_assert_cmpint (foo_igen_bar_get_i (skeleton), ==, 1); | |
| g_assert_cmpint (foo_igen_bar_get_i (proxy), ==, 1); | |
| /* Double-check the gdouble case */ | |
| g_assert_cmpfloat (foo_igen_bar_get_d (skeleton), ==, 0.0); | |
| g_assert_cmpfloat (foo_igen_bar_get_d (proxy), ==, 0.0); | |
| foo_igen_bar_set_d (skeleton, 1.0); | |
| _g_assert_property_notify (proxy, "d"); | |
| /* Verify that re-setting it to the same value doesn't cause a | |
| * notify on the proxy, by taking advantage of the fact that | |
| * notifications are serialized. | |
| */ | |
| handler = g_signal_connect (proxy, "notify::d", | |
| G_CALLBACK (property_changed), &d_changed); | |
| foo_igen_bar_set_d (skeleton, 1.0); | |
| foo_igen_bar_set_i (skeleton, 2); | |
| _g_assert_property_notify (proxy, "i"); | |
| g_assert (d_changed == FALSE); | |
| g_signal_handler_disconnect (proxy, handler); | |
| /* Verify that re-setting a property with the "EmitsChangedSignal" | |
| * set to false doesn't emit a signal. */ | |
| handler = g_signal_connect (proxy, "notify::quiet", | |
| G_CALLBACK (property_changed), &quiet_changed); | |
| foo_igen_bar_set_quiet (skeleton, "hush!"); | |
| foo_igen_bar_set_i (skeleton, 3); | |
| _g_assert_property_notify (proxy, "i"); | |
| g_assert (quiet_changed == FALSE); | |
| g_assert_cmpstr (foo_igen_bar_get_quiet (skeleton), ==, "hush!"); | |
| g_signal_handler_disconnect (proxy, handler); | |
| /* Also verify that re-setting a property with the "EmitsChangedSignal" | |
| * set to 'const' doesn't emit a signal. */ | |
| handler = g_signal_connect (proxy, "notify::quiet-too", | |
| G_CALLBACK (property_changed), &quiet_changed); | |
| foo_igen_bar_set_quiet_too (skeleton, "hush too!"); | |
| foo_igen_bar_set_i (skeleton, 4); | |
| _g_assert_property_notify (proxy, "i"); | |
| g_assert (quiet_too_changed == FALSE); | |
| g_assert_cmpstr (foo_igen_bar_get_quiet_too (skeleton), ==, "hush too!"); | |
| g_signal_handler_disconnect (proxy, handler); | |
| /* Then just a regular signal */ | |
| foo_igen_bar_emit_another_signal (skeleton, "word"); | |
| _g_assert_signal_received (proxy, "another-signal"); | |
| } | |
| static void | |
| check_object_manager (void) | |
| { | |
| FooiGenObjectSkeleton *o = NULL; | |
| FooiGenObjectSkeleton *o2 = NULL; | |
| FooiGenObjectSkeleton *o3 = NULL; | |
| GDBusInterfaceSkeleton *i; | |
| GDBusConnection *c; | |
| GDBusObjectManagerServer *manager = NULL; | |
| GDBusNodeInfo *info; | |
| GError *error; | |
| GMainLoop *loop; | |
| OMData *om_data = NULL; | |
| guint om_signal_id = 0; | |
| GDBusObjectManager *pm = NULL; | |
| GList *object_proxies; | |
| GList *proxies; | |
| GDBusObject *op; | |
| GDBusProxy *p; | |
| FooiGenBar *bar_skeleton; | |
| GDBusInterface *iface; | |
| gchar *path, *name, *name_owner; | |
| GDBusConnection *c2; | |
| GDBusObjectManagerClientFlags flags; | |
| 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 */ | |
| DBUS_INTERFACE_OBJECT_MANAGER, | |
| 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_igen_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_assert (g_dbus_object_manager_server_get_connection (manager) == NULL); | |
| g_dbus_object_manager_server_set_connection (manager, c); | |
| g_assert_cmpstr (g_dbus_object_manager_get_object_path (G_DBUS_OBJECT_MANAGER (manager)), ==, "/managed"); | |
| g_object_get (manager, "object-path", &path, "connection", &c2, NULL); | |
| g_assert_cmpstr (path, ==, "/managed"); | |
| g_assert (c2 == c); | |
| g_free (path); | |
| g_clear_object (&c2); | |
| /* 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, DBUS_INTERFACE_OBJECT_MANAGER)); | |
| 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 proxy manager again - this time it should work */ | |
| error = NULL; | |
| foo_igen_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_igen_object_manager_client_new_finish (om_res, &error); | |
| g_clear_object (&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); | |
| g_assert_cmpstr (g_dbus_object_manager_get_object_path (G_DBUS_OBJECT_MANAGER (pm)), ==, "/managed"); | |
| g_object_get (pm, | |
| "object-path", &path, | |
| "connection", &c2, | |
| "name", &name, | |
| "name-owner", &name_owner, | |
| "flags", &flags, | |
| NULL); | |
| g_assert_cmpstr (path, ==, "/managed"); | |
| g_assert_cmpstr (name, ==, g_dbus_connection_get_unique_name (c)); | |
| g_assert_cmpstr (name_owner, ==, g_dbus_connection_get_unique_name (c)); | |
| g_assert_cmpint (flags, ==, G_DBUS_OBJECT_MANAGER_CLIENT_FLAGS_NONE); | |
| g_assert (c2 == c); | |
| g_free (path); | |
| g_clear_object (&c2); | |
| g_free (name); | |
| g_free (name_owner); | |
| /* ... 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_igen_object_skeleton_new ("/managed/first"); | |
| i = G_DBUS_INTERFACE_SKELETON (foo_igen_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_igen_object_skeleton_set_bar (o, FOO_IGEN_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); | |
| foo_igen_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_igen_object_skeleton_set_bar (o, FOO_IGEN_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); | |
| o2 = FOO_IGEN_OBJECT_SKELETON (g_dbus_interface_dup_object (G_DBUS_INTERFACE (i))); | |
| g_assert (G_DBUS_OBJECT (o2) == G_DBUS_OBJECT (o)); | |
| g_assert_cmpint (G_OBJECT (o2)->ref_count, ==, 2); | |
| g_clear_object (&o2); | |
| 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); | |
| /* Also check g_dbus_object_manager_get_interface */ | |
| iface = g_dbus_object_manager_get_interface (G_DBUS_OBJECT_MANAGER (manager), "/managed/first", "org.project.Bar"); | |
| g_assert (iface != NULL); | |
| g_clear_object (&iface); | |
| iface = g_dbus_object_manager_get_interface (G_DBUS_OBJECT_MANAGER (manager), "/managed/first", "org.project.Bat"); | |
| g_assert (iface == NULL); | |
| iface = g_dbus_object_manager_get_interface (G_DBUS_OBJECT_MANAGER (pm), "/managed/first", "org.project.Bar"); | |
| g_assert (iface != NULL); | |
| g_clear_object (&iface); | |
| iface = g_dbus_object_manager_get_interface (G_DBUS_OBJECT_MANAGER (pm), "/managed/first", "org.project.Bat"); | |
| g_assert (iface == NULL); | |
| /* Now, check adding the same interface replaces the existing one */ | |
| foo_igen_object_skeleton_set_bar (o, FOO_IGEN_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_clear_object (&i); | |
| /* check adding an interface of same type (but not same object) replaces the existing one */ | |
| i = G_DBUS_INTERFACE_SKELETON (foo_igen_bar_skeleton_new ()); | |
| foo_igen_object_skeleton_set_bar (o, FOO_IGEN_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_clear_object (&i); | |
| /* check adding an interface of another type doesn't replace the existing one */ | |
| i = G_DBUS_INTERFACE_SKELETON (foo_igen_bat_skeleton_new ()); | |
| foo_igen_object_skeleton_set_bat (o, FOO_IGEN_BAT (i)); | |
| g_clear_object (&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_igen_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_igen_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_igen_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_igen_com_acme_coyote_skeleton_new ()); | |
| foo_igen_object_skeleton_set_com_acme_coyote (o, FOO_IGEN_COM_ACME_COYOTE (i)); | |
| g_clear_object (&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_igen_object_skeleton_new ("/managed/second"); | |
| i = G_DBUS_INTERFACE_SKELETON (foo_igen_bar_skeleton_new ()); | |
| bar_skeleton = FOO_IGEN_BAR (i); /* save for later test */ | |
| foo_igen_object_skeleton_set_bar (o2, FOO_IGEN_BAR (i)); | |
| g_clear_object (&i); | |
| i = G_DBUS_INTERFACE_SKELETON (foo_igen_bat_skeleton_new ()); | |
| foo_igen_object_skeleton_set_bat (o2, FOO_IGEN_BAT (i)); | |
| g_clear_object (&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': <''>, 'quiet': <''>, 'quiet_too': <''>, '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': <''>, 'quiet': <''>, 'quiet_too': <''>, '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_free_full (object_proxies, g_object_unref); | |
| op = g_dbus_object_manager_get_object (pm, "/managed/first"); | |
| g_assert (op != NULL); | |
| g_assert (FOO_IGEN_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_free_full (proxies, g_object_unref); | |
| p = G_DBUS_PROXY (foo_igen_object_get_com_acme_coyote (FOO_IGEN_OBJECT (op))); | |
| g_assert (p != NULL); | |
| g_assert_cmpint (G_TYPE_FROM_INSTANCE (p), ==, FOO_IGEN_TYPE_COM_ACME_COYOTE_PROXY); | |
| g_assert (g_type_is_a (G_TYPE_FROM_INSTANCE (p), FOO_IGEN_TYPE_COM_ACME_COYOTE)); | |
| g_clear_object (&p); | |
| p = (GDBusProxy *) g_dbus_object_get_interface (op, "org.project.NonExisting"); | |
| g_assert (p == NULL); | |
| g_clear_object (&op); | |
| /* -- */ | |
| op = g_dbus_object_manager_get_object (pm, "/managed/second"); | |
| g_assert (op != NULL); | |
| g_assert (FOO_IGEN_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_free_full (proxies, g_object_unref); | |
| p = G_DBUS_PROXY (foo_igen_object_get_bat (FOO_IGEN_OBJECT (op))); | |
| g_assert (p != NULL); | |
| g_assert_cmpint (G_TYPE_FROM_INSTANCE (p), ==, FOO_IGEN_TYPE_BAT_PROXY); | |
| g_assert (g_type_is_a (G_TYPE_FROM_INSTANCE (p), FOO_IGEN_TYPE_BAT)); | |
| g_clear_object (&p); | |
| p = G_DBUS_PROXY (foo_igen_object_get_bar (FOO_IGEN_OBJECT (op))); | |
| g_assert (p != NULL); | |
| g_assert_cmpint (G_TYPE_FROM_INSTANCE (p), ==, FOO_IGEN_TYPE_BAR_PROXY); | |
| g_assert (g_type_is_a (G_TYPE_FROM_INSTANCE (p), FOO_IGEN_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_IGEN_BAR (p)); | |
| g_clear_object (&p); | |
| p = (GDBusProxy *) g_dbus_object_get_interface (op, "org.project.NonExisting"); | |
| g_assert (p == NULL); | |
| g_clear_object (&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': <''>}}},)"); | |
| /* -------------------------------------------------- */ | |
| /* Check that export_uniquely() works */ | |
| o3 = foo_igen_object_skeleton_new ("/managed/first"); | |
| i = G_DBUS_INTERFACE_SKELETON (foo_igen_com_acme_coyote_skeleton_new ()); | |
| foo_igen_com_acme_coyote_set_mood (FOO_IGEN_COM_ACME_COYOTE (i), "indifferent"); | |
| foo_igen_object_skeleton_set_com_acme_coyote (o3, FOO_IGEN_COM_ACME_COYOTE (i)); | |
| g_clear_object (&i); | |
| g_dbus_object_manager_server_export_uniquely (manager, G_DBUS_OBJECT_SKELETON (o3)); | |
| /* ... check we get the InterfacesAdded signal */ | |
| om_data->state = 200; | |
| g_main_loop_run (om_data->loop); | |
| g_assert_cmpint (om_data->state, ==, 201); | |
| om_check_get_all (c, loop, | |
| "({objectpath '/managed/first': {'com.acme.Coyote': {'Mood': <''>}}, '/managed/first_1': {'com.acme.Coyote': {'Mood': <'indifferent'>}}},)"); | |
| //g_main_loop_run (loop); /* TODO: tmp */ | |
| /* Clean up objects */ | |
| g_assert (g_dbus_object_manager_server_unexport (manager, "/managed/first_1")); | |
| //g_assert (g_dbus_object_manager_server_unexport (manager, "/managed/second")); | |
| g_assert (g_dbus_object_manager_server_unexport (manager, "/managed/first")); | |
| g_assert_cmpint (g_list_length (g_dbus_object_manager_get_objects (G_DBUS_OBJECT_MANAGER (manager))), ==, 0); | |
| if (loop != NULL) | |
| g_main_loop_unref (loop); | |
| if (om_signal_id != 0) | |
| g_dbus_connection_signal_unsubscribe (c, om_signal_id); | |
| g_clear_object (&o3); | |
| g_clear_object (&o2); | |
| g_clear_object (&o); | |
| g_clear_object (&manager); | |
| if (pm != NULL) | |
| { | |
| 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_clear_object (&pm); | |
| } | |
| g_clear_object (&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); */ | |
| unexport_objects (); | |
| 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_igen_rocket123_get_type; | |
| gpointer name_forcing_2 = foo_igen_rocket123_call_ignite_xyz; | |
| gpointer name_forcing_3 = foo_igen_rocket123_emit_exploded_xyz; | |
| gpointer name_forcing_4 = foo_igen_rocket123_get_speed_xyz; | |
| gpointer name_forcing_5 = foo_igen_test_ugly_case_interface_call_get_iscsi_servers; | |
| gpointer name_forcing_6 = foo_igen_test_ugly_case_interface_emit_servers_updated_now; | |
| gpointer name_forcing_7 = foo_igen_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 (FooiGenChangingInterface##v1##Iface, name), ==, G_STRUCT_OFFSET (FooiGenChangingInterface##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 | |
| /* ---------------------------------------------------------------------------------------------------- */ | |
| /* property naming | |
| * | |
| * - check that a property with name "Type" is mapped into g-name "type" | |
| * with C accessors get_type_ (to avoid clashing with the GType accessor) | |
| * and set_type_ (for symmetry) | |
| * (see https://bugzilla.gnome.org/show_bug.cgi?id=679473 for details) | |
| * | |
| * - (could add more tests here) | |
| */ | |
| static void | |
| test_property_naming (void) | |
| { | |
| gpointer c_getter_name = foo_igen_naming_get_type_; | |
| gpointer c_setter_name = foo_igen_naming_set_type_; | |
| FooiGenNaming *skel; | |
| (void) c_getter_name; | |
| (void) c_setter_name; | |
| skel = foo_igen_naming_skeleton_new (); | |
| g_assert (g_object_class_find_property (G_OBJECT_GET_CLASS (skel), "type") != NULL); | |
| g_object_unref (skel); | |
| } | |
| /* ---------------------------------------------------------------------------------------------------- */ | |
| /* autocleanups | |
| * | |
| * - check that g_autoptr() works for all generated types, if supported by the | |
| * current compiler | |
| */ | |
| static void | |
| test_autocleanups (void) | |
| { | |
| #ifdef g_autoptr | |
| g_autoptr(FooiGenBar) bar = NULL; | |
| g_autoptr(FooiGenBarProxy) bar_proxy = NULL; | |
| g_autoptr(FooiGenBarSkeleton) bar_skeleton = NULL; | |
| g_autoptr(FooiGenObject) object = NULL; | |
| g_autoptr(FooiGenObjectProxy) object_proxy = NULL; | |
| g_autoptr(FooiGenObjectSkeleton) object_skeleton = NULL; | |
| g_autoptr(FooiGenObjectManagerClient) object_manager_client = NULL; | |
| (void) bar; | |
| (void) bar_proxy; | |
| (void) bar_skeleton; | |
| (void) object; | |
| (void) object_proxy; | |
| (void) object_skeleton; | |
| (void) object_manager_client; | |
| #elif GLIB_CHECK_VERSION(2, 38, 0) | |
| /* This file is compiled twice, once without GLib version guards and once | |
| * with | |
| * | |
| * -DGLIB_VERSION_MIN_REQUIRED=GLIB_VERSION_2_36 | |
| * -DGLIB_VERSION_MAX_ALLOWED=GLIB_VERSION_2_36 | |
| * | |
| * g_test_skip() was added in 2.38. | |
| */ | |
| g_test_skip ("g_autoptr() not supported on this compiler"); | |
| #else | |
| /* Let's just say it passed. */ | |
| #endif | |
| } | |
| /* ---------------------------------------------------------------------------------------------------- */ | |
| /* deprecations | |
| */ | |
| static void | |
| test_deprecations (void) | |
| { | |
| { | |
| FooiGenOldieInterface *iskel; | |
| GParamSpec *pspec; | |
| G_GNUC_BEGIN_IGNORE_DEPRECATIONS; | |
| iskel = foo_igen_oldie_interface_skeleton_new (); | |
| G_GNUC_END_IGNORE_DEPRECATIONS; | |
| pspec = g_object_class_find_property (G_OBJECT_GET_CLASS (iskel), "bat"); | |
| g_assert_nonnull (pspec); | |
| g_assert_cmpint (pspec->flags & G_PARAM_DEPRECATED, ==, G_PARAM_DEPRECATED); | |
| g_object_unref (iskel); | |
| } | |
| { | |
| FooiGenObjectSkeleton *oskel; | |
| GParamSpec *pspec; | |
| oskel = foo_igen_object_skeleton_new ("/objects/first"); | |
| pspec = g_object_class_find_property (G_OBJECT_GET_CLASS (oskel), "oldie-interface"); | |
| g_assert_nonnull (pspec); | |
| g_assert_cmpint (pspec->flags & G_PARAM_DEPRECATED, ==, G_PARAM_DEPRECATED); | |
| g_object_unref (oskel); | |
| } | |
| } | |
| /* ---------------------------------------------------------------------------------------------------- */ | |
| static void | |
| assert_arg_infos_equal (GDBusArgInfo **a, | |
| GDBusArgInfo **b) | |
| { | |
| if (a == NULL) | |
| { | |
| g_assert_null (b); | |
| return; | |
| } | |
| g_assert_nonnull (b); | |
| for (; *a != NULL && *b != NULL; a++, b++) | |
| { | |
| g_assert_cmpstr ((*a)->name, ==, (*b)->name); | |
| g_assert_cmpstr ((*a)->signature, ==, (*b)->signature); | |
| } | |
| g_assert_null (*a); | |
| g_assert_null (*b); | |
| } | |
| static void | |
| assert_annotations_equal (GDBusAnnotationInfo **a, | |
| GDBusAnnotationInfo **b) | |
| { | |
| guint a_len = count_annotations (a); | |
| guint b_len = count_annotations (b); | |
| g_assert_cmpuint (a_len, ==, b_len); | |
| if (a == NULL || b == NULL) | |
| return; | |
| for (; *a != NULL && *b != NULL; a++, b++) | |
| { | |
| g_assert_cmpstr ((*a)->key, ==, (*b)->key); | |
| g_assert_cmpstr ((*a)->value, ==, (*b)->value); | |
| assert_annotations_equal ((*a)->annotations, (*b)->annotations); | |
| } | |
| g_assert_null (*a); | |
| g_assert_null (*b); | |
| } | |
| /* Test that the GDBusInterfaceInfo structure generated by gdbus-codegen | |
| * --interface-info-body matches that generated by the other mode. | |
| */ | |
| static void | |
| test_standalone_interface_info (void) | |
| { | |
| GDBusInterfaceSkeleton *skel = G_DBUS_INTERFACE_SKELETON (foo_igen_bar_skeleton_new ()); | |
| GDBusInterfaceInfo *skel_info = g_dbus_interface_skeleton_get_info (skel); | |
| const GDBusInterfaceInfo *slim_info = &org_project_bar_interface; | |
| gsize i; | |
| g_assert_cmpstr (skel_info->name, ==, slim_info->name); | |
| for (i = 0; skel_info->methods[i] != NULL; i++) | |
| { | |
| GDBusMethodInfo *skel_method = skel_info->methods[i]; | |
| GDBusMethodInfo *slim_method = slim_info->methods[i]; | |
| g_assert_nonnull (slim_method); | |
| g_assert_cmpstr (skel_method->name, ==, slim_method->name); | |
| assert_arg_infos_equal (skel_method->in_args, slim_method->in_args); | |
| assert_arg_infos_equal (skel_method->out_args, slim_method->out_args); | |
| assert_annotations_equal (skel_method->annotations, slim_method->annotations); | |
| } | |
| g_assert_null (slim_info->methods[i]); | |
| for (i = 0; skel_info->signals[i] != NULL; i++) | |
| { | |
| GDBusSignalInfo *skel_signal = skel_info->signals[i]; | |
| GDBusSignalInfo *slim_signal = slim_info->signals[i]; | |
| g_assert_nonnull (slim_signal); | |
| g_assert_cmpstr (skel_signal->name, ==, slim_signal->name); | |
| assert_arg_infos_equal (skel_signal->args, slim_signal->args); | |
| assert_annotations_equal (skel_signal->annotations, slim_signal->annotations); | |
| } | |
| g_assert_null (slim_info->signals[i]); | |
| for (i = 0; skel_info->properties[i] != NULL; i++) | |
| { | |
| GDBusPropertyInfo *skel_prop = skel_info->properties[i]; | |
| GDBusPropertyInfo *slim_prop = slim_info->properties[i]; | |
| g_assert_nonnull (slim_prop); | |
| g_assert_cmpstr (skel_prop->name, ==, slim_prop->name); | |
| g_assert_cmpstr (skel_prop->signature, ==, slim_prop->signature); | |
| g_assert_cmpuint (skel_prop->flags, ==, slim_prop->flags); | |
| assert_annotations_equal (skel_prop->annotations, slim_prop->annotations); | |
| } | |
| g_assert_null (slim_info->properties[i]); | |
| assert_annotations_equal (skel_info->annotations, slim_info->annotations); | |
| g_clear_object (&skel); | |
| } | |
| /* ---------------------------------------------------------------------------------------------------- */ | |
| static gboolean | |
| handle_hello_fd (FooiGenTestFDPassing *object, | |
| GDBusMethodInvocation *invocation, | |
| GUnixFDList *fd_list, | |
| const gchar *arg_greeting) | |
| { | |
| foo_igen_test_fdpassing_complete_hello_fd (object, invocation, fd_list, arg_greeting); | |
| return G_DBUS_METHOD_INVOCATION_HANDLED; | |
| } | |
| #if GLIB_VERSION_MIN_REQUIRED >= GLIB_VERSION_2_64 | |
| static gboolean | |
| handle_no_annotation (FooiGenTestFDPassing *object, | |
| GDBusMethodInvocation *invocation, | |
| GUnixFDList *fd_list, | |
| GVariant *arg_greeting, | |
| const gchar *arg_greeting_locale) | |
| { | |
| foo_igen_test_fdpassing_complete_no_annotation (object, invocation, fd_list, arg_greeting, arg_greeting_locale); | |
| return G_DBUS_METHOD_INVOCATION_HANDLED; | |
| } | |
| static gboolean | |
| handle_no_annotation_nested (FooiGenTestFDPassing *object, | |
| GDBusMethodInvocation *invocation, | |
| GUnixFDList *fd_list, | |
| GVariant *arg_files) | |
| { | |
| foo_igen_test_fdpassing_complete_no_annotation_nested (object, invocation, fd_list); | |
| return G_DBUS_METHOD_INVOCATION_HANDLED; | |
| } | |
| #else | |
| static gboolean | |
| handle_no_annotation (FooiGenTestFDPassing *object, | |
| GDBusMethodInvocation *invocation, | |
| GVariant *arg_greeting, | |
| const gchar *arg_greeting_locale) | |
| { | |
| foo_igen_test_fdpassing_complete_no_annotation (object, invocation, arg_greeting, arg_greeting_locale); | |
| return G_DBUS_METHOD_INVOCATION_HANDLED; | |
| } | |
| static gboolean | |
| handle_no_annotation_nested (FooiGenTestFDPassing *object, | |
| GDBusMethodInvocation *invocation, | |
| GVariant *arg_files) | |
| { | |
| foo_igen_test_fdpassing_complete_no_annotation_nested (object, invocation); | |
| return G_DBUS_METHOD_INVOCATION_HANDLED; | |
| } | |
| #endif | |
| /* Test that generated code for methods includes GUnixFDList arguments | |
| * unconditionally if the method is explicitly annotated as C.UnixFD, and only | |
| * emits GUnixFDList arguments when there's merely an 'h' parameter if | |
| * --glib-min-required=2.64 or greater. | |
| */ | |
| static void | |
| test_unix_fd_list (void) | |
| { | |
| FooiGenTestFDPassingIface iface; | |
| g_test_bug ("https://gitlab.gnome.org/GNOME/glib/issues/1726"); | |
| /* This method is explicitly annotated. */ | |
| iface.handle_hello_fd = handle_hello_fd; | |
| /* This one is not annotated; even though it's got an in and out 'h' | |
| * parameter, for backwards compatibility we cannot emit GUnixFDList | |
| * arguments unless --glib-min-required >= 2.64 was used. | |
| */ | |
| iface.handle_no_annotation = handle_no_annotation; | |
| /* This method has an 'h' inside a complex type. */ | |
| iface.handle_no_annotation_nested = handle_no_annotation_nested; | |
| (void) iface; | |
| } | |
| /* ---------------------------------------------------------------------------------------------------- */ | |
| int | |
| main (int argc, | |
| char *argv[]) | |
| { | |
| g_test_init (&argc, &argv, G_TEST_OPTION_ISOLATE_DIRS, NULL); | |
| 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); | |
| g_test_add_func ("/gdbus/codegen/property-naming", test_property_naming); | |
| g_test_add_func ("/gdbus/codegen/autocleanups", test_autocleanups); | |
| g_test_add_func ("/gdbus/codegen/deprecations", test_deprecations); | |
| g_test_add_func ("/gdbus/codegen/standalone-interface-info", test_standalone_interface_info); | |
| g_test_add_func ("/gdbus/codegen/unix-fd-list", test_unix_fd_list); | |
| return session_bus_run (); | |
| } |