struct.pack has become picky about h (short) and H (unsigned short).
[python/dscho.git] / Lib / test / test_sax.py
blobe080217c06a42e025aefdc56c543af2d55396cd2
2 # regression test for SAX 2.0
3 # $Id$
5 from xml.sax import make_parser, ContentHandler, \
6 SAXException, SAXReaderNotAvailable, SAXParseException
7 try:
8 make_parser()
9 except SAXReaderNotAvailable:
10 # don't try to test this module if we cannot create a parser
11 raise ImportError("no XML parsers available")
12 from xml.sax.saxutils import XMLGenerator, escape, XMLFilterBase
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_support import verbose, TestFailed, findfile
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 # ===========================================================================
35 # saxutils tests
37 # ===========================================================================
39 # ===== escape
41 def test_escape_basic():
42 return escape("Donald Duck & Co") == "Donald Duck & Co"
44 def test_escape_all():
45 return escape("<Donald Duck & Co>") == "&lt;Donald Duck &amp; Co&gt;"
47 def test_escape_extra():
48 return escape("Hei på deg", {"å" : "&aring;"}) == "Hei p&aring; deg"
50 def test_make_parser():
51 try:
52 # Creating a parser should succeed - it should fall back
53 # to the expatreader
54 p = make_parser(['xml.parsers.no_such_parser'])
55 except:
56 return 0
57 else:
58 return p
61 # ===== XMLGenerator
63 start = '<?xml version="1.0" encoding="iso-8859-1"?>\n'
65 def test_xmlgen_basic():
66 result = StringIO()
67 gen = XMLGenerator(result)
68 gen.startDocument()
69 gen.startElement("doc", {})
70 gen.endElement("doc")
71 gen.endDocument()
73 return result.getvalue() == start + "<doc></doc>"
75 def test_xmlgen_content():
76 result = StringIO()
77 gen = XMLGenerator(result)
79 gen.startDocument()
80 gen.startElement("doc", {})
81 gen.characters("huhei")
82 gen.endElement("doc")
83 gen.endDocument()
85 return result.getvalue() == start + "<doc>huhei</doc>"
87 def test_xmlgen_pi():
88 result = StringIO()
89 gen = XMLGenerator(result)
91 gen.startDocument()
92 gen.processingInstruction("test", "data")
93 gen.startElement("doc", {})
94 gen.endElement("doc")
95 gen.endDocument()
97 return result.getvalue() == start + "<?test data?><doc></doc>"
99 def test_xmlgen_content_escape():
100 result = StringIO()
101 gen = XMLGenerator(result)
103 gen.startDocument()
104 gen.startElement("doc", {})
105 gen.characters("<huhei&")
106 gen.endElement("doc")
107 gen.endDocument()
109 return result.getvalue() == start + "<doc>&lt;huhei&amp;</doc>"
111 def test_xmlgen_ignorable():
112 result = StringIO()
113 gen = XMLGenerator(result)
115 gen.startDocument()
116 gen.startElement("doc", {})
117 gen.ignorableWhitespace(" ")
118 gen.endElement("doc")
119 gen.endDocument()
121 return result.getvalue() == start + "<doc> </doc>"
123 ns_uri = "http://www.python.org/xml-ns/saxtest/"
125 def test_xmlgen_ns():
126 result = StringIO()
127 gen = XMLGenerator(result)
129 gen.startDocument()
130 gen.startPrefixMapping("ns1", ns_uri)
131 gen.startElementNS((ns_uri, "doc"), "ns1:doc", {})
132 # add an unqualified name
133 gen.startElementNS((None, "udoc"), None, {})
134 gen.endElementNS((None, "udoc"), None)
135 gen.endElementNS((ns_uri, "doc"), "ns1:doc")
136 gen.endPrefixMapping("ns1")
137 gen.endDocument()
139 return result.getvalue() == start + \
140 ('<ns1:doc xmlns:ns1="%s"><udoc></udoc></ns1:doc>' %
141 ns_uri)
143 # ===== XMLFilterBase
145 def test_filter_basic():
146 result = StringIO()
147 gen = XMLGenerator(result)
148 filter = XMLFilterBase()
149 filter.setContentHandler(gen)
151 filter.startDocument()
152 filter.startElement("doc", {})
153 filter.characters("content")
154 filter.ignorableWhitespace(" ")
155 filter.endElement("doc")
156 filter.endDocument()
158 return result.getvalue() == start + "<doc>content </doc>"
160 # ===========================================================================
162 # expatreader tests
164 # ===========================================================================
166 # ===== DTDHandler support
168 class TestDTDHandler:
170 def __init__(self):
171 self._notations = []
172 self._entities = []
174 def notationDecl(self, name, publicId, systemId):
175 self._notations.append((name, publicId, systemId))
177 def unparsedEntityDecl(self, name, publicId, systemId, ndata):
178 self._entities.append((name, publicId, systemId, ndata))
180 def test_expat_dtdhandler():
181 parser = create_parser()
182 handler = TestDTDHandler()
183 parser.setDTDHandler(handler)
185 parser.feed('<!DOCTYPE doc [\n')
186 parser.feed(' <!ENTITY img SYSTEM "expat.gif" NDATA GIF>\n')
187 parser.feed(' <!NOTATION GIF PUBLIC "-//CompuServe//NOTATION Graphics Interchange Format 89a//EN">\n')
188 parser.feed(']>\n')
189 parser.feed('<doc></doc>')
190 parser.close()
192 return handler._notations == [("GIF", "-//CompuServe//NOTATION Graphics Interchange Format 89a//EN", None)] and \
193 handler._entities == [("img", None, "expat.gif", "GIF")]
195 # ===== EntityResolver support
197 class TestEntityResolver:
199 def resolveEntity(self, publicId, systemId):
200 inpsrc = InputSource()
201 inpsrc.setByteStream(StringIO("<entity/>"))
202 return inpsrc
204 def test_expat_entityresolver():
205 parser = create_parser()
206 parser.setEntityResolver(TestEntityResolver())
207 result = StringIO()
208 parser.setContentHandler(XMLGenerator(result))
210 parser.feed('<!DOCTYPE doc [\n')
211 parser.feed(' <!ENTITY test SYSTEM "whatever">\n')
212 parser.feed(']>\n')
213 parser.feed('<doc>&test;</doc>')
214 parser.close()
216 return result.getvalue() == start + "<doc><entity></entity></doc>"
218 # ===== Attributes support
220 class AttrGatherer(ContentHandler):
222 def startElement(self, name, attrs):
223 self._attrs = attrs
225 def startElementNS(self, name, qname, attrs):
226 self._attrs = attrs
228 def test_expat_attrs_empty():
229 parser = create_parser()
230 gather = AttrGatherer()
231 parser.setContentHandler(gather)
233 parser.feed("<doc/>")
234 parser.close()
236 return verify_empty_attrs(gather._attrs)
238 def test_expat_attrs_wattr():
239 parser = create_parser()
240 gather = AttrGatherer()
241 parser.setContentHandler(gather)
243 parser.feed("<doc attr='val'/>")
244 parser.close()
246 return verify_attrs_wattr(gather._attrs)
248 def test_expat_nsattrs_empty():
249 parser = create_parser(1)
250 gather = AttrGatherer()
251 parser.setContentHandler(gather)
253 parser.feed("<doc/>")
254 parser.close()
256 return verify_empty_nsattrs(gather._attrs)
258 def test_expat_nsattrs_wattr():
259 parser = create_parser(1)
260 gather = AttrGatherer()
261 parser.setContentHandler(gather)
263 parser.feed("<doc xmlns:ns='%s' ns:attr='val'/>" % ns_uri)
264 parser.close()
266 attrs = gather._attrs
268 return attrs.getLength() == 1 and \
269 attrs.getNames() == [(ns_uri, "attr")] and \
270 attrs.getQNames() == [] and \
271 len(attrs) == 1 and \
272 attrs.has_key((ns_uri, "attr")) and \
273 attrs.keys() == [(ns_uri, "attr")] and \
274 attrs.get((ns_uri, "attr")) == "val" and \
275 attrs.get((ns_uri, "attr"), 25) == "val" and \
276 attrs.items() == [((ns_uri, "attr"), "val")] and \
277 attrs.values() == ["val"] and \
278 attrs.getValue((ns_uri, "attr")) == "val" and \
279 attrs[(ns_uri, "attr")] == "val"
281 # ===== InputSource support
283 xml_test_out = open(findfile("test.xml.out")).read()
285 def test_expat_inpsource_filename():
286 parser = create_parser()
287 result = StringIO()
288 xmlgen = XMLGenerator(result)
290 parser.setContentHandler(xmlgen)
291 parser.parse(findfile("test.xml"))
293 return result.getvalue() == xml_test_out
295 def test_expat_inpsource_sysid():
296 parser = create_parser()
297 result = StringIO()
298 xmlgen = XMLGenerator(result)
300 parser.setContentHandler(xmlgen)
301 parser.parse(InputSource(findfile("test.xml")))
303 return result.getvalue() == xml_test_out
305 def test_expat_inpsource_stream():
306 parser = create_parser()
307 result = StringIO()
308 xmlgen = XMLGenerator(result)
310 parser.setContentHandler(xmlgen)
311 inpsrc = InputSource()
312 inpsrc.setByteStream(open(findfile("test.xml")))
313 parser.parse(inpsrc)
315 return result.getvalue() == xml_test_out
318 # ===========================================================================
320 # error reporting
322 # ===========================================================================
324 def test_expat_inpsource_location():
325 parser = create_parser()
326 parser.setContentHandler(ContentHandler()) # do nothing
327 source = InputSource()
328 source.setByteStream(StringIO("<foo bar foobar>")) #ill-formed
329 name = "a file name"
330 source.setSystemId(name)
331 try:
332 parser.parse(source)
333 except SAXException, e:
334 return e.getSystemId() == name
336 def test_expat_incomplete():
337 parser = create_parser()
338 parser.setContentHandler(ContentHandler()) # do nothing
339 try:
340 parser.parse(StringIO("<foo>"))
341 except SAXParseException:
342 return 1 # ok, error found
343 else:
344 return 0
347 # ===========================================================================
349 # xmlreader tests
351 # ===========================================================================
353 # ===== AttributesImpl
355 def verify_empty_attrs(attrs):
356 try:
357 attrs.getValue("attr")
358 gvk = 0
359 except KeyError:
360 gvk = 1
362 try:
363 attrs.getValueByQName("attr")
364 gvqk = 0
365 except KeyError:
366 gvqk = 1
368 try:
369 attrs.getNameByQName("attr")
370 gnqk = 0
371 except KeyError:
372 gnqk = 1
374 try:
375 attrs.getQNameByName("attr")
376 gqnk = 0
377 except KeyError:
378 gqnk = 1
380 try:
381 attrs["attr"]
382 gik = 0
383 except KeyError:
384 gik = 1
386 return attrs.getLength() == 0 and \
387 attrs.getNames() == [] and \
388 attrs.getQNames() == [] and \
389 len(attrs) == 0 and \
390 not attrs.has_key("attr") and \
391 attrs.keys() == [] and \
392 attrs.get("attrs") == None and \
393 attrs.get("attrs", 25) == 25 and \
394 attrs.items() == [] and \
395 attrs.values() == [] and \
396 gvk and gvqk and gnqk and gik and gqnk
398 def verify_attrs_wattr(attrs):
399 return attrs.getLength() == 1 and \
400 attrs.getNames() == ["attr"] and \
401 attrs.getQNames() == ["attr"] and \
402 len(attrs) == 1 and \
403 attrs.has_key("attr") and \
404 attrs.keys() == ["attr"] and \
405 attrs.get("attr") == "val" and \
406 attrs.get("attr", 25) == "val" and \
407 attrs.items() == [("attr", "val")] and \
408 attrs.values() == ["val"] and \
409 attrs.getValue("attr") == "val" and \
410 attrs.getValueByQName("attr") == "val" and \
411 attrs.getNameByQName("attr") == "attr" and \
412 attrs["attr"] == "val" and \
413 attrs.getQNameByName("attr") == "attr"
415 def test_attrs_empty():
416 return verify_empty_attrs(AttributesImpl({}))
418 def test_attrs_wattr():
419 return verify_attrs_wattr(AttributesImpl({"attr" : "val"}))
421 # ===== AttributesImpl
423 def verify_empty_nsattrs(attrs):
424 try:
425 attrs.getValue((ns_uri, "attr"))
426 gvk = 0
427 except KeyError:
428 gvk = 1
430 try:
431 attrs.getValueByQName("ns:attr")
432 gvqk = 0
433 except KeyError:
434 gvqk = 1
436 try:
437 attrs.getNameByQName("ns:attr")
438 gnqk = 0
439 except KeyError:
440 gnqk = 1
442 try:
443 attrs.getQNameByName((ns_uri, "attr"))
444 gqnk = 0
445 except KeyError:
446 gqnk = 1
448 try:
449 attrs[(ns_uri, "attr")]
450 gik = 0
451 except KeyError:
452 gik = 1
454 return attrs.getLength() == 0 and \
455 attrs.getNames() == [] and \
456 attrs.getQNames() == [] and \
457 len(attrs) == 0 and \
458 not attrs.has_key((ns_uri, "attr")) and \
459 attrs.keys() == [] and \
460 attrs.get((ns_uri, "attr")) == None and \
461 attrs.get((ns_uri, "attr"), 25) == 25 and \
462 attrs.items() == [] and \
463 attrs.values() == [] and \
464 gvk and gvqk and gnqk and gik and gqnk
466 def test_nsattrs_empty():
467 return verify_empty_nsattrs(AttributesNSImpl({}, {}))
469 def test_nsattrs_wattr():
470 attrs = AttributesNSImpl({(ns_uri, "attr") : "val"},
471 {(ns_uri, "attr") : "ns:attr"})
473 return attrs.getLength() == 1 and \
474 attrs.getNames() == [(ns_uri, "attr")] and \
475 attrs.getQNames() == ["ns:attr"] and \
476 len(attrs) == 1 and \
477 attrs.has_key((ns_uri, "attr")) and \
478 attrs.keys() == [(ns_uri, "attr")] and \
479 attrs.get((ns_uri, "attr")) == "val" and \
480 attrs.get((ns_uri, "attr"), 25) == "val" and \
481 attrs.items() == [((ns_uri, "attr"), "val")] and \
482 attrs.values() == ["val"] and \
483 attrs.getValue((ns_uri, "attr")) == "val" and \
484 attrs.getValueByQName("ns:attr") == "val" and \
485 attrs.getNameByQName("ns:attr") == (ns_uri, "attr") and \
486 attrs[(ns_uri, "attr")] == "val" and \
487 attrs.getQNameByName((ns_uri, "attr")) == "ns:attr"
490 # ===== Main program
492 def make_test_output():
493 parser = create_parser()
494 result = StringIO()
495 xmlgen = XMLGenerator(result)
497 parser.setContentHandler(xmlgen)
498 parser.parse(findfile("test.xml"))
500 outf = open(findfile("test.xml.out"), "w")
501 outf.write(result.getvalue())
502 outf.close()
504 items = locals().items()
505 items.sort()
506 for (name, value) in items:
507 if name[ : 5] == "test_":
508 confirm(value(), name)
510 print "%d tests, %d failures" % (tests, fails)
511 if fails != 0:
512 raise TestFailed, "%d of %d tests failed" % (fails, tests)