Apparently the code to forestall Tk eating events was too aggressive (Tk user input...
[python/dscho.git] / Lib / test / test_sax.py
blobf4b43fede83ee74d939c2570da6746f297c463d8
1 # regression test for SAX 2.0
2 # $Id$
4 from xml.sax import make_parser, ContentHandler, \
5 SAXException, SAXReaderNotAvailable, SAXParseException
6 try:
7 make_parser()
8 except SAXReaderNotAvailable:
9 # don't try to test this module if we cannot create a parser
10 raise ImportError("no XML parsers available")
11 from xml.sax.saxutils import XMLGenerator, escape, XMLFilterBase
12 from xml.sax.expatreader import create_parser
13 from xml.sax.xmlreader import InputSource, AttributesImpl, AttributesNSImpl
14 from cStringIO import StringIO
15 from test_support import verify, verbose, TestFailed, findfile
17 # ===== Utilities
19 tests = 0
20 fails = 0
22 def confirm(outcome, name):
23 global tests, fails
25 tests = tests + 1
26 if outcome:
27 print "Passed", name
28 else:
29 print "Failed", name
30 fails = fails + 1
32 def 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
55 # ===========================================================================
57 # saxutils tests
59 # ===========================================================================
61 # ===== escape
63 def test_escape_basic():
64 return escape("Donald Duck & Co") == "Donald Duck & Co"
66 def test_escape_all():
67 return escape("<Donald Duck & Co>") == "&lt;Donald Duck &amp; Co&gt;"
69 def test_escape_extra():
70 return escape("Hei på deg", {"å" : "&aring;"}) == "Hei p&aring; deg"
72 def 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
83 # ===== XMLGenerator
85 start = '<?xml version="1.0" encoding="iso-8859-1"?>\n'
87 def test_xmlgen_basic():
88 result = StringIO()
89 gen = XMLGenerator(result)
90 gen.startDocument()
91 gen.startElement("doc", {})
92 gen.endElement("doc")
93 gen.endDocument()
95 return result.getvalue() == start + "<doc></doc>"
97 def test_xmlgen_content():
98 result = StringIO()
99 gen = XMLGenerator(result)
101 gen.startDocument()
102 gen.startElement("doc", {})
103 gen.characters("huhei")
104 gen.endElement("doc")
105 gen.endDocument()
107 return result.getvalue() == start + "<doc>huhei</doc>"
109 def test_xmlgen_pi():
110 result = StringIO()
111 gen = XMLGenerator(result)
113 gen.startDocument()
114 gen.processingInstruction("test", "data")
115 gen.startElement("doc", {})
116 gen.endElement("doc")
117 gen.endDocument()
119 return result.getvalue() == start + "<?test data?><doc></doc>"
121 def test_xmlgen_content_escape():
122 result = StringIO()
123 gen = XMLGenerator(result)
125 gen.startDocument()
126 gen.startElement("doc", {})
127 gen.characters("<huhei&")
128 gen.endElement("doc")
129 gen.endDocument()
131 return result.getvalue() == start + "<doc>&lt;huhei&amp;</doc>"
133 def test_xmlgen_ignorable():
134 result = StringIO()
135 gen = XMLGenerator(result)
137 gen.startDocument()
138 gen.startElement("doc", {})
139 gen.ignorableWhitespace(" ")
140 gen.endElement("doc")
141 gen.endDocument()
143 return result.getvalue() == start + "<doc> </doc>"
145 ns_uri = "http://www.python.org/xml-ns/saxtest/"
147 def test_xmlgen_ns():
148 result = StringIO()
149 gen = XMLGenerator(result)
151 gen.startDocument()
152 gen.startPrefixMapping("ns1", ns_uri)
153 gen.startElementNS((ns_uri, "doc"), "ns1:doc", {})
154 # add an unqualified name
155 gen.startElementNS((None, "udoc"), None, {})
156 gen.endElementNS((None, "udoc"), None)
157 gen.endElementNS((ns_uri, "doc"), "ns1:doc")
158 gen.endPrefixMapping("ns1")
159 gen.endDocument()
161 return result.getvalue() == start + \
162 ('<ns1:doc xmlns:ns1="%s"><udoc></udoc></ns1:doc>' %
163 ns_uri)
165 # ===== XMLFilterBase
167 def test_filter_basic():
168 result = StringIO()
169 gen = XMLGenerator(result)
170 filter = XMLFilterBase()
171 filter.setContentHandler(gen)
173 filter.startDocument()
174 filter.startElement("doc", {})
175 filter.characters("content")
176 filter.ignorableWhitespace(" ")
177 filter.endElement("doc")
178 filter.endDocument()
180 return result.getvalue() == start + "<doc>content </doc>"
182 # ===========================================================================
184 # expatreader tests
186 # ===========================================================================
188 # ===== XMLReader support
190 def test_expat_file():
191 parser = create_parser()
192 result = StringIO()
193 xmlgen = XMLGenerator(result)
195 parser.setContentHandler(xmlgen)
196 parser.parse(open(findfile("test.xml")))
198 return result.getvalue() == xml_test_out
200 # ===== DTDHandler support
202 class TestDTDHandler:
204 def __init__(self):
205 self._notations = []
206 self._entities = []
208 def notationDecl(self, name, publicId, systemId):
209 self._notations.append((name, publicId, systemId))
211 def unparsedEntityDecl(self, name, publicId, systemId, ndata):
212 self._entities.append((name, publicId, systemId, ndata))
214 def test_expat_dtdhandler():
215 parser = create_parser()
216 handler = TestDTDHandler()
217 parser.setDTDHandler(handler)
219 parser.feed('<!DOCTYPE doc [\n')
220 parser.feed(' <!ENTITY img SYSTEM "expat.gif" NDATA GIF>\n')
221 parser.feed(' <!NOTATION GIF PUBLIC "-//CompuServe//NOTATION Graphics Interchange Format 89a//EN">\n')
222 parser.feed(']>\n')
223 parser.feed('<doc></doc>')
224 parser.close()
226 return handler._notations == [("GIF", "-//CompuServe//NOTATION Graphics Interchange Format 89a//EN", None)] and \
227 handler._entities == [("img", None, "expat.gif", "GIF")]
229 # ===== EntityResolver support
231 class TestEntityResolver:
233 def resolveEntity(self, publicId, systemId):
234 inpsrc = InputSource()
235 inpsrc.setByteStream(StringIO("<entity/>"))
236 return inpsrc
238 def test_expat_entityresolver():
239 parser = create_parser()
240 parser.setEntityResolver(TestEntityResolver())
241 result = StringIO()
242 parser.setContentHandler(XMLGenerator(result))
244 parser.feed('<!DOCTYPE doc [\n')
245 parser.feed(' <!ENTITY test SYSTEM "whatever">\n')
246 parser.feed(']>\n')
247 parser.feed('<doc>&test;</doc>')
248 parser.close()
250 return result.getvalue() == start + "<doc><entity></entity></doc>"
252 # ===== Attributes support
254 class AttrGatherer(ContentHandler):
256 def startElement(self, name, attrs):
257 self._attrs = attrs
259 def startElementNS(self, name, qname, attrs):
260 self._attrs = attrs
262 def test_expat_attrs_empty():
263 parser = create_parser()
264 gather = AttrGatherer()
265 parser.setContentHandler(gather)
267 parser.feed("<doc/>")
268 parser.close()
270 return verify_empty_attrs(gather._attrs)
272 def test_expat_attrs_wattr():
273 parser = create_parser()
274 gather = AttrGatherer()
275 parser.setContentHandler(gather)
277 parser.feed("<doc attr='val'/>")
278 parser.close()
280 return verify_attrs_wattr(gather._attrs)
282 def test_expat_nsattrs_empty():
283 parser = create_parser(1)
284 gather = AttrGatherer()
285 parser.setContentHandler(gather)
287 parser.feed("<doc/>")
288 parser.close()
290 return verify_empty_nsattrs(gather._attrs)
292 def test_expat_nsattrs_wattr():
293 parser = create_parser(1)
294 gather = AttrGatherer()
295 parser.setContentHandler(gather)
297 parser.feed("<doc xmlns:ns='%s' ns:attr='val'/>" % ns_uri)
298 parser.close()
300 attrs = gather._attrs
302 return attrs.getLength() == 1 and \
303 attrs.getNames() == [(ns_uri, "attr")] and \
304 attrs.getQNames() == [] and \
305 len(attrs) == 1 and \
306 attrs.has_key((ns_uri, "attr")) and \
307 attrs.keys() == [(ns_uri, "attr")] and \
308 attrs.get((ns_uri, "attr")) == "val" and \
309 attrs.get((ns_uri, "attr"), 25) == "val" and \
310 attrs.items() == [((ns_uri, "attr"), "val")] and \
311 attrs.values() == ["val"] and \
312 attrs.getValue((ns_uri, "attr")) == "val" and \
313 attrs[(ns_uri, "attr")] == "val"
315 # ===== InputSource support
317 xml_test_out = open(findfile("test.xml.out")).read()
319 def test_expat_inpsource_filename():
320 parser = create_parser()
321 result = StringIO()
322 xmlgen = XMLGenerator(result)
324 parser.setContentHandler(xmlgen)
325 parser.parse(findfile("test.xml"))
327 return result.getvalue() == xml_test_out
329 def test_expat_inpsource_sysid():
330 parser = create_parser()
331 result = StringIO()
332 xmlgen = XMLGenerator(result)
334 parser.setContentHandler(xmlgen)
335 parser.parse(InputSource(findfile("test.xml")))
337 return result.getvalue() == xml_test_out
339 def test_expat_inpsource_stream():
340 parser = create_parser()
341 result = StringIO()
342 xmlgen = XMLGenerator(result)
344 parser.setContentHandler(xmlgen)
345 inpsrc = InputSource()
346 inpsrc.setByteStream(open(findfile("test.xml")))
347 parser.parse(inpsrc)
349 return result.getvalue() == xml_test_out
351 # ===== IncrementalParser support
353 def test_expat_incremental():
354 result = StringIO()
355 xmlgen = XMLGenerator(result)
356 parser = create_parser()
357 parser.setContentHandler(xmlgen)
359 parser.feed("<doc>")
360 parser.feed("</doc>")
361 parser.close()
363 return result.getvalue() == start + "<doc></doc>"
365 def test_expat_incremental_reset():
366 result = StringIO()
367 xmlgen = XMLGenerator(result)
368 parser = create_parser()
369 parser.setContentHandler(xmlgen)
371 parser.feed("<doc>")
372 parser.feed("text")
374 result = StringIO()
375 xmlgen = XMLGenerator(result)
376 parser.setContentHandler(xmlgen)
377 parser.reset()
379 parser.feed("<doc>")
380 parser.feed("text")
381 parser.feed("</doc>")
382 parser.close()
384 return result.getvalue() == start + "<doc>text</doc>"
386 # ===== Locator support
388 def test_expat_locator_noinfo():
389 result = StringIO()
390 xmlgen = XMLGenerator(result)
391 parser = create_parser()
392 parser.setContentHandler(xmlgen)
394 parser.feed("<doc>")
395 parser.feed("</doc>")
396 parser.close()
398 return parser.getSystemId() is None and \
399 parser.getPublicId() is None and \
400 parser.getLineNumber() == 1
402 def test_expat_locator_withinfo():
403 result = StringIO()
404 xmlgen = XMLGenerator(result)
405 parser = create_parser()
406 parser.setContentHandler(xmlgen)
407 parser.parse(findfile("test.xml"))
409 return parser.getSystemId() == findfile("test.xml") and \
410 parser.getPublicId() is None
413 # ===========================================================================
415 # error reporting
417 # ===========================================================================
419 def test_expat_inpsource_location():
420 parser = create_parser()
421 parser.setContentHandler(ContentHandler()) # do nothing
422 source = InputSource()
423 source.setByteStream(StringIO("<foo bar foobar>")) #ill-formed
424 name = "a file name"
425 source.setSystemId(name)
426 try:
427 parser.parse(source)
428 except SAXException, e:
429 return e.getSystemId() == name
431 def test_expat_incomplete():
432 parser = create_parser()
433 parser.setContentHandler(ContentHandler()) # do nothing
434 try:
435 parser.parse(StringIO("<foo>"))
436 except SAXParseException:
437 return 1 # ok, error found
438 else:
439 return 0
442 # ===========================================================================
444 # xmlreader tests
446 # ===========================================================================
448 # ===== AttributesImpl
450 def verify_empty_attrs(attrs):
451 try:
452 attrs.getValue("attr")
453 gvk = 0
454 except KeyError:
455 gvk = 1
457 try:
458 attrs.getValueByQName("attr")
459 gvqk = 0
460 except KeyError:
461 gvqk = 1
463 try:
464 attrs.getNameByQName("attr")
465 gnqk = 0
466 except KeyError:
467 gnqk = 1
469 try:
470 attrs.getQNameByName("attr")
471 gqnk = 0
472 except KeyError:
473 gqnk = 1
475 try:
476 attrs["attr"]
477 gik = 0
478 except KeyError:
479 gik = 1
481 return attrs.getLength() == 0 and \
482 attrs.getNames() == [] and \
483 attrs.getQNames() == [] and \
484 len(attrs) == 0 and \
485 not attrs.has_key("attr") and \
486 attrs.keys() == [] and \
487 attrs.get("attrs") is None and \
488 attrs.get("attrs", 25) == 25 and \
489 attrs.items() == [] and \
490 attrs.values() == [] and \
491 gvk and gvqk and gnqk and gik and gqnk
493 def verify_attrs_wattr(attrs):
494 return attrs.getLength() == 1 and \
495 attrs.getNames() == ["attr"] and \
496 attrs.getQNames() == ["attr"] and \
497 len(attrs) == 1 and \
498 attrs.has_key("attr") and \
499 attrs.keys() == ["attr"] and \
500 attrs.get("attr") == "val" and \
501 attrs.get("attr", 25) == "val" and \
502 attrs.items() == [("attr", "val")] and \
503 attrs.values() == ["val"] and \
504 attrs.getValue("attr") == "val" and \
505 attrs.getValueByQName("attr") == "val" and \
506 attrs.getNameByQName("attr") == "attr" and \
507 attrs["attr"] == "val" and \
508 attrs.getQNameByName("attr") == "attr"
510 def test_attrs_empty():
511 return verify_empty_attrs(AttributesImpl({}))
513 def test_attrs_wattr():
514 return verify_attrs_wattr(AttributesImpl({"attr" : "val"}))
516 # ===== AttributesImpl
518 def verify_empty_nsattrs(attrs):
519 try:
520 attrs.getValue((ns_uri, "attr"))
521 gvk = 0
522 except KeyError:
523 gvk = 1
525 try:
526 attrs.getValueByQName("ns:attr")
527 gvqk = 0
528 except KeyError:
529 gvqk = 1
531 try:
532 attrs.getNameByQName("ns:attr")
533 gnqk = 0
534 except KeyError:
535 gnqk = 1
537 try:
538 attrs.getQNameByName((ns_uri, "attr"))
539 gqnk = 0
540 except KeyError:
541 gqnk = 1
543 try:
544 attrs[(ns_uri, "attr")]
545 gik = 0
546 except KeyError:
547 gik = 1
549 return attrs.getLength() == 0 and \
550 attrs.getNames() == [] and \
551 attrs.getQNames() == [] and \
552 len(attrs) == 0 and \
553 not attrs.has_key((ns_uri, "attr")) and \
554 attrs.keys() == [] and \
555 attrs.get((ns_uri, "attr")) is None and \
556 attrs.get((ns_uri, "attr"), 25) == 25 and \
557 attrs.items() == [] and \
558 attrs.values() == [] and \
559 gvk and gvqk and gnqk and gik and gqnk
561 def test_nsattrs_empty():
562 return verify_empty_nsattrs(AttributesNSImpl({}, {}))
564 def test_nsattrs_wattr():
565 attrs = AttributesNSImpl({(ns_uri, "attr") : "val"},
566 {(ns_uri, "attr") : "ns:attr"})
568 return attrs.getLength() == 1 and \
569 attrs.getNames() == [(ns_uri, "attr")] and \
570 attrs.getQNames() == ["ns:attr"] and \
571 len(attrs) == 1 and \
572 attrs.has_key((ns_uri, "attr")) and \
573 attrs.keys() == [(ns_uri, "attr")] and \
574 attrs.get((ns_uri, "attr")) == "val" and \
575 attrs.get((ns_uri, "attr"), 25) == "val" and \
576 attrs.items() == [((ns_uri, "attr"), "val")] and \
577 attrs.values() == ["val"] and \
578 attrs.getValue((ns_uri, "attr")) == "val" and \
579 attrs.getValueByQName("ns:attr") == "val" and \
580 attrs.getNameByQName("ns:attr") == (ns_uri, "attr") and \
581 attrs[(ns_uri, "attr")] == "val" and \
582 attrs.getQNameByName((ns_uri, "attr")) == "ns:attr"
585 # ===== Main program
587 def make_test_output():
588 parser = create_parser()
589 result = StringIO()
590 xmlgen = XMLGenerator(result)
592 parser.setContentHandler(xmlgen)
593 parser.parse(findfile("test.xml"))
595 outf = open(findfile("test.xml.out"), "w")
596 outf.write(result.getvalue())
597 outf.close()
599 items = locals().items()
600 items.sort()
601 for (name, value) in items:
602 if name[ : 5] == "test_":
603 confirm(value(), name)
605 print "%d tests, %d failures" % (tests, fails)
606 if fails != 0:
607 raise TestFailed, "%d of %d tests failed" % (fails, tests)