Unconditionally include <config.h> in unit tests.
[gnulib.git] / tests / test-avltreehash_list.c
1 /* Test of sequential list data type implementation.
2    Copyright (C) 2006-2007 Free Software Foundation, Inc.
3    Written by Bruno Haible <bruno@clisp.org>, 2006.
4
5    This program is free software; you can redistribute it and/or modify
6    it under the terms of the GNU General Public License as published by
7    the Free Software Foundation; either version 2, or (at your option)
8    any later version.
9
10    This program is distributed in the hope that it will be useful,
11    but WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13    GNU General Public License for more details.
14
15    You should have received a copy of the GNU General Public License
16    along with this program; if not, write to the Free Software Foundation,
17    Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.  */
18
19 #include <config.h>
20
21 #include "gl_avltreehash_list.h"
22
23 #include <limits.h>
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <string.h>
27
28 #include "gl_array_list.h"
29 #include "progname.h"
30
31 extern void gl_avltreehash_list_check_invariants (gl_list_t list);
32
33 static const char *objects[15] =
34   {
35     "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o"
36   };
37
38 #define SIZE_BITS (sizeof (size_t) * CHAR_BIT)
39
40 static bool
41 string_equals (const void *x1, const void *x2)
42 {
43   const char *s1 = x1;
44   const char *s2 = x2;
45   return strcmp (s1, s2) == 0;
46 }
47
48 /* A hash function for NUL-terminated char* strings using
49    the method described by Bruno Haible.
50    See http://www.haible.de/bruno/hashfunc.html.  */
51 static size_t
52 string_hash (const void *x)
53 {
54   const char *s = x;
55   size_t h = 0;
56
57   for (; *s; s++)
58     h = *s + ((h << 9) | (h >> (SIZE_BITS - 9)));
59
60   return h;
61 }
62
63 #define SIZEOF(array) (sizeof (array) / sizeof (array[0]))
64 #define ASSERT(expr) \
65   do                                                                         \
66     {                                                                        \
67       if (!(expr))                                                           \
68         {                                                                    \
69           fprintf (stderr, "%s:%d: assertion failed\n", __FILE__, __LINE__); \
70           abort ();                                                          \
71         }                                                                    \
72     }                                                                        \
73   while (0)
74 #define RANDOM(n) (rand () % (n))
75 #define RANDOM_OBJECT() objects[RANDOM (SIZEOF (objects))]
76
77 static void
78 check_equals (gl_list_t list1, gl_list_t list2)
79 {
80   size_t n, i;
81
82   n = gl_list_size (list1);
83   ASSERT (n == gl_list_size (list2));
84   for (i = 0; i < n; i++)
85     {
86       ASSERT (gl_list_get_at (list1, i) == gl_list_get_at (list2, i));
87     }
88 }
89
90 static void
91 check_all (gl_list_t list1, gl_list_t list2, gl_list_t list3)
92 {
93   gl_avltreehash_list_check_invariants (list2);
94   gl_avltreehash_list_check_invariants (list3);
95   check_equals (list1, list2);
96   check_equals (list1, list3);
97 }
98
99 int
100 main (int argc, char *argv[])
101 {
102   gl_list_t list1, list2, list3;
103
104   set_program_name (argv[0]);
105
106   /* Allow the user to provide a non-default random seed on the command line.  */
107   if (argc > 1)
108     srand (atoi (argv[1]));
109
110   {
111     size_t initial_size = RANDOM (50);
112     const void **contents =
113       (const void **) malloc (initial_size * sizeof (const void *));
114     size_t i;
115     unsigned int repeat;
116
117     for (i = 0; i < initial_size; i++)
118       contents[i] = RANDOM_OBJECT ();
119
120     /* Create list1.  */
121     list1 = gl_list_create (GL_ARRAY_LIST,
122                             string_equals, string_hash, NULL, true,
123                             initial_size, contents);
124     /* Create list2.  */
125     list2 = gl_list_create_empty (GL_AVLTREEHASH_LIST,
126                                   string_equals, string_hash, NULL, true);
127     for (i = 0; i < initial_size; i++)
128       gl_list_add_last (list2, contents[i]);
129
130     /* Create list3.  */
131     list3 = gl_list_create (GL_AVLTREEHASH_LIST,
132                             string_equals, string_hash, NULL, true,
133                             initial_size, contents);
134
135     check_all (list1, list2, list3);
136
137     for (repeat = 0; repeat < 10000; repeat++)
138       {
139         unsigned int operation = RANDOM (16);
140         switch (operation)
141           {
142           case 0:
143             if (gl_list_size (list1) > 0)
144               {
145                 size_t index = RANDOM (gl_list_size (list1));
146                 const char *obj = RANDOM_OBJECT ();
147                 gl_list_node_t node1, node2, node3;
148
149                 node1 = gl_list_set_at (list1, index, obj);
150                 ASSERT (gl_list_get_at (list1, index) == obj);
151                 ASSERT (gl_list_node_value (list1, node1) == obj);
152
153                 node2 = gl_list_set_at (list2, index, obj);
154                 ASSERT (gl_list_get_at (list2, index) == obj);
155                 ASSERT (gl_list_node_value (list2, node2) == obj);
156
157                 node3 = gl_list_set_at (list3, index, obj);
158                 ASSERT (gl_list_get_at (list3, index) == obj);
159                 ASSERT (gl_list_node_value (list3, node3) == obj);
160
161                 if (index > 0)
162                   {
163                     ASSERT (gl_list_node_value (list1, gl_list_previous_node (list1, node1))
164                             == gl_list_get_at (list1, index - 1));
165                     ASSERT (gl_list_node_value (list2, gl_list_previous_node (list3, node3))
166                             == gl_list_get_at (list2, index - 1));
167                     ASSERT (gl_list_node_value (list3, gl_list_previous_node (list3, node3))
168                             == gl_list_get_at (list2, index - 1));
169                   }
170                 if (index + 1 < gl_list_size (list1))
171                   {
172                     ASSERT (gl_list_node_value (list1, gl_list_next_node (list1, node1))
173                             == gl_list_get_at (list1, index + 1));
174                     ASSERT (gl_list_node_value (list2, gl_list_next_node (list3, node3))
175                             == gl_list_get_at (list2, index + 1));
176                     ASSERT (gl_list_node_value (list3, gl_list_next_node (list3, node3))
177                             == gl_list_get_at (list2, index + 1));
178                   }
179               }
180             break;
181           case 1:
182             {
183               const char *obj = RANDOM_OBJECT ();
184               gl_list_node_t node1, node2, node3;
185               node1 = gl_list_search (list1, obj);
186               node2 = gl_list_search (list2, obj);
187               node3 = gl_list_search (list3, obj);
188               if (node1 == NULL)
189                 {
190                   ASSERT (node2 == NULL);
191                   ASSERT (node3 == NULL);
192                 }
193               else
194                 {
195                   ASSERT (node2 != NULL);
196                   ASSERT (node3 != NULL);
197                   ASSERT (gl_list_node_value (list1, node1) == obj);
198                   ASSERT (gl_list_node_value (list2, node2) == obj);
199                   ASSERT (gl_list_node_value (list3, node3) == obj);
200                 }
201             }
202             break;
203           case 2:
204             {
205               const char *obj = RANDOM_OBJECT ();
206               size_t index1, index2, index3;
207               index1 = gl_list_indexof (list1, obj);
208               index2 = gl_list_indexof (list2, obj);
209               index3 = gl_list_indexof (list3, obj);
210               if (index1 == (size_t)(-1))
211                 {
212                   ASSERT (index2 == (size_t)(-1));
213                   ASSERT (index3 == (size_t)(-1));
214                 }
215               else
216                 {
217                   ASSERT (index2 != (size_t)(-1));
218                   ASSERT (index3 != (size_t)(-1));
219                   ASSERT (gl_list_get_at (list1, index1) == obj);
220                   ASSERT (gl_list_get_at (list2, index2) == obj);
221                   ASSERT (gl_list_get_at (list3, index3) == obj);
222                   ASSERT (index2 == index1);
223                   ASSERT (index3 == index1);
224                 }
225             }
226             break;
227           case 3: /* add 1 element */
228             {
229               const char *obj = RANDOM_OBJECT ();
230               gl_list_node_t node1, node2, node3;
231               node1 = gl_list_add_first (list1, obj);
232               node2 = gl_list_add_first (list2, obj);
233               node3 = gl_list_add_first (list3, obj);
234               ASSERT (gl_list_node_value (list1, node1) == obj);
235               ASSERT (gl_list_node_value (list2, node2) == obj);
236               ASSERT (gl_list_node_value (list3, node3) == obj);
237               ASSERT (gl_list_get_at (list1, 0) == obj);
238               ASSERT (gl_list_get_at (list2, 0) == obj);
239               ASSERT (gl_list_get_at (list3, 0) == obj);
240             }
241             break;
242           case 4: /* add 1 element */
243             {
244               const char *obj = RANDOM_OBJECT ();
245               gl_list_node_t node1, node2, node3;
246               node1 = gl_list_add_last (list1, obj);
247               node2 = gl_list_add_last (list2, obj);
248               node3 = gl_list_add_last (list3, obj);
249               ASSERT (gl_list_node_value (list1, node1) == obj);
250               ASSERT (gl_list_node_value (list2, node2) == obj);
251               ASSERT (gl_list_node_value (list3, node3) == obj);
252               ASSERT (gl_list_get_at (list1, gl_list_size (list1) - 1) == obj);
253               ASSERT (gl_list_get_at (list2, gl_list_size (list2) - 1) == obj);
254               ASSERT (gl_list_get_at (list3, gl_list_size (list3) - 1) == obj);
255             }
256             break;
257           case 5: /* add 3 elements */
258             {
259               const char *obj0 = RANDOM_OBJECT ();
260               const char *obj1 = RANDOM_OBJECT ();
261               const char *obj2 = RANDOM_OBJECT ();
262               gl_list_node_t node1, node2, node3;
263               node1 = gl_list_add_first (list1, obj2);
264               node1 = gl_list_add_before (list1, node1, obj0);
265               node1 = gl_list_add_after (list1, node1, obj1);
266               node2 = gl_list_add_first (list2, obj2);
267               node2 = gl_list_add_before (list2, node2, obj0);
268               node2 = gl_list_add_after (list2, node2, obj1);
269               node3 = gl_list_add_first (list3, obj2);
270               node3 = gl_list_add_before (list3, node3, obj0);
271               node3 = gl_list_add_after (list3, node3, obj1);
272               ASSERT (gl_list_node_value (list1, node1) == obj1);
273               ASSERT (gl_list_node_value (list2, node2) == obj1);
274               ASSERT (gl_list_node_value (list3, node3) == obj1);
275               ASSERT (gl_list_get_at (list1, 0) == obj0);
276               ASSERT (gl_list_get_at (list1, 1) == obj1);
277               ASSERT (gl_list_get_at (list1, 2) == obj2);
278               ASSERT (gl_list_get_at (list2, 0) == obj0);
279               ASSERT (gl_list_get_at (list2, 1) == obj1);
280               ASSERT (gl_list_get_at (list2, 2) == obj2);
281               ASSERT (gl_list_get_at (list3, 0) == obj0);
282               ASSERT (gl_list_get_at (list3, 1) == obj1);
283               ASSERT (gl_list_get_at (list3, 2) == obj2);
284             }
285             break;
286           case 6: /* add 1 element */
287             {
288               size_t index = RANDOM (gl_list_size (list1) + 1);
289               const char *obj = RANDOM_OBJECT ();
290               gl_list_node_t node1, node2, node3;
291               node1 = gl_list_add_at (list1, index, obj);
292               node2 = gl_list_add_at (list2, index, obj);
293               node3 = gl_list_add_at (list3, index, obj);
294               ASSERT (gl_list_get_at (list1, index) == obj);
295               ASSERT (gl_list_node_value (list1, node1) == obj);
296               ASSERT (gl_list_get_at (list2, index) == obj);
297               ASSERT (gl_list_node_value (list2, node2) == obj);
298               ASSERT (gl_list_get_at (list3, index) == obj);
299               ASSERT (gl_list_node_value (list3, node3) == obj);
300               if (index > 0)
301                 {
302                   ASSERT (gl_list_node_value (list1, gl_list_previous_node (list1, node1))
303                           == gl_list_get_at (list1, index - 1));
304                   ASSERT (gl_list_node_value (list2, gl_list_previous_node (list3, node3))
305                           == gl_list_get_at (list2, index - 1));
306                   ASSERT (gl_list_node_value (list3, gl_list_previous_node (list3, node3))
307                           == gl_list_get_at (list2, index - 1));
308                 }
309               if (index + 1 < gl_list_size (list1))
310                 {
311                   ASSERT (gl_list_node_value (list1, gl_list_next_node (list1, node1))
312                           == gl_list_get_at (list1, index + 1));
313                   ASSERT (gl_list_node_value (list2, gl_list_next_node (list3, node3))
314                           == gl_list_get_at (list2, index + 1));
315                   ASSERT (gl_list_node_value (list3, gl_list_next_node (list3, node3))
316                           == gl_list_get_at (list2, index + 1));
317                 }
318             }
319             break;
320           case 7: case 8: /* remove 1 element */
321             if (gl_list_size (list1) > 0)
322               {
323                 size_t n = gl_list_size (list1);
324                 const char *obj = gl_list_get_at (list1, RANDOM (n));
325                 gl_list_node_t node1, node2, node3;
326                 node1 = gl_list_search (list1, obj);
327                 node2 = gl_list_search (list2, obj);
328                 node3 = gl_list_search (list3, obj);
329                 ASSERT (node1 != NULL);
330                 ASSERT (node2 != NULL);
331                 ASSERT (node3 != NULL);
332                 ASSERT (gl_list_remove_node (list1, node1));
333                 ASSERT (gl_list_remove_node (list2, node2));
334                 ASSERT (gl_list_remove_node (list3, node3));
335                 ASSERT (gl_list_size (list1) == n - 1);
336               }
337             break;
338           case 9: case 10: /* remove 1 element */
339             if (gl_list_size (list1) > 0)
340               {
341                 size_t n = gl_list_size (list1);
342                 size_t index = RANDOM (n);
343                 ASSERT (gl_list_remove_at (list1, index));
344                 ASSERT (gl_list_remove_at (list2, index));
345                 ASSERT (gl_list_remove_at (list3, index));
346                 ASSERT (gl_list_size (list1) == n - 1);
347               }
348             break;
349           case 11: case 12: /* remove 1 element */
350             if (gl_list_size (list1) > 0)
351               {
352                 size_t n = gl_list_size (list1);
353                 const char *obj = gl_list_get_at (list1, RANDOM (n));
354                 ASSERT (gl_list_remove (list1, obj));
355                 ASSERT (gl_list_remove (list2, obj));
356                 ASSERT (gl_list_remove (list3, obj));
357                 ASSERT (gl_list_size (list1) == n - 1);
358               }
359             break;
360           case 13:
361             if (gl_list_size (list1) > 0)
362               {
363                 size_t n = gl_list_size (list1);
364                 const char *obj = "xyzzy";
365                 ASSERT (!gl_list_remove (list1, obj));
366                 ASSERT (!gl_list_remove (list2, obj));
367                 ASSERT (!gl_list_remove (list3, obj));
368                 ASSERT (gl_list_size (list1) == n);
369               }
370             break;
371           case 14:
372             {
373               size_t n = gl_list_size (list1);
374               gl_list_iterator_t iter1, iter2, iter3;
375               const void *elt;
376               iter1 = gl_list_iterator (list1);
377               iter2 = gl_list_iterator (list2);
378               iter3 = gl_list_iterator (list3);
379               for (i = 0; i < n; i++)
380                 {
381                   ASSERT (gl_list_iterator_next (&iter1, &elt, NULL));
382                   ASSERT (gl_list_get_at (list1, i) == elt);
383                   ASSERT (gl_list_iterator_next (&iter2, &elt, NULL));
384                   ASSERT (gl_list_get_at (list2, i) == elt);
385                   ASSERT (gl_list_iterator_next (&iter3, &elt, NULL));
386                   ASSERT (gl_list_get_at (list3, i) == elt);
387                 }
388               ASSERT (!gl_list_iterator_next (&iter1, &elt, NULL));
389               ASSERT (!gl_list_iterator_next (&iter2, &elt, NULL));
390               ASSERT (!gl_list_iterator_next (&iter3, &elt, NULL));
391               gl_list_iterator_free (&iter1);
392               gl_list_iterator_free (&iter2);
393               gl_list_iterator_free (&iter3);
394             }
395             break;
396           case 15:
397             {
398               size_t end = RANDOM (gl_list_size (list1) + 1);
399               size_t start = RANDOM (end + 1);
400               gl_list_iterator_t iter1, iter2, iter3;
401               const void *elt;
402               iter1 = gl_list_iterator_from_to (list1, start, end);
403               iter2 = gl_list_iterator_from_to (list2, start, end);
404               iter3 = gl_list_iterator_from_to (list3, start, end);
405               for (i = start; i < end; i++)
406                 {
407                   ASSERT (gl_list_iterator_next (&iter1, &elt, NULL));
408                   ASSERT (gl_list_get_at (list1, i) == elt);
409                   ASSERT (gl_list_iterator_next (&iter2, &elt, NULL));
410                   ASSERT (gl_list_get_at (list2, i) == elt);
411                   ASSERT (gl_list_iterator_next (&iter3, &elt, NULL));
412                   ASSERT (gl_list_get_at (list3, i) == elt);
413                 }
414               ASSERT (!gl_list_iterator_next (&iter1, &elt, NULL));
415               ASSERT (!gl_list_iterator_next (&iter2, &elt, NULL));
416               ASSERT (!gl_list_iterator_next (&iter3, &elt, NULL));
417               gl_list_iterator_free (&iter1);
418               gl_list_iterator_free (&iter2);
419               gl_list_iterator_free (&iter3);
420             }
421             break;
422           }
423         check_all (list1, list2, list3);
424       }
425
426     gl_list_free (list1);
427     gl_list_free (list2);
428     gl_list_free (list3);
429     free (contents);
430   }
431
432   return 0;
433 }