From: Sebastian Lackner Subject: [2/2] include: Introduce a with_context macro and use it to simplify vcomp tests. [RFC] Message-Id: Date: Tue, 7 Mar 2017 18:29:50 +0100 Based on ideas by Mark Jansen. Signed-off-by: Sebastian Lackner --- The with_context macro allows to specify a format string which is printed in case of test failures and for trace messages. Currently, to track down the origin of a test failure, it is necessary to write down all relevant variables in each ok message. With the new macro it is much easier: with_context("a = %d, b = %d, c = %d", a, b, c) { ok(cond1, "cond1 failed\n"); ok(cond2, "cond2 failed\n"); ok(cond3, "cond3 failed\n"); } It can also be combined with a loop like: for (i = 0; i < 100; i++) with_context("i = %d", i) { ... } Other remarks: * To all submaintainers, please let me know if you would be fine to use such a macro in your test. It should only be merged if we can agree on a concept which is fine for everyone. Also feel free to suggest a different name or syntax if you would like to see a different mechanism for this. * The macro uses __VA_ARGS__ which is already used in a couple of other tests. If there is any reason why we shouldn't depend on it, please let me know. * The macro can also be nested (strings will be separated by ":" then). Currently it is not allowed to use ":" inside of a context string yet, but it could be implemented later if needed. * It is fine to use 'continue;' inside of the block, but it is not allowed to use 'break;' (the context would not be cleared). Also, you have to be careful when the block can be left using exception handling or gotos. * I am NOT planning to refactor all of the Wine tests. For existing tests, it should only be used when it significantly improves readability (for example, tracing 3 or more variables in each call). This rule is to ensure Alexandre and Michael Stefaniuc don't freak out. ;) dlls/vcomp/tests/vcomp.c | 60 +++++++++++------------------- include/wine/test.h | 91 +++++++++++++++++++++++++++++++++-------------- 2 files changed, 87 insertions(+), 64 deletions(-) diff --git a/dlls/vcomp/tests/vcomp.c b/dlls/vcomp/tests/vcomp.c index 96a3d9c20a8..5aea6856ea3 100644 --- a/dlls/vcomp/tests/vcomp.c +++ b/dlls/vcomp/tests/vcomp.c @@ -765,6 +765,7 @@ static void CDECL for_static_simple_cb(void) int i; for (i = 0; i < sizeof(tests)/sizeof(tests[0]); i++) + with_context("test %d, thread %d/%d", i, thread_num, num_threads) { unsigned int my_begin, my_end, begin, end; @@ -772,10 +773,8 @@ static void CDECL for_static_simple_cb(void) my_for_static_simple_init(FALSE, tests[i].first, tests[i].last, tests[i].step, FALSE, &my_begin, &my_end); p_vcomp_for_static_simple_init(tests[i].first, tests[i].last, tests[i].step, FALSE, &begin, &end); - ok(begin == my_begin, "test %d, thread %d/%d: expected begin == %u, got %u\n", - i, thread_num, num_threads, my_begin, begin); - ok(end == my_end, "test %d, thread %d/%d: expected end == %u, got %u\n", - i, thread_num, num_threads, my_end, end); + ok(begin == my_begin, "expected begin == %u, got %u\n", my_begin, begin); + ok(end == my_end, "expected end == %u, got %u\n", my_end, end); p_vcomp_for_static_end(); p_vcomp_barrier(); @@ -784,10 +783,8 @@ static void CDECL for_static_simple_cb(void) my_for_static_simple_init(FALSE, tests[i].first, tests[i].last, tests[i].step, TRUE, &my_begin, &my_end); p_vcomp_for_static_simple_init(tests[i].first, tests[i].last, tests[i].step, TRUE, &begin, &end); - ok(begin == my_begin, "test %d, thread %d/%d: expected begin == %u, got %u\n", - i, thread_num, num_threads, my_begin, begin); - ok(end == my_end, "test %d, thread %d/%d: expected end == %u, got %u\n", - i, thread_num, num_threads, my_end, end); + ok(begin == my_begin, "expected begin == %u, got %u\n", my_begin, begin); + ok(end == my_end, "expected end == %u, got %u\n", my_end, end); p_vcomp_for_static_end(); p_vcomp_barrier(); @@ -798,10 +795,8 @@ static void CDECL for_static_simple_cb(void) my_for_static_simple_init(FALSE, tests[i].last, tests[i].first, tests[i].step, FALSE, &my_begin, &my_end); p_vcomp_for_static_simple_init(tests[i].last, tests[i].first, tests[i].step, FALSE, &begin, &end); - ok(begin == my_begin, "test %d, thread %d/%d: expected begin == %u, got %u\n", - i, thread_num, num_threads, my_begin, begin); - ok(end == my_end, "test %d, thread %d/%d: expected end == %u, got %u\n", - i, thread_num, num_threads, my_end, end); + ok(begin == my_begin, "expected begin == %u, got %u\n", my_begin, begin); + ok(end == my_end, "expected end == %u, got %u\n", my_end, end); p_vcomp_for_static_end(); p_vcomp_barrier(); @@ -810,10 +805,8 @@ static void CDECL for_static_simple_cb(void) my_for_static_simple_init(FALSE, tests[i].last, tests[i].first, tests[i].step, TRUE, &my_begin, &my_end); p_vcomp_for_static_simple_init(tests[i].last, tests[i].first, tests[i].step, TRUE, &begin, &end); - ok(begin == my_begin, "test %d, thread %d/%d: expected begin == %u, got %u\n", - i, thread_num, num_threads, my_begin, begin); - ok(end == my_end, "test %d, thread %d/%d: expected end == %u, got %u\n", - i, thread_num, num_threads, my_end, end); + ok(begin == my_begin, "expected begin == %u, got %u\n", my_begin, begin); + ok(end == my_end, "expected end == %u, got %u\n", my_end, end); p_vcomp_for_static_end(); p_vcomp_barrier(); @@ -965,6 +958,7 @@ static void CDECL for_static_cb(void) int i; for (i = 0; i < sizeof(tests)/sizeof(tests[0]); i++) + with_context("test %d, thread %d/%d", i, thread_num, num_threads) { int my_begin, my_end, my_next, my_lastchunk; int begin, end, next, lastchunk; @@ -980,21 +974,16 @@ static void CDECL for_static_cb(void) if (broken_flags & VCOMP_FOR_STATIC_BROKEN_LOOP) { - ok(loops == 0 || loops == 1, "test %d, thread %d/%d: expected loops == 0 or 1, got %u\n", - i, thread_num, num_threads, loops); + ok(loops == 0 || loops == 1, "expected loops == 0 or 1, got %u\n", loops); } else { - ok(loops == my_loops, "test %d, thread %d/%d: expected loops == %u, got %u\n", - i, thread_num, num_threads, my_loops, loops); - ok(begin == my_begin, "test %d, thread %d/%d: expected begin == %d, got %d\n", - i, thread_num, num_threads, my_begin, begin); - ok(end == my_end, "test %d, thread %d/%d: expected end == %d, got %d\n", - i, thread_num, num_threads, my_end, end); + ok(loops == my_loops, "expected loops == %u, got %u\n", my_loops, loops); + ok(begin == my_begin, "expected begin == %d, got %d\n", my_begin, begin); + ok(end == my_end, "expected end == %d, got %d\n", my_end, end); ok(next == my_next || broken(broken_flags & VCOMP_FOR_STATIC_BROKEN_NEXT), - "test %d, thread %d/%d: expected next == %d, got %d\n", i, thread_num, num_threads, my_next, next); - ok(lastchunk == my_lastchunk, "test %d, thread %d/%d: expected lastchunk == %d, got %d\n", - i, thread_num, num_threads, my_lastchunk, lastchunk); + "expected next == %d, got %d\n", my_next, next); + ok(lastchunk == my_lastchunk, "expected lastchunk == %d, got %d\n", my_lastchunk, lastchunk); } p_vcomp_for_static_end(); @@ -1011,21 +1000,16 @@ static void CDECL for_static_cb(void) if (broken_flags & VCOMP_FOR_STATIC_BROKEN_LOOP) { - ok(loops == 0 || loops == 1, "test %d, thread %d/%d: expected loops == 0 or 1, got %u\n", - i, thread_num, num_threads, loops); + ok(loops == 0 || loops == 1, "expected loops == 0 or 1, got %u\n", loops); } else { - ok(loops == my_loops, "test %d, thread %d/%d: expected loops == %u, got %u\n", - i, thread_num, num_threads, my_loops, loops); - ok(begin == my_begin, "test %d, thread %d/%d: expected begin == %d, got %d\n", - i, thread_num, num_threads, my_begin, begin); - ok(end == my_end, "test %d, thread %d/%d: expected end == %d, got %d\n", - i, thread_num, num_threads, my_end, end); + ok(loops == my_loops, "expected loops == %u, got %u\n", my_loops, loops); + ok(begin == my_begin, "expected begin == %d, got %d\n", my_begin, begin); + ok(end == my_end, "expected end == %d, got %d\n", my_end, end); ok(next == my_next || broken(broken_flags & VCOMP_FOR_STATIC_BROKEN_NEXT), - "test %d, thread %d/%d: expected next == %d, got %d\n", i, thread_num, num_threads, my_next, next); - ok(lastchunk == my_lastchunk, "test %d, thread %d/%d: expected lastchunk == %d, got %d\n", - i, thread_num, num_threads, my_lastchunk, lastchunk); + "expected next == %d, got %d\n", my_next, next); + ok(lastchunk == my_lastchunk, "expected lastchunk == %d, got %d\n", my_lastchunk, lastchunk); } p_vcomp_for_static_end(); diff --git a/include/wine/test.h b/include/wine/test.h index af602c0fac0..52e017e32ab 100644 --- a/include/wine/test.h +++ b/include/wine/test.h @@ -46,6 +46,20 @@ #define INVALID_SET_FILE_POINTER (~0u) #endif +#if defined(__x86_64__) && defined(__GNUC__) && defined(__WINE_USE_MSVCRT) +#define __winetest_cdecl __cdecl +#define __winetest_va_list __builtin_ms_va_list +#else +#define __winetest_cdecl +#define __winetest_va_list va_list +#endif + +#ifdef __GNUC__ +# define WINETEST_PRINTF_ATTR(fmt,args) __attribute__((format (printf,fmt,args))) +#else +# define WINETEST_PRINTF_ATTR(fmt,args) +#endif + /* debug level */ extern int winetest_debug; @@ -59,6 +73,9 @@ extern void winetest_set_location( const char* file, int line ); extern void winetest_start_todo( int is_todo ); extern int winetest_loop_todo(void); extern void winetest_end_todo(void); +extern void __winetest_cdecl winetest_start_context( const char *msg, ... ) WINETEST_PRINTF_ATTR(1,2); +extern int winetest_loop_context(void); +extern void winetest_end_context(void); extern int winetest_get_mainargs( char*** pargv ); extern LONG winetest_get_failures(void); extern void winetest_add_failures( LONG new_failures ); @@ -86,24 +103,10 @@ static inline int winetest_strcmpW( const WCHAR *str1, const WCHAR *str2 ) #define START_TEST(name) void func_##name(void) #endif -#if defined(__x86_64__) && defined(__GNUC__) && defined(__WINE_USE_MSVCRT) -#define __winetest_cdecl __cdecl -#define __winetest_va_list __builtin_ms_va_list -#else -#define __winetest_cdecl -#define __winetest_va_list va_list -#endif - extern int broken( int condition ); extern int winetest_vok( int condition, const char *msg, __winetest_va_list ap ); extern void winetest_vskip( const char *msg, __winetest_va_list ap ); -#ifdef __GNUC__ -# define WINETEST_PRINTF_ATTR(fmt,args) __attribute__((format (printf,fmt,args))) -#else -# define WINETEST_PRINTF_ATTR(fmt,args) -#endif - extern void __winetest_cdecl winetest_ok( int condition, const char *msg, ... ) WINETEST_PRINTF_ATTR(2,3); extern void __winetest_cdecl winetest_skip( const char *msg, ... ) WINETEST_PRINTF_ATTR(1,2); extern void __winetest_cdecl winetest_win_skip( const char *msg, ... ) WINETEST_PRINTF_ATTR(1,2); @@ -125,6 +128,9 @@ extern void __winetest_cdecl winetest_trace( const char *msg, ... ) WINETEST_PRI #define todo_wine todo_if(!strcmp(winetest_platform, "wine")) #define todo_wine_if(is_todo) todo_if((is_todo) && !strcmp(winetest_platform, "wine")) +#define with_context(...) for (winetest_start_context(__VA_ARGS__); \ + winetest_loop_context(); \ + winetest_end_context()) #ifdef NONAMELESSUNION # define U(x) (x).u @@ -175,6 +181,7 @@ extern void __winetest_cdecl winetest_trace( const char *msg, ... ) WINETEST_PRI #ifdef STANDALONE #include +#include #include #if defined(__x86_64__) && defined(__GNUC__) && defined(__WINE_USE_MSVCRT) @@ -224,7 +231,9 @@ struct tls_data int current_line; /* line of current check */ unsigned int todo_level; /* current todo nesting level */ int todo_do_loop; + int context_do_loop; char *str_pos; /* position in debug buffer */ + char context[2000]; /* buffer for debug context */ char strings[2000]; /* buffer for debug strings */ }; static DWORD tls_index; @@ -307,8 +316,8 @@ int winetest_vok( int condition, const char *msg, __winetest_va_list args ) { if (condition) { - printf( "%s:%d: Test succeeded inside todo block: ", - data->current_file, data->current_line ); + printf( "%s:%d%s: Test succeeded inside todo block: ", + data->current_file, data->current_line, data->context ); vprintf(msg, args); InterlockedIncrement(&todo_failures); return 0; @@ -317,8 +326,8 @@ int winetest_vok( int condition, const char *msg, __winetest_va_list args ) { if (winetest_debug > 0) { - printf( "%s:%d: Test marked todo: ", - data->current_file, data->current_line ); + printf( "%s:%d%s: Test marked todo: ", + data->current_file, data->current_line, data->context ); vprintf(msg, args); } InterlockedIncrement(&todo_successes); @@ -329,8 +338,8 @@ int winetest_vok( int condition, const char *msg, __winetest_va_list args ) { if (!condition) { - printf( "%s:%d: Test failed: ", - data->current_file, data->current_line ); + printf( "%s:%d%s: Test failed: ", + data->current_file, data->current_line, data->context ); vprintf(msg, args); InterlockedIncrement(&failures); return 0; @@ -338,8 +347,8 @@ int winetest_vok( int condition, const char *msg, __winetest_va_list args ) else { if (report_success) - printf( "%s:%d: Test succeeded\n", - data->current_file, data->current_line); + printf( "%s:%d%s: Test succeeded\n", + data->current_file, data->current_line, data->context ); InterlockedIncrement(&successes); return 1; } @@ -362,7 +371,7 @@ void __winetest_cdecl winetest_trace( const char *msg, ... ) if (winetest_debug > 0) { - printf( "%s:%d: ", data->current_file, data->current_line ); + printf( "%s:%d%s: ", data->current_file, data->current_line, data->context ); __winetest_va_start(valist, msg); vprintf(msg, valist); __winetest_va_end(valist); @@ -373,7 +382,7 @@ void winetest_vskip( const char *msg, __winetest_va_list args ) { struct tls_data *data = get_tls_data(); - printf( "%s:%d: Tests skipped: ", data->current_file, data->current_line ); + printf( "%s:%d%s: Tests skipped: ", data->current_file, data->current_line, data->context ); vprintf(msg, args); skipped++; } @@ -418,6 +427,36 @@ void winetest_end_todo(void) data->todo_level >>= 1; } +void __winetest_cdecl winetest_start_context( const char *msg, ... ) +{ + __winetest_va_list valist; + struct tls_data *data = get_tls_data(); + char *buf = data->context + strlen(data->context); + + *buf++ = ':'; + __winetest_va_start(valist, msg); + vsprintf(buf, msg, valist); + __winetest_va_end(valist); + if ((buf = strchr(buf, ':'))) *buf = 0; + + data->context_do_loop = 1; +} + +int winetest_loop_context(void) +{ + struct tls_data *data = get_tls_data(); + int do_loop = data->context_do_loop; + data->context_do_loop = 0; + return do_loop; +} + +void winetest_end_context(void) +{ + struct tls_data *data = get_tls_data(); + char *buf = strrchr(data->context, ':'); + *buf = 0; +} + int winetest_get_mainargs( char*** pargv ) { *pargv = winetest_argv; @@ -616,8 +655,8 @@ static LONG CALLBACK exc_filter( EXCEPTION_POINTERS *ptrs ) struct tls_data *data = get_tls_data(); if (data->current_file) - printf( "%s:%d: this is the last test seen before the exception\n", - data->current_file, data->current_line ); + printf( "%s:%d%s: this is the last test seen before the exception\n", + data->current_file, data->current_line, data->context ); printf( "%04x:%s: unhandled exception %08x at %p\n", GetCurrentProcessId(), current_test->name, ptrs->ExceptionRecord->ExceptionCode, ptrs->ExceptionRecord->ExceptionAddress ); -- 2.11.0