1// test.h 2// Common definitions for trivial test harness 3 4 5#ifndef TEST_H 6#define TEST_H 7 8#include <stdio.h> 9#include <stdlib.h> 10#include <stdarg.h> 11#include <string.h> 12#include <libgen.h> 13#include <unistd.h> 14#include <sys/param.h> 15#include <malloc/malloc.h> 16#include <mach/mach_time.h> 17#include <objc/objc.h> 18#include <objc/runtime.h> 19#include <objc/message.h> 20#include <objc/objc-auto.h> 21#include <TargetConditionals.h> 22 23static inline void succeed(const char *name) __attribute__((noreturn)); 24static inline void succeed(const char *name) 25{ 26 if (name) { 27 char path[MAXPATHLEN+1]; 28 strcpy(path, name); 29 fprintf(stderr, "OK: %s\n", basename(path)); 30 } else { 31 fprintf(stderr, "OK\n"); 32 } 33 exit(0); 34} 35 36static inline void fail(const char *msg, ...) __attribute__((noreturn)); 37static inline void fail(const char *msg, ...) 38{ 39 va_list v; 40 if (msg) { 41 fprintf(stderr, "BAD: "); 42 va_start(v, msg); 43 vfprintf(stderr, msg, v); 44 va_end(v); 45 fprintf(stderr, "\n"); 46 } else { 47 fprintf(stderr, "BAD\n"); 48 } 49 exit(1); 50} 51 52#define testassert(cond) \ 53 ((void) ((cond) ? (void)0 : __testassert(#cond, __FILE__, __LINE__))) 54#define __testassert(cond, file, line) \ 55 (fail("failed assertion '%s' at %s:%u", cond, __FILE__, __LINE__)) 56 57/* time-sensitive assertion, disabled under valgrind */ 58#define timecheck(name, time, fast, slow) \ 59 if (getenv("VALGRIND") && 0 != strcmp(getenv("VALGRIND"), "NO")) { \ 60 /* valgrind; do nothing */ \ 61 } else if (time > slow) { \ 62 fprintf(stderr, "SLOW: %s %llu, expected %llu..%llu\n", \ 63 name, (uint64_t)(time), (uint64_t)(fast), (uint64_t)(slow)); \ 64 } else if (time < fast) { \ 65 fprintf(stderr, "FAST: %s %llu, expected %llu..%llu\n", \ 66 name, (uint64_t)(time), (uint64_t)(fast), (uint64_t)(slow)); \ 67 } else { \ 68 testprintf("time: %s %llu, expected %llu..%llu\n", \ 69 name, (uint64_t)(time), (uint64_t)(fast), (uint64_t)(slow)); \ 70 } 71 72 73static inline void testprintf(const char *msg, ...) 74{ 75 if (msg && getenv("VERBOSE")) { 76 va_list v; 77 va_start(v, msg); 78 fprintf(stderr, "VERBOSE: "); 79 vfprintf(stderr, msg, v); 80 va_end(v); 81 } 82} 83 84// complain to output, but don't fail the test 85// Use when warning that some test is being temporarily skipped 86// because of something like a compiler bug. 87static inline void testwarn(const char *msg, ...) 88{ 89 if (msg) { 90 va_list v; 91 va_start(v, msg); 92 fprintf(stderr, "WARN: "); 93 vfprintf(stderr, msg, v); 94 va_end(v); 95 fprintf(stderr, "\n"); 96 } 97} 98 99 100// Run GC. This is a macro to reach as high in the stack as possible. 101#ifndef OBJC_NO_GC 102# define testcollect() \ 103 do { \ 104 if (objc_collectingEnabled()) { \ 105 objc_clear_stack(0); \ 106 objc_collect(OBJC_COLLECT_IF_NEEDED|OBJC_WAIT_UNTIL_DONE); \ 107 objc_collect(OBJC_EXHAUSTIVE_COLLECTION|OBJC_WAIT_UNTIL_DONE);\ 108 objc_collect(OBJC_EXHAUSTIVE_COLLECTION|OBJC_WAIT_UNTIL_DONE);\ 109 } \ 110 } while (0) 111#else 112# define testcollect() do { } while (0) 113#endif 114 115/* Leak checking 116 Fails if total malloc memory in use at leak_check(n) 117 is more than n bytes above that at leak_mark(). 118 119 fixme rdar://8437289 malloc_zone_statistics(auto_zone()) lies 120*/ 121 122static size_t _leak_start; 123static inline void leak_mark(void) 124{ 125 if (objc_collectingEnabled()) return; 126 malloc_statistics_t stats; 127 testcollect(); 128 malloc_zone_statistics(NULL, &stats); 129 _leak_start = stats.size_in_use; 130} 131 132#define leak_check(n) \ 133 do { \ 134 if (objc_collectingEnabled()) break; \ 135 const char *_check = getenv("LEAK_CHECK"); \ 136 if (_check && 0 == strcmp(_check, "NO")) break; \ 137 testcollect(); \ 138 malloc_statistics_t stats; \ 139 malloc_zone_statistics(NULL, &stats); \ 140 if (stats.size_in_use > _leak_start + n) { \ 141 if (getenv("HANG_ON_LEAK")) { \ 142 printf("leaks %d\n", getpid()); \ 143 while (1) sleep(1); \ 144 } \ 145 fail("%zu bytes leaked at %s:%u", \ 146 stats.size_in_use - _leak_start, __FILE__, __LINE__); \ 147 } \ 148 } while (0) 149 150static inline bool is_guardmalloc(void) 151{ 152 const char *env = getenv("GUARDMALLOC"); 153 return (env && 0 == strcmp(env, "YES")); 154} 155 156#endif 157