# -*- coding: utf-8 -*- import io import os import sys import array import tempfile import struct import sysconfig import platform import cairo import pytest def test_context_manager(): with cairo.ImageSurface(cairo.FORMAT_ARGB32, 10, 10) as surface: surface.show_page() with pytest.raises(cairo.Error) as excinfo: surface.show_page() assert excinfo.value.status == cairo.Status.SURFACE_FINISHED def test_surface_cmp_hash(): main = cairo.ImageSurface(cairo.FORMAT_ARGB32, 10, 10) ctx = cairo.Context(main) assert ctx.get_target() == main assert not ctx.get_target() != main assert main != object() assert hash(ctx.get_target()) == hash(main) # we implement some hackery to change the underlying object after unmap # which would change the hash. Make sure this type is unhashable. mapped = main.map_to_image(None) with pytest.raises(TypeError): hash(mapped) assert mapped == mapped main.unmap_image(mapped) def test_surface_map_to_image(): main = cairo.ImageSurface(cairo.FORMAT_ARGB32, 10, 10) image = main.map_to_image(None) with pytest.raises(TypeError): type(image)() other = cairo.ImageSurface(cairo.FORMAT_ARGB32, 10, 10) with pytest.raises(ValueError): other.unmap_image(image) with pytest.raises(TypeError): main.unmap_image(other) with pytest.raises(RuntimeError): image.finish() main.unmap_image(image) with pytest.raises(RuntimeError): main.unmap_image(image) # from here on everything should fail with pytest.raises(cairo.Error): cairo.Context(image) with pytest.raises(TypeError): main.map_to_image(object()) with pytest.raises(TypeError): main.map_to_image() gced = main.map_to_image(None) del gced def test_surface_map_to_image_context_manager(): main = cairo.ImageSurface(cairo.FORMAT_ARGB32, 10, 10) with main.map_to_image(None) as image: pass with pytest.raises(RuntimeError): main.unmap_image(image) with pytest.raises(cairo.Error) as excinfo: image.show_page() assert excinfo.value.status == cairo.Status.SURFACE_FINISHED with pytest.raises(RuntimeError): with image: pass def test_surface_map_to_image_data(): main = cairo.ImageSurface(cairo.Format.RGB24, 2, 1) main.flush() assert bytes(main.get_data()) == b"\x00\x00\x00\x00\x00\x00\x00\x00" image = main.map_to_image(None) ctx = cairo.Context(image) ctx.set_source_rgb(1, 1, 1) ctx.paint() main.unmap_image(image) main.flush() assert bytes(main.get_data()) == b"\xff\xff\xff\xff\xff\xff\xff\xff" main = cairo.ImageSurface(cairo.Format.RGB24, 2, 1) image = main.map_to_image(cairo.RectangleInt(0, 0, 1, 1)) ctx = cairo.Context(image) ctx.set_source_rgb(1, 1, 1) ctx.paint() main.unmap_image(image) main.flush() assert bytes(main.get_data()) == b"\xff\xff\xff\xff\x00\x00\x00\x00" @pytest.mark.skipif(not cairo.HAS_TEE_SURFACE, reason="no tee surface") def test_tee_surface(): main = cairo.ImageSurface(cairo.FORMAT_ARGB32, 10, 10) tee = cairo.TeeSurface(main) assert isinstance(tee, cairo.TeeSurface) with pytest.raises(TypeError): cairo.TeeSurface(object()) with pytest.raises(TypeError): tee.add(object()) with pytest.raises(TypeError): tee.remove(object()) with pytest.raises(TypeError): tee.index(object()) # the API is horrible, passing a wrong arg sets the surface to an error # state instead of returning the status. s1 = cairo.ImageSurface(cairo.FORMAT_ARGB32, 10, 10) tee.add(s1) assert tee.index(0) assert tee.index(1) tee.remove(s1) @pytest.mark.skipif(not hasattr(sys, "getrefcount"), reason="PyPy") def test_image_surface_get_data_refcount(): surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, 10, 10) assert sys.getrefcount(surface) == 2 d = surface.get_data() assert sys.getrefcount(surface) == 3 del d assert sys.getrefcount(surface) == 2 def test_image_surface_get_data_crasher(): surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, 10, 10) try: assert 0, surface.get_data() except Exception: pass def test_surface_get_content(): surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, 10, 10) assert surface.get_content() == cairo.Content.COLOR_ALPHA assert isinstance(surface.get_content(), cairo.Content) def test_surface_get_format(): surface = cairo.ImageSurface(cairo.Format.ARGB32, 10, 10) assert surface.get_format() == cairo.Format.ARGB32 assert isinstance(surface.get_format(), cairo.Format) def test_pdf_get_versions(): versions = cairo.PDFSurface.get_versions() assert isinstance(versions, list) assert all(isinstance(v, cairo.PDFVersion) for v in versions) def test_pdf_set_size(): fileobj = io.BytesIO() surface = cairo.PDFSurface(fileobj, 128, 128) surface.set_size(10, 10) with pytest.raises(TypeError): surface.set_size(10, object()) @pytest.mark.skipif(not hasattr(cairo.PDFSurface, "set_page_label"), reason="too old cairo") def test_pdf_set_page_label(): fileobj = io.BytesIO() with cairo.PDFSurface(fileobj, 128, 128) as surface: surface.set_page_label("foo") surface.set_page_label("bar") with pytest.raises(cairo.Error): surface.set_page_label("bar") @pytest.mark.skipif(not hasattr(cairo.PDFSurface, "set_metadata"), reason="too old cairo") def test_pdf_set_metadata(): fileobj = io.BytesIO() with cairo.PDFSurface(fileobj, 128, 128) as surface: surface.set_metadata(cairo.PDFMetadata.TITLE, "title") surface.set_metadata(cairo.PDFMetadata.TITLE, "title") surface.set_metadata(cairo.PDFMetadata.AUTHOR, "author") with pytest.raises(cairo.Error): surface.set_metadata(cairo.PDFMetadata.AUTHOR, "author") @pytest.mark.skipif(not hasattr(cairo.PDFSurface, "add_outline"), reason="too old cairo") def test_pdf_add_outline(): fileobj = io.BytesIO() with cairo.PDFSurface(fileobj, 128, 128) as surface: res = surface.add_outline( cairo.PDF_OUTLINE_ROOT, "foo", "page=3 pos=[3.1 6.2]", cairo.PDFOutlineFlags.OPEN) assert isinstance(res, int) @pytest.mark.skipif(not hasattr(cairo.PDFSurface, "set_thumbnail_size"), reason="too old cairo") def test_pdf_set_thumbnail_size(): fileobj = io.BytesIO() with cairo.PDFSurface(fileobj, 128, 128) as surface: surface.set_thumbnail_size(10, 10) surface.set_thumbnail_size(0, 0) surface.set_thumbnail_size(1, 1) with pytest.raises(cairo.Error): surface.set_thumbnail_size(0, 0) @pytest.mark.skipif( sysconfig.get_platform().startswith("win"), reason="msvc fixme") def test_pdf_surface(): fd, fname = tempfile.mkstemp() os.close(fd) try: cairo.PDFSurface(fname, 10, 10).finish() finally: os.unlink(fname) with pytest.raises(TypeError): cairo.PDFSurface() with pytest.raises((ValueError, TypeError)): cairo.PDFSurface("\x00") with pytest.raises(TypeError): cairo.PDFSurface(object(), 100, 100) def test_svg_version_to_string(): ver = cairo.SVGSurface.version_to_string(cairo.SVG_VERSION_1_1) assert ver and isinstance(ver, str) with pytest.raises(ValueError): cairo.SVGSurface.version_to_string(-1) with pytest.raises(TypeError): cairo.SVGSurface.version_to_string(object()) @pytest.mark.skipif(not hasattr(cairo.SVGSurface, "get_document_unit"), reason="too old cairo") def test_svg_surface_get_document_unit(): with cairo.SVGSurface(None, 10, 10) as surface: assert surface.get_document_unit() == cairo.SVGUnit.PT surface.set_document_unit(cairo.SVGUnit.PX) assert surface.get_document_unit() == cairo.SVGUnit.PX with pytest.raises(cairo.Error): surface.set_document_unit(cairo.SVGUnit.PX) def test_svg_surface_restrict_to_version(): surface = cairo.SVGSurface(None, 10, 10) surface.restrict_to_version(cairo.SVG_VERSION_1_1) surface.finish() with pytest.raises(cairo.Error): surface.restrict_to_version(cairo.SVG_VERSION_1_2) with pytest.raises(TypeError): surface.restrict_to_version(object()) @pytest.mark.skipif( sysconfig.get_platform().startswith("win"), reason="msvc fixme") def test_pdf_surface_restrict_to_version(): surface = cairo.PDFSurface(None, 10, 10) surface.restrict_to_version(cairo.PDF_VERSION_1_4) surface.finish() with pytest.raises(cairo.Error): surface.restrict_to_version(cairo.PDF_VERSION_1_5) with pytest.raises(TypeError): surface.restrict_to_version(object()) def test_pdf_version_to_string(): ver = cairo.PDFSurface.version_to_string(cairo.PDF_VERSION_1_4) assert ver and isinstance(ver, str) with pytest.raises(ValueError): cairo.PDFSurface.version_to_string(-1) with pytest.raises(TypeError): cairo.PDFSurface.version_to_string(object()) def test_ps_surface_misc(): surface = cairo.PSSurface(None, 10, 10) surface.dsc_begin_page_setup() surface.dsc_begin_setup() def test_ps_surface_dsc_comment(): surface = cairo.PSSurface(None, 10, 10) surface.dsc_comment("%%Title: My excellent document") with pytest.raises(cairo.Error): surface.dsc_comment("") with pytest.raises(TypeError): surface.dsc_comment(object()) def test_ps_get_eps(): surface = cairo.PSSurface(None, 10, 10) assert isinstance(surface.get_eps(), bool) surface.set_eps(True) assert surface.get_eps() with pytest.raises(TypeError): surface.set_eps(object()) def test_ps_set_size(): surface = cairo.PSSurface(None, 10, 10) surface.set_size(10, 10) with pytest.raises(TypeError): surface.set_size(10, object()) def test_ps_restrict_to_level(): surface = cairo.PSSurface(None, 10, 10) surface.restrict_to_level(cairo.PSLevel.LEVEL_2) with pytest.raises(TypeError): surface.restrict_to_level(object()) @pytest.mark.skipif( sysconfig.get_platform().startswith("win"), reason="msvc fixme") def test_ps_surface_level_to_string(): level_id = cairo.PSSurface.level_to_string(cairo.PS_LEVEL_2) assert isinstance(level_id, str) assert cairo.PSSurface.ps_level_to_string(cairo.PS_LEVEL_2) == level_id with pytest.raises(ValueError): cairo.PSSurface.level_to_string(-1) with pytest.raises(TypeError): cairo.PSSurface.level_to_string(object()) def test_ps_surface_get_levels(): levels = cairo.PSSurface.get_levels() assert isinstance(levels, list) assert all(isinstance(v, cairo.PSLevel) for v in levels) def test_ps_surface(): assert isinstance(cairo.PSSurface(None, 10, 10), cairo.PSSurface) fd, fname = tempfile.mkstemp() os.close(fd) try: cairo.PSSurface(fname, 10, 10).finish() finally: os.unlink(fname) with pytest.raises(TypeError): cairo.PSSurface() with pytest.raises((ValueError, TypeError)): cairo.PSSurface("\x00", 100, 100) with pytest.raises(TypeError): cairo.PSSurface(object(), 100, 100) def test_scg_surface(): fd, fname = tempfile.mkstemp() os.close(fd) try: cairo.SVGSurface(fname, 10, 10).finish() finally: os.unlink(fname) with pytest.raises(TypeError): cairo.SVGSurface() with pytest.raises((ValueError, TypeError)): cairo.SVGSurface("\x00", 10, 10) with pytest.raises(TypeError): cairo.SVGSurface(object(), 100, 100) def test_svg_surface_get_versions(): versions = cairo.SVGSurface.get_versions() assert isinstance(versions, list) assert all(isinstance(v, cairo.SVGVersion) for v in versions) def test_surface_get_device_scale(): surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, 10, 10) device_scale = surface.get_device_scale() assert all(isinstance(s, float) for s in device_scale) def test_surface_set_device_scale(): surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, 10, 10) ret = surface.set_device_scale(5.0, 3.0) assert ret is None surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, 100, 100) with pytest.raises(cairo.Error): surface.set_device_scale(1, 0) with pytest.raises(TypeError): surface.set_device_scale(1, object()) def test_surface_create_for_rectangle(): surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, 100, 100) new = surface.create_for_rectangle(0, 0, 10, 10) assert new assert isinstance(new, cairo.Surface) with pytest.raises(cairo.Error) as excinfo: surface.create_for_rectangle(0, 0, 10, -1) assert excinfo.value.status == cairo.STATUS_INVALID_SIZE with pytest.raises(TypeError): surface.create_for_rectangle(0, 0, 10, object()) def test_surface_create_similar_image(): surface = cairo.PDFSurface(None, 1, 1) image = surface.create_similar_image(cairo.FORMAT_ARGB32, 24, 42) assert image assert isinstance(image, cairo.ImageSurface) del surface assert image.get_width() == 24 assert image.get_height() == 42 surface = cairo.PDFSurface(None, 1, 1) with pytest.raises(TypeError): surface.create_similar_image(cairo.FORMAT_ARGB32, 24, object()) def test_surface_get_set_mime_data(): surface = cairo.ImageSurface(cairo.FORMAT_RGB24, 1, 1) assert surface.get_mime_data("foo") is None assert surface.get_mime_data(cairo.MIME_TYPE_JPEG) is None surface.set_mime_data("foo", b"bar") assert surface.get_mime_data("foo") == b"bar" surface.set_mime_data("foo", None) assert surface.get_mime_data("foo") is None surface.set_mime_data(cairo.MIME_TYPE_JPEG, b"\x00quux\x00") assert surface.get_mime_data(cairo.MIME_TYPE_JPEG)[:] == b"\x00quux\x00" surface.set_mime_data(cairo.MIME_TYPE_JPEG, None) assert surface.get_mime_data(cairo.MIME_TYPE_JPEG) is None with pytest.raises(TypeError): surface.set_mime_data(cairo.MIME_TYPE_JPEG, object()) with pytest.raises(TypeError): surface.get_mime_data(object()) def test_supports_mime_type(): surface = cairo.PDFSurface(None, 3, 3) assert surface.supports_mime_type(cairo.MIME_TYPE_JPEG) assert not surface.supports_mime_type("nope") with pytest.raises(TypeError): surface.supports_mime_type(object()) # https://bitbucket.org/pypy/pypy/issues/2751 @pytest.mark.skipif(platform.python_implementation() == "PyPy", reason="PyPy") def test_image_surface_create_for_data_array(): width, height = 255, 255 data = array.array('B', [0] * width * height * 4) for y in range(height): for x in range(width): offset = (x + (y * width)) * 4 alpha = y b = int(x * alpha / 255.0) g = int(y * alpha / 255.0) # cairo.FORMAT_ARGB32 uses pre-multiplied alpha data[offset:offset + 4] = array.array( "B", struct.pack("=I", b | g << 8 | alpha << 24)) surface = cairo.ImageSurface.create_for_data( data, cairo.FORMAT_ARGB32, width, height) # for debugging fd, filename = tempfile.mkstemp(prefix='pycairo_', suffix='.png') os.close(fd) surface.write_to_png(filename) os.unlink(filename) def test_image_surface_write_to_png_filename_and_obj_compare(): surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, 128, 128) fd, filename = tempfile.mkstemp(prefix='pycairo_', suffix='.png') os.close(fd) surface.write_to_png(filename) fileobj = io.BytesIO() surface.write_to_png(fileobj) with open(filename, "rb") as h: assert h.read() == fileobj.getvalue() os.unlink(filename) def test_image_surface_png_obj_roundtrip(): fileobj = io.BytesIO() surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, 128, 128) surface.write_to_png(fileobj) fileobj.seek(0) new_surface = cairo.ImageSurface.create_from_png(fileobj) assert surface.get_data() == new_surface.get_data() with pytest.raises(TypeError): cairo.ImageSurface.create_from_png() with pytest.raises((ValueError, TypeError)): cairo.ImageSurface.create_from_png("\x00") with pytest.raises(TypeError): cairo.ImageSurface.create_from_png(object()) def test_image_surface_png_file_roundtrip(): fd, filename = tempfile.mkstemp(prefix='pycairo_', suffix='.png') os.close(fd) surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, 128, 128) surface.write_to_png(filename) new_surface = cairo.ImageSurface.create_from_png(filename) assert surface.get_data() == new_surface.get_data() os.unlink(filename) def test_image_surface_write_to_png_error(): surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, 128, 128) with pytest.raises(TypeError): surface.write_to_png(42) with pytest.raises((ValueError, TypeError)): surface.write_to_png("\x00") def test_surface_from_stream_closed_before_finished(): for Kind in [cairo.PDFSurface, cairo.PSSurface, cairo.SVGSurface]: fileobj = io.BytesIO() surface = cairo.PDFSurface(fileobj, 128, 128) fileobj.close() with pytest.raises(IOError): surface.finish() def test_script_surface(): f = io.BytesIO() dev = cairo.ScriptDevice(f) surface = cairo.ScriptSurface(dev, cairo.Content.COLOR_ALPHA, 42, 10) assert isinstance(surface, cairo.ScriptSurface) cairo.Context(surface).paint() dev.flush() assert b"42" in f.getvalue() assert b"paint" in f.getvalue() with pytest.raises(TypeError): cairo.ScriptSurface() def test_script_device_device_ref(): f = io.BytesIO() dev = cairo.ScriptDevice(f) surface = cairo.ScriptSurface(dev, cairo.Content.COLOR_ALPHA, 42, 10) del dev for i in range(10): surface.get_device() def test_script_surface_create_for_target(): # paint the script proxy f = io.BytesIO() dev = cairo.ScriptDevice(f) surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, 10, 10) script = cairo.ScriptSurface.create_for_target(dev, surface) with pytest.raises(TypeError): cairo.ScriptSurface.create_for_target(dev, object()) assert isinstance(script, cairo.ScriptSurface) ctx = cairo.Context(script) ctx.set_source_rgb(0.25, 0.5, 1.0) ctx.paint() assert b"paint" in f.getvalue() surface.flush() image_data = bytes(surface.get_data()) # check if the result is the same surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, 10, 10) ctx = cairo.Context(surface) ctx.set_source_rgb(0.25, 0.5, 1.0) ctx.paint() surface.flush() assert bytes(surface.get_data()) == image_data def test_misc(): surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, 10, 10) surface.copy_page() surface.mark_dirty() surface.show_page() @pytest.fixture def surface(): return cairo.ImageSurface(cairo.Format.ARGB32, 10, 10) @pytest.fixture def image_surface(): return cairo.ImageSurface(cairo.Format.ARGB32, 10, 10) def test_create_similar(surface): similar = surface.create_similar(cairo.Content.COLOR, 10, 10) assert isinstance(similar, cairo.Surface) with pytest.raises(TypeError): surface.create_similar() def test_get_device_offset(surface): surface.set_device_offset(1, 1) assert surface.get_device_offset() == (1, 1) with pytest.raises(TypeError): surface.set_device_offset(1, object()) def test_get_fallback_resolution(surface): surface.set_fallback_resolution(42, 42) assert surface.get_fallback_resolution() == (42, 42) with pytest.raises(TypeError): surface.set_fallback_resolution(42, object()) def test_mark_dirty_rectangle(surface): surface.mark_dirty_rectangle(0, 0, 10, 10) with pytest.raises(TypeError): surface.mark_dirty_rectangle(0, 0, 10, object()) def test_write_to_png(image_surface): with pytest.raises(TypeError): image_surface.write_to_png() with pytest.raises((ValueError, TypeError)) as excinfo: image_surface.write_to_png("\x00") excinfo.match(r'.* (null|NUL) .*') with pytest.raises(TypeError): image_surface.write_to_png(object()) def test_image_surface(): with pytest.raises(TypeError): cairo.ImageSurface(cairo.FORMAT_ARGB32, 3, object()) def test_image_surface_create_for_data(): format_ = cairo.FORMAT_ARGB32 surface = cairo.ImageSurface(format_, 3, 3) ctx = cairo.Context(surface) ctx.paint() surface.flush() buf = surface.get_data() new = cairo.ImageSurface.create_for_data(buf, format_, 3, 3) assert new.get_data() == buf with pytest.raises(ValueError): cairo.ImageSurface.create_for_data(buf, format_, 3, -1) with pytest.raises(ValueError): cairo.ImageSurface.create_for_data(buf, format_, -1, 3) with pytest.raises(ValueError): cairo.ImageSurface.create_for_data(buf, format_, 0, 0, -1) with pytest.raises(cairo.Error) as excinfo: cairo.ImageSurface.create_for_data(buf, format_, 3, 3, 3) assert excinfo.value.status == cairo.STATUS_INVALID_STRIDE with pytest.raises(TypeError): cairo.ImageSurface.create_for_data(buf, format_, 3, object()) def test_image_surface_stride_for_width(): v = cairo.ImageSurface.format_stride_for_width(cairo.Format.ARGB32, 10) assert v == 40 with pytest.raises(TypeError): cairo.ImageSurface.format_stride_for_width( cairo.Format.ARGB32, object()) def test_image_surface_get_stride(image_surface): assert image_surface.get_stride() == 40 def test_recording_surface(): with pytest.raises(TypeError): cairo.RecordingSurface(cairo.CONTENT_COLOR, object()) with pytest.raises(TypeError): cairo.RecordingSurface() surface = cairo.RecordingSurface(cairo.CONTENT_COLOR, None) assert surface.ink_extents() == (0.0, 0.0, 0.0, 0.0)