| 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|---|
| 19 | */
|
|---|
| 20 |
|
|---|
| 21 | #ifndef __WINE_TEST_H
|
|---|
| 22 | #define __WINE_TEST_H
|
|---|
| 23 |
|
|---|
| 24 |
|
|---|
| 25 | #include <stdarg.h>
|
|---|
| 26 | #include "windef.h"
|
|---|
| 27 |
|
|---|
| 28 | /* debug level */
|
|---|
| 29 | extern int winetest_debug;
|
|---|
| 30 |
|
|---|
| 31 | /* running in interactive mode? */
|
|---|
| 32 | extern int winetest_interactive;
|
|---|
| 33 |
|
|---|
| 34 | /* current platform */
|
|---|
| 35 | extern const char *winetest_platform;
|
|---|
| 36 |
|
|---|
| 37 | extern void winetest_set_location( const char* file, int line );
|
|---|
| 38 | extern void winetest_start_todo( const char* platform );
|
|---|
| 39 | extern int winetest_loop_todo(void);
|
|---|
| 40 | extern void winetest_end_todo( const char* platform );
|
|---|
| 41 | extern int winetest_get_mainargs( char*** pargv );
|
|---|
| 42 |
|
|---|
| 43 | #define START_TEST(name) void func_##name(void)
|
|---|
| 44 |
|
|---|
| 45 | #ifdef __GNUC__
|
|---|
| 46 |
|
|---|
| 47 | extern int winetest_ok( int condition, const char *msg, ... ) __attribute__((format (printf,2,3) ));
|
|---|
| 48 | extern void winetest_trace( const char *msg, ... ) __attribute__((format (printf,1,2)));
|
|---|
| 49 |
|
|---|
| 50 | #else /* __GNUC__ */
|
|---|
| 51 |
|
|---|
| 52 | extern int winetest_ok( int condition, const char *msg, ... );
|
|---|
| 53 | extern void winetest_trace( const char *msg, ... );
|
|---|
| 54 |
|
|---|
| 55 | #endif /* __GNUC__ */
|
|---|
| 56 |
|
|---|
| 57 | #define ok_(file, line) (winetest_set_location(file, line), 0) ? 0 : winetest_ok
|
|---|
| 58 | #define trace_(file, line) (winetest_set_location(file, line), 0) ? (void)0 : winetest_trace
|
|---|
| 59 |
|
|---|
| 60 | #define ok ok_(__FILE__, __LINE__)
|
|---|
| 61 | #define trace trace_(__FILE__, __LINE__)
|
|---|
| 62 |
|
|---|
| 63 | #define todo(platform) for (winetest_start_todo(platform); \
|
|---|
| 64 | winetest_loop_todo(); \
|
|---|
| 65 | winetest_end_todo(platform))
|
|---|
| 66 | #define todo_wine todo("wine")
|
|---|
| 67 |
|
|---|
| 68 |
|
|---|
| 69 | /************************************************************************/
|
|---|
| 70 | /* Below is the implementation of the various functions, to be included
|
|---|
| 71 | * directly into the generated testlist.c file.
|
|---|
| 72 | * It is done that way so that the dlls can build the test routines with
|
|---|
| 73 | * different includes or flags if needed.
|
|---|
| 74 | */
|
|---|
| 75 |
|
|---|
| 76 | #ifdef WINETEST_WANT_MAIN
|
|---|
| 77 |
|
|---|
| 78 | /* debug level */
|
|---|
| 79 | int winetest_debug = 1;
|
|---|
| 80 |
|
|---|
| 81 | /* interactive mode? */
|
|---|
| 82 | int winetest_interactive = 0;
|
|---|
| 83 |
|
|---|
| 84 | /* current platform */
|
|---|
| 85 | const char *winetest_platform = "windows";
|
|---|
| 86 |
|
|---|
| 87 | /* report successful tests (BOOL) */
|
|---|
| 88 | static int report_success = 0;
|
|---|
| 89 |
|
|---|
| 90 | /* passing arguments around */
|
|---|
| 91 | static int winetest_argc;
|
|---|
| 92 | static char** winetest_argv;
|
|---|
| 93 |
|
|---|
| 94 | static const struct test *current_test; /* test currently being run */
|
|---|
| 95 |
|
|---|
| 96 | static LONG successes; /* number of successful tests */
|
|---|
| 97 | static LONG failures; /* number of failures */
|
|---|
| 98 | static LONG todo_successes; /* number of successful tests inside todo block */
|
|---|
| 99 | static LONG todo_failures; /* number of failures inside todo block */
|
|---|
| 100 |
|
|---|
| 101 | /* The following data must be kept track of on a per-thread basis */
|
|---|
| 102 | typedef struct
|
|---|
| 103 | {
|
|---|
| 104 | const char* current_file; /* file of current check */
|
|---|
| 105 | int current_line; /* line of current check */
|
|---|
| 106 | int todo_level; /* current todo nesting level */
|
|---|
| 107 | int todo_do_loop;
|
|---|
| 108 | } tls_data;
|
|---|
| 109 | static DWORD tls_index;
|
|---|
| 110 |
|
|---|
| 111 | static tls_data* get_tls_data(void)
|
|---|
| 112 | {
|
|---|
| 113 | tls_data* data;
|
|---|
| 114 | DWORD last_error;
|
|---|
| 115 |
|
|---|
| 116 | last_error=GetLastError();
|
|---|
| 117 | data=TlsGetValue(tls_index);
|
|---|
| 118 | if (!data)
|
|---|
| 119 | {
|
|---|
| 120 | data=HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(tls_data));
|
|---|
| 121 | TlsSetValue(tls_index,data);
|
|---|
| 122 | }
|
|---|
| 123 | SetLastError(last_error);
|
|---|
| 124 | return data;
|
|---|
| 125 | }
|
|---|
| 126 |
|
|---|
| 127 | static void exit_process( int code )
|
|---|
| 128 | {
|
|---|
| 129 | fflush( stdout );
|
|---|
| 130 | ExitProcess( code );
|
|---|
| 131 | }
|
|---|
| 132 |
|
|---|
| 133 |
|
|---|
| 134 | void winetest_set_location( const char* file, int line )
|
|---|
| 135 | {
|
|---|
| 136 | tls_data* data=get_tls_data();
|
|---|
| 137 | data->current_file=strrchr(file,'/');
|
|---|
| 138 | if (data->current_file==NULL)
|
|---|
| 139 | data->current_file=strrchr(file,'\\');
|
|---|
| 140 | if (data->current_file==NULL)
|
|---|
| 141 | data->current_file=file;
|
|---|
| 142 | else
|
|---|
| 143 | data->current_file++;
|
|---|
| 144 | data->current_line=line;
|
|---|
| 145 | }
|
|---|
| 146 |
|
|---|
| 147 | /*
|
|---|
| 148 | * Checks condition.
|
|---|
| 149 | * Parameters:
|
|---|
| 150 | * - condition - condition to check;
|
|---|
| 151 | * - msg test description;
|
|---|
| 152 | * - file - test application source code file name of the check
|
|---|
| 153 | * - line - test application source code file line number of the check
|
|---|
| 154 | * Return:
|
|---|
| 155 | * 0 if condition does not have the expected value, 1 otherwise
|
|---|
| 156 | */
|
|---|
| 157 | int winetest_ok( int condition, const char *msg, ... )
|
|---|
| 158 | {
|
|---|
| 159 | va_list valist;
|
|---|
| 160 | tls_data* data=get_tls_data();
|
|---|
| 161 |
|
|---|
| 162 | if (data->todo_level)
|
|---|
| 163 | {
|
|---|
| 164 | if (condition)
|
|---|
| 165 | {
|
|---|
| 166 | fprintf( stdout, "%s:%d: Test succeeded inside todo block",
|
|---|
| 167 | data->current_file, data->current_line );
|
|---|
| 168 | if (msg && msg[0])
|
|---|
| 169 | {
|
|---|
| 170 | va_start(valist, msg);
|
|---|
| 171 | fprintf(stdout,": ");
|
|---|
| 172 | vfprintf(stdout, msg, valist);
|
|---|
| 173 | va_end(valist);
|
|---|
| 174 | }
|
|---|
| 175 | fputc( '\n', stdout );
|
|---|
| 176 | InterlockedIncrement(&todo_failures);
|
|---|
| 177 | return 0;
|
|---|
| 178 | }
|
|---|
| 179 | else InterlockedIncrement(&todo_successes);
|
|---|
| 180 | }
|
|---|
| 181 | else
|
|---|
| 182 | {
|
|---|
| 183 | if (!condition)
|
|---|
| 184 | {
|
|---|
| 185 | fprintf( stdout, "%s:%d: Test failed",
|
|---|
| 186 | data->current_file, data->current_line );
|
|---|
| 187 | if (msg && msg[0])
|
|---|
| 188 | {
|
|---|
| 189 | va_start(valist, msg);
|
|---|
| 190 | fprintf( stdout,": ");
|
|---|
| 191 | vfprintf(stdout, msg, valist);
|
|---|
| 192 | va_end(valist);
|
|---|
| 193 | }
|
|---|
| 194 | fputc( '\n', stdout );
|
|---|
| 195 | InterlockedIncrement(&failures);
|
|---|
| 196 | return 0;
|
|---|
| 197 | }
|
|---|
| 198 | else
|
|---|
| 199 | {
|
|---|
| 200 | if (report_success)
|
|---|
| 201 | fprintf( stdout, "%s:%d: Test succeeded\n",
|
|---|
| 202 | data->current_file, data->current_line);
|
|---|
| 203 | InterlockedIncrement(&successes);
|
|---|
| 204 | }
|
|---|
| 205 | }
|
|---|
| 206 | return 1;
|
|---|
| 207 | }
|
|---|
| 208 |
|
|---|
| 209 | void winetest_trace( const char *msg, ... )
|
|---|
| 210 | {
|
|---|
| 211 | va_list valist;
|
|---|
| 212 | tls_data* data=get_tls_data();
|
|---|
| 213 |
|
|---|
| 214 | if (winetest_debug > 0)
|
|---|
| 215 | {
|
|---|
| 216 | fprintf( stdout, "%s:%d:", data->current_file, data->current_line );
|
|---|
| 217 | va_start(valist, msg);
|
|---|
| 218 | vfprintf(stdout, msg, valist);
|
|---|
| 219 | va_end(valist);
|
|---|
| 220 | }
|
|---|
| 221 | }
|
|---|
| 222 |
|
|---|
| 223 | void winetest_start_todo( const char* platform )
|
|---|
| 224 | {
|
|---|
| 225 | tls_data* data=get_tls_data();
|
|---|
| 226 | if (strcmp(winetest_platform,platform)==0)
|
|---|
| 227 | data->todo_level++;
|
|---|
| 228 | data->todo_do_loop=1;
|
|---|
| 229 | }
|
|---|
| 230 |
|
|---|
| 231 | int winetest_loop_todo(void)
|
|---|
| 232 | {
|
|---|
| 233 | tls_data* data=get_tls_data();
|
|---|
| 234 | int do_loop=data->todo_do_loop;
|
|---|
| 235 | data->todo_do_loop=0;
|
|---|
| 236 | return do_loop;
|
|---|
| 237 | }
|
|---|
| 238 |
|
|---|
| 239 | void winetest_end_todo( const char* platform )
|
|---|
| 240 | {
|
|---|
| 241 | if (strcmp(winetest_platform,platform)==0)
|
|---|
| 242 | {
|
|---|
| 243 | tls_data* data=get_tls_data();
|
|---|
| 244 | data->todo_level--;
|
|---|
| 245 | }
|
|---|
| 246 | }
|
|---|
| 247 |
|
|---|
| 248 | int winetest_get_mainargs( char*** pargv )
|
|---|
| 249 | {
|
|---|
| 250 | *pargv = winetest_argv;
|
|---|
| 251 | return winetest_argc;
|
|---|
| 252 | }
|
|---|
| 253 |
|
|---|
| 254 | /* Find a test by name */
|
|---|
| 255 | static const struct test *find_test( const char *name )
|
|---|
| 256 | {
|
|---|
| 257 | const struct test *test;
|
|---|
| 258 | const char *p;
|
|---|
| 259 | int len;
|
|---|
| 260 |
|
|---|
| 261 | if ((p = strrchr( name, '/' ))) name = p + 1;
|
|---|
| 262 | if ((p = strrchr( name, '\\' ))) name = p + 1;
|
|---|
| 263 | len = strlen(name);
|
|---|
| 264 | if (len > 2 && !strcmp( name + len - 2, ".c" )) len -= 2;
|
|---|
| 265 |
|
|---|
| 266 | for (test = winetest_testlist; test->name; test++)
|
|---|
| 267 | {
|
|---|
| 268 | if (!strncmp( test->name, name, len ) && !test->name[len]) break;
|
|---|
| 269 | }
|
|---|
| 270 | return test->name ? test : NULL;
|
|---|
| 271 | }
|
|---|
| 272 |
|
|---|
| 273 |
|
|---|
| 274 | /* Run a named test, and return exit status */
|
|---|
| 275 | static int run_test( const char *name )
|
|---|
| 276 | {
|
|---|
| 277 | const struct test *test;
|
|---|
| 278 | int status;
|
|---|
| 279 |
|
|---|
| 280 | if (!(test = find_test( name )))
|
|---|
| 281 | {
|
|---|
| 282 | fprintf( stdout, "Fatal: test '%s' does not exist.\n", name );
|
|---|
| 283 | exit_process(1);
|
|---|
| 284 | }
|
|---|
| 285 | successes = failures = todo_successes = todo_failures = 0;
|
|---|
| 286 | tls_index=TlsAlloc();
|
|---|
| 287 | current_test = test;
|
|---|
| 288 | test->func();
|
|---|
| 289 |
|
|---|
| 290 | if (winetest_debug)
|
|---|
| 291 | {
|
|---|
| 292 | fprintf( stdout, "%s: %ld tests executed, %ld marked as todo, %ld %s.\n",
|
|---|
| 293 | name, successes + failures + todo_successes + todo_failures,
|
|---|
| 294 | todo_successes, failures + todo_failures,
|
|---|
| 295 | (failures + todo_failures != 1) ? "failures" : "failure" );
|
|---|
| 296 | }
|
|---|
| 297 | status = (failures + todo_failures < 255) ? failures + todo_failures : 255;
|
|---|
| 298 | return status;
|
|---|
| 299 | }
|
|---|
| 300 |
|
|---|
| 301 |
|
|---|
| 302 | /* Display usage and exit */
|
|---|
| 303 | static void usage( const char *argv0 )
|
|---|
| 304 | {
|
|---|
| 305 | const struct test *test;
|
|---|
| 306 |
|
|---|
| 307 | fprintf( stdout, "Usage: %s test_name\n", argv0 );
|
|---|
| 308 | fprintf( stdout, "\nValid test names:\n" );
|
|---|
| 309 | for (test = winetest_testlist; test->name; test++) fprintf( stdout, " %s\n", test->name );
|
|---|
| 310 | exit_process(1);
|
|---|
| 311 | }
|
|---|
| 312 |
|
|---|
| 313 |
|
|---|
| 314 | /* main function */
|
|---|
| 315 | int main( int argc, char **argv )
|
|---|
| 316 | {
|
|---|
| 317 | char *p;
|
|---|
| 318 |
|
|---|
| 319 | winetest_argc = argc;
|
|---|
| 320 | winetest_argv = argv;
|
|---|
| 321 |
|
|---|
| 322 | if ((p = getenv( "WINETEST_PLATFORM" ))) winetest_platform = p;
|
|---|
| 323 | if ((p = getenv( "WINETEST_DEBUG" ))) winetest_debug = atoi(p);
|
|---|
| 324 | if ((p = getenv( "WINETEST_INTERACTIVE" ))) winetest_interactive = atoi(p);
|
|---|
| 325 | if ((p = getenv( "WINETEST_REPORT_SUCCESS"))) report_success = atoi(p);
|
|---|
| 326 | if (!argv[1]) usage( argv[0] );
|
|---|
| 327 |
|
|---|
| 328 | return run_test(argv[1]);
|
|---|
| 329 | }
|
|---|
| 330 |
|
|---|
| 331 | #endif /* WINETEST_WANT_MAIN */
|
|---|
| 332 |
|
|---|
| 333 | #endif /* __WINE_TEST_H */
|
|---|