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

# Source Code for Module lxml.tests.test_etree

       1  # -*- coding: utf-8 -*-
       2
       3  """
       4  Tests specific to the extended etree API
       5
       6  Tests that apply to the general ElementTree API should go into
       7  test_elementtree
       8  """
       9
      10  from __future__ import absolute_import
      11
      12  import os.path
      13  import unittest
      14  import copy
      15  import sys
      16  import re
      17  import gc
      18  import operator
      19  import tempfile
      20  import textwrap
      21  import zlib
      22  import gzip
      23  from contextlib import closing, contextmanager
      24
      25  from .common_imports import etree, StringIO, BytesIO, HelperTestCase
      26  from .common_imports import fileInTestDir, fileUrlInTestDir, read_file, path2url
      27  from .common_imports import SillyFileLike, LargeFileLikeUnicode, doctest, make_doctest
      28  from .common_imports import canonicalize, _str, _bytes
      29
      30  print("")
      31  print("TESTED VERSION: %s" % etree.__version__)
      32  print("    Python:           " + repr(sys.version_info))
      33  print("    lxml.etree:       " + repr(etree.LXML_VERSION))
      34  print("    libxml used:      " + repr(etree.LIBXML_VERSION))
      35  print("    libxml compiled:  " + repr(etree.LIBXML_COMPILED_VERSION))
      36  print("    libxslt used:     " + repr(etree.LIBXSLT_VERSION))
      37  print("    libxslt compiled: " + repr(etree.LIBXSLT_COMPILED_VERSION))
      38  print("")
      39
      40  try:
      41      _unicode = unicode
      42  except NameError:
      43      # Python 3
      44      _unicode = str
      45
      46
      47  @contextmanager
      48 -def tmpfile():
      49      handle, filename = tempfile.mkstemp()
      50      try:
      51          yield filename
      52      finally:
      53          os.close(handle)
      54          os.remove(filename)
      55
      56
      57 -class ETreeOnlyTestCase(HelperTestCase):
      58      """Tests only for etree, not ElementTree"""
      59      etree = etree
      60
      61 -    def test_version(self):
      62          self.assertTrue(isinstance(etree.__version__, _unicode))
      63          self.assertTrue(isinstance(etree.LXML_VERSION, tuple))
      64          self.assertEqual(len(etree.LXML_VERSION), 4)
      65          self.assertTrue(isinstance(etree.LXML_VERSION[0], int))
      66          self.assertTrue(isinstance(etree.LXML_VERSION[1], int))
      67          self.assertTrue(isinstance(etree.LXML_VERSION[2], int))
      68          self.assertTrue(isinstance(etree.LXML_VERSION[3], int))
      69          self.assertTrue(etree.__version__.startswith(
      70              str(etree.LXML_VERSION[0])))
      71
      72 -    def test_c_api(self):
      73          if hasattr(self.etree, '__pyx_capi__'):
      74              # newer Pyrex compatible C-API
      75              self.assertTrue(isinstance(self.etree.__pyx_capi__, dict))
      76              self.assertTrue(len(self.etree.__pyx_capi__) > 0)
      77          else:
      78              # older C-API mechanism
      79              self.assertTrue(hasattr(self.etree, '_import_c_api'))
      80
      81 -    def test_include_paths(self):
      82          import lxml
      83          includes = lxml.get_include()
      84          self.assertTrue(includes)
      85          self.assertTrue(len(includes) >= 2)
      86          self.assertTrue(os.path.join(os.path.dirname(lxml.__file__), 'includes') in includes,
      87                          includes)
      88
      89 -    def test_element_names(self):
      90          Element = self.etree.Element
      91          el = Element('name')
      92          self.assertEqual(el.tag, 'name')
      93          el = Element('{}name')
      94          self.assertEqual(el.tag, 'name')
      95
      96 -    def test_element_name_empty(self):
      97          Element = self.etree.Element
      98          el = Element('name')
      99          self.assertRaises(ValueError, Element, '{}')
     100          self.assertRaises(ValueError, setattr, el, 'tag', '{}')
     101
     102          self.assertRaises(ValueError, Element, '{test}')
     103          self.assertRaises(ValueError, setattr, el, 'tag', '{test}')
     104
     105 -    def test_element_name_colon(self):
     106          Element = self.etree.Element
     107          self.assertRaises(ValueError, Element, 'p:name')
     108          self.assertRaises(ValueError, Element, '{test}p:name')
     109
     110          el = Element('name')
     111          self.assertRaises(ValueError, setattr, el, 'tag', 'p:name')
     112
     113 -    def test_element_name_quote(self):
     114          Element = self.etree.Element
     115          self.assertRaises(ValueError, Element, "p'name")
     116          self.assertRaises(ValueError, Element, 'p"name')
     117
     118          self.assertRaises(ValueError, Element, "{test}p'name")
     119          self.assertRaises(ValueError, Element, '{test}p"name')
     120
     121          el = Element('name')
     122          self.assertRaises(ValueError, setattr, el, 'tag', "p'name")
     123          self.assertRaises(ValueError, setattr, el, 'tag', 'p"name')
     124
     125 -    def test_element_name_space(self):
     126          Element = self.etree.Element
     127          self.assertRaises(ValueError, Element, ' name ')
     128          self.assertRaises(ValueError, Element, 'na me')
     129          self.assertRaises(ValueError, Element, '{test} name')
     130
     131          el = Element('name')
     132          self.assertRaises(ValueError, setattr, el, 'tag', ' name ')
     133
     134 -    def test_subelement_name_empty(self):
     135          Element = self.etree.Element
     136          SubElement = self.etree.SubElement
     137
     138          el = Element('name')
     139          self.assertRaises(ValueError, SubElement, el, '{}')
     140          self.assertRaises(ValueError, SubElement, el, '{test}')
     141
     142 -    def test_subelement_name_colon(self):
     143          Element = self.etree.Element
     144          SubElement = self.etree.SubElement
     145
     146          el = Element('name')
     147          self.assertRaises(ValueError, SubElement, el, 'p:name')
     148          self.assertRaises(ValueError, SubElement, el, '{test}p:name')
     149
     150 -    def test_subelement_name_quote(self):
     151          Element = self.etree.Element
     152          SubElement = self.etree.SubElement
     153
     154          el = Element('name')
     155          self.assertRaises(ValueError, SubElement, el, "p'name")
     156          self.assertRaises(ValueError, SubElement, el, "{test}p'name")
     157
     158          self.assertRaises(ValueError, SubElement, el, 'p"name')
     159          self.assertRaises(ValueError, SubElement, el, '{test}p"name')
     160
     161 -    def test_subelement_name_space(self):
     162          Element = self.etree.Element
     163          SubElement = self.etree.SubElement
     164
     165          el = Element('name')
     166          self.assertRaises(ValueError, SubElement, el, ' name ')
     167          self.assertRaises(ValueError, SubElement, el, 'na me')
     168          self.assertRaises(ValueError, SubElement, el, '{test} name')
     169
     170 -    def test_subelement_attribute_invalid(self):
     171          Element = self.etree.Element
     172          SubElement = self.etree.SubElement
     173
     174          el = Element('name')
     175          self.assertRaises(ValueError, SubElement, el, 'name', {'a b c' : 'abc'})
     176          self.assertRaises(ValueError, SubElement, el, 'name', {'a' : 'a\0\n'})
     177          self.assertEqual(0, len(el))
     178
     179 -    def test_qname_empty(self):
     180          QName = self.etree.QName
     181          self.assertRaises(ValueError, QName, '')
     182          self.assertRaises(ValueError, QName, None)
     183          self.assertRaises(ValueError, QName, None, None)
     184          self.assertRaises(ValueError, QName, 'test', '')
     185
     186 -    def test_qname_none(self):
     187          QName = self.etree.QName
     188          q = QName(None, 'TAG')
     189          self.assertEqual('TAG', q)
     190          self.assertEqual('TAG', q.localname)
     191          self.assertEqual(None, q.namespace)
     192
     193 -    def test_qname_colon(self):
     194          QName = self.etree.QName
     195          self.assertRaises(ValueError, QName, 'p:name')
     196          self.assertRaises(ValueError, QName, 'test', 'p:name')
     197
     198 -    def test_qname_space(self):
     199          QName = self.etree.QName
     200          self.assertRaises(ValueError, QName, ' name ')
     201          self.assertRaises(ValueError, QName, 'na me')
     202          self.assertRaises(ValueError, QName, 'test', ' name')
     203
     204 -    def test_qname_namespace_localname(self):
     205          # ET doesn't have namespace/localname properties on QNames
     206          QName = self.etree.QName
     207          namespace, localname = 'http://myns', 'a'
     208          qname = QName(namespace, localname)
     209          self.assertEqual(namespace, qname.namespace)
     210          self.assertEqual(localname, qname.localname)
     211
     212 -    def test_qname_element(self):
     213          # ET doesn't have namespace/localname properties on QNames
     214          QName = self.etree.QName
     215          qname1 = QName('http://myns', 'a')
     216          a = self.etree.Element(qname1, nsmap={'p' : 'http://myns'})
     217
     218          qname2 = QName(a)
     219          self.assertEqual(a.tag, qname1.text)
     220          self.assertEqual(a.tag, qname1)
     221          self.assertEqual(qname1.text, qname2.text)
     222          self.assertEqual(qname1, qname2.text)
     223          self.assertEqual(qname1.text, qname2)
     224          self.assertEqual(qname1, qname2)
     225
     226 -    def test_qname_text_resolve(self):
     227          # ET doesn't resove QNames as text values
     228          etree = self.etree
     229          qname = etree.QName('http://myns', 'a')
     230          a = etree.Element(qname, nsmap={'p' : 'http://myns'})
     231          a.text = qname
     232
     233          self.assertEqual("p:a", a.text)
     234
     235 -    def test_nsmap_prefix_invalid(self):
     236          etree = self.etree
     237          self.assertRaises(ValueError,
     238                            etree.Element, "root", nsmap={'"' : 'testns'})
     239          self.assertRaises(ValueError,
     240                            etree.Element, "root", nsmap={'&' : 'testns'})
     241          self.assertRaises(ValueError,
     242                            etree.Element, "root", nsmap={'a:b' : 'testns'})
     243
     244 -    def test_attribute_has_key(self):
     245          # ET in Py 3.x has no "attrib.has_key()" method
     246          XML = self.etree.XML
     247
     248          root = XML(_bytes('<foo bar="Bar" xmlns:ns="http://ns.codespeak.net/test" ns:baz="Baz" />'))
     249          self.assertEqual(
     250              True, root.attrib.has_key('bar'))
     251          self.assertEqual(
     252              False, root.attrib.has_key('baz'))
     253          self.assertEqual(
     254              False, root.attrib.has_key('hah'))
     255          self.assertEqual(
     256              True,
     257              root.attrib.has_key('{http://ns.codespeak.net/test}baz'))
     258
     259 -    def test_attribute_set(self):
     260          Element = self.etree.Element
     261          root = Element("root")
     262          root.set("attr", "TEST")
     263          self.assertEqual("TEST", root.get("attr"))
     264
     265 -    def test_attribute_set_nonstring(self):
     266          # ElementTree accepts arbitrary attribute values
     267          # lxml.etree allows only strings
     268          Element = self.etree.Element
     269
     270          root = Element("root")
     271          root.set("attr", "TEST")
     272          self.assertEqual("TEST", root.get("attr"))
     273          self.assertRaises(TypeError, root.set, "newattr", 5)
     274
     275 -    def test_attrib_and_keywords(self):
     276          Element = self.etree.Element
     277
     278          root = Element("root")
     279          root.set("attr", "TEST")
     280          self.assertEqual("TEST", root.attrib["attr"])
     281
     282          root2 = Element("root2", root.attrib, attr2='TOAST')
     283          self.assertEqual("TEST", root2.attrib["attr"])
     284          self.assertEqual("TOAST", root2.attrib["attr2"])
     285          self.assertEqual(None, root.attrib.get("attr2"))
     286
     287 -    def test_attrib_order(self):
     288          Element = self.etree.Element
     289
     290          keys = ["attr%d" % i for i in range(10)]
     291          values = ["TEST-%d" % i for i in range(10)]
     292          items = list(zip(keys, values))
     293
     294          root = Element("root")
     295          for key, value in items:
     296              root.set(key, value)
     297          self.assertEqual(keys, root.attrib.keys())
     298          self.assertEqual(values, root.attrib.values())
     299
     300          root2 = Element("root2", root.attrib,
     301                          attr_99='TOAST-1', attr_98='TOAST-2')
     302          self.assertEqual(['attr_98', 'attr_99'] + keys,
     303                           root2.attrib.keys())
     304          self.assertEqual(['TOAST-2', 'TOAST-1'] + values,
     305                           root2.attrib.values())
     306
     307          self.assertEqual(keys, root.attrib.keys())
     308          self.assertEqual(values, root.attrib.values())
     309
     310 -    def test_attribute_set_invalid(self):
     311          # ElementTree accepts arbitrary attribute values
     312          # lxml.etree allows only strings, or None for (html5) boolean attributes
     313          Element = self.etree.Element
     314          root = Element("root")
     315          self.assertRaises(TypeError, root.set, "newattr", 5)
     316          self.assertRaises(TypeError, root.set, "newattr", object)
     317          self.assertRaises(TypeError, root.set, "newattr", None)
     318          self.assertRaises(TypeError, root.set, "newattr")
     319
     320 -    def test_strip_attributes(self):
     321          XML = self.etree.XML
     322          xml = _bytes('<test a="5" b="10" c="20"><x a="4" b="2"/></test>')
     323
     324          root = XML(xml)
     325          self.etree.strip_attributes(root, 'a')
     326          self.assertEqual(_bytes('<test b="10" c="20"><x b="2"></x></test>'),
     327                            self._writeElement(root))
     328
     329          root = XML(xml)
     330          self.etree.strip_attributes(root, 'b', 'c')
     331          self.assertEqual(_bytes('<test a="5"><x a="4"></x></test>'),
     332                            self._writeElement(root))
     333
     334 -    def test_strip_attributes_ns(self):
     335          XML = self.etree.XML
     336          xml = _bytes('<test xmlns:n="http://test/ns" a="6" b="10" c="20" n:a="5"><x a="4" n:b="2"/></test>')
     337
     338          root = XML(xml)
     339          self.etree.strip_attributes(root, 'a')
     340          self.assertEqual(
     341              _bytes('<test xmlns:n="http://test/ns" b="10" c="20" n:a="5"><x n:b="2"></x></test>'),
     342              self._writeElement(root))
     343
     344          root = XML(xml)
     345          self.etree.strip_attributes(root, '{http://test/ns}a', 'c')
     346          self.assertEqual(
     347              _bytes('<test xmlns:n="http://test/ns" a="6" b="10"><x a="4" n:b="2"></x></test>'),
     348              self._writeElement(root))
     349
     350          root = XML(xml)
     351          self.etree.strip_attributes(root, '{http://test/ns}*')
     352          self.assertEqual(
     353              _bytes('<test xmlns:n="http://test/ns" a="6" b="10" c="20"><x a="4"></x></test>'),
     354              self._writeElement(root))
     355
     356 -    def test_strip_elements(self):
     357          XML = self.etree.XML
     358          xml = _bytes('<test><a><b><c/></b></a><x><a><b/><c/></a></x></test>')
     359
     360          root = XML(xml)
     361          self.etree.strip_elements(root, 'a')
     362          self.assertEqual(_bytes('<test><x></x></test>'),
     363                            self._writeElement(root))
     364
     365          root = XML(xml)
     366          self.etree.strip_elements(root, 'b', 'c', 'X', 'Y', 'Z')
     367          self.assertEqual(_bytes('<test><a></a><x><a></a></x></test>'),
     368                            self._writeElement(root))
     369
     370          root = XML(xml)
     371          self.etree.strip_elements(root, 'c')
     372          self.assertEqual(_bytes('<test><a><b></b></a><x><a><b></b></a></x></test>'),
     373                            self._writeElement(root))
     374
     375 -    def test_strip_elements_ns(self):
     376          XML = self.etree.XML
     377          xml = _bytes('<test>TEST<n:a xmlns:n="urn:a">A<b>B<c xmlns="urn:c"/>C</b>BT</n:a>AT<x>X<a>A<b xmlns="urn:a"/>BT<c xmlns="urn:x"/>CT</a>AT</x>XT</test>')
     378
     379          root = XML(xml)
     380          self.etree.strip_elements(root, 'a')
     381          self.assertEqual(_bytes('<test>TEST<n:a xmlns:n="urn:a">A<b>B<c xmlns="urn:c"></c>C</b>BT</n:a>AT<x>X</x>XT</test>'),
     382                            self._writeElement(root))
     383
     384          root = XML(xml)
     385          self.etree.strip_elements(root, '{urn:a}b', 'c')
     386          self.assertEqual(_bytes('<test>TEST<n:a xmlns:n="urn:a">A<b>B<c xmlns="urn:c"></c>C</b>BT</n:a>AT<x>X<a>A<c xmlns="urn:x"></c>CT</a>AT</x>XT</test>'),
     387                            self._writeElement(root))
     388
     389          root = XML(xml)
     390          self.etree.strip_elements(root, '{urn:a}*', 'c')
     391          self.assertEqual(_bytes('<test>TEST<x>X<a>A<c xmlns="urn:x"></c>CT</a>AT</x>XT</test>'),
     392                            self._writeElement(root))
     393
     394          root = XML(xml)
     395          self.etree.strip_elements(root, '{urn:a}*', 'c', with_tail=False)
     396          self.assertEqual(_bytes('<test>TESTAT<x>X<a>ABT<c xmlns="urn:x"></c>CT</a>AT</x>XT</test>'),
     397                            self._writeElement(root))
     398
     399 -    def test_strip_tags(self):
     400          XML = self.etree.XML
     401          xml = _bytes('<test>TEST<a>A<b>B<c/>CT</b>BT</a>AT<x>X<a>A<b/>BT<c/>CT</a>AT</x>XT</test>')
     402
     403          root = XML(xml)
     404          self.etree.strip_tags(root, 'a')
     405          self.assertEqual(_bytes('<test>TESTA<b>B<c></c>CT</b>BTAT<x>XA<b></b>BT<c></c>CTAT</x>XT</test>'),
     406                            self._writeElement(root))
     407
     408          root = XML(xml)
     409          self.etree.strip_tags(root, 'b', 'c', 'X', 'Y', 'Z')
     410          self.assertEqual(_bytes('<test>TEST<a>ABCTBT</a>AT<x>X<a>ABTCT</a>AT</x>XT</test>'),
     411                            self._writeElement(root))
     412
     413          root = XML(xml)
     414          self.etree.strip_tags(root, 'c')
     415          self.assertEqual(_bytes('<test>TEST<a>A<b>BCT</b>BT</a>AT<x>X<a>A<b></b>BTCT</a>AT</x>XT</test>'),
     416                            self._writeElement(root))
     417
     418 -    def test_strip_tags_pi_comment(self):
     419          XML = self.etree.XML
     420          PI = self.etree.ProcessingInstruction
     421          Comment = self.etree.Comment
     422          xml = _bytes('<!--comment1-->\n<?PI1?>\n<test>TEST<!--comment2-->XT<?PI2?></test>\n<!--comment3-->\n<?PI1?>')
     423
     424          root = XML(xml)
     425          self.etree.strip_tags(root, PI)
     426          self.assertEqual(_bytes('<!--comment1-->\n<?PI1?>\n<test>TEST<!--comment2-->XT</test>\n<!--comment3-->\n<?PI1?>'),
     427                            self._writeElement(root))
     428
     429          root = XML(xml)
     430          self.etree.strip_tags(root, Comment)
     431          self.assertEqual(_bytes('<!--comment1-->\n<?PI1?>\n<test>TESTXT<?PI2?></test>\n<!--comment3-->\n<?PI1?>'),
     432                            self._writeElement(root))
     433
     434          root = XML(xml)
     435          self.etree.strip_tags(root, PI, Comment)
     436          self.assertEqual(_bytes('<!--comment1-->\n<?PI1?>\n<test>TESTXT</test>\n<!--comment3-->\n<?PI1?>'),
     437                            self._writeElement(root))
     438
     439          root = XML(xml)
     440          self.etree.strip_tags(root, Comment, PI)
     441          self.assertEqual(_bytes('<!--comment1-->\n<?PI1?>\n<test>TESTXT</test>\n<!--comment3-->\n<?PI1?>'),
     442                            self._writeElement(root))
     443
     444 -    def test_strip_tags_pi_comment_all(self):
     445          XML = self.etree.XML
     446          ElementTree = self.etree.ElementTree
     447          PI = self.etree.ProcessingInstruction
     448          Comment = self.etree.Comment
     449          xml = _bytes('<!--comment1-->\n<?PI1?>\n<test>TEST<!--comment2-->XT<?PI2?></test>\n<!--comment3-->\n<?PI1?>')
     450
     451          root = XML(xml)
     452          self.etree.strip_tags(ElementTree(root), PI)
     453          self.assertEqual(_bytes('<!--comment1-->\n<test>TEST<!--comment2-->XT</test>\n<!--comment3-->'),
     454                            self._writeElement(root))
     455
     456          root = XML(xml)
     457          self.etree.strip_tags(ElementTree(root), Comment)
     458          self.assertEqual(_bytes('<?PI1?>\n<test>TESTXT<?PI2?></test>\n<?PI1?>'),
     459                            self._writeElement(root))
     460
     461          root = XML(xml)
     462          self.etree.strip_tags(ElementTree(root), PI, Comment)
     463          self.assertEqual(_bytes('<test>TESTXT</test>'),
     464                            self._writeElement(root))
     465
     466          root = XML(xml)
     467          self.etree.strip_tags(ElementTree(root), Comment, PI)
     468          self.assertEqual(_bytes('<test>TESTXT</test>'),
     469                            self._writeElement(root))
     470
     471 -    def test_strip_tags_doc_style(self):
     472          XML = self.etree.XML
     473          xml = _bytes('''
     474          <div>
     475              <div>
     476                  I like <strong>sheep</strong>.
     477                  <br/>
     478                  I like lots of <strong>sheep</strong>.
     479                  <br/>
     480                  Click <a href="http://www.sheep.com">here</a>
     481                   for <a href="http://www.sheep.com">those</a> sheep.
     482                  <br/>
     483              </div>
     484          </div>
     485          '''.strip())
     486
     487          root = XML(xml)
     488          self.etree.strip_tags(root, 'a')
     489          self.assertEqual(re.sub(_bytes('</?a[^>]*>'), _bytes(''), xml).replace(_bytes('<br/>'), _bytes('<br></br>')),
     490                            self._writeElement(root))
     491
     492          root = XML(xml)
     493          self.etree.strip_tags(root, 'a', 'br')
     494          self.assertEqual(re.sub(_bytes('</?a[^>]*>'), _bytes(''),
     495                                   re.sub(_bytes('<br[^>]*>'), _bytes(''), xml)),
     496                            self._writeElement(root))
     497
     498 -    def test_strip_tags_ns(self):
     499          XML = self.etree.XML
     500          xml = _bytes('<test>TEST<n:a xmlns:n="urn:a">A<b>B<c xmlns="urn:c"/>CT</b>BT</n:a>AT<x>X<a>A<b xmlns="urn:a"/>BT<c xmlns="urn:x"/>CT</a>AT</x>XT</test>')
     501
     502          root = XML(xml)
     503          self.etree.strip_tags(root, 'a')
     504          self.assertEqual(_bytes('<test>TEST<n:a xmlns:n="urn:a">A<b>B<c xmlns="urn:c"></c>CT</b>BT</n:a>AT<x>XA<b xmlns="urn:a"></b>BT<c xmlns="urn:x"></c>CTAT</x>XT</test>'),
     505                            self._writeElement(root))
     506
     507          root = XML(xml)
     508          self.etree.strip_tags(root, '{urn:a}b', 'c')
     509          self.assertEqual(_bytes('<test>TEST<n:a xmlns:n="urn:a">A<b>B<c xmlns="urn:c"></c>CT</b>BT</n:a>AT<x>X<a>ABT<c xmlns="urn:x"></c>CT</a>AT</x>XT</test>'),
     510                            self._writeElement(root))
     511
     512          root = XML(xml)
     513          self.etree.strip_tags(root, '{urn:a}*', 'c')
     514          self.assertEqual(_bytes('<test>TESTA<b>B<c xmlns="urn:c"></c>CT</b>BTAT<x>X<a>ABT<c xmlns="urn:x"></c>CT</a>AT</x>XT</test>'),
     515                            self._writeElement(root))
     516
     517 -    def test_strip_tags_and_remove(self):
     518          # previously crashed
     519          HTML = self.etree.HTML
     520          root = HTML(_bytes('<div><h1>title</h1> <b>foo</b> <p>boo</p></div>'))[0][0]
     521          self.assertEqual(_bytes('<div><h1>title</h1> <b>foo</b> <p>boo</p></div>'),
     522                            self.etree.tostring(root))
     523          self.etree.strip_tags(root, 'b')
     524          self.assertEqual(_bytes('<div><h1>title</h1> foo <p>boo</p></div>'),
     525                            self.etree.tostring(root))
     526          root.remove(root[0])
     527          self.assertEqual(_bytes('<div><p>boo</p></div>'),
     528                            self.etree.tostring(root))
     529
     530 -    def test_pi(self):
     531          # lxml.etree separates target and text
     532          Element = self.etree.Element
     533          SubElement = self.etree.SubElement
     534          ProcessingInstruction = self.etree.ProcessingInstruction
     535
     536          a = Element('a')
     537          a.append(ProcessingInstruction('foo', 'some more text'))
     538          self.assertEqual(a[0].target, 'foo')
     539          self.assertEqual(a[0].text, 'some more text')
     540
     541 -    def test_pi_parse(self):
     542          XML = self.etree.XML
     543          root = XML(_bytes("<test><?mypi my test ?></test>"))
     544          self.assertEqual(root[0].target, "mypi")
     545          self.assertEqual(root[0].text, "my test ")
     546
     547 -    def test_pi_pseudo_attributes_get(self):
     548          XML = self.etree.XML
     549          root = XML(_bytes("<test><?mypi my='1' test=\" abc \" quotes=\"' '\" only names ?></test>"))
     550          self.assertEqual(root[0].target, "mypi")
     551          self.assertEqual(root[0].get('my'), "1")
     552          self.assertEqual(root[0].get('test'), " abc ")
     553          self.assertEqual(root[0].get('quotes'), "' '")
     554          self.assertEqual(root[0].get('only'), None)
     555          self.assertEqual(root[0].get('names'), None)
     556          self.assertEqual(root[0].get('nope'), None)
     557
     558 -    def test_pi_pseudo_attributes_attrib(self):
     559          XML = self.etree.XML
     560          root = XML(_bytes("<test><?mypi my='1' test=\" abc \" quotes=\"' '\" only names ?></test>"))
     561          self.assertEqual(root[0].target, "mypi")
     562          self.assertEqual(root[0].attrib['my'], "1")
     563          self.assertEqual(root[0].attrib['test'], " abc ")
     564          self.assertEqual(root[0].attrib['quotes'], "' '")
     565          self.assertRaises(KeyError, root[0].attrib.__getitem__, 'only')
     566          self.assertRaises(KeyError, root[0].attrib.__getitem__, 'names')
     567          self.assertRaises(KeyError, root[0].attrib.__getitem__, 'nope')
     568
     569 -    def test_deepcopy_pi(self):
     570          # previously caused a crash
     571          ProcessingInstruction = self.etree.ProcessingInstruction
     572
     573          a = ProcessingInstruction("PI", "ONE")
     574          b = copy.deepcopy(a)
     575          b.text = "ANOTHER"
     576
     577          self.assertEqual('ONE',     a.text)
     578          self.assertEqual('ANOTHER', b.text)
     579
     580 -    def test_deepcopy_elementtree_pi(self):
     581          XML = self.etree.XML
     582          tostring = self.etree.tostring
     583          root = XML(_bytes("<?mypi my test ?><test/><!--comment -->"))
     584          tree1 = self.etree.ElementTree(root)
     585          self.assertEqual(_bytes("<?mypi my test ?><test/><!--comment -->"),
     586                            tostring(tree1))
     587
     588          tree2 = copy.deepcopy(tree1)
     589          self.assertEqual(_bytes("<?mypi my test ?><test/><!--comment -->"),
     590                            tostring(tree2))
     591
     592          root2 = copy.deepcopy(tree1.getroot())
     593          self.assertEqual(_bytes("<test/>"),
     594                            tostring(root2))
     595
     596 -    def test_deepcopy_elementtree_dtd(self):
     597          XML = self.etree.XML
     598          tostring = self.etree.tostring
     599          xml = _bytes('<!DOCTYPE test [\n<!ENTITY entity "tasty">\n]>\n<test/>')
     600          root = XML(xml)
     601          tree1 = self.etree.ElementTree(root)
     602          self.assertEqual(xml, tostring(tree1))
     603
     604          tree2 = copy.deepcopy(tree1)
     605          self.assertEqual(xml, tostring(tree2))
     606
     607          root2 = copy.deepcopy(tree1.getroot())
     608          self.assertEqual(_bytes("<test/>"),
     609                            tostring(root2))
     610
     611 -    def test_deepcopy_pi_dtd(self):
     612          XML = self.etree.XML
     613          tostring = self.etree.tostring
     614          xml = _bytes('<!-- comment --><!DOCTYPE test [\n<!ENTITY entity "tasty">\n]>\n<test/>')
     615          root = XML(xml)
     616          tree1 = self.etree.ElementTree(root)
     617          self.assertEqual(xml, tostring(tree1))
     618
     619          tree2 = copy.deepcopy(tree1)
     620          self.assertEqual(xml, tostring(tree2))
     621
     622 -    def test_parse_remove_comments(self):
     623          fromstring = self.etree.fromstring
     624          tostring = self.etree.tostring
     625          XMLParser = self.etree.XMLParser
     626
     627          xml = _bytes('<a><!--A--><b><!-- B --><c/></b><!--C--></a>')
     628          parser = XMLParser(remove_comments=True)
     629          root = fromstring(xml, parser)
     630          self.assertEqual(
     631              _bytes('<a><b><c/></b></a>'),
     632              tostring(root))
     633
     634 -    def test_parse_remove_pis(self):
     635          parse = self.etree.parse
     636          tostring = self.etree.tostring
     637          XMLParser = self.etree.XMLParser
     638
     639          xml = _bytes('<?test?><a><?A?><b><?B?><c/></b><?C?></a><?tail?>')
     640
     641          f = BytesIO(xml)
     642          tree = parse(f)
     643          self.assertEqual(
     644              xml,
     645              tostring(tree))
     646
     647          parser = XMLParser(remove_pis=True)
     648          tree = parse(f, parser)
     649          self.assertEqual(
     650              _bytes('<a><b><c/></b></a>'),
     651              tostring(tree))
     652
     653 -    def test_parse_parser_type_error(self):
     654          # ET raises IOError only
     655          parse = self.etree.parse
     656          self.assertRaises(TypeError, parse, 'notthere.xml', object())
     657
     658 -    def test_iterparse_tree_comments(self):
     659          # ET removes comments
     660          iterparse = self.etree.iterparse
     661          tostring = self.etree.tostring
     662
     663          f = BytesIO('<a><!--A--><b><!-- B --><c/></b><!--C--></a>')
     664          events = list(iterparse(f))
     665          root = events[-1][1]
     666          self.assertEqual(3, len(events))
     667          self.assertEqual(
     668              _bytes('<a><!--A--><b><!-- B --><c/></b><!--C--></a>'),
     669              tostring(root))
     670
     671 -    def test_iterparse_comments(self):
     672          # ET removes comments
     673          iterparse = self.etree.iterparse
     674          tostring = self.etree.tostring
     675
     676          def name(event, el):
     677              if event == 'comment':
     678                  return el.text
     679              else:
     680                  return el.tag
     681
     682          f = BytesIO('<a><!--A--><b><!-- B --><c/></b><!--C--></a>')
     683          events = list(iterparse(f, events=('end', 'comment')))
     684          root = events[-1][1]
     685          self.assertEqual(6, len(events))
     686          self.assertEqual(['A', ' B ', 'c', 'b', 'C', 'a'],
     687                            [ name(*item) for item in events ])
     688          self.assertEqual(
     689              _bytes('<a><!--A--><b><!-- B --><c/></b><!--C--></a>'),
     690              tostring(root))
     691
     692 -    def test_iterparse_pis(self):
     693          # ET removes pis
     694          iterparse = self.etree.iterparse
     695          tostring = self.etree.tostring
     696          ElementTree = self.etree.ElementTree
     697
     698          def name(event, el):
     699              if event == 'pi':
     700                  return (el.target, el.text)
     701              else:
     702                  return el.tag
     703
     704          f = BytesIO('<?pia a?><a><?pib b?><b><?pic c?><c/></b><?pid d?></a><?pie e?>')
     705          events = list(iterparse(f, events=('end', 'pi')))
     706          root = events[-2][1]
     707          self.assertEqual(8, len(events))
     708          self.assertEqual([('pia','a'), ('pib','b'), ('pic','c'), 'c', 'b',
     709                             ('pid','d'), 'a', ('pie','e')],
     710                            [ name(*item) for item in events ])
     711          self.assertEqual(
     712              _bytes('<?pia a?><a><?pib b?><b><?pic c?><c/></b><?pid d?></a><?pie e?>'),
     713              tostring(ElementTree(root)))
     714
     715 -    def test_iterparse_remove_comments(self):
     716          iterparse = self.etree.iterparse
     717          tostring = self.etree.tostring
     718
     719          f = BytesIO('<a><!--A--><b><!-- B --><c/></b><!--C--></a>')
     720          events = list(iterparse(f, remove_comments=True,
     721                                  events=('end', 'comment')))
     722          root = events[-1][1]
     723          self.assertEqual(3, len(events))
     724          self.assertEqual(['c', 'b', 'a'],
     725                            [ el.tag for (event, el) in events ])
     726          self.assertEqual(
     727              _bytes('<a><b><c/></b></a>'),
     728              tostring(root))
     729
     730 -    def test_iterparse_broken(self):
     731          iterparse = self.etree.iterparse
     732          f = BytesIO('<a><b><c/></a>')
     733          # ET raises ExpatError, lxml raises XMLSyntaxError
     734          self.assertRaises(self.etree.XMLSyntaxError, list, iterparse(f))
     735
     736 -    def test_iterparse_broken_recover(self):
     737          iterparse = self.etree.iterparse
     738          f = BytesIO('<a><b><c/></a>')
     739          it = iterparse(f, events=('start', 'end'), recover=True)
     740          events = [(ev, el.tag) for ev, el in it]
     741          root = it.root
     742          self.assertTrue(root is not None)
     743
     744          self.assertEqual(1, events.count(('start', 'a')))
     745          self.assertEqual(1, events.count(('end', 'a')))
     746
     747          self.assertEqual(1, events.count(('start', 'b')))
     748          self.assertEqual(1, events.count(('end', 'b')))
     749
     750          self.assertEqual(1, events.count(('start', 'c')))
     751          self.assertEqual(1, events.count(('end', 'c')))
     752
     753 -    def test_iterparse_broken_multi_recover(self):
     754          iterparse = self.etree.iterparse
     755          f = BytesIO('<a><b><c/></d><b><c/></a></b>')
     756          it = iterparse(f, events=('start', 'end'), recover=True)
     757          events = [(ev, el.tag) for ev, el in it]
     758          root = it.root
     759          self.assertTrue(root is not None)
     760
     761          self.assertEqual(1, events.count(('start', 'a')))
     762          self.assertEqual(1, events.count(('end', 'a')))
     763
     764          self.assertEqual(2, events.count(('start', 'b')))
     765          self.assertEqual(2, events.count(('end', 'b')))
     766
     767          self.assertEqual(2, events.count(('start', 'c')))
     768          self.assertEqual(2, events.count(('end', 'c')))
     769
     770 -    def test_iterparse_strip(self):
     771          iterparse = self.etree.iterparse
     772          f = BytesIO("""
     773                 <a>  \n \n  <b> b test </b>  \n
     774
     775                 \n\t <c> \n </c> </a>  \n """)
     776          iterator = iterparse(f, remove_blank_text=True)
     777          text = [ (element.text, element.tail)
     778                   for event, element in iterator ]
     779          self.assertEqual(
     780              [(" b test ", None), (" \n ", None), (None, None)],
     781              text)
     782
     783 -    def test_iterparse_tag(self):
     784          iterparse = self.etree.iterparse
     785          f = BytesIO('<a><b><d/></b><c/></a>')
     786
     787          iterator = iterparse(f, tag="b", events=('start', 'end'))
     788          events = list(iterator)
     789          root = iterator.root
     790          self.assertEqual(
     791              [('start', root[0]), ('end', root[0])],
     792              events)
     793
     794 -    def test_iterparse_tag_all(self):
     795          iterparse = self.etree.iterparse
     796          f = BytesIO('<a><b><d/></b><c/></a>')
     797
     798          iterator = iterparse(f, tag="*", events=('start', 'end'))
     799          events = list(iterator)
     800          self.assertEqual(
     801              8,
     802              len(events))
     803
     804 -    def test_iterparse_tag_ns(self):
     805          iterparse = self.etree.iterparse
     806          f = BytesIO('<a xmlns="urn:test:1"><b><d/></b><c/></a>')
     807
     808          iterator = iterparse(f, tag="{urn:test:1}b", events=('start', 'end'))
     809          events = list(iterator)
     810          root = iterator.root
     811          self.assertEqual(
     812              [('start', root[0]), ('end', root[0])],
     813              events)
     814
     815 -    def test_iterparse_tag_ns_empty(self):
     816          iterparse = self.etree.iterparse
     817          f = BytesIO('<a><b><d/></b><c/></a>')
     818          iterator = iterparse(f, tag="{}b", events=('start', 'end'))
     819          events = list(iterator)
     820          root = iterator.root
     821          self.assertEqual(
     822              [('start', root[0]), ('end', root[0])],
     823              events)
     824
     825          f = BytesIO('<a xmlns="urn:test:1"><b><d/></b><c/></a>')
     826          iterator = iterparse(f, tag="{}b", events=('start', 'end'))
     827          events = list(iterator)
     828          root = iterator.root
     829          self.assertEqual([], events)
     830
     831 -    def test_iterparse_tag_ns_all(self):
     832          iterparse = self.etree.iterparse
     833          f = BytesIO('<a xmlns="urn:test:1"><b><d/></b><c/></a>')
     834          iterator = iterparse(f, tag="{urn:test:1}*", events=('start', 'end'))
     835          events = list(iterator)
     836          self.assertEqual(8, len(events))
     837
     838 -    def test_iterparse_tag_ns_empty_all(self):
     839          iterparse = self.etree.iterparse
     840          f = BytesIO('<a xmlns="urn:test:1"><b><d/></b><c/></a>')
     841          iterator = iterparse(f, tag="{}*", events=('start', 'end'))
     842          events = list(iterator)
     843          self.assertEqual([], events)
     844
     845          f = BytesIO('<a><b><d/></b><c/></a>')
     846          iterator = iterparse(f, tag="{}*", events=('start', 'end'))
     847          events = list(iterator)
     848          self.assertEqual(8, len(events))
     849
     850 -    def test_iterparse_encoding_error(self):
     851          text = _str('Søk på nettet')
     852          wrong_declaration = "<?xml version='1.0' encoding='UTF-8'?>"
     853          xml_latin1 = (_str('%s<a>%s</a>') % (wrong_declaration, text)
     854                        ).encode('iso-8859-1')
     855
     856          self.assertRaises(self.etree.ParseError,
     857                            list, self.etree.iterparse(BytesIO(xml_latin1)))
     858
     859 -    def test_iterparse_encoding_8bit_override(self):
     860          text = _str('Søk på nettet', encoding="UTF-8")
     861          wrong_declaration = "<?xml version='1.0' encoding='UTF-8'?>"
     862          xml_latin1 = (_str('%s<a>%s</a>') % (wrong_declaration, text)
     863                        ).encode('iso-8859-1')
     864
     865          iterator = self.etree.iterparse(BytesIO(xml_latin1),
     866                                          encoding="iso-8859-1")
     867          self.assertEqual(1, len(list(iterator)))
     868
     869          a = iterator.root
     870          self.assertEqual(a.text, text)
     871
     872 -    def test_iterparse_keep_cdata(self):
     873          tostring = self.etree.tostring
     874          f = BytesIO('<root><![CDATA[test]]></root>')
     875          context = self.etree.iterparse(f, strip_cdata=False)
     876          content = [ el.text for event,el in context ]
     877
     878          self.assertEqual(['test'], content)
     879          self.assertEqual(_bytes('<root><![CDATA[test]]></root>'),
     880                            tostring(context.root))
     881
     882 -    def test_parser_encoding_unknown(self):
     883          self.assertRaises(
     884              LookupError, self.etree.XMLParser, encoding="hopefully unknown")
     885
     886 -    def test_parser_encoding(self):
     887          self.etree.XMLParser(encoding="ascii")
     888          self.etree.XMLParser(encoding="utf-8")
     889          self.etree.XMLParser(encoding="iso-8859-1")
     890
     891 -    def test_feed_parser_recover(self):
     892          parser = self.etree.XMLParser(recover=True)
     893
     894          parser.feed('<?xml version=')
     895          parser.feed('"1.0"?><ro')
     896          parser.feed('ot><')
     897          parser.feed('a test="works"')
     898          parser.feed('><othertag/></root') # <a> not closed!
     899          parser.feed('>')
     900
     901          root = parser.close()
     902
     903          self.assertEqual(root.tag, "root")
     904          self.assertEqual(len(root), 1)
     905          self.assertEqual(root[0].tag, "a")
     906          self.assertEqual(root[0].get("test"), "works")
     907          self.assertEqual(len(root[0]), 1)
     908          self.assertEqual(root[0][0].tag, "othertag")
     909          # FIXME: would be nice to get some errors logged ...
     910          #self.assertTrue(len(parser.error_log) > 0, "error log is empty")
     911
     912 -    def test_feed_parser_recover_no_id_dict(self):
     913          # test that recover mode plays nicely with the no-id-dict setup
     914          parser = self.etree.XMLParser(recover=True, collect_ids=False)
     915
     916          parser.feed('<?xml version=')
     917          parser.feed('"1.0"?><ro')
     918          parser.feed('ot xml:id="123"><')
     919          parser.feed('a test="works" xml:id=')
     920          parser.feed('"321"><othertag/></root') # <a> not closed!
     921          parser.feed('>')
     922
     923          root = parser.close()
     924
     925          self.assertEqual(root.tag, "root")
     926          self.assertEqual(len(root), 1)
     927          self.assertEqual(root[0].tag, "a")
     928          self.assertEqual(root[0].get("test"), "works")
     929          self.assertEqual(root[0].attrib, {
     930              'test': 'works',
     931              '{http://www.w3.org/XML/1998/namespace}id': '321'})
     932          self.assertEqual(len(root[0]), 1)
     933          self.assertEqual(root[0][0].tag, "othertag")
     934          # FIXME: would be nice to get some errors logged ...
     935          #self.assertTrue(len(parser.error_log) > 0, "error log is empty")
     936
     937 -    def test_elementtree_parser_target_type_error(self):
     938          assertEqual = self.assertEqual
     939          assertFalse  = self.assertFalse
     940
     941          events = []
     942          class Target(object):
     943              def start(self, tag, attrib):
     944                  events.append("start")
     945                  assertFalse(attrib)
     946                  assertEqual("TAG", tag)
     947              def end(self, tag):
     948                  events.append("end")
     949                  assertEqual("TAG", tag)
     950              def close(self):
     951                  return "DONE" # no Element!
     952
     953          parser = self.etree.XMLParser(target=Target())
     954          tree = self.etree.ElementTree()
     955
     956          self.assertRaises(TypeError,
     957                            tree.parse, BytesIO("<TAG/>"), parser=parser)
     958          self.assertEqual(["start", "end"], events)
     959
     960 -    def test_parser_target_feed_exception(self):
     961          # ET doesn't call .close() on errors
     962          events = []
     963          class Target(object):
     964              def start(self, tag, attrib):
     965                  events.append("start-" + tag)
     966              def end(self, tag):
     967                  events.append("end-" + tag)
     968                  if tag == 'a':
     969                      raise ValueError("dead and gone")
     970              def data(self, data):
     971                  events.append("data-" + data)
     972              def close(self):
     973                  events.append("close")
     974                  return "DONE"
     975
     976          parser = self.etree.XMLParser(target=Target())
     977
     978          try:
     979              parser.feed(_bytes('<root>A<a>ca</a>B</root>'))
     980              done = parser.close()
     981              self.fail("error expected, but parsing succeeded")
     982          except ValueError:
     983              done = 'value error received as expected'
     984
     985          self.assertEqual(["start-root", "data-A", "start-a",
     986                             "data-ca", "end-a", "close"],
     987                            events)
     988
     989 -    def test_parser_target_fromstring_exception(self):
     990          # ET doesn't call .close() on errors
     991          events = []
     992          class Target(object):
     993              def start(self, tag, attrib):
     994                  events.append("start-" + tag)
     995              def end(self, tag):
     996                  events.append("end-" + tag)
     997                  if tag == 'a':
     998                      raise ValueError("dead and gone")
     999              def data(self, data):
    1000                  events.append("data-" + data)
    1001              def close(self):
    1002                  events.append("close")
    1003                  return "DONE"
    1004
    1005          parser = self.etree.XMLParser(target=Target())
    1006
    1007          try:
    1008              done = self.etree.fromstring(_bytes('<root>A<a>ca</a>B</root>'),
    1009                                           parser=parser)
    1010              self.fail("error expected, but parsing succeeded")
    1011          except ValueError:
    1012              done = 'value error received as expected'
    1013
    1014          self.assertEqual(["start-root", "data-A", "start-a",
    1015                            "data-ca", "end-a", "close"],
    1016                           events)
    1017
    1018 -    def test_parser_target_feed_no_id_dict(self):
    1019          # test that target parsing works nicely with the no-id-hash setup
    1020          events = []
    1021          class Target(object):
    1022              def start(self, tag, attrib):
    1023                  events.append("start-" + tag)
    1024              def end(self, tag):
    1025                  events.append("end-" + tag)
    1026              def data(self, data):
    1027                  events.append("data-" + data)
    1028              def comment(self, text):
    1029                  events.append("comment-" + text)
    1030              def close(self):
    1031                  return "DONE"
    1032
    1033          parser = self.etree.XMLParser(target=Target(), collect_ids=False)
    1034
    1035          parser.feed(_bytes('<!--a--><root xml:id="123">A<!--b-->'))
    1036          parser.feed(_bytes('<sub xml:id="321"/>B</root>'))
    1037          done = parser.close()
    1038
    1039          self.assertEqual("DONE", done)
    1040          self.assertEqual(["comment-a", "start-root", "data-A", "comment-b",
    1041                            "start-sub", "end-sub", "data-B", "end-root"],
    1042                           events)
    1043
    1044 -    def test_parser_target_comment(self):
    1045          events = []
    1046          class Target(object):
    1047              def start(self, tag, attrib):
    1048                  events.append("start-" + tag)
    1049              def end(self, tag):
    1050                  events.append("end-" + tag)
    1051              def data(self, data):
    1052                  events.append("data-" + data)
    1053              def comment(self, text):
    1054                  events.append("comment-" + text)
    1055              def close(self):
    1056                  return "DONE"
    1057
    1058          parser = self.etree.XMLParser(target=Target())
    1059
    1060          parser.feed(_bytes('<!--a--><root>A<!--b--><sub/><!--c-->B</root><!--d-->'))
    1061          done = parser.close()
    1062
    1063          self.assertEqual("DONE", done)
    1064          self.assertEqual(["comment-a", "start-root", "data-A", "comment-b",
    1065                             "start-sub", "end-sub", "comment-c", "data-B",
    1066                             "end-root", "comment-d"],
    1067                            events)
    1068
    1069 -    def test_parser_target_pi(self):
    1070          events = []
    1071          class Target(object):
    1072              def start(self, tag, attrib):
    1073                  events.append("start-" + tag)
    1074              def end(self, tag):
    1075                  events.append("end-" + tag)
    1076              def data(self, data):
    1077                  events.append("data-" + data)
    1078              def pi(self, target, data):
    1079                  events.append("pi-" + target + "-" + data)
    1080              def close(self):
    1081                  return "DONE"
    1082
    1083          parser = self.etree.XMLParser(target=Target())
    1084
    1085          parser.feed(_bytes('<?test a?><root>A<?test b?>B</root><?test c?>'))
    1086          done = parser.close()
    1087
    1088          self.assertEqual("DONE", done)
    1089          self.assertEqual(["pi-test-a", "start-root", "data-A", "pi-test-b",
    1090                             "data-B", "end-root", "pi-test-c"],
    1091                            events)
    1092
    1093 -    def test_parser_target_cdata(self):
    1094          events = []
    1095          class Target(object):
    1096              def start(self, tag, attrib):
    1097                  events.append("start-" + tag)
    1098              def end(self, tag):
    1099                  events.append("end-" + tag)
    1100              def data(self, data):
    1101                  events.append("data-" + data)
    1102              def close(self):
    1103                  return "DONE"
    1104
    1105          parser = self.etree.XMLParser(target=Target(),
    1106                                        strip_cdata=False)
    1107
    1108          parser.feed(_bytes('<root>A<a><![CDATA[ca]]></a>B</root>'))
    1109          done = parser.close()
    1110
    1111          self.assertEqual("DONE", done)
    1112          self.assertEqual(["start-root", "data-A", "start-a",
    1113                             "data-ca", "end-a", "data-B", "end-root"],
    1114                            events)
    1115
    1116 -    def test_parser_target_recover(self):
    1117          events = []
    1118          class Target(object):
    1119              def start(self, tag, attrib):
    1120                  events.append("start-" + tag)
    1121              def end(self, tag):
    1122                  events.append("end-" + tag)
    1123              def data(self, data):
    1124                  events.append("data-" + data)
    1125              def close(self):
    1126                  events.append("close")
    1127                  return "DONE"
    1128
    1129          parser = self.etree.XMLParser(target=Target(),
    1130                                        recover=True)
    1131
    1132          parser.feed(_bytes('<root>A<a>ca</a>B</not-root>'))
    1133          done = parser.close()
    1134
    1135          self.assertEqual("DONE", done)
    1136          self.assertEqual(["start-root", "data-A", "start-a",
    1137                             "data-ca", "end-a", "data-B",
    1138                             "end-root", "close"],
    1139                            events)
    1140
    1141 -    def test_iterwalk_tag(self):
    1142          iterwalk = self.etree.iterwalk
    1143          root = self.etree.XML(_bytes('<a><b><d/></b><c/></a>'))
    1144
    1145          iterator = iterwalk(root, tag="b", events=('start', 'end'))
    1146          events = list(iterator)
    1147          self.assertEqual(
    1148              [('start', root[0]), ('end', root[0])],
    1149              events)
    1150
    1151 -    def test_iterwalk_tag_all(self):
    1152          iterwalk = self.etree.iterwalk
    1153          root = self.etree.XML(_bytes('<a><b><d/></b><c/></a>'))
    1154
    1155          iterator = iterwalk(root, tag="*", events=('start', 'end'))
    1156          events = list(iterator)
    1157          self.assertEqual(
    1158              8,
    1159              len(events))
    1160
    1161 -    def test_iterwalk(self):
    1162          iterwalk = self.etree.iterwalk
    1163          root = self.etree.XML(_bytes('<a><b></b><c/></a>'))
    1164
    1165          events = list(iterwalk(root))
    1166          self.assertEqual(
    1167              [('end', root[0]), ('end', root[1]), ('end', root)],
    1168              events)
    1169
    1170 -    def test_iterwalk_start(self):
    1171          iterwalk = self.etree.iterwalk
    1172          root = self.etree.XML(_bytes('<a><b></b><c/></a>'))
    1173
    1174          iterator = iterwalk(root, events=('start',))
    1175          events = list(iterator)
    1176          self.assertEqual(
    1177              [('start', root), ('start', root[0]), ('start', root[1])],
    1178              events)
    1179
    1180 -    def test_iterwalk_start_end(self):
    1181          iterwalk = self.etree.iterwalk
    1182          root = self.etree.XML(_bytes('<a><b></b><c/></a>'))
    1183
    1184          iterator = iterwalk(root, events=('start','end'))
    1185          events = list(iterator)
    1186          self.assertEqual(
    1187              [('start', root), ('start', root[0]), ('end', root[0]),
    1188               ('start', root[1]), ('end', root[1]), ('end', root)],
    1189              events)
    1190
    1191 -    def test_iterwalk_start_tags(self):
    1192          iterwalk = self.etree.iterwalk
    1193          root = self.etree.XML(_bytes('<a><b></b><c/><b><d/></b></a>'))
    1194
    1195          iterator = iterwalk(root, events=('start',), tag='b')
    1196          events = list(iterator)
    1197          self.assertEqual(
    1198              [('start', root[0]), ('start', root[2])],
    1199              events)
    1200
    1201 -    def test_iterwalk_start_end_tags(self):
    1202          iterwalk = self.etree.iterwalk
    1203          root = self.etree.XML(_bytes('<a><b></b><c/><b><d/></b></a>'))
    1204
    1205          iterator = iterwalk(root, events=('start', 'end'), tag='b')
    1206          events = list(iterator)
    1207          self.assertEqual(
    1208              [('start', root[0]), ('end', root[0]), ('start', root[2]), ('end', root[2])],
    1209              events)
    1210
    1211 -    def test_iterwalk_start_end_tags_with_root(self):
    1212          iterwalk = self.etree.iterwalk
    1213          root = self.etree.XML(_bytes('<a><b></b><c/><b><d/></b></a>'))
    1214
    1215          iterator = iterwalk(root, events=('start', 'end'), tag=('b', 'a'))
    1216          events = list(iterator)
    1217          self.assertEqual(
    1218              [('start', root),
    1219               ('start', root[0]), ('end', root[0]),
    1220               ('start', root[2]), ('end', root[2]),
    1221               ('end', root),
    1222               ],
    1223              events)
    1224
    1225 -    def test_iterwalk_clear(self):
    1226          iterwalk = self.etree.iterwalk
    1227          root = self.etree.XML(_bytes('<a><b></b><c/></a>'))
    1228
    1229          iterator = iterwalk(root)
    1230          for event, elem in iterator:
    1231              elem.clear()
    1232
    1233          self.assertEqual(0,
    1234                            len(root))
    1235
    1236 -    def test_iterwalk_attrib_ns(self):
    1237          iterwalk = self.etree.iterwalk
    1238          root = self.etree.XML(_bytes('<a xmlns="ns1"><b><c xmlns="ns2"/></b></a>'))
    1239
    1240          attr_name = '{testns}bla'
    1241          events = []
    1242          iterator = iterwalk(root, events=('start','end','start-ns','end-ns'))
    1243          for event, elem in iterator:
    1244              events.append(event)
    1245              if event == 'start':
    1246                  if elem.tag != '{ns1}a':
    1247                      elem.set(attr_name, 'value')
    1248
    1249          self.assertEqual(
    1250              ['start-ns', 'start', 'start', 'start-ns', 'start',
    1251               'end', 'end-ns', 'end', 'end', 'end-ns'],
    1252              events)
    1253
    1254          self.assertEqual(
    1255              None,
    1256              root.get(attr_name))
    1257          self.assertEqual(
    1258              'value',
    1259              root[0].get(attr_name))
    1260
    1261 -    def test_iterwalk_end_skip(self):
    1262          iterwalk = self.etree.iterwalk
    1263          root = self.etree.XML(_bytes('<a><b><c/></b><d><e/></d></a>'))
    1264
    1265          iterator = iterwalk(root)
    1266          tags = []
    1267          for event, elem in iterator:
    1268              tags.append(elem.tag)
    1269              # requesting a skip after an 'end' event should never have an effect
    1270              iterator.skip_subtree()
    1271
    1272          self.assertEqual(['c', 'b', 'e', 'd', 'a'], tags)
    1273
    1274 -    def test_iterwalk_start_end_skip(self):
    1275          iterwalk = self.etree.iterwalk
    1276          root = self.etree.XML(_bytes('<a><b><c/></b><d><e/></d></a>'))
    1277
    1278          iterator = iterwalk(root, events=('start', 'end'))
    1279          tags = []
    1280          for event, elem in iterator:
    1281              tags.append((event, elem.tag))
    1282              if elem.tag in ('b', 'e'):
    1283                  # skipping should only have an effect on 'start', not on 'end'
    1284                  iterator.skip_subtree()
    1285
    1286          self.assertEqual(
    1287              [('start', 'a'),
    1288               ('start', 'b'), ('end', 'b'),  # ignored child 'c'
    1289               ('start', 'd'),
    1290               ('start', 'e'), ('end', 'e'),
    1291               ('end', 'd'),
    1292               ('end', 'a')],
    1293              tags)
    1294
    1295 -    def test_iterwalk_ns_skip(self):
    1296          iterwalk = self.etree.iterwalk
    1297          root = self.etree.XML(_bytes(
    1298              '<a xmlns="ns1"><b xmlns="nsb"><c xmlns="ns2"/></b><d xmlns="ns2"><e/></d></a>'))
    1299
    1300          events = []
    1301          iterator = iterwalk(root, events=('start','start-ns','end-ns'))
    1302          for event, elem in iterator:
    1303              if event in ('start-ns', 'end-ns'):
    1304                  events.append((event, elem))
    1305                  if event == 'start-ns' and elem == ('', 'nsb'):
    1306                      events.append('skip')
    1307                      iterator.skip_subtree()
    1308              else:
    1309                  events.append((event, elem.tag))
    1310
    1311          self.assertEqual(
    1312              [('start-ns', ('', 'ns1')),
    1313               ('start', '{ns1}a'),
    1314               ('start-ns', ('', 'nsb')),
    1315               'skip',
    1316               ('start', '{nsb}b'),
    1317               ('end-ns', None),
    1318               ('start-ns', ('', 'ns2')),
    1319               ('start', '{ns2}d'),
    1320               ('start', '{ns2}e'),
    1321               ('end-ns', None),
    1322               ('end-ns', None)
    1323               ],
    1324              events)
    1325
    1326 -    def test_iterwalk_getiterator(self):
    1327          iterwalk = self.etree.iterwalk
    1328          root = self.etree.XML(_bytes('<a><b><d/></b><c/></a>'))
    1329
    1330          counts = []
    1331          for event, elem in iterwalk(root):
    1332              counts.append(len(list(elem.getiterator())))
    1333          self.assertEqual(
    1334              [1,2,1,4],
    1335              counts)
    1336
    1337 -    def test_resolve_string_dtd(self):
    1338          parse = self.etree.parse
    1339          parser = self.etree.XMLParser(dtd_validation=True)
    1340          assertEqual = self.assertEqual
    1341          test_url = _str("__nosuch.dtd")
    1342
    1343          class MyResolver(self.etree.Resolver):
    1344              def resolve(self, url, id, context):
    1345                  assertEqual(url, test_url)
    1346                  return self.resolve_string(
    1347                      _str('''<!ENTITY myentity "%s">
    1348                          <!ELEMENT doc ANY>''') % url, context)
    1349
    1350          parser.resolvers.add(MyResolver())
    1351
    1352          xml = _str('<!DOCTYPE doc SYSTEM "%s"><doc>&myentity;</doc>') % test_url
    1353          tree = parse(StringIO(xml), parser)
    1354          root = tree.getroot()
    1355          self.assertEqual(root.text, test_url)
    1356
    1357 -    def test_resolve_bytes_dtd(self):
    1358          parse = self.etree.parse
    1359          parser = self.etree.XMLParser(dtd_validation=True)
    1360          assertEqual = self.assertEqual
    1361          test_url = _str("__nosuch.dtd")
    1362
    1363          class MyResolver(self.etree.Resolver):
    1364              def resolve(self, url, id, context):
    1365                  assertEqual(url, test_url)
    1366                  return self.resolve_string(
    1367                      (_str('''<!ENTITY myentity "%s">
    1368                               <!ELEMENT doc ANY>''') % url).encode('utf-8'),
    1369                      context)
    1370
    1371          parser.resolvers.add(MyResolver())
    1372
    1373          xml = _str('<!DOCTYPE doc SYSTEM "%s"><doc>&myentity;</doc>') % test_url
    1374          tree = parse(StringIO(xml), parser)
    1375          root = tree.getroot()
    1376          self.assertEqual(root.text, test_url)
    1377
    1378 -    def test_resolve_filelike_dtd(self):
    1379          parse = self.etree.parse
    1380          parser = self.etree.XMLParser(dtd_validation=True)
    1381          assertEqual = self.assertEqual
    1382          test_url = _str("__nosuch.dtd")
    1383
    1384          class MyResolver(self.etree.Resolver):
    1385              def resolve(self, url, id, context):
    1386                  assertEqual(url, test_url)
    1387                  return self.resolve_file(
    1388                      SillyFileLike(
    1389                          _str('''<!ENTITY myentity "%s">
    1390                          <!ELEMENT doc ANY>''') % url), context)
    1391
    1392          parser.resolvers.add(MyResolver())
    1393
    1394          xml = _str('<!DOCTYPE doc SYSTEM "%s"><doc>&myentity;</doc>') % test_url
    1395          tree = parse(StringIO(xml), parser)
    1396          root = tree.getroot()
    1397          self.assertEqual(root.text, test_url)
    1398
    1399 -    def test_resolve_filename_dtd(self):
    1400          parse = self.etree.parse
    1401          parser = self.etree.XMLParser(attribute_defaults=True)
    1402          assertEqual = self.assertEqual
    1403          test_url = _str("__nosuch.dtd")
    1404
    1405          class MyResolver(self.etree.Resolver):
    1406              def resolve(self, url, id, context):
    1407                  assertEqual(url, test_url)
    1408                  return self.resolve_filename(
    1409                      fileInTestDir('test.dtd'), context)
    1410
    1411          parser.resolvers.add(MyResolver())
    1412
    1413          xml = _str('<!DOCTYPE a SYSTEM "%s"><a><b/></a>') % test_url
    1414          tree = parse(StringIO(xml), parser)
    1415          root = tree.getroot()
    1416          self.assertEqual(
    1417              root.attrib,    {'default': 'valueA'})
    1418          self.assertEqual(
    1419              root[0].attrib, {'default': 'valueB'})
    1420
    1421 -    def test_resolve_filename_dtd_relative(self):
    1422          parse = self.etree.parse
    1423          parser = self.etree.XMLParser(attribute_defaults=True)
    1424          assertEqual = self.assertEqual
    1425          test_url = _str("__nosuch.dtd")
    1426
    1427          class MyResolver(self.etree.Resolver):
    1428              def resolve(self, url, id, context):
    1429                  expected = fileUrlInTestDir(test_url)
    1430                  url = url.replace('file://', 'file:')  # depends on libxml2 version
    1431                  expected = expected.replace('file://', 'file:')
    1432                  assertEqual(url, expected)
    1433                  return self.resolve_filename(
    1434                      fileUrlInTestDir('test.dtd'), context)
    1435
    1436          parser.resolvers.add(MyResolver())
    1437
    1438          xml = _str('<!DOCTYPE a SYSTEM "%s"><a><b/></a>') % test_url
    1439          tree = parse(StringIO(xml), parser,
    1440                       base_url=fileUrlInTestDir('__test.xml'))
    1441          root = tree.getroot()
    1442          self.assertEqual(
    1443              root.attrib,    {'default': 'valueA'})
    1444          self.assertEqual(
    1445              root[0].attrib, {'default': 'valueB'})
    1446
    1447 -    def test_resolve_file_dtd(self):
    1448          parse = self.etree.parse
    1449          parser = self.etree.XMLParser(attribute_defaults=True)
    1450          assertEqual = self.assertEqual
    1451          test_url = _str("__nosuch.dtd")
    1452
    1453          class MyResolver(self.etree.Resolver):
    1454              def resolve(self, url, id, context):
    1455                  assertEqual(url, test_url)
    1456                  return self.resolve_file(
    1457                      open(fileInTestDir('test.dtd'), 'rb'), context)
    1458
    1459          parser.resolvers.add(MyResolver())
    1460
    1461          xml = _str('<!DOCTYPE a SYSTEM "%s"><a><b/></a>') % test_url
    1462          tree = parse(StringIO(xml), parser)
    1463          root = tree.getroot()
    1464          self.assertEqual(
    1465              root.attrib,    {'default': 'valueA'})
    1466          self.assertEqual(
    1467              root[0].attrib, {'default': 'valueB'})
    1468
    1469 -    def test_resolve_empty(self):
    1470          parse = self.etree.parse
    1471          parser = self.etree.XMLParser(load_dtd=True)
    1472          assertEqual = self.assertEqual
    1473          test_url = _str("__nosuch.dtd")
    1474
    1475          class check(object):
    1476              resolved = False
    1477
    1478          class MyResolver(self.etree.Resolver):
    1479              def resolve(self, url, id, context):
    1480                  assertEqual(url, test_url)
    1481                  check.resolved = True
    1482                  return self.resolve_empty(context)
    1483
    1484          parser.resolvers.add(MyResolver())
    1485
    1486          xml = _str('<!DOCTYPE doc SYSTEM "%s"><doc>&myentity;</doc>') % test_url
    1487          self.assertRaises(etree.XMLSyntaxError, parse, StringIO(xml), parser)
    1488          self.assertTrue(check.resolved)
    1489
    1490 -    def test_resolve_error(self):
    1491          parse = self.etree.parse
    1492          parser = self.etree.XMLParser(dtd_validation=True)
    1493
    1494          class _LocalException(Exception):
    1495              pass
    1496
    1497          class MyResolver(self.etree.Resolver):
    1498              def resolve(self, url, id, context):
    1499                  raise _LocalException
    1500
    1501          parser.resolvers.add(MyResolver())
    1502
    1503          xml = '<!DOCTYPE doc SYSTEM "test"><doc>&myentity;</doc>'
    1504          self.assertRaises(_LocalException, parse, BytesIO(xml), parser)
    1505
    1506      if etree.LIBXML_VERSION > (2,6,20):
    1507 -        def test_entity_parse(self):
    1508              parse = self.etree.parse
    1509              tostring = self.etree.tostring
    1510              parser = self.etree.XMLParser(resolve_entities=False)
    1511              Entity = self.etree.Entity
    1512
    1513              xml = _bytes('<!DOCTYPE doc SYSTEM "test"><doc>&myentity;</doc>')
    1514              tree = parse(BytesIO(xml), parser)
    1515              root = tree.getroot()
    1516              self.assertEqual(root[0].tag, Entity)
    1517              self.assertEqual(root[0].text, "&myentity;")
    1518              self.assertEqual(root[0].tail, None)
    1519              self.assertEqual(root[0].name, "myentity")
    1520
    1521              self.assertEqual(_bytes('<doc>&myentity;</doc>'),
    1522                                tostring(root))
    1523
    1524 -        def test_entity_restructure(self):
    1525              xml = _bytes('''<!DOCTYPE root [ <!ENTITY nbsp "&#160;"> ]>
    1526                  <root>
    1527                    <child1/>
    1528                    <child2/>
    1529                    <child3>&nbsp;</child3>
    1530                  </root>''')
    1531
    1532              parser = self.etree.XMLParser(resolve_entities=False)
    1533              root = etree.fromstring(xml, parser)
    1534              self.assertEqual([ el.tag for el in root ],
    1535                                ['child1', 'child2', 'child3'])
    1536
    1537              root[0] = root[-1]
    1538              self.assertEqual([ el.tag for el in root ],
    1539                                ['child3', 'child2'])
    1540              self.assertEqual(root[0][0].text, '&nbsp;')
    1541              self.assertEqual(root[0][0].name, 'nbsp')
    1542
    1543 -    def test_entity_append(self):
    1544          Entity = self.etree.Entity
    1545          Element = self.etree.Element
    1546          tostring = self.etree.tostring
    1547
    1548          root = Element("root")
    1549          root.append( Entity("test") )
    1550
    1551          self.assertEqual(root[0].tag, Entity)
    1552          self.assertEqual(root[0].text, "&test;")
    1553          self.assertEqual(root[0].tail, None)
    1554          self.assertEqual(root[0].name, "test")
    1555
    1556          self.assertEqual(_bytes('<root>&test;</root>'),
    1557                            tostring(root))
    1558
    1559 -    def test_entity_values(self):
    1560          Entity = self.etree.Entity
    1561          self.assertEqual(Entity("test").text, '&test;')
    1562          self.assertEqual(Entity("#17683").text, '&#17683;')
    1563          self.assertEqual(Entity("#x1768").text, '&#x1768;')
    1564          self.assertEqual(Entity("#x98AF").text, '&#x98AF;')
    1565
    1566 -    def test_entity_error(self):
    1567          Entity = self.etree.Entity
    1568          self.assertRaises(ValueError, Entity, 'a b c')
    1569          self.assertRaises(ValueError, Entity, 'a,b')
    1570          self.assertRaises(ValueError, Entity, 'a\0b')
    1571          self.assertRaises(ValueError, Entity, '#abc')
    1572          self.assertRaises(ValueError, Entity, '#xxyz')
    1573
    1574 -    def test_cdata(self):
    1575          CDATA = self.etree.CDATA
    1576          Element = self.etree.Element
    1577          tostring = self.etree.tostring
    1578
    1579          root = Element("root")
    1580          root.text = CDATA('test')
    1581
    1582          self.assertEqual('test',
    1583                            root.text)
    1584          self.assertEqual(_bytes('<root><![CDATA[test]]></root>'),
    1585                            tostring(root))
    1586
    1587 -    def test_cdata_tail(self):
    1588          CDATA = self.etree.CDATA
    1589          Element = self.etree.Element
    1590          SubElement = self.etree.SubElement
    1591          tostring = self.etree.tostring
    1592
    1593          root = Element("root")
    1594          child = SubElement(root, 'child')
    1595          child.tail = CDATA('test')
    1596
    1597          self.assertEqual('test', child.tail)
    1598          self.assertEqual(_bytes('<root><child/><![CDATA[test]]></root>'),
    1599                           tostring(root))
    1600
    1601          root = Element("root")
    1602          root.tail = CDATA('test')
    1603
    1604          self.assertEqual('test', root.tail)
    1605          self.assertEqual(_bytes('<root/><![CDATA[test]]>'),
    1606                           tostring(root))
    1607
    1608 -    def test_cdata_type(self):
    1609          CDATA = self.etree.CDATA
    1610          Element = self.etree.Element
    1611          root = Element("root")
    1612
    1613          root.text = CDATA("test")
    1614          self.assertEqual('test', root.text)
    1615
    1616          root.text = CDATA(_str("test"))
    1617          self.assertEqual('test', root.text)
    1618
    1619          self.assertRaises(TypeError, CDATA, 1)
    1620
    1621 -    def test_cdata_errors(self):
    1622          CDATA = self.etree.CDATA
    1623          Element = self.etree.Element
    1624
    1625          root = Element("root")
    1626          cdata = CDATA('test')
    1627
    1628          self.assertRaises(TypeError,
    1629                            root.set, 'attr', cdata)
    1630          self.assertRaises(TypeError,
    1631                            operator.setitem, root.attrib, 'attr', cdata)
    1632
    1633 -    def test_cdata_parser(self):
    1634          tostring = self.etree.tostring
    1635          parser = self.etree.XMLParser(strip_cdata=False)
    1636          root = self.etree.XML(_bytes('<root><![CDATA[test]]></root>'), parser)
    1637
    1638          self.assertEqual('test', root.text)
    1639          self.assertEqual(_bytes('<root><![CDATA[test]]></root>'),
    1640                            tostring(root))
    1641
    1642 -    def test_cdata_xpath(self):
    1643          tostring = self.etree.tostring
    1644          parser = self.etree.XMLParser(strip_cdata=False)
    1645          root = self.etree.XML(_bytes('<root><![CDATA[test]]></root>'), parser)
    1646          self.assertEqual(_bytes('<root><![CDATA[test]]></root>'),
    1647                            tostring(root))
    1648
    1649          self.assertEqual(['test'], root.xpath('//text()'))
    1650
    1651      # TypeError in etree, AssertionError in ElementTree;
    1652 -    def test_setitem_assert(self):
    1653          Element = self.etree.Element
    1654          SubElement = self.etree.SubElement
    1655
    1656          a = Element('a')
    1657          b = SubElement(a, 'b')
    1658
    1659          self.assertRaises(TypeError,
    1660                            a.__setitem__, 0, 'foo')
    1661
    1662 -    def test_append_error(self):
    1663          Element = self.etree.Element
    1664          root = Element('root')
    1665          # raises AssertionError in ElementTree
    1666          self.assertRaises(TypeError, root.append, None)
    1667          self.assertRaises(TypeError, root.extend, [None])
    1668          self.assertRaises(TypeError, root.extend, [Element('one'), None])
    1669          self.assertEqual('one', root[0].tag)
    1670
    1671 -    def test_append_recursive_error(self):
    1672          Element = self.etree.Element
    1673          SubElement = self.etree.SubElement
    1674          root = Element('root')
    1675          self.assertRaises(ValueError, root.append, root)
    1676          child = SubElement(root, 'child')
    1677          self.assertRaises(ValueError, child.append, root)
    1678          child2 = SubElement(child, 'child2')
    1679          self.assertRaises(ValueError, child2.append, root)
    1680          self.assertRaises(ValueError, child2.append, child)
    1681          self.assertEqual('child2', root[0][0].tag)
    1682
    1683 -    def test_addnext(self):
    1684          Element = self.etree.Element
    1685          SubElement = self.etree.SubElement
    1686          root = Element('root')
    1687          SubElement(root, 'a')
    1688          SubElement(root, 'b')
    1689
    1690          self.assertEqual(['a', 'b'],
    1691                            [c.tag for c in root])
    1692          root[1].addnext(root[0])
    1693          self.assertEqual(['b', 'a'],
    1694                            [c.tag for c in root])
    1695
    1696 -    def test_addprevious(self):
    1697          Element = self.etree.Element
    1698          SubElement = self.etree.SubElement
    1699          root = Element('root')
    1700          SubElement(root, 'a')
    1701          SubElement(root, 'b')
    1702
    1703          self.assertEqual(['a', 'b'],
    1704                            [c.tag for c in root])
    1705          root[0].addprevious(root[1])
    1706          self.assertEqual(['b', 'a'],
    1707                            [c.tag for c in root])
    1708
    1709 -    def test_addnext_cycle(self):
    1710          Element = self.etree.Element
    1711          SubElement = self.etree.SubElement
    1712          root = Element('root')
    1713          a = SubElement(root, 'a')
    1714          b = SubElement(a, 'b')
    1715          # appending parent as sibling is forbidden
    1716          self.assertRaises(ValueError, b.addnext, a)
    1717          self.assertEqual(['a'], [c.tag for c in root])
    1718          self.assertEqual(['b'], [c.tag for c in a])
    1719
    1720 -    def test_addprevious_cycle(self):
    1721          Element = self.etree.Element
    1722          SubElement = self.etree.SubElement
    1723          root = Element('root')
    1724          a = SubElement(root, 'a')
    1725          b = SubElement(a, 'b')
    1726          # appending parent as sibling is forbidden
    1727          self.assertRaises(ValueError, b.addprevious, a)
    1728          self.assertEqual(['a'], [c.tag for c in root])
    1729          self.assertEqual(['b'], [c.tag for c in a])
    1730
    1731 -    def test_addnext_cycle_long(self):
    1732          Element = self.etree.Element
    1733          SubElement = self.etree.SubElement
    1734          root = Element('root')
    1735          a = SubElement(root, 'a')
    1736          b = SubElement(a, 'b')
    1737          c = SubElement(b, 'c')
    1738          # appending parent as sibling is forbidden
    1739          self.assertRaises(ValueError, c.addnext, a)
    1740
    1741 -    def test_addprevious_cycle_long(self):
    1742          Element = self.etree.Element
    1743          SubElement = self.etree.SubElement
    1744          root = Element('root')
    1745          a = SubElement(root, 'a')
    1746          b = SubElement(a, 'b')
    1747          c = SubElement(b, 'c')
    1748          # appending parent as sibling is forbidden
    1749          self.assertRaises(ValueError, c.addprevious, a)
    1750
    1751 -    def test_addprevious_noops(self):
    1752          Element = self.etree.Element
    1753          SubElement = self.etree.SubElement
    1754          root = Element('root')
    1755          a = SubElement(root, 'a')
    1756          b = SubElement(root, 'b')
    1757          a.addprevious(a)
    1758          self.assertEqual('a', root[0].tag)
    1759          self.assertEqual('b', root[1].tag)
    1760          b.addprevious(b)
    1761          self.assertEqual('a', root[0].tag)
    1762          self.assertEqual('b', root[1].tag)
    1763          b.addprevious(a)
    1764          self.assertEqual('a', root[0].tag)
    1765          self.assertEqual('b', root[1].tag)
    1766
    1767 -    def test_addnext_noops(self):
    1768          Element = self.etree.Element
    1769          SubElement = self.etree.SubElement
    1770          root = Element('root')
    1771          a = SubElement(root, 'a')
    1772          b = SubElement(root, 'b')
    1773          a.addnext(a)
    1774          self.assertEqual('a', root[0].tag)
    1775          self.assertEqual('b', root[1].tag)
    1776          b.addnext(b)
    1777          self.assertEqual('a', root[0].tag)
    1778          self.assertEqual('b', root[1].tag)
    1779          a.addnext(b)
    1780          self.assertEqual('a', root[0].tag)
    1781          self.assertEqual('b', root[1].tag)
    1782
    1783 -    def test_addnext_root(self):
    1784          Element = self.etree.Element
    1785          a = Element('a')
    1786          b = Element('b')
    1787          self.assertRaises(TypeError, a.addnext, b)
    1788
    1789 -    def test_addprevious_pi(self):
    1790          Element = self.etree.Element
    1791          SubElement = self.etree.SubElement
    1792          PI = self.etree.PI
    1793          root = Element('root')
    1794          SubElement(root, 'a')
    1795          pi = PI('TARGET', 'TEXT')
    1796          pi.tail = "TAIL"
    1797
    1798          self.assertEqual(_bytes('<root><a></a></root>'),
    1799                            self._writeElement(root))
    1800          root[0].addprevious(pi)
    1801          self.assertEqual(_bytes('<root><?TARGET TEXT?>TAIL<a></a></root>'),
    1802                            self._writeElement(root))
    1803
    1804 -    def test_addprevious_root_pi(self):
    1805          Element = self.etree.Element
    1806          PI = self.etree.PI
    1807          root = Element('root')
    1808          pi = PI('TARGET', 'TEXT')
    1809          pi.tail = "TAIL"
    1810
    1811          self.assertEqual(_bytes('<root></root>'),
    1812                            self._writeElement(root))
    1813          root.addprevious(pi)
    1814          self.assertEqual(_bytes('<?TARGET TEXT?>\n<root></root>'),
    1815                            self._writeElement(root))
    1816
    1817 -    def test_addnext_pi(self):
    1818          Element = self.etree.Element
    1819          SubElement = self.etree.SubElement
    1820          PI = self.etree.PI
    1821          root = Element('root')
    1822          SubElement(root, 'a')
    1823          pi = PI('TARGET', 'TEXT')
    1824          pi.tail = "TAIL"
    1825
    1826          self.assertEqual(_bytes('<root><a></a></root>'),
    1827                            self._writeElement(root))
    1828          root[0].addnext(pi)
    1829          self.assertEqual(_bytes('<root><a></a><?TARGET TEXT?>TAIL</root>'),
    1830                            self._writeElement(root))
    1831
    1832 -    def test_addnext_root_pi(self):
    1833          Element = self.etree.Element
    1834          PI = self.etree.PI
    1835          root = Element('root')
    1836          pi = PI('TARGET', 'TEXT')
    1837          pi.tail = "TAIL"
    1838
    1839          self.assertEqual(_bytes('<root></root>'),
    1840                            self._writeElement(root))
    1841          root.addnext(pi)
    1842          self.assertEqual(_bytes('<root></root>\n<?TARGET TEXT?>'),
    1843                            self._writeElement(root))
    1844
    1845 -    def test_addnext_comment(self):
    1846          Element = self.etree.Element
    1847          SubElement = self.etree.SubElement
    1848          Comment = self.etree.Comment
    1849          root = Element('root')
    1850          SubElement(root, 'a')
    1851          comment = Comment('TEXT ')
    1852          comment.tail = "TAIL"
    1853
    1854          self.assertEqual(_bytes('<root><a></a></root>'),
    1855                            self._writeElement(root))
    1856          root[0].addnext(comment)
    1857          self.assertEqual(_bytes('<root><a></a><!--TEXT -->TAIL</root>'),
    1858                            self._writeElement(root))
    1859
    1860 -    def test_addnext_root_comment(self):
    1861          Element = self.etree.Element
    1862          Comment = self.etree.Comment
    1863          root = Element('root')
    1864          comment = Comment('TEXT ')
    1865          comment.tail = "TAIL"
    1866
    1867          self.assertEqual(_bytes('<root></root>'),
    1868                            self._writeElement(root))
    1869          root.addnext(comment)
    1870          self.assertEqual(_bytes('<root></root>\n<!--TEXT -->'),
    1871                            self._writeElement(root))
    1872
    1873 -    def test_addprevious_comment(self):
    1874          Element = self.etree.Element
    1875          SubElement = self.etree.SubElement
    1876          Comment = self.etree.Comment
    1877          root = Element('root')
    1878          SubElement(root, 'a')
    1879          comment = Comment('TEXT ')
    1880          comment.tail = "TAIL"
    1881
    1882          self.assertEqual(_bytes('<root><a></a></root>'),
    1883                            self._writeElement(root))
    1884          root[0].addprevious(comment)
    1885          self.assertEqual(_bytes('<root><!--TEXT -->TAIL<a></a></root>'),
    1886                            self._writeElement(root))
    1887
    1888 -    def test_addprevious_root_comment(self):
    1889          Element = self.etree.Element
    1890          Comment = self.etree.Comment
    1891          root = Element('root')
    1892          comment = Comment('TEXT ')
    1893          comment.tail = "TAIL"
    1894
    1895          self.assertEqual(_bytes('<root></root>'),
    1896                            self._writeElement(root))
    1897          root.addprevious(comment)
    1898          self.assertEqual(_bytes('<!--TEXT -->\n<root></root>'),
    1899                            self._writeElement(root))
    1900
    1901      # ET's Elements have items() and key(), but not values()
    1902 -    def test_attribute_values(self):
    1903          XML = self.etree.XML
    1904
    1905          root = XML(_bytes('<doc alpha="Alpha" beta="Beta" gamma="Gamma"/>'))
    1906          values = root.values()
    1907          values.sort()
    1908          self.assertEqual(['Alpha', 'Beta', 'Gamma'], values)
    1909
    1910      # gives error in ElementTree
    1911 -    def test_comment_empty(self):
    1912          Element = self.etree.Element
    1913          Comment = self.etree.Comment
    1914
    1915          a = Element('a')
    1916          a.append(Comment())
    1917          self.assertEqual(
    1918              _bytes('<a><!----></a>'),
    1919              self._writeElement(a))
    1920
    1921      # ElementTree ignores comments
    1922 -    def test_comment_parse_empty(self):
    1923          ElementTree = self.etree.ElementTree
    1924          tostring = self.etree.tostring
    1925
    1926          xml = _bytes('<a><b/><!----><c/></a>')
    1927          f = BytesIO(xml)
    1928          doc = ElementTree(file=f)
    1929          a = doc.getroot()
    1930          self.assertEqual(
    1931              '',
    1932              a[1].text)
    1933          self.assertEqual(
    1934              xml,
    1935              tostring(a))
    1936
    1937      # ElementTree ignores comments
    1938 -    def test_comment_no_proxy_yet(self):
    1939          ElementTree = self.etree.ElementTree
    1940
    1941          f = BytesIO('<a><b></b><!-- hoi --><c></c></a>')
    1942          doc = ElementTree(file=f)
    1943          a = doc.getroot()
    1944          self.assertEqual(
    1945              ' hoi ',
    1946              a[1].text)
    1947
    1948      # does not raise an exception in ElementTree
    1949 -    def test_comment_immutable(self):
    1950          Element = self.etree.Element
    1951          Comment = self.etree.Comment
    1952
    1953          c = Comment()
    1954          el = Element('myel')
    1955
    1956          self.assertRaises(TypeError, c.append, el)
    1957          self.assertRaises(TypeError, c.insert, 0, el)
    1958          self.assertRaises(TypeError, c.set, "myattr", "test")
    1959
    1960 -    def test_comment_immutable_attrib(self):
    1961          c = self.etree.Comment()
    1962          self.assertEqual(0, len(c.attrib))
    1963
    1964          self.assertFalse(c.attrib.__contains__('nope'))
    1965          self.assertFalse('nope' in c.attrib)
    1966          self.assertFalse('nope' in c.attrib.keys())
    1967          self.assertFalse('nope' in c.attrib.values())
    1968          self.assertFalse(('nope', 'huhu') in c.attrib.items())
    1969
    1970          self.assertEqual([], list(c.attrib))
    1971          self.assertEqual([], list(c.attrib.keys()))
    1972          self.assertEqual([], list(c.attrib.items()))
    1973          self.assertEqual([], list(c.attrib.values()))
    1974          self.assertEqual([], list(c.attrib.iterkeys()))
    1975          self.assertEqual([], list(c.attrib.iteritems()))
    1976          self.assertEqual([], list(c.attrib.itervalues()))
    1977
    1978          self.assertEqual('HUHU', c.attrib.pop('nope', 'HUHU'))
    1979          self.assertRaises(KeyError, c.attrib.pop, 'nope')
    1980
    1981          self.assertRaises(KeyError, c.attrib.__getitem__, 'only')
    1982          self.assertRaises(KeyError, c.attrib.__getitem__, 'names')
    1983          self.assertRaises(KeyError, c.attrib.__getitem__, 'nope')
    1984          self.assertRaises(KeyError, c.attrib.__setitem__, 'nope', 'yep')
    1985          self.assertRaises(KeyError, c.attrib.__delitem__, 'nope')
    1986
    1987      # test passing 'None' to dump()
    1988 -    def test_dump_none(self):
    1989          self.assertRaises(TypeError, self.etree.dump, None)
    1990
    1991 -    def test_prefix(self):
    1992          ElementTree = self.etree.ElementTree
    1993
    1994          f = BytesIO('<a xmlns:foo="http://www.infrae.com/ns/1"><foo:b/></a>')
    1995          doc = ElementTree(file=f)
    1996          a = doc.getroot()
    1997          self.assertEqual(
    1998              None,
    1999              a.prefix)
    2000          self.assertEqual(
    2001              'foo',
    2002              a[0].prefix)
    2003
    2004 -    def test_prefix_default_ns(self):
    2005          ElementTree = self.etree.ElementTree
    2006
    2007          f = BytesIO('<a xmlns="http://www.infrae.com/ns/1"><b/></a>')
    2008          doc = ElementTree(file=f)
    2009          a = doc.getroot()
    2010          self.assertEqual(
    2011              None,
    2012              a.prefix)
    2013          self.assertEqual(
    2014              None,
    2015              a[0].prefix)
    2016
    2017 -    def test_getparent(self):
    2018          Element = self.etree.Element
    2019          SubElement = self.etree.SubElement
    2020
    2021          a = Element('a')
    2022          b = SubElement(a, 'b')
    2023          c = SubElement(a, 'c')
    2024          d = SubElement(b, 'd')
    2025          self.assertEqual(
    2026              None,
    2027              a.getparent())
    2028          self.assertEqual(
    2029              a,
    2030              b.getparent())
    2031          self.assertEqual(
    2032              b.getparent(),
    2033              c.getparent())
    2034          self.assertEqual(
    2035              b,
    2036              d.getparent())
    2037
    2038 -    def test_iterchildren(self):
    2039          XML = self.etree.XML
    2040
    2041          root = XML(_bytes('<doc><one/><two>Two</two>Hm<three/></doc>'))
    2042          result = []
    2043          for el in root.iterchildren():
    2044              result.append(el.tag)
    2045          self.assertEqual(['one', 'two', 'three'], result)
    2046
    2047 -    def test_iterchildren_reversed(self):
    2048          XML = self.etree.XML
    2049
    2050          root = XML(_bytes('<doc><one/><two>Two</two>Hm<three/></doc>'))
    2051          result = []
    2052          for el in root.iterchildren(reversed=True):
    2053              result.append(el.tag)
    2054          self.assertEqual(['three', 'two', 'one'], result)
    2055
    2056 -    def test_iterchildren_tag(self):
    2057          XML = self.etree.XML
    2058
    2059          root = XML(_bytes('<doc><one/><two>Two</two>Hm<two>Bla</two></doc>'))
    2060          result = []
    2061          for el in root.iterchildren(tag='two'):
    2062              result.append(el.text)
    2063          self.assertEqual(['Two', 'Bla'], result)
    2064
    2065 -    def test_iterchildren_tag_posarg(self):
    2066          XML = self.etree.XML
    2067
    2068          root = XML(_bytes('<doc><one/><two>Two</two>Hm<two>Bla</two></doc>'))
    2069          result = []
    2070          for el in root.iterchildren('two'):
    2071              result.append(el.text)
    2072          self.assertEqual(['Two', 'Bla'], result)
    2073
    2074 -    def test_iterchildren_tag_reversed(self):
    2075          XML = self.etree.XML
    2076
    2077          root = XML(_bytes('<doc><one/><two>Two</two>Hm<two>Bla</two></doc>'))
    2078          result = []
    2079          for el in root.iterchildren(reversed=True, tag='two'):
    2080              result.append(el.text)
    2081          self.assertEqual(['Bla', 'Two'], result)
    2082
    2083 -    def test_iterchildren_tag_multiple(self):
    2084          XML = self.etree.XML
    2085
    2086          root = XML(_bytes('<doc><one/><two>Two</two>Hm<two>Bla</two><three/></doc>'))
    2087          result = []
    2088          for el in root.iterchildren(tag=['two', 'three']):
    2089              result.append(el.text)
    2090          self.assertEqual(['Two', 'Bla', None], result)
    2091
    2092 -    def test_iterchildren_tag_multiple_posarg(self):
    2093          XML = self.etree.XML
    2094
    2095          root = XML(_bytes('<doc><one/><two>Two</two>Hm<two>Bla</two><three/></doc>'))
    2096          result = []
    2097          for el in root.iterchildren('two', 'three'):
    2098              result.append(el.text)
    2099          self.assertEqual(['Two', 'Bla', None], result)
    2100
    2101 -    def test_iterchildren_tag_multiple_reversed(self):
    2102          XML = self.etree.XML
    2103
    2104          root = XML(_bytes('<doc><one/><two>Two</two>Hm<two>Bla</two><three/></doc>'))
    2105          result = []
    2106          for el in root.iterchildren(reversed=True, tag=['two', 'three']):
    2107              result.append(el.text)
    2108          self.assertEqual([None, 'Bla', 'Two'], result)
    2109
    2110 -    def test_iterancestors(self):
    2111          Element    = self.etree.Element
    2112          SubElement = self.etree.SubElement
    2113
    2114          a = Element('a')
    2115          b = SubElement(a, 'b')
    2116          c = SubElement(a, 'c')
    2117          d = SubElement(b, 'd')
    2118          self.assertEqual(
    2119              [],
    2120              list(a.iterancestors()))
    2121          self.assertEqual(
    2122              [a],
    2123              list(b.iterancestors()))
    2124          self.assertEqual(
    2125              [a],
    2126              list(c.iterancestors()))
    2127          self.assertEqual(
    2128              [b, a],
    2129              list(d.iterancestors()))
    2130
    2131 -    def test_iterancestors_tag(self):
    2132          Element    = self.etree.Element
    2133          SubElement = self.etree.SubElement
    2134
    2135          a = Element('a')
    2136          b = SubElement(a, 'b')
    2137          c = SubElement(a, 'c')
    2138          d = SubElement(b, 'd')
    2139          self.assertEqual(
    2140              [a],
    2141              list(d.iterancestors('a')))
    2142          self.assertEqual(
    2143              [a],
    2144              list(d.iterancestors(tag='a')))
    2145
    2146          self.assertEqual(
    2147              [b, a],
    2148              list(d.iterancestors('*')))
    2149          self.assertEqual(
    2150              [b, a],
    2151              list(d.iterancestors(tag='*')))
    2152
    2153 -    def test_iterancestors_tag_multiple(self):
    2154          Element    = self.etree.Element
    2155          SubElement = self.etree.SubElement
    2156
    2157          a = Element('a')
    2158          b = SubElement(a, 'b')
    2159          c = SubElement(a, 'c')
    2160          d = SubElement(b, 'd')
    2161          self.assertEqual(
    2162              [b, a],
    2163              list(d.iterancestors(tag=('a', 'b'))))
    2164          self.assertEqual(
    2165              [b, a],
    2166              list(d.iterancestors('a', 'b')))
    2167
    2168          self.assertEqual(
    2169              [],
    2170              list(d.iterancestors(tag=('w', 'x', 'y', 'z'))))
    2171          self.assertEqual(
    2172              [],
    2173              list(d.iterancestors('w', 'x', 'y', 'z')))
    2174
    2175          self.assertEqual(
    2176              [],
    2177              list(d.iterancestors(tag=('d', 'x'))))
    2178          self.assertEqual(
    2179              [],
    2180              list(d.iterancestors('d', 'x')))
    2181
    2182          self.assertEqual(
    2183              [b, a],
    2184              list(d.iterancestors(tag=('b', '*'))))
    2185          self.assertEqual(
    2186              [b, a],
    2187              list(d.iterancestors('b', '*')))
    2188
    2189          self.assertEqual(
    2190              [b],
    2191              list(d.iterancestors(tag=('b', 'c'))))
    2192          self.assertEqual(
    2193              [b],
    2194              list(d.iterancestors('b', 'c')))
    2195
    2196 -    def test_iterdescendants(self):
    2197          Element = self.etree.Element
    2198          SubElement = self.etree.SubElement
    2199
    2200          a = Element('a')
    2201          b = SubElement(a, 'b')
    2202          c = SubElement(a, 'c')
    2203          d = SubElement(b, 'd')
    2204          e = SubElement(c, 'e')
    2205
    2206          self.assertEqual(
    2207              [b, d, c, e],
    2208              list(a.iterdescendants()))
    2209          self.assertEqual(
    2210              [],
    2211              list(d.iterdescendants()))
    2212
    2213 -    def test_iterdescendants_tag(self):
    2214          Element = self.etree.Element
    2215          SubElement = self.etree.SubElement
    2216
    2217          a = Element('a')
    2218          b = SubElement(a, 'b')
    2219          c = SubElement(a, 'c')
    2220          d = SubElement(b, 'd')
    2221          e = SubElement(c, 'e')
    2222
    2223          self.assertEqual(
    2224              [],
    2225              list(a.iterdescendants('a')))
    2226          self.assertEqual(
    2227              [],
    2228              list(a.iterdescendants(tag='a')))
    2229
    2230          a2 = SubElement(e, 'a')
    2231          self.assertEqual(
    2232              [a2],
    2233              list(a.iterdescendants('a')))
    2234
    2235          self.assertEqual(
    2236              [a2],
    2237              list(c.iterdescendants('a')))
    2238          self.assertEqual(
    2239              [a2],
    2240              list(c.iterdescendants(tag='a')))
    2241
    2242 -    def test_iterdescendants_tag_multiple(self):
    2243          Element = self.etree.Element
    2244          SubElement = self.etree.SubElement
    2245
    2246          a = Element('a')
    2247          b = SubElement(a, 'b')
    2248          c = SubElement(a, 'c')
    2249          d = SubElement(b, 'd')
    2250          e = SubElement(c, 'e')
    2251
    2252          self.assertEqual(
    2253              [b, e],
    2254              list(a.iterdescendants(tag=('a', 'b', 'e'))))
    2255          self.assertEqual(
    2256              [b, e],
    2257              list(a.iterdescendants('a', 'b', 'e')))
    2258
    2259          a2 = SubElement(e, 'a')
    2260          self.assertEqual(
    2261              [b, a2],
    2262              list(a.iterdescendants(tag=('a', 'b'))))
    2263          self.assertEqual(
    2264              [b, a2],
    2265              list(a.iterdescendants('a', 'b')))
    2266
    2267          self.assertEqual(
    2268              [],
    2269              list(c.iterdescendants(tag=('x', 'y', 'z'))))
    2270          self.assertEqual(
    2271              [],
    2272              list(c.iterdescendants('x', 'y', 'z')))
    2273
    2274          self.assertEqual(
    2275              [b, d, c, e, a2],
    2276              list(a.iterdescendants(tag=('x', 'y', 'z', '*'))))
    2277          self.assertEqual(
    2278              [b, d, c, e, a2],
    2279              list(a.iterdescendants('x', 'y', 'z', '*')))
    2280
    2281 -    def test_getroottree(self):
    2282          Element = self.etree.Element
    2283          SubElement = self.etree.SubElement
    2284
    2285          a = Element('a')
    2286          b = SubElement(a, 'b')
    2287          c = SubElement(a, 'c')
    2288          d = SubElement(b, 'd')
    2289          self.assertEqual(
    2290              a,
    2291              a.getroottree().getroot())
    2292          self.assertEqual(
    2293              a,
    2294              b.getroottree().getroot())
    2295          self.assertEqual(
    2296              a,
    2297              d.getroottree().getroot())
    2298
    2299 -    def test_getnext(self):
    2300          Element    = self.etree.Element
    2301          SubElement = self.etree.SubElement
    2302
    2303          a = Element('a')
    2304          b = SubElement(a, 'b')
    2305          c = SubElement(a, 'c')
    2306          self.assertEqual(
    2307              None,
    2308              a.getnext())
    2309          self.assertEqual(
    2310              c,
    2311              b.getnext())
    2312          self.assertEqual(
    2313              None,
    2314              c.getnext())
    2315
    2316 -    def test_getprevious(self):
    2317          Element    = self.etree.Element
    2318          SubElement = self.etree.SubElement
    2319
    2320          a = Element('a')
    2321          b = SubElement(a, 'b')
    2322          c = SubElement(a, 'c')
    2323          d = SubElement(b, 'd')
    2324          self.assertEqual(
    2325              None,
    2326              a.getprevious())
    2327          self.assertEqual(
    2328              b,
    2329              c.getprevious())
    2330          self.assertEqual(
    2331              None,
    2332              b.getprevious())
    2333
    2334 -    def test_itersiblings(self):
    2335          Element    = self.etree.Element
    2336          SubElement = self.etree.SubElement
    2337
    2338          a = Element('a')
    2339          b = SubElement(a, 'b')
    2340          c = SubElement(a, 'c')
    2341          d = SubElement(b, 'd')
    2342          self.assertEqual(
    2343              [],
    2344              list(a.itersiblings()))
    2345          self.assertEqual(
    2346              [c],
    2347              list(b.itersiblings()))
    2348          self.assertEqual(
    2349              [],
    2350              list(c.itersiblings()))
    2351          self.assertEqual(
    2352              [b],
    2353              list(c.itersiblings(preceding=True)))
    2354          self.assertEqual(
    2355              [],
    2356              list(b.itersiblings(preceding=True)))
    2357
    2358 -    def test_itersiblings_tag(self):
    2359          Element    = self.etree.Element
    2360          SubElement = self.etree.SubElement
    2361
    2362          a = Element('a')
    2363          b = SubElement(a, 'b')
    2364          c = SubElement(a, 'c')
    2365          d = SubElement(b, 'd')
    2366          self.assertEqual(
    2367              [],
    2368              list(a.itersiblings(tag='XXX')))
    2369          self.assertEqual(
    2370              [c],
    2371              list(b.itersiblings(tag='c')))
    2372          self.assertEqual(
    2373              [c],
    2374              list(b.itersiblings(tag='*')))
    2375          self.assertEqual(
    2376              [b],
    2377              list(c.itersiblings(preceding=True, tag='b')))
    2378          self.assertEqual(
    2379              [],
    2380              list(c.itersiblings(preceding=True, tag='c')))
    2381
    2382 -    def test_itersiblings_tag_multiple(self):
    2383          Element    = self.etree.Element
    2384          SubElement = self.etree.SubElement
    2385
    2386          a = Element('a')
    2387          b = SubElement(a, 'b')
    2388          c = SubElement(a, 'c')
    2389          d = SubElement(b, 'd')
    2390          e = SubElement(a, 'e')
    2391          self.assertEqual(
    2392              [],
    2393              list(a.itersiblings(tag=('XXX', 'YYY'))))
    2394          self.assertEqual(
    2395              [c, e],
    2396              list(b.itersiblings(tag=('c', 'd', 'e'))))
    2397          self.assertEqual(
    2398              [b],
    2399              list(c.itersiblings(preceding=True, tag=('b', 'b', 'c', 'd'))))
    2400          self.assertEqual(
    2401              [c, b],
    2402              list(e.itersiblings(preceding=True, tag=('c', '*'))))
    2403
    2404 -    def test_parseid(self):
    2405          parseid = self.etree.parseid
    2406          XML     = self.etree.XML
    2407          xml_text = _bytes('''
    2408          <!DOCTYPE document [
    2409          <!ELEMENT document (h1,p)*>
    2410          <!ELEMENT h1 (#PCDATA)>
    2411          <!ATTLIST h1 myid ID #REQUIRED>
    2412          <!ELEMENT p  (#PCDATA)>
    2413          <!ATTLIST p  someid ID #REQUIRED>
    2414          ]>
    2415          <document>
    2416            <h1 myid="chapter1">...</h1>
    2417            <p id="note1" class="note">...</p>
    2418            <p>Regular paragraph.</p>
    2419            <p xml:id="xmlid">XML:ID paragraph.</p>
    2420            <p someid="warn1" class="warning">...</p>
    2421          </document>
    2422          ''')
    2423
    2424          tree, dic = parseid(BytesIO(xml_text))
    2425          root = tree.getroot()
    2426          root2 = XML(xml_text)
    2427          self.assertEqual(self._writeElement(root),
    2428                            self._writeElement(root2))
    2429          expected = {
    2430              "chapter1" : root[0],
    2431              "xmlid"    : root[3],
    2432              "warn1"    : root[4]
    2433              }
    2434          self.assertTrue("chapter1" in dic)
    2435          self.assertTrue("warn1" in dic)
    2436          self.assertTrue("xmlid" in dic)
    2437          self._checkIDDict(dic, expected)
    2438
    2439 -    def test_XMLDTDID(self):
    2440          XMLDTDID = self.etree.XMLDTDID
    2441          XML      = self.etree.XML
    2442          xml_text = _bytes('''
    2443          <!DOCTYPE document [
    2444          <!ELEMENT document (h1,p)*>
    2445          <!ELEMENT h1 (#PCDATA)>
    2446          <!ATTLIST h1 myid ID #REQUIRED>
    2447          <!ELEMENT p  (#PCDATA)>
    2448          <!ATTLIST p  someid ID #REQUIRED>
    2449          ]>
    2450          <document>
    2451            <h1 myid="chapter1">...</h1>
    2452            <p id="note1" class="note">...</p>
    2453            <p>Regular paragraph.</p>
    2454            <p xml:id="xmlid">XML:ID paragraph.</p>
    2455            <p someid="warn1" class="warning">...</p>
    2456          </document>
    2457          ''')
    2458
    2459          root, dic = XMLDTDID(xml_text)
    2460          root2 = XML(xml_text)
    2461          self.assertEqual(self._writeElement(root),
    2462                            self._writeElement(root2))
    2463          expected = {
    2464              "chapter1" : root[0],
    2465              "xmlid"    : root[3],
    2466              "warn1"    : root[4]
    2467              }
    2468          self.assertTrue("chapter1" in dic)
    2469          self.assertTrue("warn1" in dic)
    2470          self.assertTrue("xmlid" in dic)
    2471          self._checkIDDict(dic, expected)
    2472
    2473 -    def test_XMLDTDID_empty(self):
    2474          XMLDTDID = self.etree.XMLDTDID
    2475          XML      = self.etree.XML
    2476          xml_text = _bytes('''
    2477          <document>
    2478            <h1 myid="chapter1">...</h1>
    2479            <p id="note1" class="note">...</p>
    2480            <p>Regular paragraph.</p>
    2481            <p someid="warn1" class="warning">...</p>
    2482          </document>
    2483          ''')
    2484
    2485          root, dic = XMLDTDID(xml_text)
    2486          root2 = XML(xml_text)
    2487          self.assertEqual(self._writeElement(root),
    2488                            self._writeElement(root2))
    2489          expected = {}
    2490          self._checkIDDict(dic, expected)
    2491
    2492 -    def test_XMLDTDID_no_id_dict(self):
    2493          XMLDTDID = self.etree.XMLDTDID
    2494          XML      = self.etree.XML
    2495          xml_text = _bytes('''
    2496          <!DOCTYPE document [
    2497          <!ELEMENT document (h1,p)*>
    2498          <!ELEMENT h1 (#PCDATA)>
    2499          <!ATTLIST h1 myid ID #REQUIRED>
    2500          <!ELEMENT p  (#PCDATA)>
    2501          <!ATTLIST p  someid ID #REQUIRED>
    2502          ]>
    2503          <document>
    2504            <h1 myid="chapter1">...</h1>
    2505            <p id="note1" class="note">...</p>
    2506            <p>Regular paragraph.</p>
    2507            <p xml:id="xmlid">XML:ID paragraph.</p>
    2508            <p someid="warn1" class="warning">...</p>
    2509          </document>
    2510          ''')
    2511
    2512          parser = etree.XMLParser(collect_ids=False)
    2513          root, dic = XMLDTDID(xml_text, parser=parser)
    2514          root2 = XML(xml_text)
    2515          self.assertEqual(self._writeElement(root),
    2516                           self._writeElement(root2))
    2517          self.assertFalse(dic)
    2518          self._checkIDDict(dic, {})
    2519
    2520 -    def _checkIDDict(self, dic, expected):
    2521          self.assertEqual(len(dic),
    2522                            len(expected))
    2523          self.assertEqual(sorted(dic.items()),
    2524                            sorted(expected.items()))
    2525          if sys.version_info < (3,):
    2526              self.assertEqual(sorted(dic.iteritems()),
    2527                                sorted(expected.iteritems()))
    2528          self.assertEqual(sorted(dic.keys()),
    2529                            sorted(expected.keys()))
    2530          if sys.version_info < (3,):
    2531              self.assertEqual(sorted(dic.iterkeys()),
    2532                                sorted(expected.iterkeys()))
    2533          if sys.version_info < (3,):
    2534              self.assertEqual(sorted(dic.values()),
    2535                                sorted(expected.values()))
    2536              self.assertEqual(sorted(dic.itervalues()),
    2537                                sorted(expected.itervalues()))
    2538
    2539 -    def test_namespaces(self):
    2540          etree = self.etree
    2541
    2542          r = {'foo': 'http://ns.infrae.com/foo'}
    2543          e = etree.Element('{http://ns.infrae.com/foo}bar', nsmap=r)
    2544          self.assertEqual(
    2545              'foo',
    2546              e.prefix)
    2547          self.assertEqual(
    2548              _bytes('<foo:bar xmlns:foo="http://ns.infrae.com/foo"></foo:bar>'),
    2549              self._writeElement(e))
    2550
    2551 -    def test_namespaces_default(self):
    2552          etree = self.etree
    2553
    2554          r = {None: 'http://ns.infrae.com/foo'}
    2555          e = etree.Element('{http://ns.infrae.com/foo}bar', nsmap=r)
    2556          self.assertEqual(
    2557              None,
    2558              e.prefix)
    2559          self.assertEqual(
    2560              '{http://ns.infrae.com/foo}bar',
    2561              e.tag)
    2562          self.assertEqual(
    2563              _bytes('<bar xmlns="http://ns.infrae.com/foo"></bar>'),
    2564              self._writeElement(e))
    2565
    2566 -    def test_namespaces_default_and_other(self):
    2567          etree = self.etree
    2568
    2569          r = {None: 'http://ns.infrae.com/foo', 'p': 'http://test/'}
    2570          e = etree.Element('{http://ns.infrae.com/foo}bar', nsmap=r)
    2571          self.assertEqual(None, e.prefix)
    2572          self.assertEqual('{http://ns.infrae.com/foo}bar', e.tag)
    2573          self.assertEqual(
    2574              _bytes('<bar xmlns="http://ns.infrae.com/foo" xmlns:p="http://test/"></bar>'),
    2575              self._writeElement(e))
    2576
    2577 -    def test_namespaces_default_and_attr(self):
    2578          etree = self.etree
    2579
    2580          r = {None: 'http://ns.infrae.com/foo',
    2581               'hoi': 'http://ns.infrae.com/hoi'}
    2582          e = etree.Element('{http://ns.infrae.com/foo}bar', nsmap=r)
    2583          e.set('{http://ns.infrae.com/hoi}test', 'value')
    2584          self.assertEqual(
    2585              _bytes('<bar xmlns="http://ns.infrae.com/foo" xmlns:hoi="http://ns.infrae.com/hoi" hoi:test="value"></bar>'),
    2586              self._writeElement(e))
    2587
    2588 -    def test_attribute_keeps_namespace_prefix_on_merge(self):
    2589          etree = self.etree
    2590
    2591          root = etree.Element('{http://test/ns}root',
    2592                               nsmap={None: 'http://test/ns'})
    2593          sub = etree.Element('{http://test/ns}sub',
    2594                              nsmap={'test': 'http://test/ns'})
    2595
    2596          sub.attrib['{http://test/ns}attr'] = 'value'
    2597          self.assertEqual(sub.attrib['{http://test/ns}attr'], 'value')
    2598          self.assertEqual(
    2599              _bytes('<test:sub xmlns:test="http://test/ns" test:attr="value"/>'),
    2600              etree.tostring(sub))
    2601
    2602          root.append(sub)
    2603          self.assertEqual(
    2604              _bytes('<root xmlns="http://test/ns">'
    2605                     '<sub xmlns:test="http://test/ns" test:attr="value"/>'
    2606                     '</root>'),
    2607              etree.tostring(root))
    2608
    2609 -    def test_attribute_keeps_namespace_prefix_on_merge_with_nons(self):
    2610          etree = self.etree
    2611
    2612          root = etree.Element('root')
    2613          sub = etree.Element('{http://test/ns}sub',
    2614                              nsmap={'test': 'http://test/ns'})
    2615
    2616          sub.attrib['{http://test/ns}attr'] = 'value'
    2617          self.assertEqual(sub.attrib['{http://test/ns}attr'], 'value')
    2618          self.assertEqual(
    2619              _bytes('<test:sub xmlns:test="http://test/ns" test:attr="value"/>'),
    2620              etree.tostring(sub))
    2621
    2622          root.append(sub)
    2623          self.assertEqual(
    2624              _bytes('<root>'
    2625                     '<test:sub xmlns:test="http://test/ns" test:attr="value"/>'
    2626                     '</root>'),
    2627              etree.tostring(root))
    2628
    2629 -    def test_attribute_gets_namespace_prefix_on_merge_with_nons(self):
    2630          etree = self.etree
    2631
    2632          root = etree.Element('root')
    2633          sub = etree.Element('{http://test/ns}sub',
    2634                              nsmap={None: 'http://test/ns'})
    2635
    2636          sub.attrib['{http://test/ns}attr'] = 'value'
    2637          self.assertEqual(sub.attrib['{http://test/ns}attr'], 'value')
    2638          self.assertEqual(
    2639              _bytes('<sub xmlns="http://test/ns" '
    2640                     'xmlns:ns0="http://test/ns" ns0:attr="value"/>'),
    2641              etree.tostring(sub))
    2642
    2643          root.append(sub)
    2644          self.assertEqual(
    2645              _bytes('<root>'
    2646                     '<sub xmlns="http://test/ns"'
    2647                     ' xmlns:ns0="http://test/ns" ns0:attr="value"/>'
    2648                     '</root>'),
    2649              etree.tostring(root))
    2650
    2651 -    def test_attribute_gets_namespace_prefix_on_merge(self):
    2652          etree = self.etree
    2653
    2654          root = etree.Element('{http://test/ns}root',
    2655                               nsmap={'test': 'http://test/ns',
    2656                                      None: 'http://test/ns'})
    2657          sub = etree.Element('{http://test/ns}sub',
    2658                              nsmap={None: 'http://test/ns'})
    2659
    2660          sub.attrib['{http://test/ns}attr'] = 'value'
    2661          self.assertEqual(sub.attrib['{http://test/ns}attr'], 'value')
    2662          self.assertEqual(
    2663              _bytes('<sub xmlns="http://test/ns" '
    2664                     'xmlns:ns0="http://test/ns" ns0:attr="value"/>'),
    2665              etree.tostring(sub))
    2666
    2667          root.append(sub)
    2668          self.assertEqual(
    2669              _bytes('<test:root xmlns:test="http://test/ns" xmlns="http://test/ns">'
    2670                     '<test:sub test:attr="value"/>'
    2671                     '</test:root>'),
    2672              etree.tostring(root))
    2673
    2674 -    def test_namespaces_elementtree(self):
    2675          etree = self.etree
    2676          r = {None: 'http://ns.infrae.com/foo',
    2677               'hoi': 'http://ns.infrae.com/hoi'}
    2678          e = etree.Element('{http://ns.infrae.com/foo}z', nsmap=r)
    2679          tree = etree.ElementTree(element=e)
    2680          etree.SubElement(e, '{http://ns.infrae.com/hoi}x')
    2681          self.assertEqual(
    2682              _bytes('<z xmlns="http://ns.infrae.com/foo" xmlns:hoi="http://ns.infrae.com/hoi"><hoi:x></hoi:x></z>'),
    2683              self._writeElement(e))
    2684
    2685 -    def test_namespaces_default_copy_element(self):
    2686          etree = self.etree
    2687
    2688          r = {None: 'http://ns.infrae.com/foo'}
    2689          e1 = etree.Element('{http://ns.infrae.com/foo}bar', nsmap=r)
    2690          e2 = etree.Element('{http://ns.infrae.com/foo}bar', nsmap=r)
    2691
    2692          e1.append(e2)
    2693
    2694          self.assertEqual(
    2695              None,
    2696              e1.prefix)
    2697          self.assertEqual(
    2698              None,
    2699              e1[0].prefix)
    2700          self.assertEqual(
    2701              '{http://ns.infrae.com/foo}bar',
    2702              e1.tag)
    2703          self.assertEqual(
    2704              '{http://ns.infrae.com/foo}bar',
    2705              e1[0].tag)
    2706
    2707 -    def test_namespaces_copy_element(self):
    2708          etree = self.etree
    2709
    2710          r = {None: 'http://ns.infrae.com/BAR'}
    2711          e1 = etree.Element('{http://ns.infrae.com/BAR}bar', nsmap=r)
    2712          e2 = etree.Element('{http://ns.infrae.com/foo}bar', nsmap=r)
    2713
    2714          e1.append(e2)
    2715
    2716          self.assertEqual(
    2717              None,
    2718              e1.prefix)
    2719          self.assertNotEqual(
    2720              None,
    2721              e2.prefix)
    2722          self.assertEqual(
    2723              '{http://ns.infrae.com/BAR}bar',
    2724              e1.tag)
    2725          self.assertEqual(
    2726              '{http://ns.infrae.com/foo}bar',
    2727              e2.tag)
    2728
    2729 -    def test_namespaces_reuse_after_move(self):
    2730          ns_href = "http://a.b.c"
    2731          one = self.etree.fromstring(
    2732              _bytes('<foo><bar xmlns:ns="%s"><ns:baz/></bar></foo>' % ns_href))
    2733          baz = one[0][0]
    2734
    2735          two = self.etree.fromstring(
    2736              _bytes('<root xmlns:ns="%s"/>' % ns_href))
    2737          two.append(baz)
    2738          del one # make sure the source document is deallocated
    2739
    2740          self.assertEqual('{%s}baz' % ns_href, baz.tag)
    2741          self.assertEqual(
    2742              _bytes('<root xmlns:ns="%s"><ns:baz/></root>' % ns_href),
    2743              self.etree.tostring(two))
    2744
    2745 -    def test_namespace_cleanup(self):
    2746          xml = _bytes(
    2747              '<foo xmlns="F" xmlns:x="x">'
    2748              '<bar xmlns:ns="NS" xmlns:b="b" xmlns="B">'
    2749              '<ns:baz/>'
    2750              '</bar></foo>'
    2751          )
    2752          root = self.etree.fromstring(xml)
    2753          self.assertEqual(xml, self.etree.tostring(root))
    2754          self.etree.cleanup_namespaces(root)
    2755          self.assertEqual(
    2756              _bytes('<foo xmlns="F"><bar xmlns:ns="NS" xmlns="B"><ns:baz/></bar></foo>'),
    2757              self.etree.tostring(root))
    2758
    2759 -    def test_namespace_cleanup_attributes(self):
    2760          xml = _bytes(
    2761              '<foo xmlns="F" xmlns:x="X" xmlns:a="A">'
    2762              '<bar xmlns:ns="NS" xmlns:b="b" xmlns="B">'
    2763              '<ns:baz a:test="attr"/>'
    2764              '</bar></foo>'
    2765          )
    2766          root = self.etree.fromstring(xml)
    2767          self.assertEqual(xml, self.etree.tostring(root))
    2768          self.etree.cleanup_namespaces(root)
    2769          self.assertEqual(
    2770              _bytes('<foo xmlns="F" xmlns:a="A">'
    2771                     '<bar xmlns:ns="NS" xmlns="B">'
    2772                     '<ns:baz a:test="attr"/>'
    2773                     '</bar></foo>'),
    2774              self.etree.tostring(root))
    2775
    2776 -    def test_namespace_cleanup_many(self):
    2777          xml = ('<n12:foo ' +
    2778                 ' '.join('xmlns:n{n}="NS{n}"'.format(n=i) for i in range(100)) +
    2779                 '><n68:a/></n12:foo>').encode('utf8')
    2780          root = self.etree.fromstring(xml)
    2781          self.assertEqual(xml, self.etree.tostring(root))
    2782          self.etree.cleanup_namespaces(root)
    2783          self.assertEqual(
    2784              b'<n12:foo xmlns:n12="NS12" xmlns:n68="NS68"><n68:a/></n12:foo>',
    2785              self.etree.tostring(root))
    2786
    2787 -    def test_namespace_cleanup_deep(self):
    2788          xml = ('<root>' +
    2789                 ''.join('<a xmlns:n{n}="NS{n}">'.format(n=i) for i in range(100)) +
    2790                 '<n64:x/>' + '</a>'*100 + '</root>').encode('utf8')
    2791          root = self.etree.fromstring(xml)
    2792          self.assertEqual(xml, self.etree.tostring(root))
    2793          self.etree.cleanup_namespaces(root)
    2794          self.assertEqual(
    2795              b'<root>' + b'<a>'*64 + b'<a xmlns:n64="NS64">' + b'<a>'*35 +
    2796              b'<n64:x/>' + b'</a>'*100 + b'</root>',
    2797              self.etree.tostring(root))
    2798
    2799 -    def test_namespace_cleanup_deep_to_top(self):
    2800          xml = ('<root>' +
    2801                 ''.join('<a xmlns:n{n}="NS{n}">'.format(n=i) for i in range(100)) +
    2802                 '<n64:x xmlns:a="A" a:attr="X"/>' +
    2803                 '</a>'*100 +
    2804                 '</root>').encode('utf8')
    2805          root = self.etree.fromstring(xml)
    2806          self.assertEqual(xml, self.etree.tostring(root))
    2807          self.etree.cleanup_namespaces(root, top_nsmap={'n64': 'NS64'})
    2808          self.assertEqual(
    2809              b'<root xmlns:n64="NS64">' + b'<a>'*100 +
    2810              b'<n64:x xmlns:a="A" a:attr="X"/>' + b'</a>'*100 + b'</root>',
    2811              self.etree.tostring(root))
    2812
    2813 -    def test_namespace_cleanup_keep_prefixes(self):
    2814          xml = ('<root xmlns:n64="NS64" xmlns:foo="FOO" xmlns:unused1="UNUSED" xmlns:no="NO">'
    2815                 '<a xmlns:unused2="UNUSED"><n64:x xmlns:a="A" a:attr="X"/></a>'
    2816                 '<foo>foo:bar</foo>'
    2817                 '</root>').encode('utf8')
    2818          root = self.etree.fromstring(xml)
    2819          self.assertEqual(xml, self.etree.tostring(root))
    2820          self.etree.cleanup_namespaces(root, keep_ns_prefixes=['foo'])
    2821          self.assertEqual(
    2822              b'<root xmlns:n64="NS64" xmlns:foo="FOO">'
    2823              b'<a><n64:x xmlns:a="A" a:attr="X"/></a>'
    2824              b'<foo>foo:bar</foo>'
    2825              b'</root>',
    2826              self.etree.tostring(root))
    2827
    2828 -    def test_namespace_cleanup_keep_prefixes_top(self):
    2829          xml = ('<root xmlns:n64="NS64" xmlns:unused1="UNUSED" xmlns:no="NO">'
    2830                 '<sub xmlns:foo="FOO">'
    2831                 '<a xmlns:unused2="UNUSED"><n64:x xmlns:a="A" a:attr="X"/></a>'
    2832                 '<foo>foo:bar</foo>'
    2833                 '</sub>'
    2834                 '</root>').encode('utf8')
    2835          root = self.etree.fromstring(xml)
    2836          self.assertEqual(xml, self.etree.tostring(root))
    2837          self.etree.cleanup_namespaces(
    2838              root,
    2839              top_nsmap={'foo': 'FOO', 'unused1': 'UNUSED'},
    2840              keep_ns_prefixes=['foo'])
    2841          self.assertEqual(
    2842              b'<root xmlns:n64="NS64" xmlns:foo="FOO">'
    2843              b'<sub>'
    2844              b'<a><n64:x xmlns:a="A" a:attr="X"/></a>'
    2845              b'<foo>foo:bar</foo>'
    2846              b'</sub>'
    2847              b'</root>',
    2848              self.etree.tostring(root))
    2849
    2850 -    def test_element_nsmap(self):
    2851          etree = self.etree
    2852
    2853          r = {None: 'http://ns.infrae.com/foo',
    2854               'hoi': 'http://ns.infrae.com/hoi'}
    2855          e = etree.Element('{http://ns.infrae.com/foo}bar', nsmap=r)
    2856          self.assertEqual(
    2857              r,
    2858              e.nsmap)
    2859
    2860 -    def test_subelement_nsmap(self):
    2861          etree = self.etree
    2862
    2863          re = {None: 'http://ns.infrae.com/foo',
    2864               'hoi': 'http://ns.infrae.com/hoi'}
    2865          e = etree.Element('{http://ns.infrae.com/foo}bar', nsmap=re)
    2866
    2867          rs = {None: 'http://ns.infrae.com/honk',
    2868               'top': 'http://ns.infrae.com/top'}
    2869          s = etree.SubElement(e, '{http://ns.infrae.com/honk}bar', nsmap=rs)
    2870
    2871          r = re.copy()
    2872          r.update(rs)
    2873          self.assertEqual(re, e.nsmap)
    2874          self.assertEqual(r,  s.nsmap)
    2875
    2876 -    def test_html_prefix_nsmap(self):
    2877          etree = self.etree
    2878          el = etree.HTML('<hha:page-description>aa</hha:page-description>').find('.//page-description')
    2879          self.assertEqual({'hha': None}, el.nsmap)
    2880
    2881 -    def test_getiterator_filter_multiple(self):
    2882          Element = self.etree.Element
    2883          SubElement = self.etree.SubElement
    2884
    2885          a = Element('a')
    2886          b = SubElement(a, 'b')
    2887          c = SubElement(a, 'c')
    2888          d = SubElement(b, 'd')
    2889          e = SubElement(c, 'e')
    2890          f = SubElement(c, 'f')
    2891
    2892          self.assertEqual(
    2893              [a, b],
    2894                 list(a.getiterator('a', 'b')))
    2895          self.assertEqual(
    2896              [],
    2897                list(a.getiterator('x', 'y')))
    2898          self.assertEqual(
    2899              [a, f],
    2900                list(a.getiterator('f', 'a')))
    2901          self.assertEqual(
    2902              [c, e, f],
    2903                 list(c.getiterator('c', '*', 'a')))
    2904          self.assertEqual(
    2905              [],
    2906                    list(a.getiterator( (), () )))
    2907
    2908 -    def test_getiterator_filter_multiple_tuple(self):
    2909          Element = self.etree.Element
    2910          SubElement = self.etree.SubElement
    2911
    2912          a = Element('a')
    2913          b = SubElement(a, 'b')
    2914          c = SubElement(a, 'c')
    2915          d = SubElement(b, 'd')
    2916          e = SubElement(c, 'e')
    2917          f = SubElement(c, 'f')
    2918
    2919          self.assertEqual(
    2920              [a, b],
    2921                    list(a.getiterator( ('a', 'b') )))
    2922          self.assertEqual(
    2923              [],
    2924                list(a.getiterator( ('x', 'y') )))
    2925          self.assertEqual(
    2926              [a, f],
    2927                    list(a.getiterator( ('f', 'a') )))
    2928          self.assertEqual(
    2929              [c, e, f],
    2930                       list(c.getiterator( ('c', '*', 'a') )))
    2931          self.assertEqual(
    2932              [],
    2933                list(a.getiterator( () )))
    2934
    2935 -    def test_getiterator_filter_namespace(self):
    2936          Element = self.etree.Element
    2937          SubElement = self.etree.SubElement
    2938
    2939          a = Element('{a}a')
    2940          b = SubElement(a, '{a}b')
    2941          c = SubElement(a, '{a}c')
    2942          d = SubElement(b, '{b}d')
    2943          e = SubElement(c, '{a}e')
    2944          f = SubElement(c, '{b}f')
    2945          g = SubElement(c, 'g')
    2946
    2947          self.assertEqual(
    2948              [a],
    2949              list(a.getiterator('{a}a')))
    2950          self.assertEqual(
    2951              [],
    2952              list(a.getiterator('{b}a')))
    2953          self.assertEqual(
    2954              [],
    2955              list(a.getiterator('a')))
    2956          self.assertEqual(
    2957              [a,b,d,c,e,f,g],
    2958              list(a.getiterator('*')))
    2959          self.assertEqual(
    2960              [f],
    2961              list(c.getiterator('{b}*')))
    2962          self.assertEqual(
    2963              [d, f],
    2964              list(a.getiterator('{b}*')))
    2965          self.assertEqual(
    2966              [g],
    2967              list(a.getiterator('g')))
    2968          self.assertEqual(
    2969              [g],
    2970              list(a.getiterator('{}g')))
    2971          self.assertEqual(
    2972              [g],
    2973              list(a.getiterator('{}*')))
    2974
    2975 -    def test_getiterator_filter_local_name(self):
    2976          Element = self.etree.Element
    2977          SubElement = self.etree.SubElement
    2978
    2979          a = Element('{a}a')
    2980          b = SubElement(a, '{nsA}b')
    2981          c = SubElement(b, '{nsB}b')
    2982          d = SubElement(a, 'b')
    2983          e = SubElement(a, '{nsA}e')
    2984          f = SubElement(e, '{nsB}e')
    2985          g = SubElement(e, 'e')
    2986
    2987          self.assertEqual(
    2988              [b, c, d],
    2989              list(a.getiterator('{*}b')))
    2990          self.assertEqual(
    2991              [e, f, g],
    2992              list(a.getiterator('{*}e')))
    2993          self.assertEqual(
    2994              [a, b, c, d, e, f, g],
    2995              list(a.getiterator('{*}*')))
    2996
    2997 -    def test_getiterator_filter_entities(self):
    2998          Element = self.etree.Element
    2999          Entity = self.etree.Entity
    3000          SubElement = self.etree.SubElement
    3001
    3002          a = Element('a')
    3003          b = SubElement(a, 'b')
    3004          entity_b = Entity("TEST-b")
    3005          b.append(entity_b)
    3006
    3007          self.assertEqual(
    3008              [entity_b],
    3009              list(a.getiterator(Entity)))
    3010
    3011          entity_a = Entity("TEST-a")
    3012          a.append(entity_a)
    3013
    3014          self.assertEqual(
    3015              [entity_b, entity_a],
    3016              list(a.getiterator(Entity)))
    3017
    3018          self.assertEqual(
    3019              [entity_b],
    3020              list(b.getiterator(Entity)))
    3021
    3022 -    def test_getiterator_filter_element(self):
    3023          Element = self.etree.Element
    3024          Comment = self.etree.Comment
    3025          PI = self.etree.PI
    3026          SubElement = self.etree.SubElement
    3027
    3028          a = Element('a')
    3029          b = SubElement(a, 'b')
    3030          a.append(Comment("test"))
    3031          a.append(PI("pi", "content"))
    3032          c = SubElement(a, 'c')
    3033
    3034          self.assertEqual(
    3035              [a, b, c],
    3036              list(a.getiterator(Element)))
    3037
    3038 -    def test_getiterator_filter_all_comment_pi(self):
    3039          # ElementTree iterates over everything here
    3040          Element = self.etree.Element
    3041          Comment = self.etree.Comment
    3042          PI = self.etree.PI
    3043          SubElement = self.etree.SubElement
    3044
    3045          a = Element('a')
    3046          b = SubElement(a, 'b')
    3047          a.append(Comment("test"))
    3048          a.append(PI("pi", "content"))
    3049          c = SubElement(a, 'c')
    3050
    3051          self.assertEqual(
    3052              [a, b, c],
    3053              list(a.getiterator('*')))
    3054
    3055 -    def test_elementtree_getelementpath(self):
    3056          a  = etree.Element("a")
    3057          b  = etree.SubElement(a, "b")
    3058          c  = etree.SubElement(a, "c")
    3059          d1 = etree.SubElement(c, "d")
    3060          d2 = etree.SubElement(c, "d")
    3061          c.text = d1.text = 'TEXT'
    3062
    3063          tree = etree.ElementTree(a)
    3064          self.assertEqual('.', tree.getelementpath(a))
    3065          self.assertEqual('c/d[1]', tree.getelementpath(d1))
    3066          self.assertEqual('c/d[2]', tree.getelementpath(d2))
    3067
    3068          self.assertEqual(d1, tree.find(tree.getelementpath(d1)))
    3069          self.assertEqual(d2, tree.find(tree.getelementpath(d2)))
    3070
    3071          tree = etree.ElementTree(c)
    3072          self.assertEqual('.', tree.getelementpath(c))
    3073          self.assertEqual('d[2]', tree.getelementpath(d2))
    3074          self.assertEqual(d2, tree.find(tree.getelementpath(d2)))
    3075
    3076          tree = etree.ElementTree(b)  # not a parent of a/c/d1/d2
    3077          self.assertEqual('.', tree.getelementpath(b))
    3078          self.assertRaises(ValueError, tree.getelementpath, a)
    3079          self.assertRaises(ValueError, tree.getelementpath, c)
    3080          self.assertRaises(ValueError, tree.getelementpath, d2)
    3081
    3082 -    def test_elementtree_getelementpath_ns(self):
    3083          a  = etree.Element("{http://ns1/}a")
    3084          b  = etree.SubElement(a, "{http://ns1/}b")
    3085          c  = etree.SubElement(a, "{http://ns1/}c")
    3086          d1 = etree.SubElement(c, "{http://ns1/}d")
    3087          d2 = etree.SubElement(c, "{http://ns2/}d")
    3088          d3 = etree.SubElement(c, "{http://ns1/}d")
    3089
    3090          tree = etree.ElementTree(a)
    3091          self.assertEqual('.', tree.getelementpath(a))
    3092          self.assertEqual('{http://ns1/}c/{http://ns1/}d[1]',
    3093                           tree.getelementpath(d1))
    3094          self.assertEqual('{http://ns1/}c/{http://ns2/}d',
    3095                           tree.getelementpath(d2))
    3096          self.assertEqual('{http://ns1/}c/{http://ns1/}d[2]',
    3097                           tree.getelementpath(d3))
    3098
    3099          self.assertEqual(a, tree.find(tree.getelementpath(a)))
    3100          self.assertEqual(b, tree.find(tree.getelementpath(b)))
    3101          self.assertEqual(c, tree.find(tree.getelementpath(c)))
    3102          self.assertEqual(d1, tree.find(tree.getelementpath(d1)))
    3103          self.assertEqual(d2, tree.find(tree.getelementpath(d2)))
    3104          self.assertEqual(d3, tree.find(tree.getelementpath(d3)))
    3105
    3106          tree = etree.ElementTree(c)
    3107          self.assertEqual('{http://ns1/}d[1]', tree.getelementpath(d1))
    3108          self.assertEqual('{http://ns2/}d', tree.getelementpath(d2))
    3109          self.assertEqual('{http://ns1/}d[2]', tree.getelementpath(d3))
    3110          self.assertEqual(d1, tree.find(tree.getelementpath(d1)))
    3111          self.assertEqual(d2, tree.find(tree.getelementpath(d2)))
    3112          self.assertEqual(d3, tree.find(tree.getelementpath(d3)))
    3113
    3114          tree = etree.ElementTree(b)  # not a parent of d1/d2
    3115          self.assertRaises(ValueError, tree.getelementpath, d1)
    3116          self.assertRaises(ValueError, tree.getelementpath, d2)
    3117
    3118 -    def test_elementtree_find_qname(self):
    3119          XML = self.etree.XML
    3120          ElementTree = self.etree.ElementTree
    3121          QName = self.etree.QName
    3122          tree = ElementTree(XML(_bytes('<a><b><c/></b><b/><c><b/></c></a>')))
    3123          self.assertEqual(tree.find(QName("c")), tree.getroot()[2])
    3124
    3125 -    def test_elementtree_findall_qname(self):
    3126          XML = self.etree.XML
    3127          ElementTree = self.etree.ElementTree
    3128          QName = self.etree.QName
    3129          tree = ElementTree(XML(_bytes('<a><b><c/></b><b/><c><b/></c></a>')))
    3130          self.assertEqual(len(list(tree.findall(QName("c")))), 1)
    3131
    3132 -    def test_elementtree_findall_ns_qname(self):
    3133          XML = self.etree.XML
    3134          ElementTree = self.etree.ElementTree
    3135          QName = self.etree.QName
    3136          tree = ElementTree(XML(
    3137                  _bytes('<a xmlns:x="X" xmlns:y="Y"><x:b><c/></x:b><b/><c><x:b/><b/></c><b/></a>')))
    3138          self.assertEqual(len(list(tree.findall(QName("b")))), 2)
    3139          self.assertEqual(len(list(tree.findall(QName("X", "b")))), 1)
    3140
    3141 -    def test_findall_ns(self):
    3142          XML = self.etree.XML
    3143          root = XML(_bytes('<a xmlns:x="X" xmlns:y="Y"><x:b><c/></x:b><b/><c><x:b/><b/></c><b/></a>'))
    3144          self.assertEqual(len(root.findall(".//{X}b")), 2)
    3145          self.assertEqual(len(root.findall(".//{X}*")), 2)
    3146          self.assertEqual(len(root.findall(".//b")), 3)
    3147
    3148 -    def test_findall_different_nsmaps(self):
    3149          XML = self.etree.XML
    3150          root = XML(_bytes('<a xmlns:x="X" xmlns:y="Y"><x:b><c/></x:b><b/><c><x:b/><b/></c><y:b/></a>'))
    3151          nsmap = {'xx': 'X'}
    3152          self.assertEqual(len(root.findall(".//xx:b", namespaces=nsmap)), 2)
    3153          self.assertEqual(len(root.findall(".//xx:*", namespaces=nsmap)), 2)
    3154          self.assertEqual(len(root.findall(".//b", namespaces=nsmap)), 2)
    3155          nsmap = {'xx': 'Y'}
    3156          self.assertEqual(len(root.findall(".//xx:b", namespaces=nsmap)), 1)
    3157          self.assertEqual(len(root.findall(".//xx:*", namespaces=nsmap)), 1)
    3158          self.assertEqual(len(root.findall(".//b", namespaces=nsmap)), 2)
    3159
    3160 -    def test_findall_empty_prefix(self):
    3161          XML = self.etree.XML
    3162          root = XML(_bytes('<a xmlns:x="X" xmlns:y="Y"><x:b><c/></x:b><b/><c><x:b/><b/></c><y:b/></a>'))
    3163          nsmap = {'xx': 'X'}
    3164          self.assertEqual(len(root.findall(".//xx:b", namespaces=nsmap)), 2)
    3165          nsmap = {'xx': 'X', None: 'Y'}
    3166          self.assertEqual(len(root.findall(".//b", namespaces=nsmap)), 1)
    3167          nsmap = {'xx': 'X', '': 'Y'}
    3168          self.assertRaises(ValueError, root.findall, ".//xx:b", namespaces=nsmap)
    3169
    3170 -    def test_findall_syntax_error(self):
    3171          XML = self.etree.XML
    3172          root = XML(_bytes('<a><b><c/></b><b/><c><b/><b/></c><b/></a>'))
    3173          self.assertRaises(SyntaxError, root.findall, '')
    3174          self.assertRaises(SyntaxError, root.findall, '//')  # absolute path on Element
    3175          self.assertRaises(SyntaxError, root.findall, './//')
    3176
    3177 -    def test_index(self):
    3178          etree = self.etree
    3179          e = etree.Element('foo')
    3180          for i in range(10):
    3181              etree.SubElement(e, 'a%s' % i)
    3182          for i in range(10):
    3183              self.assertEqual(
    3184                  i,
    3185                  e.index(e[i]))
    3186          self.assertEqual(
    3187              3, e.index(e[3], 3))
    3188          self.assertRaises(
    3189              ValueError, e.index, e[3], 4)
    3190          self.assertRaises(
    3191              ValueError, e.index, e[3], 0, 2)
    3192          self.assertRaises(
    3193              ValueError, e.index, e[8], 0, -3)
    3194          self.assertRaises(
    3195              ValueError, e.index, e[8], -5, -3)
    3196          self.assertEqual(
    3197              8, e.index(e[8], 0, -1))
    3198          self.assertEqual(
    3199              8, e.index(e[8], -12, -1))
    3200          self.assertEqual(
    3201              0, e.index(e[0], -12, -1))
    3202
    3203 -    def test_replace(self):
    3204          etree = self.etree
    3205          e = etree.Element('foo')
    3206          for i in range(10):
    3207              el = etree.SubElement(e, 'a%s' % i)
    3208              el.text = "text%d" % i
    3209              el.tail = "tail%d" % i
    3210
    3211          child0 = e[0]
    3212          child1 = e[1]
    3213          child2 = e[2]
    3214
    3215          e.replace(e[0], e[1])
    3216          self.assertEqual(
    3217              9, len(e))
    3218          self.assertEqual(
    3219              child1, e[0])
    3220          self.assertEqual(
    3221              child1.text, "text1")
    3222          self.assertEqual(
    3223              child1.tail, "tail1")
    3224          self.assertEqual(
    3225              child0.tail, "tail0")
    3226          self.assertEqual(
    3227              child2, e[1])
    3228
    3229          e.replace(e[-1], e[0])
    3230          self.assertEqual(
    3231              child1, e[-1])
    3232          self.assertEqual(
    3233              child1.text, "text1")
    3234          self.assertEqual(
    3235              child1.tail, "tail1")
    3236          self.assertEqual(
    3237              child2, e[0])
    3238
    3239 -    def test_replace_new(self):
    3240          etree = self.etree
    3241          e = etree.Element('foo')
    3242          for i in range(10):
    3243              etree.SubElement(e, 'a%s' % i)
    3244
    3245          new_element = etree.Element("test")
    3246          new_element.text = "TESTTEXT"
    3247          new_element.tail = "TESTTAIL"
    3248          child1 = e[1]
    3249          e.replace(e[0], new_element)
    3250          self.assertEqual(
    3251              new_element, e[0])
    3252          self.assertEqual(
    3253              "TESTTEXT",
    3254              e[0].text)
    3255          self.assertEqual(
    3256              "TESTTAIL",
    3257              e[0].tail)
    3258          self.assertEqual(
    3259              child1, e[1])
    3260
    3261 -    def test_setslice_all_empty_reversed(self):
    3262          Element = self.etree.Element
    3263          SubElement = self.etree.SubElement
    3264
    3265          a = Element('a')
    3266
    3267          e = Element('e')
    3268          f = Element('f')
    3269          g = Element('g')
    3270
    3271          s = [e, f, g]
    3272          a[::-1] = s
    3273          self.assertEqual(
    3274              [g, f, e],
    3275              list(a))
    3276
    3277 -    def test_setslice_step(self):
    3278          Element = self.etree.Element
    3279          SubElement = self.etree.SubElement
    3280
    3281          a = Element('a')
    3282          b = SubElement(a, 'b')
    3283          c = SubElement(a, 'c')
    3284          d = SubElement(a, 'd')
    3285          e = SubElement(a, 'e')
    3286
    3287          x = Element('x')
    3288          y = Element('y')
    3289
    3290          a[1::2] = [x, y]
    3291          self.assertEqual(
    3292              [b, x, d, y],
    3293              list(a))
    3294
    3295 -    def test_setslice_step_negative(self):
    3296          Element = self.etree.Element
    3297          SubElement = self.etree.SubElement
    3298
    3299          a = Element('a')
    3300          b = SubElement(a, 'b')
    3301          c = SubElement(a, 'c')
    3302          d = SubElement(a, 'd')
    3303          e = SubElement(a, 'e')
    3304
    3305          x = Element('x')
    3306          y = Element('y')
    3307
    3308          a[1::-1] = [x, y]
    3309          self.assertEqual(
    3310              [y, x, d, e],
    3311              list(a))
    3312
    3313 -    def test_setslice_step_negative2(self):
    3314          Element = self.etree.Element
    3315          SubElement = self.etree.SubElement
    3316
    3317          a = Element('a')
    3318          b = SubElement(a, 'b')
    3319          c = SubElement(a, 'c')
    3320          d = SubElement(a, 'd')
    3321          e = SubElement(a, 'e')
    3322
    3323          x = Element('x')
    3324          y = Element('y')
    3325
    3326          a[::-2] = [x, y]
    3327          self.assertEqual(
    3328              [b, y, d, x],
    3329              list(a))
    3330
    3331 -    def test_setslice_step_overrun(self):
    3332          Element = self.etree.Element
    3333          SubElement = self.etree.SubElement
    3334          try:
    3335              slice
    3336          except NameError:
    3337              print("slice() not found")
    3338              return
    3339
    3340          a = Element('a')
    3341          b = SubElement(a, 'b')
    3342          c = SubElement(a, 'c')
    3343          d = SubElement(a, 'd')
    3344          e = SubElement(a, 'e')
    3345
    3346          x = Element('x')
    3347          y = Element('y')
    3348          z = Element('z')
    3349
    3350          self.assertRaises(
    3351              ValueError,
    3352              operator.setitem, a, slice(1,None,2), [x, y, z])
    3353
    3354          self.assertEqual(
    3355              [b, c, d, e],
    3356              list(a))
    3357
    3358 -    def test_sourceline_XML(self):
    3359          XML = self.etree.XML
    3360          root = XML(_bytes('''<?xml version="1.0"?>
    3361          <root><test>
    3362
    3363          <bla/></test>
    3364          </root>
    3365          '''))
    3366
    3367          self.assertEqual(
    3368              [2, 2, 4],
    3369              [ el.sourceline for el in root.getiterator() ])
    3370
    3371 -    def test_large_sourceline_XML(self):
    3372          XML = self.etree.XML
    3373          root = XML(_bytes(
    3374              '<?xml version="1.0"?>\n'
    3375              '<root>' + '\n' * 65536 +
    3376              '<p>' + '\n' * 65536 + '</p>\n' +
    3377              '<br/>\n'
    3378              '</root>'))
    3379
    3380          if self.etree.LIBXML_VERSION >= (2, 9):
    3381              expected = [2, 131074, 131076]
    3382          else:
    3383              expected = [2, 65535, 65535]
    3384
    3385          self.assertEqual(expected, [el.sourceline for el in root.iter()])
    3386
    3387 -    def test_sourceline_parse(self):
    3388          parse = self.etree.parse
    3389          tree = parse(fileInTestDir('include/test_xinclude.xml'))
    3390
    3391          self.assertEqual(
    3392              [1, 2, 3],
    3393              [ el.sourceline for el in tree.getiterator() ])
    3394
    3395 -    def test_sourceline_iterparse_end(self):
    3396          iterparse = self.etree.iterparse
    3397          lines = [ el.sourceline for (event, el) in
    3398                    iterparse(fileInTestDir('include/test_xinclude.xml')) ]
    3399
    3400          self.assertEqual(
    3401              [2, 3, 1],
    3402              lines)
    3403
    3404 -    def test_sourceline_iterparse_start(self):
    3405          iterparse = self.etree.iterparse
    3406          lines = [ el.sourceline for (event, el) in
    3407                    iterparse(fileInTestDir('include/test_xinclude.xml'),
    3408                              events=("start",)) ]
    3409
    3410          self.assertEqual(
    3411              [1, 2, 3],
    3412              lines)
    3413
    3414 -    def test_sourceline_element(self):
    3415          Element = self.etree.Element
    3416          SubElement = self.etree.SubElement
    3417          el = Element("test")
    3418          self.assertEqual(None, el.sourceline)
    3419
    3420          child = SubElement(el, "test")
    3421          self.assertEqual(None, el.sourceline)
    3422          self.assertEqual(None, child.sourceline)
    3423
    3424 -    def test_XML_base_url_docinfo(self):
    3425          etree = self.etree
    3426          root = etree.XML(_bytes("<root/>"), base_url="http://no/such/url")
    3427          docinfo = root.getroottree().docinfo
    3428          self.assertEqual(docinfo.URL, "http://no/such/url")
    3429
    3430 -    def test_XML_set_base_url_docinfo(self):
    3431          etree = self.etree
    3432          root = etree.XML(_bytes("<root/>"), base_url="http://no/such/url")
    3433          docinfo = root.getroottree().docinfo
    3434          self.assertEqual(docinfo.URL, "http://no/such/url")
    3435          docinfo.URL = "https://secret/url"
    3436          self.assertEqual(docinfo.URL, "https://secret/url")
    3437
    3438 -    def test_parse_stringio_base_url(self):
    3439          etree = self.etree
    3440          tree = etree.parse(BytesIO("<root/>"), base_url="http://no/such/url")
    3441          docinfo = tree.docinfo
    3442          self.assertEqual(docinfo.URL, "http://no/such/url")
    3443
    3444 -    def test_parse_base_url_docinfo(self):
    3445          etree = self.etree
    3446          tree = etree.parse(fileInTestDir('include/test_xinclude.xml'),
    3447                             base_url="http://no/such/url")
    3448          docinfo = tree.docinfo
    3449          self.assertEqual(docinfo.URL, "http://no/such/url")
    3450
    3451 -    def test_HTML_base_url_docinfo(self):
    3452          etree = self.etree
    3453          root = etree.HTML(_bytes("<html/>"), base_url="http://no/such/url")
    3454          docinfo = root.getroottree().docinfo
    3455          self.assertEqual(docinfo.URL, "http://no/such/url")
    3456
    3457 -    def test_docinfo_public(self):
    3458          etree = self.etree
    3459          xml_header = '<?xml version="1.0" encoding="ascii"?>'
    3460          pub_id = "-//W3C//DTD XHTML 1.0 Transitional//EN"
    3461          sys_id = "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"
    3462          doctype_string = '<!DOCTYPE html PUBLIC "%s" "%s">' % (pub_id, sys_id)
    3463
    3464          xml = _bytes(xml_header + doctype_string + '<html><body></body></html>')
    3465
    3466          tree = etree.parse(BytesIO(xml))
    3467          docinfo = tree.docinfo
    3468          self.assertEqual(docinfo.encoding,    "ascii")
    3469          self.assertEqual(docinfo.xml_version, "1.0")
    3470          self.assertEqual(docinfo.public_id,   pub_id)
    3471          self.assertEqual(docinfo.system_url,  sys_id)
    3472          self.assertEqual(docinfo.root_name,   'html')
    3473          self.assertEqual(docinfo.doctype, doctype_string)
    3474
    3475 -    def test_docinfo_system(self):
    3476          etree = self.etree
    3477          xml_header = '<?xml version="1.0" encoding="UTF-8"?>'
    3478          sys_id = "some.dtd"
    3479          doctype_string = '<!DOCTYPE html SYSTEM "%s">' % sys_id
    3480          xml = _bytes(xml_header + doctype_string + '<html><body></body></html>')
    3481
    3482          tree = etree.parse(BytesIO(xml))
    3483          docinfo = tree.docinfo
    3484          self.assertEqual(docinfo.encoding,    "UTF-8")
    3485          self.assertEqual(docinfo.xml_version, "1.0")
    3486          self.assertEqual(docinfo.public_id,   None)
    3487          self.assertEqual(docinfo.system_url,  sys_id)
    3488          self.assertEqual(docinfo.root_name,   'html')
    3489          self.assertEqual(docinfo.doctype, doctype_string)
    3490
    3491 -    def test_docinfo_empty(self):
    3492          etree = self.etree
    3493          xml = _bytes('<html><body></body></html>')
    3494          tree = etree.parse(BytesIO(xml))
    3495          docinfo = tree.docinfo
    3496          self.assertEqual(docinfo.encoding,    "UTF-8")
    3497          self.assertEqual(docinfo.xml_version, "1.0")
    3498          self.assertEqual(docinfo.public_id,   None)
    3499          self.assertEqual(docinfo.system_url,  None)
    3500          self.assertEqual(docinfo.root_name,   'html')
    3501          self.assertEqual(docinfo.doctype, '')
    3502
    3503 -    def test_docinfo_name_only(self):
    3504          etree = self.etree
    3505          xml = _bytes('<!DOCTYPE root><root></root>')
    3506          tree = etree.parse(BytesIO(xml))
    3507          docinfo = tree.docinfo
    3508          self.assertEqual(docinfo.encoding,    "UTF-8")
    3509          self.assertEqual(docinfo.xml_version, "1.0")
    3510          self.assertEqual(docinfo.public_id,   None)
    3511          self.assertEqual(docinfo.system_url,  None)
    3512          self.assertEqual(docinfo.root_name,   'root')
    3513          self.assertEqual(docinfo.doctype, '<!DOCTYPE root>')
    3514
    3515 -    def test_doctype_name_only_roundtrip(self):
    3516          etree = self.etree
    3517          xml = _bytes('<!DOCTYPE root>\n<root/>')
    3518          tree = etree.parse(BytesIO(xml))
    3519          self.assertEqual(xml, etree.tostring(tree))
    3520
    3521 -    def test_doctype_output_override(self):
    3522          etree = self.etree
    3523          pub_id = "-//W3C//DTD XHTML 1.0 Transitional//EN"
    3524          sys_id = "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"
    3525          doctype_string = _bytes('<!DOCTYPE html PUBLIC "%s" "%s">' % (pub_id, sys_id))
    3526
    3527          xml = _bytes('<!DOCTYPE root>\n<root/>')
    3528          tree = etree.parse(BytesIO(xml))
    3529          self.assertEqual(xml.replace(_bytes('<!DOCTYPE root>'), doctype_string),
    3530                            etree.tostring(tree, doctype=doctype_string))
    3531
    3532 -    def test_xml_base(self):
    3533          etree = self.etree
    3534          root = etree.XML(_bytes("<root/>"), base_url="http://no/such/url")
    3535          self.assertEqual(root.base, "http://no/such/url")
    3536          self.assertEqual(
    3537              root.get('{http://www.w3.org/XML/1998/namespace}base'), None)
    3538          root.base = "https://secret/url"
    3539          self.assertEqual(root.base, "https://secret/url")
    3540          self.assertEqual(
    3541              root.get('{http://www.w3.org/XML/1998/namespace}base'),
    3542              "https://secret/url")
    3543
    3544 -    def test_xml_base_attribute(self):
    3545          etree = self.etree
    3546          root = etree.XML(_bytes("<root/>"), base_url="http://no/such/url")
    3547          self.assertEqual(root.base, "http://no/such/url")
    3548          self.assertEqual(
    3549              root.get('{http://www.w3.org/XML/1998/namespace}base'), None)
    3550          root.set('{http://www.w3.org/XML/1998/namespace}base',
    3551                   "https://secret/url")
    3552          self.assertEqual(root.base, "https://secret/url")
    3553          self.assertEqual(
    3554              root.get('{http://www.w3.org/XML/1998/namespace}base'),
    3555              "https://secret/url")
    3556
    3557 -    def test_html_base(self):
    3558          etree = self.etree
    3559          root = etree.HTML(_bytes("<html><body></body></html>"),
    3560                            base_url="http://no/such/url")
    3561          self.assertEqual(root.base, "http://no/such/url")
    3562
    3563 -    def test_html_base_tag(self):
    3564          etree = self.etree
    3565          root = etree.HTML(_bytes('<html><head><base href="http://no/such/url"></head></html>'))
    3566          self.assertEqual(root.base, "http://no/such/url")
    3567
    3568 -    def test_parse_fileobject_unicode(self):
    3569          # parse from a file object that returns unicode strings
    3570          f = LargeFileLikeUnicode()
    3571          tree = self.etree.parse(f)
    3572          root = tree.getroot()
    3573          self.assertTrue(root.tag.endswith('root'))
    3574
    3575 -    def test_dtd_io(self):
    3576          # check that DTDs that go in also go back out
    3577          xml = _bytes('''\
    3578          <!DOCTYPE test SYSTEM "test.dtd" [
    3579            <!ENTITY entity "tasty">
    3580            <!ELEMENT test (a)>
    3581            <!ELEMENT a (#PCDATA)>
    3582          ]>
    3583          <test><a>test-test</a></test>\
    3584          ''')
    3585          tree = self.etree.parse(BytesIO(xml))
    3586          self.assertEqual(self.etree.tostring(tree).replace(_bytes(" "), _bytes("")),
    3587                           xml.replace(_bytes(" "), _bytes("")))
    3588
    3589 -    def test_byte_zero(self):
    3590          Element = self.etree.Element
    3591
    3592          a = Element('a')
    3593          self.assertRaises(ValueError, setattr, a, "text", 'ha\0ho')
    3594          self.assertRaises(ValueError, setattr, a, "tail", 'ha\0ho')
    3595
    3596          self.assertRaises(ValueError, Element, 'ha\0ho')
    3597
    3598 -    def test_unicode_byte_zero(self):
    3599          Element = self.etree.Element
    3600
    3601          a = Element('a')
    3602          self.assertRaises(ValueError, setattr, a, "text",
    3603                            _str('ha\0ho'))
    3604          self.assertRaises(ValueError, setattr, a, "tail",
    3605                            _str('ha\0ho'))
    3606
    3607          self.assertRaises(ValueError, Element,
    3608                            _str('ha\0ho'))
    3609
    3610 -    def test_byte_invalid(self):
    3611          Element = self.etree.Element
    3612
    3613          a = Element('a')
    3614          self.assertRaises(ValueError, setattr, a, "text", 'ha\x07ho')
    3615          self.assertRaises(ValueError, setattr, a, "text", 'ha\x02ho')
    3616
    3617          self.assertRaises(ValueError, setattr, a, "tail", 'ha\x07ho')
    3618          self.assertRaises(ValueError, setattr, a, "tail", 'ha\x02ho')
    3619
    3620          self.assertRaises(ValueError, Element, 'ha\x07ho')
    3621          self.assertRaises(ValueError, Element, 'ha\x02ho')
    3622
    3623 -    def test_unicode_byte_invalid(self):
    3624          Element = self.etree.Element
    3625
    3626          a = Element('a')
    3627          self.assertRaises(ValueError, setattr, a, "text",
    3628                            _str('ha\x07ho'))
    3629          self.assertRaises(ValueError, setattr, a, "text",
    3630                            _str('ha\x02ho'))
    3631
    3632          self.assertRaises(ValueError, setattr, a, "tail",
    3633                            _str('ha\x07ho'))
    3634          self.assertRaises(ValueError, setattr, a, "tail",
    3635                            _str('ha\x02ho'))
    3636
    3637          self.assertRaises(ValueError, Element,
    3638                            _str('ha\x07ho'))
    3639          self.assertRaises(ValueError, Element,
    3640                            _str('ha\x02ho'))
    3641
    3642 -    def test_unicode_byte_invalid_sequence(self):
    3643          Element = self.etree.Element
    3644
    3645          a = Element('a')
    3646          self.assertRaises(ValueError, setattr, a, "text",
    3647                            _str('ha\u1234\x07ho'))
    3648          self.assertRaises(ValueError, setattr, a, "text",
    3649                            _str('ha\u1234\x02ho'))
    3650
    3651          self.assertRaises(ValueError, setattr, a, "tail",
    3652                            _str('ha\u1234\x07ho'))
    3653          self.assertRaises(ValueError, setattr, a, "tail",
    3654                            _str('ha\u1234\x02ho'))
    3655
    3656          self.assertRaises(ValueError, Element,
    3657                            _str('ha\u1234\x07ho'))
    3658          self.assertRaises(ValueError, Element,
    3659                            _str('ha\u1234\x02ho'))
    3660
    3661 -    def test_encoding_tostring_utf16(self):
    3662          # ElementTree fails to serialize this
    3663          tostring = self.etree.tostring
    3664          Element = self.etree.Element
    3665          SubElement = self.etree.SubElement
    3666
    3667          a = Element('a')
    3668          b = SubElement(a, 'b')
    3669          c = SubElement(a, 'c')
    3670
    3671          result = tostring(a, encoding='UTF-16')
    3672          self.assertEqual(_bytes('<a><b></b><c></c></a>'),
    3673                            canonicalize(result))
    3674
    3675 -    def test_tostring_none(self):
    3676          # ElementTree raises an AssertionError here
    3677          tostring = self.etree.tostring
    3678          self.assertRaises(TypeError, self.etree.tostring, None)
    3679
    3680 -    def test_tostring_pretty(self):
    3681          tostring = self.etree.tostring
    3682          Element = self.etree.Element
    3683          SubElement = self.etree.SubElement
    3684
    3685          a = Element('a')
    3686          b = SubElement(a, 'b')
    3687          c = SubElement(a, 'c')
    3688
    3689          result = tostring(a)
    3690          self.assertEqual(result, _bytes("<a><b/><c/></a>"))
    3691
    3692          result = tostring(a, pretty_print=False)
    3693          self.assertEqual(result, _bytes("<a><b/><c/></a>"))
    3694
    3695          result = tostring(a, pretty_print=True)
    3696          self.assertEqual(result, _bytes("<a>\n  <b/>\n  <c/>\n</a>\n"))
    3697
    3698 -    def test_tostring_with_tail(self):
    3699          tostring = self.etree.tostring
    3700          Element = self.etree.Element
    3701          SubElement = self.etree.SubElement
    3702
    3703          a = Element('a')
    3704          a.tail = "aTAIL"
    3705          b = SubElement(a, 'b')
    3706          b.tail = "bTAIL"
    3707          c = SubElement(a, 'c')
    3708
    3709          result = tostring(a)
    3710          self.assertEqual(result, _bytes("<a><b/>bTAIL<c/></a>aTAIL"))
    3711
    3712          result = tostring(a, with_tail=False)
    3713          self.assertEqual(result, _bytes("<a><b/>bTAIL<c/></a>"))
    3714
    3715          result = tostring(a, with_tail=True)
    3716          self.assertEqual(result, _bytes("<a><b/>bTAIL<c/></a>aTAIL"))
    3717
    3718 -    def test_tostring_method_html_with_tail(self):
    3719          tostring = self.etree.tostring
    3720          html = self.etree.fromstring(
    3721              '<html><body>'
    3722              '<div><p>Some text<i>\r\n</i></p></div>\r\n'
    3723              '</body></html>',
    3724              parser=self.etree.HTMLParser())
    3725          self.assertEqual(html.tag, 'html')
    3726          div = html.find('.//div')
    3727          self.assertEqual(div.tail, '\r\n')
    3728          result = tostring(div, method='html')
    3729          self.assertEqual(
    3730              result,
    3731              _bytes("<div><p>Some text<i>\r\n</i></p></div>\r\n"))
    3732          result = tostring(div, method='html', with_tail=True)
    3733          self.assertEqual(
    3734              result,
    3735              _bytes("<div><p>Some text<i>\r\n</i></p></div>\r\n"))
    3736          result = tostring(div, method='html', with_tail=False)
    3737          self.assertEqual(
    3738              result,
    3739              _bytes("<div><p>Some text<i>\r\n</i></p></div>"))
    3740
    3741 -    def test_standalone(self):
    3742          tostring = self.etree.tostring
    3743          XML = self.etree.XML
    3744          ElementTree = self.etree.ElementTree
    3745          Element = self.etree.Element
    3746
    3747          tree = Element("root").getroottree()
    3748          self.assertEqual(None, tree.docinfo.standalone)
    3749
    3750          tree = XML(_bytes("<root/>")).getroottree()
    3751          self.assertEqual(None, tree.docinfo.standalone)
    3752
    3753          tree = XML(_bytes(
    3754              "<?xml version='1.0' encoding='ASCII' standalone='yes'?>\n<root/>"
    3755              )).getroottree()
    3756          self.assertEqual(True, tree.docinfo.standalone)
    3757
    3758          tree = XML(_bytes(
    3759              "<?xml version='1.0' encoding='ASCII' standalone='no'?>\n<root/>"
    3760              )).getroottree()
    3761          self.assertEqual(False, tree.docinfo.standalone)
    3762
    3763 -    def test_tostring_standalone(self):
    3764          tostring = self.etree.tostring
    3765          XML = self.etree.XML
    3766          ElementTree = self.etree.ElementTree
    3767
    3768          root = XML(_bytes("<root/>"))
    3769
    3770          tree = ElementTree(root)
    3771          self.assertEqual(None, tree.docinfo.standalone)
    3772
    3773          result = tostring(root, xml_declaration=True, encoding="ASCII")
    3774          self.assertEqual(result, _bytes(
    3775              "<?xml version='1.0' encoding='ASCII'?>\n<root/>"))
    3776
    3777          result = tostring(root, xml_declaration=True, encoding="ASCII",
    3778                            standalone=True)
    3779          self.assertEqual(result, _bytes(
    3780              "<?xml version='1.0' encoding='ASCII' standalone='yes'?>\n<root/>"))
    3781
    3782          tree = ElementTree(XML(result))
    3783          self.assertEqual(True, tree.docinfo.standalone)
    3784
    3785          result = tostring(root, xml_declaration=True, encoding="ASCII",
    3786                            standalone=False)
    3787          self.assertEqual(result, _bytes(
    3788              "<?xml version='1.0' encoding='ASCII' standalone='no'?>\n<root/>"))
    3789
    3790          tree = ElementTree(XML(result))
    3791          self.assertEqual(False, tree.docinfo.standalone)
    3792
    3793 -    def test_tostring_standalone_in_out(self):
    3794          tostring = self.etree.tostring
    3795          XML = self.etree.XML
    3796          ElementTree = self.etree.ElementTree
    3797
    3798          root = XML(_bytes(
    3799              "<?xml version='1.0' encoding='UTF-8' standalone='yes'?>\n<root/>"))
    3800
    3801          tree = ElementTree(root)
    3802          self.assertEqual(True, tree.docinfo.standalone)
    3803
    3804          result = tostring(root, xml_declaration=True, encoding="ASCII")
    3805          self.assertEqual(result, _bytes(
    3806              "<?xml version='1.0' encoding='ASCII'?>\n<root/>"))
    3807
    3808          result = tostring(root, xml_declaration=True, encoding="ASCII",
    3809                            standalone=True)
    3810          self.assertEqual(result, _bytes(
    3811              "<?xml version='1.0' encoding='ASCII' standalone='yes'?>\n<root/>"))
    3812
    3813 -    def test_tostring_method_text_encoding(self):
    3814          tostring = self.etree.tostring
    3815          Element = self.etree.Element
    3816          SubElement = self.etree.SubElement
    3817
    3818          a = Element('a')
    3819          a.text = "A"
    3820          a.tail = "tail"
    3821          b = SubElement(a, 'b')
    3822          b.text = "B"
    3823          b.tail = _str("Søk på nettet")
    3824          c = SubElement(a, 'c')
    3825          c.text = "C"
    3826
    3827          result = tostring(a, method="text", encoding="UTF-16")
    3828
    3829          self.assertEqual(_str('ABSøk på nettetCtail').encode("UTF-16"),
    3830                            result)
    3831
    3832 -    def test_tostring_method_text_unicode(self):
    3833          tostring = self.etree.tostring
    3834          Element = self.etree.Element
    3835          SubElement = self.etree.SubElement
    3836
    3837          a = Element('a')
    3838          a.text = _str('Søk på nettetA')
    3839          a.tail = "tail"
    3840          b = SubElement(a, 'b')
    3841          b.text = "B"
    3842          b.tail = _str('Søk på nettetB')
    3843          c = SubElement(a, 'c')
    3844          c.text = "C"
    3845
    3846          self.assertRaises(UnicodeEncodeError,
    3847                            tostring, a, method="text")
    3848
    3849          self.assertEqual(
    3850              _str('Søk på nettetABSøk på nettetBCtail').encode('utf-8'),
    3851              tostring(a, encoding="UTF-8", method="text"))
    3852
    3853 -    def test_tounicode(self):
    3854          tounicode = self.etree.tounicode
    3855          Element = self.etree.Element
    3856          SubElement = self.etree.SubElement
    3857
    3858          a = Element('a')
    3859          b = SubElement(a, 'b')
    3860          c = SubElement(a, 'c')
    3861
    3862          self.assertTrue(isinstance(tounicode(a), _unicode))
    3863          self.assertEqual(_bytes('<a><b></b><c></c></a>'),
    3864                            canonicalize(tounicode(a)))
    3865
    3866 -    def test_tounicode_element(self):
    3867          tounicode = self.etree.tounicode
    3868          Element = self.etree.Element
    3869          SubElement = self.etree.SubElement
    3870
    3871          a = Element('a')
    3872          b = SubElement(a, 'b')
    3873          c = SubElement(a, 'c')
    3874          d = SubElement(c, 'd')
    3875          self.assertTrue(isinstance(tounicode(b), _unicode))
    3876          self.assertTrue(isinstance(tounicode(c), _unicode))
    3877          self.assertEqual(_bytes('<b></b>'),
    3878                            canonicalize(tounicode(b)))
    3879          self.assertEqual(_bytes('<c><d></d></c>'),
    3880                            canonicalize(tounicode(c)))
    3881
    3882 -    def test_tounicode_none(self):
    3883          tounicode = self.etree.tounicode
    3884          self.assertRaises(TypeError, self.etree.tounicode, None)
    3885
    3886 -    def test_tounicode_element_tail(self):
    3887          tounicode = self.etree.tounicode
    3888          Element = self.etree.Element
    3889          SubElement = self.etree.SubElement
    3890
    3891          a = Element('a')
    3892          b = SubElement(a, 'b')
    3893          c = SubElement(a, 'c')
    3894          d = SubElement(c, 'd')
    3895          b.tail = 'Foo'
    3896
    3897          self.assertTrue(isinstance(tounicode(b), _unicode))
    3898          self.assertTrue(tounicode(b) == '<b/>Foo' or
    3899                       tounicode(b) == '<b />Foo')
    3900
    3901 -    def test_tounicode_pretty(self):
    3902          tounicode = self.etree.tounicode
    3903          Element = self.etree.Element
    3904          SubElement = self.etree.SubElement
    3905
    3906          a = Element('a')
    3907          b = SubElement(a, 'b')
    3908          c = SubElement(a, 'c')
    3909
    3910          result = tounicode(a)
    3911          self.assertEqual(result, "<a><b/><c/></a>")
    3912
    3913          result = tounicode(a, pretty_print=False)
    3914          self.assertEqual(result, "<a><b/><c/></a>")
    3915
    3916          result = tounicode(a, pretty_print=True)
    3917          self.assertEqual(result, "<a>\n  <b/>\n  <c/>\n</a>\n")
    3918
    3919 -    def test_tostring_unicode(self):
    3920          tostring = self.etree.tostring
    3921          Element = self.etree.Element
    3922          SubElement = self.etree.SubElement
    3923
    3924          a = Element('a')
    3925          b = SubElement(a, 'b')
    3926          c = SubElement(a, 'c')
    3927
    3928          self.assertTrue(isinstance(tostring(a, encoding=_unicode), _unicode))
    3929          self.assertEqual(_bytes('<a><b></b><c></c></a>'),
    3930                            canonicalize(tostring(a, encoding=_unicode)))
    3931
    3932 -    def test_tostring_unicode_element(self):
    3933          tostring = self.etree.tostring
    3934          Element = self.etree.Element
    3935          SubElement = self.etree.SubElement
    3936
    3937          a = Element('a')
    3938          b = SubElement(a, 'b')
    3939          c = SubElement(a, 'c')
    3940          d = SubElement(c, 'd')
    3941          self.assertTrue(isinstance(tostring(b, encoding=_unicode), _unicode))
    3942          self.assertTrue(isinstance(tostring(c, encoding=_unicode), _unicode))
    3943          self.assertEqual(_bytes('<b></b>'),
    3944                            canonicalize(tostring(b, encoding=_unicode)))
    3945          self.assertEqual(_bytes('<c><d></d></c>'),
    3946                            canonicalize(tostring(c, encoding=_unicode)))
    3947
    3948 -    def test_tostring_unicode_none(self):
    3949          tostring = self.etree.tostring
    3950          self.assertRaises(TypeError, self.etree.tostring,
    3951                            None, encoding=_unicode)
    3952
    3953 -    def test_tostring_unicode_element_tail(self):
    3954          tostring = self.etree.tostring
    3955          Element = self.etree.Element
    3956          SubElement = self.etree.SubElement
    3957
    3958          a = Element('a')
    3959          b = SubElement(a, 'b')
    3960          c = SubElement(a, 'c')
    3961          d = SubElement(c, 'd')
    3962          b.tail = 'Foo'
    3963
    3964          self.assertTrue(isinstance(tostring(b, encoding=_unicode), _unicode))
    3965          self.assertTrue(tostring(b, encoding=_unicode) == '<b/>Foo' or
    3966                       tostring(b, encoding=_unicode) == '<b />Foo')
    3967
    3968 -    def test_tostring_unicode_pretty(self):
    3969          tostring = self.etree.tostring
    3970          Element = self.etree.Element
    3971          SubElement = self.etree.SubElement
    3972
    3973          a = Element('a')
    3974          b = SubElement(a, 'b')
    3975          c = SubElement(a, 'c')
    3976
    3977          result = tostring(a, encoding=_unicode)
    3978          self.assertEqual(result, "<a><b/><c/></a>")
    3979
    3980          result = tostring(a, encoding=_unicode, pretty_print=False)
    3981          self.assertEqual(result, "<a><b/><c/></a>")
    3982
    3983          result = tostring(a, encoding=_unicode, pretty_print=True)
    3984          self.assertEqual(result, "<a>\n  <b/>\n  <c/>\n</a>\n")
    3985
    3986 -    def test_pypy_proxy_collect(self):
    3987          root = etree.Element('parent')
    3988          etree.SubElement(root, 'child')
    3989
    3990          self.assertEqual(len(root), 1)
    3991          self.assertEqual(root[0].tag, 'child')
    3992
    3993          # in PyPy, GC used to kill the Python proxy instance without cleanup
    3994          gc.collect()
    3995          self.assertEqual(len(root), 1)
    3996          self.assertEqual(root[0].tag, 'child')
    3997
    3998 -    def test_element_refcycle(self):
    3999          class SubEl(etree.ElementBase):
    4000              pass
    4001
    4002          el1 = SubEl()
    4003          el2 = SubEl()
    4004          self.assertEqual('SubEl', el1.tag)
    4005          self.assertEqual('SubEl', el2.tag)
    4006          el1.other = el2
    4007          el2.other = el1
    4008
    4009          del el1, el2
    4010          gc.collect()
    4011          # not really testing anything here, but it shouldn't crash
    4012
    4013 -    def test_proxy_collect_siblings(self):
    4014          root = etree.Element('parent')
    4015          c1 = etree.SubElement(root, 'child1')
    4016          c2 = etree.SubElement(root, 'child2')
    4017
    4018          root.remove(c1)
    4019          root.remove(c2)
    4020          c1.addnext(c2)
    4021          del c1
    4022          # trigger deallocation attempt of c1
    4023          c2.getprevious()
    4024          # make sure it wasn't deallocated
    4025          self.assertEqual('child1', c2.getprevious().tag)
    4026
    4027 -    def test_proxy_collect_siblings_text(self):
    4028          root = etree.Element('parent')
    4029          c1 = etree.SubElement(root, 'child1')
    4030          c2 = etree.SubElement(root, 'child2')
    4031
    4032          root.remove(c1)
    4033          root.remove(c2)
    4034          c1.addnext(c2)
    4035          c1.tail = 'abc'
    4036          c2.tail = 'xyz'
    4037          del c1
    4038          # trigger deallocation attempt of c1
    4039          c2.getprevious()
    4040          # make sure it wasn't deallocated
    4041          self.assertEqual('child1', c2.getprevious().tag)
    4042          self.assertEqual('abc', c2.getprevious().tail)
    4043
    4044      # helper methods
    4045
    4046 -    def _writeElement(self, element, encoding='us-ascii', compression=0):
    4047          """Write out element for comparison.
    4048          """
    4049          ElementTree = self.etree.ElementTree
    4050          f = BytesIO()
    4051          tree = ElementTree(element=element)
    4052          tree.write(f, encoding=encoding, compression=compression)
    4053          data = f.getvalue()
    4054          if compression:
    4055              data = zlib.decompress(data)
    4056          return canonicalize(data)
    4057
    4058
    4059 -class _XIncludeTestCase(HelperTestCase):
    4060 -    def test_xinclude_text(self):
    4061          filename = fileInTestDir('test_broken.xml')
    4062          root = etree.XML(_bytes('''\
    4063          <doc xmlns:xi="http://www.w3.org/2001/XInclude">
    4064            <xi:include href="%s" parse="text"/>
    4065          </doc>
    4066          ''' % path2url(filename)))
    4067          old_text = root.text
    4068          content = read_file(filename)
    4069          old_tail = root[0].tail
    4070
    4071          self.include( etree.ElementTree(root) )
    4072          self.assertEqual(old_text + content + old_tail,
    4073                            root.text)
    4074
    4075 -    def test_xinclude(self):
    4076          tree = etree.parse(fileInTestDir('include/test_xinclude.xml'))
    4077          self.assertNotEqual(
    4078              'a',
    4079              tree.getroot()[1].tag)
    4080          # process xincludes
    4081          self.include( tree )
    4082          # check whether we find it replaced with included data
    4083          self.assertEqual(
    4084              'a',
    4085              tree.getroot()[1].tag)
    4086
    4087 -    def test_xinclude_resolver(self):
    4088          class res(etree.Resolver):
    4089              include_text = read_file(fileInTestDir('test.xml'))
    4090              called = {}
    4091              def resolve(self, url, id, context):
    4092                  if url.endswith(".dtd"):
    4093                      self.called["dtd"] = True
    4094                      return self.resolve_filename(
    4095                          fileInTestDir('test.dtd'), context)
    4096                  elif url.endswith("test_xinclude.xml"):
    4097                      self.called["input"] = True
    4098                      return None # delegate to default resolver
    4099                  else:
    4100                      self.called["include"] = True
    4101                      return self.resolve_string(self.include_text, context)
    4102
    4103          res_instance = res()
    4104          parser = etree.XMLParser(load_dtd = True)
    4105          parser.resolvers.add(res_instance)
    4106
    4107          tree = etree.parse(fileInTestDir('include/test_xinclude.xml'),
    4108                             parser = parser)
    4109
    4110          self.include(tree)
    4111
    4112          called = list(res_instance.called.items())
    4113          called.sort()
    4114          self.assertEqual(
    4115              [("dtd", True), ("include", True), ("input", True)],
    4116              called)
    4117
    4118 -    def test_xinclude_resolver_recursive(self):
    4119          data = textwrap.dedent('''
    4120          <doc xmlns:xi="http://www.w3.org/2001/XInclude">
    4121          <foo/>
    4122          <xi:include href="./test.xml" />
    4123          </doc>
    4124          ''')
    4125
    4126          class Resolver(etree.Resolver):
    4127              called = {}
    4128
    4129              def resolve(self, url, id, context):
    4130                  if url.endswith("test_xinclude.xml"):
    4131                      assert not self.called.get("input")
    4132                      self.called["input"] = True
    4133                      return None  # delegate to default resolver
    4134                  elif url.endswith('/test5.xml'):
    4135                      assert not self.called.get("DONE")
    4136                      self.called["DONE"] = True
    4137                      return self.resolve_string('<DONE/>', context)
    4138                  else:
    4139                      _, filename = url.rsplit('/', 1)
    4140                      assert not self.called.get(filename)
    4141                      self.called[filename] = True
    4142                      next_data = data.replace(
    4143                          'test.xml', 'test%d.xml' % len(self.called))
    4144                      return self.resolve_string(next_data, context)
    4145
    4146          res_instance = Resolver()
    4147          parser = etree.XMLParser(load_dtd=True)
    4148          parser.resolvers.add(res_instance)
    4149
    4150          tree = etree.parse(fileInTestDir('include/test_xinclude.xml'),
    4151                             parser=parser)
    4152
    4153          self.include(tree)
    4154
    4155          called = list(res_instance.called.items())
    4156          called.sort()
    4157          self.assertEqual(
    4158              [("DONE", True), ("input", True), ("test.xml", True),
    4159               ("test2.xml", True), ("test3.xml", True), ("test4.xml", True)],
    4160              called)
    4161
    4162
    4163 -class ETreeXIncludeTestCase(_XIncludeTestCase):
    4164 -    def include(self, tree):
    4165          tree.xinclude()
    4166
    4167
    4168 -class ElementIncludeTestCase(_XIncludeTestCase):
    4169      from lxml import ElementInclude
    4170 -    def include(self, tree):
    4171          self.ElementInclude.include(tree.getroot())
    4172
    4173
    4174 -class ETreeC14NTestCase(HelperTestCase):
    4175 -    def test_c14n(self):
    4176          tree = self.parse(_bytes('<a><b/></a>'))
    4177          f = BytesIO()
    4178          tree.write_c14n(f)
    4179          s = f.getvalue()
    4180          self.assertEqual(_bytes('<a><b></b></a>'),
    4181                            s)
    4182
    4183 -    def test_c14n_gzip(self):
    4184          tree = self.parse(_bytes('<a>'+'<b/>'*200+'</a>'))
    4185          f = BytesIO()
    4186          tree.write_c14n(f, compression=9)
    4187          with closing(gzip.GzipFile(fileobj=BytesIO(f.getvalue()))) as gzfile:
    4188              s = gzfile.read()
    4189          self.assertEqual(_bytes('<a>'+'<b></b>'*200+'</a>'),
    4190                            s)
    4191
    4192 -    def test_c14n_file(self):
    4193          tree = self.parse(_bytes('<a><b/></a>'))
    4194          with tmpfile() as filename:
    4195              tree.write_c14n(filename)
    4196              data = read_file(filename, 'rb')
    4197          self.assertEqual(_bytes('<a><b></b></a>'),
    4198                            data)
    4199
    4200 -    def test_c14n_file_gzip(self):
    4201          tree = self.parse(_bytes('<a>'+'<b/>'*200+'</a>'))
    4202          with tmpfile() as filename:
    4203              tree.write_c14n(filename, compression=9)
    4204              with closing(gzip.open(filename, 'rb')) as f:
    4205                  data = f.read()
    4206          self.assertEqual(_bytes('<a>'+'<b></b>'*200+'</a>'),
    4207                            data)
    4208
    4209 -    def test_c14n_with_comments(self):
    4210          tree = self.parse(_bytes('<!--hi--><a><!--ho--><b/></a><!--hu-->'))
    4211          f = BytesIO()
    4212          tree.write_c14n(f)
    4213          s = f.getvalue()
    4214          self.assertEqual(_bytes('<!--hi-->\n<a><!--ho--><b></b></a>\n<!--hu-->'),
    4215                            s)
    4216          f = BytesIO()
    4217          tree.write_c14n(f, with_comments=True)
    4218          s = f.getvalue()
    4219          self.assertEqual(_bytes('<!--hi-->\n<a><!--ho--><b></b></a>\n<!--hu-->'),
    4220                            s)
    4221          f = BytesIO()
    4222          tree.write_c14n(f, with_comments=False)
    4223          s = f.getvalue()
    4224          self.assertEqual(_bytes('<a><b></b></a>'),
    4225                            s)
    4226
    4227 -    def test_c14n_tostring_with_comments(self):
    4228          tree = self.parse(_bytes('<!--hi--><a><!--ho--><b/></a><!--hu-->'))
    4229          s = etree.tostring(tree, method='c14n')
    4230          self.assertEqual(_bytes('<!--hi-->\n<a><!--ho--><b></b></a>\n<!--hu-->'),
    4231                            s)
    4232          s = etree.tostring(tree, method='c14n', with_comments=True)
    4233          self.assertEqual(_bytes('<!--hi-->\n<a><!--ho--><b></b></a>\n<!--hu-->'),
    4234                            s)
    4235          s = etree.tostring(tree, method='c14n', with_comments=False)
    4236          self.assertEqual(_bytes('<a><b></b></a>'),
    4237                            s)
    4238
    4239 -    def test_c14n_element_tostring_with_comments(self):
    4240          tree = self.parse(_bytes('<!--hi--><a><!--ho--><b/></a><!--hu-->'))
    4241          s = etree.tostring(tree.getroot(), method='c14n')
    4242          self.assertEqual(_bytes('<a><!--ho--><b></b></a>'),
    4243                            s)
    4244          s = etree.tostring(tree.getroot(), method='c14n', with_comments=True)
    4245          self.assertEqual(_bytes('<a><!--ho--><b></b></a>'),
    4246                            s)
    4247          s = etree.tostring(tree.getroot(), method='c14n', with_comments=False)
    4248          self.assertEqual(_bytes('<a><b></b></a>'),
    4249                            s)
    4250
    4251 -    def test_c14n_exclusive(self):
    4252          tree = self.parse(_bytes(
    4253                  '<a xmlns="http://abc" xmlns:y="http://bcd" xmlns:z="http://cde"><z:b/></a>'))
    4254          f = BytesIO()
    4255          tree.write_c14n(f)
    4256          s = f.getvalue()
    4257          self.assertEqual(_bytes('<a xmlns="http://abc" xmlns:y="http://bcd" xmlns:z="http://cde"><z:b></z:b></a>'),
    4258                            s)
    4259          f = BytesIO()
    4260          tree.write_c14n(f, exclusive=False)
    4261          s = f.getvalue()
    4262          self.assertEqual(_bytes('<a xmlns="http://abc" xmlns:y="http://bcd" xmlns:z="http://cde"><z:b></z:b></a>'),
    4263                            s)
    4264          f = BytesIO()
    4265          tree.write_c14n(f, exclusive=True)
    4266          s = f.getvalue()
    4267          self.assertEqual(_bytes('<a xmlns="http://abc"><z:b xmlns:z="http://cde"></z:b></a>'),
    4268                            s)
    4269
    4270          f = BytesIO()
    4271          tree.write_c14n(f, exclusive=True, inclusive_ns_prefixes=['z'])
    4272          s = f.getvalue()
    4273          self.assertEqual(_bytes('<a xmlns="http://abc" xmlns:z="http://cde"><z:b></z:b></a>'),
    4274                            s)
    4275
    4276 -    def test_c14n_tostring_exclusive(self):
    4277          tree = self.parse(_bytes(
    4278                  '<a xmlns="http://abc" xmlns:y="http://bcd" xmlns:z="http://cde"><z:b/></a>'))
    4279          s = etree.tostring(tree, method='c14n')
    4280          self.assertEqual(_bytes('<a xmlns="http://abc" xmlns:y="http://bcd" xmlns:z="http://cde"><z:b></z:b></a>'),
    4281                            s)
    4282          s = etree.tostring(tree, method='c14n', exclusive=False)
    4283          self.assertEqual(_bytes('<a xmlns="http://abc" xmlns:y="http://bcd" xmlns:z="http://cde"><z:b></z:b></a>'),
    4284                            s)
    4285          s = etree.tostring(tree, method='c14n', exclusive=True)
    4286          self.assertEqual(_bytes('<a xmlns="http://abc"><z:b xmlns:z="http://cde"></z:b></a>'),
    4287                            s)
    4288
    4289          s = etree.tostring(tree, method='c14n', exclusive=True, inclusive_ns_prefixes=['y'])
    4290          self.assertEqual(_bytes('<a xmlns="http://abc" xmlns:y="http://bcd"><z:b xmlns:z="http://cde"></z:b></a>'),
    4291                            s)
    4292
    4293 -    def test_c14n_element_tostring_exclusive(self):
    4294          tree = self.parse(_bytes(
    4295                  '<a xmlns="http://abc" xmlns:y="http://bcd" xmlns:z="http://cde"><z:b/></a>'))
    4296          s = etree.tostring(tree.getroot(), method='c14n')
    4297          self.assertEqual(_bytes('<a xmlns="http://abc" xmlns:y="http://bcd" xmlns:z="http://cde"><z:b></z:b></a>'),
    4298                            s)
    4299          s = etree.tostring(tree.getroot(), method='c14n', exclusive=False)
    4300          self.assertEqual(_bytes('<a xmlns="http://abc" xmlns:y="http://bcd" xmlns:z="http://cde"><z:b></z:b></a>'),
    4301                            s)
    4302          s = etree.tostring(tree.getroot(), method='c14n', exclusive=True)
    4303          self.assertEqual(_bytes('<a xmlns="http://abc"><z:b xmlns:z="http://cde"></z:b></a>'),
    4304                            s)
    4305
    4306          s = etree.tostring(tree.getroot()[0], method='c14n', exclusive=False)
    4307          self.assertEqual(_bytes('<z:b xmlns="http://abc" xmlns:y="http://bcd" xmlns:z="http://cde"></z:b>'),
    4308                            s)
    4309          s = etree.tostring(tree.getroot()[0], method='c14n', exclusive=True)
    4310          self.assertEqual(_bytes('<z:b xmlns:z="http://cde"></z:b>'),
    4311                            s)
    4312
    4313          s = etree.tostring(tree.getroot()[0], method='c14n', exclusive=True, inclusive_ns_prefixes=['y'])
    4314          self.assertEqual(_bytes('<z:b xmlns:y="http://bcd" xmlns:z="http://cde"></z:b>'),
    4315                            s)
    4316
    4317 -    def test_c14n_tostring_inclusive_ns_prefixes(self):
    4318          """ Regression test to fix memory allocation issues (use 3+ inclusive NS spaces)"""
    4319          tree = self.parse(_bytes(
    4320                  '<a xmlns:x="http://abc" xmlns:y="http://bcd" xmlns:z="http://cde"><z:b/></a>'))
    4321
    4322          s = etree.tostring(tree, method='c14n', exclusive=True, inclusive_ns_prefixes=['x', 'y', 'z'])
    4323          self.assertEqual(_bytes('<a xmlns:x="http://abc" xmlns:y="http://bcd" xmlns:z="http://cde"><z:b></z:b></a>'),
    4324                            s)
    4325
    4326
    4327 -class ETreeWriteTestCase(HelperTestCase):
    4328 -    def test_write(self):
    4329          tree = self.parse(_bytes('<a><b/></a>'))
    4330          f = BytesIO()
    4331          tree.write(f)
    4332          s = f.getvalue()
    4333          self.assertEqual(_bytes('<a><b/></a>'),
    4334                            s)
    4335
    4336 -    def test_write_doctype(self):
    4337          tree = self.parse(_bytes('<a><b/></a>'))
    4338          f = BytesIO()
    4339          tree.write(f, doctype='HUHU')
    4340          s = f.getvalue()
    4341          self.assertEqual(_bytes('HUHU\n<a><b/></a>'),
    4342                            s)
    4343
    4344 -    def test_write_gzip(self):
    4345          tree = self.parse(_bytes('<a>'+'<b/>'*200+'</a>'))
    4346          f = BytesIO()
    4347          tree.write(f, compression=9)
    4348          with closing(gzip.GzipFile(fileobj=BytesIO(f.getvalue()))) as gzfile:
    4349              s = gzfile.read()
    4350          self.assertEqual(_bytes('<a>'+'<b/>'*200+'</a>'),
    4351                            s)
    4352
    4353 -    def test_write_gzip_doctype(self):
    4354          tree = self.parse(_bytes('<a>'+'<b/>'*200+'</a>'))
    4355          f = BytesIO()
    4356          tree.write(f, compression=9, doctype='<!DOCTYPE a>')
    4357          with closing(gzip.GzipFile(fileobj=BytesIO(f.getvalue()))) as gzfile:
    4358              s = gzfile.read()
    4359          self.assertEqual(_bytes('<!DOCTYPE a>\n<a>'+'<b/>'*200+'</a>'),
    4360                            s)
    4361
    4362 -    def test_write_gzip_level(self):
    4363          tree = self.parse(_bytes('<a>'+'<b/>'*200+'</a>'))
    4364          f = BytesIO()
    4365          tree.write(f, compression=0)
    4366          s0 = f.getvalue()
    4367
    4368          f = BytesIO()
    4369          tree.write(f)
    4370          self.assertEqual(f.getvalue(), s0)
    4371
    4372          f = BytesIO()
    4373          tree.write(f, compression=1)
    4374          s = f.getvalue()
    4375          self.assertTrue(len(s) <= len(s0))
    4376          with closing(gzip.GzipFile(fileobj=BytesIO(s))) as gzfile:
    4377              s1 = gzfile.read()
    4378
    4379          f = BytesIO()
    4380          tree.write(f, compression=9)
    4381          s = f.getvalue()
    4382          self.assertTrue(len(s) <= len(s0))
    4383          with closing(gzip.GzipFile(fileobj=BytesIO(s))) as gzfile:
    4384              s9 = gzfile.read()
    4385
    4386          self.assertEqual(_bytes('<a>'+'<b/>'*200+'</a>'),
    4387                            s0)
    4388          self.assertEqual(_bytes('<a>'+'<b/>'*200+'</a>'),
    4389                            s1)
    4390          self.assertEqual(_bytes('<a>'+'<b/>'*200+'</a>'),
    4391                            s9)
    4392
    4393 -    def test_write_file(self):
    4394          tree = self.parse(_bytes('<a><b/></a>'))
    4395          with tmpfile() as filename:
    4396              tree.write(filename)
    4397              data = read_file(filename, 'rb')
    4398          self.assertEqual(_bytes('<a><b/></a>'),
    4399                            data)
    4400
    4401 -    def test_write_file_gzip(self):
    4402          tree = self.parse(_bytes('<a>'+'<b/>'*200+'</a>'))
    4403          with tmpfile() as filename:
    4404              tree.write(filename, compression=9)
    4405              with closing(gzip.open(filename, 'rb')) as f:
    4406                  data = f.read()
    4407          self.assertEqual(_bytes('<a>'+'<b/>'*200+'</a>'),
    4408                            data)
    4409
    4410 -    def test_write_file_gzip_parse(self):
    4411          tree = self.parse(_bytes('<a>'+'<b/>'*200+'</a>'))
    4412          with tmpfile() as filename:
    4413              tree.write(filename, compression=9)
    4414              data = etree.tostring(etree.parse(filename))
    4415          self.assertEqual(_bytes('<a>'+'<b/>'*200+'</a>'),
    4416                            data)
    4417
    4418 -    def test_write_file_gzipfile_parse(self):
    4419          tree = self.parse(_bytes('<a>'+'<b/>'*200+'</a>'))
    4420          with tmpfile() as filename:
    4421              tree.write(filename, compression=9)
    4422              with closing(gzip.GzipFile(filename)) as f:
    4423                  data = etree.tostring(etree.parse(f))
    4424          self.assertEqual(_bytes('<a>'+'<b/>'*200+'</a>'),
    4425                            data)
    4426
    4427
    4428 -class ETreeErrorLogTest(HelperTestCase):
    4429      etree = etree
    4430
    4431 -    def test_parse_error_logging(self):
    4432          parse = self.etree.parse
    4433          f = BytesIO('<a><b></c></b></a>')
    4434          self.etree.clear_error_log()
    4435          try:
    4436              parse(f)
    4437              logs = None
    4438          except SyntaxError:
    4439              e = sys.exc_info()[1]
    4440              logs = e.error_log
    4441          f.close()
    4442          self.assertTrue([ log for log in logs
    4443                         if 'mismatch' in log.message ])
    4444          self.assertTrue([ log for log in logs
    4445                         if 'PARSER'   in log.domain_name])
    4446          self.assertTrue([ log for log in logs
    4447                         if 'ERR_TAG_NAME_MISMATCH' in log.type_name ])
    4448          self.assertTrue([ log for log in logs
    4449                         if 1 == log.line ])
    4450          self.assertTrue([ log for log in logs
    4451                         if 15 == log.column ])
    4452
    4453 -    def _test_python_error_logging(self):
    4454          """This can't really be tested as long as there isn't a way to
    4455          reset the logging setup ...
    4456          """
    4457          parse = self.etree.parse
    4458
    4459          messages = []
    4460          class Logger(self.etree.PyErrorLog):
    4461              def log(self, entry, message, *args):
    4462                  messages.append(message)
    4463
    4464          self.etree.use_global_python_log(Logger())
    4465          f = BytesIO('<a><b></c></b></a>')
    4466          try:
    4467              parse(f)
    4468          except SyntaxError:
    4469              pass
    4470          f.close()
    4471
    4472          self.assertTrue([ message for message in messages
    4473                         if 'mismatch' in message ])
    4474          self.assertTrue([ message for message in messages
    4475                         if ':PARSER:'   in message])
    4476          self.assertTrue([ message for message in messages
    4477                         if ':ERR_TAG_NAME_MISMATCH:' in message ])
    4478          self.assertTrue([ message for message in messages
    4479                         if ':1:15:' in message ])
    4480
    4481
    4482 -class XMLPullParserTest(unittest.TestCase):
    4483      etree = etree
    4484
    4485 -    def assert_event_tags(self, events, expected):
    4486          self.assertEqual([(action, elem.tag) for action, elem in events],
    4487                           expected)
    4488
    4489 -    def test_pull_from_simple_target(self):
    4490          class Target(object):
    4491              def start(self, tag, attrib):
    4492                  return 'start(%s)' % tag
    4493              def end(self, tag):
    4494                  return 'end(%s)' % tag
    4495              def close(self):
    4496                  return 'close()'
    4497
    4498          parser = self.etree.XMLPullParser(target=Target())
    4499          events = parser.read_events()
    4500
    4501          parser.feed('<root><element>')
    4502          self.assertFalse(list(events))
    4503          self.assertFalse(list(events))
    4504          parser.feed('</element><child>')
    4505          self.assertEqual([('end', 'end(element)')], list(events))
    4506          parser.feed('</child>')
    4507          self.assertEqual([('end', 'end(child)')], list(events))
    4508          parser.feed('</root>')
    4509          self.assertEqual([('end', 'end(root)')], list(events))
    4510          self.assertFalse(list(events))
    4511          self.assertEqual('close()', parser.close())
    4512
    4513 -    def test_pull_from_simple_target_start_end(self):
    4514          class Target(object):
    4515              def start(self, tag, attrib):
    4516                  return 'start(%s)' % tag
    4517              def end(self, tag):
    4518                  return 'end(%s)' % tag
    4519              def close(self):
    4520                  return 'close()'
    4521
    4522          parser = self.etree.XMLPullParser(
    4523              ['start', 'end'], target=Target())
    4524          events = parser.read_events()
    4525
    4526          parser.feed('<root><element>')
    4527          self.assertEqual(
    4528              [('start', 'start(root)'), ('start', 'start(element)')],
    4529              list(events))
    4530          self.assertFalse(list(events))
    4531          parser.feed('</element><child>')
    4532          self.assertEqual(
    4533              [('end', 'end(element)'), ('start', 'start(child)')],
    4534              list(events))
    4535          parser.feed('</child>')
    4536          self.assertEqual(
    4537              [('end', 'end(child)')],
    4538              list(events))
    4539          parser.feed('</root>')
    4540          self.assertEqual(
    4541              [('end', 'end(root)')],
    4542              list(events))
    4543          self.assertFalse(list(events))
    4544          self.assertEqual('close()', parser.close())
    4545
    4546 -    def test_pull_from_tree_builder(self):
    4547          parser = self.etree.XMLPullParser(
    4548              ['start', 'end'], target=etree.TreeBuilder())
    4549          events = parser.read_events()
    4550
    4551          parser.feed('<root><element>')
    4552          self.assert_event_tags(
    4553              events, [('start', 'root'), ('start', 'element')])
    4554          self.assertFalse(list(events))
    4555          parser.feed('</element><child>')
    4556          self.assert_event_tags(
    4557              events, [('end', 'element'), ('start', 'child')])
    4558          parser.feed('</child>')
    4559          self.assert_event_tags(
    4560              events, [('end', 'child')])
    4561          parser.feed('</root>')
    4562          self.assert_event_tags(
    4563              events, [('end', 'root')])
    4564          self.assertFalse(list(events))
    4565          root = parser.close()
    4566          self.assertEqual('root', root.tag)
    4567
    4568 -    def test_pull_from_tree_builder_subclass(self):
    4569          class Target(etree.TreeBuilder):
    4570              def end(self, tag):
    4571                  el = super(Target, self).end(tag)
    4572                  el.tag += '-huhu'
    4573                  return el
    4574
    4575          parser = self.etree.XMLPullParser(
    4576              ['start', 'end'], target=Target())
    4577          events = parser.read_events()
    4578
    4579          parser.feed('<root><element>')
    4580          self.assert_event_tags(
    4581              events, [('start', 'root'), ('start', 'element')])
    4582          self.assertFalse(list(events))
    4583          parser.feed('</element><child>')
    4584          self.assert_event_tags(
    4585              events, [('end', 'element-huhu'), ('start', 'child')])
    4586          parser.feed('</child>')
    4587          self.assert_event_tags(
    4588              events, [('end', 'child-huhu')])
    4589          parser.feed('</root>')
    4590          self.assert_event_tags(
    4591              events, [('end', 'root-huhu')])
    4592          self.assertFalse(list(events))
    4593          root = parser.close()
    4594          self.assertEqual('root-huhu', root.tag)
    4595
    4596
    4597 -def test_suite():
    4598      suite = unittest.TestSuite()
    4599      suite.addTests([unittest.makeSuite(ETreeOnlyTestCase)])
    4600      suite.addTests([unittest.makeSuite(ETreeXIncludeTestCase)])
    4601      suite.addTests([unittest.makeSuite(ElementIncludeTestCase)])
    4602      suite.addTests([unittest.makeSuite(ETreeC14NTestCase)])
    4603      suite.addTests([unittest.makeSuite(ETreeWriteTestCase)])
    4604      suite.addTests([unittest.makeSuite(ETreeErrorLogTest)])
    4605      suite.addTests([unittest.makeSuite(XMLPullParserTest)])
    4606
    4607      # add original doctests from ElementTree selftest modules
    4608      from . import selftest, selftest2
    4609      suite.addTests(doctest.DocTestSuite(selftest))
    4610      suite.addTests(doctest.DocTestSuite(selftest2))
    4611
    4612      # add doctests
    4613      suite.addTests(doctest.DocTestSuite(etree))
    4614      suite.addTests(
    4615          [make_doctest('../../../doc/tutorial.txt')])
    4616      if sys.version_info >= (2,6):
    4617          # now requires the 'with' statement
    4618          suite.addTests(
    4619              [make_doctest('../../../doc/api.txt')])
    4620      suite.addTests(
    4621          [make_doctest('../../../doc/FAQ.txt')])
    4622      suite.addTests(
    4623          [make_doctest('../../../doc/parsing.txt')])
    4624      suite.addTests(
    4625          [make_doctest('../../../doc/resolvers.txt')])
    4626      return suite
    4627
    4628
    4629  if __name__ == '__main__':
    4630      print('to test use test.py %s' % __file__)
    4631