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