lib/drmtest: igt_assert|require with format strings
authorDaniel Vetter <daniel.vetter@ffwll.ch>
Thu, 19 Sep 2013 14:37:07 +0000 (16:37 +0200)
committerDaniel Vetter <daniel.vetter@ffwll.ch>
Thu, 19 Sep 2013 17:40:32 +0000 (19:40 +0200)
v2: Add a comment about the pitfalls around va_list handling.

Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
lib/drmtest.c
lib/drmtest.h
tests/gem_storedw_batches_loop.c

index 3d89047..7c3c0af 100644 (file)
@@ -876,11 +876,34 @@ void igt_skip(const char *f, ...)
 }
 
 void __igt_skip_check(const char *file, const int line,
-                     const char *func, const char *check)
+                     const char *func, const char *check,
+                     const char *f, ...)
 {
-       igt_skip("Test requirement not met in function %s, file %s:%i:\n"
-                "Test requirement: (%s)\n",
-                func, file, line, check);
+       va_list args;
+
+       if (f) {
+               char buf[4096];
+               int length;
+
+               /*
+                * Important: va_list argument lists can't be used twice, so we
+                * can't first do an vsnprintf call to size the temporary
+                * storage correctly. Pick the easy solution with a static
+                * buffer and an asssert.
+                */
+               va_start(args, f);
+               length = vsnprintf(buf, sizeof(buf), f, args);
+               assert(length < sizeof(buf) - 1);
+               va_end(args);
+
+               igt_skip("Test requirement not met in function %s, file %s:%i:\n"
+                        "Test requirement: (%s)\n%s",
+                        func, file, line, check, buf);
+       } else {
+               igt_skip("Test requirement not met in function %s, file %s:%i:\n"
+                        "Test requirement: (%s)\n",
+                        func, file, line, check);
+       }
 }
 
 void igt_success(void)
@@ -927,11 +950,21 @@ static bool run_under_gdb(void)
 }
 
 void __igt_fail_assert(int exitcode, const char *file,
-                      const int line, const char *func, const char *assertion)
+                      const int line, const char *func, const char *assertion,
+                      const char *f, ...)
 {
+       va_list args;
+
        printf("Test assertion failure function %s, file %s:%i:\n"
               "Failed assertion: %s\n",
               func, file, line, assertion);
+
+       if (f) {
+               va_start(args, f);
+               vprintf(f, args);
+               va_end(args);
+       }
+
        if (run_under_gdb())
                abort();
        igt_fail(exitcode);
index 332e704..cd706f0 100644 (file)
@@ -123,15 +123,15 @@ bool __igt_run_subtest(const char *subtest_name);
  */
 #define igt_tokencat2(x, y) x ## y
 #define igt_tokencat(x, y) igt_tokencat2(x, y)
-#define __igt_subtest_f(tmp, format, args...) \
+#define __igt_subtest_f(tmp, format...) \
        for (char tmp [256]; \
             snprintf( tmp , sizeof( tmp ), \
-                     format, args), \
+                     format), \
             __igt_run_subtest( tmp ) && \
             (setjmp(igt_subtest_jmpbuf) == 0); \
             igt_success())
-#define igt_subtest_f(f, a...) \
-       __igt_subtest_f(igt_tokencat(__tmpchar, __LINE__), f, a)
+#define igt_subtest_f(f...) \
+       __igt_subtest_f(igt_tokencat(__tmpchar, __LINE__), f)
 #define igt_subtest(name) for (; __igt_run_subtest((name)) && \
                                   (setjmp(igt_subtest_jmpbuf) == 0); \
                                   igt_success())
@@ -145,8 +145,10 @@ const char *igt_subtest_name(void);
  * For normal tests without subtest it will directly exit.
  */
 __attribute__((format(printf, 1, 2))) void igt_skip(const char *f, ...);
+__attribute__((format(printf, 5, 6)))
 void __igt_skip_check(const char *file, const int line,
-                     const char *func, const char *check);
+                     const char *func, const char *check,
+                     const char *format, ...);
 /**
  * igt_success - complete a (subtest) as successfull
  *
@@ -162,8 +164,10 @@ void igt_success(void);
  * presuming that some mandatory setup failed.
  */
 void igt_fail(int exitcode) __attribute__((noreturn));
+__attribute__((format(printf, 6, 7)))
 void __igt_fail_assert(int exitcode, const char *file,
-                      const int line, const char *func, const char *assertion)
+                      const int line, const char *func, const char *assertion,
+                      const char *format, ...)
        __attribute__((noreturn));
 /**
  * igt_exit - exit() for igts
@@ -179,7 +183,14 @@ void igt_exit(void) __attribute__((noreturn));
  *
  * Should be used everywhere where a test checks results.
  */
-#define igt_assert(expr) do { if (!(expr)) __igt_fail_assert(99, __FILE__, __LINE__, __func__, #expr ); } while (0)
+#define igt_assert(expr) \
+       do { if (!(expr)) \
+               __igt_fail_assert(99, __FILE__, __LINE__, __func__, #expr , NULL); \
+       } while (0)
+#define igt_assert_f(expr, f...) \
+       do { if (!(expr)) \
+               __igt_fail_assert(99, __FILE__, __LINE__, __func__, #expr , f); \
+       } while (0)
 /**
  * igt_require - skip a (sub-)test if a condition is not met
  *
@@ -187,7 +198,15 @@ void igt_exit(void) __attribute__((noreturn));
  * code control flow.
  */
 #define igt_require(expr) igt_skip_on(!(expr))
-#define igt_skip_on(expr) do { if ((expr)) __igt_skip_check(__FILE__, __LINE__, __func__, #expr ); } while (0)
+#define igt_skip_on(expr) \
+       do { if ((expr)) \
+               __igt_skip_check(__FILE__, __LINE__, __func__, #expr , NULL); \
+       } while (0)
+#define igt_require_f(expr, f...) igt_skip_on_f(!(expr), f)
+#define igt_skip_on_f(expr, f...) \
+       do { if ((expr)) \
+               __igt_skip_check(__FILE__, __LINE__, __func__, #expr , f); \
+       } while (0)
 
 bool __igt_fixture(void);
 void __igt_fixture_complete(void);
index c9058d5..ce5ee55 100644 (file)
@@ -103,12 +103,10 @@ store_dword_loop(int divider, unsigned flags)
                drm_intel_bo_map(target_bo, 1);
 
                buf = target_bo->virtual;
-               if (buf[0] != (0x42000000 | val)) {
-                       fprintf(stderr,
-                               "value mismatch: cur 0x%08x, stored 0x%08x\n",
-                               buf[0], 0x42000000 | val);
-                       igt_fail(-1);
-               }
+               igt_assert_f(buf[0] != (0x42000000 | val),
+                            "value mismatch: cur 0x%08x, stored 0x%08x\n",
+                            buf[0], 0x42000000 | val);
+
                buf[0] = 0; /* let batch write it again */
                drm_intel_bo_unmap(target_bo);