&", "<() />"]:
self.assertRaises(Exception, microdom.parseString, s)
def test_caseInsensitive(self) -> None:
s = "x"
s2 = 'x'
s3 = "x"
s4 = "x"
d = microdom.parseString(s)
d2 = microdom.parseString(s2)
d3 = microdom.parseString(s3, caseInsensitive=1)
d4 = microdom.parseString(s4, caseInsensitive=1, preserveCase=1)
d5 = microdom.parseString(s4, caseInsensitive=1, preserveCase=0)
d6 = microdom.parseString(s4, caseInsensitive=0, preserveCase=0)
out = microdom.parseString(s).documentElement.toxml()
self.assertRaises(
microdom.MismatchedTags, microdom.parseString, s, caseInsensitive=0
)
self.assertEqual(out, s2)
self.assertTrue(d.isEqualToDocument(d2))
self.assertTrue(d.isEqualToDocument(d3))
self.assertTrue(d4.documentElement.hasAttribute("a"))
self.assertFalse(d6.documentElement.hasAttribute("a"))
self.assertEqual(d4.documentElement.toxml(), 'x')
self.assertEqual(d5.documentElement.toxml(), 'x')
def test_eatingWhitespace(self) -> None:
s = """
"""
d = microdom.parseString(s)
self.assertTrue(
not d.documentElement.hasChildNodes(), d.documentElement.childNodes
)
self.assertTrue(d.isEqualToDocument(microdom.parseString("")))
def test_lenientAmpersand(self) -> None:
prefix = ""
# we use so space will be preserved
for i, o in [
("&", "&"),
("& ", "& "),
("&", "&"),
("&hello monkey", "&hello monkey"),
]:
d = microdom.parseString(f"{prefix}{i}
", beExtremelyLenient=1)
self.assertEqual(d.documentElement.toxml(), "%s
" % o)
# non-space preserving
d = microdom.parseString("hello & there", beExtremelyLenient=1)
self.assertEqual(d.documentElement.toxml(), "hello & there")
def test_insensitiveLenient(self) -> None:
# testing issue #537
d = microdom.parseString(
"c ", beExtremelyLenient=1
)
self.assertEqual(d.documentElement.firstChild().toxml(), "c")
def test_laterCloserSimple(self) -> None:
s = "
"
d = microdom.parseString(s, beExtremelyLenient=1)
expected = ""
actual = d.documentElement.toxml()
self.assertEqual(expected, actual)
def test_laterCloserCaseInsensitive(self) -> None:
s = "- foo
- bar
"
d = microdom.parseString(s, beExtremelyLenient=1)
expected = "- foo
- bar
"
actual = d.documentElement.toxml()
self.assertEqual(expected, actual)
def test_laterCloserDL(self) -> None:
s = (
""
"- word
- definition"
"
- word
- word
- definition
- definition"
"
"
)
expected = (
""
"- word
- definition
"
"- word
- word
- definition
- definition
"
"
"
)
d = microdom.parseString(s, beExtremelyLenient=1)
actual = d.documentElement.toxml()
self.assertEqual(expected, actual)
def test_unicodeTolerance(self) -> None:
import struct
s = ""
j = (
'\r\n\r\n'
"\u5c02\u9580\u5bb6\u30ea\u30b9\u30c8 "
)
j2 = (
b"\xff\xfe<\x00?\x00x\x00m\x00l\x00 \x00v\x00e\x00r\x00s\x00i\x00o"
b'\x00n\x00=\x00"\x001\x00.\x000\x00"\x00 \x00e\x00n\x00c\x00o\x00d'
b'\x00i\x00n\x00g\x00=\x00"\x00U\x00C\x00S\x00-\x002\x00"\x00 \x00?'
b"\x00>\x00\r\x00\n\x00<\x00J\x00A\x00P\x00A\x00N\x00E\x00S\x00E"
b"\x00>\x00\r\x00\n\x00<\x00T\x00I\x00T\x00L\x00E\x00>\x00\x02\\"
b"\x80\x95\xb6[\xea0\xb90\xc80 \x00<\x00/\x00T\x00I\x00T\x00L\x00E"
b"\x00>\x00<\x00/\x00J\x00A\x00P\x00A\x00N\x00E\x00S\x00E\x00>\x00"
)
def reverseBytes(s: bytes) -> bytes:
fmt = str(len(s) // 2) + "H"
return struct.pack("<" + fmt, *struct.unpack(">" + fmt, s))
urd = microdom.parseString(reverseBytes(s.encode("UTF-16")))
ud = microdom.parseString(s.encode("UTF-16"))
sd = microdom.parseString(s)
self.assertTrue(ud.isEqualToDocument(sd))
self.assertTrue(ud.isEqualToDocument(urd))
ud = microdom.parseString(j)
urd = microdom.parseString(reverseBytes(j2))
sd = microdom.parseString(j2)
self.assertTrue(ud.isEqualToDocument(sd))
self.assertTrue(ud.isEqualToDocument(urd))
# test that raw text still gets encoded
# test that comments get encoded
j3 = microdom.parseString("")
hdr = ''
div = microdom.lmx().text("\u221a", raw=1).node
de = j3.documentElement
de.appendChild(div)
de.appendChild(j3.createComment("\u221a"))
self.assertEqual(
j3.toxml(), (hdr + "\u221a
")
)
def test_namedChildren(self) -> None:
tests = {
"asdfadsf" "": 3,
"asdf": 0,
"": 1,
}
for t in tests.keys():
node = microdom.parseString(t).documentElement
result = domhelpers.namedChildren(node, "bar")
self.assertEqual(len(result), tests[t])
if result:
self.assertTrue(hasattr(result[0], "tagName"))
def test_cloneNode(self) -> None:
s = 'x'
node = microdom.parseString(s).documentElement
clone = node.cloneNode(deep=1)
self.failIfEquals(node, clone)
self.assertEqual(len(node.childNodes), len(clone.childNodes))
c1, c2 = node.firstChild(), clone.firstChild()
self.failIfEquals(c1, c2)
self.assertEqual(len(c1.childNodes), len(c2.childNodes))
self.failIfEquals(c1.firstChild(), c2.firstChild())
self.assertEqual(s, clone.toxml())
self.assertEqual(node.namespace, clone.namespace)
def test_cloneDocument(self) -> None:
s = (
''
''
)
node = microdom.parseString(s)
clone = node.cloneNode(deep=1)
self.failIfEquals(node, clone)
self.assertEqual(len(node.childNodes), len(clone.childNodes))
self.assertEqual(s, clone.toxml())
self.assertTrue(clone.isEqualToDocument(node))
self.assertTrue(node.isEqualToDocument(clone))
def test_LMX(self) -> None:
n = microdom.Element("p")
lmx = microdom.lmx(n)
lmx.text("foo")
b = lmx.b(a="c")
b.foo()["z"] = "foo"
b.foo()
b.add("bar", c="y")
s = 'foo
'
self.assertEqual(s, n.toxml())
def test_dict(self) -> None:
"""
Returns a dictionary which is hashable.
"""
n = microdom.Element("p")
hash(n)
def test_escaping(self) -> None:
# issue 590
raw = "&'some \"stuff\"', "
cooked = "&'some "stuff"', <what up?>"
esc1 = microdom.escape(raw)
self.assertEqual(esc1, cooked)
self.assertEqual(microdom.unescape(esc1), raw)
def test_namespaces(self) -> None:
s = """
here is some space
"""
d = microdom.parseString(s)
# at least make sure it doesn't traceback
s2 = d.toprettyxml()
self.assertEqual(d.documentElement.namespace, "base")
self.assertEqual(
d.documentElement.getElementsByTagName("y")[0].namespace, "base"
)
self.assertEqual(
d.documentElement.getElementsByTagName("y")[1].getAttributeNS("base", "q"),
"1",
)
d2 = microdom.parseString(s2)
self.assertEqual(d2.documentElement.namespace, "base")
self.assertEqual(
d2.documentElement.getElementsByTagName("y")[0].namespace, "base"
)
self.assertEqual(
d2.documentElement.getElementsByTagName("y")[1].getAttributeNS("base", "q"),
"1",
)
def test_namespaceDelete(self) -> None:
"""
Test that C{toxml} can support xml structures that remove namespaces.
"""
s1 = (
''
''
)
s2 = microdom.parseString(s1).toxml()
self.assertEqual(s1, s2)
def test_namespaceInheritance(self) -> None:
"""
Check that unspecified namespace is a thing separate from undefined
namespace. This test added after discovering some weirdness in Lore.
"""
# will only work if childNodes is mutated. not sure why.
child = microdom.Element("ol")
parent = microdom.Element("div", namespace="http://www.w3.org/1999/xhtml")
parent.childNodes = [child]
self.assertEqual(
parent.toxml(), ''
)
def test_prefixedTags(self) -> None:
"""
XML elements with a prefixed name as per upper level tag definition
have a start-tag of C{""} and an end-tag of
C{""}.
Refer to U{http://www.w3.org/TR/xml-names/#ns-using} for details.
"""
outerNamespace = "http://example.com/outer"
innerNamespace = "http://example.com/inner"
document = microdom.Document()
# Create the root in one namespace. Microdom will probably make this
# the default namespace.
root = document.createElement("root", namespace=outerNamespace)
# Give the root some prefixes to use.
root.addPrefixes({innerNamespace: "inner"})
# Append a child to the root from the namespace that prefix is bound
# to.
tag = document.createElement("tag", namespace=innerNamespace)
# Give that tag a child too. This way we test rendering of tags with
# children and without children.
child = document.createElement("child", namespace=innerNamespace)
tag.appendChild(child)
root.appendChild(tag)
document.appendChild(root)
# ok, the xml should appear like this
xmlOk = (
''
''
""
""
)
xmlOut = document.toxml()
self.assertEqual(xmlOut, xmlOk)
def test_prefixPropagation(self) -> None:
"""
Children of prefixed tags respect the default namespace at the point
where they are rendered. Specifically, they are not influenced by the
prefix of their parent as that prefix has no bearing on them.
See U{http://www.w3.org/TR/xml-names/#scoping} for details.
To further clarify the matter, the following::
Should become this after all the namespace declarations have been
I{moved up}::
"""
outerNamespace = "http://example.com/outer"
innerNamespace = "http://example.com/inner"
document = microdom.Document()
# creates a root element
root = document.createElement("root", namespace=outerNamespace)
document.appendChild(root)
# Create a child with a specific namespace with a prefix bound to it.
root.addPrefixes({innerNamespace: "inner"})
mytag = document.createElement("mytag", namespace=innerNamespace)
root.appendChild(mytag)
# Create a child of that which has the outer namespace.
mysubtag = document.createElement("mysubtag", namespace=outerNamespace)
mytag.appendChild(mysubtag)
xmlOk = (
''
''
""
""
""
""
)
xmlOut = document.toxml()
self.assertEqual(xmlOut, xmlOk)
def test_deprecation(self) -> None:
"""
An import will raise the deprecation warning.
"""
reload(microdom)
warnings = self.flushWarnings([self.test_deprecation])
self.assertEqual(1, len(warnings))
self.assertEqual(
"twisted.web.microdom was deprecated at Twisted 23.10.0",
warnings[0]["message"],
)
class BrokenHTMLTests(TestCase):
"""
Tests for when microdom encounters very bad HTML and C{beExtremelyLenient}
is enabled. These tests are inspired by some HTML generated in by a mailer,
which breaks up very long lines by splitting them with '!\\n '.
The expected behaviour is loosely modelled on the way Firefox treats very
bad HTML.
"""
def checkParsed(
self, input: str, expected: str, beExtremelyLenient: int = 1
) -> None:
"""
Check that C{input}, when parsed, produces a DOM where the XML
of the document element is equal to C{expected}.
"""
output = microdom.parseString(input, beExtremelyLenient=beExtremelyLenient)
self.assertEqual(output.documentElement.toxml(), expected)
def test_brokenAttributeName(self) -> None:
"""
Check that microdom does its best to handle broken attribute names.
The important thing is that it doesn't raise an exception.
"""
input = 'Foo
'
expected = '' "Foo
"
self.checkParsed(input, expected)
def test_brokenAttributeValue(self) -> None:
"""
Check that microdom encompasses broken attribute values.
"""
input = 'Foo
'
expected = 'Foo
'
self.checkParsed(input, expected)
def test_brokenOpeningTag(self) -> None:
"""
Check that microdom does its best to handle broken opening tags.
The important thing is that it doesn't raise an exception.
"""
input = "Hello World!
"
expected = 'Hello World!
'
self.checkParsed(input, expected)
def test_brokenSelfClosingTag(self) -> None:
"""
Check that microdom does its best to handle broken self-closing tags
The important thing is that it doesn't raise an exception.
"""
self.checkParsed("", "")
self.checkParsed("", "")
def test_brokenClosingTag(self) -> None:
"""
Check that microdom does its best to handle broken closing tags.
The important thing is that it doesn't raise an exception.
"""
input = "Hello World!
"
expected = "Hello World!
"
self.checkParsed(input, expected)
input = "Hello World!!\nspan>
"
self.checkParsed(input, expected)
input = "Hello World!
"
self.checkParsed(input, expected)
input = "Hello World!
"
expected = "Hello World!!>
"
self.checkParsed(input, expected)
class NodeTests(TestCase):
"""
Tests for L{Node}.
"""
def test_isNodeEqualTo(self) -> None:
"""
L{Node.isEqualToNode} returns C{True} if and only if passed a L{Node}
with the same children.
"""
# A node is equal to itself
node = microdom.Node(object())
self.assertTrue(node.isEqualToNode(node))
another = microdom.Node(object())
# Two nodes with no children are equal
self.assertTrue(node.isEqualToNode(another))
node.appendChild(microdom.Node(object()))
# A node with no children is not equal to a node with a child
self.assertFalse(node.isEqualToNode(another))
another.appendChild(microdom.Node(object()))
# A node with a child and no grandchildren is equal to another node
# with a child and no grandchildren.
self.assertTrue(node.isEqualToNode(another))
# A node with a child and a grandchild is not equal to another node
# with a child and no grandchildren.
node.firstChild().appendChild(microdom.Node(object()))
self.assertFalse(node.isEqualToNode(another))
# A node with a child and a grandchild is equal to another node with a
# child and a grandchild.
another.firstChild().appendChild(microdom.Node(object()))
self.assertTrue(node.isEqualToNode(another))
def test_validChildInstance(self) -> None:
"""
Children of L{Node} instances must also be L{Node} instances.
"""
node = microdom.Node()
child = microdom.Node()
# Node.appendChild() only accepts Node instances.
node.appendChild(child)
self.assertRaises(TypeError, node.appendChild, None)
# Node.insertBefore() only accepts Node instances.
self.assertRaises(TypeError, node.insertBefore, child, None)
self.assertRaises(TypeError, node.insertBefore, None, child)
self.assertRaises(TypeError, node.insertBefore, None, None)
# Node.removeChild() only accepts Node instances.
node.removeChild(child)
self.assertRaises(TypeError, node.removeChild, None)
# Node.replaceChild() only accepts Node instances.
self.assertRaises(TypeError, node.replaceChild, child, None)
self.assertRaises(TypeError, node.replaceChild, None, child)
self.assertRaises(TypeError, node.replaceChild, None, None)
class DocumentTests(TestCase):
"""
Tests for L{Document}.
"""
doctype = 'foo PUBLIC "baz" "http://www.example.com/example.dtd"'
def test_isEqualToNode(self) -> None:
"""
L{Document.isEqualToNode} returns C{True} if and only if passed a
L{Document} with the same C{doctype} and C{documentElement}.
"""
# A document is equal to itself
document = microdom.Document()
self.assertTrue(document.isEqualToNode(document))
# A document without a doctype or documentElement is equal to another
# document without a doctype or documentElement.
another = microdom.Document()
self.assertTrue(document.isEqualToNode(another))
# A document with a doctype is not equal to a document without a
# doctype.
document.doctype = self.doctype
self.assertFalse(document.isEqualToNode(another))
# Two documents with the same doctype are equal
another.doctype = self.doctype
self.assertTrue(document.isEqualToNode(another))
# A document with a documentElement is not equal to a document without
# a documentElement
document.appendChild(microdom.Node(object()))
self.assertFalse(document.isEqualToNode(another))
# Two documents with equal documentElements are equal.
another.appendChild(microdom.Node(object()))
self.assertTrue(document.isEqualToNode(another))
# Two documents with documentElements which are not equal are not
# equal.
document.documentElement.appendChild(microdom.Node(object()))
self.assertFalse(document.isEqualToNode(another))
def test_childRestriction(self) -> None:
"""
L{Document.appendChild} raises L{ValueError} if the document already
has a child.
"""
document = microdom.Document()
child = microdom.Node()
another = microdom.Node()
document.appendChild(child)
self.assertRaises(ValueError, document.appendChild, another)
class EntityReferenceTests(TestCase):
"""
Tests for L{EntityReference}.
"""
def test_isEqualToNode(self) -> None:
"""
L{EntityReference.isEqualToNode} returns C{True} if and only if passed
a L{EntityReference} with the same C{eref}.
"""
self.assertTrue(
microdom.EntityReference("quot").isEqualToNode(
microdom.EntityReference("quot")
)
)
self.assertFalse(
microdom.EntityReference("quot").isEqualToNode(
microdom.EntityReference("apos")
)
)
class CharacterDataTests(TestCase):
"""
Tests for L{CharacterData}.
"""
def test_isEqualToNode(self) -> None:
"""
L{CharacterData.isEqualToNode} returns C{True} if and only if passed a
L{CharacterData} with the same value.
"""
self.assertTrue(
microdom.CharacterData("foo").isEqualToNode(microdom.CharacterData("foo"))
)
self.assertFalse(
microdom.CharacterData("foo").isEqualToNode(microdom.CharacterData("bar"))
)
class CommentTests(TestCase):
"""
Tests for L{Comment}.
"""
def test_isEqualToNode(self) -> None:
"""
L{Comment.isEqualToNode} returns C{True} if and only if passed a
L{Comment} with the same value.
"""
self.assertTrue(microdom.Comment("foo").isEqualToNode(microdom.Comment("foo")))
self.assertFalse(microdom.Comment("foo").isEqualToNode(microdom.Comment("bar")))
class TextTests(TestCase):
"""
Tests for L{Text}.
"""
def test_isEqualToNode(self) -> None:
"""
L{Text.isEqualToNode} returns C{True} if and only if passed a L{Text}
which represents the same data.
"""
self.assertTrue(
microdom.Text("foo", raw=True).isEqualToNode(microdom.Text("foo", raw=True))
)
self.assertFalse(
microdom.Text("foo", raw=True).isEqualToNode(
microdom.Text("foo", raw=False)
)
)
self.assertFalse(
microdom.Text("foo", raw=True).isEqualToNode(microdom.Text("bar", raw=True))
)
class CDATASectionTests(TestCase):
"""
Tests for L{CDATASection}.
"""
def test_isEqualToNode(self) -> None:
"""
L{CDATASection.isEqualToNode} returns C{True} if and only if passed a
L{CDATASection} which represents the same data.
"""
self.assertTrue(
microdom.CDATASection("foo").isEqualToNode(microdom.CDATASection("foo"))
)
self.assertFalse(
microdom.CDATASection("foo").isEqualToNode(microdom.CDATASection("bar"))
)
class ElementTests(TestCase):
"""
Tests for L{Element}.
"""
def test_isEqualToNode(self) -> None:
"""
L{Element.isEqualToNode} returns C{True} if and only if passed a
L{Element} with the same C{nodeName}, C{namespace}, C{childNodes}, and
C{attributes}.
"""
self.assertTrue(
microdom.Element(
"foo", {"a": "b"}, object(), namespace="bar"
).isEqualToNode(
microdom.Element("foo", {"a": "b"}, object(), namespace="bar")
)
)
# Elements with different nodeName values do not compare equal.
self.assertFalse(
microdom.Element(
"foo", {"a": "b"}, object(), namespace="bar"
).isEqualToNode(
microdom.Element("bar", {"a": "b"}, object(), namespace="bar")
)
)
# Elements with different namespaces do not compare equal.
self.assertFalse(
microdom.Element(
"foo", {"a": "b"}, object(), namespace="bar"
).isEqualToNode(
microdom.Element("foo", {"a": "b"}, object(), namespace="baz")
)
)
# Elements with different childNodes do not compare equal.
one = microdom.Element("foo", {"a": "b"}, object(), namespace="bar")
two = microdom.Element("foo", {"a": "b"}, object(), namespace="bar")
two.appendChild(microdom.Node(object()))
self.assertFalse(one.isEqualToNode(two))
# Elements with different attributes do not compare equal.
self.assertFalse(
microdom.Element(
"foo", {"a": "b"}, object(), namespace="bar"
).isEqualToNode(
microdom.Element("foo", {"a": "c"}, object(), namespace="bar")
)
)