#include <sc_unittest.h>
#include <sc_error.h>
#include <sc_mmgr.h>


/* 単体テストユーティリティ	*/
static void UT_SC_mInit(bool);
static void UT_SC_mHandler(SC_MMgr*);
static void UT_SC_fHandler(SC_MMgr*);
static void UT_SC_eHandler(SC_MMgr*);
static void UT_SC_entries_handler(SC_MMgr* mgr);


/* 単体テスト関数			*/
static void UT_SC_calloc(void);
static void UT_SC_malloc(void);
static void UT_SC_realloc(void);
static void UT_SC_realloc_nullPtr(void);
static void UT_SC_realloc_zeroSize(void);
static void UT_SC_realloc_deletedPtr(void);
static void UT_SC_realloc_unmngPtr(void);
static void UT_SC_free(void);
static void UT_SC_free_deletedPtr(void);
static void UT_SC_free_unmngPtr(void);
static void UT_SC_handlers(void);
static void UT_SC_handlers_free(void);
static void UT_SC_cleanup(void);
static void UT_SC_entries(void);

void UT_regist_sc_mmgr(void)
{
	SC_Unittest_add("SC_calloc"             , UT_SC_calloc);
	SC_Unittest_add("SC_malloc"             , UT_SC_malloc);
	SC_Unittest_add("SC_realloc"            , UT_SC_realloc);
	SC_Unittest_add("SC_realloc_nullPtr"    , UT_SC_realloc_nullPtr);
	SC_Unittest_add("SC_realloc_zeroSize"   , UT_SC_realloc_zeroSize);
	SC_Unittest_add("SC_realloc_deletedPtr" , UT_SC_realloc_deletedPtr);
	SC_Unittest_add("SC_realloc_unmngPtr"   , UT_SC_realloc_unmngPtr);
	SC_Unittest_add("SC_free"               , UT_SC_free);
	SC_Unittest_add("SC_free_deletedPtr"    , UT_SC_free_deletedPtr);
	SC_Unittest_add("SC_free_unmngPtr"      , UT_SC_free_unmngPtr);
	SC_Unittest_add("SC_handlers"           , UT_SC_handlers);
	SC_Unittest_add("SC_handlers_free"      , UT_SC_handlers_free);
	SC_Unittest_add("SC_MMgr_cleanup"       , UT_SC_cleanup);
	SC_Unittest_add("SC_MMgr_entries"       , UT_SC_entries);

}


/* ハンドラが実行された際の引数を保持するための変数	*/
#define UT_SC_MMGR_MAX_STACK_SIZE (1024)
static int UT_SC_entries_count = 0;
static int UT_SC_MMgr_msize = 0;
static int UT_SC_MMgr_fsize = 0;
static int UT_SC_MMgr_esize = 0;
static SC_MMgr* UT_SC_MMgr_mStack[UT_SC_MMGR_MAX_STACK_SIZE];
static SC_MMgr* UT_SC_MMgr_fStack[UT_SC_MMGR_MAX_STACK_SIZE];
static SC_MMgr* UT_SC_MMgr_eStack[UT_SC_MMGR_MAX_STACK_SIZE];

static
void UT_SC_mInit(bool isSetHandler)
{
	UT_SC_MMgr_msize = 0;
	UT_SC_MMgr_fsize = 0;
	UT_SC_MMgr_esize = 0;
	if (isSetHandler)
	{
		SC_MMgr_setHandler(UT_SC_mHandler, UT_SC_fHandler, UT_SC_eHandler);
	}
	else
	{
		SC_MMgr_setHandler(NULL, NULL, NULL);
	}
}

static
void UT_SC_mHandler(SC_MMgr* mmgr)
{
	if (UT_SC_MMgr_msize < UT_SC_MMGR_MAX_STACK_SIZE)
	{
		UT_SC_MMgr_mStack[UT_SC_MMgr_msize] = mmgr;
		UT_SC_MMgr_msize++;
	}
}

static
void UT_SC_fHandler(SC_MMgr* mmgr)
{
	if (UT_SC_MMgr_fsize < UT_SC_MMGR_MAX_STACK_SIZE)
	{
		UT_SC_MMgr_fStack[UT_SC_MMgr_fsize] = mmgr;
		UT_SC_MMgr_fsize++;
	}
}

static
void UT_SC_eHandler(SC_MMgr* mmgr)
{
	if (UT_SC_MMgr_esize < UT_SC_MMGR_MAX_STACK_SIZE)
	{
		UT_SC_MMgr_eStack[UT_SC_MMgr_esize] = mmgr;
		UT_SC_MMgr_esize++;
	}
}

static
void UT_SC_malloc(void)
{
	int  i;
	int* ptr = (int*) malloc(1024*sizeof(int));
	SC_assert(ptr != NULL);
	for (i = 0; i < 1024; i++)
	{
		ptr[i] = i;
	}
	for (i = 0; i < 1024; i++)
	{
		SC_assertNumber(ptr[i], i);
	}
	free(ptr);
}

static
void UT_SC_calloc(void)
{
	int  i;
	int* ptr = (int*) calloc(1024, sizeof(int));
	SC_assert(ptr != NULL);
	for (i = 0; i < 1024; i++)
	{
		ptr[i] = i;
	}
	for (i = 0; i < 1024; i++)
	{
		SC_assertNumber(ptr[i], i);
	}
	free(ptr);
}

static
void UT_SC_realloc(void)
{
	int i;
	char* ptr  = (char*) malloc(10);
	char* ptrr = (char*) realloc(ptr, 20);

	for (i = 0; i < 20; i++)
	{
		ptrr[i] = 'A';
	}

	for (i = 0; i < 20; i++)
	{
		SC_assert(ptrr[i] == 'A');
	}

	free(ptrr);
}

static
void UT_SC_realloc_nullPtr(void)
{
	char* ptr = (char*) realloc(NULL, 10);
	free(ptr);
}

static
void UT_SC_realloc_zeroSize(void)
{
	char* ptr  = (char*) malloc(10);
	char* ptrr = (char*) realloc(ptr, 0);
	free(ptrr);
}

static
void UT_SC_realloc_deletedPtr(void)
{
	char* ptr    = (char*) malloc(10);
	SC_MMgr* mng = (SC_MMgr*) ptr;
	mng--;
	mng->_mark   = SC_MMgr_DELETED;
	char* ptrr   = (char*) realloc(ptr, 20);
	free(ptrr);
}

static
void UT_SC_realloc_unmngPtr(void)
{
	char* ptr    = (char*) SC_realMalloc(10);
	char* ptrr   = (char*) realloc(ptr, 20);
	free(ptrr);
}

static
void UT_SC_free(void)
{
	char* ptr = (char*) malloc(10);
	free(ptr);
}

static
void UT_SC_free_deletedPtr(void)
{
	char* ptr    = (char*) malloc(10);
	SC_MMgr* mng = (SC_MMgr*) ptr;
	mng--;
	mng->_mark   = SC_MMgr_DELETED;
	free(ptr);

	/* free */
	mng->_mark   = SC_MMgr_ALLOCATED;
	free(ptr);
}

static
void UT_SC_free_unmngPtr(void)
{
	char* ptr = (char*) SC_realMalloc(10);
	free(ptr);
}

static
void UT_SC_handlers(void)
{
	char* ptr;
	UT_SC_mInit(false);
	UT_SC_mInit(true);
	ptr = (char*) malloc(10);
	free(ptr);

}

static
void UT_SC_handlers_free(void)
{
	char* ptr    = (char*) malloc(10);
	SC_MMgr* mng = (SC_MMgr*) ptr;
	UT_SC_mInit(false);
	UT_SC_mInit(true);
	mng--;
	mng->_mark   = SC_MMgr_DELETED;
	free(ptr);

	/* free */
	mng->_mark   = SC_MMgr_ALLOCATED;
	free(ptr);
}

static
void UT_SC_entries_handler(SC_MMgr* mgr)
{
	UT_SC_entries_count++;
}


static
void UT_SC_cleanup(void)
{
	char* ptr;
	/* 全管理メモリクリア			*/
	SC_MMgr_cleanup(NULL, -1);

#line 264
	ptr = (char*) malloc(10);

	/* 行番号が異なる場合			*/
	SC_MMgr_cleanup("src/ut_sc_mmgr.c", 1);
	UT_SC_entries_count = 0;
	SC_MMgr_entries(UT_SC_entries_handler);
	SC_assertNumber(1, UT_SC_entries_count);

	/* 行番号が一致する場合			*/
	SC_MMgr_cleanup("src/ut_sc_mmgr.c", 264);
	UT_SC_entries_count = 0;
	SC_MMgr_entries(UT_SC_entries_handler);
	SC_assertNumber(0, UT_SC_entries_count);

	/* ファイル名のみ指定する場合	*/
	ptr = (char*) malloc(10);
	SC_MMgr_cleanup("src/ut_sc_mmgr.c", -1);
	UT_SC_entries_count = 0;
	SC_MMgr_entries(UT_SC_entries_handler);
	SC_assertNumber(0, UT_SC_entries_count);
}

static
void UT_SC_entries(void)
{
	char* ptr;
	ptr = (char*) malloc(10);
	UT_SC_entries_count = 0;
	SC_MMgr_entries(UT_SC_entries_handler);
	SC_assertNumber(1, UT_SC_entries_count);
	free(ptr);
}

