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 49#pragma GCC diagnostic push 50#pragma clang diagnostic push 51#pragma GCC diagnostic ignored "-Wformat-nonliteral" 52#pragma clang diagnostic ignored "-Wformat-nonliteral" 53 54static inline void 55unittest_assert_failed(const char* file, int line, char* msg, ...) 56{ 57 char buf[10240]; 58 va_list ap; 59 60 va_start(ap, msg); 61 vsnprintf(buf, sizeof(buf), msg, ap); 62 va_end(ap); 63 PyErr_Format(PyExc_AssertionError, "%s:%d %s", file, line, buf); 64} 65 66#pragma GCC diagnostic pop 67#pragma clang diagnostic pop 68 69#define ASSERT(expr) \ 70 do { \ 71 if (!(expr)) { \ 72 unittest_assert_failed(__FILE__, __LINE__,"%s",#expr); \ 73 goto error; \ 74 } \ 75 } while (0) 76 77#define ASSERT_EQUALS(val1, val2, fmt) \ 78 do { \ 79 if ((val1) != (val2)) { \ 80 unittest_assert_failed(__FILE__, __LINE__, \ 81 fmt " != " fmt, (val1), (val2)); \ 82 goto error; \ 83 } \ 84 } while (0) 85 86#define ASSERT_STREQUALS(val1, val2) \ 87 do { \ 88 const char* _val1 = (val1); \ 89 const char* _val2 = (val2); \ 90 \ 91 if (strcmp(_val1, _val2) != 0) { \ 92 unittest_assert_failed(__FILE__, __LINE__, \ 93 "%s != %s", (_val1), (_val2)); \ 94 goto error; \ 95 } \ 96 } while (0) 97 98#define ASSERT_ISINSTANCE(val, type) \ 99 do { \ 100 if (!Py##type##_Check((val))) { \ 101 unittest_assert_failed(__FILE__, __LINE__, \ 102 "type of value is %s not %s", \ 103 (val)->ob_type->tp_name, \ 104 Py##type##_Type.tp_name); \ 105 goto error; \ 106 } \ 107 } while (0) 108 109 110#define TESTDEF(name) \ 111 { \ 112 #name, \ 113 (PyCFunction)test_##name, \ 114 METH_NOARGS, \ 115 NULL \ 116 } 117 118#endif /* PyObjC_UNITTEST_H */ 119