53891bd7bd7fce84f16c778d177ba31fb9810a8c
[framework/graphics/cairo.git] / test / api-special-cases.c
1 /*
2  * Copyright © 2010 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: Benjamin Otte <otte@redhat.com>
24  */
25
26 /*
27  * WHAT THIS TEST DOES
28  *
29  * This test tests that for all public APIs Cairo behaves correct, consistent
30  * and most of all doesn't crash. It does this by calling all APIs that take
31  * surfaces and calling them on specially prepared surfaces that should fail 
32  * when called on this function.
33  *
34  * ADDING NEW FUNCTIONS
35  *
36  * You need (for adding the function cairo_surface_foo):
37  * 1) A surface_test_func_t named test_cairo_surface_foo that gets passed the
38  *    prepared surface and has the job of calling the function and checking
39  *    the return value (if one exists) for correctness. The top of this file
40  *    contains all these shim functions.
41  * 2) Knowledge if the function behaves like a setter or like a getter. A 
42  *    setter should set an error status on the surface, a getter does not
43  *    modify the function.
44  * 3) Knowledge if the function only works for a specific surface type and for
45  *    which one.
46  * 4) An entry in the tests array using the TEST() macro. It takes as arguments:
47  *    - The function name
48  *    - TRUE if the function modifies the surface, FALSE otherwise
49  *    - the surface type for which the function is valid or -1 if it is valid
50  *      for all surface types.
51  *
52  * FIXING FAILURES
53  *
54  * The test will dump failures notices into the api-special-cases.log file (when 
55  * it doesn't crash). These should be pretty self-explanatory. Usually it is 
56  * enough to just add a new check to the function it complained about.
57  */
58
59 #ifdef HAVE_CONFIG_H
60 #include "config.h"
61 #endif
62
63 #include <assert.h>
64 #include <limits.h>
65
66 #include "cairo-test.h"
67
68 #if CAIRO_HAS_GL_SURFACE
69 #include <cairo-gl.h>
70 #endif
71 #if CAIRO_HAS_OS2_SURFACE
72 #include <cairo-os2.h>
73 #endif
74 #if CAIRO_HAS_PDF_SURFACE
75 #include <cairo-pdf.h>
76 #endif
77 #if CAIRO_HAS_PS_SURFACE
78 #include <cairo-ps.h>
79 #endif
80 #if CAIRO_HAS_QUARTZ_SURFACE
81 #define Cursor QuartzCursor
82 #include <cairo-quartz.h>
83 #undef Cursor
84 #endif
85 #if CAIRO_HAS_SVG_SURFACE
86 #include <cairo-svg.h>
87 #endif
88 #if CAIRO_HAS_TEE_SURFACE
89 #include <cairo-tee.h>
90 #endif
91 #if CAIRO_HAS_XCB_SURFACE
92 #include <cairo-xcb.h>
93 #endif
94 #if CAIRO_HAS_XLIB_SURFACE
95 #define Cursor XCursor
96 #include <cairo-xlib.h>
97 #undef Cursor
98 #endif
99
100 #define surface_has_type(surface,type) (cairo_surface_get_type (surface) == (type))
101
102 typedef cairo_test_status_t (* surface_test_func_t) (cairo_surface_t *surface);
103
104 static cairo_test_status_t
105 test_cairo_surface_create_similar (cairo_surface_t *surface)
106 {
107     cairo_surface_t *similar;
108     
109     similar = cairo_surface_create_similar (surface, CAIRO_CONTENT_ALPHA, 100, 100);
110     
111     cairo_surface_destroy (similar);
112     return CAIRO_TEST_SUCCESS;
113 }
114
115 static cairo_test_status_t
116 test_cairo_surface_create_for_rectangle (cairo_surface_t *surface)
117 {
118     cairo_surface_t *similar;
119     
120     similar = cairo_surface_create_for_rectangle (surface, 1, 1, 8, 8);
121     
122     cairo_surface_destroy (similar);
123     return CAIRO_TEST_SUCCESS;
124 }
125
126 static cairo_test_status_t
127 test_cairo_surface_reference (cairo_surface_t *surface)
128 {
129     cairo_surface_destroy (cairo_surface_reference (surface));
130     return CAIRO_TEST_SUCCESS;
131 }
132
133 static cairo_test_status_t
134 test_cairo_surface_finish (cairo_surface_t *surface)
135 {
136     cairo_surface_finish (surface);
137     return CAIRO_TEST_SUCCESS;
138 }
139
140 static cairo_test_status_t
141 test_cairo_surface_get_device (cairo_surface_t *surface)
142 {
143     /* cairo_device_t *device = */cairo_surface_get_device (surface);
144     return CAIRO_TEST_SUCCESS;
145 }
146
147 static cairo_test_status_t
148 test_cairo_surface_get_reference_count (cairo_surface_t *surface)
149 {
150     unsigned int refcount = cairo_surface_get_reference_count (surface);
151     if (refcount > 0)
152         return CAIRO_TEST_SUCCESS;
153     /* inert error surfaces have a refcount of 0 */
154     return cairo_surface_status (surface) ? CAIRO_TEST_SUCCESS : CAIRO_TEST_ERROR;
155 }
156
157 static cairo_test_status_t
158 test_cairo_surface_status (cairo_surface_t *surface)
159 {
160     cairo_status_t status = cairo_surface_status (surface);
161     return status < CAIRO_STATUS_LAST_STATUS ? CAIRO_TEST_SUCCESS : CAIRO_TEST_ERROR;
162 }
163
164 static cairo_test_status_t
165 test_cairo_surface_get_type (cairo_surface_t *surface)
166 {
167     /* cairo_surface_type_t type = */cairo_surface_get_type (surface);
168     return CAIRO_TEST_SUCCESS;
169 }
170
171 static cairo_test_status_t
172 test_cairo_surface_get_content (cairo_surface_t *surface)
173 {
174     cairo_content_t content = cairo_surface_get_content (surface);
175
176     switch (content) {
177     case CAIRO_CONTENT_COLOR:
178     case CAIRO_CONTENT_ALPHA:
179     case CAIRO_CONTENT_COLOR_ALPHA:
180         return CAIRO_TEST_SUCCESS;
181     default:
182         return CAIRO_TEST_ERROR;
183     }
184 }
185
186 static cairo_test_status_t
187 test_cairo_surface_set_user_data (cairo_surface_t *surface)
188 {
189     static cairo_user_data_key_t key;
190     cairo_status_t status;
191
192     status = cairo_surface_set_user_data (surface, &key, &key, NULL);
193     if (status == CAIRO_STATUS_NO_MEMORY)
194         return CAIRO_TEST_NO_MEMORY;
195     else if (status)
196         return CAIRO_TEST_SUCCESS;
197
198     if (cairo_surface_get_user_data (surface, &key) != &key)
199         return CAIRO_TEST_ERROR;
200
201     return CAIRO_TEST_SUCCESS;
202 }
203
204 static cairo_test_status_t
205 test_cairo_surface_set_mime_data (cairo_surface_t *surface)
206 {
207     const char *mimetype = "text/x-uri";
208     const char *data = "http://www.cairographics.org";
209     cairo_status_t status;
210
211     status = cairo_surface_set_mime_data (surface,
212                                           mimetype,
213                                           (const unsigned char *) data,
214                                           strlen (data),
215                                           NULL, NULL);
216     return status ? CAIRO_TEST_SUCCESS : CAIRO_TEST_ERROR;
217 }
218
219 static cairo_test_status_t
220 test_cairo_surface_get_mime_data (cairo_surface_t *surface)
221 {
222     const char *mimetype = "text/x-uri";
223     const unsigned char *data;
224     unsigned long length;
225
226     cairo_surface_get_mime_data (surface, mimetype, &data, &length);
227     return data == NULL && length == 0 ? CAIRO_TEST_SUCCESS : CAIRO_TEST_ERROR;
228 }
229
230 static cairo_test_status_t
231 test_cairo_surface_get_font_options (cairo_surface_t *surface)
232 {
233     cairo_font_options_t *options;
234     cairo_status_t status;
235
236     options = cairo_font_options_create ();
237     if (likely (!cairo_font_options_status (options)))
238         cairo_surface_get_font_options (surface, options);
239     status = cairo_font_options_status (options);
240     cairo_font_options_destroy (options);
241     return status ? CAIRO_TEST_ERROR : CAIRO_TEST_SUCCESS;
242 }
243
244 static cairo_test_status_t
245 test_cairo_surface_flush (cairo_surface_t *surface)
246 {
247     cairo_surface_flush (surface);
248     return CAIRO_TEST_SUCCESS;
249 }
250
251 static cairo_test_status_t
252 test_cairo_surface_mark_dirty (cairo_surface_t *surface)
253 {
254     cairo_surface_mark_dirty (surface);
255     return CAIRO_TEST_SUCCESS;
256 }
257
258 static cairo_test_status_t
259 test_cairo_surface_mark_dirty_rectangle (cairo_surface_t *surface)
260 {
261     cairo_surface_mark_dirty_rectangle (surface, 1, 1, 8, 8);
262     return CAIRO_TEST_SUCCESS;
263 }
264
265 static cairo_test_status_t
266 test_cairo_surface_set_device_offset (cairo_surface_t *surface)
267 {
268     cairo_surface_set_device_offset (surface, 5, 5);
269     return CAIRO_TEST_SUCCESS;
270 }
271
272 static cairo_test_status_t
273 test_cairo_surface_get_device_offset (cairo_surface_t *surface)
274 {
275     double x, y;
276
277     cairo_surface_get_device_offset (surface, &x, &y);
278     return CAIRO_TEST_SUCCESS;
279 }
280
281 static cairo_test_status_t
282 test_cairo_surface_set_fallback_resolution (cairo_surface_t *surface)
283 {
284     cairo_surface_set_fallback_resolution (surface, 42, 42);
285     return CAIRO_TEST_SUCCESS;
286 }
287
288 static cairo_test_status_t
289 test_cairo_surface_get_fallback_resolution (cairo_surface_t *surface)
290 {
291     double x, y;
292
293     cairo_surface_get_fallback_resolution (surface, &x, &y);
294     return CAIRO_TEST_SUCCESS;
295 }
296
297 static cairo_test_status_t
298 test_cairo_surface_copy_page (cairo_surface_t *surface)
299 {
300     cairo_surface_copy_page (surface);
301     return CAIRO_TEST_SUCCESS;
302 }
303
304 static cairo_test_status_t
305 test_cairo_surface_show_page (cairo_surface_t *surface)
306 {
307     cairo_surface_show_page (surface);
308     return CAIRO_TEST_SUCCESS;
309 }
310
311 static cairo_test_status_t
312 test_cairo_surface_has_show_text_glyphs (cairo_surface_t *surface)
313 {
314     cairo_surface_has_show_text_glyphs (surface);
315     return CAIRO_TEST_SUCCESS;
316 }
317
318 static cairo_test_status_t
319 test_cairo_image_surface_get_data (cairo_surface_t *surface)
320 {
321     unsigned char *data = cairo_image_surface_get_data (surface);
322     return data == NULL || surface_has_type (surface, CAIRO_SURFACE_TYPE_IMAGE) ? CAIRO_TEST_SUCCESS : CAIRO_TEST_ERROR;
323 }
324
325 static cairo_test_status_t
326 test_cairo_image_surface_get_format (cairo_surface_t *surface)
327 {
328     cairo_format_t format = cairo_image_surface_get_format (surface);
329     return format == CAIRO_FORMAT_INVALID || surface_has_type (surface, CAIRO_SURFACE_TYPE_IMAGE) ? CAIRO_TEST_SUCCESS : CAIRO_TEST_ERROR;
330 }
331
332 static cairo_test_status_t
333 test_cairo_image_surface_get_width (cairo_surface_t *surface)
334 {
335     unsigned int width = cairo_image_surface_get_width (surface);
336     return width == 0 || surface_has_type (surface, CAIRO_SURFACE_TYPE_IMAGE) ? CAIRO_TEST_SUCCESS : CAIRO_TEST_ERROR;
337 }
338
339 static cairo_test_status_t
340 test_cairo_image_surface_get_height (cairo_surface_t *surface)
341 {
342     unsigned int height = cairo_image_surface_get_height (surface);
343     return height == 0 || surface_has_type (surface, CAIRO_SURFACE_TYPE_IMAGE) ? CAIRO_TEST_SUCCESS : CAIRO_TEST_ERROR;
344 }
345
346 static cairo_test_status_t
347 test_cairo_image_surface_get_stride (cairo_surface_t *surface)
348 {
349     unsigned int stride = cairo_image_surface_get_stride (surface);
350     return stride == 0 || surface_has_type (surface, CAIRO_SURFACE_TYPE_IMAGE) ? CAIRO_TEST_SUCCESS : CAIRO_TEST_ERROR;
351 }
352
353 #if CAIRO_HAS_PNG_FUNCTIONS
354
355 static cairo_test_status_t
356 test_cairo_surface_write_to_png (cairo_surface_t *surface)
357 {
358     cairo_status_t status;
359
360     status = cairo_surface_write_to_png (surface, "/this/file/will/definitely/not/exist.png");
361     
362     return status ? CAIRO_TEST_SUCCESS : CAIRO_TEST_ERROR;
363 }
364
365 static cairo_status_t
366 write_func_that_always_fails (void *closure, const unsigned char *data, unsigned int length)
367 {
368     return CAIRO_STATUS_WRITE_ERROR;
369 }
370
371 static cairo_test_status_t
372 test_cairo_surface_write_to_png_stream (cairo_surface_t *surface)
373 {
374     cairo_status_t status;
375
376     status = cairo_surface_write_to_png_stream (surface,
377                                                 write_func_that_always_fails,
378                                                 NULL);
379     
380     return status && status != CAIRO_STATUS_WRITE_ERROR ? CAIRO_TEST_SUCCESS : CAIRO_TEST_ERROR;
381 }
382
383 #endif /* CAIRO_HAS_PNG_FUNCTIONS */
384
385 static cairo_test_status_t
386 test_cairo_recording_surface_ink_extents (cairo_surface_t *surface)
387 {
388     double x, y, w, h;
389
390     cairo_recording_surface_ink_extents (surface, &x, &y, &w, &h);
391     return x == 0 && y == 0 && w == 0 && h == 0 ? CAIRO_TEST_SUCCESS : CAIRO_TEST_ERROR;
392 }
393
394 #if CAIRO_HAS_TEE_SURFACE
395
396 static cairo_test_status_t
397 test_cairo_tee_surface_add (cairo_surface_t *surface)
398 {
399     cairo_surface_t *image = cairo_image_surface_create (CAIRO_FORMAT_A8, 10, 10);
400
401     cairo_tee_surface_add (surface, image);
402     cairo_surface_destroy (image);
403     return CAIRO_TEST_SUCCESS;
404 }
405
406 static cairo_test_status_t
407 test_cairo_tee_surface_remove (cairo_surface_t *surface)
408 {
409     cairo_surface_t *image = cairo_image_surface_create (CAIRO_FORMAT_A8, 10, 10);
410
411     cairo_tee_surface_remove (surface, image);
412     cairo_surface_destroy (image);
413     return CAIRO_TEST_SUCCESS;
414 }
415
416 static cairo_test_status_t
417 test_cairo_tee_surface_index (cairo_surface_t *surface)
418 {
419     cairo_surface_t *master;
420     cairo_status_t status;
421
422     master = cairo_tee_surface_index (surface, 0);
423     status = cairo_surface_status (master);
424     cairo_surface_destroy (master);
425     return status ? CAIRO_TEST_SUCCESS : CAIRO_TEST_ERROR;
426 }
427
428 #endif /* CAIRO_HAS_TEE_SURFACE */
429
430 #if CAIRO_HAS_GL_SURFACE
431
432 static cairo_test_status_t
433 test_cairo_gl_surface_set_size (cairo_surface_t *surface)
434 {
435     cairo_gl_surface_set_size (surface, 5, 5);
436     return CAIRO_TEST_SUCCESS;
437 }
438
439 static cairo_test_status_t
440 test_cairo_gl_surface_get_width (cairo_surface_t *surface)
441 {
442     unsigned int width = cairo_gl_surface_get_width (surface);
443     return width == 0 || surface_has_type (surface, CAIRO_SURFACE_TYPE_GL) ? CAIRO_TEST_SUCCESS : CAIRO_TEST_ERROR;
444 }
445
446 static cairo_test_status_t
447 test_cairo_gl_surface_get_height (cairo_surface_t *surface)
448 {
449     unsigned int height = cairo_gl_surface_get_height (surface);
450     return height == 0 || surface_has_type (surface, CAIRO_SURFACE_TYPE_GL) ? CAIRO_TEST_SUCCESS : CAIRO_TEST_ERROR;
451 }
452
453 static cairo_test_status_t
454 test_cairo_gl_surface_swapbuffers (cairo_surface_t *surface)
455 {
456     cairo_gl_surface_swapbuffers (surface);
457     return CAIRO_TEST_SUCCESS;
458 }
459
460 #endif /* CAIRO_HAS_GL_SURFACE */
461
462 #if CAIRO_HAS_PDF_SURFACE
463
464 static cairo_test_status_t
465 test_cairo_pdf_surface_restrict_to_version (cairo_surface_t *surface)
466 {
467     cairo_pdf_surface_restrict_to_version (surface, CAIRO_PDF_VERSION_1_4);
468     return CAIRO_TEST_SUCCESS;
469 }
470
471 static cairo_test_status_t
472 test_cairo_pdf_surface_set_size (cairo_surface_t *surface)
473 {
474     cairo_pdf_surface_set_size (surface, 5, 5);
475     return CAIRO_TEST_SUCCESS;
476 }
477
478 #endif /* CAIRO_HAS_PDF_SURFACE */
479
480 #if CAIRO_HAS_PS_SURFACE
481
482 static cairo_test_status_t
483 test_cairo_ps_surface_restrict_to_level (cairo_surface_t *surface)
484 {
485     cairo_ps_surface_restrict_to_level (surface, CAIRO_PS_LEVEL_2);
486     return CAIRO_TEST_SUCCESS;
487 }
488
489 static cairo_test_status_t
490 test_cairo_ps_surface_set_eps (cairo_surface_t *surface)
491 {
492     cairo_ps_surface_set_eps (surface, TRUE);
493     return CAIRO_TEST_SUCCESS;
494 }
495
496 static cairo_test_status_t
497 test_cairo_ps_surface_get_eps (cairo_surface_t *surface)
498 {
499     cairo_bool_t eps = cairo_ps_surface_get_eps (surface);
500     return eps ? CAIRO_TEST_ERROR : CAIRO_TEST_SUCCESS;
501 }
502
503 static cairo_test_status_t
504 test_cairo_ps_surface_set_size (cairo_surface_t *surface)
505 {
506     cairo_ps_surface_set_size (surface, 5, 5);
507     return CAIRO_TEST_SUCCESS;
508 }
509
510 static cairo_test_status_t
511 test_cairo_ps_surface_dsc_comment (cairo_surface_t *surface)
512 {
513     cairo_ps_surface_dsc_comment (surface, "54, 74, 90, 2010");
514     return CAIRO_TEST_SUCCESS;
515 }
516
517 static cairo_test_status_t
518 test_cairo_ps_surface_dsc_begin_setup (cairo_surface_t *surface)
519 {
520     cairo_ps_surface_dsc_begin_setup (surface);
521     return CAIRO_TEST_SUCCESS;
522 }
523
524 static cairo_test_status_t
525 test_cairo_ps_surface_dsc_begin_page_setup (cairo_surface_t *surface)
526 {
527     cairo_ps_surface_dsc_begin_page_setup (surface);
528     return CAIRO_TEST_SUCCESS;
529 }
530
531 #endif /* CAIRO_HAS_PS_SURFACE */
532
533 #if CAIRO_HAS_QUARTZ_SURFACE
534
535 static cairo_test_status_t
536 test_cairo_quartz_surface_get_cg_context (cairo_surface_t *surface)
537 {
538     CGContextRef context = cairo_quartz_surface_get_cg_context (surface);
539     return context == NULL || surface_has_type (surface, CAIRO_SURFACE_TYPE_QUARTZ) ? CAIRO_TEST_SUCCESS : CAIRO_TEST_ERROR;
540 }
541
542 #endif /* CAIRO_HAS_QUARTZ_SURFACE */
543
544 #if CAIRO_HAS_SVG_SURFACE
545
546 static cairo_test_status_t
547 test_cairo_svg_surface_restrict_to_version (cairo_surface_t *surface)
548 {
549     cairo_svg_surface_restrict_to_version (surface, CAIRO_SVG_VERSION_1_1);
550     return CAIRO_TEST_SUCCESS;
551 }
552
553 #endif /* CAIRO_HAS_SVG_SURFACE */
554
555 #if CAIRO_HAS_XCB_SURFACE
556
557 static cairo_test_status_t
558 test_cairo_xcb_surface_set_size (cairo_surface_t *surface)
559 {
560     cairo_xcb_surface_set_size (surface, 5, 5);
561     return CAIRO_TEST_SUCCESS;
562 }
563
564 static cairo_test_status_t
565 test_cairo_xcb_surface_set_drawable (cairo_surface_t *surface)
566 {
567     cairo_xcb_surface_set_drawable (surface, 0, 5, 5);
568     return CAIRO_TEST_SUCCESS;
569 }
570
571 #endif
572
573 #if CAIRO_HAS_XLIB_SURFACE
574
575 static cairo_test_status_t
576 test_cairo_xlib_surface_set_size (cairo_surface_t *surface)
577 {
578     cairo_xlib_surface_set_size (surface, 5, 5);
579     return CAIRO_TEST_SUCCESS;
580 }
581
582 static cairo_test_status_t
583 test_cairo_xlib_surface_set_drawable (cairo_surface_t *surface)
584 {
585     cairo_xlib_surface_set_drawable (surface, 0, 5, 5);
586     return CAIRO_TEST_SUCCESS;
587 }
588
589 static cairo_test_status_t
590 test_cairo_xlib_surface_get_display (cairo_surface_t *surface)
591 {
592     Display *display = cairo_xlib_surface_get_display (surface);
593     return display == NULL || surface_has_type (surface, CAIRO_SURFACE_TYPE_XLIB) ? CAIRO_TEST_SUCCESS : CAIRO_TEST_ERROR;
594 }
595
596 static cairo_test_status_t
597 test_cairo_xlib_surface_get_screen (cairo_surface_t *surface)
598 {
599     Screen *screen = cairo_xlib_surface_get_screen (surface);
600     return screen == NULL || surface_has_type (surface, CAIRO_SURFACE_TYPE_XLIB) ? CAIRO_TEST_SUCCESS : CAIRO_TEST_ERROR;
601 }
602
603 static cairo_test_status_t
604 test_cairo_xlib_surface_get_visual (cairo_surface_t *surface)
605 {
606     Visual *visual = cairo_xlib_surface_get_visual (surface);
607     return visual == NULL || surface_has_type (surface, CAIRO_SURFACE_TYPE_XLIB) ? CAIRO_TEST_SUCCESS : CAIRO_TEST_ERROR;
608 }
609
610 static cairo_test_status_t
611 test_cairo_xlib_surface_get_drawable (cairo_surface_t *surface)
612 {
613     Drawable drawable = cairo_xlib_surface_get_drawable (surface);
614     return drawable == 0 || surface_has_type (surface, CAIRO_SURFACE_TYPE_XLIB) ? CAIRO_TEST_SUCCESS : CAIRO_TEST_ERROR;
615 }
616
617 static cairo_test_status_t
618 test_cairo_xlib_surface_get_depth (cairo_surface_t *surface)
619 {
620     int depth = cairo_xlib_surface_get_depth (surface);
621     return depth == 0 || surface_has_type (surface, CAIRO_SURFACE_TYPE_XLIB) ? CAIRO_TEST_SUCCESS : CAIRO_TEST_ERROR;
622 }
623
624 static cairo_test_status_t
625 test_cairo_xlib_surface_get_width (cairo_surface_t *surface)
626 {
627     int width = cairo_xlib_surface_get_width (surface);
628     return width == 0 || surface_has_type (surface, CAIRO_SURFACE_TYPE_XLIB) ? CAIRO_TEST_SUCCESS : CAIRO_TEST_ERROR;
629 }
630
631 static cairo_test_status_t
632 test_cairo_xlib_surface_get_height (cairo_surface_t *surface)
633 {
634     int height = cairo_xlib_surface_get_height (surface);
635     return height == 0 || surface_has_type (surface, CAIRO_SURFACE_TYPE_XLIB) ? CAIRO_TEST_SUCCESS : CAIRO_TEST_ERROR;
636 }
637
638 #endif
639
640
641 #define TEST(name, surface_type, sets_status) { #name, test_ ## name, surface_type, sets_status }
642
643 struct {
644     const char *name;
645     surface_test_func_t func;
646     int surface_type; /* cairo_surface_type_t or -1 */
647     cairo_bool_t modifies_surface;
648 } tests[] = {
649     TEST (cairo_surface_create_similar, -1, FALSE),
650     TEST (cairo_surface_create_for_rectangle, -1, FALSE),
651     TEST (cairo_surface_reference, -1, FALSE),
652     TEST (cairo_surface_finish, -1, TRUE),
653     TEST (cairo_surface_get_device, -1, FALSE),
654     TEST (cairo_surface_get_reference_count, -1, FALSE),
655     TEST (cairo_surface_status, -1, FALSE),
656     TEST (cairo_surface_get_type, -1, FALSE),
657     TEST (cairo_surface_get_content, -1, FALSE),
658     TEST (cairo_surface_set_user_data, -1, FALSE),
659     TEST (cairo_surface_set_mime_data, -1, TRUE),
660     TEST (cairo_surface_get_mime_data, -1, FALSE),
661     TEST (cairo_surface_get_font_options, -1, FALSE),
662     TEST (cairo_surface_flush, -1, TRUE),
663     TEST (cairo_surface_mark_dirty, -1, TRUE),
664     TEST (cairo_surface_mark_dirty_rectangle, -1, TRUE),
665     TEST (cairo_surface_set_device_offset, -1, TRUE),
666     TEST (cairo_surface_get_device_offset, -1, FALSE),
667     TEST (cairo_surface_set_fallback_resolution, -1, TRUE),
668     TEST (cairo_surface_get_fallback_resolution, -1, FALSE),
669     TEST (cairo_surface_copy_page, -1, TRUE),
670     TEST (cairo_surface_show_page, -1, TRUE),
671     TEST (cairo_surface_has_show_text_glyphs, -1, FALSE),
672     TEST (cairo_image_surface_get_data, CAIRO_SURFACE_TYPE_IMAGE, FALSE),
673     TEST (cairo_image_surface_get_format, CAIRO_SURFACE_TYPE_IMAGE, FALSE),
674     TEST (cairo_image_surface_get_width, CAIRO_SURFACE_TYPE_IMAGE, FALSE),
675     TEST (cairo_image_surface_get_height, CAIRO_SURFACE_TYPE_IMAGE, FALSE),
676     TEST (cairo_image_surface_get_stride, CAIRO_SURFACE_TYPE_IMAGE, FALSE),
677 #if CAIRO_HAS_PNG_FUNCTIONS
678     TEST (cairo_surface_write_to_png, -1, FALSE),
679     TEST (cairo_surface_write_to_png_stream, -1, FALSE),
680 #endif
681     TEST (cairo_recording_surface_ink_extents, CAIRO_SURFACE_TYPE_RECORDING, FALSE),
682 #if CAIRO_HAS_TEE_SURFACE
683     TEST (cairo_tee_surface_add, CAIRO_SURFACE_TYPE_TEE, TRUE),
684     TEST (cairo_tee_surface_remove, CAIRO_SURFACE_TYPE_TEE, TRUE),
685     TEST (cairo_tee_surface_index, CAIRO_SURFACE_TYPE_TEE, FALSE),
686 #endif
687 #if CAIRO_HAS_GL_SURFACE
688     TEST (cairo_gl_surface_set_size, CAIRO_SURFACE_TYPE_GL, TRUE),
689     TEST (cairo_gl_surface_get_width, CAIRO_SURFACE_TYPE_GL, FALSE),
690     TEST (cairo_gl_surface_get_height, CAIRO_SURFACE_TYPE_GL, FALSE),
691     TEST (cairo_gl_surface_swapbuffers, CAIRO_SURFACE_TYPE_GL, TRUE),
692 #endif
693 #if CAIRO_HAS_PDF_SURFACE
694     TEST (cairo_pdf_surface_restrict_to_version, CAIRO_SURFACE_TYPE_PDF, TRUE),
695     TEST (cairo_pdf_surface_set_size, CAIRO_SURFACE_TYPE_PDF, TRUE),
696 #endif
697 #if CAIRO_HAS_PS_SURFACE
698     TEST (cairo_ps_surface_restrict_to_level, CAIRO_SURFACE_TYPE_PS, TRUE),
699     TEST (cairo_ps_surface_set_eps, CAIRO_SURFACE_TYPE_PS, TRUE),
700     TEST (cairo_ps_surface_get_eps, CAIRO_SURFACE_TYPE_PS, FALSE),
701     TEST (cairo_ps_surface_set_size, CAIRO_SURFACE_TYPE_PS, TRUE),
702     TEST (cairo_ps_surface_dsc_comment, CAIRO_SURFACE_TYPE_PS, TRUE),
703     TEST (cairo_ps_surface_dsc_begin_setup, CAIRO_SURFACE_TYPE_PS, TRUE),
704     TEST (cairo_ps_surface_dsc_begin_page_setup, CAIRO_SURFACE_TYPE_PS, TRUE),
705 #endif
706 #if CAIRO_HAS_QUARTZ_SURFACE
707     TEST (cairo_quartz_surface_get_cg_context, CAIRO_SURFACE_TYPE_QUARTZ, FALSE),
708 #endif
709 #if CAIRO_HAS_SVG_SURFACE
710     TEST (cairo_svg_surface_restrict_to_version, CAIRO_SURFACE_TYPE_SVG, TRUE),
711 #endif
712 #if CAIRO_HAS_XCB_SURFACE
713     TEST (cairo_xcb_surface_set_size, CAIRO_SURFACE_TYPE_XCB, TRUE),
714     TEST (cairo_xcb_surface_set_drawable, CAIRO_SURFACE_TYPE_XCB, TRUE),
715 #endif
716 #if CAIRO_HAS_XLIB_SURFACE
717     TEST (cairo_xlib_surface_set_size, CAIRO_SURFACE_TYPE_XLIB, TRUE),
718     TEST (cairo_xlib_surface_set_drawable, CAIRO_SURFACE_TYPE_XLIB, TRUE),
719     TEST (cairo_xlib_surface_get_display, CAIRO_SURFACE_TYPE_XLIB, FALSE),
720     TEST (cairo_xlib_surface_get_drawable, CAIRO_SURFACE_TYPE_XLIB, FALSE),
721     TEST (cairo_xlib_surface_get_screen, CAIRO_SURFACE_TYPE_XLIB, FALSE),
722     TEST (cairo_xlib_surface_get_visual, CAIRO_SURFACE_TYPE_XLIB, FALSE),
723     TEST (cairo_xlib_surface_get_depth, CAIRO_SURFACE_TYPE_XLIB, FALSE),
724     TEST (cairo_xlib_surface_get_width, CAIRO_SURFACE_TYPE_XLIB, FALSE),
725     TEST (cairo_xlib_surface_get_height, CAIRO_SURFACE_TYPE_XLIB, FALSE),
726 #endif
727 };
728
729 static cairo_test_status_t
730 preamble (cairo_test_context_t *ctx)
731 {
732     cairo_surface_t *surface;
733     cairo_test_status_t test_status;
734     cairo_status_t status_before, status_after;
735     unsigned int i;
736
737     /* Test an error surface */
738     for (i = 0; i < ARRAY_LENGTH (tests); i++) {
739         surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, INT_MAX, INT_MAX);
740         status_before = cairo_surface_status (surface);
741         assert (status_before);
742
743         test_status = tests[i].func (surface);
744
745         status_after = cairo_surface_status (surface);
746         cairo_surface_destroy (surface);
747
748         if (test_status != CAIRO_TEST_SUCCESS) {
749             cairo_test_log (ctx,
750                             "Failed test %s with %d\n",
751                             tests[i].name, (int) test_status);
752             return test_status;
753         }
754
755         if (status_before != status_after) {
756             cairo_test_log (ctx,
757                             "Failed test %s: Modified surface status from %u (%s) to %u (%s)\n",
758                             tests[i].name,
759                             status_before, cairo_status_to_string (status_before),
760                             status_after, cairo_status_to_string (status_after));
761             return CAIRO_TEST_ERROR;
762         }
763     }
764
765     return CAIRO_TEST_SUCCESS;
766 }
767
768 static cairo_test_status_t
769 draw (cairo_t *cr, int width, int height)
770 {
771     const cairo_test_context_t *ctx = cairo_test_get_context (cr);
772     cairo_surface_t *similar, *target;
773     cairo_test_status_t test_status;
774     cairo_status_t status;
775     unsigned int i;
776
777     target = cairo_get_target (cr);
778
779     /* Test a finished similar surface */
780     for (i = 0; i < ARRAY_LENGTH (tests); i++) {
781         similar = cairo_surface_create_similar (target,
782                                                 cairo_surface_get_content (target),
783                                                 10, 10);
784         cairo_surface_finish (similar);
785         test_status = tests[i].func (similar);
786         status = cairo_surface_status (similar);
787         cairo_surface_destroy (similar);
788
789         if (test_status != CAIRO_TEST_SUCCESS) {
790             cairo_test_log (ctx,
791                             "Failed test %s with %d\n",
792                             tests[i].name, (int) test_status);
793             return test_status;
794         }
795
796         if (tests[i].modifies_surface &&
797             strcmp (tests[i].name, "cairo_surface_finish") &&
798             strcmp (tests[i].name, "cairo_surface_flush") &&
799             status != CAIRO_STATUS_SURFACE_FINISHED) {
800             cairo_test_log (ctx,
801                             "Failed test %s: Finished surface not set into error state\n",
802                             tests[i].name);
803             return CAIRO_TEST_ERROR;
804         }
805     }
806
807     /* Test a normal surface for functions that have the wrong type */
808     for (i = 0; i < ARRAY_LENGTH (tests); i++) {
809         cairo_status_t desired_status;
810
811         if (tests[i].surface_type == -1)
812             continue;
813         similar = cairo_surface_create_similar (target,
814                                                 cairo_surface_get_content (target),
815                                                 10, 10);
816         if (cairo_surface_get_type (similar) == (cairo_surface_type_t) tests[i].surface_type) {
817             cairo_surface_destroy (similar);
818             continue;
819         }
820
821         test_status = tests[i].func (similar);
822         status = cairo_surface_status (similar);
823         cairo_surface_destroy (similar);
824
825         if (test_status != CAIRO_TEST_SUCCESS) {
826             cairo_test_log (ctx,
827                             "Failed test %s with %d\n",
828                             tests[i].name, (int) test_status);
829             return test_status;
830         }
831
832         desired_status = tests[i].modifies_surface ? CAIRO_STATUS_SURFACE_TYPE_MISMATCH : CAIRO_STATUS_SUCCESS;
833         if (status != desired_status) {
834             cairo_test_log (ctx,
835                             "Failed test %s: Surface status should be %u (%s), but is %u (%s)\n",
836                             tests[i].name,
837                             desired_status, cairo_status_to_string (desired_status),
838                             status, cairo_status_to_string (status));
839             return CAIRO_TEST_ERROR;
840         }
841     }
842
843     /* 565-compatible gray background */
844     cairo_set_source_rgb (cr, 0.51613, 0.55555, 0.51613);
845     cairo_paint (cr);
846
847     return CAIRO_TEST_SUCCESS;
848 }
849
850 CAIRO_TEST (api_special_cases,
851             "Check surface functions properly handle wrong surface arguments",
852             "api", /* keywords */
853             NULL, /* requirements */
854             10, 10,
855             preamble, draw)