From 0e6b350ae0c8b695d73e88f1a24c0b80d3dd5909 Mon Sep 17 00:00:00 2001 From: Simon McVittie Date: Wed, 28 Sep 2011 14:56:45 +0100 Subject: [PATCH 07/10] Add a new test for error mapping Signed-off-by: Simon McVittie Bug: https://bugs.freedesktop.org/show_bug.cgi?id=40151 --- .gitignore | 1 + test/core/Makefile.am | 7 + test/core/error-mapping.c | 327 +++++++++++++++++++++++++++++++++++++++++++++ test/core/run-test.sh | 1 + 4 files changed, 336 insertions(+), 0 deletions(-) create mode 100644 test/core/error-mapping.c diff --git a/.gitignore b/.gitignore index c568858..ac454ed 100644 --- a/.gitignore +++ b/.gitignore @@ -198,6 +198,7 @@ test/core/run-with-tmp-session-bus.conf test/core/peer-client test/core/peer-server test/core/test-dbus-glib +/test/core/test-error-mapping test/core/test-profile test/core/test-proxy-peer test/core/test-service-glib diff --git a/test/core/Makefile.am b/test/core/Makefile.am index ef6cb26..e1d3502 100644 --- a/test/core/Makefile.am +++ b/test/core/Makefile.am @@ -48,6 +48,7 @@ endif ## build even when not doing "make check" noinst_PROGRAMS = \ test-dbus-glib \ + test-error-mapping \ test-service-glib \ $(THREAD_APPS) \ peer-server \ @@ -84,6 +85,12 @@ test_dbus_glib_SOURCES= \ test_dbus_glib_LDADD= $(tool_ldadd) +test_error_mapping_SOURCES = \ + my-object.c \ + my-object.h \ + my-object-marshal.c \ + error-mapping.c + test_variant_recursion_SOURCES=test-variant-recursion.c test_variant_recursion_LDADD= $(tool_ldadd) diff --git a/test/core/error-mapping.c b/test/core/error-mapping.c new file mode 100644 index 0000000..eafef01 --- /dev/null +++ b/test/core/error-mapping.c @@ -0,0 +1,327 @@ +/* Feature test for exported object methods raising errors + * + * Copyright © 2006-2010 Red Hat, Inc. + * Copyright © 2006-2010 Collabora Ltd. + * Copyright © 2006-2011 Nokia Corporation + * Copyright © 2006 Steve Frécinaux + * + * Licensed under the Academic Free License version 2.1 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301 USA + */ + +#include + +#include +#include + +#include +#include +#include + +#include + +#include "my-object.h" +#include "test-service-glib-bindings.h" + +/* my-object wants this to exist */ +GMainLoop *loop = NULL; + +typedef struct { + GError *error; + gchar *error_name; + DBusGConnection *conn; + DBusGProxy *proxy; + GObject *object; +} Fixture; + +#define assert_contains(haystack, needle) \ + assert_contains_impl (__FILE__, __LINE__, G_STRINGIFY (haystack), haystack, \ + G_STRINGIFY (needle), needle) + +static void +assert_contains_impl (const gchar *file, + gint line, + const gchar *haystack_desc, + const gchar *haystack, + const gchar *needle_desc, + const gchar *needle) +{ + if (G_UNLIKELY (strstr (haystack, needle) == NULL)) + { + g_error ("%s:%d: assertion failed: (%s) contains (%s): " + "values are \"%s\", \"%s\"", + file, line, haystack_desc, needle_desc, haystack, needle); + } +} + +static void +setup (Fixture *f, + gconstpointer context) +{ + static gsize once = 0; + + dbus_g_type_specialized_init (); + + if (g_once_init_enter (&once)) + { + /* this may only be called once */ + dbus_g_error_domain_register (MY_OBJECT_ERROR, NULL, MY_TYPE_ERROR); + + g_once_init_leave (&once, 1); + } + + f->conn = dbus_g_bus_get_private (DBUS_BUS_SESSION, NULL, &f->error); + g_assert_no_error (f->error); + g_assert (f->conn != NULL); + + f->object = g_object_new (MY_TYPE_OBJECT, NULL); + g_assert (MY_IS_OBJECT (f->object)); + dbus_g_connection_register_g_object (f->conn, "/com/example/Test/Object", + f->object); + + f->proxy = dbus_g_proxy_new_for_name (f->conn, + dbus_bus_get_unique_name (dbus_g_connection_get_connection (f->conn)), + "/com/example/Test/Object", "org.freedesktop.DBus.GLib.Tests.MyObject"); + g_assert (f->proxy != NULL); +} + +static void +throw_error_cb (DBusGProxy *proxy, + GError *error, + gpointer user_data) +{ + Fixture *f = user_data; + + g_assert (error != NULL); + g_clear_error (&f->error); + g_free (f->error_name); + f->error = g_error_copy (error); + + if (g_error_matches (error, DBUS_GERROR, DBUS_GERROR_REMOTE_EXCEPTION)) + f->error_name = g_strdup (dbus_g_error_get_name (error)); + else + f->error_name = NULL; +} + +static void +test_async (Fixture *f, + gconstpointer context) +{ + /* This is equivalent to test_simple but uses a method that's implemented + * async at the service side - it's a different calling convention for the + * service, but is indistinguishable here. */ + + my_object_save_error ((MyObject *) f->object, MY_OBJECT_ERROR, + MY_OBJECT_ERROR_FOO, ""); + + if (!org_freedesktop_DBus_GLib_Tests_MyObject_async_throw_error_async ( + f->proxy, throw_error_cb, f)) + g_error ("Failed to start async AsyncThrowError call"); + + while (f->error == NULL) + g_main_context_iteration (NULL, TRUE); + + g_assert_error (f->error, DBUS_GERROR, DBUS_GERROR_REMOTE_EXCEPTION); + g_assert_cmpstr (f->error_name, ==, + "org.freedesktop.DBus.GLib.Tests.MyObject.Foo"); + assert_contains (f->error->message, ""); +} + +static void +test_simple (Fixture *f, + gconstpointer context) +{ + my_object_save_error ((MyObject *) f->object, MY_OBJECT_ERROR, + MY_OBJECT_ERROR_FOO, ""); + + if (!org_freedesktop_DBus_GLib_Tests_MyObject_throw_error_async ( + f->proxy, throw_error_cb, f)) + g_error ("Failed to start async ThrowError call"); + + while (f->error == NULL) + g_main_context_iteration (NULL, TRUE); + + g_assert_error (f->error, DBUS_GERROR, DBUS_GERROR_REMOTE_EXCEPTION); + g_assert_cmpstr (f->error_name, ==, + "org.freedesktop.DBus.GLib.Tests.MyObject.Foo"); + assert_contains (f->error->message, ""); +} + +static void +test_builtin (Fixture *f, + gconstpointer context) +{ + g_test_bug ("16776"); + + my_object_save_error ((MyObject *) f->object, DBUS_GERROR, + DBUS_GERROR_NOT_SUPPORTED, ""); + + if (!org_freedesktop_DBus_GLib_Tests_MyObject_throw_error_async ( + f->proxy, throw_error_cb, f)) + g_error ("Failed to start async ThrowError call"); + + while (f->error == NULL) + g_main_context_iteration (NULL, TRUE); + + g_assert_error (f->error, DBUS_GERROR, DBUS_GERROR_NOT_SUPPORTED); + assert_contains (f->error->message, ""); +} + +static void +test_multi_word (Fixture *f, + gconstpointer context) +{ + /* no bug#, but this is a regression test for commit 3d69cfeab177e */ + + my_object_save_error ((MyObject *) f->object, MY_OBJECT_ERROR, + MY_OBJECT_ERROR_MULTI_WORD, "this method's error has a hyphen"); + + if (!org_freedesktop_DBus_GLib_Tests_MyObject_throw_error_async ( + f->proxy, throw_error_cb, f)) + g_error ("Failed to start async ThrowError call"); + + while (f->error == NULL) + g_main_context_iteration (NULL, TRUE); + + g_assert_error (f->error, DBUS_GERROR, DBUS_GERROR_REMOTE_EXCEPTION); + g_assert_cmpstr (f->error_name, ==, + "org.freedesktop.DBus.GLib.Tests.MyObject.MultiWord"); + assert_contains (f->error->message, "this method's error has a hyphen"); +} + +static void +test_underscore (Fixture *f, + gconstpointer context) +{ + g_test_bug ("30274"); + + my_object_save_error ((MyObject *) f->object, MY_OBJECT_ERROR, + MY_OBJECT_ERROR_UNDER_SCORE, "this method's error has an underscore"); + + if (!org_freedesktop_DBus_GLib_Tests_MyObject_throw_error_async ( + f->proxy, throw_error_cb, f)) + g_error ("Failed to start async ThrowError call"); + + while (f->error == NULL) + g_main_context_iteration (NULL, TRUE); + + g_assert_error (f->error, DBUS_GERROR, DBUS_GERROR_REMOTE_EXCEPTION); + g_assert_cmpstr (f->error_name, ==, + "org.freedesktop.DBus.GLib.Tests.MyObject.Under_score"); + assert_contains (f->error->message, "this method's error has an underscore"); +} + +static void +test_unregistered (Fixture *f, + gconstpointer context) +{ + g_test_bug ("27799"); + + my_object_save_error ((MyObject *) f->object, G_IO_ERROR, + G_IO_ERROR_NOT_INITIALIZED, + "dbus-glib does not know about this error domain"); + + if (!org_freedesktop_DBus_GLib_Tests_MyObject_throw_error_async ( + f->proxy, throw_error_cb, f)) + g_error ("Failed to start async ThrowError call"); + + while (f->error == NULL) + g_main_context_iteration (NULL, TRUE); + + g_assert_error (f->error, DBUS_GERROR, DBUS_GERROR_REMOTE_EXCEPTION); + assert_contains (f->error->message, + "dbus-glib does not know about this error domain"); +} + +static void +test_nonsensical (Fixture *f, + gconstpointer context) +{ + /* This throws an error with domain 0 and code 0, which makes no sense. + * It's programmer error, really: g_error_new() would critical if given + * the same domain and code. See GNOME#660371. + * + * This was added for fd.o #27799, but there's a difference between + * "this is an error domain, but not one registered with dbus-glib" and + * "this isn't even an error domain". */ + g_test_bug ("27799"); + + if (!org_freedesktop_DBus_GLib_Tests_MyObject_throw_unregistered_error_async ( + f->proxy, throw_error_cb, f)) + g_error ("Failed to start async ThrowUnregisteredError call"); + + while (f->error == NULL) + g_main_context_iteration (NULL, TRUE); + + g_assert_error (f->error, DBUS_GERROR, DBUS_GERROR_REMOTE_EXCEPTION); + assert_contains (f->error->message, "this method always loses more"); +} + +static void +teardown (Fixture *f, + gconstpointer context G_GNUC_UNUSED) +{ + g_free (f->error_name); + + g_clear_error (&f->error); + + if (f->proxy != NULL) + { + g_object_unref (f->proxy); + f->proxy = NULL; + } + + if (f->object != NULL) + { + g_object_unref (f->object); + f->object = NULL; + } + + if (f->conn != NULL) + { + dbus_connection_close (dbus_g_connection_get_connection (f->conn)); + dbus_g_connection_unref (f->conn); + f->conn = NULL; + } +} + +int +main (int argc, + char **argv) +{ + g_test_init (&argc, &argv, NULL); + g_test_bug_base ("https://bugs.freedesktop.org/show_bug.cgi?id="); + + g_type_init (); + + g_test_add ("/error-mapping/async", Fixture, NULL, setup, test_async, + teardown); + g_test_add ("/error-mapping/builtin", Fixture, NULL, setup, test_builtin, + teardown); + g_test_add ("/error-mapping/multi-word", Fixture, NULL, setup, + test_multi_word, teardown); + g_test_add ("/error-mapping/nonsensical", Fixture, NULL, setup, + test_nonsensical, teardown); + g_test_add ("/error-mapping/simple", Fixture, NULL, setup, test_simple, + teardown); + g_test_add ("/error-mapping/underscore", Fixture, NULL, setup, + test_underscore, teardown); + g_test_add ("/error-mapping/unregistered", Fixture, NULL, setup, + test_unregistered, teardown); + + return g_test_run (); +} diff --git a/test/core/run-test.sh b/test/core/run-test.sh index 09e28b1..b4c2fbc 100755 --- a/test/core/run-test.sh +++ b/test/core/run-test.sh @@ -49,4 +49,5 @@ else ${DBUS_TOP_BUILDDIR}/libtool --mode=execute $DEBUG $DBUS_TOP_BUILDDIR/test/core/test-variant-recursion || die "test-variant-recursion failed" ${DBUS_TOP_BUILDDIR}/libtool --mode=execute $DEBUG $DBUS_TOP_BUILDDIR/test/core/test-gvariant || die "test-gvariant failed" ${DBUS_TOP_BUILDDIR}/libtool --mode=execute $DEBUG $DBUS_TOP_BUILDDIR/test/core/test-30574 || die "test-30574 failed" + ${DBUS_TOP_BUILDDIR}/libtool --mode=execute $DEBUG $DBUS_TOP_BUILDDIR/test/core/test-error-mapping || die "test-error-mapping failed" fi -- 1.7.6.3