# test for xml.dom.minidom



import os

import sys

import pickle

from StringIO import StringIO

from test.test_support import verbose, run_unittest, TestSkipped

import unittest



import xml.dom

import xml.dom.minidom

import xml.parsers.expat



from xml.dom.minidom import parse, Node, Document, parseString

from xml.dom.minidom import getDOMImplementation





if __name__ == "__main__":

    base = sys.argv[0]

else:

    base = __file__

tstfile = os.path.join(os.path.dirname(base), "test"+os.extsep+"xml")

del base



# The tests of DocumentType importing use these helpers to construct

# the documents to work with, since not all DOM builders actually

# create the DocumentType nodes.

def create_doc_without_doctype(doctype=None):

    return getDOMImplementation().createDocument(None, "doc", doctype)



def create_nonempty_doctype():

    doctype = getDOMImplementation().createDocumentType("doc", None, None)

    doctype.entities._seq = []

    doctype.notations._seq = []

    notation = xml.dom.minidom.Notation("my-notation", None,

                                        "http://xml.python.org/notations/my")

    doctype.notations._seq.append(notation)

    entity = xml.dom.minidom.Entity("my-entity", None,

                                    "http://xml.python.org/entities/my",

                                    "my-notation")

    entity.version = "1.0"

    entity.encoding = "utf-8"

    entity.actualEncoding = "us-ascii"

    doctype.entities._seq.append(entity)

    return doctype



def create_doc_with_doctype():

    doctype = create_nonempty_doctype()

    doc = create_doc_without_doctype(doctype)

    doctype.entities.item(0).ownerDocument = doc

    doctype.notations.item(0).ownerDocument = doc

    return doc



class MinidomTest(unittest.TestCase):

    def tearDown(self):

        try:

            Node.allnodes

        except AttributeError:

            # We don't actually have the minidom from the standard library,

            # but are picking up the PyXML version from site-packages.

            pass

        else:

            self.confirm(len(Node.allnodes) == 0,

                    "assertion: len(Node.allnodes) == 0")

            if len(Node.allnodes):

                print "Garbage left over:"

                if verbose:

                    print Node.allnodes.items()[0:10]

                else:

                    # Don't print specific nodes if repeatable results

                    # are needed

                    print len(Node.allnodes)

            Node.allnodes = {}



    def confirm(self, test, testname = "Test"):

        self.assertTrue(test, testname)



    def checkWholeText(self, node, s):

        t = node.wholeText

        self.confirm(t == s, "looking for %s, found %s" % (repr(s), repr(t)))



    def testParseFromFile(self):

        dom = parse(StringIO(open(tstfile).read()))

        dom.unlink()

        self.confirm(isinstance(dom,Document))



    def testGetElementsByTagName(self):

        dom = parse(tstfile)

        self.confirm(dom.getElementsByTagName("LI") == \

                dom.documentElement.getElementsByTagName("LI"))

        dom.unlink()



    def testInsertBefore(self):

        dom = parseString("<doc><foo/></doc>")

        root = dom.documentElement

        elem = root.childNodes[0]

        nelem = dom.createElement("element")

        root.insertBefore(nelem, elem)

        self.confirm(len(root.childNodes) == 2

                and root.childNodes.length == 2

                and root.childNodes[0] is nelem

                and root.childNodes.item(0) is nelem

                and root.childNodes[1] is elem

                and root.childNodes.item(1) is elem

                and root.firstChild is nelem

                and root.lastChild is elem

                and root.toxml() == "<doc><element/><foo/></doc>"

                , "testInsertBefore -- node properly placed in tree")

        nelem = dom.createElement("element")

        root.insertBefore(nelem, None)

        self.confirm(len(root.childNodes) == 3

                and root.childNodes.length == 3

                and root.childNodes[1] is elem

                and root.childNodes.item(1) is elem

                and root.childNodes[2] is nelem

                and root.childNodes.item(2) is nelem

                and root.lastChild is nelem

                and nelem.previousSibling is elem

                and root.toxml() == "<doc><element/><foo/><element/></doc>"

                , "testInsertBefore -- node properly placed in tree")

        nelem2 = dom.createElement("bar")

        root.insertBefore(nelem2, nelem)

        self.confirm(len(root.childNodes) == 4

                and root.childNodes.length == 4

                and root.childNodes[2] is nelem2

                and root.childNodes.item(2) is nelem2

                and root.childNodes[3] is nelem

                and root.childNodes.item(3) is nelem

                and nelem2.nextSibling is nelem

                and nelem.previousSibling is nelem2

                and root.toxml() ==

                "<doc><element/><foo/><bar/><element/></doc>"

                , "testInsertBefore -- node properly placed in tree")

        dom.unlink()



    def _create_fragment_test_nodes(self):

        dom = parseString("<doc/>")

        orig = dom.createTextNode("original")

        c1 = dom.createTextNode("foo")

        c2 = dom.createTextNode("bar")

        c3 = dom.createTextNode("bat")

        dom.documentElement.appendChild(orig)

        frag = dom.createDocumentFragment()

        frag.appendChild(c1)

        frag.appendChild(c2)

        frag.appendChild(c3)

        return dom, orig, c1, c2, c3, frag



    def testInsertBeforeFragment(self):

        dom, orig, c1, c2, c3, frag = self._create_fragment_test_nodes()

        dom.documentElement.insertBefore(frag, None)

        self.confirm(tuple(dom.documentElement.childNodes) ==

                     (orig, c1, c2, c3),

                     "insertBefore(<fragment>, None)")

        frag.unlink()

        dom.unlink()



        dom, orig, c1, c2, c3, frag = self._create_fragment_test_nodes()

        dom.documentElement.insertBefore(frag, orig)

        self.confirm(tuple(dom.documentElement.childNodes) ==

                     (c1, c2, c3, orig),

                     "insertBefore(<fragment>, orig)")

        frag.unlink()

        dom.unlink()



    def testAppendChild(self):

        dom = parse(tstfile)

        dom.documentElement.appendChild(dom.createComment(u"Hello"))

        self.confirm(dom.documentElement.childNodes[-1].nodeName == "#comment")

        self.confirm(dom.documentElement.childNodes[-1].data == "Hello")

        dom.unlink()



    def testAppendChildFragment(self):

        dom, orig, c1, c2, c3, frag = self._create_fragment_test_nodes()

        dom.documentElement.appendChild(frag)

        self.confirm(tuple(dom.documentElement.childNodes) ==

                     (orig, c1, c2, c3),

                     "appendChild(<fragment>)")

        frag.unlink()

        dom.unlink()



    def testReplaceChildFragment(self):

        dom, orig, c1, c2, c3, frag = self._create_fragment_test_nodes()

        dom.documentElement.replaceChild(frag, orig)

        orig.unlink()

        self.confirm(tuple(dom.documentElement.childNodes) == (c1, c2, c3),

                "replaceChild(<fragment>)")

        frag.unlink()

        dom.unlink()



    def testLegalChildren(self):

        dom = Document()

        elem = dom.createElement('element')

        text = dom.createTextNode('text')

        self.assertRaises(xml.dom.HierarchyRequestErr, dom.appendChild, text)



        dom.appendChild(elem)

        self.assertRaises(xml.dom.HierarchyRequestErr, dom.insertBefore, text,

                          elem)

        self.assertRaises(xml.dom.HierarchyRequestErr, dom.replaceChild, text,

                          elem)



        nodemap = elem.attributes

        self.assertRaises(xml.dom.HierarchyRequestErr, nodemap.setNamedItem,

                          text)

        self.assertRaises(xml.dom.HierarchyRequestErr, nodemap.setNamedItemNS,

                          text)



        elem.appendChild(text)

        dom.unlink()



    def testNamedNodeMapSetItem(self):

        dom = Document()

        elem = dom.createElement('element')

        attrs = elem.attributes

        attrs["foo"] = "bar"

        a = attrs.item(0)

        self.confirm(a.ownerDocument is dom,

                "NamedNodeMap.__setitem__() sets ownerDocument")

        self.confirm(a.ownerElement is elem,

                "NamedNodeMap.__setitem__() sets ownerElement")

        self.confirm(a.value == "bar",

                "NamedNodeMap.__setitem__() sets value")

        self.confirm(a.nodeValue == "bar",

                "NamedNodeMap.__setitem__() sets nodeValue")

        elem.unlink()

        dom.unlink()



    def testNonZero(self):

        dom = parse(tstfile)

        self.confirm(dom)# should not be zero

        dom.appendChild(dom.createComment("foo"))

        self.confirm(not dom.childNodes[-1].childNodes)

        dom.unlink()



    def testUnlink(self):

        dom = parse(tstfile)

        dom.unlink()



    def testElement(self):

        dom = Document()

        dom.appendChild(dom.createElement("abc"))

        self.confirm(dom.documentElement)

        dom.unlink()



    def testAAA(self):

        dom = parseString("<abc/>")

        el = dom.documentElement

        el.setAttribute("spam", "jam2")

        self.confirm(el.toxml() == '<abc spam="jam2"/>', "testAAA")

        a = el.getAttributeNode("spam")

        self.confirm(a.ownerDocument is dom,

                "setAttribute() sets ownerDocument")

        self.confirm(a.ownerElement is dom.documentElement,

                "setAttribute() sets ownerElement")

        dom.unlink()



    def testAAB(self):

        dom = parseString("<abc/>")

        el = dom.documentElement

        el.setAttribute("spam", "jam")

        el.setAttribute("spam", "jam2")

        self.confirm(el.toxml() == '<abc spam="jam2"/>', "testAAB")

        dom.unlink()



    def testAddAttr(self):

        dom = Document()

        child = dom.appendChild(dom.createElement("abc"))



        child.setAttribute("def", "ghi")

        self.confirm(child.getAttribute("def") == "ghi")

        self.confirm(child.attributes["def"].value == "ghi")



        child.setAttribute("jkl", "mno")

        self.confirm(child.getAttribute("jkl") == "mno")

        self.confirm(child.attributes["jkl"].value == "mno")



        self.confirm(len(child.attributes) == 2)



        child.setAttribute("def", "newval")

        self.confirm(child.getAttribute("def") == "newval")

        self.confirm(child.attributes["def"].value == "newval")



        self.confirm(len(child.attributes) == 2)

        dom.unlink()



    def testDeleteAttr(self):

        dom = Document()

        child = dom.appendChild(dom.createElement("abc"))



        self.confirm(len(child.attributes) == 0)

        child.setAttribute("def", "ghi")

        self.confirm(len(child.attributes) == 1)

        del child.attributes["def"]

        self.confirm(len(child.attributes) == 0)

        dom.unlink()



    def testRemoveAttr(self):

        dom = Document()

        child = dom.appendChild(dom.createElement("abc"))



        child.setAttribute("def", "ghi")

        self.confirm(len(child.attributes) == 1)

        child.removeAttribute("def")

        self.confirm(len(child.attributes) == 0)

        dom.unlink()



    def testRemoveAttrNS(self):

        dom = Document()

        child = dom.appendChild(

                dom.createElementNS("http://www.python.org", "python:abc"))

        child.setAttributeNS("http://www.w3.org", "xmlns:python",

                                                "http://www.python.org")

        child.setAttributeNS("http://www.python.org", "python:abcattr", "foo")

        self.confirm(len(child.attributes) == 2)

        child.removeAttributeNS("http://www.python.org", "abcattr")

        self.confirm(len(child.attributes) == 1)

        dom.unlink()



    def testRemoveAttributeNode(self):

        dom = Document()

        child = dom.appendChild(dom.createElement("foo"))

        child.setAttribute("spam", "jam")

        self.confirm(len(child.attributes) == 1)

        node = child.getAttributeNode("spam")

        child.removeAttributeNode(node)

        self.confirm(len(child.attributes) == 0

                and child.getAttributeNode("spam") is None)

        dom.unlink()



    def testChangeAttr(self):

        dom = parseString("<abc/>")

        el = dom.documentElement

        el.setAttribute("spam", "jam")

        self.confirm(len(el.attributes) == 1)

        el.setAttribute("spam", "bam")

        # Set this attribute to be an ID and make sure that doesn't change

        # when changing the value:

        el.setIdAttribute("spam")

        self.confirm(len(el.attributes) == 1

                and el.attributes["spam"].value == "bam"

                and el.attributes["spam"].nodeValue == "bam"

                and el.getAttribute("spam") == "bam"

                and el.getAttributeNode("spam").isId)

        el.attributes["spam"] = "ham"

        self.confirm(len(el.attributes) == 1

                and el.attributes["spam"].value == "ham"

                and el.attributes["spam"].nodeValue == "ham"

                and el.getAttribute("spam") == "ham"

                and el.attributes["spam"].isId)

        el.setAttribute("spam2", "bam")

        self.confirm(len(el.attributes) == 2

                and el.attributes["spam"].value == "ham"

                and el.attributes["spam"].nodeValue == "ham"

                and el.getAttribute("spam") == "ham"

                and el.attributes["spam2"].value == "bam"

                and el.attributes["spam2"].nodeValue == "bam"

                and el.getAttribute("spam2") == "bam")

        el.attributes["spam2"] = "bam2"

        self.confirm(len(el.attributes) == 2

                and el.attributes["spam"].value == "ham"

                and el.attributes["spam"].nodeValue == "ham"

                and el.getAttribute("spam") == "ham"

                and el.attributes["spam2"].value == "bam2"

                and el.attributes["spam2"].nodeValue == "bam2"

                and el.getAttribute("spam2") == "bam2")

        dom.unlink()



    def testGetAttrList(self):

        pass



    def testGetAttrValues(self): pass



    def testGetAttrLength(self): pass



    def testGetAttribute(self): pass



    def testGetAttributeNS(self): pass



    def testGetAttributeNode(self): pass



    def testGetElementsByTagNameNS(self):

        d="""<foo xmlns:minidom='http://pyxml.sf.net/minidom'>

        <minidom:myelem/>

        </foo>"""

        dom = parseString(d)

        elems = dom.getElementsByTagNameNS("http://pyxml.sf.net/minidom",

                                           "myelem")

        self.confirm(len(elems) == 1

                and elems[0].namespaceURI == "http://pyxml.sf.net/minidom"

                and elems[0].localName == "myelem"

                and elems[0].prefix == "minidom"

                and elems[0].tagName == "minidom:myelem"

                and elems[0].nodeName == "minidom:myelem")

        dom.unlink()



    def get_empty_nodelist_from_elements_by_tagName_ns_helper(self, doc, nsuri,

                                                              lname):

        nodelist = doc.getElementsByTagNameNS(nsuri, lname)

        self.confirm(len(nodelist) == 0)



    def testGetEmptyNodeListFromElementsByTagNameNS(self):

        doc = parseString('<doc/>')

        self.get_empty_nodelist_from_elements_by_tagName_ns_helper(

            doc, 'http://xml.python.org/namespaces/a', 'localname')

        self.get_empty_nodelist_from_elements_by_tagName_ns_helper(

            doc, '*', 'splat')

        self.get_empty_nodelist_from_elements_by_tagName_ns_helper(

            doc, 'http://xml.python.org/namespaces/a', '*')



        doc = parseString('<doc xmlns="http://xml.python.org/splat"><e/></doc>')

        self.get_empty_nodelist_from_elements_by_tagName_ns_helper(

            doc, "http://xml.python.org/splat", "not-there")

        self.get_empty_nodelist_from_elements_by_tagName_ns_helper(

            doc, "*", "not-there")

        self.get_empty_nodelist_from_elements_by_tagName_ns_helper(

            doc, "http://somewhere.else.net/not-there", "e")



    def testElementReprAndStr(self):

        dom = Document()

        el = dom.appendChild(dom.createElement("abc"))

        string1 = repr(el)

        string2 = str(el)

        self.confirm(string1 == string2)

        dom.unlink()



    def testElementReprAndStrUnicode(self):

        dom = Document()

        el = dom.appendChild(dom.createElement(u"abc"))

        string1 = repr(el)

        string2 = str(el)

        self.confirm(string1 == string2)

        dom.unlink()



    def testElementReprAndStrUnicodeNS(self):

        dom = Document()

        el = dom.appendChild(

            dom.createElementNS(u"http://www.slashdot.org", u"slash:abc"))

        string1 = repr(el)

        string2 = str(el)

        self.confirm(string1 == string2)

        self.confirm(string1.find("slash:abc") != -1)

        dom.unlink()



    def testAttributeRepr(self):

        dom = Document()

        el = dom.appendChild(dom.createElement(u"abc"))

        node = el.setAttribute("abc", "def")

        self.confirm(str(node) == repr(node))

        dom.unlink()



    def testTextNodeRepr(self): pass



    def testWriteXML(self):

        str = '<?xml version="1.0" ?><a b="c"/>'

        dom = parseString(str)

        domstr = dom.toxml()

        dom.unlink()

        self.confirm(str == domstr)



    def testAltNewline(self):

        str = '<?xml version="1.0" ?>\n<a b="c"/>\n'

        dom = parseString(str)

        domstr = dom.toprettyxml(newl="\r\n")

        dom.unlink()

        self.confirm(domstr == str.replace("\n", "\r\n"))



    def testProcessingInstruction(self):

        dom = parseString('<e><?mypi \t\n data \t\n ?></e>')

        pi = dom.documentElement.firstChild

        self.confirm(pi.target == "mypi"

                and pi.data == "data \t\n "

                and pi.nodeName == "mypi"

                and pi.nodeType == Node.PROCESSING_INSTRUCTION_NODE

                and pi.attributes is None

                and not pi.hasChildNodes()

                and len(pi.childNodes) == 0

                and pi.firstChild is None

                and pi.lastChild is None

                and pi.localName is None

                and pi.namespaceURI == xml.dom.EMPTY_NAMESPACE)



    def testProcessingInstructionRepr(self): pass



    def testTextRepr(self): pass



    def testWriteText(self): pass



    def testDocumentElement(self): pass



    def testTooManyDocumentElements(self):

        doc = parseString("<doc/>")

        elem = doc.createElement("extra")

        # Should raise an exception when adding an extra document element.

        self.assertRaises(xml.dom.HierarchyRequestErr, doc.appendChild, elem)

        elem.unlink()

        doc.unlink()



    def testCreateElementNS(self): pass



    def testCreateAttributeNS(self): pass



    def testParse(self): pass



    def testParseString(self): pass



    def testComment(self): pass



    def testAttrListItem(self): pass



    def testAttrListItems(self): pass



    def testAttrListItemNS(self): pass



    def testAttrListKeys(self): pass



    def testAttrListKeysNS(self): pass



    def testRemoveNamedItem(self):

        doc = parseString("<doc a=''/>")

        e = doc.documentElement

        attrs = e.attributes

        a1 = e.getAttributeNode("a")

        a2 = attrs.removeNamedItem("a")

        self.confirm(a1.isSameNode(a2))

        self.assertRaises(xml.dom.NotFoundErr, attrs.removeNamedItem, "a")



    def testRemoveNamedItemNS(self):

        doc = parseString("<doc xmlns:a='http://xml.python.org/' a:b=''/>")

        e = doc.documentElement

        attrs = e.attributes

        a1 = e.getAttributeNodeNS("http://xml.python.org/", "b")

        a2 = attrs.removeNamedItemNS("http://xml.python.org/", "b")

        self.confirm(a1.isSameNode(a2))

        self.assertRaises(xml.dom.NotFoundErr, attrs.removeNamedItemNS,

                          "http://xml.python.org/", "b")



    def testAttrListValues(self): pass



    def testAttrListLength(self): pass



    def testAttrList__getitem__(self): pass



    def testAttrList__setitem__(self): pass



    def testSetAttrValueandNodeValue(self): pass



    def testParseElement(self): pass



    def testParseAttributes(self): pass



    def testParseElementNamespaces(self): pass



    def testParseAttributeNamespaces(self): pass



    def testParseProcessingInstructions(self): pass



    def testChildNodes(self): pass



    def testFirstChild(self): pass



    def testHasChildNodes(self): pass



    def _testCloneElementCopiesAttributes(self, e1, e2, test):

        attrs1 = e1.attributes

        attrs2 = e2.attributes

        keys1 = attrs1.keys()

        keys2 = attrs2.keys()

        keys1.sort()

        keys2.sort()

        self.confirm(keys1 == keys2, "clone of element has same attribute keys")

        for i in range(len(keys1)):

            a1 = attrs1.item(i)

            a2 = attrs2.item(i)

            self.confirm(a1 is not a2

                    and a1.value == a2.value

                    and a1.nodeValue == a2.nodeValue

                    and a1.namespaceURI == a2.namespaceURI

                    and a1.localName == a2.localName

                    , "clone of attribute node has proper attribute values")

            self.confirm(a2.ownerElement is e2,

                    "clone of attribute node correctly owned")



    def _setupCloneElement(self, deep):

        dom = parseString("<doc attr='value'><foo/></doc>")

        root = dom.documentElement

        clone = root.cloneNode(deep)

        self._testCloneElementCopiesAttributes(

            root, clone, "testCloneElement" + (deep and "Deep" or "Shallow"))

        # mutilate the original so shared data is detected

        root.tagName = root.nodeName = "MODIFIED"

        root.setAttribute("attr", "NEW VALUE")

        root.setAttribute("added", "VALUE")

        return dom, clone



    def testCloneElementShallow(self):

        dom, clone = self._setupCloneElement(0)

        self.confirm(len(clone.childNodes) == 0

                and clone.childNodes.length == 0

                and clone.parentNode is None

                and clone.toxml() == '<doc attr="value"/>'

                , "testCloneElementShallow")

        dom.unlink()



    def testCloneElementDeep(self):

        dom, clone = self._setupCloneElement(1)

        self.confirm(len(clone.childNodes) == 1

                and clone.childNodes.length == 1

                and clone.parentNode is None

                and clone.toxml() == '<doc attr="value"><foo/></doc>'

                , "testCloneElementDeep")

        dom.unlink()



    def testCloneDocumentShallow(self):

        doc = parseString("<?xml version='1.0'?>\n"

                    "<!-- comment -->"

                    "<!DOCTYPE doc [\n"

                    "<!NOTATION notation SYSTEM 'http://xml.python.org/'>\n"

                    "]>\n"

                    "<doc attr='value'/>")

        doc2 = doc.cloneNode(0)

        self.confirm(doc2 is None,

                "testCloneDocumentShallow:"

                " shallow cloning of documents makes no sense!")



    def testCloneDocumentDeep(self):

        doc = parseString("<?xml version='1.0'?>\n"

                    "<!-- comment -->"

                    "<!DOCTYPE doc [\n"

                    "<!NOTATION notation SYSTEM 'http://xml.python.org/'>\n"

                    "]>\n"

                    "<doc attr='value'/>")

        doc2 = doc.cloneNode(1)

        self.confirm(not (doc.isSameNode(doc2) or doc2.isSameNode(doc)),

                "testCloneDocumentDeep: document objects not distinct")

        self.confirm(len(doc.childNodes) == len(doc2.childNodes),

                "testCloneDocumentDeep: wrong number of Document children")

        self.confirm(doc2.documentElement.nodeType == Node.ELEMENT_NODE,

                "testCloneDocumentDeep: documentElement not an ELEMENT_NODE")

        self.confirm(doc2.documentElement.ownerDocument.isSameNode(doc2),

            "testCloneDocumentDeep: documentElement owner is not new document")

        self.confirm(not doc.documentElement.isSameNode(doc2.documentElement),

                "testCloneDocumentDeep: documentElement should not be shared")

        if doc.doctype is not None:

            # check the doctype iff the original DOM maintained it

            self.confirm(doc2.doctype.nodeType == Node.DOCUMENT_TYPE_NODE,

                    "testCloneDocumentDeep: doctype not a DOCUMENT_TYPE_NODE")

            self.confirm(doc2.doctype.ownerDocument.isSameNode(doc2))

            self.confirm(not doc.doctype.isSameNode(doc2.doctype))



    def testCloneDocumentTypeDeepOk(self):

        doctype = create_nonempty_doctype()

        clone = doctype.cloneNode(1)

        self.confirm(clone is not None

                and clone.nodeName == doctype.nodeName

                and clone.name == doctype.name

                and clone.publicId == doctype.publicId

                and clone.systemId == doctype.systemId

                and len(clone.entities) == len(doctype.entities)

                and clone.entities.item(len(clone.entities)) is None

                and len(clone.notations) == len(doctype.notations)

                and clone.notations.item(len(clone.notations)) is None

                and len(clone.childNodes) == 0)

        for i in range(len(doctype.entities)):

            se = doctype.entities.item(i)

            ce = clone.entities.item(i)

            self.confirm((not se.isSameNode(ce))

                    and (not ce.isSameNode(se))

                    and ce.nodeName == se.nodeName

                    and ce.notationName == se.notationName

                    and ce.publicId == se.publicId

                    and ce.systemId == se.systemId

                    and ce.encoding == se.encoding

                    and ce.actualEncoding == se.actualEncoding

                    and ce.version == se.version)

        for i in range(len(doctype.notations)):

            sn = doctype.notations.item(i)

            cn = clone.notations.item(i)

            self.confirm((not sn.isSameNode(cn))

                    and (not cn.isSameNode(sn))

                    and cn.nodeName == sn.nodeName

                    and cn.publicId == sn.publicId

                    and cn.systemId == sn.systemId)



    def testCloneDocumentTypeDeepNotOk(self):

        doc = create_doc_with_doctype()

        clone = doc.doctype.cloneNode(1)

        self.confirm(clone is None, "testCloneDocumentTypeDeepNotOk")



    def testCloneDocumentTypeShallowOk(self):

        doctype = create_nonempty_doctype()

        clone = doctype.cloneNode(0)

        self.confirm(clone is not None

                and clone.nodeName == doctype.nodeName

                and clone.name == doctype.name

                and clone.publicId == doctype.publicId

                and clone.systemId == doctype.systemId

                and len(clone.entities) == 0

                and clone.entities.item(0) is None

                and len(clone.notations) == 0

                and clone.notations.item(0) is None

                and len(clone.childNodes) == 0)



    def testCloneDocumentTypeShallowNotOk(self):

        doc = create_doc_with_doctype()

        clone = doc.doctype.cloneNode(0)

        self.confirm(clone is None, "testCloneDocumentTypeShallowNotOk")



    def check_import_document(self, deep, testName):

        doc1 = parseString("<doc/>")

        doc2 = parseString("<doc/>")

        self.assertRaises(xml.dom.NotSupportedErr, doc1.importNode, doc2, deep)



    def testImportDocumentShallow(self):

        self.check_import_document(0, "testImportDocumentShallow")



    def testImportDocumentDeep(self):

        self.check_import_document(1, "testImportDocumentDeep")



    def testImportDocumentTypeShallow(self):

        src = create_doc_with_doctype()

        target = create_doc_without_doctype()

        self.assertRaises(xml.dom.NotSupportedErr, target.importNode,

                          src.doctype, 0)



    def testImportDocumentTypeDeep(self):

        src = create_doc_with_doctype()

        target = create_doc_without_doctype()

        self.assertRaises(xml.dom.NotSupportedErr, target.importNode,

                          src.doctype, 1)



    # Testing attribute clones uses a helper, and should always be deep,

    # even if the argument to cloneNode is false.

    def check_clone_attribute(self, deep, testName):

        doc = parseString("<doc attr='value'/>")

        attr = doc.documentElement.getAttributeNode("attr")

        self.failIfEqual(attr, None)

        clone = attr.cloneNode(deep)

        self.confirm(not clone.isSameNode(attr))

        self.confirm(not attr.isSameNode(clone))

        self.confirm(clone.ownerElement is None,

                testName + ": ownerElement should be None")

        self.confirm(clone.ownerDocument.isSameNode(attr.ownerDocument),

                testName + ": ownerDocument does not match")

        self.confirm(clone.specified,

                testName + ": cloned attribute must have specified == True")



    def testCloneAttributeShallow(self):

        self.check_clone_attribute(0, "testCloneAttributeShallow")



    def testCloneAttributeDeep(self):

        self.check_clone_attribute(1, "testCloneAttributeDeep")



    def check_clone_pi(self, deep, testName):

        doc = parseString("<?target data?><doc/>")

        pi = doc.firstChild

        self.assertEquals(pi.nodeType, Node.PROCESSING_INSTRUCTION_NODE)

        clone = pi.cloneNode(deep)

        self.confirm(clone.target == pi.target

                and clone.data == pi.data)



    def testClonePIShallow(self):

        self.check_clone_pi(0, "testClonePIShallow")



    def testClonePIDeep(self):

        self.check_clone_pi(1, "testClonePIDeep")



    def testNormalize(self):

        doc = parseString("<doc/>")

        root = doc.documentElement

        root.appendChild(doc.createTextNode("first"))

        root.appendChild(doc.createTextNode("second"))

        self.confirm(len(root.childNodes) == 2

                and root.childNodes.length == 2,

                "testNormalize -- preparation")

        doc.normalize()

        self.confirm(len(root.childNodes) == 1

                and root.childNodes.length == 1

                and root.firstChild is root.lastChild

                and root.firstChild.data == "firstsecond"

                , "testNormalize -- result")

        doc.unlink()



        doc = parseString("<doc/>")

        root = doc.documentElement

        root.appendChild(doc.createTextNode(""))

        doc.normalize()

        self.confirm(len(root.childNodes) == 0

                and root.childNodes.length == 0,

                "testNormalize -- single empty node removed")

        doc.unlink()



    def testBug1433694(self):

        doc = parseString("<o><i/>t</o>")

        node = doc.documentElement

        node.childNodes[1].nodeValue = ""

        node.normalize()

        self.confirm(node.childNodes[-1].nextSibling == None,

                     "Final child's .nextSibling should be None")



    def testSiblings(self):

        doc = parseString("<doc><?pi?>text?<elm/></doc>")

        root = doc.documentElement

        (pi, text, elm) = root.childNodes



        self.confirm(pi.nextSibling is text and

                pi.previousSibling is None and

                text.nextSibling is elm and

                text.previousSibling is pi and

                elm.nextSibling is None and

                elm.previousSibling is text, "testSiblings")



        doc.unlink()



    def testParents(self):

        doc = parseString(

            "<doc><elm1><elm2/><elm2><elm3/></elm2></elm1></doc>")

        root = doc.documentElement

        elm1 = root.childNodes[0]

        (elm2a, elm2b) = elm1.childNodes

        elm3 = elm2b.childNodes[0]



        self.confirm(root.parentNode is doc and

                elm1.parentNode is root and

                elm2a.parentNode is elm1 and

                elm2b.parentNode is elm1 and

                elm3.parentNode is elm2b, "testParents")

        doc.unlink()



    def testNodeListItem(self):

        doc = parseString("<doc><e/><e/></doc>")

        children = doc.childNodes

        docelem = children[0]

        self.confirm(children[0] is children.item(0)

                and children.item(1) is None

                and docelem.childNodes.item(0) is docelem.childNodes[0]

                and docelem.childNodes.item(1) is docelem.childNodes[1]

                and docelem.childNodes.item(0).childNodes.item(0) is None,

                "test NodeList.item()")

        doc.unlink()



    def testSAX2DOM(self):

        from xml.dom import pulldom



        sax2dom = pulldom.SAX2DOM()

        sax2dom.startDocument()

        sax2dom.startElement("doc", {})

        sax2dom.characters("text")

        sax2dom.startElement("subelm", {})

        sax2dom.characters("text")

        sax2dom.endElement("subelm")

        sax2dom.characters("text")

        sax2dom.endElement("doc")

        sax2dom.endDocument()



        doc = sax2dom.document

        root = doc.documentElement

        (text1, elm1, text2) = root.childNodes

        text3 = elm1.childNodes[0]



        self.confirm(text1.previousSibling is None and

                text1.nextSibling is elm1 and

                elm1.previousSibling is text1 and

                elm1.nextSibling is text2 and

                text2.previousSibling is elm1 and

                text2.nextSibling is None and

                text3.previousSibling is None and

                text3.nextSibling is None, "testSAX2DOM - siblings")



        self.confirm(root.parentNode is doc and

                text1.parentNode is root and

                elm1.parentNode is root and

                text2.parentNode is root and

                text3.parentNode is elm1, "testSAX2DOM - parents")

        doc.unlink()



    def testEncodings(self):

        doc = parseString('<foo>&#x20ac;</foo>')

        self.confirm(doc.toxml() == u'<?xml version="1.0" ?><foo>\u20ac</foo>'

                and doc.toxml('utf-8') ==

                '<?xml version="1.0" encoding="utf-8"?><foo>\xe2\x82\xac</foo>'

                and doc.toxml('iso-8859-15') ==

                '<?xml version="1.0" encoding="iso-8859-15"?><foo>\xa4</foo>',

                "testEncodings - encoding EURO SIGN")



        # Verify that character decoding errors throw exceptions instead

        # of crashing

        self.assertRaises(UnicodeDecodeError, parseString,

                '<fran\xe7ais>Comment \xe7a va ? Tr\xe8s bien ?</fran\xe7ais>')



        doc.unlink()



    class UserDataHandler:

        called = 0

        def handle(self, operation, key, data, src, dst):

            dst.setUserData(key, data + 1, self)

            src.setUserData(key, None, None)

            self.called = 1



    def testUserData(self):

        dom = Document()

        n = dom.createElement('e')

        self.confirm(n.getUserData("foo") is None)

        n.setUserData("foo", None, None)

        self.confirm(n.getUserData("foo") is None)

        n.setUserData("foo", 12, 12)

        n.setUserData("bar", 13, 13)

        self.confirm(n.getUserData("foo") == 12)

        self.confirm(n.getUserData("bar") == 13)

        n.setUserData("foo", None, None)

        self.confirm(n.getUserData("foo") is None)

        self.confirm(n.getUserData("bar") == 13)



        handler = self.UserDataHandler()

        n.setUserData("bar", 12, handler)

        c = n.cloneNode(1)

        self.confirm(handler.called

                and n.getUserData("bar") is None

                and c.getUserData("bar") == 13)

        n.unlink()

        c.unlink()

        dom.unlink()



    def checkRenameNodeSharedConstraints(self, doc, node):

        # Make sure illegal NS usage is detected:

        self.assertRaises(xml.dom.NamespaceErr, doc.renameNode, node,

                          "http://xml.python.org/ns", "xmlns:foo")

        doc2 = parseString("<doc/>")

        self.assertRaises(xml.dom.WrongDocumentErr, doc2.renameNode, node,

                          xml.dom.EMPTY_NAMESPACE, "foo")



    def testRenameAttribute(self):

        doc = parseString("<doc a='v'/>")

        elem = doc.documentElement

        attrmap = elem.attributes

        attr = elem.attributes['a']



        # Simple renaming

        attr = doc.renameNode(attr, xml.dom.EMPTY_NAMESPACE, "b")

        self.confirm(attr.name == "b"

                and attr.nodeName == "b"

                and attr.localName is None

                and attr.namespaceURI == xml.dom.EMPTY_NAMESPACE

                and attr.prefix is None

                and attr.value == "v"

                and elem.getAttributeNode("a") is None

                and elem.getAttributeNode("b").isSameNode(attr)

                and attrmap["b"].isSameNode(attr)

                and attr.ownerDocument.isSameNode(doc)

                and attr.ownerElement.isSameNode(elem))



        # Rename to have a namespace, no prefix

        attr = doc.renameNode(attr, "http://xml.python.org/ns", "c")

        self.confirm(attr.name == "c"

                and attr.nodeName == "c"

                and attr.localName == "c"

                and attr.namespaceURI == "http://xml.python.org/ns"

                and attr.prefix is None

                and attr.value == "v"

                and elem.getAttributeNode("a") is None

                and elem.getAttributeNode("b") is None

                and elem.getAttributeNode("c").isSameNode(attr)

                and elem.getAttributeNodeNS(

                    "http://xml.python.org/ns", "c").isSameNode(attr)

                and attrmap["c"].isSameNode(attr)

                and attrmap[("http://xml.python.org/ns", "c")].isSameNode(attr))



        # Rename to have a namespace, with prefix

        attr = doc.renameNode(attr, "http://xml.python.org/ns2", "p:d")

        self.confirm(attr.name == "p:d"

                and attr.nodeName == "p:d"

                and attr.localName == "d"

                and attr.namespaceURI == "http://xml.python.org/ns2"

                and attr.prefix == "p"

                and attr.value == "v"

                and elem.getAttributeNode("a") is None

                and elem.getAttributeNode("b") is None

                and elem.getAttributeNode("c") is None

                and elem.getAttributeNodeNS(

                    "http://xml.python.org/ns", "c") is None

                and elem.getAttributeNode("p:d").isSameNode(attr)

                and elem.getAttributeNodeNS(

                    "http://xml.python.org/ns2", "d").isSameNode(attr)

                and attrmap["p:d"].isSameNode(attr)

                and attrmap[("http://xml.python.org/ns2", "d")].isSameNode(attr))



        # Rename back to a simple non-NS node

        attr = doc.renameNode(attr, xml.dom.EMPTY_NAMESPACE, "e")

        self.confirm(attr.name == "e"

                and attr.nodeName == "e"

                and attr.localName is None

                and attr.namespaceURI == xml.dom.EMPTY_NAMESPACE

                and attr.prefix is None

                and attr.value == "v"

                and elem.getAttributeNode("a") is None

                and elem.getAttributeNode("b") is None

                and elem.getAttributeNode("c") is None

                and elem.getAttributeNode("p:d") is None

                and elem.getAttributeNodeNS(

                    "http://xml.python.org/ns", "c") is None

                and elem.getAttributeNode("e").isSameNode(attr)

                and attrmap["e"].isSameNode(attr))



        self.assertRaises(xml.dom.NamespaceErr, doc.renameNode, attr,

                          "http://xml.python.org/ns", "xmlns")

        self.checkRenameNodeSharedConstraints(doc, attr)

        doc.unlink()



    def testRenameElement(self):

        doc = parseString("<doc/>")

        elem = doc.documentElement



        # Simple renaming

        elem = doc.renameNode(elem, xml.dom.EMPTY_NAMESPACE, "a")

        self.confirm(elem.tagName == "a"

                and elem.nodeName == "a"

                and elem.localName is None

                and elem.namespaceURI == xml.dom.EMPTY_NAMESPACE

                and elem.prefix is None

                and elem.ownerDocument.isSameNode(doc))



        # Rename to have a namespace, no prefix

        elem = doc.renameNode(elem, "http://xml.python.org/ns", "b")

        self.confirm(elem.tagName == "b"

                and elem.nodeName == "b"

                and elem.localName == "b"

                and elem.namespaceURI == "http://xml.python.org/ns"

                and elem.prefix is None

                and elem.ownerDocument.isSameNode(doc))



        # Rename to have a namespace, with prefix

        elem = doc.renameNode(elem, "http://xml.python.org/ns2", "p:c")

        self.confirm(elem.tagName == "p:c"

                and elem.nodeName == "p:c"

                and elem.localName == "c"

                and elem.namespaceURI == "http://xml.python.org/ns2"

                and elem.prefix == "p"

                and elem.ownerDocument.isSameNode(doc))



        # Rename back to a simple non-NS node

        elem = doc.renameNode(elem, xml.dom.EMPTY_NAMESPACE, "d")

        self.confirm(elem.tagName == "d"

                and elem.nodeName == "d"

                and elem.localName is None

                and elem.namespaceURI == xml.dom.EMPTY_NAMESPACE

                and elem.prefix is None

                and elem.ownerDocument.isSameNode(doc))



        self.checkRenameNodeSharedConstraints(doc, elem)

        doc.unlink()



    def testRenameOther(self):

        # We have to create a comment node explicitly since not all DOM

        # builders used with minidom add comments to the DOM.

        doc = xml.dom.minidom.getDOMImplementation().createDocument(

            xml.dom.EMPTY_NAMESPACE, "e", None)

        node = doc.createComment("comment")

        self.assertRaises(xml.dom.NotSupportedErr, doc.renameNode, node,

                          xml.dom.EMPTY_NAMESPACE, "foo")

        doc.unlink()



    def testWholeText(self):

        doc = parseString("<doc>a</doc>")

        elem = doc.documentElement

        text = elem.childNodes[0]

        self.assertEquals(text.nodeType, Node.TEXT_NODE)



        self.checkWholeText(text, "a")

        elem.appendChild(doc.createTextNode("b"))

        self.checkWholeText(text, "ab")

        elem.insertBefore(doc.createCDATASection("c"), text)

        self.checkWholeText(text, "cab")



        # make sure we don't cross other nodes

        splitter = doc.createComment("comment")

        elem.appendChild(splitter)

        text2 = doc.createTextNode("d")

        elem.appendChild(text2)

        self.checkWholeText(text, "cab")

        self.checkWholeText(text2, "d")



        x = doc.createElement("x")

        elem.replaceChild(x, splitter)

        splitter = x

        self.checkWholeText(text, "cab")

        self.checkWholeText(text2, "d")



        x = doc.createProcessingInstruction("y", "z")

        elem.replaceChild(x, splitter)

        splitter = x

        self.checkWholeText(text, "cab")

        self.checkWholeText(text2, "d")



        elem.removeChild(splitter)

        self.checkWholeText(text, "cabd")

        self.checkWholeText(text2, "cabd")



    def testPatch1094164(self):

        doc = parseString("<doc><e/></doc>")

        elem = doc.documentElement

        e = elem.firstChild

        self.confirm(e.parentNode is elem, "Before replaceChild()")

        # Check that replacing a child with itself leaves the tree unchanged

        elem.replaceChild(e, e)

        self.confirm(e.parentNode is elem, "After replaceChild()")



    def testReplaceWholeText(self):

        def setup():

            doc = parseString("<doc>a<e/>d</doc>")

            elem = doc.documentElement

            text1 = elem.firstChild

            text2 = elem.lastChild

            splitter = text1.nextSibling

            elem.insertBefore(doc.createTextNode("b"), splitter)

            elem.insertBefore(doc.createCDATASection("c"), text1)

            return doc, elem, text1, splitter, text2



        doc, elem, text1, splitter, text2 = setup()

        text = text1.replaceWholeText("new content")

        self.checkWholeText(text, "new content")

        self.checkWholeText(text2, "d")

        self.confirm(len(elem.childNodes) == 3)



        doc, elem, text1, splitter, text2 = setup()

        text = text2.replaceWholeText("new content")

        self.checkWholeText(text, "new content")

        self.checkWholeText(text1, "cab")

        self.confirm(len(elem.childNodes) == 5)



        doc, elem, text1, splitter, text2 = setup()

        text = text1.replaceWholeText("")

        self.checkWholeText(text2, "d")

        self.confirm(text is None

                and len(elem.childNodes) == 2)



    def testSchemaType(self):

        doc = parseString(

            "<!DOCTYPE doc [\n"

            "  <!ENTITY e1 SYSTEM 'http://xml.python.org/e1'>\n"

            "  <!ENTITY e2 SYSTEM 'http://xml.python.org/e2'>\n"

            "  <!ATTLIST doc id   ID       #IMPLIED \n"

            "                ref  IDREF    #IMPLIED \n"

            "                refs IDREFS   #IMPLIED \n"

            "                enum (a|b)    #IMPLIED \n"

            "                ent  ENTITY   #IMPLIED \n"

            "                ents ENTITIES #IMPLIED \n"

            "                nm   NMTOKEN  #IMPLIED \n"

            "                nms  NMTOKENS #IMPLIED \n"

            "                text CDATA    #IMPLIED \n"

            "    >\n"

            "]><doc id='name' notid='name' text='splat!' enum='b'"

            "       ref='name' refs='name name' ent='e1' ents='e1 e2'"

            "       nm='123' nms='123 abc' />")

        elem = doc.documentElement

        # We don't want to rely on any specific loader at this point, so

        # just make sure we can get to all the names, and that the

        # DTD-based namespace is right.  The names can vary by loader

        # since each supports a different level of DTD information.

        t = elem.schemaType

        self.confirm(t.name is None

                and t.namespace == xml.dom.EMPTY_NAMESPACE)

        names = "id notid text enum ref refs ent ents nm nms".split()

        for name in names:

            a = elem.getAttributeNode(name)

            t = a.schemaType

            self.confirm(hasattr(t, "name")

                    and t.namespace == xml.dom.EMPTY_NAMESPACE)



    def testSetIdAttribute(self):

        doc = parseString("<doc a1='v' a2='w'/>")

        e = doc.documentElement

        a1 = e.getAttributeNode("a1")

        a2 = e.getAttributeNode("a2")

        self.confirm(doc.getElementById("v") is None

                and not a1.isId

                and not a2.isId)

        e.setIdAttribute("a1")

        self.confirm(e.isSameNode(doc.getElementById("v"))

                and a1.isId

                and not a2.isId)

        e.setIdAttribute("a2")

        self.confirm(e.isSameNode(doc.getElementById("v"))

                and e.isSameNode(doc.getElementById("w"))

                and a1.isId

                and a2.isId)

        # replace the a1 node; the new node should *not* be an ID

        a3 = doc.createAttribute("a1")

        a3.value = "v"

        e.setAttributeNode(a3)

        self.confirm(doc.getElementById("v") is None

                and e.isSameNode(doc.getElementById("w"))

                and not a1.isId

                and a2.isId

                and not a3.isId)

        # renaming an attribute should not affect its ID-ness:

        doc.renameNode(a2, xml.dom.EMPTY_NAMESPACE, "an")

        self.confirm(e.isSameNode(doc.getElementById("w"))

                and a2.isId)



    def testSetIdAttributeNS(self):

        NS1 = "http://xml.python.org/ns1"

        NS2 = "http://xml.python.org/ns2"

        doc = parseString("<doc"

                          " xmlns:ns1='" + NS1 + "'"

                          " xmlns:ns2='" + NS2 + "'"

                          " ns1:a1='v' ns2:a2='w'/>")

        e = doc.documentElement

        a1 = e.getAttributeNodeNS(NS1, "a1")

        a2 = e.getAttributeNodeNS(NS2, "a2")

        self.confirm(doc.getElementById("v") is None

                and not a1.isId

                and not a2.isId)

        e.setIdAttributeNS(NS1, "a1")

        self.confirm(e.isSameNode(doc.getElementById("v"))

                and a1.isId

                and not a2.isId)

        e.setIdAttributeNS(NS2, "a2")

        self.confirm(e.isSameNode(doc.getElementById("v"))

                and e.isSameNode(doc.getElementById("w"))

                and a1.isId

                and a2.isId)

        # replace the a1 node; the new node should *not* be an ID

        a3 = doc.createAttributeNS(NS1, "a1")

        a3.value = "v"

        e.setAttributeNode(a3)

        self.confirm(e.isSameNode(doc.getElementById("w")))

        self.confirm(not a1.isId)

        self.confirm(a2.isId)

        self.confirm(not a3.isId)

        self.confirm(doc.getElementById("v") is None)

        # renaming an attribute should not affect its ID-ness:

        doc.renameNode(a2, xml.dom.EMPTY_NAMESPACE, "an")

        self.confirm(e.isSameNode(doc.getElementById("w"))

                and a2.isId)



    def testSetIdAttributeNode(self):

        NS1 = "http://xml.python.org/ns1"

        NS2 = "http://xml.python.org/ns2"

        doc = parseString("<doc"

                          " xmlns:ns1='" + NS1 + "'"

                          " xmlns:ns2='" + NS2 + "'"

                          " ns1:a1='v' ns2:a2='w'/>")

        e = doc.documentElement

        a1 = e.getAttributeNodeNS(NS1, "a1")

        a2 = e.getAttributeNodeNS(NS2, "a2")

        self.confirm(doc.getElementById("v") is None

                and not a1.isId

                and not a2.isId)

        e.setIdAttributeNode(a1)

        self.confirm(e.isSameNode(doc.getElementById("v"))

                and a1.isId

                and not a2.isId)

        e.setIdAttributeNode(a2)

        self.confirm(e.isSameNode(doc.getElementById("v"))

                and e.isSameNode(doc.getElementById("w"))

                and a1.isId

                and a2.isId)

        # replace the a1 node; the new node should *not* be an ID

        a3 = doc.createAttributeNS(NS1, "a1")

        a3.value = "v"

        e.setAttributeNode(a3)

        self.confirm(e.isSameNode(doc.getElementById("w")))

        self.confirm(not a1.isId)

        self.confirm(a2.isId)

        self.confirm(not a3.isId)

        self.confirm(doc.getElementById("v") is None)

        # renaming an attribute should not affect its ID-ness:

        doc.renameNode(a2, xml.dom.EMPTY_NAMESPACE, "an")

        self.confirm(e.isSameNode(doc.getElementById("w"))

                and a2.isId)



    def testPickledDocument(self):

        doc = parseString("<?xml version='1.0' encoding='us-ascii'?>\n"

                    "<!DOCTYPE doc PUBLIC 'http://xml.python.org/public'"

                    " 'http://xml.python.org/system' [\n"

                    "  <!ELEMENT e EMPTY>\n"

                    "  <!ENTITY ent SYSTEM 'http://xml.python.org/entity'>\n"

                    "]><doc attr='value'> text\n"

                    "<?pi sample?> <!-- comment --> <e/> </doc>")

        s = pickle.dumps(doc)

        doc2 = pickle.loads(s)

        stack = [(doc, doc2)]

        while stack:

            n1, n2 = stack.pop()

            self.confirm(n1.nodeType == n2.nodeType

                    and len(n1.childNodes) == len(n2.childNodes)

                    and n1.nodeName == n2.nodeName

                    and not n1.isSameNode(n2)

                    and not n2.isSameNode(n1))

            if n1.nodeType == Node.DOCUMENT_TYPE_NODE:

                len(n1.entities)

                len(n2.entities)

                len(n1.notations)

                len(n2.notations)

                self.confirm(len(n1.entities) == len(n2.entities)

                        and len(n1.notations) == len(n2.notations))

                for i in range(len(n1.notations)):

                    no1 = n1.notations.item(i)

                    no2 = n1.notations.item(i)

                    self.confirm(no1.name == no2.name

                            and no1.publicId == no2.publicId

                            and no1.systemId == no2.systemId)

                    statck.append((no1, no2))

                for i in range(len(n1.entities)):

                    e1 = n1.entities.item(i)

                    e2 = n2.entities.item(i)

                    self.confirm(e1.notationName == e2.notationName

                            and e1.publicId == e2.publicId

                            and e1.systemId == e2.systemId)

                    stack.append((e1, e2))

            if n1.nodeType != Node.DOCUMENT_NODE:

                self.confirm(n1.ownerDocument.isSameNode(doc)

                        and n2.ownerDocument.isSameNode(doc2))

            for i in range(len(n1.childNodes)):

                stack.append((n1.childNodes[i], n2.childNodes[i]))



    def testSerializeCommentNodeWithDoubleHyphen(self):

        doc = create_doc_without_doctype()

        doc.appendChild(doc.createComment("foo--bar"))

        self.assertRaises(ValueError, doc.toxml)



def test_main():

    run_unittest(MinidomTest)



if __name__ == "__main__":

    test_main()

