[2/2] include: Introduce a with_context macro and use it to simplify vcomp tests. [RFC]

Sebastian Lackner sebastian at fds-team.de
Tue Mar 7 11:29:50 CST 2017


Based on ideas by Mark Jansen.

Signed-off-by: Sebastian Lackner <sebastian at fds-team.de>
---

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 <stdio.h>
+#include <string.h>
 #include <excpt.h>
 
 #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



More information about the wine-patches mailing list