blob: 3044960a0ed165466a7a425161ba49e5e50ed98c [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 Heimes394e55a2018-09-24 14:38:37 +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 Heimes394e55a2018-09-24 14:38:37 +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
257
Lars Gustäbel96753b32000-09-24 12:24:24 +0000258# ===========================================================================
259#
260# saxutils tests
261#
262# ===========================================================================
263
Guido van Rossumd8faa362007-04-27 19:54:29 +0000264class SaxutilsTest(unittest.TestCase):
265 # ===== escape
266 def test_escape_basic(self):
Ezio Melottib3aedd42010-11-20 19:04:17 +0000267 self.assertEqual(escape("Donald Duck & Co"), "Donald Duck &amp; Co")
Lars Gustäbel96753b32000-09-24 12:24:24 +0000268
Guido van Rossumd8faa362007-04-27 19:54:29 +0000269 def test_escape_all(self):
Ezio Melottib3aedd42010-11-20 19:04:17 +0000270 self.assertEqual(escape("<Donald Duck & Co>"),
271 "&lt;Donald Duck &amp; Co&gt;")
Lars Gustäbel96753b32000-09-24 12:24:24 +0000272
Guido van Rossumd8faa362007-04-27 19:54:29 +0000273 def test_escape_extra(self):
Ezio Melottib3aedd42010-11-20 19:04:17 +0000274 self.assertEqual(escape("Hei på deg", {"å" : "&aring;"}),
275 "Hei p&aring; deg")
Lars Gustäbel96753b32000-09-24 12:24:24 +0000276
Guido van Rossumd8faa362007-04-27 19:54:29 +0000277 # ===== unescape
278 def test_unescape_basic(self):
Ezio Melottib3aedd42010-11-20 19:04:17 +0000279 self.assertEqual(unescape("Donald Duck &amp; Co"), "Donald Duck & Co")
Lars Gustäbel96753b32000-09-24 12:24:24 +0000280
Guido van Rossumd8faa362007-04-27 19:54:29 +0000281 def test_unescape_all(self):
Ezio Melottib3aedd42010-11-20 19:04:17 +0000282 self.assertEqual(unescape("&lt;Donald Duck &amp; Co&gt;"),
283 "<Donald Duck & Co>")
Martin v. Löwis74b51ac2002-10-26 14:50:45 +0000284
Guido van Rossumd8faa362007-04-27 19:54:29 +0000285 def test_unescape_extra(self):
Ezio Melottib3aedd42010-11-20 19:04:17 +0000286 self.assertEqual(unescape("Hei på deg", {"å" : "&aring;"}),
287 "Hei p&aring; deg")
Martin v. Löwis74b51ac2002-10-26 14:50:45 +0000288
Guido van Rossumd8faa362007-04-27 19:54:29 +0000289 def test_unescape_amp_extra(self):
Ezio Melottib3aedd42010-11-20 19:04:17 +0000290 self.assertEqual(unescape("&amp;foo;", {"&foo;": "splat"}), "&foo;")
Martin v. Löwis74b51ac2002-10-26 14:50:45 +0000291
Guido van Rossumd8faa362007-04-27 19:54:29 +0000292 # ===== quoteattr
293 def test_quoteattr_basic(self):
Ezio Melottib3aedd42010-11-20 19:04:17 +0000294 self.assertEqual(quoteattr("Donald Duck & Co"),
295 '"Donald Duck &amp; Co"')
Martin v. Löwis74b51ac2002-10-26 14:50:45 +0000296
Guido van Rossumd8faa362007-04-27 19:54:29 +0000297 def test_single_quoteattr(self):
Ezio Melottib3aedd42010-11-20 19:04:17 +0000298 self.assertEqual(quoteattr('Includes "double" quotes'),
299 '\'Includes "double" quotes\'')
Fred Drake32f3add2002-10-28 17:58:48 +0000300
Guido van Rossumd8faa362007-04-27 19:54:29 +0000301 def test_double_quoteattr(self):
Ezio Melottib3aedd42010-11-20 19:04:17 +0000302 self.assertEqual(quoteattr("Includes 'single' quotes"),
303 "\"Includes 'single' quotes\"")
Fred Drakeacd32d32001-07-19 16:10:15 +0000304
Guido van Rossumd8faa362007-04-27 19:54:29 +0000305 def test_single_double_quoteattr(self):
Ezio Melottib3aedd42010-11-20 19:04:17 +0000306 self.assertEqual(quoteattr("Includes 'single' and \"double\" quotes"),
307 "\"Includes 'single' and &quot;double&quot; quotes\"")
Fred Drakeacd32d32001-07-19 16:10:15 +0000308
Guido van Rossumd8faa362007-04-27 19:54:29 +0000309 # ===== make_parser
310 def test_make_parser(self):
Martin v. Löwis962c9e72000-10-06 17:41:52 +0000311 # Creating a parser should succeed - it should fall back
312 # to the expatreader
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000313 p = make_parser(['xml.parsers.no_such_parser'])
Martin v. Löwis962c9e72000-10-06 17:41:52 +0000314
315
Serhiy Storchakaaa9563c2015-04-02 20:55:59 +0300316class PrepareInputSourceTest(unittest.TestCase):
317
318 def setUp(self):
319 self.file = support.TESTFN
320 with open(self.file, "w") as tmp:
321 tmp.write("This was read from a file.")
322
323 def tearDown(self):
324 support.unlink(self.file)
325
326 def make_byte_stream(self):
327 return BytesIO(b"This is a byte stream.")
328
Serhiy Storchaka61de0872015-04-02 21:00:13 +0300329 def make_character_stream(self):
330 return StringIO("This is a character stream.")
331
Serhiy Storchakaaa9563c2015-04-02 20:55:59 +0300332 def checkContent(self, stream, content):
333 self.assertIsNotNone(stream)
334 self.assertEqual(stream.read(), content)
335 stream.close()
336
337
Serhiy Storchaka61de0872015-04-02 21:00:13 +0300338 def test_character_stream(self):
339 # If the source is an InputSource with a character stream, use it.
340 src = InputSource(self.file)
341 src.setCharacterStream(self.make_character_stream())
342 prep = prepare_input_source(src)
343 self.assertIsNone(prep.getByteStream())
344 self.checkContent(prep.getCharacterStream(),
345 "This is a character stream.")
346
Serhiy Storchakaaa9563c2015-04-02 20:55:59 +0300347 def test_byte_stream(self):
348 # If the source is an InputSource that does not have a character
349 # stream but does have a byte stream, use the byte stream.
350 src = InputSource(self.file)
351 src.setByteStream(self.make_byte_stream())
352 prep = prepare_input_source(src)
353 self.assertIsNone(prep.getCharacterStream())
354 self.checkContent(prep.getByteStream(),
355 b"This is a byte stream.")
356
357 def test_system_id(self):
358 # If the source is an InputSource that has neither a character
359 # stream nor a byte stream, open the system ID.
360 src = InputSource(self.file)
361 prep = prepare_input_source(src)
362 self.assertIsNone(prep.getCharacterStream())
363 self.checkContent(prep.getByteStream(),
364 b"This was read from a file.")
365
366 def test_string(self):
367 # If the source is a string, use it as a system ID and open it.
368 prep = prepare_input_source(self.file)
369 self.assertIsNone(prep.getCharacterStream())
370 self.checkContent(prep.getByteStream(),
371 b"This was read from a file.")
372
373 def test_binary_file(self):
374 # If the source is a binary file-like object, use it as a byte
375 # stream.
376 prep = prepare_input_source(self.make_byte_stream())
377 self.assertIsNone(prep.getCharacterStream())
378 self.checkContent(prep.getByteStream(),
379 b"This is a byte stream.")
380
Serhiy Storchaka61de0872015-04-02 21:00:13 +0300381 def test_text_file(self):
382 # If the source is a text file-like object, use it as a character
383 # stream.
384 prep = prepare_input_source(self.make_character_stream())
385 self.assertIsNone(prep.getByteStream())
386 self.checkContent(prep.getCharacterStream(),
387 "This is a character stream.")
388
Serhiy Storchakaaa9563c2015-04-02 20:55:59 +0300389
Lars Gustäbel96753b32000-09-24 12:24:24 +0000390# ===== XMLGenerator
391
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200392class XmlgenTest:
Guido van Rossumd8faa362007-04-27 19:54:29 +0000393 def test_xmlgen_basic(self):
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200394 result = self.ioclass()
Guido van Rossumd8faa362007-04-27 19:54:29 +0000395 gen = XMLGenerator(result)
396 gen.startDocument()
397 gen.startElement("doc", {})
398 gen.endElement("doc")
399 gen.endDocument()
Lars Gustäbel96753b32000-09-24 12:24:24 +0000400
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200401 self.assertEqual(result.getvalue(), self.xml("<doc></doc>"))
Lars Gustäbel96753b32000-09-24 12:24:24 +0000402
R. David Murraya90032a2010-10-17 22:46:45 +0000403 def test_xmlgen_basic_empty(self):
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200404 result = self.ioclass()
R. David Murraya90032a2010-10-17 22:46:45 +0000405 gen = XMLGenerator(result, short_empty_elements=True)
406 gen.startDocument()
407 gen.startElement("doc", {})
408 gen.endElement("doc")
409 gen.endDocument()
410
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200411 self.assertEqual(result.getvalue(), self.xml("<doc/>"))
R. David Murraya90032a2010-10-17 22:46:45 +0000412
Guido van Rossumd8faa362007-04-27 19:54:29 +0000413 def test_xmlgen_content(self):
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200414 result = self.ioclass()
Guido van Rossumd8faa362007-04-27 19:54:29 +0000415 gen = XMLGenerator(result)
Fred Drake004d5e62000-10-23 17:22:08 +0000416
Guido van Rossumd8faa362007-04-27 19:54:29 +0000417 gen.startDocument()
418 gen.startElement("doc", {})
419 gen.characters("huhei")
420 gen.endElement("doc")
421 gen.endDocument()
Lars Gustäbel96753b32000-09-24 12:24:24 +0000422
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200423 self.assertEqual(result.getvalue(), self.xml("<doc>huhei</doc>"))
Lars Gustäbel96753b32000-09-24 12:24:24 +0000424
R. David Murraya90032a2010-10-17 22:46:45 +0000425 def test_xmlgen_content_empty(self):
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200426 result = self.ioclass()
R. David Murraya90032a2010-10-17 22:46:45 +0000427 gen = XMLGenerator(result, short_empty_elements=True)
428
429 gen.startDocument()
430 gen.startElement("doc", {})
431 gen.characters("huhei")
432 gen.endElement("doc")
433 gen.endDocument()
434
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200435 self.assertEqual(result.getvalue(), self.xml("<doc>huhei</doc>"))
R. David Murraya90032a2010-10-17 22:46:45 +0000436
Guido van Rossumd8faa362007-04-27 19:54:29 +0000437 def test_xmlgen_pi(self):
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200438 result = self.ioclass()
Guido van Rossumd8faa362007-04-27 19:54:29 +0000439 gen = XMLGenerator(result)
Fred Drake004d5e62000-10-23 17:22:08 +0000440
Guido van Rossumd8faa362007-04-27 19:54:29 +0000441 gen.startDocument()
442 gen.processingInstruction("test", "data")
443 gen.startElement("doc", {})
444 gen.endElement("doc")
445 gen.endDocument()
Lars Gustäbel96753b32000-09-24 12:24:24 +0000446
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200447 self.assertEqual(result.getvalue(),
448 self.xml("<?test data?><doc></doc>"))
Lars Gustäbel96753b32000-09-24 12:24:24 +0000449
Guido van Rossumd8faa362007-04-27 19:54:29 +0000450 def test_xmlgen_content_escape(self):
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200451 result = self.ioclass()
Guido van Rossumd8faa362007-04-27 19:54:29 +0000452 gen = XMLGenerator(result)
Fred Drake004d5e62000-10-23 17:22:08 +0000453
Guido van Rossumd8faa362007-04-27 19:54:29 +0000454 gen.startDocument()
455 gen.startElement("doc", {})
456 gen.characters("<huhei&")
457 gen.endElement("doc")
458 gen.endDocument()
Lars Gustäbel96753b32000-09-24 12:24:24 +0000459
Ezio Melottib3aedd42010-11-20 19:04:17 +0000460 self.assertEqual(result.getvalue(),
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200461 self.xml("<doc>&lt;huhei&amp;</doc>"))
Lars Gustäbel96753b32000-09-24 12:24:24 +0000462
Guido van Rossumd8faa362007-04-27 19:54:29 +0000463 def test_xmlgen_attr_escape(self):
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200464 result = self.ioclass()
Guido van Rossumd8faa362007-04-27 19:54:29 +0000465 gen = XMLGenerator(result)
Fred Drakec9fadf92001-08-07 19:17:06 +0000466
Guido van Rossumd8faa362007-04-27 19:54:29 +0000467 gen.startDocument()
468 gen.startElement("doc", {"a": '"'})
469 gen.startElement("e", {"a": "'"})
470 gen.endElement("e")
471 gen.startElement("e", {"a": "'\""})
472 gen.endElement("e")
473 gen.startElement("e", {"a": "\n\r\t"})
474 gen.endElement("e")
475 gen.endElement("doc")
476 gen.endDocument()
Fred Drakec9fadf92001-08-07 19:17:06 +0000477
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200478 self.assertEqual(result.getvalue(), self.xml(
479 "<doc a='\"'><e a=\"'\"></e>"
480 "<e a=\"'&quot;\"></e>"
481 "<e a=\"&#10;&#13;&#9;\"></e></doc>"))
482
483 def test_xmlgen_encoding(self):
484 encodings = ('iso-8859-15', 'utf-8', 'utf-8-sig',
485 'utf-16', 'utf-16be', 'utf-16le',
486 'utf-32', 'utf-32be', 'utf-32le')
487 for encoding in encodings:
488 result = self.ioclass()
489 gen = XMLGenerator(result, encoding=encoding)
490
491 gen.startDocument()
492 gen.startElement("doc", {"a": '\u20ac'})
493 gen.characters("\u20ac")
494 gen.endElement("doc")
495 gen.endDocument()
496
497 self.assertEqual(result.getvalue(),
498 self.xml('<doc a="\u20ac">\u20ac</doc>', encoding=encoding))
499
500 def test_xmlgen_unencodable(self):
501 result = self.ioclass()
502 gen = XMLGenerator(result, encoding='ascii')
503
504 gen.startDocument()
505 gen.startElement("doc", {"a": '\u20ac'})
506 gen.characters("\u20ac")
507 gen.endElement("doc")
508 gen.endDocument()
509
510 self.assertEqual(result.getvalue(),
511 self.xml('<doc a="&#8364;">&#8364;</doc>', encoding='ascii'))
Fred Drakec9fadf92001-08-07 19:17:06 +0000512
Guido van Rossumd8faa362007-04-27 19:54:29 +0000513 def test_xmlgen_ignorable(self):
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200514 result = self.ioclass()
Guido van Rossumd8faa362007-04-27 19:54:29 +0000515 gen = XMLGenerator(result)
Fred Drake004d5e62000-10-23 17:22:08 +0000516
Guido van Rossumd8faa362007-04-27 19:54:29 +0000517 gen.startDocument()
518 gen.startElement("doc", {})
519 gen.ignorableWhitespace(" ")
520 gen.endElement("doc")
521 gen.endDocument()
Lars Gustäbel96753b32000-09-24 12:24:24 +0000522
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200523 self.assertEqual(result.getvalue(), self.xml("<doc> </doc>"))
Lars Gustäbel96753b32000-09-24 12:24:24 +0000524
R. David Murraya90032a2010-10-17 22:46:45 +0000525 def test_xmlgen_ignorable_empty(self):
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200526 result = self.ioclass()
R. David Murraya90032a2010-10-17 22:46:45 +0000527 gen = XMLGenerator(result, short_empty_elements=True)
528
529 gen.startDocument()
530 gen.startElement("doc", {})
531 gen.ignorableWhitespace(" ")
532 gen.endElement("doc")
533 gen.endDocument()
534
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200535 self.assertEqual(result.getvalue(), self.xml("<doc> </doc>"))
R. David Murraya90032a2010-10-17 22:46:45 +0000536
Serhiy Storchaka3eab6b32013-05-12 17:31:16 +0300537 def test_xmlgen_encoding_bytes(self):
538 encodings = ('iso-8859-15', 'utf-8', 'utf-8-sig',
539 'utf-16', 'utf-16be', 'utf-16le',
540 'utf-32', 'utf-32be', 'utf-32le')
541 for encoding in encodings:
542 result = self.ioclass()
543 gen = XMLGenerator(result, encoding=encoding)
544
545 gen.startDocument()
546 gen.startElement("doc", {"a": '\u20ac'})
547 gen.characters("\u20ac".encode(encoding))
548 gen.ignorableWhitespace(" ".encode(encoding))
549 gen.endElement("doc")
550 gen.endDocument()
551
552 self.assertEqual(result.getvalue(),
553 self.xml('<doc a="\u20ac">\u20ac </doc>', encoding=encoding))
554
Guido van Rossumd8faa362007-04-27 19:54:29 +0000555 def test_xmlgen_ns(self):
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200556 result = self.ioclass()
Guido van Rossumd8faa362007-04-27 19:54:29 +0000557 gen = XMLGenerator(result)
Lars Gustäbel96753b32000-09-24 12:24:24 +0000558
Guido van Rossumd8faa362007-04-27 19:54:29 +0000559 gen.startDocument()
560 gen.startPrefixMapping("ns1", ns_uri)
561 gen.startElementNS((ns_uri, "doc"), "ns1:doc", {})
562 # add an unqualified name
563 gen.startElementNS((None, "udoc"), None, {})
564 gen.endElementNS((None, "udoc"), None)
565 gen.endElementNS((ns_uri, "doc"), "ns1:doc")
566 gen.endPrefixMapping("ns1")
567 gen.endDocument()
Fred Drake004d5e62000-10-23 17:22:08 +0000568
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200569 self.assertEqual(result.getvalue(), self.xml(
570 '<ns1:doc xmlns:ns1="%s"><udoc></udoc></ns1:doc>' %
Guido van Rossumd8faa362007-04-27 19:54:29 +0000571 ns_uri))
Lars Gustäbel96753b32000-09-24 12:24:24 +0000572
R. David Murraya90032a2010-10-17 22:46:45 +0000573 def test_xmlgen_ns_empty(self):
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200574 result = self.ioclass()
R. David Murraya90032a2010-10-17 22:46:45 +0000575 gen = XMLGenerator(result, short_empty_elements=True)
576
577 gen.startDocument()
578 gen.startPrefixMapping("ns1", ns_uri)
579 gen.startElementNS((ns_uri, "doc"), "ns1:doc", {})
580 # add an unqualified name
581 gen.startElementNS((None, "udoc"), None, {})
582 gen.endElementNS((None, "udoc"), None)
583 gen.endElementNS((ns_uri, "doc"), "ns1:doc")
584 gen.endPrefixMapping("ns1")
585 gen.endDocument()
586
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200587 self.assertEqual(result.getvalue(), self.xml(
588 '<ns1:doc xmlns:ns1="%s"><udoc/></ns1:doc>' %
R. David Murraya90032a2010-10-17 22:46:45 +0000589 ns_uri))
590
Guido van Rossumd8faa362007-04-27 19:54:29 +0000591 def test_1463026_1(self):
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200592 result = self.ioclass()
Guido van Rossumd8faa362007-04-27 19:54:29 +0000593 gen = XMLGenerator(result)
Thomas Wouterscf297e42007-02-23 15:07:44 +0000594
Guido van Rossumd8faa362007-04-27 19:54:29 +0000595 gen.startDocument()
596 gen.startElementNS((None, 'a'), 'a', {(None, 'b'):'c'})
597 gen.endElementNS((None, 'a'), 'a')
598 gen.endDocument()
Thomas Wouterscf297e42007-02-23 15:07:44 +0000599
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200600 self.assertEqual(result.getvalue(), self.xml('<a b="c"></a>'))
Thomas Wouterscf297e42007-02-23 15:07:44 +0000601
R. David Murraya90032a2010-10-17 22:46:45 +0000602 def test_1463026_1_empty(self):
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200603 result = self.ioclass()
R. David Murraya90032a2010-10-17 22:46:45 +0000604 gen = XMLGenerator(result, short_empty_elements=True)
605
606 gen.startDocument()
607 gen.startElementNS((None, 'a'), 'a', {(None, 'b'):'c'})
608 gen.endElementNS((None, 'a'), 'a')
609 gen.endDocument()
610
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200611 self.assertEqual(result.getvalue(), self.xml('<a b="c"/>'))
R. David Murraya90032a2010-10-17 22:46:45 +0000612
Guido van Rossumd8faa362007-04-27 19:54:29 +0000613 def test_1463026_2(self):
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200614 result = self.ioclass()
Guido van Rossumd8faa362007-04-27 19:54:29 +0000615 gen = XMLGenerator(result)
Thomas Wouterscf297e42007-02-23 15:07:44 +0000616
Guido van Rossumd8faa362007-04-27 19:54:29 +0000617 gen.startDocument()
618 gen.startPrefixMapping(None, 'qux')
619 gen.startElementNS(('qux', 'a'), 'a', {})
620 gen.endElementNS(('qux', 'a'), 'a')
621 gen.endPrefixMapping(None)
622 gen.endDocument()
Thomas Wouterscf297e42007-02-23 15:07:44 +0000623
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200624 self.assertEqual(result.getvalue(), self.xml('<a xmlns="qux"></a>'))
Thomas Wouterscf297e42007-02-23 15:07:44 +0000625
R. David Murraya90032a2010-10-17 22:46:45 +0000626 def test_1463026_2_empty(self):
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200627 result = self.ioclass()
R. David Murraya90032a2010-10-17 22:46:45 +0000628 gen = XMLGenerator(result, short_empty_elements=True)
629
630 gen.startDocument()
631 gen.startPrefixMapping(None, 'qux')
632 gen.startElementNS(('qux', 'a'), 'a', {})
633 gen.endElementNS(('qux', 'a'), 'a')
634 gen.endPrefixMapping(None)
635 gen.endDocument()
636
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200637 self.assertEqual(result.getvalue(), self.xml('<a xmlns="qux"/>'))
R. David Murraya90032a2010-10-17 22:46:45 +0000638
Guido van Rossumd8faa362007-04-27 19:54:29 +0000639 def test_1463026_3(self):
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200640 result = self.ioclass()
Guido van Rossumd8faa362007-04-27 19:54:29 +0000641 gen = XMLGenerator(result)
Thomas Wouterscf297e42007-02-23 15:07:44 +0000642
Guido van Rossumd8faa362007-04-27 19:54:29 +0000643 gen.startDocument()
644 gen.startPrefixMapping('my', 'qux')
645 gen.startElementNS(('qux', 'a'), 'a', {(None, 'b'):'c'})
646 gen.endElementNS(('qux', 'a'), 'a')
647 gen.endPrefixMapping('my')
648 gen.endDocument()
Thomas Wouterscf297e42007-02-23 15:07:44 +0000649
Ezio Melottib3aedd42010-11-20 19:04:17 +0000650 self.assertEqual(result.getvalue(),
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200651 self.xml('<my:a xmlns:my="qux" b="c"></my:a>'))
Lars Gustäbel96753b32000-09-24 12:24:24 +0000652
R. David Murraya90032a2010-10-17 22:46:45 +0000653 def test_1463026_3_empty(self):
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200654 result = self.ioclass()
R. David Murraya90032a2010-10-17 22:46:45 +0000655 gen = XMLGenerator(result, short_empty_elements=True)
656
657 gen.startDocument()
658 gen.startPrefixMapping('my', 'qux')
659 gen.startElementNS(('qux', 'a'), 'a', {(None, 'b'):'c'})
660 gen.endElementNS(('qux', 'a'), 'a')
661 gen.endPrefixMapping('my')
662 gen.endDocument()
663
Ezio Melottib3aedd42010-11-20 19:04:17 +0000664 self.assertEqual(result.getvalue(),
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200665 self.xml('<my:a xmlns:my="qux" b="c"/>'))
R. David Murraya90032a2010-10-17 22:46:45 +0000666
Antoine Pitrou6b03ee62010-10-27 18:33:30 +0000667 def test_5027_1(self):
668 # The xml prefix (as in xml:lang below) is reserved and bound by
669 # definition to http://www.w3.org/XML/1998/namespace. XMLGenerator had
Andrew Svetlov737fb892012-12-18 21:14:22 +0200670 # a bug whereby a KeyError is raised because this namespace is missing
Antoine Pitrou6b03ee62010-10-27 18:33:30 +0000671 # from a dictionary.
672 #
673 # This test demonstrates the bug by parsing a document.
674 test_xml = StringIO(
675 '<?xml version="1.0"?>'
676 '<a:g1 xmlns:a="http://example.com/ns">'
677 '<a:g2 xml:lang="en">Hello</a:g2>'
678 '</a:g1>')
679
680 parser = make_parser()
681 parser.setFeature(feature_namespaces, True)
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200682 result = self.ioclass()
Antoine Pitrou6b03ee62010-10-27 18:33:30 +0000683 gen = XMLGenerator(result)
684 parser.setContentHandler(gen)
685 parser.parse(test_xml)
686
Ezio Melottib3aedd42010-11-20 19:04:17 +0000687 self.assertEqual(result.getvalue(),
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200688 self.xml(
Ezio Melottib3aedd42010-11-20 19:04:17 +0000689 '<a:g1 xmlns:a="http://example.com/ns">'
690 '<a:g2 xml:lang="en">Hello</a:g2>'
691 '</a:g1>'))
Antoine Pitrou6b03ee62010-10-27 18:33:30 +0000692
693 def test_5027_2(self):
694 # The xml prefix (as in xml:lang below) is reserved and bound by
695 # definition to http://www.w3.org/XML/1998/namespace. XMLGenerator had
Andrew Svetlov737fb892012-12-18 21:14:22 +0200696 # a bug whereby a KeyError is raised because this namespace is missing
Antoine Pitrou6b03ee62010-10-27 18:33:30 +0000697 # from a dictionary.
698 #
699 # This test demonstrates the bug by direct manipulation of the
700 # XMLGenerator.
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200701 result = self.ioclass()
Antoine Pitrou6b03ee62010-10-27 18:33:30 +0000702 gen = XMLGenerator(result)
703
704 gen.startDocument()
705 gen.startPrefixMapping('a', 'http://example.com/ns')
706 gen.startElementNS(('http://example.com/ns', 'g1'), 'g1', {})
707 lang_attr = {('http://www.w3.org/XML/1998/namespace', 'lang'): 'en'}
708 gen.startElementNS(('http://example.com/ns', 'g2'), 'g2', lang_attr)
709 gen.characters('Hello')
710 gen.endElementNS(('http://example.com/ns', 'g2'), 'g2')
711 gen.endElementNS(('http://example.com/ns', 'g1'), 'g1')
712 gen.endPrefixMapping('a')
713 gen.endDocument()
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
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200721 def test_no_close_file(self):
722 result = self.ioclass()
723 def func(out):
724 gen = XMLGenerator(out)
725 gen.startDocument()
726 gen.startElement("doc", {})
727 func(result)
728 self.assertFalse(result.closed)
729
Serhiy Storchakaa5f13d22013-02-25 13:46:10 +0200730 def test_xmlgen_fragment(self):
731 result = self.ioclass()
732 gen = XMLGenerator(result)
733
734 # Don't call gen.startDocument()
735 gen.startElement("foo", {"a": "1.0"})
736 gen.characters("Hello")
737 gen.endElement("foo")
738 gen.startElement("bar", {"b": "2.0"})
739 gen.endElement("bar")
740 # Don't call gen.endDocument()
741
742 self.assertEqual(result.getvalue(),
743 self.xml('<foo a="1.0">Hello</foo><bar b="2.0"></bar>')[len(self.xml('')):])
744
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200745class StringXmlgenTest(XmlgenTest, unittest.TestCase):
746 ioclass = StringIO
747
748 def xml(self, doc, encoding='iso-8859-1'):
749 return '<?xml version="1.0" encoding="%s"?>\n%s' % (encoding, doc)
750
751 test_xmlgen_unencodable = None
752
753class BytesXmlgenTest(XmlgenTest, unittest.TestCase):
754 ioclass = BytesIO
755
756 def xml(self, doc, encoding='iso-8859-1'):
757 return ('<?xml version="1.0" encoding="%s"?>\n%s' %
758 (encoding, doc)).encode(encoding, 'xmlcharrefreplace')
759
760class WriterXmlgenTest(BytesXmlgenTest):
761 class ioclass(list):
762 write = list.append
763 closed = False
764
765 def seekable(self):
766 return True
767
768 def tell(self):
769 # return 0 at start and not 0 after start
770 return len(self)
771
772 def getvalue(self):
773 return b''.join(self)
774
Georg Brandlc502df42013-05-12 11:41:12 +0200775class StreamWriterXmlgenTest(XmlgenTest, unittest.TestCase):
776 def ioclass(self):
777 raw = BytesIO()
778 writer = codecs.getwriter('ascii')(raw, 'xmlcharrefreplace')
779 writer.getvalue = raw.getvalue
780 return writer
781
782 def xml(self, doc, encoding='iso-8859-1'):
783 return ('<?xml version="1.0" encoding="%s"?>\n%s' %
784 (encoding, doc)).encode('ascii', 'xmlcharrefreplace')
785
786class StreamReaderWriterXmlgenTest(XmlgenTest, unittest.TestCase):
787 fname = support.TESTFN + '-codecs'
788
789 def ioclass(self):
790 writer = codecs.open(self.fname, 'w', encoding='ascii',
791 errors='xmlcharrefreplace', buffering=0)
Antoine Pitrou2adb6fe2013-05-13 22:34:21 +0200792 def cleanup():
793 writer.close()
794 support.unlink(self.fname)
795 self.addCleanup(cleanup)
Richard Oudkerk90a24272013-05-18 18:11:30 +0100796 def getvalue():
797 # Windows will not let use reopen without first closing
798 writer.close()
799 with open(writer.name, 'rb') as f:
800 return f.read()
801 writer.getvalue = getvalue
Georg Brandlc502df42013-05-12 11:41:12 +0200802 return writer
803
Georg Brandlc502df42013-05-12 11:41:12 +0200804 def xml(self, doc, encoding='iso-8859-1'):
805 return ('<?xml version="1.0" encoding="%s"?>\n%s' %
806 (encoding, doc)).encode('ascii', 'xmlcharrefreplace')
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200807
808start = b'<?xml version="1.0" encoding="iso-8859-1"?>\n'
809
Fred Drake004d5e62000-10-23 17:22:08 +0000810
Guido van Rossumd8faa362007-04-27 19:54:29 +0000811class XMLFilterBaseTest(unittest.TestCase):
812 def test_filter_basic(self):
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200813 result = BytesIO()
Guido van Rossumd8faa362007-04-27 19:54:29 +0000814 gen = XMLGenerator(result)
815 filter = XMLFilterBase()
816 filter.setContentHandler(gen)
Lars Gustäbel96753b32000-09-24 12:24:24 +0000817
Guido van Rossumd8faa362007-04-27 19:54:29 +0000818 filter.startDocument()
819 filter.startElement("doc", {})
820 filter.characters("content")
821 filter.ignorableWhitespace(" ")
822 filter.endElement("doc")
823 filter.endDocument()
824
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200825 self.assertEqual(result.getvalue(), start + b"<doc>content </doc>")
Lars Gustäbel96753b32000-09-24 12:24:24 +0000826
827# ===========================================================================
828#
829# expatreader tests
830#
831# ===========================================================================
832
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200833with open(TEST_XMLFILE_OUT, 'rb') as f:
Benjamin Petersond5df36d2010-10-31 18:23:23 +0000834 xml_test_out = f.read()
Lars Gustäbelb7536d52000-09-24 18:53:56 +0000835
Guido van Rossumd8faa362007-04-27 19:54:29 +0000836class ExpatReaderTest(XmlTestBase):
Lars Gustäbelb7536d52000-09-24 18:53:56 +0000837
Guido van Rossumd8faa362007-04-27 19:54:29 +0000838 # ===== XMLReader support
Lars Gustäbelb7536d52000-09-24 18:53:56 +0000839
Serhiy Storchakaaa9563c2015-04-02 20:55:59 +0300840 def test_expat_binary_file(self):
Guido van Rossumd8faa362007-04-27 19:54:29 +0000841 parser = create_parser()
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200842 result = BytesIO()
Guido van Rossumd8faa362007-04-27 19:54:29 +0000843 xmlgen = XMLGenerator(result)
Lars Gustäbelb7536d52000-09-24 18:53:56 +0000844
Guido van Rossumd8faa362007-04-27 19:54:29 +0000845 parser.setContentHandler(xmlgen)
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200846 with open(TEST_XMLFILE, 'rb') as f:
Benjamin Petersond5df36d2010-10-31 18:23:23 +0000847 parser.parse(f)
Lars Gustäbelb7536d52000-09-24 18:53:56 +0000848
Ezio Melottib3aedd42010-11-20 19:04:17 +0000849 self.assertEqual(result.getvalue(), xml_test_out)
Lars Gustäbelb7536d52000-09-24 18:53:56 +0000850
Serhiy Storchakaaa9563c2015-04-02 20:55:59 +0300851 def test_expat_text_file(self):
852 parser = create_parser()
853 result = BytesIO()
854 xmlgen = XMLGenerator(result)
855
856 parser.setContentHandler(xmlgen)
857 with open(TEST_XMLFILE, 'rt', encoding='iso-8859-1') as f:
858 parser.parse(f)
859
860 self.assertEqual(result.getvalue(), xml_test_out)
861
Serhiy Storchaka1a4ed4c2013-02-02 12:17:05 +0200862 @requires_nonascii_filenames
Serhiy Storchakaaa9563c2015-04-02 20:55:59 +0300863 def test_expat_binary_file_nonascii(self):
Serhiy Storchakad5202392013-02-02 10:31:17 +0200864 fname = support.TESTFN_UNICODE
865 shutil.copyfile(TEST_XMLFILE, fname)
866 self.addCleanup(support.unlink, fname)
867
868 parser = create_parser()
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200869 result = BytesIO()
Serhiy Storchakad5202392013-02-02 10:31:17 +0200870 xmlgen = XMLGenerator(result)
871
872 parser.setContentHandler(xmlgen)
Serhiy Storchakaaa9563c2015-04-02 20:55:59 +0300873 parser.parse(open(fname, 'rb'))
Serhiy Storchakad5202392013-02-02 10:31:17 +0200874
875 self.assertEqual(result.getvalue(), xml_test_out)
876
Serhiy Storchakafc8e9b02014-11-27 22:13:16 +0200877 def test_expat_binary_file_bytes_name(self):
878 fname = os.fsencode(TEST_XMLFILE)
879 parser = create_parser()
880 result = BytesIO()
881 xmlgen = XMLGenerator(result)
882
883 parser.setContentHandler(xmlgen)
884 with open(fname, 'rb') as f:
885 parser.parse(f)
886
887 self.assertEqual(result.getvalue(), xml_test_out)
888
889 def test_expat_binary_file_int_name(self):
890 parser = create_parser()
891 result = BytesIO()
892 xmlgen = XMLGenerator(result)
893
894 parser.setContentHandler(xmlgen)
895 with open(TEST_XMLFILE, 'rb') as f:
896 with open(f.fileno(), 'rb', closefd=False) as f2:
897 parser.parse(f2)
898
899 self.assertEqual(result.getvalue(), xml_test_out)
900
Guido van Rossumd8faa362007-04-27 19:54:29 +0000901 # ===== DTDHandler support
Lars Gustäbelb7536d52000-09-24 18:53:56 +0000902
Guido van Rossumd8faa362007-04-27 19:54:29 +0000903 class TestDTDHandler:
Lars Gustäbelb7536d52000-09-24 18:53:56 +0000904
Guido van Rossumd8faa362007-04-27 19:54:29 +0000905 def __init__(self):
906 self._notations = []
907 self._entities = []
Lars Gustäbelb7536d52000-09-24 18:53:56 +0000908
Guido van Rossumd8faa362007-04-27 19:54:29 +0000909 def notationDecl(self, name, publicId, systemId):
910 self._notations.append((name, publicId, systemId))
Lars Gustäbelb7536d52000-09-24 18:53:56 +0000911
Guido van Rossumd8faa362007-04-27 19:54:29 +0000912 def unparsedEntityDecl(self, name, publicId, systemId, ndata):
913 self._entities.append((name, publicId, systemId, ndata))
Lars Gustäbel2fc52942000-10-24 15:35:07 +0000914
Christian Heimes394e55a2018-09-24 14:38:37 +0200915
916 class TestEntityRecorder:
917 def __init__(self):
918 self.entities = []
919
920 def resolveEntity(self, publicId, systemId):
921 self.entities.append((publicId, systemId))
922 source = InputSource()
923 source.setPublicId(publicId)
924 source.setSystemId(systemId)
925 return source
926
Guido van Rossumd8faa362007-04-27 19:54:29 +0000927 def test_expat_dtdhandler(self):
928 parser = create_parser()
929 handler = self.TestDTDHandler()
930 parser.setDTDHandler(handler)
Lars Gustäbel2fc52942000-10-24 15:35:07 +0000931
Guido van Rossumd8faa362007-04-27 19:54:29 +0000932 parser.feed('<!DOCTYPE doc [\n')
933 parser.feed(' <!ENTITY img SYSTEM "expat.gif" NDATA GIF>\n')
934 parser.feed(' <!NOTATION GIF PUBLIC "-//CompuServe//NOTATION Graphics Interchange Format 89a//EN">\n')
935 parser.feed(']>\n')
936 parser.feed('<doc></doc>')
937 parser.close()
Lars Gustäbel2fc52942000-10-24 15:35:07 +0000938
Ezio Melottib3aedd42010-11-20 19:04:17 +0000939 self.assertEqual(handler._notations,
Guido van Rossumd8faa362007-04-27 19:54:29 +0000940 [("GIF", "-//CompuServe//NOTATION Graphics Interchange Format 89a//EN", None)])
Ezio Melottib3aedd42010-11-20 19:04:17 +0000941 self.assertEqual(handler._entities, [("img", None, "expat.gif", "GIF")])
Lars Gustäbel2fc52942000-10-24 15:35:07 +0000942
Christian Heimes394e55a2018-09-24 14:38:37 +0200943 def test_expat_external_dtd_enabled(self):
944 parser = create_parser()
945 parser.setFeature(feature_external_ges, True)
946 resolver = self.TestEntityRecorder()
947 parser.setEntityResolver(resolver)
948
949 with self.assertRaises(URLError):
950 parser.feed(
951 '<!DOCTYPE external SYSTEM "unsupported://non-existing">\n'
952 )
953 self.assertEqual(
954 resolver.entities, [(None, 'unsupported://non-existing')]
955 )
956
957 def test_expat_external_dtd_default(self):
958 parser = create_parser()
959 resolver = self.TestEntityRecorder()
960 parser.setEntityResolver(resolver)
961
962 parser.feed(
963 '<!DOCTYPE external SYSTEM "unsupported://non-existing">\n'
964 )
965 parser.feed('<doc />')
966 parser.close()
967 self.assertEqual(resolver.entities, [])
968
Guido van Rossumd8faa362007-04-27 19:54:29 +0000969 # ===== EntityResolver support
Lars Gustäbel2fc52942000-10-24 15:35:07 +0000970
Guido van Rossumd8faa362007-04-27 19:54:29 +0000971 class TestEntityResolver:
Lars Gustäbel2fc52942000-10-24 15:35:07 +0000972
Guido van Rossumd8faa362007-04-27 19:54:29 +0000973 def resolveEntity(self, publicId, systemId):
974 inpsrc = InputSource()
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200975 inpsrc.setByteStream(BytesIO(b"<entity/>"))
Guido van Rossumd8faa362007-04-27 19:54:29 +0000976 return inpsrc
Lars Gustäbel2fc52942000-10-24 15:35:07 +0000977
Christian Heimes394e55a2018-09-24 14:38:37 +0200978 def test_expat_entityresolver_enabled(self):
Guido van Rossumd8faa362007-04-27 19:54:29 +0000979 parser = create_parser()
Christian Heimes394e55a2018-09-24 14:38:37 +0200980 parser.setFeature(feature_external_ges, True)
Guido van Rossumd8faa362007-04-27 19:54:29 +0000981 parser.setEntityResolver(self.TestEntityResolver())
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200982 result = BytesIO()
Guido van Rossumd8faa362007-04-27 19:54:29 +0000983 parser.setContentHandler(XMLGenerator(result))
Lars Gustäbel2fc52942000-10-24 15:35:07 +0000984
Guido van Rossumd8faa362007-04-27 19:54:29 +0000985 parser.feed('<!DOCTYPE doc [\n')
986 parser.feed(' <!ENTITY test SYSTEM "whatever">\n')
987 parser.feed(']>\n')
988 parser.feed('<doc>&test;</doc>')
989 parser.close()
Lars Gustäbel2fc52942000-10-24 15:35:07 +0000990
Ezio Melottib3aedd42010-11-20 19:04:17 +0000991 self.assertEqual(result.getvalue(), start +
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200992 b"<doc><entity></entity></doc>")
Lars Gustäbel2fc52942000-10-24 15:35:07 +0000993
Christian Heimes394e55a2018-09-24 14:38:37 +0200994 def test_expat_entityresolver_default(self):
995 parser = create_parser()
996 self.assertEqual(parser.getFeature(feature_external_ges), False)
997 parser.setEntityResolver(self.TestEntityResolver())
998 result = BytesIO()
999 parser.setContentHandler(XMLGenerator(result))
1000
1001 parser.feed('<!DOCTYPE doc [\n')
1002 parser.feed(' <!ENTITY test SYSTEM "whatever">\n')
1003 parser.feed(']>\n')
1004 parser.feed('<doc>&test;</doc>')
1005 parser.close()
1006
1007 self.assertEqual(result.getvalue(), start +
1008 b"<doc></doc>")
1009
Guido van Rossumd8faa362007-04-27 19:54:29 +00001010 # ===== Attributes support
Lars Gustäbel2fc52942000-10-24 15:35:07 +00001011
Guido van Rossumd8faa362007-04-27 19:54:29 +00001012 class AttrGatherer(ContentHandler):
Lars Gustäbel2fc52942000-10-24 15:35:07 +00001013
Guido van Rossumd8faa362007-04-27 19:54:29 +00001014 def startElement(self, name, attrs):
1015 self._attrs = attrs
Lars Gustäbel2fc52942000-10-24 15:35:07 +00001016
Guido van Rossumd8faa362007-04-27 19:54:29 +00001017 def startElementNS(self, name, qname, attrs):
1018 self._attrs = attrs
Lars Gustäbel2fc52942000-10-24 15:35:07 +00001019
Guido van Rossumd8faa362007-04-27 19:54:29 +00001020 def test_expat_attrs_empty(self):
1021 parser = create_parser()
1022 gather = self.AttrGatherer()
1023 parser.setContentHandler(gather)
1024
1025 parser.feed("<doc/>")
1026 parser.close()
1027
1028 self.verify_empty_attrs(gather._attrs)
1029
1030 def test_expat_attrs_wattr(self):
1031 parser = create_parser()
1032 gather = self.AttrGatherer()
1033 parser.setContentHandler(gather)
1034
1035 parser.feed("<doc attr='val'/>")
1036 parser.close()
1037
1038 self.verify_attrs_wattr(gather._attrs)
1039
1040 def test_expat_nsattrs_empty(self):
1041 parser = create_parser(1)
1042 gather = self.AttrGatherer()
1043 parser.setContentHandler(gather)
1044
1045 parser.feed("<doc/>")
1046 parser.close()
1047
1048 self.verify_empty_nsattrs(gather._attrs)
1049
1050 def test_expat_nsattrs_wattr(self):
1051 parser = create_parser(1)
1052 gather = self.AttrGatherer()
1053 parser.setContentHandler(gather)
1054
1055 parser.feed("<doc xmlns:ns='%s' ns:attr='val'/>" % ns_uri)
1056 parser.close()
1057
1058 attrs = gather._attrs
1059
Ezio Melottib3aedd42010-11-20 19:04:17 +00001060 self.assertEqual(attrs.getLength(), 1)
1061 self.assertEqual(attrs.getNames(), [(ns_uri, "attr")])
Guido van Rossumd8faa362007-04-27 19:54:29 +00001062 self.assertTrue((attrs.getQNames() == [] or
1063 attrs.getQNames() == ["ns:attr"]))
Ezio Melottib3aedd42010-11-20 19:04:17 +00001064 self.assertEqual(len(attrs), 1)
Benjamin Peterson577473f2010-01-19 00:09:57 +00001065 self.assertIn((ns_uri, "attr"), attrs)
Ezio Melottib3aedd42010-11-20 19:04:17 +00001066 self.assertEqual(attrs.get((ns_uri, "attr")), "val")
1067 self.assertEqual(attrs.get((ns_uri, "attr"), 25), "val")
1068 self.assertEqual(list(attrs.items()), [((ns_uri, "attr"), "val")])
1069 self.assertEqual(list(attrs.values()), ["val"])
1070 self.assertEqual(attrs.getValue((ns_uri, "attr")), "val")
1071 self.assertEqual(attrs[(ns_uri, "attr")], "val")
Guido van Rossumd8faa362007-04-27 19:54:29 +00001072
1073 # ===== InputSource support
1074
Benjamin Petersona7f4f5a2008-09-04 02:22:52 +00001075 def test_expat_inpsource_filename(self):
Guido van Rossumd8faa362007-04-27 19:54:29 +00001076 parser = create_parser()
Serhiy Storchaka88efc522013-02-10 14:29:52 +02001077 result = BytesIO()
Guido van Rossumd8faa362007-04-27 19:54:29 +00001078 xmlgen = XMLGenerator(result)
1079
1080 parser.setContentHandler(xmlgen)
Florent Xiclunaf15351d2010-03-13 23:24:31 +00001081 parser.parse(TEST_XMLFILE)
Guido van Rossumd8faa362007-04-27 19:54:29 +00001082
Ezio Melottib3aedd42010-11-20 19:04:17 +00001083 self.assertEqual(result.getvalue(), xml_test_out)
Guido van Rossumd8faa362007-04-27 19:54:29 +00001084
Benjamin Petersona7f4f5a2008-09-04 02:22:52 +00001085 def test_expat_inpsource_sysid(self):
Guido van Rossumd8faa362007-04-27 19:54:29 +00001086 parser = create_parser()
Serhiy Storchaka88efc522013-02-10 14:29:52 +02001087 result = BytesIO()
Guido van Rossumd8faa362007-04-27 19:54:29 +00001088 xmlgen = XMLGenerator(result)
1089
1090 parser.setContentHandler(xmlgen)
Florent Xiclunaf15351d2010-03-13 23:24:31 +00001091 parser.parse(InputSource(TEST_XMLFILE))
Guido van Rossumd8faa362007-04-27 19:54:29 +00001092
Ezio Melottib3aedd42010-11-20 19:04:17 +00001093 self.assertEqual(result.getvalue(), xml_test_out)
Guido van Rossumd8faa362007-04-27 19:54:29 +00001094
Serhiy Storchaka1a4ed4c2013-02-02 12:17:05 +02001095 @requires_nonascii_filenames
Serhiy Storchakad5202392013-02-02 10:31:17 +02001096 def test_expat_inpsource_sysid_nonascii(self):
1097 fname = support.TESTFN_UNICODE
1098 shutil.copyfile(TEST_XMLFILE, fname)
1099 self.addCleanup(support.unlink, fname)
1100
1101 parser = create_parser()
Serhiy Storchaka88efc522013-02-10 14:29:52 +02001102 result = BytesIO()
Serhiy Storchakad5202392013-02-02 10:31:17 +02001103 xmlgen = XMLGenerator(result)
1104
1105 parser.setContentHandler(xmlgen)
1106 parser.parse(InputSource(fname))
1107
1108 self.assertEqual(result.getvalue(), xml_test_out)
1109
Serhiy Storchakaaa9563c2015-04-02 20:55:59 +03001110 def test_expat_inpsource_byte_stream(self):
Guido van Rossumd8faa362007-04-27 19:54:29 +00001111 parser = create_parser()
Serhiy Storchaka88efc522013-02-10 14:29:52 +02001112 result = BytesIO()
Guido van Rossumd8faa362007-04-27 19:54:29 +00001113 xmlgen = XMLGenerator(result)
1114
1115 parser.setContentHandler(xmlgen)
1116 inpsrc = InputSource()
Serhiy Storchaka88efc522013-02-10 14:29:52 +02001117 with open(TEST_XMLFILE, 'rb') as f:
Benjamin Petersond5df36d2010-10-31 18:23:23 +00001118 inpsrc.setByteStream(f)
1119 parser.parse(inpsrc)
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 Storchaka61de0872015-04-02 21:00:13 +03001123 def test_expat_inpsource_character_stream(self):
1124 parser = create_parser()
1125 result = BytesIO()
1126 xmlgen = XMLGenerator(result)
1127
1128 parser.setContentHandler(xmlgen)
1129 inpsrc = InputSource()
1130 with open(TEST_XMLFILE, 'rt', encoding='iso-8859-1') as f:
1131 inpsrc.setCharacterStream(f)
1132 parser.parse(inpsrc)
1133
1134 self.assertEqual(result.getvalue(), xml_test_out)
1135
Guido van Rossumd8faa362007-04-27 19:54:29 +00001136 # ===== IncrementalParser support
1137
1138 def test_expat_incremental(self):
Serhiy Storchaka88efc522013-02-10 14:29:52 +02001139 result = BytesIO()
Guido van Rossumd8faa362007-04-27 19:54:29 +00001140 xmlgen = XMLGenerator(result)
1141 parser = create_parser()
1142 parser.setContentHandler(xmlgen)
1143
1144 parser.feed("<doc>")
1145 parser.feed("</doc>")
1146 parser.close()
1147
Serhiy Storchaka88efc522013-02-10 14:29:52 +02001148 self.assertEqual(result.getvalue(), start + b"<doc></doc>")
Guido van Rossumd8faa362007-04-27 19:54:29 +00001149
1150 def test_expat_incremental_reset(self):
Serhiy Storchaka88efc522013-02-10 14:29:52 +02001151 result = BytesIO()
Guido van Rossumd8faa362007-04-27 19:54:29 +00001152 xmlgen = XMLGenerator(result)
1153 parser = create_parser()
1154 parser.setContentHandler(xmlgen)
1155
1156 parser.feed("<doc>")
1157 parser.feed("text")
1158
Serhiy Storchaka88efc522013-02-10 14:29:52 +02001159 result = BytesIO()
Guido van Rossumd8faa362007-04-27 19:54:29 +00001160 xmlgen = XMLGenerator(result)
1161 parser.setContentHandler(xmlgen)
1162 parser.reset()
1163
1164 parser.feed("<doc>")
1165 parser.feed("text")
1166 parser.feed("</doc>")
1167 parser.close()
1168
Serhiy Storchaka88efc522013-02-10 14:29:52 +02001169 self.assertEqual(result.getvalue(), start + b"<doc>text</doc>")
Guido van Rossumd8faa362007-04-27 19:54:29 +00001170
1171 # ===== Locator support
1172
1173 def test_expat_locator_noinfo(self):
Serhiy Storchaka88efc522013-02-10 14:29:52 +02001174 result = BytesIO()
Guido van Rossumd8faa362007-04-27 19:54:29 +00001175 xmlgen = XMLGenerator(result)
1176 parser = create_parser()
1177 parser.setContentHandler(xmlgen)
1178
1179 parser.feed("<doc>")
1180 parser.feed("</doc>")
1181 parser.close()
1182
Ezio Melottib3aedd42010-11-20 19:04:17 +00001183 self.assertEqual(parser.getSystemId(), None)
1184 self.assertEqual(parser.getPublicId(), None)
1185 self.assertEqual(parser.getLineNumber(), 1)
Guido van Rossumd8faa362007-04-27 19:54:29 +00001186
Benjamin Petersona7f4f5a2008-09-04 02:22:52 +00001187 def test_expat_locator_withinfo(self):
Serhiy Storchaka88efc522013-02-10 14:29:52 +02001188 result = BytesIO()
Guido van Rossumd8faa362007-04-27 19:54:29 +00001189 xmlgen = XMLGenerator(result)
1190 parser = create_parser()
1191 parser.setContentHandler(xmlgen)
Florent Xiclunaf15351d2010-03-13 23:24:31 +00001192 parser.parse(TEST_XMLFILE)
Guido van Rossumd8faa362007-04-27 19:54:29 +00001193
Ezio Melottib3aedd42010-11-20 19:04:17 +00001194 self.assertEqual(parser.getSystemId(), TEST_XMLFILE)
1195 self.assertEqual(parser.getPublicId(), None)
Lars Gustäbel2fc52942000-10-24 15:35:07 +00001196
Serhiy Storchaka1a4ed4c2013-02-02 12:17:05 +02001197 @requires_nonascii_filenames
Serhiy Storchakad5202392013-02-02 10:31:17 +02001198 def test_expat_locator_withinfo_nonascii(self):
1199 fname = support.TESTFN_UNICODE
1200 shutil.copyfile(TEST_XMLFILE, fname)
1201 self.addCleanup(support.unlink, fname)
1202
Serhiy Storchaka88efc522013-02-10 14:29:52 +02001203 result = BytesIO()
Serhiy Storchakad5202392013-02-02 10:31:17 +02001204 xmlgen = XMLGenerator(result)
1205 parser = create_parser()
1206 parser.setContentHandler(xmlgen)
1207 parser.parse(fname)
1208
1209 self.assertEqual(parser.getSystemId(), fname)
1210 self.assertEqual(parser.getPublicId(), None)
1211
Martin v. Löwis80670bc2000-10-06 21:13:23 +00001212
1213# ===========================================================================
1214#
1215# error reporting
1216#
1217# ===========================================================================
1218
Guido van Rossumd8faa362007-04-27 19:54:29 +00001219class ErrorReportingTest(unittest.TestCase):
1220 def test_expat_inpsource_location(self):
1221 parser = create_parser()
1222 parser.setContentHandler(ContentHandler()) # do nothing
1223 source = InputSource()
Serhiy Storchaka88efc522013-02-10 14:29:52 +02001224 source.setByteStream(BytesIO(b"<foo bar foobar>")) #ill-formed
Guido van Rossumd8faa362007-04-27 19:54:29 +00001225 name = "a file name"
1226 source.setSystemId(name)
1227 try:
1228 parser.parse(source)
1229 self.fail()
1230 except SAXException as e:
Ezio Melottib3aedd42010-11-20 19:04:17 +00001231 self.assertEqual(e.getSystemId(), name)
Martin v. Löwis80670bc2000-10-06 21:13:23 +00001232
Guido van Rossumd8faa362007-04-27 19:54:29 +00001233 def test_expat_incomplete(self):
1234 parser = create_parser()
1235 parser.setContentHandler(ContentHandler()) # do nothing
1236 self.assertRaises(SAXParseException, parser.parse, StringIO("<foo>"))
Serhiy Storchakaab914782015-05-06 09:36:06 +03001237 self.assertEqual(parser.getColumnNumber(), 5)
1238 self.assertEqual(parser.getLineNumber(), 1)
Martin v. Löwis80670bc2000-10-06 21:13:23 +00001239
Guido van Rossumd8faa362007-04-27 19:54:29 +00001240 def test_sax_parse_exception_str(self):
1241 # pass various values from a locator to the SAXParseException to
1242 # make sure that the __str__() doesn't fall apart when None is
1243 # passed instead of an integer line and column number
1244 #
1245 # use "normal" values for the locator:
1246 str(SAXParseException("message", None,
1247 self.DummyLocator(1, 1)))
1248 # use None for the line number:
1249 str(SAXParseException("message", None,
1250 self.DummyLocator(None, 1)))
1251 # use None for the column number:
1252 str(SAXParseException("message", None,
1253 self.DummyLocator(1, None)))
1254 # use None for both:
1255 str(SAXParseException("message", None,
1256 self.DummyLocator(None, None)))
Fred Drake6fd0b0d2004-03-20 08:15:30 +00001257
Guido van Rossumd8faa362007-04-27 19:54:29 +00001258 class DummyLocator:
1259 def __init__(self, lineno, colno):
1260 self._lineno = lineno
1261 self._colno = colno
Fred Drake6fd0b0d2004-03-20 08:15:30 +00001262
Guido van Rossumd8faa362007-04-27 19:54:29 +00001263 def getPublicId(self):
1264 return "pubid"
Fred Drake6fd0b0d2004-03-20 08:15:30 +00001265
Guido van Rossumd8faa362007-04-27 19:54:29 +00001266 def getSystemId(self):
1267 return "sysid"
Fred Drake6fd0b0d2004-03-20 08:15:30 +00001268
Guido van Rossumd8faa362007-04-27 19:54:29 +00001269 def getLineNumber(self):
1270 return self._lineno
Fred Drake6fd0b0d2004-03-20 08:15:30 +00001271
Guido van Rossumd8faa362007-04-27 19:54:29 +00001272 def getColumnNumber(self):
1273 return self._colno
Martin v. Löwis80670bc2000-10-06 21:13:23 +00001274
Lars Gustäbelab647872000-09-24 18:40:52 +00001275# ===========================================================================
1276#
1277# xmlreader tests
1278#
1279# ===========================================================================
1280
Guido van Rossumd8faa362007-04-27 19:54:29 +00001281class XmlReaderTest(XmlTestBase):
Lars Gustäbelab647872000-09-24 18:40:52 +00001282
Guido van Rossumd8faa362007-04-27 19:54:29 +00001283 # ===== AttributesImpl
1284 def test_attrs_empty(self):
1285 self.verify_empty_attrs(AttributesImpl({}))
Lars Gustäbelab647872000-09-24 18:40:52 +00001286
Guido van Rossumd8faa362007-04-27 19:54:29 +00001287 def test_attrs_wattr(self):
1288 self.verify_attrs_wattr(AttributesImpl({"attr" : "val"}))
Lars Gustäbelab647872000-09-24 18:40:52 +00001289
Guido van Rossumd8faa362007-04-27 19:54:29 +00001290 def test_nsattrs_empty(self):
1291 self.verify_empty_nsattrs(AttributesNSImpl({}, {}))
Lars Gustäbelab647872000-09-24 18:40:52 +00001292
Guido van Rossumd8faa362007-04-27 19:54:29 +00001293 def test_nsattrs_wattr(self):
1294 attrs = AttributesNSImpl({(ns_uri, "attr") : "val"},
1295 {(ns_uri, "attr") : "ns:attr"})
Fred Drake004d5e62000-10-23 17:22:08 +00001296
Ezio Melottib3aedd42010-11-20 19:04:17 +00001297 self.assertEqual(attrs.getLength(), 1)
1298 self.assertEqual(attrs.getNames(), [(ns_uri, "attr")])
1299 self.assertEqual(attrs.getQNames(), ["ns:attr"])
1300 self.assertEqual(len(attrs), 1)
Benjamin Peterson577473f2010-01-19 00:09:57 +00001301 self.assertIn((ns_uri, "attr"), attrs)
Ezio Melottib3aedd42010-11-20 19:04:17 +00001302 self.assertEqual(list(attrs.keys()), [(ns_uri, "attr")])
1303 self.assertEqual(attrs.get((ns_uri, "attr")), "val")
1304 self.assertEqual(attrs.get((ns_uri, "attr"), 25), "val")
1305 self.assertEqual(list(attrs.items()), [((ns_uri, "attr"), "val")])
1306 self.assertEqual(list(attrs.values()), ["val"])
1307 self.assertEqual(attrs.getValue((ns_uri, "attr")), "val")
1308 self.assertEqual(attrs.getValueByQName("ns:attr"), "val")
1309 self.assertEqual(attrs.getNameByQName("ns:attr"), (ns_uri, "attr"))
1310 self.assertEqual(attrs[(ns_uri, "attr")], "val")
1311 self.assertEqual(attrs.getQNameByName((ns_uri, "attr")), "ns:attr")
Fred Drake004d5e62000-10-23 17:22:08 +00001312
Lars Gustäbelab647872000-09-24 18:40:52 +00001313
Christian Heimesbbe741d2008-03-28 10:53:29 +00001314def test_main():
Guido van Rossumd8faa362007-04-27 19:54:29 +00001315 run_unittest(MakeParserTest,
Serhiy Storchaka13e41c52015-04-02 23:05:57 +03001316 ParseTest,
Guido van Rossumd8faa362007-04-27 19:54:29 +00001317 SaxutilsTest,
Serhiy Storchakaaa9563c2015-04-02 20:55:59 +03001318 PrepareInputSourceTest,
Serhiy Storchaka88efc522013-02-10 14:29:52 +02001319 StringXmlgenTest,
1320 BytesXmlgenTest,
1321 WriterXmlgenTest,
Georg Brandlc502df42013-05-12 11:41:12 +02001322 StreamWriterXmlgenTest,
1323 StreamReaderWriterXmlgenTest,
Guido van Rossumd8faa362007-04-27 19:54:29 +00001324 ExpatReaderTest,
1325 ErrorReportingTest,
1326 XmlReaderTest)
Lars Gustäbelb7536d52000-09-24 18:53:56 +00001327
Guido van Rossumd8faa362007-04-27 19:54:29 +00001328if __name__ == "__main__":
Christian Heimesbbe741d2008-03-28 10:53:29 +00001329 test_main()