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