1 | #include <glib.h> |
2 | |
3 | #include "glib-private.h" |
4 | |
5 | static void |
6 | test_overwrite (void) |
7 | { |
8 | GError *error, *dest, *src; |
9 | |
10 | if (!g_test_undefined ()) |
11 | return; |
12 | |
13 | error = g_error_new_literal (G_MARKUP_ERROR, code: G_MARKUP_ERROR_EMPTY, message: "bla" ); |
14 | |
15 | g_test_expect_message (G_LOG_DOMAIN, log_level: G_LOG_LEVEL_WARNING, |
16 | pattern: "*set over the top*" ); |
17 | g_set_error_literal (err: &error, G_MARKUP_ERROR, code: G_MARKUP_ERROR_PARSE, message: "bla" ); |
18 | g_test_assert_expected_messages (); |
19 | |
20 | g_assert_error (error, G_MARKUP_ERROR, G_MARKUP_ERROR_EMPTY); |
21 | g_error_free (error); |
22 | |
23 | |
24 | error = g_error_new_literal (G_MARKUP_ERROR, code: G_MARKUP_ERROR_EMPTY, message: "bla" ); |
25 | |
26 | g_test_expect_message (G_LOG_DOMAIN, log_level: G_LOG_LEVEL_WARNING, |
27 | pattern: "*set over the top*" ); |
28 | g_set_error (err: &error, G_MARKUP_ERROR, code: G_MARKUP_ERROR_PARSE, format: "bla" ); |
29 | g_test_assert_expected_messages (); |
30 | |
31 | g_assert_error (error, G_MARKUP_ERROR, G_MARKUP_ERROR_EMPTY); |
32 | g_error_free (error); |
33 | |
34 | |
35 | dest = g_error_new_literal (G_MARKUP_ERROR, code: G_MARKUP_ERROR_EMPTY, message: "bla" ); |
36 | src = g_error_new_literal (G_MARKUP_ERROR, code: G_MARKUP_ERROR_PARSE, message: "bla" ); |
37 | |
38 | g_test_expect_message (G_LOG_DOMAIN, log_level: G_LOG_LEVEL_WARNING, |
39 | pattern: "*set over the top*" ); |
40 | g_propagate_error (dest: &dest, src); |
41 | g_test_assert_expected_messages (); |
42 | |
43 | g_assert_error (dest, G_MARKUP_ERROR, G_MARKUP_ERROR_EMPTY); |
44 | g_error_free (error: dest); |
45 | } |
46 | |
47 | static void |
48 | test_prefix (void) |
49 | { |
50 | GError *error; |
51 | GError *dest, *src; |
52 | |
53 | error = NULL; |
54 | g_prefix_error (err: &error, format: "foo %d %s: " , 1, "two" ); |
55 | g_assert (error == NULL); |
56 | |
57 | error = g_error_new_literal (G_MARKUP_ERROR, code: G_MARKUP_ERROR_EMPTY, message: "bla" ); |
58 | g_prefix_error (err: &error, format: "foo %d %s: " , 1, "two" ); |
59 | g_assert_cmpstr (error->message, ==, "foo 1 two: bla" ); |
60 | g_error_free (error); |
61 | |
62 | dest = NULL; |
63 | src = g_error_new_literal (G_MARKUP_ERROR, code: G_MARKUP_ERROR_EMPTY, message: "bla" ); |
64 | g_propagate_prefixed_error (dest: &dest, src, format: "foo %d %s: " , 1, "two" ); |
65 | g_assert_cmpstr (dest->message, ==, "foo 1 two: bla" ); |
66 | g_error_free (error: dest); |
67 | |
68 | src = g_error_new_literal (G_MARKUP_ERROR, code: G_MARKUP_ERROR_EMPTY, message: "bla" ); |
69 | g_propagate_prefixed_error (NULL, src, format: "foo %d %s: " , 1, "two" ); |
70 | } |
71 | |
72 | static void |
73 | test_literal (void) |
74 | { |
75 | GError *error; |
76 | |
77 | error = NULL; |
78 | g_set_error_literal (err: &error, G_MARKUP_ERROR, code: G_MARKUP_ERROR_EMPTY, message: "%s %d %x" ); |
79 | g_assert_error (error, G_MARKUP_ERROR, G_MARKUP_ERROR_EMPTY); |
80 | g_assert_cmpstr (error->message, ==, "%s %d %x" ); |
81 | g_error_free (error); |
82 | } |
83 | |
84 | static void |
85 | test_copy (void) |
86 | { |
87 | GError *error; |
88 | GError *copy; |
89 | |
90 | error = NULL; |
91 | g_set_error_literal (err: &error, G_MARKUP_ERROR, code: G_MARKUP_ERROR_EMPTY, message: "%s %d %x" ); |
92 | copy = g_error_copy (error); |
93 | |
94 | g_assert_error (copy, G_MARKUP_ERROR, G_MARKUP_ERROR_EMPTY); |
95 | g_assert_cmpstr (copy->message, ==, "%s %d %x" ); |
96 | |
97 | g_error_free (error); |
98 | g_error_free (error: copy); |
99 | } |
100 | |
101 | static void |
102 | test_new_valist_invalid_va (gpointer dummy, |
103 | ...) |
104 | { |
105 | #ifdef __linux__ |
106 | /* Only worth testing this on Linux; if other platforms regress on this legacy |
107 | * behaviour, we don’t care. In particular, calling g_error_new_valist() with |
108 | * a %NULL format will crash on FreeBSD as its implementation of vasprintf() |
109 | * is less forgiving than Linux’s. That’s fine: it’s a programmer error in |
110 | * either case. */ |
111 | const struct |
112 | { |
113 | GQuark domain; |
114 | const gchar *format; |
115 | } |
116 | tests[] = |
117 | { |
118 | { G_MARKUP_ERROR, NULL }, |
119 | { 0, "Message" }, |
120 | }; |
121 | gsize i; |
122 | |
123 | g_test_summary (summary: "Test that g_error_new_valist() rejects invalid input" ); |
124 | |
125 | if (!g_test_undefined ()) |
126 | { |
127 | g_test_skip (msg: "Not testing response to programmer error" ); |
128 | return; |
129 | } |
130 | |
131 | for (i = 0; i < G_N_ELEMENTS (tests); i++) |
132 | { |
133 | GError *error = NULL, *error_copy = NULL; |
134 | va_list ap; |
135 | |
136 | g_test_message (format: "Test %" G_GSIZE_FORMAT, i); |
137 | |
138 | va_start (ap, dummy); |
139 | |
140 | #pragma GCC diagnostic push |
141 | #pragma GCC diagnostic ignored "-Wformat-nonliteral" |
142 | |
143 | g_test_expect_message (G_LOG_DOMAIN, |
144 | log_level: G_LOG_LEVEL_WARNING, |
145 | pattern: "*g_error_new_valist: runtime check failed*" ); |
146 | error = g_error_new_valist (domain: tests[i].domain, code: G_MARKUP_ERROR_EMPTY, format: tests[i].format, args: ap); |
147 | g_test_assert_expected_messages (); |
148 | g_assert_nonnull (error); |
149 | |
150 | #pragma GCC diagnostic pop |
151 | |
152 | g_test_expect_message (G_LOG_DOMAIN, |
153 | log_level: G_LOG_LEVEL_WARNING, |
154 | pattern: "*g_error_copy: runtime check failed*" ); |
155 | error_copy = g_error_copy (error); |
156 | g_test_assert_expected_messages (); |
157 | g_assert_nonnull (error_copy); |
158 | |
159 | g_clear_error (err: &error); |
160 | g_clear_error (err: &error_copy); |
161 | |
162 | va_end (ap); |
163 | } |
164 | #else /* if !__linux__ */ |
165 | g_test_skip ("g_error_new_valist() programmer error handling is only relevant on Linux" ); |
166 | #endif /* !__linux__ */ |
167 | } |
168 | |
169 | static void |
170 | test_new_valist_invalid (void) |
171 | { |
172 | /* We need a wrapper function so we can build a va_list */ |
173 | test_new_valist_invalid_va (NULL); |
174 | } |
175 | |
176 | static void |
177 | test_matches (void) |
178 | { |
179 | GError *error = NULL; |
180 | |
181 | g_test_summary (summary: "Test g_error_matches()" ); |
182 | |
183 | error = g_error_new (G_MARKUP_ERROR, code: G_MARKUP_ERROR_EMPTY, format: "Oh no!" ); |
184 | |
185 | g_assert_true (g_error_matches (error, G_MARKUP_ERROR, G_MARKUP_ERROR_EMPTY)); |
186 | g_assert_false (g_error_matches (NULL, G_MARKUP_ERROR, G_MARKUP_ERROR_EMPTY)); |
187 | g_assert_false (g_error_matches (error, G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE)); /* same numeric value as G_MARKUP_ERROR_EMPTY */ |
188 | g_assert_false (g_error_matches (error, G_OPTION_ERROR, G_OPTION_ERROR_FAILED)); /* different numeric value from G_MARKUP_ERROR_EMPTY */ |
189 | g_assert_false (g_error_matches (error, G_MARKUP_ERROR, G_MARKUP_ERROR_BAD_UTF8)); |
190 | |
191 | g_error_free (error); |
192 | } |
193 | |
194 | static void |
195 | test_clear (void) |
196 | { |
197 | GError *error = NULL; |
198 | |
199 | g_test_summary (summary: "Test g_error_clear()" ); |
200 | |
201 | g_clear_error (err: &error); |
202 | g_assert_null (error); |
203 | |
204 | g_clear_error (NULL); |
205 | |
206 | error = g_error_new (G_MARKUP_ERROR, code: G_MARKUP_ERROR_EMPTY, format: "Oh no!" ); |
207 | g_clear_error (err: &error); |
208 | g_assert_null (error); |
209 | } |
210 | |
211 | typedef struct |
212 | { |
213 | int init_called; |
214 | int copy_called; |
215 | int free_called; |
216 | } TestErrorCheck; |
217 | |
218 | static TestErrorCheck *init_check; |
219 | |
220 | GQuark test_error_quark (void); |
221 | #define TEST_ERROR (test_error_quark ()) |
222 | |
223 | typedef struct |
224 | { |
225 | int foo; |
226 | TestErrorCheck *check; |
227 | } TestErrorPrivate; |
228 | |
229 | static void |
230 | test_error_private_init (TestErrorPrivate *priv) |
231 | { |
232 | priv->foo = 13; |
233 | /* If that triggers, it's test bug. |
234 | */ |
235 | g_assert_nonnull (init_check); |
236 | /* Using global init_check, because error->check is still nil at |
237 | * this point. |
238 | */ |
239 | init_check->init_called++; |
240 | } |
241 | |
242 | static void |
243 | test_error_private_copy (const TestErrorPrivate *src_priv, |
244 | TestErrorPrivate *dest_priv) |
245 | { |
246 | dest_priv->foo = src_priv->foo; |
247 | dest_priv->check = src_priv->check; |
248 | |
249 | dest_priv->check->copy_called++; |
250 | } |
251 | |
252 | static void |
253 | test_error_private_clear (TestErrorPrivate *priv) |
254 | { |
255 | priv->check->free_called++; |
256 | } |
257 | |
258 | G_DEFINE_EXTENDED_ERROR (TestError, test_error) |
259 | |
260 | static TestErrorPrivate * |
261 | fill_test_error (GError *error, TestErrorCheck *check) |
262 | { |
263 | TestErrorPrivate *test_error = test_error_get_private (error); |
264 | |
265 | test_error->check = check; |
266 | |
267 | return test_error; |
268 | } |
269 | |
270 | static void |
271 | test_extended (void) |
272 | { |
273 | TestErrorCheck check = { 0, 0, 0 }; |
274 | GError *error; |
275 | TestErrorPrivate *test_priv; |
276 | GError *copy_error; |
277 | TestErrorPrivate *copy_test_priv; |
278 | |
279 | init_check = ✓ |
280 | error = g_error_new_literal (TEST_ERROR, code: 0, message: "foo" ); |
281 | test_priv = fill_test_error (error, check: &check); |
282 | |
283 | g_assert_cmpint (check.init_called, ==, 1); |
284 | g_assert_cmpint (check.copy_called, ==, 0); |
285 | g_assert_cmpint (check.free_called, ==, 0); |
286 | |
287 | g_assert_cmpuint (error->domain, ==, TEST_ERROR); |
288 | g_assert_cmpint (test_priv->foo, ==, 13); |
289 | |
290 | copy_error = g_error_copy (error); |
291 | g_assert_cmpint (check.init_called, ==, 2); |
292 | g_assert_cmpint (check.copy_called, ==, 1); |
293 | g_assert_cmpint (check.free_called, ==, 0); |
294 | |
295 | g_assert_cmpuint (error->domain, ==, copy_error->domain); |
296 | g_assert_cmpint (error->code, ==, copy_error->code); |
297 | g_assert_cmpstr (error->message, ==, copy_error->message); |
298 | |
299 | copy_test_priv = test_error_get_private (error: copy_error); |
300 | g_assert_cmpint (test_priv->foo, ==, copy_test_priv->foo); |
301 | |
302 | g_error_free (error); |
303 | g_error_free (error: copy_error); |
304 | |
305 | g_assert_cmpint (check.init_called, ==, 2); |
306 | g_assert_cmpint (check.copy_called, ==, 1); |
307 | g_assert_cmpint (check.free_called, ==, 2); |
308 | } |
309 | |
310 | static void |
311 | test_extended_duplicate (void) |
312 | { |
313 | g_test_summary (summary: "Test that registering a duplicate extended error domain doesn’t work" ); |
314 | |
315 | if (!g_test_subprocess ()) |
316 | { |
317 | /* Spawn a subprocess and expect it to fail. */ |
318 | g_test_trap_subprocess (NULL, usec_timeout: 0, test_flags: 0); |
319 | g_test_trap_assert_failed (); |
320 | g_test_trap_assert_stderr ("*CRITICAL*Attempted to register an extended error domain for TestError more than once*" ); |
321 | } |
322 | else |
323 | { |
324 | GQuark q; |
325 | guint i; |
326 | |
327 | for (i = 0; i < 2; i++) |
328 | { |
329 | q = g_error_domain_register_static (error_type_name: "TestError" , |
330 | error_type_private_size: sizeof (TestErrorPrivate), |
331 | error_type_init: g_error_with_test_error_private_init, |
332 | error_type_copy: g_error_with_test_error_private_copy, |
333 | error_type_clear: g_error_with_test_error_private_clear); |
334 | g_assert_cmpstr (g_quark_to_string (q), ==, "TestError" ); |
335 | } |
336 | } |
337 | } |
338 | |
339 | typedef struct |
340 | { |
341 | int dummy; |
342 | } TestErrorNonStaticPrivate; |
343 | |
344 | static void test_error_non_static_private_init (GError *error) {} |
345 | static void test_error_non_static_private_copy (const GError *src_error, GError *dest_error) {} |
346 | static void test_error_non_static_private_clear (GError *error) {} |
347 | |
348 | static void |
349 | test_extended_non_static (void) |
350 | { |
351 | gchar *domain_name = g_strdup (str: "TestErrorNonStatic" ); |
352 | GQuark q; |
353 | GError *error = NULL; |
354 | |
355 | g_test_summary (summary: "Test registering an extended error domain with a non-static name" ); |
356 | |
357 | q = g_error_domain_register (error_type_name: domain_name, |
358 | error_type_private_size: sizeof (TestErrorNonStaticPrivate), |
359 | error_type_init: test_error_non_static_private_init, |
360 | error_type_copy: test_error_non_static_private_copy, |
361 | error_type_clear: test_error_non_static_private_clear); |
362 | g_free (mem: domain_name); |
363 | |
364 | error = g_error_new (domain: q, code: 0, format: "Test error: %s" , "hello" ); |
365 | g_assert_true (g_error_matches (error, q, 0)); |
366 | g_assert_cmpstr (g_quark_to_string (q), ==, "TestErrorNonStatic" ); |
367 | g_error_free (error); |
368 | } |
369 | |
370 | int |
371 | main (int argc, char *argv[]) |
372 | { |
373 | g_test_init (argc: &argc, argv: &argv, NULL); |
374 | |
375 | g_test_add_func (testpath: "/error/overwrite" , test_func: test_overwrite); |
376 | g_test_add_func (testpath: "/error/prefix" , test_func: test_prefix); |
377 | g_test_add_func (testpath: "/error/literal" , test_func: test_literal); |
378 | g_test_add_func (testpath: "/error/copy" , test_func: test_copy); |
379 | g_test_add_func (testpath: "/error/matches" , test_func: test_matches); |
380 | g_test_add_func (testpath: "/error/clear" , test_func: test_clear); |
381 | g_test_add_func (testpath: "/error/new-valist/invalid" , test_func: test_new_valist_invalid); |
382 | g_test_add_func (testpath: "/error/extended" , test_func: test_extended); |
383 | g_test_add_func (testpath: "/error/extended/duplicate" , test_func: test_extended_duplicate); |
384 | g_test_add_func (testpath: "/error/extended/non-static" , test_func: test_extended_non_static); |
385 | |
386 | return g_test_run (); |
387 | } |
388 | |