lxml.tests.test_external_document

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

# Source Code for Module lxml.tests.test_external_document

      1  # -*- coding: utf-8 -*-
      2  """
      3  Test cases related to direct loading of external libxml2 documents
      4  """
      5
      6  from __future__ import absolute_import
      7
      8  import sys
      9  import unittest
     10
     11  from .common_imports import HelperTestCase, etree, skipIf
     12
     13  DOC_NAME = b'libxml2:xmlDoc'
     14  DESTRUCTOR_NAME = b'destructor:xmlFreeDoc'
     15
     16
     17  @skipIf(sys.version_info[:2] < (2, 7),
     18          'Not supported for python < 2.7')
     19 -class ExternalDocumentTestCase(HelperTestCase):
     20 -    def setUp(self):
     21          import ctypes
     22          from ctypes import pythonapi
     23          from ctypes.util import find_library
     24
     25          def wrap(func, restype, *argtypes):
     26              func.restype = restype
     27              func.argtypes = list(argtypes)
     28              return func
     29
     30          self.get_capsule_name = wrap(pythonapi.PyCapsule_GetName,
     31                                       ctypes.c_char_p, ctypes.py_object)
     32          self.capsule_is_valid = wrap(pythonapi.PyCapsule_IsValid, ctypes.c_int,
     33                                       ctypes.py_object, ctypes.c_char_p)
     34          self.new_capsule = wrap(pythonapi.PyCapsule_New, ctypes.py_object,
     35                                  ctypes.c_void_p, ctypes.c_char_p,
     36                                  ctypes.c_void_p)
     37          self.set_capsule_name = wrap(pythonapi.PyCapsule_SetName, ctypes.c_int,
     38                                       ctypes.py_object, ctypes.c_char_p)
     39          self.set_capsule_context = wrap(pythonapi.PyCapsule_SetContext,
     40                                          ctypes.c_int, ctypes.py_object,
     41                                          ctypes.c_char_p)
     42          self.get_capsule_context = wrap(pythonapi.PyCapsule_GetContext,
     43                                          ctypes.c_char_p, ctypes.py_object)
     44          self.get_capsule_pointer = wrap(pythonapi.PyCapsule_GetPointer,
     45                                          ctypes.c_void_p, ctypes.py_object,
     46                                          ctypes.c_char_p)
     47          self.set_capsule_pointer = wrap(pythonapi.PyCapsule_SetPointer,
     48                                          ctypes.c_int, ctypes.py_object,
     49                                          ctypes.c_void_p)
     50          self.set_capsule_destructor = wrap(pythonapi.PyCapsule_SetDestructor,
     51                                             ctypes.c_int, ctypes.py_object,
     52                                             ctypes.c_void_p)
     53          self.PyCapsule_Destructor = ctypes.CFUNCTYPE(None, ctypes.py_object)
     54          libxml2 = ctypes.CDLL(find_library('xml2'))
     55          self.create_doc = wrap(libxml2.xmlReadMemory, ctypes.c_void_p,
     56                                 ctypes.c_char_p, ctypes.c_int, ctypes.c_char_p,
     57                                 ctypes.c_char_p, ctypes.c_int)
     58          self.free_doc = wrap(libxml2.xmlFreeDoc, None, ctypes.c_void_p)
     59
     60 -    def as_capsule(self, text, capsule_name=DOC_NAME):
     61          if not isinstance(text, bytes):
     62              text = text.encode('utf-8')
     63          doc = self.create_doc(text, len(text), b'base.xml', b'utf-8', 0)
     64          ans = self.new_capsule(doc, capsule_name, None)
     65          self.set_capsule_context(ans, DESTRUCTOR_NAME)
     66          return ans
     67
     68 -    def test_external_document_adoption(self):
     69          xml = '<r a="1">t</r>'
     70          self.assertRaises(TypeError, etree.adopt_external_document, None)
     71          capsule = self.as_capsule(xml)
     72          self.assertTrue(self.capsule_is_valid(capsule, DOC_NAME))
     73          self.assertEqual(DOC_NAME, self.get_capsule_name(capsule))
     74          # Create an lxml tree from the capsule (this is a move not a copy)
     75          root = etree.adopt_external_document(capsule).getroot()
     76          self.assertIsNone(self.get_capsule_name(capsule))
     77          self.assertEqual(root.text, 't')
     78          root.text = 'new text'
     79          # Now reset the capsule so we can copy it
     80          self.assertEqual(0, self.set_capsule_name(capsule, DOC_NAME))
     81          self.assertEqual(0, self.set_capsule_context(capsule, b'invalid'))
     82          # Create an lxml tree from the capsule (this is a copy not a move)
     83          root2 = etree.adopt_external_document(capsule).getroot()
     84          self.assertEqual(self.get_capsule_context(capsule), b'invalid')
     85          # Check that the modification to the tree using the transferred
     86          # document was successful
     87          self.assertEqual(root.text, root2.text)
     88          # Check that further modifications do not show up in the copy (they are
     89          # disjoint)
     90          root.text = 'other text'
     91          self.assertNotEqual(root.text, root2.text)
     92          # delete root and ensure root2 survives
     93          del root
     94          self.assertEqual(root2.text, 'new text')
     95
     96
     97 -def test_suite():
     98      suite = unittest.TestSuite()
     99      suite.addTests([unittest.makeSuite(ExternalDocumentTestCase)])
    100      return suite
    101
    102
    103  if __name__ == '__main__':
    104      print('to test use test.py %s' % __file__)
    105