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