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


static void UT_SC_stream_newFileStream(void);
static void UT_SC_stream_delete(void);
static void UT_SC_stream_fileReadc(void);
static void UT_SC_stream_fileRead(void);
static void UT_SC_stream_fileReadExact(void);
static void UT_SC_stream_fileReadLine(void);
static void UT_SC_stream_fileReadLine_fewbuff(void);
static void UT_SC_stream_fileLimitedRead(void);
static void UT_SC_stream_fileLimitedRead_fewbuff(void);
static void UT_SC_stream_fileWritec(void);
static void UT_SC_stream_fileWrite(void);
static void UT_SC_stream_fileWriteExact(void);
static void UT_SC_stream_fileClose(void);
static void UT_SC_stream_fileClose_dup(void);


static void UT_SC_stream_makeTestData(void);
static void UT_SC_stream_makeTestData2(const char* data, size_t size);


static const char* UT_SC_stream_data
	= "abcdefghijklmnopqrstuvwxyz";


void UT_regist_sc_stream(void)
{
	SC_Unittest_add("SC_stream_newFileStream"		, UT_SC_stream_newFileStream);
	SC_Unittest_add("SC_stream_delete"				, UT_SC_stream_delete);
	SC_Unittest_add("SC_stream_fileReadc"			, UT_SC_stream_fileReadc);
	SC_Unittest_add("SC_stream_fileRead"				, UT_SC_stream_fileRead);
	SC_Unittest_add("SC_stream_fileReadExact"		, UT_SC_stream_fileReadExact);
	SC_Unittest_add("SC_stream_fileReadLine"			, UT_SC_stream_fileReadLine);
	SC_Unittest_add("SC_stream_fileReadLine_fewbuff"	, UT_SC_stream_fileReadLine_fewbuff);
	SC_Unittest_add("SC_stream_fileLimitedRead"		, UT_SC_stream_fileLimitedRead);
	SC_Unittest_add("SC_stream_fileLimitedRead_fewbuff", UT_SC_stream_fileLimitedRead_fewbuff);
	SC_Unittest_add("SC_stream_fileWritec"			, UT_SC_stream_fileWritec);
	SC_Unittest_add("SC_stream_fileWrite"			, UT_SC_stream_fileWrite);
	SC_Unittest_add("SC_stream_fileWriteExact"		, UT_SC_stream_fileWriteExact);
	SC_Unittest_add("SC_stream_fileClose"			, UT_SC_stream_fileClose);
	SC_Unittest_add("SC_stream_fileClose_dup"		, UT_SC_stream_fileClose_dup);

}


static
void UT_SC_stream_makeTestData(void)
{
	FILE* fp;
	int   ret;
	remove("unittest.tmp");
	fp  = fopen("unittest.tmp", "wb");
	ret = fputs(UT_SC_stream_data, fp);
	SC_assert(ret >= 0);
	ret = fclose(fp);
	SC_assertNumber(0, ret);
}

static
void UT_SC_stream_makeTestData2(const char* data, size_t size)
{
	FILE* fp;
	size_t ret;
	remove("unittest.tmp");
	fp  = fopen("unittest.tmp", "wb");
	ret = fwrite(data, size, 1, fp);
	SC_assert(ret > 0);
	ret = fclose(fp);
	SC_assertNumber(0, ret);
}

static
void UT_SC_stream_newFileStream(void)
{
	FILE*      fp;
	SC_Stream* strm;
	UT_SC_stream_makeTestData();

	fp   = fopen("unittest.tmp", "rb");
	strm = SC_Stream_newFileStream(fp, 5);
	SC_Stream_delete(strm);
}

static
void UT_SC_stream_delete(void)
{
	FILE*      fp;
	SC_Stream* strm;
	UT_SC_stream_makeTestData();

	fp   = fopen("unittest.tmp", "rb");
	strm = SC_Stream_newFileStream(fp, 5);
	SC_Stream_delete(strm);
}

static
void UT_SC_stream_fileReadc(void)
{
	FILE*      fp;
	SC_Stream* strm;
	char       c;
	int        ret;
	int        i;
	UT_SC_stream_makeTestData();

	fp   = fopen("unittest.tmp", "rb");
	strm = SC_Stream_newFileStream(fp, 5);

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

	SC_Stream_delete(strm);
}

static
void UT_SC_stream_fileRead(void)
{
	FILE*      fp;
	SC_Stream* strm;
	char       buff[3];
	char       c;
	int        i;
	int        ret;
	int        count;
	UT_SC_stream_makeTestData();

	fp   = fopen("unittest.tmp", "rb");
	strm = SC_Stream_newFileStream(fp, 5);

	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_data[count] == buff[i]);
			count++;
		}
	}
	SC_Stream_delete(strm);
}

static
void UT_SC_stream_fileReadExact(void)
{
	FILE*      fp;
	SC_Stream* strm;
	char       buff[3];
	int        i;
	int        ret;
	int        count;
	UT_SC_stream_makeTestData();

	fp   = fopen("unittest.tmp", "rb");
	strm = SC_Stream_newFileStream(fp, 5);

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

static
void UT_SC_stream_fileReadLine(void)
{
	FILE*      fp;
	SC_Stream* strm;
	char       buff[10];
	int        ret;
	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" };

	int count = 0;

	UT_SC_stream_makeTestData2(data, strlen(data));

	fp   = fopen("unittest.tmp", "rb");
	strm = SC_Stream_newFileStream(fp, 2);

	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_fileReadLine_fewbuff(void)
{
	FILE*      fp;
	SC_Stream* strm;
	char       buff[2];
	int        ret;
	const char data[]
		= "abc\rabc\r\nabc\nabc\r\rabc\n\nabc\r\n\r\nabc";

	UT_SC_stream_makeTestData2(data, strlen(data));

	fp   = fopen("unittest.tmp", "rb");
	strm = SC_Stream_newFileStream(fp, 2);

	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_fileLimitedRead(void)
{
	FILE*      fp;
	SC_Stream* strm;
	char       buff[4];
	int        ret;
	const char data[]
		= "abcdefghijklmnopqrstuvwxyz";

	UT_SC_stream_makeTestData2(data, strlen(data));

	fp   = fopen("unittest.tmp", "rb");
	strm = SC_Stream_newFileStream(fp, 6);

	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_fileLimitedRead_fewbuff(void)
{
	FILE*      fp;
	SC_Stream* strm;
	char       buff[4];
	int        ret;
	const char data[]
		= "abcdefghijklmnopqrstuvwxyz";

	UT_SC_stream_makeTestData2(data, strlen(data));

	fp   = fopen("unittest.tmp", "rb");
	strm = SC_Stream_newFileStream(fp, 6);

	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_fileWritec(void)
{
	int        ret;
	bool       result;
	FILE*      fp;
	SC_Stream* wStrm;
	SC_Stream* rStrm;
	char       c;
	int        i;

	remove("unittest.tmp");
	fp    = fopen("unittest.tmp", "wb");
	wStrm = SC_Stream_newFileStream(fp, 5);

	for (i = 0; i < strlen(UT_SC_stream_data); i++)
	{
		ret = wStrm->writec(wStrm, UT_SC_stream_data[i]);
		SC_assertNumber(1, ret);
	}
	result = wStrm->close(wStrm);
	SC_assert(result);
	SC_Stream_delete(wStrm);

	fp   = fopen("unittest.tmp", "rb");
	rStrm = SC_Stream_newFileStream(fp, 5);
	for (i = 0; i < strlen(UT_SC_stream_data); i++)
	{
		ret = rStrm->readc(rStrm, &c);
		SC_assertNumber(1, ret);
		SC_assert(UT_SC_stream_data[i] == c);
	}
	SC_Stream_delete(rStrm);
}

static
void UT_SC_stream_fileWrite(void)
{
	int        ret;
	bool       result;
	FILE*      fp;
	SC_Stream* wStrm;
	SC_Stream* rStrm;
	char       c;
	int        i;
	size_t     len;

	remove("unittest.tmp");
	fp     = fopen("unittest.tmp", "wb");
	wStrm  = SC_Stream_newFileStream(fp, 5);
	len    = strlen(UT_SC_stream_data);
	ret    = wStrm->write(wStrm, UT_SC_stream_data, len);
	SC_assertNumber(len, ret);
	result = wStrm->close(wStrm);
	SC_assert(result);
	SC_Stream_delete(wStrm);

	fp    = fopen("unittest.tmp", "rb");
	rStrm = SC_Stream_newFileStream(fp, 5);
	for (i = 0; i < strlen(UT_SC_stream_data); i++)
	{
		ret = rStrm->readc(rStrm, &c);
		SC_assertNumber(1, ret);
		SC_assert(UT_SC_stream_data[i] == c);
	}
	SC_Stream_delete(rStrm);
}

static
void UT_SC_stream_fileWriteExact(void)
{
	int        ret;
	bool       result;
	FILE*      fp;
	SC_Stream* wStrm;
	SC_Stream* rStrm;
	char       c;
	int        i;
	size_t     len;

	remove("unittest.tmp");
	fp     = fopen("unittest.tmp", "wb");
	wStrm  = SC_Stream_newFileStream(fp, 5);
	len    = strlen(UT_SC_stream_data);
	ret    = wStrm->writeExact(wStrm, UT_SC_stream_data, len);
	SC_assertNumber(len, ret);
	result = wStrm->close(wStrm);
	SC_assert(result);
	SC_Stream_delete(wStrm);

	fp    = fopen("unittest.tmp", "rb");
	rStrm = SC_Stream_newFileStream(fp, 5);
	for (i = 0; i < strlen(UT_SC_stream_data); i++)
	{
		ret = rStrm->readc(rStrm, &c);
		SC_assertNumber(1, ret);
		SC_assert(UT_SC_stream_data[i] == c);
	}
	SC_Stream_delete(rStrm);
}

static
void UT_SC_stream_fileClose(void)
{
	int        ret;
	bool       result;
	FILE*      fp;
	SC_Stream* wStrm;
	SC_Stream* rStrm;
	char       c;
	int        i;
	size_t     len;

	remove("unittest.tmp");
	fp     = fopen("unittest.tmp", "wb");
	wStrm  = SC_Stream_newFileStream(fp, 5);
	len    = strlen(UT_SC_stream_data);
	ret    = wStrm->write(wStrm, UT_SC_stream_data, len);
	SC_assertNumber(len, ret);
	result = wStrm->close(wStrm);
	SC_assert(result);
	wStrm->close(wStrm);
	SC_Stream_delete(wStrm);

	fp    = fopen("unittest.tmp", "rb");
	rStrm = SC_Stream_newFileStream(fp, 5);
	for (i = 0; i < strlen(UT_SC_stream_data); i++)
	{
		ret = rStrm->readc(rStrm, &c);
		SC_assertNumber(1, ret);
		SC_assert(UT_SC_stream_data[i] == c);
	}
	rStrm->close(rStrm);
	SC_Stream_delete(rStrm);
}

static
void UT_SC_stream_fileClose_dup(void)
{
	int        ret;
	bool       result;
	FILE*      fp;
	SC_Stream* wStrm;
	SC_Stream* rStrm;
	char       c;
	int        i;
	size_t     len;

	remove("unittest.tmp");
	fp     = fopen("unittest.tmp", "wb");
	wStrm  = SC_Stream_newFileStream(fp, 5);
	len    = strlen(UT_SC_stream_data);
	ret    = wStrm->write(wStrm, UT_SC_stream_data, len);
	SC_assertNumber(len, ret);
	result = wStrm->close(wStrm);
	SC_assert(result);
	wStrm->close(wStrm);
	SC_Stream_delete(wStrm);

	fp    = fopen("unittest.tmp", "rb");
	rStrm = SC_Stream_newFileStream(fp, 5);
	for (i = 0; i < strlen(UT_SC_stream_data); i++)
	{
		ret = rStrm->readc(rStrm, &c);
		SC_assertNumber(1, ret);
		SC_assert(UT_SC_stream_data[i] == c);
	}
	result = rStrm->close(rStrm);
	SC_assert(result);
	result = rStrm->close(rStrm);
	SC_assert(!result);
	SC_Stream_delete(rStrm);
}
