blob: c8c7b3a34b366e2662cac095a91782afcadbc48e [file] [log] [blame]
Antoine Pitrou43ffd5c2010-10-27 18:54:06 +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
Martin v. Löwis962c9e72000-10-06 17:41:52 +00006try:
7 make_parser()
Martin v. Löwis80670bc2000-10-06 21:13:23 +00008except SAXReaderNotAvailable:
Martin v. Löwis962c9e72000-10-06 17:41:52 +00009 # don't try to test this module if we cannot create a parser
10 raise ImportError("no XML parsers available")
Thomas Wouters0e3f5912006-08-11 14:57:12 +000011from xml.sax.saxutils import XMLGenerator, escape, unescape, quoteattr, \
12 XMLFilterBase
13from xml.sax.expatreader import create_parser
Antoine Pitrou0619ae72010-10-27 18:37:51 +000014from xml.sax.handler import feature_namespaces
Thomas Wouters0e3f5912006-08-11 14:57:12 +000015from xml.sax.xmlreader import InputSource, AttributesImpl, AttributesNSImpl
Guido van Rossum34d19282007-08-09 01:03:29 +000016from io import StringIO
Benjamin Petersonee8712c2008-05-20 21:35:26 +000017from test.support import findfile, run_unittest
Guido van Rossumd8faa362007-04-27 19:54:29 +000018import unittest
Guido van Rossume2ae77b2001-10-24 20:42:55 +000019import os
Lars Gustäbel96753b32000-09-24 12:24:24 +000020
Guido van Rossumd8faa362007-04-27 19:54:29 +000021ns_uri = "http://www.python.org/xml-ns/saxtest/"
Lars Gustäbel96753b32000-09-24 12:24:24 +000022
Guido van Rossumd8faa362007-04-27 19:54:29 +000023class XmlTestBase(unittest.TestCase):
24 def verify_empty_attrs(self, attrs):
25 self.assertRaises(KeyError, attrs.getValue, "attr")
26 self.assertRaises(KeyError, attrs.getValueByQName, "attr")
27 self.assertRaises(KeyError, attrs.getNameByQName, "attr")
28 self.assertRaises(KeyError, attrs.getQNameByName, "attr")
29 self.assertRaises(KeyError, attrs.__getitem__, "attr")
30 self.assertEquals(attrs.getLength(), 0)
31 self.assertEquals(attrs.getNames(), [])
32 self.assertEquals(attrs.getQNames(), [])
33 self.assertEquals(len(attrs), 0)
34 self.assertFalse("attr" in attrs)
35 self.assertEquals(list(attrs.keys()), [])
36 self.assertEquals(attrs.get("attrs"), None)
37 self.assertEquals(attrs.get("attrs", 25), 25)
38 self.assertEquals(list(attrs.items()), [])
39 self.assertEquals(list(attrs.values()), [])
Lars Gustäbel96753b32000-09-24 12:24:24 +000040
Guido van Rossumd8faa362007-04-27 19:54:29 +000041 def verify_empty_nsattrs(self, attrs):
42 self.assertRaises(KeyError, attrs.getValue, (ns_uri, "attr"))
43 self.assertRaises(KeyError, attrs.getValueByQName, "ns:attr")
44 self.assertRaises(KeyError, attrs.getNameByQName, "ns:attr")
45 self.assertRaises(KeyError, attrs.getQNameByName, (ns_uri, "attr"))
46 self.assertRaises(KeyError, attrs.__getitem__, (ns_uri, "attr"))
47 self.assertEquals(attrs.getLength(), 0)
48 self.assertEquals(attrs.getNames(), [])
49 self.assertEquals(attrs.getQNames(), [])
50 self.assertEquals(len(attrs), 0)
51 self.assertFalse((ns_uri, "attr") in attrs)
52 self.assertEquals(list(attrs.keys()), [])
53 self.assertEquals(attrs.get((ns_uri, "attr")), None)
54 self.assertEquals(attrs.get((ns_uri, "attr"), 25), 25)
55 self.assertEquals(list(attrs.items()), [])
56 self.assertEquals(list(attrs.values()), [])
Lars Gustäbel96753b32000-09-24 12:24:24 +000057
Guido van Rossumd8faa362007-04-27 19:54:29 +000058 def verify_attrs_wattr(self, attrs):
59 self.assertEquals(attrs.getLength(), 1)
60 self.assertEquals(attrs.getNames(), ["attr"])
61 self.assertEquals(attrs.getQNames(), ["attr"])
62 self.assertEquals(len(attrs), 1)
63 self.assertTrue("attr" in attrs)
64 self.assertEquals(list(attrs.keys()), ["attr"])
65 self.assertEquals(attrs.get("attr"), "val")
66 self.assertEquals(attrs.get("attr", 25), "val")
67 self.assertEquals(list(attrs.items()), [("attr", "val")])
68 self.assertEquals(list(attrs.values()), ["val"])
69 self.assertEquals(attrs.getValue("attr"), "val")
70 self.assertEquals(attrs.getValueByQName("attr"), "val")
71 self.assertEquals(attrs.getNameByQName("attr"), "attr")
72 self.assertEquals(attrs["attr"], "val")
73 self.assertEquals(attrs.getQNameByName("attr"), "attr")
Lars Gustäbel96753b32000-09-24 12:24:24 +000074
Guido van Rossumd8faa362007-04-27 19:54:29 +000075class MakeParserTest(unittest.TestCase):
76 def test_make_parser2(self):
Lars Gustäbel2fc52942000-10-24 15:35:07 +000077 # Creating parsers several times in a row should succeed.
78 # Testing this because there have been failures of this kind
79 # before.
Thomas Wouters0e3f5912006-08-11 14:57:12 +000080 from xml.sax import make_parser
Lars Gustäbel2fc52942000-10-24 15:35:07 +000081 p = make_parser()
Thomas Wouters0e3f5912006-08-11 14:57:12 +000082 from xml.sax import make_parser
Lars Gustäbel2fc52942000-10-24 15:35:07 +000083 p = make_parser()
Thomas Wouters0e3f5912006-08-11 14:57:12 +000084 from xml.sax import make_parser
Lars Gustäbel2fc52942000-10-24 15:35:07 +000085 p = make_parser()
Thomas Wouters0e3f5912006-08-11 14:57:12 +000086 from xml.sax import make_parser
Lars Gustäbel2fc52942000-10-24 15:35:07 +000087 p = make_parser()
Thomas Wouters0e3f5912006-08-11 14:57:12 +000088 from xml.sax import make_parser
Lars Gustäbel2fc52942000-10-24 15:35:07 +000089 p = make_parser()
Thomas Wouters0e3f5912006-08-11 14:57:12 +000090 from xml.sax import make_parser
Lars Gustäbel2fc52942000-10-24 15:35:07 +000091 p = make_parser()
Tim Petersd2bf3b72001-01-18 02:22:22 +000092
93
Lars Gustäbel96753b32000-09-24 12:24:24 +000094# ===========================================================================
95#
96# saxutils tests
97#
98# ===========================================================================
99
Guido van Rossumd8faa362007-04-27 19:54:29 +0000100class SaxutilsTest(unittest.TestCase):
101 # ===== escape
102 def test_escape_basic(self):
103 self.assertEquals(escape("Donald Duck & Co"), "Donald Duck & Co")
Lars Gustäbel96753b32000-09-24 12:24:24 +0000104
Guido van Rossumd8faa362007-04-27 19:54:29 +0000105 def test_escape_all(self):
106 self.assertEquals(escape("<Donald Duck & Co>"),
107 "&lt;Donald Duck &amp; Co&gt;")
Lars Gustäbel96753b32000-09-24 12:24:24 +0000108
Guido van Rossumd8faa362007-04-27 19:54:29 +0000109 def test_escape_extra(self):
Antoine Pitrou43ffd5c2010-10-27 18:54:06 +0000110 self.assertEquals(escape("Hei på deg", {"å" : "&aring;"}),
Guido van Rossumd8faa362007-04-27 19:54:29 +0000111 "Hei p&aring; deg")
Lars Gustäbel96753b32000-09-24 12:24:24 +0000112
Guido van Rossumd8faa362007-04-27 19:54:29 +0000113 # ===== unescape
114 def test_unescape_basic(self):
115 self.assertEquals(unescape("Donald Duck &amp; Co"), "Donald Duck & Co")
Lars Gustäbel96753b32000-09-24 12:24:24 +0000116
Guido van Rossumd8faa362007-04-27 19:54:29 +0000117 def test_unescape_all(self):
118 self.assertEquals(unescape("&lt;Donald Duck &amp; Co&gt;"),
119 "<Donald Duck & Co>")
Martin v. Löwis74b51ac2002-10-26 14:50:45 +0000120
Guido van Rossumd8faa362007-04-27 19:54:29 +0000121 def test_unescape_extra(self):
Antoine Pitrou43ffd5c2010-10-27 18:54:06 +0000122 self.assertEquals(unescape("Hei på deg", {"å" : "&aring;"}),
Guido van Rossumd8faa362007-04-27 19:54:29 +0000123 "Hei p&aring; deg")
Martin v. Löwis74b51ac2002-10-26 14:50:45 +0000124
Guido van Rossumd8faa362007-04-27 19:54:29 +0000125 def test_unescape_amp_extra(self):
126 self.assertEquals(unescape("&amp;foo;", {"&foo;": "splat"}), "&foo;")
Martin v. Löwis74b51ac2002-10-26 14:50:45 +0000127
Guido van Rossumd8faa362007-04-27 19:54:29 +0000128 # ===== quoteattr
129 def test_quoteattr_basic(self):
130 self.assertEquals(quoteattr("Donald Duck & Co"),
131 '"Donald Duck &amp; Co"')
Martin v. Löwis74b51ac2002-10-26 14:50:45 +0000132
Guido van Rossumd8faa362007-04-27 19:54:29 +0000133 def test_single_quoteattr(self):
134 self.assertEquals(quoteattr('Includes "double" quotes'),
135 '\'Includes "double" quotes\'')
Fred Drake32f3add2002-10-28 17:58:48 +0000136
Guido van Rossumd8faa362007-04-27 19:54:29 +0000137 def test_double_quoteattr(self):
138 self.assertEquals(quoteattr("Includes 'single' quotes"),
139 "\"Includes 'single' quotes\"")
Fred Drakeacd32d32001-07-19 16:10:15 +0000140
Guido van Rossumd8faa362007-04-27 19:54:29 +0000141 def test_single_double_quoteattr(self):
142 self.assertEquals(quoteattr("Includes 'single' and \"double\" quotes"),
143 "\"Includes 'single' and &quot;double&quot; quotes\"")
Fred Drakeacd32d32001-07-19 16:10:15 +0000144
Guido van Rossumd8faa362007-04-27 19:54:29 +0000145 # ===== make_parser
146 def test_make_parser(self):
Martin v. Löwis962c9e72000-10-06 17:41:52 +0000147 # Creating a parser should succeed - it should fall back
148 # to the expatreader
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000149 p = make_parser(['xml.parsers.no_such_parser'])
Martin v. Löwis962c9e72000-10-06 17:41:52 +0000150
151
Lars Gustäbel96753b32000-09-24 12:24:24 +0000152# ===== XMLGenerator
153
154start = '<?xml version="1.0" encoding="iso-8859-1"?>\n'
155
Guido van Rossumd8faa362007-04-27 19:54:29 +0000156class XmlgenTest(unittest.TestCase):
157 def test_xmlgen_basic(self):
158 result = StringIO()
159 gen = XMLGenerator(result)
160 gen.startDocument()
161 gen.startElement("doc", {})
162 gen.endElement("doc")
163 gen.endDocument()
Lars Gustäbel96753b32000-09-24 12:24:24 +0000164
Guido van Rossumd8faa362007-04-27 19:54:29 +0000165 self.assertEquals(result.getvalue(), start + "<doc></doc>")
Lars Gustäbel96753b32000-09-24 12:24:24 +0000166
Guido van Rossumd8faa362007-04-27 19:54:29 +0000167 def test_xmlgen_content(self):
168 result = StringIO()
169 gen = XMLGenerator(result)
Fred Drake004d5e62000-10-23 17:22:08 +0000170
Guido van Rossumd8faa362007-04-27 19:54:29 +0000171 gen.startDocument()
172 gen.startElement("doc", {})
173 gen.characters("huhei")
174 gen.endElement("doc")
175 gen.endDocument()
Lars Gustäbel96753b32000-09-24 12:24:24 +0000176
Guido van Rossumd8faa362007-04-27 19:54:29 +0000177 self.assertEquals(result.getvalue(), start + "<doc>huhei</doc>")
Lars Gustäbel96753b32000-09-24 12:24:24 +0000178
Guido van Rossumd8faa362007-04-27 19:54:29 +0000179 def test_xmlgen_pi(self):
180 result = StringIO()
181 gen = XMLGenerator(result)
Fred Drake004d5e62000-10-23 17:22:08 +0000182
Guido van Rossumd8faa362007-04-27 19:54:29 +0000183 gen.startDocument()
184 gen.processingInstruction("test", "data")
185 gen.startElement("doc", {})
186 gen.endElement("doc")
187 gen.endDocument()
Lars Gustäbel96753b32000-09-24 12:24:24 +0000188
Guido van Rossumd8faa362007-04-27 19:54:29 +0000189 self.assertEquals(result.getvalue(), start + "<?test data?><doc></doc>")
Lars Gustäbel96753b32000-09-24 12:24:24 +0000190
Guido van Rossumd8faa362007-04-27 19:54:29 +0000191 def test_xmlgen_content_escape(self):
192 result = StringIO()
193 gen = XMLGenerator(result)
Fred Drake004d5e62000-10-23 17:22:08 +0000194
Guido van Rossumd8faa362007-04-27 19:54:29 +0000195 gen.startDocument()
196 gen.startElement("doc", {})
197 gen.characters("<huhei&")
198 gen.endElement("doc")
199 gen.endDocument()
Lars Gustäbel96753b32000-09-24 12:24:24 +0000200
Guido van Rossumd8faa362007-04-27 19:54:29 +0000201 self.assertEquals(result.getvalue(),
202 start + "<doc>&lt;huhei&amp;</doc>")
Lars Gustäbel96753b32000-09-24 12:24:24 +0000203
Guido van Rossumd8faa362007-04-27 19:54:29 +0000204 def test_xmlgen_attr_escape(self):
205 result = StringIO()
206 gen = XMLGenerator(result)
Fred Drakec9fadf92001-08-07 19:17:06 +0000207
Guido van Rossumd8faa362007-04-27 19:54:29 +0000208 gen.startDocument()
209 gen.startElement("doc", {"a": '"'})
210 gen.startElement("e", {"a": "'"})
211 gen.endElement("e")
212 gen.startElement("e", {"a": "'\""})
213 gen.endElement("e")
214 gen.startElement("e", {"a": "\n\r\t"})
215 gen.endElement("e")
216 gen.endElement("doc")
217 gen.endDocument()
Fred Drakec9fadf92001-08-07 19:17:06 +0000218
Guido van Rossumd8faa362007-04-27 19:54:29 +0000219 self.assertEquals(result.getvalue(), start +
220 ("<doc a='\"'><e a=\"'\"></e>"
221 "<e a=\"'&quot;\"></e>"
222 "<e a=\"&#10;&#13;&#9;\"></e></doc>"))
Fred Drakec9fadf92001-08-07 19:17:06 +0000223
Guido van Rossumd8faa362007-04-27 19:54:29 +0000224 def test_xmlgen_ignorable(self):
225 result = StringIO()
226 gen = XMLGenerator(result)
Fred Drake004d5e62000-10-23 17:22:08 +0000227
Guido van Rossumd8faa362007-04-27 19:54:29 +0000228 gen.startDocument()
229 gen.startElement("doc", {})
230 gen.ignorableWhitespace(" ")
231 gen.endElement("doc")
232 gen.endDocument()
Lars Gustäbel96753b32000-09-24 12:24:24 +0000233
Guido van Rossumd8faa362007-04-27 19:54:29 +0000234 self.assertEquals(result.getvalue(), start + "<doc> </doc>")
Lars Gustäbel96753b32000-09-24 12:24:24 +0000235
Guido van Rossumd8faa362007-04-27 19:54:29 +0000236 def test_xmlgen_ns(self):
237 result = StringIO()
238 gen = XMLGenerator(result)
Lars Gustäbel96753b32000-09-24 12:24:24 +0000239
Guido van Rossumd8faa362007-04-27 19:54:29 +0000240 gen.startDocument()
241 gen.startPrefixMapping("ns1", ns_uri)
242 gen.startElementNS((ns_uri, "doc"), "ns1:doc", {})
243 # add an unqualified name
244 gen.startElementNS((None, "udoc"), None, {})
245 gen.endElementNS((None, "udoc"), None)
246 gen.endElementNS((ns_uri, "doc"), "ns1:doc")
247 gen.endPrefixMapping("ns1")
248 gen.endDocument()
Fred Drake004d5e62000-10-23 17:22:08 +0000249
Guido van Rossumd8faa362007-04-27 19:54:29 +0000250 self.assertEquals(result.getvalue(), start + \
Martin v. Löwiscf0a1cc2000-10-03 22:35:29 +0000251 ('<ns1:doc xmlns:ns1="%s"><udoc></udoc></ns1:doc>' %
Guido van Rossumd8faa362007-04-27 19:54:29 +0000252 ns_uri))
Lars Gustäbel96753b32000-09-24 12:24:24 +0000253
Guido van Rossumd8faa362007-04-27 19:54:29 +0000254 def test_1463026_1(self):
255 result = StringIO()
256 gen = XMLGenerator(result)
Thomas Wouterscf297e42007-02-23 15:07:44 +0000257
Guido van Rossumd8faa362007-04-27 19:54:29 +0000258 gen.startDocument()
259 gen.startElementNS((None, 'a'), 'a', {(None, 'b'):'c'})
260 gen.endElementNS((None, 'a'), 'a')
261 gen.endDocument()
Thomas Wouterscf297e42007-02-23 15:07:44 +0000262
Guido van Rossumd8faa362007-04-27 19:54:29 +0000263 self.assertEquals(result.getvalue(), start+'<a b="c"></a>')
Thomas Wouterscf297e42007-02-23 15:07:44 +0000264
Guido van Rossumd8faa362007-04-27 19:54:29 +0000265 def test_1463026_2(self):
266 result = StringIO()
267 gen = XMLGenerator(result)
Thomas Wouterscf297e42007-02-23 15:07:44 +0000268
Guido van Rossumd8faa362007-04-27 19:54:29 +0000269 gen.startDocument()
270 gen.startPrefixMapping(None, 'qux')
271 gen.startElementNS(('qux', 'a'), 'a', {})
272 gen.endElementNS(('qux', 'a'), 'a')
273 gen.endPrefixMapping(None)
274 gen.endDocument()
Thomas Wouterscf297e42007-02-23 15:07:44 +0000275
Guido van Rossumd8faa362007-04-27 19:54:29 +0000276 self.assertEquals(result.getvalue(), start+'<a xmlns="qux"></a>')
Thomas Wouterscf297e42007-02-23 15:07:44 +0000277
Guido van Rossumd8faa362007-04-27 19:54:29 +0000278 def test_1463026_3(self):
279 result = StringIO()
280 gen = XMLGenerator(result)
Thomas Wouterscf297e42007-02-23 15:07:44 +0000281
Guido van Rossumd8faa362007-04-27 19:54:29 +0000282 gen.startDocument()
283 gen.startPrefixMapping('my', 'qux')
284 gen.startElementNS(('qux', 'a'), 'a', {(None, 'b'):'c'})
285 gen.endElementNS(('qux', 'a'), 'a')
286 gen.endPrefixMapping('my')
287 gen.endDocument()
Thomas Wouterscf297e42007-02-23 15:07:44 +0000288
Guido van Rossumd8faa362007-04-27 19:54:29 +0000289 self.assertEquals(result.getvalue(),
290 start+'<my:a xmlns:my="qux" b="c"></my:a>')
Lars Gustäbel96753b32000-09-24 12:24:24 +0000291
Antoine Pitrou0619ae72010-10-27 18:37:51 +0000292 def test_5027_1(self):
293 # The xml prefix (as in xml:lang below) is reserved and bound by
294 # definition to http://www.w3.org/XML/1998/namespace. XMLGenerator had
295 # a bug whereby a KeyError is thrown because this namespace is missing
296 # from a dictionary.
297 #
298 # This test demonstrates the bug by parsing a document.
299 test_xml = StringIO(
300 '<?xml version="1.0"?>'
301 '<a:g1 xmlns:a="http://example.com/ns">'
302 '<a:g2 xml:lang="en">Hello</a:g2>'
303 '</a:g1>')
304
305 parser = make_parser()
306 parser.setFeature(feature_namespaces, True)
307 result = StringIO()
308 gen = XMLGenerator(result)
309 parser.setContentHandler(gen)
310 parser.parse(test_xml)
311
312 self.assertEquals(result.getvalue(),
313 start + (
314 '<a:g1 xmlns:a="http://example.com/ns">'
315 '<a:g2 xml:lang="en">Hello</a:g2>'
316 '</a:g1>'))
317
318 def test_5027_2(self):
319 # The xml prefix (as in xml:lang below) is reserved and bound by
320 # definition to http://www.w3.org/XML/1998/namespace. XMLGenerator had
321 # a bug whereby a KeyError is thrown because this namespace is missing
322 # from a dictionary.
323 #
324 # This test demonstrates the bug by direct manipulation of the
325 # XMLGenerator.
326 result = StringIO()
327 gen = XMLGenerator(result)
328
329 gen.startDocument()
330 gen.startPrefixMapping('a', 'http://example.com/ns')
331 gen.startElementNS(('http://example.com/ns', 'g1'), 'g1', {})
332 lang_attr = {('http://www.w3.org/XML/1998/namespace', 'lang'): 'en'}
333 gen.startElementNS(('http://example.com/ns', 'g2'), 'g2', lang_attr)
334 gen.characters('Hello')
335 gen.endElementNS(('http://example.com/ns', 'g2'), 'g2')
336 gen.endElementNS(('http://example.com/ns', 'g1'), 'g1')
337 gen.endPrefixMapping('a')
338 gen.endDocument()
339
340 self.assertEquals(result.getvalue(),
341 start + (
342 '<a:g1 xmlns:a="http://example.com/ns">'
343 '<a:g2 xml:lang="en">Hello</a:g2>'
344 '</a:g1>'))
345
Fred Drake004d5e62000-10-23 17:22:08 +0000346
Guido van Rossumd8faa362007-04-27 19:54:29 +0000347class XMLFilterBaseTest(unittest.TestCase):
348 def test_filter_basic(self):
349 result = StringIO()
350 gen = XMLGenerator(result)
351 filter = XMLFilterBase()
352 filter.setContentHandler(gen)
Lars Gustäbel96753b32000-09-24 12:24:24 +0000353
Guido van Rossumd8faa362007-04-27 19:54:29 +0000354 filter.startDocument()
355 filter.startElement("doc", {})
356 filter.characters("content")
357 filter.ignorableWhitespace(" ")
358 filter.endElement("doc")
359 filter.endDocument()
360
361 self.assertEquals(result.getvalue(), start + "<doc>content </doc>")
Lars Gustäbel96753b32000-09-24 12:24:24 +0000362
363# ===========================================================================
364#
365# expatreader tests
366#
367# ===========================================================================
368
Skip Montanaro7a98be22007-08-16 14:35:24 +0000369xml_test_out = open(findfile("test.xml.out")).read()
Lars Gustäbelb7536d52000-09-24 18:53:56 +0000370
Guido van Rossumd8faa362007-04-27 19:54:29 +0000371class ExpatReaderTest(XmlTestBase):
Lars Gustäbelb7536d52000-09-24 18:53:56 +0000372
Guido van Rossumd8faa362007-04-27 19:54:29 +0000373 # ===== XMLReader support
Lars Gustäbelb7536d52000-09-24 18:53:56 +0000374
Guido van Rossumd8faa362007-04-27 19:54:29 +0000375 def test_expat_file(self):
376 parser = create_parser()
377 result = StringIO()
378 xmlgen = XMLGenerator(result)
Lars Gustäbelb7536d52000-09-24 18:53:56 +0000379
Guido van Rossumd8faa362007-04-27 19:54:29 +0000380 parser.setContentHandler(xmlgen)
Skip Montanaro7a98be22007-08-16 14:35:24 +0000381 parser.parse(open(findfile("test.xml")))
Lars Gustäbelb7536d52000-09-24 18:53:56 +0000382
Guido van Rossumd8faa362007-04-27 19:54:29 +0000383 self.assertEquals(result.getvalue(), xml_test_out)
Lars Gustäbelb7536d52000-09-24 18:53:56 +0000384
Guido van Rossumd8faa362007-04-27 19:54:29 +0000385 # ===== DTDHandler support
Lars Gustäbelb7536d52000-09-24 18:53:56 +0000386
Guido van Rossumd8faa362007-04-27 19:54:29 +0000387 class TestDTDHandler:
Lars Gustäbelb7536d52000-09-24 18:53:56 +0000388
Guido van Rossumd8faa362007-04-27 19:54:29 +0000389 def __init__(self):
390 self._notations = []
391 self._entities = []
Lars Gustäbelb7536d52000-09-24 18:53:56 +0000392
Guido van Rossumd8faa362007-04-27 19:54:29 +0000393 def notationDecl(self, name, publicId, systemId):
394 self._notations.append((name, publicId, systemId))
Lars Gustäbelb7536d52000-09-24 18:53:56 +0000395
Guido van Rossumd8faa362007-04-27 19:54:29 +0000396 def unparsedEntityDecl(self, name, publicId, systemId, ndata):
397 self._entities.append((name, publicId, systemId, ndata))
Lars Gustäbel2fc52942000-10-24 15:35:07 +0000398
Guido van Rossumd8faa362007-04-27 19:54:29 +0000399 def test_expat_dtdhandler(self):
400 parser = create_parser()
401 handler = self.TestDTDHandler()
402 parser.setDTDHandler(handler)
Lars Gustäbel2fc52942000-10-24 15:35:07 +0000403
Guido van Rossumd8faa362007-04-27 19:54:29 +0000404 parser.feed('<!DOCTYPE doc [\n')
405 parser.feed(' <!ENTITY img SYSTEM "expat.gif" NDATA GIF>\n')
406 parser.feed(' <!NOTATION GIF PUBLIC "-//CompuServe//NOTATION Graphics Interchange Format 89a//EN">\n')
407 parser.feed(']>\n')
408 parser.feed('<doc></doc>')
409 parser.close()
Lars Gustäbel2fc52942000-10-24 15:35:07 +0000410
Guido van Rossumd8faa362007-04-27 19:54:29 +0000411 self.assertEquals(handler._notations,
412 [("GIF", "-//CompuServe//NOTATION Graphics Interchange Format 89a//EN", None)])
413 self.assertEquals(handler._entities, [("img", None, "expat.gif", "GIF")])
Lars Gustäbel2fc52942000-10-24 15:35:07 +0000414
Guido van Rossumd8faa362007-04-27 19:54:29 +0000415 # ===== EntityResolver support
Lars Gustäbel2fc52942000-10-24 15:35:07 +0000416
Guido van Rossumd8faa362007-04-27 19:54:29 +0000417 class TestEntityResolver:
Lars Gustäbel2fc52942000-10-24 15:35:07 +0000418
Guido van Rossumd8faa362007-04-27 19:54:29 +0000419 def resolveEntity(self, publicId, systemId):
420 inpsrc = InputSource()
421 inpsrc.setByteStream(StringIO("<entity/>"))
422 return inpsrc
Lars Gustäbel2fc52942000-10-24 15:35:07 +0000423
Guido van Rossumd8faa362007-04-27 19:54:29 +0000424 def test_expat_entityresolver(self):
425 parser = create_parser()
426 parser.setEntityResolver(self.TestEntityResolver())
427 result = StringIO()
428 parser.setContentHandler(XMLGenerator(result))
Lars Gustäbel2fc52942000-10-24 15:35:07 +0000429
Guido van Rossumd8faa362007-04-27 19:54:29 +0000430 parser.feed('<!DOCTYPE doc [\n')
431 parser.feed(' <!ENTITY test SYSTEM "whatever">\n')
432 parser.feed(']>\n')
433 parser.feed('<doc>&test;</doc>')
434 parser.close()
Lars Gustäbel2fc52942000-10-24 15:35:07 +0000435
Guido van Rossumd8faa362007-04-27 19:54:29 +0000436 self.assertEquals(result.getvalue(), start +
437 "<doc><entity></entity></doc>")
Lars Gustäbel2fc52942000-10-24 15:35:07 +0000438
Guido van Rossumd8faa362007-04-27 19:54:29 +0000439 # ===== Attributes support
Lars Gustäbel2fc52942000-10-24 15:35:07 +0000440
Guido van Rossumd8faa362007-04-27 19:54:29 +0000441 class AttrGatherer(ContentHandler):
Lars Gustäbel2fc52942000-10-24 15:35:07 +0000442
Guido van Rossumd8faa362007-04-27 19:54:29 +0000443 def startElement(self, name, attrs):
444 self._attrs = attrs
Lars Gustäbel2fc52942000-10-24 15:35:07 +0000445
Guido van Rossumd8faa362007-04-27 19:54:29 +0000446 def startElementNS(self, name, qname, attrs):
447 self._attrs = attrs
Lars Gustäbel2fc52942000-10-24 15:35:07 +0000448
Guido van Rossumd8faa362007-04-27 19:54:29 +0000449 def test_expat_attrs_empty(self):
450 parser = create_parser()
451 gather = self.AttrGatherer()
452 parser.setContentHandler(gather)
453
454 parser.feed("<doc/>")
455 parser.close()
456
457 self.verify_empty_attrs(gather._attrs)
458
459 def test_expat_attrs_wattr(self):
460 parser = create_parser()
461 gather = self.AttrGatherer()
462 parser.setContentHandler(gather)
463
464 parser.feed("<doc attr='val'/>")
465 parser.close()
466
467 self.verify_attrs_wattr(gather._attrs)
468
469 def test_expat_nsattrs_empty(self):
470 parser = create_parser(1)
471 gather = self.AttrGatherer()
472 parser.setContentHandler(gather)
473
474 parser.feed("<doc/>")
475 parser.close()
476
477 self.verify_empty_nsattrs(gather._attrs)
478
479 def test_expat_nsattrs_wattr(self):
480 parser = create_parser(1)
481 gather = self.AttrGatherer()
482 parser.setContentHandler(gather)
483
484 parser.feed("<doc xmlns:ns='%s' ns:attr='val'/>" % ns_uri)
485 parser.close()
486
487 attrs = gather._attrs
488
489 self.assertEquals(attrs.getLength(), 1)
490 self.assertEquals(attrs.getNames(), [(ns_uri, "attr")])
491 self.assertTrue((attrs.getQNames() == [] or
492 attrs.getQNames() == ["ns:attr"]))
493 self.assertEquals(len(attrs), 1)
494 self.assertTrue((ns_uri, "attr") in attrs)
495 self.assertEquals(attrs.get((ns_uri, "attr")), "val")
496 self.assertEquals(attrs.get((ns_uri, "attr"), 25), "val")
497 self.assertEquals(list(attrs.items()), [((ns_uri, "attr"), "val")])
498 self.assertEquals(list(attrs.values()), ["val"])
499 self.assertEquals(attrs.getValue((ns_uri, "attr")), "val")
500 self.assertEquals(attrs[(ns_uri, "attr")], "val")
501
502 # ===== InputSource support
503
Benjamin Petersona7f4f5a2008-09-04 02:22:52 +0000504 def test_expat_inpsource_filename(self):
Guido van Rossumd8faa362007-04-27 19:54:29 +0000505 parser = create_parser()
506 result = StringIO()
507 xmlgen = XMLGenerator(result)
508
509 parser.setContentHandler(xmlgen)
Skip Montanaro7a98be22007-08-16 14:35:24 +0000510 parser.parse(findfile("test.xml"))
Guido van Rossumd8faa362007-04-27 19:54:29 +0000511
512 self.assertEquals(result.getvalue(), xml_test_out)
513
Benjamin Petersona7f4f5a2008-09-04 02:22:52 +0000514 def test_expat_inpsource_sysid(self):
Guido van Rossumd8faa362007-04-27 19:54:29 +0000515 parser = create_parser()
516 result = StringIO()
517 xmlgen = XMLGenerator(result)
518
519 parser.setContentHandler(xmlgen)
Skip Montanaro7a98be22007-08-16 14:35:24 +0000520 parser.parse(InputSource(findfile("test.xml")))
Guido van Rossumd8faa362007-04-27 19:54:29 +0000521
522 self.assertEquals(result.getvalue(), xml_test_out)
523
524 def test_expat_inpsource_stream(self):
525 parser = create_parser()
526 result = StringIO()
527 xmlgen = XMLGenerator(result)
528
529 parser.setContentHandler(xmlgen)
530 inpsrc = InputSource()
Skip Montanaro7a98be22007-08-16 14:35:24 +0000531 inpsrc.setByteStream(open(findfile("test.xml")))
Guido van Rossumd8faa362007-04-27 19:54:29 +0000532 parser.parse(inpsrc)
533
534 self.assertEquals(result.getvalue(), xml_test_out)
535
536 # ===== IncrementalParser support
537
538 def test_expat_incremental(self):
539 result = StringIO()
540 xmlgen = XMLGenerator(result)
541 parser = create_parser()
542 parser.setContentHandler(xmlgen)
543
544 parser.feed("<doc>")
545 parser.feed("</doc>")
546 parser.close()
547
548 self.assertEquals(result.getvalue(), start + "<doc></doc>")
549
550 def test_expat_incremental_reset(self):
551 result = StringIO()
552 xmlgen = XMLGenerator(result)
553 parser = create_parser()
554 parser.setContentHandler(xmlgen)
555
556 parser.feed("<doc>")
557 parser.feed("text")
558
559 result = StringIO()
560 xmlgen = XMLGenerator(result)
561 parser.setContentHandler(xmlgen)
562 parser.reset()
563
564 parser.feed("<doc>")
565 parser.feed("text")
566 parser.feed("</doc>")
567 parser.close()
568
569 self.assertEquals(result.getvalue(), start + "<doc>text</doc>")
570
571 # ===== Locator support
572
573 def test_expat_locator_noinfo(self):
574 result = StringIO()
575 xmlgen = XMLGenerator(result)
576 parser = create_parser()
577 parser.setContentHandler(xmlgen)
578
579 parser.feed("<doc>")
580 parser.feed("</doc>")
581 parser.close()
582
583 self.assertEquals(parser.getSystemId(), None)
584 self.assertEquals(parser.getPublicId(), None)
585 self.assertEquals(parser.getLineNumber(), 1)
586
Benjamin Petersona7f4f5a2008-09-04 02:22:52 +0000587 def test_expat_locator_withinfo(self):
Guido van Rossumd8faa362007-04-27 19:54:29 +0000588 result = StringIO()
589 xmlgen = XMLGenerator(result)
590 parser = create_parser()
591 parser.setContentHandler(xmlgen)
592 parser.parse(findfile("test.xml"))
593
594 self.assertEquals(parser.getSystemId(), findfile("test.xml"))
595 self.assertEquals(parser.getPublicId(), None)
Lars Gustäbel2fc52942000-10-24 15:35:07 +0000596
Martin v. Löwis80670bc2000-10-06 21:13:23 +0000597
598# ===========================================================================
599#
600# error reporting
601#
602# ===========================================================================
603
Guido van Rossumd8faa362007-04-27 19:54:29 +0000604class ErrorReportingTest(unittest.TestCase):
605 def test_expat_inpsource_location(self):
606 parser = create_parser()
607 parser.setContentHandler(ContentHandler()) # do nothing
608 source = InputSource()
609 source.setByteStream(StringIO("<foo bar foobar>")) #ill-formed
610 name = "a file name"
611 source.setSystemId(name)
612 try:
613 parser.parse(source)
614 self.fail()
615 except SAXException as e:
616 self.assertEquals(e.getSystemId(), name)
Martin v. Löwis80670bc2000-10-06 21:13:23 +0000617
Guido van Rossumd8faa362007-04-27 19:54:29 +0000618 def test_expat_incomplete(self):
619 parser = create_parser()
620 parser.setContentHandler(ContentHandler()) # do nothing
621 self.assertRaises(SAXParseException, parser.parse, StringIO("<foo>"))
Martin v. Löwis80670bc2000-10-06 21:13:23 +0000622
Guido van Rossumd8faa362007-04-27 19:54:29 +0000623 def test_sax_parse_exception_str(self):
624 # pass various values from a locator to the SAXParseException to
625 # make sure that the __str__() doesn't fall apart when None is
626 # passed instead of an integer line and column number
627 #
628 # use "normal" values for the locator:
629 str(SAXParseException("message", None,
630 self.DummyLocator(1, 1)))
631 # use None for the line number:
632 str(SAXParseException("message", None,
633 self.DummyLocator(None, 1)))
634 # use None for the column number:
635 str(SAXParseException("message", None,
636 self.DummyLocator(1, None)))
637 # use None for both:
638 str(SAXParseException("message", None,
639 self.DummyLocator(None, None)))
Fred Drake6fd0b0d2004-03-20 08:15:30 +0000640
Guido van Rossumd8faa362007-04-27 19:54:29 +0000641 class DummyLocator:
642 def __init__(self, lineno, colno):
643 self._lineno = lineno
644 self._colno = colno
Fred Drake6fd0b0d2004-03-20 08:15:30 +0000645
Guido van Rossumd8faa362007-04-27 19:54:29 +0000646 def getPublicId(self):
647 return "pubid"
Fred Drake6fd0b0d2004-03-20 08:15:30 +0000648
Guido van Rossumd8faa362007-04-27 19:54:29 +0000649 def getSystemId(self):
650 return "sysid"
Fred Drake6fd0b0d2004-03-20 08:15:30 +0000651
Guido van Rossumd8faa362007-04-27 19:54:29 +0000652 def getLineNumber(self):
653 return self._lineno
Fred Drake6fd0b0d2004-03-20 08:15:30 +0000654
Guido van Rossumd8faa362007-04-27 19:54:29 +0000655 def getColumnNumber(self):
656 return self._colno
Martin v. Löwis80670bc2000-10-06 21:13:23 +0000657
Lars Gustäbelab647872000-09-24 18:40:52 +0000658# ===========================================================================
659#
660# xmlreader tests
661#
662# ===========================================================================
663
Guido van Rossumd8faa362007-04-27 19:54:29 +0000664class XmlReaderTest(XmlTestBase):
Lars Gustäbelab647872000-09-24 18:40:52 +0000665
Guido van Rossumd8faa362007-04-27 19:54:29 +0000666 # ===== AttributesImpl
667 def test_attrs_empty(self):
668 self.verify_empty_attrs(AttributesImpl({}))
Lars Gustäbelab647872000-09-24 18:40:52 +0000669
Guido van Rossumd8faa362007-04-27 19:54:29 +0000670 def test_attrs_wattr(self):
671 self.verify_attrs_wattr(AttributesImpl({"attr" : "val"}))
Lars Gustäbelab647872000-09-24 18:40:52 +0000672
Guido van Rossumd8faa362007-04-27 19:54:29 +0000673 def test_nsattrs_empty(self):
674 self.verify_empty_nsattrs(AttributesNSImpl({}, {}))
Lars Gustäbelab647872000-09-24 18:40:52 +0000675
Guido van Rossumd8faa362007-04-27 19:54:29 +0000676 def test_nsattrs_wattr(self):
677 attrs = AttributesNSImpl({(ns_uri, "attr") : "val"},
678 {(ns_uri, "attr") : "ns:attr"})
Fred Drake004d5e62000-10-23 17:22:08 +0000679
Guido van Rossumd8faa362007-04-27 19:54:29 +0000680 self.assertEquals(attrs.getLength(), 1)
681 self.assertEquals(attrs.getNames(), [(ns_uri, "attr")])
682 self.assertEquals(attrs.getQNames(), ["ns:attr"])
683 self.assertEquals(len(attrs), 1)
684 self.assertTrue((ns_uri, "attr") in attrs)
685 self.assertEquals(list(attrs.keys()), [(ns_uri, "attr")])
686 self.assertEquals(attrs.get((ns_uri, "attr")), "val")
687 self.assertEquals(attrs.get((ns_uri, "attr"), 25), "val")
688 self.assertEquals(list(attrs.items()), [((ns_uri, "attr"), "val")])
689 self.assertEquals(list(attrs.values()), ["val"])
690 self.assertEquals(attrs.getValue((ns_uri, "attr")), "val")
691 self.assertEquals(attrs.getValueByQName("ns:attr"), "val")
692 self.assertEquals(attrs.getNameByQName("ns:attr"), (ns_uri, "attr"))
693 self.assertEquals(attrs[(ns_uri, "attr")], "val")
694 self.assertEquals(attrs.getQNameByName((ns_uri, "attr")), "ns:attr")
Fred Drake004d5e62000-10-23 17:22:08 +0000695
Lars Gustäbelab647872000-09-24 18:40:52 +0000696
Guido van Rossumd8faa362007-04-27 19:54:29 +0000697 # During the development of Python 2.5, an attempt to move the "xml"
698 # package implementation to a new package ("xmlcore") proved painful.
699 # The goal of this change was to allow applications to be able to
700 # obtain and rely on behavior in the standard library implementation
701 # of the XML support without needing to be concerned about the
702 # availability of the PyXML implementation.
703 #
704 # While the existing import hackery in Lib/xml/__init__.py can cause
705 # PyXML's _xmlpus package to supplant the "xml" package, that only
706 # works because either implementation uses the "xml" package name for
707 # imports.
708 #
709 # The move resulted in a number of problems related to the fact that
710 # the import machinery's "package context" is based on the name that's
711 # being imported rather than the __name__ of the actual package
712 # containment; it wasn't possible for the "xml" package to be replaced
713 # by a simple module that indirected imports to the "xmlcore" package.
714 #
715 # The following two tests exercised bugs that were introduced in that
716 # attempt. Keeping these tests around will help detect problems with
717 # other attempts to provide reliable access to the standard library's
718 # implementation of the XML support.
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000719
Guido van Rossumd8faa362007-04-27 19:54:29 +0000720 def test_sf_1511497(self):
721 # Bug report: http://www.python.org/sf/1511497
722 import sys
723 old_modules = sys.modules.copy()
724 for modname in list(sys.modules.keys()):
725 if modname.startswith("xml."):
726 del sys.modules[modname]
727 try:
728 import xml.sax.expatreader
729 module = xml.sax.expatreader
730 self.assertEquals(module.__name__, "xml.sax.expatreader")
731 finally:
732 sys.modules.update(old_modules)
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000733
Guido van Rossumd8faa362007-04-27 19:54:29 +0000734 def test_sf_1513611(self):
735 # Bug report: http://www.python.org/sf/1513611
736 sio = StringIO("invalid")
737 parser = make_parser()
738 from xml.sax import SAXParseException
739 self.assertRaises(SAXParseException, parser.parse, sio)
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000740
Lars Gustäbel96753b32000-09-24 12:24:24 +0000741
Christian Heimesbbe741d2008-03-28 10:53:29 +0000742def test_main():
Guido van Rossumd8faa362007-04-27 19:54:29 +0000743 run_unittest(MakeParserTest,
744 SaxutilsTest,
745 XmlgenTest,
746 ExpatReaderTest,
747 ErrorReportingTest,
748 XmlReaderTest)
Lars Gustäbelb7536d52000-09-24 18:53:56 +0000749
Guido van Rossumd8faa362007-04-27 19:54:29 +0000750if __name__ == "__main__":
Christian Heimesbbe741d2008-03-28 10:53:29 +0000751 test_main()