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 */
39 #if HAVE_FEENABLEEXCEPT
49 #include <fontconfig/fontconfig.h>
61 #define RUNNING_ON_VALGRIND 0
71 #include "cairo-test-private.h"
73 #include "buffer-diff.h"
77 #define vsnprintf _vsnprintf
78 #define access _access
89 static const cairo_user_data_key_t _cairo_test_context_key
;
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
107 _cairo_test_fixup_name (const char *original
)
109 int len
= strlen (original
);
112 name
= xmalloc (len
+ 1);
113 s
= memcpy (name
, original
, len
+ 1);
114 while ((s
= strchr (s
, '_')) != NULL
)
121 cairo_test_get_name (const cairo_test_t
*test
)
123 return _cairo_test_fixup_name (test
->name
);
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
)
135 MF (MEMFAULT_DISABLE_FAULTS ());
137 #if HAVE_FEENABLEEXCEPT
138 feenableexcept (FE_DIVBYZERO
| FE_INVALID
| FE_OVERFLOW
);
142 ctx
->test_name
= _cairo_test_fixup_name (test_name
);
143 ctx
->expectation
= expectation
;
145 ctx
->malloc_failure
= 0;
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;
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
;
167 ctx
->ref_name
= NULL
;
168 ctx
->ref_image
= NULL
;
169 ctx
->ref_image_flattened
= NULL
;
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
;
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
)
194 ctx
->refdir
= getenv ("CAIRO_REF_DIR");
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";
203 print_fail_on_stdout
= FALSE
;
207 printf ("\nTESTING %s\n", ctx
->test_name
);
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
);
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
);
226 cairo_test_init_thread (cairo_test_context_t
*ctx
,
227 cairo_test_context_t
*master
,
230 MF (MEMFAULT_DISABLE_FAULTS ());
233 ctx
->thread
= thread
;
237 cairo_test_fini (cairo_test_context_t
*ctx
)
239 if (ctx
->thread
!= 0)
242 if (ctx
->log_file
== NULL
)
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 ();
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
, ...)
278 FILE *file
= ctx
&& ctx
->log_file
? ctx
->log_file
: stderr
;
281 vfprintf (file
, fmt
, va
);
286 cairo_test_log_path (const cairo_test_context_t
*ctx
,
287 const cairo_path_t
*path
)
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
:
296 " cairo_move_to (cr, %g, %g);\n",
297 data
[1].point
.x
, data
[1].point
.y
);
299 case CAIRO_PATH_LINE_TO
:
301 " cairo_line_to (cr, %g, %g);\n",
302 data
[1].point
.x
, data
[1].point
.y
);
304 case CAIRO_PATH_CURVE_TO
:
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
);
311 case CAIRO_PATH_CLOSE_PATH
:
313 " cairo_close_path (cr);\n\n");
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
));
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
,
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",
346 CAIRO_TEST_PNG_SUFFIX
);
347 if (access (ref_name
, F_OK
) != 0)
353 /* Next look for a target/format-specific reference image. */
354 xasprintf (&ref_name
, "%s/%s.%s.%s%s",
359 CAIRO_TEST_REF_SUFFIX
);
360 if (access (ref_name
, F_OK
) != 0)
365 /* Next, look for target-specific reference image. */
366 xasprintf (&ref_name
, "%s/%s.%s%s",
370 CAIRO_TEST_REF_SUFFIX
);
371 if (access (ref_name
, F_OK
) != 0)
376 /* Next look for a base/format-specific reference image. */
377 xasprintf (&ref_name
, "%s/%s.%s.%s%s",
382 CAIRO_TEST_REF_SUFFIX
);
383 if (access (ref_name
, F_OK
) != 0)
388 /* Next, look for base-specific reference image. */
389 xasprintf (&ref_name
, "%s/%s.%s%s",
393 CAIRO_TEST_REF_SUFFIX
);
394 if (access (ref_name
, F_OK
) != 0)
399 /* Next, look for format-specific reference image. */
400 xasprintf (&ref_name
, "%s/%s.%s%s",
404 CAIRO_TEST_REF_SUFFIX
);
405 if (access (ref_name
, F_OK
) != 0)
410 /* Finally, look for the standard reference image. */
411 xasprintf (&ref_name
, "%s/%s%s", ctx
->srcdir
,
413 CAIRO_TEST_REF_SUFFIX
);
414 if (access (ref_name
, F_OK
) != 0)
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
;
432 cairo_surface_t
*similar
;
433 cairo_status_t status
;
436 /* ignore image intermediate targets */
437 if (target
->expected_type
== CAIRO_SURFACE_TYPE_IMAGE
)
440 if (getenv ("CAIRO_TEST_IGNORE_SIMILAR"))
445 surface
= (target
->create_surface
) (ctx
->test
->name
,
449 ctx
->test
->width
+ 25 * NUM_DEVICE_OFFSETS
,
450 ctx
->test
->height
+ 25 * NUM_DEVICE_OFFSETS
,
451 CAIRO_BOILERPLATE_MODE_TEST
,
456 } while (cairo_test_malloc_failure (ctx
, cairo_surface_status (surface
)));
458 if (cairo_surface_status (surface
))
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
);
471 cairo_surface_destroy (surface
);
474 target
->cleanup (closure
);
475 } while (cairo_test_malloc_failure (ctx
, status
));
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
;
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);
502 cairo_set_source_surface (cr
, ctx
->ref_image
, 0, 0);
505 surface
= cairo_surface_reference (cairo_get_target (cr
));
508 if (cairo_surface_status (surface
) == CAIRO_STATUS_SUCCESS
)
509 ctx
->ref_image_flattened
= surface
;
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
;
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
))
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
);
548 cairo_test_file_is_older (const char *filename
,
549 const char *ref_filename
)
554 if (stat (filename
, &st
) < 0)
557 if (stat (ref_filename
, &ref
) < 0)
560 return st
.st_mtime
< ref
.st_mtime
;
568 cairo_test_files_equal (const char *test_filename
,
569 const char *pass_filename
)
574 test
= fopen (test_filename
, "rb");
578 pass
= fopen (pass_filename
, "rb");
584 /* as simple as it gets */
590 } while (t
!= EOF
&& p
!= EOF
);
595 return t
== p
; /* both EOF */
599 cairo_test_copy_file (const char *src_filename
,
600 const char *dst_filename
)
606 if (link (src_filename
, dst_filename
) == 0)
609 unlink (dst_filename
);
612 src
= fopen (src_filename
, "rb");
616 dst
= fopen (dst_filename
, "wb");
622 /* as simple as it gets */
623 while ((c
= getc (src
)) != EOF
)
633 _cairo_test_mkdir (const char *path
)
637 #elif HAVE_MKDIR == 1
638 if (mkdir (path
) == 0)
640 #elif HAVE_MKDIR == 2
641 if (mkdir (path
, 0770) == 0)
644 #error Bad value for HAVE_MKDIR
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
,
654 cairo_bool_t similar
)
656 cairo_test_status_t status
;
657 cairo_surface_t
*surface
= NULL
;
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
;
668 cairo_bool_t have_output
= FALSE
;
669 cairo_bool_t have_result
= FALSE
;
671 double width
, height
;
672 cairo_bool_t have_output_dir
;
674 int malloc_failure_iterations
= ctx
->malloc_failure
;
675 int last_fault_count
= 0;
678 /* Get the strings ready that we'll need. */
679 format
= cairo_boilerplate_content_name (target
->content
);
681 xasprintf (&offset_str
, ".%d", dev_offset
);
683 offset_str
= (char *) empty_str
;
685 xasprintf (&thread_str
, ".thread%d", ctx
->thread
);
687 thread_str
= (char *) empty_str
;
689 xasprintf (&base_name
, "%s.%s.%s%s%s%s",
693 similar
? ".similar" : "",
697 if (offset_str
!= empty_str
)
699 if (thread_str
!= empty_str
)
703 ref_path
= cairo_test_reference_image_filename (ctx
,
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
: ".",
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",
724 ret
= CAIRO_TEST_UNTESTED
;
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",
733 ret
= CAIRO_TEST_UNTESTED
;
738 width
= ctx
->test
->width
;
739 height
= ctx
->test
->height
;
740 if (width
&& height
) {
742 height
+= dev_offset
;
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).
759 MEMFAULT_ENABLE_FAULTS ();
764 /* Run the actual drawing code. */
765 ret
= CAIRO_TEST_SUCCESS
;
766 surface
= (target
->create_surface
) (base_path
,
769 ctx
->test
->width
+ 25 * NUM_DEVICE_OFFSETS
,
770 ctx
->test
->height
+ 25 * NUM_DEVICE_OFFSETS
,
771 CAIRO_BOILERPLATE_MODE_TEST
,
774 if (surface
== NULL
) {
775 cairo_test_log (ctx
, "Error: Failed to set %s target\n", target
->name
);
776 ret
= CAIRO_TEST_UNTESTED
;
781 if (ctx
->malloc_failure
&&
782 MEMFAULT_COUNT_FAULTS () - last_fault_count
> 0 &&
783 cairo_surface_status (surface
) == CAIRO_STATUS_NO_MEMORY
)
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
;
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
;
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
;
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
)) {
824 cairo_surface_destroy (surface
);
827 target
->cleanup (closure
);
831 ret
= CAIRO_TEST_FAILURE
;
837 cairo_push_group_with_content (cr
, expected_content
);
839 /* Clear to transparent (or black) depending on whether the target
840 * surface supports alpha. */
842 cairo_set_operator (cr
, CAIRO_OPERATOR_CLEAR
);
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
);
857 alarm (ctx
->timeout
);
859 status
= (ctx
->test
->draw
) (cr
, ctx
->test
->width
, ctx
->test
->height
);
866 cairo_pop_group_to_source (cr
);
867 cairo_set_operator (cr
, CAIRO_OPERATOR_SOURCE
);
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
))
882 cairo_surface_destroy (surface
);
884 target
->cleanup (closure
);
885 if (ctx
->thread
== 0) {
886 cairo_debug_reset_static_data ();
890 if (MEMFAULT_COUNT_LEAKS () > 0) {
891 MEMFAULT_PRINT_FAULTS ();
892 MEMFAULT_PRINT_LEAKS ();
900 /* Then, check all the different ways it could fail. */
902 cairo_test_log (ctx
, "Error: Function under test failed\n");
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
;
915 if (MEMFAULT_COUNT_FAULTS () - last_fault_count
> 0 &&
916 MEMFAULT_HAS_FAULTS ())
918 VALGRIND_PRINTF ("Unreported memfaults...");
919 MEMFAULT_PRINT_FAULTS ();
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
) {
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 ();
941 diff_status
= target
->finish_surface (surface
);
944 MEMFAULT_DISABLE_FAULTS ();
946 if (ctx
->malloc_failure
&&
947 MEMFAULT_COUNT_FAULTS () - last_fault_count
> 0 &&
948 diff_status
== CAIRO_STATUS_NO_MEMORY
)
951 cairo_surface_destroy (surface
);
953 target
->cleanup (closure
);
954 if (ctx
->thread
== 0) {
955 cairo_debug_reset_static_data ();
959 if (MEMFAULT_COUNT_LEAKS () > 0) {
960 MEMFAULT_PRINT_FAULTS ();
961 MEMFAULT_PRINT_LEAKS ();
969 cairo_test_log (ctx
, "Error: Failed to finish surface: %s\n",
970 cairo_status_to_string (diff_status
));
971 ret
= CAIRO_TEST_FAILURE
;
976 if (ref_path
== NULL
) {
977 cairo_test_log (ctx
, "Error: Cannot find reference image for %s\n",
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,
985 diff_status
= cairo_surface_write_to_png (test_image
, png_path
);
988 "Error: Failed to write output image: %s\n",
989 cairo_status_to_string (diff_status
));
992 cairo_surface_destroy (test_image
);
994 ret
= CAIRO_TEST_FAILURE
;
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");
1015 ret
= CAIRO_TEST_SUCCESS
;
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 */
1023 ret
= CAIRO_TEST_FAILURE
;
1028 test_image
= target
->get_image_surface (surface
, 0,
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
;
1039 _xunlink (ctx
, png_path
);
1040 diff_status
= cairo_surface_write_to_png (test_image
, png_path
);
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
;
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
;
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
;
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
;
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
;
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",
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
;
1100 diff_image
= cairo_image_surface_create (CAIRO_FORMAT_ARGB32
,
1104 diff_status
= image_diff (ctx
,
1105 test_image
, ref_image
,
1108 _xunlink (ctx
, diff_path
);
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
);
1121 cairo_test_log (ctx
, "Error: Failed to write differences image: %s\n",
1122 cairo_status_to_string (diff_status
));
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
);
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
;
1150 if (ret
== CAIRO_TEST_FAILURE
&& ctx
->expectation
!= CAIRO_TEST_FAILURE
)
1151 MEMFAULT_PRINT_FAULTS ();
1155 cairo_surface_destroy (surface
);
1157 if (target
->cleanup
)
1158 target
->cleanup (closure
);
1161 if (ctx
->thread
== 0) {
1162 cairo_debug_reset_static_data ();
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)
1182 if (ctx
->thread
== 0) {
1184 cairo_test_log (ctx
, "OUTPUT: %s\n", png_path
);
1187 cairo_test_log (ctx
,
1188 "REFERENCE: %s\nDIFFERENCE: %s\n",
1189 ref_path
, diff_path
);
1208 #if defined(HAVE_SIGNAL_H) && defined(HAVE_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
;
1217 segfault_handler (int signal
)
1219 longjmp (jmpbuf
, signal
);
1224 _cairo_test_context_run_for_target (cairo_test_context_t
*ctx
,
1225 const cairo_boilerplate_target_t
*target
,
1226 cairo_bool_t similar
,
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",
1240 similar
? " (similar) " : "",
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
),
1248 similar
? " (similar)": "");
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. */
1261 old_segfault_handler
= signal (SIGSEGV
, segfault_handler
);
1264 old_sigpipe_handler
= signal (SIGPIPE
, segfault_handler
);
1267 old_sigabrt_handler
= signal (SIGABRT
, segfault_handler
);
1270 old_sigalrm_handler
= signal (SIGALRM
, segfault_handler
);
1272 if (0 == setjmp (jmpbuf
))
1273 status
= cairo_test_for_target (ctx
, target
, dev_offset
, similar
);
1275 status
= CAIRO_TEST_CRASHED
;
1277 signal (SIGSEGV
, old_segfault_handler
);
1280 signal (SIGPIPE
, old_sigpipe_handler
);
1283 signal (SIGABRT
, old_sigabrt_handler
);
1286 signal (SIGALRM
, old_sigalrm_handler
);
1289 status
= cairo_test_for_target (ctx
, target
, dev_offset
, similar
);
1292 status
= cairo_test_for_target (ctx
, target
, dev_offset
, similar
);
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
);
1302 case CAIRO_TEST_SUCCESS
:
1304 cairo_test_log (ctx
, "PASS\n");
1306 case CAIRO_TEST_UNTESTED
:
1307 printf ("UNTESTED\n");
1308 cairo_test_log (ctx
, "UNTESTED\n");
1310 case CAIRO_TEST_CRASHED
:
1311 if (print_fail_on_stdout
&& ctx
->thread
== 0) {
1312 printf ("!!!CRASHED!!!\n");
1314 /* eat the test name */
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
);
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) {
1331 /* eat the test name */
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");
1341 if (print_fail_on_stdout
&& ctx
->thread
== 0) {
1344 /* eat the test name */
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");
1358 #if _POSIX_THREAD_SAFE_FUNCTIONS
1361 printf ("%s.%s.%s %d [%d]:\t",
1362 ctx
->test_name
, target
->name
,
1363 cairo_boilerplate_content_name (target
->content
),
1367 case CAIRO_TEST_SUCCESS
:
1370 case CAIRO_TEST_UNTESTED
:
1371 printf ("UNTESTED\n");
1373 case CAIRO_TEST_CRASHED
:
1374 printf ("!!!CRASHED!!!\n");
1377 case CAIRO_TEST_NO_MEMORY
:
1378 case CAIRO_TEST_FAILURE
:
1379 if (ctx
->expectation
== CAIRO_TEST_FAILURE
) {
1388 #if _POSIX_THREAD_SAFE_FUNCTIONS
1389 funlockfile (stdout
);
1397 _cairo_test_context_run (cairo_test_context_t
*ctx
)
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
)
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.
1415 * if backends limited and no backend tested
1417 * else if any backend not SUCCESS
1419 * else if all backends UNTESTED
1421 * else (== some backend 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
,
1441 if (ret
== CAIRO_TEST_UNTESTED
)
1451 typedef struct _cairo_test_thread
{
1453 cairo_test_context_t
*ctx
;
1455 } cairo_test_thread_t
;
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
;
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
;
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");
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
;
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
++) {
1506 pthread_join (threads
[n
].thread
, &tmp
);
1507 if (ret
== CAIRO_TEST_SUCCESS
)
1508 ret
= (cairo_test_status_t
) tmp
;
1513 if (ret
== CAIRO_TEST_SUCCESS
)
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
);
1540 cairo_test (const cairo_test_t
*test
)
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
);
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
);
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
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
);
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
);
1600 static cairo_surface_t
*
1601 _draw_check (int width
, int height
)
1603 cairo_surface_t
*surface
;
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 */
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);
1618 surface
= cairo_surface_reference (cairo_get_target (cr
));
1625 cairo_test_paint_checkered (cairo_t
*cr
)
1627 cairo_surface_t
*check
;
1629 check
= _draw_check (12, 12);
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
);
1643 cairo_test_is_target_enabled (const cairo_test_context_t
*ctx
,
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
1655 return t
->get_image_surface
!= NULL
;
1663 cairo_test_malloc_failure (const cairo_test_context_t
*ctx
,
1664 cairo_status_t status
)
1666 if (! ctx
->malloc_failure
)
1669 if (status
!= CAIRO_STATUS_NO_MEMORY
)
1676 /* prevent infinite loops... */
1677 n_faults
= MEMFAULT_COUNT_FAULTS ();
1678 if (n_faults
== ctx
->last_fault_count
)
1681 ((cairo_test_context_t
*) ctx
)->last_fault_count
= n_faults
;
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
;