add a new test/fail module, and rewrite test/assert to use it
authorTero Marttila <terom@fixme.fi>
Fri, 08 May 2009 01:43:02 +0300
changeset 194 808b1b047620
parent 193 9f8c6eaf9d50
child 195 42aedce3e2eb
add a new test/fail module, and rewrite test/assert to use it
src/log.c
src/log.h
src/test/assert.c
src/test/assert.h
src/test/fail.c
src/test/fail.h
src/test/test.h
--- a/src/log.c	Fri May 08 01:42:44 2009 +0300
+++ b/src/log.c	Fri May 08 01:43:02 2009 +0300
@@ -72,11 +72,7 @@
     _log_output_ctx.arg = arg;
 }
 
-/**
- * Format the full output line, and pass it to the log_output_func. The line will be of the form:
- *  "[<level>] <func> : <log_fmt> [ <user_fmt> ]"
- */
-static void log_output (enum log_level level, const char *func, const char *user_fmt, va_list user_fmtargs, const char *log_fmt, ...)
+void log_output_tag (enum log_level level, const char *tag, const char *func, const char *user_fmt, va_list user_fmtargs, const char *log_fmt, ...)
 {
     char buf[LOG_MSG_MAX], *buf_ptr = buf;
     size_t buf_size = sizeof(buf);
@@ -86,7 +82,7 @@
         return;
 
     // output the header
-    buf_ptr += str_advance(NULL, &buf_size, str_append_fmt(buf_ptr, buf_size, "[%5s] %20s : ", log_level_name(level), func));
+    buf_ptr += str_advance(NULL, &buf_size, str_append_fmt(buf_ptr, buf_size, "[%5s] %20s : ", tag, func));
     
     // output the user data
     buf_ptr += str_advance(NULL, &buf_size, str_append_fmt_va(buf_ptr, buf_size, user_fmt, user_fmtargs));
@@ -110,7 +106,7 @@
     
     // formatted output: no suffix
     va_start(vargs, format);
-    log_output(level, func, format, vargs, NULL);
+    log_output_tag(level, log_level_name(level), func, format, vargs, NULL);
     va_end(vargs);
 }
 
@@ -120,7 +116,7 @@
 
     // formatted output: suffix error_name()
     va_start(vargs, format);
-    log_output(level, func, format, vargs, ": %s", error_name(err));
+    log_output_tag(level, log_level_name(level), func, format, vargs, ": %s", error_name(err));
     va_end(vargs);
 }
 
@@ -130,7 +126,7 @@
 
     // formatted output: suffix error_msg()
     va_start(vargs, format);
-    log_output(level, func, format, vargs, ": %s", error_msg(err));
+    log_output_tag(level, log_level_name(level), func, format, vargs, ": %s", error_msg(err));
     va_end(vargs);
 }
 
@@ -140,7 +136,7 @@
 
     // formatted output: suffix strerror()
     va_start(vargs, format);
-    log_output(level, func, format, vargs, ": %s", strerror(errno));
+    log_output_tag(level, log_level_name(level), func, format, vargs, ": %s", strerror(errno));
     va_end(vargs);
 }
 
--- a/src/log.h	Fri May 08 01:42:44 2009 +0300
+++ b/src/log.h	Fri May 08 01:43:02 2009 +0300
@@ -6,6 +6,7 @@
  * Local logging functions
  */
 #include "error.h"
+#include <stdarg.h>
 
 /**
  * Log level definitions
@@ -53,6 +54,15 @@
 void log_set_func (log_output_func func, void *arg);
 
 /**
+ * Internal logging func, meant for using custom level tags. This performs the filtering of log levels.
+ *
+ * Format the full output line, and pass it to the log_output_func. The line will be of the form:
+ *  "[<tag>] <func> : <user_fmt> [ <log_fmt> ]"
+ */
+void log_output_tag (enum log_level level, const char *tag, const char *func, const char *user_fmt, va_list user_fmtargs, const char *log_fmt, ...)
+    __attribute__ ((format (printf, 6, 7)));
+
+/**
  * Log a message with the given level
  */
 void log_msg (enum log_level level, const char *func, const char *format, ...)
--- a/src/test/assert.c	Fri May 08 01:42:44 2009 +0300
+++ b/src/test/assert.c	Fri May 08 01:43:02 2009 +0300
@@ -1,70 +1,62 @@
 #include "assert.h"
 #include "util.h"
-#include "backtrace.h"
 
 #include <string.h>
 
-#define ASSERT_FAIL(...) do { log_fatal(__VA_ARGS__); test_backtrace(1); abort(); } while (0)
 
-void assert_true (bool cond, const char *msg)
+#define _ASSERT_FUNC_FAIL(...) test_fail(func, file, line, 1, __VA_ARGS__)
+
+void _assert_null (_ASSERT_FUNC_ARGS, const void *ptr)
 {
-    if (!cond)
-        ASSERT_FAIL("%s", msg);
+    if (ptr)
+        _ASSERT_FUNC_FAIL("%p != NULL", ptr);
 }
 
-void assert_null (const void *ptr)
-{
-    if (ptr)
-        ASSERT_FAIL("%p != NULL", ptr);
-}
-
-void assert_strcmp (const char *is, const char *should_be)
+void _assert_strcmp (_ASSERT_FUNC_ARGS, const char *is, const char *should_be)
 {
     if (!should_be && !is)
         return;
-
+    
     if (!is || strcmp(is, should_be))
-        ASSERT_FAIL("%s != %s", dump_str(is), dump_str(should_be));
-}
-
-void assert_strncmp (const char *is, const char *should_be, size_t n)
-{   
-    if (!should_be && !is)
-        return;
-
-    if (!is || strncmp(is, should_be, n))
-        ASSERT_FAIL("%s:%u != %s", dump_strn(is, n), (unsigned) n, dump_strn(should_be, n));
-}
-
-void assert_strlen (const char *str, size_t n)
-{
-    if (!str || strlen(str) != n)
-        ASSERT_FAIL("strlen(%s) != %u", dump_str(str), (unsigned) n);
+        _ASSERT_FUNC_FAIL("%s != %s", dump_str(is), dump_str(should_be));
 }
 
-void assert_strnull (const char *str)
+void _assert_strncmp (_ASSERT_FUNC_ARGS, const char *is, const char *should_be, size_t n)
 {
-    if (str != NULL)
-        ASSERT_FAIL("%s != NULL", dump_str(str));
-}
-
-void assert_success (err_t err)
-{
-    if (err != SUCCESS)
-        ASSERT_FAIL("error: %s", error_name(err));
+    if (!should_be && !is)
+        return;
+    
+    if (!is || strncmp(is, should_be, n))
+        _ASSERT_FUNC_FAIL("%s:%u != %s", dump_strn(is, n), (unsigned) n, dump_strn(should_be, n));
 }
 
-void assert_err (err_t err, err_t target)
+void _assert_strlen (_ASSERT_FUNC_ARGS, const char *str, size_t n)
 {
-    if (err != target)
-        ASSERT_FAIL("error: <%s> != <%s>", error_name(err), error_name(target));
+    if (!str || strlen(str) != n)
+        _ASSERT_FUNC_FAIL("strlen(%s) != %u", dump_str(str), (unsigned) n);
 }
 
-void assert_error (error_t *is, error_t *should_be)
+void _assert_strnull (_ASSERT_FUNC_ARGS, const char *str)
+{
+    if (str)
+        _ASSERT_FUNC_FAIL("%s != NULL", dump_str(str));
+}
+
+void _assert_success (_ASSERT_FUNC_ARGS, err_t err)
+{
+    if (err)
+        _ASSERT_FUNC_FAIL("err: %s", dump_str(error_name(err)));
+}
+
+void _assert_err (_ASSERT_FUNC_ARGS, err_t is, err_t should_be)
+{
+    if (is != should_be)
+        _ASSERT_FUNC_FAIL("err: %s != %s", dump_str(error_name(is)), dump_str(error_name(should_be)));
+}
+
+void _assert_error (_ASSERT_FUNC_ARGS, error_t *is, error_t *should_be)
 {
     if (ERROR_CODE(is) != ERROR_CODE(should_be) || ERROR_EXTRA(is) != ERROR_EXTRA(should_be))
-        // XXX: dual use of error_msg
-        ASSERT_FAIL("error: <%s> != <%s>", error_msg(is), error_msg(should_be));
+        _ASSERT_FUNC_FAIL("error: %s != %s", dump_str(error_msg(is)), dump_str(error_msg(should_be)));
+
 }
-
-
--- a/src/test/assert.h	Fri May 08 01:42:44 2009 +0300
+++ b/src/test/assert.h	Fri May 08 01:43:02 2009 +0300
@@ -6,58 +6,76 @@
  *
  * Various general assert-condition tests used to fail tests
  */
+#include "fail.h"
 #include "../error.h"
-#include "../log.h"
 
 /*
  * Also accept the existance of the system assert() function
  */
 #include <assert.h>
-#include <stdbool.h>
+
+/*
+ * Internal shorthand macros for passing func/file/line args
+ */
+#define _ASSERT_FUNC_ARGS const char *func, const char *file, int line
+#define _ASSERT_FUNC_CALL(func, ...) func(__func__, __FILE__, __LINE__, __VA_ARGS__)
 
 /**
  * Assert that the given condition is true, and fail with the given error if not
  */
-void assert_true (bool cond, const char *msg);
+#define assert_true(cond, ...) fail_if(cond, __VA_ARGS__)
+
+/**
+ * Assert failure unconditionally
+ */
+#define assert_fail(...) fail(__VA_ARGS__)
 
 /**
  * Assert that the given pointer value is NULL.
  */
-void assert_null (const void *ptr);
+#define assert_null(ptr) _ASSERT_FUNC_CALL(_assert_null, ptr)
+void _assert_null (_ASSERT_FUNC_ARGS, const void *ptr);
 
 /**
  * Assert that the given NUL-terminated string matches the given target string exactly.
  */
-void assert_strcmp (const char *is, const char *should_be);
+#define assert_strcmp(is, should_be) _ASSERT_FUNC_CALL(_assert_strcmp, is, should_be)
+void _assert_strcmp (_ASSERT_FUNC_ARGS, const char *is, const char *should_be);
 
 /**
  * Assert that the first \a n chars of the first string matches the second string exactly.
  */
-void assert_strncmp (const char *is, const char *should_be, size_t n);
+#define assert_strncmp(is, should_be, n) _ASSERT_FUNC_CALL(_assert_strncmp, is, should_be, n)
+void _assert_strncmp (_ASSERT_FUNC_ARGS, const char *is, const char *should_be, size_t n);
 
 /**
  * Assert that the given \a str is \a n chars long.
  */
-void assert_strlen (const char *str, size_t n);
+#define assert_strlen(str, n) _ASSERT_FUNC_CALL(_assert_strlen, str, n)
+void _assert_strlen (_ASSERT_FUNC_ARGS, const char *str, size_t n);
 
 /**
  * Assert that the given \a str is NULL.
  */
-void assert_strnull (const char *str);
+#define assert_strnull(str) _ASSERT_FUNC_CALL(_assert_strnull, str)
+void _assert_strnull (_ASSERT_FUNC_ARGS, const char *str);
 
 /**
  * Assert that the given error code is SUCCESS.
  */
-void assert_success (err_t err);
+#define assert_success(err) _ASSERT_FUNC_CALL(_assert_success, err)
+void _assert_success (_ASSERT_FUNC_ARGS, err_t err);
 
 /**
- * Assert that the given actual error code \a err matches the expected error code \target.
+ * Assert that the given actual error code \a err matches the expected error code \a should_be.
  */
-void assert_err (err_t err, err_t target);
+#define assert_err(is, should_be) _ASSERT_FUNC_CALL(_assert_err, is, should_be)
+void _assert_err (_ASSERT_FUNC_ARGS, err_t is, err_t should_be);
 
 /**
  * Assert that the given actual error \a is matches the expected error \a should_be
  */ 
-void assert_error (error_t *is, error_t *should_be);
+#define assert_error(is, should_be) _ASSERT_FUNC_CALL(_assert_error, is, should_be)
+void _assert_error (_ASSERT_FUNC_ARGS, error_t *is, error_t *should_be);
 
 #endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/test/fail.c	Fri May 08 01:43:02 2009 +0300
@@ -0,0 +1,30 @@
+#include "fail.h"
+#include "../str.h"
+#include "../log.h"
+#include "backtrace.h"
+
+#include <stdarg.h>
+
+void test_fail_va (const char *func, const char *file, int line, int skip, const char *fmt, va_list vargs)
+{
+    // log it
+    log_output_tag(LOG_ERROR, "FAIL", func, fmt, vargs, " @@ %s@%s:%d - backtrace follows:", func, file, line);
+
+    // print out a stack dump, not including this function or the backtrace func
+    test_backtrace(skip + 2);
+
+    // then exit with a failure code
+    abort();
+}
+
+void test_fail (const char *func, const char *file, int line, int skip, const char *fmt, ...)
+{   
+    va_list vargs; 
+    
+    va_start(vargs, fmt);
+
+    test_fail_va(func, file, line, skip, fmt, vargs);
+
+    va_end(vargs);
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/test/fail.h	Fri May 08 01:43:02 2009 +0300
@@ -0,0 +1,50 @@
+#ifndef TEST_FAIL_H
+#define TEST_FAIL_H
+
+/**
+ * @file
+ *
+ * Various ways to mark the current test as failed.
+ */
+#include "../error.h"
+#include <stdarg.h>
+
+#define NORETURN __attribute((noreturn))
+
+/**
+ * Output a message representing the given failure using log_output.
+ *
+ * Also dumps out a stacktrace for the calling function using log_debug, skipping this func, the backtrace func, and
+ * the given number of frames.
+ */
+void test_fail_va (const char *func, const char *file, int line, int skip, const char *fmt, va_list vargs) NORETURN;
+
+/**
+ * Output given fail using test_fail_va().
+ */
+void test_fail (const char *func, const char *file, int line, int skip, const char *fmt, ...) NORETURN;
+
+/**
+ * Fail with a simply error message
+ */
+#define fail(...) test_fail(__func__, __FILE__, __LINE__, 0, __VA_ARGS__)
+
+/**
+ * Fail conditionally
+ */
+#define fail_if(cond, ...) do { \
+        if (cond)   \
+            fail(__VA_ARGS__);   \
+    } while (0)
+
+/**
+ * Fail with an error code
+ */
+#define fail_err(err, fmt, ...) fail(fmt ": %s", __VA_ARGS__, ## error_name(err))
+
+/**
+ * Fail with an error info
+ */
+#define fail_error(error, fmt, ...) fail(fmt ": %s", __VA_ARGS__, ## error_msg(error))
+
+#endif /* TEST_FAIL_H */
--- a/src/test/test.h	Fri May 08 01:42:44 2009 +0300
+++ b/src/test/test.h	Fri May 08 01:43:02 2009 +0300
@@ -9,8 +9,11 @@
 #include "assert.h"
 #include "util.h"
 
+#include "../log.h"
+
 #include <event2/event.h>
 #include <string.h>
+#include <stdbool.h>
 
 /**
  * Global test-running state