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