1
/*
2
 * Copyright © 2004 Red Hat, Inc.
3
 *
4
 * Permission to use, copy, modify, distribute, and sell this software
5
 * and its documentation for any purpose is hereby granted without
6
 * fee, provided that the above copyright notice appear in all copies
7
 * and that both that copyright notice and this permission notice
8
 * appear in supporting documentation, and that the name of
9
 * Red Hat, Inc. not be used in advertising or publicity pertaining to
10
 * distribution of the software without specific, written prior
11
 * permission. Red Hat, Inc. makes no representations about the
12
 * suitability of this software for any purpose.  It is provided "as
13
 * is" without express or implied warranty.
14
 *
15
 * RED HAT, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
16
 * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
17
 * FITNESS, IN NO EVENT SHALL RED HAT, INC. BE LIABLE FOR ANY SPECIAL,
18
 * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
19
 * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
20
 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
21
 * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
22
 *
23
 * Author: Carl D. Worth <cworth@cworth.org>
24
 */
25

            
26
#ifndef _CAIRO_TEST_H_
27
#define _CAIRO_TEST_H_
28

            
29
#include "cairo-boilerplate.h"
30

            
31
#include <stdarg.h>
32

            
33
CAIRO_BEGIN_DECLS
34

            
35
#if   HAVE_STDINT_H
36
# include <stdint.h>
37
#elif HAVE_INTTYPES_H
38
# include <inttypes.h>
39
#elif HAVE_SYS_INT_TYPES_H
40
# include <sys/int_types.h>
41
#elif defined(_MSC_VER)
42
typedef __int8 int8_t;
43
typedef unsigned __int8 uint8_t;
44
typedef __int16 int16_t;
45
typedef unsigned __int16 uint16_t;
46
typedef __int32 int32_t;
47
typedef unsigned __int32 uint32_t;
48
typedef __int64 int64_t;
49
typedef unsigned __int64 uint64_t;
50
# ifndef HAVE_UINT64_T
51
#  define HAVE_UINT64_T 1
52
# endif
53
#else
54
#error Cannot find definitions for fixed-width integral types (uint8_t, uint32_t, \etc.)
55
#endif
56

            
57
#ifdef _MSC_VER
58
#include <float.h>
59
#endif
60

            
61
#if HAVE_FENV_H
62
# include <fenv.h>
63
#endif
64
/* The following are optional in C99, so define them if they aren't yet */
65
#ifndef FE_DIVBYZERO
66
#define FE_DIVBYZERO 0
67
#endif
68
#ifndef FE_INEXACT
69
#define FE_INEXACT 0
70
#endif
71
#ifndef FE_INVALID
72
#define FE_INVALID 0
73
#endif
74
#ifndef FE_OVERFLOW
75
#define FE_OVERFLOW 0
76
#endif
77
#ifndef FE_UNDERFLOW
78
#define FE_UNDERFLOW 0
79
#endif
80

            
81
#include <math.h>
82

            
83
static inline double
84
273
cairo_test_NaN (void)
85
{
86
#ifdef _MSC_VER
87
    /* MSVC strtod("NaN", NULL) returns 0.0 */
88
    union {
89
	uint32_t i[2];
90
	double d;
91
    } nan = {{0xffffffff, 0x7fffffff}};
92
    return nan.d;
93
#else
94
273
    return strtod("NaN", NULL);
95
#endif
96
}
97

            
98
#ifndef MIN
99
#define MIN(a, b) ((a) < (b) ? (a) : (b))
100
#endif
101

            
102
#ifndef MAX
103
#define MAX(a, b) ((a) > (b) ? (a) : (b))
104
#endif
105

            
106
#define CAIRO_TEST_OUTPUT_DIR "output"
107

            
108
#define CAIRO_TEST_LOG_SUFFIX ".log"
109

            
110
#define CAIRO_TEST_FONT_FAMILY "DejaVu"
111

            
112
/* What is a fail and what isn't?
113
 * When running the test suite we want to detect unexpected output. This
114
 * can be caused by a change we have made to cairo itself, or a change
115
 * in our environment. To capture this we classify the expected output into 3
116
 * classes:
117
 *
118
 *   REF  -- Perfect output.
119
 *           Might be different for each backend, due to slight implementation
120
 *           differences.
121
 *
122
 *   NEW  -- A new failure. We have uncovered a bug within cairo and have
123
 *           recorded the current failure (along with the expected output
124
 *           if possible!) so we can detect any changes in our attempt to
125
 *           fix the bug.
126
 *
127
 *  XFAIL -- An external failure. We believe the cairo output is perfect,
128
 *           but an external renderer is causing gross failure.
129
 *           (We also use this to capture current WONTFIX issues within cairo,
130
 *           such as overflow in internal coordinates, so as not to distract
131
 *           us when regression testing.)
132
 *
133
 *  If no REF is given for a test, then it is assumed to be XFAIL.
134
 */
135
#define CAIRO_TEST_REF_SUFFIX ".ref"
136
#define CAIRO_TEST_XFAIL_SUFFIX ".xfail"
137
#define CAIRO_TEST_NEW_SUFFIX ".new"
138

            
139
#define CAIRO_TEST_OUT_SUFFIX ".out"
140
#define CAIRO_TEST_DIFF_SUFFIX ".diff"
141

            
142
#define CAIRO_TEST_PNG_EXTENSION ".png"
143
#define CAIRO_TEST_OUT_PNG CAIRO_TEST_OUT_SUFFIX CAIRO_TEST_PNG_EXTENSION
144
#define CAIRO_TEST_REF_PNG CAIRO_TEST_REF_SUFFIX CAIRO_TEST_PNG_EXTENSION
145
#define CAIRO_TEST_DIFF_PNG CAIRO_TEST_DIFF_SUFFIX CAIRO_TEST_PNG_EXTENSION
146

            
147
typedef enum cairo_test_status {
148
    CAIRO_TEST_SUCCESS = 0,
149
    CAIRO_TEST_NO_MEMORY,
150
    CAIRO_TEST_FAILURE,
151
    CAIRO_TEST_NEW,
152
    CAIRO_TEST_XFAILURE,
153
    CAIRO_TEST_ERROR,
154
    CAIRO_TEST_CRASHED,
155
    CAIRO_TEST_UNTESTED = 77 /* match automake's skipped exit status */
156
} cairo_test_status_t;
157

            
158
typedef struct _cairo_test_context cairo_test_context_t;
159
typedef struct _cairo_test cairo_test_t;
160

            
161
typedef cairo_test_status_t
162
(cairo_test_preamble_function_t) (cairo_test_context_t *ctx);
163

            
164
typedef cairo_test_status_t
165
(cairo_test_draw_function_t) (cairo_t *cr, int width, int height);
166

            
167
struct _cairo_test {
168
    const char *name;
169
    const char *description;
170
    const char *keywords;
171
    const char *requirements;
172
    double width;
173
    double height;
174
    cairo_test_preamble_function_t *preamble;
175
    cairo_test_draw_function_t *draw;
176
};
177

            
178
/* The standard test interface which works by examining result image.
179
 *
180
 * CAIRO_TEST() constructs a test which will be called once before (the
181
 * preamble callback), and then once for each testable backend (the draw
182
 * callback). The following checks will be performed for each backend:
183
 *
184
 * 1) If preamble() returns CAIRO_TEST_UNTESTED, the test is skipped.
185
 *
186
 * 2) If preamble() does not return CAIRO_TEST_SUCCESS, the test fails.
187
 *
188
 * 3) If draw() does not return CAIRO_TEST_SUCCESS then this backend
189
 *    fails.
190
 *
191
 * 4) Otherwise, if cairo_status(cr) indicates an error then this
192
 *    backend fails.
193
 *
194
 * 5) Otherwise, if the image size is 0, then this backend passes.
195
 *
196
 * 6) Otherwise, if every channel of every pixel exactly matches the
197
 *    reference image then this backend passes. If not, this backend
198
 *    fails.
199
 *
200
 * The overall test result is PASS if and only if there is at least
201
 * one backend that is tested and if all tested backend pass according
202
 * to the four criteria above.
203
 */
204
#define CAIRO_TEST(name, description, keywords, requirements, width, height, preamble, draw) \
205
void _register_##name (void); \
206
void _register_##name (void) { \
207
    static cairo_test_t test = { \
208
	#name, description, \
209
	keywords, requirements, \
210
	width, height, \
211
	preamble, draw \
212
    }; \
213
    cairo_test_register (&test); \
214
}
215

            
216
void
217
cairo_test_register (cairo_test_t *test);
218

            
219
/* The full context for the test.
220
 * For ordinary tests (using the CAIRO_TEST()->draw interface) the context
221
 * is passed to the draw routine via user_data on the cairo_t.
222
 * The reason why the context is not passed as an explicit parameter is that
223
 * it is rarely required by the test itself and by removing the parameter
224
 * we can keep the draw routines simple and serve as example code.
225
 *
226
 * In contrast, for the preamble phase the context is passed as the only
227
 * parameter.
228
 */
229
struct _cairo_test_context {
230
    const cairo_test_t *test;
231
    const char *test_name;
232

            
233
    FILE *log_file;
234
    const char *output;
235
    const char *srcdir; /* directory containing sources and input data */
236
    char *refdir; /* directory containing reference images */
237

            
238
    char *ref_name; /* cache of the current reference image */
239
    cairo_surface_t *ref_image;
240
    cairo_surface_t *ref_image_flattened;
241

            
242
    size_t num_targets;
243
    cairo_bool_t limited_targets;
244
    const cairo_boilerplate_target_t **targets_to_test;
245
    cairo_bool_t own_targets;
246

            
247
    int malloc_failure;
248
    int last_fault_count;
249

            
250
    int timeout;
251
};
252

            
253
/* Retrieve the test context from the cairo_t, used for logging, paths etc */
254
const cairo_test_context_t *
255
cairo_test_get_context (cairo_t *cr);
256

            
257

            
258
/* Print a message to the log file, ala printf. */
259
void
260
cairo_test_log (const cairo_test_context_t *ctx,
261
	        const char *fmt, ...) CAIRO_BOILERPLATE_PRINTF_FORMAT(2, 3);
262
void
263
cairo_test_logv (const cairo_test_context_t *ctx,
264
	        const char *fmt, va_list ap) CAIRO_BOILERPLATE_PRINTF_FORMAT(2, 0);
265

            
266
/* Helper functions that take care of finding source images even when
267
 * building in a non-srcdir manner, (i.e. the tests will be run in a
268
 * directory that is different from the one where the source image
269
 * exists). */
270
cairo_surface_t *
271
cairo_test_create_surface_from_png (const cairo_test_context_t *ctx,
272
	                            const char *filename);
273

            
274
cairo_pattern_t *
275
cairo_test_create_pattern_from_png (const cairo_test_context_t *ctx,
276
	                            const char *filename);
277

            
278
void
279
cairo_test_paint_checkered (cairo_t *cr);
280

            
281
#define CAIRO_TEST_DOUBLE_EQUALS(a,b)  (fabs((a)-(b)) < 0.00001)
282

            
283
cairo_bool_t
284
cairo_test_is_target_enabled (const cairo_test_context_t *ctx,
285
	                      const char *target);
286

            
287
char *
288
cairo_test_get_name (const cairo_test_t *test);
289

            
290
cairo_bool_t
291
cairo_test_malloc_failure (const cairo_test_context_t *ctx,
292
	                   cairo_status_t status);
293

            
294
cairo_test_status_t
295
cairo_test_status_from_status (const cairo_test_context_t *ctx,
296
			       cairo_status_t status);
297

            
298
char *
299
cairo_test_reference_filename (const cairo_test_context_t *ctx,
300
			       const char *base_name,
301
			       const char *test_name,
302
			       const char *target_name,
303
			       const char *base_target_name,
304
			       const char *format,
305
			       const char *suffix,
306
			       const char *extension);
307

            
308
cairo_surface_t *
309
cairo_test_get_reference_image (cairo_test_context_t *ctx,
310
				const char *filename,
311
				cairo_bool_t flatten);
312

            
313
cairo_bool_t
314
cairo_test_mkdir (const char *path);
315

            
316
cairo_t *
317
cairo_test_create (cairo_surface_t *surface,
318
		   const cairo_test_context_t *ctx);
319

            
320
/* Set font face from a font file in build or src dir, using the FT backend. */
321
cairo_test_status_t
322
cairo_test_ft_select_font_from_file (cairo_t      *cr,
323
                                     const char   *filename);
324

            
325
CAIRO_END_DECLS
326

            
327
#endif