tests: new adg_test_cairo_num_data helper function
[adg.git] / src / tests / adg-test.c
blob1a22fe686904ffa90d850bf74c33ffa06b92b4e2
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"
22 #include "adg-test.h"
25 typedef struct {
26 void (*func)(gpointer);
27 gpointer data;
28 } _FuncData;
30 typedef struct {
31 GType type;
32 gpointer instance;
33 } _BoxedData;
36 /* Using adg_nop() would require to pull in the whole libadg stack:
37 * better to replicate that trivial function instead.
39 static void
40 _adg_nop(void)
44 void
45 adg_test_init(int *p_argc, char **p_argv[])
47 #if GLIB_CHECK_VERSION(2, 34, 0)
48 #else
49 /* On GLib older than 2.34.0 g_type_init() *must* be called */
50 g_type_init();
51 #endif
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/");
66 const gpointer
67 adg_test_invalid_pointer(void)
69 static int junk[10] = { 0 };
70 return junk;
73 cairo_t *
74 adg_test_cairo_context(void)
76 cairo_surface_t *surface;
77 cairo_t *cr;
79 surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, 800, 600);
80 cr = cairo_create(surface);
81 cairo_surface_destroy(surface);
83 return cr;
86 int
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);
93 return length;
96 static void
97 _adg_test_func(_FuncData *func_data)
99 func_data->func(func_data->data);
100 g_free(func_data);
103 void
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);
114 void
115 adg_test_add_func(const char *testpath, GCallback test_func)
117 adg_test_add_func_full(testpath, test_func, NULL);
120 static void
121 _adg_enum_checks(gconstpointer user_data)
123 GType type;
124 gpointer class;
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"));
137 void
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));
143 static void
144 _adg_boxed_checks(_BoxedData *boxed_data)
146 gpointer replica;
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);
158 g_free(boxed_data);
161 void
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);
171 static void
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);
216 void
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));
224 static void
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);
249 } else {
250 /* NON-RENDERABLE ENTITY (e.g., empty container) */
253 g_object_unref(entity);
257 void
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));
265 static void
266 _adg_global_space_checks(AdgEntity *entity)
268 cairo_t *cr;
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);
305 cairo_destroy(cr);
306 g_object_unref(entity);
309 void
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);
315 static void
316 _adg_local_space_checks(AdgEntity *entity)
318 cairo_t *cr;
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);
352 cairo_destroy(cr);
353 g_object_unref(entity);
356 void
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);