| xf.li | 6c8fc1e | 2023-08-12 00:11:09 -0700 | [diff] [blame] | 1 | /*************************************************************************** | 
|  | 2 | *                                  _   _ ____  _ | 
|  | 3 | *  Project                     ___| | | |  _ \| | | 
|  | 4 | *                             / __| | | | |_) | | | 
|  | 5 | *                            | (__| |_| |  _ <| |___ | 
|  | 6 | *                             \___|\___/|_| \_\_____| | 
|  | 7 | * | 
|  | 8 | * Copyright (C) 1998 - 2022, Daniel Stenberg, <daniel@haxx.se>, et al. | 
|  | 9 | * | 
|  | 10 | * This software is licensed as described in the file COPYING, which | 
|  | 11 | * you should have received as part of this distribution. The terms | 
|  | 12 | * are also available at https://curl.se/docs/copyright.html. | 
|  | 13 | * | 
|  | 14 | * You may opt to use, copy, modify, merge, publish, distribute and/or sell | 
|  | 15 | * copies of the Software, and permit persons to whom the Software is | 
|  | 16 | * furnished to do so, under the terms of the COPYING file. | 
|  | 17 | * | 
|  | 18 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | 
|  | 19 | * KIND, either express or implied. | 
|  | 20 | * | 
|  | 21 | * SPDX-License-Identifier: curl | 
|  | 22 | * | 
|  | 23 | ***************************************************************************/ | 
|  | 24 | #include "curlcheck.h" | 
|  | 25 |  | 
|  | 26 | #include "llist.h" | 
|  | 27 |  | 
|  | 28 | static struct Curl_llist llist; | 
|  | 29 |  | 
|  | 30 | static struct Curl_llist llist_destination; | 
|  | 31 |  | 
|  | 32 | static void test_Curl_llist_dtor(void *key, void *value) | 
|  | 33 | { | 
|  | 34 | /* used by the llist API, does nothing here */ | 
|  | 35 | (void)key; | 
|  | 36 | (void)value; | 
|  | 37 | } | 
|  | 38 |  | 
|  | 39 | static CURLcode unit_setup(void) | 
|  | 40 | { | 
|  | 41 | Curl_llist_init(&llist, test_Curl_llist_dtor); | 
|  | 42 | Curl_llist_init(&llist_destination, test_Curl_llist_dtor); | 
|  | 43 | return CURLE_OK; | 
|  | 44 | } | 
|  | 45 |  | 
|  | 46 | static void unit_stop(void) | 
|  | 47 | { | 
|  | 48 | } | 
|  | 49 |  | 
|  | 50 | UNITTEST_START | 
|  | 51 | { | 
|  | 52 | int unusedData_case1 = 1; | 
|  | 53 | int unusedData_case2 = 2; | 
|  | 54 | int unusedData_case3 = 3; | 
|  | 55 | struct Curl_llist_element case1_list; | 
|  | 56 | struct Curl_llist_element case2_list; | 
|  | 57 | struct Curl_llist_element case3_list; | 
|  | 58 | struct Curl_llist_element case4_list; | 
|  | 59 | struct Curl_llist_element *head; | 
|  | 60 | struct Curl_llist_element *element_next; | 
|  | 61 | struct Curl_llist_element *element_prev; | 
|  | 62 | struct Curl_llist_element *to_remove; | 
|  | 63 | size_t llist_size = Curl_llist_count(&llist); | 
|  | 64 |  | 
|  | 65 | /** | 
|  | 66 | * testing llist_init | 
|  | 67 | * case 1: | 
|  | 68 | * list initiation | 
|  | 69 | * @assumptions: | 
|  | 70 | * 1: list size will be 0 | 
|  | 71 | * 2: list head will be NULL | 
|  | 72 | * 3: list tail will be NULL | 
|  | 73 | * 4: list dtor will be NULL | 
|  | 74 | */ | 
|  | 75 |  | 
|  | 76 | fail_unless(llist.size == 0, "list initial size should be zero"); | 
|  | 77 | fail_unless(llist.head == NULL, "list head should initiate to NULL"); | 
|  | 78 | fail_unless(llist.tail == NULL, "list tail should intiate to NULL"); | 
|  | 79 | fail_unless(llist.dtor == test_Curl_llist_dtor, | 
|  | 80 | "list dtor should initiate to test_Curl_llist_dtor"); | 
|  | 81 |  | 
|  | 82 | /** | 
|  | 83 | * testing Curl_llist_insert_next | 
|  | 84 | * case 1: | 
|  | 85 | * list is empty | 
|  | 86 | * @assumptions: | 
|  | 87 | * 1: list size will be 1 | 
|  | 88 | * 2: list head will hold the data "unusedData_case1" | 
|  | 89 | * 3: list tail will be the same as list head | 
|  | 90 | */ | 
|  | 91 |  | 
|  | 92 | Curl_llist_insert_next(&llist, llist.head, &unusedData_case1, &case1_list); | 
|  | 93 |  | 
|  | 94 | fail_unless(Curl_llist_count(&llist) == 1, | 
|  | 95 | "List size should be 1 after adding a new element"); | 
|  | 96 | /*test that the list head data holds my unusedData */ | 
|  | 97 | fail_unless(llist.head->ptr == &unusedData_case1, | 
|  | 98 | "head ptr should be first entry"); | 
|  | 99 | /*same goes for the list tail */ | 
|  | 100 | fail_unless(llist.tail == llist.head, | 
|  | 101 | "tail and head should be the same"); | 
|  | 102 |  | 
|  | 103 | /** | 
|  | 104 | * testing Curl_llist_insert_next | 
|  | 105 | * case 2: | 
|  | 106 | * list has 1 element, adding one element after the head | 
|  | 107 | * @assumptions: | 
|  | 108 | * 1: the element next to head should be our newly created element | 
|  | 109 | * 2: the list tail should be our newly created element | 
|  | 110 | */ | 
|  | 111 |  | 
|  | 112 | Curl_llist_insert_next(&llist, llist.head, | 
|  | 113 | &unusedData_case3, &case3_list); | 
|  | 114 | fail_unless(llist.head->next->ptr == &unusedData_case3, | 
|  | 115 | "the node next to head is not getting set correctly"); | 
|  | 116 | fail_unless(llist.tail->ptr == &unusedData_case3, | 
|  | 117 | "the list tail is not getting set correctly"); | 
|  | 118 |  | 
|  | 119 | /** | 
|  | 120 | * testing Curl_llist_insert_next | 
|  | 121 | * case 3: | 
|  | 122 | * list has >1 element, adding one element after "NULL" | 
|  | 123 | * @assumptions: | 
|  | 124 | * 1: the element next to head should be our newly created element | 
|  | 125 | * 2: the list tail should different from newly created element | 
|  | 126 | */ | 
|  | 127 |  | 
|  | 128 | Curl_llist_insert_next(&llist, llist.head, | 
|  | 129 | &unusedData_case2, &case2_list); | 
|  | 130 | fail_unless(llist.head->next->ptr == &unusedData_case2, | 
|  | 131 | "the node next to head is not getting set correctly"); | 
|  | 132 | /* better safe than sorry, check that the tail isn't corrupted */ | 
|  | 133 | fail_unless(llist.tail->ptr != &unusedData_case2, | 
|  | 134 | "the list tail is not getting set correctly"); | 
|  | 135 |  | 
|  | 136 | /* unit tests for Curl_llist_remove */ | 
|  | 137 |  | 
|  | 138 | /** | 
|  | 139 | * case 1: | 
|  | 140 | * list has >1 element, removing head | 
|  | 141 | * @assumptions: | 
|  | 142 | * 1: list size will be decremented by one | 
|  | 143 | * 2: head will be the head->next | 
|  | 144 | * 3: "new" head's previous will be NULL | 
|  | 145 | */ | 
|  | 146 |  | 
|  | 147 | head = llist.head; | 
|  | 148 | abort_unless(head, "llist.head is NULL"); | 
|  | 149 | element_next = head->next; | 
|  | 150 | llist_size = Curl_llist_count(&llist); | 
|  | 151 |  | 
|  | 152 | Curl_llist_remove(&llist, llist.head, NULL); | 
|  | 153 |  | 
|  | 154 | fail_unless(Curl_llist_count(&llist) ==  (llist_size-1), | 
|  | 155 | "llist size not decremented as expected"); | 
|  | 156 | fail_unless(llist.head == element_next, | 
|  | 157 | "llist new head not modified properly"); | 
|  | 158 | abort_unless(llist.head, "llist.head is NULL"); | 
|  | 159 | fail_unless(llist.head->prev == NULL, | 
|  | 160 | "new head previous not set to null"); | 
|  | 161 |  | 
|  | 162 | /** | 
|  | 163 | * case 2: | 
|  | 164 | * removing non head element, with list having >=2 elements | 
|  | 165 | * @setup: | 
|  | 166 | * 1: insert another element to the list to make element >=2 | 
|  | 167 | * @assumptions: | 
|  | 168 | * 1: list size will be decremented by one ; tested | 
|  | 169 | * 2: element->previous->next will be element->next | 
|  | 170 | * 3: element->next->previous will be element->previous | 
|  | 171 | */ | 
|  | 172 | Curl_llist_insert_next(&llist, llist.head, &unusedData_case3, | 
|  | 173 | &case4_list); | 
|  | 174 | llist_size = Curl_llist_count(&llist); | 
|  | 175 | fail_unless(llist_size == 3, "should be 3 list members"); | 
|  | 176 |  | 
|  | 177 | to_remove = llist.head->next; | 
|  | 178 | abort_unless(to_remove, "to_remove is NULL"); | 
|  | 179 | element_next = to_remove->next; | 
|  | 180 | element_prev = to_remove->prev; | 
|  | 181 | Curl_llist_remove(&llist, to_remove, NULL); | 
|  | 182 | fail_unless(element_prev->next == element_next, | 
|  | 183 | "element previous->next is not being adjusted"); | 
|  | 184 | abort_unless(element_next, "element_next is NULL"); | 
|  | 185 | fail_unless(element_next->prev == element_prev, | 
|  | 186 | "element next->previous is not being adjusted"); | 
|  | 187 |  | 
|  | 188 | /** | 
|  | 189 | * case 3: | 
|  | 190 | * removing the tail with list having >=1 element | 
|  | 191 | * @assumptions | 
|  | 192 | * 1: list size will be decremented by one ;tested | 
|  | 193 | * 2: element->previous->next will be element->next ;tested | 
|  | 194 | * 3: element->next->previous will be element->previous ;tested | 
|  | 195 | * 4: list->tail will be tail->previous | 
|  | 196 | */ | 
|  | 197 |  | 
|  | 198 | to_remove = llist.tail; | 
|  | 199 | element_prev = to_remove->prev; | 
|  | 200 | Curl_llist_remove(&llist, to_remove, NULL); | 
|  | 201 | fail_unless(llist.tail == element_prev, | 
|  | 202 | "llist tail is not being adjusted when removing tail"); | 
|  | 203 |  | 
|  | 204 | /** | 
|  | 205 | * case 4: | 
|  | 206 | * removing head with list having 1 element | 
|  | 207 | * @assumptions: | 
|  | 208 | * 1: list size will be decremented by one ;tested | 
|  | 209 | * 2: list head will be null | 
|  | 210 | * 3: list tail will be null | 
|  | 211 | */ | 
|  | 212 |  | 
|  | 213 | to_remove = llist.head; | 
|  | 214 | Curl_llist_remove(&llist, to_remove, NULL); | 
|  | 215 | fail_unless(llist.head == NULL, | 
|  | 216 | "llist head is not NULL while the llist is empty"); | 
|  | 217 | fail_unless(llist.tail == NULL, | 
|  | 218 | "llist tail is not NULL while the llist is empty"); | 
|  | 219 |  | 
|  | 220 | Curl_llist_destroy(&llist, NULL); | 
|  | 221 | Curl_llist_destroy(&llist_destination, NULL); | 
|  | 222 | } | 
|  | 223 | UNITTEST_STOP |