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