diff --git a/include/tests.h b/include/tests.h index 36b68587..de358106 100644 --- a/include/tests.h +++ b/include/tests.h @@ -14,5 +14,10 @@ enum wrapper_behavior { int reset_mem_wrappers(void **state); void memory_behavior(enum wrapper_behavior behavior); +int malloc_calls(); +int free_calls(); +int calloc_calls(); +int realloc_calls(); +int alloc_calls(); #endif diff --git a/test/common/list/list.c b/test/common/list/list.c index 7cfc2609..9d3077bc 100644 --- a/test/common/list/list.c +++ b/test/common/list/list.c @@ -5,16 +5,185 @@ #include "tests.h" #include "list.h" -static void test_create_list(void **state) { - memory_behavior(WRAPPER_INVOKE_CMOCKA); +static void assert_list_contents(list_t *list, int contents[], size_t len) { + assert_int_equal(list->length, (int)len); + for (size_t i = 0; i < (size_t)list->length; ++i) { + assert_int_equal(contents[i], *(int *)list->items[i]); + } +} + +static list_t *create_test_list(int contents[], size_t len) { + list_t *l = create_list(); + for (size_t i = 0; i < len; ++i) { + list_add(l, &contents[i]); + } + return l; +} + +static void test_create_and_free(void **state) { list_t *list = create_list(); assert_int_equal(list->length, 0); + assert_int_equal(list->capacity, 10); + assert_non_null(list->items); + list_free(list); + assert_int_equal(malloc_calls(), 2); + assert_int_equal(free_calls(), 2); +} + +static void test_add(void **state) { + list_t *list = create_list(); + + int items[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 }; + for (size_t i = 0; i < sizeof(items) / sizeof(int); ++i) { + list_add(list, &items[i]); + assert_int_equal(items[i], *(int *)list->items[i]); + assert_int_equal(list->length, i + 1); + } + assert_list_contents(list, items, 15); + assert_int_equal(list->length, 15); + assert_int_equal(list->capacity, 20); + assert_int_equal(realloc_calls(), 1); + + list_free(list); +} + +static void test_insert(void **state) { + list_t *list = create_list(); + int i = 1, j = 2; + list_add(list, &i); + list_add(list, &i); + list_add(list, &i); + list_insert(list, 0, &j); + assert_int_equal(j, *(int *)list->items[0]); + assert_int_equal(list->length, 4); + list_free(list); +} + +static void test_del(void **state) { + list_t *list = create_list(); + + int items[] = { 1, 2, 3, 4, 5 }; + int new_items[] = { 1, 2, 4, 5 }; + for (size_t i = 0; i < sizeof(items) / sizeof(int); ++i) { + list_add(list, &items[i]); + } + + list_del(list, 2); + assert_list_contents(list, new_items, 4); + list_free(list); +} + +static void test_cat(void **state) { + int items_a[] = { 1, 2, 3, 4 }; + int items_b[] = { 5, 6, 7, 8 }; + int items_final[] = { 1, 2, 3, 4, 5, 6, 7, 8 }; + + list_t *list_a = create_test_list(items_a, 4); + list_t *list_b = create_test_list(items_b, 4); + + list_cat(list_a, list_b); + + assert_list_contents(list_a, items_final, 8); + list_free(list_a); + list_free(list_b); +} + +static int qsort_compare(const void *left, const void *right) { + return **(int * const *)left - **(int * const *)right; +} + +static void test_qsort(void **state) { + int items_start[] = { 1, 4, 3, 2 }; + int items_final[] = { 1, 2, 3, 4 }; + list_t *list = create_test_list(items_start, 4); + list_qsort(list, qsort_compare); + assert_list_contents(list, items_final, 4); + list_free(list); +} + +static int find_compare(const void *a, const void *b) { + return *(int *)a - *(int *)b; +} + +static void test_seq_find(void **state) { + int items[] = { 1, 2, 3, 4 }; + int expected = 3; + list_t *list = create_test_list(items, 4); + int index = list_seq_find(list, find_compare, &expected); + assert_int_equal(index, 2); + list_free(list); +} + +int foreach_count = 0; + +static void foreach(void *item) { + foreach_count++; + assert_int_equal(*(int *)item, foreach_count); +} + +static void test_foreach(void **state) { + int items[] = { 1, 2, 3, 4 }; + list_t *list = create_test_list(items, 4); + list_foreach(list, foreach); + assert_int_equal(foreach_count, 4); + list_free(list); +} + +struct stable_data { + int id, value; +}; + +static int stable_compare(const void *_a, const void *_b) { + struct stable_data * const *a = _a; + struct stable_data * const *b = _b; + return (*a)->value - (*b)->value; +} + +static void test_stable_sort(void **state) { + struct stable_data initial[] = { + { .id = 0, .value = 0 }, + { .id = 3, .value = 2 }, + { .id = 4, .value = 3 }, + { .id = 1, .value = 1 }, + { .id = 2, .value = 1 }, + { .id = 5, .value = 4 }, + { .id = 7, .value = 5 }, + { .id = 6, .value = 5 }, + }; + struct stable_data expected[] = { + { .id = 0, .value = 0 }, + { .id = 1, .value = 1 }, + { .id = 2, .value = 1 }, + { .id = 3, .value = 2 }, + { .id = 4, .value = 3 }, + { .id = 5, .value = 4 }, + { .id = 7, .value = 5 }, + { .id = 6, .value = 5 }, + }; + list_t *list = create_list(); + for (size_t i = 0; i < sizeof(initial) / sizeof(initial[0]); ++i) { + list_add(list, &initial[i]); + } + list_stable_sort(list, stable_compare); + for (size_t i = 0; i < sizeof(expected) / sizeof(expected[0]); ++i) { + struct stable_data *item = list->items[i]; + assert_int_equal(item->value, expected[i].value); + assert_int_equal(item->id, expected[i].id); + } list_free(list); } int main(int argc, char **argv) { const struct CMUnitTest tests[] = { - cmocka_unit_test(test_create_list), + cmocka_unit_test(test_create_and_free), + cmocka_unit_test(test_add), + cmocka_unit_test(test_insert), + cmocka_unit_test(test_del), + cmocka_unit_test(test_cat), + cmocka_unit_test(test_qsort), + cmocka_unit_test(test_seq_find), + cmocka_unit_test(test_foreach), + cmocka_unit_test(test_stable_sort), }; return cmocka_run_group_tests(tests, reset_mem_wrappers, NULL); } diff --git a/test/util.c b/test/util.c index ef825200..837ac3d5 100644 --- a/test/util.c +++ b/test/util.c @@ -6,10 +6,18 @@ void __real_free(void *ptr); void *__real_calloc(size_t nmemb, size_t size); void *__real_realloc(void *ptr, size_t size); -enum wrapper_behavior _memory_behavior = WRAPPER_INVOKE_REAL; +enum wrapper_behavior _memory_behavior = WRAPPER_INVOKE_CMOCKA; +int malloc_callcount = 0, + free_callcount = 0, + calloc_callcount = 0, + realloc_callcount = 0; int reset_mem_wrappers(void **state) { - _memory_behavior = WRAPPER_INVOKE_REAL; + _memory_behavior = WRAPPER_INVOKE_CMOCKA; + malloc_callcount = + free_callcount = + calloc_callcount = + realloc_callcount = 0; return 0; } @@ -17,7 +25,28 @@ void memory_behavior(enum wrapper_behavior behavior) { _memory_behavior = behavior; } +int malloc_calls() { + return malloc_callcount; +} + +int free_calls() { + return free_callcount; +} + +int calloc_calls() { + return calloc_callcount; +} + +int realloc_calls() { + return realloc_callcount; +} + +int alloc_calls() { + return malloc_callcount + calloc_callcount; +} + void *__wrap_malloc(size_t size) { + ++malloc_callcount; switch (_memory_behavior) { case WRAPPER_INVOKE_CMOCKA: return test_malloc(size); @@ -31,6 +60,7 @@ void *__wrap_malloc(size_t size) { } void __wrap_free(void *ptr) { + ++free_callcount; switch (_memory_behavior) { case WRAPPER_INVOKE_CMOCKA: test_free(ptr); @@ -46,6 +76,7 @@ void __wrap_free(void *ptr) { } void *__wrap_calloc(size_t nmemb, size_t size) { + ++calloc_callcount; switch (_memory_behavior) { case WRAPPER_INVOKE_CMOCKA: return test_calloc(nmemb, size); @@ -60,6 +91,7 @@ void *__wrap_calloc(size_t nmemb, size_t size) { } void *__wrap_realloc(void *ptr, size_t size) { + ++realloc_callcount; switch (_memory_behavior) { case WRAPPER_INVOKE_CMOCKA: return test_realloc(ptr, size);