# This file is part of CairoSVG # Copyright © 2010-2018 Kozea # # This library is free software: you can redistribute it and/or modify it under # the terms of the GNU Lesser General Public License as published by the Free # Software Foundation, either version 3 of the License, or (at your option) any # later version. # # This library is distributed in the hope that it will be useful, but WITHOUT # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS # FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more # details. # # You should have received a copy of the GNU Lesser General Public License # along with CairoSVG. If not, see . """ CairoSVG API test suite. These tests can be used as deployment tests. """ import io import os import shutil import sys import tempfile import cairocffi as cairo import pytest from . import SURFACES, VERSION, parser, surface, svg2pdf, svg2png from .__main__ import main MAGIC_NUMBERS = { 'SVG': b' ''' @pytest.mark.parametrize('format_name', MAGIC_NUMBERS) def test_formats(format_name): """Convert to a given format and test that output looks right.""" content = SURFACES[format_name].convert(SVG_SAMPLE) assert content.startswith(MAGIC_NUMBERS[format_name]) def read_file(filename): """Shortcut to return the whole content of a file as a byte string.""" with open(filename, 'rb') as file_object: return file_object.read() def test_api(): """Test the Python API with various parameters.""" expected_content = svg2png(SVG_SAMPLE) # Already tested above: just a sanity check: assert expected_content.startswith(MAGIC_NUMBERS['PNG']) # Read from a byte string assert svg2png(SVG_SAMPLE) == expected_content assert svg2png(bytestring=SVG_SAMPLE) == expected_content file_like = io.BytesIO(SVG_SAMPLE) # Read from a file-like object assert svg2png(file_obj=file_like) == expected_content file_like = io.BytesIO() # Write to a file-like object svg2png(SVG_SAMPLE, write_to=file_like) assert file_like.getvalue() == expected_content temp = tempfile.mkdtemp() try: temp_0 = os.path.join(temp, 'sample_0.svg') with open(temp_0, 'wb') as file_object: file_object.write(SVG_SAMPLE) # Read from a filename assert svg2png(url=temp_0) == expected_content assert svg2png( url='file://{}'.format(temp_0)) == expected_content with open(temp_0, 'rb') as file_object: # Read from a real file object assert svg2png(file_obj=file_object) == expected_content temp_1 = os.path.join(temp, 'result_1.png') with open(temp_1, 'wb') as file_object: # Write to a real file object svg2png(SVG_SAMPLE, write_to=file_object) assert read_file(temp_1) == expected_content temp_2 = os.path.join(temp, 'result_2.png') # Write to a filename svg2png(SVG_SAMPLE, write_to=temp_2) assert read_file(temp_2) == expected_content finally: shutil.rmtree(temp) file_like = io.BytesIO() try: svg2png(write_to=file_like) except TypeError: pass else: # pragma: no cover raise Exception('TypeError not raised') def test_low_level_api(): """Test the low-level Python API with various parameters.""" expected_content = svg2png(SVG_SAMPLE) # Same as above, longer version tree = parser.Tree(bytestring=SVG_SAMPLE) file_like = io.BytesIO() png_surface = surface.PNGSurface(tree, file_like, 96) png_surface.finish() assert file_like.getvalue() == expected_content png_result = cairo.ImageSurface.create_from_png( io.BytesIO(expected_content)) expected_width = png_result.get_width() expected_height = png_result.get_height() # Abstract surface png_surface = surface.PNGSurface(tree, None, 96) assert png_surface.width == expected_width assert png_surface.height == expected_height assert cairo.SurfacePattern(png_surface.cairo) def test_script(): """Test the ``cairosvg`` script and the ``main`` function.""" expected_png = svg2png(SVG_SAMPLE)[:100] expected_pdf = svg2pdf(SVG_SAMPLE)[:100] def test_main(args, exit_=False, input_=None, full=False): """Test main called with given ``args``. If ``exit_`` is ``True``, check that ``SystemExit`` is raised. We then assume that the program output is an unicode string. If ``input_`` is given, use this stream as input stream. """ sys.argv = ['cairosvg'] + args old_stdin, old_stdout = sys.stdin, sys.stdout output_buffer = io.BytesIO() sys.stdout = io.TextIOWrapper(output_buffer) if input_: sys.stdin = open(input_, 'rb') sys.stdin.buffer = sys.stdin if exit_: try: main() except SystemExit: pass else: # pragma: no cover raise Exception('CairoSVG did not exit') else: main() sys.stdout.flush() output = output_buffer.getvalue() sys.stdin, sys.stdout = old_stdin, old_stdout return output if full else output[:100] with tempfile.NamedTemporaryFile(delete=False) as file_object: file_object.write(SVG_SAMPLE) file_object.flush() svg_filename = file_object.name file_object.close() assert test_main(['--help'], exit_=True).startswith(b'usage: ') assert test_main(['--version'], exit_=True).strip() == ( VERSION.encode('ascii')) assert test_main([svg_filename]) == expected_pdf assert test_main([svg_filename, '-d', '96', '-f', 'pdf']) == ( expected_pdf) assert test_main([svg_filename, '-f', 'png']) == expected_png assert test_main(['-'], input_=svg_filename) == expected_pdf # Test DPI output = test_main([svg_filename, '-d', '10', '-f', 'png'], full=True) image = cairo.ImageSurface.create_from_png(io.BytesIO(output)) assert image.get_width() == 40 assert image.get_height() == 50 temp = tempfile.mkdtemp() try: temp_1 = os.path.join(temp, 'result_1') # Default to PDF assert not test_main([svg_filename, '-o', temp_1]) assert read_file(temp_1)[:100] == expected_pdf temp_2 = os.path.join(temp, 'result_2.png') # Guess from the file extension assert not test_main([svg_filename, '-o', temp_2]) assert read_file(temp_2)[:100] == expected_png temp_3 = os.path.join(temp, 'result_3.png') # Explicit -f wins assert not test_main([svg_filename, '-o', temp_3, '-f', 'pdf']) assert read_file(temp_3)[:100] == expected_pdf finally: shutil.rmtree(temp) try: os.remove(svg_filename) except PermissionError: # On Windows/NT systems, the temporary file sometimes fails to # get deleted due to ``PermissionError`` exception. This is due # to how Windows/NT handles the same file being opened twice at # the same time. pass