]> git.saurik.com Git - apple/objc4.git/blobdiff - test/test.h
objc4-437.tar.gz
[apple/objc4.git] / test / test.h
diff --git a/test/test.h b/test/test.h
new file mode 100644 (file)
index 0000000..a9fa266
--- /dev/null
@@ -0,0 +1,104 @@
+// test.h
+// Common definitions for trivial test harness
+
+
+#ifndef TEST_H
+#define TEST_H
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <libgen.h>
+#include <unistd.h>
+#include <malloc/malloc.h>
+#include <mach/mach_time.h>
+#include <objc/objc-auto.h>
+
+static inline void succeed(const char *msg, ...)  __attribute__((noreturn));
+static inline void succeed(const char *msg, ...)
+{
+    va_list v;
+    if (msg) {
+        fprintf(stderr, "OK: ");
+        va_start(v, msg);
+        vfprintf(stderr, msg, v);
+        va_end(v);
+        fprintf(stderr, "\n");
+    } else {
+        fprintf(stderr, "OK\n");
+    }
+    exit(0);
+}
+
+static inline int fail(const char *msg, ...)   __attribute__((noreturn));
+static inline int fail(const char *msg, ...)
+{
+    va_list v;
+    if (msg) {
+        fprintf(stderr, "BAD: ");
+        va_start(v, msg);
+        vfprintf(stderr, msg, v);
+        va_end(v);
+        fprintf(stderr, "\n");
+    } else {
+        fprintf(stderr, "BAD\n");
+    }
+    exit(1);
+}
+
+#define testassert(cond) \
+    ((void) ((cond) ? 0 : __testassert(#cond, __FILE__, __LINE__)))
+#define __testassert(cond, file, line) \
+    fail("failed assertion '%s' at %s:%u", cond, __FILE__, __LINE__)
+
+/* time-sensitive assertion, disabled under valgrind */
+#define timeassert(cond) \
+    testassert((getenv("VALGRIND") && 0 != strcmp(getenv("VALGRIND"), "NO")) || (cond))
+
+static inline void testprintf(const char *msg, ...)
+{
+    va_list v;
+    va_start(v, msg);
+    if (getenv("VERBOSE")) vfprintf(stderr, msg, v);
+    va_end(v);
+}
+
+
+/* Leak checking
+   Fails if total malloc memory in use at leak_check(n) 
+   is more than n bytes above that at leak_mark().
+*/
+
+static size_t _leak_start;
+static inline void leak_mark(void)
+{
+    malloc_statistics_t stats;
+    if (objc_collecting_enabled()) {
+        objc_startCollectorThread();
+        objc_collect(OBJC_EXHAUSTIVE_COLLECTION|OBJC_WAIT_UNTIL_DONE);
+    }
+    malloc_zone_statistics(NULL, &stats);
+    _leak_start = stats.size_in_use;
+}
+
+#define leak_check(n)                                                   \
+    do {                                                                \
+        const char *_check = getenv("LEAK_CHECK");                      \
+        if (_check && 0 == strcmp(_check, "NO")) break;                 \
+        if (objc_collecting_enabled()) {                                \
+            objc_collect(OBJC_EXHAUSTIVE_COLLECTION|OBJC_WAIT_UNTIL_DONE); \
+        }                                                               \
+        malloc_statistics_t stats;                                      \
+        malloc_zone_statistics(NULL, &stats);                           \
+        if (stats.size_in_use > _leak_start + n) {                      \
+            if (getenv("HANG_ON_LEAK")) {                               \
+                printf("leaks %d\n", getpid());                         \
+                while (1) sleep(1);                                     \
+            }                                                           \
+            fail("%zu bytes leaked at %s:%u",                           \
+                 stats.size_in_use - _leak_start, __FILE__, __LINE__);  \
+        }                                                               \
+    } while (0)
+
+#endif