1 /***************************************************************************
2 * _ _ ____ _
3 * Project ___| | | | _ \| |
4 * / __| | | | |_) | |
5 * | (__| |_| | _ <| |___
6 * \___|\___/|_| \_\_____|
7 *
8 * Copyright (C) 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
test_Curl_llist_dtor(void * key,void * value)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
unit_setup(void)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
unit_stop(void)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_node case1_list;
56 struct Curl_llist_node case2_list;
57 struct Curl_llist_node case3_list;
58 struct Curl_llist_node case4_list;
59 struct Curl_llist_node *head;
60 struct Curl_llist_node *element_next;
61 struct Curl_llist_node *element_prev;
62 struct Curl_llist_node *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(Curl_llist_count(&llist) == 0,
77 "list initial size should be zero");
78 fail_unless(Curl_llist_head(&llist) == NULL,
79 "list head should initiate to NULL");
80 fail_unless(Curl_llist_tail(&llist) == NULL,
81 "list tail should initiate to NULL");
82
83 /**
84 * testing Curl_llist_insert_next
85 * case 1:
86 * list is empty
87 * @assumptions:
88 * 1: list size will be 1
89 * 2: list head will hold the data "unusedData_case1"
90 * 3: list tail will be the same as list head
91 */
92
93 Curl_llist_insert_next(&llist, Curl_llist_head(&llist), &unusedData_case1,
94 &case1_list);
95
96 fail_unless(Curl_llist_count(&llist) == 1,
97 "List size should be 1 after adding a new element");
98 /* test that the list head data holds my unusedData */
99 fail_unless(Curl_node_elem(Curl_llist_head(&llist)) == &unusedData_case1,
100 "head ptr should be first entry");
101 /* same goes for the list tail */
102 fail_unless(Curl_llist_tail(&llist) == Curl_llist_head(&llist),
103 "tail and head should be the same");
104
105 /**
106 * testing Curl_llist_insert_next
107 * case 2:
108 * list has 1 element, adding one element after the head
109 * @assumptions:
110 * 1: the element next to head should be our newly created element
111 * 2: the list tail should be our newly created element
112 */
113
114 Curl_llist_insert_next(&llist, Curl_llist_head(&llist),
115 &unusedData_case3, &case3_list);
116 fail_unless(Curl_node_elem(Curl_node_next(Curl_llist_head(&llist))) ==
117 &unusedData_case3,
118 "the node next to head is not getting set correctly");
119 fail_unless(Curl_node_elem(Curl_llist_tail(&llist)) == &unusedData_case3,
120 "the list tail is not getting set correctly");
121
122 /**
123 * testing Curl_llist_insert_next
124 * case 3:
125 * list has >1 element, adding one element after "NULL"
126 * @assumptions:
127 * 1: the element next to head should be our newly created element
128 * 2: the list tail should different from newly created element
129 */
130
131 Curl_llist_insert_next(&llist, Curl_llist_head(&llist),
132 &unusedData_case2, &case2_list);
133 fail_unless(Curl_node_elem(Curl_node_next(Curl_llist_head(&llist))) ==
134 &unusedData_case2,
135 "the node next to head is not getting set correctly");
136 /* better safe than sorry, check that the tail isn't corrupted */
137 fail_unless(Curl_node_elem(Curl_llist_tail(&llist)) != &unusedData_case2,
138 "the list tail is not getting set correctly");
139
140 /* unit tests for Curl_node_remove */
141
142 /**
143 * case 1:
144 * list has >1 element, removing head
145 * @assumptions:
146 * 1: list size will be decremented by one
147 * 2: head will be the head->next
148 * 3: "new" head's previous will be NULL
149 */
150
151 head = Curl_llist_head(&llist);
152 abort_unless(head, "llist.head is NULL");
153 element_next = Curl_node_next(head);
154 llist_size = Curl_llist_count(&llist);
155
156 Curl_node_remove(Curl_llist_head(&llist));
157
158 fail_unless(Curl_llist_count(&llist) == (llist_size-1),
159 "llist size not decremented as expected");
160 fail_unless(Curl_llist_head(&llist) == element_next,
161 "llist new head not modified properly");
162 abort_unless(Curl_llist_head(&llist), "llist.head is NULL");
163 fail_unless(Curl_node_prev(Curl_llist_head(&llist)) == NULL,
164 "new head previous not set to null");
165
166 /**
167 * case 2:
168 * removing non head element, with list having >=2 elements
169 * @setup:
170 * 1: insert another element to the list to make element >=2
171 * @assumptions:
172 * 1: list size will be decremented by one ; tested
173 * 2: element->previous->next will be element->next
174 * 3: element->next->previous will be element->previous
175 */
176 Curl_llist_insert_next(&llist, Curl_llist_head(&llist), &unusedData_case3,
177 &case4_list);
178 llist_size = Curl_llist_count(&llist);
179 fail_unless(llist_size == 3, "should be 3 list members");
180
181 to_remove = Curl_node_next(Curl_llist_head(&llist));
182 abort_unless(to_remove, "to_remove is NULL");
183 element_next = Curl_node_next(to_remove);
184 element_prev = Curl_node_prev(to_remove);
185 Curl_node_uremove(to_remove, NULL);
186 fail_unless(Curl_node_next(element_prev) == element_next,
187 "element previous->next is not being adjusted");
188 abort_unless(element_next, "element_next is NULL");
189 fail_unless(Curl_node_prev(element_next) == element_prev,
190 "element next->previous is not being adjusted");
191
192 /**
193 * case 3:
194 * removing the tail with list having >=1 element
195 * @assumptions
196 * 1: list size will be decremented by one ;tested
197 * 2: element->previous->next will be element->next ;tested
198 * 3: element->next->previous will be element->previous ;tested
199 * 4: list->tail will be tail->previous
200 */
201
202 to_remove = Curl_llist_tail(&llist);
203 element_prev = Curl_node_prev(to_remove);
204 Curl_node_remove(to_remove);
205 fail_unless(Curl_llist_tail(&llist) == element_prev,
206 "llist tail is not being adjusted when removing tail");
207
208 /**
209 * case 4:
210 * removing head with list having 1 element
211 * @assumptions:
212 * 1: list size will be decremented by one ;tested
213 * 2: list head will be null
214 * 3: list tail will be null
215 */
216
217 to_remove = Curl_llist_head(&llist);
218 Curl_node_remove(to_remove);
219 fail_unless(Curl_llist_head(&llist) == NULL,
220 "llist head is not NULL while the llist is empty");
221 fail_unless(Curl_llist_tail(&llist) == NULL,
222 "llist tail is not NULL while the llist is empty");
223
224 /**
225 * testing Curl_llist_append
226 * case 1:
227 * list is empty
228 * @assumptions:
229 * 1: the element next to head should be our newly created element
230 * 2: the list tail should different from newly created element
231 */
232 Curl_llist_append(&llist, &unusedData_case1, &case1_list);
233 fail_unless(Curl_llist_count(&llist) == 1,
234 "List size should be 1 after appending a new element");
235 /* test that the list head data holds my unusedData */
236 fail_unless(Curl_node_elem(Curl_llist_head(&llist)) == &unusedData_case1,
237 "head ptr should be first entry");
238 /* same goes for the list tail */
239 fail_unless(Curl_llist_tail(&llist) == Curl_llist_head(&llist),
240 "tail and head should be the same");
241
242 /**
243 * testing Curl_llist_append
244 * case 2:
245 * list is not empty
246 * @assumptions:
247 * 1: the list head-next should be the newly created element
248 * 2: the list tail should be the newly created element
249 */
250 Curl_llist_append(&llist, &unusedData_case2, &case2_list);
251 fail_unless(Curl_node_elem(Curl_node_next(Curl_llist_head(&llist))) ==
252 &unusedData_case2,
253 "the node next to head is not getting set correctly");
254 fail_unless(Curl_node_elem(Curl_llist_tail(&llist)) == &unusedData_case2,
255 "the list tail is not getting set correctly");
256
257 /**
258 * testing Curl_llist_append
259 * case 3:
260 * list is has 2 members
261 * @assumptions:
262 * 1: the list head-next should remain the same
263 * 2: the list tail should be the newly created element
264 */
265 Curl_llist_append(&llist, &unusedData_case3, &case3_list);
266 fail_unless(Curl_node_elem(Curl_node_next(Curl_llist_head(&llist))) ==
267 &unusedData_case2,
268 "the node next to head did not stay the same");
269 fail_unless(Curl_node_elem(Curl_llist_tail(&llist)) == &unusedData_case3,
270 "the list tail is not getting set correctly");
271
272 Curl_llist_destroy(&llist, NULL);
273 Curl_llist_destroy(&llist_destination, NULL);
274 }
275 UNITTEST_STOP
276