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