from __future__ import absolute_import """ Tests for the incremental XML serialisation API. Adapted from the tests from lxml.etree.xmlfile """ try: import lxml except ImportError: raise ImportError("lxml is required to run the tests.") from io import BytesIO import unittest import tempfile, os, sys from .common_imports import HelperTestCase, skipIf from et_xmlfile import xmlfile from et_xmlfile.xmlfile import LxmlSyntaxError import pytest from .helper import compare_xml import xml.etree.ElementTree from xml.etree.ElementTree import Element, parse class _XmlFileTestCaseBase(HelperTestCase): _file = None # to be set by specific subtypes below def setUp(self): self._file = BytesIO() def test_element(self): with xmlfile(self._file) as xf: with xf.element('test'): pass self.assertXml('') def test_element_write_text(self): with xmlfile(self._file) as xf: with xf.element('test'): xf.write('toast') self.assertXml('toast') def test_element_nested(self): with xmlfile(self._file) as xf: with xf.element('test'): with xf.element('toast'): with xf.element('taste'): xf.write('conTent') self.assertXml('conTent') def test_element_nested_with_text(self): with xmlfile(self._file) as xf: with xf.element('test'): xf.write('con') with xf.element('toast'): xf.write('tent') with xf.element('taste'): xf.write('inside') xf.write('tnet') xf.write('noc') self.assertXml('contentinside' 'tnetnoc') def test_write_Element(self): with xmlfile(self._file) as xf: xf.write(Element('test')) self.assertXml('') def test_write_Element_repeatedly(self): element = Element('test') with xmlfile(self._file) as xf: with xf.element('test'): for i in range(100): xf.write(element) tree = self._parse_file() self.assertTrue(tree is not None) self.assertEqual(100, len(tree.getroot())) self.assertEqual(set(['test']), set(el.tag for el in tree.getroot())) def test_namespace_nsmap(self): with xmlfile(self._file) as xf: with xf.element('{nsURI}test', nsmap={'x': 'nsURI'}): pass self.assertXml('') def test_namespace_nested_nsmap(self): with xmlfile(self._file) as xf: with xf.element('test', nsmap={'x': 'nsURI'}): with xf.element('{nsURI}toast'): pass self.assertXml('') def test_anonymous_namespace(self): with xmlfile(self._file) as xf: with xf.element('{nsURI}test'): pass self.assertXml('') def test_namespace_nested_anonymous(self): with xmlfile(self._file) as xf: with xf.element('test'): with xf.element('{nsURI}toast'): pass self.assertXml('') def test_default_namespace(self): with xmlfile(self._file) as xf: with xf.element('{nsURI}test', nsmap={None: 'nsURI'}): pass self.assertXml('') def test_nested_default_namespace(self): with xmlfile(self._file) as xf: with xf.element('{nsURI}test', nsmap={None: 'nsURI'}): with xf.element('{nsURI}toast'): pass self.assertXml('') @pytest.mark.xfail def test_pi(self): from et_xmlfile.xmlfile import ProcessingInstruction with xmlfile(self._file) as xf: xf.write(ProcessingInstruction('pypi')) with xf.element('test'): pass self.assertXml('') @pytest.mark.xfail def test_comment(self): with xmlfile(self._file) as xf: xf.write(etree.Comment('a comment')) with xf.element('test'): pass self.assertXml('') def test_attribute(self): with xmlfile(self._file) as xf: with xf.element('test', attrib={'k': 'v'}): pass self.assertXml('') def test_escaping(self): with xmlfile(self._file) as xf: with xf.element('test'): xf.write('Comments: \n') xf.write('Entities: &') self.assertXml( 'Comments: <!-- text -->\nEntities: &amp;') @pytest.mark.xfail def test_encoding(self): with xmlfile(self._file, encoding='utf16') as xf: with xf.element('test'): xf.write('toast') self.assertXml('toast', encoding='utf16') @pytest.mark.xfail def test_buffering(self): with xmlfile(self._file, buffered=False) as xf: with xf.element('test'): self.assertXml("") xf.write('toast') self.assertXml("toast") with xf.element('taste'): self.assertXml("toast") xf.write('some', etree.Element("more"), "toast") self.assertXml("toastsometoast") self.assertXml("toastsometoast") xf.write('end') self.assertXml("toastsometoastend") self.assertXml("toastsometoastend") self.assertXml("toastsometoastend") @pytest.mark.xfail def test_flush(self): with xmlfile(self._file, buffered=True) as xf: with xf.element('test'): self.assertXml("") xf.write('toast') self.assertXml("") with xf.element('taste'): self.assertXml("") xf.flush() self.assertXml("toast") self.assertXml("toast") self.assertXml("toast") self.assertXml("toast") def test_failure_preceding_text(self): try: with xmlfile(self._file) as xf: xf.write('toast') except LxmlSyntaxError: self.assertTrue(True) else: self.assertTrue(False) def test_failure_trailing_text(self): with xmlfile(self._file) as xf: with xf.element('test'): pass try: xf.write('toast') except LxmlSyntaxError: self.assertTrue(True) else: self.assertTrue(False) def test_failure_trailing_Element(self): with xmlfile(self._file) as xf: with xf.element('test'): pass try: xf.write(Element('test')) except LxmlSyntaxError: self.assertTrue(True) else: self.assertTrue(False) @pytest.mark.xfail def test_closing_out_of_order_in_error_case(self): cm_exit = None try: with xmlfile(self._file) as xf: x = xf.element('test') cm_exit = x.__exit__ x.__enter__() raise ValueError('123') except ValueError: self.assertTrue(cm_exit) try: cm_exit(ValueError, ValueError("huhu"), None) except LxmlSyntaxError: self.assertTrue(True) else: self.assertTrue(False) else: self.assertTrue(False) def _read_file(self): pos = self._file.tell() self._file.seek(0) try: return self._file.read() finally: self._file.seek(pos) def _parse_file(self): pos = self._file.tell() self._file.seek(0) try: return parse(self._file) finally: self._file.seek(pos) def tearDown(self): if self._file is not None: self._file.close() def assertXml(self, expected, encoding='utf8'): diff = compare_xml(self._read_file().decode(encoding), expected) assert diff is None, diff class BytesIOXmlFileTestCase(_XmlFileTestCaseBase): def setUp(self): self._file = BytesIO() def test_filelike_close(self): with xmlfile(self._file, close=True) as xf: with xf.element('test'): pass self.assertRaises(ValueError, self._file.getvalue) class TempXmlFileTestCase(_XmlFileTestCaseBase): def setUp(self): self._file = tempfile.TemporaryFile() class TempPathXmlFileTestCase(_XmlFileTestCaseBase): def setUp(self): self._tmpfile = tempfile.NamedTemporaryFile(delete=False) self._file = self._tmpfile.name def tearDown(self): try: self._tmpfile.close() finally: if os.path.exists(self._tmpfile.name): os.unlink(self._tmpfile.name) def _read_file(self): self._tmpfile.seek(0) return self._tmpfile.read() def _parse_file(self): self._tmpfile.seek(0) return parse(self._tmpfile) @skipIf(True, "temp file behaviour is too platform specific here") def test_buffering(self): pass @skipIf(True, "temp file behaviour is too platform specific here") def test_flush(self): pass class SimpleFileLikeXmlFileTestCase(_XmlFileTestCaseBase): class SimpleFileLike(object): def __init__(self, target): self._target = target self.write = target.write self.tell = target.tell self.seek = target.seek self.closed = False def close(self): assert not self.closed self.closed = True self._target.close() def setUp(self): self._target = BytesIO() self._file = self.SimpleFileLike(self._target) def _read_file(self): return self._target.getvalue() def _parse_file(self): pos = self._file.tell() self._target.seek(0) try: return parse(self._target) finally: self._target.seek(pos) def test_filelike_not_closing(self): with xmlfile(self._file) as xf: with xf.element('test'): pass self.assertFalse(self._file.closed) def test_filelike_close(self): with xmlfile(self._file, close=True) as xf: with xf.element('test'): pass self.assertTrue(self._file.closed) self._file = None # prevent closing in tearDown()