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 37char* CuStrAlloc(int size) 38{ 39 char* newStr = (char*) malloc( sizeof(char) * (size) ); 40 return newStr; 41} 42 43char* 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 55void 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 63CuString* 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 73void CuStringDelete(CuString *str) 74{ 75 if (!str) return; 76 free(str->buffer); 77 free(str); 78} 79 80void CuStringResize(CuString* str, int newSize) 81{ 82 str->buffer = (char*) realloc(str->buffer, sizeof(char) * newSize); 83 str->size = newSize; 84} 85 86void 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 101void 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 119void 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 135void 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 145CuTest* CuTestNew(const char* name, TestFunction function) 146{ 147 CuTest* tc = CU_ALLOC(CuTest); 148 CuTestInit(tc, name, function); 149 return tc; 150} 151 152void CuTestDelete(CuTest *t) 153{ 154 if (!t) return; 155 free(t->name); 156 free(t); 157} 158 159void 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 171static 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 183void 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 197void 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 203void 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 228void 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 237void 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 247void 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 261void CuSuiteInit(CuSuite* testSuite) 262{ 263 testSuite->count = 0; 264 testSuite->failCount = 0; 265 memset(testSuite->list, 0, sizeof(testSuite->list)); 266} 267 268CuSuite* CuSuiteNew(void) 269{ 270 CuSuite* testSuite = CU_ALLOC(CuSuite); 271 CuSuiteInit(testSuite); 272 return testSuite; 273} 274 275void 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 289void CuSuiteAdd(CuSuite* testSuite, CuTest *testCase) 290{ 291 assert(testSuite->count < MAX_TEST_CASES); 292 testSuite->list[testSuite->count] = testCase; 293 testSuite->count++; 294} 295 296void 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 306void 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 317void 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 328void 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