testing/CuTest/CuTest.c (334 lines of code) (raw):
// Portions Copyright (c) Microsoft Corporation
#include "CuTest.h"
#include <assert.h>
#include <math.h>
#include <setjmp.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "platform_io_api.h"
/*-------------------------------------------------------------------------*
* CuStr
*-------------------------------------------------------------------------*/
char* CuStrAlloc (int size)
{
char *newStr = (char*) platform_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*) platform_malloc (sizeof (char) * str->size);
str->buffer[0] = '\0';
}
CuString* CuStringNew (void)
{
CuString *str = (CuString*) platform_malloc (sizeof (CuString));
str->length = 0;
str->size = STRING_MAX;
str->buffer = (char*) platform_malloc (sizeof (char) * str->size);
str->buffer[0] = '\0';
return str;
}
void CuStringDelete (CuString *str)
{
if (!str) {
return;
}
platform_free (str->buffer);
platform_free (str);
}
void CuStringResize (CuString *str, int newSize)
{
str->buffer = (char*) platform_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)
{
if (!t) {
return;
}
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;
}
CuStringDelete (t->message);
platform_free (t->name);
platform_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;
platform_free (tc->message);
tc->message = CuStringNew ();
CuStringAppend (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 CuAssertInt64Equals_LineMsg (CuTest *tc, const char *file, int line, const char *message,
long long expected, long long actual)
{
char buf[STRING_MAX];
if (expected == actual) {
return;
}
sprintf (buf, "expected [%lld] but was [%lld]", 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,
const void *expected, const 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)
{
if (!testSuite) {
return;
}
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;
if (!testSuite) {
return;
}
for (n = 0; n < MAX_TEST_CASES; n++) {
if (testSuite->list[n]) {
CuTestDelete (testSuite->list[n]);
}
}
platform_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);
}
platform_free (testSuite2);
}
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];
platform_CuStringAppend (summary, testCase->failed ? "F" : ".");
}
platform_CuStringAppend (summary, NEWLINE NEWLINE);
}
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";
platform_CuStringAppendFormat (details, "OK (%d %s)" NEWLINE, passCount, testWord);
}
else {
if (testSuite->failCount == 1) {
platform_CuStringAppend (details, "There was 1 failure:" NEWLINE);
}
else {
platform_CuStringAppendFormat (details, "There were %d failures:" NEWLINE,
testSuite->failCount);
}
for (i = 0; i < testSuite->count; ++i) {
CuTest *testCase = testSuite->list[i];
if (testCase->failed) {
failCount++;
platform_CuStringAppendFormat (details, "%d) %s: %s" NEWLINE, failCount,
testCase->name, testCase->message->buffer);
}
}
platform_CuStringAppend (details, NEWLINE "!!!FAILURES!!!" NEWLINE);
platform_CuStringAppendFormat (details, "Runs: %d ", testSuite->count);
platform_CuStringAppendFormat (details, "Passes: %d ",
testSuite->count - testSuite->failCount);
platform_CuStringAppendFormat (details, "Fails: %d" NEWLINE, testSuite->failCount);
}
}
void CuSuiteToJUnitXML (CuSuite *testSuite, CuString *report)
{
int i;
// XML header and suite information
platform_CuStringAppend (report, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" NEWLINE);
platform_CuStringAppendFormat (report,
"<testsuite name=\"CuTest\" tests=\"%d\" failures=\"%d\" errors=\"%d\">" NEWLINE,
testSuite->count, testSuite->failCount, testSuite->failCount);
for (i = 0; i < testSuite->count; ++i) {
CuTest *testCase = testSuite->list[i];
platform_CuStringAppendFormat (report, " <testcase classname=\"CuTest\" name=\"%s\">",
testCase->name);
if (testCase->failed) {
platform_CuStringAppendFormat (report, NEWLINE " <failure>%s</failure>" NEWLINE,
testCase->message->buffer);
}
platform_CuStringAppend (report, " </testcase>" NEWLINE);
}
platform_CuStringAppend (report, "</testsuite>" NEWLINE);
}