blob: 59e14c5ef3785fc77b3a34c6687fde387e1ac05d [file] [log] [blame]
Lars Gustäbel96753b32000-09-24 12:24:24 +00001# regression test for SAX 2.0
2# $Id$
3
Martin v. Löwis80670bc2000-10-06 21:13:23 +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")
Lars Gustäbel96753b32000-09-24 12:24:24 +000011from xml.sax.saxutils import XMLGenerator, escape, XMLFilterBase
12from xml.sax.expatreader import create_parser
Lars Gustäbelb7536d52000-09-24 18:53:56 +000013from xml.sax.xmlreader import InputSource, AttributesImpl, AttributesNSImpl
Lars Gustäbel96753b32000-09-24 12:24:24 +000014from cStringIO import StringIO
Martin v. Löwis33315b12000-09-24 20:30:24 +000015from test_support import verbose, TestFailed, findfile
Lars Gustäbel96753b32000-09-24 12:24:24 +000016
17# ===== Utilities
18
19tests = 0
20fails = 0
21
22def confirm(outcome, name):
23 global tests, fails
24
25 tests = tests + 1
26 if outcome:
27 print "Passed", name
28 else:
29 print "Failed", name
30 fails = fails + 1
31
Lars Gustäbel2fc52942000-10-24 15:35:07 +000032def test_make_parser2():
33 try:
34 # Creating parsers several times in a row should succeed.
35 # Testing this because there have been failures of this kind
36 # before.
37 from xml.sax import make_parser
38 p = make_parser()
39 from xml.sax import make_parser
40 p = make_parser()
41 from xml.sax import make_parser
42 p = make_parser()
43 from xml.sax import make_parser
44 p = make_parser()
45 from xml.sax import make_parser
46 p = make_parser()
47 from xml.sax import make_parser
48 p = make_parser()
49 except:
50 return 0
51 else:
52 return p
53
54
Lars Gustäbel96753b32000-09-24 12:24:24 +000055# ===========================================================================
56#
57# saxutils tests
58#
59# ===========================================================================
60
61# ===== escape
62
63def test_escape_basic():
64 return escape("Donald Duck & Co") == "Donald Duck & Co"
65
66def test_escape_all():
67 return escape("<Donald Duck & Co>") == "&lt;Donald Duck &amp; Co&gt;"
68
69def test_escape_extra():
70 return escape("Hei på deg", {"å" : "&aring;"}) == "Hei p&aring; deg"
71
Martin v. Löwis962c9e72000-10-06 17:41:52 +000072def test_make_parser():
73 try:
74 # Creating a parser should succeed - it should fall back
75 # to the expatreader
76 p = make_parser(['xml.parsers.no_such_parser'])
77 except:
78 return 0
79 else:
80 return p
81
82
Lars Gustäbel96753b32000-09-24 12:24:24 +000083# ===== XMLGenerator
84
85start = '<?xml version="1.0" encoding="iso-8859-1"?>\n'
86
87def test_xmlgen_basic():
88 result = StringIO()
89 gen = XMLGenerator(result)
90 gen.startDocument()
91 gen.startElement("doc", {})
92 gen.endElement("doc")
93 gen.endDocument()
94
95 return result.getvalue() == start + "<doc></doc>"
96
97def test_xmlgen_content():
98 result = StringIO()
99 gen = XMLGenerator(result)
Fred Drake004d5e62000-10-23 17:22:08 +0000100
Lars Gustäbel96753b32000-09-24 12:24:24 +0000101 gen.startDocument()
102 gen.startElement("doc", {})
103 gen.characters("huhei")
104 gen.endElement("doc")
105 gen.endDocument()
106
107 return result.getvalue() == start + "<doc>huhei</doc>"
108
109def test_xmlgen_pi():
110 result = StringIO()
111 gen = XMLGenerator(result)
Fred Drake004d5e62000-10-23 17:22:08 +0000112
Lars Gustäbel96753b32000-09-24 12:24:24 +0000113 gen.startDocument()
114 gen.processingInstruction("test", "data")
115 gen.startElement("doc", {})
116 gen.endElement("doc")
117 gen.endDocument()
118
119 return result.getvalue() == start + "<?test data?><doc></doc>"
120
121def test_xmlgen_content_escape():
122 result = StringIO()
123 gen = XMLGenerator(result)
Fred Drake004d5e62000-10-23 17:22:08 +0000124
Lars Gustäbel96753b32000-09-24 12:24:24 +0000125 gen.startDocument()
126 gen.startElement("doc", {})
127 gen.characters("<huhei&")
128 gen.endElement("doc")
129 gen.endDocument()
130
131 return result.getvalue() == start + "<doc>&lt;huhei&amp;</doc>"
132
133def test_xmlgen_ignorable():
134 result = StringIO()
135 gen = XMLGenerator(result)
Fred Drake004d5e62000-10-23 17:22:08 +0000136
Lars Gustäbel96753b32000-09-24 12:24:24 +0000137 gen.startDocument()
138 gen.startElement("doc", {})
139 gen.ignorableWhitespace(" ")
140 gen.endElement("doc")
141 gen.endDocument()
142
143 return result.getvalue() == start + "<doc> </doc>"
144
145ns_uri = "http://www.python.org/xml-ns/saxtest/"
146
147def test_xmlgen_ns():
148 result = StringIO()
149 gen = XMLGenerator(result)
Fred Drake004d5e62000-10-23 17:22:08 +0000150
Lars Gustäbel96753b32000-09-24 12:24:24 +0000151 gen.startDocument()
152 gen.startPrefixMapping("ns1", ns_uri)
Lars Gustäbel6a7768a2000-09-27 08:12:17 +0000153 gen.startElementNS((ns_uri, "doc"), "ns1:doc", {})
Martin v. Löwiscf0a1cc2000-10-03 22:35:29 +0000154 # add an unqualified name
155 gen.startElementNS((None, "udoc"), None, {})
156 gen.endElementNS((None, "udoc"), None)
Lars Gustäbel6a7768a2000-09-27 08:12:17 +0000157 gen.endElementNS((ns_uri, "doc"), "ns1:doc")
Lars Gustäbel96753b32000-09-24 12:24:24 +0000158 gen.endPrefixMapping("ns1")
159 gen.endDocument()
160
Martin v. Löwiscf0a1cc2000-10-03 22:35:29 +0000161 return result.getvalue() == start + \
162 ('<ns1:doc xmlns:ns1="%s"><udoc></udoc></ns1:doc>' %
Lars Gustäbel96753b32000-09-24 12:24:24 +0000163 ns_uri)
164
165# ===== XMLFilterBase
166
167def test_filter_basic():
168 result = StringIO()
169 gen = XMLGenerator(result)
170 filter = XMLFilterBase()
171 filter.setContentHandler(gen)
Fred Drake004d5e62000-10-23 17:22:08 +0000172
Lars Gustäbel96753b32000-09-24 12:24:24 +0000173 filter.startDocument()
174 filter.startElement("doc", {})
175 filter.characters("content")
176 filter.ignorableWhitespace(" ")
177 filter.endElement("doc")
178 filter.endDocument()
179
180 return result.getvalue() == start + "<doc>content </doc>"
181
182# ===========================================================================
183#
184# expatreader tests
185#
186# ===========================================================================
187
188# ===== DTDHandler support
189
190class TestDTDHandler:
191
192 def __init__(self):
193 self._notations = []
194 self._entities = []
Fred Drake004d5e62000-10-23 17:22:08 +0000195
Lars Gustäbel96753b32000-09-24 12:24:24 +0000196 def notationDecl(self, name, publicId, systemId):
197 self._notations.append((name, publicId, systemId))
198
199 def unparsedEntityDecl(self, name, publicId, systemId, ndata):
200 self._entities.append((name, publicId, systemId, ndata))
201
Lars Gustäbele292a242000-09-24 20:19:45 +0000202def test_expat_dtdhandler():
203 parser = create_parser()
204 handler = TestDTDHandler()
205 parser.setDTDHandler(handler)
Lars Gustäbel96753b32000-09-24 12:24:24 +0000206
Lars Gustäbele292a242000-09-24 20:19:45 +0000207 parser.feed('<!DOCTYPE doc [\n')
208 parser.feed(' <!ENTITY img SYSTEM "expat.gif" NDATA GIF>\n')
209 parser.feed(' <!NOTATION GIF PUBLIC "-//CompuServe//NOTATION Graphics Interchange Format 89a//EN">\n')
210 parser.feed(']>\n')
211 parser.feed('<doc></doc>')
212 parser.close()
Lars Gustäbel96753b32000-09-24 12:24:24 +0000213
Lars Gustäbele292a242000-09-24 20:19:45 +0000214 return handler._notations == [("GIF", "-//CompuServe//NOTATION Graphics Interchange Format 89a//EN", None)] and \
215 handler._entities == [("img", None, "expat.gif", "GIF")]
Lars Gustäbel96753b32000-09-24 12:24:24 +0000216
217# ===== EntityResolver support
218
Lars Gustäbele292a242000-09-24 20:19:45 +0000219class TestEntityResolver:
Lars Gustäbel96753b32000-09-24 12:24:24 +0000220
Lars Gustäbele292a242000-09-24 20:19:45 +0000221 def resolveEntity(self, publicId, systemId):
222 inpsrc = InputSource()
223 inpsrc.setByteStream(StringIO("<entity/>"))
224 return inpsrc
225
226def test_expat_entityresolver():
Lars Gustäbele292a242000-09-24 20:19:45 +0000227 parser = create_parser()
228 parser.setEntityResolver(TestEntityResolver())
229 result = StringIO()
230 parser.setContentHandler(XMLGenerator(result))
231
232 parser.feed('<!DOCTYPE doc [\n')
233 parser.feed(' <!ENTITY test SYSTEM "whatever">\n')
234 parser.feed(']>\n')
235 parser.feed('<doc>&test;</doc>')
236 parser.close()
237
238 return result.getvalue() == start + "<doc><entity></entity></doc>"
Fred Drake004d5e62000-10-23 17:22:08 +0000239
Lars Gustäbelab647872000-09-24 18:40:52 +0000240# ===== Attributes support
241
242class AttrGatherer(ContentHandler):
243
244 def startElement(self, name, attrs):
245 self._attrs = attrs
246
247 def startElementNS(self, name, qname, attrs):
248 self._attrs = attrs
Fred Drake004d5e62000-10-23 17:22:08 +0000249
Lars Gustäbelab647872000-09-24 18:40:52 +0000250def test_expat_attrs_empty():
251 parser = create_parser()
252 gather = AttrGatherer()
253 parser.setContentHandler(gather)
254
255 parser.feed("<doc/>")
256 parser.close()
257
258 return verify_empty_attrs(gather._attrs)
259
260def test_expat_attrs_wattr():
261 parser = create_parser()
262 gather = AttrGatherer()
263 parser.setContentHandler(gather)
264
265 parser.feed("<doc attr='val'/>")
266 parser.close()
267
268 return verify_attrs_wattr(gather._attrs)
269
270def test_expat_nsattrs_empty():
271 parser = create_parser(1)
272 gather = AttrGatherer()
273 parser.setContentHandler(gather)
274
275 parser.feed("<doc/>")
276 parser.close()
277
278 return verify_empty_nsattrs(gather._attrs)
279
280def test_expat_nsattrs_wattr():
281 parser = create_parser(1)
282 gather = AttrGatherer()
283 parser.setContentHandler(gather)
284
285 parser.feed("<doc xmlns:ns='%s' ns:attr='val'/>" % ns_uri)
286 parser.close()
287
288 attrs = gather._attrs
Fred Drake004d5e62000-10-23 17:22:08 +0000289
Lars Gustäbelab647872000-09-24 18:40:52 +0000290 return attrs.getLength() == 1 and \
291 attrs.getNames() == [(ns_uri, "attr")] and \
292 attrs.getQNames() == [] and \
293 len(attrs) == 1 and \
294 attrs.has_key((ns_uri, "attr")) and \
295 attrs.keys() == [(ns_uri, "attr")] and \
296 attrs.get((ns_uri, "attr")) == "val" and \
297 attrs.get((ns_uri, "attr"), 25) == "val" and \
298 attrs.items() == [((ns_uri, "attr"), "val")] and \
299 attrs.values() == ["val"] and \
300 attrs.getValue((ns_uri, "attr")) == "val" and \
301 attrs[(ns_uri, "attr")] == "val"
302
Lars Gustäbelb7536d52000-09-24 18:53:56 +0000303# ===== InputSource support
304
Martin v. Löwis33315b12000-09-24 20:30:24 +0000305xml_test_out = open(findfile("test.xml.out")).read()
Lars Gustäbelb7536d52000-09-24 18:53:56 +0000306
307def test_expat_inpsource_filename():
308 parser = create_parser()
309 result = StringIO()
310 xmlgen = XMLGenerator(result)
311
312 parser.setContentHandler(xmlgen)
Martin v. Löwis33315b12000-09-24 20:30:24 +0000313 parser.parse(findfile("test.xml"))
Lars Gustäbelb7536d52000-09-24 18:53:56 +0000314
315 return result.getvalue() == xml_test_out
316
317def test_expat_inpsource_sysid():
318 parser = create_parser()
319 result = StringIO()
320 xmlgen = XMLGenerator(result)
321
322 parser.setContentHandler(xmlgen)
Martin v. Löwis33315b12000-09-24 20:30:24 +0000323 parser.parse(InputSource(findfile("test.xml")))
Lars Gustäbelb7536d52000-09-24 18:53:56 +0000324
325 return result.getvalue() == xml_test_out
326
327def test_expat_inpsource_stream():
328 parser = create_parser()
329 result = StringIO()
330 xmlgen = XMLGenerator(result)
331
332 parser.setContentHandler(xmlgen)
333 inpsrc = InputSource()
Martin v. Löwis33315b12000-09-24 20:30:24 +0000334 inpsrc.setByteStream(open(findfile("test.xml")))
Lars Gustäbelb7536d52000-09-24 18:53:56 +0000335 parser.parse(inpsrc)
336
337 return result.getvalue() == xml_test_out
338
Lars Gustäbel2fc52942000-10-24 15:35:07 +0000339# ===== IncrementalParser support
340
341def test_expat_incremental():
342 result = StringIO()
343 xmlgen = XMLGenerator(result)
344 parser = create_parser()
345 parser.setContentHandler(xmlgen)
346
347 parser.feed("<doc>")
348 parser.feed("</doc>")
349 parser.close()
350
351 return result.getvalue() == start + "<doc></doc>"
352
353def test_expat_incremental_reset():
354 result = StringIO()
355 xmlgen = XMLGenerator(result)
356 parser = create_parser()
357 parser.setContentHandler(xmlgen)
358
359 parser.feed("<doc>")
360 parser.feed("text")
361
362 result = StringIO()
363 xmlgen = XMLGenerator(result)
364 parser.setContentHandler(xmlgen)
365 parser.reset()
366
367 parser.feed("<doc>")
368 parser.feed("text")
369 parser.feed("</doc>")
370 parser.close()
371
372 return result.getvalue() == start + "<doc>text</doc>"
373
374# ===== Locator support
375
376def test_expat_locator_noinfo():
377 result = StringIO()
378 xmlgen = XMLGenerator(result)
379 parser = create_parser()
380 parser.setContentHandler(xmlgen)
381
382 parser.feed("<doc>")
383 parser.feed("</doc>")
384 parser.close()
385
386 return parser.getSystemId() == None and \
387 parser.getPublicId() == None and \
388 parser.getLineNumber() == 1
389
390def test_expat_locator_withinfo():
391 result = StringIO()
392 xmlgen = XMLGenerator(result)
393 parser = create_parser()
394 parser.setContentHandler(xmlgen)
395 parser.parse(findfile("test.xml"))
396
397 return parser.getSystemId() == findfile("test.xml") and \
398 parser.getPublicId() == None
399
Martin v. Löwis80670bc2000-10-06 21:13:23 +0000400
401# ===========================================================================
402#
403# error reporting
404#
405# ===========================================================================
406
407def test_expat_inpsource_location():
408 parser = create_parser()
409 parser.setContentHandler(ContentHandler()) # do nothing
410 source = InputSource()
411 source.setByteStream(StringIO("<foo bar foobar>")) #ill-formed
412 name = "a file name"
413 source.setSystemId(name)
414 try:
415 parser.parse(source)
416 except SAXException, e:
417 return e.getSystemId() == name
418
419def test_expat_incomplete():
420 parser = create_parser()
421 parser.setContentHandler(ContentHandler()) # do nothing
422 try:
423 parser.parse(StringIO("<foo>"))
424 except SAXParseException:
425 return 1 # ok, error found
426 else:
427 return 0
428
429
Lars Gustäbelab647872000-09-24 18:40:52 +0000430# ===========================================================================
431#
432# xmlreader tests
433#
434# ===========================================================================
435
436# ===== AttributesImpl
437
438def verify_empty_attrs(attrs):
439 try:
440 attrs.getValue("attr")
441 gvk = 0
442 except KeyError:
443 gvk = 1
444
445 try:
446 attrs.getValueByQName("attr")
447 gvqk = 0
448 except KeyError:
449 gvqk = 1
450
451 try:
452 attrs.getNameByQName("attr")
453 gnqk = 0
454 except KeyError:
455 gnqk = 1
456
457 try:
458 attrs.getQNameByName("attr")
459 gqnk = 0
460 except KeyError:
461 gqnk = 1
Fred Drake004d5e62000-10-23 17:22:08 +0000462
Lars Gustäbelab647872000-09-24 18:40:52 +0000463 try:
464 attrs["attr"]
465 gik = 0
466 except KeyError:
467 gik = 1
Fred Drake004d5e62000-10-23 17:22:08 +0000468
Lars Gustäbelab647872000-09-24 18:40:52 +0000469 return attrs.getLength() == 0 and \
470 attrs.getNames() == [] and \
471 attrs.getQNames() == [] and \
472 len(attrs) == 0 and \
473 not attrs.has_key("attr") and \
474 attrs.keys() == [] and \
475 attrs.get("attrs") == None and \
476 attrs.get("attrs", 25) == 25 and \
477 attrs.items() == [] and \
478 attrs.values() == [] and \
479 gvk and gvqk and gnqk and gik and gqnk
480
481def verify_attrs_wattr(attrs):
482 return attrs.getLength() == 1 and \
483 attrs.getNames() == ["attr"] and \
484 attrs.getQNames() == ["attr"] and \
485 len(attrs) == 1 and \
486 attrs.has_key("attr") and \
487 attrs.keys() == ["attr"] and \
488 attrs.get("attr") == "val" and \
489 attrs.get("attr", 25) == "val" and \
490 attrs.items() == [("attr", "val")] and \
491 attrs.values() == ["val"] and \
492 attrs.getValue("attr") == "val" and \
493 attrs.getValueByQName("attr") == "val" and \
494 attrs.getNameByQName("attr") == "attr" and \
495 attrs["attr"] == "val" and \
496 attrs.getQNameByName("attr") == "attr"
497
498def test_attrs_empty():
499 return verify_empty_attrs(AttributesImpl({}))
500
501def test_attrs_wattr():
502 return verify_attrs_wattr(AttributesImpl({"attr" : "val"}))
503
504# ===== AttributesImpl
505
506def verify_empty_nsattrs(attrs):
507 try:
508 attrs.getValue((ns_uri, "attr"))
509 gvk = 0
510 except KeyError:
511 gvk = 1
512
513 try:
514 attrs.getValueByQName("ns:attr")
515 gvqk = 0
516 except KeyError:
517 gvqk = 1
518
519 try:
520 attrs.getNameByQName("ns:attr")
521 gnqk = 0
522 except KeyError:
523 gnqk = 1
524
525 try:
526 attrs.getQNameByName((ns_uri, "attr"))
527 gqnk = 0
528 except KeyError:
529 gqnk = 1
Fred Drake004d5e62000-10-23 17:22:08 +0000530
Lars Gustäbelab647872000-09-24 18:40:52 +0000531 try:
532 attrs[(ns_uri, "attr")]
533 gik = 0
534 except KeyError:
535 gik = 1
Fred Drake004d5e62000-10-23 17:22:08 +0000536
Lars Gustäbelab647872000-09-24 18:40:52 +0000537 return attrs.getLength() == 0 and \
538 attrs.getNames() == [] and \
539 attrs.getQNames() == [] and \
540 len(attrs) == 0 and \
541 not attrs.has_key((ns_uri, "attr")) and \
542 attrs.keys() == [] and \
543 attrs.get((ns_uri, "attr")) == None and \
544 attrs.get((ns_uri, "attr"), 25) == 25 and \
545 attrs.items() == [] and \
546 attrs.values() == [] and \
547 gvk and gvqk and gnqk and gik and gqnk
548
549def test_nsattrs_empty():
550 return verify_empty_nsattrs(AttributesNSImpl({}, {}))
551
552def test_nsattrs_wattr():
553 attrs = AttributesNSImpl({(ns_uri, "attr") : "val"},
554 {(ns_uri, "attr") : "ns:attr"})
Fred Drake004d5e62000-10-23 17:22:08 +0000555
Lars Gustäbelab647872000-09-24 18:40:52 +0000556 return attrs.getLength() == 1 and \
557 attrs.getNames() == [(ns_uri, "attr")] and \
558 attrs.getQNames() == ["ns:attr"] and \
559 len(attrs) == 1 and \
560 attrs.has_key((ns_uri, "attr")) and \
561 attrs.keys() == [(ns_uri, "attr")] and \
562 attrs.get((ns_uri, "attr")) == "val" and \
563 attrs.get((ns_uri, "attr"), 25) == "val" and \
564 attrs.items() == [((ns_uri, "attr"), "val")] and \
565 attrs.values() == ["val"] and \
566 attrs.getValue((ns_uri, "attr")) == "val" and \
567 attrs.getValueByQName("ns:attr") == "val" and \
568 attrs.getNameByQName("ns:attr") == (ns_uri, "attr") and \
569 attrs[(ns_uri, "attr")] == "val" and \
570 attrs.getQNameByName((ns_uri, "attr")) == "ns:attr"
Fred Drake004d5e62000-10-23 17:22:08 +0000571
Lars Gustäbelab647872000-09-24 18:40:52 +0000572
Lars Gustäbel96753b32000-09-24 12:24:24 +0000573# ===== Main program
574
Lars Gustäbelb7536d52000-09-24 18:53:56 +0000575def make_test_output():
576 parser = create_parser()
577 result = StringIO()
578 xmlgen = XMLGenerator(result)
579
580 parser.setContentHandler(xmlgen)
Martin v. Löwis33315b12000-09-24 20:30:24 +0000581 parser.parse(findfile("test.xml"))
Lars Gustäbelb7536d52000-09-24 18:53:56 +0000582
Martin v. Löwis33315b12000-09-24 20:30:24 +0000583 outf = open(findfile("test.xml.out"), "w")
Lars Gustäbelb7536d52000-09-24 18:53:56 +0000584 outf.write(result.getvalue())
585 outf.close()
586
Lars Gustäbel96753b32000-09-24 12:24:24 +0000587items = locals().items()
588items.sort()
589for (name, value) in items:
590 if name[ : 5] == "test_":
591 confirm(value(), name)
592
593print "%d tests, %d failures" % (tests, fails)
594if fails != 0:
595 raise TestFailed, "%d of %d tests failed" % (fails, tests)