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");