]> Pileus Git - ~andy/gtk/blob - gtk/tests/filtermodel.c
Add a rather specially crafted test case
[~andy/gtk] / gtk / tests / filtermodel.c
1 /* Extensive GtkTreeModelFilter tests.
2  * Copyright (C) 2009  Kristian Rietveld  <kris@gtk.org>
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 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, write to the
16  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17  * Boston, MA 02111-1307, USA.
18  */
19
20 #include <gtk/gtk.h>
21
22
23 /*
24  * Model creation
25  */
26
27 #define LEVEL_LENGTH 5
28
29 static void
30 create_tree_store_set_values (GtkTreeStore *store,
31                               GtkTreeIter  *iter,
32                               gboolean      visible)
33 {
34   GtkTreePath *path;
35
36   path = gtk_tree_model_get_path (GTK_TREE_MODEL (store), iter);
37   gtk_tree_store_set (store, iter,
38                       0, gtk_tree_path_to_string (path),
39                       1, visible,
40                       -1);
41   gtk_tree_path_free (path);
42 }
43
44 static void
45 create_tree_store_recurse (int           depth,
46                            GtkTreeStore *store,
47                            GtkTreeIter  *parent,
48                            gboolean      visible)
49 {
50   int i;
51
52   for (i = 0; i < LEVEL_LENGTH; i++)
53     {
54       GtkTreeIter iter;
55
56       gtk_tree_store_insert (store, &iter, parent, i);
57       create_tree_store_set_values (store, &iter, visible);
58
59       if (depth > 0)
60         create_tree_store_recurse (depth - 1, store, &iter, visible);
61     }
62 }
63
64 static GtkTreeStore *
65 create_tree_store (int      depth,
66                    gboolean visible)
67 {
68   GtkTreeStore *store;
69
70   store = gtk_tree_store_new (2, G_TYPE_STRING, G_TYPE_BOOLEAN);
71
72   create_tree_store_recurse (depth, store, NULL, visible);
73
74   return store;
75 }
76
77
78 /*
79  * Fixture
80  */
81
82 typedef struct
83 {
84   GtkWidget *tree_view;
85
86   GtkTreeStore *store;
87   GtkTreeModelFilter *filter;
88 } FilterTest;
89
90 static void
91 filter_test_setup_generic (FilterTest    *fixture,
92                            gconstpointer  test_data,
93                            int            depth,
94                            gboolean       empty,
95                            gboolean       unfiltered)
96 {
97   const GtkTreePath *vroot = test_data;
98   GtkTreeModel *filter;
99
100   fixture->store = create_tree_store (depth, !empty);
101
102   /* Please forgive me for casting const away. */
103   filter = gtk_tree_model_filter_new (GTK_TREE_MODEL (fixture->store),
104                                       (GtkTreePath *)vroot);
105   fixture->filter = GTK_TREE_MODEL_FILTER (filter);
106
107   if (!unfiltered)
108     gtk_tree_model_filter_set_visible_column (fixture->filter, 1);
109
110   /* We need a tree view that's listening to get ref counting from that
111    * side.
112    */
113   fixture->tree_view = gtk_tree_view_new_with_model (filter);
114 }
115
116 static void
117 filter_test_setup (FilterTest    *fixture,
118                    gconstpointer  test_data)
119 {
120   filter_test_setup_generic (fixture, test_data, 3, FALSE, FALSE);
121 }
122
123 static void
124 filter_test_setup_empty (FilterTest    *fixture,
125                          gconstpointer  test_data)
126 {
127   filter_test_setup_generic (fixture, test_data, 3, TRUE, FALSE);
128 }
129
130 static void
131 filter_test_setup_unfiltered (FilterTest    *fixture,
132                               gconstpointer  test_data)
133 {
134   filter_test_setup_generic (fixture, test_data, 3, FALSE, TRUE);
135 }
136
137 static void
138 filter_test_setup_empty_unfiltered (FilterTest    *fixture,
139                                     gconstpointer  test_data)
140 {
141   filter_test_setup_generic (fixture, test_data, 3, TRUE, TRUE);
142 }
143
144 static void
145 filter_test_enable_filter (FilterTest *fixture)
146 {
147   gtk_tree_model_filter_set_visible_column (fixture->filter, 1);
148   gtk_tree_model_filter_refilter (fixture->filter);
149 }
150
151 static void
152 filter_test_teardown (FilterTest    *fixture,
153                       gconstpointer  test_data)
154 {
155   g_object_unref (fixture->filter);
156   g_object_unref (fixture->store);
157 }
158
159 /*
160  * Model structure validation
161  */
162
163 static void
164 check_filter_model_recurse (FilterTest  *fixture,
165                             GtkTreePath *store_parent_path,
166                             GtkTreePath *filter_parent_path)
167 {
168   int i;
169   GtkTreeIter store_iter;
170   GtkTreeIter filter_iter;
171   gboolean store_has_next, filter_has_next;
172
173   gtk_tree_path_down (store_parent_path);
174   gtk_tree_path_down (filter_parent_path);
175
176   store_has_next = gtk_tree_model_get_iter (GTK_TREE_MODEL (fixture->store),
177                                             &store_iter, store_parent_path);
178   filter_has_next = gtk_tree_model_get_iter (GTK_TREE_MODEL (fixture->filter),
179                                              &filter_iter, filter_parent_path);
180
181   for (i = 0; i < LEVEL_LENGTH; i++)
182     {
183       gboolean visible;
184
185       g_return_if_fail (store_has_next == TRUE);
186
187       gtk_tree_model_get (GTK_TREE_MODEL (fixture->store),
188                           &store_iter,
189                           1, &visible,
190                           -1);
191
192       if (visible)
193         {
194           GtkTreePath *tmp;
195           gchar *filter_str, *store_str;
196
197           g_return_if_fail (filter_has_next == TRUE);
198
199           /* Verify path */
200           tmp = gtk_tree_model_get_path (GTK_TREE_MODEL (fixture->filter),
201                                          &filter_iter);
202           g_return_if_fail (gtk_tree_path_compare (tmp, filter_parent_path) == 0);
203
204           /* Verify model content */
205           gtk_tree_model_get (GTK_TREE_MODEL (fixture->store),
206                               &store_iter,
207                               0, &store_str,
208                               -1);
209           gtk_tree_model_get (GTK_TREE_MODEL (fixture->filter),
210                               &filter_iter,
211                               0, &filter_str,
212                               -1);
213
214           g_return_if_fail (g_strcmp0 (store_str, filter_str) == 0);
215
216           g_free (store_str);
217           g_free (filter_str);
218
219           if (gtk_tree_model_iter_has_child (GTK_TREE_MODEL (fixture->filter),
220                                              &filter_iter))
221             {
222               g_return_if_fail (gtk_tree_model_iter_has_child (GTK_TREE_MODEL (fixture->store), &store_iter));
223
224               check_filter_model_recurse (fixture,
225                                           gtk_tree_path_copy (store_parent_path),
226                                           tmp);
227             }
228
229           gtk_tree_path_next (filter_parent_path);
230           filter_has_next = gtk_tree_model_iter_next (GTK_TREE_MODEL (fixture->filter), &filter_iter);
231         }
232
233       gtk_tree_path_next (store_parent_path);
234       store_has_next = gtk_tree_model_iter_next (GTK_TREE_MODEL (fixture->store), &store_iter);
235     }
236
237   /* Both models should have no more content! */
238   g_return_if_fail (store_has_next == FALSE);
239   g_return_if_fail (filter_has_next == FALSE);
240
241   gtk_tree_path_free (store_parent_path);
242   gtk_tree_path_free (filter_parent_path);
243 }
244
245 static void
246 check_filter_model (FilterTest *fixture)
247 {
248   GtkTreePath *path;
249
250   path = gtk_tree_path_new ();
251
252   check_filter_model_recurse (fixture, path, gtk_tree_path_copy (path));
253 }
254
255 static void
256 check_filter_model_with_root (FilterTest  *fixture,
257                               GtkTreePath *path)
258 {
259   check_filter_model_recurse (fixture,
260                               gtk_tree_path_copy (path),
261                               gtk_tree_path_new ());
262 }
263
264 /* Helpers */
265
266 static void
267 check_level_length (GtkTreeModelFilter *filter,
268                     const gchar        *level,
269                     const int           length)
270 {
271   if (!level)
272     {
273       int l = gtk_tree_model_iter_n_children (GTK_TREE_MODEL (filter), NULL);
274       g_return_if_fail (l == length);
275     }
276   else
277     {
278       int l;
279       gboolean retrieved_iter = FALSE;
280       GtkTreeIter iter;
281
282       retrieved_iter = gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL (filter),
283                                                             &iter, level);
284       g_return_if_fail (retrieved_iter);
285       l = gtk_tree_model_iter_n_children (GTK_TREE_MODEL (filter), &iter);
286       g_return_if_fail (l == length);
287     }
288 }
289
290 static void
291 set_path_visibility (FilterTest  *fixture,
292                      const gchar *path,
293                      gboolean     visible)
294 {
295   GtkTreeIter store_iter;
296
297   gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL (fixture->store),
298                                        &store_iter, path);
299   gtk_tree_store_set (fixture->store, &store_iter,
300                       1, visible,
301                       -1);
302 }
303
304 static void
305 insert_path_with_visibility (FilterTest  *fixture,
306                              const gchar *path_string,
307                              gboolean     visible)
308 {
309   int position;
310   GtkTreePath *path;
311   GtkTreeIter parent, iter;
312
313   path = gtk_tree_path_new_from_string (path_string);
314   position = gtk_tree_path_get_indices (path)[gtk_tree_path_get_depth (path)];
315   gtk_tree_path_up (path);
316
317   if (gtk_tree_model_get_iter (GTK_TREE_MODEL (fixture->store), &parent, path))
318     {
319       gtk_tree_store_insert (fixture->store, &iter, &parent, position);
320       create_tree_store_set_values (fixture->store, &iter, visible);
321     }
322   gtk_tree_path_free (path);
323 }
324
325 /*
326  * The actual tests.
327  */
328
329 static void
330 verify_test_suite (FilterTest    *fixture,
331                    gconstpointer  user_data)
332 {
333   check_filter_model (fixture);
334 }
335
336 static void
337 verify_test_suite_vroot (FilterTest    *fixture,
338                          gconstpointer  user_data)
339 {
340   check_filter_model_with_root (fixture, (GtkTreePath *)user_data);
341 }
342
343
344 static void
345 filled_hide_root_level (FilterTest    *fixture,
346                         gconstpointer  user_data)
347 {
348   set_path_visibility (fixture, "2", FALSE);
349   check_filter_model (fixture);
350   check_level_length (fixture->filter, NULL, LEVEL_LENGTH - 1);
351
352   set_path_visibility (fixture, "0", FALSE);
353   check_filter_model (fixture);
354   check_level_length (fixture->filter, NULL, LEVEL_LENGTH - 2);
355
356   set_path_visibility (fixture, "4", FALSE);
357   check_filter_model (fixture);
358   check_level_length (fixture->filter, NULL, LEVEL_LENGTH - 3);
359
360
361   /* Hide remaining */
362   set_path_visibility (fixture, "1", FALSE);
363   check_level_length (fixture->filter, NULL, LEVEL_LENGTH - 4);
364
365   set_path_visibility (fixture, "3", FALSE);
366   check_level_length (fixture->filter, NULL, LEVEL_LENGTH - 5);
367
368   check_filter_model (fixture);
369
370   /* Show some */
371   set_path_visibility (fixture, "1", TRUE);
372   check_level_length (fixture->filter, NULL, LEVEL_LENGTH - 4);
373
374   set_path_visibility (fixture, "3", TRUE);
375   check_level_length (fixture->filter, NULL, LEVEL_LENGTH - 3);
376
377   check_filter_model (fixture);
378 }
379
380 static void
381 filled_hide_child_levels (FilterTest    *fixture,
382                           gconstpointer  user_data)
383 {
384   set_path_visibility (fixture, "0:2", FALSE);
385   check_filter_model (fixture);
386   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
387   check_level_length (fixture->filter, "0", LEVEL_LENGTH - 1);
388
389   set_path_visibility (fixture, "0:4", FALSE);
390   check_filter_model (fixture);
391   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
392   check_level_length (fixture->filter, "0", LEVEL_LENGTH - 2);
393
394   set_path_visibility (fixture, "0:4:3", FALSE);
395   check_filter_model (fixture);
396   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
397   check_level_length (fixture->filter, "0", LEVEL_LENGTH - 2);
398
399   set_path_visibility (fixture, "0:4:0", FALSE);
400   set_path_visibility (fixture, "0:4:1", FALSE);
401   set_path_visibility (fixture, "0:4:2", FALSE);
402   set_path_visibility (fixture, "0:4:4", FALSE);
403   check_filter_model (fixture);
404   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
405   check_level_length (fixture->filter, "0", LEVEL_LENGTH - 2);
406
407   set_path_visibility (fixture, "0:4", TRUE);
408   /* Since "0:2" is hidden, "0:4" must be "0:3" in the filter model */
409   check_filter_model (fixture);
410   check_level_length (fixture->filter, "0:3", 0);
411
412   set_path_visibility (fixture, "0:2", TRUE);
413   check_filter_model (fixture);
414   check_level_length (fixture->filter, "0:2", LEVEL_LENGTH);
415   check_level_length (fixture->filter, "0:3", LEVEL_LENGTH);
416   check_level_length (fixture->filter, "0:4", 0);
417
418   set_path_visibility (fixture, "0:4:2", TRUE);
419   set_path_visibility (fixture, "0:4:4", TRUE);
420   check_level_length (fixture->filter, "0:4", 2);
421 }
422
423
424 static void
425 filled_vroot_hide_root_level (FilterTest    *fixture,
426                               gconstpointer  user_data)
427 {
428   GtkTreePath *path = (GtkTreePath *)user_data;
429
430   /* These changes do not affect the filter's root level */
431   set_path_visibility (fixture, "0", FALSE);
432   check_filter_model_with_root (fixture, path);
433   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
434   check_level_length (fixture->filter, "0", LEVEL_LENGTH);
435
436   set_path_visibility (fixture, "4", FALSE);
437   check_filter_model_with_root (fixture, path);
438   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
439   check_level_length (fixture->filter, "0", LEVEL_LENGTH);
440
441   /* Even though we set the virtual root parent node to FALSE,
442    * the virtual root contents remain.
443    */
444   set_path_visibility (fixture, "2", FALSE);
445   check_filter_model_with_root (fixture, path);
446   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
447   check_level_length (fixture->filter, "0", LEVEL_LENGTH);
448
449   /* No change */
450   set_path_visibility (fixture, "1", FALSE);
451   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
452   check_level_length (fixture->filter, "0", LEVEL_LENGTH);
453
454   set_path_visibility (fixture, "3", FALSE);
455   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
456   check_level_length (fixture->filter, "0", LEVEL_LENGTH);
457
458   check_filter_model_with_root (fixture, path);
459
460   /* Show some */
461   set_path_visibility (fixture, "2", TRUE);
462   check_filter_model_with_root (fixture, path);
463   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
464   check_level_length (fixture->filter, "0", LEVEL_LENGTH);
465
466   set_path_visibility (fixture, "1", TRUE);
467   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
468   check_level_length (fixture->filter, "0", LEVEL_LENGTH);
469
470   set_path_visibility (fixture, "3", TRUE);
471   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
472   check_level_length (fixture->filter, "0", LEVEL_LENGTH);
473
474   check_filter_model_with_root (fixture, path);
475
476   /* Now test changes in the virtual root level */
477   set_path_visibility (fixture, "2:2", FALSE);
478   check_filter_model_with_root (fixture, path);
479   check_level_length (fixture->filter, NULL, LEVEL_LENGTH - 1);
480
481   set_path_visibility (fixture, "2:4", FALSE);
482   check_filter_model_with_root (fixture, path);
483   check_level_length (fixture->filter, NULL, LEVEL_LENGTH - 2);
484
485   set_path_visibility (fixture, "1:4", FALSE);
486   check_filter_model_with_root (fixture, path);
487   check_level_length (fixture->filter, NULL, LEVEL_LENGTH - 2);
488
489   set_path_visibility (fixture, "2:4", TRUE);
490   check_filter_model_with_root (fixture, path);
491   check_level_length (fixture->filter, NULL, LEVEL_LENGTH - 1);
492
493   set_path_visibility (fixture, "2", FALSE);
494   check_filter_model_with_root (fixture, path);
495   check_level_length (fixture->filter, NULL, LEVEL_LENGTH - 1);
496
497   set_path_visibility (fixture, "2:0", FALSE);
498   set_path_visibility (fixture, "2:1", FALSE);
499   set_path_visibility (fixture, "2:2", FALSE);
500   set_path_visibility (fixture, "2:3", FALSE);
501   set_path_visibility (fixture, "2:4", FALSE);
502   check_filter_model_with_root (fixture, path);
503   check_level_length (fixture->filter, NULL, 0);
504
505   set_path_visibility (fixture, "2", TRUE);
506   check_filter_model_with_root (fixture, path);
507   check_level_length (fixture->filter, NULL, 0);
508
509   set_path_visibility (fixture, "1:4", FALSE);
510   check_filter_model_with_root (fixture, path);
511   check_level_length (fixture->filter, NULL, 0);
512
513   set_path_visibility (fixture, "2:4", TRUE);
514   check_filter_model_with_root (fixture, path);
515   check_level_length (fixture->filter, NULL, LEVEL_LENGTH - 4);
516
517   set_path_visibility (fixture, "2:4", FALSE);
518   check_filter_model_with_root (fixture, path);
519   check_level_length (fixture->filter, NULL, 0);
520
521   set_path_visibility (fixture, "2", FALSE);
522   check_filter_model_with_root (fixture, path);
523   check_level_length (fixture->filter, NULL, 0);
524
525   set_path_visibility (fixture, "2:0", TRUE);
526   set_path_visibility (fixture, "2:1", TRUE);
527   set_path_visibility (fixture, "2:2", TRUE);
528   check_filter_model_with_root (fixture, path);
529   check_level_length (fixture->filter, NULL, LEVEL_LENGTH - 2);
530
531   set_path_visibility (fixture, "2", TRUE);
532   check_filter_model_with_root (fixture, path);
533   check_level_length (fixture->filter, NULL, LEVEL_LENGTH - 2);
534 }
535
536 static void
537 filled_vroot_hide_child_levels (FilterTest    *fixture,
538                                 gconstpointer  user_data)
539 {
540   GtkTreePath *path = (GtkTreePath *)user_data;
541
542   set_path_visibility (fixture, "2:0:2", FALSE);
543   check_filter_model_with_root (fixture, path);
544   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
545   check_level_length (fixture->filter, "0", LEVEL_LENGTH - 1);
546
547   set_path_visibility (fixture, "2:0:4", FALSE);
548   check_filter_model_with_root (fixture, path);
549   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
550   check_level_length (fixture->filter, "0", LEVEL_LENGTH - 2);
551
552   set_path_visibility (fixture, "2:0:4:3", FALSE);
553   check_filter_model_with_root (fixture, path);
554   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
555   check_level_length (fixture->filter, "0", LEVEL_LENGTH - 2);
556
557   set_path_visibility (fixture, "2:0:4:0", FALSE);
558   set_path_visibility (fixture, "2:0:4:1", FALSE);
559   set_path_visibility (fixture, "2:0:4:2", FALSE);
560   set_path_visibility (fixture, "2:0:4:4", FALSE);
561   check_filter_model_with_root (fixture, path);
562   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
563   check_level_length (fixture->filter, "0", LEVEL_LENGTH - 2);
564
565   set_path_visibility (fixture, "2:0:4", TRUE);
566   /* Since "0:2" is hidden, "0:4" must be "0:3" in the filter model */
567   check_filter_model_with_root (fixture, path);
568   check_level_length (fixture->filter, "0:3", 0);
569
570   set_path_visibility (fixture, "2:0:2", TRUE);
571   check_filter_model_with_root (fixture, path);
572   check_level_length (fixture->filter, "0:2", LEVEL_LENGTH);
573   check_level_length (fixture->filter, "0:3", LEVEL_LENGTH);
574   check_level_length (fixture->filter, "0:4", 0);
575
576   set_path_visibility (fixture, "2:0:4:2", TRUE);
577   set_path_visibility (fixture, "2:0:4:4", TRUE);
578   check_level_length (fixture->filter, "0:4", 2);
579 }
580
581
582 static void
583 empty_show_nodes (FilterTest    *fixture,
584                   gconstpointer  user_data)
585 {
586   check_filter_model (fixture);
587   check_level_length (fixture->filter, NULL, 0);
588
589   set_path_visibility (fixture, "3", TRUE);
590   check_filter_model (fixture);
591   check_level_length (fixture->filter, NULL, 1);
592   check_level_length (fixture->filter, "0", 0);
593
594   set_path_visibility (fixture, "3:2:2", TRUE);
595   check_filter_model (fixture);
596   check_level_length (fixture->filter, NULL, 1);
597   check_level_length (fixture->filter, "0", 0);
598
599   set_path_visibility (fixture, "3:2", TRUE);
600   check_filter_model (fixture);
601   check_level_length (fixture->filter, NULL, 1);
602   check_level_length (fixture->filter, "0", 1);
603   check_level_length (fixture->filter, "0:0", 1);
604   check_level_length (fixture->filter, "0:0:0", 0);
605
606   set_path_visibility (fixture, "3", FALSE);
607   check_filter_model (fixture);
608   check_level_length (fixture->filter, NULL, 0);
609
610   set_path_visibility (fixture, "3:2:1", TRUE);
611   set_path_visibility (fixture, "3", TRUE);
612   check_filter_model (fixture);
613   check_level_length (fixture->filter, NULL, 1);
614   check_level_length (fixture->filter, "0", 1);
615   check_level_length (fixture->filter, "0:0", 2);
616   check_level_length (fixture->filter, "0:0:0", 0);
617 }
618
619 static void
620 empty_vroot_show_nodes (FilterTest    *fixture,
621                         gconstpointer  user_data)
622 {
623   GtkTreePath *path = (GtkTreePath *)user_data;
624
625   check_filter_model_with_root (fixture, path);
626   check_level_length (fixture->filter, NULL, 0);
627
628   set_path_visibility (fixture, "2", TRUE);
629   check_filter_model_with_root (fixture, path);
630   check_level_length (fixture->filter, NULL, 0);
631
632   set_path_visibility (fixture, "2:2:2", TRUE);
633   check_filter_model_with_root (fixture, path);
634   check_level_length (fixture->filter, NULL, 0);
635
636   set_path_visibility (fixture, "2:2", TRUE);
637   check_filter_model_with_root (fixture, path);
638   check_level_length (fixture->filter, NULL, 1);
639   check_level_length (fixture->filter, "0", 1);
640   check_level_length (fixture->filter, "0:0", 0);
641
642   set_path_visibility (fixture, "3", TRUE);
643   check_filter_model_with_root (fixture, path);
644   check_level_length (fixture->filter, NULL, 1);
645
646   set_path_visibility (fixture, "2:2", FALSE);
647   check_filter_model_with_root (fixture, path);
648   check_level_length (fixture->filter, NULL, 0);
649
650   set_path_visibility (fixture, "2:2:1", TRUE);
651   set_path_visibility (fixture, "2:2", TRUE);
652   check_filter_model_with_root (fixture, path);
653   check_level_length (fixture->filter, NULL, 1);
654   check_level_length (fixture->filter, "0", 2);
655   check_level_length (fixture->filter, "0:1", 0);
656 }
657
658
659 static void
660 unfiltered_hide_single (FilterTest    *fixture,
661                         gconstpointer  user_data)
662
663 {
664   set_path_visibility (fixture, "2", FALSE);
665
666   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
667
668   filter_test_enable_filter (fixture);
669
670   check_filter_model (fixture);
671   check_level_length (fixture->filter, NULL, LEVEL_LENGTH - 1);
672 }
673
674 static void
675 unfiltered_hide_single_child (FilterTest    *fixture,
676                               gconstpointer  user_data)
677
678 {
679   set_path_visibility (fixture, "2:2", FALSE);
680
681   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
682   check_level_length (fixture->filter, "2", LEVEL_LENGTH);
683
684   filter_test_enable_filter (fixture);
685
686   check_filter_model (fixture);
687   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
688   check_level_length (fixture->filter, "2", LEVEL_LENGTH - 1);
689 }
690
691 static void
692 unfiltered_hide_single_multi_level (FilterTest    *fixture,
693                                     gconstpointer  user_data)
694
695 {
696   set_path_visibility (fixture, "2:2:2", FALSE);
697   set_path_visibility (fixture, "2:2", FALSE);
698
699   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
700   check_level_length (fixture->filter, "2", LEVEL_LENGTH);
701   check_level_length (fixture->filter, "2:2", LEVEL_LENGTH);
702
703   filter_test_enable_filter (fixture);
704
705   check_filter_model (fixture);
706   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
707   check_level_length (fixture->filter, "2", LEVEL_LENGTH - 1);
708
709   set_path_visibility (fixture, "2:2", TRUE);
710
711   check_filter_model (fixture);
712   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
713   check_level_length (fixture->filter, "2", LEVEL_LENGTH);
714   check_level_length (fixture->filter, "2:2", LEVEL_LENGTH - 1);
715 }
716
717
718 static void
719 unfiltered_show_single (FilterTest    *fixture,
720                         gconstpointer  user_data)
721
722 {
723   set_path_visibility (fixture, "2", TRUE);
724
725   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
726
727   filter_test_enable_filter (fixture);
728
729   check_filter_model (fixture);
730   check_level_length (fixture->filter, NULL, 1);
731 }
732
733 static void
734 unfiltered_show_single_child (FilterTest    *fixture,
735                               gconstpointer  user_data)
736
737 {
738   set_path_visibility (fixture, "2:2", TRUE);
739
740   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
741   check_level_length (fixture->filter, "2", LEVEL_LENGTH);
742
743   filter_test_enable_filter (fixture);
744
745   check_filter_model (fixture);
746   check_level_length (fixture->filter, NULL, 0);
747
748   /* From here we are filtered, "2" in the real model is "0" in the filter
749    * model.
750    */
751   set_path_visibility (fixture, "2", TRUE);
752   check_level_length (fixture->filter, NULL, 1);
753   check_level_length (fixture->filter, "0", 1);
754 }
755
756 static void
757 unfiltered_show_single_multi_level (FilterTest    *fixture,
758                                     gconstpointer  user_data)
759
760 {
761   set_path_visibility (fixture, "2:2:2", TRUE);
762   set_path_visibility (fixture, "2:2", TRUE);
763
764   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
765   check_level_length (fixture->filter, "2", LEVEL_LENGTH);
766   check_level_length (fixture->filter, "2:2", LEVEL_LENGTH);
767
768   filter_test_enable_filter (fixture);
769
770   check_filter_model (fixture);
771   check_level_length (fixture->filter, NULL, 0);
772
773   /* From here we are filtered, "2" in the real model is "0" in the filter
774    * model.
775    */
776   set_path_visibility (fixture, "2", TRUE);
777   check_filter_model (fixture);
778   check_level_length (fixture->filter, NULL, 1);
779   check_level_length (fixture->filter, "0", 1);
780   check_level_length (fixture->filter, "0:0", 1);
781 }
782
783
784 static gboolean
785 specific_path_dependent_filter_func (GtkTreeModel *model,
786                                      GtkTreeIter  *iter,
787                                      gpointer      data)
788 {
789   GtkTreePath *path;
790
791   path = gtk_tree_model_get_path (model, iter);
792   if (gtk_tree_path_get_indices (path)[0] < 4)
793     return FALSE;
794
795   return TRUE;
796 }
797
798 static void
799 specific_path_dependent_filter (void)
800 {
801   int i;
802   GtkTreeIter iter;
803   GtkListStore *list;
804   GtkTreeModel *sort;
805   GtkTreeModel *filter;
806
807   list = gtk_list_store_new (1, G_TYPE_INT);
808   gtk_list_store_insert_with_values (list, &iter, 0, 0, 1, -1);
809   gtk_list_store_insert_with_values (list, &iter, 1, 0, 2, -1);
810   gtk_list_store_insert_with_values (list, &iter, 2, 0, 3, -1);
811   gtk_list_store_insert_with_values (list, &iter, 3, 0, 4, -1);
812   gtk_list_store_insert_with_values (list, &iter, 4, 0, 5, -1);
813   gtk_list_store_insert_with_values (list, &iter, 5, 0, 6, -1);
814   gtk_list_store_insert_with_values (list, &iter, 6, 0, 7, -1);
815   gtk_list_store_insert_with_values (list, &iter, 7, 0, 8, -1);
816
817   sort = gtk_tree_model_sort_new_with_model (GTK_TREE_MODEL (list));
818   filter = gtk_tree_model_filter_new (GTK_TREE_MODEL (sort), NULL);
819   gtk_tree_model_filter_set_visible_func (GTK_TREE_MODEL_FILTER (filter),
820                                           specific_path_dependent_filter_func,
821                                           NULL, NULL);
822
823   gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (sort), 0,
824                                         GTK_SORT_DESCENDING);
825
826   for (i = 0; i < 4; i++)
827     {
828       if (gtk_tree_model_iter_nth_child (GTK_TREE_MODEL (list), &iter,
829                                          NULL, 1))
830         gtk_list_store_remove (list, &iter);
831
832       if (gtk_tree_model_iter_nth_child (GTK_TREE_MODEL (list), &iter,
833                                          NULL, 2))
834         gtk_list_store_remove (list, &iter);
835     }
836 }
837
838
839 static gboolean
840 specific_append_after_collapse_visible_func (GtkTreeModel *model,
841                                              GtkTreeIter  *iter,
842                                              gpointer      data)
843 {
844   gint number;
845   gboolean hide_negative_numbers;
846
847   gtk_tree_model_get (model, iter, 1, &number, -1);
848   hide_negative_numbers = GPOINTER_TO_INT (g_object_get_data (data, "private-hide-negative-numbers"));
849
850   return (number >= 0 || !hide_negative_numbers);
851 }
852
853 static void
854 specific_append_after_collapse (void)
855 {
856   /* This test is based on one of the test cases I found in my
857    * old test cases directory.  I unfortunately do not have a record
858    * from who this test case originated.  -Kris.
859    *
860    * General idea:
861    * - Construct tree.
862    * - Show tree, expand, collapse.
863    * - Add a row.
864    */
865
866   GtkTreeIter iter;
867   GtkTreeIter child_iter;
868   GtkTreeIter child_iter2;
869   GtkTreePath *append_path;
870   GtkTreeStore *store;
871   GtkTreeModel *filter;
872   GtkTreeModel *sort;
873
874   GtkWidget *window;
875   GtkWidget *tree_view;
876
877   store = gtk_tree_store_new (2, G_TYPE_STRING, G_TYPE_INT);
878
879   filter = gtk_tree_model_filter_new (GTK_TREE_MODEL (store), NULL);
880   g_object_set_data (G_OBJECT (filter), "private-hide-negative-numbers",
881                      GINT_TO_POINTER (FALSE));
882   gtk_tree_model_filter_set_visible_func (GTK_TREE_MODEL_FILTER (filter),
883                                           specific_append_after_collapse_visible_func,
884                                           filter, NULL);
885
886   sort = gtk_tree_model_sort_new_with_model (filter);
887
888   window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
889   tree_view = gtk_tree_view_new_with_model (sort);
890   gtk_container_add (GTK_CONTAINER (window), tree_view);
891   gtk_widget_realize (tree_view);
892
893   while (gtk_events_pending ())
894     gtk_main_iteration ();
895
896   gtk_tree_store_prepend (store, &iter, NULL);
897   gtk_tree_store_set (store, &iter,
898                       0, "hallo", 1, 1, -1);
899
900   gtk_tree_store_append (store, &child_iter, &iter);
901   gtk_tree_store_set (store, &child_iter,
902                       0, "toemaar", 1, 1, -1);
903
904   gtk_tree_store_append (store, &child_iter2, &child_iter);
905   gtk_tree_store_set (store, &child_iter2,
906                       0, "very deep", 1, 1, -1);
907
908   append_path = gtk_tree_model_get_path (GTK_TREE_MODEL (store), &child_iter2);
909
910   gtk_tree_store_append (store, &child_iter, &iter);
911   gtk_tree_store_set (store, &child_iter,
912                       0, "sja", 1, 1, -1);
913
914   gtk_tree_store_append (store, &child_iter, &iter);
915   gtk_tree_store_set (store, &child_iter,
916                       0, "some word", 1, -1, -1);
917
918   /* Expand and collapse the tree */
919   gtk_tree_view_expand_all (GTK_TREE_VIEW (tree_view));
920   while (gtk_events_pending ())
921     gtk_main_iteration ();
922
923   gtk_tree_view_collapse_all (GTK_TREE_VIEW (tree_view));
924   while (gtk_events_pending ())
925     gtk_main_iteration ();
926
927   /* Add another it */
928   g_object_set_data (G_OBJECT (filter), "private-hide-negative-numbers",
929                      GINT_TO_POINTER (TRUE));
930
931   if (gtk_tree_model_get_iter (GTK_TREE_MODEL (store), &iter, append_path))
932     {
933       gtk_tree_store_append (store, &child_iter, &iter);
934       gtk_tree_store_set (store, &child_iter,
935                           0, "new new new !!", 1, 1, -1);
936     }
937   gtk_tree_path_free (append_path);
938
939   /* Expand */
940   gtk_tree_view_expand_all (GTK_TREE_VIEW (tree_view));
941   while (gtk_events_pending ())
942     gtk_main_iteration ();
943 }
944
945
946 static gint
947 specific_sort_filter_remove_node_compare_func (GtkTreeModel  *model,
948                                                GtkTreeIter   *iter1,
949                                                GtkTreeIter   *iter2,
950                                                gpointer       data)
951 {
952   return -1;
953 }
954
955 static gboolean
956 specific_sort_filter_remove_node_visible_func (GtkTreeModel  *model,
957                                                GtkTreeIter   *iter,
958                                                gpointer       data)
959 {
960   char *item = NULL;
961
962   /* Do reference the model */
963   gtk_tree_model_get (model, iter, 0, &item, -1);
964   g_free (item);
965
966   return FALSE;
967 }
968
969 static void
970 specific_sort_filter_remove_node (void)
971 {
972   /* This test is based on one of the test cases I found in my
973    * old test cases directory.  I unfortunately do not have a record
974    * from who this test case originated.  -Kris.
975    *
976    * General idea:
977    *  - Create tree store, sort, filter models.  The sort model has
978    *    a default sort func that is enabled, filter model a visible func
979    *    that defaults to returning FALSE.
980    *  - Remove a node from the tree store.
981    */
982
983   GtkTreeIter iter;
984   GtkTreeStore *store;
985   GtkTreeModel *filter;
986   GtkTreeModel *sort;
987
988   GtkWidget *window;
989   GtkWidget *tree_view;
990
991   store = gtk_tree_store_new (1, G_TYPE_STRING);
992   gtk_tree_store_append (store, &iter, NULL);
993   gtk_tree_store_set (store, &iter, 0, "Hello1", -1);
994
995   gtk_tree_store_append (store, &iter, NULL);
996   gtk_tree_store_set (store, &iter, 0, "Hello2", -1);
997
998   sort = gtk_tree_model_sort_new_with_model (GTK_TREE_MODEL (store));
999   gtk_tree_sortable_set_default_sort_func (GTK_TREE_SORTABLE (sort),
1000                                            specific_sort_filter_remove_node_compare_func, NULL, NULL);
1001
1002   filter = gtk_tree_model_filter_new (sort, NULL);
1003   gtk_tree_model_filter_set_visible_func (GTK_TREE_MODEL_FILTER (filter),
1004                                           specific_sort_filter_remove_node_visible_func,
1005                                           filter, NULL);
1006
1007
1008   window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
1009   tree_view = gtk_tree_view_new_with_model (filter);
1010   gtk_container_add (GTK_CONTAINER (window), tree_view);
1011   gtk_widget_realize (tree_view);
1012
1013   while (gtk_events_pending ())
1014     gtk_main_iteration ();
1015
1016   /* Remove a node */
1017   gtk_tree_model_get_iter_first (GTK_TREE_MODEL (store), &iter);
1018   gtk_tree_model_iter_next (GTK_TREE_MODEL (store), &iter);
1019   gtk_tree_store_remove (store, &iter);
1020
1021   while (gtk_events_pending ())
1022     gtk_main_iteration ();
1023 }
1024
1025
1026 static void
1027 specific_sort_filter_remove_root (void)
1028 {
1029   /* This test is based on one of the test cases I found in my
1030    * old test cases directory.  I unfortunately do not have a record
1031    * from who this test case originated.  -Kris.
1032    */
1033
1034   GtkTreeModel *model, *sort, *filter;
1035   GtkTreeIter root, mid, leaf;
1036   GtkTreePath *path;
1037
1038   model = GTK_TREE_MODEL (gtk_tree_store_new (1, G_TYPE_INT));
1039   gtk_tree_store_append (GTK_TREE_STORE (model), &root, NULL);
1040   gtk_tree_store_append (GTK_TREE_STORE (model), &mid, &root);
1041   gtk_tree_store_append (GTK_TREE_STORE (model), &leaf, &mid);
1042
1043   path = gtk_tree_model_get_path (model, &mid);
1044
1045   sort = gtk_tree_model_sort_new_with_model (model);
1046   filter = gtk_tree_model_filter_new (sort, path);
1047
1048   gtk_tree_store_remove (GTK_TREE_STORE (model), &root);
1049
1050   g_object_unref (filter);
1051   g_object_unref (sort);
1052   g_object_unref (model);
1053 }
1054
1055
1056 static void
1057 specific_root_mixed_visibility (void)
1058 {
1059   int i;
1060   /* A bit nasty, apologies */
1061   GtkWidget *view;
1062   GtkTreeModel *filter;
1063   FilterTest fixture;
1064
1065   fixture.store = gtk_tree_store_new (2, G_TYPE_STRING, G_TYPE_BOOLEAN);
1066
1067   for (i = 0; i < LEVEL_LENGTH; i++)
1068     {
1069       GtkTreeIter iter;
1070
1071       gtk_tree_store_insert (fixture.store, &iter, NULL, i);
1072       if (i % 2 == 0)
1073         create_tree_store_set_values (fixture.store, &iter, TRUE);
1074       else
1075         create_tree_store_set_values (fixture.store, &iter, FALSE);
1076     }
1077
1078   filter = gtk_tree_model_filter_new (GTK_TREE_MODEL (fixture.store), NULL);
1079   fixture.filter = GTK_TREE_MODEL_FILTER (filter);
1080
1081   gtk_tree_model_filter_set_visible_column (fixture.filter, 1);
1082
1083   /* In order to trigger the potential bug, we should not access
1084    * the filter model here (so don't call the check functions).
1085    */
1086
1087   /* Change visibility of an odd row to TRUE */
1088   set_path_visibility (&fixture, "3", TRUE);
1089   check_filter_model (&fixture);
1090   check_level_length (fixture.filter, NULL, 4);
1091 }
1092
1093
1094 static void
1095 specific_filter_add_child (void)
1096 {
1097   /* This test is based on one of the test cases I found in my
1098    * old test cases directory.  I unfortunately do not have a record
1099    * from who this test case originated.  -Kris.
1100    */
1101
1102   GtkTreeIter iter;
1103   GtkTreeIter iter_first;
1104   GtkTreeIter child;
1105   GtkTreeStore *store;
1106   GtkTreeModel *filter;
1107
1108   store = gtk_tree_store_new (1, G_TYPE_STRING);
1109
1110   gtk_tree_store_append (store, &iter_first, NULL);
1111   gtk_tree_store_set (store, &iter_first, 0, "Hello", -1);
1112
1113   gtk_tree_store_append (store, &iter, NULL);
1114   gtk_tree_store_set (store, &iter, 0, "Hello", -1);
1115
1116   gtk_tree_store_append (store, &iter, NULL);
1117   gtk_tree_store_set (store, &iter, 0, "Hello", -1);
1118
1119   gtk_tree_store_append (store, &iter, NULL);
1120   gtk_tree_store_set (store, &iter, 0, "Hello", -1);
1121
1122   filter = gtk_tree_model_filter_new (GTK_TREE_MODEL (store), NULL);
1123
1124   gtk_tree_store_set (store, &iter, 0, "Hello", -1);
1125   gtk_tree_store_append (store, &child, &iter_first);
1126   gtk_tree_store_set (store, &child, 0, "Hello", -1);
1127 }
1128
1129
1130 static void
1131 specific_bug_300089 (void)
1132 {
1133   /* Test case for GNOME Bugzilla bug 300089.  Written by
1134    * Matthias Clasen.
1135    */
1136   GtkTreeModel *sort_model, *child_model;
1137   GtkTreePath *path;
1138   GtkTreeIter iter, iter2, sort_iter;
1139
1140   child_model = GTK_TREE_MODEL (gtk_tree_store_new (1, G_TYPE_STRING));
1141
1142   gtk_tree_store_append (GTK_TREE_STORE (child_model), &iter, NULL);
1143   gtk_tree_store_set (GTK_TREE_STORE (child_model), &iter, 0, "A", -1);
1144   gtk_tree_store_append (GTK_TREE_STORE (child_model), &iter, NULL);
1145   gtk_tree_store_set (GTK_TREE_STORE (child_model), &iter, 0, "B", -1);
1146
1147   gtk_tree_store_append (GTK_TREE_STORE (child_model), &iter2, &iter);
1148   gtk_tree_store_set (GTK_TREE_STORE (child_model), &iter2, 0, "D", -1);
1149   gtk_tree_store_append (GTK_TREE_STORE (child_model), &iter2, &iter);
1150   gtk_tree_store_set (GTK_TREE_STORE (child_model), &iter2, 0, "E", -1);
1151
1152   gtk_tree_store_append (GTK_TREE_STORE (child_model), &iter, NULL);
1153   gtk_tree_store_set (GTK_TREE_STORE (child_model), &iter, 0, "C", -1);
1154
1155
1156   sort_model = GTK_TREE_MODEL (gtk_tree_model_sort_new_with_model (child_model));
1157   gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (sort_model),
1158                                         0, GTK_SORT_ASCENDING);
1159
1160   path = gtk_tree_path_new_from_indices (1, 1, -1);
1161
1162   /* make sure a level is constructed */ 
1163   gtk_tree_model_get_iter (sort_model, &sort_iter, path);
1164
1165   /* change the "E" row in a way that causes it to change position */ 
1166   gtk_tree_model_get_iter (child_model, &iter, path);
1167   gtk_tree_store_set (GTK_TREE_STORE (child_model), &iter, 0, "A", -1);
1168 }
1169
1170
1171 static int
1172 specific_bug_301558_sort_func (GtkTreeModel *model,
1173                                GtkTreeIter  *a,
1174                                GtkTreeIter  *b,
1175                                gpointer      data)
1176 {
1177   int i, j;
1178
1179   gtk_tree_model_get (model, a, 0, &i, -1);
1180   gtk_tree_model_get (model, b, 0, &j, -1);
1181
1182   return j - i;
1183 }
1184
1185 static void
1186 specific_bug_301558 (void)
1187 {
1188   /* Test case for GNOME Bugzilla bug 301558 provided by
1189    * Markku Vire.
1190    */
1191   GtkTreeStore *tree;
1192   GtkTreeModel *filter;
1193   GtkTreeModel *sort;
1194   GtkTreeIter root, iter, iter2;
1195   GtkWidget *view;
1196   int i;
1197   gboolean add;
1198
1199   tree = gtk_tree_store_new (2, G_TYPE_INT, G_TYPE_BOOLEAN);
1200   gtk_tree_store_append (tree, &iter, NULL);
1201   gtk_tree_store_set (tree, &iter, 0, 123, 1, TRUE, -1);
1202   gtk_tree_store_append (tree, &iter2, &iter);
1203   gtk_tree_store_set (tree, &iter2, 0, 73, 1, TRUE, -1);
1204
1205   sort = gtk_tree_model_sort_new_with_model (GTK_TREE_MODEL (tree));
1206   gtk_tree_sortable_set_default_sort_func (GTK_TREE_SORTABLE (sort),
1207                                            specific_bug_301558_sort_func,
1208                                            NULL, NULL);
1209
1210   filter = gtk_tree_model_filter_new (sort, NULL);
1211   gtk_tree_model_filter_set_visible_column (GTK_TREE_MODEL_FILTER (filter), 1);
1212
1213   view = gtk_tree_view_new_with_model (filter);
1214
1215   while (gtk_events_pending ())
1216     gtk_main_iteration ();
1217
1218   add = TRUE;
1219
1220   for (i = 0; i < 10; i++)
1221     {
1222       if (!gtk_tree_model_get_iter_first (GTK_TREE_MODEL (tree), &root))
1223         g_assert_not_reached ();
1224
1225       if (add)
1226         {
1227           gtk_tree_store_append (tree, &iter, &root);
1228           gtk_tree_store_set (tree, &iter, 0, 456, 1, TRUE, -1);
1229         }
1230       else
1231         {
1232           int n;
1233           n = gtk_tree_model_iter_n_children (GTK_TREE_MODEL (tree), &root);
1234           gtk_tree_model_iter_nth_child (GTK_TREE_MODEL (tree), &iter,
1235                                          &root, n - 1);
1236           gtk_tree_store_remove (tree, &iter);
1237         }
1238
1239       add = !add;
1240     }
1241 }
1242
1243
1244 static gboolean
1245 specific_bug_311955_filter_func (GtkTreeModel *model,
1246                                  GtkTreeIter  *iter,
1247                                  gpointer      data)
1248 {
1249   int value;
1250
1251   gtk_tree_model_get (model, iter, 0, &value, -1);
1252
1253   return (value != 0);
1254 }
1255
1256 static void
1257 specific_bug_311955 (void)
1258 {
1259   /* This is a test case for GNOME Bugzilla bug 311955.  It was written
1260    * by Markku Vire.
1261    */
1262   GtkTreeIter iter, child, root;
1263   GtkTreeStore *store;
1264   GtkTreeModel *sort;
1265   GtkTreeModel *filter;
1266
1267   GtkWidget *window;
1268   GtkWidget *tree_view;
1269   int i;
1270   int n;
1271
1272   store = gtk_tree_store_new (1, G_TYPE_INT);
1273
1274   gtk_tree_store_append (store, &root, NULL);
1275   gtk_tree_store_set (store, &root, 0, 33, -1);
1276
1277   gtk_tree_store_append (store, &iter, &root);
1278   gtk_tree_store_set (store, &iter, 0, 50, -1);
1279
1280   gtk_tree_store_append (store, &iter, NULL);
1281   gtk_tree_store_set (store, &iter, 0, 22, -1);
1282
1283   sort = gtk_tree_model_sort_new_with_model (GTK_TREE_MODEL (store));
1284   filter = gtk_tree_model_filter_new (sort, NULL);
1285
1286   gtk_tree_model_filter_set_visible_func (GTK_TREE_MODEL_FILTER (filter),
1287                                           specific_bug_311955_filter_func,
1288                                           NULL, NULL);
1289
1290   window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
1291   tree_view = gtk_tree_view_new_with_model (filter);
1292   g_object_unref (store);
1293
1294   gtk_tree_view_expand_all (GTK_TREE_VIEW (tree_view));
1295
1296   while (gtk_events_pending ())
1297     gtk_main_iteration ();
1298
1299   /* Fill model */
1300   for (i = 0; i < 4; i++)
1301     {
1302       gtk_tree_model_get_iter_first (GTK_TREE_MODEL (store), &root);
1303
1304       gtk_tree_store_append (store, &iter, &root);
1305
1306       if (i < 3)
1307         gtk_tree_store_set (store, &iter, 0, i, -1);
1308
1309       if (i % 2 == 0)
1310         {
1311           gtk_tree_store_append (store, &child, &iter);
1312           gtk_tree_store_set (store, &child, 0, 10, -1);
1313         }
1314     }
1315
1316   while (gtk_events_pending ())
1317     gtk_main_iteration ();
1318
1319   /* Remove bottommost child from the tree. */
1320   gtk_tree_model_get_iter_first (GTK_TREE_MODEL (store), &root);
1321   n = gtk_tree_model_iter_n_children (GTK_TREE_MODEL (store), &root);
1322
1323   if (gtk_tree_model_iter_nth_child (GTK_TREE_MODEL (store), &iter, &root, n - 2))
1324     {
1325       if (gtk_tree_model_iter_children (GTK_TREE_MODEL (store), &child, &iter))
1326         gtk_tree_store_remove (store, &child);
1327     }
1328   else
1329     g_assert_not_reached ();
1330 }
1331
1332 static void
1333 specific_bug_346800 (void)
1334 {
1335   /* This is a test case for GNOME Bugzilla bug 346800.  It was written
1336    * by Jonathan Matthew.
1337    */
1338
1339   GtkTreeIter node_iters[50];
1340   GtkTreeIter child_iters[50];
1341   GtkTreeModel *model;
1342   GtkTreeModelFilter *filter;
1343   GtkTreeStore *store;
1344   GType *columns;
1345   int i;
1346   int items = 50;
1347   columns = g_new (GType, 2);
1348   columns[0] = G_TYPE_STRING;
1349   columns[1] = G_TYPE_BOOLEAN;
1350   store = gtk_tree_store_newv (2, columns);
1351   model = GTK_TREE_MODEL (store);
1352
1353   filter = GTK_TREE_MODEL_FILTER (gtk_tree_model_filter_new (model, NULL));
1354   gtk_tree_model_filter_set_visible_column (filter, 1);
1355
1356   for (i=0; i<items; i++)
1357     {
1358       /* allocate random amounts of junk, otherwise the filter model's arrays can expand without moving */
1359
1360       g_malloc (138);
1361       gtk_tree_store_append (store, &node_iters[i], NULL);
1362       gtk_tree_store_set (store, &node_iters[i],
1363                           0, "something",
1364                           1, ((i%6) == 0) ? FALSE : TRUE,
1365                           -1);
1366
1367       g_malloc (47);
1368       gtk_tree_store_append (store, &child_iters[i], &node_iters[i]);
1369       gtk_tree_store_set (store, &child_iters[i],
1370                           0, "something else",
1371                           1, FALSE,
1372                           -1);
1373       gtk_tree_model_filter_refilter (filter);
1374
1375       if (i > 6)
1376         {
1377           gtk_tree_store_set (GTK_TREE_STORE (model), &child_iters[i-1], 1,
1378                               (i & 1) ? TRUE : FALSE, -1);
1379           gtk_tree_model_filter_refilter (filter);
1380
1381           gtk_tree_store_set (GTK_TREE_STORE (model), &child_iters[i-2], 1,
1382                               (i & 1) ? FALSE: TRUE, -1);
1383           gtk_tree_model_filter_refilter (filter);
1384         }
1385     }
1386 }
1387
1388
1389 static void
1390 specific_bug_364946 (void)
1391 {
1392   /* This is a test case for GNOME Bugzilla bug 364946.  It was written
1393    * by Andreas Koehler.
1394    */
1395   GtkTreeStore *store;
1396   GtkTreeIter a, aa, aaa, aab, iter;
1397   GtkTreeModel *s_model;
1398
1399   store = gtk_tree_store_new (1, G_TYPE_STRING);
1400
1401   gtk_tree_store_append (store, &a, NULL);
1402   gtk_tree_store_set (store, &a, 0, "0", -1);
1403
1404   gtk_tree_store_append (store, &aa, &a);
1405   gtk_tree_store_set (store, &aa, 0, "0:0", -1);
1406
1407   gtk_tree_store_append (store, &aaa, &aa);
1408   gtk_tree_store_set (store, &aaa, 0, "0:0:0", -1);
1409
1410   gtk_tree_store_append (store, &aab, &aa);
1411   gtk_tree_store_set (store, &aab, 0, "0:0:1", -1);
1412
1413   s_model = gtk_tree_model_sort_new_with_model (GTK_TREE_MODEL (store));
1414   gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (s_model), 0,
1415                                         GTK_SORT_ASCENDING);
1416
1417   gtk_tree_model_get_iter_from_string (s_model, &iter, "0:0:0");
1418
1419   gtk_tree_store_set (store, &aaa, 0, "0:0:0", -1);
1420   gtk_tree_store_remove (store, &aaa);
1421   gtk_tree_store_remove (store, &aab);
1422
1423   gtk_tree_model_sort_clear_cache (GTK_TREE_MODEL_SORT (s_model));
1424 }
1425
1426
1427 static gboolean
1428 specific_bug_464173_visible_func (GtkTreeModel *model,
1429                                   GtkTreeIter  *iter,
1430                                   gpointer      data)
1431 {
1432   gboolean *visible = (gboolean *)data;
1433
1434   return *visible;
1435 }
1436
1437 static void
1438 specific_bug_464173 (void)
1439 {
1440   /* Test case for GNOME Bugzilla bug 464173, test case written
1441    * by Andreas Koehler.
1442    */
1443   GtkTreeStore *model;
1444   GtkTreeModelFilter *f_model;
1445   GtkTreeIter iter1, iter2;
1446   GtkWidget *view;
1447   gboolean visible = TRUE;
1448
1449   model = gtk_tree_store_new (1, G_TYPE_STRING);
1450   gtk_tree_store_append (model, &iter1, NULL);
1451   gtk_tree_store_set (model, &iter1, 0, "Foo", -1);
1452   gtk_tree_store_append (model, &iter2, &iter1);
1453   gtk_tree_store_set (model, &iter2, 0, "Bar", -1);
1454
1455   f_model = GTK_TREE_MODEL_FILTER (gtk_tree_model_filter_new (GTK_TREE_MODEL(model), NULL));
1456   gtk_tree_model_filter_set_visible_func (f_model,
1457                                           specific_bug_464173_visible_func,
1458                                           &visible, NULL);
1459
1460   view = gtk_tree_view_new_with_model (GTK_TREE_MODEL (f_model));
1461
1462   visible = FALSE;
1463   gtk_tree_model_filter_refilter (f_model);
1464 }
1465
1466
1467 static gboolean
1468 specific_bug_540201_filter_func (GtkTreeModel *model,
1469                                  GtkTreeIter  *iter,
1470                                  gpointer      data)
1471 {
1472   gboolean has_children;
1473
1474   has_children = gtk_tree_model_iter_has_child (model, iter);
1475
1476   return has_children;
1477 }
1478
1479 static void
1480 specific_bug_540201 (void)
1481 {
1482   /* Test case for GNOME Bugzilla bug 540201, steps provided by
1483    * Charles Day.
1484    */
1485   GtkTreeIter iter, root;
1486   GtkTreeStore *store;
1487   GtkTreeModel *filter;
1488
1489   GtkWidget *tree_view;
1490
1491   store = gtk_tree_store_new (1, G_TYPE_INT);
1492
1493   gtk_tree_store_append (store, &root, NULL);
1494   gtk_tree_store_set (store, &root, 0, 33, -1);
1495
1496   filter = gtk_tree_model_filter_new (GTK_TREE_MODEL (store), NULL);
1497   tree_view = gtk_tree_view_new_with_model (filter);
1498
1499   gtk_tree_model_filter_set_visible_func (GTK_TREE_MODEL_FILTER (filter),
1500                                           specific_bug_540201_filter_func,
1501                                           NULL, NULL);
1502
1503   gtk_tree_store_append (store, &iter, &root);
1504   gtk_tree_store_set (store, &iter, 0, 50, -1);
1505
1506   gtk_tree_store_append (store, &iter, &root);
1507   gtk_tree_store_set (store, &iter, 0, 22, -1);
1508
1509
1510   gtk_tree_store_append (store, &root, NULL);
1511   gtk_tree_store_set (store, &root, 0, 33, -1);
1512
1513   gtk_tree_store_append (store, &iter, &root);
1514   gtk_tree_store_set (store, &iter, 0, 22, -1);
1515 }
1516
1517
1518 static gboolean
1519 specific_bug_549287_visible_func (GtkTreeModel *model,
1520                                   GtkTreeIter  *iter,
1521                                   gpointer      data)
1522 {
1523   gboolean result = FALSE;
1524
1525   result = gtk_tree_model_iter_has_child (model, iter);
1526
1527   return result;
1528 }
1529
1530 static void
1531 specific_bug_549287 (void)
1532 {
1533   /* Test case for GNOME Bugzilla bug 529287, provided by Julient Puydt */
1534
1535   int i;
1536   GtkTreeStore *store;
1537   GtkTreeModel *filtered;
1538   GtkWidget *view;
1539   GtkTreeIter iter;
1540   GtkTreeIter *swap, *parent, *child;
1541
1542   store = gtk_tree_store_new (1, G_TYPE_STRING);
1543   filtered = gtk_tree_model_filter_new (GTK_TREE_MODEL (store), NULL);
1544   gtk_tree_model_filter_set_visible_func (GTK_TREE_MODEL_FILTER (filtered),
1545                                           specific_bug_549287_visible_func,
1546                                           NULL, NULL);
1547
1548   view = gtk_tree_view_new_with_model (filtered);
1549
1550   for (i = 0; i < 4; i++)
1551     {
1552       if (gtk_tree_model_get_iter_first (GTK_TREE_MODEL (store), &iter))
1553         {
1554           parent = gtk_tree_iter_copy (&iter);
1555           child = gtk_tree_iter_copy (&iter);
1556
1557           while (gtk_tree_model_iter_nth_child (GTK_TREE_MODEL (store),
1558                                                 child, parent, 0))
1559             {
1560
1561               swap = parent;
1562               parent = child;
1563               child = swap;
1564             }
1565
1566           gtk_tree_store_append (store, child, parent);
1567           gtk_tree_store_set (store, child,
1568                               0, "Something",
1569                               -1);
1570
1571           gtk_tree_iter_free (parent);
1572           gtk_tree_iter_free (child);
1573         }
1574       else
1575         {
1576           gtk_tree_store_append (store, &iter, NULL);
1577           gtk_tree_store_set (store, &iter,
1578                               0, "Something",
1579                               -1);
1580         }
1581
1582       /* since we inserted something, we changed the visibility conditions: */
1583       gtk_tree_model_filter_refilter (GTK_TREE_MODEL_FILTER (filtered));
1584     }
1585 }
1586
1587 /* main */
1588
1589 int
1590 main (int    argc,
1591       char **argv)
1592 {
1593   gtk_test_init (&argc, &argv, NULL);
1594
1595   g_test_add ("/FilterModel/self/verify-test-suite",
1596               FilterTest, NULL,
1597               filter_test_setup,
1598               verify_test_suite,
1599               filter_test_teardown);
1600
1601   g_test_add ("/FilterModel/self/verify-test-suite/vroot/depth-1",
1602               FilterTest, gtk_tree_path_new_from_indices (2, -1),
1603               filter_test_setup,
1604               verify_test_suite_vroot,
1605               filter_test_teardown);
1606   g_test_add ("/FilterModel/self/verify-test-suite/vroot/depth-2",
1607               FilterTest, gtk_tree_path_new_from_indices (2, 3, -1),
1608               filter_test_setup,
1609               verify_test_suite_vroot,
1610               filter_test_teardown);
1611
1612
1613   g_test_add ("/FilterModel/filled/hide-root-level",
1614               FilterTest, NULL,
1615               filter_test_setup,
1616               filled_hide_root_level,
1617               filter_test_teardown);
1618   g_test_add ("/FilterModel/filled/hide-child-levels",
1619               FilterTest, NULL,
1620               filter_test_setup,
1621               filled_hide_child_levels,
1622               filter_test_teardown);
1623
1624   g_test_add ("/FilterModel/filled/hide-root-level/vroot",
1625               FilterTest, gtk_tree_path_new_from_indices (2, -1),
1626               filter_test_setup,
1627               filled_vroot_hide_root_level,
1628               filter_test_teardown);
1629   g_test_add ("/FilterModel/filled/hide-child-levels/vroot",
1630               FilterTest, gtk_tree_path_new_from_indices (2, -1),
1631               filter_test_setup,
1632               filled_vroot_hide_child_levels,
1633               filter_test_teardown);
1634
1635
1636   g_test_add ("/FilterModel/empty/show-nodes",
1637               FilterTest, NULL,
1638               filter_test_setup_empty,
1639               empty_show_nodes,
1640               filter_test_teardown);
1641
1642   g_test_add ("/FilterModel/empty/show-nodes/vroot",
1643               FilterTest, gtk_tree_path_new_from_indices (2, -1),
1644               filter_test_setup_empty,
1645               empty_vroot_show_nodes,
1646               filter_test_teardown);
1647
1648
1649   g_test_add ("/FilterModel/unfiltered/hide-single",
1650               FilterTest, NULL,
1651               filter_test_setup_unfiltered,
1652               unfiltered_hide_single,
1653               filter_test_teardown);
1654   g_test_add ("/FilterModel/unfiltered/hide-single-child",
1655               FilterTest, NULL,
1656               filter_test_setup_unfiltered,
1657               unfiltered_hide_single_child,
1658               filter_test_teardown);
1659   g_test_add ("/FilterModel/unfiltered/hide-single-multi-level",
1660               FilterTest, NULL,
1661               filter_test_setup_unfiltered,
1662               unfiltered_hide_single_multi_level,
1663               filter_test_teardown);
1664
1665   g_test_add ("/FilterModel/unfiltered/show-single",
1666               FilterTest, NULL,
1667               filter_test_setup_empty_unfiltered,
1668               unfiltered_show_single,
1669               filter_test_teardown);
1670   g_test_add ("/FilterModel/unfiltered/show-single-child",
1671               FilterTest, NULL,
1672               filter_test_setup_empty_unfiltered,
1673               unfiltered_show_single_child,
1674               filter_test_teardown);
1675   g_test_add ("/FilterModel/unfiltered/show-single-multi-level",
1676               FilterTest, NULL,
1677               filter_test_setup_empty_unfiltered,
1678               unfiltered_show_single_multi_level,
1679               filter_test_teardown);
1680
1681
1682   g_test_add_func ("/FilterModel/specific/path-dependent-filter",
1683                    specific_path_dependent_filter);
1684   g_test_add_func ("/FilterModel/specific/append-after-collapse",
1685                    specific_append_after_collapse);
1686   g_test_add_func ("/FilterModel/specific/sort-filter-remove-node",
1687                    specific_sort_filter_remove_node);
1688   g_test_add_func ("/FilterModel/specific/sort-filter-remove-root",
1689                    specific_sort_filter_remove_root);
1690   g_test_add_func ("/FilterModel/specific/root-mixed-visibility",
1691                    specific_root_mixed_visibility);
1692   g_test_add_func ("/FilterModel/specific/filter-add-child",
1693                    specific_filter_add_child);
1694
1695   g_test_add_func ("/FilterModel/specific/bug-300089",
1696                    specific_bug_300089);
1697   g_test_add_func ("/FilterModel/specific/bug-301558",
1698                    specific_bug_301558);
1699   g_test_add_func ("/FilterModel/specific/bug-311955",
1700                    specific_bug_311955);
1701   g_test_add_func ("/FilterModel/specific/bug-346800",
1702                    specific_bug_346800);
1703   g_test_add_func ("/FilterModel/specific/bug-364946",
1704                    specific_bug_364946);
1705   g_test_add_func ("/FilterModel/specific/bug-464173",
1706                    specific_bug_464173);
1707   g_test_add_func ("/FilterModel/specific/bug-540201",
1708                    specific_bug_540201);
1709   g_test_add_func ("/FilterModel/specific/bug-549287",
1710                    specific_bug_549287);
1711
1712   return g_test_run ();
1713 }