home *** CD-ROM | disk | FTP | other *** search
/ Maximum CD 2011 June / maximum-cd-2011-06.iso / DiscContents / LibO_3.3.1_Win_x86_install_multi.exe / libreoffice1.cab / test_minidom.py < prev    next >
Encoding:
Python Source  |  2011-02-15  |  51.9 KB  |  1,327 lines

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