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_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 initiate 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
224