Subversion Repositories wimsdev

Rev

Rev 8192 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
8192 georgesk 1
#!/usr/bin/python3
2
 
3
import os, os.path, tempfile, re, copy, subprocess, locale
4
 
10454 obado 5
titlePattern = re.compile(r"^== (.*) ==$")
6
varPattern = re.compile(r"^(.*) == (.*)$")
7
rulePattern = re.compile(r"^----.*$")
8
commentPattern = re.compile(r"^\s*#.*$")
9
codingPattern = re.compile(r"^# -\*- coding: (.*) -\*-$")
8192 georgesk 10
 
11
locale.setlocale(locale.LC_ALL, '')
10454 obado 12
codeset = locale.nl_langinfo(locale.CODESET)  # coding used by the user's locale
8192 georgesk 13
 
10454 obado 14
 
8192 georgesk 15
def notAtest(f):
16
    """
17
    consider some filenames as not useable to perfom tests.
18
    @param f a filename
19
    @return True if f seems to be the name of a backup file
20
    """
10454 obado 21
    return re.match(r".*~", f) or re.match(r".*\.bak", f)
8192 georgesk 22
 
10454 obado 23
 
8192 georgesk 24
def mkTestList(lines, cur, title, coding="utf-8"):
25
    """
26
    makes a list of objects for unitary tests of Wims modtool primitives
27
    @param lines a list of lines coming from a file
28
    @param cur a pointer on the current line to be read
29
    @param title a title which has been read from a previous line
30
    @param coding the coding of the .proc file used for tests
31
    @return a list of Test objects
32
    """
10454 obado 33
    result = []
34
    proclines = []
35
    variables = {}
36
    currentVar = None
8192 georgesk 37
    while cur < len(lines):
10454 obado 38
        l = lines[cur].decode(coding).replace('\n', '')
39
        t = titlePattern.match(l)
40
        v = varPattern.match(l)
41
        r = rulePattern.match(l)
42
        c = commentPattern.match(l)
8192 georgesk 43
        if t:
44
            result.append(Test(title, proclines, variables, coding))
10454 obado 45
            title = t.group(1)
46
            proclines = []
47
            variables = {}
48
            currentVar = None
8192 georgesk 49
        elif v:
10454 obado 50
            currentVar = v.group(1)
51
            variables[currentVar] = v.group(2)
52
        elif currentVar is not None and len(l) > 0:
53
            variables[currentVar] += '\n' + l
54
        elif not r and not c:
8192 georgesk 55
            # not a title, nor variable, nor a ruler, nor a comment:
56
            # these are commands
57
            proclines.append(lines[cur].strip())
10454 obado 58
        cur = cur + 1
8192 georgesk 59
    result.append(Test(title, proclines, variables, coding))
60
    return result
61
 
10454 obado 62
 
8192 georgesk 63
class Test:
64
    """
65
    This class implements data for a unitary test of Wims.
66
    Each test has a title, a set of lines to be pasted into
67
    a .proc file for Wims, and a set assertions about
68
    variables and the values which they should be assigned
69
    upon completion of the test.
70
    """
71
    def __init__(self, title, proclines, variables, coding="utf-8"):
72
        """
73
        The constructor.
74
        @param title a title for the unitary test
75
        @param proclines a list of lines to be processed by Wims in a
76
        .proc file.
77
        @param variables a dictionary associating variable names with
78
        values they should have when the test finishes.
79
        @param coding the coding used for the .proc file
80
        """
10454 obado 81
        self.title = "" + title
82
        self.proclines = copy.copy(proclines)
83
        self.variables = copy.copy(variables)
84
        self.coding = coding
85
        self.gotResults = {}
86
        self.errors = []
87
        self.success = None
8192 georgesk 88
 
89
    def __str__(self):
90
        """
91
        Conversion to a str.
92
        """
10454 obado 93
        result = "Test {title=«%s»," % (self.title,)
94
        result += " coding=%s," % self.coding
95
        result += " proclines=%s," % self.proclines
96
        result += " variables=%s" % self.variables
97
        result += "}"
8192 georgesk 98
        return result
99
 
100
    def __repr__(self):
101
        """
102
        The representation is the same as the conversion to a str.
103
        """
104
        return self.__str__()
10454 obado 105
 
8192 georgesk 106
    def gotError(self):
107
        """
108
        checks whether some error occurred
109
        @return True if an error came out of the wims subprocess
110
        """
10454 obado 111
        return len(self.errors) > 1 or (len(self.errors) == 1 and
112
                                        self.errors[0] != "")
8192 georgesk 113
 
114
    def run(self, path, fName="test.proc"):
115
        """
116
        runs the unitary tests, and gather the results in
117
        self.gotResults, self.errors and self.success
118
        @param path a path to the .proc file
119
        @param fName the name of the .proc file, defaults to "test.proc"
120
        """
10454 obado 121
        self.success = True
122
        self.failedVars = []
123
        cmd = "./wims test %s %s '%s'" % (path,
124
                                          fName,
125
                                          ' '.join([v for v in self.variables]))
126
        with open(os.path.join(path, fName), "wb") as outfile:
8192 georgesk 127
            for l in self.proclines:
10454 obado 128
                outfile.write(l + b'\n')
8192 georgesk 129
            outfile.close()
10454 obado 130
            p = subprocess.Popen(cmd,
131
                                 shell=True,
132
                                 stdout=subprocess.PIPE,
133
                                 stderr=subprocess.PIPE)
8192 georgesk 134
            out, err = p.communicate()
10454 obado 135
            currentVar = None
8192 georgesk 136
            for l in out.decode(self.coding).split("\n"):
10454 obado 137
                v = varPattern.match(l)
8192 georgesk 138
                if v:
10454 obado 139
                    currentVar = v.group(1)
140
                    self.gotResults[currentVar] = v.group(2)
8192 georgesk 141
                else:
10454 obado 142
                    if currentVar is not None and len(l) > 0:
8192 georgesk 143
                        # add an other line to the current variable
10454 obado 144
                        self.gotResults[currentVar] += '\n' + l
145
            self.errors = err.decode(codeset).split("\n")
8192 georgesk 146
            if self.gotError():
10454 obado 147
                self.success = False
8192 georgesk 148
            for v in self.variables:
10454 obado 149
                if v not in self.gotResults or self.variables[v] != self.gotResults[v]:
8192 georgesk 150
                    self.failedVars.append(v)
10454 obado 151
                    self.success = False
8192 georgesk 152
 
153
    def showResult(self, msg="", tmpDir="/tmp"):
154
        """
155
        runs the test if self.success is undefined, and
156
        pretty-prints the result
157
        @param msg a message string to prepend to the result (for instance,
158
        a test number)
159
        @param tmpDir a directory to run the tests
160
        """
10454 obado 161
        if self.success is None:
8192 georgesk 162
            self.run(tmpDir)
163
        if self.success:
10454 obado 164
            print("[%s] %s: OK." % (msg, self.title))
8192 georgesk 165
        else:
10454 obado 166
            hrule = "[%s] ========< %s >==========" % (msg, self.title)
8192 georgesk 167
            print(hrule)
168
            for l in self.proclines:
169
                print(l)
10454 obado 170
            hrule = "=" * len(hrule)
8192 georgesk 171
            print(hrule)
172
            if self.gotError():
10454 obado 173
                print ("ERROR: %s" % self.errors)
8192 georgesk 174
            for v in self.failedVars:
175
                if v in self.gotResults:
10454 obado 176
                    print("FAILED for variable %s, expected: «%s»; got: «%s»"
177
                          % (v, self.variables[v], self.gotResults[v]))
8192 georgesk 178
                else:
10454 obado 179
                    print("FAILED for variable %s, expected: «%s»; got nothing"
180
                          % (v, self.variables[v]))
8192 georgesk 181
                for v in self.variables:
182
                    if v not in self.failedVars:
10454 obado 183
                        print("OK for variable %s,  expected: «%s»; got: «%s»"
184
                              % (v, self.variables[v], self.gotResults[v]))
8192 georgesk 185
                print(hrule)
186
 
187
 
188
if __name__ == "__main__":
189
    print ("Test suite for Wims.")
190
    for dirpath, dirnames, filenames in os.walk("test"):
191
        for f in filenames:
192
            if notAtest(f):
193
                continue
10454 obado 194
            lines = open(os.path.join(dirpath, f), "rb").readlines()
195
            cur = 0
196
            t = titlePattern.match(lines[cur].decode("utf-8"))
197
            coding = "utf-8"  # default
8192 georgesk 198
            while cur < len(lines) and not t:
199
                # take in account coding declaration
10454 obado 200
                c = codingPattern.match(lines[cur].decode("utf-8"))
8192 georgesk 201
                if c:
10454 obado 202
                    coding = c.group(1)
203
                cur += 1
204
                t = titlePattern.match(lines[cur].decode(coding))
8192 georgesk 205
            if cur < len(lines):
206
                print("Running tests from {}/{} (coding: {})".format(dirpath, f, coding))
10454 obado 207
                title = t.group(1)
208
                tests = mkTestList(lines, cur, title, coding=coding)
8192 georgesk 209
                with tempfile.TemporaryDirectory(prefix='wimstest-') as tmpDir:
10454 obado 210
                    i = 1
211
                    ok = 0
212
                    nok = 0
8192 georgesk 213
                    for t in tests:
214
                        t.showResult(tmpDir=tmpDir, msg=i)
215
                        i += 1
216
                        if t.success:
10454 obado 217
                            ok += 1
8192 georgesk 218
                        else:
10454 obado 219
                            nok += 1
220
                print ("Ran {} tests; {} OK, {} WRONG.".format(i - 1, ok, nok))
8192 georgesk 221
            else:
10454 obado 222
                print("Error: the first line of the file should contain some == title ==")
8192 georgesk 223
                os.exit(1)