#include <stdio.h>
#include <string.h>
#include <kc.h>
#include <kc_assert.h>
#include <kc_ut.h>
#include <kc_memory.h>
#include "ut.h"
// プロトタイプ宣言
static void test_memory_start(void);
static void test_memory_dump(void);
static void test_memory_set_listener(void);
static void test_memory_entries(void);
static void test_memory_freeif(void);
static void test_memory_aligned(void);
static void test_memory_calloc(void);
static void test_memory_realloc(void);
static void test_memory_raw_xxxxx(void);
/**
* memory_mark 単体テストスイート
*/
void suite_memory(void)
{
KcUt *ut = KcUt_get_instance();
ut->add(ut, UT_TESTCASE, "memory start", test_memory_start);
ut->add(ut, UT_TESTCASE, "memory dump", test_memory_dump);
ut->add(ut, UT_TESTCASE, "memory set_listener", test_memory_set_listener);
ut->add(ut, UT_TESTCASE, "memory entries", test_memory_entries);
ut->add(ut, UT_TESTCASE, "memory freeif", test_memory_freeif);
ut->add(ut, UT_TESTCASE, "memory aligned", test_memory_aligned);
ut->add(ut, UT_TESTCASE, "memory calloc", test_memory_calloc);
ut->add(ut, UT_TESTCASE, "memory realloc", test_memory_realloc);
ut->add(ut, UT_TESTCASE, "memory raw_xxxxx", test_memory_raw_xxxxx);
}
/**
* メモリ管理開始。
*
* @process メモリ管理開始(情報詳細出力あり)
* @process メモリ管理開始(情報詳細出力無し)
*/
static void test_memory_start(void)
{
// NOP
// ut.c にて、下記実施
// KcMemory_start(false);
// KcMemory_start(true);
}
extern void KcMemory_dump_leak(void);
static bool test_memory_dump_handler(const char *data)
{
printf("%s", data);
return true;
}
/**
* 確保中のメモリ情報出力。
*
* @process dump を実行する。
* @result 確保中のメモリ情報が出力されること。
*
* @param dump_leak を実行する。
* @result メモリリーク情報が出力されること。
*
* @process 確保しているメモリがない状態で dump を実行する。
* @result メモリ情報が出力されないこと。
*
* @process 出力用ハンドラを指定してメモリをダンプする。
* @result ハンドラに対してメモリ情報が渡されること。
*/
static void test_memory_dump(void)
{
int *val = (int *)malloc(sizeof(int));
*val = 10;
printf("---DUMP---\n");
KcMemory_dump();
printf("---DUMP LEAK---\n");
KcMemory_dump_leak();
free(val);
printf("---DUMP---\n");
KcMemory_dump();
val = (int *)malloc(sizeof(int));
*val = 20;
kc_memory_manager->dump(
test_memory_dump_handler, 16, true, true, 8192);
free(val);
}
/**
* リスナ設定(NULL指定)。
*
* @process リスナを登録する。(NULL指定)
* @result リスナが設定されないこと。
*/
static void test_memory_set_listener(void)
{
KcMemoryListener listener;
listener.allocate = NULL;
listener.free = NULL;
listener.error = NULL;
kc_memory_manager->set_listener(&listener);
}
// ハンドラ実行用
static int test_memory_entries_handler_counter = 0;
static int test_memory_entries_handler_values[10];
static int test_memory_entries_handler_can_loop = 0;
static bool test_memory_entries_handler(const KcMemoryEntry *entry, void *info)
{
assert_equals(
test_memory_entries_handler_values[test_memory_entries_handler_counter],
*((int *)entry->data));
test_memory_entries_handler_counter++;
test_memory_entries_handler_can_loop--;
assert_equals("X", (const char *)info);
if (test_memory_entries_handler_can_loop <= 0)
{
return false;
}
return true;
}
/**
* メモリエントリハンドラ実行
*/
static void test_memory_entries(void)
{
int *val1 = (int *)malloc(sizeof(int));
int *val2 = (int *)malloc(sizeof(int));
int *val3 = (int *)malloc(sizeof(int));
*val1 = 123;
*val2 = 456;
*val3 = 789;
test_memory_entries_handler_values[0] = 123;
test_memory_entries_handler_values[1] = 456;
test_memory_entries_handler_values[2] = 789;
// 途中中断パターン
test_memory_entries_handler_counter = 0;
test_memory_entries_handler_can_loop = 2;
kc_memory_manager->entries(test_memory_entries_handler, "X");
assert_equals(2, test_memory_entries_handler_counter);
// 全てダンプパターン
test_memory_entries_handler_counter = 0;
test_memory_entries_handler_can_loop = 999;
kc_memory_manager->entries(test_memory_entries_handler, "X");
assert_equals(3, test_memory_entries_handler_counter);
free(val1);
free(val2);
free(val3);
}
bool test_memory_freeif_handler(const KcMemoryEntry *entry, void *info)
{
assert_equals("FREEIF", (const char *)info);
if (strcmp("test_memory_freeif", entry->func) == 0)
{
int *data = (int *)entry->data;
if (*data == 456)
{
return true;
}
}
return false;
}
/**
* 強制メモリ破棄
*/
static void test_memory_freeif(void)
{
int *val1 = (int *)malloc(sizeof(int));
int *val2 = (int *)malloc(sizeof(int));
int *val3 = (int *)malloc(sizeof(int));
*val1 = 123;
*val2 = 456;
*val3 = 789;
test_memory_entries_handler_values[0] = 123;
test_memory_entries_handler_values[1] = 456;
test_memory_entries_handler_values[2] = 789;
kc_memory_manager->freeif(test_memory_freeif_handler, "FREEIF");
free(val1);
// free(val2);
free(val3);
}
// メモリ確保失敗動作確認用
static int UT_Memory_can_alloc_counter = 0;
static bool UT_Memory_can_alloc(
KcMemoryEntry *entry, size_t alignment, size_t size,
KcMemoryMark mark, const char *file, const char *func, int line)
{
UNUSED_VARIABLE(entry);
UNUSED_VARIABLE(alignment);
UNUSED_VARIABLE(size);
UNUSED_VARIABLE(mark);
UNUSED_VARIABLE(file);
UNUSED_VARIABLE(func);
UNUSED_VARIABLE(line);
UT_Memory_can_alloc_counter--;
if (UT_Memory_can_alloc_counter < 0)
{
return false;
}
return true;
}
/**
* アライメント指定メモリ確保
*
* @process aligned_alloc によりメモリを確保する。
* @result メモリが確保されること。
*
* @process メモリ確保が失敗する状態で、aligned_alloc を実行する。
* @result メモリ確保に失敗し、NULL が返されること。
*/
static void test_memory_aligned(void)
{
int *val = (int *)aligned_alloc(sizeof(long long), sizeof(int));
assert_not_null(val);
*val = 123;
free(val);
UT_Memory_can_alloc_counter = 0;
_UT_KcMemory_can_alloc = UT_Memory_can_alloc;
val = (int *)aligned_alloc(sizeof(long long), sizeof(int));
assert_null(val);
_UT_KcMemory_can_alloc = NULL;
}
/**
* calloc によるメモリ確保
*
* @process calloc によりメモリを確保する。
* @result メモリが確保されること。内容がすべて 0 のこと。
*
* @process メモリ確保が失敗する状態で、calloc を実行する。
* @result メモリ確保に失敗し、NULL が返されること。
*/
static void test_memory_calloc(void)
{
int *val = (int *)calloc(10, sizeof(int));
for (int i = 0; i < 10; i++)
{
assert_equals(0, val[i]);
}
free(val);
UT_Memory_can_alloc_counter = 0;
_UT_KcMemory_can_alloc = UT_Memory_can_alloc;
val = (int *)calloc(10, sizeof(int));
assert_null(val);
_UT_KcMemory_can_alloc = NULL;
}
/**
* realloc によるメモリ確保
*
* @process NULL を指定して、realloc によりメモリを確保する。
* @result メモリが確保されること。
*
* @process メモリ確保が失敗する状態で、calloc を実行する。
* @result メモリ確保に失敗し、NULL が返されること。
*/
static void test_memory_realloc(void)
{
// NULL 指定
int *val = realloc(NULL, sizeof(int));
assert_not_null(val);
*val = 123;
free(val);
// 管理外メモリによる realloc
int *unmng_ptr = raw_malloc(sizeof(int) * 2);
unmng_ptr[0] = 123;
unmng_ptr[1] = 456;
assert_equals(123, unmng_ptr[0]);
assert_equals(456, unmng_ptr[1]);
int *mng_ptr = (int *)realloc(unmng_ptr, sizeof(int) * 3);
assert_null(mng_ptr);
free(unmng_ptr);
}
/**
* raw_xxxxx 関数動作確認。
*/
static void test_memory_raw_xxxxx(void)
{
int *ptr = (int *)raw_malloc(sizeof(int));
assert_not_null(ptr);
raw_free(ptr);
ptr = raw_aligned_alloc(sizeof(int), sizeof(int));
assert_not_null(ptr);
#if (KC_IS_WINDOWS)
_aligned_free(ptr);
#else
raw_free(ptr);
#endif
ptr = raw_calloc(10, sizeof(int));
assert_not_null(ptr);
ptr = raw_realloc(ptr, 20);
assert_not_null(ptr);
raw_free(ptr);
}