/* * Copyright (C) 2013 Tobias Brunner * HSR Hochschule fuer Technik Rapperswil * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. See . * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. */ #include "test_suite.h" #include /******************************************************************************* * test fixture */ static linked_list_t *list; START_SETUP(setup_list) { void *x = NULL; list = linked_list_create(); ck_assert_int_eq(list->get_count(list), 0); ck_assert(list->get_first(list, &x) == NOT_FOUND); ck_assert(list->get_last(list, &x) == NOT_FOUND); } END_SETUP START_TEARDOWN(teardown_list) { list->destroy(list); } END_TEARDOWN /******************************************************************************* * insert first/last */ START_TEST(test_insert_first) { void *a = (void*)1, *b = (void*)2, *x = NULL; list->insert_first(list, a); ck_assert_int_eq(list->get_count(list), 1); ck_assert(list->get_first(list, &x) == SUCCESS); ck_assert(x == a); ck_assert(list->get_last(list, &x) == SUCCESS); ck_assert(x == a); list->insert_first(list, b); ck_assert_int_eq(list->get_count(list), 2); ck_assert(list->get_first(list, &x) == SUCCESS); ck_assert(x == b); ck_assert(list->get_last(list, &x) == SUCCESS); ck_assert(x == a); } END_TEST START_TEST(test_insert_last) { void *a = (void*)1, *b = (void*)2, *x = NULL; list->insert_last(list, a); ck_assert_int_eq(list->get_count(list), 1); ck_assert(list->get_first(list, &x) == SUCCESS); ck_assert(x == a); ck_assert(list->get_last(list, &x) == SUCCESS); ck_assert(x == a); list->insert_last(list, b); ck_assert_int_eq(list->get_count(list), 2); ck_assert(list->get_first(list, &x) == SUCCESS); ck_assert(x == a); ck_assert(list->get_last(list, &x) == SUCCESS); ck_assert(x == b); } END_TEST /******************************************************************************* * remove first/last */ START_TEST(test_remove_first) { void *a = (void*)1, *b = (void*)2, *x = NULL; list->insert_first(list, a); list->insert_first(list, b); ck_assert(list->remove_first(list, &x) == SUCCESS); ck_assert_int_eq(list->get_count(list), 1); ck_assert(x == b); ck_assert(list->remove_first(list, &x) == SUCCESS); ck_assert_int_eq(list->get_count(list), 0); ck_assert(x == a); ck_assert(list->remove_first(list, &x) == NOT_FOUND); ck_assert(list->remove_last(list, &x) == NOT_FOUND); } END_TEST START_TEST(test_remove_last) { void *a = (void*)1, *b = (void*)2, *x = NULL; list->insert_first(list, a); list->insert_first(list, b); ck_assert(list->remove_last(list, &x) == SUCCESS); ck_assert_int_eq(list->get_count(list), 1); ck_assert(x == a); ck_assert(list->remove_last(list, &x) == SUCCESS); ck_assert_int_eq(list->get_count(list), 0); ck_assert(x == b); ck_assert(list->remove_first(list, &x) == NOT_FOUND); ck_assert(list->remove_last(list, &x) == NOT_FOUND); } END_TEST /******************************************************************************* * helper function for remove and find tests */ static bool match_a(void *item, void *a) { ck_assert(a == (void*)1); return item == a; } static bool match_b(void *item, void *b) { ck_assert(b == (void*)2); return item == b; } /******************************************************************************* * remove */ START_TEST(test_remove) { void *a = (void*)1, *b = (void*)2; list->insert_first(list, a); ck_assert(list->remove(list, a, NULL) == 1); ck_assert_int_eq(list->get_count(list), 0); list->insert_last(list, a); list->insert_last(list, a); list->insert_last(list, a); list->insert_last(list, b); ck_assert(list->remove(list, a, NULL) == 3); ck_assert(list->remove(list, a, NULL) == 0); ck_assert_int_eq(list->get_count(list), 1); ck_assert(list->remove(list, b, NULL) == 1); ck_assert(list->remove(list, b, NULL) == 0); } END_TEST START_TEST(test_remove_callback) { void *a = (void*)1, *b = (void*)2; list->insert_last(list, a); list->insert_last(list, b); list->insert_last(list, a); list->insert_last(list, b); ck_assert(list->remove(list, a, match_a) == 2); ck_assert(list->remove(list, a, match_a) == 0); ck_assert_int_eq(list->get_count(list), 2); ck_assert(list->remove(list, b, match_b) == 2); ck_assert(list->remove(list, b, match_b) == 0); ck_assert_int_eq(list->get_count(list), 0); } END_TEST /******************************************************************************* * find */ CALLBACK(find_a_b, bool, void *item, va_list args) { void *a, *b; VA_ARGS_VGET(args, a, b); ck_assert(a == (void*)1); ck_assert(b == (void*)2); return item == a || item == b; } CALLBACK(find_a, bool, void *item, va_list args) { void *a; VA_ARGS_VGET(args, a); return match_a(item, a); } CALLBACK(find_b, bool, void *item, va_list args) { void *b; VA_ARGS_VGET(args, b); return match_b(item, b); } START_TEST(test_find) { void *a = (void*)1, *b = (void*)2; ck_assert(!list->find_first(list, NULL, &a)); list->insert_last(list, a); ck_assert(list->find_first(list, NULL, &a)); ck_assert(!list->find_first(list, NULL, &b)); list->insert_last(list, b); ck_assert(list->find_first(list, NULL, &a)); ck_assert(list->find_first(list, NULL, &b)); ck_assert(!list->find_first(list, NULL, NULL)); } END_TEST START_TEST(test_find_callback) { void *a = (void*)1, *b = (void*)2, *x = NULL; ck_assert(!list->find_first(list, find_a_b, &x, a, b)); list->insert_last(list, a); ck_assert(list->find_first(list, find_a, NULL, a)); x = NULL; ck_assert(list->find_first(list, find_a, &x, a)); ck_assert(a == x); ck_assert(!list->find_first(list, find_b, &x, b)); ck_assert(a == x); x = NULL; ck_assert(list->find_first(list, find_a_b, &x, a, b)); ck_assert(a == x); list->insert_last(list, b); ck_assert(list->find_first(list, find_a, &x, a)); ck_assert(a == x); ck_assert(list->find_first(list, find_b, &x, b)); ck_assert(b == x); x = NULL; ck_assert(list->find_first(list, find_a_b, &x, a, b)); ck_assert(a == x); } END_TEST CALLBACK(find_args, bool, void *item, va_list args) { uint64_t d, e; level_t c; int *a, b; VA_ARGS_VGET(args, a, b, c, d, e); ck_assert_int_eq(*a, 1); ck_assert_int_eq(b, 2); ck_assert_int_eq(c, LEVEL_PRIVATE); ck_assert_int_eq(d, UINT64_MAX); ck_assert_int_eq(e, UINT64_MAX-1); return item == a; } START_TEST(test_find_callback_args) { int a = 1, b = 2, *x; uint64_t d = UINT64_MAX; list->insert_last(list, &a); ck_assert(list->find_first(list, find_args, (void**)&x, &a, b, LEVEL_PRIVATE, d, UINT64_MAX-1)); ck_assert_int_eq(a, *x); } END_TEST /******************************************************************************* * invoke */ typedef struct invoke_t invoke_t; struct invoke_t { int val; void (*invoke)(invoke_t *item); }; CALLBACK(invoke, void, intptr_t item, va_list args) { void *a, *b, *c, *d; int *sum; VA_ARGS_VGET(args, a, b, c, d, sum); ck_assert_int_eq((uintptr_t)a, 1); ck_assert_int_eq((uintptr_t)b, 2); ck_assert_int_eq((uintptr_t)c, 3); ck_assert_int_eq((uintptr_t)d, 4); *sum += item; } static void invoke_offset(invoke_t *item) { item->val++; } START_TEST(test_invoke_function) { int sum = 0; list->insert_last(list, (void*)1); list->insert_last(list, (void*)2); list->insert_last(list, (void*)3); list->insert_last(list, (void*)4); list->insert_last(list, (void*)5); list->invoke_function(list, invoke, (uintptr_t)1, (uintptr_t)2, (uintptr_t)3, (uintptr_t)4, &sum); ck_assert_int_eq(sum, 15); } END_TEST START_TEST(test_invoke_offset) { invoke_t items[] = { { .val = 1, .invoke = invoke_offset, }, { .val = 2, .invoke = invoke_offset, }, { .val = 3, .invoke = invoke_offset, }, { .val = 4, .invoke = invoke_offset, }, { .val = 5, .invoke = invoke_offset, }, }, *item; int i; for (i = 0; i < countof(items); i++) { list->insert_last(list, &items[i]); } list->invoke_offset(list, offsetof(invoke_t, invoke)); i = 2; while (list->remove_first(list, (void**)&item) == SUCCESS) { ck_assert_int_eq(item->val, i++); } } END_TEST /******************************************************************************* * clone */ typedef struct clone_t clone_t; struct clone_t { void *val; void *(*clone)(clone_t *item); }; static void *clonefn(clone_t *item) { return item->val; } static void test_clone(linked_list_t *list) { intptr_t x; int round = 1; ck_assert_int_eq(list->get_count(list), 5); while (list->remove_first(list, (void*)&x) == SUCCESS) { ck_assert_int_eq(round, x); round++; } ck_assert_int_eq(round, 6); } START_TEST(test_clone_offset) { linked_list_t *other; clone_t items[] = { { .val = (void*)1, .clone = clonefn, }, { .val = (void*)2, .clone = clonefn, }, { .val = (void*)3, .clone = clonefn, }, { .val = (void*)4, .clone = clonefn, }, { .val = (void*)5, .clone = clonefn, }, }; int i; for (i = 0; i < countof(items); i++) { list->insert_last(list, &items[i]); } other = list->clone_offset(list, offsetof(clone_t, clone)); test_clone(other); other->destroy(other); } END_TEST /******************************************************************************* * equals */ typedef struct equals_t equals_t; struct equals_t { int val; bool (*equals)(equals_t *a, equals_t *b); }; static bool equalsfn(equals_t *a, equals_t *b) { return a->val == b->val; } START_TEST(test_equals_offset) { linked_list_t *other; equals_t *x, items[] = { { .val = 1, .equals = equalsfn, }, { .val = 2, .equals = equalsfn, }, { .val = 3, .equals = equalsfn, }, { .val = 4, .equals = equalsfn, }, { .val = 5, .equals = equalsfn, }, }; int i; for (i = 0; i < countof(items); i++) { list->insert_last(list, &items[i]); } ck_assert(list->equals_offset(list, list, offsetof(equals_t, equals))); other = linked_list_create_from_enumerator(list->create_enumerator(list)); ck_assert(list->equals_offset(list, other, offsetof(equals_t, equals))); other->remove_last(other, (void**)&x); ck_assert(!list->equals_offset(list, other, offsetof(equals_t, equals))); list->remove_last(list, (void**)&x); ck_assert(list->equals_offset(list, other, offsetof(equals_t, equals))); other->remove_first(other, (void**)&x); ck_assert(!list->equals_offset(list, other, offsetof(equals_t, equals))); list->remove_first(list, (void**)&x); ck_assert(list->equals_offset(list, other, offsetof(equals_t, equals))); while (list->remove_first(list, (void**)&x) == SUCCESS); while (other->remove_first(other, (void**)&x) == SUCCESS); ck_assert(list->equals_offset(list, other, offsetof(equals_t, equals))); other->destroy(other); } END_TEST START_TEST(test_equals_function) { linked_list_t *other; equals_t *x, items[] = { { .val = 1, }, { .val = 2, }, { .val = 3, }, { .val = 4, }, { .val = 5, }, }; int i; for (i = 0; i < countof(items); i++) { list->insert_last(list, &items[i]); } ck_assert(list->equals_function(list, list, (void*)equalsfn)); other = linked_list_create_from_enumerator(list->create_enumerator(list)); ck_assert(list->equals_function(list, other, (void*)equalsfn)); other->remove_last(other, (void**)&x); ck_assert(!list->equals_function(list, other, (void*)equalsfn)); list->remove_last(list, (void**)&x); ck_assert(list->equals_function(list, other, (void*)equalsfn)); other->remove_first(other, (void**)&x); ck_assert(!list->equals_function(list, other, (void*)equalsfn)); list->remove_first(list, (void**)&x); ck_assert(list->equals_function(list, other, (void*)equalsfn)); while (list->remove_first(list, (void**)&x) == SUCCESS); while (other->remove_first(other, (void**)&x) == SUCCESS); ck_assert(list->equals_function(list, other, (void*)equalsfn)); other->destroy(other); } END_TEST Suite *linked_list_suite_create() { Suite *s; TCase *tc; s = suite_create("linked list"); tc = tcase_create("insert/get"); tcase_add_checked_fixture(tc, setup_list, teardown_list); tcase_add_test(tc, test_insert_first); tcase_add_test(tc, test_insert_last); suite_add_tcase(s, tc); tc = tcase_create("remove"); tcase_add_checked_fixture(tc, setup_list, teardown_list); tcase_add_test(tc, test_remove_first); tcase_add_test(tc, test_remove_last); tcase_add_test(tc, test_remove); tcase_add_test(tc, test_remove_callback); suite_add_tcase(s, tc); tc = tcase_create("find"); tcase_add_checked_fixture(tc, setup_list, teardown_list); tcase_add_test(tc, test_find); tcase_add_test(tc, test_find_callback); tcase_add_test(tc, test_find_callback_args); suite_add_tcase(s, tc); tc = tcase_create("invoke"); tcase_add_checked_fixture(tc, setup_list, teardown_list); tcase_add_test(tc, test_invoke_function); tcase_add_test(tc, test_invoke_offset); suite_add_tcase(s, tc); tc = tcase_create("clone"); tcase_add_checked_fixture(tc, setup_list, teardown_list); tcase_add_test(tc, test_clone_offset); suite_add_tcase(s, tc); tc = tcase_create("equals"); tcase_add_checked_fixture(tc, setup_list, teardown_list); tcase_add_test(tc, test_equals_offset); tcase_add_test(tc, test_equals_function); suite_add_tcase(s, tc); return s; }