Moved a number of 16-bit functions to file16.c.
[wine.git] / programs / winetest / main.c
blobf92cf4903e6fc51e741b9e5f71c73a8e08610e98
1 /*
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.
27 #include "config.h"
28 #include "wine/port.h"
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <errno.h>
33 #ifdef HAVE_UNISTD_H
34 # include <unistd.h>
35 #endif
36 #include <windows.h>
38 #include "winetest.h"
40 #define TESTRESOURCE "USERDATA"
42 struct wine_test
44 char *name;
45 int resource;
46 int subtest_count;
47 char **subtests;
48 int is_elf;
49 char *exename;
52 static struct wine_test *wine_tests;
54 static const char *wineloader;
56 void print_version ()
58 OSVERSIONINFOEX ver;
59 BOOL ext;
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);
74 if (!ext) return;
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)
89 HANDLE hFind;
90 WIN32_FIND_DATA wfd;
91 char path[MAX_PATH];
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;
100 do {
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)
107 remove_dir(path);
108 else if (!DeleteFile (path))
109 report (R_WARNING, "Can't delete file %s: error %d",
110 path, GetLastError ());
111 } while (FindNextFile (hFind, &wfd));
112 FindClose (hFind);
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)
120 HRSRC rsrc;
121 HGLOBAL hdl;
122 LPVOID addr = NULL;
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 ());
130 return addr;
133 /* Fills out the name, is_elf and exename fields */
134 void
135 extract_test (struct wine_test *test, const char *dir, int id)
137 BYTE* code;
138 DWORD size;
139 FILE* fout;
140 int strlen, bufflen = 128;
141 char *exepos;
143 code = extract_rcdata (id, &size);
144 test->name = xmalloc (bufflen);
145 while ((strlen = LoadStringA (NULL, id, test->name, bufflen))
146 == bufflen - 1) {
147 bufflen *= 2;
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);
154 *exepos = 0;
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.",
162 test->exename);
165 void
166 get_subtests (const char *tempdir, struct wine_test *test, int id)
168 char *subname;
169 FILE *subfile;
170 size_t subsize, bytes_read, total;
171 char *buffer, *index;
172 const char header[] = "Valid test names:", seps[] = " \r\n";
173 int oldstdout;
174 const char *argv[] = {"wine", NULL, NULL};
175 int allocated;
177 subname = tempnam (0, "sub");
178 if (!subname) report (R_FATAL, "Can't name subtests file.");
179 oldstdout = dup (1);
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.");
185 fclose (subfile);
187 extract_test (test, tempdir, id);
188 argv[1] = test->exename;
189 if (test->is_elf)
190 spawnvp (_P_WAIT, wineloader, argv);
191 else
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);
197 total = 0;
198 while ((bytes_read = read (1, buffer + total, subsize - total))
199 && (signed)bytes_read != -1)
200 total += bytes_read;
201 if (bytes_read)
202 report (R_FATAL, "Can't get subtests of %s", test->name);
203 buffer[total] = 0;
204 index = strstr (buffer, header);
205 if (!index)
206 report (R_FATAL, "Can't parse subtests output of %s",
207 test->name);
208 index += sizeof header;
210 allocated = 10;
211 test->subtests = xmalloc (allocated * sizeof(char*));
212 test->subtest_count = 0;
213 index = strtok (index, seps);
214 while (index) {
215 if (test->subtest_count == allocated) {
216 allocated *= 2;
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*));
225 free (buffer);
226 close (1);
227 if (-1 == dup2 (oldstdout, 1))
228 report (R_FATAL, "Can't recover old stdout.");
229 close (oldstdout);
230 if (remove (subname))
231 report (R_FATAL, "Can't remove subtests file.");
232 free (subname);
235 /* Return number of failures, -1 if couldn't spawn process. */
236 int run_test (struct wine_test* test, const char* subtest)
238 int status;
239 const char *argv[] = {"wine", test->exename, subtest, NULL};
241 xprintf ("%s:%s start\n", test->name, subtest);
242 if (test->is_elf)
243 status = spawnvp (_P_WAIT, wineloader, argv);
244 else
245 status = spawnvp (_P_WAIT, test->exename, argv+1);
246 if (status == -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);
250 return status;
253 BOOL CALLBACK
254 EnumTestFileProc (HMODULE hModule, LPCTSTR lpszType,
255 LPTSTR lpszName, LONG_PTR lParam)
257 (*(int*)lParam)++;
258 return TRUE;
261 char *
262 run_tests (char *logname, const char *tag)
264 int nr_of_files = 0, nr_of_tests = 0, i;
265 char *tempdir;
266 FILE *logfile;
267 char build_tag[128];
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");
276 if (!tempdir)
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);
282 if (!logname) {
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.");
292 fclose (logfile);
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");
303 print_version ();
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",
310 GetLastError ());
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;
325 int j;
327 for (j = 0; j < test->subtest_count; j++) {
328 report (R_STEP, "Running: %s: %s", test->name,
329 test->subtests[j]);
330 run_test (test, test->subtests[j]);
333 report (R_DELTA, 0, "Running: Done");
335 report (R_STATUS, "Cleaning up");
336 close (1);
337 remove_dir (tempdir);
338 free (tempdir);
339 free (wine_tests);
341 return logname;
344 void
345 usage ()
347 fprintf (stderr, "\
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, " ");
365 while (cmdLine) {
366 if (*cmdLine == '-')
367 if (cmdLine[2]) {
368 report (R_ERROR, "Not a single letter option: %s",
369 cmdLine);
370 usage ();
371 exit (2);
373 cmdLine++;
374 switch (*cmdLine) {
375 case 'c':
376 report (R_TEXTMODE);
377 break;
378 case 'h':
379 usage ();
380 exit (0);
381 case 'q':
382 report (R_QUIET);
383 break;
384 case 's':
385 submit = strtok (NULL, " ");
386 if (tag)
387 report (R_WARNING, "ignoring tag for submit");
388 send_file (submit);
389 break;
390 case 'o':
391 logname = strtok (NULL, " ");
392 run_tests (logname, tag);
393 break;
394 case 't':
395 tag = strtok (NULL, " ");
396 cp = badtagchar (tag);
397 if (cp) {
398 report (R_ERROR, "invalid char in tag: %c", *cp);
399 usage ();
400 exit (2);
402 break;
403 default:
404 report (R_ERROR, "invalid option: -%c", *cmdLine);
405 usage ();
406 exit (2);
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);
417 free (logname);
418 report (R_STATUS, "Finished");
420 exit (0);