-
Notifications
You must be signed in to change notification settings - Fork 208
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add some tests to catch failing XML serialisation, #103
- Loading branch information
1 parent
55c8fae
commit 2ef0ce4
Showing
2 changed files
with
207 additions
and
6 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,97 @@ | ||
import re | ||
from xml.dom.minidom import Node, parseString | ||
|
||
|
||
def strip_quotes(want, got): | ||
""" | ||
Strip quotes of doctests output values: | ||
>>> strip_quotes("'foo'") | ||
"foo" | ||
>>> strip_quotes('"foo"') | ||
"foo" | ||
""" | ||
def is_quoted_string(s): | ||
s = s.strip() | ||
return (len(s) >= 2 | ||
and s[0] == s[-1] | ||
and s[0] in ('"', "'")) | ||
|
||
def is_quoted_unicode(s): | ||
s = s.strip() | ||
return (len(s) >= 3 | ||
and s[0] == 'u' | ||
and s[1] == s[-1] | ||
and s[1] in ('"', "'")) | ||
|
||
if is_quoted_string(want) and is_quoted_string(got): | ||
want = want.strip()[1:-1] | ||
got = got.strip()[1:-1] | ||
elif is_quoted_unicode(want) and is_quoted_unicode(got): | ||
want = want.strip()[2:-1] | ||
got = got.strip()[2:-1] | ||
return want, got | ||
|
||
|
||
def compare_xml(want, got): | ||
"""Tries to do a 'xml-comparison' of want and got. Plain string | ||
comparison doesn't always work because, for example, attribute | ||
ordering should not be important. Comment nodes are not considered in the | ||
comparison. | ||
Based on http://codespeak.net/svn/lxml/trunk/src/lxml/doctestcompare.py | ||
""" | ||
_norm_whitespace_re = re.compile(r'[ \t\n][ \t\n]+') | ||
|
||
def norm_whitespace(v): | ||
return _norm_whitespace_re.sub(' ', v) | ||
|
||
def child_text(element): | ||
return ''.join(c.data for c in element.childNodes | ||
if c.nodeType == Node.TEXT_NODE) | ||
|
||
def children(element): | ||
return [c for c in element.childNodes | ||
if c.nodeType == Node.ELEMENT_NODE] | ||
|
||
def norm_child_text(element): | ||
return norm_whitespace(child_text(element)) | ||
|
||
def attrs_dict(element): | ||
return dict(element.attributes.items()) | ||
|
||
def check_element(want_element, got_element): | ||
if want_element.tagName != got_element.tagName: | ||
return False | ||
if norm_child_text(want_element) != norm_child_text(got_element): | ||
return False | ||
if attrs_dict(want_element) != attrs_dict(got_element): | ||
return False | ||
want_children = children(want_element) | ||
got_children = children(got_element) | ||
if len(want_children) != len(got_children): | ||
return False | ||
for want, got in zip(want_children, got_children): | ||
if not check_element(want, got): | ||
return False | ||
return True | ||
|
||
def first_node(document): | ||
for node in document.childNodes: | ||
if node.nodeType != Node.COMMENT_NODE: | ||
return node | ||
|
||
want, got = strip_quotes(want, got) | ||
want = want.replace('\\n', '\n') | ||
got = got.replace('\\n', '\n') | ||
|
||
# If the string is not a complete xml document, we may need to add a | ||
# root element. This allow us to compare fragments, like "<foo/><bar/>" | ||
if not want.startswith('<?xml'): | ||
wrapper = '<root>%s</root>' | ||
want = wrapper % want | ||
got = wrapper % got | ||
|
||
# Parse the want and got strings, and compare the parsings. | ||
want_root = first_node(parseString(want)) | ||
got_root = first_node(parseString(got)) | ||
|
||
return check_element(want_root, got_root) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters