Home | History | Annotate | Download | only in unit
      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 
     37 char* CuStrAlloc(int size)
     38 {
     39 	char* newStr = (char*) malloc( sizeof(char) * (size) );
     40 	return newStr;
     41 }
     42 
     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 
     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 
     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 
     73 void CuStringDelete(CuString *str)
     74 {
     75         if (!str) return;
     76         free(str->buffer);
     77         free(str);
     78 }
     79 
     80 void CuStringResize(CuString* str, int newSize)
     81 {
     82 	str->buffer = (char*) realloc(str->buffer, sizeof(char) * newSize);
     83 	str->size = newSize;
     84 }
     85 
     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 
    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 
    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 
    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 
    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 
    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 
    152 void CuTestDelete(CuTest *t)
    153 {
    154         if (!t) return;
    155         free(t->name);
    156         free(t);
    157 }
    158 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    261 void CuSuiteInit(CuSuite* testSuite)
    262 {
    263 	testSuite->count = 0;
    264 	testSuite->failCount = 0;
    265         memset(testSuite->list, 0, sizeof(testSuite->list));
    266 }
    267 
    268 CuSuite* CuSuiteNew(void)
    269 {
    270 	CuSuite* testSuite = CU_ALLOC(CuSuite);
    271 	CuSuiteInit(testSuite);
    272 	return testSuite;
    273 }
    274 
    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 
    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 
    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 
    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 
    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 
    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