append(): Fixing the test for convertability after consultation with
[python/dscho.git] / Lib / test / test_sax.py
blob1200329934e86f569ec2bc86ba53f189e3be8a57
1 # regression test for SAX 2.0 -*- coding: iso-8859-1 -*-
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, quoteattr, 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.test_support import verify, verbose, TestFailed, findfile
16 import os
18 # ===== Utilities
20 tests = 0
21 fails = 0
23 def confirm(outcome, name):
24 global tests, fails
26 tests = tests + 1
27 if outcome:
28 print "Passed", name
29 else:
30 print "Failed", name
31 fails = fails + 1
33 def test_make_parser2():
34 try:
35 # Creating parsers several times in a row should succeed.
36 # Testing this because there have been failures of this kind
37 # before.
38 from xml.sax import make_parser
39 p = make_parser()
40 from xml.sax import make_parser
41 p = make_parser()
42 from xml.sax import make_parser
43 p = make_parser()
44 from xml.sax import make_parser
45 p = make_parser()
46 from xml.sax import make_parser
47 p = make_parser()
48 from xml.sax import make_parser
49 p = make_parser()
50 except:
51 return 0
52 else:
53 return p
56 # ===========================================================================
58 # saxutils tests
60 # ===========================================================================
62 # ===== escape
64 def test_escape_basic():
65 return escape("Donald Duck & Co") == "Donald Duck & Co"
67 def test_escape_all():
68 return escape("<Donald Duck & Co>") == "&lt;Donald Duck &amp; Co&gt;"
70 def test_escape_extra():
71 return escape("Hei på deg", {"å" : "&aring;"}) == "Hei p&aring; deg"
73 # ===== quoteattr
75 def test_quoteattr_basic():
76 return quoteattr("Donald Duck & Co") == '"Donald Duck &amp; Co"'
78 def test_single_quoteattr():
79 return (quoteattr('Includes "double" quotes')
80 == '\'Includes "double" quotes\'')
82 def test_double_quoteattr():
83 return (quoteattr("Includes 'single' quotes")
84 == "\"Includes 'single' quotes\"")
86 def test_single_double_quoteattr():
87 return (quoteattr("Includes 'single' and \"double\" quotes")
88 == "\"Includes 'single' and &quot;double&quot; quotes\"")
90 # ===== make_parser
92 def test_make_parser():
93 try:
94 # Creating a parser should succeed - it should fall back
95 # to the expatreader
96 p = make_parser(['xml.parsers.no_such_parser'])
97 except:
98 return 0
99 else:
100 return p
103 # ===== XMLGenerator
105 start = '<?xml version="1.0" encoding="iso-8859-1"?>\n'
107 def test_xmlgen_basic():
108 result = StringIO()
109 gen = XMLGenerator(result)
110 gen.startDocument()
111 gen.startElement("doc", {})
112 gen.endElement("doc")
113 gen.endDocument()
115 return result.getvalue() == start + "<doc></doc>"
117 def test_xmlgen_content():
118 result = StringIO()
119 gen = XMLGenerator(result)
121 gen.startDocument()
122 gen.startElement("doc", {})
123 gen.characters("huhei")
124 gen.endElement("doc")
125 gen.endDocument()
127 return result.getvalue() == start + "<doc>huhei</doc>"
129 def test_xmlgen_pi():
130 result = StringIO()
131 gen = XMLGenerator(result)
133 gen.startDocument()
134 gen.processingInstruction("test", "data")
135 gen.startElement("doc", {})
136 gen.endElement("doc")
137 gen.endDocument()
139 return result.getvalue() == start + "<?test data?><doc></doc>"
141 def test_xmlgen_content_escape():
142 result = StringIO()
143 gen = XMLGenerator(result)
145 gen.startDocument()
146 gen.startElement("doc", {})
147 gen.characters("<huhei&")
148 gen.endElement("doc")
149 gen.endDocument()
151 return result.getvalue() == start + "<doc>&lt;huhei&amp;</doc>"
153 def test_xmlgen_attr_escape():
154 result = StringIO()
155 gen = XMLGenerator(result)
157 gen.startDocument()
158 gen.startElement("doc", {"a": '"'})
159 gen.startElement("e", {"a": "'"})
160 gen.endElement("e")
161 gen.startElement("e", {"a": "'\""})
162 gen.endElement("e")
163 gen.endElement("doc")
164 gen.endDocument()
166 return result.getvalue() == start \
167 + "<doc a='\"'><e a=\"'\"></e><e a=\"'&quot;\"></e></doc>"
169 def test_xmlgen_ignorable():
170 result = StringIO()
171 gen = XMLGenerator(result)
173 gen.startDocument()
174 gen.startElement("doc", {})
175 gen.ignorableWhitespace(" ")
176 gen.endElement("doc")
177 gen.endDocument()
179 return result.getvalue() == start + "<doc> </doc>"
181 ns_uri = "http://www.python.org/xml-ns/saxtest/"
183 def test_xmlgen_ns():
184 result = StringIO()
185 gen = XMLGenerator(result)
187 gen.startDocument()
188 gen.startPrefixMapping("ns1", ns_uri)
189 gen.startElementNS((ns_uri, "doc"), "ns1:doc", {})
190 # add an unqualified name
191 gen.startElementNS((None, "udoc"), None, {})
192 gen.endElementNS((None, "udoc"), None)
193 gen.endElementNS((ns_uri, "doc"), "ns1:doc")
194 gen.endPrefixMapping("ns1")
195 gen.endDocument()
197 return result.getvalue() == start + \
198 ('<ns1:doc xmlns:ns1="%s"><udoc></udoc></ns1:doc>' %
199 ns_uri)
201 # ===== XMLFilterBase
203 def test_filter_basic():
204 result = StringIO()
205 gen = XMLGenerator(result)
206 filter = XMLFilterBase()
207 filter.setContentHandler(gen)
209 filter.startDocument()
210 filter.startElement("doc", {})
211 filter.characters("content")
212 filter.ignorableWhitespace(" ")
213 filter.endElement("doc")
214 filter.endDocument()
216 return result.getvalue() == start + "<doc>content </doc>"
218 # ===========================================================================
220 # expatreader tests
222 # ===========================================================================
224 # ===== XMLReader support
226 def test_expat_file():
227 parser = create_parser()
228 result = StringIO()
229 xmlgen = XMLGenerator(result)
231 parser.setContentHandler(xmlgen)
232 parser.parse(open(findfile("test"+os.extsep+"xml")))
234 return result.getvalue() == xml_test_out
236 # ===== DTDHandler support
238 class TestDTDHandler:
240 def __init__(self):
241 self._notations = []
242 self._entities = []
244 def notationDecl(self, name, publicId, systemId):
245 self._notations.append((name, publicId, systemId))
247 def unparsedEntityDecl(self, name, publicId, systemId, ndata):
248 self._entities.append((name, publicId, systemId, ndata))
250 def test_expat_dtdhandler():
251 parser = create_parser()
252 handler = TestDTDHandler()
253 parser.setDTDHandler(handler)
255 parser.feed('<!DOCTYPE doc [\n')
256 parser.feed(' <!ENTITY img SYSTEM "expat.gif" NDATA GIF>\n')
257 parser.feed(' <!NOTATION GIF PUBLIC "-//CompuServe//NOTATION Graphics Interchange Format 89a//EN">\n')
258 parser.feed(']>\n')
259 parser.feed('<doc></doc>')
260 parser.close()
262 return handler._notations == [("GIF", "-//CompuServe//NOTATION Graphics Interchange Format 89a//EN", None)] and \
263 handler._entities == [("img", None, "expat.gif", "GIF")]
265 # ===== EntityResolver support
267 class TestEntityResolver:
269 def resolveEntity(self, publicId, systemId):
270 inpsrc = InputSource()
271 inpsrc.setByteStream(StringIO("<entity/>"))
272 return inpsrc
274 def test_expat_entityresolver():
275 parser = create_parser()
276 parser.setEntityResolver(TestEntityResolver())
277 result = StringIO()
278 parser.setContentHandler(XMLGenerator(result))
280 parser.feed('<!DOCTYPE doc [\n')
281 parser.feed(' <!ENTITY test SYSTEM "whatever">\n')
282 parser.feed(']>\n')
283 parser.feed('<doc>&test;</doc>')
284 parser.close()
286 return result.getvalue() == start + "<doc><entity></entity></doc>"
288 # ===== Attributes support
290 class AttrGatherer(ContentHandler):
292 def startElement(self, name, attrs):
293 self._attrs = attrs
295 def startElementNS(self, name, qname, attrs):
296 self._attrs = attrs
298 def test_expat_attrs_empty():
299 parser = create_parser()
300 gather = AttrGatherer()
301 parser.setContentHandler(gather)
303 parser.feed("<doc/>")
304 parser.close()
306 return verify_empty_attrs(gather._attrs)
308 def test_expat_attrs_wattr():
309 parser = create_parser()
310 gather = AttrGatherer()
311 parser.setContentHandler(gather)
313 parser.feed("<doc attr='val'/>")
314 parser.close()
316 return verify_attrs_wattr(gather._attrs)
318 def test_expat_nsattrs_empty():
319 parser = create_parser(1)
320 gather = AttrGatherer()
321 parser.setContentHandler(gather)
323 parser.feed("<doc/>")
324 parser.close()
326 return verify_empty_nsattrs(gather._attrs)
328 def test_expat_nsattrs_wattr():
329 parser = create_parser(1)
330 gather = AttrGatherer()
331 parser.setContentHandler(gather)
333 parser.feed("<doc xmlns:ns='%s' ns:attr='val'/>" % ns_uri)
334 parser.close()
336 attrs = gather._attrs
338 return attrs.getLength() == 1 and \
339 attrs.getNames() == [(ns_uri, "attr")] and \
340 (attrs.getQNames() == [] or attrs.getQNames() == ["ns:attr"]) and \
341 len(attrs) == 1 and \
342 attrs.has_key((ns_uri, "attr")) and \
343 attrs.keys() == [(ns_uri, "attr")] and \
344 attrs.get((ns_uri, "attr")) == "val" and \
345 attrs.get((ns_uri, "attr"), 25) == "val" and \
346 attrs.items() == [((ns_uri, "attr"), "val")] and \
347 attrs.values() == ["val"] and \
348 attrs.getValue((ns_uri, "attr")) == "val" and \
349 attrs[(ns_uri, "attr")] == "val"
351 # ===== InputSource support
353 xml_test_out = open(findfile("test"+os.extsep+"xml"+os.extsep+"out")).read()
355 def test_expat_inpsource_filename():
356 parser = create_parser()
357 result = StringIO()
358 xmlgen = XMLGenerator(result)
360 parser.setContentHandler(xmlgen)
361 parser.parse(findfile("test"+os.extsep+"xml"))
363 return result.getvalue() == xml_test_out
365 def test_expat_inpsource_sysid():
366 parser = create_parser()
367 result = StringIO()
368 xmlgen = XMLGenerator(result)
370 parser.setContentHandler(xmlgen)
371 parser.parse(InputSource(findfile("test"+os.extsep+"xml")))
373 return result.getvalue() == xml_test_out
375 def test_expat_inpsource_stream():
376 parser = create_parser()
377 result = StringIO()
378 xmlgen = XMLGenerator(result)
380 parser.setContentHandler(xmlgen)
381 inpsrc = InputSource()
382 inpsrc.setByteStream(open(findfile("test"+os.extsep+"xml")))
383 parser.parse(inpsrc)
385 return result.getvalue() == xml_test_out
387 # ===== IncrementalParser support
389 def test_expat_incremental():
390 result = StringIO()
391 xmlgen = XMLGenerator(result)
392 parser = create_parser()
393 parser.setContentHandler(xmlgen)
395 parser.feed("<doc>")
396 parser.feed("</doc>")
397 parser.close()
399 return result.getvalue() == start + "<doc></doc>"
401 def test_expat_incremental_reset():
402 result = StringIO()
403 xmlgen = XMLGenerator(result)
404 parser = create_parser()
405 parser.setContentHandler(xmlgen)
407 parser.feed("<doc>")
408 parser.feed("text")
410 result = StringIO()
411 xmlgen = XMLGenerator(result)
412 parser.setContentHandler(xmlgen)
413 parser.reset()
415 parser.feed("<doc>")
416 parser.feed("text")
417 parser.feed("</doc>")
418 parser.close()
420 return result.getvalue() == start + "<doc>text</doc>"
422 # ===== Locator support
424 def test_expat_locator_noinfo():
425 result = StringIO()
426 xmlgen = XMLGenerator(result)
427 parser = create_parser()
428 parser.setContentHandler(xmlgen)
430 parser.feed("<doc>")
431 parser.feed("</doc>")
432 parser.close()
434 return parser.getSystemId() is None and \
435 parser.getPublicId() is None and \
436 parser.getLineNumber() == 1
438 def test_expat_locator_withinfo():
439 result = StringIO()
440 xmlgen = XMLGenerator(result)
441 parser = create_parser()
442 parser.setContentHandler(xmlgen)
443 parser.parse(findfile("test.xml"))
445 return parser.getSystemId() == findfile("test.xml") and \
446 parser.getPublicId() is None
449 # ===========================================================================
451 # error reporting
453 # ===========================================================================
455 def test_expat_inpsource_location():
456 parser = create_parser()
457 parser.setContentHandler(ContentHandler()) # do nothing
458 source = InputSource()
459 source.setByteStream(StringIO("<foo bar foobar>")) #ill-formed
460 name = "a file name"
461 source.setSystemId(name)
462 try:
463 parser.parse(source)
464 except SAXException, e:
465 return e.getSystemId() == name
467 def test_expat_incomplete():
468 parser = create_parser()
469 parser.setContentHandler(ContentHandler()) # do nothing
470 try:
471 parser.parse(StringIO("<foo>"))
472 except SAXParseException:
473 return 1 # ok, error found
474 else:
475 return 0
478 # ===========================================================================
480 # xmlreader tests
482 # ===========================================================================
484 # ===== AttributesImpl
486 def verify_empty_attrs(attrs):
487 try:
488 attrs.getValue("attr")
489 gvk = 0
490 except KeyError:
491 gvk = 1
493 try:
494 attrs.getValueByQName("attr")
495 gvqk = 0
496 except KeyError:
497 gvqk = 1
499 try:
500 attrs.getNameByQName("attr")
501 gnqk = 0
502 except KeyError:
503 gnqk = 1
505 try:
506 attrs.getQNameByName("attr")
507 gqnk = 0
508 except KeyError:
509 gqnk = 1
511 try:
512 attrs["attr"]
513 gik = 0
514 except KeyError:
515 gik = 1
517 return attrs.getLength() == 0 and \
518 attrs.getNames() == [] and \
519 attrs.getQNames() == [] and \
520 len(attrs) == 0 and \
521 not attrs.has_key("attr") and \
522 attrs.keys() == [] and \
523 attrs.get("attrs") is None and \
524 attrs.get("attrs", 25) == 25 and \
525 attrs.items() == [] and \
526 attrs.values() == [] and \
527 gvk and gvqk and gnqk and gik and gqnk
529 def verify_attrs_wattr(attrs):
530 return attrs.getLength() == 1 and \
531 attrs.getNames() == ["attr"] and \
532 attrs.getQNames() == ["attr"] and \
533 len(attrs) == 1 and \
534 attrs.has_key("attr") and \
535 attrs.keys() == ["attr"] and \
536 attrs.get("attr") == "val" and \
537 attrs.get("attr", 25) == "val" and \
538 attrs.items() == [("attr", "val")] and \
539 attrs.values() == ["val"] and \
540 attrs.getValue("attr") == "val" and \
541 attrs.getValueByQName("attr") == "val" and \
542 attrs.getNameByQName("attr") == "attr" and \
543 attrs["attr"] == "val" and \
544 attrs.getQNameByName("attr") == "attr"
546 def test_attrs_empty():
547 return verify_empty_attrs(AttributesImpl({}))
549 def test_attrs_wattr():
550 return verify_attrs_wattr(AttributesImpl({"attr" : "val"}))
552 # ===== AttributesImpl
554 def verify_empty_nsattrs(attrs):
555 try:
556 attrs.getValue((ns_uri, "attr"))
557 gvk = 0
558 except KeyError:
559 gvk = 1
561 try:
562 attrs.getValueByQName("ns:attr")
563 gvqk = 0
564 except KeyError:
565 gvqk = 1
567 try:
568 attrs.getNameByQName("ns:attr")
569 gnqk = 0
570 except KeyError:
571 gnqk = 1
573 try:
574 attrs.getQNameByName((ns_uri, "attr"))
575 gqnk = 0
576 except KeyError:
577 gqnk = 1
579 try:
580 attrs[(ns_uri, "attr")]
581 gik = 0
582 except KeyError:
583 gik = 1
585 return attrs.getLength() == 0 and \
586 attrs.getNames() == [] and \
587 attrs.getQNames() == [] and \
588 len(attrs) == 0 and \
589 not attrs.has_key((ns_uri, "attr")) and \
590 attrs.keys() == [] and \
591 attrs.get((ns_uri, "attr")) is None and \
592 attrs.get((ns_uri, "attr"), 25) == 25 and \
593 attrs.items() == [] and \
594 attrs.values() == [] and \
595 gvk and gvqk and gnqk and gik and gqnk
597 def test_nsattrs_empty():
598 return verify_empty_nsattrs(AttributesNSImpl({}, {}))
600 def test_nsattrs_wattr():
601 attrs = AttributesNSImpl({(ns_uri, "attr") : "val"},
602 {(ns_uri, "attr") : "ns:attr"})
604 return attrs.getLength() == 1 and \
605 attrs.getNames() == [(ns_uri, "attr")] and \
606 attrs.getQNames() == ["ns:attr"] and \
607 len(attrs) == 1 and \
608 attrs.has_key((ns_uri, "attr")) and \
609 attrs.keys() == [(ns_uri, "attr")] and \
610 attrs.get((ns_uri, "attr")) == "val" and \
611 attrs.get((ns_uri, "attr"), 25) == "val" and \
612 attrs.items() == [((ns_uri, "attr"), "val")] and \
613 attrs.values() == ["val"] and \
614 attrs.getValue((ns_uri, "attr")) == "val" and \
615 attrs.getValueByQName("ns:attr") == "val" and \
616 attrs.getNameByQName("ns:attr") == (ns_uri, "attr") and \
617 attrs[(ns_uri, "attr")] == "val" and \
618 attrs.getQNameByName((ns_uri, "attr")) == "ns:attr"
621 # ===== Main program
623 def make_test_output():
624 parser = create_parser()
625 result = StringIO()
626 xmlgen = XMLGenerator(result)
628 parser.setContentHandler(xmlgen)
629 parser.parse(findfile("test"+os.extsep+"xml"))
631 outf = open(findfile("test"+os.extsep+"xml"+os.extsep+"out"), "w")
632 outf.write(result.getvalue())
633 outf.close()
635 items = locals().items()
636 items.sort()
637 for (name, value) in items:
638 if name[ : 5] == "test_":
639 confirm(value(), name)
641 print "%d tests, %d failures" % (tests, fails)
642 if fails != 0:
643 raise TestFailed, "%d of %d tests failed" % (fails, tests)