blob: 26fd87344ecbe33651a875fbfdf7d88fe23f0bd1 [file] [log] [blame]
Lars Gustäbel96753b32000-09-24 12:24:24 +00001# regression test for SAX 2.0
2# $Id$
3
Martin v. Löwis80670bc2000-10-06 21:13:23 +00004from xml.sax import make_parser, ContentHandler, \
5 SAXException, SAXReaderNotAvailable, SAXParseException
Martin v. Löwis962c9e72000-10-06 17:41:52 +00006try:
7 make_parser()
Martin v. Löwis80670bc2000-10-06 21:13:23 +00008except SAXReaderNotAvailable:
Martin v. Löwis962c9e72000-10-06 17:41:52 +00009 # don't try to test this module if we cannot create a parser
10 raise ImportError("no XML parsers available")
Lars Gustäbel96753b32000-09-24 12:24:24 +000011from xml.sax.saxutils import XMLGenerator, escape, XMLFilterBase
12from xml.sax.expatreader import create_parser
Lars Gustäbelb7536d52000-09-24 18:53:56 +000013from xml.sax.xmlreader import InputSource, AttributesImpl, AttributesNSImpl
Lars Gustäbel96753b32000-09-24 12:24:24 +000014from cStringIO import StringIO
Martin v. Löwis33315b12000-09-24 20:30:24 +000015from test_support import verbose, TestFailed, findfile
Lars Gustäbel96753b32000-09-24 12:24:24 +000016
17# ===== Utilities
18
19tests = 0
20fails = 0
21
22def confirm(outcome, name):
23 global tests, fails
24
25 tests = tests + 1
26 if outcome:
27 print "Passed", name
28 else:
29 print "Failed", name
30 fails = fails + 1
31
32# ===========================================================================
33#
34# saxutils tests
35#
36# ===========================================================================
37
38# ===== escape
39
40def test_escape_basic():
41 return escape("Donald Duck & Co") == "Donald Duck & Co"
42
43def test_escape_all():
44 return escape("<Donald Duck & Co>") == "&lt;Donald Duck &amp; Co&gt;"
45
46def test_escape_extra():
47 return escape("Hei på deg", {"å" : "&aring;"}) == "Hei p&aring; deg"
48
Martin v. Löwis962c9e72000-10-06 17:41:52 +000049def test_make_parser():
50 try:
51 # Creating a parser should succeed - it should fall back
52 # to the expatreader
53 p = make_parser(['xml.parsers.no_such_parser'])
54 except:
55 return 0
56 else:
57 return p
58
59
Lars Gustäbel96753b32000-09-24 12:24:24 +000060# ===== XMLGenerator
61
62start = '<?xml version="1.0" encoding="iso-8859-1"?>\n'
63
64def test_xmlgen_basic():
65 result = StringIO()
66 gen = XMLGenerator(result)
67 gen.startDocument()
68 gen.startElement("doc", {})
69 gen.endElement("doc")
70 gen.endDocument()
71
72 return result.getvalue() == start + "<doc></doc>"
73
74def test_xmlgen_content():
75 result = StringIO()
76 gen = XMLGenerator(result)
Fred Drake004d5e62000-10-23 17:22:08 +000077
Lars Gustäbel96753b32000-09-24 12:24:24 +000078 gen.startDocument()
79 gen.startElement("doc", {})
80 gen.characters("huhei")
81 gen.endElement("doc")
82 gen.endDocument()
83
84 return result.getvalue() == start + "<doc>huhei</doc>"
85
86def test_xmlgen_pi():
87 result = StringIO()
88 gen = XMLGenerator(result)
Fred Drake004d5e62000-10-23 17:22:08 +000089
Lars Gustäbel96753b32000-09-24 12:24:24 +000090 gen.startDocument()
91 gen.processingInstruction("test", "data")
92 gen.startElement("doc", {})
93 gen.endElement("doc")
94 gen.endDocument()
95
96 return result.getvalue() == start + "<?test data?><doc></doc>"
97
98def test_xmlgen_content_escape():
99 result = StringIO()
100 gen = XMLGenerator(result)
Fred Drake004d5e62000-10-23 17:22:08 +0000101
Lars Gustäbel96753b32000-09-24 12:24:24 +0000102 gen.startDocument()
103 gen.startElement("doc", {})
104 gen.characters("<huhei&")
105 gen.endElement("doc")
106 gen.endDocument()
107
108 return result.getvalue() == start + "<doc>&lt;huhei&amp;</doc>"
109
110def test_xmlgen_ignorable():
111 result = StringIO()
112 gen = XMLGenerator(result)
Fred Drake004d5e62000-10-23 17:22:08 +0000113
Lars Gustäbel96753b32000-09-24 12:24:24 +0000114 gen.startDocument()
115 gen.startElement("doc", {})
116 gen.ignorableWhitespace(" ")
117 gen.endElement("doc")
118 gen.endDocument()
119
120 return result.getvalue() == start + "<doc> </doc>"
121
122ns_uri = "http://www.python.org/xml-ns/saxtest/"
123
124def test_xmlgen_ns():
125 result = StringIO()
126 gen = XMLGenerator(result)
Fred Drake004d5e62000-10-23 17:22:08 +0000127
Lars Gustäbel96753b32000-09-24 12:24:24 +0000128 gen.startDocument()
129 gen.startPrefixMapping("ns1", ns_uri)
Lars Gustäbel6a7768a2000-09-27 08:12:17 +0000130 gen.startElementNS((ns_uri, "doc"), "ns1:doc", {})
Martin v. Löwiscf0a1cc2000-10-03 22:35:29 +0000131 # add an unqualified name
132 gen.startElementNS((None, "udoc"), None, {})
133 gen.endElementNS((None, "udoc"), None)
Lars Gustäbel6a7768a2000-09-27 08:12:17 +0000134 gen.endElementNS((ns_uri, "doc"), "ns1:doc")
Lars Gustäbel96753b32000-09-24 12:24:24 +0000135 gen.endPrefixMapping("ns1")
136 gen.endDocument()
137
Martin v. Löwiscf0a1cc2000-10-03 22:35:29 +0000138 return result.getvalue() == start + \
139 ('<ns1:doc xmlns:ns1="%s"><udoc></udoc></ns1:doc>' %
Lars Gustäbel96753b32000-09-24 12:24:24 +0000140 ns_uri)
141
142# ===== XMLFilterBase
143
144def test_filter_basic():
145 result = StringIO()
146 gen = XMLGenerator(result)
147 filter = XMLFilterBase()
148 filter.setContentHandler(gen)
Fred Drake004d5e62000-10-23 17:22:08 +0000149
Lars Gustäbel96753b32000-09-24 12:24:24 +0000150 filter.startDocument()
151 filter.startElement("doc", {})
152 filter.characters("content")
153 filter.ignorableWhitespace(" ")
154 filter.endElement("doc")
155 filter.endDocument()
156
157 return result.getvalue() == start + "<doc>content </doc>"
158
159# ===========================================================================
160#
161# expatreader tests
162#
163# ===========================================================================
164
165# ===== DTDHandler support
166
167class TestDTDHandler:
168
169 def __init__(self):
170 self._notations = []
171 self._entities = []
Fred Drake004d5e62000-10-23 17:22:08 +0000172
Lars Gustäbel96753b32000-09-24 12:24:24 +0000173 def notationDecl(self, name, publicId, systemId):
174 self._notations.append((name, publicId, systemId))
175
176 def unparsedEntityDecl(self, name, publicId, systemId, ndata):
177 self._entities.append((name, publicId, systemId, ndata))
178
Lars Gustäbele292a242000-09-24 20:19:45 +0000179def test_expat_dtdhandler():
180 parser = create_parser()
181 handler = TestDTDHandler()
182 parser.setDTDHandler(handler)
Lars Gustäbel96753b32000-09-24 12:24:24 +0000183
Lars Gustäbele292a242000-09-24 20:19:45 +0000184 parser.feed('<!DOCTYPE doc [\n')
185 parser.feed(' <!ENTITY img SYSTEM "expat.gif" NDATA GIF>\n')
186 parser.feed(' <!NOTATION GIF PUBLIC "-//CompuServe//NOTATION Graphics Interchange Format 89a//EN">\n')
187 parser.feed(']>\n')
188 parser.feed('<doc></doc>')
189 parser.close()
Lars Gustäbel96753b32000-09-24 12:24:24 +0000190
Lars Gustäbele292a242000-09-24 20:19:45 +0000191 return handler._notations == [("GIF", "-//CompuServe//NOTATION Graphics Interchange Format 89a//EN", None)] and \
192 handler._entities == [("img", None, "expat.gif", "GIF")]
Lars Gustäbel96753b32000-09-24 12:24:24 +0000193
194# ===== EntityResolver support
195
Lars Gustäbele292a242000-09-24 20:19:45 +0000196class TestEntityResolver:
Lars Gustäbel96753b32000-09-24 12:24:24 +0000197
Lars Gustäbele292a242000-09-24 20:19:45 +0000198 def resolveEntity(self, publicId, systemId):
199 inpsrc = InputSource()
200 inpsrc.setByteStream(StringIO("<entity/>"))
201 return inpsrc
202
203def test_expat_entityresolver():
Lars Gustäbele292a242000-09-24 20:19:45 +0000204 parser = create_parser()
205 parser.setEntityResolver(TestEntityResolver())
206 result = StringIO()
207 parser.setContentHandler(XMLGenerator(result))
208
209 parser.feed('<!DOCTYPE doc [\n')
210 parser.feed(' <!ENTITY test SYSTEM "whatever">\n')
211 parser.feed(']>\n')
212 parser.feed('<doc>&test;</doc>')
213 parser.close()
214
215 return result.getvalue() == start + "<doc><entity></entity></doc>"
Fred Drake004d5e62000-10-23 17:22:08 +0000216
Lars Gustäbelab647872000-09-24 18:40:52 +0000217# ===== Attributes support
218
219class AttrGatherer(ContentHandler):
220
221 def startElement(self, name, attrs):
222 self._attrs = attrs
223
224 def startElementNS(self, name, qname, attrs):
225 self._attrs = attrs
Fred Drake004d5e62000-10-23 17:22:08 +0000226
Lars Gustäbelab647872000-09-24 18:40:52 +0000227def test_expat_attrs_empty():
228 parser = create_parser()
229 gather = AttrGatherer()
230 parser.setContentHandler(gather)
231
232 parser.feed("<doc/>")
233 parser.close()
234
235 return verify_empty_attrs(gather._attrs)
236
237def test_expat_attrs_wattr():
238 parser = create_parser()
239 gather = AttrGatherer()
240 parser.setContentHandler(gather)
241
242 parser.feed("<doc attr='val'/>")
243 parser.close()
244
245 return verify_attrs_wattr(gather._attrs)
246
247def test_expat_nsattrs_empty():
248 parser = create_parser(1)
249 gather = AttrGatherer()
250 parser.setContentHandler(gather)
251
252 parser.feed("<doc/>")
253 parser.close()
254
255 return verify_empty_nsattrs(gather._attrs)
256
257def test_expat_nsattrs_wattr():
258 parser = create_parser(1)
259 gather = AttrGatherer()
260 parser.setContentHandler(gather)
261
262 parser.feed("<doc xmlns:ns='%s' ns:attr='val'/>" % ns_uri)
263 parser.close()
264
265 attrs = gather._attrs
Fred Drake004d5e62000-10-23 17:22:08 +0000266
Lars Gustäbelab647872000-09-24 18:40:52 +0000267 return attrs.getLength() == 1 and \
268 attrs.getNames() == [(ns_uri, "attr")] and \
269 attrs.getQNames() == [] and \
270 len(attrs) == 1 and \
271 attrs.has_key((ns_uri, "attr")) and \
272 attrs.keys() == [(ns_uri, "attr")] and \
273 attrs.get((ns_uri, "attr")) == "val" and \
274 attrs.get((ns_uri, "attr"), 25) == "val" and \
275 attrs.items() == [((ns_uri, "attr"), "val")] and \
276 attrs.values() == ["val"] and \
277 attrs.getValue((ns_uri, "attr")) == "val" and \
278 attrs[(ns_uri, "attr")] == "val"
279
Lars Gustäbelb7536d52000-09-24 18:53:56 +0000280# ===== InputSource support
281
Martin v. Löwis33315b12000-09-24 20:30:24 +0000282xml_test_out = open(findfile("test.xml.out")).read()
Lars Gustäbelb7536d52000-09-24 18:53:56 +0000283
284def test_expat_inpsource_filename():
285 parser = create_parser()
286 result = StringIO()
287 xmlgen = XMLGenerator(result)
288
289 parser.setContentHandler(xmlgen)
Martin v. Löwis33315b12000-09-24 20:30:24 +0000290 parser.parse(findfile("test.xml"))
Lars Gustäbelb7536d52000-09-24 18:53:56 +0000291
292 return result.getvalue() == xml_test_out
293
294def test_expat_inpsource_sysid():
295 parser = create_parser()
296 result = StringIO()
297 xmlgen = XMLGenerator(result)
298
299 parser.setContentHandler(xmlgen)
Martin v. Löwis33315b12000-09-24 20:30:24 +0000300 parser.parse(InputSource(findfile("test.xml")))
Lars Gustäbelb7536d52000-09-24 18:53:56 +0000301
302 return result.getvalue() == xml_test_out
303
304def test_expat_inpsource_stream():
305 parser = create_parser()
306 result = StringIO()
307 xmlgen = XMLGenerator(result)
308
309 parser.setContentHandler(xmlgen)
310 inpsrc = InputSource()
Martin v. Löwis33315b12000-09-24 20:30:24 +0000311 inpsrc.setByteStream(open(findfile("test.xml")))
Lars Gustäbelb7536d52000-09-24 18:53:56 +0000312 parser.parse(inpsrc)
313
314 return result.getvalue() == xml_test_out
315
Martin v. Löwis80670bc2000-10-06 21:13:23 +0000316
317# ===========================================================================
318#
319# error reporting
320#
321# ===========================================================================
322
323def test_expat_inpsource_location():
324 parser = create_parser()
325 parser.setContentHandler(ContentHandler()) # do nothing
326 source = InputSource()
327 source.setByteStream(StringIO("<foo bar foobar>")) #ill-formed
328 name = "a file name"
329 source.setSystemId(name)
330 try:
331 parser.parse(source)
332 except SAXException, e:
333 return e.getSystemId() == name
334
335def test_expat_incomplete():
336 parser = create_parser()
337 parser.setContentHandler(ContentHandler()) # do nothing
338 try:
339 parser.parse(StringIO("<foo>"))
340 except SAXParseException:
341 return 1 # ok, error found
342 else:
343 return 0
344
345
Lars Gustäbelab647872000-09-24 18:40:52 +0000346# ===========================================================================
347#
348# xmlreader tests
349#
350# ===========================================================================
351
352# ===== AttributesImpl
353
354def verify_empty_attrs(attrs):
355 try:
356 attrs.getValue("attr")
357 gvk = 0
358 except KeyError:
359 gvk = 1
360
361 try:
362 attrs.getValueByQName("attr")
363 gvqk = 0
364 except KeyError:
365 gvqk = 1
366
367 try:
368 attrs.getNameByQName("attr")
369 gnqk = 0
370 except KeyError:
371 gnqk = 1
372
373 try:
374 attrs.getQNameByName("attr")
375 gqnk = 0
376 except KeyError:
377 gqnk = 1
Fred Drake004d5e62000-10-23 17:22:08 +0000378
Lars Gustäbelab647872000-09-24 18:40:52 +0000379 try:
380 attrs["attr"]
381 gik = 0
382 except KeyError:
383 gik = 1
Fred Drake004d5e62000-10-23 17:22:08 +0000384
Lars Gustäbelab647872000-09-24 18:40:52 +0000385 return attrs.getLength() == 0 and \
386 attrs.getNames() == [] and \
387 attrs.getQNames() == [] and \
388 len(attrs) == 0 and \
389 not attrs.has_key("attr") and \
390 attrs.keys() == [] and \
391 attrs.get("attrs") == None and \
392 attrs.get("attrs", 25) == 25 and \
393 attrs.items() == [] and \
394 attrs.values() == [] and \
395 gvk and gvqk and gnqk and gik and gqnk
396
397def verify_attrs_wattr(attrs):
398 return attrs.getLength() == 1 and \
399 attrs.getNames() == ["attr"] and \
400 attrs.getQNames() == ["attr"] and \
401 len(attrs) == 1 and \
402 attrs.has_key("attr") and \
403 attrs.keys() == ["attr"] and \
404 attrs.get("attr") == "val" and \
405 attrs.get("attr", 25) == "val" and \
406 attrs.items() == [("attr", "val")] and \
407 attrs.values() == ["val"] and \
408 attrs.getValue("attr") == "val" and \
409 attrs.getValueByQName("attr") == "val" and \
410 attrs.getNameByQName("attr") == "attr" and \
411 attrs["attr"] == "val" and \
412 attrs.getQNameByName("attr") == "attr"
413
414def test_attrs_empty():
415 return verify_empty_attrs(AttributesImpl({}))
416
417def test_attrs_wattr():
418 return verify_attrs_wattr(AttributesImpl({"attr" : "val"}))
419
420# ===== AttributesImpl
421
422def verify_empty_nsattrs(attrs):
423 try:
424 attrs.getValue((ns_uri, "attr"))
425 gvk = 0
426 except KeyError:
427 gvk = 1
428
429 try:
430 attrs.getValueByQName("ns:attr")
431 gvqk = 0
432 except KeyError:
433 gvqk = 1
434
435 try:
436 attrs.getNameByQName("ns:attr")
437 gnqk = 0
438 except KeyError:
439 gnqk = 1
440
441 try:
442 attrs.getQNameByName((ns_uri, "attr"))
443 gqnk = 0
444 except KeyError:
445 gqnk = 1
Fred Drake004d5e62000-10-23 17:22:08 +0000446
Lars Gustäbelab647872000-09-24 18:40:52 +0000447 try:
448 attrs[(ns_uri, "attr")]
449 gik = 0
450 except KeyError:
451 gik = 1
Fred Drake004d5e62000-10-23 17:22:08 +0000452
Lars Gustäbelab647872000-09-24 18:40:52 +0000453 return attrs.getLength() == 0 and \
454 attrs.getNames() == [] and \
455 attrs.getQNames() == [] and \
456 len(attrs) == 0 and \
457 not attrs.has_key((ns_uri, "attr")) and \
458 attrs.keys() == [] and \
459 attrs.get((ns_uri, "attr")) == None and \
460 attrs.get((ns_uri, "attr"), 25) == 25 and \
461 attrs.items() == [] and \
462 attrs.values() == [] and \
463 gvk and gvqk and gnqk and gik and gqnk
464
465def test_nsattrs_empty():
466 return verify_empty_nsattrs(AttributesNSImpl({}, {}))
467
468def test_nsattrs_wattr():
469 attrs = AttributesNSImpl({(ns_uri, "attr") : "val"},
470 {(ns_uri, "attr") : "ns:attr"})
Fred Drake004d5e62000-10-23 17:22:08 +0000471
Lars Gustäbelab647872000-09-24 18:40:52 +0000472 return attrs.getLength() == 1 and \
473 attrs.getNames() == [(ns_uri, "attr")] and \
474 attrs.getQNames() == ["ns:attr"] and \
475 len(attrs) == 1 and \
476 attrs.has_key((ns_uri, "attr")) and \
477 attrs.keys() == [(ns_uri, "attr")] and \
478 attrs.get((ns_uri, "attr")) == "val" and \
479 attrs.get((ns_uri, "attr"), 25) == "val" and \
480 attrs.items() == [((ns_uri, "attr"), "val")] and \
481 attrs.values() == ["val"] and \
482 attrs.getValue((ns_uri, "attr")) == "val" and \
483 attrs.getValueByQName("ns:attr") == "val" and \
484 attrs.getNameByQName("ns:attr") == (ns_uri, "attr") and \
485 attrs[(ns_uri, "attr")] == "val" and \
486 attrs.getQNameByName((ns_uri, "attr")) == "ns:attr"
Fred Drake004d5e62000-10-23 17:22:08 +0000487
Lars Gustäbelab647872000-09-24 18:40:52 +0000488
Lars Gustäbel96753b32000-09-24 12:24:24 +0000489# ===== Main program
490
Lars Gustäbelb7536d52000-09-24 18:53:56 +0000491def make_test_output():
492 parser = create_parser()
493 result = StringIO()
494 xmlgen = XMLGenerator(result)
495
496 parser.setContentHandler(xmlgen)
Martin v. Löwis33315b12000-09-24 20:30:24 +0000497 parser.parse(findfile("test.xml"))
Lars Gustäbelb7536d52000-09-24 18:53:56 +0000498
Martin v. Löwis33315b12000-09-24 20:30:24 +0000499 outf = open(findfile("test.xml.out"), "w")
Lars Gustäbelb7536d52000-09-24 18:53:56 +0000500 outf.write(result.getvalue())
501 outf.close()
502
Lars Gustäbel96753b32000-09-24 12:24:24 +0000503items = locals().items()
504items.sort()
505for (name, value) in items:
506 if name[ : 5] == "test_":
507 confirm(value(), name)
508
509print "%d tests, %d failures" % (tests, fails)
510if fails != 0:
511 raise TestFailed, "%d of %d tests failed" % (fails, tests)