#include <string.h>
#include <sc_unittest.h>
#include <sc_mmgr.h>
#include <sc_stream.h>
#include <sc_stream_memory.h>


static void UT_SC_stream_newMemoryStream(void);
static void UT_SC_stream_memoryDelete(void);
static void UT_SC_stream_memoryReadc(void);
static void UT_SC_stream_memoryRead(void);
static void UT_SC_stream_memoryReadExact(void);
static void UT_SC_stream_memoryReadLine(void);
static void UT_SC_stream_memoryReadLine_fewbuff(void);
static void UT_SC_stream_memoryLimitedRead(void);
static void UT_SC_stream_memoryLimitedRead_fewbuff(void);
static void UT_SC_stream_memoryWritec(void);
static void UT_SC_stream_memoryWrite(void);
static void UT_SC_stream_memoryWriteExact(void);
static void UT_SC_stream_memoryClose(void);
static void UT_SC_stream_memoryReadWrite(void);

static const char* UT_SC_stream_memory_data
	= "abcdefghijklmnopqrstuvwxyz";


void UT_regist_sc_stream_memory(void)
{
	SC_Unittest_add("SC_stream_newMemoryStream"			, UT_SC_stream_newMemoryStream);
	SC_Unittest_add("SC_stream_delete"					, UT_SC_stream_memoryDelete);
	SC_Unittest_add("SC_stream_memoryReadc"				, UT_SC_stream_memoryReadc);
	SC_Unittest_add("SC_stream_memoryRead"				, UT_SC_stream_memoryRead);
	SC_Unittest_add("SC_stream_memoryReadExact"			, UT_SC_stream_memoryReadExact);
	SC_Unittest_add("SC_stream_memoryReadLine"			, UT_SC_stream_memoryReadLine);
	SC_Unittest_add("SC_stream_memoryReadLine_fewbuff"	, UT_SC_stream_memoryReadLine_fewbuff);
	SC_Unittest_add("SC_stream_memoryLimitedRead"		, UT_SC_stream_memoryLimitedRead);
	SC_Unittest_add("SC_stream_memoryLimitedRead_fewbuff", UT_SC_stream_memoryLimitedRead_fewbuff);
	SC_Unittest_add("SC_stream_memoryWritec"				, UT_SC_stream_memoryWritec);
	SC_Unittest_add("SC_stream_memoryWrite"				, UT_SC_stream_memoryWrite);
	SC_Unittest_add("SC_stream_memoryWriteExact"			, UT_SC_stream_memoryWriteExact);
	SC_Unittest_add("SC_stream_memoryClose"				, UT_SC_stream_memoryClose);
	SC_Unittest_add("SC_stream_memoryReadWrite"			, UT_SC_stream_memoryReadWrite);

}


static
void UT_SC_stream_newMemoryStream(void)
{
	SC_Stream* strm;
	strm = SC_Stream_newMemoryStream(16, 5);
	SC_Stream_delete(strm);
}

static
void UT_SC_stream_memoryDelete(void)
{
	SC_Stream* strm;
	strm = SC_Stream_newMemoryStream(16, 5);
	SC_Stream_delete(strm);
}

static
void UT_SC_stream_memoryReadc(void)
{
	SC_Stream* strm;
	char       c;
	int        ret;
	int        i;
	size_t     len;

	strm = SC_Stream_newMemoryStream(32, 5);

	/* テストデータを書き込む	*/
	len  = strlen(UT_SC_stream_memory_data);
	ret  = strm->write(strm, UT_SC_stream_memory_data, len);
	SC_assertNumber(len, ret);

	/* 読み込んでチェックする	*/
	for (i = 0; i < strlen(UT_SC_stream_memory_data); i++)
	{
		ret = strm->readc(strm, &c);
		SC_assertNumber(1, ret);
		SC_assert(UT_SC_stream_memory_data[i]== c);
	}

	SC_Stream_delete(strm);
}

static
void UT_SC_stream_memoryRead(void)
{
	SC_Stream* strm;
	char       buff[3];
	char       c;
	int        i;
	int        ret;
	int        count;
	size_t     len;

	strm = SC_Stream_newMemoryStream(32, 5);

	/* テストデータを書き込む	*/
	len  = strlen(UT_SC_stream_memory_data);
	ret  = strm->write(strm, UT_SC_stream_memory_data, len);
	SC_assertNumber(len, ret);

	/* 正常に読み込みできているかチェックする	*/
	ret = strm->readc(strm, &c);
	SC_assertNumber(1, ret);
	SC_assert('a' == c);

	count = 1;
	while (ret > 0)
	{
		ret = strm->read(strm, buff, sizeof(buff));
		for (i = 0; i < ret; i++)
		{
			SC_assert(UT_SC_stream_memory_data[count] == buff[i]);
			count++;
		}
	}
	SC_Stream_delete(strm);
}

static
void UT_SC_stream_memoryReadExact(void)
{
	SC_Stream* strm;
	char       buff[3];
	int        i;
	int        ret;
	int        count;
	size_t     len;

	strm = SC_Stream_newMemoryStream(32, 5);

	/* テストデータを書き込む	*/
	len  = strlen(UT_SC_stream_memory_data);
	ret  = strm->write(strm, UT_SC_stream_memory_data, len);
	SC_assertNumber(len, ret);

	count = 0;
	while (ret > 0)
	{
		ret = strm->readExact(strm, buff, sizeof(buff));
		for (i = 0; i < ret; i++)
		{
			SC_assert(UT_SC_stream_memory_data[count] == buff[i]);
			count++;
		}
	}
	SC_Stream_delete(strm);
}

static
void UT_SC_stream_memoryReadLine(void)
{
	SC_Stream* strm;
	char       buff[10];
	int        ret;
	size_t     len;
	const char data[]
		= "abc\rabc\r\nabc\nabc\r\rabc\n\nabc\r\n\r\nabc";
	const char* resultData[]
		= { "abc\r", "abc\r\n", "abc\n", "abc\r", "\r",
			"abc\n", "\n", "abc\r\n", "\r\n", "abc" };

	strm = SC_Stream_newMemoryStream(64, 5);

	/* テストデータを書き込む	*/
	len  = strlen(data);
	ret  = strm->write(strm, data, len);
	SC_assertNumber(len, ret);

	int count = 0;

	ret  = strm->readLine(strm, buff, sizeof(buff));
	while (ret > 0)
	{
		SC_assertNumber(strlen(resultData[count]), ret);
		SC_assertString(resultData[count], buff);
		count++;
		ret  = strm->readLine(strm, buff, sizeof(buff));
	}

	strm->close(strm);
	SC_Stream_delete(strm);
}

static
void UT_SC_stream_memoryReadLine_fewbuff(void)
{
	SC_Stream* strm;
	char       buff[2];
	int        ret;
	size_t     len;
	const char data[]
		= "abc\rabc\r\nabc\nabc\r\rabc\n\nabc\r\n\r\nabc";

	strm = SC_Stream_newMemoryStream(64, 2);

	/* テストデータを書き込む	*/
	len  = strlen(data);
	ret  = strm->write(strm, data, len);
	SC_assertNumber(len, ret);

	ret = strm->readLine(strm, buff, sizeof(buff));
	SC_assertNumber(1, ret);
	SC_assertString("a", buff);

	strm->close(strm);
	SC_Stream_delete(strm);
}

static
void UT_SC_stream_memoryLimitedRead(void)
{
	SC_Stream* strm;
	char       buff[4];
	int        ret;
	size_t     len;
	const char data[]
		= "abcdefghijklmnopqrstuvwxyz";

	strm = SC_Stream_newMemoryStream(32, 6);

	/* テストデータを書き込む	*/
	len  = strlen(data);
	ret  = strm->write(strm, data, len);
	SC_assertNumber(len, ret);

	memset(buff, 0x00, sizeof(buff));
	ret = strm->limitedRead(strm, buff, sizeof(buff), "efg", 3);
	SC_assertNumber(3, ret);
	SC_assertString("abc", buff);

	memset(buff, 0x00, sizeof(buff));
	ret = strm->limitedRead(strm, buff, sizeof(buff), "efg", 3);
	SC_assertNumber(1, ret);
	SC_assertString("d", buff);

	ret = strm->limitedRead(strm, buff, sizeof(buff), "efg", 3);
	SC_assertNumber(0, ret);

	SC_Stream_delete(strm);
}

static
void UT_SC_stream_memoryLimitedRead_fewbuff(void)
{
	SC_Stream* strm;
	char       buff[4];
	int        ret;
	size_t     len;
	const char data[]
		= "abcdefghijklmnopqrstuvwxyz";

	strm = SC_Stream_newMemoryStream(32, 6);

	/* テストデータを書き込む	*/
	len  = strlen(data);
	ret  = strm->write(strm, data, len);
	SC_assertNumber(len, ret);

	memset(buff, 0x00, sizeof(buff));
	ret = strm->limitedRead(strm, buff, sizeof(buff), "efgh", 4);
	SC_assertNumber(-1, ret);

	SC_Stream_delete(strm);
}


static
void UT_SC_stream_memoryWritec(void)
{
	int        ret;
	SC_Stream* wStrm;
	SC_Stream* rStrm;
	char       c;
	int        i;

	wStrm = SC_Stream_newMemoryStream(32, 5);

	for (i = 0; i < strlen(UT_SC_stream_memory_data); i++)
	{
		ret = wStrm->writec(wStrm, UT_SC_stream_memory_data[i]);
		SC_assertNumber(1, ret);
	}

	rStrm = wStrm;
	for (i = 0; i < strlen(UT_SC_stream_memory_data); i++)
	{
		ret = rStrm->readc(rStrm, &c);
		SC_assertNumber(1, ret);
		SC_assert(UT_SC_stream_memory_data[i] == c);
	}
	SC_Stream_delete(rStrm);
}

static
void UT_SC_stream_memoryWrite(void)
{
	int        ret;
	SC_Stream* wStrm;
	SC_Stream* rStrm;
	char       c;
	int        i;
	size_t     len;

	wStrm = SC_Stream_newMemoryStream(32, 5);
	len    = strlen(UT_SC_stream_memory_data);
	ret    = wStrm->write(wStrm, UT_SC_stream_memory_data, len);
	SC_assertNumber(len, ret);

	rStrm = wStrm;
	for (i = 0; i < strlen(UT_SC_stream_memory_data); i++)
	{
		ret = rStrm->readc(rStrm, &c);
		SC_assertNumber(1, ret);
		SC_assert(UT_SC_stream_memory_data[i] == c);
	}
	SC_Stream_delete(rStrm);
}

static
void UT_SC_stream_memoryWriteExact(void)
{
	int        ret;
	SC_Stream* wStrm;
	SC_Stream* rStrm;
	char       c;
	int        i;
	size_t     len;

	wStrm = SC_Stream_newMemoryStream(32, 5);

	len    = strlen(UT_SC_stream_memory_data);
	ret    = wStrm->writeExact(wStrm, UT_SC_stream_memory_data, len);
	SC_assertNumber(len, ret);

	rStrm = wStrm;
	for (i = 0; i < strlen(UT_SC_stream_memory_data); i++)
	{
		ret = rStrm->readc(rStrm, &c);
		SC_assertNumber(1, ret);
		SC_assert(UT_SC_stream_memory_data[i] == c);
	}
	SC_Stream_delete(rStrm);
}

static
void UT_SC_stream_memoryClose(void)
{
	int        ret;
	bool       result;
	SC_Stream* wStrm;
	size_t     len;

	wStrm = SC_Stream_newMemoryStream(32, 5);
	len    = strlen(UT_SC_stream_memory_data);
	ret    = wStrm->write(wStrm, UT_SC_stream_memory_data, len);
	SC_assertNumber(len, ret);
	result = wStrm->close(wStrm);
	SC_assert(result);
	wStrm->close(wStrm);
	SC_Stream_delete(wStrm);
}

static
void UT_SC_stream_memoryReadWrite(void)
{
	SC_Stream* strm;
	char data[] = "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz";
	char buff[8];
	int  ret;
	int  wPtr  = 0;
	int  rPtr  = 0;
	int  len   = strlen(data);
	int  wSize = 13;
	strm = SC_Stream_newMemoryStream(23, 5);

	while (rPtr < len)
	{
		if ((len - wPtr) < 13)
		{
			wSize = len - wPtr;
		}
		ret   = strm->_writeCore(strm, &data[wPtr], wSize);
		wPtr += ret;
		ret   = strm->_readCore(strm, buff, 7);

		SC_assert(strncmp(&data[rPtr], buff, ret) == 0);
		rPtr += ret;
	}

	SC_Stream_delete(strm);
}

