blob: da4eb1da3c6ada53918912cd1763af4313ce80ff [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
Serhiy Storchakad5202392013-02-02 10:31:17 +020023from test import support
Mickaël Schoentgen929b7042019-04-14 09:16:54 +000024from test.support import findfile, run_unittest, FakePath, TESTFN
Florent Xiclunaf15351d2010-03-13 23:24:31 +000025
26TEST_XMLFILE = findfile("test.xml", subdir="xmltestdata")
27TEST_XMLFILE_OUT = findfile("test.xml.out", subdir="xmltestdata")
Victor Stinner6c6f8512010-08-07 10:09:35 +000028try:
Marc-André Lemburg8f36af72011-02-25 15:42:01 +000029 TEST_XMLFILE.encode("utf-8")
30 TEST_XMLFILE_OUT.encode("utf-8")
Victor Stinner6c6f8512010-08-07 10:09:35 +000031except UnicodeEncodeError:
32 raise unittest.SkipTest("filename is not encodable to utf8")
Lars Gustäbel96753b32000-09-24 12:24:24 +000033
Serhiy Storchaka1a4ed4c2013-02-02 12:17:05 +020034supports_nonascii_filenames = True
35if not os.path.supports_unicode_filenames:
36 try:
37 support.TESTFN_UNICODE.encode(support.TESTFN_ENCODING)
38 except (UnicodeError, TypeError):
39 # Either the file system encoding is None, or the file name
40 # cannot be encoded in the file system encoding.
41 supports_nonascii_filenames = False
42requires_nonascii_filenames = unittest.skipUnless(
43 supports_nonascii_filenames,
44 'Requires non-ascii filenames support')
45
Guido van Rossumd8faa362007-04-27 19:54:29 +000046ns_uri = "http://www.python.org/xml-ns/saxtest/"
Lars Gustäbel96753b32000-09-24 12:24:24 +000047
Guido van Rossumd8faa362007-04-27 19:54:29 +000048class XmlTestBase(unittest.TestCase):
49 def verify_empty_attrs(self, attrs):
50 self.assertRaises(KeyError, attrs.getValue, "attr")
51 self.assertRaises(KeyError, attrs.getValueByQName, "attr")
52 self.assertRaises(KeyError, attrs.getNameByQName, "attr")
53 self.assertRaises(KeyError, attrs.getQNameByName, "attr")
54 self.assertRaises(KeyError, attrs.__getitem__, "attr")
Ezio Melottib3aedd42010-11-20 19:04:17 +000055 self.assertEqual(attrs.getLength(), 0)
56 self.assertEqual(attrs.getNames(), [])
57 self.assertEqual(attrs.getQNames(), [])
58 self.assertEqual(len(attrs), 0)
Ezio Melottib58e0bd2010-01-23 15:40:09 +000059 self.assertNotIn("attr", attrs)
Ezio Melottib3aedd42010-11-20 19:04:17 +000060 self.assertEqual(list(attrs.keys()), [])
61 self.assertEqual(attrs.get("attrs"), None)
62 self.assertEqual(attrs.get("attrs", 25), 25)
63 self.assertEqual(list(attrs.items()), [])
64 self.assertEqual(list(attrs.values()), [])
Lars Gustäbel96753b32000-09-24 12:24:24 +000065
Guido van Rossumd8faa362007-04-27 19:54:29 +000066 def verify_empty_nsattrs(self, attrs):
67 self.assertRaises(KeyError, attrs.getValue, (ns_uri, "attr"))
68 self.assertRaises(KeyError, attrs.getValueByQName, "ns:attr")
69 self.assertRaises(KeyError, attrs.getNameByQName, "ns:attr")
70 self.assertRaises(KeyError, attrs.getQNameByName, (ns_uri, "attr"))
71 self.assertRaises(KeyError, attrs.__getitem__, (ns_uri, "attr"))
Ezio Melottib3aedd42010-11-20 19:04:17 +000072 self.assertEqual(attrs.getLength(), 0)
73 self.assertEqual(attrs.getNames(), [])
74 self.assertEqual(attrs.getQNames(), [])
75 self.assertEqual(len(attrs), 0)
Ezio Melottib58e0bd2010-01-23 15:40:09 +000076 self.assertNotIn((ns_uri, "attr"), attrs)
Ezio Melottib3aedd42010-11-20 19:04:17 +000077 self.assertEqual(list(attrs.keys()), [])
78 self.assertEqual(attrs.get((ns_uri, "attr")), None)
79 self.assertEqual(attrs.get((ns_uri, "attr"), 25), 25)
80 self.assertEqual(list(attrs.items()), [])
81 self.assertEqual(list(attrs.values()), [])
Lars Gustäbel96753b32000-09-24 12:24:24 +000082
Guido van Rossumd8faa362007-04-27 19:54:29 +000083 def verify_attrs_wattr(self, attrs):
Ezio Melottib3aedd42010-11-20 19:04:17 +000084 self.assertEqual(attrs.getLength(), 1)
85 self.assertEqual(attrs.getNames(), ["attr"])
86 self.assertEqual(attrs.getQNames(), ["attr"])
87 self.assertEqual(len(attrs), 1)
Benjamin Peterson577473f2010-01-19 00:09:57 +000088 self.assertIn("attr", attrs)
Ezio Melottib3aedd42010-11-20 19:04:17 +000089 self.assertEqual(list(attrs.keys()), ["attr"])
90 self.assertEqual(attrs.get("attr"), "val")
91 self.assertEqual(attrs.get("attr", 25), "val")
92 self.assertEqual(list(attrs.items()), [("attr", "val")])
93 self.assertEqual(list(attrs.values()), ["val"])
94 self.assertEqual(attrs.getValue("attr"), "val")
95 self.assertEqual(attrs.getValueByQName("attr"), "val")
96 self.assertEqual(attrs.getNameByQName("attr"), "attr")
97 self.assertEqual(attrs["attr"], "val")
98 self.assertEqual(attrs.getQNameByName("attr"), "attr")
Lars Gustäbel96753b32000-09-24 12:24:24 +000099
Serhiy Storchaka13e41c52015-04-02 23:05:57 +0300100
101def xml_str(doc, encoding=None):
102 if encoding is None:
103 return doc
104 return '<?xml version="1.0" encoding="%s"?>\n%s' % (encoding, doc)
105
106def xml_bytes(doc, encoding, decl_encoding=...):
107 if decl_encoding is ...:
108 decl_encoding = encoding
109 return xml_str(doc, decl_encoding).encode(encoding, 'xmlcharrefreplace')
110
111def make_xml_file(doc, encoding, decl_encoding=...):
112 if decl_encoding is ...:
113 decl_encoding = encoding
114 with open(TESTFN, 'w', encoding=encoding, errors='xmlcharrefreplace') as f:
115 f.write(xml_str(doc, decl_encoding))
116
117
118class ParseTest(unittest.TestCase):
119 data = '<money value="$\xa3\u20ac\U0001017b">$\xa3\u20ac\U0001017b</money>'
120
121 def tearDown(self):
122 support.unlink(TESTFN)
123
124 def check_parse(self, f):
125 from xml.sax import parse
126 result = StringIO()
127 parse(f, XMLGenerator(result, 'utf-8'))
128 self.assertEqual(result.getvalue(), xml_str(self.data, 'utf-8'))
129
130 def test_parse_text(self):
131 encodings = ('us-ascii', 'iso-8859-1', 'utf-8',
132 'utf-16', 'utf-16le', 'utf-16be')
133 for encoding in encodings:
134 self.check_parse(StringIO(xml_str(self.data, encoding)))
135 make_xml_file(self.data, encoding)
136 with open(TESTFN, 'r', encoding=encoding) as f:
137 self.check_parse(f)
138 self.check_parse(StringIO(self.data))
139 make_xml_file(self.data, encoding, None)
140 with open(TESTFN, 'r', encoding=encoding) as f:
141 self.check_parse(f)
142
143 def test_parse_bytes(self):
144 # UTF-8 is default encoding, US-ASCII is compatible with UTF-8,
145 # UTF-16 is autodetected
146 encodings = ('us-ascii', 'utf-8', 'utf-16', 'utf-16le', 'utf-16be')
147 for encoding in encodings:
148 self.check_parse(BytesIO(xml_bytes(self.data, encoding)))
149 make_xml_file(self.data, encoding)
150 self.check_parse(TESTFN)
151 with open(TESTFN, 'rb') as f:
152 self.check_parse(f)
153 self.check_parse(BytesIO(xml_bytes(self.data, encoding, None)))
154 make_xml_file(self.data, encoding, None)
155 self.check_parse(TESTFN)
156 with open(TESTFN, 'rb') as f:
157 self.check_parse(f)
158 # accept UTF-8 with BOM
159 self.check_parse(BytesIO(xml_bytes(self.data, 'utf-8-sig', 'utf-8')))
160 make_xml_file(self.data, 'utf-8-sig', 'utf-8')
161 self.check_parse(TESTFN)
162 with open(TESTFN, 'rb') as f:
163 self.check_parse(f)
164 self.check_parse(BytesIO(xml_bytes(self.data, 'utf-8-sig', None)))
165 make_xml_file(self.data, 'utf-8-sig', None)
166 self.check_parse(TESTFN)
167 with open(TESTFN, 'rb') as f:
168 self.check_parse(f)
169 # accept data with declared encoding
170 self.check_parse(BytesIO(xml_bytes(self.data, 'iso-8859-1')))
171 make_xml_file(self.data, 'iso-8859-1')
172 self.check_parse(TESTFN)
173 with open(TESTFN, 'rb') as f:
174 self.check_parse(f)
175 # fail on non-UTF-8 incompatible data without declared encoding
176 with self.assertRaises(SAXException):
177 self.check_parse(BytesIO(xml_bytes(self.data, 'iso-8859-1', None)))
178 make_xml_file(self.data, 'iso-8859-1', None)
Victor Stinneref9c0e72017-05-05 09:46:47 +0200179 with self.assertRaises(SAXException):
180 self.check_parse(TESTFN)
Serhiy Storchaka13e41c52015-04-02 23:05:57 +0300181 with open(TESTFN, 'rb') as f:
182 with self.assertRaises(SAXException):
183 self.check_parse(f)
184
Mickaël Schoentgen929b7042019-04-14 09:16:54 +0000185 def test_parse_path_object(self):
186 make_xml_file(self.data, 'utf-8', None)
187 self.check_parse(FakePath(TESTFN))
188
Serhiy Storchaka13e41c52015-04-02 23:05:57 +0300189 def test_parse_InputSource(self):
190 # accept data without declared but with explicitly specified encoding
191 make_xml_file(self.data, 'iso-8859-1', None)
192 with open(TESTFN, 'rb') as f:
193 input = InputSource()
194 input.setByteStream(f)
195 input.setEncoding('iso-8859-1')
196 self.check_parse(input)
197
Victor Stinneref9c0e72017-05-05 09:46:47 +0200198 def test_parse_close_source(self):
199 builtin_open = open
200 fileobj = None
201
202 def mock_open(*args):
203 nonlocal fileobj
204 fileobj = builtin_open(*args)
205 return fileobj
206
207 with mock.patch('xml.sax.saxutils.open', side_effect=mock_open):
208 make_xml_file(self.data, 'iso-8859-1', None)
209 with self.assertRaises(SAXException):
210 self.check_parse(TESTFN)
211 self.assertTrue(fileobj.closed)
212
Serhiy Storchaka13e41c52015-04-02 23:05:57 +0300213 def check_parseString(self, s):
214 from xml.sax import parseString
215 result = StringIO()
216 parseString(s, XMLGenerator(result, 'utf-8'))
217 self.assertEqual(result.getvalue(), xml_str(self.data, 'utf-8'))
218
Serhiy Storchaka778db282015-04-04 10:12:26 +0300219 def test_parseString_text(self):
220 encodings = ('us-ascii', 'iso-8859-1', 'utf-8',
221 'utf-16', 'utf-16le', 'utf-16be')
222 for encoding in encodings:
223 self.check_parseString(xml_str(self.data, encoding))
224 self.check_parseString(self.data)
225
Serhiy Storchaka13e41c52015-04-02 23:05:57 +0300226 def test_parseString_bytes(self):
227 # UTF-8 is default encoding, US-ASCII is compatible with UTF-8,
228 # UTF-16 is autodetected
229 encodings = ('us-ascii', 'utf-8', 'utf-16', 'utf-16le', 'utf-16be')
230 for encoding in encodings:
231 self.check_parseString(xml_bytes(self.data, encoding))
232 self.check_parseString(xml_bytes(self.data, encoding, None))
233 # accept UTF-8 with BOM
234 self.check_parseString(xml_bytes(self.data, 'utf-8-sig', 'utf-8'))
235 self.check_parseString(xml_bytes(self.data, 'utf-8-sig', None))
236 # accept data with declared encoding
237 self.check_parseString(xml_bytes(self.data, 'iso-8859-1'))
238 # fail on non-UTF-8 incompatible data without declared encoding
239 with self.assertRaises(SAXException):
240 self.check_parseString(xml_bytes(self.data, 'iso-8859-1', None))
241
Guido van Rossumd8faa362007-04-27 19:54:29 +0000242class MakeParserTest(unittest.TestCase):
243 def test_make_parser2(self):
Lars Gustäbel2fc52942000-10-24 15:35:07 +0000244 # Creating parsers several times in a row should succeed.
245 # Testing this because there have been failures of this kind
246 # before.
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000247 from xml.sax import make_parser
Lars Gustäbel2fc52942000-10-24 15:35:07 +0000248 p = make_parser()
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000249 from xml.sax import make_parser
Lars Gustäbel2fc52942000-10-24 15:35:07 +0000250 p = make_parser()
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000251 from xml.sax import make_parser
Lars Gustäbel2fc52942000-10-24 15:35:07 +0000252 p = make_parser()
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000253 from xml.sax import make_parser
Lars Gustäbel2fc52942000-10-24 15:35:07 +0000254 p = make_parser()
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000255 from xml.sax import make_parser
Lars Gustäbel2fc52942000-10-24 15:35:07 +0000256 p = make_parser()
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000257 from xml.sax import make_parser
Lars Gustäbel2fc52942000-10-24 15:35:07 +0000258 p = make_parser()
Tim Petersd2bf3b72001-01-18 02:22:22 +0000259
Andrés Delfinoa6dc5312018-10-26 11:56:57 -0300260 def test_make_parser3(self):
261 # Testing that make_parser can handle different types of
262 # iterables.
263 make_parser(['module'])
264 make_parser(('module', ))
265 make_parser({'module'})
266 make_parser(frozenset({'module'}))
267 make_parser({'module': None})
268 make_parser(iter(['module']))
269
270 def test_make_parser4(self):
271 # Testing that make_parser can handle empty iterables.
272 make_parser([])
273 make_parser(tuple())
274 make_parser(set())
275 make_parser(frozenset())
276 make_parser({})
277 make_parser(iter([]))
278
279 def test_make_parser5(self):
280 # Testing that make_parser can handle iterables with more than
281 # one item.
282 make_parser(['module1', 'module2'])
283 make_parser(('module1', 'module2'))
284 make_parser({'module1', 'module2'})
285 make_parser(frozenset({'module1', 'module2'}))
286 make_parser({'module1': None, 'module2': None})
287 make_parser(iter(['module1', 'module2']))
Tim Petersd2bf3b72001-01-18 02:22:22 +0000288
Lars Gustäbel96753b32000-09-24 12:24:24 +0000289# ===========================================================================
290#
291# saxutils tests
292#
293# ===========================================================================
294
Guido van Rossumd8faa362007-04-27 19:54:29 +0000295class SaxutilsTest(unittest.TestCase):
296 # ===== escape
297 def test_escape_basic(self):
Ezio Melottib3aedd42010-11-20 19:04:17 +0000298 self.assertEqual(escape("Donald Duck & Co"), "Donald Duck &amp; Co")
Lars Gustäbel96753b32000-09-24 12:24:24 +0000299
Guido van Rossumd8faa362007-04-27 19:54:29 +0000300 def test_escape_all(self):
Ezio Melottib3aedd42010-11-20 19:04:17 +0000301 self.assertEqual(escape("<Donald Duck & Co>"),
302 "&lt;Donald Duck &amp; Co&gt;")
Lars Gustäbel96753b32000-09-24 12:24:24 +0000303
Guido van Rossumd8faa362007-04-27 19:54:29 +0000304 def test_escape_extra(self):
Ezio Melottib3aedd42010-11-20 19:04:17 +0000305 self.assertEqual(escape("Hei på deg", {"å" : "&aring;"}),
306 "Hei p&aring; deg")
Lars Gustäbel96753b32000-09-24 12:24:24 +0000307
Guido van Rossumd8faa362007-04-27 19:54:29 +0000308 # ===== unescape
309 def test_unescape_basic(self):
Ezio Melottib3aedd42010-11-20 19:04:17 +0000310 self.assertEqual(unescape("Donald Duck &amp; Co"), "Donald Duck & Co")
Lars Gustäbel96753b32000-09-24 12:24:24 +0000311
Guido van Rossumd8faa362007-04-27 19:54:29 +0000312 def test_unescape_all(self):
Ezio Melottib3aedd42010-11-20 19:04:17 +0000313 self.assertEqual(unescape("&lt;Donald Duck &amp; Co&gt;"),
314 "<Donald Duck & Co>")
Martin v. Löwis74b51ac2002-10-26 14:50:45 +0000315
Guido van Rossumd8faa362007-04-27 19:54:29 +0000316 def test_unescape_extra(self):
Ezio Melottib3aedd42010-11-20 19:04:17 +0000317 self.assertEqual(unescape("Hei på deg", {"å" : "&aring;"}),
318 "Hei p&aring; deg")
Martin v. Löwis74b51ac2002-10-26 14:50:45 +0000319
Guido van Rossumd8faa362007-04-27 19:54:29 +0000320 def test_unescape_amp_extra(self):
Ezio Melottib3aedd42010-11-20 19:04:17 +0000321 self.assertEqual(unescape("&amp;foo;", {"&foo;": "splat"}), "&foo;")
Martin v. Löwis74b51ac2002-10-26 14:50:45 +0000322
Guido van Rossumd8faa362007-04-27 19:54:29 +0000323 # ===== quoteattr
324 def test_quoteattr_basic(self):
Ezio Melottib3aedd42010-11-20 19:04:17 +0000325 self.assertEqual(quoteattr("Donald Duck & Co"),
326 '"Donald Duck &amp; Co"')
Martin v. Löwis74b51ac2002-10-26 14:50:45 +0000327
Guido van Rossumd8faa362007-04-27 19:54:29 +0000328 def test_single_quoteattr(self):
Ezio Melottib3aedd42010-11-20 19:04:17 +0000329 self.assertEqual(quoteattr('Includes "double" quotes'),
330 '\'Includes "double" quotes\'')
Fred Drake32f3add2002-10-28 17:58:48 +0000331
Guido van Rossumd8faa362007-04-27 19:54:29 +0000332 def test_double_quoteattr(self):
Ezio Melottib3aedd42010-11-20 19:04:17 +0000333 self.assertEqual(quoteattr("Includes 'single' quotes"),
334 "\"Includes 'single' quotes\"")
Fred Drakeacd32d32001-07-19 16:10:15 +0000335
Guido van Rossumd8faa362007-04-27 19:54:29 +0000336 def test_single_double_quoteattr(self):
Ezio Melottib3aedd42010-11-20 19:04:17 +0000337 self.assertEqual(quoteattr("Includes 'single' and \"double\" quotes"),
338 "\"Includes 'single' and &quot;double&quot; quotes\"")
Fred Drakeacd32d32001-07-19 16:10:15 +0000339
Guido van Rossumd8faa362007-04-27 19:54:29 +0000340 # ===== make_parser
341 def test_make_parser(self):
Martin v. Löwis962c9e72000-10-06 17:41:52 +0000342 # Creating a parser should succeed - it should fall back
343 # to the expatreader
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000344 p = make_parser(['xml.parsers.no_such_parser'])
Martin v. Löwis962c9e72000-10-06 17:41:52 +0000345
346
Serhiy Storchakaaa9563c2015-04-02 20:55:59 +0300347class PrepareInputSourceTest(unittest.TestCase):
348
349 def setUp(self):
350 self.file = support.TESTFN
351 with open(self.file, "w") as tmp:
352 tmp.write("This was read from a file.")
353
354 def tearDown(self):
355 support.unlink(self.file)
356
357 def make_byte_stream(self):
358 return BytesIO(b"This is a byte stream.")
359
Serhiy Storchaka61de0872015-04-02 21:00:13 +0300360 def make_character_stream(self):
361 return StringIO("This is a character stream.")
362
Serhiy Storchakaaa9563c2015-04-02 20:55:59 +0300363 def checkContent(self, stream, content):
364 self.assertIsNotNone(stream)
365 self.assertEqual(stream.read(), content)
366 stream.close()
367
368
Serhiy Storchaka61de0872015-04-02 21:00:13 +0300369 def test_character_stream(self):
370 # If the source is an InputSource with a character stream, use it.
371 src = InputSource(self.file)
372 src.setCharacterStream(self.make_character_stream())
373 prep = prepare_input_source(src)
374 self.assertIsNone(prep.getByteStream())
375 self.checkContent(prep.getCharacterStream(),
376 "This is a character stream.")
377
Serhiy Storchakaaa9563c2015-04-02 20:55:59 +0300378 def test_byte_stream(self):
379 # If the source is an InputSource that does not have a character
380 # stream but does have a byte stream, use the byte stream.
381 src = InputSource(self.file)
382 src.setByteStream(self.make_byte_stream())
383 prep = prepare_input_source(src)
384 self.assertIsNone(prep.getCharacterStream())
385 self.checkContent(prep.getByteStream(),
386 b"This is a byte stream.")
387
388 def test_system_id(self):
389 # If the source is an InputSource that has neither a character
390 # stream nor a byte stream, open the system ID.
391 src = InputSource(self.file)
392 prep = prepare_input_source(src)
393 self.assertIsNone(prep.getCharacterStream())
394 self.checkContent(prep.getByteStream(),
395 b"This was read from a file.")
396
397 def test_string(self):
398 # If the source is a string, use it as a system ID and open it.
399 prep = prepare_input_source(self.file)
400 self.assertIsNone(prep.getCharacterStream())
401 self.checkContent(prep.getByteStream(),
402 b"This was read from a file.")
403
Mickaël Schoentgen929b7042019-04-14 09:16:54 +0000404 def test_path_objects(self):
405 # If the source is a Path object, use it as a system ID and open it.
406 prep = prepare_input_source(FakePath(self.file))
407 self.assertIsNone(prep.getCharacterStream())
408 self.checkContent(prep.getByteStream(),
409 b"This was read from a file.")
410
Serhiy Storchakaaa9563c2015-04-02 20:55:59 +0300411 def test_binary_file(self):
412 # If the source is a binary file-like object, use it as a byte
413 # stream.
414 prep = prepare_input_source(self.make_byte_stream())
415 self.assertIsNone(prep.getCharacterStream())
416 self.checkContent(prep.getByteStream(),
417 b"This is a byte stream.")
418
Serhiy Storchaka61de0872015-04-02 21:00:13 +0300419 def test_text_file(self):
420 # If the source is a text file-like object, use it as a character
421 # stream.
422 prep = prepare_input_source(self.make_character_stream())
423 self.assertIsNone(prep.getByteStream())
424 self.checkContent(prep.getCharacterStream(),
425 "This is a character stream.")
426
Serhiy Storchakaaa9563c2015-04-02 20:55:59 +0300427
Lars Gustäbel96753b32000-09-24 12:24:24 +0000428# ===== XMLGenerator
429
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200430class XmlgenTest:
Guido van Rossumd8faa362007-04-27 19:54:29 +0000431 def test_xmlgen_basic(self):
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200432 result = self.ioclass()
Guido van Rossumd8faa362007-04-27 19:54:29 +0000433 gen = XMLGenerator(result)
434 gen.startDocument()
435 gen.startElement("doc", {})
436 gen.endElement("doc")
437 gen.endDocument()
Lars Gustäbel96753b32000-09-24 12:24:24 +0000438
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200439 self.assertEqual(result.getvalue(), self.xml("<doc></doc>"))
Lars Gustäbel96753b32000-09-24 12:24:24 +0000440
R. David Murraya90032a2010-10-17 22:46:45 +0000441 def test_xmlgen_basic_empty(self):
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200442 result = self.ioclass()
R. David Murraya90032a2010-10-17 22:46:45 +0000443 gen = XMLGenerator(result, short_empty_elements=True)
444 gen.startDocument()
445 gen.startElement("doc", {})
446 gen.endElement("doc")
447 gen.endDocument()
448
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200449 self.assertEqual(result.getvalue(), self.xml("<doc/>"))
R. David Murraya90032a2010-10-17 22:46:45 +0000450
Guido van Rossumd8faa362007-04-27 19:54:29 +0000451 def test_xmlgen_content(self):
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200452 result = self.ioclass()
Guido van Rossumd8faa362007-04-27 19:54:29 +0000453 gen = XMLGenerator(result)
Fred Drake004d5e62000-10-23 17:22:08 +0000454
Guido van Rossumd8faa362007-04-27 19:54:29 +0000455 gen.startDocument()
456 gen.startElement("doc", {})
457 gen.characters("huhei")
458 gen.endElement("doc")
459 gen.endDocument()
Lars Gustäbel96753b32000-09-24 12:24:24 +0000460
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200461 self.assertEqual(result.getvalue(), self.xml("<doc>huhei</doc>"))
Lars Gustäbel96753b32000-09-24 12:24:24 +0000462
R. David Murraya90032a2010-10-17 22:46:45 +0000463 def test_xmlgen_content_empty(self):
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200464 result = self.ioclass()
R. David Murraya90032a2010-10-17 22:46:45 +0000465 gen = XMLGenerator(result, short_empty_elements=True)
466
467 gen.startDocument()
468 gen.startElement("doc", {})
469 gen.characters("huhei")
470 gen.endElement("doc")
471 gen.endDocument()
472
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200473 self.assertEqual(result.getvalue(), self.xml("<doc>huhei</doc>"))
R. David Murraya90032a2010-10-17 22:46:45 +0000474
Guido van Rossumd8faa362007-04-27 19:54:29 +0000475 def test_xmlgen_pi(self):
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200476 result = self.ioclass()
Guido van Rossumd8faa362007-04-27 19:54:29 +0000477 gen = XMLGenerator(result)
Fred Drake004d5e62000-10-23 17:22:08 +0000478
Guido van Rossumd8faa362007-04-27 19:54:29 +0000479 gen.startDocument()
480 gen.processingInstruction("test", "data")
481 gen.startElement("doc", {})
482 gen.endElement("doc")
483 gen.endDocument()
Lars Gustäbel96753b32000-09-24 12:24:24 +0000484
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200485 self.assertEqual(result.getvalue(),
486 self.xml("<?test data?><doc></doc>"))
Lars Gustäbel96753b32000-09-24 12:24:24 +0000487
Guido van Rossumd8faa362007-04-27 19:54:29 +0000488 def test_xmlgen_content_escape(self):
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200489 result = self.ioclass()
Guido van Rossumd8faa362007-04-27 19:54:29 +0000490 gen = XMLGenerator(result)
Fred Drake004d5e62000-10-23 17:22:08 +0000491
Guido van Rossumd8faa362007-04-27 19:54:29 +0000492 gen.startDocument()
493 gen.startElement("doc", {})
494 gen.characters("<huhei&")
495 gen.endElement("doc")
496 gen.endDocument()
Lars Gustäbel96753b32000-09-24 12:24:24 +0000497
Ezio Melottib3aedd42010-11-20 19:04:17 +0000498 self.assertEqual(result.getvalue(),
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200499 self.xml("<doc>&lt;huhei&amp;</doc>"))
Lars Gustäbel96753b32000-09-24 12:24:24 +0000500
Guido van Rossumd8faa362007-04-27 19:54:29 +0000501 def test_xmlgen_attr_escape(self):
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200502 result = self.ioclass()
Guido van Rossumd8faa362007-04-27 19:54:29 +0000503 gen = XMLGenerator(result)
Fred Drakec9fadf92001-08-07 19:17:06 +0000504
Guido van Rossumd8faa362007-04-27 19:54:29 +0000505 gen.startDocument()
506 gen.startElement("doc", {"a": '"'})
507 gen.startElement("e", {"a": "'"})
508 gen.endElement("e")
509 gen.startElement("e", {"a": "'\""})
510 gen.endElement("e")
511 gen.startElement("e", {"a": "\n\r\t"})
512 gen.endElement("e")
513 gen.endElement("doc")
514 gen.endDocument()
Fred Drakec9fadf92001-08-07 19:17:06 +0000515
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200516 self.assertEqual(result.getvalue(), self.xml(
517 "<doc a='\"'><e a=\"'\"></e>"
518 "<e a=\"'&quot;\"></e>"
519 "<e a=\"&#10;&#13;&#9;\"></e></doc>"))
520
521 def test_xmlgen_encoding(self):
522 encodings = ('iso-8859-15', 'utf-8', 'utf-8-sig',
523 'utf-16', 'utf-16be', 'utf-16le',
524 'utf-32', 'utf-32be', 'utf-32le')
525 for encoding in encodings:
526 result = self.ioclass()
527 gen = XMLGenerator(result, encoding=encoding)
528
529 gen.startDocument()
530 gen.startElement("doc", {"a": '\u20ac'})
531 gen.characters("\u20ac")
532 gen.endElement("doc")
533 gen.endDocument()
534
535 self.assertEqual(result.getvalue(),
536 self.xml('<doc a="\u20ac">\u20ac</doc>', encoding=encoding))
537
538 def test_xmlgen_unencodable(self):
539 result = self.ioclass()
540 gen = XMLGenerator(result, encoding='ascii')
541
542 gen.startDocument()
543 gen.startElement("doc", {"a": '\u20ac'})
544 gen.characters("\u20ac")
545 gen.endElement("doc")
546 gen.endDocument()
547
548 self.assertEqual(result.getvalue(),
549 self.xml('<doc a="&#8364;">&#8364;</doc>', encoding='ascii'))
Fred Drakec9fadf92001-08-07 19:17:06 +0000550
Guido van Rossumd8faa362007-04-27 19:54:29 +0000551 def test_xmlgen_ignorable(self):
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200552 result = self.ioclass()
Guido van Rossumd8faa362007-04-27 19:54:29 +0000553 gen = XMLGenerator(result)
Fred Drake004d5e62000-10-23 17:22:08 +0000554
Guido van Rossumd8faa362007-04-27 19:54:29 +0000555 gen.startDocument()
556 gen.startElement("doc", {})
557 gen.ignorableWhitespace(" ")
558 gen.endElement("doc")
559 gen.endDocument()
Lars Gustäbel96753b32000-09-24 12:24:24 +0000560
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200561 self.assertEqual(result.getvalue(), self.xml("<doc> </doc>"))
Lars Gustäbel96753b32000-09-24 12:24:24 +0000562
R. David Murraya90032a2010-10-17 22:46:45 +0000563 def test_xmlgen_ignorable_empty(self):
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200564 result = self.ioclass()
R. David Murraya90032a2010-10-17 22:46:45 +0000565 gen = XMLGenerator(result, short_empty_elements=True)
566
567 gen.startDocument()
568 gen.startElement("doc", {})
569 gen.ignorableWhitespace(" ")
570 gen.endElement("doc")
571 gen.endDocument()
572
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200573 self.assertEqual(result.getvalue(), self.xml("<doc> </doc>"))
R. David Murraya90032a2010-10-17 22:46:45 +0000574
Serhiy Storchaka3eab6b32013-05-12 17:31:16 +0300575 def test_xmlgen_encoding_bytes(self):
576 encodings = ('iso-8859-15', 'utf-8', 'utf-8-sig',
577 'utf-16', 'utf-16be', 'utf-16le',
578 'utf-32', 'utf-32be', 'utf-32le')
579 for encoding in encodings:
580 result = self.ioclass()
581 gen = XMLGenerator(result, encoding=encoding)
582
583 gen.startDocument()
584 gen.startElement("doc", {"a": '\u20ac'})
585 gen.characters("\u20ac".encode(encoding))
586 gen.ignorableWhitespace(" ".encode(encoding))
587 gen.endElement("doc")
588 gen.endDocument()
589
590 self.assertEqual(result.getvalue(),
591 self.xml('<doc a="\u20ac">\u20ac </doc>', encoding=encoding))
592
Guido van Rossumd8faa362007-04-27 19:54:29 +0000593 def test_xmlgen_ns(self):
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200594 result = self.ioclass()
Guido van Rossumd8faa362007-04-27 19:54:29 +0000595 gen = XMLGenerator(result)
Lars Gustäbel96753b32000-09-24 12:24:24 +0000596
Guido van Rossumd8faa362007-04-27 19:54:29 +0000597 gen.startDocument()
598 gen.startPrefixMapping("ns1", ns_uri)
599 gen.startElementNS((ns_uri, "doc"), "ns1:doc", {})
600 # add an unqualified name
601 gen.startElementNS((None, "udoc"), None, {})
602 gen.endElementNS((None, "udoc"), None)
603 gen.endElementNS((ns_uri, "doc"), "ns1:doc")
604 gen.endPrefixMapping("ns1")
605 gen.endDocument()
Fred Drake004d5e62000-10-23 17:22:08 +0000606
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200607 self.assertEqual(result.getvalue(), self.xml(
608 '<ns1:doc xmlns:ns1="%s"><udoc></udoc></ns1:doc>' %
Guido van Rossumd8faa362007-04-27 19:54:29 +0000609 ns_uri))
Lars Gustäbel96753b32000-09-24 12:24:24 +0000610
R. David Murraya90032a2010-10-17 22:46:45 +0000611 def test_xmlgen_ns_empty(self):
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200612 result = self.ioclass()
R. David Murraya90032a2010-10-17 22:46:45 +0000613 gen = XMLGenerator(result, short_empty_elements=True)
614
615 gen.startDocument()
616 gen.startPrefixMapping("ns1", ns_uri)
617 gen.startElementNS((ns_uri, "doc"), "ns1:doc", {})
618 # add an unqualified name
619 gen.startElementNS((None, "udoc"), None, {})
620 gen.endElementNS((None, "udoc"), None)
621 gen.endElementNS((ns_uri, "doc"), "ns1:doc")
622 gen.endPrefixMapping("ns1")
623 gen.endDocument()
624
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200625 self.assertEqual(result.getvalue(), self.xml(
626 '<ns1:doc xmlns:ns1="%s"><udoc/></ns1:doc>' %
R. David Murraya90032a2010-10-17 22:46:45 +0000627 ns_uri))
628
Guido van Rossumd8faa362007-04-27 19:54:29 +0000629 def test_1463026_1(self):
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200630 result = self.ioclass()
Guido van Rossumd8faa362007-04-27 19:54:29 +0000631 gen = XMLGenerator(result)
Thomas Wouterscf297e42007-02-23 15:07:44 +0000632
Guido van Rossumd8faa362007-04-27 19:54:29 +0000633 gen.startDocument()
634 gen.startElementNS((None, 'a'), 'a', {(None, 'b'):'c'})
635 gen.endElementNS((None, 'a'), 'a')
636 gen.endDocument()
Thomas Wouterscf297e42007-02-23 15:07:44 +0000637
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200638 self.assertEqual(result.getvalue(), self.xml('<a b="c"></a>'))
Thomas Wouterscf297e42007-02-23 15:07:44 +0000639
R. David Murraya90032a2010-10-17 22:46:45 +0000640 def test_1463026_1_empty(self):
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200641 result = self.ioclass()
R. David Murraya90032a2010-10-17 22:46:45 +0000642 gen = XMLGenerator(result, short_empty_elements=True)
643
644 gen.startDocument()
645 gen.startElementNS((None, 'a'), 'a', {(None, 'b'):'c'})
646 gen.endElementNS((None, 'a'), 'a')
647 gen.endDocument()
648
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200649 self.assertEqual(result.getvalue(), self.xml('<a b="c"/>'))
R. David Murraya90032a2010-10-17 22:46:45 +0000650
Guido van Rossumd8faa362007-04-27 19:54:29 +0000651 def test_1463026_2(self):
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200652 result = self.ioclass()
Guido van Rossumd8faa362007-04-27 19:54:29 +0000653 gen = XMLGenerator(result)
Thomas Wouterscf297e42007-02-23 15:07:44 +0000654
Guido van Rossumd8faa362007-04-27 19:54:29 +0000655 gen.startDocument()
656 gen.startPrefixMapping(None, 'qux')
657 gen.startElementNS(('qux', 'a'), 'a', {})
658 gen.endElementNS(('qux', 'a'), 'a')
659 gen.endPrefixMapping(None)
660 gen.endDocument()
Thomas Wouterscf297e42007-02-23 15:07:44 +0000661
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200662 self.assertEqual(result.getvalue(), self.xml('<a xmlns="qux"></a>'))
Thomas Wouterscf297e42007-02-23 15:07:44 +0000663
R. David Murraya90032a2010-10-17 22:46:45 +0000664 def test_1463026_2_empty(self):
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200665 result = self.ioclass()
R. David Murraya90032a2010-10-17 22:46:45 +0000666 gen = XMLGenerator(result, short_empty_elements=True)
667
668 gen.startDocument()
669 gen.startPrefixMapping(None, 'qux')
670 gen.startElementNS(('qux', 'a'), 'a', {})
671 gen.endElementNS(('qux', 'a'), 'a')
672 gen.endPrefixMapping(None)
673 gen.endDocument()
674
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200675 self.assertEqual(result.getvalue(), self.xml('<a xmlns="qux"/>'))
R. David Murraya90032a2010-10-17 22:46:45 +0000676
Guido van Rossumd8faa362007-04-27 19:54:29 +0000677 def test_1463026_3(self):
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200678 result = self.ioclass()
Guido van Rossumd8faa362007-04-27 19:54:29 +0000679 gen = XMLGenerator(result)
Thomas Wouterscf297e42007-02-23 15:07:44 +0000680
Guido van Rossumd8faa362007-04-27 19:54:29 +0000681 gen.startDocument()
682 gen.startPrefixMapping('my', 'qux')
683 gen.startElementNS(('qux', 'a'), 'a', {(None, 'b'):'c'})
684 gen.endElementNS(('qux', 'a'), 'a')
685 gen.endPrefixMapping('my')
686 gen.endDocument()
Thomas Wouterscf297e42007-02-23 15:07:44 +0000687
Ezio Melottib3aedd42010-11-20 19:04:17 +0000688 self.assertEqual(result.getvalue(),
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200689 self.xml('<my:a xmlns:my="qux" b="c"></my:a>'))
Lars Gustäbel96753b32000-09-24 12:24:24 +0000690
R. David Murraya90032a2010-10-17 22:46:45 +0000691 def test_1463026_3_empty(self):
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200692 result = self.ioclass()
R. David Murraya90032a2010-10-17 22:46:45 +0000693 gen = XMLGenerator(result, short_empty_elements=True)
694
695 gen.startDocument()
696 gen.startPrefixMapping('my', 'qux')
697 gen.startElementNS(('qux', 'a'), 'a', {(None, 'b'):'c'})
698 gen.endElementNS(('qux', 'a'), 'a')
699 gen.endPrefixMapping('my')
700 gen.endDocument()
701
Ezio Melottib3aedd42010-11-20 19:04:17 +0000702 self.assertEqual(result.getvalue(),
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200703 self.xml('<my:a xmlns:my="qux" b="c"/>'))
R. David Murraya90032a2010-10-17 22:46:45 +0000704
Antoine Pitrou6b03ee62010-10-27 18:33:30 +0000705 def test_5027_1(self):
706 # The xml prefix (as in xml:lang below) is reserved and bound by
707 # definition to http://www.w3.org/XML/1998/namespace. XMLGenerator had
Andrew Svetlov737fb892012-12-18 21:14:22 +0200708 # a bug whereby a KeyError is raised because this namespace is missing
Antoine Pitrou6b03ee62010-10-27 18:33:30 +0000709 # from a dictionary.
710 #
711 # This test demonstrates the bug by parsing a document.
712 test_xml = StringIO(
713 '<?xml version="1.0"?>'
714 '<a:g1 xmlns:a="http://example.com/ns">'
715 '<a:g2 xml:lang="en">Hello</a:g2>'
716 '</a:g1>')
717
718 parser = make_parser()
719 parser.setFeature(feature_namespaces, True)
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200720 result = self.ioclass()
Antoine Pitrou6b03ee62010-10-27 18:33:30 +0000721 gen = XMLGenerator(result)
722 parser.setContentHandler(gen)
723 parser.parse(test_xml)
724
Ezio Melottib3aedd42010-11-20 19:04:17 +0000725 self.assertEqual(result.getvalue(),
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200726 self.xml(
Ezio Melottib3aedd42010-11-20 19:04:17 +0000727 '<a:g1 xmlns:a="http://example.com/ns">'
728 '<a:g2 xml:lang="en">Hello</a:g2>'
729 '</a:g1>'))
Antoine Pitrou6b03ee62010-10-27 18:33:30 +0000730
731 def test_5027_2(self):
732 # The xml prefix (as in xml:lang below) is reserved and bound by
733 # definition to http://www.w3.org/XML/1998/namespace. XMLGenerator had
Andrew Svetlov737fb892012-12-18 21:14:22 +0200734 # a bug whereby a KeyError is raised because this namespace is missing
Antoine Pitrou6b03ee62010-10-27 18:33:30 +0000735 # from a dictionary.
736 #
737 # This test demonstrates the bug by direct manipulation of the
738 # XMLGenerator.
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200739 result = self.ioclass()
Antoine Pitrou6b03ee62010-10-27 18:33:30 +0000740 gen = XMLGenerator(result)
741
742 gen.startDocument()
743 gen.startPrefixMapping('a', 'http://example.com/ns')
744 gen.startElementNS(('http://example.com/ns', 'g1'), 'g1', {})
745 lang_attr = {('http://www.w3.org/XML/1998/namespace', 'lang'): 'en'}
746 gen.startElementNS(('http://example.com/ns', 'g2'), 'g2', lang_attr)
747 gen.characters('Hello')
748 gen.endElementNS(('http://example.com/ns', 'g2'), 'g2')
749 gen.endElementNS(('http://example.com/ns', 'g1'), 'g1')
750 gen.endPrefixMapping('a')
751 gen.endDocument()
752
Ezio Melottib3aedd42010-11-20 19:04:17 +0000753 self.assertEqual(result.getvalue(),
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200754 self.xml(
Ezio Melottib3aedd42010-11-20 19:04:17 +0000755 '<a:g1 xmlns:a="http://example.com/ns">'
756 '<a:g2 xml:lang="en">Hello</a:g2>'
757 '</a:g1>'))
Antoine Pitrou6b03ee62010-10-27 18:33:30 +0000758
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200759 def test_no_close_file(self):
760 result = self.ioclass()
761 def func(out):
762 gen = XMLGenerator(out)
763 gen.startDocument()
764 gen.startElement("doc", {})
765 func(result)
766 self.assertFalse(result.closed)
767
Serhiy Storchakaa5f13d22013-02-25 13:46:10 +0200768 def test_xmlgen_fragment(self):
769 result = self.ioclass()
770 gen = XMLGenerator(result)
771
772 # Don't call gen.startDocument()
773 gen.startElement("foo", {"a": "1.0"})
774 gen.characters("Hello")
775 gen.endElement("foo")
776 gen.startElement("bar", {"b": "2.0"})
777 gen.endElement("bar")
778 # Don't call gen.endDocument()
779
780 self.assertEqual(result.getvalue(),
781 self.xml('<foo a="1.0">Hello</foo><bar b="2.0"></bar>')[len(self.xml('')):])
782
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200783class StringXmlgenTest(XmlgenTest, unittest.TestCase):
784 ioclass = StringIO
785
786 def xml(self, doc, encoding='iso-8859-1'):
787 return '<?xml version="1.0" encoding="%s"?>\n%s' % (encoding, doc)
788
789 test_xmlgen_unencodable = None
790
791class BytesXmlgenTest(XmlgenTest, unittest.TestCase):
792 ioclass = BytesIO
793
794 def xml(self, doc, encoding='iso-8859-1'):
795 return ('<?xml version="1.0" encoding="%s"?>\n%s' %
796 (encoding, doc)).encode(encoding, 'xmlcharrefreplace')
797
798class WriterXmlgenTest(BytesXmlgenTest):
799 class ioclass(list):
800 write = list.append
801 closed = False
802
803 def seekable(self):
804 return True
805
806 def tell(self):
807 # return 0 at start and not 0 after start
808 return len(self)
809
810 def getvalue(self):
811 return b''.join(self)
812
Georg Brandlc502df42013-05-12 11:41:12 +0200813class StreamWriterXmlgenTest(XmlgenTest, unittest.TestCase):
814 def ioclass(self):
815 raw = BytesIO()
816 writer = codecs.getwriter('ascii')(raw, 'xmlcharrefreplace')
817 writer.getvalue = raw.getvalue
818 return writer
819
820 def xml(self, doc, encoding='iso-8859-1'):
821 return ('<?xml version="1.0" encoding="%s"?>\n%s' %
822 (encoding, doc)).encode('ascii', 'xmlcharrefreplace')
823
824class StreamReaderWriterXmlgenTest(XmlgenTest, unittest.TestCase):
825 fname = support.TESTFN + '-codecs'
826
827 def ioclass(self):
828 writer = codecs.open(self.fname, 'w', encoding='ascii',
829 errors='xmlcharrefreplace', buffering=0)
Antoine Pitrou2adb6fe2013-05-13 22:34:21 +0200830 def cleanup():
831 writer.close()
832 support.unlink(self.fname)
833 self.addCleanup(cleanup)
Richard Oudkerk90a24272013-05-18 18:11:30 +0100834 def getvalue():
835 # Windows will not let use reopen without first closing
836 writer.close()
837 with open(writer.name, 'rb') as f:
838 return f.read()
839 writer.getvalue = getvalue
Georg Brandlc502df42013-05-12 11:41:12 +0200840 return writer
841
Georg Brandlc502df42013-05-12 11:41:12 +0200842 def xml(self, doc, encoding='iso-8859-1'):
843 return ('<?xml version="1.0" encoding="%s"?>\n%s' %
844 (encoding, doc)).encode('ascii', 'xmlcharrefreplace')
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200845
846start = b'<?xml version="1.0" encoding="iso-8859-1"?>\n'
847
Fred Drake004d5e62000-10-23 17:22:08 +0000848
Guido van Rossumd8faa362007-04-27 19:54:29 +0000849class XMLFilterBaseTest(unittest.TestCase):
850 def test_filter_basic(self):
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200851 result = BytesIO()
Guido van Rossumd8faa362007-04-27 19:54:29 +0000852 gen = XMLGenerator(result)
853 filter = XMLFilterBase()
854 filter.setContentHandler(gen)
Lars Gustäbel96753b32000-09-24 12:24:24 +0000855
Guido van Rossumd8faa362007-04-27 19:54:29 +0000856 filter.startDocument()
857 filter.startElement("doc", {})
858 filter.characters("content")
859 filter.ignorableWhitespace(" ")
860 filter.endElement("doc")
861 filter.endDocument()
862
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200863 self.assertEqual(result.getvalue(), start + b"<doc>content </doc>")
Lars Gustäbel96753b32000-09-24 12:24:24 +0000864
865# ===========================================================================
866#
867# expatreader tests
868#
869# ===========================================================================
870
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200871with open(TEST_XMLFILE_OUT, 'rb') as f:
Benjamin Petersond5df36d2010-10-31 18:23:23 +0000872 xml_test_out = f.read()
Lars Gustäbelb7536d52000-09-24 18:53:56 +0000873
Guido van Rossumd8faa362007-04-27 19:54:29 +0000874class ExpatReaderTest(XmlTestBase):
Lars Gustäbelb7536d52000-09-24 18:53:56 +0000875
Guido van Rossumd8faa362007-04-27 19:54:29 +0000876 # ===== XMLReader support
Lars Gustäbelb7536d52000-09-24 18:53:56 +0000877
Serhiy Storchakaaa9563c2015-04-02 20:55:59 +0300878 def test_expat_binary_file(self):
Guido van Rossumd8faa362007-04-27 19:54:29 +0000879 parser = create_parser()
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200880 result = BytesIO()
Guido van Rossumd8faa362007-04-27 19:54:29 +0000881 xmlgen = XMLGenerator(result)
Lars Gustäbelb7536d52000-09-24 18:53:56 +0000882
Guido van Rossumd8faa362007-04-27 19:54:29 +0000883 parser.setContentHandler(xmlgen)
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200884 with open(TEST_XMLFILE, 'rb') as f:
Benjamin Petersond5df36d2010-10-31 18:23:23 +0000885 parser.parse(f)
Lars Gustäbelb7536d52000-09-24 18:53:56 +0000886
Ezio Melottib3aedd42010-11-20 19:04:17 +0000887 self.assertEqual(result.getvalue(), xml_test_out)
Lars Gustäbelb7536d52000-09-24 18:53:56 +0000888
Serhiy Storchakaaa9563c2015-04-02 20:55:59 +0300889 def test_expat_text_file(self):
890 parser = create_parser()
891 result = BytesIO()
892 xmlgen = XMLGenerator(result)
893
894 parser.setContentHandler(xmlgen)
895 with open(TEST_XMLFILE, 'rt', encoding='iso-8859-1') as f:
896 parser.parse(f)
897
898 self.assertEqual(result.getvalue(), xml_test_out)
899
Serhiy Storchaka1a4ed4c2013-02-02 12:17:05 +0200900 @requires_nonascii_filenames
Serhiy Storchakaaa9563c2015-04-02 20:55:59 +0300901 def test_expat_binary_file_nonascii(self):
Serhiy Storchakad5202392013-02-02 10:31:17 +0200902 fname = support.TESTFN_UNICODE
903 shutil.copyfile(TEST_XMLFILE, fname)
904 self.addCleanup(support.unlink, fname)
905
906 parser = create_parser()
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200907 result = BytesIO()
Serhiy Storchakad5202392013-02-02 10:31:17 +0200908 xmlgen = XMLGenerator(result)
909
910 parser.setContentHandler(xmlgen)
Serhiy Storchakaaa9563c2015-04-02 20:55:59 +0300911 parser.parse(open(fname, 'rb'))
Serhiy Storchakad5202392013-02-02 10:31:17 +0200912
913 self.assertEqual(result.getvalue(), xml_test_out)
914
Serhiy Storchakafc8e9b02014-11-27 22:13:16 +0200915 def test_expat_binary_file_bytes_name(self):
916 fname = os.fsencode(TEST_XMLFILE)
917 parser = create_parser()
918 result = BytesIO()
919 xmlgen = XMLGenerator(result)
920
921 parser.setContentHandler(xmlgen)
922 with open(fname, 'rb') as f:
923 parser.parse(f)
924
925 self.assertEqual(result.getvalue(), xml_test_out)
926
927 def test_expat_binary_file_int_name(self):
928 parser = create_parser()
929 result = BytesIO()
930 xmlgen = XMLGenerator(result)
931
932 parser.setContentHandler(xmlgen)
933 with open(TEST_XMLFILE, 'rb') as f:
934 with open(f.fileno(), 'rb', closefd=False) as f2:
935 parser.parse(f2)
936
937 self.assertEqual(result.getvalue(), xml_test_out)
938
Guido van Rossumd8faa362007-04-27 19:54:29 +0000939 # ===== DTDHandler support
Lars Gustäbelb7536d52000-09-24 18:53:56 +0000940
Guido van Rossumd8faa362007-04-27 19:54:29 +0000941 class TestDTDHandler:
Lars Gustäbelb7536d52000-09-24 18:53:56 +0000942
Guido van Rossumd8faa362007-04-27 19:54:29 +0000943 def __init__(self):
944 self._notations = []
945 self._entities = []
Lars Gustäbelb7536d52000-09-24 18:53:56 +0000946
Guido van Rossumd8faa362007-04-27 19:54:29 +0000947 def notationDecl(self, name, publicId, systemId):
948 self._notations.append((name, publicId, systemId))
Lars Gustäbelb7536d52000-09-24 18:53:56 +0000949
Guido van Rossumd8faa362007-04-27 19:54:29 +0000950 def unparsedEntityDecl(self, name, publicId, systemId, ndata):
951 self._entities.append((name, publicId, systemId, ndata))
Lars Gustäbel2fc52942000-10-24 15:35:07 +0000952
Christian Heimes17b1d5d2018-09-23 09:50:25 +0200953
954 class TestEntityRecorder:
955 def __init__(self):
956 self.entities = []
957
958 def resolveEntity(self, publicId, systemId):
959 self.entities.append((publicId, systemId))
960 source = InputSource()
961 source.setPublicId(publicId)
962 source.setSystemId(systemId)
963 return source
964
Guido van Rossumd8faa362007-04-27 19:54:29 +0000965 def test_expat_dtdhandler(self):
966 parser = create_parser()
967 handler = self.TestDTDHandler()
968 parser.setDTDHandler(handler)
Lars Gustäbel2fc52942000-10-24 15:35:07 +0000969
Guido van Rossumd8faa362007-04-27 19:54:29 +0000970 parser.feed('<!DOCTYPE doc [\n')
971 parser.feed(' <!ENTITY img SYSTEM "expat.gif" NDATA GIF>\n')
972 parser.feed(' <!NOTATION GIF PUBLIC "-//CompuServe//NOTATION Graphics Interchange Format 89a//EN">\n')
973 parser.feed(']>\n')
974 parser.feed('<doc></doc>')
975 parser.close()
Lars Gustäbel2fc52942000-10-24 15:35:07 +0000976
Ezio Melottib3aedd42010-11-20 19:04:17 +0000977 self.assertEqual(handler._notations,
Guido van Rossumd8faa362007-04-27 19:54:29 +0000978 [("GIF", "-//CompuServe//NOTATION Graphics Interchange Format 89a//EN", None)])
Ezio Melottib3aedd42010-11-20 19:04:17 +0000979 self.assertEqual(handler._entities, [("img", None, "expat.gif", "GIF")])
Lars Gustäbel2fc52942000-10-24 15:35:07 +0000980
Christian Heimes17b1d5d2018-09-23 09:50:25 +0200981 def test_expat_external_dtd_enabled(self):
982 parser = create_parser()
983 parser.setFeature(feature_external_ges, True)
984 resolver = self.TestEntityRecorder()
985 parser.setEntityResolver(resolver)
986
987 with self.assertRaises(URLError):
988 parser.feed(
989 '<!DOCTYPE external SYSTEM "unsupported://non-existing">\n'
990 )
991 self.assertEqual(
992 resolver.entities, [(None, 'unsupported://non-existing')]
993 )
994
995 def test_expat_external_dtd_default(self):
996 parser = create_parser()
997 resolver = self.TestEntityRecorder()
998 parser.setEntityResolver(resolver)
999
1000 parser.feed(
1001 '<!DOCTYPE external SYSTEM "unsupported://non-existing">\n'
1002 )
1003 parser.feed('<doc />')
1004 parser.close()
1005 self.assertEqual(resolver.entities, [])
1006
Guido van Rossumd8faa362007-04-27 19:54:29 +00001007 # ===== EntityResolver support
Lars Gustäbel2fc52942000-10-24 15:35:07 +00001008
Guido van Rossumd8faa362007-04-27 19:54:29 +00001009 class TestEntityResolver:
Lars Gustäbel2fc52942000-10-24 15:35:07 +00001010
Guido van Rossumd8faa362007-04-27 19:54:29 +00001011 def resolveEntity(self, publicId, systemId):
1012 inpsrc = InputSource()
Serhiy Storchaka88efc522013-02-10 14:29:52 +02001013 inpsrc.setByteStream(BytesIO(b"<entity/>"))
Guido van Rossumd8faa362007-04-27 19:54:29 +00001014 return inpsrc
Lars Gustäbel2fc52942000-10-24 15:35:07 +00001015
Christian Heimes17b1d5d2018-09-23 09:50:25 +02001016 def test_expat_entityresolver_enabled(self):
Guido van Rossumd8faa362007-04-27 19:54:29 +00001017 parser = create_parser()
Christian Heimes17b1d5d2018-09-23 09:50:25 +02001018 parser.setFeature(feature_external_ges, True)
Guido van Rossumd8faa362007-04-27 19:54:29 +00001019 parser.setEntityResolver(self.TestEntityResolver())
Serhiy Storchaka88efc522013-02-10 14:29:52 +02001020 result = BytesIO()
Guido van Rossumd8faa362007-04-27 19:54:29 +00001021 parser.setContentHandler(XMLGenerator(result))
Lars Gustäbel2fc52942000-10-24 15:35:07 +00001022
Guido van Rossumd8faa362007-04-27 19:54:29 +00001023 parser.feed('<!DOCTYPE doc [\n')
1024 parser.feed(' <!ENTITY test SYSTEM "whatever">\n')
1025 parser.feed(']>\n')
1026 parser.feed('<doc>&test;</doc>')
1027 parser.close()
Lars Gustäbel2fc52942000-10-24 15:35:07 +00001028
Ezio Melottib3aedd42010-11-20 19:04:17 +00001029 self.assertEqual(result.getvalue(), start +
Serhiy Storchaka88efc522013-02-10 14:29:52 +02001030 b"<doc><entity></entity></doc>")
Lars Gustäbel2fc52942000-10-24 15:35:07 +00001031
Christian Heimes17b1d5d2018-09-23 09:50:25 +02001032 def test_expat_entityresolver_default(self):
1033 parser = create_parser()
1034 self.assertEqual(parser.getFeature(feature_external_ges), False)
1035 parser.setEntityResolver(self.TestEntityResolver())
1036 result = BytesIO()
1037 parser.setContentHandler(XMLGenerator(result))
1038
1039 parser.feed('<!DOCTYPE doc [\n')
1040 parser.feed(' <!ENTITY test SYSTEM "whatever">\n')
1041 parser.feed(']>\n')
1042 parser.feed('<doc>&test;</doc>')
1043 parser.close()
1044
1045 self.assertEqual(result.getvalue(), start +
1046 b"<doc></doc>")
1047
Guido van Rossumd8faa362007-04-27 19:54:29 +00001048 # ===== Attributes support
Lars Gustäbel2fc52942000-10-24 15:35:07 +00001049
Guido van Rossumd8faa362007-04-27 19:54:29 +00001050 class AttrGatherer(ContentHandler):
Lars Gustäbel2fc52942000-10-24 15:35:07 +00001051
Guido van Rossumd8faa362007-04-27 19:54:29 +00001052 def startElement(self, name, attrs):
1053 self._attrs = attrs
Lars Gustäbel2fc52942000-10-24 15:35:07 +00001054
Guido van Rossumd8faa362007-04-27 19:54:29 +00001055 def startElementNS(self, name, qname, attrs):
1056 self._attrs = attrs
Lars Gustäbel2fc52942000-10-24 15:35:07 +00001057
Guido van Rossumd8faa362007-04-27 19:54:29 +00001058 def test_expat_attrs_empty(self):
1059 parser = create_parser()
1060 gather = self.AttrGatherer()
1061 parser.setContentHandler(gather)
1062
1063 parser.feed("<doc/>")
1064 parser.close()
1065
1066 self.verify_empty_attrs(gather._attrs)
1067
1068 def test_expat_attrs_wattr(self):
1069 parser = create_parser()
1070 gather = self.AttrGatherer()
1071 parser.setContentHandler(gather)
1072
1073 parser.feed("<doc attr='val'/>")
1074 parser.close()
1075
1076 self.verify_attrs_wattr(gather._attrs)
1077
1078 def test_expat_nsattrs_empty(self):
1079 parser = create_parser(1)
1080 gather = self.AttrGatherer()
1081 parser.setContentHandler(gather)
1082
1083 parser.feed("<doc/>")
1084 parser.close()
1085
1086 self.verify_empty_nsattrs(gather._attrs)
1087
1088 def test_expat_nsattrs_wattr(self):
1089 parser = create_parser(1)
1090 gather = self.AttrGatherer()
1091 parser.setContentHandler(gather)
1092
1093 parser.feed("<doc xmlns:ns='%s' ns:attr='val'/>" % ns_uri)
1094 parser.close()
1095
1096 attrs = gather._attrs
1097
Ezio Melottib3aedd42010-11-20 19:04:17 +00001098 self.assertEqual(attrs.getLength(), 1)
1099 self.assertEqual(attrs.getNames(), [(ns_uri, "attr")])
Guido van Rossumd8faa362007-04-27 19:54:29 +00001100 self.assertTrue((attrs.getQNames() == [] or
1101 attrs.getQNames() == ["ns:attr"]))
Ezio Melottib3aedd42010-11-20 19:04:17 +00001102 self.assertEqual(len(attrs), 1)
Benjamin Peterson577473f2010-01-19 00:09:57 +00001103 self.assertIn((ns_uri, "attr"), attrs)
Ezio Melottib3aedd42010-11-20 19:04:17 +00001104 self.assertEqual(attrs.get((ns_uri, "attr")), "val")
1105 self.assertEqual(attrs.get((ns_uri, "attr"), 25), "val")
1106 self.assertEqual(list(attrs.items()), [((ns_uri, "attr"), "val")])
1107 self.assertEqual(list(attrs.values()), ["val"])
1108 self.assertEqual(attrs.getValue((ns_uri, "attr")), "val")
1109 self.assertEqual(attrs[(ns_uri, "attr")], "val")
Guido van Rossumd8faa362007-04-27 19:54:29 +00001110
1111 # ===== InputSource support
1112
Benjamin Petersona7f4f5a2008-09-04 02:22:52 +00001113 def test_expat_inpsource_filename(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(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
Benjamin Petersona7f4f5a2008-09-04 02:22:52 +00001123 def test_expat_inpsource_sysid(self):
Guido van Rossumd8faa362007-04-27 19:54:29 +00001124 parser = create_parser()
Serhiy Storchaka88efc522013-02-10 14:29:52 +02001125 result = BytesIO()
Guido van Rossumd8faa362007-04-27 19:54:29 +00001126 xmlgen = XMLGenerator(result)
1127
1128 parser.setContentHandler(xmlgen)
Florent Xiclunaf15351d2010-03-13 23:24:31 +00001129 parser.parse(InputSource(TEST_XMLFILE))
Guido van Rossumd8faa362007-04-27 19:54:29 +00001130
Ezio Melottib3aedd42010-11-20 19:04:17 +00001131 self.assertEqual(result.getvalue(), xml_test_out)
Guido van Rossumd8faa362007-04-27 19:54:29 +00001132
Serhiy Storchaka1a4ed4c2013-02-02 12:17:05 +02001133 @requires_nonascii_filenames
Serhiy Storchakad5202392013-02-02 10:31:17 +02001134 def test_expat_inpsource_sysid_nonascii(self):
1135 fname = support.TESTFN_UNICODE
1136 shutil.copyfile(TEST_XMLFILE, fname)
1137 self.addCleanup(support.unlink, fname)
1138
1139 parser = create_parser()
Serhiy Storchaka88efc522013-02-10 14:29:52 +02001140 result = BytesIO()
Serhiy Storchakad5202392013-02-02 10:31:17 +02001141 xmlgen = XMLGenerator(result)
1142
1143 parser.setContentHandler(xmlgen)
1144 parser.parse(InputSource(fname))
1145
1146 self.assertEqual(result.getvalue(), xml_test_out)
1147
Serhiy Storchakaaa9563c2015-04-02 20:55:59 +03001148 def test_expat_inpsource_byte_stream(self):
Guido van Rossumd8faa362007-04-27 19:54:29 +00001149 parser = create_parser()
Serhiy Storchaka88efc522013-02-10 14:29:52 +02001150 result = BytesIO()
Guido van Rossumd8faa362007-04-27 19:54:29 +00001151 xmlgen = XMLGenerator(result)
1152
1153 parser.setContentHandler(xmlgen)
1154 inpsrc = InputSource()
Serhiy Storchaka88efc522013-02-10 14:29:52 +02001155 with open(TEST_XMLFILE, 'rb') as f:
Benjamin Petersond5df36d2010-10-31 18:23:23 +00001156 inpsrc.setByteStream(f)
1157 parser.parse(inpsrc)
Guido van Rossumd8faa362007-04-27 19:54:29 +00001158
Ezio Melottib3aedd42010-11-20 19:04:17 +00001159 self.assertEqual(result.getvalue(), xml_test_out)
Guido van Rossumd8faa362007-04-27 19:54:29 +00001160
Serhiy Storchaka61de0872015-04-02 21:00:13 +03001161 def test_expat_inpsource_character_stream(self):
1162 parser = create_parser()
1163 result = BytesIO()
1164 xmlgen = XMLGenerator(result)
1165
1166 parser.setContentHandler(xmlgen)
1167 inpsrc = InputSource()
1168 with open(TEST_XMLFILE, 'rt', encoding='iso-8859-1') as f:
1169 inpsrc.setCharacterStream(f)
1170 parser.parse(inpsrc)
1171
1172 self.assertEqual(result.getvalue(), xml_test_out)
1173
Guido van Rossumd8faa362007-04-27 19:54:29 +00001174 # ===== IncrementalParser support
1175
1176 def test_expat_incremental(self):
Serhiy Storchaka88efc522013-02-10 14:29:52 +02001177 result = BytesIO()
Guido van Rossumd8faa362007-04-27 19:54:29 +00001178 xmlgen = XMLGenerator(result)
1179 parser = create_parser()
1180 parser.setContentHandler(xmlgen)
1181
1182 parser.feed("<doc>")
1183 parser.feed("</doc>")
1184 parser.close()
1185
Serhiy Storchaka88efc522013-02-10 14:29:52 +02001186 self.assertEqual(result.getvalue(), start + b"<doc></doc>")
Guido van Rossumd8faa362007-04-27 19:54:29 +00001187
1188 def test_expat_incremental_reset(self):
Serhiy Storchaka88efc522013-02-10 14:29:52 +02001189 result = BytesIO()
Guido van Rossumd8faa362007-04-27 19:54:29 +00001190 xmlgen = XMLGenerator(result)
1191 parser = create_parser()
1192 parser.setContentHandler(xmlgen)
1193
1194 parser.feed("<doc>")
1195 parser.feed("text")
1196
Serhiy Storchaka88efc522013-02-10 14:29:52 +02001197 result = BytesIO()
Guido van Rossumd8faa362007-04-27 19:54:29 +00001198 xmlgen = XMLGenerator(result)
1199 parser.setContentHandler(xmlgen)
1200 parser.reset()
1201
1202 parser.feed("<doc>")
1203 parser.feed("text")
1204 parser.feed("</doc>")
1205 parser.close()
1206
Serhiy Storchaka88efc522013-02-10 14:29:52 +02001207 self.assertEqual(result.getvalue(), start + b"<doc>text</doc>")
Guido van Rossumd8faa362007-04-27 19:54:29 +00001208
1209 # ===== Locator support
1210
1211 def test_expat_locator_noinfo(self):
Serhiy Storchaka88efc522013-02-10 14:29:52 +02001212 result = BytesIO()
Guido van Rossumd8faa362007-04-27 19:54:29 +00001213 xmlgen = XMLGenerator(result)
1214 parser = create_parser()
1215 parser.setContentHandler(xmlgen)
1216
1217 parser.feed("<doc>")
1218 parser.feed("</doc>")
1219 parser.close()
1220
Ezio Melottib3aedd42010-11-20 19:04:17 +00001221 self.assertEqual(parser.getSystemId(), None)
1222 self.assertEqual(parser.getPublicId(), None)
1223 self.assertEqual(parser.getLineNumber(), 1)
Guido van Rossumd8faa362007-04-27 19:54:29 +00001224
Benjamin Petersona7f4f5a2008-09-04 02:22:52 +00001225 def test_expat_locator_withinfo(self):
Serhiy Storchaka88efc522013-02-10 14:29:52 +02001226 result = BytesIO()
Guido van Rossumd8faa362007-04-27 19:54:29 +00001227 xmlgen = XMLGenerator(result)
1228 parser = create_parser()
1229 parser.setContentHandler(xmlgen)
Florent Xiclunaf15351d2010-03-13 23:24:31 +00001230 parser.parse(TEST_XMLFILE)
Guido van Rossumd8faa362007-04-27 19:54:29 +00001231
Ezio Melottib3aedd42010-11-20 19:04:17 +00001232 self.assertEqual(parser.getSystemId(), TEST_XMLFILE)
1233 self.assertEqual(parser.getPublicId(), None)
Lars Gustäbel2fc52942000-10-24 15:35:07 +00001234
Serhiy Storchaka1a4ed4c2013-02-02 12:17:05 +02001235 @requires_nonascii_filenames
Serhiy Storchakad5202392013-02-02 10:31:17 +02001236 def test_expat_locator_withinfo_nonascii(self):
1237 fname = support.TESTFN_UNICODE
1238 shutil.copyfile(TEST_XMLFILE, fname)
1239 self.addCleanup(support.unlink, fname)
1240
Serhiy Storchaka88efc522013-02-10 14:29:52 +02001241 result = BytesIO()
Serhiy Storchakad5202392013-02-02 10:31:17 +02001242 xmlgen = XMLGenerator(result)
1243 parser = create_parser()
1244 parser.setContentHandler(xmlgen)
1245 parser.parse(fname)
1246
1247 self.assertEqual(parser.getSystemId(), fname)
1248 self.assertEqual(parser.getPublicId(), None)
1249
Martin v. Löwis80670bc2000-10-06 21:13:23 +00001250
1251# ===========================================================================
1252#
1253# error reporting
1254#
1255# ===========================================================================
1256
Guido van Rossumd8faa362007-04-27 19:54:29 +00001257class ErrorReportingTest(unittest.TestCase):
1258 def test_expat_inpsource_location(self):
1259 parser = create_parser()
1260 parser.setContentHandler(ContentHandler()) # do nothing
1261 source = InputSource()
Serhiy Storchaka88efc522013-02-10 14:29:52 +02001262 source.setByteStream(BytesIO(b"<foo bar foobar>")) #ill-formed
Guido van Rossumd8faa362007-04-27 19:54:29 +00001263 name = "a file name"
1264 source.setSystemId(name)
1265 try:
1266 parser.parse(source)
1267 self.fail()
1268 except SAXException as e:
Ezio Melottib3aedd42010-11-20 19:04:17 +00001269 self.assertEqual(e.getSystemId(), name)
Martin v. Löwis80670bc2000-10-06 21:13:23 +00001270
Guido van Rossumd8faa362007-04-27 19:54:29 +00001271 def test_expat_incomplete(self):
1272 parser = create_parser()
1273 parser.setContentHandler(ContentHandler()) # do nothing
1274 self.assertRaises(SAXParseException, parser.parse, StringIO("<foo>"))
Serhiy Storchakaab914782015-05-06 09:36:06 +03001275 self.assertEqual(parser.getColumnNumber(), 5)
1276 self.assertEqual(parser.getLineNumber(), 1)
Martin v. Löwis80670bc2000-10-06 21:13:23 +00001277
Guido van Rossumd8faa362007-04-27 19:54:29 +00001278 def test_sax_parse_exception_str(self):
1279 # pass various values from a locator to the SAXParseException to
1280 # make sure that the __str__() doesn't fall apart when None is
1281 # passed instead of an integer line and column number
1282 #
1283 # use "normal" values for the locator:
1284 str(SAXParseException("message", None,
1285 self.DummyLocator(1, 1)))
1286 # use None for the line number:
1287 str(SAXParseException("message", None,
1288 self.DummyLocator(None, 1)))
1289 # use None for the column number:
1290 str(SAXParseException("message", None,
1291 self.DummyLocator(1, None)))
1292 # use None for both:
1293 str(SAXParseException("message", None,
1294 self.DummyLocator(None, None)))
Fred Drake6fd0b0d2004-03-20 08:15:30 +00001295
Guido van Rossumd8faa362007-04-27 19:54:29 +00001296 class DummyLocator:
1297 def __init__(self, lineno, colno):
1298 self._lineno = lineno
1299 self._colno = colno
Fred Drake6fd0b0d2004-03-20 08:15:30 +00001300
Guido van Rossumd8faa362007-04-27 19:54:29 +00001301 def getPublicId(self):
1302 return "pubid"
Fred Drake6fd0b0d2004-03-20 08:15:30 +00001303
Guido van Rossumd8faa362007-04-27 19:54:29 +00001304 def getSystemId(self):
1305 return "sysid"
Fred Drake6fd0b0d2004-03-20 08:15:30 +00001306
Guido van Rossumd8faa362007-04-27 19:54:29 +00001307 def getLineNumber(self):
1308 return self._lineno
Fred Drake6fd0b0d2004-03-20 08:15:30 +00001309
Guido van Rossumd8faa362007-04-27 19:54:29 +00001310 def getColumnNumber(self):
1311 return self._colno
Martin v. Löwis80670bc2000-10-06 21:13:23 +00001312
Lars Gustäbelab647872000-09-24 18:40:52 +00001313# ===========================================================================
1314#
1315# xmlreader tests
1316#
1317# ===========================================================================
1318
Guido van Rossumd8faa362007-04-27 19:54:29 +00001319class XmlReaderTest(XmlTestBase):
Lars Gustäbelab647872000-09-24 18:40:52 +00001320
Guido van Rossumd8faa362007-04-27 19:54:29 +00001321 # ===== AttributesImpl
1322 def test_attrs_empty(self):
1323 self.verify_empty_attrs(AttributesImpl({}))
Lars Gustäbelab647872000-09-24 18:40:52 +00001324
Guido van Rossumd8faa362007-04-27 19:54:29 +00001325 def test_attrs_wattr(self):
1326 self.verify_attrs_wattr(AttributesImpl({"attr" : "val"}))
Lars Gustäbelab647872000-09-24 18:40:52 +00001327
Guido van Rossumd8faa362007-04-27 19:54:29 +00001328 def test_nsattrs_empty(self):
1329 self.verify_empty_nsattrs(AttributesNSImpl({}, {}))
Lars Gustäbelab647872000-09-24 18:40:52 +00001330
Guido van Rossumd8faa362007-04-27 19:54:29 +00001331 def test_nsattrs_wattr(self):
1332 attrs = AttributesNSImpl({(ns_uri, "attr") : "val"},
1333 {(ns_uri, "attr") : "ns:attr"})
Fred Drake004d5e62000-10-23 17:22:08 +00001334
Ezio Melottib3aedd42010-11-20 19:04:17 +00001335 self.assertEqual(attrs.getLength(), 1)
1336 self.assertEqual(attrs.getNames(), [(ns_uri, "attr")])
1337 self.assertEqual(attrs.getQNames(), ["ns:attr"])
1338 self.assertEqual(len(attrs), 1)
Benjamin Peterson577473f2010-01-19 00:09:57 +00001339 self.assertIn((ns_uri, "attr"), attrs)
Ezio Melottib3aedd42010-11-20 19:04:17 +00001340 self.assertEqual(list(attrs.keys()), [(ns_uri, "attr")])
1341 self.assertEqual(attrs.get((ns_uri, "attr")), "val")
1342 self.assertEqual(attrs.get((ns_uri, "attr"), 25), "val")
1343 self.assertEqual(list(attrs.items()), [((ns_uri, "attr"), "val")])
1344 self.assertEqual(list(attrs.values()), ["val"])
1345 self.assertEqual(attrs.getValue((ns_uri, "attr")), "val")
1346 self.assertEqual(attrs.getValueByQName("ns:attr"), "val")
1347 self.assertEqual(attrs.getNameByQName("ns:attr"), (ns_uri, "attr"))
1348 self.assertEqual(attrs[(ns_uri, "attr")], "val")
1349 self.assertEqual(attrs.getQNameByName((ns_uri, "attr")), "ns:attr")
Fred Drake004d5e62000-10-23 17:22:08 +00001350
Lars Gustäbelab647872000-09-24 18:40:52 +00001351
Christian Heimesbbe741d2008-03-28 10:53:29 +00001352def test_main():
Guido van Rossumd8faa362007-04-27 19:54:29 +00001353 run_unittest(MakeParserTest,
Serhiy Storchaka13e41c52015-04-02 23:05:57 +03001354 ParseTest,
Guido van Rossumd8faa362007-04-27 19:54:29 +00001355 SaxutilsTest,
Serhiy Storchakaaa9563c2015-04-02 20:55:59 +03001356 PrepareInputSourceTest,
Serhiy Storchaka88efc522013-02-10 14:29:52 +02001357 StringXmlgenTest,
1358 BytesXmlgenTest,
1359 WriterXmlgenTest,
Georg Brandlc502df42013-05-12 11:41:12 +02001360 StreamWriterXmlgenTest,
1361 StreamReaderWriterXmlgenTest,
Guido van Rossumd8faa362007-04-27 19:54:29 +00001362 ExpatReaderTest,
1363 ErrorReportingTest,
1364 XmlReaderTest)
Lars Gustäbelb7536d52000-09-24 18:53:56 +00001365
Guido van Rossumd8faa362007-04-27 19:54:29 +00001366if __name__ == "__main__":
Christian Heimesbbe741d2008-03-28 10:53:29 +00001367 test_main()