From e2d596e4bd5bcf1c870c0631ac6d68d6a6dbead7 Mon Sep 17 00:00:00 2001 From: Bailey Thompson Date: Sat, 4 May 2019 17:59:20 -0400 Subject: [PATCH] Refactor tests (#31) Refactor tests in order for the component or logic that they are testing to be contained into individual sub-tests instead of all tests being contained in one big test for the whole data structure. Add testing for out-of-memory (OOM) conditions. This makes the source code now 100% covered. Bug fix! A bug has been identified and fixed in the list data structure in the list_add_last function. This bug would occur when adding an item to the back of the list because the pointers were not being updated properly. Minor Bug fix! A bug has been identified and fixed in the unordered_set, unordered_map, unordered_multiset, and unordered_multimap data structures in their respective unordered_xxx_put functions. This bug would occur in an out-of-memory condition, which would cause the size of the collection to increase without actually adding the new element to it. --- CMakeLists.txt | 2 +- README.md | 1 + src/array.c | 3 +- src/deque.c | 3 +- src/forward_list.c | 3 +- src/list.c | 83 +-- src/map.c | 4 +- src/multimap.c | 4 +- src/multiset.c | 4 +- src/priority_queue.c | 3 +- src/queue.c | 3 +- src/set.c | 4 +- src/stack.c | 3 +- src/unordered_map.c | 16 +- src/unordered_multimap.c | 15 +- src/unordered_multiset.c | 16 +- src/unordered_set.c | 16 +- src/vector.c | 3 +- tst/array.c | 84 ++- tst/deque.c | 174 +++++- tst/forward_list.c | 179 +++++- tst/list.c | 172 +++++- tst/map.c | 1032 ++++++++++++++++++----------------- tst/multimap.c | 1108 ++++++++++++++++++++------------------ tst/multiset.c | 986 +++++++++++++++++---------------- tst/priority_queue.c | 72 ++- tst/queue.c | 87 ++- tst/set.c | 855 ++++++++++++++++------------- tst/stack.c | 64 ++- tst/test.c | 65 +++ tst/test.h | 8 + tst/unordered_map.c | 171 +++++- tst/unordered_multimap.c | 234 ++++++-- tst/unordered_multiset.c | 174 +++++- tst/unordered_set.c | 153 +++++- tst/vector.c | 241 ++++++--- 36 files changed, 3750 insertions(+), 2295 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index a397b55..2c1c647 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -3,7 +3,7 @@ project(Containers C) set(CMAKE_C_STANDARD 90) -set(CMAKE_C_FLAGS "-pedantic -Werror -g -O0 -Wall -fprofile-arcs -ftest-coverage") +set(CMAKE_C_FLAGS "-pedantic -ldl -g -O0 -Wall -fprofile-arcs -ftest-coverage") add_executable(Containers tst/test.c tst/test.h src/array.c src/array.h tst/array.c diff --git a/README.md b/README.md index 98b529d..4dbe3df 100644 --- a/README.md +++ b/README.md @@ -38,3 +38,4 @@ Data structures which adapt other containers to enhance functionality. * stack - adapts a container to provide stack (last-in first-out) * queue - adapts a container to provide queue (first-in first-out) * priority_queue - adapts a container to provide priority queue + diff --git a/src/array.c b/src/array.c index d8b06b3..88bb396 100644 --- a/src/array.c +++ b/src/array.c @@ -154,7 +154,8 @@ int array_get(void *const data, array me, const int index) } /** - * Frees the array memory. + * Frees the array memory. Performing further operations after calling this + * function results in undefined behavior. * * @param me the array to free from memory * diff --git a/src/deque.c b/src/deque.c index fabf683..a1929c7 100644 --- a/src/deque.c +++ b/src/deque.c @@ -460,7 +460,8 @@ int deque_clear(deque me) } /** - * Destroys the deque. + * Destroys the deque. Performing further operations after calling this function + * results in undefined behavior. * * @param me the deque to destroy * diff --git a/src/forward_list.c b/src/forward_list.c index 0e060ee..f92528e 100644 --- a/src/forward_list.c +++ b/src/forward_list.c @@ -367,7 +367,8 @@ void forward_list_clear(forward_list me) } /** - * Destroys the singly-linked list. + * Destroys the singly-linked list. Performing further operations after calling + * this function results in undefined behavior. * * @param me the singly-linked list to destroy * diff --git a/src/list.c b/src/list.c index 5869d53..fa1adc1 100644 --- a/src/list.c +++ b/src/list.c @@ -153,28 +153,7 @@ static struct node *list_get_node_at(list me, const int index) */ int list_add_first(list me, void *const data) { - struct node *const traverse = me->head; - struct node *const add = malloc(sizeof(struct node)); - if (!add) { - return -ENOMEM; - } - add->data = malloc(me->bytes_per_item); - if (!add->data) { - free(add); - return -ENOMEM; - } - add->prev = NULL; - memcpy(add->data, data, me->bytes_per_item); - add->next = traverse; - if (traverse) { - traverse->prev = add; - } - me->head = add; - if (!me->tail) { - me->tail = traverse; - } - me->item_count++; - return 0; + return list_add_at(me, 0, data); } /** @@ -190,19 +169,10 @@ int list_add_first(list me, void *const data) */ int list_add_at(list me, const int index, void *const data) { - struct node *traverse; struct node *add; if (index < 0 || index > me->item_count) { return -EINVAL; } - if (index == 0) { - return list_add_first(me, data); - } - if (index == me->item_count) { - return list_add_last(me, data); - } - /* The new node will go right before this node. */ - traverse = list_get_node_at(me, index); add = malloc(sizeof(struct node)); if (!add) { return -ENOMEM; @@ -212,11 +182,31 @@ int list_add_at(list me, const int index, void *const data) free(add); return -ENOMEM; } - add->prev = traverse->prev; memcpy(add->data, data, me->bytes_per_item); - add->next = traverse; - traverse->prev->next = add; - traverse->prev = add; + if (!me->head) { + add->prev = NULL; + add->next = NULL; + me->head = add; + me->tail = add; + } else if (index == 0) { + struct node *const traverse = me->head; + traverse->prev = add; + add->prev = NULL; + add->next = traverse; + me->head = add; + } else if (index == me->item_count) { + struct node *const traverse = me->tail; + traverse->next = add; + add->prev = traverse; + add->next = NULL; + me->tail = add; + } else { + struct node *const traverse = list_get_node_at(me, index); + add->prev = traverse->prev; + add->next = traverse; + traverse->prev->next = add; + traverse->prev = add; + } me->item_count++; return 0; } @@ -232,25 +222,7 @@ int list_add_at(list me, const int index, void *const data) */ int list_add_last(list me, void *const data) { - struct node *const traverse = me->tail; - struct node *const add = malloc(sizeof(struct node)); - if (!add) { - return -ENOMEM; - } - add->data = malloc(me->bytes_per_item); - if (!add->data) { - free(add); - return -ENOMEM; - } - add->prev = traverse; - memcpy(add->data, data, me->bytes_per_item); - add->next = NULL; - if (traverse) { - traverse->next = add; - } - me->tail = add; - me->item_count++; - return 0; + return list_add_at(me, me->item_count, data); } /* @@ -437,7 +409,8 @@ void list_clear(list me) } /** - * Destroys the doubly-linked list. + * Destroys the doubly-linked list. Performing further operations after calling + * this function results in undefined behavior. * * @param me the doubly-linked list to destroy * diff --git a/src/map.c b/src/map.c index ff0e6a6..b39682e 100644 --- a/src/map.c +++ b/src/map.c @@ -212,7 +212,6 @@ static struct node *map_repair(map me, return grand_child; } /* Impossible to get here. */ - return NULL; } /* @@ -612,7 +611,8 @@ void map_clear(map me) } /** - * Frees the map memory. + * Frees the map memory. Performing further operations after calling this + * function results in undefined behavior. * * @param me the map to free from memory * diff --git a/src/multimap.c b/src/multimap.c index 256b4f0..b83c11c 100644 --- a/src/multimap.c +++ b/src/multimap.c @@ -228,7 +228,6 @@ static struct node *multimap_repair(multimap me, return grand_child; } /* Impossible to get here. */ - return NULL; } /* @@ -750,7 +749,8 @@ void multimap_clear(multimap me) } /** - * Frees the multi-map memory. + * Frees the multi-map memory. Performing further operations after calling this + * function results in undefined behavior. * * @param me the multi-map to free from memory * diff --git a/src/multiset.c b/src/multiset.c index 1417de9..b3c4d3a 100644 --- a/src/multiset.c +++ b/src/multiset.c @@ -210,7 +210,6 @@ static struct node *multiset_repair(multiset me, return grand_child; } /* Impossible to get here. */ - return NULL; } /* @@ -625,7 +624,8 @@ void multiset_clear(multiset me) } /** - * Frees the multi-set memory. + * Frees the multi-set memory. Performing further operations after calling this + * function results in undefined behavior. * * @param me the multi-set to free from memory * diff --git a/src/priority_queue.c b/src/priority_queue.c index dc7b9f9..9d53503 100644 --- a/src/priority_queue.c +++ b/src/priority_queue.c @@ -223,7 +223,8 @@ int priority_queue_clear(priority_queue me) } /** - * Frees the priority queue memory. + * Frees the priority queue memory. Performing further operations after calling + * this function results in undefined behavior. * * @param me the priority queue to free from memory * diff --git a/src/queue.c b/src/queue.c index 56bf26a..ca12df8 100644 --- a/src/queue.c +++ b/src/queue.c @@ -178,7 +178,8 @@ int queue_clear(queue me) } /** - * Destroys the queue. + * Destroys the queue. Performing further operations after calling this function + * results in undefined behavior. * * @param me the queue to destroy * diff --git a/src/set.c b/src/set.c index 00ae122..7a21592 100644 --- a/src/set.c +++ b/src/set.c @@ -207,7 +207,6 @@ static struct node *set_repair(set me, return grand_child; } /* Impossible to get here. */ - return NULL; } /* @@ -576,7 +575,8 @@ void set_clear(set me) } /** - * Frees the set memory. + * Frees the set memory. Performing further operations after calling this + * function results in undefined behavior. * * @param me the set to free from memory * diff --git a/src/stack.c b/src/stack.c index c5023be..ec260d6 100644 --- a/src/stack.c +++ b/src/stack.c @@ -157,7 +157,8 @@ int stack_clear(stack me) } /** - * Destroys the stack and frees the memory associated with it. + * Frees the stack memory. Performing further operations after calling this + * function results in undefined behavior. * * @param me the stack to destroy * diff --git a/src/unordered_map.c b/src/unordered_map.c index 4acf4cf..5d28733 100644 --- a/src/unordered_map.c +++ b/src/unordered_map.c @@ -257,9 +257,15 @@ static struct node *const unordered_map_create_element(unordered_map me, */ int unordered_map_put(unordered_map me, void *const key, void *const value) { - const unsigned long hash = unordered_map_hash(me, key); - const int index = (int) (hash % me->capacity); + int index; + if (me->size + 1 >= RESIZE_AT * me->capacity) { + const int rc = unordered_map_resize(me); + if (rc != 0) { + return rc; + } + } + index = (int) (hash % me->capacity); if (!me->buckets[index]) { me->buckets[index] = unordered_map_create_element(me, hash, key, value); if (!me->buckets[index]) { @@ -284,9 +290,6 @@ int unordered_map_put(unordered_map me, void *const key, void *const value) } } me->size++; - if (me->size >= RESIZE_AT * me->capacity) { - return unordered_map_resize(me); - } return 0; } @@ -411,7 +414,8 @@ int unordered_map_clear(unordered_map me) } /** - * Frees the unordered map memory. + * Frees the unordered map memory. Performing further operations after calling + * this function results in undefined behavior. * * @param me the unordered map to free from memory * diff --git a/src/unordered_multimap.c b/src/unordered_multimap.c index 0b804fe..5366fef 100644 --- a/src/unordered_multimap.c +++ b/src/unordered_multimap.c @@ -280,7 +280,14 @@ int unordered_multimap_put(unordered_multimap me, void *const value) { const unsigned long hash = unordered_multimap_hash(me, key); - const int index = (int) (hash % me->capacity); + int index; + if (me->size + 1 >= RESIZE_AT * me->capacity) { + const int rc = unordered_multimap_resize(me); + if (rc != 0) { + return rc; + } + } + index = (int) (hash % me->capacity); if (!me->buckets[index]) { me->buckets[index] = unordered_multimap_create_element(me, hash, key, value); @@ -299,9 +306,6 @@ int unordered_multimap_put(unordered_multimap me, } } me->size++; - if (me->size >= RESIZE_AT * me->capacity) { - return unordered_multimap_resize(me); - } return 0; } @@ -538,7 +542,8 @@ int unordered_multimap_clear(unordered_multimap me) } /** - * Frees the unordered multi-map memory. + * Frees the unordered multi-map memory. Performing further operations after + * calling this function results in undefined behavior. * * @param me the unordered multi-map to free from memory * diff --git a/src/unordered_multiset.c b/src/unordered_multiset.c index 6f1f5de..3bb6557 100644 --- a/src/unordered_multiset.c +++ b/src/unordered_multiset.c @@ -247,9 +247,15 @@ unordered_multiset_create_element(unordered_multiset me, */ int unordered_multiset_put(unordered_multiset me, void *const key) { - const unsigned long hash = unordered_multiset_hash(me, key); - const int index = (int) (hash % me->capacity); + int index; + if (me->used + 1 >= RESIZE_AT * me->capacity) { + const int rc = unordered_multiset_resize(me); + if (rc != 0) { + return rc; + } + } + index = (int) (hash % me->capacity); if (!me->buckets[index]) { me->buckets[index] = unordered_multiset_create_element(me, hash, key); if (!me->buckets[index]) { @@ -277,9 +283,6 @@ int unordered_multiset_put(unordered_multiset me, void *const key) } me->size++; me->used++; - if (me->used >= RESIZE_AT * me->capacity) { - return unordered_multiset_resize(me); - } return 0; } @@ -440,7 +443,8 @@ int unordered_multiset_clear(unordered_multiset me) } /** - * Frees the unordered multi-set memory. + * Frees the unordered multi-set memory. Performing further operations after + * calling this function results in undefined behavior. * * @param me the unordered multi-set to free from memory * diff --git a/src/unordered_set.c b/src/unordered_set.c index 24c03be..549a14c 100644 --- a/src/unordered_set.c +++ b/src/unordered_set.c @@ -241,9 +241,15 @@ static struct node *const unordered_set_create_element(unordered_set me, */ int unordered_set_put(unordered_set me, void *const key) { - const unsigned long hash = unordered_set_hash(me, key); - const int index = (int) (hash % me->capacity); + int index; + if (me->size + 1 >= RESIZE_AT * me->capacity) { + const int rc = unordered_set_resize(me); + if (rc != 0) { + return rc; + } + } + index = (int) (hash % me->capacity); if (!me->buckets[index]) { me->buckets[index] = unordered_set_create_element(me, hash, key); if (!me->buckets[index]) { @@ -266,9 +272,6 @@ int unordered_set_put(unordered_set me, void *const key) } } me->size++; - if (me->size >= RESIZE_AT * me->capacity) { - return unordered_set_resize(me); - } return 0; } @@ -366,7 +369,8 @@ int unordered_set_clear(unordered_set me) } /** - * Frees the unordered set memory. + * Frees the unordered set memory. Performing further operations after calling + * this function results in undefined behavior. * * @param me the unordered set to free from memory * diff --git a/src/vector.c b/src/vector.c index 35f49f5..21ee66d 100644 --- a/src/vector.c +++ b/src/vector.c @@ -405,7 +405,8 @@ int vector_clear(vector me) } /** - * Frees the vector memory. + * Frees the vector memory. Performing further operations after calling this + * function results in undefined behavior. * * @param me the vector to free from memory * diff --git a/tst/array.c b/tst/array.c index dea7fab..911b254 100644 --- a/tst/array.c +++ b/tst/array.c @@ -1,35 +1,54 @@ #include "test.h" #include "../src/array.h" -void test_array(void) +static void test_invalid_init(void) { - array me; - int i; - int *data; - int arr[10] = {0}; - int array[2] = {0xdeadbeef, 0xdeadbeef}; - int get; assert(!array_init(-1, sizeof(int))); assert(!array_init(1, 0)); - me = array_init(10, sizeof(int)); +} + +static void test_empty_array(void) +{ + int get = 0xdeadbeef; + int arr[2] = {0xdeadbeef, 0xdeadbeef}; + array me = array_init(0, sizeof(int)); assert(me); - assert(array_size(me) == 10); + assert(array_size(me) == 0); + array_copy_to_array(arr, me); + assert(arr[0] == 0xdeadbeef); + assert(arr[1] == 0xdeadbeef); + assert(!array_get_data(me)); + assert(array_set(me, 0, &get) == -EINVAL); + assert(array_get(&get, me, 0) == -EINVAL); + assert(!array_destroy(me)); +} + +static void test_individual_operations(array me) +{ + int i; for (i = 0; i < 10; i++) { - get = 0xdeadbeef; + int get = 0xdeadbeef; array_get(&get, me, i); assert(get == 0); } for (i = 0; i < 10; i++) { - get = 0xdeadbeef; + int get = 0xdeadbeef; array_set(me, i, &i); array_get(&get, me, i); assert(get == i); } for (i = 0; i < 10; i++) { - get = 0xdeadbeef; + int get = 0xdeadbeef; array_get(&get, me, i); assert(get == i); } +} + +static void test_array_copying(array me) +{ + int i; + int *data; + int arr[10] = {0}; array_copy_to_array(arr, me); for (i = 0; i < 10; i++) { assert(arr[i] == i); @@ -38,18 +57,39 @@ void test_array(void) for (i = 0; i < 10; i++) { assert(data[i] == i); } - get = 0xdeadbeef; +} + +static void test_out_of_bounds(array me) +{ + int get = 0xdeadbeef; assert(array_set(me, -1, &get) == -EINVAL); assert(array_get(&get, me, -1) == -EINVAL); +} + +static void test_not_empty_array(void) +{ + array me = array_init(10, sizeof(int)); + assert(me); + assert(array_size(me) == 10); + test_individual_operations(me); + test_array_copying(me); + test_out_of_bounds(me); me = array_destroy(me); assert(!me); - me = array_init(0, sizeof(int)); - assert(array_size(me) == 0); - array_copy_to_array(array, me); - assert(array[0] == 0xdeadbeef); - assert(array[1] == 0xdeadbeef); - assert(!array_get_data(me)); - assert(array_set(me, 0, &get) == -EINVAL); - assert(array_get(&get, me, 0) == -EINVAL); - assert(!array_destroy(me)); +} + +static void test_init_out_of_memory(void) +{ + fail_malloc = 1; + assert(!array_init(10, sizeof(int))); + fail_calloc = 1; + assert(!array_init(10, sizeof(int))); +} + +void test_array(void) +{ + test_invalid_init(); + test_empty_array(); + test_not_empty_array(); + test_init_out_of_memory(); } diff --git a/tst/deque.c b/tst/deque.c index a2ea5d7..7fe63e2 100644 --- a/tst/deque.c +++ b/tst/deque.c @@ -1,22 +1,18 @@ #include "test.h" #include "../src/deque.h" -void test_deque(void) +static void test_invalid_init(void) +{ + assert(!deque_init(0)); +} + +static void test_copy(deque me) { int val[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; int get_arr[10] = {0}; int trimmed[5] = {0}; - int arr[3] = {0}; - deque me; int get; - int add; - int set; int i; - assert(!deque_init(0)); - me = deque_init(sizeof(int)); - assert(me); - assert(deque_size(me) == 0); - assert(deque_is_empty(me)); for (i = 0; i < 10; i++) { deque_push_front(me, &val[i]); get = 0; @@ -43,7 +39,14 @@ void test_deque(void) for (i = 0; i < 3; i++) { assert(10 - i == trimmed[i]); } - add = 3; +} + +static void test_linear_operations(deque me) +{ + int arr[3] = {0}; + int get; + int set; + int add = 3; deque_push_back(me, &add); add = -2; deque_push_back(me, &add); @@ -103,20 +106,161 @@ void test_deque(void) assert(arr[0] == -5); assert(arr[1] == -6); assert(arr[2] == -7); +} + +static void test_invalid_input(deque me) +{ + int set; assert(deque_set_at(me, 4, &set) == -EINVAL); assert(deque_get_at(&set, me, 4) == -EINVAL); assert(deque_set_at(me, -1, &set) == -EINVAL); assert(deque_get_at(&set, me, -1) == -EINVAL); +} + +static void test_basic(void) +{ + deque me = deque_init(sizeof(int)); + assert(me); + assert(deque_size(me) == 0); + assert(deque_is_empty(me)); + test_copy(me); + test_linear_operations(me); + test_invalid_input(me); deque_clear(me); assert(deque_size(me) == 0); assert(deque_is_empty(me)); - me = deque_destroy(me); - assert(!me); - /* Testing automatic trim */ - me = deque_init(sizeof(int)); + assert(!deque_destroy(me)); +} + +static void test_trim(void) +{ + deque me = deque_init(sizeof(int)); + int i; for (i = 0; i < 100; i++) { + int get; deque_push_back(me, &i); deque_pop_front(&get, me); } deque_destroy(me); } + +static void test_init_out_of_memory(void) +{ + fail_malloc = 1; + assert(!deque_init(sizeof(int))); + fail_malloc = 1; + delay_fail_malloc = 1; + assert(!deque_init(sizeof(int))); + fail_malloc = 1; + delay_fail_malloc = 2; + assert(!deque_init(sizeof(int))); +} + +static void test_trim_out_of_memory(void) +{ + deque me = deque_init(sizeof(int)); + int i; + for (i = 0; i < 32; i++) { + deque_push_back(me, &i); + } + assert(deque_size(me) == 32); + fail_malloc = 1; + assert(deque_trim(me) == -ENOMEM); + for (i = 0; i < 32; i++) { + int get = 0xdeadbeef; + deque_get_at(&get, me, i); + assert(get == i); + } + assert(deque_size(me) == 32); + assert(!deque_destroy(me)); +} + +static void test_push_front_out_of_memory(void) +{ + deque me = deque_init(sizeof(int)); + int i; + for (i = 0; i < 5; i++) { + assert(deque_push_front(me, &i) == 0); + } + assert(deque_size(me) == 5); + fail_realloc = 1; + assert(deque_push_front(me, &i) == -ENOMEM); + assert(deque_size(me) == 5); + for (i = 0; i < 5; i++) { + int get = 0xdeadbeef; + deque_get_at(&get, me, i); + } + fail_malloc = 1; + assert(deque_push_front(me, &i) == -ENOMEM); + assert(deque_size(me) == 5); + for (i = 0; i < 5; i++) { + int get = 0xdeadbeef; + deque_get_at(&get, me, i); + } + assert(!deque_destroy(me)); +} + +static void test_push_back_out_of_memory(void) +{ + deque me = deque_init(sizeof(int)); + int i; + for (i = 0; i < 3; i++) { + assert(deque_push_back(me, &i) == 0); + } + assert(deque_size(me) == 3); + fail_realloc = 1; + assert(deque_push_back(me, &i) == -ENOMEM); + assert(deque_size(me) == 3); + for (i = 0; i < 3; i++) { + int get = 0xdeadbeef; + deque_get_at(&get, me, i); + } + fail_malloc = 1; + assert(deque_push_back(me, &i) == -ENOMEM); + assert(deque_size(me) == 3); + for (i = 0; i < 3; i++) { + int get = 0xdeadbeef; + deque_get_at(&get, me, i); + } + assert(!deque_destroy(me)); +} + +static void test_clear_out_of_memory(void) +{ + deque me = deque_init(sizeof(int)); + int i; + for (i = 0; i < 32; i++) { + deque_push_back(me, &i); + } + assert(deque_size(me) == 32); + fail_malloc = 1; + assert(deque_clear(me) == -ENOMEM); + for (i = 0; i < 32; i++) { + int get = 0xdeadbeef; + deque_get_at(&get, me, i); + assert(get == i); + } + assert(deque_size(me) == 32); + fail_malloc = 1; + delay_fail_malloc = 1; + assert(deque_clear(me) == -ENOMEM); + for (i = 0; i < 32; i++) { + int get = 0xdeadbeef; + deque_get_at(&get, me, i); + assert(get == i); + } + assert(deque_size(me) == 32); + assert(!deque_destroy(me)); +} + +void test_deque(void) +{ + test_invalid_init(); + test_basic(); + test_trim(); + test_init_out_of_memory(); + test_trim_out_of_memory(); + test_push_front_out_of_memory(); + test_push_back_out_of_memory(); + test_clear_out_of_memory(); +} diff --git a/tst/forward_list.c b/tst/forward_list.c index eb0c0fa..436b4f5 100644 --- a/tst/forward_list.c +++ b/tst/forward_list.c @@ -1,20 +1,17 @@ #include "test.h" #include "../src/forward_list.h" -void test_forward_list(void) +static void test_invalid_init(void) +{ + assert(!forward_list_init(0)); +} + +static void test_front(forward_list me) { int val[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; int get_arr[10] = {0}; - int trimmed[5] = {0}; - int arr[3] = {0}; - int add; - forward_list me; int get; - int set; int i; - assert(!forward_list_init(0)); - me = forward_list_init(sizeof(int)); - assert(me); assert(forward_list_size(me) == 0); assert(forward_list_is_empty(me)); for (i = 0; i < 10; i++) { @@ -36,13 +33,25 @@ void test_forward_list(void) for (i = 0; i < 7; i++) { forward_list_remove_last(me); } +} + +static void test_linear_operations(forward_list me) +{ + int trimmed[5] = {0}; + int index; + int first; + int add; + int get; + int set; + int i; forward_list_copy_to_array(trimmed, me); assert(forward_list_size(me) == 3); for (i = 0; i < 3; i++) { assert(10 - i == trimmed[i]); } + index = forward_list_size(me); add = 3; - forward_list_add_last(me, &add); + forward_list_add_at(me, index, &add); add = -1; forward_list_add_at(me, 1, &add); add = -2; @@ -70,6 +79,12 @@ void test_forward_list(void) forward_list_remove_first(me); forward_list_remove_at(me, 2); forward_list_remove_last(me); + get = 34; + forward_list_add_at(me, 0, &get); + first = 0xdeadbeef; + forward_list_get_first(&first, me); + assert(first == get); + forward_list_remove_first(me); assert(forward_list_size(me) == 3); get = 345; forward_list_get_first(&get, me); @@ -84,6 +99,12 @@ void test_forward_list(void) forward_list_set_at(me, 1, &set); set = 14; forward_list_set_last(me, &set); +} + +static void test_array_copy(forward_list me) +{ + int arr[3] = {0}; + int set; forward_list_copy_to_array(arr, me); assert(arr[0] == 12); assert(arr[1] == 13); @@ -98,6 +119,11 @@ void test_forward_list(void) assert(arr[0] == -5); assert(arr[1] == -6); assert(arr[2] == -7); +} + +static void test_invalid_index(forward_list me) +{ + int set = 0xdeadbeef; assert(forward_list_set_at(me, 4, &set) == -EINVAL); assert(forward_list_get_at(&set, me, 4) == -EINVAL); assert(forward_list_remove_at(me, 4) == -EINVAL); @@ -111,6 +137,135 @@ void test_forward_list(void) assert(forward_list_is_empty(me)); assert(forward_list_remove_first(me) == -EINVAL); assert(forward_list_remove_last(me) == -EINVAL); - me = forward_list_destroy(me); - assert(!me); +} + +static void test_basic(void) +{ + forward_list me = forward_list_init(sizeof(int)); + assert(me); + test_front(me); + test_linear_operations(me); + test_array_copy(me); + test_invalid_index(me); + assert(!forward_list_destroy(me)); +} + +static void test_init_out_of_memory(void) +{ + fail_malloc = 1; + assert(!forward_list_init(sizeof(int))); +} + +static void test_add_first_out_of_memory(void) +{ + int i; + forward_list me = forward_list_init(sizeof(int)); + assert(me); + for (i = 0; i < 16; i++) { + assert(forward_list_add_first(me, &i) == 0); + } + assert(forward_list_size(me) == 16); + fail_malloc = 1; + assert(forward_list_add_first(me, &i) == -ENOMEM); + assert(forward_list_size(me) == 16); + for (i = 0; i < 16; i++) { + int get = 0xdeadbeef; + assert(forward_list_get_at(&get, me, i) == 0); + assert(get == 15 - i); + } + fail_malloc = 1; + delay_fail_malloc = 1; + assert(forward_list_add_first(me, &i) == -ENOMEM); + assert(forward_list_size(me) == 16); + for (i = 0; i < 16; i++) { + int get = 0xdeadbeef; + assert(forward_list_get_at(&get, me, i) == 0); + assert(get == 15 - i); + } + assert(!forward_list_destroy(me)); +} + +static void test_add_at_out_of_memory(void) +{ + int get; + int i; + forward_list me = forward_list_init(sizeof(int)); + assert(me); + i = 982; + assert(forward_list_add_first(me, &i) == 0); + i = 157; + assert(forward_list_add_first(me, &i) == 0); + for (i = 1; i < 15; i++) { + assert(forward_list_add_at(me, i, &i) == 0); + } + assert(forward_list_size(me) == 16); + fail_malloc = 1; + assert(forward_list_add_at(me, 5, &i) == -ENOMEM); + assert(forward_list_size(me) == 16); + get = 0xdeadbeef; + assert(forward_list_get_at(&get, me, 0) == 0); + assert(get == 157); + for (i = 1; i < 15; i++) { + get = 0xdeadbeef; + assert(forward_list_get_at(&get, me, i) == 0); + assert(get == i); + } + get = 0xdeadbeef; + assert(forward_list_get_at(&get, me, 15) == 0); + assert(get == 982); + fail_malloc = 1; + delay_fail_malloc = 1; + assert(forward_list_add_at(me, 5, &i) == -ENOMEM); + assert(forward_list_size(me) == 16); + get = 0xdeadbeef; + assert(forward_list_get_at(&get, me, 0) == 0); + assert(get == 157); + for (i = 1; i < 15; i++) { + get = 0xdeadbeef; + assert(forward_list_get_at(&get, me, i) == 0); + assert(get == i); + } + get = 0xdeadbeef; + assert(forward_list_get_at(&get, me, 15) == 0); + assert(get == 982); + assert(!forward_list_destroy(me)); +} + +static void test_add_last_out_of_memory(void) +{ + int i; + forward_list me = forward_list_init(sizeof(int)); + assert(me); + for (i = 0; i < 16; i++) { + assert(forward_list_add_last(me, &i) == 0); + } + assert(forward_list_size(me) == 16); + fail_malloc = 1; + assert(forward_list_add_last(me, &i) == -ENOMEM); + assert(forward_list_size(me) == 16); + for (i = 0; i < 16; i++) { + int get = 0xdeadbeef; + assert(forward_list_get_at(&get, me, i) == 0); + assert(get == i); + } + fail_malloc = 1; + delay_fail_malloc = 1; + assert(forward_list_add_last(me, &i) == -ENOMEM); + assert(forward_list_size(me) == 16); + for (i = 0; i < 16; i++) { + int get = 0xdeadbeef; + assert(forward_list_get_at(&get, me, i) == 0); + assert(get == i); + } + assert(!forward_list_destroy(me)); +} + +void test_forward_list(void) +{ + test_invalid_init(); + test_basic(); + test_init_out_of_memory(); + test_add_first_out_of_memory(); + test_add_at_out_of_memory(); + test_add_last_out_of_memory(); } diff --git a/tst/list.c b/tst/list.c index 401bbf8..3706488 100644 --- a/tst/list.c +++ b/tst/list.c @@ -1,22 +1,17 @@ #include "test.h" #include "../src/list.h" -void test_list(void) +static void test_invalid_init(void) +{ + assert(!list_init(0)); +} + +static void test_front(list me) { int val[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; int get_arr[10] = {0}; - int trimmed[5] = {0}; - int arr[3] = {0}; - list me; - int first; - int index; - int add; int get; - int set; int i; - assert(!list_init(0)); - me = list_init(sizeof(int)); - assert(me); assert(list_size(me) == 0); assert(list_is_empty(me)); for (i = 0; i < 10; i++) { @@ -38,6 +33,17 @@ void test_list(void) for (i = 0; i < 7; i++) { list_remove_last(me); } +} + +static void test_linear_operations(list me) +{ + int trimmed[5] = {0}; + int index; + int first; + int add; + int get; + int set; + int i; list_copy_to_array(trimmed, me); assert(list_size(me) == 3); for (i = 0; i < 3; i++) { @@ -93,6 +99,12 @@ void test_list(void) list_set_at(me, 1, &set); set = 14; list_set_last(me, &set); +} + +static void test_array_copy(list me) +{ + int arr[3] = {0}; + int set; list_copy_to_array(arr, me); assert(arr[0] == 12); assert(arr[1] == 13); @@ -107,6 +119,11 @@ void test_list(void) assert(arr[0] == -5); assert(arr[1] == -6); assert(arr[2] == -7); +} + +static void test_invalid_index(list me) +{ + int set = 0xdeadbeef; assert(list_set_at(me, 4, &set) == -EINVAL); assert(list_get_at(&set, me, 4) == -EINVAL); assert(list_remove_at(me, 4) == -EINVAL); @@ -120,6 +137,135 @@ void test_list(void) assert(list_is_empty(me)); assert(list_remove_first(me) == -EINVAL); assert(list_remove_last(me) == -EINVAL); - me = list_destroy(me); - assert(!me); +} + +static void test_basic(void) +{ + list me = list_init(sizeof(int)); + assert(me); + test_front(me); + test_linear_operations(me); + test_array_copy(me); + test_invalid_index(me); + assert(!list_destroy(me)); +} + +static void test_init_out_of_memory(void) +{ + fail_malloc = 1; + assert(!list_init(sizeof(int))); +} + +static void test_add_first_out_of_memory(void) +{ + int i; + list me = list_init(sizeof(int)); + assert(me); + for (i = 0; i < 16; i++) { + assert(list_add_first(me, &i) == 0); + } + assert(list_size(me) == 16); + fail_malloc = 1; + assert(list_add_first(me, &i) == -ENOMEM); + assert(list_size(me) == 16); + for (i = 0; i < 16; i++) { + int get = 0xdeadbeef; + assert(list_get_at(&get, me, i) == 0); + assert(get == 15 - i); + } + fail_malloc = 1; + delay_fail_malloc = 1; + assert(list_add_first(me, &i) == -ENOMEM); + assert(list_size(me) == 16); + for (i = 0; i < 16; i++) { + int get = 0xdeadbeef; + assert(list_get_at(&get, me, i) == 0); + assert(get == 15 - i); + } + assert(!list_destroy(me)); +} + +static void test_add_at_out_of_memory(void) +{ + int get; + int i; + list me = list_init(sizeof(int)); + assert(me); + i = 982; + assert(list_add_first(me, &i) == 0); + i = 157; + assert(list_add_first(me, &i) == 0); + for (i = 1; i < 15; i++) { + assert(list_add_at(me, i, &i) == 0); + } + assert(list_size(me) == 16); + fail_malloc = 1; + assert(list_add_at(me, 5, &i) == -ENOMEM); + assert(list_size(me) == 16); + get = 0xdeadbeef; + assert(list_get_at(&get, me, 0) == 0); + assert(get == 157); + for (i = 1; i < 15; i++) { + get = 0xdeadbeef; + assert(list_get_at(&get, me, i) == 0); + assert(get == i); + } + get = 0xdeadbeef; + assert(list_get_at(&get, me, 15) == 0); + assert(get == 982); + fail_malloc = 1; + delay_fail_malloc = 1; + assert(list_add_at(me, 5, &i) == -ENOMEM); + assert(list_size(me) == 16); + get = 0xdeadbeef; + assert(list_get_at(&get, me, 0) == 0); + assert(get == 157); + for (i = 1; i < 15; i++) { + get = 0xdeadbeef; + assert(list_get_at(&get, me, i) == 0); + assert(get == i); + } + get = 0xdeadbeef; + assert(list_get_at(&get, me, 15) == 0); + assert(get == 982); + assert(!list_destroy(me)); +} + +static void test_add_last_out_of_memory(void) +{ + int i; + list me = list_init(sizeof(int)); + assert(me); + for (i = 0; i < 16; i++) { + assert(list_add_last(me, &i) == 0); + } + assert(list_size(me) == 16); + fail_malloc = 1; + assert(list_add_last(me, &i) == -ENOMEM); + assert(list_size(me) == 16); + for (i = 0; i < 16; i++) { + int get = 0xdeadbeef; + assert(list_get_at(&get, me, i) == 0); + assert(get == i); + } + fail_malloc = 1; + delay_fail_malloc = 1; + assert(list_add_last(me, &i) == -ENOMEM); + assert(list_size(me) == 16); + for (i = 0; i < 16; i++) { + int get = 0xdeadbeef; + assert(list_get_at(&get, me, i) == 0); + assert(get == i); + } + assert(!list_destroy(me)); +} + +void test_list(void) +{ + test_invalid_init(); + test_basic(); + test_init_out_of_memory(); + test_add_first_out_of_memory(); + test_add_at_out_of_memory(); + test_add_last_out_of_memory(); } diff --git a/tst/map.c b/tst/map.c index d4f3c7a..5e880bf 100644 --- a/tst/map.c +++ b/tst/map.c @@ -1,6 +1,77 @@ #include "test.h" #include "../src/map.h" +/* + * Include this struct to verify the tree. + */ +struct internal_map { + size_t key_size; + size_t value_size; + int (*comparator)(const void *const one, const void *const two); + int size; + struct node *root; +}; + +/* + * Include this struct to verify the tree. + */ +struct node { + struct node *parent; + int balance; + void *key; + void *value; + struct node *left; + struct node *right; +}; + + +/* + * Verifies that the AVL tree rules are followed. The balance factor of an item + * must be the right height minus the left height. Also, the left key must be + * less than the right key. + */ +static int map_verify_recursive(struct node *const item) +{ + int left; + int right; + int max; + if (!item) { + return 0; + } + left = map_verify_recursive(item->left); + right = map_verify_recursive(item->right); + max = left > right ? left : right; + assert(right - left == item->balance); + if (item->left && item->right) { + const int left_val = *(int *) item->left->key; + const int right_val = *(int *) item->right->key; + assert(left_val < right_val); + } + if (item->left) { + assert(item->left->parent == item); + assert(item->left->parent->key == item->key); + } + if (item->right) { + assert(item->right->parent == item); + assert(item->right->parent->key == item->key); + } + return max + 1; +} + +static int map_compute_size(struct node *const item) +{ + if (!item) { + return 0; + } + return 1 + map_compute_size(item->left) + map_compute_size(item->right); +} + +static void map_verify(map me) +{ + map_verify_recursive(me->root); + assert(map_compute_size(me->root) == map_size(me)); +} + static int compare_int(const void *const one, const void *const two) { const int a = *(int *) one; @@ -8,250 +79,313 @@ static int compare_int(const void *const one, const void *const two) return a - b; } -void test_map(void) +static void test_invalid_init(void) { - int val_arr[10] = {5, 9, 4, -5, 0, 6, 1, 5, 7, 2}; - int c[10] = {5, 9, 4, -5, 0, 6, 1, 5, 7, 2}; - map me; - int key; - int value; - int num; - int count; - int flip; - int p; - int i; - int j; assert(!map_init(0, sizeof(int), compare_int)); assert(!map_init(sizeof(int), 0, compare_int)); assert(!map_init(sizeof(int), sizeof(int), NULL)); - me = map_init(sizeof(int), sizeof(int), compare_int); +} + +static void mutation_order(map me, const int *const arr, const int size) +{ + int i; + int actual_size = 0; + assert(map_is_empty(me)); + for (i = 0; i < size; i++) { + int num = arr[i]; + if (num > 0) { + assert(map_put(me, &num, &num) == 0); + actual_size++; + } else { + int actual_num = -1 * num; + assert(map_remove(me, &actual_num)); + actual_size--; + } + } + assert(map_size(me) == actual_size); + map_verify(me); +} + +/* + * Targets the (child->balance == 0) branch. + */ +static void test_rotate_left_balanced_child(map me) +{ + int i; + int arr[] = {2, 4, 1, 3, 5, -1}; + int size = sizeof(arr) / sizeof(arr[0]); + mutation_order(me, arr, size); + for (i = 2; i <= 5; i++) { + assert(map_contains(me, &i)); + } +} + +/* + * Targets the else branch. + */ +static void test_rotate_left_unbalanced_child(map me) +{ + int i; + int arr[] = {1, 2, 3}; + int size = sizeof(arr) / sizeof(arr[0]); + mutation_order(me, arr, size); + for (i = 1; i <= 3; i++) { + assert(map_contains(me, &i)); + } +} + +/* + * Targets (parent->balance == 2 && child->balance >= 0) in the map_repair + * function. + */ +static void test_rotate_left(void) +{ + map me = map_init(sizeof(int), sizeof(int), compare_int); + assert(me); + test_rotate_left_balanced_child(me); + map_clear(me); + test_rotate_left_unbalanced_child(me); + assert(!map_destroy(me)); +} + +/* + * Targets the (child->balance == 0) branch. + */ +static void test_rotate_right_balanced_child(map me) +{ + int i; + int arr[] = {4, 2, 5, 1, 3, -5}; + int size = sizeof(arr) / sizeof(arr[0]); + mutation_order(me, arr, size); + for (i = 1; i <= 4; i++) { + assert(map_contains(me, &i)); + } +} + +/* + * Targets the else branch. + */ +static void test_rotate_right_unbalanced_child(map me) +{ + int i; + int arr[] = {3, 2, 1}; + int size = sizeof(arr) / sizeof(arr[0]); + mutation_order(me, arr, size); + for (i = 1; i <= 3; i++) { + assert(map_contains(me, &i)); + } +} + +/* + * Targets (parent->balance == -2 && child->balance <= 0) in the map_repair + * function. + */ +static void test_rotate_right(void) +{ + map me = map_init(sizeof(int), sizeof(int), compare_int); + assert(me); + test_rotate_right_balanced_child(me); + map_clear(me); + test_rotate_right_unbalanced_child(me); + assert(!map_destroy(me)); +} + +/* + * Targets the (grand_child->balance == 1) branch. + */ +static void test_rotate_left_right_positively_balanced_grand_child(map me) +{ + int i; + int arr[] = {5, 2, 6, 1, 3, 4}; + int size = sizeof(arr) / sizeof(arr[0]); + mutation_order(me, arr, size); + for (i = 1; i <= 6; i++) { + assert(map_contains(me, &i)); + } +} + +/* + * Targets the (grand_child->balance == 0) branch. + */ +static void test_rotate_left_right_neutral_balanced_grand_child(map me) +{ + int i; + int arr[] = {3, 1, 2}; + int size = sizeof(arr) / sizeof(arr[0]); + mutation_order(me, arr, size); + for (i = 1; i <= 3; i++) { + assert(map_contains(me, &i)); + } +} + +/* + * Targets the else branch. + */ +static void test_rotate_left_right_negatively_balanced_grand_child(map me) +{ + int i; + int arr[] = {5, 2, 6, 1, 4, 3}; + int size = sizeof(arr) / sizeof(arr[0]); + mutation_order(me, arr, size); + for (i = 1; i <= 6; i++) { + assert(map_contains(me, &i)); + } +} + +/* + * Targets (parent->balance == -2 && child->balance == 1) in the map_repair + * function. + */ +static void test_rotate_left_right(void) +{ + map me = map_init(sizeof(int), sizeof(int), compare_int); + assert(me); + test_rotate_left_right_positively_balanced_grand_child(me); + map_clear(me); + test_rotate_left_right_neutral_balanced_grand_child(me); + map_clear(me); + test_rotate_left_right_negatively_balanced_grand_child(me); + assert(!map_destroy(me)); +} + +/* + * Targets the (grand_child->balance == 1) branch. + */ +static void test_rotate_right_left_positively_balanced_grand_child(map me) +{ + int i; + int arr[] = {2, 1, 5, 3, 6, 4}; + int size = sizeof(arr) / sizeof(arr[0]); + mutation_order(me, arr, size); + for (i = 1; i <= 6; i++) { + assert(map_contains(me, &i)); + } +} + +/* + * Targets the (grand_child->balance == 0) branch. + */ +static void test_rotate_right_left_neutral_balanced_grand_child(map me) +{ + int i; + int arr[] = {1, 3, 2}; + int size = sizeof(arr) / sizeof(arr[0]); + mutation_order(me, arr, size); + for (i = 1; i <= 3; i++) { + assert(map_contains(me, &i)); + } +} + +/* + * Targets the else branch. + */ +static void test_rotate_right_left_negatively_balanced_grand_child(map me) +{ + int i; + int arr[] = {2, 1, 5, 4, 6, 3}; + int size = sizeof(arr) / sizeof(arr[0]); + mutation_order(me, arr, size); + for (i = 1; i <= 6; i++) { + assert(map_contains(me, &i)); + } +} + +/* + * Targets (parent->balance == 2 && child->balance == -1) in the map_repair + * function. + */ +static void test_rotate_right_left(void) +{ + map me = map_init(sizeof(int), sizeof(int), compare_int); + assert(me); + test_rotate_right_left_positively_balanced_grand_child(me); + map_clear(me); + test_rotate_right_left_neutral_balanced_grand_child(me); + map_clear(me); + test_rotate_right_left_negatively_balanced_grand_child(me); + assert(!map_destroy(me)); +} + +/* + * Targets the map_repair function. + */ +static void test_auto_balancing(void) +{ + test_rotate_left(); + test_rotate_right(); + test_rotate_left_right(); + test_rotate_right_left(); +} + +static void test_put_already_existing(void) +{ + int key = 5; + map me = map_init(sizeof(int), sizeof(int), compare_int); assert(me); assert(map_size(me) == 0); - assert(map_is_empty(me)); - key = 4; - value = 9; - map_put(me, &key, &value); + map_put(me, &key, &key); assert(map_size(me) == 1); - value = 5; - map_put(me, &key, &value); + map_put(me, &key, &key); assert(map_size(me) == 1); - assert(!map_is_empty(me)); - assert(map_contains(me, &key)); - value = 0xdeadbeef; - map_get(&value, me, &key); - assert(value == 5); + assert(!map_destroy(me)); +} + +static void test_remove_nothing(void) +{ + int key; + map me = map_init(sizeof(int), sizeof(int), compare_int); + assert(me); + key = 3; + map_put(me, &key, &key); + key = 5; + assert(!map_remove(me, &key)); + assert(!map_destroy(me)); +} + +static void test_contains(void) +{ + int key; + map me = map_init(sizeof(int), sizeof(int), compare_int); + assert(me); key = 7; assert(!map_contains(me, &key)); - map_put(me, &key, &value); - assert(map_size(me) == 2); + key = 3; + map_put(me, &key, &key); + key = 1; + map_put(me, &key, &key); + key = 5; + map_put(me, &key, &key); + key = 0; + assert(!map_contains(me, &key)); + key = 1; assert(map_contains(me, &key)); - for (i = 0; i < 10; i++) { - map_put(me, &val_arr[i], &value); - assert(map_contains(me, &val_arr[i])); - } - assert(map_size(me) == 9); - for (i = 0; i < 10; i++) { - assert(map_contains(me, &val_arr[i])); - } - for (i = -100; i < 100; i++) { - int contains = 0; - for (j = 0; j < 10; j++) { - if (val_arr[j] == i) { - contains = 1; - } - } - assert(map_contains(me, &i) == contains); - } - num = -3; - assert(!map_remove(me, &num)); - assert(map_size(me) == 9); - assert(!map_contains(me, &num)); - num = 6; - assert(map_remove(me, &num)); - assert(map_size(me) == 8); - assert(!map_contains(me, &num)); - num = 4; - assert(map_remove(me, &num)); - assert(map_size(me) == 7); - assert(!map_contains(me, &num)); - num = 7; - assert(map_remove(me, &num)); - assert(map_size(me) == 6); - assert(!map_contains(me, &num)); - num = 9; - assert(map_remove(me, &num)); - assert(map_size(me) == 5); - assert(!map_contains(me, &num)); - num = -5; - assert(map_remove(me, &num)); - assert(map_size(me) == 4); - assert(!map_contains(me, &num)); - num = 0; - assert(map_remove(me, &num)); - assert(map_size(me) == 3); - assert(!map_contains(me, &num)); - num = 1; - assert(map_remove(me, &num)); - assert(map_size(me) == 2); - assert(!map_contains(me, &num)); - num = 5; - assert(map_remove(me, &num)); - assert(map_size(me) == 1); - assert(!map_contains(me, &num)); - num = 2; - assert(map_remove(me, &num)); - assert(map_size(me) == 0); - assert(!map_contains(me, &num)); - /* Add a lot of items and remove individually. */ - for (i = 5000; i < 6000; i++) { - map_put(me, &i, &value); - assert(map_contains(me, &i)); - } - assert(map_size(me) == 1000); - for (i = 5000; i < 6000; i++) { - map_remove(me, &i); - assert(!map_contains(me, &i)); - } - assert(map_size(me) == 0); - assert(map_is_empty(me)); - map_clear(me); - assert(map_size(me) == 0); - assert(map_is_empty(me)); - /* Add a lot of items and clear. */ - for (i = 5000; i < 6000; i++) { - map_put(me, &i, &value); - assert(map_contains(me, &i)); - } - assert(map_size(me) == 1000); - map_clear(me); - key = 0xdeadbeef; - assert(!map_remove(me, &key)); - assert(map_size(me) == 0); - assert(map_is_empty(me)); - me = map_destroy(me); - assert(!me); - me = map_init(sizeof(int), sizeof(int), compare_int); + key = 2; + assert(!map_contains(me, &key)); + key = 3; + assert(map_contains(me, &key)); + key = 4; + assert(!map_contains(me, &key)); + key = 5; + assert(map_contains(me, &key)); + key = 6; + assert(!map_contains(me, &key)); + assert(!map_destroy(me)); +} + +static void test_stress_add(void) +{ + int count = 0; + int flip = 0; + int i; + map me = map_init(sizeof(int), sizeof(int), compare_int); assert(me); - /* left-left */ - key = 5; - map_put(me, &key, &num); - key = 3; - map_put(me, &key, &num); - key = 1; - map_put(me, &key, &num); - key = 0xdeadbeef; - map_contains(me, &key); - map_clear(me); - /* right-right */ - key = 1; - map_put(me, &key, &num); - key = 3; - map_put(me, &key, &num); - key = 5; - map_put(me, &key, &num); - key = 0xdeadbeef; - map_contains(me, &key); - map_clear(me); - /* left-right */ - key = 5; - map_put(me, &key, &num); - key = 1; - map_put(me, &key, &num); - key = 3; - map_put(me, &key, &num); - key = 0xdeadbeef; - map_contains(me, &key); - map_clear(me); - /* right-left */ - key = 1; - map_put(me, &key, &num); - key = 5; - map_put(me, &key, &num); - key = 3; - map_put(me, &key, &num); - key = 0xdeadbeef; - map_contains(me, &key); - map_clear(me); - /* Two children edge case. */ - key = 8; - map_put(me, &key, &num); - key = 5; - map_put(me, &key, &num); - key = 11; - map_put(me, &key, &num); - key = 2; - map_put(me, &key, &num); - key = 6; - map_put(me, &key, &num); - key = 10; - map_put(me, &key, &num); - key = 15; - map_put(me, &key, &num); - key = 1; - map_put(me, &key, &num); - key = 3; - map_put(me, &key, &num); - key = 4; - map_put(me, &key, &num); - key = 7; - map_put(me, &key, &num); - key = 9; - map_put(me, &key, &num); - key = 12; - map_put(me, &key, &num); - key = 13; - map_put(me, &key, &num); - key = 16; - map_put(me, &key, &num); - key = 14; - map_put(me, &key, &num); - map_clear(me); - /* Two children edge case. */ - key = 8; - map_put(me, &key, &num); - key = 4; - map_put(me, &key, &num); - key = 12; - map_put(me, &key, &num); - key = 2; - map_put(me, &key, &num); - key = 6; - map_put(me, &key, &num); - key = 10; - map_put(me, &key, &num); - key = 15; - map_put(me, &key, &num); - key = 1; - map_put(me, &key, &num); - key = 3; - map_put(me, &key, &num); - key = 5; - map_put(me, &key, &num); - key = 7; - map_put(me, &key, &num); - key = 9; - map_put(me, &key, &num); - key = 11; - map_put(me, &key, &num); - key = 13; - map_put(me, &key, &num); - key = 16; - map_put(me, &key, &num); - key = 14; - map_put(me, &key, &num); - map_clear(me); - /* Add a lot of items. */ - count = 0; - flip = 0; for (i = 1234; i < 82400; i++) { int is_already_present; - int is_now_present; - key = i % 765; - is_already_present = map_contains(me, &key); - map_put(me, &key, &num); - is_now_present = map_contains(me, &key); - assert(is_now_present); - if (!is_already_present && is_now_present) { + int num = i % 765; + is_already_present = map_contains(me, &num); + map_put(me, &num, &num); + assert(map_contains(me, &num)); + if (!is_already_present) { count++; } if (i == 1857 && !flip) { @@ -260,288 +394,172 @@ void test_map(void) } } assert(count == map_size(me)); - map_put(me, &key, &num); - map_destroy(me); - me = map_init(sizeof(int), sizeof(int), compare_int); - assert(map_size(me) == 0); - assert(map_is_empty(me)); - key = 4; - map_put(me, &key, &num); - assert(map_size(me) == 1); - map_put(me, &key, &num); - assert(map_size(me) == 1); - assert(!map_is_empty(me)); - assert(map_contains(me, &key)); - key = 7; - assert(!map_contains(me, &key)); - map_put(me, &key, &num); - assert(map_size(me) == 2); - assert(map_contains(me, &key)); - for (i = 0; i < 10; i++) { - map_put(me, &c[i], &num); - assert(map_contains(me, &c[i])); - } - assert(map_size(me) == 9); - for (i = 0; i < 10; i++) { - assert(map_contains(me, &c[i])); - } - for (i = -100; i < 100; i++) { - int contains = 0; - for (j = 0; j < 10; j++) { - if (c[j] == i) { - contains = 1; - } - } - assert(map_contains(me, &i) == contains); - } - num = -3; - assert(!map_remove(me, &num)); - assert(map_size(me) == 9); - assert(!map_contains(me, &num)); - num = 6; - assert(map_remove(me, &num)); - assert(map_size(me) == 8); - assert(!map_contains(me, &num)); - num = 4; - assert(map_remove(me, &num)); - assert(map_size(me) == 7); - assert(!map_contains(me, &num)); - num = 7; - assert(map_remove(me, &num)); - assert(map_size(me) == 6); - assert(!map_contains(me, &num)); - num = 9; - assert(map_remove(me, &num)); - assert(map_size(me) == 5); - assert(!map_contains(me, &num)); - num = -5; - assert(map_remove(me, &num)); - assert(map_size(me) == 4); - assert(!map_contains(me, &num)); - num = 0; - assert(map_remove(me, &num)); - assert(map_size(me) == 3); - assert(!map_contains(me, &num)); - num = 1; - assert(map_remove(me, &num)); - assert(map_size(me) == 2); - assert(!map_contains(me, &num)); - num = 5; - assert(map_remove(me, &num)); - assert(map_size(me) == 1); - assert(!map_contains(me, &num)); - num = 2; - assert(map_remove(me, &num)); - assert(map_size(me) == 0); - assert(!map_contains(me, &num)); - /* Add a lot of items and remove individually. */ - for (i = 5000; i < 6000; i++) { - map_put(me, &i, &num); - assert(map_contains(me, &i)); - } - assert(map_size(me) == 1000); - for (i = 5000; i < 5500; i++) { - map_remove(me, &i); - assert(!map_contains(me, &i)); - } - assert(map_size(me) == 500); - assert(!map_is_empty(me)); - map_clear(me); - assert(map_size(me) == 0); - assert(map_is_empty(me)); - /* Add a lot of items and clear. */ - for (i = 5000; i < 6000; i++) { - map_put(me, &i, &num); - assert(map_contains(me, &i)); - } - assert(map_size(me) == 1000); - map_clear(me); - p = 0xdeadbeef; - assert(!map_remove(me, &p)); - assert(map_size(me) == 0); - assert(map_is_empty(me)); - me = map_destroy(me); - assert(!me); - /* Create odd shape graph. */ - me = map_init(sizeof(int), sizeof(int), compare_int); - key = 10; - map_put(me, &key, &num); - key = 5; - map_put(me, &key, &num); - key = 15; - map_put(me, &key, &num); - key = 3; - map_put(me, &key, &num); - key = 8; - map_put(me, &key, &num); - key = 12; - map_put(me, &key, &num); - key = 18; - map_put(me, &key, &num); - key = 12; - map_remove(me, &key); - key = 5; - map_remove(me, &key); - key = 3; - map_remove(me, &key); - key = 8; - map_remove(me, &key); - map_clear(me); - /* Allocate many nodes. */ + assert(!map_destroy(me)); +} + +static void test_stress_remove(void) +{ + int i; + map me = map_init(sizeof(int), sizeof(int), compare_int); + assert(me); for (i = 8123; i < 12314; i += 3) { - map_put(me, &i, &num); + map_put(me, &i, &i); assert(map_contains(me, &i)); } for (i = 13000; i > 8000; i--) { map_remove(me, &i); assert(!map_contains(me, &i)); } - map_clear(me); - /* Create another odd shape graph. */ - key = 20; - map_put(me, &key, &num); - key = 10; - map_put(me, &key, &num); - key = 40; - map_put(me, &key, &num); - key = 5; - map_put(me, &key, &num); - key = 15; - map_put(me, &key, &num); - key = 30; - map_put(me, &key, &num); - key = 50; - map_put(me, &key, &num); - key = 25; - map_put(me, &key, &num); - key = 35; - map_put(me, &key, &num); - key = 36; - map_put(me, &key, &num); - key = 34; - map_put(me, &key, &num); - key = 33; - map_put(me, &key, &num); - key = 32; - map_put(me, &key, &num); - key = 30; - map_remove(me, &key); - key = 32; - assert(map_contains(me, &key)); - map_clear(me); - /* One sided tree. */ - key = 10; - map_put(me, &key, &num); - key = 9; - map_put(me, &key, &num); - key = 8; - map_put(me, &key, &num); - key = 7; - map_put(me, &key, &num); - key = 8; - map_remove(me, &key); - key = 7; - assert(map_contains(me, &key)); - map_destroy(me); - /* Replace two sided two children. */ - me = map_init(sizeof(int), sizeof(int), compare_int); - key = 5; - map_put(me, &key, &num); - key = 1; - map_put(me, &key, &num); - key = 6; - map_put(me, &key, &num); - key = -1; - map_put(me, &key, &num); - key = 3; - map_put(me, &key, &num); - key = 7; - map_put(me, &key, &num); - key = -2; - map_put(me, &key, &num); - key = 0; - map_put(me, &key, &num); - key = 2; - map_put(me, &key, &num); - key = 4; - map_put(me, &key, &num); - key = 1; - map_remove(me, &key); - assert(!map_contains(me, &key)); - map_clear(me); - key = 5; - map_put(me, &key, &num); - key = 1; - map_put(me, &key, &num); - key = 6; - map_put(me, &key, &num); - key = -1; - map_put(me, &key, &num); - key = 3; - map_put(me, &key, &num); - key = 7; - map_put(me, &key, &num); - key = -2; - map_put(me, &key, &num); - key = 0; - map_put(me, &key, &num); - key = 4; - map_put(me, &key, &num); - key = 1; - map_remove(me, &key); - assert(!map_contains(me, &key)); - me = map_destroy(me); - assert(!me); - me = map_init(sizeof(int), sizeof(int), compare_int); - for (i = 4817; i > -2983; i -= 11) { - map_put(me, &i, &num); - assert(map_contains(me, &i)); - } - for (i = -432; i < 3849; i += 7) { - map_remove(me, &i); - assert(!map_contains(me, &i)); - } - map_clear(me); - key = 5; - map_put(me, &key, &num); - key = 7; - map_put(me, &key, &num); - key = 5; - map_remove(me, &key); - map_clear(me); - /* Two children edge case other side. */ - key = 8; - map_put(me, &key, &num); - key = 4; - map_put(me, &key, &num); - key = 12; - map_put(me, &key, &num); - key = 2; - map_put(me, &key, &num); - key = 6; - map_put(me, &key, &num); - key = 10; - map_put(me, &key, &num); - key = 16; - map_put(me, &key, &num); - key = 1; - map_put(me, &key, &num); - key = 3; - map_put(me, &key, &num); - key = 5; - map_put(me, &key, &num); - key = 7; - map_put(me, &key, &num); - key = 9; - map_put(me, &key, &num); - key = 11; - map_put(me, &key, &num); - key = 15; - map_put(me, &key, &num); - key = 17; - map_put(me, &key, &num); - key = 13; - map_put(me, &key, &num); - map_clear(me); - assert(!map_get(&value, me, &key)); + assert(!map_destroy(me)); +} + +static void test_unique_delete_one_child(map me) +{ + int arr1[] = {2, 1, -2}; + int arr2[] = {1, 2, -1}; + int arr3[] = {3, 2, 4, 1, -2}; + int arr4[] = {3, 1, 4, 2, -1}; + int arr5[] = {3, 1, 4, 2, -4}; + int arr6[] = {2, 1, 3, 4, -3}; + int sz1 = sizeof(arr1) / sizeof(arr1[0]); + int sz2 = sizeof(arr2) / sizeof(arr2[0]); + int sz3 = sizeof(arr3) / sizeof(arr3[0]); + int sz4 = sizeof(arr4) / sizeof(arr4[0]); + int sz5 = sizeof(arr5) / sizeof(arr5[0]); + int sz6 = sizeof(arr6) / sizeof(arr6[0]); + mutation_order(me, arr1, sz1); + map_clear(me); + mutation_order(me, arr2, sz2); + map_clear(me); + mutation_order(me, arr3, sz3); + map_clear(me); + mutation_order(me, arr4, sz4); + map_clear(me); + mutation_order(me, arr5, sz5); + map_clear(me); + mutation_order(me, arr6, sz6); +} + +static void test_unique_delete_two_children(map me) +{ + int arr1[] = {2, 1, 3, -2}; + int arr2[] = {4, 2, 5, 1, 3, -2}; + int arr3[] = {2, 1, 4, 3, 5, -4}; + int sz1 = sizeof(arr1) / sizeof(arr1[0]); + int sz2 = sizeof(arr2) / sizeof(arr2[0]); + int sz3 = sizeof(arr3) / sizeof(arr3[0]); + mutation_order(me, arr1, sz1); + map_clear(me); + mutation_order(me, arr2, sz2); + map_clear(me); + mutation_order(me, arr3, sz3); +} + +static void test_unique_deletion_patterns(void) +{ + map me = map_init(sizeof(int), sizeof(int), compare_int); + assert(me); + test_unique_delete_one_child(me); + map_clear(me); + test_unique_delete_two_children(me); + assert(!map_destroy(me)); +} + +static void test_override_value(void) +{ + int key = 5; + int value = 17; + map me = map_init(sizeof(int), sizeof(int), compare_int); + assert(me); + assert(!map_get(&value, me, &key)); + assert(key == 5); + assert(value == 17); + map_put(me, &key, &value); + key = 5; + value = 0xdeafbeef; + map_get(&value, me, &key); + assert(key == 5); + assert(value == 17); + value = 97; + map_put(me, &key, &value); + key = 5; + value = 0xdeafbeef; + map_get(&value, me, &key); + assert(key == 5); + assert(value != 17); + assert(value == 97); + assert(map_size(me) == 1); + assert(!map_destroy(me)); +} + +static void test_init_out_of_memory(void) +{ + fail_malloc = 1; + assert(!map_init(sizeof(int), sizeof(int), compare_int)); +} + +static void test_put_root_out_of_memory(map me) +{ + int key = 2; + fail_malloc = 1; + assert(map_put(me, &key, &key) == -ENOMEM); + fail_malloc = 1; + delay_fail_malloc = 1; + assert(map_put(me, &key, &key) == -ENOMEM); + fail_malloc = 1; + delay_fail_malloc = 2; + assert(map_put(me, &key, &key) == -ENOMEM); +} + +static void test_put_on_left_out_of_memory(map me) +{ + int key = 1; + fail_malloc = 1; + assert(map_put(me, &key, &key) == -ENOMEM); + fail_malloc = 1; + delay_fail_malloc = 1; + assert(map_put(me, &key, &key) == -ENOMEM); + fail_malloc = 1; + delay_fail_malloc = 2; + assert(map_put(me, &key, &key) == -ENOMEM); +} + +static void test_put_on_right_out_of_memory(map me) +{ + int key = 3; + fail_malloc = 1; + assert(map_put(me, &key, &key) == -ENOMEM); + fail_malloc = 1; + delay_fail_malloc = 1; + assert(map_put(me, &key, &key) == -ENOMEM); + fail_malloc = 1; + delay_fail_malloc = 2; + assert(map_put(me, &key, &key) == -ENOMEM); +} + +static void test_put_out_of_memory(void) +{ + int key = 2; + map me = map_init(sizeof(int), sizeof(int), compare_int); + assert(me); + test_put_root_out_of_memory(me); + assert(map_put(me, &key, &key) == 0); + test_put_on_left_out_of_memory(me); + test_put_on_right_out_of_memory(me); + assert(!map_destroy(me)); +} + +void test_map(void) +{ + test_invalid_init(); + test_auto_balancing(); + test_put_already_existing(); + test_remove_nothing(); + test_contains(); + test_stress_add(); + test_stress_remove(); + test_unique_deletion_patterns(); + test_override_value(); + test_init_out_of_memory(); + test_put_out_of_memory(); } diff --git a/tst/multimap.c b/tst/multimap.c index 859ee43..3ee06f1 100644 --- a/tst/multimap.c +++ b/tst/multimap.c @@ -1,6 +1,80 @@ #include "test.h" #include "../src/multimap.h" +/* + * Include this struct to verify the tree. + */ +struct internal_multimap { + size_t key_size; + size_t value_size; + int (*key_comparator)(const void *const one, const void *const two); + int (*value_comparator)(const void *const one, const void *const two); + int size; + struct node *root; + struct value_node *iterate_get; +}; + +/* + * Include this struct to verify the tree. + */ +struct node { + struct node *parent; + int balance; + void *key; + int value_count; + struct value_node *head; + struct node *left; + struct node *right; +}; + +/* + * Verifies that the AVL tree rules are followed. The balance factor of an item + * must be the right height minus the left height. Also, the left key must be + * less than the right key. + */ +static int multimap_verify_recursive(struct node *const item) +{ + int left; + int right; + int max; + if (!item) { + return 0; + } + left = multimap_verify_recursive(item->left); + right = multimap_verify_recursive(item->right); + max = left > right ? left : right; + assert(right - left == item->balance); + if (item->left && item->right) { + const int left_val = *(int *) item->left->key; + const int right_val = *(int *) item->right->key; + assert(left_val < right_val); + } + if (item->left) { + assert(item->left->parent == item); + assert(item->left->parent->key == item->key); + } + if (item->right) { + assert(item->right->parent == item); + assert(item->right->parent->key == item->key); + } + return max + 1; +} + +static int multimap_compute_size(struct node *const item) +{ + if (!item) { + return 0; + } + return 1 + multimap_compute_size(item->left) + + multimap_compute_size(item->right); +} + +static void multimap_verify(multimap me) +{ + multimap_verify_recursive(me->root); + assert(multimap_compute_size(me->root) == multimap_size(me)); +} + static int compare_int(const void *const one, const void *const two) { const int a = *(int *) one; @@ -8,276 +82,319 @@ static int compare_int(const void *const one, const void *const two) return a - b; } -void test_multimap(void) +static void test_invalid_init(void) { - int val_arr[10] = {5, 9, 4, -5, 0, 6, 1, 5, 7, 2}; - int c[10] = {5, 9, 4, -5, 0, 6, 1, 5, 7, 2}; - multimap me; - int key; - int value; - int num; - int count; - int val; - int flip; - int p; - int i; - int j; assert(!multimap_init(0, sizeof(int), compare_int, compare_int)); assert(!multimap_init(sizeof(int), 0, compare_int, compare_int)); assert(!multimap_init(sizeof(int), sizeof(int), NULL, compare_int)); assert(!multimap_init(sizeof(int), sizeof(int), compare_int, NULL)); - me = multimap_init(sizeof(int), sizeof(int), compare_int, compare_int); - assert(me); - assert(multimap_size(me) == 0); - assert(multimap_is_empty(me)); - key = 4; - value = 123; - multimap_put(me, &key, &value); - assert(multimap_size(me) == 1); - multimap_put(me, &key, &value); - assert(multimap_size(me) == 2); - assert(!multimap_is_empty(me)); - assert(multimap_contains(me, &key)); - key = 7; - assert(!multimap_contains(me, &key)); - multimap_put(me, &key, &value); - assert(multimap_size(me) == 3); - assert(multimap_contains(me, &key)); - multimap_remove(me, &key, &value); - assert(multimap_size(me) == 2); - assert(!multimap_contains(me, &key)); - key = 4; - multimap_remove(me, &key, &value); - assert(multimap_size(me) == 1); - multimap_remove(me, &key, &value); - assert(multimap_size(me) == 0); +} - for (i = 0; i < 10; i++) { - multimap_put(me, &val_arr[i], &value); - assert(multimap_contains(me, &val_arr[i])); - } - assert(multimap_size(me) == 10); - for (i = 0; i < 10; i++) { - assert(multimap_contains(me, &val_arr[i])); - } - for (i = -100; i < 100; i++) { - int contains = 0; - for (j = 0; j < 10; j++) { - if (val_arr[j] == i) { - contains = 1; - } +static void mutation_order(multimap me, const int *const arr, const int size) +{ + int i; + int actual_size = 0; + assert(multimap_is_empty(me)); + for (i = 0; i < size; i++) { + int num = arr[i]; + if (num > 0) { + assert(multimap_put(me, &num, &num) == 0); + actual_size++; + } else { + int actual_num = -1 * num; + assert(multimap_remove(me, &actual_num, &actual_num)); + actual_size--; } - assert(multimap_contains(me, &i) == contains); } - num = -3; - assert(!multimap_remove(me, &num, &value)); - assert(multimap_size(me) == 10); - assert(!multimap_contains(me, &num)); - num = 6; - assert(multimap_remove(me, &num, &value)); - assert(multimap_size(me) == 9); - assert(!multimap_contains(me, &num)); - num = 4; - assert(multimap_remove(me, &num, &value)); - assert(multimap_size(me) == 8); - assert(!multimap_contains(me, &num)); - num = 7; - assert(multimap_remove(me, &num, &value)); - assert(multimap_size(me) == 7); - assert(!multimap_contains(me, &num)); - num = 9; - assert(multimap_remove(me, &num, &value)); - assert(multimap_size(me) == 6); - assert(!multimap_contains(me, &num)); - num = -5; - assert(multimap_remove(me, &num, &value)); - assert(multimap_size(me) == 5); - assert(!multimap_contains(me, &num)); - num = 0; - assert(multimap_remove(me, &num, &value)); - assert(multimap_size(me) == 4); - assert(!multimap_contains(me, &num)); - num = 1; - assert(multimap_remove(me, &num, &value)); - assert(multimap_size(me) == 3); - assert(!multimap_contains(me, &num)); - num = 5; - assert(multimap_count(me, &num) == 2); - multimap_get_start(me, &num); - count = 0; - val = 0xdeadbeef; - while (multimap_get_next(&val, me)) { - count++; - assert(val == 123); - val = 0xdeadbeef; - } - assert(count == 2); - assert(multimap_remove(me, &num, &value)); - assert(multimap_size(me) == 2); - assert(multimap_contains(me, &num)); - num = 2; - assert(multimap_remove(me, &num, &value)); - assert(multimap_size(me) == 1); - assert(!multimap_contains(me, &num)); - num = 5; - assert(multimap_remove(me, &num, &value)); - assert(multimap_size(me) == 0); - assert(!multimap_contains(me, &num)); - /* Add a lot of items and remove individually. */ - for (i = 5000; i < 6000; i++) { - multimap_put(me, &i, &value); + assert(multimap_size(me) == actual_size); + multimap_verify(me); +} + +/* + * Targets the (child->balance == 0) branch. + */ +static void test_rotate_left_balanced_child(multimap me) +{ + int i; + int arr[] = {2, 4, 1, 3, 5, -1}; + int size = sizeof(arr) / sizeof(arr[0]); + mutation_order(me, arr, size); + for (i = 2; i <= 5; i++) { assert(multimap_contains(me, &i)); } - assert(multimap_size(me) == 1000); - for (i = 5000; i < 6000; i++) { - multimap_remove(me, &i, &value); - assert(!multimap_contains(me, &i)); - } - assert(multimap_size(me) == 0); - assert(multimap_is_empty(me)); - multimap_clear(me); - assert(multimap_size(me) == 0); - assert(multimap_is_empty(me)); - /* Add a lot of items and clear. */ - for (i = 5000; i < 6000; i++) { - multimap_put(me, &i, &value); +} + +/* + * Targets the else branch. + */ +static void test_rotate_left_unbalanced_child(multimap me) +{ + int i; + int arr[] = {1, 2, 3}; + int size = sizeof(arr) / sizeof(arr[0]); + mutation_order(me, arr, size); + for (i = 1; i <= 3; i++) { assert(multimap_contains(me, &i)); } - assert(multimap_size(me) == 1000); - multimap_clear(me); - key = 0xdeadbeef; - assert(!multimap_remove(me, &key, &value)); - assert(multimap_size(me) == 0); - assert(multimap_is_empty(me)); - key = 5; - multimap_put(me, &key, &value); - assert(multimap_size(me) == 1); - key = 7; - for (i = 0; i < 10; i++) { - multimap_put(me, &key, &value); - } - assert(multimap_size(me) == 11); - multimap_remove_all(me, &key); - assert(multimap_size(me) == 1); - me = multimap_destroy(me); - assert(!me); - me = multimap_init(sizeof(int), sizeof(int), compare_int, compare_int); +} + +/* + * Targets (parent->balance == 2 && child->balance >= 0) in the multimap_repair + * function. + */ +static void test_rotate_left(void) +{ + multimap me = multimap_init(sizeof(int), sizeof(int), compare_int, + compare_int); assert(me); - /* left-left */ - key = 5; - multimap_put(me, &key, &num); - key = 3; - multimap_put(me, &key, &num); - key = 1; - multimap_put(me, &key, &num); - key = 0xdeadbeef; - multimap_contains(me, &key); + test_rotate_left_balanced_child(me); multimap_clear(me); - /* right-right */ - key = 1; - multimap_put(me, &key, &num); - key = 3; - multimap_put(me, &key, &num); - key = 5; - multimap_put(me, &key, &num); - key = 0xdeadbeef; - multimap_contains(me, &key); + test_rotate_left_unbalanced_child(me); + assert(!multimap_destroy(me)); +} + +/* + * Targets the (child->balance == 0) branch. + */ +static void test_rotate_right_balanced_child(multimap me) +{ + int i; + int arr[] = {4, 2, 5, 1, 3, -5}; + int size = sizeof(arr) / sizeof(arr[0]); + mutation_order(me, arr, size); + for (i = 1; i <= 4; i++) { + assert(multimap_contains(me, &i)); + } +} + +/* + * Targets the else branch. + */ +static void test_rotate_right_unbalanced_child(multimap me) +{ + int i; + int arr[] = {3, 2, 1}; + int size = sizeof(arr) / sizeof(arr[0]); + mutation_order(me, arr, size); + for (i = 1; i <= 3; i++) { + assert(multimap_contains(me, &i)); + } +} + +/* + * Targets (parent->balance == -2 && child->balance <= 0) in the multimap_repair + * function. + */ +static void test_rotate_right(void) +{ + multimap me = multimap_init(sizeof(int), sizeof(int), compare_int, + compare_int); + assert(me); + test_rotate_right_balanced_child(me); multimap_clear(me); - /* left-right */ - key = 5; - multimap_put(me, &key, &num); - key = 1; - multimap_put(me, &key, &num); - key = 3; - multimap_put(me, &key, &num); - key = 0xdeadbeef; - multimap_contains(me, &key); + test_rotate_right_unbalanced_child(me); + assert(!multimap_destroy(me)); +} + +/* + * Targets the (grand_child->balance == 1) branch. + */ +static void test_rotate_left_right_positively_balanced_grand_child(multimap me) +{ + int i; + int arr[] = {5, 2, 6, 1, 3, 4}; + int size = sizeof(arr) / sizeof(arr[0]); + mutation_order(me, arr, size); + for (i = 1; i <= 6; i++) { + assert(multimap_contains(me, &i)); + } +} + +/* + * Targets the (grand_child->balance == 0) branch. + */ +static void test_rotate_left_right_neutral_balanced_grand_child(multimap me) +{ + int i; + int arr[] = {3, 1, 2}; + int size = sizeof(arr) / sizeof(arr[0]); + mutation_order(me, arr, size); + for (i = 1; i <= 3; i++) { + assert(multimap_contains(me, &i)); + } +} + +/* + * Targets the else branch. + */ +static void test_rotate_left_right_negatively_balanced_grand_child(multimap me) +{ + int i; + int arr[] = {5, 2, 6, 1, 4, 3}; + int size = sizeof(arr) / sizeof(arr[0]); + mutation_order(me, arr, size); + for (i = 1; i <= 6; i++) { + assert(multimap_contains(me, &i)); + } +} + +/* + * Targets (parent->balance == -2 && child->balance == 1) in the multimap_repair + * function. + */ +static void test_rotate_left_right(void) +{ + multimap me = multimap_init(sizeof(int), sizeof(int), compare_int, + compare_int); + assert(me); + test_rotate_left_right_positively_balanced_grand_child(me); multimap_clear(me); - /* right-left */ - key = 1; - multimap_put(me, &key, &num); - key = 5; - multimap_put(me, &key, &num); - key = 3; - multimap_put(me, &key, &num); - key = 0xdeadbeef; - multimap_contains(me, &key); + test_rotate_left_right_neutral_balanced_grand_child(me); multimap_clear(me); - /* Two children edge case. */ - key = 8; - multimap_put(me, &key, &num); - key = 5; - multimap_put(me, &key, &num); - key = 11; - multimap_put(me, &key, &num); - key = 2; - multimap_put(me, &key, &num); - key = 6; - multimap_put(me, &key, &num); - key = 10; - multimap_put(me, &key, &num); - key = 15; - multimap_put(me, &key, &num); - key = 1; - multimap_put(me, &key, &num); + test_rotate_left_right_negatively_balanced_grand_child(me); + assert(!multimap_destroy(me)); +} + +/* + * Targets the (grand_child->balance == 1) branch. + */ +static void test_rotate_right_left_positively_balanced_grand_child(multimap me) +{ + int i; + int arr[] = {2, 1, 5, 3, 6, 4}; + int size = sizeof(arr) / sizeof(arr[0]); + mutation_order(me, arr, size); + for (i = 1; i <= 6; i++) { + assert(multimap_contains(me, &i)); + } +} + +/* + * Targets the (grand_child->balance == 0) branch. + */ +static void test_rotate_right_left_neutral_balanced_grand_child(multimap me) +{ + int i; + int arr[] = {1, 3, 2}; + int size = sizeof(arr) / sizeof(arr[0]); + mutation_order(me, arr, size); + for (i = 1; i <= 3; i++) { + assert(multimap_contains(me, &i)); + } +} + +/* + * Targets the else branch. + */ +static void test_rotate_right_left_negatively_balanced_grand_child(multimap me) +{ + int i; + int arr[] = {2, 1, 5, 4, 6, 3}; + int size = sizeof(arr) / sizeof(arr[0]); + mutation_order(me, arr, size); + for (i = 1; i <= 6; i++) { + assert(multimap_contains(me, &i)); + } +} + +/* + * Targets (parent->balance == 2 && child->balance == -1) in the multimap_repair + * function. + */ +static void test_rotate_right_left(void) +{ + multimap me = multimap_init(sizeof(int), sizeof(int), compare_int, + compare_int); + assert(me); + test_rotate_right_left_positively_balanced_grand_child(me); + multimap_clear(me); + test_rotate_right_left_neutral_balanced_grand_child(me); + multimap_clear(me); + test_rotate_right_left_negatively_balanced_grand_child(me); + assert(!multimap_destroy(me)); +} + +/* + * Targets the multimap_repair function. + */ +static void test_auto_balancing(void) +{ + test_rotate_left(); + test_rotate_right(); + test_rotate_left_right(); + test_rotate_right_left(); +} + +static void test_put_already_existing(void) +{ + int key = 5; + multimap me = multimap_init(sizeof(int), sizeof(int), compare_int, + compare_int); + assert(me); + assert(multimap_size(me) == 0); + multimap_put(me, &key, &key); + assert(multimap_size(me) == 1); + multimap_put(me, &key, &key); + assert(multimap_size(me) == 2); + assert(!multimap_destroy(me)); +} + +static void test_remove_nothing(void) +{ + int key; + multimap me = multimap_init(sizeof(int), sizeof(int), compare_int, + compare_int); + assert(me); key = 3; - multimap_put(me, &key, &num); - key = 4; - multimap_put(me, &key, &num); + multimap_put(me, &key, &key); + key = 5; + assert(!multimap_remove(me, &key, &key)); + assert(!multimap_destroy(me)); +} + +static void test_contains(void) +{ + int key; + multimap me = multimap_init(sizeof(int), sizeof(int), compare_int, + compare_int); + assert(me); key = 7; - multimap_put(me, &key, &num); - key = 9; - multimap_put(me, &key, &num); - key = 12; - multimap_put(me, &key, &num); - key = 13; - multimap_put(me, &key, &num); - key = 16; - multimap_put(me, &key, &num); - key = 14; - multimap_put(me, &key, &num); - multimap_clear(me); - /* Two children edge case. */ - key = 8; - multimap_put(me, &key, &num); - key = 4; - multimap_put(me, &key, &num); - key = 12; - multimap_put(me, &key, &num); - key = 2; - multimap_put(me, &key, &num); - key = 6; - multimap_put(me, &key, &num); - key = 10; - multimap_put(me, &key, &num); - key = 15; - multimap_put(me, &key, &num); - key = 1; - multimap_put(me, &key, &num); + assert(!multimap_contains(me, &key)); key = 3; - multimap_put(me, &key, &num); + multimap_put(me, &key, &key); + key = 1; + multimap_put(me, &key, &key); key = 5; - multimap_put(me, &key, &num); - key = 7; - multimap_put(me, &key, &num); - key = 9; - multimap_put(me, &key, &num); - key = 11; - multimap_put(me, &key, &num); - key = 13; - multimap_put(me, &key, &num); - key = 16; - multimap_put(me, &key, &num); - key = 14; - multimap_put(me, &key, &num); - multimap_clear(me); - /* Add a lot of items. */ - count = 0; - flip = 0; + multimap_put(me, &key, &key); + key = 0; + assert(!multimap_contains(me, &key)); + key = 1; + assert(multimap_contains(me, &key)); + key = 2; + assert(!multimap_contains(me, &key)); + key = 3; + assert(multimap_contains(me, &key)); + key = 4; + assert(!multimap_contains(me, &key)); + key = 5; + assert(multimap_contains(me, &key)); + key = 6; + assert(!multimap_contains(me, &key)); + assert(!multimap_destroy(me)); +} + +static void test_stress_add(void) +{ + int count = 0; + int flip = 0; + int i; + multimap me = multimap_init(sizeof(int), sizeof(int), compare_int, + compare_int); + assert(me); for (i = 1234; i < 82400; i++) { - key = i % 765; - multimap_put(me, &key, &num); - assert(multimap_contains(me, &key)); + int num = i % 765; + multimap_put(me, &num, &num); + assert(multimap_contains(me, &num)); count++; if (i == 1857 && !flip) { i *= -1; @@ -285,310 +402,227 @@ void test_multimap(void) } } assert(count == multimap_size(me)); - multimap_put(me, &key, &num); - multimap_destroy(me); - me = multimap_init(sizeof(int), sizeof(int), compare_int, compare_int); - assert(multimap_size(me) == 0); - assert(multimap_is_empty(me)); - key = 4; - multimap_put(me, &key, &num); - assert(multimap_size(me) == 1); - multimap_put(me, &key, &num); - assert(multimap_size(me) == 2); - assert(!multimap_is_empty(me)); - assert(multimap_contains(me, &key)); - key = 7; - assert(!multimap_contains(me, &key)); - multimap_put(me, &key, &num); - assert(multimap_size(me) == 3); - assert(multimap_contains(me, &key)); - for (i = 0; i < 10; i++) { - multimap_put(me, &c[i], &value); - assert(multimap_contains(me, &c[i])); - } - assert(multimap_size(me) == 13); - for (i = 0; i < 10; i++) { - assert(multimap_contains(me, &c[i])); - } - for (i = -100; i < 100; i++) { - int contains = 0; - for (j = 0; j < 10; j++) { - if (c[j] == i) { - contains = 1; - } - } - assert(multimap_contains(me, &i) == contains); - } - num = -3; - assert(!multimap_remove(me, &num, &value)); - assert(multimap_size(me) == 13); - assert(!multimap_contains(me, &num)); - num = 6; - assert(multimap_remove(me, &num, &value)); - assert(multimap_size(me) == 12); - assert(!multimap_contains(me, &num)); - num = 4; - assert(multimap_remove(me, &num, &value)); - assert(multimap_size(me) == 11); - assert(multimap_contains(me, &num)); - num = 7; - assert(multimap_remove(me, &num, &value)); - assert(multimap_size(me) == 10); - assert(multimap_contains(me, &num)); - num = 9; - assert(multimap_remove(me, &num, &value)); - assert(multimap_size(me) == 9); - assert(!multimap_contains(me, &num)); - num = -5; - assert(multimap_remove(me, &num, &value)); - assert(multimap_size(me) == 8); - assert(!multimap_contains(me, &num)); - num = 0; - assert(multimap_remove(me, &num, &value)); - assert(multimap_size(me) == 7); - assert(!multimap_contains(me, &num)); - num = 1; - assert(multimap_remove(me, &num, &value)); - assert(multimap_size(me) == 6); - assert(!multimap_contains(me, &num)); - num = 5; - assert(multimap_remove(me, &num, &value)); - assert(multimap_size(me) == 5); - assert(multimap_contains(me, &num)); - num = 2; - assert(multimap_remove(me, &num, &value)); - assert(multimap_size(me) == 4); - assert(!multimap_contains(me, &num)); - multimap_clear(me); - /* Add a lot of items and remove individually. */ - value = 37; - for (i = 5000; i < 6000; i++) { - multimap_put(me, &i, &value); - assert(multimap_contains(me, &i)); - } - assert(multimap_size(me) == 1000); - for (i = 5000; i < 5500; i++) { - multimap_remove(me, &i, &value); - assert(!multimap_contains(me, &i)); - } - assert(multimap_size(me) == 500); - assert(!multimap_is_empty(me)); - multimap_clear(me); - assert(multimap_size(me) == 0); - assert(multimap_is_empty(me)); - /* Add a lot of items and clear. */ - for (i = 5000; i < 6000; i++) { - multimap_put(me, &i, &num); - assert(multimap_contains(me, &i)); - } - assert(multimap_size(me) == 1000); - multimap_clear(me); - p = 0xdeadbeef; - assert(!multimap_remove(me, &p, &value)); - assert(multimap_size(me) == 0); - assert(multimap_is_empty(me)); - me = multimap_destroy(me); - assert(!me); - /* Create odd shape graph. */ - me = multimap_init(sizeof(int), sizeof(int), compare_int, compare_int); - key = 10; - multimap_put(me, &key, &num); - key = 5; - multimap_put(me, &key, &num); - key = 15; - multimap_put(me, &key, &num); - key = 3; - multimap_put(me, &key, &num); - key = 8; - multimap_put(me, &key, &num); - key = 12; - multimap_put(me, &key, &num); - key = 18; - multimap_put(me, &key, &num); - key = 12; - multimap_remove(me, &key, &value); - key = 5; - multimap_remove(me, &key, &value); - key = 3; - multimap_remove(me, &key, &value); - key = 8; - multimap_remove(me, &key, &value); - multimap_clear(me); - /* Allocate many nodes. */ - value = 54; + assert(!multimap_destroy(me)); +} + +static void test_stress_remove(void) +{ + int i; + multimap me = multimap_init(sizeof(int), sizeof(int), compare_int, + compare_int); + assert(me); for (i = 8123; i < 12314; i += 3) { - multimap_put(me, &i, &value); + multimap_put(me, &i, &i); assert(multimap_contains(me, &i)); } for (i = 13000; i > 8000; i--) { - multimap_remove(me, &i, &value); + multimap_remove(me, &i, &i); assert(!multimap_contains(me, &i)); } + assert(!multimap_destroy(me)); +} + +static void test_unique_delete_one_child(multimap me) +{ + int arr1[] = {2, 1, -2}; + int arr2[] = {1, 2, -1}; + int arr3[] = {3, 2, 4, 1, -2}; + int arr4[] = {3, 1, 4, 2, -1}; + int arr5[] = {3, 1, 4, 2, -4}; + int arr6[] = {2, 1, 3, 4, -3}; + int sz1 = sizeof(arr1) / sizeof(arr1[0]); + int sz2 = sizeof(arr2) / sizeof(arr2[0]); + int sz3 = sizeof(arr3) / sizeof(arr3[0]); + int sz4 = sizeof(arr4) / sizeof(arr4[0]); + int sz5 = sizeof(arr5) / sizeof(arr5[0]); + int sz6 = sizeof(arr6) / sizeof(arr6[0]); + mutation_order(me, arr1, sz1); multimap_clear(me); - /* Create another odd shape graph. */ - key = 20; - multimap_put(me, &key, &num); - key = 10; - multimap_put(me, &key, &num); - key = 40; - multimap_put(me, &key, &num); - key = 5; - multimap_put(me, &key, &num); - key = 15; - multimap_put(me, &key, &num); - key = 30; - multimap_put(me, &key, &num); - key = 50; - multimap_put(me, &key, &num); - key = 25; - multimap_put(me, &key, &num); - key = 35; - multimap_put(me, &key, &num); - key = 36; - multimap_put(me, &key, &num); - key = 34; - multimap_put(me, &key, &num); - key = 33; - multimap_put(me, &key, &num); - key = 32; - multimap_put(me, &key, &num); - key = 30; - multimap_remove(me, &key, &value); - key = 32; - assert(multimap_contains(me, &key)); + mutation_order(me, arr2, sz2); multimap_clear(me); - /* One sided tree. */ - key = 10; - multimap_put(me, &key, &num); - key = 9; - multimap_put(me, &key, &num); - key = 8; - multimap_put(me, &key, &num); - key = 7; - multimap_put(me, &key, &num); - key = 8; - multimap_remove(me, &key, &value); - key = 7; - assert(multimap_contains(me, &key)); - multimap_destroy(me); - /* Replace two sided two children. */ - me = multimap_init(sizeof(int), sizeof(int), compare_int, compare_int); - key = 5; - multimap_put(me, &key, &num); - key = 1; - multimap_put(me, &key, &num); - key = 6; - multimap_put(me, &key, &num); - key = -1; - multimap_put(me, &key, &num); - key = 3; - multimap_put(me, &key, &num); - key = 7; - multimap_put(me, &key, &num); - key = -2; - multimap_put(me, &key, &num); - key = 0; - multimap_put(me, &key, &num); - key = 2; - multimap_put(me, &key, &num); - key = 4; - multimap_put(me, &key, &num); - key = 1; - multimap_remove_all(me, &key); - assert(!multimap_contains(me, &key)); + mutation_order(me, arr3, sz3); multimap_clear(me); - key = 5; - multimap_put(me, &key, &num); - key = 1; - multimap_put(me, &key, &num); - key = 6; - multimap_put(me, &key, &num); - key = -1; - multimap_put(me, &key, &num); - key = 3; - multimap_put(me, &key, &num); - key = 7; - multimap_put(me, &key, &num); - key = -2; - multimap_put(me, &key, &num); - key = 0; - multimap_put(me, &key, &num); - key = 4; - multimap_put(me, &key, &num); - key = 1; - multimap_remove_all(me, &key); - assert(!multimap_contains(me, &key)); - me = multimap_destroy(me); - assert(!me); - me = multimap_init(sizeof(int), sizeof(int), compare_int, compare_int); + mutation_order(me, arr4, sz4); + multimap_clear(me); + mutation_order(me, arr5, sz5); + multimap_clear(me); + mutation_order(me, arr6, sz6); +} + +static void test_unique_delete_two_children(multimap me) +{ + int arr1[] = {2, 1, 3, -2}; + int arr2[] = {4, 2, 5, 1, 3, -2}; + int arr3[] = {2, 1, 4, 3, 5, -4}; + int sz1 = sizeof(arr1) / sizeof(arr1[0]); + int sz2 = sizeof(arr2) / sizeof(arr2[0]); + int sz3 = sizeof(arr3) / sizeof(arr3[0]); + mutation_order(me, arr1, sz1); + multimap_clear(me); + mutation_order(me, arr2, sz2); + multimap_clear(me); + mutation_order(me, arr3, sz3); +} + +static void test_unique_deletion_patterns(void) +{ + multimap me = multimap_init(sizeof(int), sizeof(int), compare_int, + compare_int); + assert(me); + test_unique_delete_one_child(me); + multimap_clear(me); + test_unique_delete_two_children(me); + assert(!multimap_destroy(me)); +} + +static void test_override_value(void) +{ + int key = 5; + int value = 0xdeadbeef; + multimap me = multimap_init(sizeof(int), sizeof(int), compare_int, + compare_int); + assert(me); + multimap_get_start(me, &key); + assert(!multimap_get_next(&value, me)); + assert(value == 0xdeadbeef); + value = 17; + multimap_put(me, &key, &value); + value = 0xdeadbeef; + multimap_get_start(me, &key); + assert(multimap_get_next(&value, me)); + assert(value == 17); + value = 0xdeadbeef; + assert(!multimap_get_next(&value, me)); + assert(value == 0xdeadbeef); value = 97; - for (i = 4817; i > -2983; i -= 11) { - multimap_put(me, &i, &value); - assert(multimap_contains(me, &i)); - } - for (i = -432; i < 3849; i += 7) { - multimap_remove(me, &i, &value); - assert(!multimap_contains(me, &i)); - } - multimap_clear(me); - key = 5; - multimap_put(me, &key, &num); - key = 7; - multimap_put(me, &key, &num); - key = 5; - multimap_remove(me, &key, &value); - multimap_clear(me); - /* Two children edge case other side. */ - key = 8; - multimap_put(me, &key, &num); - key = 4; - multimap_put(me, &key, &num); - key = 12; - multimap_put(me, &key, &num); - key = 2; - multimap_put(me, &key, &num); - key = 6; - multimap_put(me, &key, &num); - key = 10; - multimap_put(me, &key, &num); - key = 16; - multimap_put(me, &key, &num); - key = 1; - multimap_put(me, &key, &num); - key = 3; - multimap_put(me, &key, &num); - key = 5; - multimap_put(me, &key, &num); - key = 7; - multimap_put(me, &key, &num); - key = 9; - multimap_put(me, &key, &num); - key = 11; - multimap_put(me, &key, &num); - key = 15; - multimap_put(me, &key, &num); - key = 17; - multimap_put(me, &key, &num); - key = 13; - multimap_put(me, &key, &num); - multimap_clear(me); + multimap_put(me, &key, &value); + value = 0xdeadbeef; + multimap_get_start(me, &key); + assert(multimap_get_next(&value, me)); + assert(value == 17); + assert(multimap_get_next(&value, me)); + assert(value == 97); + value = 0xdeadbeef; + assert(!multimap_get_next(&value, me)); + assert(value == 0xdeadbeef); + assert(multimap_size(me) == 2); + assert(!multimap_destroy(me)); +} + +static void test_multiple_operations(void) +{ + int key = 5; + int value = 17; + multimap me = multimap_init(sizeof(int), sizeof(int), compare_int, + compare_int); + assert(me); assert(multimap_count(me, &key) == 0); assert(!multimap_remove_all(me, &key)); - /* Edge case. */ - me = multimap_init(sizeof(int), sizeof(int), compare_int, compare_int); - value = 17; - key = 5; multimap_put(me, &key, &value); - key = 3; multimap_put(me, &key, &value); + multimap_put(me, &key, &key); + multimap_put(me, &key, &key); + multimap_put(me, &key, &key); + assert(multimap_size(me) == 5); key = 7; + multimap_put(me, &key, &key); + assert(multimap_size(me) == 6); + assert(multimap_count(me, &key) == 1); + key = 5; + assert(multimap_count(me, &key) == 5); + multimap_remove(me, &key, &key); + assert(multimap_count(me, &key) == 4); + multimap_remove_all(me, &key); + assert(multimap_size(me) == 1); + key = 7; + multimap_remove_all(me, &key); + assert(multimap_size(me) == 0); multimap_put(me, &key, &value); - key = 2; - multimap_put(me, &key, &value); - key = 6; - multimap_put(me, &key, &value); - key = 9; - multimap_put(me, &key, &value); - key = 3; + value = 23; multimap_remove(me, &key, &value); + assert(multimap_size(me) == 1); + assert(!multimap_destroy(me)); +} + +static void test_init_out_of_memory(void) +{ + fail_malloc = 1; + assert(!multimap_init(sizeof(int), sizeof(int), compare_int, compare_int)); +} + +static void test_put_root_out_of_memory(multimap me) +{ + int key = 2; + fail_malloc = 1; + assert(multimap_put(me, &key, &key) == -ENOMEM); + fail_malloc = 1; + delay_fail_malloc = 1; + assert(multimap_put(me, &key, &key) == -ENOMEM); + fail_malloc = 1; + delay_fail_malloc = 2; + assert(multimap_put(me, &key, &key) == -ENOMEM); + fail_malloc = 1; + delay_fail_malloc = 3; + assert(multimap_put(me, &key, &key) == -ENOMEM); +} + +static void test_put_on_left_out_of_memory(multimap me) +{ + int key = 1; + fail_malloc = 1; + assert(multimap_put(me, &key, &key) == -ENOMEM); + fail_malloc = 1; + delay_fail_malloc = 1; + assert(multimap_put(me, &key, &key) == -ENOMEM); + fail_malloc = 1; + delay_fail_malloc = 2; + assert(multimap_put(me, &key, &key) == -ENOMEM); + fail_malloc = 1; + delay_fail_malloc = 3; + assert(multimap_put(me, &key, &key) == -ENOMEM); +} + +static void test_put_on_right_out_of_memory(multimap me) +{ + int key = 3; + fail_malloc = 1; + assert(multimap_put(me, &key, &key) == -ENOMEM); + fail_malloc = 1; + delay_fail_malloc = 1; + assert(multimap_put(me, &key, &key) == -ENOMEM); + fail_malloc = 1; + delay_fail_malloc = 2; + assert(multimap_put(me, &key, &key) == -ENOMEM); + fail_malloc = 1; + delay_fail_malloc = 3; + assert(multimap_put(me, &key, &key) == -ENOMEM); +} + +static void test_put_out_of_memory(void) +{ + int key = 2; + multimap me = multimap_init(sizeof(int), sizeof(int), compare_int, + compare_int); + assert(me); + test_put_root_out_of_memory(me); + assert(multimap_put(me, &key, &key) == 0); + test_put_on_left_out_of_memory(me); + test_put_on_right_out_of_memory(me); + assert(!multimap_destroy(me)); +} + +void test_multimap(void) +{ + test_invalid_init(); + test_auto_balancing(); + test_put_already_existing(); + test_remove_nothing(); + test_contains(); + test_stress_add(); + test_stress_remove(); + test_unique_deletion_patterns(); + test_override_value(); + test_multiple_operations(); + test_init_out_of_memory(); + test_put_out_of_memory(); } diff --git a/tst/multiset.c b/tst/multiset.c index e1e4d53..9254010 100644 --- a/tst/multiset.c +++ b/tst/multiset.c @@ -1,6 +1,76 @@ #include "test.h" #include "../src/multiset.h" +/* + * Include this struct to verify the tree. + */ +struct internal_multiset { + size_t key_size; + int (*comparator)(const void *const one, const void *const two); + int size; + struct node *root; +}; + +/* + * Include this struct to verify the tree. + */ +struct node { + int count; + struct node *parent; + int balance; + void *key; + struct node *left; + struct node *right; +}; + +/* + * Verifies that the AVL tree rules are followed. The balance factor of an item + * must be the right height minus the left height. Also, the left key must be + * less than the right key. + */ +static int multiset_verify_recursive(struct node *const item) +{ + int left; + int right; + int max; + if (!item) { + return 0; + } + left = multiset_verify_recursive(item->left); + right = multiset_verify_recursive(item->right); + max = left > right ? left : right; + assert(right - left == item->balance); + if (item->left && item->right) { + const int left_val = *(int *) item->left->key; + const int right_val = *(int *) item->right->key; + assert(left_val < right_val); + } + if (item->left) { + assert(item->left->parent == item); + assert(item->left->parent->key == item->key); + } + if (item->right) { + assert(item->right->parent == item); + assert(item->right->parent->key == item->key); + } + return max + 1; +} + +static int multiset_compute_size(struct node *const item) +{ + if (!item) { + return 0; + } + return 1 + multiset_compute_size(item->left) + + multiset_compute_size(item->right); +} + +static void multiset_verify(multiset me) +{ + multiset_verify_recursive(me->root); + assert(multiset_compute_size(me->root) == multiset_size(me)); +} + static int compare_int(const void *const one, const void *const two) { const int a = *(int *) one; @@ -8,261 +78,309 @@ static int compare_int(const void *const one, const void *const two) return a - b; } -void test_multiset(void) +static void test_invalid_init(void) { - int val_arr[10] = {5, 9, 4, -5, 0, 6, 1, 5, 7, 2}; - int c[10] = {5, 9, 4, -5, 0, 6, 1, 5, 7, 2}; - multiset me; - int key; - int num; - int count; - int flip; - int p; - int i; - int j; assert(!multiset_init(0, compare_int)); assert(!multiset_init(sizeof(int), NULL)); - me = multiset_init(sizeof(int), compare_int); - assert(me); - assert(multiset_size(me) == 0); +} + +static void mutation_order(multiset me, const int *const arr, const int size) +{ + int i; + int actual_size = 0; assert(multiset_is_empty(me)); - key = 4; - multiset_put(me, &key); - assert(multiset_size(me) == 1); - multiset_put(me, &key); - assert(multiset_size(me) == 2); - assert(multiset_count(me, &key) == 2); - assert(!multiset_is_empty(me)); - assert(multiset_contains(me, &key)); - key = 7; - assert(!multiset_contains(me, &key)); - multiset_put(me, &key); - assert(multiset_size(me) == 3); - assert(multiset_contains(me, &key)); - multiset_remove(me, &key); - assert(multiset_size(me) == 2); - assert(!multiset_contains(me, &key)); - key = 4; - multiset_remove(me, &key); - assert(multiset_size(me) == 1); - multiset_remove(me, &key); - assert(multiset_size(me) == 0); - for (i = 0; i < 10; i++) { - multiset_put(me, &val_arr[i]); - assert(multiset_contains(me, &val_arr[i])); - } - assert(multiset_size(me) == 10); - for (i = 0; i < 10; i++) { - assert(multiset_contains(me, &val_arr[i])); - } - for (i = -100; i < 100; i++) { - int contains = 0; - for (j = 0; j < 10; j++) { - if (val_arr[j] == i) { - contains = 1; - } + for (i = 0; i < size; i++) { + int num = arr[i]; + if (num > 0) { + assert(multiset_put(me, &num) == 0); + actual_size++; + } else { + int actual_num = -1 * num; + assert(multiset_remove(me, &actual_num)); + actual_size--; } - assert(multiset_contains(me, &i) == contains); } - num = -3; - assert(!multiset_remove(me, &num)); - assert(multiset_size(me) == 10); - assert(!multiset_contains(me, &num)); - num = 6; - assert(multiset_remove(me, &num)); - assert(multiset_size(me) == 9); - assert(!multiset_contains(me, &num)); - num = 4; - assert(multiset_remove(me, &num)); - assert(multiset_size(me) == 8); - assert(!multiset_contains(me, &num)); - num = 7; - assert(multiset_remove(me, &num)); - assert(multiset_size(me) == 7); - assert(!multiset_contains(me, &num)); - num = 9; - assert(multiset_remove(me, &num)); - assert(multiset_size(me) == 6); - assert(!multiset_contains(me, &num)); - num = -5; - assert(multiset_remove(me, &num)); - assert(multiset_size(me) == 5); - assert(!multiset_contains(me, &num)); - num = 0; - assert(multiset_remove(me, &num)); - assert(multiset_size(me) == 4); - assert(!multiset_contains(me, &num)); - num = 1; - assert(multiset_remove(me, &num)); - assert(multiset_size(me) == 3); - assert(!multiset_contains(me, &num)); - num = 5; - assert(multiset_remove(me, &num)); - assert(multiset_size(me) == 2); - assert(multiset_contains(me, &num)); - num = 2; - assert(multiset_remove(me, &num)); - assert(multiset_size(me) == 1); - assert(!multiset_contains(me, &num)); - num = 5; - assert(multiset_remove(me, &num)); - assert(multiset_size(me) == 0); - assert(!multiset_contains(me, &num)); - /* Add a lot of items and remove individually. */ - for (i = 5000; i < 6000; i++) { - multiset_put(me, &i); + assert(multiset_size(me) == actual_size); + multiset_verify(me); +} + +/* + * Targets the (child->balance == 0) branch. + */ +static void test_rotate_left_balanced_child(multiset me) +{ + int i; + int arr[] = {2, 4, 1, 3, 5, -1}; + int size = sizeof(arr) / sizeof(arr[0]); + mutation_order(me, arr, size); + for (i = 2; i <= 5; i++) { assert(multiset_contains(me, &i)); } - assert(multiset_size(me) == 1000); - for (i = 5000; i < 6000; i++) { - multiset_remove(me, &i); - assert(!multiset_contains(me, &i)); - } - assert(multiset_size(me) == 0); - assert(multiset_is_empty(me)); - multiset_clear(me); - assert(multiset_size(me) == 0); - assert(multiset_is_empty(me)); - /* Add a lot of items and clear. */ - for (i = 5000; i < 6000; i++) { - multiset_put(me, &i); +} + +/* + * Targets the else branch. + */ +static void test_rotate_left_unbalanced_child(multiset me) +{ + int i; + int arr[] = {1, 2, 3}; + int size = sizeof(arr) / sizeof(arr[0]); + mutation_order(me, arr, size); + for (i = 1; i <= 3; i++) { assert(multiset_contains(me, &i)); } - assert(multiset_size(me) == 1000); - multiset_clear(me); - key = 0xdeadbeef; - assert(!multiset_remove(me, &key)); - assert(multiset_size(me) == 0); - assert(multiset_is_empty(me)); - key = 5; - multiset_put(me, &key); - assert(multiset_size(me) == 1); - key = 7; - for (i = 0; i < 10; i++) { - multiset_put(me, &key); - } - assert(multiset_size(me) == 11); - multiset_remove_all(me, &key); - assert(multiset_size(me) == 1); - me = multiset_destroy(me); - assert(!me); - me = multiset_init(sizeof(int), compare_int); +} + +/* + * Targets (parent->balance == 2 && child->balance >= 0) in the multiset_repair + * function. + */ +static void test_rotate_left(void) +{ + multiset me = multiset_init(sizeof(int), compare_int); assert(me); - /* left-left */ - key = 5; - multiset_put(me, &key); - key = 3; - multiset_put(me, &key); - key = 1; - multiset_put(me, &key); - key = 0xdeadbeef; - multiset_contains(me, &key); + test_rotate_left_balanced_child(me); multiset_clear(me); - /* right-right */ - key = 1; - multiset_put(me, &key); - key = 3; - multiset_put(me, &key); - key = 5; - multiset_put(me, &key); - key = 0xdeadbeef; - multiset_contains(me, &key); + test_rotate_left_unbalanced_child(me); + assert(!multiset_destroy(me)); +} + +/* + * Targets the (child->balance == 0) branch. + */ +static void test_rotate_right_balanced_child(multiset me) +{ + int i; + int arr[] = {4, 2, 5, 1, 3, -5}; + int size = sizeof(arr) / sizeof(arr[0]); + mutation_order(me, arr, size); + for (i = 1; i <= 4; i++) { + assert(multiset_contains(me, &i)); + } +} + +/* + * Targets the else branch. + */ +static void test_rotate_right_unbalanced_child(multiset me) +{ + int i; + int arr[] = {3, 2, 1}; + int size = sizeof(arr) / sizeof(arr[0]); + mutation_order(me, arr, size); + for (i = 1; i <= 3; i++) { + assert(multiset_contains(me, &i)); + } +} + +/* + * Targets (parent->balance == -2 && child->balance <= 0) in the multiset_repair + * function. + */ +static void test_rotate_right(void) +{ + multiset me = multiset_init(sizeof(int), compare_int); + assert(me); + test_rotate_right_balanced_child(me); multiset_clear(me); - /* left-right */ - key = 5; - multiset_put(me, &key); - key = 1; - multiset_put(me, &key); - key = 3; - multiset_put(me, &key); - key = 0xdeadbeef; - multiset_contains(me, &key); + test_rotate_right_unbalanced_child(me); + assert(!multiset_destroy(me)); +} + +/* + * Targets the (grand_child->balance == 1) branch. + */ +static void test_rotate_left_right_positively_balanced_grand_child(multiset me) +{ + int i; + int arr[] = {5, 2, 6, 1, 3, 4}; + int size = sizeof(arr) / sizeof(arr[0]); + mutation_order(me, arr, size); + for (i = 1; i <= 6; i++) { + assert(multiset_contains(me, &i)); + } +} + +/* + * Targets the (grand_child->balance == 0) branch. + */ +static void test_rotate_left_right_neutral_balanced_grand_child(multiset me) +{ + int i; + int arr[] = {3, 1, 2}; + int size = sizeof(arr) / sizeof(arr[0]); + mutation_order(me, arr, size); + for (i = 1; i <= 3; i++) { + assert(multiset_contains(me, &i)); + } +} + +/* + * Targets the else branch. + */ +static void test_rotate_left_right_negatively_balanced_grand_child(multiset me) +{ + int i; + int arr[] = {5, 2, 6, 1, 4, 3}; + int size = sizeof(arr) / sizeof(arr[0]); + mutation_order(me, arr, size); + for (i = 1; i <= 6; i++) { + assert(multiset_contains(me, &i)); + } +} + +/* + * Targets (parent->balance == -2 && child->balance == 1) in the multiset_repair + * function. + */ +static void test_rotate_left_right(void) +{ + multiset me = multiset_init(sizeof(int), compare_int); + assert(me); + test_rotate_left_right_positively_balanced_grand_child(me); multiset_clear(me); - /* right-left */ - key = 1; - multiset_put(me, &key); - key = 5; - multiset_put(me, &key); - key = 3; - multiset_put(me, &key); - key = 0xdeadbeef; - multiset_contains(me, &key); + test_rotate_left_right_neutral_balanced_grand_child(me); multiset_clear(me); - /* Two children edge case. */ - key = 8; + test_rotate_left_right_negatively_balanced_grand_child(me); + assert(!multiset_destroy(me)); +} + +/* + * Targets the (grand_child->balance == 1) branch. + */ +static void test_rotate_right_left_positively_balanced_grand_child(multiset me) +{ + int i; + int arr[] = {2, 1, 5, 3, 6, 4}; + int size = sizeof(arr) / sizeof(arr[0]); + mutation_order(me, arr, size); + for (i = 1; i <= 6; i++) { + assert(multiset_contains(me, &i)); + } +} + +/* + * Targets the (grand_child->balance == 0) branch. + */ +static void test_rotate_right_left_neutral_balanced_grand_child(multiset me) +{ + int i; + int arr[] = {1, 3, 2}; + int size = sizeof(arr) / sizeof(arr[0]); + mutation_order(me, arr, size); + for (i = 1; i <= 3; i++) { + assert(multiset_contains(me, &i)); + } +} + +/* + * Targets the else branch. + */ +static void test_rotate_right_left_negatively_balanced_grand_child(multiset me) +{ + int i; + int arr[] = {2, 1, 5, 4, 6, 3}; + int size = sizeof(arr) / sizeof(arr[0]); + mutation_order(me, arr, size); + for (i = 1; i <= 6; i++) { + assert(multiset_contains(me, &i)); + } +} + +/* + * Targets (parent->balance == 2 && child->balance == -1) in the multiset_repair + * function. + */ +static void test_rotate_right_left(void) +{ + multiset me = multiset_init(sizeof(int), compare_int); + assert(me); + test_rotate_right_left_positively_balanced_grand_child(me); + multiset_clear(me); + test_rotate_right_left_neutral_balanced_grand_child(me); + multiset_clear(me); + test_rotate_right_left_negatively_balanced_grand_child(me); + assert(!multiset_destroy(me)); +} + +/* + * Targets the multiset_repair function. + */ +static void test_auto_balancing(void) +{ + test_rotate_left(); + test_rotate_right(); + test_rotate_left_right(); + test_rotate_right_left(); +} + +static void test_put_already_existing(void) +{ + int key = 5; + multiset me = multiset_init(sizeof(int), compare_int); + assert(me); + assert(multiset_size(me) == 0); multiset_put(me, &key); - key = 5; - multiset_put(me, &key); - key = 11; - multiset_put(me, &key); - key = 2; - multiset_put(me, &key); - key = 6; - multiset_put(me, &key); - key = 10; - multiset_put(me, &key); - key = 15; - multiset_put(me, &key); - key = 1; + assert(multiset_size(me) == 1); multiset_put(me, &key); + assert(multiset_size(me) == 2); + assert(!multiset_destroy(me)); +} + +static void test_remove_nothing(void) +{ + int key; + multiset me = multiset_init(sizeof(int), compare_int); + assert(me); key = 3; multiset_put(me, &key); - key = 4; - multiset_put(me, &key); + key = 5; + assert(!multiset_remove(me, &key)); + assert(!multiset_destroy(me)); +} + +static void test_contains(void) +{ + int key; + multiset me = multiset_init(sizeof(int), compare_int); + assert(me); key = 7; - multiset_put(me, &key); - key = 9; - multiset_put(me, &key); - key = 12; - multiset_put(me, &key); - key = 13; - multiset_put(me, &key); - key = 16; - multiset_put(me, &key); - key = 14; - multiset_put(me, &key); - multiset_clear(me); - /* Two children edge case. */ - key = 8; - multiset_put(me, &key); - key = 4; - multiset_put(me, &key); - key = 12; - multiset_put(me, &key); - key = 2; - multiset_put(me, &key); - key = 6; - multiset_put(me, &key); - key = 10; - multiset_put(me, &key); - key = 15; + assert(!multiset_contains(me, &key)); + key = 3; multiset_put(me, &key); key = 1; multiset_put(me, &key); - key = 3; - multiset_put(me, &key); key = 5; multiset_put(me, &key); - key = 7; - multiset_put(me, &key); - key = 9; - multiset_put(me, &key); - key = 11; - multiset_put(me, &key); - key = 13; - multiset_put(me, &key); - key = 16; - multiset_put(me, &key); - key = 14; - multiset_put(me, &key); - multiset_clear(me); - /* Add a lot of items. */ - count = 0; - flip = 0; + key = 0; + assert(!multiset_contains(me, &key)); + key = 1; + assert(multiset_contains(me, &key)); + key = 2; + assert(!multiset_contains(me, &key)); + key = 3; + assert(multiset_contains(me, &key)); + key = 4; + assert(!multiset_contains(me, &key)); + key = 5; + assert(multiset_contains(me, &key)); + key = 6; + assert(!multiset_contains(me, &key)); + assert(!multiset_destroy(me)); +} + +static void test_stress_add(void) +{ + int count = 0; + int flip = 0; + int i; + multiset me = multiset_init(sizeof(int), compare_int); + assert(me); for (i = 1234; i < 82400; i++) { - key = i % 765; - multiset_put(me, &key); - assert(multiset_contains(me, &key)); + int num = i % 765; + multiset_put(me, &num); + assert(multiset_contains(me, &num)); count++; if (i == 1857 && !flip) { i *= -1; @@ -270,135 +388,14 @@ void test_multiset(void) } } assert(count == multiset_size(me)); - multiset_contains(me, &key); - multiset_destroy(me); - me = multiset_init(sizeof(int), compare_int); - assert(multiset_size(me) == 0); - assert(multiset_is_empty(me)); - key = 4; - multiset_put(me, &key); - assert(multiset_size(me) == 1); - multiset_put(me, &key); - assert(multiset_size(me) == 2); - assert(!multiset_is_empty(me)); - assert(multiset_contains(me, &key)); - key = 7; - assert(!multiset_contains(me, &key)); - multiset_put(me, &key); - assert(multiset_size(me) == 3); - assert(multiset_contains(me, &key)); - for (i = 0; i < 10; i++) { - multiset_put(me, &c[i]); - assert(multiset_contains(me, &c[i])); - } - assert(multiset_size(me) == 13); - for (i = 0; i < 10; i++) { - assert(multiset_contains(me, &c[i])); - } - for (i = -100; i < 100; i++) { - int contains = 0; - for (j = 0; j < 10; j++) { - if (c[j] == i) { - contains = 1; - } - } - assert(multiset_contains(me, &i) == contains); - } - num = -3; - assert(!multiset_remove(me, &num)); - assert(multiset_size(me) == 13); - assert(!multiset_contains(me, &num)); - num = 6; - assert(multiset_remove(me, &num)); - assert(multiset_size(me) == 12); - assert(!multiset_contains(me, &num)); - num = 4; - assert(multiset_remove(me, &num)); - assert(multiset_size(me) == 11); - assert(multiset_contains(me, &num)); - num = 7; - assert(multiset_remove(me, &num)); - assert(multiset_size(me) == 10); - assert(multiset_contains(me, &num)); - num = 9; - assert(multiset_remove(me, &num)); - assert(multiset_size(me) == 9); - assert(!multiset_contains(me, &num)); - num = -5; - assert(multiset_remove(me, &num)); - assert(multiset_size(me) == 8); - assert(!multiset_contains(me, &num)); - num = 0; - assert(multiset_remove(me, &num)); - assert(multiset_size(me) == 7); - assert(!multiset_contains(me, &num)); - num = 1; - assert(multiset_remove(me, &num)); - assert(multiset_size(me) == 6); - assert(!multiset_contains(me, &num)); - num = 5; - assert(multiset_remove(me, &num)); - assert(multiset_size(me) == 5); - assert(multiset_contains(me, &num)); - num = 2; - assert(multiset_remove(me, &num)); - assert(multiset_size(me) == 4); - assert(!multiset_contains(me, &num)); - multiset_clear(me); - /* Add a lot of items and remove individually. */ - for (i = 5000; i < 6000; i++) { - multiset_put(me, &i); - assert(multiset_contains(me, &i)); - } - assert(multiset_size(me) == 1000); - for (i = 5000; i < 5500; i++) { - multiset_remove(me, &i); - assert(!multiset_contains(me, &i)); - } - assert(multiset_size(me) == 500); - assert(!multiset_is_empty(me)); - multiset_clear(me); - assert(multiset_size(me) == 0); - assert(multiset_is_empty(me)); - /* Add a lot of items and clear. */ - for (i = 5000; i < 6000; i++) { - multiset_put(me, &i); - assert(multiset_contains(me, &i)); - } - assert(multiset_size(me) == 1000); - multiset_clear(me); - p = 0xdeadbeef; - assert(!multiset_remove(me, &p)); - assert(multiset_size(me) == 0); - assert(multiset_is_empty(me)); - me = multiset_destroy(me); - assert(!me); - /* Create odd shape graph. */ - me = multiset_init(sizeof(int), compare_int); - key = 10; - multiset_put(me, &key); - key = 5; - multiset_put(me, &key); - key = 15; - multiset_put(me, &key); - key = 3; - multiset_put(me, &key); - key = 8; - multiset_put(me, &key); - key = 12; - multiset_put(me, &key); - key = 18; - multiset_put(me, &key); - key = 12; - multiset_remove(me, &key); - key = 5; - multiset_remove(me, &key); - key = 3; - multiset_remove(me, &key); - key = 8; - multiset_remove(me, &key); - multiset_clear(me); - /* Allocate many nodes. */ + assert(!multiset_destroy(me)); +} + +static void test_stress_remove(void) +{ + int i; + multiset me = multiset_init(sizeof(int), compare_int); + assert(me); for (i = 8123; i < 12314; i += 3) { multiset_put(me, &i); assert(multiset_contains(me, &i)); @@ -407,153 +404,144 @@ void test_multiset(void) multiset_remove(me, &i); assert(!multiset_contains(me, &i)); } + assert(!multiset_destroy(me)); +} + +static void test_unique_delete_one_child(multiset me) +{ + int arr1[] = {2, 1, -2}; + int arr2[] = {1, 2, -1}; + int arr3[] = {3, 2, 4, 1, -2}; + int arr4[] = {3, 1, 4, 2, -1}; + int arr5[] = {3, 1, 4, 2, -4}; + int arr6[] = {2, 1, 3, 4, -3}; + int sz1 = sizeof(arr1) / sizeof(arr1[0]); + int sz2 = sizeof(arr2) / sizeof(arr2[0]); + int sz3 = sizeof(arr3) / sizeof(arr3[0]); + int sz4 = sizeof(arr4) / sizeof(arr4[0]); + int sz5 = sizeof(arr5) / sizeof(arr5[0]); + int sz6 = sizeof(arr6) / sizeof(arr6[0]); + mutation_order(me, arr1, sz1); multiset_clear(me); - /* Create another odd shape graph. */ - key = 20; - multiset_put(me, &key); - key = 10; - multiset_put(me, &key); - key = 40; - multiset_put(me, &key); - key = 5; - multiset_put(me, &key); - key = 15; - multiset_put(me, &key); - key = 30; - multiset_put(me, &key); - key = 50; - multiset_put(me, &key); - key = 25; - multiset_put(me, &key); - key = 35; - multiset_put(me, &key); - key = 36; - multiset_put(me, &key); - key = 34; - multiset_put(me, &key); - key = 33; - multiset_put(me, &key); - key = 32; - multiset_put(me, &key); - key = 30; - multiset_remove(me, &key); - key = 32; - assert(multiset_contains(me, &key)); + mutation_order(me, arr2, sz2); multiset_clear(me); - /* One sided tree. */ - key = 10; - multiset_put(me, &key); - key = 9; - multiset_put(me, &key); - key = 8; - multiset_put(me, &key); - key = 7; - multiset_put(me, &key); - key = 8; - multiset_remove(me, &key); - key = 7; - assert(multiset_contains(me, &key)); - multiset_destroy(me); - /* Replace two sided two children. */ - me = multiset_init(sizeof(int), compare_int); - key = 5; - multiset_put(me, &key); - key = 1; - multiset_put(me, &key); - key = 6; - multiset_put(me, &key); - key = -1; - multiset_put(me, &key); - key = 3; - multiset_put(me, &key); - key = 7; - multiset_put(me, &key); - key = -2; - multiset_put(me, &key); - key = 0; - multiset_put(me, &key); - key = 2; - multiset_put(me, &key); - key = 4; - multiset_put(me, &key); - key = 1; - multiset_remove(me, &key); - assert(!multiset_contains(me, &key)); + mutation_order(me, arr3, sz3); multiset_clear(me); - key = 5; - multiset_put(me, &key); - key = 1; - multiset_put(me, &key); - key = 6; - multiset_put(me, &key); - key = -1; - multiset_put(me, &key); - key = 3; - multiset_put(me, &key); - key = 7; - multiset_put(me, &key); - key = -2; - multiset_put(me, &key); - key = 0; - multiset_put(me, &key); - key = 4; - multiset_put(me, &key); - key = 1; - multiset_remove(me, &key); - assert(!multiset_contains(me, &key)); - me = multiset_destroy(me); - assert(!me); - me = multiset_init(sizeof(int), compare_int); - for (i = 4817; i > -2983; i -= 11) { - multiset_put(me, &i); - assert(multiset_contains(me, &i)); - } - for (i = -432; i < 3849; i += 7) { - multiset_remove(me, &i); - assert(!multiset_contains(me, &i)); - } + mutation_order(me, arr4, sz4); multiset_clear(me); - key = 5; - multiset_put(me, &key); - key = 7; - multiset_put(me, &key); - key = 5; - multiset_remove(me, &key); + mutation_order(me, arr5, sz5); multiset_clear(me); - /* Two children edge case other side. */ - key = 8; - multiset_put(me, &key); - key = 4; - multiset_put(me, &key); - key = 12; - multiset_put(me, &key); - key = 2; - multiset_put(me, &key); - key = 6; - multiset_put(me, &key); - key = 10; - multiset_put(me, &key); - key = 16; - multiset_put(me, &key); - key = 1; - multiset_put(me, &key); - key = 3; - multiset_put(me, &key); - key = 5; - multiset_put(me, &key); - key = 7; - multiset_put(me, &key); - key = 9; - multiset_put(me, &key); - key = 11; - multiset_put(me, &key); - key = 15; - multiset_put(me, &key); - key = 17; - multiset_put(me, &key); - key = 13; - multiset_put(me, &key); + mutation_order(me, arr6, sz6); +} + +static void test_unique_delete_two_children(multiset me) +{ + int arr1[] = {2, 1, 3, -2}; + int arr2[] = {4, 2, 5, 1, 3, -2}; + int arr3[] = {2, 1, 4, 3, 5, -4}; + int sz1 = sizeof(arr1) / sizeof(arr1[0]); + int sz2 = sizeof(arr2) / sizeof(arr2[0]); + int sz3 = sizeof(arr3) / sizeof(arr3[0]); + mutation_order(me, arr1, sz1); multiset_clear(me); + mutation_order(me, arr2, sz2); + multiset_clear(me); + mutation_order(me, arr3, sz3); +} + +static void test_unique_deletion_patterns(void) +{ + multiset me = multiset_init(sizeof(int), compare_int); + assert(me); + test_unique_delete_one_child(me); + multiset_clear(me); + test_unique_delete_two_children(me); + assert(!multiset_destroy(me)); +} + +static void test_multiple_operations(void) +{ + int key = 5; + multiset me = multiset_init(sizeof(int), compare_int); + assert(me); assert(multiset_count(me, &key) == 0); assert(!multiset_remove_all(me, &key)); + multiset_put(me, &key); + multiset_put(me, &key); + assert(multiset_size(me) == 2); + key = 7; + multiset_put(me, &key); + assert(multiset_size(me) == 3); + assert(multiset_count(me, &key) == 1); + key = 5; + assert(multiset_count(me, &key) == 2); + multiset_remove_all(me, &key); + assert(multiset_size(me) == 1); + key = 7; + multiset_remove_all(me, &key); + assert(multiset_size(me) == 0); + assert(!multiset_destroy(me)); +} + +static void test_init_out_of_memory(void) +{ + fail_malloc = 1; + assert(!multiset_init(sizeof(int), compare_int)); +} + +static void test_put_root_out_of_memory(multiset me) +{ + int key = 2; + fail_malloc = 1; + assert(multiset_put(me, &key) == -ENOMEM); + fail_malloc = 1; + delay_fail_malloc = 1; + assert(multiset_put(me, &key) == -ENOMEM); +} + +static void test_put_on_left_out_of_memory(multiset me) +{ + int key = 1; + fail_malloc = 1; + assert(multiset_put(me, &key) == -ENOMEM); + fail_malloc = 1; + delay_fail_malloc = 1; + assert(multiset_put(me, &key) == -ENOMEM); +} + +static void test_put_on_right_out_of_memory(multiset me) +{ + int key = 3; + fail_malloc = 1; + assert(multiset_put(me, &key) == -ENOMEM); + fail_malloc = 1; + delay_fail_malloc = 1; + assert(multiset_put(me, &key) == -ENOMEM); +} + +static void test_put_out_of_memory(void) +{ + int key = 2; + multiset me = multiset_init(sizeof(int), compare_int); + assert(me); + test_put_root_out_of_memory(me); + assert(multiset_put(me, &key) == 0); + test_put_on_left_out_of_memory(me); + test_put_on_right_out_of_memory(me); + assert(!multiset_destroy(me)); +} + +void test_multiset(void) +{ + test_invalid_init(); + test_auto_balancing(); + test_put_already_existing(); + test_remove_nothing(); + test_contains(); + test_stress_add(); + test_stress_remove(); + test_unique_deletion_patterns(); + test_multiple_operations(); + test_init_out_of_memory(); + test_put_out_of_memory(); } diff --git a/tst/priority_queue.c b/tst/priority_queue.c index c90bf7c..346412c 100644 --- a/tst/priority_queue.c +++ b/tst/priority_queue.c @@ -42,29 +42,32 @@ static int compare_int(const void *const one, const void *const two) return a - b; } -int stub_priority_queue_push(priority_queue me, void *const data) +static int stub_priority_queue_push(priority_queue me, void *const data) { const int ret = priority_queue_push(me, data); priority_queue_verify(me); return ret; } -int stub_priority_queue_pop(void *const data, priority_queue me) +static int stub_priority_queue_pop(void *const data, priority_queue me) { const int ret = priority_queue_pop(data, me); priority_queue_verify(me); return ret; } -void test_priority_queue(void) +static void test_invalid_init(void) +{ + assert(!priority_queue_init(0, compare_int)); + assert(!priority_queue_init(sizeof(int), NULL)); +} + +static void test_basic(void) { - priority_queue me; int item; int latest; int i; - assert(!priority_queue_init(0, compare_int)); - assert(!priority_queue_init(sizeof(int), NULL)); - me = priority_queue_init(sizeof(int), compare_int); + priority_queue me = priority_queue_init(sizeof(int), compare_int); assert(me); assert(priority_queue_size(me) == 0); assert(priority_queue_is_empty(me)); @@ -128,6 +131,57 @@ void test_priority_queue(void) assert(!priority_queue_front(&item, me)); assert(item == 0xdeadbeef); assert(priority_queue_is_empty(me)); - me = priority_queue_destroy(me); - assert(!me); + assert(!priority_queue_destroy(me)); +} + +static void test_init_out_of_memory(void) +{ + fail_malloc = 1; + assert(!priority_queue_init(sizeof(int), compare_int)); + fail_malloc = 1; + delay_fail_malloc = 1; + assert(!priority_queue_init(sizeof(int), compare_int)); + fail_malloc = 1; + delay_fail_malloc = 2; + assert(!priority_queue_init(sizeof(int), compare_int)); +} + +static void test_push_out_of_memory(void) +{ + int i; + int get = 0xdeadbeef; + priority_queue me = priority_queue_init(sizeof(int), compare_int); + for (i = 0; i < 16; i++) { + assert(priority_queue_push(me, &i) == 0); + } + assert(priority_queue_size(me) == 16); + fail_malloc = 1; + assert(priority_queue_push(me, &get) == -ENOMEM); + for (i = 0; i < 16; i++) { + get = 0xdeadbeef; + assert(priority_queue_pop(&get, me)); + assert(get == 15 - i); + } + assert(priority_queue_size(me) == 0); + priority_queue_clear(me); + for (i = 0; i < 11; i++) { + assert(priority_queue_push(me, &i) == 0); + } + assert(priority_queue_size(me) == 11); + fail_realloc = 1; + assert(priority_queue_push(me, &get) == -ENOMEM); + for (i = 0; i < 11; i++) { + get = 0xdeadbeef; + assert(priority_queue_pop(&get, me)); + assert(get == 10 - i); + } + assert(!priority_queue_destroy(me)); +} + +void test_priority_queue(void) +{ + test_invalid_init(); + test_basic(); + test_init_out_of_memory(); + test_push_out_of_memory(); } diff --git a/tst/queue.c b/tst/queue.c index aa5f0a9..7171abe 100644 --- a/tst/queue.c +++ b/tst/queue.c @@ -1,19 +1,17 @@ #include "test.h" #include "../src/queue.h" -void test_queue(void) +static void test_invalid_init(void) +{ + assert(!queue_init(0)); +} + +static void test_linear_operations(queue me) { int val[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; - int get_arr[10] = {0}; - queue me; - int get; int stuff; - int old_size; - int pop_count; + int get; int i; - assert(!queue_init(0)); - me = queue_init(sizeof(int)); - assert(me); assert(queue_size(me) == 0); assert(queue_is_empty(me)); for (i = 0; i < 10; i++) { @@ -27,6 +25,13 @@ void test_queue(void) } assert(queue_size(me) == 10); assert(!queue_is_empty(me)); +} + +static void test_array_copy(queue me) +{ + int get_arr[10] = {0}; + int get; + int i; queue_copy_to_array(get_arr, me); for (i = 0; i < 10; i++) { assert(get_arr[i] == i + 1); @@ -36,6 +41,11 @@ void test_queue(void) assert(queue_pop(&get, me)); assert(get == i + 1); } +} + +static void test_array_trim(queue me) +{ + int get; queue_trim(me); assert(queue_size(me) == 1); queue_clear(me); @@ -44,9 +54,25 @@ void test_queue(void) assert(!queue_pop(&get, me)); assert(!queue_front(&get, me)); assert(!queue_back(&get, me)); - me = queue_destroy(me); - assert(!me); - me = queue_init(sizeof(int)); +} + +static void test_basic(void) +{ + queue me = queue_init(sizeof(int)); + assert(me); + test_linear_operations(me); + test_array_copy(me); + test_array_trim(me); + assert(!queue_destroy(me)); +} + +static void test_large_alloc(void) +{ + int old_size; + int pop_count; + int get; + int i; + queue me = queue_init(sizeof(int)); assert(me); for (i = 123; i < 123456; i++) { queue_push(me, &i); @@ -58,12 +84,41 @@ void test_queue(void) pop_count++; } assert(pop_count == old_size); - queue_destroy(me); - /* Testing automatic trim. */ - me = queue_init(sizeof(int)); + assert(!queue_destroy(me)); +} + +static void test_automated_trim(void) +{ + queue me = queue_init(sizeof(int)); + int get; + int i; for (i = 0; i < 100; i++) { queue_push(me, &i); queue_pop(&get, me); } - queue_destroy(me); + assert(!queue_destroy(me)); +} + +static void test_init_out_of_memory(void) +{ + fail_malloc = 1; + assert(!queue_init(sizeof(int))); + fail_malloc = 1; + delay_fail_malloc = 1; + assert(!queue_init(sizeof(int))); + fail_malloc = 1; + delay_fail_malloc = 2; + assert(!queue_init(sizeof(int))); + fail_malloc = 1; + delay_fail_malloc = 3; + assert(!queue_init(sizeof(int))); +} + +void test_queue(void) +{ + test_invalid_init(); + test_basic(); + test_large_alloc(); + test_automated_trim(); + test_init_out_of_memory(); } diff --git a/tst/set.c b/tst/set.c index c1552bb..21fc568 100644 --- a/tst/set.c +++ b/tst/set.c @@ -2,7 +2,7 @@ #include "../src/set.h" /* - * Include this struct for the stubs. + * Include this struct to verify the tree. */ struct internal_set { size_t key_size; @@ -11,6 +11,64 @@ struct internal_set { struct node *root; }; +/* + * Include this struct to verify the tree. + */ +struct node { + struct node *parent; + int balance; + void *key; + struct node *left; + struct node *right; +}; + +/* + * Verifies that the AVL tree rules are followed. The balance factor of an item + * must be the right height minus the left height. Also, the left key must be + * less than the right key. + */ +static int set_verify_recursive(struct node *const item) +{ + int left; + int right; + int max; + if (!item) { + return 0; + } + left = set_verify_recursive(item->left); + right = set_verify_recursive(item->right); + max = left > right ? left : right; + assert(right - left == item->balance); + if (item->left && item->right) { + const int left_val = *(int *) item->left->key; + const int right_val = *(int *) item->right->key; + assert(left_val < right_val); + } + if (item->left) { + assert(item->left->parent == item); + assert(item->left->parent->key == item->key); + } + if (item->right) { + assert(item->right->parent == item); + assert(item->right->parent->key == item->key); + } + return max + 1; +} + +static int set_compute_size(struct node *const item) +{ + if (!item) { + return 0; + } + return 1 + set_compute_size(item->left) + set_compute_size(item->right); +} + +static void set_verify(set me) +{ + set_verify_recursive(me->root); + assert(set_compute_size(me->root) == set_size(me)); +} + static int compare_int(const void *const one, const void *const two) { const int a = *(int *) one; @@ -18,141 +76,312 @@ static int compare_int(const void *const one, const void *const two) return a - b; } -void test_set(void) +static void test_invalid_init(void) { - int c[10] = {5, 9, 4, -5, 0, 6, 1, 5, 7, 2}; - set me; - int key; - int count; - int flip; - int i; - int j; - int num; - int p; assert(!set_init(0, compare_int)); assert(!set_init(sizeof(int), NULL)); - me = set_init(sizeof(int), compare_int); +} + +static void mutation_order(set me, const int *const arr, const int size) +{ + int i; + int actual_size = 0; + assert(set_is_empty(me)); + for (i = 0; i < size; i++) { + int num = arr[i]; + if (num > 0) { + assert(set_put(me, &num) == 0); + actual_size++; + } else { + int actual_num = -1 * num; + assert(set_remove(me, &actual_num)); + actual_size--; + } + } + assert(set_size(me) == actual_size); + set_verify(me); +} + +/* + * Targets the (child->balance == 0) branch. + */ +static void test_rotate_left_balanced_child(set me) +{ + int i; + int arr[] = {2, 4, 1, 3, 5, -1}; + int size = sizeof(arr) / sizeof(arr[0]); + mutation_order(me, arr, size); + for (i = 2; i <= 5; i++) { + assert(set_contains(me, &i)); + } +} + +/* + * Targets the else branch. + */ +static void test_rotate_left_unbalanced_child(set me) +{ + int i; + int arr[] = {1, 2, 3}; + int size = sizeof(arr) / sizeof(arr[0]); + mutation_order(me, arr, size); + for (i = 1; i <= 3; i++) { + assert(set_contains(me, &i)); + } +} + +/* + * Targets (parent->balance == 2 && child->balance >= 0) in the set_repair + * function. + */ +static void test_rotate_left(void) +{ + set me = set_init(sizeof(int), compare_int); assert(me); - /* left-left */ - key = 5; - set_put(me, &key); - key = 3; - set_put(me, &key); - key = 1; - set_put(me, &key); - key = 0xdeadbeef; - set_contains(me, &key); + test_rotate_left_balanced_child(me); set_clear(me); - /* right-right */ - key = 1; - set_put(me, &key); - key = 3; - set_put(me, &key); - key = 5; - set_put(me, &key); - key = 0xdeadbeef; - set_contains(me, &key); + test_rotate_left_unbalanced_child(me); + assert(!set_destroy(me)); +} + +/* + * Targets the (child->balance == 0) branch. + */ +static void test_rotate_right_balanced_child(set me) +{ + int i; + int arr[] = {4, 2, 5, 1, 3, -5}; + int size = sizeof(arr) / sizeof(arr[0]); + mutation_order(me, arr, size); + for (i = 1; i <= 4; i++) { + assert(set_contains(me, &i)); + } +} + +/* + * Targets the else branch. + */ +static void test_rotate_right_unbalanced_child(set me) +{ + int i; + int arr[] = {3, 2, 1}; + int size = sizeof(arr) / sizeof(arr[0]); + mutation_order(me, arr, size); + for (i = 1; i <= 3; i++) { + assert(set_contains(me, &i)); + } +} + +/* + * Targets (parent->balance == -2 && child->balance <= 0) in the set_repair + * function. + */ +static void test_rotate_right(void) +{ + set me = set_init(sizeof(int), compare_int); + assert(me); + test_rotate_right_balanced_child(me); set_clear(me); - /* left-right */ - key = 5; - set_put(me, &key); - key = 1; - set_put(me, &key); - key = 3; - set_put(me, &key); - key = 0xdeadbeef; - set_contains(me, &key); + test_rotate_right_unbalanced_child(me); + assert(!set_destroy(me)); +} + +/* + * Targets the (grand_child->balance == 1) branch. + */ +static void test_rotate_left_right_positively_balanced_grand_child(set me) +{ + int i; + int arr[] = {5, 2, 6, 1, 3, 4}; + int size = sizeof(arr) / sizeof(arr[0]); + mutation_order(me, arr, size); + for (i = 1; i <= 6; i++) { + assert(set_contains(me, &i)); + } +} + +/* + * Targets the (grand_child->balance == 0) branch. + */ +static void test_rotate_left_right_neutral_balanced_grand_child(set me) +{ + int i; + int arr[] = {3, 1, 2}; + int size = sizeof(arr) / sizeof(arr[0]); + mutation_order(me, arr, size); + for (i = 1; i <= 3; i++) { + assert(set_contains(me, &i)); + } +} + +/* + * Targets the else branch. + */ +static void test_rotate_left_right_negatively_balanced_grand_child(set me) +{ + int i; + int arr[] = {5, 2, 6, 1, 4, 3}; + int size = sizeof(arr) / sizeof(arr[0]); + mutation_order(me, arr, size); + for (i = 1; i <= 6; i++) { + assert(set_contains(me, &i)); + } +} + +/* + * Targets (parent->balance == -2 && child->balance == 1) in the set_repair + * function. + */ +static void test_rotate_left_right(void) +{ + set me = set_init(sizeof(int), compare_int); + assert(me); + test_rotate_left_right_positively_balanced_grand_child(me); set_clear(me); - /* right-left */ - key = 1; - set_put(me, &key); - key = 5; - set_put(me, &key); - key = 3; - set_put(me, &key); - key = 0xdeadbeef; - set_contains(me, &key); + test_rotate_left_right_neutral_balanced_grand_child(me); set_clear(me); - /* Two children edge case. */ - key = 8; + test_rotate_left_right_negatively_balanced_grand_child(me); + assert(!set_destroy(me)); +} + +/* + * Targets the (grand_child->balance == 1) branch. + */ +static void test_rotate_right_left_positively_balanced_grand_child(set me) +{ + int i; + int arr[] = {2, 1, 5, 3, 6, 4}; + int size = sizeof(arr) / sizeof(arr[0]); + mutation_order(me, arr, size); + for (i = 1; i <= 6; i++) { + assert(set_contains(me, &i)); + } +} + +/* + * Targets the (grand_child->balance == 0) branch. + */ +static void test_rotate_right_left_neutral_balanced_grand_child(set me) +{ + int i; + int arr[] = {1, 3, 2}; + int size = sizeof(arr) / sizeof(arr[0]); + mutation_order(me, arr, size); + for (i = 1; i <= 3; i++) { + assert(set_contains(me, &i)); + } +} + +/* + * Targets the else branch. + */ +static void test_rotate_right_left_negatively_balanced_grand_child(set me) +{ + int i; + int arr[] = {2, 1, 5, 4, 6, 3}; + int size = sizeof(arr) / sizeof(arr[0]); + mutation_order(me, arr, size); + for (i = 1; i <= 6; i++) { + assert(set_contains(me, &i)); + } +} + +/* + * Targets (parent->balance == 2 && child->balance == -1) in the set_repair + * function. + */ +static void test_rotate_right_left(void) +{ + set me = set_init(sizeof(int), compare_int); + assert(me); + test_rotate_right_left_positively_balanced_grand_child(me); + set_clear(me); + test_rotate_right_left_neutral_balanced_grand_child(me); + set_clear(me); + test_rotate_right_left_negatively_balanced_grand_child(me); + assert(!set_destroy(me)); +} + +/* + * Targets the set_repair function. + */ +static void test_auto_balancing(void) +{ + test_rotate_left(); + test_rotate_right(); + test_rotate_left_right(); + test_rotate_right_left(); +} + +static void test_put_already_existing(void) +{ + int key = 5; + set me = set_init(sizeof(int), compare_int); + assert(me); + assert(set_size(me) == 0); set_put(me, &key); - key = 5; - set_put(me, &key); - key = 11; - set_put(me, &key); - key = 2; - set_put(me, &key); - key = 6; - set_put(me, &key); - key = 10; - set_put(me, &key); - key = 15; - set_put(me, &key); - key = 1; + assert(set_size(me) == 1); set_put(me, &key); + assert(set_size(me) == 1); + assert(!set_destroy(me)); +} + +static void test_remove_nothing(void) +{ + int key; + set me = set_init(sizeof(int), compare_int); + assert(me); key = 3; set_put(me, &key); - key = 4; - set_put(me, &key); + key = 5; + assert(!set_remove(me, &key)); + assert(!set_destroy(me)); +} + +static void test_contains(void) +{ + int key; + set me = set_init(sizeof(int), compare_int); + assert(me); key = 7; - set_put(me, &key); - key = 9; - set_put(me, &key); - key = 12; - set_put(me, &key); - key = 13; - set_put(me, &key); - key = 16; - set_put(me, &key); - key = 14; - set_put(me, &key); - set_clear(me); - /* Two children edge case. */ - key = 8; - set_put(me, &key); - key = 4; - set_put(me, &key); - key = 12; - set_put(me, &key); - key = 2; - set_put(me, &key); - key = 6; - set_put(me, &key); - key = 10; - set_put(me, &key); - key = 15; + assert(!set_contains(me, &key)); + key = 3; set_put(me, &key); key = 1; set_put(me, &key); - key = 3; - set_put(me, &key); key = 5; set_put(me, &key); - key = 7; - set_put(me, &key); - key = 9; - set_put(me, &key); - key = 11; - set_put(me, &key); - key = 13; - set_put(me, &key); - key = 16; - set_put(me, &key); - key = 14; - set_put(me, &key); - set_clear(me); - /* Add a lot of items. */ - count = 0; - flip = 0; + key = 0; + assert(!set_contains(me, &key)); + key = 1; + assert(set_contains(me, &key)); + key = 2; + assert(!set_contains(me, &key)); + key = 3; + assert(set_contains(me, &key)); + key = 4; + assert(!set_contains(me, &key)); + key = 5; + assert(set_contains(me, &key)); + key = 6; + assert(!set_contains(me, &key)); + assert(!set_destroy(me)); +} + +static void test_stress_add(void) +{ + int count = 0; + int flip = 0; + int i; + set me = set_init(sizeof(int), compare_int); + assert(me); for (i = 1234; i < 82400; i++) { int is_already_present; - int is_now_present; - num = i % 765; + int num = i % 765; is_already_present = set_contains(me, &num); set_put(me, &num); - is_now_present = set_contains(me, &num); - assert(is_now_present); - if (!is_already_present && is_now_present) { + assert(set_contains(me, &num)); + if (!is_already_present) { count++; } if (i == 1857 && !flip) { @@ -161,134 +390,14 @@ void test_set(void) } } assert(count == set_size(me)); - set_contains(me, &key); - set_destroy(me); - me = set_init(sizeof(int), compare_int); - assert(set_size(me) == 0); - assert(set_is_empty(me)); - key = 4; - set_put(me, &key); - assert(set_size(me) == 1); - set_put(me, &key); - assert(set_size(me) == 1); - assert(!set_is_empty(me)); - assert(set_contains(me, &key)); - key = 7; - assert(!set_contains(me, &key)); - set_put(me, &key); - assert(set_size(me) == 2); - assert(set_contains(me, &key)); - for (i = 0; i < 10; i++) { - set_put(me, &c[i]); - assert(set_contains(me, &c[i])); - } - assert(set_size(me) == 9); - for (i = 0; i < 10; i++) { - assert(set_contains(me, &c[i])); - } - for (i = -100; i < 100; i++) { - int contains = 0; - for (j = 0; j < 10; j++) { - if (c[j] == i) { - contains = 1; - } - } - assert(set_contains(me, &i) == contains); - } - num = -3; - assert(!set_remove(me, &num)); - assert(set_size(me) == 9); - assert(!set_contains(me, &num)); - num = 6; - assert(set_remove(me, &num)); - assert(set_size(me) == 8); - assert(!set_contains(me, &num)); - num = 4; - assert(set_remove(me, &num)); - assert(set_size(me) == 7); - assert(!set_contains(me, &num)); - num = 7; - assert(set_remove(me, &num)); - assert(set_size(me) == 6); - assert(!set_contains(me, &num)); - num = 9; - assert(set_remove(me, &num)); - assert(set_size(me) == 5); - assert(!set_contains(me, &num)); - num = -5; - assert(set_remove(me, &num)); - assert(set_size(me) == 4); - assert(!set_contains(me, &num)); - num = 0; - assert(set_remove(me, &num)); - assert(set_size(me) == 3); - assert(!set_contains(me, &num)); - num = 1; - assert(set_remove(me, &num)); - assert(set_size(me) == 2); - assert(!set_contains(me, &num)); - num = 5; - assert(set_remove(me, &num)); - assert(set_size(me) == 1); - assert(!set_contains(me, &num)); - num = 2; - assert(set_remove(me, &num)); - assert(set_size(me) == 0); - assert(!set_contains(me, &num)); - /* Add a lot of items and remove individually. */ - for (i = 5000; i < 6000; i++) { - set_put(me, &i); - assert(set_contains(me, &i)); - } - assert(set_size(me) == 1000); - for (i = 5000; i < 5500; i++) { - set_remove(me, &i); - assert(!set_contains(me, &i)); - } - assert(set_size(me) == 500); - assert(!set_is_empty(me)); - set_clear(me); - assert(set_size(me) == 0); - assert(set_is_empty(me)); - /* Add a lot of items and clear. */ - for (i = 5000; i < 6000; i++) { - set_put(me, &i); - assert(set_contains(me, &i)); - } - assert(set_size(me) == 1000); - set_clear(me); - p = 0xdeadbeef; - assert(!set_remove(me, &p)); - assert(set_size(me) == 0); - assert(set_is_empty(me)); - me = set_destroy(me); - assert(!me); - /* Create odd shape graph. */ - me = set_init(sizeof(int), compare_int); - key = 10; - set_put(me, &key); - key = 5; - set_put(me, &key); - key = 15; - set_put(me, &key); - key = 3; - set_put(me, &key); - key = 8; - set_put(me, &key); - key = 12; - set_put(me, &key); - key = 18; - set_put(me, &key); - key = 12; - set_remove(me, &key); - key = 5; - set_remove(me, &key); - key = 3; - set_remove(me, &key); - key = 8; - set_remove(me, &key); - set_clear(me); - /* Allocate many nodes. */ + assert(!set_destroy(me)); +} + +static void test_stress_remove(void) +{ + int i; + set me = set_init(sizeof(int), compare_int); + assert(me); for (i = 8123; i < 12314; i += 3) { set_put(me, &i); assert(set_contains(me, &i)); @@ -297,151 +406,119 @@ void test_set(void) set_remove(me, &i); assert(!set_contains(me, &i)); } - set_clear(me); - /* Create another odd shape graph. */ - key = 20; - set_put(me, &key); - key = 10; - set_put(me, &key); - key = 40; - set_put(me, &key); - key = 5; - set_put(me, &key); - key = 15; - set_put(me, &key); - key = 30; - set_put(me, &key); - key = 50; - set_put(me, &key); - key = 25; - set_put(me, &key); - key = 35; - set_put(me, &key); - key = 36; - set_put(me, &key); - key = 34; - set_put(me, &key); - key = 33; - set_put(me, &key); - key = 32; - set_put(me, &key); - key = 30; - set_remove(me, &key); - key = 32; - assert(set_contains(me, &key)); - set_clear(me); - /* One sided tree. */ - key = 10; - set_put(me, &key); - key = 9; - set_put(me, &key); - key = 8; - set_put(me, &key); - key = 7; - set_put(me, &key); - key = 8; - set_remove(me, &key); - key = 7; - assert(set_contains(me, &key)); - set_destroy(me); - /* Replace two sided two children. */ - me = set_init(sizeof(int), compare_int); - key = 5; - set_put(me, &key); - key = 1; - set_put(me, &key); - key = 6; - set_put(me, &key); - key = -1; - set_put(me, &key); - key = 3; - set_put(me, &key); - key = 7; - set_put(me, &key); - key = -2; - set_put(me, &key); - key = 0; - set_put(me, &key); - key = 2; - set_put(me, &key); - key = 4; - set_put(me, &key); - key = 1; - set_remove(me, &key); - assert(!set_contains(me, &key)); - set_clear(me); - key = 5; - set_put(me, &key); - key = 1; - set_put(me, &key); - key = 6; - set_put(me, &key); - key = -1; - set_put(me, &key); - key = 3; - set_put(me, &key); - key = 7; - set_put(me, &key); - key = -2; - set_put(me, &key); - key = 0; - set_put(me, &key); - key = 4; - set_put(me, &key); - key = 1; - set_remove(me, &key); - assert(!set_contains(me, &key)); - me = set_destroy(me); - assert(!me); - me = set_init(sizeof(int), compare_int); - for (i = 4817; i > -2983; i -= 11) { - set_put(me, &i); - assert(set_contains(me, &i)); - } - for (i = -432; i < 3849; i += 7) { - set_remove(me, &i); - assert(!set_contains(me, &i)); - } - set_clear(me); - key = 5; - set_put(me, &key); - key = 7; - set_put(me, &key); - key = 5; - set_remove(me, &key); - set_clear(me); - /* Two children edge case on the other side. */ - key = 8; - set_put(me, &key); - key = 4; - set_put(me, &key); - key = 12; - set_put(me, &key); - key = 2; - set_put(me, &key); - key = 6; - set_put(me, &key); - key = 10; - set_put(me, &key); - key = 16; - set_put(me, &key); - key = 1; - set_put(me, &key); - key = 3; - set_put(me, &key); - key = 5; - set_put(me, &key); - key = 7; - set_put(me, &key); - key = 9; - set_put(me, &key); - key = 11; - set_put(me, &key); - key = 15; - set_put(me, &key); - key = 17; - set_put(me, &key); - key = 13; - set_put(me, &key); - set_clear(me); + assert(!set_destroy(me)); +} + +static void test_unique_delete_one_child(set me) +{ + int arr1[] = {2, 1, -2}; + int arr2[] = {1, 2, -1}; + int arr3[] = {3, 2, 4, 1, -2}; + int arr4[] = {3, 1, 4, 2, -1}; + int arr5[] = {3, 1, 4, 2, -4}; + int arr6[] = {2, 1, 3, 4, -3}; + int sz1 = sizeof(arr1) / sizeof(arr1[0]); + int sz2 = sizeof(arr2) / sizeof(arr2[0]); + int sz3 = sizeof(arr3) / sizeof(arr3[0]); + int sz4 = sizeof(arr4) / sizeof(arr4[0]); + int sz5 = sizeof(arr5) / sizeof(arr5[0]); + int sz6 = sizeof(arr6) / sizeof(arr6[0]); + mutation_order(me, arr1, sz1); + set_clear(me); + mutation_order(me, arr2, sz2); + set_clear(me); + mutation_order(me, arr3, sz3); + set_clear(me); + mutation_order(me, arr4, sz4); + set_clear(me); + mutation_order(me, arr5, sz5); + set_clear(me); + mutation_order(me, arr6, sz6); +} + +static void test_unique_delete_two_children(set me) +{ + int arr1[] = {2, 1, 3, -2}; + int arr2[] = {4, 2, 5, 1, 3, -2}; + int arr3[] = {2, 1, 4, 3, 5, -4}; + int sz1 = sizeof(arr1) / sizeof(arr1[0]); + int sz2 = sizeof(arr2) / sizeof(arr2[0]); + int sz3 = sizeof(arr3) / sizeof(arr3[0]); + mutation_order(me, arr1, sz1); + set_clear(me); + mutation_order(me, arr2, sz2); + set_clear(me); + mutation_order(me, arr3, sz3); +} + +static void test_unique_deletion_patterns(void) +{ + set me = set_init(sizeof(int), compare_int); + assert(me); + test_unique_delete_one_child(me); + set_clear(me); + test_unique_delete_two_children(me); + assert(!set_destroy(me)); +} + +static void test_init_out_of_memory(void) +{ + fail_malloc = 1; + assert(!set_init(sizeof(int), compare_int)); +} + +static void test_put_root_out_of_memory(set me) +{ + int key = 2; + fail_malloc = 1; + assert(set_put(me, &key) == -ENOMEM); + fail_malloc = 1; + delay_fail_malloc = 1; + assert(set_put(me, &key) == -ENOMEM); +} + +static void test_put_on_left_out_of_memory(set me) +{ + int key = 1; + fail_malloc = 1; + assert(set_put(me, &key) == -ENOMEM); + fail_malloc = 1; + delay_fail_malloc = 1; + assert(set_put(me, &key) == -ENOMEM); +} + +static void test_put_on_right_out_of_memory(set me) +{ + int key = 3; + fail_malloc = 1; + assert(set_put(me, &key) == -ENOMEM); + fail_malloc = 1; + delay_fail_malloc = 1; + assert(set_put(me, &key) == -ENOMEM); +} + +static void test_put_out_of_memory(void) +{ + int key = 2; + set me = set_init(sizeof(int), compare_int); + assert(me); + test_put_root_out_of_memory(me); + assert(set_put(me, &key) == 0); + test_put_on_left_out_of_memory(me); + test_put_on_right_out_of_memory(me); + assert(!set_destroy(me)); +} + +void test_set(void) +{ + test_invalid_init(); + test_auto_balancing(); + test_put_already_existing(); + test_remove_nothing(); + test_contains(); + test_stress_add(); + test_stress_remove(); + test_unique_deletion_patterns(); + test_init_out_of_memory(); + test_put_out_of_memory(); } diff --git a/tst/stack.c b/tst/stack.c index 29fe084..1416ddb 100644 --- a/tst/stack.c +++ b/tst/stack.c @@ -1,16 +1,16 @@ #include "test.h" #include "../src/stack.h" -void test_stack(void) +static void test_invalid_init(void) +{ + assert(!stack_init(0)); +} + +static void test_linear_operations(stack me) { int val[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; - int get_arr[10] = {0}; - stack me; int get; int i; - assert(!stack_init(0)); - me = stack_init(sizeof(int)); - assert(me); assert(stack_size(me) == 0); assert(stack_is_empty(me)); for (i = 0; i < 10; i++) { @@ -19,6 +19,13 @@ void test_stack(void) assert(stack_top(&get, me)); assert(get == val[i]); } +} + +static void test_array_copy(stack me) +{ + int get_arr[10] = {0}; + int get; + int i; assert(stack_size(me) == 10); assert(!stack_is_empty(me)); stack_copy_to_array(get_arr, me); @@ -37,13 +44,48 @@ void test_stack(void) get = 0; assert(!stack_pop(&get, me)); assert(!stack_top(&get, me)); - me = stack_destroy(me); - assert(!me); - /* Testing automatic trim. */ - me = stack_init(sizeof(int)); +} + +static void test_basic(void) +{ + stack me = stack_init(sizeof(int)); + assert(me); + test_linear_operations(me); + test_array_copy(me); + assert(!stack_destroy(me)); +} + +static void test_automated_trim(void) +{ + stack me = stack_init(sizeof(int)); + int get; + int i; for (i = 0; i < 100; i++) { stack_push(me, &i); stack_pop(&get, me); } - stack_destroy(me); + assert(!stack_destroy(me)); +} + +static void test_init_out_of_memory(void) +{ + fail_malloc = 1; + assert(!stack_init(sizeof(int))); + fail_malloc = 1; + delay_fail_malloc = 1; + assert(!stack_init(sizeof(int))); + fail_malloc = 1; + delay_fail_malloc = 2; + assert(!stack_init(sizeof(int))); + fail_malloc = 1; + delay_fail_malloc = 3; + assert(!stack_init(sizeof(int))); +} + +void test_stack(void) +{ + test_invalid_init(); + test_basic(); + test_automated_trim(); + test_init_out_of_memory(); } diff --git a/tst/test.c b/tst/test.c index 937469b..d7f3db7 100644 --- a/tst/test.c +++ b/tst/test.c @@ -1,5 +1,70 @@ #include "test.h" +#define _GNU_SOURCE + +#include + +#ifndef RTLD_NEXT +#define RTLD_NEXT ((void *) -1L) +#endif + +int fail_malloc = 0; +int fail_calloc = 0; +int fail_realloc = 0; + +int delay_fail_malloc = 0; +int delay_fail_calloc = 0; +int delay_fail_realloc = 0; + +static void *(*real_malloc)(size_t); +static void *(*real_calloc)(size_t, size_t); +static void *(*real_realloc)(void *, size_t); + +void *malloc(size_t size) +{ + if (!real_malloc) { + real_malloc = dlsym(RTLD_NEXT, "malloc"); + } + if (delay_fail_malloc == 0 && fail_malloc == 1) { + fail_malloc = 0; + return NULL; + } + if (delay_fail_malloc > 0) { + delay_fail_malloc--; + } + return real_malloc(size); +} + +void *calloc(size_t count, size_t size) +{ + if (!real_calloc) { + real_calloc = dlsym(RTLD_NEXT, "calloc"); + } + if (delay_fail_calloc == 0 && fail_calloc == 1) { + fail_calloc = 0; + return NULL; + } + if (delay_fail_calloc > 0) { + delay_fail_calloc--; + } + return real_calloc(count, size); +} + +void *realloc(void *ptr, size_t new_size) +{ + if (!real_realloc) { + real_realloc = dlsym(RTLD_NEXT, "realloc"); + } + if (delay_fail_realloc == 0 && fail_realloc == 1) { + fail_realloc = 0; + return NULL; + } + if (delay_fail_realloc > 0) { + delay_fail_realloc--; + } + return real_realloc(ptr, new_size); +} + int main(void) { test_array(); diff --git a/tst/test.h b/tst/test.h index dbef271..129a237 100644 --- a/tst/test.h +++ b/tst/test.h @@ -5,6 +5,14 @@ #include #include +extern int fail_malloc; +extern int fail_calloc; +extern int fail_realloc; + +extern int delay_fail_malloc; +extern int delay_fail_calloc; +extern int delay_fail_realloc; + void test_array(void); void test_vector(void); void test_deque(void); diff --git a/tst/unordered_map.c b/tst/unordered_map.c index 0cfb71c..a82f420 100644 --- a/tst/unordered_map.c +++ b/tst/unordered_map.c @@ -18,25 +18,26 @@ static unsigned long hash_int(const void *const key) return hash; } -static unsigned long bad_hash_int(const void *const key) +static unsigned long bad_hash_int() { return 5; } -void test_unordered_map(void) +static void test_invalid_init(void) { - int val_arr[10] = {5, 9, 4, -5, 0, 6, 1, 5, 7, 2}; - unordered_map me; - int key; - int num; - int value; - int i; - int j; assert(!unordered_map_init(0, sizeof(int), hash_int, compare_int)); assert(!unordered_map_init(sizeof(int), 0, hash_int, compare_int)); assert(!unordered_map_init(sizeof(int), sizeof(int), NULL, compare_int)); assert(!unordered_map_init(sizeof(int), sizeof(int), hash_int, NULL)); - me = unordered_map_init(sizeof(int), sizeof(int), hash_int, compare_int); +} + +static void test_put(unordered_map me) +{ + int val_arr[10] = {5, 9, 4, -5, 0, 6, 1, 5, 7, 2}; + int key; + int value; + int i; + int j; assert(unordered_map_size(me) == 0); assert(unordered_map_is_empty(me)); key = 4; @@ -73,7 +74,11 @@ void test_unordered_map(void) } assert(unordered_map_contains(me, &i) == contains); } - num = -3; +} + +static void test_remove(unordered_map me) +{ + int num = -3; assert(!unordered_map_remove(me, &num)); assert(unordered_map_size(me) == 9); assert(!unordered_map_contains(me, &num)); @@ -113,7 +118,12 @@ void test_unordered_map(void) assert(unordered_map_remove(me, &num)); assert(unordered_map_size(me) == 0); assert(!unordered_map_contains(me, &num)); - /* Add a lot of items and remove individually. */ +} + +static void test_stress_remove(unordered_map me) +{ + int value = 27; + int i; for (i = 5000; i < 6000; i++) { unordered_map_put(me, &i, &value); assert(unordered_map_contains(me, &i)); @@ -128,7 +138,13 @@ void test_unordered_map(void) unordered_map_clear(me); assert(unordered_map_size(me) == 0); assert(unordered_map_is_empty(me)); - /* Add a lot of items and clear. */ +} + +static void test_stress_clear(unordered_map me) +{ + int value = 57; + int key; + int i; for (i = 5000; i < 6000; i++) { unordered_map_put(me, &i, &value); assert(unordered_map_contains(me, &i)); @@ -142,10 +158,27 @@ void test_unordered_map(void) assert(!unordered_map_remove(me, &key)); assert(unordered_map_size(me) == 0); assert(unordered_map_is_empty(me)); - me = unordered_map_destroy(me); - assert(!me); - me = unordered_map_init(sizeof(int), sizeof(int), bad_hash_int, - compare_int); +} + +static void test_basic(void) +{ + unordered_map me = unordered_map_init(sizeof(int), sizeof(int), hash_int, + compare_int); + assert(me); + test_put(me); + test_remove(me); + test_stress_remove(me); + test_stress_clear(me); + assert(!unordered_map_destroy(me)); +} + +static void test_bad_hash(void) +{ + int num; + int key; + int value; + unordered_map me = unordered_map_init(sizeof(int), sizeof(int), + bad_hash_int, compare_int); num = 1; unordered_map_put(me, &num, &num); num = 2; @@ -166,4 +199,108 @@ void test_unordered_map(void) value = 0xdeadbeef; assert(!unordered_map_get(&value, me, &key)); assert(value == 0xdeadbeef); + assert(!unordered_map_destroy(me)); +} + +static void test_init_out_of_memory(void) +{ + fail_malloc = 1; + assert(!unordered_map_init(sizeof(int), sizeof(int), bad_hash_int, + compare_int)); + fail_calloc = 1; + assert(!unordered_map_init(sizeof(int), sizeof(int), bad_hash_int, + compare_int)); +} + +static void test_rehash_out_of_memory(void) +{ + int key = 5; + int value = 7; + unordered_map me = unordered_map_init(sizeof(int), sizeof(int), + bad_hash_int, compare_int); + assert(me); + unordered_map_put(me, &key, &value); + assert(unordered_map_size(me) == 1); + assert(unordered_map_contains(me, &key)); + fail_calloc = 1; + assert(unordered_map_rehash(me) == -ENOMEM); + assert(unordered_map_size(me) == 1); + assert(unordered_map_contains(me, &key)); + assert(!unordered_map_destroy(me)); +} + +static void test_put_out_of_memory(void) +{ + int key = 5; + int value = 7; + unordered_map me = unordered_map_init(sizeof(int), sizeof(int), + bad_hash_int, compare_int); + assert(me); + fail_malloc = 1; + assert(unordered_map_put(me, &key, &value) == -ENOMEM); + fail_malloc = 1; + delay_fail_malloc = 1; + assert(unordered_map_put(me, &key, &value) == -ENOMEM); + fail_malloc = 1; + delay_fail_malloc = 2; + assert(unordered_map_put(me, &key, &value) == -ENOMEM); + assert(unordered_map_put(me, &key, &value) == 0); + key = 7; + fail_malloc = 1; + assert(unordered_map_put(me, &key, &value) == -ENOMEM); + fail_malloc = 1; + delay_fail_malloc = 1; + assert(unordered_map_put(me, &key, &value) == -ENOMEM); + fail_malloc = 1; + delay_fail_malloc = 2; + assert(unordered_map_put(me, &key, &value) == -ENOMEM); + assert(!unordered_map_destroy(me)); +} + +static void test_resize_out_of_memory(void) +{ + int i; + unordered_map me = unordered_map_init(sizeof(int), sizeof(int), hash_int, + compare_int); + for (i = 0; i < 5; i++) { + assert(unordered_map_put(me, &i, &i) == 0); + } + assert(unordered_map_size(me) == 5); + i++; + fail_calloc = 1; + assert(unordered_map_put(me, &i, &i) == -ENOMEM); + assert(unordered_map_size(me) == 5); + for (i = 0; i < 5; i++) { + assert(unordered_map_contains(me, &i)); + } + assert(!unordered_map_destroy(me)); +} + +static void test_clear_out_of_memory(void) +{ + int key = 5; + int value = 7; + unordered_map me = unordered_map_init(sizeof(int), sizeof(int), hash_int, + compare_int); + assert(me); + assert(unordered_map_put(me, &key, &value) == 0); + assert(unordered_map_size(me) == 1); + assert(unordered_map_contains(me, &key)); + fail_calloc = 1; + assert(unordered_map_clear(me) == -ENOMEM); + assert(unordered_map_size(me) == 1); + assert(unordered_map_contains(me, &key)); + assert(!unordered_map_destroy(me)); +} + +void test_unordered_map(void) +{ + test_invalid_init(); + test_basic(); + test_bad_hash(); + test_init_out_of_memory(); + test_rehash_out_of_memory(); + test_put_out_of_memory(); + test_resize_out_of_memory(); + test_clear_out_of_memory(); } diff --git a/tst/unordered_multimap.c b/tst/unordered_multimap.c index 4ffa46d..99128f4 100644 --- a/tst/unordered_multimap.c +++ b/tst/unordered_multimap.c @@ -18,22 +18,13 @@ static unsigned long hash_int(const void *const key) return hash; } -static unsigned long bad_hash_int(const void *const key) +static unsigned long bad_hash_int() { return 5; } -void test_unordered_multimap(void) +static void test_invalid_init(void) { - int c[10] = {5, 9, 4, -5, 0, 6, 1, 5, 7, 2}; - unordered_multimap me; - int key; - int value; - int num; - int count; - int val; - int i; - int j; assert(!unordered_multimap_init(0, sizeof(int), hash_int, compare_int, compare_int)); assert(!unordered_multimap_init(sizeof(int), 0, hash_int, compare_int, @@ -44,13 +35,18 @@ void test_unordered_multimap(void) compare_int)); assert(!unordered_multimap_init(sizeof(int), sizeof(int), hash_int, compare_int, NULL)); - me = unordered_multimap_init(sizeof(int), sizeof(int), hash_int, - compare_int, compare_int); - assert(me); +} + +static void test_put(unordered_multimap me) +{ + int val_arr[10] = {5, 9, 4, -5, 0, 6, 1, 5, 7, 2}; + int value = 123; + int key; + int i; + int j; assert(unordered_multimap_size(me) == 0); assert(unordered_multimap_is_empty(me)); key = 4; - value = 123; unordered_multimap_put(me, &key, &value); assert(unordered_multimap_size(me) == 1); unordered_multimap_put(me, &key, &value); @@ -71,23 +67,28 @@ void test_unordered_multimap(void) unordered_multimap_remove(me, &key, &value); assert(unordered_multimap_size(me) == 0); for (i = 0; i < 10; i++) { - unordered_multimap_put(me, &c[i], &value); - assert(unordered_multimap_contains(me, &c[i])); + unordered_multimap_put(me, &val_arr[i], &value); + assert(unordered_multimap_contains(me, &val_arr[i])); } assert(unordered_multimap_size(me) == 10); for (i = 0; i < 10; i++) { - assert(unordered_multimap_contains(me, &c[i])); + assert(unordered_multimap_contains(me, &val_arr[i])); } for (i = -100; i < 100; i++) { int contains = 0; for (j = 0; j < 10; j++) { - if (c[j] == i) { + if (val_arr[j] == i) { contains = 1; } } assert(unordered_multimap_contains(me, &i) == contains); } - num = -3; +} + +static void test_remove(unordered_multimap me) +{ + int value = 123; + int num = -3; assert(!unordered_multimap_remove(me, &num, &value)); assert(unordered_multimap_size(me) == 10); assert(!unordered_multimap_contains(me, &num)); @@ -119,7 +120,14 @@ void test_unordered_multimap(void) assert(unordered_multimap_remove(me, &num, &value)); assert(unordered_multimap_size(me) == 3); assert(!unordered_multimap_contains(me, &num)); - num = 5; +} + +static void test_multiple_values_one_key(unordered_multimap me) +{ + int value = 123; + int num = 5; + int count; + int val; assert(unordered_multimap_count(me, &num) == 2); unordered_multimap_get_start(me, &num); count = 0; @@ -141,7 +149,12 @@ void test_unordered_multimap(void) assert(unordered_multimap_remove(me, &num, &value)); assert(unordered_multimap_size(me) == 0); assert(!unordered_multimap_contains(me, &num)); - /* Add a lot of items and remove individually. */ +} + +static void test_stress_remove(unordered_multimap me) +{ + int value = 123; + int i; for (i = 5000; i < 6000; i++) { unordered_multimap_put(me, &i, &value); assert(unordered_multimap_contains(me, &i)); @@ -156,7 +169,13 @@ void test_unordered_multimap(void) unordered_multimap_clear(me); assert(unordered_multimap_size(me) == 0); assert(unordered_multimap_is_empty(me)); - /* Add a lot of items and clear. */ +} + +static void test_stress_clear(unordered_multimap me) +{ + int value = 123; + int key; + int i; for (i = 5000; i < 6000; i++) { unordered_multimap_put(me, &i, &value); assert(unordered_multimap_contains(me, &i)); @@ -180,11 +199,29 @@ void test_unordered_multimap(void) assert(unordered_multimap_size(me) == 11); unordered_multimap_remove_all(me, &key); assert(unordered_multimap_size(me) == 1); - me = unordered_multimap_destroy(me); - assert(!me); - me = unordered_multimap_init(sizeof(int), sizeof(int), bad_hash_int, - compare_int, compare_int); - key = 1; +} + +static void test_basic(void) +{ + unordered_multimap me = unordered_multimap_init(sizeof(int), sizeof(int), + hash_int, compare_int, + compare_int); + assert(me); + test_put(me); + test_remove(me); + test_multiple_values_one_key(me); + test_stress_remove(me); + test_stress_clear(me); + assert(!unordered_multimap_destroy(me)); +} + +static void test_bad_hash(void) +{ + unordered_multimap me = unordered_multimap_init(sizeof(int), sizeof(int), + bad_hash_int, compare_int, + compare_int); + int value = 123; + int key = 1; unordered_multimap_put(me, &key, &value); key = 2; unordered_multimap_put(me, &key, &value); @@ -201,9 +238,16 @@ void test_unordered_multimap(void) assert(unordered_multimap_size(me) == 4); unordered_multimap_rehash(me); assert(unordered_multimap_size(me) == 4); - me = unordered_multimap_init(sizeof(int), sizeof(int), bad_hash_int, - compare_int, compare_int); - key = 1; + assert(!unordered_multimap_destroy(me)); +} + +static void test_collision(void) +{ + unordered_multimap me = unordered_multimap_init(sizeof(int), sizeof(int), + bad_hash_int, compare_int, + compare_int); + int value = 123; + int key = 1; unordered_multimap_put(me, &key, &value); key = 2; unordered_multimap_put(me, &key, &value); @@ -224,10 +268,16 @@ void test_unordered_multimap(void) assert(unordered_multimap_size(me) == 0); assert(!unordered_multimap_remove_all(me, &key)); assert(unordered_multimap_size(me) == 0); - me = unordered_multimap_init(sizeof(int), sizeof(int), bad_hash_int, - compare_int, compare_int); - key = 1; - value = 10; + assert(!unordered_multimap_destroy(me)); +} + +static void test_bad_hash_collision(void) +{ + unordered_multimap me = unordered_multimap_init(sizeof(int), sizeof(int), + bad_hash_int, compare_int, + compare_int); + int key = 1; + int value = 10; unordered_multimap_put(me, &key, &value); key = 2; value = 11; @@ -250,4 +300,118 @@ void test_unordered_multimap(void) value = 30; assert(!unordered_multimap_get_next(&value, me)); assert(value == 30); + assert(!unordered_multimap_destroy(me)); +} + +static void test_init_out_of_memory(void) +{ + fail_malloc = 1; + assert(!unordered_multimap_init(sizeof(int), sizeof(int), hash_int, + compare_int, compare_int)); + fail_calloc = 1; + assert(!unordered_multimap_init(sizeof(int), sizeof(int), hash_int, + compare_int, compare_int)); + fail_calloc = 1; + delay_fail_calloc = 1; + assert(!unordered_multimap_init(sizeof(int), sizeof(int), hash_int, + compare_int, compare_int)); +} + +static void test_rehash_out_of_memory(void) +{ + int key = 5; + int value = 7; + unordered_multimap me = unordered_multimap_init(sizeof(int), sizeof(int), + bad_hash_int, compare_int, + compare_int); + assert(me); + unordered_multimap_put(me, &key, &value); + assert(unordered_multimap_size(me) == 1); + assert(unordered_multimap_contains(me, &key)); + fail_calloc = 1; + assert(unordered_multimap_rehash(me) == -ENOMEM); + assert(unordered_multimap_size(me) == 1); + assert(unordered_multimap_contains(me, &key)); + assert(!unordered_multimap_destroy(me)); +} + +static void test_put_out_of_memory(void) +{ + int key = 5; + int value = 7; + unordered_multimap me = unordered_multimap_init(sizeof(int), sizeof(int), + bad_hash_int, compare_int, + compare_int); + assert(me); + fail_malloc = 1; + assert(unordered_multimap_put(me, &key, &value) == -ENOMEM); + fail_malloc = 1; + delay_fail_malloc = 1; + assert(unordered_multimap_put(me, &key, &value) == -ENOMEM); + fail_malloc = 1; + delay_fail_malloc = 2; + assert(unordered_multimap_put(me, &key, &value) == -ENOMEM); + assert(unordered_multimap_put(me, &key, &value) == 0); + key = 7; + fail_malloc = 1; + assert(unordered_multimap_put(me, &key, &value) == -ENOMEM); + fail_malloc = 1; + delay_fail_malloc = 1; + assert(unordered_multimap_put(me, &key, &value) == -ENOMEM); + fail_malloc = 1; + delay_fail_malloc = 2; + assert(unordered_multimap_put(me, &key, &value) == -ENOMEM); + assert(!unordered_multimap_destroy(me)); +} + +static void test_resize_out_of_memory(void) +{ + int i; + unordered_multimap me = unordered_multimap_init(sizeof(int), sizeof(int), + hash_int, compare_int, + compare_int); + for (i = 0; i < 5; i++) { + assert(unordered_multimap_put(me, &i, &i) == 0); + } + assert(unordered_multimap_size(me) == 5); + i++; + fail_calloc = 1; + assert(unordered_multimap_put(me, &i, &i) == -ENOMEM); + assert(unordered_multimap_size(me) == 5); + for (i = 0; i < 5; i++) { + assert(unordered_multimap_contains(me, &i)); + } + assert(!unordered_multimap_destroy(me)); +} + +static void test_clear_out_of_memory(void) +{ + int key = 5; + int value = 7; + unordered_multimap me = unordered_multimap_init(sizeof(int), sizeof(int), + hash_int, compare_int, + compare_int); + assert(me); + assert(unordered_multimap_put(me, &key, &value) == 0); + assert(unordered_multimap_size(me) == 1); + assert(unordered_multimap_contains(me, &key)); + fail_calloc = 1; + assert(unordered_multimap_clear(me) == -ENOMEM); + assert(unordered_multimap_size(me) == 1); + assert(unordered_multimap_contains(me, &key)); + assert(!unordered_multimap_destroy(me)); +} + +void test_unordered_multimap(void) +{ + test_invalid_init(); + test_basic(); + test_bad_hash(); + test_collision(); + test_bad_hash_collision(); + test_init_out_of_memory(); + test_rehash_out_of_memory(); + test_put_out_of_memory(); + test_resize_out_of_memory(); + test_clear_out_of_memory(); } diff --git a/tst/unordered_multiset.c b/tst/unordered_multiset.c index 6011451..1da920c 100644 --- a/tst/unordered_multiset.c +++ b/tst/unordered_multiset.c @@ -18,24 +18,24 @@ static unsigned long hash_int(const void *const key) return hash; } -static unsigned long bad_hash_int(const void *const key) +static unsigned long bad_hash_int() { return 5; } -void test_unordered_multiset(void) +static void test_invalid_init(void) { - int c[10] = {5, 9, 4, -5, 0, 6, 1, 5, 7, 2}; - unordered_multiset me; - int key; - int num; - int i; - int j; assert(!unordered_multiset_init(0, hash_int, compare_int)); assert(!unordered_multiset_init(sizeof(int), NULL, compare_int)); assert(!unordered_multiset_init(sizeof(int), hash_int, NULL)); - me = unordered_multiset_init(sizeof(int), hash_int, compare_int); - assert(me); +} + +static void test_put(unordered_multiset me) +{ + int val_arr[10] = {5, 9, 4, -5, 0, 6, 1, 5, 7, 2}; + int key; + int i; + int j; assert(unordered_multiset_size(me) == 0); assert(unordered_multiset_is_empty(me)); key = 4; @@ -59,23 +59,27 @@ void test_unordered_multiset(void) unordered_multiset_remove(me, &key); assert(unordered_multiset_size(me) == 0); for (i = 0; i < 10; i++) { - unordered_multiset_put(me, &c[i]); - assert(unordered_multiset_contains(me, &c[i])); + unordered_multiset_put(me, &val_arr[i]); + assert(unordered_multiset_contains(me, &val_arr[i])); } assert(unordered_multiset_size(me) == 10); for (i = 0; i < 10; i++) { - assert(unordered_multiset_contains(me, &c[i])); + assert(unordered_multiset_contains(me, &val_arr[i])); } for (i = -100; i < 100; i++) { int contains = 0; for (j = 0; j < 10; j++) { - if (c[j] == i) { + if (val_arr[j] == i) { contains = 1; } } assert(unordered_multiset_contains(me, &i) == contains); } - num = -3; +} + +static void test_remove(unordered_multiset me) +{ + int num = -3; assert(!unordered_multiset_remove(me, &num)); assert(unordered_multiset_size(me) == 10); assert(!unordered_multiset_contains(me, &num)); @@ -119,7 +123,11 @@ void test_unordered_multiset(void) assert(unordered_multiset_remove(me, &num)); assert(unordered_multiset_size(me) == 0); assert(!unordered_multiset_contains(me, &num)); - /* Add a lot of items and remove individually. */ +} + +static void test_stress_remove(unordered_multiset me) +{ + int i; for (i = 5000; i < 6000; i++) { unordered_multiset_put(me, &i); assert(unordered_multiset_contains(me, &i)); @@ -134,7 +142,12 @@ void test_unordered_multiset(void) unordered_multiset_clear(me); assert(unordered_multiset_size(me) == 0); assert(unordered_multiset_is_empty(me)); - /* Add a lot of items and clear. */ +} + +static void test_stress_clear(unordered_multiset me) +{ + int key; + int i; for (i = 5000; i < 6000; i++) { unordered_multiset_put(me, &i); assert(unordered_multiset_contains(me, &i)); @@ -158,9 +171,26 @@ void test_unordered_multiset(void) assert(unordered_multiset_size(me) == 11); unordered_multiset_remove_all(me, &key); assert(unordered_multiset_size(me) == 1); - me = unordered_multiset_destroy(me); - assert(!me); - me = unordered_multiset_init(sizeof(int), bad_hash_int, compare_int); +} + +static void test_basic(void) +{ + unordered_multiset me = unordered_multiset_init(sizeof(int), hash_int, + compare_int); + assert(me); + test_put(me); + test_remove(me); + test_stress_remove(me); + test_stress_clear(me); + assert(!unordered_multiset_destroy(me)); +} + +static void test_bad_hash(void) +{ + int num; + unordered_multiset me = unordered_multiset_init(sizeof(int), bad_hash_int, + compare_int); + assert(me); num = 1; unordered_multiset_put(me, &num); num = 2; @@ -178,7 +208,15 @@ void test_unordered_multiset(void) assert(unordered_multiset_size(me) == 4); unordered_multiset_rehash(me); assert(unordered_multiset_size(me) == 4); - me = unordered_multiset_init(sizeof(int), bad_hash_int, compare_int); + assert(!unordered_multiset_destroy(me)); +} + +static void test_collision(void) +{ + int num; + unordered_multiset me = unordered_multiset_init(sizeof(int), bad_hash_int, + compare_int); + assert(me); num = 1; unordered_multiset_put(me, &num); num = 2; @@ -200,4 +238,98 @@ void test_unordered_multiset(void) assert(unordered_multiset_size(me) == 0); assert(!unordered_multiset_remove_all(me, &num)); assert(unordered_multiset_size(me) == 0); + assert(!unordered_multiset_destroy(me)); +} + +static void test_init_out_of_memory(void) +{ + fail_malloc = 1; + assert(!unordered_multiset_init(sizeof(int), hash_int, compare_int)); + fail_calloc = 1; + assert(!unordered_multiset_init(sizeof(int), hash_int, compare_int)); +} + +static void test_rehash_out_of_memory(void) +{ + int key = 5; + unordered_multiset me = unordered_multiset_init(sizeof(int), hash_int, + compare_int); + assert(me); + unordered_multiset_put(me, &key); + assert(unordered_multiset_size(me) == 1); + assert(unordered_multiset_contains(me, &key)); + fail_calloc = 1; + assert(unordered_multiset_rehash(me) == -ENOMEM); + assert(unordered_multiset_size(me) == 1); + assert(unordered_multiset_contains(me, &key)); + assert(!unordered_multiset_destroy(me)); +} + +static void test_put_out_of_memory(void) +{ + int key = 5; + unordered_multiset me = unordered_multiset_init(sizeof(int), bad_hash_int, + compare_int); + assert(me); + fail_malloc = 1; + assert(unordered_multiset_put(me, &key) == -ENOMEM); + fail_malloc = 1; + delay_fail_malloc = 1; + assert(unordered_multiset_put(me, &key) == -ENOMEM); + assert(unordered_multiset_put(me, &key) == 0); + key = 7; + fail_malloc = 1; + assert(unordered_multiset_put(me, &key) == -ENOMEM); + fail_malloc = 1; + delay_fail_malloc = 1; + assert(unordered_multiset_put(me, &key) == -ENOMEM); + assert(!unordered_multiset_destroy(me)); +} + +static void test_resize_out_of_memory(void) +{ + int i; + unordered_multiset me = unordered_multiset_init(sizeof(int), hash_int, + compare_int); + for (i = 0; i < 5; i++) { + assert(unordered_multiset_put(me, &i) == 0); + } + assert(unordered_multiset_size(me) == 5); + i++; + fail_calloc = 1; + assert(unordered_multiset_put(me, &i) == -ENOMEM); + assert(unordered_multiset_size(me) == 5); + for (i = 0; i < 5; i++) { + assert(unordered_multiset_contains(me, &i)); + } + assert(!unordered_multiset_destroy(me)); +} + +static void test_clear_out_of_memory(void) +{ + int key = 5; + unordered_multiset me = unordered_multiset_init(sizeof(int), hash_int, + compare_int); + assert(me); + assert(unordered_multiset_put(me, &key) == 0); + assert(unordered_multiset_size(me) == 1); + assert(unordered_multiset_contains(me, &key)); + fail_calloc = 1; + assert(unordered_multiset_clear(me) == -ENOMEM); + assert(unordered_multiset_size(me) == 1); + assert(unordered_multiset_contains(me, &key)); + assert(!unordered_multiset_destroy(me)); +} + +void test_unordered_multiset(void) +{ + test_invalid_init(); + test_basic(); + test_bad_hash(); + test_collision(); + test_init_out_of_memory(); + test_rehash_out_of_memory(); + test_put_out_of_memory(); + test_resize_out_of_memory(); + test_clear_out_of_memory(); } diff --git a/tst/unordered_set.c b/tst/unordered_set.c index e58bde9..914856a 100644 --- a/tst/unordered_set.c +++ b/tst/unordered_set.c @@ -18,25 +18,24 @@ static unsigned long hash_int(const void *const key) return hash; } -static unsigned long bad_hash_int(const void *const key) +static unsigned long bad_hash_int() { return 5; } -void test_unordered_set(void) +static void test_invalid_init(void) { - int val_arr[10] = {5, 9, 4, -5, 0, 6, 1, 5, 7, 2}; - unordered_set me; - int key; - int num; - int p; - int i; - int j; assert(!unordered_set_init(0, hash_int, compare_int)); assert(!unordered_set_init(sizeof(int), NULL, compare_int)); assert(!unordered_set_init(sizeof(int), hash_int, NULL)); - me = unordered_set_init(sizeof(int), hash_int, compare_int); - assert(me); +} + +static void test_put(unordered_set me) +{ + int val_arr[10] = {5, 9, 4, -5, 0, 6, 1, 5, 7, 2}; + int key; + int i; + int j; assert(unordered_set_size(me) == 0); assert(unordered_set_is_empty(me)); key = 4; @@ -68,7 +67,11 @@ void test_unordered_set(void) } assert(unordered_set_contains(me, &i) == contains); } - num = -3; +} + +static void test_remove(unordered_set me) +{ + int num = -3; assert(!unordered_set_remove(me, &num)); assert(unordered_set_size(me) == 9); assert(!unordered_set_contains(me, &num)); @@ -108,7 +111,11 @@ void test_unordered_set(void) assert(unordered_set_remove(me, &num)); assert(unordered_set_size(me) == 0); assert(!unordered_set_contains(me, &num)); - /* Add a lot of items and remove individually. */ +} + +static void test_stress_remove(unordered_set me) +{ + int i; for (i = 5000; i < 6000; i++) { unordered_set_put(me, &i); assert(unordered_set_contains(me, &i)); @@ -123,7 +130,12 @@ void test_unordered_set(void) unordered_set_clear(me); assert(unordered_set_size(me) == 0); assert(unordered_set_is_empty(me)); - /* Add a lot of items and clear. */ +} + +static void test_stress_clear(unordered_set me) +{ + int i; + int p = 0xdeadbeef; for (i = 5000; i < 6000; i++) { unordered_set_put(me, &i); assert(unordered_set_contains(me, &i)); @@ -133,13 +145,28 @@ void test_unordered_set(void) unordered_set_rehash(me); assert(hash_count == 1000); unordered_set_clear(me); - p = 0xdeadbeef; assert(!unordered_set_remove(me, &p)); assert(unordered_set_size(me) == 0); assert(unordered_set_is_empty(me)); - me = unordered_set_destroy(me); - assert(!me); - me = unordered_set_init(sizeof(int), bad_hash_int, compare_int); +} + +static void test_basic(void) +{ + unordered_set me = unordered_set_init(sizeof(int), hash_int, compare_int); + assert(me); + test_put(me); + test_remove(me); + test_stress_remove(me); + test_stress_clear(me); + assert(!unordered_set_destroy(me)); +} + +static void test_bad_hash(void) +{ + int num; + unordered_set me = unordered_set_init(sizeof(int), bad_hash_int, + compare_int); + assert(me); num = 1; unordered_set_put(me, &num); num = 2; @@ -156,4 +183,94 @@ void test_unordered_set(void) assert(unordered_set_size(me) == 3); unordered_set_rehash(me); assert(unordered_set_size(me) == 3); + assert(!unordered_set_destroy(me)); +} + +static void test_init_out_of_memory(void) +{ + fail_malloc = 1; + assert(!unordered_set_init(sizeof(int), hash_int, compare_int)); + fail_calloc = 1; + assert(!unordered_set_init(sizeof(int), hash_int, compare_int)); +} + +static void test_rehash_out_of_memory(void) +{ + int key = 5; + unordered_set me = unordered_set_init(sizeof(int), hash_int, compare_int); + assert(me); + unordered_set_put(me, &key); + assert(unordered_set_size(me) == 1); + assert(unordered_set_contains(me, &key)); + fail_calloc = 1; + assert(unordered_set_rehash(me) == -ENOMEM); + assert(unordered_set_size(me) == 1); + assert(unordered_set_contains(me, &key)); + assert(!unordered_set_destroy(me)); +} + +static void test_put_out_of_memory(void) +{ + int key = 5; + unordered_set me = unordered_set_init(sizeof(int), bad_hash_int, + compare_int); + assert(me); + fail_malloc = 1; + assert(unordered_set_put(me, &key) == -ENOMEM); + fail_malloc = 1; + delay_fail_malloc = 1; + assert(unordered_set_put(me, &key) == -ENOMEM); + assert(unordered_set_put(me, &key) == 0); + key = 7; + fail_malloc = 1; + assert(unordered_set_put(me, &key) == -ENOMEM); + fail_malloc = 1; + delay_fail_malloc = 1; + assert(unordered_set_put(me, &key) == -ENOMEM); + assert(!unordered_set_destroy(me)); +} + +static void test_resize_out_of_memory(void) +{ + int i; + unordered_set me = unordered_set_init(sizeof(int), hash_int, compare_int); + for (i = 0; i < 5; i++) { + assert(unordered_set_put(me, &i) == 0); + } + assert(unordered_set_size(me) == 5); + i++; + fail_calloc = 1; + assert(unordered_set_put(me, &i) == -ENOMEM); + assert(unordered_set_size(me) == 5); + for (i = 0; i < 5; i++) { + assert(unordered_set_contains(me, &i)); + } + assert(!unordered_set_destroy(me)); +} + +static void test_clear_out_of_memory(void) +{ + int key = 5; + unordered_set me = unordered_set_init(sizeof(int), hash_int, compare_int); + assert(me); + assert(unordered_set_put(me, &key) == 0); + assert(unordered_set_size(me) == 1); + assert(unordered_set_contains(me, &key)); + fail_calloc = 1; + assert(unordered_set_clear(me) == -ENOMEM); + assert(unordered_set_size(me) == 1); + assert(unordered_set_contains(me, &key)); + assert(!unordered_set_destroy(me)); +} + +void test_unordered_set(void) +{ + test_invalid_init(); + test_basic(); + test_bad_hash(); + test_init_out_of_memory(); + test_rehash_out_of_memory(); + test_put_out_of_memory(); + test_resize_out_of_memory(); + test_clear_out_of_memory(); } diff --git a/tst/vector.c b/tst/vector.c index e6f5c9f..bc9ce79 100644 --- a/tst/vector.c +++ b/tst/vector.c @@ -2,88 +2,18 @@ #include "test.h" #include "../src/vector.h" -static void test_vector_of_vectors(void) +static void test_invalid_init(void) { - /* Test using a vector of vectors of ints */ - vector outer = vector_init(sizeof(vector)); - /* Add vectors to the outer vector */ - int i; - int j; - for (i = 0; i < 5; i++) { - vector inner = vector_init(sizeof(int)); - for (j = 1; j <= 10; j++) { - vector_add_last(inner, &j); - } - assert(vector_size(inner) == 10); - vector_add_last(outer, &inner); - } - assert(vector_size(outer) == 5); - /* Delete the vectors in the outer vector */ - for (i = 0; i < 5; i++) { - vector inner = NULL; - vector_get_first(&inner, outer); - for (j = 0; j < 10; j++) { - int num = 0xdeadbeef; - vector_get_at(&num, inner, j); - assert(num == j + 1); - } - vector_remove_first(outer); - vector_destroy(inner); - } - assert(vector_is_empty(outer)); - vector_destroy(outer); + assert(!vector_init(0)); } -static void test_vector_dynamic(void) +static void test_adding(vector me) { - char **str = malloc(5 * sizeof(char **)); - int i; - int j; - vector str_vector; - for (i = 0; i < 5; i++) { - str[i] = malloc(10 * sizeof(char *)); - for (j = 0; j < 9; j++) { - str[i][j] = (char) ('a' + i); - } - str[i][9] = '\0'; - } - str_vector = vector_init(sizeof(char *)); - assert(str_vector); - for (i = 0; i < 5; i++) { - vector_add_last(str_vector, &str[i]); - } - assert(vector_size(str_vector) == 5); - for (i = 0; i < 5; i++) { - char *retrieve = NULL; - vector_get_first(&retrieve, str_vector); - vector_remove_first(str_vector); - assert(strcmp(retrieve, str[i]) == 0); - free(retrieve); - } - free(str); - assert(vector_size(str_vector) == 0); - str_vector = vector_destroy(str_vector); - assert(!str_vector); -} - -void test_vector(void) -{ - int val[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; int get_arr[10] = {0}; - int trimmed[5] = {0}; - int arr[3] = {0}; - int get; - vector me; - int i; int *data; - int add; - int set; - assert(!vector_init(0)); - me = vector_init(sizeof(int)); - assert(me); - assert(vector_size(me) == 0); - assert(vector_is_empty(me)); + int get; + int i; for (i = 0; i < 10; i++) { vector_add_first(me, &val[i]); get = 0; @@ -104,6 +34,12 @@ void test_vector(void) assert(data[i] == val[9 - i]); } assert(vector_capacity(me) >= vector_size(me)); +} + +static void test_trim(vector me) +{ + int trimmed[5] = {0}; + int i; vector_trim(me); vector_reserve(me, 3); for (i = 0; i < 7; i++) { @@ -114,7 +50,15 @@ void test_vector(void) for (i = 0; i < 3; i++) { assert(10 - i == trimmed[i]); } - add = 3; +} + +static void test_linear_operations(vector me) +{ + int arr[3] = {0}; + int get; + int set; + int add = 3; + assert(vector_size(me) == 3); vector_add_last(me, &add); add = -1; vector_add_at(me, 1, &add); @@ -171,6 +115,12 @@ void test_vector(void) assert(arr[0] == -5); assert(arr[1] == -6); assert(arr[2] == -7); +} + +static void test_invalid_operations(vector me) +{ + int set; + int i; assert(vector_reserve(me, 100) == 0); assert(vector_set_at(me, 4, &set) == -EINVAL); assert(vector_get_at(&set, me, 4) == -EINVAL); @@ -190,8 +140,139 @@ void test_vector(void) assert(vector_is_empty(me)); assert(vector_remove_first(me) == -EINVAL); assert(vector_remove_last(me) == -EINVAL); - me = vector_destroy(me); - assert(!me); - test_vector_dynamic(); - test_vector_of_vectors(); +} + +static void test_basic(void) +{ + vector me = vector_init(sizeof(int)); + assert(me); + assert(vector_size(me) == 0); + assert(vector_is_empty(me)); + test_adding(me); + test_trim(me); + test_linear_operations(me); + test_invalid_operations(me); + assert(!vector_destroy(me)); +} + +static void test_vector_of_vectors(void) +{ + /* Test using a vector of vectors of ints. */ + vector outer = vector_init(sizeof(vector)); + /* Add vectors to the outer vector. */ + int i; + int j; + for (i = 0; i < 5; i++) { + vector inner = vector_init(sizeof(int)); + for (j = 1; j <= 10; j++) { + vector_add_last(inner, &j); + } + assert(vector_size(inner) == 10); + vector_add_last(outer, &inner); + } + assert(vector_size(outer) == 5); + /* Delete the vectors in the outer vector. */ + for (i = 0; i < 5; i++) { + vector inner = NULL; + vector_get_first(&inner, outer); + for (j = 0; j < 10; j++) { + int num = 0xdeadbeef; + vector_get_at(&num, inner, j); + assert(num == j + 1); + } + vector_remove_first(outer); + vector_destroy(inner); + } + assert(vector_is_empty(outer)); + vector_destroy(outer); +} + +static void test_dynamic(void) +{ + char **str = malloc(5 * sizeof(char **)); + int i; + int j; + vector str_vector; + for (i = 0; i < 5; i++) { + str[i] = malloc(10 * sizeof(char *)); + for (j = 0; j < 9; j++) { + str[i][j] = (char) ('a' + i); + } + str[i][9] = '\0'; + } + str_vector = vector_init(sizeof(char *)); + assert(str_vector); + for (i = 0; i < 5; i++) { + vector_add_last(str_vector, &str[i]); + } + assert(vector_size(str_vector) == 5); + for (i = 0; i < 5; i++) { + char *retrieve = NULL; + vector_get_first(&retrieve, str_vector); + vector_remove_first(str_vector); + assert(strcmp(retrieve, str[i]) == 0); + free(retrieve); + } + free(str); + assert(vector_size(str_vector) == 0); + assert(!vector_destroy(str_vector)); +} + +static void test_init_out_of_memory(void) +{ + fail_malloc = 1; + assert(!vector_init(sizeof(int))); + fail_malloc = 1; + delay_fail_malloc = 1; + assert(!vector_init(sizeof(int))); +} + +static void test_set_space_out_of_memory(void) +{ + vector me = vector_init(sizeof(int)); + int i; + for (i = 0; i < 7; i++) { + assert(vector_add_last(me, &i) == 0); + } + fail_realloc = 1; + assert(vector_reserve(me, 9) == -ENOMEM); + assert(vector_size(me) == 7); + assert(vector_capacity(me) == 8); + for (i = 0; i < 7; i++) { + int get = 0xdeadbeef; + vector_get_at(&get, me, i); + assert(get == i); + } + assert(!vector_destroy(me)); +} + +static void test_add_out_of_memory(void) +{ + vector me = vector_init(sizeof(int)); + int i; + for (i = 0; i < 7; i++) { + assert(vector_add_last(me, &i) == 0); + } + i++; + fail_realloc = 1; + assert(vector_add_last(me, &i) == -ENOMEM); + assert(vector_size(me) == 7); + assert(vector_capacity(me) == 8); + for (i = 0; i < 7; i++) { + int get = 0xdeadbeef; + vector_get_at(&get, me, i); + assert(get == i); + } + assert(!vector_destroy(me)); +} + +void test_vector(void) +{ + test_invalid_init(); + test_basic(); + test_vector_of_vectors(); + test_dynamic(); + test_init_out_of_memory(); + test_set_space_out_of_memory(); + test_add_out_of_memory(); }