1 #include <clutter/clutter.h>
2 #include <cairo.h>
3 #include <string.h>
4 #include <math.h>
5 
6 #include "test-conform-common.h"
7 
8 #define MAX_NODES 128
9 
10 #define FLOAT_FUZZ_AMOUNT 5.0f
11 
12 typedef struct _CallbackData CallbackData;
13 
14 typedef gboolean (* PathTestFunc) (CallbackData *data);
15 
16 static void compare_node (const ClutterPathNode *node, gpointer data_p);
17 
18 struct _CallbackData
19 {
20   ClutterPath *path;
21 
22   guint n_nodes;
23   ClutterPathNode nodes[MAX_NODES];
24 
25   gboolean nodes_different;
26   guint nodes_found;
27 };
28 
29 static const char path_desc[] =
30   "M 21 22 "
31   "L 25 26 "
32   "C 29 30 31 32 33 34 "
33   "m 23 24 "
34   "l 27 28 "
35   "c 35 36 37 38 39 40 "
36   "z";
37 static const ClutterPathNode path_nodes[] =
38   { { CLUTTER_PATH_MOVE_TO,      { { 21, 22 }, { 0,  0 },  { 0,  0 } } },
39     { CLUTTER_PATH_LINE_TO,      { { 25, 26 }, { 0,  0 },  { 0,  0 } } },
40     { CLUTTER_PATH_CURVE_TO,     { { 29, 30 }, { 31, 32 }, { 33, 34 } } },
41     { CLUTTER_PATH_REL_MOVE_TO,  { { 23, 24 }, { 0,  0 },  { 0,  0 } } },
42     { CLUTTER_PATH_REL_LINE_TO,  { { 27, 28 }, { 0,  0 },  { 0,  0 } } },
43     { CLUTTER_PATH_REL_CURVE_TO, { { 35, 36 }, { 37, 38 }, { 39, 40 } } },
44     { CLUTTER_PATH_CLOSE,        { { 0,  0 },  { 0,  0 },  { 0,  0 } } } };
45 
46 static gboolean
path_test_add_move_to(CallbackData * data)47 path_test_add_move_to (CallbackData *data)
48 {
49   ClutterPathNode node = { 0, };
50 
51   node.type = CLUTTER_PATH_MOVE_TO;
52   node.points[0].x = 1;
53   node.points[0].y = 2;
54 
55   clutter_path_add_move_to (data->path, node.points[0].x, node.points[0].y);
56 
57   data->nodes[data->n_nodes++] = node;
58 
59   return TRUE;
60 }
61 
62 static gboolean
path_test_add_line_to(CallbackData * data)63 path_test_add_line_to (CallbackData *data)
64 {
65   ClutterPathNode node = { 0, };
66 
67   node.type = CLUTTER_PATH_LINE_TO;
68   node.points[0].x = 3;
69   node.points[0].y = 4;
70 
71   clutter_path_add_line_to (data->path, node.points[0].x, node.points[0].y);
72 
73   data->nodes[data->n_nodes++] = node;
74 
75   return TRUE;
76 }
77 
78 static gboolean
path_test_add_curve_to(CallbackData * data)79 path_test_add_curve_to (CallbackData *data)
80 {
81   ClutterPathNode node = { 0, };
82 
83   node.type = CLUTTER_PATH_CURVE_TO;
84   node.points[0].x = 5;
85   node.points[0].y = 6;
86   node.points[1].x = 7;
87   node.points[1].y = 8;
88   node.points[2].x = 9;
89   node.points[2].y = 10;
90 
91   clutter_path_add_curve_to (data->path,
92                              node.points[0].x, node.points[0].y,
93                              node.points[1].x, node.points[1].y,
94                              node.points[2].x, node.points[2].y);
95 
96   data->nodes[data->n_nodes++] = node;
97 
98   return TRUE;
99 }
100 
101 static gboolean
path_test_add_close(CallbackData * data)102 path_test_add_close (CallbackData *data)
103 {
104   ClutterPathNode node = { 0, };
105 
106   node.type = CLUTTER_PATH_CLOSE;
107 
108   clutter_path_add_close (data->path);
109 
110   data->nodes[data->n_nodes++] = node;
111 
112   return TRUE;
113 }
114 
115 static gboolean
path_test_add_rel_move_to(CallbackData * data)116 path_test_add_rel_move_to (CallbackData *data)
117 {
118   ClutterPathNode node = { 0, };
119 
120   node.type = CLUTTER_PATH_REL_MOVE_TO;
121   node.points[0].x = 11;
122   node.points[0].y = 12;
123 
124   clutter_path_add_rel_move_to (data->path, node.points[0].x, node.points[0].y);
125 
126   data->nodes[data->n_nodes++] = node;
127 
128   return TRUE;
129 }
130 
131 static gboolean
path_test_add_rel_line_to(CallbackData * data)132 path_test_add_rel_line_to (CallbackData *data)
133 {
134   ClutterPathNode node = { 0, };
135 
136   node.type = CLUTTER_PATH_REL_LINE_TO;
137   node.points[0].x = 13;
138   node.points[0].y = 14;
139 
140   clutter_path_add_rel_line_to (data->path, node.points[0].x, node.points[0].y);
141 
142   data->nodes[data->n_nodes++] = node;
143 
144   return TRUE;
145 }
146 
147 static gboolean
path_test_add_rel_curve_to(CallbackData * data)148 path_test_add_rel_curve_to (CallbackData *data)
149 {
150   ClutterPathNode node = { 0, };
151 
152   node.type = CLUTTER_PATH_REL_CURVE_TO;
153   node.points[0].x = 15;
154   node.points[0].y = 16;
155   node.points[1].x = 17;
156   node.points[1].y = 18;
157   node.points[2].x = 19;
158   node.points[2].y = 20;
159 
160   clutter_path_add_rel_curve_to (data->path,
161                                  node.points[0].x, node.points[0].y,
162                                  node.points[1].x, node.points[1].y,
163                                  node.points[2].x, node.points[2].y);
164 
165   data->nodes[data->n_nodes++] = node;
166 
167   return TRUE;
168 }
169 
170 static gboolean
path_test_add_string(CallbackData * data)171 path_test_add_string (CallbackData *data)
172 {
173   int i;
174 
175   for (i = 0; i < G_N_ELEMENTS (path_nodes); i++)
176     data->nodes[data->n_nodes++] = path_nodes[i];
177 
178   clutter_path_add_string (data->path, path_desc);
179 
180   return TRUE;
181 }
182 
183 static gboolean
path_test_add_node_by_struct(CallbackData * data)184 path_test_add_node_by_struct (CallbackData *data)
185 {
186   int i;
187 
188   for (i = 0; i < G_N_ELEMENTS (path_nodes); i++)
189     {
190       data->nodes[data->n_nodes++] = path_nodes[i];
191       clutter_path_add_node (data->path, path_nodes + i);
192     }
193 
194   return TRUE;
195 }
196 
197 static gboolean
path_test_get_n_nodes(CallbackData * data)198 path_test_get_n_nodes (CallbackData *data)
199 {
200   return clutter_path_get_n_nodes (data->path) == data->n_nodes;
201 }
202 
203 static gboolean
path_test_get_node(CallbackData * data)204 path_test_get_node (CallbackData *data)
205 {
206   int i;
207 
208   data->nodes_found = 0;
209   data->nodes_different = FALSE;
210 
211   for (i = 0; i < data->n_nodes; i++)
212     {
213       ClutterPathNode node;
214 
215       clutter_path_get_node (data->path, i, &node);
216 
217       compare_node (&node, data);
218     }
219 
220   return !data->nodes_different;
221 }
222 
223 static gboolean
path_test_get_nodes(CallbackData * data)224 path_test_get_nodes (CallbackData *data)
225 {
226   GSList *list, *node;
227 
228   data->nodes_found = 0;
229   data->nodes_different = FALSE;
230 
231   list = clutter_path_get_nodes (data->path);
232 
233   for (node = list; node; node = node->next)
234     compare_node (node->data, data);
235 
236   g_slist_free (list);
237 
238   return !data->nodes_different && data->nodes_found == data->n_nodes;
239 }
240 
241 static gboolean
path_test_insert_beginning(CallbackData * data)242 path_test_insert_beginning (CallbackData *data)
243 {
244   ClutterPathNode node;
245 
246   node.type = CLUTTER_PATH_LINE_TO;
247   node.points[0].x = 41;
248   node.points[0].y = 42;
249 
250   memmove (data->nodes + 1, data->nodes,
251            data->n_nodes++ * sizeof (ClutterPathNode));
252   data->nodes[0] = node;
253 
254   clutter_path_insert_node (data->path, 0, &node);
255 
256   return TRUE;
257 }
258 
259 static gboolean
path_test_insert_end(CallbackData * data)260 path_test_insert_end (CallbackData *data)
261 {
262   ClutterPathNode node;
263 
264   node.type = CLUTTER_PATH_LINE_TO;
265   node.points[0].x = 43;
266   node.points[0].y = 44;
267 
268   data->nodes[data->n_nodes++] = node;
269 
270   clutter_path_insert_node (data->path, -1, &node);
271 
272   return TRUE;
273 }
274 
275 static gboolean
path_test_insert_middle(CallbackData * data)276 path_test_insert_middle (CallbackData *data)
277 {
278   ClutterPathNode node;
279   int pos = data->n_nodes / 2;
280 
281   node.type = CLUTTER_PATH_LINE_TO;
282   node.points[0].x = 45;
283   node.points[0].y = 46;
284 
285   memmove (data->nodes + pos + 1, data->nodes + pos,
286            (data->n_nodes - pos) * sizeof (ClutterPathNode));
287   data->nodes[pos] = node;
288   data->n_nodes++;
289 
290   clutter_path_insert_node (data->path, pos, &node);
291 
292   return TRUE;
293 }
294 
295 static gboolean
path_test_clear(CallbackData * data)296 path_test_clear (CallbackData *data)
297 {
298   clutter_path_clear (data->path);
299 
300   data->n_nodes = 0;
301 
302   return TRUE;
303 }
304 
305 static gboolean
path_test_clear_insert(CallbackData * data)306 path_test_clear_insert (CallbackData *data)
307 {
308   return path_test_clear (data) && path_test_insert_middle (data);
309 }
310 
311 static gboolean
path_test_remove_beginning(CallbackData * data)312 path_test_remove_beginning (CallbackData *data)
313 {
314   memmove (data->nodes, data->nodes + 1,
315            --data->n_nodes * sizeof (ClutterPathNode));
316 
317   clutter_path_remove_node (data->path, 0);
318 
319   return TRUE;
320 }
321 
322 static gboolean
path_test_remove_end(CallbackData * data)323 path_test_remove_end (CallbackData *data)
324 {
325   clutter_path_remove_node (data->path, --data->n_nodes);
326 
327   return TRUE;
328 }
329 
330 static gboolean
path_test_remove_middle(CallbackData * data)331 path_test_remove_middle (CallbackData *data)
332 {
333   int pos = data->n_nodes / 2;
334 
335   memmove (data->nodes + pos, data->nodes + pos + 1,
336            (--data->n_nodes - pos) * sizeof (ClutterPathNode));
337 
338   clutter_path_remove_node (data->path, pos);
339 
340   return TRUE;
341 }
342 
343 static gboolean
path_test_remove_only(CallbackData * data)344 path_test_remove_only (CallbackData *data)
345 {
346   return path_test_clear (data)
347     && path_test_add_line_to (data)
348     && path_test_remove_beginning (data);
349 }
350 
351 static gboolean
path_test_replace(CallbackData * data)352 path_test_replace (CallbackData *data)
353 {
354   ClutterPathNode node;
355   int pos = data->n_nodes / 2;
356 
357   node.type = CLUTTER_PATH_LINE_TO;
358   node.points[0].x = 47;
359   node.points[0].y = 48;
360 
361   data->nodes[pos] = node;
362 
363   clutter_path_replace_node (data->path, pos, &node);
364 
365   return TRUE;
366 }
367 
368 static gboolean
path_test_set_description(CallbackData * data)369 path_test_set_description (CallbackData *data)
370 {
371   data->n_nodes = G_N_ELEMENTS (path_nodes);
372   memcpy (data->nodes, path_nodes, sizeof (path_nodes));
373 
374   return clutter_path_set_description (data->path, path_desc);
375 }
376 
377 static gboolean
path_test_get_description(CallbackData * data)378 path_test_get_description (CallbackData *data)
379 {
380   char *desc1, *desc2;
381   gboolean ret = TRUE;
382 
383   desc1 = clutter_path_get_description (data->path);
384   clutter_path_clear (data->path);
385   if (!clutter_path_set_description (data->path, desc1))
386     ret = FALSE;
387   desc2 = clutter_path_get_description (data->path);
388 
389   if (strcmp (desc1, desc2))
390     ret = FALSE;
391 
392   g_free (desc1);
393   g_free (desc2);
394 
395   return ret;
396 }
397 
398 static gboolean
path_test_convert_to_cairo_path(CallbackData * data)399 path_test_convert_to_cairo_path (CallbackData *data)
400 {
401   cairo_surface_t *surface;
402   cairo_t *cr;
403   cairo_path_t *cpath;
404   guint i, j;
405   ClutterKnot path_start = { 0, 0 }, last_point = { 0, 0 };
406 
407   /* Create a temporary image surface and context to hold the cairo
408      path */
409   surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, 10, 10);
410   cr = cairo_create (surface);
411 
412   /* Convert to a cairo path */
413   clutter_path_to_cairo_path (data->path, cr);
414 
415   /* Get a copy of the cairo path data */
416   cpath = cairo_copy_path (cr);
417 
418   /* Convert back to a clutter path */
419   clutter_path_clear (data->path);
420   clutter_path_add_cairo_path (data->path, cpath);
421 
422   /* The relative nodes will have been converted to absolute so we
423      need to reflect this in the node array for comparison */
424   for (i = 0; i < data->n_nodes; i++)
425     {
426       switch (data->nodes[i].type)
427         {
428         case CLUTTER_PATH_MOVE_TO:
429           path_start = last_point = data->nodes[i].points[0];
430           break;
431 
432         case CLUTTER_PATH_LINE_TO:
433           last_point = data->nodes[i].points[0];
434           break;
435 
436         case CLUTTER_PATH_CURVE_TO:
437           last_point = data->nodes[i].points[2];
438           break;
439 
440         case CLUTTER_PATH_REL_MOVE_TO:
441           last_point.x += data->nodes[i].points[0].x;
442           last_point.y += data->nodes[i].points[0].y;
443           data->nodes[i].points[0] = last_point;
444           data->nodes[i].type = CLUTTER_PATH_MOVE_TO;
445           path_start = last_point;
446           break;
447 
448         case CLUTTER_PATH_REL_LINE_TO:
449           last_point.x += data->nodes[i].points[0].x;
450           last_point.y += data->nodes[i].points[0].y;
451           data->nodes[i].points[0] = last_point;
452           data->nodes[i].type = CLUTTER_PATH_LINE_TO;
453           break;
454 
455         case CLUTTER_PATH_REL_CURVE_TO:
456           for (j = 0; j < 3; j++)
457             {
458               data->nodes[i].points[j].x += last_point.x;
459               data->nodes[i].points[j].y += last_point.y;
460             }
461           last_point = data->nodes[i].points[2];
462           data->nodes[i].type = CLUTTER_PATH_CURVE_TO;
463           break;
464 
465         case CLUTTER_PATH_CLOSE:
466           last_point = path_start;
467 
468           /* Cairo always adds a move to after every close so we need
469              to insert one here. Since Cairo commit 166453c1abf2 it
470              doesn't seem to do this anymore so will assume that if
471              Cairo's minor version is >= 11 then it includes that
472              commit */
473           if (cairo_version () < CAIRO_VERSION_ENCODE (1, 11, 0))
474             {
475               memmove (data->nodes + i + 2, data->nodes + i + 1,
476                        (data->n_nodes - i - 1) * sizeof (ClutterPathNode));
477               data->nodes[i + 1].type = CLUTTER_PATH_MOVE_TO;
478               data->nodes[i + 1].points[0] = last_point;
479               data->n_nodes++;
480             }
481           break;
482         }
483     }
484 
485   /* Free the cairo resources */
486   cairo_path_destroy (cpath);
487   cairo_destroy (cr);
488   cairo_surface_destroy (surface);
489 
490   return TRUE;
491 }
492 
493 static gboolean
float_fuzzy_equals(float fa,float fb)494 float_fuzzy_equals (float fa, float fb)
495 {
496   return fabs (fa - fb) <= FLOAT_FUZZ_AMOUNT;
497 }
498 
499 static void
set_triangle_path(CallbackData * data)500 set_triangle_path (CallbackData *data)
501 {
502   /* Triangular shaped path hitting (0,0), (64,64) and (128,0) in four
503      parts. The two curves are actually straight lines */
504   static const ClutterPathNode nodes[] =
505     { { CLUTTER_PATH_MOVE_TO,      { { 0, 0 } } },
506       { CLUTTER_PATH_LINE_TO,      { { 32, 32 } } },
507       { CLUTTER_PATH_CURVE_TO,     { { 40, 40 }, { 56, 56 }, { 64, 64 } } },
508       { CLUTTER_PATH_REL_CURVE_TO, { { 8, -8 }, { 24, -24 }, { 32, -32 } } },
509       { CLUTTER_PATH_REL_LINE_TO,  { { 32, -32 } } } };
510   gint i;
511 
512   clutter_path_clear (data->path);
513 
514   for (i = 0; i < G_N_ELEMENTS (nodes); i++)
515     clutter_path_add_node (data->path, nodes + i);
516 
517   memcpy (data->nodes, nodes, sizeof (nodes));
518   data->n_nodes = G_N_ELEMENTS (nodes);
519 }
520 
521 static gboolean
path_test_get_position(CallbackData * data)522 path_test_get_position (CallbackData *data)
523 {
524   static const float values[] = { 0.125f, 16.0f, 16.0f,
525                                   0.375f, 48.0f, 48.0f,
526                                   0.625f, 80.0f, 48.0f,
527                                   0.875f, 112.0f, 16.0f };
528   gint i;
529 
530   set_triangle_path (data);
531 
532   for (i = 0; i < G_N_ELEMENTS (values); i += 3)
533     {
534       ClutterKnot pos;
535 
536       clutter_path_get_position (data->path,
537                                  values[i],
538                                  &pos);
539 
540       if (!float_fuzzy_equals (values[i + 1], pos.x)
541           || !float_fuzzy_equals (values[i + 2], pos.y))
542         return FALSE;
543     }
544 
545   return TRUE;
546 }
547 
548 static gboolean
path_test_get_length(CallbackData * data)549 path_test_get_length (CallbackData *data)
550 {
551   const float actual_length /* sqrt(64**2 + 64**2) * 2 */ = 181.019336f;
552   guint approx_length;
553 
554   clutter_path_set_description (data->path, "M 0 0 L 46340 0");
555   g_object_get (data->path, "length", &approx_length, NULL);
556 
557   if (!(fabs (approx_length - 46340.f) / 46340.f <= 0.15f))
558     {
559       if (!g_test_quiet ())
560         g_print ("M 0 0 L 46340 0 - Expected 46340, got %d instead.", approx_length);
561 
562       return FALSE;
563     }
564 
565   clutter_path_set_description (data->path, "M 0 0 L 46341 0");
566   g_object_get (data->path, "length", &approx_length, NULL);
567 
568   if (!(fabs (approx_length - 46341.f) / 46341.f <= 0.15f))
569     {
570       if (!g_test_quiet ())
571         g_print ("M 0 0 L 46341 0 - Expected 46341, got %d instead.", approx_length);
572 
573       return FALSE;
574     }
575 
576   set_triangle_path (data);
577 
578   g_object_get (data->path, "length", &approx_length, NULL);
579 
580   /* Allow 15% margin of error */
581   if (!(fabs (approx_length - actual_length) / (float) actual_length <= 0.15f))
582     {
583       if (!g_test_quiet ())
584         g_print ("Expected %g, got %d instead.\n", actual_length, approx_length);
585 
586       return FALSE;
587     }
588 
589   return TRUE;
590 }
591 
592 static gboolean
path_test_boxed_type(CallbackData * data)593 path_test_boxed_type (CallbackData *data)
594 {
595   gboolean ret = TRUE;
596   GSList *nodes, *l;
597   GValue value;
598 
599   nodes = clutter_path_get_nodes (data->path);
600 
601   memset (&value, 0, sizeof (value));
602 
603   for (l = nodes; l; l = l->next)
604     {
605       g_value_init (&value, CLUTTER_TYPE_PATH_NODE);
606 
607       g_value_set_boxed (&value, l->data);
608 
609       if (!clutter_path_node_equal (l->data,
610                                     g_value_get_boxed (&value)))
611         ret = FALSE;
612 
613       g_value_unset (&value);
614     }
615 
616   g_slist_free (nodes);
617 
618   return ret;
619 }
620 
621 static const struct
622 {
623   const char *desc;
624   PathTestFunc func;
625 }
626 path_tests[] =
627   {
628     { "Add line to", path_test_add_line_to },
629     { "Add move to", path_test_add_move_to },
630     { "Add curve to", path_test_add_curve_to },
631     { "Add close", path_test_add_close },
632     { "Add relative line to", path_test_add_rel_line_to },
633     { "Add relative move to", path_test_add_rel_move_to },
634     { "Add relative curve to", path_test_add_rel_curve_to },
635     { "Add string", path_test_add_string },
636     { "Add node by struct", path_test_add_node_by_struct },
637     { "Get number of nodes", path_test_get_n_nodes },
638     { "Get a node", path_test_get_node },
639     { "Get all nodes", path_test_get_nodes },
640     { "Insert at beginning", path_test_insert_beginning },
641     { "Insert at end", path_test_insert_end },
642     { "Insert at middle", path_test_insert_middle },
643     { "Add after insert", path_test_add_line_to },
644     { "Clear then insert", path_test_clear_insert },
645     { "Add string again", path_test_add_string },
646     { "Remove from beginning", path_test_remove_beginning },
647     { "Remove from end", path_test_remove_end },
648     { "Remove from middle", path_test_remove_middle },
649     { "Add after remove", path_test_add_line_to },
650     { "Remove only node", path_test_remove_only },
651     { "Add after remove again", path_test_add_line_to },
652     { "Replace a node", path_test_replace },
653     { "Set description", path_test_set_description },
654     { "Get description", path_test_get_description },
655     { "Convert to cairo path and back", path_test_convert_to_cairo_path },
656     { "Clear", path_test_clear },
657     { "Get position", path_test_get_position },
658     { "Check node boxed type", path_test_boxed_type },
659     { "Get length", path_test_get_length }
660   };
661 
662 static void
compare_node(const ClutterPathNode * node,gpointer data_p)663 compare_node (const ClutterPathNode *node, gpointer data_p)
664 {
665   CallbackData *data = data_p;
666 
667   if (data->nodes_found >= data->n_nodes)
668     data->nodes_different = TRUE;
669   else
670     {
671       guint n_points = 0, i;
672       const ClutterPathNode *onode = data->nodes + data->nodes_found;
673 
674       if (node->type != onode->type)
675         data->nodes_different = TRUE;
676 
677       switch (node->type & ~CLUTTER_PATH_RELATIVE)
678         {
679         case CLUTTER_PATH_MOVE_TO: n_points = 1; break;
680         case CLUTTER_PATH_LINE_TO: n_points = 1; break;
681         case CLUTTER_PATH_CURVE_TO: n_points = 3; break;
682         case CLUTTER_PATH_CLOSE: n_points = 0; break;
683 
684         default:
685           data->nodes_different = TRUE;
686           break;
687         }
688 
689       for (i = 0; i < n_points; i++)
690         if (node->points[i].x != onode->points[i].x
691             || node->points[i].y != onode->points[i].y)
692           {
693             data->nodes_different = TRUE;
694             break;
695           }
696     }
697 
698   data->nodes_found++;
699 }
700 
701 static gboolean
compare_nodes(CallbackData * data)702 compare_nodes (CallbackData *data)
703 {
704   data->nodes_different = FALSE;
705   data->nodes_found = 0;
706 
707   clutter_path_foreach (data->path, compare_node, data);
708 
709   return !data->nodes_different && data->nodes_found == data->n_nodes;
710 }
711 
712 void
path_base(TestConformSimpleFixture * fixture,gconstpointer _data)713 path_base (TestConformSimpleFixture *fixture,
714            gconstpointer _data)
715 {
716   CallbackData data;
717   gint i;
718 
719   memset (&data, 0, sizeof (data));
720 
721   data.path = clutter_path_new ();
722 
723   for (i = 0; i < G_N_ELEMENTS (path_tests); i++)
724     {
725       gboolean succeeded;
726 
727       if (!g_test_quiet ())
728         g_print ("%s... ", path_tests[i].desc);
729 
730       succeeded = path_tests[i].func (&data) && compare_nodes (&data);
731 
732       if (!g_test_quiet ())
733         g_print ("%s\n", succeeded ? "ok" : "FAIL");
734 
735       g_assert (succeeded);
736     }
737 
738   g_object_unref (data.path);
739 }
740 
741