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
, unescape
, quoteattr
, \
13 from xml
.sax
.expatreader
import create_parser
14 from xml
.sax
.xmlreader
import InputSource
, AttributesImpl
, AttributesNSImpl
15 from cStringIO
import StringIO
16 from test
.test_support
import verify
, verbose
, TestFailed
, findfile
24 def confirm(outcome
, name
):
34 def test_make_parser2():
36 # Creating parsers several times in a row should succeed.
37 # Testing this because there have been failures of this kind
39 from xml
.sax
import make_parser
41 from xml
.sax
import make_parser
43 from xml
.sax
import make_parser
45 from xml
.sax
import make_parser
47 from xml
.sax
import make_parser
49 from xml
.sax
import make_parser
57 # ===========================================================================
61 # ===========================================================================
65 def test_escape_basic():
66 return escape("Donald Duck & Co") == "Donald Duck & Co"
68 def test_escape_all():
69 return escape("<Donald Duck & Co>") == "<Donald Duck & Co>"
71 def test_escape_extra():
72 return escape("Hei på deg", {"å" : "å"}) == "Hei på deg"
76 def test_unescape_basic():
77 return unescape("Donald Duck & Co") == "Donald Duck & Co"
79 def test_unescape_all():
80 return unescape("<Donald Duck & Co>") == "<Donald Duck & Co>"
82 def test_unescape_extra():
83 return unescape("Hei på deg", {"å" : "å"}) == "Hei på deg"
85 def test_unescape_amp_extra():
86 return unescape("&foo;", {"&foo;": "splat"}) == "&foo;"
90 def test_quoteattr_basic():
91 return quoteattr("Donald Duck & Co") == '"Donald Duck & Co"'
93 def test_single_quoteattr():
94 return (quoteattr('Includes "double" quotes')
95 == '\'Includes "double" quotes\'')
97 def test_double_quoteattr():
98 return (quoteattr("Includes 'single' quotes")
99 == "\"Includes 'single' quotes\"")
101 def test_single_double_quoteattr():
102 return (quoteattr("Includes 'single' and \"double\" quotes")
103 == "\"Includes 'single' and "double" quotes\"")
107 def test_make_parser():
109 # Creating a parser should succeed - it should fall back
111 p
= make_parser(['xml.parsers.no_such_parser'])
120 start
= '<?xml version="1.0" encoding="iso-8859-1"?>\n'
122 def test_xmlgen_basic():
124 gen
= XMLGenerator(result
)
126 gen
.startElement("doc", {})
127 gen
.endElement("doc")
130 return result
.getvalue() == start
+ "<doc></doc>"
132 def test_xmlgen_content():
134 gen
= XMLGenerator(result
)
137 gen
.startElement("doc", {})
138 gen
.characters("huhei")
139 gen
.endElement("doc")
142 return result
.getvalue() == start
+ "<doc>huhei</doc>"
144 def test_xmlgen_pi():
146 gen
= XMLGenerator(result
)
149 gen
.processingInstruction("test", "data")
150 gen
.startElement("doc", {})
151 gen
.endElement("doc")
154 return result
.getvalue() == start
+ "<?test data?><doc></doc>"
156 def test_xmlgen_content_escape():
158 gen
= XMLGenerator(result
)
161 gen
.startElement("doc", {})
162 gen
.characters("<huhei&")
163 gen
.endElement("doc")
166 return result
.getvalue() == start
+ "<doc><huhei&</doc>"
168 def test_xmlgen_attr_escape():
170 gen
= XMLGenerator(result
)
173 gen
.startElement("doc", {"a": '"'})
174 gen
.startElement("e", {"a": "'"})
176 gen
.startElement("e", {"a": "'\""})
178 gen
.endElement("doc")
181 return result
.getvalue() == start \
182 + "<doc a='\"'><e a=\"'\"></e><e a=\"'"\"></e></doc>"
184 def test_xmlgen_ignorable():
186 gen
= XMLGenerator(result
)
189 gen
.startElement("doc", {})
190 gen
.ignorableWhitespace(" ")
191 gen
.endElement("doc")
194 return result
.getvalue() == start
+ "<doc> </doc>"
196 ns_uri
= "http://www.python.org/xml-ns/saxtest/"
198 def test_xmlgen_ns():
200 gen
= XMLGenerator(result
)
203 gen
.startPrefixMapping("ns1", ns_uri
)
204 gen
.startElementNS((ns_uri
, "doc"), "ns1:doc", {})
205 # add an unqualified name
206 gen
.startElementNS((None, "udoc"), None, {})
207 gen
.endElementNS((None, "udoc"), None)
208 gen
.endElementNS((ns_uri
, "doc"), "ns1:doc")
209 gen
.endPrefixMapping("ns1")
212 return result
.getvalue() == start
+ \
213 ('<ns1:doc xmlns:ns1="%s"><udoc></udoc></ns1:doc>' %
216 # ===== XMLFilterBase
218 def test_filter_basic():
220 gen
= XMLGenerator(result
)
221 filter = XMLFilterBase()
222 filter.setContentHandler(gen
)
224 filter.startDocument()
225 filter.startElement("doc", {})
226 filter.characters("content")
227 filter.ignorableWhitespace(" ")
228 filter.endElement("doc")
231 return result
.getvalue() == start
+ "<doc>content </doc>"
233 # ===========================================================================
237 # ===========================================================================
239 # ===== XMLReader support
241 def test_expat_file():
242 parser
= create_parser()
244 xmlgen
= XMLGenerator(result
)
246 parser
.setContentHandler(xmlgen
)
247 parser
.parse(open(findfile("test"+os
.extsep
+"xml")))
249 return result
.getvalue() == xml_test_out
251 # ===== DTDHandler support
253 class TestDTDHandler
:
259 def notationDecl(self
, name
, publicId
, systemId
):
260 self
._notations
.append((name
, publicId
, systemId
))
262 def unparsedEntityDecl(self
, name
, publicId
, systemId
, ndata
):
263 self
._entities
.append((name
, publicId
, systemId
, ndata
))
265 def test_expat_dtdhandler():
266 parser
= create_parser()
267 handler
= TestDTDHandler()
268 parser
.setDTDHandler(handler
)
270 parser
.feed('<!DOCTYPE doc [\n')
271 parser
.feed(' <!ENTITY img SYSTEM "expat.gif" NDATA GIF>\n')
272 parser
.feed(' <!NOTATION GIF PUBLIC "-//CompuServe//NOTATION Graphics Interchange Format 89a//EN">\n')
274 parser
.feed('<doc></doc>')
277 return handler
._notations
== [("GIF", "-//CompuServe//NOTATION Graphics Interchange Format 89a//EN", None)] and \
278 handler
._entities
== [("img", None, "expat.gif", "GIF")]
280 # ===== EntityResolver support
282 class TestEntityResolver
:
284 def resolveEntity(self
, publicId
, systemId
):
285 inpsrc
= InputSource()
286 inpsrc
.setByteStream(StringIO("<entity/>"))
289 def test_expat_entityresolver():
290 parser
= create_parser()
291 parser
.setEntityResolver(TestEntityResolver())
293 parser
.setContentHandler(XMLGenerator(result
))
295 parser
.feed('<!DOCTYPE doc [\n')
296 parser
.feed(' <!ENTITY test SYSTEM "whatever">\n')
298 parser
.feed('<doc>&test;</doc>')
301 return result
.getvalue() == start
+ "<doc><entity></entity></doc>"
303 # ===== Attributes support
305 class AttrGatherer(ContentHandler
):
307 def startElement(self
, name
, attrs
):
310 def startElementNS(self
, name
, qname
, attrs
):
313 def test_expat_attrs_empty():
314 parser
= create_parser()
315 gather
= AttrGatherer()
316 parser
.setContentHandler(gather
)
318 parser
.feed("<doc/>")
321 return verify_empty_attrs(gather
._attrs
)
323 def test_expat_attrs_wattr():
324 parser
= create_parser()
325 gather
= AttrGatherer()
326 parser
.setContentHandler(gather
)
328 parser
.feed("<doc attr='val'/>")
331 return verify_attrs_wattr(gather
._attrs
)
333 def test_expat_nsattrs_empty():
334 parser
= create_parser(1)
335 gather
= AttrGatherer()
336 parser
.setContentHandler(gather
)
338 parser
.feed("<doc/>")
341 return verify_empty_nsattrs(gather
._attrs
)
343 def test_expat_nsattrs_wattr():
344 parser
= create_parser(1)
345 gather
= AttrGatherer()
346 parser
.setContentHandler(gather
)
348 parser
.feed("<doc xmlns:ns='%s' ns:attr='val'/>" % ns_uri
)
351 attrs
= gather
._attrs
353 return attrs
.getLength() == 1 and \
354 attrs
.getNames() == [(ns_uri
, "attr")] and \
355 (attrs
.getQNames() == [] or attrs
.getQNames() == ["ns:attr"]) and \
356 len(attrs
) == 1 and \
357 attrs
.has_key((ns_uri
, "attr")) and \
358 attrs
.keys() == [(ns_uri
, "attr")] and \
359 attrs
.get((ns_uri
, "attr")) == "val" and \
360 attrs
.get((ns_uri
, "attr"), 25) == "val" and \
361 attrs
.items() == [((ns_uri
, "attr"), "val")] and \
362 attrs
.values() == ["val"] and \
363 attrs
.getValue((ns_uri
, "attr")) == "val" and \
364 attrs
[(ns_uri
, "attr")] == "val"
366 # ===== InputSource support
368 xml_test_out
= open(findfile("test"+os
.extsep
+"xml"+os
.extsep
+"out")).read()
370 def test_expat_inpsource_filename():
371 parser
= create_parser()
373 xmlgen
= XMLGenerator(result
)
375 parser
.setContentHandler(xmlgen
)
376 parser
.parse(findfile("test"+os
.extsep
+"xml"))
378 return result
.getvalue() == xml_test_out
380 def test_expat_inpsource_sysid():
381 parser
= create_parser()
383 xmlgen
= XMLGenerator(result
)
385 parser
.setContentHandler(xmlgen
)
386 parser
.parse(InputSource(findfile("test"+os
.extsep
+"xml")))
388 return result
.getvalue() == xml_test_out
390 def test_expat_inpsource_stream():
391 parser
= create_parser()
393 xmlgen
= XMLGenerator(result
)
395 parser
.setContentHandler(xmlgen
)
396 inpsrc
= InputSource()
397 inpsrc
.setByteStream(open(findfile("test"+os
.extsep
+"xml")))
400 return result
.getvalue() == xml_test_out
402 # ===== IncrementalParser support
404 def test_expat_incremental():
406 xmlgen
= XMLGenerator(result
)
407 parser
= create_parser()
408 parser
.setContentHandler(xmlgen
)
411 parser
.feed("</doc>")
414 return result
.getvalue() == start
+ "<doc></doc>"
416 def test_expat_incremental_reset():
418 xmlgen
= XMLGenerator(result
)
419 parser
= create_parser()
420 parser
.setContentHandler(xmlgen
)
426 xmlgen
= XMLGenerator(result
)
427 parser
.setContentHandler(xmlgen
)
432 parser
.feed("</doc>")
435 return result
.getvalue() == start
+ "<doc>text</doc>"
437 # ===== Locator support
439 def test_expat_locator_noinfo():
441 xmlgen
= XMLGenerator(result
)
442 parser
= create_parser()
443 parser
.setContentHandler(xmlgen
)
446 parser
.feed("</doc>")
449 return parser
.getSystemId() is None and \
450 parser
.getPublicId() is None and \
451 parser
.getLineNumber() == 1
453 def test_expat_locator_withinfo():
455 xmlgen
= XMLGenerator(result
)
456 parser
= create_parser()
457 parser
.setContentHandler(xmlgen
)
458 parser
.parse(findfile("test.xml"))
460 return parser
.getSystemId() == findfile("test.xml") and \
461 parser
.getPublicId() is None
464 # ===========================================================================
468 # ===========================================================================
470 def test_expat_inpsource_location():
471 parser
= create_parser()
472 parser
.setContentHandler(ContentHandler()) # do nothing
473 source
= InputSource()
474 source
.setByteStream(StringIO("<foo bar foobar>")) #ill-formed
476 source
.setSystemId(name
)
479 except SAXException
, e
:
480 return e
.getSystemId() == name
482 def test_expat_incomplete():
483 parser
= create_parser()
484 parser
.setContentHandler(ContentHandler()) # do nothing
486 parser
.parse(StringIO("<foo>"))
487 except SAXParseException
:
488 return 1 # ok, error found
493 # ===========================================================================
497 # ===========================================================================
499 # ===== AttributesImpl
501 def verify_empty_attrs(attrs
):
503 attrs
.getValue("attr")
509 attrs
.getValueByQName("attr")
515 attrs
.getNameByQName("attr")
521 attrs
.getQNameByName("attr")
532 return attrs
.getLength() == 0 and \
533 attrs
.getNames() == [] and \
534 attrs
.getQNames() == [] and \
535 len(attrs
) == 0 and \
536 not attrs
.has_key("attr") and \
537 attrs
.keys() == [] and \
538 attrs
.get("attrs") is None and \
539 attrs
.get("attrs", 25) == 25 and \
540 attrs
.items() == [] and \
541 attrs
.values() == [] and \
542 gvk
and gvqk
and gnqk
and gik
and gqnk
544 def verify_attrs_wattr(attrs
):
545 return attrs
.getLength() == 1 and \
546 attrs
.getNames() == ["attr"] and \
547 attrs
.getQNames() == ["attr"] and \
548 len(attrs
) == 1 and \
549 attrs
.has_key("attr") and \
550 attrs
.keys() == ["attr"] and \
551 attrs
.get("attr") == "val" and \
552 attrs
.get("attr", 25) == "val" and \
553 attrs
.items() == [("attr", "val")] and \
554 attrs
.values() == ["val"] and \
555 attrs
.getValue("attr") == "val" and \
556 attrs
.getValueByQName("attr") == "val" and \
557 attrs
.getNameByQName("attr") == "attr" and \
558 attrs
["attr"] == "val" and \
559 attrs
.getQNameByName("attr") == "attr"
561 def test_attrs_empty():
562 return verify_empty_attrs(AttributesImpl({}))
564 def test_attrs_wattr():
565 return verify_attrs_wattr(AttributesImpl({"attr" : "val"}))
567 # ===== AttributesImpl
569 def verify_empty_nsattrs(attrs
):
571 attrs
.getValue((ns_uri
, "attr"))
577 attrs
.getValueByQName("ns:attr")
583 attrs
.getNameByQName("ns:attr")
589 attrs
.getQNameByName((ns_uri
, "attr"))
595 attrs
[(ns_uri
, "attr")]
600 return attrs
.getLength() == 0 and \
601 attrs
.getNames() == [] and \
602 attrs
.getQNames() == [] and \
603 len(attrs
) == 0 and \
604 not attrs
.has_key((ns_uri
, "attr")) and \
605 attrs
.keys() == [] and \
606 attrs
.get((ns_uri
, "attr")) is None and \
607 attrs
.get((ns_uri
, "attr"), 25) == 25 and \
608 attrs
.items() == [] and \
609 attrs
.values() == [] and \
610 gvk
and gvqk
and gnqk
and gik
and gqnk
612 def test_nsattrs_empty():
613 return verify_empty_nsattrs(AttributesNSImpl({}, {}))
615 def test_nsattrs_wattr():
616 attrs
= AttributesNSImpl({(ns_uri
, "attr") : "val"},
617 {(ns_uri
, "attr") : "ns:attr"})
619 return attrs
.getLength() == 1 and \
620 attrs
.getNames() == [(ns_uri
, "attr")] and \
621 attrs
.getQNames() == ["ns:attr"] and \
622 len(attrs
) == 1 and \
623 attrs
.has_key((ns_uri
, "attr")) and \
624 attrs
.keys() == [(ns_uri
, "attr")] and \
625 attrs
.get((ns_uri
, "attr")) == "val" and \
626 attrs
.get((ns_uri
, "attr"), 25) == "val" and \
627 attrs
.items() == [((ns_uri
, "attr"), "val")] and \
628 attrs
.values() == ["val"] and \
629 attrs
.getValue((ns_uri
, "attr")) == "val" and \
630 attrs
.getValueByQName("ns:attr") == "val" and \
631 attrs
.getNameByQName("ns:attr") == (ns_uri
, "attr") and \
632 attrs
[(ns_uri
, "attr")] == "val" and \
633 attrs
.getQNameByName((ns_uri
, "attr")) == "ns:attr"
638 def make_test_output():
639 parser
= create_parser()
641 xmlgen
= XMLGenerator(result
)
643 parser
.setContentHandler(xmlgen
)
644 parser
.parse(findfile("test"+os
.extsep
+"xml"))
646 outf
= open(findfile("test"+os
.extsep
+"xml"+os
.extsep
+"out"), "w")
647 outf
.write(result
.getvalue())
650 items
= locals().items()
652 for (name
, value
) in items
:
653 if name
[ : 5] == "test_":
654 confirm(value(), name
)
657 print "%d tests, %d failures" % (tests
, len(failures
))
659 raise TestFailed("%d of %d tests failed: %s"
660 % (len(failures
), tests
, ", ".join(failures
)))