Viewport clipping now works with both GL and Gallium.
[cairo/gpu.git] / test / cairo-test.c
blob3e2dc1243c62102fa66adca1508093d8e0c4f7d3
1 /*
2 * Copyright © 2004 Red Hat, Inc.
3 * Copyright © 2008 Chris Wilson
5 * Permission to use, copy, modify, distribute, and sell this software
6 * and its documentation for any purpose is hereby granted without
7 * fee, provided that the above copyright notice appear in all copies
8 * and that both that copyright notice and this permission notice
9 * appear in supporting documentation, and that the name of
10 * Red Hat, Inc. not be used in advertising or publicity pertaining to
11 * distribution of the software without specific, written prior
12 * permission. Red Hat, Inc. makes no representations about the
13 * suitability of this software for any purpose. It is provided "as
14 * is" without express or implied warranty.
16 * RED HAT, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
17 * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
18 * FITNESS, IN NO EVENT SHALL RED HAT, INC. BE LIABLE FOR ANY SPECIAL,
19 * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
20 * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
21 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
22 * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
24 * Author: Carl D. Worth <cworth@cworth.org>
25 * Chris Wilson <chris@chris-wilson.co.uk>
28 #define _GNU_SOURCE 1 /* for feenableexcept() et al */
29 #define _POSIX_C_SOURCE 200112L /* for flockfile() et al */
31 #if HAVE_CONFIG_H
32 #include "config.h"
33 #endif
35 #include <stdio.h>
36 #include <stdlib.h>
37 #include <stdarg.h>
38 #include <ctype.h>
39 #if HAVE_FEENABLEEXCEPT
40 #include <fenv.h>
41 #endif
42 #include <assert.h>
43 #if HAVE_UNISTD_H
44 #include <unistd.h>
45 #endif
46 #include <errno.h>
47 #include <string.h>
48 #if HAVE_FCFINI
49 #include <fontconfig/fontconfig.h>
50 #endif
51 #if HAVE_PTHREAD_H
52 #include <pthread.h>
53 #endif
54 #if HAVE_SYS_STAT_H
55 #include <sys/stat.h>
56 #endif
58 #if HAVE_VALGRIND
59 #include <valgrind.h>
60 #else
61 #define RUNNING_ON_VALGRIND 0
62 #endif
64 #if HAVE_MEMFAULT
65 #include <memfault.h>
66 #define MF(x) x
67 #else
68 #define MF(x)
69 #endif
71 #include "cairo-test-private.h"
73 #include "buffer-diff.h"
75 #ifdef _MSC_VER
76 #include <crtdbg.h>
77 #define vsnprintf _vsnprintf
78 #define access _access
79 #define F_OK 0
80 #endif
82 #ifndef FALSE
83 #define FALSE 0
84 #endif
85 #ifndef TRUE
86 #define TRUE !FALSE
87 #endif
89 static const cairo_user_data_key_t _cairo_test_context_key;
91 static void
92 _xunlink (const cairo_test_context_t *ctx, const char *pathname);
94 static const char *fail_face = "", *xfail_face="", *normal_face = "";
95 static cairo_bool_t print_fail_on_stdout;
96 static int cairo_test_timeout = 60;
98 #define CAIRO_TEST_LOG_SUFFIX ".log"
99 #define CAIRO_TEST_PNG_SUFFIX ".out.png"
100 #define CAIRO_TEST_REF_SUFFIX ".ref.png"
101 #define CAIRO_TEST_DIFF_SUFFIX ".diff.png"
102 #define CAIRO_TEST_OUTPUT_DIR "output"
104 #define NUM_DEVICE_OFFSETS 2
106 static char *
107 _cairo_test_fixup_name (const char *original)
109 int len = strlen (original);
110 char *name, *s;
112 name = xmalloc (len + 1);
113 s = memcpy (name, original, len + 1);
114 while ((s = strchr (s, '_')) != NULL)
115 *s++ = '-';
117 return name;
120 char *
121 cairo_test_get_name (const cairo_test_t *test)
123 return _cairo_test_fixup_name (test->name);
126 static void
127 _cairo_test_init (cairo_test_context_t *ctx,
128 const cairo_test_context_t *parent,
129 const cairo_test_t *test,
130 const char *test_name,
131 cairo_test_status_t expectation)
133 char *log_name;
135 MF (MEMFAULT_DISABLE_FAULTS ());
137 #if HAVE_FEENABLEEXCEPT
138 feenableexcept (FE_DIVBYZERO | FE_INVALID | FE_OVERFLOW);
139 #endif
141 ctx->test = test;
142 ctx->test_name = _cairo_test_fixup_name (test_name);
143 ctx->expectation = expectation;
145 ctx->malloc_failure = 0;
146 #if HAVE_MEMFAULT
147 if (getenv ("CAIRO_TEST_MALLOC_FAILURE"))
148 ctx->malloc_failure = atoi (getenv ("CAIRO_TEST_MALLOC_FAILURE"));
149 if (ctx->malloc_failure && ! RUNNING_ON_MEMFAULT ())
150 ctx->malloc_failure = 0;
151 #endif
153 ctx->timeout = cairo_test_timeout;
154 if (getenv ("CAIRO_TEST_TIMEOUT"))
155 ctx->timeout = atoi (getenv ("CAIRO_TEST_TIMEOUT"));
157 xasprintf (&log_name, "%s%s", ctx->test_name, CAIRO_TEST_LOG_SUFFIX);
158 _xunlink (NULL, log_name);
160 ctx->log_file = fopen (log_name, "a");
161 if (ctx->log_file == NULL) {
162 fprintf (stderr, "Error opening log file: %s\n", log_name);
163 ctx->log_file = stderr;
165 free (log_name);
167 ctx->ref_name = NULL;
168 ctx->ref_image = NULL;
169 ctx->ref_image_flattened = NULL;
171 ctx->thread = 0;
173 if (parent != NULL) {
174 ctx->targets_to_test = parent->targets_to_test;
175 ctx->num_targets = parent->num_targets;
176 ctx->limited_targets = parent->limited_targets;
177 ctx->own_targets = FALSE;
179 ctx->srcdir = parent->srcdir;
180 ctx->refdir = parent->refdir;
181 } else {
182 int tmp_num_targets;
183 cairo_bool_t tmp_limited_targets;
185 ctx->targets_to_test = cairo_boilerplate_get_targets (&tmp_num_targets, &tmp_limited_targets);
186 ctx->num_targets = tmp_num_targets;
187 ctx->limited_targets = tmp_limited_targets;
188 ctx->own_targets = TRUE;
190 ctx->srcdir = getenv ("srcdir");
191 if (ctx->srcdir == NULL)
192 ctx->srcdir = ".";
194 ctx->refdir = getenv ("CAIRO_REF_DIR");
197 #ifdef HAVE_UNISTD_H
198 if (*fail_face == '\0' && isatty (2)) {
199 fail_face = "\033[41;37;1m";
200 xfail_face = "\033[43;37;1m";
201 normal_face = "\033[m";
202 if (isatty (1))
203 print_fail_on_stdout = FALSE;
205 #endif
207 printf ("\nTESTING %s\n", ctx->test_name);
210 void
211 _cairo_test_context_init_for_test (cairo_test_context_t *ctx,
212 const cairo_test_context_t *parent,
213 const cairo_test_t *test)
215 _cairo_test_init (ctx, parent, test, test->name, CAIRO_TEST_SUCCESS);
218 void
219 cairo_test_init (cairo_test_context_t *ctx,
220 const char *test_name)
222 _cairo_test_init (ctx, NULL, NULL, test_name, CAIRO_TEST_SUCCESS);
225 static void
226 cairo_test_init_thread (cairo_test_context_t *ctx,
227 cairo_test_context_t *master,
228 int thread)
230 MF (MEMFAULT_DISABLE_FAULTS ());
232 *ctx = *master;
233 ctx->thread = thread;
236 void
237 cairo_test_fini (cairo_test_context_t *ctx)
239 if (ctx->thread != 0)
240 return;
242 if (ctx->log_file == NULL)
243 return;
245 if (ctx->log_file != stderr)
246 fclose (ctx->log_file);
247 ctx->log_file = NULL;
249 if (ctx->ref_name != NULL)
250 free (ctx->ref_name);
251 cairo_surface_destroy (ctx->ref_image);
252 cairo_surface_destroy (ctx->ref_image_flattened);
254 if (ctx->test_name != NULL)
255 free ((char *) ctx->test_name);
257 if (ctx->own_targets)
258 cairo_boilerplate_free_targets (ctx->targets_to_test);
260 cairo_debug_reset_static_data ();
261 #if HAVE_FCFINI
262 FcFini ();
263 #endif
266 void
267 cairo_test_logv (const cairo_test_context_t *ctx,
268 const char *fmt, va_list va)
270 FILE *file = ctx && ctx->log_file ? ctx->log_file : stderr;
271 vfprintf (file, fmt, va);
274 void
275 cairo_test_log (const cairo_test_context_t *ctx, const char *fmt, ...)
277 va_list va;
278 FILE *file = ctx && ctx->log_file ? ctx->log_file : stderr;
280 va_start (va, fmt);
281 vfprintf (file, fmt, va);
282 va_end (va);
285 void
286 cairo_test_log_path (const cairo_test_context_t *ctx,
287 const cairo_path_t *path)
289 int i;
291 for (i = 0; i < path->num_data; i += path->data[i].header.length) {
292 cairo_path_data_t *data = &path->data[i];
293 switch (data->header.type) {
294 case CAIRO_PATH_MOVE_TO:
295 cairo_test_log (ctx,
296 " cairo_move_to (cr, %g, %g);\n",
297 data[1].point.x, data[1].point.y);
298 break;
299 case CAIRO_PATH_LINE_TO:
300 cairo_test_log (ctx,
301 " cairo_line_to (cr, %g, %g);\n",
302 data[1].point.x, data[1].point.y);
303 break;
304 case CAIRO_PATH_CURVE_TO:
305 cairo_test_log (ctx,
306 " cairo_curve_to (cr, %g, %g, %g, %g, %g, %g);\n",
307 data[1].point.x, data[1].point.y,
308 data[2].point.x, data[2].point.y,
309 data[3].point.x, data[3].point.y);
310 break;
311 case CAIRO_PATH_CLOSE_PATH:
312 cairo_test_log (ctx,
313 " cairo_close_path (cr);\n\n");
314 break;
315 default:
316 assert (0);
321 static void
322 _xunlink (const cairo_test_context_t *ctx, const char *pathname)
324 if (unlink (pathname) < 0 && errno != ENOENT) {
325 cairo_test_log (ctx, "Error: Cannot remove %s: %s\n",
326 pathname, strerror (errno));
327 exit (1);
331 char *
332 cairo_test_reference_image_filename (const cairo_test_context_t *ctx,
333 const char *base_name,
334 const char *test_name,
335 const char *target_name,
336 const char *base_target_name,
337 const char *format)
339 char *ref_name = NULL;
341 /* First look for a previous build for comparison. */
342 if (ctx->refdir != NULL) {
343 xasprintf (&ref_name, "%s/%s%s",
344 ctx->refdir,
345 base_name,
346 CAIRO_TEST_PNG_SUFFIX);
347 if (access (ref_name, F_OK) != 0)
348 free (ref_name);
349 else
350 goto done;
353 /* Next look for a target/format-specific reference image. */
354 xasprintf (&ref_name, "%s/%s.%s.%s%s",
355 ctx->srcdir,
356 test_name,
357 target_name,
358 format,
359 CAIRO_TEST_REF_SUFFIX);
360 if (access (ref_name, F_OK) != 0)
361 free (ref_name);
362 else
363 goto done;
365 /* Next, look for target-specific reference image. */
366 xasprintf (&ref_name, "%s/%s.%s%s",
367 ctx->srcdir,
368 test_name,
369 target_name,
370 CAIRO_TEST_REF_SUFFIX);
371 if (access (ref_name, F_OK) != 0)
372 free (ref_name);
373 else
374 goto done;
376 /* Next look for a base/format-specific reference image. */
377 xasprintf (&ref_name, "%s/%s.%s.%s%s",
378 ctx->srcdir,
379 test_name,
380 base_target_name,
381 format,
382 CAIRO_TEST_REF_SUFFIX);
383 if (access (ref_name, F_OK) != 0)
384 free (ref_name);
385 else
386 goto done;
388 /* Next, look for base-specific reference image. */
389 xasprintf (&ref_name, "%s/%s.%s%s",
390 ctx->srcdir,
391 test_name,
392 base_target_name,
393 CAIRO_TEST_REF_SUFFIX);
394 if (access (ref_name, F_OK) != 0)
395 free (ref_name);
396 else
397 goto done;
399 /* Next, look for format-specific reference image. */
400 xasprintf (&ref_name, "%s/%s.%s%s",
401 ctx->srcdir,
402 test_name,
403 format,
404 CAIRO_TEST_REF_SUFFIX);
405 if (access (ref_name, F_OK) != 0)
406 free (ref_name);
407 else
408 goto done;
410 /* Finally, look for the standard reference image. */
411 xasprintf (&ref_name, "%s/%s%s", ctx->srcdir,
412 test_name,
413 CAIRO_TEST_REF_SUFFIX);
414 if (access (ref_name, F_OK) != 0)
415 free (ref_name);
416 else
417 goto done;
419 ref_name = NULL;
421 done:
422 return ref_name;
425 cairo_bool_t
426 cairo_test_target_has_similar (const cairo_test_context_t *ctx,
427 const cairo_boilerplate_target_t *target)
429 cairo_surface_t *surface;
430 cairo_bool_t has_similar;
431 cairo_t * cr;
432 cairo_surface_t *similar;
433 cairo_status_t status;
434 void *closure;
436 /* ignore image intermediate targets */
437 if (target->expected_type == CAIRO_SURFACE_TYPE_IMAGE)
438 return FALSE;
440 if (getenv ("CAIRO_TEST_IGNORE_SIMILAR"))
441 return FALSE;
443 do {
444 do {
445 surface = (target->create_surface) (ctx->test->name,
446 target->content,
447 ctx->test->width,
448 ctx->test->height,
449 ctx->test->width + 25 * NUM_DEVICE_OFFSETS,
450 ctx->test->height + 25 * NUM_DEVICE_OFFSETS,
451 CAIRO_BOILERPLATE_MODE_TEST,
453 &closure);
454 if (surface == NULL)
455 return FALSE;
456 } while (cairo_test_malloc_failure (ctx, cairo_surface_status (surface)));
458 if (cairo_surface_status (surface))
459 return FALSE;
462 cr = cairo_create (surface);
463 cairo_push_group_with_content (cr,
464 cairo_boilerplate_content (target->content));
465 similar = cairo_get_group_target (cr);
466 status = cairo_surface_status (similar);
468 has_similar = cairo_surface_get_type (similar) == cairo_surface_get_type (surface);
470 cairo_destroy (cr);
471 cairo_surface_destroy (surface);
473 if (target->cleanup)
474 target->cleanup (closure);
475 } while (cairo_test_malloc_failure (ctx, status));
477 return has_similar;
480 static cairo_surface_t *
481 _cairo_test_flatten_reference_image (cairo_test_context_t *ctx,
482 cairo_bool_t flatten)
484 cairo_surface_t *surface;
485 cairo_t *cr;
487 if (! flatten)
488 return ctx->ref_image;
490 if (ctx->ref_image_flattened != NULL)
491 return ctx->ref_image_flattened;
493 surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32,
494 cairo_image_surface_get_width (ctx->ref_image),
495 cairo_image_surface_get_height (ctx->ref_image));
496 cr = cairo_create (surface);
497 cairo_surface_destroy (surface);
499 cairo_set_source_rgb (cr, 1, 1, 1);
500 cairo_paint (cr);
502 cairo_set_source_surface (cr, ctx->ref_image, 0, 0);
503 cairo_paint (cr);
505 surface = cairo_surface_reference (cairo_get_target (cr));
506 cairo_destroy (cr);
508 if (cairo_surface_status (surface) == CAIRO_STATUS_SUCCESS)
509 ctx->ref_image_flattened = surface;
510 return surface;
513 cairo_surface_t *
514 cairo_test_get_reference_image (cairo_test_context_t *ctx,
515 const char *filename,
516 cairo_bool_t flatten)
518 cairo_surface_t *surface;
519 int len;
521 if (ctx->ref_name != NULL) {
522 if (strcmp (ctx->ref_name, filename) == 0)
523 return _cairo_test_flatten_reference_image (ctx, flatten);
525 cairo_surface_destroy (ctx->ref_image);
526 ctx->ref_image = NULL;
528 cairo_surface_destroy (ctx->ref_image_flattened);
529 ctx->ref_image_flattened = NULL;
531 free (ctx->ref_name);
532 ctx->ref_name = NULL;
535 surface = cairo_image_surface_create_from_png (filename);
536 if (cairo_surface_status (surface))
537 return surface;
539 len = strlen (filename);
540 ctx->ref_name = xmalloc (len + 1);
541 memcpy (ctx->ref_name, filename, len + 1);
543 ctx->ref_image = surface;
544 return _cairo_test_flatten_reference_image (ctx, flatten);
547 static cairo_bool_t
548 cairo_test_file_is_older (const char *filename,
549 const char *ref_filename)
551 #if HAVE_SYS_STAT_H
552 struct stat st, ref;
554 if (stat (filename, &st) < 0)
555 return FALSE;
557 if (stat (ref_filename, &ref) < 0)
558 return TRUE;
560 return st.st_mtime < ref.st_mtime;
561 #else
562 /* XXX */
563 return FALSE;
564 #endif
567 static cairo_bool_t
568 cairo_test_files_equal (const char *test_filename,
569 const char *pass_filename)
571 FILE *test, *pass;
572 int t, p;
574 test = fopen (test_filename, "rb");
575 if (test == NULL)
576 return FALSE;
578 pass = fopen (pass_filename, "rb");
579 if (pass == NULL) {
580 fclose (test);
581 return FALSE;
584 /* as simple as it gets */
585 do {
586 t = getc (test);
587 p = getc (pass);
588 if (t != p)
589 break;
590 } while (t != EOF && p != EOF);
592 fclose (pass);
593 fclose (test);
595 return t == p; /* both EOF */
598 static cairo_bool_t
599 cairo_test_copy_file (const char *src_filename,
600 const char *dst_filename)
602 FILE *src, *dst;
603 int c;
605 #if HAVE_LINK
606 if (link (src_filename, dst_filename) == 0)
607 return TRUE;
609 unlink (dst_filename);
610 #endif
612 src = fopen (src_filename, "rb");
613 if (src == NULL)
614 return FALSE;
616 dst = fopen (dst_filename, "wb");
617 if (dst == NULL) {
618 fclose (src);
619 return FALSE;
622 /* as simple as it gets */
623 while ((c = getc (src)) != EOF)
624 putc (c, dst);
626 fclose (src);
627 fclose (dst);
629 return TRUE;
632 static cairo_bool_t
633 _cairo_test_mkdir (const char *path)
635 #if ! HAVE_MKDIR
636 return FALSE;
637 #elif HAVE_MKDIR == 1
638 if (mkdir (path) == 0)
639 return TRUE;
640 #elif HAVE_MKDIR == 2
641 if (mkdir (path, 0770) == 0)
642 return TRUE;
643 #else
644 #error Bad value for HAVE_MKDIR
645 #endif
647 return errno == EEXIST;
650 static cairo_test_status_t
651 cairo_test_for_target (cairo_test_context_t *ctx,
652 const cairo_boilerplate_target_t *target,
653 int dev_offset,
654 cairo_bool_t similar)
656 cairo_test_status_t status;
657 cairo_surface_t *surface = NULL;
658 cairo_t *cr;
659 const char *empty_str = "";
660 char *offset_str, *thread_str;
661 char *base_name, *base_path;
662 char *png_path, *ref_path, *diff_path;
663 char *test_filename = NULL, *pass_filename = NULL, *fail_filename = NULL;
664 cairo_test_status_t ret;
665 cairo_content_t expected_content;
666 cairo_font_options_t *font_options;
667 const char *format;
668 cairo_bool_t have_output = FALSE;
669 cairo_bool_t have_result = FALSE;
670 void *closure;
671 double width, height;
672 cairo_bool_t have_output_dir;
673 #if HAVE_MEMFAULT
674 int malloc_failure_iterations = ctx->malloc_failure;
675 int last_fault_count = 0;
676 #endif
678 /* Get the strings ready that we'll need. */
679 format = cairo_boilerplate_content_name (target->content);
680 if (dev_offset)
681 xasprintf (&offset_str, ".%d", dev_offset);
682 else
683 offset_str = (char *) empty_str;
684 if (ctx->thread)
685 xasprintf (&thread_str, ".thread%d", ctx->thread);
686 else
687 thread_str = (char *) empty_str;
689 xasprintf (&base_name, "%s.%s.%s%s%s%s",
690 ctx->test_name,
691 target->name,
692 format,
693 similar ? ".similar" : "",
694 offset_str,
695 thread_str);
697 if (offset_str != empty_str)
698 free (offset_str);
699 if (thread_str != empty_str)
700 free (thread_str);
703 ref_path = cairo_test_reference_image_filename (ctx,
704 base_name,
705 ctx->test_name,
706 target->name,
707 target->basename,
708 format);
709 have_output_dir = _cairo_test_mkdir (CAIRO_TEST_OUTPUT_DIR);
710 xasprintf (&base_path, "%s/%s",
711 have_output_dir ? CAIRO_TEST_OUTPUT_DIR : ".",
712 base_name);
713 xasprintf (&png_path, "%s" CAIRO_TEST_PNG_SUFFIX, base_path);
714 xasprintf (&diff_path, "%s" CAIRO_TEST_DIFF_SUFFIX, base_path);
716 if (ctx->test->requirements != NULL) {
717 const char *required;
719 required = target->is_vector ? "target=raster" : "target=vector";
720 if (strstr (ctx->test->requirements, required) != NULL) {
721 cairo_test_log (ctx, "Error: Skipping for %s target %s\n",
722 target->is_vector ? "vector" : "raster",
723 target->name);
724 ret = CAIRO_TEST_UNTESTED;
725 goto UNWIND_STRINGS;
728 required = target->is_meta ? "target=!meta" : "target=meta";
729 if (strstr (ctx->test->requirements, required) != NULL) {
730 cairo_test_log (ctx, "Error: Skipping for %s target %s\n",
731 target->is_meta ? "meta" : "non-meta",
732 target->name);
733 ret = CAIRO_TEST_UNTESTED;
734 goto UNWIND_STRINGS;
738 width = ctx->test->width;
739 height = ctx->test->height;
740 if (width && height) {
741 width += dev_offset;
742 height += dev_offset;
745 #if HAVE_MEMFAULT
746 REPEAT:
747 MEMFAULT_CLEAR_FAULTS ();
748 MEMFAULT_RESET_LEAKS ();
749 ctx->last_fault_count = 0;
750 last_fault_count = MEMFAULT_COUNT_FAULTS ();
752 /* Pre-initialise fontconfig so that the configuration is loaded without
753 * malloc failures (our primary goal is to test cairo fault tolerance).
755 #if HAVE_FCINIT
756 FcInit ();
757 #endif
759 MEMFAULT_ENABLE_FAULTS ();
760 #endif
761 have_output = FALSE;
762 have_result = FALSE;
764 /* Run the actual drawing code. */
765 ret = CAIRO_TEST_SUCCESS;
766 surface = (target->create_surface) (base_path,
767 target->content,
768 width, height,
769 ctx->test->width + 25 * NUM_DEVICE_OFFSETS,
770 ctx->test->height + 25 * NUM_DEVICE_OFFSETS,
771 CAIRO_BOILERPLATE_MODE_TEST,
772 ctx->thread,
773 &closure);
774 if (surface == NULL) {
775 cairo_test_log (ctx, "Error: Failed to set %s target\n", target->name);
776 ret = CAIRO_TEST_UNTESTED;
777 goto UNWIND_STRINGS;
780 #if HAVE_MEMFAULT
781 if (ctx->malloc_failure &&
782 MEMFAULT_COUNT_FAULTS () - last_fault_count > 0 &&
783 cairo_surface_status (surface) == CAIRO_STATUS_NO_MEMORY)
785 goto REPEAT;
787 #endif
789 if (cairo_surface_status (surface)) {
790 MF (MEMFAULT_PRINT_FAULTS ());
791 cairo_test_log (ctx, "Error: Created an error surface\n");
792 ret = CAIRO_TEST_FAILURE;
793 goto UNWIND_STRINGS;
796 /* Check that we created a surface of the expected type. */
797 if (cairo_surface_get_type (surface) != target->expected_type) {
798 MF (MEMFAULT_PRINT_FAULTS ());
799 cairo_test_log (ctx, "Error: Created surface is of type %d (expected %d)\n",
800 cairo_surface_get_type (surface), target->expected_type);
801 ret = CAIRO_TEST_FAILURE;
802 goto UNWIND_SURFACE;
805 /* Check that we created a surface of the expected content,
806 * (ignore the artificial CAIRO_TEST_CONTENT_COLOR_ALPHA_FLATTENED value).
808 expected_content = cairo_boilerplate_content (target->content);
810 if (cairo_surface_get_content (surface) != expected_content) {
811 MF (MEMFAULT_PRINT_FAULTS ());
812 cairo_test_log (ctx, "Error: Created surface has content %d (expected %d)\n",
813 cairo_surface_get_content (surface), expected_content);
814 ret = CAIRO_TEST_FAILURE;
815 goto UNWIND_SURFACE;
818 cairo_surface_set_device_offset (surface, dev_offset, dev_offset);
820 cr = cairo_create (surface);
821 if (cairo_set_user_data (cr, &_cairo_test_context_key, (void*) ctx, NULL)) {
822 #if HAVE_MEMFAULT
823 cairo_destroy (cr);
824 cairo_surface_destroy (surface);
826 if (target->cleanup)
827 target->cleanup (closure);
829 goto REPEAT;
830 #else
831 ret = CAIRO_TEST_FAILURE;
832 goto UNWIND_CAIRO;
833 #endif
836 if (similar)
837 cairo_push_group_with_content (cr, expected_content);
839 /* Clear to transparent (or black) depending on whether the target
840 * surface supports alpha. */
841 cairo_save (cr);
842 cairo_set_operator (cr, CAIRO_OPERATOR_CLEAR);
843 cairo_paint (cr);
844 cairo_restore (cr);
846 /* Set all components of font_options to avoid backend differences
847 * and reduce number of needed reference images. */
848 font_options = cairo_font_options_create ();
849 cairo_font_options_set_hint_style (font_options, CAIRO_HINT_STYLE_NONE);
850 cairo_font_options_set_hint_metrics (font_options, CAIRO_HINT_METRICS_ON);
851 cairo_font_options_set_antialias (font_options, CAIRO_ANTIALIAS_GRAY);
852 cairo_set_font_options (cr, font_options);
853 cairo_font_options_destroy (font_options);
855 cairo_save (cr);
856 #if HAVE_ALARM
857 alarm (ctx->timeout);
858 #endif
859 status = (ctx->test->draw) (cr, ctx->test->width, ctx->test->height);
860 #if HAVE_ALARM
861 alarm (0);
862 #endif
863 cairo_restore (cr);
865 if (similar) {
866 cairo_pop_group_to_source (cr);
867 cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
868 cairo_paint (cr);
871 #if HAVE_MEMFAULT
872 MEMFAULT_DISABLE_FAULTS ();
874 /* repeat test after malloc failure injection */
875 if (ctx->malloc_failure &&
876 MEMFAULT_COUNT_FAULTS () - last_fault_count > 0 &&
877 (status == CAIRO_TEST_NO_MEMORY ||
878 cairo_status (cr) == CAIRO_STATUS_NO_MEMORY ||
879 cairo_surface_status (surface) == CAIRO_STATUS_NO_MEMORY))
881 cairo_destroy (cr);
882 cairo_surface_destroy (surface);
883 if (target->cleanup)
884 target->cleanup (closure);
885 if (ctx->thread == 0) {
886 cairo_debug_reset_static_data ();
887 #if HAVE_FCFINI
888 FcFini ();
889 #endif
890 if (MEMFAULT_COUNT_LEAKS () > 0) {
891 MEMFAULT_PRINT_FAULTS ();
892 MEMFAULT_PRINT_LEAKS ();
896 goto REPEAT;
898 #endif
900 /* Then, check all the different ways it could fail. */
901 if (status) {
902 cairo_test_log (ctx, "Error: Function under test failed\n");
903 ret = status;
904 goto UNWIND_CAIRO;
907 if (cairo_status (cr) != CAIRO_STATUS_SUCCESS) {
908 cairo_test_log (ctx, "Error: Function under test left cairo status in an error state: %s\n",
909 cairo_status_to_string (cairo_status (cr)));
910 ret = CAIRO_TEST_FAILURE;
911 goto UNWIND_CAIRO;
914 #if HAVE_MEMFAULT
915 if (MEMFAULT_COUNT_FAULTS () - last_fault_count > 0 &&
916 MEMFAULT_HAS_FAULTS ())
918 VALGRIND_PRINTF ("Unreported memfaults...");
919 MEMFAULT_PRINT_FAULTS ();
921 #endif
923 /* Skip image check for tests with no image (width,height == 0,0) */
924 if (ctx->test->width != 0 && ctx->test->height != 0) {
925 cairo_surface_t *ref_image;
926 cairo_surface_t *test_image;
927 cairo_surface_t *diff_image;
928 buffer_diff_result_t result;
929 cairo_status_t diff_status;
931 if (target->finish_surface != NULL) {
932 #if HAVE_MEMFAULT
933 /* We need to re-enable faults as most meta-surface processing
934 * is done during cairo_surface_finish().
936 MEMFAULT_CLEAR_FAULTS ();
937 last_fault_count = MEMFAULT_COUNT_FAULTS ();
938 MEMFAULT_ENABLE_FAULTS ();
939 #endif
941 diff_status = target->finish_surface (surface);
943 #if HAVE_MEMFAULT
944 MEMFAULT_DISABLE_FAULTS ();
946 if (ctx->malloc_failure &&
947 MEMFAULT_COUNT_FAULTS () - last_fault_count > 0 &&
948 diff_status == CAIRO_STATUS_NO_MEMORY)
950 cairo_destroy (cr);
951 cairo_surface_destroy (surface);
952 if (target->cleanup)
953 target->cleanup (closure);
954 if (ctx->thread == 0) {
955 cairo_debug_reset_static_data ();
956 #if HAVE_FCFINI
957 FcFini ();
958 #endif
959 if (MEMFAULT_COUNT_LEAKS () > 0) {
960 MEMFAULT_PRINT_FAULTS ();
961 MEMFAULT_PRINT_LEAKS ();
965 goto REPEAT;
967 #endif
968 if (diff_status) {
969 cairo_test_log (ctx, "Error: Failed to finish surface: %s\n",
970 cairo_status_to_string (diff_status));
971 ret = CAIRO_TEST_FAILURE;
972 goto UNWIND_CAIRO;
976 if (ref_path == NULL) {
977 cairo_test_log (ctx, "Error: Cannot find reference image for %s\n",
978 base_name);
980 /* we may be running this test to generate reference images */
981 _xunlink (ctx, png_path);
982 test_image = target->get_image_surface (surface, 0,
983 ctx->test->width,
984 ctx->test->height);
985 diff_status = cairo_surface_write_to_png (test_image, png_path);
986 if (diff_status) {
987 cairo_test_log (ctx,
988 "Error: Failed to write output image: %s\n",
989 cairo_status_to_string (diff_status));
991 have_output = TRUE;
992 cairo_surface_destroy (test_image);
994 ret = CAIRO_TEST_FAILURE;
995 goto UNWIND_CAIRO;
998 if (target->file_extension != NULL) { /* compare vector surfaces */
999 xasprintf (&test_filename, "%s.out%s",
1000 base_path, target->file_extension);
1001 xasprintf (&pass_filename, "%s.pass%s",
1002 base_path, target->file_extension);
1003 xasprintf (&fail_filename, "%s.fail%s",
1004 base_path, target->file_extension);
1006 if (cairo_test_file_is_older (pass_filename, ref_path))
1007 _xunlink (ctx, pass_filename);
1008 if (cairo_test_file_is_older (fail_filename, ref_path))
1009 _xunlink (ctx, fail_filename);
1011 if (cairo_test_files_equal (test_filename, pass_filename)) {
1012 /* identical output as last known PASS */
1013 cairo_test_log (ctx, "Vector surface matches last pass.\n");
1014 have_output = TRUE;
1015 ret = CAIRO_TEST_SUCCESS;
1016 goto UNWIND_CAIRO;
1018 if (cairo_test_files_equal (test_filename, fail_filename)) {
1019 /* identical output as last known FAIL, fail */
1020 cairo_test_log (ctx, "Vector surface matches last fail.\n");
1021 have_result = TRUE; /* presume these were kept around as well */
1022 have_output = TRUE;
1023 ret = CAIRO_TEST_FAILURE;
1024 goto UNWIND_CAIRO;
1028 test_image = target->get_image_surface (surface, 0,
1029 ctx->test->width,
1030 ctx->test->height);
1031 if (cairo_surface_status (test_image)) {
1032 cairo_test_log (ctx, "Error: Failed to extract image: %s\n",
1033 cairo_status_to_string (cairo_surface_status (test_image)));
1034 cairo_surface_destroy (test_image);
1035 ret = CAIRO_TEST_FAILURE;
1036 goto UNWIND_CAIRO;
1039 _xunlink (ctx, png_path);
1040 diff_status = cairo_surface_write_to_png (test_image, png_path);
1041 if (diff_status) {
1042 cairo_test_log (ctx, "Error: Failed to write output image: %s\n",
1043 cairo_status_to_string (diff_status));
1044 cairo_surface_destroy (test_image);
1045 ret = CAIRO_TEST_FAILURE;
1046 goto UNWIND_CAIRO;
1048 have_output = TRUE;
1050 /* binary compare png files (no decompression) */
1051 if (target->file_extension == NULL) {
1052 xasprintf (&test_filename, "%s", png_path);
1053 xasprintf (&pass_filename, "%s.pass.png", base_path);
1054 xasprintf (&fail_filename, "%s.fail.png", base_path);
1056 if (cairo_test_files_equal (test_filename, pass_filename)) {
1057 /* identical output as last known PASS, pass */
1058 cairo_test_log (ctx, "PNG file exactly matches last pass.\n");
1059 cairo_surface_destroy (test_image);
1060 ret = CAIRO_TEST_SUCCESS;
1061 goto UNWIND_CAIRO;
1063 if (cairo_test_files_equal (png_path, ref_path)) {
1064 /* identical output as reference image */
1065 cairo_test_log (ctx, "PNG file exactly reference image.\n");
1066 cairo_surface_destroy (test_image);
1067 ret = CAIRO_TEST_SUCCESS;
1068 goto UNWIND_CAIRO;
1071 if (cairo_test_files_equal (test_filename, fail_filename)) {
1072 cairo_test_log (ctx, "PNG file exactly matches last fail.\n");
1073 /* identical output as last known FAIL, fail */
1074 have_result = TRUE; /* presume these were kept around as well */
1075 cairo_surface_destroy (test_image);
1076 ret = CAIRO_TEST_FAILURE;
1077 goto UNWIND_CAIRO;
1079 } else {
1080 if (cairo_test_files_equal (png_path, ref_path)) {
1081 cairo_test_log (ctx, "PNG file exactly matches reference image.\n");
1082 cairo_surface_destroy (test_image);
1083 ret = CAIRO_TEST_SUCCESS;
1084 goto UNWIND_CAIRO;
1088 ref_image = cairo_test_get_reference_image (ctx, ref_path,
1089 target->content == CAIRO_TEST_CONTENT_COLOR_ALPHA_FLATTENED);
1090 if (cairo_surface_status (ref_image)) {
1091 cairo_test_log (ctx, "Error: Cannot open reference image for %s: %s\n",
1092 ref_path,
1093 cairo_status_to_string (cairo_surface_status (ref_image)));
1094 cairo_surface_destroy (ref_image);
1095 cairo_surface_destroy (test_image);
1096 ret = CAIRO_TEST_FAILURE;
1097 goto UNWIND_CAIRO;
1100 diff_image = cairo_image_surface_create (CAIRO_FORMAT_ARGB32,
1101 ctx->test->width,
1102 ctx->test->height);
1104 diff_status = image_diff (ctx,
1105 test_image, ref_image,
1106 diff_image,
1107 &result);
1108 _xunlink (ctx, diff_path);
1109 if (diff_status) {
1110 cairo_test_log (ctx, "Error: Failed to compare images: %s\n",
1111 cairo_status_to_string (diff_status));
1112 ret = CAIRO_TEST_FAILURE;
1114 else if (result.pixels_changed &&
1115 result.max_diff > target->error_tolerance)
1117 ret = CAIRO_TEST_FAILURE;
1119 diff_status = cairo_surface_write_to_png (diff_image, diff_path);
1120 if (diff_status) {
1121 cairo_test_log (ctx, "Error: Failed to write differences image: %s\n",
1122 cairo_status_to_string (diff_status));
1123 } else
1124 have_result = TRUE;
1126 cairo_test_copy_file (test_filename, fail_filename);
1127 } else { /* success */
1128 cairo_test_copy_file (test_filename, pass_filename);
1131 cairo_surface_destroy (test_image);
1132 cairo_surface_destroy (diff_image);
1135 UNWIND_CAIRO:
1136 if (test_filename != NULL) {
1137 free (test_filename);
1138 test_filename = NULL;
1140 if (fail_filename != NULL) {
1141 free (fail_filename);
1142 fail_filename = NULL;
1144 if (pass_filename != NULL) {
1145 free (pass_filename);
1146 pass_filename = NULL;
1149 #if HAVE_MEMFAULT
1150 if (ret == CAIRO_TEST_FAILURE && ctx->expectation != CAIRO_TEST_FAILURE)
1151 MEMFAULT_PRINT_FAULTS ();
1152 #endif
1153 cairo_destroy (cr);
1154 UNWIND_SURFACE:
1155 cairo_surface_destroy (surface);
1157 if (target->cleanup)
1158 target->cleanup (closure);
1160 #if HAVE_MEMFAULT
1161 if (ctx->thread == 0) {
1162 cairo_debug_reset_static_data ();
1164 #if HAVE_FCFINI
1165 FcFini ();
1166 #endif
1168 if (MEMFAULT_COUNT_LEAKS () > 0) {
1169 if (ret != CAIRO_TEST_FAILURE ||
1170 ctx->expectation == CAIRO_TEST_FAILURE)
1172 MEMFAULT_PRINT_FAULTS ();
1174 MEMFAULT_PRINT_LEAKS ();
1178 if (ret == CAIRO_TEST_SUCCESS && --malloc_failure_iterations > 0)
1179 goto REPEAT;
1180 #endif
1182 if (ctx->thread == 0) {
1183 if (have_output)
1184 cairo_test_log (ctx, "OUTPUT: %s\n", png_path);
1186 if (have_result) {
1187 cairo_test_log (ctx,
1188 "REFERENCE: %s\nDIFFERENCE: %s\n",
1189 ref_path, diff_path);
1193 UNWIND_STRINGS:
1194 if (png_path)
1195 free (png_path);
1196 if (ref_path)
1197 free (ref_path);
1198 if (diff_path)
1199 free (diff_path);
1200 if (base_path)
1201 free (base_path);
1202 if (base_name)
1203 free (base_name);
1205 return ret;
1208 #if defined(HAVE_SIGNAL_H) && defined(HAVE_SETJMP_H)
1209 #include <signal.h>
1210 #include <setjmp.h>
1211 /* Used to catch crashes in a test, so that we report it as such and
1212 * continue testing, although one crasher may already have corrupted memory in
1213 * an nonrecoverable fashion. */
1214 static jmp_buf jmpbuf;
1216 static void
1217 segfault_handler (int signal)
1219 longjmp (jmpbuf, signal);
1221 #endif
1223 cairo_test_status_t
1224 _cairo_test_context_run_for_target (cairo_test_context_t *ctx,
1225 const cairo_boilerplate_target_t *target,
1226 cairo_bool_t similar,
1227 int dev_offset)
1229 cairo_test_status_t status;
1231 if (target->get_image_surface == NULL)
1232 return CAIRO_TEST_UNTESTED;
1234 if (similar && ! cairo_test_target_has_similar (ctx, target))
1235 return CAIRO_TEST_UNTESTED;
1237 cairo_test_log (ctx,
1238 "Testing %s with %s%s target (dev offset %d)\n",
1239 ctx->test_name,
1240 similar ? " (similar) " : "",
1241 target->name,
1242 dev_offset);
1244 if (ctx->thread == 0) {
1245 printf ("%s.%s.%s [%d]%s:\t", ctx->test_name, target->name,
1246 cairo_boilerplate_content_name (target->content),
1247 dev_offset,
1248 similar ? " (similar)": "");
1249 fflush (stdout);
1252 #if defined(HAVE_SIGNAL_H) && defined(HAVE_SETJMP_H)
1253 if (ctx->thread == 0 && ! RUNNING_ON_VALGRIND) {
1254 void (* volatile old_segfault_handler)(int);
1255 void (* volatile old_sigpipe_handler)(int);
1256 void (* volatile old_sigabrt_handler)(int);
1257 void (* volatile old_sigalrm_handler)(int);
1259 /* Set up a checkpoint to get back to in case of segfaults. */
1260 #ifdef SIGSEGV
1261 old_segfault_handler = signal (SIGSEGV, segfault_handler);
1262 #endif
1263 #ifdef SIGPIPE
1264 old_sigpipe_handler = signal (SIGPIPE, segfault_handler);
1265 #endif
1266 #ifdef SIGABRT
1267 old_sigabrt_handler = signal (SIGABRT, segfault_handler);
1268 #endif
1269 #ifdef SIGALRM
1270 old_sigalrm_handler = signal (SIGALRM, segfault_handler);
1271 #endif
1272 if (0 == setjmp (jmpbuf))
1273 status = cairo_test_for_target (ctx, target, dev_offset, similar);
1274 else
1275 status = CAIRO_TEST_CRASHED;
1276 #ifdef SIGSEGV
1277 signal (SIGSEGV, old_segfault_handler);
1278 #endif
1279 #ifdef SIGPIPE
1280 signal (SIGPIPE, old_sigpipe_handler);
1281 #endif
1282 #ifdef SIGABRT
1283 signal (SIGABRT, old_sigabrt_handler);
1284 #endif
1285 #ifdef SIGALRM
1286 signal (SIGALRM, old_sigalrm_handler);
1287 #endif
1288 } else {
1289 status = cairo_test_for_target (ctx, target, dev_offset, similar);
1291 #else
1292 status = cairo_test_for_target (ctx, target, dev_offset, similar);
1293 #endif
1295 if (ctx->thread == 0) {
1296 cairo_test_log (ctx,
1297 "TEST: %s TARGET: %s FORMAT: %s OFFSET: %d SIMILAR: %d RESULT: ",
1298 ctx->test_name, target->name,
1299 cairo_boilerplate_content_name (target->content),
1300 dev_offset, similar);
1301 switch (status) {
1302 case CAIRO_TEST_SUCCESS:
1303 printf ("PASS\n");
1304 cairo_test_log (ctx, "PASS\n");
1305 break;
1306 case CAIRO_TEST_UNTESTED:
1307 printf ("UNTESTED\n");
1308 cairo_test_log (ctx, "UNTESTED\n");
1309 break;
1310 case CAIRO_TEST_CRASHED:
1311 if (print_fail_on_stdout && ctx->thread == 0) {
1312 printf ("!!!CRASHED!!!\n");
1313 } else {
1314 /* eat the test name */
1315 printf ("\r");
1316 fflush (stdout);
1318 cairo_test_log (ctx, "CRASHED\n");
1319 fprintf (stderr, "%s.%s.%s [%d]%s:\t%s!!!CRASHED!!!%s\n",
1320 ctx->test_name, target->name,
1321 cairo_boilerplate_content_name (target->content), dev_offset, similar ? " (similar)" : "",
1322 fail_face, normal_face);
1323 break;
1324 default:
1325 case CAIRO_TEST_NO_MEMORY:
1326 case CAIRO_TEST_FAILURE:
1327 if (ctx->expectation == CAIRO_TEST_FAILURE) {
1328 if (print_fail_on_stdout && ctx->thread == 0) {
1329 printf ("XFAIL\n");
1330 } else {
1331 /* eat the test name */
1332 printf ("\r");
1333 fflush (stdout);
1335 fprintf (stderr, "%s.%s.%s [%d]%s:\t%sXFAIL%s\n",
1336 ctx->test_name, target->name,
1337 cairo_boilerplate_content_name (target->content), dev_offset, similar ? " (similar)" : "",
1338 xfail_face, normal_face);
1339 cairo_test_log (ctx, "XFAIL\n");
1340 } else {
1341 if (print_fail_on_stdout && ctx->thread == 0) {
1342 printf ("FAIL\n");
1343 } else {
1344 /* eat the test name */
1345 printf ("\r");
1346 fflush (stdout);
1348 fprintf (stderr, "%s.%s.%s [%d]%s:\t%sFAIL%s\n",
1349 ctx->test_name, target->name,
1350 cairo_boilerplate_content_name (target->content), dev_offset, similar ? " (similar)" : "",
1351 fail_face, normal_face);
1352 cairo_test_log (ctx, "FAIL\n");
1354 break;
1356 fflush (stdout);
1357 } else {
1358 #if _POSIX_THREAD_SAFE_FUNCTIONS
1359 flockfile (stdout);
1360 #endif
1361 printf ("%s.%s.%s %d [%d]:\t",
1362 ctx->test_name, target->name,
1363 cairo_boilerplate_content_name (target->content),
1364 ctx->thread,
1365 dev_offset);
1366 switch (status) {
1367 case CAIRO_TEST_SUCCESS:
1368 printf ("PASS\n");
1369 break;
1370 case CAIRO_TEST_UNTESTED:
1371 printf ("UNTESTED\n");
1372 break;
1373 case CAIRO_TEST_CRASHED:
1374 printf ("!!!CRASHED!!!\n");
1375 break;
1376 default:
1377 case CAIRO_TEST_NO_MEMORY:
1378 case CAIRO_TEST_FAILURE:
1379 if (ctx->expectation == CAIRO_TEST_FAILURE) {
1380 printf ("XFAIL\n");
1381 } else {
1382 printf ("FAIL\n");
1384 break;
1387 fflush (stdout);
1388 #if _POSIX_THREAD_SAFE_FUNCTIONS
1389 funlockfile (stdout);
1390 #endif
1393 return status;
1396 cairo_test_status_t
1397 _cairo_test_context_run (cairo_test_context_t *ctx)
1399 size_t i, j;
1400 cairo_test_status_t ret;
1402 ret = CAIRO_TEST_UNTESTED;
1403 if (ctx->test->preamble != NULL)
1404 ret = ctx->test->preamble (ctx);
1406 if (ctx->test->draw == NULL)
1407 return ret;
1409 /* The intended logic here is that we return overall SUCCESS
1410 * iff. there is at least one tested backend and that all tested
1411 * backends return SUCCESS, OR, there's backends were manually
1412 * limited, and none were tested.
1413 * In other words:
1415 * if backends limited and no backend tested
1416 * -> SUCCESS
1417 * else if any backend not SUCCESS
1418 * -> FAILURE
1419 * else if all backends UNTESTED
1420 * -> FAILURE
1421 * else (== some backend SUCCESS)
1422 * -> SUCCESS
1424 * Also, on a crash, run no further tests.
1426 for (i = 0; i < ctx->num_targets && ret != CAIRO_TEST_CRASHED; i++) {
1427 const cairo_boilerplate_target_t *target = ctx->targets_to_test[(i + ctx->thread) % ctx->num_targets];
1429 for (j = 0; j < NUM_DEVICE_OFFSETS; j++) {
1430 int dev_offset = ((j + ctx->thread) % NUM_DEVICE_OFFSETS) * 25;
1431 int similar, has_similar;
1433 has_similar = cairo_test_target_has_similar (ctx, target);
1434 for (similar = 0; similar <= has_similar ; similar++) {
1435 cairo_status_t status;
1437 status = _cairo_test_context_run_for_target (ctx,
1438 target,
1439 similar,
1440 dev_offset);
1441 if (ret == CAIRO_TEST_UNTESTED)
1442 ret = status;
1447 return ret;
1450 #if HAVE_PTHREAD_H
1451 typedef struct _cairo_test_thread {
1452 pthread_t thread;
1453 cairo_test_context_t *ctx;
1454 size_t id;
1455 } cairo_test_thread_t;
1457 static void *
1458 cairo_test_run_threaded (void *closure)
1460 cairo_test_thread_t *arg = closure;
1461 cairo_test_context_t ctx;
1462 cairo_test_status_t ret;
1464 cairo_test_init_thread (&ctx, arg->ctx, arg->id);
1466 ret = _cairo_test_context_run (&ctx);
1468 cairo_test_fini (&ctx);
1470 return (void *) ret;
1472 #endif
1475 static cairo_test_status_t
1476 cairo_test_expecting (const cairo_test_t *test,
1477 cairo_test_status_t expectation)
1479 cairo_test_context_t ctx;
1480 cairo_test_status_t ret = CAIRO_TEST_SUCCESS;
1481 size_t num_threads;
1483 _cairo_test_init (&ctx, NULL, test, test->name, expectation);
1484 printf ("%s\n", test->description);
1486 if (expectation == CAIRO_TEST_FAILURE)
1487 printf ("Expecting failure\n");
1489 #if HAVE_PTHREAD_H
1490 num_threads = 0;
1491 if (getenv ("CAIRO_TEST_NUM_THREADS"))
1492 num_threads = atoi (getenv ("CAIRO_TEST_NUM_THREADS"));
1493 if (num_threads > 1) {
1494 cairo_test_thread_t *threads;
1495 size_t n;
1497 threads = xmalloc (sizeof (cairo_test_thread_t) * num_threads);
1498 for (n = 0; n < num_threads; n++) {
1499 threads[n].ctx = &ctx;
1500 threads[n].id = n + 1;
1501 pthread_create (&threads[n].thread, NULL,
1502 cairo_test_run_threaded, &threads[n]);
1504 for (n = 0; n < num_threads; n++) {
1505 void *tmp;
1506 pthread_join (threads[n].thread, &tmp);
1507 if (ret == CAIRO_TEST_SUCCESS)
1508 ret = (cairo_test_status_t) tmp;
1510 free (threads);
1513 if (ret == CAIRO_TEST_SUCCESS)
1514 #endif
1515 ret = _cairo_test_context_run (&ctx);
1517 if (ret != CAIRO_TEST_SUCCESS)
1518 printf ("Check %s%s out for more information.\n", ctx.test_name, CAIRO_TEST_LOG_SUFFIX);
1520 /* if the set of targets to test was limited using CAIRO_TEST_TARGET, we
1521 * behave slightly differently, to ensure that limiting the targets does
1522 * not increase the number of tests failing. */
1523 if (ctx.limited_targets) {
1524 /* if all passed, but expecting failure, return failure to not
1525 * trigger an XPASS failure */
1526 if (expectation == CAIRO_TEST_FAILURE && ret == CAIRO_TEST_SUCCESS) {
1527 printf ("All tested backends passed, but tested targets are manually limited\n"
1528 "and the test suite expects this test to fail for at least one target.\n"
1529 "Intentionally failing the test, to not fail the suite.\n");
1530 ret = CAIRO_TEST_FAILURE;
1534 cairo_test_fini (&ctx);
1536 return ret;
1539 cairo_test_status_t
1540 cairo_test (const cairo_test_t *test)
1542 #ifdef _MSC_VER
1543 /* We don't want an assert dialog, we want stderr */
1544 _CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_FILE);
1545 _CrtSetReportFile(_CRT_ERROR, _CRTDBG_FILE_STDERR);
1546 #endif
1548 return cairo_test_expecting (test, CAIRO_TEST_SUCCESS);
1551 const cairo_test_context_t *
1552 cairo_test_get_context (cairo_t *cr)
1554 return cairo_get_user_data (cr, &_cairo_test_context_key);
1557 cairo_surface_t *
1558 cairo_test_create_surface_from_png (const cairo_test_context_t *ctx,
1559 const char *filename)
1561 cairo_surface_t *image;
1562 cairo_status_t status;
1564 image = cairo_image_surface_create_from_png (filename);
1565 status = cairo_surface_status (image);
1566 if (status == CAIRO_STATUS_FILE_NOT_FOUND) {
1567 /* expect not found when running with srcdir != builddir
1568 * such as when 'make distcheck' is run
1570 if (ctx->srcdir) {
1571 char *srcdir_filename;
1572 xasprintf (&srcdir_filename, "%s/%s", ctx->srcdir, filename);
1573 cairo_surface_destroy (image);
1574 image = cairo_image_surface_create_from_png (srcdir_filename);
1575 free (srcdir_filename);
1579 return image;
1582 cairo_pattern_t *
1583 cairo_test_create_pattern_from_png (const cairo_test_context_t *ctx,
1584 const char *filename)
1586 cairo_surface_t *image;
1587 cairo_pattern_t *pattern;
1589 image = cairo_test_create_surface_from_png (ctx, filename);
1591 pattern = cairo_pattern_create_for_surface (image);
1593 cairo_pattern_set_extend (pattern, CAIRO_EXTEND_REPEAT);
1595 cairo_surface_destroy (image);
1597 return pattern;
1600 static cairo_surface_t *
1601 _draw_check (int width, int height)
1603 cairo_surface_t *surface;
1604 cairo_t *cr;
1606 surface = cairo_image_surface_create (CAIRO_FORMAT_RGB24, 12, 12);
1607 cr = cairo_create (surface);
1608 cairo_surface_destroy (surface);
1610 cairo_set_source_rgb (cr, 0.75, 0.75, 0.75); /* light gray */
1611 cairo_paint (cr);
1613 cairo_set_source_rgb (cr, 0.25, 0.25, 0.25); /* dark gray */
1614 cairo_rectangle (cr, width / 2, 0, width / 2, height / 2);
1615 cairo_rectangle (cr, 0, height / 2, width / 2, height / 2);
1616 cairo_fill (cr);
1618 surface = cairo_surface_reference (cairo_get_target (cr));
1619 cairo_destroy (cr);
1621 return surface;
1624 void
1625 cairo_test_paint_checkered (cairo_t *cr)
1627 cairo_surface_t *check;
1629 check = _draw_check (12, 12);
1631 cairo_save (cr);
1632 cairo_set_source_surface (cr, check, 0, 0);
1633 cairo_surface_destroy (check);
1635 cairo_pattern_set_filter (cairo_get_source (cr), CAIRO_FILTER_NEAREST);
1636 cairo_pattern_set_extend (cairo_get_source (cr), CAIRO_EXTEND_REPEAT);
1637 cairo_paint (cr);
1639 cairo_restore (cr);
1642 cairo_bool_t
1643 cairo_test_is_target_enabled (const cairo_test_context_t *ctx,
1644 const char *target)
1646 size_t i;
1648 for (i = 0; i < ctx->num_targets; i++) {
1649 const cairo_boilerplate_target_t *t = ctx->targets_to_test[i];
1650 if (strcmp (t->name, target) == 0) {
1651 /* XXX ask the target whether is it possible to run?
1652 * e.g. the xlib backend could check whether it is able to connect
1653 * to the Display.
1655 return t->get_image_surface != NULL;
1659 return FALSE;
1662 cairo_bool_t
1663 cairo_test_malloc_failure (const cairo_test_context_t *ctx,
1664 cairo_status_t status)
1666 if (! ctx->malloc_failure)
1667 return FALSE;
1669 if (status != CAIRO_STATUS_NO_MEMORY)
1670 return FALSE;
1672 #if HAVE_MEMFAULT
1674 int n_faults;
1676 /* prevent infinite loops... */
1677 n_faults = MEMFAULT_COUNT_FAULTS ();
1678 if (n_faults == ctx->last_fault_count)
1679 return FALSE;
1681 ((cairo_test_context_t *) ctx)->last_fault_count = n_faults;
1683 #endif
1685 return TRUE;
1688 cairo_test_status_t
1689 cairo_test_status_from_status (const cairo_test_context_t *ctx,
1690 cairo_status_t status)
1692 if (status == CAIRO_STATUS_SUCCESS)
1693 return CAIRO_TEST_SUCCESS;
1695 if (cairo_test_malloc_failure (ctx, status))
1696 return CAIRO_TEST_NO_MEMORY;
1698 return CAIRO_TEST_FAILURE;