<html><head><meta name="color-scheme" content="light dark"></head><body><pre style="word-wrap: break-word; white-space: pre-wrap;"># -*- test-case-name: twisted.web.test.test_domhelpers -*-
# Copyright (c) Twisted Matrix Laboratories.
# See LICENSE for details.

"""
Specific tests for (some of) the methods in L{twisted.web.domhelpers}.
"""

from xml.dom import minidom

from twisted.python.compat import unicode
from twisted.trial.unittest import TestCase
from twisted.web import domhelpers, microdom


class DOMHelpersTestsMixin:
    """
    A mixin for L{TestCase} subclasses which defines test methods for
    domhelpers functionality based on a DOM creation function provided by a
    subclass.
    """
    dom = None

    def test_getElementsByTagName(self):
        doc1 = self.dom.parseString('&lt;foo/&gt;')
        actual = domhelpers.getElementsByTagName(doc1, 'foo')[0].nodeName
        expected = 'foo'
        self.assertEqual(actual, expected)
        el1 = doc1.documentElement
        actual = domhelpers.getElementsByTagName(el1, 'foo')[0].nodeName
        self.assertEqual(actual, expected)

        doc2_xml = '&lt;a&gt;&lt;foo in="a"/&gt;&lt;b&gt;&lt;foo in="b"/&gt;&lt;/b&gt;&lt;c&gt;&lt;foo in="c"/&gt;&lt;/c&gt;&lt;foo in="d"/&gt;&lt;foo in="ef"/&gt;&lt;g&gt;&lt;foo in="g"/&gt;&lt;h&gt;&lt;foo in="h"/&gt;&lt;/h&gt;&lt;/g&gt;&lt;/a&gt;'
        doc2 = self.dom.parseString(doc2_xml)
        tag_list = domhelpers.getElementsByTagName(doc2, 'foo')
        actual = ''.join([node.getAttribute('in') for node in tag_list])
        expected = 'abcdefgh'
        self.assertEqual(actual, expected)
        el2 = doc2.documentElement
        tag_list = domhelpers.getElementsByTagName(el2, 'foo')
        actual = ''.join([node.getAttribute('in') for node in tag_list])
        self.assertEqual(actual, expected)

        doc3_xml = '''
&lt;a&gt;&lt;foo in="a"/&gt;
    &lt;b&gt;&lt;foo in="b"/&gt;
        &lt;d&gt;&lt;foo in="d"/&gt;
            &lt;g&gt;&lt;foo in="g"/&gt;&lt;/g&gt;
            &lt;h&gt;&lt;foo in="h"/&gt;&lt;/h&gt;
        &lt;/d&gt;
        &lt;e&gt;&lt;foo in="e"/&gt;
            &lt;i&gt;&lt;foo in="i"/&gt;&lt;/i&gt;
        &lt;/e&gt;
    &lt;/b&gt;
    &lt;c&gt;&lt;foo in="c"/&gt;
        &lt;f&gt;&lt;foo in="f"/&gt;
            &lt;j&gt;&lt;foo in="j"/&gt;&lt;/j&gt;
        &lt;/f&gt;
    &lt;/c&gt;
&lt;/a&gt;'''
        doc3 = self.dom.parseString(doc3_xml)
        tag_list = domhelpers.getElementsByTagName(doc3, 'foo')
        actual = ''.join([node.getAttribute('in') for node in tag_list])
        expected = 'abdgheicfj'
        self.assertEqual(actual, expected)
        el3 = doc3.documentElement
        tag_list = domhelpers.getElementsByTagName(el3, 'foo')
        actual = ''.join([node.getAttribute('in') for node in tag_list])
        self.assertEqual(actual, expected)

        doc4_xml = '&lt;foo&gt;&lt;bar&gt;&lt;/bar&gt;&lt;baz&gt;&lt;foo/&gt;&lt;/baz&gt;&lt;/foo&gt;'
        doc4 = self.dom.parseString(doc4_xml)
        actual = domhelpers.getElementsByTagName(doc4, 'foo')
        root = doc4.documentElement
        expected = [root, root.childNodes[-1].childNodes[0]]
        self.assertEqual(actual, expected)
        actual = domhelpers.getElementsByTagName(root, 'foo')
        self.assertEqual(actual, expected)


    def test_gatherTextNodes(self):
        doc1 = self.dom.parseString('&lt;a&gt;foo&lt;/a&gt;')
        actual = domhelpers.gatherTextNodes(doc1)
        expected = 'foo'
        self.assertEqual(actual, expected)
        actual = domhelpers.gatherTextNodes(doc1.documentElement)
        self.assertEqual(actual, expected)

        doc2_xml = '&lt;a&gt;a&lt;b&gt;b&lt;/b&gt;&lt;c&gt;c&lt;/c&gt;def&lt;g&gt;g&lt;h&gt;h&lt;/h&gt;&lt;/g&gt;&lt;/a&gt;'
        doc2 = self.dom.parseString(doc2_xml)
        actual = domhelpers.gatherTextNodes(doc2)
        expected = 'abcdefgh'
        self.assertEqual(actual, expected)
        actual = domhelpers.gatherTextNodes(doc2.documentElement)
        self.assertEqual(actual, expected)

        doc3_xml = ('&lt;a&gt;a&lt;b&gt;b&lt;d&gt;d&lt;g&gt;g&lt;/g&gt;&lt;h&gt;h&lt;/h&gt;&lt;/d&gt;&lt;e&gt;e&lt;i&gt;i&lt;/i&gt;&lt;/e&gt;&lt;/b&gt;' +
                    '&lt;c&gt;c&lt;f&gt;f&lt;j&gt;j&lt;/j&gt;&lt;/f&gt;&lt;/c&gt;&lt;/a&gt;')
        doc3 = self.dom.parseString(doc3_xml)
        actual = domhelpers.gatherTextNodes(doc3)
        expected = 'abdgheicfj'
        self.assertEqual(actual, expected)
        actual = domhelpers.gatherTextNodes(doc3.documentElement)
        self.assertEqual(actual, expected)


    def test_clearNode(self):
        doc1 = self.dom.parseString('&lt;a&gt;&lt;b&gt;&lt;c&gt;&lt;d/&gt;&lt;/c&gt;&lt;/b&gt;&lt;/a&gt;')
        a_node = doc1.documentElement
        domhelpers.clearNode(a_node)
        self.assertEqual(
            a_node.toxml(),
            self.dom.Element('a').toxml())

        doc2 = self.dom.parseString('&lt;a&gt;&lt;b&gt;&lt;c&gt;&lt;d/&gt;&lt;/c&gt;&lt;/b&gt;&lt;/a&gt;')
        b_node = doc2.documentElement.childNodes[0]
        domhelpers.clearNode(b_node)
        actual = doc2.documentElement.toxml()
        expected = self.dom.Element('a')
        expected.appendChild(self.dom.Element('b'))
        self.assertEqual(actual, expected.toxml())


    def test_get(self):
        doc1 = self.dom.parseString('&lt;a&gt;&lt;b id="bar"/&gt;&lt;c class="foo"/&gt;&lt;/a&gt;')
        doc = self.dom.Document()
        node = domhelpers.get(doc1, "foo")
        actual = node.toxml()
        expected = doc.createElement('c')
        expected.setAttribute('class', 'foo')
        self.assertEqual(actual, expected.toxml())

        node = domhelpers.get(doc1, "bar")
        actual = node.toxml()
        expected = doc.createElement('b')
        expected.setAttribute('id', 'bar')
        self.assertEqual(actual, expected.toxml())

        self.assertRaises(domhelpers.NodeLookupError,
                          domhelpers.get,
                          doc1,
                          "pzork")


    def test_getIfExists(self):
        doc1 = self.dom.parseString('&lt;a&gt;&lt;b id="bar"/&gt;&lt;c class="foo"/&gt;&lt;/a&gt;')
        doc = self.dom.Document()
        node = domhelpers.getIfExists(doc1, "foo")
        actual = node.toxml()
        expected = doc.createElement('c')
        expected.setAttribute('class', 'foo')
        self.assertEqual(actual, expected.toxml())

        node = domhelpers.getIfExists(doc1, "pzork")
        self.assertIdentical(node, None)


    def test_getAndClear(self):
        doc1 = self.dom.parseString('&lt;a&gt;&lt;b id="foo"&gt;&lt;c&gt;&lt;/c&gt;&lt;/b&gt;&lt;/a&gt;')
        doc = self.dom.Document()
        node = domhelpers.getAndClear(doc1, "foo")
        actual = node.toxml()
        expected = doc.createElement('b')
        expected.setAttribute('id', 'foo')
        self.assertEqual(actual, expected.toxml())


    def test_locateNodes(self):
        doc1 = self.dom.parseString('&lt;a&gt;&lt;b foo="olive"&gt;&lt;c foo="olive"/&gt;&lt;/b&gt;&lt;d foo="poopy"/&gt;&lt;/a&gt;')
        doc = self.dom.Document()
        node_list = domhelpers.locateNodes(
            doc1.childNodes, 'foo', 'olive', noNesting=1)
        actual = ''.join([node.toxml() for node in node_list])
        expected = doc.createElement('b')
        expected.setAttribute('foo', 'olive')
        c = doc.createElement('c')
        c.setAttribute('foo', 'olive')
        expected.appendChild(c)

        self.assertEqual(actual, expected.toxml())

        node_list = domhelpers.locateNodes(
            doc1.childNodes, 'foo', 'olive', noNesting=0)
        actual = ''.join([node.toxml() for node in node_list])
        self.assertEqual(actual, expected.toxml() + c.toxml())


    def test_getParents(self):
        doc1 = self.dom.parseString('&lt;a&gt;&lt;b&gt;&lt;c&gt;&lt;d/&gt;&lt;/c&gt;&lt;e/&gt;&lt;/b&gt;&lt;f/&gt;&lt;/a&gt;')
        node_list = domhelpers.getParents(
            doc1.childNodes[0].childNodes[0].childNodes[0])
        actual = ''.join([node.tagName for node in node_list
                          if hasattr(node, 'tagName')])
        self.assertEqual(actual, 'cba')


    def test_findElementsWithAttribute(self):
        doc1 = self.dom.parseString('&lt;a foo="1"&gt;&lt;b foo="2"/&gt;&lt;c foo="1"/&gt;&lt;d/&gt;&lt;/a&gt;')
        node_list = domhelpers.findElementsWithAttribute(doc1, 'foo')
        actual = ''.join([node.tagName for node in node_list])
        self.assertEqual(actual, 'abc')

        node_list = domhelpers.findElementsWithAttribute(doc1, 'foo', '1')
        actual = ''.join([node.tagName for node in node_list])
        self.assertEqual(actual, 'ac')


    def test_findNodesNamed(self):
        doc1 = self.dom.parseString('&lt;doc&gt;&lt;foo/&gt;&lt;bar/&gt;&lt;foo&gt;a&lt;/foo&gt;&lt;/doc&gt;')
        node_list = domhelpers.findNodesNamed(doc1, 'foo')
        actual = len(node_list)
        self.assertEqual(actual, 2)


    def test_escape(self):
        j = 'this string " contains many &amp; characters&gt; xml&lt; won\'t like'
        expected = 'this string &amp;quot; contains many &amp;amp; characters&amp;gt; xml&amp;lt; won\'t like'
        self.assertEqual(domhelpers.escape(j), expected)


    def test_unescape(self):
        j = 'this string &amp;quot; has &amp;&amp;amp; entities &amp;gt; &amp;lt; and some characters xml won\'t like&lt;'
        expected = 'this string " has &amp;&amp; entities &gt; &lt; and some characters xml won\'t like&lt;'
        self.assertEqual(domhelpers.unescape(j), expected)


    def test_getNodeText(self):
        """
        L{getNodeText} returns the concatenation of all the text data at or
        beneath the node passed to it.
        """
        node = self.dom.parseString('&lt;foo&gt;&lt;bar&gt;baz&lt;/bar&gt;&lt;bar&gt;quux&lt;/bar&gt;&lt;/foo&gt;')
        self.assertEqual(domhelpers.getNodeText(node), "bazquux")



class MicroDOMHelpersTests(DOMHelpersTestsMixin, TestCase):
    dom = microdom

    def test_gatherTextNodesDropsWhitespace(self):
        """
        Microdom discards whitespace-only text nodes, so L{gatherTextNodes}
        returns only the text from nodes which had non-whitespace characters.
        """
        doc4_xml = '''&lt;html&gt;
  &lt;head&gt;
  &lt;/head&gt;
  &lt;body&gt;
    stuff
  &lt;/body&gt;
&lt;/html&gt;
'''
        doc4 = self.dom.parseString(doc4_xml)
        actual = domhelpers.gatherTextNodes(doc4)
        expected = '\n    stuff\n  '
        self.assertEqual(actual, expected)
        actual = domhelpers.gatherTextNodes(doc4.documentElement)
        self.assertEqual(actual, expected)


    def test_textEntitiesNotDecoded(self):
        """
        Microdom does not decode entities in text nodes.
        """
        doc5_xml = '&lt;x&gt;Souffl&amp;amp;&lt;/x&gt;'
        doc5 = self.dom.parseString(doc5_xml)
        actual = domhelpers.gatherTextNodes(doc5)
        expected = 'Souffl&amp;amp;'
        self.assertEqual(actual, expected)
        actual = domhelpers.gatherTextNodes(doc5.documentElement)
        self.assertEqual(actual, expected)



class MiniDOMHelpersTests(DOMHelpersTestsMixin, TestCase):
    dom = minidom

    def test_textEntitiesDecoded(self):
        """
        Minidom does decode entities in text nodes.
        """
        doc5_xml = '&lt;x&gt;Souffl&amp;amp;&lt;/x&gt;'
        doc5 = self.dom.parseString(doc5_xml)
        actual = domhelpers.gatherTextNodes(doc5)
        expected = 'Souffl&amp;'
        self.assertEqual(actual, expected)
        actual = domhelpers.gatherTextNodes(doc5.documentElement)
        self.assertEqual(actual, expected)


    def test_getNodeUnicodeText(self):
        """
        L{domhelpers.getNodeText} returns a C{unicode} string when text
        nodes are represented in the DOM with unicode, whether or not there
        are non-ASCII characters present.
        """
        node = self.dom.parseString("&lt;foo&gt;bar&lt;/foo&gt;")
        text = domhelpers.getNodeText(node)
        self.assertEqual(text, u"bar")
        self.assertIsInstance(text, unicode)

        node = self.dom.parseString(u"&lt;foo&gt;\N{SNOWMAN}&lt;/foo&gt;".encode('utf-8'))
        text = domhelpers.getNodeText(node)
        self.assertEqual(text, u"\N{SNOWMAN}")
        self.assertIsInstance(text, unicode)
</pre></body></html>