lxml.tests.test_etree

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