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