comparison tests/findregressions.d @ 186:395223f9875e trunk

[svn r202] added start of dstress-based test suite to tests/
author ChristianK
date Thu, 08 May 2008 22:32:22 +0200
parents
children 648409a7fb0c
comparison
equal deleted inserted replaced
185:89e21eeaf4c4 186:395223f9875e
1 // Based on DSTRESS code by Thomas Kühne
2
3 module findregressions;
4
5 private import std.string;
6 private import std.conv;
7 private import std.stdio;
8 private import std.stream;
9 private import std.file;
10 private import std.c.stdlib;
11 private import std.date;
12
13
14 enum Result{
15 UNTESTED = 0,
16 PASS = 1 << 2,
17 XFAIL = 2 << 2,
18 XPASS = 3 << 2,
19 FAIL = 4 << 2,
20 ERROR = 5 << 2,
21 BASE_MASK = 7 << 2,
22
23 EXT_MASK = 3,
24 BAD_MSG = 1,
25 BAD_GDB = 2,
26
27 MAX = BAD_GDB + BASE_MASK
28 }
29
30 char[] toString(Result r){
31 switch(r & Result.BASE_MASK){
32 case Result.PASS: return "PASS";
33 case Result.XPASS: return "XPASS";
34 case Result.FAIL: return "FAIL";
35 case Result.XFAIL: return "XFAIL";
36 case Result.ERROR: return "ERROR";
37 case Result.UNTESTED: return "UNTESTED";
38 default:
39 break;
40 }
41 throw new Exception(format("unhandled Result value %s", cast(int)r));
42 }
43
44 char[] dateString(){
45 static char[] date;
46 if(date is null){
47 auto time = getUTCtime();
48 auto year = YearFromTime(time);
49 auto month = MonthFromTime(time);
50 auto day = DateFromTime(time);
51 date = format("%d-%02d-%02d", year, month+1, day);
52 }
53 return date;
54 }
55
56 char[][] unique(char[][] a){
57 char[][] b = a.sort;
58 char[][] back;
59
60 back ~= b[0];
61
62 size_t ii=0;
63 for(size_t i=0; i<b.length; i++){
64 if(back[ii]!=b[i]){
65 back~=b[i];
66 ii++;
67 }
68 }
69
70 return back;
71 }
72
73 private{
74 version(Windows){
75 import std.c.windows.windows;
76 extern(Windows) BOOL GetFileTime(HANDLE hFile, LPFILETIME lpCreationTime, LPFILETIME lpLastAccessTime, LPFILETIME lpLastWriteTime);
77 }else version(linux){
78 import std.c.linux.linux;
79 version = Unix;
80 }else version(Unix){
81 import std.c.unix.unix;
82 }else{
83 static assert(0);
84 }
85
86 alias ulong FStime;
87
88 FStime getFStime(char[] fileName){
89 version(Windows){
90 HANDLE h;
91
92 if (useWfuncs){
93 wchar* namez = std.utf.toUTF16z(fileName);
94 h = CreateFileW(namez,GENERIC_WRITE,0,null,OPEN_ALWAYS,
95 FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN,cast(HANDLE)null);
96 }else{
97 char* namez = toMBSz(fileName);
98 h = CreateFileA(namez,GENERIC_WRITE,0,null,OPEN_ALWAYS,
99 FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN,cast(HANDLE)null);
100 }
101
102 if (h == INVALID_HANDLE_VALUE)
103 goto err;
104
105 FILETIME creationTime;
106 FILETIME accessTime;
107 FILETIME writeTime;
108
109 BOOL b = GetFileTime(h, &creationTime, &accessTime, &writeTime);
110 if(b==1){
111 long modA = writeTime.dwLowDateTime;
112 long modB = writeTime.dwHighDateTime;
113 return modA | (modB << (writeTime.dwHighDateTime.sizeof*8));
114 }
115
116 err:
117 CloseHandle(h);
118 throw new Exception("failed to query file modification : "~fileName);
119 }else version(Unix){
120 char* namez = toStringz(fileName);
121 struct_stat statbuf;
122
123 if(stat(namez, &statbuf)){
124 throw new FileException(fileName, getErrno());
125 }
126
127 return statbuf.st_mtime;
128 }else{
129 static assert(0);
130 }
131 }
132 }
133
134 char[] cleanFileName(char[] file){
135 char[] back;
136 bool hadSep;
137
138 foreach(char c; file){
139 if(c == '/' || c == '\\'){
140 if(!hadSep){
141 back ~= '/';
142 hadSep = true;
143 }
144 }else{
145 back ~= c;
146 hadSep = false;
147 }
148 }
149
150 size_t start = 0;
151 while(back[start] <= ' ' && start < back.length){
152 start++;
153 }
154
155 size_t end = back.length-1;
156 while(back[end] <= ' ' && end >= start){
157 end--;
158 }
159
160 back = back[start .. end+1];
161
162 return back;
163 }
164
165 class Test{
166 char[] name;
167 char[] file;
168 Result r;
169
170 this(char[] file){
171 this.file = file;
172
173 int start = rfind(file, "/");
174 if(start<0){
175 start = 0;
176 }else{
177 start += 1;
178 }
179
180 int end = rfind(file, ".");
181 if(end < start){
182 end = file.length;
183 }
184
185 name = file[start .. end];
186 }
187 }
188
189
190 class Log{
191 Test[char[]] tests;
192
193 char[] id;
194
195 this(char[] id){
196 this.id = id;
197 }
198
199
200 void dropBogusResults(FStime recordTime, char[] testRoot){
201 uint totalCount = tests.length;
202
203 char[][] sourcesTests = tests.keys;
204 foreach(char[] source; sourcesTests){
205 if(find(source, "complex/") < 0){
206 try{
207 FStime caseTime = getFStime(testRoot~std.path.sep~source);
208 if(caseTime > recordTime){
209 debug(drop) fwritefln(stderr, "dropped: %s", source);
210 tests.remove(source);
211 }
212 }catch(Exception e){
213 debug(drop) fwritefln(stderr, "dropped: %s", source);
214 tests.remove(source);
215 }
216 }
217 // asm-filter
218 int i = find(source, "asm_p");
219 if(i >= 0){
220 tests.remove(source);
221 }
222 }
223 tests.rehash;
224
225 writefln("dropped %s outdated tests (%s remaining)", totalCount - tests.length, tests.length);
226 }
227
228
229 bool add(char[] line){
230 const char[] SUB = "Torture-Sub-";
231 const char[] TORTURE = "Torture:";
232
233 line = strip(line);
234 int id = -1;
235 Result r = Result.UNTESTED;
236
237 if(line.length > SUB.length && line[0 .. SUB.length] == SUB){
238 line = line[SUB.length .. $];
239 id = 0;
240 while(line[id] >= '0' && line[id] <= '9'){
241 id++;
242 }
243 int start = id;
244 id = std.conv.toUint(line[0 .. id]);
245
246 while(line[start] != '-'){
247 start++;
248 }
249 line = line[start+1 .. $];
250 }
251
252 char[][] token = split(line);
253 if(token.length < 2){
254 return false;
255 }
256 char[] file = strip(token[1]);
257
258 switch(token[0]){
259 case "PASS:":
260 r = Result.PASS; break;
261 case "FAIL:":
262 r = Result.FAIL; break;
263 case "XPASS:":
264 r = Result.XPASS; break;
265 case "XFAIL:":
266 r = Result.XFAIL; break;
267 case "ERROR:":
268 r = Result.ERROR; break;
269 default:{
270 if(token[0] == TORTURE){
271 throw new Exception("not yet handled: "~line);
272 }else if(id > -1){
273 throw new Exception(format("bug in SUB line: (%s) %s", id, line));
274 }
275 }
276 }
277
278 if(r != Result.UNTESTED){
279 if(std.string.find(line, "bad error message") > -1){
280 r |= Result.BAD_MSG;
281 }
282 if(std.string.find(line, "bad debugger message") > -1){
283 r |= Result.BAD_MSG;
284 }
285
286 file = cleanFileName(file);
287
288 if(id >= 0){
289 // update sub
290 id--;
291
292 Test* test = file in tests;
293
294 if(test is null){
295 Test t = new Test(file);
296 tests[file] = t;
297 t.r = r;
298 }else{
299 if(test.r != Result.UNTESTED){
300 test.r = Result.UNTESTED;
301 }
302 test.r = r;
303 }
304 }
305 return true;
306 }
307 return false;
308 }
309 }
310
311
312 int main(char[][] args){
313
314 if(args.length < 2){
315 fwritefln(stderr, "%s <old log> <new log>", args[0]);
316 return 1;
317 }
318
319
320 Log[] logs;
321
322 foreach(size_t id, char[] file; args[1 .. $]){
323 writefln("parsing: %s", file);
324 FStime logTime = getFStime(file);
325 debug fwritefln(stderr, "sourceTime: %s", logTime);
326
327 Log l= new Log(file);
328 Stream source = new BufferedFile(file, FileMode.In);
329 while(!source.eof()){
330 l.add(source.readLine());
331 }
332
333 l.dropBogusResults(logTime, "dstress");
334
335 logs ~= l;
336 }
337
338 Log oldLog = logs[0];
339 Log newLog = logs[1];
340
341 foreach(Test t; newLog.tests.values){
342 Test* oldT = t.file in oldLog.tests;
343
344 if(oldT !is null){
345 if(oldT.r == t.r)
346 continue;
347 else if(oldT.r < t.r && oldT.r && oldT.r <= Result.XFAIL){
348 writef("Regression ");
349 }
350 else if(t.r < oldT.r && t.r && t.r <= Result.XFAIL){
351 writef("Improvement ");
352 }
353 else {
354 writef("Change ");
355 }
356 writefln(toString(oldT.r), " -> ", toString(t.r), " : ", t.name, " in ", t.file);
357 }
358 }
359
360
361 return 0;
362 }
363