Subversion Repositories wimsdev

Rev

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