diff --git a/cutest-1.5/AllTests.c b/cutest-1.5/AllTests.c new file mode 100644 index 0000000..5c849ef --- /dev/null +++ b/cutest-1.5/AllTests.c @@ -0,0 +1,25 @@ +#include + +#include "CuTest.h" + +CuSuite* CuGetSuite(); +CuSuite* CuStringGetSuite(); + +void RunAllTests(void) +{ + CuString *output = CuStringNew(); + CuSuite* suite = CuSuiteNew(); + + CuSuiteAddSuite(suite, CuGetSuite()); + CuSuiteAddSuite(suite, CuStringGetSuite()); + + CuSuiteRun(suite); + CuSuiteSummary(suite, output); + CuSuiteDetails(suite, output); + printf("%s\n", output->buffer); +} + +int main(void) +{ + RunAllTests(); +} diff --git a/cutest-1.5/CuTest.c b/cutest-1.5/CuTest.c new file mode 100644 index 0000000..8f61199 --- /dev/null +++ b/cutest-1.5/CuTest.c @@ -0,0 +1,339 @@ +#include +#include +#include +#include +#include +#include + +#include "CuTest.h" + +/*-------------------------------------------------------------------------* + * CuStr + *-------------------------------------------------------------------------*/ + +char* CuStrAlloc(int size) +{ + char* newStr = (char*) malloc( sizeof(char) * (size) ); + return newStr; +} + +char* CuStrCopy(const char* old) +{ + int len = strlen(old); + char* newStr = CuStrAlloc(len + 1); + strcpy(newStr, old); + return newStr; +} + +/*-------------------------------------------------------------------------* + * CuString + *-------------------------------------------------------------------------*/ + +void CuStringInit(CuString* str) +{ + str->length = 0; + str->size = STRING_MAX; + str->buffer = (char*) malloc(sizeof(char) * str->size); + str->buffer[0] = '\0'; +} + +CuString* CuStringNew(void) +{ + CuString* str = (CuString*) malloc(sizeof(CuString)); + str->length = 0; + str->size = STRING_MAX; + str->buffer = (char*) malloc(sizeof(char) * str->size); + str->buffer[0] = '\0'; + return str; +} + +void CuStringDelete(CuString *str) +{ + if (!str) return; + free(str->buffer); + free(str); +} + +void CuStringResize(CuString* str, int newSize) +{ + str->buffer = (char*) realloc(str->buffer, sizeof(char) * newSize); + str->size = newSize; +} + +void CuStringAppend(CuString* str, const char* text) +{ + int length; + + if (text == NULL) { + text = "NULL"; + } + + length = strlen(text); + if (str->length + length + 1 >= str->size) + CuStringResize(str, str->length + length + 1 + STRING_INC); + str->length += length; + strcat(str->buffer, text); +} + +void CuStringAppendChar(CuString* str, char ch) +{ + char text[2]; + text[0] = ch; + text[1] = '\0'; + CuStringAppend(str, text); +} + +void CuStringAppendFormat(CuString* str, const char* format, ...) +{ + va_list argp; + char buf[HUGE_STRING_LEN]; + va_start(argp, format); + vsprintf(buf, format, argp); + va_end(argp); + CuStringAppend(str, buf); +} + +void CuStringInsert(CuString* str, const char* text, int pos) +{ + int length = strlen(text); + if (pos > str->length) + pos = str->length; + if (str->length + length + 1 >= str->size) + CuStringResize(str, str->length + length + 1 + STRING_INC); + memmove(str->buffer + pos + length, str->buffer + pos, (str->length - pos) + 1); + str->length += length; + memcpy(str->buffer + pos, text, length); +} + +/*-------------------------------------------------------------------------* + * CuTest + *-------------------------------------------------------------------------*/ + +void CuTestInit(CuTest* t, const char* name, TestFunction function) +{ + t->name = CuStrCopy(name); + t->failed = 0; + t->ran = 0; + t->message = NULL; + t->function = function; + t->jumpBuf = NULL; +} + +CuTest* CuTestNew(const char* name, TestFunction function) +{ + CuTest* tc = CU_ALLOC(CuTest); + CuTestInit(tc, name, function); + return tc; +} + +void CuTestDelete(CuTest *t) +{ + if (!t) return; + free(t->name); + free(t); +} + +void CuTestRun(CuTest* tc) +{ + jmp_buf buf; + tc->jumpBuf = &buf; + if (setjmp(buf) == 0) + { + tc->ran = 1; + (tc->function)(tc); + } + tc->jumpBuf = 0; +} + +static void CuFailInternal(CuTest* tc, const char* file, int line, CuString* string) +{ + char buf[HUGE_STRING_LEN]; + + sprintf(buf, "%s:%d: ", file, line); + CuStringInsert(string, buf, 0); + + tc->failed = 1; + tc->message = string->buffer; + if (tc->jumpBuf != 0) longjmp(*(tc->jumpBuf), 0); +} + +void CuFail_Line(CuTest* tc, const char* file, int line, const char* message2, const char* message) +{ + CuString string; + + CuStringInit(&string); + if (message2 != NULL) + { + CuStringAppend(&string, message2); + CuStringAppend(&string, ": "); + } + CuStringAppend(&string, message); + CuFailInternal(tc, file, line, &string); +} + +void CuAssert_Line(CuTest* tc, const char* file, int line, const char* message, int condition) +{ + if (condition) return; + CuFail_Line(tc, file, line, NULL, message); +} + +void CuAssertStrEquals_LineMsg(CuTest* tc, const char* file, int line, const char* message, + const char* expected, const char* actual) +{ + CuString string; + if ((expected == NULL && actual == NULL) || + (expected != NULL && actual != NULL && + strcmp(expected, actual) == 0)) + { + return; + } + + CuStringInit(&string); + if (message != NULL) + { + CuStringAppend(&string, message); + CuStringAppend(&string, ": "); + } + CuStringAppend(&string, "expected <"); + CuStringAppend(&string, expected); + CuStringAppend(&string, "> but was <"); + CuStringAppend(&string, actual); + CuStringAppend(&string, ">"); + CuFailInternal(tc, file, line, &string); +} + +void CuAssertIntEquals_LineMsg(CuTest* tc, const char* file, int line, const char* message, + int expected, int actual) +{ + char buf[STRING_MAX]; + if (expected == actual) return; + sprintf(buf, "expected <%d> but was <%d>", expected, actual); + CuFail_Line(tc, file, line, message, buf); +} + +void CuAssertDblEquals_LineMsg(CuTest* tc, const char* file, int line, const char* message, + double expected, double actual, double delta) +{ + char buf[STRING_MAX]; + if (fabs(expected - actual) <= delta) return; + sprintf(buf, "expected <%f> but was <%f>", expected, actual); + + CuFail_Line(tc, file, line, message, buf); +} + +void CuAssertPtrEquals_LineMsg(CuTest* tc, const char* file, int line, const char* message, + void* expected, void* actual) +{ + char buf[STRING_MAX]; + if (expected == actual) return; + sprintf(buf, "expected pointer <0x%p> but was <0x%p>", expected, actual); + CuFail_Line(tc, file, line, message, buf); +} + + +/*-------------------------------------------------------------------------* + * CuSuite + *-------------------------------------------------------------------------*/ + +void CuSuiteInit(CuSuite* testSuite) +{ + testSuite->count = 0; + testSuite->failCount = 0; + memset(testSuite->list, 0, sizeof(testSuite->list)); +} + +CuSuite* CuSuiteNew(void) +{ + CuSuite* testSuite = CU_ALLOC(CuSuite); + CuSuiteInit(testSuite); + return testSuite; +} + +void CuSuiteDelete(CuSuite *testSuite) +{ + unsigned int n; + for (n=0; n < MAX_TEST_CASES; n++) + { + if (testSuite->list[n]) + { + CuTestDelete(testSuite->list[n]); + } + } + free(testSuite); + +} + +void CuSuiteAdd(CuSuite* testSuite, CuTest *testCase) +{ + assert(testSuite->count < MAX_TEST_CASES); + testSuite->list[testSuite->count] = testCase; + testSuite->count++; +} + +void CuSuiteAddSuite(CuSuite* testSuite, CuSuite* testSuite2) +{ + int i; + for (i = 0 ; i < testSuite2->count ; ++i) + { + CuTest* testCase = testSuite2->list[i]; + CuSuiteAdd(testSuite, testCase); + } +} + +void CuSuiteRun(CuSuite* testSuite) +{ + int i; + for (i = 0 ; i < testSuite->count ; ++i) + { + CuTest* testCase = testSuite->list[i]; + CuTestRun(testCase); + if (testCase->failed) { testSuite->failCount += 1; } + } +} + +void CuSuiteSummary(CuSuite* testSuite, CuString* summary) +{ + int i; + for (i = 0 ; i < testSuite->count ; ++i) + { + CuTest* testCase = testSuite->list[i]; + CuStringAppend(summary, testCase->failed ? "F" : "."); + } + CuStringAppend(summary, "\n\n"); +} + +void CuSuiteDetails(CuSuite* testSuite, CuString* details) +{ + int i; + int failCount = 0; + + if (testSuite->failCount == 0) + { + int passCount = testSuite->count - testSuite->failCount; + const char* testWord = passCount == 1 ? "test" : "tests"; + CuStringAppendFormat(details, "OK (%d %s)\n", passCount, testWord); + } + else + { + if (testSuite->failCount == 1) + CuStringAppend(details, "There was 1 failure:\n"); + else + CuStringAppendFormat(details, "There were %d failures:\n", testSuite->failCount); + + for (i = 0 ; i < testSuite->count ; ++i) + { + CuTest* testCase = testSuite->list[i]; + if (testCase->failed) + { + failCount++; + CuStringAppendFormat(details, "%d) %s: %s\n", + failCount, testCase->name, testCase->message); + } + } + CuStringAppend(details, "\n!!!FAILURES!!!\n"); + + CuStringAppendFormat(details, "Runs: %d ", testSuite->count); + CuStringAppendFormat(details, "Passes: %d ", testSuite->count - testSuite->failCount); + CuStringAppendFormat(details, "Fails: %d\n", testSuite->failCount); + } +} diff --git a/cutest-1.5/CuTest.h b/cutest-1.5/CuTest.h new file mode 100644 index 0000000..8b32773 --- /dev/null +++ b/cutest-1.5/CuTest.h @@ -0,0 +1,116 @@ +#ifndef CU_TEST_H +#define CU_TEST_H + +#include +#include + +#define CUTEST_VERSION "CuTest 1.5" + +/* CuString */ + +char* CuStrAlloc(int size); +char* CuStrCopy(const char* old); + +#define CU_ALLOC(TYPE) ((TYPE*) malloc(sizeof(TYPE))) + +#define HUGE_STRING_LEN 8192 +#define STRING_MAX 256 +#define STRING_INC 256 + +typedef struct +{ + int length; + int size; + char* buffer; +} CuString; + +void CuStringInit(CuString* str); +CuString* CuStringNew(void); +void CuStringRead(CuString* str, const char* path); +void CuStringAppend(CuString* str, const char* text); +void CuStringAppendChar(CuString* str, char ch); +void CuStringAppendFormat(CuString* str, const char* format, ...); +void CuStringInsert(CuString* str, const char* text, int pos); +void CuStringResize(CuString* str, int newSize); +void CuStringDelete(CuString* str); + +/* CuTest */ + +typedef struct CuTest CuTest; + +typedef void (*TestFunction)(CuTest *); + +struct CuTest +{ + char* name; + TestFunction function; + int failed; + int ran; + const char* message; + jmp_buf *jumpBuf; +}; + +void CuTestInit(CuTest* t, const char* name, TestFunction function); +CuTest* CuTestNew(const char* name, TestFunction function); +void CuTestRun(CuTest* tc); +void CuTestDelete(CuTest *t); + +/* Internal versions of assert functions -- use the public versions */ +void CuFail_Line(CuTest* tc, const char* file, int line, const char* message2, const char* message); +void CuAssert_Line(CuTest* tc, const char* file, int line, const char* message, int condition); +void CuAssertStrEquals_LineMsg(CuTest* tc, + const char* file, int line, const char* message, + const char* expected, const char* actual); +void CuAssertIntEquals_LineMsg(CuTest* tc, + const char* file, int line, const char* message, + int expected, int actual); +void CuAssertDblEquals_LineMsg(CuTest* tc, + const char* file, int line, const char* message, + double expected, double actual, double delta); +void CuAssertPtrEquals_LineMsg(CuTest* tc, + const char* file, int line, const char* message, + void* expected, void* actual); + +/* public assert functions */ + +#define CuFail(tc, ms) CuFail_Line( (tc), __FILE__, __LINE__, NULL, (ms)) +#define CuAssert(tc, ms, cond) CuAssert_Line((tc), __FILE__, __LINE__, (ms), (cond)) +#define CuAssertTrue(tc, cond) CuAssert_Line((tc), __FILE__, __LINE__, "assert failed", (cond)) + +#define CuAssertStrEquals(tc,ex,ac) CuAssertStrEquals_LineMsg((tc),__FILE__,__LINE__,NULL,(ex),(ac)) +#define CuAssertStrEquals_Msg(tc,ms,ex,ac) CuAssertStrEquals_LineMsg((tc),__FILE__,__LINE__,(ms),(ex),(ac)) +#define CuAssertIntEquals(tc,ex,ac) CuAssertIntEquals_LineMsg((tc),__FILE__,__LINE__,NULL,(ex),(ac)) +#define CuAssertIntEquals_Msg(tc,ms,ex,ac) CuAssertIntEquals_LineMsg((tc),__FILE__,__LINE__,(ms),(ex),(ac)) +#define CuAssertDblEquals(tc,ex,ac,dl) CuAssertDblEquals_LineMsg((tc),__FILE__,__LINE__,NULL,(ex),(ac),(dl)) +#define CuAssertDblEquals_Msg(tc,ms,ex,ac,dl) CuAssertDblEquals_LineMsg((tc),__FILE__,__LINE__,(ms),(ex),(ac),(dl)) +#define CuAssertPtrEquals(tc,ex,ac) CuAssertPtrEquals_LineMsg((tc),__FILE__,__LINE__,NULL,(ex),(ac)) +#define CuAssertPtrEquals_Msg(tc,ms,ex,ac) CuAssertPtrEquals_LineMsg((tc),__FILE__,__LINE__,(ms),(ex),(ac)) + +#define CuAssertPtrNotNull(tc,p) CuAssert_Line((tc),__FILE__,__LINE__,"null pointer unexpected",(p != NULL)) +#define CuAssertPtrNotNullMsg(tc,msg,p) CuAssert_Line((tc),__FILE__,__LINE__,(msg),(p != NULL)) + +/* CuSuite */ + +#define MAX_TEST_CASES 1024 + +#define SUITE_ADD_TEST(SUITE,TEST) CuSuiteAdd(SUITE, CuTestNew(#TEST, TEST)) + +typedef struct +{ + int count; + CuTest* list[MAX_TEST_CASES]; + int failCount; + +} CuSuite; + + +void CuSuiteInit(CuSuite* testSuite); +CuSuite* CuSuiteNew(void); +void CuSuiteDelete(CuSuite *testSuite); +void CuSuiteAdd(CuSuite* testSuite, CuTest *testCase); +void CuSuiteAddSuite(CuSuite* testSuite, CuSuite* testSuite2); +void CuSuiteRun(CuSuite* testSuite); +void CuSuiteSummary(CuSuite* testSuite, CuString* summary); +void CuSuiteDetails(CuSuite* testSuite, CuString* details); + +#endif /* CU_TEST_H */ diff --git a/cutest-1.5/CuTestTest.c b/cutest-1.5/CuTestTest.c new file mode 100644 index 0000000..547f119 --- /dev/null +++ b/cutest-1.5/CuTestTest.c @@ -0,0 +1,709 @@ +#include +#include +#include +#include +#include + +#include "CuTest.h" + +/*-------------------------------------------------------------------------* + * Helper functions + *-------------------------------------------------------------------------*/ + +#define CompareAsserts(tc, message, expected, actual) X_CompareAsserts((tc), __FILE__, __LINE__, (message), (expected), (actual)) + +static void X_CompareAsserts(CuTest* tc, const char *file, int line, const char* message, const char* expected, const char* actual) +{ + int mismatch; + if (expected == NULL || actual == NULL) { + mismatch = (expected != NULL || actual != NULL); + } else { + const char *front = __FILE__ ":"; + const size_t frontLen = strlen(front); + const size_t expectedLen = strlen(expected); + + const char *matchStr = actual; + + mismatch = (strncmp(matchStr, front, frontLen) != 0); + if (!mismatch) { + matchStr = strchr(matchStr + frontLen, ':'); + mismatch |= (matchStr == NULL || strncmp(matchStr, ": ", 2)); + if (!mismatch) { + matchStr += 2; + mismatch |= (strncmp(matchStr, expected, expectedLen) != 0); + } + } + } + + CuAssert_Line(tc, file, line, message, !mismatch); +} + +/*-------------------------------------------------------------------------* + * CuString Test + *-------------------------------------------------------------------------*/ + +void TestCuStringNew(CuTest* tc) +{ + CuString* str = CuStringNew(); + CuAssertTrue(tc, 0 == str->length); + CuAssertTrue(tc, 0 != str->size); + CuAssertStrEquals(tc, "", str->buffer); +} + + +void TestCuStringAppend(CuTest* tc) +{ + CuString* str = CuStringNew(); + CuStringAppend(str, "hello"); + CuAssertIntEquals(tc, 5, str->length); + CuAssertStrEquals(tc, "hello", str->buffer); + CuStringAppend(str, " world"); + CuAssertIntEquals(tc, 11, str->length); + CuAssertStrEquals(tc, "hello world", str->buffer); +} + + +void TestCuStringAppendNULL(CuTest* tc) +{ + CuString* str = CuStringNew(); + CuStringAppend(str, NULL); + CuAssertIntEquals(tc, 4, str->length); + CuAssertStrEquals(tc, "NULL", str->buffer); +} + + +void TestCuStringAppendChar(CuTest* tc) +{ + CuString* str = CuStringNew(); + CuStringAppendChar(str, 'a'); + CuStringAppendChar(str, 'b'); + CuStringAppendChar(str, 'c'); + CuStringAppendChar(str, 'd'); + CuAssertIntEquals(tc, 4, str->length); + CuAssertStrEquals(tc, "abcd", str->buffer); +} + + +void TestCuStringInserts(CuTest* tc) +{ + CuString* str = CuStringNew(); + CuStringAppend(str, "world"); + CuAssertIntEquals(tc, 5, str->length); + CuAssertStrEquals(tc, "world", str->buffer); + CuStringInsert(str, "hell", 0); + CuAssertIntEquals(tc, 9, str->length); + CuAssertStrEquals(tc, "hellworld", str->buffer); + CuStringInsert(str, "o ", 4); + CuAssertIntEquals(tc, 11, str->length); + CuAssertStrEquals(tc, "hello world", str->buffer); + CuStringInsert(str, "!", 11); + CuAssertIntEquals(tc, 12, str->length); + CuAssertStrEquals(tc, "hello world!", str->buffer); +} + + +void TestCuStringResizes(CuTest* tc) +{ + CuString* str = CuStringNew(); + int i; + for(i = 0 ; i < STRING_MAX ; ++i) + { + CuStringAppend(str, "aa"); + } + CuAssertTrue(tc, STRING_MAX * 2 == str->length); + CuAssertTrue(tc, STRING_MAX * 2 <= str->size); +} + +CuSuite* CuStringGetSuite(void) +{ + CuSuite* suite = CuSuiteNew(); + + SUITE_ADD_TEST(suite, TestCuStringNew); + SUITE_ADD_TEST(suite, TestCuStringAppend); + SUITE_ADD_TEST(suite, TestCuStringAppendNULL); + SUITE_ADD_TEST(suite, TestCuStringAppendChar); + SUITE_ADD_TEST(suite, TestCuStringInserts); + SUITE_ADD_TEST(suite, TestCuStringResizes); + + return suite; +} + +/*-------------------------------------------------------------------------* + * CuTest Test + *-------------------------------------------------------------------------*/ + +void TestPasses(CuTest* tc) +{ + CuAssert(tc, "test should pass", 1 == 0 + 1); +} + +void zTestFails(CuTest* tc) +{ + CuAssert(tc, "test should fail", 1 == 1 + 1); +} + + +void TestCuTestNew(CuTest* tc) +{ + CuTest* tc2 = CuTestNew("MyTest", TestPasses); + CuAssertStrEquals(tc, "MyTest", tc2->name); + CuAssertTrue(tc, !tc2->failed); + CuAssertTrue(tc, tc2->message == NULL); + CuAssertTrue(tc, tc2->function == TestPasses); + CuAssertTrue(tc, tc2->ran == 0); + CuAssertTrue(tc, tc2->jumpBuf == NULL); +} + + +void TestCuTestInit(CuTest *tc) +{ + CuTest tc2; + CuTestInit(&tc2, "MyTest", TestPasses); + CuAssertStrEquals(tc, "MyTest", tc2.name); + CuAssertTrue(tc, !tc2.failed); + CuAssertTrue(tc, tc2.message == NULL); + CuAssertTrue(tc, tc2.function == TestPasses); + CuAssertTrue(tc, tc2.ran == 0); + CuAssertTrue(tc, tc2.jumpBuf == NULL); +} + +void TestCuAssert(CuTest* tc) +{ + CuTest tc2; + CuTestInit(&tc2, "MyTest", TestPasses); + + CuAssert(&tc2, "test 1", 5 == 4 + 1); + CuAssertTrue(tc, !tc2.failed); + CuAssertTrue(tc, tc2.message == NULL); + + CuAssert(&tc2, "test 2", 0); + CuAssertTrue(tc, tc2.failed); + CompareAsserts(tc, "CuAssert didn't fail", "test 2", tc2.message); + + CuAssert(&tc2, "test 3", 1); + CuAssertTrue(tc, tc2.failed); + CompareAsserts(tc, "CuAssert didn't fail", "test 2", tc2.message); + + CuAssert(&tc2, "test 4", 0); + CuAssertTrue(tc, tc2.failed); + CompareAsserts(tc, "CuAssert didn't fail", "test 4", tc2.message); + +} + +void TestCuAssertPtrEquals_Success(CuTest* tc) +{ + CuTest tc2; + int x; + + CuTestInit(&tc2, "MyTest", TestPasses); + + /* test success case */ + CuAssertPtrEquals(&tc2, &x, &x); + CuAssertTrue(tc, ! tc2.failed); + CuAssertTrue(tc, NULL == tc2.message); +} + +void TestCuAssertPtrEquals_Failure(CuTest* tc) +{ + CuTest tc2; + int x; + int* nullPtr = NULL; + char expected_message[STRING_MAX]; + + CuTestInit(&tc2, "MyTest", TestPasses); + + /* test failing case */ + sprintf(expected_message, "expected pointer <0x%p> but was <0x%p>", nullPtr, &x); + CuAssertPtrEquals(&tc2, NULL, &x); + CuAssertTrue(tc, tc2.failed); + CompareAsserts(tc, "CuAssertPtrEquals failed", expected_message, tc2.message); +} + +void TestCuAssertPtrNotNull_Success(CuTest* tc) +{ + CuTest tc2; + int x; + + CuTestInit(&tc2, "MyTest", TestPasses); + + /* test success case */ + CuAssertPtrNotNull(&tc2, &x); + CuAssertTrue(tc, ! tc2.failed); + CuAssertTrue(tc, NULL == tc2.message); +} + +void TestCuAssertPtrNotNull_Failure(CuTest* tc) +{ + CuTest tc2; + + CuTestInit(&tc2, "MyTest", TestPasses); + + /* test failing case */ + CuAssertPtrNotNull(&tc2, NULL); + CuAssertTrue(tc, tc2.failed); + CompareAsserts(tc, "CuAssertPtrNotNull failed", "null pointer unexpected", tc2.message); +} + +void TestCuTestRun(CuTest* tc) +{ + CuTest tc2; + CuTestInit(&tc2, "MyTest", zTestFails); + CuTestRun(&tc2); + + CuAssertStrEquals(tc, "MyTest", tc2.name); + CuAssertTrue(tc, tc2.failed); + CuAssertTrue(tc, tc2.ran); + CompareAsserts(tc, "TestRun failed", "test should fail", tc2.message); +} + +/*-------------------------------------------------------------------------* + * CuSuite Test + *-------------------------------------------------------------------------*/ + +void TestCuSuiteInit(CuTest* tc) +{ + CuSuite ts; + CuSuiteInit(&ts); + CuAssertTrue(tc, ts.count == 0); + CuAssertTrue(tc, ts.failCount == 0); +} + +void TestCuSuiteNew(CuTest* tc) +{ + CuSuite* ts = CuSuiteNew(); + CuAssertTrue(tc, ts->count == 0); + CuAssertTrue(tc, ts->failCount == 0); +} + +void TestCuSuiteAddTest(CuTest* tc) +{ + CuSuite ts; + CuTest tc2; + + CuSuiteInit(&ts); + CuTestInit(&tc2, "MyTest", zTestFails); + + CuSuiteAdd(&ts, &tc2); + CuAssertTrue(tc, ts.count == 1); + + CuAssertStrEquals(tc, "MyTest", ts.list[0]->name); +} + +void TestCuSuiteAddSuite(CuTest* tc) +{ + CuSuite* ts1 = CuSuiteNew(); + CuSuite* ts2 = CuSuiteNew(); + + CuSuiteAdd(ts1, CuTestNew("TestFails1", zTestFails)); + CuSuiteAdd(ts1, CuTestNew("TestFails2", zTestFails)); + + CuSuiteAdd(ts2, CuTestNew("TestFails3", zTestFails)); + CuSuiteAdd(ts2, CuTestNew("TestFails4", zTestFails)); + + CuSuiteAddSuite(ts1, ts2); + CuAssertIntEquals(tc, 4, ts1->count); + + CuAssertStrEquals(tc, "TestFails1", ts1->list[0]->name); + CuAssertStrEquals(tc, "TestFails2", ts1->list[1]->name); + CuAssertStrEquals(tc, "TestFails3", ts1->list[2]->name); + CuAssertStrEquals(tc, "TestFails4", ts1->list[3]->name); +} + +void TestCuSuiteRun(CuTest* tc) +{ + CuSuite ts; + CuTest tc1, tc2, tc3, tc4; + + CuSuiteInit(&ts); + CuTestInit(&tc1, "TestPasses", TestPasses); + CuTestInit(&tc2, "TestPasses", TestPasses); + CuTestInit(&tc3, "TestFails", zTestFails); + CuTestInit(&tc4, "TestFails", zTestFails); + + CuSuiteAdd(&ts, &tc1); + CuSuiteAdd(&ts, &tc2); + CuSuiteAdd(&ts, &tc3); + CuSuiteAdd(&ts, &tc4); + CuAssertTrue(tc, ts.count == 4); + + CuSuiteRun(&ts); + CuAssertTrue(tc, ts.count - ts.failCount == 2); + CuAssertTrue(tc, ts.failCount == 2); +} + +void TestCuSuiteSummary(CuTest* tc) +{ + CuSuite ts; + CuTest tc1, tc2; + CuString summary; + + CuSuiteInit(&ts); + CuTestInit(&tc1, "TestPasses", TestPasses); + CuTestInit(&tc2, "TestFails", zTestFails); + CuStringInit(&summary); + + CuSuiteAdd(&ts, &tc1); + CuSuiteAdd(&ts, &tc2); + CuSuiteRun(&ts); + + CuSuiteSummary(&ts, &summary); + + CuAssertTrue(tc, ts.count == 2); + CuAssertTrue(tc, ts.failCount == 1); + CuAssertStrEquals(tc, ".F\n\n", summary.buffer); +} + + +void TestCuSuiteDetails_SingleFail(CuTest* tc) +{ + CuSuite ts; + CuTest tc1, tc2; + CuString details; + const char* front; + const char* back; + + CuSuiteInit(&ts); + CuTestInit(&tc1, "TestPasses", TestPasses); + CuTestInit(&tc2, "TestFails", zTestFails); + CuStringInit(&details); + + CuSuiteAdd(&ts, &tc1); + CuSuiteAdd(&ts, &tc2); + CuSuiteRun(&ts); + + CuSuiteDetails(&ts, &details); + + CuAssertTrue(tc, ts.count == 2); + CuAssertTrue(tc, ts.failCount == 1); + + front = "There was 1 failure:\n" + "1) TestFails: "; + back = "test should fail\n" + "\n!!!FAILURES!!!\n" + "Runs: 2 Passes: 1 Fails: 1\n"; + + CuAssertStrEquals(tc, back, details.buffer + strlen(details.buffer) - strlen(back)); + details.buffer[strlen(front)] = 0; + CuAssertStrEquals(tc, front, details.buffer); +} + + +void TestCuSuiteDetails_SinglePass(CuTest* tc) +{ + CuSuite ts; + CuTest tc1; + CuString details; + const char* expected; + + CuSuiteInit(&ts); + CuTestInit(&tc1, "TestPasses", TestPasses); + CuStringInit(&details); + + CuSuiteAdd(&ts, &tc1); + CuSuiteRun(&ts); + + CuSuiteDetails(&ts, &details); + + CuAssertTrue(tc, ts.count == 1); + CuAssertTrue(tc, ts.failCount == 0); + + expected = + "OK (1 test)\n"; + + CuAssertStrEquals(tc, expected, details.buffer); +} + +void TestCuSuiteDetails_MultiplePasses(CuTest* tc) +{ + CuSuite ts; + CuTest tc1, tc2; + CuString details; + const char* expected; + + CuSuiteInit(&ts); + CuTestInit(&tc1, "TestPasses", TestPasses); + CuTestInit(&tc2, "TestPasses", TestPasses); + CuStringInit(&details); + + CuSuiteAdd(&ts, &tc1); + CuSuiteAdd(&ts, &tc2); + CuSuiteRun(&ts); + + CuSuiteDetails(&ts, &details); + + CuAssertTrue(tc, ts.count == 2); + CuAssertTrue(tc, ts.failCount == 0); + + expected = + "OK (2 tests)\n"; + + CuAssertStrEquals(tc, expected, details.buffer); +} + +void TestCuSuiteDetails_MultipleFails(CuTest* tc) +{ + CuSuite ts; + CuTest tc1, tc2; + CuString details; + const char* front; + const char* mid; + const char* back; + + CuSuiteInit(&ts); + CuTestInit(&tc1, "TestFails1", zTestFails); + CuTestInit(&tc2, "TestFails2", zTestFails); + CuStringInit(&details); + + CuSuiteAdd(&ts, &tc1); + CuSuiteAdd(&ts, &tc2); + CuSuiteRun(&ts); + + CuSuiteDetails(&ts, &details); + + CuAssertTrue(tc, ts.count == 2); + CuAssertTrue(tc, ts.failCount == 2); + + front = + "There were 2 failures:\n" + "1) TestFails1: "; + mid = "test should fail\n" + "2) TestFails2: "; + back = "test should fail\n" + "\n!!!FAILURES!!!\n" + "Runs: 2 Passes: 0 Fails: 2\n"; + + CuAssertStrEquals(tc, back, details.buffer + strlen(details.buffer) - strlen(back)); + CuAssert(tc, "Couldn't find middle", strstr(details.buffer, mid) != NULL); + details.buffer[strlen(front)] = 0; + CuAssertStrEquals(tc, front, details.buffer); +} + + +/*-------------------------------------------------------------------------* + * Misc Test + *-------------------------------------------------------------------------*/ + +void TestCuStrCopy(CuTest* tc) +{ + const char* old = "hello world"; + const char* newStr = CuStrCopy(old); + CuAssert(tc, "old is new", strcmp(old, newStr) == 0); +} + + +void TestCuStringAppendFormat(CuTest* tc) +{ + int i; + char* text = CuStrAlloc(301); /* long string */ + CuString* str = CuStringNew(); + for (i = 0 ; i < 300 ; ++i) + text[i] = 'a'; + text[300] = '\0'; + CuStringAppendFormat(str, "%s", text); + + /* buffer limit raised to HUGE_STRING_LEN so no overflow */ + + CuAssert(tc, "length of str->buffer is 300", 300 == strlen(str->buffer)); +} + +void TestFail(CuTest* tc) +{ + jmp_buf buf; + int pointReached = 0; + CuTest* tc2 = CuTestNew("TestFails", zTestFails); + tc2->jumpBuf = &buf; + if (setjmp(buf) == 0) + { + CuFail(tc2, "hello world"); + pointReached = 1; + } + CuAssert(tc, "point was not reached", pointReached == 0); +} + +void TestAssertStrEquals(CuTest* tc) +{ + jmp_buf buf; + CuTest *tc2 = CuTestNew("TestAssertStrEquals", zTestFails); + + const char* expected = "expected but was "; + const char *expectedMsg = "some text: expected but was "; + + tc2->jumpBuf = &buf; + if (setjmp(buf) == 0) + { + CuAssertStrEquals(tc2, "hello", "world"); + } + CuAssertTrue(tc, tc2->failed); + CompareAsserts(tc, "CuAssertStrEquals failed", expected, tc2->message); + if (setjmp(buf) == 0) + { + CuAssertStrEquals_Msg(tc2, "some text", "hello", "world"); + } + CuAssertTrue(tc, tc2->failed); + CompareAsserts(tc, "CuAssertStrEquals failed", expectedMsg, tc2->message); +} + +void TestAssertStrEquals_NULL(CuTest* tc) +{ + jmp_buf buf; + CuTest *tc2 = CuTestNew("TestAssertStrEquals_NULL", zTestFails); + + tc2->jumpBuf = &buf; + if (setjmp(buf) == 0) + { + CuAssertStrEquals(tc2, NULL, NULL); + } + CuAssertTrue(tc, !tc2->failed); + CompareAsserts(tc, "CuAssertStrEquals_NULL failed", NULL, tc2->message); + if (setjmp(buf) == 0) + { + CuAssertStrEquals_Msg(tc2, "some text", NULL, NULL); + } + CuAssertTrue(tc, !tc2->failed); + CompareAsserts(tc, "CuAssertStrEquals_NULL failed", NULL, tc2->message); +} + +void TestAssertStrEquals_FailNULLStr(CuTest* tc) +{ + jmp_buf buf; + CuTest *tc2 = CuTestNew("TestAssertStrEquals_FailNULLStr", zTestFails); + + const char* expected = "expected but was "; + const char *expectedMsg = "some text: expected but was "; + + tc2->jumpBuf = &buf; + if (setjmp(buf) == 0) + { + CuAssertStrEquals(tc2, "hello", NULL); + } + CuAssertTrue(tc, tc2->failed); + CompareAsserts(tc, "CuAssertStrEquals_FailNULLStr failed", expected, tc2->message); + if (setjmp(buf) == 0) + { + CuAssertStrEquals_Msg(tc2, "some text", "hello", NULL); + } + CuAssertTrue(tc, tc2->failed); + CompareAsserts(tc, "CuAssertStrEquals_FailNULLStr failed", expectedMsg, tc2->message); +} + +void TestAssertStrEquals_FailStrNULL(CuTest* tc) +{ + jmp_buf buf; + CuTest *tc2 = CuTestNew("TestAssertStrEquals_FailStrNULL", zTestFails); + + const char* expected = "expected but was "; + const char *expectedMsg = "some text: expected but was "; + + tc2->jumpBuf = &buf; + if (setjmp(buf) == 0) + { + CuAssertStrEquals(tc2, NULL, "hello"); + } + CuAssertTrue(tc, tc2->failed); + CompareAsserts(tc, "CuAssertStrEquals_FailStrNULL failed", expected, tc2->message); + if (setjmp(buf) == 0) + { + CuAssertStrEquals_Msg(tc2, "some text", NULL, "hello"); + } + CuAssertTrue(tc, tc2->failed); + CompareAsserts(tc, "CuAssertStrEquals_FailStrNULL failed", expectedMsg, tc2->message); +} + +void TestAssertIntEquals(CuTest* tc) +{ + jmp_buf buf; + CuTest *tc2 = CuTestNew("TestAssertIntEquals", zTestFails); + const char* expected = "expected <42> but was <32>"; + const char* expectedMsg = "some text: expected <42> but was <32>"; + tc2->jumpBuf = &buf; + if (setjmp(buf) == 0) + { + CuAssertIntEquals(tc2, 42, 32); + } + CuAssertTrue(tc, tc2->failed); + CompareAsserts(tc, "CuAssertIntEquals failed", expected, tc2->message); + if (setjmp(buf) == 0) + { + CuAssertIntEquals_Msg(tc2, "some text", 42, 32); + } + CuAssertTrue(tc, tc2->failed); + CompareAsserts(tc, "CuAssertStrEquals failed", expectedMsg, tc2->message); +} + +void TestAssertDblEquals(CuTest* tc) +{ + jmp_buf buf; + double x = 3.33; + double y = 10.0 / 3.0; + CuTest *tc2 = CuTestNew("TestAssertDblEquals", zTestFails); + char expected[STRING_MAX]; + char expectedMsg[STRING_MAX]; + sprintf(expected, "expected <%lf> but was <%lf>", x, y); + sprintf(expectedMsg, "some text: expected <%lf> but was <%lf>", x, y); + + CuTestInit(tc2, "TestAssertDblEquals", TestPasses); + + CuAssertDblEquals(tc2, x, x, 0.0); + CuAssertTrue(tc, ! tc2->failed); + CuAssertTrue(tc, NULL == tc2->message); + + CuAssertDblEquals(tc2, x, y, 0.01); + CuAssertTrue(tc, ! tc2->failed); + CuAssertTrue(tc, NULL == tc2->message); + + tc2->jumpBuf = &buf; + if (setjmp(buf) == 0) + { + CuAssertDblEquals(tc2, x, y, 0.001); + } + CuAssertTrue(tc, tc2->failed); + CompareAsserts(tc, "CuAssertDblEquals failed", expected, tc2->message); + tc2->jumpBuf = &buf; + if (setjmp(buf) == 0) + { + CuAssertDblEquals_Msg(tc2, "some text", x, y, 0.001); + } + CuAssertTrue(tc, tc2->failed); + CompareAsserts(tc, "CuAssertDblEquals failed", expectedMsg, tc2->message); +} + +/*-------------------------------------------------------------------------* + * main + *-------------------------------------------------------------------------*/ + +CuSuite* CuGetSuite(void) +{ + CuSuite* suite = CuSuiteNew(); + + SUITE_ADD_TEST(suite, TestCuStringAppendFormat); + SUITE_ADD_TEST(suite, TestCuStrCopy); + SUITE_ADD_TEST(suite, TestFail); + SUITE_ADD_TEST(suite, TestAssertStrEquals); + SUITE_ADD_TEST(suite, TestAssertStrEquals_NULL); + SUITE_ADD_TEST(suite, TestAssertStrEquals_FailStrNULL); + SUITE_ADD_TEST(suite, TestAssertStrEquals_FailNULLStr); + SUITE_ADD_TEST(suite, TestAssertIntEquals); + SUITE_ADD_TEST(suite, TestAssertDblEquals); + + SUITE_ADD_TEST(suite, TestCuTestNew); + SUITE_ADD_TEST(suite, TestCuTestInit); + SUITE_ADD_TEST(suite, TestCuAssert); + SUITE_ADD_TEST(suite, TestCuAssertPtrEquals_Success); + SUITE_ADD_TEST(suite, TestCuAssertPtrEquals_Failure); + SUITE_ADD_TEST(suite, TestCuAssertPtrNotNull_Success); + SUITE_ADD_TEST(suite, TestCuAssertPtrNotNull_Failure); + SUITE_ADD_TEST(suite, TestCuTestRun); + + SUITE_ADD_TEST(suite, TestCuSuiteInit); + SUITE_ADD_TEST(suite, TestCuSuiteNew); + SUITE_ADD_TEST(suite, TestCuSuiteAddTest); + SUITE_ADD_TEST(suite, TestCuSuiteAddSuite); + SUITE_ADD_TEST(suite, TestCuSuiteRun); + SUITE_ADD_TEST(suite, TestCuSuiteSummary); + SUITE_ADD_TEST(suite, TestCuSuiteDetails_SingleFail); + SUITE_ADD_TEST(suite, TestCuSuiteDetails_SinglePass); + SUITE_ADD_TEST(suite, TestCuSuiteDetails_MultiplePasses); + SUITE_ADD_TEST(suite, TestCuSuiteDetails_MultipleFails); + + return suite; +} diff --git a/cutest-1.5/README.txt b/cutest-1.5/README.txt new file mode 100644 index 0000000..12b9796 --- /dev/null +++ b/cutest-1.5/README.txt @@ -0,0 +1,211 @@ +HOW TO USE + +You can use CuTest to create unit tests to drive your development +in the style of Extreme Programming. You can also add unit tests to +existing code to ensure that it works as you suspect. + +Your unit tests are an investment. They let you to change your +code and add new features confidently without worrying about +accidentally breaking earlier features. + + +LICENSING + +For details on licensing see license.txt. + + +GETTING STARTED + +To add unit testing to your C code the only files you need are +CuTest.c and CuTest.h. + +CuTestTest.c and AllTests.c have been included to provide an +example of how to write unit tests and then how to aggregate them +into suites and into a single AllTests.c file. Suites allow you +to put group tests into logical sets. AllTests.c combines all the +suites and runs them. + +You should not have to look inside CuTest.c. Looking in +CuTestTest.c and AllTests.c (for example usage) should be +sufficient. + +After downloading the sources, run your compiler to create an +executable called AllTests.exe. For example, if you are using +Windows with the cl.exe compiler you would type: + + cl.exe AllTests.c CuTest.c CuTestTest.c + AllTests.exe + +This will run all the unit tests associated with CuTest and print +the output on the console. You can replace cl.exe with gcc or +your favorite compiler in the command above. + + +DETAILED EXAMPLE + +Here is a more detailed example. We will work through a simple +test first exercise. The goal is to create a library of string +utilities. First, lets write a function that converts a +null-terminated string to all upper case. + +Ensure that CuTest.c and CuTest.h are accessible from your C +project. Next, create a file called StrUtil.c with these +contents: + + #include "CuTest.h" + + char* StrToUpper(char* str) { + return str; + } + + void TestStrToUpper(CuTest *tc) { + char* input = strdup("hello world"); + char* actual = StrToUpper(input); + char* expected = "HELLO WORLD"; + CuAssertStrEquals(tc, expected, actual); + } + + CuSuite* StrUtilGetSuite() { + CuSuite* suite = CuSuiteNew(); + SUITE_ADD_TEST(suite, TestStrToUpper); + return suite; + } + +Create another file called AllTests.c with these contents: + + #include "CuTest.h" + + CuSuite* StrUtilGetSuite(); + + void RunAllTests(void) { + CuString *output = CuStringNew(); + CuSuite* suite = CuSuiteNew(); + + CuSuiteAddSuite(suite, StrUtilGetSuite()); + + CuSuiteRun(suite); + CuSuiteSummary(suite, output); + CuSuiteDetails(suite, output); + printf("%s\n", output->buffer); + } + + int main(void) { + RunAllTests(); + } + +Then type this on the command line: + + gcc AllTests.c CuTest.c StrUtil.c + +to compile. You can replace gcc with your favorite compiler. +CuTest should be portable enough to handle all Windows and Unix +compilers. Then to run the tests type: + + a.out + +This will print an error because we haven't implemented the +StrToUpper function correctly. We are just returning the string +without changing it to upper case. + + char* StrToUpper(char* str) { + return str; + } + +Rewrite this as follows: + + char* StrToUpper(char* str) { + char* p; + for (p = str ; *p ; ++p) *p = toupper(*p); + return str; + } + +Recompile and run the tests again. The test should pass this +time. + + +WHAT TO DO NEXT + +At this point you might want to write more tests for the +StrToUpper function. Here are some ideas: + +TestStrToUpper_EmptyString : pass in "" +TestStrToUpper_UpperCase : pass in "HELLO WORLD" +TestStrToUpper_MixedCase : pass in "HELLO world" +TestStrToUpper_Numbers : pass in "1234 hello" + +As you write each one of these tests add it to StrUtilGetSuite +function. If you don't the tests won't be run. Later as you write +other functions and write tests for them be sure to include those +in StrUtilGetSuite also. The StrUtilGetSuite function should +include all the tests in StrUtil.c + +Over time you will create another file called FunkyStuff.c +containing other functions unrelated to StrUtil. Follow the same +pattern. Create a FunkyStuffGetSuite function in FunkyStuff.c. +And add FunkyStuffGetSuite to AllTests.c. + +The framework is designed in the way it is so that it is easy to +organize a lot of tests. + +THE BIG PICTURE + +Each individual test corresponds to a CuTest. These are grouped +to form a CuSuite. CuSuites can hold CuTests or other CuSuites. +AllTests.c collects all the CuSuites in the program into a single +CuSuite which it then runs as a single CuSuite. + +The project is open source so feel free to take a peek under the +hood at the CuTest.c file to see how it works. CuTestTest.c +contains tests for CuTest.c. So CuTest tests itself. + +Since AllTests.c has a main() you will need to exclude this when +you are building your product. Here is a nicer way to do this if +you want to avoid messing with multiple builds. Remove the main() +in AllTests.c. Note that it just calls RunAllTests(). Instead +we'll call this directly from the main program. + +Now in the main() of the actual program check to see if the +command line option "--test" was passed. If it was then I call +RunAllTests() from AllTests.c. Otherwise run the real program. + +Shipping the tests with the code can be useful. If you customers +complain about a problem you can ask them to run the unit tests +and send you the output. This can help you to quickly isolate the +piece of your system that is malfunctioning in the customer's +environment. + +CuTest offers a rich set of CuAssert functions. Here is a list: + +void CuAssert(CuTest* tc, char* message, int condition); +void CuAssertTrue(CuTest* tc, int condition); +void CuAssertStrEquals(CuTest* tc, char* expected, char* actual); +void CuAssertIntEquals(CuTest* tc, int expected, int actual); +void CuAssertPtrEquals(CuTest* tc, void* expected, void* actual); +void CuAssertPtrNotNull(CuTest* tc, void* pointer); + +The project is open source and so you can add other more powerful +asserts to make your tests easier to write and more concise. +Please feel free to send me changes you make so that I can +incorporate them into future releases. + +If you see any errors in this document please contact me at +asimjalis@peakprogramming.com. + + +AUTOMATING TEST SUITE GENERATION + +make-tests.sh will grep through all the .c files in the current +directory and generate the code to run all the tests contained in +them. Using this script you don't have to worry about writing +AllTests.c or dealing with any of the other suite code. + + +CREDITS + +These people have contributed useful code changes to the CuTest project. +Thanks! + +- [02.23.2003] Dave Glowacki +- [04.17.2009] Tobias Lippert +- [11.13.2009] Eli Bendersky +- [12.14.2009] Andrew Brown diff --git a/cutest-1.5/index.html b/cutest-1.5/index.html new file mode 100644 index 0000000..f8c9a42 --- /dev/null +++ b/cutest-1.5/index.html @@ -0,0 +1,196 @@ + + + + + +CuTest: The Cutest C Unit Testing Framework + + + + + + + +
+
+
+ +[ + Download Now +| Download Statistics +| Browse Source +| SourceForge +| Blog +| asimjalis(nospam)gmail.com +] + +
+ + +

CuTest: C Unit Testing Framework

+ + +

Overview

+ +CuTest is a unit testing library for the C language. It can be +used to do Extreme Programming and Test-First Development in the +C language. It's a fun and cute library that will make your +programming fun and productive. + +

Benefits

+ +
    + +
  • Lower Defects. The tests ensure that your code keeps working +as you make small changes in it. + +
  • Faster Debugging. The tests tell you which subroutine is +broken. You avoid spending hours trying to figure out what's +broken. + +
  • Development Speed. You trust your old code and can keep +adding to it without worrying about bad interactions. If there is +a bad interaction the tests will catch it. + +
  • Permanent Bug Fixes. If every time a bug is reported you +write a quick test, you will guarantee that the bug never +reappears again. + +
  • Fun. As your bug count drops you will begin to enjoy +programming like you've never done before. Running the tests +every few minutes and seeing them pass feels good. + +
+ +

Features

+ +
    + +
  • Small. Consists of a single .c and .h file. + +
  • Easy to Deploy. Just drop the two files into your source +tree. + +
  • Highly Portable. Works with all major compilers on Windows +(Microsoft, Borland), Linux, Unix, PalmOS. + +
  • Open Source. You can extend it to add more functionality. +The source can be invaluable if you are trying to trace a test +failure. + +
  • Cuteness. Of all the testing frameworks CuTest has the +cutest name :-) + +
+ + +

Licensing

+ +CuTest is distributed under the zlib/libpng +license. See license.txt in the distribution for text of license. The +intent of the license is to: + +
    + +
  • Keep the license as simple as possible +
  • Encourage the use of CuTest in both free and commercial applications and libraries +
  • Keep the source code together +
  • Give credit to the CuTest contributors for their work + +
+ +If you find CuTest useful we would like to hear about it. + + +

Getting Started

+ +

For a detailed tutorial see README in the distribution. This shows you how +to organize your tests and how to autogenerate the AllTests.c file from your +source files. + +

To add unit testing to your C code the only files you need +are CuTest.c and CuTest.h. + +

CuTestTest.c and AllTests.c have been included to provide an +example of how to write unit tests and then how to aggregate them +into suites and into a single AllTests.c file. Suites allow you +to put unit tests for different parts of your code in different +files. AllTests.c combines all the suites and runs them. + +

You should not have to look inside CuTest.c. Looking in +CuTestTest.c (for example usage) should be sufficient. + +

After downloading the sources, run your compiler to create an +executable called AllTests.exe. For example, if you are using +Windows you would type: + +

+cl AllTests.c CuTest.c CuTestTest.c
+AllTests.exe
+
+ +

This will run all the unit tests associated with CuTest and +print the output on the console. + +

For more details on how to use the library look at the README file included +with the distribution. + +

Contribute

+ +

We hope you CuTest saves you time and helps you produce high quality +software. + +

If you find CuTest useful, let us know. Tell us what platform you are using +it on (Windows, Linux, etc), and what kinds of applications you are using it +with. + +

If you would like to contribute documentation or tutorials to this project +please send e-mail. + +
+
+ +


+ +Copyright © 2002-2003, Asim Jalis (asimjalis(nospam)gmail.com). +All rights reserved. + + + + +

+SourceForge.net Logo + + + diff --git a/cutest-1.5/license.txt b/cutest-1.5/license.txt new file mode 100644 index 0000000..5f053ba --- /dev/null +++ b/cutest-1.5/license.txt @@ -0,0 +1,38 @@ +NOTE + +The license is based on the zlib/libpng license. For more details see +http://www.opensource.org/licenses/zlib-license.html. The intent of the +license is to: + +- keep the license as simple as possible +- encourage the use of CuTest in both free and commercial applications + and libraries +- keep the source code together +- give credit to the CuTest contributors for their work + +If you ship CuTest in source form with your source distribution, the +following license document must be included with it in unaltered form. +If you find CuTest useful we would like to hear about it. + +LICENSE + +Copyright (c) 2003 Asim Jalis + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any damages +arising from the use of this software. + +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it +freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not +claim that you wrote the original software. If you use this software in +a product, an acknowledgment in the product documentation would be +appreciated but is not required. + +2. Altered source versions must be plainly marked as such, and must not +be misrepresented as being the original software. + +3. This notice may not be removed or altered from any source +distribution. diff --git a/cutest-1.5/make-tests.sh b/cutest-1.5/make-tests.sh new file mode 100644 index 0000000..3988c5e --- /dev/null +++ b/cutest-1.5/make-tests.sh @@ -0,0 +1,55 @@ +#!/usr/bin/env bash + +# Auto generate single AllTests file for CuTest. +# Searches through all *.c files in the current directory. +# Prints to stdout. +# Author: Asim Jalis +# Date: 01/08/2003 + +if test $# -eq 0 ; then FILES=*.c ; else FILES=$* ; fi + +echo ' + +/* This is auto-generated code. Edit at your own peril. */ +#include +#include + +#include "CuTest.h" + +' + +cat $FILES | grep '^void Test' | + sed -e 's/(.*$//' \ + -e 's/$/(CuTest*);/' \ + -e 's/^/extern /' + +echo \ +' + +void RunAllTests(void) +{ + CuString *output = CuStringNew(); + CuSuite* suite = CuSuiteNew(); + +' +cat $FILES | grep '^void Test' | + sed -e 's/^void //' \ + -e 's/(.*$//' \ + -e 's/^/ SUITE_ADD_TEST(suite, /' \ + -e 's/$/);/' + +echo \ +' + CuSuiteRun(suite); + CuSuiteSummary(suite, output); + CuSuiteDetails(suite, output); + printf("%s\n", output->buffer); + CuStringDelete(output); + CuSuiteDelete(suite); +} + +int main(void) +{ + RunAllTests(); +} +' diff --git a/cutest-1.5/style.css b/cutest-1.5/style.css new file mode 100644 index 0000000..7759d5a --- /dev/null +++ b/cutest-1.5/style.css @@ -0,0 +1,21 @@ +BODY { + font-family: "Verdana,Arial,sans-serif"; + font-size: 10pt; +} +PRE.LIST { + background: #CFD9FF; + border: 1ex solid #AAAAE6; + padding: 1ex; +} + +PRE.SNIP { + background: #CFD9FF; + padding: 1ex; +} + +PRE.CONSOLE { + color: #CCCCCC; + background: #000000; + font-family: "Courier New,Courier"; + padding: 1ex; +} diff --git a/game.c b/game.c index 469228c..e3e602c 100644 --- a/game.c +++ b/game.c @@ -17,6 +17,7 @@ #include "movement.h" #include "combat.h" #include "game.h" +#include "spawn.h" // TODO: centralize these outside of game.c struct CompiledSpriteRender rabbit, @@ -49,17 +50,6 @@ struct BulletPosition enemyBulletPosition[ENEMY_BULLET_LIMIT]; struct RabbitWeaponry rabbitWeaponry; struct PlayerPowerup playerPowerup; -struct SpawnPointRange spawnPointRanges[4] = { - // top - { .left = TILE_SIZE * 4, .width = TILE_SIZE * 2, .top = TILE_SIZE - 8, .height = TILE_SIZE }, - // right - { .left = (ARENA_WIDTH_TILES - 1) * TILE_SIZE - 8, .width = TILE_SIZE, .top = TILE_SIZE * 4, .height = TILE_SIZE * 2 }, - // bottom - { .left = TILE_SIZE * 4, .width = TILE_SIZE * 2, .top = (ARENA_HEIGHT_TILES - 1) * TILE_SIZE - 8, .height = TILE_SIZE }, - // left - { .left = TILE_SIZE - 8, .width = TILE_SIZE, .top = TILE_SIZE * 4, .height = TILE_SIZE * 2 }, -}; - void setupRabbitBullets() { int i; @@ -99,8 +89,11 @@ void setupEnemies() { } } -int spawnCooldown = 0; -int difficulty = 0; +struct GlobalGameState globalGameState = { + .spawnCooldown = 0, + .difficulty = 0 +}; + int kills = 0; int health = RABBIT_HEALTH_MAX; @@ -131,69 +124,19 @@ void handleEnemyKills() { playerPowerup.y = TILE_SIZE + rand() % ((ARENA_HEIGHT_TILES - 2) * TILE_SIZE); playerPowerup.isActive = 1; - playerPowerup.cooldown = POWERUP_RESPAWN_COOLDOWN_PER_LEVEL * difficulty + - rand() % (POWERUP_RESPAWN_COOLDOWN_PER_LEVEL * difficulty); + playerPowerup.cooldown = POWERUP_RESPAWN_COOLDOWN_PER_LEVEL * globalGameState.difficulty + + rand() % (POWERUP_RESPAWN_COOLDOWN_PER_LEVEL * globalGameState.difficulty); } if (hadKill) { for (i = 0; i < 10; ++i) { if (kills > difficultyBands[i]) { - difficulty = i + 1; + globalGameState.difficulty = i + 1; } } } } -void maybeSpawnEnemy() { - char canSpawn; - int i, gate, availableEnemy, gatePlayerIsFacing; - int spawnX, spawnY, spawnTry; - - char buffer[20]; - - if (spawnCooldown-- > 0) return; - - for (i = 0; i < ENEMY_MAX_COUNT; ++i) { - if (!enemyPosition[i].isActive) { - availableEnemy = i; - canSpawn = 1; - break; - } - } - - if (!canSpawn) return; - - // determine which gate the player is at and reduce the likelihood of - // spawning from that gate - // * 8 chances to spawn [0, 1] for each gate - // * if the gate the player is looking at gets [0], reroll - // * try three times max to limit cost of calculating - for (spawnTry = 0; spawnTry < 3; ++spawnTry) { - i = rand() % 12; - gate = i / 3; - - if (gatePlayerIsFacing == gate && i % 3 != 0) continue; - } - - spawnX = spawnPointRanges[gate].left + rand() % spawnPointRanges[gate].width; - spawnY = spawnPointRanges[gate].top + rand() % spawnPointRanges[gate].height; - - enemyPosition[availableEnemy].isActive = 1; - enemyPosition[availableEnemy].willBeInactive = 0; - enemyPosition[availableEnemy].wasKilled = 0; - enemyPosition[availableEnemy].hitPoints = 1 + difficulty / ENEMY_HIT_POINT_DIFFICULTY_INCREASE_EVERY; - enemyPosition[availableEnemy].hasLeftGate = 0; - enemyPosition[availableEnemy].gateExitedFrom = gate; - enemyPosition[availableEnemy].enemyMoveDelayStep = 0; - enemyPosition[availableEnemy].enemyFireDelayStep = ENEMY_FIRE_MIN_DELAY + rand() % ENEMY_FIRE_VARIABLE_DELAY; - enemyPosition[availableEnemy].enemyPosition[0] = spawnX; - enemyPosition[availableEnemy].enemyPosition[1] = spawnY; - enemyPosition[availableEnemy].oldEnemyPosition[0] = spawnX; - enemyPosition[availableEnemy].oldEnemyPosition[1] = spawnY; - - spawnCooldown = (BASE_ENEMY_SPAWN_COOLDOWN - (difficulty * DIFFICULTY_SPAWN_COOLDOWN_REDUCTION)) + MINIMUM_ENEMY_SPAWN_COOLDOWN + rand() % VARIABLE_ENEMY_SPAWN_COOLDOWN; -} - void setupEnemySprites() { buildCompiledSprite( &sprite_enemy, @@ -495,7 +438,7 @@ void handleCombat() { enemyPosition, enemyBulletPosition, &rabbitPosition, - difficulty + globalGameState.difficulty ); advanceRabbitBullets( @@ -541,7 +484,7 @@ void handleCombat() { if (handleRabbitToPowerupCollision(&rabbitPosition, &playerPowerup)) { playerPowerup.willBeInactive = 1; rabbitWeaponry.currentWeapon = WEAPON_TYPE_SPREAD_SHOT_GUN; - rabbitWeaponry.currentWeaponRemainingRounds = (difficulty + 1) * SHOTGUN_ROUNDS_PER_LEVEL; + rabbitWeaponry.currentWeaponRemainingRounds = (globalGameState.difficulty + 1) * SHOTGUN_ROUNDS_PER_LEVEL; } } @@ -585,7 +528,11 @@ int main(void) { readMouse(&mouseStatus); populateKeyboardKeydownState(); - maybeSpawnEnemy(); + maybeSpawnEnemy( + &globalGameState, + enemyPosition, + &rabbitPosition + ); handleMovement(); handleRedraw(); diff --git a/game.h b/game.h index 17d8cc5..9beb271 100644 --- a/game.h +++ b/game.h @@ -3,13 +3,12 @@ #include "system/vga.h" -struct SpawnPointRange { - int left, width; - int top, height; -}; - extern struct CompiledSpriteRender rabbit, mouse, bullet, enemy, enemyBullet, shotgun, shieldKiller; extern struct SpriteBounds bounds; -extern struct SpawnPointRange spawnPointRanges[]; + +struct GlobalGameState { + int difficulty; + int spawnCooldown; +}; #endif diff --git a/makefile b/makefile index 7f40282..cb1e5b3 100644 --- a/makefile +++ b/makefile @@ -1,6 +1,6 @@ -obj = sprites.o game.o bmpload.o arena.o movement.o combat.o +obj = sprites.o game.o bmpload.o arena.o movement.o combat.o spawn.o -all: system/system.lib game.exe .SYMBOLIC +all: system/system.lib game.exe test .SYMBOLIC system/system.lib: .SYMBOLIC cd system @@ -19,6 +19,9 @@ sprites.asm: sprtsht.bmp spritesheet.yml game.exe: $(obj) system/system.lib wcl386 -q -fe=game -bt=dos -l=dos4g $(obj) system/system.lib +test: test.c spawn_test.c spawn.c .SYMBOLIC + wcl386 -fe=test -bt=dos -l=dos4g test.c spawn.c spawn_test.c cutest-1.5/CuTest.c + clean: .SYMBOLIC rm *.o rm system/*.o diff --git a/movement.c b/movement.c index db2a833..66bb54f 100644 --- a/movement.c +++ b/movement.c @@ -4,8 +4,9 @@ #include "game.h" #include "const.h" #include "movement.h" -#include "system/mouse_io.h" +#include "spawn.h" +#include "system/mouse_io.h" #include "system/pc_stuff.h" void captureAndLimitMousePosition( diff --git a/spawn.c b/spawn.c new file mode 100644 index 0000000..22eff90 --- /dev/null +++ b/spawn.c @@ -0,0 +1,118 @@ +#include +#include + +#include "game.h" +#include "movement.h" +#include "const.h" +#include "spawn.h" + +struct SpawnPointRange spawnPointRanges[4] = { + // top + { .left = TILE_SIZE * 4, .width = TILE_SIZE * 2, .top = TILE_SIZE - 8, .height = TILE_SIZE }, + // right + { .left = (ARENA_WIDTH_TILES - 1) * TILE_SIZE - 8, .width = TILE_SIZE, .top = TILE_SIZE * 4, .height = TILE_SIZE * 2 }, + // bottom + { .left = TILE_SIZE * 4, .width = TILE_SIZE * 2, .top = (ARENA_HEIGHT_TILES - 1) * TILE_SIZE - 8, .height = TILE_SIZE }, + // left + { .left = TILE_SIZE - 8, .width = TILE_SIZE, .top = TILE_SIZE * 4, .height = TILE_SIZE * 2 }, +}; + +int HIT_POINT_RANGES[10][4] = { + { 1, 1, 1, 1 }, + { 1, 1, 1, 1 }, + { 1, 1, 1, 2 }, + { 1, 1, 1, 2 }, + { 1, 1, 2, 2 }, + { 1, 2, 2, 2 }, + { 1, 2, 2, 2 }, + { 1, 2, 2, 3 }, + { 1, 2, 2, 3 }, + { 1, 2, 3, 3 } +}; + +int determineEnemyHitPointCalculation(int difficulty, int roll) { + return HIT_POINT_RANGES[difficulty][roll]; +} + +void selectEnemySpawnLocation( + struct EnemySpawningDetails *spawnDetails, + struct RabbitPosition *rabbitPosition +) { + int spawnTry, gate, i; + int gatePlayerIsFacing = rabbitPosition->mouseAngle / 90; + + // determine which gate the player is at and reduce the likelihood of + // spawning from that gate + // * 8 chances to spawn [0, 1] for each gate + // * if the gate the player is looking at gets [0], reroll + // * try three times max to limit cost of calculating + for (spawnTry = 0; spawnTry < 3; ++spawnTry) { + i = rand() % 12; + gate = i / 3; + + if (gatePlayerIsFacing == gate && i % 3 != 0) continue; + } + + spawnDetails->gate = gate; + spawnDetails->spawnX = spawnPointRanges[gate].left + rand() % spawnPointRanges[gate].width; + spawnDetails->spawnY = spawnPointRanges[gate].top + rand() % spawnPointRanges[gate].height; +} + +void spawnEnemy( + struct EnemySpawningDetails *spawnDetails, + struct GlobalGameState *globalGameState +) { + spawnDetails->enemyPosition->isActive = 1; + spawnDetails->enemyPosition->willBeInactive = 0; + spawnDetails->enemyPosition->wasKilled = 0; + spawnDetails->enemyPosition->hitPoints = determineEnemyHitPointCalculation( + globalGameState->difficulty, + rand() % 4 + ); + spawnDetails->enemyPosition->hasLeftGate = 0; + spawnDetails->enemyPosition->gateExitedFrom = spawnDetails->gate; + spawnDetails->enemyPosition->enemyMoveDelayStep = 0; + spawnDetails->enemyPosition->enemyFireDelayStep = ENEMY_FIRE_MIN_DELAY + rand() % ENEMY_FIRE_VARIABLE_DELAY; + spawnDetails->enemyPosition->enemyPosition[0] = spawnDetails->spawnX; + spawnDetails->enemyPosition->enemyPosition[1] = spawnDetails->spawnY; + spawnDetails->enemyPosition->oldEnemyPosition[0] = spawnDetails->spawnX; + spawnDetails->enemyPosition->oldEnemyPosition[1] = spawnDetails->spawnY; +} + +void maybeSpawnEnemy( + struct GlobalGameState *globalGameState, + struct EnemyPosition enemyPosition[], + struct RabbitPosition *rabbitPosition +) { + char canSpawn; + int i, availableEnemy; + + struct EnemySpawningDetails spawnDetails; + + if (globalGameState->spawnCooldown-- > 0) return; + + for (i = 0; i < ENEMY_MAX_COUNT; ++i) { + if (!enemyPosition[i].isActive) { + availableEnemy = i; + canSpawn = 1; + break; + } + } + + if (!canSpawn) return; + + spawnDetails.enemyPosition = &enemyPosition[availableEnemy]; + spawnDetails.difficulty = globalGameState->difficulty; + selectEnemySpawnLocation( + &spawnDetails, + rabbitPosition + ); + spawnEnemy( + &spawnDetails, + globalGameState + ); + + globalGameState->spawnCooldown = ( + BASE_ENEMY_SPAWN_COOLDOWN - (globalGameState->difficulty * DIFFICULTY_SPAWN_COOLDOWN_REDUCTION)) + + MINIMUM_ENEMY_SPAWN_COOLDOWN + rand() % VARIABLE_ENEMY_SPAWN_COOLDOWN; +} diff --git a/spawn.h b/spawn.h new file mode 100644 index 0000000..3b79d7b --- /dev/null +++ b/spawn.h @@ -0,0 +1,26 @@ +#ifndef __SPAWN_H__ +#define __SPAWN_H__ + +#include "game.h" +#include "movement.h" + +void maybeSpawnEnemy( + struct GlobalGameState*, struct EnemyPosition[], struct RabbitPosition* +); + +struct EnemySpawningDetails { + struct EnemyPosition *enemyPosition; + int gate; + int difficulty; + int spawnX; + int spawnY; +}; + +struct SpawnPointRange { + int left, width; + int top, height; +}; + +extern struct SpawnPointRange spawnPointRanges[]; + +#endif diff --git a/spawn_test.c b/spawn_test.c new file mode 100644 index 0000000..754982b --- /dev/null +++ b/spawn_test.c @@ -0,0 +1,82 @@ +#include +#include "cutest-1.5/CuTest.h" + +#include "movement.h" +#include "game.h" +#include "spawn.h" +#include "movement.h" + +// testing these private methods, i know +void selectEnemySpawnLocation( + struct EnemySpawningDetails *spawnDetails, + struct RabbitPosition *rabbitPosition +); +int determineEnemyHitPointCalculation(int difficulty, int pcnt); +int spawnEnemy(struct EnemySpawningDetails*, struct GlobalGameState*); + +struct EnemySpawningDetails spawnDetails; +struct RabbitPosition rabbitPosition; +struct GlobalGameState globalGameState; +struct EnemyPosition enemyPosition; + +void TestSelectEnemySpawnLocation(CuTest *tc) { + srand(1); + + spawnDetails.gate = -1; + spawnDetails.spawnX = -1; + spawnDetails.spawnY = -1; + + rabbitPosition.mouseAngle = 30; + + selectEnemySpawnLocation( + &spawnDetails, + &rabbitPosition + ); + + // built from setting seed to 1 + CuAssertIntEquals(tc, 3, spawnDetails.gate); + CuAssertIntEquals(tc, 27, spawnDetails.spawnX); + CuAssertIntEquals(tc, 91, spawnDetails.spawnY); +} + +void TestDetermineEnemyHitPointCalculation(CuTest *tc) { + srand(1); + + CuAssertIntEquals(tc, 1, determineEnemyHitPointCalculation(0, 0)); + CuAssertIntEquals(tc, 1, determineEnemyHitPointCalculation(0, 3)); + + CuAssertIntEquals(tc, 1, determineEnemyHitPointCalculation(2, 0)); + CuAssertIntEquals(tc, 1, determineEnemyHitPointCalculation(2, 2)); + CuAssertIntEquals(tc, 2, determineEnemyHitPointCalculation(2, 3)); +} + +void TestSpawnEnemy(CuTest *tc) { + srand(1); + + spawnDetails.gate = 1; + spawnDetails.spawnX = 100; + spawnDetails.spawnY = 50; + spawnDetails.enemyPosition = &enemyPosition; + globalGameState.difficulty = 4; + + spawnEnemy(&spawnDetails, &globalGameState); + + // randomized values + CuAssertIntEquals(tc, 2, enemyPosition.hitPoints); + CuAssertIntEquals(tc, 103, enemyPosition.enemyFireDelayStep); + + // from spawndetails + CuAssertIntEquals(tc, 1, enemyPosition.gateExitedFrom); + CuAssertIntEquals(tc, 100, enemyPosition.enemyPosition[0]); + CuAssertIntEquals(tc, 50, enemyPosition.enemyPosition[1]); + CuAssertIntEquals(tc, 100, enemyPosition.oldEnemyPosition[0]); + CuAssertIntEquals(tc, 50, enemyPosition.oldEnemyPosition[1]); +} + +CuSuite *SpawnGetSuite() { + CuSuite *suite = CuSuiteNew(); + SUITE_ADD_TEST(suite, TestSelectEnemySpawnLocation); + SUITE_ADD_TEST(suite, TestDetermineEnemyHitPointCalculation); + SUITE_ADD_TEST(suite, TestSpawnEnemy); + return suite; +} diff --git a/test b/test new file mode 100755 index 0000000..887576f Binary files /dev/null and b/test differ diff --git a/test.c b/test.c new file mode 100644 index 0000000..dee4f63 --- /dev/null +++ b/test.c @@ -0,0 +1,20 @@ +#include "cutest-1.5/CuTest.h" +#include + +CuSuite *SpawnGetSuite(); + +void RunAllTests(void) { + CuString *output = CuStringNew(); + CuSuite *suite = CuSuiteNew(); + + CuSuiteAddSuite(suite, SpawnGetSuite()); + + CuSuiteRun(suite); + CuSuiteSummary(suite, output); + CuSuiteDetails(suite, output); + printf("%s\n", output->buffer); +} + +int main(void) { + RunAllTests(); +}