blob: bc77103641b6ffe4efa37fba9fa147ec791032fc [file] [log] [blame]
Antoine Pitroud72402e2010-10-27 18:52:48 +00001# regression test for SAX 2.0
Lars Gustäbel96753b32000-09-24 12:24:24 +00002# $Id$
3
Thomas Wouters0e3f5912006-08-11 14:57:12 +00004from xml.sax import make_parser, ContentHandler, \
5 SAXException, SAXReaderNotAvailable, SAXParseException
R David Murraya846f5a2013-03-18 00:18:12 -04006import unittest
Victor Stinneref9c0e72017-05-05 09:46:47 +02007from unittest import mock
Martin v. Löwis962c9e72000-10-06 17:41:52 +00008try:
9 make_parser()
Martin v. Löwis80670bc2000-10-06 21:13:23 +000010except SAXReaderNotAvailable:
Martin v. Löwis962c9e72000-10-06 17:41:52 +000011 # don't try to test this module if we cannot create a parser
R David Murraya846f5a2013-03-18 00:18:12 -040012 raise unittest.SkipTest("no XML parsers available")
Thomas Wouters0e3f5912006-08-11 14:57:12 +000013from xml.sax.saxutils import XMLGenerator, escape, unescape, quoteattr, \
Serhiy Storchakaaa9563c2015-04-02 20:55:59 +030014 XMLFilterBase, prepare_input_source
Thomas Wouters0e3f5912006-08-11 14:57:12 +000015from xml.sax.expatreader import create_parser
Christian Heimes17b1d5d2018-09-23 09:50:25 +020016from xml.sax.handler import feature_namespaces, feature_external_ges
Thomas Wouters0e3f5912006-08-11 14:57:12 +000017from xml.sax.xmlreader import InputSource, AttributesImpl, AttributesNSImpl
Serhiy Storchaka88efc522013-02-10 14:29:52 +020018from io import BytesIO, StringIO
Georg Brandlc502df42013-05-12 11:41:12 +020019import codecs
Serhiy Storchaka1a4ed4c2013-02-02 12:17:05 +020020import os.path
Serhiy Storchakad5202392013-02-02 10:31:17 +020021import shutil
Hai Shi24bddc12020-05-28 22:24:39 +080022import sys
Christian Heimes17b1d5d2018-09-23 09:50:25 +020023from urllib.error import URLError
Victor Stinner7cb92042019-07-02 14:50:19 +020024import urllib.request
Serhiy Storchakad5202392013-02-02 10:31:17 +020025from test import support
Mickaël Schoentgen929b7042019-04-14 09:16:54 +000026from test.support import findfile, run_unittest, FakePath, TESTFN
Florent Xiclunaf15351d2010-03-13 23:24:31 +000027
28TEST_XMLFILE = findfile("test.xml", subdir="xmltestdata")
29TEST_XMLFILE_OUT = findfile("test.xml.out", subdir="xmltestdata")
Victor Stinner6c6f8512010-08-07 10:09:35 +000030try:
Marc-André Lemburg8f36af72011-02-25 15:42:01 +000031 TEST_XMLFILE.encode("utf-8")
32 TEST_XMLFILE_OUT.encode("utf-8")
Victor Stinner6c6f8512010-08-07 10:09:35 +000033except UnicodeEncodeError:
34 raise unittest.SkipTest("filename is not encodable to utf8")
Lars Gustäbel96753b32000-09-24 12:24:24 +000035
Serhiy Storchaka1a4ed4c2013-02-02 12:17:05 +020036supports_nonascii_filenames = True
37if not os.path.supports_unicode_filenames:
38 try:
Hai Shi24bddc12020-05-28 22:24:39 +080039 support.TESTFN_UNICODE.encode(sys.getfilesystemencoding())
Serhiy Storchaka1a4ed4c2013-02-02 12:17:05 +020040 except (UnicodeError, TypeError):
41 # Either the file system encoding is None, or the file name
42 # cannot be encoded in the file system encoding.
43 supports_nonascii_filenames = False
44requires_nonascii_filenames = unittest.skipUnless(
45 supports_nonascii_filenames,
46 'Requires non-ascii filenames support')
47
Guido van Rossumd8faa362007-04-27 19:54:29 +000048ns_uri = "http://www.python.org/xml-ns/saxtest/"
Lars Gustäbel96753b32000-09-24 12:24:24 +000049
Guido van Rossumd8faa362007-04-27 19:54:29 +000050class XmlTestBase(unittest.TestCase):
51 def verify_empty_attrs(self, attrs):
52 self.assertRaises(KeyError, attrs.getValue, "attr")
53 self.assertRaises(KeyError, attrs.getValueByQName, "attr")
54 self.assertRaises(KeyError, attrs.getNameByQName, "attr")
55 self.assertRaises(KeyError, attrs.getQNameByName, "attr")
56 self.assertRaises(KeyError, attrs.__getitem__, "attr")
Ezio Melottib3aedd42010-11-20 19:04:17 +000057 self.assertEqual(attrs.getLength(), 0)
58 self.assertEqual(attrs.getNames(), [])
59 self.assertEqual(attrs.getQNames(), [])
60 self.assertEqual(len(attrs), 0)
Ezio Melottib58e0bd2010-01-23 15:40:09 +000061 self.assertNotIn("attr", attrs)
Ezio Melottib3aedd42010-11-20 19:04:17 +000062 self.assertEqual(list(attrs.keys()), [])
63 self.assertEqual(attrs.get("attrs"), None)
64 self.assertEqual(attrs.get("attrs", 25), 25)
65 self.assertEqual(list(attrs.items()), [])
66 self.assertEqual(list(attrs.values()), [])
Lars Gustäbel96753b32000-09-24 12:24:24 +000067
Guido van Rossumd8faa362007-04-27 19:54:29 +000068 def verify_empty_nsattrs(self, attrs):
69 self.assertRaises(KeyError, attrs.getValue, (ns_uri, "attr"))
70 self.assertRaises(KeyError, attrs.getValueByQName, "ns:attr")
71 self.assertRaises(KeyError, attrs.getNameByQName, "ns:attr")
72 self.assertRaises(KeyError, attrs.getQNameByName, (ns_uri, "attr"))
73 self.assertRaises(KeyError, attrs.__getitem__, (ns_uri, "attr"))
Ezio Melottib3aedd42010-11-20 19:04:17 +000074 self.assertEqual(attrs.getLength(), 0)
75 self.assertEqual(attrs.getNames(), [])
76 self.assertEqual(attrs.getQNames(), [])
77 self.assertEqual(len(attrs), 0)
Ezio Melottib58e0bd2010-01-23 15:40:09 +000078 self.assertNotIn((ns_uri, "attr"), attrs)
Ezio Melottib3aedd42010-11-20 19:04:17 +000079 self.assertEqual(list(attrs.keys()), [])
80 self.assertEqual(attrs.get((ns_uri, "attr")), None)
81 self.assertEqual(attrs.get((ns_uri, "attr"), 25), 25)
82 self.assertEqual(list(attrs.items()), [])
83 self.assertEqual(list(attrs.values()), [])
Lars Gustäbel96753b32000-09-24 12:24:24 +000084
Guido van Rossumd8faa362007-04-27 19:54:29 +000085 def verify_attrs_wattr(self, attrs):
Ezio Melottib3aedd42010-11-20 19:04:17 +000086 self.assertEqual(attrs.getLength(), 1)
87 self.assertEqual(attrs.getNames(), ["attr"])
88 self.assertEqual(attrs.getQNames(), ["attr"])
89 self.assertEqual(len(attrs), 1)
Benjamin Peterson577473f2010-01-19 00:09:57 +000090 self.assertIn("attr", attrs)
Ezio Melottib3aedd42010-11-20 19:04:17 +000091 self.assertEqual(list(attrs.keys()), ["attr"])
92 self.assertEqual(attrs.get("attr"), "val")
93 self.assertEqual(attrs.get("attr", 25), "val")
94 self.assertEqual(list(attrs.items()), [("attr", "val")])
95 self.assertEqual(list(attrs.values()), ["val"])
96 self.assertEqual(attrs.getValue("attr"), "val")
97 self.assertEqual(attrs.getValueByQName("attr"), "val")
98 self.assertEqual(attrs.getNameByQName("attr"), "attr")
99 self.assertEqual(attrs["attr"], "val")
100 self.assertEqual(attrs.getQNameByName("attr"), "attr")
Lars Gustäbel96753b32000-09-24 12:24:24 +0000101
Serhiy Storchaka13e41c52015-04-02 23:05:57 +0300102
103def xml_str(doc, encoding=None):
104 if encoding is None:
105 return doc
106 return '<?xml version="1.0" encoding="%s"?>\n%s' % (encoding, doc)
107
108def xml_bytes(doc, encoding, decl_encoding=...):
109 if decl_encoding is ...:
110 decl_encoding = encoding
111 return xml_str(doc, decl_encoding).encode(encoding, 'xmlcharrefreplace')
112
113def make_xml_file(doc, encoding, decl_encoding=...):
114 if decl_encoding is ...:
115 decl_encoding = encoding
116 with open(TESTFN, 'w', encoding=encoding, errors='xmlcharrefreplace') as f:
117 f.write(xml_str(doc, decl_encoding))
118
119
120class ParseTest(unittest.TestCase):
121 data = '<money value="$\xa3\u20ac\U0001017b">$\xa3\u20ac\U0001017b</money>'
122
123 def tearDown(self):
124 support.unlink(TESTFN)
125
126 def check_parse(self, f):
127 from xml.sax import parse
128 result = StringIO()
129 parse(f, XMLGenerator(result, 'utf-8'))
130 self.assertEqual(result.getvalue(), xml_str(self.data, 'utf-8'))
131
132 def test_parse_text(self):
133 encodings = ('us-ascii', 'iso-8859-1', 'utf-8',
134 'utf-16', 'utf-16le', 'utf-16be')
135 for encoding in encodings:
136 self.check_parse(StringIO(xml_str(self.data, encoding)))
137 make_xml_file(self.data, encoding)
138 with open(TESTFN, 'r', encoding=encoding) as f:
139 self.check_parse(f)
140 self.check_parse(StringIO(self.data))
141 make_xml_file(self.data, encoding, None)
142 with open(TESTFN, 'r', encoding=encoding) as f:
143 self.check_parse(f)
144
145 def test_parse_bytes(self):
146 # UTF-8 is default encoding, US-ASCII is compatible with UTF-8,
147 # UTF-16 is autodetected
148 encodings = ('us-ascii', 'utf-8', 'utf-16', 'utf-16le', 'utf-16be')
149 for encoding in encodings:
150 self.check_parse(BytesIO(xml_bytes(self.data, encoding)))
151 make_xml_file(self.data, encoding)
152 self.check_parse(TESTFN)
153 with open(TESTFN, 'rb') as f:
154 self.check_parse(f)
155 self.check_parse(BytesIO(xml_bytes(self.data, encoding, None)))
156 make_xml_file(self.data, encoding, None)
157 self.check_parse(TESTFN)
158 with open(TESTFN, 'rb') as f:
159 self.check_parse(f)
160 # accept UTF-8 with BOM
161 self.check_parse(BytesIO(xml_bytes(self.data, 'utf-8-sig', 'utf-8')))
162 make_xml_file(self.data, 'utf-8-sig', 'utf-8')
163 self.check_parse(TESTFN)
164 with open(TESTFN, 'rb') as f:
165 self.check_parse(f)
166 self.check_parse(BytesIO(xml_bytes(self.data, 'utf-8-sig', None)))
167 make_xml_file(self.data, 'utf-8-sig', None)
168 self.check_parse(TESTFN)
169 with open(TESTFN, 'rb') as f:
170 self.check_parse(f)
171 # accept data with declared encoding
172 self.check_parse(BytesIO(xml_bytes(self.data, 'iso-8859-1')))
173 make_xml_file(self.data, 'iso-8859-1')
174 self.check_parse(TESTFN)
175 with open(TESTFN, 'rb') as f:
176 self.check_parse(f)
177 # fail on non-UTF-8 incompatible data without declared encoding
178 with self.assertRaises(SAXException):
179 self.check_parse(BytesIO(xml_bytes(self.data, 'iso-8859-1', None)))
180 make_xml_file(self.data, 'iso-8859-1', None)
Victor Stinneref9c0e72017-05-05 09:46:47 +0200181 with self.assertRaises(SAXException):
182 self.check_parse(TESTFN)
Serhiy Storchaka13e41c52015-04-02 23:05:57 +0300183 with open(TESTFN, 'rb') as f:
184 with self.assertRaises(SAXException):
185 self.check_parse(f)
186
Mickaël Schoentgen929b7042019-04-14 09:16:54 +0000187 def test_parse_path_object(self):
188 make_xml_file(self.data, 'utf-8', None)
189 self.check_parse(FakePath(TESTFN))
190
Serhiy Storchaka13e41c52015-04-02 23:05:57 +0300191 def test_parse_InputSource(self):
192 # accept data without declared but with explicitly specified encoding
193 make_xml_file(self.data, 'iso-8859-1', None)
194 with open(TESTFN, 'rb') as f:
195 input = InputSource()
196 input.setByteStream(f)
197 input.setEncoding('iso-8859-1')
198 self.check_parse(input)
199
Victor Stinneref9c0e72017-05-05 09:46:47 +0200200 def test_parse_close_source(self):
201 builtin_open = open
202 fileobj = None
203
204 def mock_open(*args):
205 nonlocal fileobj
206 fileobj = builtin_open(*args)
207 return fileobj
208
209 with mock.patch('xml.sax.saxutils.open', side_effect=mock_open):
210 make_xml_file(self.data, 'iso-8859-1', None)
211 with self.assertRaises(SAXException):
212 self.check_parse(TESTFN)
213 self.assertTrue(fileobj.closed)
214
Serhiy Storchaka13e41c52015-04-02 23:05:57 +0300215 def check_parseString(self, s):
216 from xml.sax import parseString
217 result = StringIO()
218 parseString(s, XMLGenerator(result, 'utf-8'))
219 self.assertEqual(result.getvalue(), xml_str(self.data, 'utf-8'))
220
Serhiy Storchaka778db282015-04-04 10:12:26 +0300221 def test_parseString_text(self):
222 encodings = ('us-ascii', 'iso-8859-1', 'utf-8',
223 'utf-16', 'utf-16le', 'utf-16be')
224 for encoding in encodings:
225 self.check_parseString(xml_str(self.data, encoding))
226 self.check_parseString(self.data)
227
Serhiy Storchaka13e41c52015-04-02 23:05:57 +0300228 def test_parseString_bytes(self):
229 # UTF-8 is default encoding, US-ASCII is compatible with UTF-8,
230 # UTF-16 is autodetected
231 encodings = ('us-ascii', 'utf-8', 'utf-16', 'utf-16le', 'utf-16be')
232 for encoding in encodings:
233 self.check_parseString(xml_bytes(self.data, encoding))
234 self.check_parseString(xml_bytes(self.data, encoding, None))
235 # accept UTF-8 with BOM
236 self.check_parseString(xml_bytes(self.data, 'utf-8-sig', 'utf-8'))
237 self.check_parseString(xml_bytes(self.data, 'utf-8-sig', None))
238 # accept data with declared encoding
239 self.check_parseString(xml_bytes(self.data, 'iso-8859-1'))
240 # fail on non-UTF-8 incompatible data without declared encoding
241 with self.assertRaises(SAXException):
242 self.check_parseString(xml_bytes(self.data, 'iso-8859-1', None))
243
Guido van Rossumd8faa362007-04-27 19:54:29 +0000244class MakeParserTest(unittest.TestCase):
245 def test_make_parser2(self):
Lars Gustäbel2fc52942000-10-24 15:35:07 +0000246 # Creating parsers several times in a row should succeed.
247 # Testing this because there have been failures of this kind
248 # before.
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000249 from xml.sax import make_parser
Lars Gustäbel2fc52942000-10-24 15:35:07 +0000250 p = make_parser()
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000251 from xml.sax import make_parser
Lars Gustäbel2fc52942000-10-24 15:35:07 +0000252 p = make_parser()
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000253 from xml.sax import make_parser
Lars Gustäbel2fc52942000-10-24 15:35:07 +0000254 p = make_parser()
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000255 from xml.sax import make_parser
Lars Gustäbel2fc52942000-10-24 15:35:07 +0000256 p = make_parser()
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000257 from xml.sax import make_parser
Lars Gustäbel2fc52942000-10-24 15:35:07 +0000258 p = make_parser()
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000259 from xml.sax import make_parser
Lars Gustäbel2fc52942000-10-24 15:35:07 +0000260 p = make_parser()
Tim Petersd2bf3b72001-01-18 02:22:22 +0000261
Andrés Delfinoa6dc5312018-10-26 11:56:57 -0300262 def test_make_parser3(self):
263 # Testing that make_parser can handle different types of
264 # iterables.
265 make_parser(['module'])
266 make_parser(('module', ))
267 make_parser({'module'})
268 make_parser(frozenset({'module'}))
269 make_parser({'module': None})
270 make_parser(iter(['module']))
271
272 def test_make_parser4(self):
273 # Testing that make_parser can handle empty iterables.
274 make_parser([])
275 make_parser(tuple())
276 make_parser(set())
277 make_parser(frozenset())
278 make_parser({})
279 make_parser(iter([]))
280
281 def test_make_parser5(self):
282 # Testing that make_parser can handle iterables with more than
283 # one item.
284 make_parser(['module1', 'module2'])
285 make_parser(('module1', 'module2'))
286 make_parser({'module1', 'module2'})
287 make_parser(frozenset({'module1', 'module2'}))
288 make_parser({'module1': None, 'module2': None})
289 make_parser(iter(['module1', 'module2']))
Tim Petersd2bf3b72001-01-18 02:22:22 +0000290
Lars Gustäbel96753b32000-09-24 12:24:24 +0000291# ===========================================================================
292#
293# saxutils tests
294#
295# ===========================================================================
296
Guido van Rossumd8faa362007-04-27 19:54:29 +0000297class SaxutilsTest(unittest.TestCase):
298 # ===== escape
299 def test_escape_basic(self):
Ezio Melottib3aedd42010-11-20 19:04:17 +0000300 self.assertEqual(escape("Donald Duck & Co"), "Donald Duck &amp; Co")
Lars Gustäbel96753b32000-09-24 12:24:24 +0000301
Guido van Rossumd8faa362007-04-27 19:54:29 +0000302 def test_escape_all(self):
Ezio Melottib3aedd42010-11-20 19:04:17 +0000303 self.assertEqual(escape("<Donald Duck & Co>"),
304 "&lt;Donald Duck &amp; Co&gt;")
Lars Gustäbel96753b32000-09-24 12:24:24 +0000305
Guido van Rossumd8faa362007-04-27 19:54:29 +0000306 def test_escape_extra(self):
Ezio Melottib3aedd42010-11-20 19:04:17 +0000307 self.assertEqual(escape("Hei på deg", {"å" : "&aring;"}),
308 "Hei p&aring; deg")
Lars Gustäbel96753b32000-09-24 12:24:24 +0000309
Guido van Rossumd8faa362007-04-27 19:54:29 +0000310 # ===== unescape
311 def test_unescape_basic(self):
Ezio Melottib3aedd42010-11-20 19:04:17 +0000312 self.assertEqual(unescape("Donald Duck &amp; Co"), "Donald Duck & Co")
Lars Gustäbel96753b32000-09-24 12:24:24 +0000313
Guido van Rossumd8faa362007-04-27 19:54:29 +0000314 def test_unescape_all(self):
Ezio Melottib3aedd42010-11-20 19:04:17 +0000315 self.assertEqual(unescape("&lt;Donald Duck &amp; Co&gt;"),
316 "<Donald Duck & Co>")
Martin v. Löwis74b51ac2002-10-26 14:50:45 +0000317
Guido van Rossumd8faa362007-04-27 19:54:29 +0000318 def test_unescape_extra(self):
Ezio Melottib3aedd42010-11-20 19:04:17 +0000319 self.assertEqual(unescape("Hei på deg", {"å" : "&aring;"}),
320 "Hei p&aring; deg")
Martin v. Löwis74b51ac2002-10-26 14:50:45 +0000321
Guido van Rossumd8faa362007-04-27 19:54:29 +0000322 def test_unescape_amp_extra(self):
Ezio Melottib3aedd42010-11-20 19:04:17 +0000323 self.assertEqual(unescape("&amp;foo;", {"&foo;": "splat"}), "&foo;")
Martin v. Löwis74b51ac2002-10-26 14:50:45 +0000324
Guido van Rossumd8faa362007-04-27 19:54:29 +0000325 # ===== quoteattr
326 def test_quoteattr_basic(self):
Ezio Melottib3aedd42010-11-20 19:04:17 +0000327 self.assertEqual(quoteattr("Donald Duck & Co"),
328 '"Donald Duck &amp; Co"')
Martin v. Löwis74b51ac2002-10-26 14:50:45 +0000329
Guido van Rossumd8faa362007-04-27 19:54:29 +0000330 def test_single_quoteattr(self):
Ezio Melottib3aedd42010-11-20 19:04:17 +0000331 self.assertEqual(quoteattr('Includes "double" quotes'),
332 '\'Includes "double" quotes\'')
Fred Drake32f3add2002-10-28 17:58:48 +0000333
Guido van Rossumd8faa362007-04-27 19:54:29 +0000334 def test_double_quoteattr(self):
Ezio Melottib3aedd42010-11-20 19:04:17 +0000335 self.assertEqual(quoteattr("Includes 'single' quotes"),
336 "\"Includes 'single' quotes\"")
Fred Drakeacd32d32001-07-19 16:10:15 +0000337
Guido van Rossumd8faa362007-04-27 19:54:29 +0000338 def test_single_double_quoteattr(self):
Ezio Melottib3aedd42010-11-20 19:04:17 +0000339 self.assertEqual(quoteattr("Includes 'single' and \"double\" quotes"),
340 "\"Includes 'single' and &quot;double&quot; quotes\"")
Fred Drakeacd32d32001-07-19 16:10:15 +0000341
Guido van Rossumd8faa362007-04-27 19:54:29 +0000342 # ===== make_parser
343 def test_make_parser(self):
Martin v. Löwis962c9e72000-10-06 17:41:52 +0000344 # Creating a parser should succeed - it should fall back
345 # to the expatreader
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000346 p = make_parser(['xml.parsers.no_such_parser'])
Martin v. Löwis962c9e72000-10-06 17:41:52 +0000347
348
Serhiy Storchakaaa9563c2015-04-02 20:55:59 +0300349class PrepareInputSourceTest(unittest.TestCase):
350
351 def setUp(self):
352 self.file = support.TESTFN
353 with open(self.file, "w") as tmp:
354 tmp.write("This was read from a file.")
355
356 def tearDown(self):
357 support.unlink(self.file)
358
359 def make_byte_stream(self):
360 return BytesIO(b"This is a byte stream.")
361
Serhiy Storchaka61de0872015-04-02 21:00:13 +0300362 def make_character_stream(self):
363 return StringIO("This is a character stream.")
364
Serhiy Storchakaaa9563c2015-04-02 20:55:59 +0300365 def checkContent(self, stream, content):
366 self.assertIsNotNone(stream)
367 self.assertEqual(stream.read(), content)
368 stream.close()
369
370
Serhiy Storchaka61de0872015-04-02 21:00:13 +0300371 def test_character_stream(self):
372 # If the source is an InputSource with a character stream, use it.
373 src = InputSource(self.file)
374 src.setCharacterStream(self.make_character_stream())
375 prep = prepare_input_source(src)
376 self.assertIsNone(prep.getByteStream())
377 self.checkContent(prep.getCharacterStream(),
378 "This is a character stream.")
379
Serhiy Storchakaaa9563c2015-04-02 20:55:59 +0300380 def test_byte_stream(self):
381 # If the source is an InputSource that does not have a character
382 # stream but does have a byte stream, use the byte stream.
383 src = InputSource(self.file)
384 src.setByteStream(self.make_byte_stream())
385 prep = prepare_input_source(src)
386 self.assertIsNone(prep.getCharacterStream())
387 self.checkContent(prep.getByteStream(),
388 b"This is a byte stream.")
389
390 def test_system_id(self):
391 # If the source is an InputSource that has neither a character
392 # stream nor a byte stream, open the system ID.
393 src = InputSource(self.file)
394 prep = prepare_input_source(src)
395 self.assertIsNone(prep.getCharacterStream())
396 self.checkContent(prep.getByteStream(),
397 b"This was read from a file.")
398
399 def test_string(self):
400 # If the source is a string, use it as a system ID and open it.
401 prep = prepare_input_source(self.file)
402 self.assertIsNone(prep.getCharacterStream())
403 self.checkContent(prep.getByteStream(),
404 b"This was read from a file.")
405
Mickaël Schoentgen929b7042019-04-14 09:16:54 +0000406 def test_path_objects(self):
407 # If the source is a Path object, use it as a system ID and open it.
408 prep = prepare_input_source(FakePath(self.file))
409 self.assertIsNone(prep.getCharacterStream())
410 self.checkContent(prep.getByteStream(),
411 b"This was read from a file.")
412
Serhiy Storchakaaa9563c2015-04-02 20:55:59 +0300413 def test_binary_file(self):
414 # If the source is a binary file-like object, use it as a byte
415 # stream.
416 prep = prepare_input_source(self.make_byte_stream())
417 self.assertIsNone(prep.getCharacterStream())
418 self.checkContent(prep.getByteStream(),
419 b"This is a byte stream.")
420
Serhiy Storchaka61de0872015-04-02 21:00:13 +0300421 def test_text_file(self):
422 # If the source is a text file-like object, use it as a character
423 # stream.
424 prep = prepare_input_source(self.make_character_stream())
425 self.assertIsNone(prep.getByteStream())
426 self.checkContent(prep.getCharacterStream(),
427 "This is a character stream.")
428
Serhiy Storchakaaa9563c2015-04-02 20:55:59 +0300429
Lars Gustäbel96753b32000-09-24 12:24:24 +0000430# ===== XMLGenerator
431
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200432class XmlgenTest:
Guido van Rossumd8faa362007-04-27 19:54:29 +0000433 def test_xmlgen_basic(self):
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200434 result = self.ioclass()
Guido van Rossumd8faa362007-04-27 19:54:29 +0000435 gen = XMLGenerator(result)
436 gen.startDocument()
437 gen.startElement("doc", {})
438 gen.endElement("doc")
439 gen.endDocument()
Lars Gustäbel96753b32000-09-24 12:24:24 +0000440
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200441 self.assertEqual(result.getvalue(), self.xml("<doc></doc>"))
Lars Gustäbel96753b32000-09-24 12:24:24 +0000442
R. David Murraya90032a2010-10-17 22:46:45 +0000443 def test_xmlgen_basic_empty(self):
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200444 result = self.ioclass()
R. David Murraya90032a2010-10-17 22:46:45 +0000445 gen = XMLGenerator(result, short_empty_elements=True)
446 gen.startDocument()
447 gen.startElement("doc", {})
448 gen.endElement("doc")
449 gen.endDocument()
450
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200451 self.assertEqual(result.getvalue(), self.xml("<doc/>"))
R. David Murraya90032a2010-10-17 22:46:45 +0000452
Guido van Rossumd8faa362007-04-27 19:54:29 +0000453 def test_xmlgen_content(self):
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200454 result = self.ioclass()
Guido van Rossumd8faa362007-04-27 19:54:29 +0000455 gen = XMLGenerator(result)
Fred Drake004d5e62000-10-23 17:22:08 +0000456
Guido van Rossumd8faa362007-04-27 19:54:29 +0000457 gen.startDocument()
458 gen.startElement("doc", {})
459 gen.characters("huhei")
460 gen.endElement("doc")
461 gen.endDocument()
Lars Gustäbel96753b32000-09-24 12:24:24 +0000462
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200463 self.assertEqual(result.getvalue(), self.xml("<doc>huhei</doc>"))
Lars Gustäbel96753b32000-09-24 12:24:24 +0000464
R. David Murraya90032a2010-10-17 22:46:45 +0000465 def test_xmlgen_content_empty(self):
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200466 result = self.ioclass()
R. David Murraya90032a2010-10-17 22:46:45 +0000467 gen = XMLGenerator(result, short_empty_elements=True)
468
469 gen.startDocument()
470 gen.startElement("doc", {})
471 gen.characters("huhei")
472 gen.endElement("doc")
473 gen.endDocument()
474
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200475 self.assertEqual(result.getvalue(), self.xml("<doc>huhei</doc>"))
R. David Murraya90032a2010-10-17 22:46:45 +0000476
Guido van Rossumd8faa362007-04-27 19:54:29 +0000477 def test_xmlgen_pi(self):
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200478 result = self.ioclass()
Guido van Rossumd8faa362007-04-27 19:54:29 +0000479 gen = XMLGenerator(result)
Fred Drake004d5e62000-10-23 17:22:08 +0000480
Guido van Rossumd8faa362007-04-27 19:54:29 +0000481 gen.startDocument()
482 gen.processingInstruction("test", "data")
483 gen.startElement("doc", {})
484 gen.endElement("doc")
485 gen.endDocument()
Lars Gustäbel96753b32000-09-24 12:24:24 +0000486
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200487 self.assertEqual(result.getvalue(),
488 self.xml("<?test data?><doc></doc>"))
Lars Gustäbel96753b32000-09-24 12:24:24 +0000489
Guido van Rossumd8faa362007-04-27 19:54:29 +0000490 def test_xmlgen_content_escape(self):
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200491 result = self.ioclass()
Guido van Rossumd8faa362007-04-27 19:54:29 +0000492 gen = XMLGenerator(result)
Fred Drake004d5e62000-10-23 17:22:08 +0000493
Guido van Rossumd8faa362007-04-27 19:54:29 +0000494 gen.startDocument()
495 gen.startElement("doc", {})
496 gen.characters("<huhei&")
497 gen.endElement("doc")
498 gen.endDocument()
Lars Gustäbel96753b32000-09-24 12:24:24 +0000499
Ezio Melottib3aedd42010-11-20 19:04:17 +0000500 self.assertEqual(result.getvalue(),
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200501 self.xml("<doc>&lt;huhei&amp;</doc>"))
Lars Gustäbel96753b32000-09-24 12:24:24 +0000502
Guido van Rossumd8faa362007-04-27 19:54:29 +0000503 def test_xmlgen_attr_escape(self):
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200504 result = self.ioclass()
Guido van Rossumd8faa362007-04-27 19:54:29 +0000505 gen = XMLGenerator(result)
Fred Drakec9fadf92001-08-07 19:17:06 +0000506
Guido van Rossumd8faa362007-04-27 19:54:29 +0000507 gen.startDocument()
508 gen.startElement("doc", {"a": '"'})
509 gen.startElement("e", {"a": "'"})
510 gen.endElement("e")
511 gen.startElement("e", {"a": "'\""})
512 gen.endElement("e")
513 gen.startElement("e", {"a": "\n\r\t"})
514 gen.endElement("e")
515 gen.endElement("doc")
516 gen.endDocument()
Fred Drakec9fadf92001-08-07 19:17:06 +0000517
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200518 self.assertEqual(result.getvalue(), self.xml(
519 "<doc a='\"'><e a=\"'\"></e>"
520 "<e a=\"'&quot;\"></e>"
521 "<e a=\"&#10;&#13;&#9;\"></e></doc>"))
522
523 def test_xmlgen_encoding(self):
524 encodings = ('iso-8859-15', 'utf-8', 'utf-8-sig',
525 'utf-16', 'utf-16be', 'utf-16le',
526 'utf-32', 'utf-32be', 'utf-32le')
527 for encoding in encodings:
528 result = self.ioclass()
529 gen = XMLGenerator(result, encoding=encoding)
530
531 gen.startDocument()
532 gen.startElement("doc", {"a": '\u20ac'})
533 gen.characters("\u20ac")
534 gen.endElement("doc")
535 gen.endDocument()
536
537 self.assertEqual(result.getvalue(),
538 self.xml('<doc a="\u20ac">\u20ac</doc>', encoding=encoding))
539
540 def test_xmlgen_unencodable(self):
541 result = self.ioclass()
542 gen = XMLGenerator(result, encoding='ascii')
543
544 gen.startDocument()
545 gen.startElement("doc", {"a": '\u20ac'})
546 gen.characters("\u20ac")
547 gen.endElement("doc")
548 gen.endDocument()
549
550 self.assertEqual(result.getvalue(),
551 self.xml('<doc a="&#8364;">&#8364;</doc>', encoding='ascii'))
Fred Drakec9fadf92001-08-07 19:17:06 +0000552
Guido van Rossumd8faa362007-04-27 19:54:29 +0000553 def test_xmlgen_ignorable(self):
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200554 result = self.ioclass()
Guido van Rossumd8faa362007-04-27 19:54:29 +0000555 gen = XMLGenerator(result)
Fred Drake004d5e62000-10-23 17:22:08 +0000556
Guido van Rossumd8faa362007-04-27 19:54:29 +0000557 gen.startDocument()
558 gen.startElement("doc", {})
559 gen.ignorableWhitespace(" ")
560 gen.endElement("doc")
561 gen.endDocument()
Lars Gustäbel96753b32000-09-24 12:24:24 +0000562
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200563 self.assertEqual(result.getvalue(), self.xml("<doc> </doc>"))
Lars Gustäbel96753b32000-09-24 12:24:24 +0000564
R. David Murraya90032a2010-10-17 22:46:45 +0000565 def test_xmlgen_ignorable_empty(self):
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200566 result = self.ioclass()
R. David Murraya90032a2010-10-17 22:46:45 +0000567 gen = XMLGenerator(result, short_empty_elements=True)
568
569 gen.startDocument()
570 gen.startElement("doc", {})
571 gen.ignorableWhitespace(" ")
572 gen.endElement("doc")
573 gen.endDocument()
574
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200575 self.assertEqual(result.getvalue(), self.xml("<doc> </doc>"))
R. David Murraya90032a2010-10-17 22:46:45 +0000576
Serhiy Storchaka3eab6b32013-05-12 17:31:16 +0300577 def test_xmlgen_encoding_bytes(self):
578 encodings = ('iso-8859-15', 'utf-8', 'utf-8-sig',
579 'utf-16', 'utf-16be', 'utf-16le',
580 'utf-32', 'utf-32be', 'utf-32le')
581 for encoding in encodings:
582 result = self.ioclass()
583 gen = XMLGenerator(result, encoding=encoding)
584
585 gen.startDocument()
586 gen.startElement("doc", {"a": '\u20ac'})
587 gen.characters("\u20ac".encode(encoding))
588 gen.ignorableWhitespace(" ".encode(encoding))
589 gen.endElement("doc")
590 gen.endDocument()
591
592 self.assertEqual(result.getvalue(),
593 self.xml('<doc a="\u20ac">\u20ac </doc>', encoding=encoding))
594
Guido van Rossumd8faa362007-04-27 19:54:29 +0000595 def test_xmlgen_ns(self):
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200596 result = self.ioclass()
Guido van Rossumd8faa362007-04-27 19:54:29 +0000597 gen = XMLGenerator(result)
Lars Gustäbel96753b32000-09-24 12:24:24 +0000598
Guido van Rossumd8faa362007-04-27 19:54:29 +0000599 gen.startDocument()
600 gen.startPrefixMapping("ns1", ns_uri)
601 gen.startElementNS((ns_uri, "doc"), "ns1:doc", {})
602 # add an unqualified name
603 gen.startElementNS((None, "udoc"), None, {})
604 gen.endElementNS((None, "udoc"), None)
605 gen.endElementNS((ns_uri, "doc"), "ns1:doc")
606 gen.endPrefixMapping("ns1")
607 gen.endDocument()
Fred Drake004d5e62000-10-23 17:22:08 +0000608
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200609 self.assertEqual(result.getvalue(), self.xml(
610 '<ns1:doc xmlns:ns1="%s"><udoc></udoc></ns1:doc>' %
Guido van Rossumd8faa362007-04-27 19:54:29 +0000611 ns_uri))
Lars Gustäbel96753b32000-09-24 12:24:24 +0000612
R. David Murraya90032a2010-10-17 22:46:45 +0000613 def test_xmlgen_ns_empty(self):
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200614 result = self.ioclass()
R. David Murraya90032a2010-10-17 22:46:45 +0000615 gen = XMLGenerator(result, short_empty_elements=True)
616
617 gen.startDocument()
618 gen.startPrefixMapping("ns1", ns_uri)
619 gen.startElementNS((ns_uri, "doc"), "ns1:doc", {})
620 # add an unqualified name
621 gen.startElementNS((None, "udoc"), None, {})
622 gen.endElementNS((None, "udoc"), None)
623 gen.endElementNS((ns_uri, "doc"), "ns1:doc")
624 gen.endPrefixMapping("ns1")
625 gen.endDocument()
626
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200627 self.assertEqual(result.getvalue(), self.xml(
628 '<ns1:doc xmlns:ns1="%s"><udoc/></ns1:doc>' %
R. David Murraya90032a2010-10-17 22:46:45 +0000629 ns_uri))
630
Guido van Rossumd8faa362007-04-27 19:54:29 +0000631 def test_1463026_1(self):
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200632 result = self.ioclass()
Guido van Rossumd8faa362007-04-27 19:54:29 +0000633 gen = XMLGenerator(result)
Thomas Wouterscf297e42007-02-23 15:07:44 +0000634
Guido van Rossumd8faa362007-04-27 19:54:29 +0000635 gen.startDocument()
636 gen.startElementNS((None, 'a'), 'a', {(None, 'b'):'c'})
637 gen.endElementNS((None, 'a'), 'a')
638 gen.endDocument()
Thomas Wouterscf297e42007-02-23 15:07:44 +0000639
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200640 self.assertEqual(result.getvalue(), self.xml('<a b="c"></a>'))
Thomas Wouterscf297e42007-02-23 15:07:44 +0000641
R. David Murraya90032a2010-10-17 22:46:45 +0000642 def test_1463026_1_empty(self):
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200643 result = self.ioclass()
R. David Murraya90032a2010-10-17 22:46:45 +0000644 gen = XMLGenerator(result, short_empty_elements=True)
645
646 gen.startDocument()
647 gen.startElementNS((None, 'a'), 'a', {(None, 'b'):'c'})
648 gen.endElementNS((None, 'a'), 'a')
649 gen.endDocument()
650
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200651 self.assertEqual(result.getvalue(), self.xml('<a b="c"/>'))
R. David Murraya90032a2010-10-17 22:46:45 +0000652
Guido van Rossumd8faa362007-04-27 19:54:29 +0000653 def test_1463026_2(self):
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200654 result = self.ioclass()
Guido van Rossumd8faa362007-04-27 19:54:29 +0000655 gen = XMLGenerator(result)
Thomas Wouterscf297e42007-02-23 15:07:44 +0000656
Guido van Rossumd8faa362007-04-27 19:54:29 +0000657 gen.startDocument()
658 gen.startPrefixMapping(None, 'qux')
659 gen.startElementNS(('qux', 'a'), 'a', {})
660 gen.endElementNS(('qux', 'a'), 'a')
661 gen.endPrefixMapping(None)
662 gen.endDocument()
Thomas Wouterscf297e42007-02-23 15:07:44 +0000663
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200664 self.assertEqual(result.getvalue(), self.xml('<a xmlns="qux"></a>'))
Thomas Wouterscf297e42007-02-23 15:07:44 +0000665
R. David Murraya90032a2010-10-17 22:46:45 +0000666 def test_1463026_2_empty(self):
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200667 result = self.ioclass()
R. David Murraya90032a2010-10-17 22:46:45 +0000668 gen = XMLGenerator(result, short_empty_elements=True)
669
670 gen.startDocument()
671 gen.startPrefixMapping(None, 'qux')
672 gen.startElementNS(('qux', 'a'), 'a', {})
673 gen.endElementNS(('qux', 'a'), 'a')
674 gen.endPrefixMapping(None)
675 gen.endDocument()
676
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200677 self.assertEqual(result.getvalue(), self.xml('<a xmlns="qux"/>'))
R. David Murraya90032a2010-10-17 22:46:45 +0000678
Guido van Rossumd8faa362007-04-27 19:54:29 +0000679 def test_1463026_3(self):
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200680 result = self.ioclass()
Guido van Rossumd8faa362007-04-27 19:54:29 +0000681 gen = XMLGenerator(result)
Thomas Wouterscf297e42007-02-23 15:07:44 +0000682
Guido van Rossumd8faa362007-04-27 19:54:29 +0000683 gen.startDocument()
684 gen.startPrefixMapping('my', 'qux')
685 gen.startElementNS(('qux', 'a'), 'a', {(None, 'b'):'c'})
686 gen.endElementNS(('qux', 'a'), 'a')
687 gen.endPrefixMapping('my')
688 gen.endDocument()
Thomas Wouterscf297e42007-02-23 15:07:44 +0000689
Ezio Melottib3aedd42010-11-20 19:04:17 +0000690 self.assertEqual(result.getvalue(),
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200691 self.xml('<my:a xmlns:my="qux" b="c"></my:a>'))
Lars Gustäbel96753b32000-09-24 12:24:24 +0000692
R. David Murraya90032a2010-10-17 22:46:45 +0000693 def test_1463026_3_empty(self):
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200694 result = self.ioclass()
R. David Murraya90032a2010-10-17 22:46:45 +0000695 gen = XMLGenerator(result, short_empty_elements=True)
696
697 gen.startDocument()
698 gen.startPrefixMapping('my', 'qux')
699 gen.startElementNS(('qux', 'a'), 'a', {(None, 'b'):'c'})
700 gen.endElementNS(('qux', 'a'), 'a')
701 gen.endPrefixMapping('my')
702 gen.endDocument()
703
Ezio Melottib3aedd42010-11-20 19:04:17 +0000704 self.assertEqual(result.getvalue(),
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200705 self.xml('<my:a xmlns:my="qux" b="c"/>'))
R. David Murraya90032a2010-10-17 22:46:45 +0000706
Antoine Pitrou6b03ee62010-10-27 18:33:30 +0000707 def test_5027_1(self):
708 # The xml prefix (as in xml:lang below) is reserved and bound by
709 # definition to http://www.w3.org/XML/1998/namespace. XMLGenerator had
Andrew Svetlov737fb892012-12-18 21:14:22 +0200710 # a bug whereby a KeyError is raised because this namespace is missing
Antoine Pitrou6b03ee62010-10-27 18:33:30 +0000711 # from a dictionary.
712 #
713 # This test demonstrates the bug by parsing a document.
714 test_xml = StringIO(
715 '<?xml version="1.0"?>'
716 '<a:g1 xmlns:a="http://example.com/ns">'
717 '<a:g2 xml:lang="en">Hello</a:g2>'
718 '</a:g1>')
719
720 parser = make_parser()
721 parser.setFeature(feature_namespaces, True)
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200722 result = self.ioclass()
Antoine Pitrou6b03ee62010-10-27 18:33:30 +0000723 gen = XMLGenerator(result)
724 parser.setContentHandler(gen)
725 parser.parse(test_xml)
726
Ezio Melottib3aedd42010-11-20 19:04:17 +0000727 self.assertEqual(result.getvalue(),
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200728 self.xml(
Ezio Melottib3aedd42010-11-20 19:04:17 +0000729 '<a:g1 xmlns:a="http://example.com/ns">'
730 '<a:g2 xml:lang="en">Hello</a:g2>'
731 '</a:g1>'))
Antoine Pitrou6b03ee62010-10-27 18:33:30 +0000732
733 def test_5027_2(self):
734 # The xml prefix (as in xml:lang below) is reserved and bound by
735 # definition to http://www.w3.org/XML/1998/namespace. XMLGenerator had
Andrew Svetlov737fb892012-12-18 21:14:22 +0200736 # a bug whereby a KeyError is raised because this namespace is missing
Antoine Pitrou6b03ee62010-10-27 18:33:30 +0000737 # from a dictionary.
738 #
739 # This test demonstrates the bug by direct manipulation of the
740 # XMLGenerator.
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200741 result = self.ioclass()
Antoine Pitrou6b03ee62010-10-27 18:33:30 +0000742 gen = XMLGenerator(result)
743
744 gen.startDocument()
745 gen.startPrefixMapping('a', 'http://example.com/ns')
746 gen.startElementNS(('http://example.com/ns', 'g1'), 'g1', {})
747 lang_attr = {('http://www.w3.org/XML/1998/namespace', 'lang'): 'en'}
748 gen.startElementNS(('http://example.com/ns', 'g2'), 'g2', lang_attr)
749 gen.characters('Hello')
750 gen.endElementNS(('http://example.com/ns', 'g2'), 'g2')
751 gen.endElementNS(('http://example.com/ns', 'g1'), 'g1')
752 gen.endPrefixMapping('a')
753 gen.endDocument()
754
Ezio Melottib3aedd42010-11-20 19:04:17 +0000755 self.assertEqual(result.getvalue(),
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200756 self.xml(
Ezio Melottib3aedd42010-11-20 19:04:17 +0000757 '<a:g1 xmlns:a="http://example.com/ns">'
758 '<a:g2 xml:lang="en">Hello</a:g2>'
759 '</a:g1>'))
Antoine Pitrou6b03ee62010-10-27 18:33:30 +0000760
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200761 def test_no_close_file(self):
762 result = self.ioclass()
763 def func(out):
764 gen = XMLGenerator(out)
765 gen.startDocument()
766 gen.startElement("doc", {})
767 func(result)
768 self.assertFalse(result.closed)
769
Serhiy Storchakaa5f13d22013-02-25 13:46:10 +0200770 def test_xmlgen_fragment(self):
771 result = self.ioclass()
772 gen = XMLGenerator(result)
773
774 # Don't call gen.startDocument()
775 gen.startElement("foo", {"a": "1.0"})
776 gen.characters("Hello")
777 gen.endElement("foo")
778 gen.startElement("bar", {"b": "2.0"})
779 gen.endElement("bar")
780 # Don't call gen.endDocument()
781
782 self.assertEqual(result.getvalue(),
783 self.xml('<foo a="1.0">Hello</foo><bar b="2.0"></bar>')[len(self.xml('')):])
784
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200785class StringXmlgenTest(XmlgenTest, unittest.TestCase):
786 ioclass = StringIO
787
788 def xml(self, doc, encoding='iso-8859-1'):
789 return '<?xml version="1.0" encoding="%s"?>\n%s' % (encoding, doc)
790
791 test_xmlgen_unencodable = None
792
793class BytesXmlgenTest(XmlgenTest, unittest.TestCase):
794 ioclass = BytesIO
795
796 def xml(self, doc, encoding='iso-8859-1'):
797 return ('<?xml version="1.0" encoding="%s"?>\n%s' %
798 (encoding, doc)).encode(encoding, 'xmlcharrefreplace')
799
800class WriterXmlgenTest(BytesXmlgenTest):
801 class ioclass(list):
802 write = list.append
803 closed = False
804
805 def seekable(self):
806 return True
807
808 def tell(self):
809 # return 0 at start and not 0 after start
810 return len(self)
811
812 def getvalue(self):
813 return b''.join(self)
814
Georg Brandlc502df42013-05-12 11:41:12 +0200815class StreamWriterXmlgenTest(XmlgenTest, unittest.TestCase):
816 def ioclass(self):
817 raw = BytesIO()
818 writer = codecs.getwriter('ascii')(raw, 'xmlcharrefreplace')
819 writer.getvalue = raw.getvalue
820 return writer
821
822 def xml(self, doc, encoding='iso-8859-1'):
823 return ('<?xml version="1.0" encoding="%s"?>\n%s' %
824 (encoding, doc)).encode('ascii', 'xmlcharrefreplace')
825
826class StreamReaderWriterXmlgenTest(XmlgenTest, unittest.TestCase):
827 fname = support.TESTFN + '-codecs'
828
829 def ioclass(self):
830 writer = codecs.open(self.fname, 'w', encoding='ascii',
831 errors='xmlcharrefreplace', buffering=0)
Antoine Pitrou2adb6fe2013-05-13 22:34:21 +0200832 def cleanup():
833 writer.close()
834 support.unlink(self.fname)
835 self.addCleanup(cleanup)
Richard Oudkerk90a24272013-05-18 18:11:30 +0100836 def getvalue():
837 # Windows will not let use reopen without first closing
838 writer.close()
839 with open(writer.name, 'rb') as f:
840 return f.read()
841 writer.getvalue = getvalue
Georg Brandlc502df42013-05-12 11:41:12 +0200842 return writer
843
Georg Brandlc502df42013-05-12 11:41:12 +0200844 def xml(self, doc, encoding='iso-8859-1'):
845 return ('<?xml version="1.0" encoding="%s"?>\n%s' %
846 (encoding, doc)).encode('ascii', 'xmlcharrefreplace')
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200847
848start = b'<?xml version="1.0" encoding="iso-8859-1"?>\n'
849
Fred Drake004d5e62000-10-23 17:22:08 +0000850
Guido van Rossumd8faa362007-04-27 19:54:29 +0000851class XMLFilterBaseTest(unittest.TestCase):
852 def test_filter_basic(self):
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200853 result = BytesIO()
Guido van Rossumd8faa362007-04-27 19:54:29 +0000854 gen = XMLGenerator(result)
855 filter = XMLFilterBase()
856 filter.setContentHandler(gen)
Lars Gustäbel96753b32000-09-24 12:24:24 +0000857
Guido van Rossumd8faa362007-04-27 19:54:29 +0000858 filter.startDocument()
859 filter.startElement("doc", {})
860 filter.characters("content")
861 filter.ignorableWhitespace(" ")
862 filter.endElement("doc")
863 filter.endDocument()
864
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200865 self.assertEqual(result.getvalue(), start + b"<doc>content </doc>")
Lars Gustäbel96753b32000-09-24 12:24:24 +0000866
867# ===========================================================================
868#
869# expatreader tests
870#
871# ===========================================================================
872
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200873with open(TEST_XMLFILE_OUT, 'rb') as f:
Benjamin Petersond5df36d2010-10-31 18:23:23 +0000874 xml_test_out = f.read()
Lars Gustäbelb7536d52000-09-24 18:53:56 +0000875
Guido van Rossumd8faa362007-04-27 19:54:29 +0000876class ExpatReaderTest(XmlTestBase):
Lars Gustäbelb7536d52000-09-24 18:53:56 +0000877
Guido van Rossumd8faa362007-04-27 19:54:29 +0000878 # ===== XMLReader support
Lars Gustäbelb7536d52000-09-24 18:53:56 +0000879
Serhiy Storchakaaa9563c2015-04-02 20:55:59 +0300880 def test_expat_binary_file(self):
Guido van Rossumd8faa362007-04-27 19:54:29 +0000881 parser = create_parser()
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200882 result = BytesIO()
Guido van Rossumd8faa362007-04-27 19:54:29 +0000883 xmlgen = XMLGenerator(result)
Lars Gustäbelb7536d52000-09-24 18:53:56 +0000884
Guido van Rossumd8faa362007-04-27 19:54:29 +0000885 parser.setContentHandler(xmlgen)
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200886 with open(TEST_XMLFILE, 'rb') as f:
Benjamin Petersond5df36d2010-10-31 18:23:23 +0000887 parser.parse(f)
Lars Gustäbelb7536d52000-09-24 18:53:56 +0000888
Ezio Melottib3aedd42010-11-20 19:04:17 +0000889 self.assertEqual(result.getvalue(), xml_test_out)
Lars Gustäbelb7536d52000-09-24 18:53:56 +0000890
Serhiy Storchakaaa9563c2015-04-02 20:55:59 +0300891 def test_expat_text_file(self):
892 parser = create_parser()
893 result = BytesIO()
894 xmlgen = XMLGenerator(result)
895
896 parser.setContentHandler(xmlgen)
897 with open(TEST_XMLFILE, 'rt', encoding='iso-8859-1') as f:
898 parser.parse(f)
899
900 self.assertEqual(result.getvalue(), xml_test_out)
901
Serhiy Storchaka1a4ed4c2013-02-02 12:17:05 +0200902 @requires_nonascii_filenames
Serhiy Storchakaaa9563c2015-04-02 20:55:59 +0300903 def test_expat_binary_file_nonascii(self):
Serhiy Storchakad5202392013-02-02 10:31:17 +0200904 fname = support.TESTFN_UNICODE
905 shutil.copyfile(TEST_XMLFILE, fname)
906 self.addCleanup(support.unlink, fname)
907
908 parser = create_parser()
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200909 result = BytesIO()
Serhiy Storchakad5202392013-02-02 10:31:17 +0200910 xmlgen = XMLGenerator(result)
911
912 parser.setContentHandler(xmlgen)
Serhiy Storchakaaa9563c2015-04-02 20:55:59 +0300913 parser.parse(open(fname, 'rb'))
Serhiy Storchakad5202392013-02-02 10:31:17 +0200914
915 self.assertEqual(result.getvalue(), xml_test_out)
916
Serhiy Storchakafc8e9b02014-11-27 22:13:16 +0200917 def test_expat_binary_file_bytes_name(self):
918 fname = os.fsencode(TEST_XMLFILE)
919 parser = create_parser()
920 result = BytesIO()
921 xmlgen = XMLGenerator(result)
922
923 parser.setContentHandler(xmlgen)
924 with open(fname, 'rb') as f:
925 parser.parse(f)
926
927 self.assertEqual(result.getvalue(), xml_test_out)
928
929 def test_expat_binary_file_int_name(self):
930 parser = create_parser()
931 result = BytesIO()
932 xmlgen = XMLGenerator(result)
933
934 parser.setContentHandler(xmlgen)
935 with open(TEST_XMLFILE, 'rb') as f:
936 with open(f.fileno(), 'rb', closefd=False) as f2:
937 parser.parse(f2)
938
939 self.assertEqual(result.getvalue(), xml_test_out)
940
Guido van Rossumd8faa362007-04-27 19:54:29 +0000941 # ===== DTDHandler support
Lars Gustäbelb7536d52000-09-24 18:53:56 +0000942
Guido van Rossumd8faa362007-04-27 19:54:29 +0000943 class TestDTDHandler:
Lars Gustäbelb7536d52000-09-24 18:53:56 +0000944
Guido van Rossumd8faa362007-04-27 19:54:29 +0000945 def __init__(self):
946 self._notations = []
947 self._entities = []
Lars Gustäbelb7536d52000-09-24 18:53:56 +0000948
Guido van Rossumd8faa362007-04-27 19:54:29 +0000949 def notationDecl(self, name, publicId, systemId):
950 self._notations.append((name, publicId, systemId))
Lars Gustäbelb7536d52000-09-24 18:53:56 +0000951
Guido van Rossumd8faa362007-04-27 19:54:29 +0000952 def unparsedEntityDecl(self, name, publicId, systemId, ndata):
953 self._entities.append((name, publicId, systemId, ndata))
Lars Gustäbel2fc52942000-10-24 15:35:07 +0000954
Christian Heimes17b1d5d2018-09-23 09:50:25 +0200955
956 class TestEntityRecorder:
957 def __init__(self):
958 self.entities = []
959
960 def resolveEntity(self, publicId, systemId):
961 self.entities.append((publicId, systemId))
962 source = InputSource()
963 source.setPublicId(publicId)
964 source.setSystemId(systemId)
965 return source
966
Guido van Rossumd8faa362007-04-27 19:54:29 +0000967 def test_expat_dtdhandler(self):
968 parser = create_parser()
969 handler = self.TestDTDHandler()
970 parser.setDTDHandler(handler)
Lars Gustäbel2fc52942000-10-24 15:35:07 +0000971
Guido van Rossumd8faa362007-04-27 19:54:29 +0000972 parser.feed('<!DOCTYPE doc [\n')
973 parser.feed(' <!ENTITY img SYSTEM "expat.gif" NDATA GIF>\n')
974 parser.feed(' <!NOTATION GIF PUBLIC "-//CompuServe//NOTATION Graphics Interchange Format 89a//EN">\n')
975 parser.feed(']>\n')
976 parser.feed('<doc></doc>')
977 parser.close()
Lars Gustäbel2fc52942000-10-24 15:35:07 +0000978
Ezio Melottib3aedd42010-11-20 19:04:17 +0000979 self.assertEqual(handler._notations,
Guido van Rossumd8faa362007-04-27 19:54:29 +0000980 [("GIF", "-//CompuServe//NOTATION Graphics Interchange Format 89a//EN", None)])
Ezio Melottib3aedd42010-11-20 19:04:17 +0000981 self.assertEqual(handler._entities, [("img", None, "expat.gif", "GIF")])
Lars Gustäbel2fc52942000-10-24 15:35:07 +0000982
Christian Heimes17b1d5d2018-09-23 09:50:25 +0200983 def test_expat_external_dtd_enabled(self):
Victor Stinner7cb92042019-07-02 14:50:19 +0200984 # clear _opener global variable
985 self.addCleanup(urllib.request.urlcleanup)
986
Christian Heimes17b1d5d2018-09-23 09:50:25 +0200987 parser = create_parser()
988 parser.setFeature(feature_external_ges, True)
989 resolver = self.TestEntityRecorder()
990 parser.setEntityResolver(resolver)
991
992 with self.assertRaises(URLError):
993 parser.feed(
994 '<!DOCTYPE external SYSTEM "unsupported://non-existing">\n'
995 )
996 self.assertEqual(
997 resolver.entities, [(None, 'unsupported://non-existing')]
998 )
999
1000 def test_expat_external_dtd_default(self):
1001 parser = create_parser()
1002 resolver = self.TestEntityRecorder()
1003 parser.setEntityResolver(resolver)
1004
1005 parser.feed(
1006 '<!DOCTYPE external SYSTEM "unsupported://non-existing">\n'
1007 )
1008 parser.feed('<doc />')
1009 parser.close()
1010 self.assertEqual(resolver.entities, [])
1011
Guido van Rossumd8faa362007-04-27 19:54:29 +00001012 # ===== EntityResolver support
Lars Gustäbel2fc52942000-10-24 15:35:07 +00001013
Guido van Rossumd8faa362007-04-27 19:54:29 +00001014 class TestEntityResolver:
Lars Gustäbel2fc52942000-10-24 15:35:07 +00001015
Guido van Rossumd8faa362007-04-27 19:54:29 +00001016 def resolveEntity(self, publicId, systemId):
1017 inpsrc = InputSource()
Serhiy Storchaka88efc522013-02-10 14:29:52 +02001018 inpsrc.setByteStream(BytesIO(b"<entity/>"))
Guido van Rossumd8faa362007-04-27 19:54:29 +00001019 return inpsrc
Lars Gustäbel2fc52942000-10-24 15:35:07 +00001020
Christian Heimes17b1d5d2018-09-23 09:50:25 +02001021 def test_expat_entityresolver_enabled(self):
Guido van Rossumd8faa362007-04-27 19:54:29 +00001022 parser = create_parser()
Christian Heimes17b1d5d2018-09-23 09:50:25 +02001023 parser.setFeature(feature_external_ges, True)
Guido van Rossumd8faa362007-04-27 19:54:29 +00001024 parser.setEntityResolver(self.TestEntityResolver())
Serhiy Storchaka88efc522013-02-10 14:29:52 +02001025 result = BytesIO()
Guido van Rossumd8faa362007-04-27 19:54:29 +00001026 parser.setContentHandler(XMLGenerator(result))
Lars Gustäbel2fc52942000-10-24 15:35:07 +00001027
Guido van Rossumd8faa362007-04-27 19:54:29 +00001028 parser.feed('<!DOCTYPE doc [\n')
1029 parser.feed(' <!ENTITY test SYSTEM "whatever">\n')
1030 parser.feed(']>\n')
1031 parser.feed('<doc>&test;</doc>')
1032 parser.close()
Lars Gustäbel2fc52942000-10-24 15:35:07 +00001033
Ezio Melottib3aedd42010-11-20 19:04:17 +00001034 self.assertEqual(result.getvalue(), start +
Serhiy Storchaka88efc522013-02-10 14:29:52 +02001035 b"<doc><entity></entity></doc>")
Lars Gustäbel2fc52942000-10-24 15:35:07 +00001036
Christian Heimes17b1d5d2018-09-23 09:50:25 +02001037 def test_expat_entityresolver_default(self):
1038 parser = create_parser()
1039 self.assertEqual(parser.getFeature(feature_external_ges), False)
1040 parser.setEntityResolver(self.TestEntityResolver())
1041 result = BytesIO()
1042 parser.setContentHandler(XMLGenerator(result))
1043
1044 parser.feed('<!DOCTYPE doc [\n')
1045 parser.feed(' <!ENTITY test SYSTEM "whatever">\n')
1046 parser.feed(']>\n')
1047 parser.feed('<doc>&test;</doc>')
1048 parser.close()
1049
1050 self.assertEqual(result.getvalue(), start +
1051 b"<doc></doc>")
1052
Guido van Rossumd8faa362007-04-27 19:54:29 +00001053 # ===== Attributes support
Lars Gustäbel2fc52942000-10-24 15:35:07 +00001054
Guido van Rossumd8faa362007-04-27 19:54:29 +00001055 class AttrGatherer(ContentHandler):
Lars Gustäbel2fc52942000-10-24 15:35:07 +00001056
Guido van Rossumd8faa362007-04-27 19:54:29 +00001057 def startElement(self, name, attrs):
1058 self._attrs = attrs
Lars Gustäbel2fc52942000-10-24 15:35:07 +00001059
Guido van Rossumd8faa362007-04-27 19:54:29 +00001060 def startElementNS(self, name, qname, attrs):
1061 self._attrs = attrs
Lars Gustäbel2fc52942000-10-24 15:35:07 +00001062
Guido van Rossumd8faa362007-04-27 19:54:29 +00001063 def test_expat_attrs_empty(self):
1064 parser = create_parser()
1065 gather = self.AttrGatherer()
1066 parser.setContentHandler(gather)
1067
1068 parser.feed("<doc/>")
1069 parser.close()
1070
1071 self.verify_empty_attrs(gather._attrs)
1072
1073 def test_expat_attrs_wattr(self):
1074 parser = create_parser()
1075 gather = self.AttrGatherer()
1076 parser.setContentHandler(gather)
1077
1078 parser.feed("<doc attr='val'/>")
1079 parser.close()
1080
1081 self.verify_attrs_wattr(gather._attrs)
1082
1083 def test_expat_nsattrs_empty(self):
1084 parser = create_parser(1)
1085 gather = self.AttrGatherer()
1086 parser.setContentHandler(gather)
1087
1088 parser.feed("<doc/>")
1089 parser.close()
1090
1091 self.verify_empty_nsattrs(gather._attrs)
1092
1093 def test_expat_nsattrs_wattr(self):
1094 parser = create_parser(1)
1095 gather = self.AttrGatherer()
1096 parser.setContentHandler(gather)
1097
1098 parser.feed("<doc xmlns:ns='%s' ns:attr='val'/>" % ns_uri)
1099 parser.close()
1100
1101 attrs = gather._attrs
1102
Ezio Melottib3aedd42010-11-20 19:04:17 +00001103 self.assertEqual(attrs.getLength(), 1)
1104 self.assertEqual(attrs.getNames(), [(ns_uri, "attr")])
Guido van Rossumd8faa362007-04-27 19:54:29 +00001105 self.assertTrue((attrs.getQNames() == [] or
1106 attrs.getQNames() == ["ns:attr"]))
Ezio Melottib3aedd42010-11-20 19:04:17 +00001107 self.assertEqual(len(attrs), 1)
Benjamin Peterson577473f2010-01-19 00:09:57 +00001108 self.assertIn((ns_uri, "attr"), attrs)
Ezio Melottib3aedd42010-11-20 19:04:17 +00001109 self.assertEqual(attrs.get((ns_uri, "attr")), "val")
1110 self.assertEqual(attrs.get((ns_uri, "attr"), 25), "val")
1111 self.assertEqual(list(attrs.items()), [((ns_uri, "attr"), "val")])
1112 self.assertEqual(list(attrs.values()), ["val"])
1113 self.assertEqual(attrs.getValue((ns_uri, "attr")), "val")
1114 self.assertEqual(attrs[(ns_uri, "attr")], "val")
Guido van Rossumd8faa362007-04-27 19:54:29 +00001115
1116 # ===== InputSource support
1117
Benjamin Petersona7f4f5a2008-09-04 02:22:52 +00001118 def test_expat_inpsource_filename(self):
Guido van Rossumd8faa362007-04-27 19:54:29 +00001119 parser = create_parser()
Serhiy Storchaka88efc522013-02-10 14:29:52 +02001120 result = BytesIO()
Guido van Rossumd8faa362007-04-27 19:54:29 +00001121 xmlgen = XMLGenerator(result)
1122
1123 parser.setContentHandler(xmlgen)
Florent Xiclunaf15351d2010-03-13 23:24:31 +00001124 parser.parse(TEST_XMLFILE)
Guido van Rossumd8faa362007-04-27 19:54:29 +00001125
Ezio Melottib3aedd42010-11-20 19:04:17 +00001126 self.assertEqual(result.getvalue(), xml_test_out)
Guido van Rossumd8faa362007-04-27 19:54:29 +00001127
Benjamin Petersona7f4f5a2008-09-04 02:22:52 +00001128 def test_expat_inpsource_sysid(self):
Guido van Rossumd8faa362007-04-27 19:54:29 +00001129 parser = create_parser()
Serhiy Storchaka88efc522013-02-10 14:29:52 +02001130 result = BytesIO()
Guido van Rossumd8faa362007-04-27 19:54:29 +00001131 xmlgen = XMLGenerator(result)
1132
1133 parser.setContentHandler(xmlgen)
Florent Xiclunaf15351d2010-03-13 23:24:31 +00001134 parser.parse(InputSource(TEST_XMLFILE))
Guido van Rossumd8faa362007-04-27 19:54:29 +00001135
Ezio Melottib3aedd42010-11-20 19:04:17 +00001136 self.assertEqual(result.getvalue(), xml_test_out)
Guido van Rossumd8faa362007-04-27 19:54:29 +00001137
Serhiy Storchaka1a4ed4c2013-02-02 12:17:05 +02001138 @requires_nonascii_filenames
Serhiy Storchakad5202392013-02-02 10:31:17 +02001139 def test_expat_inpsource_sysid_nonascii(self):
1140 fname = support.TESTFN_UNICODE
1141 shutil.copyfile(TEST_XMLFILE, fname)
1142 self.addCleanup(support.unlink, fname)
1143
1144 parser = create_parser()
Serhiy Storchaka88efc522013-02-10 14:29:52 +02001145 result = BytesIO()
Serhiy Storchakad5202392013-02-02 10:31:17 +02001146 xmlgen = XMLGenerator(result)
1147
1148 parser.setContentHandler(xmlgen)
1149 parser.parse(InputSource(fname))
1150
1151 self.assertEqual(result.getvalue(), xml_test_out)
1152
Serhiy Storchakaaa9563c2015-04-02 20:55:59 +03001153 def test_expat_inpsource_byte_stream(self):
Guido van Rossumd8faa362007-04-27 19:54:29 +00001154 parser = create_parser()
Serhiy Storchaka88efc522013-02-10 14:29:52 +02001155 result = BytesIO()
Guido van Rossumd8faa362007-04-27 19:54:29 +00001156 xmlgen = XMLGenerator(result)
1157
1158 parser.setContentHandler(xmlgen)
1159 inpsrc = InputSource()
Serhiy Storchaka88efc522013-02-10 14:29:52 +02001160 with open(TEST_XMLFILE, 'rb') as f:
Benjamin Petersond5df36d2010-10-31 18:23:23 +00001161 inpsrc.setByteStream(f)
1162 parser.parse(inpsrc)
Guido van Rossumd8faa362007-04-27 19:54:29 +00001163
Ezio Melottib3aedd42010-11-20 19:04:17 +00001164 self.assertEqual(result.getvalue(), xml_test_out)
Guido van Rossumd8faa362007-04-27 19:54:29 +00001165
Serhiy Storchaka61de0872015-04-02 21:00:13 +03001166 def test_expat_inpsource_character_stream(self):
1167 parser = create_parser()
1168 result = BytesIO()
1169 xmlgen = XMLGenerator(result)
1170
1171 parser.setContentHandler(xmlgen)
1172 inpsrc = InputSource()
1173 with open(TEST_XMLFILE, 'rt', encoding='iso-8859-1') as f:
1174 inpsrc.setCharacterStream(f)
1175 parser.parse(inpsrc)
1176
1177 self.assertEqual(result.getvalue(), xml_test_out)
1178
Guido van Rossumd8faa362007-04-27 19:54:29 +00001179 # ===== IncrementalParser support
1180
1181 def test_expat_incremental(self):
Serhiy Storchaka88efc522013-02-10 14:29:52 +02001182 result = BytesIO()
Guido van Rossumd8faa362007-04-27 19:54:29 +00001183 xmlgen = XMLGenerator(result)
1184 parser = create_parser()
1185 parser.setContentHandler(xmlgen)
1186
1187 parser.feed("<doc>")
1188 parser.feed("</doc>")
1189 parser.close()
1190
Serhiy Storchaka88efc522013-02-10 14:29:52 +02001191 self.assertEqual(result.getvalue(), start + b"<doc></doc>")
Guido van Rossumd8faa362007-04-27 19:54:29 +00001192
1193 def test_expat_incremental_reset(self):
Serhiy Storchaka88efc522013-02-10 14:29:52 +02001194 result = BytesIO()
Guido van Rossumd8faa362007-04-27 19:54:29 +00001195 xmlgen = XMLGenerator(result)
1196 parser = create_parser()
1197 parser.setContentHandler(xmlgen)
1198
1199 parser.feed("<doc>")
1200 parser.feed("text")
1201
Serhiy Storchaka88efc522013-02-10 14:29:52 +02001202 result = BytesIO()
Guido van Rossumd8faa362007-04-27 19:54:29 +00001203 xmlgen = XMLGenerator(result)
1204 parser.setContentHandler(xmlgen)
1205 parser.reset()
1206
1207 parser.feed("<doc>")
1208 parser.feed("text")
1209 parser.feed("</doc>")
1210 parser.close()
1211
Serhiy Storchaka88efc522013-02-10 14:29:52 +02001212 self.assertEqual(result.getvalue(), start + b"<doc>text</doc>")
Guido van Rossumd8faa362007-04-27 19:54:29 +00001213
1214 # ===== Locator support
1215
1216 def test_expat_locator_noinfo(self):
Serhiy Storchaka88efc522013-02-10 14:29:52 +02001217 result = BytesIO()
Guido van Rossumd8faa362007-04-27 19:54:29 +00001218 xmlgen = XMLGenerator(result)
1219 parser = create_parser()
1220 parser.setContentHandler(xmlgen)
1221
1222 parser.feed("<doc>")
1223 parser.feed("</doc>")
1224 parser.close()
1225
Ezio Melottib3aedd42010-11-20 19:04:17 +00001226 self.assertEqual(parser.getSystemId(), None)
1227 self.assertEqual(parser.getPublicId(), None)
1228 self.assertEqual(parser.getLineNumber(), 1)
Guido van Rossumd8faa362007-04-27 19:54:29 +00001229
Benjamin Petersona7f4f5a2008-09-04 02:22:52 +00001230 def test_expat_locator_withinfo(self):
Serhiy Storchaka88efc522013-02-10 14:29:52 +02001231 result = BytesIO()
Guido van Rossumd8faa362007-04-27 19:54:29 +00001232 xmlgen = XMLGenerator(result)
1233 parser = create_parser()
1234 parser.setContentHandler(xmlgen)
Florent Xiclunaf15351d2010-03-13 23:24:31 +00001235 parser.parse(TEST_XMLFILE)
Guido van Rossumd8faa362007-04-27 19:54:29 +00001236
Ezio Melottib3aedd42010-11-20 19:04:17 +00001237 self.assertEqual(parser.getSystemId(), TEST_XMLFILE)
1238 self.assertEqual(parser.getPublicId(), None)
Lars Gustäbel2fc52942000-10-24 15:35:07 +00001239
Serhiy Storchaka1a4ed4c2013-02-02 12:17:05 +02001240 @requires_nonascii_filenames
Serhiy Storchakad5202392013-02-02 10:31:17 +02001241 def test_expat_locator_withinfo_nonascii(self):
1242 fname = support.TESTFN_UNICODE
1243 shutil.copyfile(TEST_XMLFILE, fname)
1244 self.addCleanup(support.unlink, fname)
1245
Serhiy Storchaka88efc522013-02-10 14:29:52 +02001246 result = BytesIO()
Serhiy Storchakad5202392013-02-02 10:31:17 +02001247 xmlgen = XMLGenerator(result)
1248 parser = create_parser()
1249 parser.setContentHandler(xmlgen)
1250 parser.parse(fname)
1251
1252 self.assertEqual(parser.getSystemId(), fname)
1253 self.assertEqual(parser.getPublicId(), None)
1254
Martin v. Löwis80670bc2000-10-06 21:13:23 +00001255
1256# ===========================================================================
1257#
1258# error reporting
1259#
1260# ===========================================================================
1261
Guido van Rossumd8faa362007-04-27 19:54:29 +00001262class ErrorReportingTest(unittest.TestCase):
1263 def test_expat_inpsource_location(self):
1264 parser = create_parser()
1265 parser.setContentHandler(ContentHandler()) # do nothing
1266 source = InputSource()
Serhiy Storchaka88efc522013-02-10 14:29:52 +02001267 source.setByteStream(BytesIO(b"<foo bar foobar>")) #ill-formed
Guido van Rossumd8faa362007-04-27 19:54:29 +00001268 name = "a file name"
1269 source.setSystemId(name)
1270 try:
1271 parser.parse(source)
1272 self.fail()
1273 except SAXException as e:
Ezio Melottib3aedd42010-11-20 19:04:17 +00001274 self.assertEqual(e.getSystemId(), name)
Martin v. Löwis80670bc2000-10-06 21:13:23 +00001275
Guido van Rossumd8faa362007-04-27 19:54:29 +00001276 def test_expat_incomplete(self):
1277 parser = create_parser()
1278 parser.setContentHandler(ContentHandler()) # do nothing
1279 self.assertRaises(SAXParseException, parser.parse, StringIO("<foo>"))
Serhiy Storchakaab914782015-05-06 09:36:06 +03001280 self.assertEqual(parser.getColumnNumber(), 5)
1281 self.assertEqual(parser.getLineNumber(), 1)
Martin v. Löwis80670bc2000-10-06 21:13:23 +00001282
Guido van Rossumd8faa362007-04-27 19:54:29 +00001283 def test_sax_parse_exception_str(self):
1284 # pass various values from a locator to the SAXParseException to
1285 # make sure that the __str__() doesn't fall apart when None is
1286 # passed instead of an integer line and column number
1287 #
1288 # use "normal" values for the locator:
1289 str(SAXParseException("message", None,
1290 self.DummyLocator(1, 1)))
1291 # use None for the line number:
1292 str(SAXParseException("message", None,
1293 self.DummyLocator(None, 1)))
1294 # use None for the column number:
1295 str(SAXParseException("message", None,
1296 self.DummyLocator(1, None)))
1297 # use None for both:
1298 str(SAXParseException("message", None,
1299 self.DummyLocator(None, None)))
Fred Drake6fd0b0d2004-03-20 08:15:30 +00001300
Guido van Rossumd8faa362007-04-27 19:54:29 +00001301 class DummyLocator:
1302 def __init__(self, lineno, colno):
1303 self._lineno = lineno
1304 self._colno = colno
Fred Drake6fd0b0d2004-03-20 08:15:30 +00001305
Guido van Rossumd8faa362007-04-27 19:54:29 +00001306 def getPublicId(self):
1307 return "pubid"
Fred Drake6fd0b0d2004-03-20 08:15:30 +00001308
Guido van Rossumd8faa362007-04-27 19:54:29 +00001309 def getSystemId(self):
1310 return "sysid"
Fred Drake6fd0b0d2004-03-20 08:15:30 +00001311
Guido van Rossumd8faa362007-04-27 19:54:29 +00001312 def getLineNumber(self):
1313 return self._lineno
Fred Drake6fd0b0d2004-03-20 08:15:30 +00001314
Guido van Rossumd8faa362007-04-27 19:54:29 +00001315 def getColumnNumber(self):
1316 return self._colno
Martin v. Löwis80670bc2000-10-06 21:13:23 +00001317
Lars Gustäbelab647872000-09-24 18:40:52 +00001318# ===========================================================================
1319#
1320# xmlreader tests
1321#
1322# ===========================================================================
1323
Guido van Rossumd8faa362007-04-27 19:54:29 +00001324class XmlReaderTest(XmlTestBase):
Lars Gustäbelab647872000-09-24 18:40:52 +00001325
Guido van Rossumd8faa362007-04-27 19:54:29 +00001326 # ===== AttributesImpl
1327 def test_attrs_empty(self):
1328 self.verify_empty_attrs(AttributesImpl({}))
Lars Gustäbelab647872000-09-24 18:40:52 +00001329
Guido van Rossumd8faa362007-04-27 19:54:29 +00001330 def test_attrs_wattr(self):
1331 self.verify_attrs_wattr(AttributesImpl({"attr" : "val"}))
Lars Gustäbelab647872000-09-24 18:40:52 +00001332
Guido van Rossumd8faa362007-04-27 19:54:29 +00001333 def test_nsattrs_empty(self):
1334 self.verify_empty_nsattrs(AttributesNSImpl({}, {}))
Lars Gustäbelab647872000-09-24 18:40:52 +00001335
Guido van Rossumd8faa362007-04-27 19:54:29 +00001336 def test_nsattrs_wattr(self):
1337 attrs = AttributesNSImpl({(ns_uri, "attr") : "val"},
1338 {(ns_uri, "attr") : "ns:attr"})
Fred Drake004d5e62000-10-23 17:22:08 +00001339
Ezio Melottib3aedd42010-11-20 19:04:17 +00001340 self.assertEqual(attrs.getLength(), 1)
1341 self.assertEqual(attrs.getNames(), [(ns_uri, "attr")])
1342 self.assertEqual(attrs.getQNames(), ["ns:attr"])
1343 self.assertEqual(len(attrs), 1)
Benjamin Peterson577473f2010-01-19 00:09:57 +00001344 self.assertIn((ns_uri, "attr"), attrs)
Ezio Melottib3aedd42010-11-20 19:04:17 +00001345 self.assertEqual(list(attrs.keys()), [(ns_uri, "attr")])
1346 self.assertEqual(attrs.get((ns_uri, "attr")), "val")
1347 self.assertEqual(attrs.get((ns_uri, "attr"), 25), "val")
1348 self.assertEqual(list(attrs.items()), [((ns_uri, "attr"), "val")])
1349 self.assertEqual(list(attrs.values()), ["val"])
1350 self.assertEqual(attrs.getValue((ns_uri, "attr")), "val")
1351 self.assertEqual(attrs.getValueByQName("ns:attr"), "val")
1352 self.assertEqual(attrs.getNameByQName("ns:attr"), (ns_uri, "attr"))
1353 self.assertEqual(attrs[(ns_uri, "attr")], "val")
1354 self.assertEqual(attrs.getQNameByName((ns_uri, "attr")), "ns:attr")
Fred Drake004d5e62000-10-23 17:22:08 +00001355
Lars Gustäbelab647872000-09-24 18:40:52 +00001356
Christian Heimesbbe741d2008-03-28 10:53:29 +00001357def test_main():
Guido van Rossumd8faa362007-04-27 19:54:29 +00001358 run_unittest(MakeParserTest,
Serhiy Storchaka13e41c52015-04-02 23:05:57 +03001359 ParseTest,
Guido van Rossumd8faa362007-04-27 19:54:29 +00001360 SaxutilsTest,
Serhiy Storchakaaa9563c2015-04-02 20:55:59 +03001361 PrepareInputSourceTest,
Serhiy Storchaka88efc522013-02-10 14:29:52 +02001362 StringXmlgenTest,
1363 BytesXmlgenTest,
1364 WriterXmlgenTest,
Georg Brandlc502df42013-05-12 11:41:12 +02001365 StreamWriterXmlgenTest,
1366 StreamReaderWriterXmlgenTest,
Guido van Rossumd8faa362007-04-27 19:54:29 +00001367 ExpatReaderTest,
1368 ErrorReportingTest,
1369 XmlReaderTest)
Lars Gustäbelb7536d52000-09-24 18:53:56 +00001370
Guido van Rossumd8faa362007-04-27 19:54:29 +00001371if __name__ == "__main__":
Christian Heimesbbe741d2008-03-28 10:53:29 +00001372 test_main()