add unit tests?

This commit is contained in:
John Bintz 2024-02-28 12:50:57 -05:00
parent 7039359067
commit 4cc709c2a0
18 changed files with 1984 additions and 78 deletions

25
cutest-1.5/AllTests.c Normal file
View File

@ -0,0 +1,25 @@
#include <stdio.h>
#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();
}

339
cutest-1.5/CuTest.c Normal file
View File

@ -0,0 +1,339 @@
#include <assert.h>
#include <setjmp.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <math.h>
#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);
}
}

116
cutest-1.5/CuTest.h Normal file
View File

@ -0,0 +1,116 @@
#ifndef CU_TEST_H
#define CU_TEST_H
#include <setjmp.h>
#include <stdarg.h>
#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 */

709
cutest-1.5/CuTestTest.c Normal file
View File

@ -0,0 +1,709 @@
#include <assert.h>
#include <setjmp.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#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 <hello> but was <world>";
const char *expectedMsg = "some text: expected <hello> but was <world>";
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 <hello> but was <NULL>";
const char *expectedMsg = "some text: expected <hello> but was <NULL>";
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 <NULL> but was <hello>";
const char *expectedMsg = "some text: expected <NULL> but was <hello>";
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;
}

211
cutest-1.5/README.txt Normal file
View File

@ -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 <dglo@hyde.ssec.wisc.edu>
- [04.17.2009] Tobias Lippert <herrmarder@googlemail.com>
- [11.13.2009] Eli Bendersky <eliben@gmail.com>
- [12.14.2009] Andrew Brown <abrown@datasci.com>

196
cutest-1.5/index.html Normal file
View File

@ -0,0 +1,196 @@
<html>
<link href="style.css" rel="stylesheet" type="text/css">
<head>
<title>CuTest: The Cutest C Unit Testing Framework</title>
</head>
<BODY>
<script type="text/javascript"><!--
google_ad_client = "pub-6301376840682363";
google_ad_width = 728;
google_ad_height = 90;
google_ad_format = "728x90_as";
google_ad_channel ="3703387138";
google_color_border = "CCCCCC";
google_color_bg = "FFFFFF";
google_color_link = "000000";
google_color_url = "666666";
google_color_text = "333333";
//--></script>
<script type="text/javascript"
src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
</script>
<br>
<br>
<HR>
<FONT SIZE="-1">
[
<A HREF="http://sourceforge.net/project/showfiles.php?group_id=52240">Download Now</A>
| <A HREF="http://sourceforge.net/project/stats/?group_id=52240&ugn=cutest">Download Statistics</A>
| <A HREF="http://sourceforge.net/cvs/?group_id=52240">Browse Source</A>
| <A HREF="http://sourceforge.net/projects/cutest">SourceForge</A>
| <A HREF="http://asimjalis.blogspot.com">Blog</A>
| <A HREF="mailto:asimjalis(nospam)gmail.com">asimjalis(nospam)gmail.com</A>
]
</FONT>
<HR>
<H1>CuTest: C Unit Testing Framework</H1>
<h2>Overview</h2>
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.
<h2>Benefits</h2>
<ul>
<li> Lower Defects. The tests ensure that your code keeps working
as you make small changes in it.
<li> Faster Debugging. The tests tell you which subroutine is
broken. You avoid spending hours trying to figure out what's
broken.
<li> 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.
<li> Permanent Bug Fixes. If every time a bug is reported you
write a quick test, you will guarantee that the bug never
reappears again.
<li> 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.
</ul>
<h2> Features </h2>
<ul>
<li> Small. Consists of a single .c and .h file.
<li> Easy to Deploy. Just drop the two files into your source
tree.
<li> Highly Portable. Works with all major compilers on Windows
(Microsoft, Borland), Linux, Unix, PalmOS.
<li> Open Source. You can extend it to add more functionality.
The source can be invaluable if you are trying to trace a test
failure.
<li> Cuteness. Of all the testing frameworks CuTest has the
cutest name :-)
</ul>
<h2>Licensing</h2>
CuTest is distributed under the <a
href="http://www.opensource.org/licenses/zlib-license.html">zlib/libpng
license</a>. See license.txt in the distribution for text of license. The
intent of the license is to:
<ul>
<li> Keep the license as simple as possible
<li> Encourage the use of CuTest in both free and commercial applications and libraries
<li> Keep the source code together
<li> Give credit to the CuTest contributors for their work
</ul>
If you find CuTest useful we would like to hear about it.
<h2>Getting Started</h2>
<p> 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.
<p> To add unit testing to your C code the only files you need
are CuTest.c and CuTest.h.
<p> 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.
<p> You should not have to look inside CuTest.c. Looking in
CuTestTest.c (for example usage) should be sufficient.
<p> After downloading the sources, run your compiler to create an
executable called AllTests.exe. For example, if you are using
Windows you would type:
<PRE CLASS="CONSOLE">
cl AllTests.c CuTest.c CuTestTest.c
AllTests.exe
</PRE>
<p> This will run all the unit tests associated with CuTest and
print the output on the console.
<p> For more details on how to use the library look at the README file included
with the distribution.
<h2>Contribute</h2>
<p> We hope you CuTest saves you time and helps you produce high quality
software.
<p> 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.
<p> If you would like to contribute documentation or tutorials to this project
please send e-mail.
<br>
<br>
<hr>
<font size="-1">
Copyright &copy; 2002-2003, Asim Jalis (<a
href="mailto:asimjalis(nospam)gmail.com">asimjalis(nospam)gmail.com</a>).
All rights reserved.
</font>
<SCRIPT language="JavaScript">
<!--
var re = /\(nospam\)/ig;
var str;
for(i = 0;i < document.links.length;i++)
{
str = "" + document.links(i).href;
if(str.search(re) != -1)
document.links(i).href = str.replace(re, "@");
str = "" + document.links(i).innerHTML;
if(str.search(re) != -1)
document.links(i).innerHTML = str.replace(re, "@");
}
-->
</SCRIPT>
<p>
<a href="http://sourceforge.net"><img src="http://sourceforge.net/sflogo.php?group_id=52240&type=1" width="88" height="31" border="0" alt="SourceForge.net Logo"></a>
</BODY>
</HTML>

38
cutest-1.5/license.txt Normal file
View File

@ -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.

55
cutest-1.5/make-tests.sh Normal file
View File

@ -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 <stdio.h>
#include <stdlib.h>
#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();
}
'

21
cutest-1.5/style.css Normal file
View File

@ -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;
}

85
game.c
View File

@ -17,6 +17,7 @@
#include "movement.h" #include "movement.h"
#include "combat.h" #include "combat.h"
#include "game.h" #include "game.h"
#include "spawn.h"
// TODO: centralize these outside of game.c // TODO: centralize these outside of game.c
struct CompiledSpriteRender rabbit, struct CompiledSpriteRender rabbit,
@ -49,17 +50,6 @@ struct BulletPosition enemyBulletPosition[ENEMY_BULLET_LIMIT];
struct RabbitWeaponry rabbitWeaponry; struct RabbitWeaponry rabbitWeaponry;
struct PlayerPowerup playerPowerup; 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() { void setupRabbitBullets() {
int i; int i;
@ -99,8 +89,11 @@ void setupEnemies() {
} }
} }
int spawnCooldown = 0; struct GlobalGameState globalGameState = {
int difficulty = 0; .spawnCooldown = 0,
.difficulty = 0
};
int kills = 0; int kills = 0;
int health = RABBIT_HEALTH_MAX; int health = RABBIT_HEALTH_MAX;
@ -131,69 +124,19 @@ void handleEnemyKills() {
playerPowerup.y = TILE_SIZE + rand() % ((ARENA_HEIGHT_TILES - 2) * TILE_SIZE); playerPowerup.y = TILE_SIZE + rand() % ((ARENA_HEIGHT_TILES - 2) * TILE_SIZE);
playerPowerup.isActive = 1; playerPowerup.isActive = 1;
playerPowerup.cooldown = POWERUP_RESPAWN_COOLDOWN_PER_LEVEL * difficulty + playerPowerup.cooldown = POWERUP_RESPAWN_COOLDOWN_PER_LEVEL * globalGameState.difficulty +
rand() % (POWERUP_RESPAWN_COOLDOWN_PER_LEVEL * difficulty); rand() % (POWERUP_RESPAWN_COOLDOWN_PER_LEVEL * globalGameState.difficulty);
} }
if (hadKill) { if (hadKill) {
for (i = 0; i < 10; ++i) { for (i = 0; i < 10; ++i) {
if (kills > difficultyBands[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() { void setupEnemySprites() {
buildCompiledSprite( buildCompiledSprite(
&sprite_enemy, &sprite_enemy,
@ -495,7 +438,7 @@ void handleCombat() {
enemyPosition, enemyPosition,
enemyBulletPosition, enemyBulletPosition,
&rabbitPosition, &rabbitPosition,
difficulty globalGameState.difficulty
); );
advanceRabbitBullets( advanceRabbitBullets(
@ -541,7 +484,7 @@ void handleCombat() {
if (handleRabbitToPowerupCollision(&rabbitPosition, &playerPowerup)) { if (handleRabbitToPowerupCollision(&rabbitPosition, &playerPowerup)) {
playerPowerup.willBeInactive = 1; playerPowerup.willBeInactive = 1;
rabbitWeaponry.currentWeapon = WEAPON_TYPE_SPREAD_SHOT_GUN; 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); readMouse(&mouseStatus);
populateKeyboardKeydownState(); populateKeyboardKeydownState();
maybeSpawnEnemy(); maybeSpawnEnemy(
&globalGameState,
enemyPosition,
&rabbitPosition
);
handleMovement(); handleMovement();
handleRedraw(); handleRedraw();

11
game.h
View File

@ -3,13 +3,12 @@
#include "system/vga.h" #include "system/vga.h"
struct SpawnPointRange {
int left, width;
int top, height;
};
extern struct CompiledSpriteRender rabbit, mouse, bullet, enemy, enemyBullet, shotgun, shieldKiller; extern struct CompiledSpriteRender rabbit, mouse, bullet, enemy, enemyBullet, shotgun, shieldKiller;
extern struct SpriteBounds bounds; extern struct SpriteBounds bounds;
extern struct SpawnPointRange spawnPointRanges[];
struct GlobalGameState {
int difficulty;
int spawnCooldown;
};
#endif #endif

View File

@ -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 system/system.lib: .SYMBOLIC
cd system cd system
@ -19,6 +19,9 @@ sprites.asm: sprtsht.bmp spritesheet.yml
game.exe: $(obj) system/system.lib game.exe: $(obj) system/system.lib
wcl386 -q -fe=game -bt=dos -l=dos4g $(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 clean: .SYMBOLIC
rm *.o rm *.o
rm system/*.o rm system/*.o

View File

@ -4,8 +4,9 @@
#include "game.h" #include "game.h"
#include "const.h" #include "const.h"
#include "movement.h" #include "movement.h"
#include "system/mouse_io.h" #include "spawn.h"
#include "system/mouse_io.h"
#include "system/pc_stuff.h" #include "system/pc_stuff.h"
void captureAndLimitMousePosition( void captureAndLimitMousePosition(

118
spawn.c Normal file
View File

@ -0,0 +1,118 @@
#include <math.h>
#include <stdio.h>
#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;
}

26
spawn.h Normal file
View File

@ -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

82
spawn_test.c Normal file
View File

@ -0,0 +1,82 @@
#include <stdlib.h>
#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;
}

BIN
test Executable file

Binary file not shown.

20
test.c Normal file
View File

@ -0,0 +1,20 @@
#include "cutest-1.5/CuTest.h"
#include <stdio.h>
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();
}