diff --git a/Makefile b/Makefile index 23ef4d06..7644e410 100644 --- a/Makefile +++ b/Makefile @@ -29,7 +29,7 @@ deps += $(LIB_OBJS:%.o=%.o.d) APPS := coop echo hello mqueues semaphore mutex cond \ pipes pipes_small pipes_struct prodcons progress \ rtsched suspend test64 timer timer_kill \ - cpubench test_libc + cpubench test_utils # Output files for __link target IMAGE_BASE := $(BUILD_DIR)/image diff --git a/app/test_libc.c b/app/test_utils.c similarity index 84% rename from app/test_libc.c rename to app/test_utils.c index bf8e34ca..8ae03e0e 100644 --- a/app/test_libc.c +++ b/app/test_utils.c @@ -1,4 +1,4 @@ -/* LibC Test Suite - Comprehensive tests for standard library functions. +/* Utility Test Suite - Comprehensive tests for utilities and helpers. * * Current Coverage: * - vsnprintf/snprintf: Buffer overflow protection @@ -6,6 +6,8 @@ * * Format specifiers: %s, %d, %u, %x, %p, %c, %% * * Edge cases: size=0, size=1, truncation, null termination * + * - list operations: pushback node, remove node + * * Future Tests (Planned): * - String functions: strlen, strcmp, strcpy, strncpy, memcpy, memset * - Memory allocation: malloc, free, realloc @@ -298,6 +300,51 @@ void test_mixed_formats(void) ASSERT_TEST(buf[test_strlen(buf)] == '\0', "Mixed format null termination"); } +/* Test 11: List node helpers behavior */ +void test_list_node_pushback_and_remove(void) +{ + list_node_t node1 = {0}; + list_node_t node2 = {0}; + + node1.next = &node2; /* make node1 artificially “linked” */ + list_t *list = list_create(); + + /* Check node push back normally - unlinked and linked */ + list_pushback_node(list, &node1); + ASSERT_TEST(list_is_empty(list), "Linked node pushback fail"); + + node1.next = NULL; + list_pushback_node(list, &node1); + ASSERT_TEST(list->length == 1, "Unlinked node pushback success "); + ASSERT_TEST(list->head->next == &node1 && node1.next == list->tail, + "List consistent after pushback first node "); + + /* Check node push back order */ + node2.next = NULL; + list_pushback_node(list, &node2); + ASSERT_TEST(list->length == 2 && list->head->next == &node1 && + node1.next == &node2 && node2.next == list->tail, + "Insertion order preserved "); + + /* Remove last node */ + list_remove_node(list, &node2); + ASSERT_TEST( + list->length == 1 && node2.next == NULL && node1.next == list->tail, + "Removing last node must keep list structure consistent"); + + /* Remove non-existing node (second time) */ + list_remove_node(list, &node2); + ASSERT_TEST( + list->length == 1 && node2.next == NULL && node1.next == list->tail, + "Removing non-existing node must not change the list"); + + /* Remove only node */ + list_remove_node(list, &node1); + ASSERT_TEST(list->length == 0 && list->head->next == list->tail, + "Removing only node "); + ASSERT_TEST(list_is_empty(list), "Empty list check "); +} + void test_runner(void) { printf("\n=== LibC Test Suite ===\n"); @@ -314,6 +361,10 @@ void test_runner(void) test_isr_safety(); test_mixed_formats(); + + printf("\n=== List Test Suite ===\n"); + test_list_node_pushback_and_remove(); + printf("\n=== Test Summary ===\n"); printf("Tests run: %d\n", tests_run); printf("Tests passed: %d\n", tests_passed); diff --git a/include/lib/list.h b/include/lib/list.h index 298e6c83..ce791a2b 100644 --- a/include/lib/list.h +++ b/include/lib/list.h @@ -100,6 +100,24 @@ static inline list_node_t *list_pushback(list_t *list, void *data) return node; } +/* Pushback list node into list */ +static inline void list_pushback_node(list_t *list, list_node_t *target) +{ + if (unlikely(!list || !target || target->next)) + return; + + target->next = list->tail; + + /* Insert before tail sentinel */ + list_node_t *prev = list->head; + while (prev->next != list->tail) + prev = prev->next; + + prev->next = target; + list->length++; + return; +} + static inline void *list_pop(list_t *list) { if (unlikely(list_is_empty(list))) @@ -134,6 +152,25 @@ static inline void *list_remove(list_t *list, list_node_t *target) return data; } +/* Remove a node from list without freeing */ +static inline void list_remove_node(list_t *list, list_node_t *target) +{ + if (unlikely(!list || !target || list_is_empty(list))) + return; + + list_node_t *prev = list->head; + while (prev->next != list->tail && prev->next != target) + prev = prev->next; + + if (unlikely(prev->next != target)) + return; /* node not found */ + + prev->next = target->next; + target->next = NULL; + list->length--; + return; +} + /* Iteration */ /* Callback should return non-NULL to stop early, NULL to continue */