16cd6a6acSopenharmony_ci/*
26cd6a6acSopenharmony_ci * Copyright (c) 2003 Asim Jalis
36cd6a6acSopenharmony_ci *
46cd6a6acSopenharmony_ci * This software is provided 'as-is', without any express or implied
56cd6a6acSopenharmony_ci * warranty. In no event will the authors be held liable for any damages
66cd6a6acSopenharmony_ci * arising from the use of this software.
76cd6a6acSopenharmony_ci *
86cd6a6acSopenharmony_ci * Permission is granted to anyone to use this software for any purpose,
96cd6a6acSopenharmony_ci * including commercial applications, and to alter it and redistribute it
106cd6a6acSopenharmony_ci * freely, subject to the following restrictions:
116cd6a6acSopenharmony_ci *
126cd6a6acSopenharmony_ci * 1. The origin of this software must not be misrepresented; you must not
136cd6a6acSopenharmony_ci * claim that you wrote the original software. If you use this software in
146cd6a6acSopenharmony_ci * a product, an acknowledgment in the product documentation would be
156cd6a6acSopenharmony_ci * appreciated but is not required.
166cd6a6acSopenharmony_ci *
176cd6a6acSopenharmony_ci * 2. Altered source versions must be plainly marked as such, and must not
186cd6a6acSopenharmony_ci * be misrepresented as being the original software.
196cd6a6acSopenharmony_ci *
206cd6a6acSopenharmony_ci * 3. This notice may not be removed or altered from any source
216cd6a6acSopenharmony_ci * distribution.
226cd6a6acSopenharmony_ci */
236cd6a6acSopenharmony_ci
246cd6a6acSopenharmony_ci#include <assert.h>
256cd6a6acSopenharmony_ci#include <setjmp.h>
266cd6a6acSopenharmony_ci#include <stdlib.h>
276cd6a6acSopenharmony_ci#include <stdio.h>
286cd6a6acSopenharmony_ci#include <string.h>
296cd6a6acSopenharmony_ci#include <math.h>
306cd6a6acSopenharmony_ci
316cd6a6acSopenharmony_ci#include "CuTest.h"
326cd6a6acSopenharmony_ci
336cd6a6acSopenharmony_ci/*-------------------------------------------------------------------------*
346cd6a6acSopenharmony_ci * CuStr
356cd6a6acSopenharmony_ci *-------------------------------------------------------------------------*/
366cd6a6acSopenharmony_ci
376cd6a6acSopenharmony_cichar* CuStrAlloc(int size)
386cd6a6acSopenharmony_ci{
396cd6a6acSopenharmony_ci	char* newStr = (char*) malloc( sizeof(char) * (size) );
406cd6a6acSopenharmony_ci	return newStr;
416cd6a6acSopenharmony_ci}
426cd6a6acSopenharmony_ci
436cd6a6acSopenharmony_cichar* CuStrCopy(const char* old)
446cd6a6acSopenharmony_ci{
456cd6a6acSopenharmony_ci	int len = strlen(old);
466cd6a6acSopenharmony_ci	char* newStr = CuStrAlloc(len + 1);
476cd6a6acSopenharmony_ci	strcpy(newStr, old);
486cd6a6acSopenharmony_ci	return newStr;
496cd6a6acSopenharmony_ci}
506cd6a6acSopenharmony_ci
516cd6a6acSopenharmony_ci/*-------------------------------------------------------------------------*
526cd6a6acSopenharmony_ci * CuString
536cd6a6acSopenharmony_ci *-------------------------------------------------------------------------*/
546cd6a6acSopenharmony_ci
556cd6a6acSopenharmony_civoid CuStringInit(CuString* str)
566cd6a6acSopenharmony_ci{
576cd6a6acSopenharmony_ci	str->length = 0;
586cd6a6acSopenharmony_ci	str->size = STRING_MAX;
596cd6a6acSopenharmony_ci	str->buffer = (char*) malloc(sizeof(char) * str->size);
606cd6a6acSopenharmony_ci	str->buffer[0] = '\0';
616cd6a6acSopenharmony_ci}
626cd6a6acSopenharmony_ci
636cd6a6acSopenharmony_ciCuString* CuStringNew(void)
646cd6a6acSopenharmony_ci{
656cd6a6acSopenharmony_ci	CuString* str = (CuString*) malloc(sizeof(CuString));
666cd6a6acSopenharmony_ci	str->length = 0;
676cd6a6acSopenharmony_ci	str->size = STRING_MAX;
686cd6a6acSopenharmony_ci	str->buffer = (char*) malloc(sizeof(char) * str->size);
696cd6a6acSopenharmony_ci	str->buffer[0] = '\0';
706cd6a6acSopenharmony_ci	return str;
716cd6a6acSopenharmony_ci}
726cd6a6acSopenharmony_ci
736cd6a6acSopenharmony_civoid CuStringDelete(CuString *str)
746cd6a6acSopenharmony_ci{
756cd6a6acSopenharmony_ci        if (!str) return;
766cd6a6acSopenharmony_ci        free(str->buffer);
776cd6a6acSopenharmony_ci        free(str);
786cd6a6acSopenharmony_ci}
796cd6a6acSopenharmony_ci
806cd6a6acSopenharmony_civoid CuStringResize(CuString* str, int newSize)
816cd6a6acSopenharmony_ci{
826cd6a6acSopenharmony_ci	str->buffer = (char*) realloc(str->buffer, sizeof(char) * newSize);
836cd6a6acSopenharmony_ci	str->size = newSize;
846cd6a6acSopenharmony_ci}
856cd6a6acSopenharmony_ci
866cd6a6acSopenharmony_civoid CuStringAppend(CuString* str, const char* text)
876cd6a6acSopenharmony_ci{
886cd6a6acSopenharmony_ci	int length;
896cd6a6acSopenharmony_ci
906cd6a6acSopenharmony_ci	if (text == NULL) {
916cd6a6acSopenharmony_ci		text = "NULL";
926cd6a6acSopenharmony_ci	}
936cd6a6acSopenharmony_ci
946cd6a6acSopenharmony_ci	length = strlen(text);
956cd6a6acSopenharmony_ci	if (str->length + length + 1 >= str->size)
966cd6a6acSopenharmony_ci		CuStringResize(str, str->length + length + 1 + STRING_INC);
976cd6a6acSopenharmony_ci	str->length += length;
986cd6a6acSopenharmony_ci	strcat(str->buffer, text);
996cd6a6acSopenharmony_ci}
1006cd6a6acSopenharmony_ci
1016cd6a6acSopenharmony_civoid CuStringAppendChar(CuString* str, char ch)
1026cd6a6acSopenharmony_ci{
1036cd6a6acSopenharmony_ci	char text[2];
1046cd6a6acSopenharmony_ci	text[0] = ch;
1056cd6a6acSopenharmony_ci	text[1] = '\0';
1066cd6a6acSopenharmony_ci	CuStringAppend(str, text);
1076cd6a6acSopenharmony_ci}
1086cd6a6acSopenharmony_ci
1096cd6a6acSopenharmony_ci__attribute__ ((format (printf, 2, 3))) void CuStringAppendFormat(CuString* str, const char* format, ...)
1106cd6a6acSopenharmony_ci{
1116cd6a6acSopenharmony_ci	va_list argp;
1126cd6a6acSopenharmony_ci	char buf[HUGE_STRING_LEN];
1136cd6a6acSopenharmony_ci	va_start(argp, format);
1146cd6a6acSopenharmony_ci	vsprintf(buf, format, argp);
1156cd6a6acSopenharmony_ci	va_end(argp);
1166cd6a6acSopenharmony_ci	CuStringAppend(str, buf);
1176cd6a6acSopenharmony_ci}
1186cd6a6acSopenharmony_ci
1196cd6a6acSopenharmony_civoid CuStringInsert(CuString* str, const char* text, int pos)
1206cd6a6acSopenharmony_ci{
1216cd6a6acSopenharmony_ci	int length = strlen(text);
1226cd6a6acSopenharmony_ci	if (pos > str->length)
1236cd6a6acSopenharmony_ci		pos = str->length;
1246cd6a6acSopenharmony_ci	if (str->length + length + 1 >= str->size)
1256cd6a6acSopenharmony_ci		CuStringResize(str, str->length + length + 1 + STRING_INC);
1266cd6a6acSopenharmony_ci	memmove(str->buffer + pos + length, str->buffer + pos, (str->length - pos) + 1);
1276cd6a6acSopenharmony_ci	str->length += length;
1286cd6a6acSopenharmony_ci	memcpy(str->buffer + pos, text, length);
1296cd6a6acSopenharmony_ci}
1306cd6a6acSopenharmony_ci
1316cd6a6acSopenharmony_ci/*-------------------------------------------------------------------------*
1326cd6a6acSopenharmony_ci * CuTest
1336cd6a6acSopenharmony_ci *-------------------------------------------------------------------------*/
1346cd6a6acSopenharmony_ci
1356cd6a6acSopenharmony_civoid CuTestInit(CuTest* t, const char* name, TestFunction function)
1366cd6a6acSopenharmony_ci{
1376cd6a6acSopenharmony_ci	t->name = CuStrCopy(name);
1386cd6a6acSopenharmony_ci	t->failed = 0;
1396cd6a6acSopenharmony_ci	t->ran = 0;
1406cd6a6acSopenharmony_ci	t->message = NULL;
1416cd6a6acSopenharmony_ci	t->function = function;
1426cd6a6acSopenharmony_ci	t->jumpBuf = NULL;
1436cd6a6acSopenharmony_ci}
1446cd6a6acSopenharmony_ci
1456cd6a6acSopenharmony_ciCuTest* CuTestNew(const char* name, TestFunction function)
1466cd6a6acSopenharmony_ci{
1476cd6a6acSopenharmony_ci	CuTest* tc = CU_ALLOC(CuTest);
1486cd6a6acSopenharmony_ci	CuTestInit(tc, name, function);
1496cd6a6acSopenharmony_ci	return tc;
1506cd6a6acSopenharmony_ci}
1516cd6a6acSopenharmony_ci
1526cd6a6acSopenharmony_civoid CuTestDelete(CuTest *t)
1536cd6a6acSopenharmony_ci{
1546cd6a6acSopenharmony_ci        if (!t) return;
1556cd6a6acSopenharmony_ci        free(t->name);
1566cd6a6acSopenharmony_ci        free(t);
1576cd6a6acSopenharmony_ci}
1586cd6a6acSopenharmony_ci
1596cd6a6acSopenharmony_civoid CuTestRun(CuTest* tc)
1606cd6a6acSopenharmony_ci{
1616cd6a6acSopenharmony_ci	jmp_buf buf;
1626cd6a6acSopenharmony_ci	tc->jumpBuf = &buf;
1636cd6a6acSopenharmony_ci	if (setjmp(buf) == 0)
1646cd6a6acSopenharmony_ci	{
1656cd6a6acSopenharmony_ci		tc->ran = 1;
1666cd6a6acSopenharmony_ci		(tc->function)(tc);
1676cd6a6acSopenharmony_ci	}
1686cd6a6acSopenharmony_ci	tc->jumpBuf = 0;
1696cd6a6acSopenharmony_ci}
1706cd6a6acSopenharmony_ci
1716cd6a6acSopenharmony_cistatic void CuFailInternal(CuTest* tc, const char* file, int line, CuString* string)
1726cd6a6acSopenharmony_ci{
1736cd6a6acSopenharmony_ci	char buf[HUGE_STRING_LEN];
1746cd6a6acSopenharmony_ci
1756cd6a6acSopenharmony_ci	sprintf(buf, "%s:%d: ", file, line);
1766cd6a6acSopenharmony_ci	CuStringInsert(string, buf, 0);
1776cd6a6acSopenharmony_ci
1786cd6a6acSopenharmony_ci	tc->failed = 1;
1796cd6a6acSopenharmony_ci	tc->message = string->buffer;
1806cd6a6acSopenharmony_ci	if (tc->jumpBuf != 0) longjmp(*(tc->jumpBuf), 0);
1816cd6a6acSopenharmony_ci}
1826cd6a6acSopenharmony_ci
1836cd6a6acSopenharmony_civoid CuFail_Line(CuTest* tc, const char* file, int line, const char* message2, const char* message)
1846cd6a6acSopenharmony_ci{
1856cd6a6acSopenharmony_ci	CuString string;
1866cd6a6acSopenharmony_ci
1876cd6a6acSopenharmony_ci	CuStringInit(&string);
1886cd6a6acSopenharmony_ci	if (message2 != NULL)
1896cd6a6acSopenharmony_ci	{
1906cd6a6acSopenharmony_ci		CuStringAppend(&string, message2);
1916cd6a6acSopenharmony_ci		CuStringAppend(&string, ": ");
1926cd6a6acSopenharmony_ci	}
1936cd6a6acSopenharmony_ci	CuStringAppend(&string, message);
1946cd6a6acSopenharmony_ci	CuFailInternal(tc, file, line, &string);
1956cd6a6acSopenharmony_ci}
1966cd6a6acSopenharmony_ci
1976cd6a6acSopenharmony_civoid CuAssert_Line(CuTest* tc, const char* file, int line, const char* message, int condition)
1986cd6a6acSopenharmony_ci{
1996cd6a6acSopenharmony_ci	if (condition) return;
2006cd6a6acSopenharmony_ci	CuFail_Line(tc, file, line, NULL, message);
2016cd6a6acSopenharmony_ci}
2026cd6a6acSopenharmony_ci
2036cd6a6acSopenharmony_civoid CuAssertStrEquals_LineMsg(CuTest* tc, const char* file, int line, const char* message,
2046cd6a6acSopenharmony_ci	const char* expected, const char* actual)
2056cd6a6acSopenharmony_ci{
2066cd6a6acSopenharmony_ci	CuString string;
2076cd6a6acSopenharmony_ci	if ((expected == NULL && actual == NULL) ||
2086cd6a6acSopenharmony_ci	    (expected != NULL && actual != NULL &&
2096cd6a6acSopenharmony_ci	     strcmp(expected, actual) == 0))
2106cd6a6acSopenharmony_ci	{
2116cd6a6acSopenharmony_ci		return;
2126cd6a6acSopenharmony_ci	}
2136cd6a6acSopenharmony_ci
2146cd6a6acSopenharmony_ci	CuStringInit(&string);
2156cd6a6acSopenharmony_ci	if (message != NULL)
2166cd6a6acSopenharmony_ci	{
2176cd6a6acSopenharmony_ci		CuStringAppend(&string, message);
2186cd6a6acSopenharmony_ci		CuStringAppend(&string, ": ");
2196cd6a6acSopenharmony_ci	}
2206cd6a6acSopenharmony_ci	CuStringAppend(&string, "expected <");
2216cd6a6acSopenharmony_ci	CuStringAppend(&string, expected);
2226cd6a6acSopenharmony_ci	CuStringAppend(&string, "> but was <");
2236cd6a6acSopenharmony_ci	CuStringAppend(&string, actual);
2246cd6a6acSopenharmony_ci	CuStringAppend(&string, ">");
2256cd6a6acSopenharmony_ci	CuFailInternal(tc, file, line, &string);
2266cd6a6acSopenharmony_ci}
2276cd6a6acSopenharmony_ci
2286cd6a6acSopenharmony_civoid CuAssertIntEquals_LineMsg(CuTest* tc, const char* file, int line, const char* message,
2296cd6a6acSopenharmony_ci	int expected, int actual)
2306cd6a6acSopenharmony_ci{
2316cd6a6acSopenharmony_ci	char buf[STRING_MAX];
2326cd6a6acSopenharmony_ci	if (expected == actual) return;
2336cd6a6acSopenharmony_ci	sprintf(buf, "expected <%d> but was <%d>", expected, actual);
2346cd6a6acSopenharmony_ci	CuFail_Line(tc, file, line, message, buf);
2356cd6a6acSopenharmony_ci}
2366cd6a6acSopenharmony_ci
2376cd6a6acSopenharmony_civoid CuAssertDblEquals_LineMsg(CuTest* tc, const char* file, int line, const char* message,
2386cd6a6acSopenharmony_ci	double expected, double actual, double delta)
2396cd6a6acSopenharmony_ci{
2406cd6a6acSopenharmony_ci	char buf[STRING_MAX];
2416cd6a6acSopenharmony_ci	if (fabs(expected - actual) <= delta) return;
2426cd6a6acSopenharmony_ci	sprintf(buf, "expected <%f> but was <%f>", expected, actual);
2436cd6a6acSopenharmony_ci
2446cd6a6acSopenharmony_ci	CuFail_Line(tc, file, line, message, buf);
2456cd6a6acSopenharmony_ci}
2466cd6a6acSopenharmony_ci
2476cd6a6acSopenharmony_civoid CuAssertPtrEquals_LineMsg(CuTest* tc, const char* file, int line, const char* message,
2486cd6a6acSopenharmony_ci	void* expected, void* actual)
2496cd6a6acSopenharmony_ci{
2506cd6a6acSopenharmony_ci	char buf[STRING_MAX];
2516cd6a6acSopenharmony_ci	if (expected == actual) return;
2526cd6a6acSopenharmony_ci	sprintf(buf, "expected pointer <0x%p> but was <0x%p>", expected, actual);
2536cd6a6acSopenharmony_ci	CuFail_Line(tc, file, line, message, buf);
2546cd6a6acSopenharmony_ci}
2556cd6a6acSopenharmony_ci
2566cd6a6acSopenharmony_ci
2576cd6a6acSopenharmony_ci/*-------------------------------------------------------------------------*
2586cd6a6acSopenharmony_ci * CuSuite
2596cd6a6acSopenharmony_ci *-------------------------------------------------------------------------*/
2606cd6a6acSopenharmony_ci
2616cd6a6acSopenharmony_civoid CuSuiteInit(CuSuite* testSuite)
2626cd6a6acSopenharmony_ci{
2636cd6a6acSopenharmony_ci	testSuite->count = 0;
2646cd6a6acSopenharmony_ci	testSuite->failCount = 0;
2656cd6a6acSopenharmony_ci        memset(testSuite->list, 0, sizeof(testSuite->list));
2666cd6a6acSopenharmony_ci}
2676cd6a6acSopenharmony_ci
2686cd6a6acSopenharmony_ciCuSuite* CuSuiteNew(void)
2696cd6a6acSopenharmony_ci{
2706cd6a6acSopenharmony_ci	CuSuite* testSuite = CU_ALLOC(CuSuite);
2716cd6a6acSopenharmony_ci	CuSuiteInit(testSuite);
2726cd6a6acSopenharmony_ci	return testSuite;
2736cd6a6acSopenharmony_ci}
2746cd6a6acSopenharmony_ci
2756cd6a6acSopenharmony_civoid CuSuiteDelete(CuSuite *testSuite)
2766cd6a6acSopenharmony_ci{
2776cd6a6acSopenharmony_ci        unsigned int n;
2786cd6a6acSopenharmony_ci        for (n=0; n < MAX_TEST_CASES; n++)
2796cd6a6acSopenharmony_ci        {
2806cd6a6acSopenharmony_ci                if (testSuite->list[n])
2816cd6a6acSopenharmony_ci                {
2826cd6a6acSopenharmony_ci                        CuTestDelete(testSuite->list[n]);
2836cd6a6acSopenharmony_ci                }
2846cd6a6acSopenharmony_ci        }
2856cd6a6acSopenharmony_ci        free(testSuite);
2866cd6a6acSopenharmony_ci
2876cd6a6acSopenharmony_ci}
2886cd6a6acSopenharmony_ci
2896cd6a6acSopenharmony_civoid CuSuiteAdd(CuSuite* testSuite, CuTest *testCase)
2906cd6a6acSopenharmony_ci{
2916cd6a6acSopenharmony_ci	assert(testSuite->count < MAX_TEST_CASES);
2926cd6a6acSopenharmony_ci	testSuite->list[testSuite->count] = testCase;
2936cd6a6acSopenharmony_ci	testSuite->count++;
2946cd6a6acSopenharmony_ci}
2956cd6a6acSopenharmony_ci
2966cd6a6acSopenharmony_civoid CuSuiteAddSuite(CuSuite* testSuite, CuSuite* testSuite2)
2976cd6a6acSopenharmony_ci{
2986cd6a6acSopenharmony_ci	int i;
2996cd6a6acSopenharmony_ci	for (i = 0 ; i < testSuite2->count ; ++i)
3006cd6a6acSopenharmony_ci	{
3016cd6a6acSopenharmony_ci		CuTest* testCase = testSuite2->list[i];
3026cd6a6acSopenharmony_ci		CuSuiteAdd(testSuite, testCase);
3036cd6a6acSopenharmony_ci	}
3046cd6a6acSopenharmony_ci}
3056cd6a6acSopenharmony_ci
3066cd6a6acSopenharmony_civoid CuSuiteRun(CuSuite* testSuite)
3076cd6a6acSopenharmony_ci{
3086cd6a6acSopenharmony_ci	int i;
3096cd6a6acSopenharmony_ci	for (i = 0 ; i < testSuite->count ; ++i)
3106cd6a6acSopenharmony_ci	{
3116cd6a6acSopenharmony_ci		CuTest* testCase = testSuite->list[i];
3126cd6a6acSopenharmony_ci		CuTestRun(testCase);
3136cd6a6acSopenharmony_ci		if (testCase->failed) { testSuite->failCount += 1; }
3146cd6a6acSopenharmony_ci	}
3156cd6a6acSopenharmony_ci}
3166cd6a6acSopenharmony_ci
3176cd6a6acSopenharmony_civoid CuSuiteSummary(CuSuite* testSuite, CuString* summary)
3186cd6a6acSopenharmony_ci{
3196cd6a6acSopenharmony_ci	int i;
3206cd6a6acSopenharmony_ci	for (i = 0 ; i < testSuite->count ; ++i)
3216cd6a6acSopenharmony_ci	{
3226cd6a6acSopenharmony_ci		CuTest* testCase = testSuite->list[i];
3236cd6a6acSopenharmony_ci		CuStringAppend(summary, testCase->failed ? "F" : ".");
3246cd6a6acSopenharmony_ci	}
3256cd6a6acSopenharmony_ci	CuStringAppend(summary, "\n\n");
3266cd6a6acSopenharmony_ci}
3276cd6a6acSopenharmony_ci
3286cd6a6acSopenharmony_civoid CuSuiteDetails(CuSuite* testSuite, CuString* details)
3296cd6a6acSopenharmony_ci{
3306cd6a6acSopenharmony_ci	int i;
3316cd6a6acSopenharmony_ci	int failCount = 0;
3326cd6a6acSopenharmony_ci
3336cd6a6acSopenharmony_ci	if (testSuite->failCount == 0)
3346cd6a6acSopenharmony_ci	{
3356cd6a6acSopenharmony_ci		int passCount = testSuite->count - testSuite->failCount;
3366cd6a6acSopenharmony_ci		const char* testWord = passCount == 1 ? "test" : "tests";
3376cd6a6acSopenharmony_ci		CuStringAppendFormat(details, "OK (%d %s)\n", passCount, testWord);
3386cd6a6acSopenharmony_ci	}
3396cd6a6acSopenharmony_ci	else
3406cd6a6acSopenharmony_ci	{
3416cd6a6acSopenharmony_ci		if (testSuite->failCount == 1)
3426cd6a6acSopenharmony_ci			CuStringAppend(details, "There was 1 failure:\n");
3436cd6a6acSopenharmony_ci		else
3446cd6a6acSopenharmony_ci			CuStringAppendFormat(details, "There were %d failures:\n", testSuite->failCount);
3456cd6a6acSopenharmony_ci
3466cd6a6acSopenharmony_ci		for (i = 0 ; i < testSuite->count ; ++i)
3476cd6a6acSopenharmony_ci		{
3486cd6a6acSopenharmony_ci			CuTest* testCase = testSuite->list[i];
3496cd6a6acSopenharmony_ci			if (testCase->failed)
3506cd6a6acSopenharmony_ci			{
3516cd6a6acSopenharmony_ci				failCount++;
3526cd6a6acSopenharmony_ci				CuStringAppendFormat(details, "%d) %s: %s\n",
3536cd6a6acSopenharmony_ci					failCount, testCase->name, testCase->message);
3546cd6a6acSopenharmony_ci			}
3556cd6a6acSopenharmony_ci		}
3566cd6a6acSopenharmony_ci		CuStringAppend(details, "\n!!!FAILURES!!!\n");
3576cd6a6acSopenharmony_ci
3586cd6a6acSopenharmony_ci		CuStringAppendFormat(details, "Runs: %d ",   testSuite->count);
3596cd6a6acSopenharmony_ci		CuStringAppendFormat(details, "Passes: %d ", testSuite->count - testSuite->failCount);
3606cd6a6acSopenharmony_ci		CuStringAppendFormat(details, "Fails: %d\n",  testSuite->failCount);
3616cd6a6acSopenharmony_ci	}
3626cd6a6acSopenharmony_ci}
363