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