Release 1.5.29.
[wine] / include / wine / test.h
1 /*
2  * Definitions for Wine C unit tests.
3  *
4  * Copyright (C) 2002 Alexandre Julliard
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  */
20
21 #ifndef __WINE_WINE_TEST_H
22 #define __WINE_WINE_TEST_H
23
24 #include <stdarg.h>
25 #include <stdlib.h>
26 #include <windef.h>
27 #include <winbase.h>
28
29 #ifdef __WINE_CONFIG_H
30 #error config.h should not be used in Wine tests
31 #endif
32 #ifdef __WINE_WINE_LIBRARY_H
33 #error wine/library.h should not be used in Wine tests
34 #endif
35 #ifdef __WINE_WINE_UNICODE_H
36 #error wine/unicode.h should not be used in Wine tests
37 #endif
38 #ifdef __WINE_WINE_DEBUG_H
39 #error wine/debug.h should not be used in Wine tests
40 #endif
41
42 #ifndef INVALID_FILE_ATTRIBUTES
43 #define INVALID_FILE_ATTRIBUTES  (~0u)
44 #endif
45 #ifndef INVALID_SET_FILE_POINTER
46 #define INVALID_SET_FILE_POINTER (~0u)
47 #endif
48
49 /* debug level */
50 extern int winetest_debug;
51
52 /* running in interactive mode? */
53 extern int winetest_interactive;
54
55 /* current platform */
56 extern const char *winetest_platform;
57
58 extern void winetest_set_location( const char* file, int line );
59 extern void winetest_start_todo( const char* platform );
60 extern int winetest_loop_todo(void);
61 extern void winetest_end_todo( const char* platform );
62 extern int winetest_get_mainargs( char*** pargv );
63 extern LONG winetest_get_failures(void);
64 extern void winetest_add_failures( LONG new_failures );
65 extern void winetest_wait_child_process( HANDLE process );
66
67 extern const char *wine_dbgstr_wn( const WCHAR *str, int n );
68 static inline const char *wine_dbgstr_w( const WCHAR *s ) { return wine_dbgstr_wn( s, -1 ); }
69
70 /* strcmpW is available for tests compiled under Wine, but not in standalone
71  * builds under Windows, so we reimplement it under a different name. */
72 static inline int winetest_strcmpW( const WCHAR *str1, const WCHAR *str2 )
73 {
74     while (*str1 && (*str1 == *str2)) { str1++; str2++; }
75     return *str1 - *str2;
76 }
77
78 #ifdef STANDALONE
79 #define START_TEST(name) \
80   static void func_##name(void); \
81   const struct test winetest_testlist[] = { { #name, func_##name }, { 0, 0 } }; \
82   static void func_##name(void)
83 #else
84 #define START_TEST(name) void func_##name(void)
85 #endif
86
87 #if defined(__x86_64__) && defined(__GNUC__) && defined(__WINE_USE_MSVCRT)
88 #define __winetest_cdecl __cdecl
89 #define __winetest_va_list __builtin_ms_va_list
90 #else
91 #define __winetest_cdecl
92 #define __winetest_va_list va_list
93 #endif
94
95 extern int broken( int condition );
96 extern int winetest_vok( int condition, const char *msg, __winetest_va_list ap );
97 extern void winetest_vskip( const char *msg, __winetest_va_list ap );
98
99 #ifdef __GNUC__
100
101 extern void __winetest_cdecl winetest_ok( int condition, const char *msg, ... ) __attribute__((format (printf,2,3) ));
102 extern void __winetest_cdecl winetest_skip( const char *msg, ... ) __attribute__((format (printf,1,2)));
103 extern void __winetest_cdecl winetest_win_skip( const char *msg, ... ) __attribute__((format (printf,1,2)));
104 extern void __winetest_cdecl winetest_trace( const char *msg, ... ) __attribute__((format (printf,1,2)));
105
106 #else /* __GNUC__ */
107
108 extern void __winetest_cdecl winetest_ok( int condition, const char *msg, ... );
109 extern void __winetest_cdecl winetest_skip( const char *msg, ... );
110 extern void __winetest_cdecl winetest_win_skip( const char *msg, ... );
111 extern void __winetest_cdecl winetest_trace( const char *msg, ... );
112
113 #endif /* __GNUC__ */
114
115 #define ok_(file, line)       (winetest_set_location(file, line), 0) ? (void)0 : winetest_ok
116 #define skip_(file, line)     (winetest_set_location(file, line), 0) ? (void)0 : winetest_skip
117 #define win_skip_(file, line) (winetest_set_location(file, line), 0) ? (void)0 : winetest_win_skip
118 #define trace_(file, line)    (winetest_set_location(file, line), 0) ? (void)0 : winetest_trace
119
120 #define ok       ok_(__FILE__, __LINE__)
121 #define skip     skip_(__FILE__, __LINE__)
122 #define win_skip win_skip_(__FILE__, __LINE__)
123 #define trace    trace_(__FILE__, __LINE__)
124
125 #define todo(platform) for (winetest_start_todo(platform); \
126                             winetest_loop_todo(); \
127                             winetest_end_todo(platform))
128 #define todo_wine      todo("wine")
129
130
131 #ifdef NONAMELESSUNION
132 # define U(x)  (x).u
133 # define U1(x) (x).u1
134 # define U2(x) (x).u2
135 # define U3(x) (x).u3
136 # define U4(x) (x).u4
137 # define U5(x) (x).u5
138 # define U6(x) (x).u6
139 # define U7(x) (x).u7
140 # define U8(x) (x).u8
141 #else
142 # define U(x)  (x)
143 # define U1(x) (x)
144 # define U2(x) (x)
145 # define U3(x) (x)
146 # define U4(x) (x)
147 # define U5(x) (x)
148 # define U6(x) (x)
149 # define U7(x) (x)
150 # define U8(x) (x)
151 #endif
152
153 #ifdef NONAMELESSSTRUCT
154 # define S(x)  (x).s
155 # define S1(x) (x).s1
156 # define S2(x) (x).s2
157 # define S3(x) (x).s3
158 # define S4(x) (x).s4
159 # define S5(x) (x).s5
160 #else
161 # define S(x)  (x)
162 # define S1(x) (x)
163 # define S2(x) (x)
164 # define S3(x) (x)
165 # define S4(x) (x)
166 # define S5(x) (x)
167 #endif
168
169
170 /************************************************************************/
171 /* Below is the implementation of the various functions, to be included
172  * directly into the generated testlist.c file.
173  * It is done that way so that the dlls can build the test routines with
174  * different includes or flags if needed.
175  */
176
177 #ifdef STANDALONE
178
179 #include <stdio.h>
180 #include <excpt.h>
181
182 #if defined(__x86_64__) && defined(__GNUC__) && defined(__WINE_USE_MSVCRT)
183 # define __winetest_va_start(list,arg) __builtin_ms_va_start(list,arg)
184 # define __winetest_va_end(list) __builtin_ms_va_end(list)
185 #else
186 # define __winetest_va_start(list,arg) va_start(list,arg)
187 # define __winetest_va_end(list) va_end(list)
188 #endif
189
190 struct test
191 {
192     const char *name;
193     void (*func)(void);
194 };
195
196 extern const struct test winetest_testlist[];
197
198 /* debug level */
199 int winetest_debug = 1;
200
201 /* interactive mode? */
202 int winetest_interactive = 0;
203
204 /* current platform */
205 const char *winetest_platform = "windows";
206
207 /* report successful tests (BOOL) */
208 static int report_success = 0;
209
210 /* passing arguments around */
211 static int winetest_argc;
212 static char** winetest_argv;
213
214 static const struct test *current_test; /* test currently being run */
215
216 static LONG successes;       /* number of successful tests */
217 static LONG failures;        /* number of failures */
218 static LONG skipped;         /* number of skipped test chunks */
219 static LONG todo_successes;  /* number of successful tests inside todo block */
220 static LONG todo_failures;   /* number of failures inside todo block */
221
222 /* The following data must be kept track of on a per-thread basis */
223 typedef struct
224 {
225     const char* current_file;        /* file of current check */
226     int current_line;                /* line of current check */
227     int todo_level;                  /* current todo nesting level */
228     int todo_do_loop;
229     char *str_pos;                   /* position in debug buffer */
230     char strings[2000];              /* buffer for debug strings */
231 } tls_data;
232 static DWORD tls_index;
233
234 static tls_data* get_tls_data(void)
235 {
236     tls_data* data;
237     DWORD last_error;
238
239     last_error=GetLastError();
240     data=TlsGetValue(tls_index);
241     if (!data)
242     {
243         data=HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(tls_data));
244         data->str_pos = data->strings;
245         TlsSetValue(tls_index,data);
246     }
247     SetLastError(last_error);
248     return data;
249 }
250
251 /* allocate some tmp space for a string */
252 static char *get_temp_buffer( size_t n )
253 {
254     tls_data *data = get_tls_data();
255     char *res = data->str_pos;
256
257     if (res + n >= &data->strings[sizeof(data->strings)]) res = data->strings;
258     data->str_pos = res + n;
259     return res;
260 }
261
262 /* release extra space that we requested in gimme1() */
263 static void release_temp_buffer( char *ptr, size_t size )
264 {
265     tls_data *data = get_tls_data();
266     data->str_pos = ptr + size;
267 }
268
269 static void exit_process( int code )
270 {
271     fflush( stdout );
272     ExitProcess( code );
273 }
274
275
276 void winetest_set_location( const char* file, int line )
277 {
278     tls_data* data=get_tls_data();
279     data->current_file=strrchr(file,'/');
280     if (data->current_file==NULL)
281         data->current_file=strrchr(file,'\\');
282     if (data->current_file==NULL)
283         data->current_file=file;
284     else
285         data->current_file++;
286     data->current_line=line;
287 }
288
289 int broken( int condition )
290 {
291     return (strcmp(winetest_platform, "windows") == 0) && condition;
292 }
293
294 /*
295  * Checks condition.
296  * Parameters:
297  *   - condition - condition to check;
298  *   - msg test description;
299  *   - file - test application source code file name of the check
300  *   - line - test application source code file line number of the check
301  * Return:
302  *   0 if condition does not have the expected value, 1 otherwise
303  */
304 int winetest_vok( int condition, const char *msg, __winetest_va_list args )
305 {
306     tls_data* data=get_tls_data();
307
308     if (data->todo_level)
309     {
310         if (condition)
311         {
312             fprintf( stdout, "%s:%d: Test succeeded inside todo block: ",
313                      data->current_file, data->current_line );
314             vfprintf(stdout, msg, args);
315             InterlockedIncrement(&todo_failures);
316             return 0;
317         }
318         else
319         {
320             if (winetest_debug > 0)
321             {
322                 fprintf( stdout, "%s:%d: Test marked todo: ",
323                          data->current_file, data->current_line );
324                 vfprintf(stdout, msg, args);
325             }
326             InterlockedIncrement(&todo_successes);
327             return 1;
328         }
329     }
330     else
331     {
332         if (!condition)
333         {
334             fprintf( stdout, "%s:%d: Test failed: ",
335                      data->current_file, data->current_line );
336             vfprintf(stdout, msg, args);
337             InterlockedIncrement(&failures);
338             return 0;
339         }
340         else
341         {
342             if (report_success)
343                 fprintf( stdout, "%s:%d: Test succeeded\n",
344                          data->current_file, data->current_line);
345             InterlockedIncrement(&successes);
346             return 1;
347         }
348     }
349 }
350
351 void __winetest_cdecl winetest_ok( int condition, const char *msg, ... )
352 {
353     __winetest_va_list valist;
354
355     __winetest_va_start(valist, msg);
356     winetest_vok(condition, msg, valist);
357     __winetest_va_end(valist);
358 }
359
360 void __winetest_cdecl winetest_trace( const char *msg, ... )
361 {
362     __winetest_va_list valist;
363     tls_data* data=get_tls_data();
364
365     if (winetest_debug > 0)
366     {
367         fprintf( stdout, "%s:%d: ", data->current_file, data->current_line );
368         __winetest_va_start(valist, msg);
369         vfprintf(stdout, msg, valist);
370         __winetest_va_end(valist);
371     }
372 }
373
374 void winetest_vskip( const char *msg, __winetest_va_list args )
375 {
376     tls_data* data=get_tls_data();
377
378     fprintf( stdout, "%s:%d: Tests skipped: ", data->current_file, data->current_line );
379     vfprintf(stdout, msg, args);
380     skipped++;
381 }
382
383 void __winetest_cdecl winetest_skip( const char *msg, ... )
384 {
385     __winetest_va_list valist;
386     __winetest_va_start(valist, msg);
387     winetest_vskip(msg, valist);
388     __winetest_va_end(valist);
389 }
390
391 void __winetest_cdecl winetest_win_skip( const char *msg, ... )
392 {
393     __winetest_va_list valist;
394     __winetest_va_start(valist, msg);
395     if (strcmp(winetest_platform, "windows") == 0)
396         winetest_vskip(msg, valist);
397     else
398         winetest_vok(0, msg, valist);
399     __winetest_va_end(valist);
400 }
401
402 void winetest_start_todo( const char* platform )
403 {
404     tls_data* data=get_tls_data();
405     if (strcmp(winetest_platform,platform)==0)
406         data->todo_level++;
407     data->todo_do_loop=1;
408 }
409
410 int winetest_loop_todo(void)
411 {
412     tls_data* data=get_tls_data();
413     int do_loop=data->todo_do_loop;
414     data->todo_do_loop=0;
415     return do_loop;
416 }
417
418 void winetest_end_todo( const char* platform )
419 {
420     if (strcmp(winetest_platform,platform)==0)
421     {
422         tls_data* data=get_tls_data();
423         data->todo_level--;
424     }
425 }
426
427 int winetest_get_mainargs( char*** pargv )
428 {
429     *pargv = winetest_argv;
430     return winetest_argc;
431 }
432
433 LONG winetest_get_failures(void)
434 {
435     return failures;
436 }
437
438 void winetest_add_failures( LONG new_failures )
439 {
440     while (new_failures-- > 0)
441         InterlockedIncrement( &failures );
442 }
443
444 void winetest_wait_child_process( HANDLE process )
445 {
446     DWORD exit_code = 1;
447
448     if (WaitForSingleObject( process, 30000 ))
449         fprintf( stdout, "%s: child process wait failed\n", current_test->name );
450     else
451         GetExitCodeProcess( process, &exit_code );
452
453     if (exit_code)
454     {
455         if (exit_code > 255)
456         {
457             fprintf( stdout, "%s: exception 0x%08x in child process\n", current_test->name, exit_code );
458             InterlockedIncrement( &failures );
459         }
460         else
461         {
462             fprintf( stdout, "%s: %u failures in child process\n",
463                      current_test->name, exit_code );
464             while (exit_code-- > 0)
465                 InterlockedIncrement(&failures);
466         }
467     }
468 }
469
470 const char *wine_dbgstr_wn( const WCHAR *str, int n )
471 {
472     char *dst, *res;
473     size_t size;
474
475     if (!((ULONG_PTR)str >> 16))
476     {
477         if (!str) return "(null)";
478         res = get_temp_buffer( 6 );
479         sprintf( res, "#%04x", LOWORD(str) );
480         return res;
481     }
482     if (n == -1)
483     {
484         const WCHAR *end = str;
485         while (*end) end++;
486         n = end - str;
487     }
488     if (n < 0) n = 0;
489     size = 12 + min( 300, n * 5 );
490     dst = res = get_temp_buffer( size );
491     *dst++ = 'L';
492     *dst++ = '"';
493     while (n-- > 0 && dst <= res + size - 10)
494     {
495         WCHAR c = *str++;
496         switch (c)
497         {
498         case '\n': *dst++ = '\\'; *dst++ = 'n'; break;
499         case '\r': *dst++ = '\\'; *dst++ = 'r'; break;
500         case '\t': *dst++ = '\\'; *dst++ = 't'; break;
501         case '"':  *dst++ = '\\'; *dst++ = '"'; break;
502         case '\\': *dst++ = '\\'; *dst++ = '\\'; break;
503         default:
504             if (c >= ' ' && c <= 126)
505                 *dst++ = c;
506             else
507             {
508                 *dst++ = '\\';
509                 sprintf(dst,"%04x",c);
510                 dst+=4;
511             }
512         }
513     }
514     *dst++ = '"';
515     if (n > 0)
516     {
517         *dst++ = '.';
518         *dst++ = '.';
519         *dst++ = '.';
520     }
521     *dst++ = 0;
522     release_temp_buffer( res, dst - res );
523     return res;
524 }
525
526 /* Find a test by name */
527 static const struct test *find_test( const char *name )
528 {
529     const struct test *test;
530     const char *p;
531     size_t len;
532
533     if ((p = strrchr( name, '/' ))) name = p + 1;
534     if ((p = strrchr( name, '\\' ))) name = p + 1;
535     len = strlen(name);
536     if (len > 2 && !strcmp( name + len - 2, ".c" )) len -= 2;
537
538     for (test = winetest_testlist; test->name; test++)
539     {
540         if (!strncmp( test->name, name, len ) && !test->name[len]) break;
541     }
542     return test->name ? test : NULL;
543 }
544
545
546 /* Display list of valid tests */
547 static void list_tests(void)
548 {
549     const struct test *test;
550
551     fprintf( stdout, "Valid test names:\n" );
552     for (test = winetest_testlist; test->name; test++) fprintf( stdout, "    %s\n", test->name );
553 }
554
555
556 /* Run a named test, and return exit status */
557 static int run_test( const char *name )
558 {
559     const struct test *test;
560     int status;
561
562     if (!(test = find_test( name )))
563     {
564         fprintf( stdout, "Fatal: test '%s' does not exist.\n", name );
565         exit_process(1);
566     }
567     successes = failures = todo_successes = todo_failures = 0;
568     tls_index=TlsAlloc();
569     current_test = test;
570     test->func();
571
572     if (winetest_debug)
573     {
574         fprintf( stdout, "%s: %d tests executed (%d marked as todo, %d %s), %d skipped.\n",
575                  test->name, successes + failures + todo_successes + todo_failures,
576                  todo_successes, failures + todo_failures,
577                  (failures + todo_failures != 1) ? "failures" : "failure",
578                  skipped );
579     }
580     status = (failures + todo_failures < 255) ? failures + todo_failures : 255;
581     return status;
582 }
583
584
585 /* Display usage and exit */
586 static void usage( const char *argv0 )
587 {
588     fprintf( stdout, "Usage: %s test_name\n\n", argv0 );
589     list_tests();
590     exit_process(1);
591 }
592
593 /* trap unhandled exceptions */
594 static LONG CALLBACK exc_filter( EXCEPTION_POINTERS *ptrs )
595 {
596     tls_data *data = get_tls_data();
597
598     if (data->current_file)
599         fprintf( stdout, "%s:%d: this is the last test seen before the exception\n",
600                  data->current_file, data->current_line );
601     fprintf( stdout, "%s: unhandled exception %08x at %p\n", current_test->name,
602              ptrs->ExceptionRecord->ExceptionCode, ptrs->ExceptionRecord->ExceptionAddress );
603     fflush( stdout );
604     return EXCEPTION_EXECUTE_HANDLER;
605 }
606
607 #ifdef __GNUC__
608 void _fpreset(void) {} /* override the mingw fpu init code */
609 #endif
610
611 /* main function */
612 int main( int argc, char **argv )
613 {
614     char p[128];
615
616     setvbuf (stdout, NULL, _IONBF, 0);
617
618     winetest_argc = argc;
619     winetest_argv = argv;
620
621     if (GetEnvironmentVariableA( "WINETEST_PLATFORM", p, sizeof(p) )) winetest_platform = strdup(p);
622     if (GetEnvironmentVariableA( "WINETEST_DEBUG", p, sizeof(p) )) winetest_debug = atoi(p);
623     if (GetEnvironmentVariableA( "WINETEST_INTERACTIVE", p, sizeof(p) )) winetest_interactive = atoi(p);
624     if (GetEnvironmentVariableA( "WINETEST_REPORT_SUCCESS", p, sizeof(p) )) report_success = atoi(p);
625
626     if (!strcmp( winetest_platform, "windows" )) SetUnhandledExceptionFilter( exc_filter );
627     if (!winetest_interactive) SetErrorMode( SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX );
628
629     if (!argv[1])
630     {
631         if (winetest_testlist[0].name && !winetest_testlist[1].name)  /* only one test */
632             return run_test( winetest_testlist[0].name );
633         usage( argv[0] );
634     }
635     if (!strcmp( argv[1], "--list" ))
636     {
637         list_tests();
638         return 0;
639     }
640     return run_test(argv[1]);
641 }
642
643 #endif  /* STANDALONE */
644
645 #endif  /* __WINE_WINE_TEST_H */