1 #include <assert.h>
2 #include <setjmp.h>
3 #include <stdlib.h>
4 #include <stdio.h>
5 #include <string.h>
6 #include <math.h>
7
8 #include "CuTest.h"
9
10 /*-------------------------------------------------------------------------*
11 * CuStr
12 *-------------------------------------------------------------------------*/
13
CuStrAlloc(int size)14 char* CuStrAlloc(int size)
15 {
16 char* newStr = (char*) malloc( sizeof(char) * (size) );
17 return newStr;
18 }
19
CuStrCopy(const char * old)20 char* CuStrCopy(const char* old)
21 {
22 int len = strlen(old);
23 char* newStr = CuStrAlloc(len + 1);
24 strcpy(newStr, old);
25 return newStr;
26 }
27
28 /*-------------------------------------------------------------------------*
29 * CuString
30 *-------------------------------------------------------------------------*/
31
CuStringInit(CuString * str)32 void CuStringInit(CuString* str)
33 {
34 str->length = 0;
35 str->size = STRING_MAX;
36 str->buffer = (char*) malloc(sizeof(char) * str->size);
37 str->buffer[0] = '\0';
38 }
39
CuStringNew(void)40 CuString* CuStringNew(void)
41 {
42 CuString* str = (CuString*) malloc(sizeof(CuString));
43 str->length = 0;
44 str->size = STRING_MAX;
45 str->buffer = (char*) malloc(sizeof(char) * str->size);
46 str->buffer[0] = '\0';
47 return str;
48 }
49
CuStringDelete(CuString * str)50 void CuStringDelete(CuString *str)
51 {
52 if (!str) return;
53 free(str->buffer);
54 free(str);
55 }
56
CuStringResize(CuString * str,int newSize)57 void CuStringResize(CuString* str, int newSize)
58 {
59 str->buffer = (char*) realloc(str->buffer, sizeof(char) * newSize);
60 str->size = newSize;
61 }
62
CuStringAppend(CuString * str,const char * text)63 void CuStringAppend(CuString* str, const char* text)
64 {
65 int length;
66
67 if (text == NULL) {
68 text = "NULL";
69 }
70
71 length = strlen(text);
72 if (str->length + length + 1 >= str->size)
73 CuStringResize(str, str->length + length + 1 + STRING_INC);
74 str->length += length;
75 strcat(str->buffer, text);
76 }
77
CuStringAppendChar(CuString * str,char ch)78 void CuStringAppendChar(CuString* str, char ch)
79 {
80 char text[2];
81 text[0] = ch;
82 text[1] = '\0';
83 CuStringAppend(str, text);
84 }
85
CuStringAppendFormat(CuString * str,const char * format,...)86 void CuStringAppendFormat(CuString* str, const char* format, ...)
87 {
88 va_list argp;
89 char buf[HUGE_STRING_LEN];
90 va_start(argp, format);
91 vsprintf(buf, format, argp);
92 va_end(argp);
93 CuStringAppend(str, buf);
94 }
95
CuStringInsert(CuString * str,const char * text,int pos)96 void CuStringInsert(CuString* str, const char* text, int pos)
97 {
98 int length = strlen(text);
99 if (pos > str->length)
100 pos = str->length;
101 if (str->length + length + 1 >= str->size)
102 CuStringResize(str, str->length + length + 1 + STRING_INC);
103 memmove(str->buffer + pos + length, str->buffer + pos, (str->length - pos) + 1);
104 str->length += length;
105 memcpy(str->buffer + pos, text, length);
106 }
107
108 /*-------------------------------------------------------------------------*
109 * CuTest
110 *-------------------------------------------------------------------------*/
111
CuTestInit(CuTest * t,const char * name,TestFunction function)112 void CuTestInit(CuTest* t, const char* name, TestFunction function)
113 {
114 t->name = CuStrCopy(name);
115 t->failed = 0;
116 t->ran = 0;
117 t->message = NULL;
118 t->function = function;
119 t->jumpBuf = NULL;
120 }
121
CuTestNew(const char * name,TestFunction function)122 CuTest* CuTestNew(const char* name, TestFunction function)
123 {
124 CuTest* tc = CU_ALLOC(CuTest);
125 CuTestInit(tc, name, function);
126 return tc;
127 }
128
CuTestDelete(CuTest * t)129 void CuTestDelete(CuTest *t)
130 {
131 if (!t) return;
132 free(t->name);
133 free(t);
134 }
135
CuTestRun(CuTest * tc)136 void CuTestRun(CuTest* tc)
137 {
138 jmp_buf buf;
139 tc->jumpBuf = &buf;
140 if (setjmp(buf) == 0)
141 {
142 tc->ran = 1;
143 (tc->function)(tc);
144 }
145 tc->jumpBuf = 0;
146 }
147
CuFailInternal(CuTest * tc,const char * file,int line,CuString * string)148 static void CuFailInternal(CuTest* tc, const char* file, int line, CuString* string)
149 {
150 char buf[HUGE_STRING_LEN];
151
152 sprintf(buf, "%s:%d: ", file, line);
153 CuStringInsert(string, buf, 0);
154
155 tc->failed = 1;
156 tc->message = string->buffer;
157 if (tc->jumpBuf != 0) longjmp(*(tc->jumpBuf), 0);
158 }
159
CuFail_Line(CuTest * tc,const char * file,int line,const char * message2,const char * message)160 void CuFail_Line(CuTest* tc, const char* file, int line, const char* message2, const char* message)
161 {
162 CuString string;
163
164 CuStringInit(&string);
165 if (message2 != NULL)
166 {
167 CuStringAppend(&string, message2);
168 CuStringAppend(&string, ": ");
169 }
170 CuStringAppend(&string, message);
171 CuFailInternal(tc, file, line, &string);
172 }
173
CuAssert_Line(CuTest * tc,const char * file,int line,const char * message,int condition)174 void CuAssert_Line(CuTest* tc, const char* file, int line, const char* message, int condition)
175 {
176 if (condition) return;
177 CuFail_Line(tc, file, line, NULL, message);
178 }
179
CuAssertStrEquals_LineMsg(CuTest * tc,const char * file,int line,const char * message,const char * expected,const char * actual)180 void CuAssertStrEquals_LineMsg(CuTest* tc, const char* file, int line, const char* message,
181 const char* expected, const char* actual)
182 {
183 CuString string;
184 if ((expected == NULL && actual == NULL) ||
185 (expected != NULL && actual != NULL &&
186 strcmp(expected, actual) == 0))
187 {
188 return;
189 }
190
191 CuStringInit(&string);
192 if (message != NULL)
193 {
194 CuStringAppend(&string, message);
195 CuStringAppend(&string, ": ");
196 }
197 CuStringAppend(&string, "expected <");
198 CuStringAppend(&string, expected);
199 CuStringAppend(&string, "> but was <");
200 CuStringAppend(&string, actual);
201 CuStringAppend(&string, ">");
202 CuFailInternal(tc, file, line, &string);
203 }
204
CuAssertIntEquals_LineMsg(CuTest * tc,const char * file,int line,const char * message,int expected,int actual)205 void CuAssertIntEquals_LineMsg(CuTest* tc, const char* file, int line, const char* message,
206 int expected, int actual)
207 {
208 char buf[STRING_MAX];
209 if (expected == actual) return;
210 sprintf(buf, "expected <%d> but was <%d>", expected, actual);
211 CuFail_Line(tc, file, line, message, buf);
212 }
213
CuAssertLongIntEquals_LineMsg(CuTest * tc,const char * file,int line,const char * message,long int expected,long int actual)214 void CuAssertLongIntEquals_LineMsg(CuTest *tc, const char *file, int line, const char *message,
215 long int expected, long int actual)
216 {
217 char buf[STRING_MAX];
218 if (expected == actual) return;
219 sprintf(buf, "expected <%ld> but was <%ld>", expected, actual);
220 CuFail_Line(tc, file, line, message, buf);
221 }
222
CuAssertDblEquals_LineMsg(CuTest * tc,const char * file,int line,const char * message,double expected,double actual,double delta)223 void CuAssertDblEquals_LineMsg(CuTest* tc, const char* file, int line, const char* message,
224 double expected, double actual, double delta)
225 {
226 char buf[STRING_MAX];
227 if (fabs(expected - actual) <= delta) return;
228 sprintf(buf, "expected <%f> but was <%f>", expected, actual);
229
230 CuFail_Line(tc, file, line, message, buf);
231 }
232
CuAssertPtrEquals_LineMsg(CuTest * tc,const char * file,int line,const char * message,const void * expected,const void * actual)233 void CuAssertPtrEquals_LineMsg(CuTest* tc, const char* file, int line, const char* message,
234 const void* expected, const void* actual)
235 {
236 char buf[STRING_MAX];
237 if (expected == actual) return;
238 sprintf(buf, "expected pointer <0x%p> but was <0x%p>", expected, actual);
239 CuFail_Line(tc, file, line, message, buf);
240 }
241
242
243 /*-------------------------------------------------------------------------*
244 * CuSuite
245 *-------------------------------------------------------------------------*/
246
CuSuiteInit(CuSuite * testSuite)247 void CuSuiteInit(CuSuite* testSuite)
248 {
249 testSuite->count = 0;
250 testSuite->failCount = 0;
251 memset(testSuite->list, 0, sizeof(testSuite->list));
252 }
253
CuSuiteNew(void)254 CuSuite* CuSuiteNew(void)
255 {
256 CuSuite* testSuite = CU_ALLOC(CuSuite);
257 CuSuiteInit(testSuite);
258 return testSuite;
259 }
260
CuSuiteDelete(CuSuite * testSuite)261 void CuSuiteDelete(CuSuite *testSuite)
262 {
263 unsigned int n;
264 for (n=0; n < MAX_TEST_CASES; n++)
265 {
266 if (testSuite->list[n])
267 {
268 CuTestDelete(testSuite->list[n]);
269 }
270 }
271 free(testSuite);
272
273 }
274
CuSuiteAdd(CuSuite * testSuite,CuTest * testCase)275 void CuSuiteAdd(CuSuite* testSuite, CuTest *testCase)
276 {
277 assert(testSuite->count < MAX_TEST_CASES);
278 testSuite->list[testSuite->count] = testCase;
279 testSuite->count++;
280 }
281
CuSuiteAddSuite(CuSuite * testSuite,CuSuite * testSuite2)282 void CuSuiteAddSuite(CuSuite* testSuite, CuSuite* testSuite2)
283 {
284 int i;
285 for (i = 0 ; i < testSuite2->count ; ++i)
286 {
287 CuTest* testCase = testSuite2->list[i];
288 CuSuiteAdd(testSuite, testCase);
289 }
290 }
291
CuSuiteRun(CuSuite * testSuite)292 void CuSuiteRun(CuSuite* testSuite)
293 {
294 int i;
295 for (i = 0 ; i < testSuite->count ; ++i)
296 {
297 CuTest* testCase = testSuite->list[i];
298 CuTestRun(testCase);
299 if (testCase->failed) { testSuite->failCount += 1; }
300 }
301 }
302
CuSuiteSummary(CuSuite * testSuite,CuString * summary)303 void CuSuiteSummary(CuSuite* testSuite, CuString* summary)
304 {
305 int i;
306 for (i = 0 ; i < testSuite->count ; ++i)
307 {
308 CuTest* testCase = testSuite->list[i];
309 CuStringAppend(summary, testCase->failed ? "F" : ".");
310 }
311 CuStringAppend(summary, "\n\n");
312 }
313
CuSuiteDetails(CuSuite * testSuite,CuString * details)314 void CuSuiteDetails(CuSuite* testSuite, CuString* details)
315 {
316 int i;
317 int failCount = 0;
318
319 if (testSuite->failCount == 0)
320 {
321 int passCount = testSuite->count - testSuite->failCount;
322 const char* testWord = passCount == 1 ? "test" : "tests";
323 CuStringAppendFormat(details, "OK (%d %s)\n", passCount, testWord);
324 }
325 else
326 {
327 if (testSuite->failCount == 1)
328 CuStringAppend(details, "There was 1 failure:\n");
329 else
330 CuStringAppendFormat(details, "There were %d failures:\n", testSuite->failCount);
331
332 for (i = 0 ; i < testSuite->count ; ++i)
333 {
334 CuTest* testCase = testSuite->list[i];
335 if (testCase->failed)
336 {
337 failCount++;
338 CuStringAppendFormat(details, "%d) %s: %s\n",
339 failCount, testCase->name, testCase->message);
340 }
341 }
342 CuStringAppend(details, "\n!!!FAILURES!!!\n");
343
344 CuStringAppendFormat(details, "Runs: %d ", testSuite->count);
345 CuStringAppendFormat(details, "Passes: %d ", testSuite->count - testSuite->failCount);
346 CuStringAppendFormat(details, "Fails: %d\n", testSuite->failCount);
347 }
348 }
349