1# xml.etree test for cElementTree 2import io 3import struct 4from test import support 5from test.support.import_helper import import_fresh_module 6import types 7import unittest 8 9cET = import_fresh_module('xml.etree.ElementTree', 10 fresh=['_elementtree']) 11cET_alias = import_fresh_module('xml.etree.cElementTree', 12 fresh=['_elementtree', 'xml.etree'], 13 deprecated=True) 14 15 16@unittest.skipUnless(cET, 'requires _elementtree') 17class MiscTests(unittest.TestCase): 18 # Issue #8651. 19 @support.bigmemtest(size=support._2G + 100, memuse=1, dry_run=False) 20 def test_length_overflow(self, size): 21 data = b'x' * size 22 parser = cET.XMLParser() 23 try: 24 self.assertRaises(OverflowError, parser.feed, data) 25 finally: 26 data = None 27 28 def test_del_attribute(self): 29 element = cET.Element('tag') 30 31 element.tag = 'TAG' 32 with self.assertRaises(AttributeError): 33 del element.tag 34 self.assertEqual(element.tag, 'TAG') 35 36 with self.assertRaises(AttributeError): 37 del element.text 38 self.assertIsNone(element.text) 39 element.text = 'TEXT' 40 with self.assertRaises(AttributeError): 41 del element.text 42 self.assertEqual(element.text, 'TEXT') 43 44 with self.assertRaises(AttributeError): 45 del element.tail 46 self.assertIsNone(element.tail) 47 element.tail = 'TAIL' 48 with self.assertRaises(AttributeError): 49 del element.tail 50 self.assertEqual(element.tail, 'TAIL') 51 52 with self.assertRaises(AttributeError): 53 del element.attrib 54 self.assertEqual(element.attrib, {}) 55 element.attrib = {'A': 'B', 'C': 'D'} 56 with self.assertRaises(AttributeError): 57 del element.attrib 58 self.assertEqual(element.attrib, {'A': 'B', 'C': 'D'}) 59 60 def test_trashcan(self): 61 # If this test fails, it will most likely die via segfault. 62 e = root = cET.Element('root') 63 for i in range(200000): 64 e = cET.SubElement(e, 'x') 65 del e 66 del root 67 support.gc_collect() 68 69 def test_parser_ref_cycle(self): 70 # bpo-31499: xmlparser_dealloc() crashed with a segmentation fault when 71 # xmlparser_gc_clear() was called previously by the garbage collector, 72 # when the parser was part of a reference cycle. 73 74 def parser_ref_cycle(): 75 parser = cET.XMLParser() 76 # Create a reference cycle using an exception to keep the frame 77 # alive, so the parser will be destroyed by the garbage collector 78 try: 79 raise ValueError 80 except ValueError as exc: 81 err = exc 82 83 # Create a parser part of reference cycle 84 parser_ref_cycle() 85 # Trigger an explicit garbage collection to break the reference cycle 86 # and so destroy the parser 87 support.gc_collect() 88 89 def test_bpo_31728(self): 90 # A crash or an assertion failure shouldn't happen, in case garbage 91 # collection triggers a call to clear() or a reading of text or tail, 92 # while a setter or clear() or __setstate__() is already running. 93 elem = cET.Element('elem') 94 class X: 95 def __del__(self): 96 elem.text 97 elem.tail 98 elem.clear() 99 100 elem.text = X() 101 elem.clear() # shouldn't crash 102 103 elem.tail = X() 104 elem.clear() # shouldn't crash 105 106 elem.text = X() 107 elem.text = X() # shouldn't crash 108 elem.clear() 109 110 elem.tail = X() 111 elem.tail = X() # shouldn't crash 112 elem.clear() 113 114 elem.text = X() 115 elem.__setstate__({'tag': 42}) # shouldn't cause an assertion failure 116 elem.clear() 117 118 elem.tail = X() 119 elem.__setstate__({'tag': 42}) # shouldn't cause an assertion failure 120 121 @support.cpython_only 122 def test_uninitialized_parser(self): 123 # The interpreter shouldn't crash in case of calling methods or 124 # accessing attributes of uninitialized XMLParser objects. 125 parser = cET.XMLParser.__new__(cET.XMLParser) 126 self.assertRaises(ValueError, parser.close) 127 self.assertRaises(ValueError, parser.feed, 'foo') 128 class MockFile: 129 def read(*args): 130 return '' 131 self.assertRaises(ValueError, parser._parse_whole, MockFile()) 132 self.assertRaises(ValueError, parser._setevents, None) 133 self.assertIsNone(parser.entity) 134 self.assertIsNone(parser.target) 135 136 def test_setstate_leaks(self): 137 # Test reference leaks 138 elem = cET.Element.__new__(cET.Element) 139 for i in range(100): 140 elem.__setstate__({'tag': 'foo', 'attrib': {'bar': 42}, 141 '_children': [cET.Element('child')], 142 'text': 'text goes here', 143 'tail': 'opposite of head'}) 144 145 self.assertEqual(elem.tag, 'foo') 146 self.assertEqual(elem.text, 'text goes here') 147 self.assertEqual(elem.tail, 'opposite of head') 148 self.assertEqual(list(elem.attrib.items()), [('bar', 42)]) 149 self.assertEqual(len(elem), 1) 150 self.assertEqual(elem[0].tag, 'child') 151 152 def test_iterparse_leaks(self): 153 # Test reference leaks in TreeBuilder (issue #35502). 154 # The test is written to be executed in the hunting reference leaks 155 # mode. 156 XML = '<a></a></b>' 157 parser = cET.iterparse(io.StringIO(XML)) 158 next(parser) 159 del parser 160 support.gc_collect() 161 162 def test_xmlpullparser_leaks(self): 163 # Test reference leaks in TreeBuilder (issue #35502). 164 # The test is written to be executed in the hunting reference leaks 165 # mode. 166 XML = '<a></a></b>' 167 parser = cET.XMLPullParser() 168 parser.feed(XML) 169 del parser 170 support.gc_collect() 171 172 def test_dict_disappearing_during_get_item(self): 173 # test fix for seg fault reported in issue 27946 174 class X: 175 def __hash__(self): 176 e.attrib = {} # this frees e->extra->attrib 177 [{i: i} for i in range(1000)] # exhaust the dict keys cache 178 return 13 179 180 e = cET.Element("elem", {1: 2}) 181 r = e.get(X()) 182 self.assertIsNone(r) 183 184 185@unittest.skipUnless(cET, 'requires _elementtree') 186class TestAliasWorking(unittest.TestCase): 187 # Test that the cET alias module is alive 188 def test_alias_working(self): 189 e = cET_alias.Element('foo') 190 self.assertEqual(e.tag, 'foo') 191 192 193@unittest.skipUnless(cET, 'requires _elementtree') 194@support.cpython_only 195class TestAcceleratorImported(unittest.TestCase): 196 # Test that the C accelerator was imported, as expected 197 def test_correct_import_cET(self): 198 # SubElement is a function so it retains _elementtree as its module. 199 self.assertEqual(cET.SubElement.__module__, '_elementtree') 200 201 def test_correct_import_cET_alias(self): 202 self.assertEqual(cET_alias.SubElement.__module__, '_elementtree') 203 204 def test_parser_comes_from_C(self): 205 # The type of methods defined in Python code is types.FunctionType, 206 # while the type of methods defined inside _elementtree is 207 # <class 'wrapper_descriptor'> 208 self.assertNotIsInstance(cET.Element.__init__, types.FunctionType) 209 210 211@unittest.skipUnless(cET, 'requires _elementtree') 212@support.cpython_only 213class SizeofTest(unittest.TestCase): 214 def setUp(self): 215 self.elementsize = support.calcobjsize('5P') 216 # extra 217 self.extra = struct.calcsize('PnnP4P') 218 219 check_sizeof = support.check_sizeof 220 221 def test_element(self): 222 e = cET.Element('a') 223 self.check_sizeof(e, self.elementsize) 224 225 def test_element_with_attrib(self): 226 e = cET.Element('a', href='about:') 227 self.check_sizeof(e, self.elementsize + self.extra) 228 229 def test_element_with_children(self): 230 e = cET.Element('a') 231 for i in range(5): 232 cET.SubElement(e, 'span') 233 # should have space for 8 children now 234 self.check_sizeof(e, self.elementsize + self.extra + 235 struct.calcsize('8P')) 236 237def test_main(): 238 from test import test_xml_etree 239 240 # Run the tests specific to the C implementation 241 support.run_unittest( 242 MiscTests, 243 TestAliasWorking, 244 TestAcceleratorImported, 245 SizeofTest, 246 ) 247 248 # Run the same test suite as the Python module 249 test_xml_etree.test_main(module=cET) 250 251 252if __name__ == '__main__': 253 test_main() 254