1#include <stdio.h>
2#include <glib.h>
3#include <stdlib.h>
4
5/* Keep this in sync with gsequence.c !!! */
6typedef struct _GSequenceNode GSequenceNode;
7
8struct _GSequence
9{
10  GSequenceNode *       end_node;
11  GDestroyNotify        data_destroy_notify;
12  gboolean              access_prohibited;
13  GSequence *           real_sequence;
14};
15
16struct _GSequenceNode
17{
18  gint                  n_nodes;
19  GSequenceNode *       parent;
20  GSequenceNode *       left;
21  GSequenceNode *       right;
22  gpointer              data;
23};
24
25static guint
26get_priority (GSequenceNode *node)
27{
28  guint key = GPOINTER_TO_UINT (node);
29
30  key = (key << 15) - key - 1;
31  key = key ^ (key >> 12);
32  key = key + (key << 2);
33  key = key ^ (key >> 4);
34  key = key + (key << 3) + (key << 11);
35  key = key ^ (key >> 16);
36
37  return key? key : 1;
38}
39
40static void
41check_node (GSequenceNode *node)
42{
43  if (node)
44    {
45      g_assert (node->parent != node);
46      if (node->parent)
47        g_assert (node->parent->left == node || node->parent->right == node);
48      g_assert (node->n_nodes == 1 + (node->left ? node->left->n_nodes : 0) + (node->right ? node->right->n_nodes : 0));
49      if (node->left)
50          g_assert (get_priority (node) >= get_priority (node->left));
51      if (node->right)
52          g_assert (get_priority (node) >= get_priority (node->right));
53      check_node (node->left);
54      check_node (node->right);
55    }
56}
57
58void
59g_sequence_check (GSequence *seq)
60{
61  GSequenceNode *node = seq->end_node;
62
63  while (node->parent)
64    node = node->parent;
65
66  check_node (node);
67
68  while (node->right)
69    node = node->right;
70
71  g_assert (seq->end_node == node);
72  g_assert (node->data == seq);
73
74}
75
76
77enum {
78  NEW, FREE, GET_LENGTH, FOREACH, FOREACH_RANGE, SORT, SORT_ITER,
79
80  /* Getting iters */
81  GET_BEGIN_ITER, GET_END_ITER, GET_ITER_AT_POS, APPEND, PREPEND,
82  INSERT_BEFORE, MOVE, SWAP, INSERT_SORTED, INSERT_SORTED_ITER, SORT_CHANGED,
83  SORT_CHANGED_ITER, REMOVE, REMOVE_RANGE, MOVE_RANGE, SEARCH, SEARCH_ITER,
84
85  /* dereferencing */
86  GET, SET,
87
88  /* operations on GSequenceIter * */
89  ITER_IS_BEGIN, ITER_IS_END, ITER_NEXT, ITER_PREV, ITER_GET_POSITION,
90  ITER_MOVE, ITER_GET_SEQUENCE,
91
92  /* search */
93  ITER_COMPARE, RANGE_GET_MIDPOINT,
94  N_OPS
95};
96
97typedef struct SequenceInfo
98{
99  GQueue *	queue;
100  GSequence *	sequence;
101  int		n_items;
102} SequenceInfo;
103
104typedef struct
105{
106  SequenceInfo *seq;
107  int		  number;
108} Item;
109
110void g_sequence_check (GSequence *sequence);
111
112static Item *
113fix_pointer (gconstpointer data)
114{
115  return (Item *)((char *)data - 1);
116}
117
118static Item *
119get_item (GSequenceIter *iter)
120{
121  return fix_pointer (g_sequence_get (iter));
122}
123
124static void
125check_integrity (SequenceInfo *info)
126{
127  GList *list;
128  GSequenceIter *iter;
129  int i;
130
131  g_sequence_check (info->sequence);
132
133  if (g_sequence_get_length (info->sequence) != info->n_items)
134    g_print ("%d %d\n",
135	     g_sequence_get_length (info->sequence), info->n_items);
136  g_assert (info->n_items == g_queue_get_length (info->queue));
137  g_assert (g_sequence_get_length (info->sequence) == info->n_items);
138
139  iter = g_sequence_get_begin_iter (info->sequence);
140  list = info->queue->head;
141  i = 0;
142  while (iter != g_sequence_get_end_iter (info->sequence))
143    {
144      Item *item;
145      g_assert (list->data == iter);
146      item = get_item (list->data);
147      g_assert (item->seq == info);
148
149      iter = g_sequence_iter_next (iter);
150      list = list->next;
151      i++;
152    }
153
154  g_assert (info->n_items == g_queue_get_length (info->queue));
155  g_assert (g_sequence_get_length (info->sequence) == info->n_items);
156}
157
158static gpointer
159new_item (SequenceInfo *seq)
160{
161  Item *item = g_new (Item, 1);
162  seq->n_items++;
163  item->seq = seq;
164  item->number = g_random_int ();
165
166  /* There have been bugs in the past where the GSequence would
167   * dereference the user pointers. This will make sure such
168   * behavior causes crashes
169   */
170  return ((char *)item + 1);
171}
172
173static void
174free_item (gpointer data)
175{
176  Item *item = fix_pointer (data);
177  item->seq->n_items--;
178  g_free (item);
179}
180
181static void
182seq_foreach (gpointer data,
183	     gpointer user_data)
184{
185  Item *item = fix_pointer (data);
186  GList **link = user_data;
187  GSequenceIter *iter;
188
189  g_assert (*link != NULL);
190
191  iter = (*link)->data;
192
193  g_assert (get_item (iter) == item);
194
195  item->number = g_random_int();
196
197  *link = (*link)->next;
198}
199
200static gint
201compare_items (gconstpointer a,
202	       gconstpointer b,
203	       gpointer	     data)
204{
205  const Item *item_a = fix_pointer (a);
206  const Item *item_b = fix_pointer (b);
207
208  if (item_a->number < item_b->number)
209    {
210      return -1;
211    }
212  else if (item_a->number == item_b->number)
213    {
214      /* Force an arbitrary order on the items
215       * We have to do this, since g_queue_insert_sorted() and
216       * g_sequence_insert_sorted() do not agree on the exact
217       * position the item is inserted if the new item is
218       * equal to an existing one.
219       */
220      if (item_a < item_b)
221	return -1;
222      else if (item_a == item_b)
223	return 0;
224      else
225	return 1;
226    }
227  else
228    {
229      return 1;
230    }
231}
232
233static void
234check_sorted (SequenceInfo *info)
235{
236  GList *list;
237  int last;
238  GSequenceIter *last_iter;
239
240  check_integrity (info);
241
242  last = G_MININT;
243  last_iter = NULL;
244  for (list = info->queue->head; list != NULL; list = list->next)
245    {
246      GSequenceIter *iter = list->data;
247      Item *item = get_item (iter);
248
249      g_assert (item->number >= last);
250      /* Check that the ordering is the same as that of the queue,
251       * ie. that the sort is stable
252       */
253      if (last_iter)
254	g_assert (iter == g_sequence_iter_next (last_iter));
255
256      last = item->number;
257      last_iter = iter;
258    }
259}
260
261static gint
262compare_iters (gconstpointer a,
263	       gconstpointer b,
264	       gpointer      data)
265{
266  GSequence *seq = data;
267  GSequenceIter *iter_a = (GSequenceIter *)a;
268  GSequenceIter *iter_b = (GSequenceIter *)b;
269  /* compare_items() will fix up the pointers */
270  Item *item_a = g_sequence_get (iter_a);
271  Item *item_b = g_sequence_get (iter_b);
272
273  if (seq)
274    {
275      g_assert (g_sequence_iter_get_sequence (iter_a) == seq);
276      g_assert (g_sequence_iter_get_sequence (iter_b) == seq);
277    }
278
279  return compare_items (item_a, item_b, data);
280}
281
282/* A version of g_queue_link_index() that treats NULL as just
283 * beyond the queue
284 */
285static int
286queue_link_index (SequenceInfo *seq, GList *link)
287{
288  if (link)
289    return g_queue_link_index (seq->queue, link);
290  else
291    return g_queue_get_length (seq->queue);
292}
293
294static void
295get_random_range (SequenceInfo *seq,
296		  GSequenceIter **begin_iter,
297		  GSequenceIter **end_iter,
298		  GList **begin_link,
299		  GList **end_link)
300{
301  int length = g_queue_get_length (seq->queue);
302  int b = g_random_int_range (0, length + 1);
303  int e = g_random_int_range (b, length + 1);
304
305  g_assert (length == g_sequence_get_length (seq->sequence));
306
307  if (begin_iter)
308    *begin_iter = g_sequence_get_iter_at_pos (seq->sequence, b);
309  if (end_iter)
310    *end_iter = g_sequence_get_iter_at_pos (seq->sequence, e);
311  if (begin_link)
312    *begin_link = g_queue_peek_nth_link (seq->queue, b);
313  if (end_link)
314    *end_link = g_queue_peek_nth_link (seq->queue, e);
315  if (begin_iter && begin_link)
316    {
317      g_assert (
318		queue_link_index (seq, *begin_link) ==
319		g_sequence_iter_get_position (*begin_iter));
320    }
321  if (end_iter && end_link)
322    {
323      g_assert (
324		queue_link_index (seq, *end_link) ==
325		g_sequence_iter_get_position (*end_iter));
326    }
327}
328
329static gint
330get_random_position (SequenceInfo *seq)
331{
332  int length = g_queue_get_length (seq->queue);
333
334  g_assert (length == g_sequence_get_length (seq->sequence));
335
336  return g_random_int_range (-2, length + 5);
337}
338
339static GSequenceIter *
340get_random_iter (SequenceInfo  *seq,
341		 GList        **link)
342{
343  GSequenceIter *iter;
344  int pos = get_random_position (seq);
345  if (link)
346    *link = g_queue_peek_nth_link (seq->queue, pos);
347  iter = g_sequence_get_iter_at_pos (seq->sequence, pos);
348  if (link)
349    g_assert (queue_link_index (seq, *link) == g_sequence_iter_get_position (iter));
350  return iter;
351}
352
353static void
354dump_info (SequenceInfo *seq)
355{
356#if 0
357  GSequenceIter *iter;
358  GList *list;
359
360  iter = g_sequence_get_begin_iter (seq->sequence);
361  list = seq->queue->head;
362
363  while (iter != g_sequence_get_end_iter (seq->sequence))
364    {
365      Item *item = get_item (iter);
366      g_print ("%p  %p    %d\n", list->data, iter, item->number);
367
368      iter = g_sequence_iter_next (iter);
369      list = list->next;
370    }
371#endif
372}
373
374/* A version of g_queue_insert_before() that appends if link is NULL */
375static void
376queue_insert_before (SequenceInfo *seq, GList *link, gpointer data)
377{
378  if (link)
379    g_queue_insert_before (seq->queue, link, data);
380  else
381    g_queue_push_tail (seq->queue, data);
382}
383
384static void
385run_random_tests (guint32 seed)
386{
387#define N_ITERATIONS 60000
388#define N_SEQUENCES 8
389#define N_TIMES 24
390
391  SequenceInfo sequences[N_SEQUENCES];
392  int k;
393
394  g_print ("    seed: %u\n", seed);
395
396  g_random_set_seed (seed);
397
398  for (k = 0; k < N_SEQUENCES; ++k)
399    {
400      sequences[k].queue = g_queue_new ();
401      sequences[k].sequence = g_sequence_new (free_item);
402      sequences[k].n_items = 0;
403    }
404
405#define RANDOM_SEQUENCE() &(sequences[g_random_int_range (0, N_SEQUENCES)])
406
407  for (k = 0; k < N_ITERATIONS; ++k)
408    {
409      int i;
410      SequenceInfo *seq = RANDOM_SEQUENCE();
411      int op = g_random_int_range (0, N_OPS);
412
413#if 0
414      g_print ("%d on %p\n", op, seq);
415#endif
416
417      switch (op)
418	{
419	case NEW:
420	case FREE:
421	  {
422	    g_queue_free (seq->queue);
423	    g_sequence_free (seq->sequence);
424
425	    g_assert (seq->n_items == 0);
426
427	    seq->queue = g_queue_new ();
428	    seq->sequence = g_sequence_new (free_item);
429
430	    check_integrity (seq);
431	  }
432	  break;
433	case GET_LENGTH:
434	  {
435	    int slen = g_sequence_get_length (seq->sequence);
436	    int qlen = g_queue_get_length (seq->queue);
437
438	    g_assert (slen == qlen);
439	  }
440	  break;
441	case FOREACH:
442	  {
443	    GList *link = seq->queue->head;
444	    g_sequence_foreach (seq->sequence, seq_foreach, &link);
445	    g_assert (link == NULL);
446	  }
447	  break;
448	case FOREACH_RANGE:
449	  {
450	    GSequenceIter *begin_iter, *end_iter;
451	    GList *begin_link, *end_link;
452
453	    get_random_range (seq, &begin_iter, &end_iter, &begin_link, &end_link);
454
455	    check_integrity (seq);
456
457	    g_sequence_foreach_range (begin_iter, end_iter, seq_foreach, &begin_link);
458
459	    g_assert (begin_link == end_link);
460	  }
461	  break;
462	case SORT:
463	  {
464	    dump_info (seq);
465
466	    g_sequence_sort (seq->sequence, compare_items, NULL);
467	    g_queue_sort (seq->queue, compare_iters, NULL);
468
469	    check_sorted (seq);
470
471	    dump_info (seq);
472	  }
473	  break;
474	case SORT_ITER:
475	  {
476	    check_integrity (seq);
477	    g_sequence_sort_iter (seq->sequence,
478				  (GSequenceIterCompareFunc)compare_iters, seq->sequence);
479	    g_queue_sort (seq->queue, compare_iters, NULL);
480	    check_sorted (seq);
481	  }
482	  break;
483
484	  /* Getting iters */
485	case GET_END_ITER:
486	case GET_BEGIN_ITER:
487	  {
488	    GSequenceIter *begin_iter;
489	    GSequenceIter *end_iter;
490	    GSequenceIter *penultimate_iter;
491
492	    begin_iter = g_sequence_get_begin_iter (seq->sequence);
493	    check_integrity (seq);
494
495	    end_iter = g_sequence_get_end_iter (seq->sequence);
496	    check_integrity (seq);
497
498	    penultimate_iter = g_sequence_iter_prev (end_iter);
499	    check_integrity (seq);
500
501	    if (g_sequence_get_length (seq->sequence) > 0)
502	      {
503		g_assert (seq->queue->head);
504		g_assert (seq->queue->head->data == begin_iter);
505		g_assert (seq->queue->tail);
506		g_assert (seq->queue->tail->data == penultimate_iter);
507	      }
508	    else
509	      {
510		g_assert (penultimate_iter == end_iter);
511		g_assert (begin_iter == end_iter);
512		g_assert (penultimate_iter == begin_iter);
513		g_assert (seq->queue->head == NULL);
514		g_assert (seq->queue->tail == NULL);
515	      }
516	  }
517	  break;
518	case GET_ITER_AT_POS:
519	  {
520	    int i;
521
522	    g_assert (g_queue_get_length (seq->queue) == g_sequence_get_length (seq->sequence));
523
524	    for (i = 0; i < 10; ++i)
525	      {
526		int pos = get_random_position (seq);
527		GSequenceIter *iter = g_sequence_get_iter_at_pos (seq->sequence, pos);
528		GList *link = g_queue_peek_nth_link (seq->queue, pos);
529		check_integrity (seq);
530		if (pos >= g_sequence_get_length (seq->sequence) || pos < 0)
531		  {
532		    g_assert (iter == g_sequence_get_end_iter (seq->sequence));
533		    g_assert (link == NULL);
534		  }
535		else
536		  {
537		    g_assert (link);
538		    g_assert (link->data == iter);
539		  }
540	      }
541	  }
542	  break;
543	case APPEND:
544	  {
545	    for (i = 0; i < 10; ++i)
546	      {
547		GSequenceIter *iter = g_sequence_append (seq->sequence, new_item (seq));
548		g_queue_push_tail (seq->queue, iter);
549	      }
550	  }
551	  break;
552	case PREPEND:
553	  {
554	    for (i = 0; i < 10; ++i)
555	      {
556		GSequenceIter *iter = g_sequence_prepend (seq->sequence, new_item (seq));
557		g_queue_push_head (seq->queue, iter);
558	      }
559	  }
560	  break;
561	case INSERT_BEFORE:
562	  {
563	    for (i = 0; i < 10; ++i)
564	      {
565		GList *link;
566		GSequenceIter *iter = get_random_iter (seq, &link);
567		GSequenceIter *new_iter;
568		check_integrity (seq);
569
570		new_iter = g_sequence_insert_before (iter, new_item (seq));
571
572		queue_insert_before (seq, link, new_iter);
573	      }
574	  }
575	  break;
576 	case MOVE:
577	  {
578	    GList *link1, *link2;
579	    SequenceInfo *seq1 = RANDOM_SEQUENCE();
580	    SequenceInfo *seq2 = RANDOM_SEQUENCE();
581	    GSequenceIter *iter1 = get_random_iter (seq1, &link1);
582	    GSequenceIter *iter2 = get_random_iter (seq2, &link2);
583
584	    if (!g_sequence_iter_is_end (iter1))
585	      {
586		g_sequence_move (iter1, iter2);
587
588		if (!link2)
589		  g_assert (g_sequence_iter_is_end (iter2));
590
591		queue_insert_before (seq2, link2, link1->data);
592
593		g_queue_delete_link (seq1->queue, link1);
594
595		get_item (iter1)->seq = seq2;
596
597		seq1->n_items--;
598		seq2->n_items++;
599	      }
600
601	    check_integrity (seq);
602
603	    iter1 = get_random_iter (seq, NULL);
604
605	    /* Moving an iter to itself should have no effect */
606	    if (!g_sequence_iter_is_end (iter1))
607	      g_sequence_move (iter1, iter1);
608	  }
609	  break;
610	case SWAP:
611	  {
612	    GList *link1, *link2;
613	    SequenceInfo *seq1 = RANDOM_SEQUENCE();
614	    SequenceInfo *seq2 = RANDOM_SEQUENCE();
615	    GSequenceIter *iter1 = get_random_iter (seq1, &link1);
616	    GSequenceIter *iter2 = get_random_iter (seq2, &link2);
617
618	    if (!g_sequence_iter_is_end (iter1) &&
619		!g_sequence_iter_is_end (iter2))
620	      {
621		gpointer tmp;
622
623		g_sequence_swap (iter1, iter2);
624
625		get_item (iter1)->seq = seq2;
626		get_item (iter2)->seq = seq1;
627
628		tmp = link1->data;
629		link1->data = link2->data;
630		link2->data = tmp;
631	      }
632	  }
633	  break;
634	case INSERT_SORTED:
635	  {
636	    int i;
637	    dump_info (seq);
638
639	    g_sequence_sort (seq->sequence, compare_items, NULL);
640	    g_queue_sort (seq->queue, compare_iters, NULL);
641
642	    check_sorted (seq);
643
644	    for (i = 0; i < N_TIMES; ++i)
645	      {
646		GSequenceIter *iter =
647		  g_sequence_insert_sorted (seq->sequence, new_item(seq), compare_items, NULL);
648
649		g_queue_insert_sorted (seq->queue, iter, compare_iters, NULL);
650	      }
651
652	    check_sorted (seq);
653
654	    dump_info (seq);
655	  }
656	  break;
657	case INSERT_SORTED_ITER:
658	  {
659	    int i;
660	    dump_info (seq);
661
662	    g_sequence_sort (seq->sequence, compare_items, NULL);
663	    g_queue_sort (seq->queue, compare_iters, NULL);
664
665	    check_sorted (seq);
666
667	    for (i = 0; i < N_TIMES; ++i)
668	      {
669		GSequenceIter *iter;
670
671		iter = g_sequence_insert_sorted_iter (seq->sequence,
672						      new_item (seq),
673						      (GSequenceIterCompareFunc)compare_iters,
674						      seq->sequence);
675
676		g_queue_insert_sorted (seq->queue, iter, compare_iters, NULL);
677	      }
678
679	    check_sorted (seq);
680
681	    dump_info (seq);
682	  }
683	  break;
684	case SORT_CHANGED:
685	  {
686	    int i;
687
688	    g_sequence_sort (seq->sequence, compare_items, NULL);
689	    g_queue_sort (seq->queue, compare_iters, NULL);
690
691	    check_sorted (seq);
692
693	    for (i = 0; i < N_TIMES; ++i)
694	      {
695		GList *link;
696		GSequenceIter *iter = get_random_iter (seq, &link);
697
698		if (!g_sequence_iter_is_end (iter))
699		  {
700		    g_sequence_set (iter, new_item (seq));
701		    g_sequence_sort_changed (iter, compare_items, NULL);
702
703		    g_queue_delete_link (seq->queue, link);
704		    g_queue_insert_sorted (seq->queue, iter, compare_iters, NULL);
705		  }
706
707		check_sorted (seq);
708	      }
709	  }
710	  break;
711	case SORT_CHANGED_ITER:
712	  {
713	    int i;
714
715	    g_sequence_sort (seq->sequence, compare_items, NULL);
716	    g_queue_sort (seq->queue, compare_iters, NULL);
717
718	    check_sorted (seq);
719
720	    for (i = 0; i < N_TIMES; ++i)
721	      {
722		GList *link;
723		GSequenceIter *iter = get_random_iter (seq, &link);
724
725		if (!g_sequence_iter_is_end (iter))
726		  {
727		    g_sequence_set (iter, new_item (seq));
728		    g_sequence_sort_changed_iter (iter,
729						  (GSequenceIterCompareFunc)compare_iters, seq->sequence);
730
731		    g_queue_delete_link (seq->queue, link);
732		    g_queue_insert_sorted (seq->queue, iter, compare_iters, NULL);
733		  }
734
735		check_sorted (seq);
736	      }
737	  }
738	  break;
739	case REMOVE:
740	  {
741	    int i;
742
743	    for (i = 0; i < N_TIMES; ++i)
744	      {
745		GList *link;
746		GSequenceIter *iter = get_random_iter (seq, &link);
747
748		if (!g_sequence_iter_is_end (iter))
749		  {
750		    g_sequence_remove (iter);
751		    g_queue_delete_link (seq->queue, link);
752		  }
753	      }
754	  }
755	  break;
756	case REMOVE_RANGE:
757	  {
758	    GSequenceIter *begin_iter, *end_iter;
759	    GList *begin_link, *end_link;
760	    GList *list;
761
762	    get_random_range (seq, &begin_iter, &end_iter, &begin_link, &end_link);
763
764	    g_sequence_remove_range (begin_iter, end_iter);
765
766	    list = begin_link;
767	    while (list != end_link)
768	      {
769		GList *next = list->next;
770
771		g_queue_delete_link (seq->queue, list);
772
773		list = next;
774	      }
775	  }
776	  break;
777	case MOVE_RANGE:
778	  {
779	    SequenceInfo *src = RANDOM_SEQUENCE();
780	    SequenceInfo *dst = RANDOM_SEQUENCE();
781
782	    GSequenceIter *begin_iter, *end_iter;
783	    GList *begin_link, *end_link;
784
785	    GSequenceIter *dst_iter;
786	    GList *dst_link;
787
788	    GList *list;
789
790	    g_assert (src->queue);
791	    g_assert (dst->queue);
792
793	    get_random_range (src, &begin_iter, &end_iter, &begin_link, &end_link);
794	    dst_iter = get_random_iter (dst, &dst_link);
795
796	    g_sequence_move_range (dst_iter, begin_iter, end_iter);
797
798	    if (dst_link == begin_link || (src == dst && dst_link == end_link))
799	      {
800		check_integrity (src);
801		check_integrity (dst);
802		break;
803	      }
804
805	    if (queue_link_index (src, begin_link) >=
806		queue_link_index (src, end_link))
807	      {
808		break;
809	      }
810
811	    if (src == dst &&
812		queue_link_index (src, dst_link) >= queue_link_index (src, begin_link) &&
813		queue_link_index (src, dst_link) <= queue_link_index (src, end_link))
814	      {
815		break;
816	      }
817
818	    list = begin_link;
819	    while (list != end_link)
820	      {
821		GList *next = list->next;
822		Item *item = get_item (list->data);
823
824		g_assert (dst->queue);
825		queue_insert_before (dst, dst_link, list->data);
826		g_queue_delete_link (src->queue, list);
827
828		g_assert (item->seq == src);
829
830		src->n_items--;
831		dst->n_items++;
832		item->seq = dst;
833
834		list = next;
835	      }
836	  }
837	  break;
838	case SEARCH:
839	  {
840	    Item *item;
841	    GSequenceIter *search_iter;
842	    GSequenceIter *insert_iter;
843
844	    g_sequence_sort (seq->sequence, compare_items, NULL);
845	    g_queue_sort (seq->queue, compare_iters, NULL);
846
847	    check_sorted (seq);
848
849	    item = new_item (seq);
850	    search_iter = g_sequence_search (seq->sequence, item, compare_items, NULL);
851
852	    insert_iter = g_sequence_insert_sorted (seq->sequence, item, compare_items, NULL);
853
854	    g_assert (search_iter == g_sequence_iter_next (insert_iter));
855
856	    g_queue_insert_sorted (seq->queue, insert_iter, compare_iters, NULL);
857	  }
858	  break;
859	case SEARCH_ITER:
860	  {
861	    Item *item;
862	    GSequenceIter *search_iter;
863	    GSequenceIter *insert_iter;
864
865	    g_sequence_sort (seq->sequence, compare_items, NULL);
866	    g_queue_sort (seq->queue, compare_iters, NULL);
867
868	    check_sorted (seq);
869
870	    item = new_item (seq);
871	    search_iter = g_sequence_search_iter (seq->sequence,
872						  item,
873						  (GSequenceIterCompareFunc)compare_iters, seq->sequence);
874
875	    insert_iter = g_sequence_insert_sorted (seq->sequence, item, compare_items, NULL);
876
877	    g_assert (search_iter == g_sequence_iter_next (insert_iter));
878
879	    g_queue_insert_sorted (seq->queue, insert_iter, compare_iters, NULL);
880	  }
881	  break;
882
883	  /* dereferencing */
884	case GET:
885	case SET:
886	  {
887	    GSequenceIter *iter;
888	    GList *link;
889
890	    iter = get_random_iter (seq, &link);
891
892	    if (!g_sequence_iter_is_end (iter))
893	      {
894		Item *item;
895		int i;
896
897		check_integrity (seq);
898
899		/* Test basic functionality */
900		item = new_item (seq);
901		g_sequence_set (iter, item);
902		g_assert (g_sequence_get (iter) == item);
903
904		/* Make sure that existing items are freed */
905		for (i = 0; i < N_TIMES; ++i)
906		  g_sequence_set (iter, new_item (seq));
907
908		check_integrity (seq);
909
910		g_sequence_set (iter, new_item (seq));
911	      }
912	  }
913	  break;
914
915	  /* operations on GSequenceIter * */
916	case ITER_IS_BEGIN:
917	  {
918	    GSequenceIter *iter;
919
920	    iter = g_sequence_get_iter_at_pos (seq->sequence, 0);
921
922	    g_assert (g_sequence_iter_is_begin (iter));
923
924	    check_integrity (seq);
925
926	    if (g_sequence_get_length (seq->sequence) > 0)
927	      {
928		g_assert (!g_sequence_iter_is_begin (g_sequence_get_end_iter (seq->sequence)));
929	      }
930	    else
931	      {
932		g_assert (g_sequence_iter_is_begin (g_sequence_get_end_iter (seq->sequence)));
933	      }
934
935	    g_assert (g_sequence_iter_is_begin (g_sequence_get_begin_iter (seq->sequence)));
936	  }
937	  break;
938	case ITER_IS_END:
939	  {
940	    GSequenceIter *iter;
941	    int len = g_sequence_get_length (seq->sequence);
942
943	    iter = g_sequence_get_iter_at_pos (seq->sequence, len);
944
945	    g_assert (g_sequence_iter_is_end (iter));
946
947	    if (len > 0)
948	      {
949		g_assert (!g_sequence_iter_is_end (g_sequence_get_begin_iter (seq->sequence)));
950	      }
951	    else
952	      {
953		g_assert (g_sequence_iter_is_end (g_sequence_get_begin_iter (seq->sequence)));
954	      }
955
956	    g_assert (g_sequence_iter_is_end (g_sequence_get_end_iter (seq->sequence)));
957	  }
958	  break;
959	case ITER_NEXT:
960	  {
961	    GSequenceIter *iter1, *iter2, *iter3, *end;
962
963	    iter1 = g_sequence_append (seq->sequence, new_item (seq));
964	    iter2 = g_sequence_append (seq->sequence, new_item (seq));
965	    iter3 = g_sequence_append (seq->sequence, new_item (seq));
966
967	    end = g_sequence_get_end_iter (seq->sequence);
968
969	    g_assert (g_sequence_iter_next (iter1) == iter2);
970	    g_assert (g_sequence_iter_next (iter2) == iter3);
971	    g_assert (g_sequence_iter_next (iter3) == end);
972	    g_assert (g_sequence_iter_next (end) == end);
973
974	    g_queue_push_tail (seq->queue, iter1);
975	    g_queue_push_tail (seq->queue, iter2);
976	    g_queue_push_tail (seq->queue, iter3);
977	  }
978	  break;
979	case ITER_PREV:
980	  {
981	    GSequenceIter *iter1, *iter2, *iter3, *begin;
982
983	    iter1 = g_sequence_prepend (seq->sequence, new_item (seq));
984	    iter2 = g_sequence_prepend (seq->sequence, new_item (seq));
985	    iter3 = g_sequence_prepend (seq->sequence, new_item (seq));
986
987	    begin = g_sequence_get_begin_iter (seq->sequence);
988
989	    g_assert (g_sequence_iter_prev (iter1) == iter2);
990	    g_assert (g_sequence_iter_prev (iter2) == iter3);
991	    g_assert (iter3 == begin);
992	    g_assert (g_sequence_iter_prev (iter3) == begin);
993	    g_assert (g_sequence_iter_prev (begin) == begin);
994
995	    g_queue_push_head (seq->queue, iter1);
996	    g_queue_push_head (seq->queue, iter2);
997	    g_queue_push_head (seq->queue, iter3);
998	  }
999	  break;
1000	case ITER_GET_POSITION:
1001	  {
1002	    GList *link;
1003	    GSequenceIter *iter = get_random_iter (seq, &link);
1004
1005	    g_assert (g_sequence_iter_get_position (iter) ==
1006		      queue_link_index (seq, link));
1007	  }
1008	  break;
1009	case ITER_MOVE:
1010	  {
1011	    int len = g_sequence_get_length (seq->sequence);
1012	    GSequenceIter *iter;
1013	    int pos;
1014
1015	    iter = get_random_iter (seq, NULL);
1016	    pos = g_sequence_iter_get_position (iter);
1017	    iter = g_sequence_iter_move (iter, len - pos);
1018	    g_assert (g_sequence_iter_is_end (iter));
1019
1020
1021	    iter = get_random_iter (seq, NULL);
1022	    pos = g_sequence_iter_get_position (iter);
1023	    while (pos < len)
1024	      {
1025		g_assert (!g_sequence_iter_is_end (iter));
1026		pos++;
1027		iter = g_sequence_iter_move (iter, 1);
1028	      }
1029	    g_assert (g_sequence_iter_is_end (iter));
1030	  }
1031	  break;
1032	case ITER_GET_SEQUENCE:
1033	  {
1034	    GSequenceIter *iter = get_random_iter (seq, NULL);
1035
1036	    g_assert (g_sequence_iter_get_sequence (iter) == seq->sequence);
1037	  }
1038	  break;
1039
1040	  /* search */
1041	case ITER_COMPARE:
1042	  {
1043	    GList *link1, *link2;
1044	    GSequenceIter *iter1 = get_random_iter (seq, &link1);
1045	    GSequenceIter *iter2 = get_random_iter (seq, &link2);
1046
1047	    int cmp = g_sequence_iter_compare (iter1, iter2);
1048	    int pos1 = queue_link_index (seq, link1);
1049	    int pos2 = queue_link_index (seq, link2);
1050
1051	    if (cmp == 0)
1052	      {
1053		g_assert (pos1 == pos2);
1054	      }
1055	    else if (cmp < 0)
1056	      {
1057		g_assert (pos1 < pos2);
1058	      }
1059	    else
1060	      {
1061		g_assert (pos1 > pos2);
1062	      }
1063	  }
1064	  break;
1065	case RANGE_GET_MIDPOINT:
1066	  {
1067	    GSequenceIter *iter1 = get_random_iter (seq, NULL);
1068	    GSequenceIter *iter2 = get_random_iter (seq, NULL);
1069	    GSequenceIter *iter3;
1070	    int cmp;
1071
1072	    cmp = g_sequence_iter_compare (iter1, iter2);
1073
1074	    if (cmp > 0)
1075	      {
1076		GSequenceIter *tmp;
1077
1078		tmp = iter1;
1079		iter1 = iter2;
1080		iter2 = tmp;
1081	      }
1082
1083	    iter3 = g_sequence_range_get_midpoint (iter1, iter2);
1084
1085	    if (cmp == 0)
1086	      {
1087		g_assert (iter3 == iter1);
1088		g_assert (iter3 == iter2);
1089	      }
1090
1091	    g_assert (g_sequence_iter_get_position (iter3) >=
1092		      g_sequence_iter_get_position (iter1));
1093	    g_assert (g_sequence_iter_get_position (iter2) >=
1094		      g_sequence_iter_get_position (iter3));
1095	  }
1096	  break;
1097
1098	}
1099
1100      check_integrity (seq);
1101    }
1102}
1103
1104/* Random seeds known to have failed at one point
1105 */
1106static gulong seeds[] =
1107  {
1108    825541564u,
1109    801678400u,
1110    1477639090u,
1111    3369132895u,
1112    1192944867u,
1113    770458294u,
1114    1099575817u,
1115    590523467u,
1116    3583571454u,
1117    579241222u
1118  };
1119
1120static void standalone_tests (void);
1121
1122static guint32
1123get_seed (int argc, char **argv)
1124{
1125  if (argc > 1)
1126    {
1127      char *endptr;
1128
1129      return strtol (argv[1], &endptr, 0);
1130    }
1131  else
1132    {
1133      return g_random_int();
1134    }
1135}
1136
1137int
1138main (int argc,
1139      char **argv)
1140{
1141  guint32 seed = get_seed (argc, argv);
1142  int i;
1143
1144  /* Run stand alone tests */
1145  g_print ("running standalone tests\n");
1146  standalone_tests();
1147
1148  g_print ("running regression tests:\n");
1149  /* Run regression tests */
1150  for (i = 0; i < G_N_ELEMENTS (seeds); ++i)
1151    {
1152      run_random_tests (seeds[i]);
1153    }
1154
1155  /* Run with a new random seed */
1156  g_print ("random seed:\n");
1157  run_random_tests (seed);
1158
1159
1160  return 0;
1161}
1162
1163
1164/* Single, stand-alone tests */
1165
1166static void
1167test_out_of_range_jump (void)
1168{
1169  GSequence *seq = g_sequence_new (NULL);
1170  GSequenceIter *iter = g_sequence_get_begin_iter (seq);
1171
1172  g_sequence_iter_move (iter, 5);
1173
1174  g_assert (g_sequence_iter_is_begin (iter));
1175  g_assert (g_sequence_iter_is_end (iter));
1176}
1177
1178static int
1179compare (gconstpointer a, gconstpointer b, gpointer userdata)
1180{
1181  int ai, bi;
1182
1183  ai = GPOINTER_TO_INT (a);
1184  bi = GPOINTER_TO_INT (b);
1185
1186  if (ai < bi)
1187    return -1;
1188  else if (ai > bi)
1189    return 1;
1190  else
1191    return 0;
1192}
1193
1194static int
1195compare_iter (GSequenceIter *a,
1196	      GSequenceIter *b,
1197	      gpointer data)
1198{
1199  return compare (g_sequence_get (a),
1200		  g_sequence_get (b),
1201		  data);
1202}
1203
1204static void
1205test_insert_sorted_non_pointer (void)
1206{
1207  int i;
1208
1209  for (i = 0; i < 10; i++)
1210    {
1211      GSequence *seq = g_sequence_new (NULL);
1212      int j;
1213
1214      for (j = 0; j < 10000; j++)
1215	{
1216	  g_sequence_insert_sorted (seq, GINT_TO_POINTER (g_random_int()),
1217				    compare, NULL);
1218
1219	  g_sequence_insert_sorted_iter (seq, GINT_TO_POINTER (g_random_int()),
1220					 compare_iter, NULL);
1221	}
1222
1223      g_sequence_check (seq);
1224
1225      g_sequence_free (seq);
1226    }
1227}
1228
1229static void
1230test_stable_sort (void)
1231{
1232  int i;
1233  GSequence *seq = g_sequence_new (NULL);
1234
1235#define N_ITEMS 1000
1236
1237  GSequenceIter *iters[N_ITEMS];
1238  GSequenceIter *iter;
1239
1240  for (i = 0; i < N_ITEMS; ++i)
1241    {
1242      iters[i] = g_sequence_append (seq, GINT_TO_POINTER (3000));
1243      g_sequence_check (seq);
1244      g_assert (g_sequence_iter_get_sequence (iters[i]) == seq);
1245   }
1246
1247  i = 0;
1248  iter = g_sequence_get_begin_iter (seq);
1249  g_assert (g_sequence_iter_get_sequence (iter) == seq);
1250  g_sequence_check (seq);
1251  while (!g_sequence_iter_is_end (iter))
1252    {
1253      g_assert (g_sequence_iter_get_sequence (iters[i]) == seq);
1254      g_assert (iters[i++] == iter);
1255
1256      iter = g_sequence_iter_next (iter);
1257      g_sequence_check (seq);
1258    }
1259
1260  g_sequence_sort (seq, compare, NULL);
1261
1262  i = 0;
1263  iter = g_sequence_get_begin_iter (seq);
1264  while (!g_sequence_iter_is_end (iter))
1265    {
1266      g_assert (g_sequence_iter_get_sequence (iters[i]) == seq);
1267      g_assert (iters[i] == iter);
1268
1269      iter = g_sequence_iter_next (iter);
1270      g_sequence_check (seq);
1271
1272      i++;
1273    }
1274
1275  for (i = N_ITEMS - 1; i >= 0; --i)
1276    {
1277      g_sequence_check (seq);
1278      g_assert (g_sequence_iter_get_sequence (iters[i]) == seq);
1279      g_assert (g_sequence_get_end_iter (seq) != iters[i]);
1280      g_sequence_sort_changed (iters[i], compare, NULL);
1281    }
1282
1283  i = 0;
1284  iter = g_sequence_get_begin_iter (seq);
1285  while (!g_sequence_iter_is_end (iter))
1286    {
1287      g_assert (iters[i++] == iter);
1288
1289      iter = g_sequence_iter_next (iter);
1290      g_sequence_check (seq);
1291    }
1292}
1293
1294static void
1295standalone_tests (void)
1296{
1297  test_out_of_range_jump ();
1298  test_insert_sorted_non_pointer ();
1299  test_stable_sort ();
1300}
1301
1302