1 /* ADG - Automatic Drawing Generation
2 * Copyright (C) 2007-2015 Nicola Fontana <ntd at entidi.it>
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the
16 * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17 * Boston, MA 02110-1301, USA.
21 #include "adg-internal.h"
26 void (*func
)(gpointer
);
36 /* Using adg_nop() would require to pull in the whole libadg stack:
37 * better to replicate that trivial function instead.
45 adg_test_init(int *p_argc
, char **p_argv
[])
47 #if GLIB_CHECK_VERSION(2, 34, 0)
49 /* On GLib older than 2.34.0 g_type_init() *must* be called */
52 g_test_init(p_argc
, p_argv
, NULL
);
54 g_log_set_always_fatal(0);
56 /* When building in silent mode (default), the ADG_QUIET
57 * environment variable is set to 1 by the Makefile and the
58 * warnings are discarded to reduce visual cluttering.
60 if (g_getenv("ADG_QUIET") != NULL
)
61 g_log_set_default_handler((GLogFunc
) _adg_nop
, NULL
);
63 g_test_bug_base("http://dev.entidi.com/p/adg/issues/%s/");
67 adg_test_invalid_pointer(void)
69 static int junk
[10] = { 0 };
74 adg_test_cairo_context(void)
76 cairo_surface_t
*surface
;
79 surface
= cairo_image_surface_create(CAIRO_FORMAT_ARGB32
, 800, 600);
80 cr
= cairo_create(surface
);
81 cairo_surface_destroy(surface
);
87 adg_test_cairo_num_data(cairo_t
*cr
)
89 cairo_path_t
*path
= cairo_copy_path(cr
);
90 int length
= path
->num_data
;
91 cairo_path_destroy(path
);
97 _adg_test_func(_FuncData
*func_data
)
99 func_data
->func(func_data
->data
);
104 adg_test_add_func_full(const char *testpath
,
105 GCallback test_func
, gpointer user_data
)
107 _FuncData
*func_data
= g_new(_FuncData
, 1);
108 func_data
->func
= (gpointer
) test_func
;
109 func_data
->data
= user_data
;
111 g_test_add_data_func(testpath
, func_data
, (GTestDataFunc
) _adg_test_func
);
115 adg_test_add_func(const char *testpath
, GCallback test_func
)
117 adg_test_add_func_full(testpath
, test_func
, NULL
);
121 _adg_enum_checks(gconstpointer user_data
)
126 type
= GPOINTER_TO_INT(user_data
);
127 g_assert_true(G_TYPE_IS_ENUM(type
));
129 class = g_type_class_ref(type
);
130 g_assert_nonnull(class);
132 g_assert_null(g_enum_get_value(class, -1));
133 g_assert_nonnull(g_enum_get_value(class, 0));
134 g_assert_null(g_enum_get_value_by_name(class, "unexistent value"));
138 adg_test_add_enum_checks(const gchar
*testpath
, GType type
)
140 adg_test_add_func_full(testpath
, G_CALLBACK(_adg_enum_checks
), GINT_TO_POINTER(type
));
144 _adg_boxed_checks(_BoxedData
*boxed_data
)
148 g_assert_true(G_TYPE_IS_BOXED(boxed_data
->type
));
150 g_assert_null(g_boxed_copy(boxed_data
->type
, NULL
));
152 replica
= g_boxed_copy(boxed_data
->type
, boxed_data
->instance
);
153 g_assert_nonnull(replica
);
155 g_boxed_free(boxed_data
->type
, replica
);
156 g_boxed_free(boxed_data
->type
, boxed_data
->instance
);
162 adg_test_add_boxed_checks(const gchar
*testpath
, GType type
, gpointer instance
)
164 _BoxedData
*boxed_data
= g_new(_BoxedData
, 1);
165 boxed_data
->type
= type
;
166 boxed_data
->instance
= instance
;
168 adg_test_add_func_full(testpath
, G_CALLBACK(_adg_boxed_checks
), boxed_data
);
172 _adg_object_checks(gconstpointer user_data
)
174 GType type
= GPOINTER_TO_INT(user_data
);
175 g_assert_true(G_TYPE_IS_OBJECT(type
));
177 if (! G_TYPE_IS_ABSTRACT(type
)) {
178 gpointer result
= GINT_TO_POINTER(0xdead);
179 GObject
*object
= g_object_new(type
, NULL
);
181 g_assert_nonnull(object
);
182 g_assert_true(G_IS_OBJECT(object
));
184 /* Check that unknown or unexistent properties does
185 * not return values (result should pass unmodified)
187 g_assert_cmpint(GPOINTER_TO_INT(result
), ==, 0xdead);
188 g_object_set(object
, "unknown", NULL
, NULL
);
189 g_object_get(object
, "unknown", &result
, NULL
);
190 g_assert_cmpint(GPOINTER_TO_INT(result
), ==, 0xdead);
191 g_object_get(object
, "unexistent", &result
, NULL
);
192 g_assert_cmpint(GPOINTER_TO_INT(result
), ==, 0xdead);
194 /* Check object lifetime: this can be done with a weak pointer
195 * that will "nullifies" result after object is destructed
197 g_object_add_weak_pointer(object
, &result
);
198 g_object_ref(object
);
199 g_object_unref(object
);
200 g_assert_nonnull(result
);
201 g_object_unref(object
);
202 g_assert_null(result
);
204 result
= GINT_TO_POINTER(0xdead);
205 object
= g_object_new(type
, NULL
);
207 g_object_add_weak_pointer(object
, &result
);
208 g_assert_nonnull(result
);
209 g_object_ref(object
);
210 g_object_ref(object
);
211 g_object_run_dispose(object
);
212 g_assert_null(result
);
217 adg_test_add_object_checks(const gchar
*testpath
, GType type
)
219 adg_test_add_func_full(testpath
,
220 G_CALLBACK(_adg_object_checks
),
221 GINT_TO_POINTER(type
));
225 _adg_entity_checks(gconstpointer user_data
)
227 GType type
= GPOINTER_TO_INT(user_data
);
228 g_assert_true(g_type_is_a(type
, ADG_TYPE_ENTITY
));
230 if (! G_TYPE_IS_ABSTRACT(type
)) {
231 AdgEntity
*entity
= g_object_new(type
, NULL
);
232 const CpmlExtents
*extents
;
234 g_assert_nonnull(entity
);
235 g_assert_true(ADG_IS_ENTITY(entity
));
237 /* Ensure that the entity extents are not initially defined */
238 extents
= adg_entity_get_extents(entity
);
239 g_assert_false(extents
->is_defined
);
241 adg_entity_arrange(entity
);
242 extents
= adg_entity_get_extents(entity
);
243 if (extents
->is_defined
) {
244 /* RENDERABLE ENTITY */
245 /* Check that invalidate() clears the cached extents */
246 adg_entity_invalidate(entity
);
247 extents
= adg_entity_get_extents(entity
);
248 g_assert_false(extents
->is_defined
);
250 /* NON-RENDERABLE ENTITY (e.g., empty container) */
253 g_object_unref(entity
);
258 adg_test_add_entity_checks(const gchar
*testpath
, GType type
)
260 adg_test_add_func_full(testpath
,
261 G_CALLBACK(_adg_entity_checks
),
262 GINT_TO_POINTER(type
));
266 _adg_global_space_checks(AdgEntity
*entity
)
269 const CpmlExtents
*extents
;
270 cairo_matrix_t scale2X
;
271 gdouble width
, height
;
273 cr
= adg_test_cairo_context();
274 cairo_matrix_init_scale(&scale2X
, 2, 2);
276 /* Store the original extents size in width/height */
277 adg_entity_render(entity
, cr
);
278 extents
= adg_entity_get_extents(entity
);
279 g_assert_true(extents
->is_defined
);
280 width
= extents
->size
.x
;
281 height
= extents
->size
.y
;
283 /* Check that a zoom in global space scales is roughly equivalent to
284 * the same zoom on extents too (not excactly because of fonts) */
285 adg_entity_transform_global_map(entity
, &scale2X
, ADG_TRANSFORM_BEFORE
);
286 adg_entity_invalidate(entity
);
287 g_assert_false(extents
->is_defined
);
288 adg_entity_render(entity
, cr
);
289 extents
= adg_entity_get_extents(entity
);
290 g_assert_cmpfloat(extents
->size
.x
, >, width
* 1.7);
291 g_assert_cmpfloat(extents
->size
.x
, <, width
* 2.3);
292 g_assert_cmpfloat(extents
->size
.y
, >, height
* 1.7);
293 g_assert_cmpfloat(extents
->size
.y
, <, height
* 2.3);
295 /* Restore the original global scale */
296 cairo_matrix_invert(&scale2X
);
297 adg_entity_transform_global_map(entity
, &scale2X
, ADG_TRANSFORM_BEFORE
);
298 adg_entity_invalidate(entity
);
299 g_assert_false(extents
->is_defined
);
300 adg_entity_render(entity
, cr
);
301 extents
= adg_entity_get_extents(entity
);
302 g_assert_cmpfloat(extents
->size
.x
, ==, width
);
303 g_assert_cmpfloat(extents
->size
.y
, ==, height
);
306 g_object_unref(entity
);
310 adg_test_add_global_space_checks(const gchar
*testpath
, gpointer entity
)
312 adg_test_add_func_full(testpath
, G_CALLBACK(_adg_global_space_checks
), entity
);
316 _adg_local_space_checks(AdgEntity
*entity
)
319 const CpmlExtents
*extents
;
320 cairo_matrix_t scale2X
;
321 gdouble width
, height
;
323 cr
= adg_test_cairo_context();
324 cairo_matrix_init_scale(&scale2X
, 2, 2);
326 /* Store the original extents size in width/height */
327 adg_entity_render(entity
, cr
);
328 extents
= adg_entity_get_extents(entity
);
329 g_assert_true(extents
->is_defined
);
330 width
= extents
->size
.x
;
331 height
= extents
->size
.y
;
333 /* Check that a scale in local space somewhat scales the extents too */
334 adg_entity_transform_local_map(entity
, &scale2X
, ADG_TRANSFORM_BEFORE
);
335 adg_entity_invalidate(entity
);
336 g_assert_false(extents
->is_defined
);
337 adg_entity_render(entity
, cr
);
338 extents
= adg_entity_get_extents(entity
);
339 g_assert_cmpfloat(extents
->size
.x
, >, width
);
340 g_assert_cmpfloat(extents
->size
.y
, >, height
);
342 /* Restore the original local scale */
343 cairo_matrix_invert(&scale2X
);
344 adg_entity_transform_local_map(entity
, &scale2X
, ADG_TRANSFORM_BEFORE
);
345 adg_entity_invalidate(entity
);
346 g_assert_false(extents
->is_defined
);
347 adg_entity_render(entity
, cr
);
348 extents
= adg_entity_get_extents(entity
);
349 g_assert_cmpfloat(extents
->size
.x
, ==, width
);
350 g_assert_cmpfloat(extents
->size
.y
, ==, height
);
353 g_object_unref(entity
);
357 adg_test_add_local_space_checks(const gchar
*testpath
, gpointer entity
)
359 adg_test_add_func_full(testpath
, G_CALLBACK(_adg_local_space_checks
), entity
);