blob: 9b28b3fa106bac1eba244a8122315c639bb3c378 [file] [log] [blame]
Martin v. Löwisa729daf2002-08-04 17:28:33 +00001# regression test for SAX 2.0 -*- coding: iso-8859-1 -*-
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
14from xml.sax.xmlreader import InputSource, AttributesImpl, AttributesNSImpl
Guido van Rossum34d19282007-08-09 01:03:29 +000015from io import StringIO
Benjamin Petersonee8712c2008-05-20 21:35:26 +000016from test.support import findfile, run_unittest
Guido van Rossumd8faa362007-04-27 19:54:29 +000017import unittest
Florent Xiclunaf15351d2010-03-13 23:24:31 +000018
19TEST_XMLFILE = findfile("test.xml", subdir="xmltestdata")
20TEST_XMLFILE_OUT = findfile("test.xml.out", subdir="xmltestdata")
Lars Gustäbel96753b32000-09-24 12:24:24 +000021
Guido van Rossumd8faa362007-04-27 19:54:29 +000022ns_uri = "http://www.python.org/xml-ns/saxtest/"
Lars Gustäbel96753b32000-09-24 12:24:24 +000023
Guido van Rossumd8faa362007-04-27 19:54:29 +000024class XmlTestBase(unittest.TestCase):
25 def verify_empty_attrs(self, attrs):
26 self.assertRaises(KeyError, attrs.getValue, "attr")
27 self.assertRaises(KeyError, attrs.getValueByQName, "attr")
28 self.assertRaises(KeyError, attrs.getNameByQName, "attr")
29 self.assertRaises(KeyError, attrs.getQNameByName, "attr")
30 self.assertRaises(KeyError, attrs.__getitem__, "attr")
31 self.assertEquals(attrs.getLength(), 0)
32 self.assertEquals(attrs.getNames(), [])
33 self.assertEquals(attrs.getQNames(), [])
34 self.assertEquals(len(attrs), 0)
Ezio Melottib58e0bd2010-01-23 15:40:09 +000035 self.assertNotIn("attr", attrs)
Guido van Rossumd8faa362007-04-27 19:54:29 +000036 self.assertEquals(list(attrs.keys()), [])
37 self.assertEquals(attrs.get("attrs"), None)
38 self.assertEquals(attrs.get("attrs", 25), 25)
39 self.assertEquals(list(attrs.items()), [])
40 self.assertEquals(list(attrs.values()), [])
Lars Gustäbel96753b32000-09-24 12:24:24 +000041
Guido van Rossumd8faa362007-04-27 19:54:29 +000042 def verify_empty_nsattrs(self, attrs):
43 self.assertRaises(KeyError, attrs.getValue, (ns_uri, "attr"))
44 self.assertRaises(KeyError, attrs.getValueByQName, "ns:attr")
45 self.assertRaises(KeyError, attrs.getNameByQName, "ns:attr")
46 self.assertRaises(KeyError, attrs.getQNameByName, (ns_uri, "attr"))
47 self.assertRaises(KeyError, attrs.__getitem__, (ns_uri, "attr"))
48 self.assertEquals(attrs.getLength(), 0)
49 self.assertEquals(attrs.getNames(), [])
50 self.assertEquals(attrs.getQNames(), [])
51 self.assertEquals(len(attrs), 0)
Ezio Melottib58e0bd2010-01-23 15:40:09 +000052 self.assertNotIn((ns_uri, "attr"), attrs)
Guido van Rossumd8faa362007-04-27 19:54:29 +000053 self.assertEquals(list(attrs.keys()), [])
54 self.assertEquals(attrs.get((ns_uri, "attr")), None)
55 self.assertEquals(attrs.get((ns_uri, "attr"), 25), 25)
56 self.assertEquals(list(attrs.items()), [])
57 self.assertEquals(list(attrs.values()), [])
Lars Gustäbel96753b32000-09-24 12:24:24 +000058
Guido van Rossumd8faa362007-04-27 19:54:29 +000059 def verify_attrs_wattr(self, attrs):
60 self.assertEquals(attrs.getLength(), 1)
61 self.assertEquals(attrs.getNames(), ["attr"])
62 self.assertEquals(attrs.getQNames(), ["attr"])
63 self.assertEquals(len(attrs), 1)
Benjamin Peterson577473f2010-01-19 00:09:57 +000064 self.assertIn("attr", attrs)
Guido van Rossumd8faa362007-04-27 19:54:29 +000065 self.assertEquals(list(attrs.keys()), ["attr"])
66 self.assertEquals(attrs.get("attr"), "val")
67 self.assertEquals(attrs.get("attr", 25), "val")
68 self.assertEquals(list(attrs.items()), [("attr", "val")])
69 self.assertEquals(list(attrs.values()), ["val"])
70 self.assertEquals(attrs.getValue("attr"), "val")
71 self.assertEquals(attrs.getValueByQName("attr"), "val")
72 self.assertEquals(attrs.getNameByQName("attr"), "attr")
73 self.assertEquals(attrs["attr"], "val")
74 self.assertEquals(attrs.getQNameByName("attr"), "attr")
Lars Gustäbel96753b32000-09-24 12:24:24 +000075
Guido van Rossumd8faa362007-04-27 19:54:29 +000076class MakeParserTest(unittest.TestCase):
77 def test_make_parser2(self):
Lars Gustäbel2fc52942000-10-24 15:35:07 +000078 # Creating parsers several times in a row should succeed.
79 # Testing this because there have been failures of this kind
80 # before.
Thomas Wouters0e3f5912006-08-11 14:57:12 +000081 from xml.sax import make_parser
Lars Gustäbel2fc52942000-10-24 15:35:07 +000082 p = make_parser()
Thomas Wouters0e3f5912006-08-11 14:57:12 +000083 from xml.sax import make_parser
Lars Gustäbel2fc52942000-10-24 15:35:07 +000084 p = make_parser()
Thomas Wouters0e3f5912006-08-11 14:57:12 +000085 from xml.sax import make_parser
Lars Gustäbel2fc52942000-10-24 15:35:07 +000086 p = make_parser()
Thomas Wouters0e3f5912006-08-11 14:57:12 +000087 from xml.sax import make_parser
Lars Gustäbel2fc52942000-10-24 15:35:07 +000088 p = make_parser()
Thomas Wouters0e3f5912006-08-11 14:57:12 +000089 from xml.sax import make_parser
Lars Gustäbel2fc52942000-10-24 15:35:07 +000090 p = make_parser()
Thomas Wouters0e3f5912006-08-11 14:57:12 +000091 from xml.sax import make_parser
Lars Gustäbel2fc52942000-10-24 15:35:07 +000092 p = make_parser()
Tim Petersd2bf3b72001-01-18 02:22:22 +000093
94
Lars Gustäbel96753b32000-09-24 12:24:24 +000095# ===========================================================================
96#
97# saxutils tests
98#
99# ===========================================================================
100
Guido van Rossumd8faa362007-04-27 19:54:29 +0000101class SaxutilsTest(unittest.TestCase):
102 # ===== escape
103 def test_escape_basic(self):
104 self.assertEquals(escape("Donald Duck & Co"), "Donald Duck & Co")
Lars Gustäbel96753b32000-09-24 12:24:24 +0000105
Guido van Rossumd8faa362007-04-27 19:54:29 +0000106 def test_escape_all(self):
107 self.assertEquals(escape("<Donald Duck & Co>"),
108 "&lt;Donald Duck &amp; Co&gt;")
Lars Gustäbel96753b32000-09-24 12:24:24 +0000109
Guido van Rossumd8faa362007-04-27 19:54:29 +0000110 def test_escape_extra(self):
111 self.assertEquals(escape("Hei på deg", {"å" : "&aring;"}),
112 "Hei p&aring; deg")
Lars Gustäbel96753b32000-09-24 12:24:24 +0000113
Guido van Rossumd8faa362007-04-27 19:54:29 +0000114 # ===== unescape
115 def test_unescape_basic(self):
116 self.assertEquals(unescape("Donald Duck &amp; Co"), "Donald Duck & Co")
Lars Gustäbel96753b32000-09-24 12:24:24 +0000117
Guido van Rossumd8faa362007-04-27 19:54:29 +0000118 def test_unescape_all(self):
119 self.assertEquals(unescape("&lt;Donald Duck &amp; Co&gt;"),
120 "<Donald Duck & Co>")
Martin v. Löwis74b51ac2002-10-26 14:50:45 +0000121
Guido van Rossumd8faa362007-04-27 19:54:29 +0000122 def test_unescape_extra(self):
123 self.assertEquals(unescape("Hei på deg", {"å" : "&aring;"}),
124 "Hei p&aring; deg")
Martin v. Löwis74b51ac2002-10-26 14:50:45 +0000125
Guido van Rossumd8faa362007-04-27 19:54:29 +0000126 def test_unescape_amp_extra(self):
127 self.assertEquals(unescape("&amp;foo;", {"&foo;": "splat"}), "&foo;")
Martin v. Löwis74b51ac2002-10-26 14:50:45 +0000128
Guido van Rossumd8faa362007-04-27 19:54:29 +0000129 # ===== quoteattr
130 def test_quoteattr_basic(self):
131 self.assertEquals(quoteattr("Donald Duck & Co"),
132 '"Donald Duck &amp; Co"')
Martin v. Löwis74b51ac2002-10-26 14:50:45 +0000133
Guido van Rossumd8faa362007-04-27 19:54:29 +0000134 def test_single_quoteattr(self):
135 self.assertEquals(quoteattr('Includes "double" quotes'),
136 '\'Includes "double" quotes\'')
Fred Drake32f3add2002-10-28 17:58:48 +0000137
Guido van Rossumd8faa362007-04-27 19:54:29 +0000138 def test_double_quoteattr(self):
139 self.assertEquals(quoteattr("Includes 'single' quotes"),
140 "\"Includes 'single' quotes\"")
Fred Drakeacd32d32001-07-19 16:10:15 +0000141
Guido van Rossumd8faa362007-04-27 19:54:29 +0000142 def test_single_double_quoteattr(self):
143 self.assertEquals(quoteattr("Includes 'single' and \"double\" quotes"),
144 "\"Includes 'single' and &quot;double&quot; quotes\"")
Fred Drakeacd32d32001-07-19 16:10:15 +0000145
Guido van Rossumd8faa362007-04-27 19:54:29 +0000146 # ===== make_parser
147 def test_make_parser(self):
Martin v. Löwis962c9e72000-10-06 17:41:52 +0000148 # Creating a parser should succeed - it should fall back
149 # to the expatreader
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000150 p = make_parser(['xml.parsers.no_such_parser'])
Martin v. Löwis962c9e72000-10-06 17:41:52 +0000151
152
Lars Gustäbel96753b32000-09-24 12:24:24 +0000153# ===== XMLGenerator
154
155start = '<?xml version="1.0" encoding="iso-8859-1"?>\n'
156
Guido van Rossumd8faa362007-04-27 19:54:29 +0000157class XmlgenTest(unittest.TestCase):
158 def test_xmlgen_basic(self):
159 result = StringIO()
160 gen = XMLGenerator(result)
161 gen.startDocument()
162 gen.startElement("doc", {})
163 gen.endElement("doc")
164 gen.endDocument()
Lars Gustäbel96753b32000-09-24 12:24:24 +0000165
Guido van Rossumd8faa362007-04-27 19:54:29 +0000166 self.assertEquals(result.getvalue(), start + "<doc></doc>")
Lars Gustäbel96753b32000-09-24 12:24:24 +0000167
Guido van Rossumd8faa362007-04-27 19:54:29 +0000168 def test_xmlgen_content(self):
169 result = StringIO()
170 gen = XMLGenerator(result)
Fred Drake004d5e62000-10-23 17:22:08 +0000171
Guido van Rossumd8faa362007-04-27 19:54:29 +0000172 gen.startDocument()
173 gen.startElement("doc", {})
174 gen.characters("huhei")
175 gen.endElement("doc")
176 gen.endDocument()
Lars Gustäbel96753b32000-09-24 12:24:24 +0000177
Guido van Rossumd8faa362007-04-27 19:54:29 +0000178 self.assertEquals(result.getvalue(), start + "<doc>huhei</doc>")
Lars Gustäbel96753b32000-09-24 12:24:24 +0000179
Guido van Rossumd8faa362007-04-27 19:54:29 +0000180 def test_xmlgen_pi(self):
181 result = StringIO()
182 gen = XMLGenerator(result)
Fred Drake004d5e62000-10-23 17:22:08 +0000183
Guido van Rossumd8faa362007-04-27 19:54:29 +0000184 gen.startDocument()
185 gen.processingInstruction("test", "data")
186 gen.startElement("doc", {})
187 gen.endElement("doc")
188 gen.endDocument()
Lars Gustäbel96753b32000-09-24 12:24:24 +0000189
Guido van Rossumd8faa362007-04-27 19:54:29 +0000190 self.assertEquals(result.getvalue(), start + "<?test data?><doc></doc>")
Lars Gustäbel96753b32000-09-24 12:24:24 +0000191
Guido van Rossumd8faa362007-04-27 19:54:29 +0000192 def test_xmlgen_content_escape(self):
193 result = StringIO()
194 gen = XMLGenerator(result)
Fred Drake004d5e62000-10-23 17:22:08 +0000195
Guido van Rossumd8faa362007-04-27 19:54:29 +0000196 gen.startDocument()
197 gen.startElement("doc", {})
198 gen.characters("<huhei&")
199 gen.endElement("doc")
200 gen.endDocument()
Lars Gustäbel96753b32000-09-24 12:24:24 +0000201
Guido van Rossumd8faa362007-04-27 19:54:29 +0000202 self.assertEquals(result.getvalue(),
203 start + "<doc>&lt;huhei&amp;</doc>")
Lars Gustäbel96753b32000-09-24 12:24:24 +0000204
Guido van Rossumd8faa362007-04-27 19:54:29 +0000205 def test_xmlgen_attr_escape(self):
206 result = StringIO()
207 gen = XMLGenerator(result)
Fred Drakec9fadf92001-08-07 19:17:06 +0000208
Guido van Rossumd8faa362007-04-27 19:54:29 +0000209 gen.startDocument()
210 gen.startElement("doc", {"a": '"'})
211 gen.startElement("e", {"a": "'"})
212 gen.endElement("e")
213 gen.startElement("e", {"a": "'\""})
214 gen.endElement("e")
215 gen.startElement("e", {"a": "\n\r\t"})
216 gen.endElement("e")
217 gen.endElement("doc")
218 gen.endDocument()
Fred Drakec9fadf92001-08-07 19:17:06 +0000219
Guido van Rossumd8faa362007-04-27 19:54:29 +0000220 self.assertEquals(result.getvalue(), start +
221 ("<doc a='\"'><e a=\"'\"></e>"
222 "<e a=\"'&quot;\"></e>"
223 "<e a=\"&#10;&#13;&#9;\"></e></doc>"))
Fred Drakec9fadf92001-08-07 19:17:06 +0000224
Guido van Rossumd8faa362007-04-27 19:54:29 +0000225 def test_xmlgen_ignorable(self):
226 result = StringIO()
227 gen = XMLGenerator(result)
Fred Drake004d5e62000-10-23 17:22:08 +0000228
Guido van Rossumd8faa362007-04-27 19:54:29 +0000229 gen.startDocument()
230 gen.startElement("doc", {})
231 gen.ignorableWhitespace(" ")
232 gen.endElement("doc")
233 gen.endDocument()
Lars Gustäbel96753b32000-09-24 12:24:24 +0000234
Guido van Rossumd8faa362007-04-27 19:54:29 +0000235 self.assertEquals(result.getvalue(), start + "<doc> </doc>")
Lars Gustäbel96753b32000-09-24 12:24:24 +0000236
Guido van Rossumd8faa362007-04-27 19:54:29 +0000237 def test_xmlgen_ns(self):
238 result = StringIO()
239 gen = XMLGenerator(result)
Lars Gustäbel96753b32000-09-24 12:24:24 +0000240
Guido van Rossumd8faa362007-04-27 19:54:29 +0000241 gen.startDocument()
242 gen.startPrefixMapping("ns1", ns_uri)
243 gen.startElementNS((ns_uri, "doc"), "ns1:doc", {})
244 # add an unqualified name
245 gen.startElementNS((None, "udoc"), None, {})
246 gen.endElementNS((None, "udoc"), None)
247 gen.endElementNS((ns_uri, "doc"), "ns1:doc")
248 gen.endPrefixMapping("ns1")
249 gen.endDocument()
Fred Drake004d5e62000-10-23 17:22:08 +0000250
Guido van Rossumd8faa362007-04-27 19:54:29 +0000251 self.assertEquals(result.getvalue(), start + \
Martin v. Löwiscf0a1cc2000-10-03 22:35:29 +0000252 ('<ns1:doc xmlns:ns1="%s"><udoc></udoc></ns1:doc>' %
Guido van Rossumd8faa362007-04-27 19:54:29 +0000253 ns_uri))
Lars Gustäbel96753b32000-09-24 12:24:24 +0000254
Guido van Rossumd8faa362007-04-27 19:54:29 +0000255 def test_1463026_1(self):
256 result = StringIO()
257 gen = XMLGenerator(result)
Thomas Wouterscf297e42007-02-23 15:07:44 +0000258
Guido van Rossumd8faa362007-04-27 19:54:29 +0000259 gen.startDocument()
260 gen.startElementNS((None, 'a'), 'a', {(None, 'b'):'c'})
261 gen.endElementNS((None, 'a'), 'a')
262 gen.endDocument()
Thomas Wouterscf297e42007-02-23 15:07:44 +0000263
Guido van Rossumd8faa362007-04-27 19:54:29 +0000264 self.assertEquals(result.getvalue(), start+'<a b="c"></a>')
Thomas Wouterscf297e42007-02-23 15:07:44 +0000265
Guido van Rossumd8faa362007-04-27 19:54:29 +0000266 def test_1463026_2(self):
267 result = StringIO()
268 gen = XMLGenerator(result)
Thomas Wouterscf297e42007-02-23 15:07:44 +0000269
Guido van Rossumd8faa362007-04-27 19:54:29 +0000270 gen.startDocument()
271 gen.startPrefixMapping(None, 'qux')
272 gen.startElementNS(('qux', 'a'), 'a', {})
273 gen.endElementNS(('qux', 'a'), 'a')
274 gen.endPrefixMapping(None)
275 gen.endDocument()
Thomas Wouterscf297e42007-02-23 15:07:44 +0000276
Guido van Rossumd8faa362007-04-27 19:54:29 +0000277 self.assertEquals(result.getvalue(), start+'<a xmlns="qux"></a>')
Thomas Wouterscf297e42007-02-23 15:07:44 +0000278
Guido van Rossumd8faa362007-04-27 19:54:29 +0000279 def test_1463026_3(self):
280 result = StringIO()
281 gen = XMLGenerator(result)
Thomas Wouterscf297e42007-02-23 15:07:44 +0000282
Guido van Rossumd8faa362007-04-27 19:54:29 +0000283 gen.startDocument()
284 gen.startPrefixMapping('my', 'qux')
285 gen.startElementNS(('qux', 'a'), 'a', {(None, 'b'):'c'})
286 gen.endElementNS(('qux', 'a'), 'a')
287 gen.endPrefixMapping('my')
288 gen.endDocument()
Thomas Wouterscf297e42007-02-23 15:07:44 +0000289
Guido van Rossumd8faa362007-04-27 19:54:29 +0000290 self.assertEquals(result.getvalue(),
291 start+'<my:a xmlns:my="qux" b="c"></my:a>')
Lars Gustäbel96753b32000-09-24 12:24:24 +0000292
Fred Drake004d5e62000-10-23 17:22:08 +0000293
Guido van Rossumd8faa362007-04-27 19:54:29 +0000294class XMLFilterBaseTest(unittest.TestCase):
295 def test_filter_basic(self):
296 result = StringIO()
297 gen = XMLGenerator(result)
298 filter = XMLFilterBase()
299 filter.setContentHandler(gen)
Lars Gustäbel96753b32000-09-24 12:24:24 +0000300
Guido van Rossumd8faa362007-04-27 19:54:29 +0000301 filter.startDocument()
302 filter.startElement("doc", {})
303 filter.characters("content")
304 filter.ignorableWhitespace(" ")
305 filter.endElement("doc")
306 filter.endDocument()
307
308 self.assertEquals(result.getvalue(), start + "<doc>content </doc>")
Lars Gustäbel96753b32000-09-24 12:24:24 +0000309
310# ===========================================================================
311#
312# expatreader tests
313#
314# ===========================================================================
315
Florent Xiclunaf15351d2010-03-13 23:24:31 +0000316xml_test_out = open(TEST_XMLFILE_OUT).read()
Lars Gustäbelb7536d52000-09-24 18:53:56 +0000317
Guido van Rossumd8faa362007-04-27 19:54:29 +0000318class ExpatReaderTest(XmlTestBase):
Lars Gustäbelb7536d52000-09-24 18:53:56 +0000319
Guido van Rossumd8faa362007-04-27 19:54:29 +0000320 # ===== XMLReader support
Lars Gustäbelb7536d52000-09-24 18:53:56 +0000321
Guido van Rossumd8faa362007-04-27 19:54:29 +0000322 def test_expat_file(self):
323 parser = create_parser()
324 result = StringIO()
325 xmlgen = XMLGenerator(result)
Lars Gustäbelb7536d52000-09-24 18:53:56 +0000326
Guido van Rossumd8faa362007-04-27 19:54:29 +0000327 parser.setContentHandler(xmlgen)
Florent Xiclunaf15351d2010-03-13 23:24:31 +0000328 parser.parse(open(TEST_XMLFILE))
Lars Gustäbelb7536d52000-09-24 18:53:56 +0000329
Guido van Rossumd8faa362007-04-27 19:54:29 +0000330 self.assertEquals(result.getvalue(), xml_test_out)
Lars Gustäbelb7536d52000-09-24 18:53:56 +0000331
Guido van Rossumd8faa362007-04-27 19:54:29 +0000332 # ===== DTDHandler support
Lars Gustäbelb7536d52000-09-24 18:53:56 +0000333
Guido van Rossumd8faa362007-04-27 19:54:29 +0000334 class TestDTDHandler:
Lars Gustäbelb7536d52000-09-24 18:53:56 +0000335
Guido van Rossumd8faa362007-04-27 19:54:29 +0000336 def __init__(self):
337 self._notations = []
338 self._entities = []
Lars Gustäbelb7536d52000-09-24 18:53:56 +0000339
Guido van Rossumd8faa362007-04-27 19:54:29 +0000340 def notationDecl(self, name, publicId, systemId):
341 self._notations.append((name, publicId, systemId))
Lars Gustäbelb7536d52000-09-24 18:53:56 +0000342
Guido van Rossumd8faa362007-04-27 19:54:29 +0000343 def unparsedEntityDecl(self, name, publicId, systemId, ndata):
344 self._entities.append((name, publicId, systemId, ndata))
Lars Gustäbel2fc52942000-10-24 15:35:07 +0000345
Guido van Rossumd8faa362007-04-27 19:54:29 +0000346 def test_expat_dtdhandler(self):
347 parser = create_parser()
348 handler = self.TestDTDHandler()
349 parser.setDTDHandler(handler)
Lars Gustäbel2fc52942000-10-24 15:35:07 +0000350
Guido van Rossumd8faa362007-04-27 19:54:29 +0000351 parser.feed('<!DOCTYPE doc [\n')
352 parser.feed(' <!ENTITY img SYSTEM "expat.gif" NDATA GIF>\n')
353 parser.feed(' <!NOTATION GIF PUBLIC "-//CompuServe//NOTATION Graphics Interchange Format 89a//EN">\n')
354 parser.feed(']>\n')
355 parser.feed('<doc></doc>')
356 parser.close()
Lars Gustäbel2fc52942000-10-24 15:35:07 +0000357
Guido van Rossumd8faa362007-04-27 19:54:29 +0000358 self.assertEquals(handler._notations,
359 [("GIF", "-//CompuServe//NOTATION Graphics Interchange Format 89a//EN", None)])
360 self.assertEquals(handler._entities, [("img", None, "expat.gif", "GIF")])
Lars Gustäbel2fc52942000-10-24 15:35:07 +0000361
Guido van Rossumd8faa362007-04-27 19:54:29 +0000362 # ===== EntityResolver support
Lars Gustäbel2fc52942000-10-24 15:35:07 +0000363
Guido van Rossumd8faa362007-04-27 19:54:29 +0000364 class TestEntityResolver:
Lars Gustäbel2fc52942000-10-24 15:35:07 +0000365
Guido van Rossumd8faa362007-04-27 19:54:29 +0000366 def resolveEntity(self, publicId, systemId):
367 inpsrc = InputSource()
368 inpsrc.setByteStream(StringIO("<entity/>"))
369 return inpsrc
Lars Gustäbel2fc52942000-10-24 15:35:07 +0000370
Guido van Rossumd8faa362007-04-27 19:54:29 +0000371 def test_expat_entityresolver(self):
372 parser = create_parser()
373 parser.setEntityResolver(self.TestEntityResolver())
374 result = StringIO()
375 parser.setContentHandler(XMLGenerator(result))
Lars Gustäbel2fc52942000-10-24 15:35:07 +0000376
Guido van Rossumd8faa362007-04-27 19:54:29 +0000377 parser.feed('<!DOCTYPE doc [\n')
378 parser.feed(' <!ENTITY test SYSTEM "whatever">\n')
379 parser.feed(']>\n')
380 parser.feed('<doc>&test;</doc>')
381 parser.close()
Lars Gustäbel2fc52942000-10-24 15:35:07 +0000382
Guido van Rossumd8faa362007-04-27 19:54:29 +0000383 self.assertEquals(result.getvalue(), start +
384 "<doc><entity></entity></doc>")
Lars Gustäbel2fc52942000-10-24 15:35:07 +0000385
Guido van Rossumd8faa362007-04-27 19:54:29 +0000386 # ===== Attributes support
Lars Gustäbel2fc52942000-10-24 15:35:07 +0000387
Guido van Rossumd8faa362007-04-27 19:54:29 +0000388 class AttrGatherer(ContentHandler):
Lars Gustäbel2fc52942000-10-24 15:35:07 +0000389
Guido van Rossumd8faa362007-04-27 19:54:29 +0000390 def startElement(self, name, attrs):
391 self._attrs = attrs
Lars Gustäbel2fc52942000-10-24 15:35:07 +0000392
Guido van Rossumd8faa362007-04-27 19:54:29 +0000393 def startElementNS(self, name, qname, attrs):
394 self._attrs = attrs
Lars Gustäbel2fc52942000-10-24 15:35:07 +0000395
Guido van Rossumd8faa362007-04-27 19:54:29 +0000396 def test_expat_attrs_empty(self):
397 parser = create_parser()
398 gather = self.AttrGatherer()
399 parser.setContentHandler(gather)
400
401 parser.feed("<doc/>")
402 parser.close()
403
404 self.verify_empty_attrs(gather._attrs)
405
406 def test_expat_attrs_wattr(self):
407 parser = create_parser()
408 gather = self.AttrGatherer()
409 parser.setContentHandler(gather)
410
411 parser.feed("<doc attr='val'/>")
412 parser.close()
413
414 self.verify_attrs_wattr(gather._attrs)
415
416 def test_expat_nsattrs_empty(self):
417 parser = create_parser(1)
418 gather = self.AttrGatherer()
419 parser.setContentHandler(gather)
420
421 parser.feed("<doc/>")
422 parser.close()
423
424 self.verify_empty_nsattrs(gather._attrs)
425
426 def test_expat_nsattrs_wattr(self):
427 parser = create_parser(1)
428 gather = self.AttrGatherer()
429 parser.setContentHandler(gather)
430
431 parser.feed("<doc xmlns:ns='%s' ns:attr='val'/>" % ns_uri)
432 parser.close()
433
434 attrs = gather._attrs
435
436 self.assertEquals(attrs.getLength(), 1)
437 self.assertEquals(attrs.getNames(), [(ns_uri, "attr")])
438 self.assertTrue((attrs.getQNames() == [] or
439 attrs.getQNames() == ["ns:attr"]))
440 self.assertEquals(len(attrs), 1)
Benjamin Peterson577473f2010-01-19 00:09:57 +0000441 self.assertIn((ns_uri, "attr"), attrs)
Guido van Rossumd8faa362007-04-27 19:54:29 +0000442 self.assertEquals(attrs.get((ns_uri, "attr")), "val")
443 self.assertEquals(attrs.get((ns_uri, "attr"), 25), "val")
444 self.assertEquals(list(attrs.items()), [((ns_uri, "attr"), "val")])
445 self.assertEquals(list(attrs.values()), ["val"])
446 self.assertEquals(attrs.getValue((ns_uri, "attr")), "val")
447 self.assertEquals(attrs[(ns_uri, "attr")], "val")
448
449 # ===== InputSource support
450
Benjamin Petersona7f4f5a2008-09-04 02:22:52 +0000451 def test_expat_inpsource_filename(self):
Guido van Rossumd8faa362007-04-27 19:54:29 +0000452 parser = create_parser()
453 result = StringIO()
454 xmlgen = XMLGenerator(result)
455
456 parser.setContentHandler(xmlgen)
Florent Xiclunaf15351d2010-03-13 23:24:31 +0000457 parser.parse(TEST_XMLFILE)
Guido van Rossumd8faa362007-04-27 19:54:29 +0000458
459 self.assertEquals(result.getvalue(), xml_test_out)
460
Benjamin Petersona7f4f5a2008-09-04 02:22:52 +0000461 def test_expat_inpsource_sysid(self):
Guido van Rossumd8faa362007-04-27 19:54:29 +0000462 parser = create_parser()
463 result = StringIO()
464 xmlgen = XMLGenerator(result)
465
466 parser.setContentHandler(xmlgen)
Florent Xiclunaf15351d2010-03-13 23:24:31 +0000467 parser.parse(InputSource(TEST_XMLFILE))
Guido van Rossumd8faa362007-04-27 19:54:29 +0000468
469 self.assertEquals(result.getvalue(), xml_test_out)
470
471 def test_expat_inpsource_stream(self):
472 parser = create_parser()
473 result = StringIO()
474 xmlgen = XMLGenerator(result)
475
476 parser.setContentHandler(xmlgen)
477 inpsrc = InputSource()
Florent Xiclunaf15351d2010-03-13 23:24:31 +0000478 inpsrc.setByteStream(open(TEST_XMLFILE))
Guido van Rossumd8faa362007-04-27 19:54:29 +0000479 parser.parse(inpsrc)
480
481 self.assertEquals(result.getvalue(), xml_test_out)
482
483 # ===== IncrementalParser support
484
485 def test_expat_incremental(self):
486 result = StringIO()
487 xmlgen = XMLGenerator(result)
488 parser = create_parser()
489 parser.setContentHandler(xmlgen)
490
491 parser.feed("<doc>")
492 parser.feed("</doc>")
493 parser.close()
494
495 self.assertEquals(result.getvalue(), start + "<doc></doc>")
496
497 def test_expat_incremental_reset(self):
498 result = StringIO()
499 xmlgen = XMLGenerator(result)
500 parser = create_parser()
501 parser.setContentHandler(xmlgen)
502
503 parser.feed("<doc>")
504 parser.feed("text")
505
506 result = StringIO()
507 xmlgen = XMLGenerator(result)
508 parser.setContentHandler(xmlgen)
509 parser.reset()
510
511 parser.feed("<doc>")
512 parser.feed("text")
513 parser.feed("</doc>")
514 parser.close()
515
516 self.assertEquals(result.getvalue(), start + "<doc>text</doc>")
517
518 # ===== Locator support
519
520 def test_expat_locator_noinfo(self):
521 result = StringIO()
522 xmlgen = XMLGenerator(result)
523 parser = create_parser()
524 parser.setContentHandler(xmlgen)
525
526 parser.feed("<doc>")
527 parser.feed("</doc>")
528 parser.close()
529
530 self.assertEquals(parser.getSystemId(), None)
531 self.assertEquals(parser.getPublicId(), None)
532 self.assertEquals(parser.getLineNumber(), 1)
533
Benjamin Petersona7f4f5a2008-09-04 02:22:52 +0000534 def test_expat_locator_withinfo(self):
Guido van Rossumd8faa362007-04-27 19:54:29 +0000535 result = StringIO()
536 xmlgen = XMLGenerator(result)
537 parser = create_parser()
538 parser.setContentHandler(xmlgen)
Florent Xiclunaf15351d2010-03-13 23:24:31 +0000539 parser.parse(TEST_XMLFILE)
Guido van Rossumd8faa362007-04-27 19:54:29 +0000540
Florent Xiclunaf15351d2010-03-13 23:24:31 +0000541 self.assertEquals(parser.getSystemId(), TEST_XMLFILE)
Guido van Rossumd8faa362007-04-27 19:54:29 +0000542 self.assertEquals(parser.getPublicId(), None)
Lars Gustäbel2fc52942000-10-24 15:35:07 +0000543
Martin v. Löwis80670bc2000-10-06 21:13:23 +0000544
545# ===========================================================================
546#
547# error reporting
548#
549# ===========================================================================
550
Guido van Rossumd8faa362007-04-27 19:54:29 +0000551class ErrorReportingTest(unittest.TestCase):
552 def test_expat_inpsource_location(self):
553 parser = create_parser()
554 parser.setContentHandler(ContentHandler()) # do nothing
555 source = InputSource()
556 source.setByteStream(StringIO("<foo bar foobar>")) #ill-formed
557 name = "a file name"
558 source.setSystemId(name)
559 try:
560 parser.parse(source)
561 self.fail()
562 except SAXException as e:
563 self.assertEquals(e.getSystemId(), name)
Martin v. Löwis80670bc2000-10-06 21:13:23 +0000564
Guido van Rossumd8faa362007-04-27 19:54:29 +0000565 def test_expat_incomplete(self):
566 parser = create_parser()
567 parser.setContentHandler(ContentHandler()) # do nothing
568 self.assertRaises(SAXParseException, parser.parse, StringIO("<foo>"))
Martin v. Löwis80670bc2000-10-06 21:13:23 +0000569
Guido van Rossumd8faa362007-04-27 19:54:29 +0000570 def test_sax_parse_exception_str(self):
571 # pass various values from a locator to the SAXParseException to
572 # make sure that the __str__() doesn't fall apart when None is
573 # passed instead of an integer line and column number
574 #
575 # use "normal" values for the locator:
576 str(SAXParseException("message", None,
577 self.DummyLocator(1, 1)))
578 # use None for the line number:
579 str(SAXParseException("message", None,
580 self.DummyLocator(None, 1)))
581 # use None for the column number:
582 str(SAXParseException("message", None,
583 self.DummyLocator(1, None)))
584 # use None for both:
585 str(SAXParseException("message", None,
586 self.DummyLocator(None, None)))
Fred Drake6fd0b0d2004-03-20 08:15:30 +0000587
Guido van Rossumd8faa362007-04-27 19:54:29 +0000588 class DummyLocator:
589 def __init__(self, lineno, colno):
590 self._lineno = lineno
591 self._colno = colno
Fred Drake6fd0b0d2004-03-20 08:15:30 +0000592
Guido van Rossumd8faa362007-04-27 19:54:29 +0000593 def getPublicId(self):
594 return "pubid"
Fred Drake6fd0b0d2004-03-20 08:15:30 +0000595
Guido van Rossumd8faa362007-04-27 19:54:29 +0000596 def getSystemId(self):
597 return "sysid"
Fred Drake6fd0b0d2004-03-20 08:15:30 +0000598
Guido van Rossumd8faa362007-04-27 19:54:29 +0000599 def getLineNumber(self):
600 return self._lineno
Fred Drake6fd0b0d2004-03-20 08:15:30 +0000601
Guido van Rossumd8faa362007-04-27 19:54:29 +0000602 def getColumnNumber(self):
603 return self._colno
Martin v. Löwis80670bc2000-10-06 21:13:23 +0000604
Lars Gustäbelab647872000-09-24 18:40:52 +0000605# ===========================================================================
606#
607# xmlreader tests
608#
609# ===========================================================================
610
Guido van Rossumd8faa362007-04-27 19:54:29 +0000611class XmlReaderTest(XmlTestBase):
Lars Gustäbelab647872000-09-24 18:40:52 +0000612
Guido van Rossumd8faa362007-04-27 19:54:29 +0000613 # ===== AttributesImpl
614 def test_attrs_empty(self):
615 self.verify_empty_attrs(AttributesImpl({}))
Lars Gustäbelab647872000-09-24 18:40:52 +0000616
Guido van Rossumd8faa362007-04-27 19:54:29 +0000617 def test_attrs_wattr(self):
618 self.verify_attrs_wattr(AttributesImpl({"attr" : "val"}))
Lars Gustäbelab647872000-09-24 18:40:52 +0000619
Guido van Rossumd8faa362007-04-27 19:54:29 +0000620 def test_nsattrs_empty(self):
621 self.verify_empty_nsattrs(AttributesNSImpl({}, {}))
Lars Gustäbelab647872000-09-24 18:40:52 +0000622
Guido van Rossumd8faa362007-04-27 19:54:29 +0000623 def test_nsattrs_wattr(self):
624 attrs = AttributesNSImpl({(ns_uri, "attr") : "val"},
625 {(ns_uri, "attr") : "ns:attr"})
Fred Drake004d5e62000-10-23 17:22:08 +0000626
Guido van Rossumd8faa362007-04-27 19:54:29 +0000627 self.assertEquals(attrs.getLength(), 1)
628 self.assertEquals(attrs.getNames(), [(ns_uri, "attr")])
629 self.assertEquals(attrs.getQNames(), ["ns:attr"])
630 self.assertEquals(len(attrs), 1)
Benjamin Peterson577473f2010-01-19 00:09:57 +0000631 self.assertIn((ns_uri, "attr"), attrs)
Guido van Rossumd8faa362007-04-27 19:54:29 +0000632 self.assertEquals(list(attrs.keys()), [(ns_uri, "attr")])
633 self.assertEquals(attrs.get((ns_uri, "attr")), "val")
634 self.assertEquals(attrs.get((ns_uri, "attr"), 25), "val")
635 self.assertEquals(list(attrs.items()), [((ns_uri, "attr"), "val")])
636 self.assertEquals(list(attrs.values()), ["val"])
637 self.assertEquals(attrs.getValue((ns_uri, "attr")), "val")
638 self.assertEquals(attrs.getValueByQName("ns:attr"), "val")
639 self.assertEquals(attrs.getNameByQName("ns:attr"), (ns_uri, "attr"))
640 self.assertEquals(attrs[(ns_uri, "attr")], "val")
641 self.assertEquals(attrs.getQNameByName((ns_uri, "attr")), "ns:attr")
Fred Drake004d5e62000-10-23 17:22:08 +0000642
Lars Gustäbelab647872000-09-24 18:40:52 +0000643
Guido van Rossumd8faa362007-04-27 19:54:29 +0000644 # During the development of Python 2.5, an attempt to move the "xml"
645 # package implementation to a new package ("xmlcore") proved painful.
646 # The goal of this change was to allow applications to be able to
647 # obtain and rely on behavior in the standard library implementation
648 # of the XML support without needing to be concerned about the
649 # availability of the PyXML implementation.
650 #
651 # While the existing import hackery in Lib/xml/__init__.py can cause
652 # PyXML's _xmlpus package to supplant the "xml" package, that only
653 # works because either implementation uses the "xml" package name for
654 # imports.
655 #
656 # The move resulted in a number of problems related to the fact that
657 # the import machinery's "package context" is based on the name that's
658 # being imported rather than the __name__ of the actual package
659 # containment; it wasn't possible for the "xml" package to be replaced
660 # by a simple module that indirected imports to the "xmlcore" package.
661 #
662 # The following two tests exercised bugs that were introduced in that
663 # attempt. Keeping these tests around will help detect problems with
664 # other attempts to provide reliable access to the standard library's
665 # implementation of the XML support.
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000666
Guido van Rossumd8faa362007-04-27 19:54:29 +0000667 def test_sf_1511497(self):
668 # Bug report: http://www.python.org/sf/1511497
669 import sys
670 old_modules = sys.modules.copy()
671 for modname in list(sys.modules.keys()):
672 if modname.startswith("xml."):
673 del sys.modules[modname]
674 try:
675 import xml.sax.expatreader
676 module = xml.sax.expatreader
677 self.assertEquals(module.__name__, "xml.sax.expatreader")
678 finally:
679 sys.modules.update(old_modules)
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000680
Guido van Rossumd8faa362007-04-27 19:54:29 +0000681 def test_sf_1513611(self):
682 # Bug report: http://www.python.org/sf/1513611
683 sio = StringIO("invalid")
684 parser = make_parser()
685 from xml.sax import SAXParseException
686 self.assertRaises(SAXParseException, parser.parse, sio)
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000687
Lars Gustäbel96753b32000-09-24 12:24:24 +0000688
Christian Heimesbbe741d2008-03-28 10:53:29 +0000689def test_main():
Guido van Rossumd8faa362007-04-27 19:54:29 +0000690 run_unittest(MakeParserTest,
691 SaxutilsTest,
692 XmlgenTest,
693 ExpatReaderTest,
694 ErrorReportingTest,
695 XmlReaderTest)
Lars Gustäbelb7536d52000-09-24 18:53:56 +0000696
Guido van Rossumd8faa362007-04-27 19:54:29 +0000697if __name__ == "__main__":
Christian Heimesbbe741d2008-03-28 10:53:29 +0000698 test_main()