tests: complete test coverage on CpmlSegment
[adg.git] / src / cpml / tests / test-segment.c
bloba580d24eac292c9de905a7176b4e34af4c52af86
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-test.h>
22 #include <cpml.h>
25 static cairo_path_data_t data[] = {
26 /* Useless heading CPML_MOVE */
27 { .header = { CPML_MOVE, 2 }},
28 { .point = { 0, 0 }},
30 /* First segment: a couple of lines of length 2 */
31 { .header = { CPML_MOVE, 2 }},
32 { .point = { 0, 0 }},
33 { .header = { CPML_LINE, 2 }},
34 { .point = { 2, 0 }},
35 { .header = { CPML_LINE, 2 }},
36 { .point = { 2, 2 }},
38 /* Another useless CPML_MOVE with useless embedded data */
39 { .header = { CPML_MOVE, 3 }},
40 { .point = { 0, 0 }},
41 { .point = { 0, 0 }},
43 /* Second segment: a Bézier curve with a trailing CPML_CLOSE */
44 { .header = { CPML_MOVE, 2 }},
45 { .point = { 10, 13 }},
46 { .header = { CPML_CURVE, 4 }},
47 { .point = { 8, 9 }},
48 { .point = { 10, 11 }},
49 { .point = { 12, 13 }},
50 { .header = { CPML_CLOSE, 1 }},
52 /* A valid cairo segment considered invalid by CPML
53 * because does not have a leading CPML_MOVE */
54 { .header = { CPML_LINE, 2 }},
55 { .point = { 10, 0 }},
56 { .header = { CPML_CLOSE, 1 }},
58 /* Another valid cairo segment invalid in CPML */
59 { .header = { CPML_CLOSE, 1 }},
61 /* Third segment: a couple of arcs */
62 { .header = { CPML_MOVE, 2 }},
63 { .point = { 14, 15 }},
64 { .header = { CPML_ARC, 3 }},
65 { .point = { 16, 17 }},
66 { .point = { 18, 19 }},
67 { .header = { CPML_ARC, 3 }},
68 { .point = { 20, 21 }},
69 { .point = { 22, 23 }},
71 /* Forth segment: a floating CPML_CLOSE */
72 { .header = { CPML_MOVE, 2 }},
73 { .point = { 24, 25 }},
74 { .header = { CPML_CLOSE, 1 }}
77 static cairo_path_data_t noop_data[] = {
78 /* Useless heading CPML_MOVE */
79 { .header = { CPML_MOVE, 2 }},
80 { .point = { 0, 1 }},
81 { .header = { CPML_MOVE, 4 }},
82 { .point = { 2, 3 }},
83 { .point = { 4, 5 }},
84 { .point = { 6, 7 }},
85 { .header = { CPML_MOVE, 2 }},
86 { .point = { 8, 9 }}
89 static cairo_path_data_t y1_data[] = {
90 { .header = { CPML_MOVE, 2 }},
91 { .point = { 0, 1 }},
92 { .header = { CPML_LINE, 2 }},
93 { .point = { 5, 1 }}
96 cairo_path_t path = {
97 CAIRO_STATUS_SUCCESS,
98 data,
99 G_N_ELEMENTS(data)
102 cairo_path_t noop_path = {
103 CAIRO_STATUS_SUCCESS,
104 noop_data,
105 G_N_ELEMENTS(noop_data)
108 cairo_path_t y1_path = {
109 CAIRO_STATUS_SUCCESS,
110 y1_data,
111 G_N_ELEMENTS(y1_data)
115 static void
116 _cpml_test_browsing(void)
118 CpmlSegment segment;
119 cpml_segment_from_cairo(&segment, &path);
121 /* First segment */
122 g_assert_cmpint(segment.data[0].header.type, ==, CPML_MOVE);
123 g_assert_cmpint(segment.data[2].header.type, ==, CPML_LINE);
125 cpml_segment_reset(&segment);
126 g_assert_cmpint(segment.data[0].header.type, ==, CPML_MOVE);
127 g_assert_cmpint(segment.data[2].header.type, ==, CPML_LINE);
129 /* Second segment */
130 g_assert_cmpint(cpml_segment_next(&segment), ==, 1);
131 g_assert_cmpint(segment.data[0].header.type, ==, CPML_MOVE);
132 g_assert_cmpint(segment.data[2].header.type, ==, CPML_CURVE);
134 /* Third segment */
135 g_assert_cmpint(cpml_segment_next(&segment), ==, 1);
136 g_assert_cmpint(segment.data[0].header.type, ==, CPML_MOVE);
137 g_assert_cmpint(segment.data[2].header.type, ==, CPML_ARC);
139 /* Forth segment */
140 g_assert_cmpint(cpml_segment_next(&segment), ==, 1);
141 g_assert_cmpint(segment.data[0].header.type, ==, CPML_MOVE);
142 g_assert_cmpint(segment.data[2].header.type, ==, CPML_CLOSE);
144 g_assert_cmpint(cpml_segment_next(&segment), ==, 0);
146 cpml_segment_reset(&segment);
147 g_assert_cmpint(segment.data[0].header.type, ==, CPML_MOVE);
148 g_assert_cmpint(segment.data[2].header.type, ==, CPML_LINE);
151 static void
152 _cpml_test_from_cairo(void)
154 CpmlSegment segment;
155 g_assert_cmpint(cpml_segment_from_cairo(NULL, &path), ==, 0);
156 g_assert_cmpint(cpml_segment_from_cairo(&segment, NULL), ==, 0);
157 g_assert_cmpint(cpml_segment_from_cairo(NULL, NULL), ==, 0);
159 g_assert_cmpint(cpml_segment_from_cairo(&segment, &noop_path), ==, 0);
160 g_assert_cmpint(cpml_segment_from_cairo(&segment, &path), ==, 1);
163 static void
164 _cpml_test_get_length(void)
166 CpmlSegment segment;
167 cpml_segment_from_cairo(&segment, &path);
169 g_assert_cmpfloat(cpml_segment_get_length(NULL), ==, 0);
171 /* First segment */
172 g_assert_cmpfloat(cpml_segment_get_length(&segment), ==, 4);
173 g_assert_cmpfloat(cpml_segment_get_length(&segment), ==, 4);
175 /* Second segment */
176 cpml_segment_next(&segment);
177 /* TODO: Bézier curve length not yet implemented
178 * g_assert_cmpfloat(cpml_segment_get_length(&segment), ==, ???); */
180 /* Third segment */
181 cpml_segment_next(&segment);
182 g_assert_cmpfloat(cpml_segment_get_length(&segment), ==, 0);
184 /* Forth segment */
185 cpml_segment_next(&segment);
186 g_assert_cmpfloat(cpml_segment_get_length(&segment), ==, 0);
189 static void
190 _cpml_test_put_intersections(void)
192 CpmlSegment segment1, segment2;
193 CpmlPair pair[2];
195 cpml_segment_from_cairo(&segment1, &path);
196 cpml_segment_from_cairo(&segment2, &y1_path);
198 g_assert_cmpuint(cpml_segment_put_intersections(NULL, &segment2, 2, pair), ==, 0);
199 g_assert_cmpuint(cpml_segment_put_intersections(&segment1, NULL, 2, pair), ==, 0);
200 g_assert_cmpuint(cpml_segment_put_intersections(&segment1, &segment2, 0, pair), ==, 0);
201 g_assert_cmpuint(cpml_segment_put_intersections(&segment1, &segment2, 2, NULL), ==, 0);
203 /* The first segment of path intersects y1_path in (2, 1) */
204 g_assert_cmpuint(cpml_segment_put_intersections(&segment1, &segment2, 2, pair), ==, 1);
205 g_assert_cmpfloat(pair[0].x, ==, 2);
206 g_assert_cmpfloat(pair[0].y, ==, 1);
208 /* The third segment of path does not intersect y1_path */
209 cpml_segment_next(&segment1);
210 cpml_segment_next(&segment1);
211 g_assert_cmpuint(cpml_segment_put_intersections(&segment1, &segment2, 2, pair), ==, 0);
214 static void
215 _cpml_test_offset(void)
217 CpmlSegment original, *segment;
219 /* Check a NULL segment does not crash the process */
220 cpml_segment_offset(NULL, 1);
222 cpml_segment_from_cairo(&original, &path);
224 /* Working on a duplicate of the first segment to avoid modifying path */
225 segment = cpml_segment_deep_dup(&original);
226 cpml_segment_offset(segment, 1);
228 g_assert_cmpint(segment->data[0].header.type, ==, CPML_MOVE);
229 g_assert_cmpfloat(segment->data[1].point.x, ==, 0);
230 g_assert_cmpfloat(segment->data[1].point.y, ==, 1);
232 g_assert_cmpint(segment->data[2].header.type, ==, CPML_LINE);
233 g_assert_cmpfloat(segment->data[3].point.x, ==, 1);
234 g_assert_cmpfloat(segment->data[3].point.y, ==, 1);
236 g_assert_cmpint(segment->data[4].header.type, ==, CPML_LINE);
237 g_assert_cmpfloat(segment->data[5].point.x, ==, 1);
238 g_assert_cmpfloat(segment->data[5].point.y, ==, 2);
240 /* TODO: provide tests for arcs and curves */
242 g_free(segment);
245 static void
246 _cpml_test_transform(void)
248 CpmlSegment original, *segment;
249 cairo_matrix_t matrix;
251 cpml_segment_from_cairo(&original, &path);
253 /* Working on a duplicate of the first segment to avoid modifying path */
254 segment = cpml_segment_deep_dup(&original);
256 /* Check invalid args does not crash the process */
257 cpml_segment_transform(NULL, &matrix);
258 cpml_segment_transform(segment, NULL);
260 cairo_matrix_init_translate(&matrix, 1, 2);
261 cpml_segment_transform(segment, &matrix);
263 g_assert_cmpint(segment->data[0].header.type, ==, CPML_MOVE);
264 g_assert_cmpfloat(segment->data[1].point.x, ==, 1);
265 g_assert_cmpfloat(segment->data[1].point.y, ==, 2);
267 g_assert_cmpint(segment->data[2].header.type, ==, CPML_LINE);
268 g_assert_cmpfloat(segment->data[3].point.x, ==, 3);
269 g_assert_cmpfloat(segment->data[3].point.y, ==, 2);
271 g_assert_cmpint(segment->data[4].header.type, ==, CPML_LINE);
272 g_assert_cmpfloat(segment->data[5].point.x, ==, 3);
273 g_assert_cmpfloat(segment->data[5].point.y, ==, 4);
275 g_free(segment);
278 static void
279 _cpml_test_reverse(void)
281 CpmlSegment original, *segment;
283 /* Check a NULL segment does not crash the process */
284 cpml_segment_reverse(NULL);
286 cpml_segment_from_cairo(&original, &path);
288 /* First segment: work on a duplicate to avoid modifying path */
289 segment = cpml_segment_deep_dup(&original);
290 cpml_segment_reverse(segment);
292 g_assert_cmpint(segment->num_data, ==, 6);
294 g_assert_cmpint(segment->data[0].header.type, ==, CPML_MOVE);
295 g_assert_cmpfloat(segment->data[1].point.x, ==, 2);
296 g_assert_cmpfloat(segment->data[1].point.y, ==, 2);
298 g_assert_cmpint(segment->data[2].header.type, ==, CPML_LINE);
299 g_assert_cmpfloat(segment->data[3].point.x, ==, 2);
300 g_assert_cmpfloat(segment->data[3].point.y, ==, 0);
302 g_assert_cmpint(segment->data[4].header.type, ==, CPML_LINE);
303 g_assert_cmpfloat(segment->data[5].point.x, ==, 0);
304 g_assert_cmpfloat(segment->data[5].point.y, ==, 0);
306 g_free(segment);
308 /* TODO: the second segment is an invalid CPML segment because
309 * it is followed by a segment without a leading move_to.
310 * Find a decent reverse algorithm and document it.
311 * I'm just skipping that segment for now.
313 cpml_segment_next(&original);
315 /* Third segment */
316 cpml_segment_next(&original);
317 segment = cpml_segment_deep_dup(&original);
318 cpml_segment_reverse(segment);
320 g_assert_cmpint(segment->num_data, ==, 8);
322 g_assert_cmpint(segment->data[0].header.type, ==, CPML_MOVE);
323 g_assert_cmpfloat(segment->data[1].point.x, ==, 22);
324 g_assert_cmpfloat(segment->data[1].point.y, ==, 23);
326 g_assert_cmpint(segment->data[2].header.type, ==, CPML_ARC);
327 g_assert_cmpfloat(segment->data[3].point.x, ==, 20);
328 g_assert_cmpfloat(segment->data[3].point.y, ==, 21);
329 g_assert_cmpfloat(segment->data[4].point.x, ==, 18);
330 g_assert_cmpfloat(segment->data[4].point.y, ==, 19);
332 g_assert_cmpint(segment->data[5].header.type, ==, CPML_ARC);
333 g_assert_cmpfloat(segment->data[6].point.x, ==, 16);
334 g_assert_cmpfloat(segment->data[6].point.y, ==, 17);
335 g_assert_cmpfloat(segment->data[7].point.x, ==, 14);
336 g_assert_cmpfloat(segment->data[7].point.y, ==, 15);
338 g_free(segment);
340 /* Forth segment */
341 cpml_segment_next(&original);
342 segment = cpml_segment_deep_dup(&original);
343 cpml_segment_reverse(segment);
345 g_assert_cmpint(segment->num_data, ==, 3);
347 g_assert_cmpint(segment->data[0].header.type, ==, CPML_MOVE);
348 g_assert_cmpfloat(segment->data[1].point.x, ==, 24);
349 g_assert_cmpfloat(segment->data[1].point.y, ==, 25);
351 g_assert_cmpint(segment->data[2].header.type, ==, CPML_CLOSE);
353 g_free(segment);
356 static void
357 _cpml_test_to_cairo(void)
359 cairo_t *cr;
360 CpmlSegment segment;
361 int length, last_length;
363 cr = adg_test_cairo_context();
364 cpml_segment_from_cairo(&segment, &path);
366 g_assert_cmpint(adg_test_cairo_num_data(cr), ==, 0);
367 cpml_segment_to_cairo(NULL, cr);
368 g_assert_cmpint(adg_test_cairo_num_data(cr), ==, 0);
369 cpml_segment_to_cairo(&segment, NULL);
370 g_assert_cmpint(adg_test_cairo_num_data(cr), ==, 0);
372 length = 0;
373 do {
374 last_length = length;
375 cpml_segment_to_cairo(&segment, cr);
376 length = adg_test_cairo_num_data(cr);
377 g_assert_cmpint(length, >, last_length);
378 } while (cpml_segment_next(&segment));
380 cairo_destroy(cr);
383 static void
384 _cpml_test_dump(void)
386 #if GLIB_CHECK_VERSION(2, 38, 0)
387 if (g_test_subprocess()) {
388 CpmlSegment segment;
390 /* This should not crash the process */
391 cpml_segment_dump(NULL);
393 cpml_segment_from_cairo(&segment, &path);
394 cpml_segment_dump(&segment);
396 cpml_segment_next(&segment);
397 cpml_segment_dump(&segment);
399 return;
402 g_test_trap_subprocess(NULL, 0, 0);
403 g_test_trap_assert_passed();
404 g_test_trap_assert_stderr_unmatched("?");
405 g_test_trap_assert_stdout("*NULL*");
406 g_test_trap_assert_stdout("*move*");
407 g_test_trap_assert_stdout("*line*");
408 g_test_trap_assert_stdout("*curve*");
409 g_test_trap_assert_stdout_unmatched("*arc*");
410 #endif
415 main(int argc, char *argv[])
417 adg_test_init(&argc, &argv);
419 adg_test_add_func("/cpml/segment/behavior/browsing", _cpml_test_browsing);
421 adg_test_add_func("/cpml/segment/method/from-cairo", _cpml_test_from_cairo);
422 adg_test_add_func("/cpml/segment/method/get-length", _cpml_test_get_length);
423 adg_test_add_func("/cpml/segment/method/put-intersections", _cpml_test_put_intersections);
424 adg_test_add_func("/cpml/segment/method/offset", _cpml_test_offset);
425 adg_test_add_func("/cpml/segment/method/transform", _cpml_test_transform);
426 adg_test_add_func("/cpml/segment/method/reverse", _cpml_test_reverse);
427 adg_test_add_func("/cpml/segment/method/to-cairo", _cpml_test_to_cairo);
428 adg_test_add_func("/cpml/segment/method/dump", _cpml_test_dump);
430 return g_test_run();