blob: ce3a422b502a06dd9df1a872b6c12a7601ac9b90 [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
Christian Heimes17b1d5d2018-09-23 09:50:25 +020022from urllib.error import URLError
Victor Stinner7cb92042019-07-02 14:50:19 +020023import urllib.request
Serhiy Storchakad5202392013-02-02 10:31:17 +020024from test import support
Mickaël Schoentgen929b7042019-04-14 09:16:54 +000025from test.support import findfile, run_unittest, FakePath, TESTFN
Florent Xiclunaf15351d2010-03-13 23:24:31 +000026
27TEST_XMLFILE = findfile("test.xml", subdir="xmltestdata")
28TEST_XMLFILE_OUT = findfile("test.xml.out", subdir="xmltestdata")
Victor Stinner6c6f8512010-08-07 10:09:35 +000029try:
Marc-André Lemburg8f36af72011-02-25 15:42:01 +000030 TEST_XMLFILE.encode("utf-8")
31 TEST_XMLFILE_OUT.encode("utf-8")
Victor Stinner6c6f8512010-08-07 10:09:35 +000032except UnicodeEncodeError:
33 raise unittest.SkipTest("filename is not encodable to utf8")
Lars Gustäbel96753b32000-09-24 12:24:24 +000034
Serhiy Storchaka1a4ed4c2013-02-02 12:17:05 +020035supports_nonascii_filenames = True
36if not os.path.supports_unicode_filenames:
37 try:
38 support.TESTFN_UNICODE.encode(support.TESTFN_ENCODING)
39 except (UnicodeError, TypeError):
40 # Either the file system encoding is None, or the file name
41 # cannot be encoded in the file system encoding.
42 supports_nonascii_filenames = False
43requires_nonascii_filenames = unittest.skipUnless(
44 supports_nonascii_filenames,
45 'Requires non-ascii filenames support')
46
Guido van Rossumd8faa362007-04-27 19:54:29 +000047ns_uri = "http://www.python.org/xml-ns/saxtest/"
Lars Gustäbel96753b32000-09-24 12:24:24 +000048
Guido van Rossumd8faa362007-04-27 19:54:29 +000049class XmlTestBase(unittest.TestCase):
50 def verify_empty_attrs(self, attrs):
51 self.assertRaises(KeyError, attrs.getValue, "attr")
52 self.assertRaises(KeyError, attrs.getValueByQName, "attr")
53 self.assertRaises(KeyError, attrs.getNameByQName, "attr")
54 self.assertRaises(KeyError, attrs.getQNameByName, "attr")
55 self.assertRaises(KeyError, attrs.__getitem__, "attr")
Ezio Melottib3aedd42010-11-20 19:04:17 +000056 self.assertEqual(attrs.getLength(), 0)
57 self.assertEqual(attrs.getNames(), [])
58 self.assertEqual(attrs.getQNames(), [])
59 self.assertEqual(len(attrs), 0)
Ezio Melottib58e0bd2010-01-23 15:40:09 +000060 self.assertNotIn("attr", attrs)
Ezio Melottib3aedd42010-11-20 19:04:17 +000061 self.assertEqual(list(attrs.keys()), [])
62 self.assertEqual(attrs.get("attrs"), None)
63 self.assertEqual(attrs.get("attrs", 25), 25)
64 self.assertEqual(list(attrs.items()), [])
65 self.assertEqual(list(attrs.values()), [])
Lars Gustäbel96753b32000-09-24 12:24:24 +000066
Guido van Rossumd8faa362007-04-27 19:54:29 +000067 def verify_empty_nsattrs(self, attrs):
68 self.assertRaises(KeyError, attrs.getValue, (ns_uri, "attr"))
69 self.assertRaises(KeyError, attrs.getValueByQName, "ns:attr")
70 self.assertRaises(KeyError, attrs.getNameByQName, "ns:attr")
71 self.assertRaises(KeyError, attrs.getQNameByName, (ns_uri, "attr"))
72 self.assertRaises(KeyError, attrs.__getitem__, (ns_uri, "attr"))
Ezio Melottib3aedd42010-11-20 19:04:17 +000073 self.assertEqual(attrs.getLength(), 0)
74 self.assertEqual(attrs.getNames(), [])
75 self.assertEqual(attrs.getQNames(), [])
76 self.assertEqual(len(attrs), 0)
Ezio Melottib58e0bd2010-01-23 15:40:09 +000077 self.assertNotIn((ns_uri, "attr"), attrs)
Ezio Melottib3aedd42010-11-20 19:04:17 +000078 self.assertEqual(list(attrs.keys()), [])
79 self.assertEqual(attrs.get((ns_uri, "attr")), None)
80 self.assertEqual(attrs.get((ns_uri, "attr"), 25), 25)
81 self.assertEqual(list(attrs.items()), [])
82 self.assertEqual(list(attrs.values()), [])
Lars Gustäbel96753b32000-09-24 12:24:24 +000083
Guido van Rossumd8faa362007-04-27 19:54:29 +000084 def verify_attrs_wattr(self, attrs):
Ezio Melottib3aedd42010-11-20 19:04:17 +000085 self.assertEqual(attrs.getLength(), 1)
86 self.assertEqual(attrs.getNames(), ["attr"])
87 self.assertEqual(attrs.getQNames(), ["attr"])
88 self.assertEqual(len(attrs), 1)
Benjamin Peterson577473f2010-01-19 00:09:57 +000089 self.assertIn("attr", attrs)
Ezio Melottib3aedd42010-11-20 19:04:17 +000090 self.assertEqual(list(attrs.keys()), ["attr"])
91 self.assertEqual(attrs.get("attr"), "val")
92 self.assertEqual(attrs.get("attr", 25), "val")
93 self.assertEqual(list(attrs.items()), [("attr", "val")])
94 self.assertEqual(list(attrs.values()), ["val"])
95 self.assertEqual(attrs.getValue("attr"), "val")
96 self.assertEqual(attrs.getValueByQName("attr"), "val")
97 self.assertEqual(attrs.getNameByQName("attr"), "attr")
98 self.assertEqual(attrs["attr"], "val")
99 self.assertEqual(attrs.getQNameByName("attr"), "attr")
Lars Gustäbel96753b32000-09-24 12:24:24 +0000100
Serhiy Storchaka13e41c52015-04-02 23:05:57 +0300101
102def xml_str(doc, encoding=None):
103 if encoding is None:
104 return doc
105 return '<?xml version="1.0" encoding="%s"?>\n%s' % (encoding, doc)
106
107def xml_bytes(doc, encoding, decl_encoding=...):
108 if decl_encoding is ...:
109 decl_encoding = encoding
110 return xml_str(doc, decl_encoding).encode(encoding, 'xmlcharrefreplace')
111
112def make_xml_file(doc, encoding, decl_encoding=...):
113 if decl_encoding is ...:
114 decl_encoding = encoding
115 with open(TESTFN, 'w', encoding=encoding, errors='xmlcharrefreplace') as f:
116 f.write(xml_str(doc, decl_encoding))
117
118
119class ParseTest(unittest.TestCase):
120 data = '<money value="$\xa3\u20ac\U0001017b">$\xa3\u20ac\U0001017b</money>'
121
122 def tearDown(self):
123 support.unlink(TESTFN)
124
125 def check_parse(self, f):
126 from xml.sax import parse
127 result = StringIO()
128 parse(f, XMLGenerator(result, 'utf-8'))
129 self.assertEqual(result.getvalue(), xml_str(self.data, 'utf-8'))
130
131 def test_parse_text(self):
132 encodings = ('us-ascii', 'iso-8859-1', 'utf-8',
133 'utf-16', 'utf-16le', 'utf-16be')
134 for encoding in encodings:
135 self.check_parse(StringIO(xml_str(self.data, encoding)))
136 make_xml_file(self.data, encoding)
137 with open(TESTFN, 'r', encoding=encoding) as f:
138 self.check_parse(f)
139 self.check_parse(StringIO(self.data))
140 make_xml_file(self.data, encoding, None)
141 with open(TESTFN, 'r', encoding=encoding) as f:
142 self.check_parse(f)
143
144 def test_parse_bytes(self):
145 # UTF-8 is default encoding, US-ASCII is compatible with UTF-8,
146 # UTF-16 is autodetected
147 encodings = ('us-ascii', 'utf-8', 'utf-16', 'utf-16le', 'utf-16be')
148 for encoding in encodings:
149 self.check_parse(BytesIO(xml_bytes(self.data, encoding)))
150 make_xml_file(self.data, encoding)
151 self.check_parse(TESTFN)
152 with open(TESTFN, 'rb') as f:
153 self.check_parse(f)
154 self.check_parse(BytesIO(xml_bytes(self.data, encoding, None)))
155 make_xml_file(self.data, encoding, None)
156 self.check_parse(TESTFN)
157 with open(TESTFN, 'rb') as f:
158 self.check_parse(f)
159 # accept UTF-8 with BOM
160 self.check_parse(BytesIO(xml_bytes(self.data, 'utf-8-sig', 'utf-8')))
161 make_xml_file(self.data, 'utf-8-sig', 'utf-8')
162 self.check_parse(TESTFN)
163 with open(TESTFN, 'rb') as f:
164 self.check_parse(f)
165 self.check_parse(BytesIO(xml_bytes(self.data, 'utf-8-sig', None)))
166 make_xml_file(self.data, 'utf-8-sig', None)
167 self.check_parse(TESTFN)
168 with open(TESTFN, 'rb') as f:
169 self.check_parse(f)
170 # accept data with declared encoding
171 self.check_parse(BytesIO(xml_bytes(self.data, 'iso-8859-1')))
172 make_xml_file(self.data, 'iso-8859-1')
173 self.check_parse(TESTFN)
174 with open(TESTFN, 'rb') as f:
175 self.check_parse(f)
176 # fail on non-UTF-8 incompatible data without declared encoding
177 with self.assertRaises(SAXException):
178 self.check_parse(BytesIO(xml_bytes(self.data, 'iso-8859-1', None)))
179 make_xml_file(self.data, 'iso-8859-1', None)
Victor Stinneref9c0e72017-05-05 09:46:47 +0200180 with self.assertRaises(SAXException):
181 self.check_parse(TESTFN)
Serhiy Storchaka13e41c52015-04-02 23:05:57 +0300182 with open(TESTFN, 'rb') as f:
183 with self.assertRaises(SAXException):
184 self.check_parse(f)
185
Mickaël Schoentgen929b7042019-04-14 09:16:54 +0000186 def test_parse_path_object(self):
187 make_xml_file(self.data, 'utf-8', None)
188 self.check_parse(FakePath(TESTFN))
189
Serhiy Storchaka13e41c52015-04-02 23:05:57 +0300190 def test_parse_InputSource(self):
191 # accept data without declared but with explicitly specified encoding
192 make_xml_file(self.data, 'iso-8859-1', None)
193 with open(TESTFN, 'rb') as f:
194 input = InputSource()
195 input.setByteStream(f)
196 input.setEncoding('iso-8859-1')
197 self.check_parse(input)
198
Victor Stinneref9c0e72017-05-05 09:46:47 +0200199 def test_parse_close_source(self):
200 builtin_open = open
201 fileobj = None
202
203 def mock_open(*args):
204 nonlocal fileobj
205 fileobj = builtin_open(*args)
206 return fileobj
207
208 with mock.patch('xml.sax.saxutils.open', side_effect=mock_open):
209 make_xml_file(self.data, 'iso-8859-1', None)
210 with self.assertRaises(SAXException):
211 self.check_parse(TESTFN)
212 self.assertTrue(fileobj.closed)
213
Serhiy Storchaka13e41c52015-04-02 23:05:57 +0300214 def check_parseString(self, s):
215 from xml.sax import parseString
216 result = StringIO()
217 parseString(s, XMLGenerator(result, 'utf-8'))
218 self.assertEqual(result.getvalue(), xml_str(self.data, 'utf-8'))
219
Serhiy Storchaka778db282015-04-04 10:12:26 +0300220 def test_parseString_text(self):
221 encodings = ('us-ascii', 'iso-8859-1', 'utf-8',
222 'utf-16', 'utf-16le', 'utf-16be')
223 for encoding in encodings:
224 self.check_parseString(xml_str(self.data, encoding))
225 self.check_parseString(self.data)
226
Serhiy Storchaka13e41c52015-04-02 23:05:57 +0300227 def test_parseString_bytes(self):
228 # UTF-8 is default encoding, US-ASCII is compatible with UTF-8,
229 # UTF-16 is autodetected
230 encodings = ('us-ascii', 'utf-8', 'utf-16', 'utf-16le', 'utf-16be')
231 for encoding in encodings:
232 self.check_parseString(xml_bytes(self.data, encoding))
233 self.check_parseString(xml_bytes(self.data, encoding, None))
234 # accept UTF-8 with BOM
235 self.check_parseString(xml_bytes(self.data, 'utf-8-sig', 'utf-8'))
236 self.check_parseString(xml_bytes(self.data, 'utf-8-sig', None))
237 # accept data with declared encoding
238 self.check_parseString(xml_bytes(self.data, 'iso-8859-1'))
239 # fail on non-UTF-8 incompatible data without declared encoding
240 with self.assertRaises(SAXException):
241 self.check_parseString(xml_bytes(self.data, 'iso-8859-1', None))
242
Guido van Rossumd8faa362007-04-27 19:54:29 +0000243class MakeParserTest(unittest.TestCase):
244 def test_make_parser2(self):
Lars Gustäbel2fc52942000-10-24 15:35:07 +0000245 # Creating parsers several times in a row should succeed.
246 # Testing this because there have been failures of this kind
247 # before.
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000248 from xml.sax import make_parser
Lars Gustäbel2fc52942000-10-24 15:35:07 +0000249 p = make_parser()
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000250 from xml.sax import make_parser
Lars Gustäbel2fc52942000-10-24 15:35:07 +0000251 p = make_parser()
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000252 from xml.sax import make_parser
Lars Gustäbel2fc52942000-10-24 15:35:07 +0000253 p = make_parser()
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000254 from xml.sax import make_parser
Lars Gustäbel2fc52942000-10-24 15:35:07 +0000255 p = make_parser()
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000256 from xml.sax import make_parser
Lars Gustäbel2fc52942000-10-24 15:35:07 +0000257 p = make_parser()
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000258 from xml.sax import make_parser
Lars Gustäbel2fc52942000-10-24 15:35:07 +0000259 p = make_parser()
Tim Petersd2bf3b72001-01-18 02:22:22 +0000260
Andrés Delfinoa6dc5312018-10-26 11:56:57 -0300261 def test_make_parser3(self):
262 # Testing that make_parser can handle different types of
263 # iterables.
264 make_parser(['module'])
265 make_parser(('module', ))
266 make_parser({'module'})
267 make_parser(frozenset({'module'}))
268 make_parser({'module': None})
269 make_parser(iter(['module']))
270
271 def test_make_parser4(self):
272 # Testing that make_parser can handle empty iterables.
273 make_parser([])
274 make_parser(tuple())
275 make_parser(set())
276 make_parser(frozenset())
277 make_parser({})
278 make_parser(iter([]))
279
280 def test_make_parser5(self):
281 # Testing that make_parser can handle iterables with more than
282 # one item.
283 make_parser(['module1', 'module2'])
284 make_parser(('module1', 'module2'))
285 make_parser({'module1', 'module2'})
286 make_parser(frozenset({'module1', 'module2'}))
287 make_parser({'module1': None, 'module2': None})
288 make_parser(iter(['module1', 'module2']))
Tim Petersd2bf3b72001-01-18 02:22:22 +0000289
Lars Gustäbel96753b32000-09-24 12:24:24 +0000290# ===========================================================================
291#
292# saxutils tests
293#
294# ===========================================================================
295
Guido van Rossumd8faa362007-04-27 19:54:29 +0000296class SaxutilsTest(unittest.TestCase):
297 # ===== escape
298 def test_escape_basic(self):
Ezio Melottib3aedd42010-11-20 19:04:17 +0000299 self.assertEqual(escape("Donald Duck & Co"), "Donald Duck &amp; Co")
Lars Gustäbel96753b32000-09-24 12:24:24 +0000300
Guido van Rossumd8faa362007-04-27 19:54:29 +0000301 def test_escape_all(self):
Ezio Melottib3aedd42010-11-20 19:04:17 +0000302 self.assertEqual(escape("<Donald Duck & Co>"),
303 "&lt;Donald Duck &amp; Co&gt;")
Lars Gustäbel96753b32000-09-24 12:24:24 +0000304
Guido van Rossumd8faa362007-04-27 19:54:29 +0000305 def test_escape_extra(self):
Ezio Melottib3aedd42010-11-20 19:04:17 +0000306 self.assertEqual(escape("Hei på deg", {"å" : "&aring;"}),
307 "Hei p&aring; deg")
Lars Gustäbel96753b32000-09-24 12:24:24 +0000308
Guido van Rossumd8faa362007-04-27 19:54:29 +0000309 # ===== unescape
310 def test_unescape_basic(self):
Ezio Melottib3aedd42010-11-20 19:04:17 +0000311 self.assertEqual(unescape("Donald Duck &amp; Co"), "Donald Duck & Co")
Lars Gustäbel96753b32000-09-24 12:24:24 +0000312
Guido van Rossumd8faa362007-04-27 19:54:29 +0000313 def test_unescape_all(self):
Ezio Melottib3aedd42010-11-20 19:04:17 +0000314 self.assertEqual(unescape("&lt;Donald Duck &amp; Co&gt;"),
315 "<Donald Duck & Co>")
Martin v. Löwis74b51ac2002-10-26 14:50:45 +0000316
Guido van Rossumd8faa362007-04-27 19:54:29 +0000317 def test_unescape_extra(self):
Ezio Melottib3aedd42010-11-20 19:04:17 +0000318 self.assertEqual(unescape("Hei på deg", {"å" : "&aring;"}),
319 "Hei p&aring; deg")
Martin v. Löwis74b51ac2002-10-26 14:50:45 +0000320
Guido van Rossumd8faa362007-04-27 19:54:29 +0000321 def test_unescape_amp_extra(self):
Ezio Melottib3aedd42010-11-20 19:04:17 +0000322 self.assertEqual(unescape("&amp;foo;", {"&foo;": "splat"}), "&foo;")
Martin v. Löwis74b51ac2002-10-26 14:50:45 +0000323
Guido van Rossumd8faa362007-04-27 19:54:29 +0000324 # ===== quoteattr
325 def test_quoteattr_basic(self):
Ezio Melottib3aedd42010-11-20 19:04:17 +0000326 self.assertEqual(quoteattr("Donald Duck & Co"),
327 '"Donald Duck &amp; Co"')
Martin v. Löwis74b51ac2002-10-26 14:50:45 +0000328
Guido van Rossumd8faa362007-04-27 19:54:29 +0000329 def test_single_quoteattr(self):
Ezio Melottib3aedd42010-11-20 19:04:17 +0000330 self.assertEqual(quoteattr('Includes "double" quotes'),
331 '\'Includes "double" quotes\'')
Fred Drake32f3add2002-10-28 17:58:48 +0000332
Guido van Rossumd8faa362007-04-27 19:54:29 +0000333 def test_double_quoteattr(self):
Ezio Melottib3aedd42010-11-20 19:04:17 +0000334 self.assertEqual(quoteattr("Includes 'single' quotes"),
335 "\"Includes 'single' quotes\"")
Fred Drakeacd32d32001-07-19 16:10:15 +0000336
Guido van Rossumd8faa362007-04-27 19:54:29 +0000337 def test_single_double_quoteattr(self):
Ezio Melottib3aedd42010-11-20 19:04:17 +0000338 self.assertEqual(quoteattr("Includes 'single' and \"double\" quotes"),
339 "\"Includes 'single' and &quot;double&quot; quotes\"")
Fred Drakeacd32d32001-07-19 16:10:15 +0000340
Guido van Rossumd8faa362007-04-27 19:54:29 +0000341 # ===== make_parser
342 def test_make_parser(self):
Martin v. Löwis962c9e72000-10-06 17:41:52 +0000343 # Creating a parser should succeed - it should fall back
344 # to the expatreader
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000345 p = make_parser(['xml.parsers.no_such_parser'])
Martin v. Löwis962c9e72000-10-06 17:41:52 +0000346
347
Serhiy Storchakaaa9563c2015-04-02 20:55:59 +0300348class PrepareInputSourceTest(unittest.TestCase):
349
350 def setUp(self):
351 self.file = support.TESTFN
352 with open(self.file, "w") as tmp:
353 tmp.write("This was read from a file.")
354
355 def tearDown(self):
356 support.unlink(self.file)
357
358 def make_byte_stream(self):
359 return BytesIO(b"This is a byte stream.")
360
Serhiy Storchaka61de0872015-04-02 21:00:13 +0300361 def make_character_stream(self):
362 return StringIO("This is a character stream.")
363
Serhiy Storchakaaa9563c2015-04-02 20:55:59 +0300364 def checkContent(self, stream, content):
365 self.assertIsNotNone(stream)
366 self.assertEqual(stream.read(), content)
367 stream.close()
368
369
Serhiy Storchaka61de0872015-04-02 21:00:13 +0300370 def test_character_stream(self):
371 # If the source is an InputSource with a character stream, use it.
372 src = InputSource(self.file)
373 src.setCharacterStream(self.make_character_stream())
374 prep = prepare_input_source(src)
375 self.assertIsNone(prep.getByteStream())
376 self.checkContent(prep.getCharacterStream(),
377 "This is a character stream.")
378
Serhiy Storchakaaa9563c2015-04-02 20:55:59 +0300379 def test_byte_stream(self):
380 # If the source is an InputSource that does not have a character
381 # stream but does have a byte stream, use the byte stream.
382 src = InputSource(self.file)
383 src.setByteStream(self.make_byte_stream())
384 prep = prepare_input_source(src)
385 self.assertIsNone(prep.getCharacterStream())
386 self.checkContent(prep.getByteStream(),
387 b"This is a byte stream.")
388
389 def test_system_id(self):
390 # If the source is an InputSource that has neither a character
391 # stream nor a byte stream, open the system ID.
392 src = InputSource(self.file)
393 prep = prepare_input_source(src)
394 self.assertIsNone(prep.getCharacterStream())
395 self.checkContent(prep.getByteStream(),
396 b"This was read from a file.")
397
398 def test_string(self):
399 # If the source is a string, use it as a system ID and open it.
400 prep = prepare_input_source(self.file)
401 self.assertIsNone(prep.getCharacterStream())
402 self.checkContent(prep.getByteStream(),
403 b"This was read from a file.")
404
Mickaël Schoentgen929b7042019-04-14 09:16:54 +0000405 def test_path_objects(self):
406 # If the source is a Path object, use it as a system ID and open it.
407 prep = prepare_input_source(FakePath(self.file))
408 self.assertIsNone(prep.getCharacterStream())
409 self.checkContent(prep.getByteStream(),
410 b"This was read from a file.")
411
Serhiy Storchakaaa9563c2015-04-02 20:55:59 +0300412 def test_binary_file(self):
413 # If the source is a binary file-like object, use it as a byte
414 # stream.
415 prep = prepare_input_source(self.make_byte_stream())
416 self.assertIsNone(prep.getCharacterStream())
417 self.checkContent(prep.getByteStream(),
418 b"This is a byte stream.")
419
Serhiy Storchaka61de0872015-04-02 21:00:13 +0300420 def test_text_file(self):
421 # If the source is a text file-like object, use it as a character
422 # stream.
423 prep = prepare_input_source(self.make_character_stream())
424 self.assertIsNone(prep.getByteStream())
425 self.checkContent(prep.getCharacterStream(),
426 "This is a character stream.")
427
Serhiy Storchakaaa9563c2015-04-02 20:55:59 +0300428
Lars Gustäbel96753b32000-09-24 12:24:24 +0000429# ===== XMLGenerator
430
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200431class XmlgenTest:
Guido van Rossumd8faa362007-04-27 19:54:29 +0000432 def test_xmlgen_basic(self):
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200433 result = self.ioclass()
Guido van Rossumd8faa362007-04-27 19:54:29 +0000434 gen = XMLGenerator(result)
435 gen.startDocument()
436 gen.startElement("doc", {})
437 gen.endElement("doc")
438 gen.endDocument()
Lars Gustäbel96753b32000-09-24 12:24:24 +0000439
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200440 self.assertEqual(result.getvalue(), self.xml("<doc></doc>"))
Lars Gustäbel96753b32000-09-24 12:24:24 +0000441
R. David Murraya90032a2010-10-17 22:46:45 +0000442 def test_xmlgen_basic_empty(self):
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200443 result = self.ioclass()
R. David Murraya90032a2010-10-17 22:46:45 +0000444 gen = XMLGenerator(result, short_empty_elements=True)
445 gen.startDocument()
446 gen.startElement("doc", {})
447 gen.endElement("doc")
448 gen.endDocument()
449
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200450 self.assertEqual(result.getvalue(), self.xml("<doc/>"))
R. David Murraya90032a2010-10-17 22:46:45 +0000451
Guido van Rossumd8faa362007-04-27 19:54:29 +0000452 def test_xmlgen_content(self):
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200453 result = self.ioclass()
Guido van Rossumd8faa362007-04-27 19:54:29 +0000454 gen = XMLGenerator(result)
Fred Drake004d5e62000-10-23 17:22:08 +0000455
Guido van Rossumd8faa362007-04-27 19:54:29 +0000456 gen.startDocument()
457 gen.startElement("doc", {})
458 gen.characters("huhei")
459 gen.endElement("doc")
460 gen.endDocument()
Lars Gustäbel96753b32000-09-24 12:24:24 +0000461
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200462 self.assertEqual(result.getvalue(), self.xml("<doc>huhei</doc>"))
Lars Gustäbel96753b32000-09-24 12:24:24 +0000463
R. David Murraya90032a2010-10-17 22:46:45 +0000464 def test_xmlgen_content_empty(self):
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200465 result = self.ioclass()
R. David Murraya90032a2010-10-17 22:46:45 +0000466 gen = XMLGenerator(result, short_empty_elements=True)
467
468 gen.startDocument()
469 gen.startElement("doc", {})
470 gen.characters("huhei")
471 gen.endElement("doc")
472 gen.endDocument()
473
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200474 self.assertEqual(result.getvalue(), self.xml("<doc>huhei</doc>"))
R. David Murraya90032a2010-10-17 22:46:45 +0000475
Guido van Rossumd8faa362007-04-27 19:54:29 +0000476 def test_xmlgen_pi(self):
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200477 result = self.ioclass()
Guido van Rossumd8faa362007-04-27 19:54:29 +0000478 gen = XMLGenerator(result)
Fred Drake004d5e62000-10-23 17:22:08 +0000479
Guido van Rossumd8faa362007-04-27 19:54:29 +0000480 gen.startDocument()
481 gen.processingInstruction("test", "data")
482 gen.startElement("doc", {})
483 gen.endElement("doc")
484 gen.endDocument()
Lars Gustäbel96753b32000-09-24 12:24:24 +0000485
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200486 self.assertEqual(result.getvalue(),
487 self.xml("<?test data?><doc></doc>"))
Lars Gustäbel96753b32000-09-24 12:24:24 +0000488
Guido van Rossumd8faa362007-04-27 19:54:29 +0000489 def test_xmlgen_content_escape(self):
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200490 result = self.ioclass()
Guido van Rossumd8faa362007-04-27 19:54:29 +0000491 gen = XMLGenerator(result)
Fred Drake004d5e62000-10-23 17:22:08 +0000492
Guido van Rossumd8faa362007-04-27 19:54:29 +0000493 gen.startDocument()
494 gen.startElement("doc", {})
495 gen.characters("<huhei&")
496 gen.endElement("doc")
497 gen.endDocument()
Lars Gustäbel96753b32000-09-24 12:24:24 +0000498
Ezio Melottib3aedd42010-11-20 19:04:17 +0000499 self.assertEqual(result.getvalue(),
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200500 self.xml("<doc>&lt;huhei&amp;</doc>"))
Lars Gustäbel96753b32000-09-24 12:24:24 +0000501
Guido van Rossumd8faa362007-04-27 19:54:29 +0000502 def test_xmlgen_attr_escape(self):
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200503 result = self.ioclass()
Guido van Rossumd8faa362007-04-27 19:54:29 +0000504 gen = XMLGenerator(result)
Fred Drakec9fadf92001-08-07 19:17:06 +0000505
Guido van Rossumd8faa362007-04-27 19:54:29 +0000506 gen.startDocument()
507 gen.startElement("doc", {"a": '"'})
508 gen.startElement("e", {"a": "'"})
509 gen.endElement("e")
510 gen.startElement("e", {"a": "'\""})
511 gen.endElement("e")
512 gen.startElement("e", {"a": "\n\r\t"})
513 gen.endElement("e")
514 gen.endElement("doc")
515 gen.endDocument()
Fred Drakec9fadf92001-08-07 19:17:06 +0000516
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200517 self.assertEqual(result.getvalue(), self.xml(
518 "<doc a='\"'><e a=\"'\"></e>"
519 "<e a=\"'&quot;\"></e>"
520 "<e a=\"&#10;&#13;&#9;\"></e></doc>"))
521
522 def test_xmlgen_encoding(self):
523 encodings = ('iso-8859-15', 'utf-8', 'utf-8-sig',
524 'utf-16', 'utf-16be', 'utf-16le',
525 'utf-32', 'utf-32be', 'utf-32le')
526 for encoding in encodings:
527 result = self.ioclass()
528 gen = XMLGenerator(result, encoding=encoding)
529
530 gen.startDocument()
531 gen.startElement("doc", {"a": '\u20ac'})
532 gen.characters("\u20ac")
533 gen.endElement("doc")
534 gen.endDocument()
535
536 self.assertEqual(result.getvalue(),
537 self.xml('<doc a="\u20ac">\u20ac</doc>', encoding=encoding))
538
539 def test_xmlgen_unencodable(self):
540 result = self.ioclass()
541 gen = XMLGenerator(result, encoding='ascii')
542
543 gen.startDocument()
544 gen.startElement("doc", {"a": '\u20ac'})
545 gen.characters("\u20ac")
546 gen.endElement("doc")
547 gen.endDocument()
548
549 self.assertEqual(result.getvalue(),
550 self.xml('<doc a="&#8364;">&#8364;</doc>', encoding='ascii'))
Fred Drakec9fadf92001-08-07 19:17:06 +0000551
Guido van Rossumd8faa362007-04-27 19:54:29 +0000552 def test_xmlgen_ignorable(self):
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200553 result = self.ioclass()
Guido van Rossumd8faa362007-04-27 19:54:29 +0000554 gen = XMLGenerator(result)
Fred Drake004d5e62000-10-23 17:22:08 +0000555
Guido van Rossumd8faa362007-04-27 19:54:29 +0000556 gen.startDocument()
557 gen.startElement("doc", {})
558 gen.ignorableWhitespace(" ")
559 gen.endElement("doc")
560 gen.endDocument()
Lars Gustäbel96753b32000-09-24 12:24:24 +0000561
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200562 self.assertEqual(result.getvalue(), self.xml("<doc> </doc>"))
Lars Gustäbel96753b32000-09-24 12:24:24 +0000563
R. David Murraya90032a2010-10-17 22:46:45 +0000564 def test_xmlgen_ignorable_empty(self):
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200565 result = self.ioclass()
R. David Murraya90032a2010-10-17 22:46:45 +0000566 gen = XMLGenerator(result, short_empty_elements=True)
567
568 gen.startDocument()
569 gen.startElement("doc", {})
570 gen.ignorableWhitespace(" ")
571 gen.endElement("doc")
572 gen.endDocument()
573
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200574 self.assertEqual(result.getvalue(), self.xml("<doc> </doc>"))
R. David Murraya90032a2010-10-17 22:46:45 +0000575
Serhiy Storchaka3eab6b32013-05-12 17:31:16 +0300576 def test_xmlgen_encoding_bytes(self):
577 encodings = ('iso-8859-15', 'utf-8', 'utf-8-sig',
578 'utf-16', 'utf-16be', 'utf-16le',
579 'utf-32', 'utf-32be', 'utf-32le')
580 for encoding in encodings:
581 result = self.ioclass()
582 gen = XMLGenerator(result, encoding=encoding)
583
584 gen.startDocument()
585 gen.startElement("doc", {"a": '\u20ac'})
586 gen.characters("\u20ac".encode(encoding))
587 gen.ignorableWhitespace(" ".encode(encoding))
588 gen.endElement("doc")
589 gen.endDocument()
590
591 self.assertEqual(result.getvalue(),
592 self.xml('<doc a="\u20ac">\u20ac </doc>', encoding=encoding))
593
Guido van Rossumd8faa362007-04-27 19:54:29 +0000594 def test_xmlgen_ns(self):
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200595 result = self.ioclass()
Guido van Rossumd8faa362007-04-27 19:54:29 +0000596 gen = XMLGenerator(result)
Lars Gustäbel96753b32000-09-24 12:24:24 +0000597
Guido van Rossumd8faa362007-04-27 19:54:29 +0000598 gen.startDocument()
599 gen.startPrefixMapping("ns1", ns_uri)
600 gen.startElementNS((ns_uri, "doc"), "ns1:doc", {})
601 # add an unqualified name
602 gen.startElementNS((None, "udoc"), None, {})
603 gen.endElementNS((None, "udoc"), None)
604 gen.endElementNS((ns_uri, "doc"), "ns1:doc")
605 gen.endPrefixMapping("ns1")
606 gen.endDocument()
Fred Drake004d5e62000-10-23 17:22:08 +0000607
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200608 self.assertEqual(result.getvalue(), self.xml(
609 '<ns1:doc xmlns:ns1="%s"><udoc></udoc></ns1:doc>' %
Guido van Rossumd8faa362007-04-27 19:54:29 +0000610 ns_uri))
Lars Gustäbel96753b32000-09-24 12:24:24 +0000611
R. David Murraya90032a2010-10-17 22:46:45 +0000612 def test_xmlgen_ns_empty(self):
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200613 result = self.ioclass()
R. David Murraya90032a2010-10-17 22:46:45 +0000614 gen = XMLGenerator(result, short_empty_elements=True)
615
616 gen.startDocument()
617 gen.startPrefixMapping("ns1", ns_uri)
618 gen.startElementNS((ns_uri, "doc"), "ns1:doc", {})
619 # add an unqualified name
620 gen.startElementNS((None, "udoc"), None, {})
621 gen.endElementNS((None, "udoc"), None)
622 gen.endElementNS((ns_uri, "doc"), "ns1:doc")
623 gen.endPrefixMapping("ns1")
624 gen.endDocument()
625
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200626 self.assertEqual(result.getvalue(), self.xml(
627 '<ns1:doc xmlns:ns1="%s"><udoc/></ns1:doc>' %
R. David Murraya90032a2010-10-17 22:46:45 +0000628 ns_uri))
629
Guido van Rossumd8faa362007-04-27 19:54:29 +0000630 def test_1463026_1(self):
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200631 result = self.ioclass()
Guido van Rossumd8faa362007-04-27 19:54:29 +0000632 gen = XMLGenerator(result)
Thomas Wouterscf297e42007-02-23 15:07:44 +0000633
Guido van Rossumd8faa362007-04-27 19:54:29 +0000634 gen.startDocument()
635 gen.startElementNS((None, 'a'), 'a', {(None, 'b'):'c'})
636 gen.endElementNS((None, 'a'), 'a')
637 gen.endDocument()
Thomas Wouterscf297e42007-02-23 15:07:44 +0000638
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200639 self.assertEqual(result.getvalue(), self.xml('<a b="c"></a>'))
Thomas Wouterscf297e42007-02-23 15:07:44 +0000640
R. David Murraya90032a2010-10-17 22:46:45 +0000641 def test_1463026_1_empty(self):
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200642 result = self.ioclass()
R. David Murraya90032a2010-10-17 22:46:45 +0000643 gen = XMLGenerator(result, short_empty_elements=True)
644
645 gen.startDocument()
646 gen.startElementNS((None, 'a'), 'a', {(None, 'b'):'c'})
647 gen.endElementNS((None, 'a'), 'a')
648 gen.endDocument()
649
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200650 self.assertEqual(result.getvalue(), self.xml('<a b="c"/>'))
R. David Murraya90032a2010-10-17 22:46:45 +0000651
Guido van Rossumd8faa362007-04-27 19:54:29 +0000652 def test_1463026_2(self):
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200653 result = self.ioclass()
Guido van Rossumd8faa362007-04-27 19:54:29 +0000654 gen = XMLGenerator(result)
Thomas Wouterscf297e42007-02-23 15:07:44 +0000655
Guido van Rossumd8faa362007-04-27 19:54:29 +0000656 gen.startDocument()
657 gen.startPrefixMapping(None, 'qux')
658 gen.startElementNS(('qux', 'a'), 'a', {})
659 gen.endElementNS(('qux', 'a'), 'a')
660 gen.endPrefixMapping(None)
661 gen.endDocument()
Thomas Wouterscf297e42007-02-23 15:07:44 +0000662
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200663 self.assertEqual(result.getvalue(), self.xml('<a xmlns="qux"></a>'))
Thomas Wouterscf297e42007-02-23 15:07:44 +0000664
R. David Murraya90032a2010-10-17 22:46:45 +0000665 def test_1463026_2_empty(self):
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200666 result = self.ioclass()
R. David Murraya90032a2010-10-17 22:46:45 +0000667 gen = XMLGenerator(result, short_empty_elements=True)
668
669 gen.startDocument()
670 gen.startPrefixMapping(None, 'qux')
671 gen.startElementNS(('qux', 'a'), 'a', {})
672 gen.endElementNS(('qux', 'a'), 'a')
673 gen.endPrefixMapping(None)
674 gen.endDocument()
675
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200676 self.assertEqual(result.getvalue(), self.xml('<a xmlns="qux"/>'))
R. David Murraya90032a2010-10-17 22:46:45 +0000677
Guido van Rossumd8faa362007-04-27 19:54:29 +0000678 def test_1463026_3(self):
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200679 result = self.ioclass()
Guido van Rossumd8faa362007-04-27 19:54:29 +0000680 gen = XMLGenerator(result)
Thomas Wouterscf297e42007-02-23 15:07:44 +0000681
Guido van Rossumd8faa362007-04-27 19:54:29 +0000682 gen.startDocument()
683 gen.startPrefixMapping('my', 'qux')
684 gen.startElementNS(('qux', 'a'), 'a', {(None, 'b'):'c'})
685 gen.endElementNS(('qux', 'a'), 'a')
686 gen.endPrefixMapping('my')
687 gen.endDocument()
Thomas Wouterscf297e42007-02-23 15:07:44 +0000688
Ezio Melottib3aedd42010-11-20 19:04:17 +0000689 self.assertEqual(result.getvalue(),
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200690 self.xml('<my:a xmlns:my="qux" b="c"></my:a>'))
Lars Gustäbel96753b32000-09-24 12:24:24 +0000691
R. David Murraya90032a2010-10-17 22:46:45 +0000692 def test_1463026_3_empty(self):
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200693 result = self.ioclass()
R. David Murraya90032a2010-10-17 22:46:45 +0000694 gen = XMLGenerator(result, short_empty_elements=True)
695
696 gen.startDocument()
697 gen.startPrefixMapping('my', 'qux')
698 gen.startElementNS(('qux', 'a'), 'a', {(None, 'b'):'c'})
699 gen.endElementNS(('qux', 'a'), 'a')
700 gen.endPrefixMapping('my')
701 gen.endDocument()
702
Ezio Melottib3aedd42010-11-20 19:04:17 +0000703 self.assertEqual(result.getvalue(),
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200704 self.xml('<my:a xmlns:my="qux" b="c"/>'))
R. David Murraya90032a2010-10-17 22:46:45 +0000705
Antoine Pitrou6b03ee62010-10-27 18:33:30 +0000706 def test_5027_1(self):
707 # The xml prefix (as in xml:lang below) is reserved and bound by
708 # definition to http://www.w3.org/XML/1998/namespace. XMLGenerator had
Andrew Svetlov737fb892012-12-18 21:14:22 +0200709 # a bug whereby a KeyError is raised because this namespace is missing
Antoine Pitrou6b03ee62010-10-27 18:33:30 +0000710 # from a dictionary.
711 #
712 # This test demonstrates the bug by parsing a document.
713 test_xml = StringIO(
714 '<?xml version="1.0"?>'
715 '<a:g1 xmlns:a="http://example.com/ns">'
716 '<a:g2 xml:lang="en">Hello</a:g2>'
717 '</a:g1>')
718
719 parser = make_parser()
720 parser.setFeature(feature_namespaces, True)
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200721 result = self.ioclass()
Antoine Pitrou6b03ee62010-10-27 18:33:30 +0000722 gen = XMLGenerator(result)
723 parser.setContentHandler(gen)
724 parser.parse(test_xml)
725
Ezio Melottib3aedd42010-11-20 19:04:17 +0000726 self.assertEqual(result.getvalue(),
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200727 self.xml(
Ezio Melottib3aedd42010-11-20 19:04:17 +0000728 '<a:g1 xmlns:a="http://example.com/ns">'
729 '<a:g2 xml:lang="en">Hello</a:g2>'
730 '</a:g1>'))
Antoine Pitrou6b03ee62010-10-27 18:33:30 +0000731
732 def test_5027_2(self):
733 # The xml prefix (as in xml:lang below) is reserved and bound by
734 # definition to http://www.w3.org/XML/1998/namespace. XMLGenerator had
Andrew Svetlov737fb892012-12-18 21:14:22 +0200735 # a bug whereby a KeyError is raised because this namespace is missing
Antoine Pitrou6b03ee62010-10-27 18:33:30 +0000736 # from a dictionary.
737 #
738 # This test demonstrates the bug by direct manipulation of the
739 # XMLGenerator.
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200740 result = self.ioclass()
Antoine Pitrou6b03ee62010-10-27 18:33:30 +0000741 gen = XMLGenerator(result)
742
743 gen.startDocument()
744 gen.startPrefixMapping('a', 'http://example.com/ns')
745 gen.startElementNS(('http://example.com/ns', 'g1'), 'g1', {})
746 lang_attr = {('http://www.w3.org/XML/1998/namespace', 'lang'): 'en'}
747 gen.startElementNS(('http://example.com/ns', 'g2'), 'g2', lang_attr)
748 gen.characters('Hello')
749 gen.endElementNS(('http://example.com/ns', 'g2'), 'g2')
750 gen.endElementNS(('http://example.com/ns', 'g1'), 'g1')
751 gen.endPrefixMapping('a')
752 gen.endDocument()
753
Ezio Melottib3aedd42010-11-20 19:04:17 +0000754 self.assertEqual(result.getvalue(),
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200755 self.xml(
Ezio Melottib3aedd42010-11-20 19:04:17 +0000756 '<a:g1 xmlns:a="http://example.com/ns">'
757 '<a:g2 xml:lang="en">Hello</a:g2>'
758 '</a:g1>'))
Antoine Pitrou6b03ee62010-10-27 18:33:30 +0000759
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200760 def test_no_close_file(self):
761 result = self.ioclass()
762 def func(out):
763 gen = XMLGenerator(out)
764 gen.startDocument()
765 gen.startElement("doc", {})
766 func(result)
767 self.assertFalse(result.closed)
768
Serhiy Storchakaa5f13d22013-02-25 13:46:10 +0200769 def test_xmlgen_fragment(self):
770 result = self.ioclass()
771 gen = XMLGenerator(result)
772
773 # Don't call gen.startDocument()
774 gen.startElement("foo", {"a": "1.0"})
775 gen.characters("Hello")
776 gen.endElement("foo")
777 gen.startElement("bar", {"b": "2.0"})
778 gen.endElement("bar")
779 # Don't call gen.endDocument()
780
781 self.assertEqual(result.getvalue(),
782 self.xml('<foo a="1.0">Hello</foo><bar b="2.0"></bar>')[len(self.xml('')):])
783
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200784class StringXmlgenTest(XmlgenTest, unittest.TestCase):
785 ioclass = StringIO
786
787 def xml(self, doc, encoding='iso-8859-1'):
788 return '<?xml version="1.0" encoding="%s"?>\n%s' % (encoding, doc)
789
790 test_xmlgen_unencodable = None
791
792class BytesXmlgenTest(XmlgenTest, unittest.TestCase):
793 ioclass = BytesIO
794
795 def xml(self, doc, encoding='iso-8859-1'):
796 return ('<?xml version="1.0" encoding="%s"?>\n%s' %
797 (encoding, doc)).encode(encoding, 'xmlcharrefreplace')
798
799class WriterXmlgenTest(BytesXmlgenTest):
800 class ioclass(list):
801 write = list.append
802 closed = False
803
804 def seekable(self):
805 return True
806
807 def tell(self):
808 # return 0 at start and not 0 after start
809 return len(self)
810
811 def getvalue(self):
812 return b''.join(self)
813
Georg Brandlc502df42013-05-12 11:41:12 +0200814class StreamWriterXmlgenTest(XmlgenTest, unittest.TestCase):
815 def ioclass(self):
816 raw = BytesIO()
817 writer = codecs.getwriter('ascii')(raw, 'xmlcharrefreplace')
818 writer.getvalue = raw.getvalue
819 return writer
820
821 def xml(self, doc, encoding='iso-8859-1'):
822 return ('<?xml version="1.0" encoding="%s"?>\n%s' %
823 (encoding, doc)).encode('ascii', 'xmlcharrefreplace')
824
825class StreamReaderWriterXmlgenTest(XmlgenTest, unittest.TestCase):
826 fname = support.TESTFN + '-codecs'
827
828 def ioclass(self):
829 writer = codecs.open(self.fname, 'w', encoding='ascii',
830 errors='xmlcharrefreplace', buffering=0)
Antoine Pitrou2adb6fe2013-05-13 22:34:21 +0200831 def cleanup():
832 writer.close()
833 support.unlink(self.fname)
834 self.addCleanup(cleanup)
Richard Oudkerk90a24272013-05-18 18:11:30 +0100835 def getvalue():
836 # Windows will not let use reopen without first closing
837 writer.close()
838 with open(writer.name, 'rb') as f:
839 return f.read()
840 writer.getvalue = getvalue
Georg Brandlc502df42013-05-12 11:41:12 +0200841 return writer
842
Georg Brandlc502df42013-05-12 11:41:12 +0200843 def xml(self, doc, encoding='iso-8859-1'):
844 return ('<?xml version="1.0" encoding="%s"?>\n%s' %
845 (encoding, doc)).encode('ascii', 'xmlcharrefreplace')
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200846
847start = b'<?xml version="1.0" encoding="iso-8859-1"?>\n'
848
Fred Drake004d5e62000-10-23 17:22:08 +0000849
Guido van Rossumd8faa362007-04-27 19:54:29 +0000850class XMLFilterBaseTest(unittest.TestCase):
851 def test_filter_basic(self):
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200852 result = BytesIO()
Guido van Rossumd8faa362007-04-27 19:54:29 +0000853 gen = XMLGenerator(result)
854 filter = XMLFilterBase()
855 filter.setContentHandler(gen)
Lars Gustäbel96753b32000-09-24 12:24:24 +0000856
Guido van Rossumd8faa362007-04-27 19:54:29 +0000857 filter.startDocument()
858 filter.startElement("doc", {})
859 filter.characters("content")
860 filter.ignorableWhitespace(" ")
861 filter.endElement("doc")
862 filter.endDocument()
863
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200864 self.assertEqual(result.getvalue(), start + b"<doc>content </doc>")
Lars Gustäbel96753b32000-09-24 12:24:24 +0000865
866# ===========================================================================
867#
868# expatreader tests
869#
870# ===========================================================================
871
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200872with open(TEST_XMLFILE_OUT, 'rb') as f:
Benjamin Petersond5df36d2010-10-31 18:23:23 +0000873 xml_test_out = f.read()
Lars Gustäbelb7536d52000-09-24 18:53:56 +0000874
Guido van Rossumd8faa362007-04-27 19:54:29 +0000875class ExpatReaderTest(XmlTestBase):
Lars Gustäbelb7536d52000-09-24 18:53:56 +0000876
Guido van Rossumd8faa362007-04-27 19:54:29 +0000877 # ===== XMLReader support
Lars Gustäbelb7536d52000-09-24 18:53:56 +0000878
Serhiy Storchakaaa9563c2015-04-02 20:55:59 +0300879 def test_expat_binary_file(self):
Guido van Rossumd8faa362007-04-27 19:54:29 +0000880 parser = create_parser()
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200881 result = BytesIO()
Guido van Rossumd8faa362007-04-27 19:54:29 +0000882 xmlgen = XMLGenerator(result)
Lars Gustäbelb7536d52000-09-24 18:53:56 +0000883
Guido van Rossumd8faa362007-04-27 19:54:29 +0000884 parser.setContentHandler(xmlgen)
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200885 with open(TEST_XMLFILE, 'rb') as f:
Benjamin Petersond5df36d2010-10-31 18:23:23 +0000886 parser.parse(f)
Lars Gustäbelb7536d52000-09-24 18:53:56 +0000887
Ezio Melottib3aedd42010-11-20 19:04:17 +0000888 self.assertEqual(result.getvalue(), xml_test_out)
Lars Gustäbelb7536d52000-09-24 18:53:56 +0000889
Serhiy Storchakaaa9563c2015-04-02 20:55:59 +0300890 def test_expat_text_file(self):
891 parser = create_parser()
892 result = BytesIO()
893 xmlgen = XMLGenerator(result)
894
895 parser.setContentHandler(xmlgen)
896 with open(TEST_XMLFILE, 'rt', encoding='iso-8859-1') as f:
897 parser.parse(f)
898
899 self.assertEqual(result.getvalue(), xml_test_out)
900
Serhiy Storchaka1a4ed4c2013-02-02 12:17:05 +0200901 @requires_nonascii_filenames
Serhiy Storchakaaa9563c2015-04-02 20:55:59 +0300902 def test_expat_binary_file_nonascii(self):
Serhiy Storchakad5202392013-02-02 10:31:17 +0200903 fname = support.TESTFN_UNICODE
904 shutil.copyfile(TEST_XMLFILE, fname)
905 self.addCleanup(support.unlink, fname)
906
907 parser = create_parser()
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200908 result = BytesIO()
Serhiy Storchakad5202392013-02-02 10:31:17 +0200909 xmlgen = XMLGenerator(result)
910
911 parser.setContentHandler(xmlgen)
Serhiy Storchakaaa9563c2015-04-02 20:55:59 +0300912 parser.parse(open(fname, 'rb'))
Serhiy Storchakad5202392013-02-02 10:31:17 +0200913
914 self.assertEqual(result.getvalue(), xml_test_out)
915
Serhiy Storchakafc8e9b02014-11-27 22:13:16 +0200916 def test_expat_binary_file_bytes_name(self):
917 fname = os.fsencode(TEST_XMLFILE)
918 parser = create_parser()
919 result = BytesIO()
920 xmlgen = XMLGenerator(result)
921
922 parser.setContentHandler(xmlgen)
923 with open(fname, 'rb') as f:
924 parser.parse(f)
925
926 self.assertEqual(result.getvalue(), xml_test_out)
927
928 def test_expat_binary_file_int_name(self):
929 parser = create_parser()
930 result = BytesIO()
931 xmlgen = XMLGenerator(result)
932
933 parser.setContentHandler(xmlgen)
934 with open(TEST_XMLFILE, 'rb') as f:
935 with open(f.fileno(), 'rb', closefd=False) as f2:
936 parser.parse(f2)
937
938 self.assertEqual(result.getvalue(), xml_test_out)
939
Guido van Rossumd8faa362007-04-27 19:54:29 +0000940 # ===== DTDHandler support
Lars Gustäbelb7536d52000-09-24 18:53:56 +0000941
Guido van Rossumd8faa362007-04-27 19:54:29 +0000942 class TestDTDHandler:
Lars Gustäbelb7536d52000-09-24 18:53:56 +0000943
Guido van Rossumd8faa362007-04-27 19:54:29 +0000944 def __init__(self):
945 self._notations = []
946 self._entities = []
Lars Gustäbelb7536d52000-09-24 18:53:56 +0000947
Guido van Rossumd8faa362007-04-27 19:54:29 +0000948 def notationDecl(self, name, publicId, systemId):
949 self._notations.append((name, publicId, systemId))
Lars Gustäbelb7536d52000-09-24 18:53:56 +0000950
Guido van Rossumd8faa362007-04-27 19:54:29 +0000951 def unparsedEntityDecl(self, name, publicId, systemId, ndata):
952 self._entities.append((name, publicId, systemId, ndata))
Lars Gustäbel2fc52942000-10-24 15:35:07 +0000953
Christian Heimes17b1d5d2018-09-23 09:50:25 +0200954
955 class TestEntityRecorder:
956 def __init__(self):
957 self.entities = []
958
959 def resolveEntity(self, publicId, systemId):
960 self.entities.append((publicId, systemId))
961 source = InputSource()
962 source.setPublicId(publicId)
963 source.setSystemId(systemId)
964 return source
965
Guido van Rossumd8faa362007-04-27 19:54:29 +0000966 def test_expat_dtdhandler(self):
967 parser = create_parser()
968 handler = self.TestDTDHandler()
969 parser.setDTDHandler(handler)
Lars Gustäbel2fc52942000-10-24 15:35:07 +0000970
Guido van Rossumd8faa362007-04-27 19:54:29 +0000971 parser.feed('<!DOCTYPE doc [\n')
972 parser.feed(' <!ENTITY img SYSTEM "expat.gif" NDATA GIF>\n')
973 parser.feed(' <!NOTATION GIF PUBLIC "-//CompuServe//NOTATION Graphics Interchange Format 89a//EN">\n')
974 parser.feed(']>\n')
975 parser.feed('<doc></doc>')
976 parser.close()
Lars Gustäbel2fc52942000-10-24 15:35:07 +0000977
Ezio Melottib3aedd42010-11-20 19:04:17 +0000978 self.assertEqual(handler._notations,
Guido van Rossumd8faa362007-04-27 19:54:29 +0000979 [("GIF", "-//CompuServe//NOTATION Graphics Interchange Format 89a//EN", None)])
Ezio Melottib3aedd42010-11-20 19:04:17 +0000980 self.assertEqual(handler._entities, [("img", None, "expat.gif", "GIF")])
Lars Gustäbel2fc52942000-10-24 15:35:07 +0000981
Christian Heimes17b1d5d2018-09-23 09:50:25 +0200982 def test_expat_external_dtd_enabled(self):
Victor Stinner7cb92042019-07-02 14:50:19 +0200983 # clear _opener global variable
984 self.addCleanup(urllib.request.urlcleanup)
985
Christian Heimes17b1d5d2018-09-23 09:50:25 +0200986 parser = create_parser()
987 parser.setFeature(feature_external_ges, True)
988 resolver = self.TestEntityRecorder()
989 parser.setEntityResolver(resolver)
990
991 with self.assertRaises(URLError):
992 parser.feed(
993 '<!DOCTYPE external SYSTEM "unsupported://non-existing">\n'
994 )
995 self.assertEqual(
996 resolver.entities, [(None, 'unsupported://non-existing')]
997 )
998
999 def test_expat_external_dtd_default(self):
1000 parser = create_parser()
1001 resolver = self.TestEntityRecorder()
1002 parser.setEntityResolver(resolver)
1003
1004 parser.feed(
1005 '<!DOCTYPE external SYSTEM "unsupported://non-existing">\n'
1006 )
1007 parser.feed('<doc />')
1008 parser.close()
1009 self.assertEqual(resolver.entities, [])
1010
Guido van Rossumd8faa362007-04-27 19:54:29 +00001011 # ===== EntityResolver support
Lars Gustäbel2fc52942000-10-24 15:35:07 +00001012
Guido van Rossumd8faa362007-04-27 19:54:29 +00001013 class TestEntityResolver:
Lars Gustäbel2fc52942000-10-24 15:35:07 +00001014
Guido van Rossumd8faa362007-04-27 19:54:29 +00001015 def resolveEntity(self, publicId, systemId):
1016 inpsrc = InputSource()
Serhiy Storchaka88efc522013-02-10 14:29:52 +02001017 inpsrc.setByteStream(BytesIO(b"<entity/>"))
Guido van Rossumd8faa362007-04-27 19:54:29 +00001018 return inpsrc
Lars Gustäbel2fc52942000-10-24 15:35:07 +00001019
Christian Heimes17b1d5d2018-09-23 09:50:25 +02001020 def test_expat_entityresolver_enabled(self):
Guido van Rossumd8faa362007-04-27 19:54:29 +00001021 parser = create_parser()
Christian Heimes17b1d5d2018-09-23 09:50:25 +02001022 parser.setFeature(feature_external_ges, True)
Guido van Rossumd8faa362007-04-27 19:54:29 +00001023 parser.setEntityResolver(self.TestEntityResolver())
Serhiy Storchaka88efc522013-02-10 14:29:52 +02001024 result = BytesIO()
Guido van Rossumd8faa362007-04-27 19:54:29 +00001025 parser.setContentHandler(XMLGenerator(result))
Lars Gustäbel2fc52942000-10-24 15:35:07 +00001026
Guido van Rossumd8faa362007-04-27 19:54:29 +00001027 parser.feed('<!DOCTYPE doc [\n')
1028 parser.feed(' <!ENTITY test SYSTEM "whatever">\n')
1029 parser.feed(']>\n')
1030 parser.feed('<doc>&test;</doc>')
1031 parser.close()
Lars Gustäbel2fc52942000-10-24 15:35:07 +00001032
Ezio Melottib3aedd42010-11-20 19:04:17 +00001033 self.assertEqual(result.getvalue(), start +
Serhiy Storchaka88efc522013-02-10 14:29:52 +02001034 b"<doc><entity></entity></doc>")
Lars Gustäbel2fc52942000-10-24 15:35:07 +00001035
Christian Heimes17b1d5d2018-09-23 09:50:25 +02001036 def test_expat_entityresolver_default(self):
1037 parser = create_parser()
1038 self.assertEqual(parser.getFeature(feature_external_ges), False)
1039 parser.setEntityResolver(self.TestEntityResolver())
1040 result = BytesIO()
1041 parser.setContentHandler(XMLGenerator(result))
1042
1043 parser.feed('<!DOCTYPE doc [\n')
1044 parser.feed(' <!ENTITY test SYSTEM "whatever">\n')
1045 parser.feed(']>\n')
1046 parser.feed('<doc>&test;</doc>')
1047 parser.close()
1048
1049 self.assertEqual(result.getvalue(), start +
1050 b"<doc></doc>")
1051
Guido van Rossumd8faa362007-04-27 19:54:29 +00001052 # ===== Attributes support
Lars Gustäbel2fc52942000-10-24 15:35:07 +00001053
Guido van Rossumd8faa362007-04-27 19:54:29 +00001054 class AttrGatherer(ContentHandler):
Lars Gustäbel2fc52942000-10-24 15:35:07 +00001055
Guido van Rossumd8faa362007-04-27 19:54:29 +00001056 def startElement(self, name, attrs):
1057 self._attrs = attrs
Lars Gustäbel2fc52942000-10-24 15:35:07 +00001058
Guido van Rossumd8faa362007-04-27 19:54:29 +00001059 def startElementNS(self, name, qname, attrs):
1060 self._attrs = attrs
Lars Gustäbel2fc52942000-10-24 15:35:07 +00001061
Guido van Rossumd8faa362007-04-27 19:54:29 +00001062 def test_expat_attrs_empty(self):
1063 parser = create_parser()
1064 gather = self.AttrGatherer()
1065 parser.setContentHandler(gather)
1066
1067 parser.feed("<doc/>")
1068 parser.close()
1069
1070 self.verify_empty_attrs(gather._attrs)
1071
1072 def test_expat_attrs_wattr(self):
1073 parser = create_parser()
1074 gather = self.AttrGatherer()
1075 parser.setContentHandler(gather)
1076
1077 parser.feed("<doc attr='val'/>")
1078 parser.close()
1079
1080 self.verify_attrs_wattr(gather._attrs)
1081
1082 def test_expat_nsattrs_empty(self):
1083 parser = create_parser(1)
1084 gather = self.AttrGatherer()
1085 parser.setContentHandler(gather)
1086
1087 parser.feed("<doc/>")
1088 parser.close()
1089
1090 self.verify_empty_nsattrs(gather._attrs)
1091
1092 def test_expat_nsattrs_wattr(self):
1093 parser = create_parser(1)
1094 gather = self.AttrGatherer()
1095 parser.setContentHandler(gather)
1096
1097 parser.feed("<doc xmlns:ns='%s' ns:attr='val'/>" % ns_uri)
1098 parser.close()
1099
1100 attrs = gather._attrs
1101
Ezio Melottib3aedd42010-11-20 19:04:17 +00001102 self.assertEqual(attrs.getLength(), 1)
1103 self.assertEqual(attrs.getNames(), [(ns_uri, "attr")])
Guido van Rossumd8faa362007-04-27 19:54:29 +00001104 self.assertTrue((attrs.getQNames() == [] or
1105 attrs.getQNames() == ["ns:attr"]))
Ezio Melottib3aedd42010-11-20 19:04:17 +00001106 self.assertEqual(len(attrs), 1)
Benjamin Peterson577473f2010-01-19 00:09:57 +00001107 self.assertIn((ns_uri, "attr"), attrs)
Ezio Melottib3aedd42010-11-20 19:04:17 +00001108 self.assertEqual(attrs.get((ns_uri, "attr")), "val")
1109 self.assertEqual(attrs.get((ns_uri, "attr"), 25), "val")
1110 self.assertEqual(list(attrs.items()), [((ns_uri, "attr"), "val")])
1111 self.assertEqual(list(attrs.values()), ["val"])
1112 self.assertEqual(attrs.getValue((ns_uri, "attr")), "val")
1113 self.assertEqual(attrs[(ns_uri, "attr")], "val")
Guido van Rossumd8faa362007-04-27 19:54:29 +00001114
1115 # ===== InputSource support
1116
Benjamin Petersona7f4f5a2008-09-04 02:22:52 +00001117 def test_expat_inpsource_filename(self):
Guido van Rossumd8faa362007-04-27 19:54:29 +00001118 parser = create_parser()
Serhiy Storchaka88efc522013-02-10 14:29:52 +02001119 result = BytesIO()
Guido van Rossumd8faa362007-04-27 19:54:29 +00001120 xmlgen = XMLGenerator(result)
1121
1122 parser.setContentHandler(xmlgen)
Florent Xiclunaf15351d2010-03-13 23:24:31 +00001123 parser.parse(TEST_XMLFILE)
Guido van Rossumd8faa362007-04-27 19:54:29 +00001124
Ezio Melottib3aedd42010-11-20 19:04:17 +00001125 self.assertEqual(result.getvalue(), xml_test_out)
Guido van Rossumd8faa362007-04-27 19:54:29 +00001126
Benjamin Petersona7f4f5a2008-09-04 02:22:52 +00001127 def test_expat_inpsource_sysid(self):
Guido van Rossumd8faa362007-04-27 19:54:29 +00001128 parser = create_parser()
Serhiy Storchaka88efc522013-02-10 14:29:52 +02001129 result = BytesIO()
Guido van Rossumd8faa362007-04-27 19:54:29 +00001130 xmlgen = XMLGenerator(result)
1131
1132 parser.setContentHandler(xmlgen)
Florent Xiclunaf15351d2010-03-13 23:24:31 +00001133 parser.parse(InputSource(TEST_XMLFILE))
Guido van Rossumd8faa362007-04-27 19:54:29 +00001134
Ezio Melottib3aedd42010-11-20 19:04:17 +00001135 self.assertEqual(result.getvalue(), xml_test_out)
Guido van Rossumd8faa362007-04-27 19:54:29 +00001136
Serhiy Storchaka1a4ed4c2013-02-02 12:17:05 +02001137 @requires_nonascii_filenames
Serhiy Storchakad5202392013-02-02 10:31:17 +02001138 def test_expat_inpsource_sysid_nonascii(self):
1139 fname = support.TESTFN_UNICODE
1140 shutil.copyfile(TEST_XMLFILE, fname)
1141 self.addCleanup(support.unlink, fname)
1142
1143 parser = create_parser()
Serhiy Storchaka88efc522013-02-10 14:29:52 +02001144 result = BytesIO()
Serhiy Storchakad5202392013-02-02 10:31:17 +02001145 xmlgen = XMLGenerator(result)
1146
1147 parser.setContentHandler(xmlgen)
1148 parser.parse(InputSource(fname))
1149
1150 self.assertEqual(result.getvalue(), xml_test_out)
1151
Serhiy Storchakaaa9563c2015-04-02 20:55:59 +03001152 def test_expat_inpsource_byte_stream(self):
Guido van Rossumd8faa362007-04-27 19:54:29 +00001153 parser = create_parser()
Serhiy Storchaka88efc522013-02-10 14:29:52 +02001154 result = BytesIO()
Guido van Rossumd8faa362007-04-27 19:54:29 +00001155 xmlgen = XMLGenerator(result)
1156
1157 parser.setContentHandler(xmlgen)
1158 inpsrc = InputSource()
Serhiy Storchaka88efc522013-02-10 14:29:52 +02001159 with open(TEST_XMLFILE, 'rb') as f:
Benjamin Petersond5df36d2010-10-31 18:23:23 +00001160 inpsrc.setByteStream(f)
1161 parser.parse(inpsrc)
Guido van Rossumd8faa362007-04-27 19:54:29 +00001162
Ezio Melottib3aedd42010-11-20 19:04:17 +00001163 self.assertEqual(result.getvalue(), xml_test_out)
Guido van Rossumd8faa362007-04-27 19:54:29 +00001164
Serhiy Storchaka61de0872015-04-02 21:00:13 +03001165 def test_expat_inpsource_character_stream(self):
1166 parser = create_parser()
1167 result = BytesIO()
1168 xmlgen = XMLGenerator(result)
1169
1170 parser.setContentHandler(xmlgen)
1171 inpsrc = InputSource()
1172 with open(TEST_XMLFILE, 'rt', encoding='iso-8859-1') as f:
1173 inpsrc.setCharacterStream(f)
1174 parser.parse(inpsrc)
1175
1176 self.assertEqual(result.getvalue(), xml_test_out)
1177
Guido van Rossumd8faa362007-04-27 19:54:29 +00001178 # ===== IncrementalParser support
1179
1180 def test_expat_incremental(self):
Serhiy Storchaka88efc522013-02-10 14:29:52 +02001181 result = BytesIO()
Guido van Rossumd8faa362007-04-27 19:54:29 +00001182 xmlgen = XMLGenerator(result)
1183 parser = create_parser()
1184 parser.setContentHandler(xmlgen)
1185
1186 parser.feed("<doc>")
1187 parser.feed("</doc>")
1188 parser.close()
1189
Serhiy Storchaka88efc522013-02-10 14:29:52 +02001190 self.assertEqual(result.getvalue(), start + b"<doc></doc>")
Guido van Rossumd8faa362007-04-27 19:54:29 +00001191
1192 def test_expat_incremental_reset(self):
Serhiy Storchaka88efc522013-02-10 14:29:52 +02001193 result = BytesIO()
Guido van Rossumd8faa362007-04-27 19:54:29 +00001194 xmlgen = XMLGenerator(result)
1195 parser = create_parser()
1196 parser.setContentHandler(xmlgen)
1197
1198 parser.feed("<doc>")
1199 parser.feed("text")
1200
Serhiy Storchaka88efc522013-02-10 14:29:52 +02001201 result = BytesIO()
Guido van Rossumd8faa362007-04-27 19:54:29 +00001202 xmlgen = XMLGenerator(result)
1203 parser.setContentHandler(xmlgen)
1204 parser.reset()
1205
1206 parser.feed("<doc>")
1207 parser.feed("text")
1208 parser.feed("</doc>")
1209 parser.close()
1210
Serhiy Storchaka88efc522013-02-10 14:29:52 +02001211 self.assertEqual(result.getvalue(), start + b"<doc>text</doc>")
Guido van Rossumd8faa362007-04-27 19:54:29 +00001212
1213 # ===== Locator support
1214
1215 def test_expat_locator_noinfo(self):
Serhiy Storchaka88efc522013-02-10 14:29:52 +02001216 result = BytesIO()
Guido van Rossumd8faa362007-04-27 19:54:29 +00001217 xmlgen = XMLGenerator(result)
1218 parser = create_parser()
1219 parser.setContentHandler(xmlgen)
1220
1221 parser.feed("<doc>")
1222 parser.feed("</doc>")
1223 parser.close()
1224
Ezio Melottib3aedd42010-11-20 19:04:17 +00001225 self.assertEqual(parser.getSystemId(), None)
1226 self.assertEqual(parser.getPublicId(), None)
1227 self.assertEqual(parser.getLineNumber(), 1)
Guido van Rossumd8faa362007-04-27 19:54:29 +00001228
Benjamin Petersona7f4f5a2008-09-04 02:22:52 +00001229 def test_expat_locator_withinfo(self):
Serhiy Storchaka88efc522013-02-10 14:29:52 +02001230 result = BytesIO()
Guido van Rossumd8faa362007-04-27 19:54:29 +00001231 xmlgen = XMLGenerator(result)
1232 parser = create_parser()
1233 parser.setContentHandler(xmlgen)
Florent Xiclunaf15351d2010-03-13 23:24:31 +00001234 parser.parse(TEST_XMLFILE)
Guido van Rossumd8faa362007-04-27 19:54:29 +00001235
Ezio Melottib3aedd42010-11-20 19:04:17 +00001236 self.assertEqual(parser.getSystemId(), TEST_XMLFILE)
1237 self.assertEqual(parser.getPublicId(), None)
Lars Gustäbel2fc52942000-10-24 15:35:07 +00001238
Serhiy Storchaka1a4ed4c2013-02-02 12:17:05 +02001239 @requires_nonascii_filenames
Serhiy Storchakad5202392013-02-02 10:31:17 +02001240 def test_expat_locator_withinfo_nonascii(self):
1241 fname = support.TESTFN_UNICODE
1242 shutil.copyfile(TEST_XMLFILE, fname)
1243 self.addCleanup(support.unlink, fname)
1244
Serhiy Storchaka88efc522013-02-10 14:29:52 +02001245 result = BytesIO()
Serhiy Storchakad5202392013-02-02 10:31:17 +02001246 xmlgen = XMLGenerator(result)
1247 parser = create_parser()
1248 parser.setContentHandler(xmlgen)
1249 parser.parse(fname)
1250
1251 self.assertEqual(parser.getSystemId(), fname)
1252 self.assertEqual(parser.getPublicId(), None)
1253
Martin v. Löwis80670bc2000-10-06 21:13:23 +00001254
1255# ===========================================================================
1256#
1257# error reporting
1258#
1259# ===========================================================================
1260
Guido van Rossumd8faa362007-04-27 19:54:29 +00001261class ErrorReportingTest(unittest.TestCase):
1262 def test_expat_inpsource_location(self):
1263 parser = create_parser()
1264 parser.setContentHandler(ContentHandler()) # do nothing
1265 source = InputSource()
Serhiy Storchaka88efc522013-02-10 14:29:52 +02001266 source.setByteStream(BytesIO(b"<foo bar foobar>")) #ill-formed
Guido van Rossumd8faa362007-04-27 19:54:29 +00001267 name = "a file name"
1268 source.setSystemId(name)
1269 try:
1270 parser.parse(source)
1271 self.fail()
1272 except SAXException as e:
Ezio Melottib3aedd42010-11-20 19:04:17 +00001273 self.assertEqual(e.getSystemId(), name)
Martin v. Löwis80670bc2000-10-06 21:13:23 +00001274
Guido van Rossumd8faa362007-04-27 19:54:29 +00001275 def test_expat_incomplete(self):
1276 parser = create_parser()
1277 parser.setContentHandler(ContentHandler()) # do nothing
1278 self.assertRaises(SAXParseException, parser.parse, StringIO("<foo>"))
Serhiy Storchakaab914782015-05-06 09:36:06 +03001279 self.assertEqual(parser.getColumnNumber(), 5)
1280 self.assertEqual(parser.getLineNumber(), 1)
Martin v. Löwis80670bc2000-10-06 21:13:23 +00001281
Guido van Rossumd8faa362007-04-27 19:54:29 +00001282 def test_sax_parse_exception_str(self):
1283 # pass various values from a locator to the SAXParseException to
1284 # make sure that the __str__() doesn't fall apart when None is
1285 # passed instead of an integer line and column number
1286 #
1287 # use "normal" values for the locator:
1288 str(SAXParseException("message", None,
1289 self.DummyLocator(1, 1)))
1290 # use None for the line number:
1291 str(SAXParseException("message", None,
1292 self.DummyLocator(None, 1)))
1293 # use None for the column number:
1294 str(SAXParseException("message", None,
1295 self.DummyLocator(1, None)))
1296 # use None for both:
1297 str(SAXParseException("message", None,
1298 self.DummyLocator(None, None)))
Fred Drake6fd0b0d2004-03-20 08:15:30 +00001299
Guido van Rossumd8faa362007-04-27 19:54:29 +00001300 class DummyLocator:
1301 def __init__(self, lineno, colno):
1302 self._lineno = lineno
1303 self._colno = colno
Fred Drake6fd0b0d2004-03-20 08:15:30 +00001304
Guido van Rossumd8faa362007-04-27 19:54:29 +00001305 def getPublicId(self):
1306 return "pubid"
Fred Drake6fd0b0d2004-03-20 08:15:30 +00001307
Guido van Rossumd8faa362007-04-27 19:54:29 +00001308 def getSystemId(self):
1309 return "sysid"
Fred Drake6fd0b0d2004-03-20 08:15:30 +00001310
Guido van Rossumd8faa362007-04-27 19:54:29 +00001311 def getLineNumber(self):
1312 return self._lineno
Fred Drake6fd0b0d2004-03-20 08:15:30 +00001313
Guido van Rossumd8faa362007-04-27 19:54:29 +00001314 def getColumnNumber(self):
1315 return self._colno
Martin v. Löwis80670bc2000-10-06 21:13:23 +00001316
Lars Gustäbelab647872000-09-24 18:40:52 +00001317# ===========================================================================
1318#
1319# xmlreader tests
1320#
1321# ===========================================================================
1322
Guido van Rossumd8faa362007-04-27 19:54:29 +00001323class XmlReaderTest(XmlTestBase):
Lars Gustäbelab647872000-09-24 18:40:52 +00001324
Guido van Rossumd8faa362007-04-27 19:54:29 +00001325 # ===== AttributesImpl
1326 def test_attrs_empty(self):
1327 self.verify_empty_attrs(AttributesImpl({}))
Lars Gustäbelab647872000-09-24 18:40:52 +00001328
Guido van Rossumd8faa362007-04-27 19:54:29 +00001329 def test_attrs_wattr(self):
1330 self.verify_attrs_wattr(AttributesImpl({"attr" : "val"}))
Lars Gustäbelab647872000-09-24 18:40:52 +00001331
Guido van Rossumd8faa362007-04-27 19:54:29 +00001332 def test_nsattrs_empty(self):
1333 self.verify_empty_nsattrs(AttributesNSImpl({}, {}))
Lars Gustäbelab647872000-09-24 18:40:52 +00001334
Guido van Rossumd8faa362007-04-27 19:54:29 +00001335 def test_nsattrs_wattr(self):
1336 attrs = AttributesNSImpl({(ns_uri, "attr") : "val"},
1337 {(ns_uri, "attr") : "ns:attr"})
Fred Drake004d5e62000-10-23 17:22:08 +00001338
Ezio Melottib3aedd42010-11-20 19:04:17 +00001339 self.assertEqual(attrs.getLength(), 1)
1340 self.assertEqual(attrs.getNames(), [(ns_uri, "attr")])
1341 self.assertEqual(attrs.getQNames(), ["ns:attr"])
1342 self.assertEqual(len(attrs), 1)
Benjamin Peterson577473f2010-01-19 00:09:57 +00001343 self.assertIn((ns_uri, "attr"), attrs)
Ezio Melottib3aedd42010-11-20 19:04:17 +00001344 self.assertEqual(list(attrs.keys()), [(ns_uri, "attr")])
1345 self.assertEqual(attrs.get((ns_uri, "attr")), "val")
1346 self.assertEqual(attrs.get((ns_uri, "attr"), 25), "val")
1347 self.assertEqual(list(attrs.items()), [((ns_uri, "attr"), "val")])
1348 self.assertEqual(list(attrs.values()), ["val"])
1349 self.assertEqual(attrs.getValue((ns_uri, "attr")), "val")
1350 self.assertEqual(attrs.getValueByQName("ns:attr"), "val")
1351 self.assertEqual(attrs.getNameByQName("ns:attr"), (ns_uri, "attr"))
1352 self.assertEqual(attrs[(ns_uri, "attr")], "val")
1353 self.assertEqual(attrs.getQNameByName((ns_uri, "attr")), "ns:attr")
Fred Drake004d5e62000-10-23 17:22:08 +00001354
Lars Gustäbelab647872000-09-24 18:40:52 +00001355
Christian Heimesbbe741d2008-03-28 10:53:29 +00001356def test_main():
Guido van Rossumd8faa362007-04-27 19:54:29 +00001357 run_unittest(MakeParserTest,
Serhiy Storchaka13e41c52015-04-02 23:05:57 +03001358 ParseTest,
Guido van Rossumd8faa362007-04-27 19:54:29 +00001359 SaxutilsTest,
Serhiy Storchakaaa9563c2015-04-02 20:55:59 +03001360 PrepareInputSourceTest,
Serhiy Storchaka88efc522013-02-10 14:29:52 +02001361 StringXmlgenTest,
1362 BytesXmlgenTest,
1363 WriterXmlgenTest,
Georg Brandlc502df42013-05-12 11:41:12 +02001364 StreamWriterXmlgenTest,
1365 StreamReaderWriterXmlgenTest,
Guido van Rossumd8faa362007-04-27 19:54:29 +00001366 ExpatReaderTest,
1367 ErrorReportingTest,
1368 XmlReaderTest)
Lars Gustäbelb7536d52000-09-24 18:53:56 +00001369
Guido van Rossumd8faa362007-04-27 19:54:29 +00001370if __name__ == "__main__":
Christian Heimesbbe741d2008-03-28 10:53:29 +00001371 test_main()