aboutsummaryrefslogtreecommitdiffstats
path: root/simple-test.h
blob: e7220cad04f2c95d0e6000a1433f5260129d7a64 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
#ifndef _TEST_H_
#define _TEST_H_

#include <stdlib.h>
#include <stdio.h>
#include <stdbool.h>

/*************
 *  REGIONS  *
 *************/

/* extra levels of abstraction are necessary
 * to get __COUNTER__ to evaluate before
 * being concatenated */
#define _TEST_PASTE(x, y) \
x ## y

/* the whole thing is inside one
 * big function. yay! */
#define BEGIN_TEST \
typedef void (*_test_cleanup_t)(void); \
_test_cleanup_t _test_cleanup_current=NULL; \
int _test_count_current=1; \
int main(int argc, char *argv[]) \
{

/* yaaaay! */
#define END_TEST \
	printf("\e[1m    :: \e[m\e[32msuccess!\e[m\n"); \
	return 0; \
}

/* print a fancy description and
 * reset the cleanup function
 * pointer to NULL so, if it isn't
 * defined again, no cleanup will
 * be called */
#define TEST(description) \
_test_cleanup_current=NULL; \
printf("\e[1m%3i :: \e[m\e[33m%s\e[m\n", _test_count_current++, description);

/* pass in statements to be called on test
 * exit. goes after varible declarations and
 * before test body. */
#define CLEANUP(statements) \
_TEST_CLEANUP_UNIQ(statements, __COUNTER__)

/* insert a unique cleanup function */
#define _TEST_CLEANUP_UNIQ(statements, unique_count) \
void _TEST_PASTE(_test_cleanup_, unique_count)(void) \
{ \
	statements \
} \
_test_cleanup_current=_TEST_PASTE(_test_cleanup_, unique_count);

/* pretty printing for the current state within
 * a test */
#define STATE(...) \
do { \
	printf("\e[1m    :: \e[m\e[34m"); \
	printf(__VA_ARGS__); \
	printf("...\e[m\n"); \
} while(0)

/* one of these goes at the end of every test
 * with CLEANUP (unless you want memory leaks).
 * if you want, stick it in those without CLEANUP
 * too. */
#define RETURN() _TEST_RETURN(false)

/* checks if there is a cleanup function to
 * call and then either continues or terminates
 * the test */
#define _TEST_RETURN(fail) \
do { \
	if(_test_cleanup_current != NULL) \
		(*_test_cleanup_current)(); \
	if(fail) \
		exit(1); \
} while(0)

/***********
 *  TESTS  *
 ***********/

#define EXPECT_NULL(summary, arg) \
do { \
	if((arg) != NULL) \
		_TEST_FAIL_VAL(summary, "%s", "%p", "NULL", (void*)(arg)); \
} while(0);

#define EXPECT_NON_NULL(summary, arg) \
do { \
	if((arg) == NULL) \
		_TEST_FAIL_VAL(summary, "%s", "%p", "non NULL", (void*)(arg)); \
} while(0);

#define EXPECT_ZERO(summary, arg) \
do { \
	if(arg) \
		_TEST_FAIL_VAL(summary, "%i", "%i", 0, arg); \
} while(0);

#define EXPECT_ONE(summary, arg) \
do { \
	if((arg) != 1) \
		_TEST_FAIL_VAL(summary, "%i", "%i", 1, arg); \
} while(0);

#define EXPECT_GREATER_THAN_ZERO(summary, arg) \
do { \
	if((arg) <= 0) \
		_TEST_FAIL_VAL(summary, "%s", "%i", ">0", arg); \
} while(0);

#define EXPECT_INT(summary, arg1, arg2) \
do { \
	if((arg1) != (arg2)) \
		_TEST_FAIL_VAL(summary, "%i", "%i", arg1, arg2); \
} while(0);

#define EXPECT_EQUAL_INT(summary, arg1, arg2) \
do { \
	if((arg1) != (arg2)) \
		_TEST_FAIL_EQUAL(summary, "%i", "%i", arg1, arg2); \
} while(0);

#define EXPECT_UNEQUAL_INT(summary, arg1, arg2) \
do { \
	if((arg1) == (arg2)) \
		_TEST_FAIL_EQUAL(summary, "%i", "%i", arg1, arg2); \
} while(0);

#define EXPECT_STR(summary, arg1, arg2) \
do { \
	if( strcmp(arg1, arg2) ) \
		_TEST_FAIL_VAL(summary, "‘%s’", "‘%s’", arg1, arg2); \
} while(0);

#define EXPECT_EQUAL_STR(summary, arg1, arg2) \
do { \
	if( strcmp(arg1, arg2) ) \
		_TEST_FAIL_EQUAL(summary, "‘%s’", "‘%s’", arg1, arg2); \
} while(0);

#define EXPECT_UNEQUAL_STR(summary, arg1, arg2) \
do { \
	if( !strcmp(arg1, arg2) ) \
		_TEST_FAIL_EQUAL(summary, "‘%s’", "‘%s’", arg1, arg2); \
} while(0);

#define _TEST_FAIL_VAL(summary, format1, format2, expected, actual) \
do { \
	printf("\e[1m    :: \e[m\e[31mFAIL: " summary "\e[m\n"); \
	printf("\e[1m    :: \e[m\e[1;32m  expected:\e[m " format1 "\n", expected);\
	printf("\e[1m    :: \e[m\e[1;31m    actual:\e[m " format2 "\n", actual); \
	_TEST_RETURN(true); \
} while(0)

#define _TEST_FAIL_EQUAL(summary, format1, format2, arg1, arg2) \
do { \
	printf("\e[1m    :: \e[m\e[31mFAIL: " summary "\e[m\n"); \
	printf("\e[1m    :: \e[m  arg1 == \e[1;31m" format1 "\e[m\n", arg1); \
	printf("\e[1m    :: \e[m  arg2 == \e[1;31m" format2 "\e[m\n", arg2); \
	_TEST_RETURN(true); \
} while(0)

#endif