1 # regression test for SAX 2.0 -*- coding: iso-8859-1 -*-
4 from xml
.sax
import make_parser
, ContentHandler
, \
5 SAXException
, SAXReaderNotAvailable
, SAXParseException
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
23 def confirm(outcome
, name
):
33 def test_make_parser2():
35 # Creating parsers several times in a row should succeed.
36 # Testing this because there have been failures of this kind
38 from xml
.sax
import make_parser
40 from xml
.sax
import make_parser
42 from xml
.sax
import make_parser
44 from xml
.sax
import make_parser
46 from xml
.sax
import make_parser
48 from xml
.sax
import make_parser
56 # ===========================================================================
60 # ===========================================================================
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>") == "<Donald Duck & Co>"
70 def test_escape_extra():
71 return escape("Hei på deg", {"å" : "å"}) == "Hei på deg"
75 def test_quoteattr_basic():
76 return quoteattr("Donald Duck & Co") == '"Donald Duck & 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 "double" quotes\"")
92 def test_make_parser():
94 # Creating a parser should succeed - it should fall back
96 p
= make_parser(['xml.parsers.no_such_parser'])
105 start
= '<?xml version="1.0" encoding="iso-8859-1"?>\n'
107 def test_xmlgen_basic():
109 gen
= XMLGenerator(result
)
111 gen
.startElement("doc", {})
112 gen
.endElement("doc")
115 return result
.getvalue() == start
+ "<doc></doc>"
117 def test_xmlgen_content():
119 gen
= XMLGenerator(result
)
122 gen
.startElement("doc", {})
123 gen
.characters("huhei")
124 gen
.endElement("doc")
127 return result
.getvalue() == start
+ "<doc>huhei</doc>"
129 def test_xmlgen_pi():
131 gen
= XMLGenerator(result
)
134 gen
.processingInstruction("test", "data")
135 gen
.startElement("doc", {})
136 gen
.endElement("doc")
139 return result
.getvalue() == start
+ "<?test data?><doc></doc>"
141 def test_xmlgen_content_escape():
143 gen
= XMLGenerator(result
)
146 gen
.startElement("doc", {})
147 gen
.characters("<huhei&")
148 gen
.endElement("doc")
151 return result
.getvalue() == start
+ "<doc><huhei&</doc>"
153 def test_xmlgen_attr_escape():
155 gen
= XMLGenerator(result
)
158 gen
.startElement("doc", {"a": '"'})
159 gen
.startElement("e", {"a": "'"})
161 gen
.startElement("e", {"a": "'\""})
163 gen
.endElement("doc")
166 return result
.getvalue() == start \
167 + "<doc a='\"'><e a=\"'\"></e><e a=\"'"\"></e></doc>"
169 def test_xmlgen_ignorable():
171 gen
= XMLGenerator(result
)
174 gen
.startElement("doc", {})
175 gen
.ignorableWhitespace(" ")
176 gen
.endElement("doc")
179 return result
.getvalue() == start
+ "<doc> </doc>"
181 ns_uri
= "http://www.python.org/xml-ns/saxtest/"
183 def test_xmlgen_ns():
185 gen
= XMLGenerator(result
)
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")
197 return result
.getvalue() == start
+ \
198 ('<ns1:doc xmlns:ns1="%s"><udoc></udoc></ns1:doc>' %
201 # ===== XMLFilterBase
203 def test_filter_basic():
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")
216 return result
.getvalue() == start
+ "<doc>content </doc>"
218 # ===========================================================================
222 # ===========================================================================
224 # ===== XMLReader support
226 def test_expat_file():
227 parser
= create_parser()
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
:
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')
259 parser
.feed('<doc></doc>')
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/>"))
274 def test_expat_entityresolver():
275 parser
= create_parser()
276 parser
.setEntityResolver(TestEntityResolver())
278 parser
.setContentHandler(XMLGenerator(result
))
280 parser
.feed('<!DOCTYPE doc [\n')
281 parser
.feed(' <!ENTITY test SYSTEM "whatever">\n')
283 parser
.feed('<doc>&test;</doc>')
286 return result
.getvalue() == start
+ "<doc><entity></entity></doc>"
288 # ===== Attributes support
290 class AttrGatherer(ContentHandler
):
292 def startElement(self
, name
, attrs
):
295 def startElementNS(self
, name
, qname
, attrs
):
298 def test_expat_attrs_empty():
299 parser
= create_parser()
300 gather
= AttrGatherer()
301 parser
.setContentHandler(gather
)
303 parser
.feed("<doc/>")
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'/>")
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/>")
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
)
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()
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()
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()
378 xmlgen
= XMLGenerator(result
)
380 parser
.setContentHandler(xmlgen
)
381 inpsrc
= InputSource()
382 inpsrc
.setByteStream(open(findfile("test"+os
.extsep
+"xml")))
385 return result
.getvalue() == xml_test_out
387 # ===== IncrementalParser support
389 def test_expat_incremental():
391 xmlgen
= XMLGenerator(result
)
392 parser
= create_parser()
393 parser
.setContentHandler(xmlgen
)
396 parser
.feed("</doc>")
399 return result
.getvalue() == start
+ "<doc></doc>"
401 def test_expat_incremental_reset():
403 xmlgen
= XMLGenerator(result
)
404 parser
= create_parser()
405 parser
.setContentHandler(xmlgen
)
411 xmlgen
= XMLGenerator(result
)
412 parser
.setContentHandler(xmlgen
)
417 parser
.feed("</doc>")
420 return result
.getvalue() == start
+ "<doc>text</doc>"
422 # ===== Locator support
424 def test_expat_locator_noinfo():
426 xmlgen
= XMLGenerator(result
)
427 parser
= create_parser()
428 parser
.setContentHandler(xmlgen
)
431 parser
.feed("</doc>")
434 return parser
.getSystemId() is None and \
435 parser
.getPublicId() is None and \
436 parser
.getLineNumber() == 1
438 def test_expat_locator_withinfo():
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 # ===========================================================================
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
461 source
.setSystemId(name
)
464 except SAXException
, e
:
465 return e
.getSystemId() == name
467 def test_expat_incomplete():
468 parser
= create_parser()
469 parser
.setContentHandler(ContentHandler()) # do nothing
471 parser
.parse(StringIO("<foo>"))
472 except SAXParseException
:
473 return 1 # ok, error found
478 # ===========================================================================
482 # ===========================================================================
484 # ===== AttributesImpl
486 def verify_empty_attrs(attrs
):
488 attrs
.getValue("attr")
494 attrs
.getValueByQName("attr")
500 attrs
.getNameByQName("attr")
506 attrs
.getQNameByName("attr")
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
):
556 attrs
.getValue((ns_uri
, "attr"))
562 attrs
.getValueByQName("ns:attr")
568 attrs
.getNameByQName("ns:attr")
574 attrs
.getQNameByName((ns_uri
, "attr"))
580 attrs
[(ns_uri
, "attr")]
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"
623 def make_test_output():
624 parser
= create_parser()
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())
635 items
= locals().items()
637 for (name
, value
) in items
:
638 if name
[ : 5] == "test_":
639 confirm(value(), name
)
641 print "%d tests, %d failures" % (tests
, fails
)
643 raise TestFailed
, "%d of %d tests failed" % (fails
, tests
)