17db96d56Sopenharmony_ci# regression test for SAX 2.0
27db96d56Sopenharmony_ci# $Id$
37db96d56Sopenharmony_ci
47db96d56Sopenharmony_cifrom xml.sax import make_parser, ContentHandler, \
57db96d56Sopenharmony_ci                    SAXException, SAXReaderNotAvailable, SAXParseException
67db96d56Sopenharmony_ciimport unittest
77db96d56Sopenharmony_cifrom unittest import mock
87db96d56Sopenharmony_citry:
97db96d56Sopenharmony_ci    make_parser()
107db96d56Sopenharmony_ciexcept SAXReaderNotAvailable:
117db96d56Sopenharmony_ci    # don't try to test this module if we cannot create a parser
127db96d56Sopenharmony_ci    raise unittest.SkipTest("no XML parsers available")
137db96d56Sopenharmony_cifrom xml.sax.saxutils import XMLGenerator, escape, unescape, quoteattr, \
147db96d56Sopenharmony_ci                             XMLFilterBase, prepare_input_source
157db96d56Sopenharmony_cifrom xml.sax.expatreader import create_parser
167db96d56Sopenharmony_cifrom xml.sax.handler import (feature_namespaces, feature_external_ges,
177db96d56Sopenharmony_ci                             LexicalHandler)
187db96d56Sopenharmony_cifrom xml.sax.xmlreader import InputSource, AttributesImpl, AttributesNSImpl
197db96d56Sopenharmony_cifrom io import BytesIO, StringIO
207db96d56Sopenharmony_ciimport codecs
217db96d56Sopenharmony_ciimport os.path
227db96d56Sopenharmony_ciimport shutil
237db96d56Sopenharmony_ciimport sys
247db96d56Sopenharmony_cifrom urllib.error import URLError
257db96d56Sopenharmony_ciimport urllib.request
267db96d56Sopenharmony_cifrom test.support import os_helper
277db96d56Sopenharmony_cifrom test.support import findfile
287db96d56Sopenharmony_cifrom test.support.os_helper import FakePath, TESTFN
297db96d56Sopenharmony_ci
307db96d56Sopenharmony_ci
317db96d56Sopenharmony_ciTEST_XMLFILE = findfile("test.xml", subdir="xmltestdata")
327db96d56Sopenharmony_ciTEST_XMLFILE_OUT = findfile("test.xml.out", subdir="xmltestdata")
337db96d56Sopenharmony_citry:
347db96d56Sopenharmony_ci    TEST_XMLFILE.encode("utf-8")
357db96d56Sopenharmony_ci    TEST_XMLFILE_OUT.encode("utf-8")
367db96d56Sopenharmony_ciexcept UnicodeEncodeError:
377db96d56Sopenharmony_ci    raise unittest.SkipTest("filename is not encodable to utf8")
387db96d56Sopenharmony_ci
397db96d56Sopenharmony_cisupports_nonascii_filenames = True
407db96d56Sopenharmony_ciif not os.path.supports_unicode_filenames:
417db96d56Sopenharmony_ci    try:
427db96d56Sopenharmony_ci        os_helper.TESTFN_UNICODE.encode(sys.getfilesystemencoding())
437db96d56Sopenharmony_ci    except (UnicodeError, TypeError):
447db96d56Sopenharmony_ci        # Either the file system encoding is None, or the file name
457db96d56Sopenharmony_ci        # cannot be encoded in the file system encoding.
467db96d56Sopenharmony_ci        supports_nonascii_filenames = False
477db96d56Sopenharmony_cirequires_nonascii_filenames = unittest.skipUnless(
487db96d56Sopenharmony_ci        supports_nonascii_filenames,
497db96d56Sopenharmony_ci        'Requires non-ascii filenames support')
507db96d56Sopenharmony_ci
517db96d56Sopenharmony_cins_uri = "http://www.python.org/xml-ns/saxtest/"
527db96d56Sopenharmony_ci
537db96d56Sopenharmony_ciclass XmlTestBase(unittest.TestCase):
547db96d56Sopenharmony_ci    def verify_empty_attrs(self, attrs):
557db96d56Sopenharmony_ci        self.assertRaises(KeyError, attrs.getValue, "attr")
567db96d56Sopenharmony_ci        self.assertRaises(KeyError, attrs.getValueByQName, "attr")
577db96d56Sopenharmony_ci        self.assertRaises(KeyError, attrs.getNameByQName, "attr")
587db96d56Sopenharmony_ci        self.assertRaises(KeyError, attrs.getQNameByName, "attr")
597db96d56Sopenharmony_ci        self.assertRaises(KeyError, attrs.__getitem__, "attr")
607db96d56Sopenharmony_ci        self.assertEqual(attrs.getLength(), 0)
617db96d56Sopenharmony_ci        self.assertEqual(attrs.getNames(), [])
627db96d56Sopenharmony_ci        self.assertEqual(attrs.getQNames(), [])
637db96d56Sopenharmony_ci        self.assertEqual(len(attrs), 0)
647db96d56Sopenharmony_ci        self.assertNotIn("attr", attrs)
657db96d56Sopenharmony_ci        self.assertEqual(list(attrs.keys()), [])
667db96d56Sopenharmony_ci        self.assertEqual(attrs.get("attrs"), None)
677db96d56Sopenharmony_ci        self.assertEqual(attrs.get("attrs", 25), 25)
687db96d56Sopenharmony_ci        self.assertEqual(list(attrs.items()), [])
697db96d56Sopenharmony_ci        self.assertEqual(list(attrs.values()), [])
707db96d56Sopenharmony_ci
717db96d56Sopenharmony_ci    def verify_empty_nsattrs(self, attrs):
727db96d56Sopenharmony_ci        self.assertRaises(KeyError, attrs.getValue, (ns_uri, "attr"))
737db96d56Sopenharmony_ci        self.assertRaises(KeyError, attrs.getValueByQName, "ns:attr")
747db96d56Sopenharmony_ci        self.assertRaises(KeyError, attrs.getNameByQName, "ns:attr")
757db96d56Sopenharmony_ci        self.assertRaises(KeyError, attrs.getQNameByName, (ns_uri, "attr"))
767db96d56Sopenharmony_ci        self.assertRaises(KeyError, attrs.__getitem__, (ns_uri, "attr"))
777db96d56Sopenharmony_ci        self.assertEqual(attrs.getLength(), 0)
787db96d56Sopenharmony_ci        self.assertEqual(attrs.getNames(), [])
797db96d56Sopenharmony_ci        self.assertEqual(attrs.getQNames(), [])
807db96d56Sopenharmony_ci        self.assertEqual(len(attrs), 0)
817db96d56Sopenharmony_ci        self.assertNotIn((ns_uri, "attr"), attrs)
827db96d56Sopenharmony_ci        self.assertEqual(list(attrs.keys()), [])
837db96d56Sopenharmony_ci        self.assertEqual(attrs.get((ns_uri, "attr")), None)
847db96d56Sopenharmony_ci        self.assertEqual(attrs.get((ns_uri, "attr"), 25), 25)
857db96d56Sopenharmony_ci        self.assertEqual(list(attrs.items()), [])
867db96d56Sopenharmony_ci        self.assertEqual(list(attrs.values()), [])
877db96d56Sopenharmony_ci
887db96d56Sopenharmony_ci    def verify_attrs_wattr(self, attrs):
897db96d56Sopenharmony_ci        self.assertEqual(attrs.getLength(), 1)
907db96d56Sopenharmony_ci        self.assertEqual(attrs.getNames(), ["attr"])
917db96d56Sopenharmony_ci        self.assertEqual(attrs.getQNames(), ["attr"])
927db96d56Sopenharmony_ci        self.assertEqual(len(attrs), 1)
937db96d56Sopenharmony_ci        self.assertIn("attr", attrs)
947db96d56Sopenharmony_ci        self.assertEqual(list(attrs.keys()), ["attr"])
957db96d56Sopenharmony_ci        self.assertEqual(attrs.get("attr"), "val")
967db96d56Sopenharmony_ci        self.assertEqual(attrs.get("attr", 25), "val")
977db96d56Sopenharmony_ci        self.assertEqual(list(attrs.items()), [("attr", "val")])
987db96d56Sopenharmony_ci        self.assertEqual(list(attrs.values()), ["val"])
997db96d56Sopenharmony_ci        self.assertEqual(attrs.getValue("attr"), "val")
1007db96d56Sopenharmony_ci        self.assertEqual(attrs.getValueByQName("attr"), "val")
1017db96d56Sopenharmony_ci        self.assertEqual(attrs.getNameByQName("attr"), "attr")
1027db96d56Sopenharmony_ci        self.assertEqual(attrs["attr"], "val")
1037db96d56Sopenharmony_ci        self.assertEqual(attrs.getQNameByName("attr"), "attr")
1047db96d56Sopenharmony_ci
1057db96d56Sopenharmony_ci
1067db96d56Sopenharmony_cidef xml_str(doc, encoding=None):
1077db96d56Sopenharmony_ci    if encoding is None:
1087db96d56Sopenharmony_ci        return doc
1097db96d56Sopenharmony_ci    return '<?xml version="1.0" encoding="%s"?>\n%s' % (encoding, doc)
1107db96d56Sopenharmony_ci
1117db96d56Sopenharmony_cidef xml_bytes(doc, encoding, decl_encoding=...):
1127db96d56Sopenharmony_ci    if decl_encoding is ...:
1137db96d56Sopenharmony_ci        decl_encoding = encoding
1147db96d56Sopenharmony_ci    return xml_str(doc, decl_encoding).encode(encoding, 'xmlcharrefreplace')
1157db96d56Sopenharmony_ci
1167db96d56Sopenharmony_cidef make_xml_file(doc, encoding, decl_encoding=...):
1177db96d56Sopenharmony_ci    if decl_encoding is ...:
1187db96d56Sopenharmony_ci        decl_encoding = encoding
1197db96d56Sopenharmony_ci    with open(TESTFN, 'w', encoding=encoding, errors='xmlcharrefreplace') as f:
1207db96d56Sopenharmony_ci        f.write(xml_str(doc, decl_encoding))
1217db96d56Sopenharmony_ci
1227db96d56Sopenharmony_ci
1237db96d56Sopenharmony_ciclass ParseTest(unittest.TestCase):
1247db96d56Sopenharmony_ci    data = '<money value="$\xa3\u20ac\U0001017b">$\xa3\u20ac\U0001017b</money>'
1257db96d56Sopenharmony_ci
1267db96d56Sopenharmony_ci    def tearDown(self):
1277db96d56Sopenharmony_ci        os_helper.unlink(TESTFN)
1287db96d56Sopenharmony_ci
1297db96d56Sopenharmony_ci    def check_parse(self, f):
1307db96d56Sopenharmony_ci        from xml.sax import parse
1317db96d56Sopenharmony_ci        result = StringIO()
1327db96d56Sopenharmony_ci        parse(f, XMLGenerator(result, 'utf-8'))
1337db96d56Sopenharmony_ci        self.assertEqual(result.getvalue(), xml_str(self.data, 'utf-8'))
1347db96d56Sopenharmony_ci
1357db96d56Sopenharmony_ci    def test_parse_text(self):
1367db96d56Sopenharmony_ci        encodings = ('us-ascii', 'iso-8859-1', 'utf-8',
1377db96d56Sopenharmony_ci                     'utf-16', 'utf-16le', 'utf-16be')
1387db96d56Sopenharmony_ci        for encoding in encodings:
1397db96d56Sopenharmony_ci            self.check_parse(StringIO(xml_str(self.data, encoding)))
1407db96d56Sopenharmony_ci            make_xml_file(self.data, encoding)
1417db96d56Sopenharmony_ci            with open(TESTFN, 'r', encoding=encoding) as f:
1427db96d56Sopenharmony_ci                self.check_parse(f)
1437db96d56Sopenharmony_ci            self.check_parse(StringIO(self.data))
1447db96d56Sopenharmony_ci            make_xml_file(self.data, encoding, None)
1457db96d56Sopenharmony_ci            with open(TESTFN, 'r', encoding=encoding) as f:
1467db96d56Sopenharmony_ci                self.check_parse(f)
1477db96d56Sopenharmony_ci
1487db96d56Sopenharmony_ci    def test_parse_bytes(self):
1497db96d56Sopenharmony_ci        # UTF-8 is default encoding, US-ASCII is compatible with UTF-8,
1507db96d56Sopenharmony_ci        # UTF-16 is autodetected
1517db96d56Sopenharmony_ci        encodings = ('us-ascii', 'utf-8', 'utf-16', 'utf-16le', 'utf-16be')
1527db96d56Sopenharmony_ci        for encoding in encodings:
1537db96d56Sopenharmony_ci            self.check_parse(BytesIO(xml_bytes(self.data, encoding)))
1547db96d56Sopenharmony_ci            make_xml_file(self.data, encoding)
1557db96d56Sopenharmony_ci            self.check_parse(TESTFN)
1567db96d56Sopenharmony_ci            with open(TESTFN, 'rb') as f:
1577db96d56Sopenharmony_ci                self.check_parse(f)
1587db96d56Sopenharmony_ci            self.check_parse(BytesIO(xml_bytes(self.data, encoding, None)))
1597db96d56Sopenharmony_ci            make_xml_file(self.data, encoding, None)
1607db96d56Sopenharmony_ci            self.check_parse(TESTFN)
1617db96d56Sopenharmony_ci            with open(TESTFN, 'rb') as f:
1627db96d56Sopenharmony_ci                self.check_parse(f)
1637db96d56Sopenharmony_ci        # accept UTF-8 with BOM
1647db96d56Sopenharmony_ci        self.check_parse(BytesIO(xml_bytes(self.data, 'utf-8-sig', 'utf-8')))
1657db96d56Sopenharmony_ci        make_xml_file(self.data, 'utf-8-sig', 'utf-8')
1667db96d56Sopenharmony_ci        self.check_parse(TESTFN)
1677db96d56Sopenharmony_ci        with open(TESTFN, 'rb') as f:
1687db96d56Sopenharmony_ci            self.check_parse(f)
1697db96d56Sopenharmony_ci        self.check_parse(BytesIO(xml_bytes(self.data, 'utf-8-sig', None)))
1707db96d56Sopenharmony_ci        make_xml_file(self.data, 'utf-8-sig', None)
1717db96d56Sopenharmony_ci        self.check_parse(TESTFN)
1727db96d56Sopenharmony_ci        with open(TESTFN, 'rb') as f:
1737db96d56Sopenharmony_ci            self.check_parse(f)
1747db96d56Sopenharmony_ci        # accept data with declared encoding
1757db96d56Sopenharmony_ci        self.check_parse(BytesIO(xml_bytes(self.data, 'iso-8859-1')))
1767db96d56Sopenharmony_ci        make_xml_file(self.data, 'iso-8859-1')
1777db96d56Sopenharmony_ci        self.check_parse(TESTFN)
1787db96d56Sopenharmony_ci        with open(TESTFN, 'rb') as f:
1797db96d56Sopenharmony_ci            self.check_parse(f)
1807db96d56Sopenharmony_ci        # fail on non-UTF-8 incompatible data without declared encoding
1817db96d56Sopenharmony_ci        with self.assertRaises(SAXException):
1827db96d56Sopenharmony_ci            self.check_parse(BytesIO(xml_bytes(self.data, 'iso-8859-1', None)))
1837db96d56Sopenharmony_ci        make_xml_file(self.data, 'iso-8859-1', None)
1847db96d56Sopenharmony_ci        with self.assertRaises(SAXException):
1857db96d56Sopenharmony_ci            self.check_parse(TESTFN)
1867db96d56Sopenharmony_ci        with open(TESTFN, 'rb') as f:
1877db96d56Sopenharmony_ci            with self.assertRaises(SAXException):
1887db96d56Sopenharmony_ci                self.check_parse(f)
1897db96d56Sopenharmony_ci
1907db96d56Sopenharmony_ci    def test_parse_path_object(self):
1917db96d56Sopenharmony_ci        make_xml_file(self.data, 'utf-8', None)
1927db96d56Sopenharmony_ci        self.check_parse(FakePath(TESTFN))
1937db96d56Sopenharmony_ci
1947db96d56Sopenharmony_ci    def test_parse_InputSource(self):
1957db96d56Sopenharmony_ci        # accept data without declared but with explicitly specified encoding
1967db96d56Sopenharmony_ci        make_xml_file(self.data, 'iso-8859-1', None)
1977db96d56Sopenharmony_ci        with open(TESTFN, 'rb') as f:
1987db96d56Sopenharmony_ci            input = InputSource()
1997db96d56Sopenharmony_ci            input.setByteStream(f)
2007db96d56Sopenharmony_ci            input.setEncoding('iso-8859-1')
2017db96d56Sopenharmony_ci            self.check_parse(input)
2027db96d56Sopenharmony_ci
2037db96d56Sopenharmony_ci    def test_parse_close_source(self):
2047db96d56Sopenharmony_ci        builtin_open = open
2057db96d56Sopenharmony_ci        fileobj = None
2067db96d56Sopenharmony_ci
2077db96d56Sopenharmony_ci        def mock_open(*args):
2087db96d56Sopenharmony_ci            nonlocal fileobj
2097db96d56Sopenharmony_ci            fileobj = builtin_open(*args)
2107db96d56Sopenharmony_ci            return fileobj
2117db96d56Sopenharmony_ci
2127db96d56Sopenharmony_ci        with mock.patch('xml.sax.saxutils.open', side_effect=mock_open):
2137db96d56Sopenharmony_ci            make_xml_file(self.data, 'iso-8859-1', None)
2147db96d56Sopenharmony_ci            with self.assertRaises(SAXException):
2157db96d56Sopenharmony_ci                self.check_parse(TESTFN)
2167db96d56Sopenharmony_ci            self.assertTrue(fileobj.closed)
2177db96d56Sopenharmony_ci
2187db96d56Sopenharmony_ci    def check_parseString(self, s):
2197db96d56Sopenharmony_ci        from xml.sax import parseString
2207db96d56Sopenharmony_ci        result = StringIO()
2217db96d56Sopenharmony_ci        parseString(s, XMLGenerator(result, 'utf-8'))
2227db96d56Sopenharmony_ci        self.assertEqual(result.getvalue(), xml_str(self.data, 'utf-8'))
2237db96d56Sopenharmony_ci
2247db96d56Sopenharmony_ci    def test_parseString_text(self):
2257db96d56Sopenharmony_ci        encodings = ('us-ascii', 'iso-8859-1', 'utf-8',
2267db96d56Sopenharmony_ci                     'utf-16', 'utf-16le', 'utf-16be')
2277db96d56Sopenharmony_ci        for encoding in encodings:
2287db96d56Sopenharmony_ci            self.check_parseString(xml_str(self.data, encoding))
2297db96d56Sopenharmony_ci        self.check_parseString(self.data)
2307db96d56Sopenharmony_ci
2317db96d56Sopenharmony_ci    def test_parseString_bytes(self):
2327db96d56Sopenharmony_ci        # UTF-8 is default encoding, US-ASCII is compatible with UTF-8,
2337db96d56Sopenharmony_ci        # UTF-16 is autodetected
2347db96d56Sopenharmony_ci        encodings = ('us-ascii', 'utf-8', 'utf-16', 'utf-16le', 'utf-16be')
2357db96d56Sopenharmony_ci        for encoding in encodings:
2367db96d56Sopenharmony_ci            self.check_parseString(xml_bytes(self.data, encoding))
2377db96d56Sopenharmony_ci            self.check_parseString(xml_bytes(self.data, encoding, None))
2387db96d56Sopenharmony_ci        # accept UTF-8 with BOM
2397db96d56Sopenharmony_ci        self.check_parseString(xml_bytes(self.data, 'utf-8-sig', 'utf-8'))
2407db96d56Sopenharmony_ci        self.check_parseString(xml_bytes(self.data, 'utf-8-sig', None))
2417db96d56Sopenharmony_ci        # accept data with declared encoding
2427db96d56Sopenharmony_ci        self.check_parseString(xml_bytes(self.data, 'iso-8859-1'))
2437db96d56Sopenharmony_ci        # fail on non-UTF-8 incompatible data without declared encoding
2447db96d56Sopenharmony_ci        with self.assertRaises(SAXException):
2457db96d56Sopenharmony_ci            self.check_parseString(xml_bytes(self.data, 'iso-8859-1', None))
2467db96d56Sopenharmony_ci
2477db96d56Sopenharmony_ciclass MakeParserTest(unittest.TestCase):
2487db96d56Sopenharmony_ci    def test_make_parser2(self):
2497db96d56Sopenharmony_ci        # Creating parsers several times in a row should succeed.
2507db96d56Sopenharmony_ci        # Testing this because there have been failures of this kind
2517db96d56Sopenharmony_ci        # before.
2527db96d56Sopenharmony_ci        from xml.sax import make_parser
2537db96d56Sopenharmony_ci        p = make_parser()
2547db96d56Sopenharmony_ci        from xml.sax import make_parser
2557db96d56Sopenharmony_ci        p = make_parser()
2567db96d56Sopenharmony_ci        from xml.sax import make_parser
2577db96d56Sopenharmony_ci        p = make_parser()
2587db96d56Sopenharmony_ci        from xml.sax import make_parser
2597db96d56Sopenharmony_ci        p = make_parser()
2607db96d56Sopenharmony_ci        from xml.sax import make_parser
2617db96d56Sopenharmony_ci        p = make_parser()
2627db96d56Sopenharmony_ci        from xml.sax import make_parser
2637db96d56Sopenharmony_ci        p = make_parser()
2647db96d56Sopenharmony_ci
2657db96d56Sopenharmony_ci    def test_make_parser3(self):
2667db96d56Sopenharmony_ci        # Testing that make_parser can handle different types of
2677db96d56Sopenharmony_ci        # iterables.
2687db96d56Sopenharmony_ci        make_parser(['module'])
2697db96d56Sopenharmony_ci        make_parser(('module', ))
2707db96d56Sopenharmony_ci        make_parser({'module'})
2717db96d56Sopenharmony_ci        make_parser(frozenset({'module'}))
2727db96d56Sopenharmony_ci        make_parser({'module': None})
2737db96d56Sopenharmony_ci        make_parser(iter(['module']))
2747db96d56Sopenharmony_ci
2757db96d56Sopenharmony_ci    def test_make_parser4(self):
2767db96d56Sopenharmony_ci        # Testing that make_parser can handle empty iterables.
2777db96d56Sopenharmony_ci        make_parser([])
2787db96d56Sopenharmony_ci        make_parser(tuple())
2797db96d56Sopenharmony_ci        make_parser(set())
2807db96d56Sopenharmony_ci        make_parser(frozenset())
2817db96d56Sopenharmony_ci        make_parser({})
2827db96d56Sopenharmony_ci        make_parser(iter([]))
2837db96d56Sopenharmony_ci
2847db96d56Sopenharmony_ci    def test_make_parser5(self):
2857db96d56Sopenharmony_ci        # Testing that make_parser can handle iterables with more than
2867db96d56Sopenharmony_ci        # one item.
2877db96d56Sopenharmony_ci        make_parser(['module1', 'module2'])
2887db96d56Sopenharmony_ci        make_parser(('module1', 'module2'))
2897db96d56Sopenharmony_ci        make_parser({'module1', 'module2'})
2907db96d56Sopenharmony_ci        make_parser(frozenset({'module1', 'module2'}))
2917db96d56Sopenharmony_ci        make_parser({'module1': None, 'module2': None})
2927db96d56Sopenharmony_ci        make_parser(iter(['module1', 'module2']))
2937db96d56Sopenharmony_ci
2947db96d56Sopenharmony_ci# ===========================================================================
2957db96d56Sopenharmony_ci#
2967db96d56Sopenharmony_ci#   saxutils tests
2977db96d56Sopenharmony_ci#
2987db96d56Sopenharmony_ci# ===========================================================================
2997db96d56Sopenharmony_ci
3007db96d56Sopenharmony_ciclass SaxutilsTest(unittest.TestCase):
3017db96d56Sopenharmony_ci    # ===== escape
3027db96d56Sopenharmony_ci    def test_escape_basic(self):
3037db96d56Sopenharmony_ci        self.assertEqual(escape("Donald Duck & Co"), "Donald Duck &amp; Co")
3047db96d56Sopenharmony_ci
3057db96d56Sopenharmony_ci    def test_escape_all(self):
3067db96d56Sopenharmony_ci        self.assertEqual(escape("<Donald Duck & Co>"),
3077db96d56Sopenharmony_ci                         "&lt;Donald Duck &amp; Co&gt;")
3087db96d56Sopenharmony_ci
3097db96d56Sopenharmony_ci    def test_escape_extra(self):
3107db96d56Sopenharmony_ci        self.assertEqual(escape("Hei på deg", {"å" : "&aring;"}),
3117db96d56Sopenharmony_ci                         "Hei p&aring; deg")
3127db96d56Sopenharmony_ci
3137db96d56Sopenharmony_ci    # ===== unescape
3147db96d56Sopenharmony_ci    def test_unescape_basic(self):
3157db96d56Sopenharmony_ci        self.assertEqual(unescape("Donald Duck &amp; Co"), "Donald Duck & Co")
3167db96d56Sopenharmony_ci
3177db96d56Sopenharmony_ci    def test_unescape_all(self):
3187db96d56Sopenharmony_ci        self.assertEqual(unescape("&lt;Donald Duck &amp; Co&gt;"),
3197db96d56Sopenharmony_ci                         "<Donald Duck & Co>")
3207db96d56Sopenharmony_ci
3217db96d56Sopenharmony_ci    def test_unescape_extra(self):
3227db96d56Sopenharmony_ci        self.assertEqual(unescape("Hei på deg", {"å" : "&aring;"}),
3237db96d56Sopenharmony_ci                         "Hei p&aring; deg")
3247db96d56Sopenharmony_ci
3257db96d56Sopenharmony_ci    def test_unescape_amp_extra(self):
3267db96d56Sopenharmony_ci        self.assertEqual(unescape("&amp;foo;", {"&foo;": "splat"}), "&foo;")
3277db96d56Sopenharmony_ci
3287db96d56Sopenharmony_ci    # ===== quoteattr
3297db96d56Sopenharmony_ci    def test_quoteattr_basic(self):
3307db96d56Sopenharmony_ci        self.assertEqual(quoteattr("Donald Duck & Co"),
3317db96d56Sopenharmony_ci                         '"Donald Duck &amp; Co"')
3327db96d56Sopenharmony_ci
3337db96d56Sopenharmony_ci    def test_single_quoteattr(self):
3347db96d56Sopenharmony_ci        self.assertEqual(quoteattr('Includes "double" quotes'),
3357db96d56Sopenharmony_ci                         '\'Includes "double" quotes\'')
3367db96d56Sopenharmony_ci
3377db96d56Sopenharmony_ci    def test_double_quoteattr(self):
3387db96d56Sopenharmony_ci        self.assertEqual(quoteattr("Includes 'single' quotes"),
3397db96d56Sopenharmony_ci                         "\"Includes 'single' quotes\"")
3407db96d56Sopenharmony_ci
3417db96d56Sopenharmony_ci    def test_single_double_quoteattr(self):
3427db96d56Sopenharmony_ci        self.assertEqual(quoteattr("Includes 'single' and \"double\" quotes"),
3437db96d56Sopenharmony_ci                         "\"Includes 'single' and &quot;double&quot; quotes\"")
3447db96d56Sopenharmony_ci
3457db96d56Sopenharmony_ci    # ===== make_parser
3467db96d56Sopenharmony_ci    def test_make_parser(self):
3477db96d56Sopenharmony_ci        # Creating a parser should succeed - it should fall back
3487db96d56Sopenharmony_ci        # to the expatreader
3497db96d56Sopenharmony_ci        p = make_parser(['xml.parsers.no_such_parser'])
3507db96d56Sopenharmony_ci
3517db96d56Sopenharmony_ci
3527db96d56Sopenharmony_ciclass PrepareInputSourceTest(unittest.TestCase):
3537db96d56Sopenharmony_ci
3547db96d56Sopenharmony_ci    def setUp(self):
3557db96d56Sopenharmony_ci        self.file = os_helper.TESTFN
3567db96d56Sopenharmony_ci        with open(self.file, "w") as tmp:
3577db96d56Sopenharmony_ci            tmp.write("This was read from a file.")
3587db96d56Sopenharmony_ci
3597db96d56Sopenharmony_ci    def tearDown(self):
3607db96d56Sopenharmony_ci        os_helper.unlink(self.file)
3617db96d56Sopenharmony_ci
3627db96d56Sopenharmony_ci    def make_byte_stream(self):
3637db96d56Sopenharmony_ci        return BytesIO(b"This is a byte stream.")
3647db96d56Sopenharmony_ci
3657db96d56Sopenharmony_ci    def make_character_stream(self):
3667db96d56Sopenharmony_ci        return StringIO("This is a character stream.")
3677db96d56Sopenharmony_ci
3687db96d56Sopenharmony_ci    def checkContent(self, stream, content):
3697db96d56Sopenharmony_ci        self.assertIsNotNone(stream)
3707db96d56Sopenharmony_ci        self.assertEqual(stream.read(), content)
3717db96d56Sopenharmony_ci        stream.close()
3727db96d56Sopenharmony_ci
3737db96d56Sopenharmony_ci
3747db96d56Sopenharmony_ci    def test_character_stream(self):
3757db96d56Sopenharmony_ci        # If the source is an InputSource with a character stream, use it.
3767db96d56Sopenharmony_ci        src = InputSource(self.file)
3777db96d56Sopenharmony_ci        src.setCharacterStream(self.make_character_stream())
3787db96d56Sopenharmony_ci        prep = prepare_input_source(src)
3797db96d56Sopenharmony_ci        self.assertIsNone(prep.getByteStream())
3807db96d56Sopenharmony_ci        self.checkContent(prep.getCharacterStream(),
3817db96d56Sopenharmony_ci                          "This is a character stream.")
3827db96d56Sopenharmony_ci
3837db96d56Sopenharmony_ci    def test_byte_stream(self):
3847db96d56Sopenharmony_ci        # If the source is an InputSource that does not have a character
3857db96d56Sopenharmony_ci        # stream but does have a byte stream, use the byte stream.
3867db96d56Sopenharmony_ci        src = InputSource(self.file)
3877db96d56Sopenharmony_ci        src.setByteStream(self.make_byte_stream())
3887db96d56Sopenharmony_ci        prep = prepare_input_source(src)
3897db96d56Sopenharmony_ci        self.assertIsNone(prep.getCharacterStream())
3907db96d56Sopenharmony_ci        self.checkContent(prep.getByteStream(),
3917db96d56Sopenharmony_ci                          b"This is a byte stream.")
3927db96d56Sopenharmony_ci
3937db96d56Sopenharmony_ci    def test_system_id(self):
3947db96d56Sopenharmony_ci        # If the source is an InputSource that has neither a character
3957db96d56Sopenharmony_ci        # stream nor a byte stream, open the system ID.
3967db96d56Sopenharmony_ci        src = InputSource(self.file)
3977db96d56Sopenharmony_ci        prep = prepare_input_source(src)
3987db96d56Sopenharmony_ci        self.assertIsNone(prep.getCharacterStream())
3997db96d56Sopenharmony_ci        self.checkContent(prep.getByteStream(),
4007db96d56Sopenharmony_ci                          b"This was read from a file.")
4017db96d56Sopenharmony_ci
4027db96d56Sopenharmony_ci    def test_string(self):
4037db96d56Sopenharmony_ci        # If the source is a string, use it as a system ID and open it.
4047db96d56Sopenharmony_ci        prep = prepare_input_source(self.file)
4057db96d56Sopenharmony_ci        self.assertIsNone(prep.getCharacterStream())
4067db96d56Sopenharmony_ci        self.checkContent(prep.getByteStream(),
4077db96d56Sopenharmony_ci                          b"This was read from a file.")
4087db96d56Sopenharmony_ci
4097db96d56Sopenharmony_ci    def test_path_objects(self):
4107db96d56Sopenharmony_ci        # If the source is a Path object, use it as a system ID and open it.
4117db96d56Sopenharmony_ci        prep = prepare_input_source(FakePath(self.file))
4127db96d56Sopenharmony_ci        self.assertIsNone(prep.getCharacterStream())
4137db96d56Sopenharmony_ci        self.checkContent(prep.getByteStream(),
4147db96d56Sopenharmony_ci                          b"This was read from a file.")
4157db96d56Sopenharmony_ci
4167db96d56Sopenharmony_ci    def test_binary_file(self):
4177db96d56Sopenharmony_ci        # If the source is a binary file-like object, use it as a byte
4187db96d56Sopenharmony_ci        # stream.
4197db96d56Sopenharmony_ci        prep = prepare_input_source(self.make_byte_stream())
4207db96d56Sopenharmony_ci        self.assertIsNone(prep.getCharacterStream())
4217db96d56Sopenharmony_ci        self.checkContent(prep.getByteStream(),
4227db96d56Sopenharmony_ci                          b"This is a byte stream.")
4237db96d56Sopenharmony_ci
4247db96d56Sopenharmony_ci    def test_text_file(self):
4257db96d56Sopenharmony_ci        # If the source is a text file-like object, use it as a character
4267db96d56Sopenharmony_ci        # stream.
4277db96d56Sopenharmony_ci        prep = prepare_input_source(self.make_character_stream())
4287db96d56Sopenharmony_ci        self.assertIsNone(prep.getByteStream())
4297db96d56Sopenharmony_ci        self.checkContent(prep.getCharacterStream(),
4307db96d56Sopenharmony_ci                          "This is a character stream.")
4317db96d56Sopenharmony_ci
4327db96d56Sopenharmony_ci
4337db96d56Sopenharmony_ci# ===== XMLGenerator
4347db96d56Sopenharmony_ci
4357db96d56Sopenharmony_ciclass XmlgenTest:
4367db96d56Sopenharmony_ci    def test_xmlgen_basic(self):
4377db96d56Sopenharmony_ci        result = self.ioclass()
4387db96d56Sopenharmony_ci        gen = XMLGenerator(result)
4397db96d56Sopenharmony_ci        gen.startDocument()
4407db96d56Sopenharmony_ci        gen.startElement("doc", {})
4417db96d56Sopenharmony_ci        gen.endElement("doc")
4427db96d56Sopenharmony_ci        gen.endDocument()
4437db96d56Sopenharmony_ci
4447db96d56Sopenharmony_ci        self.assertEqual(result.getvalue(), self.xml("<doc></doc>"))
4457db96d56Sopenharmony_ci
4467db96d56Sopenharmony_ci    def test_xmlgen_basic_empty(self):
4477db96d56Sopenharmony_ci        result = self.ioclass()
4487db96d56Sopenharmony_ci        gen = XMLGenerator(result, short_empty_elements=True)
4497db96d56Sopenharmony_ci        gen.startDocument()
4507db96d56Sopenharmony_ci        gen.startElement("doc", {})
4517db96d56Sopenharmony_ci        gen.endElement("doc")
4527db96d56Sopenharmony_ci        gen.endDocument()
4537db96d56Sopenharmony_ci
4547db96d56Sopenharmony_ci        self.assertEqual(result.getvalue(), self.xml("<doc/>"))
4557db96d56Sopenharmony_ci
4567db96d56Sopenharmony_ci    def test_xmlgen_content(self):
4577db96d56Sopenharmony_ci        result = self.ioclass()
4587db96d56Sopenharmony_ci        gen = XMLGenerator(result)
4597db96d56Sopenharmony_ci
4607db96d56Sopenharmony_ci        gen.startDocument()
4617db96d56Sopenharmony_ci        gen.startElement("doc", {})
4627db96d56Sopenharmony_ci        gen.characters("huhei")
4637db96d56Sopenharmony_ci        gen.endElement("doc")
4647db96d56Sopenharmony_ci        gen.endDocument()
4657db96d56Sopenharmony_ci
4667db96d56Sopenharmony_ci        self.assertEqual(result.getvalue(), self.xml("<doc>huhei</doc>"))
4677db96d56Sopenharmony_ci
4687db96d56Sopenharmony_ci    def test_xmlgen_content_empty(self):
4697db96d56Sopenharmony_ci        result = self.ioclass()
4707db96d56Sopenharmony_ci        gen = XMLGenerator(result, short_empty_elements=True)
4717db96d56Sopenharmony_ci
4727db96d56Sopenharmony_ci        gen.startDocument()
4737db96d56Sopenharmony_ci        gen.startElement("doc", {})
4747db96d56Sopenharmony_ci        gen.characters("huhei")
4757db96d56Sopenharmony_ci        gen.endElement("doc")
4767db96d56Sopenharmony_ci        gen.endDocument()
4777db96d56Sopenharmony_ci
4787db96d56Sopenharmony_ci        self.assertEqual(result.getvalue(), self.xml("<doc>huhei</doc>"))
4797db96d56Sopenharmony_ci
4807db96d56Sopenharmony_ci    def test_xmlgen_pi(self):
4817db96d56Sopenharmony_ci        result = self.ioclass()
4827db96d56Sopenharmony_ci        gen = XMLGenerator(result)
4837db96d56Sopenharmony_ci
4847db96d56Sopenharmony_ci        gen.startDocument()
4857db96d56Sopenharmony_ci        gen.processingInstruction("test", "data")
4867db96d56Sopenharmony_ci        gen.startElement("doc", {})
4877db96d56Sopenharmony_ci        gen.endElement("doc")
4887db96d56Sopenharmony_ci        gen.endDocument()
4897db96d56Sopenharmony_ci
4907db96d56Sopenharmony_ci        self.assertEqual(result.getvalue(),
4917db96d56Sopenharmony_ci            self.xml("<?test data?><doc></doc>"))
4927db96d56Sopenharmony_ci
4937db96d56Sopenharmony_ci    def test_xmlgen_content_escape(self):
4947db96d56Sopenharmony_ci        result = self.ioclass()
4957db96d56Sopenharmony_ci        gen = XMLGenerator(result)
4967db96d56Sopenharmony_ci
4977db96d56Sopenharmony_ci        gen.startDocument()
4987db96d56Sopenharmony_ci        gen.startElement("doc", {})
4997db96d56Sopenharmony_ci        gen.characters("<huhei&")
5007db96d56Sopenharmony_ci        gen.endElement("doc")
5017db96d56Sopenharmony_ci        gen.endDocument()
5027db96d56Sopenharmony_ci
5037db96d56Sopenharmony_ci        self.assertEqual(result.getvalue(),
5047db96d56Sopenharmony_ci            self.xml("<doc>&lt;huhei&amp;</doc>"))
5057db96d56Sopenharmony_ci
5067db96d56Sopenharmony_ci    def test_xmlgen_attr_escape(self):
5077db96d56Sopenharmony_ci        result = self.ioclass()
5087db96d56Sopenharmony_ci        gen = XMLGenerator(result)
5097db96d56Sopenharmony_ci
5107db96d56Sopenharmony_ci        gen.startDocument()
5117db96d56Sopenharmony_ci        gen.startElement("doc", {"a": '"'})
5127db96d56Sopenharmony_ci        gen.startElement("e", {"a": "'"})
5137db96d56Sopenharmony_ci        gen.endElement("e")
5147db96d56Sopenharmony_ci        gen.startElement("e", {"a": "'\""})
5157db96d56Sopenharmony_ci        gen.endElement("e")
5167db96d56Sopenharmony_ci        gen.startElement("e", {"a": "\n\r\t"})
5177db96d56Sopenharmony_ci        gen.endElement("e")
5187db96d56Sopenharmony_ci        gen.endElement("doc")
5197db96d56Sopenharmony_ci        gen.endDocument()
5207db96d56Sopenharmony_ci
5217db96d56Sopenharmony_ci        self.assertEqual(result.getvalue(), self.xml(
5227db96d56Sopenharmony_ci            "<doc a='\"'><e a=\"'\"></e>"
5237db96d56Sopenharmony_ci            "<e a=\"'&quot;\"></e>"
5247db96d56Sopenharmony_ci            "<e a=\"&#10;&#13;&#9;\"></e></doc>"))
5257db96d56Sopenharmony_ci
5267db96d56Sopenharmony_ci    def test_xmlgen_encoding(self):
5277db96d56Sopenharmony_ci        encodings = ('iso-8859-15', 'utf-8', 'utf-8-sig',
5287db96d56Sopenharmony_ci                     'utf-16', 'utf-16be', 'utf-16le',
5297db96d56Sopenharmony_ci                     'utf-32', 'utf-32be', 'utf-32le')
5307db96d56Sopenharmony_ci        for encoding in encodings:
5317db96d56Sopenharmony_ci            result = self.ioclass()
5327db96d56Sopenharmony_ci            gen = XMLGenerator(result, encoding=encoding)
5337db96d56Sopenharmony_ci
5347db96d56Sopenharmony_ci            gen.startDocument()
5357db96d56Sopenharmony_ci            gen.startElement("doc", {"a": '\u20ac'})
5367db96d56Sopenharmony_ci            gen.characters("\u20ac")
5377db96d56Sopenharmony_ci            gen.endElement("doc")
5387db96d56Sopenharmony_ci            gen.endDocument()
5397db96d56Sopenharmony_ci
5407db96d56Sopenharmony_ci            self.assertEqual(result.getvalue(),
5417db96d56Sopenharmony_ci                self.xml('<doc a="\u20ac">\u20ac</doc>', encoding=encoding))
5427db96d56Sopenharmony_ci
5437db96d56Sopenharmony_ci    def test_xmlgen_unencodable(self):
5447db96d56Sopenharmony_ci        result = self.ioclass()
5457db96d56Sopenharmony_ci        gen = XMLGenerator(result, encoding='ascii')
5467db96d56Sopenharmony_ci
5477db96d56Sopenharmony_ci        gen.startDocument()
5487db96d56Sopenharmony_ci        gen.startElement("doc", {"a": '\u20ac'})
5497db96d56Sopenharmony_ci        gen.characters("\u20ac")
5507db96d56Sopenharmony_ci        gen.endElement("doc")
5517db96d56Sopenharmony_ci        gen.endDocument()
5527db96d56Sopenharmony_ci
5537db96d56Sopenharmony_ci        self.assertEqual(result.getvalue(),
5547db96d56Sopenharmony_ci            self.xml('<doc a="&#8364;">&#8364;</doc>', encoding='ascii'))
5557db96d56Sopenharmony_ci
5567db96d56Sopenharmony_ci    def test_xmlgen_ignorable(self):
5577db96d56Sopenharmony_ci        result = self.ioclass()
5587db96d56Sopenharmony_ci        gen = XMLGenerator(result)
5597db96d56Sopenharmony_ci
5607db96d56Sopenharmony_ci        gen.startDocument()
5617db96d56Sopenharmony_ci        gen.startElement("doc", {})
5627db96d56Sopenharmony_ci        gen.ignorableWhitespace(" ")
5637db96d56Sopenharmony_ci        gen.endElement("doc")
5647db96d56Sopenharmony_ci        gen.endDocument()
5657db96d56Sopenharmony_ci
5667db96d56Sopenharmony_ci        self.assertEqual(result.getvalue(), self.xml("<doc> </doc>"))
5677db96d56Sopenharmony_ci
5687db96d56Sopenharmony_ci    def test_xmlgen_ignorable_empty(self):
5697db96d56Sopenharmony_ci        result = self.ioclass()
5707db96d56Sopenharmony_ci        gen = XMLGenerator(result, short_empty_elements=True)
5717db96d56Sopenharmony_ci
5727db96d56Sopenharmony_ci        gen.startDocument()
5737db96d56Sopenharmony_ci        gen.startElement("doc", {})
5747db96d56Sopenharmony_ci        gen.ignorableWhitespace(" ")
5757db96d56Sopenharmony_ci        gen.endElement("doc")
5767db96d56Sopenharmony_ci        gen.endDocument()
5777db96d56Sopenharmony_ci
5787db96d56Sopenharmony_ci        self.assertEqual(result.getvalue(), self.xml("<doc> </doc>"))
5797db96d56Sopenharmony_ci
5807db96d56Sopenharmony_ci    def test_xmlgen_encoding_bytes(self):
5817db96d56Sopenharmony_ci        encodings = ('iso-8859-15', 'utf-8', 'utf-8-sig',
5827db96d56Sopenharmony_ci                     'utf-16', 'utf-16be', 'utf-16le',
5837db96d56Sopenharmony_ci                     'utf-32', 'utf-32be', 'utf-32le')
5847db96d56Sopenharmony_ci        for encoding in encodings:
5857db96d56Sopenharmony_ci            result = self.ioclass()
5867db96d56Sopenharmony_ci            gen = XMLGenerator(result, encoding=encoding)
5877db96d56Sopenharmony_ci
5887db96d56Sopenharmony_ci            gen.startDocument()
5897db96d56Sopenharmony_ci            gen.startElement("doc", {"a": '\u20ac'})
5907db96d56Sopenharmony_ci            gen.characters("\u20ac".encode(encoding))
5917db96d56Sopenharmony_ci            gen.ignorableWhitespace(" ".encode(encoding))
5927db96d56Sopenharmony_ci            gen.endElement("doc")
5937db96d56Sopenharmony_ci            gen.endDocument()
5947db96d56Sopenharmony_ci
5957db96d56Sopenharmony_ci            self.assertEqual(result.getvalue(),
5967db96d56Sopenharmony_ci                self.xml('<doc a="\u20ac">\u20ac </doc>', encoding=encoding))
5977db96d56Sopenharmony_ci
5987db96d56Sopenharmony_ci    def test_xmlgen_ns(self):
5997db96d56Sopenharmony_ci        result = self.ioclass()
6007db96d56Sopenharmony_ci        gen = XMLGenerator(result)
6017db96d56Sopenharmony_ci
6027db96d56Sopenharmony_ci        gen.startDocument()
6037db96d56Sopenharmony_ci        gen.startPrefixMapping("ns1", ns_uri)
6047db96d56Sopenharmony_ci        gen.startElementNS((ns_uri, "doc"), "ns1:doc", {})
6057db96d56Sopenharmony_ci        # add an unqualified name
6067db96d56Sopenharmony_ci        gen.startElementNS((None, "udoc"), None, {})
6077db96d56Sopenharmony_ci        gen.endElementNS((None, "udoc"), None)
6087db96d56Sopenharmony_ci        gen.endElementNS((ns_uri, "doc"), "ns1:doc")
6097db96d56Sopenharmony_ci        gen.endPrefixMapping("ns1")
6107db96d56Sopenharmony_ci        gen.endDocument()
6117db96d56Sopenharmony_ci
6127db96d56Sopenharmony_ci        self.assertEqual(result.getvalue(), self.xml(
6137db96d56Sopenharmony_ci           '<ns1:doc xmlns:ns1="%s"><udoc></udoc></ns1:doc>' %
6147db96d56Sopenharmony_ci                                         ns_uri))
6157db96d56Sopenharmony_ci
6167db96d56Sopenharmony_ci    def test_xmlgen_ns_empty(self):
6177db96d56Sopenharmony_ci        result = self.ioclass()
6187db96d56Sopenharmony_ci        gen = XMLGenerator(result, short_empty_elements=True)
6197db96d56Sopenharmony_ci
6207db96d56Sopenharmony_ci        gen.startDocument()
6217db96d56Sopenharmony_ci        gen.startPrefixMapping("ns1", ns_uri)
6227db96d56Sopenharmony_ci        gen.startElementNS((ns_uri, "doc"), "ns1:doc", {})
6237db96d56Sopenharmony_ci        # add an unqualified name
6247db96d56Sopenharmony_ci        gen.startElementNS((None, "udoc"), None, {})
6257db96d56Sopenharmony_ci        gen.endElementNS((None, "udoc"), None)
6267db96d56Sopenharmony_ci        gen.endElementNS((ns_uri, "doc"), "ns1:doc")
6277db96d56Sopenharmony_ci        gen.endPrefixMapping("ns1")
6287db96d56Sopenharmony_ci        gen.endDocument()
6297db96d56Sopenharmony_ci
6307db96d56Sopenharmony_ci        self.assertEqual(result.getvalue(), self.xml(
6317db96d56Sopenharmony_ci           '<ns1:doc xmlns:ns1="%s"><udoc/></ns1:doc>' %
6327db96d56Sopenharmony_ci                                         ns_uri))
6337db96d56Sopenharmony_ci
6347db96d56Sopenharmony_ci    def test_1463026_1(self):
6357db96d56Sopenharmony_ci        result = self.ioclass()
6367db96d56Sopenharmony_ci        gen = XMLGenerator(result)
6377db96d56Sopenharmony_ci
6387db96d56Sopenharmony_ci        gen.startDocument()
6397db96d56Sopenharmony_ci        gen.startElementNS((None, 'a'), 'a', {(None, 'b'):'c'})
6407db96d56Sopenharmony_ci        gen.endElementNS((None, 'a'), 'a')
6417db96d56Sopenharmony_ci        gen.endDocument()
6427db96d56Sopenharmony_ci
6437db96d56Sopenharmony_ci        self.assertEqual(result.getvalue(), self.xml('<a b="c"></a>'))
6447db96d56Sopenharmony_ci
6457db96d56Sopenharmony_ci    def test_1463026_1_empty(self):
6467db96d56Sopenharmony_ci        result = self.ioclass()
6477db96d56Sopenharmony_ci        gen = XMLGenerator(result, short_empty_elements=True)
6487db96d56Sopenharmony_ci
6497db96d56Sopenharmony_ci        gen.startDocument()
6507db96d56Sopenharmony_ci        gen.startElementNS((None, 'a'), 'a', {(None, 'b'):'c'})
6517db96d56Sopenharmony_ci        gen.endElementNS((None, 'a'), 'a')
6527db96d56Sopenharmony_ci        gen.endDocument()
6537db96d56Sopenharmony_ci
6547db96d56Sopenharmony_ci        self.assertEqual(result.getvalue(), self.xml('<a b="c"/>'))
6557db96d56Sopenharmony_ci
6567db96d56Sopenharmony_ci    def test_1463026_2(self):
6577db96d56Sopenharmony_ci        result = self.ioclass()
6587db96d56Sopenharmony_ci        gen = XMLGenerator(result)
6597db96d56Sopenharmony_ci
6607db96d56Sopenharmony_ci        gen.startDocument()
6617db96d56Sopenharmony_ci        gen.startPrefixMapping(None, 'qux')
6627db96d56Sopenharmony_ci        gen.startElementNS(('qux', 'a'), 'a', {})
6637db96d56Sopenharmony_ci        gen.endElementNS(('qux', 'a'), 'a')
6647db96d56Sopenharmony_ci        gen.endPrefixMapping(None)
6657db96d56Sopenharmony_ci        gen.endDocument()
6667db96d56Sopenharmony_ci
6677db96d56Sopenharmony_ci        self.assertEqual(result.getvalue(), self.xml('<a xmlns="qux"></a>'))
6687db96d56Sopenharmony_ci
6697db96d56Sopenharmony_ci    def test_1463026_2_empty(self):
6707db96d56Sopenharmony_ci        result = self.ioclass()
6717db96d56Sopenharmony_ci        gen = XMLGenerator(result, short_empty_elements=True)
6727db96d56Sopenharmony_ci
6737db96d56Sopenharmony_ci        gen.startDocument()
6747db96d56Sopenharmony_ci        gen.startPrefixMapping(None, 'qux')
6757db96d56Sopenharmony_ci        gen.startElementNS(('qux', 'a'), 'a', {})
6767db96d56Sopenharmony_ci        gen.endElementNS(('qux', 'a'), 'a')
6777db96d56Sopenharmony_ci        gen.endPrefixMapping(None)
6787db96d56Sopenharmony_ci        gen.endDocument()
6797db96d56Sopenharmony_ci
6807db96d56Sopenharmony_ci        self.assertEqual(result.getvalue(), self.xml('<a xmlns="qux"/>'))
6817db96d56Sopenharmony_ci
6827db96d56Sopenharmony_ci    def test_1463026_3(self):
6837db96d56Sopenharmony_ci        result = self.ioclass()
6847db96d56Sopenharmony_ci        gen = XMLGenerator(result)
6857db96d56Sopenharmony_ci
6867db96d56Sopenharmony_ci        gen.startDocument()
6877db96d56Sopenharmony_ci        gen.startPrefixMapping('my', 'qux')
6887db96d56Sopenharmony_ci        gen.startElementNS(('qux', 'a'), 'a', {(None, 'b'):'c'})
6897db96d56Sopenharmony_ci        gen.endElementNS(('qux', 'a'), 'a')
6907db96d56Sopenharmony_ci        gen.endPrefixMapping('my')
6917db96d56Sopenharmony_ci        gen.endDocument()
6927db96d56Sopenharmony_ci
6937db96d56Sopenharmony_ci        self.assertEqual(result.getvalue(),
6947db96d56Sopenharmony_ci            self.xml('<my:a xmlns:my="qux" b="c"></my:a>'))
6957db96d56Sopenharmony_ci
6967db96d56Sopenharmony_ci    def test_1463026_3_empty(self):
6977db96d56Sopenharmony_ci        result = self.ioclass()
6987db96d56Sopenharmony_ci        gen = XMLGenerator(result, short_empty_elements=True)
6997db96d56Sopenharmony_ci
7007db96d56Sopenharmony_ci        gen.startDocument()
7017db96d56Sopenharmony_ci        gen.startPrefixMapping('my', 'qux')
7027db96d56Sopenharmony_ci        gen.startElementNS(('qux', 'a'), 'a', {(None, 'b'):'c'})
7037db96d56Sopenharmony_ci        gen.endElementNS(('qux', 'a'), 'a')
7047db96d56Sopenharmony_ci        gen.endPrefixMapping('my')
7057db96d56Sopenharmony_ci        gen.endDocument()
7067db96d56Sopenharmony_ci
7077db96d56Sopenharmony_ci        self.assertEqual(result.getvalue(),
7087db96d56Sopenharmony_ci            self.xml('<my:a xmlns:my="qux" b="c"/>'))
7097db96d56Sopenharmony_ci
7107db96d56Sopenharmony_ci    def test_5027_1(self):
7117db96d56Sopenharmony_ci        # The xml prefix (as in xml:lang below) is reserved and bound by
7127db96d56Sopenharmony_ci        # definition to http://www.w3.org/XML/1998/namespace.  XMLGenerator had
7137db96d56Sopenharmony_ci        # a bug whereby a KeyError is raised because this namespace is missing
7147db96d56Sopenharmony_ci        # from a dictionary.
7157db96d56Sopenharmony_ci        #
7167db96d56Sopenharmony_ci        # This test demonstrates the bug by parsing a document.
7177db96d56Sopenharmony_ci        test_xml = StringIO(
7187db96d56Sopenharmony_ci            '<?xml version="1.0"?>'
7197db96d56Sopenharmony_ci            '<a:g1 xmlns:a="http://example.com/ns">'
7207db96d56Sopenharmony_ci             '<a:g2 xml:lang="en">Hello</a:g2>'
7217db96d56Sopenharmony_ci            '</a:g1>')
7227db96d56Sopenharmony_ci
7237db96d56Sopenharmony_ci        parser = make_parser()
7247db96d56Sopenharmony_ci        parser.setFeature(feature_namespaces, True)
7257db96d56Sopenharmony_ci        result = self.ioclass()
7267db96d56Sopenharmony_ci        gen = XMLGenerator(result)
7277db96d56Sopenharmony_ci        parser.setContentHandler(gen)
7287db96d56Sopenharmony_ci        parser.parse(test_xml)
7297db96d56Sopenharmony_ci
7307db96d56Sopenharmony_ci        self.assertEqual(result.getvalue(),
7317db96d56Sopenharmony_ci                         self.xml(
7327db96d56Sopenharmony_ci                         '<a:g1 xmlns:a="http://example.com/ns">'
7337db96d56Sopenharmony_ci                          '<a:g2 xml:lang="en">Hello</a:g2>'
7347db96d56Sopenharmony_ci                         '</a:g1>'))
7357db96d56Sopenharmony_ci
7367db96d56Sopenharmony_ci    def test_5027_2(self):
7377db96d56Sopenharmony_ci        # The xml prefix (as in xml:lang below) is reserved and bound by
7387db96d56Sopenharmony_ci        # definition to http://www.w3.org/XML/1998/namespace.  XMLGenerator had
7397db96d56Sopenharmony_ci        # a bug whereby a KeyError is raised because this namespace is missing
7407db96d56Sopenharmony_ci        # from a dictionary.
7417db96d56Sopenharmony_ci        #
7427db96d56Sopenharmony_ci        # This test demonstrates the bug by direct manipulation of the
7437db96d56Sopenharmony_ci        # XMLGenerator.
7447db96d56Sopenharmony_ci        result = self.ioclass()
7457db96d56Sopenharmony_ci        gen = XMLGenerator(result)
7467db96d56Sopenharmony_ci
7477db96d56Sopenharmony_ci        gen.startDocument()
7487db96d56Sopenharmony_ci        gen.startPrefixMapping('a', 'http://example.com/ns')
7497db96d56Sopenharmony_ci        gen.startElementNS(('http://example.com/ns', 'g1'), 'g1', {})
7507db96d56Sopenharmony_ci        lang_attr = {('http://www.w3.org/XML/1998/namespace', 'lang'): 'en'}
7517db96d56Sopenharmony_ci        gen.startElementNS(('http://example.com/ns', 'g2'), 'g2', lang_attr)
7527db96d56Sopenharmony_ci        gen.characters('Hello')
7537db96d56Sopenharmony_ci        gen.endElementNS(('http://example.com/ns', 'g2'), 'g2')
7547db96d56Sopenharmony_ci        gen.endElementNS(('http://example.com/ns', 'g1'), 'g1')
7557db96d56Sopenharmony_ci        gen.endPrefixMapping('a')
7567db96d56Sopenharmony_ci        gen.endDocument()
7577db96d56Sopenharmony_ci
7587db96d56Sopenharmony_ci        self.assertEqual(result.getvalue(),
7597db96d56Sopenharmony_ci                         self.xml(
7607db96d56Sopenharmony_ci                         '<a:g1 xmlns:a="http://example.com/ns">'
7617db96d56Sopenharmony_ci                          '<a:g2 xml:lang="en">Hello</a:g2>'
7627db96d56Sopenharmony_ci                         '</a:g1>'))
7637db96d56Sopenharmony_ci
7647db96d56Sopenharmony_ci    def test_no_close_file(self):
7657db96d56Sopenharmony_ci        result = self.ioclass()
7667db96d56Sopenharmony_ci        def func(out):
7677db96d56Sopenharmony_ci            gen = XMLGenerator(out)
7687db96d56Sopenharmony_ci            gen.startDocument()
7697db96d56Sopenharmony_ci            gen.startElement("doc", {})
7707db96d56Sopenharmony_ci        func(result)
7717db96d56Sopenharmony_ci        self.assertFalse(result.closed)
7727db96d56Sopenharmony_ci
7737db96d56Sopenharmony_ci    def test_xmlgen_fragment(self):
7747db96d56Sopenharmony_ci        result = self.ioclass()
7757db96d56Sopenharmony_ci        gen = XMLGenerator(result)
7767db96d56Sopenharmony_ci
7777db96d56Sopenharmony_ci        # Don't call gen.startDocument()
7787db96d56Sopenharmony_ci        gen.startElement("foo", {"a": "1.0"})
7797db96d56Sopenharmony_ci        gen.characters("Hello")
7807db96d56Sopenharmony_ci        gen.endElement("foo")
7817db96d56Sopenharmony_ci        gen.startElement("bar", {"b": "2.0"})
7827db96d56Sopenharmony_ci        gen.endElement("bar")
7837db96d56Sopenharmony_ci        # Don't call gen.endDocument()
7847db96d56Sopenharmony_ci
7857db96d56Sopenharmony_ci        self.assertEqual(result.getvalue(),
7867db96d56Sopenharmony_ci            self.xml('<foo a="1.0">Hello</foo><bar b="2.0"></bar>')[len(self.xml('')):])
7877db96d56Sopenharmony_ci
7887db96d56Sopenharmony_ciclass StringXmlgenTest(XmlgenTest, unittest.TestCase):
7897db96d56Sopenharmony_ci    ioclass = StringIO
7907db96d56Sopenharmony_ci
7917db96d56Sopenharmony_ci    def xml(self, doc, encoding='iso-8859-1'):
7927db96d56Sopenharmony_ci        return '<?xml version="1.0" encoding="%s"?>\n%s' % (encoding, doc)
7937db96d56Sopenharmony_ci
7947db96d56Sopenharmony_ci    test_xmlgen_unencodable = None
7957db96d56Sopenharmony_ci
7967db96d56Sopenharmony_ciclass BytesXmlgenTest(XmlgenTest, unittest.TestCase):
7977db96d56Sopenharmony_ci    ioclass = BytesIO
7987db96d56Sopenharmony_ci
7997db96d56Sopenharmony_ci    def xml(self, doc, encoding='iso-8859-1'):
8007db96d56Sopenharmony_ci        return ('<?xml version="1.0" encoding="%s"?>\n%s' %
8017db96d56Sopenharmony_ci                (encoding, doc)).encode(encoding, 'xmlcharrefreplace')
8027db96d56Sopenharmony_ci
8037db96d56Sopenharmony_ciclass WriterXmlgenTest(BytesXmlgenTest):
8047db96d56Sopenharmony_ci    class ioclass(list):
8057db96d56Sopenharmony_ci        write = list.append
8067db96d56Sopenharmony_ci        closed = False
8077db96d56Sopenharmony_ci
8087db96d56Sopenharmony_ci        def seekable(self):
8097db96d56Sopenharmony_ci            return True
8107db96d56Sopenharmony_ci
8117db96d56Sopenharmony_ci        def tell(self):
8127db96d56Sopenharmony_ci            # return 0 at start and not 0 after start
8137db96d56Sopenharmony_ci            return len(self)
8147db96d56Sopenharmony_ci
8157db96d56Sopenharmony_ci        def getvalue(self):
8167db96d56Sopenharmony_ci            return b''.join(self)
8177db96d56Sopenharmony_ci
8187db96d56Sopenharmony_ciclass StreamWriterXmlgenTest(XmlgenTest, unittest.TestCase):
8197db96d56Sopenharmony_ci    def ioclass(self):
8207db96d56Sopenharmony_ci        raw = BytesIO()
8217db96d56Sopenharmony_ci        writer = codecs.getwriter('ascii')(raw, 'xmlcharrefreplace')
8227db96d56Sopenharmony_ci        writer.getvalue = raw.getvalue
8237db96d56Sopenharmony_ci        return writer
8247db96d56Sopenharmony_ci
8257db96d56Sopenharmony_ci    def xml(self, doc, encoding='iso-8859-1'):
8267db96d56Sopenharmony_ci        return ('<?xml version="1.0" encoding="%s"?>\n%s' %
8277db96d56Sopenharmony_ci                (encoding, doc)).encode('ascii', 'xmlcharrefreplace')
8287db96d56Sopenharmony_ci
8297db96d56Sopenharmony_ciclass StreamReaderWriterXmlgenTest(XmlgenTest, unittest.TestCase):
8307db96d56Sopenharmony_ci    fname = os_helper.TESTFN + '-codecs'
8317db96d56Sopenharmony_ci
8327db96d56Sopenharmony_ci    def ioclass(self):
8337db96d56Sopenharmony_ci        writer = codecs.open(self.fname, 'w', encoding='ascii',
8347db96d56Sopenharmony_ci                             errors='xmlcharrefreplace', buffering=0)
8357db96d56Sopenharmony_ci        def cleanup():
8367db96d56Sopenharmony_ci            writer.close()
8377db96d56Sopenharmony_ci            os_helper.unlink(self.fname)
8387db96d56Sopenharmony_ci        self.addCleanup(cleanup)
8397db96d56Sopenharmony_ci        def getvalue():
8407db96d56Sopenharmony_ci            # Windows will not let use reopen without first closing
8417db96d56Sopenharmony_ci            writer.close()
8427db96d56Sopenharmony_ci            with open(writer.name, 'rb') as f:
8437db96d56Sopenharmony_ci                return f.read()
8447db96d56Sopenharmony_ci        writer.getvalue = getvalue
8457db96d56Sopenharmony_ci        return writer
8467db96d56Sopenharmony_ci
8477db96d56Sopenharmony_ci    def xml(self, doc, encoding='iso-8859-1'):
8487db96d56Sopenharmony_ci        return ('<?xml version="1.0" encoding="%s"?>\n%s' %
8497db96d56Sopenharmony_ci                (encoding, doc)).encode('ascii', 'xmlcharrefreplace')
8507db96d56Sopenharmony_ci
8517db96d56Sopenharmony_cistart = b'<?xml version="1.0" encoding="iso-8859-1"?>\n'
8527db96d56Sopenharmony_ci
8537db96d56Sopenharmony_ci
8547db96d56Sopenharmony_ciclass XMLFilterBaseTest(unittest.TestCase):
8557db96d56Sopenharmony_ci    def test_filter_basic(self):
8567db96d56Sopenharmony_ci        result = BytesIO()
8577db96d56Sopenharmony_ci        gen = XMLGenerator(result)
8587db96d56Sopenharmony_ci        filter = XMLFilterBase()
8597db96d56Sopenharmony_ci        filter.setContentHandler(gen)
8607db96d56Sopenharmony_ci
8617db96d56Sopenharmony_ci        filter.startDocument()
8627db96d56Sopenharmony_ci        filter.startElement("doc", {})
8637db96d56Sopenharmony_ci        filter.characters("content")
8647db96d56Sopenharmony_ci        filter.ignorableWhitespace(" ")
8657db96d56Sopenharmony_ci        filter.endElement("doc")
8667db96d56Sopenharmony_ci        filter.endDocument()
8677db96d56Sopenharmony_ci
8687db96d56Sopenharmony_ci        self.assertEqual(result.getvalue(), start + b"<doc>content </doc>")
8697db96d56Sopenharmony_ci
8707db96d56Sopenharmony_ci# ===========================================================================
8717db96d56Sopenharmony_ci#
8727db96d56Sopenharmony_ci#   expatreader tests
8737db96d56Sopenharmony_ci#
8747db96d56Sopenharmony_ci# ===========================================================================
8757db96d56Sopenharmony_ci
8767db96d56Sopenharmony_ciwith open(TEST_XMLFILE_OUT, 'rb') as f:
8777db96d56Sopenharmony_ci    xml_test_out = f.read()
8787db96d56Sopenharmony_ci
8797db96d56Sopenharmony_ciclass ExpatReaderTest(XmlTestBase):
8807db96d56Sopenharmony_ci
8817db96d56Sopenharmony_ci    # ===== XMLReader support
8827db96d56Sopenharmony_ci
8837db96d56Sopenharmony_ci    def test_expat_binary_file(self):
8847db96d56Sopenharmony_ci        parser = create_parser()
8857db96d56Sopenharmony_ci        result = BytesIO()
8867db96d56Sopenharmony_ci        xmlgen = XMLGenerator(result)
8877db96d56Sopenharmony_ci
8887db96d56Sopenharmony_ci        parser.setContentHandler(xmlgen)
8897db96d56Sopenharmony_ci        with open(TEST_XMLFILE, 'rb') as f:
8907db96d56Sopenharmony_ci            parser.parse(f)
8917db96d56Sopenharmony_ci
8927db96d56Sopenharmony_ci        self.assertEqual(result.getvalue(), xml_test_out)
8937db96d56Sopenharmony_ci
8947db96d56Sopenharmony_ci    def test_expat_text_file(self):
8957db96d56Sopenharmony_ci        parser = create_parser()
8967db96d56Sopenharmony_ci        result = BytesIO()
8977db96d56Sopenharmony_ci        xmlgen = XMLGenerator(result)
8987db96d56Sopenharmony_ci
8997db96d56Sopenharmony_ci        parser.setContentHandler(xmlgen)
9007db96d56Sopenharmony_ci        with open(TEST_XMLFILE, 'rt', encoding='iso-8859-1') as f:
9017db96d56Sopenharmony_ci            parser.parse(f)
9027db96d56Sopenharmony_ci
9037db96d56Sopenharmony_ci        self.assertEqual(result.getvalue(), xml_test_out)
9047db96d56Sopenharmony_ci
9057db96d56Sopenharmony_ci    @requires_nonascii_filenames
9067db96d56Sopenharmony_ci    def test_expat_binary_file_nonascii(self):
9077db96d56Sopenharmony_ci        fname = os_helper.TESTFN_UNICODE
9087db96d56Sopenharmony_ci        shutil.copyfile(TEST_XMLFILE, fname)
9097db96d56Sopenharmony_ci        self.addCleanup(os_helper.unlink, fname)
9107db96d56Sopenharmony_ci
9117db96d56Sopenharmony_ci        parser = create_parser()
9127db96d56Sopenharmony_ci        result = BytesIO()
9137db96d56Sopenharmony_ci        xmlgen = XMLGenerator(result)
9147db96d56Sopenharmony_ci
9157db96d56Sopenharmony_ci        parser.setContentHandler(xmlgen)
9167db96d56Sopenharmony_ci        parser.parse(open(fname, 'rb'))
9177db96d56Sopenharmony_ci
9187db96d56Sopenharmony_ci        self.assertEqual(result.getvalue(), xml_test_out)
9197db96d56Sopenharmony_ci
9207db96d56Sopenharmony_ci    def test_expat_binary_file_bytes_name(self):
9217db96d56Sopenharmony_ci        fname = os.fsencode(TEST_XMLFILE)
9227db96d56Sopenharmony_ci        parser = create_parser()
9237db96d56Sopenharmony_ci        result = BytesIO()
9247db96d56Sopenharmony_ci        xmlgen = XMLGenerator(result)
9257db96d56Sopenharmony_ci
9267db96d56Sopenharmony_ci        parser.setContentHandler(xmlgen)
9277db96d56Sopenharmony_ci        with open(fname, 'rb') as f:
9287db96d56Sopenharmony_ci            parser.parse(f)
9297db96d56Sopenharmony_ci
9307db96d56Sopenharmony_ci        self.assertEqual(result.getvalue(), xml_test_out)
9317db96d56Sopenharmony_ci
9327db96d56Sopenharmony_ci    def test_expat_binary_file_int_name(self):
9337db96d56Sopenharmony_ci        parser = create_parser()
9347db96d56Sopenharmony_ci        result = BytesIO()
9357db96d56Sopenharmony_ci        xmlgen = XMLGenerator(result)
9367db96d56Sopenharmony_ci
9377db96d56Sopenharmony_ci        parser.setContentHandler(xmlgen)
9387db96d56Sopenharmony_ci        with open(TEST_XMLFILE, 'rb') as f:
9397db96d56Sopenharmony_ci            with open(f.fileno(), 'rb', closefd=False) as f2:
9407db96d56Sopenharmony_ci                parser.parse(f2)
9417db96d56Sopenharmony_ci
9427db96d56Sopenharmony_ci        self.assertEqual(result.getvalue(), xml_test_out)
9437db96d56Sopenharmony_ci
9447db96d56Sopenharmony_ci    # ===== DTDHandler support
9457db96d56Sopenharmony_ci
9467db96d56Sopenharmony_ci    class TestDTDHandler:
9477db96d56Sopenharmony_ci
9487db96d56Sopenharmony_ci        def __init__(self):
9497db96d56Sopenharmony_ci            self._notations = []
9507db96d56Sopenharmony_ci            self._entities  = []
9517db96d56Sopenharmony_ci
9527db96d56Sopenharmony_ci        def notationDecl(self, name, publicId, systemId):
9537db96d56Sopenharmony_ci            self._notations.append((name, publicId, systemId))
9547db96d56Sopenharmony_ci
9557db96d56Sopenharmony_ci        def unparsedEntityDecl(self, name, publicId, systemId, ndata):
9567db96d56Sopenharmony_ci            self._entities.append((name, publicId, systemId, ndata))
9577db96d56Sopenharmony_ci
9587db96d56Sopenharmony_ci
9597db96d56Sopenharmony_ci    class TestEntityRecorder:
9607db96d56Sopenharmony_ci        def __init__(self):
9617db96d56Sopenharmony_ci            self.entities = []
9627db96d56Sopenharmony_ci
9637db96d56Sopenharmony_ci        def resolveEntity(self, publicId, systemId):
9647db96d56Sopenharmony_ci            self.entities.append((publicId, systemId))
9657db96d56Sopenharmony_ci            source = InputSource()
9667db96d56Sopenharmony_ci            source.setPublicId(publicId)
9677db96d56Sopenharmony_ci            source.setSystemId(systemId)
9687db96d56Sopenharmony_ci            return source
9697db96d56Sopenharmony_ci
9707db96d56Sopenharmony_ci    def test_expat_dtdhandler(self):
9717db96d56Sopenharmony_ci        parser = create_parser()
9727db96d56Sopenharmony_ci        handler = self.TestDTDHandler()
9737db96d56Sopenharmony_ci        parser.setDTDHandler(handler)
9747db96d56Sopenharmony_ci
9757db96d56Sopenharmony_ci        parser.feed('<!DOCTYPE doc [\n')
9767db96d56Sopenharmony_ci        parser.feed('  <!ENTITY img SYSTEM "expat.gif" NDATA GIF>\n')
9777db96d56Sopenharmony_ci        parser.feed('  <!NOTATION GIF PUBLIC "-//CompuServe//NOTATION Graphics Interchange Format 89a//EN">\n')
9787db96d56Sopenharmony_ci        parser.feed(']>\n')
9797db96d56Sopenharmony_ci        parser.feed('<doc></doc>')
9807db96d56Sopenharmony_ci        parser.close()
9817db96d56Sopenharmony_ci
9827db96d56Sopenharmony_ci        self.assertEqual(handler._notations,
9837db96d56Sopenharmony_ci            [("GIF", "-//CompuServe//NOTATION Graphics Interchange Format 89a//EN", None)])
9847db96d56Sopenharmony_ci        self.assertEqual(handler._entities, [("img", None, "expat.gif", "GIF")])
9857db96d56Sopenharmony_ci
9867db96d56Sopenharmony_ci    def test_expat_external_dtd_enabled(self):
9877db96d56Sopenharmony_ci        # clear _opener global variable
9887db96d56Sopenharmony_ci        self.addCleanup(urllib.request.urlcleanup)
9897db96d56Sopenharmony_ci
9907db96d56Sopenharmony_ci        parser = create_parser()
9917db96d56Sopenharmony_ci        parser.setFeature(feature_external_ges, True)
9927db96d56Sopenharmony_ci        resolver = self.TestEntityRecorder()
9937db96d56Sopenharmony_ci        parser.setEntityResolver(resolver)
9947db96d56Sopenharmony_ci
9957db96d56Sopenharmony_ci        with self.assertRaises(URLError):
9967db96d56Sopenharmony_ci            parser.feed(
9977db96d56Sopenharmony_ci                '<!DOCTYPE external SYSTEM "unsupported://non-existing">\n'
9987db96d56Sopenharmony_ci            )
9997db96d56Sopenharmony_ci        self.assertEqual(
10007db96d56Sopenharmony_ci            resolver.entities, [(None, 'unsupported://non-existing')]
10017db96d56Sopenharmony_ci        )
10027db96d56Sopenharmony_ci
10037db96d56Sopenharmony_ci    def test_expat_external_dtd_default(self):
10047db96d56Sopenharmony_ci        parser = create_parser()
10057db96d56Sopenharmony_ci        resolver = self.TestEntityRecorder()
10067db96d56Sopenharmony_ci        parser.setEntityResolver(resolver)
10077db96d56Sopenharmony_ci
10087db96d56Sopenharmony_ci        parser.feed(
10097db96d56Sopenharmony_ci            '<!DOCTYPE external SYSTEM "unsupported://non-existing">\n'
10107db96d56Sopenharmony_ci        )
10117db96d56Sopenharmony_ci        parser.feed('<doc />')
10127db96d56Sopenharmony_ci        parser.close()
10137db96d56Sopenharmony_ci        self.assertEqual(resolver.entities, [])
10147db96d56Sopenharmony_ci
10157db96d56Sopenharmony_ci    # ===== EntityResolver support
10167db96d56Sopenharmony_ci
10177db96d56Sopenharmony_ci    class TestEntityResolver:
10187db96d56Sopenharmony_ci
10197db96d56Sopenharmony_ci        def resolveEntity(self, publicId, systemId):
10207db96d56Sopenharmony_ci            inpsrc = InputSource()
10217db96d56Sopenharmony_ci            inpsrc.setByteStream(BytesIO(b"<entity/>"))
10227db96d56Sopenharmony_ci            return inpsrc
10237db96d56Sopenharmony_ci
10247db96d56Sopenharmony_ci    def test_expat_entityresolver_enabled(self):
10257db96d56Sopenharmony_ci        parser = create_parser()
10267db96d56Sopenharmony_ci        parser.setFeature(feature_external_ges, True)
10277db96d56Sopenharmony_ci        parser.setEntityResolver(self.TestEntityResolver())
10287db96d56Sopenharmony_ci        result = BytesIO()
10297db96d56Sopenharmony_ci        parser.setContentHandler(XMLGenerator(result))
10307db96d56Sopenharmony_ci
10317db96d56Sopenharmony_ci        parser.feed('<!DOCTYPE doc [\n')
10327db96d56Sopenharmony_ci        parser.feed('  <!ENTITY test SYSTEM "whatever">\n')
10337db96d56Sopenharmony_ci        parser.feed(']>\n')
10347db96d56Sopenharmony_ci        parser.feed('<doc>&test;</doc>')
10357db96d56Sopenharmony_ci        parser.close()
10367db96d56Sopenharmony_ci
10377db96d56Sopenharmony_ci        self.assertEqual(result.getvalue(), start +
10387db96d56Sopenharmony_ci                         b"<doc><entity></entity></doc>")
10397db96d56Sopenharmony_ci
10407db96d56Sopenharmony_ci    def test_expat_entityresolver_default(self):
10417db96d56Sopenharmony_ci        parser = create_parser()
10427db96d56Sopenharmony_ci        self.assertEqual(parser.getFeature(feature_external_ges), False)
10437db96d56Sopenharmony_ci        parser.setEntityResolver(self.TestEntityResolver())
10447db96d56Sopenharmony_ci        result = BytesIO()
10457db96d56Sopenharmony_ci        parser.setContentHandler(XMLGenerator(result))
10467db96d56Sopenharmony_ci
10477db96d56Sopenharmony_ci        parser.feed('<!DOCTYPE doc [\n')
10487db96d56Sopenharmony_ci        parser.feed('  <!ENTITY test SYSTEM "whatever">\n')
10497db96d56Sopenharmony_ci        parser.feed(']>\n')
10507db96d56Sopenharmony_ci        parser.feed('<doc>&test;</doc>')
10517db96d56Sopenharmony_ci        parser.close()
10527db96d56Sopenharmony_ci
10537db96d56Sopenharmony_ci        self.assertEqual(result.getvalue(), start +
10547db96d56Sopenharmony_ci                         b"<doc></doc>")
10557db96d56Sopenharmony_ci
10567db96d56Sopenharmony_ci    # ===== Attributes support
10577db96d56Sopenharmony_ci
10587db96d56Sopenharmony_ci    class AttrGatherer(ContentHandler):
10597db96d56Sopenharmony_ci
10607db96d56Sopenharmony_ci        def startElement(self, name, attrs):
10617db96d56Sopenharmony_ci            self._attrs = attrs
10627db96d56Sopenharmony_ci
10637db96d56Sopenharmony_ci        def startElementNS(self, name, qname, attrs):
10647db96d56Sopenharmony_ci            self._attrs = attrs
10657db96d56Sopenharmony_ci
10667db96d56Sopenharmony_ci    def test_expat_attrs_empty(self):
10677db96d56Sopenharmony_ci        parser = create_parser()
10687db96d56Sopenharmony_ci        gather = self.AttrGatherer()
10697db96d56Sopenharmony_ci        parser.setContentHandler(gather)
10707db96d56Sopenharmony_ci
10717db96d56Sopenharmony_ci        parser.feed("<doc/>")
10727db96d56Sopenharmony_ci        parser.close()
10737db96d56Sopenharmony_ci
10747db96d56Sopenharmony_ci        self.verify_empty_attrs(gather._attrs)
10757db96d56Sopenharmony_ci
10767db96d56Sopenharmony_ci    def test_expat_attrs_wattr(self):
10777db96d56Sopenharmony_ci        parser = create_parser()
10787db96d56Sopenharmony_ci        gather = self.AttrGatherer()
10797db96d56Sopenharmony_ci        parser.setContentHandler(gather)
10807db96d56Sopenharmony_ci
10817db96d56Sopenharmony_ci        parser.feed("<doc attr='val'/>")
10827db96d56Sopenharmony_ci        parser.close()
10837db96d56Sopenharmony_ci
10847db96d56Sopenharmony_ci        self.verify_attrs_wattr(gather._attrs)
10857db96d56Sopenharmony_ci
10867db96d56Sopenharmony_ci    def test_expat_nsattrs_empty(self):
10877db96d56Sopenharmony_ci        parser = create_parser(1)
10887db96d56Sopenharmony_ci        gather = self.AttrGatherer()
10897db96d56Sopenharmony_ci        parser.setContentHandler(gather)
10907db96d56Sopenharmony_ci
10917db96d56Sopenharmony_ci        parser.feed("<doc/>")
10927db96d56Sopenharmony_ci        parser.close()
10937db96d56Sopenharmony_ci
10947db96d56Sopenharmony_ci        self.verify_empty_nsattrs(gather._attrs)
10957db96d56Sopenharmony_ci
10967db96d56Sopenharmony_ci    def test_expat_nsattrs_wattr(self):
10977db96d56Sopenharmony_ci        parser = create_parser(1)
10987db96d56Sopenharmony_ci        gather = self.AttrGatherer()
10997db96d56Sopenharmony_ci        parser.setContentHandler(gather)
11007db96d56Sopenharmony_ci
11017db96d56Sopenharmony_ci        parser.feed("<doc xmlns:ns='%s' ns:attr='val'/>" % ns_uri)
11027db96d56Sopenharmony_ci        parser.close()
11037db96d56Sopenharmony_ci
11047db96d56Sopenharmony_ci        attrs = gather._attrs
11057db96d56Sopenharmony_ci
11067db96d56Sopenharmony_ci        self.assertEqual(attrs.getLength(), 1)
11077db96d56Sopenharmony_ci        self.assertEqual(attrs.getNames(), [(ns_uri, "attr")])
11087db96d56Sopenharmony_ci        self.assertTrue((attrs.getQNames() == [] or
11097db96d56Sopenharmony_ci                         attrs.getQNames() == ["ns:attr"]))
11107db96d56Sopenharmony_ci        self.assertEqual(len(attrs), 1)
11117db96d56Sopenharmony_ci        self.assertIn((ns_uri, "attr"), attrs)
11127db96d56Sopenharmony_ci        self.assertEqual(attrs.get((ns_uri, "attr")), "val")
11137db96d56Sopenharmony_ci        self.assertEqual(attrs.get((ns_uri, "attr"), 25), "val")
11147db96d56Sopenharmony_ci        self.assertEqual(list(attrs.items()), [((ns_uri, "attr"), "val")])
11157db96d56Sopenharmony_ci        self.assertEqual(list(attrs.values()), ["val"])
11167db96d56Sopenharmony_ci        self.assertEqual(attrs.getValue((ns_uri, "attr")), "val")
11177db96d56Sopenharmony_ci        self.assertEqual(attrs[(ns_uri, "attr")], "val")
11187db96d56Sopenharmony_ci
11197db96d56Sopenharmony_ci    # ===== InputSource support
11207db96d56Sopenharmony_ci
11217db96d56Sopenharmony_ci    def test_expat_inpsource_filename(self):
11227db96d56Sopenharmony_ci        parser = create_parser()
11237db96d56Sopenharmony_ci        result = BytesIO()
11247db96d56Sopenharmony_ci        xmlgen = XMLGenerator(result)
11257db96d56Sopenharmony_ci
11267db96d56Sopenharmony_ci        parser.setContentHandler(xmlgen)
11277db96d56Sopenharmony_ci        parser.parse(TEST_XMLFILE)
11287db96d56Sopenharmony_ci
11297db96d56Sopenharmony_ci        self.assertEqual(result.getvalue(), xml_test_out)
11307db96d56Sopenharmony_ci
11317db96d56Sopenharmony_ci    def test_expat_inpsource_sysid(self):
11327db96d56Sopenharmony_ci        parser = create_parser()
11337db96d56Sopenharmony_ci        result = BytesIO()
11347db96d56Sopenharmony_ci        xmlgen = XMLGenerator(result)
11357db96d56Sopenharmony_ci
11367db96d56Sopenharmony_ci        parser.setContentHandler(xmlgen)
11377db96d56Sopenharmony_ci        parser.parse(InputSource(TEST_XMLFILE))
11387db96d56Sopenharmony_ci
11397db96d56Sopenharmony_ci        self.assertEqual(result.getvalue(), xml_test_out)
11407db96d56Sopenharmony_ci
11417db96d56Sopenharmony_ci    @requires_nonascii_filenames
11427db96d56Sopenharmony_ci    def test_expat_inpsource_sysid_nonascii(self):
11437db96d56Sopenharmony_ci        fname = os_helper.TESTFN_UNICODE
11447db96d56Sopenharmony_ci        shutil.copyfile(TEST_XMLFILE, fname)
11457db96d56Sopenharmony_ci        self.addCleanup(os_helper.unlink, fname)
11467db96d56Sopenharmony_ci
11477db96d56Sopenharmony_ci        parser = create_parser()
11487db96d56Sopenharmony_ci        result = BytesIO()
11497db96d56Sopenharmony_ci        xmlgen = XMLGenerator(result)
11507db96d56Sopenharmony_ci
11517db96d56Sopenharmony_ci        parser.setContentHandler(xmlgen)
11527db96d56Sopenharmony_ci        parser.parse(InputSource(fname))
11537db96d56Sopenharmony_ci
11547db96d56Sopenharmony_ci        self.assertEqual(result.getvalue(), xml_test_out)
11557db96d56Sopenharmony_ci
11567db96d56Sopenharmony_ci    def test_expat_inpsource_byte_stream(self):
11577db96d56Sopenharmony_ci        parser = create_parser()
11587db96d56Sopenharmony_ci        result = BytesIO()
11597db96d56Sopenharmony_ci        xmlgen = XMLGenerator(result)
11607db96d56Sopenharmony_ci
11617db96d56Sopenharmony_ci        parser.setContentHandler(xmlgen)
11627db96d56Sopenharmony_ci        inpsrc = InputSource()
11637db96d56Sopenharmony_ci        with open(TEST_XMLFILE, 'rb') as f:
11647db96d56Sopenharmony_ci            inpsrc.setByteStream(f)
11657db96d56Sopenharmony_ci            parser.parse(inpsrc)
11667db96d56Sopenharmony_ci
11677db96d56Sopenharmony_ci        self.assertEqual(result.getvalue(), xml_test_out)
11687db96d56Sopenharmony_ci
11697db96d56Sopenharmony_ci    def test_expat_inpsource_character_stream(self):
11707db96d56Sopenharmony_ci        parser = create_parser()
11717db96d56Sopenharmony_ci        result = BytesIO()
11727db96d56Sopenharmony_ci        xmlgen = XMLGenerator(result)
11737db96d56Sopenharmony_ci
11747db96d56Sopenharmony_ci        parser.setContentHandler(xmlgen)
11757db96d56Sopenharmony_ci        inpsrc = InputSource()
11767db96d56Sopenharmony_ci        with open(TEST_XMLFILE, 'rt', encoding='iso-8859-1') as f:
11777db96d56Sopenharmony_ci            inpsrc.setCharacterStream(f)
11787db96d56Sopenharmony_ci            parser.parse(inpsrc)
11797db96d56Sopenharmony_ci
11807db96d56Sopenharmony_ci        self.assertEqual(result.getvalue(), xml_test_out)
11817db96d56Sopenharmony_ci
11827db96d56Sopenharmony_ci    # ===== IncrementalParser support
11837db96d56Sopenharmony_ci
11847db96d56Sopenharmony_ci    def test_expat_incremental(self):
11857db96d56Sopenharmony_ci        result = BytesIO()
11867db96d56Sopenharmony_ci        xmlgen = XMLGenerator(result)
11877db96d56Sopenharmony_ci        parser = create_parser()
11887db96d56Sopenharmony_ci        parser.setContentHandler(xmlgen)
11897db96d56Sopenharmony_ci
11907db96d56Sopenharmony_ci        parser.feed("<doc>")
11917db96d56Sopenharmony_ci        parser.feed("</doc>")
11927db96d56Sopenharmony_ci        parser.close()
11937db96d56Sopenharmony_ci
11947db96d56Sopenharmony_ci        self.assertEqual(result.getvalue(), start + b"<doc></doc>")
11957db96d56Sopenharmony_ci
11967db96d56Sopenharmony_ci    def test_expat_incremental_reset(self):
11977db96d56Sopenharmony_ci        result = BytesIO()
11987db96d56Sopenharmony_ci        xmlgen = XMLGenerator(result)
11997db96d56Sopenharmony_ci        parser = create_parser()
12007db96d56Sopenharmony_ci        parser.setContentHandler(xmlgen)
12017db96d56Sopenharmony_ci
12027db96d56Sopenharmony_ci        parser.feed("<doc>")
12037db96d56Sopenharmony_ci        parser.feed("text")
12047db96d56Sopenharmony_ci
12057db96d56Sopenharmony_ci        result = BytesIO()
12067db96d56Sopenharmony_ci        xmlgen = XMLGenerator(result)
12077db96d56Sopenharmony_ci        parser.setContentHandler(xmlgen)
12087db96d56Sopenharmony_ci        parser.reset()
12097db96d56Sopenharmony_ci
12107db96d56Sopenharmony_ci        parser.feed("<doc>")
12117db96d56Sopenharmony_ci        parser.feed("text")
12127db96d56Sopenharmony_ci        parser.feed("</doc>")
12137db96d56Sopenharmony_ci        parser.close()
12147db96d56Sopenharmony_ci
12157db96d56Sopenharmony_ci        self.assertEqual(result.getvalue(), start + b"<doc>text</doc>")
12167db96d56Sopenharmony_ci
12177db96d56Sopenharmony_ci    # ===== Locator support
12187db96d56Sopenharmony_ci
12197db96d56Sopenharmony_ci    def test_expat_locator_noinfo(self):
12207db96d56Sopenharmony_ci        result = BytesIO()
12217db96d56Sopenharmony_ci        xmlgen = XMLGenerator(result)
12227db96d56Sopenharmony_ci        parser = create_parser()
12237db96d56Sopenharmony_ci        parser.setContentHandler(xmlgen)
12247db96d56Sopenharmony_ci
12257db96d56Sopenharmony_ci        parser.feed("<doc>")
12267db96d56Sopenharmony_ci        parser.feed("</doc>")
12277db96d56Sopenharmony_ci        parser.close()
12287db96d56Sopenharmony_ci
12297db96d56Sopenharmony_ci        self.assertEqual(parser.getSystemId(), None)
12307db96d56Sopenharmony_ci        self.assertEqual(parser.getPublicId(), None)
12317db96d56Sopenharmony_ci        self.assertEqual(parser.getLineNumber(), 1)
12327db96d56Sopenharmony_ci
12337db96d56Sopenharmony_ci    def test_expat_locator_withinfo(self):
12347db96d56Sopenharmony_ci        result = BytesIO()
12357db96d56Sopenharmony_ci        xmlgen = XMLGenerator(result)
12367db96d56Sopenharmony_ci        parser = create_parser()
12377db96d56Sopenharmony_ci        parser.setContentHandler(xmlgen)
12387db96d56Sopenharmony_ci        parser.parse(TEST_XMLFILE)
12397db96d56Sopenharmony_ci
12407db96d56Sopenharmony_ci        self.assertEqual(parser.getSystemId(), TEST_XMLFILE)
12417db96d56Sopenharmony_ci        self.assertEqual(parser.getPublicId(), None)
12427db96d56Sopenharmony_ci
12437db96d56Sopenharmony_ci    @requires_nonascii_filenames
12447db96d56Sopenharmony_ci    def test_expat_locator_withinfo_nonascii(self):
12457db96d56Sopenharmony_ci        fname = os_helper.TESTFN_UNICODE
12467db96d56Sopenharmony_ci        shutil.copyfile(TEST_XMLFILE, fname)
12477db96d56Sopenharmony_ci        self.addCleanup(os_helper.unlink, fname)
12487db96d56Sopenharmony_ci
12497db96d56Sopenharmony_ci        result = BytesIO()
12507db96d56Sopenharmony_ci        xmlgen = XMLGenerator(result)
12517db96d56Sopenharmony_ci        parser = create_parser()
12527db96d56Sopenharmony_ci        parser.setContentHandler(xmlgen)
12537db96d56Sopenharmony_ci        parser.parse(fname)
12547db96d56Sopenharmony_ci
12557db96d56Sopenharmony_ci        self.assertEqual(parser.getSystemId(), fname)
12567db96d56Sopenharmony_ci        self.assertEqual(parser.getPublicId(), None)
12577db96d56Sopenharmony_ci
12587db96d56Sopenharmony_ci
12597db96d56Sopenharmony_ci# ===========================================================================
12607db96d56Sopenharmony_ci#
12617db96d56Sopenharmony_ci#   error reporting
12627db96d56Sopenharmony_ci#
12637db96d56Sopenharmony_ci# ===========================================================================
12647db96d56Sopenharmony_ci
12657db96d56Sopenharmony_ciclass ErrorReportingTest(unittest.TestCase):
12667db96d56Sopenharmony_ci    def test_expat_inpsource_location(self):
12677db96d56Sopenharmony_ci        parser = create_parser()
12687db96d56Sopenharmony_ci        parser.setContentHandler(ContentHandler()) # do nothing
12697db96d56Sopenharmony_ci        source = InputSource()
12707db96d56Sopenharmony_ci        source.setByteStream(BytesIO(b"<foo bar foobar>"))   #ill-formed
12717db96d56Sopenharmony_ci        name = "a file name"
12727db96d56Sopenharmony_ci        source.setSystemId(name)
12737db96d56Sopenharmony_ci        try:
12747db96d56Sopenharmony_ci            parser.parse(source)
12757db96d56Sopenharmony_ci            self.fail()
12767db96d56Sopenharmony_ci        except SAXException as e:
12777db96d56Sopenharmony_ci            self.assertEqual(e.getSystemId(), name)
12787db96d56Sopenharmony_ci
12797db96d56Sopenharmony_ci    def test_expat_incomplete(self):
12807db96d56Sopenharmony_ci        parser = create_parser()
12817db96d56Sopenharmony_ci        parser.setContentHandler(ContentHandler()) # do nothing
12827db96d56Sopenharmony_ci        self.assertRaises(SAXParseException, parser.parse, StringIO("<foo>"))
12837db96d56Sopenharmony_ci        self.assertEqual(parser.getColumnNumber(), 5)
12847db96d56Sopenharmony_ci        self.assertEqual(parser.getLineNumber(), 1)
12857db96d56Sopenharmony_ci
12867db96d56Sopenharmony_ci    def test_sax_parse_exception_str(self):
12877db96d56Sopenharmony_ci        # pass various values from a locator to the SAXParseException to
12887db96d56Sopenharmony_ci        # make sure that the __str__() doesn't fall apart when None is
12897db96d56Sopenharmony_ci        # passed instead of an integer line and column number
12907db96d56Sopenharmony_ci        #
12917db96d56Sopenharmony_ci        # use "normal" values for the locator:
12927db96d56Sopenharmony_ci        str(SAXParseException("message", None,
12937db96d56Sopenharmony_ci                              self.DummyLocator(1, 1)))
12947db96d56Sopenharmony_ci        # use None for the line number:
12957db96d56Sopenharmony_ci        str(SAXParseException("message", None,
12967db96d56Sopenharmony_ci                              self.DummyLocator(None, 1)))
12977db96d56Sopenharmony_ci        # use None for the column number:
12987db96d56Sopenharmony_ci        str(SAXParseException("message", None,
12997db96d56Sopenharmony_ci                              self.DummyLocator(1, None)))
13007db96d56Sopenharmony_ci        # use None for both:
13017db96d56Sopenharmony_ci        str(SAXParseException("message", None,
13027db96d56Sopenharmony_ci                              self.DummyLocator(None, None)))
13037db96d56Sopenharmony_ci
13047db96d56Sopenharmony_ci    class DummyLocator:
13057db96d56Sopenharmony_ci        def __init__(self, lineno, colno):
13067db96d56Sopenharmony_ci            self._lineno = lineno
13077db96d56Sopenharmony_ci            self._colno = colno
13087db96d56Sopenharmony_ci
13097db96d56Sopenharmony_ci        def getPublicId(self):
13107db96d56Sopenharmony_ci            return "pubid"
13117db96d56Sopenharmony_ci
13127db96d56Sopenharmony_ci        def getSystemId(self):
13137db96d56Sopenharmony_ci            return "sysid"
13147db96d56Sopenharmony_ci
13157db96d56Sopenharmony_ci        def getLineNumber(self):
13167db96d56Sopenharmony_ci            return self._lineno
13177db96d56Sopenharmony_ci
13187db96d56Sopenharmony_ci        def getColumnNumber(self):
13197db96d56Sopenharmony_ci            return self._colno
13207db96d56Sopenharmony_ci
13217db96d56Sopenharmony_ci# ===========================================================================
13227db96d56Sopenharmony_ci#
13237db96d56Sopenharmony_ci#   xmlreader tests
13247db96d56Sopenharmony_ci#
13257db96d56Sopenharmony_ci# ===========================================================================
13267db96d56Sopenharmony_ci
13277db96d56Sopenharmony_ciclass XmlReaderTest(XmlTestBase):
13287db96d56Sopenharmony_ci
13297db96d56Sopenharmony_ci    # ===== AttributesImpl
13307db96d56Sopenharmony_ci    def test_attrs_empty(self):
13317db96d56Sopenharmony_ci        self.verify_empty_attrs(AttributesImpl({}))
13327db96d56Sopenharmony_ci
13337db96d56Sopenharmony_ci    def test_attrs_wattr(self):
13347db96d56Sopenharmony_ci        self.verify_attrs_wattr(AttributesImpl({"attr" : "val"}))
13357db96d56Sopenharmony_ci
13367db96d56Sopenharmony_ci    def test_nsattrs_empty(self):
13377db96d56Sopenharmony_ci        self.verify_empty_nsattrs(AttributesNSImpl({}, {}))
13387db96d56Sopenharmony_ci
13397db96d56Sopenharmony_ci    def test_nsattrs_wattr(self):
13407db96d56Sopenharmony_ci        attrs = AttributesNSImpl({(ns_uri, "attr") : "val"},
13417db96d56Sopenharmony_ci                                 {(ns_uri, "attr") : "ns:attr"})
13427db96d56Sopenharmony_ci
13437db96d56Sopenharmony_ci        self.assertEqual(attrs.getLength(), 1)
13447db96d56Sopenharmony_ci        self.assertEqual(attrs.getNames(), [(ns_uri, "attr")])
13457db96d56Sopenharmony_ci        self.assertEqual(attrs.getQNames(), ["ns:attr"])
13467db96d56Sopenharmony_ci        self.assertEqual(len(attrs), 1)
13477db96d56Sopenharmony_ci        self.assertIn((ns_uri, "attr"), attrs)
13487db96d56Sopenharmony_ci        self.assertEqual(list(attrs.keys()), [(ns_uri, "attr")])
13497db96d56Sopenharmony_ci        self.assertEqual(attrs.get((ns_uri, "attr")), "val")
13507db96d56Sopenharmony_ci        self.assertEqual(attrs.get((ns_uri, "attr"), 25), "val")
13517db96d56Sopenharmony_ci        self.assertEqual(list(attrs.items()), [((ns_uri, "attr"), "val")])
13527db96d56Sopenharmony_ci        self.assertEqual(list(attrs.values()), ["val"])
13537db96d56Sopenharmony_ci        self.assertEqual(attrs.getValue((ns_uri, "attr")), "val")
13547db96d56Sopenharmony_ci        self.assertEqual(attrs.getValueByQName("ns:attr"), "val")
13557db96d56Sopenharmony_ci        self.assertEqual(attrs.getNameByQName("ns:attr"), (ns_uri, "attr"))
13567db96d56Sopenharmony_ci        self.assertEqual(attrs[(ns_uri, "attr")], "val")
13577db96d56Sopenharmony_ci        self.assertEqual(attrs.getQNameByName((ns_uri, "attr")), "ns:attr")
13587db96d56Sopenharmony_ci
13597db96d56Sopenharmony_ci
13607db96d56Sopenharmony_ciclass LexicalHandlerTest(unittest.TestCase):
13617db96d56Sopenharmony_ci    def setUp(self):
13627db96d56Sopenharmony_ci        self.parser = None
13637db96d56Sopenharmony_ci
13647db96d56Sopenharmony_ci        self.specified_version = '1.0'
13657db96d56Sopenharmony_ci        self.specified_encoding = 'UTF-8'
13667db96d56Sopenharmony_ci        self.specified_doctype = 'wish'
13677db96d56Sopenharmony_ci        self.specified_entity_names = ('nbsp', 'source', 'target')
13687db96d56Sopenharmony_ci        self.specified_comment = ('Comment in a DTD',
13697db96d56Sopenharmony_ci                                  'Really! You think so?')
13707db96d56Sopenharmony_ci        self.test_data = StringIO()
13717db96d56Sopenharmony_ci        self.test_data.write('<?xml version="{}" encoding="{}"?>\n'.
13727db96d56Sopenharmony_ci                             format(self.specified_version,
13737db96d56Sopenharmony_ci                                    self.specified_encoding))
13747db96d56Sopenharmony_ci        self.test_data.write('<!DOCTYPE {} [\n'.
13757db96d56Sopenharmony_ci                             format(self.specified_doctype))
13767db96d56Sopenharmony_ci        self.test_data.write('<!-- {} -->\n'.
13777db96d56Sopenharmony_ci                             format(self.specified_comment[0]))
13787db96d56Sopenharmony_ci        self.test_data.write('<!ELEMENT {} (to,from,heading,body,footer)>\n'.
13797db96d56Sopenharmony_ci                             format(self.specified_doctype))
13807db96d56Sopenharmony_ci        self.test_data.write('<!ELEMENT to (#PCDATA)>\n')
13817db96d56Sopenharmony_ci        self.test_data.write('<!ELEMENT from (#PCDATA)>\n')
13827db96d56Sopenharmony_ci        self.test_data.write('<!ELEMENT heading (#PCDATA)>\n')
13837db96d56Sopenharmony_ci        self.test_data.write('<!ELEMENT body (#PCDATA)>\n')
13847db96d56Sopenharmony_ci        self.test_data.write('<!ELEMENT footer (#PCDATA)>\n')
13857db96d56Sopenharmony_ci        self.test_data.write('<!ENTITY {} "&#xA0;">\n'.
13867db96d56Sopenharmony_ci                             format(self.specified_entity_names[0]))
13877db96d56Sopenharmony_ci        self.test_data.write('<!ENTITY {} "Written by: Alexander.">\n'.
13887db96d56Sopenharmony_ci                             format(self.specified_entity_names[1]))
13897db96d56Sopenharmony_ci        self.test_data.write('<!ENTITY {} "Hope it gets to: Aristotle.">\n'.
13907db96d56Sopenharmony_ci                             format(self.specified_entity_names[2]))
13917db96d56Sopenharmony_ci        self.test_data.write(']>\n')
13927db96d56Sopenharmony_ci        self.test_data.write('<{}>'.format(self.specified_doctype))
13937db96d56Sopenharmony_ci        self.test_data.write('<to>Aristotle</to>\n')
13947db96d56Sopenharmony_ci        self.test_data.write('<from>Alexander</from>\n')
13957db96d56Sopenharmony_ci        self.test_data.write('<heading>Supplication</heading>\n')
13967db96d56Sopenharmony_ci        self.test_data.write('<body>Teach me patience!</body>\n')
13977db96d56Sopenharmony_ci        self.test_data.write('<footer>&{};&{};&{};</footer>\n'.
13987db96d56Sopenharmony_ci                             format(self.specified_entity_names[1],
13997db96d56Sopenharmony_ci                                    self.specified_entity_names[0],
14007db96d56Sopenharmony_ci                                    self.specified_entity_names[2]))
14017db96d56Sopenharmony_ci        self.test_data.write('<!-- {} -->\n'.format(self.specified_comment[1]))
14027db96d56Sopenharmony_ci        self.test_data.write('</{}>\n'.format(self.specified_doctype))
14037db96d56Sopenharmony_ci        self.test_data.seek(0)
14047db96d56Sopenharmony_ci
14057db96d56Sopenharmony_ci        # Data received from handlers - to be validated
14067db96d56Sopenharmony_ci        self.version = None
14077db96d56Sopenharmony_ci        self.encoding = None
14087db96d56Sopenharmony_ci        self.standalone = None
14097db96d56Sopenharmony_ci        self.doctype = None
14107db96d56Sopenharmony_ci        self.publicID = None
14117db96d56Sopenharmony_ci        self.systemID = None
14127db96d56Sopenharmony_ci        self.end_of_dtd = False
14137db96d56Sopenharmony_ci        self.comments = []
14147db96d56Sopenharmony_ci
14157db96d56Sopenharmony_ci    def test_handlers(self):
14167db96d56Sopenharmony_ci        class TestLexicalHandler(LexicalHandler):
14177db96d56Sopenharmony_ci            def __init__(self, test_harness, *args, **kwargs):
14187db96d56Sopenharmony_ci                super().__init__(*args, **kwargs)
14197db96d56Sopenharmony_ci                self.test_harness = test_harness
14207db96d56Sopenharmony_ci
14217db96d56Sopenharmony_ci            def startDTD(self, doctype, publicID, systemID):
14227db96d56Sopenharmony_ci                self.test_harness.doctype = doctype
14237db96d56Sopenharmony_ci                self.test_harness.publicID = publicID
14247db96d56Sopenharmony_ci                self.test_harness.systemID = systemID
14257db96d56Sopenharmony_ci
14267db96d56Sopenharmony_ci            def endDTD(self):
14277db96d56Sopenharmony_ci                self.test_harness.end_of_dtd = True
14287db96d56Sopenharmony_ci
14297db96d56Sopenharmony_ci            def comment(self, text):
14307db96d56Sopenharmony_ci                self.test_harness.comments.append(text)
14317db96d56Sopenharmony_ci
14327db96d56Sopenharmony_ci        self.parser = create_parser()
14337db96d56Sopenharmony_ci        self.parser.setContentHandler(ContentHandler())
14347db96d56Sopenharmony_ci        self.parser.setProperty(
14357db96d56Sopenharmony_ci            'http://xml.org/sax/properties/lexical-handler',
14367db96d56Sopenharmony_ci            TestLexicalHandler(self))
14377db96d56Sopenharmony_ci        source = InputSource()
14387db96d56Sopenharmony_ci        source.setCharacterStream(self.test_data)
14397db96d56Sopenharmony_ci        self.parser.parse(source)
14407db96d56Sopenharmony_ci        self.assertEqual(self.doctype, self.specified_doctype)
14417db96d56Sopenharmony_ci        self.assertIsNone(self.publicID)
14427db96d56Sopenharmony_ci        self.assertIsNone(self.systemID)
14437db96d56Sopenharmony_ci        self.assertTrue(self.end_of_dtd)
14447db96d56Sopenharmony_ci        self.assertEqual(len(self.comments),
14457db96d56Sopenharmony_ci                         len(self.specified_comment))
14467db96d56Sopenharmony_ci        self.assertEqual(f' {self.specified_comment[0]} ', self.comments[0])
14477db96d56Sopenharmony_ci
14487db96d56Sopenharmony_ci
14497db96d56Sopenharmony_ciclass CDATAHandlerTest(unittest.TestCase):
14507db96d56Sopenharmony_ci    def setUp(self):
14517db96d56Sopenharmony_ci        self.parser = None
14527db96d56Sopenharmony_ci        self.specified_chars = []
14537db96d56Sopenharmony_ci        self.specified_chars.append(('Parseable character data', False))
14547db96d56Sopenharmony_ci        self.specified_chars.append(('<> &% - assorted other XML junk.', True))
14557db96d56Sopenharmony_ci        self.char_index = 0  # Used to index specified results within handlers
14567db96d56Sopenharmony_ci        self.test_data = StringIO()
14577db96d56Sopenharmony_ci        self.test_data.write('<root_doc>\n')
14587db96d56Sopenharmony_ci        self.test_data.write('<some_pcdata>\n')
14597db96d56Sopenharmony_ci        self.test_data.write(f'{self.specified_chars[0][0]}\n')
14607db96d56Sopenharmony_ci        self.test_data.write('</some_pcdata>\n')
14617db96d56Sopenharmony_ci        self.test_data.write('<some_cdata>\n')
14627db96d56Sopenharmony_ci        self.test_data.write(f'<![CDATA[{self.specified_chars[1][0]}]]>\n')
14637db96d56Sopenharmony_ci        self.test_data.write('</some_cdata>\n')
14647db96d56Sopenharmony_ci        self.test_data.write('</root_doc>\n')
14657db96d56Sopenharmony_ci        self.test_data.seek(0)
14667db96d56Sopenharmony_ci
14677db96d56Sopenharmony_ci        # Data received from handlers - to be validated
14687db96d56Sopenharmony_ci        self.chardata = []
14697db96d56Sopenharmony_ci        self.in_cdata = False
14707db96d56Sopenharmony_ci
14717db96d56Sopenharmony_ci    def test_handlers(self):
14727db96d56Sopenharmony_ci        class TestLexicalHandler(LexicalHandler):
14737db96d56Sopenharmony_ci            def __init__(self, test_harness, *args, **kwargs):
14747db96d56Sopenharmony_ci                super().__init__(*args, **kwargs)
14757db96d56Sopenharmony_ci                self.test_harness = test_harness
14767db96d56Sopenharmony_ci
14777db96d56Sopenharmony_ci            def startCDATA(self):
14787db96d56Sopenharmony_ci                self.test_harness.in_cdata = True
14797db96d56Sopenharmony_ci
14807db96d56Sopenharmony_ci            def endCDATA(self):
14817db96d56Sopenharmony_ci                self.test_harness.in_cdata = False
14827db96d56Sopenharmony_ci
14837db96d56Sopenharmony_ci        class TestCharHandler(ContentHandler):
14847db96d56Sopenharmony_ci            def __init__(self, test_harness, *args, **kwargs):
14857db96d56Sopenharmony_ci                super().__init__(*args, **kwargs)
14867db96d56Sopenharmony_ci                self.test_harness = test_harness
14877db96d56Sopenharmony_ci
14887db96d56Sopenharmony_ci            def characters(self, content):
14897db96d56Sopenharmony_ci                if content != '\n':
14907db96d56Sopenharmony_ci                    h = self.test_harness
14917db96d56Sopenharmony_ci                    t = h.specified_chars[h.char_index]
14927db96d56Sopenharmony_ci                    h.assertEqual(t[0], content)
14937db96d56Sopenharmony_ci                    h.assertEqual(t[1], h.in_cdata)
14947db96d56Sopenharmony_ci                    h.char_index += 1
14957db96d56Sopenharmony_ci
14967db96d56Sopenharmony_ci        self.parser = create_parser()
14977db96d56Sopenharmony_ci        self.parser.setContentHandler(TestCharHandler(self))
14987db96d56Sopenharmony_ci        self.parser.setProperty(
14997db96d56Sopenharmony_ci            'http://xml.org/sax/properties/lexical-handler',
15007db96d56Sopenharmony_ci            TestLexicalHandler(self))
15017db96d56Sopenharmony_ci        source = InputSource()
15027db96d56Sopenharmony_ci        source.setCharacterStream(self.test_data)
15037db96d56Sopenharmony_ci        self.parser.parse(source)
15047db96d56Sopenharmony_ci
15057db96d56Sopenharmony_ci        self.assertFalse(self.in_cdata)
15067db96d56Sopenharmony_ci        self.assertEqual(self.char_index, 2)
15077db96d56Sopenharmony_ci
15087db96d56Sopenharmony_ci
15097db96d56Sopenharmony_ciif __name__ == "__main__":
15107db96d56Sopenharmony_ci    unittest.main()
1511