From 07bbc87615c6c0d6a525f40c2bffad2c11e400d2 Mon Sep 17 00:00:00 2001 From: Xavier Claessens Date: Tue, 17 Apr 2012 19:33:11 +0200 Subject: [PATCH] Add a private copy of gio/tests/gdbus-tests.c,h to gio/ https://bugzilla.gnome.org/show_bug.cgi?id=672985 --- gio/Makefile.am | 1 + gio/gdbus-tests.c | 268 ++++++++++++++++++++++++++++++++++++++++++++++ gio/gdbus-tests.h | 145 +++++++++++++++++++++++++ 3 files changed, 414 insertions(+) create mode 100644 gio/gdbus-tests.c create mode 100644 gio/gdbus-tests.h diff --git a/gio/Makefile.am b/gio/Makefile.am index f34dfa307..cb30475f7 100644 --- a/gio/Makefile.am +++ b/gio/Makefile.am @@ -94,6 +94,7 @@ gdbus_sources = \ gdbusobjectmanager.h gdbusobjectmanager.c \ gdbusobjectmanagerclient.h gdbusobjectmanagerclient.c \ gdbusobjectmanagerserver.h gdbusobjectmanagerserver.c \ + gdbus-tests.h gdbus-tests.c \ $(NULL) settings_headers = \ diff --git a/gio/gdbus-tests.c b/gio/gdbus-tests.c new file mode 100644 index 000000000..c51aebe94 --- /dev/null +++ b/gio/gdbus-tests.c @@ -0,0 +1,268 @@ +/* GLib testing framework examples and tests + * + * Copyright (C) 2008-2010 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General + * Public License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place, Suite 330, + * Boston, MA 02111-1307, USA. + * + * Author: David Zeuthen + */ + +#include "config.h" + +#include + +#include "gdbus-tests.h" +#include "gdbusaddress.h" +#include "gdbusconnection.h" + +/* ---------------------------------------------------------------------------------------------------- */ + +typedef struct +{ + GMainLoop *loop; + gboolean timed_out; +} PropertyNotifyData; + +static void +on_property_notify (GObject *object, + GParamSpec *pspec, + gpointer user_data) +{ + PropertyNotifyData *data = user_data; + g_main_loop_quit (data->loop); +} + +static gboolean +on_property_notify_timeout (gpointer user_data) +{ + PropertyNotifyData *data = user_data; + data->timed_out = TRUE; + g_main_loop_quit (data->loop); + return TRUE; +} + +gboolean +_g_assert_property_notify_run (gpointer object, + const gchar *property_name) +{ + gchar *s; + gulong handler_id; + guint timeout_id; + PropertyNotifyData data; + + data.loop = g_main_loop_new (g_main_context_get_thread_default (), FALSE); + data.timed_out = FALSE; + s = g_strdup_printf ("notify::%s", property_name); + handler_id = g_signal_connect (object, + s, + G_CALLBACK (on_property_notify), + &data); + g_free (s); + timeout_id = g_timeout_add (30 * 1000, + on_property_notify_timeout, + &data); + g_main_loop_run (data.loop); + g_signal_handler_disconnect (object, handler_id); + g_source_remove (timeout_id); + g_main_loop_unref (data.loop); + + return data.timed_out; +} + +/* ---------------------------------------------------------------------------------------------------- */ + +typedef struct +{ + GMainLoop *loop; + gboolean timed_out; +} SignalReceivedData; + +static void +on_signal_received (gpointer user_data) +{ + SignalReceivedData *data = user_data; + g_main_loop_quit (data->loop); +} + +static gboolean +on_signal_received_timeout (gpointer user_data) +{ + SignalReceivedData *data = user_data; + data->timed_out = TRUE; + g_main_loop_quit (data->loop); + return TRUE; +} + +gboolean +_g_assert_signal_received_run (gpointer object, + const gchar *signal_name) +{ + gulong handler_id; + guint timeout_id; + SignalReceivedData data; + + data.loop = g_main_loop_new (g_main_context_get_thread_default (), FALSE); + data.timed_out = FALSE; + handler_id = g_signal_connect_swapped (object, + signal_name, + G_CALLBACK (on_signal_received), + &data); + timeout_id = g_timeout_add (30 * 1000, + on_signal_received_timeout, + &data); + g_main_loop_run (data.loop); + g_signal_handler_disconnect (object, handler_id); + g_source_remove (timeout_id); + g_main_loop_unref (data.loop); + + return data.timed_out; +} + +/* ---------------------------------------------------------------------------------------------------- */ + +GDBusConnection * +_g_bus_get_priv (GBusType bus_type, + GCancellable *cancellable, + GError **error) +{ + gchar *address; + GDBusConnection *ret; + + ret = NULL; + + address = g_dbus_address_get_for_bus_sync (bus_type, cancellable, error); + if (address == NULL) + goto out; + + ret = g_dbus_connection_new_for_address_sync (address, + G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_CLIENT | + G_DBUS_CONNECTION_FLAGS_MESSAGE_BUS_CONNECTION, + NULL, /* GDBusAuthObserver */ + cancellable, + error); + g_free (address); + + out: + return ret; +} + +/* ---------------------------------------------------------------------------------------------------- */ + +#if 0 +/* toggle refs are not easy to use (maybe not even safe) when multiple + * threads are involved so implement this by busy-waiting for now + */ +gboolean +_g_object_wait_for_single_ref_do (gpointer object) +{ + guint num_ms_elapsed; + gboolean timed_out; + + timed_out = FALSE; + num_ms_elapsed = 0; + + while (TRUE) + { + if (G_OBJECT (object)->ref_count == 1) + goto out; + + if (num_ms_elapsed > 30000) + { + timed_out = TRUE; + goto out; + } + + usleep (10 * 1000); + num_ms_elapsed += 10; + } + + out: + return timed_out; +} + +#else + +typedef struct +{ + GMainLoop *loop; + gboolean timed_out; +} WaitSingleRefData; + +static gboolean +on_wait_single_ref_timeout (gpointer user_data) +{ + WaitSingleRefData *data = user_data; + data->timed_out = TRUE; + g_main_loop_quit (data->loop); + return TRUE; +} + +static void +on_wait_for_single_ref_toggled (gpointer user_data, + GObject *object, + gboolean is_last_ref) +{ + WaitSingleRefData *data = user_data; + g_main_loop_quit (data->loop); +} + +gboolean +_g_object_wait_for_single_ref_do (gpointer object) +{ + WaitSingleRefData data; + guint timeout_id; + + data.timed_out = FALSE; + + if (G_OBJECT (object)->ref_count == 1) + goto out; + + data.loop = g_main_loop_new (NULL, FALSE); + timeout_id = g_timeout_add (30 * 1000, + on_wait_single_ref_timeout, + &data); + + g_object_add_toggle_ref (G_OBJECT (object), + on_wait_for_single_ref_toggled, + &data); + /* the reference could have been removed between us checking the + * ref_count and the toggle ref being added + */ + if (G_OBJECT (object)->ref_count == 2) + goto single_ref_already; + + g_object_unref (object); + g_main_loop_run (data.loop); + g_object_ref (object); + +single_ref_already: + g_object_remove_toggle_ref (object, + on_wait_for_single_ref_toggled, + &data); + + g_source_remove (timeout_id); + g_main_loop_unref (data.loop); + + out: + if (data.timed_out) + { + g_printerr ("b ref_count is %d\n", G_OBJECT (object)->ref_count); + } + return data.timed_out; +} +#endif + +/* ---------------------------------------------------------------------------------------------------- */ diff --git a/gio/gdbus-tests.h b/gio/gdbus-tests.h new file mode 100644 index 000000000..a92d24282 --- /dev/null +++ b/gio/gdbus-tests.h @@ -0,0 +1,145 @@ +/* GLib testing framework examples and tests + * + * Copyright (C) 2008-2009 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General + * Public License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place, Suite 330, + * Boston, MA 02111-1307, USA. + * + * Author: David Zeuthen + */ + +#ifndef __TESTS_H__ +#define __TESTS_H__ + +#include + +G_BEGIN_DECLS + +/* TODO: clean up and move to gtestutils.c + * + * This is needed because libdbus-1 does not give predictable error messages - e.g. you + * get a different error message on connecting to a bus if the socket file is there vs + * if the socket file is missing. + */ + +#define _g_assert_error_domain(err, dom) do { if (!err || (err)->domain != dom) \ + g_assertion_message_error (G_LOG_DOMAIN, __FILE__, __LINE__, G_STRFUNC, \ + #err, err, dom, -1); } while (0) + +#define _g_assert_property_notify(object, property_name) \ + do \ + { \ + if (!G_IS_OBJECT (object)) \ + { \ + g_assertion_message (G_LOG_DOMAIN, \ + __FILE__, \ + __LINE__, \ + G_STRFUNC, \ + "Not a GObject instance"); \ + } \ + if (g_object_class_find_property (G_OBJECT_GET_CLASS (object), \ + property_name) == NULL) \ + { \ + g_assertion_message (G_LOG_DOMAIN, \ + __FILE__, \ + __LINE__, \ + G_STRFUNC, \ + "Property " property_name " does not " \ + "exist on object"); \ + } \ + if (_g_assert_property_notify_run (object, property_name)) \ + { \ + g_assertion_message (G_LOG_DOMAIN, \ + __FILE__, \ + __LINE__, \ + G_STRFUNC, \ + "Timed out waiting for notification " \ + "on property " property_name); \ + } \ + } \ + while (FALSE) + +#define _g_assert_signal_received(object, signal_name) \ + do \ + { \ + if (!G_IS_OBJECT (object)) \ + { \ + g_assertion_message (G_LOG_DOMAIN, \ + __FILE__, \ + __LINE__, \ + G_STRFUNC, \ + "Not a GObject instance"); \ + } \ + if (g_signal_lookup (signal_name, \ + G_TYPE_FROM_INSTANCE (object)) == 0) \ + { \ + g_assertion_message (G_LOG_DOMAIN, \ + __FILE__, \ + __LINE__, \ + G_STRFUNC, \ + "Signal `" signal_name "' does not " \ + "exist on object"); \ + } \ + if (_g_assert_signal_received_run (object, signal_name)) \ + { \ + g_assertion_message (G_LOG_DOMAIN, \ + __FILE__, \ + __LINE__, \ + G_STRFUNC, \ + "Timed out waiting for signal `" \ + signal_name "'"); \ + } \ + } \ + while (FALSE) + +gboolean _g_assert_property_notify_run (gpointer object, + const gchar *property_name); + + +gboolean _g_assert_signal_received_run (gpointer object, + const gchar *signal_name); + +GDBusConnection *_g_bus_get_priv (GBusType bus_type, + GCancellable *cancellable, + GError **error); + + +#define _g_object_wait_for_single_ref(object) \ + do \ + { \ + if (!G_IS_OBJECT (object)) \ + { \ + g_assertion_message (G_LOG_DOMAIN, \ + __FILE__, \ + __LINE__, \ + G_STRFUNC, \ + "Not a GObject instance"); \ + } \ + if (_g_object_wait_for_single_ref_do (object)) \ + { \ + g_assertion_message (G_LOG_DOMAIN, \ + __FILE__, \ + __LINE__, \ + G_STRFUNC, \ + "Timed out waiting for single ref"); \ + } \ + } \ + while (FALSE) + +gboolean _g_object_wait_for_single_ref_do (gpointer object); + +G_END_DECLS + +#endif /* __TESTS_H__ */