Package lxml :: Package tests :: Module test_incremental_xmlfile |
[hide private]
[frames] | no frames]

# Source Code for Module lxml.tests.test_incremental_xmlfile

      1  # -*- coding: utf-8 -*-
      2
      3  """
      4  Tests for the incremental XML serialisation API.
      5  """
      6
      7  from __future__ import with_statement, absolute_import
      8
      9  import unittest
     10  import tempfile, os, sys
     11
     12  from lxml.etree import LxmlSyntaxError
     13
     14  this_dir = os.path.dirname(__file__)
     15  if this_dir not in sys.path:
     16      sys.path.insert(0, this_dir) # needed for Py3
     17
     18  from .common_imports import etree, BytesIO, HelperTestCase, skipIf, _str
     19
     20
     21 -class _XmlFileTestCaseBase(HelperTestCase):
     22      _file = None  # to be set by specific subtypes below
     23
     24 -    def test_element(self):
     25          with etree.xmlfile(self._file) as xf:
     26              with xf.element('test'):
     27                  pass
     28          self.assertXml('<test></test>')
     29
     30 -    def test_element_write_text(self):
     31          with etree.xmlfile(self._file) as xf:
     32              with xf.element('test'):
     33                  xf.write('toast')
     34          self.assertXml('<test>toast</test>')
     35
     36 -    def test_element_nested(self):
     37          with etree.xmlfile(self._file) as xf:
     38              with xf.element('test'):
     39                  with xf.element('toast'):
     40                      with xf.element('taste'):
     41                          xf.write('conTent')
     42          self.assertXml('<test><toast><taste>conTent</taste></toast></test>')
     43
     44 -    def test_element_nested_with_text(self):
     45          with etree.xmlfile(self._file) as xf:
     46              with xf.element('test'):
     47                  xf.write('con')
     48                  with xf.element('toast'):
     49                      xf.write('tent')
     50                      with xf.element('taste'):
     51                          xf.write('inside')
     52                      xf.write('tnet')
     53                  xf.write('noc')
     54          self.assertXml('<test>con<toast>tent<taste>inside</taste>'
     55                         'tnet</toast>noc</test>')
     56
     57 -    def test_write_Element(self):
     58          with etree.xmlfile(self._file) as xf:
     59              xf.write(etree.Element('test'))
     60          self.assertXml('<test/>')
     61
     62 -    def test_write_Element_repeatedly(self):
     63          element = etree.Element('test')
     64          with etree.xmlfile(self._file) as xf:
     65              with xf.element('test'):
     66                  for i in range(100):
     67                      xf.write(element)
     68
     69          tree = self._parse_file()
     70          self.assertTrue(tree is not None)
     71          self.assertEqual(100, len(tree.getroot()))
     72          self.assertEqual(set(['test']), set(el.tag for el in tree.getroot()))
     73
     74 -    def test_namespace_nsmap(self):
     75          with etree.xmlfile(self._file) as xf:
     76              with xf.element('{nsURI}test', nsmap={'x': 'nsURI'}):
     77                  pass
     78          self.assertXml('<x:test xmlns:x="nsURI"></x:test>')
     79
     80 -    def test_namespace_nested_nsmap(self):
     81          with etree.xmlfile(self._file) as xf:
     82              with xf.element('test', nsmap={'x': 'nsURI'}):
     83                  with xf.element('{nsURI}toast'):
     84                      pass
     85          self.assertXml('<test xmlns:x="nsURI"><x:toast></x:toast></test>')
     86
     87 -    def test_anonymous_namespace(self):
     88          with etree.xmlfile(self._file) as xf:
     89              with xf.element('{nsURI}test'):
     90                  pass
     91          self.assertXml('<ns0:test xmlns:ns0="nsURI"></ns0:test>')
     92
     93 -    def test_namespace_nested_anonymous(self):
     94          with etree.xmlfile(self._file) as xf:
     95              with xf.element('test'):
     96                  with xf.element('{nsURI}toast'):
     97                      pass
     98          self.assertXml('<test><ns0:toast xmlns:ns0="nsURI"></ns0:toast></test>')
     99
    100 -    def test_default_namespace(self):
    101          with etree.xmlfile(self._file) as xf:
    102              with xf.element('{nsURI}test', nsmap={None: 'nsURI'}):
    103                  pass
    104          self.assertXml('<test xmlns="nsURI"></test>')
    105
    106 -    def test_nested_default_namespace(self):
    107          with etree.xmlfile(self._file) as xf:
    108              with xf.element('{nsURI}test', nsmap={None: 'nsURI'}):
    109                  with xf.element('{nsURI}toast'):
    110                      pass
    111          self.assertXml('<test xmlns="nsURI"><toast></toast></test>')
    112
    113 -    def test_nested_default_namespace_and_other(self):
    114          with etree.xmlfile(self._file) as xf:
    115              with xf.element('{nsURI}test', nsmap={None: 'nsURI', 'p': 'ns2'}):
    116                  with xf.element('{nsURI}toast'):
    117                      pass
    118                  with xf.element('{ns2}toast'):
    119                      pass
    120          self.assertXml(
    121              '<test xmlns="nsURI" xmlns:p="ns2"><toast></toast><p:toast></p:toast></test>')
    122
    123 -    def test_pi(self):
    124          with etree.xmlfile(self._file) as xf:
    125              xf.write(etree.ProcessingInstruction('pypi'))
    126              with xf.element('test'):
    127                  pass
    128          self.assertXml('<?pypi ?><test></test>')
    129
    130 -    def test_comment(self):
    131          with etree.xmlfile(self._file) as xf:
    132              xf.write(etree.Comment('a comment'))
    133              with xf.element('test'):
    134                  pass
    135          self.assertXml('<!--a comment--><test></test>')
    136
    137 -    def test_attribute(self):
    138          with etree.xmlfile(self._file) as xf:
    139              with xf.element('test', attrib={'k': 'v'}):
    140                  pass
    141          self.assertXml('<test k="v"></test>')
    142
    143 -    def test_attribute_extra(self):
    144          with etree.xmlfile(self._file) as xf:
    145              with xf.element('test', attrib={'k': 'v'}, n='N'):
    146                  pass
    147          self.assertXml('<test k="v" n="N"></test>')
    148
    149 -    def test_attribute_extra_duplicate(self):
    150          with etree.xmlfile(self._file) as xf:
    151              with xf.element('test', attrib={'k': 'v'}, k='V'):
    152                  pass
    153          self.assertXml('<test k="V"></test>')
    154
    155 -    def test_escaping(self):
    156          with etree.xmlfile(self._file) as xf:
    157              with xf.element('test'):
    158                  xf.write('Comments: <!-- text -->\n')
    159                  xf.write('Entities: &amp;')
    160          self.assertXml(
    161              '<test>Comments: &lt;!-- text --&gt;\nEntities: &amp;amp;</test>')
    162
    163 -    def test_encoding(self):
    164          with etree.xmlfile(self._file, encoding='utf16') as xf:
    165              with xf.element('test'):
    166                  xf.write('toast')
    167          self.assertXml('<test>toast</test>', encoding='utf16')
    168
    169 -    def test_buffering(self):
    170          with etree.xmlfile(self._file, buffered=False) as xf:
    171              with xf.element('test'):
    172                  self.assertXml("<test>")
    173                  xf.write('toast')
    174                  self.assertXml("<test>toast")
    175                  with xf.element('taste'):
    176                      self.assertXml("<test>toast<taste>")
    177                      xf.write('some', etree.Element("more"), "toast")
    178                      self.assertXml("<test>toast<taste>some<more/>toast")
    179                  self.assertXml("<test>toast<taste>some<more/>toast</taste>")
    180                  xf.write('end')
    181                  self.assertXml("<test>toast<taste>some<more/>toast</taste>end")
    182              self.assertXml("<test>toast<taste>some<more/>toast</taste>end</test>")
    183          self.assertXml("<test>toast<taste>some<more/>toast</taste>end</test>")
    184
    185 -    def test_flush(self):
    186          with etree.xmlfile(self._file, buffered=True) as xf:
    187              with xf.element('test'):
    188                  self.assertXml("")
    189                  xf.write('toast')
    190                  self.assertXml("")
    191                  with xf.element('taste'):
    192                      self.assertXml("")
    193                      xf.flush()
    194                      self.assertXml("<test>toast<taste>")
    195                  self.assertXml("<test>toast<taste>")
    196              self.assertXml("<test>toast<taste>")
    197          self.assertXml("<test>toast<taste></taste></test>")
    198
    199 -    def test_failure_preceding_text(self):
    200          try:
    201              with etree.xmlfile(self._file) as xf:
    202                  xf.write('toast')
    203          except etree.LxmlSyntaxError:
    204              self.assertTrue(True)
    205          else:
    206              self.assertTrue(False)
    207
    208 -    def test_failure_trailing_text(self):
    209          with etree.xmlfile(self._file) as xf:
    210              with xf.element('test'):
    211                  pass
    212              try:
    213                  xf.write('toast')
    214              except etree.LxmlSyntaxError:
    215                  self.assertTrue(True)
    216              else:
    217                  self.assertTrue(False)
    218
    219 -    def test_failure_trailing_Element(self):
    220          with etree.xmlfile(self._file) as xf:
    221              with xf.element('test'):
    222                  pass
    223              try:
    224                  xf.write(etree.Element('test'))
    225              except etree.LxmlSyntaxError:
    226                  self.assertTrue(True)
    227              else:
    228                  self.assertTrue(False)
    229
    230 -    def test_closing_out_of_order_in_error_case(self):
    231          cm_exit = None
    232          try:
    233              with etree.xmlfile(self._file) as xf:
    234                  x = xf.element('test')
    235                  cm_exit = x.__exit__
    236                  x.__enter__()
    237                  raise ValueError('123')
    238          except ValueError:
    239              self.assertTrue(cm_exit)
    240              try:
    241                  cm_exit(ValueError, ValueError("huhu"), None)
    242              except etree.LxmlSyntaxError:
    243                  self.assertTrue(True)
    244              else:
    245                  self.assertTrue(False)
    246          else:
    247              self.assertTrue(False)
    248
    249 -    def _read_file(self):
    250          pos = self._file.tell()
    251          self._file.seek(0)
    252          try:
    253              return self._file.read()
    254          finally:
    255              self._file.seek(pos)
    256
    257 -    def _parse_file(self):
    258          pos = self._file.tell()
    259          self._file.seek(0)
    260          try:
    261              return etree.parse(self._file)
    262          finally:
    263              self._file.seek(pos)
    264
    265 -    def tearDown(self):
    266          if self._file is not None:
    267              self._file.close()
    268
    269 -    def assertXml(self, expected, encoding='utf8'):
    270          self.assertEqual(self._read_file().decode(encoding), expected)
    271
    272
    273 -class BytesIOXmlFileTestCase(_XmlFileTestCaseBase):
    274 -    def setUp(self):
    275          self._file = BytesIO()
    276
    277 -    def test_filelike_close(self):
    278          with etree.xmlfile(self._file, close=True) as xf:
    279              with xf.element('test'):
    280                  pass
    281          self.assertRaises(ValueError, self._file.getvalue)
    282
    283
    284 -class TempXmlFileTestCase(_XmlFileTestCaseBase):
    285 -    def setUp(self):
    286          self._file = tempfile.TemporaryFile()
    287
    288
    289  @skipIf(sys.platform.startswith("win"), "Can't reopen temporary files on Windows")
    290 -class TempPathXmlFileTestCase(_XmlFileTestCaseBase):
    291 -    def setUp(self):
    292          self._tmpfile = tempfile.NamedTemporaryFile()
    293          self._file = self._tmpfile.name
    294
    295 -    def tearDown(self):
    296          try:
    297              self._tmpfile.close()
    298          finally:
    299              if os.path.exists(self._tmpfile.name):
    300                  os.unlink(self._tmpfile.name)
    301
    302 -    def _read_file(self):
    303          self._tmpfile.seek(0)
    304          return self._tmpfile.read()
    305
    306 -    def _parse_file(self):
    307          self._tmpfile.seek(0)
    308          return etree.parse(self._tmpfile)
    309
    310      @skipIf(True, "temp file behaviour is too platform specific here")
    311 -    def test_buffering(self):
    312          pass
    313
    314      @skipIf(True, "temp file behaviour is too platform specific here")
    315 -    def test_flush(self):
    316          pass
    317
    318
    319 -class SimpleFileLikeXmlFileTestCase(_XmlFileTestCaseBase):
    320 -    class SimpleFileLike(object):
    321 -        def __init__(self, target):
    322              self._target = target
    323              self.write = target.write
    324              self.tell = target.tell
    325              self.seek = target.seek
    326              self.closed = False
    327
    328 -        def close(self):
    329              assert not self.closed
    330              self.closed = True
    331              self._target.close()
    332
    333 -    def setUp(self):
    334          self._target = BytesIO()
    335          self._file = self.SimpleFileLike(self._target)
    336
    337 -    def _read_file(self):
    338          return self._target.getvalue()
    339
    340 -    def _parse_file(self):
    341          pos = self._file.tell()
    342          self._target.seek(0)
    343          try:
    344              return etree.parse(self._target)
    345          finally:
    346              self._target.seek(pos)
    347
    348 -    def test_filelike_not_closing(self):
    349          with etree.xmlfile(self._file) as xf:
    350              with xf.element('test'):
    351                  pass
    352          self.assertFalse(self._file.closed)
    353
    354 -    def test_filelike_close(self):
    355          with etree.xmlfile(self._file, close=True) as xf:
    356              with xf.element('test'):
    357                  pass
    358          self.assertTrue(self._file.closed)
    359          self._file = None  # prevent closing in tearDown()
    360
    361
    362 -class HtmlFileTestCase(_XmlFileTestCaseBase):
    363 -    def setUp(self):
    364          self._file = BytesIO()
    365
    366 -    def test_void_elements(self):
    367          # http://www.w3.org/TR/html5/syntax.html#elements-0
    368          void_elements = set([
    369              "area", "base", "br", "col", "embed", "hr", "img",
    370              "input", "keygen", "link", "meta", "param",
    371              "source", "track", "wbr"
    372          ])
    373
    374          # FIXME: These don't get serialized as void elements.
    375          void_elements.difference_update([
    376              'area', 'embed', 'keygen', 'source', 'track', 'wbr'
    377          ])
    378
    379          for tag in sorted(void_elements):
    380              with etree.htmlfile(self._file) as xf:
    381                  xf.write(etree.Element(tag))
    382              self.assertXml('<%s>' % tag)
    383              self._file = BytesIO()
    384
    385 -    def test_method_context_manager_misuse(self):
    386          with etree.htmlfile(self._file) as xf:
    387              with xf.element('foo'):
    388                  cm = xf.method('xml')
    389                  cm.__enter__()
    390
    391                  self.assertRaises(LxmlSyntaxError, cm.__enter__)
    392
    393                  cm2 = xf.method('xml')
    394                  cm2.__enter__()
    395                  cm2.__exit__(None, None, None)
    396
    397                  self.assertRaises(LxmlSyntaxError, cm2.__exit__, None, None, None)
    398
    399                  cm3 = xf.method('xml')
    400                  cm3.__enter__()
    401                  with xf.method('html'):
    402                      self.assertRaises(LxmlSyntaxError, cm3.__exit__, None, None, None)
    403
    404 -    def test_xml_mode_write_inside_html(self):
    405          tag = 'foo'
    406          attrib = {'selected': 'bar'}
    407          elt = etree.Element(tag, attrib=attrib)
    408
    409          with etree.htmlfile(self._file) as xf:
    410              with xf.element("root"):
    411                  xf.write(elt)  # 1
    412
    413                  assert elt.text is None
    414                  xf.write(elt, method='xml')  # 2
    415
    416                  elt.text = ""
    417                  xf.write(elt, method='xml')  # 3
    418
    419                  with xf.element(tag, attrib=attrib, method='xml'):
    420                      pass # 4
    421
    422                  xf.write(elt)  # 5
    423
    424                  with xf.method('xml'):
    425                      xf.write(elt)  # 6
    426
    427          self.assertXml(
    428              '<root>'
    429                  '<foo selected></foo>'  # 1
    430                  '<foo selected="bar"/>'  # 2
    431                  '<foo selected="bar"></foo>'  # 3
    432                  '<foo selected="bar"></foo>'  # 4
    433                  '<foo selected></foo>'  # 5
    434                  '<foo selected="bar"></foo>'  # 6
    435              '</root>')
    436          self._file = BytesIO()
    437
    438 -    def test_xml_mode_element_inside_html(self):
    439          # The htmlfile already outputs in xml mode for .element calls. This
    440          # test actually illustrates a bug
    441
    442          with etree.htmlfile(self._file) as xf:
    443              with xf.element("root"):
    444                  with xf.element('foo', attrib={'selected': 'bar'}):
    445                      pass
    446
    447          self.assertXml(
    448              '<root>'
    449                # '<foo selected></foo>'  # FIXME: this is the correct output
    450                                          # in html mode
    451                '<foo selected="bar"></foo>'
    452              '</root>')
    453          self._file = BytesIO()
    454
    455 -    def test_attribute_quoting(self):
    456          with etree.htmlfile(self._file) as xf:
    457              with xf.element("tagname", attrib={"attr": '"misquoted"'}):
    458                  xf.write("foo")
    459
    460          self.assertXml('<tagname attr="&quot;misquoted&quot;">foo</tagname>')
    461
    462 -    def test_attribute_quoting_unicode(self):
    463          with etree.htmlfile(self._file) as xf:
    464              with xf.element("tagname", attrib={"attr": _str('"misquöted\\u3344\\U00013344"')}):
    465                  xf.write("foo")
    466
    467          self.assertXml('<tagname attr="&quot;misqu&#xF6;ted&#x3344;&#x13344;&quot;">foo</tagname>')
    468
    469 -    def test_unescaped_script(self):
    470          with etree.htmlfile(self._file) as xf:
    471              elt = etree.Element('script')
    472              elt.text = "if (a < b);"
    473              xf.write(elt)
    474          self.assertXml('<script>if (a < b);</script>')
    475
    476 -    def test_unescaped_script_incremental(self):
    477          with etree.htmlfile(self._file) as xf:
    478              with xf.element('script'):
    479                  xf.write("if (a < b);")
    480
    481          self.assertXml('<script>if (a < b);</script>')
    482
    483 -    def test_write_declaration(self):
    484          with etree.htmlfile(self._file) as xf:
    485              try:
    486                  xf.write_declaration()
    487              except etree.LxmlSyntaxError:
    488                  self.assertTrue(True)
    489              else:
    490                  self.assertTrue(False)
    491              xf.write(etree.Element('html'))
    492
    493 -    def test_write_namespaced_element(self):
    494          with etree.htmlfile(self._file) as xf:
    495              xf.write(etree.Element('{some_ns}some_tag'))
    496          self.assertXml('<ns0:some_tag xmlns:ns0="some_ns"></ns0:some_tag>')
    497
    498 -    def test_open_namespaced_element(self):
    499          with etree.htmlfile(self._file) as xf:
    500              with xf.element("{some_ns}some_tag"):
    501                  pass
    502          self.assertXml('<ns0:some_tag xmlns:ns0="some_ns"></ns0:some_tag>')
    503
    504
    505 -def test_suite():
    506      suite = unittest.TestSuite()
    507      suite.addTests([unittest.makeSuite(BytesIOXmlFileTestCase),
    508                      unittest.makeSuite(TempXmlFileTestCase),
    509                      unittest.makeSuite(TempPathXmlFileTestCase),
    510                      unittest.makeSuite(SimpleFileLikeXmlFileTestCase),
    511                      unittest.makeSuite(HtmlFileTestCase),
    512                      ])
    513      return suite
    514
    515  if __name__ == '__main__':
    516      print('to test use test.py %s' % __file__)
    517