tests: check invalid values crash
[adg.git] / src / cpml / tests / test-segment.c
blobd3f672a8b38b3715e9ed0ee548ecb1dce064c3fa
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_sanity_from_cairo(gint i)
154 CpmlSegment segment;
156 switch (i) {
157 case 1:
158 cpml_segment_from_cairo(NULL, &path);
159 break;
160 case 2:
161 cpml_segment_from_cairo(&segment, NULL);
162 break;
163 default:
164 g_test_trap_assert_failed();
165 break;
169 static void
170 _cpml_test_sanity_get_length(gint i)
172 switch (i) {
173 case 1:
174 cpml_segment_get_length(NULL);
175 break;
176 default:
177 g_test_trap_assert_failed();
178 break;
182 static void
183 _cpml_test_sanity_put_intersections(gint i)
185 CpmlSegment segment;
186 CpmlPair pair;
188 switch (i) {
189 case 1:
190 cpml_segment_put_intersections(NULL, &segment, 2, &pair);
191 break;
192 case 2:
193 cpml_segment_put_intersections(&segment, NULL, 2, &pair);
194 break;
195 case 3:
196 cpml_segment_put_intersections(&segment, &segment, 2, NULL);
197 break;
198 default:
199 g_test_trap_assert_failed();
200 break;
204 static void
205 _cpml_test_sanity_offset(gint i)
207 switch (i) {
208 case 1:
209 cpml_segment_offset(NULL, 1);
210 break;
211 default:
212 g_test_trap_assert_failed();
213 break;
217 static void
218 _cpml_test_sanity_transform(gint i)
220 CpmlSegment segment;
221 cairo_matrix_t matrix;
223 switch (i) {
224 case 1:
225 cpml_segment_transform(NULL, &matrix);
226 break;
227 case 2:
228 cpml_segment_transform(&segment, NULL);
229 break;
230 default:
231 g_test_trap_assert_failed();
232 break;
236 static void
237 _cpml_test_sanity_reverse(gint i)
239 switch (i) {
240 case 1:
241 cpml_segment_reverse(NULL);
242 break;
243 default:
244 g_test_trap_assert_failed();
245 break;
249 static void
250 _cpml_test_sanity_to_cairo(gint i)
252 CpmlSegment segment;
254 switch (i) {
255 case 1:
256 cpml_segment_to_cairo(NULL, adg_test_cairo_context());
257 break;
258 case 2:
259 cpml_segment_to_cairo(&segment, NULL);
260 default:
261 g_test_trap_assert_failed();
262 break;
266 static void
267 _cpml_test_sanity_dump(gint i)
269 switch (i) {
270 case 1:
271 cpml_segment_dump(NULL);
272 break;
273 default:
274 g_test_trap_assert_failed();
275 break;
279 static void
280 _cpml_test_from_cairo(void)
282 CpmlSegment segment;
283 g_assert_cmpint(cpml_segment_from_cairo(&segment, &noop_path), ==, 0);
284 g_assert_cmpint(cpml_segment_from_cairo(&segment, &path), ==, 1);
287 static void
288 _cpml_test_get_length(void)
290 CpmlSegment segment;
291 cpml_segment_from_cairo(&segment, &path);
294 /* First segment */
295 g_assert_cmpfloat(cpml_segment_get_length(&segment), ==, 4);
296 g_assert_cmpfloat(cpml_segment_get_length(&segment), ==, 4);
298 /* Second segment */
299 cpml_segment_next(&segment);
300 /* TODO: Bézier curve length not yet implemented
301 * g_assert_cmpfloat(cpml_segment_get_length(&segment), ==, ???); */
303 /* Third segment */
304 cpml_segment_next(&segment);
305 g_assert_cmpfloat(cpml_segment_get_length(&segment), ==, 0);
307 /* Forth segment */
308 cpml_segment_next(&segment);
309 g_assert_cmpfloat(cpml_segment_get_length(&segment), ==, 0);
312 static void
313 _cpml_test_put_intersections(void)
315 CpmlSegment segment1, segment2;
316 CpmlPair pair[2];
318 cpml_segment_from_cairo(&segment1, &path);
319 cpml_segment_from_cairo(&segment2, &y1_path);
321 g_assert_cmpuint(cpml_segment_put_intersections(&segment1, &segment2, 0, pair), ==, 0);
323 /* The first segment of path intersects y1_path in (2, 1) */
324 g_assert_cmpuint(cpml_segment_put_intersections(&segment1, &segment2, 2, pair), ==, 1);
325 g_assert_cmpfloat(pair[0].x, ==, 2);
326 g_assert_cmpfloat(pair[0].y, ==, 1);
328 /* The third segment of path does not intersect y1_path */
329 cpml_segment_next(&segment1);
330 cpml_segment_next(&segment1);
331 g_assert_cmpuint(cpml_segment_put_intersections(&segment1, &segment2, 2, pair), ==, 0);
334 static void
335 _cpml_test_offset(void)
337 CpmlSegment original, *segment;
339 cpml_segment_from_cairo(&original, &path);
341 /* Working on a duplicate of the first segment to avoid modifying path */
342 segment = cpml_segment_deep_dup(&original);
343 cpml_segment_offset(segment, 1);
345 g_assert_cmpint(segment->data[0].header.type, ==, CPML_MOVE);
346 g_assert_cmpfloat(segment->data[1].point.x, ==, 0);
347 g_assert_cmpfloat(segment->data[1].point.y, ==, 1);
349 g_assert_cmpint(segment->data[2].header.type, ==, CPML_LINE);
350 g_assert_cmpfloat(segment->data[3].point.x, ==, 1);
351 g_assert_cmpfloat(segment->data[3].point.y, ==, 1);
353 g_assert_cmpint(segment->data[4].header.type, ==, CPML_LINE);
354 g_assert_cmpfloat(segment->data[5].point.x, ==, 1);
355 g_assert_cmpfloat(segment->data[5].point.y, ==, 2);
357 /* TODO: provide tests for arcs and curves */
359 g_free(segment);
362 static void
363 _cpml_test_transform(void)
365 CpmlSegment original, *segment;
366 cairo_matrix_t matrix;
368 cpml_segment_from_cairo(&original, &path);
370 /* Working on a duplicate of the first segment to avoid modifying path */
371 segment = cpml_segment_deep_dup(&original);
373 cairo_matrix_init_translate(&matrix, 1, 2);
374 cpml_segment_transform(segment, &matrix);
376 g_assert_cmpint(segment->data[0].header.type, ==, CPML_MOVE);
377 g_assert_cmpfloat(segment->data[1].point.x, ==, 1);
378 g_assert_cmpfloat(segment->data[1].point.y, ==, 2);
380 g_assert_cmpint(segment->data[2].header.type, ==, CPML_LINE);
381 g_assert_cmpfloat(segment->data[3].point.x, ==, 3);
382 g_assert_cmpfloat(segment->data[3].point.y, ==, 2);
384 g_assert_cmpint(segment->data[4].header.type, ==, CPML_LINE);
385 g_assert_cmpfloat(segment->data[5].point.x, ==, 3);
386 g_assert_cmpfloat(segment->data[5].point.y, ==, 4);
388 g_free(segment);
391 static void
392 _cpml_test_reverse(void)
394 CpmlSegment original, *segment;
396 cpml_segment_from_cairo(&original, &path);
398 /* First segment: work on a duplicate to avoid modifying path */
399 segment = cpml_segment_deep_dup(&original);
400 cpml_segment_reverse(segment);
402 g_assert_cmpint(segment->num_data, ==, 6);
404 g_assert_cmpint(segment->data[0].header.type, ==, CPML_MOVE);
405 g_assert_cmpfloat(segment->data[1].point.x, ==, 2);
406 g_assert_cmpfloat(segment->data[1].point.y, ==, 2);
408 g_assert_cmpint(segment->data[2].header.type, ==, CPML_LINE);
409 g_assert_cmpfloat(segment->data[3].point.x, ==, 2);
410 g_assert_cmpfloat(segment->data[3].point.y, ==, 0);
412 g_assert_cmpint(segment->data[4].header.type, ==, CPML_LINE);
413 g_assert_cmpfloat(segment->data[5].point.x, ==, 0);
414 g_assert_cmpfloat(segment->data[5].point.y, ==, 0);
416 g_free(segment);
418 /* TODO: the second segment is an invalid CPML segment because
419 * it is followed by a segment without a leading move_to.
420 * Find a decent reverse algorithm and document it.
421 * I'm just skipping that segment for now.
423 cpml_segment_next(&original);
425 /* Third segment */
426 cpml_segment_next(&original);
427 segment = cpml_segment_deep_dup(&original);
428 cpml_segment_reverse(segment);
430 g_assert_cmpint(segment->num_data, ==, 8);
432 g_assert_cmpint(segment->data[0].header.type, ==, CPML_MOVE);
433 g_assert_cmpfloat(segment->data[1].point.x, ==, 22);
434 g_assert_cmpfloat(segment->data[1].point.y, ==, 23);
436 g_assert_cmpint(segment->data[2].header.type, ==, CPML_ARC);
437 g_assert_cmpfloat(segment->data[3].point.x, ==, 20);
438 g_assert_cmpfloat(segment->data[3].point.y, ==, 21);
439 g_assert_cmpfloat(segment->data[4].point.x, ==, 18);
440 g_assert_cmpfloat(segment->data[4].point.y, ==, 19);
442 g_assert_cmpint(segment->data[5].header.type, ==, CPML_ARC);
443 g_assert_cmpfloat(segment->data[6].point.x, ==, 16);
444 g_assert_cmpfloat(segment->data[6].point.y, ==, 17);
445 g_assert_cmpfloat(segment->data[7].point.x, ==, 14);
446 g_assert_cmpfloat(segment->data[7].point.y, ==, 15);
448 g_free(segment);
450 /* Forth segment */
451 cpml_segment_next(&original);
452 segment = cpml_segment_deep_dup(&original);
453 cpml_segment_reverse(segment);
455 g_assert_cmpint(segment->num_data, ==, 3);
457 g_assert_cmpint(segment->data[0].header.type, ==, CPML_MOVE);
458 g_assert_cmpfloat(segment->data[1].point.x, ==, 24);
459 g_assert_cmpfloat(segment->data[1].point.y, ==, 25);
461 g_assert_cmpint(segment->data[2].header.type, ==, CPML_CLOSE);
463 g_free(segment);
466 static void
467 _cpml_test_to_cairo(void)
469 cairo_t *cr;
470 CpmlSegment segment;
471 int length, last_length;
473 cr = adg_test_cairo_context();
474 cpml_segment_from_cairo(&segment, &path);
476 g_assert_cmpint(adg_test_cairo_num_data(cr), ==, 0);
478 length = 0;
479 do {
480 last_length = length;
481 cpml_segment_to_cairo(&segment, cr);
482 length = adg_test_cairo_num_data(cr);
483 g_assert_cmpint(length, >, last_length);
484 } while (cpml_segment_next(&segment));
486 cairo_destroy(cr);
489 static void
490 _cpml_test_dump(gint i)
492 CpmlSegment segment;
494 switch (i) {
495 case 1:
496 cpml_segment_from_cairo(&segment, &path);
497 cpml_segment_dump(&segment);
498 cpml_segment_next(&segment);
499 cpml_segment_dump(&segment);
500 break;
501 default:
502 g_test_trap_assert_passed();
503 g_test_trap_assert_stderr_unmatched("?");
504 g_test_trap_assert_stdout("*move*");
505 g_test_trap_assert_stdout("*line*");
506 g_test_trap_assert_stdout("*curve*");
507 g_test_trap_assert_stdout_unmatched("*arc*");
508 break;
514 main(int argc, char *argv[])
516 adg_test_init(&argc, &argv);
518 g_test_add_func("/cpml/segment/behavior/browsing", _cpml_test_browsing);
520 adg_test_add_traps("/cpml/segment/sanity/from-cairo", _cpml_test_sanity_from_cairo, 2);
521 adg_test_add_traps("/cpml/segment/sanity/get-length", _cpml_test_sanity_get_length, 1);
522 adg_test_add_traps("/cpml/segment/sanity/put-intersections", _cpml_test_sanity_put_intersections, 3);
523 adg_test_add_traps("/cpml/segment/sanity/offset", _cpml_test_sanity_offset, 1);
524 adg_test_add_traps("/cpml/segment/sanity/transform", _cpml_test_sanity_transform, 2);
525 adg_test_add_traps("/cpml/segment/sanity/reverse", _cpml_test_sanity_reverse, 1);
526 adg_test_add_traps("/cpml/segment/sanity/to-cairo", _cpml_test_sanity_to_cairo, 2);
527 adg_test_add_traps("/cpml/segment/sanity/dump", _cpml_test_sanity_dump, 1);
529 g_test_add_func("/cpml/segment/method/from-cairo", _cpml_test_from_cairo);
530 g_test_add_func("/cpml/segment/method/get-length", _cpml_test_get_length);
531 g_test_add_func("/cpml/segment/method/put-intersections", _cpml_test_put_intersections);
532 g_test_add_func("/cpml/segment/method/offset", _cpml_test_offset);
533 g_test_add_func("/cpml/segment/method/transform", _cpml_test_transform);
534 g_test_add_func("/cpml/segment/method/reverse", _cpml_test_reverse);
535 g_test_add_func("/cpml/segment/method/to-cairo", _cpml_test_to_cairo);
536 adg_test_add_traps("/cpml/segment/method/dump", _cpml_test_dump, 1);
538 return g_test_run();