# This file was originally based on the meld3 package version 2.0.0
# (https://pypi.org/project/meld3/2.0.0/). The meld3 package is not
# called out separately in Supervisor's license or copyright files
# because meld3 had the same authors, copyright, and license as
# Supervisor at the time this file was bundled with Supervisor.
import unittest
import re
import sys
_SIMPLE_XML = r"""
NameDescription"""
_SIMPLE_XHTML = r"""
', encoding='latin1'))
def test_shortrepr2(self):
from supervisor.templating import parse_xmlstring
from supervisor.compat import as_bytes
root = parse_xmlstring(_COMPLEX_XHTML)
r = root.shortrepr()
self.assertEqual(r,
as_bytes('\n'
' \n'
' \n'
' [...]\n\n'
' \n'
' [...]\n'
'', encoding='latin1'))
def test_diffmeld1(self):
from supervisor.templating import parse_xmlstring
from supervisor.templating import _MELD_ID
root = parse_xmlstring(_COMPLEX_XHTML)
clone = root.clone()
div = self._makeOne('div', {_MELD_ID:'newdiv'})
clone.append(div)
tr = clone.findmeld('tr')
tr.deparent()
title = clone.findmeld('title')
title.deparent()
clone.append(title)
# unreduced
diff = root.diffmeld(clone)
changes = diff['unreduced']
addedtags = [ x.attrib[_MELD_ID] for x in changes['added'] ]
removedtags = [x.attrib[_MELD_ID] for x in changes['removed'] ]
movedtags = [ x.attrib[_MELD_ID] for x in changes['moved'] ]
addedtags.sort()
removedtags.sort()
movedtags.sort()
self.assertEqual(addedtags,['newdiv'])
self.assertEqual(removedtags,['td1', 'td2', 'tr'])
self.assertEqual(movedtags, ['title'])
# reduced
changes = diff['reduced']
addedtags = [ x.attrib[_MELD_ID] for x in changes['added'] ]
removedtags = [x.attrib[_MELD_ID] for x in changes['removed'] ]
movedtags = [ x.attrib[_MELD_ID] for x in changes['moved'] ]
addedtags.sort()
removedtags.sort()
movedtags.sort()
self.assertEqual(addedtags,['newdiv'])
self.assertEqual(removedtags,['tr'])
self.assertEqual(movedtags, ['title'])
def test_diffmeld2(self):
source = """
"""
target = """
"""
from supervisor.templating import parse_htmlstring
source_root = parse_htmlstring(source)
target_root = parse_htmlstring(target)
changes = source_root.diffmeld(target_root)
# unreduced
actual = [x.meldid() for x in changes['unreduced']['moved']]
expected = ['b']
self.assertEqual(expected, actual)
actual = [x.meldid() for x in changes['unreduced']['added']]
expected = []
self.assertEqual(expected, actual)
actual = [x.meldid() for x in changes['unreduced']['removed']]
expected = []
self.assertEqual(expected, actual)
# reduced
actual = [x.meldid() for x in changes['reduced']['moved']]
expected = ['b']
self.assertEqual(expected, actual)
actual = [x.meldid() for x in changes['reduced']['added']]
expected = []
self.assertEqual(expected, actual)
actual = [x.meldid() for x in changes['reduced']['removed']]
expected = []
self.assertEqual(expected, actual)
def test_diffmeld3(self):
source = """
"""
target = """
"""
from supervisor.templating import parse_htmlstring
source_root = parse_htmlstring(source)
target_root = parse_htmlstring(target)
changes = source_root.diffmeld(target_root)
# unreduced
actual = [x.meldid() for x in changes['unreduced']['moved']]
expected = ['b', 'c']
self.assertEqual(expected, actual)
actual = [x.meldid() for x in changes['unreduced']['added']]
expected = ['d', 'e']
self.assertEqual(expected, actual)
actual = [x.meldid() for x in changes['unreduced']['removed']]
expected = ['z', 'y']
self.assertEqual(expected, actual)
# reduced
actual = [x.meldid() for x in changes['reduced']['moved']]
expected = ['b']
self.assertEqual(expected, actual)
actual = [x.meldid() for x in changes['reduced']['added']]
expected = ['d']
self.assertEqual(expected, actual)
actual = [x.meldid() for x in changes['reduced']['removed']]
expected = ['z']
self.assertEqual(expected, actual)
def test_diffmeld4(self):
source = """
"""
target = """
"""
from supervisor.templating import parse_htmlstring
source_root = parse_htmlstring(source)
target_root = parse_htmlstring(target)
changes = source_root.diffmeld(target_root)
# unreduced
actual = [x.meldid() for x in changes['unreduced']['moved']]
expected = ['a', 'b']
self.assertEqual(expected, actual)
actual = [x.meldid() for x in changes['unreduced']['added']]
expected = ['m', 'n']
self.assertEqual(expected, actual)
actual = [x.meldid() for x in changes['unreduced']['removed']]
expected = ['c', 'd', 'z', 'y']
self.assertEqual(expected, actual)
# reduced
actual = [x.meldid() for x in changes['reduced']['moved']]
expected = ['a']
self.assertEqual(expected, actual)
actual = [x.meldid() for x in changes['reduced']['added']]
expected = ['m']
self.assertEqual(expected, actual)
actual = [x.meldid() for x in changes['reduced']['removed']]
expected = ['c', 'z']
self.assertEqual(expected, actual)
def test_diffmeld5(self):
source = """
"""
target = """
"""
from supervisor.templating import parse_htmlstring
source_root = parse_htmlstring(source)
target_root = parse_htmlstring(target)
changes = source_root.diffmeld(target_root)
# unreduced
actual = [x.meldid() for x in changes['unreduced']['moved']]
expected = ['a', 'b', 'c', 'd']
self.assertEqual(expected, actual)
actual = [x.meldid() for x in changes['unreduced']['added']]
expected = []
self.assertEqual(expected, actual)
actual = [x.meldid() for x in changes['unreduced']['removed']]
expected = []
self.assertEqual(expected, actual)
# reduced
actual = [x.meldid() for x in changes['reduced']['moved']]
expected = ['a', 'c']
self.assertEqual(expected, actual)
actual = [x.meldid() for x in changes['reduced']['added']]
expected = []
self.assertEqual(expected, actual)
actual = [x.meldid() for x in changes['reduced']['removed']]
expected = []
self.assertEqual(expected, actual)
class ParserTests(unittest.TestCase):
def _parse(self, *args):
from supervisor.templating import parse_xmlstring
root = parse_xmlstring(*args)
return root
def _parse_html(self, *args):
from supervisor.templating import parse_htmlstring
root = parse_htmlstring(*args)
return root
def test_parse_simple_xml(self):
from supervisor.templating import _MELD_ID
root = self._parse(_SIMPLE_XML)
self.assertEqual(root.tag, 'root')
self.assertEqual(root.parent, None)
l1st = root[0]
self.assertEqual(l1st.tag, 'list')
self.assertEqual(l1st.parent, root)
self.assertEqual(l1st.attrib[_MELD_ID], 'list')
item = l1st[0]
self.assertEqual(item.tag, 'item')
self.assertEqual(item.parent, l1st)
self.assertEqual(item.attrib[_MELD_ID], 'item')
name = item[0]
description = item[1]
self.assertEqual(name.tag, 'name')
self.assertEqual(name.parent, item)
self.assertEqual(name.attrib[_MELD_ID], 'name')
self.assertEqual(description.tag, 'description')
self.assertEqual(description.parent, item)
self.assertEqual(description.attrib[_MELD_ID], 'description')
def test_parse_simple_xhtml(self):
xhtml_ns = '{http://www.w3.org/1999/xhtml}%s'
from supervisor.templating import _MELD_ID
root = self._parse(_SIMPLE_XHTML)
self.assertEqual(root.tag, xhtml_ns % 'html')
self.assertEqual(root.attrib, {})
self.assertEqual(root.parent, None)
body = root[0]
self.assertEqual(body.tag, xhtml_ns % 'body')
self.assertEqual(body.attrib[_MELD_ID], 'body')
self.assertEqual(body.parent, root)
def test_parse_complex_xhtml(self):
xhtml_ns = '{http://www.w3.org/1999/xhtml}%s'
from supervisor.templating import _MELD_ID
root = self._parse(_COMPLEX_XHTML)
self.assertEqual(root.tag, xhtml_ns % 'html')
self.assertEqual(root.attrib, {})
self.assertEqual(root.parent, None)
head = root[0]
self.assertEqual(head.tag, xhtml_ns % 'head')
self.assertEqual(head.attrib, {})
self.assertEqual(head.parent, root)
meta = head[0]
self.assertEqual(meta.tag, xhtml_ns % 'meta')
self.assertEqual(meta.attrib['content'],
'text/html; charset=ISO-8859-1')
self.assertEqual(meta.parent, head)
title = head[1]
self.assertEqual(title.tag, xhtml_ns % 'title')
self.assertEqual(title.attrib[_MELD_ID], 'title')
self.assertEqual(title.parent, head)
body = root[2]
self.assertEqual(body.tag, xhtml_ns % 'body')
self.assertEqual(body.attrib, {})
self.assertEqual(body.parent, root)
div1 = body[0]
self.assertEqual(div1.tag, xhtml_ns % 'div')
self.assertEqual(div1.attrib, {'{http://foo/bar}baz': 'slab'})
self.assertEqual(div1.parent, body)
div2 = body[1]
self.assertEqual(div2.tag, xhtml_ns % 'div')
self.assertEqual(div2.attrib[_MELD_ID], 'content_well')
self.assertEqual(div2.parent, body)
form = div2[0]
self.assertEqual(form.tag, xhtml_ns % 'form')
self.assertEqual(form.attrib[_MELD_ID], 'form1')
self.assertEqual(form.attrib['action'], '.')
self.assertEqual(form.attrib['method'], 'POST')
self.assertEqual(form.parent, div2)
img = form[0]
self.assertEqual(img.tag, xhtml_ns % 'img')
self.assertEqual(img.parent, form)
table = form[1]
self.assertEqual(table.tag, xhtml_ns % 'table')
self.assertEqual(table.attrib[_MELD_ID], 'table1')
self.assertEqual(table.attrib['border'], '0')
self.assertEqual(table.parent, form)
tbody = table[0]
self.assertEqual(tbody.tag, xhtml_ns % 'tbody')
self.assertEqual(tbody.attrib[_MELD_ID], 'tbody')
self.assertEqual(tbody.parent, table)
tr = tbody[0]
self.assertEqual(tr.tag, xhtml_ns % 'tr')
self.assertEqual(tr.attrib[_MELD_ID], 'tr')
self.assertEqual(tr.attrib['class'], 'foo')
self.assertEqual(tr.parent, tbody)
td1 = tr[0]
self.assertEqual(td1.tag, xhtml_ns % 'td')
self.assertEqual(td1.attrib[_MELD_ID], 'td1')
self.assertEqual(td1.parent, tr)
td2 = tr[1]
self.assertEqual(td2.tag, xhtml_ns % 'td')
self.assertEqual(td2.attrib[_MELD_ID], 'td2')
self.assertEqual(td2.parent, tr)
def test_nvu_html(self):
from supervisor.templating import _MELD_ID
from supervisor.templating import Comment
root = self._parse_html(_NVU_HTML)
self.assertEqual(root.tag, 'html')
self.assertEqual(root.attrib, {})
self.assertEqual(root.parent, None)
head = root[0]
self.assertEqual(head.tag, 'head')
self.assertEqual(head.attrib, {})
self.assertEqual(head.parent, root)
meta = head[0]
self.assertEqual(meta.tag, 'meta')
self.assertEqual(meta.attrib['content'],
'text/html; charset=ISO-8859-1')
title = head[1]
self.assertEqual(title.tag, 'title')
self.assertEqual(title.attrib[_MELD_ID], 'title')
self.assertEqual(title.parent, head)
body = root[1]
self.assertEqual(body.tag, 'body')
self.assertEqual(body.attrib, {})
self.assertEqual(body.parent, root)
comment = body[0]
self.assertEqual(comment.tag, Comment)
table = body[3]
self.assertEqual(table.tag, 'table')
self.assertEqual(table.attrib, {'style':
'text-align: left; width: 100px;',
'border':'1',
'cellpadding':'2',
'cellspacing':'2'})
self.assertEqual(table.parent, body)
href = body[5]
self.assertEqual(href.tag, 'a')
img = body[8]
self.assertEqual(img.tag, 'img')
def test_dupe_meldids_fails_parse_xml(self):
meld_ns = "https://github.com/Supervisor/supervisor"
repeated = (''
'Hello!"""
self.assertNormalizedXMLEqual(actual, expected)
def test_write_simple_xhtml_as_html(self):
root = self._parse(_SIMPLE_XHTML)
actual = self._write_html(root)
expected = """
Hello!
"""
self.assertNormalizedHTMLEqual(actual, expected)
def test_write_complex_xhtml_as_html(self):
root = self._parse(_COMPLEX_XHTML)
actual = self._write_html(root)
expected = """
This will be escaped in html output: &
"""
self.assertNormalizedHTMLEqual(actual, expected)
def test_write_complex_xhtml_as_xhtml(self):
# I'm not entirely sure if the cdata "script" quoting in this
# test is entirely correct for XHTML. Ryan Tomayko suggests
# that escaped entities are handled properly in script tags by
# XML-aware browsers at
# http://sourceforge.net/mailarchive/message.php?msg_id=10835582
# but I haven't tested it at all. ZPT does not seem to do
# this; it outputs unescaped data.
root = self._parse(_COMPLEX_XHTML)
actual = self._write_xhtml(root)
expected = """
This will be escaped in html output: &
"""
self.assertNormalizedXMLEqual(actual, expected)
def test_write_emptytags_html(self):
from supervisor.compat import as_string
root = self._parse(_EMPTYTAGS_HTML)
actual = self._write_html(root)
expected = """
"""
self.assertEqual(as_string(actual, encoding='latin1'), expected)
def test_write_booleanattrs_xhtml_as_html(self):
root = self._parse(_BOOLEANATTRS_XHTML)
actual = self._write_html(root)
expected = """
"""
self.assertNormalizedHTMLEqual(actual, expected)
def test_write_simple_xhtml_pipeline(self):
root = self._parse(_SIMPLE_XHTML)
actual = self._write_xhtml(root, pipeline=True)
expected = """Hello!"""
self.assertNormalizedXMLEqual(actual, expected)
def test_write_simple_xml_pipeline(self):
root = self._parse(_SIMPLE_XML)
actual = self._write_xml(root, pipeline=True)
expected = """NameDescription"""
self.assertNormalizedXMLEqual(actual, expected)
def test_write_simple_xml_override_encoding(self):
root = self._parse(_SIMPLE_XML)
actual = self._write_xml(root, encoding="latin-1")
expected = """NameDescription"""
self.assertNormalizedXMLEqual(actual, expected)
def test_write_simple_xml_as_fragment(self):
root = self._parse(_SIMPLE_XML)
actual = self._write_xml(root, fragment=True)
expected = """NameDescription"""
self.assertNormalizedXMLEqual(actual, expected)
def test_write_simple_xml_with_doctype(self):
root = self._parse(_SIMPLE_XML)
from supervisor.templating import doctype
actual = self._write_xml(root, doctype=doctype.xhtml)
expected = """
NameDescription"""
self.assertNormalizedXMLEqual(actual, expected)
def test_write_simple_xml_doctype_nodeclaration(self):
root = self._parse(_SIMPLE_XML)
from supervisor.templating import doctype
actual = self._write_xml(root, declaration=False,
doctype=doctype.xhtml)
expected = """NameDescription"""
self.assertNormalizedXMLEqual(actual, expected)
def test_write_simple_xml_fragment_kills_doctype_and_declaration(self):
root = self._parse(_SIMPLE_XML)
from supervisor.templating import doctype
actual = self._write_xml(root, declaration=True,
doctype=doctype.xhtml, fragment=True)
expected = """NameDescription"""
self.assertNormalizedXMLEqual(actual, expected)
def test_write_simple_xhtml_override_encoding(self):
root = self._parse(_SIMPLE_XHTML)
actual = self._write_xhtml(root, encoding="latin-1", declaration=True)
expected = """Hello!"""
self.assertNormalizedXMLEqual(actual, expected)
def test_write_simple_xhtml_as_fragment(self):
root = self._parse(_SIMPLE_XHTML)
actual = self._write_xhtml(root, fragment=True)
expected = """Hello!"""
self.assertNormalizedXMLEqual(actual, expected)
def test_write_simple_xhtml_with_doctype(self):
root = self._parse(_SIMPLE_XHTML)
from supervisor.templating import doctype
actual = self._write_xhtml(root, doctype=doctype.xhtml)
expected = """Hello!"""
self.assertNormalizedXMLEqual(actual, expected)
def test_write_simple_xhtml_doctype_nodeclaration(self):
root = self._parse(_SIMPLE_XHTML)
from supervisor.templating import doctype
actual = self._write_xhtml(root, declaration=False,
doctype=doctype.xhtml)
expected = """Hello!"""
self.assertNormalizedXMLEqual(actual, expected)
def test_write_simple_xhtml_fragment_kills_doctype_and_declaration(self):
root = self._parse(_SIMPLE_XHTML)
from supervisor.templating import doctype
actual = self._write_xhtml(root, declaration=True,
doctype=doctype.xhtml, fragment=True)
expected = """Hello!"""
self.assertNormalizedXMLEqual(actual, expected)
def test_write_simple_xhtml_as_html_fragment(self):
root = self._parse(_SIMPLE_XHTML)
actual = self._write_html(root, fragment=True)
expected = """Hello!"""
self.assertNormalizedXMLEqual(actual, expected)
def test_write_simple_xhtml_with_doctype_as_html(self):
root = self._parse(_SIMPLE_XHTML)
actual = self._write_html(root)
expected = """
Hello!"""
self.assertNormalizedXMLEqual(actual, expected)
def test_write_simple_xhtml_as_html_new_doctype(self):
root = self._parse(_SIMPLE_XHTML)
from supervisor.templating import doctype
actual = self._write_html(root, doctype=doctype.html_strict)
expected = """
Hello!"""
self.assertNormalizedXMLEqual(actual, expected)
def test_unknown_entity(self):
# exception thrown may vary by python or expat version
from xml.parsers import expat
self.assertRaises((expat.error, SyntaxError), self._parse,
'&fleeb;')
def test_content_nostructure(self):
root = self._parse(_SIMPLE_XML)
D = root.findmeld('description')
D.content('description &&', structure=False)
actual = self._write_xml(root)
expected = """
Namedescription &<foo>&<bar>"""
self.assertNormalizedXMLEqual(actual, expected)
def test_content_structure(self):
root = self._parse(_SIMPLE_XML)
D = root.findmeld('description')
D.content('description &', structure=True)
actual = self._write_xml(root)
expected = """
Namedescription &"""
self.assertNormalizedXMLEqual(actual, expected)
def test_replace_nostructure(self):
root = self._parse(_SIMPLE_XML)
D = root.findmeld('description')
D.replace('description &&', structure=False)
actual = self._write_xml(root)
expected = """
Name
description &<foo>&<bar>
"""
self.assertNormalizedXMLEqual(actual, expected)
def test_replace_structure(self):
root = self._parse(_SIMPLE_XML)
D = root.findmeld('description')
D.replace('description &', structure=True)
actual = self._write_xml(root)
expected = """
Name
description &"""
self.assertNormalizedXMLEqual(actual, expected)
def test_escape_cdata(self):
from supervisor.compat import as_bytes
from supervisor.templating import _escape_cdata
a = ('< > <& &' && &foo "" '
'http://www.example.com?foo=bar&bang=baz {')
self.assertEqual(
as_bytes('< > <& &' && &foo "" '
'http://www.example.com?foo=bar&bang=baz {',
encoding='latin1'),
_escape_cdata(a))
def test_escape_cdata_unicodeerror(self):
from supervisor.templating import _escape_cdata
from supervisor.compat import as_bytes
from supervisor.compat import as_string
a = as_string(as_bytes('\x80', encoding='latin1'), encoding='latin1')
self.assertEqual(as_bytes('', encoding='latin1'),
_escape_cdata(a, 'ascii'))
def test_escape_attrib(self):
from supervisor.templating import _escape_attrib
from supervisor.compat import as_bytes
a = ('< > <& &' && &foo "" '
'http://www.example.com?foo=bar&bang=baz {')
self.assertEqual(
as_bytes('< > <& &' '
'&& &foo "" '
'http://www.example.com?foo=bar&bang=baz {',
encoding='latin1'),
_escape_attrib(a, None))
def test_escape_attrib_unicodeerror(self):
from supervisor.templating import _escape_attrib
from supervisor.compat import as_bytes
from supervisor.compat import as_string
a = as_string(as_bytes('\x80', encoding='latin1'), encoding='latin1')
self.assertEqual(as_bytes('', encoding='latin1'),
_escape_attrib(a, 'ascii'))
def normalize_html(s):
s = re.sub(r"[ \t]+", " ", s)
s = re.sub(r"/>", ">", s)
return s
def normalize_xml(s):
s = re.sub(r"\s+", " ", s)
s = re.sub(r"(?s)\s+<", "<", s)
s = re.sub(r"(?s)>\s+", ">", s)
return s
def test_suite():
return unittest.findTestCases(sys.modules[__name__])
def main():
unittest.main(defaultTest='test_suite')
if __name__ == '__main__':
main()