--- a/tests/test_list.c Fri Oct 10 12:26:43 2025 +0200 +++ b/tests/test_list.c Fri Oct 10 17:24:19 2025 +0200 @@ -171,9 +171,11 @@ int d6a[6] = {52, 54, 56, 62, 64, 75}; int d7a[6] = {51, 57, 58, 65, 77, 78}; int d8 = 90; - int expected[18] = { - 40, 50, 51, 52, 54, 56, 57, 58, 60, - 62, 64, 65, 70, 75, 77, 78, 80, 90 + int d9 = 56; + int d10a[3] = {67, 75, 90}; + int expected[22] = { + 40, 50, 51, 52, 54, 56, 56, 57, 58, 60, + 62, 64, 65, 67, 70, 75, 75, 77, 78, 80, 90, 90 }; CX_ARRAY_DECLARE(int, array); @@ -204,8 +206,70 @@ CX_TEST_ASSERT(0 == cx_array_simple_add_sorted(array, d8, cx_cmp_int)); CX_TEST_ASSERT(array_size == 18); CX_TEST_ASSERT(array_capacity >= 18); + CX_TEST_ASSERT(0 == cx_array_simple_add_sorted(array, d9, cx_cmp_int)); + CX_TEST_ASSERT(array_size == 19); + CX_TEST_ASSERT(array_capacity >= 19); + CX_TEST_ASSERT(0 == cx_array_simple_insert_sorted(array, d10a, 3, cx_cmp_int)); + CX_TEST_ASSERT(array_size == 22); + CX_TEST_ASSERT(array_capacity >= 22); - CX_TEST_ASSERT(0 == memcmp(array, expected, 18 * sizeof(int))); + CX_TEST_ASSERT(0 == memcmp(array, expected, 22 * sizeof(int))); + } + cxFreeDefault(array); +} + +CX_TEST(test_array_insert_unique) { + int d1 = 50; + int d2 = 80; + int d3 = 60; + int d4 = 40; + int d5 = 70; + int d6a[6] = {52, 54, 56, 62, 64, 75}; + int d7a[6] = {51, 57, 58, 65, 77, 78}; + int d8 = 90; + int d9 = 56; + int d10a[3] = {67, 75, 90}; + int expected[19] = { + 40, 50, 51, 52, 54, 56, 57, 58, 60, + 62, 64, 65, 67, 70, 75, 77, 78, 80, 90 + }; + + CX_ARRAY_DECLARE(int, array); + cx_array_initialize(array, 4); + + CX_TEST_DO { + CX_TEST_ASSERT(0 == cx_array_simple_add_unique(array, d1, cx_cmp_int)); + CX_TEST_ASSERT(array_size == 1); + CX_TEST_ASSERT(array_capacity == 4); + CX_TEST_ASSERT(0 == cx_array_simple_add_unique(array, d2, cx_cmp_int)); + CX_TEST_ASSERT(array_size == 2); + CX_TEST_ASSERT(array_capacity == 4); + CX_TEST_ASSERT(0 == cx_array_simple_add_unique(array, d3, cx_cmp_int)); + CX_TEST_ASSERT(array_size == 3); + CX_TEST_ASSERT(array_capacity == 4); + CX_TEST_ASSERT(0 == cx_array_simple_add_unique(array, d4, cx_cmp_int)); + CX_TEST_ASSERT(array_size == 4); + CX_TEST_ASSERT(array_capacity == 4); + CX_TEST_ASSERT(0 == cx_array_simple_add_unique(array, d5, cx_cmp_int)); + CX_TEST_ASSERT(array_size == 5); + CX_TEST_ASSERT(array_capacity >= 5); + CX_TEST_ASSERT(0 == cx_array_simple_insert_unique(array, d6a, 6, cx_cmp_int)); + CX_TEST_ASSERT(array_size == 11); + CX_TEST_ASSERT(array_capacity >= 11); + CX_TEST_ASSERT(0 == cx_array_simple_insert_unique(array, d7a, 6, cx_cmp_int)); + CX_TEST_ASSERT(array_size == 17); + CX_TEST_ASSERT(array_capacity >= 17); + CX_TEST_ASSERT(0 == cx_array_simple_add_unique(array, d8, cx_cmp_int)); + CX_TEST_ASSERT(array_size == 18); + CX_TEST_ASSERT(array_capacity >= 18); + CX_TEST_ASSERT(0 == cx_array_simple_add_unique(array, d9, cx_cmp_int)); + CX_TEST_ASSERT(array_size == 18); + CX_TEST_ASSERT(array_capacity >= 18); + CX_TEST_ASSERT(0 == cx_array_simple_insert_unique(array, d10a, 3, cx_cmp_int)); + CX_TEST_ASSERT(array_size == 19); + CX_TEST_ASSERT(array_capacity >= 19); + + CX_TEST_ASSERT(0 == memcmp(array, expected, 19 * sizeof(int))); } cxFreeDefault(array); } @@ -737,6 +801,121 @@ } } +CX_TEST(test_linked_list_insert_unique) { + node nodes[5] = {0}; + void *begin, *end; + nodes[0].data = 3; + nodes[1].data = 6; + nodes[2].data = 10; + nodes[3].data = 11; + nodes[4].data = 15; + for (unsigned i = 0 ; i < 4 ; i++) { + cx_linked_list_link(&nodes[i], &nodes[i+1], loc_prev, loc_next); + } + begin = &nodes[0]; + end = &nodes[4]; + CX_TEST_DO { + // insert a single node + node new_node = {0}; + new_node.data = 5; + CX_TEST_ASSERT(0 == cx_linked_list_insert_unique( + &begin, &end, + loc_prev, loc_next, + &new_node, test_cmp_node + )); + CX_TEST_ASSERT(new_node.prev == &nodes[0]); + CX_TEST_ASSERT(new_node.next == &nodes[1]); + CX_TEST_ASSERT(nodes[0].next == &new_node); + CX_TEST_ASSERT(nodes[1].prev == &new_node); + CX_TEST_ASSERT(begin == &nodes[0]); + CX_TEST_ASSERT(end == &nodes[4]); + + // now as duplicate + node new_node_dup = {0}; + new_node_dup.data = 5; + CX_TEST_ASSERT(0 != cx_linked_list_insert_unique( + &begin, &end, + loc_prev, loc_next, + &new_node_dup, test_cmp_node + )); + CX_TEST_ASSERT(new_node_dup.prev == NULL); + CX_TEST_ASSERT(new_node_dup.next == NULL); + CX_TEST_ASSERT(new_node.prev == &nodes[0]); + CX_TEST_ASSERT(new_node.next == &nodes[1]); + CX_TEST_ASSERT(nodes[0].next == &new_node); + CX_TEST_ASSERT(nodes[1].prev == &new_node); + CX_TEST_ASSERT(begin == &nodes[0]); + CX_TEST_ASSERT(end == &nodes[4]); + + // insert a new beginning node + node new_begin = {0}; + new_begin.data = 1; + CX_TEST_ASSERT(0 == cx_linked_list_insert_unique( + &begin, &end, + loc_prev, loc_next, + &new_begin, test_cmp_node + )); + CX_TEST_ASSERT(new_begin.prev == NULL); + CX_TEST_ASSERT(new_begin.next == &nodes[0]); + CX_TEST_ASSERT(nodes[0].prev == &new_begin); + CX_TEST_ASSERT(begin == &new_begin); + CX_TEST_ASSERT(end == &nodes[4]); + + // now as duplicate + node new_begin_dup = {0}; + new_begin_dup.data = 1; + CX_TEST_ASSERT(0 != cx_linked_list_insert_unique( + &begin, &end, + loc_prev, loc_next, + &new_begin_dup, test_cmp_node + )); + CX_TEST_ASSERT(new_begin_dup.prev == NULL); + CX_TEST_ASSERT(new_begin_dup.next == NULL); + CX_TEST_ASSERT(new_begin.prev == NULL); + CX_TEST_ASSERT(new_begin.next == &nodes[0]); + CX_TEST_ASSERT(nodes[0].prev == &new_begin); + CX_TEST_ASSERT(begin == &new_begin); + CX_TEST_ASSERT(end == &nodes[4]); + + // now insert a chain with two duplicates + node chain_start = {NULL, NULL, 8}; + node chain_mid1 = {NULL, NULL, 11}; + node chain_mid2 = {NULL, NULL, 14}; + node chain_mid3 = {NULL, NULL, 15}; + node chain_mid4 = {NULL, NULL, 15}; + node chain_end = {NULL, NULL, 17}; + cx_linked_list_link(&chain_start, &chain_mid1, loc_prev, loc_next); + cx_linked_list_link(&chain_mid1, &chain_mid2, loc_prev, loc_next); + cx_linked_list_link(&chain_mid2, &chain_mid3, loc_prev, loc_next); + cx_linked_list_link(&chain_mid3, &chain_mid4, loc_prev, loc_next); + cx_linked_list_link(&chain_mid4, &chain_end, loc_prev, loc_next); + + node *dup_start = cx_linked_list_insert_unique_chain( + &begin, &end, + loc_prev, loc_next, + &chain_start, test_cmp_node + ); + + CX_TEST_ASSERT(chain_start.prev == &nodes[1]); + CX_TEST_ASSERT(chain_start.next == &nodes[2]); + CX_TEST_ASSERT(chain_mid2.prev == &nodes[3]); + CX_TEST_ASSERT(chain_mid2.next == &nodes[4]); + CX_TEST_ASSERT(chain_end.prev == &nodes[4]); + CX_TEST_ASSERT(chain_end.next == NULL); + CX_TEST_ASSERT(begin == &new_begin); + CX_TEST_ASSERT(end == &chain_end); + + // the duplicates + CX_TEST_ASSERT(dup_start == &chain_mid1); + CX_TEST_ASSERT(dup_start->prev == NULL); + CX_TEST_ASSERT(dup_start->next == &chain_mid3); + CX_TEST_ASSERT(chain_mid3.prev == &chain_mid1); + CX_TEST_ASSERT(chain_mid3.next == &chain_mid4); + CX_TEST_ASSERT(chain_mid4.prev == &chain_mid3); + CX_TEST_ASSERT(chain_mid4.next == NULL); + } +} + CX_TEST(test_linked_list_first) { node *testdata = create_nodes_test_data(3); void *begin = testdata; @@ -1299,6 +1478,7 @@ const cx_list_class *cl = list->climpl == NULL ? list->cl : list->climpl; memcpy(defaulted_cl, cl, sizeof(cx_list_class)); defaulted_cl->insert_array = cx_list_default_insert_array; + defaulted_cl->insert_unique = cx_list_default_insert_unique; defaulted_cl->insert_sorted = cx_list_default_insert_sorted; defaulted_cl->sort = cx_list_default_sort; defaulted_cl->swap = cx_list_default_swap; @@ -1513,16 +1693,22 @@ int d6a[6] = array_init(52, 54, 56, 62, 64, 75); int d7a[6] = array_init(51, 57, 58, 65, 77, 78); int d8 = 90; + int d9 = 56; + int d10a[3] = array_init(67, 75, 90); int *d6ptr[6]; int *d7ptr[6]; + int *d10ptr[3]; for (size_t i = 0; i < 6; i++) { d6ptr[i] = &d6a[i]; d7ptr[i] = &d7a[i]; } + for (size_t i = 0 ; i < 3 ; i++) { + d10ptr[i] = &d10a[i]; + } size_t inserted; - int expected[18] = array_init( - 40, 50, 51, 52, 54, 56, 57, 58, 60, - 62, 64, 65, 70, 75, 77, 78, 80, 90 + int expected[22] = array_init( + 40, 50, 51, 52, 54, 56, 56, 57, 58, 60, + 62, 64, 65, 67, 70, 75, 75, 77, 78, 80, 90, 90 ); CX_TEST_ASSERT(0 == cxListInsertSorted(list, &d1)); @@ -1543,9 +1729,73 @@ } CX_TEST_ASSERT(inserted == 6); CX_TEST_ASSERT(0 == cxListInsertSorted(list, &d8)); + CX_TEST_ASSERT(0 == cxListInsertSorted(list, &d9)); + if (isptrlist) { + inserted = cxListInsertSortedArray(list, d10ptr, 3); + } else { + inserted = cxListInsertSortedArray(list, d10a, 3); + } + CX_TEST_ASSERT(inserted == 3); + CX_TEST_ASSERT(cxListSize(list) == 22); + for (size_t i = 0; i < 22; i++) { + CX_TEST_ASSERT(*(int *) cxListAt(list, i) == expected[i]); + } +}) - CX_TEST_ASSERT(cxListSize(list) == 18); - for (size_t i = 0; i < 18; i++) { +roll_out_test_combos_with_defaulted_funcs(insert_unique, { + int d1 = 50; + int d2 = 80; + int d3 = 60; + int d4 = 40; + int d5 = 70; + int d6a[6] = array_init(52, 54, 56, 62, 64, 75); + int d7a[6] = array_init(51, 57, 58, 65, 77, 78); + int d8 = 90; + int d9 = 56; + int d10a[3] = array_init(67, 75, 90); + int *d6ptr[6]; + int *d7ptr[6]; + int *d10ptr[3]; + for (size_t i = 0; i < 6; i++) { + d6ptr[i] = &d6a[i]; + d7ptr[i] = &d7a[i]; + } + for (size_t i = 0 ; i < 3 ; i++) { + d10ptr[i] = &d10a[i]; + } + size_t inserted; + int expected[19] = array_init( + 40, 50, 51, 52, 54, 56, 57, 58, 60, + 62, 64, 65, 67, 70, 75, 77, 78, 80, 90 + ); + + CX_TEST_ASSERT(0 == cxListInsertUnique(list, &d1)); + CX_TEST_ASSERT(0 == cxListInsertUnique(list, &d2)); + CX_TEST_ASSERT(0 == cxListInsertUnique(list, &d3)); + CX_TEST_ASSERT(0 == cxListInsertUnique(list, &d4)); + CX_TEST_ASSERT(0 == cxListInsertUnique(list, &d5)); + if (isptrlist) { + inserted = cxListInsertUniqueArray(list, d6ptr, 6); + } else { + inserted = cxListInsertUniqueArray(list, d6a, 6); + } + CX_TEST_ASSERT(inserted == 6); + if (isptrlist) { + inserted = cxListInsertUniqueArray(list, d7ptr, 6); + } else { + inserted = cxListInsertUniqueArray(list, d7a, 6); + } + CX_TEST_ASSERT(inserted == 6); + CX_TEST_ASSERT(0 == cxListInsertUnique(list, &d8)); + CX_TEST_ASSERT(0 == cxListInsertUnique(list, &d9)); + if (isptrlist) { + inserted = cxListInsertUniqueArray(list, d10ptr, 3); + } else { + inserted = cxListInsertUniqueArray(list, d10a, 3); + } + CX_TEST_ASSERT(inserted == 3); + CX_TEST_ASSERT(cxListSize(list) == 19); + for (size_t i = 0; i < 19; i++) { CX_TEST_ASSERT(*(int *) cxListAt(list, i) == expected[i]); } }) @@ -2173,6 +2423,7 @@ cx_test_register(suite, test_array_copy_unsupported_width); cx_test_register(suite, test_array_reserve); cx_test_register(suite, test_array_insert_sorted); + cx_test_register(suite, test_array_insert_unique); cx_test_register(suite, test_array_binary_search); cx_test_register(suite, test_list_arl_create); @@ -2192,6 +2443,8 @@ cx_test_register(suite, test_list_parl_insert_array); cx_test_register(suite, test_list_arl_insert_sorted); cx_test_register(suite, test_list_parl_insert_sorted); + cx_test_register(suite, test_list_arl_insert_unique); + cx_test_register(suite, test_list_parl_insert_unique); cx_test_register(suite, test_list_arl_remove); cx_test_register(suite, test_list_parl_remove); cx_test_register(suite, test_list_arl_remove_and_get); @@ -2247,6 +2500,8 @@ cx_test_register(suite, test_list_parlm_insert_array); cx_test_register(suite, test_list_arlm_insert_sorted); cx_test_register(suite, test_list_parlm_insert_sorted); + cx_test_register(suite, test_list_arlm_insert_unique); + cx_test_register(suite, test_list_parlm_insert_unique); cx_test_register(suite, test_list_arlm_swap); cx_test_register(suite, test_list_parlm_swap); cx_test_register(suite, test_list_arlm_sort); @@ -2272,6 +2527,7 @@ cx_test_register(suite, test_linked_list_insert); cx_test_register(suite, test_linked_list_insert_chain); cx_test_register(suite, test_linked_list_insert_sorted); + cx_test_register(suite, test_linked_list_insert_unique); cx_test_register(suite, test_linked_list_first); cx_test_register(suite, test_linked_list_last); cx_test_register(suite, test_linked_list_prev); @@ -2299,6 +2555,8 @@ cx_test_register(suite, test_list_pll_insert_array); cx_test_register(suite, test_list_ll_insert_sorted); cx_test_register(suite, test_list_pll_insert_sorted); + cx_test_register(suite, test_list_ll_insert_unique); + cx_test_register(suite, test_list_pll_insert_unique); cx_test_register(suite, test_list_ll_remove); cx_test_register(suite, test_list_pll_remove); cx_test_register(suite, test_list_ll_remove_and_get); @@ -2353,6 +2611,8 @@ cx_test_register(suite, test_list_pllm_insert_array); cx_test_register(suite, test_list_llm_insert_sorted); cx_test_register(suite, test_list_pllm_insert_sorted); + cx_test_register(suite, test_list_llm_insert_unique); + cx_test_register(suite, test_list_pllm_insert_unique); cx_test_register(suite, test_list_llm_swap); cx_test_register(suite, test_list_pllm_swap); cx_test_register(suite, test_list_llm_sort); @@ -2379,6 +2639,8 @@ cx_test_register(suite, test_list_pkvl_insert_array); cx_test_register(suite, test_list_kvl_insert_sorted); cx_test_register(suite, test_list_pkvl_insert_sorted); + cx_test_register(suite, test_list_kvl_insert_unique); + cx_test_register(suite, test_list_pkvl_insert_unique); cx_test_register(suite, test_list_kvl_remove); cx_test_register(suite, test_list_pkvl_remove); cx_test_register(suite, test_list_kvl_remove_and_get);