2cf35cf7162884e0c4065d149ac449329a11f2c3
[reactos.git] / reactos / include / reactos / 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 #include <wingdi.h>
29 #include <winreg.h>
30
31 #ifdef __WINE_WINE_LIBRARY_H
32 #error wine/library.h should not be used in Wine tests
33 #endif
34 #ifdef __WINE_WINE_UNICODE_H
35 #error wine/unicode.h should not be used in Wine tests
36 #endif
37 #ifdef __WINE_WINE_DEBUG_H
38 #error wine/debug.h should not be used in Wine tests
39 #endif
40
41 #ifndef INVALID_FILE_ATTRIBUTES
42 #define INVALID_FILE_ATTRIBUTES ((DWORD)~0UL)
43 #endif
44 #ifndef INVALID_SET_FILE_POINTER
45 #define INVALID_SET_FILE_POINTER ((DWORD)~0UL)
46 #endif
47
48 /* debug level */
49 extern int winetest_debug;
50
51 /* running in interactive mode? */
52 extern int winetest_interactive;
53
54 /* current platform */
55 extern const char *winetest_platform;
56
57 extern void winetest_set_location( const char* file, int line );
58 extern void winetest_start_todo( const char* platform );
59 extern int winetest_loop_todo(void);
60 extern void winetest_end_todo( const char* platform );
61 extern int winetest_get_mainargs( char*** pargv );
62 extern void winetest_wait_child_process( HANDLE process );
63
64 #ifdef STANDALONE
65 #define START_TEST(name) \
66 static void func_##name(void); \
67 const struct test winetest_testlist[] = { { #name, func_##name }, { 0, 0 } }; \
68 static void func_##name(void)
69 #else
70 #define START_TEST(name) void func_##name(void)
71 #endif
72
73 #ifdef __GNUC__
74
75 extern int winetest_ok( int condition, const char *msg, ... ) __attribute__((format (printf,2,3) ));
76 extern void winetest_skip( const char *msg, ... ) __attribute__((format (printf,1,2)));
77 extern void winetest_trace( const char *msg, ... ) __attribute__((format (printf,1,2)));
78
79 #else /* __GNUC__ */
80
81 extern int winetest_ok( int condition, const char *msg, ... );
82 extern void winetest_skip( const char *msg, ... );
83 extern void winetest_trace( const char *msg, ... );
84
85 #endif /* __GNUC__ */
86
87 #define ok_(file, line) (winetest_set_location(file, line), 0) ? 0 : winetest_ok
88 #define skip_(file, line) (winetest_set_location(file, line), 0) ? (void)0 : winetest_skip
89 #define trace_(file, line) (winetest_set_location(file, line), 0) ? (void)0 : winetest_trace
90
91 #define ok ok_(__FILE__, __LINE__)
92 #define skip skip_(__FILE__, __LINE__)
93 #define trace trace_(__FILE__, __LINE__)
94
95 #define todo(platform) for (winetest_start_todo(platform); \
96 winetest_loop_todo(); \
97 winetest_end_todo(platform))
98 #define todo_wine todo("wine")
99
100
101 #ifdef NONAMELESSUNION
102 # define U(x) (x).u
103 # define U1(x) (x).u1
104 # define U2(x) (x).u2
105 # define U3(x) (x).u3
106 # define U4(x) (x).u4
107 # define U5(x) (x).u5
108 # define U6(x) (x).u6
109 # define U7(x) (x).u7
110 # define U8(x) (x).u8
111 #else
112 # define U(x) (x)
113 # define U1(x) (x)
114 # define U2(x) (x)
115 # define U3(x) (x)
116 # define U4(x) (x)
117 # define U5(x) (x)
118 # define U6(x) (x)
119 # define U7(x) (x)
120 # define U8(x) (x)
121 #endif
122
123 #ifdef NONAMELESSSTRUCT
124 # define S(x) (x).s
125 # define S1(x) (x).s1
126 # define S2(x) (x).s2
127 # define S3(x) (x).s3
128 # define S4(x) (x).s4
129 # define S5(x) (x).s5
130 #else
131 # define S(x) (x)
132 # define S1(x) (x)
133 # define S2(x) (x)
134 # define S3(x) (x)
135 # define S4(x) (x)
136 # define S5(x) (x)
137 #endif
138
139
140 /************************************************************************/
141 /* Below is the implementation of the various functions, to be included
142 * directly into the generated testlist.c file.
143 * It is done that way so that the dlls can build the test routines with
144 * different includes or flags if needed.
145 */
146
147 #ifdef STANDALONE
148
149 #include <stdio.h>
150
151 struct test
152 {
153 const char *name;
154 void (*func)(void);
155 };
156
157 extern const struct test winetest_testlist[];
158
159 /* debug level */
160 int winetest_debug = 1;
161
162 /* interactive mode? */
163 int winetest_interactive = 0;
164
165 /* current platform */
166 const char *winetest_platform = "windows";
167
168 /* report successful tests (BOOL) */
169 static int report_success = 0;
170
171 /* passing arguments around */
172 static int winetest_argc;
173 static char** winetest_argv;
174
175 static const struct test *current_test; /* test currently being run */
176
177 static LONG successes; /* number of successful tests */
178 static LONG failures; /* number of failures */
179 static LONG skipped; /* number of skipped test chunks */
180 static LONG todo_successes; /* number of successful tests inside todo block */
181 static LONG todo_failures; /* number of failures inside todo block */
182
183 /* The following data must be kept track of on a per-thread basis */
184 typedef struct
185 {
186 const char* current_file; /* file of current check */
187 int current_line; /* line of current check */
188 int todo_level; /* current todo nesting level */
189 int todo_do_loop;
190 } tls_data;
191 static DWORD tls_index;
192
193 static tls_data* get_tls_data(void)
194 {
195 tls_data* data;
196 DWORD last_error;
197
198 last_error=GetLastError();
199 data=TlsGetValue(tls_index);
200 if (!data)
201 {
202 data=HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(tls_data));
203 TlsSetValue(tls_index,data);
204 }
205 SetLastError(last_error);
206 return data;
207 }
208
209 static void exit_process( int code )
210 {
211 fflush( stdout );
212 ExitProcess( code );
213 }
214
215
216 void winetest_set_location( const char* file, int line )
217 {
218 tls_data* data=get_tls_data();
219 data->current_file=strrchr(file,'/');
220 if (data->current_file==NULL)
221 data->current_file=strrchr(file,'\\');
222 if (data->current_file==NULL)
223 data->current_file=file;
224 else
225 data->current_file++;
226 data->current_line=line;
227 }
228
229 /*
230 * Checks condition.
231 * Parameters:
232 * - condition - condition to check;
233 * - msg test description;
234 * - file - test application source code file name of the check
235 * - line - test application source code file line number of the check
236 * Return:
237 * 0 if condition does not have the expected value, 1 otherwise
238 */
239 int winetest_ok( int condition, const char *msg, ... )
240 {
241 va_list valist;
242 tls_data* data=get_tls_data();
243
244 if (data->todo_level)
245 {
246 if (condition)
247 {
248 fprintf( stdout, "%s:%d: Test succeeded inside todo block",
249 data->current_file, data->current_line );
250 if (msg[0])
251 {
252 va_start(valist, msg);
253 fprintf(stdout,": ");
254 vfprintf(stdout, msg, valist);
255 va_end(valist);
256 }
257 InterlockedIncrement(&todo_failures);
258 return 0;
259 }
260 else InterlockedIncrement(&todo_successes);
261 }
262 else
263 {
264 if (!condition)
265 {
266 fprintf( stdout, "%s:%d: Test failed",
267 data->current_file, data->current_line );
268 if (msg[0])
269 {
270 va_start(valist, msg);
271 fprintf( stdout,": ");
272 vfprintf(stdout, msg, valist);
273 va_end(valist);
274 }
275 InterlockedIncrement(&failures);
276 return 0;
277 }
278 else
279 {
280 if (report_success)
281 fprintf( stdout, "%s:%d: Test succeeded\n",
282 data->current_file, data->current_line);
283 InterlockedIncrement(&successes);
284 }
285 }
286 return 1;
287 }
288
289 void winetest_trace( const char *msg, ... )
290 {
291 va_list valist;
292 tls_data* data=get_tls_data();
293
294 if (winetest_debug > 0)
295 {
296 fprintf( stdout, "%s:%d:", data->current_file, data->current_line );
297 va_start(valist, msg);
298 vfprintf(stdout, msg, valist);
299 va_end(valist);
300 }
301 }
302
303 void winetest_skip( const char *msg, ... )
304 {
305 va_list valist;
306 tls_data* data=get_tls_data();
307
308 fprintf( stdout, "%s:%d: Tests skipped: ", data->current_file, data->current_line );
309 va_start(valist, msg);
310 vfprintf(stdout, msg, valist);
311 va_end(valist);
312 skipped++;
313 }
314
315 void winetest_start_todo( const char* platform )
316 {
317 tls_data* data=get_tls_data();
318 if (strcmp(winetest_platform,platform)==0)
319 data->todo_level++;
320 data->todo_do_loop=1;
321 }
322
323 int winetest_loop_todo(void)
324 {
325 tls_data* data=get_tls_data();
326 int do_loop=data->todo_do_loop;
327 data->todo_do_loop=0;
328 return do_loop;
329 }
330
331 void winetest_end_todo( const char* platform )
332 {
333 if (strcmp(winetest_platform,platform)==0)
334 {
335 tls_data* data=get_tls_data();
336 data->todo_level--;
337 }
338 }
339
340 int winetest_get_mainargs( char*** pargv )
341 {
342 *pargv = winetest_argv;
343 return winetest_argc;
344 }
345
346 void winetest_wait_child_process( HANDLE process )
347 {
348 DWORD exit_code = 1;
349
350 if (WaitForSingleObject( process, 30000 ))
351 fprintf( stdout, "%s: child process wait failed\n", current_test->name );
352 else
353 GetExitCodeProcess( process, &exit_code );
354
355 if (exit_code)
356 {
357 if (exit_code > 255)
358 {
359 fprintf( stdout, "%s: exception 0x%08x in child process\n", current_test->name, exit_code );
360 InterlockedIncrement( &failures );
361 }
362 else
363 {
364 fprintf( stdout, "%s: %u failures in child process\n",
365 current_test->name, exit_code );
366 while (exit_code-- > 0)
367 InterlockedIncrement(&failures);
368 }
369 }
370 }
371
372 /* Find a test by name */
373 static const struct test *find_test( const char *name )
374 {
375 const struct test *test;
376 const char *p;
377 int len;
378
379 if ((p = strrchr( name, '/' ))) name = p + 1;
380 if ((p = strrchr( name, '\\' ))) name = p + 1;
381 len = strlen(name);
382 if (len > 2 && !strcmp( name + len - 2, ".c" )) len -= 2;
383
384 for (test = winetest_testlist; test->name; test++)
385 {
386 if (!strncmp( test->name, name, len ) && !test->name[len]) break;
387 }
388 return test->name ? test : NULL;
389 }
390
391
392 /* Display list of valid tests */
393 static void list_tests(void)
394 {
395 const struct test *test;
396
397 fprintf( stdout, "Valid test names:\n" );
398 for (test = winetest_testlist; test->name; test++) fprintf( stdout, " %s\n", test->name );
399 }
400
401
402 /* Run a named test, and return exit status */
403 static int run_test( const char *name )
404 {
405 const struct test *test;
406 int status;
407
408 if (!(test = find_test( name )))
409 {
410 fprintf( stdout, "Fatal: test '%s' does not exist.\n", name );
411 exit_process(1);
412 }
413 successes = failures = todo_successes = todo_failures = 0;
414 tls_index=TlsAlloc();
415 current_test = test;
416 test->func();
417
418 if (winetest_debug)
419 {
420 fprintf( stdout, "%s: %d tests executed (%d marked as todo, %d %s), %d skipped.\n",
421 test->name, successes + failures + todo_successes + todo_failures,
422 todo_successes, failures + todo_failures,
423 (failures + todo_failures != 1) ? "failures" : "failure",
424 skipped );
425 }
426 status = (failures + todo_failures < 255) ? failures + todo_failures : 255;
427 return status;
428 }
429
430
431 /* Display usage and exit */
432 static void usage( const char *argv0 )
433 {
434 fprintf( stdout, "Usage: %s test_name\n\n", argv0 );
435 list_tests();
436 exit_process(1);
437 }
438
439
440 /* main function */
441 int main( int argc, char **argv )
442 {
443 char *p;
444
445 setvbuf (stdout, NULL, _IONBF, 0);
446
447 winetest_argc = argc;
448 winetest_argv = argv;
449
450 if ((p = getenv( "WINETEST_PLATFORM" ))) winetest_platform = strdup(p);
451 if ((p = getenv( "WINETEST_DEBUG" ))) winetest_debug = atoi(p);
452 if ((p = getenv( "WINETEST_INTERACTIVE" ))) winetest_interactive = atoi(p);
453 if ((p = getenv( "WINETEST_REPORT_SUCCESS"))) report_success = atoi(p);
454 if (!argv[1])
455 {
456 if (winetest_testlist[0].name && !winetest_testlist[1].name) /* only one test */
457 return run_test( winetest_testlist[0].name );
458 usage( argv[0] );
459 }
460 if (!strcmp( argv[1], "--list" ))
461 {
462 list_tests();
463 return 0;
464 }
465 return run_test(argv[1]);
466 }
467
468 #endif /* STANDALONE */
469
470 #endif /* __WINE_WINE_TEST_H */