1 #include <stdbool.h> 2 #include <stdlib.h> 3 #include <stdio.h> 4 5 #include "doubly-linked-list.h" 6 7 #ifndef EXIT_SUCCESS 8 #define EXIT_SUCCESS 0 9 #endif 10 11 #ifndef EXIT_FAILURE 12 #define EXIT_FAILURE 1 13 #endif 14 15 /* Implementation */ 16 17 typedef int T; 18 19 typedef struct ListNodeType 20 { 21 T value; 22 struct ListNodeType *next; 23 struct ListNodeType *prev; 24 } ListNodeType; 25 26 ListNodeType * l_new_node (T value) 27 { 28 ListNodeType *n = malloc (sizeof (ListNodeType)); 29 n->next = NULL; 30 n->prev = NULL; 31 n->value = value; 32 return n; 33 } 34 35 typedef struct LinkedListWrapperType 36 { 37 ListNodeType *first; 38 ListNodeType *last; 39 size_t size; 40 } LinkedListWrapperType; 41 42 int compare_nodes (const ListNodeType *n1, const ListNodeType *n2) 43 { 44 if (n1->value == n2->value) 45 return 0; 46 else if (n1->value < n2->value) 47 return -1; 48 else 49 return 1; 50 } 51 52 LINKED_LIST_MUTATIVE_OPS_PROTOTYPE (LinkedListWrapperType, ListNodeType, static); 53 LINKED_LIST_MERGE_SORT_PROTOTYPE (LinkedListWrapperType, ListNodeType, static); 54 55 LINKED_LIST_MUTATIVE_OPS_DECL (LinkedListWrapperType, ListNodeType, static) 56 LINKED_LIST_MERGE_SORT_DECL (LinkedListWrapperType, ListNodeType, static) 57 58 ListNodeType * find_last_node (ListNodeType *head) 59 { 60 if (head == NULL) 61 return NULL; 62 63 ListNodeType *n = head; 64 while (n->next != NULL) 65 n = n->next; 66 67 return n; 68 } 69 70 void l_print (ListNodeType *node) 71 { 72 for (ListNodeType *l = node; l != NULL; l = l->next) 73 printf ("%d ", l->value); 74 printf ("\n"); 75 } 76 77 void l_reverse_print (ListNodeType *last_node) 78 { 79 for (ListNodeType *l = last_node; l != NULL; l = l->prev) 80 printf ("%d ", l->value); 81 printf ("\n"); 82 } 83 84 struct test_data_t 85 { 86 T const *content; 87 size_t size; 88 }; 89 90 bool run_test (const struct test_data_t *expect, 91 LinkedListWrapperType *current, 92 bool reversed) 93 { 94 ListNodeType *node = (reversed) ? current->last : current->first; 95 bool passed = true; 96 for (int i=0; i<expect->size && node != NULL; ++i) 97 { 98 if (reversed) 99 { 100 if (expect->content[expect->size - 1 - i] != node->value) 101 { 102 printf ("FAIL: mismatching expected (%d) VS current (%d).\n", 103 expect->content[expect->size - 1 - i], node->value); 104 passed = false; 105 } 106 if (node->prev == NULL && current->first != node) 107 { 108 printf ("FAIL: first is not matching the first node.\n"); 109 passed = false; 110 } 111 } 112 else 113 { 114 if (expect->content[i] != node->value) 115 { 116 printf ("FAIL: mismatching expected (%d) VS current (%d).\n", 117 expect->content[i], node->value); 118 passed = false; 119 } 120 if (node->next == NULL && current->last != node) 121 { 122 printf ("FAIL: last_ is not matching the last node.\n"); 123 passed = false; 124 } 125 } 126 127 if (!passed) 128 return false; 129 130 if (reversed) 131 node = node->prev; 132 else 133 node = node->next; 134 } 135 136 if (node != NULL) 137 { 138 printf ("FAIL: the list is longer than expected.\n"); 139 passed = false; 140 } 141 if (expect->size != current->size) 142 { 143 printf ("FAIL: size (%ld) is not matching the real size of the list (%ld).\n", 144 current->size, expect->size); 145 passed = false; 146 } 147 148 return passed; 149 } 150 151 bool check(const char *op, 152 const struct test_data_t *expect, 153 LinkedListWrapperType *wrapper) 154 { 155 bool success = true; 156 bool res; 157 158 #define DUMP_LIST 0 159 160 if (DUMP_LIST) 161 l_print (wrapper->first); 162 163 res = run_test (expect, wrapper, false); 164 printf ("%s: test-linked-list::%s: check forward conformity\n", 165 res ? "PASS": "FAIL", op); 166 success &= res; 167 168 if (DUMP_LIST) 169 l_reverse_print (wrapper->last); 170 171 res = run_test (expect, wrapper, true); 172 printf ("%s: test-linked-list::%s: check backward conformity\n", 173 res ? "PASS": "FAIL", op); 174 success &= res; 175 176 if (DUMP_LIST) 177 printf("\n"); 178 179 return success; 180 } 181 182 const int EXPECT_0 [] = { 10, 4, 3, 1, 9, 2 }; 183 const int EXPECT_1 [] = { 1, 2, 3, 4, 9, 10 }; 184 const int EXPECT_2 [] = { 11, 1, 2, 3, 4, 9, 10 }; 185 const int EXPECT_3 [] = { 11, 1, 2, 3, 4, 9, 8, 10 }; 186 const int EXPECT_4 [] = { 11, 2, 3, 4, 9, 8, 10 }; 187 const int EXPECT_5 [] = { 10, 2, 3, 4, 9, 8, 11 }; 188 const int EXPECT_6 [] = { 10, 3, 2, 4, 9, 8, 11 }; 189 const int EXPECT_7 [] = { 10, 9, 2, 4, 3, 8, 11 }; 190 const int EXPECT_8 [] = { 2, 3, 4, 8, 9, 10, 11 }; 191 const int EXPECT_9 [] = { 3, 4, 8, 9, 10, 11 }; 192 const int EXPECT_10 [] = { 3, 4, 8, 9, 10 }; 193 const struct test_data_t test_data[] = { 194 { .content = EXPECT_0, .size = sizeof(EXPECT_0) / sizeof(EXPECT_0[0]) }, 195 { .content = EXPECT_1, .size = sizeof(EXPECT_1) / sizeof(EXPECT_1[0]) }, 196 { .content = EXPECT_2, .size = sizeof(EXPECT_2) / sizeof(EXPECT_2[0]) }, 197 { .content = EXPECT_3, .size = sizeof(EXPECT_3) / sizeof(EXPECT_3[0]) }, 198 { .content = EXPECT_4, .size = sizeof(EXPECT_4) / sizeof(EXPECT_4[0]) }, 199 { .content = EXPECT_5, .size = sizeof(EXPECT_5) / sizeof(EXPECT_5[0]) }, 200 { .content = EXPECT_6, .size = sizeof(EXPECT_6) / sizeof(EXPECT_6[0]) }, 201 { .content = EXPECT_7, .size = sizeof(EXPECT_7) / sizeof(EXPECT_7[0]) }, 202 { .content = EXPECT_8, .size = sizeof(EXPECT_8) / sizeof(EXPECT_8[0]) }, 203 { .content = EXPECT_9, .size = sizeof(EXPECT_9) / sizeof(EXPECT_9[0]) }, 204 { .content = EXPECT_10, .size = sizeof(EXPECT_10) / sizeof(EXPECT_10[0]) }, 205 }; 206 207 int main (void) 208 { 209 int failures = 0; 210 211 LinkedListWrapperType wrapper = { 212 .first = NULL, 213 .last = NULL, 214 .size = 0, 215 }; 216 217 /* Append nodes. */ 218 LINKED_LIST_APPEND(ListNodeType) (&wrapper, l_new_node (10)); 219 LINKED_LIST_APPEND(ListNodeType) (&wrapper, l_new_node (4)); 220 LINKED_LIST_APPEND(ListNodeType) (&wrapper, l_new_node (3)); 221 LINKED_LIST_APPEND(ListNodeType) (&wrapper, l_new_node (1)); 222 LINKED_LIST_APPEND(ListNodeType) (&wrapper, l_new_node (9)); 223 LINKED_LIST_APPEND(ListNodeType) (&wrapper, l_new_node (2)); 224 225 failures += ! check ("append", &test_data[0], &wrapper); 226 227 /* Sort nodes (without updating wrapper). */ 228 wrapper.first = 229 LINKED_LIST_MERGE_SORT_(ListNodeType) (wrapper.first, compare_nodes); 230 wrapper.last = find_last_node (wrapper.first); 231 232 failures += ! check ("sort", &test_data[1], &wrapper); 233 234 /* Save a reference to this node for later. */ 235 ListNodeType *n_to_remove = wrapper.first; 236 237 /* Prepend node. */ 238 LINKED_LIST_PREPEND(ListNodeType) (&wrapper, l_new_node (11)); 239 failures += ! check ("prepend", &test_data[2], &wrapper); 240 241 /* Insert node. */ 242 LINKED_LIST_INSERT_BEFORE(ListNodeType) (&wrapper, l_new_node (8), wrapper.last); 243 failures += ! check ("insert_before", &test_data[3], &wrapper); 244 245 /* Remove a node. */ 246 LINKED_LIST_REMOVE(ListNodeType) (&wrapper, n_to_remove); 247 failures += ! check ("remove", &test_data[4], &wrapper); 248 249 /* Swap first and last. */ 250 LINKED_LIST_SWAP(ListNodeType) (&wrapper, wrapper.first, wrapper.last); 251 failures += ! check ("swap first and last", &test_data[5], &wrapper); 252 253 /* Swap adjacent nodes. */ 254 LINKED_LIST_SWAP(ListNodeType) (&wrapper, wrapper.first->next, 255 wrapper.first->next->next); 256 failures += ! check ("swap adjacent nodes", &test_data[6], &wrapper); 257 258 /* Swap non-adjacent nodes, but neither first nor last. */ 259 LINKED_LIST_SWAP(ListNodeType) (&wrapper, wrapper.first->next, 260 wrapper.first->next->next->next->next); 261 failures += ! check ("swap non-adjacent nodes", &test_data[7], &wrapper); 262 263 /* Sort nodes. */ 264 LINKED_LIST_MERGE_SORT(ListNodeType) (&wrapper, compare_nodes); 265 failures += ! check ("sort", &test_data[8], &wrapper); 266 267 /* Pop front. */ 268 LINKED_LIST_POP_FRONT(ListNodeType) (&wrapper); 269 failures += ! check ("pop_front", &test_data[9], &wrapper); 270 271 /* Pop back. */ 272 LINKED_LIST_POP_BACK(ListNodeType) (&wrapper); 273 failures += ! check ("pop_back", &test_data[10], &wrapper); 274 275 exit (failures ? EXIT_FAILURE : EXIT_SUCCESS); 276 } 277