#include <string.h>
#include <sc_unittest.h>
#include <sc_mmgr.h>
#include <sc_map.h>

#define UT_SC_MAP_DATA_SIZE (21)
typedef struct {
	const char* key;
	const char* val;
} UT_SC_Map_KeyAndVal;
static UT_SC_Map_KeyAndVal UT_SC_Map_datas[UT_SC_MAP_DATA_SIZE] =
{
	{ "a"			, "val1(a)"				},	/* 0	*/
	{ "b"			, "val2(b)"				},	/* 1	*/
	{ "c"			, "val3(c)"				},	/* 2	*/
	{ "a1"			, "val4(a1)"			},	/* 3	*/
	{ "a2"			, "val5(a2)"			},	/* 4	*/
	{ "a3"			, "val6(a3)"			},	/* 5	*/
	{ "b1"			, "val7(b1)"			},	/* 6	*/
	{ "b2"			, "val8(b2)"			},	/* 7	*/
	{ "b3"			, "val9(b3)"			},	/* 8	*/
	{ "d" 			, "val10(d)"			},	/* 9	*/
	{ "abcdefg"		, "val11(abcdefg)"		},	/* 10	*/
	{ "xyz"			, "val12(xyz)"			},	/* 11	*/
	{ "a1"			, "val13(a1-overwrite)"	},	/* 12	*/
	{ "abcdef"		, "val13(abcdef)"		},	/* 13	*/
	{ "zzz"			, "val14(zzz)"			},	/* 14	*/
	{ "@"			, "val16(@)"			},	/* 15	*/
	{ "日本語"		, "val17(日本語)"		},	/* 16	*/
	{ "&\r\n"		, "val19(&\\r\\n)"		},	/* 17	*/
	{ "&"			, "val20(&)"			},	/* 18	*/
	{ " "			, "val21( )"			},	/* 19	*/
	{ ""			, "val22()"				}	/* 20	*/
};
static int  UT_SC_map_handler_counter    = 0;
static bool UT_SC_map_handler_isContinue = true;


static void UT_SC_map_new(void);
static void UT_SC_map_delete(void);
static void UT_SC_map_hashCode(void);
static void UT_SC_map_put(void);
static void UT_SC_map_put_dup(void);
static void UT_SC_map_put_tblOver(void);
static void UT_SC_map_put_tblOverDup(void);
static void UT_SC_map_putStr(void);
static void UT_SC_map_get(void);
static void UT_SC_map_get_noData(void);
static void UT_SC_map_get_noTarget(void);
static void UT_SC_map_getStr(void);
static void UT_SC_map_getStr_noData(void);
static void UT_SC_map_getStr_noTarget(void);
static void UT_SC_map_remove(void);
static void UT_SC_map_remove_noData(void);
static void UT_SC_map_remove_noTarget(void);
static void UT_SC_map_clear(void);
static void UT_SC_map_entries(void);


static bool UT_SC_map_handler(char* key, void* val, size_t size);


void UT_regist_sc_map(void)
{
	SC_Unittest_add("SC_map_new"				, UT_SC_map_new);
	SC_Unittest_add("SC_map_delete"      	, UT_SC_map_delete);
	SC_Unittest_add("SC_map_hashCode"    	, UT_SC_map_hashCode);
	SC_Unittest_add("SC_map_put"				, UT_SC_map_put);
	SC_Unittest_add("SC_map_put_dup"			, UT_SC_map_put_dup);
	SC_Unittest_add("SC_map_put_tblOver"		, UT_SC_map_put_tblOver);
	SC_Unittest_add("SC_map_put_tblOverDup"	, UT_SC_map_put_tblOverDup);
	SC_Unittest_add("SC_map_putStr"			, UT_SC_map_putStr);
	SC_Unittest_add("SC_map_get"				, UT_SC_map_get);
	SC_Unittest_add("SC_map_get_noData"		, UT_SC_map_get_noData);
	SC_Unittest_add("SC_map_get_noTarget"	, UT_SC_map_get_noTarget);
	SC_Unittest_add("SC_map_getStr"			, UT_SC_map_getStr);
	SC_Unittest_add("SC_map_getStr_noData"	, UT_SC_map_getStr_noData);
	SC_Unittest_add("SC_map_getStr_noTarget"	, UT_SC_map_getStr_noTarget);
	SC_Unittest_add("SC_map_remove"			, UT_SC_map_remove);
	SC_Unittest_add("SC_map_remove_noData"	, UT_SC_map_remove_noData);
	SC_Unittest_add("SC_map_remove_noTarget"	, UT_SC_map_remove_noTarget);
	SC_Unittest_add("SC_map_clear"			, UT_SC_map_clear);
	SC_Unittest_add("SC_map_entries"			, UT_SC_map_entries);

}


static
void UT_SC_map_new(void)
{
	SC_Map* map = SC_Map_new(0);
	SC_assert(map != NULL);
	SC_Map_delete(map);
}

static
void UT_SC_map_delete(void)
{
	SC_Map* map = SC_Map_new(100);
	SC_assert(map != NULL);
	SC_Map_delete(map);
}

static
void UT_SC_map_hashCode(void)
{
	int i, j;
	int dupCount = 0;
	int code[UT_SC_MAP_DATA_SIZE];
	int tmpCode;
	for (i = 0; i < UT_SC_MAP_DATA_SIZE; i++)
	{
		code[i] = SC_Map_hashCode(UT_SC_Map_datas[i].key);
	}

	/* ハッシュコードが重複している数をカウント	*/
	for (i = 0; i < UT_SC_MAP_DATA_SIZE; i++)
	{
		tmpCode = code[i];
		for (j = (i + 1); j < UT_SC_MAP_DATA_SIZE; j++)
		{
			if (tmpCode == code[j])
			{
				dupCount++;
			}
		}
	}
	/* 重なり率が20%以下ならよしとする	*/
	SC_assert(dupCount < (UT_SC_MAP_DATA_SIZE / 5));
}

static
void UT_SC_map_put(void)
{
	int     i;
	size_t  size;
	char*   data;
	SC_Map* map = SC_Map_new(100);
	for (i = 0; i < 10; i++)
	{
		map->put(map,
				UT_SC_Map_datas[i].key,
				UT_SC_Map_datas[i].val,
				strlen(UT_SC_Map_datas[i].val) + 1);
	}
	SC_assertNumber(10, map->size);
	for (i = 0; i < 10; i++)
	{
		data = (char*) map->get(map, UT_SC_Map_datas[i].key, &size);
		SC_assertNumber(strlen(UT_SC_Map_datas[i].val) + 1, size);
		SC_assertString(UT_SC_Map_datas[i].val, data);
	}
	SC_Map_delete(map);

}

static
void UT_SC_map_put_dup(void)
{
	int     i;
	size_t  size;
	char*   data;
	SC_Map* map = SC_Map_new(100);
	for (i = 0; i < UT_SC_MAP_DATA_SIZE; i++)
	{
		map->put(map,
				UT_SC_Map_datas[i].key,
				UT_SC_Map_datas[i].val,
				strlen(UT_SC_Map_datas[i].val) + 1);
	}
	/* 1つは同じキーのためサイズは -1	*/
	SC_assertNumber(UT_SC_MAP_DATA_SIZE - 1, map->size);

	for (i = 0; i < UT_SC_MAP_DATA_SIZE; i++)
	{
		data = (char*) map->get(map, UT_SC_Map_datas[i].key, &size);
		if (i == 3)
		{	/* 4つめのデータは13番目のデータで上書き	*/
			SC_assertNumber(strlen(UT_SC_Map_datas[12].val) + 1, size);
			SC_assertString(UT_SC_Map_datas[12].val, data);
		}
		else
		{
			SC_assertNumber(strlen(UT_SC_Map_datas[i].val) + 1, size);
			SC_assertString(UT_SC_Map_datas[i].val, data);
		}
	}
	SC_Map_delete(map);
}

static
void UT_SC_map_put_tblOver(void)
{
	int    i;
	char*  data;
	size_t size;
	SC_Map* map;
	map = SC_Map_new(5);
	for (i = 0; i < 10; i++)
	{
		map->put(map,
				UT_SC_Map_datas[i].key,
				UT_SC_Map_datas[i].val,
				strlen(UT_SC_Map_datas[i].val) + 1);
	}
	SC_assertNumber(10, map->size);
	for (i = 0; i < 10; i++)
	{
		data = (char*) map->get(map, UT_SC_Map_datas[i].key, &size);
		SC_assertNumber(strlen(UT_SC_Map_datas[i].val) + 1, size);
		SC_assertString(UT_SC_Map_datas[i].val, data);
	}
	SC_Map_delete(map);
}

static
void UT_SC_map_put_tblOverDup(void)
{
	int     i;
	size_t  size;
	char*   data;
	SC_Map* map = SC_Map_new(1);
	for (i = 0; i < UT_SC_MAP_DATA_SIZE; i++)
	{
		map->put(map,
				UT_SC_Map_datas[i].key,
				UT_SC_Map_datas[i].val,
				strlen(UT_SC_Map_datas[i].val) + 1);
	}
	/* 1つは同じキーのためサイズは -1	*/
	SC_assertNumber(UT_SC_MAP_DATA_SIZE - 1, map->size);

	for (i = 0; i < UT_SC_MAP_DATA_SIZE; i++)
	{
		data = (char*) map->get(map, UT_SC_Map_datas[i].key, &size);
		if (i == 3)
		{	/* 4つめのデータは13番目のデータで上書き	*/
			SC_assertNumber(strlen(UT_SC_Map_datas[12].val) + 1, size);
			SC_assertString(UT_SC_Map_datas[12].val, data);
		}
		else
		{
			SC_assertNumber(strlen(UT_SC_Map_datas[i].val) + 1, size);
			SC_assertString(UT_SC_Map_datas[i].val, data);
		}
	}
	SC_Map_delete(map);
}

static
void UT_SC_map_putStr(void)
{
	int     i;
	char*   data;
	SC_Map* map = SC_Map_new(100);
	for (i = 0; i < 10; i++)
	{
		map->putStr(map,
				UT_SC_Map_datas[i].key,
				UT_SC_Map_datas[i].val);
	}
	SC_assertNumber(10, map->size);
	for (i = 0; i < 10; i++)
	{
		data = map->getStr(map, UT_SC_Map_datas[i].key);
		SC_assertString(UT_SC_Map_datas[i].val, data);
	}
	SC_Map_delete(map);

}
static
void UT_SC_map_get(void)
{
	int     i;
	size_t  size;
	char*   data;
	SC_Map* map = SC_Map_new(100);
	for (i = 0; i < 10; i++)
	{
		map->put(map,
				UT_SC_Map_datas[i].key,
				UT_SC_Map_datas[i].val,
				strlen(UT_SC_Map_datas[i].val) + 1);
	}
	SC_assertNumber(10, map->size);
	for (i = 0; i < 10; i++)
	{
		data = (char*) map->get(map, UT_SC_Map_datas[i].key, &size);
		SC_assertNumber(strlen(UT_SC_Map_datas[i].val) + 1, size);
		SC_assertString(UT_SC_Map_datas[i].val, data);
	}
	SC_Map_delete(map);
}

static
void UT_SC_map_get_noData(void)
{
	size_t  size;
	char*   data;
	SC_Map* map = SC_Map_new(100);
	SC_assertNumber(0, map->size);
	data = (char*) map->get(map, "sample", &size);
	SC_assert(data == NULL);
	SC_Map_delete(map);
}

static
void UT_SC_map_get_noTarget(void)
{
	int     i;
	size_t  size;
	char*   data;
	SC_Map* map = SC_Map_new(100);
	for (i = 0; i < 10; i++)
	{
		map->put(map,
				UT_SC_Map_datas[i].key,
				UT_SC_Map_datas[i].val,
				strlen(UT_SC_Map_datas[i].val) + 1);
	}
	SC_assertNumber(10, map->size);
	data = (char*) map->get(map, "sample", &size);
	SC_assert(data == NULL);
	SC_Map_delete(map);
}

static
void UT_SC_map_getStr(void)
{
	int     i;
	char*   data;
	SC_Map* map = SC_Map_new(100);
	for (i = 0; i < 10; i++)
	{
		map->putStr(map,
				UT_SC_Map_datas[i].key,
				UT_SC_Map_datas[i].val);
	}
	SC_assertNumber(10, map->size);
	for (i = 0; i < 10; i++)
	{
		data = map->getStr(map, UT_SC_Map_datas[i].key);
		SC_assertString(UT_SC_Map_datas[i].val, data);
	}
	SC_Map_delete(map);
}

static
void UT_SC_map_getStr_noData(void)
{
	char*   data;
	SC_Map* map = SC_Map_new(100);
	SC_assertNumber(0, map->size);
	data = map->getStr(map, "sample");
	SC_assert(data == NULL);
	SC_Map_delete(map);
}

static
void UT_SC_map_getStr_noTarget(void)
{
	int     i;
	char*   data;
	SC_Map* map = SC_Map_new(100);
	for (i = 0; i < 10; i++)
	{
		map->put(map,
				UT_SC_Map_datas[i].key,
				UT_SC_Map_datas[i].val,
				strlen(UT_SC_Map_datas[i].val) + 1);
	}
	SC_assertNumber(10, map->size);
	data = map->getStr(map, "sample");
	SC_assert(data == NULL);
	SC_Map_delete(map);
}

static
void UT_SC_map_remove(void)
{
	int     i;
	SC_Map* map = SC_Map_new(5);
	for (i = 0; i < 10; i++)
	{
		map->put(map,
				UT_SC_Map_datas[i].key,
				UT_SC_Map_datas[i].val,
				strlen(UT_SC_Map_datas[i].val) + 1);
	}
	SC_assertNumber(10, map->size);
	for (i = 9; i >= 0; i--)
	{
		map->remove(map, UT_SC_Map_datas[i].key);
		SC_assertNumber(i, map->size);
	}
	SC_Map_delete(map);
}

static
void UT_SC_map_remove_noData(void)
{
	SC_Map* map = SC_Map_new(100);
	SC_assertNumber(0, map->size);
	map->remove(map, "sample");
	SC_Map_delete(map);
}

static
void UT_SC_map_remove_noTarget(void)
{
	int     i;
	SC_Map* map = SC_Map_new(5);
	for (i = 0; i < 10; i++)
	{
		map->put(map,
				UT_SC_Map_datas[i].key,
				UT_SC_Map_datas[i].val,
				strlen(UT_SC_Map_datas[i].val) + 1);
	}
	SC_assertNumber(10, map->size);
	map->remove(map, "sample");
	SC_assertNumber(10, map->size);
	SC_Map_delete(map);
}

static
void UT_SC_map_clear(void)
{
	int     i;
	SC_Map* map = SC_Map_new(5);
	for (i = 0; i < 10; i++)
	{
		map->put(map,
				UT_SC_Map_datas[i].key,
				UT_SC_Map_datas[i].val,
				strlen(UT_SC_Map_datas[i].val) + 1);
	}
	SC_assertNumber(10, map->size);
	map->clear(map);
	SC_assertNumber(0, map->size);
	SC_Map_delete(map);
}

static
bool UT_SC_map_handler(char* key, void* val, size_t size)
{
	UT_SC_map_handler_counter++;
	return UT_SC_map_handler_isContinue;
}
static
void UT_SC_map_entries(void)
{
	int     i;
	SC_Map* map = SC_Map_new(5);
	for (i = 0; i < 10; i++)
	{
		map->put(map,
				UT_SC_Map_datas[i].key,
				UT_SC_Map_datas[i].val,
				strlen(UT_SC_Map_datas[i].val) + 1);
	}
	SC_assertNumber(10, map->size);

	UT_SC_map_handler_counter    = 0;
	UT_SC_map_handler_isContinue = true;
	map->entries(map, UT_SC_map_handler);
	SC_assertNumber(10, UT_SC_map_handler_counter);

	UT_SC_map_handler_counter    = 0;
	UT_SC_map_handler_isContinue = false;
	map->entries(map, UT_SC_map_handler);
	SC_assertNumber(1, UT_SC_map_handler_counter);

	SC_Map_delete(map);
}
