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 */
45 #include <fontconfig/fontconfig.h>
47 #if CAIRO_HAS_REAL_PTHREAD
57 #define RUNNING_ON_VALGRIND 0
67 #include "cairo-test-private.h"
69 #include "buffer-diff.h"
86 #if ! HAVE_ALARM || ! defined(SIGALRM)
90 static const cairo_user_data_key_t _cairo_test_context_key;
93 _xunlink (const cairo_test_context_t *ctx, const char *pathname);
95 static const char *fail_face = "", *xfail_face="", *normal_face = "";
96 static cairo_bool_t print_fail_on_stdout;
97 static int cairo_test_timeout = 60;
99 #define NUM_DEVICE_OFFSETS 2
100 #define NUM_DEVICE_SCALE 2
103 cairo_test_mkdir (const char *path)
107 #elif HAVE_MKDIR == 1
108 if (mkdir (path) == 0)
110 #elif HAVE_MKDIR == 2
111 if (mkdir (path, 0770) == 0)
114 #error Bad value for HAVE_MKDIR
117 return errno == EEXIST;
121 _cairo_test_fixup_name (const char *original)
125 s = name = xstrdup (original);
126 while ((s = strchr (s, '_')) != NULL)
133 cairo_test_get_name (const cairo_test_t *test)
135 return _cairo_test_fixup_name (test->name);
139 _cairo_test_init (cairo_test_context_t *ctx,
140 const cairo_test_context_t *parent,
141 const cairo_test_t *test,
142 const char *test_name,
147 MF (MEMFAULT_DISABLE_FAULTS ());
149 #if HAVE_FEENABLEEXCEPT
150 feenableexcept (FE_DIVBYZERO | FE_INVALID | FE_OVERFLOW);
154 ctx->test_name = _cairo_test_fixup_name (test_name);
155 ctx->output = output;
157 cairo_test_mkdir (ctx->output);
159 ctx->malloc_failure = 0;
161 if (getenv ("CAIRO_TEST_MALLOC_FAILURE"))
162 ctx->malloc_failure = atoi (getenv ("CAIRO_TEST_MALLOC_FAILURE"));
163 if (ctx->malloc_failure && ! RUNNING_ON_MEMFAULT ())
164 ctx->malloc_failure = 0;
167 ctx->timeout = cairo_test_timeout;
168 if (getenv ("CAIRO_TEST_TIMEOUT"))
169 ctx->timeout = atoi (getenv ("CAIRO_TEST_TIMEOUT"));
171 xasprintf (&log_name, "%s/%s%s", ctx->output, ctx->test_name, CAIRO_TEST_LOG_SUFFIX);
172 _xunlink (NULL, log_name);
174 ctx->log_file = fopen (log_name, "a");
175 if (ctx->log_file == NULL) {
176 fprintf (stderr, "Error opening log file: %s\n", log_name);
177 ctx->log_file = stderr;
181 ctx->ref_name = NULL;
182 ctx->ref_image = NULL;
183 ctx->ref_image_flattened = NULL;
185 if (parent != NULL) {
186 ctx->targets_to_test = parent->targets_to_test;
187 ctx->num_targets = parent->num_targets;
188 ctx->limited_targets = parent->limited_targets;
189 ctx->own_targets = FALSE;
191 ctx->srcdir = parent->srcdir;
192 ctx->refdir = parent->refdir;
195 cairo_bool_t tmp_limited_targets;
197 ctx->targets_to_test = cairo_boilerplate_get_targets (&tmp_num_targets, &tmp_limited_targets);
198 ctx->num_targets = tmp_num_targets;
199 ctx->limited_targets = tmp_limited_targets;
200 ctx->own_targets = TRUE;
202 ctx->srcdir = getenv ("srcdir");
203 if (ctx->srcdir == NULL)
206 ctx->refdir = getenv ("CAIRO_REF_DIR");
210 if (*fail_face == '\0' && isatty (2)) {
211 fail_face = "\033[41;37;1m";
212 xfail_face = "\033[43;37;1m";
213 normal_face = "\033[m";
215 print_fail_on_stdout = FALSE;
219 printf ("\nTESTING %s\n", ctx->test_name);
223 _cairo_test_context_init_for_test (cairo_test_context_t *ctx,
224 const cairo_test_context_t *parent,
225 const cairo_test_t *test)
227 _cairo_test_init (ctx, parent, test, test->name, CAIRO_TEST_OUTPUT_DIR);
231 cairo_test_init (cairo_test_context_t *ctx,
232 const char *test_name,
235 _cairo_test_init (ctx, NULL, NULL, test_name, output);
239 cairo_test_fini (cairo_test_context_t *ctx)
241 if (ctx->log_file == NULL)
244 if (ctx->log_file != stderr)
245 fclose (ctx->log_file);
246 ctx->log_file = NULL;
248 free (ctx->ref_name);
249 cairo_surface_destroy (ctx->ref_image);
250 cairo_surface_destroy (ctx->ref_image_flattened);
252 if (ctx->test_name != NULL)
253 free ((char *) ctx->test_name);
255 if (ctx->own_targets)
256 cairo_boilerplate_free_targets (ctx->targets_to_test);
258 cairo_boilerplate_fini ();
260 cairo_debug_reset_static_data ();
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);
275 cairo_test_log (const cairo_test_context_t *ctx, const char *fmt, ...)
280 cairo_test_logv (ctx, fmt, va);
285 _xunlink (const cairo_test_context_t *ctx, const char *pathname)
287 if (unlink (pathname) < 0 && errno != ENOENT) {
288 cairo_test_log (ctx, "Error: Cannot remove %s: %s\n",
289 pathname, strerror (errno));
295 cairo_test_reference_filename (const cairo_test_context_t *ctx,
296 const char *base_name,
297 const char *test_name,
298 const char *target_name,
299 const char *base_target_name,
302 const char *extension)
304 char *ref_name = NULL;
306 /* First look for a previous build for comparison. */
307 if (ctx->refdir != NULL && strcmp(suffix, CAIRO_TEST_REF_SUFFIX) == 0) {
308 xasprintf (&ref_name, "%s/%s" CAIRO_TEST_OUT_SUFFIX "%s",
312 if (access (ref_name, F_OK) != 0)
318 if (target_name != NULL) {
319 /* Next look for a target/format-specific reference image. */
320 xasprintf (&ref_name, "%s/reference/%s.%s.%s%s%s",
327 if (access (ref_name, F_OK) != 0)
332 /* Next, look for target-specific reference image. */
333 xasprintf (&ref_name, "%s/reference/%s.%s%s%s",
339 if (access (ref_name, F_OK) != 0)
345 if (base_target_name != NULL) {
346 /* Next look for a base/format-specific reference image. */
347 xasprintf (&ref_name, "%s/reference/%s.%s.%s%s%s",
354 if (access (ref_name, F_OK) != 0)
359 /* Next, look for base-specific reference image. */
360 xasprintf (&ref_name, "%s/reference/%s.%s%s%s",
366 if (access (ref_name, F_OK) != 0)
372 /* Next, look for format-specific reference image. */
373 xasprintf (&ref_name, "%s/reference/%s.%s%s%s",
379 if (access (ref_name, F_OK) != 0)
384 /* Finally, look for the standard reference image. */
385 xasprintf (&ref_name, "%s/reference/%s%s%s", ctx->srcdir,
389 if (access (ref_name, F_OK) != 0)
401 cairo_test_target_has_similar (const cairo_test_context_t *ctx,
402 const cairo_boilerplate_target_t *target)
404 cairo_surface_t *surface;
405 cairo_test_similar_t has_similar;
407 cairo_surface_t *similar;
408 cairo_status_t status;
412 /* ignore image intermediate targets */
413 if (target->expected_type == CAIRO_SURFACE_TYPE_IMAGE)
416 if (getenv ("CAIRO_TEST_IGNORE_SIMILAR"))
419 xasprintf (&path, "%s/%s",
420 cairo_test_mkdir (ctx->output) ? ctx->output : ".",
423 has_similar = DIRECT;
426 surface = (target->create_surface) (path,
430 ctx->test->width* NUM_DEVICE_SCALE + 25 * NUM_DEVICE_OFFSETS,
431 ctx->test->height* NUM_DEVICE_SCALE + 25 * NUM_DEVICE_OFFSETS,
432 CAIRO_BOILERPLATE_MODE_TEST,
436 } while (cairo_test_malloc_failure (ctx, cairo_surface_status (surface)));
438 if (cairo_surface_status (surface))
441 cr = cairo_create (surface);
442 cairo_push_group_with_content (cr,
443 cairo_boilerplate_content (target->content));
444 similar = cairo_get_group_target (cr);
445 status = cairo_surface_status (similar);
447 if (cairo_surface_get_type (similar) == cairo_surface_get_type (surface))
448 has_similar = SIMILAR;
450 has_similar = DIRECT;
453 cairo_surface_destroy (surface);
456 target->cleanup (closure);
457 } while (! has_similar && cairo_test_malloc_failure (ctx, status));
464 static cairo_surface_t *
465 _cairo_test_flatten_reference_image (cairo_test_context_t *ctx,
466 cairo_bool_t flatten)
468 cairo_surface_t *surface;
472 return ctx->ref_image;
474 if (ctx->ref_image_flattened != NULL)
475 return ctx->ref_image_flattened;
477 surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32,
478 cairo_image_surface_get_width (ctx->ref_image),
479 cairo_image_surface_get_height (ctx->ref_image));
480 cr = cairo_create (surface);
481 cairo_surface_destroy (surface);
483 cairo_set_source_rgb (cr, 1, 1, 1);
486 cairo_set_source_surface (cr, ctx->ref_image, 0, 0);
489 surface = cairo_surface_reference (cairo_get_target (cr));
492 if (cairo_surface_status (surface) == CAIRO_STATUS_SUCCESS)
493 ctx->ref_image_flattened = surface;
498 cairo_test_get_reference_image (cairo_test_context_t *ctx,
499 const char *filename,
500 cairo_bool_t flatten)
502 cairo_surface_t *surface;
504 if (ctx->ref_name != NULL) {
505 if (strcmp (ctx->ref_name, filename) == 0)
506 return _cairo_test_flatten_reference_image (ctx, flatten);
508 cairo_surface_destroy (ctx->ref_image);
509 ctx->ref_image = NULL;
511 cairo_surface_destroy (ctx->ref_image_flattened);
512 ctx->ref_image_flattened = NULL;
514 free (ctx->ref_name);
515 ctx->ref_name = NULL;
518 surface = cairo_image_surface_create_from_png (filename);
519 if (cairo_surface_status (surface))
522 ctx->ref_name = xstrdup (filename);
523 ctx->ref_image = surface;
524 return _cairo_test_flatten_reference_image (ctx, flatten);
528 cairo_test_file_is_older (const char *filename,
529 char **ref_filenames,
530 int num_ref_filenames)
535 if (stat (filename, &st) < 0)
538 while (num_ref_filenames--) {
540 char *ref_filename = *ref_filenames++;
542 if (ref_filename == NULL)
545 if (stat (ref_filename++, &ref) < 0)
548 if (st.st_mtime <= ref.st_mtime)
557 cairo_test_files_equal (const char *test_filename,
558 const char *pass_filename)
563 if (test_filename == NULL || pass_filename == NULL)
566 test = fopen (test_filename, "rb");
570 pass = fopen (pass_filename, "rb");
576 /* as simple as it gets */
582 } while (t != EOF && p != EOF);
587 return t == p; /* both EOF */
591 cairo_test_copy_file (const char *src_filename,
592 const char *dst_filename)
598 if (link (src_filename, dst_filename) == 0)
601 unlink (dst_filename);
604 src = fopen (src_filename, "rb");
608 dst = fopen (dst_filename, "wb");
614 /* as simple as it gets */
615 while ((c = getc (src)) != EOF)
624 static cairo_test_status_t
625 cairo_test_for_target (cairo_test_context_t *ctx,
626 const cairo_boilerplate_target_t *target,
629 cairo_bool_t similar)
631 cairo_test_status_t status;
632 cairo_surface_t *surface = NULL;
634 const char *empty_str = "";
637 char *base_name, *base_path;
639 char *ref_path = NULL, *ref_png_path, *cmp_png_path = NULL;
640 char *new_path = NULL, *new_png_path;
641 char *xfail_path = NULL, *xfail_png_path;
642 char *base_ref_png_path;
643 char *base_new_png_path;
644 char *base_xfail_png_path;
646 char *test_filename = NULL, *pass_filename = NULL, *fail_filename = NULL;
647 cairo_test_status_t ret;
648 cairo_content_t expected_content;
649 cairo_font_options_t *font_options;
651 cairo_bool_t have_output = FALSE;
652 cairo_bool_t have_result = FALSE;
654 double width, height;
655 cairo_bool_t have_output_dir;
657 int malloc_failure_iterations = ctx->malloc_failure;
658 int last_fault_count = 0;
661 /* Get the strings ready that we'll need. */
662 format = cairo_boilerplate_content_name (target->content);
664 xasprintf (&offset_str, ".%d", dev_offset);
666 offset_str = (char *) empty_str;
669 xasprintf (&scale_str, ".x%d", dev_scale);
671 scale_str = (char *) empty_str;
673 xasprintf (&base_name, "%s.%s.%s%s%s%s",
677 similar ? ".similar" : "",
681 if (offset_str != empty_str)
683 if (scale_str != empty_str)
686 ref_png_path = cairo_test_reference_filename (ctx,
692 CAIRO_TEST_REF_SUFFIX,
693 CAIRO_TEST_PNG_EXTENSION);
694 new_png_path = cairo_test_reference_filename (ctx,
700 CAIRO_TEST_NEW_SUFFIX,
701 CAIRO_TEST_PNG_EXTENSION);
702 xfail_png_path = cairo_test_reference_filename (ctx,
708 CAIRO_TEST_XFAIL_SUFFIX,
709 CAIRO_TEST_PNG_EXTENSION);
711 base_ref_png_path = cairo_test_reference_filename (ctx,
716 CAIRO_TEST_REF_SUFFIX,
717 CAIRO_TEST_PNG_EXTENSION);
718 base_new_png_path = cairo_test_reference_filename (ctx,
723 CAIRO_TEST_NEW_SUFFIX,
724 CAIRO_TEST_PNG_EXTENSION);
725 base_xfail_png_path = cairo_test_reference_filename (ctx,
730 CAIRO_TEST_XFAIL_SUFFIX,
731 CAIRO_TEST_PNG_EXTENSION);
733 if (target->file_extension != NULL) {
734 ref_path = cairo_test_reference_filename (ctx,
740 CAIRO_TEST_REF_SUFFIX,
741 target->file_extension);
742 new_path = cairo_test_reference_filename (ctx,
748 CAIRO_TEST_NEW_SUFFIX,
749 target->file_extension);
750 xfail_path = cairo_test_reference_filename (ctx,
756 CAIRO_TEST_XFAIL_SUFFIX,
757 target->file_extension);
760 have_output_dir = cairo_test_mkdir (ctx->output);
761 xasprintf (&base_path, "%s/%s",
762 have_output_dir ? ctx->output : ".",
764 xasprintf (&out_png_path, "%s" CAIRO_TEST_OUT_PNG, base_path);
765 xasprintf (&diff_png_path, "%s" CAIRO_TEST_DIFF_PNG, base_path);
767 if (ctx->test->requirements != NULL) {
768 const char *required;
770 required = target->is_vector ? "target=raster" : "target=vector";
771 if (strstr (ctx->test->requirements, required) != NULL) {
772 cairo_test_log (ctx, "Error: Skipping for %s target %s\n",
773 target->is_vector ? "vector" : "raster",
775 ret = CAIRO_TEST_UNTESTED;
779 required = target->is_recording ? "target=!recording" : "target=recording";
780 if (strstr (ctx->test->requirements, required) != NULL) {
781 cairo_test_log (ctx, "Error: Skipping for %s target %s\n",
782 target->is_recording ? "recording" : "non-recording",
784 ret = CAIRO_TEST_UNTESTED;
789 width = ctx->test->width;
790 height = ctx->test->height;
791 if (width && height) {
795 height += dev_offset;
800 MEMFAULT_CLEAR_FAULTS ();
801 MEMFAULT_RESET_LEAKS ();
802 ctx->last_fault_count = 0;
803 last_fault_count = MEMFAULT_COUNT_FAULTS ();
805 /* Pre-initialise fontconfig so that the configuration is loaded without
806 * malloc failures (our primary goal is to test cairo fault tolerance).
812 MEMFAULT_ENABLE_FAULTS ();
817 /* Run the actual drawing code. */
818 ret = CAIRO_TEST_SUCCESS;
819 surface = (target->create_surface) (base_path,
822 ctx->test->width * NUM_DEVICE_SCALE + 25 * NUM_DEVICE_OFFSETS,
823 ctx->test->height * NUM_DEVICE_SCALE + 25 * NUM_DEVICE_OFFSETS,
824 CAIRO_BOILERPLATE_MODE_TEST,
826 if (surface == NULL) {
827 cairo_test_log (ctx, "Error: Failed to set %s target\n", target->name);
828 ret = CAIRO_TEST_UNTESTED;
833 if (ctx->malloc_failure &&
834 MEMFAULT_COUNT_FAULTS () - last_fault_count > 0 &&
835 cairo_surface_status (surface) == CAIRO_STATUS_NO_MEMORY)
841 if (cairo_surface_status (surface)) {
842 MF (MEMFAULT_PRINT_FAULTS ());
843 cairo_test_log (ctx, "Error: Created an error surface: %s\n",
844 cairo_status_to_string (cairo_surface_status (surface)));
845 ret = CAIRO_TEST_FAILURE;
849 /* Check that we created a surface of the expected type. */
850 if (cairo_surface_get_type (surface) != target->expected_type) {
851 MF (MEMFAULT_PRINT_FAULTS ());
852 cairo_test_log (ctx, "Error: Created surface is of type %d (expected %d)\n",
853 cairo_surface_get_type (surface), target->expected_type);
854 ret = CAIRO_TEST_UNTESTED;
858 /* Check that we created a surface of the expected content,
859 * (ignore the artificial CAIRO_TEST_CONTENT_COLOR_ALPHA_FLATTENED value).
861 expected_content = cairo_boilerplate_content (target->content);
863 if (cairo_surface_get_content (surface) != expected_content) {
864 MF (MEMFAULT_PRINT_FAULTS ());
865 cairo_test_log (ctx, "Error: Created surface has content %d (expected %d)\n",
866 cairo_surface_get_content (surface), expected_content);
867 ret = CAIRO_TEST_FAILURE;
871 if (cairo_surface_set_user_data (surface,
872 &cairo_boilerplate_output_basename_key,
877 cairo_surface_destroy (surface);
880 target->cleanup (closure);
884 ret = CAIRO_TEST_FAILURE;
889 cairo_surface_set_device_offset (surface, dev_offset, dev_offset);
890 cairo_surface_set_device_scale (surface, dev_scale, dev_scale);
892 cr = cairo_create (surface);
893 if (cairo_set_user_data (cr, &_cairo_test_context_key, (void*) ctx, NULL)) {
896 cairo_surface_destroy (surface);
899 target->cleanup (closure);
903 ret = CAIRO_TEST_FAILURE;
909 cairo_push_group_with_content (cr, expected_content);
911 /* Clear to transparent (or black) depending on whether the target
912 * surface supports alpha. */
914 cairo_set_operator (cr, CAIRO_OPERATOR_CLEAR);
918 /* Set all components of font_options to avoid backend differences
919 * and reduce number of needed reference images. */
920 font_options = cairo_font_options_create ();
921 cairo_font_options_set_hint_style (font_options, CAIRO_HINT_STYLE_NONE);
922 cairo_font_options_set_hint_metrics (font_options, CAIRO_HINT_METRICS_ON);
923 cairo_font_options_set_antialias (font_options, CAIRO_ANTIALIAS_GRAY);
924 cairo_set_font_options (cr, font_options);
925 cairo_font_options_destroy (font_options);
928 alarm (ctx->timeout);
929 status = (ctx->test->draw) (cr, ctx->test->width, ctx->test->height);
934 cairo_pop_group_to_source (cr);
935 cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
940 MEMFAULT_DISABLE_FAULTS ();
942 /* repeat test after malloc failure injection */
943 if (ctx->malloc_failure &&
944 MEMFAULT_COUNT_FAULTS () - last_fault_count > 0 &&
945 (status == CAIRO_TEST_NO_MEMORY ||
946 cairo_status (cr) == CAIRO_STATUS_NO_MEMORY ||
947 cairo_surface_status (surface) == CAIRO_STATUS_NO_MEMORY))
950 cairo_surface_destroy (surface);
952 target->cleanup (closure);
953 cairo_debug_reset_static_data ();
957 if (MEMFAULT_COUNT_LEAKS () > 0) {
958 MEMFAULT_PRINT_FAULTS ();
959 MEMFAULT_PRINT_LEAKS ();
966 /* Then, check all the different ways it could fail. */
968 cairo_test_log (ctx, "Error: Function under test failed\n");
974 if (MEMFAULT_COUNT_FAULTS () - last_fault_count > 0 &&
975 MEMFAULT_HAS_FAULTS ())
977 VALGRIND_PRINTF ("Unreported memfaults...");
978 MEMFAULT_PRINT_FAULTS ();
982 if (target->finish_surface != NULL) {
984 /* We need to re-enable faults as most recording-surface processing
985 * is done during cairo_surface_finish().
987 MEMFAULT_CLEAR_FAULTS ();
988 last_fault_count = MEMFAULT_COUNT_FAULTS ();
989 MEMFAULT_ENABLE_FAULTS ();
992 /* also check for infinite loops whilst replaying */
993 alarm (ctx->timeout);
994 status = target->finish_surface (surface);
998 MEMFAULT_DISABLE_FAULTS ();
1000 if (ctx->malloc_failure &&
1001 MEMFAULT_COUNT_FAULTS () - last_fault_count > 0 &&
1002 status == CAIRO_STATUS_NO_MEMORY)
1005 cairo_surface_destroy (surface);
1006 if (target->cleanup)
1007 target->cleanup (closure);
1008 cairo_debug_reset_static_data ();
1012 if (MEMFAULT_COUNT_LEAKS () > 0) {
1013 MEMFAULT_PRINT_FAULTS ();
1014 MEMFAULT_PRINT_LEAKS ();
1021 cairo_test_log (ctx, "Error: Failed to finish surface: %s\n",
1022 cairo_status_to_string (status));
1023 ret = CAIRO_TEST_FAILURE;
1028 /* Skip image check for tests with no image (width,height == 0,0) */
1029 if (ctx->test->width != 0 && ctx->test->height != 0) {
1030 cairo_surface_t *ref_image;
1031 cairo_surface_t *test_image;
1032 cairo_surface_t *diff_image;
1033 buffer_diff_result_t result;
1034 cairo_status_t diff_status;
1036 if (ref_png_path == NULL) {
1037 cairo_test_log (ctx, "Error: Cannot find reference image for %s\n",
1040 /* we may be running this test to generate reference images */
1041 _xunlink (ctx, out_png_path);
1042 /* be more generous as we may need to use external renderers */
1043 alarm (4 * ctx->timeout);
1044 test_image = target->get_image_surface (surface, 0,
1048 diff_status = cairo_surface_write_to_png (test_image, out_png_path);
1049 cairo_surface_destroy (test_image);
1051 if (cairo_surface_status (test_image) == CAIRO_STATUS_INVALID_STATUS)
1052 ret = CAIRO_TEST_CRASHED;
1054 ret = CAIRO_TEST_FAILURE;
1055 cairo_test_log (ctx,
1056 "Error: Failed to write output image: %s\n",
1057 cairo_status_to_string (diff_status));
1061 ret = CAIRO_TEST_XFAILURE;
1065 if (target->file_extension != NULL) { /* compare vector surfaces */
1066 char *filenames[] = {
1075 base_xfail_png_path,
1078 xasprintf (&test_filename, "%s.out%s",
1079 base_path, target->file_extension);
1080 xasprintf (&pass_filename, "%s.pass%s",
1081 base_path, target->file_extension);
1082 xasprintf (&fail_filename, "%s.fail%s",
1083 base_path, target->file_extension);
1085 if (cairo_test_file_is_older (pass_filename,
1087 ARRAY_LENGTH (filenames)))
1089 _xunlink (ctx, pass_filename);
1091 if (cairo_test_file_is_older (fail_filename,
1093 ARRAY_LENGTH (filenames)))
1095 _xunlink (ctx, fail_filename);
1098 if (cairo_test_files_equal (out_png_path, ref_path)) {
1099 cairo_test_log (ctx, "Vector surface matches reference.\n");
1100 have_output = FALSE;
1101 ret = CAIRO_TEST_SUCCESS;
1104 if (cairo_test_files_equal (out_png_path, new_path)) {
1105 cairo_test_log (ctx, "Vector surface matches current failure.\n");
1106 have_output = FALSE;
1107 ret = CAIRO_TEST_NEW;
1110 if (cairo_test_files_equal (out_png_path, xfail_path)) {
1111 cairo_test_log (ctx, "Vector surface matches known failure.\n");
1112 have_output = FALSE;
1113 ret = CAIRO_TEST_XFAILURE;
1117 if (cairo_test_files_equal (test_filename, pass_filename)) {
1118 /* identical output as last known PASS */
1119 cairo_test_log (ctx, "Vector surface matches last pass.\n");
1121 ret = CAIRO_TEST_SUCCESS;
1124 if (cairo_test_files_equal (test_filename, fail_filename)) {
1125 /* identical output as last known FAIL, fail */
1126 cairo_test_log (ctx, "Vector surface matches last fail.\n");
1127 have_result = TRUE; /* presume these were kept around as well */
1129 ret = CAIRO_TEST_FAILURE;
1134 /* be more generous as we may need to use external renderers */
1135 alarm (4 * ctx->timeout);
1136 test_image = target->get_image_surface (surface, 0,
1140 if (cairo_surface_status (test_image)) {
1141 cairo_test_log (ctx, "Error: Failed to extract image: %s\n",
1142 cairo_status_to_string (cairo_surface_status (test_image)));
1143 if (cairo_surface_status (test_image) == CAIRO_STATUS_INVALID_STATUS)
1144 ret = CAIRO_TEST_CRASHED;
1146 ret = CAIRO_TEST_FAILURE;
1147 cairo_surface_destroy (test_image);
1151 _xunlink (ctx, out_png_path);
1152 diff_status = cairo_surface_write_to_png (test_image, out_png_path);
1154 cairo_test_log (ctx, "Error: Failed to write output image: %s\n",
1155 cairo_status_to_string (diff_status));
1156 cairo_surface_destroy (test_image);
1157 ret = CAIRO_TEST_FAILURE;
1162 /* binary compare png files (no decompression) */
1163 if (target->file_extension == NULL) {
1164 char *filenames[] = {
1170 base_xfail_png_path,
1173 xasprintf (&test_filename, "%s", out_png_path);
1174 xasprintf (&pass_filename, "%s.pass.png", base_path);
1175 xasprintf (&fail_filename, "%s.fail.png", base_path);
1177 if (cairo_test_file_is_older (pass_filename,
1179 ARRAY_LENGTH (filenames)))
1181 _xunlink (ctx, pass_filename);
1183 if (cairo_test_file_is_older (fail_filename,
1185 ARRAY_LENGTH (filenames)))
1187 _xunlink (ctx, fail_filename);
1190 if (cairo_test_files_equal (test_filename, pass_filename)) {
1191 cairo_test_log (ctx, "PNG file exactly matches last pass.\n");
1193 cairo_surface_destroy (test_image);
1194 ret = CAIRO_TEST_SUCCESS;
1197 if (cairo_test_files_equal (out_png_path, ref_png_path)) {
1198 cairo_test_log (ctx, "PNG file exactly matches reference image.\n");
1200 cairo_surface_destroy (test_image);
1201 ret = CAIRO_TEST_SUCCESS;
1204 if (cairo_test_files_equal (out_png_path, new_png_path)) {
1205 cairo_test_log (ctx, "PNG file exactly matches current failure image.\n");
1207 cairo_surface_destroy (test_image);
1208 ret = CAIRO_TEST_NEW;
1211 if (cairo_test_files_equal (out_png_path, xfail_png_path)) {
1212 cairo_test_log (ctx, "PNG file exactly matches known failure image.\n");
1214 cairo_surface_destroy (test_image);
1215 ret = CAIRO_TEST_XFAILURE;
1218 if (cairo_test_files_equal (test_filename, fail_filename)) {
1219 cairo_test_log (ctx, "PNG file exactly matches last fail.\n");
1220 have_result = TRUE; /* presume these were kept around as well */
1221 cairo_surface_destroy (test_image);
1222 ret = CAIRO_TEST_FAILURE;
1226 if (cairo_test_files_equal (out_png_path, ref_png_path)) {
1227 cairo_test_log (ctx, "PNG file exactly matches reference image.\n");
1229 cairo_surface_destroy (test_image);
1230 ret = CAIRO_TEST_SUCCESS;
1233 if (cairo_test_files_equal (out_png_path, new_png_path)) {
1234 cairo_test_log (ctx, "PNG file exactly matches current failure image.\n");
1236 cairo_surface_destroy (test_image);
1237 ret = CAIRO_TEST_NEW;
1240 if (cairo_test_files_equal (out_png_path, xfail_png_path)) {
1241 cairo_test_log (ctx, "PNG file exactly matches known failure image.\n");
1243 cairo_surface_destroy (test_image);
1244 ret = CAIRO_TEST_XFAILURE;
1249 if (cairo_test_files_equal (out_png_path, base_ref_png_path)) {
1250 cairo_test_log (ctx, "PNG file exactly reference image.\n");
1252 cairo_surface_destroy (test_image);
1253 ret = CAIRO_TEST_SUCCESS;
1256 if (cairo_test_files_equal (out_png_path, base_new_png_path)) {
1257 cairo_test_log (ctx, "PNG file exactly current failure image.\n");
1259 cairo_surface_destroy (test_image);
1260 ret = CAIRO_TEST_NEW;
1263 if (cairo_test_files_equal (out_png_path, base_xfail_png_path)) {
1264 cairo_test_log (ctx, "PNG file exactly known failure image.\n");
1266 cairo_surface_destroy (test_image);
1267 ret = CAIRO_TEST_XFAILURE;
1271 /* first compare against the ideal reference */
1272 ref_image = cairo_test_get_reference_image (ctx, base_ref_png_path,
1273 target->content == CAIRO_TEST_CONTENT_COLOR_ALPHA_FLATTENED);
1274 if (cairo_surface_status (ref_image)) {
1275 cairo_test_log (ctx, "Error: Cannot open reference image for %s: %s\n",
1277 cairo_status_to_string (cairo_surface_status (ref_image)));
1278 cairo_surface_destroy (test_image);
1279 ret = CAIRO_TEST_FAILURE;
1283 diff_image = cairo_image_surface_create (CAIRO_FORMAT_ARGB32,
1287 cmp_png_path = base_ref_png_path;
1288 diff_status = image_diff (ctx,
1289 test_image, ref_image, diff_image,
1291 _xunlink (ctx, diff_png_path);
1293 image_diff_is_failure (&result, target->error_tolerance))
1295 /* that failed, so check against the specific backend */
1296 ref_image = cairo_test_get_reference_image (ctx, ref_png_path,
1297 target->content == CAIRO_TEST_CONTENT_COLOR_ALPHA_FLATTENED);
1298 if (cairo_surface_status (ref_image)) {
1299 cairo_test_log (ctx, "Error: Cannot open reference image for %s: %s\n",
1301 cairo_status_to_string (cairo_surface_status (ref_image)));
1302 cairo_surface_destroy (test_image);
1303 ret = CAIRO_TEST_FAILURE;
1307 cmp_png_path = ref_png_path;
1308 diff_status = image_diff (ctx,
1309 test_image, ref_image,
1314 cairo_test_log (ctx, "Error: Failed to compare images: %s\n",
1315 cairo_status_to_string (diff_status));
1316 ret = CAIRO_TEST_FAILURE;
1318 else if (image_diff_is_failure (&result, target->error_tolerance))
1320 ret = CAIRO_TEST_FAILURE;
1322 diff_status = cairo_surface_write_to_png (diff_image,
1325 cairo_test_log (ctx, "Error: Failed to write differences image: %s\n",
1326 cairo_status_to_string (diff_status));
1331 cairo_test_copy_file (test_filename, fail_filename);
1335 cairo_test_copy_file (test_filename, pass_filename);
1340 cairo_test_copy_file (test_filename, pass_filename);
1343 /* If failed, compare against the current image output,
1344 * and attempt to detect systematic failures.
1346 if (ret == CAIRO_TEST_FAILURE) {
1347 char *image_out_path;
1350 cairo_test_reference_filename (ctx,
1356 CAIRO_TEST_OUT_SUFFIX,
1357 CAIRO_TEST_PNG_EXTENSION);
1358 if (image_out_path != NULL) {
1359 if (cairo_test_files_equal (out_png_path,
1362 ret = CAIRO_TEST_XFAILURE;
1367 cairo_image_surface_create_from_png (image_out_path);
1368 if (cairo_surface_status (ref_image) == CAIRO_STATUS_SUCCESS)
1370 diff_status = image_diff (ctx,
1371 test_image, ref_image,
1374 if (diff_status == CAIRO_STATUS_SUCCESS &&
1375 !image_diff_is_failure (&result, target->error_tolerance))
1377 ret = CAIRO_TEST_XFAILURE;
1380 cairo_surface_destroy (ref_image);
1384 free (image_out_path);
1388 cairo_surface_destroy (test_image);
1389 cairo_surface_destroy (diff_image);
1392 if (cairo_status (cr) != CAIRO_STATUS_SUCCESS) {
1393 cairo_test_log (ctx, "Error: Function under test left cairo status in an error state: %s\n",
1394 cairo_status_to_string (cairo_status (cr)));
1395 ret = CAIRO_TEST_ERROR;
1400 free (test_filename);
1401 free (fail_filename);
1402 free (pass_filename);
1404 test_filename = fail_filename = pass_filename = NULL;
1407 if (ret == CAIRO_TEST_FAILURE)
1408 MEMFAULT_PRINT_FAULTS ();
1412 cairo_surface_destroy (surface);
1414 if (target->cleanup)
1415 target->cleanup (closure);
1418 cairo_debug_reset_static_data ();
1424 if (MEMFAULT_COUNT_LEAKS () > 0) {
1425 if (ret != CAIRO_TEST_FAILURE)
1426 MEMFAULT_PRINT_FAULTS ();
1427 MEMFAULT_PRINT_LEAKS ();
1430 if (ret == CAIRO_TEST_SUCCESS && --malloc_failure_iterations > 0)
1435 cairo_test_log (ctx, "OUTPUT: %s\n", out_png_path);
1438 if (cmp_png_path == NULL) {
1439 /* XXX presume we matched the normal ref last time */
1440 cmp_png_path = ref_png_path;
1442 cairo_test_log (ctx,
1443 "REFERENCE: %s\nDIFFERENCE: %s\n",
1444 cmp_png_path, diff_png_path);
1448 free (out_png_path);
1449 free (ref_png_path);
1450 free (base_ref_png_path);
1452 free (new_png_path);
1453 free (base_new_png_path);
1455 free (xfail_png_path);
1456 free (base_xfail_png_path);
1458 free (diff_png_path);
1465 #if defined(HAVE_SIGNAL_H) && defined(HAVE_SETJMP_H)
1468 /* Used to catch crashes in a test, so that we report it as such and
1469 * continue testing, although one crasher may already have corrupted memory in
1470 * an nonrecoverable fashion. */
1471 static jmp_buf jmpbuf;
1474 segfault_handler (int signal)
1476 longjmp (jmpbuf, signal);
1481 _cairo_test_context_run_for_target (cairo_test_context_t *ctx,
1482 const cairo_boilerplate_target_t *target,
1483 cairo_bool_t similar,
1484 int dev_offset, int dev_scale)
1486 cairo_test_status_t status;
1488 if (target->get_image_surface == NULL)
1489 return CAIRO_TEST_UNTESTED;
1491 if (similar && ! cairo_test_target_has_similar (ctx, target))
1492 return CAIRO_TEST_UNTESTED;
1494 cairo_test_log (ctx,
1495 "Testing %s with %s%s target (dev offset %d scale: %d)\n",
1497 similar ? " (similar) " : "",
1499 dev_offset, dev_scale);
1501 printf ("%s.%s.%s [%dx%d]%s:\t", ctx->test_name, target->name,
1502 cairo_boilerplate_content_name (target->content),
1503 dev_offset, dev_scale,
1504 similar ? " (similar)": "");
1507 #if defined(HAVE_SIGNAL_H) && defined(HAVE_SETJMP_H)
1508 if (! RUNNING_ON_VALGRIND) {
1509 void (* volatile old_segfault_handler)(int);
1510 void (* volatile old_segfpe_handler)(int);
1511 void (* volatile old_sigpipe_handler)(int);
1512 void (* volatile old_sigabrt_handler)(int);
1513 void (* volatile old_sigalrm_handler)(int);
1515 /* Set up a checkpoint to get back to in case of segfaults. */
1517 old_segfault_handler = signal (SIGSEGV, segfault_handler);
1520 old_segfpe_handler = signal (SIGFPE, segfault_handler);
1523 old_sigpipe_handler = signal (SIGPIPE, segfault_handler);
1526 old_sigabrt_handler = signal (SIGABRT, segfault_handler);
1529 old_sigalrm_handler = signal (SIGALRM, segfault_handler);
1531 if (0 == setjmp (jmpbuf))
1532 status = cairo_test_for_target (ctx, target, dev_offset, dev_scale, similar);
1534 status = CAIRO_TEST_CRASHED;
1536 signal (SIGSEGV, old_segfault_handler);
1539 signal (SIGFPE, old_segfpe_handler);
1542 signal (SIGPIPE, old_sigpipe_handler);
1545 signal (SIGABRT, old_sigabrt_handler);
1548 signal (SIGALRM, old_sigalrm_handler);
1551 status = cairo_test_for_target (ctx, target, dev_offset, dev_scale, similar);
1554 status = cairo_test_for_target (ctx, target, dev_offset, dev_scale, similar);
1557 cairo_test_log (ctx,
1558 "TEST: %s TARGET: %s FORMAT: %s OFFSET: %d SCALE: %d SIMILAR: %d RESULT: ",
1559 ctx->test_name, target->name,
1560 cairo_boilerplate_content_name (target->content),
1561 dev_offset, dev_scale, similar);
1563 case CAIRO_TEST_SUCCESS:
1565 cairo_test_log (ctx, "PASS\n");
1568 case CAIRO_TEST_UNTESTED:
1569 printf ("UNTESTED\n");
1570 cairo_test_log (ctx, "UNTESTED\n");
1574 case CAIRO_TEST_CRASHED:
1575 if (print_fail_on_stdout) {
1576 printf ("!!!CRASHED!!!\n");
1578 /* eat the test name */
1582 cairo_test_log (ctx, "CRASHED\n");
1583 fprintf (stderr, "%s.%s.%s [%dx%d]%s:\t%s!!!CRASHED!!!%s\n",
1584 ctx->test_name, target->name,
1585 cairo_boilerplate_content_name (target->content), dev_offset, dev_scale, similar ? " (similar)" : "",
1586 fail_face, normal_face);
1589 case CAIRO_TEST_ERROR:
1590 if (print_fail_on_stdout) {
1591 printf ("!!!ERROR!!!\n");
1593 /* eat the test name */
1597 cairo_test_log (ctx, "ERROR\n");
1598 fprintf (stderr, "%s.%s.%s [%dx%d]%s:\t%s!!!ERROR!!!%s\n",
1599 ctx->test_name, target->name,
1600 cairo_boilerplate_content_name (target->content), dev_offset, dev_scale, similar ? " (similar)" : "",
1601 fail_face, normal_face);
1604 case CAIRO_TEST_XFAILURE:
1605 if (print_fail_on_stdout) {
1608 /* eat the test name */
1612 fprintf (stderr, "%s.%s.%s [%dx%d]%s:\t%sXFAIL%s\n",
1613 ctx->test_name, target->name,
1614 cairo_boilerplate_content_name (target->content), dev_offset, dev_scale, similar ? " (similar)" : "",
1615 xfail_face, normal_face);
1616 cairo_test_log (ctx, "XFAIL\n");
1619 case CAIRO_TEST_NEW:
1620 if (print_fail_on_stdout) {
1623 /* eat the test name */
1627 fprintf (stderr, "%s.%s.%s [%dx%d]%s:\t%sNEW%s\n",
1628 ctx->test_name, target->name,
1629 cairo_boilerplate_content_name (target->content), dev_offset, dev_scale, similar ? " (similar)" : "",
1630 fail_face, normal_face);
1631 cairo_test_log (ctx, "NEW\n");
1634 case CAIRO_TEST_NO_MEMORY:
1635 case CAIRO_TEST_FAILURE:
1636 if (print_fail_on_stdout) {
1639 /* eat the test name */
1643 fprintf (stderr, "%s.%s.%s [%dx%d]%s:\t%sFAIL%s\n",
1644 ctx->test_name, target->name,
1645 cairo_boilerplate_content_name (target->content), dev_offset, dev_scale, similar ? " (similar)" : "",
1646 fail_face, normal_face);
1647 cairo_test_log (ctx, "FAIL\n");
1655 const cairo_test_context_t *
1656 cairo_test_get_context (cairo_t *cr)
1658 return cairo_get_user_data (cr, &_cairo_test_context_key);
1662 cairo_test_create_surface_from_png (const cairo_test_context_t *ctx,
1663 const char *filename)
1665 cairo_surface_t *image;
1666 cairo_status_t status;
1668 image = cairo_image_surface_create_from_png (filename);
1669 status = cairo_surface_status (image);
1670 if (status == CAIRO_STATUS_FILE_NOT_FOUND) {
1671 /* expect not found when running with srcdir != builddir
1672 * such as when 'make distcheck' is run
1675 char *srcdir_filename;
1676 xasprintf (&srcdir_filename, "%s/%s", ctx->srcdir, filename);
1677 cairo_surface_destroy (image);
1678 image = cairo_image_surface_create_from_png (srcdir_filename);
1679 free (srcdir_filename);
1687 cairo_test_create_pattern_from_png (const cairo_test_context_t *ctx,
1688 const char *filename)
1690 cairo_surface_t *image;
1691 cairo_pattern_t *pattern;
1693 image = cairo_test_create_surface_from_png (ctx, filename);
1695 pattern = cairo_pattern_create_for_surface (image);
1697 cairo_pattern_set_extend (pattern, CAIRO_EXTEND_REPEAT);
1699 cairo_surface_destroy (image);
1704 static cairo_surface_t *
1705 _draw_check (int width, int height)
1707 cairo_surface_t *surface;
1710 surface = cairo_image_surface_create (CAIRO_FORMAT_RGB24, 12, 12);
1711 cr = cairo_create (surface);
1712 cairo_surface_destroy (surface);
1714 cairo_set_source_rgb (cr, 0.75, 0.75, 0.75); /* light gray */
1717 cairo_set_source_rgb (cr, 0.25, 0.25, 0.25); /* dark gray */
1718 cairo_rectangle (cr, width / 2, 0, width / 2, height / 2);
1719 cairo_rectangle (cr, 0, height / 2, width / 2, height / 2);
1722 surface = cairo_surface_reference (cairo_get_target (cr));
1729 cairo_test_paint_checkered (cairo_t *cr)
1731 cairo_surface_t *check;
1733 check = _draw_check (12, 12);
1736 cairo_set_source_surface (cr, check, 0, 0);
1737 cairo_surface_destroy (check);
1739 cairo_pattern_set_filter (cairo_get_source (cr), CAIRO_FILTER_NEAREST);
1740 cairo_pattern_set_extend (cairo_get_source (cr), CAIRO_EXTEND_REPEAT);
1747 cairo_test_is_target_enabled (const cairo_test_context_t *ctx,
1752 for (i = 0; i < ctx->num_targets; i++) {
1753 const cairo_boilerplate_target_t *t = ctx->targets_to_test[i];
1754 if (strcmp (t->name, target) == 0) {
1755 /* XXX ask the target whether is it possible to run?
1756 * e.g. the xlib backend could check whether it is able to connect
1759 return t->get_image_surface != NULL;
1767 cairo_test_malloc_failure (const cairo_test_context_t *ctx,
1768 cairo_status_t status)
1770 if (! ctx->malloc_failure)
1773 if (status != CAIRO_STATUS_NO_MEMORY)
1780 /* prevent infinite loops... */
1781 n_faults = MEMFAULT_COUNT_FAULTS ();
1782 if (n_faults == ctx->last_fault_count)
1785 ((cairo_test_context_t *) ctx)->last_fault_count = n_faults;
1793 cairo_test_status_from_status (const cairo_test_context_t *ctx,
1794 cairo_status_t status)
1796 if (status == CAIRO_STATUS_SUCCESS)
1797 return CAIRO_TEST_SUCCESS;
1799 if (cairo_test_malloc_failure (ctx, status))
1800 return CAIRO_TEST_NO_MEMORY;
1802 return CAIRO_TEST_FAILURE;