blob: eabbf57c2d92fdf3a5fb2a904c7fb1a7e85289d2 [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
Martin v. Löwis962c9e72000-10-06 17:41:52 +00007try:
8 make_parser()
Martin v. Löwis80670bc2000-10-06 21:13:23 +00009except SAXReaderNotAvailable:
Martin v. Löwis962c9e72000-10-06 17:41:52 +000010 # don't try to test this module if we cannot create a parser
R David Murraya846f5a2013-03-18 00:18:12 -040011 raise unittest.SkipTest("no XML parsers available")
Thomas Wouters0e3f5912006-08-11 14:57:12 +000012from xml.sax.saxutils import XMLGenerator, escape, unescape, quoteattr, \
Serhiy Storchakaaa9563c2015-04-02 20:55:59 +030013 XMLFilterBase, prepare_input_source
Thomas Wouters0e3f5912006-08-11 14:57:12 +000014from xml.sax.expatreader import create_parser
Antoine Pitrou6b03ee62010-10-27 18:33:30 +000015from xml.sax.handler import feature_namespaces
Thomas Wouters0e3f5912006-08-11 14:57:12 +000016from xml.sax.xmlreader import InputSource, AttributesImpl, AttributesNSImpl
Serhiy Storchaka88efc522013-02-10 14:29:52 +020017from io import BytesIO, StringIO
Georg Brandlc502df42013-05-12 11:41:12 +020018import codecs
Serhiy Storchaka13e41c52015-04-02 23:05:57 +030019import gc
Serhiy Storchaka1a4ed4c2013-02-02 12:17:05 +020020import os.path
Serhiy Storchakad5202392013-02-02 10:31:17 +020021import shutil
22from test import support
Serhiy Storchaka13e41c52015-04-02 23:05:57 +030023from test.support import findfile, run_unittest, TESTFN
Florent Xiclunaf15351d2010-03-13 23:24:31 +000024
25TEST_XMLFILE = findfile("test.xml", subdir="xmltestdata")
26TEST_XMLFILE_OUT = findfile("test.xml.out", subdir="xmltestdata")
Victor Stinner6c6f8512010-08-07 10:09:35 +000027try:
Marc-André Lemburg8f36af72011-02-25 15:42:01 +000028 TEST_XMLFILE.encode("utf-8")
29 TEST_XMLFILE_OUT.encode("utf-8")
Victor Stinner6c6f8512010-08-07 10:09:35 +000030except UnicodeEncodeError:
31 raise unittest.SkipTest("filename is not encodable to utf8")
Lars Gustäbel96753b32000-09-24 12:24:24 +000032
Serhiy Storchaka1a4ed4c2013-02-02 12:17:05 +020033supports_nonascii_filenames = True
34if not os.path.supports_unicode_filenames:
35 try:
36 support.TESTFN_UNICODE.encode(support.TESTFN_ENCODING)
37 except (UnicodeError, TypeError):
38 # Either the file system encoding is None, or the file name
39 # cannot be encoded in the file system encoding.
40 supports_nonascii_filenames = False
41requires_nonascii_filenames = unittest.skipUnless(
42 supports_nonascii_filenames,
43 'Requires non-ascii filenames support')
44
Guido van Rossumd8faa362007-04-27 19:54:29 +000045ns_uri = "http://www.python.org/xml-ns/saxtest/"
Lars Gustäbel96753b32000-09-24 12:24:24 +000046
Guido van Rossumd8faa362007-04-27 19:54:29 +000047class XmlTestBase(unittest.TestCase):
48 def verify_empty_attrs(self, attrs):
49 self.assertRaises(KeyError, attrs.getValue, "attr")
50 self.assertRaises(KeyError, attrs.getValueByQName, "attr")
51 self.assertRaises(KeyError, attrs.getNameByQName, "attr")
52 self.assertRaises(KeyError, attrs.getQNameByName, "attr")
53 self.assertRaises(KeyError, attrs.__getitem__, "attr")
Ezio Melottib3aedd42010-11-20 19:04:17 +000054 self.assertEqual(attrs.getLength(), 0)
55 self.assertEqual(attrs.getNames(), [])
56 self.assertEqual(attrs.getQNames(), [])
57 self.assertEqual(len(attrs), 0)
Ezio Melottib58e0bd2010-01-23 15:40:09 +000058 self.assertNotIn("attr", attrs)
Ezio Melottib3aedd42010-11-20 19:04:17 +000059 self.assertEqual(list(attrs.keys()), [])
60 self.assertEqual(attrs.get("attrs"), None)
61 self.assertEqual(attrs.get("attrs", 25), 25)
62 self.assertEqual(list(attrs.items()), [])
63 self.assertEqual(list(attrs.values()), [])
Lars Gustäbel96753b32000-09-24 12:24:24 +000064
Guido van Rossumd8faa362007-04-27 19:54:29 +000065 def verify_empty_nsattrs(self, attrs):
66 self.assertRaises(KeyError, attrs.getValue, (ns_uri, "attr"))
67 self.assertRaises(KeyError, attrs.getValueByQName, "ns:attr")
68 self.assertRaises(KeyError, attrs.getNameByQName, "ns:attr")
69 self.assertRaises(KeyError, attrs.getQNameByName, (ns_uri, "attr"))
70 self.assertRaises(KeyError, attrs.__getitem__, (ns_uri, "attr"))
Ezio Melottib3aedd42010-11-20 19:04:17 +000071 self.assertEqual(attrs.getLength(), 0)
72 self.assertEqual(attrs.getNames(), [])
73 self.assertEqual(attrs.getQNames(), [])
74 self.assertEqual(len(attrs), 0)
Ezio Melottib58e0bd2010-01-23 15:40:09 +000075 self.assertNotIn((ns_uri, "attr"), attrs)
Ezio Melottib3aedd42010-11-20 19:04:17 +000076 self.assertEqual(list(attrs.keys()), [])
77 self.assertEqual(attrs.get((ns_uri, "attr")), None)
78 self.assertEqual(attrs.get((ns_uri, "attr"), 25), 25)
79 self.assertEqual(list(attrs.items()), [])
80 self.assertEqual(list(attrs.values()), [])
Lars Gustäbel96753b32000-09-24 12:24:24 +000081
Guido van Rossumd8faa362007-04-27 19:54:29 +000082 def verify_attrs_wattr(self, attrs):
Ezio Melottib3aedd42010-11-20 19:04:17 +000083 self.assertEqual(attrs.getLength(), 1)
84 self.assertEqual(attrs.getNames(), ["attr"])
85 self.assertEqual(attrs.getQNames(), ["attr"])
86 self.assertEqual(len(attrs), 1)
Benjamin Peterson577473f2010-01-19 00:09:57 +000087 self.assertIn("attr", attrs)
Ezio Melottib3aedd42010-11-20 19:04:17 +000088 self.assertEqual(list(attrs.keys()), ["attr"])
89 self.assertEqual(attrs.get("attr"), "val")
90 self.assertEqual(attrs.get("attr", 25), "val")
91 self.assertEqual(list(attrs.items()), [("attr", "val")])
92 self.assertEqual(list(attrs.values()), ["val"])
93 self.assertEqual(attrs.getValue("attr"), "val")
94 self.assertEqual(attrs.getValueByQName("attr"), "val")
95 self.assertEqual(attrs.getNameByQName("attr"), "attr")
96 self.assertEqual(attrs["attr"], "val")
97 self.assertEqual(attrs.getQNameByName("attr"), "attr")
Lars Gustäbel96753b32000-09-24 12:24:24 +000098
Serhiy Storchaka13e41c52015-04-02 23:05:57 +030099
100def xml_str(doc, encoding=None):
101 if encoding is None:
102 return doc
103 return '<?xml version="1.0" encoding="%s"?>\n%s' % (encoding, doc)
104
105def xml_bytes(doc, encoding, decl_encoding=...):
106 if decl_encoding is ...:
107 decl_encoding = encoding
108 return xml_str(doc, decl_encoding).encode(encoding, 'xmlcharrefreplace')
109
110def make_xml_file(doc, encoding, decl_encoding=...):
111 if decl_encoding is ...:
112 decl_encoding = encoding
113 with open(TESTFN, 'w', encoding=encoding, errors='xmlcharrefreplace') as f:
114 f.write(xml_str(doc, decl_encoding))
115
116
117class ParseTest(unittest.TestCase):
118 data = '<money value="$\xa3\u20ac\U0001017b">$\xa3\u20ac\U0001017b</money>'
119
120 def tearDown(self):
121 support.unlink(TESTFN)
122
123 def check_parse(self, f):
124 from xml.sax import parse
125 result = StringIO()
126 parse(f, XMLGenerator(result, 'utf-8'))
127 self.assertEqual(result.getvalue(), xml_str(self.data, 'utf-8'))
128
129 def test_parse_text(self):
130 encodings = ('us-ascii', 'iso-8859-1', 'utf-8',
131 'utf-16', 'utf-16le', 'utf-16be')
132 for encoding in encodings:
133 self.check_parse(StringIO(xml_str(self.data, encoding)))
134 make_xml_file(self.data, encoding)
135 with open(TESTFN, 'r', encoding=encoding) as f:
136 self.check_parse(f)
137 self.check_parse(StringIO(self.data))
138 make_xml_file(self.data, encoding, None)
139 with open(TESTFN, 'r', encoding=encoding) as f:
140 self.check_parse(f)
141
142 def test_parse_bytes(self):
143 # UTF-8 is default encoding, US-ASCII is compatible with UTF-8,
144 # UTF-16 is autodetected
145 encodings = ('us-ascii', 'utf-8', 'utf-16', 'utf-16le', 'utf-16be')
146 for encoding in encodings:
147 self.check_parse(BytesIO(xml_bytes(self.data, encoding)))
148 make_xml_file(self.data, encoding)
149 self.check_parse(TESTFN)
150 with open(TESTFN, 'rb') as f:
151 self.check_parse(f)
152 self.check_parse(BytesIO(xml_bytes(self.data, encoding, None)))
153 make_xml_file(self.data, encoding, None)
154 self.check_parse(TESTFN)
155 with open(TESTFN, 'rb') as f:
156 self.check_parse(f)
157 # accept UTF-8 with BOM
158 self.check_parse(BytesIO(xml_bytes(self.data, 'utf-8-sig', 'utf-8')))
159 make_xml_file(self.data, 'utf-8-sig', 'utf-8')
160 self.check_parse(TESTFN)
161 with open(TESTFN, 'rb') as f:
162 self.check_parse(f)
163 self.check_parse(BytesIO(xml_bytes(self.data, 'utf-8-sig', None)))
164 make_xml_file(self.data, 'utf-8-sig', None)
165 self.check_parse(TESTFN)
166 with open(TESTFN, 'rb') as f:
167 self.check_parse(f)
168 # accept data with declared encoding
169 self.check_parse(BytesIO(xml_bytes(self.data, 'iso-8859-1')))
170 make_xml_file(self.data, 'iso-8859-1')
171 self.check_parse(TESTFN)
172 with open(TESTFN, 'rb') as f:
173 self.check_parse(f)
174 # fail on non-UTF-8 incompatible data without declared encoding
175 with self.assertRaises(SAXException):
176 self.check_parse(BytesIO(xml_bytes(self.data, 'iso-8859-1', None)))
177 make_xml_file(self.data, 'iso-8859-1', None)
178 with support.check_warnings(('unclosed file', ResourceWarning)):
179 # XXX Failed parser leaks an opened file.
180 with self.assertRaises(SAXException):
181 self.check_parse(TESTFN)
182 # Collect leaked file.
183 gc.collect()
184 with open(TESTFN, 'rb') as f:
185 with self.assertRaises(SAXException):
186 self.check_parse(f)
187
188 def test_parse_InputSource(self):
189 # accept data without declared but with explicitly specified encoding
190 make_xml_file(self.data, 'iso-8859-1', None)
191 with open(TESTFN, 'rb') as f:
192 input = InputSource()
193 input.setByteStream(f)
194 input.setEncoding('iso-8859-1')
195 self.check_parse(input)
196
197 def check_parseString(self, s):
198 from xml.sax import parseString
199 result = StringIO()
200 parseString(s, XMLGenerator(result, 'utf-8'))
201 self.assertEqual(result.getvalue(), xml_str(self.data, 'utf-8'))
202
203 def test_parseString_bytes(self):
204 # UTF-8 is default encoding, US-ASCII is compatible with UTF-8,
205 # UTF-16 is autodetected
206 encodings = ('us-ascii', 'utf-8', 'utf-16', 'utf-16le', 'utf-16be')
207 for encoding in encodings:
208 self.check_parseString(xml_bytes(self.data, encoding))
209 self.check_parseString(xml_bytes(self.data, encoding, None))
210 # accept UTF-8 with BOM
211 self.check_parseString(xml_bytes(self.data, 'utf-8-sig', 'utf-8'))
212 self.check_parseString(xml_bytes(self.data, 'utf-8-sig', None))
213 # accept data with declared encoding
214 self.check_parseString(xml_bytes(self.data, 'iso-8859-1'))
215 # fail on non-UTF-8 incompatible data without declared encoding
216 with self.assertRaises(SAXException):
217 self.check_parseString(xml_bytes(self.data, 'iso-8859-1', None))
218
Guido van Rossumd8faa362007-04-27 19:54:29 +0000219class MakeParserTest(unittest.TestCase):
220 def test_make_parser2(self):
Lars Gustäbel2fc52942000-10-24 15:35:07 +0000221 # Creating parsers several times in a row should succeed.
222 # Testing this because there have been failures of this kind
223 # before.
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000224 from xml.sax import make_parser
Lars Gustäbel2fc52942000-10-24 15:35:07 +0000225 p = make_parser()
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000226 from xml.sax import make_parser
Lars Gustäbel2fc52942000-10-24 15:35:07 +0000227 p = make_parser()
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000228 from xml.sax import make_parser
Lars Gustäbel2fc52942000-10-24 15:35:07 +0000229 p = make_parser()
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000230 from xml.sax import make_parser
Lars Gustäbel2fc52942000-10-24 15:35:07 +0000231 p = make_parser()
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000232 from xml.sax import make_parser
Lars Gustäbel2fc52942000-10-24 15:35:07 +0000233 p = make_parser()
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000234 from xml.sax import make_parser
Lars Gustäbel2fc52942000-10-24 15:35:07 +0000235 p = make_parser()
Tim Petersd2bf3b72001-01-18 02:22:22 +0000236
237
Lars Gustäbel96753b32000-09-24 12:24:24 +0000238# ===========================================================================
239#
240# saxutils tests
241#
242# ===========================================================================
243
Guido van Rossumd8faa362007-04-27 19:54:29 +0000244class SaxutilsTest(unittest.TestCase):
245 # ===== escape
246 def test_escape_basic(self):
Ezio Melottib3aedd42010-11-20 19:04:17 +0000247 self.assertEqual(escape("Donald Duck & Co"), "Donald Duck &amp; Co")
Lars Gustäbel96753b32000-09-24 12:24:24 +0000248
Guido van Rossumd8faa362007-04-27 19:54:29 +0000249 def test_escape_all(self):
Ezio Melottib3aedd42010-11-20 19:04:17 +0000250 self.assertEqual(escape("<Donald Duck & Co>"),
251 "&lt;Donald Duck &amp; Co&gt;")
Lars Gustäbel96753b32000-09-24 12:24:24 +0000252
Guido van Rossumd8faa362007-04-27 19:54:29 +0000253 def test_escape_extra(self):
Ezio Melottib3aedd42010-11-20 19:04:17 +0000254 self.assertEqual(escape("Hei på deg", {"å" : "&aring;"}),
255 "Hei p&aring; deg")
Lars Gustäbel96753b32000-09-24 12:24:24 +0000256
Guido van Rossumd8faa362007-04-27 19:54:29 +0000257 # ===== unescape
258 def test_unescape_basic(self):
Ezio Melottib3aedd42010-11-20 19:04:17 +0000259 self.assertEqual(unescape("Donald Duck &amp; Co"), "Donald Duck & Co")
Lars Gustäbel96753b32000-09-24 12:24:24 +0000260
Guido van Rossumd8faa362007-04-27 19:54:29 +0000261 def test_unescape_all(self):
Ezio Melottib3aedd42010-11-20 19:04:17 +0000262 self.assertEqual(unescape("&lt;Donald Duck &amp; Co&gt;"),
263 "<Donald Duck & Co>")
Martin v. Löwis74b51ac2002-10-26 14:50:45 +0000264
Guido van Rossumd8faa362007-04-27 19:54:29 +0000265 def test_unescape_extra(self):
Ezio Melottib3aedd42010-11-20 19:04:17 +0000266 self.assertEqual(unescape("Hei på deg", {"å" : "&aring;"}),
267 "Hei p&aring; deg")
Martin v. Löwis74b51ac2002-10-26 14:50:45 +0000268
Guido van Rossumd8faa362007-04-27 19:54:29 +0000269 def test_unescape_amp_extra(self):
Ezio Melottib3aedd42010-11-20 19:04:17 +0000270 self.assertEqual(unescape("&amp;foo;", {"&foo;": "splat"}), "&foo;")
Martin v. Löwis74b51ac2002-10-26 14:50:45 +0000271
Guido van Rossumd8faa362007-04-27 19:54:29 +0000272 # ===== quoteattr
273 def test_quoteattr_basic(self):
Ezio Melottib3aedd42010-11-20 19:04:17 +0000274 self.assertEqual(quoteattr("Donald Duck & Co"),
275 '"Donald Duck &amp; Co"')
Martin v. Löwis74b51ac2002-10-26 14:50:45 +0000276
Guido van Rossumd8faa362007-04-27 19:54:29 +0000277 def test_single_quoteattr(self):
Ezio Melottib3aedd42010-11-20 19:04:17 +0000278 self.assertEqual(quoteattr('Includes "double" quotes'),
279 '\'Includes "double" quotes\'')
Fred Drake32f3add2002-10-28 17:58:48 +0000280
Guido van Rossumd8faa362007-04-27 19:54:29 +0000281 def test_double_quoteattr(self):
Ezio Melottib3aedd42010-11-20 19:04:17 +0000282 self.assertEqual(quoteattr("Includes 'single' quotes"),
283 "\"Includes 'single' quotes\"")
Fred Drakeacd32d32001-07-19 16:10:15 +0000284
Guido van Rossumd8faa362007-04-27 19:54:29 +0000285 def test_single_double_quoteattr(self):
Ezio Melottib3aedd42010-11-20 19:04:17 +0000286 self.assertEqual(quoteattr("Includes 'single' and \"double\" quotes"),
287 "\"Includes 'single' and &quot;double&quot; quotes\"")
Fred Drakeacd32d32001-07-19 16:10:15 +0000288
Guido van Rossumd8faa362007-04-27 19:54:29 +0000289 # ===== make_parser
290 def test_make_parser(self):
Martin v. Löwis962c9e72000-10-06 17:41:52 +0000291 # Creating a parser should succeed - it should fall back
292 # to the expatreader
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000293 p = make_parser(['xml.parsers.no_such_parser'])
Martin v. Löwis962c9e72000-10-06 17:41:52 +0000294
295
Serhiy Storchakaaa9563c2015-04-02 20:55:59 +0300296class PrepareInputSourceTest(unittest.TestCase):
297
298 def setUp(self):
299 self.file = support.TESTFN
300 with open(self.file, "w") as tmp:
301 tmp.write("This was read from a file.")
302
303 def tearDown(self):
304 support.unlink(self.file)
305
306 def make_byte_stream(self):
307 return BytesIO(b"This is a byte stream.")
308
309 def checkContent(self, stream, content):
310 self.assertIsNotNone(stream)
311 self.assertEqual(stream.read(), content)
312 stream.close()
313
314
315 def test_byte_stream(self):
316 # If the source is an InputSource that does not have a character
317 # stream but does have a byte stream, use the byte stream.
318 src = InputSource(self.file)
319 src.setByteStream(self.make_byte_stream())
320 prep = prepare_input_source(src)
321 self.assertIsNone(prep.getCharacterStream())
322 self.checkContent(prep.getByteStream(),
323 b"This is a byte stream.")
324
325 def test_system_id(self):
326 # If the source is an InputSource that has neither a character
327 # stream nor a byte stream, open the system ID.
328 src = InputSource(self.file)
329 prep = prepare_input_source(src)
330 self.assertIsNone(prep.getCharacterStream())
331 self.checkContent(prep.getByteStream(),
332 b"This was read from a file.")
333
334 def test_string(self):
335 # If the source is a string, use it as a system ID and open it.
336 prep = prepare_input_source(self.file)
337 self.assertIsNone(prep.getCharacterStream())
338 self.checkContent(prep.getByteStream(),
339 b"This was read from a file.")
340
341 def test_binary_file(self):
342 # If the source is a binary file-like object, use it as a byte
343 # stream.
344 prep = prepare_input_source(self.make_byte_stream())
345 self.assertIsNone(prep.getCharacterStream())
346 self.checkContent(prep.getByteStream(),
347 b"This is a byte stream.")
348
349
Lars Gustäbel96753b32000-09-24 12:24:24 +0000350# ===== XMLGenerator
351
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200352class XmlgenTest:
Guido van Rossumd8faa362007-04-27 19:54:29 +0000353 def test_xmlgen_basic(self):
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200354 result = self.ioclass()
Guido van Rossumd8faa362007-04-27 19:54:29 +0000355 gen = XMLGenerator(result)
356 gen.startDocument()
357 gen.startElement("doc", {})
358 gen.endElement("doc")
359 gen.endDocument()
Lars Gustäbel96753b32000-09-24 12:24:24 +0000360
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200361 self.assertEqual(result.getvalue(), self.xml("<doc></doc>"))
Lars Gustäbel96753b32000-09-24 12:24:24 +0000362
R. David Murraya90032a2010-10-17 22:46:45 +0000363 def test_xmlgen_basic_empty(self):
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200364 result = self.ioclass()
R. David Murraya90032a2010-10-17 22:46:45 +0000365 gen = XMLGenerator(result, short_empty_elements=True)
366 gen.startDocument()
367 gen.startElement("doc", {})
368 gen.endElement("doc")
369 gen.endDocument()
370
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200371 self.assertEqual(result.getvalue(), self.xml("<doc/>"))
R. David Murraya90032a2010-10-17 22:46:45 +0000372
Guido van Rossumd8faa362007-04-27 19:54:29 +0000373 def test_xmlgen_content(self):
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200374 result = self.ioclass()
Guido van Rossumd8faa362007-04-27 19:54:29 +0000375 gen = XMLGenerator(result)
Fred Drake004d5e62000-10-23 17:22:08 +0000376
Guido van Rossumd8faa362007-04-27 19:54:29 +0000377 gen.startDocument()
378 gen.startElement("doc", {})
379 gen.characters("huhei")
380 gen.endElement("doc")
381 gen.endDocument()
Lars Gustäbel96753b32000-09-24 12:24:24 +0000382
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200383 self.assertEqual(result.getvalue(), self.xml("<doc>huhei</doc>"))
Lars Gustäbel96753b32000-09-24 12:24:24 +0000384
R. David Murraya90032a2010-10-17 22:46:45 +0000385 def test_xmlgen_content_empty(self):
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200386 result = self.ioclass()
R. David Murraya90032a2010-10-17 22:46:45 +0000387 gen = XMLGenerator(result, short_empty_elements=True)
388
389 gen.startDocument()
390 gen.startElement("doc", {})
391 gen.characters("huhei")
392 gen.endElement("doc")
393 gen.endDocument()
394
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200395 self.assertEqual(result.getvalue(), self.xml("<doc>huhei</doc>"))
R. David Murraya90032a2010-10-17 22:46:45 +0000396
Guido van Rossumd8faa362007-04-27 19:54:29 +0000397 def test_xmlgen_pi(self):
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200398 result = self.ioclass()
Guido van Rossumd8faa362007-04-27 19:54:29 +0000399 gen = XMLGenerator(result)
Fred Drake004d5e62000-10-23 17:22:08 +0000400
Guido van Rossumd8faa362007-04-27 19:54:29 +0000401 gen.startDocument()
402 gen.processingInstruction("test", "data")
403 gen.startElement("doc", {})
404 gen.endElement("doc")
405 gen.endDocument()
Lars Gustäbel96753b32000-09-24 12:24:24 +0000406
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200407 self.assertEqual(result.getvalue(),
408 self.xml("<?test data?><doc></doc>"))
Lars Gustäbel96753b32000-09-24 12:24:24 +0000409
Guido van Rossumd8faa362007-04-27 19:54:29 +0000410 def test_xmlgen_content_escape(self):
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200411 result = self.ioclass()
Guido van Rossumd8faa362007-04-27 19:54:29 +0000412 gen = XMLGenerator(result)
Fred Drake004d5e62000-10-23 17:22:08 +0000413
Guido van Rossumd8faa362007-04-27 19:54:29 +0000414 gen.startDocument()
415 gen.startElement("doc", {})
416 gen.characters("<huhei&")
417 gen.endElement("doc")
418 gen.endDocument()
Lars Gustäbel96753b32000-09-24 12:24:24 +0000419
Ezio Melottib3aedd42010-11-20 19:04:17 +0000420 self.assertEqual(result.getvalue(),
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200421 self.xml("<doc>&lt;huhei&amp;</doc>"))
Lars Gustäbel96753b32000-09-24 12:24:24 +0000422
Guido van Rossumd8faa362007-04-27 19:54:29 +0000423 def test_xmlgen_attr_escape(self):
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200424 result = self.ioclass()
Guido van Rossumd8faa362007-04-27 19:54:29 +0000425 gen = XMLGenerator(result)
Fred Drakec9fadf92001-08-07 19:17:06 +0000426
Guido van Rossumd8faa362007-04-27 19:54:29 +0000427 gen.startDocument()
428 gen.startElement("doc", {"a": '"'})
429 gen.startElement("e", {"a": "'"})
430 gen.endElement("e")
431 gen.startElement("e", {"a": "'\""})
432 gen.endElement("e")
433 gen.startElement("e", {"a": "\n\r\t"})
434 gen.endElement("e")
435 gen.endElement("doc")
436 gen.endDocument()
Fred Drakec9fadf92001-08-07 19:17:06 +0000437
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200438 self.assertEqual(result.getvalue(), self.xml(
439 "<doc a='\"'><e a=\"'\"></e>"
440 "<e a=\"'&quot;\"></e>"
441 "<e a=\"&#10;&#13;&#9;\"></e></doc>"))
442
443 def test_xmlgen_encoding(self):
444 encodings = ('iso-8859-15', 'utf-8', 'utf-8-sig',
445 'utf-16', 'utf-16be', 'utf-16le',
446 'utf-32', 'utf-32be', 'utf-32le')
447 for encoding in encodings:
448 result = self.ioclass()
449 gen = XMLGenerator(result, encoding=encoding)
450
451 gen.startDocument()
452 gen.startElement("doc", {"a": '\u20ac'})
453 gen.characters("\u20ac")
454 gen.endElement("doc")
455 gen.endDocument()
456
457 self.assertEqual(result.getvalue(),
458 self.xml('<doc a="\u20ac">\u20ac</doc>', encoding=encoding))
459
460 def test_xmlgen_unencodable(self):
461 result = self.ioclass()
462 gen = XMLGenerator(result, encoding='ascii')
463
464 gen.startDocument()
465 gen.startElement("doc", {"a": '\u20ac'})
466 gen.characters("\u20ac")
467 gen.endElement("doc")
468 gen.endDocument()
469
470 self.assertEqual(result.getvalue(),
471 self.xml('<doc a="&#8364;">&#8364;</doc>', encoding='ascii'))
Fred Drakec9fadf92001-08-07 19:17:06 +0000472
Guido van Rossumd8faa362007-04-27 19:54:29 +0000473 def test_xmlgen_ignorable(self):
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200474 result = self.ioclass()
Guido van Rossumd8faa362007-04-27 19:54:29 +0000475 gen = XMLGenerator(result)
Fred Drake004d5e62000-10-23 17:22:08 +0000476
Guido van Rossumd8faa362007-04-27 19:54:29 +0000477 gen.startDocument()
478 gen.startElement("doc", {})
479 gen.ignorableWhitespace(" ")
480 gen.endElement("doc")
481 gen.endDocument()
Lars Gustäbel96753b32000-09-24 12:24:24 +0000482
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200483 self.assertEqual(result.getvalue(), self.xml("<doc> </doc>"))
Lars Gustäbel96753b32000-09-24 12:24:24 +0000484
R. David Murraya90032a2010-10-17 22:46:45 +0000485 def test_xmlgen_ignorable_empty(self):
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200486 result = self.ioclass()
R. David Murraya90032a2010-10-17 22:46:45 +0000487 gen = XMLGenerator(result, short_empty_elements=True)
488
489 gen.startDocument()
490 gen.startElement("doc", {})
491 gen.ignorableWhitespace(" ")
492 gen.endElement("doc")
493 gen.endDocument()
494
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200495 self.assertEqual(result.getvalue(), self.xml("<doc> </doc>"))
R. David Murraya90032a2010-10-17 22:46:45 +0000496
Serhiy Storchaka3eab6b32013-05-12 17:31:16 +0300497 def test_xmlgen_encoding_bytes(self):
498 encodings = ('iso-8859-15', 'utf-8', 'utf-8-sig',
499 'utf-16', 'utf-16be', 'utf-16le',
500 'utf-32', 'utf-32be', 'utf-32le')
501 for encoding in encodings:
502 result = self.ioclass()
503 gen = XMLGenerator(result, encoding=encoding)
504
505 gen.startDocument()
506 gen.startElement("doc", {"a": '\u20ac'})
507 gen.characters("\u20ac".encode(encoding))
508 gen.ignorableWhitespace(" ".encode(encoding))
509 gen.endElement("doc")
510 gen.endDocument()
511
512 self.assertEqual(result.getvalue(),
513 self.xml('<doc a="\u20ac">\u20ac </doc>', encoding=encoding))
514
Guido van Rossumd8faa362007-04-27 19:54:29 +0000515 def test_xmlgen_ns(self):
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200516 result = self.ioclass()
Guido van Rossumd8faa362007-04-27 19:54:29 +0000517 gen = XMLGenerator(result)
Lars Gustäbel96753b32000-09-24 12:24:24 +0000518
Guido van Rossumd8faa362007-04-27 19:54:29 +0000519 gen.startDocument()
520 gen.startPrefixMapping("ns1", ns_uri)
521 gen.startElementNS((ns_uri, "doc"), "ns1:doc", {})
522 # add an unqualified name
523 gen.startElementNS((None, "udoc"), None, {})
524 gen.endElementNS((None, "udoc"), None)
525 gen.endElementNS((ns_uri, "doc"), "ns1:doc")
526 gen.endPrefixMapping("ns1")
527 gen.endDocument()
Fred Drake004d5e62000-10-23 17:22:08 +0000528
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200529 self.assertEqual(result.getvalue(), self.xml(
530 '<ns1:doc xmlns:ns1="%s"><udoc></udoc></ns1:doc>' %
Guido van Rossumd8faa362007-04-27 19:54:29 +0000531 ns_uri))
Lars Gustäbel96753b32000-09-24 12:24:24 +0000532
R. David Murraya90032a2010-10-17 22:46:45 +0000533 def test_xmlgen_ns_empty(self):
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200534 result = self.ioclass()
R. David Murraya90032a2010-10-17 22:46:45 +0000535 gen = XMLGenerator(result, short_empty_elements=True)
536
537 gen.startDocument()
538 gen.startPrefixMapping("ns1", ns_uri)
539 gen.startElementNS((ns_uri, "doc"), "ns1:doc", {})
540 # add an unqualified name
541 gen.startElementNS((None, "udoc"), None, {})
542 gen.endElementNS((None, "udoc"), None)
543 gen.endElementNS((ns_uri, "doc"), "ns1:doc")
544 gen.endPrefixMapping("ns1")
545 gen.endDocument()
546
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200547 self.assertEqual(result.getvalue(), self.xml(
548 '<ns1:doc xmlns:ns1="%s"><udoc/></ns1:doc>' %
R. David Murraya90032a2010-10-17 22:46:45 +0000549 ns_uri))
550
Guido van Rossumd8faa362007-04-27 19:54:29 +0000551 def test_1463026_1(self):
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200552 result = self.ioclass()
Guido van Rossumd8faa362007-04-27 19:54:29 +0000553 gen = XMLGenerator(result)
Thomas Wouterscf297e42007-02-23 15:07:44 +0000554
Guido van Rossumd8faa362007-04-27 19:54:29 +0000555 gen.startDocument()
556 gen.startElementNS((None, 'a'), 'a', {(None, 'b'):'c'})
557 gen.endElementNS((None, 'a'), 'a')
558 gen.endDocument()
Thomas Wouterscf297e42007-02-23 15:07:44 +0000559
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200560 self.assertEqual(result.getvalue(), self.xml('<a b="c"></a>'))
Thomas Wouterscf297e42007-02-23 15:07:44 +0000561
R. David Murraya90032a2010-10-17 22:46:45 +0000562 def test_1463026_1_empty(self):
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200563 result = self.ioclass()
R. David Murraya90032a2010-10-17 22:46:45 +0000564 gen = XMLGenerator(result, short_empty_elements=True)
565
566 gen.startDocument()
567 gen.startElementNS((None, 'a'), 'a', {(None, 'b'):'c'})
568 gen.endElementNS((None, 'a'), 'a')
569 gen.endDocument()
570
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200571 self.assertEqual(result.getvalue(), self.xml('<a b="c"/>'))
R. David Murraya90032a2010-10-17 22:46:45 +0000572
Guido van Rossumd8faa362007-04-27 19:54:29 +0000573 def test_1463026_2(self):
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200574 result = self.ioclass()
Guido van Rossumd8faa362007-04-27 19:54:29 +0000575 gen = XMLGenerator(result)
Thomas Wouterscf297e42007-02-23 15:07:44 +0000576
Guido van Rossumd8faa362007-04-27 19:54:29 +0000577 gen.startDocument()
578 gen.startPrefixMapping(None, 'qux')
579 gen.startElementNS(('qux', 'a'), 'a', {})
580 gen.endElementNS(('qux', 'a'), 'a')
581 gen.endPrefixMapping(None)
582 gen.endDocument()
Thomas Wouterscf297e42007-02-23 15:07:44 +0000583
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200584 self.assertEqual(result.getvalue(), self.xml('<a xmlns="qux"></a>'))
Thomas Wouterscf297e42007-02-23 15:07:44 +0000585
R. David Murraya90032a2010-10-17 22:46:45 +0000586 def test_1463026_2_empty(self):
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200587 result = self.ioclass()
R. David Murraya90032a2010-10-17 22:46:45 +0000588 gen = XMLGenerator(result, short_empty_elements=True)
589
590 gen.startDocument()
591 gen.startPrefixMapping(None, 'qux')
592 gen.startElementNS(('qux', 'a'), 'a', {})
593 gen.endElementNS(('qux', 'a'), 'a')
594 gen.endPrefixMapping(None)
595 gen.endDocument()
596
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200597 self.assertEqual(result.getvalue(), self.xml('<a xmlns="qux"/>'))
R. David Murraya90032a2010-10-17 22:46:45 +0000598
Guido van Rossumd8faa362007-04-27 19:54:29 +0000599 def test_1463026_3(self):
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200600 result = self.ioclass()
Guido van Rossumd8faa362007-04-27 19:54:29 +0000601 gen = XMLGenerator(result)
Thomas Wouterscf297e42007-02-23 15:07:44 +0000602
Guido van Rossumd8faa362007-04-27 19:54:29 +0000603 gen.startDocument()
604 gen.startPrefixMapping('my', 'qux')
605 gen.startElementNS(('qux', 'a'), 'a', {(None, 'b'):'c'})
606 gen.endElementNS(('qux', 'a'), 'a')
607 gen.endPrefixMapping('my')
608 gen.endDocument()
Thomas Wouterscf297e42007-02-23 15:07:44 +0000609
Ezio Melottib3aedd42010-11-20 19:04:17 +0000610 self.assertEqual(result.getvalue(),
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200611 self.xml('<my:a xmlns:my="qux" b="c"></my:a>'))
Lars Gustäbel96753b32000-09-24 12:24:24 +0000612
R. David Murraya90032a2010-10-17 22:46:45 +0000613 def test_1463026_3_empty(self):
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200614 result = self.ioclass()
R. David Murraya90032a2010-10-17 22:46:45 +0000615 gen = XMLGenerator(result, short_empty_elements=True)
616
617 gen.startDocument()
618 gen.startPrefixMapping('my', 'qux')
619 gen.startElementNS(('qux', 'a'), 'a', {(None, 'b'):'c'})
620 gen.endElementNS(('qux', 'a'), 'a')
621 gen.endPrefixMapping('my')
622 gen.endDocument()
623
Ezio Melottib3aedd42010-11-20 19:04:17 +0000624 self.assertEqual(result.getvalue(),
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200625 self.xml('<my:a xmlns:my="qux" b="c"/>'))
R. David Murraya90032a2010-10-17 22:46:45 +0000626
Antoine Pitrou6b03ee62010-10-27 18:33:30 +0000627 def test_5027_1(self):
628 # The xml prefix (as in xml:lang below) is reserved and bound by
629 # definition to http://www.w3.org/XML/1998/namespace. XMLGenerator had
Andrew Svetlov737fb892012-12-18 21:14:22 +0200630 # a bug whereby a KeyError is raised because this namespace is missing
Antoine Pitrou6b03ee62010-10-27 18:33:30 +0000631 # from a dictionary.
632 #
633 # This test demonstrates the bug by parsing a document.
634 test_xml = StringIO(
635 '<?xml version="1.0"?>'
636 '<a:g1 xmlns:a="http://example.com/ns">'
637 '<a:g2 xml:lang="en">Hello</a:g2>'
638 '</a:g1>')
639
640 parser = make_parser()
641 parser.setFeature(feature_namespaces, True)
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200642 result = self.ioclass()
Antoine Pitrou6b03ee62010-10-27 18:33:30 +0000643 gen = XMLGenerator(result)
644 parser.setContentHandler(gen)
645 parser.parse(test_xml)
646
Ezio Melottib3aedd42010-11-20 19:04:17 +0000647 self.assertEqual(result.getvalue(),
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200648 self.xml(
Ezio Melottib3aedd42010-11-20 19:04:17 +0000649 '<a:g1 xmlns:a="http://example.com/ns">'
650 '<a:g2 xml:lang="en">Hello</a:g2>'
651 '</a:g1>'))
Antoine Pitrou6b03ee62010-10-27 18:33:30 +0000652
653 def test_5027_2(self):
654 # The xml prefix (as in xml:lang below) is reserved and bound by
655 # definition to http://www.w3.org/XML/1998/namespace. XMLGenerator had
Andrew Svetlov737fb892012-12-18 21:14:22 +0200656 # a bug whereby a KeyError is raised because this namespace is missing
Antoine Pitrou6b03ee62010-10-27 18:33:30 +0000657 # from a dictionary.
658 #
659 # This test demonstrates the bug by direct manipulation of the
660 # XMLGenerator.
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200661 result = self.ioclass()
Antoine Pitrou6b03ee62010-10-27 18:33:30 +0000662 gen = XMLGenerator(result)
663
664 gen.startDocument()
665 gen.startPrefixMapping('a', 'http://example.com/ns')
666 gen.startElementNS(('http://example.com/ns', 'g1'), 'g1', {})
667 lang_attr = {('http://www.w3.org/XML/1998/namespace', 'lang'): 'en'}
668 gen.startElementNS(('http://example.com/ns', 'g2'), 'g2', lang_attr)
669 gen.characters('Hello')
670 gen.endElementNS(('http://example.com/ns', 'g2'), 'g2')
671 gen.endElementNS(('http://example.com/ns', 'g1'), 'g1')
672 gen.endPrefixMapping('a')
673 gen.endDocument()
674
Ezio Melottib3aedd42010-11-20 19:04:17 +0000675 self.assertEqual(result.getvalue(),
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200676 self.xml(
Ezio Melottib3aedd42010-11-20 19:04:17 +0000677 '<a:g1 xmlns:a="http://example.com/ns">'
678 '<a:g2 xml:lang="en">Hello</a:g2>'
679 '</a:g1>'))
Antoine Pitrou6b03ee62010-10-27 18:33:30 +0000680
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200681 def test_no_close_file(self):
682 result = self.ioclass()
683 def func(out):
684 gen = XMLGenerator(out)
685 gen.startDocument()
686 gen.startElement("doc", {})
687 func(result)
688 self.assertFalse(result.closed)
689
Serhiy Storchakaa5f13d22013-02-25 13:46:10 +0200690 def test_xmlgen_fragment(self):
691 result = self.ioclass()
692 gen = XMLGenerator(result)
693
694 # Don't call gen.startDocument()
695 gen.startElement("foo", {"a": "1.0"})
696 gen.characters("Hello")
697 gen.endElement("foo")
698 gen.startElement("bar", {"b": "2.0"})
699 gen.endElement("bar")
700 # Don't call gen.endDocument()
701
702 self.assertEqual(result.getvalue(),
703 self.xml('<foo a="1.0">Hello</foo><bar b="2.0"></bar>')[len(self.xml('')):])
704
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200705class StringXmlgenTest(XmlgenTest, unittest.TestCase):
706 ioclass = StringIO
707
708 def xml(self, doc, encoding='iso-8859-1'):
709 return '<?xml version="1.0" encoding="%s"?>\n%s' % (encoding, doc)
710
711 test_xmlgen_unencodable = None
712
713class BytesXmlgenTest(XmlgenTest, unittest.TestCase):
714 ioclass = BytesIO
715
716 def xml(self, doc, encoding='iso-8859-1'):
717 return ('<?xml version="1.0" encoding="%s"?>\n%s' %
718 (encoding, doc)).encode(encoding, 'xmlcharrefreplace')
719
720class WriterXmlgenTest(BytesXmlgenTest):
721 class ioclass(list):
722 write = list.append
723 closed = False
724
725 def seekable(self):
726 return True
727
728 def tell(self):
729 # return 0 at start and not 0 after start
730 return len(self)
731
732 def getvalue(self):
733 return b''.join(self)
734
Georg Brandlc502df42013-05-12 11:41:12 +0200735class StreamWriterXmlgenTest(XmlgenTest, unittest.TestCase):
736 def ioclass(self):
737 raw = BytesIO()
738 writer = codecs.getwriter('ascii')(raw, 'xmlcharrefreplace')
739 writer.getvalue = raw.getvalue
740 return writer
741
742 def xml(self, doc, encoding='iso-8859-1'):
743 return ('<?xml version="1.0" encoding="%s"?>\n%s' %
744 (encoding, doc)).encode('ascii', 'xmlcharrefreplace')
745
746class StreamReaderWriterXmlgenTest(XmlgenTest, unittest.TestCase):
747 fname = support.TESTFN + '-codecs'
748
749 def ioclass(self):
750 writer = codecs.open(self.fname, 'w', encoding='ascii',
751 errors='xmlcharrefreplace', buffering=0)
Antoine Pitrou2adb6fe2013-05-13 22:34:21 +0200752 def cleanup():
753 writer.close()
754 support.unlink(self.fname)
755 self.addCleanup(cleanup)
Richard Oudkerk90a24272013-05-18 18:11:30 +0100756 def getvalue():
757 # Windows will not let use reopen without first closing
758 writer.close()
759 with open(writer.name, 'rb') as f:
760 return f.read()
761 writer.getvalue = getvalue
Georg Brandlc502df42013-05-12 11:41:12 +0200762 return writer
763
Georg Brandlc502df42013-05-12 11:41:12 +0200764 def xml(self, doc, encoding='iso-8859-1'):
765 return ('<?xml version="1.0" encoding="%s"?>\n%s' %
766 (encoding, doc)).encode('ascii', 'xmlcharrefreplace')
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200767
768start = b'<?xml version="1.0" encoding="iso-8859-1"?>\n'
769
Fred Drake004d5e62000-10-23 17:22:08 +0000770
Guido van Rossumd8faa362007-04-27 19:54:29 +0000771class XMLFilterBaseTest(unittest.TestCase):
772 def test_filter_basic(self):
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200773 result = BytesIO()
Guido van Rossumd8faa362007-04-27 19:54:29 +0000774 gen = XMLGenerator(result)
775 filter = XMLFilterBase()
776 filter.setContentHandler(gen)
Lars Gustäbel96753b32000-09-24 12:24:24 +0000777
Guido van Rossumd8faa362007-04-27 19:54:29 +0000778 filter.startDocument()
779 filter.startElement("doc", {})
780 filter.characters("content")
781 filter.ignorableWhitespace(" ")
782 filter.endElement("doc")
783 filter.endDocument()
784
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200785 self.assertEqual(result.getvalue(), start + b"<doc>content </doc>")
Lars Gustäbel96753b32000-09-24 12:24:24 +0000786
787# ===========================================================================
788#
789# expatreader tests
790#
791# ===========================================================================
792
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200793with open(TEST_XMLFILE_OUT, 'rb') as f:
Benjamin Petersond5df36d2010-10-31 18:23:23 +0000794 xml_test_out = f.read()
Lars Gustäbelb7536d52000-09-24 18:53:56 +0000795
Guido van Rossumd8faa362007-04-27 19:54:29 +0000796class ExpatReaderTest(XmlTestBase):
Lars Gustäbelb7536d52000-09-24 18:53:56 +0000797
Guido van Rossumd8faa362007-04-27 19:54:29 +0000798 # ===== XMLReader support
Lars Gustäbelb7536d52000-09-24 18:53:56 +0000799
Serhiy Storchakaaa9563c2015-04-02 20:55:59 +0300800 def test_expat_binary_file(self):
Guido van Rossumd8faa362007-04-27 19:54:29 +0000801 parser = create_parser()
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200802 result = BytesIO()
Guido van Rossumd8faa362007-04-27 19:54:29 +0000803 xmlgen = XMLGenerator(result)
Lars Gustäbelb7536d52000-09-24 18:53:56 +0000804
Guido van Rossumd8faa362007-04-27 19:54:29 +0000805 parser.setContentHandler(xmlgen)
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200806 with open(TEST_XMLFILE, 'rb') as f:
Benjamin Petersond5df36d2010-10-31 18:23:23 +0000807 parser.parse(f)
Lars Gustäbelb7536d52000-09-24 18:53:56 +0000808
Ezio Melottib3aedd42010-11-20 19:04:17 +0000809 self.assertEqual(result.getvalue(), xml_test_out)
Lars Gustäbelb7536d52000-09-24 18:53:56 +0000810
Serhiy Storchakaaa9563c2015-04-02 20:55:59 +0300811 def test_expat_text_file(self):
812 parser = create_parser()
813 result = BytesIO()
814 xmlgen = XMLGenerator(result)
815
816 parser.setContentHandler(xmlgen)
817 with open(TEST_XMLFILE, 'rt', encoding='iso-8859-1') as f:
818 parser.parse(f)
819
820 self.assertEqual(result.getvalue(), xml_test_out)
821
Serhiy Storchaka1a4ed4c2013-02-02 12:17:05 +0200822 @requires_nonascii_filenames
Serhiy Storchakaaa9563c2015-04-02 20:55:59 +0300823 def test_expat_binary_file_nonascii(self):
Serhiy Storchakad5202392013-02-02 10:31:17 +0200824 fname = support.TESTFN_UNICODE
825 shutil.copyfile(TEST_XMLFILE, fname)
826 self.addCleanup(support.unlink, fname)
827
828 parser = create_parser()
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200829 result = BytesIO()
Serhiy Storchakad5202392013-02-02 10:31:17 +0200830 xmlgen = XMLGenerator(result)
831
832 parser.setContentHandler(xmlgen)
Serhiy Storchakaaa9563c2015-04-02 20:55:59 +0300833 parser.parse(open(fname, 'rb'))
Serhiy Storchakad5202392013-02-02 10:31:17 +0200834
835 self.assertEqual(result.getvalue(), xml_test_out)
836
Serhiy Storchakafc8e9b02014-11-27 22:13:16 +0200837 def test_expat_binary_file_bytes_name(self):
838 fname = os.fsencode(TEST_XMLFILE)
839 parser = create_parser()
840 result = BytesIO()
841 xmlgen = XMLGenerator(result)
842
843 parser.setContentHandler(xmlgen)
844 with open(fname, 'rb') as f:
845 parser.parse(f)
846
847 self.assertEqual(result.getvalue(), xml_test_out)
848
849 def test_expat_binary_file_int_name(self):
850 parser = create_parser()
851 result = BytesIO()
852 xmlgen = XMLGenerator(result)
853
854 parser.setContentHandler(xmlgen)
855 with open(TEST_XMLFILE, 'rb') as f:
856 with open(f.fileno(), 'rb', closefd=False) as f2:
857 parser.parse(f2)
858
859 self.assertEqual(result.getvalue(), xml_test_out)
860
Guido van Rossumd8faa362007-04-27 19:54:29 +0000861 # ===== DTDHandler support
Lars Gustäbelb7536d52000-09-24 18:53:56 +0000862
Guido van Rossumd8faa362007-04-27 19:54:29 +0000863 class TestDTDHandler:
Lars Gustäbelb7536d52000-09-24 18:53:56 +0000864
Guido van Rossumd8faa362007-04-27 19:54:29 +0000865 def __init__(self):
866 self._notations = []
867 self._entities = []
Lars Gustäbelb7536d52000-09-24 18:53:56 +0000868
Guido van Rossumd8faa362007-04-27 19:54:29 +0000869 def notationDecl(self, name, publicId, systemId):
870 self._notations.append((name, publicId, systemId))
Lars Gustäbelb7536d52000-09-24 18:53:56 +0000871
Guido van Rossumd8faa362007-04-27 19:54:29 +0000872 def unparsedEntityDecl(self, name, publicId, systemId, ndata):
873 self._entities.append((name, publicId, systemId, ndata))
Lars Gustäbel2fc52942000-10-24 15:35:07 +0000874
Guido van Rossumd8faa362007-04-27 19:54:29 +0000875 def test_expat_dtdhandler(self):
876 parser = create_parser()
877 handler = self.TestDTDHandler()
878 parser.setDTDHandler(handler)
Lars Gustäbel2fc52942000-10-24 15:35:07 +0000879
Guido van Rossumd8faa362007-04-27 19:54:29 +0000880 parser.feed('<!DOCTYPE doc [\n')
881 parser.feed(' <!ENTITY img SYSTEM "expat.gif" NDATA GIF>\n')
882 parser.feed(' <!NOTATION GIF PUBLIC "-//CompuServe//NOTATION Graphics Interchange Format 89a//EN">\n')
883 parser.feed(']>\n')
884 parser.feed('<doc></doc>')
885 parser.close()
Lars Gustäbel2fc52942000-10-24 15:35:07 +0000886
Ezio Melottib3aedd42010-11-20 19:04:17 +0000887 self.assertEqual(handler._notations,
Guido van Rossumd8faa362007-04-27 19:54:29 +0000888 [("GIF", "-//CompuServe//NOTATION Graphics Interchange Format 89a//EN", None)])
Ezio Melottib3aedd42010-11-20 19:04:17 +0000889 self.assertEqual(handler._entities, [("img", None, "expat.gif", "GIF")])
Lars Gustäbel2fc52942000-10-24 15:35:07 +0000890
Guido van Rossumd8faa362007-04-27 19:54:29 +0000891 # ===== EntityResolver support
Lars Gustäbel2fc52942000-10-24 15:35:07 +0000892
Guido van Rossumd8faa362007-04-27 19:54:29 +0000893 class TestEntityResolver:
Lars Gustäbel2fc52942000-10-24 15:35:07 +0000894
Guido van Rossumd8faa362007-04-27 19:54:29 +0000895 def resolveEntity(self, publicId, systemId):
896 inpsrc = InputSource()
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200897 inpsrc.setByteStream(BytesIO(b"<entity/>"))
Guido van Rossumd8faa362007-04-27 19:54:29 +0000898 return inpsrc
Lars Gustäbel2fc52942000-10-24 15:35:07 +0000899
Guido van Rossumd8faa362007-04-27 19:54:29 +0000900 def test_expat_entityresolver(self):
901 parser = create_parser()
902 parser.setEntityResolver(self.TestEntityResolver())
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200903 result = BytesIO()
Guido van Rossumd8faa362007-04-27 19:54:29 +0000904 parser.setContentHandler(XMLGenerator(result))
Lars Gustäbel2fc52942000-10-24 15:35:07 +0000905
Guido van Rossumd8faa362007-04-27 19:54:29 +0000906 parser.feed('<!DOCTYPE doc [\n')
907 parser.feed(' <!ENTITY test SYSTEM "whatever">\n')
908 parser.feed(']>\n')
909 parser.feed('<doc>&test;</doc>')
910 parser.close()
Lars Gustäbel2fc52942000-10-24 15:35:07 +0000911
Ezio Melottib3aedd42010-11-20 19:04:17 +0000912 self.assertEqual(result.getvalue(), start +
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200913 b"<doc><entity></entity></doc>")
Lars Gustäbel2fc52942000-10-24 15:35:07 +0000914
Guido van Rossumd8faa362007-04-27 19:54:29 +0000915 # ===== Attributes support
Lars Gustäbel2fc52942000-10-24 15:35:07 +0000916
Guido van Rossumd8faa362007-04-27 19:54:29 +0000917 class AttrGatherer(ContentHandler):
Lars Gustäbel2fc52942000-10-24 15:35:07 +0000918
Guido van Rossumd8faa362007-04-27 19:54:29 +0000919 def startElement(self, name, attrs):
920 self._attrs = attrs
Lars Gustäbel2fc52942000-10-24 15:35:07 +0000921
Guido van Rossumd8faa362007-04-27 19:54:29 +0000922 def startElementNS(self, name, qname, attrs):
923 self._attrs = attrs
Lars Gustäbel2fc52942000-10-24 15:35:07 +0000924
Guido van Rossumd8faa362007-04-27 19:54:29 +0000925 def test_expat_attrs_empty(self):
926 parser = create_parser()
927 gather = self.AttrGatherer()
928 parser.setContentHandler(gather)
929
930 parser.feed("<doc/>")
931 parser.close()
932
933 self.verify_empty_attrs(gather._attrs)
934
935 def test_expat_attrs_wattr(self):
936 parser = create_parser()
937 gather = self.AttrGatherer()
938 parser.setContentHandler(gather)
939
940 parser.feed("<doc attr='val'/>")
941 parser.close()
942
943 self.verify_attrs_wattr(gather._attrs)
944
945 def test_expat_nsattrs_empty(self):
946 parser = create_parser(1)
947 gather = self.AttrGatherer()
948 parser.setContentHandler(gather)
949
950 parser.feed("<doc/>")
951 parser.close()
952
953 self.verify_empty_nsattrs(gather._attrs)
954
955 def test_expat_nsattrs_wattr(self):
956 parser = create_parser(1)
957 gather = self.AttrGatherer()
958 parser.setContentHandler(gather)
959
960 parser.feed("<doc xmlns:ns='%s' ns:attr='val'/>" % ns_uri)
961 parser.close()
962
963 attrs = gather._attrs
964
Ezio Melottib3aedd42010-11-20 19:04:17 +0000965 self.assertEqual(attrs.getLength(), 1)
966 self.assertEqual(attrs.getNames(), [(ns_uri, "attr")])
Guido van Rossumd8faa362007-04-27 19:54:29 +0000967 self.assertTrue((attrs.getQNames() == [] or
968 attrs.getQNames() == ["ns:attr"]))
Ezio Melottib3aedd42010-11-20 19:04:17 +0000969 self.assertEqual(len(attrs), 1)
Benjamin Peterson577473f2010-01-19 00:09:57 +0000970 self.assertIn((ns_uri, "attr"), attrs)
Ezio Melottib3aedd42010-11-20 19:04:17 +0000971 self.assertEqual(attrs.get((ns_uri, "attr")), "val")
972 self.assertEqual(attrs.get((ns_uri, "attr"), 25), "val")
973 self.assertEqual(list(attrs.items()), [((ns_uri, "attr"), "val")])
974 self.assertEqual(list(attrs.values()), ["val"])
975 self.assertEqual(attrs.getValue((ns_uri, "attr")), "val")
976 self.assertEqual(attrs[(ns_uri, "attr")], "val")
Guido van Rossumd8faa362007-04-27 19:54:29 +0000977
978 # ===== InputSource support
979
Benjamin Petersona7f4f5a2008-09-04 02:22:52 +0000980 def test_expat_inpsource_filename(self):
Guido van Rossumd8faa362007-04-27 19:54:29 +0000981 parser = create_parser()
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200982 result = BytesIO()
Guido van Rossumd8faa362007-04-27 19:54:29 +0000983 xmlgen = XMLGenerator(result)
984
985 parser.setContentHandler(xmlgen)
Florent Xiclunaf15351d2010-03-13 23:24:31 +0000986 parser.parse(TEST_XMLFILE)
Guido van Rossumd8faa362007-04-27 19:54:29 +0000987
Ezio Melottib3aedd42010-11-20 19:04:17 +0000988 self.assertEqual(result.getvalue(), xml_test_out)
Guido van Rossumd8faa362007-04-27 19:54:29 +0000989
Benjamin Petersona7f4f5a2008-09-04 02:22:52 +0000990 def test_expat_inpsource_sysid(self):
Guido van Rossumd8faa362007-04-27 19:54:29 +0000991 parser = create_parser()
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200992 result = BytesIO()
Guido van Rossumd8faa362007-04-27 19:54:29 +0000993 xmlgen = XMLGenerator(result)
994
995 parser.setContentHandler(xmlgen)
Florent Xiclunaf15351d2010-03-13 23:24:31 +0000996 parser.parse(InputSource(TEST_XMLFILE))
Guido van Rossumd8faa362007-04-27 19:54:29 +0000997
Ezio Melottib3aedd42010-11-20 19:04:17 +0000998 self.assertEqual(result.getvalue(), xml_test_out)
Guido van Rossumd8faa362007-04-27 19:54:29 +0000999
Serhiy Storchaka1a4ed4c2013-02-02 12:17:05 +02001000 @requires_nonascii_filenames
Serhiy Storchakad5202392013-02-02 10:31:17 +02001001 def test_expat_inpsource_sysid_nonascii(self):
1002 fname = support.TESTFN_UNICODE
1003 shutil.copyfile(TEST_XMLFILE, fname)
1004 self.addCleanup(support.unlink, fname)
1005
1006 parser = create_parser()
Serhiy Storchaka88efc522013-02-10 14:29:52 +02001007 result = BytesIO()
Serhiy Storchakad5202392013-02-02 10:31:17 +02001008 xmlgen = XMLGenerator(result)
1009
1010 parser.setContentHandler(xmlgen)
1011 parser.parse(InputSource(fname))
1012
1013 self.assertEqual(result.getvalue(), xml_test_out)
1014
Serhiy Storchakaaa9563c2015-04-02 20:55:59 +03001015 def test_expat_inpsource_byte_stream(self):
Guido van Rossumd8faa362007-04-27 19:54:29 +00001016 parser = create_parser()
Serhiy Storchaka88efc522013-02-10 14:29:52 +02001017 result = BytesIO()
Guido van Rossumd8faa362007-04-27 19:54:29 +00001018 xmlgen = XMLGenerator(result)
1019
1020 parser.setContentHandler(xmlgen)
1021 inpsrc = InputSource()
Serhiy Storchaka88efc522013-02-10 14:29:52 +02001022 with open(TEST_XMLFILE, 'rb') as f:
Benjamin Petersond5df36d2010-10-31 18:23:23 +00001023 inpsrc.setByteStream(f)
1024 parser.parse(inpsrc)
Guido van Rossumd8faa362007-04-27 19:54:29 +00001025
Ezio Melottib3aedd42010-11-20 19:04:17 +00001026 self.assertEqual(result.getvalue(), xml_test_out)
Guido van Rossumd8faa362007-04-27 19:54:29 +00001027
1028 # ===== IncrementalParser support
1029
1030 def test_expat_incremental(self):
Serhiy Storchaka88efc522013-02-10 14:29:52 +02001031 result = BytesIO()
Guido van Rossumd8faa362007-04-27 19:54:29 +00001032 xmlgen = XMLGenerator(result)
1033 parser = create_parser()
1034 parser.setContentHandler(xmlgen)
1035
1036 parser.feed("<doc>")
1037 parser.feed("</doc>")
1038 parser.close()
1039
Serhiy Storchaka88efc522013-02-10 14:29:52 +02001040 self.assertEqual(result.getvalue(), start + b"<doc></doc>")
Guido van Rossumd8faa362007-04-27 19:54:29 +00001041
1042 def test_expat_incremental_reset(self):
Serhiy Storchaka88efc522013-02-10 14:29:52 +02001043 result = BytesIO()
Guido van Rossumd8faa362007-04-27 19:54:29 +00001044 xmlgen = XMLGenerator(result)
1045 parser = create_parser()
1046 parser.setContentHandler(xmlgen)
1047
1048 parser.feed("<doc>")
1049 parser.feed("text")
1050
Serhiy Storchaka88efc522013-02-10 14:29:52 +02001051 result = BytesIO()
Guido van Rossumd8faa362007-04-27 19:54:29 +00001052 xmlgen = XMLGenerator(result)
1053 parser.setContentHandler(xmlgen)
1054 parser.reset()
1055
1056 parser.feed("<doc>")
1057 parser.feed("text")
1058 parser.feed("</doc>")
1059 parser.close()
1060
Serhiy Storchaka88efc522013-02-10 14:29:52 +02001061 self.assertEqual(result.getvalue(), start + b"<doc>text</doc>")
Guido van Rossumd8faa362007-04-27 19:54:29 +00001062
1063 # ===== Locator support
1064
1065 def test_expat_locator_noinfo(self):
Serhiy Storchaka88efc522013-02-10 14:29:52 +02001066 result = BytesIO()
Guido van Rossumd8faa362007-04-27 19:54:29 +00001067 xmlgen = XMLGenerator(result)
1068 parser = create_parser()
1069 parser.setContentHandler(xmlgen)
1070
1071 parser.feed("<doc>")
1072 parser.feed("</doc>")
1073 parser.close()
1074
Ezio Melottib3aedd42010-11-20 19:04:17 +00001075 self.assertEqual(parser.getSystemId(), None)
1076 self.assertEqual(parser.getPublicId(), None)
1077 self.assertEqual(parser.getLineNumber(), 1)
Guido van Rossumd8faa362007-04-27 19:54:29 +00001078
Benjamin Petersona7f4f5a2008-09-04 02:22:52 +00001079 def test_expat_locator_withinfo(self):
Serhiy Storchaka88efc522013-02-10 14:29:52 +02001080 result = BytesIO()
Guido van Rossumd8faa362007-04-27 19:54:29 +00001081 xmlgen = XMLGenerator(result)
1082 parser = create_parser()
1083 parser.setContentHandler(xmlgen)
Florent Xiclunaf15351d2010-03-13 23:24:31 +00001084 parser.parse(TEST_XMLFILE)
Guido van Rossumd8faa362007-04-27 19:54:29 +00001085
Ezio Melottib3aedd42010-11-20 19:04:17 +00001086 self.assertEqual(parser.getSystemId(), TEST_XMLFILE)
1087 self.assertEqual(parser.getPublicId(), None)
Lars Gustäbel2fc52942000-10-24 15:35:07 +00001088
Serhiy Storchaka1a4ed4c2013-02-02 12:17:05 +02001089 @requires_nonascii_filenames
Serhiy Storchakad5202392013-02-02 10:31:17 +02001090 def test_expat_locator_withinfo_nonascii(self):
1091 fname = support.TESTFN_UNICODE
1092 shutil.copyfile(TEST_XMLFILE, fname)
1093 self.addCleanup(support.unlink, fname)
1094
Serhiy Storchaka88efc522013-02-10 14:29:52 +02001095 result = BytesIO()
Serhiy Storchakad5202392013-02-02 10:31:17 +02001096 xmlgen = XMLGenerator(result)
1097 parser = create_parser()
1098 parser.setContentHandler(xmlgen)
1099 parser.parse(fname)
1100
1101 self.assertEqual(parser.getSystemId(), fname)
1102 self.assertEqual(parser.getPublicId(), None)
1103
Martin v. Löwis80670bc2000-10-06 21:13:23 +00001104
1105# ===========================================================================
1106#
1107# error reporting
1108#
1109# ===========================================================================
1110
Guido van Rossumd8faa362007-04-27 19:54:29 +00001111class ErrorReportingTest(unittest.TestCase):
1112 def test_expat_inpsource_location(self):
1113 parser = create_parser()
1114 parser.setContentHandler(ContentHandler()) # do nothing
1115 source = InputSource()
Serhiy Storchaka88efc522013-02-10 14:29:52 +02001116 source.setByteStream(BytesIO(b"<foo bar foobar>")) #ill-formed
Guido van Rossumd8faa362007-04-27 19:54:29 +00001117 name = "a file name"
1118 source.setSystemId(name)
1119 try:
1120 parser.parse(source)
1121 self.fail()
1122 except SAXException as e:
Ezio Melottib3aedd42010-11-20 19:04:17 +00001123 self.assertEqual(e.getSystemId(), name)
Martin v. Löwis80670bc2000-10-06 21:13:23 +00001124
Guido van Rossumd8faa362007-04-27 19:54:29 +00001125 def test_expat_incomplete(self):
1126 parser = create_parser()
1127 parser.setContentHandler(ContentHandler()) # do nothing
1128 self.assertRaises(SAXParseException, parser.parse, StringIO("<foo>"))
Martin v. Löwis80670bc2000-10-06 21:13:23 +00001129
Guido van Rossumd8faa362007-04-27 19:54:29 +00001130 def test_sax_parse_exception_str(self):
1131 # pass various values from a locator to the SAXParseException to
1132 # make sure that the __str__() doesn't fall apart when None is
1133 # passed instead of an integer line and column number
1134 #
1135 # use "normal" values for the locator:
1136 str(SAXParseException("message", None,
1137 self.DummyLocator(1, 1)))
1138 # use None for the line number:
1139 str(SAXParseException("message", None,
1140 self.DummyLocator(None, 1)))
1141 # use None for the column number:
1142 str(SAXParseException("message", None,
1143 self.DummyLocator(1, None)))
1144 # use None for both:
1145 str(SAXParseException("message", None,
1146 self.DummyLocator(None, None)))
Fred Drake6fd0b0d2004-03-20 08:15:30 +00001147
Guido van Rossumd8faa362007-04-27 19:54:29 +00001148 class DummyLocator:
1149 def __init__(self, lineno, colno):
1150 self._lineno = lineno
1151 self._colno = colno
Fred Drake6fd0b0d2004-03-20 08:15:30 +00001152
Guido van Rossumd8faa362007-04-27 19:54:29 +00001153 def getPublicId(self):
1154 return "pubid"
Fred Drake6fd0b0d2004-03-20 08:15:30 +00001155
Guido van Rossumd8faa362007-04-27 19:54:29 +00001156 def getSystemId(self):
1157 return "sysid"
Fred Drake6fd0b0d2004-03-20 08:15:30 +00001158
Guido van Rossumd8faa362007-04-27 19:54:29 +00001159 def getLineNumber(self):
1160 return self._lineno
Fred Drake6fd0b0d2004-03-20 08:15:30 +00001161
Guido van Rossumd8faa362007-04-27 19:54:29 +00001162 def getColumnNumber(self):
1163 return self._colno
Martin v. Löwis80670bc2000-10-06 21:13:23 +00001164
Lars Gustäbelab647872000-09-24 18:40:52 +00001165# ===========================================================================
1166#
1167# xmlreader tests
1168#
1169# ===========================================================================
1170
Guido van Rossumd8faa362007-04-27 19:54:29 +00001171class XmlReaderTest(XmlTestBase):
Lars Gustäbelab647872000-09-24 18:40:52 +00001172
Guido van Rossumd8faa362007-04-27 19:54:29 +00001173 # ===== AttributesImpl
1174 def test_attrs_empty(self):
1175 self.verify_empty_attrs(AttributesImpl({}))
Lars Gustäbelab647872000-09-24 18:40:52 +00001176
Guido van Rossumd8faa362007-04-27 19:54:29 +00001177 def test_attrs_wattr(self):
1178 self.verify_attrs_wattr(AttributesImpl({"attr" : "val"}))
Lars Gustäbelab647872000-09-24 18:40:52 +00001179
Guido van Rossumd8faa362007-04-27 19:54:29 +00001180 def test_nsattrs_empty(self):
1181 self.verify_empty_nsattrs(AttributesNSImpl({}, {}))
Lars Gustäbelab647872000-09-24 18:40:52 +00001182
Guido van Rossumd8faa362007-04-27 19:54:29 +00001183 def test_nsattrs_wattr(self):
1184 attrs = AttributesNSImpl({(ns_uri, "attr") : "val"},
1185 {(ns_uri, "attr") : "ns:attr"})
Fred Drake004d5e62000-10-23 17:22:08 +00001186
Ezio Melottib3aedd42010-11-20 19:04:17 +00001187 self.assertEqual(attrs.getLength(), 1)
1188 self.assertEqual(attrs.getNames(), [(ns_uri, "attr")])
1189 self.assertEqual(attrs.getQNames(), ["ns:attr"])
1190 self.assertEqual(len(attrs), 1)
Benjamin Peterson577473f2010-01-19 00:09:57 +00001191 self.assertIn((ns_uri, "attr"), attrs)
Ezio Melottib3aedd42010-11-20 19:04:17 +00001192 self.assertEqual(list(attrs.keys()), [(ns_uri, "attr")])
1193 self.assertEqual(attrs.get((ns_uri, "attr")), "val")
1194 self.assertEqual(attrs.get((ns_uri, "attr"), 25), "val")
1195 self.assertEqual(list(attrs.items()), [((ns_uri, "attr"), "val")])
1196 self.assertEqual(list(attrs.values()), ["val"])
1197 self.assertEqual(attrs.getValue((ns_uri, "attr")), "val")
1198 self.assertEqual(attrs.getValueByQName("ns:attr"), "val")
1199 self.assertEqual(attrs.getNameByQName("ns:attr"), (ns_uri, "attr"))
1200 self.assertEqual(attrs[(ns_uri, "attr")], "val")
1201 self.assertEqual(attrs.getQNameByName((ns_uri, "attr")), "ns:attr")
Fred Drake004d5e62000-10-23 17:22:08 +00001202
Lars Gustäbelab647872000-09-24 18:40:52 +00001203
Christian Heimesbbe741d2008-03-28 10:53:29 +00001204def test_main():
Guido van Rossumd8faa362007-04-27 19:54:29 +00001205 run_unittest(MakeParserTest,
Serhiy Storchaka13e41c52015-04-02 23:05:57 +03001206 ParseTest,
Guido van Rossumd8faa362007-04-27 19:54:29 +00001207 SaxutilsTest,
Serhiy Storchakaaa9563c2015-04-02 20:55:59 +03001208 PrepareInputSourceTest,
Serhiy Storchaka88efc522013-02-10 14:29:52 +02001209 StringXmlgenTest,
1210 BytesXmlgenTest,
1211 WriterXmlgenTest,
Georg Brandlc502df42013-05-12 11:41:12 +02001212 StreamWriterXmlgenTest,
1213 StreamReaderWriterXmlgenTest,
Guido van Rossumd8faa362007-04-27 19:54:29 +00001214 ExpatReaderTest,
1215 ErrorReportingTest,
1216 XmlReaderTest)
Lars Gustäbelb7536d52000-09-24 18:53:56 +00001217
Guido van Rossumd8faa362007-04-27 19:54:29 +00001218if __name__ == "__main__":
Christian Heimesbbe741d2008-03-28 10:53:29 +00001219 test_main()