blob: 5b071ddaaa22c0ee271c7aa745f7fd648c6f8516 [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
Lars Gustäbel96753b32000-09-24 12:24:24 +000015from cStringIO import StringIO
Barry Warsaw04f357c2002-07-23 19:04:11 +000016from test.test_support import verify, verbose, TestFailed, findfile
Guido van Rossume2ae77b2001-10-24 20:42:55 +000017import os
Lars Gustäbel96753b32000-09-24 12:24:24 +000018
19# ===== Utilities
20
21tests = 0
Fred Drake32f3add2002-10-28 17:58:48 +000022failures = []
Lars Gustäbel96753b32000-09-24 12:24:24 +000023
24def confirm(outcome, name):
Fred Drake32f3add2002-10-28 17:58:48 +000025 global tests
Lars Gustäbel96753b32000-09-24 12:24:24 +000026
27 tests = tests + 1
28 if outcome:
Fred Drake32f3add2002-10-28 17:58:48 +000029 if verbose:
Guido van Rossumbe19ed72007-02-09 05:37:30 +000030 print("Passed", name)
Lars Gustäbel96753b32000-09-24 12:24:24 +000031 else:
Fred Drake32f3add2002-10-28 17:58:48 +000032 failures.append(name)
Lars Gustäbel96753b32000-09-24 12:24:24 +000033
Lars Gustäbel2fc52942000-10-24 15:35:07 +000034def test_make_parser2():
Tim Petersd2bf3b72001-01-18 02:22:22 +000035 try:
Lars Gustäbel2fc52942000-10-24 15:35:07 +000036 # Creating parsers several times in a row should succeed.
37 # Testing this because there have been failures of this kind
38 # before.
Thomas Wouters0e3f5912006-08-11 14:57:12 +000039 from xml.sax import make_parser
Lars Gustäbel2fc52942000-10-24 15:35:07 +000040 p = make_parser()
Thomas Wouters0e3f5912006-08-11 14:57:12 +000041 from xml.sax import make_parser
Lars Gustäbel2fc52942000-10-24 15:35:07 +000042 p = make_parser()
Thomas Wouters0e3f5912006-08-11 14:57:12 +000043 from xml.sax import make_parser
Lars Gustäbel2fc52942000-10-24 15:35:07 +000044 p = make_parser()
Thomas Wouters0e3f5912006-08-11 14:57:12 +000045 from xml.sax import make_parser
Lars Gustäbel2fc52942000-10-24 15:35:07 +000046 p = make_parser()
Thomas Wouters0e3f5912006-08-11 14:57:12 +000047 from xml.sax import make_parser
Lars Gustäbel2fc52942000-10-24 15:35:07 +000048 p = make_parser()
Thomas Wouters0e3f5912006-08-11 14:57:12 +000049 from xml.sax import make_parser
Lars Gustäbel2fc52942000-10-24 15:35:07 +000050 p = make_parser()
51 except:
52 return 0
53 else:
54 return p
Tim Petersd2bf3b72001-01-18 02:22:22 +000055
56
Lars Gustäbel96753b32000-09-24 12:24:24 +000057# ===========================================================================
58#
59# saxutils tests
60#
61# ===========================================================================
62
63# ===== escape
64
65def test_escape_basic():
66 return escape("Donald Duck & Co") == "Donald Duck & Co"
67
68def test_escape_all():
69 return escape("<Donald Duck & Co>") == "&lt;Donald Duck &amp; Co&gt;"
70
71def test_escape_extra():
72 return escape("Hei på deg", {"å" : "&aring;"}) == "Hei p&aring; deg"
73
Martin v. Löwis74b51ac2002-10-26 14:50:45 +000074# ===== unescape
75
76def test_unescape_basic():
77 return unescape("Donald Duck &amp; Co") == "Donald Duck & Co"
78
79def test_unescape_all():
80 return unescape("&lt;Donald Duck &amp; Co&gt;") == "<Donald Duck & Co>"
81
82def test_unescape_extra():
83 return unescape("Hei på deg", {"å" : "&aring;"}) == "Hei p&aring; deg"
84
Fred Drake32f3add2002-10-28 17:58:48 +000085def test_unescape_amp_extra():
86 return unescape("&amp;foo;", {"&foo;": "splat"}) == "&foo;"
87
Fred Drakeacd32d32001-07-19 16:10:15 +000088# ===== quoteattr
89
90def test_quoteattr_basic():
91 return quoteattr("Donald Duck & Co") == '"Donald Duck &amp; Co"'
92
93def test_single_quoteattr():
94 return (quoteattr('Includes "double" quotes')
95 == '\'Includes "double" quotes\'')
96
97def test_double_quoteattr():
98 return (quoteattr("Includes 'single' quotes")
99 == "\"Includes 'single' quotes\"")
100
101def test_single_double_quoteattr():
102 return (quoteattr("Includes 'single' and \"double\" quotes")
103 == "\"Includes 'single' and &quot;double&quot; quotes\"")
104
105# ===== make_parser
106
Martin v. Löwis962c9e72000-10-06 17:41:52 +0000107def test_make_parser():
108 try:
109 # Creating a parser should succeed - it should fall back
110 # to the expatreader
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000111 p = make_parser(['xml.parsers.no_such_parser'])
Martin v. Löwis962c9e72000-10-06 17:41:52 +0000112 except:
113 return 0
114 else:
115 return p
116
117
Lars Gustäbel96753b32000-09-24 12:24:24 +0000118# ===== XMLGenerator
119
120start = '<?xml version="1.0" encoding="iso-8859-1"?>\n'
121
122def test_xmlgen_basic():
123 result = StringIO()
124 gen = XMLGenerator(result)
125 gen.startDocument()
126 gen.startElement("doc", {})
127 gen.endElement("doc")
128 gen.endDocument()
129
130 return result.getvalue() == start + "<doc></doc>"
131
132def test_xmlgen_content():
133 result = StringIO()
134 gen = XMLGenerator(result)
Fred Drake004d5e62000-10-23 17:22:08 +0000135
Lars Gustäbel96753b32000-09-24 12:24:24 +0000136 gen.startDocument()
137 gen.startElement("doc", {})
138 gen.characters("huhei")
139 gen.endElement("doc")
140 gen.endDocument()
141
142 return result.getvalue() == start + "<doc>huhei</doc>"
143
144def test_xmlgen_pi():
145 result = StringIO()
146 gen = XMLGenerator(result)
Fred Drake004d5e62000-10-23 17:22:08 +0000147
Lars Gustäbel96753b32000-09-24 12:24:24 +0000148 gen.startDocument()
149 gen.processingInstruction("test", "data")
150 gen.startElement("doc", {})
151 gen.endElement("doc")
152 gen.endDocument()
153
154 return result.getvalue() == start + "<?test data?><doc></doc>"
155
156def test_xmlgen_content_escape():
157 result = StringIO()
158 gen = XMLGenerator(result)
Fred Drake004d5e62000-10-23 17:22:08 +0000159
Lars Gustäbel96753b32000-09-24 12:24:24 +0000160 gen.startDocument()
161 gen.startElement("doc", {})
162 gen.characters("<huhei&")
163 gen.endElement("doc")
164 gen.endDocument()
165
166 return result.getvalue() == start + "<doc>&lt;huhei&amp;</doc>"
167
Fred Drakec9fadf92001-08-07 19:17:06 +0000168def test_xmlgen_attr_escape():
169 result = StringIO()
170 gen = XMLGenerator(result)
171
172 gen.startDocument()
173 gen.startElement("doc", {"a": '"'})
174 gen.startElement("e", {"a": "'"})
175 gen.endElement("e")
176 gen.startElement("e", {"a": "'\""})
177 gen.endElement("e")
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000178 gen.startElement("e", {"a": "\n\r\t"})
179 gen.endElement("e")
Fred Drakec9fadf92001-08-07 19:17:06 +0000180 gen.endElement("doc")
181 gen.endDocument()
182
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000183 return result.getvalue() == start + ("<doc a='\"'><e a=\"'\"></e>"
184 "<e a=\"'&quot;\"></e>"
185 "<e a=\"&#10;&#13;&#9;\"></e></doc>")
Fred Drakec9fadf92001-08-07 19:17:06 +0000186
Lars Gustäbel96753b32000-09-24 12:24:24 +0000187def test_xmlgen_ignorable():
188 result = StringIO()
189 gen = XMLGenerator(result)
Fred Drake004d5e62000-10-23 17:22:08 +0000190
Lars Gustäbel96753b32000-09-24 12:24:24 +0000191 gen.startDocument()
192 gen.startElement("doc", {})
193 gen.ignorableWhitespace(" ")
194 gen.endElement("doc")
195 gen.endDocument()
196
197 return result.getvalue() == start + "<doc> </doc>"
198
199ns_uri = "http://www.python.org/xml-ns/saxtest/"
200
201def test_xmlgen_ns():
202 result = StringIO()
203 gen = XMLGenerator(result)
Fred Drake004d5e62000-10-23 17:22:08 +0000204
Lars Gustäbel96753b32000-09-24 12:24:24 +0000205 gen.startDocument()
206 gen.startPrefixMapping("ns1", ns_uri)
Lars Gustäbel6a7768a2000-09-27 08:12:17 +0000207 gen.startElementNS((ns_uri, "doc"), "ns1:doc", {})
Martin v. Löwiscf0a1cc2000-10-03 22:35:29 +0000208 # add an unqualified name
209 gen.startElementNS((None, "udoc"), None, {})
210 gen.endElementNS((None, "udoc"), None)
Lars Gustäbel6a7768a2000-09-27 08:12:17 +0000211 gen.endElementNS((ns_uri, "doc"), "ns1:doc")
Lars Gustäbel96753b32000-09-24 12:24:24 +0000212 gen.endPrefixMapping("ns1")
213 gen.endDocument()
214
Martin v. Löwiscf0a1cc2000-10-03 22:35:29 +0000215 return result.getvalue() == start + \
216 ('<ns1:doc xmlns:ns1="%s"><udoc></udoc></ns1:doc>' %
Lars Gustäbel96753b32000-09-24 12:24:24 +0000217 ns_uri)
218
Thomas Wouterscf297e42007-02-23 15:07:44 +0000219def test_1463026_1():
220 result = StringIO()
221 gen = XMLGenerator(result)
222
223 gen.startDocument()
224 gen.startElementNS((None, 'a'), 'a', {(None, 'b'):'c'})
225 gen.endElementNS((None, 'a'), 'a')
226 gen.endDocument()
227
228 return result.getvalue() == start+'<a b="c"></a>'
229
230def test_1463026_2():
231 result = StringIO()
232 gen = XMLGenerator(result)
233
234 gen.startDocument()
235 gen.startPrefixMapping(None, 'qux')
236 gen.startElementNS(('qux', 'a'), 'a', {})
237 gen.endElementNS(('qux', 'a'), 'a')
238 gen.endPrefixMapping(None)
239 gen.endDocument()
240
241 return result.getvalue() == start+'<a xmlns="qux"></a>'
242
243def test_1463026_3():
244 result = StringIO()
245 gen = XMLGenerator(result)
246
247 gen.startDocument()
248 gen.startPrefixMapping('my', 'qux')
249 gen.startElementNS(('qux', 'a'), 'a', {(None, 'b'):'c'})
250 gen.endElementNS(('qux', 'a'), 'a')
251 gen.endPrefixMapping('my')
252 gen.endDocument()
253
254 return result.getvalue() == start+'<my:a xmlns:my="qux" b="c"></my:a>'
255
256# ===== Xmlfilterbase
Lars Gustäbel96753b32000-09-24 12:24:24 +0000257
258def test_filter_basic():
259 result = StringIO()
260 gen = XMLGenerator(result)
261 filter = XMLFilterBase()
262 filter.setContentHandler(gen)
Fred Drake004d5e62000-10-23 17:22:08 +0000263
Lars Gustäbel96753b32000-09-24 12:24:24 +0000264 filter.startDocument()
265 filter.startElement("doc", {})
266 filter.characters("content")
267 filter.ignorableWhitespace(" ")
268 filter.endElement("doc")
269 filter.endDocument()
270
271 return result.getvalue() == start + "<doc>content </doc>"
272
273# ===========================================================================
274#
275# expatreader tests
276#
277# ===========================================================================
278
Lars Gustäbel07025072000-10-24 16:00:22 +0000279# ===== XMLReader support
280
281def test_expat_file():
282 parser = create_parser()
283 result = StringIO()
284 xmlgen = XMLGenerator(result)
285
286 parser.setContentHandler(xmlgen)
Guido van Rossume2ae77b2001-10-24 20:42:55 +0000287 parser.parse(open(findfile("test"+os.extsep+"xml")))
Lars Gustäbel07025072000-10-24 16:00:22 +0000288
289 return result.getvalue() == xml_test_out
290
Lars Gustäbel96753b32000-09-24 12:24:24 +0000291# ===== DTDHandler support
292
293class TestDTDHandler:
294
295 def __init__(self):
296 self._notations = []
297 self._entities = []
Fred Drake004d5e62000-10-23 17:22:08 +0000298
Lars Gustäbel96753b32000-09-24 12:24:24 +0000299 def notationDecl(self, name, publicId, systemId):
300 self._notations.append((name, publicId, systemId))
301
302 def unparsedEntityDecl(self, name, publicId, systemId, ndata):
303 self._entities.append((name, publicId, systemId, ndata))
304
Lars Gustäbele292a242000-09-24 20:19:45 +0000305def test_expat_dtdhandler():
306 parser = create_parser()
307 handler = TestDTDHandler()
308 parser.setDTDHandler(handler)
Lars Gustäbel96753b32000-09-24 12:24:24 +0000309
Lars Gustäbele292a242000-09-24 20:19:45 +0000310 parser.feed('<!DOCTYPE doc [\n')
311 parser.feed(' <!ENTITY img SYSTEM "expat.gif" NDATA GIF>\n')
312 parser.feed(' <!NOTATION GIF PUBLIC "-//CompuServe//NOTATION Graphics Interchange Format 89a//EN">\n')
313 parser.feed(']>\n')
314 parser.feed('<doc></doc>')
315 parser.close()
Lars Gustäbel96753b32000-09-24 12:24:24 +0000316
Lars Gustäbele292a242000-09-24 20:19:45 +0000317 return handler._notations == [("GIF", "-//CompuServe//NOTATION Graphics Interchange Format 89a//EN", None)] and \
318 handler._entities == [("img", None, "expat.gif", "GIF")]
Lars Gustäbel96753b32000-09-24 12:24:24 +0000319
320# ===== EntityResolver support
321
Lars Gustäbele292a242000-09-24 20:19:45 +0000322class TestEntityResolver:
Lars Gustäbel96753b32000-09-24 12:24:24 +0000323
Lars Gustäbele292a242000-09-24 20:19:45 +0000324 def resolveEntity(self, publicId, systemId):
325 inpsrc = InputSource()
326 inpsrc.setByteStream(StringIO("<entity/>"))
327 return inpsrc
328
329def test_expat_entityresolver():
Lars Gustäbele292a242000-09-24 20:19:45 +0000330 parser = create_parser()
331 parser.setEntityResolver(TestEntityResolver())
332 result = StringIO()
333 parser.setContentHandler(XMLGenerator(result))
334
335 parser.feed('<!DOCTYPE doc [\n')
336 parser.feed(' <!ENTITY test SYSTEM "whatever">\n')
337 parser.feed(']>\n')
338 parser.feed('<doc>&test;</doc>')
339 parser.close()
340
341 return result.getvalue() == start + "<doc><entity></entity></doc>"
Fred Drake004d5e62000-10-23 17:22:08 +0000342
Lars Gustäbelab647872000-09-24 18:40:52 +0000343# ===== Attributes support
344
345class AttrGatherer(ContentHandler):
346
347 def startElement(self, name, attrs):
348 self._attrs = attrs
349
350 def startElementNS(self, name, qname, attrs):
351 self._attrs = attrs
Fred Drake004d5e62000-10-23 17:22:08 +0000352
Lars Gustäbelab647872000-09-24 18:40:52 +0000353def test_expat_attrs_empty():
354 parser = create_parser()
355 gather = AttrGatherer()
356 parser.setContentHandler(gather)
357
358 parser.feed("<doc/>")
359 parser.close()
360
361 return verify_empty_attrs(gather._attrs)
362
363def test_expat_attrs_wattr():
364 parser = create_parser()
365 gather = AttrGatherer()
366 parser.setContentHandler(gather)
367
368 parser.feed("<doc attr='val'/>")
369 parser.close()
370
371 return verify_attrs_wattr(gather._attrs)
372
373def test_expat_nsattrs_empty():
374 parser = create_parser(1)
375 gather = AttrGatherer()
376 parser.setContentHandler(gather)
377
378 parser.feed("<doc/>")
379 parser.close()
380
381 return verify_empty_nsattrs(gather._attrs)
382
383def test_expat_nsattrs_wattr():
384 parser = create_parser(1)
385 gather = AttrGatherer()
386 parser.setContentHandler(gather)
387
388 parser.feed("<doc xmlns:ns='%s' ns:attr='val'/>" % ns_uri)
389 parser.close()
390
391 attrs = gather._attrs
Fred Drake004d5e62000-10-23 17:22:08 +0000392
Lars Gustäbelab647872000-09-24 18:40:52 +0000393 return attrs.getLength() == 1 and \
394 attrs.getNames() == [(ns_uri, "attr")] and \
Fred Draked2909c92002-09-12 17:02:01 +0000395 (attrs.getQNames() == [] or attrs.getQNames() == ["ns:attr"]) and \
Lars Gustäbelab647872000-09-24 18:40:52 +0000396 len(attrs) == 1 and \
Guido van Rossume2b70bc2006-08-18 22:13:04 +0000397 (ns_uri, "attr") in attrs and \
Guido van Rossum091153d2007-02-11 18:44:55 +0000398 list(attrs.keys()) == [(ns_uri, "attr")] and \
Lars Gustäbelab647872000-09-24 18:40:52 +0000399 attrs.get((ns_uri, "attr")) == "val" and \
400 attrs.get((ns_uri, "attr"), 25) == "val" and \
Guido van Rossum091153d2007-02-11 18:44:55 +0000401 list(attrs.items()) == [((ns_uri, "attr"), "val")] and \
402 list(attrs.values()) == ["val"] and \
Lars Gustäbelab647872000-09-24 18:40:52 +0000403 attrs.getValue((ns_uri, "attr")) == "val" and \
404 attrs[(ns_uri, "attr")] == "val"
405
Lars Gustäbelb7536d52000-09-24 18:53:56 +0000406# ===== InputSource support
407
Guido van Rossume2ae77b2001-10-24 20:42:55 +0000408xml_test_out = open(findfile("test"+os.extsep+"xml"+os.extsep+"out")).read()
Lars Gustäbelb7536d52000-09-24 18:53:56 +0000409
410def test_expat_inpsource_filename():
411 parser = create_parser()
412 result = StringIO()
413 xmlgen = XMLGenerator(result)
414
415 parser.setContentHandler(xmlgen)
Guido van Rossume2ae77b2001-10-24 20:42:55 +0000416 parser.parse(findfile("test"+os.extsep+"xml"))
Lars Gustäbelb7536d52000-09-24 18:53:56 +0000417
418 return result.getvalue() == xml_test_out
419
420def test_expat_inpsource_sysid():
421 parser = create_parser()
422 result = StringIO()
423 xmlgen = XMLGenerator(result)
424
425 parser.setContentHandler(xmlgen)
Guido van Rossume2ae77b2001-10-24 20:42:55 +0000426 parser.parse(InputSource(findfile("test"+os.extsep+"xml")))
Lars Gustäbelb7536d52000-09-24 18:53:56 +0000427
428 return result.getvalue() == xml_test_out
429
430def test_expat_inpsource_stream():
431 parser = create_parser()
432 result = StringIO()
433 xmlgen = XMLGenerator(result)
434
435 parser.setContentHandler(xmlgen)
436 inpsrc = InputSource()
Guido van Rossume2ae77b2001-10-24 20:42:55 +0000437 inpsrc.setByteStream(open(findfile("test"+os.extsep+"xml")))
Lars Gustäbelb7536d52000-09-24 18:53:56 +0000438 parser.parse(inpsrc)
439
440 return result.getvalue() == xml_test_out
441
Lars Gustäbel2fc52942000-10-24 15:35:07 +0000442# ===== IncrementalParser support
443
444def test_expat_incremental():
445 result = StringIO()
446 xmlgen = XMLGenerator(result)
447 parser = create_parser()
448 parser.setContentHandler(xmlgen)
449
450 parser.feed("<doc>")
451 parser.feed("</doc>")
452 parser.close()
453
454 return result.getvalue() == start + "<doc></doc>"
455
456def test_expat_incremental_reset():
457 result = StringIO()
458 xmlgen = XMLGenerator(result)
459 parser = create_parser()
460 parser.setContentHandler(xmlgen)
461
462 parser.feed("<doc>")
463 parser.feed("text")
464
465 result = StringIO()
466 xmlgen = XMLGenerator(result)
467 parser.setContentHandler(xmlgen)
468 parser.reset()
469
470 parser.feed("<doc>")
471 parser.feed("text")
472 parser.feed("</doc>")
473 parser.close()
474
475 return result.getvalue() == start + "<doc>text</doc>"
476
477# ===== Locator support
478
479def test_expat_locator_noinfo():
480 result = StringIO()
481 xmlgen = XMLGenerator(result)
482 parser = create_parser()
483 parser.setContentHandler(xmlgen)
484
485 parser.feed("<doc>")
486 parser.feed("</doc>")
487 parser.close()
488
Fred Drake132dce22000-12-12 23:11:42 +0000489 return parser.getSystemId() is None and \
490 parser.getPublicId() is None and \
Tim Petersd2bf3b72001-01-18 02:22:22 +0000491 parser.getLineNumber() == 1
Lars Gustäbel2fc52942000-10-24 15:35:07 +0000492
493def test_expat_locator_withinfo():
494 result = StringIO()
495 xmlgen = XMLGenerator(result)
496 parser = create_parser()
497 parser.setContentHandler(xmlgen)
498 parser.parse(findfile("test.xml"))
499
500 return parser.getSystemId() == findfile("test.xml") and \
Fred Drake132dce22000-12-12 23:11:42 +0000501 parser.getPublicId() is None
Lars Gustäbel2fc52942000-10-24 15:35:07 +0000502
Martin v. Löwis80670bc2000-10-06 21:13:23 +0000503
504# ===========================================================================
505#
506# error reporting
507#
508# ===========================================================================
509
510def test_expat_inpsource_location():
511 parser = create_parser()
512 parser.setContentHandler(ContentHandler()) # do nothing
513 source = InputSource()
514 source.setByteStream(StringIO("<foo bar foobar>")) #ill-formed
515 name = "a file name"
516 source.setSystemId(name)
517 try:
518 parser.parse(source)
Guido van Rossumb940e112007-01-10 16:19:56 +0000519 except SAXException as e:
Martin v. Löwis80670bc2000-10-06 21:13:23 +0000520 return e.getSystemId() == name
521
522def test_expat_incomplete():
523 parser = create_parser()
524 parser.setContentHandler(ContentHandler()) # do nothing
525 try:
526 parser.parse(StringIO("<foo>"))
527 except SAXParseException:
528 return 1 # ok, error found
529 else:
530 return 0
531
Fred Drake6fd0b0d2004-03-20 08:15:30 +0000532def test_sax_parse_exception_str():
533 # pass various values from a locator to the SAXParseException to
534 # make sure that the __str__() doesn't fall apart when None is
535 # passed instead of an integer line and column number
536 #
537 # use "normal" values for the locator:
538 str(SAXParseException("message", None,
539 DummyLocator(1, 1)))
540 # use None for the line number:
541 str(SAXParseException("message", None,
542 DummyLocator(None, 1)))
543 # use None for the column number:
544 str(SAXParseException("message", None,
545 DummyLocator(1, None)))
546 # use None for both:
547 str(SAXParseException("message", None,
548 DummyLocator(None, None)))
549 return 1
550
551class DummyLocator:
552 def __init__(self, lineno, colno):
553 self._lineno = lineno
554 self._colno = colno
555
556 def getPublicId(self):
557 return "pubid"
558
559 def getSystemId(self):
560 return "sysid"
561
562 def getLineNumber(self):
563 return self._lineno
564
565 def getColumnNumber(self):
566 return self._colno
Martin v. Löwis80670bc2000-10-06 21:13:23 +0000567
Lars Gustäbelab647872000-09-24 18:40:52 +0000568# ===========================================================================
569#
570# xmlreader tests
571#
572# ===========================================================================
573
574# ===== AttributesImpl
575
576def verify_empty_attrs(attrs):
577 try:
578 attrs.getValue("attr")
579 gvk = 0
580 except KeyError:
581 gvk = 1
582
583 try:
584 attrs.getValueByQName("attr")
585 gvqk = 0
586 except KeyError:
587 gvqk = 1
588
589 try:
590 attrs.getNameByQName("attr")
591 gnqk = 0
592 except KeyError:
593 gnqk = 1
594
595 try:
596 attrs.getQNameByName("attr")
597 gqnk = 0
598 except KeyError:
599 gqnk = 1
Fred Drake004d5e62000-10-23 17:22:08 +0000600
Lars Gustäbelab647872000-09-24 18:40:52 +0000601 try:
602 attrs["attr"]
603 gik = 0
604 except KeyError:
605 gik = 1
Fred Drake004d5e62000-10-23 17:22:08 +0000606
Lars Gustäbelab647872000-09-24 18:40:52 +0000607 return attrs.getLength() == 0 and \
608 attrs.getNames() == [] and \
609 attrs.getQNames() == [] and \
610 len(attrs) == 0 and \
Guido van Rossume2b70bc2006-08-18 22:13:04 +0000611 "attr" not in attrs and \
Lars Gustäbelab647872000-09-24 18:40:52 +0000612 attrs.keys() == [] and \
Fred Drake132dce22000-12-12 23:11:42 +0000613 attrs.get("attrs") is None and \
Lars Gustäbelab647872000-09-24 18:40:52 +0000614 attrs.get("attrs", 25) == 25 and \
615 attrs.items() == [] and \
616 attrs.values() == [] and \
617 gvk and gvqk and gnqk and gik and gqnk
618
619def verify_attrs_wattr(attrs):
620 return attrs.getLength() == 1 and \
621 attrs.getNames() == ["attr"] and \
622 attrs.getQNames() == ["attr"] and \
623 len(attrs) == 1 and \
Guido van Rossume2b70bc2006-08-18 22:13:04 +0000624 "attr" in attrs and \
Lars Gustäbelab647872000-09-24 18:40:52 +0000625 attrs.keys() == ["attr"] and \
626 attrs.get("attr") == "val" and \
627 attrs.get("attr", 25) == "val" and \
628 attrs.items() == [("attr", "val")] and \
629 attrs.values() == ["val"] and \
630 attrs.getValue("attr") == "val" and \
631 attrs.getValueByQName("attr") == "val" and \
632 attrs.getNameByQName("attr") == "attr" and \
633 attrs["attr"] == "val" and \
634 attrs.getQNameByName("attr") == "attr"
635
636def test_attrs_empty():
637 return verify_empty_attrs(AttributesImpl({}))
638
639def test_attrs_wattr():
640 return verify_attrs_wattr(AttributesImpl({"attr" : "val"}))
641
642# ===== AttributesImpl
643
644def verify_empty_nsattrs(attrs):
645 try:
646 attrs.getValue((ns_uri, "attr"))
647 gvk = 0
648 except KeyError:
649 gvk = 1
650
651 try:
652 attrs.getValueByQName("ns:attr")
653 gvqk = 0
654 except KeyError:
655 gvqk = 1
656
657 try:
658 attrs.getNameByQName("ns:attr")
659 gnqk = 0
660 except KeyError:
661 gnqk = 1
662
663 try:
664 attrs.getQNameByName((ns_uri, "attr"))
665 gqnk = 0
666 except KeyError:
667 gqnk = 1
Fred Drake004d5e62000-10-23 17:22:08 +0000668
Lars Gustäbelab647872000-09-24 18:40:52 +0000669 try:
670 attrs[(ns_uri, "attr")]
671 gik = 0
672 except KeyError:
673 gik = 1
Fred Drake004d5e62000-10-23 17:22:08 +0000674
Lars Gustäbelab647872000-09-24 18:40:52 +0000675 return attrs.getLength() == 0 and \
676 attrs.getNames() == [] and \
677 attrs.getQNames() == [] and \
678 len(attrs) == 0 and \
Guido van Rossume2b70bc2006-08-18 22:13:04 +0000679 (ns_uri, "attr") not in attrs and \
Lars Gustäbelab647872000-09-24 18:40:52 +0000680 attrs.keys() == [] and \
Fred Drake132dce22000-12-12 23:11:42 +0000681 attrs.get((ns_uri, "attr")) is None and \
Lars Gustäbelab647872000-09-24 18:40:52 +0000682 attrs.get((ns_uri, "attr"), 25) == 25 and \
683 attrs.items() == [] and \
684 attrs.values() == [] and \
685 gvk and gvqk and gnqk and gik and gqnk
686
687def test_nsattrs_empty():
688 return verify_empty_nsattrs(AttributesNSImpl({}, {}))
689
690def test_nsattrs_wattr():
691 attrs = AttributesNSImpl({(ns_uri, "attr") : "val"},
692 {(ns_uri, "attr") : "ns:attr"})
Fred Drake004d5e62000-10-23 17:22:08 +0000693
Lars Gustäbelab647872000-09-24 18:40:52 +0000694 return attrs.getLength() == 1 and \
695 attrs.getNames() == [(ns_uri, "attr")] and \
696 attrs.getQNames() == ["ns:attr"] and \
697 len(attrs) == 1 and \
Guido van Rossume2b70bc2006-08-18 22:13:04 +0000698 (ns_uri, "attr") in attrs and \
Lars Gustäbelab647872000-09-24 18:40:52 +0000699 attrs.keys() == [(ns_uri, "attr")] and \
700 attrs.get((ns_uri, "attr")) == "val" and \
701 attrs.get((ns_uri, "attr"), 25) == "val" and \
702 attrs.items() == [((ns_uri, "attr"), "val")] and \
703 attrs.values() == ["val"] and \
704 attrs.getValue((ns_uri, "attr")) == "val" and \
705 attrs.getValueByQName("ns:attr") == "val" and \
706 attrs.getNameByQName("ns:attr") == (ns_uri, "attr") and \
707 attrs[(ns_uri, "attr")] == "val" and \
708 attrs.getQNameByName((ns_uri, "attr")) == "ns:attr"
Fred Drake004d5e62000-10-23 17:22:08 +0000709
Lars Gustäbelab647872000-09-24 18:40:52 +0000710
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000711# During the development of Python 2.5, an attempt to move the "xml"
712# package implementation to a new package ("xmlcore") proved painful.
713# The goal of this change was to allow applications to be able to
714# obtain and rely on behavior in the standard library implementation
715# of the XML support without needing to be concerned about the
716# availability of the PyXML implementation.
717#
718# While the existing import hackery in Lib/xml/__init__.py can cause
719# PyXML's _xmlpus package to supplant the "xml" package, that only
720# works because either implementation uses the "xml" package name for
721# imports.
722#
723# The move resulted in a number of problems related to the fact that
724# the import machinery's "package context" is based on the name that's
725# being imported rather than the __name__ of the actual package
726# containment; it wasn't possible for the "xml" package to be replaced
727# by a simple module that indirected imports to the "xmlcore" package.
728#
729# The following two tests exercised bugs that were introduced in that
730# attempt. Keeping these tests around will help detect problems with
731# other attempts to provide reliable access to the standard library's
732# implementation of the XML support.
733
734def test_sf_1511497():
735 # Bug report: http://www.python.org/sf/1511497
736 import sys
737 old_modules = sys.modules.copy()
Guido van Rossum091153d2007-02-11 18:44:55 +0000738 for modname in list(sys.modules.keys()):
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000739 if modname.startswith("xml."):
740 del sys.modules[modname]
741 try:
742 import xml.sax.expatreader
743 module = xml.sax.expatreader
744 return module.__name__ == "xml.sax.expatreader"
745 finally:
746 sys.modules.update(old_modules)
747
748def test_sf_1513611():
749 # Bug report: http://www.python.org/sf/1513611
750 sio = StringIO("invalid")
751 parser = make_parser()
752 from xml.sax import SAXParseException
753 try:
754 parser.parse(sio)
755 except SAXParseException:
756 return True
757 else:
758 return False
759
Lars Gustäbel96753b32000-09-24 12:24:24 +0000760# ===== Main program
761
Lars Gustäbelb7536d52000-09-24 18:53:56 +0000762def make_test_output():
763 parser = create_parser()
764 result = StringIO()
765 xmlgen = XMLGenerator(result)
766
767 parser.setContentHandler(xmlgen)
Guido van Rossume2ae77b2001-10-24 20:42:55 +0000768 parser.parse(findfile("test"+os.extsep+"xml"))
Lars Gustäbelb7536d52000-09-24 18:53:56 +0000769
Guido van Rossume2ae77b2001-10-24 20:42:55 +0000770 outf = open(findfile("test"+os.extsep+"xml"+os.extsep+"out"), "w")
Lars Gustäbelb7536d52000-09-24 18:53:56 +0000771 outf.write(result.getvalue())
772 outf.close()
773
Guido van Rossum091153d2007-02-11 18:44:55 +0000774items = sorted(locals().items())
Lars Gustäbel96753b32000-09-24 12:24:24 +0000775for (name, value) in items:
776 if name[ : 5] == "test_":
777 confirm(value(), name)
Michael W. Hudson3bfed9c2004-08-03 10:17:34 +0000778# We delete the items variable so that the assignment to items above
779# doesn't pick up the old value of items (which messes with attempts
780# to find reference leaks).
781del items
Lars Gustäbel96753b32000-09-24 12:24:24 +0000782
Fred Drake32f3add2002-10-28 17:58:48 +0000783if verbose:
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000784 print("%d tests, %d failures" % (tests, len(failures)))
Fred Drake32f3add2002-10-28 17:58:48 +0000785if failures:
786 raise TestFailed("%d of %d tests failed: %s"
787 % (len(failures), tests, ", ".join(failures)))