Hi all, due to the number of regressions I found few days ago, it occurred to me that we really need an API test suite now. Thus I went ahead and implemented a test functionality for LoadModule16(). The result: 7 of the 21 tests that I implemented were FAILING !! That's ONE THIRD. And that for such a highly basic function as LoadModule16(). That's quite incredible.
I guess we really should change our development model from trying tons of programs to *systematically* testing functions and Windows mechanisms now. If we can show everyone where stuff is failing, it might be a lot easier to attract new people. I attached a preview of the posting I intend to post on *tons* of Windows devel newsgroups ("Call For Volunteers"). That way we might actually get hold of hundreds of Windows developers helping us implement a complete test suite (complete tests of up to 12000 Windows functions). Not to mention the additional PR we might get out of this... If this works, then we'd need someone in charge of managing the assignment of specific windows functions to specific programmers. I won't do that (very limited time). Anyone from Codeweavers up to the task ? Or maybe someone non-developer and rather foreign to the Wine devel could do that task ? About the program: My goal was to get a program with very easy parsing interface: fields separated by colons, nothing fancy and difficult to implement, ... A .exe can be found at: http://home.nexgo.de/andi.mohr/download/wt_ldr16.exe Please comment on both my intended posting and the way I programmed the first version of the test suite (I'm not extremely happy with the current program; if you have any improvements, then get them here ASAP !). As 12000 Windows functions is an enormous number, I think we should really start doing this NOW instead of years later once Wine really needs this. Wine does not extremely need this yet, but we're getting pretty damn close to that already. Thanks ! -- Andreas Mohr Stauferstr. 6, D-71272 Renningen, Germany
/* * This is part of the Wine API test suite. * This code verifies proper Win16 LoadModule() operation. * I used Win98SE to find out/implement checks for use with this function. */ #include <stdio.h> #include <string.h> #include "windows.h" #define PART "Loader_16" #define TEST_START(funcname) \ { \ currfunc = funcname; \ step = 1; \ result = TRUE; \ } #define TEST_NEXT \ step++; #define TEST_FAILED(retval) \ { \ print_result(PART, currfunc, FALSE, step, retval); \ result = FALSE; \ }; #define TEST_END \ if (result) \ print_result(PART, currfunc, TRUE, 0, 0); \ LPSTR currfunc = NULL; DWORD step; BOOL result = TRUE; #define GUI 0 void print_string(LPCSTR str) { char outstr[512]; strcpy(outstr, "WINETEST:"); strcat(outstr, str); #if GUI MessageBox(GetDesktopWindow(), outstr, "WINETEST", MB_OK); #else printf(outstr); #endif } void print_result(LPCSTR part, LPCSTR funcname, BOOL res, DWORD step, DWORD retval) { LPSTR resstr = res ? "OK" : "FAILED"; char outbuf[256]; if (step) sprintf(outbuf, "test:%s:%s:%s:%02ld:[%08lx]\n", part, funcname, resstr, step, retval); else sprintf(outbuf, "test:%s:%s:%s\n", part, funcname, resstr); print_string(outbuf); } void finish_check(BOOL res, DWORD retval) { if (!res) TEST_FAILED(retval); TEST_NEXT; } typedef struct _LOADPARMS { WORD segEnv; /* child environment */ LPSTR lpszCmdLine; /* child command tail */ UINT *lpShow; /* how to show child */ UINT *lpReserved; /* must be NULL */ } LOADPARMS; void wt_LoadModule(void) { HMODULE hMod; LOADPARMS lp; UINT ar[2]; char text[256]; TEST_START("LoadModule"); /* check NULL parameters */ hMod = LoadModule(NULL, NULL); /* Wine failure #1 */ finish_check(hMod == 0, hMod); /* check empty string */ hMod = LoadModule("", NULL); finish_check(hMod == 2, hMod); /* file not found */ /* check LOADPARMS */ lp.segEnv = 0; lp.lpszCmdLine = ""; ar[0] = 2; ar[1] = SW_SHOW; lp.lpShow = ar; lp.lpReserved = NULL; /* check lpszCmdLine; NULL is supposed to be invalid according to docu, but it isn't */ lp.lpszCmdLine = NULL; hMod = LoadModule("kernel", &lp); finish_check(hMod >= 32, hMod); FreeModule(hMod); lp.lpszCmdLine = ""; /* 121 chars */ lp.lpszCmdLine = "1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901"; hMod = LoadModule("kernel", &lp); finish_check(hMod >= 32, hMod); FreeModule(hMod); lp.lpszCmdLine = ""; /* check lpShow */ lp.lpShow = NULL; hMod = LoadModule("kernel", &lp); finish_check(hMod >= 32, hMod); FreeModule(hMod); lp.lpShow = ar; ar[0] = 1; hMod = LoadModule("kernel", &lp); finish_check(hMod >= 32, hMod); FreeModule(hMod); ar[0] = 2; ar[0] = 0xabcd; hMod = LoadModule("kernel", &lp); finish_check(hMod >= 32, hMod); FreeModule(hMod); ar[0] = 2; ar[1] = 0xabcd; hMod = LoadModule("kernel", &lp); finish_check(hMod >= 32, hMod); FreeModule(hMod); ar[1] = SW_SHOW; /* check lpReserved */ lp.lpReserved = (UINT *)0x12345678; hMod = LoadModule("kernel", &lp); finish_check(hMod >= 32, hMod); FreeModule(hMod); lp.lpReserved = NULL; /* check empty string */ hMod = LoadModule("", &lp); finish_check(hMod == 2, hMod); /* file not found */ /* check wrong pointer */ hMod = LoadModule(NULL, (LPVOID)0x1234); /* Wine failure #1 */ finish_check(hMod == 0, hMod); /* check nonexisting file */ hMod = LoadModule("c:\\DOESNOTEXIST", &lp); finish_check(hMod == 2, hMod); /* file not found */ /* check strange backslash */ hMod = LoadModule("C:\\\\command.com", &lp); finish_check(hMod == 5, hMod); /* hmm, why error 5 ? */ /* check strange filename */ hMod = LoadModule("C:\\command.com\\", &lp); /* Wine failure #2 */ finish_check(hMod == 3, hMod); /* path was not found */ /* check strange filename */ hMod = LoadModule("C:\\command.comfoobar", &lp); finish_check(hMod == 2, hMod); /* file not found */ /* check loading of DOS file */ hMod = LoadModule("C:\\command.com", &lp); finish_check(hMod == 22, hMod); /* hmm, why error 22 ? */ if (hMod == 2) /* command.com not found */ print_string("c:\\command.com couldn't be found. You might want to repeat this test with proper configuration...\n"); /* check loading of Windows file */ hMod = LoadModule("winver.exe", &lp); finish_check((hMod >= 32) || (hMod == 2), hMod); /* successful execution or file not found */ /* check win16 DLL loading */ hMod = LoadModule("kernel", &lp); finish_check(hMod >= 32, hMod); FreeModule(hMod); /* check win32 DLL loading */ hMod = LoadModule("wnaspi32.dll", &lp); /* Wine failure #3 */ finish_check(hMod == 0, hMod); hMod = LoadModule("wnaspi32", &lp); finish_check(hMod == 2, hMod); /* inexistent drive */ hMod = LoadModule("V:\\mytest", &lp); finish_check(hMod == 3, hMod); /* path not found */ /* Wine failure #4 */ #if 0 sprintf(text, "3: %08lx", hMod); MessageBox(GetDesktopWindow(), text, "", MB_OK); #endif TEST_END; } int PASCAL WinMain( HINSTANCE hInst, HINSTANCE hPrevInst, LPSTR lpCmdLine, int nCmdShow) { wt_LoadModule(); return 1; } /* WinMain */
Call For Volunteers: API test suite for Wine To all Windows developers ! Subject: Internet-wide call (about 10000 people required) for a small amount of help on Windows related development About us ======== The Wine project (www.winehq.com), an Open Source (free) Windows compatibility layer for UNIX (Linux, *BSD, ...), has had an astonishing amount of success already at getting various Windows programs (e.g. Office, HalfLife, Internet Explorer) to run on various Unix versions during its 8 years of development. Wine is a very ambitious and huge Open Source project, with contributions of about 300 people: together with Odin, which reuses large chunks of Wine's code, it's the *only* viable true poject which seeks to rewrite a free implementation of Windows from scratch. The landscape is littered with dozens of bodies of proudly announced very similar projects (Windows rewrites) that all found their way into failure after a pretty short time. Where dozens have failed, Wine will "win" (pun intended). Where do YOU come into the picture ? ================================== After 8 years of development, our project is pretty refined already. However by simply testing whether specific programs run, we don't really have a systematic approach of verifying the compatibility of the Windows functions we implemented. Thus there are often regressions (bugs introduced by changes to the code base) that go unnoticed for several months sometimes, thus severely degrading Wine's Windows program compatibility. Having a systematic test suite specially designed to test *every single* Windows function out there as tightly as possible would help a LOT in reducing bugs before the next "official" development release of Wine, simply by doing a run of the whole test suite before release, thus finding almost every problematic code change. Problem is: if you sum up the number of exported functions of public Windows system DLLs, you easily get to a number which almost reaches 12000. 12000 Windows functions !! The Wine project would have considerable problems if it was to implement a whole test suite for this puzzling amount of Windows API functions alongside the "real" implementation of these functions, which is already overwhelming on its own. This is where we desperately need your help: by implementing a test for a specific Windows function that you're pretty familiar with (a matter of about 1 or 2 hours for an experienced programmer) according to the description given below, you'd help us tremenduously ! We'd also be glad to have companies donate some limited development time to help us reach this goal. So why should you be as naive as to help us ? ============================================= Hmm, right. After all the operating system market is very healthy and competitive, so why should I donate time for free for this "pet project" ? Wrong. The operating system market is everything but that (do you still manage to remember OS/2, BeOS, ... ?). That's why we think that it's EXTREMELY important to make sure that Linux and other OSes gain close to 100% Windows compatibility in order to make sure that a barrier to adoption of such OSes gets torn down almost completely. After all just about every PC anywhere runs Windows programs, so you almost *have* to be compatible with that. This very worthwhile goal can only be achieved by rigorous compatibility testing of Wine's implementation of Windows functions, thereby enabling Wine to run almost all Windows programs. Don't you think that the IT market has been under the lock of monopolistic actions far too long, and that there might finally actually be some *real* change for good if YOU get involved ? Great, I'll help, now how to implement a test for a Windows function ? ====================================================================== The files listing the names of the Windows functions waiting to be tested can be found at http://www.winehq.com/source/dlls/ The list at the end of this paragraph indicates the actual files to be found there. E.g. let's take kernel/kernel.spec as an example. This would lead to the URL http://www.winehq.com/source/dlls/kernel/kernel.spec In this file, you find the following entry: type win16 This means that this is a Win16 DLL, in contrast to win32, which would indicate a Win32 DLL, and thus Win32 functions. This entry: 45 pascal16 LoadModule(str ptr) LoadModule16 describes a function entry in Wine's builtin KERNEL.DLL file. All you need to care about is the "LoadModule" entry, which is the Windows function name. The "LoadModule16" entry simply indicates the name of the corresponding Wine function, so it doesn't matter at all. In case of Win32 functions, you could look up their documentation at search.microsoft.com. In case of Win16 functions, check your (older ?) own documentation. Now that I described how to create a test for a particular function (LoadModule), just choose one of the files below, choose a function belonging to it and start coding a test for Wine's test suite ! :-) Or in short: take ANY Windows function that you know pretty well and write a test for it. The following .spec files are available at WineHQ. Choose the one you like best and choose your favourite function from it: gdi/wing.spec gdi/dispdib.spec gdi/gdi.spec gdi/gdi32.spec mpr/mpr.spec sti/sti.spec url/url.spec wsock32/wsock32.spec icmp/icmp.spec qcap/qcap.spec user/ddeml.spec user/user32.spec user/keyboard.spec user/user.spec user/mouse.spec user/display.spec shfolder/shfolder.spec commdlg/comdlg32.spec commdlg/commdlg.spec devenum/devenum.spec oleaut32/ole2disp.spec oleaut32/oleaut32.spec oleaut32/typelib.spec olepro32/olepro32.spec ddraw/ddraw.spec dplay/dplay.spec glu32/glu32.spec imm32/imm.spec imm32/imm32.spec msacm/msacm.spec msacm/msacm32.spec msdmo/msdmo.spec ntdll/ntdll.spec ole32/ole32.spec ole32/ole2prox.spec ole32/ole2.spec ole32/storage.spec ole32/compobj.spec ole32/ole2conv.spec ole32/ole2thk.spec ole32/ole2nls.spec psapi/psapi.spec winmm/winmm.spec winmm/mmsystem.spec winmm/mcianim/mcianim.drv.spec winmm/mciwave/mciwave.drv.spec winmm/midimap/midimap.drv.spec winmm/mciavi/mciavi.drv.spec winmm/mcicda/mcicda.drv.spec winmm/mciseq/mciseq.drv.spec winmm/wavemap/msacm.drv.spec winmm/sound.spec winmm/joystick/joystick.drv.spec winmm/wineoss/wineoss.drv.spec wow32/wow32.spec avicap32/avicap32.spec avifil32/avifile.spec avifil32/avifil32.spec dciman32/dciman32.spec shdocvw/shdocvw.spec shell32/shell32.spec shell32/shell.spec shlwapi/shlwapi.spec lzexpand/lzexpand.spec lzexpand/lz32.spec comctl32/comctl32.spec crtdll/crtdll.spec dinput/dinput.spec dplayx/dplayx.spec dsound/dsound.spec richedit/riched32.spec msimg32/msimg32.spec msnet32/msnet32.spec kernel/comm.spec kernel/kernel32.spec kernel/win87em.spec kernel/kernel.spec kernel/toolhelp.spec kernel/windebug.spec kernel/system.spec kernel/stress.spec msrle32/msrle32.spec msvideo/msvfw32.spec msvideo/msvideo.spec rasapi32/rasapi16.spec rasapi32/rasapi32.spec mapi32/mapi32.spec imagehlp/imagehlp.spec msvcrt/msvcrt.spec odbc32/odbc32.spec olecli/olecli32.spec olecli/olecli.spec oledlg/oledlg.spec olesvr/olesvr32.spec olesvr/olesvr.spec quartz/quartz.spec x11drv/x11drv.spec rpcrt4/rpcrt4.spec winspool/winspool.drv.spec wintrust/wintrust.spec netapi32/netapi32.spec tapi32/tapi32.spec opengl32/opengl32.spec version/version.spec version/ver.spec ttydrv/ttydrv.spec urlmon/urlmon.spec win32s/w32skrnl.spec win32s/win32s16.spec win32s/w32sys.spec wineps/wineps.spec wineps/wineps16.spec winnls/winnls.spec winnls/winnls32.spec serialui/serialui.spec setupapi/setupx.spec setupapi/setupapi.spec advapi32/advapi32.spec winaspi/wnaspi32.spec winaspi/winaspi.spec wininet/wininet.spec winsock/ws2_32.spec winsock/winsock.spec Now let me show you how to implement a program to test a certain function: [add part here explaining my program] Of course this gigantic effort has to be coordinated... Indicate the Windows version that you ran/programmed your test on... Test code should never "crash" on Windows... Maybe make use of exception handlers to cause "crashes" that don't do harm...