formencode.doctest_xml_compare
Covered: 36 lines
Missed: 82 lines
Skipped 13 lines
Percent: 30 %
  1
try:
  2
    import doctest
  3
    doctest.OutputChecker
  4
except AttributeError:
  5
    import util.doctest24 as doctest
  6
try:
  7
    import xml.etree.ElementTree as ET
  8
except ImportError:
  9
    import elementtree.ElementTree as ET
 10
from xml.parsers.expat import ExpatError as XMLParseError
 12
RealOutputChecker = doctest.OutputChecker
 14
def debug(*msg):
 15
    import sys
 16
    print >> sys.stderr, ' '.join(map(str, msg))
 18
class HTMLOutputChecker(RealOutputChecker):
 20
    def check_output(self, want, got, optionflags):
 21
        normal = RealOutputChecker.check_output(self, want, got, optionflags)
 22
        if normal or not got:
 23
            return normal
 24
        try:
 25
            want_xml = make_xml(want)
 26
        except XMLParseError, e:
 27
            pass
 28
        else:
 29
            try:
 30
                got_xml = make_xml(got)
 31
            except XMLParseError:
 32
                pass
 33
            else:
 34
                if xml_compare(want_xml, got_xml):
 35
                    return True
 36
        return False
 38
    def output_difference(self, example, got, optionflags):
 39
        actual = RealOutputChecker.output_difference(
 40
            self, example, got, optionflags)
 41
        want_xml = got_xml = None
 42
        try:
 43
            want_xml = make_xml(example.want)
 44
            want_norm = make_string(want_xml)
 45
        except XMLParseError, e:
 46
            if example.want.startswith('<'):
 47
                want_norm = '(bad XML: %s)' % e
 49
            else:
 50
                return actual
 51
        try:
 52
            got_xml = make_xml(got)
 53
            got_norm = make_string(got_xml)
 54
        except XMLParseError, e:
 55
            if example.want.startswith('<'):
 56
                got_norm = '(bad XML: %s)' % e
 57
            else:
 58
                return actual
 59
        s = '%s\nXML Wanted: %s\nXML Got   : %s\n' % (
 60
            actual, want_norm, got_norm)
 61
        if got_xml and want_xml:
 62
            result = []
 63
            xml_compare(want_xml, got_xml, result.append)
 64
            s += 'Difference report:\n%s\n' % '\n'.join(result)
 65
        return s
 67
def xml_compare(x1, x2, reporter=None):
 68
    if x1.tag != x2.tag:
 69
        if reporter:
 70
            reporter('Tags do not match: %s and %s' % (x1.tag, x2.tag))
 71
        return False
 72
    for name, value in x1.attrib.items():
 73
        if x2.attrib.get(name) != value:
 74
            if reporter:
 75
                reporter('Attributes do not match: %s=%r, %s=%r'
 76
                         % (name, value, name, x2.attrib.get(name)))
 77
            return False
 78
    for name in x2.attrib.keys():
 79
        if not x1.attrib.has_key(name):
 80
            if reporter:
 81
                reporter('x2 has an attribute x1 is missing: %s'
 82
                         % name)
 83
            return False
 84
    if not text_compare(x1.text, x2.text):
 85
        if reporter:
 86
            reporter('text: %r != %r' % (x1.text, x2.text))
 87
        return False
 88
    if not text_compare(x1.tail, x2.tail):
 89
        if reporter:
 90
            reporter('tail: %r != %r' % (x1.tail, x2.tail))
 91
        return False
 92
    cl1 = x1.getchildren()
 93
    cl2 = x2.getchildren()
 94
    if len(cl1) != len(cl2):
 95
        if reporter:
 96
            reporter('children length differs, %i != %i'
 97
                     % (len(cl1), len(cl2)))
 98
        return False
 99
    i = 0
100
    for c1, c2 in zip(cl1, cl2):
101
        i += 1
102
        if not xml_compare(c1, c2, reporter=reporter):
103
            if reporter:
104
                reporter('children %i do not match: %s'
105
                         % (i, c1.tag))
106
            return False
107
    return True
109
def text_compare(t1, t2):
110
    if not t1 and not t2:
111
        return True
112
    if t1 == '*' or t2 == '*':
113
        return True
114
    return (t1 or '').strip() == (t2 or '').strip()
116
def make_xml(s):
117
    return ET.XML('<xml>%s</xml>' % s)
119
def make_string(xml):
120
    if isinstance(xml, (str, unicode)):
121
        xml = make_xml(xml)
122
    s = ET.tostring(xml)
123
    if s == '<xml />':
124
        return ''
125
    assert s.startswith('<xml>') and s.endswith('</xml>'), repr(s)
126
    return s[5:-6]
128
def install():
129
    doctest.OutputChecker = HTMLOutputChecker