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