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 */
38 #if HAVE_FEENABLEEXCEPT
48 #include <fontconfig/fontconfig.h>
50 #if CAIRO_HAS_REAL_PTHREAD
60 #define RUNNING_ON_VALGRIND 0
70 #include "cairo-test-private.h"
72 #include "buffer-diff.h"
90 #define ARRAY_SIZE(A) (sizeof(A) / sizeof (A[0]))
93 #if ! HAVE_ALARM || ! defined(SIGALRM)
97 static const cairo_user_data_key_t _cairo_test_context_key;
100 _xunlink (const cairo_test_context_t *ctx, const char *pathname);
102 static const char *fail_face = "", *xfail_face="", *normal_face = "";
103 static cairo_bool_t print_fail_on_stdout;
104 static int cairo_test_timeout = 60;
106 #define NUM_DEVICE_OFFSETS 2
109 _cairo_test_mkdir (const char *path)
113 #elif HAVE_MKDIR == 1
114 if (mkdir (path) == 0)
116 #elif HAVE_MKDIR == 2
117 if (mkdir (path, 0770) == 0)
120 #error Bad value for HAVE_MKDIR
123 return errno == EEXIST;
127 _cairo_test_fixup_name (const char *original)
131 s = name = xstrdup (original);
132 while ((s = strchr (s, '_')) != NULL)
139 cairo_test_get_name (const cairo_test_t *test)
141 return _cairo_test_fixup_name (test->name);
145 _cairo_test_init (cairo_test_context_t *ctx,
146 const cairo_test_context_t *parent,
147 const cairo_test_t *test,
148 const char *test_name,
153 MF (MEMFAULT_DISABLE_FAULTS ());
155 #if HAVE_FEENABLEEXCEPT
156 feenableexcept (FE_DIVBYZERO | FE_INVALID | FE_OVERFLOW);
160 ctx->test_name = _cairo_test_fixup_name (test_name);
161 ctx->output = output;
163 _cairo_test_mkdir (ctx->output);
165 ctx->malloc_failure = 0;
167 if (getenv ("CAIRO_TEST_MALLOC_FAILURE"))
168 ctx->malloc_failure = atoi (getenv ("CAIRO_TEST_MALLOC_FAILURE"));
169 if (ctx->malloc_failure && ! RUNNING_ON_MEMFAULT ())
170 ctx->malloc_failure = 0;
173 ctx->timeout = cairo_test_timeout;
174 if (getenv ("CAIRO_TEST_TIMEOUT"))
175 ctx->timeout = atoi (getenv ("CAIRO_TEST_TIMEOUT"));
177 xasprintf (&log_name, "%s/%s%s", ctx->output, ctx->test_name, CAIRO_TEST_LOG_SUFFIX);
178 _xunlink (NULL, log_name);
180 ctx->log_file = fopen (log_name, "a");
181 if (ctx->log_file == NULL) {
182 fprintf (stderr, "Error opening log file: %s\n", log_name);
183 ctx->log_file = stderr;
187 ctx->ref_name = NULL;
188 ctx->ref_image = NULL;
189 ctx->ref_image_flattened = NULL;
191 if (parent != NULL) {
192 ctx->targets_to_test = parent->targets_to_test;
193 ctx->num_targets = parent->num_targets;
194 ctx->limited_targets = parent->limited_targets;
195 ctx->own_targets = FALSE;
197 ctx->srcdir = parent->srcdir;
198 ctx->refdir = parent->refdir;
201 cairo_bool_t tmp_limited_targets;
203 ctx->targets_to_test = cairo_boilerplate_get_targets (&tmp_num_targets, &tmp_limited_targets);
204 ctx->num_targets = tmp_num_targets;
205 ctx->limited_targets = tmp_limited_targets;
206 ctx->own_targets = TRUE;
208 ctx->srcdir = getenv ("srcdir");
209 if (ctx->srcdir == NULL)
212 ctx->refdir = getenv ("CAIRO_REF_DIR");
216 if (*fail_face == '\0' && isatty (2)) {
217 fail_face = "\033[41;37;1m";
218 xfail_face = "\033[43;37;1m";
219 normal_face = "\033[m";
221 print_fail_on_stdout = FALSE;
225 printf ("\nTESTING %s\n", ctx->test_name);
229 _cairo_test_context_init_for_test (cairo_test_context_t *ctx,
230 const cairo_test_context_t *parent,
231 const cairo_test_t *test)
233 _cairo_test_init (ctx, parent, test, test->name, CAIRO_TEST_OUTPUT_DIR);
237 cairo_test_init (cairo_test_context_t *ctx,
238 const char *test_name,
241 _cairo_test_init (ctx, NULL, NULL, test_name, output);
245 cairo_test_fini (cairo_test_context_t *ctx)
247 if (ctx->log_file == NULL)
250 if (ctx->log_file != stderr)
251 fclose (ctx->log_file);
252 ctx->log_file = NULL;
254 free (ctx->ref_name);
255 cairo_surface_destroy (ctx->ref_image);
256 cairo_surface_destroy (ctx->ref_image_flattened);
258 if (ctx->test_name != NULL)
259 free ((char *) ctx->test_name);
261 if (ctx->own_targets)
262 cairo_boilerplate_free_targets (ctx->targets_to_test);
264 cairo_boilerplate_fini ();
266 cairo_debug_reset_static_data ();
273 cairo_test_logv (const cairo_test_context_t *ctx,
274 const char *fmt, va_list va)
276 FILE *file = ctx && ctx->log_file ? ctx->log_file : stderr;
277 vfprintf (file, fmt, va);
281 cairo_test_log (const cairo_test_context_t *ctx, const char *fmt, ...)
286 cairo_test_logv (ctx, fmt, va);
291 _xunlink (const cairo_test_context_t *ctx, const char *pathname)
293 if (unlink (pathname) < 0 && errno != ENOENT) {
294 cairo_test_log (ctx, "Error: Cannot remove %s: %s\n",
295 pathname, strerror (errno));
301 cairo_test_reference_filename (const cairo_test_context_t *ctx,
302 const char *base_name,
303 const char *test_name,
304 const char *target_name,
305 const char *base_target_name,
308 const char *extension)
310 char *ref_name = NULL;
312 /* First look for a previous build for comparison. */
313 if (ctx->refdir != NULL) {
314 xasprintf (&ref_name, "%s/%s%s%s",
319 if (access (ref_name, F_OK) != 0)
325 if (target_name != NULL) {
326 /* Next look for a target/format-specific reference image. */
327 xasprintf (&ref_name, "%s/reference/%s.%s.%s%s%s",
334 if (access (ref_name, F_OK) != 0)
339 /* Next, look for target-specific reference image. */
340 xasprintf (&ref_name, "%s/reference/%s.%s%s%s",
346 if (access (ref_name, F_OK) != 0)
352 if (base_target_name != NULL) {
353 /* Next look for a base/format-specific reference image. */
354 xasprintf (&ref_name, "%s/reference/%s.%s.%s%s%s",
361 if (access (ref_name, F_OK) != 0)
366 /* Next, look for base-specific reference image. */
367 xasprintf (&ref_name, "%s/reference/%s.%s%s%s",
373 if (access (ref_name, F_OK) != 0)
379 /* Next, look for format-specific reference image. */
380 xasprintf (&ref_name, "%s/reference/%s.%s%s%s",
386 if (access (ref_name, F_OK) != 0)
391 /* Finally, look for the standard reference image. */
392 xasprintf (&ref_name, "%s/reference/%s%s%s", ctx->srcdir,
396 if (access (ref_name, F_OK) != 0)
408 cairo_test_target_has_similar (const cairo_test_context_t *ctx,
409 const cairo_boilerplate_target_t *target)
411 cairo_surface_t *surface;
412 cairo_test_similar_t has_similar;
414 cairo_surface_t *similar;
415 cairo_status_t status;
419 /* ignore image intermediate targets */
420 if (target->expected_type == CAIRO_SURFACE_TYPE_IMAGE)
423 if (getenv ("CAIRO_TEST_IGNORE_SIMILAR"))
426 xasprintf (&path, "%s/%s",
427 _cairo_test_mkdir (ctx->output) ? ctx->output : ".",
430 has_similar = DIRECT;
433 surface = (target->create_surface) (path,
437 ctx->test->width + 25 * NUM_DEVICE_OFFSETS,
438 ctx->test->height + 25 * NUM_DEVICE_OFFSETS,
439 CAIRO_BOILERPLATE_MODE_TEST,
443 } while (cairo_test_malloc_failure (ctx, cairo_surface_status (surface)));
445 if (cairo_surface_status (surface))
448 cr = cairo_create (surface);
449 cairo_push_group_with_content (cr,
450 cairo_boilerplate_content (target->content));
451 similar = cairo_get_group_target (cr);
452 status = cairo_surface_status (similar);
454 if (cairo_surface_get_type (similar) == cairo_surface_get_type (surface))
455 has_similar = SIMILAR;
457 has_similar = DIRECT;
460 cairo_surface_destroy (surface);
463 target->cleanup (closure);
464 } while (! has_similar && cairo_test_malloc_failure (ctx, status));
471 static cairo_surface_t *
472 _cairo_test_flatten_reference_image (cairo_test_context_t *ctx,
473 cairo_bool_t flatten)
475 cairo_surface_t *surface;
479 return ctx->ref_image;
481 if (ctx->ref_image_flattened != NULL)
482 return ctx->ref_image_flattened;
484 surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32,
485 cairo_image_surface_get_width (ctx->ref_image),
486 cairo_image_surface_get_height (ctx->ref_image));
487 cr = cairo_create (surface);
488 cairo_surface_destroy (surface);
490 cairo_set_source_rgb (cr, 1, 1, 1);
493 cairo_set_source_surface (cr, ctx->ref_image, 0, 0);
496 surface = cairo_surface_reference (cairo_get_target (cr));
499 if (cairo_surface_status (surface) == CAIRO_STATUS_SUCCESS)
500 ctx->ref_image_flattened = surface;
505 cairo_test_get_reference_image (cairo_test_context_t *ctx,
506 const char *filename,
507 cairo_bool_t flatten)
509 cairo_surface_t *surface;
511 if (ctx->ref_name != NULL) {
512 if (strcmp (ctx->ref_name, filename) == 0)
513 return _cairo_test_flatten_reference_image (ctx, flatten);
515 cairo_surface_destroy (ctx->ref_image);
516 ctx->ref_image = NULL;
518 cairo_surface_destroy (ctx->ref_image_flattened);
519 ctx->ref_image_flattened = NULL;
521 free (ctx->ref_name);
522 ctx->ref_name = NULL;
525 surface = cairo_image_surface_create_from_png (filename);
526 if (cairo_surface_status (surface))
529 ctx->ref_name = xstrdup (filename);
530 ctx->ref_image = surface;
531 return _cairo_test_flatten_reference_image (ctx, flatten);
535 cairo_test_file_is_older (const char *filename,
536 char **ref_filenames,
537 int num_ref_filenames)
542 if (stat (filename, &st) < 0)
545 while (num_ref_filenames--) {
547 char *ref_filename = *ref_filenames++;
549 if (ref_filename == NULL)
552 if (stat (ref_filename++, &ref) < 0)
555 if (st.st_mtime <= ref.st_mtime)
564 cairo_test_files_equal (const char *test_filename,
565 const char *pass_filename)
570 if (test_filename == NULL || pass_filename == NULL)
573 test = fopen (test_filename, "rb");
577 pass = fopen (pass_filename, "rb");
583 /* as simple as it gets */
589 } while (t != EOF && p != EOF);
594 return t == p; /* both EOF */
598 cairo_test_copy_file (const char *src_filename,
599 const char *dst_filename)
605 if (link (src_filename, dst_filename) == 0)
608 unlink (dst_filename);
611 src = fopen (src_filename, "rb");
615 dst = fopen (dst_filename, "wb");
621 /* as simple as it gets */
622 while ((c = getc (src)) != EOF)
631 static cairo_test_status_t
632 cairo_test_for_target (cairo_test_context_t *ctx,
633 const cairo_boilerplate_target_t *target,
635 cairo_bool_t similar)
637 cairo_test_status_t status;
638 cairo_surface_t *surface = NULL;
640 const char *empty_str = "";
642 char *base_name, *base_path;
644 char *ref_path = NULL, *ref_png_path, *cmp_png_path = NULL;
645 char *new_path = NULL, *new_png_path;
646 char *xfail_path = NULL, *xfail_png_path;
647 char *base_ref_png_path;
648 char *base_new_png_path;
649 char *base_xfail_png_path;
651 char *test_filename = NULL, *pass_filename = NULL, *fail_filename = NULL;
652 cairo_test_status_t ret;
653 cairo_content_t expected_content;
654 cairo_font_options_t *font_options;
656 cairo_bool_t have_output = FALSE;
657 cairo_bool_t have_result = FALSE;
659 double width, height;
660 cairo_bool_t have_output_dir;
662 int malloc_failure_iterations = ctx->malloc_failure;
663 int last_fault_count = 0;
666 /* Get the strings ready that we'll need. */
667 format = cairo_boilerplate_content_name (target->content);
669 xasprintf (&offset_str, ".%d", dev_offset);
671 offset_str = (char *) empty_str;
673 xasprintf (&base_name, "%s.%s.%s%s%s",
677 similar ? ".similar" : "",
680 if (offset_str != empty_str)
683 ref_png_path = cairo_test_reference_filename (ctx,
689 CAIRO_TEST_REF_SUFFIX,
690 CAIRO_TEST_PNG_EXTENSION);
691 new_png_path = cairo_test_reference_filename (ctx,
697 CAIRO_TEST_NEW_SUFFIX,
698 CAIRO_TEST_PNG_EXTENSION);
699 xfail_png_path = cairo_test_reference_filename (ctx,
705 CAIRO_TEST_XFAIL_SUFFIX,
706 CAIRO_TEST_PNG_EXTENSION);
708 base_ref_png_path = cairo_test_reference_filename (ctx,
713 CAIRO_TEST_REF_SUFFIX,
714 CAIRO_TEST_PNG_EXTENSION);
715 base_new_png_path = cairo_test_reference_filename (ctx,
720 CAIRO_TEST_NEW_SUFFIX,
721 CAIRO_TEST_PNG_EXTENSION);
722 base_xfail_png_path = cairo_test_reference_filename (ctx,
727 CAIRO_TEST_XFAIL_SUFFIX,
728 CAIRO_TEST_PNG_EXTENSION);
730 if (target->file_extension != NULL) {
731 ref_path = cairo_test_reference_filename (ctx,
737 CAIRO_TEST_REF_SUFFIX,
738 target->file_extension);
739 new_path = cairo_test_reference_filename (ctx,
745 CAIRO_TEST_NEW_SUFFIX,
746 target->file_extension);
747 xfail_path = cairo_test_reference_filename (ctx,
753 CAIRO_TEST_XFAIL_SUFFIX,
754 target->file_extension);
757 have_output_dir = _cairo_test_mkdir (ctx->output);
758 xasprintf (&base_path, "%s/%s",
759 have_output_dir ? ctx->output : ".",
761 xasprintf (&out_png_path, "%s" CAIRO_TEST_OUT_PNG, base_path);
762 xasprintf (&diff_png_path, "%s" CAIRO_TEST_DIFF_PNG, base_path);
764 if (ctx->test->requirements != NULL) {
765 const char *required;
767 required = target->is_vector ? "target=raster" : "target=vector";
768 if (strstr (ctx->test->requirements, required) != NULL) {
769 cairo_test_log (ctx, "Error: Skipping for %s target %s\n",
770 target->is_vector ? "vector" : "raster",
772 ret = CAIRO_TEST_UNTESTED;
776 required = target->is_recording ? "target=!recording" : "target=recording";
777 if (strstr (ctx->test->requirements, required) != NULL) {
778 cairo_test_log (ctx, "Error: Skipping for %s target %s\n",
779 target->is_recording ? "recording" : "non-recording",
781 ret = CAIRO_TEST_UNTESTED;
786 width = ctx->test->width;
787 height = ctx->test->height;
788 if (width && height) {
790 height += dev_offset;
795 MEMFAULT_CLEAR_FAULTS ();
796 MEMFAULT_RESET_LEAKS ();
797 ctx->last_fault_count = 0;
798 last_fault_count = MEMFAULT_COUNT_FAULTS ();
800 /* Pre-initialise fontconfig so that the configuration is loaded without
801 * malloc failures (our primary goal is to test cairo fault tolerance).
807 MEMFAULT_ENABLE_FAULTS ();
812 /* Run the actual drawing code. */
813 ret = CAIRO_TEST_SUCCESS;
814 surface = (target->create_surface) (base_path,
817 ctx->test->width + 25 * NUM_DEVICE_OFFSETS,
818 ctx->test->height + 25 * NUM_DEVICE_OFFSETS,
819 CAIRO_BOILERPLATE_MODE_TEST,
821 if (surface == NULL) {
822 cairo_test_log (ctx, "Error: Failed to set %s target\n", target->name);
823 ret = CAIRO_TEST_UNTESTED;
828 if (ctx->malloc_failure &&
829 MEMFAULT_COUNT_FAULTS () - last_fault_count > 0 &&
830 cairo_surface_status (surface) == CAIRO_STATUS_NO_MEMORY)
836 if (cairo_surface_status (surface)) {
837 MF (MEMFAULT_PRINT_FAULTS ());
838 cairo_test_log (ctx, "Error: Created an error surface: %s\n",
839 cairo_status_to_string (cairo_surface_status (surface)));
840 ret = CAIRO_TEST_FAILURE;
844 /* Check that we created a surface of the expected type. */
845 if (cairo_surface_get_type (surface) != target->expected_type) {
846 MF (MEMFAULT_PRINT_FAULTS ());
847 cairo_test_log (ctx, "Error: Created surface is of type %d (expected %d)\n",
848 cairo_surface_get_type (surface), target->expected_type);
849 ret = CAIRO_TEST_UNTESTED;
853 /* Check that we created a surface of the expected content,
854 * (ignore the artificial CAIRO_TEST_CONTENT_COLOR_ALPHA_FLATTENED value).
856 expected_content = cairo_boilerplate_content (target->content);
858 if (cairo_surface_get_content (surface) != expected_content) {
859 MF (MEMFAULT_PRINT_FAULTS ());
860 cairo_test_log (ctx, "Error: Created surface has content %d (expected %d)\n",
861 cairo_surface_get_content (surface), expected_content);
862 ret = CAIRO_TEST_FAILURE;
866 if (cairo_surface_set_user_data (surface,
867 &cairo_boilerplate_output_basename_key,
872 cairo_surface_destroy (surface);
875 target->cleanup (closure);
879 ret = CAIRO_TEST_FAILURE;
884 cairo_surface_set_device_offset (surface, dev_offset, dev_offset);
886 cr = cairo_create (surface);
887 if (cairo_set_user_data (cr, &_cairo_test_context_key, (void*) ctx, NULL)) {
890 cairo_surface_destroy (surface);
893 target->cleanup (closure);
897 ret = CAIRO_TEST_FAILURE;
903 cairo_push_group_with_content (cr, expected_content);
905 /* Clear to transparent (or black) depending on whether the target
906 * surface supports alpha. */
908 cairo_set_operator (cr, CAIRO_OPERATOR_CLEAR);
912 /* Set all components of font_options to avoid backend differences
913 * and reduce number of needed reference images. */
914 font_options = cairo_font_options_create ();
915 cairo_font_options_set_hint_style (font_options, CAIRO_HINT_STYLE_NONE);
916 cairo_font_options_set_hint_metrics (font_options, CAIRO_HINT_METRICS_ON);
917 cairo_font_options_set_antialias (font_options, CAIRO_ANTIALIAS_GRAY);
918 cairo_set_font_options (cr, font_options);
919 cairo_font_options_destroy (font_options);
922 alarm (ctx->timeout);
923 status = (ctx->test->draw) (cr, ctx->test->width, ctx->test->height);
928 cairo_pop_group_to_source (cr);
929 cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
934 MEMFAULT_DISABLE_FAULTS ();
936 /* repeat test after malloc failure injection */
937 if (ctx->malloc_failure &&
938 MEMFAULT_COUNT_FAULTS () - last_fault_count > 0 &&
939 (status == CAIRO_TEST_NO_MEMORY ||
940 cairo_status (cr) == CAIRO_STATUS_NO_MEMORY ||
941 cairo_surface_status (surface) == CAIRO_STATUS_NO_MEMORY))
944 cairo_surface_destroy (surface);
946 target->cleanup (closure);
947 cairo_debug_reset_static_data ();
951 if (MEMFAULT_COUNT_LEAKS () > 0) {
952 MEMFAULT_PRINT_FAULTS ();
953 MEMFAULT_PRINT_LEAKS ();
960 /* Then, check all the different ways it could fail. */
962 cairo_test_log (ctx, "Error: Function under test failed\n");
968 if (MEMFAULT_COUNT_FAULTS () - last_fault_count > 0 &&
969 MEMFAULT_HAS_FAULTS ())
971 VALGRIND_PRINTF ("Unreported memfaults...");
972 MEMFAULT_PRINT_FAULTS ();
976 if (target->finish_surface != NULL) {
978 /* We need to re-enable faults as most recording-surface processing
979 * is done during cairo_surface_finish().
981 MEMFAULT_CLEAR_FAULTS ();
982 last_fault_count = MEMFAULT_COUNT_FAULTS ();
983 MEMFAULT_ENABLE_FAULTS ();
986 /* also check for infinite loops whilst replaying */
987 alarm (ctx->timeout);
988 status = target->finish_surface (surface);
992 MEMFAULT_DISABLE_FAULTS ();
994 if (ctx->malloc_failure &&
995 MEMFAULT_COUNT_FAULTS () - last_fault_count > 0 &&
996 status == CAIRO_STATUS_NO_MEMORY)
999 cairo_surface_destroy (surface);
1000 if (target->cleanup)
1001 target->cleanup (closure);
1002 cairo_debug_reset_static_data ();
1006 if (MEMFAULT_COUNT_LEAKS () > 0) {
1007 MEMFAULT_PRINT_FAULTS ();
1008 MEMFAULT_PRINT_LEAKS ();
1015 cairo_test_log (ctx, "Error: Failed to finish surface: %s\n",
1016 cairo_status_to_string (status));
1017 ret = CAIRO_TEST_FAILURE;
1022 /* Skip image check for tests with no image (width,height == 0,0) */
1023 if (ctx->test->width != 0 && ctx->test->height != 0) {
1024 cairo_surface_t *ref_image;
1025 cairo_surface_t *test_image;
1026 cairo_surface_t *diff_image;
1027 buffer_diff_result_t result;
1028 cairo_status_t diff_status;
1030 if (ref_png_path == NULL) {
1031 cairo_test_log (ctx, "Error: Cannot find reference image for %s\n",
1034 /* we may be running this test to generate reference images */
1035 _xunlink (ctx, out_png_path);
1036 /* be more generous as we may need to use external renderers */
1037 alarm (4 * ctx->timeout);
1038 test_image = target->get_image_surface (surface, 0,
1042 diff_status = cairo_surface_write_to_png (test_image, out_png_path);
1043 cairo_surface_destroy (test_image);
1045 if (cairo_surface_status (test_image) == CAIRO_STATUS_INVALID_STATUS)
1046 ret = CAIRO_TEST_CRASHED;
1048 ret = CAIRO_TEST_FAILURE;
1049 cairo_test_log (ctx,
1050 "Error: Failed to write output image: %s\n",
1051 cairo_status_to_string (diff_status));
1055 ret = CAIRO_TEST_XFAILURE;
1059 if (target->file_extension != NULL) { /* compare vector surfaces */
1060 char *filenames[] = {
1069 base_xfail_png_path,
1072 xasprintf (&test_filename, "%s.out%s",
1073 base_path, target->file_extension);
1074 xasprintf (&pass_filename, "%s.pass%s",
1075 base_path, target->file_extension);
1076 xasprintf (&fail_filename, "%s.fail%s",
1077 base_path, target->file_extension);
1079 if (cairo_test_file_is_older (pass_filename,
1081 ARRAY_SIZE (filenames)))
1083 _xunlink (ctx, pass_filename);
1085 if (cairo_test_file_is_older (fail_filename,
1087 ARRAY_SIZE (filenames)))
1089 _xunlink (ctx, fail_filename);
1092 if (cairo_test_files_equal (out_png_path, ref_path)) {
1093 cairo_test_log (ctx, "Vector surface matches reference.\n");
1094 have_output = FALSE;
1095 ret = CAIRO_TEST_SUCCESS;
1098 if (cairo_test_files_equal (out_png_path, new_path)) {
1099 cairo_test_log (ctx, "Vector surface matches current failure.\n");
1100 have_output = FALSE;
1101 ret = CAIRO_TEST_NEW;
1104 if (cairo_test_files_equal (out_png_path, xfail_path)) {
1105 cairo_test_log (ctx, "Vector surface matches known failure.\n");
1106 have_output = FALSE;
1107 ret = CAIRO_TEST_XFAILURE;
1111 if (cairo_test_files_equal (test_filename, pass_filename)) {
1112 /* identical output as last known PASS */
1113 cairo_test_log (ctx, "Vector surface matches last pass.\n");
1115 ret = CAIRO_TEST_SUCCESS;
1118 if (cairo_test_files_equal (test_filename, fail_filename)) {
1119 /* identical output as last known FAIL, fail */
1120 cairo_test_log (ctx, "Vector surface matches last fail.\n");
1121 have_result = TRUE; /* presume these were kept around as well */
1123 ret = CAIRO_TEST_FAILURE;
1128 /* be more generous as we may need to use external renderers */
1129 alarm (4 * ctx->timeout);
1130 test_image = target->get_image_surface (surface, 0,
1134 if (cairo_surface_status (test_image)) {
1135 cairo_test_log (ctx, "Error: Failed to extract image: %s\n",
1136 cairo_status_to_string (cairo_surface_status (test_image)));
1137 if (cairo_surface_status (test_image) == CAIRO_STATUS_INVALID_STATUS)
1138 ret = CAIRO_TEST_CRASHED;
1140 ret = CAIRO_TEST_FAILURE;
1141 cairo_surface_destroy (test_image);
1145 _xunlink (ctx, out_png_path);
1146 diff_status = cairo_surface_write_to_png (test_image, out_png_path);
1148 cairo_test_log (ctx, "Error: Failed to write output image: %s\n",
1149 cairo_status_to_string (diff_status));
1150 cairo_surface_destroy (test_image);
1151 ret = CAIRO_TEST_FAILURE;
1156 /* binary compare png files (no decompression) */
1157 if (target->file_extension == NULL) {
1158 char *filenames[] = {
1164 base_xfail_png_path,
1167 xasprintf (&test_filename, "%s", out_png_path);
1168 xasprintf (&pass_filename, "%s.pass.png", base_path);
1169 xasprintf (&fail_filename, "%s.fail.png", base_path);
1171 if (cairo_test_file_is_older (pass_filename,
1173 ARRAY_SIZE (filenames)))
1175 _xunlink (ctx, pass_filename);
1177 if (cairo_test_file_is_older (fail_filename,
1179 ARRAY_SIZE (filenames)))
1181 _xunlink (ctx, fail_filename);
1184 if (cairo_test_files_equal (test_filename, pass_filename)) {
1185 cairo_test_log (ctx, "PNG file exactly matches last pass.\n");
1187 cairo_surface_destroy (test_image);
1188 ret = CAIRO_TEST_SUCCESS;
1191 if (cairo_test_files_equal (out_png_path, ref_png_path)) {
1192 cairo_test_log (ctx, "PNG file exactly matches reference image.\n");
1194 cairo_surface_destroy (test_image);
1195 ret = CAIRO_TEST_SUCCESS;
1198 if (cairo_test_files_equal (out_png_path, new_png_path)) {
1199 cairo_test_log (ctx, "PNG file exactly matches current failure image.\n");
1201 cairo_surface_destroy (test_image);
1202 ret = CAIRO_TEST_NEW;
1205 if (cairo_test_files_equal (out_png_path, xfail_png_path)) {
1206 cairo_test_log (ctx, "PNG file exactly matches known failure image.\n");
1208 cairo_surface_destroy (test_image);
1209 ret = CAIRO_TEST_XFAILURE;
1212 if (cairo_test_files_equal (test_filename, fail_filename)) {
1213 cairo_test_log (ctx, "PNG file exactly matches last fail.\n");
1214 have_result = TRUE; /* presume these were kept around as well */
1215 cairo_surface_destroy (test_image);
1216 ret = CAIRO_TEST_FAILURE;
1220 if (cairo_test_files_equal (out_png_path, ref_png_path)) {
1221 cairo_test_log (ctx, "PNG file exactly matches reference image.\n");
1223 cairo_surface_destroy (test_image);
1224 ret = CAIRO_TEST_SUCCESS;
1227 if (cairo_test_files_equal (out_png_path, new_png_path)) {
1228 cairo_test_log (ctx, "PNG file exactly matches current failure image.\n");
1230 cairo_surface_destroy (test_image);
1231 ret = CAIRO_TEST_NEW;
1234 if (cairo_test_files_equal (out_png_path, xfail_png_path)) {
1235 cairo_test_log (ctx, "PNG file exactly matches known failure image.\n");
1237 cairo_surface_destroy (test_image);
1238 ret = CAIRO_TEST_XFAILURE;
1243 if (cairo_test_files_equal (out_png_path, base_ref_png_path)) {
1244 cairo_test_log (ctx, "PNG file exactly reference image.\n");
1246 cairo_surface_destroy (test_image);
1247 ret = CAIRO_TEST_SUCCESS;
1250 if (cairo_test_files_equal (out_png_path, base_new_png_path)) {
1251 cairo_test_log (ctx, "PNG file exactly current failure image.\n");
1253 cairo_surface_destroy (test_image);
1254 ret = CAIRO_TEST_NEW;
1257 if (cairo_test_files_equal (out_png_path, base_xfail_png_path)) {
1258 cairo_test_log (ctx, "PNG file exactly known failure image.\n");
1260 cairo_surface_destroy (test_image);
1261 ret = CAIRO_TEST_XFAILURE;
1265 /* first compare against the ideal reference */
1266 ref_image = cairo_test_get_reference_image (ctx, base_ref_png_path,
1267 target->content == CAIRO_TEST_CONTENT_COLOR_ALPHA_FLATTENED);
1268 if (cairo_surface_status (ref_image)) {
1269 cairo_test_log (ctx, "Error: Cannot open reference image for %s: %s\n",
1271 cairo_status_to_string (cairo_surface_status (ref_image)));
1272 cairo_surface_destroy (test_image);
1273 ret = CAIRO_TEST_FAILURE;
1277 diff_image = cairo_image_surface_create (CAIRO_FORMAT_ARGB32,
1281 cmp_png_path = base_ref_png_path;
1282 diff_status = image_diff (ctx,
1283 test_image, ref_image, diff_image,
1285 _xunlink (ctx, diff_png_path);
1287 image_diff_is_failure (&result, target->error_tolerance))
1289 /* that failed, so check against the specific backend */
1290 ref_image = cairo_test_get_reference_image (ctx, ref_png_path,
1291 target->content == CAIRO_TEST_CONTENT_COLOR_ALPHA_FLATTENED);
1292 if (cairo_surface_status (ref_image)) {
1293 cairo_test_log (ctx, "Error: Cannot open reference image for %s: %s\n",
1295 cairo_status_to_string (cairo_surface_status (ref_image)));
1296 cairo_surface_destroy (test_image);
1297 ret = CAIRO_TEST_FAILURE;
1301 cmp_png_path = ref_png_path;
1302 diff_status = image_diff (ctx,
1303 test_image, ref_image,
1308 cairo_test_log (ctx, "Error: Failed to compare images: %s\n",
1309 cairo_status_to_string (diff_status));
1310 ret = CAIRO_TEST_FAILURE;
1312 else if (image_diff_is_failure (&result, target->error_tolerance))
1314 ret = CAIRO_TEST_FAILURE;
1316 diff_status = cairo_surface_write_to_png (diff_image,
1319 cairo_test_log (ctx, "Error: Failed to write differences image: %s\n",
1320 cairo_status_to_string (diff_status));
1325 cairo_test_copy_file (test_filename, fail_filename);
1329 cairo_test_copy_file (test_filename, pass_filename);
1334 cairo_test_copy_file (test_filename, pass_filename);
1337 /* If failed, compare against the current image output,
1338 * and attempt to detect systematic failures.
1340 if (ret == CAIRO_TEST_FAILURE) {
1341 char *image_out_path;
1344 cairo_test_reference_filename (ctx,
1350 CAIRO_TEST_OUT_SUFFIX,
1351 CAIRO_TEST_PNG_EXTENSION);
1352 if (image_out_path != NULL) {
1353 if (cairo_test_files_equal (out_png_path,
1356 ret = CAIRO_TEST_XFAILURE;
1361 cairo_image_surface_create_from_png (image_out_path);
1362 if (cairo_surface_status (ref_image) == CAIRO_STATUS_SUCCESS)
1364 diff_status = image_diff (ctx,
1365 test_image, ref_image,
1368 if (diff_status == CAIRO_STATUS_SUCCESS &&
1369 !image_diff_is_failure (&result, target->error_tolerance))
1371 ret = CAIRO_TEST_XFAILURE;
1374 cairo_surface_destroy (ref_image);
1378 free (image_out_path);
1382 cairo_surface_destroy (test_image);
1383 cairo_surface_destroy (diff_image);
1386 if (cairo_status (cr) != CAIRO_STATUS_SUCCESS) {
1387 cairo_test_log (ctx, "Error: Function under test left cairo status in an error state: %s\n",
1388 cairo_status_to_string (cairo_status (cr)));
1389 ret = CAIRO_TEST_ERROR;
1394 free (test_filename);
1395 free (fail_filename);
1396 free (pass_filename);
1398 test_filename = fail_filename = pass_filename = NULL;
1401 if (ret == CAIRO_TEST_FAILURE)
1402 MEMFAULT_PRINT_FAULTS ();
1406 cairo_surface_destroy (surface);
1408 if (target->cleanup)
1409 target->cleanup (closure);
1412 cairo_debug_reset_static_data ();
1418 if (MEMFAULT_COUNT_LEAKS () > 0) {
1419 if (ret != CAIRO_TEST_FAILURE)
1420 MEMFAULT_PRINT_FAULTS ();
1421 MEMFAULT_PRINT_LEAKS ();
1424 if (ret == CAIRO_TEST_SUCCESS && --malloc_failure_iterations > 0)
1429 cairo_test_log (ctx, "OUTPUT: %s\n", out_png_path);
1432 if (cmp_png_path == NULL) {
1433 /* XXX presume we matched the normal ref last time */
1434 cmp_png_path = ref_png_path;
1436 cairo_test_log (ctx,
1437 "REFERENCE: %s\nDIFFERENCE: %s\n",
1438 cmp_png_path, diff_png_path);
1442 free (out_png_path);
1443 free (ref_png_path);
1444 free (base_ref_png_path);
1446 free (new_png_path);
1447 free (base_new_png_path);
1449 free (xfail_png_path);
1450 free (base_xfail_png_path);
1452 free (diff_png_path);
1459 #if defined(HAVE_SIGNAL_H) && defined(HAVE_SETJMP_H)
1462 /* Used to catch crashes in a test, so that we report it as such and
1463 * continue testing, although one crasher may already have corrupted memory in
1464 * an nonrecoverable fashion. */
1465 static jmp_buf jmpbuf;
1468 segfault_handler (int signal)
1470 longjmp (jmpbuf, signal);
1475 _cairo_test_context_run_for_target (cairo_test_context_t *ctx,
1476 const cairo_boilerplate_target_t *target,
1477 cairo_bool_t similar,
1480 cairo_test_status_t status;
1482 if (target->get_image_surface == NULL)
1483 return CAIRO_TEST_UNTESTED;
1485 if (similar && ! cairo_test_target_has_similar (ctx, target))
1486 return CAIRO_TEST_UNTESTED;
1488 cairo_test_log (ctx,
1489 "Testing %s with %s%s target (dev offset %d)\n",
1491 similar ? " (similar) " : "",
1495 printf ("%s.%s.%s [%d]%s:\t", ctx->test_name, target->name,
1496 cairo_boilerplate_content_name (target->content),
1498 similar ? " (similar)": "");
1501 #if defined(HAVE_SIGNAL_H) && defined(HAVE_SETJMP_H)
1502 if (! RUNNING_ON_VALGRIND) {
1503 void (* volatile old_segfault_handler)(int);
1504 void (* volatile old_segfpe_handler)(int);
1505 void (* volatile old_sigpipe_handler)(int);
1506 void (* volatile old_sigabrt_handler)(int);
1507 void (* volatile old_sigalrm_handler)(int);
1509 /* Set up a checkpoint to get back to in case of segfaults. */
1511 old_segfault_handler = signal (SIGSEGV, segfault_handler);
1514 old_segfpe_handler = signal (SIGFPE, segfault_handler);
1517 old_sigpipe_handler = signal (SIGPIPE, segfault_handler);
1520 old_sigabrt_handler = signal (SIGABRT, segfault_handler);
1523 old_sigalrm_handler = signal (SIGALRM, segfault_handler);
1525 if (0 == setjmp (jmpbuf))
1526 status = cairo_test_for_target (ctx, target, dev_offset, similar);
1528 status = CAIRO_TEST_CRASHED;
1530 signal (SIGSEGV, old_segfault_handler);
1533 signal (SIGFPE, old_segfpe_handler);
1536 signal (SIGPIPE, old_sigpipe_handler);
1539 signal (SIGABRT, old_sigabrt_handler);
1542 signal (SIGALRM, old_sigalrm_handler);
1545 status = cairo_test_for_target (ctx, target, dev_offset, similar);
1548 status = cairo_test_for_target (ctx, target, dev_offset, similar);
1551 cairo_test_log (ctx,
1552 "TEST: %s TARGET: %s FORMAT: %s OFFSET: %d SIMILAR: %d RESULT: ",
1553 ctx->test_name, target->name,
1554 cairo_boilerplate_content_name (target->content),
1555 dev_offset, similar);
1557 case CAIRO_TEST_SUCCESS:
1559 cairo_test_log (ctx, "PASS\n");
1562 case CAIRO_TEST_UNTESTED:
1563 printf ("UNTESTED\n");
1564 cairo_test_log (ctx, "UNTESTED\n");
1568 case CAIRO_TEST_CRASHED:
1569 if (print_fail_on_stdout) {
1570 printf ("!!!CRASHED!!!\n");
1572 /* eat the test name */
1576 cairo_test_log (ctx, "CRASHED\n");
1577 fprintf (stderr, "%s.%s.%s [%d]%s:\t%s!!!CRASHED!!!%s\n",
1578 ctx->test_name, target->name,
1579 cairo_boilerplate_content_name (target->content), dev_offset, similar ? " (similar)" : "",
1580 fail_face, normal_face);
1583 case CAIRO_TEST_ERROR:
1584 if (print_fail_on_stdout) {
1585 printf ("!!!ERROR!!!\n");
1587 /* eat the test name */
1591 cairo_test_log (ctx, "ERROR\n");
1592 fprintf (stderr, "%s.%s.%s [%d]%s:\t%s!!!ERROR!!!%s\n",
1593 ctx->test_name, target->name,
1594 cairo_boilerplate_content_name (target->content), dev_offset, similar ? " (similar)" : "",
1595 fail_face, normal_face);
1598 case CAIRO_TEST_XFAILURE:
1599 if (print_fail_on_stdout) {
1602 /* eat the test name */
1606 fprintf (stderr, "%s.%s.%s [%d]%s:\t%sXFAIL%s\n",
1607 ctx->test_name, target->name,
1608 cairo_boilerplate_content_name (target->content), dev_offset, similar ? " (similar)" : "",
1609 xfail_face, normal_face);
1610 cairo_test_log (ctx, "XFAIL\n");
1613 case CAIRO_TEST_NEW:
1614 if (print_fail_on_stdout) {
1617 /* eat the test name */
1621 fprintf (stderr, "%s.%s.%s [%d]%s:\t%sNEW%s\n",
1622 ctx->test_name, target->name,
1623 cairo_boilerplate_content_name (target->content), dev_offset, similar ? " (similar)" : "",
1624 fail_face, normal_face);
1625 cairo_test_log (ctx, "NEW\n");
1628 case CAIRO_TEST_NO_MEMORY:
1629 case CAIRO_TEST_FAILURE:
1630 if (print_fail_on_stdout) {
1633 /* eat the test name */
1637 fprintf (stderr, "%s.%s.%s [%d]%s:\t%sFAIL%s\n",
1638 ctx->test_name, target->name,
1639 cairo_boilerplate_content_name (target->content), dev_offset, similar ? " (similar)" : "",
1640 fail_face, normal_face);
1641 cairo_test_log (ctx, "FAIL\n");
1649 const cairo_test_context_t *
1650 cairo_test_get_context (cairo_t *cr)
1652 return cairo_get_user_data (cr, &_cairo_test_context_key);
1656 cairo_test_create_surface_from_png (const cairo_test_context_t *ctx,
1657 const char *filename)
1659 cairo_surface_t *image;
1660 cairo_status_t status;
1662 image = cairo_image_surface_create_from_png (filename);
1663 status = cairo_surface_status (image);
1664 if (status == CAIRO_STATUS_FILE_NOT_FOUND) {
1665 /* expect not found when running with srcdir != builddir
1666 * such as when 'make distcheck' is run
1669 char *srcdir_filename;
1670 xasprintf (&srcdir_filename, "%s/%s", ctx->srcdir, filename);
1671 cairo_surface_destroy (image);
1672 image = cairo_image_surface_create_from_png (srcdir_filename);
1673 free (srcdir_filename);
1681 cairo_test_create_pattern_from_png (const cairo_test_context_t *ctx,
1682 const char *filename)
1684 cairo_surface_t *image;
1685 cairo_pattern_t *pattern;
1687 image = cairo_test_create_surface_from_png (ctx, filename);
1689 pattern = cairo_pattern_create_for_surface (image);
1691 cairo_pattern_set_extend (pattern, CAIRO_EXTEND_REPEAT);
1693 cairo_surface_destroy (image);
1698 static cairo_surface_t *
1699 _draw_check (int width, int height)
1701 cairo_surface_t *surface;
1704 surface = cairo_image_surface_create (CAIRO_FORMAT_RGB24, 12, 12);
1705 cr = cairo_create (surface);
1706 cairo_surface_destroy (surface);
1708 cairo_set_source_rgb (cr, 0.75, 0.75, 0.75); /* light gray */
1711 cairo_set_source_rgb (cr, 0.25, 0.25, 0.25); /* dark gray */
1712 cairo_rectangle (cr, width / 2, 0, width / 2, height / 2);
1713 cairo_rectangle (cr, 0, height / 2, width / 2, height / 2);
1716 surface = cairo_surface_reference (cairo_get_target (cr));
1723 cairo_test_paint_checkered (cairo_t *cr)
1725 cairo_surface_t *check;
1727 check = _draw_check (12, 12);
1730 cairo_set_source_surface (cr, check, 0, 0);
1731 cairo_surface_destroy (check);
1733 cairo_pattern_set_filter (cairo_get_source (cr), CAIRO_FILTER_NEAREST);
1734 cairo_pattern_set_extend (cairo_get_source (cr), CAIRO_EXTEND_REPEAT);
1741 cairo_test_is_target_enabled (const cairo_test_context_t *ctx,
1746 for (i = 0; i < ctx->num_targets; i++) {
1747 const cairo_boilerplate_target_t *t = ctx->targets_to_test[i];
1748 if (strcmp (t->name, target) == 0) {
1749 /* XXX ask the target whether is it possible to run?
1750 * e.g. the xlib backend could check whether it is able to connect
1753 return t->get_image_surface != NULL;
1761 cairo_test_malloc_failure (const cairo_test_context_t *ctx,
1762 cairo_status_t status)
1764 if (! ctx->malloc_failure)
1767 if (status != CAIRO_STATUS_NO_MEMORY)
1774 /* prevent infinite loops... */
1775 n_faults = MEMFAULT_COUNT_FAULTS ();
1776 if (n_faults == ctx->last_fault_count)
1779 ((cairo_test_context_t *) ctx)->last_fault_count = n_faults;
1787 cairo_test_status_from_status (const cairo_test_context_t *ctx,
1788 cairo_status_t status)
1790 if (status == CAIRO_STATUS_SUCCESS)
1791 return CAIRO_TEST_SUCCESS;
1793 if (cairo_test_malloc_failure (ctx, status))
1794 return CAIRO_TEST_NO_MEMORY;
1796 return CAIRO_TEST_FAILURE;