1 # -*- test-case-name: twisted.web.test.test_domhelpers -*-
2 # Copyright (c) Twisted Matrix Laboratories.
3 # See LICENSE for details.
6 Specific tests for (some of) the methods in L{twisted.web.domhelpers}.
9 from xml.dom import minidom
11 from twisted.trial.unittest import TestCase
13 from twisted.web import microdom
15 from twisted.web import domhelpers
18 class DOMHelpersTestsMixin:
20 A mixin for L{TestCase} subclasses which defines test methods for
21 domhelpers functionality based on a DOM creation function provided by a
26 def test_getElementsByTagName(self):
27 doc1 = self.dom.parseString('<foo/>')
28 actual=domhelpers.getElementsByTagName(doc1, 'foo')[0].nodeName
30 self.assertEqual(actual, expected)
31 el1=doc1.documentElement
32 actual=domhelpers.getElementsByTagName(el1, 'foo')[0].nodeName
33 self.assertEqual(actual, expected)
35 doc2_xml='<a><foo in="a"/><b><foo in="b"/></b><c><foo in="c"/></c><foo in="d"/><foo in="ef"/><g><foo in="g"/><h><foo in="h"/></h></g></a>'
36 doc2 = self.dom.parseString(doc2_xml)
37 tag_list=domhelpers.getElementsByTagName(doc2, 'foo')
38 actual=''.join([node.getAttribute('in') for node in tag_list])
40 self.assertEqual(actual, expected)
41 el2=doc2.documentElement
42 tag_list=domhelpers.getElementsByTagName(el2, 'foo')
43 actual=''.join([node.getAttribute('in') for node in tag_list])
44 self.assertEqual(actual, expected)
63 doc3 = self.dom.parseString(doc3_xml)
64 tag_list=domhelpers.getElementsByTagName(doc3, 'foo')
65 actual=''.join([node.getAttribute('in') for node in tag_list])
67 self.assertEqual(actual, expected)
68 el3=doc3.documentElement
69 tag_list=domhelpers.getElementsByTagName(el3, 'foo')
70 actual=''.join([node.getAttribute('in') for node in tag_list])
71 self.assertEqual(actual, expected)
73 doc4_xml='<foo><bar></bar><baz><foo/></baz></foo>'
74 doc4 = self.dom.parseString(doc4_xml)
75 actual=domhelpers.getElementsByTagName(doc4, 'foo')
76 root=doc4.documentElement
77 expected=[root, root.childNodes[-1].childNodes[0]]
78 self.assertEqual(actual, expected)
79 actual=domhelpers.getElementsByTagName(root, 'foo')
80 self.assertEqual(actual, expected)
83 def test_gatherTextNodes(self):
84 doc1 = self.dom.parseString('<a>foo</a>')
85 actual=domhelpers.gatherTextNodes(doc1)
87 self.assertEqual(actual, expected)
88 actual=domhelpers.gatherTextNodes(doc1.documentElement)
89 self.assertEqual(actual, expected)
91 doc2_xml='<a>a<b>b</b><c>c</c>def<g>g<h>h</h></g></a>'
92 doc2 = self.dom.parseString(doc2_xml)
93 actual=domhelpers.gatherTextNodes(doc2)
95 self.assertEqual(actual, expected)
96 actual=domhelpers.gatherTextNodes(doc2.documentElement)
97 self.assertEqual(actual, expected)
99 doc3_xml=('<a>a<b>b<d>d<g>g</g><h>h</h></d><e>e<i>i</i></e></b>' +
100 '<c>c<f>f<j>j</j></f></c></a>')
101 doc3 = self.dom.parseString(doc3_xml)
102 actual=domhelpers.gatherTextNodes(doc3)
103 expected='abdgheicfj'
104 self.assertEqual(actual, expected)
105 actual=domhelpers.gatherTextNodes(doc3.documentElement)
106 self.assertEqual(actual, expected)
108 def test_clearNode(self):
109 doc1 = self.dom.parseString('<a><b><c><d/></c></b></a>')
110 a_node=doc1.documentElement
111 domhelpers.clearNode(a_node)
114 self.dom.Element('a').toxml())
116 doc2 = self.dom.parseString('<a><b><c><d/></c></b></a>')
117 b_node=doc2.documentElement.childNodes[0]
118 domhelpers.clearNode(b_node)
119 actual=doc2.documentElement.toxml()
120 expected = self.dom.Element('a')
121 expected.appendChild(self.dom.Element('b'))
122 self.assertEqual(actual, expected.toxml())
126 doc1 = self.dom.parseString('<a><b id="bar"/><c class="foo"/></a>')
127 node=domhelpers.get(doc1, "foo")
129 expected = self.dom.Element('c')
130 expected.setAttribute('class', 'foo')
131 self.assertEqual(actual, expected.toxml())
133 node=domhelpers.get(doc1, "bar")
135 expected = self.dom.Element('b')
136 expected.setAttribute('id', 'bar')
137 self.assertEqual(actual, expected.toxml())
139 self.assertRaises(domhelpers.NodeLookupError,
144 def test_getIfExists(self):
145 doc1 = self.dom.parseString('<a><b id="bar"/><c class="foo"/></a>')
146 node=domhelpers.getIfExists(doc1, "foo")
148 expected = self.dom.Element('c')
149 expected.setAttribute('class', 'foo')
150 self.assertEqual(actual, expected.toxml())
152 node=domhelpers.getIfExists(doc1, "pzork")
153 self.assertIdentical(node, None)
156 def test_getAndClear(self):
157 doc1 = self.dom.parseString('<a><b id="foo"><c></c></b></a>')
158 node=domhelpers.getAndClear(doc1, "foo")
160 expected = self.dom.Element('b')
161 expected.setAttribute('id', 'foo')
162 self.assertEqual(actual, expected.toxml())
165 def test_locateNodes(self):
166 doc1 = self.dom.parseString('<a><b foo="olive"><c foo="olive"/></b><d foo="poopy"/></a>')
167 node_list=domhelpers.locateNodes(
168 doc1.childNodes, 'foo', 'olive', noNesting=1)
169 actual=''.join([node.toxml() for node in node_list])
170 expected = self.dom.Element('b')
171 expected.setAttribute('foo', 'olive')
172 c = self.dom.Element('c')
173 c.setAttribute('foo', 'olive')
174 expected.appendChild(c)
176 self.assertEqual(actual, expected.toxml())
178 node_list=domhelpers.locateNodes(
179 doc1.childNodes, 'foo', 'olive', noNesting=0)
180 actual=''.join([node.toxml() for node in node_list])
181 self.assertEqual(actual, expected.toxml() + c.toxml())
184 def test_getParents(self):
185 doc1 = self.dom.parseString('<a><b><c><d/></c><e/></b><f/></a>')
186 node_list = domhelpers.getParents(
187 doc1.childNodes[0].childNodes[0].childNodes[0])
188 actual = ''.join([node.tagName for node in node_list
189 if hasattr(node, 'tagName')])
190 self.assertEqual(actual, 'cba')
193 def test_findElementsWithAttribute(self):
194 doc1 = self.dom.parseString('<a foo="1"><b foo="2"/><c foo="1"/><d/></a>')
195 node_list = domhelpers.findElementsWithAttribute(doc1, 'foo')
196 actual = ''.join([node.tagName for node in node_list])
197 self.assertEqual(actual, 'abc')
199 node_list = domhelpers.findElementsWithAttribute(doc1, 'foo', '1')
200 actual = ''.join([node.tagName for node in node_list])
201 self.assertEqual(actual, 'ac')
204 def test_findNodesNamed(self):
205 doc1 = self.dom.parseString('<doc><foo/><bar/><foo>a</foo></doc>')
206 node_list = domhelpers.findNodesNamed(doc1, 'foo')
207 actual = len(node_list)
208 self.assertEqual(actual, 2)
210 # NOT SURE WHAT THESE ARE SUPPOSED TO DO..
211 # def test_RawText FIXME
212 # def test_superSetAttribute FIXME
213 # def test_superPrependAttribute FIXME
214 # def test_superAppendAttribute FIXME
215 # def test_substitute FIXME
217 def test_escape(self):
218 j='this string " contains many & characters> xml< won\'t like'
219 expected='this string " contains many & characters> xml< won\'t like'
220 self.assertEqual(domhelpers.escape(j), expected)
222 def test_unescape(self):
223 j='this string " has && entities > < and some characters xml won\'t like<'
224 expected='this string " has && entities > < and some characters xml won\'t like<'
225 self.assertEqual(domhelpers.unescape(j), expected)
228 def test_getNodeText(self):
230 L{getNodeText} returns the concatenation of all the text data at or
231 beneath the node passed to it.
233 node = self.dom.parseString('<foo><bar>baz</bar><bar>quux</bar></foo>')
234 self.assertEqual(domhelpers.getNodeText(node), "bazquux")
238 class MicroDOMHelpersTests(DOMHelpersTestsMixin, TestCase):
241 def test_gatherTextNodesDropsWhitespace(self):
243 Microdom discards whitespace-only text nodes, so L{gatherTextNodes}
244 returns only the text from nodes which had non-whitespace characters.
254 doc4 = self.dom.parseString(doc4_xml)
255 actual = domhelpers.gatherTextNodes(doc4)
256 expected = '\n stuff\n '
257 self.assertEqual(actual, expected)
258 actual = domhelpers.gatherTextNodes(doc4.documentElement)
259 self.assertEqual(actual, expected)
262 def test_textEntitiesNotDecoded(self):
264 Microdom does not decode entities in text nodes.
266 doc5_xml='<x>Souffl&</x>'
267 doc5 = self.dom.parseString(doc5_xml)
268 actual=domhelpers.gatherTextNodes(doc5)
269 expected='Souffl&'
270 self.assertEqual(actual, expected)
271 actual=domhelpers.gatherTextNodes(doc5.documentElement)
272 self.assertEqual(actual, expected)
276 class MiniDOMHelpersTests(DOMHelpersTestsMixin, TestCase):
279 def test_textEntitiesDecoded(self):
281 Minidom does decode entities in text nodes.
283 doc5_xml='<x>Souffl&</x>'
284 doc5 = self.dom.parseString(doc5_xml)
285 actual=domhelpers.gatherTextNodes(doc5)
287 self.assertEqual(actual, expected)
288 actual=domhelpers.gatherTextNodes(doc5.documentElement)
289 self.assertEqual(actual, expected)
292 def test_getNodeUnicodeText(self):
294 L{domhelpers.getNodeText} returns a C{unicode} string when text
295 nodes are represented in the DOM with unicode, whether or not there
296 are non-ASCII characters present.
298 node = self.dom.parseString("<foo>bar</foo>")
299 text = domhelpers.getNodeText(node)
300 self.assertEqual(text, u"bar")
301 self.assertIsInstance(text, unicode)
303 node = self.dom.parseString(u"<foo>\N{SNOWMAN}</foo>".encode('utf-8'))
304 text = domhelpers.getNodeText(node)
305 self.assertEqual(text, u"\N{SNOWMAN}")
306 self.assertIsInstance(text, unicode)