Imported Upstream version 2.57.2
[platform/upstream/glib.git] / glib / tests / array-test.c
1 /* GLIB - Library of useful routines for C programming
2  * Copyright (C) 1995-1997  Peter Mattis, Spencer Kimball and Josh MacDonald
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2.1 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, see <http://www.gnu.org/licenses/>.
16  */
17
18 /*
19  * Modified by the GLib Team and others 1997-2000.  See the AUTHORS
20  * file for a list of people on the GLib Team.  See the ChangeLog
21  * files for a list of changes.  These files are distributed with
22  * GLib at ftp://ftp.gtk.org/pub/gtk/. 
23  */
24
25 #undef G_DISABLE_ASSERT
26 #undef G_LOG_DOMAIN
27
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <string.h>
31 #include "glib.h"
32
33 /* Test data to be passed to any function which calls g_array_new(), providing
34  * the parameters for that call. Most #GArray tests should be repeated for all
35  * possible values of #ArrayTestData. */
36 typedef struct
37 {
38   gboolean zero_terminated;
39   gboolean clear_;
40 } ArrayTestData;
41
42 /* Assert that @garray contains @n_expected_elements as given in @expected_data.
43  * @garray must contain #gint elements. */
44 static void
45 assert_int_array_equal (GArray     *garray,
46                         const gint *expected_data,
47                         gsize       n_expected_elements)
48 {
49   gsize i;
50
51   g_assert_cmpuint (garray->len, ==, n_expected_elements);
52   for (i = 0; i < garray->len; i++)
53     g_assert_cmpint (g_array_index (garray, gint, i), ==, expected_data[i]);
54 }
55
56 /* Iff config->zero_terminated is %TRUE, assert that the final element of
57  * @garray is zero. @garray must contain #gint elements. */
58 static void
59 assert_int_array_zero_terminated (const ArrayTestData *config,
60                                   GArray              *garray)
61 {
62   if (config->zero_terminated)
63     {
64       gint *data = (gint *) garray->data;
65       g_assert_cmpint (data[garray->len], ==, 0);
66     }
67 }
68
69 static void
70 sum_up (gpointer data,
71         gpointer user_data)
72 {
73   gint *sum = (gint *)user_data;
74
75   *sum += GPOINTER_TO_INT (data);
76 }
77
78 /* Check that expanding an array with g_array_set_size() clears the new elements
79  * if @clear_ was specified during construction. */
80 static void
81 array_set_size (gconstpointer test_data)
82 {
83   const ArrayTestData *config = test_data;
84   GArray *garray;
85   gsize i;
86
87   garray = g_array_new (config->zero_terminated, config->clear_, sizeof (gint));
88   g_assert_cmpuint (garray->len, ==, 0);
89   assert_int_array_zero_terminated (config, garray);
90
91   g_array_set_size (garray, 5);
92   g_assert_cmpuint (garray->len, ==, 5);
93   assert_int_array_zero_terminated (config, garray);
94
95   if (config->clear_)
96     for (i = 0; i < 5; i++)
97       g_assert_cmpint (g_array_index (garray, gint, i), ==, 0);
98
99   g_array_unref (garray);
100 }
101
102 /* As with array_set_size(), but with a sized array. */
103 static void
104 array_set_size_sized (gconstpointer test_data)
105 {
106   const ArrayTestData *config = test_data;
107   GArray *garray;
108   gsize i;
109
110   garray = g_array_sized_new (config->zero_terminated, config->clear_, sizeof (gint), 10);
111   g_assert_cmpuint (garray->len, ==, 0);
112   assert_int_array_zero_terminated (config, garray);
113
114   g_array_set_size (garray, 5);
115   g_assert_cmpuint (garray->len, ==, 5);
116   assert_int_array_zero_terminated (config, garray);
117
118   if (config->clear_)
119     for (i = 0; i < 5; i++)
120       g_assert_cmpint (g_array_index (garray, gint, i), ==, 0);
121
122   g_array_unref (garray);
123 }
124
125 /* Check that a zero-terminated array does actually have a zero terminator. */
126 static void
127 array_new_zero_terminated (void)
128 {
129   GArray *garray;
130   gchar *out_str = NULL;
131
132   garray = g_array_new (TRUE, FALSE, sizeof (gchar));
133   g_assert_cmpuint (garray->len, ==, 0);
134
135   g_array_append_vals (garray, "hello", strlen ("hello"));
136   g_assert_cmpuint (garray->len, ==, 5);
137   g_assert_cmpstr (garray->data, ==, "hello");
138
139   out_str = g_array_free (garray, FALSE);
140   g_assert_cmpstr (out_str, ==, "hello");
141   g_free (out_str);
142 }
143
144 /* Check that g_array_append_val() works correctly for various #GArray
145  * configurations. */
146 static void
147 array_append_val (gconstpointer test_data)
148 {
149   const ArrayTestData *config = test_data;
150   GArray *garray;
151   gint i;
152   gint *segment;
153
154   garray = g_array_new (config->zero_terminated, config->clear_, sizeof (gint));
155   for (i = 0; i < 10000; i++)
156     g_array_append_val (garray, i);
157   assert_int_array_zero_terminated (config, garray);
158
159   for (i = 0; i < 10000; i++)
160     g_assert_cmpint (g_array_index (garray, gint, i), ==, i);
161
162   segment = (gint*)g_array_free (garray, FALSE);
163   for (i = 0; i < 10000; i++)
164     g_assert_cmpint (segment[i], ==, i);
165   if (config->zero_terminated)
166     g_assert_cmpint (segment[10000], ==, 0);
167
168   g_free (segment);
169 }
170
171 /* Check that g_array_prepend_val() works correctly for various #GArray
172  * configurations. */
173 static void
174 array_prepend_val (gconstpointer test_data)
175 {
176   const ArrayTestData *config = test_data;
177   GArray *garray;
178   gint i;
179
180   garray = g_array_new (config->zero_terminated, config->clear_, sizeof (gint));
181   for (i = 0; i < 100; i++)
182     g_array_prepend_val (garray, i);
183   assert_int_array_zero_terminated (config, garray);
184
185   for (i = 0; i < 100; i++)
186     g_assert_cmpint (g_array_index (garray, gint, i), ==, (100 - i - 1));
187
188   g_array_free (garray, TRUE);
189 }
190
191 /* Test that g_array_prepend_vals() works correctly with various array
192  * configurations. */
193 static void
194 array_prepend_vals (gconstpointer test_data)
195 {
196   const ArrayTestData *config = test_data;
197   GArray *garray, *garray_out;
198   const gint vals[] = { 0, 1, 2, 3, 4 };
199   const gint expected_vals1[] = { 0, 1 };
200   const gint expected_vals2[] = { 2, 0, 1 };
201   const gint expected_vals3[] = { 3, 4, 2, 0, 1 };
202
203   /* Set up an array. */
204   garray = g_array_new (config->zero_terminated, config->clear_, sizeof (gint));
205   assert_int_array_zero_terminated (config, garray);
206
207   /* Prepend several values to an empty array. */
208   garray_out = g_array_prepend_vals (garray, vals, 2);
209   g_assert_true (garray == garray_out);
210   assert_int_array_equal (garray, expected_vals1, G_N_ELEMENTS (expected_vals1));
211   assert_int_array_zero_terminated (config, garray);
212
213   /* Prepend a single value. */
214   garray_out = g_array_prepend_vals (garray, vals + 2, 1);
215   g_assert_true (garray == garray_out);
216   assert_int_array_equal (garray, expected_vals2, G_N_ELEMENTS (expected_vals2));
217   assert_int_array_zero_terminated (config, garray);
218
219   /* Prepend several values to a non-empty array. */
220   garray_out = g_array_prepend_vals (garray, vals + 3, 2);
221   g_assert_true (garray == garray_out);
222   assert_int_array_equal (garray, expected_vals3, G_N_ELEMENTS (expected_vals3));
223   assert_int_array_zero_terminated (config, garray);
224
225   /* Prepend no values. */
226   garray_out = g_array_prepend_vals (garray, vals, 0);
227   g_assert_true (garray == garray_out);
228   assert_int_array_equal (garray, expected_vals3, G_N_ELEMENTS (expected_vals3));
229   assert_int_array_zero_terminated (config, garray);
230
231   /* Prepend no values with %NULL data. */
232   garray_out = g_array_prepend_vals (garray, NULL, 0);
233   g_assert_true (garray == garray_out);
234   assert_int_array_equal (garray, expected_vals3, G_N_ELEMENTS (expected_vals3));
235   assert_int_array_zero_terminated (config, garray);
236
237   g_array_free (garray, TRUE);
238 }
239
240 /* Test that g_array_insert_vals() works correctly with various array
241  * configurations. */
242 static void
243 array_insert_vals (gconstpointer test_data)
244 {
245   const ArrayTestData *config = test_data;
246   GArray *garray, *garray_out;
247   gsize i;
248   const gint vals[] = { 0, 1, 2, 3, 4, 5, 6, 7 };
249   const gint expected_vals1[] = { 0, 1 };
250   const gint expected_vals2[] = { 0, 2, 3, 1 };
251   const gint expected_vals3[] = { 0, 2, 3, 1, 4 };
252   const gint expected_vals4[] = { 5, 0, 2, 3, 1, 4 };
253   const gint expected_vals5[] = { 5, 0, 2, 3, 1, 4, 0, 0, 0, 0, 6, 7 };
254
255   /* Set up an array. */
256   garray = g_array_new (config->zero_terminated, config->clear_, sizeof (gint));
257   assert_int_array_zero_terminated (config, garray);
258
259   /* Insert several values at the beginning. */
260   garray_out = g_array_insert_vals (garray, 0, vals, 2);
261   g_assert_true (garray == garray_out);
262   assert_int_array_equal (garray, expected_vals1, G_N_ELEMENTS (expected_vals1));
263   assert_int_array_zero_terminated (config, garray);
264
265   /* Insert some more part-way through. */
266   garray_out = g_array_insert_vals (garray, 1, vals + 2, 2);
267   g_assert_true (garray == garray_out);
268   assert_int_array_equal (garray, expected_vals2, G_N_ELEMENTS (expected_vals2));
269   assert_int_array_zero_terminated (config, garray);
270
271   /* And at the end. */
272   garray_out = g_array_insert_vals (garray, garray->len, vals + 4, 1);
273   g_assert_true (garray == garray_out);
274   assert_int_array_equal (garray, expected_vals3, G_N_ELEMENTS (expected_vals3));
275   assert_int_array_zero_terminated (config, garray);
276
277   /* Then back at the beginning again. */
278   garray_out = g_array_insert_vals (garray, 0, vals + 5, 1);
279   g_assert_true (garray == garray_out);
280   assert_int_array_equal (garray, expected_vals4, G_N_ELEMENTS (expected_vals4));
281   assert_int_array_zero_terminated (config, garray);
282
283   /* Insert zero elements. */
284   garray_out = g_array_insert_vals (garray, 0, vals, 0);
285   g_assert_true (garray == garray_out);
286   assert_int_array_equal (garray, expected_vals4, G_N_ELEMENTS (expected_vals4));
287   assert_int_array_zero_terminated (config, garray);
288
289   /* Insert zero elements with a %NULL pointer. */
290   garray_out = g_array_insert_vals (garray, 0, NULL, 0);
291   g_assert_true (garray == garray_out);
292   assert_int_array_equal (garray, expected_vals4, G_N_ELEMENTS (expected_vals4));
293   assert_int_array_zero_terminated (config, garray);
294
295   /* Insert some elements off the end of the array. The behaviour here depends
296    * on whether the array clears entries. */
297   garray_out = g_array_insert_vals (garray, garray->len + 4, vals + 6, 2);
298   g_assert_true (garray == garray_out);
299
300   g_assert_cmpuint (garray->len, ==, G_N_ELEMENTS (expected_vals5));
301   for (i = 0; i < G_N_ELEMENTS (expected_vals5); i++)
302     {
303       if (config->clear_ || i < 6 || i > 9)
304         g_assert_cmpint (g_array_index (garray, gint, i), ==, expected_vals5[i]);
305     }
306
307   assert_int_array_zero_terminated (config, garray);
308
309   g_array_free (garray, TRUE);
310 }
311
312 /* Check that g_array_remove_index() works correctly for various #GArray
313  * configurations. */
314 static void
315 array_remove_index (gconstpointer test_data)
316 {
317   const ArrayTestData *config = test_data;
318   GArray *garray;
319   gint i;
320   gint prev, cur;
321
322   garray = g_array_new (config->zero_terminated, config->clear_, sizeof (gint));
323   for (i = 0; i < 100; i++)
324     g_array_append_val (garray, i);
325   assert_int_array_zero_terminated (config, garray);
326
327   g_assert_cmpint (garray->len, ==, 100);
328
329   g_array_remove_index (garray, 1);
330   g_array_remove_index (garray, 3);
331   g_array_remove_index (garray, 21);
332   g_array_remove_index (garray, 57);
333
334   g_assert_cmpint (garray->len, ==, 96);
335   assert_int_array_zero_terminated (config, garray);
336
337   prev = -1;
338   for (i = 0; i < garray->len; i++)
339     {
340       cur = g_array_index (garray, gint, i);
341       g_assert (cur != 1 &&  cur != 4 && cur != 23 && cur != 60);
342       g_assert_cmpint (prev, <, cur);
343       prev = cur;
344     }
345
346   g_array_free (garray, TRUE);
347 }
348
349 /* Check that g_array_remove_index_fast() works correctly for various #GArray
350  * configurations. */
351 static void
352 array_remove_index_fast (gconstpointer test_data)
353 {
354   const ArrayTestData *config = test_data;
355   GArray *garray;
356   gint i;
357   gint prev, cur;
358
359   garray = g_array_new (config->zero_terminated, config->clear_, sizeof (gint));
360   for (i = 0; i < 100; i++)
361     g_array_append_val (garray, i);
362
363   g_assert_cmpint (garray->len, ==, 100);
364   assert_int_array_zero_terminated (config, garray);
365
366   g_array_remove_index_fast (garray, 1);
367   g_array_remove_index_fast (garray, 3);
368   g_array_remove_index_fast (garray, 21);
369   g_array_remove_index_fast (garray, 57);
370
371   g_assert_cmpint (garray->len, ==, 96);
372   assert_int_array_zero_terminated (config, garray);
373
374   prev = -1;
375   for (i = 0; i < garray->len; i++)
376     {
377       cur = g_array_index (garray, gint, i);
378       g_assert (cur != 1 &&  cur != 3 && cur != 21 && cur != 57);
379       if (cur < 96)
380         {
381           g_assert_cmpint (prev, <, cur);
382           prev = cur;
383         }
384     }
385
386   g_array_free (garray, TRUE);
387 }
388
389 /* Check that g_array_remove_range() works correctly for various #GArray
390  * configurations. */
391 static void
392 array_remove_range (gconstpointer test_data)
393 {
394   const ArrayTestData *config = test_data;
395   GArray *garray;
396   gint i;
397   gint prev, cur;
398
399   garray = g_array_new (config->zero_terminated, config->clear_, sizeof (gint));
400   for (i = 0; i < 100; i++)
401     g_array_append_val (garray, i);
402
403   g_assert_cmpint (garray->len, ==, 100);
404   assert_int_array_zero_terminated (config, garray);
405
406   g_array_remove_range (garray, 31, 4);
407
408   g_assert_cmpint (garray->len, ==, 96);
409   assert_int_array_zero_terminated (config, garray);
410
411   prev = -1;
412   for (i = 0; i < garray->len; i++)
413     {
414       cur = g_array_index (garray, gint, i);
415       g_assert (cur < 31 || cur > 34);
416       g_assert_cmpint (prev, <, cur);
417       prev = cur;
418     }
419
420   /* Ensure the entire array can be cleared, even when empty. */
421   g_array_remove_range (garray, 0, garray->len);
422
423   g_assert_cmpint (garray->len, ==, 0);
424   assert_int_array_zero_terminated (config, garray);
425
426   g_array_remove_range (garray, 0, garray->len);
427
428   g_assert_cmpint (garray->len, ==, 0);
429   assert_int_array_zero_terminated (config, garray);
430
431   g_array_free (garray, TRUE);
432 }
433
434 static void
435 array_ref_count (void)
436 {
437   GArray *garray;
438   GArray *garray2;
439   gint i;
440
441   garray = g_array_new (FALSE, FALSE, sizeof (gint));
442   g_assert_cmpint (g_array_get_element_size (garray), ==, sizeof (gint));
443   for (i = 0; i < 100; i++)
444     g_array_prepend_val (garray, i);
445
446   /* check we can ref, unref and still access the array */
447   garray2 = g_array_ref (garray);
448   g_assert (garray == garray2);
449   g_array_unref (garray2);
450   for (i = 0; i < 100; i++)
451     g_assert_cmpint (g_array_index (garray, gint, i), ==, (100 - i - 1));
452
453   /* garray2 should be an empty valid GArray wrapper */
454   garray2 = g_array_ref (garray);
455   g_array_free (garray, TRUE);
456
457   g_assert_cmpint (garray2->len, ==, 0);
458   g_array_unref (garray2);
459 }
460
461 static int
462 int_compare (gconstpointer p1, gconstpointer p2)
463 {
464   const gint *i1 = p1;
465   const gint *i2 = p2;
466
467   return *i1 - *i2;
468 }
469
470 static int
471 int_compare_data (gconstpointer p1, gconstpointer p2, gpointer data)
472 {
473   const gint *i1 = p1;
474   const gint *i2 = p2;
475
476   return *i1 - *i2;
477 }
478
479 /* Check that g_array_sort() works correctly for various #GArray
480  * configurations. */
481 static void
482 array_sort (gconstpointer test_data)
483 {
484   const ArrayTestData *config = test_data;
485   GArray *garray;
486   gint i;
487   gint prev, cur;
488
489   garray = g_array_new (config->zero_terminated, config->clear_, sizeof (gint));
490   for (i = 0; i < 10000; i++)
491     {
492       cur = g_random_int_range (0, 10000);
493       g_array_append_val (garray, cur);
494     }
495   assert_int_array_zero_terminated (config, garray);
496
497   g_array_sort (garray, int_compare);
498   assert_int_array_zero_terminated (config, garray);
499
500   prev = -1;
501   for (i = 0; i < garray->len; i++)
502     {
503       cur = g_array_index (garray, gint, i);
504       g_assert_cmpint (prev, <=, cur);
505       prev = cur;
506     }
507
508   g_array_free (garray, TRUE);
509 }
510
511 /* Check that g_array_sort_with_data() works correctly for various #GArray
512  * configurations. */
513 static void
514 array_sort_with_data (gconstpointer test_data)
515 {
516   const ArrayTestData *config = test_data;
517   GArray *garray;
518   gint i;
519   gint prev, cur;
520
521   garray = g_array_new (config->zero_terminated, config->clear_, sizeof (gint));
522   for (i = 0; i < 10000; i++)
523     {
524       cur = g_random_int_range (0, 10000);
525       g_array_append_val (garray, cur);
526     }
527   assert_int_array_zero_terminated (config, garray);
528
529   g_array_sort_with_data (garray, int_compare_data, NULL);
530   assert_int_array_zero_terminated (config, garray);
531
532   prev = -1;
533   for (i = 0; i < garray->len; i++)
534     {
535       cur = g_array_index (garray, gint, i);
536       g_assert_cmpint (prev, <=, cur);
537       prev = cur;
538     }
539
540   g_array_free (garray, TRUE);
541 }
542
543 static gint num_clear_func_invocations = 0;
544
545 static void
546 my_clear_func (gpointer data)
547 {
548   num_clear_func_invocations += 1;
549 }
550
551 static void
552 array_clear_func (void)
553 {
554   GArray *garray;
555   gint i;
556   gint cur;
557
558   garray = g_array_new (FALSE, FALSE, sizeof (gint));
559   g_array_set_clear_func (garray, my_clear_func);
560
561   for (i = 0; i < 10; i++)
562     {
563       cur = g_random_int_range (0, 100);
564       g_array_append_val (garray, cur);
565     }
566
567   g_array_remove_index (garray, 9);
568   g_assert_cmpint (num_clear_func_invocations, ==, 1);
569
570   g_array_remove_range (garray, 5, 3);
571   g_assert_cmpint (num_clear_func_invocations, ==, 4);
572
573   g_array_remove_index_fast (garray, 4);
574   g_assert_cmpint (num_clear_func_invocations, ==, 5);
575
576   g_array_free (garray, TRUE);
577   g_assert_cmpint (num_clear_func_invocations, ==, 10);
578 }
579
580 static void
581 pointer_array_add (void)
582 {
583   GPtrArray *gparray;
584   gint i;
585   gint sum = 0;
586   gpointer *segment;
587
588   gparray = g_ptr_array_sized_new (1000);
589
590   for (i = 0; i < 10000; i++)
591     g_ptr_array_add (gparray, GINT_TO_POINTER (i));
592
593   for (i = 0; i < 10000; i++)
594     g_assert (g_ptr_array_index (gparray, i) == GINT_TO_POINTER (i));
595   
596   g_ptr_array_foreach (gparray, sum_up, &sum);
597   g_assert (sum == 49995000);
598
599   segment = g_ptr_array_free (gparray, FALSE);
600   for (i = 0; i < 10000; i++)
601     g_assert (segment[i] == GINT_TO_POINTER (i));
602   g_free (segment);
603 }
604
605 static void
606 pointer_array_insert (void)
607 {
608   GPtrArray *gparray;
609   gint i;
610   gint sum = 0;
611   gint index;
612
613   gparray = g_ptr_array_sized_new (1000);
614
615   for (i = 0; i < 10000; i++)
616     {
617       index = g_random_int_range (-1, i + 1);
618       g_ptr_array_insert (gparray, index, GINT_TO_POINTER (i));
619     }
620
621   g_ptr_array_foreach (gparray, sum_up, &sum);
622   g_assert (sum == 49995000);
623
624   g_ptr_array_free (gparray, TRUE);
625 }
626
627 static void
628 pointer_array_ref_count (void)
629 {
630   GPtrArray *gparray;
631   GPtrArray *gparray2;
632   gint i;
633   gint sum = 0;
634
635   gparray = g_ptr_array_new ();
636   for (i = 0; i < 10000; i++)
637     g_ptr_array_add (gparray, GINT_TO_POINTER (i));
638
639   /* check we can ref, unref and still access the array */
640   gparray2 = g_ptr_array_ref (gparray);
641   g_assert (gparray == gparray2);
642   g_ptr_array_unref (gparray2);
643   for (i = 0; i < 10000; i++)
644     g_assert (g_ptr_array_index (gparray, i) == GINT_TO_POINTER (i));
645
646   g_ptr_array_foreach (gparray, sum_up, &sum);
647   g_assert (sum == 49995000);
648
649   /* gparray2 should be an empty valid GPtrArray wrapper */
650   gparray2 = g_ptr_array_ref (gparray);
651   g_ptr_array_free (gparray, TRUE);
652
653   g_assert_cmpint (gparray2->len, ==, 0);
654   g_ptr_array_unref (gparray2);
655 }
656
657 static gint num_free_func_invocations = 0;
658
659 static void
660 my_free_func (gpointer data)
661 {
662   num_free_func_invocations++;
663   g_free (data);
664 }
665
666 static void
667 pointer_array_free_func (void)
668 {
669   GPtrArray *gparray;
670   GPtrArray *gparray2;
671   gchar **strv;
672   gchar *s;
673
674   num_free_func_invocations = 0;
675   gparray = g_ptr_array_new_with_free_func (my_free_func);
676   g_ptr_array_unref (gparray);
677   g_assert_cmpint (num_free_func_invocations, ==, 0);
678
679   gparray = g_ptr_array_new_with_free_func (my_free_func);
680   g_ptr_array_free (gparray, TRUE);
681   g_assert_cmpint (num_free_func_invocations, ==, 0);
682
683   num_free_func_invocations = 0;
684   gparray = g_ptr_array_new_with_free_func (my_free_func);
685   g_ptr_array_add (gparray, g_strdup ("foo"));
686   g_ptr_array_add (gparray, g_strdup ("bar"));
687   g_ptr_array_add (gparray, g_strdup ("baz"));
688   g_ptr_array_remove_index (gparray, 0);
689   g_assert_cmpint (num_free_func_invocations, ==, 1);
690   g_ptr_array_remove_index_fast (gparray, 1);
691   g_assert_cmpint (num_free_func_invocations, ==, 2);
692   s = g_strdup ("frob");
693   g_ptr_array_add (gparray, s);
694   g_assert (g_ptr_array_remove (gparray, s));
695   g_assert (!g_ptr_array_remove (gparray, "nuun"));
696   g_assert (!g_ptr_array_remove_fast (gparray, "mlo"));
697   g_assert_cmpint (num_free_func_invocations, ==, 3);
698   s = g_strdup ("frob");
699   g_ptr_array_add (gparray, s);
700   g_ptr_array_set_size (gparray, 1);
701   g_assert_cmpint (num_free_func_invocations, ==, 4);
702   g_ptr_array_ref (gparray);
703   g_ptr_array_unref (gparray);
704   g_assert_cmpint (num_free_func_invocations, ==, 4);
705   g_ptr_array_unref (gparray);
706   g_assert_cmpint (num_free_func_invocations, ==, 5);
707
708   num_free_func_invocations = 0;
709   gparray = g_ptr_array_new_full (10, my_free_func);
710   g_ptr_array_add (gparray, g_strdup ("foo"));
711   g_ptr_array_add (gparray, g_strdup ("bar"));
712   g_ptr_array_add (gparray, g_strdup ("baz"));
713   g_ptr_array_set_size (gparray, 20);
714   g_ptr_array_add (gparray, NULL);
715   gparray2 = g_ptr_array_ref (gparray);
716   strv = (gchar **) g_ptr_array_free (gparray, FALSE);
717   g_assert_cmpint (num_free_func_invocations, ==, 0);
718   g_strfreev (strv);
719   g_ptr_array_unref (gparray2);
720   g_assert_cmpint (num_free_func_invocations, ==, 0);
721
722   num_free_func_invocations = 0;
723   gparray = g_ptr_array_new_with_free_func (my_free_func);
724   g_ptr_array_add (gparray, g_strdup ("foo"));
725   g_ptr_array_add (gparray, g_strdup ("bar"));
726   g_ptr_array_add (gparray, g_strdup ("baz"));
727   g_ptr_array_remove_range (gparray, 1, 1);
728   g_ptr_array_unref (gparray);
729   g_assert_cmpint (num_free_func_invocations, ==, 3);
730
731   num_free_func_invocations = 0;
732   gparray = g_ptr_array_new_with_free_func (my_free_func);
733   g_ptr_array_add (gparray, g_strdup ("foo"));
734   g_ptr_array_add (gparray, g_strdup ("bar"));
735   g_ptr_array_add (gparray, g_strdup ("baz"));
736   g_ptr_array_free (gparray, TRUE);
737   g_assert_cmpint (num_free_func_invocations, ==, 3);
738
739   num_free_func_invocations = 0;
740   gparray = g_ptr_array_new_with_free_func (my_free_func);
741   g_ptr_array_add (gparray, "foo");
742   g_ptr_array_add (gparray, "bar");
743   g_ptr_array_add (gparray, "baz");
744   g_ptr_array_set_free_func (gparray, NULL);
745   g_ptr_array_free (gparray, TRUE);
746   g_assert_cmpint (num_free_func_invocations, ==, 0);
747 }
748
749 static gint
750 ptr_compare (gconstpointer p1, gconstpointer p2)
751 {
752   gpointer i1 = *(gpointer*)p1;
753   gpointer i2 = *(gpointer*)p2;
754
755   return GPOINTER_TO_INT (i1) - GPOINTER_TO_INT (i2);
756 }
757
758 static gint
759 ptr_compare_data (gconstpointer p1, gconstpointer p2, gpointer data)
760 {
761   gpointer i1 = *(gpointer*)p1;
762   gpointer i2 = *(gpointer*)p2;
763
764   return GPOINTER_TO_INT (i1) - GPOINTER_TO_INT (i2);
765 }
766
767 static void
768 pointer_array_sort (void)
769 {
770   GPtrArray *gparray;
771   gint i;
772   gint val;
773   gint prev, cur;
774
775   gparray = g_ptr_array_new ();
776   for (i = 0; i < 10000; i++)
777     {
778       val = g_random_int_range (0, 10000);
779       g_ptr_array_add (gparray, GINT_TO_POINTER (val));
780     }
781
782   g_ptr_array_sort (gparray, ptr_compare);
783
784   prev = -1;
785   for (i = 0; i < 10000; i++)
786     {
787       cur = GPOINTER_TO_INT (g_ptr_array_index (gparray, i));
788       g_assert_cmpint (prev, <=, cur);
789       prev = cur;
790     }
791
792   g_ptr_array_free (gparray, TRUE);
793 }
794
795 static void
796 pointer_array_sort_with_data (void)
797 {
798   GPtrArray *gparray;
799   gint i;
800   gint prev, cur;
801
802   gparray = g_ptr_array_new ();
803   for (i = 0; i < 10000; i++)
804     g_ptr_array_add (gparray, GINT_TO_POINTER (g_random_int_range (0, 10000)));
805
806   g_ptr_array_sort_with_data (gparray, ptr_compare_data, NULL);
807
808   prev = -1;
809   for (i = 0; i < 10000; i++)
810     {
811       cur = GPOINTER_TO_INT (g_ptr_array_index (gparray, i));
812       g_assert_cmpint (prev, <=, cur);
813       prev = cur;
814     }
815
816   g_ptr_array_free (gparray, TRUE);
817 }
818
819 static void
820 pointer_array_find_empty (void)
821 {
822   GPtrArray *array;
823   guint idx;
824
825   array = g_ptr_array_new ();
826
827   g_assert_false (g_ptr_array_find (array, "some-value", NULL));  /* NULL index */
828   g_assert_false (g_ptr_array_find (array, "some-value", &idx));  /* non-NULL index */
829   g_assert_false (g_ptr_array_find_with_equal_func (array, "some-value", g_str_equal, NULL));  /* NULL index */
830   g_assert_false (g_ptr_array_find_with_equal_func (array, "some-value", g_str_equal, &idx));  /* non-NULL index */
831
832   g_ptr_array_free (array, TRUE);
833 }
834
835 static void
836 pointer_array_find_non_empty (void)
837 {
838   GPtrArray *array;
839   guint idx;
840   const gchar *str_pointer = "static-string";
841
842   array = g_ptr_array_new ();
843
844   g_ptr_array_add (array, "some");
845   g_ptr_array_add (array, "random");
846   g_ptr_array_add (array, "values");
847   g_ptr_array_add (array, "some");
848   g_ptr_array_add (array, "duplicated");
849   g_ptr_array_add (array, (gpointer) str_pointer);
850
851   g_assert_true (g_ptr_array_find_with_equal_func (array, "random", g_str_equal, NULL));  /* NULL index */
852   g_assert_true (g_ptr_array_find_with_equal_func (array, "random", g_str_equal, &idx));  /* non-NULL index */
853   g_assert_cmpuint (idx, ==, 1);
854
855   g_assert_true (g_ptr_array_find_with_equal_func (array, "some", g_str_equal, &idx));  /* duplicate element */
856   g_assert_cmpuint (idx, ==, 0);
857
858   g_assert_false (g_ptr_array_find_with_equal_func (array, "nope", g_str_equal, NULL));
859
860   g_assert_true (g_ptr_array_find_with_equal_func (array, str_pointer, g_str_equal, &idx));
861   g_assert_cmpuint (idx, ==, 5);
862   idx = G_MAXUINT;
863   g_assert_true (g_ptr_array_find_with_equal_func (array, str_pointer, NULL, &idx));  /* NULL equal func */
864   g_assert_cmpuint (idx, ==, 5);
865   idx = G_MAXUINT;
866   g_assert_true (g_ptr_array_find (array, str_pointer, &idx));  /* NULL equal func */
867   g_assert_cmpuint (idx, ==, 5);
868
869   g_ptr_array_free (array, TRUE);
870 }
871
872 static void
873 steal_destroy_notify (gpointer data)
874 {
875   guint *counter = data;
876   *counter = *counter + 1;
877 }
878
879 /* Test that g_ptr_array_steal_index() and g_ptr_array_steal_index_fast() can
880  * remove elements from a pointer array without the #GDestroyNotify being called. */
881 static void
882 pointer_array_steal (void)
883 {
884   guint i1 = 0, i2 = 0, i3 = 0, i4 = 0;
885   gpointer out1, out2;
886   GPtrArray *array = g_ptr_array_new_with_free_func (steal_destroy_notify);
887
888   g_ptr_array_add (array, &i1);
889   g_ptr_array_add (array, &i2);
890   g_ptr_array_add (array, &i3);
891   g_ptr_array_add (array, &i4);
892
893   g_assert_cmpuint (array->len, ==, 4);
894
895   /* Remove a single element. */
896   out1 = g_ptr_array_steal_index (array, 0);
897   g_assert_true (out1 == &i1);
898   g_assert_cmpuint (i1, ==, 0);  /* should not have been destroyed */
899
900   /* Following elements should have been moved down. */
901   g_assert_cmpuint (array->len, ==, 3);
902   g_assert_true (g_ptr_array_index (array, 0) == &i2);
903   g_assert_true (g_ptr_array_index (array, 1) == &i3);
904   g_assert_true (g_ptr_array_index (array, 2) == &i4);
905
906   /* Remove another element, quickly. */
907   out2 = g_ptr_array_steal_index_fast (array, 0);
908   g_assert_true (out2 == &i2);
909   g_assert_cmpuint (i2, ==, 0);  /* should not have been destroyed */
910
911   /* Last element should have been swapped in place. */
912   g_assert_cmpuint (array->len, ==, 2);
913   g_assert_true (g_ptr_array_index (array, 0) == &i4);
914   g_assert_true (g_ptr_array_index (array, 1) == &i3);
915
916   /* Check that destroying the pointer array doesn’t affect the stolen elements. */
917   g_ptr_array_unref (array);
918
919   g_assert_cmpuint (i1, ==, 0);
920   g_assert_cmpuint (i2, ==, 0);
921   g_assert_cmpuint (i3, ==, 1);
922   g_assert_cmpuint (i4, ==, 1);
923 }
924
925 static void
926 byte_array_append (void)
927 {
928   GByteArray *gbarray;
929   gint i;
930   guint8 *segment;
931
932   gbarray = g_byte_array_sized_new (1000);
933   for (i = 0; i < 10000; i++)
934     g_byte_array_append (gbarray, (guint8*) "abcd", 4);
935
936   for (i = 0; i < 10000; i++)
937     {
938       g_assert (gbarray->data[4*i] == 'a');
939       g_assert (gbarray->data[4*i+1] == 'b');
940       g_assert (gbarray->data[4*i+2] == 'c');
941       g_assert (gbarray->data[4*i+3] == 'd');
942     }
943
944   segment = g_byte_array_free (gbarray, FALSE);
945
946   for (i = 0; i < 10000; i++)
947     {
948       g_assert (segment[4*i] == 'a');
949       g_assert (segment[4*i+1] == 'b');
950       g_assert (segment[4*i+2] == 'c');
951       g_assert (segment[4*i+3] == 'd');
952     }
953
954   g_free (segment);
955 }
956
957 static void
958 byte_array_prepend (void)
959 {
960   GByteArray *gbarray;
961   gint i;
962
963   gbarray = g_byte_array_new ();
964   g_byte_array_set_size (gbarray, 1000);
965
966   for (i = 0; i < 10000; i++)
967     g_byte_array_prepend (gbarray, (guint8*) "abcd", 4);
968
969   for (i = 0; i < 10000; i++)
970     {
971       g_assert (gbarray->data[4*i] == 'a');
972       g_assert (gbarray->data[4*i+1] == 'b');
973       g_assert (gbarray->data[4*i+2] == 'c');
974       g_assert (gbarray->data[4*i+3] == 'd');
975     }
976
977   g_byte_array_free (gbarray, TRUE);
978 }
979
980 static void
981 byte_array_ref_count (void)
982 {
983   GByteArray *gbarray;
984   GByteArray *gbarray2;
985   gint i;
986
987   gbarray = g_byte_array_new ();
988   for (i = 0; i < 10000; i++)
989     g_byte_array_append (gbarray, (guint8*) "abcd", 4);
990
991   gbarray2 = g_byte_array_ref (gbarray);
992   g_assert (gbarray2 == gbarray);
993   g_byte_array_unref (gbarray2);
994   for (i = 0; i < 10000; i++)
995     {
996       g_assert (gbarray->data[4*i] == 'a');
997       g_assert (gbarray->data[4*i+1] == 'b');
998       g_assert (gbarray->data[4*i+2] == 'c');
999       g_assert (gbarray->data[4*i+3] == 'd');
1000     }
1001
1002   gbarray2 = g_byte_array_ref (gbarray);
1003   g_assert (gbarray2 == gbarray);
1004   g_byte_array_free (gbarray, TRUE);
1005   g_assert_cmpint (gbarray2->len, ==, 0);
1006   g_byte_array_unref (gbarray2);
1007 }
1008
1009 static void
1010 byte_array_remove (void)
1011 {
1012   GByteArray *gbarray;
1013   gint i;
1014
1015   gbarray = g_byte_array_new ();
1016   for (i = 0; i < 100; i++)
1017     g_byte_array_append (gbarray, (guint8*) "abcd", 4);
1018
1019   g_assert_cmpint (gbarray->len, ==, 400);
1020
1021   g_byte_array_remove_index (gbarray, 4);
1022   g_byte_array_remove_index (gbarray, 4);
1023   g_byte_array_remove_index (gbarray, 4);
1024   g_byte_array_remove_index (gbarray, 4);
1025
1026   g_assert_cmpint (gbarray->len, ==, 396);
1027
1028   for (i = 0; i < 99; i++)
1029     {
1030       g_assert (gbarray->data[4*i] == 'a');
1031       g_assert (gbarray->data[4*i+1] == 'b');
1032       g_assert (gbarray->data[4*i+2] == 'c');
1033       g_assert (gbarray->data[4*i+3] == 'd');
1034     }
1035
1036   g_byte_array_free (gbarray, TRUE);
1037 }
1038
1039 static void
1040 byte_array_remove_fast (void)
1041 {
1042   GByteArray *gbarray;
1043   gint i;
1044
1045   gbarray = g_byte_array_new ();
1046   for (i = 0; i < 100; i++)
1047     g_byte_array_append (gbarray, (guint8*) "abcd", 4);
1048
1049   g_assert_cmpint (gbarray->len, ==, 400);
1050
1051   g_byte_array_remove_index_fast (gbarray, 4);
1052   g_byte_array_remove_index_fast (gbarray, 4);
1053   g_byte_array_remove_index_fast (gbarray, 4);
1054   g_byte_array_remove_index_fast (gbarray, 4);
1055
1056   g_assert_cmpint (gbarray->len, ==, 396);
1057
1058   for (i = 0; i < 99; i++)
1059     {
1060       g_assert (gbarray->data[4*i] == 'a');
1061       g_assert (gbarray->data[4*i+1] == 'b');
1062       g_assert (gbarray->data[4*i+2] == 'c');
1063       g_assert (gbarray->data[4*i+3] == 'd');
1064     }
1065
1066   g_byte_array_free (gbarray, TRUE);
1067 }
1068
1069 static void
1070 byte_array_remove_range (void)
1071 {
1072   GByteArray *gbarray;
1073   gint i;
1074
1075   gbarray = g_byte_array_new ();
1076   for (i = 0; i < 100; i++)
1077     g_byte_array_append (gbarray, (guint8*) "abcd", 4);
1078
1079   g_assert_cmpint (gbarray->len, ==, 400);
1080
1081   g_byte_array_remove_range (gbarray, 12, 4);
1082
1083   g_assert_cmpint (gbarray->len, ==, 396);
1084
1085   for (i = 0; i < 99; i++)
1086     {
1087       g_assert (gbarray->data[4*i] == 'a');
1088       g_assert (gbarray->data[4*i+1] == 'b');
1089       g_assert (gbarray->data[4*i+2] == 'c');
1090       g_assert (gbarray->data[4*i+3] == 'd');
1091     }
1092
1093   /* Ensure the entire array can be cleared, even when empty. */
1094   g_byte_array_remove_range (gbarray, 0, gbarray->len);
1095   g_byte_array_remove_range (gbarray, 0, gbarray->len);
1096
1097   g_byte_array_free (gbarray, TRUE);
1098 }
1099
1100 static int
1101 byte_compare (gconstpointer p1, gconstpointer p2)
1102 {
1103   const guint8 *i1 = p1;
1104   const guint8 *i2 = p2;
1105
1106   return *i1 - *i2;
1107 }
1108
1109 static int
1110 byte_compare_data (gconstpointer p1, gconstpointer p2, gpointer data)
1111 {
1112   const guint8 *i1 = p1;
1113   const guint8 *i2 = p2;
1114
1115   return *i1 - *i2;
1116 }
1117
1118 static void
1119 byte_array_sort (void)
1120 {
1121   GByteArray *gbarray;
1122   gint i;
1123   guint8 val;
1124   guint8 prev, cur;
1125
1126   gbarray = g_byte_array_new ();
1127   for (i = 0; i < 100; i++)
1128     {
1129       val = 'a' + g_random_int_range (0, 26);
1130       g_byte_array_append (gbarray, (guint8*) &val, 1);
1131     }
1132
1133   g_byte_array_sort (gbarray, byte_compare);
1134
1135   prev = 'a';
1136   for (i = 0; i < gbarray->len; i++)
1137     {
1138       cur = gbarray->data[i];
1139       g_assert_cmpint (prev, <=, cur);
1140       prev = cur;
1141     }
1142
1143   g_byte_array_free (gbarray, TRUE);
1144 }
1145
1146 static void
1147 byte_array_sort_with_data (void)
1148 {
1149   GByteArray *gbarray;
1150   gint i;
1151   guint8 val;
1152   guint8 prev, cur;
1153
1154   gbarray = g_byte_array_new ();
1155   for (i = 0; i < 100; i++)
1156     {
1157       val = 'a' + g_random_int_range (0, 26);
1158       g_byte_array_append (gbarray, (guint8*) &val, 1);
1159     }
1160
1161   g_byte_array_sort_with_data (gbarray, byte_compare_data, NULL);
1162
1163   prev = 'a';
1164   for (i = 0; i < gbarray->len; i++)
1165     {
1166       cur = gbarray->data[i];
1167       g_assert_cmpint (prev, <=, cur);
1168       prev = cur;
1169     }
1170
1171   g_byte_array_free (gbarray, TRUE);
1172 }
1173
1174 static void
1175 byte_array_new_take (void)
1176 {
1177   GByteArray *gbarray;
1178   guint8 *data;
1179
1180   data = g_memdup ("woooweeewow", 11);
1181   gbarray = g_byte_array_new_take (data, 11);
1182   g_assert (gbarray->data == data);
1183   g_assert_cmpuint (gbarray->len, ==, 11);
1184   g_byte_array_free (gbarray, TRUE);
1185 }
1186
1187 static void
1188 byte_array_free_to_bytes (void)
1189 {
1190   GByteArray *gbarray;
1191   gpointer memory;
1192   GBytes *bytes;
1193   gsize size;
1194
1195   gbarray = g_byte_array_new ();
1196   g_byte_array_append (gbarray, (guint8 *)"woooweeewow", 11);
1197   memory = gbarray->data;
1198
1199   bytes = g_byte_array_free_to_bytes (gbarray);
1200   g_assert (bytes != NULL);
1201   g_assert_cmpuint (g_bytes_get_size (bytes), ==, 11);
1202   g_assert (g_bytes_get_data (bytes, &size) == memory);
1203   g_assert_cmpuint (size, ==, 11);
1204
1205   g_bytes_unref (bytes);
1206 }
1207
1208 static void
1209 add_array_test (const gchar         *test_path,
1210                 const ArrayTestData *config,
1211                 GTestDataFunc        test_func)
1212 {
1213   gchar *test_name = NULL;
1214
1215   test_name = g_strdup_printf ("%s/%s-%s",
1216                                test_path,
1217                                config->zero_terminated ? "zero-terminated" : "non-zero-terminated",
1218                                config->clear_ ? "clear" : "no-clear");
1219   g_test_add_data_func (test_name, config, test_func);
1220   g_free (test_name);
1221 }
1222
1223 int
1224 main (int argc, char *argv[])
1225 {
1226   /* Test all possible combinations of g_array_new() parameters. */
1227   const ArrayTestData array_configurations[] =
1228     {
1229       { FALSE, FALSE },
1230       { FALSE, TRUE },
1231       { TRUE, FALSE },
1232       { TRUE, TRUE },
1233     };
1234   gsize i;
1235
1236   g_test_init (&argc, &argv, NULL);
1237
1238   g_test_bug_base ("https://bugzilla.gnome.org/");
1239
1240   /* array tests */
1241   g_test_add_func ("/array/new/zero-terminated", array_new_zero_terminated);
1242   g_test_add_func ("/array/ref-count", array_ref_count);
1243   g_test_add_func ("/array/clear-func", array_clear_func);
1244
1245   for (i = 0; i < G_N_ELEMENTS (array_configurations); i++)
1246     {
1247       add_array_test ("/array/set-size", &array_configurations[i], array_set_size);
1248       add_array_test ("/array/set-size/sized", &array_configurations[i], array_set_size_sized);
1249       add_array_test ("/array/append-val", &array_configurations[i], array_append_val);
1250       add_array_test ("/array/prepend-val", &array_configurations[i], array_prepend_val);
1251       add_array_test ("/array/prepend-vals", &array_configurations[i], array_prepend_vals);
1252       add_array_test ("/array/insert-vals", &array_configurations[i], array_insert_vals);
1253       add_array_test ("/array/remove-index", &array_configurations[i], array_remove_index);
1254       add_array_test ("/array/remove-index-fast", &array_configurations[i], array_remove_index_fast);
1255       add_array_test ("/array/remove-range", &array_configurations[i], array_remove_range);
1256       add_array_test ("/array/sort", &array_configurations[i], array_sort);
1257       add_array_test ("/array/sort-with-data", &array_configurations[i], array_sort_with_data);
1258     }
1259
1260   /* pointer arrays */
1261   g_test_add_func ("/pointerarray/add", pointer_array_add);
1262   g_test_add_func ("/pointerarray/insert", pointer_array_insert);
1263   g_test_add_func ("/pointerarray/ref-count", pointer_array_ref_count);
1264   g_test_add_func ("/pointerarray/free-func", pointer_array_free_func);
1265   g_test_add_func ("/pointerarray/sort", pointer_array_sort);
1266   g_test_add_func ("/pointerarray/sort-with-data", pointer_array_sort_with_data);
1267   g_test_add_func ("/pointerarray/find/empty", pointer_array_find_empty);
1268   g_test_add_func ("/pointerarray/find/non-empty", pointer_array_find_non_empty);
1269   g_test_add_func ("/pointerarray/steal", pointer_array_steal);
1270
1271   /* byte arrays */
1272   g_test_add_func ("/bytearray/append", byte_array_append);
1273   g_test_add_func ("/bytearray/prepend", byte_array_prepend);
1274   g_test_add_func ("/bytearray/remove", byte_array_remove);
1275   g_test_add_func ("/bytearray/remove-fast", byte_array_remove_fast);
1276   g_test_add_func ("/bytearray/remove-range", byte_array_remove_range);
1277   g_test_add_func ("/bytearray/ref-count", byte_array_ref_count);
1278   g_test_add_func ("/bytearray/sort", byte_array_sort);
1279   g_test_add_func ("/bytearray/sort-with-data", byte_array_sort_with_data);
1280   g_test_add_func ("/bytearray/new-take", byte_array_new_take);
1281   g_test_add_func ("/bytearray/free-to-bytes", byte_array_free_to_bytes);
1282
1283   return g_test_run ();
1284 }
1285