2 * Wine Conformance Test EXE
4 * Copyright 2003 Jakob Eriksson (for Solid Form Sweden AB)
5 * Copyright 2003 Dimitrie O. Paun
6 * Copyright 2003 Ferenc Wagner
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
21 * This program is dedicated to Anna Lindh,
22 * Swedish Minister of Foreign Affairs.
23 * Anna was murdered September 11, 2003.
28 #include "wine/port.h"
40 #define TESTRESOURCE "USERDATA"
52 static struct wine_test
*wine_tests
;
54 static const char *wineloader
;
61 ver
.dwOSVersionInfoSize
= sizeof(OSVERSIONINFOEX
);
62 if (!(ext
= GetVersionEx ((OSVERSIONINFO
*) &ver
)))
64 ver
.dwOSVersionInfoSize
= sizeof(OSVERSIONINFO
);
65 if (!GetVersionEx ((OSVERSIONINFO
*) &ver
))
66 report (R_FATAL
, "Can't get OS version.");
69 xprintf (" dwMajorVersion=%ld\n dwMinorVersion=%ld\n"
70 " dwBuildNumber=%ld\n PlatformId=%ld\n szCSDVersion=%s\n",
71 ver
.dwMajorVersion
, ver
.dwMinorVersion
, ver
.dwBuildNumber
,
72 ver
.dwPlatformId
, ver
.szCSDVersion
);
76 xprintf (" wServicePackMajor=%d\n wServicePackMinor=%d\n"
77 " wSuiteMask=%d\n wProductType=%d\n wReserved=%d\n",
78 ver
.wServicePackMajor
, ver
.wServicePackMinor
, ver
.wSuiteMask
,
79 ver
.wProductType
, ver
.wReserved
);
82 static inline int is_dot_dir(const char* x
)
84 return ((x
[0] == '.') && ((x
[1] == 0) || ((x
[1] == '.') && (x
[2] == 0))));
87 void remove_dir (const char *dir
)
92 size_t dirlen
= strlen (dir
);
94 /* Make sure the directory exists before going further */
95 memcpy (path
, dir
, dirlen
);
96 strcpy (path
+ dirlen
++, "\\*");
97 hFind
= FindFirstFile (path
, &wfd
);
98 if (hFind
== INVALID_HANDLE_VALUE
) return;
101 char *lp
= wfd
.cFileName
;
103 if (!lp
[0]) lp
= wfd
.cAlternateFileName
; /* ? FIXME not (!lp) ? */
104 if (is_dot_dir (lp
)) continue;
105 strcpy (path
+ dirlen
, lp
);
106 if (FILE_ATTRIBUTE_DIRECTORY
& wfd
.dwFileAttributes
)
108 else if (!DeleteFile (path
))
109 report (R_WARNING
, "Can't delete file %s: error %d",
110 path
, GetLastError ());
111 } while (FindNextFile (hFind
, &wfd
));
113 if (!RemoveDirectory (dir
))
114 report (R_WARNING
, "Can't remove directory %s: error %d",
115 dir
, GetLastError ());
118 void* extract_rcdata (int id
, DWORD
* size
)
124 if (!(rsrc
= FindResource (0, (LPTSTR
)id
, TESTRESOURCE
)) ||
125 !(*size
= SizeofResource (0, rsrc
)) ||
126 !(hdl
= LoadResource (0, rsrc
)) ||
127 !(addr
= LockResource (hdl
)))
128 report (R_FATAL
, "Can't extract test file of id %d: %d",
129 id
, GetLastError ());
133 /* Fills out the name, is_elf and exename fields */
135 extract_test (struct wine_test
*test
, const char *dir
, int id
)
140 int strlen
, bufflen
= 128;
143 code
= extract_rcdata (id
, &size
);
144 test
->name
= xmalloc (bufflen
);
145 while ((strlen
= LoadStringA (NULL
, id
, test
->name
, bufflen
))
148 test
->name
= xrealloc (test
->name
, bufflen
);
150 if (!strlen
) report (R_FATAL
, "Can't read name of test %d.", id
);
151 test
->exename
= strmake (NULL
, "%s/%s", dir
, test
->name
);
152 exepos
= strstr (test
->name
, ".exe");
153 if (!exepos
) report (R_FATAL
, "Not an .exe file: %s", test
->name
);
155 test
->name
= xrealloc (test
->name
, exepos
- test
->name
+ 1);
156 report (R_STEP
, "Extracting: %s", test
->name
);
157 test
->is_elf
= !memcmp (code
+1, "ELF", 3);
159 if (!(fout
= fopen (test
->exename
, "wb")) ||
160 (fwrite (code
, size
, 1, fout
) != 1) ||
161 fclose (fout
)) report (R_FATAL
, "Failed to write file %s.",
166 get_subtests (const char *tempdir
, struct wine_test
*test
, int id
)
170 size_t subsize
, bytes_read
, total
;
171 char *buffer
, *index
;
172 const char header
[] = "Valid test names:", seps
[] = " \r\n";
174 const char *argv
[] = {"wine", NULL
, NULL
};
177 subname
= tempnam (0, "sub");
178 if (!subname
) report (R_FATAL
, "Can't name subtests file.");
180 if (-1 == oldstdout
) report (R_FATAL
, "Can't preserve stdout.");
181 subfile
= fopen (subname
, "w+b");
182 if (!subfile
) report (R_FATAL
, "Can't open subtests file.");
183 if (-1 == dup2 (fileno (subfile
), 1))
184 report (R_FATAL
, "Can't redirect output to subtests.");
187 extract_test (test
, tempdir
, id
);
188 argv
[1] = test
->exename
;
190 spawnvp (_P_WAIT
, wineloader
, argv
);
192 spawnvp (_P_WAIT
, test
->exename
, argv
+1);
193 subsize
= lseek (1, 0, SEEK_CUR
);
194 buffer
= xmalloc (subsize
+1);
196 lseek (1, 0, SEEK_SET
);
198 while ((bytes_read
= read (1, buffer
+ total
, subsize
- total
))
199 && (signed)bytes_read
!= -1)
202 report (R_FATAL
, "Can't get subtests of %s", test
->name
);
204 index
= strstr (buffer
, header
);
206 report (R_FATAL
, "Can't parse subtests output of %s",
208 index
+= sizeof header
;
211 test
->subtests
= xmalloc (allocated
* sizeof(char*));
212 test
->subtest_count
= 0;
213 index
= strtok (index
, seps
);
215 if (test
->subtest_count
== allocated
) {
217 test
->subtests
= xrealloc (test
->subtests
,
218 allocated
* sizeof(char*));
220 test
->subtests
[test
->subtest_count
++] = strdup (index
);
221 index
= strtok (NULL
, seps
);
223 test
->subtests
= xrealloc (test
->subtests
,
224 test
->subtest_count
* sizeof(char*));
227 if (-1 == dup2 (oldstdout
, 1))
228 report (R_FATAL
, "Can't recover old stdout.");
230 if (remove (subname
))
231 report (R_FATAL
, "Can't remove subtests file.");
235 /* Return number of failures, -1 if couldn't spawn process. */
236 int run_test (struct wine_test
* test
, const char* subtest
)
239 const char *argv
[] = {"wine", test
->exename
, subtest
, NULL
};
241 xprintf ("%s:%s start\n", test
->name
, subtest
);
243 status
= spawnvp (_P_WAIT
, wineloader
, argv
);
245 status
= spawnvp (_P_WAIT
, test
->exename
, argv
+1);
247 xprintf ("Can't run: %d, errno=%d: %s\n",
248 status
, errno
, strerror (errno
));
249 xprintf ("%s:%s done (%d)\n", test
->name
, subtest
, status
);
254 EnumTestFileProc (HMODULE hModule
, LPCTSTR lpszType
,
255 LPTSTR lpszName
, LONG_PTR lParam
)
262 run_tests (char *logname
, const char *tag
)
264 int nr_of_files
= 0, nr_of_tests
= 0, i
;
269 SetErrorMode (SEM_FAILCRITICALERRORS
);
271 if (!(wineloader
= getenv("WINELOADER"))) wineloader
= "wine";
272 if (setvbuf (stdout
, NULL
, _IONBF
, 0))
273 report (R_FATAL
, "Can't unbuffer output.");
275 tempdir
= tempnam (0, "wct");
277 report (R_FATAL
, "Can't name temporary dir (check %%TEMP%%).");
278 report (R_DIR
, tempdir
);
279 if (!CreateDirectory (tempdir
, NULL
))
280 report (R_FATAL
, "Could not create directory: %s", tempdir
);
283 logname
= tempnam (0, "res");
284 if (!logname
) report (R_FATAL
, "Can't name logfile.");
286 report (R_OUT
, logname
);
288 logfile
= fopen (logname
, "a");
289 if (!logfile
) report (R_FATAL
, "Could not open logfile.");
290 if (-1 == dup2 (fileno (logfile
), 1))
291 report (R_FATAL
, "Can't redirect stdout.");
294 xprintf ("Version 2\n");
295 i
= LoadStringA (GetModuleHandle (NULL
), 0,
296 build_tag
, sizeof build_tag
);
297 if (i
== 0) report (R_FATAL
, "Build descriptor not found.");
298 if (i
>= sizeof build_tag
)
299 report (R_FATAL
, "Build descriptor too long.");
300 xprintf ("Tests from build %s\n", build_tag
);
301 xprintf ("Tag: %s", tag
?tag
:"");
302 xprintf ("Operating system version:\n");
304 xprintf ("Test output:\n" );
306 report (R_STATUS
, "Counting tests");
307 if (!EnumResourceNames (NULL
, TESTRESOURCE
,
308 EnumTestFileProc
, (LPARAM
)&nr_of_files
))
309 report (R_FATAL
, "Can't enumerate test files: %d",
311 wine_tests
= xmalloc (nr_of_files
* sizeof wine_tests
[0]);
313 report (R_STATUS
, "Extracting tests");
314 report (R_PROGRESS
, 0, nr_of_files
);
315 for (i
= 0; i
< nr_of_files
; i
++) {
316 get_subtests (tempdir
, wine_tests
+i
, i
+1);
317 nr_of_tests
+= wine_tests
[i
].subtest_count
;
319 report (R_DELTA
, 0, "Extracting: Done");
321 report (R_STATUS
, "Running tests");
322 report (R_PROGRESS
, 1, nr_of_tests
);
323 for (i
= 0; i
< nr_of_files
; i
++) {
324 struct wine_test
*test
= wine_tests
+ i
;
327 for (j
= 0; j
< test
->subtest_count
; j
++) {
328 report (R_STEP
, "Running: %s: %s", test
->name
,
330 run_test (test
, test
->subtests
[j
]);
333 report (R_DELTA
, 0, "Running: Done");
335 report (R_STATUS
, "Cleaning up");
337 remove_dir (tempdir
);
348 Usage: winetest [OPTION]...\n\n\
349 -c console mode, no GUI\n\
350 -h print this message and exit\n\
351 -q quiet mode, no output at all\n\
352 -o FILE put report into FILE, do not submit\n\
353 -s FILE submit FILE, do not run tests\n\
354 -t TAG include TAG of characters [-.0-9a-zA-Z] in the report\n");
357 int WINAPI
WinMain (HINSTANCE hInst
, HINSTANCE hPrevInst
,
358 LPSTR cmdLine
, int cmdShow
)
360 char *logname
= NULL
;
361 char *tag
= NULL
, *cp
;
362 const char *submit
= NULL
;
364 cmdLine
= strtok (cmdLine
, " ");
368 report (R_ERROR
, "Not a single letter option: %s",
385 submit
= strtok (NULL
, " ");
387 report (R_WARNING
, "ignoring tag for submit");
391 logname
= strtok (NULL
, " ");
392 run_tests (logname
, tag
);
395 tag
= strtok (NULL
, " ");
396 cp
= badtagchar (tag
);
398 report (R_ERROR
, "invalid char in tag: %c", *cp
);
404 report (R_ERROR
, "invalid option: -%c", *cmdLine
);
408 cmdLine
= strtok (NULL
, " ");
410 if (!logname
&& !submit
) {
411 report (R_STATUS
, "Starting up");
412 logname
= run_tests (NULL
, tag
);
413 if (report (R_ASK
, MB_YESNO
, "Do you want to submit the "
414 "test results?") == IDYES
)
415 if (!send_file (logname
) && remove (logname
))
416 report (R_WARNING
, "Can't remove logfile: %d.", errno
);
418 report (R_STATUS
, "Finished");