1# xml.etree test for cElementTree 2import io 3import struct 4from test import support 5from test.support 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 173@unittest.skipUnless(cET, 'requires _elementtree') 174class TestAliasWorking(unittest.TestCase): 175 # Test that the cET alias module is alive 176 def test_alias_working(self): 177 e = cET_alias.Element('foo') 178 self.assertEqual(e.tag, 'foo') 179 180 181@unittest.skipUnless(cET, 'requires _elementtree') 182@support.cpython_only 183class TestAcceleratorImported(unittest.TestCase): 184 # Test that the C accelerator was imported, as expected 185 def test_correct_import_cET(self): 186 # SubElement is a function so it retains _elementtree as its module. 187 self.assertEqual(cET.SubElement.__module__, '_elementtree') 188 189 def test_correct_import_cET_alias(self): 190 self.assertEqual(cET_alias.SubElement.__module__, '_elementtree') 191 192 def test_parser_comes_from_C(self): 193 # The type of methods defined in Python code is types.FunctionType, 194 # while the type of methods defined inside _elementtree is 195 # <class 'wrapper_descriptor'> 196 self.assertNotIsInstance(cET.Element.__init__, types.FunctionType) 197 198 199@unittest.skipUnless(cET, 'requires _elementtree') 200@support.cpython_only 201class SizeofTest(unittest.TestCase): 202 def setUp(self): 203 self.elementsize = support.calcobjsize('5P') 204 # extra 205 self.extra = struct.calcsize('PnnP4P') 206 207 check_sizeof = support.check_sizeof 208 209 def test_element(self): 210 e = cET.Element('a') 211 self.check_sizeof(e, self.elementsize) 212 213 def test_element_with_attrib(self): 214 e = cET.Element('a', href='about:') 215 self.check_sizeof(e, self.elementsize + self.extra) 216 217 def test_element_with_children(self): 218 e = cET.Element('a') 219 for i in range(5): 220 cET.SubElement(e, 'span') 221 # should have space for 8 children now 222 self.check_sizeof(e, self.elementsize + self.extra + 223 struct.calcsize('8P')) 224 225def test_main(): 226 from test import test_xml_etree 227 228 # Run the tests specific to the C implementation 229 support.run_unittest( 230 MiscTests, 231 TestAliasWorking, 232 TestAcceleratorImported, 233 SizeofTest, 234 ) 235 236 # Run the same test suite as the Python module 237 test_xml_etree.test_main(module=cET) 238 239 240if __name__ == '__main__': 241 test_main() 242