Newer
Older
libkc / modules / test / src / test_map.c
#include <stdio.h>
#include <string.h>

#include <kc.h>
#include <kc_ut.h>
#include <kc_assert.h>
#include <kc_map.h>
#include <kc_memory.h>

#include "ut.h"

// プロトタイプ宣言
static void test_map_new(void);
static void test_map_put(void);
static void test_map_remove(void);
static void test_map_entries(void);
static void test_map_malloc_error(void);

/**
 * KcMap 単体テストスイート
 */
void suite_map(void)
{
    KcUt *ut = KcUt_get_instance();
    ut->add(ut, UT_TESTCASE, "map new/delete", test_map_new);
    ut->add(ut, UT_TESTCASE, "map put/get", test_map_put);
    ut->add(ut, UT_TESTCASE, "map remove", test_map_remove);
    ut->add(ut, UT_TESTCASE, "map entries", test_map_entries);
    ut->add(ut, UT_TESTCASE, "map malloc error", test_map_malloc_error);
}

/**
 * Map 生成/破棄。
 *
 * @process KcMap_new を実行する。。
 * @result KcMap が生成されること。
 *
 * @process KcMap_delete にて Map を破棄する。
 * @result Map が破棄されること。
 */
static void test_map_new(void)
{
    KcMap *map = KcMap_new(0);
    assert_not_null(map);
    KcMap_delete(map);

    map = KcMap_new(65538);
    assert_not_null(map);
    KcMap_delete(map);

    // map にデータが残った状態での削除
    map = KcMap_new(10);
    assert_not_null(map);
    map->put(map, "key1", "value1", 7);
    KcMap_delete(map);
}

/**
 * Map への追加/取得。
 */
static void test_map_put(void)
{
    KcMap *map = KcMap_new(5);
    assert_not_null(map);

    const char *keys[] = {
        "key1", "key2", "key3", "key4", "key5",
        "key6", "key7", "key8", "key9", "key10",
        "key11", "key12", "key13", "key14", "key15"};
    const char *vals[] = {
        "val1", "val2", "val3", "val4", "val5",
        "val6", "val7", "val8", "val9", "val10",
        "val11", "val12", "val13", "val14", "val15"};

    char *res;
    for (int i = 0; i < (int)(sizeof(keys) / sizeof(const char *)); i++)
    {
        res = (char *)map->put(map, keys[i], vals[i], strlen(vals[i]) + 1);
        assert_equals(vals[i], (const char *)res);
    }

    // 値取得
    for (int i = 0; i < (int)(sizeof(keys) / sizeof(const char *)); i++)
    {
        size_t size;
        const char *value = (const char *)map->get(map, keys[i], &size);
        assert_equals(vals[i], value);
    }

    // 存在しないキーの値取得
    void *ptr = map->get(map, "ABC", NULL);
    assert_null(ptr);

    // キー上書き登録
    res = (char *)map->put(map, "key10", "abcdefg", strlen("abcdefg") + 1);
    assert_equals("abcdefg", (const char *)res);
    res = (char *)map->get(map, "key10", NULL);
    assert_equals("abcdefg", (const char *)res);

    KcMap_delete(map);
}

/**
 * Map からの削除/サイズ確認。
 */
static void test_map_remove(void)
{
    KcMap *map = KcMap_new(3);
    assert_not_null(map);

    const char *keys[] = {
        "key1", "key2", "key3", "key4", "key5",
        "key6", "key7", "key8", "key9", "key10",
        "key11", "key12", "key13", "key14", "key15"};
    const char *vals[] = {
        "val1", "val2", "val3", "val4", "val5",
        "val6", "val7", "val8", "val9", "val10",
        "val11", "val12", "val13", "val14", "val15"};

    char *res;
    for (int i = 0; i < (int)(sizeof(keys) / sizeof(const char *)); i++)
    {
        res = (char *)map->put(map, keys[i], vals[i], strlen(vals[i]) + 1);
        assert_equals(vals[i], (const char *)res);
    }

    int size_counter = 14;
    map->remove(map, "key15");
    size_t size = map->size(map);
    assert_equals(size_counter, size);
    size_counter--;
    res = (char *)map->get(map, "key15", NULL);
    assert_null(res);

    map->remove(map, "key7");
    size = map->size(map);
    assert_equals(size_counter, size);
    size_counter--;
    res = (char *)map->get(map, "key7", NULL);
    assert_null(res);

    map->remove(map, "key13");
    size = map->size(map);
    assert_equals(size_counter, size);
    size_counter--;
    res = (char *)map->get(map, "key13", NULL);
    assert_null(res);

    map->remove(map, "key1");
    size = map->size(map);
    assert_equals(size_counter, size);
    size_counter--;
    res = (char *)map->get(map, "key1", NULL);
    assert_null(res);

    map->remove(map, "key2");
    size = map->size(map);
    assert_equals(size_counter, size);
    size_counter--;
    res = (char *)map->get(map, "key2", NULL);
    assert_null(res);

    map->remove(map, "key3");
    size = map->size(map);
    assert_equals(size_counter, size);
    size_counter--;
    res = (char *)map->get(map, "key3", NULL);
    assert_null(res);

    // 存在しないキー削除
    map->remove(map, "abc");
    size = map->size(map);
    assert_equals(9, size);

    KcMap_delete(map);

    // パターン2
    map = KcMap_new(3);
    assert_not_null(map);

    size_counter = 3;
    for (int i = 0; i < size_counter; i++)
    {
        res = (char *)map->put(map, keys[i], vals[i], strlen(vals[i]) + 1);
        assert_equals(vals[i], (const char *)res);
    }
    size_counter--;

    map->remove(map, "key1");
    size = map->size(map);
    assert_equals(size_counter, size);
    size_counter--;
    res = (char *)map->get(map, "key1", NULL);
    assert_null(res);

    map->remove(map, "key2");
    size = map->size(map);
    assert_equals(size_counter, size);
    size_counter--;
    res = (char *)map->get(map, "key2", NULL);
    assert_null(res);

    map->remove(map, "key3");
    size = map->size(map);
    assert_equals(size_counter, size);
    size_counter--;
    res = (char *)map->get(map, "key3", NULL);
    assert_null(res);

    KcMap_delete(map);
}

// エントリ
typedef struct UserData_
{
    int value;
} UserData;
static bool test_map_entries_handler(const char *key, const void *val, size_t size, void *args)
{
    UserData *user_data = (UserData *)args;
    user_data->value--;
    printf("key=%-5s, value=%-5s, size=%zu\n", key, (const char *)val, size);
    return (user_data->value >= 0);
}

/**
 * Map エントリ取得
 */
static void test_map_entries(void)
{
    KcMap *map = KcMap_new(5);
    assert_not_null(map);

    const char *keys[] = {
        "key1", "key2", "key3", "key4", "key5",
        "key6", "key7", "key8", "key9", "key10",
        "key11", "key12", "key13", "key14", "key15"};
    const char *vals[] = {
        "val1", "val2", "val3", "val4", "val5",
        "val6", "val7", "val8", "val9", "val10",
        "val11", "val12", "val13", "val14", "val15"};

    char *res;
    for (int i = 0; i < (int)(sizeof(keys) / sizeof(const char *)); i++)
    {
        res = (char *)map->put(map, keys[i], vals[i], strlen(vals[i]) + 1);
        assert_equals(vals[i], (const char *)res);
    }

    // entries
    UserData args = {
        .value = 10000};
    map->entries(map, test_map_entries_handler, &args);

    // entries [途中中断]
    UserData args2 = {
        .value = 5};
    map->entries(map, test_map_entries_handler, &args2);

    KcMap_delete(map);
}

/**
 * メモリ確保失敗
 */
static void test_map_malloc_error(void)
{
    // 生成時失敗
    ut_alloc_control(0)
    {
        KcMap *map = KcMap_new(5);
        assert_null(map);
    }

    // put 時失敗
    KcMap *map = KcMap_new(5);
    const char *keys[] = {
        "key1", "key2", "key3", "key4", "key5",
        "key6", "key7", "key8", "key9", "key10",
        "key11", "key12", "key13", "key14", "key15"};
    const char *vals[] = {
        "val1", "val2", "val3", "val4", "val5",
        "val6", "val7", "val8", "val9", "val10",
        "val11", "val12", "val13", "val14", "val15"};
    char *res;
    for (int i = 0; i < (int)(sizeof(keys) / sizeof(const char *)); i++)
    {
        res = (char *)map->put(map, keys[i], vals[i], strlen(vals[i]) + 1);
        assert_equals(vals[i], (const char *)res);
    }

    ut_alloc_control(0)
    {
        res = (char *)map->put(map, "abc", "def", 4);
        assert_null(res);
    }
    KcMap_delete(map);
}