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 -    def test_entity_parse(self):
    1507          parse = self.etree.parse
    1508          tostring = self.etree.tostring
    1509          parser = self.etree.XMLParser(resolve_entities=False)
    1510          Entity = self.etree.Entity
    1511
    1512          xml = _bytes('<!DOCTYPE doc SYSTEM "test"><doc>&myentity;</doc>')
    1513          tree = parse(BytesIO(xml), parser)
    1514          root = tree.getroot()
    1515          self.assertEqual(root[0].tag, Entity)
    1516          self.assertEqual(root[0].text, "&myentity;")
    1517          self.assertEqual(root[0].tail, None)
    1518          self.assertEqual(root[0].name, "myentity")
    1519
    1520          self.assertEqual(_bytes('<doc>&myentity;</doc>'),
    1521                            tostring(root))
    1522
    1523 -    def test_entity_restructure(self):
    1524          xml = _bytes('''<!DOCTYPE root [ <!ENTITY nbsp "&#160;"> ]>
    1525              <root>
    1526                <child1/>
    1527                <child2/>
    1528                <child3>&nbsp;</child3>
    1529              </root>''')
    1530
    1531          parser = self.etree.XMLParser(resolve_entities=False)
    1532          root = etree.fromstring(xml, parser)
    1533          self.assertEqual([ el.tag for el in root ],
    1534                            ['child1', 'child2', 'child3'])
    1535
    1536          root[0] = root[-1]
    1537          self.assertEqual([ el.tag for el in root ],
    1538                            ['child3', 'child2'])
    1539          self.assertEqual(root[0][0].text, '&nbsp;')
    1540          self.assertEqual(root[0][0].name, 'nbsp')
    1541
    1542 -    def test_entity_append(self):
    1543          Entity = self.etree.Entity
    1544          Element = self.etree.Element
    1545          tostring = self.etree.tostring
    1546
    1547          root = Element("root")
    1548          root.append( Entity("test") )
    1549
    1550          self.assertEqual(root[0].tag, Entity)
    1551          self.assertEqual(root[0].text, "&test;")
    1552          self.assertEqual(root[0].tail, None)
    1553          self.assertEqual(root[0].name, "test")
    1554
    1555          self.assertEqual(_bytes('<root>&test;</root>'),
    1556                            tostring(root))
    1557
    1558 -    def test_entity_values(self):
    1559          Entity = self.etree.Entity
    1560          self.assertEqual(Entity("test").text, '&test;')
    1561          self.assertEqual(Entity("#17683").text, '&#17683;')
    1562          self.assertEqual(Entity("#x1768").text, '&#x1768;')
    1563          self.assertEqual(Entity("#x98AF").text, '&#x98AF;')
    1564
    1565 -    def test_entity_error(self):
    1566          Entity = self.etree.Entity
    1567          self.assertRaises(ValueError, Entity, 'a b c')
    1568          self.assertRaises(ValueError, Entity, 'a,b')
    1569          self.assertRaises(ValueError, Entity, 'a\0b')
    1570          self.assertRaises(ValueError, Entity, '#abc')
    1571          self.assertRaises(ValueError, Entity, '#xxyz')
    1572
    1573 -    def test_cdata(self):
    1574          CDATA = self.etree.CDATA
    1575          Element = self.etree.Element
    1576          tostring = self.etree.tostring
    1577
    1578          root = Element("root")
    1579          root.text = CDATA('test')
    1580
    1581          self.assertEqual('test',
    1582                            root.text)
    1583          self.assertEqual(_bytes('<root><![CDATA[test]]></root>'),
    1584                            tostring(root))
    1585
    1586 -    def test_cdata_tail(self):
    1587          CDATA = self.etree.CDATA
    1588          Element = self.etree.Element
    1589          SubElement = self.etree.SubElement
    1590          tostring = self.etree.tostring
    1591
    1592          root = Element("root")
    1593          child = SubElement(root, 'child')
    1594          child.tail = CDATA('test')
    1595
    1596          self.assertEqual('test', child.tail)
    1597          self.assertEqual(_bytes('<root><child/><![CDATA[test]]></root>'),
    1598                           tostring(root))
    1599
    1600          root = Element("root")
    1601          root.tail = CDATA('test')
    1602
    1603          self.assertEqual('test', root.tail)
    1604          self.assertEqual(_bytes('<root/><![CDATA[test]]>'),
    1605                           tostring(root))
    1606
    1607 -    def test_cdata_type(self):
    1608          CDATA = self.etree.CDATA
    1609          Element = self.etree.Element
    1610          root = Element("root")
    1611
    1612          root.text = CDATA("test")
    1613          self.assertEqual('test', root.text)
    1614
    1615          root.text = CDATA(_str("test"))
    1616          self.assertEqual('test', root.text)
    1617
    1618          self.assertRaises(TypeError, CDATA, 1)
    1619
    1620 -    def test_cdata_errors(self):
    1621          CDATA = self.etree.CDATA
    1622          Element = self.etree.Element
    1623
    1624          root = Element("root")
    1625          cdata = CDATA('test')
    1626
    1627          self.assertRaises(TypeError,
    1628                            root.set, 'attr', cdata)
    1629          self.assertRaises(TypeError,
    1630                            operator.setitem, root.attrib, 'attr', cdata)
    1631
    1632 -    def test_cdata_parser(self):
    1633          tostring = self.etree.tostring
    1634          parser = self.etree.XMLParser(strip_cdata=False)
    1635          root = self.etree.XML(_bytes('<root><![CDATA[test]]></root>'), parser)
    1636
    1637          self.assertEqual('test', root.text)
    1638          self.assertEqual(_bytes('<root><![CDATA[test]]></root>'),
    1639                            tostring(root))
    1640
    1641 -    def test_cdata_xpath(self):
    1642          tostring = self.etree.tostring
    1643          parser = self.etree.XMLParser(strip_cdata=False)
    1644          root = self.etree.XML(_bytes('<root><![CDATA[test]]></root>'), parser)
    1645          self.assertEqual(_bytes('<root><![CDATA[test]]></root>'),
    1646                            tostring(root))
    1647
    1648          self.assertEqual(['test'], root.xpath('//text()'))
    1649
    1650      # TypeError in etree, AssertionError in ElementTree;
    1651 -    def test_setitem_assert(self):
    1652          Element = self.etree.Element
    1653          SubElement = self.etree.SubElement
    1654
    1655          a = Element('a')
    1656          b = SubElement(a, 'b')
    1657
    1658          self.assertRaises(TypeError,
    1659                            a.__setitem__, 0, 'foo')
    1660
    1661 -    def test_append_error(self):
    1662          Element = self.etree.Element
    1663          root = Element('root')
    1664          # raises AssertionError in ElementTree
    1665          self.assertRaises(TypeError, root.append, None)
    1666          self.assertRaises(TypeError, root.extend, [None])
    1667          self.assertRaises(TypeError, root.extend, [Element('one'), None])
    1668          self.assertEqual('one', root[0].tag)
    1669
    1670 -    def test_append_recursive_error(self):
    1671          Element = self.etree.Element
    1672          SubElement = self.etree.SubElement
    1673          root = Element('root')
    1674          self.assertRaises(ValueError, root.append, root)
    1675          child = SubElement(root, 'child')
    1676          self.assertRaises(ValueError, child.append, root)
    1677          child2 = SubElement(child, 'child2')
    1678          self.assertRaises(ValueError, child2.append, root)
    1679          self.assertRaises(ValueError, child2.append, child)
    1680          self.assertEqual('child2', root[0][0].tag)
    1681
    1682 -    def test_addnext(self):
    1683          Element = self.etree.Element
    1684          SubElement = self.etree.SubElement
    1685          root = Element('root')
    1686          SubElement(root, 'a')
    1687          SubElement(root, 'b')
    1688
    1689          self.assertEqual(['a', 'b'],
    1690                            [c.tag for c in root])
    1691          root[1].addnext(root[0])
    1692          self.assertEqual(['b', 'a'],
    1693                            [c.tag for c in root])
    1694
    1695 -    def test_addprevious(self):
    1696          Element = self.etree.Element
    1697          SubElement = self.etree.SubElement
    1698          root = Element('root')
    1699          SubElement(root, 'a')
    1700          SubElement(root, 'b')
    1701
    1702          self.assertEqual(['a', 'b'],
    1703                            [c.tag for c in root])
    1704          root[0].addprevious(root[1])
    1705          self.assertEqual(['b', 'a'],
    1706                            [c.tag for c in root])
    1707
    1708 -    def test_addnext_cycle(self):
    1709          Element = self.etree.Element
    1710          SubElement = self.etree.SubElement
    1711          root = Element('root')
    1712          a = SubElement(root, 'a')
    1713          b = SubElement(a, 'b')
    1714          # appending parent as sibling is forbidden
    1715          self.assertRaises(ValueError, b.addnext, a)
    1716          self.assertEqual(['a'], [c.tag for c in root])
    1717          self.assertEqual(['b'], [c.tag for c in a])
    1718
    1719 -    def test_addprevious_cycle(self):
    1720          Element = self.etree.Element
    1721          SubElement = self.etree.SubElement
    1722          root = Element('root')
    1723          a = SubElement(root, 'a')
    1724          b = SubElement(a, 'b')
    1725          # appending parent as sibling is forbidden
    1726          self.assertRaises(ValueError, b.addprevious, a)
    1727          self.assertEqual(['a'], [c.tag for c in root])
    1728          self.assertEqual(['b'], [c.tag for c in a])
    1729
    1730 -    def test_addnext_cycle_long(self):
    1731          Element = self.etree.Element
    1732          SubElement = self.etree.SubElement
    1733          root = Element('root')
    1734          a = SubElement(root, 'a')
    1735          b = SubElement(a, 'b')
    1736          c = SubElement(b, 'c')
    1737          # appending parent as sibling is forbidden
    1738          self.assertRaises(ValueError, c.addnext, a)
    1739
    1740 -    def test_addprevious_cycle_long(self):
    1741          Element = self.etree.Element
    1742          SubElement = self.etree.SubElement
    1743          root = Element('root')
    1744          a = SubElement(root, 'a')
    1745          b = SubElement(a, 'b')
    1746          c = SubElement(b, 'c')
    1747          # appending parent as sibling is forbidden
    1748          self.assertRaises(ValueError, c.addprevious, a)
    1749
    1750 -    def test_addprevious_noops(self):
    1751          Element = self.etree.Element
    1752          SubElement = self.etree.SubElement
    1753          root = Element('root')
    1754          a = SubElement(root, 'a')
    1755          b = SubElement(root, 'b')
    1756          a.addprevious(a)
    1757          self.assertEqual('a', root[0].tag)
    1758          self.assertEqual('b', root[1].tag)
    1759          b.addprevious(b)
    1760          self.assertEqual('a', root[0].tag)
    1761          self.assertEqual('b', root[1].tag)
    1762          b.addprevious(a)
    1763          self.assertEqual('a', root[0].tag)
    1764          self.assertEqual('b', root[1].tag)
    1765
    1766 -    def test_addnext_noops(self):
    1767          Element = self.etree.Element
    1768          SubElement = self.etree.SubElement
    1769          root = Element('root')
    1770          a = SubElement(root, 'a')
    1771          b = SubElement(root, 'b')
    1772          a.addnext(a)
    1773          self.assertEqual('a', root[0].tag)
    1774          self.assertEqual('b', root[1].tag)
    1775          b.addnext(b)
    1776          self.assertEqual('a', root[0].tag)
    1777          self.assertEqual('b', root[1].tag)
    1778          a.addnext(b)
    1779          self.assertEqual('a', root[0].tag)
    1780          self.assertEqual('b', root[1].tag)
    1781
    1782 -    def test_addnext_root(self):
    1783          Element = self.etree.Element
    1784          a = Element('a')
    1785          b = Element('b')
    1786          self.assertRaises(TypeError, a.addnext, b)
    1787
    1788 -    def test_addprevious_pi(self):
    1789          Element = self.etree.Element
    1790          SubElement = self.etree.SubElement
    1791          PI = self.etree.PI
    1792          root = Element('root')
    1793          SubElement(root, 'a')
    1794          pi = PI('TARGET', 'TEXT')
    1795          pi.tail = "TAIL"
    1796
    1797          self.assertEqual(_bytes('<root><a></a></root>'),
    1798                            self._writeElement(root))
    1799          root[0].addprevious(pi)
    1800          self.assertEqual(_bytes('<root><?TARGET TEXT?>TAIL<a></a></root>'),
    1801                            self._writeElement(root))
    1802
    1803 -    def test_addprevious_root_pi(self):
    1804          Element = self.etree.Element
    1805          PI = self.etree.PI
    1806          root = Element('root')
    1807          pi = PI('TARGET', 'TEXT')
    1808          pi.tail = "TAIL"
    1809
    1810          self.assertEqual(_bytes('<root></root>'),
    1811                            self._writeElement(root))
    1812          root.addprevious(pi)
    1813          self.assertEqual(_bytes('<?TARGET TEXT?>\n<root></root>'),
    1814                            self._writeElement(root))
    1815
    1816 -    def test_addnext_pi(self):
    1817          Element = self.etree.Element
    1818          SubElement = self.etree.SubElement
    1819          PI = self.etree.PI
    1820          root = Element('root')
    1821          SubElement(root, 'a')
    1822          pi = PI('TARGET', 'TEXT')
    1823          pi.tail = "TAIL"
    1824
    1825          self.assertEqual(_bytes('<root><a></a></root>'),
    1826                            self._writeElement(root))
    1827          root[0].addnext(pi)
    1828          self.assertEqual(_bytes('<root><a></a><?TARGET TEXT?>TAIL</root>'),
    1829                            self._writeElement(root))
    1830
    1831 -    def test_addnext_root_pi(self):
    1832          Element = self.etree.Element
    1833          PI = self.etree.PI
    1834          root = Element('root')
    1835          pi = PI('TARGET', 'TEXT')
    1836          pi.tail = "TAIL"
    1837
    1838          self.assertEqual(_bytes('<root></root>'),
    1839                            self._writeElement(root))
    1840          root.addnext(pi)
    1841          self.assertEqual(_bytes('<root></root>\n<?TARGET TEXT?>'),
    1842                            self._writeElement(root))
    1843
    1844 -    def test_addnext_comment(self):
    1845          Element = self.etree.Element
    1846          SubElement = self.etree.SubElement
    1847          Comment = self.etree.Comment
    1848          root = Element('root')
    1849          SubElement(root, 'a')
    1850          comment = Comment('TEXT ')
    1851          comment.tail = "TAIL"
    1852
    1853          self.assertEqual(_bytes('<root><a></a></root>'),
    1854                            self._writeElement(root))
    1855          root[0].addnext(comment)
    1856          self.assertEqual(_bytes('<root><a></a><!--TEXT -->TAIL</root>'),
    1857                            self._writeElement(root))
    1858
    1859 -    def test_addnext_root_comment(self):
    1860          Element = self.etree.Element
    1861          Comment = self.etree.Comment
    1862          root = Element('root')
    1863          comment = Comment('TEXT ')
    1864          comment.tail = "TAIL"
    1865
    1866          self.assertEqual(_bytes('<root></root>'),
    1867                            self._writeElement(root))
    1868          root.addnext(comment)
    1869          self.assertEqual(_bytes('<root></root>\n<!--TEXT -->'),
    1870                            self._writeElement(root))
    1871
    1872 -    def test_addprevious_comment(self):
    1873          Element = self.etree.Element
    1874          SubElement = self.etree.SubElement
    1875          Comment = self.etree.Comment
    1876          root = Element('root')
    1877          SubElement(root, 'a')
    1878          comment = Comment('TEXT ')
    1879          comment.tail = "TAIL"
    1880
    1881          self.assertEqual(_bytes('<root><a></a></root>'),
    1882                            self._writeElement(root))
    1883          root[0].addprevious(comment)
    1884          self.assertEqual(_bytes('<root><!--TEXT -->TAIL<a></a></root>'),
    1885                            self._writeElement(root))
    1886
    1887 -    def test_addprevious_root_comment(self):
    1888          Element = self.etree.Element
    1889          Comment = self.etree.Comment
    1890          root = Element('root')
    1891          comment = Comment('TEXT ')
    1892          comment.tail = "TAIL"
    1893
    1894          self.assertEqual(_bytes('<root></root>'),
    1895                            self._writeElement(root))
    1896          root.addprevious(comment)
    1897          self.assertEqual(_bytes('<!--TEXT -->\n<root></root>'),
    1898                            self._writeElement(root))
    1899
    1900      # ET's Elements have items() and key(), but not values()
    1901 -    def test_attribute_values(self):
    1902          XML = self.etree.XML
    1903
    1904          root = XML(_bytes('<doc alpha="Alpha" beta="Beta" gamma="Gamma"/>'))
    1905          values = root.values()
    1906          values.sort()
    1907          self.assertEqual(['Alpha', 'Beta', 'Gamma'], values)
    1908
    1909      # gives error in ElementTree
    1910 -    def test_comment_empty(self):
    1911          Element = self.etree.Element
    1912          Comment = self.etree.Comment
    1913
    1914          a = Element('a')
    1915          a.append(Comment())
    1916          self.assertEqual(
    1917              _bytes('<a><!----></a>'),
    1918              self._writeElement(a))
    1919
    1920      # ElementTree ignores comments
    1921 -    def test_comment_parse_empty(self):
    1922          ElementTree = self.etree.ElementTree
    1923          tostring = self.etree.tostring
    1924
    1925          xml = _bytes('<a><b/><!----><c/></a>')
    1926          f = BytesIO(xml)
    1927          doc = ElementTree(file=f)
    1928          a = doc.getroot()
    1929          self.assertEqual(
    1930              '',
    1931              a[1].text)
    1932          self.assertEqual(
    1933              xml,
    1934              tostring(a))
    1935
    1936      # ElementTree ignores comments
    1937 -    def test_comment_no_proxy_yet(self):
    1938          ElementTree = self.etree.ElementTree
    1939
    1940          f = BytesIO('<a><b></b><!-- hoi --><c></c></a>')
    1941          doc = ElementTree(file=f)
    1942          a = doc.getroot()
    1943          self.assertEqual(
    1944              ' hoi ',
    1945              a[1].text)
    1946
    1947      # does not raise an exception in ElementTree
    1948 -    def test_comment_immutable(self):
    1949          Element = self.etree.Element
    1950          Comment = self.etree.Comment
    1951
    1952          c = Comment()
    1953          el = Element('myel')
    1954
    1955          self.assertRaises(TypeError, c.append, el)
    1956          self.assertRaises(TypeError, c.insert, 0, el)
    1957          self.assertRaises(TypeError, c.set, "myattr", "test")
    1958
    1959 -    def test_comment_immutable_attrib(self):
    1960          c = self.etree.Comment()
    1961          self.assertEqual(0, len(c.attrib))
    1962
    1963          self.assertFalse(c.attrib.__contains__('nope'))
    1964          self.assertFalse('nope' in c.attrib)
    1965          self.assertFalse('nope' in c.attrib.keys())
    1966          self.assertFalse('nope' in c.attrib.values())
    1967          self.assertFalse(('nope', 'huhu') in c.attrib.items())
    1968
    1969          self.assertEqual([], list(c.attrib))
    1970          self.assertEqual([], list(c.attrib.keys()))
    1971          self.assertEqual([], list(c.attrib.items()))
    1972          self.assertEqual([], list(c.attrib.values()))
    1973          self.assertEqual([], list(c.attrib.iterkeys()))
    1974          self.assertEqual([], list(c.attrib.iteritems()))
    1975          self.assertEqual([], list(c.attrib.itervalues()))
    1976
    1977          self.assertEqual('HUHU', c.attrib.pop('nope', 'HUHU'))
    1978          self.assertRaises(KeyError, c.attrib.pop, 'nope')
    1979
    1980          self.assertRaises(KeyError, c.attrib.__getitem__, 'only')
    1981          self.assertRaises(KeyError, c.attrib.__getitem__, 'names')
    1982          self.assertRaises(KeyError, c.attrib.__getitem__, 'nope')
    1983          self.assertRaises(KeyError, c.attrib.__setitem__, 'nope', 'yep')
    1984          self.assertRaises(KeyError, c.attrib.__delitem__, 'nope')
    1985
    1986      # test passing 'None' to dump()
    1987 -    def test_dump_none(self):
    1988          self.assertRaises(TypeError, self.etree.dump, None)
    1989
    1990 -    def test_prefix(self):
    1991          ElementTree = self.etree.ElementTree
    1992
    1993          f = BytesIO('<a xmlns:foo="http://www.infrae.com/ns/1"><foo:b/></a>')
    1994          doc = ElementTree(file=f)
    1995          a = doc.getroot()
    1996          self.assertEqual(
    1997              None,
    1998              a.prefix)
    1999          self.assertEqual(
    2000              'foo',
    2001              a[0].prefix)
    2002
    2003 -    def test_prefix_default_ns(self):
    2004          ElementTree = self.etree.ElementTree
    2005
    2006          f = BytesIO('<a xmlns="http://www.infrae.com/ns/1"><b/></a>')
    2007          doc = ElementTree(file=f)
    2008          a = doc.getroot()
    2009          self.assertEqual(
    2010              None,
    2011              a.prefix)
    2012          self.assertEqual(
    2013              None,
    2014              a[0].prefix)
    2015
    2016 -    def test_getparent(self):
    2017          Element = self.etree.Element
    2018          SubElement = self.etree.SubElement
    2019
    2020          a = Element('a')
    2021          b = SubElement(a, 'b')
    2022          c = SubElement(a, 'c')
    2023          d = SubElement(b, 'd')
    2024          self.assertEqual(
    2025              None,
    2026              a.getparent())
    2027          self.assertEqual(
    2028              a,
    2029              b.getparent())
    2030          self.assertEqual(
    2031              b.getparent(),
    2032              c.getparent())
    2033          self.assertEqual(
    2034              b,
    2035              d.getparent())
    2036
    2037 -    def test_iterchildren(self):
    2038          XML = self.etree.XML
    2039
    2040          root = XML(_bytes('<doc><one/><two>Two</two>Hm<three/></doc>'))
    2041          result = []
    2042          for el in root.iterchildren():
    2043              result.append(el.tag)
    2044          self.assertEqual(['one', 'two', 'three'], result)
    2045
    2046 -    def test_iterchildren_reversed(self):
    2047          XML = self.etree.XML
    2048
    2049          root = XML(_bytes('<doc><one/><two>Two</two>Hm<three/></doc>'))
    2050          result = []
    2051          for el in root.iterchildren(reversed=True):
    2052              result.append(el.tag)
    2053          self.assertEqual(['three', 'two', 'one'], result)
    2054
    2055 -    def test_iterchildren_tag(self):
    2056          XML = self.etree.XML
    2057
    2058          root = XML(_bytes('<doc><one/><two>Two</two>Hm<two>Bla</two></doc>'))
    2059          result = []
    2060          for el in root.iterchildren(tag='two'):
    2061              result.append(el.text)
    2062          self.assertEqual(['Two', 'Bla'], result)
    2063
    2064 -    def test_iterchildren_tag_posarg(self):
    2065          XML = self.etree.XML
    2066
    2067          root = XML(_bytes('<doc><one/><two>Two</two>Hm<two>Bla</two></doc>'))
    2068          result = []
    2069          for el in root.iterchildren('two'):
    2070              result.append(el.text)
    2071          self.assertEqual(['Two', 'Bla'], result)
    2072
    2073 -    def test_iterchildren_tag_reversed(self):
    2074          XML = self.etree.XML
    2075
    2076          root = XML(_bytes('<doc><one/><two>Two</two>Hm<two>Bla</two></doc>'))
    2077          result = []
    2078          for el in root.iterchildren(reversed=True, tag='two'):
    2079              result.append(el.text)
    2080          self.assertEqual(['Bla', 'Two'], result)
    2081
    2082 -    def test_iterchildren_tag_multiple(self):
    2083          XML = self.etree.XML
    2084
    2085          root = XML(_bytes('<doc><one/><two>Two</two>Hm<two>Bla</two><three/></doc>'))
    2086          result = []
    2087          for el in root.iterchildren(tag=['two', 'three']):
    2088              result.append(el.text)
    2089          self.assertEqual(['Two', 'Bla', None], result)
    2090
    2091 -    def test_iterchildren_tag_multiple_posarg(self):
    2092          XML = self.etree.XML
    2093
    2094          root = XML(_bytes('<doc><one/><two>Two</two>Hm<two>Bla</two><three/></doc>'))
    2095          result = []
    2096          for el in root.iterchildren('two', 'three'):
    2097              result.append(el.text)
    2098          self.assertEqual(['Two', 'Bla', None], result)
    2099
    2100 -    def test_iterchildren_tag_multiple_reversed(self):
    2101          XML = self.etree.XML
    2102
    2103          root = XML(_bytes('<doc><one/><two>Two</two>Hm<two>Bla</two><three/></doc>'))
    2104          result = []
    2105          for el in root.iterchildren(reversed=True, tag=['two', 'three']):
    2106              result.append(el.text)
    2107          self.assertEqual([None, 'Bla', 'Two'], result)
    2108
    2109 -    def test_iterancestors(self):
    2110          Element    = self.etree.Element
    2111          SubElement = self.etree.SubElement
    2112
    2113          a = Element('a')
    2114          b = SubElement(a, 'b')
    2115          c = SubElement(a, 'c')
    2116          d = SubElement(b, 'd')
    2117          self.assertEqual(
    2118              [],
    2119              list(a.iterancestors()))
    2120          self.assertEqual(
    2121              [a],
    2122              list(b.iterancestors()))
    2123          self.assertEqual(
    2124              [a],
    2125              list(c.iterancestors()))
    2126          self.assertEqual(
    2127              [b, a],
    2128              list(d.iterancestors()))
    2129
    2130 -    def test_iterancestors_tag(self):
    2131          Element    = self.etree.Element
    2132          SubElement = self.etree.SubElement
    2133
    2134          a = Element('a')
    2135          b = SubElement(a, 'b')
    2136          c = SubElement(a, 'c')
    2137          d = SubElement(b, 'd')
    2138          self.assertEqual(
    2139              [a],
    2140              list(d.iterancestors('a')))
    2141          self.assertEqual(
    2142              [a],
    2143              list(d.iterancestors(tag='a')))
    2144
    2145          self.assertEqual(
    2146              [b, a],
    2147              list(d.iterancestors('*')))
    2148          self.assertEqual(
    2149              [b, a],
    2150              list(d.iterancestors(tag='*')))
    2151
    2152 -    def test_iterancestors_tag_multiple(self):
    2153          Element    = self.etree.Element
    2154          SubElement = self.etree.SubElement
    2155
    2156          a = Element('a')
    2157          b = SubElement(a, 'b')
    2158          c = SubElement(a, 'c')
    2159          d = SubElement(b, 'd')
    2160          self.assertEqual(
    2161              [b, a],
    2162              list(d.iterancestors(tag=('a', 'b'))))
    2163          self.assertEqual(
    2164              [b, a],
    2165              list(d.iterancestors('a', 'b')))
    2166
    2167          self.assertEqual(
    2168              [],
    2169              list(d.iterancestors(tag=('w', 'x', 'y', 'z'))))
    2170          self.assertEqual(
    2171              [],
    2172              list(d.iterancestors('w', 'x', 'y', 'z')))
    2173
    2174          self.assertEqual(
    2175              [],
    2176              list(d.iterancestors(tag=('d', 'x'))))
    2177          self.assertEqual(
    2178              [],
    2179              list(d.iterancestors('d', 'x')))
    2180
    2181          self.assertEqual(
    2182              [b, a],
    2183              list(d.iterancestors(tag=('b', '*'))))
    2184          self.assertEqual(
    2185              [b, a],
    2186              list(d.iterancestors('b', '*')))
    2187
    2188          self.assertEqual(
    2189              [b],
    2190              list(d.iterancestors(tag=('b', 'c'))))
    2191          self.assertEqual(
    2192              [b],
    2193              list(d.iterancestors('b', 'c')))
    2194
    2195 -    def test_iterdescendants(self):
    2196          Element = self.etree.Element
    2197          SubElement = self.etree.SubElement
    2198
    2199          a = Element('a')
    2200          b = SubElement(a, 'b')
    2201          c = SubElement(a, 'c')
    2202          d = SubElement(b, 'd')
    2203          e = SubElement(c, 'e')
    2204
    2205          self.assertEqual(
    2206              [b, d, c, e],
    2207              list(a.iterdescendants()))
    2208          self.assertEqual(
    2209              [],
    2210              list(d.iterdescendants()))
    2211
    2212 -    def test_iterdescendants_tag(self):
    2213          Element = self.etree.Element
    2214          SubElement = self.etree.SubElement
    2215
    2216          a = Element('a')
    2217          b = SubElement(a, 'b')
    2218          c = SubElement(a, 'c')
    2219          d = SubElement(b, 'd')
    2220          e = SubElement(c, 'e')
    2221
    2222          self.assertEqual(
    2223              [],
    2224              list(a.iterdescendants('a')))
    2225          self.assertEqual(
    2226              [],
    2227              list(a.iterdescendants(tag='a')))
    2228
    2229          a2 = SubElement(e, 'a')
    2230          self.assertEqual(
    2231              [a2],
    2232              list(a.iterdescendants('a')))
    2233
    2234          self.assertEqual(
    2235              [a2],
    2236              list(c.iterdescendants('a')))
    2237          self.assertEqual(
    2238              [a2],
    2239              list(c.iterdescendants(tag='a')))
    2240
    2241 -    def test_iterdescendants_tag_multiple(self):
    2242          Element = self.etree.Element
    2243          SubElement = self.etree.SubElement
    2244
    2245          a = Element('a')
    2246          b = SubElement(a, 'b')
    2247          c = SubElement(a, 'c')
    2248          d = SubElement(b, 'd')
    2249          e = SubElement(c, 'e')
    2250
    2251          self.assertEqual(
    2252              [b, e],
    2253              list(a.iterdescendants(tag=('a', 'b', 'e'))))
    2254          self.assertEqual(
    2255              [b, e],
    2256              list(a.iterdescendants('a', 'b', 'e')))
    2257
    2258          a2 = SubElement(e, 'a')
    2259          self.assertEqual(
    2260              [b, a2],
    2261              list(a.iterdescendants(tag=('a', 'b'))))
    2262          self.assertEqual(
    2263              [b, a2],
    2264              list(a.iterdescendants('a', 'b')))
    2265
    2266          self.assertEqual(
    2267              [],
    2268              list(c.iterdescendants(tag=('x', 'y', 'z'))))
    2269          self.assertEqual(
    2270              [],
    2271              list(c.iterdescendants('x', 'y', 'z')))
    2272
    2273          self.assertEqual(
    2274              [b, d, c, e, a2],
    2275              list(a.iterdescendants(tag=('x', 'y', 'z', '*'))))
    2276          self.assertEqual(
    2277              [b, d, c, e, a2],
    2278              list(a.iterdescendants('x', 'y', 'z', '*')))
    2279
    2280 -    def test_getroottree(self):
    2281          Element = self.etree.Element
    2282          SubElement = self.etree.SubElement
    2283
    2284          a = Element('a')
    2285          b = SubElement(a, 'b')
    2286          c = SubElement(a, 'c')
    2287          d = SubElement(b, 'd')
    2288          self.assertEqual(
    2289              a,
    2290              a.getroottree().getroot())
    2291          self.assertEqual(
    2292              a,
    2293              b.getroottree().getroot())
    2294          self.assertEqual(
    2295              a,
    2296              d.getroottree().getroot())
    2297
    2298 -    def test_getnext(self):
    2299          Element    = self.etree.Element
    2300          SubElement = self.etree.SubElement
    2301
    2302          a = Element('a')
    2303          b = SubElement(a, 'b')
    2304          c = SubElement(a, 'c')
    2305          self.assertEqual(
    2306              None,
    2307              a.getnext())
    2308          self.assertEqual(
    2309              c,
    2310              b.getnext())
    2311          self.assertEqual(
    2312              None,
    2313              c.getnext())
    2314
    2315 -    def test_getprevious(self):
    2316          Element    = self.etree.Element
    2317          SubElement = self.etree.SubElement
    2318
    2319          a = Element('a')
    2320          b = SubElement(a, 'b')
    2321          c = SubElement(a, 'c')
    2322          d = SubElement(b, 'd')
    2323          self.assertEqual(
    2324              None,
    2325              a.getprevious())
    2326          self.assertEqual(
    2327              b,
    2328              c.getprevious())
    2329          self.assertEqual(
    2330              None,
    2331              b.getprevious())
    2332
    2333 -    def test_itersiblings(self):
    2334          Element    = self.etree.Element
    2335          SubElement = self.etree.SubElement
    2336
    2337          a = Element('a')
    2338          b = SubElement(a, 'b')
    2339          c = SubElement(a, 'c')
    2340          d = SubElement(b, 'd')
    2341          self.assertEqual(
    2342              [],
    2343              list(a.itersiblings()))
    2344          self.assertEqual(
    2345              [c],
    2346              list(b.itersiblings()))
    2347          self.assertEqual(
    2348              [],
    2349              list(c.itersiblings()))
    2350          self.assertEqual(
    2351              [b],
    2352              list(c.itersiblings(preceding=True)))
    2353          self.assertEqual(
    2354              [],
    2355              list(b.itersiblings(preceding=True)))
    2356
    2357 -    def test_itersiblings_tag(self):
    2358          Element    = self.etree.Element
    2359          SubElement = self.etree.SubElement
    2360
    2361          a = Element('a')
    2362          b = SubElement(a, 'b')
    2363          c = SubElement(a, 'c')
    2364          d = SubElement(b, 'd')
    2365          self.assertEqual(
    2366              [],
    2367              list(a.itersiblings(tag='XXX')))
    2368          self.assertEqual(
    2369              [c],
    2370              list(b.itersiblings(tag='c')))
    2371          self.assertEqual(
    2372              [c],
    2373              list(b.itersiblings(tag='*')))
    2374          self.assertEqual(
    2375              [b],
    2376              list(c.itersiblings(preceding=True, tag='b')))
    2377          self.assertEqual(
    2378              [],
    2379              list(c.itersiblings(preceding=True, tag='c')))
    2380
    2381 -    def test_itersiblings_tag_multiple(self):
    2382          Element    = self.etree.Element
    2383          SubElement = self.etree.SubElement
    2384
    2385          a = Element('a')
    2386          b = SubElement(a, 'b')
    2387          c = SubElement(a, 'c')
    2388          d = SubElement(b, 'd')
    2389          e = SubElement(a, 'e')
    2390          self.assertEqual(
    2391              [],
    2392              list(a.itersiblings(tag=('XXX', 'YYY'))))
    2393          self.assertEqual(
    2394              [c, e],
    2395              list(b.itersiblings(tag=('c', 'd', 'e'))))
    2396          self.assertEqual(
    2397              [b],
    2398              list(c.itersiblings(preceding=True, tag=('b', 'b', 'c', 'd'))))
    2399          self.assertEqual(
    2400              [c, b],
    2401              list(e.itersiblings(preceding=True, tag=('c', '*'))))
    2402
    2403 -    def test_parseid(self):
    2404          parseid = self.etree.parseid
    2405          XML     = self.etree.XML
    2406          xml_text = _bytes('''
    2407          <!DOCTYPE document [
    2408          <!ELEMENT document (h1,p)*>
    2409          <!ELEMENT h1 (#PCDATA)>
    2410          <!ATTLIST h1 myid ID #REQUIRED>
    2411          <!ELEMENT p  (#PCDATA)>
    2412          <!ATTLIST p  someid ID #REQUIRED>
    2413          ]>
    2414          <document>
    2415            <h1 myid="chapter1">...</h1>
    2416            <p id="note1" class="note">...</p>
    2417            <p>Regular paragraph.</p>
    2418            <p xml:id="xmlid">XML:ID paragraph.</p>
    2419            <p someid="warn1" class="warning">...</p>
    2420          </document>
    2421          ''')
    2422
    2423          tree, dic = parseid(BytesIO(xml_text))
    2424          root = tree.getroot()
    2425          root2 = XML(xml_text)
    2426          self.assertEqual(self._writeElement(root),
    2427                            self._writeElement(root2))
    2428          expected = {
    2429              "chapter1" : root[0],
    2430              "xmlid"    : root[3],
    2431              "warn1"    : root[4]
    2432              }
    2433          self.assertTrue("chapter1" in dic)
    2434          self.assertTrue("warn1" in dic)
    2435          self.assertTrue("xmlid" in dic)
    2436          self._checkIDDict(dic, expected)
    2437
    2438 -    def test_XMLDTDID(self):
    2439          XMLDTDID = self.etree.XMLDTDID
    2440          XML      = self.etree.XML
    2441          xml_text = _bytes('''
    2442          <!DOCTYPE document [
    2443          <!ELEMENT document (h1,p)*>
    2444          <!ELEMENT h1 (#PCDATA)>
    2445          <!ATTLIST h1 myid ID #REQUIRED>
    2446          <!ELEMENT p  (#PCDATA)>
    2447          <!ATTLIST p  someid ID #REQUIRED>
    2448          ]>
    2449          <document>
    2450            <h1 myid="chapter1">...</h1>
    2451            <p id="note1" class="note">...</p>
    2452            <p>Regular paragraph.</p>
    2453            <p xml:id="xmlid">XML:ID paragraph.</p>
    2454            <p someid="warn1" class="warning">...</p>
    2455          </document>
    2456          ''')
    2457
    2458          root, dic = XMLDTDID(xml_text)
    2459          root2 = XML(xml_text)
    2460          self.assertEqual(self._writeElement(root),
    2461                            self._writeElement(root2))
    2462          expected = {
    2463              "chapter1" : root[0],
    2464              "xmlid"    : root[3],
    2465              "warn1"    : root[4]
    2466              }
    2467          self.assertTrue("chapter1" in dic)
    2468          self.assertTrue("warn1" in dic)
    2469          self.assertTrue("xmlid" in dic)
    2470          self._checkIDDict(dic, expected)
    2471
    2472 -    def test_XMLDTDID_empty(self):
    2473          XMLDTDID = self.etree.XMLDTDID
    2474          XML      = self.etree.XML
    2475          xml_text = _bytes('''
    2476          <document>
    2477            <h1 myid="chapter1">...</h1>
    2478            <p id="note1" class="note">...</p>
    2479            <p>Regular paragraph.</p>
    2480            <p someid="warn1" class="warning">...</p>
    2481          </document>
    2482          ''')
    2483
    2484          root, dic = XMLDTDID(xml_text)
    2485          root2 = XML(xml_text)
    2486          self.assertEqual(self._writeElement(root),
    2487                            self._writeElement(root2))
    2488          expected = {}
    2489          self._checkIDDict(dic, expected)
    2490
    2491 -    def test_XMLDTDID_no_id_dict(self):
    2492          XMLDTDID = self.etree.XMLDTDID
    2493          XML      = self.etree.XML
    2494          xml_text = _bytes('''
    2495          <!DOCTYPE document [
    2496          <!ELEMENT document (h1,p)*>
    2497          <!ELEMENT h1 (#PCDATA)>
    2498          <!ATTLIST h1 myid ID #REQUIRED>
    2499          <!ELEMENT p  (#PCDATA)>
    2500          <!ATTLIST p  someid ID #REQUIRED>
    2501          ]>
    2502          <document>
    2503            <h1 myid="chapter1">...</h1>
    2504            <p id="note1" class="note">...</p>
    2505            <p>Regular paragraph.</p>
    2506            <p xml:id="xmlid">XML:ID paragraph.</p>
    2507            <p someid="warn1" class="warning">...</p>
    2508          </document>
    2509          ''')
    2510
    2511          parser = etree.XMLParser(collect_ids=False)
    2512          root, dic = XMLDTDID(xml_text, parser=parser)
    2513          root2 = XML(xml_text)
    2514          self.assertEqual(self._writeElement(root),
    2515                           self._writeElement(root2))
    2516          self.assertFalse(dic)
    2517          self._checkIDDict(dic, {})
    2518
    2519 -    def _checkIDDict(self, dic, expected):
    2520          self.assertEqual(len(dic),
    2521                            len(expected))
    2522          self.assertEqual(sorted(dic.items()),
    2523                            sorted(expected.items()))
    2524          if sys.version_info < (3,):
    2525              self.assertEqual(sorted(dic.iteritems()),
    2526                                sorted(expected.iteritems()))
    2527          self.assertEqual(sorted(dic.keys()),
    2528                            sorted(expected.keys()))
    2529          if sys.version_info < (3,):
    2530              self.assertEqual(sorted(dic.iterkeys()),
    2531                                sorted(expected.iterkeys()))
    2532          if sys.version_info < (3,):
    2533              self.assertEqual(sorted(dic.values()),
    2534                                sorted(expected.values()))
    2535              self.assertEqual(sorted(dic.itervalues()),
    2536                                sorted(expected.itervalues()))
    2537
    2538 -    def test_namespaces(self):
    2539          etree = self.etree
    2540
    2541          r = {'foo': 'http://ns.infrae.com/foo'}
    2542          e = etree.Element('{http://ns.infrae.com/foo}bar', nsmap=r)
    2543          self.assertEqual(
    2544              'foo',
    2545              e.prefix)
    2546          self.assertEqual(
    2547              _bytes('<foo:bar xmlns:foo="http://ns.infrae.com/foo"></foo:bar>'),
    2548              self._writeElement(e))
    2549
    2550 -    def test_namespaces_default(self):
    2551          etree = self.etree
    2552
    2553          r = {None: 'http://ns.infrae.com/foo'}
    2554          e = etree.Element('{http://ns.infrae.com/foo}bar', nsmap=r)
    2555          self.assertEqual(
    2556              None,
    2557              e.prefix)
    2558          self.assertEqual(
    2559              '{http://ns.infrae.com/foo}bar',
    2560              e.tag)
    2561          self.assertEqual(
    2562              _bytes('<bar xmlns="http://ns.infrae.com/foo"></bar>'),
    2563              self._writeElement(e))
    2564
    2565 -    def test_namespaces_default_and_other(self):
    2566          etree = self.etree
    2567
    2568          r = {None: 'http://ns.infrae.com/foo', 'p': 'http://test/'}
    2569          e = etree.Element('{http://ns.infrae.com/foo}bar', nsmap=r)
    2570          self.assertEqual(None, e.prefix)
    2571          self.assertEqual('{http://ns.infrae.com/foo}bar', e.tag)
    2572          self.assertEqual(
    2573              _bytes('<bar xmlns="http://ns.infrae.com/foo" xmlns:p="http://test/"></bar>'),
    2574              self._writeElement(e))
    2575
    2576 -    def test_namespaces_default_and_attr(self):
    2577          etree = self.etree
    2578
    2579          r = {None: 'http://ns.infrae.com/foo',
    2580               'hoi': 'http://ns.infrae.com/hoi'}
    2581          e = etree.Element('{http://ns.infrae.com/foo}bar', nsmap=r)
    2582          e.set('{http://ns.infrae.com/hoi}test', 'value')
    2583          self.assertEqual(
    2584              _bytes('<bar xmlns="http://ns.infrae.com/foo" xmlns:hoi="http://ns.infrae.com/hoi" hoi:test="value"></bar>'),
    2585              self._writeElement(e))
    2586
    2587 -    def test_attribute_keeps_namespace_prefix_on_merge(self):
    2588          etree = self.etree
    2589
    2590          root = etree.Element('{http://test/ns}root',
    2591                               nsmap={None: 'http://test/ns'})
    2592          sub = etree.Element('{http://test/ns}sub',
    2593                              nsmap={'test': 'http://test/ns'})
    2594
    2595          sub.attrib['{http://test/ns}attr'] = 'value'
    2596          self.assertEqual(sub.attrib['{http://test/ns}attr'], 'value')
    2597          self.assertEqual(
    2598              _bytes('<test:sub xmlns:test="http://test/ns" test:attr="value"/>'),
    2599              etree.tostring(sub))
    2600
    2601          root.append(sub)
    2602          self.assertEqual(
    2603              _bytes('<root xmlns="http://test/ns">'
    2604                     '<sub xmlns:test="http://test/ns" test:attr="value"/>'
    2605                     '</root>'),
    2606              etree.tostring(root))
    2607
    2608 -    def test_attribute_keeps_namespace_prefix_on_merge_with_nons(self):
    2609          etree = self.etree
    2610
    2611          root = etree.Element('root')
    2612          sub = etree.Element('{http://test/ns}sub',
    2613                              nsmap={'test': 'http://test/ns'})
    2614
    2615          sub.attrib['{http://test/ns}attr'] = 'value'
    2616          self.assertEqual(sub.attrib['{http://test/ns}attr'], 'value')
    2617          self.assertEqual(
    2618              _bytes('<test:sub xmlns:test="http://test/ns" test:attr="value"/>'),
    2619              etree.tostring(sub))
    2620
    2621          root.append(sub)
    2622          self.assertEqual(
    2623              _bytes('<root>'
    2624                     '<test:sub xmlns:test="http://test/ns" test:attr="value"/>'
    2625                     '</root>'),
    2626              etree.tostring(root))
    2627
    2628 -    def test_attribute_gets_namespace_prefix_on_merge_with_nons(self):
    2629          etree = self.etree
    2630
    2631          root = etree.Element('root')
    2632          sub = etree.Element('{http://test/ns}sub',
    2633                              nsmap={None: 'http://test/ns'})
    2634
    2635          sub.attrib['{http://test/ns}attr'] = 'value'
    2636          self.assertEqual(sub.attrib['{http://test/ns}attr'], 'value')
    2637          self.assertEqual(
    2638              _bytes('<sub xmlns="http://test/ns" '
    2639                     'xmlns:ns0="http://test/ns" ns0:attr="value"/>'),
    2640              etree.tostring(sub))
    2641
    2642          root.append(sub)
    2643          self.assertEqual(
    2644              _bytes('<root>'
    2645                     '<sub xmlns="http://test/ns"'
    2646                     ' xmlns:ns0="http://test/ns" ns0:attr="value"/>'
    2647                     '</root>'),
    2648              etree.tostring(root))
    2649
    2650 -    def test_attribute_gets_namespace_prefix_on_merge(self):
    2651          etree = self.etree
    2652
    2653          root = etree.Element('{http://test/ns}root',
    2654                               nsmap={'test': 'http://test/ns',
    2655                                      None: 'http://test/ns'})
    2656          sub = etree.Element('{http://test/ns}sub',
    2657                              nsmap={None: 'http://test/ns'})
    2658
    2659          sub.attrib['{http://test/ns}attr'] = 'value'
    2660          self.assertEqual(sub.attrib['{http://test/ns}attr'], 'value')
    2661          self.assertEqual(
    2662              _bytes('<sub xmlns="http://test/ns" '
    2663                     'xmlns:ns0="http://test/ns" ns0:attr="value"/>'),
    2664              etree.tostring(sub))
    2665
    2666          root.append(sub)
    2667          self.assertEqual(
    2668              _bytes('<test:root xmlns:test="http://test/ns" xmlns="http://test/ns">'
    2669                     '<test:sub test:attr="value"/>'
    2670                     '</test:root>'),
    2671              etree.tostring(root))
    2672
    2673 -    def test_namespaces_elementtree(self):
    2674          etree = self.etree
    2675          r = {None: 'http://ns.infrae.com/foo',
    2676               'hoi': 'http://ns.infrae.com/hoi'}
    2677          e = etree.Element('{http://ns.infrae.com/foo}z', nsmap=r)
    2678          tree = etree.ElementTree(element=e)
    2679          etree.SubElement(e, '{http://ns.infrae.com/hoi}x')
    2680          self.assertEqual(
    2681              _bytes('<z xmlns="http://ns.infrae.com/foo" xmlns:hoi="http://ns.infrae.com/hoi"><hoi:x></hoi:x></z>'),
    2682              self._writeElement(e))
    2683
    2684 -    def test_namespaces_default_copy_element(self):
    2685          etree = self.etree
    2686
    2687          r = {None: 'http://ns.infrae.com/foo'}
    2688          e1 = etree.Element('{http://ns.infrae.com/foo}bar', nsmap=r)
    2689          e2 = etree.Element('{http://ns.infrae.com/foo}bar', nsmap=r)
    2690
    2691          e1.append(e2)
    2692
    2693          self.assertEqual(
    2694              None,
    2695              e1.prefix)
    2696          self.assertEqual(
    2697              None,
    2698              e1[0].prefix)
    2699          self.assertEqual(
    2700              '{http://ns.infrae.com/foo}bar',
    2701              e1.tag)
    2702          self.assertEqual(
    2703              '{http://ns.infrae.com/foo}bar',
    2704              e1[0].tag)
    2705
    2706 -    def test_namespaces_copy_element(self):
    2707          etree = self.etree
    2708
    2709          r = {None: 'http://ns.infrae.com/BAR'}
    2710          e1 = etree.Element('{http://ns.infrae.com/BAR}bar', nsmap=r)
    2711          e2 = etree.Element('{http://ns.infrae.com/foo}bar', nsmap=r)
    2712
    2713          e1.append(e2)
    2714
    2715          self.assertEqual(
    2716              None,
    2717              e1.prefix)
    2718          self.assertNotEqual(
    2719              None,
    2720              e2.prefix)
    2721          self.assertEqual(
    2722              '{http://ns.infrae.com/BAR}bar',
    2723              e1.tag)
    2724          self.assertEqual(
    2725              '{http://ns.infrae.com/foo}bar',
    2726              e2.tag)
    2727
    2728 -    def test_namespaces_reuse_after_move(self):
    2729          ns_href = "http://a.b.c"
    2730          one = self.etree.fromstring(
    2731              _bytes('<foo><bar xmlns:ns="%s"><ns:baz/></bar></foo>' % ns_href))
    2732          baz = one[0][0]
    2733
    2734          two = self.etree.fromstring(
    2735              _bytes('<root xmlns:ns="%s"/>' % ns_href))
    2736          two.append(baz)
    2737          del one # make sure the source document is deallocated
    2738
    2739          self.assertEqual('{%s}baz' % ns_href, baz.tag)
    2740          self.assertEqual(
    2741              _bytes('<root xmlns:ns="%s"><ns:baz/></root>' % ns_href),
    2742              self.etree.tostring(two))
    2743
    2744 -    def test_namespace_cleanup(self):
    2745          xml = _bytes(
    2746              '<foo xmlns="F" xmlns:x="x">'
    2747              '<bar xmlns:ns="NS" xmlns:b="b" xmlns="B">'
    2748              '<ns:baz/>'
    2749              '</bar></foo>'
    2750          )
    2751          root = self.etree.fromstring(xml)
    2752          self.assertEqual(xml, self.etree.tostring(root))
    2753          self.etree.cleanup_namespaces(root)
    2754          self.assertEqual(
    2755              _bytes('<foo xmlns="F"><bar xmlns:ns="NS" xmlns="B"><ns:baz/></bar></foo>'),
    2756              self.etree.tostring(root))
    2757
    2758 -    def test_namespace_cleanup_attributes(self):
    2759          xml = _bytes(
    2760              '<foo xmlns="F" xmlns:x="X" xmlns:a="A">'
    2761              '<bar xmlns:ns="NS" xmlns:b="b" xmlns="B">'
    2762              '<ns:baz a:test="attr"/>'
    2763              '</bar></foo>'
    2764          )
    2765          root = self.etree.fromstring(xml)
    2766          self.assertEqual(xml, self.etree.tostring(root))
    2767          self.etree.cleanup_namespaces(root)
    2768          self.assertEqual(
    2769              _bytes('<foo xmlns="F" xmlns:a="A">'
    2770                     '<bar xmlns:ns="NS" xmlns="B">'
    2771                     '<ns:baz a:test="attr"/>'
    2772                     '</bar></foo>'),
    2773              self.etree.tostring(root))
    2774
    2775 -    def test_namespace_cleanup_many(self):
    2776          xml = ('<n12:foo ' +
    2777                 ' '.join('xmlns:n{n}="NS{n}"'.format(n=i) for i in range(100)) +
    2778                 '><n68:a/></n12:foo>').encode('utf8')
    2779          root = self.etree.fromstring(xml)
    2780          self.assertEqual(xml, self.etree.tostring(root))
    2781          self.etree.cleanup_namespaces(root)
    2782          self.assertEqual(
    2783              b'<n12:foo xmlns:n12="NS12" xmlns:n68="NS68"><n68:a/></n12:foo>',
    2784              self.etree.tostring(root))
    2785
    2786 -    def test_namespace_cleanup_deep(self):
    2787          xml = ('<root>' +
    2788                 ''.join('<a xmlns:n{n}="NS{n}">'.format(n=i) for i in range(100)) +
    2789                 '<n64:x/>' + '</a>'*100 + '</root>').encode('utf8')
    2790          root = self.etree.fromstring(xml)
    2791          self.assertEqual(xml, self.etree.tostring(root))
    2792          self.etree.cleanup_namespaces(root)
    2793          self.assertEqual(
    2794              b'<root>' + b'<a>'*64 + b'<a xmlns:n64="NS64">' + b'<a>'*35 +
    2795              b'<n64:x/>' + b'</a>'*100 + b'</root>',
    2796              self.etree.tostring(root))
    2797
    2798 -    def test_namespace_cleanup_deep_to_top(self):
    2799          xml = ('<root>' +
    2800                 ''.join('<a xmlns:n{n}="NS{n}">'.format(n=i) for i in range(100)) +
    2801                 '<n64:x xmlns:a="A" a:attr="X"/>' +
    2802                 '</a>'*100 +
    2803                 '</root>').encode('utf8')
    2804          root = self.etree.fromstring(xml)
    2805          self.assertEqual(xml, self.etree.tostring(root))
    2806          self.etree.cleanup_namespaces(root, top_nsmap={'n64': 'NS64'})
    2807          self.assertEqual(
    2808              b'<root xmlns:n64="NS64">' + b'<a>'*100 +
    2809              b'<n64:x xmlns:a="A" a:attr="X"/>' + b'</a>'*100 + b'</root>',
    2810              self.etree.tostring(root))
    2811
    2812 -    def test_namespace_cleanup_keep_prefixes(self):
    2813          xml = ('<root xmlns:n64="NS64" xmlns:foo="FOO" xmlns:unused1="UNUSED" xmlns:no="NO">'
    2814                 '<a xmlns:unused2="UNUSED"><n64:x xmlns:a="A" a:attr="X"/></a>'
    2815                 '<foo>foo:bar</foo>'
    2816                 '</root>').encode('utf8')
    2817          root = self.etree.fromstring(xml)
    2818          self.assertEqual(xml, self.etree.tostring(root))
    2819          self.etree.cleanup_namespaces(root, keep_ns_prefixes=['foo'])
    2820          self.assertEqual(
    2821              b'<root xmlns:n64="NS64" xmlns:foo="FOO">'
    2822              b'<a><n64:x xmlns:a="A" a:attr="X"/></a>'
    2823              b'<foo>foo:bar</foo>'
    2824              b'</root>',
    2825              self.etree.tostring(root))
    2826
    2827 -    def test_namespace_cleanup_keep_prefixes_top(self):
    2828          xml = ('<root xmlns:n64="NS64" xmlns:unused1="UNUSED" xmlns:no="NO">'
    2829                 '<sub xmlns:foo="FOO">'
    2830                 '<a xmlns:unused2="UNUSED"><n64:x xmlns:a="A" a:attr="X"/></a>'
    2831                 '<foo>foo:bar</foo>'
    2832                 '</sub>'
    2833                 '</root>').encode('utf8')
    2834          root = self.etree.fromstring(xml)
    2835          self.assertEqual(xml, self.etree.tostring(root))
    2836          self.etree.cleanup_namespaces(
    2837              root,
    2838              top_nsmap={'foo': 'FOO', 'unused1': 'UNUSED'},
    2839              keep_ns_prefixes=['foo'])
    2840          self.assertEqual(
    2841              b'<root xmlns:n64="NS64" xmlns:foo="FOO">'
    2842              b'<sub>'
    2843              b'<a><n64:x xmlns:a="A" a:attr="X"/></a>'
    2844              b'<foo>foo:bar</foo>'
    2845              b'</sub>'
    2846              b'</root>',
    2847              self.etree.tostring(root))
    2848
    2849 -    def test_element_nsmap(self):
    2850          etree = self.etree
    2851
    2852          r = {None: 'http://ns.infrae.com/foo',
    2853               'hoi': 'http://ns.infrae.com/hoi'}
    2854          e = etree.Element('{http://ns.infrae.com/foo}bar', nsmap=r)
    2855          self.assertEqual(
    2856              r,
    2857              e.nsmap)
    2858
    2859 -    def test_subelement_nsmap(self):
    2860          etree = self.etree
    2861
    2862          re = {None: 'http://ns.infrae.com/foo',
    2863               'hoi': 'http://ns.infrae.com/hoi'}
    2864          e = etree.Element('{http://ns.infrae.com/foo}bar', nsmap=re)
    2865
    2866          rs = {None: 'http://ns.infrae.com/honk',
    2867               'top': 'http://ns.infrae.com/top'}
    2868          s = etree.SubElement(e, '{http://ns.infrae.com/honk}bar', nsmap=rs)
    2869
    2870          r = re.copy()
    2871          r.update(rs)
    2872          self.assertEqual(re, e.nsmap)
    2873          self.assertEqual(r,  s.nsmap)
    2874
    2875 -    def test_html_prefix_nsmap(self):
    2876          etree = self.etree
    2877          el = etree.HTML('<hha:page-description>aa</hha:page-description>').find('.//page-description')
    2878          self.assertEqual({'hha': None}, el.nsmap)
    2879
    2880 -    def test_getiterator_filter_multiple(self):
    2881          Element = self.etree.Element
    2882          SubElement = self.etree.SubElement
    2883
    2884          a = Element('a')
    2885          b = SubElement(a, 'b')
    2886          c = SubElement(a, 'c')
    2887          d = SubElement(b, 'd')
    2888          e = SubElement(c, 'e')
    2889          f = SubElement(c, 'f')
    2890
    2891          self.assertEqual(
    2892              [a, b],
    2893                 list(a.getiterator('a', 'b')))
    2894          self.assertEqual(
    2895              [],
    2896                list(a.getiterator('x', 'y')))
    2897          self.assertEqual(
    2898              [a, f],
    2899                list(a.getiterator('f', 'a')))
    2900          self.assertEqual(
    2901              [c, e, f],
    2902                 list(c.getiterator('c', '*', 'a')))
    2903          self.assertEqual(
    2904              [],
    2905                    list(a.getiterator( (), () )))
    2906
    2907 -    def test_getiterator_filter_multiple_tuple(self):
    2908          Element = self.etree.Element
    2909          SubElement = self.etree.SubElement
    2910
    2911          a = Element('a')
    2912          b = SubElement(a, 'b')
    2913          c = SubElement(a, 'c')
    2914          d = SubElement(b, 'd')
    2915          e = SubElement(c, 'e')
    2916          f = SubElement(c, 'f')
    2917
    2918          self.assertEqual(
    2919              [a, b],
    2920                    list(a.getiterator( ('a', 'b') )))
    2921          self.assertEqual(
    2922              [],
    2923                list(a.getiterator( ('x', 'y') )))
    2924          self.assertEqual(
    2925              [a, f],
    2926                    list(a.getiterator( ('f', 'a') )))
    2927          self.assertEqual(
    2928              [c, e, f],
    2929                       list(c.getiterator( ('c', '*', 'a') )))
    2930          self.assertEqual(
    2931              [],
    2932                list(a.getiterator( () )))
    2933
    2934 -    def test_getiterator_filter_namespace(self):
    2935          Element = self.etree.Element
    2936          SubElement = self.etree.SubElement
    2937
    2938          a = Element('{a}a')
    2939          b = SubElement(a, '{a}b')
    2940          c = SubElement(a, '{a}c')
    2941          d = SubElement(b, '{b}d')
    2942          e = SubElement(c, '{a}e')
    2943          f = SubElement(c, '{b}f')
    2944          g = SubElement(c, 'g')
    2945
    2946          self.assertEqual(
    2947              [a],
    2948              list(a.getiterator('{a}a')))
    2949          self.assertEqual(
    2950              [],
    2951              list(a.getiterator('{b}a')))
    2952          self.assertEqual(
    2953              [],
    2954              list(a.getiterator('a')))
    2955          self.assertEqual(
    2956              [a,b,d,c,e,f,g],
    2957              list(a.getiterator('*')))
    2958          self.assertEqual(
    2959              [f],
    2960              list(c.getiterator('{b}*')))
    2961          self.assertEqual(
    2962              [d, f],
    2963              list(a.getiterator('{b}*')))
    2964          self.assertEqual(
    2965              [g],
    2966              list(a.getiterator('g')))
    2967          self.assertEqual(
    2968              [g],
    2969              list(a.getiterator('{}g')))
    2970          self.assertEqual(
    2971              [g],
    2972              list(a.getiterator('{}*')))
    2973
    2974 -    def test_getiterator_filter_local_name(self):
    2975          Element = self.etree.Element
    2976          SubElement = self.etree.SubElement
    2977
    2978          a = Element('{a}a')
    2979          b = SubElement(a, '{nsA}b')
    2980          c = SubElement(b, '{nsB}b')
    2981          d = SubElement(a, 'b')
    2982          e = SubElement(a, '{nsA}e')
    2983          f = SubElement(e, '{nsB}e')
    2984          g = SubElement(e, 'e')
    2985
    2986          self.assertEqual(
    2987              [b, c, d],
    2988              list(a.getiterator('{*}b')))
    2989          self.assertEqual(
    2990              [e, f, g],
    2991              list(a.getiterator('{*}e')))
    2992          self.assertEqual(
    2993              [a, b, c, d, e, f, g],
    2994              list(a.getiterator('{*}*')))
    2995
    2996 -    def test_getiterator_filter_entities(self):
    2997          Element = self.etree.Element
    2998          Entity = self.etree.Entity
    2999          SubElement = self.etree.SubElement
    3000
    3001          a = Element('a')
    3002          b = SubElement(a, 'b')
    3003          entity_b = Entity("TEST-b")
    3004          b.append(entity_b)
    3005
    3006          self.assertEqual(
    3007              [entity_b],
    3008              list(a.getiterator(Entity)))
    3009
    3010          entity_a = Entity("TEST-a")
    3011          a.append(entity_a)
    3012
    3013          self.assertEqual(
    3014              [entity_b, entity_a],
    3015              list(a.getiterator(Entity)))
    3016
    3017          self.assertEqual(
    3018              [entity_b],
    3019              list(b.getiterator(Entity)))
    3020
    3021 -    def test_getiterator_filter_element(self):
    3022          Element = self.etree.Element
    3023          Comment = self.etree.Comment
    3024          PI = self.etree.PI
    3025          SubElement = self.etree.SubElement
    3026
    3027          a = Element('a')
    3028          b = SubElement(a, 'b')
    3029          a.append(Comment("test"))
    3030          a.append(PI("pi", "content"))
    3031          c = SubElement(a, 'c')
    3032
    3033          self.assertEqual(
    3034              [a, b, c],
    3035              list(a.getiterator(Element)))
    3036
    3037 -    def test_getiterator_filter_all_comment_pi(self):
    3038          # ElementTree iterates over everything here
    3039          Element = self.etree.Element
    3040          Comment = self.etree.Comment
    3041          PI = self.etree.PI
    3042          SubElement = self.etree.SubElement
    3043
    3044          a = Element('a')
    3045          b = SubElement(a, 'b')
    3046          a.append(Comment("test"))
    3047          a.append(PI("pi", "content"))
    3048          c = SubElement(a, 'c')
    3049
    3050          self.assertEqual(
    3051              [a, b, c],
    3052              list(a.getiterator('*')))
    3053
    3054 -    def test_elementtree_getelementpath(self):
    3055          a  = etree.Element("a")
    3056          b  = etree.SubElement(a, "b")
    3057          c  = etree.SubElement(a, "c")
    3058          d1 = etree.SubElement(c, "d")
    3059          d2 = etree.SubElement(c, "d")
    3060          c.text = d1.text = 'TEXT'
    3061
    3062          tree = etree.ElementTree(a)
    3063          self.assertEqual('.', tree.getelementpath(a))
    3064          self.assertEqual('c/d[1]', tree.getelementpath(d1))
    3065          self.assertEqual('c/d[2]', tree.getelementpath(d2))
    3066
    3067          self.assertEqual(d1, tree.find(tree.getelementpath(d1)))
    3068          self.assertEqual(d2, tree.find(tree.getelementpath(d2)))
    3069
    3070          tree = etree.ElementTree(c)
    3071          self.assertEqual('.', tree.getelementpath(c))
    3072          self.assertEqual('d[2]', tree.getelementpath(d2))
    3073          self.assertEqual(d2, tree.find(tree.getelementpath(d2)))
    3074
    3075          tree = etree.ElementTree(b)  # not a parent of a/c/d1/d2
    3076          self.assertEqual('.', tree.getelementpath(b))
    3077          self.assertRaises(ValueError, tree.getelementpath, a)
    3078          self.assertRaises(ValueError, tree.getelementpath, c)
    3079          self.assertRaises(ValueError, tree.getelementpath, d2)
    3080
    3081 -    def test_elementtree_getelementpath_ns(self):
    3082          a  = etree.Element("{http://ns1/}a")
    3083          b  = etree.SubElement(a, "{http://ns1/}b")
    3084          c  = etree.SubElement(a, "{http://ns1/}c")
    3085          d1 = etree.SubElement(c, "{http://ns1/}d")
    3086          d2 = etree.SubElement(c, "{http://ns2/}d")
    3087          d3 = etree.SubElement(c, "{http://ns1/}d")
    3088
    3089          tree = etree.ElementTree(a)
    3090          self.assertEqual('.', tree.getelementpath(a))
    3091          self.assertEqual('{http://ns1/}c/{http://ns1/}d[1]',
    3092                           tree.getelementpath(d1))
    3093          self.assertEqual('{http://ns1/}c/{http://ns2/}d',
    3094                           tree.getelementpath(d2))
    3095          self.assertEqual('{http://ns1/}c/{http://ns1/}d[2]',
    3096                           tree.getelementpath(d3))
    3097
    3098          self.assertEqual(a, tree.find(tree.getelementpath(a)))
    3099          self.assertEqual(b, tree.find(tree.getelementpath(b)))
    3100          self.assertEqual(c, tree.find(tree.getelementpath(c)))
    3101          self.assertEqual(d1, tree.find(tree.getelementpath(d1)))
    3102          self.assertEqual(d2, tree.find(tree.getelementpath(d2)))
    3103          self.assertEqual(d3, tree.find(tree.getelementpath(d3)))
    3104
    3105          tree = etree.ElementTree(c)
    3106          self.assertEqual('{http://ns1/}d[1]', tree.getelementpath(d1))
    3107          self.assertEqual('{http://ns2/}d', tree.getelementpath(d2))
    3108          self.assertEqual('{http://ns1/}d[2]', tree.getelementpath(d3))
    3109          self.assertEqual(d1, tree.find(tree.getelementpath(d1)))
    3110          self.assertEqual(d2, tree.find(tree.getelementpath(d2)))
    3111          self.assertEqual(d3, tree.find(tree.getelementpath(d3)))
    3112
    3113          tree = etree.ElementTree(b)  # not a parent of d1/d2
    3114          self.assertRaises(ValueError, tree.getelementpath, d1)
    3115          self.assertRaises(ValueError, tree.getelementpath, d2)
    3116
    3117 -    def test_elementtree_find_qname(self):
    3118          XML = self.etree.XML
    3119          ElementTree = self.etree.ElementTree
    3120          QName = self.etree.QName
    3121          tree = ElementTree(XML(_bytes('<a><b><c/></b><b/><c><b/></c></a>')))
    3122          self.assertEqual(tree.find(QName("c")), tree.getroot()[2])
    3123
    3124 -    def test_elementtree_findall_qname(self):
    3125          XML = self.etree.XML
    3126          ElementTree = self.etree.ElementTree
    3127          QName = self.etree.QName
    3128          tree = ElementTree(XML(_bytes('<a><b><c/></b><b/><c><b/></c></a>')))
    3129          self.assertEqual(len(list(tree.findall(QName("c")))), 1)
    3130
    3131 -    def test_elementtree_findall_ns_qname(self):
    3132          XML = self.etree.XML
    3133          ElementTree = self.etree.ElementTree
    3134          QName = self.etree.QName
    3135          tree = ElementTree(XML(
    3136                  _bytes('<a xmlns:x="X" xmlns:y="Y"><x:b><c/></x:b><b/><c><x:b/><b/></c><b/></a>')))
    3137          self.assertEqual(len(list(tree.findall(QName("b")))), 2)
    3138          self.assertEqual(len(list(tree.findall(QName("X", "b")))), 1)
    3139
    3140 -    def test_findall_ns(self):
    3141          XML = self.etree.XML
    3142          root = XML(_bytes('<a xmlns:x="X" xmlns:y="Y"><x:b><c/></x:b><b/><c><x:b/><b/></c><b/></a>'))
    3143          self.assertEqual(len(root.findall(".//{X}b")), 2)
    3144          self.assertEqual(len(root.findall(".//{X}*")), 2)
    3145          self.assertEqual(len(root.findall(".//b")), 3)
    3146
    3147 -    def test_findall_different_nsmaps(self):
    3148          XML = self.etree.XML
    3149          root = XML(_bytes('<a xmlns:x="X" xmlns:y="Y"><x:b><c/></x:b><b/><c><x:b/><b/></c><y:b/></a>'))
    3150          nsmap = {'xx': 'X'}
    3151          self.assertEqual(len(root.findall(".//xx:b", namespaces=nsmap)), 2)
    3152          self.assertEqual(len(root.findall(".//xx:*", namespaces=nsmap)), 2)
    3153          self.assertEqual(len(root.findall(".//b", namespaces=nsmap)), 2)
    3154          nsmap = {'xx': 'Y'}
    3155          self.assertEqual(len(root.findall(".//xx:b", namespaces=nsmap)), 1)
    3156          self.assertEqual(len(root.findall(".//xx:*", namespaces=nsmap)), 1)
    3157          self.assertEqual(len(root.findall(".//b", namespaces=nsmap)), 2)
    3158
    3159 -    def test_findall_empty_prefix(self):
    3160          XML = self.etree.XML
    3161          root = XML(_bytes('<a xmlns:x="X" xmlns:y="Y"><x:b><c/></x:b><b/><c><x:b/><b/></c><y:b/></a>'))
    3162          nsmap = {'xx': 'X'}
    3163          self.assertEqual(len(root.findall(".//xx:b", namespaces=nsmap)), 2)
    3164          nsmap = {'xx': 'X', None: 'Y'}
    3165          self.assertEqual(len(root.findall(".//b", namespaces=nsmap)), 1)
    3166          nsmap = {'xx': 'X', '': 'Y'}
    3167          self.assertRaises(ValueError, root.findall, ".//xx:b", namespaces=nsmap)
    3168
    3169 -    def test_findall_syntax_error(self):
    3170          XML = self.etree.XML
    3171          root = XML(_bytes('<a><b><c/></b><b/><c><b/><b/></c><b/></a>'))
    3172          self.assertRaises(SyntaxError, root.findall, '')
    3173          self.assertRaises(SyntaxError, root.findall, '//')  # absolute path on Element
    3174          self.assertRaises(SyntaxError, root.findall, './//')
    3175
    3176 -    def test_index(self):
    3177          etree = self.etree
    3178          e = etree.Element('foo')
    3179          for i in range(10):
    3180              etree.SubElement(e, 'a%s' % i)
    3181          for i in range(10):
    3182              self.assertEqual(
    3183                  i,
    3184                  e.index(e[i]))
    3185          self.assertEqual(
    3186              3, e.index(e[3], 3))
    3187          self.assertRaises(
    3188              ValueError, e.index, e[3], 4)
    3189          self.assertRaises(
    3190              ValueError, e.index, e[3], 0, 2)
    3191          self.assertRaises(
    3192              ValueError, e.index, e[8], 0, -3)
    3193          self.assertRaises(
    3194              ValueError, e.index, e[8], -5, -3)
    3195          self.assertEqual(
    3196              8, e.index(e[8], 0, -1))
    3197          self.assertEqual(
    3198              8, e.index(e[8], -12, -1))
    3199          self.assertEqual(
    3200              0, e.index(e[0], -12, -1))
    3201
    3202 -    def test_replace(self):
    3203          etree = self.etree
    3204          e = etree.Element('foo')
    3205          for i in range(10):
    3206              el = etree.SubElement(e, 'a%s' % i)
    3207              el.text = "text%d" % i
    3208              el.tail = "tail%d" % i
    3209
    3210          child0 = e[0]
    3211          child1 = e[1]
    3212          child2 = e[2]
    3213
    3214          e.replace(e[0], e[1])
    3215          self.assertEqual(
    3216              9, len(e))
    3217          self.assertEqual(
    3218              child1, e[0])
    3219          self.assertEqual(
    3220              child1.text, "text1")
    3221          self.assertEqual(
    3222              child1.tail, "tail1")
    3223          self.assertEqual(
    3224              child0.tail, "tail0")
    3225          self.assertEqual(
    3226              child2, e[1])
    3227
    3228          e.replace(e[-1], e[0])
    3229          self.assertEqual(
    3230              child1, e[-1])
    3231          self.assertEqual(
    3232              child1.text, "text1")
    3233          self.assertEqual(
    3234              child1.tail, "tail1")
    3235          self.assertEqual(
    3236              child2, e[0])
    3237
    3238 -    def test_replace_new(self):
    3239          etree = self.etree
    3240          e = etree.Element('foo')
    3241          for i in range(10):
    3242              etree.SubElement(e, 'a%s' % i)
    3243
    3244          new_element = etree.Element("test")
    3245          new_element.text = "TESTTEXT"
    3246          new_element.tail = "TESTTAIL"
    3247          child1 = e[1]
    3248          e.replace(e[0], new_element)
    3249          self.assertEqual(
    3250              new_element, e[0])
    3251          self.assertEqual(
    3252              "TESTTEXT",
    3253              e[0].text)
    3254          self.assertEqual(
    3255              "TESTTAIL",
    3256              e[0].tail)
    3257          self.assertEqual(
    3258              child1, e[1])
    3259
    3260 -    def test_setslice_all_empty_reversed(self):
    3261          Element = self.etree.Element
    3262          SubElement = self.etree.SubElement
    3263
    3264          a = Element('a')
    3265
    3266          e = Element('e')
    3267          f = Element('f')
    3268          g = Element('g')
    3269
    3270          s = [e, f, g]
    3271          a[::-1] = s
    3272          self.assertEqual(
    3273              [g, f, e],
    3274              list(a))
    3275
    3276 -    def test_setslice_step(self):
    3277          Element = self.etree.Element
    3278          SubElement = self.etree.SubElement
    3279
    3280          a = Element('a')
    3281          b = SubElement(a, 'b')
    3282          c = SubElement(a, 'c')
    3283          d = SubElement(a, 'd')
    3284          e = SubElement(a, 'e')
    3285
    3286          x = Element('x')
    3287          y = Element('y')
    3288
    3289          a[1::2] = [x, y]
    3290          self.assertEqual(
    3291              [b, x, d, y],
    3292              list(a))
    3293
    3294 -    def test_setslice_step_negative(self):
    3295          Element = self.etree.Element
    3296          SubElement = self.etree.SubElement
    3297
    3298          a = Element('a')
    3299          b = SubElement(a, 'b')
    3300          c = SubElement(a, 'c')
    3301          d = SubElement(a, 'd')
    3302          e = SubElement(a, 'e')
    3303
    3304          x = Element('x')
    3305          y = Element('y')
    3306
    3307          a[1::-1] = [x, y]
    3308          self.assertEqual(
    3309              [y, x, d, e],
    3310              list(a))
    3311
    3312 -    def test_setslice_step_negative2(self):
    3313          Element = self.etree.Element
    3314          SubElement = self.etree.SubElement
    3315
    3316          a = Element('a')
    3317          b = SubElement(a, 'b')
    3318          c = SubElement(a, 'c')
    3319          d = SubElement(a, 'd')
    3320          e = SubElement(a, 'e')
    3321
    3322          x = Element('x')
    3323          y = Element('y')
    3324
    3325          a[::-2] = [x, y]
    3326          self.assertEqual(
    3327              [b, y, d, x],
    3328              list(a))
    3329
    3330 -    def test_setslice_step_overrun(self):
    3331          Element = self.etree.Element
    3332          SubElement = self.etree.SubElement
    3333          try:
    3334              slice
    3335          except NameError:
    3336              print("slice() not found")
    3337              return
    3338
    3339          a = Element('a')
    3340          b = SubElement(a, 'b')
    3341          c = SubElement(a, 'c')
    3342          d = SubElement(a, 'd')
    3343          e = SubElement(a, 'e')
    3344
    3345          x = Element('x')
    3346          y = Element('y')
    3347          z = Element('z')
    3348
    3349          self.assertRaises(
    3350              ValueError,
    3351              operator.setitem, a, slice(1,None,2), [x, y, z])
    3352
    3353          self.assertEqual(
    3354              [b, c, d, e],
    3355              list(a))
    3356
    3357 -    def test_sourceline_XML(self):
    3358          XML = self.etree.XML
    3359          root = XML(_bytes('''<?xml version="1.0"?>
    3360          <root><test>
    3361
    3362          <bla/></test>
    3363          </root>
    3364          '''))
    3365
    3366          self.assertEqual(
    3367              [2, 2, 4],
    3368              [ el.sourceline for el in root.getiterator() ])
    3369
    3370 -    def test_large_sourceline_XML(self):
    3371          XML = self.etree.XML
    3372          root = XML(_bytes(
    3373              '<?xml version="1.0"?>\n'
    3374              '<root>' + '\n' * 65536 +
    3375              '<p>' + '\n' * 65536 + '</p>\n' +
    3376              '<br/>\n'
    3377              '</root>'))
    3378
    3379          if self.etree.LIBXML_VERSION >= (2, 9):
    3380              expected = [2, 131074, 131076]
    3381          else:
    3382              expected = [2, 65535, 65535]
    3383
    3384          self.assertEqual(expected, [el.sourceline for el in root.iter()])
    3385
    3386 -    def test_sourceline_parse(self):
    3387          parse = self.etree.parse
    3388          tree = parse(fileInTestDir('include/test_xinclude.xml'))
    3389
    3390          self.assertEqual(
    3391              [1, 2, 3],
    3392              [ el.sourceline for el in tree.getiterator() ])
    3393
    3394 -    def test_sourceline_iterparse_end(self):
    3395          iterparse = self.etree.iterparse
    3396          lines = [ el.sourceline for (event, el) in
    3397                    iterparse(fileInTestDir('include/test_xinclude.xml')) ]
    3398
    3399          self.assertEqual(
    3400              [2, 3, 1],
    3401              lines)
    3402
    3403 -    def test_sourceline_iterparse_start(self):
    3404          iterparse = self.etree.iterparse
    3405          lines = [ el.sourceline for (event, el) in
    3406                    iterparse(fileInTestDir('include/test_xinclude.xml'),
    3407                              events=("start",)) ]
    3408
    3409          self.assertEqual(
    3410              [1, 2, 3],
    3411              lines)
    3412
    3413 -    def test_sourceline_element(self):
    3414          Element = self.etree.Element
    3415          SubElement = self.etree.SubElement
    3416          el = Element("test")
    3417          self.assertEqual(None, el.sourceline)
    3418
    3419          child = SubElement(el, "test")
    3420          self.assertEqual(None, el.sourceline)
    3421          self.assertEqual(None, child.sourceline)
    3422
    3423 -    def test_XML_base_url_docinfo(self):
    3424          etree = self.etree
    3425          root = etree.XML(_bytes("<root/>"), base_url="http://no/such/url")
    3426          docinfo = root.getroottree().docinfo
    3427          self.assertEqual(docinfo.URL, "http://no/such/url")
    3428
    3429 -    def test_XML_set_base_url_docinfo(self):
    3430          etree = self.etree
    3431          root = etree.XML(_bytes("<root/>"), base_url="http://no/such/url")
    3432          docinfo = root.getroottree().docinfo
    3433          self.assertEqual(docinfo.URL, "http://no/such/url")
    3434          docinfo.URL = "https://secret/url"
    3435          self.assertEqual(docinfo.URL, "https://secret/url")
    3436
    3437 -    def test_parse_stringio_base_url(self):
    3438          etree = self.etree
    3439          tree = etree.parse(BytesIO("<root/>"), base_url="http://no/such/url")
    3440          docinfo = tree.docinfo
    3441          self.assertEqual(docinfo.URL, "http://no/such/url")
    3442
    3443 -    def test_parse_base_url_docinfo(self):
    3444          etree = self.etree
    3445          tree = etree.parse(fileInTestDir('include/test_xinclude.xml'),
    3446                             base_url="http://no/such/url")
    3447          docinfo = tree.docinfo
    3448          self.assertEqual(docinfo.URL, "http://no/such/url")
    3449
    3450 -    def test_HTML_base_url_docinfo(self):
    3451          etree = self.etree
    3452          root = etree.HTML(_bytes("<html/>"), base_url="http://no/such/url")
    3453          docinfo = root.getroottree().docinfo
    3454          self.assertEqual(docinfo.URL, "http://no/such/url")
    3455
    3456 -    def test_docinfo_public(self):
    3457          etree = self.etree
    3458          xml_header = '<?xml version="1.0" encoding="ascii"?>'
    3459          pub_id = "-//W3C//DTD XHTML 1.0 Transitional//EN"
    3460          sys_id = "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"
    3461          doctype_string = '<!DOCTYPE html PUBLIC "%s" "%s">' % (pub_id, sys_id)
    3462
    3463          xml = _bytes(xml_header + doctype_string + '<html><body></body></html>')
    3464
    3465          tree = etree.parse(BytesIO(xml))
    3466          docinfo = tree.docinfo
    3467          self.assertEqual(docinfo.encoding,    "ascii")
    3468          self.assertEqual(docinfo.xml_version, "1.0")
    3469          self.assertEqual(docinfo.public_id,   pub_id)
    3470          self.assertEqual(docinfo.system_url,  sys_id)
    3471          self.assertEqual(docinfo.root_name,   'html')
    3472          self.assertEqual(docinfo.doctype, doctype_string)
    3473
    3474 -    def test_docinfo_system(self):
    3475          etree = self.etree
    3476          xml_header = '<?xml version="1.0" encoding="UTF-8"?>'
    3477          sys_id = "some.dtd"
    3478          doctype_string = '<!DOCTYPE html SYSTEM "%s">' % sys_id
    3479          xml = _bytes(xml_header + doctype_string + '<html><body></body></html>')
    3480
    3481          tree = etree.parse(BytesIO(xml))
    3482          docinfo = tree.docinfo
    3483          self.assertEqual(docinfo.encoding,    "UTF-8")
    3484          self.assertEqual(docinfo.xml_version, "1.0")
    3485          self.assertEqual(docinfo.public_id,   None)
    3486          self.assertEqual(docinfo.system_url,  sys_id)
    3487          self.assertEqual(docinfo.root_name,   'html')
    3488          self.assertEqual(docinfo.doctype, doctype_string)
    3489
    3490 -    def test_docinfo_empty(self):
    3491          etree = self.etree
    3492          xml = _bytes('<html><body></body></html>')
    3493          tree = etree.parse(BytesIO(xml))
    3494          docinfo = tree.docinfo
    3495          self.assertEqual(docinfo.encoding,    "UTF-8")
    3496          self.assertEqual(docinfo.xml_version, "1.0")
    3497          self.assertEqual(docinfo.public_id,   None)
    3498          self.assertEqual(docinfo.system_url,  None)
    3499          self.assertEqual(docinfo.root_name,   'html')
    3500          self.assertEqual(docinfo.doctype, '')
    3501
    3502 -    def test_docinfo_name_only(self):
    3503          etree = self.etree
    3504          xml = _bytes('<!DOCTYPE root><root></root>')
    3505          tree = etree.parse(BytesIO(xml))
    3506          docinfo = tree.docinfo
    3507          self.assertEqual(docinfo.encoding,    "UTF-8")
    3508          self.assertEqual(docinfo.xml_version, "1.0")
    3509          self.assertEqual(docinfo.public_id,   None)
    3510          self.assertEqual(docinfo.system_url,  None)
    3511          self.assertEqual(docinfo.root_name,   'root')
    3512          self.assertEqual(docinfo.doctype, '<!DOCTYPE root>')
    3513
    3514 -    def test_doctype_name_only_roundtrip(self):
    3515          etree = self.etree
    3516          xml = _bytes('<!DOCTYPE root>\n<root/>')
    3517          tree = etree.parse(BytesIO(xml))
    3518          self.assertEqual(xml, etree.tostring(tree))
    3519
    3520 -    def test_doctype_output_override(self):
    3521          etree = self.etree
    3522          pub_id = "-//W3C//DTD XHTML 1.0 Transitional//EN"
    3523          sys_id = "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"
    3524          doctype_string = _bytes('<!DOCTYPE html PUBLIC "%s" "%s">' % (pub_id, sys_id))
    3525
    3526          xml = _bytes('<!DOCTYPE root>\n<root/>')
    3527          tree = etree.parse(BytesIO(xml))
    3528          self.assertEqual(xml.replace(_bytes('<!DOCTYPE root>'), doctype_string),
    3529                            etree.tostring(tree, doctype=doctype_string))
    3530
    3531 -    def test_xml_base(self):
    3532          etree = self.etree
    3533          root = etree.XML(_bytes("<root/>"), base_url="http://no/such/url")
    3534          self.assertEqual(root.base, "http://no/such/url")
    3535          self.assertEqual(
    3536              root.get('{http://www.w3.org/XML/1998/namespace}base'), None)
    3537          root.base = "https://secret/url"
    3538          self.assertEqual(root.base, "https://secret/url")
    3539          self.assertEqual(
    3540              root.get('{http://www.w3.org/XML/1998/namespace}base'),
    3541              "https://secret/url")
    3542
    3543 -    def test_xml_base_attribute(self):
    3544          etree = self.etree
    3545          root = etree.XML(_bytes("<root/>"), base_url="http://no/such/url")
    3546          self.assertEqual(root.base, "http://no/such/url")
    3547          self.assertEqual(
    3548              root.get('{http://www.w3.org/XML/1998/namespace}base'), None)
    3549          root.set('{http://www.w3.org/XML/1998/namespace}base',
    3550                   "https://secret/url")
    3551          self.assertEqual(root.base, "https://secret/url")
    3552          self.assertEqual(
    3553              root.get('{http://www.w3.org/XML/1998/namespace}base'),
    3554              "https://secret/url")
    3555
    3556 -    def test_html_base(self):
    3557          etree = self.etree
    3558          root = etree.HTML(_bytes("<html><body></body></html>"),
    3559                            base_url="http://no/such/url")
    3560          self.assertEqual(root.base, "http://no/such/url")
    3561
    3562 -    def test_html_base_tag(self):
    3563          etree = self.etree
    3564          root = etree.HTML(_bytes('<html><head><base href="http://no/such/url"></head></html>'))
    3565          self.assertEqual(root.base, "http://no/such/url")
    3566
    3567 -    def test_parse_fileobject_unicode(self):
    3568          # parse from a file object that returns unicode strings
    3569          f = LargeFileLikeUnicode()
    3570          tree = self.etree.parse(f)
    3571          root = tree.getroot()
    3572          self.assertTrue(root.tag.endswith('root'))
    3573
    3574 -    def test_dtd_io(self):
    3575          # check that DTDs that go in also go back out
    3576          xml = _bytes('''\
    3577          <!DOCTYPE test SYSTEM "test.dtd" [
    3578            <!ENTITY entity "tasty">
    3579            <!ELEMENT test (a)>
    3580            <!ELEMENT a (#PCDATA)>
    3581          ]>
    3582          <test><a>test-test</a></test>\
    3583          ''')
    3584          tree = self.etree.parse(BytesIO(xml))
    3585          self.assertEqual(self.etree.tostring(tree).replace(_bytes(" "), _bytes("")),
    3586                           xml.replace(_bytes(" "), _bytes("")))
    3587
    3588 -    def test_byte_zero(self):
    3589          Element = self.etree.Element
    3590
    3591          a = Element('a')
    3592          self.assertRaises(ValueError, setattr, a, "text", 'ha\0ho')
    3593          self.assertRaises(ValueError, setattr, a, "tail", 'ha\0ho')
    3594
    3595          self.assertRaises(ValueError, Element, 'ha\0ho')
    3596
    3597 -    def test_unicode_byte_zero(self):
    3598          Element = self.etree.Element
    3599
    3600          a = Element('a')
    3601          self.assertRaises(ValueError, setattr, a, "text",
    3602                            _str('ha\0ho'))
    3603          self.assertRaises(ValueError, setattr, a, "tail",
    3604                            _str('ha\0ho'))
    3605
    3606          self.assertRaises(ValueError, Element,
    3607                            _str('ha\0ho'))
    3608
    3609 -    def test_byte_invalid(self):
    3610          Element = self.etree.Element
    3611
    3612          a = Element('a')
    3613          self.assertRaises(ValueError, setattr, a, "text", 'ha\x07ho')
    3614          self.assertRaises(ValueError, setattr, a, "text", 'ha\x02ho')
    3615
    3616          self.assertRaises(ValueError, setattr, a, "tail", 'ha\x07ho')
    3617          self.assertRaises(ValueError, setattr, a, "tail", 'ha\x02ho')
    3618
    3619          self.assertRaises(ValueError, Element, 'ha\x07ho')
    3620          self.assertRaises(ValueError, Element, 'ha\x02ho')
    3621
    3622 -    def test_unicode_byte_invalid(self):
    3623          Element = self.etree.Element
    3624
    3625          a = Element('a')
    3626          self.assertRaises(ValueError, setattr, a, "text",
    3627                            _str('ha\x07ho'))
    3628          self.assertRaises(ValueError, setattr, a, "text",
    3629                            _str('ha\x02ho'))
    3630
    3631          self.assertRaises(ValueError, setattr, a, "tail",
    3632                            _str('ha\x07ho'))
    3633          self.assertRaises(ValueError, setattr, a, "tail",
    3634                            _str('ha\x02ho'))
    3635
    3636          self.assertRaises(ValueError, Element,
    3637                            _str('ha\x07ho'))
    3638          self.assertRaises(ValueError, Element,
    3639                            _str('ha\x02ho'))
    3640
    3641 -    def test_unicode_byte_invalid_sequence(self):
    3642          Element = self.etree.Element
    3643
    3644          a = Element('a')
    3645          self.assertRaises(ValueError, setattr, a, "text",
    3646                            _str('ha\u1234\x07ho'))
    3647          self.assertRaises(ValueError, setattr, a, "text",
    3648                            _str('ha\u1234\x02ho'))
    3649
    3650          self.assertRaises(ValueError, setattr, a, "tail",
    3651                            _str('ha\u1234\x07ho'))
    3652          self.assertRaises(ValueError, setattr, a, "tail",
    3653                            _str('ha\u1234\x02ho'))
    3654
    3655          self.assertRaises(ValueError, Element,
    3656                            _str('ha\u1234\x07ho'))
    3657          self.assertRaises(ValueError, Element,
    3658                            _str('ha\u1234\x02ho'))
    3659
    3660 -    def test_encoding_tostring_utf16(self):
    3661          # ElementTree fails to serialize this
    3662          tostring = self.etree.tostring
    3663          Element = self.etree.Element
    3664          SubElement = self.etree.SubElement
    3665
    3666          a = Element('a')
    3667          b = SubElement(a, 'b')
    3668          c = SubElement(a, 'c')
    3669
    3670          result = tostring(a, encoding='UTF-16')
    3671          self.assertEqual(_bytes('<a><b></b><c></c></a>'),
    3672                            canonicalize(result))
    3673
    3674 -    def test_tostring_none(self):
    3675          # ElementTree raises an AssertionError here
    3676          tostring = self.etree.tostring
    3677          self.assertRaises(TypeError, self.etree.tostring, None)
    3678
    3679 -    def test_tostring_pretty(self):
    3680          tostring = self.etree.tostring
    3681          Element = self.etree.Element
    3682          SubElement = self.etree.SubElement
    3683
    3684          a = Element('a')
    3685          b = SubElement(a, 'b')
    3686          c = SubElement(a, 'c')
    3687
    3688          result = tostring(a)
    3689          self.assertEqual(result, _bytes("<a><b/><c/></a>"))
    3690
    3691          result = tostring(a, pretty_print=False)
    3692          self.assertEqual(result, _bytes("<a><b/><c/></a>"))
    3693
    3694          result = tostring(a, pretty_print=True)
    3695          self.assertEqual(result, _bytes("<a>\n  <b/>\n  <c/>\n</a>\n"))
    3696
    3697 -    def test_tostring_with_tail(self):
    3698          tostring = self.etree.tostring
    3699          Element = self.etree.Element
    3700          SubElement = self.etree.SubElement
    3701
    3702          a = Element('a')
    3703          a.tail = "aTAIL"
    3704          b = SubElement(a, 'b')
    3705          b.tail = "bTAIL"
    3706          c = SubElement(a, 'c')
    3707
    3708          result = tostring(a)
    3709          self.assertEqual(result, _bytes("<a><b/>bTAIL<c/></a>aTAIL"))
    3710
    3711          result = tostring(a, with_tail=False)
    3712          self.assertEqual(result, _bytes("<a><b/>bTAIL<c/></a>"))
    3713
    3714          result = tostring(a, with_tail=True)
    3715          self.assertEqual(result, _bytes("<a><b/>bTAIL<c/></a>aTAIL"))
    3716
    3717 -    def test_tostring_method_html_with_tail(self):
    3718          tostring = self.etree.tostring
    3719          html = self.etree.fromstring(
    3720              '<html><body>'
    3721              '<div><p>Some text<i>\r\n</i></p></div>\r\n'
    3722              '</body></html>',
    3723              parser=self.etree.HTMLParser())
    3724          self.assertEqual(html.tag, 'html')
    3725          div = html.find('.//div')
    3726          self.assertEqual(div.tail, '\r\n')
    3727          result = tostring(div, method='html')
    3728          self.assertEqual(
    3729              result,
    3730              _bytes("<div><p>Some text<i>\r\n</i></p></div>\r\n"))
    3731          result = tostring(div, method='html', with_tail=True)
    3732          self.assertEqual(
    3733              result,
    3734              _bytes("<div><p>Some text<i>\r\n</i></p></div>\r\n"))
    3735          result = tostring(div, method='html', with_tail=False)
    3736          self.assertEqual(
    3737              result,
    3738              _bytes("<div><p>Some text<i>\r\n</i></p></div>"))
    3739
    3740 -    def test_standalone(self):
    3741          tostring = self.etree.tostring
    3742          XML = self.etree.XML
    3743          ElementTree = self.etree.ElementTree
    3744          Element = self.etree.Element
    3745
    3746          tree = Element("root").getroottree()
    3747          self.assertEqual(None, tree.docinfo.standalone)
    3748
    3749          tree = XML(_bytes("<root/>")).getroottree()
    3750          self.assertEqual(None, tree.docinfo.standalone)
    3751
    3752          tree = XML(_bytes(
    3753              "<?xml version='1.0' encoding='ASCII' standalone='yes'?>\n<root/>"
    3754              )).getroottree()
    3755          self.assertEqual(True, tree.docinfo.standalone)
    3756
    3757          tree = XML(_bytes(
    3758              "<?xml version='1.0' encoding='ASCII' standalone='no'?>\n<root/>"
    3759              )).getroottree()
    3760          self.assertEqual(False, tree.docinfo.standalone)
    3761
    3762 -    def test_tostring_standalone(self):
    3763          tostring = self.etree.tostring
    3764          XML = self.etree.XML
    3765          ElementTree = self.etree.ElementTree
    3766
    3767          root = XML(_bytes("<root/>"))
    3768
    3769          tree = ElementTree(root)
    3770          self.assertEqual(None, tree.docinfo.standalone)
    3771
    3772          result = tostring(root, xml_declaration=True, encoding="ASCII")
    3773          self.assertEqual(result, _bytes(
    3774              "<?xml version='1.0' encoding='ASCII'?>\n<root/>"))
    3775
    3776          result = tostring(root, xml_declaration=True, encoding="ASCII",
    3777                            standalone=True)
    3778          self.assertEqual(result, _bytes(
    3779              "<?xml version='1.0' encoding='ASCII' standalone='yes'?>\n<root/>"))
    3780
    3781          tree = ElementTree(XML(result))
    3782          self.assertEqual(True, tree.docinfo.standalone)
    3783
    3784          result = tostring(root, xml_declaration=True, encoding="ASCII",
    3785                            standalone=False)
    3786          self.assertEqual(result, _bytes(
    3787              "<?xml version='1.0' encoding='ASCII' standalone='no'?>\n<root/>"))
    3788
    3789          tree = ElementTree(XML(result))
    3790          self.assertEqual(False, tree.docinfo.standalone)
    3791
    3792 -    def test_tostring_standalone_in_out(self):
    3793          tostring = self.etree.tostring
    3794          XML = self.etree.XML
    3795          ElementTree = self.etree.ElementTree
    3796
    3797          root = XML(_bytes(
    3798              "<?xml version='1.0' encoding='UTF-8' standalone='yes'?>\n<root/>"))
    3799
    3800          tree = ElementTree(root)
    3801          self.assertEqual(True, tree.docinfo.standalone)
    3802
    3803          result = tostring(root, xml_declaration=True, encoding="ASCII")
    3804          self.assertEqual(result, _bytes(
    3805              "<?xml version='1.0' encoding='ASCII'?>\n<root/>"))
    3806
    3807          result = tostring(root, xml_declaration=True, encoding="ASCII",
    3808                            standalone=True)
    3809          self.assertEqual(result, _bytes(
    3810              "<?xml version='1.0' encoding='ASCII' standalone='yes'?>\n<root/>"))
    3811
    3812 -    def test_tostring_method_text_encoding(self):
    3813          tostring = self.etree.tostring
    3814          Element = self.etree.Element
    3815          SubElement = self.etree.SubElement
    3816
    3817          a = Element('a')
    3818          a.text = "A"
    3819          a.tail = "tail"
    3820          b = SubElement(a, 'b')
    3821          b.text = "B"
    3822          b.tail = _str("Søk på nettet")
    3823          c = SubElement(a, 'c')
    3824          c.text = "C"
    3825
    3826          result = tostring(a, method="text", encoding="UTF-16")
    3827
    3828          self.assertEqual(_str('ABSøk på nettetCtail').encode("UTF-16"),
    3829                            result)
    3830
    3831 -    def test_tostring_method_text_unicode(self):
    3832          tostring = self.etree.tostring
    3833          Element = self.etree.Element
    3834          SubElement = self.etree.SubElement
    3835
    3836          a = Element('a')
    3837          a.text = _str('Søk på nettetA')
    3838          a.tail = "tail"
    3839          b = SubElement(a, 'b')
    3840          b.text = "B"
    3841          b.tail = _str('Søk på nettetB')
    3842          c = SubElement(a, 'c')
    3843          c.text = "C"
    3844
    3845          self.assertRaises(UnicodeEncodeError,
    3846                            tostring, a, method="text")
    3847
    3848          self.assertEqual(
    3849              _str('Søk på nettetABSøk på nettetBCtail').encode('utf-8'),
    3850              tostring(a, encoding="UTF-8", method="text"))
    3851
    3852 -    def test_tounicode(self):
    3853          tounicode = self.etree.tounicode
    3854          Element = self.etree.Element
    3855          SubElement = self.etree.SubElement
    3856
    3857          a = Element('a')
    3858          b = SubElement(a, 'b')
    3859          c = SubElement(a, 'c')
    3860
    3861          self.assertTrue(isinstance(tounicode(a), _unicode))
    3862          self.assertEqual(_bytes('<a><b></b><c></c></a>'),
    3863                            canonicalize(tounicode(a)))
    3864
    3865 -    def test_tounicode_element(self):
    3866          tounicode = self.etree.tounicode
    3867          Element = self.etree.Element
    3868          SubElement = self.etree.SubElement
    3869
    3870          a = Element('a')
    3871          b = SubElement(a, 'b')
    3872          c = SubElement(a, 'c')
    3873          d = SubElement(c, 'd')
    3874          self.assertTrue(isinstance(tounicode(b), _unicode))
    3875          self.assertTrue(isinstance(tounicode(c), _unicode))
    3876          self.assertEqual(_bytes('<b></b>'),
    3877                            canonicalize(tounicode(b)))
    3878          self.assertEqual(_bytes('<c><d></d></c>'),
    3879                            canonicalize(tounicode(c)))
    3880
    3881 -    def test_tounicode_none(self):
    3882          tounicode = self.etree.tounicode
    3883          self.assertRaises(TypeError, self.etree.tounicode, None)
    3884
    3885 -    def test_tounicode_element_tail(self):
    3886          tounicode = self.etree.tounicode
    3887          Element = self.etree.Element
    3888          SubElement = self.etree.SubElement
    3889
    3890          a = Element('a')
    3891          b = SubElement(a, 'b')
    3892          c = SubElement(a, 'c')
    3893          d = SubElement(c, 'd')
    3894          b.tail = 'Foo'
    3895
    3896          self.assertTrue(isinstance(tounicode(b), _unicode))
    3897          self.assertTrue(tounicode(b) == '<b/>Foo' or
    3898                       tounicode(b) == '<b />Foo')
    3899
    3900 -    def test_tounicode_pretty(self):
    3901          tounicode = self.etree.tounicode
    3902          Element = self.etree.Element
    3903          SubElement = self.etree.SubElement
    3904
    3905          a = Element('a')
    3906          b = SubElement(a, 'b')
    3907          c = SubElement(a, 'c')
    3908
    3909          result = tounicode(a)
    3910          self.assertEqual(result, "<a><b/><c/></a>")
    3911
    3912          result = tounicode(a, pretty_print=False)
    3913          self.assertEqual(result, "<a><b/><c/></a>")
    3914
    3915          result = tounicode(a, pretty_print=True)
    3916          self.assertEqual(result, "<a>\n  <b/>\n  <c/>\n</a>\n")
    3917
    3918 -    def test_tostring_unicode(self):
    3919          tostring = self.etree.tostring
    3920          Element = self.etree.Element
    3921          SubElement = self.etree.SubElement
    3922
    3923          a = Element('a')
    3924          b = SubElement(a, 'b')
    3925          c = SubElement(a, 'c')
    3926
    3927          self.assertTrue(isinstance(tostring(a, encoding=_unicode), _unicode))
    3928          self.assertEqual(_bytes('<a><b></b><c></c></a>'),
    3929                            canonicalize(tostring(a, encoding=_unicode)))
    3930
    3931 -    def test_tostring_unicode_element(self):
    3932          tostring = self.etree.tostring
    3933          Element = self.etree.Element
    3934          SubElement = self.etree.SubElement
    3935
    3936          a = Element('a')
    3937          b = SubElement(a, 'b')
    3938          c = SubElement(a, 'c')
    3939          d = SubElement(c, 'd')
    3940          self.assertTrue(isinstance(tostring(b, encoding=_unicode), _unicode))
    3941          self.assertTrue(isinstance(tostring(c, encoding=_unicode), _unicode))
    3942          self.assertEqual(_bytes('<b></b>'),
    3943                            canonicalize(tostring(b, encoding=_unicode)))
    3944          self.assertEqual(_bytes('<c><d></d></c>'),
    3945                            canonicalize(tostring(c, encoding=_unicode)))
    3946
    3947 -    def test_tostring_unicode_none(self):
    3948          tostring = self.etree.tostring
    3949          self.assertRaises(TypeError, self.etree.tostring,
    3950                            None, encoding=_unicode)
    3951
    3952 -    def test_tostring_unicode_element_tail(self):
    3953          tostring = self.etree.tostring
    3954          Element = self.etree.Element
    3955          SubElement = self.etree.SubElement
    3956
    3957          a = Element('a')
    3958          b = SubElement(a, 'b')
    3959          c = SubElement(a, 'c')
    3960          d = SubElement(c, 'd')
    3961          b.tail = 'Foo'
    3962
    3963          self.assertTrue(isinstance(tostring(b, encoding=_unicode), _unicode))
    3964          self.assertTrue(tostring(b, encoding=_unicode) == '<b/>Foo' or
    3965                       tostring(b, encoding=_unicode) == '<b />Foo')
    3966
    3967 -    def test_tostring_unicode_pretty(self):
    3968          tostring = self.etree.tostring
    3969          Element = self.etree.Element
    3970          SubElement = self.etree.SubElement
    3971
    3972          a = Element('a')
    3973          b = SubElement(a, 'b')
    3974          c = SubElement(a, 'c')
    3975
    3976          result = tostring(a, encoding=_unicode)
    3977          self.assertEqual(result, "<a><b/><c/></a>")
    3978
    3979          result = tostring(a, encoding=_unicode, pretty_print=False)
    3980          self.assertEqual(result, "<a><b/><c/></a>")
    3981
    3982          result = tostring(a, encoding=_unicode, pretty_print=True)
    3983          self.assertEqual(result, "<a>\n  <b/>\n  <c/>\n</a>\n")
    3984
    3985 -    def test_pypy_proxy_collect(self):
    3986          root = etree.Element('parent')
    3987          etree.SubElement(root, 'child')
    3988
    3989          self.assertEqual(len(root), 1)
    3990          self.assertEqual(root[0].tag, 'child')
    3991
    3992          # in PyPy, GC used to kill the Python proxy instance without cleanup
    3993          gc.collect()
    3994          self.assertEqual(len(root), 1)
    3995          self.assertEqual(root[0].tag, 'child')
    3996
    3997 -    def test_element_refcycle(self):
    3998          class SubEl(etree.ElementBase):
    3999              pass
    4000
    4001          el1 = SubEl()
    4002          el2 = SubEl()
    4003          self.assertEqual('SubEl', el1.tag)
    4004          self.assertEqual('SubEl', el2.tag)
    4005          el1.other = el2
    4006          el2.other = el1
    4007
    4008          del el1, el2
    4009          gc.collect()
    4010          # not really testing anything here, but it shouldn't crash
    4011
    4012 -    def test_proxy_collect_siblings(self):
    4013          root = etree.Element('parent')
    4014          c1 = etree.SubElement(root, 'child1')
    4015          c2 = etree.SubElement(root, 'child2')
    4016
    4017          root.remove(c1)
    4018          root.remove(c2)
    4019          c1.addnext(c2)
    4020          del c1
    4021          # trigger deallocation attempt of c1
    4022          c2.getprevious()
    4023          # make sure it wasn't deallocated
    4024          self.assertEqual('child1', c2.getprevious().tag)
    4025
    4026 -    def test_proxy_collect_siblings_text(self):
    4027          root = etree.Element('parent')
    4028          c1 = etree.SubElement(root, 'child1')
    4029          c2 = etree.SubElement(root, 'child2')
    4030
    4031          root.remove(c1)
    4032          root.remove(c2)
    4033          c1.addnext(c2)
    4034          c1.tail = 'abc'
    4035          c2.tail = 'xyz'
    4036          del c1
    4037          # trigger deallocation attempt of c1
    4038          c2.getprevious()
    4039          # make sure it wasn't deallocated
    4040          self.assertEqual('child1', c2.getprevious().tag)
    4041          self.assertEqual('abc', c2.getprevious().tail)
    4042
    4043      # helper methods
    4044
    4045 -    def _writeElement(self, element, encoding='us-ascii', compression=0):
    4046          """Write out element for comparison.
    4047          """
    4048          ElementTree = self.etree.ElementTree
    4049          f = BytesIO()
    4050          tree = ElementTree(element=element)
    4051          tree.write(f, encoding=encoding, compression=compression)
    4052          data = f.getvalue()
    4053          if compression:
    4054              data = zlib.decompress(data)
    4055          return canonicalize(data)
    4056
    4057
    4058 -class _XIncludeTestCase(HelperTestCase):
    4059 -    def test_xinclude_text(self):
    4060          filename = fileInTestDir('test_broken.xml')
    4061          root = etree.XML(_bytes('''\
    4062          <doc xmlns:xi="http://www.w3.org/2001/XInclude">
    4063            <xi:include href="%s" parse="text"/>
    4064          </doc>
    4065          ''' % path2url(filename)))
    4066          old_text = root.text
    4067          content = read_file(filename)
    4068          old_tail = root[0].tail
    4069
    4070          self.include( etree.ElementTree(root) )
    4071          self.assertEqual(old_text + content + old_tail,
    4072                            root.text)
    4073
    4074 -    def test_xinclude(self):
    4075          tree = etree.parse(fileInTestDir('include/test_xinclude.xml'))
    4076          self.assertNotEqual(
    4077              'a',
    4078              tree.getroot()[1].tag)
    4079          # process xincludes
    4080          self.include( tree )
    4081          # check whether we find it replaced with included data
    4082          self.assertEqual(
    4083              'a',
    4084              tree.getroot()[1].tag)
    4085
    4086 -    def test_xinclude_resolver(self):
    4087          class res(etree.Resolver):
    4088              include_text = read_file(fileInTestDir('test.xml'))
    4089              called = {}
    4090              def resolve(self, url, id, context):
    4091                  if url.endswith(".dtd"):
    4092                      self.called["dtd"] = True
    4093                      return self.resolve_filename(
    4094                          fileInTestDir('test.dtd'), context)
    4095                  elif url.endswith("test_xinclude.xml"):
    4096                      self.called["input"] = True
    4097                      return None # delegate to default resolver
    4098                  else:
    4099                      self.called["include"] = True
    4100                      return self.resolve_string(self.include_text, context)
    4101
    4102          res_instance = res()
    4103          parser = etree.XMLParser(load_dtd = True)
    4104          parser.resolvers.add(res_instance)
    4105
    4106          tree = etree.parse(fileInTestDir('include/test_xinclude.xml'),
    4107                             parser = parser)
    4108
    4109          self.include(tree)
    4110
    4111          called = list(res_instance.called.items())
    4112          called.sort()
    4113          self.assertEqual(
    4114              [("dtd", True), ("include", True), ("input", True)],
    4115              called)
    4116
    4117 -    def test_xinclude_resolver_recursive(self):
    4118          data = textwrap.dedent('''
    4119          <doc xmlns:xi="http://www.w3.org/2001/XInclude">
    4120          <foo/>
    4121          <xi:include href="./test.xml" />
    4122          </doc>
    4123          ''')
    4124
    4125          class Resolver(etree.Resolver):
    4126              called = {}
    4127
    4128              def resolve(self, url, id, context):
    4129                  if url.endswith("test_xinclude.xml"):
    4130                      assert not self.called.get("input")
    4131                      self.called["input"] = True
    4132                      return None  # delegate to default resolver
    4133                  elif url.endswith('/test5.xml'):
    4134                      assert not self.called.get("DONE")
    4135                      self.called["DONE"] = True
    4136                      return self.resolve_string('<DONE/>', context)
    4137                  else:
    4138                      _, filename = url.rsplit('/', 1)
    4139                      assert not self.called.get(filename)
    4140                      self.called[filename] = True
    4141                      next_data = data.replace(
    4142                          'test.xml', 'test%d.xml' % len(self.called))
    4143                      return self.resolve_string(next_data, context)
    4144
    4145          res_instance = Resolver()
    4146          parser = etree.XMLParser(load_dtd=True)
    4147          parser.resolvers.add(res_instance)
    4148
    4149          tree = etree.parse(fileInTestDir('include/test_xinclude.xml'),
    4150                             parser=parser)
    4151
    4152          self.include(tree)
    4153
    4154          called = list(res_instance.called.items())
    4155          called.sort()
    4156          self.assertEqual(
    4157              [("DONE", True), ("input", True), ("test.xml", True),
    4158               ("test2.xml", True), ("test3.xml", True), ("test4.xml", True)],
    4159              called)
    4160
    4161
    4162 -class ETreeXIncludeTestCase(_XIncludeTestCase):
    4163 -    def include(self, tree):
    4164          tree.xinclude()
    4165
    4166
    4167 -class ElementIncludeTestCase(_XIncludeTestCase):
    4168      from lxml import ElementInclude
    4169 -    def include(self, tree):
    4170          self.ElementInclude.include(tree.getroot())
    4171
    4172
    4173 -class ETreeC14NTestCase(HelperTestCase):
    4174 -    def test_c14n(self):
    4175          tree = self.parse(_bytes('<a><b/></a>'))
    4176          f = BytesIO()
    4177          tree.write_c14n(f)
    4178          s = f.getvalue()
    4179          self.assertEqual(_bytes('<a><b></b></a>'),
    4180                            s)
    4181
    4182 -    def test_c14n_gzip(self):
    4183          tree = self.parse(_bytes('<a>'+'<b/>'*200+'</a>'))
    4184          f = BytesIO()
    4185          tree.write_c14n(f, compression=9)
    4186          with closing(gzip.GzipFile(fileobj=BytesIO(f.getvalue()))) as gzfile:
    4187              s = gzfile.read()
    4188          self.assertEqual(_bytes('<a>'+'<b></b>'*200+'</a>'),
    4189                            s)
    4190
    4191 -    def test_c14n_file(self):
    4192          tree = self.parse(_bytes('<a><b/></a>'))
    4193          with tmpfile() as filename:
    4194              tree.write_c14n(filename)
    4195              data = read_file(filename, 'rb')
    4196          self.assertEqual(_bytes('<a><b></b></a>'),
    4197                            data)
    4198
    4199 -    def test_c14n_file_gzip(self):
    4200          tree = self.parse(_bytes('<a>'+'<b/>'*200+'</a>'))
    4201          with tmpfile() as filename:
    4202              tree.write_c14n(filename, compression=9)
    4203              with closing(gzip.open(filename, 'rb')) as f:
    4204                  data = f.read()
    4205          self.assertEqual(_bytes('<a>'+'<b></b>'*200+'</a>'),
    4206                            data)
    4207
    4208 -    def test_c14n_with_comments(self):
    4209          tree = self.parse(_bytes('<!--hi--><a><!--ho--><b/></a><!--hu-->'))
    4210          f = BytesIO()
    4211          tree.write_c14n(f)
    4212          s = f.getvalue()
    4213          self.assertEqual(_bytes('<!--hi-->\n<a><!--ho--><b></b></a>\n<!--hu-->'),
    4214                            s)
    4215          f = BytesIO()
    4216          tree.write_c14n(f, with_comments=True)
    4217          s = f.getvalue()
    4218          self.assertEqual(_bytes('<!--hi-->\n<a><!--ho--><b></b></a>\n<!--hu-->'),
    4219                            s)
    4220          f = BytesIO()
    4221          tree.write_c14n(f, with_comments=False)
    4222          s = f.getvalue()
    4223          self.assertEqual(_bytes('<a><b></b></a>'),
    4224                            s)
    4225
    4226 -    def test_c14n_tostring_with_comments(self):
    4227          tree = self.parse(_bytes('<!--hi--><a><!--ho--><b/></a><!--hu-->'))
    4228          s = etree.tostring(tree, method='c14n')
    4229          self.assertEqual(_bytes('<!--hi-->\n<a><!--ho--><b></b></a>\n<!--hu-->'),
    4230                            s)
    4231          s = etree.tostring(tree, method='c14n', with_comments=True)
    4232          self.assertEqual(_bytes('<!--hi-->\n<a><!--ho--><b></b></a>\n<!--hu-->'),
    4233                            s)
    4234          s = etree.tostring(tree, method='c14n', with_comments=False)
    4235          self.assertEqual(_bytes('<a><b></b></a>'),
    4236                            s)
    4237
    4238 -    def test_c14n_element_tostring_with_comments(self):
    4239          tree = self.parse(_bytes('<!--hi--><a><!--ho--><b/></a><!--hu-->'))
    4240          s = etree.tostring(tree.getroot(), method='c14n')
    4241          self.assertEqual(_bytes('<a><!--ho--><b></b></a>'),
    4242                            s)
    4243          s = etree.tostring(tree.getroot(), method='c14n', with_comments=True)
    4244          self.assertEqual(_bytes('<a><!--ho--><b></b></a>'),
    4245                            s)
    4246          s = etree.tostring(tree.getroot(), method='c14n', with_comments=False)
    4247          self.assertEqual(_bytes('<a><b></b></a>'),
    4248                            s)
    4249
    4250 -    def test_c14n_exclusive(self):
    4251          tree = self.parse(_bytes(
    4252                  '<a xmlns="http://abc" xmlns:y="http://bcd" xmlns:z="http://cde"><z:b/></a>'))
    4253          f = BytesIO()
    4254          tree.write_c14n(f)
    4255          s = f.getvalue()
    4256          self.assertEqual(_bytes('<a xmlns="http://abc" xmlns:y="http://bcd" xmlns:z="http://cde"><z:b></z:b></a>'),
    4257                            s)
    4258          f = BytesIO()
    4259          tree.write_c14n(f, exclusive=False)
    4260          s = f.getvalue()
    4261          self.assertEqual(_bytes('<a xmlns="http://abc" xmlns:y="http://bcd" xmlns:z="http://cde"><z:b></z:b></a>'),
    4262                            s)
    4263          f = BytesIO()
    4264          tree.write_c14n(f, exclusive=True)
    4265          s = f.getvalue()
    4266          self.assertEqual(_bytes('<a xmlns="http://abc"><z:b xmlns:z="http://cde"></z:b></a>'),
    4267                            s)
    4268
    4269          f = BytesIO()
    4270          tree.write_c14n(f, exclusive=True, inclusive_ns_prefixes=['z'])
    4271          s = f.getvalue()
    4272          self.assertEqual(_bytes('<a xmlns="http://abc" xmlns:z="http://cde"><z:b></z:b></a>'),
    4273                            s)
    4274
    4275 -    def test_c14n_tostring_exclusive(self):
    4276          tree = self.parse(_bytes(
    4277                  '<a xmlns="http://abc" xmlns:y="http://bcd" xmlns:z="http://cde"><z:b/></a>'))
    4278          s = etree.tostring(tree, method='c14n')
    4279          self.assertEqual(_bytes('<a xmlns="http://abc" xmlns:y="http://bcd" xmlns:z="http://cde"><z:b></z:b></a>'),
    4280                            s)
    4281          s = etree.tostring(tree, method='c14n', exclusive=False)
    4282          self.assertEqual(_bytes('<a xmlns="http://abc" xmlns:y="http://bcd" xmlns:z="http://cde"><z:b></z:b></a>'),
    4283                            s)
    4284          s = etree.tostring(tree, method='c14n', exclusive=True)
    4285          self.assertEqual(_bytes('<a xmlns="http://abc"><z:b xmlns:z="http://cde"></z:b></a>'),
    4286                            s)
    4287
    4288          s = etree.tostring(tree, method='c14n', exclusive=True, inclusive_ns_prefixes=['y'])
    4289          self.assertEqual(_bytes('<a xmlns="http://abc" xmlns:y="http://bcd"><z:b xmlns:z="http://cde"></z:b></a>'),
    4290                            s)
    4291
    4292 -    def test_c14n_element_tostring_exclusive(self):
    4293          tree = self.parse(_bytes(
    4294                  '<a xmlns="http://abc" xmlns:y="http://bcd" xmlns:z="http://cde"><z:b/></a>'))
    4295          s = etree.tostring(tree.getroot(), method='c14n')
    4296          self.assertEqual(_bytes('<a xmlns="http://abc" xmlns:y="http://bcd" xmlns:z="http://cde"><z:b></z:b></a>'),
    4297                            s)
    4298          s = etree.tostring(tree.getroot(), method='c14n', exclusive=False)
    4299          self.assertEqual(_bytes('<a xmlns="http://abc" xmlns:y="http://bcd" xmlns:z="http://cde"><z:b></z:b></a>'),
    4300                            s)
    4301          s = etree.tostring(tree.getroot(), method='c14n', exclusive=True)
    4302          self.assertEqual(_bytes('<a xmlns="http://abc"><z:b xmlns:z="http://cde"></z:b></a>'),
    4303                            s)
    4304
    4305          s = etree.tostring(tree.getroot()[0], method='c14n', exclusive=False)
    4306          self.assertEqual(_bytes('<z:b xmlns="http://abc" xmlns:y="http://bcd" xmlns:z="http://cde"></z:b>'),
    4307                            s)
    4308          s = etree.tostring(tree.getroot()[0], method='c14n', exclusive=True)
    4309          self.assertEqual(_bytes('<z:b xmlns:z="http://cde"></z:b>'),
    4310                            s)
    4311
    4312          s = etree.tostring(tree.getroot()[0], method='c14n', exclusive=True, inclusive_ns_prefixes=['y'])
    4313          self.assertEqual(_bytes('<z:b xmlns:y="http://bcd" xmlns:z="http://cde"></z:b>'),
    4314                            s)
    4315
    4316 -    def test_c14n_tostring_inclusive_ns_prefixes(self):
    4317          """ Regression test to fix memory allocation issues (use 3+ inclusive NS spaces)"""
    4318          tree = self.parse(_bytes(
    4319                  '<a xmlns:x="http://abc" xmlns:y="http://bcd" xmlns:z="http://cde"><z:b/></a>'))
    4320
    4321          s = etree.tostring(tree, method='c14n', exclusive=True, inclusive_ns_prefixes=['x', 'y', 'z'])
    4322          self.assertEqual(_bytes('<a xmlns:x="http://abc" xmlns:y="http://bcd" xmlns:z="http://cde"><z:b></z:b></a>'),
    4323                            s)
    4324
    4325
    4326 -class ETreeWriteTestCase(HelperTestCase):
    4327 -    def test_write(self):
    4328          tree = self.parse(_bytes('<a><b/></a>'))
    4329          f = BytesIO()
    4330          tree.write(f)
    4331          s = f.getvalue()
    4332          self.assertEqual(_bytes('<a><b/></a>'),
    4333                            s)
    4334
    4335 -    def test_write_doctype(self):
    4336          tree = self.parse(_bytes('<a><b/></a>'))
    4337          f = BytesIO()
    4338          tree.write(f, doctype='HUHU')
    4339          s = f.getvalue()
    4340          self.assertEqual(_bytes('HUHU\n<a><b/></a>'),
    4341                            s)
    4342
    4343 -    def test_write_gzip(self):
    4344          tree = self.parse(_bytes('<a>'+'<b/>'*200+'</a>'))
    4345          f = BytesIO()
    4346          tree.write(f, compression=9)
    4347          with closing(gzip.GzipFile(fileobj=BytesIO(f.getvalue()))) as gzfile:
    4348              s = gzfile.read()
    4349          self.assertEqual(_bytes('<a>'+'<b/>'*200+'</a>'),
    4350                            s)
    4351
    4352 -    def test_write_gzip_doctype(self):
    4353          tree = self.parse(_bytes('<a>'+'<b/>'*200+'</a>'))
    4354          f = BytesIO()
    4355          tree.write(f, compression=9, doctype='<!DOCTYPE a>')
    4356          with closing(gzip.GzipFile(fileobj=BytesIO(f.getvalue()))) as gzfile:
    4357              s = gzfile.read()
    4358          self.assertEqual(_bytes('<!DOCTYPE a>\n<a>'+'<b/>'*200+'</a>'),
    4359                            s)
    4360
    4361 -    def test_write_gzip_level(self):
    4362          tree = self.parse(_bytes('<a>'+'<b/>'*200+'</a>'))
    4363          f = BytesIO()
    4364          tree.write(f, compression=0)
    4365          s0 = f.getvalue()
    4366
    4367          f = BytesIO()
    4368          tree.write(f)
    4369          self.assertEqual(f.getvalue(), s0)
    4370
    4371          f = BytesIO()
    4372          tree.write(f, compression=1)
    4373          s = f.getvalue()
    4374          self.assertTrue(len(s) <= len(s0))
    4375          with closing(gzip.GzipFile(fileobj=BytesIO(s))) as gzfile:
    4376              s1 = gzfile.read()
    4377
    4378          f = BytesIO()
    4379          tree.write(f, compression=9)
    4380          s = f.getvalue()
    4381          self.assertTrue(len(s) <= len(s0))
    4382          with closing(gzip.GzipFile(fileobj=BytesIO(s))) as gzfile:
    4383              s9 = gzfile.read()
    4384
    4385          self.assertEqual(_bytes('<a>'+'<b/>'*200+'</a>'),
    4386                            s0)
    4387          self.assertEqual(_bytes('<a>'+'<b/>'*200+'</a>'),
    4388                            s1)
    4389          self.assertEqual(_bytes('<a>'+'<b/>'*200+'</a>'),
    4390                            s9)
    4391
    4392 -    def test_write_file(self):
    4393          tree = self.parse(_bytes('<a><b/></a>'))
    4394          with tmpfile() as filename:
    4395              tree.write(filename)
    4396              data = read_file(filename, 'rb')
    4397          self.assertEqual(_bytes('<a><b/></a>'),
    4398                            data)
    4399
    4400 -    def test_write_file_gzip(self):
    4401          tree = self.parse(_bytes('<a>'+'<b/>'*200+'</a>'))
    4402          with tmpfile() as filename:
    4403              tree.write(filename, compression=9)
    4404              with closing(gzip.open(filename, 'rb')) as f:
    4405                  data = f.read()
    4406          self.assertEqual(_bytes('<a>'+'<b/>'*200+'</a>'),
    4407                            data)
    4408
    4409 -    def test_write_file_gzip_parse(self):
    4410          tree = self.parse(_bytes('<a>'+'<b/>'*200+'</a>'))
    4411          with tmpfile() as filename:
    4412              tree.write(filename, compression=9)
    4413              data = etree.tostring(etree.parse(filename))
    4414          self.assertEqual(_bytes('<a>'+'<b/>'*200+'</a>'),
    4415                            data)
    4416
    4417 -    def test_write_file_gzipfile_parse(self):
    4418          tree = self.parse(_bytes('<a>'+'<b/>'*200+'</a>'))
    4419          with tmpfile() as filename:
    4420              tree.write(filename, compression=9)
    4421              with closing(gzip.GzipFile(filename)) as f:
    4422                  data = etree.tostring(etree.parse(f))
    4423          self.assertEqual(_bytes('<a>'+'<b/>'*200+'</a>'),
    4424                            data)
    4425
    4426
    4427 -class ETreeErrorLogTest(HelperTestCase):
    4428      etree = etree
    4429
    4430 -    def test_parse_error_logging(self):
    4431          parse = self.etree.parse
    4432          f = BytesIO('<a><b></c></b></a>')
    4433          self.etree.clear_error_log()
    4434          try:
    4435              parse(f)
    4436              logs = None
    4437          except SyntaxError:
    4438              e = sys.exc_info()[1]
    4439              logs = e.error_log
    4440          f.close()
    4441          self.assertTrue([ log for log in logs
    4442                         if 'mismatch' in log.message ])
    4443          self.assertTrue([ log for log in logs
    4444                         if 'PARSER'   in log.domain_name])
    4445          self.assertTrue([ log for log in logs
    4446                         if 'ERR_TAG_NAME_MISMATCH' in log.type_name ])
    4447          self.assertTrue([ log for log in logs
    4448                         if 1 == log.line ])
    4449          self.assertTrue([ log for log in logs
    4450                         if 15 == log.column ])
    4451
    4452 -    def _test_python_error_logging(self):
    4453          """This can't really be tested as long as there isn't a way to
    4454          reset the logging setup ...
    4455          """
    4456          parse = self.etree.parse
    4457
    4458          messages = []
    4459          class Logger(self.etree.PyErrorLog):
    4460              def log(self, entry, message, *args):
    4461                  messages.append(message)
    4462
    4463          self.etree.use_global_python_log(Logger())
    4464          f = BytesIO('<a><b></c></b></a>')
    4465          try:
    4466              parse(f)
    4467          except SyntaxError:
    4468              pass
    4469          f.close()
    4470
    4471          self.assertTrue([ message for message in messages
    4472                         if 'mismatch' in message ])
    4473          self.assertTrue([ message for message in messages
    4474                         if ':PARSER:'   in message])
    4475          self.assertTrue([ message for message in messages
    4476                         if ':ERR_TAG_NAME_MISMATCH:' in message ])
    4477          self.assertTrue([ message for message in messages
    4478                         if ':1:15:' in message ])
    4479
    4480
    4481 -class XMLPullParserTest(unittest.TestCase):
    4482      etree = etree
    4483
    4484 -    def assert_event_tags(self, events, expected):
    4485          self.assertEqual([(action, elem.tag) for action, elem in events],
    4486                           expected)
    4487
    4488 -    def test_pull_from_simple_target(self):
    4489          class Target(object):
    4490              def start(self, tag, attrib):
    4491                  return 'start(%s)' % tag
    4492              def end(self, tag):
    4493                  return 'end(%s)' % tag
    4494              def close(self):
    4495                  return 'close()'
    4496
    4497          parser = self.etree.XMLPullParser(target=Target())
    4498          events = parser.read_events()
    4499
    4500          parser.feed('<root><element>')
    4501          self.assertFalse(list(events))
    4502          self.assertFalse(list(events))
    4503          parser.feed('</element><child>')
    4504          self.assertEqual([('end', 'end(element)')], list(events))
    4505          parser.feed('</child>')
    4506          self.assertEqual([('end', 'end(child)')], list(events))
    4507          parser.feed('</root>')
    4508          self.assertEqual([('end', 'end(root)')], list(events))
    4509          self.assertFalse(list(events))
    4510          self.assertEqual('close()', parser.close())
    4511
    4512 -    def test_pull_from_simple_target_start_end(self):
    4513          class Target(object):
    4514              def start(self, tag, attrib):
    4515                  return 'start(%s)' % tag
    4516              def end(self, tag):
    4517                  return 'end(%s)' % tag
    4518              def close(self):
    4519                  return 'close()'
    4520
    4521          parser = self.etree.XMLPullParser(
    4522              ['start', 'end'], target=Target())
    4523          events = parser.read_events()
    4524
    4525          parser.feed('<root><element>')
    4526          self.assertEqual(
    4527              [('start', 'start(root)'), ('start', 'start(element)')],
    4528              list(events))
    4529          self.assertFalse(list(events))
    4530          parser.feed('</element><child>')
    4531          self.assertEqual(
    4532              [('end', 'end(element)'), ('start', 'start(child)')],
    4533              list(events))
    4534          parser.feed('</child>')
    4535          self.assertEqual(
    4536              [('end', 'end(child)')],
    4537              list(events))
    4538          parser.feed('</root>')
    4539          self.assertEqual(
    4540              [('end', 'end(root)')],
    4541              list(events))
    4542          self.assertFalse(list(events))
    4543          self.assertEqual('close()', parser.close())
    4544
    4545 -    def test_pull_from_tree_builder(self):
    4546          parser = self.etree.XMLPullParser(
    4547              ['start', 'end'], target=etree.TreeBuilder())
    4548          events = parser.read_events()
    4549
    4550          parser.feed('<root><element>')
    4551          self.assert_event_tags(
    4552              events, [('start', 'root'), ('start', 'element')])
    4553          self.assertFalse(list(events))
    4554          parser.feed('</element><child>')
    4555          self.assert_event_tags(
    4556              events, [('end', 'element'), ('start', 'child')])
    4557          parser.feed('</child>')
    4558          self.assert_event_tags(
    4559              events, [('end', 'child')])
    4560          parser.feed('</root>')
    4561          self.assert_event_tags(
    4562              events, [('end', 'root')])
    4563          self.assertFalse(list(events))
    4564          root = parser.close()
    4565          self.assertEqual('root', root.tag)
    4566
    4567 -    def test_pull_from_tree_builder_subclass(self):
    4568          class Target(etree.TreeBuilder):
    4569              def end(self, tag):
    4570                  el = super(Target, self).end(tag)
    4571                  el.tag += '-huhu'
    4572                  return el
    4573
    4574          parser = self.etree.XMLPullParser(
    4575              ['start', 'end'], target=Target())
    4576          events = parser.read_events()
    4577
    4578          parser.feed('<root><element>')
    4579          self.assert_event_tags(
    4580              events, [('start', 'root'), ('start', 'element')])
    4581          self.assertFalse(list(events))
    4582          parser.feed('</element><child>')
    4583          self.assert_event_tags(
    4584              events, [('end', 'element-huhu'), ('start', 'child')])
    4585          parser.feed('</child>')
    4586          self.assert_event_tags(
    4587              events, [('end', 'child-huhu')])
    4588          parser.feed('</root>')
    4589          self.assert_event_tags(
    4590              events, [('end', 'root-huhu')])
    4591          self.assertFalse(list(events))
    4592          root = parser.close()
    4593          self.assertEqual('root-huhu', root.tag)
    4594
    4595
    4596 -def test_suite():
    4597      suite = unittest.TestSuite()
    4598      suite.addTests([unittest.makeSuite(ETreeOnlyTestCase)])
    4599      suite.addTests([unittest.makeSuite(ETreeXIncludeTestCase)])
    4600      suite.addTests([unittest.makeSuite(ElementIncludeTestCase)])
    4601      suite.addTests([unittest.makeSuite(ETreeC14NTestCase)])
    4602      suite.addTests([unittest.makeSuite(ETreeWriteTestCase)])
    4603      suite.addTests([unittest.makeSuite(ETreeErrorLogTest)])
    4604      suite.addTests([unittest.makeSuite(XMLPullParserTest)])
    4605
    4606      # add original doctests from ElementTree selftest modules
    4607      from . import selftest, selftest2
    4608      suite.addTests(doctest.DocTestSuite(selftest))
    4609      suite.addTests(doctest.DocTestSuite(selftest2))
    4610
    4611      # add doctests
    4612      suite.addTests(doctest.DocTestSuite(etree))
    4613      suite.addTests(
    4614          [make_doctest('../../../doc/tutorial.txt')])
    4615      suite.addTests(
    4616          [make_doctest('../../../doc/api.txt')])
    4617      suite.addTests(
    4618          [make_doctest('../../../doc/FAQ.txt')])
    4619      suite.addTests(
    4620          [make_doctest('../../../doc/parsing.txt')])
    4621      suite.addTests(
    4622          [make_doctest('../../../doc/resolvers.txt')])
    4623      return suite
    4624
    4625
    4626  if __name__ == '__main__':
    4627      print('to test use test.py %s' % __file__)
    4628