test_domhelpers.py 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306
  1. # -*- test-case-name: twisted.web.test.test_domhelpers -*-
  2. # Copyright (c) Twisted Matrix Laboratories.
  3. # See LICENSE for details.
  4. """
  5. Specific tests for (some of) the methods in L{twisted.web.domhelpers}.
  6. """
  7. from xml.dom import minidom
  8. from twisted.trial.unittest import TestCase
  9. from twisted.web import microdom
  10. from twisted.web import domhelpers
  11. class DOMHelpersTestsMixin:
  12. """
  13. A mixin for L{TestCase} subclasses which defines test methods for
  14. domhelpers functionality based on a DOM creation function provided by a
  15. subclass.
  16. """
  17. dom = None
  18. def test_getElementsByTagName(self):
  19. doc1 = self.dom.parseString('<foo/>')
  20. actual=domhelpers.getElementsByTagName(doc1, 'foo')[0].nodeName
  21. expected='foo'
  22. self.assertEqual(actual, expected)
  23. el1=doc1.documentElement
  24. actual=domhelpers.getElementsByTagName(el1, 'foo')[0].nodeName
  25. self.assertEqual(actual, expected)
  26. 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>'
  27. doc2 = self.dom.parseString(doc2_xml)
  28. tag_list=domhelpers.getElementsByTagName(doc2, 'foo')
  29. actual=''.join([node.getAttribute('in') for node in tag_list])
  30. expected='abcdefgh'
  31. self.assertEqual(actual, expected)
  32. el2=doc2.documentElement
  33. tag_list=domhelpers.getElementsByTagName(el2, 'foo')
  34. actual=''.join([node.getAttribute('in') for node in tag_list])
  35. self.assertEqual(actual, expected)
  36. doc3_xml='''
  37. <a><foo in="a"/>
  38. <b><foo in="b"/>
  39. <d><foo in="d"/>
  40. <g><foo in="g"/></g>
  41. <h><foo in="h"/></h>
  42. </d>
  43. <e><foo in="e"/>
  44. <i><foo in="i"/></i>
  45. </e>
  46. </b>
  47. <c><foo in="c"/>
  48. <f><foo in="f"/>
  49. <j><foo in="j"/></j>
  50. </f>
  51. </c>
  52. </a>'''
  53. doc3 = self.dom.parseString(doc3_xml)
  54. tag_list=domhelpers.getElementsByTagName(doc3, 'foo')
  55. actual=''.join([node.getAttribute('in') for node in tag_list])
  56. expected='abdgheicfj'
  57. self.assertEqual(actual, expected)
  58. el3=doc3.documentElement
  59. tag_list=domhelpers.getElementsByTagName(el3, 'foo')
  60. actual=''.join([node.getAttribute('in') for node in tag_list])
  61. self.assertEqual(actual, expected)
  62. doc4_xml='<foo><bar></bar><baz><foo/></baz></foo>'
  63. doc4 = self.dom.parseString(doc4_xml)
  64. actual=domhelpers.getElementsByTagName(doc4, 'foo')
  65. root=doc4.documentElement
  66. expected=[root, root.childNodes[-1].childNodes[0]]
  67. self.assertEqual(actual, expected)
  68. actual=domhelpers.getElementsByTagName(root, 'foo')
  69. self.assertEqual(actual, expected)
  70. def test_gatherTextNodes(self):
  71. doc1 = self.dom.parseString('<a>foo</a>')
  72. actual=domhelpers.gatherTextNodes(doc1)
  73. expected='foo'
  74. self.assertEqual(actual, expected)
  75. actual=domhelpers.gatherTextNodes(doc1.documentElement)
  76. self.assertEqual(actual, expected)
  77. doc2_xml='<a>a<b>b</b><c>c</c>def<g>g<h>h</h></g></a>'
  78. doc2 = self.dom.parseString(doc2_xml)
  79. actual=domhelpers.gatherTextNodes(doc2)
  80. expected='abcdefgh'
  81. self.assertEqual(actual, expected)
  82. actual=domhelpers.gatherTextNodes(doc2.documentElement)
  83. self.assertEqual(actual, expected)
  84. doc3_xml=('<a>a<b>b<d>d<g>g</g><h>h</h></d><e>e<i>i</i></e></b>' +
  85. '<c>c<f>f<j>j</j></f></c></a>')
  86. doc3 = self.dom.parseString(doc3_xml)
  87. actual=domhelpers.gatherTextNodes(doc3)
  88. expected='abdgheicfj'
  89. self.assertEqual(actual, expected)
  90. actual=domhelpers.gatherTextNodes(doc3.documentElement)
  91. self.assertEqual(actual, expected)
  92. def test_clearNode(self):
  93. doc1 = self.dom.parseString('<a><b><c><d/></c></b></a>')
  94. a_node=doc1.documentElement
  95. domhelpers.clearNode(a_node)
  96. self.assertEqual(
  97. a_node.toxml(),
  98. self.dom.Element('a').toxml())
  99. doc2 = self.dom.parseString('<a><b><c><d/></c></b></a>')
  100. b_node=doc2.documentElement.childNodes[0]
  101. domhelpers.clearNode(b_node)
  102. actual=doc2.documentElement.toxml()
  103. expected = self.dom.Element('a')
  104. expected.appendChild(self.dom.Element('b'))
  105. self.assertEqual(actual, expected.toxml())
  106. def test_get(self):
  107. doc1 = self.dom.parseString('<a><b id="bar"/><c class="foo"/></a>')
  108. node=domhelpers.get(doc1, "foo")
  109. actual=node.toxml()
  110. expected = self.dom.Element('c')
  111. expected.setAttribute('class', 'foo')
  112. self.assertEqual(actual, expected.toxml())
  113. node=domhelpers.get(doc1, "bar")
  114. actual=node.toxml()
  115. expected = self.dom.Element('b')
  116. expected.setAttribute('id', 'bar')
  117. self.assertEqual(actual, expected.toxml())
  118. self.assertRaises(domhelpers.NodeLookupError,
  119. domhelpers.get,
  120. doc1,
  121. "pzork")
  122. def test_getIfExists(self):
  123. doc1 = self.dom.parseString('<a><b id="bar"/><c class="foo"/></a>')
  124. node=domhelpers.getIfExists(doc1, "foo")
  125. actual=node.toxml()
  126. expected = self.dom.Element('c')
  127. expected.setAttribute('class', 'foo')
  128. self.assertEqual(actual, expected.toxml())
  129. node=domhelpers.getIfExists(doc1, "pzork")
  130. self.assertIdentical(node, None)
  131. def test_getAndClear(self):
  132. doc1 = self.dom.parseString('<a><b id="foo"><c></c></b></a>')
  133. node=domhelpers.getAndClear(doc1, "foo")
  134. actual=node.toxml()
  135. expected = self.dom.Element('b')
  136. expected.setAttribute('id', 'foo')
  137. self.assertEqual(actual, expected.toxml())
  138. def test_locateNodes(self):
  139. doc1 = self.dom.parseString('<a><b foo="olive"><c foo="olive"/></b><d foo="poopy"/></a>')
  140. node_list=domhelpers.locateNodes(
  141. doc1.childNodes, 'foo', 'olive', noNesting=1)
  142. actual=''.join([node.toxml() for node in node_list])
  143. expected = self.dom.Element('b')
  144. expected.setAttribute('foo', 'olive')
  145. c = self.dom.Element('c')
  146. c.setAttribute('foo', 'olive')
  147. expected.appendChild(c)
  148. self.assertEqual(actual, expected.toxml())
  149. node_list=domhelpers.locateNodes(
  150. doc1.childNodes, 'foo', 'olive', noNesting=0)
  151. actual=''.join([node.toxml() for node in node_list])
  152. self.assertEqual(actual, expected.toxml() + c.toxml())
  153. def test_getParents(self):
  154. doc1 = self.dom.parseString('<a><b><c><d/></c><e/></b><f/></a>')
  155. node_list = domhelpers.getParents(
  156. doc1.childNodes[0].childNodes[0].childNodes[0])
  157. actual = ''.join([node.tagName for node in node_list
  158. if hasattr(node, 'tagName')])
  159. self.assertEqual(actual, 'cba')
  160. def test_findElementsWithAttribute(self):
  161. doc1 = self.dom.parseString('<a foo="1"><b foo="2"/><c foo="1"/><d/></a>')
  162. node_list = domhelpers.findElementsWithAttribute(doc1, 'foo')
  163. actual = ''.join([node.tagName for node in node_list])
  164. self.assertEqual(actual, 'abc')
  165. node_list = domhelpers.findElementsWithAttribute(doc1, 'foo', '1')
  166. actual = ''.join([node.tagName for node in node_list])
  167. self.assertEqual(actual, 'ac')
  168. def test_findNodesNamed(self):
  169. doc1 = self.dom.parseString('<doc><foo/><bar/><foo>a</foo></doc>')
  170. node_list = domhelpers.findNodesNamed(doc1, 'foo')
  171. actual = len(node_list)
  172. self.assertEqual(actual, 2)
  173. # NOT SURE WHAT THESE ARE SUPPOSED TO DO..
  174. # def test_RawText FIXME
  175. # def test_superSetAttribute FIXME
  176. # def test_superPrependAttribute FIXME
  177. # def test_superAppendAttribute FIXME
  178. # def test_substitute FIXME
  179. def test_escape(self):
  180. j='this string " contains many & characters> xml< won\'t like'
  181. expected='this string &quot; contains many &amp; characters&gt; xml&lt; won\'t like'
  182. self.assertEqual(domhelpers.escape(j), expected)
  183. def test_unescape(self):
  184. j='this string &quot; has &&amp; entities &gt; &lt; and some characters xml won\'t like<'
  185. expected='this string " has && entities > < and some characters xml won\'t like<'
  186. self.assertEqual(domhelpers.unescape(j), expected)
  187. def test_getNodeText(self):
  188. """
  189. L{getNodeText} returns the concatenation of all the text data at or
  190. beneath the node passed to it.
  191. """
  192. node = self.dom.parseString('<foo><bar>baz</bar><bar>quux</bar></foo>')
  193. self.assertEqual(domhelpers.getNodeText(node), "bazquux")
  194. class MicroDOMHelpersTests(DOMHelpersTestsMixin, TestCase):
  195. dom = microdom
  196. def test_gatherTextNodesDropsWhitespace(self):
  197. """
  198. Microdom discards whitespace-only text nodes, so L{gatherTextNodes}
  199. returns only the text from nodes which had non-whitespace characters.
  200. """
  201. doc4_xml='''<html>
  202. <head>
  203. </head>
  204. <body>
  205. stuff
  206. </body>
  207. </html>
  208. '''
  209. doc4 = self.dom.parseString(doc4_xml)
  210. actual = domhelpers.gatherTextNodes(doc4)
  211. expected = '\n stuff\n '
  212. self.assertEqual(actual, expected)
  213. actual = domhelpers.gatherTextNodes(doc4.documentElement)
  214. self.assertEqual(actual, expected)
  215. def test_textEntitiesNotDecoded(self):
  216. """
  217. Microdom does not decode entities in text nodes.
  218. """
  219. doc5_xml='<x>Souffl&amp;</x>'
  220. doc5 = self.dom.parseString(doc5_xml)
  221. actual=domhelpers.gatherTextNodes(doc5)
  222. expected='Souffl&amp;'
  223. self.assertEqual(actual, expected)
  224. actual=domhelpers.gatherTextNodes(doc5.documentElement)
  225. self.assertEqual(actual, expected)
  226. class MiniDOMHelpersTests(DOMHelpersTestsMixin, TestCase):
  227. dom = minidom
  228. def test_textEntitiesDecoded(self):
  229. """
  230. Minidom does decode entities in text nodes.
  231. """
  232. doc5_xml='<x>Souffl&amp;</x>'
  233. doc5 = self.dom.parseString(doc5_xml)
  234. actual=domhelpers.gatherTextNodes(doc5)
  235. expected='Souffl&'
  236. self.assertEqual(actual, expected)
  237. actual=domhelpers.gatherTextNodes(doc5.documentElement)
  238. self.assertEqual(actual, expected)
  239. def test_getNodeUnicodeText(self):
  240. """
  241. L{domhelpers.getNodeText} returns a C{unicode} string when text
  242. nodes are represented in the DOM with unicode, whether or not there
  243. are non-ASCII characters present.
  244. """
  245. node = self.dom.parseString("<foo>bar</foo>")
  246. text = domhelpers.getNodeText(node)
  247. self.assertEqual(text, u"bar")
  248. self.assertIsInstance(text, unicode)
  249. node = self.dom.parseString(u"<foo>\N{SNOWMAN}</foo>".encode('utf-8'))
  250. text = domhelpers.getNodeText(node)
  251. self.assertEqual(text, u"\N{SNOWMAN}")
  252. self.assertIsInstance(text, unicode)