1#ifndef PyObjC_UNITTEST_H 2#define PyObjC_UNITTEST_H 3/*! 4 * @header pyobjc-unittest.h 5 * @abstract Defining C-based unittests 6 * @discussion 7 * 8 * This file defines a very simple unittest framework for the Objective-C 9 * modules of PyObjC. 10 * 11 * It is intended to be used with PyUnit, see objc.test.test_ctests for more 12 * information on that. 13 * 14 * Usage: 15 * <PRE> 16 * BEGIN_UNITEST(IntSize) 17 * // This is a normal C block, starting with variable definitions 18 * int i = 3; 19 * 20 * ASSERT_EQUALS(sizeof(int), sizeof(i), "%d"); 21 * 22 * END_UNITTEST 23 * </PRE> 24 * 25 * And in the PyMethodDef list for the module: 26 * <PRE> 27 * TESTDEF(IntSize), 28 * </PRE> 29 * 30 * Use 'FAIL_IF' to abort a test due to a Python exception. 31 */ 32 33#include <stdarg.h> 34 35#define BEGIN_UNITTEST(name) \ 36 static PyObject* \ 37 test_##name (PyObject* self __attribute__((__unused__))) \ 38 { \ 39 40#define END_UNITTEST \ 41 Py_INCREF(Py_None); \ 42 return Py_None; \ 43 error: \ 44 return NULL; \ 45 } 46 47#define FAIL_IF(expr) do { if ((expr)) goto error; } while(0) 48 49static inline void 50unittest_assert_failed(const char* file, int line, char* msg, ...) 51{ 52 char buf[10240]; 53 va_list ap; 54 55 va_start(ap, msg); 56 vsnprintf(buf, sizeof(buf), msg, ap); 57 va_end(ap); 58 PyErr_Format(PyExc_AssertionError, "%s:%d %s", file, line, buf); 59} 60 61#define ASSERT(expr) \ 62 do { \ 63 if (!(expr)) { \ 64 unittest_assert_failed(__FILE__, __LINE__,"%s",#expr); \ 65 goto error; \ 66 } \ 67 } while (0) 68 69#define ASSERT_EQUALS(val1, val2, fmt) \ 70 do { \ 71 if ((val1) != (val2)) { \ 72 unittest_assert_failed(__FILE__, __LINE__, \ 73 fmt " != " fmt, (val1), (val2)); \ 74 goto error; \ 75 } \ 76 } while (0) 77 78#define ASSERT_STREQUALS(val1, val2) \ 79 do { \ 80 const char* _val1 = (val1); \ 81 const char* _val2 = (val2); \ 82 \ 83 if (strcmp(_val1, _val2) != 0) { \ 84 unittest_assert_failed(__FILE__, __LINE__, \ 85 "%s != %s", (_val1), (_val2)); \ 86 goto error; \ 87 } \ 88 } while (0) 89 90#define ASSERT_ISINSTANCE(val, type) \ 91 do { \ 92 if (!Py##type##_Check((val))) { \ 93 unittest_assert_failed(__FILE__, __LINE__, \ 94 "type of value is %s not %s", \ 95 (val)->ob_type->tp_name, \ 96 Py##type##_Type.tp_name); \ 97 goto error; \ 98 } \ 99 } while (0) 100 101 102#define TESTDEF(name) \ 103 { \ 104 #name, \ 105 (PyCFunction)test_##name, \ 106 METH_NOARGS, \ 107 NULL \ 108 } 109 110#endif /* PyObjC_UNITTEST_H */ 111