#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> #include "ut.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); /** * ArrayList 単体テストスイート */ 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 不正[負の値を指定]) * @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); // 値取得 (index 不正[負の値を指定]) res_val = list->get(list, -1, NULL); assert_null(res_val); // 値取得 (index 不正[サイズ以上を指定]) res_val = list->get(list, 4, NULL); assert_null(res_val); KcList_delete(list); } /** * ArrayList データ削除。 * * @process 末尾削除 * @process 中間削除 * @process 先頭削除 * @process 削除(index 不正[負の値を指定]) * @process 削除(index 不正[サイズ以上を指定]) * @process 残っているデータを確認 * @process 容量調整(初期容量→1/4以下) */ 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, -1, NULL, NULL); assert_false(ret); // 削除(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); // 容量調整(初期容量→1/4以下) KcList *big_list = KcList_new_ArrayList(sizeof(int), 12); int big_val = 10; // 追加 bool big_ret = big_list->add(list, 0, &big_val, sizeof(int)); assert_true(big_ret); // 削除 (この時、容量調整発生) big_ret = big_list->remove(list, 0, NULL, NULL); assert_true(big_ret); KcList_delete(big_list); } /** * ArrayList データ設定。 * * @process 値設定(複数設定) * @process 値設定(元の値、サイズ取得) * @process 値設定(元の値取得) * @process 値設定(不正index[負の値指定]) * @process 値設定(不正index[サイズ以上指定]) */ 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); // 値設定 (サイズ取得) set_value = 97; ret = list->set(list, 0, &set_value, sizeof(int), NULL, &orig_size); assert_true(ret); assert_equals((int)sizeof(int), (int)orig_size); res_val = list->get(list, 0, NULL); assert_equals(97, *res_val); now_size = list->size(list); assert_equals(5, now_size); // 値設定(不正index[負の値指定]) set_value = 96; ret = list->set(list, -1, &set_value, sizeof(int), NULL, NULL); assert_false(ret); // 値設定(不正index[サイズ以上指定]) set_value = 95; ret = list->set(list, 5, &set_value, sizeof(int), NULL, NULL); assert_false(ret); KcList_delete(list); } /** * ArrayList 検索。 * * @process リスト {10, 30, 50, 40, 20, 10, 30, 60, 20 } を構築する。 * @result リストが構築されること * * @process is_contains でリストに含まれる値を確認する。 * @result true が返されること。 * * @process index_of で各インデックス位置を取得する。 * @result 先頭からのインデックス位置が正しく取得されること。 * * @process last_index_of で各インデックス位置を取得する。 * @result 末尾からのインデックス位置が正しく取得されること。 * * @process リストに含まれない値を指定して、is_contains を実行する。 * @result false が返されること。 * * @process リストに含まれない値を指定して、index_of を実行する。 * @result -1 が返されること。 * * @process リストに含まれない値を指定して、last_index_of を実行する。 * @result -1 が返されること。 */ 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 ソート。 * * @process リスト {10, 30, 50, 40, 20, 10, 30, 60, 20} を構築する。 * @result リストが構築されること。 * * @process 昇順用コンパレータを渡し、ソートする。 * @result リストがソートされること。 * * @process Iterator を取得する。 * @result Iterator にて順次値が取得できること。 */ 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}; // Iterator にて値を取得&確認 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) { // ArrayList のメモリ確保失敗 ut_alloc_control(0) { KcList *list = KcList_new_ArrayList(sizeof(int), 3); assert_null(list); } // ArrayList のデータ用メモリ確保失敗 ut_alloc_control(1) { KcList *list = KcList_new_ArrayList(sizeof(int), 3); assert_null(list); } // Array Size 拡張時のメモリ確保失敗 KcList *list = KcList_new_ArrayList(sizeof(int), 3); int val = 10; list->add(list, 0, &val, sizeof(int)); list->add(list, 1, &val, sizeof(int)); list->add(list, 2, &val, sizeof(int)); ut_alloc_control(0) { // size 以上 bool ret = list->add(list, 3, &val, sizeof(int)); assert_false(ret); // 0 指定 ret = list->add(list, 0, &val, sizeof(int)); assert_false(ret); } // Iterator 生成時のメモリ確保失敗 ut_alloc_control(0) { KcIterator *ite = list->iterator(list, 0); assert_null(ite); } KcList_delete(list); }