1*c2c66affSColin Finck /*
2*c2c66affSColin Finck * Wine Conformance Test EXE
3*c2c66affSColin Finck *
4*c2c66affSColin Finck * Copyright 2003, 2004 Jakob Eriksson (for Solid Form Sweden AB)
5*c2c66affSColin Finck * Copyright 2003 Dimitrie O. Paun
6*c2c66affSColin Finck * Copyright 2003 Ferenc Wagner
7*c2c66affSColin Finck *
8*c2c66affSColin Finck * This library is free software; you can redistribute it and/or
9*c2c66affSColin Finck * modify it under the terms of the GNU Lesser General Public
10*c2c66affSColin Finck * License as published by the Free Software Foundation; either
11*c2c66affSColin Finck * version 2.1 of the License, or (at your option) any later version.
12*c2c66affSColin Finck *
13*c2c66affSColin Finck * This library is distributed in the hope that it will be useful,
14*c2c66affSColin Finck * but WITHOUT ANY WARRANTY; without even the implied warranty of
15*c2c66affSColin Finck * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16*c2c66affSColin Finck * Lesser General Public License for more details.
17*c2c66affSColin Finck *
18*c2c66affSColin Finck * You should have received a copy of the GNU Lesser General Public
19*c2c66affSColin Finck * License along with this library; if not, write to the Free Software
20*c2c66affSColin Finck * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21*c2c66affSColin Finck *
22*c2c66affSColin Finck * This program is dedicated to Anna Lindh,
23*c2c66affSColin Finck * Swedish Minister of Foreign Affairs.
24*c2c66affSColin Finck * Anna was murdered September 11, 2003.
25*c2c66affSColin Finck *
26*c2c66affSColin Finck */
27*c2c66affSColin Finck
28*c2c66affSColin Finck #include "config.h"
29*c2c66affSColin Finck #include "wine/port.h"
30*c2c66affSColin Finck
31*c2c66affSColin Finck #include <stdio.h>
32*c2c66affSColin Finck #include <stdlib.h>
33*c2c66affSColin Finck #include <assert.h>
34*c2c66affSColin Finck #include <errno.h>
35*c2c66affSColin Finck #ifdef HAVE_UNISTD_H
36*c2c66affSColin Finck # include <unistd.h>
37*c2c66affSColin Finck #endif
38*c2c66affSColin Finck #include <windows.h>
39*c2c66affSColin Finck
40*c2c66affSColin Finck #include "winetest.h"
41*c2c66affSColin Finck #include "resource.h"
42*c2c66affSColin Finck #include <reason.h>
43*c2c66affSColin Finck
44*c2c66affSColin Finck struct wine_test
45*c2c66affSColin Finck {
46*c2c66affSColin Finck char *name;
47*c2c66affSColin Finck int resource;
48*c2c66affSColin Finck int subtest_count;
49*c2c66affSColin Finck char **subtests;
50*c2c66affSColin Finck char *exename;
51*c2c66affSColin Finck };
52*c2c66affSColin Finck
53*c2c66affSColin Finck struct rev_info
54*c2c66affSColin Finck {
55*c2c66affSColin Finck const char* file;
56*c2c66affSColin Finck const char* rev;
57*c2c66affSColin Finck };
58*c2c66affSColin Finck
59*c2c66affSColin Finck char *tag = NULL;
60*c2c66affSColin Finck static struct wine_test *wine_tests;
61*c2c66affSColin Finck static int nr_of_files, nr_of_tests;
62*c2c66affSColin Finck static struct rev_info *rev_infos = NULL;
63*c2c66affSColin Finck static const char whitespace[] = " \t\r\n";
64*c2c66affSColin Finck static const char testexe[] = "_test.exe";
65*c2c66affSColin Finck
get_file_version(char * file_name)66*c2c66affSColin Finck static char * get_file_version(char * file_name)
67*c2c66affSColin Finck {
68*c2c66affSColin Finck static char version[32];
69*c2c66affSColin Finck DWORD size;
70*c2c66affSColin Finck DWORD handle;
71*c2c66affSColin Finck
72*c2c66affSColin Finck size = GetFileVersionInfoSizeA(file_name, &handle);
73*c2c66affSColin Finck if (size) {
74*c2c66affSColin Finck char * data = xmalloc(size);
75*c2c66affSColin Finck if (data) {
76*c2c66affSColin Finck if (GetFileVersionInfoA(file_name, handle, size, data)) {
77*c2c66affSColin Finck static char backslash[] = "\\";
78*c2c66affSColin Finck VS_FIXEDFILEINFO *pFixedVersionInfo;
79*c2c66affSColin Finck UINT len;
80*c2c66affSColin Finck if (VerQueryValueA(data, backslash, (LPVOID *)&pFixedVersionInfo, &len)) {
81*c2c66affSColin Finck sprintf(version, "%d.%d.%d.%d",
82*c2c66affSColin Finck pFixedVersionInfo->dwFileVersionMS >> 16,
83*c2c66affSColin Finck pFixedVersionInfo->dwFileVersionMS & 0xffff,
84*c2c66affSColin Finck pFixedVersionInfo->dwFileVersionLS >> 16,
85*c2c66affSColin Finck pFixedVersionInfo->dwFileVersionLS & 0xffff);
86*c2c66affSColin Finck } else
87*c2c66affSColin Finck sprintf(version, "version not available");
88*c2c66affSColin Finck } else
89*c2c66affSColin Finck sprintf(version, "unknown");
90*c2c66affSColin Finck free(data);
91*c2c66affSColin Finck } else
92*c2c66affSColin Finck sprintf(version, "failed");
93*c2c66affSColin Finck } else
94*c2c66affSColin Finck sprintf(version, "version not available");
95*c2c66affSColin Finck
96*c2c66affSColin Finck return version;
97*c2c66affSColin Finck }
98*c2c66affSColin Finck
running_under_wine(void)99*c2c66affSColin Finck static int running_under_wine (void)
100*c2c66affSColin Finck {
101*c2c66affSColin Finck HMODULE module = GetModuleHandleA("ntdll.dll");
102*c2c66affSColin Finck
103*c2c66affSColin Finck if (!module) return 0;
104*c2c66affSColin Finck return (GetProcAddress(module, "wine_server_call") != NULL);
105*c2c66affSColin Finck }
106*c2c66affSColin Finck
running_on_visible_desktop(void)107*c2c66affSColin Finck static int running_on_visible_desktop (void)
108*c2c66affSColin Finck {
109*c2c66affSColin Finck HWND desktop;
110*c2c66affSColin Finck HMODULE huser32 = GetModuleHandle("user32.dll");
111*c2c66affSColin Finck FARPROC pGetProcessWindowStation = GetProcAddress(huser32, "GetProcessWindowStation");
112*c2c66affSColin Finck FARPROC pGetUserObjectInformationA = GetProcAddress(huser32, "GetUserObjectInformationA");
113*c2c66affSColin Finck
114*c2c66affSColin Finck desktop = GetDesktopWindow();
115*c2c66affSColin Finck if (!GetWindowLongPtrW(desktop, GWLP_WNDPROC)) /* Win9x */
116*c2c66affSColin Finck return IsWindowVisible(desktop);
117*c2c66affSColin Finck
118*c2c66affSColin Finck if (pGetProcessWindowStation && pGetUserObjectInformationA)
119*c2c66affSColin Finck {
120*c2c66affSColin Finck DWORD len;
121*c2c66affSColin Finck HWINSTA wstation;
122*c2c66affSColin Finck USEROBJECTFLAGS uoflags;
123*c2c66affSColin Finck
124*c2c66affSColin Finck wstation = (HWINSTA)pGetProcessWindowStation();
125*c2c66affSColin Finck assert(pGetUserObjectInformationA(wstation, UOI_FLAGS, &uoflags, sizeof(uoflags), &len));
126*c2c66affSColin Finck return (uoflags.dwFlags & WSF_VISIBLE) != 0;
127*c2c66affSColin Finck }
128*c2c66affSColin Finck return IsWindowVisible(desktop);
129*c2c66affSColin Finck }
130*c2c66affSColin Finck
print_version(void)131*c2c66affSColin Finck static void print_version (void)
132*c2c66affSColin Finck {
133*c2c66affSColin Finck OSVERSIONINFOEX ver;
134*c2c66affSColin Finck BOOL ext;
135*c2c66affSColin Finck int is_win2k3_r2;
136*c2c66affSColin Finck const char *(*wine_get_build_id)(void);
137*c2c66affSColin Finck
138*c2c66affSColin Finck ver.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
139*c2c66affSColin Finck if (!(ext = GetVersionEx ((OSVERSIONINFO *) &ver)))
140*c2c66affSColin Finck {
141*c2c66affSColin Finck ver.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
142*c2c66affSColin Finck if (!GetVersionEx ((OSVERSIONINFO *) &ver))
143*c2c66affSColin Finck report (R_FATAL, "Can't get OS version.");
144*c2c66affSColin Finck }
145*c2c66affSColin Finck
146*c2c66affSColin Finck xprintf (" bRunningUnderWine=%d\n", running_under_wine ());
147*c2c66affSColin Finck xprintf (" bRunningOnVisibleDesktop=%d\n", running_on_visible_desktop ());
148*c2c66affSColin Finck xprintf (" dwMajorVersion=%ld\n dwMinorVersion=%ld\n"
149*c2c66affSColin Finck " dwBuildNumber=%ld\n PlatformId=%ld\n szCSDVersion=%s\n",
150*c2c66affSColin Finck ver.dwMajorVersion, ver.dwMinorVersion, ver.dwBuildNumber,
151*c2c66affSColin Finck ver.dwPlatformId, ver.szCSDVersion);
152*c2c66affSColin Finck
153*c2c66affSColin Finck wine_get_build_id = (void *)GetProcAddress(GetModuleHandleA("ntdll.dll"), "wine_get_build_id");
154*c2c66affSColin Finck if (wine_get_build_id) xprintf( " WineBuild=%s\n", wine_get_build_id() );
155*c2c66affSColin Finck
156*c2c66affSColin Finck is_win2k3_r2 = GetSystemMetrics(SM_SERVERR2);
157*c2c66affSColin Finck if(is_win2k3_r2)
158*c2c66affSColin Finck xprintf(" R2 build number=%d\n", is_win2k3_r2);
159*c2c66affSColin Finck
160*c2c66affSColin Finck if (!ext) return;
161*c2c66affSColin Finck
162*c2c66affSColin Finck xprintf (" wServicePackMajor=%d\n wServicePackMinor=%d\n"
163*c2c66affSColin Finck " wSuiteMask=%d\n wProductType=%d\n wReserved=%d\n",
164*c2c66affSColin Finck ver.wServicePackMajor, ver.wServicePackMinor, ver.wSuiteMask,
165*c2c66affSColin Finck ver.wProductType, ver.wReserved);
166*c2c66affSColin Finck }
167*c2c66affSColin Finck
is_dot_dir(const char * x)168*c2c66affSColin Finck static inline int is_dot_dir(const char* x)
169*c2c66affSColin Finck {
170*c2c66affSColin Finck return ((x[0] == '.') && ((x[1] == 0) || ((x[1] == '.') && (x[2] == 0))));
171*c2c66affSColin Finck }
172*c2c66affSColin Finck
remove_dir(const char * dir)173*c2c66affSColin Finck static void remove_dir (const char *dir)
174*c2c66affSColin Finck {
175*c2c66affSColin Finck HANDLE hFind;
176*c2c66affSColin Finck WIN32_FIND_DATA wfd;
177*c2c66affSColin Finck char path[MAX_PATH];
178*c2c66affSColin Finck size_t dirlen = strlen (dir);
179*c2c66affSColin Finck
180*c2c66affSColin Finck /* Make sure the directory exists before going further */
181*c2c66affSColin Finck memcpy (path, dir, dirlen);
182*c2c66affSColin Finck strcpy (path + dirlen++, "\\*");
183*c2c66affSColin Finck hFind = FindFirstFile (path, &wfd);
184*c2c66affSColin Finck if (hFind == INVALID_HANDLE_VALUE) return;
185*c2c66affSColin Finck
186*c2c66affSColin Finck do {
187*c2c66affSColin Finck char *lp = wfd.cFileName;
188*c2c66affSColin Finck
189*c2c66affSColin Finck if (!lp[0]) lp = wfd.cAlternateFileName; /* ? FIXME not (!lp) ? */
190*c2c66affSColin Finck if (is_dot_dir (lp)) continue;
191*c2c66affSColin Finck strcpy (path + dirlen, lp);
192*c2c66affSColin Finck if (FILE_ATTRIBUTE_DIRECTORY & wfd.dwFileAttributes)
193*c2c66affSColin Finck remove_dir(path);
194*c2c66affSColin Finck else if (!DeleteFile (path))
195*c2c66affSColin Finck report (R_WARNING, "Can't delete file %s: error %d",
196*c2c66affSColin Finck path, GetLastError ());
197*c2c66affSColin Finck } while (FindNextFile (hFind, &wfd));
198*c2c66affSColin Finck FindClose (hFind);
199*c2c66affSColin Finck if (!RemoveDirectory (dir))
200*c2c66affSColin Finck report (R_WARNING, "Can't remove directory %s: error %d",
201*c2c66affSColin Finck dir, GetLastError ());
202*c2c66affSColin Finck }
203*c2c66affSColin Finck
get_test_source_file(const char * test,const char * subtest)204*c2c66affSColin Finck static const char* get_test_source_file(const char* test, const char* subtest)
205*c2c66affSColin Finck {
206*c2c66affSColin Finck static const char* special_dirs[][2] = {
207*c2c66affSColin Finck { 0, 0 }
208*c2c66affSColin Finck };
209*c2c66affSColin Finck static char buffer[MAX_PATH];
210*c2c66affSColin Finck int i;
211*c2c66affSColin Finck
212*c2c66affSColin Finck for (i = 0; special_dirs[i][0]; i++) {
213*c2c66affSColin Finck if (strcmp(test, special_dirs[i][0]) == 0) {
214*c2c66affSColin Finck test = special_dirs[i][1];
215*c2c66affSColin Finck break;
216*c2c66affSColin Finck }
217*c2c66affSColin Finck }
218*c2c66affSColin Finck
219*c2c66affSColin Finck snprintf(buffer, sizeof(buffer), "dlls/%s/tests/%s.c", test, subtest);
220*c2c66affSColin Finck return buffer;
221*c2c66affSColin Finck }
222*c2c66affSColin Finck
get_file_rev(const char * file)223*c2c66affSColin Finck static const char* get_file_rev(const char* file)
224*c2c66affSColin Finck {
225*c2c66affSColin Finck const struct rev_info* rev;
226*c2c66affSColin Finck
227*c2c66affSColin Finck for(rev = rev_infos; rev->file; rev++) {
228*c2c66affSColin Finck if (strcmp(rev->file, file) == 0) return rev->rev;
229*c2c66affSColin Finck }
230*c2c66affSColin Finck
231*c2c66affSColin Finck return "-";
232*c2c66affSColin Finck }
233*c2c66affSColin Finck
extract_rev_infos(void)234*c2c66affSColin Finck static void extract_rev_infos (void)
235*c2c66affSColin Finck {
236*c2c66affSColin Finck char revinfo[256], *p;
237*c2c66affSColin Finck int size = 0, i;
238*c2c66affSColin Finck unsigned int len;
239*c2c66affSColin Finck HMODULE module = GetModuleHandle (NULL);
240*c2c66affSColin Finck
241*c2c66affSColin Finck for (i = 0; TRUE; i++) {
242*c2c66affSColin Finck if (i >= size) {
243*c2c66affSColin Finck size += 100;
244*c2c66affSColin Finck rev_infos = xrealloc (rev_infos, size * sizeof (*rev_infos));
245*c2c66affSColin Finck }
246*c2c66affSColin Finck memset(rev_infos + i, 0, sizeof(rev_infos[i]));
247*c2c66affSColin Finck
248*c2c66affSColin Finck len = LoadStringA (module, REV_INFO+i, revinfo, sizeof(revinfo));
249*c2c66affSColin Finck if (len == 0) break; /* end of revision info */
250*c2c66affSColin Finck if (len >= sizeof(revinfo) - 1)
251*c2c66affSColin Finck report (R_FATAL, "Revision info too long.");
252*c2c66affSColin Finck if(!(p = strrchr(revinfo, ':')))
253*c2c66affSColin Finck report (R_FATAL, "Revision info malformed (i=%d)", i);
254*c2c66affSColin Finck *p = 0;
255*c2c66affSColin Finck rev_infos[i].file = strdup(revinfo);
256*c2c66affSColin Finck rev_infos[i].rev = strdup(p + 1);
257*c2c66affSColin Finck }
258*c2c66affSColin Finck }
259*c2c66affSColin Finck
extract_rcdata(LPTSTR name,int type,DWORD * size)260*c2c66affSColin Finck static void* extract_rcdata (LPTSTR name, int type, DWORD* size)
261*c2c66affSColin Finck {
262*c2c66affSColin Finck HRSRC rsrc;
263*c2c66affSColin Finck HGLOBAL hdl;
264*c2c66affSColin Finck LPVOID addr;
265*c2c66affSColin Finck
266*c2c66affSColin Finck if (!(rsrc = FindResource (NULL, name, MAKEINTRESOURCE(type))) ||
267*c2c66affSColin Finck !(*size = SizeofResource (0, rsrc)) ||
268*c2c66affSColin Finck !(hdl = LoadResource (0, rsrc)) ||
269*c2c66affSColin Finck !(addr = LockResource (hdl)))
270*c2c66affSColin Finck return NULL;
271*c2c66affSColin Finck return addr;
272*c2c66affSColin Finck }
273*c2c66affSColin Finck
274*c2c66affSColin Finck /* Fills in the name and exename fields */
275*c2c66affSColin Finck static void
extract_test(struct wine_test * test,const char * dir,LPTSTR res_name)276*c2c66affSColin Finck extract_test (struct wine_test *test, const char *dir, LPTSTR res_name)
277*c2c66affSColin Finck {
278*c2c66affSColin Finck BYTE* code;
279*c2c66affSColin Finck DWORD size;
280*c2c66affSColin Finck FILE* fout;
281*c2c66affSColin Finck char *exepos;
282*c2c66affSColin Finck
283*c2c66affSColin Finck code = extract_rcdata (res_name, TESTRES, &size);
284*c2c66affSColin Finck if (!code) report (R_FATAL, "Can't find test resource %s: %d",
285*c2c66affSColin Finck res_name, GetLastError ());
286*c2c66affSColin Finck test->name = xstrdup( res_name );
287*c2c66affSColin Finck test->exename = strmake (NULL, "%s/%s", dir, test->name);
288*c2c66affSColin Finck exepos = strstr (test->name, testexe);
289*c2c66affSColin Finck if (!exepos) report (R_FATAL, "Not an .exe file: %s", test->name);
290*c2c66affSColin Finck *exepos = 0;
291*c2c66affSColin Finck test->name = xrealloc (test->name, exepos - test->name + 1);
292*c2c66affSColin Finck report (R_STEP, "Extracting: %s", test->name);
293*c2c66affSColin Finck
294*c2c66affSColin Finck if (!(fout = fopen (test->exename, "wb")) ||
295*c2c66affSColin Finck (fwrite (code, size, 1, fout) != 1) ||
296*c2c66affSColin Finck fclose (fout)) report (R_FATAL, "Failed to write file %s.",
297*c2c66affSColin Finck test->exename);
298*c2c66affSColin Finck }
299*c2c66affSColin Finck
300*c2c66affSColin Finck /* Run a command for MS milliseconds. If OUT != NULL, also redirect
301*c2c66affSColin Finck stdout to there.
302*c2c66affSColin Finck
303*c2c66affSColin Finck Return the exit status, -2 if can't create process or the return
304*c2c66affSColin Finck value of WaitForSingleObject.
305*c2c66affSColin Finck */
306*c2c66affSColin Finck static int
run_ex(char * cmd,const char * out,const char * tempdir,DWORD ms)307*c2c66affSColin Finck run_ex (char *cmd, const char *out, const char *tempdir, DWORD ms)
308*c2c66affSColin Finck {
309*c2c66affSColin Finck STARTUPINFO si;
310*c2c66affSColin Finck PROCESS_INFORMATION pi;
311*c2c66affSColin Finck int fd, oldstdout = -1;
312*c2c66affSColin Finck DWORD wait, status;
313*c2c66affSColin Finck
314*c2c66affSColin Finck GetStartupInfo (&si);
315*c2c66affSColin Finck si.dwFlags = 0;
316*c2c66affSColin Finck
317*c2c66affSColin Finck if (out) {
318*c2c66affSColin Finck fd = open (out, O_WRONLY | O_CREAT, 0666);
319*c2c66affSColin Finck if (-1 == fd)
320*c2c66affSColin Finck report (R_FATAL, "Can't open '%s': %d", out, errno);
321*c2c66affSColin Finck oldstdout = dup (1);
322*c2c66affSColin Finck if (-1 == oldstdout)
323*c2c66affSColin Finck report (R_FATAL, "Can't save stdout: %d", errno);
324*c2c66affSColin Finck if (-1 == dup2 (fd, 1))
325*c2c66affSColin Finck report (R_FATAL, "Can't redirect stdout: %d", errno);
326*c2c66affSColin Finck close (fd);
327*c2c66affSColin Finck }
328*c2c66affSColin Finck
329*c2c66affSColin Finck if (!CreateProcessA (NULL, cmd, NULL, NULL, TRUE, CREATE_DEFAULT_ERROR_MODE,
330*c2c66affSColin Finck NULL, tempdir, &si, &pi)) {
331*c2c66affSColin Finck status = -2;
332*c2c66affSColin Finck } else {
333*c2c66affSColin Finck CloseHandle (pi.hThread);
334*c2c66affSColin Finck wait = WaitForSingleObject (pi.hProcess, ms);
335*c2c66affSColin Finck if (wait == WAIT_OBJECT_0) {
336*c2c66affSColin Finck GetExitCodeProcess (pi.hProcess, &status);
337*c2c66affSColin Finck } else {
338*c2c66affSColin Finck switch (wait) {
339*c2c66affSColin Finck case WAIT_FAILED:
340*c2c66affSColin Finck report (R_ERROR, "Wait for '%s' failed: %d", cmd,
341*c2c66affSColin Finck GetLastError ());
342*c2c66affSColin Finck break;
343*c2c66affSColin Finck case WAIT_TIMEOUT:
344*c2c66affSColin Finck report (R_ERROR, "Process '%s' timed out.", cmd);
345*c2c66affSColin Finck break;
346*c2c66affSColin Finck default:
347*c2c66affSColin Finck report (R_ERROR, "Wait returned %d", wait);
348*c2c66affSColin Finck }
349*c2c66affSColin Finck status = wait;
350*c2c66affSColin Finck if (!TerminateProcess (pi.hProcess, 257))
351*c2c66affSColin Finck report (R_ERROR, "TerminateProcess failed: %d",
352*c2c66affSColin Finck GetLastError ());
353*c2c66affSColin Finck wait = WaitForSingleObject (pi.hProcess, 5000);
354*c2c66affSColin Finck switch (wait) {
355*c2c66affSColin Finck case WAIT_FAILED:
356*c2c66affSColin Finck report (R_ERROR,
357*c2c66affSColin Finck "Wait for termination of '%s' failed: %d",
358*c2c66affSColin Finck cmd, GetLastError ());
359*c2c66affSColin Finck break;
360*c2c66affSColin Finck case WAIT_OBJECT_0:
361*c2c66affSColin Finck break;
362*c2c66affSColin Finck case WAIT_TIMEOUT:
363*c2c66affSColin Finck report (R_ERROR, "Can't kill process '%s'", cmd);
364*c2c66affSColin Finck break;
365*c2c66affSColin Finck default:
366*c2c66affSColin Finck report (R_ERROR, "Waiting for termination: %d",
367*c2c66affSColin Finck wait);
368*c2c66affSColin Finck }
369*c2c66affSColin Finck }
370*c2c66affSColin Finck CloseHandle (pi.hProcess);
371*c2c66affSColin Finck }
372*c2c66affSColin Finck
373*c2c66affSColin Finck if (out) {
374*c2c66affSColin Finck close (1);
375*c2c66affSColin Finck if (-1 == dup2 (oldstdout, 1))
376*c2c66affSColin Finck report (R_FATAL, "Can't recover stdout: %d", errno);
377*c2c66affSColin Finck close (oldstdout);
378*c2c66affSColin Finck }
379*c2c66affSColin Finck return status;
380*c2c66affSColin Finck }
381*c2c66affSColin Finck
382*c2c66affSColin Finck static void
get_subtests(const char * tempdir,struct wine_test * test,LPTSTR res_name)383*c2c66affSColin Finck get_subtests (const char *tempdir, struct wine_test *test, LPTSTR res_name)
384*c2c66affSColin Finck {
385*c2c66affSColin Finck char *subname, *cmd;
386*c2c66affSColin Finck FILE *subfile;
387*c2c66affSColin Finck size_t total;
388*c2c66affSColin Finck char buffer[8192], *index;
389*c2c66affSColin Finck static const char header[] = "Valid test names:";
390*c2c66affSColin Finck int allocated;
391*c2c66affSColin Finck
392*c2c66affSColin Finck test->subtest_count = 0;
393*c2c66affSColin Finck
394*c2c66affSColin Finck subname = tempnam (0, "sub");
395*c2c66affSColin Finck if (!subname) report (R_FATAL, "Can't name subtests file.");
396*c2c66affSColin Finck
397*c2c66affSColin Finck extract_test (test, tempdir, res_name);
398*c2c66affSColin Finck cmd = strmake (NULL, "%s --list", test->exename);
399*c2c66affSColin Finck run_ex (cmd, subname, tempdir, 5000);
400*c2c66affSColin Finck free (cmd);
401*c2c66affSColin Finck
402*c2c66affSColin Finck subfile = fopen (subname, "r");
403*c2c66affSColin Finck if (!subfile) {
404*c2c66affSColin Finck report (R_ERROR, "Can't open subtests output of %s: %d",
405*c2c66affSColin Finck test->name, errno);
406*c2c66affSColin Finck goto quit;
407*c2c66affSColin Finck }
408*c2c66affSColin Finck total = fread (buffer, 1, sizeof buffer, subfile);
409*c2c66affSColin Finck fclose (subfile);
410*c2c66affSColin Finck if (sizeof buffer == total) {
411*c2c66affSColin Finck report (R_ERROR, "Subtest list of %s too big.",
412*c2c66affSColin Finck test->name, sizeof buffer);
413*c2c66affSColin Finck goto quit;
414*c2c66affSColin Finck }
415*c2c66affSColin Finck buffer[total] = 0;
416*c2c66affSColin Finck
417*c2c66affSColin Finck index = strstr (buffer, header);
418*c2c66affSColin Finck if (!index) {
419*c2c66affSColin Finck report (R_ERROR, "Can't parse subtests output of %s",
420*c2c66affSColin Finck test->name);
421*c2c66affSColin Finck goto quit;
422*c2c66affSColin Finck }
423*c2c66affSColin Finck index += sizeof header;
424*c2c66affSColin Finck
425*c2c66affSColin Finck allocated = 10;
426*c2c66affSColin Finck test->subtests = xmalloc (allocated * sizeof(char*));
427*c2c66affSColin Finck index = strtok (index, whitespace);
428*c2c66affSColin Finck while (index) {
429*c2c66affSColin Finck if (test->subtest_count == allocated) {
430*c2c66affSColin Finck allocated *= 2;
431*c2c66affSColin Finck test->subtests = xrealloc (test->subtests,
432*c2c66affSColin Finck allocated * sizeof(char*));
433*c2c66affSColin Finck }
434*c2c66affSColin Finck test->subtests[test->subtest_count++] = strdup (index);
435*c2c66affSColin Finck index = strtok (NULL, whitespace);
436*c2c66affSColin Finck }
437*c2c66affSColin Finck test->subtests = xrealloc (test->subtests,
438*c2c66affSColin Finck test->subtest_count * sizeof(char*));
439*c2c66affSColin Finck
440*c2c66affSColin Finck quit:
441*c2c66affSColin Finck if (remove (subname))
442*c2c66affSColin Finck report (R_WARNING, "Can't delete file '%s': %d",
443*c2c66affSColin Finck subname, errno);
444*c2c66affSColin Finck free (subname);
445*c2c66affSColin Finck }
446*c2c66affSColin Finck
447*c2c66affSColin Finck static void
run_test(struct wine_test * test,const char * subtest,const char * tempdir)448*c2c66affSColin Finck run_test (struct wine_test* test, const char* subtest, const char *tempdir)
449*c2c66affSColin Finck {
450*c2c66affSColin Finck int status;
451*c2c66affSColin Finck const char* file = get_test_source_file(test->name, subtest);
452*c2c66affSColin Finck const char* rev = get_file_rev(file);
453*c2c66affSColin Finck char *cmd = strmake (NULL, "%s %s", test->exename, subtest);
454*c2c66affSColin Finck
455*c2c66affSColin Finck xprintf ("%s:%s start %s %s\n", test->name, subtest, file, rev);
456*c2c66affSColin Finck status = run_ex (cmd, NULL, tempdir, 120000);
457*c2c66affSColin Finck free (cmd);
458*c2c66affSColin Finck xprintf ("%s:%s done (%d)\n", test->name, subtest, status);
459*c2c66affSColin Finck }
460*c2c66affSColin Finck
461*c2c66affSColin Finck static BOOL CALLBACK
EnumTestFileProc(HMODULE hModule,LPCTSTR lpszType,LPTSTR lpszName,LONG_PTR lParam)462*c2c66affSColin Finck EnumTestFileProc (HMODULE hModule, LPCTSTR lpszType,
463*c2c66affSColin Finck LPTSTR lpszName, LONG_PTR lParam)
464*c2c66affSColin Finck {
465*c2c66affSColin Finck (*(int*)lParam)++;
466*c2c66affSColin Finck return TRUE;
467*c2c66affSColin Finck }
468*c2c66affSColin Finck
469*c2c66affSColin Finck static BOOL CALLBACK
extract_test_proc(HMODULE hModule,LPCTSTR lpszType,LPTSTR lpszName,LONG_PTR lParam)470*c2c66affSColin Finck extract_test_proc (HMODULE hModule, LPCTSTR lpszType,
471*c2c66affSColin Finck LPTSTR lpszName, LONG_PTR lParam)
472*c2c66affSColin Finck {
473*c2c66affSColin Finck const char *tempdir = (const char *)lParam;
474*c2c66affSColin Finck char dllname[MAX_PATH];
475*c2c66affSColin Finck HMODULE dll;
476*c2c66affSColin Finck
477*c2c66affSColin Finck /* Check if the main dll is present on this system */
478*c2c66affSColin Finck CharLowerA(lpszName);
479*c2c66affSColin Finck strcpy(dllname, lpszName);
480*c2c66affSColin Finck *strstr(dllname, testexe) = 0;
481*c2c66affSColin Finck
482*c2c66affSColin Finck dll = LoadLibraryExA(dllname, NULL, LOAD_LIBRARY_AS_DATAFILE);
483*c2c66affSColin Finck if (!dll) {
484*c2c66affSColin Finck xprintf (" %s=dll is missing\n", dllname);
485*c2c66affSColin Finck return TRUE;
486*c2c66affSColin Finck }
487*c2c66affSColin Finck FreeLibrary(dll);
488*c2c66affSColin Finck
489*c2c66affSColin Finck xprintf (" %s=%s\n", dllname, get_file_version(dllname));
490*c2c66affSColin Finck
491*c2c66affSColin Finck get_subtests( tempdir, &wine_tests[nr_of_files], lpszName );
492*c2c66affSColin Finck nr_of_tests += wine_tests[nr_of_files].subtest_count;
493*c2c66affSColin Finck nr_of_files++;
494*c2c66affSColin Finck return TRUE;
495*c2c66affSColin Finck }
496*c2c66affSColin Finck
497*c2c66affSColin Finck static char *
run_tests(char * logname)498*c2c66affSColin Finck run_tests (char *logname)
499*c2c66affSColin Finck {
500*c2c66affSColin Finck int i;
501*c2c66affSColin Finck char *tempdir, *shorttempdir;
502*c2c66affSColin Finck int logfile;
503*c2c66affSColin Finck char *strres, *eol, *nextline;
504*c2c66affSColin Finck DWORD strsize;
505*c2c66affSColin Finck char build[64];
506*c2c66affSColin Finck
507*c2c66affSColin Finck SetErrorMode (SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX);
508*c2c66affSColin Finck
509*c2c66affSColin Finck if (!logname) {
510*c2c66affSColin Finck logname = tempnam (0, "res");
511*c2c66affSColin Finck if (!logname) report (R_FATAL, "Can't name logfile.");
512*c2c66affSColin Finck }
513*c2c66affSColin Finck report (R_OUT, logname);
514*c2c66affSColin Finck
515*c2c66affSColin Finck logfile = open (logname, O_WRONLY | O_CREAT | O_EXCL | O_APPEND,
516*c2c66affSColin Finck 0666);
517*c2c66affSColin Finck if (-1 == logfile) {
518*c2c66affSColin Finck if (EEXIST == errno)
519*c2c66affSColin Finck report (R_FATAL, "File %s already exists.", logname);
520*c2c66affSColin Finck else report (R_FATAL, "Could not open logfile: %d", errno);
521*c2c66affSColin Finck }
522*c2c66affSColin Finck if (-1 == dup2 (logfile, 1))
523*c2c66affSColin Finck report (R_FATAL, "Can't redirect stdout: %d", errno);
524*c2c66affSColin Finck close (logfile);
525*c2c66affSColin Finck
526*c2c66affSColin Finck tempdir = tempnam (0, "wct");
527*c2c66affSColin Finck if (!tempdir)
528*c2c66affSColin Finck report (R_FATAL, "Can't name temporary dir (check %%TEMP%%).");
529*c2c66affSColin Finck shorttempdir = strdup (tempdir);
530*c2c66affSColin Finck if (shorttempdir) { /* try stable path for ZoneAlarm */
531*c2c66affSColin Finck strstr (shorttempdir, "wct")[3] = 0;
532*c2c66affSColin Finck if (CreateDirectoryA (shorttempdir, NULL)) {
533*c2c66affSColin Finck free (tempdir);
534*c2c66affSColin Finck tempdir = shorttempdir;
535*c2c66affSColin Finck } else free (shorttempdir);
536*c2c66affSColin Finck }
537*c2c66affSColin Finck if (tempdir != shorttempdir && !CreateDirectoryA (tempdir, NULL))
538*c2c66affSColin Finck report (R_FATAL, "Could not create directory: %s", tempdir);
539*c2c66affSColin Finck report (R_DIR, tempdir);
540*c2c66affSColin Finck
541*c2c66affSColin Finck xprintf ("Version 4\n");
542*c2c66affSColin Finck strres = extract_rcdata (MAKEINTRESOURCE(WINE_BUILD), STRINGRES, &strsize);
543*c2c66affSColin Finck xprintf ("Tests from build ");
544*c2c66affSColin Finck if (LoadStringA( 0, IDS_BUILD_ID, build, sizeof(build) )) xprintf( "%s\n", build );
545*c2c66affSColin Finck else if (strres) xprintf ("%.*s", strsize, strres);
546*c2c66affSColin Finck else xprintf ("-\n");
547*c2c66affSColin Finck strres = extract_rcdata (MAKEINTRESOURCE(TESTS_URL), STRINGRES, &strsize);
548*c2c66affSColin Finck xprintf ("Archive: ");
549*c2c66affSColin Finck if (strres) xprintf ("%.*s", strsize, strres);
550*c2c66affSColin Finck else xprintf ("-\n");
551*c2c66affSColin Finck xprintf ("Tag: %s\n", tag);
552*c2c66affSColin Finck xprintf ("Build info:\n");
553*c2c66affSColin Finck strres = extract_rcdata (MAKEINTRESOURCE(BUILD_INFO), STRINGRES, &strsize);
554*c2c66affSColin Finck while (strres) {
555*c2c66affSColin Finck eol = memchr (strres, '\n', strsize);
556*c2c66affSColin Finck if (!eol) {
557*c2c66affSColin Finck nextline = NULL;
558*c2c66affSColin Finck eol = strres + strsize;
559*c2c66affSColin Finck } else {
560*c2c66affSColin Finck strsize -= eol - strres + 1;
561*c2c66affSColin Finck nextline = strsize?eol+1:NULL;
562*c2c66affSColin Finck if (eol > strres && *(eol-1) == '\r') eol--;
563*c2c66affSColin Finck }
564*c2c66affSColin Finck xprintf (" %.*s\n", eol-strres, strres);
565*c2c66affSColin Finck strres = nextline;
566*c2c66affSColin Finck }
567*c2c66affSColin Finck xprintf ("Operating system version:\n");
568*c2c66affSColin Finck print_version ();
569*c2c66affSColin Finck xprintf ("Dll info:\n" );
570*c2c66affSColin Finck
571*c2c66affSColin Finck report (R_STATUS, "Counting tests");
572*c2c66affSColin Finck if (!EnumResourceNames (NULL, MAKEINTRESOURCE(TESTRES),
573*c2c66affSColin Finck EnumTestFileProc, (LPARAM)&nr_of_files))
574*c2c66affSColin Finck report (R_FATAL, "Can't enumerate test files: %d",
575*c2c66affSColin Finck GetLastError ());
576*c2c66affSColin Finck wine_tests = xmalloc (nr_of_files * sizeof wine_tests[0]);
577*c2c66affSColin Finck
578*c2c66affSColin Finck report (R_STATUS, "Extracting tests");
579*c2c66affSColin Finck report (R_PROGRESS, 0, nr_of_files);
580*c2c66affSColin Finck nr_of_files = 0;
581*c2c66affSColin Finck nr_of_tests = 0;
582*c2c66affSColin Finck if (!EnumResourceNames (NULL, MAKEINTRESOURCE(TESTRES),
583*c2c66affSColin Finck extract_test_proc, (LPARAM)tempdir))
584*c2c66affSColin Finck report (R_FATAL, "Can't enumerate test files: %d",
585*c2c66affSColin Finck GetLastError ());
586*c2c66affSColin Finck
587*c2c66affSColin Finck xprintf ("Test output:\n" );
588*c2c66affSColin Finck
589*c2c66affSColin Finck report (R_DELTA, 0, "Extracting: Done");
590*c2c66affSColin Finck
591*c2c66affSColin Finck report (R_STATUS, "Running tests");
592*c2c66affSColin Finck report (R_PROGRESS, 1, nr_of_tests);
593*c2c66affSColin Finck for (i = 0; i < nr_of_files; i++) {
594*c2c66affSColin Finck struct wine_test *test = wine_tests + i;
595*c2c66affSColin Finck int j;
596*c2c66affSColin Finck
597*c2c66affSColin Finck for (j = 0; j < test->subtest_count; j++) {
598*c2c66affSColin Finck report (R_STEP, "Running: %s:%s", test->name,
599*c2c66affSColin Finck test->subtests[j]);
600*c2c66affSColin Finck run_test (test, test->subtests[j], tempdir);
601*c2c66affSColin Finck }
602*c2c66affSColin Finck }
603*c2c66affSColin Finck report (R_DELTA, 0, "Running: Done");
604*c2c66affSColin Finck
605*c2c66affSColin Finck report (R_STATUS, "Cleaning up");
606*c2c66affSColin Finck close (1);
607*c2c66affSColin Finck remove_dir (tempdir);
608*c2c66affSColin Finck free (tempdir);
609*c2c66affSColin Finck free (wine_tests);
610*c2c66affSColin Finck
611*c2c66affSColin Finck return logname;
612*c2c66affSColin Finck }
613*c2c66affSColin Finck
614*c2c66affSColin Finck static void
usage(void)615*c2c66affSColin Finck usage (void)
616*c2c66affSColin Finck {
617*c2c66affSColin Finck fprintf (stderr,
618*c2c66affSColin Finck "Usage: winetest [OPTION]...\n\n"
619*c2c66affSColin Finck " -c console mode, no GUI\n"
620*c2c66affSColin Finck " -e preserve the environment\n"
621*c2c66affSColin Finck " -h print this message and exit\n"
622*c2c66affSColin Finck " -p shutdown when the tests are done\n"
623*c2c66affSColin Finck " -q quiet mode, no output at all\n"
624*c2c66affSColin Finck " -o FILE put report into FILE, do not submit\n"
625*c2c66affSColin Finck " -s FILE submit FILE, do not run tests\n"
626*c2c66affSColin Finck " -t TAG include TAG of characters [-.0-9a-zA-Z] in the report\n");
627*c2c66affSColin Finck }
628*c2c66affSColin Finck
WinMain(HINSTANCE hInst,HINSTANCE hPrevInst,LPSTR cmdLine,int cmdShow)629*c2c66affSColin Finck int WINAPI WinMain (HINSTANCE hInst, HINSTANCE hPrevInst,
630*c2c66affSColin Finck LPSTR cmdLine, int cmdShow)
631*c2c66affSColin Finck {
632*c2c66affSColin Finck char *logname = NULL;
633*c2c66affSColin Finck const char *cp, *submit = NULL;
634*c2c66affSColin Finck int reset_env = 1;
635*c2c66affSColin Finck int poweroff = 0;
636*c2c66affSColin Finck int interactive = 1;
637*c2c66affSColin Finck
638*c2c66affSColin Finck /* initialize the revision information first */
639*c2c66affSColin Finck extract_rev_infos();
640*c2c66affSColin Finck
641*c2c66affSColin Finck cmdLine = strtok (cmdLine, whitespace);
642*c2c66affSColin Finck while (cmdLine) {
643*c2c66affSColin Finck if (cmdLine[0] != '-' || cmdLine[2]) {
644*c2c66affSColin Finck report (R_ERROR, "Not a single letter option: %s", cmdLine);
645*c2c66affSColin Finck usage ();
646*c2c66affSColin Finck exit (2);
647*c2c66affSColin Finck }
648*c2c66affSColin Finck switch (cmdLine[1]) {
649*c2c66affSColin Finck case 'c':
650*c2c66affSColin Finck report (R_TEXTMODE);
651*c2c66affSColin Finck interactive = 0;
652*c2c66affSColin Finck break;
653*c2c66affSColin Finck case 'e':
654*c2c66affSColin Finck reset_env = 0;
655*c2c66affSColin Finck break;
656*c2c66affSColin Finck case 'h':
657*c2c66affSColin Finck case '?':
658*c2c66affSColin Finck usage ();
659*c2c66affSColin Finck exit (0);
660*c2c66affSColin Finck case 'p':
661*c2c66affSColin Finck poweroff = 1;
662*c2c66affSColin Finck break;
663*c2c66affSColin Finck case 'q':
664*c2c66affSColin Finck report (R_QUIET);
665*c2c66affSColin Finck interactive = 0;
666*c2c66affSColin Finck break;
667*c2c66affSColin Finck case 's':
668*c2c66affSColin Finck submit = strtok (NULL, whitespace);
669*c2c66affSColin Finck if (tag)
670*c2c66affSColin Finck report (R_WARNING, "ignoring tag for submission");
671*c2c66affSColin Finck send_file (submit);
672*c2c66affSColin Finck break;
673*c2c66affSColin Finck case 'o':
674*c2c66affSColin Finck logname = strtok (NULL, whitespace);
675*c2c66affSColin Finck break;
676*c2c66affSColin Finck case 't':
677*c2c66affSColin Finck tag = strtok (NULL, whitespace);
678*c2c66affSColin Finck if (strlen (tag) > MAXTAGLEN)
679*c2c66affSColin Finck report (R_FATAL, "tag is too long (maximum %d characters)",
680*c2c66affSColin Finck MAXTAGLEN);
681*c2c66affSColin Finck cp = findbadtagchar (tag);
682*c2c66affSColin Finck if (cp) {
683*c2c66affSColin Finck report (R_ERROR, "invalid char in tag: %c", *cp);
684*c2c66affSColin Finck usage ();
685*c2c66affSColin Finck exit (2);
686*c2c66affSColin Finck }
687*c2c66affSColin Finck break;
688*c2c66affSColin Finck default:
689*c2c66affSColin Finck report (R_ERROR, "invalid option: -%c", cmdLine[1]);
690*c2c66affSColin Finck usage ();
691*c2c66affSColin Finck exit (2);
692*c2c66affSColin Finck }
693*c2c66affSColin Finck cmdLine = strtok (NULL, whitespace);
694*c2c66affSColin Finck }
695*c2c66affSColin Finck if (!submit) {
696*c2c66affSColin Finck static CHAR platform_windows[] = "WINETEST_PLATFORM=windows",
697*c2c66affSColin Finck platform_wine[] = "WINETEST_PLATFORM=wine",
698*c2c66affSColin Finck debug_yes[] = "WINETEST_DEBUG=1",
699*c2c66affSColin Finck interactive_no[] = "WINETEST_INTERACTIVE=0",
700*c2c66affSColin Finck report_success_no[] = "WINETEST_REPORT_SUCCESS=0";
701*c2c66affSColin Finck CHAR *platform;
702*c2c66affSColin Finck
703*c2c66affSColin Finck report (R_STATUS, "Starting up");
704*c2c66affSColin Finck
705*c2c66affSColin Finck if (!running_on_visible_desktop ())
706*c2c66affSColin Finck report (R_FATAL, "Tests must be run on a visible desktop");
707*c2c66affSColin Finck
708*c2c66affSColin Finck platform = running_under_wine () ? platform_wine : platform_windows;
709*c2c66affSColin Finck
710*c2c66affSColin Finck if (reset_env && (putenv (platform) ||
711*c2c66affSColin Finck putenv (debug_yes) ||
712*c2c66affSColin Finck putenv (interactive_no) ||
713*c2c66affSColin Finck putenv (report_success_no)))
714*c2c66affSColin Finck report (R_FATAL, "Could not reset environment: %d", errno);
715*c2c66affSColin Finck
716*c2c66affSColin Finck if (!tag) {
717*c2c66affSColin Finck if (!interactive)
718*c2c66affSColin Finck report (R_FATAL, "Please specify a tag (-t option) if "
719*c2c66affSColin Finck "running noninteractive!");
720*c2c66affSColin Finck if (guiAskTag () == IDABORT) exit (1);
721*c2c66affSColin Finck }
722*c2c66affSColin Finck report (R_TAG);
723*c2c66affSColin Finck
724*c2c66affSColin Finck if (!logname) {
725*c2c66affSColin Finck logname = run_tests (NULL);
726*c2c66affSColin Finck if (report (R_ASK, MB_YESNO, "Do you want to submit the "
727*c2c66affSColin Finck "test results?") == IDYES)
728*c2c66affSColin Finck if (!send_file (logname) && remove (logname))
729*c2c66affSColin Finck report (R_WARNING, "Can't remove logfile: %d.", errno);
730*c2c66affSColin Finck free (logname);
731*c2c66affSColin Finck } else run_tests (logname);
732*c2c66affSColin Finck report (R_STATUS, "Finished");
733*c2c66affSColin Finck }
734*c2c66affSColin Finck if (poweroff)
735*c2c66affSColin Finck {
736*c2c66affSColin Finck HANDLE hToken;
737*c2c66affSColin Finck TOKEN_PRIVILEGES npr;
738*c2c66affSColin Finck
739*c2c66affSColin Finck /* enable the shutdown privilege for the current process */
740*c2c66affSColin Finck if (OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &hToken))
741*c2c66affSColin Finck {
742*c2c66affSColin Finck LookupPrivilegeValueA(0, SE_SHUTDOWN_NAME, &npr.Privileges[0].Luid);
743*c2c66affSColin Finck npr.PrivilegeCount = 1;
744*c2c66affSColin Finck npr.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
745*c2c66affSColin Finck AdjustTokenPrivileges(hToken, FALSE, &npr, 0, 0, 0);
746*c2c66affSColin Finck CloseHandle(hToken);
747*c2c66affSColin Finck }
748*c2c66affSColin Finck ExitWindowsEx(EWX_SHUTDOWN | EWX_POWEROFF | EWX_FORCEIFHUNG, SHTDN_REASON_MAJOR_OTHER | SHTDN_REASON_MINOR_OTHER);
749*c2c66affSColin Finck }
750*c2c66affSColin Finck exit (0);
751*c2c66affSColin Finck }
752