1 /* GLib testing framework examples and tests
2 *
3 * Copyright (C) 2008-2010 Red Hat, Inc.
4 *
5 * SPDX-License-Identifier: LGPL-2.1-or-later
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General
18 * Public License along with this library; if not, see <http://www.gnu.org/licenses/>.
19 *
20 * Author: David Zeuthen <davidz@redhat.com>
21 */
22
23 #include <gio/gio.h>
24 #include <unistd.h>
25 #include <string.h>
26
27 /* ---------------------------------------------------------------------------------------------------- */
28 /* Test that registered errors are properly mapped */
29 /* ---------------------------------------------------------------------------------------------------- */
30
31 static void
32 check_registered_error (const gchar *given_dbus_error_name,
33 GQuark error_domain,
34 gint error_code)
35 {
36 GError *error;
37 gchar *dbus_error_name;
38
39 error = g_dbus_error_new_for_dbus_error (given_dbus_error_name, "test message");
40 g_assert_error (error, error_domain, error_code);
41 g_assert (g_dbus_error_is_remote_error (error));
42 g_assert (g_dbus_error_strip_remote_error (error));
43 g_assert_cmpstr (error->message, ==, "test message");
44 dbus_error_name = g_dbus_error_get_remote_error (error);
45 g_assert_cmpstr (dbus_error_name, ==, given_dbus_error_name);
46 g_free (dbus_error_name);
47 g_error_free (error);
48 }
49
50 static void
51 test_registered_errors (void)
52 {
53 /* Here we check that we are able to map to GError and back for registered
54 * errors.
55 *
56 * For example, if "org.freedesktop.DBus.Error.AddressInUse" is
57 * associated with (G_DBUS_ERROR, G_DBUS_ERROR_DBUS_FAILED), check
58 * that
59 *
60 * - Creating a GError for e.g. "org.freedesktop.DBus.Error.AddressInUse"
61 * has (error_domain, code) == (G_DBUS_ERROR, G_DBUS_ERROR_DBUS_FAILED)
62 *
63 * - That it is possible to recover e.g. "org.freedesktop.DBus.Error.AddressInUse"
64 * as the D-Bus error name when dealing with an error with (error_domain, code) ==
65 * (G_DBUS_ERROR, G_DBUS_ERROR_DBUS_FAILED)
66 *
67 * We just check a couple of well-known errors.
68 */
69 check_registered_error ("org.freedesktop.DBus.Error.Failed",
70 G_DBUS_ERROR,
71 G_DBUS_ERROR_FAILED);
72 check_registered_error ("org.freedesktop.DBus.Error.AddressInUse",
73 G_DBUS_ERROR,
74 G_DBUS_ERROR_ADDRESS_IN_USE);
75 check_registered_error ("org.freedesktop.DBus.Error.UnknownMethod",
76 G_DBUS_ERROR,
77 G_DBUS_ERROR_UNKNOWN_METHOD);
78 check_registered_error ("org.freedesktop.DBus.Error.UnknownObject",
79 G_DBUS_ERROR,
80 G_DBUS_ERROR_UNKNOWN_OBJECT);
81 }
82
83 /* ---------------------------------------------------------------------------------------------------- */
84
85 static void
86 check_unregistered_error (const gchar *given_dbus_error_name)
87 {
88 GError *error;
89 gchar *dbus_error_name;
90
91 error = g_dbus_error_new_for_dbus_error (given_dbus_error_name, "test message");
92 g_assert_error (error, G_IO_ERROR, G_IO_ERROR_DBUS_ERROR);
93 g_assert (g_dbus_error_is_remote_error (error));
94 dbus_error_name = g_dbus_error_get_remote_error (error);
95 g_assert_cmpstr (dbus_error_name, ==, given_dbus_error_name);
96 g_free (dbus_error_name);
97
98 /* strip the message */
99 g_assert (g_dbus_error_strip_remote_error (error));
100 g_assert_cmpstr (error->message, ==, "test message");
101
102 /* check that we can no longer recover the D-Bus error name */
103 g_assert (g_dbus_error_get_remote_error (error) == NULL);
104
105 g_error_free (error);
106
107 }
108
109 static void
110 test_unregistered_errors (void)
111 {
112 /* Here we check that we are able to map to GError and back for unregistered
113 * errors.
114 *
115 * For example, if "com.example.Error.Failed" is not registered, then check
116 *
117 * - Creating a GError for e.g. "com.example.Error.Failed" has (error_domain, code) ==
118 * (G_IO_ERROR, G_IO_ERROR_DBUS_ERROR)
119 *
120 * - That it is possible to recover e.g. "com.example.Error.Failed" from that
121 * GError.
122 *
123 * We just check a couple of random errors.
124 */
125
126 check_unregistered_error ("com.example.Error.Failed");
127 check_unregistered_error ("foobar.buh");
128 }
129
130 /* ---------------------------------------------------------------------------------------------------- */
131
132 static void
133 check_transparent_gerror (GQuark error_domain,
134 gint error_code)
135 {
136 GError *error;
137 gchar *given_dbus_error_name;
138 gchar *dbus_error_name;
139
140 error = g_error_new (error_domain, error_code, "test message");
141 given_dbus_error_name = g_dbus_error_encode_gerror (error);
142 g_assert (g_str_has_prefix (given_dbus_error_name, "org.gtk.GDBus.UnmappedGError.Quark"));
143 g_error_free (error);
144
145 error = g_dbus_error_new_for_dbus_error (given_dbus_error_name, "test message");
146 g_assert_error (error, error_domain, error_code);
147 g_assert (g_dbus_error_is_remote_error (error));
148 dbus_error_name = g_dbus_error_get_remote_error (error);
149 g_assert_cmpstr (dbus_error_name, ==, given_dbus_error_name);
150 g_free (dbus_error_name);
151 g_free (given_dbus_error_name);
152
153 /* strip the message */
154 g_assert (g_dbus_error_strip_remote_error (error));
155 g_assert_cmpstr (error->message, ==, "test message");
156
157 /* check that we can no longer recover the D-Bus error name */
158 g_assert (g_dbus_error_get_remote_error (error) == NULL);
159
160 g_error_free (error);
161 }
162
163 static void
164 test_transparent_gerror (void)
165 {
166 /* Here we check that we are able to transparent pass unregistered GError's
167 * over the wire.
168 *
169 * For example, if G_IO_ERROR_FAILED is not registered, then check
170 *
171 * - g_dbus_error_encode_gerror() returns something of the form
172 * org.gtk.GDBus.UnmappedGError.Quark_HEXENCODED_QUARK_NAME_.Code_ERROR_CODE
173 *
174 * - mapping back the D-Bus error name gives us G_IO_ERROR_FAILED
175 *
176 * - That it is possible to recover the D-Bus error name from the
177 * GError.
178 *
179 * We just check a couple of random errors.
180 */
181
182 check_transparent_gerror (G_IO_ERROR, G_IO_ERROR_FAILED);
183 check_transparent_gerror (G_KEY_FILE_ERROR, G_KEY_FILE_ERROR_PARSE);
184 }
185
186 typedef enum
187 {
188 TEST_ERROR_FAILED,
189 TEST_ERROR_BLA
190 } TestError;
191
192 GDBusErrorEntry test_error_entries[] =
193 {
194 { TEST_ERROR_FAILED, "org.gtk.test.Error.Failed" },
195 { TEST_ERROR_BLA, "org.gtk.test.Error.Bla" }
196 };
197
198 static void
199 test_register_error (void)
200 {
201 gsize test_error_quark = 0;
202 gboolean res;
203 gchar *msg;
204 GError *error;
205
206 g_dbus_error_register_error_domain ("test-error-quark",
207 &test_error_quark,
208 test_error_entries,
209 G_N_ELEMENTS (test_error_entries));
210 g_assert_cmpint (test_error_quark, !=, 0);
211
212 error = g_dbus_error_new_for_dbus_error ("org.gtk.test.Error.Failed", "Failed");
213 g_assert_error (error, test_error_quark, TEST_ERROR_FAILED);
214 res = g_dbus_error_is_remote_error (error);
215 msg = g_dbus_error_get_remote_error (error);
216 g_assert (res);
217 g_assert_cmpstr (msg, ==, "org.gtk.test.Error.Failed");
218 res = g_dbus_error_strip_remote_error (error);
219 g_assert (res);
220 g_assert_cmpstr (error->message, ==, "Failed");
221 g_clear_error (&error);
222 g_free (msg);
223
224 g_dbus_error_set_dbus_error (&error, "org.gtk.test.Error.Failed", "Failed again", "Prefix %d", 1);
225 res = g_dbus_error_is_remote_error (error);
226 msg = g_dbus_error_get_remote_error (error);
227 g_assert (res);
228 g_assert_cmpstr (msg, ==, "org.gtk.test.Error.Failed");
229 res = g_dbus_error_strip_remote_error (error);
230 g_assert (res);
231 g_assert_cmpstr (error->message, ==, "Prefix 1: Failed again");
232 g_clear_error (&error);
233 g_free (msg);
234
235 error = g_error_new_literal (G_IO_ERROR, G_IO_ERROR_NOT_EMPTY, "Not Empty");
236 res = g_dbus_error_is_remote_error (error);
237 msg = g_dbus_error_get_remote_error (error);
238 g_assert (!res);
239 g_assert_cmpstr (msg, ==, NULL);
240 res = g_dbus_error_strip_remote_error (error);
241 g_assert (!res);
242 g_assert_cmpstr (error->message, ==, "Not Empty");
243 g_clear_error (&error);
244
245 error = g_error_new_literal (test_error_quark, TEST_ERROR_BLA, "Bla");
246 msg = g_dbus_error_encode_gerror (error);
247 g_assert_cmpstr (msg, ==, "org.gtk.test.Error.Bla");
248 g_free (msg);
249 g_clear_error (&error);
250
251 res = g_dbus_error_unregister_error (test_error_quark,
252 TEST_ERROR_BLA, "org.gtk.test.Error.Bla");
253 g_assert (res);
254 }
255
256
257 /* ---------------------------------------------------------------------------------------------------- */
258
259 int
260 main (int argc,
261 char *argv[])
262 {
263 g_test_init (&argc, &argv, G_TEST_OPTION_ISOLATE_DIRS, NULL);
264
265 g_test_add_func ("/gdbus/registered-errors", test_registered_errors);
266 g_test_add_func ("/gdbus/unregistered-errors", test_unregistered_errors);
267 g_test_add_func ("/gdbus/transparent-gerror", test_transparent_gerror);
268 g_test_add_func ("/gdbus/register-error", test_register_error);
269
270 return g_test_run();
271 }