blob: 3efd97245829e135de88a5054ded8077163b2cf6 [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, \
13 XMLFilterBase
14from 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
Serhiy Storchaka1a4ed4c2013-02-02 12:17:05 +020018import os.path
Serhiy Storchakad5202392013-02-02 10:31:17 +020019import shutil
20from test import support
Benjamin Petersonee8712c2008-05-20 21:35:26 +000021from test.support import findfile, run_unittest
Florent Xiclunaf15351d2010-03-13 23:24:31 +000022
23TEST_XMLFILE = findfile("test.xml", subdir="xmltestdata")
24TEST_XMLFILE_OUT = findfile("test.xml.out", subdir="xmltestdata")
Victor Stinner6c6f8512010-08-07 10:09:35 +000025try:
26 TEST_XMLFILE.encode("utf8")
27 TEST_XMLFILE_OUT.encode("utf8")
28except UnicodeEncodeError:
29 raise unittest.SkipTest("filename is not encodable to utf8")
Lars Gustäbel96753b32000-09-24 12:24:24 +000030
Serhiy Storchaka1a4ed4c2013-02-02 12:17:05 +020031supports_nonascii_filenames = True
32if not os.path.supports_unicode_filenames:
33 try:
34 support.TESTFN_UNICODE.encode(support.TESTFN_ENCODING)
35 except (UnicodeError, TypeError):
36 # Either the file system encoding is None, or the file name
37 # cannot be encoded in the file system encoding.
38 supports_nonascii_filenames = False
39requires_nonascii_filenames = unittest.skipUnless(
40 supports_nonascii_filenames,
41 'Requires non-ascii filenames support')
42
Guido van Rossumd8faa362007-04-27 19:54:29 +000043ns_uri = "http://www.python.org/xml-ns/saxtest/"
Lars Gustäbel96753b32000-09-24 12:24:24 +000044
Guido van Rossumd8faa362007-04-27 19:54:29 +000045class XmlTestBase(unittest.TestCase):
46 def verify_empty_attrs(self, attrs):
47 self.assertRaises(KeyError, attrs.getValue, "attr")
48 self.assertRaises(KeyError, attrs.getValueByQName, "attr")
49 self.assertRaises(KeyError, attrs.getNameByQName, "attr")
50 self.assertRaises(KeyError, attrs.getQNameByName, "attr")
51 self.assertRaises(KeyError, attrs.__getitem__, "attr")
Ezio Melottib3aedd42010-11-20 19:04:17 +000052 self.assertEqual(attrs.getLength(), 0)
53 self.assertEqual(attrs.getNames(), [])
54 self.assertEqual(attrs.getQNames(), [])
55 self.assertEqual(len(attrs), 0)
Ezio Melottib58e0bd2010-01-23 15:40:09 +000056 self.assertNotIn("attr", attrs)
Ezio Melottib3aedd42010-11-20 19:04:17 +000057 self.assertEqual(list(attrs.keys()), [])
58 self.assertEqual(attrs.get("attrs"), None)
59 self.assertEqual(attrs.get("attrs", 25), 25)
60 self.assertEqual(list(attrs.items()), [])
61 self.assertEqual(list(attrs.values()), [])
Lars Gustäbel96753b32000-09-24 12:24:24 +000062
Guido van Rossumd8faa362007-04-27 19:54:29 +000063 def verify_empty_nsattrs(self, attrs):
64 self.assertRaises(KeyError, attrs.getValue, (ns_uri, "attr"))
65 self.assertRaises(KeyError, attrs.getValueByQName, "ns:attr")
66 self.assertRaises(KeyError, attrs.getNameByQName, "ns:attr")
67 self.assertRaises(KeyError, attrs.getQNameByName, (ns_uri, "attr"))
68 self.assertRaises(KeyError, attrs.__getitem__, (ns_uri, "attr"))
Ezio Melottib3aedd42010-11-20 19:04:17 +000069 self.assertEqual(attrs.getLength(), 0)
70 self.assertEqual(attrs.getNames(), [])
71 self.assertEqual(attrs.getQNames(), [])
72 self.assertEqual(len(attrs), 0)
Ezio Melottib58e0bd2010-01-23 15:40:09 +000073 self.assertNotIn((ns_uri, "attr"), attrs)
Ezio Melottib3aedd42010-11-20 19:04:17 +000074 self.assertEqual(list(attrs.keys()), [])
75 self.assertEqual(attrs.get((ns_uri, "attr")), None)
76 self.assertEqual(attrs.get((ns_uri, "attr"), 25), 25)
77 self.assertEqual(list(attrs.items()), [])
78 self.assertEqual(list(attrs.values()), [])
Lars Gustäbel96753b32000-09-24 12:24:24 +000079
Guido van Rossumd8faa362007-04-27 19:54:29 +000080 def verify_attrs_wattr(self, attrs):
Ezio Melottib3aedd42010-11-20 19:04:17 +000081 self.assertEqual(attrs.getLength(), 1)
82 self.assertEqual(attrs.getNames(), ["attr"])
83 self.assertEqual(attrs.getQNames(), ["attr"])
84 self.assertEqual(len(attrs), 1)
Benjamin Peterson577473f2010-01-19 00:09:57 +000085 self.assertIn("attr", attrs)
Ezio Melottib3aedd42010-11-20 19:04:17 +000086 self.assertEqual(list(attrs.keys()), ["attr"])
87 self.assertEqual(attrs.get("attr"), "val")
88 self.assertEqual(attrs.get("attr", 25), "val")
89 self.assertEqual(list(attrs.items()), [("attr", "val")])
90 self.assertEqual(list(attrs.values()), ["val"])
91 self.assertEqual(attrs.getValue("attr"), "val")
92 self.assertEqual(attrs.getValueByQName("attr"), "val")
93 self.assertEqual(attrs.getNameByQName("attr"), "attr")
94 self.assertEqual(attrs["attr"], "val")
95 self.assertEqual(attrs.getQNameByName("attr"), "attr")
Lars Gustäbel96753b32000-09-24 12:24:24 +000096
Guido van Rossumd8faa362007-04-27 19:54:29 +000097class MakeParserTest(unittest.TestCase):
98 def test_make_parser2(self):
Lars Gustäbel2fc52942000-10-24 15:35:07 +000099 # Creating parsers several times in a row should succeed.
100 # Testing this because there have been failures of this kind
101 # before.
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000102 from xml.sax import make_parser
Lars Gustäbel2fc52942000-10-24 15:35:07 +0000103 p = make_parser()
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000104 from xml.sax import make_parser
Lars Gustäbel2fc52942000-10-24 15:35:07 +0000105 p = make_parser()
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000106 from xml.sax import make_parser
Lars Gustäbel2fc52942000-10-24 15:35:07 +0000107 p = make_parser()
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000108 from xml.sax import make_parser
Lars Gustäbel2fc52942000-10-24 15:35:07 +0000109 p = make_parser()
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000110 from xml.sax import make_parser
Lars Gustäbel2fc52942000-10-24 15:35:07 +0000111 p = make_parser()
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000112 from xml.sax import make_parser
Lars Gustäbel2fc52942000-10-24 15:35:07 +0000113 p = make_parser()
Tim Petersd2bf3b72001-01-18 02:22:22 +0000114
115
Lars Gustäbel96753b32000-09-24 12:24:24 +0000116# ===========================================================================
117#
118# saxutils tests
119#
120# ===========================================================================
121
Guido van Rossumd8faa362007-04-27 19:54:29 +0000122class SaxutilsTest(unittest.TestCase):
123 # ===== escape
124 def test_escape_basic(self):
Ezio Melottib3aedd42010-11-20 19:04:17 +0000125 self.assertEqual(escape("Donald Duck & Co"), "Donald Duck & Co")
Lars Gustäbel96753b32000-09-24 12:24:24 +0000126
Guido van Rossumd8faa362007-04-27 19:54:29 +0000127 def test_escape_all(self):
Ezio Melottib3aedd42010-11-20 19:04:17 +0000128 self.assertEqual(escape("<Donald Duck & Co>"),
129 "&lt;Donald Duck &amp; Co&gt;")
Lars Gustäbel96753b32000-09-24 12:24:24 +0000130
Guido van Rossumd8faa362007-04-27 19:54:29 +0000131 def test_escape_extra(self):
Ezio Melottib3aedd42010-11-20 19:04:17 +0000132 self.assertEqual(escape("Hei på deg", {"å" : "&aring;"}),
133 "Hei p&aring; deg")
Lars Gustäbel96753b32000-09-24 12:24:24 +0000134
Guido van Rossumd8faa362007-04-27 19:54:29 +0000135 # ===== unescape
136 def test_unescape_basic(self):
Ezio Melottib3aedd42010-11-20 19:04:17 +0000137 self.assertEqual(unescape("Donald Duck &amp; Co"), "Donald Duck & Co")
Lars Gustäbel96753b32000-09-24 12:24:24 +0000138
Guido van Rossumd8faa362007-04-27 19:54:29 +0000139 def test_unescape_all(self):
Ezio Melottib3aedd42010-11-20 19:04:17 +0000140 self.assertEqual(unescape("&lt;Donald Duck &amp; Co&gt;"),
141 "<Donald Duck & Co>")
Martin v. Löwis74b51ac2002-10-26 14:50:45 +0000142
Guido van Rossumd8faa362007-04-27 19:54:29 +0000143 def test_unescape_extra(self):
Ezio Melottib3aedd42010-11-20 19:04:17 +0000144 self.assertEqual(unescape("Hei på deg", {"å" : "&aring;"}),
145 "Hei p&aring; deg")
Martin v. Löwis74b51ac2002-10-26 14:50:45 +0000146
Guido van Rossumd8faa362007-04-27 19:54:29 +0000147 def test_unescape_amp_extra(self):
Ezio Melottib3aedd42010-11-20 19:04:17 +0000148 self.assertEqual(unescape("&amp;foo;", {"&foo;": "splat"}), "&foo;")
Martin v. Löwis74b51ac2002-10-26 14:50:45 +0000149
Guido van Rossumd8faa362007-04-27 19:54:29 +0000150 # ===== quoteattr
151 def test_quoteattr_basic(self):
Ezio Melottib3aedd42010-11-20 19:04:17 +0000152 self.assertEqual(quoteattr("Donald Duck & Co"),
153 '"Donald Duck &amp; Co"')
Martin v. Löwis74b51ac2002-10-26 14:50:45 +0000154
Guido van Rossumd8faa362007-04-27 19:54:29 +0000155 def test_single_quoteattr(self):
Ezio Melottib3aedd42010-11-20 19:04:17 +0000156 self.assertEqual(quoteattr('Includes "double" quotes'),
157 '\'Includes "double" quotes\'')
Fred Drake32f3add2002-10-28 17:58:48 +0000158
Guido van Rossumd8faa362007-04-27 19:54:29 +0000159 def test_double_quoteattr(self):
Ezio Melottib3aedd42010-11-20 19:04:17 +0000160 self.assertEqual(quoteattr("Includes 'single' quotes"),
161 "\"Includes 'single' quotes\"")
Fred Drakeacd32d32001-07-19 16:10:15 +0000162
Guido van Rossumd8faa362007-04-27 19:54:29 +0000163 def test_single_double_quoteattr(self):
Ezio Melottib3aedd42010-11-20 19:04:17 +0000164 self.assertEqual(quoteattr("Includes 'single' and \"double\" quotes"),
165 "\"Includes 'single' and &quot;double&quot; quotes\"")
Fred Drakeacd32d32001-07-19 16:10:15 +0000166
Guido van Rossumd8faa362007-04-27 19:54:29 +0000167 # ===== make_parser
168 def test_make_parser(self):
Martin v. Löwis962c9e72000-10-06 17:41:52 +0000169 # Creating a parser should succeed - it should fall back
170 # to the expatreader
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000171 p = make_parser(['xml.parsers.no_such_parser'])
Martin v. Löwis962c9e72000-10-06 17:41:52 +0000172
173
Lars Gustäbel96753b32000-09-24 12:24:24 +0000174# ===== XMLGenerator
175
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200176class XmlgenTest:
Guido van Rossumd8faa362007-04-27 19:54:29 +0000177 def test_xmlgen_basic(self):
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200178 result = self.ioclass()
Guido van Rossumd8faa362007-04-27 19:54:29 +0000179 gen = XMLGenerator(result)
180 gen.startDocument()
181 gen.startElement("doc", {})
182 gen.endElement("doc")
183 gen.endDocument()
Lars Gustäbel96753b32000-09-24 12:24:24 +0000184
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200185 self.assertEqual(result.getvalue(), self.xml("<doc></doc>"))
Lars Gustäbel96753b32000-09-24 12:24:24 +0000186
R. David Murraya90032a2010-10-17 22:46:45 +0000187 def test_xmlgen_basic_empty(self):
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200188 result = self.ioclass()
R. David Murraya90032a2010-10-17 22:46:45 +0000189 gen = XMLGenerator(result, short_empty_elements=True)
190 gen.startDocument()
191 gen.startElement("doc", {})
192 gen.endElement("doc")
193 gen.endDocument()
194
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200195 self.assertEqual(result.getvalue(), self.xml("<doc/>"))
R. David Murraya90032a2010-10-17 22:46:45 +0000196
Guido van Rossumd8faa362007-04-27 19:54:29 +0000197 def test_xmlgen_content(self):
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200198 result = self.ioclass()
Guido van Rossumd8faa362007-04-27 19:54:29 +0000199 gen = XMLGenerator(result)
Fred Drake004d5e62000-10-23 17:22:08 +0000200
Guido van Rossumd8faa362007-04-27 19:54:29 +0000201 gen.startDocument()
202 gen.startElement("doc", {})
203 gen.characters("huhei")
204 gen.endElement("doc")
205 gen.endDocument()
Lars Gustäbel96753b32000-09-24 12:24:24 +0000206
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200207 self.assertEqual(result.getvalue(), self.xml("<doc>huhei</doc>"))
Lars Gustäbel96753b32000-09-24 12:24:24 +0000208
R. David Murraya90032a2010-10-17 22:46:45 +0000209 def test_xmlgen_content_empty(self):
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200210 result = self.ioclass()
R. David Murraya90032a2010-10-17 22:46:45 +0000211 gen = XMLGenerator(result, short_empty_elements=True)
212
213 gen.startDocument()
214 gen.startElement("doc", {})
215 gen.characters("huhei")
216 gen.endElement("doc")
217 gen.endDocument()
218
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200219 self.assertEqual(result.getvalue(), self.xml("<doc>huhei</doc>"))
R. David Murraya90032a2010-10-17 22:46:45 +0000220
Guido van Rossumd8faa362007-04-27 19:54:29 +0000221 def test_xmlgen_pi(self):
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200222 result = self.ioclass()
Guido van Rossumd8faa362007-04-27 19:54:29 +0000223 gen = XMLGenerator(result)
Fred Drake004d5e62000-10-23 17:22:08 +0000224
Guido van Rossumd8faa362007-04-27 19:54:29 +0000225 gen.startDocument()
226 gen.processingInstruction("test", "data")
227 gen.startElement("doc", {})
228 gen.endElement("doc")
229 gen.endDocument()
Lars Gustäbel96753b32000-09-24 12:24:24 +0000230
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200231 self.assertEqual(result.getvalue(),
232 self.xml("<?test data?><doc></doc>"))
Lars Gustäbel96753b32000-09-24 12:24:24 +0000233
Guido van Rossumd8faa362007-04-27 19:54:29 +0000234 def test_xmlgen_content_escape(self):
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200235 result = self.ioclass()
Guido van Rossumd8faa362007-04-27 19:54:29 +0000236 gen = XMLGenerator(result)
Fred Drake004d5e62000-10-23 17:22:08 +0000237
Guido van Rossumd8faa362007-04-27 19:54:29 +0000238 gen.startDocument()
239 gen.startElement("doc", {})
240 gen.characters("<huhei&")
241 gen.endElement("doc")
242 gen.endDocument()
Lars Gustäbel96753b32000-09-24 12:24:24 +0000243
Ezio Melottib3aedd42010-11-20 19:04:17 +0000244 self.assertEqual(result.getvalue(),
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200245 self.xml("<doc>&lt;huhei&amp;</doc>"))
Lars Gustäbel96753b32000-09-24 12:24:24 +0000246
Guido van Rossumd8faa362007-04-27 19:54:29 +0000247 def test_xmlgen_attr_escape(self):
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200248 result = self.ioclass()
Guido van Rossumd8faa362007-04-27 19:54:29 +0000249 gen = XMLGenerator(result)
Fred Drakec9fadf92001-08-07 19:17:06 +0000250
Guido van Rossumd8faa362007-04-27 19:54:29 +0000251 gen.startDocument()
252 gen.startElement("doc", {"a": '"'})
253 gen.startElement("e", {"a": "'"})
254 gen.endElement("e")
255 gen.startElement("e", {"a": "'\""})
256 gen.endElement("e")
257 gen.startElement("e", {"a": "\n\r\t"})
258 gen.endElement("e")
259 gen.endElement("doc")
260 gen.endDocument()
Fred Drakec9fadf92001-08-07 19:17:06 +0000261
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200262 self.assertEqual(result.getvalue(), self.xml(
263 "<doc a='\"'><e a=\"'\"></e>"
264 "<e a=\"'&quot;\"></e>"
265 "<e a=\"&#10;&#13;&#9;\"></e></doc>"))
266
267 def test_xmlgen_encoding(self):
268 encodings = ('iso-8859-15', 'utf-8', 'utf-8-sig',
269 'utf-16', 'utf-16be', 'utf-16le',
270 'utf-32', 'utf-32be', 'utf-32le')
271 for encoding in encodings:
272 result = self.ioclass()
273 gen = XMLGenerator(result, encoding=encoding)
274
275 gen.startDocument()
276 gen.startElement("doc", {"a": '\u20ac'})
277 gen.characters("\u20ac")
278 gen.endElement("doc")
279 gen.endDocument()
280
281 self.assertEqual(result.getvalue(),
282 self.xml('<doc a="\u20ac">\u20ac</doc>', encoding=encoding))
283
284 def test_xmlgen_unencodable(self):
285 result = self.ioclass()
286 gen = XMLGenerator(result, encoding='ascii')
287
288 gen.startDocument()
289 gen.startElement("doc", {"a": '\u20ac'})
290 gen.characters("\u20ac")
291 gen.endElement("doc")
292 gen.endDocument()
293
294 self.assertEqual(result.getvalue(),
295 self.xml('<doc a="&#8364;">&#8364;</doc>', encoding='ascii'))
Fred Drakec9fadf92001-08-07 19:17:06 +0000296
Guido van Rossumd8faa362007-04-27 19:54:29 +0000297 def test_xmlgen_ignorable(self):
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200298 result = self.ioclass()
Guido van Rossumd8faa362007-04-27 19:54:29 +0000299 gen = XMLGenerator(result)
Fred Drake004d5e62000-10-23 17:22:08 +0000300
Guido van Rossumd8faa362007-04-27 19:54:29 +0000301 gen.startDocument()
302 gen.startElement("doc", {})
303 gen.ignorableWhitespace(" ")
304 gen.endElement("doc")
305 gen.endDocument()
Lars Gustäbel96753b32000-09-24 12:24:24 +0000306
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200307 self.assertEqual(result.getvalue(), self.xml("<doc> </doc>"))
Lars Gustäbel96753b32000-09-24 12:24:24 +0000308
R. David Murraya90032a2010-10-17 22:46:45 +0000309 def test_xmlgen_ignorable_empty(self):
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200310 result = self.ioclass()
R. David Murraya90032a2010-10-17 22:46:45 +0000311 gen = XMLGenerator(result, short_empty_elements=True)
312
313 gen.startDocument()
314 gen.startElement("doc", {})
315 gen.ignorableWhitespace(" ")
316 gen.endElement("doc")
317 gen.endDocument()
318
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200319 self.assertEqual(result.getvalue(), self.xml("<doc> </doc>"))
R. David Murraya90032a2010-10-17 22:46:45 +0000320
Guido van Rossumd8faa362007-04-27 19:54:29 +0000321 def test_xmlgen_ns(self):
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200322 result = self.ioclass()
Guido van Rossumd8faa362007-04-27 19:54:29 +0000323 gen = XMLGenerator(result)
Lars Gustäbel96753b32000-09-24 12:24:24 +0000324
Guido van Rossumd8faa362007-04-27 19:54:29 +0000325 gen.startDocument()
326 gen.startPrefixMapping("ns1", ns_uri)
327 gen.startElementNS((ns_uri, "doc"), "ns1:doc", {})
328 # add an unqualified name
329 gen.startElementNS((None, "udoc"), None, {})
330 gen.endElementNS((None, "udoc"), None)
331 gen.endElementNS((ns_uri, "doc"), "ns1:doc")
332 gen.endPrefixMapping("ns1")
333 gen.endDocument()
Fred Drake004d5e62000-10-23 17:22:08 +0000334
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200335 self.assertEqual(result.getvalue(), self.xml(
336 '<ns1:doc xmlns:ns1="%s"><udoc></udoc></ns1:doc>' %
Guido van Rossumd8faa362007-04-27 19:54:29 +0000337 ns_uri))
Lars Gustäbel96753b32000-09-24 12:24:24 +0000338
R. David Murraya90032a2010-10-17 22:46:45 +0000339 def test_xmlgen_ns_empty(self):
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200340 result = self.ioclass()
R. David Murraya90032a2010-10-17 22:46:45 +0000341 gen = XMLGenerator(result, short_empty_elements=True)
342
343 gen.startDocument()
344 gen.startPrefixMapping("ns1", ns_uri)
345 gen.startElementNS((ns_uri, "doc"), "ns1:doc", {})
346 # add an unqualified name
347 gen.startElementNS((None, "udoc"), None, {})
348 gen.endElementNS((None, "udoc"), None)
349 gen.endElementNS((ns_uri, "doc"), "ns1:doc")
350 gen.endPrefixMapping("ns1")
351 gen.endDocument()
352
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200353 self.assertEqual(result.getvalue(), self.xml(
354 '<ns1:doc xmlns:ns1="%s"><udoc/></ns1:doc>' %
R. David Murraya90032a2010-10-17 22:46:45 +0000355 ns_uri))
356
Guido van Rossumd8faa362007-04-27 19:54:29 +0000357 def test_1463026_1(self):
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200358 result = self.ioclass()
Guido van Rossumd8faa362007-04-27 19:54:29 +0000359 gen = XMLGenerator(result)
Thomas Wouterscf297e42007-02-23 15:07:44 +0000360
Guido van Rossumd8faa362007-04-27 19:54:29 +0000361 gen.startDocument()
362 gen.startElementNS((None, 'a'), 'a', {(None, 'b'):'c'})
363 gen.endElementNS((None, 'a'), 'a')
364 gen.endDocument()
Thomas Wouterscf297e42007-02-23 15:07:44 +0000365
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200366 self.assertEqual(result.getvalue(), self.xml('<a b="c"></a>'))
Thomas Wouterscf297e42007-02-23 15:07:44 +0000367
R. David Murraya90032a2010-10-17 22:46:45 +0000368 def test_1463026_1_empty(self):
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200369 result = self.ioclass()
R. David Murraya90032a2010-10-17 22:46:45 +0000370 gen = XMLGenerator(result, short_empty_elements=True)
371
372 gen.startDocument()
373 gen.startElementNS((None, 'a'), 'a', {(None, 'b'):'c'})
374 gen.endElementNS((None, 'a'), 'a')
375 gen.endDocument()
376
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200377 self.assertEqual(result.getvalue(), self.xml('<a b="c"/>'))
R. David Murraya90032a2010-10-17 22:46:45 +0000378
Guido van Rossumd8faa362007-04-27 19:54:29 +0000379 def test_1463026_2(self):
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200380 result = self.ioclass()
Guido van Rossumd8faa362007-04-27 19:54:29 +0000381 gen = XMLGenerator(result)
Thomas Wouterscf297e42007-02-23 15:07:44 +0000382
Guido van Rossumd8faa362007-04-27 19:54:29 +0000383 gen.startDocument()
384 gen.startPrefixMapping(None, 'qux')
385 gen.startElementNS(('qux', 'a'), 'a', {})
386 gen.endElementNS(('qux', 'a'), 'a')
387 gen.endPrefixMapping(None)
388 gen.endDocument()
Thomas Wouterscf297e42007-02-23 15:07:44 +0000389
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200390 self.assertEqual(result.getvalue(), self.xml('<a xmlns="qux"></a>'))
Thomas Wouterscf297e42007-02-23 15:07:44 +0000391
R. David Murraya90032a2010-10-17 22:46:45 +0000392 def test_1463026_2_empty(self):
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200393 result = self.ioclass()
R. David Murraya90032a2010-10-17 22:46:45 +0000394 gen = XMLGenerator(result, short_empty_elements=True)
395
396 gen.startDocument()
397 gen.startPrefixMapping(None, 'qux')
398 gen.startElementNS(('qux', 'a'), 'a', {})
399 gen.endElementNS(('qux', 'a'), 'a')
400 gen.endPrefixMapping(None)
401 gen.endDocument()
402
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200403 self.assertEqual(result.getvalue(), self.xml('<a xmlns="qux"/>'))
R. David Murraya90032a2010-10-17 22:46:45 +0000404
Guido van Rossumd8faa362007-04-27 19:54:29 +0000405 def test_1463026_3(self):
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200406 result = self.ioclass()
Guido van Rossumd8faa362007-04-27 19:54:29 +0000407 gen = XMLGenerator(result)
Thomas Wouterscf297e42007-02-23 15:07:44 +0000408
Guido van Rossumd8faa362007-04-27 19:54:29 +0000409 gen.startDocument()
410 gen.startPrefixMapping('my', 'qux')
411 gen.startElementNS(('qux', 'a'), 'a', {(None, 'b'):'c'})
412 gen.endElementNS(('qux', 'a'), 'a')
413 gen.endPrefixMapping('my')
414 gen.endDocument()
Thomas Wouterscf297e42007-02-23 15:07:44 +0000415
Ezio Melottib3aedd42010-11-20 19:04:17 +0000416 self.assertEqual(result.getvalue(),
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200417 self.xml('<my:a xmlns:my="qux" b="c"></my:a>'))
Lars Gustäbel96753b32000-09-24 12:24:24 +0000418
R. David Murraya90032a2010-10-17 22:46:45 +0000419 def test_1463026_3_empty(self):
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200420 result = self.ioclass()
R. David Murraya90032a2010-10-17 22:46:45 +0000421 gen = XMLGenerator(result, short_empty_elements=True)
422
423 gen.startDocument()
424 gen.startPrefixMapping('my', 'qux')
425 gen.startElementNS(('qux', 'a'), 'a', {(None, 'b'):'c'})
426 gen.endElementNS(('qux', 'a'), 'a')
427 gen.endPrefixMapping('my')
428 gen.endDocument()
429
Ezio Melottib3aedd42010-11-20 19:04:17 +0000430 self.assertEqual(result.getvalue(),
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200431 self.xml('<my:a xmlns:my="qux" b="c"/>'))
R. David Murraya90032a2010-10-17 22:46:45 +0000432
Antoine Pitrou6b03ee62010-10-27 18:33:30 +0000433 def test_5027_1(self):
434 # The xml prefix (as in xml:lang below) is reserved and bound by
435 # definition to http://www.w3.org/XML/1998/namespace. XMLGenerator had
Andrew Svetlov737fb892012-12-18 21:14:22 +0200436 # a bug whereby a KeyError is raised because this namespace is missing
Antoine Pitrou6b03ee62010-10-27 18:33:30 +0000437 # from a dictionary.
438 #
439 # This test demonstrates the bug by parsing a document.
440 test_xml = StringIO(
441 '<?xml version="1.0"?>'
442 '<a:g1 xmlns:a="http://example.com/ns">'
443 '<a:g2 xml:lang="en">Hello</a:g2>'
444 '</a:g1>')
445
446 parser = make_parser()
447 parser.setFeature(feature_namespaces, True)
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200448 result = self.ioclass()
Antoine Pitrou6b03ee62010-10-27 18:33:30 +0000449 gen = XMLGenerator(result)
450 parser.setContentHandler(gen)
451 parser.parse(test_xml)
452
Ezio Melottib3aedd42010-11-20 19:04:17 +0000453 self.assertEqual(result.getvalue(),
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200454 self.xml(
Ezio Melottib3aedd42010-11-20 19:04:17 +0000455 '<a:g1 xmlns:a="http://example.com/ns">'
456 '<a:g2 xml:lang="en">Hello</a:g2>'
457 '</a:g1>'))
Antoine Pitrou6b03ee62010-10-27 18:33:30 +0000458
459 def test_5027_2(self):
460 # The xml prefix (as in xml:lang below) is reserved and bound by
461 # definition to http://www.w3.org/XML/1998/namespace. XMLGenerator had
Andrew Svetlov737fb892012-12-18 21:14:22 +0200462 # a bug whereby a KeyError is raised because this namespace is missing
Antoine Pitrou6b03ee62010-10-27 18:33:30 +0000463 # from a dictionary.
464 #
465 # This test demonstrates the bug by direct manipulation of the
466 # XMLGenerator.
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200467 result = self.ioclass()
Antoine Pitrou6b03ee62010-10-27 18:33:30 +0000468 gen = XMLGenerator(result)
469
470 gen.startDocument()
471 gen.startPrefixMapping('a', 'http://example.com/ns')
472 gen.startElementNS(('http://example.com/ns', 'g1'), 'g1', {})
473 lang_attr = {('http://www.w3.org/XML/1998/namespace', 'lang'): 'en'}
474 gen.startElementNS(('http://example.com/ns', 'g2'), 'g2', lang_attr)
475 gen.characters('Hello')
476 gen.endElementNS(('http://example.com/ns', 'g2'), 'g2')
477 gen.endElementNS(('http://example.com/ns', 'g1'), 'g1')
478 gen.endPrefixMapping('a')
479 gen.endDocument()
480
Ezio Melottib3aedd42010-11-20 19:04:17 +0000481 self.assertEqual(result.getvalue(),
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200482 self.xml(
Ezio Melottib3aedd42010-11-20 19:04:17 +0000483 '<a:g1 xmlns:a="http://example.com/ns">'
484 '<a:g2 xml:lang="en">Hello</a:g2>'
485 '</a:g1>'))
Antoine Pitrou6b03ee62010-10-27 18:33:30 +0000486
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200487 def test_no_close_file(self):
488 result = self.ioclass()
489 def func(out):
490 gen = XMLGenerator(out)
491 gen.startDocument()
492 gen.startElement("doc", {})
493 func(result)
494 self.assertFalse(result.closed)
495
Serhiy Storchakaa5f13d22013-02-25 13:46:10 +0200496 def test_xmlgen_fragment(self):
497 result = self.ioclass()
498 gen = XMLGenerator(result)
499
500 # Don't call gen.startDocument()
501 gen.startElement("foo", {"a": "1.0"})
502 gen.characters("Hello")
503 gen.endElement("foo")
504 gen.startElement("bar", {"b": "2.0"})
505 gen.endElement("bar")
506 # Don't call gen.endDocument()
507
508 self.assertEqual(result.getvalue(),
509 self.xml('<foo a="1.0">Hello</foo><bar b="2.0"></bar>')[len(self.xml('')):])
510
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200511class StringXmlgenTest(XmlgenTest, unittest.TestCase):
512 ioclass = StringIO
513
514 def xml(self, doc, encoding='iso-8859-1'):
515 return '<?xml version="1.0" encoding="%s"?>\n%s' % (encoding, doc)
516
517 test_xmlgen_unencodable = None
518
519class BytesXmlgenTest(XmlgenTest, unittest.TestCase):
520 ioclass = BytesIO
521
522 def xml(self, doc, encoding='iso-8859-1'):
523 return ('<?xml version="1.0" encoding="%s"?>\n%s' %
524 (encoding, doc)).encode(encoding, 'xmlcharrefreplace')
525
526class WriterXmlgenTest(BytesXmlgenTest):
527 class ioclass(list):
528 write = list.append
529 closed = False
530
531 def seekable(self):
532 return True
533
534 def tell(self):
535 # return 0 at start and not 0 after start
536 return len(self)
537
538 def getvalue(self):
539 return b''.join(self)
540
541
542start = b'<?xml version="1.0" encoding="iso-8859-1"?>\n'
543
Fred Drake004d5e62000-10-23 17:22:08 +0000544
Guido van Rossumd8faa362007-04-27 19:54:29 +0000545class XMLFilterBaseTest(unittest.TestCase):
546 def test_filter_basic(self):
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200547 result = BytesIO()
Guido van Rossumd8faa362007-04-27 19:54:29 +0000548 gen = XMLGenerator(result)
549 filter = XMLFilterBase()
550 filter.setContentHandler(gen)
Lars Gustäbel96753b32000-09-24 12:24:24 +0000551
Guido van Rossumd8faa362007-04-27 19:54:29 +0000552 filter.startDocument()
553 filter.startElement("doc", {})
554 filter.characters("content")
555 filter.ignorableWhitespace(" ")
556 filter.endElement("doc")
557 filter.endDocument()
558
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200559 self.assertEqual(result.getvalue(), start + b"<doc>content </doc>")
Lars Gustäbel96753b32000-09-24 12:24:24 +0000560
561# ===========================================================================
562#
563# expatreader tests
564#
565# ===========================================================================
566
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200567with open(TEST_XMLFILE_OUT, 'rb') as f:
Benjamin Petersond5df36d2010-10-31 18:23:23 +0000568 xml_test_out = f.read()
Lars Gustäbelb7536d52000-09-24 18:53:56 +0000569
Guido van Rossumd8faa362007-04-27 19:54:29 +0000570class ExpatReaderTest(XmlTestBase):
Lars Gustäbelb7536d52000-09-24 18:53:56 +0000571
Guido van Rossumd8faa362007-04-27 19:54:29 +0000572 # ===== XMLReader support
Lars Gustäbelb7536d52000-09-24 18:53:56 +0000573
Guido van Rossumd8faa362007-04-27 19:54:29 +0000574 def test_expat_file(self):
575 parser = create_parser()
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200576 result = BytesIO()
Guido van Rossumd8faa362007-04-27 19:54:29 +0000577 xmlgen = XMLGenerator(result)
Lars Gustäbelb7536d52000-09-24 18:53:56 +0000578
Guido van Rossumd8faa362007-04-27 19:54:29 +0000579 parser.setContentHandler(xmlgen)
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200580 with open(TEST_XMLFILE, 'rb') as f:
Benjamin Petersond5df36d2010-10-31 18:23:23 +0000581 parser.parse(f)
Lars Gustäbelb7536d52000-09-24 18:53:56 +0000582
Ezio Melottib3aedd42010-11-20 19:04:17 +0000583 self.assertEqual(result.getvalue(), xml_test_out)
Lars Gustäbelb7536d52000-09-24 18:53:56 +0000584
Serhiy Storchaka1a4ed4c2013-02-02 12:17:05 +0200585 @requires_nonascii_filenames
Serhiy Storchakad5202392013-02-02 10:31:17 +0200586 def test_expat_file_nonascii(self):
587 fname = support.TESTFN_UNICODE
588 shutil.copyfile(TEST_XMLFILE, fname)
589 self.addCleanup(support.unlink, fname)
590
591 parser = create_parser()
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200592 result = BytesIO()
Serhiy Storchakad5202392013-02-02 10:31:17 +0200593 xmlgen = XMLGenerator(result)
594
595 parser.setContentHandler(xmlgen)
596 parser.parse(open(fname))
597
598 self.assertEqual(result.getvalue(), xml_test_out)
599
Guido van Rossumd8faa362007-04-27 19:54:29 +0000600 # ===== DTDHandler support
Lars Gustäbelb7536d52000-09-24 18:53:56 +0000601
Guido van Rossumd8faa362007-04-27 19:54:29 +0000602 class TestDTDHandler:
Lars Gustäbelb7536d52000-09-24 18:53:56 +0000603
Guido van Rossumd8faa362007-04-27 19:54:29 +0000604 def __init__(self):
605 self._notations = []
606 self._entities = []
Lars Gustäbelb7536d52000-09-24 18:53:56 +0000607
Guido van Rossumd8faa362007-04-27 19:54:29 +0000608 def notationDecl(self, name, publicId, systemId):
609 self._notations.append((name, publicId, systemId))
Lars Gustäbelb7536d52000-09-24 18:53:56 +0000610
Guido van Rossumd8faa362007-04-27 19:54:29 +0000611 def unparsedEntityDecl(self, name, publicId, systemId, ndata):
612 self._entities.append((name, publicId, systemId, ndata))
Lars Gustäbel2fc52942000-10-24 15:35:07 +0000613
Guido van Rossumd8faa362007-04-27 19:54:29 +0000614 def test_expat_dtdhandler(self):
615 parser = create_parser()
616 handler = self.TestDTDHandler()
617 parser.setDTDHandler(handler)
Lars Gustäbel2fc52942000-10-24 15:35:07 +0000618
Guido van Rossumd8faa362007-04-27 19:54:29 +0000619 parser.feed('<!DOCTYPE doc [\n')
620 parser.feed(' <!ENTITY img SYSTEM "expat.gif" NDATA GIF>\n')
621 parser.feed(' <!NOTATION GIF PUBLIC "-//CompuServe//NOTATION Graphics Interchange Format 89a//EN">\n')
622 parser.feed(']>\n')
623 parser.feed('<doc></doc>')
624 parser.close()
Lars Gustäbel2fc52942000-10-24 15:35:07 +0000625
Ezio Melottib3aedd42010-11-20 19:04:17 +0000626 self.assertEqual(handler._notations,
Guido van Rossumd8faa362007-04-27 19:54:29 +0000627 [("GIF", "-//CompuServe//NOTATION Graphics Interchange Format 89a//EN", None)])
Ezio Melottib3aedd42010-11-20 19:04:17 +0000628 self.assertEqual(handler._entities, [("img", None, "expat.gif", "GIF")])
Lars Gustäbel2fc52942000-10-24 15:35:07 +0000629
Guido van Rossumd8faa362007-04-27 19:54:29 +0000630 # ===== EntityResolver support
Lars Gustäbel2fc52942000-10-24 15:35:07 +0000631
Guido van Rossumd8faa362007-04-27 19:54:29 +0000632 class TestEntityResolver:
Lars Gustäbel2fc52942000-10-24 15:35:07 +0000633
Guido van Rossumd8faa362007-04-27 19:54:29 +0000634 def resolveEntity(self, publicId, systemId):
635 inpsrc = InputSource()
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200636 inpsrc.setByteStream(BytesIO(b"<entity/>"))
Guido van Rossumd8faa362007-04-27 19:54:29 +0000637 return inpsrc
Lars Gustäbel2fc52942000-10-24 15:35:07 +0000638
Guido van Rossumd8faa362007-04-27 19:54:29 +0000639 def test_expat_entityresolver(self):
640 parser = create_parser()
641 parser.setEntityResolver(self.TestEntityResolver())
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200642 result = BytesIO()
Guido van Rossumd8faa362007-04-27 19:54:29 +0000643 parser.setContentHandler(XMLGenerator(result))
Lars Gustäbel2fc52942000-10-24 15:35:07 +0000644
Guido van Rossumd8faa362007-04-27 19:54:29 +0000645 parser.feed('<!DOCTYPE doc [\n')
646 parser.feed(' <!ENTITY test SYSTEM "whatever">\n')
647 parser.feed(']>\n')
648 parser.feed('<doc>&test;</doc>')
649 parser.close()
Lars Gustäbel2fc52942000-10-24 15:35:07 +0000650
Ezio Melottib3aedd42010-11-20 19:04:17 +0000651 self.assertEqual(result.getvalue(), start +
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200652 b"<doc><entity></entity></doc>")
Lars Gustäbel2fc52942000-10-24 15:35:07 +0000653
Guido van Rossumd8faa362007-04-27 19:54:29 +0000654 # ===== Attributes support
Lars Gustäbel2fc52942000-10-24 15:35:07 +0000655
Guido van Rossumd8faa362007-04-27 19:54:29 +0000656 class AttrGatherer(ContentHandler):
Lars Gustäbel2fc52942000-10-24 15:35:07 +0000657
Guido van Rossumd8faa362007-04-27 19:54:29 +0000658 def startElement(self, name, attrs):
659 self._attrs = attrs
Lars Gustäbel2fc52942000-10-24 15:35:07 +0000660
Guido van Rossumd8faa362007-04-27 19:54:29 +0000661 def startElementNS(self, name, qname, attrs):
662 self._attrs = attrs
Lars Gustäbel2fc52942000-10-24 15:35:07 +0000663
Guido van Rossumd8faa362007-04-27 19:54:29 +0000664 def test_expat_attrs_empty(self):
665 parser = create_parser()
666 gather = self.AttrGatherer()
667 parser.setContentHandler(gather)
668
669 parser.feed("<doc/>")
670 parser.close()
671
672 self.verify_empty_attrs(gather._attrs)
673
674 def test_expat_attrs_wattr(self):
675 parser = create_parser()
676 gather = self.AttrGatherer()
677 parser.setContentHandler(gather)
678
679 parser.feed("<doc attr='val'/>")
680 parser.close()
681
682 self.verify_attrs_wattr(gather._attrs)
683
684 def test_expat_nsattrs_empty(self):
685 parser = create_parser(1)
686 gather = self.AttrGatherer()
687 parser.setContentHandler(gather)
688
689 parser.feed("<doc/>")
690 parser.close()
691
692 self.verify_empty_nsattrs(gather._attrs)
693
694 def test_expat_nsattrs_wattr(self):
695 parser = create_parser(1)
696 gather = self.AttrGatherer()
697 parser.setContentHandler(gather)
698
699 parser.feed("<doc xmlns:ns='%s' ns:attr='val'/>" % ns_uri)
700 parser.close()
701
702 attrs = gather._attrs
703
Ezio Melottib3aedd42010-11-20 19:04:17 +0000704 self.assertEqual(attrs.getLength(), 1)
705 self.assertEqual(attrs.getNames(), [(ns_uri, "attr")])
Guido van Rossumd8faa362007-04-27 19:54:29 +0000706 self.assertTrue((attrs.getQNames() == [] or
707 attrs.getQNames() == ["ns:attr"]))
Ezio Melottib3aedd42010-11-20 19:04:17 +0000708 self.assertEqual(len(attrs), 1)
Benjamin Peterson577473f2010-01-19 00:09:57 +0000709 self.assertIn((ns_uri, "attr"), attrs)
Ezio Melottib3aedd42010-11-20 19:04:17 +0000710 self.assertEqual(attrs.get((ns_uri, "attr")), "val")
711 self.assertEqual(attrs.get((ns_uri, "attr"), 25), "val")
712 self.assertEqual(list(attrs.items()), [((ns_uri, "attr"), "val")])
713 self.assertEqual(list(attrs.values()), ["val"])
714 self.assertEqual(attrs.getValue((ns_uri, "attr")), "val")
715 self.assertEqual(attrs[(ns_uri, "attr")], "val")
Guido van Rossumd8faa362007-04-27 19:54:29 +0000716
717 # ===== InputSource support
718
Benjamin Petersona7f4f5a2008-09-04 02:22:52 +0000719 def test_expat_inpsource_filename(self):
Guido van Rossumd8faa362007-04-27 19:54:29 +0000720 parser = create_parser()
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200721 result = BytesIO()
Guido van Rossumd8faa362007-04-27 19:54:29 +0000722 xmlgen = XMLGenerator(result)
723
724 parser.setContentHandler(xmlgen)
Florent Xiclunaf15351d2010-03-13 23:24:31 +0000725 parser.parse(TEST_XMLFILE)
Guido van Rossumd8faa362007-04-27 19:54:29 +0000726
Ezio Melottib3aedd42010-11-20 19:04:17 +0000727 self.assertEqual(result.getvalue(), xml_test_out)
Guido van Rossumd8faa362007-04-27 19:54:29 +0000728
Benjamin Petersona7f4f5a2008-09-04 02:22:52 +0000729 def test_expat_inpsource_sysid(self):
Guido van Rossumd8faa362007-04-27 19:54:29 +0000730 parser = create_parser()
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200731 result = BytesIO()
Guido van Rossumd8faa362007-04-27 19:54:29 +0000732 xmlgen = XMLGenerator(result)
733
734 parser.setContentHandler(xmlgen)
Florent Xiclunaf15351d2010-03-13 23:24:31 +0000735 parser.parse(InputSource(TEST_XMLFILE))
Guido van Rossumd8faa362007-04-27 19:54:29 +0000736
Ezio Melottib3aedd42010-11-20 19:04:17 +0000737 self.assertEqual(result.getvalue(), xml_test_out)
Guido van Rossumd8faa362007-04-27 19:54:29 +0000738
Serhiy Storchaka1a4ed4c2013-02-02 12:17:05 +0200739 @requires_nonascii_filenames
Serhiy Storchakad5202392013-02-02 10:31:17 +0200740 def test_expat_inpsource_sysid_nonascii(self):
741 fname = support.TESTFN_UNICODE
742 shutil.copyfile(TEST_XMLFILE, fname)
743 self.addCleanup(support.unlink, fname)
744
745 parser = create_parser()
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200746 result = BytesIO()
Serhiy Storchakad5202392013-02-02 10:31:17 +0200747 xmlgen = XMLGenerator(result)
748
749 parser.setContentHandler(xmlgen)
750 parser.parse(InputSource(fname))
751
752 self.assertEqual(result.getvalue(), xml_test_out)
753
Guido van Rossumd8faa362007-04-27 19:54:29 +0000754 def test_expat_inpsource_stream(self):
755 parser = create_parser()
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200756 result = BytesIO()
Guido van Rossumd8faa362007-04-27 19:54:29 +0000757 xmlgen = XMLGenerator(result)
758
759 parser.setContentHandler(xmlgen)
760 inpsrc = InputSource()
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200761 with open(TEST_XMLFILE, 'rb') as f:
Benjamin Petersond5df36d2010-10-31 18:23:23 +0000762 inpsrc.setByteStream(f)
763 parser.parse(inpsrc)
Guido van Rossumd8faa362007-04-27 19:54:29 +0000764
Ezio Melottib3aedd42010-11-20 19:04:17 +0000765 self.assertEqual(result.getvalue(), xml_test_out)
Guido van Rossumd8faa362007-04-27 19:54:29 +0000766
767 # ===== IncrementalParser support
768
769 def test_expat_incremental(self):
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200770 result = BytesIO()
Guido van Rossumd8faa362007-04-27 19:54:29 +0000771 xmlgen = XMLGenerator(result)
772 parser = create_parser()
773 parser.setContentHandler(xmlgen)
774
775 parser.feed("<doc>")
776 parser.feed("</doc>")
777 parser.close()
778
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200779 self.assertEqual(result.getvalue(), start + b"<doc></doc>")
Guido van Rossumd8faa362007-04-27 19:54:29 +0000780
781 def test_expat_incremental_reset(self):
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200782 result = BytesIO()
Guido van Rossumd8faa362007-04-27 19:54:29 +0000783 xmlgen = XMLGenerator(result)
784 parser = create_parser()
785 parser.setContentHandler(xmlgen)
786
787 parser.feed("<doc>")
788 parser.feed("text")
789
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200790 result = BytesIO()
Guido van Rossumd8faa362007-04-27 19:54:29 +0000791 xmlgen = XMLGenerator(result)
792 parser.setContentHandler(xmlgen)
793 parser.reset()
794
795 parser.feed("<doc>")
796 parser.feed("text")
797 parser.feed("</doc>")
798 parser.close()
799
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200800 self.assertEqual(result.getvalue(), start + b"<doc>text</doc>")
Guido van Rossumd8faa362007-04-27 19:54:29 +0000801
802 # ===== Locator support
803
804 def test_expat_locator_noinfo(self):
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200805 result = BytesIO()
Guido van Rossumd8faa362007-04-27 19:54:29 +0000806 xmlgen = XMLGenerator(result)
807 parser = create_parser()
808 parser.setContentHandler(xmlgen)
809
810 parser.feed("<doc>")
811 parser.feed("</doc>")
812 parser.close()
813
Ezio Melottib3aedd42010-11-20 19:04:17 +0000814 self.assertEqual(parser.getSystemId(), None)
815 self.assertEqual(parser.getPublicId(), None)
816 self.assertEqual(parser.getLineNumber(), 1)
Guido van Rossumd8faa362007-04-27 19:54:29 +0000817
Benjamin Petersona7f4f5a2008-09-04 02:22:52 +0000818 def test_expat_locator_withinfo(self):
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200819 result = BytesIO()
Guido van Rossumd8faa362007-04-27 19:54:29 +0000820 xmlgen = XMLGenerator(result)
821 parser = create_parser()
822 parser.setContentHandler(xmlgen)
Florent Xiclunaf15351d2010-03-13 23:24:31 +0000823 parser.parse(TEST_XMLFILE)
Guido van Rossumd8faa362007-04-27 19:54:29 +0000824
Ezio Melottib3aedd42010-11-20 19:04:17 +0000825 self.assertEqual(parser.getSystemId(), TEST_XMLFILE)
826 self.assertEqual(parser.getPublicId(), None)
Lars Gustäbel2fc52942000-10-24 15:35:07 +0000827
Serhiy Storchaka1a4ed4c2013-02-02 12:17:05 +0200828 @requires_nonascii_filenames
Serhiy Storchakad5202392013-02-02 10:31:17 +0200829 def test_expat_locator_withinfo_nonascii(self):
830 fname = support.TESTFN_UNICODE
831 shutil.copyfile(TEST_XMLFILE, fname)
832 self.addCleanup(support.unlink, fname)
833
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200834 result = BytesIO()
Serhiy Storchakad5202392013-02-02 10:31:17 +0200835 xmlgen = XMLGenerator(result)
836 parser = create_parser()
837 parser.setContentHandler(xmlgen)
838 parser.parse(fname)
839
840 self.assertEqual(parser.getSystemId(), fname)
841 self.assertEqual(parser.getPublicId(), None)
842
Martin v. Löwis80670bc2000-10-06 21:13:23 +0000843
844# ===========================================================================
845#
846# error reporting
847#
848# ===========================================================================
849
Guido van Rossumd8faa362007-04-27 19:54:29 +0000850class ErrorReportingTest(unittest.TestCase):
851 def test_expat_inpsource_location(self):
852 parser = create_parser()
853 parser.setContentHandler(ContentHandler()) # do nothing
854 source = InputSource()
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200855 source.setByteStream(BytesIO(b"<foo bar foobar>")) #ill-formed
Guido van Rossumd8faa362007-04-27 19:54:29 +0000856 name = "a file name"
857 source.setSystemId(name)
858 try:
859 parser.parse(source)
860 self.fail()
861 except SAXException as e:
Ezio Melottib3aedd42010-11-20 19:04:17 +0000862 self.assertEqual(e.getSystemId(), name)
Martin v. Löwis80670bc2000-10-06 21:13:23 +0000863
Guido van Rossumd8faa362007-04-27 19:54:29 +0000864 def test_expat_incomplete(self):
865 parser = create_parser()
866 parser.setContentHandler(ContentHandler()) # do nothing
867 self.assertRaises(SAXParseException, parser.parse, StringIO("<foo>"))
Martin v. Löwis80670bc2000-10-06 21:13:23 +0000868
Guido van Rossumd8faa362007-04-27 19:54:29 +0000869 def test_sax_parse_exception_str(self):
870 # pass various values from a locator to the SAXParseException to
871 # make sure that the __str__() doesn't fall apart when None is
872 # passed instead of an integer line and column number
873 #
874 # use "normal" values for the locator:
875 str(SAXParseException("message", None,
876 self.DummyLocator(1, 1)))
877 # use None for the line number:
878 str(SAXParseException("message", None,
879 self.DummyLocator(None, 1)))
880 # use None for the column number:
881 str(SAXParseException("message", None,
882 self.DummyLocator(1, None)))
883 # use None for both:
884 str(SAXParseException("message", None,
885 self.DummyLocator(None, None)))
Fred Drake6fd0b0d2004-03-20 08:15:30 +0000886
Guido van Rossumd8faa362007-04-27 19:54:29 +0000887 class DummyLocator:
888 def __init__(self, lineno, colno):
889 self._lineno = lineno
890 self._colno = colno
Fred Drake6fd0b0d2004-03-20 08:15:30 +0000891
Guido van Rossumd8faa362007-04-27 19:54:29 +0000892 def getPublicId(self):
893 return "pubid"
Fred Drake6fd0b0d2004-03-20 08:15:30 +0000894
Guido van Rossumd8faa362007-04-27 19:54:29 +0000895 def getSystemId(self):
896 return "sysid"
Fred Drake6fd0b0d2004-03-20 08:15:30 +0000897
Guido van Rossumd8faa362007-04-27 19:54:29 +0000898 def getLineNumber(self):
899 return self._lineno
Fred Drake6fd0b0d2004-03-20 08:15:30 +0000900
Guido van Rossumd8faa362007-04-27 19:54:29 +0000901 def getColumnNumber(self):
902 return self._colno
Martin v. Löwis80670bc2000-10-06 21:13:23 +0000903
Lars Gustäbelab647872000-09-24 18:40:52 +0000904# ===========================================================================
905#
906# xmlreader tests
907#
908# ===========================================================================
909
Guido van Rossumd8faa362007-04-27 19:54:29 +0000910class XmlReaderTest(XmlTestBase):
Lars Gustäbelab647872000-09-24 18:40:52 +0000911
Guido van Rossumd8faa362007-04-27 19:54:29 +0000912 # ===== AttributesImpl
913 def test_attrs_empty(self):
914 self.verify_empty_attrs(AttributesImpl({}))
Lars Gustäbelab647872000-09-24 18:40:52 +0000915
Guido van Rossumd8faa362007-04-27 19:54:29 +0000916 def test_attrs_wattr(self):
917 self.verify_attrs_wattr(AttributesImpl({"attr" : "val"}))
Lars Gustäbelab647872000-09-24 18:40:52 +0000918
Guido van Rossumd8faa362007-04-27 19:54:29 +0000919 def test_nsattrs_empty(self):
920 self.verify_empty_nsattrs(AttributesNSImpl({}, {}))
Lars Gustäbelab647872000-09-24 18:40:52 +0000921
Guido van Rossumd8faa362007-04-27 19:54:29 +0000922 def test_nsattrs_wattr(self):
923 attrs = AttributesNSImpl({(ns_uri, "attr") : "val"},
924 {(ns_uri, "attr") : "ns:attr"})
Fred Drake004d5e62000-10-23 17:22:08 +0000925
Ezio Melottib3aedd42010-11-20 19:04:17 +0000926 self.assertEqual(attrs.getLength(), 1)
927 self.assertEqual(attrs.getNames(), [(ns_uri, "attr")])
928 self.assertEqual(attrs.getQNames(), ["ns:attr"])
929 self.assertEqual(len(attrs), 1)
Benjamin Peterson577473f2010-01-19 00:09:57 +0000930 self.assertIn((ns_uri, "attr"), attrs)
Ezio Melottib3aedd42010-11-20 19:04:17 +0000931 self.assertEqual(list(attrs.keys()), [(ns_uri, "attr")])
932 self.assertEqual(attrs.get((ns_uri, "attr")), "val")
933 self.assertEqual(attrs.get((ns_uri, "attr"), 25), "val")
934 self.assertEqual(list(attrs.items()), [((ns_uri, "attr"), "val")])
935 self.assertEqual(list(attrs.values()), ["val"])
936 self.assertEqual(attrs.getValue((ns_uri, "attr")), "val")
937 self.assertEqual(attrs.getValueByQName("ns:attr"), "val")
938 self.assertEqual(attrs.getNameByQName("ns:attr"), (ns_uri, "attr"))
939 self.assertEqual(attrs[(ns_uri, "attr")], "val")
940 self.assertEqual(attrs.getQNameByName((ns_uri, "attr")), "ns:attr")
Fred Drake004d5e62000-10-23 17:22:08 +0000941
Lars Gustäbelab647872000-09-24 18:40:52 +0000942
Christian Heimesbbe741d2008-03-28 10:53:29 +0000943def test_main():
Guido van Rossumd8faa362007-04-27 19:54:29 +0000944 run_unittest(MakeParserTest,
945 SaxutilsTest,
Serhiy Storchaka88efc522013-02-10 14:29:52 +0200946 StringXmlgenTest,
947 BytesXmlgenTest,
948 WriterXmlgenTest,
Guido van Rossumd8faa362007-04-27 19:54:29 +0000949 ExpatReaderTest,
950 ErrorReportingTest,
951 XmlReaderTest)
Lars Gustäbelb7536d52000-09-24 18:53:56 +0000952
Guido van Rossumd8faa362007-04-27 19:54:29 +0000953if __name__ == "__main__":
Christian Heimesbbe741d2008-03-28 10:53:29 +0000954 test_main()