blob: 9addc06f20dd5d132e7c078a6a0941bfb728b5a2 [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
Serhiy Storchaka13e41c52015-04-02 23:05:57 +030024from test.support import findfile, run_unittest, 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
185 def test_parse_InputSource(self):
186 # accept data without declared but with explicitly specified encoding
187 make_xml_file(self.data, 'iso-8859-1', None)
188 with open(TESTFN, 'rb') as f:
189 input = InputSource()
190 input.setByteStream(f)
191 input.setEncoding('iso-8859-1')
192 self.check_parse(input)
193
Victor Stinneref9c0e72017-05-05 09:46:47 +0200194 def test_parse_close_source(self):
195 builtin_open = open
196 fileobj = None
197
198 def mock_open(*args):
199 nonlocal fileobj
200 fileobj = builtin_open(*args)
201 return fileobj
202
203 with mock.patch('xml.sax.saxutils.open', side_effect=mock_open):
204 make_xml_file(self.data, 'iso-8859-1', None)
205 with self.assertRaises(SAXException):
206 self.check_parse(TESTFN)
207 self.assertTrue(fileobj.closed)
208
Serhiy Storchaka13e41c52015-04-02 23:05:57 +0300209 def check_parseString(self, s):
210 from xml.sax import parseString
211 result = StringIO()
212 parseString(s, XMLGenerator(result, 'utf-8'))
213 self.assertEqual(result.getvalue(), xml_str(self.data, 'utf-8'))
214
Serhiy Storchaka778db282015-04-04 10:12:26 +0300215 def test_parseString_text(self):
216 encodings = ('us-ascii', 'iso-8859-1', 'utf-8',
217 'utf-16', 'utf-16le', 'utf-16be')
218 for encoding in encodings:
219 self.check_parseString(xml_str(self.data, encoding))
220 self.check_parseString(self.data)
221
Serhiy Storchaka13e41c52015-04-02 23:05:57 +0300222 def test_parseString_bytes(self):
223 # UTF-8 is default encoding, US-ASCII is compatible with UTF-8,
224 # UTF-16 is autodetected
225 encodings = ('us-ascii', 'utf-8', 'utf-16', 'utf-16le', 'utf-16be')
226 for encoding in encodings:
227 self.check_parseString(xml_bytes(self.data, encoding))
228 self.check_parseString(xml_bytes(self.data, encoding, None))
229 # accept UTF-8 with BOM
230 self.check_parseString(xml_bytes(self.data, 'utf-8-sig', 'utf-8'))
231 self.check_parseString(xml_bytes(self.data, 'utf-8-sig', None))
232 # accept data with declared encoding
233 self.check_parseString(xml_bytes(self.data, 'iso-8859-1'))
234 # fail on non-UTF-8 incompatible data without declared encoding
235 with self.assertRaises(SAXException):
236 self.check_parseString(xml_bytes(self.data, 'iso-8859-1', None))
237
Guido van Rossumd8faa362007-04-27 19:54:29 +0000238class MakeParserTest(unittest.TestCase):
239 def test_make_parser2(self):
Lars Gustäbel2fc52942000-10-24 15:35:07 +0000240 # Creating parsers several times in a row should succeed.
241 # Testing this because there have been failures of this kind
242 # before.
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000243 from xml.sax import make_parser
Lars Gustäbel2fc52942000-10-24 15:35:07 +0000244 p = make_parser()
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000245 from xml.sax import make_parser
Lars Gustäbel2fc52942000-10-24 15:35:07 +0000246 p = make_parser()
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()
Tim Petersd2bf3b72001-01-18 02:22:22 +0000255
Andrés Delfinoa6dc5312018-10-26 11:56:57 -0300256 def test_make_parser3(self):
257 # Testing that make_parser can handle different types of
258 # iterables.
259 make_parser(['module'])
260 make_parser(('module', ))
261 make_parser({'module'})
262 make_parser(frozenset({'module'}))
263 make_parser({'module': None})
264 make_parser(iter(['module']))
265
266 def test_make_parser4(self):
267 # Testing that make_parser can handle empty iterables.
268 make_parser([])
269 make_parser(tuple())
270 make_parser(set())
271 make_parser(frozenset())
272 make_parser({})
273 make_parser(iter([]))
274
275 def test_make_parser5(self):
276 # Testing that make_parser can handle iterables with more than
277 # one item.
278 make_parser(['module1', 'module2'])
279 make_parser(('module1', 'module2'))
280 make_parser({'module1', 'module2'})
281 make_parser(frozenset({'module1', 'module2'}))
282 make_parser({'module1': None, 'module2': None})
283 make_parser(iter(['module1', 'module2']))
Tim Petersd2bf3b72001-01-18 02:22:22 +0000284
Lars Gustäbel96753b32000-09-24 12:24:24 +0000285# ===========================================================================
286#
287# saxutils tests
288#
289# ===========================================================================
290
Guido van Rossumd8faa362007-04-27 19:54:29 +0000291class SaxutilsTest(unittest.TestCase):
292 # ===== escape
293 def test_escape_basic(self):
Ezio Melottib3aedd42010-11-20 19:04:17 +0000294 self.assertEqual(escape("Donald Duck & Co"), "Donald Duck &amp; Co")
Lars Gustäbel96753b32000-09-24 12:24:24 +0000295
Guido van Rossumd8faa362007-04-27 19:54:29 +0000296 def test_escape_all(self):
Ezio Melottib3aedd42010-11-20 19:04:17 +0000297 self.assertEqual(escape("<Donald Duck & Co>"),
298 "&lt;Donald Duck &amp; Co&gt;")
Lars Gustäbel96753b32000-09-24 12:24:24 +0000299
Guido van Rossumd8faa362007-04-27 19:54:29 +0000300 def test_escape_extra(self):
Ezio Melottib3aedd42010-11-20 19:04:17 +0000301 self.assertEqual(escape("Hei på deg", {"å" : "&aring;"}),
302 "Hei p&aring; deg")
Lars Gustäbel96753b32000-09-24 12:24:24 +0000303
Guido van Rossumd8faa362007-04-27 19:54:29 +0000304 # ===== unescape
305 def test_unescape_basic(self):
Ezio Melottib3aedd42010-11-20 19:04:17 +0000306 self.assertEqual(unescape("Donald Duck &amp; Co"), "Donald Duck & Co")
Lars Gustäbel96753b32000-09-24 12:24:24 +0000307
Guido van Rossumd8faa362007-04-27 19:54:29 +0000308 def test_unescape_all(self):
Ezio Melottib3aedd42010-11-20 19:04:17 +0000309 self.assertEqual(unescape("&lt;Donald Duck &amp; Co&gt;"),
310 "<Donald Duck & Co>")
Martin v. Löwis74b51ac2002-10-26 14:50:45 +0000311
Guido van Rossumd8faa362007-04-27 19:54:29 +0000312 def test_unescape_extra(self):
Ezio Melottib3aedd42010-11-20 19:04:17 +0000313 self.assertEqual(unescape("Hei på deg", {"å" : "&aring;"}),
314 "Hei p&aring; deg")
Martin v. Löwis74b51ac2002-10-26 14:50:45 +0000315
Guido van Rossumd8faa362007-04-27 19:54:29 +0000316 def test_unescape_amp_extra(self):
Ezio Melottib3aedd42010-11-20 19:04:17 +0000317 self.assertEqual(unescape("&amp;foo;", {"&foo;": "splat"}), "&foo;")
Martin v. Löwis74b51ac2002-10-26 14:50:45 +0000318
Guido van Rossumd8faa362007-04-27 19:54:29 +0000319 # ===== quoteattr
320 def test_quoteattr_basic(self):
Ezio Melottib3aedd42010-11-20 19:04:17 +0000321 self.assertEqual(quoteattr("Donald Duck & Co"),
322 '"Donald Duck &amp; Co"')
Martin v. Löwis74b51ac2002-10-26 14:50:45 +0000323
Guido van Rossumd8faa362007-04-27 19:54:29 +0000324 def test_single_quoteattr(self):
Ezio Melottib3aedd42010-11-20 19:04:17 +0000325 self.assertEqual(quoteattr('Includes "double" quotes'),
326 '\'Includes "double" quotes\'')
Fred Drake32f3add2002-10-28 17:58:48 +0000327
Guido van Rossumd8faa362007-04-27 19:54:29 +0000328 def test_double_quoteattr(self):
Ezio Melottib3aedd42010-11-20 19:04:17 +0000329 self.assertEqual(quoteattr("Includes 'single' quotes"),
330 "\"Includes 'single' quotes\"")
Fred Drakeacd32d32001-07-19 16:10:15 +0000331
Guido van Rossumd8faa362007-04-27 19:54:29 +0000332 def test_single_double_quoteattr(self):
Ezio Melottib3aedd42010-11-20 19:04:17 +0000333 self.assertEqual(quoteattr("Includes 'single' and \"double\" quotes"),
334 "\"Includes 'single' and &quot;double&quot; quotes\"")
Fred Drakeacd32d32001-07-19 16:10:15 +0000335
Guido van Rossumd8faa362007-04-27 19:54:29 +0000336 # ===== make_parser
337 def test_make_parser(self):
Martin v. Löwis962c9e72000-10-06 17:41:52 +0000338 # Creating a parser should succeed - it should fall back
339 # to the expatreader
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000340 p = make_parser(['xml.parsers.no_such_parser'])
Martin v. Löwis962c9e72000-10-06 17:41:52 +0000341
342
Serhiy Storchakaaa9563c2015-04-02 20:55:59 +0300343class PrepareInputSourceTest(unittest.TestCase):
344
345 def setUp(self):
346 self.file = support.TESTFN
347 with open(self.file, "w") as tmp:
348 tmp.write("This was read from a file.")
349
350 def tearDown(self):
351 support.unlink(self.file)
352
353 def make_byte_stream(self):
354 return BytesIO(b"This is a byte stream.")
355
Serhiy Storchaka61de0872015-04-02 21:00:13 +0300356 def make_character_stream(self):
357 return StringIO("This is a character stream.")
358
Serhiy Storchakaaa9563c2015-04-02 20:55:59 +0300359 def checkContent(self, stream, content):
360 self.assertIsNotNone(stream)
361 self.assertEqual(stream.read(), content)
362 stream.close()
363
364
Serhiy Storchaka61de0872015-04-02 21:00:13 +0300365 def test_character_stream(self):
366 # If the source is an InputSource with a character stream, use it.
367 src = InputSource(self.file)
368 src.setCharacterStream(self.make_character_stream())
369 prep = prepare_input_source(src)
370 self.assertIsNone(prep.getByteStream())
371 self.checkContent(prep.getCharacterStream(),
372 "This is a character stream.")
373
Serhiy Storchakaaa9563c2015-04-02 20:55:59 +0300374 def test_byte_stream(self):
375 # If the source is an InputSource that does not have a character
376 # stream but does have a byte stream, use the byte stream.
377 src = InputSource(self.file)
378 src.setByteStream(self.make_byte_stream())
379 prep = prepare_input_source(src)
380 self.assertIsNone(prep.getCharacterStream())
381 self.checkContent(prep.getByteStream(),
382 b"This is a byte stream.")
383
384 def test_system_id(self):
385 # If the source is an InputSource that has neither a character
386 # stream nor a byte stream, open the system ID.
387 src = InputSource(self.file)
388 prep = prepare_input_source(src)
389 self.assertIsNone(prep.getCharacterStream())
390 self.checkContent(prep.getByteStream(),
391 b"This was read from a file.")
392
393 def test_string(self):
394 # If the source is a string, use it as a system ID and open it.
395 prep = prepare_input_source(self.file)
396 self.assertIsNone(prep.getCharacterStream())
397 self.checkContent(prep.getByteStream(),
398 b"This was read from a file.")
399
400 def test_binary_file(self):
401 # If the source is a binary file-like object, use it as a byte
402 # stream.
403 prep = prepare_input_source(self.make_byte_stream())
404 self.assertIsNone(prep.getCharacterStream())
405 self.checkContent(prep.getByteStream(),
406 b"This is a byte stream.")
407
Serhiy Storchaka61de0872015-04-02 21:00:13 +0300408 def test_text_file(self):
409 # If the source is a text file-like object, use it as a character
410 # stream.
411 prep = prepare_input_source(self.make_character_stream())
412 self.assertIsNone(prep.getByteStream())
413 self.checkContent(prep.getCharacterStream(),
414 "This is a character stream.")
415
Serhiy Storchakaaa9563c2015-04-02 20:55:59 +0300416
Lars Gustäbel96753b32000-09-24 12:24:24 +0000417# ===== XMLGenerator
418
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200419class XmlgenTest:
Guido van Rossumd8faa362007-04-27 19:54:29 +0000420 def test_xmlgen_basic(self):
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200421 result = self.ioclass()
Guido van Rossumd8faa362007-04-27 19:54:29 +0000422 gen = XMLGenerator(result)
423 gen.startDocument()
424 gen.startElement("doc", {})
425 gen.endElement("doc")
426 gen.endDocument()
Lars Gustäbel96753b32000-09-24 12:24:24 +0000427
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200428 self.assertEqual(result.getvalue(), self.xml("<doc></doc>"))
Lars Gustäbel96753b32000-09-24 12:24:24 +0000429
R. David Murraya90032a2010-10-17 22:46:45 +0000430 def test_xmlgen_basic_empty(self):
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200431 result = self.ioclass()
R. David Murraya90032a2010-10-17 22:46:45 +0000432 gen = XMLGenerator(result, short_empty_elements=True)
433 gen.startDocument()
434 gen.startElement("doc", {})
435 gen.endElement("doc")
436 gen.endDocument()
437
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200438 self.assertEqual(result.getvalue(), self.xml("<doc/>"))
R. David Murraya90032a2010-10-17 22:46:45 +0000439
Guido van Rossumd8faa362007-04-27 19:54:29 +0000440 def test_xmlgen_content(self):
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200441 result = self.ioclass()
Guido van Rossumd8faa362007-04-27 19:54:29 +0000442 gen = XMLGenerator(result)
Fred Drake004d5e62000-10-23 17:22:08 +0000443
Guido van Rossumd8faa362007-04-27 19:54:29 +0000444 gen.startDocument()
445 gen.startElement("doc", {})
446 gen.characters("huhei")
447 gen.endElement("doc")
448 gen.endDocument()
Lars Gustäbel96753b32000-09-24 12:24:24 +0000449
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200450 self.assertEqual(result.getvalue(), self.xml("<doc>huhei</doc>"))
Lars Gustäbel96753b32000-09-24 12:24:24 +0000451
R. David Murraya90032a2010-10-17 22:46:45 +0000452 def test_xmlgen_content_empty(self):
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200453 result = self.ioclass()
R. David Murraya90032a2010-10-17 22:46:45 +0000454 gen = XMLGenerator(result, short_empty_elements=True)
455
456 gen.startDocument()
457 gen.startElement("doc", {})
458 gen.characters("huhei")
459 gen.endElement("doc")
460 gen.endDocument()
461
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200462 self.assertEqual(result.getvalue(), self.xml("<doc>huhei</doc>"))
R. David Murraya90032a2010-10-17 22:46:45 +0000463
Guido van Rossumd8faa362007-04-27 19:54:29 +0000464 def test_xmlgen_pi(self):
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200465 result = self.ioclass()
Guido van Rossumd8faa362007-04-27 19:54:29 +0000466 gen = XMLGenerator(result)
Fred Drake004d5e62000-10-23 17:22:08 +0000467
Guido van Rossumd8faa362007-04-27 19:54:29 +0000468 gen.startDocument()
469 gen.processingInstruction("test", "data")
470 gen.startElement("doc", {})
471 gen.endElement("doc")
472 gen.endDocument()
Lars Gustäbel96753b32000-09-24 12:24:24 +0000473
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200474 self.assertEqual(result.getvalue(),
475 self.xml("<?test data?><doc></doc>"))
Lars Gustäbel96753b32000-09-24 12:24:24 +0000476
Guido van Rossumd8faa362007-04-27 19:54:29 +0000477 def test_xmlgen_content_escape(self):
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200478 result = self.ioclass()
Guido van Rossumd8faa362007-04-27 19:54:29 +0000479 gen = XMLGenerator(result)
Fred Drake004d5e62000-10-23 17:22:08 +0000480
Guido van Rossumd8faa362007-04-27 19:54:29 +0000481 gen.startDocument()
482 gen.startElement("doc", {})
483 gen.characters("<huhei&")
484 gen.endElement("doc")
485 gen.endDocument()
Lars Gustäbel96753b32000-09-24 12:24:24 +0000486
Ezio Melottib3aedd42010-11-20 19:04:17 +0000487 self.assertEqual(result.getvalue(),
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200488 self.xml("<doc>&lt;huhei&amp;</doc>"))
Lars Gustäbel96753b32000-09-24 12:24:24 +0000489
Guido van Rossumd8faa362007-04-27 19:54:29 +0000490 def test_xmlgen_attr_escape(self):
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200491 result = self.ioclass()
Guido van Rossumd8faa362007-04-27 19:54:29 +0000492 gen = XMLGenerator(result)
Fred Drakec9fadf92001-08-07 19:17:06 +0000493
Guido van Rossumd8faa362007-04-27 19:54:29 +0000494 gen.startDocument()
495 gen.startElement("doc", {"a": '"'})
496 gen.startElement("e", {"a": "'"})
497 gen.endElement("e")
498 gen.startElement("e", {"a": "'\""})
499 gen.endElement("e")
500 gen.startElement("e", {"a": "\n\r\t"})
501 gen.endElement("e")
502 gen.endElement("doc")
503 gen.endDocument()
Fred Drakec9fadf92001-08-07 19:17:06 +0000504
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200505 self.assertEqual(result.getvalue(), self.xml(
506 "<doc a='\"'><e a=\"'\"></e>"
507 "<e a=\"'&quot;\"></e>"
508 "<e a=\"&#10;&#13;&#9;\"></e></doc>"))
509
510 def test_xmlgen_encoding(self):
511 encodings = ('iso-8859-15', 'utf-8', 'utf-8-sig',
512 'utf-16', 'utf-16be', 'utf-16le',
513 'utf-32', 'utf-32be', 'utf-32le')
514 for encoding in encodings:
515 result = self.ioclass()
516 gen = XMLGenerator(result, encoding=encoding)
517
518 gen.startDocument()
519 gen.startElement("doc", {"a": '\u20ac'})
520 gen.characters("\u20ac")
521 gen.endElement("doc")
522 gen.endDocument()
523
524 self.assertEqual(result.getvalue(),
525 self.xml('<doc a="\u20ac">\u20ac</doc>', encoding=encoding))
526
527 def test_xmlgen_unencodable(self):
528 result = self.ioclass()
529 gen = XMLGenerator(result, encoding='ascii')
530
531 gen.startDocument()
532 gen.startElement("doc", {"a": '\u20ac'})
533 gen.characters("\u20ac")
534 gen.endElement("doc")
535 gen.endDocument()
536
537 self.assertEqual(result.getvalue(),
538 self.xml('<doc a="&#8364;">&#8364;</doc>', encoding='ascii'))
Fred Drakec9fadf92001-08-07 19:17:06 +0000539
Guido van Rossumd8faa362007-04-27 19:54:29 +0000540 def test_xmlgen_ignorable(self):
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200541 result = self.ioclass()
Guido van Rossumd8faa362007-04-27 19:54:29 +0000542 gen = XMLGenerator(result)
Fred Drake004d5e62000-10-23 17:22:08 +0000543
Guido van Rossumd8faa362007-04-27 19:54:29 +0000544 gen.startDocument()
545 gen.startElement("doc", {})
546 gen.ignorableWhitespace(" ")
547 gen.endElement("doc")
548 gen.endDocument()
Lars Gustäbel96753b32000-09-24 12:24:24 +0000549
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200550 self.assertEqual(result.getvalue(), self.xml("<doc> </doc>"))
Lars Gustäbel96753b32000-09-24 12:24:24 +0000551
R. David Murraya90032a2010-10-17 22:46:45 +0000552 def test_xmlgen_ignorable_empty(self):
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200553 result = self.ioclass()
R. David Murraya90032a2010-10-17 22:46:45 +0000554 gen = XMLGenerator(result, short_empty_elements=True)
555
556 gen.startDocument()
557 gen.startElement("doc", {})
558 gen.ignorableWhitespace(" ")
559 gen.endElement("doc")
560 gen.endDocument()
561
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200562 self.assertEqual(result.getvalue(), self.xml("<doc> </doc>"))
R. David Murraya90032a2010-10-17 22:46:45 +0000563
Serhiy Storchaka3eab6b32013-05-12 17:31:16 +0300564 def test_xmlgen_encoding_bytes(self):
565 encodings = ('iso-8859-15', 'utf-8', 'utf-8-sig',
566 'utf-16', 'utf-16be', 'utf-16le',
567 'utf-32', 'utf-32be', 'utf-32le')
568 for encoding in encodings:
569 result = self.ioclass()
570 gen = XMLGenerator(result, encoding=encoding)
571
572 gen.startDocument()
573 gen.startElement("doc", {"a": '\u20ac'})
574 gen.characters("\u20ac".encode(encoding))
575 gen.ignorableWhitespace(" ".encode(encoding))
576 gen.endElement("doc")
577 gen.endDocument()
578
579 self.assertEqual(result.getvalue(),
580 self.xml('<doc a="\u20ac">\u20ac </doc>', encoding=encoding))
581
Guido van Rossumd8faa362007-04-27 19:54:29 +0000582 def test_xmlgen_ns(self):
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200583 result = self.ioclass()
Guido van Rossumd8faa362007-04-27 19:54:29 +0000584 gen = XMLGenerator(result)
Lars Gustäbel96753b32000-09-24 12:24:24 +0000585
Guido van Rossumd8faa362007-04-27 19:54:29 +0000586 gen.startDocument()
587 gen.startPrefixMapping("ns1", ns_uri)
588 gen.startElementNS((ns_uri, "doc"), "ns1:doc", {})
589 # add an unqualified name
590 gen.startElementNS((None, "udoc"), None, {})
591 gen.endElementNS((None, "udoc"), None)
592 gen.endElementNS((ns_uri, "doc"), "ns1:doc")
593 gen.endPrefixMapping("ns1")
594 gen.endDocument()
Fred Drake004d5e62000-10-23 17:22:08 +0000595
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200596 self.assertEqual(result.getvalue(), self.xml(
597 '<ns1:doc xmlns:ns1="%s"><udoc></udoc></ns1:doc>' %
Guido van Rossumd8faa362007-04-27 19:54:29 +0000598 ns_uri))
Lars Gustäbel96753b32000-09-24 12:24:24 +0000599
R. David Murraya90032a2010-10-17 22:46:45 +0000600 def test_xmlgen_ns_empty(self):
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200601 result = self.ioclass()
R. David Murraya90032a2010-10-17 22:46:45 +0000602 gen = XMLGenerator(result, short_empty_elements=True)
603
604 gen.startDocument()
605 gen.startPrefixMapping("ns1", ns_uri)
606 gen.startElementNS((ns_uri, "doc"), "ns1:doc", {})
607 # add an unqualified name
608 gen.startElementNS((None, "udoc"), None, {})
609 gen.endElementNS((None, "udoc"), None)
610 gen.endElementNS((ns_uri, "doc"), "ns1:doc")
611 gen.endPrefixMapping("ns1")
612 gen.endDocument()
613
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200614 self.assertEqual(result.getvalue(), self.xml(
615 '<ns1:doc xmlns:ns1="%s"><udoc/></ns1:doc>' %
R. David Murraya90032a2010-10-17 22:46:45 +0000616 ns_uri))
617
Guido van Rossumd8faa362007-04-27 19:54:29 +0000618 def test_1463026_1(self):
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200619 result = self.ioclass()
Guido van Rossumd8faa362007-04-27 19:54:29 +0000620 gen = XMLGenerator(result)
Thomas Wouterscf297e42007-02-23 15:07:44 +0000621
Guido van Rossumd8faa362007-04-27 19:54:29 +0000622 gen.startDocument()
623 gen.startElementNS((None, 'a'), 'a', {(None, 'b'):'c'})
624 gen.endElementNS((None, 'a'), 'a')
625 gen.endDocument()
Thomas Wouterscf297e42007-02-23 15:07:44 +0000626
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200627 self.assertEqual(result.getvalue(), self.xml('<a b="c"></a>'))
Thomas Wouterscf297e42007-02-23 15:07:44 +0000628
R. David Murraya90032a2010-10-17 22:46:45 +0000629 def test_1463026_1_empty(self):
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200630 result = self.ioclass()
R. David Murraya90032a2010-10-17 22:46:45 +0000631 gen = XMLGenerator(result, short_empty_elements=True)
632
633 gen.startDocument()
634 gen.startElementNS((None, 'a'), 'a', {(None, 'b'):'c'})
635 gen.endElementNS((None, 'a'), 'a')
636 gen.endDocument()
637
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200638 self.assertEqual(result.getvalue(), self.xml('<a b="c"/>'))
R. David Murraya90032a2010-10-17 22:46:45 +0000639
Guido van Rossumd8faa362007-04-27 19:54:29 +0000640 def test_1463026_2(self):
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200641 result = self.ioclass()
Guido van Rossumd8faa362007-04-27 19:54:29 +0000642 gen = XMLGenerator(result)
Thomas Wouterscf297e42007-02-23 15:07:44 +0000643
Guido van Rossumd8faa362007-04-27 19:54:29 +0000644 gen.startDocument()
645 gen.startPrefixMapping(None, 'qux')
646 gen.startElementNS(('qux', 'a'), 'a', {})
647 gen.endElementNS(('qux', 'a'), 'a')
648 gen.endPrefixMapping(None)
649 gen.endDocument()
Thomas Wouterscf297e42007-02-23 15:07:44 +0000650
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200651 self.assertEqual(result.getvalue(), self.xml('<a xmlns="qux"></a>'))
Thomas Wouterscf297e42007-02-23 15:07:44 +0000652
R. David Murraya90032a2010-10-17 22:46:45 +0000653 def test_1463026_2_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(None, 'qux')
659 gen.startElementNS(('qux', 'a'), 'a', {})
660 gen.endElementNS(('qux', 'a'), 'a')
661 gen.endPrefixMapping(None)
662 gen.endDocument()
663
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200664 self.assertEqual(result.getvalue(), self.xml('<a xmlns="qux"/>'))
R. David Murraya90032a2010-10-17 22:46:45 +0000665
Guido van Rossumd8faa362007-04-27 19:54:29 +0000666 def test_1463026_3(self):
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200667 result = self.ioclass()
Guido van Rossumd8faa362007-04-27 19:54:29 +0000668 gen = XMLGenerator(result)
Thomas Wouterscf297e42007-02-23 15:07:44 +0000669
Guido van Rossumd8faa362007-04-27 19:54:29 +0000670 gen.startDocument()
671 gen.startPrefixMapping('my', 'qux')
672 gen.startElementNS(('qux', 'a'), 'a', {(None, 'b'):'c'})
673 gen.endElementNS(('qux', 'a'), 'a')
674 gen.endPrefixMapping('my')
675 gen.endDocument()
Thomas Wouterscf297e42007-02-23 15:07:44 +0000676
Ezio Melottib3aedd42010-11-20 19:04:17 +0000677 self.assertEqual(result.getvalue(),
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200678 self.xml('<my:a xmlns:my="qux" b="c"></my:a>'))
Lars Gustäbel96753b32000-09-24 12:24:24 +0000679
R. David Murraya90032a2010-10-17 22:46:45 +0000680 def test_1463026_3_empty(self):
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200681 result = self.ioclass()
R. David Murraya90032a2010-10-17 22:46:45 +0000682 gen = XMLGenerator(result, short_empty_elements=True)
683
684 gen.startDocument()
685 gen.startPrefixMapping('my', 'qux')
686 gen.startElementNS(('qux', 'a'), 'a', {(None, 'b'):'c'})
687 gen.endElementNS(('qux', 'a'), 'a')
688 gen.endPrefixMapping('my')
689 gen.endDocument()
690
Ezio Melottib3aedd42010-11-20 19:04:17 +0000691 self.assertEqual(result.getvalue(),
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200692 self.xml('<my:a xmlns:my="qux" b="c"/>'))
R. David Murraya90032a2010-10-17 22:46:45 +0000693
Antoine Pitrou6b03ee62010-10-27 18:33:30 +0000694 def test_5027_1(self):
695 # The xml prefix (as in xml:lang below) is reserved and bound by
696 # definition to http://www.w3.org/XML/1998/namespace. XMLGenerator had
Andrew Svetlov737fb892012-12-18 21:14:22 +0200697 # a bug whereby a KeyError is raised because this namespace is missing
Antoine Pitrou6b03ee62010-10-27 18:33:30 +0000698 # from a dictionary.
699 #
700 # This test demonstrates the bug by parsing a document.
701 test_xml = StringIO(
702 '<?xml version="1.0"?>'
703 '<a:g1 xmlns:a="http://example.com/ns">'
704 '<a:g2 xml:lang="en">Hello</a:g2>'
705 '</a:g1>')
706
707 parser = make_parser()
708 parser.setFeature(feature_namespaces, True)
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200709 result = self.ioclass()
Antoine Pitrou6b03ee62010-10-27 18:33:30 +0000710 gen = XMLGenerator(result)
711 parser.setContentHandler(gen)
712 parser.parse(test_xml)
713
Ezio Melottib3aedd42010-11-20 19:04:17 +0000714 self.assertEqual(result.getvalue(),
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200715 self.xml(
Ezio Melottib3aedd42010-11-20 19:04:17 +0000716 '<a:g1 xmlns:a="http://example.com/ns">'
717 '<a:g2 xml:lang="en">Hello</a:g2>'
718 '</a:g1>'))
Antoine Pitrou6b03ee62010-10-27 18:33:30 +0000719
720 def test_5027_2(self):
721 # The xml prefix (as in xml:lang below) is reserved and bound by
722 # definition to http://www.w3.org/XML/1998/namespace. XMLGenerator had
Andrew Svetlov737fb892012-12-18 21:14:22 +0200723 # a bug whereby a KeyError is raised because this namespace is missing
Antoine Pitrou6b03ee62010-10-27 18:33:30 +0000724 # from a dictionary.
725 #
726 # This test demonstrates the bug by direct manipulation of the
727 # XMLGenerator.
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200728 result = self.ioclass()
Antoine Pitrou6b03ee62010-10-27 18:33:30 +0000729 gen = XMLGenerator(result)
730
731 gen.startDocument()
732 gen.startPrefixMapping('a', 'http://example.com/ns')
733 gen.startElementNS(('http://example.com/ns', 'g1'), 'g1', {})
734 lang_attr = {('http://www.w3.org/XML/1998/namespace', 'lang'): 'en'}
735 gen.startElementNS(('http://example.com/ns', 'g2'), 'g2', lang_attr)
736 gen.characters('Hello')
737 gen.endElementNS(('http://example.com/ns', 'g2'), 'g2')
738 gen.endElementNS(('http://example.com/ns', 'g1'), 'g1')
739 gen.endPrefixMapping('a')
740 gen.endDocument()
741
Ezio Melottib3aedd42010-11-20 19:04:17 +0000742 self.assertEqual(result.getvalue(),
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200743 self.xml(
Ezio Melottib3aedd42010-11-20 19:04:17 +0000744 '<a:g1 xmlns:a="http://example.com/ns">'
745 '<a:g2 xml:lang="en">Hello</a:g2>'
746 '</a:g1>'))
Antoine Pitrou6b03ee62010-10-27 18:33:30 +0000747
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200748 def test_no_close_file(self):
749 result = self.ioclass()
750 def func(out):
751 gen = XMLGenerator(out)
752 gen.startDocument()
753 gen.startElement("doc", {})
754 func(result)
755 self.assertFalse(result.closed)
756
Serhiy Storchakaa5f13d22013-02-25 13:46:10 +0200757 def test_xmlgen_fragment(self):
758 result = self.ioclass()
759 gen = XMLGenerator(result)
760
761 # Don't call gen.startDocument()
762 gen.startElement("foo", {"a": "1.0"})
763 gen.characters("Hello")
764 gen.endElement("foo")
765 gen.startElement("bar", {"b": "2.0"})
766 gen.endElement("bar")
767 # Don't call gen.endDocument()
768
769 self.assertEqual(result.getvalue(),
770 self.xml('<foo a="1.0">Hello</foo><bar b="2.0"></bar>')[len(self.xml('')):])
771
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200772class StringXmlgenTest(XmlgenTest, unittest.TestCase):
773 ioclass = StringIO
774
775 def xml(self, doc, encoding='iso-8859-1'):
776 return '<?xml version="1.0" encoding="%s"?>\n%s' % (encoding, doc)
777
778 test_xmlgen_unencodable = None
779
780class BytesXmlgenTest(XmlgenTest, unittest.TestCase):
781 ioclass = BytesIO
782
783 def xml(self, doc, encoding='iso-8859-1'):
784 return ('<?xml version="1.0" encoding="%s"?>\n%s' %
785 (encoding, doc)).encode(encoding, 'xmlcharrefreplace')
786
787class WriterXmlgenTest(BytesXmlgenTest):
788 class ioclass(list):
789 write = list.append
790 closed = False
791
792 def seekable(self):
793 return True
794
795 def tell(self):
796 # return 0 at start and not 0 after start
797 return len(self)
798
799 def getvalue(self):
800 return b''.join(self)
801
Georg Brandlc502df42013-05-12 11:41:12 +0200802class StreamWriterXmlgenTest(XmlgenTest, unittest.TestCase):
803 def ioclass(self):
804 raw = BytesIO()
805 writer = codecs.getwriter('ascii')(raw, 'xmlcharrefreplace')
806 writer.getvalue = raw.getvalue
807 return writer
808
809 def xml(self, doc, encoding='iso-8859-1'):
810 return ('<?xml version="1.0" encoding="%s"?>\n%s' %
811 (encoding, doc)).encode('ascii', 'xmlcharrefreplace')
812
813class StreamReaderWriterXmlgenTest(XmlgenTest, unittest.TestCase):
814 fname = support.TESTFN + '-codecs'
815
816 def ioclass(self):
817 writer = codecs.open(self.fname, 'w', encoding='ascii',
818 errors='xmlcharrefreplace', buffering=0)
Antoine Pitrou2adb6fe2013-05-13 22:34:21 +0200819 def cleanup():
820 writer.close()
821 support.unlink(self.fname)
822 self.addCleanup(cleanup)
Richard Oudkerk90a24272013-05-18 18:11:30 +0100823 def getvalue():
824 # Windows will not let use reopen without first closing
825 writer.close()
826 with open(writer.name, 'rb') as f:
827 return f.read()
828 writer.getvalue = getvalue
Georg Brandlc502df42013-05-12 11:41:12 +0200829 return writer
830
Georg Brandlc502df42013-05-12 11:41:12 +0200831 def xml(self, doc, encoding='iso-8859-1'):
832 return ('<?xml version="1.0" encoding="%s"?>\n%s' %
833 (encoding, doc)).encode('ascii', 'xmlcharrefreplace')
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200834
835start = b'<?xml version="1.0" encoding="iso-8859-1"?>\n'
836
Fred Drake004d5e62000-10-23 17:22:08 +0000837
Guido van Rossumd8faa362007-04-27 19:54:29 +0000838class XMLFilterBaseTest(unittest.TestCase):
839 def test_filter_basic(self):
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200840 result = BytesIO()
Guido van Rossumd8faa362007-04-27 19:54:29 +0000841 gen = XMLGenerator(result)
842 filter = XMLFilterBase()
843 filter.setContentHandler(gen)
Lars Gustäbel96753b32000-09-24 12:24:24 +0000844
Guido van Rossumd8faa362007-04-27 19:54:29 +0000845 filter.startDocument()
846 filter.startElement("doc", {})
847 filter.characters("content")
848 filter.ignorableWhitespace(" ")
849 filter.endElement("doc")
850 filter.endDocument()
851
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200852 self.assertEqual(result.getvalue(), start + b"<doc>content </doc>")
Lars Gustäbel96753b32000-09-24 12:24:24 +0000853
854# ===========================================================================
855#
856# expatreader tests
857#
858# ===========================================================================
859
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200860with open(TEST_XMLFILE_OUT, 'rb') as f:
Benjamin Petersond5df36d2010-10-31 18:23:23 +0000861 xml_test_out = f.read()
Lars Gustäbelb7536d52000-09-24 18:53:56 +0000862
Guido van Rossumd8faa362007-04-27 19:54:29 +0000863class ExpatReaderTest(XmlTestBase):
Lars Gustäbelb7536d52000-09-24 18:53:56 +0000864
Guido van Rossumd8faa362007-04-27 19:54:29 +0000865 # ===== XMLReader support
Lars Gustäbelb7536d52000-09-24 18:53:56 +0000866
Serhiy Storchakaaa9563c2015-04-02 20:55:59 +0300867 def test_expat_binary_file(self):
Guido van Rossumd8faa362007-04-27 19:54:29 +0000868 parser = create_parser()
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200869 result = BytesIO()
Guido van Rossumd8faa362007-04-27 19:54:29 +0000870 xmlgen = XMLGenerator(result)
Lars Gustäbelb7536d52000-09-24 18:53:56 +0000871
Guido van Rossumd8faa362007-04-27 19:54:29 +0000872 parser.setContentHandler(xmlgen)
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200873 with open(TEST_XMLFILE, 'rb') as f:
Benjamin Petersond5df36d2010-10-31 18:23:23 +0000874 parser.parse(f)
Lars Gustäbelb7536d52000-09-24 18:53:56 +0000875
Ezio Melottib3aedd42010-11-20 19:04:17 +0000876 self.assertEqual(result.getvalue(), xml_test_out)
Lars Gustäbelb7536d52000-09-24 18:53:56 +0000877
Serhiy Storchakaaa9563c2015-04-02 20:55:59 +0300878 def test_expat_text_file(self):
879 parser = create_parser()
880 result = BytesIO()
881 xmlgen = XMLGenerator(result)
882
883 parser.setContentHandler(xmlgen)
884 with open(TEST_XMLFILE, 'rt', encoding='iso-8859-1') as f:
885 parser.parse(f)
886
887 self.assertEqual(result.getvalue(), xml_test_out)
888
Serhiy Storchaka1a4ed4c2013-02-02 12:17:05 +0200889 @requires_nonascii_filenames
Serhiy Storchakaaa9563c2015-04-02 20:55:59 +0300890 def test_expat_binary_file_nonascii(self):
Serhiy Storchakad5202392013-02-02 10:31:17 +0200891 fname = support.TESTFN_UNICODE
892 shutil.copyfile(TEST_XMLFILE, fname)
893 self.addCleanup(support.unlink, fname)
894
895 parser = create_parser()
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200896 result = BytesIO()
Serhiy Storchakad5202392013-02-02 10:31:17 +0200897 xmlgen = XMLGenerator(result)
898
899 parser.setContentHandler(xmlgen)
Serhiy Storchakaaa9563c2015-04-02 20:55:59 +0300900 parser.parse(open(fname, 'rb'))
Serhiy Storchakad5202392013-02-02 10:31:17 +0200901
902 self.assertEqual(result.getvalue(), xml_test_out)
903
Serhiy Storchakafc8e9b02014-11-27 22:13:16 +0200904 def test_expat_binary_file_bytes_name(self):
905 fname = os.fsencode(TEST_XMLFILE)
906 parser = create_parser()
907 result = BytesIO()
908 xmlgen = XMLGenerator(result)
909
910 parser.setContentHandler(xmlgen)
911 with open(fname, 'rb') as f:
912 parser.parse(f)
913
914 self.assertEqual(result.getvalue(), xml_test_out)
915
916 def test_expat_binary_file_int_name(self):
917 parser = create_parser()
918 result = BytesIO()
919 xmlgen = XMLGenerator(result)
920
921 parser.setContentHandler(xmlgen)
922 with open(TEST_XMLFILE, 'rb') as f:
923 with open(f.fileno(), 'rb', closefd=False) as f2:
924 parser.parse(f2)
925
926 self.assertEqual(result.getvalue(), xml_test_out)
927
Guido van Rossumd8faa362007-04-27 19:54:29 +0000928 # ===== DTDHandler support
Lars Gustäbelb7536d52000-09-24 18:53:56 +0000929
Guido van Rossumd8faa362007-04-27 19:54:29 +0000930 class TestDTDHandler:
Lars Gustäbelb7536d52000-09-24 18:53:56 +0000931
Guido van Rossumd8faa362007-04-27 19:54:29 +0000932 def __init__(self):
933 self._notations = []
934 self._entities = []
Lars Gustäbelb7536d52000-09-24 18:53:56 +0000935
Guido van Rossumd8faa362007-04-27 19:54:29 +0000936 def notationDecl(self, name, publicId, systemId):
937 self._notations.append((name, publicId, systemId))
Lars Gustäbelb7536d52000-09-24 18:53:56 +0000938
Guido van Rossumd8faa362007-04-27 19:54:29 +0000939 def unparsedEntityDecl(self, name, publicId, systemId, ndata):
940 self._entities.append((name, publicId, systemId, ndata))
Lars Gustäbel2fc52942000-10-24 15:35:07 +0000941
Christian Heimes17b1d5d2018-09-23 09:50:25 +0200942
943 class TestEntityRecorder:
944 def __init__(self):
945 self.entities = []
946
947 def resolveEntity(self, publicId, systemId):
948 self.entities.append((publicId, systemId))
949 source = InputSource()
950 source.setPublicId(publicId)
951 source.setSystemId(systemId)
952 return source
953
Guido van Rossumd8faa362007-04-27 19:54:29 +0000954 def test_expat_dtdhandler(self):
955 parser = create_parser()
956 handler = self.TestDTDHandler()
957 parser.setDTDHandler(handler)
Lars Gustäbel2fc52942000-10-24 15:35:07 +0000958
Guido van Rossumd8faa362007-04-27 19:54:29 +0000959 parser.feed('<!DOCTYPE doc [\n')
960 parser.feed(' <!ENTITY img SYSTEM "expat.gif" NDATA GIF>\n')
961 parser.feed(' <!NOTATION GIF PUBLIC "-//CompuServe//NOTATION Graphics Interchange Format 89a//EN">\n')
962 parser.feed(']>\n')
963 parser.feed('<doc></doc>')
964 parser.close()
Lars Gustäbel2fc52942000-10-24 15:35:07 +0000965
Ezio Melottib3aedd42010-11-20 19:04:17 +0000966 self.assertEqual(handler._notations,
Guido van Rossumd8faa362007-04-27 19:54:29 +0000967 [("GIF", "-//CompuServe//NOTATION Graphics Interchange Format 89a//EN", None)])
Ezio Melottib3aedd42010-11-20 19:04:17 +0000968 self.assertEqual(handler._entities, [("img", None, "expat.gif", "GIF")])
Lars Gustäbel2fc52942000-10-24 15:35:07 +0000969
Christian Heimes17b1d5d2018-09-23 09:50:25 +0200970 def test_expat_external_dtd_enabled(self):
971 parser = create_parser()
972 parser.setFeature(feature_external_ges, True)
973 resolver = self.TestEntityRecorder()
974 parser.setEntityResolver(resolver)
975
976 with self.assertRaises(URLError):
977 parser.feed(
978 '<!DOCTYPE external SYSTEM "unsupported://non-existing">\n'
979 )
980 self.assertEqual(
981 resolver.entities, [(None, 'unsupported://non-existing')]
982 )
983
984 def test_expat_external_dtd_default(self):
985 parser = create_parser()
986 resolver = self.TestEntityRecorder()
987 parser.setEntityResolver(resolver)
988
989 parser.feed(
990 '<!DOCTYPE external SYSTEM "unsupported://non-existing">\n'
991 )
992 parser.feed('<doc />')
993 parser.close()
994 self.assertEqual(resolver.entities, [])
995
Guido van Rossumd8faa362007-04-27 19:54:29 +0000996 # ===== EntityResolver support
Lars Gustäbel2fc52942000-10-24 15:35:07 +0000997
Guido van Rossumd8faa362007-04-27 19:54:29 +0000998 class TestEntityResolver:
Lars Gustäbel2fc52942000-10-24 15:35:07 +0000999
Guido van Rossumd8faa362007-04-27 19:54:29 +00001000 def resolveEntity(self, publicId, systemId):
1001 inpsrc = InputSource()
Serhiy Storchaka88efc522013-02-10 14:29:52 +02001002 inpsrc.setByteStream(BytesIO(b"<entity/>"))
Guido van Rossumd8faa362007-04-27 19:54:29 +00001003 return inpsrc
Lars Gustäbel2fc52942000-10-24 15:35:07 +00001004
Christian Heimes17b1d5d2018-09-23 09:50:25 +02001005 def test_expat_entityresolver_enabled(self):
Guido van Rossumd8faa362007-04-27 19:54:29 +00001006 parser = create_parser()
Christian Heimes17b1d5d2018-09-23 09:50:25 +02001007 parser.setFeature(feature_external_ges, True)
Guido van Rossumd8faa362007-04-27 19:54:29 +00001008 parser.setEntityResolver(self.TestEntityResolver())
Serhiy Storchaka88efc522013-02-10 14:29:52 +02001009 result = BytesIO()
Guido van Rossumd8faa362007-04-27 19:54:29 +00001010 parser.setContentHandler(XMLGenerator(result))
Lars Gustäbel2fc52942000-10-24 15:35:07 +00001011
Guido van Rossumd8faa362007-04-27 19:54:29 +00001012 parser.feed('<!DOCTYPE doc [\n')
1013 parser.feed(' <!ENTITY test SYSTEM "whatever">\n')
1014 parser.feed(']>\n')
1015 parser.feed('<doc>&test;</doc>')
1016 parser.close()
Lars Gustäbel2fc52942000-10-24 15:35:07 +00001017
Ezio Melottib3aedd42010-11-20 19:04:17 +00001018 self.assertEqual(result.getvalue(), start +
Serhiy Storchaka88efc522013-02-10 14:29:52 +02001019 b"<doc><entity></entity></doc>")
Lars Gustäbel2fc52942000-10-24 15:35:07 +00001020
Christian Heimes17b1d5d2018-09-23 09:50:25 +02001021 def test_expat_entityresolver_default(self):
1022 parser = create_parser()
1023 self.assertEqual(parser.getFeature(feature_external_ges), False)
1024 parser.setEntityResolver(self.TestEntityResolver())
1025 result = BytesIO()
1026 parser.setContentHandler(XMLGenerator(result))
1027
1028 parser.feed('<!DOCTYPE doc [\n')
1029 parser.feed(' <!ENTITY test SYSTEM "whatever">\n')
1030 parser.feed(']>\n')
1031 parser.feed('<doc>&test;</doc>')
1032 parser.close()
1033
1034 self.assertEqual(result.getvalue(), start +
1035 b"<doc></doc>")
1036
Guido van Rossumd8faa362007-04-27 19:54:29 +00001037 # ===== Attributes support
Lars Gustäbel2fc52942000-10-24 15:35:07 +00001038
Guido van Rossumd8faa362007-04-27 19:54:29 +00001039 class AttrGatherer(ContentHandler):
Lars Gustäbel2fc52942000-10-24 15:35:07 +00001040
Guido van Rossumd8faa362007-04-27 19:54:29 +00001041 def startElement(self, name, attrs):
1042 self._attrs = attrs
Lars Gustäbel2fc52942000-10-24 15:35:07 +00001043
Guido van Rossumd8faa362007-04-27 19:54:29 +00001044 def startElementNS(self, name, qname, attrs):
1045 self._attrs = attrs
Lars Gustäbel2fc52942000-10-24 15:35:07 +00001046
Guido van Rossumd8faa362007-04-27 19:54:29 +00001047 def test_expat_attrs_empty(self):
1048 parser = create_parser()
1049 gather = self.AttrGatherer()
1050 parser.setContentHandler(gather)
1051
1052 parser.feed("<doc/>")
1053 parser.close()
1054
1055 self.verify_empty_attrs(gather._attrs)
1056
1057 def test_expat_attrs_wattr(self):
1058 parser = create_parser()
1059 gather = self.AttrGatherer()
1060 parser.setContentHandler(gather)
1061
1062 parser.feed("<doc attr='val'/>")
1063 parser.close()
1064
1065 self.verify_attrs_wattr(gather._attrs)
1066
1067 def test_expat_nsattrs_empty(self):
1068 parser = create_parser(1)
1069 gather = self.AttrGatherer()
1070 parser.setContentHandler(gather)
1071
1072 parser.feed("<doc/>")
1073 parser.close()
1074
1075 self.verify_empty_nsattrs(gather._attrs)
1076
1077 def test_expat_nsattrs_wattr(self):
1078 parser = create_parser(1)
1079 gather = self.AttrGatherer()
1080 parser.setContentHandler(gather)
1081
1082 parser.feed("<doc xmlns:ns='%s' ns:attr='val'/>" % ns_uri)
1083 parser.close()
1084
1085 attrs = gather._attrs
1086
Ezio Melottib3aedd42010-11-20 19:04:17 +00001087 self.assertEqual(attrs.getLength(), 1)
1088 self.assertEqual(attrs.getNames(), [(ns_uri, "attr")])
Guido van Rossumd8faa362007-04-27 19:54:29 +00001089 self.assertTrue((attrs.getQNames() == [] or
1090 attrs.getQNames() == ["ns:attr"]))
Ezio Melottib3aedd42010-11-20 19:04:17 +00001091 self.assertEqual(len(attrs), 1)
Benjamin Peterson577473f2010-01-19 00:09:57 +00001092 self.assertIn((ns_uri, "attr"), attrs)
Ezio Melottib3aedd42010-11-20 19:04:17 +00001093 self.assertEqual(attrs.get((ns_uri, "attr")), "val")
1094 self.assertEqual(attrs.get((ns_uri, "attr"), 25), "val")
1095 self.assertEqual(list(attrs.items()), [((ns_uri, "attr"), "val")])
1096 self.assertEqual(list(attrs.values()), ["val"])
1097 self.assertEqual(attrs.getValue((ns_uri, "attr")), "val")
1098 self.assertEqual(attrs[(ns_uri, "attr")], "val")
Guido van Rossumd8faa362007-04-27 19:54:29 +00001099
1100 # ===== InputSource support
1101
Benjamin Petersona7f4f5a2008-09-04 02:22:52 +00001102 def test_expat_inpsource_filename(self):
Guido van Rossumd8faa362007-04-27 19:54:29 +00001103 parser = create_parser()
Serhiy Storchaka88efc522013-02-10 14:29:52 +02001104 result = BytesIO()
Guido van Rossumd8faa362007-04-27 19:54:29 +00001105 xmlgen = XMLGenerator(result)
1106
1107 parser.setContentHandler(xmlgen)
Florent Xiclunaf15351d2010-03-13 23:24:31 +00001108 parser.parse(TEST_XMLFILE)
Guido van Rossumd8faa362007-04-27 19:54:29 +00001109
Ezio Melottib3aedd42010-11-20 19:04:17 +00001110 self.assertEqual(result.getvalue(), xml_test_out)
Guido van Rossumd8faa362007-04-27 19:54:29 +00001111
Benjamin Petersona7f4f5a2008-09-04 02:22:52 +00001112 def test_expat_inpsource_sysid(self):
Guido van Rossumd8faa362007-04-27 19:54:29 +00001113 parser = create_parser()
Serhiy Storchaka88efc522013-02-10 14:29:52 +02001114 result = BytesIO()
Guido van Rossumd8faa362007-04-27 19:54:29 +00001115 xmlgen = XMLGenerator(result)
1116
1117 parser.setContentHandler(xmlgen)
Florent Xiclunaf15351d2010-03-13 23:24:31 +00001118 parser.parse(InputSource(TEST_XMLFILE))
Guido van Rossumd8faa362007-04-27 19:54:29 +00001119
Ezio Melottib3aedd42010-11-20 19:04:17 +00001120 self.assertEqual(result.getvalue(), xml_test_out)
Guido van Rossumd8faa362007-04-27 19:54:29 +00001121
Serhiy Storchaka1a4ed4c2013-02-02 12:17:05 +02001122 @requires_nonascii_filenames
Serhiy Storchakad5202392013-02-02 10:31:17 +02001123 def test_expat_inpsource_sysid_nonascii(self):
1124 fname = support.TESTFN_UNICODE
1125 shutil.copyfile(TEST_XMLFILE, fname)
1126 self.addCleanup(support.unlink, fname)
1127
1128 parser = create_parser()
Serhiy Storchaka88efc522013-02-10 14:29:52 +02001129 result = BytesIO()
Serhiy Storchakad5202392013-02-02 10:31:17 +02001130 xmlgen = XMLGenerator(result)
1131
1132 parser.setContentHandler(xmlgen)
1133 parser.parse(InputSource(fname))
1134
1135 self.assertEqual(result.getvalue(), xml_test_out)
1136
Serhiy Storchakaaa9563c2015-04-02 20:55:59 +03001137 def test_expat_inpsource_byte_stream(self):
Guido van Rossumd8faa362007-04-27 19:54:29 +00001138 parser = create_parser()
Serhiy Storchaka88efc522013-02-10 14:29:52 +02001139 result = BytesIO()
Guido van Rossumd8faa362007-04-27 19:54:29 +00001140 xmlgen = XMLGenerator(result)
1141
1142 parser.setContentHandler(xmlgen)
1143 inpsrc = InputSource()
Serhiy Storchaka88efc522013-02-10 14:29:52 +02001144 with open(TEST_XMLFILE, 'rb') as f:
Benjamin Petersond5df36d2010-10-31 18:23:23 +00001145 inpsrc.setByteStream(f)
1146 parser.parse(inpsrc)
Guido van Rossumd8faa362007-04-27 19:54:29 +00001147
Ezio Melottib3aedd42010-11-20 19:04:17 +00001148 self.assertEqual(result.getvalue(), xml_test_out)
Guido van Rossumd8faa362007-04-27 19:54:29 +00001149
Serhiy Storchaka61de0872015-04-02 21:00:13 +03001150 def test_expat_inpsource_character_stream(self):
1151 parser = create_parser()
1152 result = BytesIO()
1153 xmlgen = XMLGenerator(result)
1154
1155 parser.setContentHandler(xmlgen)
1156 inpsrc = InputSource()
1157 with open(TEST_XMLFILE, 'rt', encoding='iso-8859-1') as f:
1158 inpsrc.setCharacterStream(f)
1159 parser.parse(inpsrc)
1160
1161 self.assertEqual(result.getvalue(), xml_test_out)
1162
Guido van Rossumd8faa362007-04-27 19:54:29 +00001163 # ===== IncrementalParser support
1164
1165 def test_expat_incremental(self):
Serhiy Storchaka88efc522013-02-10 14:29:52 +02001166 result = BytesIO()
Guido van Rossumd8faa362007-04-27 19:54:29 +00001167 xmlgen = XMLGenerator(result)
1168 parser = create_parser()
1169 parser.setContentHandler(xmlgen)
1170
1171 parser.feed("<doc>")
1172 parser.feed("</doc>")
1173 parser.close()
1174
Serhiy Storchaka88efc522013-02-10 14:29:52 +02001175 self.assertEqual(result.getvalue(), start + b"<doc></doc>")
Guido van Rossumd8faa362007-04-27 19:54:29 +00001176
1177 def test_expat_incremental_reset(self):
Serhiy Storchaka88efc522013-02-10 14:29:52 +02001178 result = BytesIO()
Guido van Rossumd8faa362007-04-27 19:54:29 +00001179 xmlgen = XMLGenerator(result)
1180 parser = create_parser()
1181 parser.setContentHandler(xmlgen)
1182
1183 parser.feed("<doc>")
1184 parser.feed("text")
1185
Serhiy Storchaka88efc522013-02-10 14:29:52 +02001186 result = BytesIO()
Guido van Rossumd8faa362007-04-27 19:54:29 +00001187 xmlgen = XMLGenerator(result)
1188 parser.setContentHandler(xmlgen)
1189 parser.reset()
1190
1191 parser.feed("<doc>")
1192 parser.feed("text")
1193 parser.feed("</doc>")
1194 parser.close()
1195
Serhiy Storchaka88efc522013-02-10 14:29:52 +02001196 self.assertEqual(result.getvalue(), start + b"<doc>text</doc>")
Guido van Rossumd8faa362007-04-27 19:54:29 +00001197
1198 # ===== Locator support
1199
1200 def test_expat_locator_noinfo(self):
Serhiy Storchaka88efc522013-02-10 14:29:52 +02001201 result = BytesIO()
Guido van Rossumd8faa362007-04-27 19:54:29 +00001202 xmlgen = XMLGenerator(result)
1203 parser = create_parser()
1204 parser.setContentHandler(xmlgen)
1205
1206 parser.feed("<doc>")
1207 parser.feed("</doc>")
1208 parser.close()
1209
Ezio Melottib3aedd42010-11-20 19:04:17 +00001210 self.assertEqual(parser.getSystemId(), None)
1211 self.assertEqual(parser.getPublicId(), None)
1212 self.assertEqual(parser.getLineNumber(), 1)
Guido van Rossumd8faa362007-04-27 19:54:29 +00001213
Benjamin Petersona7f4f5a2008-09-04 02:22:52 +00001214 def test_expat_locator_withinfo(self):
Serhiy Storchaka88efc522013-02-10 14:29:52 +02001215 result = BytesIO()
Guido van Rossumd8faa362007-04-27 19:54:29 +00001216 xmlgen = XMLGenerator(result)
1217 parser = create_parser()
1218 parser.setContentHandler(xmlgen)
Florent Xiclunaf15351d2010-03-13 23:24:31 +00001219 parser.parse(TEST_XMLFILE)
Guido van Rossumd8faa362007-04-27 19:54:29 +00001220
Ezio Melottib3aedd42010-11-20 19:04:17 +00001221 self.assertEqual(parser.getSystemId(), TEST_XMLFILE)
1222 self.assertEqual(parser.getPublicId(), None)
Lars Gustäbel2fc52942000-10-24 15:35:07 +00001223
Serhiy Storchaka1a4ed4c2013-02-02 12:17:05 +02001224 @requires_nonascii_filenames
Serhiy Storchakad5202392013-02-02 10:31:17 +02001225 def test_expat_locator_withinfo_nonascii(self):
1226 fname = support.TESTFN_UNICODE
1227 shutil.copyfile(TEST_XMLFILE, fname)
1228 self.addCleanup(support.unlink, fname)
1229
Serhiy Storchaka88efc522013-02-10 14:29:52 +02001230 result = BytesIO()
Serhiy Storchakad5202392013-02-02 10:31:17 +02001231 xmlgen = XMLGenerator(result)
1232 parser = create_parser()
1233 parser.setContentHandler(xmlgen)
1234 parser.parse(fname)
1235
1236 self.assertEqual(parser.getSystemId(), fname)
1237 self.assertEqual(parser.getPublicId(), None)
1238
Martin v. Löwis80670bc2000-10-06 21:13:23 +00001239
1240# ===========================================================================
1241#
1242# error reporting
1243#
1244# ===========================================================================
1245
Guido van Rossumd8faa362007-04-27 19:54:29 +00001246class ErrorReportingTest(unittest.TestCase):
1247 def test_expat_inpsource_location(self):
1248 parser = create_parser()
1249 parser.setContentHandler(ContentHandler()) # do nothing
1250 source = InputSource()
Serhiy Storchaka88efc522013-02-10 14:29:52 +02001251 source.setByteStream(BytesIO(b"<foo bar foobar>")) #ill-formed
Guido van Rossumd8faa362007-04-27 19:54:29 +00001252 name = "a file name"
1253 source.setSystemId(name)
1254 try:
1255 parser.parse(source)
1256 self.fail()
1257 except SAXException as e:
Ezio Melottib3aedd42010-11-20 19:04:17 +00001258 self.assertEqual(e.getSystemId(), name)
Martin v. Löwis80670bc2000-10-06 21:13:23 +00001259
Guido van Rossumd8faa362007-04-27 19:54:29 +00001260 def test_expat_incomplete(self):
1261 parser = create_parser()
1262 parser.setContentHandler(ContentHandler()) # do nothing
1263 self.assertRaises(SAXParseException, parser.parse, StringIO("<foo>"))
Serhiy Storchakaab914782015-05-06 09:36:06 +03001264 self.assertEqual(parser.getColumnNumber(), 5)
1265 self.assertEqual(parser.getLineNumber(), 1)
Martin v. Löwis80670bc2000-10-06 21:13:23 +00001266
Guido van Rossumd8faa362007-04-27 19:54:29 +00001267 def test_sax_parse_exception_str(self):
1268 # pass various values from a locator to the SAXParseException to
1269 # make sure that the __str__() doesn't fall apart when None is
1270 # passed instead of an integer line and column number
1271 #
1272 # use "normal" values for the locator:
1273 str(SAXParseException("message", None,
1274 self.DummyLocator(1, 1)))
1275 # use None for the line number:
1276 str(SAXParseException("message", None,
1277 self.DummyLocator(None, 1)))
1278 # use None for the column number:
1279 str(SAXParseException("message", None,
1280 self.DummyLocator(1, None)))
1281 # use None for both:
1282 str(SAXParseException("message", None,
1283 self.DummyLocator(None, None)))
Fred Drake6fd0b0d2004-03-20 08:15:30 +00001284
Guido van Rossumd8faa362007-04-27 19:54:29 +00001285 class DummyLocator:
1286 def __init__(self, lineno, colno):
1287 self._lineno = lineno
1288 self._colno = colno
Fred Drake6fd0b0d2004-03-20 08:15:30 +00001289
Guido van Rossumd8faa362007-04-27 19:54:29 +00001290 def getPublicId(self):
1291 return "pubid"
Fred Drake6fd0b0d2004-03-20 08:15:30 +00001292
Guido van Rossumd8faa362007-04-27 19:54:29 +00001293 def getSystemId(self):
1294 return "sysid"
Fred Drake6fd0b0d2004-03-20 08:15:30 +00001295
Guido van Rossumd8faa362007-04-27 19:54:29 +00001296 def getLineNumber(self):
1297 return self._lineno
Fred Drake6fd0b0d2004-03-20 08:15:30 +00001298
Guido van Rossumd8faa362007-04-27 19:54:29 +00001299 def getColumnNumber(self):
1300 return self._colno
Martin v. Löwis80670bc2000-10-06 21:13:23 +00001301
Lars Gustäbelab647872000-09-24 18:40:52 +00001302# ===========================================================================
1303#
1304# xmlreader tests
1305#
1306# ===========================================================================
1307
Guido van Rossumd8faa362007-04-27 19:54:29 +00001308class XmlReaderTest(XmlTestBase):
Lars Gustäbelab647872000-09-24 18:40:52 +00001309
Guido van Rossumd8faa362007-04-27 19:54:29 +00001310 # ===== AttributesImpl
1311 def test_attrs_empty(self):
1312 self.verify_empty_attrs(AttributesImpl({}))
Lars Gustäbelab647872000-09-24 18:40:52 +00001313
Guido van Rossumd8faa362007-04-27 19:54:29 +00001314 def test_attrs_wattr(self):
1315 self.verify_attrs_wattr(AttributesImpl({"attr" : "val"}))
Lars Gustäbelab647872000-09-24 18:40:52 +00001316
Guido van Rossumd8faa362007-04-27 19:54:29 +00001317 def test_nsattrs_empty(self):
1318 self.verify_empty_nsattrs(AttributesNSImpl({}, {}))
Lars Gustäbelab647872000-09-24 18:40:52 +00001319
Guido van Rossumd8faa362007-04-27 19:54:29 +00001320 def test_nsattrs_wattr(self):
1321 attrs = AttributesNSImpl({(ns_uri, "attr") : "val"},
1322 {(ns_uri, "attr") : "ns:attr"})
Fred Drake004d5e62000-10-23 17:22:08 +00001323
Ezio Melottib3aedd42010-11-20 19:04:17 +00001324 self.assertEqual(attrs.getLength(), 1)
1325 self.assertEqual(attrs.getNames(), [(ns_uri, "attr")])
1326 self.assertEqual(attrs.getQNames(), ["ns:attr"])
1327 self.assertEqual(len(attrs), 1)
Benjamin Peterson577473f2010-01-19 00:09:57 +00001328 self.assertIn((ns_uri, "attr"), attrs)
Ezio Melottib3aedd42010-11-20 19:04:17 +00001329 self.assertEqual(list(attrs.keys()), [(ns_uri, "attr")])
1330 self.assertEqual(attrs.get((ns_uri, "attr")), "val")
1331 self.assertEqual(attrs.get((ns_uri, "attr"), 25), "val")
1332 self.assertEqual(list(attrs.items()), [((ns_uri, "attr"), "val")])
1333 self.assertEqual(list(attrs.values()), ["val"])
1334 self.assertEqual(attrs.getValue((ns_uri, "attr")), "val")
1335 self.assertEqual(attrs.getValueByQName("ns:attr"), "val")
1336 self.assertEqual(attrs.getNameByQName("ns:attr"), (ns_uri, "attr"))
1337 self.assertEqual(attrs[(ns_uri, "attr")], "val")
1338 self.assertEqual(attrs.getQNameByName((ns_uri, "attr")), "ns:attr")
Fred Drake004d5e62000-10-23 17:22:08 +00001339
Lars Gustäbelab647872000-09-24 18:40:52 +00001340
Christian Heimesbbe741d2008-03-28 10:53:29 +00001341def test_main():
Guido van Rossumd8faa362007-04-27 19:54:29 +00001342 run_unittest(MakeParserTest,
Serhiy Storchaka13e41c52015-04-02 23:05:57 +03001343 ParseTest,
Guido van Rossumd8faa362007-04-27 19:54:29 +00001344 SaxutilsTest,
Serhiy Storchakaaa9563c2015-04-02 20:55:59 +03001345 PrepareInputSourceTest,
Serhiy Storchaka88efc522013-02-10 14:29:52 +02001346 StringXmlgenTest,
1347 BytesXmlgenTest,
1348 WriterXmlgenTest,
Georg Brandlc502df42013-05-12 11:41:12 +02001349 StreamWriterXmlgenTest,
1350 StreamReaderWriterXmlgenTest,
Guido van Rossumd8faa362007-04-27 19:54:29 +00001351 ExpatReaderTest,
1352 ErrorReportingTest,
1353 XmlReaderTest)
Lars Gustäbelb7536d52000-09-24 18:53:56 +00001354
Guido van Rossumd8faa362007-04-27 19:54:29 +00001355if __name__ == "__main__":
Christian Heimesbbe741d2008-03-28 10:53:29 +00001356 test_main()