From 4a08e7b3431cd32a0daf22a33421cd3035343dc4 Mon Sep 17 00:00:00 2001
From: Serhiy Storchaka <storchaka@gmail.com>
Date: Sun, 11 Feb 2024 12:08:39 +0200
Subject: [PATCH] gh-115133: Fix tests for XMLPullParser with Expat 2.6.0
 (GH-115164)

Feeding the parser by too small chunks defers parsing to prevent
CVE-2023-52425. Future versions of Expat may be more reactive.

Other adaptation:
For the expat version number, whether a feature exists in the header file is used to determine whether to execute a test case.

diff --git a/Lib/test/test_xml_etree.py b/Lib/test/test_xml_etree.py
index 142ce2c..a8d5c2d 100644
--- a/Lib/test/test_xml_etree.py
+++ b/Lib/test/test_xml_etree.py
@@ -14,6 +14,8 @@ import locale
 import operator
 import os
 import pickle
+import pyexpat
+import subprocess
 import sys
 import textwrap
 import types
@@ -96,6 +98,11 @@ ENTITY_XML = """\
 <document>&entity;</document>
 """
 
+macro_to_find = 'XML_SetReparseDeferralEnabled'  
+header_file = '/usr/include/expat.h'  
+result = subprocess.run(['grep', '-q', macro_to_find, header_file], stdout=subprocess.PIPE, stderr=subprocess.PIPE)  
+fails_with_expat = (unittest.expectedFailure if result.returncode == 0 else lambda test: test)
+
 EXTERNAL_ENTITY_XML = """\
 <!DOCTYPE points [
 <!ENTITY entity SYSTEM "file:///non-existing-file.xml">
@@ -1410,27 +1417,38 @@ class XMLPullParserTest(unittest.TestCase):
         with self.assertRaises(StopIteration):
             next(it)
 
-    def test_simple_xml_with_ns(self):
+    def test_simple_xml(self, chunk_size=None):
         parser = ET.XMLPullParser()
         self.assert_event_tags(parser, [])
-        self._feed(parser, "<!-- comment -->\n")
-        self.assert_event_tags(parser, [])
-        self._feed(parser, "<root xmlns='namespace'>\n")
+        self._feed(parser, "<!-- comment -->\n", chunk_size)
         self.assert_event_tags(parser, [])
-        self._feed(parser, "<element key='value'>text</element")
+        self._feed(parser,
+                   "<root>\n  <element key='value'>text</element",
+                   chunk_size)
         self.assert_event_tags(parser, [])
-        self._feed(parser, ">\n")
-        self.assert_event_tags(parser, [('end', '{namespace}element')])
-        self._feed(parser, "<element>text</element>tail\n")
-        self._feed(parser, "<empty-element/>\n")
+        self._feed(parser, ">\n", chunk_size)
+        self.assert_event_tags(parser, [('end', 'element')])
+        self._feed(parser, "<element>text</element>tail\n", chunk_size)
+        self._feed(parser, "<empty-element/>\n", chunk_size)
         self.assert_event_tags(parser, [
-            ('end', '{namespace}element'),
-            ('end', '{namespace}empty-element'),
+            ('end', 'element'),
+            ('end', 'empty-element'),
             ])
-        self._feed(parser, "</root>\n")
-        self.assert_event_tags(parser, [('end', '{namespace}root')])
+        self._feed(parser, "</root>\n", chunk_size)
+        self.assert_event_tags(parser, [('end', 'root')])
         self.assertIsNone(parser.close())
 
+    @fails_with_expat
+    def test_simple_xml_chunk_1(self):
+        self.test_simple_xml(chunk_size=1)
+
+    @fails_with_expat
+    def test_simple_xml_chunk_5(self):
+        self.test_simple_xml(chunk_size=5)
+
+    def test_simple_xml_chunk_22(self):
+        self.test_simple_xml(chunk_size=22)
+
     def test_ns_events(self):
         parser = ET.XMLPullParser(events=('start-ns', 'end-ns'))
         self._feed(parser, "<!-- comment -->\n")
