MoinLight

Annotated tests/test_parser.py

85:15c19a3d61e9
2018-07-24 Paul Boddie Introduced families of serialisers for each output format, with parser-specific serialisers retaining knowledge of how their document tree nodes are to be serialised. Introduced a get_serialiser function as a convenience to replace general access to the all_serialisers dictionary. Changed the dynamic import mechanism to qualify identified module names using package name information.
paul@0 1
#!/usr/bin/env python
paul@0 2
paul@65 3
from os.path import abspath, exists, join, split
paul@44 4
import sys
paul@44 5
paul@44 6
dirname = split(abspath(sys.argv[0]))[0]
paul@44 7
parent = split(dirname)[0]
paul@44 8
paul@44 9
try:
paul@44 10
    import moinformat
paul@44 11
except ImportError:
paul@44 12
    if split(parent)[1] == "MoinLight":
paul@44 13
        sys.path.append(parent)
paul@44 14
paul@85 15
from moinformat import all_parsers, get_serialiser, parse, serialise
paul@83 16
from moinformat.tree.moin import Container
paul@26 17
from glob import glob
paul@16 18
paul@65 19
def test_input(d, s):
paul@65 20
paul@65 21
    "Compare serialised output from 'd' with its original form 's'."
paul@65 22
paul@26 23
    o = serialise(d)
paul@12 24
paul@60 25
    identical = o == s
paul@38 26
paul@38 27
    if quiet:
paul@60 28
        return identical
paul@38 29
paul@60 30
    # Show output versus input comparison result.
paul@60 31
paul@60 32
    print identical
paul@26 33
    print "-" * 60
paul@26 34
    print o
paul@65 35
    if not identical:
paul@26 36
        print "-" * 60
paul@26 37
        print s
paul@26 38
    print "-" * 60
paul@85 39
    print serialise(d, get_serialiser("html"))
paul@26 40
    print "-" * 60
paul@26 41
    print
paul@20 42
paul@60 43
    return identical
paul@60 44
paul@65 45
def test_tree(d, t, ts):
paul@65 46
paul@65 47
    "Compare tree structure 'd' with simplified, expected form 't' from 'ts'."
paul@65 48
paul@65 49
    failing = t.test(d)
paul@65 50
paul@65 51
    if quiet:
paul@65 52
        return not failing
paul@65 53
paul@65 54
    # Show tree versus expected forms.
paul@65 55
paul@65 56
    print not failing
paul@65 57
    print "-" * 60
paul@65 58
    print d.prettyprint()
paul@65 59
    if failing:
paul@68 60
        print "-" * 60
paul@68 61
        print ts
paul@68 62
        simple, tree, error = failing
paul@68 63
        print "-" * 60
paul@68 64
        print error
paul@68 65
        print repr(simple)
paul@68 66
        print repr(tree)
paul@65 67
        print "-" * 60
paul@65 68
        print tree.prettyprint()
paul@65 69
        print "-" * 60
paul@65 70
        print simple.prettyprint()
paul@65 71
    print "-" * 60
paul@65 72
    print
paul@65 73
paul@65 74
    return not failing
paul@65 75
paul@65 76
class Node:
paul@65 77
paul@65 78
    "A simplified tree node representation."
paul@65 79
paul@65 80
    def __init__(self, name):
paul@65 81
        self.name = name
paul@65 82
        self.nodes = []
paul@65 83
paul@65 84
    def __repr__(self):
paul@68 85
        return "Node(%r, %r)" % (self.name, self.nodes)
paul@65 86
paul@65 87
    def prettyprint(self, indent=""):
paul@68 88
        l = []
paul@68 89
        l.append("%s%s%s" % (indent, self.name, len(self.nodes) and " nodes=%d" % len(self.nodes) or ""))
paul@65 90
        for node in self.nodes:
paul@65 91
            l.append(node.prettyprint(indent + "  "))
paul@65 92
        return "\n".join(l)
paul@65 93
paul@65 94
    def append(self, node):
paul@65 95
        self.nodes.append(node)
paul@65 96
paul@65 97
    def test(self, other):
paul@65 98
paul@65 99
        """
paul@65 100
        Test whether this node is considered equivalent to 'other', where
paul@65 101
        'other' is a moinparser.tree node.
paul@65 102
paul@65 103
        Return any failing tree nodes or None.
paul@65 104
        """
paul@65 105
paul@65 106
        if other.__class__.__name__ != self.name:
paul@68 107
            return self, other, "name"
paul@65 108
paul@65 109
        if isinstance(other, Container):
paul@65 110
            for node, other_node in map(None, self.nodes, other.nodes):
paul@65 111
                if node is None or other_node is None:
paul@68 112
                    return self, other, node is None and "simple" or "document"
paul@68 113
                t = node.test(other_node)
paul@68 114
                if t:
paul@68 115
                    return t
paul@68 116
        elif self.nodes:
paul@68 117
            return self, other, "empty"
paul@65 118
paul@65 119
        return None
paul@65 120
paul@65 121
def parse_tree(s):
paul@65 122
paul@65 123
    "Parse the tree structure representation in 's'."
paul@65 124
paul@65 125
    indent = 0
paul@65 126
    branches = []
paul@65 127
paul@65 128
    for line in s.split("\n"):
paul@65 129
        line = line.rstrip()
paul@65 130
        if not line:
paul@65 131
            continue
paul@65 132
paul@65 133
        new_indent = line.rfind(" ") + 1
paul@65 134
        node = Node(line[new_indent:])
paul@65 135
paul@65 136
        # Establish a branch to add nodes to.
paul@65 137
paul@65 138
        if not branches:
paul@65 139
            branches.append(node)
paul@65 140
        else:
paul@65 141
            # Note the current node as outermost branch.
paul@65 142
paul@65 143
            if new_indent > indent:
paul@65 144
                branches.append(node)
paul@65 145
            else:
paul@65 146
                # Reduced indent involves obtaining an inner branch again.
paul@65 147
paul@65 148
                while indent > new_indent:
paul@65 149
                    del branches[-1]
paul@65 150
                    indent -= 2
paul@65 151
paul@65 152
                # Note the current node as outermost branch.
paul@65 153
paul@65 154
                branches[-1] = node
paul@65 155
paul@65 156
            # Append the current node to the parent branch.
paul@65 157
paul@65 158
            branches[-2].append(node)
paul@65 159
paul@65 160
        indent = new_indent
paul@65 161
paul@65 162
    return branches[0]
paul@65 163
paul@65 164
def readfile(filename):
paul@65 165
paul@65 166
    "Read the contents of 'filename' and return them."
paul@65 167
paul@65 168
    f = open(filename)
paul@65 169
    try:
paul@65 170
        return f.read()
paul@65 171
    finally:
paul@65 172
        f.close()
paul@65 173
paul@26 174
if __name__ == "__main__":
paul@38 175
    args = sys.argv[1:]
paul@65 176
paul@38 177
    quiet = "-q" in args
paul@38 178
    if quiet:
paul@38 179
        del args[args.index("-q")]
paul@65 180
paul@38 181
    filenames = args or glob(join(dirname, "test*.txt"))
paul@26 182
    filenames.sort()
paul@0 183
paul@26 184
    for filename in filenames:
paul@65 185
        tree_filename = "%s.tree" % filename.rsplit(".", 1)[0]
paul@65 186
paul@65 187
        s = readfile(filename)
paul@65 188
        d = parse(s, all_parsers)
paul@65 189
paul@65 190
        if exists(tree_filename):
paul@65 191
            ts = readfile(tree_filename)
paul@65 192
            t = parse_tree(ts)
paul@65 193
        else:
paul@65 194
            ts = None
paul@65 195
paul@65 196
        if not quiet:
paul@65 197
            print filename
paul@65 198
paul@65 199
        identical = test_input(d, s)
paul@65 200
        tree_identical = ts and test_tree(d, t, ts)
paul@65 201
paul@65 202
        if quiet:
paul@65 203
            print "%s %s: %s" % (identical, tree_identical, filename)
paul@3 204
paul@0 205
# vim: tabstop=4 expandtab shiftwidth=4