Exceptions raised during renaming in rotating file handlers are now passed to handleE...
[python.git] / Lib / test / test_minidom.py
blobb9377ae486fabc8ee0da840a746c233134e5b227
1 # test for xmlcore.dom.minidom
3 import os
4 import sys
5 import pickle
6 import traceback
7 from StringIO import StringIO
8 from test.test_support import verbose
10 import xmlcore.dom
11 import xmlcore.dom.minidom
12 import xmlcore.parsers.expat
14 from xmlcore.dom.minidom import parse, Node, Document, parseString
15 from xmlcore.dom.minidom import getDOMImplementation
18 if __name__ == "__main__":
19 base = sys.argv[0]
20 else:
21 base = __file__
22 tstfile = os.path.join(os.path.dirname(base), "test"+os.extsep+"xml")
23 del base
25 def confirm(test, testname = "Test"):
26 if not test:
27 print "Failed " + testname
28 raise Exception
30 def testParseFromFile():
31 dom = parse(StringIO(open(tstfile).read()))
32 dom.unlink()
33 confirm(isinstance(dom,Document))
35 def testGetElementsByTagName():
36 dom = parse(tstfile)
37 confirm(dom.getElementsByTagName("LI") == \
38 dom.documentElement.getElementsByTagName("LI"))
39 dom.unlink()
41 def testInsertBefore():
42 dom = parseString("<doc><foo/></doc>")
43 root = dom.documentElement
44 elem = root.childNodes[0]
45 nelem = dom.createElement("element")
46 root.insertBefore(nelem, elem)
47 confirm(len(root.childNodes) == 2
48 and root.childNodes.length == 2
49 and root.childNodes[0] is nelem
50 and root.childNodes.item(0) is nelem
51 and root.childNodes[1] is elem
52 and root.childNodes.item(1) is elem
53 and root.firstChild is nelem
54 and root.lastChild is elem
55 and root.toxml() == "<doc><element/><foo/></doc>"
56 , "testInsertBefore -- node properly placed in tree")
57 nelem = dom.createElement("element")
58 root.insertBefore(nelem, None)
59 confirm(len(root.childNodes) == 3
60 and root.childNodes.length == 3
61 and root.childNodes[1] is elem
62 and root.childNodes.item(1) is elem
63 and root.childNodes[2] is nelem
64 and root.childNodes.item(2) is nelem
65 and root.lastChild is nelem
66 and nelem.previousSibling is elem
67 and root.toxml() == "<doc><element/><foo/><element/></doc>"
68 , "testInsertBefore -- node properly placed in tree")
69 nelem2 = dom.createElement("bar")
70 root.insertBefore(nelem2, nelem)
71 confirm(len(root.childNodes) == 4
72 and root.childNodes.length == 4
73 and root.childNodes[2] is nelem2
74 and root.childNodes.item(2) is nelem2
75 and root.childNodes[3] is nelem
76 and root.childNodes.item(3) is nelem
77 and nelem2.nextSibling is nelem
78 and nelem.previousSibling is nelem2
79 and root.toxml() == "<doc><element/><foo/><bar/><element/></doc>"
80 , "testInsertBefore -- node properly placed in tree")
81 dom.unlink()
83 def _create_fragment_test_nodes():
84 dom = parseString("<doc/>")
85 orig = dom.createTextNode("original")
86 c1 = dom.createTextNode("foo")
87 c2 = dom.createTextNode("bar")
88 c3 = dom.createTextNode("bat")
89 dom.documentElement.appendChild(orig)
90 frag = dom.createDocumentFragment()
91 frag.appendChild(c1)
92 frag.appendChild(c2)
93 frag.appendChild(c3)
94 return dom, orig, c1, c2, c3, frag
96 def testInsertBeforeFragment():
97 dom, orig, c1, c2, c3, frag = _create_fragment_test_nodes()
98 dom.documentElement.insertBefore(frag, None)
99 confirm(tuple(dom.documentElement.childNodes) == (orig, c1, c2, c3),
100 "insertBefore(<fragment>, None)")
101 frag.unlink()
102 dom.unlink()
104 dom, orig, c1, c2, c3, frag = _create_fragment_test_nodes()
105 dom.documentElement.insertBefore(frag, orig)
106 confirm(tuple(dom.documentElement.childNodes) == (c1, c2, c3, orig),
107 "insertBefore(<fragment>, orig)")
108 frag.unlink()
109 dom.unlink()
111 def testAppendChild():
112 dom = parse(tstfile)
113 dom.documentElement.appendChild(dom.createComment(u"Hello"))
114 confirm(dom.documentElement.childNodes[-1].nodeName == "#comment")
115 confirm(dom.documentElement.childNodes[-1].data == "Hello")
116 dom.unlink()
118 def testAppendChildFragment():
119 dom, orig, c1, c2, c3, frag = _create_fragment_test_nodes()
120 dom.documentElement.appendChild(frag)
121 confirm(tuple(dom.documentElement.childNodes) == (orig, c1, c2, c3),
122 "appendChild(<fragment>)")
123 frag.unlink()
124 dom.unlink()
126 def testReplaceChildFragment():
127 dom, orig, c1, c2, c3, frag = _create_fragment_test_nodes()
128 dom.documentElement.replaceChild(frag, orig)
129 orig.unlink()
130 confirm(tuple(dom.documentElement.childNodes) == (c1, c2, c3),
131 "replaceChild(<fragment>)")
132 frag.unlink()
133 dom.unlink()
135 def testLegalChildren():
136 dom = Document()
137 elem = dom.createElement('element')
138 text = dom.createTextNode('text')
140 try: dom.appendChild(text)
141 except xmlcore.dom.HierarchyRequestErr: pass
142 else:
143 print "dom.appendChild didn't raise HierarchyRequestErr"
145 dom.appendChild(elem)
146 try: dom.insertBefore(text, elem)
147 except xmlcore.dom.HierarchyRequestErr: pass
148 else:
149 print "dom.appendChild didn't raise HierarchyRequestErr"
151 try: dom.replaceChild(text, elem)
152 except xmlcore.dom.HierarchyRequestErr: pass
153 else:
154 print "dom.appendChild didn't raise HierarchyRequestErr"
156 nodemap = elem.attributes
157 try: nodemap.setNamedItem(text)
158 except xmlcore.dom.HierarchyRequestErr: pass
159 else:
160 print "NamedNodeMap.setNamedItem didn't raise HierarchyRequestErr"
162 try: nodemap.setNamedItemNS(text)
163 except xmlcore.dom.HierarchyRequestErr: pass
164 else:
165 print "NamedNodeMap.setNamedItemNS didn't raise HierarchyRequestErr"
167 elem.appendChild(text)
168 dom.unlink()
170 def testNamedNodeMapSetItem():
171 dom = Document()
172 elem = dom.createElement('element')
173 attrs = elem.attributes
174 attrs["foo"] = "bar"
175 a = attrs.item(0)
176 confirm(a.ownerDocument is dom,
177 "NamedNodeMap.__setitem__() sets ownerDocument")
178 confirm(a.ownerElement is elem,
179 "NamedNodeMap.__setitem__() sets ownerElement")
180 confirm(a.value == "bar",
181 "NamedNodeMap.__setitem__() sets value")
182 confirm(a.nodeValue == "bar",
183 "NamedNodeMap.__setitem__() sets nodeValue")
184 elem.unlink()
185 dom.unlink()
187 def testNonZero():
188 dom = parse(tstfile)
189 confirm(dom)# should not be zero
190 dom.appendChild(dom.createComment("foo"))
191 confirm(not dom.childNodes[-1].childNodes)
192 dom.unlink()
194 def testUnlink():
195 dom = parse(tstfile)
196 dom.unlink()
198 def testElement():
199 dom = Document()
200 dom.appendChild(dom.createElement("abc"))
201 confirm(dom.documentElement)
202 dom.unlink()
204 def testAAA():
205 dom = parseString("<abc/>")
206 el = dom.documentElement
207 el.setAttribute("spam", "jam2")
208 confirm(el.toxml() == '<abc spam="jam2"/>', "testAAA")
209 a = el.getAttributeNode("spam")
210 confirm(a.ownerDocument is dom,
211 "setAttribute() sets ownerDocument")
212 confirm(a.ownerElement is dom.documentElement,
213 "setAttribute() sets ownerElement")
214 dom.unlink()
216 def testAAB():
217 dom = parseString("<abc/>")
218 el = dom.documentElement
219 el.setAttribute("spam", "jam")
220 el.setAttribute("spam", "jam2")
221 confirm(el.toxml() == '<abc spam="jam2"/>', "testAAB")
222 dom.unlink()
224 def testAddAttr():
225 dom = Document()
226 child = dom.appendChild(dom.createElement("abc"))
228 child.setAttribute("def", "ghi")
229 confirm(child.getAttribute("def") == "ghi")
230 confirm(child.attributes["def"].value == "ghi")
232 child.setAttribute("jkl", "mno")
233 confirm(child.getAttribute("jkl") == "mno")
234 confirm(child.attributes["jkl"].value == "mno")
236 confirm(len(child.attributes) == 2)
238 child.setAttribute("def", "newval")
239 confirm(child.getAttribute("def") == "newval")
240 confirm(child.attributes["def"].value == "newval")
242 confirm(len(child.attributes) == 2)
243 dom.unlink()
245 def testDeleteAttr():
246 dom = Document()
247 child = dom.appendChild(dom.createElement("abc"))
249 confirm(len(child.attributes) == 0)
250 child.setAttribute("def", "ghi")
251 confirm(len(child.attributes) == 1)
252 del child.attributes["def"]
253 confirm(len(child.attributes) == 0)
254 dom.unlink()
256 def testRemoveAttr():
257 dom = Document()
258 child = dom.appendChild(dom.createElement("abc"))
260 child.setAttribute("def", "ghi")
261 confirm(len(child.attributes) == 1)
262 child.removeAttribute("def")
263 confirm(len(child.attributes) == 0)
265 dom.unlink()
267 def testRemoveAttrNS():
268 dom = Document()
269 child = dom.appendChild(
270 dom.createElementNS("http://www.python.org", "python:abc"))
271 child.setAttributeNS("http://www.w3.org", "xmlns:python",
272 "http://www.python.org")
273 child.setAttributeNS("http://www.python.org", "python:abcattr", "foo")
274 confirm(len(child.attributes) == 2)
275 child.removeAttributeNS("http://www.python.org", "abcattr")
276 confirm(len(child.attributes) == 1)
278 dom.unlink()
280 def testRemoveAttributeNode():
281 dom = Document()
282 child = dom.appendChild(dom.createElement("foo"))
283 child.setAttribute("spam", "jam")
284 confirm(len(child.attributes) == 1)
285 node = child.getAttributeNode("spam")
286 child.removeAttributeNode(node)
287 confirm(len(child.attributes) == 0
288 and child.getAttributeNode("spam") is None)
290 dom.unlink()
292 def testChangeAttr():
293 dom = parseString("<abc/>")
294 el = dom.documentElement
295 el.setAttribute("spam", "jam")
296 confirm(len(el.attributes) == 1)
297 el.setAttribute("spam", "bam")
298 # Set this attribute to be an ID and make sure that doesn't change
299 # when changing the value:
300 el.setIdAttribute("spam")
301 confirm(len(el.attributes) == 1
302 and el.attributes["spam"].value == "bam"
303 and el.attributes["spam"].nodeValue == "bam"
304 and el.getAttribute("spam") == "bam"
305 and el.getAttributeNode("spam").isId)
306 el.attributes["spam"] = "ham"
307 confirm(len(el.attributes) == 1
308 and el.attributes["spam"].value == "ham"
309 and el.attributes["spam"].nodeValue == "ham"
310 and el.getAttribute("spam") == "ham"
311 and el.attributes["spam"].isId)
312 el.setAttribute("spam2", "bam")
313 confirm(len(el.attributes) == 2
314 and el.attributes["spam"].value == "ham"
315 and el.attributes["spam"].nodeValue == "ham"
316 and el.getAttribute("spam") == "ham"
317 and el.attributes["spam2"].value == "bam"
318 and el.attributes["spam2"].nodeValue == "bam"
319 and el.getAttribute("spam2") == "bam")
320 el.attributes["spam2"] = "bam2"
321 confirm(len(el.attributes) == 2
322 and el.attributes["spam"].value == "ham"
323 and el.attributes["spam"].nodeValue == "ham"
324 and el.getAttribute("spam") == "ham"
325 and el.attributes["spam2"].value == "bam2"
326 and el.attributes["spam2"].nodeValue == "bam2"
327 and el.getAttribute("spam2") == "bam2")
328 dom.unlink()
330 def testGetAttrList():
331 pass
333 def testGetAttrValues(): pass
335 def testGetAttrLength(): pass
337 def testGetAttribute(): pass
339 def testGetAttributeNS(): pass
341 def testGetAttributeNode(): pass
343 def testGetElementsByTagNameNS():
344 d="""<foo xmlns:minidom='http://pyxml.sf.net/minidom'>
345 <minidom:myelem/>
346 </foo>"""
347 dom = parseString(d)
348 elems = dom.getElementsByTagNameNS("http://pyxml.sf.net/minidom", "myelem")
349 confirm(len(elems) == 1
350 and elems[0].namespaceURI == "http://pyxml.sf.net/minidom"
351 and elems[0].localName == "myelem"
352 and elems[0].prefix == "minidom"
353 and elems[0].tagName == "minidom:myelem"
354 and elems[0].nodeName == "minidom:myelem")
355 dom.unlink()
357 def get_empty_nodelist_from_elements_by_tagName_ns_helper(doc, nsuri, lname):
358 nodelist = doc.getElementsByTagNameNS(nsuri, lname)
359 confirm(len(nodelist) == 0)
361 def testGetEmptyNodeListFromElementsByTagNameNS():
362 doc = parseString('<doc/>')
363 get_empty_nodelist_from_elements_by_tagName_ns_helper(
364 doc, 'http://xml.python.org/namespaces/a', 'localname')
365 get_empty_nodelist_from_elements_by_tagName_ns_helper(
366 doc, '*', 'splat')
367 get_empty_nodelist_from_elements_by_tagName_ns_helper(
368 doc, 'http://xml.python.org/namespaces/a', '*')
370 doc = parseString('<doc xmlns="http://xml.python.org/splat"><e/></doc>')
371 get_empty_nodelist_from_elements_by_tagName_ns_helper(
372 doc, "http://xml.python.org/splat", "not-there")
373 get_empty_nodelist_from_elements_by_tagName_ns_helper(
374 doc, "*", "not-there")
375 get_empty_nodelist_from_elements_by_tagName_ns_helper(
376 doc, "http://somewhere.else.net/not-there", "e")
378 def testElementReprAndStr():
379 dom = Document()
380 el = dom.appendChild(dom.createElement("abc"))
381 string1 = repr(el)
382 string2 = str(el)
383 confirm(string1 == string2)
384 dom.unlink()
386 # commented out until Fredrick's fix is checked in
387 def _testElementReprAndStrUnicode():
388 dom = Document()
389 el = dom.appendChild(dom.createElement(u"abc"))
390 string1 = repr(el)
391 string2 = str(el)
392 confirm(string1 == string2)
393 dom.unlink()
395 # commented out until Fredrick's fix is checked in
396 def _testElementReprAndStrUnicodeNS():
397 dom = Document()
398 el = dom.appendChild(
399 dom.createElementNS(u"http://www.slashdot.org", u"slash:abc"))
400 string1 = repr(el)
401 string2 = str(el)
402 confirm(string1 == string2)
403 confirm(string1.find("slash:abc") != -1)
404 dom.unlink()
406 def testAttributeRepr():
407 dom = Document()
408 el = dom.appendChild(dom.createElement(u"abc"))
409 node = el.setAttribute("abc", "def")
410 confirm(str(node) == repr(node))
411 dom.unlink()
413 def testTextNodeRepr(): pass
415 def testWriteXML():
416 str = '<?xml version="1.0" ?><a b="c"/>'
417 dom = parseString(str)
418 domstr = dom.toxml()
419 dom.unlink()
420 confirm(str == domstr)
422 def testAltNewline():
423 str = '<?xml version="1.0" ?>\n<a b="c"/>\n'
424 dom = parseString(str)
425 domstr = dom.toprettyxml(newl="\r\n")
426 dom.unlink()
427 confirm(domstr == str.replace("\n", "\r\n"))
429 def testProcessingInstruction():
430 dom = parseString('<e><?mypi \t\n data \t\n ?></e>')
431 pi = dom.documentElement.firstChild
432 confirm(pi.target == "mypi"
433 and pi.data == "data \t\n "
434 and pi.nodeName == "mypi"
435 and pi.nodeType == Node.PROCESSING_INSTRUCTION_NODE
436 and pi.attributes is None
437 and not pi.hasChildNodes()
438 and len(pi.childNodes) == 0
439 and pi.firstChild is None
440 and pi.lastChild is None
441 and pi.localName is None
442 and pi.namespaceURI == xmlcore.dom.EMPTY_NAMESPACE)
444 def testProcessingInstructionRepr(): pass
446 def testTextRepr(): pass
448 def testWriteText(): pass
450 def testDocumentElement(): pass
452 def testTooManyDocumentElements():
453 doc = parseString("<doc/>")
454 elem = doc.createElement("extra")
455 try:
456 doc.appendChild(elem)
457 except xmlcore.dom.HierarchyRequestErr:
458 pass
459 else:
460 print "Failed to catch expected exception when" \
461 " adding extra document element."
462 elem.unlink()
463 doc.unlink()
465 def testCreateElementNS(): pass
467 def testCreateAttributeNS(): pass
469 def testParse(): pass
471 def testParseString(): pass
473 def testComment(): pass
475 def testAttrListItem(): pass
477 def testAttrListItems(): pass
479 def testAttrListItemNS(): pass
481 def testAttrListKeys(): pass
483 def testAttrListKeysNS(): pass
485 def testRemoveNamedItem():
486 doc = parseString("<doc a=''/>")
487 e = doc.documentElement
488 attrs = e.attributes
489 a1 = e.getAttributeNode("a")
490 a2 = attrs.removeNamedItem("a")
491 confirm(a1.isSameNode(a2))
492 try:
493 attrs.removeNamedItem("a")
494 except xmlcore.dom.NotFoundErr:
495 pass
497 def testRemoveNamedItemNS():
498 doc = parseString("<doc xmlns:a='http://xml.python.org/' a:b=''/>")
499 e = doc.documentElement
500 attrs = e.attributes
501 a1 = e.getAttributeNodeNS("http://xml.python.org/", "b")
502 a2 = attrs.removeNamedItemNS("http://xml.python.org/", "b")
503 confirm(a1.isSameNode(a2))
504 try:
505 attrs.removeNamedItemNS("http://xml.python.org/", "b")
506 except xmlcore.dom.NotFoundErr:
507 pass
509 def testAttrListValues(): pass
511 def testAttrListLength(): pass
513 def testAttrList__getitem__(): pass
515 def testAttrList__setitem__(): pass
517 def testSetAttrValueandNodeValue(): pass
519 def testParseElement(): pass
521 def testParseAttributes(): pass
523 def testParseElementNamespaces(): pass
525 def testParseAttributeNamespaces(): pass
527 def testParseProcessingInstructions(): pass
529 def testChildNodes(): pass
531 def testFirstChild(): pass
533 def testHasChildNodes(): pass
535 def testCloneElementShallow():
536 dom, clone = _setupCloneElement(0)
537 confirm(len(clone.childNodes) == 0
538 and clone.childNodes.length == 0
539 and clone.parentNode is None
540 and clone.toxml() == '<doc attr="value"/>'
541 , "testCloneElementShallow")
542 dom.unlink()
544 def testCloneElementDeep():
545 dom, clone = _setupCloneElement(1)
546 confirm(len(clone.childNodes) == 1
547 and clone.childNodes.length == 1
548 and clone.parentNode is None
549 and clone.toxml() == '<doc attr="value"><foo/></doc>'
550 , "testCloneElementDeep")
551 dom.unlink()
553 def _setupCloneElement(deep):
554 dom = parseString("<doc attr='value'><foo/></doc>")
555 root = dom.documentElement
556 clone = root.cloneNode(deep)
557 _testCloneElementCopiesAttributes(
558 root, clone, "testCloneElement" + (deep and "Deep" or "Shallow"))
559 # mutilate the original so shared data is detected
560 root.tagName = root.nodeName = "MODIFIED"
561 root.setAttribute("attr", "NEW VALUE")
562 root.setAttribute("added", "VALUE")
563 return dom, clone
565 def _testCloneElementCopiesAttributes(e1, e2, test):
566 attrs1 = e1.attributes
567 attrs2 = e2.attributes
568 keys1 = attrs1.keys()
569 keys2 = attrs2.keys()
570 keys1.sort()
571 keys2.sort()
572 confirm(keys1 == keys2, "clone of element has same attribute keys")
573 for i in range(len(keys1)):
574 a1 = attrs1.item(i)
575 a2 = attrs2.item(i)
576 confirm(a1 is not a2
577 and a1.value == a2.value
578 and a1.nodeValue == a2.nodeValue
579 and a1.namespaceURI == a2.namespaceURI
580 and a1.localName == a2.localName
581 , "clone of attribute node has proper attribute values")
582 confirm(a2.ownerElement is e2,
583 "clone of attribute node correctly owned")
585 def testCloneDocumentShallow():
586 doc = parseString("<?xml version='1.0'?>\n"
587 "<!-- comment -->"
588 "<!DOCTYPE doc [\n"
589 "<!NOTATION notation SYSTEM 'http://xml.python.org/'>\n"
590 "]>\n"
591 "<doc attr='value'/>")
592 doc2 = doc.cloneNode(0)
593 confirm(doc2 is None,
594 "testCloneDocumentShallow:"
595 " shallow cloning of documents makes no sense!")
597 def testCloneDocumentDeep():
598 doc = parseString("<?xml version='1.0'?>\n"
599 "<!-- comment -->"
600 "<!DOCTYPE doc [\n"
601 "<!NOTATION notation SYSTEM 'http://xml.python.org/'>\n"
602 "]>\n"
603 "<doc attr='value'/>")
604 doc2 = doc.cloneNode(1)
605 confirm(not (doc.isSameNode(doc2) or doc2.isSameNode(doc)),
606 "testCloneDocumentDeep: document objects not distinct")
607 confirm(len(doc.childNodes) == len(doc2.childNodes),
608 "testCloneDocumentDeep: wrong number of Document children")
609 confirm(doc2.documentElement.nodeType == Node.ELEMENT_NODE,
610 "testCloneDocumentDeep: documentElement not an ELEMENT_NODE")
611 confirm(doc2.documentElement.ownerDocument.isSameNode(doc2),
612 "testCloneDocumentDeep: documentElement owner is not new document")
613 confirm(not doc.documentElement.isSameNode(doc2.documentElement),
614 "testCloneDocumentDeep: documentElement should not be shared")
615 if doc.doctype is not None:
616 # check the doctype iff the original DOM maintained it
617 confirm(doc2.doctype.nodeType == Node.DOCUMENT_TYPE_NODE,
618 "testCloneDocumentDeep: doctype not a DOCUMENT_TYPE_NODE")
619 confirm(doc2.doctype.ownerDocument.isSameNode(doc2))
620 confirm(not doc.doctype.isSameNode(doc2.doctype))
622 def testCloneDocumentTypeDeepOk():
623 doctype = create_nonempty_doctype()
624 clone = doctype.cloneNode(1)
625 confirm(clone is not None
626 and clone.nodeName == doctype.nodeName
627 and clone.name == doctype.name
628 and clone.publicId == doctype.publicId
629 and clone.systemId == doctype.systemId
630 and len(clone.entities) == len(doctype.entities)
631 and clone.entities.item(len(clone.entities)) is None
632 and len(clone.notations) == len(doctype.notations)
633 and clone.notations.item(len(clone.notations)) is None
634 and len(clone.childNodes) == 0)
635 for i in range(len(doctype.entities)):
636 se = doctype.entities.item(i)
637 ce = clone.entities.item(i)
638 confirm((not se.isSameNode(ce))
639 and (not ce.isSameNode(se))
640 and ce.nodeName == se.nodeName
641 and ce.notationName == se.notationName
642 and ce.publicId == se.publicId
643 and ce.systemId == se.systemId
644 and ce.encoding == se.encoding
645 and ce.actualEncoding == se.actualEncoding
646 and ce.version == se.version)
647 for i in range(len(doctype.notations)):
648 sn = doctype.notations.item(i)
649 cn = clone.notations.item(i)
650 confirm((not sn.isSameNode(cn))
651 and (not cn.isSameNode(sn))
652 and cn.nodeName == sn.nodeName
653 and cn.publicId == sn.publicId
654 and cn.systemId == sn.systemId)
656 def testCloneDocumentTypeDeepNotOk():
657 doc = create_doc_with_doctype()
658 clone = doc.doctype.cloneNode(1)
659 confirm(clone is None, "testCloneDocumentTypeDeepNotOk")
661 def testCloneDocumentTypeShallowOk():
662 doctype = create_nonempty_doctype()
663 clone = doctype.cloneNode(0)
664 confirm(clone is not None
665 and clone.nodeName == doctype.nodeName
666 and clone.name == doctype.name
667 and clone.publicId == doctype.publicId
668 and clone.systemId == doctype.systemId
669 and len(clone.entities) == 0
670 and clone.entities.item(0) is None
671 and len(clone.notations) == 0
672 and clone.notations.item(0) is None
673 and len(clone.childNodes) == 0)
675 def testCloneDocumentTypeShallowNotOk():
676 doc = create_doc_with_doctype()
677 clone = doc.doctype.cloneNode(0)
678 confirm(clone is None, "testCloneDocumentTypeShallowNotOk")
680 def check_import_document(deep, testName):
681 doc1 = parseString("<doc/>")
682 doc2 = parseString("<doc/>")
683 try:
684 doc1.importNode(doc2, deep)
685 except xmlcore.dom.NotSupportedErr:
686 pass
687 else:
688 raise Exception(testName +
689 ": expected NotSupportedErr when importing a document")
691 def testImportDocumentShallow():
692 check_import_document(0, "testImportDocumentShallow")
694 def testImportDocumentDeep():
695 check_import_document(1, "testImportDocumentDeep")
697 # The tests of DocumentType importing use these helpers to construct
698 # the documents to work with, since not all DOM builders actually
699 # create the DocumentType nodes.
701 def create_doc_without_doctype(doctype=None):
702 return getDOMImplementation().createDocument(None, "doc", doctype)
704 def create_nonempty_doctype():
705 doctype = getDOMImplementation().createDocumentType("doc", None, None)
706 doctype.entities._seq = []
707 doctype.notations._seq = []
708 notation = xmlcore.dom.minidom.Notation(
709 "my-notation", None,
710 "http://xml.python.org/notations/my")
711 doctype.notations._seq.append(notation)
712 entity = xmlcore.dom.minidom.Entity(
713 "my-entity", None,
714 "http://xml.python.org/entities/my",
715 "my-notation")
716 entity.version = "1.0"
717 entity.encoding = "utf-8"
718 entity.actualEncoding = "us-ascii"
719 doctype.entities._seq.append(entity)
720 return doctype
722 def create_doc_with_doctype():
723 doctype = create_nonempty_doctype()
724 doc = create_doc_without_doctype(doctype)
725 doctype.entities.item(0).ownerDocument = doc
726 doctype.notations.item(0).ownerDocument = doc
727 return doc
729 def testImportDocumentTypeShallow():
730 src = create_doc_with_doctype()
731 target = create_doc_without_doctype()
732 try:
733 imported = target.importNode(src.doctype, 0)
734 except xmlcore.dom.NotSupportedErr:
735 pass
736 else:
737 raise Exception(
738 "testImportDocumentTypeShallow: expected NotSupportedErr")
740 def testImportDocumentTypeDeep():
741 src = create_doc_with_doctype()
742 target = create_doc_without_doctype()
743 try:
744 imported = target.importNode(src.doctype, 1)
745 except xmlcore.dom.NotSupportedErr:
746 pass
747 else:
748 raise Exception(
749 "testImportDocumentTypeDeep: expected NotSupportedErr")
751 # Testing attribute clones uses a helper, and should always be deep,
752 # even if the argument to cloneNode is false.
753 def check_clone_attribute(deep, testName):
754 doc = parseString("<doc attr='value'/>")
755 attr = doc.documentElement.getAttributeNode("attr")
756 assert attr is not None
757 clone = attr.cloneNode(deep)
758 confirm(not clone.isSameNode(attr))
759 confirm(not attr.isSameNode(clone))
760 confirm(clone.ownerElement is None,
761 testName + ": ownerElement should be None")
762 confirm(clone.ownerDocument.isSameNode(attr.ownerDocument),
763 testName + ": ownerDocument does not match")
764 confirm(clone.specified,
765 testName + ": cloned attribute must have specified == True")
767 def testCloneAttributeShallow():
768 check_clone_attribute(0, "testCloneAttributeShallow")
770 def testCloneAttributeDeep():
771 check_clone_attribute(1, "testCloneAttributeDeep")
773 def check_clone_pi(deep, testName):
774 doc = parseString("<?target data?><doc/>")
775 pi = doc.firstChild
776 assert pi.nodeType == Node.PROCESSING_INSTRUCTION_NODE
777 clone = pi.cloneNode(deep)
778 confirm(clone.target == pi.target
779 and clone.data == pi.data)
781 def testClonePIShallow():
782 check_clone_pi(0, "testClonePIShallow")
784 def testClonePIDeep():
785 check_clone_pi(1, "testClonePIDeep")
787 def testNormalize():
788 doc = parseString("<doc/>")
789 root = doc.documentElement
790 root.appendChild(doc.createTextNode("first"))
791 root.appendChild(doc.createTextNode("second"))
792 confirm(len(root.childNodes) == 2
793 and root.childNodes.length == 2, "testNormalize -- preparation")
794 doc.normalize()
795 confirm(len(root.childNodes) == 1
796 and root.childNodes.length == 1
797 and root.firstChild is root.lastChild
798 and root.firstChild.data == "firstsecond"
799 , "testNormalize -- result")
800 doc.unlink()
802 doc = parseString("<doc/>")
803 root = doc.documentElement
804 root.appendChild(doc.createTextNode(""))
805 doc.normalize()
806 confirm(len(root.childNodes) == 0
807 and root.childNodes.length == 0,
808 "testNormalize -- single empty node removed")
809 doc.unlink()
811 def testSiblings():
812 doc = parseString("<doc><?pi?>text?<elm/></doc>")
813 root = doc.documentElement
814 (pi, text, elm) = root.childNodes
816 confirm(pi.nextSibling is text and
817 pi.previousSibling is None and
818 text.nextSibling is elm and
819 text.previousSibling is pi and
820 elm.nextSibling is None and
821 elm.previousSibling is text, "testSiblings")
823 doc.unlink()
825 def testParents():
826 doc = parseString("<doc><elm1><elm2/><elm2><elm3/></elm2></elm1></doc>")
827 root = doc.documentElement
828 elm1 = root.childNodes[0]
829 (elm2a, elm2b) = elm1.childNodes
830 elm3 = elm2b.childNodes[0]
832 confirm(root.parentNode is doc and
833 elm1.parentNode is root and
834 elm2a.parentNode is elm1 and
835 elm2b.parentNode is elm1 and
836 elm3.parentNode is elm2b, "testParents")
838 doc.unlink()
840 def testNodeListItem():
841 doc = parseString("<doc><e/><e/></doc>")
842 children = doc.childNodes
843 docelem = children[0]
844 confirm(children[0] is children.item(0)
845 and children.item(1) is None
846 and docelem.childNodes.item(0) is docelem.childNodes[0]
847 and docelem.childNodes.item(1) is docelem.childNodes[1]
848 and docelem.childNodes.item(0).childNodes.item(0) is None,
849 "test NodeList.item()")
850 doc.unlink()
852 def testSAX2DOM():
853 from xmlcore.dom import pulldom
855 sax2dom = pulldom.SAX2DOM()
856 sax2dom.startDocument()
857 sax2dom.startElement("doc", {})
858 sax2dom.characters("text")
859 sax2dom.startElement("subelm", {})
860 sax2dom.characters("text")
861 sax2dom.endElement("subelm")
862 sax2dom.characters("text")
863 sax2dom.endElement("doc")
864 sax2dom.endDocument()
866 doc = sax2dom.document
867 root = doc.documentElement
868 (text1, elm1, text2) = root.childNodes
869 text3 = elm1.childNodes[0]
871 confirm(text1.previousSibling is None and
872 text1.nextSibling is elm1 and
873 elm1.previousSibling is text1 and
874 elm1.nextSibling is text2 and
875 text2.previousSibling is elm1 and
876 text2.nextSibling is None and
877 text3.previousSibling is None and
878 text3.nextSibling is None, "testSAX2DOM - siblings")
880 confirm(root.parentNode is doc and
881 text1.parentNode is root and
882 elm1.parentNode is root and
883 text2.parentNode is root and
884 text3.parentNode is elm1, "testSAX2DOM - parents")
886 doc.unlink()
888 def testEncodings():
889 doc = parseString('<foo>&#x20ac;</foo>')
890 confirm(doc.toxml() == u'<?xml version="1.0" ?><foo>\u20ac</foo>'
891 and doc.toxml('utf-8') == '<?xml version="1.0" encoding="utf-8"?><foo>\xe2\x82\xac</foo>'
892 and doc.toxml('iso-8859-15') == '<?xml version="1.0" encoding="iso-8859-15"?><foo>\xa4</foo>',
893 "testEncodings - encoding EURO SIGN")
895 # Verify that character decoding errors throw exceptions instead of crashing
896 try:
897 doc = parseString('<fran\xe7ais>Comment \xe7a va ? Tr\xe8s bien ?</fran\xe7ais>')
898 except UnicodeDecodeError:
899 pass
900 else:
901 print 'parsing with bad encoding should raise a UnicodeDecodeError'
903 doc.unlink()
905 class UserDataHandler:
906 called = 0
907 def handle(self, operation, key, data, src, dst):
908 dst.setUserData(key, data + 1, self)
909 src.setUserData(key, None, None)
910 self.called = 1
912 def testUserData():
913 dom = Document()
914 n = dom.createElement('e')
915 confirm(n.getUserData("foo") is None)
916 n.setUserData("foo", None, None)
917 confirm(n.getUserData("foo") is None)
918 n.setUserData("foo", 12, 12)
919 n.setUserData("bar", 13, 13)
920 confirm(n.getUserData("foo") == 12)
921 confirm(n.getUserData("bar") == 13)
922 n.setUserData("foo", None, None)
923 confirm(n.getUserData("foo") is None)
924 confirm(n.getUserData("bar") == 13)
926 handler = UserDataHandler()
927 n.setUserData("bar", 12, handler)
928 c = n.cloneNode(1)
929 confirm(handler.called
930 and n.getUserData("bar") is None
931 and c.getUserData("bar") == 13)
932 n.unlink()
933 c.unlink()
934 dom.unlink()
936 def testRenameAttribute():
937 doc = parseString("<doc a='v'/>")
938 elem = doc.documentElement
939 attrmap = elem.attributes
940 attr = elem.attributes['a']
942 # Simple renaming
943 attr = doc.renameNode(attr, xmlcore.dom.EMPTY_NAMESPACE, "b")
944 confirm(attr.name == "b"
945 and attr.nodeName == "b"
946 and attr.localName is None
947 and attr.namespaceURI == xmlcore.dom.EMPTY_NAMESPACE
948 and attr.prefix is None
949 and attr.value == "v"
950 and elem.getAttributeNode("a") is None
951 and elem.getAttributeNode("b").isSameNode(attr)
952 and attrmap["b"].isSameNode(attr)
953 and attr.ownerDocument.isSameNode(doc)
954 and attr.ownerElement.isSameNode(elem))
956 # Rename to have a namespace, no prefix
957 attr = doc.renameNode(attr, "http://xml.python.org/ns", "c")
958 confirm(attr.name == "c"
959 and attr.nodeName == "c"
960 and attr.localName == "c"
961 and attr.namespaceURI == "http://xml.python.org/ns"
962 and attr.prefix is None
963 and attr.value == "v"
964 and elem.getAttributeNode("a") is None
965 and elem.getAttributeNode("b") is None
966 and elem.getAttributeNode("c").isSameNode(attr)
967 and elem.getAttributeNodeNS(
968 "http://xml.python.org/ns", "c").isSameNode(attr)
969 and attrmap["c"].isSameNode(attr)
970 and attrmap[("http://xml.python.org/ns", "c")].isSameNode(attr))
972 # Rename to have a namespace, with prefix
973 attr = doc.renameNode(attr, "http://xml.python.org/ns2", "p:d")
974 confirm(attr.name == "p:d"
975 and attr.nodeName == "p:d"
976 and attr.localName == "d"
977 and attr.namespaceURI == "http://xml.python.org/ns2"
978 and attr.prefix == "p"
979 and attr.value == "v"
980 and elem.getAttributeNode("a") is None
981 and elem.getAttributeNode("b") is None
982 and elem.getAttributeNode("c") is None
983 and elem.getAttributeNodeNS(
984 "http://xml.python.org/ns", "c") is None
985 and elem.getAttributeNode("p:d").isSameNode(attr)
986 and elem.getAttributeNodeNS(
987 "http://xml.python.org/ns2", "d").isSameNode(attr)
988 and attrmap["p:d"].isSameNode(attr)
989 and attrmap[("http://xml.python.org/ns2", "d")].isSameNode(attr))
991 # Rename back to a simple non-NS node
992 attr = doc.renameNode(attr, xmlcore.dom.EMPTY_NAMESPACE, "e")
993 confirm(attr.name == "e"
994 and attr.nodeName == "e"
995 and attr.localName is None
996 and attr.namespaceURI == xmlcore.dom.EMPTY_NAMESPACE
997 and attr.prefix is None
998 and attr.value == "v"
999 and elem.getAttributeNode("a") is None
1000 and elem.getAttributeNode("b") is None
1001 and elem.getAttributeNode("c") is None
1002 and elem.getAttributeNode("p:d") is None
1003 and elem.getAttributeNodeNS(
1004 "http://xml.python.org/ns", "c") is None
1005 and elem.getAttributeNode("e").isSameNode(attr)
1006 and attrmap["e"].isSameNode(attr))
1008 try:
1009 doc.renameNode(attr, "http://xml.python.org/ns", "xmlns")
1010 except xmlcore.dom.NamespaceErr:
1011 pass
1012 else:
1013 print "expected NamespaceErr"
1015 checkRenameNodeSharedConstraints(doc, attr)
1016 doc.unlink()
1018 def testRenameElement():
1019 doc = parseString("<doc/>")
1020 elem = doc.documentElement
1022 # Simple renaming
1023 elem = doc.renameNode(elem, xmlcore.dom.EMPTY_NAMESPACE, "a")
1024 confirm(elem.tagName == "a"
1025 and elem.nodeName == "a"
1026 and elem.localName is None
1027 and elem.namespaceURI == xmlcore.dom.EMPTY_NAMESPACE
1028 and elem.prefix is None
1029 and elem.ownerDocument.isSameNode(doc))
1031 # Rename to have a namespace, no prefix
1032 elem = doc.renameNode(elem, "http://xml.python.org/ns", "b")
1033 confirm(elem.tagName == "b"
1034 and elem.nodeName == "b"
1035 and elem.localName == "b"
1036 and elem.namespaceURI == "http://xml.python.org/ns"
1037 and elem.prefix is None
1038 and elem.ownerDocument.isSameNode(doc))
1040 # Rename to have a namespace, with prefix
1041 elem = doc.renameNode(elem, "http://xml.python.org/ns2", "p:c")
1042 confirm(elem.tagName == "p:c"
1043 and elem.nodeName == "p:c"
1044 and elem.localName == "c"
1045 and elem.namespaceURI == "http://xml.python.org/ns2"
1046 and elem.prefix == "p"
1047 and elem.ownerDocument.isSameNode(doc))
1049 # Rename back to a simple non-NS node
1050 elem = doc.renameNode(elem, xmlcore.dom.EMPTY_NAMESPACE, "d")
1051 confirm(elem.tagName == "d"
1052 and elem.nodeName == "d"
1053 and elem.localName is None
1054 and elem.namespaceURI == xmlcore.dom.EMPTY_NAMESPACE
1055 and elem.prefix is None
1056 and elem.ownerDocument.isSameNode(doc))
1058 checkRenameNodeSharedConstraints(doc, elem)
1059 doc.unlink()
1061 def checkRenameNodeSharedConstraints(doc, node):
1062 # Make sure illegal NS usage is detected:
1063 try:
1064 doc.renameNode(node, "http://xml.python.org/ns", "xmlns:foo")
1065 except xmlcore.dom.NamespaceErr:
1066 pass
1067 else:
1068 print "expected NamespaceErr"
1070 doc2 = parseString("<doc/>")
1071 try:
1072 doc2.renameNode(node, xmlcore.dom.EMPTY_NAMESPACE, "foo")
1073 except xmlcore.dom.WrongDocumentErr:
1074 pass
1075 else:
1076 print "expected WrongDocumentErr"
1078 def testRenameOther():
1079 # We have to create a comment node explicitly since not all DOM
1080 # builders used with minidom add comments to the DOM.
1081 doc = xmlcore.dom.minidom.getDOMImplementation().createDocument(
1082 xmlcore.dom.EMPTY_NAMESPACE, "e", None)
1083 node = doc.createComment("comment")
1084 try:
1085 doc.renameNode(node, xmlcore.dom.EMPTY_NAMESPACE, "foo")
1086 except xmlcore.dom.NotSupportedErr:
1087 pass
1088 else:
1089 print "expected NotSupportedErr when renaming comment node"
1090 doc.unlink()
1092 def checkWholeText(node, s):
1093 t = node.wholeText
1094 confirm(t == s, "looking for %s, found %s" % (repr(s), repr(t)))
1096 def testWholeText():
1097 doc = parseString("<doc>a</doc>")
1098 elem = doc.documentElement
1099 text = elem.childNodes[0]
1100 assert text.nodeType == Node.TEXT_NODE
1102 checkWholeText(text, "a")
1103 elem.appendChild(doc.createTextNode("b"))
1104 checkWholeText(text, "ab")
1105 elem.insertBefore(doc.createCDATASection("c"), text)
1106 checkWholeText(text, "cab")
1108 # make sure we don't cross other nodes
1109 splitter = doc.createComment("comment")
1110 elem.appendChild(splitter)
1111 text2 = doc.createTextNode("d")
1112 elem.appendChild(text2)
1113 checkWholeText(text, "cab")
1114 checkWholeText(text2, "d")
1116 x = doc.createElement("x")
1117 elem.replaceChild(x, splitter)
1118 splitter = x
1119 checkWholeText(text, "cab")
1120 checkWholeText(text2, "d")
1122 x = doc.createProcessingInstruction("y", "z")
1123 elem.replaceChild(x, splitter)
1124 splitter = x
1125 checkWholeText(text, "cab")
1126 checkWholeText(text2, "d")
1128 elem.removeChild(splitter)
1129 checkWholeText(text, "cabd")
1130 checkWholeText(text2, "cabd")
1132 def testPatch1094164 ():
1133 doc = parseString("<doc><e/></doc>")
1134 elem = doc.documentElement
1135 e = elem.firstChild
1136 confirm(e.parentNode is elem, "Before replaceChild()")
1137 # Check that replacing a child with itself leaves the tree unchanged
1138 elem.replaceChild(e, e)
1139 confirm(e.parentNode is elem, "After replaceChild()")
1143 def testReplaceWholeText():
1144 def setup():
1145 doc = parseString("<doc>a<e/>d</doc>")
1146 elem = doc.documentElement
1147 text1 = elem.firstChild
1148 text2 = elem.lastChild
1149 splitter = text1.nextSibling
1150 elem.insertBefore(doc.createTextNode("b"), splitter)
1151 elem.insertBefore(doc.createCDATASection("c"), text1)
1152 return doc, elem, text1, splitter, text2
1154 doc, elem, text1, splitter, text2 = setup()
1155 text = text1.replaceWholeText("new content")
1156 checkWholeText(text, "new content")
1157 checkWholeText(text2, "d")
1158 confirm(len(elem.childNodes) == 3)
1160 doc, elem, text1, splitter, text2 = setup()
1161 text = text2.replaceWholeText("new content")
1162 checkWholeText(text, "new content")
1163 checkWholeText(text1, "cab")
1164 confirm(len(elem.childNodes) == 5)
1166 doc, elem, text1, splitter, text2 = setup()
1167 text = text1.replaceWholeText("")
1168 checkWholeText(text2, "d")
1169 confirm(text is None
1170 and len(elem.childNodes) == 2)
1172 def testSchemaType():
1173 doc = parseString(
1174 "<!DOCTYPE doc [\n"
1175 " <!ENTITY e1 SYSTEM 'http://xml.python.org/e1'>\n"
1176 " <!ENTITY e2 SYSTEM 'http://xml.python.org/e2'>\n"
1177 " <!ATTLIST doc id ID #IMPLIED \n"
1178 " ref IDREF #IMPLIED \n"
1179 " refs IDREFS #IMPLIED \n"
1180 " enum (a|b) #IMPLIED \n"
1181 " ent ENTITY #IMPLIED \n"
1182 " ents ENTITIES #IMPLIED \n"
1183 " nm NMTOKEN #IMPLIED \n"
1184 " nms NMTOKENS #IMPLIED \n"
1185 " text CDATA #IMPLIED \n"
1186 " >\n"
1187 "]><doc id='name' notid='name' text='splat!' enum='b'"
1188 " ref='name' refs='name name' ent='e1' ents='e1 e2'"
1189 " nm='123' nms='123 abc' />")
1190 elem = doc.documentElement
1191 # We don't want to rely on any specific loader at this point, so
1192 # just make sure we can get to all the names, and that the
1193 # DTD-based namespace is right. The names can vary by loader
1194 # since each supports a different level of DTD information.
1195 t = elem.schemaType
1196 confirm(t.name is None
1197 and t.namespace == xmlcore.dom.EMPTY_NAMESPACE)
1198 names = "id notid text enum ref refs ent ents nm nms".split()
1199 for name in names:
1200 a = elem.getAttributeNode(name)
1201 t = a.schemaType
1202 confirm(hasattr(t, "name")
1203 and t.namespace == xmlcore.dom.EMPTY_NAMESPACE)
1205 def testSetIdAttribute():
1206 doc = parseString("<doc a1='v' a2='w'/>")
1207 e = doc.documentElement
1208 a1 = e.getAttributeNode("a1")
1209 a2 = e.getAttributeNode("a2")
1210 confirm(doc.getElementById("v") is None
1211 and not a1.isId
1212 and not a2.isId)
1213 e.setIdAttribute("a1")
1214 confirm(e.isSameNode(doc.getElementById("v"))
1215 and a1.isId
1216 and not a2.isId)
1217 e.setIdAttribute("a2")
1218 confirm(e.isSameNode(doc.getElementById("v"))
1219 and e.isSameNode(doc.getElementById("w"))
1220 and a1.isId
1221 and a2.isId)
1222 # replace the a1 node; the new node should *not* be an ID
1223 a3 = doc.createAttribute("a1")
1224 a3.value = "v"
1225 e.setAttributeNode(a3)
1226 confirm(doc.getElementById("v") is None
1227 and e.isSameNode(doc.getElementById("w"))
1228 and not a1.isId
1229 and a2.isId
1230 and not a3.isId)
1231 # renaming an attribute should not affect its ID-ness:
1232 doc.renameNode(a2, xmlcore.dom.EMPTY_NAMESPACE, "an")
1233 confirm(e.isSameNode(doc.getElementById("w"))
1234 and a2.isId)
1236 def testSetIdAttributeNS():
1237 NS1 = "http://xml.python.org/ns1"
1238 NS2 = "http://xml.python.org/ns2"
1239 doc = parseString("<doc"
1240 " xmlns:ns1='" + NS1 + "'"
1241 " xmlns:ns2='" + NS2 + "'"
1242 " ns1:a1='v' ns2:a2='w'/>")
1243 e = doc.documentElement
1244 a1 = e.getAttributeNodeNS(NS1, "a1")
1245 a2 = e.getAttributeNodeNS(NS2, "a2")
1246 confirm(doc.getElementById("v") is None
1247 and not a1.isId
1248 and not a2.isId)
1249 e.setIdAttributeNS(NS1, "a1")
1250 confirm(e.isSameNode(doc.getElementById("v"))
1251 and a1.isId
1252 and not a2.isId)
1253 e.setIdAttributeNS(NS2, "a2")
1254 confirm(e.isSameNode(doc.getElementById("v"))
1255 and e.isSameNode(doc.getElementById("w"))
1256 and a1.isId
1257 and a2.isId)
1258 # replace the a1 node; the new node should *not* be an ID
1259 a3 = doc.createAttributeNS(NS1, "a1")
1260 a3.value = "v"
1261 e.setAttributeNode(a3)
1262 confirm(e.isSameNode(doc.getElementById("w")))
1263 confirm(not a1.isId)
1264 confirm(a2.isId)
1265 confirm(not a3.isId)
1266 confirm(doc.getElementById("v") is None)
1267 # renaming an attribute should not affect its ID-ness:
1268 doc.renameNode(a2, xmlcore.dom.EMPTY_NAMESPACE, "an")
1269 confirm(e.isSameNode(doc.getElementById("w"))
1270 and a2.isId)
1272 def testSetIdAttributeNode():
1273 NS1 = "http://xml.python.org/ns1"
1274 NS2 = "http://xml.python.org/ns2"
1275 doc = parseString("<doc"
1276 " xmlns:ns1='" + NS1 + "'"
1277 " xmlns:ns2='" + NS2 + "'"
1278 " ns1:a1='v' ns2:a2='w'/>")
1279 e = doc.documentElement
1280 a1 = e.getAttributeNodeNS(NS1, "a1")
1281 a2 = e.getAttributeNodeNS(NS2, "a2")
1282 confirm(doc.getElementById("v") is None
1283 and not a1.isId
1284 and not a2.isId)
1285 e.setIdAttributeNode(a1)
1286 confirm(e.isSameNode(doc.getElementById("v"))
1287 and a1.isId
1288 and not a2.isId)
1289 e.setIdAttributeNode(a2)
1290 confirm(e.isSameNode(doc.getElementById("v"))
1291 and e.isSameNode(doc.getElementById("w"))
1292 and a1.isId
1293 and a2.isId)
1294 # replace the a1 node; the new node should *not* be an ID
1295 a3 = doc.createAttributeNS(NS1, "a1")
1296 a3.value = "v"
1297 e.setAttributeNode(a3)
1298 confirm(e.isSameNode(doc.getElementById("w")))
1299 confirm(not a1.isId)
1300 confirm(a2.isId)
1301 confirm(not a3.isId)
1302 confirm(doc.getElementById("v") is None)
1303 # renaming an attribute should not affect its ID-ness:
1304 doc.renameNode(a2, xmlcore.dom.EMPTY_NAMESPACE, "an")
1305 confirm(e.isSameNode(doc.getElementById("w"))
1306 and a2.isId)
1308 def testPickledDocument():
1309 doc = parseString("<?xml version='1.0' encoding='us-ascii'?>\n"
1310 "<!DOCTYPE doc PUBLIC 'http://xml.python.org/public'"
1311 " 'http://xml.python.org/system' [\n"
1312 " <!ELEMENT e EMPTY>\n"
1313 " <!ENTITY ent SYSTEM 'http://xml.python.org/entity'>\n"
1314 "]><doc attr='value'> text\n"
1315 "<?pi sample?> <!-- comment --> <e/> </doc>")
1316 s = pickle.dumps(doc)
1317 doc2 = pickle.loads(s)
1318 stack = [(doc, doc2)]
1319 while stack:
1320 n1, n2 = stack.pop()
1321 confirm(n1.nodeType == n2.nodeType
1322 and len(n1.childNodes) == len(n2.childNodes)
1323 and n1.nodeName == n2.nodeName
1324 and not n1.isSameNode(n2)
1325 and not n2.isSameNode(n1))
1326 if n1.nodeType == Node.DOCUMENT_TYPE_NODE:
1327 len(n1.entities)
1328 len(n2.entities)
1329 len(n1.notations)
1330 len(n2.notations)
1331 confirm(len(n1.entities) == len(n2.entities)
1332 and len(n1.notations) == len(n2.notations))
1333 for i in range(len(n1.notations)):
1334 no1 = n1.notations.item(i)
1335 no2 = n1.notations.item(i)
1336 confirm(no1.name == no2.name
1337 and no1.publicId == no2.publicId
1338 and no1.systemId == no2.systemId)
1339 statck.append((no1, no2))
1340 for i in range(len(n1.entities)):
1341 e1 = n1.entities.item(i)
1342 e2 = n2.entities.item(i)
1343 confirm(e1.notationName == e2.notationName
1344 and e1.publicId == e2.publicId
1345 and e1.systemId == e2.systemId)
1346 stack.append((e1, e2))
1347 if n1.nodeType != Node.DOCUMENT_NODE:
1348 confirm(n1.ownerDocument.isSameNode(doc)
1349 and n2.ownerDocument.isSameNode(doc2))
1350 for i in range(len(n1.childNodes)):
1351 stack.append((n1.childNodes[i], n2.childNodes[i]))
1354 # --- MAIN PROGRAM
1356 names = globals().keys()
1357 names.sort()
1359 failed = []
1361 try:
1362 Node.allnodes
1363 except AttributeError:
1364 # We don't actually have the minidom from the standard library,
1365 # but are picking up the PyXML version from site-packages.
1366 def check_allnodes():
1367 pass
1368 else:
1369 def check_allnodes():
1370 confirm(len(Node.allnodes) == 0,
1371 "assertion: len(Node.allnodes) == 0")
1372 if len(Node.allnodes):
1373 print "Garbage left over:"
1374 if verbose:
1375 print Node.allnodes.items()[0:10]
1376 else:
1377 # Don't print specific nodes if repeatable results
1378 # are needed
1379 print len(Node.allnodes)
1380 Node.allnodes = {}
1382 for name in names:
1383 if name.startswith("test"):
1384 func = globals()[name]
1385 try:
1386 func()
1387 check_allnodes()
1388 except:
1389 failed.append(name)
1390 print "Test Failed: ", name
1391 sys.stdout.flush()
1392 traceback.print_exception(*sys.exc_info())
1393 print repr(sys.exc_info()[1])
1394 Node.allnodes = {}
1396 if failed:
1397 print "\n\n\n**** Check for failures in these tests:"
1398 for name in failed:
1399 print " " + name