openfile(): Go back to opening the files in text mode. This undoes
[python/dscho.git] / Lib / test / test_minidom.py
blob0791bbfdae5d248ec9749fde8aee0142bea2e812
1 # test for xml.dom.minidom
3 import os
4 import sys
5 import traceback
7 from test.test_support import verbose
9 import xml.dom
10 import xml.parsers.expat
12 from xml.dom.minidom import parse, Node, Document, parseString
14 if __name__ == "__main__":
15 base = sys.argv[0]
16 else:
17 base = __file__
18 tstfile = os.path.join(os.path.dirname(base), "test"+os.extsep+"xml")
19 del base
21 def confirm(test, testname = "Test"):
22 if not test:
23 print "Failed " + testname
24 raise Exception
26 Node._debug = 1
28 def testParseFromFile():
29 from StringIO import StringIO
30 dom = parse(StringIO(open(tstfile).read()))
31 dom.unlink()
32 confirm(isinstance(dom,Document))
34 def testGetElementsByTagName():
35 dom = parse(tstfile)
36 confirm(dom.getElementsByTagName("LI") == \
37 dom.documentElement.getElementsByTagName("LI"))
38 dom.unlink()
40 def testInsertBefore():
41 dom = parseString("<doc><foo/></doc>")
42 root = dom.documentElement
43 elem = root.childNodes[0]
44 nelem = dom.createElement("element")
45 root.insertBefore(nelem, elem)
46 confirm(len(root.childNodes) == 2
47 and root.childNodes.length == 2
48 and root.childNodes[0] is nelem
49 and root.childNodes.item(0) is nelem
50 and root.childNodes[1] is elem
51 and root.childNodes.item(1) is elem
52 and root.firstChild is nelem
53 and root.lastChild is elem
54 and root.toxml() == "<doc><element/><foo/></doc>"
55 , "testInsertBefore -- node properly placed in tree")
56 nelem = dom.createElement("element")
57 root.insertBefore(nelem, None)
58 confirm(len(root.childNodes) == 3
59 and root.childNodes.length == 3
60 and root.childNodes[1] is elem
61 and root.childNodes.item(1) is elem
62 and root.childNodes[2] is nelem
63 and root.childNodes.item(2) is nelem
64 and root.lastChild is nelem
65 and nelem.previousSibling is elem
66 and root.toxml() == "<doc><element/><foo/><element/></doc>"
67 , "testInsertBefore -- node properly placed in tree")
68 nelem2 = dom.createElement("bar")
69 root.insertBefore(nelem2, nelem)
70 confirm(len(root.childNodes) == 4
71 and root.childNodes.length == 4
72 and root.childNodes[2] is nelem2
73 and root.childNodes.item(2) is nelem2
74 and root.childNodes[3] is nelem
75 and root.childNodes.item(3) is nelem
76 and nelem2.nextSibling is nelem
77 and nelem.previousSibling is nelem2
78 and root.toxml() == "<doc><element/><foo/><bar/><element/></doc>"
79 , "testInsertBefore -- node properly placed in tree")
80 dom.unlink()
82 def _create_fragment_test_nodes():
83 dom = parseString("<doc/>")
84 orig = dom.createTextNode("original")
85 c1 = dom.createTextNode("foo")
86 c2 = dom.createTextNode("bar")
87 c3 = dom.createTextNode("bat")
88 dom.documentElement.appendChild(orig)
89 frag = dom.createDocumentFragment()
90 frag.appendChild(c1)
91 frag.appendChild(c2)
92 frag.appendChild(c3)
93 return dom, orig, c1, c2, c3, frag
95 def testInsertBeforeFragment():
96 dom, orig, c1, c2, c3, frag = _create_fragment_test_nodes()
97 dom.documentElement.insertBefore(frag, None)
98 confirm(tuple(dom.documentElement.childNodes) == (orig, c1, c2, c3),
99 "insertBefore(<fragment>, None)")
100 frag.unlink()
101 dom.unlink()
103 dom, orig, c1, c2, c3, frag = _create_fragment_test_nodes()
104 dom.documentElement.insertBefore(frag, orig)
105 confirm(tuple(dom.documentElement.childNodes) == (c1, c2, c3, orig),
106 "insertBefore(<fragment>, orig)")
107 frag.unlink()
108 dom.unlink()
110 def testAppendChild():
111 dom = parse(tstfile)
112 dom.documentElement.appendChild(dom.createComment(u"Hello"))
113 confirm(dom.documentElement.childNodes[-1].nodeName == "#comment")
114 confirm(dom.documentElement.childNodes[-1].data == "Hello")
115 dom.unlink()
117 def testAppendChildFragment():
118 dom, orig, c1, c2, c3, frag = _create_fragment_test_nodes()
119 dom.documentElement.appendChild(frag)
120 confirm(tuple(dom.documentElement.childNodes) == (orig, c1, c2, c3),
121 "appendChild(<fragment>)")
122 frag.unlink()
123 dom.unlink()
125 def testReplaceChildFragment():
126 dom, orig, c1, c2, c3, frag = _create_fragment_test_nodes()
127 dom.documentElement.replaceChild(frag, orig)
128 orig.unlink()
129 confirm(tuple(dom.documentElement.childNodes) == (c1, c2, c3),
130 "replaceChild(<fragment>)")
131 frag.unlink()
132 dom.unlink()
134 def testLegalChildren():
135 dom = Document()
136 elem = dom.createElement('element')
137 text = dom.createTextNode('text')
139 try: dom.appendChild(text)
140 except xml.dom.HierarchyRequestErr: pass
141 else:
142 print "dom.appendChild didn't raise HierarchyRequestErr"
144 dom.appendChild(elem)
145 try: dom.insertBefore(text, elem)
146 except xml.dom.HierarchyRequestErr: pass
147 else:
148 print "dom.appendChild didn't raise HierarchyRequestErr"
150 try: dom.replaceChild(text, elem)
151 except xml.dom.HierarchyRequestErr: pass
152 else:
153 print "dom.appendChild didn't raise HierarchyRequestErr"
155 nodemap = elem.attributes
156 try: nodemap.setNamedItem(text)
157 except xml.dom.HierarchyRequestErr: pass
158 else:
159 print "NamedNodeMap.setNamedItem didn't raise HierarchyRequestErr"
161 try: nodemap.setNamedItemNS(text)
162 except xml.dom.HierarchyRequestErr: pass
163 else:
164 print "NamedNodeMap.setNamedItemNS didn't raise HierarchyRequestErr"
166 elem.appendChild(text)
167 dom.unlink()
169 def testNamedNodeMapSetItem():
170 dom = Document()
171 elem = dom.createElement('element')
172 attrs = elem.attributes
173 attrs["foo"] = "bar"
174 a = attrs.item(0)
175 confirm(a.ownerDocument is dom,
176 "NamedNodeMap.__setitem__() sets ownerDocument")
177 confirm(a.ownerElement is elem,
178 "NamedNodeMap.__setitem__() sets ownerElement")
179 confirm(a.value == "bar",
180 "NamedNodeMap.__setitem__() sets value")
181 confirm(a.nodeValue == "bar",
182 "NamedNodeMap.__setitem__() sets nodeValue")
183 elem.unlink()
184 dom.unlink()
186 def testNonZero():
187 dom = parse(tstfile)
188 confirm(dom)# should not be zero
189 dom.appendChild(dom.createComment("foo"))
190 confirm(not dom.childNodes[-1].childNodes)
191 dom.unlink()
193 def testUnlink():
194 dom = parse(tstfile)
195 dom.unlink()
197 def testElement():
198 dom = Document()
199 dom.appendChild(dom.createElement("abc"))
200 confirm(dom.documentElement)
201 dom.unlink()
203 def testAAA():
204 dom = parseString("<abc/>")
205 el = dom.documentElement
206 el.setAttribute("spam", "jam2")
207 confirm(el.toxml() == '<abc spam="jam2"/>', "testAAA")
208 a = el.getAttributeNode("spam")
209 confirm(a.ownerDocument is dom,
210 "setAttribute() sets ownerDocument")
211 confirm(a.ownerElement is dom.documentElement,
212 "setAttribute() sets ownerElement")
213 dom.unlink()
215 def testAAB():
216 dom = parseString("<abc/>")
217 el = dom.documentElement
218 el.setAttribute("spam", "jam")
219 el.setAttribute("spam", "jam2")
220 confirm(el.toxml() == '<abc spam="jam2"/>', "testAAB")
221 dom.unlink()
223 def testAddAttr():
224 dom = Document()
225 child = dom.appendChild(dom.createElement("abc"))
227 child.setAttribute("def", "ghi")
228 confirm(child.getAttribute("def") == "ghi")
229 confirm(child.attributes["def"].value == "ghi")
231 child.setAttribute("jkl", "mno")
232 confirm(child.getAttribute("jkl") == "mno")
233 confirm(child.attributes["jkl"].value == "mno")
235 confirm(len(child.attributes) == 2)
237 child.setAttribute("def", "newval")
238 confirm(child.getAttribute("def") == "newval")
239 confirm(child.attributes["def"].value == "newval")
241 confirm(len(child.attributes) == 2)
242 dom.unlink()
244 def testDeleteAttr():
245 dom = Document()
246 child = dom.appendChild(dom.createElement("abc"))
248 confirm(len(child.attributes) == 0)
249 child.setAttribute("def", "ghi")
250 confirm(len(child.attributes) == 1)
251 del child.attributes["def"]
252 confirm(len(child.attributes) == 0)
253 dom.unlink()
255 def testRemoveAttr():
256 dom = Document()
257 child = dom.appendChild(dom.createElement("abc"))
259 child.setAttribute("def", "ghi")
260 confirm(len(child.attributes) == 1)
261 child.removeAttribute("def")
262 confirm(len(child.attributes) == 0)
264 dom.unlink()
266 def testRemoveAttrNS():
267 dom = Document()
268 child = dom.appendChild(
269 dom.createElementNS("http://www.python.org", "python:abc"))
270 child.setAttributeNS("http://www.w3.org", "xmlns:python",
271 "http://www.python.org")
272 child.setAttributeNS("http://www.python.org", "python:abcattr", "foo")
273 confirm(len(child.attributes) == 2)
274 child.removeAttributeNS("http://www.python.org", "abcattr")
275 confirm(len(child.attributes) == 1)
277 dom.unlink()
279 def testRemoveAttributeNode():
280 dom = Document()
281 child = dom.appendChild(dom.createElement("foo"))
282 child.setAttribute("spam", "jam")
283 confirm(len(child.attributes) == 1)
284 node = child.getAttributeNode("spam")
285 child.removeAttributeNode(node)
286 confirm(len(child.attributes) == 0)
288 dom.unlink()
290 def testChangeAttr():
291 dom = parseString("<abc/>")
292 el = dom.documentElement
293 el.setAttribute("spam", "jam")
294 confirm(len(el.attributes) == 1)
295 el.setAttribute("spam", "bam")
296 confirm(len(el.attributes) == 1)
297 el.attributes["spam"] = "ham"
298 confirm(len(el.attributes) == 1)
299 el.setAttribute("spam2", "bam")
300 confirm(len(el.attributes) == 2)
301 el.attributes[ "spam2"] = "bam2"
302 confirm(len(el.attributes) == 2)
303 dom.unlink()
305 def testGetAttrList():
306 pass
308 def testGetAttrValues(): pass
310 def testGetAttrLength(): pass
312 def testGetAttribute(): pass
314 def testGetAttributeNS(): pass
316 def testGetAttributeNode(): pass
318 def testGetElementsByTagNameNS():
319 d="""<foo xmlns:minidom="http://pyxml.sf.net/minidom">
320 <minidom:myelem/>
321 </foo>"""
322 dom = parseString(d)
323 elem = dom.getElementsByTagNameNS("http://pyxml.sf.net/minidom","myelem")
324 confirm(len(elem) == 1)
325 dom.unlink()
327 def testGetEmptyNodeListFromElementsByTagNameNS(): pass
329 def testElementReprAndStr():
330 dom = Document()
331 el = dom.appendChild(dom.createElement("abc"))
332 string1 = repr(el)
333 string2 = str(el)
334 confirm(string1 == string2)
335 dom.unlink()
337 # commented out until Fredrick's fix is checked in
338 def _testElementReprAndStrUnicode():
339 dom = Document()
340 el = dom.appendChild(dom.createElement(u"abc"))
341 string1 = repr(el)
342 string2 = str(el)
343 confirm(string1 == string2)
344 dom.unlink()
346 # commented out until Fredrick's fix is checked in
347 def _testElementReprAndStrUnicodeNS():
348 dom = Document()
349 el = dom.appendChild(
350 dom.createElementNS(u"http://www.slashdot.org", u"slash:abc"))
351 string1 = repr(el)
352 string2 = str(el)
353 confirm(string1 == string2)
354 confirm(string1.find("slash:abc") != -1)
355 dom.unlink()
357 def testAttributeRepr():
358 dom = Document()
359 el = dom.appendChild(dom.createElement(u"abc"))
360 node = el.setAttribute("abc", "def")
361 confirm(str(node) == repr(node))
362 dom.unlink()
364 def testTextNodeRepr(): pass
366 def testWriteXML():
367 str = '<?xml version="1.0" ?>\n<a b="c"/>'
368 dom = parseString(str)
369 domstr = dom.toxml()
370 dom.unlink()
371 confirm(str == domstr)
373 def testProcessingInstruction(): pass
375 def testProcessingInstructionRepr(): pass
377 def testTextRepr(): pass
379 def testWriteText(): pass
381 def testDocumentElement(): pass
383 def testTooManyDocumentElements():
384 doc = parseString("<doc/>")
385 elem = doc.createElement("extra")
386 try:
387 doc.appendChild(elem)
388 except xml.dom.HierarchyRequestErr:
389 pass
390 else:
391 print "Failed to catch expected exception when" \
392 " adding extra document element."
393 elem.unlink()
394 doc.unlink()
396 def testCreateElementNS(): pass
398 def testCreateAttributeNS(): pass
400 def testParse(): pass
402 def testParseString(): pass
404 def testComment(): pass
406 def testAttrListItem(): pass
408 def testAttrListItems(): pass
410 def testAttrListItemNS(): pass
412 def testAttrListKeys(): pass
414 def testAttrListKeysNS(): pass
416 def testAttrListValues(): pass
418 def testAttrListLength(): pass
420 def testAttrList__getitem__(): pass
422 def testAttrList__setitem__(): pass
424 def testSetAttrValueandNodeValue(): pass
426 def testParseElement(): pass
428 def testParseAttributes(): pass
430 def testParseElementNamespaces(): pass
432 def testParseAttributeNamespaces(): pass
434 def testParseProcessingInstructions(): pass
436 def testChildNodes(): pass
438 def testFirstChild(): pass
440 def testHasChildNodes(): pass
442 def testCloneElementShallow():
443 dom, clone = _setupCloneElement(0)
444 confirm(len(clone.childNodes) == 0
445 and clone.childNodes.length == 0
446 and clone.parentNode is None
447 and clone.toxml() == '<doc attr="value"/>'
448 , "testCloneElementShallow")
449 dom.unlink()
451 def testCloneElementDeep():
452 dom, clone = _setupCloneElement(1)
453 confirm(len(clone.childNodes) == 1
454 and clone.childNodes.length == 1
455 and clone.parentNode is None
456 and clone.toxml() == '<doc attr="value"><foo/></doc>'
457 , "testCloneElementDeep")
458 dom.unlink()
460 def _setupCloneElement(deep):
461 dom = parseString("<doc attr='value'><foo/></doc>")
462 root = dom.documentElement
463 clone = root.cloneNode(deep)
464 _testCloneElementCopiesAttributes(
465 root, clone, "testCloneElement" + (deep and "Deep" or "Shallow"))
466 # mutilate the original so shared data is detected
467 root.tagName = root.nodeName = "MODIFIED"
468 root.setAttribute("attr", "NEW VALUE")
469 root.setAttribute("added", "VALUE")
470 return dom, clone
472 def _testCloneElementCopiesAttributes(e1, e2, test):
473 attrs1 = e1.attributes
474 attrs2 = e2.attributes
475 keys1 = attrs1.keys()
476 keys2 = attrs2.keys()
477 keys1.sort()
478 keys2.sort()
479 confirm(keys1 == keys2, "clone of element has same attribute keys")
480 for i in range(len(keys1)):
481 a1 = attrs1.item(i)
482 a2 = attrs2.item(i)
483 confirm(a1 is not a2
484 and a1.value == a2.value
485 and a1.nodeValue == a2.nodeValue
486 and a1.namespaceURI == a2.namespaceURI
487 and a1.localName == a2.localName
488 , "clone of attribute node has proper attribute values")
489 confirm(a2.ownerElement is e2,
490 "clone of attribute node correctly owned")
493 def testCloneDocumentShallow(): pass
495 def testCloneDocumentDeep(): pass
497 def testCloneAttributeShallow(): pass
499 def testCloneAttributeDeep(): pass
501 def testClonePIShallow(): pass
503 def testClonePIDeep(): pass
505 def testNormalize():
506 doc = parseString("<doc/>")
507 root = doc.documentElement
508 root.appendChild(doc.createTextNode("first"))
509 root.appendChild(doc.createTextNode("second"))
510 confirm(len(root.childNodes) == 2
511 and root.childNodes.length == 2, "testNormalize -- preparation")
512 doc.normalize()
513 confirm(len(root.childNodes) == 1
514 and root.childNodes.length == 1
515 and root.firstChild is root.lastChild
516 and root.firstChild.data == "firstsecond"
517 , "testNormalize -- result")
518 doc.unlink()
520 doc = parseString("<doc/>")
521 root = doc.documentElement
522 root.appendChild(doc.createTextNode(""))
523 doc.normalize()
524 confirm(len(root.childNodes) == 0
525 and root.childNodes.length == 0,
526 "testNormalize -- single empty node removed")
527 doc.unlink()
529 def testSiblings():
530 doc = parseString("<doc><?pi?>text?<elm/></doc>")
531 root = doc.documentElement
532 (pi, text, elm) = root.childNodes
534 confirm(pi.nextSibling is text and
535 pi.previousSibling is None and
536 text.nextSibling is elm and
537 text.previousSibling is pi and
538 elm.nextSibling is None and
539 elm.previousSibling is text, "testSiblings")
541 doc.unlink()
543 def testParents():
544 doc = parseString("<doc><elm1><elm2/><elm2><elm3/></elm2></elm1></doc>")
545 root = doc.documentElement
546 elm1 = root.childNodes[0]
547 (elm2a, elm2b) = elm1.childNodes
548 elm3 = elm2b.childNodes[0]
550 confirm(root.parentNode is doc and
551 elm1.parentNode is root and
552 elm2a.parentNode is elm1 and
553 elm2b.parentNode is elm1 and
554 elm3.parentNode is elm2b, "testParents")
556 doc.unlink()
558 def testNodeListItem():
559 doc = parseString("<doc><e/><e/></doc>")
560 children = doc.childNodes
561 docelem = children[0]
562 confirm(children[0] is children.item(0)
563 and children.item(1) is None
564 and docelem.childNodes.item(0) is docelem.childNodes[0]
565 and docelem.childNodes.item(1) is docelem.childNodes[1]
566 and docelem.childNodes.item(0).childNodes.item(0) is None,
567 "test NodeList.item()")
568 doc.unlink()
570 def testSAX2DOM():
571 from xml.dom import pulldom
573 sax2dom = pulldom.SAX2DOM()
574 sax2dom.startDocument()
575 sax2dom.startElement("doc", {})
576 sax2dom.characters("text")
577 sax2dom.startElement("subelm", {})
578 sax2dom.characters("text")
579 sax2dom.endElement("subelm")
580 sax2dom.characters("text")
581 sax2dom.endElement("doc")
582 sax2dom.endDocument()
584 doc = sax2dom.document
585 root = doc.documentElement
586 (text1, elm1, text2) = root.childNodes
587 text3 = elm1.childNodes[0]
589 confirm(text1.previousSibling is None and
590 text1.nextSibling is elm1 and
591 elm1.previousSibling is text1 and
592 elm1.nextSibling is text2 and
593 text2.previousSibling is elm1 and
594 text2.nextSibling is None and
595 text3.previousSibling is None and
596 text3.nextSibling is None, "testSAX2DOM - siblings")
598 confirm(root.parentNode is doc and
599 text1.parentNode is root and
600 elm1.parentNode is root and
601 text2.parentNode is root and
602 text3.parentNode is elm1, "testSAX2DOM - parents")
604 doc.unlink()
606 def testEncodings():
607 doc = parseString('<foo>&#x20ac;</foo>')
608 confirm(doc.toxml() == u'<?xml version="1.0" ?>\n<foo>\u20ac</foo>'
609 and doc.toxml('utf-8') == '<?xml version="1.0" encoding="utf-8"?>\n<foo>\xe2\x82\xac</foo>'
610 and doc.toxml('iso-8859-15') == '<?xml version="1.0" encoding="iso-8859-15"?>\n<foo>\xa4</foo>',
611 "testEncodings - encoding EURO SIGN")
612 doc.unlink()
614 # --- MAIN PROGRAM
616 names = globals().keys()
617 names.sort()
619 failed = []
621 try:
622 Node.allnodes
623 except AttributeError:
624 # We don't actually have the minidom from teh standard library,
625 # but are picking up the PyXML version from site-packages.
626 def check_allnodes():
627 pass
628 else:
629 def check_allnodes():
630 confirm(len(Node.allnodes) == 0,
631 "assertion: len(Node.allnodes) == 0")
632 if len(Node.allnodes):
633 print "Garbage left over:"
634 if verbose:
635 print Node.allnodes.items()[0:10]
636 else:
637 # Don't print specific nodes if repeatable results
638 # are needed
639 print len(Node.allnodes)
640 Node.allnodes = {}
642 for name in names:
643 if name.startswith("test"):
644 func = globals()[name]
645 try:
646 func()
647 check_allnodes()
648 except:
649 failed.append(name)
650 print "Test Failed: ", name
651 sys.stdout.flush()
652 traceback.print_exception(*sys.exc_info())
653 print `sys.exc_info()[1]`
654 Node.allnodes = {}
656 if failed:
657 print "\n\n\n**** Check for failures in these tests:"
658 for name in failed:
659 print " " + name