blob: 894d86ac71f03c79161cf6e27b55f5a0cb328f3b [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 Storchaka13e41c52015-04-02 23:05:57 +030020import gc
Serhiy Storchaka1a4ed4c2013-02-02 12:17:05 +020021import os.path
Serhiy Storchakad5202392013-02-02 10:31:17 +020022import shutil
Christian Heimes17b1d5d2018-09-23 09:50:25 +020023from urllib.error import URLError
Serhiy Storchakad5202392013-02-02 10:31:17 +020024from test import support
Serhiy Storchaka13e41c52015-04-02 23:05:57 +030025from test.support import findfile, run_unittest, 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
186 def test_parse_InputSource(self):
187 # accept data without declared but with explicitly specified encoding
188 make_xml_file(self.data, 'iso-8859-1', None)
189 with open(TESTFN, 'rb') as f:
190 input = InputSource()
191 input.setByteStream(f)
192 input.setEncoding('iso-8859-1')
193 self.check_parse(input)
194
Victor Stinneref9c0e72017-05-05 09:46:47 +0200195 def test_parse_close_source(self):
196 builtin_open = open
197 fileobj = None
198
199 def mock_open(*args):
200 nonlocal fileobj
201 fileobj = builtin_open(*args)
202 return fileobj
203
204 with mock.patch('xml.sax.saxutils.open', side_effect=mock_open):
205 make_xml_file(self.data, 'iso-8859-1', None)
206 with self.assertRaises(SAXException):
207 self.check_parse(TESTFN)
208 self.assertTrue(fileobj.closed)
209
Serhiy Storchaka13e41c52015-04-02 23:05:57 +0300210 def check_parseString(self, s):
211 from xml.sax import parseString
212 result = StringIO()
213 parseString(s, XMLGenerator(result, 'utf-8'))
214 self.assertEqual(result.getvalue(), xml_str(self.data, 'utf-8'))
215
Serhiy Storchaka778db282015-04-04 10:12:26 +0300216 def test_parseString_text(self):
217 encodings = ('us-ascii', 'iso-8859-1', 'utf-8',
218 'utf-16', 'utf-16le', 'utf-16be')
219 for encoding in encodings:
220 self.check_parseString(xml_str(self.data, encoding))
221 self.check_parseString(self.data)
222
Serhiy Storchaka13e41c52015-04-02 23:05:57 +0300223 def test_parseString_bytes(self):
224 # UTF-8 is default encoding, US-ASCII is compatible with UTF-8,
225 # UTF-16 is autodetected
226 encodings = ('us-ascii', 'utf-8', 'utf-16', 'utf-16le', 'utf-16be')
227 for encoding in encodings:
228 self.check_parseString(xml_bytes(self.data, encoding))
229 self.check_parseString(xml_bytes(self.data, encoding, None))
230 # accept UTF-8 with BOM
231 self.check_parseString(xml_bytes(self.data, 'utf-8-sig', 'utf-8'))
232 self.check_parseString(xml_bytes(self.data, 'utf-8-sig', None))
233 # accept data with declared encoding
234 self.check_parseString(xml_bytes(self.data, 'iso-8859-1'))
235 # fail on non-UTF-8 incompatible data without declared encoding
236 with self.assertRaises(SAXException):
237 self.check_parseString(xml_bytes(self.data, 'iso-8859-1', None))
238
Guido van Rossumd8faa362007-04-27 19:54:29 +0000239class MakeParserTest(unittest.TestCase):
240 def test_make_parser2(self):
Lars Gustäbel2fc52942000-10-24 15:35:07 +0000241 # Creating parsers several times in a row should succeed.
242 # Testing this because there have been failures of this kind
243 # before.
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000244 from xml.sax import make_parser
Lars Gustäbel2fc52942000-10-24 15:35:07 +0000245 p = make_parser()
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000246 from xml.sax import make_parser
Lars Gustäbel2fc52942000-10-24 15:35:07 +0000247 p = make_parser()
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()
Tim Petersd2bf3b72001-01-18 02:22:22 +0000256
Andrés Delfinoa6dc5312018-10-26 11:56:57 -0300257 def test_make_parser3(self):
258 # Testing that make_parser can handle different types of
259 # iterables.
260 make_parser(['module'])
261 make_parser(('module', ))
262 make_parser({'module'})
263 make_parser(frozenset({'module'}))
264 make_parser({'module': None})
265 make_parser(iter(['module']))
266
267 def test_make_parser4(self):
268 # Testing that make_parser can handle empty iterables.
269 make_parser([])
270 make_parser(tuple())
271 make_parser(set())
272 make_parser(frozenset())
273 make_parser({})
274 make_parser(iter([]))
275
276 def test_make_parser5(self):
277 # Testing that make_parser can handle iterables with more than
278 # one item.
279 make_parser(['module1', 'module2'])
280 make_parser(('module1', 'module2'))
281 make_parser({'module1', 'module2'})
282 make_parser(frozenset({'module1', 'module2'}))
283 make_parser({'module1': None, 'module2': None})
284 make_parser(iter(['module1', 'module2']))
Tim Petersd2bf3b72001-01-18 02:22:22 +0000285
Lars Gustäbel96753b32000-09-24 12:24:24 +0000286# ===========================================================================
287#
288# saxutils tests
289#
290# ===========================================================================
291
Guido van Rossumd8faa362007-04-27 19:54:29 +0000292class SaxutilsTest(unittest.TestCase):
293 # ===== escape
294 def test_escape_basic(self):
Ezio Melottib3aedd42010-11-20 19:04:17 +0000295 self.assertEqual(escape("Donald Duck & Co"), "Donald Duck &amp; Co")
Lars Gustäbel96753b32000-09-24 12:24:24 +0000296
Guido van Rossumd8faa362007-04-27 19:54:29 +0000297 def test_escape_all(self):
Ezio Melottib3aedd42010-11-20 19:04:17 +0000298 self.assertEqual(escape("<Donald Duck & Co>"),
299 "&lt;Donald Duck &amp; Co&gt;")
Lars Gustäbel96753b32000-09-24 12:24:24 +0000300
Guido van Rossumd8faa362007-04-27 19:54:29 +0000301 def test_escape_extra(self):
Ezio Melottib3aedd42010-11-20 19:04:17 +0000302 self.assertEqual(escape("Hei på deg", {"å" : "&aring;"}),
303 "Hei p&aring; deg")
Lars Gustäbel96753b32000-09-24 12:24:24 +0000304
Guido van Rossumd8faa362007-04-27 19:54:29 +0000305 # ===== unescape
306 def test_unescape_basic(self):
Ezio Melottib3aedd42010-11-20 19:04:17 +0000307 self.assertEqual(unescape("Donald Duck &amp; Co"), "Donald Duck & Co")
Lars Gustäbel96753b32000-09-24 12:24:24 +0000308
Guido van Rossumd8faa362007-04-27 19:54:29 +0000309 def test_unescape_all(self):
Ezio Melottib3aedd42010-11-20 19:04:17 +0000310 self.assertEqual(unescape("&lt;Donald Duck &amp; Co&gt;"),
311 "<Donald Duck & Co>")
Martin v. Löwis74b51ac2002-10-26 14:50:45 +0000312
Guido van Rossumd8faa362007-04-27 19:54:29 +0000313 def test_unescape_extra(self):
Ezio Melottib3aedd42010-11-20 19:04:17 +0000314 self.assertEqual(unescape("Hei på deg", {"å" : "&aring;"}),
315 "Hei p&aring; deg")
Martin v. Löwis74b51ac2002-10-26 14:50:45 +0000316
Guido van Rossumd8faa362007-04-27 19:54:29 +0000317 def test_unescape_amp_extra(self):
Ezio Melottib3aedd42010-11-20 19:04:17 +0000318 self.assertEqual(unescape("&amp;foo;", {"&foo;": "splat"}), "&foo;")
Martin v. Löwis74b51ac2002-10-26 14:50:45 +0000319
Guido van Rossumd8faa362007-04-27 19:54:29 +0000320 # ===== quoteattr
321 def test_quoteattr_basic(self):
Ezio Melottib3aedd42010-11-20 19:04:17 +0000322 self.assertEqual(quoteattr("Donald Duck & Co"),
323 '"Donald Duck &amp; Co"')
Martin v. Löwis74b51ac2002-10-26 14:50:45 +0000324
Guido van Rossumd8faa362007-04-27 19:54:29 +0000325 def test_single_quoteattr(self):
Ezio Melottib3aedd42010-11-20 19:04:17 +0000326 self.assertEqual(quoteattr('Includes "double" quotes'),
327 '\'Includes "double" quotes\'')
Fred Drake32f3add2002-10-28 17:58:48 +0000328
Guido van Rossumd8faa362007-04-27 19:54:29 +0000329 def test_double_quoteattr(self):
Ezio Melottib3aedd42010-11-20 19:04:17 +0000330 self.assertEqual(quoteattr("Includes 'single' quotes"),
331 "\"Includes 'single' quotes\"")
Fred Drakeacd32d32001-07-19 16:10:15 +0000332
Guido van Rossumd8faa362007-04-27 19:54:29 +0000333 def test_single_double_quoteattr(self):
Ezio Melottib3aedd42010-11-20 19:04:17 +0000334 self.assertEqual(quoteattr("Includes 'single' and \"double\" quotes"),
335 "\"Includes 'single' and &quot;double&quot; quotes\"")
Fred Drakeacd32d32001-07-19 16:10:15 +0000336
Guido van Rossumd8faa362007-04-27 19:54:29 +0000337 # ===== make_parser
338 def test_make_parser(self):
Martin v. Löwis962c9e72000-10-06 17:41:52 +0000339 # Creating a parser should succeed - it should fall back
340 # to the expatreader
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000341 p = make_parser(['xml.parsers.no_such_parser'])
Martin v. Löwis962c9e72000-10-06 17:41:52 +0000342
343
Serhiy Storchakaaa9563c2015-04-02 20:55:59 +0300344class PrepareInputSourceTest(unittest.TestCase):
345
346 def setUp(self):
347 self.file = support.TESTFN
348 with open(self.file, "w") as tmp:
349 tmp.write("This was read from a file.")
350
351 def tearDown(self):
352 support.unlink(self.file)
353
354 def make_byte_stream(self):
355 return BytesIO(b"This is a byte stream.")
356
Serhiy Storchaka61de0872015-04-02 21:00:13 +0300357 def make_character_stream(self):
358 return StringIO("This is a character stream.")
359
Serhiy Storchakaaa9563c2015-04-02 20:55:59 +0300360 def checkContent(self, stream, content):
361 self.assertIsNotNone(stream)
362 self.assertEqual(stream.read(), content)
363 stream.close()
364
365
Serhiy Storchaka61de0872015-04-02 21:00:13 +0300366 def test_character_stream(self):
367 # If the source is an InputSource with a character stream, use it.
368 src = InputSource(self.file)
369 src.setCharacterStream(self.make_character_stream())
370 prep = prepare_input_source(src)
371 self.assertIsNone(prep.getByteStream())
372 self.checkContent(prep.getCharacterStream(),
373 "This is a character stream.")
374
Serhiy Storchakaaa9563c2015-04-02 20:55:59 +0300375 def test_byte_stream(self):
376 # If the source is an InputSource that does not have a character
377 # stream but does have a byte stream, use the byte stream.
378 src = InputSource(self.file)
379 src.setByteStream(self.make_byte_stream())
380 prep = prepare_input_source(src)
381 self.assertIsNone(prep.getCharacterStream())
382 self.checkContent(prep.getByteStream(),
383 b"This is a byte stream.")
384
385 def test_system_id(self):
386 # If the source is an InputSource that has neither a character
387 # stream nor a byte stream, open the system ID.
388 src = InputSource(self.file)
389 prep = prepare_input_source(src)
390 self.assertIsNone(prep.getCharacterStream())
391 self.checkContent(prep.getByteStream(),
392 b"This was read from a file.")
393
394 def test_string(self):
395 # If the source is a string, use it as a system ID and open it.
396 prep = prepare_input_source(self.file)
397 self.assertIsNone(prep.getCharacterStream())
398 self.checkContent(prep.getByteStream(),
399 b"This was read from a file.")
400
401 def test_binary_file(self):
402 # If the source is a binary file-like object, use it as a byte
403 # stream.
404 prep = prepare_input_source(self.make_byte_stream())
405 self.assertIsNone(prep.getCharacterStream())
406 self.checkContent(prep.getByteStream(),
407 b"This is a byte stream.")
408
Serhiy Storchaka61de0872015-04-02 21:00:13 +0300409 def test_text_file(self):
410 # If the source is a text file-like object, use it as a character
411 # stream.
412 prep = prepare_input_source(self.make_character_stream())
413 self.assertIsNone(prep.getByteStream())
414 self.checkContent(prep.getCharacterStream(),
415 "This is a character stream.")
416
Serhiy Storchakaaa9563c2015-04-02 20:55:59 +0300417
Lars Gustäbel96753b32000-09-24 12:24:24 +0000418# ===== XMLGenerator
419
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200420class XmlgenTest:
Guido van Rossumd8faa362007-04-27 19:54:29 +0000421 def test_xmlgen_basic(self):
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200422 result = self.ioclass()
Guido van Rossumd8faa362007-04-27 19:54:29 +0000423 gen = XMLGenerator(result)
424 gen.startDocument()
425 gen.startElement("doc", {})
426 gen.endElement("doc")
427 gen.endDocument()
Lars Gustäbel96753b32000-09-24 12:24:24 +0000428
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200429 self.assertEqual(result.getvalue(), self.xml("<doc></doc>"))
Lars Gustäbel96753b32000-09-24 12:24:24 +0000430
R. David Murraya90032a2010-10-17 22:46:45 +0000431 def test_xmlgen_basic_empty(self):
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200432 result = self.ioclass()
R. David Murraya90032a2010-10-17 22:46:45 +0000433 gen = XMLGenerator(result, short_empty_elements=True)
434 gen.startDocument()
435 gen.startElement("doc", {})
436 gen.endElement("doc")
437 gen.endDocument()
438
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200439 self.assertEqual(result.getvalue(), self.xml("<doc/>"))
R. David Murraya90032a2010-10-17 22:46:45 +0000440
Guido van Rossumd8faa362007-04-27 19:54:29 +0000441 def test_xmlgen_content(self):
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200442 result = self.ioclass()
Guido van Rossumd8faa362007-04-27 19:54:29 +0000443 gen = XMLGenerator(result)
Fred Drake004d5e62000-10-23 17:22:08 +0000444
Guido van Rossumd8faa362007-04-27 19:54:29 +0000445 gen.startDocument()
446 gen.startElement("doc", {})
447 gen.characters("huhei")
448 gen.endElement("doc")
449 gen.endDocument()
Lars Gustäbel96753b32000-09-24 12:24:24 +0000450
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200451 self.assertEqual(result.getvalue(), self.xml("<doc>huhei</doc>"))
Lars Gustäbel96753b32000-09-24 12:24:24 +0000452
R. David Murraya90032a2010-10-17 22:46:45 +0000453 def test_xmlgen_content_empty(self):
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200454 result = self.ioclass()
R. David Murraya90032a2010-10-17 22:46:45 +0000455 gen = XMLGenerator(result, short_empty_elements=True)
456
457 gen.startDocument()
458 gen.startElement("doc", {})
459 gen.characters("huhei")
460 gen.endElement("doc")
461 gen.endDocument()
462
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200463 self.assertEqual(result.getvalue(), self.xml("<doc>huhei</doc>"))
R. David Murraya90032a2010-10-17 22:46:45 +0000464
Guido van Rossumd8faa362007-04-27 19:54:29 +0000465 def test_xmlgen_pi(self):
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200466 result = self.ioclass()
Guido van Rossumd8faa362007-04-27 19:54:29 +0000467 gen = XMLGenerator(result)
Fred Drake004d5e62000-10-23 17:22:08 +0000468
Guido van Rossumd8faa362007-04-27 19:54:29 +0000469 gen.startDocument()
470 gen.processingInstruction("test", "data")
471 gen.startElement("doc", {})
472 gen.endElement("doc")
473 gen.endDocument()
Lars Gustäbel96753b32000-09-24 12:24:24 +0000474
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200475 self.assertEqual(result.getvalue(),
476 self.xml("<?test data?><doc></doc>"))
Lars Gustäbel96753b32000-09-24 12:24:24 +0000477
Guido van Rossumd8faa362007-04-27 19:54:29 +0000478 def test_xmlgen_content_escape(self):
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200479 result = self.ioclass()
Guido van Rossumd8faa362007-04-27 19:54:29 +0000480 gen = XMLGenerator(result)
Fred Drake004d5e62000-10-23 17:22:08 +0000481
Guido van Rossumd8faa362007-04-27 19:54:29 +0000482 gen.startDocument()
483 gen.startElement("doc", {})
484 gen.characters("<huhei&")
485 gen.endElement("doc")
486 gen.endDocument()
Lars Gustäbel96753b32000-09-24 12:24:24 +0000487
Ezio Melottib3aedd42010-11-20 19:04:17 +0000488 self.assertEqual(result.getvalue(),
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200489 self.xml("<doc>&lt;huhei&amp;</doc>"))
Lars Gustäbel96753b32000-09-24 12:24:24 +0000490
Guido van Rossumd8faa362007-04-27 19:54:29 +0000491 def test_xmlgen_attr_escape(self):
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200492 result = self.ioclass()
Guido van Rossumd8faa362007-04-27 19:54:29 +0000493 gen = XMLGenerator(result)
Fred Drakec9fadf92001-08-07 19:17:06 +0000494
Guido van Rossumd8faa362007-04-27 19:54:29 +0000495 gen.startDocument()
496 gen.startElement("doc", {"a": '"'})
497 gen.startElement("e", {"a": "'"})
498 gen.endElement("e")
499 gen.startElement("e", {"a": "'\""})
500 gen.endElement("e")
501 gen.startElement("e", {"a": "\n\r\t"})
502 gen.endElement("e")
503 gen.endElement("doc")
504 gen.endDocument()
Fred Drakec9fadf92001-08-07 19:17:06 +0000505
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200506 self.assertEqual(result.getvalue(), self.xml(
507 "<doc a='\"'><e a=\"'\"></e>"
508 "<e a=\"'&quot;\"></e>"
509 "<e a=\"&#10;&#13;&#9;\"></e></doc>"))
510
511 def test_xmlgen_encoding(self):
512 encodings = ('iso-8859-15', 'utf-8', 'utf-8-sig',
513 'utf-16', 'utf-16be', 'utf-16le',
514 'utf-32', 'utf-32be', 'utf-32le')
515 for encoding in encodings:
516 result = self.ioclass()
517 gen = XMLGenerator(result, encoding=encoding)
518
519 gen.startDocument()
520 gen.startElement("doc", {"a": '\u20ac'})
521 gen.characters("\u20ac")
522 gen.endElement("doc")
523 gen.endDocument()
524
525 self.assertEqual(result.getvalue(),
526 self.xml('<doc a="\u20ac">\u20ac</doc>', encoding=encoding))
527
528 def test_xmlgen_unencodable(self):
529 result = self.ioclass()
530 gen = XMLGenerator(result, encoding='ascii')
531
532 gen.startDocument()
533 gen.startElement("doc", {"a": '\u20ac'})
534 gen.characters("\u20ac")
535 gen.endElement("doc")
536 gen.endDocument()
537
538 self.assertEqual(result.getvalue(),
539 self.xml('<doc a="&#8364;">&#8364;</doc>', encoding='ascii'))
Fred Drakec9fadf92001-08-07 19:17:06 +0000540
Guido van Rossumd8faa362007-04-27 19:54:29 +0000541 def test_xmlgen_ignorable(self):
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200542 result = self.ioclass()
Guido van Rossumd8faa362007-04-27 19:54:29 +0000543 gen = XMLGenerator(result)
Fred Drake004d5e62000-10-23 17:22:08 +0000544
Guido van Rossumd8faa362007-04-27 19:54:29 +0000545 gen.startDocument()
546 gen.startElement("doc", {})
547 gen.ignorableWhitespace(" ")
548 gen.endElement("doc")
549 gen.endDocument()
Lars Gustäbel96753b32000-09-24 12:24:24 +0000550
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200551 self.assertEqual(result.getvalue(), self.xml("<doc> </doc>"))
Lars Gustäbel96753b32000-09-24 12:24:24 +0000552
R. David Murraya90032a2010-10-17 22:46:45 +0000553 def test_xmlgen_ignorable_empty(self):
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200554 result = self.ioclass()
R. David Murraya90032a2010-10-17 22:46:45 +0000555 gen = XMLGenerator(result, short_empty_elements=True)
556
557 gen.startDocument()
558 gen.startElement("doc", {})
559 gen.ignorableWhitespace(" ")
560 gen.endElement("doc")
561 gen.endDocument()
562
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200563 self.assertEqual(result.getvalue(), self.xml("<doc> </doc>"))
R. David Murraya90032a2010-10-17 22:46:45 +0000564
Serhiy Storchaka3eab6b32013-05-12 17:31:16 +0300565 def test_xmlgen_encoding_bytes(self):
566 encodings = ('iso-8859-15', 'utf-8', 'utf-8-sig',
567 'utf-16', 'utf-16be', 'utf-16le',
568 'utf-32', 'utf-32be', 'utf-32le')
569 for encoding in encodings:
570 result = self.ioclass()
571 gen = XMLGenerator(result, encoding=encoding)
572
573 gen.startDocument()
574 gen.startElement("doc", {"a": '\u20ac'})
575 gen.characters("\u20ac".encode(encoding))
576 gen.ignorableWhitespace(" ".encode(encoding))
577 gen.endElement("doc")
578 gen.endDocument()
579
580 self.assertEqual(result.getvalue(),
581 self.xml('<doc a="\u20ac">\u20ac </doc>', encoding=encoding))
582
Guido van Rossumd8faa362007-04-27 19:54:29 +0000583 def test_xmlgen_ns(self):
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200584 result = self.ioclass()
Guido van Rossumd8faa362007-04-27 19:54:29 +0000585 gen = XMLGenerator(result)
Lars Gustäbel96753b32000-09-24 12:24:24 +0000586
Guido van Rossumd8faa362007-04-27 19:54:29 +0000587 gen.startDocument()
588 gen.startPrefixMapping("ns1", ns_uri)
589 gen.startElementNS((ns_uri, "doc"), "ns1:doc", {})
590 # add an unqualified name
591 gen.startElementNS((None, "udoc"), None, {})
592 gen.endElementNS((None, "udoc"), None)
593 gen.endElementNS((ns_uri, "doc"), "ns1:doc")
594 gen.endPrefixMapping("ns1")
595 gen.endDocument()
Fred Drake004d5e62000-10-23 17:22:08 +0000596
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200597 self.assertEqual(result.getvalue(), self.xml(
598 '<ns1:doc xmlns:ns1="%s"><udoc></udoc></ns1:doc>' %
Guido van Rossumd8faa362007-04-27 19:54:29 +0000599 ns_uri))
Lars Gustäbel96753b32000-09-24 12:24:24 +0000600
R. David Murraya90032a2010-10-17 22:46:45 +0000601 def test_xmlgen_ns_empty(self):
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200602 result = self.ioclass()
R. David Murraya90032a2010-10-17 22:46:45 +0000603 gen = XMLGenerator(result, short_empty_elements=True)
604
605 gen.startDocument()
606 gen.startPrefixMapping("ns1", ns_uri)
607 gen.startElementNS((ns_uri, "doc"), "ns1:doc", {})
608 # add an unqualified name
609 gen.startElementNS((None, "udoc"), None, {})
610 gen.endElementNS((None, "udoc"), None)
611 gen.endElementNS((ns_uri, "doc"), "ns1:doc")
612 gen.endPrefixMapping("ns1")
613 gen.endDocument()
614
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200615 self.assertEqual(result.getvalue(), self.xml(
616 '<ns1:doc xmlns:ns1="%s"><udoc/></ns1:doc>' %
R. David Murraya90032a2010-10-17 22:46:45 +0000617 ns_uri))
618
Guido van Rossumd8faa362007-04-27 19:54:29 +0000619 def test_1463026_1(self):
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200620 result = self.ioclass()
Guido van Rossumd8faa362007-04-27 19:54:29 +0000621 gen = XMLGenerator(result)
Thomas Wouterscf297e42007-02-23 15:07:44 +0000622
Guido van Rossumd8faa362007-04-27 19:54:29 +0000623 gen.startDocument()
624 gen.startElementNS((None, 'a'), 'a', {(None, 'b'):'c'})
625 gen.endElementNS((None, 'a'), 'a')
626 gen.endDocument()
Thomas Wouterscf297e42007-02-23 15:07:44 +0000627
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200628 self.assertEqual(result.getvalue(), self.xml('<a b="c"></a>'))
Thomas Wouterscf297e42007-02-23 15:07:44 +0000629
R. David Murraya90032a2010-10-17 22:46:45 +0000630 def test_1463026_1_empty(self):
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200631 result = self.ioclass()
R. David Murraya90032a2010-10-17 22:46:45 +0000632 gen = XMLGenerator(result, short_empty_elements=True)
633
634 gen.startDocument()
635 gen.startElementNS((None, 'a'), 'a', {(None, 'b'):'c'})
636 gen.endElementNS((None, 'a'), 'a')
637 gen.endDocument()
638
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200639 self.assertEqual(result.getvalue(), self.xml('<a b="c"/>'))
R. David Murraya90032a2010-10-17 22:46:45 +0000640
Guido van Rossumd8faa362007-04-27 19:54:29 +0000641 def test_1463026_2(self):
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200642 result = self.ioclass()
Guido van Rossumd8faa362007-04-27 19:54:29 +0000643 gen = XMLGenerator(result)
Thomas Wouterscf297e42007-02-23 15:07:44 +0000644
Guido van Rossumd8faa362007-04-27 19:54:29 +0000645 gen.startDocument()
646 gen.startPrefixMapping(None, 'qux')
647 gen.startElementNS(('qux', 'a'), 'a', {})
648 gen.endElementNS(('qux', 'a'), 'a')
649 gen.endPrefixMapping(None)
650 gen.endDocument()
Thomas Wouterscf297e42007-02-23 15:07:44 +0000651
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200652 self.assertEqual(result.getvalue(), self.xml('<a xmlns="qux"></a>'))
Thomas Wouterscf297e42007-02-23 15:07:44 +0000653
R. David Murraya90032a2010-10-17 22:46:45 +0000654 def test_1463026_2_empty(self):
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200655 result = self.ioclass()
R. David Murraya90032a2010-10-17 22:46:45 +0000656 gen = XMLGenerator(result, short_empty_elements=True)
657
658 gen.startDocument()
659 gen.startPrefixMapping(None, 'qux')
660 gen.startElementNS(('qux', 'a'), 'a', {})
661 gen.endElementNS(('qux', 'a'), 'a')
662 gen.endPrefixMapping(None)
663 gen.endDocument()
664
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200665 self.assertEqual(result.getvalue(), self.xml('<a xmlns="qux"/>'))
R. David Murraya90032a2010-10-17 22:46:45 +0000666
Guido van Rossumd8faa362007-04-27 19:54:29 +0000667 def test_1463026_3(self):
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200668 result = self.ioclass()
Guido van Rossumd8faa362007-04-27 19:54:29 +0000669 gen = XMLGenerator(result)
Thomas Wouterscf297e42007-02-23 15:07:44 +0000670
Guido van Rossumd8faa362007-04-27 19:54:29 +0000671 gen.startDocument()
672 gen.startPrefixMapping('my', 'qux')
673 gen.startElementNS(('qux', 'a'), 'a', {(None, 'b'):'c'})
674 gen.endElementNS(('qux', 'a'), 'a')
675 gen.endPrefixMapping('my')
676 gen.endDocument()
Thomas Wouterscf297e42007-02-23 15:07:44 +0000677
Ezio Melottib3aedd42010-11-20 19:04:17 +0000678 self.assertEqual(result.getvalue(),
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200679 self.xml('<my:a xmlns:my="qux" b="c"></my:a>'))
Lars Gustäbel96753b32000-09-24 12:24:24 +0000680
R. David Murraya90032a2010-10-17 22:46:45 +0000681 def test_1463026_3_empty(self):
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200682 result = self.ioclass()
R. David Murraya90032a2010-10-17 22:46:45 +0000683 gen = XMLGenerator(result, short_empty_elements=True)
684
685 gen.startDocument()
686 gen.startPrefixMapping('my', 'qux')
687 gen.startElementNS(('qux', 'a'), 'a', {(None, 'b'):'c'})
688 gen.endElementNS(('qux', 'a'), 'a')
689 gen.endPrefixMapping('my')
690 gen.endDocument()
691
Ezio Melottib3aedd42010-11-20 19:04:17 +0000692 self.assertEqual(result.getvalue(),
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200693 self.xml('<my:a xmlns:my="qux" b="c"/>'))
R. David Murraya90032a2010-10-17 22:46:45 +0000694
Antoine Pitrou6b03ee62010-10-27 18:33:30 +0000695 def test_5027_1(self):
696 # The xml prefix (as in xml:lang below) is reserved and bound by
697 # definition to http://www.w3.org/XML/1998/namespace. XMLGenerator had
Andrew Svetlov737fb892012-12-18 21:14:22 +0200698 # a bug whereby a KeyError is raised because this namespace is missing
Antoine Pitrou6b03ee62010-10-27 18:33:30 +0000699 # from a dictionary.
700 #
701 # This test demonstrates the bug by parsing a document.
702 test_xml = StringIO(
703 '<?xml version="1.0"?>'
704 '<a:g1 xmlns:a="http://example.com/ns">'
705 '<a:g2 xml:lang="en">Hello</a:g2>'
706 '</a:g1>')
707
708 parser = make_parser()
709 parser.setFeature(feature_namespaces, True)
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200710 result = self.ioclass()
Antoine Pitrou6b03ee62010-10-27 18:33:30 +0000711 gen = XMLGenerator(result)
712 parser.setContentHandler(gen)
713 parser.parse(test_xml)
714
Ezio Melottib3aedd42010-11-20 19:04:17 +0000715 self.assertEqual(result.getvalue(),
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200716 self.xml(
Ezio Melottib3aedd42010-11-20 19:04:17 +0000717 '<a:g1 xmlns:a="http://example.com/ns">'
718 '<a:g2 xml:lang="en">Hello</a:g2>'
719 '</a:g1>'))
Antoine Pitrou6b03ee62010-10-27 18:33:30 +0000720
721 def test_5027_2(self):
722 # The xml prefix (as in xml:lang below) is reserved and bound by
723 # definition to http://www.w3.org/XML/1998/namespace. XMLGenerator had
Andrew Svetlov737fb892012-12-18 21:14:22 +0200724 # a bug whereby a KeyError is raised because this namespace is missing
Antoine Pitrou6b03ee62010-10-27 18:33:30 +0000725 # from a dictionary.
726 #
727 # This test demonstrates the bug by direct manipulation of the
728 # XMLGenerator.
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200729 result = self.ioclass()
Antoine Pitrou6b03ee62010-10-27 18:33:30 +0000730 gen = XMLGenerator(result)
731
732 gen.startDocument()
733 gen.startPrefixMapping('a', 'http://example.com/ns')
734 gen.startElementNS(('http://example.com/ns', 'g1'), 'g1', {})
735 lang_attr = {('http://www.w3.org/XML/1998/namespace', 'lang'): 'en'}
736 gen.startElementNS(('http://example.com/ns', 'g2'), 'g2', lang_attr)
737 gen.characters('Hello')
738 gen.endElementNS(('http://example.com/ns', 'g2'), 'g2')
739 gen.endElementNS(('http://example.com/ns', 'g1'), 'g1')
740 gen.endPrefixMapping('a')
741 gen.endDocument()
742
Ezio Melottib3aedd42010-11-20 19:04:17 +0000743 self.assertEqual(result.getvalue(),
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200744 self.xml(
Ezio Melottib3aedd42010-11-20 19:04:17 +0000745 '<a:g1 xmlns:a="http://example.com/ns">'
746 '<a:g2 xml:lang="en">Hello</a:g2>'
747 '</a:g1>'))
Antoine Pitrou6b03ee62010-10-27 18:33:30 +0000748
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200749 def test_no_close_file(self):
750 result = self.ioclass()
751 def func(out):
752 gen = XMLGenerator(out)
753 gen.startDocument()
754 gen.startElement("doc", {})
755 func(result)
756 self.assertFalse(result.closed)
757
Serhiy Storchakaa5f13d22013-02-25 13:46:10 +0200758 def test_xmlgen_fragment(self):
759 result = self.ioclass()
760 gen = XMLGenerator(result)
761
762 # Don't call gen.startDocument()
763 gen.startElement("foo", {"a": "1.0"})
764 gen.characters("Hello")
765 gen.endElement("foo")
766 gen.startElement("bar", {"b": "2.0"})
767 gen.endElement("bar")
768 # Don't call gen.endDocument()
769
770 self.assertEqual(result.getvalue(),
771 self.xml('<foo a="1.0">Hello</foo><bar b="2.0"></bar>')[len(self.xml('')):])
772
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200773class StringXmlgenTest(XmlgenTest, unittest.TestCase):
774 ioclass = StringIO
775
776 def xml(self, doc, encoding='iso-8859-1'):
777 return '<?xml version="1.0" encoding="%s"?>\n%s' % (encoding, doc)
778
779 test_xmlgen_unencodable = None
780
781class BytesXmlgenTest(XmlgenTest, unittest.TestCase):
782 ioclass = BytesIO
783
784 def xml(self, doc, encoding='iso-8859-1'):
785 return ('<?xml version="1.0" encoding="%s"?>\n%s' %
786 (encoding, doc)).encode(encoding, 'xmlcharrefreplace')
787
788class WriterXmlgenTest(BytesXmlgenTest):
789 class ioclass(list):
790 write = list.append
791 closed = False
792
793 def seekable(self):
794 return True
795
796 def tell(self):
797 # return 0 at start and not 0 after start
798 return len(self)
799
800 def getvalue(self):
801 return b''.join(self)
802
Georg Brandlc502df42013-05-12 11:41:12 +0200803class StreamWriterXmlgenTest(XmlgenTest, unittest.TestCase):
804 def ioclass(self):
805 raw = BytesIO()
806 writer = codecs.getwriter('ascii')(raw, 'xmlcharrefreplace')
807 writer.getvalue = raw.getvalue
808 return writer
809
810 def xml(self, doc, encoding='iso-8859-1'):
811 return ('<?xml version="1.0" encoding="%s"?>\n%s' %
812 (encoding, doc)).encode('ascii', 'xmlcharrefreplace')
813
814class StreamReaderWriterXmlgenTest(XmlgenTest, unittest.TestCase):
815 fname = support.TESTFN + '-codecs'
816
817 def ioclass(self):
818 writer = codecs.open(self.fname, 'w', encoding='ascii',
819 errors='xmlcharrefreplace', buffering=0)
Antoine Pitrou2adb6fe2013-05-13 22:34:21 +0200820 def cleanup():
821 writer.close()
822 support.unlink(self.fname)
823 self.addCleanup(cleanup)
Richard Oudkerk90a24272013-05-18 18:11:30 +0100824 def getvalue():
825 # Windows will not let use reopen without first closing
826 writer.close()
827 with open(writer.name, 'rb') as f:
828 return f.read()
829 writer.getvalue = getvalue
Georg Brandlc502df42013-05-12 11:41:12 +0200830 return writer
831
Georg Brandlc502df42013-05-12 11:41:12 +0200832 def xml(self, doc, encoding='iso-8859-1'):
833 return ('<?xml version="1.0" encoding="%s"?>\n%s' %
834 (encoding, doc)).encode('ascii', 'xmlcharrefreplace')
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200835
836start = b'<?xml version="1.0" encoding="iso-8859-1"?>\n'
837
Fred Drake004d5e62000-10-23 17:22:08 +0000838
Guido van Rossumd8faa362007-04-27 19:54:29 +0000839class XMLFilterBaseTest(unittest.TestCase):
840 def test_filter_basic(self):
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200841 result = BytesIO()
Guido van Rossumd8faa362007-04-27 19:54:29 +0000842 gen = XMLGenerator(result)
843 filter = XMLFilterBase()
844 filter.setContentHandler(gen)
Lars Gustäbel96753b32000-09-24 12:24:24 +0000845
Guido van Rossumd8faa362007-04-27 19:54:29 +0000846 filter.startDocument()
847 filter.startElement("doc", {})
848 filter.characters("content")
849 filter.ignorableWhitespace(" ")
850 filter.endElement("doc")
851 filter.endDocument()
852
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200853 self.assertEqual(result.getvalue(), start + b"<doc>content </doc>")
Lars Gustäbel96753b32000-09-24 12:24:24 +0000854
855# ===========================================================================
856#
857# expatreader tests
858#
859# ===========================================================================
860
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200861with open(TEST_XMLFILE_OUT, 'rb') as f:
Benjamin Petersond5df36d2010-10-31 18:23:23 +0000862 xml_test_out = f.read()
Lars Gustäbelb7536d52000-09-24 18:53:56 +0000863
Guido van Rossumd8faa362007-04-27 19:54:29 +0000864class ExpatReaderTest(XmlTestBase):
Lars Gustäbelb7536d52000-09-24 18:53:56 +0000865
Guido van Rossumd8faa362007-04-27 19:54:29 +0000866 # ===== XMLReader support
Lars Gustäbelb7536d52000-09-24 18:53:56 +0000867
Serhiy Storchakaaa9563c2015-04-02 20:55:59 +0300868 def test_expat_binary_file(self):
Guido van Rossumd8faa362007-04-27 19:54:29 +0000869 parser = create_parser()
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200870 result = BytesIO()
Guido van Rossumd8faa362007-04-27 19:54:29 +0000871 xmlgen = XMLGenerator(result)
Lars Gustäbelb7536d52000-09-24 18:53:56 +0000872
Guido van Rossumd8faa362007-04-27 19:54:29 +0000873 parser.setContentHandler(xmlgen)
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200874 with open(TEST_XMLFILE, 'rb') as f:
Benjamin Petersond5df36d2010-10-31 18:23:23 +0000875 parser.parse(f)
Lars Gustäbelb7536d52000-09-24 18:53:56 +0000876
Ezio Melottib3aedd42010-11-20 19:04:17 +0000877 self.assertEqual(result.getvalue(), xml_test_out)
Lars Gustäbelb7536d52000-09-24 18:53:56 +0000878
Serhiy Storchakaaa9563c2015-04-02 20:55:59 +0300879 def test_expat_text_file(self):
880 parser = create_parser()
881 result = BytesIO()
882 xmlgen = XMLGenerator(result)
883
884 parser.setContentHandler(xmlgen)
885 with open(TEST_XMLFILE, 'rt', encoding='iso-8859-1') as f:
886 parser.parse(f)
887
888 self.assertEqual(result.getvalue(), xml_test_out)
889
Serhiy Storchaka1a4ed4c2013-02-02 12:17:05 +0200890 @requires_nonascii_filenames
Serhiy Storchakaaa9563c2015-04-02 20:55:59 +0300891 def test_expat_binary_file_nonascii(self):
Serhiy Storchakad5202392013-02-02 10:31:17 +0200892 fname = support.TESTFN_UNICODE
893 shutil.copyfile(TEST_XMLFILE, fname)
894 self.addCleanup(support.unlink, fname)
895
896 parser = create_parser()
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200897 result = BytesIO()
Serhiy Storchakad5202392013-02-02 10:31:17 +0200898 xmlgen = XMLGenerator(result)
899
900 parser.setContentHandler(xmlgen)
Serhiy Storchakaaa9563c2015-04-02 20:55:59 +0300901 parser.parse(open(fname, 'rb'))
Serhiy Storchakad5202392013-02-02 10:31:17 +0200902
903 self.assertEqual(result.getvalue(), xml_test_out)
904
Serhiy Storchakafc8e9b02014-11-27 22:13:16 +0200905 def test_expat_binary_file_bytes_name(self):
906 fname = os.fsencode(TEST_XMLFILE)
907 parser = create_parser()
908 result = BytesIO()
909 xmlgen = XMLGenerator(result)
910
911 parser.setContentHandler(xmlgen)
912 with open(fname, 'rb') as f:
913 parser.parse(f)
914
915 self.assertEqual(result.getvalue(), xml_test_out)
916
917 def test_expat_binary_file_int_name(self):
918 parser = create_parser()
919 result = BytesIO()
920 xmlgen = XMLGenerator(result)
921
922 parser.setContentHandler(xmlgen)
923 with open(TEST_XMLFILE, 'rb') as f:
924 with open(f.fileno(), 'rb', closefd=False) as f2:
925 parser.parse(f2)
926
927 self.assertEqual(result.getvalue(), xml_test_out)
928
Guido van Rossumd8faa362007-04-27 19:54:29 +0000929 # ===== DTDHandler support
Lars Gustäbelb7536d52000-09-24 18:53:56 +0000930
Guido van Rossumd8faa362007-04-27 19:54:29 +0000931 class TestDTDHandler:
Lars Gustäbelb7536d52000-09-24 18:53:56 +0000932
Guido van Rossumd8faa362007-04-27 19:54:29 +0000933 def __init__(self):
934 self._notations = []
935 self._entities = []
Lars Gustäbelb7536d52000-09-24 18:53:56 +0000936
Guido van Rossumd8faa362007-04-27 19:54:29 +0000937 def notationDecl(self, name, publicId, systemId):
938 self._notations.append((name, publicId, systemId))
Lars Gustäbelb7536d52000-09-24 18:53:56 +0000939
Guido van Rossumd8faa362007-04-27 19:54:29 +0000940 def unparsedEntityDecl(self, name, publicId, systemId, ndata):
941 self._entities.append((name, publicId, systemId, ndata))
Lars Gustäbel2fc52942000-10-24 15:35:07 +0000942
Christian Heimes17b1d5d2018-09-23 09:50:25 +0200943
944 class TestEntityRecorder:
945 def __init__(self):
946 self.entities = []
947
948 def resolveEntity(self, publicId, systemId):
949 self.entities.append((publicId, systemId))
950 source = InputSource()
951 source.setPublicId(publicId)
952 source.setSystemId(systemId)
953 return source
954
Guido van Rossumd8faa362007-04-27 19:54:29 +0000955 def test_expat_dtdhandler(self):
956 parser = create_parser()
957 handler = self.TestDTDHandler()
958 parser.setDTDHandler(handler)
Lars Gustäbel2fc52942000-10-24 15:35:07 +0000959
Guido van Rossumd8faa362007-04-27 19:54:29 +0000960 parser.feed('<!DOCTYPE doc [\n')
961 parser.feed(' <!ENTITY img SYSTEM "expat.gif" NDATA GIF>\n')
962 parser.feed(' <!NOTATION GIF PUBLIC "-//CompuServe//NOTATION Graphics Interchange Format 89a//EN">\n')
963 parser.feed(']>\n')
964 parser.feed('<doc></doc>')
965 parser.close()
Lars Gustäbel2fc52942000-10-24 15:35:07 +0000966
Ezio Melottib3aedd42010-11-20 19:04:17 +0000967 self.assertEqual(handler._notations,
Guido van Rossumd8faa362007-04-27 19:54:29 +0000968 [("GIF", "-//CompuServe//NOTATION Graphics Interchange Format 89a//EN", None)])
Ezio Melottib3aedd42010-11-20 19:04:17 +0000969 self.assertEqual(handler._entities, [("img", None, "expat.gif", "GIF")])
Lars Gustäbel2fc52942000-10-24 15:35:07 +0000970
Christian Heimes17b1d5d2018-09-23 09:50:25 +0200971 def test_expat_external_dtd_enabled(self):
972 parser = create_parser()
973 parser.setFeature(feature_external_ges, True)
974 resolver = self.TestEntityRecorder()
975 parser.setEntityResolver(resolver)
976
977 with self.assertRaises(URLError):
978 parser.feed(
979 '<!DOCTYPE external SYSTEM "unsupported://non-existing">\n'
980 )
981 self.assertEqual(
982 resolver.entities, [(None, 'unsupported://non-existing')]
983 )
984
985 def test_expat_external_dtd_default(self):
986 parser = create_parser()
987 resolver = self.TestEntityRecorder()
988 parser.setEntityResolver(resolver)
989
990 parser.feed(
991 '<!DOCTYPE external SYSTEM "unsupported://non-existing">\n'
992 )
993 parser.feed('<doc />')
994 parser.close()
995 self.assertEqual(resolver.entities, [])
996
Guido van Rossumd8faa362007-04-27 19:54:29 +0000997 # ===== EntityResolver support
Lars Gustäbel2fc52942000-10-24 15:35:07 +0000998
Guido van Rossumd8faa362007-04-27 19:54:29 +0000999 class TestEntityResolver:
Lars Gustäbel2fc52942000-10-24 15:35:07 +00001000
Guido van Rossumd8faa362007-04-27 19:54:29 +00001001 def resolveEntity(self, publicId, systemId):
1002 inpsrc = InputSource()
Serhiy Storchaka88efc522013-02-10 14:29:52 +02001003 inpsrc.setByteStream(BytesIO(b"<entity/>"))
Guido van Rossumd8faa362007-04-27 19:54:29 +00001004 return inpsrc
Lars Gustäbel2fc52942000-10-24 15:35:07 +00001005
Christian Heimes17b1d5d2018-09-23 09:50:25 +02001006 def test_expat_entityresolver_enabled(self):
Guido van Rossumd8faa362007-04-27 19:54:29 +00001007 parser = create_parser()
Christian Heimes17b1d5d2018-09-23 09:50:25 +02001008 parser.setFeature(feature_external_ges, True)
Guido van Rossumd8faa362007-04-27 19:54:29 +00001009 parser.setEntityResolver(self.TestEntityResolver())
Serhiy Storchaka88efc522013-02-10 14:29:52 +02001010 result = BytesIO()
Guido van Rossumd8faa362007-04-27 19:54:29 +00001011 parser.setContentHandler(XMLGenerator(result))
Lars Gustäbel2fc52942000-10-24 15:35:07 +00001012
Guido van Rossumd8faa362007-04-27 19:54:29 +00001013 parser.feed('<!DOCTYPE doc [\n')
1014 parser.feed(' <!ENTITY test SYSTEM "whatever">\n')
1015 parser.feed(']>\n')
1016 parser.feed('<doc>&test;</doc>')
1017 parser.close()
Lars Gustäbel2fc52942000-10-24 15:35:07 +00001018
Ezio Melottib3aedd42010-11-20 19:04:17 +00001019 self.assertEqual(result.getvalue(), start +
Serhiy Storchaka88efc522013-02-10 14:29:52 +02001020 b"<doc><entity></entity></doc>")
Lars Gustäbel2fc52942000-10-24 15:35:07 +00001021
Christian Heimes17b1d5d2018-09-23 09:50:25 +02001022 def test_expat_entityresolver_default(self):
1023 parser = create_parser()
1024 self.assertEqual(parser.getFeature(feature_external_ges), False)
1025 parser.setEntityResolver(self.TestEntityResolver())
1026 result = BytesIO()
1027 parser.setContentHandler(XMLGenerator(result))
1028
1029 parser.feed('<!DOCTYPE doc [\n')
1030 parser.feed(' <!ENTITY test SYSTEM "whatever">\n')
1031 parser.feed(']>\n')
1032 parser.feed('<doc>&test;</doc>')
1033 parser.close()
1034
1035 self.assertEqual(result.getvalue(), start +
1036 b"<doc></doc>")
1037
Guido van Rossumd8faa362007-04-27 19:54:29 +00001038 # ===== Attributes support
Lars Gustäbel2fc52942000-10-24 15:35:07 +00001039
Guido van Rossumd8faa362007-04-27 19:54:29 +00001040 class AttrGatherer(ContentHandler):
Lars Gustäbel2fc52942000-10-24 15:35:07 +00001041
Guido van Rossumd8faa362007-04-27 19:54:29 +00001042 def startElement(self, name, attrs):
1043 self._attrs = attrs
Lars Gustäbel2fc52942000-10-24 15:35:07 +00001044
Guido van Rossumd8faa362007-04-27 19:54:29 +00001045 def startElementNS(self, name, qname, attrs):
1046 self._attrs = attrs
Lars Gustäbel2fc52942000-10-24 15:35:07 +00001047
Guido van Rossumd8faa362007-04-27 19:54:29 +00001048 def test_expat_attrs_empty(self):
1049 parser = create_parser()
1050 gather = self.AttrGatherer()
1051 parser.setContentHandler(gather)
1052
1053 parser.feed("<doc/>")
1054 parser.close()
1055
1056 self.verify_empty_attrs(gather._attrs)
1057
1058 def test_expat_attrs_wattr(self):
1059 parser = create_parser()
1060 gather = self.AttrGatherer()
1061 parser.setContentHandler(gather)
1062
1063 parser.feed("<doc attr='val'/>")
1064 parser.close()
1065
1066 self.verify_attrs_wattr(gather._attrs)
1067
1068 def test_expat_nsattrs_empty(self):
1069 parser = create_parser(1)
1070 gather = self.AttrGatherer()
1071 parser.setContentHandler(gather)
1072
1073 parser.feed("<doc/>")
1074 parser.close()
1075
1076 self.verify_empty_nsattrs(gather._attrs)
1077
1078 def test_expat_nsattrs_wattr(self):
1079 parser = create_parser(1)
1080 gather = self.AttrGatherer()
1081 parser.setContentHandler(gather)
1082
1083 parser.feed("<doc xmlns:ns='%s' ns:attr='val'/>" % ns_uri)
1084 parser.close()
1085
1086 attrs = gather._attrs
1087
Ezio Melottib3aedd42010-11-20 19:04:17 +00001088 self.assertEqual(attrs.getLength(), 1)
1089 self.assertEqual(attrs.getNames(), [(ns_uri, "attr")])
Guido van Rossumd8faa362007-04-27 19:54:29 +00001090 self.assertTrue((attrs.getQNames() == [] or
1091 attrs.getQNames() == ["ns:attr"]))
Ezio Melottib3aedd42010-11-20 19:04:17 +00001092 self.assertEqual(len(attrs), 1)
Benjamin Peterson577473f2010-01-19 00:09:57 +00001093 self.assertIn((ns_uri, "attr"), attrs)
Ezio Melottib3aedd42010-11-20 19:04:17 +00001094 self.assertEqual(attrs.get((ns_uri, "attr")), "val")
1095 self.assertEqual(attrs.get((ns_uri, "attr"), 25), "val")
1096 self.assertEqual(list(attrs.items()), [((ns_uri, "attr"), "val")])
1097 self.assertEqual(list(attrs.values()), ["val"])
1098 self.assertEqual(attrs.getValue((ns_uri, "attr")), "val")
1099 self.assertEqual(attrs[(ns_uri, "attr")], "val")
Guido van Rossumd8faa362007-04-27 19:54:29 +00001100
1101 # ===== InputSource support
1102
Benjamin Petersona7f4f5a2008-09-04 02:22:52 +00001103 def test_expat_inpsource_filename(self):
Guido van Rossumd8faa362007-04-27 19:54:29 +00001104 parser = create_parser()
Serhiy Storchaka88efc522013-02-10 14:29:52 +02001105 result = BytesIO()
Guido van Rossumd8faa362007-04-27 19:54:29 +00001106 xmlgen = XMLGenerator(result)
1107
1108 parser.setContentHandler(xmlgen)
Florent Xiclunaf15351d2010-03-13 23:24:31 +00001109 parser.parse(TEST_XMLFILE)
Guido van Rossumd8faa362007-04-27 19:54:29 +00001110
Ezio Melottib3aedd42010-11-20 19:04:17 +00001111 self.assertEqual(result.getvalue(), xml_test_out)
Guido van Rossumd8faa362007-04-27 19:54:29 +00001112
Benjamin Petersona7f4f5a2008-09-04 02:22:52 +00001113 def test_expat_inpsource_sysid(self):
Guido van Rossumd8faa362007-04-27 19:54:29 +00001114 parser = create_parser()
Serhiy Storchaka88efc522013-02-10 14:29:52 +02001115 result = BytesIO()
Guido van Rossumd8faa362007-04-27 19:54:29 +00001116 xmlgen = XMLGenerator(result)
1117
1118 parser.setContentHandler(xmlgen)
Florent Xiclunaf15351d2010-03-13 23:24:31 +00001119 parser.parse(InputSource(TEST_XMLFILE))
Guido van Rossumd8faa362007-04-27 19:54:29 +00001120
Ezio Melottib3aedd42010-11-20 19:04:17 +00001121 self.assertEqual(result.getvalue(), xml_test_out)
Guido van Rossumd8faa362007-04-27 19:54:29 +00001122
Serhiy Storchaka1a4ed4c2013-02-02 12:17:05 +02001123 @requires_nonascii_filenames
Serhiy Storchakad5202392013-02-02 10:31:17 +02001124 def test_expat_inpsource_sysid_nonascii(self):
1125 fname = support.TESTFN_UNICODE
1126 shutil.copyfile(TEST_XMLFILE, fname)
1127 self.addCleanup(support.unlink, fname)
1128
1129 parser = create_parser()
Serhiy Storchaka88efc522013-02-10 14:29:52 +02001130 result = BytesIO()
Serhiy Storchakad5202392013-02-02 10:31:17 +02001131 xmlgen = XMLGenerator(result)
1132
1133 parser.setContentHandler(xmlgen)
1134 parser.parse(InputSource(fname))
1135
1136 self.assertEqual(result.getvalue(), xml_test_out)
1137
Serhiy Storchakaaa9563c2015-04-02 20:55:59 +03001138 def test_expat_inpsource_byte_stream(self):
Guido van Rossumd8faa362007-04-27 19:54:29 +00001139 parser = create_parser()
Serhiy Storchaka88efc522013-02-10 14:29:52 +02001140 result = BytesIO()
Guido van Rossumd8faa362007-04-27 19:54:29 +00001141 xmlgen = XMLGenerator(result)
1142
1143 parser.setContentHandler(xmlgen)
1144 inpsrc = InputSource()
Serhiy Storchaka88efc522013-02-10 14:29:52 +02001145 with open(TEST_XMLFILE, 'rb') as f:
Benjamin Petersond5df36d2010-10-31 18:23:23 +00001146 inpsrc.setByteStream(f)
1147 parser.parse(inpsrc)
Guido van Rossumd8faa362007-04-27 19:54:29 +00001148
Ezio Melottib3aedd42010-11-20 19:04:17 +00001149 self.assertEqual(result.getvalue(), xml_test_out)
Guido van Rossumd8faa362007-04-27 19:54:29 +00001150
Serhiy Storchaka61de0872015-04-02 21:00:13 +03001151 def test_expat_inpsource_character_stream(self):
1152 parser = create_parser()
1153 result = BytesIO()
1154 xmlgen = XMLGenerator(result)
1155
1156 parser.setContentHandler(xmlgen)
1157 inpsrc = InputSource()
1158 with open(TEST_XMLFILE, 'rt', encoding='iso-8859-1') as f:
1159 inpsrc.setCharacterStream(f)
1160 parser.parse(inpsrc)
1161
1162 self.assertEqual(result.getvalue(), xml_test_out)
1163
Guido van Rossumd8faa362007-04-27 19:54:29 +00001164 # ===== IncrementalParser support
1165
1166 def test_expat_incremental(self):
Serhiy Storchaka88efc522013-02-10 14:29:52 +02001167 result = BytesIO()
Guido van Rossumd8faa362007-04-27 19:54:29 +00001168 xmlgen = XMLGenerator(result)
1169 parser = create_parser()
1170 parser.setContentHandler(xmlgen)
1171
1172 parser.feed("<doc>")
1173 parser.feed("</doc>")
1174 parser.close()
1175
Serhiy Storchaka88efc522013-02-10 14:29:52 +02001176 self.assertEqual(result.getvalue(), start + b"<doc></doc>")
Guido van Rossumd8faa362007-04-27 19:54:29 +00001177
1178 def test_expat_incremental_reset(self):
Serhiy Storchaka88efc522013-02-10 14:29:52 +02001179 result = BytesIO()
Guido van Rossumd8faa362007-04-27 19:54:29 +00001180 xmlgen = XMLGenerator(result)
1181 parser = create_parser()
1182 parser.setContentHandler(xmlgen)
1183
1184 parser.feed("<doc>")
1185 parser.feed("text")
1186
Serhiy Storchaka88efc522013-02-10 14:29:52 +02001187 result = BytesIO()
Guido van Rossumd8faa362007-04-27 19:54:29 +00001188 xmlgen = XMLGenerator(result)
1189 parser.setContentHandler(xmlgen)
1190 parser.reset()
1191
1192 parser.feed("<doc>")
1193 parser.feed("text")
1194 parser.feed("</doc>")
1195 parser.close()
1196
Serhiy Storchaka88efc522013-02-10 14:29:52 +02001197 self.assertEqual(result.getvalue(), start + b"<doc>text</doc>")
Guido van Rossumd8faa362007-04-27 19:54:29 +00001198
1199 # ===== Locator support
1200
1201 def test_expat_locator_noinfo(self):
Serhiy Storchaka88efc522013-02-10 14:29:52 +02001202 result = BytesIO()
Guido van Rossumd8faa362007-04-27 19:54:29 +00001203 xmlgen = XMLGenerator(result)
1204 parser = create_parser()
1205 parser.setContentHandler(xmlgen)
1206
1207 parser.feed("<doc>")
1208 parser.feed("</doc>")
1209 parser.close()
1210
Ezio Melottib3aedd42010-11-20 19:04:17 +00001211 self.assertEqual(parser.getSystemId(), None)
1212 self.assertEqual(parser.getPublicId(), None)
1213 self.assertEqual(parser.getLineNumber(), 1)
Guido van Rossumd8faa362007-04-27 19:54:29 +00001214
Benjamin Petersona7f4f5a2008-09-04 02:22:52 +00001215 def test_expat_locator_withinfo(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)
Florent Xiclunaf15351d2010-03-13 23:24:31 +00001220 parser.parse(TEST_XMLFILE)
Guido van Rossumd8faa362007-04-27 19:54:29 +00001221
Ezio Melottib3aedd42010-11-20 19:04:17 +00001222 self.assertEqual(parser.getSystemId(), TEST_XMLFILE)
1223 self.assertEqual(parser.getPublicId(), None)
Lars Gustäbel2fc52942000-10-24 15:35:07 +00001224
Serhiy Storchaka1a4ed4c2013-02-02 12:17:05 +02001225 @requires_nonascii_filenames
Serhiy Storchakad5202392013-02-02 10:31:17 +02001226 def test_expat_locator_withinfo_nonascii(self):
1227 fname = support.TESTFN_UNICODE
1228 shutil.copyfile(TEST_XMLFILE, fname)
1229 self.addCleanup(support.unlink, fname)
1230
Serhiy Storchaka88efc522013-02-10 14:29:52 +02001231 result = BytesIO()
Serhiy Storchakad5202392013-02-02 10:31:17 +02001232 xmlgen = XMLGenerator(result)
1233 parser = create_parser()
1234 parser.setContentHandler(xmlgen)
1235 parser.parse(fname)
1236
1237 self.assertEqual(parser.getSystemId(), fname)
1238 self.assertEqual(parser.getPublicId(), None)
1239
Martin v. Löwis80670bc2000-10-06 21:13:23 +00001240
1241# ===========================================================================
1242#
1243# error reporting
1244#
1245# ===========================================================================
1246
Guido van Rossumd8faa362007-04-27 19:54:29 +00001247class ErrorReportingTest(unittest.TestCase):
1248 def test_expat_inpsource_location(self):
1249 parser = create_parser()
1250 parser.setContentHandler(ContentHandler()) # do nothing
1251 source = InputSource()
Serhiy Storchaka88efc522013-02-10 14:29:52 +02001252 source.setByteStream(BytesIO(b"<foo bar foobar>")) #ill-formed
Guido van Rossumd8faa362007-04-27 19:54:29 +00001253 name = "a file name"
1254 source.setSystemId(name)
1255 try:
1256 parser.parse(source)
1257 self.fail()
1258 except SAXException as e:
Ezio Melottib3aedd42010-11-20 19:04:17 +00001259 self.assertEqual(e.getSystemId(), name)
Martin v. Löwis80670bc2000-10-06 21:13:23 +00001260
Guido van Rossumd8faa362007-04-27 19:54:29 +00001261 def test_expat_incomplete(self):
1262 parser = create_parser()
1263 parser.setContentHandler(ContentHandler()) # do nothing
1264 self.assertRaises(SAXParseException, parser.parse, StringIO("<foo>"))
Serhiy Storchakaab914782015-05-06 09:36:06 +03001265 self.assertEqual(parser.getColumnNumber(), 5)
1266 self.assertEqual(parser.getLineNumber(), 1)
Martin v. Löwis80670bc2000-10-06 21:13:23 +00001267
Guido van Rossumd8faa362007-04-27 19:54:29 +00001268 def test_sax_parse_exception_str(self):
1269 # pass various values from a locator to the SAXParseException to
1270 # make sure that the __str__() doesn't fall apart when None is
1271 # passed instead of an integer line and column number
1272 #
1273 # use "normal" values for the locator:
1274 str(SAXParseException("message", None,
1275 self.DummyLocator(1, 1)))
1276 # use None for the line number:
1277 str(SAXParseException("message", None,
1278 self.DummyLocator(None, 1)))
1279 # use None for the column number:
1280 str(SAXParseException("message", None,
1281 self.DummyLocator(1, None)))
1282 # use None for both:
1283 str(SAXParseException("message", None,
1284 self.DummyLocator(None, None)))
Fred Drake6fd0b0d2004-03-20 08:15:30 +00001285
Guido van Rossumd8faa362007-04-27 19:54:29 +00001286 class DummyLocator:
1287 def __init__(self, lineno, colno):
1288 self._lineno = lineno
1289 self._colno = colno
Fred Drake6fd0b0d2004-03-20 08:15:30 +00001290
Guido van Rossumd8faa362007-04-27 19:54:29 +00001291 def getPublicId(self):
1292 return "pubid"
Fred Drake6fd0b0d2004-03-20 08:15:30 +00001293
Guido van Rossumd8faa362007-04-27 19:54:29 +00001294 def getSystemId(self):
1295 return "sysid"
Fred Drake6fd0b0d2004-03-20 08:15:30 +00001296
Guido van Rossumd8faa362007-04-27 19:54:29 +00001297 def getLineNumber(self):
1298 return self._lineno
Fred Drake6fd0b0d2004-03-20 08:15:30 +00001299
Guido van Rossumd8faa362007-04-27 19:54:29 +00001300 def getColumnNumber(self):
1301 return self._colno
Martin v. Löwis80670bc2000-10-06 21:13:23 +00001302
Lars Gustäbelab647872000-09-24 18:40:52 +00001303# ===========================================================================
1304#
1305# xmlreader tests
1306#
1307# ===========================================================================
1308
Guido van Rossumd8faa362007-04-27 19:54:29 +00001309class XmlReaderTest(XmlTestBase):
Lars Gustäbelab647872000-09-24 18:40:52 +00001310
Guido van Rossumd8faa362007-04-27 19:54:29 +00001311 # ===== AttributesImpl
1312 def test_attrs_empty(self):
1313 self.verify_empty_attrs(AttributesImpl({}))
Lars Gustäbelab647872000-09-24 18:40:52 +00001314
Guido van Rossumd8faa362007-04-27 19:54:29 +00001315 def test_attrs_wattr(self):
1316 self.verify_attrs_wattr(AttributesImpl({"attr" : "val"}))
Lars Gustäbelab647872000-09-24 18:40:52 +00001317
Guido van Rossumd8faa362007-04-27 19:54:29 +00001318 def test_nsattrs_empty(self):
1319 self.verify_empty_nsattrs(AttributesNSImpl({}, {}))
Lars Gustäbelab647872000-09-24 18:40:52 +00001320
Guido van Rossumd8faa362007-04-27 19:54:29 +00001321 def test_nsattrs_wattr(self):
1322 attrs = AttributesNSImpl({(ns_uri, "attr") : "val"},
1323 {(ns_uri, "attr") : "ns:attr"})
Fred Drake004d5e62000-10-23 17:22:08 +00001324
Ezio Melottib3aedd42010-11-20 19:04:17 +00001325 self.assertEqual(attrs.getLength(), 1)
1326 self.assertEqual(attrs.getNames(), [(ns_uri, "attr")])
1327 self.assertEqual(attrs.getQNames(), ["ns:attr"])
1328 self.assertEqual(len(attrs), 1)
Benjamin Peterson577473f2010-01-19 00:09:57 +00001329 self.assertIn((ns_uri, "attr"), attrs)
Ezio Melottib3aedd42010-11-20 19:04:17 +00001330 self.assertEqual(list(attrs.keys()), [(ns_uri, "attr")])
1331 self.assertEqual(attrs.get((ns_uri, "attr")), "val")
1332 self.assertEqual(attrs.get((ns_uri, "attr"), 25), "val")
1333 self.assertEqual(list(attrs.items()), [((ns_uri, "attr"), "val")])
1334 self.assertEqual(list(attrs.values()), ["val"])
1335 self.assertEqual(attrs.getValue((ns_uri, "attr")), "val")
1336 self.assertEqual(attrs.getValueByQName("ns:attr"), "val")
1337 self.assertEqual(attrs.getNameByQName("ns:attr"), (ns_uri, "attr"))
1338 self.assertEqual(attrs[(ns_uri, "attr")], "val")
1339 self.assertEqual(attrs.getQNameByName((ns_uri, "attr")), "ns:attr")
Fred Drake004d5e62000-10-23 17:22:08 +00001340
Lars Gustäbelab647872000-09-24 18:40:52 +00001341
Christian Heimesbbe741d2008-03-28 10:53:29 +00001342def test_main():
Guido van Rossumd8faa362007-04-27 19:54:29 +00001343 run_unittest(MakeParserTest,
Serhiy Storchaka13e41c52015-04-02 23:05:57 +03001344 ParseTest,
Guido van Rossumd8faa362007-04-27 19:54:29 +00001345 SaxutilsTest,
Serhiy Storchakaaa9563c2015-04-02 20:55:59 +03001346 PrepareInputSourceTest,
Serhiy Storchaka88efc522013-02-10 14:29:52 +02001347 StringXmlgenTest,
1348 BytesXmlgenTest,
1349 WriterXmlgenTest,
Georg Brandlc502df42013-05-12 11:41:12 +02001350 StreamWriterXmlgenTest,
1351 StreamReaderWriterXmlgenTest,
Guido van Rossumd8faa362007-04-27 19:54:29 +00001352 ExpatReaderTest,
1353 ErrorReportingTest,
1354 XmlReaderTest)
Lars Gustäbelb7536d52000-09-24 18:53:56 +00001355
Guido van Rossumd8faa362007-04-27 19:54:29 +00001356if __name__ == "__main__":
Christian Heimesbbe741d2008-03-28 10:53:29 +00001357 test_main()