00001 #include <assert.h>
00002 #include <setjmp.h>
00003 #include <stdlib.h>
00004 #include <stdio.h>
00005 #include <string.h>
00006 #include <math.h>
00007
00008 #include "CuTest.h"
00009
00010
00011
00012
00013
00014 char* CuStrAlloc(int size)
00015 {
00016 char* newStr = (char*) malloc( sizeof(char) * (size) );
00017 return newStr;
00018 }
00019
00020 char* CuStrCopy(const char* old)
00021 {
00022 int len = strlen(old);
00023 char* newStr = CuStrAlloc(len + 1);
00024 strcpy(newStr, old);
00025 return newStr;
00026 }
00027
00028
00029
00030
00031
00032 void CuStringInit(CuString* str)
00033 {
00034 str->length = 0;
00035 str->size = STRING_MAX;
00036 str->buffer = (char*) malloc(sizeof(char) * str->size);
00037 str->buffer[0] = '\0';
00038 }
00039
00040 CuString* CuStringNew(void)
00041 {
00042 CuString* str = (CuString*) malloc(sizeof(CuString));
00043 str->length = 0;
00044 str->size = STRING_MAX;
00045 str->buffer = (char*) malloc(sizeof(char) * str->size);
00046 str->buffer[0] = '\0';
00047 return str;
00048 }
00049
00050 void CuStringResize(CuString* str, int newSize)
00051 {
00052 str->buffer = (char*) realloc(str->buffer, sizeof(char) * newSize);
00053 str->size = newSize;
00054 }
00055
00056 void CuStringAppend(CuString* str, const char* text)
00057 {
00058 int length;
00059
00060 if (text == NULL) {
00061 text = "NULL";
00062 }
00063
00064 length = strlen(text);
00065 if (str->length + length + 1 >= str->size)
00066 CuStringResize(str, str->length + length + 1 + STRING_INC);
00067 str->length += length;
00068 strcat(str->buffer, text);
00069 }
00070
00071 void CuStringAppendChar(CuString* str, char ch)
00072 {
00073 char text[2];
00074 text[0] = ch;
00075 text[1] = '\0';
00076 CuStringAppend(str, text);
00077 }
00078
00079 void CuStringAppendFormat(CuString* str, const char* format, ...)
00080 {
00081 va_list argp;
00082 char buf[HUGE_STRING_LEN];
00083 va_start(argp, format);
00084 vsprintf(buf, format, argp);
00085 va_end(argp);
00086 CuStringAppend(str, buf);
00087 }
00088
00089 void CuStringInsert(CuString* str, const char* text, int pos)
00090 {
00091 int length = strlen(text);
00092 if (pos > str->length)
00093 pos = str->length;
00094 if (str->length + length + 1 >= str->size)
00095 CuStringResize(str, str->length + length + 1 + STRING_INC);
00096 memmove(str->buffer + pos + length, str->buffer + pos, (str->length - pos) + 1);
00097 str->length += length;
00098 memcpy(str->buffer + pos, text, length);
00099 }
00100
00101
00102
00103
00104
00105 void CuTestInit(CuTest* t, const char* name, TestFunction function)
00106 {
00107 t->name = CuStrCopy(name);
00108 t->failed = 0;
00109 t->ran = 0;
00110 t->message = NULL;
00111 t->function = function;
00112 t->jumpBuf = NULL;
00113 }
00114
00115 CuTest* CuTestNew(const char* name, TestFunction function)
00116 {
00117 CuTest* tc = CU_ALLOC(CuTest);
00118 CuTestInit(tc, name, function);
00119 return tc;
00120 }
00121
00122 void CuTestRun(CuTest* tc)
00123 {
00124 jmp_buf buf;
00125 tc->jumpBuf = &buf;
00126 if (setjmp(buf) == 0)
00127 {
00128 tc->ran = 1;
00129 (tc->function)(tc);
00130 }
00131 tc->jumpBuf = 0;
00132 }
00133
00134 static void CuFailInternal(CuTest* tc, const char* file, int line, CuString* string)
00135 {
00136 char buf[HUGE_STRING_LEN];
00137
00138 sprintf(buf, "%s:%d: ", file, line);
00139 CuStringInsert(string, buf, 0);
00140
00141 tc->failed = 1;
00142 tc->message = string->buffer;
00143 if (tc->jumpBuf != 0) longjmp(*(tc->jumpBuf), 0);
00144 }
00145
00146 void CuFail_Line(CuTest* tc, const char* file, int line, const char* message2, const char* message)
00147 {
00148 CuString string;
00149
00150 CuStringInit(&string);
00151 if (message2 != NULL)
00152 {
00153 CuStringAppend(&string, message2);
00154 CuStringAppend(&string, ": ");
00155 }
00156 CuStringAppend(&string, message);
00157 CuFailInternal(tc, file, line, &string);
00158 }
00159
00160 void CuAssert_Line(CuTest* tc, const char* file, int line, const char* message, int condition)
00161 {
00162 if (condition) return;
00163 CuFail_Line(tc, file, line, NULL, message);
00164 }
00165
00166 void CuAssertStrEquals_LineMsg(CuTest* tc, const char* file, int line, const char* message,
00167 const char* expected, const char* actual)
00168 {
00169 CuString string;
00170 if ((expected == NULL && actual == NULL) ||
00171 (expected != NULL && actual != NULL &&
00172 strcmp(expected, actual) == 0))
00173 {
00174 return;
00175 }
00176
00177 CuStringInit(&string);
00178 if (message != NULL)
00179 {
00180 CuStringAppend(&string, message);
00181 CuStringAppend(&string, ": ");
00182 }
00183 CuStringAppend(&string, "expected <");
00184 CuStringAppend(&string, expected);
00185 CuStringAppend(&string, "> but was <");
00186 CuStringAppend(&string, actual);
00187 CuStringAppend(&string, ">");
00188 CuFailInternal(tc, file, line, &string);
00189 }
00190
00191 void CuAssertIntEquals_LineMsg(CuTest* tc, const char* file, int line, const char* message,
00192 int expected, int actual)
00193 {
00194 char buf[STRING_MAX];
00195 if (expected == actual) return;
00196 sprintf(buf, "expected <%d> but was <%d>", expected, actual);
00197 CuFail_Line(tc, file, line, message, buf);
00198 }
00199
00200 void CuAssertDblEquals_LineMsg(CuTest* tc, const char* file, int line, const char* message,
00201 double expected, double actual, double delta)
00202 {
00203 char buf[STRING_MAX];
00204 if (fabs(expected - actual) <= delta) return;
00205 sprintf(buf, "expected <%lf> but was <%lf>", expected, actual);
00206 CuFail_Line(tc, file, line, message, buf);
00207 }
00208
00209 void CuAssertPtrEquals_LineMsg(CuTest* tc, const char* file, int line, const char* message,
00210 void* expected, void* actual)
00211 {
00212 char buf[STRING_MAX];
00213 if (expected == actual) return;
00214 sprintf(buf, "expected pointer <0x%p> but was <0x%p>", expected, actual);
00215 CuFail_Line(tc, file, line, message, buf);
00216 }
00217
00218
00219
00220
00221
00222
00223 void CuSuiteInit(CuSuite* testSuite)
00224 {
00225 testSuite->count = 0;
00226 testSuite->failCount = 0;
00227 }
00228
00229 CuSuite* CuSuiteNew(void)
00230 {
00231 CuSuite* testSuite = CU_ALLOC(CuSuite);
00232 CuSuiteInit(testSuite);
00233 return testSuite;
00234 }
00235
00236 void CuSuiteAdd(CuSuite* testSuite, CuTest *testCase)
00237 {
00238 assert(testSuite->count < MAX_TEST_CASES);
00239 testSuite->list[testSuite->count] = testCase;
00240 testSuite->count++;
00241 }
00242
00243 void CuSuiteAddSuite(CuSuite* testSuite, CuSuite* testSuite2)
00244 {
00245 int i;
00246 for (i = 0 ; i < testSuite2->count ; ++i)
00247 {
00248 CuTest* testCase = testSuite2->list[i];
00249 CuSuiteAdd(testSuite, testCase);
00250 }
00251 }
00252
00253 void CuSuiteRun(CuSuite* testSuite)
00254 {
00255 int i;
00256 for (i = 0 ; i < testSuite->count ; ++i)
00257 {
00258 CuTest* testCase = testSuite->list[i];
00259 CuTestRun(testCase);
00260 if (testCase->failed) { testSuite->failCount += 1; }
00261 }
00262 }
00263
00264 void CuSuiteSummary(CuSuite* testSuite, CuString* summary)
00265 {
00266 int i;
00267 for (i = 0 ; i < testSuite->count ; ++i)
00268 {
00269 CuTest* testCase = testSuite->list[i];
00270 CuStringAppend(summary, testCase->failed ? "F" : ".");
00271 }
00272 CuStringAppend(summary, "\n\n");
00273 }
00274
00275 void CuSuiteDetails(CuSuite* testSuite, CuString* details)
00276 {
00277 int i;
00278 int failCount = 0;
00279
00280 if (testSuite->failCount == 0)
00281 {
00282 int passCount = testSuite->count - testSuite->failCount;
00283 const char* testWord = passCount == 1 ? "test" : "tests";
00284 CuStringAppendFormat(details, "OK (%d %s)\n", passCount, testWord);
00285 }
00286 else
00287 {
00288 if (testSuite->failCount == 1)
00289 CuStringAppend(details, "There was 1 failure:\n");
00290 else
00291 CuStringAppendFormat(details, "There were %d failures:\n", testSuite->failCount);
00292
00293 for (i = 0 ; i < testSuite->count ; ++i)
00294 {
00295 CuTest* testCase = testSuite->list[i];
00296 if (testCase->failed)
00297 {
00298 failCount++;
00299 CuStringAppendFormat(details, "%d) %s: %s\n",
00300 failCount, testCase->name, testCase->message);
00301 }
00302 }
00303 CuStringAppend(details, "\n!!!FAILURES!!!\n");
00304
00305 CuStringAppendFormat(details, "Runs: %d ", testSuite->count);
00306 CuStringAppendFormat(details, "Passes: %d ", testSuite->count - testSuite->failCount);
00307 CuStringAppendFormat(details, "Fails: %d\n", testSuite->failCount);
00308 }
00309 }