blob: e080217c06a42e025aefdc56c543af2d55396cd2 [file] [log] [blame]
Lars Gustäbel96753b32000-09-24 12:24:24 +00001
2# regression test for SAX 2.0
3# $Id$
4
Martin v. Löwis80670bc2000-10-06 21:13:23 +00005from xml.sax import make_parser, ContentHandler, \
6 SAXException, SAXReaderNotAvailable, SAXParseException
Martin v. Löwis962c9e72000-10-06 17:41:52 +00007try:
8 make_parser()
Martin v. Löwis80670bc2000-10-06 21:13:23 +00009except SAXReaderNotAvailable:
Martin v. Löwis962c9e72000-10-06 17:41:52 +000010 # don't try to test this module if we cannot create a parser
11 raise ImportError("no XML parsers available")
Lars Gustäbel96753b32000-09-24 12:24:24 +000012from xml.sax.saxutils import XMLGenerator, escape, XMLFilterBase
13from xml.sax.expatreader import create_parser
Lars Gustäbelb7536d52000-09-24 18:53:56 +000014from xml.sax.xmlreader import InputSource, AttributesImpl, AttributesNSImpl
Lars Gustäbel96753b32000-09-24 12:24:24 +000015from cStringIO import StringIO
Martin v. Löwis33315b12000-09-24 20:30:24 +000016from test_support import verbose, TestFailed, findfile
Lars Gustäbel96753b32000-09-24 12:24:24 +000017
18# ===== Utilities
19
20tests = 0
21fails = 0
22
23def confirm(outcome, name):
24 global tests, fails
25
26 tests = tests + 1
27 if outcome:
28 print "Passed", name
29 else:
30 print "Failed", name
31 fails = fails + 1
32
33# ===========================================================================
34#
35# saxutils tests
36#
37# ===========================================================================
38
39# ===== escape
40
41def test_escape_basic():
42 return escape("Donald Duck & Co") == "Donald Duck & Co"
43
44def test_escape_all():
45 return escape("<Donald Duck & Co>") == "&lt;Donald Duck &amp; Co&gt;"
46
47def test_escape_extra():
48 return escape("Hei på deg", {"å" : "&aring;"}) == "Hei p&aring; deg"
49
Martin v. Löwis962c9e72000-10-06 17:41:52 +000050def 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
59
60
Lars Gustäbel96753b32000-09-24 12:24:24 +000061# ===== XMLGenerator
62
63start = '<?xml version="1.0" encoding="iso-8859-1"?>\n'
64
65def test_xmlgen_basic():
66 result = StringIO()
67 gen = XMLGenerator(result)
68 gen.startDocument()
69 gen.startElement("doc", {})
70 gen.endElement("doc")
71 gen.endDocument()
72
73 return result.getvalue() == start + "<doc></doc>"
74
75def test_xmlgen_content():
76 result = StringIO()
77 gen = XMLGenerator(result)
78
79 gen.startDocument()
80 gen.startElement("doc", {})
81 gen.characters("huhei")
82 gen.endElement("doc")
83 gen.endDocument()
84
85 return result.getvalue() == start + "<doc>huhei</doc>"
86
87def test_xmlgen_pi():
88 result = StringIO()
89 gen = XMLGenerator(result)
90
91 gen.startDocument()
92 gen.processingInstruction("test", "data")
93 gen.startElement("doc", {})
94 gen.endElement("doc")
95 gen.endDocument()
96
97 return result.getvalue() == start + "<?test data?><doc></doc>"
98
99def test_xmlgen_content_escape():
100 result = StringIO()
101 gen = XMLGenerator(result)
102
103 gen.startDocument()
104 gen.startElement("doc", {})
105 gen.characters("<huhei&")
106 gen.endElement("doc")
107 gen.endDocument()
108
109 return result.getvalue() == start + "<doc>&lt;huhei&amp;</doc>"
110
111def test_xmlgen_ignorable():
112 result = StringIO()
113 gen = XMLGenerator(result)
114
115 gen.startDocument()
116 gen.startElement("doc", {})
117 gen.ignorableWhitespace(" ")
118 gen.endElement("doc")
119 gen.endDocument()
120
121 return result.getvalue() == start + "<doc> </doc>"
122
123ns_uri = "http://www.python.org/xml-ns/saxtest/"
124
125def test_xmlgen_ns():
126 result = StringIO()
127 gen = XMLGenerator(result)
128
129 gen.startDocument()
130 gen.startPrefixMapping("ns1", ns_uri)
Lars Gustäbel6a7768a2000-09-27 08:12:17 +0000131 gen.startElementNS((ns_uri, "doc"), "ns1:doc", {})
Martin v. Löwiscf0a1cc2000-10-03 22:35:29 +0000132 # add an unqualified name
133 gen.startElementNS((None, "udoc"), None, {})
134 gen.endElementNS((None, "udoc"), None)
Lars Gustäbel6a7768a2000-09-27 08:12:17 +0000135 gen.endElementNS((ns_uri, "doc"), "ns1:doc")
Lars Gustäbel96753b32000-09-24 12:24:24 +0000136 gen.endPrefixMapping("ns1")
137 gen.endDocument()
138
Martin v. Löwiscf0a1cc2000-10-03 22:35:29 +0000139 return result.getvalue() == start + \
140 ('<ns1:doc xmlns:ns1="%s"><udoc></udoc></ns1:doc>' %
Lars Gustäbel96753b32000-09-24 12:24:24 +0000141 ns_uri)
142
143# ===== XMLFilterBase
144
145def test_filter_basic():
146 result = StringIO()
147 gen = XMLGenerator(result)
148 filter = XMLFilterBase()
149 filter.setContentHandler(gen)
150
151 filter.startDocument()
152 filter.startElement("doc", {})
153 filter.characters("content")
154 filter.ignorableWhitespace(" ")
155 filter.endElement("doc")
156 filter.endDocument()
157
158 return result.getvalue() == start + "<doc>content </doc>"
159
160# ===========================================================================
161#
162# expatreader tests
163#
164# ===========================================================================
165
166# ===== DTDHandler support
167
168class TestDTDHandler:
169
170 def __init__(self):
171 self._notations = []
172 self._entities = []
173
174 def notationDecl(self, name, publicId, systemId):
175 self._notations.append((name, publicId, systemId))
176
177 def unparsedEntityDecl(self, name, publicId, systemId, ndata):
178 self._entities.append((name, publicId, systemId, ndata))
179
Lars Gustäbele292a242000-09-24 20:19:45 +0000180def test_expat_dtdhandler():
181 parser = create_parser()
182 handler = TestDTDHandler()
183 parser.setDTDHandler(handler)
Lars Gustäbel96753b32000-09-24 12:24:24 +0000184
Lars Gustäbele292a242000-09-24 20:19:45 +0000185 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()
Lars Gustäbel96753b32000-09-24 12:24:24 +0000191
Lars Gustäbele292a242000-09-24 20:19:45 +0000192 return handler._notations == [("GIF", "-//CompuServe//NOTATION Graphics Interchange Format 89a//EN", None)] and \
193 handler._entities == [("img", None, "expat.gif", "GIF")]
Lars Gustäbel96753b32000-09-24 12:24:24 +0000194
195# ===== EntityResolver support
196
Lars Gustäbele292a242000-09-24 20:19:45 +0000197class TestEntityResolver:
Lars Gustäbel96753b32000-09-24 12:24:24 +0000198
Lars Gustäbele292a242000-09-24 20:19:45 +0000199 def resolveEntity(self, publicId, systemId):
200 inpsrc = InputSource()
201 inpsrc.setByteStream(StringIO("<entity/>"))
202 return inpsrc
203
204def test_expat_entityresolver():
Lars Gustäbele292a242000-09-24 20:19:45 +0000205 parser = create_parser()
206 parser.setEntityResolver(TestEntityResolver())
207 result = StringIO()
208 parser.setContentHandler(XMLGenerator(result))
209
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()
215
216 return result.getvalue() == start + "<doc><entity></entity></doc>"
217
Lars Gustäbelab647872000-09-24 18:40:52 +0000218# ===== Attributes support
219
220class AttrGatherer(ContentHandler):
221
222 def startElement(self, name, attrs):
223 self._attrs = attrs
224
225 def startElementNS(self, name, qname, attrs):
226 self._attrs = attrs
227
228def test_expat_attrs_empty():
229 parser = create_parser()
230 gather = AttrGatherer()
231 parser.setContentHandler(gather)
232
233 parser.feed("<doc/>")
234 parser.close()
235
236 return verify_empty_attrs(gather._attrs)
237
238def test_expat_attrs_wattr():
239 parser = create_parser()
240 gather = AttrGatherer()
241 parser.setContentHandler(gather)
242
243 parser.feed("<doc attr='val'/>")
244 parser.close()
245
246 return verify_attrs_wattr(gather._attrs)
247
248def test_expat_nsattrs_empty():
249 parser = create_parser(1)
250 gather = AttrGatherer()
251 parser.setContentHandler(gather)
252
253 parser.feed("<doc/>")
254 parser.close()
255
256 return verify_empty_nsattrs(gather._attrs)
257
258def test_expat_nsattrs_wattr():
259 parser = create_parser(1)
260 gather = AttrGatherer()
261 parser.setContentHandler(gather)
262
263 parser.feed("<doc xmlns:ns='%s' ns:attr='val'/>" % ns_uri)
264 parser.close()
265
266 attrs = gather._attrs
267
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"
280
Lars Gustäbelb7536d52000-09-24 18:53:56 +0000281# ===== InputSource support
282
Martin v. Löwis33315b12000-09-24 20:30:24 +0000283xml_test_out = open(findfile("test.xml.out")).read()
Lars Gustäbelb7536d52000-09-24 18:53:56 +0000284
285def test_expat_inpsource_filename():
286 parser = create_parser()
287 result = StringIO()
288 xmlgen = XMLGenerator(result)
289
290 parser.setContentHandler(xmlgen)
Martin v. Löwis33315b12000-09-24 20:30:24 +0000291 parser.parse(findfile("test.xml"))
Lars Gustäbelb7536d52000-09-24 18:53:56 +0000292
293 return result.getvalue() == xml_test_out
294
295def test_expat_inpsource_sysid():
296 parser = create_parser()
297 result = StringIO()
298 xmlgen = XMLGenerator(result)
299
300 parser.setContentHandler(xmlgen)
Martin v. Löwis33315b12000-09-24 20:30:24 +0000301 parser.parse(InputSource(findfile("test.xml")))
Lars Gustäbelb7536d52000-09-24 18:53:56 +0000302
303 return result.getvalue() == xml_test_out
304
305def test_expat_inpsource_stream():
306 parser = create_parser()
307 result = StringIO()
308 xmlgen = XMLGenerator(result)
309
310 parser.setContentHandler(xmlgen)
311 inpsrc = InputSource()
Martin v. Löwis33315b12000-09-24 20:30:24 +0000312 inpsrc.setByteStream(open(findfile("test.xml")))
Lars Gustäbelb7536d52000-09-24 18:53:56 +0000313 parser.parse(inpsrc)
314
315 return result.getvalue() == xml_test_out
316
Martin v. Löwis80670bc2000-10-06 21:13:23 +0000317
318# ===========================================================================
319#
320# error reporting
321#
322# ===========================================================================
323
324def 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
335
336def 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
345
346
Lars Gustäbelab647872000-09-24 18:40:52 +0000347# ===========================================================================
348#
349# xmlreader tests
350#
351# ===========================================================================
352
353# ===== AttributesImpl
354
355def verify_empty_attrs(attrs):
356 try:
357 attrs.getValue("attr")
358 gvk = 0
359 except KeyError:
360 gvk = 1
361
362 try:
363 attrs.getValueByQName("attr")
364 gvqk = 0
365 except KeyError:
366 gvqk = 1
367
368 try:
369 attrs.getNameByQName("attr")
370 gnqk = 0
371 except KeyError:
372 gnqk = 1
373
374 try:
375 attrs.getQNameByName("attr")
376 gqnk = 0
377 except KeyError:
378 gqnk = 1
379
380 try:
381 attrs["attr"]
382 gik = 0
383 except KeyError:
384 gik = 1
385
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
397
398def 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"
414
415def test_attrs_empty():
416 return verify_empty_attrs(AttributesImpl({}))
417
418def test_attrs_wattr():
419 return verify_attrs_wattr(AttributesImpl({"attr" : "val"}))
420
421# ===== AttributesImpl
422
423def verify_empty_nsattrs(attrs):
424 try:
425 attrs.getValue((ns_uri, "attr"))
426 gvk = 0
427 except KeyError:
428 gvk = 1
429
430 try:
431 attrs.getValueByQName("ns:attr")
432 gvqk = 0
433 except KeyError:
434 gvqk = 1
435
436 try:
437 attrs.getNameByQName("ns:attr")
438 gnqk = 0
439 except KeyError:
440 gnqk = 1
441
442 try:
443 attrs.getQNameByName((ns_uri, "attr"))
444 gqnk = 0
445 except KeyError:
446 gqnk = 1
447
448 try:
449 attrs[(ns_uri, "attr")]
450 gik = 0
451 except KeyError:
452 gik = 1
453
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
465
466def test_nsattrs_empty():
467 return verify_empty_nsattrs(AttributesNSImpl({}, {}))
468
469def test_nsattrs_wattr():
470 attrs = AttributesNSImpl({(ns_uri, "attr") : "val"},
471 {(ns_uri, "attr") : "ns:attr"})
472
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"
488
489
Lars Gustäbel96753b32000-09-24 12:24:24 +0000490# ===== Main program
491
Lars Gustäbelb7536d52000-09-24 18:53:56 +0000492def make_test_output():
493 parser = create_parser()
494 result = StringIO()
495 xmlgen = XMLGenerator(result)
496
497 parser.setContentHandler(xmlgen)
Martin v. Löwis33315b12000-09-24 20:30:24 +0000498 parser.parse(findfile("test.xml"))
Lars Gustäbelb7536d52000-09-24 18:53:56 +0000499
Martin v. Löwis33315b12000-09-24 20:30:24 +0000500 outf = open(findfile("test.xml.out"), "w")
Lars Gustäbelb7536d52000-09-24 18:53:56 +0000501 outf.write(result.getvalue())
502 outf.close()
503
Lars Gustäbel96753b32000-09-24 12:24:24 +0000504items = locals().items()
505items.sort()
506for (name, value) in items:
507 if name[ : 5] == "test_":
508 confirm(value(), name)
509
510print "%d tests, %d failures" % (tests, fails)
511if fails != 0:
512 raise TestFailed, "%d of %d tests failed" % (fails, tests)