"""Tests of the extended features of xml.dom.expatbuilder."""
import os
import pprint
import unittest
from cStringIO import StringIO
from xml.dom import XMLNS_NAMESPACE
from xml.dom import xmlbuilder
INTERNAL_SUBSET = ("\n"
"")
DOCUMENT_SOURCE = (
'
''')
class Tests(unittest.TestCase):
def setUp(self):
self.builder = xmlbuilder.DOMBuilder()
def makeSource(self, text):
source = xmlbuilder.DOMInputSource()
source.byteStream = StringIO(text)
return source
def check_attrs(self, atts, expected):
self.assertEqual(atts.length, len(expected))
info = atts.itemsNS()
info.sort()
if info != expected:
self.fail("bad attribute information:\n" + pprint.pformat(info))
def run_checks(self, attributes):
document = self.builder.parse(self.makeSource(DOCUMENT_SOURCE))
self.assertEqual(document.doctype.internalSubset, INTERNAL_SUBSET)
self.assertEqual(document.doctype.entities.length, 1,
"entity not stored in doctype")
node = document.doctype.entities['e']
self.assert_(node.notationName is None)
self.assert_(node.publicId is None)
self.assertEqual(node.systemId, 'http://xml.python.org/entity/e')
self.assertEqual(document.doctype.notations.length, 1)
node = document.doctype.notations['x']
self.assert_(node.publicId is None)
self.assertEqual(node.systemId, 'http://xml.python.org/notation/x')
self.check_attrs(document.documentElement.attributes, attributes)
def test_namespace_decls_on(self):
self.builder.setFeature("namespace_declarations", 1)
self.run_checks(#((nsuri, localName), value),
[((XMLNS_NAMESPACE, "A"), "http://xml.python.org/a"),
((XMLNS_NAMESPACE, "a"), "http://xml.python.org/a"),
((XMLNS_NAMESPACE, "b"), "http://xml.python.org/b"),
(("http://xml.python.org/a", "a"), "a"),
(("http://xml.python.org/b", "b"), "b"),
])
def test_namespace_decls_off(self):
self.builder.setFeature("namespace_declarations", 0)
self.run_checks(#((nsuri, localName), value),
[(("http://xml.python.org/a", "a"), "a"),
(("http://xml.python.org/b", "b"), "b"),
])
def test_get_element_by_id(self):
ID_PREFIX = " ]>"
doc = self.builder.parse(self.makeSource(
ID_PREFIX + ""))
self.assert_(doc.getElementById("bar") is None,
"received unexpected node")
self.assertEqual(doc.getElementById("foo").nodeName, "e",
"did not get expected node")
# Check an implementation detail; this is testing the
# ID-caching behavior.
self.assert_(doc._id_cache.has_key("foo"))
# make sure adding an element with an ID works
e = doc.createElement("e")
e.setAttribute("id", "new")
doc.documentElement.appendChild(e)
self.assert_(e.isSameNode(doc.getElementById("new")))
# make sure the cache doesn't cause false hits when we remove nodes
doc.documentElement.removeChild(e)
self.assert_(e.parentNode is None)
self.assert_(doc.getElementById("new") is None)
# now add the node back, make sure we can still get it by id,
# the change the value of the id attribute and check that it's
# returned only for the new ID
doc.documentElement.appendChild(e)
self.assert_(e.isSameNode(doc.getElementById("new")))
a = e.getAttributeNode("id")
a.value = "no-longer-new"
self.assert_(doc.getElementById("new") is None)
self.assert_(e.isSameNode(doc.getElementById("no-longer-new")))
# make sure removing the attribute makes the ID lookup return None:
e.removeAttributeNode(a)
self.assertEqual(e.getAttribute("id"), "")
self.assert_(doc.getElementById("no-longer-new") is None)
# check that modifying e.attributes works as well
attrs = e.attributes
e.setAttributeNode(a)
self.assert_(e.isSameNode(doc.getElementById("no-longer-new")))
attrs.removeNamedItem("id")
self.assert_(doc.getElementById("no-longer-new") is None)
a2 = doc.createAttribute("id")
a2.value = "alternate-id"
attrs.setNamedItem(a)
self.assert_(e.isSameNode(doc.getElementById("no-longer-new")))
attrs.setNamedItem(a2)
self.assert_(doc.getElementById("no-longer-new") is None)
self.assert_(e.isSameNode(doc.getElementById("alternate-id")))
# make sure nodes with an ID in a fragment are not located.
f = doc.createDocumentFragment()
e = doc.createElement("e")
e.setAttribute("id", "in-fragment")
f.appendChild(e)
self.assert_(doc.getElementById("in-fragment") is None)
doc = self.builder.parse(self.makeSource(
ID_PREFIX + ""))
self.assertEqual(doc.getElementById("foo").nodeName, "e",
"did not get expected node")
doc = self.builder.parse(self.makeSource(
ID_PREFIX + (""
"")))
self.assertEqual(doc.getElementById("foo").getAttribute("name"), "a",
"did not get expected node")
def test_whitespace_in_element_content(self):
DTD_PREFIX = " ]>"
doc = self.builder.parse(self.makeSource(
DTD_PREFIX + (" ")))
docelem = doc.documentElement
e1, e2 = docelem.getElementsByTagName("e")
ws1 = docelem.firstChild
ws2 = e2.firstChild
# test WS in element content
self.assert_(ws1.isWhitespaceInElementContent)
ws1.appendData("not-white")
self.assert_(not ws1.isWhitespaceInElementContent)
ws1.replaceData(0, len(ws1.data), " ")
self.assert_(ws1.isWhitespaceInElementContent)
ws1.replaceData(0, len(ws1.data), "not-white")
self.assert_(not ws1.isWhitespaceInElementContent)
ws1.data = " "
self.assert_(ws1.isWhitespaceInElementContent)
# test WS not in element content
self.assert_(not ws2.isWhitespaceInElementContent)
ws2.appendData("not-white")
self.assert_(not ws2.isWhitespaceInElementContent)
ws2.replaceData(0, len(ws2.data), " ")
self.assert_(not ws2.isWhitespaceInElementContent)
ws2.replaceData(0, len(ws2.data), "not-white")
self.assert_(not ws2.isWhitespaceInElementContent)
ws2.data = " "
self.assert_(not ws2.isWhitespaceInElementContent)
def check_resolver(self, content_type, encoding):
resolver = TestingResolver(content_type)
source = resolver.resolveEntity(None, DUMMY_URL)
self.assertEqual(source.encoding, encoding,
"wrong encoding; expected %s, got %s"
% (repr(encoding), repr(source.encoding)))
def test_entity_resolver_encodings(self):
self.check_resolver((None, None, []), None)
self.check_resolver(("text", "plain", []), None)
self.check_resolver(("text", "plain", ["charset=iso-8859-1"]),
"iso-8859-1")
self.check_resolver(("text", "plain", ["charset=UTF-8"]), "utf-8")
def test_internal_subset_isolation(self):
document = self.builder.parse(self.makeSource(
" "
"]>"
))
s = document.toxml()
self.assertEqual(s,
'\n'
' '
']>\n'
'')
def test_document_prolog_in_order(self):
source = self.makeSource(
"\n"
"\n"
"\n"
"")
document = self.builder.parse(source)
s = document.toxml()
self.assertEqual(s,
'\n'
''
'\n'
''
'')
def test_docelem_has_namespace(self):
source = self.makeSource(
"abcdef")
document = self.builder.parse(source)
self.assertEqual(document.documentElement.namespaceURI,
'http://xml.python.org/namespace/x')
def test_isId(self):
source = self.makeSource(
"\n"
"]>")
document = self.builder.parse(source)
elem = document.documentElement
a1 = elem.getAttributeNode("id")
a2 = elem.getAttributeNode("notid")
self.failUnless(a1.isId)
self.failIf(a2.isId)
def test_schemaType(self):
source = self.makeSource(
"\n"
" \n"
" \n"
"]>")
document = self.builder.parse(source)
elem = document.documentElement
t = elem.schemaType
self.assert_(t.name is None)
self.assert_(t.namespace is None)
check_attr = self.check_attr_schemaType
check_attr(elem, "id", "id")
check_attr(elem, "notid", None)
check_attr(elem, "enum", "enumeration")
check_attr(elem, "ent", "entity")
check_attr(elem, "ents", "entities")
check_attr(elem, "ref", "idref")
check_attr(elem, "refs", "idrefs")
check_attr(elem, "text", "cdata")
def check_attr_schemaType(self, elem, attrname, name):
a = elem.getAttributeNode(attrname)
t = a.schemaType
self.assert_(t.namespace is None)
self.assertEqual(t.name, name)
DUMMY_URL = "http://xml.python.org/dummy.xml"
class TestingResolver(xmlbuilder.DOMEntityResolver):
def __init__(self, content_type):
self._content_type = content_type
def _create_opener(self):
return FakeOpener(self._content_type)
if os.name == "nt":
NULLFILE = "nul"
else:
NULLFILE = "/dev/null"
class FakeOpener:
def __init__(self, content_type):
self._content_type = content_type
def open(self, url):
if url != DUMMY_URL:
raise ValueError, "unexpected URL: " + repr(url)
return FakeFile(open(NULLFILE, "rb"), self._content_type)
class FakeFile:
def __init__(self, file, content_type):
self._file = file
self._content_type = content_type
def info(self):
return FakeMessage(self._content_type)
def __getattr__(self, name):
return getattr(self._file, name)
class FakeMessage:
def __init__(self, content_type):
self._maintype, self._subtype, self._plist = content_type
def has_key(self, name):
name = name.lower()
if name != "content-type":
raise ValueError, "unexpected has_key(%s)" % repr(name)
return self._maintype is not None
def getplist(self):
return self._plist
def getmaintype(self):
return self._maintype or "text"
def getsubtype(self):
return self._subtype or "plain"
def gettype(self):
return "%s/%s" % (self.getmaintype(), self.getsubtype())
def test_suite():
return unittest.makeSuite(Tests)
def test_main():
import test_support
test_support.run_suite(test_suite())
if __name__ == "__main__":
import test_support
test_support.verbose = 1
test_main()