/* * Copyright 2024 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "util/list.h" #include #include #include #include "clar.h" #include "stubs_passert.h" // Stubs /////////////////////////////////////////////////////////// int g_pbl_log_level = 0; void pbl_log(int level, const char* src_filename, int src_line_number, const char* fmt, ...) { } // Tests /////////////////////////////////////////////////////////// void test_list__initialize(void) { } void test_list__cleanup(void) { } void test_list__insert_after(void) { ListNode *tail = NULL; ListNode a = LIST_NODE_NULL, b = LIST_NODE_NULL; tail = list_insert_after(tail, &a); cl_assert(tail == &a); tail = list_insert_after(&a, &b); cl_assert(tail == &b); } void test_list__insert_before(void) { ListNode *head = NULL; ListNode a = LIST_NODE_NULL, b = LIST_NODE_NULL; head = list_insert_before(head, &a); cl_assert(head == &a); head = list_insert_before(&b, &a); cl_assert(head == &a); } void test_list__pop_head(void) { ListNode a = LIST_NODE_NULL, b = LIST_NODE_NULL; list_insert_after(&a, &b); ListNode *new_head = list_pop_head(&b); cl_assert(new_head == &b); cl_assert(list_get_next(&a) == NULL); cl_assert(list_get_head(&b) == &b); } void test_list__pop_tail(void) { ListNode a = LIST_NODE_NULL, b = LIST_NODE_NULL; list_insert_after(&a, &b); ListNode *new_tail = list_pop_tail(&a); cl_assert(new_tail == &a); cl_assert(list_get_prev(&b) == NULL); cl_assert(list_get_tail(&b) == &b); } void test_list__append(void) { ListNode a = LIST_NODE_NULL, b = LIST_NODE_NULL, c = LIST_NODE_NULL; ListNode *tail; tail = list_append(&a, &b); cl_assert(tail == &b); tail = list_append(&a, &c); cl_assert(tail == &c); cl_assert(list_get_prev(&a) == NULL); cl_assert(list_get_next(&a) == &b); cl_assert(list_get_prev(&b) == &a); cl_assert(list_get_next(&b) == &c); cl_assert(list_get_prev(&c) == &b); cl_assert(list_get_next(&c) == NULL); } void test_list__prepend(void) { ListNode a = LIST_NODE_NULL, b = LIST_NODE_NULL, c = LIST_NODE_NULL; ListNode *head; head = list_prepend(&c, &b); cl_assert(head == &b); head = list_prepend(&b, &a); cl_assert(head == &a); cl_assert(list_get_prev(&a) == NULL); cl_assert(list_get_next(&a) == &b); cl_assert(list_get_prev(&b) == &a); cl_assert(list_get_next(&b) == &c); cl_assert(list_get_prev(&c) == &b); cl_assert(list_get_next(&c) == NULL); } void test_list__count(void) { ListNode a = LIST_NODE_NULL, b = LIST_NODE_NULL, c = LIST_NODE_NULL; ListNode *tail = list_append(list_append(&a, &b), &c); cl_assert(list_count(tail) == 3); cl_assert(list_count(&a) == 3); cl_assert(list_count(&b) == 3); cl_assert(list_count(&c) == 3); cl_assert(list_count_to_tail_from(&a) == 3); cl_assert(list_count_to_tail_from(&b) == 2); cl_assert(list_count_to_tail_from(&c) == 1); cl_assert(list_count_to_head_from(&c) == 3); cl_assert(list_count_to_head_from(&b) == 2); cl_assert(list_count_to_head_from(&a) == 1); } typedef struct IntNode { ListNode list_node; int value; } IntNode; int sorting_comparator(IntNode* a, IntNode* b) { return b->value - a->value; } void test_list__sort_ascending(void) { IntNode bar1 = { .value = 1 }; IntNode bar2 = { .value = 2 }; IntNode bar3 = { .value = 3 }; ListNode* head = 0; head = list_sorted_add(head, &bar2.list_node, (Comparator) sorting_comparator, true); cl_assert(head == &bar2.list_node); head = list_sorted_add(head, &bar3.list_node, (Comparator) sorting_comparator, true); cl_assert(head == &bar2.list_node); cl_assert(list_get_tail(head) == &bar3.list_node); head = list_sorted_add(head, &bar1.list_node, (Comparator) sorting_comparator, true); cl_assert(head == &bar1.list_node); cl_assert(list_get_next(head) == &bar2.list_node); cl_assert(list_get_tail(head) == &bar3.list_node); } void test_list__sort_descending(void) { IntNode bar1 = { .value = 1 }; IntNode bar2 = { .value = 2 }; IntNode bar3 = { .value = 3 }; ListNode* head = 0; head = list_sorted_add(head, &bar2.list_node, (Comparator) sorting_comparator, false); cl_assert(head == &bar2.list_node); head = list_sorted_add(head, &bar3.list_node, (Comparator) sorting_comparator, false); cl_assert(head == &bar3.list_node); cl_assert(list_get_tail(head) == &bar2.list_node); head = list_sorted_add(head, &bar1.list_node, (Comparator) sorting_comparator, false); cl_assert(head == &bar3.list_node); cl_assert(list_get_next(head) == &bar2.list_node); cl_assert(list_get_tail(head) == &bar1.list_node); } static bool is_odd(IntNode *node, void *data) { return (node->value & 1); (void)data; } static bool is_even(IntNode *node, void *data) { return ((node->value & 1) == 0); (void)data; } void test_list__find_next_and_prev(void) { IntNode bar[5] = {0}; ListNode* tail = NULL; for (int i = 0; i < 5; ++i) { bar[i].value = i; tail = list_append(tail, &bar[i].list_node); } bool(*filter_odd)(ListNode*, void *) = (bool(*)(ListNode*, void *)) is_odd; bool(*filter_even)(ListNode*, void *) = (bool(*)(ListNode*, void *)) is_even; // Find next odd one after '2': cl_assert(list_find_next(&bar[2].list_node, filter_odd, false, NULL) == &bar[3].list_node); // 5 is the last odd number, so NULL is next: cl_assert(list_find_next(&bar[4].list_node, filter_odd, false, NULL) == NULL); // Test wrap around, find '1' after '4': cl_assert(list_find_next(&bar[4].list_node, filter_odd, true, NULL) == &bar[1].list_node); // Test wrap around matching first item, find '0' after '4': cl_assert(list_find_next(&bar[4].list_node, filter_even, true, NULL) == &bar[0].list_node); // Find prev odd one before '2': cl_assert(list_find_prev(&bar[2].list_node, filter_odd, false, NULL) == &bar[1].list_node); // '1' is the first odd number, so NULL is prev: cl_assert(list_find_prev(&bar[1].list_node, filter_odd, false, NULL) == NULL); // Test wrap around, find '3' before '0': cl_assert(list_find_prev(&bar[0].list_node, filter_odd, true, NULL) == &bar[3].list_node); // Test wrap around matching last item, find '4' before '0': cl_assert(list_find_prev(&bar[0].list_node, filter_even, true, NULL) == &bar[4].list_node); // Make everything even: for (int i = 0; i < 5; ++i) { bar[i].value = i * 2; } // Wrap around once, find nothing and return NULL: cl_assert(list_find_next(&bar[3].list_node, (bool(*)(ListNode*, void*))is_odd, true, NULL) == NULL); cl_assert(list_find_prev(&bar[3].list_node, (bool(*)(ListNode*, void*))is_odd, true, NULL) == NULL); // Test NULL starting node: cl_assert(list_find_next(NULL, filter_odd, false, NULL) == NULL); cl_assert(list_find_prev(NULL, filter_odd, false, NULL) == NULL); } void test_list__concatenate(void) { ListNode a = LIST_NODE_NULL, b = LIST_NODE_NULL, c = LIST_NODE_NULL; ListNode d = LIST_NODE_NULL, e = LIST_NODE_NULL, f = LIST_NODE_NULL; cl_assert_equal_p(list_concatenate(&a, &b), &a); cl_assert_equal_p(a.next, &b); cl_assert_equal_p(b.prev, &a); cl_assert_equal_p(list_concatenate(&b, &c), &a); cl_assert_equal_p(b.next, &c); cl_assert_equal_p(c.prev, &b); cl_assert_equal_p(list_concatenate(&e, &f), &e); cl_assert_equal_p(list_concatenate(&d, &f), &d); cl_assert_equal_p(list_concatenate(&f, &d), &d); cl_assert_equal_p(list_concatenate(NULL, &d), &d); cl_assert_equal_p(list_concatenate(NULL, &f), &d); cl_assert_equal_p(list_concatenate(&f, NULL), &d); cl_assert_equal_p(list_concatenate(&d, NULL), &d); cl_assert_equal_p(list_concatenate(&a, &d), &a); cl_assert_equal_p(list_get_head(&e), &a); cl_assert_equal_p(list_get_tail(&b), &f); c.next = NULL; d.prev = NULL; cl_assert_equal_p(list_concatenate(&c, &f), &a); cl_assert_equal_p(list_get_head(&e), &a); cl_assert_equal_p(list_get_tail(&b), &f); } #define CTX_VALUE 0xdeadbeef #define INT_VALUE 17 static bool prv_list_set_val_each(ListNode *node, void *context) { IntNode *int_node = (IntNode *)node; int_node->value = INT_VALUE; cl_assert_equal_i(CTX_VALUE, (uintptr_t) context); return true; } void test_list__each(void) { IntNode a = {}, b = {}, c = {}; ListNode *head; head = list_prepend((ListNode *)&c, (ListNode *)&b); head = list_prepend((ListNode *)&b, (ListNode *)&a); cl_assert_equal_i(list_count((ListNode *)head), 3); list_foreach(head, prv_list_set_val_each, (void *)(uintptr_t)CTX_VALUE); uint32_t num_nodes = 0; ListNode *temp = head; while (temp) { ListNode *next = temp->next; IntNode *int_node = (IntNode *)temp; cl_assert_equal_i(int_node->value, INT_VALUE); temp = next; num_nodes++; } cl_assert_equal_i(num_nodes, 3); }