Newer
Older
libkc / modules / test / src / test_list_array.c
#include <stdio.h>
#include <errno.h>

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

// プロトタイプ宣言
static void test_list_array_new(void);
static void test_list_array_add(void);
static void test_list_array_remove(void);
static void test_list_array_set(void);
static void test_list_array_search(void);
static void test_list_array_sort(void);
static void test_list_array_malloc_error(void);

/**
 * memory_mark 単体テストスイート
 */
void suite_list_array(void)
{
    KcUt *ut = KcUt_get_instance();
    ut->add(ut, UT_TESTCASE, "list_array new ArrayList", test_list_array_new);
    ut->add(ut, UT_TESTCASE, "list_array add/get", test_list_array_add);
    ut->add(ut, UT_TESTCASE, "list_array remove", test_list_array_remove);
    ut->add(ut, UT_TESTCASE, "list_array set", test_list_array_set);
    ut->add(ut, UT_TESTCASE, "list_array search", test_list_array_search);
    ut->add(ut, UT_TESTCASE, "list_array sort", test_list_array_sort);
    ut->add(ut, UT_TESTCASE, "list_array malloc error", test_list_array_malloc_error);
}

/**
 * ArrayList 生成/破棄。
 *
 * @process KcList_new_ArrayList を実行する。。
 * @result ArrayList が生成されること。
 *
 * @process KcList_delete にて ArrayList を破棄する。
 * @result ArrayList が破棄されること。
 */
static void test_list_array_new(void)
{
    KcList *list = KcList_new_ArrayList(sizeof(int), 5);
    assert_not_null(list);
    KcList_delete(list);
}

/**
 * ArrayList データ追加/取得。
 *
 * @process 初回追加 (index = 0)
 * @process 2つめ追加 (index = 1)
 * @process 先頭に追加 (index = 0)
 * @process 末尾に追加 (index = 負値(-1))
 * @process 追加(index 不正)
 * @process 値取得(サイズ取得あり)
 * @process 値取得(サイズ取得なし)
 * @process 値取得 (index 不正)
 */
static void test_list_array_add(void)
{
    KcList *list = KcList_new_ArrayList(sizeof(int), 5);
    assert_not_null(list);

    // 空
    bool is_empty = list->is_empty(list);
    assert_true(is_empty);

    // 1つめ追加
    int val = 10;
    bool res = list->add(list, 0, &val, sizeof(int));
    assert_true(res);
    is_empty = list->is_empty(list);
    assert_false(is_empty);

    // 2つめ追加
    val = 20;
    res = list->add(list, 1, &val, sizeof(int));
    assert_true(res);

    // 先頭に追加
    val = 30;
    res = list->add(list, 0, &val, sizeof(int));
    assert_true(res);

    // 末尾に追加
    val = 40;
    res = list->add(list, -1, &val, sizeof(int));
    assert_true(res);

    // 追加不可位置への追加
    val = 50;
    res = list->add(list, 10, &val, sizeof(int));
    assert_false(res);

    // 1つめ取得
    size_t size;
    int *res_val = list->get(list, 0, &size);
    assert_equals((int)sizeof(int), (int)size);
    assert_equals(30, *res_val);

    // 2つめ取得
    res_val = list->get(list, 1, &size);
    assert_equals((int)sizeof(int), (int)size);
    assert_equals(10, *res_val);

    // 3つめ取得(サイズ取得なし)
    res_val = list->get(list, 2, NULL);
    assert_equals(20, *res_val);

    // 4つめ取得(サイズ取得なし)
    res_val = list->get(list, 3, NULL);
    assert_equals(40, *res_val);

    // 存在しないデータ取得
    res_val = list->get(list, 4, NULL);
    assert_null(res_val);

    KcList_delete(list);
}

/**
 * ArrayList データ削除。
 *
 * @process 末尾削除
 * @process 中間削除
 * @process 先頭削除
 * @process 削除(index 不正)
 * @process 残っているデータを確認
 */
static void test_list_array_remove(void)
{
    KcList *list = KcList_new_ArrayList(sizeof(int), 5);
    assert_not_null(list);

    // 値設定
    int vals[] = {10, 20, 30, 40, 50, 60, 70, 80, 90, 100, 110, 120, 130, 140, 150, 160};
    int default_size = 16;
    for (int i = 0; i < (int)(sizeof(vals) / sizeof(int)); i++)
    {
        int val = vals[i];
        bool res = list->add(list, -1, &val, sizeof(int));
        assert_true(res);
    }

    // 末尾削除 (値、サイズ取得あり)
    int rval;
    size_t rsize;
    bool ret = list->remove(list, (default_size - 1), &rval, &rsize);
    assert_true(ret);
    assert_equals(vals[(default_size - 1)], rval);
    assert_equals((int)sizeof(int), (int)rsize);
    int now_size = list->size(list);
    assert_equals((default_size - 1), now_size);

    // 値を追加して戻しておく
    list->add(list, (default_size - 1), &vals[(default_size - 1)], sizeof(int));
    now_size = list->size(list);
    assert_equals(default_size, now_size);

    // 中間削除 (値取得あり)
    // 10, 20, <30>, 40, 50, ...
    ret = list->remove(list, 2, &rval, NULL);
    assert_true(ret);
    assert_equals(vals[2], rval);
    now_size = list->size(list);
    assert_equals((default_size - 1), now_size);

    // 先頭削除 (値取得なし)
    // <10>, 20, 40, 50, ...
    ret = list->remove(list, 0, NULL, NULL);
    assert_true(ret);
    now_size = list->size(list);
    assert_equals((default_size - 2), now_size);

    // 削除(index 不正)
    ret = list->remove(list, default_size, NULL, NULL);
    assert_false(ret);

    // 残り3つになるまで削除 (3つめを削除)
    int rest_size = list->size(list);
    while (rest_size > 3)
    {
        ret = list->remove(list, 3, NULL, NULL);
        assert_true(ret);
        rest_size = list->size(list);
    }

    // 残っているデータの確認
    // 20, 40, 50
    int *res_val_1 = list->get(list, 0, NULL);
    int *res_val_2 = list->get(list, 1, NULL);
    int *res_val_3 = list->get(list, 2, NULL);
    assert_equals(20, *res_val_1);
    assert_equals(40, *res_val_2);
    assert_equals(50, *res_val_3);

    bool is_empty = list->is_empty(list);
    assert_false(is_empty);

    // クリア
    list->clear(list);
    is_empty = list->is_empty(list);
    assert_true(is_empty);

    KcList_delete(list);
}

/**
 * ArrayList データ設定。
 */
static void test_list_array_set(void)
{
    KcList *list = KcList_new_ArrayList(sizeof(int), 5);
    assert_not_null(list);

    // 値設定
    int vals[] = {10, 20, 30, 40, 50};
    for (int i = 0; i < (int)(sizeof(vals) / sizeof(int)); i++)
    {
        int val = vals[i];
        bool res = list->add(list, -1, &val, sizeof(int));
        assert_true(res);
    }
    int now_size = list->size(list);
    assert_equals(5, now_size);

    // 値設定 (元の値, サイズ取得)
    int set_value = 99;
    int orig_val;
    size_t orig_size;
    bool ret = list->set(list, 1, &set_value, sizeof(int), &orig_val, &orig_size);
    assert_true(ret);
    assert_equals(20, orig_val);
    assert_equals((int)sizeof(int), (int)orig_size);
    int *res_val = list->get(list, 1, NULL);
    assert_equals(99, *res_val);

    // 値設定 (元の値取得)
    set_value = 98;
    ret = list->set(list, 0, &set_value, sizeof(int), &orig_val, NULL);
    assert_true(ret);
    assert_equals(10, orig_val);
    res_val = list->get(list, 0, NULL);
    assert_equals(98, *res_val);

    now_size = list->size(list);
    assert_equals(5, now_size);

    KcList_delete(list);
}

/**
 * ArrayList 検索。
 */
static void test_list_array_search(void)
{
    KcList *list = KcList_new_ArrayList(sizeof(int), 5);
    assert_not_null(list);

    // 値設定
    int vals[] = {10, 30, 50, 40, 20, 10, 30, 60, 20};
    for (int i = 0; i < (int)(sizeof(vals) / sizeof(int)); i++)
    {
        int val = vals[i];
        bool res = list->add(list, -1, &val, sizeof(int));
        assert_true(res);
    }
    int now_size = list->size(list);
    assert_equals(9, now_size);

    // 値が含まれることの確認
    // index_of, last_index_of の確認
    int c_vals[] = {10, 20, 30, 40, 50, 60};
    int c_vals_index[] = {0, 4, 1, 3, 2, 7};
    int c_vals_lindex[] = {5, 8, 6, 3, 2, 7};
    bool is_contains;
    int res_index;
    int res_lindex;
    for (int i = 0; i < (int)(sizeof(c_vals) / sizeof(int)); i++)
    {
        is_contains = list->contains(list, &c_vals[i], sizeof(int));
        assert_true(is_contains);

        res_index = list->index_of(list, &c_vals[i], sizeof(int));
        assert_equals(c_vals_index[i], res_index);

        res_lindex = list->last_index_of(list, &c_vals[i], sizeof(int));
        assert_equals(c_vals_lindex[i], res_lindex);
    }

    // 値が含まれないことの確認
    int c_val = 99;
    is_contains = list->contains(list, &c_val, sizeof(int));
    assert_false(is_contains);

    res_index = list->index_of(list, &c_val, sizeof(int));
    assert_equals(-1, res_index);

    res_lindex = list->last_index_of(list, &c_val, sizeof(int));
    assert_equals(-1, res_lindex);

    KcList_delete(list);
}

// ソート用コンパレータ
static int test_list_array_sort_comparator(
    const void *element1, size_t size1,
    const void *element2, size_t size2,
    void *args)
{
    int val1 = *((int *)element1);
    int val2 = *((int *)element2);
    assert_equals((int)sizeof(int), (int)size1);
    assert_equals((int)sizeof(int), (int)size2);
    assert_equals("ABCDEFG", (const char *)args);
    return (val1 - val2);
}

/**
 * ArrayList ソート。
 */
static void test_list_array_sort(void)
{
    KcList *list = KcList_new_ArrayList(sizeof(int), 5);
    assert_not_null(list);

    // 値設定
    int vals[] = {10, 30, 50, 40, 20, 10, 30, 60, 20};
    for (int i = 0; i < (int)(sizeof(vals) / sizeof(int)); i++)
    {
        int val = vals[i];
        bool res = list->add(list, -1, &val, sizeof(int));
        assert_true(res);
    }
    int now_size = list->size(list);
    assert_equals(9, now_size);

    // ソート実施
    list->sort(list, test_list_array_sort_comparator, "ABCDEFG");
    int sorted_vals[] = {10, 10, 20, 20, 30, 30, 40, 50, 60};

    KcIterator *ite = list->iterator(list, 0);
    int sorted_index = 0;
    while (ite->hasNext(ite))
    {
        size_t res_size;
        int *res_val = (int *)ite->next(ite, &res_size);
        assert_equals((int)sizeof(int), (int)res_size);
        assert_equals(sorted_vals[sorted_index], *res_val);
        sorted_index++;
    }
    KcIterator_delete(ite);

    // index = 5 より取得
    ite = list->iterator(list, 5);
    sorted_index = 5;
    while (ite->hasNext(ite))
    {
        int *res_val = (int *)ite->next(ite, NULL);
        assert_equals(sorted_vals[sorted_index], *res_val);
        sorted_index++;
    }
    KcIterator_delete(ite);

    KcList_delete(list);
}

/**
 * ArrayList メモリ確保失敗。
 */

static void test_list_array_malloc_error(void)
{
    KcList *list = KcList_new_ArrayList(sizeof(int), -1);
    assert_null(list);
}