Mini Shell
import unittest
import re
import sys
_SIMPLE_XML = r"""<?xml version="1.0"?>
<root xmlns:meld="http://www.plope.com/software/meld3">
<list meld:id="list">
<item meld:id="item">
<name meld:id="name">Name</name>
<description meld:id="description">Description</description>
</item>
</list>
</root>"""
_SIMPLE_XHTML = r"""<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:meld="http://www.plope.com/software/meld3">
<body meld:id="body">Hello!</body>
</html>"""
_EMPTYTAGS_HTML = """<html>
<body>
<area/><base/><basefont/><br/><col/><frame/><hr/><img/><input/><isindex/>
<link/><meta/><param/>
</body>
</html>"""
_BOOLEANATTRS_XHTML= """<html>
<body>
<tag selected="true"/>
<tag checked="true"/>
<tag compact="true"/>
<tag declare="true"/>
<tag defer="true"/>
<tag disabled="true"/>
<tag ismap="true"/>
<tag multiple="true"/>
<tag nohref="true"/>
<tag noresize="true"/>
<tag noshade="true"/>
<tag nowrap="true"/>
</body>
</html>"""
_ENTITIES_XHTML= r"""
<html>
<head></head>
<body>
<!-- test entity references -->
<p> </p>
</body>
</html>"""
_COMPLEX_XHTML = r"""<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:meld="http://www.plope.com/software/meld3"
xmlns:bar="http://foo/bar">
<head>
<meta content="text/html; charset=ISO-8859-1" http-equiv="content-type" />
<title meld:id="title">This will be escaped in html output: &</title>
<script>this won't be escaped in html output: &</script>
<script type="text/javascript">
//<![CDATA[
// this won't be escaped in html output
function match(a,b) {
if (a < b && a > 0) then { return 1 }
}
//]]>
</script>
<style>this won't be escaped in html output: &</style>
</head>
<!-- a comment -->
<body>
<div bar:baz="slab"/>
<div meld:id="content_well">
<form meld:id="form1" action="." method="POST">
<img src="foo.gif"/>
<table border="0" meld:id="table1">
<tbody meld:id="tbody">
<tr meld:id="tr" class="foo">
<td meld:id="td1">Name</td>
<td meld:id="td2">Description</td>
</tr>
</tbody>
</table>
<input type="submit" name="submit" value=" Next "/>
</form>
</div>
</body>
</html>"""
_NVU_HTML = """<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<meta content="text/html; charset=ISO-8859-1" http-equiv="content-type">
<title meld:id="title">test doc</title>
</head>
<body>
<!-- comment! -->
Oh yeah...<br>
<br>
<table style="text-align: left; width: 100px;" border="1" cellpadding="2" cellspacing="2">
<tbody>
<tr>
<td>Yup</td>
<td>More </td>
<td>Stuff</td>
<td>Oh Yeah</td>
</tr>
<tr>
<td>1</td>
<td>2</td>
<td>3</td>
<td>4</td>
</tr>
<tr>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
</tbody>
</table>
<br>
<a href=".">And an image...</a><br>
<br>
<img style="width: 2048px; height: 1536px;" alt="dumb" src="IMG_0102.jpg">
</body>
</html>"""
_FILLMELDFORM_HTML = """\
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<html>
<head>
<title>Emergency Contacts</title>
</head>
<body>
<div class="header">Emergency Contacts</div>
<form action="." method="POST">
<table>
<tbody meld:id="tbody">
<tr>
<th>Title</th>
<td>
<input type="text" name="honorific" size="6" value=""
meld:id="honorific"/>
</td>
</tr>
<tr>
<th>First Name</th>
<td>
<input type="text" name="firstname" size="20" value=""
meld:id="firstname"/>
</td>
</tr>
<tr>
<th>Middle Name</th>
<td>
<input type="text" name="middlename" size="15" value=""
meld:id="middlename"/>
</td>
</tr>
<tr>
<th>Last Name</th>
<td>
<input type="text" name="lastname" size="20" value=""
meld:id="lastname"/>
</td>
</tr>
<tr>
<th>Suffix</th>
<td style="width: 554px;">
<select name="suffix" meld:id="suffix">
<option value="Jr.">Jr.</option>
<option value="Sr.">Sr.</option>
<option value="III">III</option>
</select>
</td>
</tr>
<tr>
<th>Address 1</th>
<td>
<input type="text" name="address1" size="30" value=""
meld:id="address1"/>
</td>
</tr>
<tr>
<th>Address 2</th>
<td>
<input type="text" name="address2" size="30" value=""
meld:id="address2"/>
</td>
</tr>
<tr>
<th>City</th>
<td>
<input type="text" name="city" size="20" value=""
meld:id="city"/>
</td>
</tr>
<tr>
<th>State</th>
<td>
<input type="text" name="state" size="5" value=""
meld:id="state"/>
</td>
</tr>
<tr>
<th>ZIP</th>
<td>
<input type="text" name="zip" size="8" value=""
meld:id="zip"/>
</td>
</tr>
<tr>
<th>Home Phone</th>
<td>
<input type="text" name="homephone" size="12" value=""
meld:id="homephone"/>
</td>
</tr>
<tr>
<th>Cell/Mobile Phone</th>
<td>
<input type="text" name="cellphone" size="12" value=""
meld:id="cellphone"/>
</td>
</tr>
<tr>
<th>Email Address</th>
<td>
<input type="text" name="email" size="20" value=""
meld:id="email"/>
</td>
</tr>
<tr>
<th>Over 18? (Checkbox Boolean)</th>
<td>
<input type="checkbox" name="over18" meld:id="over18"
value="true" checked="true"/>
</td>
</tr>
<tr>
<th>Mail OK? (Checkbox Ternary)</th>
<td style="width: 554px;" meld:id="mailok:inputgroup">
<input type="hidden" name="mailok:default"
value="false"/>
<input type="checkbox" name="mailok"
value="true" checked/>
<input type="checkbox" name="mailok"
value="false"/>
</td>
</tr>
<tr>
<th>Favorite Color (Radio)</th>
<td style="width: 554px;" meld:id="favorite_color:inputgroup">
Red <input type="radio" name="favorite_color"
value="Red"/>
Green <input type="radio" name="favorite_color"
value="Green"/>
Blue <input type="radio" name="favorite_color"
value="Blue"/>
</td>
</tr>
<tr>
<th></th>
<td>
<input type="submit" value=" Update " name="edit:method" />
</td>
</tr>
</tbody>
</table>
</form>
<p><a href="..">Return to list</a></p>
</body>
</html>
"""
class MeldAPITests(unittest.TestCase):
def _makeElement(self, string):
from . import parse_xmlstring
return parse_xmlstring(string)
def _makeElementFromHTML(self, string):
from . import parse_htmlstring
return parse_htmlstring(string)
def test_findmeld(self):
root = self._makeElement(_SIMPLE_XML)
item = root.findmeld('item')
self.assertEqual(item.tag, 'item')
name = root.findmeld('name')
self.assertEqual(name.text, 'Name')
def test_findmeld_default(self):
root = self._makeElement(_SIMPLE_XML)
item = root.findmeld('item')
self.assertEqual(item.tag, 'item')
unknown = root.findmeld('unknown', 'foo')
self.assertEqual(unknown, 'foo')
self.assertEqual(root.findmeld('unknown'), None)
def test_repeat_nochild(self):
root = self._makeElement(_SIMPLE_XML)
item = root.findmeld('item')
self.assertEqual(item.tag, 'item')
data = [{'name':'Jeff Buckley', 'description':'ethereal'},
{'name':'Slipknot', 'description':'heavy'}]
for element, d in item.repeat(data):
element.findmeld('name').text = d['name']
element.findmeld('description').text = d['description']
self.assertEqual(item[0].text, 'Jeff Buckley')
self.assertEqual(item[1].text, 'ethereal')
def test_repeat_child(self):
root = self._makeElement(_SIMPLE_XML)
list = root.findmeld('list')
self.assertEqual(list.tag, 'list')
data = [{'name':'Jeff Buckley', 'description':'ethereal'},
{'name':'Slipknot', 'description':'heavy'}]
for element, d in list.repeat(data, 'item'):
element.findmeld('name').text = d['name']
element.findmeld('description').text = d['description']
self.assertEqual(list[0][0].text, 'Jeff Buckley')
self.assertEqual(list[0][1].text, 'ethereal')
self.assertEqual(list[1][0].text, 'Slipknot')
self.assertEqual(list[1][1].text, 'heavy')
def test_mod(self):
root = self._makeElement(_SIMPLE_XML)
root % {'description':'foo', 'name':'bar'}
name = root.findmeld('name')
self.assertEqual(name.text, 'bar')
desc = root.findmeld('description')
self.assertEqual(desc.text, 'foo')
def test_fillmelds(self):
root = self._makeElement(_SIMPLE_XML)
unfilled = root.fillmelds(**{'description':'foo', 'jammyjam':'a'})
desc = root.findmeld('description')
self.assertEqual(desc.text, 'foo')
self.assertEqual(unfilled, ['jammyjam'])
def test_fillmeldhtmlform(self):
data = [
{'honorific':'Mr.', 'firstname':'Chris', 'middlename':'Phillips',
'lastname':'McDonough', 'address1':'802 Caroline St.',
'address2':'Apt. 2B', 'city':'Fredericksburg', 'state': 'VA',
'zip':'22401', 'homephone':'555-1212', 'cellphone':'555-1313',
'email':'chrism@plope.com', 'suffix':'Sr.', 'over18':True,
'mailok:inputgroup':'true', 'favorite_color:inputgroup':'Green'},
{'honorific':'Mr.', 'firstname':'Fred', 'middlename':'',
'lastname':'Rogers', 'address1':'1 Imaginary Lane',
'address2':'Apt. 3A', 'city':'Never Never Land', 'state': 'LA',
'zip':'00001', 'homephone':'555-1111', 'cellphone':'555-4444',
'email':'fred@neighborhood.com', 'suffix':'Jr.', 'over18':False,
'mailok:inputgroup':'false','favorite_color:inputgroup':'Yellow',},
{'firstname':'Fred', 'middlename':'',
'lastname':'Rogers', 'address1':'1 Imaginary Lane',
'address2':'Apt. 3A', 'city':'Never Never Land', 'state': 'LA',
'zip':'00001', 'homephone':'555-1111', 'cellphone':'555-4444',
'email':'fred@neighborhood.com', 'suffix':'IV', 'over18':False,
'mailok:inputgroup':'false', 'favorite_color:inputgroup':'Blue',
'notthere':1,},
]
root = self._makeElementFromHTML(_FILLMELDFORM_HTML)
clone = root.clone()
unfilled = clone.fillmeldhtmlform(**data[0])
self.assertEqual(unfilled, [])
self.assertEqual(clone.findmeld('honorific').attrib['value'], 'Mr.')
self.assertEqual(clone.findmeld('firstname').attrib['value'], 'Chris')
middlename = clone.findmeld('middlename')
self.assertEqual(middlename.attrib['value'], 'Phillips')
suffix = clone.findmeld('suffix')
self.assertEqual(suffix[1].attrib['selected'], 'selected')
self.assertEqual(clone.findmeld('over18').attrib['checked'], 'checked')
mailok = clone.findmeld('mailok:inputgroup')
self.assertEqual(mailok[1].attrib['checked'], 'checked')
favoritecolor = clone.findmeld('favorite_color:inputgroup')
self.assertEqual(favoritecolor[1].attrib['checked'], 'checked')
clone = root.clone()
unfilled = clone.fillmeldhtmlform(**data[1])
self.assertEqual(unfilled, ['favorite_color:inputgroup'])
self.assertEqual(clone.findmeld('over18').attrib.get('checked'), None)
mailok = clone.findmeld('mailok:inputgroup')
self.assertEqual(mailok[2].attrib['checked'], 'checked')
self.assertEqual(mailok[1].attrib.get('checked'), None)
clone = root.clone()
unfilled = clone.fillmeldhtmlform(**data[2])
self.assertEqual(sorted(unfilled), ['notthere', 'suffix'])
self.assertEqual(clone.findmeld('honorific').text, None)
favoritecolor = clone.findmeld('favorite_color:inputgroup')
self.assertEqual(favoritecolor[2].attrib['checked'], 'checked')
self.assertEqual(favoritecolor[1].attrib.get('checked'), None)
def test_replace_removes_all_elements(self):
from . import Replace
root = self._makeElement(_SIMPLE_XML)
L = root.findmeld('list')
L.replace('this is a textual replacement')
R = root[0]
self.assertEqual(R.tag, Replace)
self.assertEqual(len(root.getchildren()), 1)
def test_replace_replaces_the_right_element(self):
from . import Replace
root = self._makeElement(_SIMPLE_XML)
D = root.findmeld('description')
D.replace('this is a textual replacement')
self.assertEqual(len(root.getchildren()), 1)
L = root[0]
self.assertEqual(L.tag, 'list')
self.assertEqual(len(L.getchildren()), 1)
I = L[0]
self.assertEqual(I.tag, 'item')
self.assertEqual(len(I.getchildren()), 2)
N = I[0]
self.assertEqual(N.tag, 'name')
self.assertEqual(len(N.getchildren()), 0)
D = I[1]
self.assertEqual(D.tag, Replace)
self.assertEqual(D.text, 'this is a textual replacement')
self.assertEqual(len(D.getchildren()), 0)
self.assertEqual(D.structure, False)
def test_content(self):
from . import Replace
root = self._makeElement(_SIMPLE_XML)
D = root.findmeld('description')
D.content('this is a textual replacement')
self.assertEqual(len(root.getchildren()), 1)
L = root[0]
self.assertEqual(L.tag, 'list')
self.assertEqual(len(L.getchildren()), 1)
I = L[0]
self.assertEqual(I.tag, 'item')
self.assertEqual(len(I.getchildren()), 2)
N = I[0]
self.assertEqual(N.tag, 'name')
self.assertEqual(len(N.getchildren()), 0)
D = I[1]
self.assertEqual(D.tag, 'description')
self.assertEqual(D.text, None)
self.assertEqual(len(D.getchildren()), 1)
T = D[0]
self.assertEqual(T.tag, Replace)
self.assertEqual(T.text, 'this is a textual replacement')
self.assertEqual(T.structure, False)
def test_attributes(self):
from . import _MELD_ID
root = self._makeElement(_COMPLEX_XHTML)
D = root.findmeld('form1')
D.attributes(foo='bar', baz='1', g='2', action='#')
self.assertEqual(D.attrib, {
'foo':'bar', 'baz':'1', 'g':'2',
'method':'POST', 'action':'#',
_MELD_ID: 'form1'})
def test_attributes_unicode(self):
from . import _MELD_ID
from ._compat import _u
root = self._makeElement(_COMPLEX_XHTML)
D = root.findmeld('form1')
D.attributes(foo=_u('bar'), action=_u('#'))
self.assertEqual(D.attrib, {
'foo':_u('bar'),
'method':'POST', 'action': _u('#'),
_MELD_ID: 'form1'})
def test_attributes_nonstringtype_raises(self):
root = self._makeElement('<root></root>')
self.assertRaises(ValueError, root.attributes, foo=1)
class MeldElementInterfaceTests(unittest.TestCase):
def _getTargetClass(self):
from . import _MeldElementInterface
return _MeldElementInterface
def _makeOne(self, *arg, **kw):
klass = self._getTargetClass()
return klass(*arg, **kw)
def test_repeat(self):
root = self._makeOne('root', {})
from . import _MELD_ID
item = self._makeOne('item', {_MELD_ID:'item'})
record = self._makeOne('record', {_MELD_ID:'record'})
name = self._makeOne('name', {_MELD_ID:'name'})
description = self._makeOne('description', {_MELD_ID:'description'})
record.append(name)
record.append(description)
item.append(record)
root.append(item)
data = [{'name':'Jeff Buckley', 'description':'ethereal'},
{'name':'Slipknot', 'description':'heavy'}]
for element, d in item.repeat(data):
element.findmeld('name').text = d['name']
element.findmeld('description').text = d['description']
self.assertEqual(len(root), 2)
item1 = root[0]
self.assertEqual(len(item1), 1)
record1 = item1[0]
self.assertEqual(len(record1), 2)
name1 = record1[0]
desc1 = record1[1]
self.assertEqual(name1.text, 'Jeff Buckley')
self.assertEqual(desc1.text, 'ethereal')
item2 = root[1]
self.assertEqual(len(item2), 1)
record2 = item2[0]
self.assertEqual(len(record2), 2)
name2 = record2[0]
desc2 = record2[1]
self.assertEqual(name2.text, 'Slipknot')
self.assertEqual(desc2.text, 'heavy')
def test_content_simple_nostructure(self):
el = self._makeOne('div', {'id':'thediv'})
el.content('hello')
self.assertEqual(len(el._children), 1)
replacenode = el._children[0]
self.assertEqual(replacenode.parent, el)
self.assertEqual(replacenode.text, 'hello')
self.assertEqual(replacenode.structure, False)
from . import Replace
self.assertEqual(replacenode.tag, Replace)
def test_content_simple_structure(self):
el = self._makeOne('div', {'id':'thediv'})
el.content('hello', structure=True)
self.assertEqual(len(el._children), 1)
replacenode = el._children[0]
self.assertEqual(replacenode.parent, el)
self.assertEqual(replacenode.text, 'hello')
self.assertEqual(replacenode.structure, True)
from . import Replace
self.assertEqual(replacenode.tag, Replace)
def test_findmeld_simple(self):
from . import _MELD_ID
el = self._makeOne('div', {_MELD_ID:'thediv'})
self.assertEqual(el.findmeld('thediv'), el)
def test_findmeld_simple_oneleveldown(self):
from . import _MELD_ID
el = self._makeOne('div', {_MELD_ID:'thediv'})
span = self._makeOne('span', {_MELD_ID:'thespan'})
el.append(span)
self.assertEqual(el.findmeld('thespan'), span)
def test_findmeld_simple_twolevelsdown(self):
from . import _MELD_ID
el = self._makeOne('div', {_MELD_ID:'thediv'})
span = self._makeOne('span', {_MELD_ID:'thespan'})
a = self._makeOne('a', {_MELD_ID:'thea'})
span.append(a)
el.append(span)
self.assertEqual(el.findmeld('thea'), a)
def test_ctor(self):
iface = self._makeOne('div', {'id':'thediv'})
self.assertEqual(iface.parent, None)
self.assertEqual(iface.tag, 'div')
self.assertEqual(iface.attrib, {'id':'thediv'})
def test_getiterator_simple(self):
div = self._makeOne('div', {'id':'thediv'})
iterator = div.getiterator()
self.assertEqual(len(iterator), 1)
self.assertEqual(iterator[0], div)
def test_getiterator(self):
div = self._makeOne('div', {'id':'thediv'})
span = self._makeOne('span', {})
span2 = self._makeOne('span', {'id':'2'})
span3 = self._makeOne('span3', {'id':'3'})
span3.text = 'abc'
span3.tail = ' '
div.append(span)
span.append(span2)
span2.append(span3)
it = div.getiterator()
self.assertEqual(len(it), 4)
self.assertEqual(it[0], div)
self.assertEqual(it[1], span)
self.assertEqual(it[2], span2)
self.assertEqual(it[3], span3)
def test_getiterator_tag_ignored(self):
div = self._makeOne('div', {'id':'thediv'})
span = self._makeOne('span', {})
span2 = self._makeOne('span', {'id':'2'})
span3 = self._makeOne('span3', {'id':'3'})
span3.text = 'abc'
span3.tail = ' '
div.append(span)
span.append(span2)
span2.append(span3)
it = div.getiterator(tag='div')
self.assertEqual(len(it), 4)
self.assertEqual(it[0], div)
self.assertEqual(it[1], span)
self.assertEqual(it[2], span2)
self.assertEqual(it[3], span3)
def test_append(self):
div = self._makeOne('div', {'id':'thediv'})
span = self._makeOne('span', {})
div.append(span)
self.assertEqual(div[0].tag, 'span')
self.assertEqual(span.parent, div)
def test__setitem__(self):
div = self._makeOne('div', {'id':'thediv'})
span = self._makeOne('span', {})
span2 = self._makeOne('span', {'id':'2'})
div.append(span)
div[0] = span2
self.assertEqual(div[0].tag, 'span')
self.assertEqual(div[0].attrib, {'id':'2'})
self.assertEqual(div[0].parent, div)
def test_insert(self):
div = self._makeOne('div', {'id':'thediv'})
span = self._makeOne('span', {})
span2 = self._makeOne('span', {'id':'2'})
div.append(span)
div.insert(0, span2)
self.assertEqual(div[0].tag, 'span')
self.assertEqual(div[0].attrib, {'id':'2'})
self.assertEqual(div[0].parent, div)
self.assertEqual(div[1].tag, 'span')
self.assertEqual(div[1].attrib, {})
self.assertEqual(div[1].parent, div)
def test_clone_simple(self):
div = self._makeOne('div', {'id':'thediv'})
div.text = 'abc'
div.tail = ' '
span = self._makeOne('span', {})
div.append(span)
div2 = div.clone()
def test_clone(self):
div = self._makeOne('div', {'id':'thediv'})
span = self._makeOne('span', {})
span2 = self._makeOne('span', {'id':'2'})
span3 = self._makeOne('span3', {'id':'3'})
span3.text = 'abc'
span3.tail = ' '
div.append(span)
span.append(span2)
span2.append(span3)
div2 = div.clone()
self.assertEqual(div.tag, div2.tag)
self.assertEqual(div.attrib, div2.attrib)
self.assertEqual(div[0].tag, div2[0].tag)
self.assertEqual(div[0].attrib, div2[0].attrib)
self.assertEqual(div[0][0].tag, div2[0][0].tag)
self.assertEqual(div[0][0].attrib, div2[0][0].attrib)
self.assertEqual(div[0][0][0].tag, div2[0][0][0].tag)
self.assertEqual(div[0][0][0].attrib, div2[0][0][0].attrib)
self.assertEqual(div[0][0][0].text, div2[0][0][0].text)
self.assertEqual(div[0][0][0].tail, div2[0][0][0].tail)
self.assertNotEqual(id(div), id(div2))
self.assertNotEqual(id(div[0]), id(div2[0]))
self.assertNotEqual(id(div[0][0]), id(div2[0][0]))
self.assertNotEqual(id(div[0][0][0]), id(div2[0][0][0]))
def test_deparent_noparent(self):
div = self._makeOne('div', {})
self.assertEqual(div.parent, None)
div.deparent()
self.assertEqual(div.parent, None)
def test_deparent_withparent(self):
parent = self._makeOne('parent', {})
self.assertEqual(parent.parent, None)
child = self._makeOne('child', {})
parent.append(child)
self.assertEqual(parent.parent, None)
self.assertEqual(child.parent, parent)
self.assertEqual(parent[0], child)
child.deparent()
self.assertEqual(child.parent, None)
self.assertRaises(IndexError, parent.__getitem__, 0)
def test_setslice(self):
parent = self._makeOne('parent', {})
child1 = self._makeOne('child1', {})
child2 = self._makeOne('child2', {})
child3 = self._makeOne('child3', {})
children = (child1, child2, child3)
parent[0:2] = children
self.assertEqual(child1.parent, parent)
self.assertEqual(child2.parent, parent)
self.assertEqual(child3.parent, parent)
self.assertEqual(parent._children, list(children))
def test_delslice(self):
parent = self._makeOne('parent', {})
child1 = self._makeOne('child1', {})
child2 = self._makeOne('child2', {})
child3 = self._makeOne('child3', {})
children = (child1, child2, child3)
parent[0:2] = children
del parent[0:2]
self.assertEqual(child1.parent, None)
self.assertEqual(child2.parent, None)
self.assertEqual(child3.parent, parent)
self.assertEqual(len(parent._children), 1)
def test_remove(self):
parent = self._makeOne('parent', {})
child1 = self._makeOne('child1', {})
parent.append(child1)
parent.remove(child1)
self.assertEqual(child1.parent, None)
self.assertEqual(len(parent._children), 0)
def test_lineage(self):
from . import _MELD_ID
div1 = self._makeOne('div', {_MELD_ID:'div1'})
span1 = self._makeOne('span', {_MELD_ID:'span1'})
span2 = self._makeOne('span', {_MELD_ID:'span2'})
span3 = self._makeOne('span', {_MELD_ID:'span3'})
span4 = self._makeOne('span', {_MELD_ID:'span4'})
span5 = self._makeOne('span', {_MELD_ID:'span5'})
span6 = self._makeOne('span', {_MELD_ID:'span6'})
unknown = self._makeOne('span', {})
div2 = self._makeOne('div2', {_MELD_ID:'div2'})
div1.append(span1)
span1.append(span2)
span2.append(span3)
span3.append(unknown)
unknown.append(span4)
span4.append(span5)
span5.append(span6)
div1.append(div2)
def ids(L):
return [ x.meldid() for x in L ]
self.assertEqual(ids(div1.lineage()), ['div1'])
self.assertEqual(ids(span1.lineage()), ['span1', 'div1'])
self.assertEqual(ids(span2.lineage()), ['span2', 'span1', 'div1'])
self.assertEqual(ids(span3.lineage()), ['span3', 'span2', 'span1',
'div1'])
self.assertEqual(ids(unknown.lineage()), [None, 'span3', 'span2',
'span1',
'div1'])
self.assertEqual(ids(span4.lineage()), ['span4', None, 'span3',
'span2',
'span1','div1'])
self.assertEqual(ids(span5.lineage()), ['span5', 'span4', None,
'span3', 'span2',
'span1','div1'])
self.assertEqual(ids(span6.lineage()), ['span6', 'span5', 'span4',
None,'span3', 'span2',
'span1','div1'])
self.assertEqual(ids(div2.lineage()), ['div2', 'div1'])
def test_shortrepr(self):
from ._compat import _b
div = self._makeOne('div', {'id':'div1'})
span = self._makeOne('span', {})
span2 = self._makeOne('span', {'id':'2'})
span3 = self._makeOne('span3', {'id':'3'})
span4 = self._makeOne('span4', {'id':'4'})
span5 = self._makeOne('span5', {'id':'5'})
span6 = self._makeOne('span6', {'id':'6'})
div2 = self._makeOne('div2', {'id':'div2'})
div.append(span)
span.append(span2)
div.append(div2)
r = div.shortrepr()
self.assertEqual(r,
_b('<div id="div1"><span><span id="2"></span></span>'
'<div2 id="div2"></div2></div>'))
def test_shortrepr2(self):
from . import parse_xmlstring
from ._compat import _b
root = parse_xmlstring(_COMPLEX_XHTML)
r = root.shortrepr()
self.assertEqual(r,
_b('<html>\n'
' <head>\n'
' <meta content="text/html; charset=ISO-8859-1" '
'http-equiv="content-type">\n'
' [...]\n</head>\n'
' <!-- a comment -->\n'
' [...]\n'
'</html>'))
def test_diffmeld1(self):
from . import parse_xmlstring
from . 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 = """
<root>
<a meld:id="a">
<b meld:id="b"></b>
</a>
</root>"""
target = """
<root>
<a meld:id="a"></a>
<b meld:id="b"></b>
</root>
"""
from . 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 = """
<root>
<a meld:id="a">
<b meld:id="b">
<c meld:id="c"></c>
</b>
</a>
<z meld:id="z">
<y meld:id="y"></y>
</z>
</root>
"""
target = """
<root>
<b meld:id="b">
<c meld:id="c"></c>
</b>
<a meld:id="a"></a>
<d meld:id="d">
<e meld:id="e"></e>
</d>
</root>
"""
from . 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 = """
<root>
<a meld:id="a">
<b meld:id="b">
<c meld:id="c">
<d meld:id="d"></d>
</c>
</b>
</a>
<z meld:id="z">
<y meld:id="y"></y>
</z>
</root>
"""
target = """
<root>
<p>
<a meld:id="a">
<b meld:id="b"></b>
</a>
</p>
<p>
<m meld:id="m">
<n meld:id="n"></n>
</m>
</p>
</root>
"""
from . 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 = """
<root>
<a meld:id="a">
<b meld:id="b">
<c meld:id="c">
<d meld:id="d"></d>
</c>
</b>
</a>
<z meld:id="z">
<y meld:id="y"></y>
</z>
</root>
"""
target = """
<root>
<p>
<a meld:id="a">
<b meld:id="b">
<p>
<c meld:id="c">
<d meld:id="d"></d>
</c>
</p>
</b>
</a>
</p>
<z meld:id="z">
<y meld:id="y"></y>
</z>
</root>
"""
from . 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 . import parse_xmlstring
root = parse_xmlstring(*args)
return root
def _parse_html(self, *args):
from . import parse_htmlstring
root = parse_htmlstring(*args)
return root
def test_parse_simple_xml(self):
from . 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 . 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 . 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)
comment = root[1]
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 . import _MELD_ID
from . 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)
br1 = body[1]
br2 = body[2]
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)
br3 = body[4]
href = body[5]
self.assertEqual(href.tag, 'a')
br4 = body[6]
br5 = body[7]
img = body[8]
self.assertEqual(img.tag, 'img')
def test_dupe_meldids_fails_parse_xml(self):
meld_ns = "http://www.plope.com/software/meld3"
repeated = ('<html xmlns:meld="%s" meld:id="repeat">'
'<body meld:id="repeat"/></html>' % meld_ns)
self.assertRaises(ValueError, self._parse, repeated)
def test_dupe_meldids_fails_parse_html(self):
meld_ns = "http://www.plope.com/software/meld3"
repeated = ('<html xmlns:meld="%s" meld:id="repeat">'
'<body meld:id="repeat"/></html>' % meld_ns)
self.assertRaises(ValueError, self._parse_html, repeated)
class UtilTests(unittest.TestCase):
def test_insert_xhtml_doctype(self):
from . import insert_doctype
orig = '<root></root>'
actual = insert_doctype(orig)
expected = '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><root></root>'
self.assertEqual(actual, expected)
def test_insert_doctype_after_xmldecl(self):
from . import insert_doctype
orig = '<?xml version="1.0" encoding="latin-1"?><root></root>'
actual = insert_doctype(orig)
expected = '<?xml version="1.0" encoding="latin-1"?><!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><root></root>'
self.assertEqual(actual, expected)
def test_insert_meld_ns_decl(self):
from . import insert_meld_ns_decl
orig = '<?xml version="1.0" encoding="latin-1"?><root></root>'
actual = insert_meld_ns_decl(orig)
expected = '<?xml version="1.0" encoding="latin-1"?><root xmlns:meld="http://www.plope.com/software/meld3"></root>'
self.assertEqual(actual, expected)
def test_prefeed_preserves_existing_meld_ns(self):
from . import prefeed
orig = '<?xml version="1.0" encoding="latin-1"?><root xmlns:meld="#"></root>'
actual = prefeed(orig)
expected = '<?xml version="1.0" encoding="latin-1"?><!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><root xmlns:meld="#"></root>'
self.assertEqual(actual, expected)
def test_prefeed_preserves_existing_doctype(self):
from . import prefeed
orig = '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"><root xmlns:meld="http://www.plope.com/software/meld3"></root>'
actual = prefeed(orig)
self.assertEqual(actual, orig)
class WriterTests(unittest.TestCase):
def _parse(self, xml):
from . import parse_xmlstring
root = parse_xmlstring(xml)
return root
def _parse_html(self, xml):
from . import parse_htmlstring
root = parse_htmlstring(xml)
return root
def _write(self, fn, **kw):
try:
from io import BytesIO
except: # python 2.5
from StringIO import StringIO as BytesIO
out = BytesIO()
fn(out, **kw)
out.seek(0)
actual = out.read()
return actual
def _write_xml(self, node, **kw):
return self._write(node.write_xml, **kw)
def _write_html(self, node, **kw):
return self._write(node.write_html, **kw)
def _write_xhtml(self, node, **kw):
return self._write(node.write_xhtml, **kw)
def assertNormalizedXMLEqual(self, a, b):
from ._compat import _u
a = normalize_xml(_u(a))
b = normalize_xml(_u(b))
self.assertEqual(a, b)
def assertNormalizedHTMLEqual(self, a, b):
from ._compat import _u
a = normalize_xml(_u(a))
b = normalize_xml(_u(b))
self.assertEqual(a, b)
def test_write_simple_xml(self):
root = self._parse(_SIMPLE_XML)
actual = self._write_xml(root)
expected = """<?xml version="1.0"?><root>
<list>
<item>
<name>Name</name>
<description>Description</description>
</item>
</list>
</root>"""
self.assertNormalizedXMLEqual(actual, expected)
for el, data in root.findmeld('item').repeat(((1,2),)):
el.findmeld('name').text = str(data[0])
el.findmeld('description').text = str(data[1])
actual = self._write_xml(root)
expected = """<?xml version="1.0"?><root>
<list>
<item>
<name>1</name>
<description>2</description>
</item>
</list>
</root>"""
self.assertNormalizedXMLEqual(actual, expected)
def test_write_simple_xhtml(self):
root = self._parse(_SIMPLE_XHTML)
actual = self._write_xhtml(root)
expected = """<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html><body>Hello!</body></html>"""
self.assertNormalizedXMLEqual(actual, expected)
def test_write_simple_xhtml_as_html(self):
root = self._parse(_SIMPLE_XHTML)
actual = self._write_html(root)
expected = """<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<body>Hello!</body>
</html>"""
self.assertNormalizedHTMLEqual(actual, expected)
def test_write_complex_xhtml_as_html(self):
root = self._parse(_COMPLEX_XHTML)
actual = self._write_html(root)
expected = """<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta content="text/html; charset=ISO-8859-1" http-equiv="content-type">
<title>This will be escaped in html output: &</title>
<script>this won't be escaped in html output: &</script>
<script type="text/javascript">
//
// this won't be escaped in html output
function match(a,b) {
if (a < b && a > 0) then { return 1 }
}
//
</script>
<style>this won't be escaped in html output: &</style>
</head>
<!-- a comment -->
<body>
<div></div>
<div>
<form action="." method="POST">
<img src="foo.gif">
<table border="0">
<tbody>
<tr class="foo">
<td>Name</td>
<td>Description</td>
</tr>
</tbody>
</table>
<input name="submit" type="submit" value=" Next ">
</form>
</div>
</body>
</html>"""
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 = """<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html>
<head>
<meta content="text/html; charset=ISO-8859-1" http-equiv="content-type" />
<title>This will be escaped in html output: &</title>
<script>this won't be escaped in html output: &</script>
<script type="text/javascript">
//
// this won't be escaped in html output
function match(a,b) {
if (a < b && a > 0) then { return 1 }
}
//
</script>
<style>this won't be escaped in html output: &</style>
</head>
<!-- a comment -->
<body>
<div ns0:baz="slab" xmlns:ns0="http://foo/bar" />
<div>
<form action="." method="POST">
<img src="foo.gif" />
<table border="0">
<tbody>
<tr class="foo">
<td>Name</td>
<td>Description</td>
</tr>
</tbody>
</table>
<input name="submit" type="submit" value=" Next " />
</form>
</div>
</body>
</html>"""
self.assertNormalizedXMLEqual(actual, expected)
def test_write_emptytags_html(self):
from ._compat import _u
root = self._parse(_EMPTYTAGS_HTML)
actual = self._write_html(root)
expected = """<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<body>
<area><base><basefont><br><col><frame><hr><img><input><isindex>
<link><meta><param>
</body>
</html>"""
self.assertEqual(_u(actual), expected)
def test_write_booleanattrs_xhtml_as_html(self):
root = self._parse(_BOOLEANATTRS_XHTML)
actual = self._write_html(root)
expected = """<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<body>
<tag selected></tag>
<tag checked></tag>
<tag compact></tag>
<tag declare></tag>
<tag defer></tag>
<tag disabled></tag>
<tag ismap></tag>
<tag multiple></tag>
<tag nohref></tag>
<tag noresize></tag>
<tag noshade></tag>
<tag nowrap></tag>
</body>
</html>"""
self.assertNormalizedHTMLEqual(actual, expected)
def test_write_simple_xhtml_pipeline(self):
root = self._parse(_SIMPLE_XHTML)
actual = self._write_xhtml(root, pipeline=True)
expected = """<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html><body ns0:id="body" xmlns:ns0="http://www.plope.com/software/meld3">Hello!</body></html>"""
self.assertNormalizedXMLEqual(actual, expected)
def test_write_simple_xml_pipeline(self):
root = self._parse(_SIMPLE_XML)
actual = self._write_xml(root, pipeline=True)
expected = """<?xml version="1.0"?><root>
<list ns0:id="list" xmlns:ns0="http://www.plope.com/software/meld3">
<item ns0:id="item">
<name ns0:id="name">Name</name>
<description ns0:id="description">Description</description>
</item>
</list>
</root>"""
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 = """<?xml version="1.0" encoding="latin-1"?><root>
<list>
<item>
<name>Name</name>
<description>Description</description>
</item>
</list>
</root>"""
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 = """<root>
<list>
<item>
<name>Name</name>
<description>Description</description>
</item>
</list>
</root>"""
self.assertNormalizedXMLEqual(actual, expected)
def test_write_simple_xml_with_doctype(self):
root = self._parse(_SIMPLE_XML)
from . import doctype
actual = self._write_xml(root, doctype=doctype.xhtml)
expected = """<?xml version="1.0"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><root>
<list>
<item>
<name>Name</name>
<description>Description</description>
</item>
</list>
</root>"""
self.assertNormalizedXMLEqual(actual, expected)
def test_write_simple_xml_doctype_nodeclaration(self):
root = self._parse(_SIMPLE_XML)
from . import doctype
actual = self._write_xml(root, declaration=False,
doctype=doctype.xhtml)
expected = """<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><root>
<list>
<item>
<name>Name</name>
<description>Description</description>
</item>
</list>
</root>"""
self.assertNormalizedXMLEqual(actual, expected)
def test_write_simple_xml_fragment_kills_doctype_and_declaration(self):
root = self._parse(_SIMPLE_XML)
from . import doctype
actual = self._write_xml(root, declaration=True,
doctype=doctype.xhtml, fragment=True)
expected = """<root>
<list>
<item>
<name>Name</name>
<description>Description</description>
</item>
</list>
</root>"""
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 = """<?xml version="1.0" encoding="latin-1"?><!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html><body>Hello!</body></html>"""
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 = """<html><body>Hello!</body></html>"""
self.assertNormalizedXMLEqual(actual, expected)
def test_write_simple_xhtml_with_doctype(self):
root = self._parse(_SIMPLE_XHTML)
from . import doctype
actual = self._write_xhtml(root, doctype=doctype.xhtml)
expected = """<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html><body>Hello!</body></html>"""
self.assertNormalizedXMLEqual(actual, expected)
def test_write_simple_xhtml_doctype_nodeclaration(self):
root = self._parse(_SIMPLE_XHTML)
from . import doctype
actual = self._write_xhtml(root, declaration=False,
doctype=doctype.xhtml)
expected = """<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html><body>Hello!</body></html>"""
self.assertNormalizedXMLEqual(actual, expected)
def test_write_simple_xhtml_fragment_kills_doctype_and_declaration(self):
root = self._parse(_SIMPLE_XHTML)
from . import doctype
actual = self._write_xhtml(root, declaration=True,
doctype=doctype.xhtml, fragment=True)
expected = """<html><body>Hello!</body></html>"""
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 = """<html><body>Hello!</body></html>"""
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 = """
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html><body>Hello!</body></html>"""
self.assertNormalizedXMLEqual(actual, expected)
def test_write_simple_xhtml_as_html_new_doctype(self):
root = self._parse(_SIMPLE_XHTML)
from . import doctype
actual = self._write_html(root, doctype=doctype.html_strict)
expected = """
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html><body>Hello!</body></html>"""
self.assertNormalizedXMLEqual(actual, expected)
def test_write_entities_xhtml_no_doctype(self):
root = self._parse_html(_ENTITIES_XHTML)
# this will be considered an XHTML document by default; we needn't
# declare a doctype
actual = self._write_xhtml(root)
expected =r"""<html>
<head></head>
<body>
<!-- test entity references -->
<p> </p>
</body>
</html>"""
def test_write_entities_xhtml_with_doctype(self):
dt = '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">'
root = self._parse_html(dt + _ENTITIES_XHTML)
actual = self._write_xhtml(root)
expected =r"""<html>
<head></head>
<body>
<!-- test entity references -->
<p> </p>
</body>
</html>"""
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,
'<html><head></head><body>&fleeb;</body></html>')
def test_content_nostructure(self):
root = self._parse(_SIMPLE_XML)
D = root.findmeld('description')
D.content('description &<foo>&<bar>', structure=False)
actual = self._write_xml(root)
expected = """<?xml version="1.0"?>
<root>
<list>
<item>
<name>Name</name>
<description>description &<foo>&<bar></description>
</item>
</list>
</root>"""
self.assertNormalizedXMLEqual(actual, expected)
def test_content_structure(self):
root = self._parse(_SIMPLE_XML)
D = root.findmeld('description')
D.content('description &<foo> <bar>', structure=True)
actual = self._write_xml(root)
expected = """<?xml version="1.0"?>
<root>
<list>
<item>
<name>Name</name>
<description>description &<foo> <bar></description>
</item>
</list>
</root>"""
self.assertNormalizedXMLEqual(actual, expected)
def test_replace_nostructure(self):
root = self._parse(_SIMPLE_XML)
D = root.findmeld('description')
D.replace('description &<foo>&<bar>', structure=False)
actual = self._write_xml(root)
expected = """<?xml version="1.0"?>
<root>
<list>
<item>
<name>Name</name>
description &<foo>&<bar>
</item>
</list>
</root>"""
self.assertNormalizedXMLEqual(actual, expected)
def test_replace_structure(self):
root = self._parse(_SIMPLE_XML)
D = root.findmeld('description')
D.replace('description &<foo> <bar>', structure=True)
actual = self._write_xml(root)
expected = """<?xml version="1.0"?>
<root>
<list>
<item>
<name>Name</name>
description &<foo> <bar>
</item>
</list>
</root>"""
self.assertNormalizedXMLEqual(actual, expected)
def test_escape_cdata(self):
from ._compat import _b
from . import _escape_cdata
a = ('< > <& &' && &foo "" '
'http://www.plope.com?foo=bar&bang=baz {')
self.assertEqual(
_b('< > <& &' && &foo "" '
'http://www.plope.com?foo=bar&bang=baz {'),
_escape_cdata(a))
def test_escape_cdata_unicodeerror(self):
from . import _escape_cdata
from ._compat import _b
from ._compat import _u
a = _u(_b('\x80'))
self.assertEqual(_b('€'), _escape_cdata(a, 'ascii'))
def test_escape_attrib(self):
from . import _escape_attrib
from ._compat import _b
a = ('< > <& &' && &foo "" '
'http://www.plope.com?foo=bar&bang=baz {')
self.assertEqual(
_b('< > <& &' '
'&& &foo "" '
'http://www.plope.com?foo=bar&bang=baz {'),
_escape_attrib(a, None))
def test_escape_attrib_unicodeerror(self):
from . import _escape_attrib
from ._compat import _b
from ._compat import _u
a = _u(_b('\x80'))
self.assertEqual(_b('€'), _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()
Zerion Mini Shell 1.0