]> Pileus Git - ~andy/gtk/blob - gtk/tests/filtermodel.c
Improve error messages of signal monitor
[~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 /* Left to do:
24  *   - Proper coverage checking to see if the unit tests cover
25  *     all possible cases.
26  *   - Verify if the ref counting is done properly for both the
27  *     normal ref_count and the zero_ref_count.  One way to test
28  *     this area is by collapsing/expanding branches on the view
29  *     that is connected to the filter model.
30  *   - Check if the iterator stamp is incremented at the correct times.
31  */
32
33
34 /*
35  * Model creation
36  */
37
38 #define LEVEL_LENGTH 5
39
40 static void
41 create_tree_store_set_values (GtkTreeStore *store,
42                               GtkTreeIter  *iter,
43                               gboolean      visible)
44 {
45   GtkTreePath *path;
46   gchar *path_string;
47
48   path = gtk_tree_model_get_path (GTK_TREE_MODEL (store), iter);
49   path_string = gtk_tree_path_to_string (path);
50
51   gtk_tree_store_set (store, iter,
52                       0, path_string,
53                       1, visible,
54                       -1);
55
56   gtk_tree_path_free (path);
57   g_free (path_string);
58 }
59
60 static void
61 create_tree_store_recurse (int           depth,
62                            GtkTreeStore *store,
63                            GtkTreeIter  *parent,
64                            gboolean      visible)
65 {
66   int i;
67
68   for (i = 0; i < LEVEL_LENGTH; i++)
69     {
70       GtkTreeIter iter;
71
72       gtk_tree_store_insert (store, &iter, parent, i);
73       create_tree_store_set_values (store, &iter, visible);
74
75       if (depth > 0)
76         create_tree_store_recurse (depth - 1, store, &iter, visible);
77     }
78 }
79
80 static GtkTreeStore *
81 create_tree_store (int      depth,
82                    gboolean visible)
83 {
84   GtkTreeStore *store;
85
86   store = gtk_tree_store_new (2, G_TYPE_STRING, G_TYPE_BOOLEAN);
87
88   create_tree_store_recurse (depth, store, NULL, visible);
89
90   return store;
91 }
92
93 /*
94  * Signal monitor
95  */
96
97 typedef enum
98 {
99   ROW_INSERTED,
100   ROW_DELETED,
101   ROW_CHANGED,
102   ROW_HAS_CHILD_TOGGLED,
103   ROWS_REORDERED,
104   LAST_SIGNAL
105 }
106 SignalName;
107
108 static const char *
109 signal_name_to_string (SignalName signal)
110 {
111   switch (signal)
112     {
113       case ROW_INSERTED:
114           return "row-inserted";
115
116       case ROW_DELETED:
117           return "row-deleted";
118
119       case ROW_CHANGED:
120           return "row-changed";
121
122       case ROW_HAS_CHILD_TOGGLED:
123           return "row-has-child-toggled";
124
125       case ROWS_REORDERED:
126           return "rows-reordered";
127
128       default:
129           /* Fall through */
130           break;
131     }
132
133   return "(unknown)";
134 }
135
136 typedef struct
137 {
138   SignalName signal;
139   GtkTreePath *path;
140 }
141 Signal;
142
143
144 static Signal *
145 signal_new (SignalName signal, GtkTreePath *path)
146 {
147   Signal *s;
148
149   s = g_new0 (Signal, 1);
150   s->signal = signal;
151   s->path = gtk_tree_path_copy (path);
152
153   return s;
154 }
155
156 static void
157 signal_free (Signal *s)
158 {
159   if (s->path)
160     gtk_tree_path_free (s->path);
161
162   g_free (s);
163 }
164
165
166 typedef struct
167 {
168   GQueue *queue;
169   GtkTreeModel *client;
170   gulong signal_ids[LAST_SIGNAL];
171 }
172 SignalMonitor;
173
174
175 static void
176 signal_monitor_generic_handler (SignalMonitor *m,
177                                 SignalName     signal,
178                                 GtkTreeModel  *model,
179                                 GtkTreePath   *path)
180 {
181   Signal *s;
182
183   if (g_queue_is_empty (m->queue))
184     {
185       gchar *path_str;
186
187       path_str = gtk_tree_path_to_string (path);
188       g_error ("Signal queue empty, got signal %s path %s\n",
189                signal_name_to_string (signal), path_str);
190       g_free (path_str);
191
192       g_assert_not_reached ();
193     }
194
195   if (m->client != model)
196     {
197       g_error ("Model mismatch; expected %p, got %p\n",
198                m->client, model);
199       g_assert_not_reached ();
200     }
201
202   s = g_queue_peek_tail (m->queue);
203
204 #if 0
205   /* For debugging: output signals that are coming in.  Leaks memory. */
206   g_print ("signal=%s path=%s\n", signal_name_to_string (signal),
207            gtk_tree_path_to_string (path));
208 #endif
209
210   if (s->signal != signal
211       || gtk_tree_path_compare (s->path, path) != 0)
212     {
213       gchar *path_str, *s_path_str;
214
215       s_path_str = gtk_tree_path_to_string (s->path);
216       path_str = gtk_tree_path_to_string (path);
217
218       g_error ("Signals don't match; expected signal %s path %s, got signal %s path %s\n",
219                signal_name_to_string (s->signal), s_path_str,
220                signal_name_to_string (signal), path_str);
221
222       g_free (s_path_str);
223       g_free (path_str);
224
225       g_assert_not_reached ();
226     }
227
228   s = g_queue_pop_tail (m->queue);
229
230   signal_free (s);
231 }
232
233 static void
234 signal_monitor_row_inserted (GtkTreeModel *model,
235                              GtkTreePath  *path,
236                              GtkTreeIter  *iter,
237                              gpointer      data)
238 {
239   signal_monitor_generic_handler (data, ROW_INSERTED,
240                                   model, path);
241 }
242
243 static void
244 signal_monitor_row_deleted (GtkTreeModel *model,
245                             GtkTreePath  *path,
246                             gpointer      data)
247 {
248   signal_monitor_generic_handler (data, ROW_DELETED,
249                                   model, path);
250 }
251
252 static void
253 signal_monitor_row_changed (GtkTreeModel *model,
254                             GtkTreePath  *path,
255                             GtkTreeIter  *iter,
256                             gpointer      data)
257 {
258   signal_monitor_generic_handler (data, ROW_CHANGED,
259                                   model, path);
260 }
261
262 static void
263 signal_monitor_row_has_child_toggled (GtkTreeModel *model,
264                                       GtkTreePath  *path,
265                                       GtkTreeIter  *iter,
266                                       gpointer      data)
267 {
268   signal_monitor_generic_handler (data, ROW_HAS_CHILD_TOGGLED,
269                                   model, path);
270 }
271
272 static void
273 signal_monitor_rows_reordered (GtkTreeModel *model,
274                                GtkTreePath  *path,
275                                GtkTreeIter  *iter,
276                                gint         *new_order,
277                                gpointer      data)
278 {
279   signal_monitor_generic_handler (data, ROWS_REORDERED,
280                                   model, path);
281 }
282
283 static SignalMonitor *
284 signal_monitor_new (GtkTreeModel *client)
285 {
286   SignalMonitor *m;
287
288   m = g_new0 (SignalMonitor, 1);
289   m->client = g_object_ref (client);
290   m->queue = g_queue_new ();
291
292   m->signal_ids[ROW_INSERTED] = g_signal_connect (client,
293                                                   "row-inserted",
294                                                   G_CALLBACK (signal_monitor_row_inserted),
295                                                   m);
296   m->signal_ids[ROW_DELETED] = g_signal_connect (client,
297                                                  "row-deleted",
298                                                  G_CALLBACK (signal_monitor_row_deleted),
299                                                  m);
300   m->signal_ids[ROW_CHANGED] = g_signal_connect (client,
301                                                  "row-changed",
302                                                  G_CALLBACK (signal_monitor_row_changed),
303                                                  m);
304   m->signal_ids[ROW_HAS_CHILD_TOGGLED] = g_signal_connect (client,
305                                                            "row-has-child-toggled",
306                                                            G_CALLBACK (signal_monitor_row_has_child_toggled),
307                                                            m);
308   m->signal_ids[ROWS_REORDERED] = g_signal_connect (client,
309                                                     "rows-reordered",
310                                                     G_CALLBACK (signal_monitor_rows_reordered),
311                                                     m);
312
313   return m;
314 }
315
316 static void
317 signal_monitor_free (SignalMonitor *m)
318 {
319   int i;
320
321   for (i = 0; i < LAST_SIGNAL; i++)
322     g_signal_handler_disconnect (m->client, m->signal_ids[i]);
323
324   g_object_unref (m->client);
325
326   if (m->queue)
327     g_queue_free (m->queue);
328
329   g_free (m);
330 }
331
332 static void
333 signal_monitor_assert_is_empty (SignalMonitor *m)
334 {
335   g_assert (g_queue_is_empty (m->queue));
336 }
337
338 static void
339 signal_monitor_append_signal_path (SignalMonitor *m,
340                                    SignalName     signal,
341                                    GtkTreePath   *path)
342 {
343   Signal *s;
344
345   s = signal_new (signal, path);
346   g_queue_push_head (m->queue, s);
347 }
348
349 static void
350 signal_monitor_append_signal (SignalMonitor *m,
351                               SignalName     signal,
352                               const gchar   *path_string)
353 {
354   Signal *s;
355   GtkTreePath *path;
356
357   path = gtk_tree_path_new_from_string (path_string);
358
359   s = signal_new (signal, path);
360   g_queue_push_head (m->queue, s);
361
362   gtk_tree_path_free (path);
363 }
364
365 /*
366  * Fixture
367  */
368
369 typedef struct
370 {
371   GtkWidget *tree_view;
372
373   GtkTreeStore *store;
374   GtkTreeModelFilter *filter;
375
376   SignalMonitor *monitor;
377
378   guint block_signals : 1;
379 } FilterTest;
380
381
382 static void
383 filter_test_store_signal (FilterTest *fixture)
384 {
385   if (fixture->block_signals)
386     g_signal_stop_emission_by_name (fixture->store, "row-changed");
387 }
388
389
390 static void
391 filter_test_setup_generic (FilterTest    *fixture,
392                            gconstpointer  test_data,
393                            int            depth,
394                            gboolean       empty,
395                            gboolean       unfiltered)
396 {
397   const GtkTreePath *vroot = test_data;
398   GtkTreeModel *filter;
399
400   fixture->store = create_tree_store (depth, !empty);
401
402   g_signal_connect_swapped (fixture->store, "row-changed",
403                             G_CALLBACK (filter_test_store_signal), fixture);
404
405   /* Please forgive me for casting const away. */
406   filter = gtk_tree_model_filter_new (GTK_TREE_MODEL (fixture->store),
407                                       (GtkTreePath *)vroot);
408   fixture->filter = GTK_TREE_MODEL_FILTER (filter);
409
410   if (!unfiltered)
411     gtk_tree_model_filter_set_visible_column (fixture->filter, 1);
412
413   /* We need a tree view that's listening to get ref counting from that
414    * side.
415    */
416   fixture->tree_view = gtk_tree_view_new_with_model (filter);
417
418   fixture->monitor = signal_monitor_new (filter);
419 }
420
421 static void
422 filter_test_setup (FilterTest    *fixture,
423                    gconstpointer  test_data)
424 {
425   filter_test_setup_generic (fixture, test_data, 3, FALSE, FALSE);
426 }
427
428 static void
429 filter_test_setup_empty (FilterTest    *fixture,
430                          gconstpointer  test_data)
431 {
432   filter_test_setup_generic (fixture, test_data, 3, TRUE, FALSE);
433 }
434
435 static void
436 filter_test_setup_unfiltered (FilterTest    *fixture,
437                               gconstpointer  test_data)
438 {
439   filter_test_setup_generic (fixture, test_data, 3, FALSE, TRUE);
440 }
441
442 static void
443 filter_test_setup_empty_unfiltered (FilterTest    *fixture,
444                                     gconstpointer  test_data)
445 {
446   filter_test_setup_generic (fixture, test_data, 3, TRUE, TRUE);
447 }
448
449 static GtkTreePath *
450 strip_virtual_root (GtkTreePath *path,
451                     GtkTreePath *root_path)
452 {
453   GtkTreePath *real_path;
454
455   if (root_path)
456     {
457       int j;
458       int depth = gtk_tree_path_get_depth (path);
459       int root_depth = gtk_tree_path_get_depth (root_path);
460
461       real_path = gtk_tree_path_new ();
462
463       for (j = 0; j < depth - root_depth; j++)
464         gtk_tree_path_append_index (real_path,
465                                     gtk_tree_path_get_indices (path)[root_depth + j]);
466     }
467   else
468     real_path = gtk_tree_path_copy (path);
469
470   return real_path;
471 }
472
473 static void
474 filter_test_append_refilter_signals_recurse (FilterTest  *fixture,
475                                              GtkTreePath *store_path,
476                                              GtkTreePath *filter_path,
477                                              int          depth,
478                                              GtkTreePath *root_path)
479 {
480   int i;
481   int rows_deleted = 0;
482   GtkTreeIter iter;
483
484   gtk_tree_path_down (store_path);
485   gtk_tree_path_down (filter_path);
486
487   gtk_tree_model_get_iter (GTK_TREE_MODEL (fixture->store),
488                            &iter, store_path);
489
490   for (i = 0; i < LEVEL_LENGTH; i++)
491     {
492       gboolean visible;
493       GtkTreePath *real_path;
494
495       gtk_tree_model_get (GTK_TREE_MODEL (fixture->store), &iter,
496                           1, &visible,
497                           -1);
498
499       if (root_path &&
500           (!gtk_tree_path_is_descendant (store_path, root_path)
501            || !gtk_tree_path_compare (store_path, root_path)))
502         {
503           if (!gtk_tree_path_compare (store_path, root_path))
504             {
505               if (depth > 1
506                   && gtk_tree_model_iter_has_child (GTK_TREE_MODEL (fixture->store),
507                                                     &iter))
508                 {
509                   GtkTreePath *store_copy;
510                   GtkTreePath *filter_copy;
511
512                   store_copy = gtk_tree_path_copy (store_path);
513                   filter_copy = gtk_tree_path_copy (filter_path);
514                   filter_test_append_refilter_signals_recurse (fixture,
515                                                                store_copy,
516                                                                filter_copy,
517                                                                depth - 1,
518                                                                root_path);
519                   gtk_tree_path_free (store_copy);
520                   gtk_tree_path_free (filter_copy);
521                 }
522             }
523
524           gtk_tree_path_next (store_path);
525           gtk_tree_model_iter_next (GTK_TREE_MODEL (fixture->store), &iter);
526
527           if (visible)
528             gtk_tree_path_next (filter_path);
529
530           continue;
531         }
532
533       real_path = strip_virtual_root (filter_path, root_path);
534
535       if (visible)
536         {
537           /* This row will be inserted */
538           signal_monitor_append_signal_path (fixture->monitor, ROW_CHANGED,
539                                              real_path);
540           signal_monitor_append_signal_path (fixture->monitor,
541                                              ROW_HAS_CHILD_TOGGLED,
542                                              real_path);
543
544           if (depth > 1
545               && gtk_tree_model_iter_has_child (GTK_TREE_MODEL (fixture->store),
546                                                 &iter))
547             {
548               GtkTreePath *store_copy;
549               GtkTreePath *filter_copy;
550
551               store_copy = gtk_tree_path_copy (store_path);
552               filter_copy = gtk_tree_path_copy (filter_path);
553               filter_test_append_refilter_signals_recurse (fixture,
554                                                            store_copy,
555                                                            filter_copy,
556                                                            depth - 1,
557                                                            root_path);
558               gtk_tree_path_free (store_copy);
559               gtk_tree_path_free (filter_copy);
560             }
561
562           gtk_tree_path_next (filter_path);
563         }
564       else
565         {
566           /* This row will be deleted */
567           rows_deleted++;
568           signal_monitor_append_signal_path (fixture->monitor, ROW_DELETED,
569                                              real_path);
570         }
571
572       gtk_tree_path_free (real_path);
573
574       gtk_tree_path_next (store_path);
575       gtk_tree_model_iter_next (GTK_TREE_MODEL (fixture->store), &iter);
576     }
577
578   if (rows_deleted == LEVEL_LENGTH
579       && gtk_tree_path_get_depth (filter_path) > 1)
580     {
581       GtkTreePath *real_path;
582
583       gtk_tree_path_up (store_path);
584       gtk_tree_path_up (filter_path);
585
586       /* A row-has-child-toggled will be emitted on the parent */
587       if (!root_path
588           || (root_path
589               && gtk_tree_path_is_descendant (store_path, root_path)
590               && gtk_tree_path_compare (store_path, root_path)))
591         {
592           real_path = strip_virtual_root (filter_path, root_path);
593           signal_monitor_append_signal_path (fixture->monitor,
594                                              ROW_HAS_CHILD_TOGGLED,
595                                              real_path);
596
597           gtk_tree_path_free (real_path);
598         }
599     }
600 }
601
602 static void
603 filter_test_append_refilter_signals (FilterTest *fixture,
604                                      int         depth)
605 {
606   /* A special function that walks the tree store like the
607    * model validation functions below.
608    */
609   GtkTreePath *path;
610   GtkTreePath *filter_path;
611
612   path = gtk_tree_path_new ();
613   filter_path = gtk_tree_path_new ();
614   filter_test_append_refilter_signals_recurse (fixture,
615                                                path,
616                                                filter_path,
617                                                depth,
618                                                NULL);
619   gtk_tree_path_free (path);
620   gtk_tree_path_free (filter_path);
621 }
622
623 static void
624 filter_test_append_refilter_signals_with_vroot (FilterTest  *fixture,
625                                                 int          depth,
626                                                 GtkTreePath *root_path)
627 {
628   /* A special function that walks the tree store like the
629    * model validation functions below.
630    */
631   GtkTreePath *path;
632   GtkTreePath *filter_path;
633
634   path = gtk_tree_path_new ();
635   filter_path = gtk_tree_path_new ();
636   filter_test_append_refilter_signals_recurse (fixture,
637                                                path,
638                                                filter_path,
639                                                depth,
640                                                root_path);
641   gtk_tree_path_free (path);
642   gtk_tree_path_free (filter_path);
643 }
644
645 static void
646 filter_test_enable_filter (FilterTest *fixture)
647 {
648   gtk_tree_model_filter_set_visible_column (fixture->filter, 1);
649   gtk_tree_model_filter_refilter (fixture->filter);
650 }
651
652 static void
653 filter_test_block_signals (FilterTest *fixture)
654 {
655   fixture->block_signals = TRUE;
656 }
657
658 static void
659 filter_test_unblock_signals (FilterTest *fixture)
660 {
661   fixture->block_signals = FALSE;
662 }
663
664 static void
665 filter_test_teardown (FilterTest    *fixture,
666                       gconstpointer  test_data)
667 {
668   signal_monitor_free (fixture->monitor);
669
670   g_object_unref (fixture->filter);
671   g_object_unref (fixture->store);
672 }
673
674 /*
675  * Model structure validation
676  */
677
678 static void
679 check_filter_model_recurse (FilterTest  *fixture,
680                             GtkTreePath *store_parent_path,
681                             GtkTreePath *filter_parent_path)
682 {
683   int i;
684   GtkTreeIter store_iter;
685   GtkTreeIter filter_iter;
686   gboolean store_has_next, filter_has_next;
687
688   gtk_tree_path_down (store_parent_path);
689   gtk_tree_path_down (filter_parent_path);
690
691   store_has_next = gtk_tree_model_get_iter (GTK_TREE_MODEL (fixture->store),
692                                             &store_iter, store_parent_path);
693   filter_has_next = gtk_tree_model_get_iter (GTK_TREE_MODEL (fixture->filter),
694                                              &filter_iter, filter_parent_path);
695
696   for (i = 0; i < LEVEL_LENGTH; i++)
697     {
698       gboolean visible;
699
700       g_return_if_fail (store_has_next == TRUE);
701
702       gtk_tree_model_get (GTK_TREE_MODEL (fixture->store),
703                           &store_iter,
704                           1, &visible,
705                           -1);
706
707       if (visible)
708         {
709           GtkTreePath *tmp;
710           gchar *filter_str, *store_str;
711
712           g_return_if_fail (filter_has_next == TRUE);
713
714           /* Verify path */
715           tmp = gtk_tree_model_get_path (GTK_TREE_MODEL (fixture->filter),
716                                          &filter_iter);
717           g_return_if_fail (gtk_tree_path_compare (tmp, filter_parent_path) == 0);
718
719           /* Verify model content */
720           gtk_tree_model_get (GTK_TREE_MODEL (fixture->store),
721                               &store_iter,
722                               0, &store_str,
723                               -1);
724           gtk_tree_model_get (GTK_TREE_MODEL (fixture->filter),
725                               &filter_iter,
726                               0, &filter_str,
727                               -1);
728
729           g_return_if_fail (g_strcmp0 (store_str, filter_str) == 0);
730
731           g_free (store_str);
732           g_free (filter_str);
733
734           if (gtk_tree_model_iter_has_child (GTK_TREE_MODEL (fixture->filter),
735                                              &filter_iter))
736             {
737               g_return_if_fail (gtk_tree_model_iter_has_child (GTK_TREE_MODEL (fixture->store), &store_iter));
738
739               check_filter_model_recurse (fixture,
740                                           gtk_tree_path_copy (store_parent_path),
741                                           tmp);
742             }
743
744           gtk_tree_path_next (filter_parent_path);
745           filter_has_next = gtk_tree_model_iter_next (GTK_TREE_MODEL (fixture->filter), &filter_iter);
746         }
747
748       gtk_tree_path_next (store_parent_path);
749       store_has_next = gtk_tree_model_iter_next (GTK_TREE_MODEL (fixture->store), &store_iter);
750     }
751
752   /* Both models should have no more content! */
753   g_return_if_fail (store_has_next == FALSE);
754   g_return_if_fail (filter_has_next == FALSE);
755
756   gtk_tree_path_free (store_parent_path);
757   gtk_tree_path_free (filter_parent_path);
758 }
759
760 static void
761 check_filter_model (FilterTest *fixture)
762 {
763   GtkTreePath *path;
764
765   if (fixture->monitor)
766     signal_monitor_assert_is_empty (fixture->monitor);
767
768   path = gtk_tree_path_new ();
769
770   check_filter_model_recurse (fixture, path, gtk_tree_path_copy (path));
771 }
772
773 static void
774 check_filter_model_with_root (FilterTest  *fixture,
775                               GtkTreePath *path)
776 {
777   if (fixture->monitor)
778     signal_monitor_assert_is_empty (fixture->monitor);
779
780   check_filter_model_recurse (fixture,
781                               gtk_tree_path_copy (path),
782                               gtk_tree_path_new ());
783 }
784
785 /* Helpers */
786
787 static void
788 check_level_length (GtkTreeModelFilter *filter,
789                     const gchar        *level,
790                     const int           length)
791 {
792   if (!level)
793     {
794       int l = gtk_tree_model_iter_n_children (GTK_TREE_MODEL (filter), NULL);
795       g_return_if_fail (l == length);
796     }
797   else
798     {
799       int l;
800       gboolean retrieved_iter = FALSE;
801       GtkTreeIter iter;
802
803       retrieved_iter = gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL (filter),
804                                                             &iter, level);
805       g_return_if_fail (retrieved_iter);
806       l = gtk_tree_model_iter_n_children (GTK_TREE_MODEL (filter), &iter);
807       g_return_if_fail (l == length);
808     }
809 }
810
811 static void
812 set_path_visibility (FilterTest  *fixture,
813                      const gchar *path,
814                      gboolean     visible)
815 {
816   GtkTreeIter store_iter;
817
818   gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL (fixture->store),
819                                        &store_iter, path);
820   gtk_tree_store_set (fixture->store, &store_iter,
821                       1, visible,
822                       -1);
823 }
824
825 #if 0
826 static void
827 insert_path_with_visibility (FilterTest  *fixture,
828                              const gchar *path_string,
829                              gboolean     visible)
830 {
831   int position;
832   GtkTreePath *path;
833   GtkTreeIter parent, iter;
834
835   path = gtk_tree_path_new_from_string (path_string);
836   position = gtk_tree_path_get_indices (path)[gtk_tree_path_get_depth (path)];
837   gtk_tree_path_up (path);
838
839   if (gtk_tree_model_get_iter (GTK_TREE_MODEL (fixture->store), &parent, path))
840     {
841       gtk_tree_store_insert (fixture->store, &iter, &parent, position);
842       create_tree_store_set_values (fixture->store, &iter, visible);
843     }
844   gtk_tree_path_free (path);
845 }
846 #endif
847
848 /*
849  * The actual tests.
850  */
851
852 static void
853 verify_test_suite (FilterTest    *fixture,
854                    gconstpointer  user_data)
855 {
856   check_filter_model (fixture);
857 }
858
859 static void
860 verify_test_suite_vroot (FilterTest    *fixture,
861                          gconstpointer  user_data)
862 {
863   check_filter_model_with_root (fixture, (GtkTreePath *)user_data);
864 }
865
866
867 static void
868 filled_hide_root_level (FilterTest    *fixture,
869                         gconstpointer  user_data)
870 {
871   signal_monitor_append_signal (fixture->monitor, ROW_DELETED, "2");
872   set_path_visibility (fixture, "2", FALSE);
873   check_filter_model (fixture);
874   check_level_length (fixture->filter, NULL, LEVEL_LENGTH - 1);
875
876   signal_monitor_append_signal (fixture->monitor, ROW_DELETED, "0");
877   set_path_visibility (fixture, "0", FALSE);
878   check_filter_model (fixture);
879   check_level_length (fixture->filter, NULL, LEVEL_LENGTH - 2);
880
881   signal_monitor_append_signal (fixture->monitor, ROW_DELETED, "2");
882   set_path_visibility (fixture, "4", FALSE);
883   check_filter_model (fixture);
884   check_level_length (fixture->filter, NULL, LEVEL_LENGTH - 3);
885
886
887   /* Hide remaining */
888   signal_monitor_append_signal (fixture->monitor, ROW_DELETED, "0");
889   signal_monitor_append_signal (fixture->monitor, ROW_DELETED, "0");
890
891   set_path_visibility (fixture, "1", FALSE);
892   check_level_length (fixture->filter, NULL, LEVEL_LENGTH - 4);
893
894   set_path_visibility (fixture, "3", FALSE);
895   check_level_length (fixture->filter, NULL, LEVEL_LENGTH - 5);
896
897   check_filter_model (fixture);
898
899   /* Show some */
900   signal_monitor_append_signal (fixture->monitor, ROW_INSERTED, "0");
901   signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "0");
902   signal_monitor_append_signal (fixture->monitor, ROW_INSERTED, "1");
903   signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "1");
904
905   set_path_visibility (fixture, "1", TRUE);
906   check_level_length (fixture->filter, NULL, LEVEL_LENGTH - 4);
907
908   set_path_visibility (fixture, "3", TRUE);
909   check_level_length (fixture->filter, NULL, LEVEL_LENGTH - 3);
910
911   check_filter_model (fixture);
912 }
913
914 static void
915 filled_hide_child_levels (FilterTest    *fixture,
916                           gconstpointer  user_data)
917 {
918   signal_monitor_append_signal (fixture->monitor, ROW_DELETED, "0:2");
919   set_path_visibility (fixture, "0:2", FALSE);
920   check_filter_model (fixture);
921   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
922   check_level_length (fixture->filter, "0", LEVEL_LENGTH - 1);
923
924   signal_monitor_append_signal (fixture->monitor, ROW_DELETED, "0:3");
925   set_path_visibility (fixture, "0:4", FALSE);
926   check_filter_model (fixture);
927   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
928   check_level_length (fixture->filter, "0", LEVEL_LENGTH - 2);
929
930   set_path_visibility (fixture, "0:4:3", FALSE);
931   check_filter_model (fixture);
932   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
933   check_level_length (fixture->filter, "0", LEVEL_LENGTH - 2);
934
935   set_path_visibility (fixture, "0:4:0", FALSE);
936   set_path_visibility (fixture, "0:4:1", FALSE);
937   set_path_visibility (fixture, "0:4:2", FALSE);
938   set_path_visibility (fixture, "0:4:4", FALSE);
939   check_filter_model (fixture);
940   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
941   check_level_length (fixture->filter, "0", LEVEL_LENGTH - 2);
942
943   /* Since "0:2" is hidden, "0:4" must be "0:3" in the filter model */
944   signal_monitor_append_signal (fixture->monitor, ROW_INSERTED, "0:3");
945   /* FIXME: Actually, the filter model should not be emitted the
946    * row-has-child-toggled signal here.  *However* an extraneous emission
947    * of this signal does not hurt and is allowed.
948    */
949   signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "0:3");
950   set_path_visibility (fixture, "0:4", TRUE);
951   check_filter_model (fixture);
952   check_level_length (fixture->filter, "0:3", 0);
953
954   signal_monitor_append_signal (fixture->monitor, ROW_INSERTED, "0:2");
955   signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "0:2");
956   set_path_visibility (fixture, "0:2", TRUE);
957   check_filter_model (fixture);
958   check_level_length (fixture->filter, "0:2", LEVEL_LENGTH);
959   check_level_length (fixture->filter, "0:3", LEVEL_LENGTH);
960   check_level_length (fixture->filter, "0:4", 0);
961
962   signal_monitor_append_signal (fixture->monitor, ROW_INSERTED, "0:4:0");
963   /* Once 0:4:0 got inserted, 0:4 became a parent */
964   signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "0:4");
965   signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "0:4:0");
966   signal_monitor_append_signal (fixture->monitor, ROW_INSERTED, "0:4:1");
967   signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "0:4:1");
968
969   set_path_visibility (fixture, "0:4:2", TRUE);
970   set_path_visibility (fixture, "0:4:4", TRUE);
971   signal_monitor_assert_is_empty (fixture->monitor);
972   check_level_length (fixture->filter, "0:4", 2);
973 }
974
975
976 static void
977 filled_vroot_hide_root_level (FilterTest    *fixture,
978                               gconstpointer  user_data)
979 {
980   GtkTreePath *path = (GtkTreePath *)user_data;
981
982   /* These changes do not affect the filter's root level */
983   set_path_visibility (fixture, "0", FALSE);
984   check_filter_model_with_root (fixture, path);
985   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
986   check_level_length (fixture->filter, "0", LEVEL_LENGTH);
987
988   set_path_visibility (fixture, "4", FALSE);
989   check_filter_model_with_root (fixture, path);
990   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
991   check_level_length (fixture->filter, "0", LEVEL_LENGTH);
992
993   /* Even though we set the virtual root parent node to FALSE,
994    * the virtual root contents remain.
995    */
996   set_path_visibility (fixture, "2", FALSE);
997   check_filter_model_with_root (fixture, path);
998   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
999   check_level_length (fixture->filter, "0", LEVEL_LENGTH);
1000
1001   /* No change */
1002   set_path_visibility (fixture, "1", FALSE);
1003   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
1004   check_level_length (fixture->filter, "0", LEVEL_LENGTH);
1005
1006   set_path_visibility (fixture, "3", FALSE);
1007   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
1008   check_level_length (fixture->filter, "0", LEVEL_LENGTH);
1009
1010   check_filter_model_with_root (fixture, path);
1011
1012   /* Show some */
1013   set_path_visibility (fixture, "2", TRUE);
1014   check_filter_model_with_root (fixture, path);
1015   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
1016   check_level_length (fixture->filter, "0", LEVEL_LENGTH);
1017
1018   set_path_visibility (fixture, "1", TRUE);
1019   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
1020   check_level_length (fixture->filter, "0", LEVEL_LENGTH);
1021
1022   set_path_visibility (fixture, "3", TRUE);
1023   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
1024   check_level_length (fixture->filter, "0", LEVEL_LENGTH);
1025
1026   check_filter_model_with_root (fixture, path);
1027
1028   /* Now test changes in the virtual root level */
1029   signal_monitor_append_signal (fixture->monitor, ROW_DELETED, "2");
1030   set_path_visibility (fixture, "2:2", FALSE);
1031   check_filter_model_with_root (fixture, path);
1032   check_level_length (fixture->filter, NULL, LEVEL_LENGTH - 1);
1033
1034   signal_monitor_append_signal (fixture->monitor, ROW_DELETED, "3");
1035   set_path_visibility (fixture, "2:4", FALSE);
1036   check_filter_model_with_root (fixture, path);
1037   check_level_length (fixture->filter, NULL, LEVEL_LENGTH - 2);
1038
1039   set_path_visibility (fixture, "1:4", FALSE);
1040   check_filter_model_with_root (fixture, path);
1041   check_level_length (fixture->filter, NULL, LEVEL_LENGTH - 2);
1042
1043   signal_monitor_append_signal (fixture->monitor, ROW_INSERTED, "3");
1044   signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "3");
1045   set_path_visibility (fixture, "2:4", TRUE);
1046   check_filter_model_with_root (fixture, path);
1047   check_level_length (fixture->filter, NULL, LEVEL_LENGTH - 1);
1048
1049   set_path_visibility (fixture, "2", FALSE);
1050   check_filter_model_with_root (fixture, path);
1051   check_level_length (fixture->filter, NULL, LEVEL_LENGTH - 1);
1052
1053   signal_monitor_append_signal (fixture->monitor, ROW_DELETED, "0");
1054   signal_monitor_append_signal (fixture->monitor, ROW_DELETED, "0");
1055   signal_monitor_append_signal (fixture->monitor, ROW_DELETED, "0");
1056   signal_monitor_append_signal (fixture->monitor, ROW_DELETED, "0");
1057   set_path_visibility (fixture, "2:0", FALSE);
1058   set_path_visibility (fixture, "2:1", FALSE);
1059   set_path_visibility (fixture, "2:2", FALSE);
1060   set_path_visibility (fixture, "2:3", FALSE);
1061   set_path_visibility (fixture, "2:4", FALSE);
1062   check_filter_model_with_root (fixture, path);
1063   check_level_length (fixture->filter, NULL, 0);
1064
1065   set_path_visibility (fixture, "2", TRUE);
1066   check_filter_model_with_root (fixture, path);
1067   check_level_length (fixture->filter, NULL, 0);
1068
1069   set_path_visibility (fixture, "1:4", FALSE);
1070   check_filter_model_with_root (fixture, path);
1071   check_level_length (fixture->filter, NULL, 0);
1072
1073   signal_monitor_append_signal (fixture->monitor, ROW_INSERTED, "0");
1074   signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "0");
1075   set_path_visibility (fixture, "2:4", TRUE);
1076   check_filter_model_with_root (fixture, path);
1077   check_level_length (fixture->filter, NULL, LEVEL_LENGTH - 4);
1078
1079   signal_monitor_append_signal (fixture->monitor, ROW_DELETED, "0");
1080   set_path_visibility (fixture, "2:4", FALSE);
1081   check_filter_model_with_root (fixture, path);
1082   check_level_length (fixture->filter, NULL, 0);
1083
1084   set_path_visibility (fixture, "2", FALSE);
1085   check_filter_model_with_root (fixture, path);
1086   check_level_length (fixture->filter, NULL, 0);
1087
1088   signal_monitor_append_signal (fixture->monitor, ROW_INSERTED, "0");
1089   signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "0");
1090   signal_monitor_append_signal (fixture->monitor, ROW_INSERTED, "1");
1091   signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "1");
1092   signal_monitor_append_signal (fixture->monitor, ROW_INSERTED, "2");
1093   signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "2");
1094   set_path_visibility (fixture, "2:0", TRUE);
1095   set_path_visibility (fixture, "2:1", TRUE);
1096   set_path_visibility (fixture, "2:2", TRUE);
1097   check_filter_model_with_root (fixture, path);
1098   check_level_length (fixture->filter, NULL, LEVEL_LENGTH - 2);
1099
1100   set_path_visibility (fixture, "2", TRUE);
1101   check_filter_model_with_root (fixture, path);
1102   check_level_length (fixture->filter, NULL, LEVEL_LENGTH - 2);
1103 }
1104
1105 static void
1106 filled_vroot_hide_child_levels (FilterTest    *fixture,
1107                                 gconstpointer  user_data)
1108 {
1109   GtkTreePath *path = (GtkTreePath *)user_data;
1110
1111   signal_monitor_append_signal (fixture->monitor, ROW_DELETED, "0:2");
1112   set_path_visibility (fixture, "2:0:2", FALSE);
1113   check_filter_model_with_root (fixture, path);
1114   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
1115   check_level_length (fixture->filter, "0", LEVEL_LENGTH - 1);
1116
1117   signal_monitor_append_signal (fixture->monitor, ROW_DELETED, "0:3");
1118   set_path_visibility (fixture, "2:0:4", FALSE);
1119   check_filter_model_with_root (fixture, path);
1120   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
1121   check_level_length (fixture->filter, "0", LEVEL_LENGTH - 2);
1122
1123   set_path_visibility (fixture, "2:0:4:3", FALSE);
1124   check_filter_model_with_root (fixture, path);
1125   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
1126   check_level_length (fixture->filter, "0", LEVEL_LENGTH - 2);
1127
1128   set_path_visibility (fixture, "2:0:4:0", FALSE);
1129   set_path_visibility (fixture, "2:0:4:1", FALSE);
1130   set_path_visibility (fixture, "2:0:4:2", FALSE);
1131   set_path_visibility (fixture, "2:0:4:4", FALSE);
1132   check_filter_model_with_root (fixture, path);
1133   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
1134   check_level_length (fixture->filter, "0", LEVEL_LENGTH - 2);
1135
1136   /* Since "0:2" is hidden, "0:4" must be "0:3" in the filter model */
1137   signal_monitor_append_signal (fixture->monitor, ROW_INSERTED, "0:3");
1138   /* FIXME: Actually, the filter model should not be emitted the
1139    * row-has-child-toggled signal here.  *However* an extraneous emission
1140    * of this signal does not hurt and is allowed.
1141    */
1142   signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "0:3");
1143   set_path_visibility (fixture, "2:0:4", TRUE);
1144   check_filter_model_with_root (fixture, path);
1145   check_level_length (fixture->filter, "0:3", 0);
1146
1147   signal_monitor_append_signal (fixture->monitor, ROW_INSERTED, "0:2");
1148   signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "0:2");
1149   set_path_visibility (fixture, "2:0:2", TRUE);
1150   check_filter_model_with_root (fixture, path);
1151   check_level_length (fixture->filter, "0:2", LEVEL_LENGTH);
1152   check_level_length (fixture->filter, "0:3", LEVEL_LENGTH);
1153   check_level_length (fixture->filter, "0:4", 0);
1154
1155   /* FIXME: Inconsistency!  For the non-vroot case we also receive two
1156    * row-has-child-toggled signals here.
1157    */
1158   signal_monitor_append_signal (fixture->monitor, ROW_INSERTED, "0:4:0");
1159   /* Once 0:4:0 got inserted, 0:4 became a parent */
1160   signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "0:4");
1161   signal_monitor_append_signal (fixture->monitor, ROW_INSERTED, "0:4:1");
1162   set_path_visibility (fixture, "2:0:4:2", TRUE);
1163   set_path_visibility (fixture, "2:0:4:4", TRUE);
1164   check_level_length (fixture->filter, "0:4", 2);
1165 }
1166
1167
1168 static void
1169 empty_show_nodes (FilterTest    *fixture,
1170                   gconstpointer  user_data)
1171 {
1172   check_filter_model (fixture);
1173   check_level_length (fixture->filter, NULL, 0);
1174
1175   signal_monitor_append_signal (fixture->monitor, ROW_INSERTED, "0");
1176   signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "0");
1177   set_path_visibility (fixture, "3", TRUE);
1178   check_filter_model (fixture);
1179   check_level_length (fixture->filter, NULL, 1);
1180   check_level_length (fixture->filter, "0", 0);
1181
1182   set_path_visibility (fixture, "3:2:2", TRUE);
1183   check_filter_model (fixture);
1184   check_level_length (fixture->filter, NULL, 1);
1185   check_level_length (fixture->filter, "0", 0);
1186
1187   signal_monitor_append_signal (fixture->monitor, ROW_INSERTED, "0:0");
1188   signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "0");
1189   signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "0:0");
1190   set_path_visibility (fixture, "3:2", TRUE);
1191   check_filter_model (fixture);
1192   check_level_length (fixture->filter, NULL, 1);
1193   check_level_length (fixture->filter, "0", 1);
1194   check_level_length (fixture->filter, "0:0", 1);
1195   check_level_length (fixture->filter, "0:0:0", 0);
1196
1197   signal_monitor_append_signal (fixture->monitor, ROW_DELETED, "0");
1198   set_path_visibility (fixture, "3", FALSE);
1199   check_filter_model (fixture);
1200   check_level_length (fixture->filter, NULL, 0);
1201
1202   signal_monitor_append_signal (fixture->monitor, ROW_INSERTED, "0");
1203   signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "0");
1204   set_path_visibility (fixture, "3:2:1", TRUE);
1205   set_path_visibility (fixture, "3", TRUE);
1206   check_filter_model (fixture);
1207   check_level_length (fixture->filter, NULL, 1);
1208   check_level_length (fixture->filter, "0", 1);
1209   check_level_length (fixture->filter, "0:0", 2);
1210   check_level_length (fixture->filter, "0:0:0", 0);
1211 }
1212
1213 static void
1214 empty_show_multiple_nodes (FilterTest    *fixture,
1215                            gconstpointer  user_data)
1216 {
1217   GtkTreeIter iter;
1218   GtkTreePath *changed_path;
1219
1220   check_filter_model (fixture);
1221   check_level_length (fixture->filter, NULL, 0);
1222
1223   signal_monitor_append_signal (fixture->monitor, ROW_INSERTED, "0");
1224   signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "0");
1225   signal_monitor_append_signal (fixture->monitor, ROW_INSERTED, "1");
1226   signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "1");
1227   signal_monitor_append_signal (fixture->monitor, ROW_CHANGED, "1");
1228   signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "1");
1229
1230   /* We simulate a change in visible func condition with this.  The
1231    * visibility state of multiple nodes changes at once, we emit row-changed
1232    * for these nodes (and others) after that.
1233    */
1234   filter_test_block_signals (fixture);
1235   set_path_visibility (fixture, "3", TRUE);
1236   set_path_visibility (fixture, "4", TRUE);
1237   filter_test_unblock_signals (fixture);
1238
1239   changed_path = gtk_tree_path_new ();
1240   gtk_tree_path_append_index (changed_path, 2);
1241   gtk_tree_model_get_iter (GTK_TREE_MODEL (fixture->store),
1242                            &iter, changed_path);
1243   gtk_tree_model_row_changed (GTK_TREE_MODEL (fixture->store),
1244                               changed_path, &iter);
1245
1246   gtk_tree_path_next (changed_path);
1247   gtk_tree_model_iter_next (GTK_TREE_MODEL (fixture->store), &iter);
1248   gtk_tree_model_row_changed (GTK_TREE_MODEL (fixture->store),
1249                               changed_path, &iter);
1250
1251   gtk_tree_path_next (changed_path);
1252   gtk_tree_model_iter_next (GTK_TREE_MODEL (fixture->store), &iter);
1253   gtk_tree_model_row_changed (GTK_TREE_MODEL (fixture->store),
1254                               changed_path, &iter);
1255
1256   gtk_tree_path_free (changed_path);
1257
1258   check_filter_model (fixture);
1259   check_level_length (fixture->filter, NULL, 2);
1260   check_level_length (fixture->filter, "0", 0);
1261
1262   set_path_visibility (fixture, "3:2:2", TRUE);
1263   check_filter_model (fixture);
1264   check_level_length (fixture->filter, NULL, 2);
1265   check_level_length (fixture->filter, "0", 0);
1266
1267   signal_monitor_append_signal (fixture->monitor, ROW_INSERTED, "0:0");
1268   signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "0");
1269   signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "0:0");
1270   set_path_visibility (fixture, "3:2", TRUE);
1271   check_filter_model (fixture);
1272   check_level_length (fixture->filter, NULL, 2);
1273   check_level_length (fixture->filter, "0", 1);
1274   check_level_length (fixture->filter, "0:0", 1);
1275   check_level_length (fixture->filter, "0:0:0", 0);
1276
1277   signal_monitor_append_signal (fixture->monitor, ROW_DELETED, "0");
1278   set_path_visibility (fixture, "3", FALSE);
1279   check_filter_model (fixture);
1280   check_level_length (fixture->filter, NULL, 1);
1281
1282   signal_monitor_append_signal (fixture->monitor, ROW_INSERTED, "0");
1283   signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "0");
1284   set_path_visibility (fixture, "3:2:1", TRUE);
1285   set_path_visibility (fixture, "3", TRUE);
1286   check_filter_model (fixture);
1287   check_level_length (fixture->filter, NULL, 2);
1288   check_level_length (fixture->filter, "0", 1);
1289   check_level_length (fixture->filter, "0:0", 2);
1290   check_level_length (fixture->filter, "0:0:0", 0);
1291 }
1292
1293 static void
1294 empty_vroot_show_nodes (FilterTest    *fixture,
1295                         gconstpointer  user_data)
1296 {
1297   GtkTreePath *path = (GtkTreePath *)user_data;
1298
1299   check_filter_model_with_root (fixture, path);
1300   check_level_length (fixture->filter, NULL, 0);
1301
1302   set_path_visibility (fixture, "2", TRUE);
1303   check_filter_model_with_root (fixture, path);
1304   check_level_length (fixture->filter, NULL, 0);
1305
1306   set_path_visibility (fixture, "2:2:2", TRUE);
1307   check_filter_model_with_root (fixture, path);
1308   check_level_length (fixture->filter, NULL, 0);
1309
1310   signal_monitor_append_signal (fixture->monitor, ROW_INSERTED, "0");
1311   signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "0");
1312   set_path_visibility (fixture, "2:2", TRUE);
1313   check_filter_model_with_root (fixture, path);
1314   check_level_length (fixture->filter, NULL, 1);
1315   check_level_length (fixture->filter, "0", 1);
1316   check_level_length (fixture->filter, "0:0", 0);
1317
1318   set_path_visibility (fixture, "3", TRUE);
1319   check_filter_model_with_root (fixture, path);
1320   check_level_length (fixture->filter, NULL, 1);
1321
1322   signal_monitor_append_signal (fixture->monitor, ROW_DELETED, "0");
1323   set_path_visibility (fixture, "2:2", FALSE);
1324   check_filter_model_with_root (fixture, path);
1325   check_level_length (fixture->filter, NULL, 0);
1326
1327   signal_monitor_append_signal (fixture->monitor, ROW_INSERTED, "0");
1328   signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "0");
1329   set_path_visibility (fixture, "2:2:1", TRUE);
1330   set_path_visibility (fixture, "2:2", TRUE);
1331   check_filter_model_with_root (fixture, path);
1332   check_level_length (fixture->filter, NULL, 1);
1333   check_level_length (fixture->filter, "0", 2);
1334   check_level_length (fixture->filter, "0:1", 0);
1335 }
1336
1337 static void
1338 empty_vroot_show_multiple_nodes (FilterTest    *fixture,
1339                                  gconstpointer  user_data)
1340 {
1341   GtkTreeIter iter;
1342   GtkTreePath *changed_path;
1343   GtkTreePath *path = (GtkTreePath *)user_data;
1344
1345   check_filter_model_with_root (fixture, path);
1346   check_level_length (fixture->filter, NULL, 0);
1347
1348   /* We simulate a change in visible func condition with this.  The
1349    * visibility state of multiple nodes changes at once, we emit row-changed
1350    * for these nodes (and others) after that.
1351    */
1352   filter_test_block_signals (fixture);
1353   set_path_visibility (fixture, "2", TRUE);
1354   set_path_visibility (fixture, "3", TRUE);
1355   filter_test_unblock_signals (fixture);
1356
1357   changed_path = gtk_tree_path_new ();
1358   gtk_tree_path_append_index (changed_path, 1);
1359   gtk_tree_model_get_iter (GTK_TREE_MODEL (fixture->store),
1360                            &iter, changed_path);
1361   gtk_tree_model_row_changed (GTK_TREE_MODEL (fixture->store),
1362                               changed_path, &iter);
1363
1364   gtk_tree_path_next (changed_path);
1365   gtk_tree_model_iter_next (GTK_TREE_MODEL (fixture->store), &iter);
1366   gtk_tree_model_row_changed (GTK_TREE_MODEL (fixture->store),
1367                               changed_path, &iter);
1368
1369   gtk_tree_path_next (changed_path);
1370   gtk_tree_model_iter_next (GTK_TREE_MODEL (fixture->store), &iter);
1371   gtk_tree_model_row_changed (GTK_TREE_MODEL (fixture->store),
1372                               changed_path, &iter);
1373
1374   gtk_tree_path_next (changed_path);
1375   gtk_tree_model_iter_next (GTK_TREE_MODEL (fixture->store), &iter);
1376   gtk_tree_model_row_changed (GTK_TREE_MODEL (fixture->store),
1377                               changed_path, &iter);
1378
1379   gtk_tree_path_free (changed_path);
1380
1381   check_filter_model_with_root (fixture, path);
1382   check_level_length (fixture->filter, NULL, 0);
1383
1384   set_path_visibility (fixture, "2:2:2", TRUE);
1385   check_filter_model_with_root (fixture, path);
1386   check_level_length (fixture->filter, NULL, 0);
1387
1388   signal_monitor_append_signal (fixture->monitor, ROW_INSERTED, "0");
1389   signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "0");
1390   signal_monitor_append_signal (fixture->monitor, ROW_INSERTED, "1");
1391   signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "1");
1392
1393   /* Again, we simulate a call to refilter */
1394   filter_test_block_signals (fixture);
1395   set_path_visibility (fixture, "2:2", TRUE);
1396   set_path_visibility (fixture, "2:3", TRUE);
1397   filter_test_unblock_signals (fixture);
1398
1399   changed_path = gtk_tree_path_new ();
1400   gtk_tree_path_append_index (changed_path, 2);
1401   gtk_tree_path_append_index (changed_path, 1);
1402   gtk_tree_model_get_iter (GTK_TREE_MODEL (fixture->store),
1403                            &iter, changed_path);
1404   gtk_tree_model_row_changed (GTK_TREE_MODEL (fixture->store),
1405                               changed_path, &iter);
1406
1407   gtk_tree_path_next (changed_path);
1408   gtk_tree_model_iter_next (GTK_TREE_MODEL (fixture->store), &iter);
1409   gtk_tree_model_row_changed (GTK_TREE_MODEL (fixture->store),
1410                               changed_path, &iter);
1411
1412   gtk_tree_path_next (changed_path);
1413   gtk_tree_model_iter_next (GTK_TREE_MODEL (fixture->store), &iter);
1414   gtk_tree_model_row_changed (GTK_TREE_MODEL (fixture->store),
1415                               changed_path, &iter);
1416
1417   gtk_tree_path_next (changed_path);
1418   gtk_tree_model_iter_next (GTK_TREE_MODEL (fixture->store), &iter);
1419   gtk_tree_model_row_changed (GTK_TREE_MODEL (fixture->store),
1420                               changed_path, &iter);
1421
1422   gtk_tree_path_free (changed_path);
1423
1424   check_filter_model_with_root (fixture, path);
1425   check_level_length (fixture->filter, NULL, 2);
1426   check_level_length (fixture->filter, "0", 1);
1427   check_level_length (fixture->filter, "0:0", 0);
1428
1429   set_path_visibility (fixture, "3", TRUE);
1430   check_filter_model_with_root (fixture, path);
1431   check_level_length (fixture->filter, NULL, 2);
1432
1433   signal_monitor_append_signal (fixture->monitor, ROW_DELETED, "0");
1434   set_path_visibility (fixture, "2:2", FALSE);
1435   check_filter_model_with_root (fixture, path);
1436   check_level_length (fixture->filter, NULL, 1);
1437
1438   signal_monitor_append_signal (fixture->monitor, ROW_INSERTED, "0");
1439   signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "0");
1440   set_path_visibility (fixture, "2:2:1", TRUE);
1441   set_path_visibility (fixture, "2:2", TRUE);
1442   check_filter_model_with_root (fixture, path);
1443   check_level_length (fixture->filter, NULL, 2);
1444   check_level_length (fixture->filter, "0", 2);
1445   check_level_length (fixture->filter, "0:1", 0);
1446 }
1447
1448
1449 static void
1450 unfiltered_hide_single (FilterTest    *fixture,
1451                         gconstpointer  user_data)
1452
1453 {
1454   signal_monitor_append_signal (fixture->monitor, ROW_CHANGED, "2");
1455   signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "2");
1456   set_path_visibility (fixture, "2", FALSE);
1457
1458   signal_monitor_assert_is_empty (fixture->monitor);
1459   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
1460
1461   /* The view only shows the root level, so the filter model only has
1462    * the first two levels cached.
1463    */
1464   filter_test_append_refilter_signals (fixture, 2);
1465   filter_test_enable_filter (fixture);
1466
1467   check_filter_model (fixture);
1468   check_level_length (fixture->filter, NULL, LEVEL_LENGTH - 1);
1469 }
1470
1471 static void
1472 unfiltered_hide_single_child (FilterTest    *fixture,
1473                               gconstpointer  user_data)
1474
1475 {
1476   signal_monitor_append_signal (fixture->monitor, ROW_CHANGED, "2:2");
1477   signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "2:2");
1478   set_path_visibility (fixture, "2:2", FALSE);
1479
1480   signal_monitor_assert_is_empty (fixture->monitor);
1481   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
1482   check_level_length (fixture->filter, "2", LEVEL_LENGTH);
1483
1484   /* The view only shows the root level, so the filter model only has
1485    * the first two levels cached.
1486    */
1487   filter_test_append_refilter_signals (fixture, 2);
1488   filter_test_enable_filter (fixture);
1489
1490   check_filter_model (fixture);
1491   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
1492   check_level_length (fixture->filter, "2", LEVEL_LENGTH - 1);
1493 }
1494
1495 static void
1496 unfiltered_hide_single_multi_level (FilterTest    *fixture,
1497                                     gconstpointer  user_data)
1498
1499 {
1500   /* This row is not shown, so its signal is not propagated */
1501   set_path_visibility (fixture, "2:2:2", FALSE);
1502
1503   signal_monitor_append_signal (fixture->monitor, ROW_CHANGED, "2:2");
1504   signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "2:2");
1505   set_path_visibility (fixture, "2:2", FALSE);
1506
1507   signal_monitor_assert_is_empty (fixture->monitor);
1508   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
1509   check_level_length (fixture->filter, "2", LEVEL_LENGTH);
1510   check_level_length (fixture->filter, "2:2", LEVEL_LENGTH);
1511
1512   /* The view only shows the root level, so the filter model only has
1513    * the first two levels cached.
1514    */
1515   filter_test_append_refilter_signals (fixture, 2);
1516   filter_test_enable_filter (fixture);
1517
1518   check_filter_model (fixture);
1519   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
1520   check_level_length (fixture->filter, "2", LEVEL_LENGTH - 1);
1521
1522   signal_monitor_append_signal (fixture->monitor, ROW_INSERTED, "2:2");
1523   signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "2:2");
1524   set_path_visibility (fixture, "2:2", TRUE);
1525
1526   check_filter_model (fixture);
1527   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
1528   check_level_length (fixture->filter, "2", LEVEL_LENGTH);
1529   check_level_length (fixture->filter, "2:2", LEVEL_LENGTH - 1);
1530 }
1531
1532
1533 static void
1534 unfiltered_vroot_hide_single (FilterTest    *fixture,
1535                               gconstpointer  user_data)
1536
1537 {
1538   GtkTreePath *path = (GtkTreePath *)user_data;
1539
1540   signal_monitor_append_signal (fixture->monitor, ROW_CHANGED, "2");
1541   signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "2");
1542   set_path_visibility (fixture, "2:2", FALSE);
1543
1544   signal_monitor_assert_is_empty (fixture->monitor);
1545   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
1546
1547   /* The view only shows the root level, so the filter model only has
1548    * the first two levels cached.  (We add an additional level to
1549    * take the virtual root into account).
1550    */
1551   filter_test_append_refilter_signals_with_vroot (fixture, 3, path);
1552   filter_test_enable_filter (fixture);
1553
1554   check_filter_model_with_root (fixture, path);
1555   check_level_length (fixture->filter, NULL, LEVEL_LENGTH - 1);
1556 }
1557
1558 static void
1559 unfiltered_vroot_hide_single_child (FilterTest    *fixture,
1560                                     gconstpointer  user_data)
1561
1562 {
1563   GtkTreePath *path = (GtkTreePath *)user_data;
1564
1565   signal_monitor_append_signal (fixture->monitor, ROW_CHANGED, "2:2");
1566   signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "2:2");
1567   set_path_visibility (fixture, "2:2:2", FALSE);
1568
1569   signal_monitor_assert_is_empty (fixture->monitor);
1570   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
1571   check_level_length (fixture->filter, "2", LEVEL_LENGTH);
1572
1573   /* The view only shows the root level, so the filter model only has
1574    * the first two levels cached.  (We add an additional level to take
1575    * the virtual root into account).
1576    */
1577   filter_test_append_refilter_signals_with_vroot (fixture, 3, path);
1578   filter_test_enable_filter (fixture);
1579
1580   check_filter_model_with_root (fixture, path);
1581   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
1582   check_level_length (fixture->filter, "2", LEVEL_LENGTH - 1);
1583 }
1584
1585 static void
1586 unfiltered_vroot_hide_single_multi_level (FilterTest    *fixture,
1587                                           gconstpointer  user_data)
1588
1589 {
1590   GtkTreePath *path = (GtkTreePath *)user_data;
1591
1592   /* This row is not shown, so its signal is not propagated */
1593   set_path_visibility (fixture, "2:2:2:2", FALSE);
1594
1595   signal_monitor_append_signal (fixture->monitor, ROW_CHANGED, "2:2");
1596   signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "2:2");
1597   set_path_visibility (fixture, "2:2:2", FALSE);
1598
1599   signal_monitor_assert_is_empty (fixture->monitor);
1600   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
1601   check_level_length (fixture->filter, "2", LEVEL_LENGTH);
1602   check_level_length (fixture->filter, "2:2", LEVEL_LENGTH);
1603
1604   /* The view only shows the root level, so the filter model only has
1605    * the first two levels cached.
1606    */
1607   filter_test_append_refilter_signals_with_vroot (fixture, 3, path);
1608   filter_test_enable_filter (fixture);
1609
1610   check_filter_model_with_root (fixture, path);
1611   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
1612   check_level_length (fixture->filter, "2", LEVEL_LENGTH - 1);
1613
1614   signal_monitor_append_signal (fixture->monitor, ROW_INSERTED, "2:2");
1615   signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "2:2");
1616   set_path_visibility (fixture, "2:2:2", TRUE);
1617
1618   check_filter_model_with_root (fixture, path);
1619   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
1620   check_level_length (fixture->filter, "2", LEVEL_LENGTH);
1621   check_level_length (fixture->filter, "2:2", LEVEL_LENGTH - 1);
1622 }
1623
1624
1625
1626 static void
1627 unfiltered_show_single (FilterTest    *fixture,
1628                         gconstpointer  user_data)
1629
1630 {
1631   signal_monitor_append_signal (fixture->monitor, ROW_CHANGED, "2");
1632   signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "2");
1633   set_path_visibility (fixture, "2", TRUE);
1634
1635   signal_monitor_assert_is_empty (fixture->monitor);
1636   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
1637
1638   /* The view only shows the root level, so the filter model only has
1639    * the first two levels cached.
1640    */
1641   filter_test_append_refilter_signals (fixture, 2);
1642   filter_test_enable_filter (fixture);
1643
1644   check_filter_model (fixture);
1645   check_level_length (fixture->filter, NULL, 1);
1646 }
1647
1648 static void
1649 unfiltered_show_single_child (FilterTest    *fixture,
1650                               gconstpointer  user_data)
1651
1652 {
1653   signal_monitor_append_signal (fixture->monitor, ROW_CHANGED, "2:2");
1654   signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "2:2");
1655   set_path_visibility (fixture, "2:2", TRUE);
1656
1657   signal_monitor_assert_is_empty (fixture->monitor);
1658   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
1659   check_level_length (fixture->filter, "2", LEVEL_LENGTH);
1660
1661   /* The view only shows the root level, so the filter model only has
1662    * the first two levels cached.
1663    */
1664   filter_test_append_refilter_signals (fixture, 3);
1665   filter_test_enable_filter (fixture);
1666
1667   check_filter_model (fixture);
1668   check_level_length (fixture->filter, NULL, 0);
1669
1670   /* From here we are filtered, "2" in the real model is "0" in the filter
1671    * model.
1672    */
1673   signal_monitor_append_signal (fixture->monitor, ROW_INSERTED, "0");
1674   signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "0");
1675   set_path_visibility (fixture, "2", TRUE);
1676   signal_monitor_assert_is_empty (fixture->monitor);
1677   check_level_length (fixture->filter, NULL, 1);
1678   check_level_length (fixture->filter, "0", 1);
1679 }
1680
1681 static void
1682 unfiltered_show_single_multi_level (FilterTest    *fixture,
1683                                     gconstpointer  user_data)
1684
1685 {
1686   /* The view is not showing this row (collapsed state), so it is not
1687    * referenced.  The signal should not go through.
1688    */
1689   set_path_visibility (fixture, "2:2:2", TRUE);
1690
1691   signal_monitor_append_signal (fixture->monitor, ROW_CHANGED, "2:2");
1692   signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "2:2");
1693   set_path_visibility (fixture, "2:2", TRUE);
1694
1695   signal_monitor_assert_is_empty (fixture->monitor);
1696   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
1697   check_level_length (fixture->filter, "2", LEVEL_LENGTH);
1698   check_level_length (fixture->filter, "2:2", LEVEL_LENGTH);
1699
1700   /* The view only shows the root level, so the filter model only has
1701    * the first two levels cached.
1702    */
1703   filter_test_append_refilter_signals (fixture, 3);
1704   filter_test_enable_filter (fixture);
1705
1706   check_filter_model (fixture);
1707   check_level_length (fixture->filter, NULL, 0);
1708
1709   /* From here we are filtered, "2" in the real model is "0" in the filter
1710    * model.
1711    */
1712   signal_monitor_append_signal (fixture->monitor, ROW_INSERTED, "0");
1713   signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "0");
1714   set_path_visibility (fixture, "2", TRUE);
1715   check_filter_model (fixture);
1716   check_level_length (fixture->filter, NULL, 1);
1717   check_level_length (fixture->filter, "0", 1);
1718   check_level_length (fixture->filter, "0:0", 1);
1719 }
1720
1721
1722 static void
1723 unfiltered_vroot_show_single (FilterTest    *fixture,
1724                               gconstpointer  user_data)
1725
1726 {
1727   GtkTreePath *path = (GtkTreePath *)user_data;
1728
1729   signal_monitor_append_signal (fixture->monitor, ROW_CHANGED, "2");
1730   signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "2");
1731   set_path_visibility (fixture, "2:2", TRUE);
1732
1733   signal_monitor_assert_is_empty (fixture->monitor);
1734   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
1735
1736   /* The view only shows the root level, so the filter model only has
1737    * the first two levels cached.
1738    */
1739   filter_test_append_refilter_signals_with_vroot (fixture, 3, path);
1740   filter_test_enable_filter (fixture);
1741
1742   check_filter_model_with_root (fixture, path);
1743   check_level_length (fixture->filter, NULL, 1);
1744 }
1745
1746 static void
1747 unfiltered_vroot_show_single_child (FilterTest    *fixture,
1748                                     gconstpointer  user_data)
1749
1750 {
1751   GtkTreePath *path = (GtkTreePath *)user_data;
1752
1753   signal_monitor_append_signal (fixture->monitor, ROW_CHANGED, "2:2");
1754   signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "2:2");
1755   set_path_visibility (fixture, "2:2:2", TRUE);
1756
1757   signal_monitor_assert_is_empty (fixture->monitor);
1758   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
1759   check_level_length (fixture->filter, "2", LEVEL_LENGTH);
1760
1761   /* The view only shows the root level, so the filter model only has
1762    * the first two levels cached.
1763    */
1764   filter_test_append_refilter_signals_with_vroot (fixture, 2, path);
1765   filter_test_enable_filter (fixture);
1766
1767   check_filter_model_with_root (fixture, path);
1768   check_level_length (fixture->filter, NULL, 0);
1769
1770   /* From here we are filtered, "2" in the real model is "0" in the filter
1771    * model.
1772    */
1773   signal_monitor_append_signal (fixture->monitor, ROW_INSERTED, "0");
1774   signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "0");
1775   set_path_visibility (fixture, "2:2", TRUE);
1776   signal_monitor_assert_is_empty (fixture->monitor);
1777   check_level_length (fixture->filter, NULL, 1);
1778   check_level_length (fixture->filter, "0", 1);
1779 }
1780
1781 static void
1782 unfiltered_vroot_show_single_multi_level (FilterTest    *fixture,
1783                                           gconstpointer  user_data)
1784
1785 {
1786   GtkTreePath *path = (GtkTreePath *)user_data;
1787
1788   /* The view is not showing this row (collapsed state), so it is not
1789    * referenced.  The signal should not go through.
1790    */
1791   set_path_visibility (fixture, "2:2:2:2", TRUE);
1792
1793   signal_monitor_append_signal (fixture->monitor, ROW_CHANGED, "2:2");
1794   signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "2:2");
1795   set_path_visibility (fixture, "2:2:2", TRUE);
1796
1797   signal_monitor_assert_is_empty (fixture->monitor);
1798   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
1799   check_level_length (fixture->filter, "2", LEVEL_LENGTH);
1800   check_level_length (fixture->filter, "2:2", LEVEL_LENGTH);
1801
1802   /* The view only shows the root level, so the filter model only has
1803    * the first two levels cached.
1804    */
1805   filter_test_append_refilter_signals_with_vroot (fixture, 4, path);
1806   filter_test_enable_filter (fixture);
1807
1808   check_filter_model_with_root (fixture, path);
1809   check_level_length (fixture->filter, NULL, 0);
1810
1811   /* From here we are filtered, "2" in the real model is "0" in the filter
1812    * model.
1813    */
1814   signal_monitor_append_signal (fixture->monitor, ROW_INSERTED, "0");
1815   signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "0");
1816   set_path_visibility (fixture, "2:2", TRUE);
1817   check_filter_model_with_root (fixture, path);
1818   check_level_length (fixture->filter, NULL, 1);
1819   check_level_length (fixture->filter, "0", 1);
1820   check_level_length (fixture->filter, "0:0", 1);
1821 }
1822
1823
1824 static void
1825 specific_remove_node (void)
1826 {
1827   GtkTreeIter iter, iter1, iter2, iter3;
1828   GtkListStore *list;
1829   GtkTreeModel *filter;
1830   GtkWidget *view G_GNUC_UNUSED;
1831
1832   list = gtk_list_store_new (1, G_TYPE_INT);
1833   gtk_list_store_insert_with_values (list, &iter1, 0, 0, 1, -1);
1834   gtk_list_store_insert_with_values (list, &iter, 1, 0, 2, -1);
1835   gtk_list_store_insert_with_values (list, &iter, 2, 0, 3, -1);
1836   gtk_list_store_insert_with_values (list, &iter, 3, 0, 4, -1);
1837   gtk_list_store_insert_with_values (list, &iter, 4, 0, 5, -1);
1838   gtk_list_store_insert_with_values (list, &iter, 5, 0, 6, -1);
1839   gtk_list_store_insert_with_values (list, &iter2, 6, 0, 7, -1);
1840   gtk_list_store_insert_with_values (list, &iter3, 7, 0, 8, -1);
1841
1842   filter = gtk_tree_model_filter_new (GTK_TREE_MODEL (list), NULL);
1843   view = gtk_tree_view_new_with_model (filter);
1844
1845   gtk_list_store_remove (list, &iter1);
1846   gtk_list_store_remove (list, &iter3);
1847   gtk_list_store_remove (list, &iter2);
1848 }
1849
1850 static void
1851 specific_remove_node_vroot (void)
1852 {
1853   GtkTreeIter parent, root;
1854   GtkTreeIter iter, iter1, iter2, iter3;
1855   GtkTreeStore *tree;
1856   GtkTreeModel *filter;
1857   GtkTreePath *path;
1858   GtkWidget *view G_GNUC_UNUSED;
1859
1860   tree = gtk_tree_store_new (1, G_TYPE_INT);
1861   gtk_tree_store_insert_with_values (tree, &parent, NULL, 0, 0, 0, -1);
1862   gtk_tree_store_insert_with_values (tree, &root, &parent, 0, 0, 0, -1);
1863
1864   gtk_tree_store_insert_with_values (tree, &iter1, &root, 0, 0, 1, -1);
1865   gtk_tree_store_insert_with_values (tree, &iter, &root, 1, 0, 2, -1);
1866   gtk_tree_store_insert_with_values (tree, &iter, &root, 2, 0, 3, -1);
1867   gtk_tree_store_insert_with_values (tree, &iter, &root, 3, 0, 4, -1);
1868   gtk_tree_store_insert_with_values (tree, &iter, &root, 4, 0, 5, -1);
1869   gtk_tree_store_insert_with_values (tree, &iter, &root, 5, 0, 6, -1);
1870   gtk_tree_store_insert_with_values (tree, &iter2, &root, 6, 0, 7, -1);
1871   gtk_tree_store_insert_with_values (tree, &iter3, &root, 7, 0, 8, -1);
1872
1873   path = gtk_tree_path_new_from_indices (0, 0, -1);
1874   filter = gtk_tree_model_filter_new (GTK_TREE_MODEL (tree), path);
1875   gtk_tree_path_free (path);
1876
1877   view = gtk_tree_view_new_with_model (filter);
1878
1879   gtk_tree_store_remove (tree, &iter1);
1880   gtk_tree_store_remove (tree, &iter3);
1881   gtk_tree_store_remove (tree, &iter2);
1882 }
1883
1884 static void
1885 specific_remove_vroot_ancestor (void)
1886 {
1887   GtkTreeIter parent, root;
1888   GtkTreeIter iter, iter1, iter2, iter3;
1889   GtkTreeStore *tree;
1890   GtkTreeModel *filter;
1891   GtkTreePath *path;
1892   GtkWidget *view G_GNUC_UNUSED;
1893
1894   tree = gtk_tree_store_new (1, G_TYPE_INT);
1895   gtk_tree_store_insert_with_values (tree, &parent, NULL, 0, 0, 0, -1);
1896   gtk_tree_store_insert_with_values (tree, &root, &parent, 0, 0, 0, -1);
1897
1898   gtk_tree_store_insert_with_values (tree, &iter1, &root, 0, 0, 1, -1);
1899   gtk_tree_store_insert_with_values (tree, &iter, &root, 1, 0, 2, -1);
1900   gtk_tree_store_insert_with_values (tree, &iter, &root, 2, 0, 3, -1);
1901   gtk_tree_store_insert_with_values (tree, &iter, &root, 3, 0, 4, -1);
1902   gtk_tree_store_insert_with_values (tree, &iter, &root, 4, 0, 5, -1);
1903   gtk_tree_store_insert_with_values (tree, &iter, &root, 5, 0, 6, -1);
1904   gtk_tree_store_insert_with_values (tree, &iter2, &root, 6, 0, 7, -1);
1905   gtk_tree_store_insert_with_values (tree, &iter3, &root, 7, 0, 8, -1);
1906
1907   path = gtk_tree_path_new_from_indices (0, 0, -1);
1908   filter = gtk_tree_model_filter_new (GTK_TREE_MODEL (tree), path);
1909   gtk_tree_path_free (path);
1910
1911   view = gtk_tree_view_new_with_model (filter);
1912
1913   gtk_tree_store_remove (tree, &parent);
1914 }
1915
1916
1917 static gboolean
1918 specific_path_dependent_filter_func (GtkTreeModel *model,
1919                                      GtkTreeIter  *iter,
1920                                      gpointer      data)
1921 {
1922   GtkTreePath *path;
1923
1924   path = gtk_tree_model_get_path (model, iter);
1925   if (gtk_tree_path_get_indices (path)[0] < 4)
1926     return FALSE;
1927
1928   return TRUE;
1929 }
1930
1931 static void
1932 specific_path_dependent_filter (void)
1933 {
1934   int i;
1935   GtkTreeIter iter;
1936   GtkListStore *list;
1937   GtkTreeModel *sort;
1938   GtkTreeModel *filter;
1939
1940   list = gtk_list_store_new (1, G_TYPE_INT);
1941   gtk_list_store_insert_with_values (list, &iter, 0, 0, 1, -1);
1942   gtk_list_store_insert_with_values (list, &iter, 1, 0, 2, -1);
1943   gtk_list_store_insert_with_values (list, &iter, 2, 0, 3, -1);
1944   gtk_list_store_insert_with_values (list, &iter, 3, 0, 4, -1);
1945   gtk_list_store_insert_with_values (list, &iter, 4, 0, 5, -1);
1946   gtk_list_store_insert_with_values (list, &iter, 5, 0, 6, -1);
1947   gtk_list_store_insert_with_values (list, &iter, 6, 0, 7, -1);
1948   gtk_list_store_insert_with_values (list, &iter, 7, 0, 8, -1);
1949
1950   sort = gtk_tree_model_sort_new_with_model (GTK_TREE_MODEL (list));
1951   filter = gtk_tree_model_filter_new (GTK_TREE_MODEL (sort), NULL);
1952   gtk_tree_model_filter_set_visible_func (GTK_TREE_MODEL_FILTER (filter),
1953                                           specific_path_dependent_filter_func,
1954                                           NULL, NULL);
1955
1956   gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (sort), 0,
1957                                         GTK_SORT_DESCENDING);
1958
1959   for (i = 0; i < 4; i++)
1960     {
1961       if (gtk_tree_model_iter_nth_child (GTK_TREE_MODEL (list), &iter,
1962                                          NULL, 1))
1963         gtk_list_store_remove (list, &iter);
1964
1965       if (gtk_tree_model_iter_nth_child (GTK_TREE_MODEL (list), &iter,
1966                                          NULL, 2))
1967         gtk_list_store_remove (list, &iter);
1968     }
1969 }
1970
1971
1972 static gboolean
1973 specific_append_after_collapse_visible_func (GtkTreeModel *model,
1974                                              GtkTreeIter  *iter,
1975                                              gpointer      data)
1976 {
1977   gint number;
1978   gboolean hide_negative_numbers;
1979
1980   gtk_tree_model_get (model, iter, 1, &number, -1);
1981   hide_negative_numbers = GPOINTER_TO_INT (g_object_get_data (data, "private-hide-negative-numbers"));
1982
1983   return (number >= 0 || !hide_negative_numbers);
1984 }
1985
1986 static void
1987 specific_append_after_collapse (void)
1988 {
1989   /* This test is based on one of the test cases I found in my
1990    * old test cases directory.  I unfortunately do not have a record
1991    * from who this test case originated.  -Kris.
1992    *
1993    * General idea:
1994    * - Construct tree.
1995    * - Show tree, expand, collapse.
1996    * - Add a row.
1997    */
1998
1999   GtkTreeIter iter;
2000   GtkTreeIter child_iter;
2001   GtkTreeIter child_iter2;
2002   GtkTreePath *append_path;
2003   GtkTreeStore *store;
2004   GtkTreeModel *filter;
2005   GtkTreeModel *sort;
2006
2007   GtkWidget *window;
2008   GtkWidget *tree_view;
2009
2010   store = gtk_tree_store_new (2, G_TYPE_STRING, G_TYPE_INT);
2011
2012   filter = gtk_tree_model_filter_new (GTK_TREE_MODEL (store), NULL);
2013   g_object_set_data (G_OBJECT (filter), "private-hide-negative-numbers",
2014                      GINT_TO_POINTER (FALSE));
2015   gtk_tree_model_filter_set_visible_func (GTK_TREE_MODEL_FILTER (filter),
2016                                           specific_append_after_collapse_visible_func,
2017                                           filter, NULL);
2018
2019   sort = gtk_tree_model_sort_new_with_model (filter);
2020
2021   window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
2022   tree_view = gtk_tree_view_new_with_model (sort);
2023   gtk_container_add (GTK_CONTAINER (window), tree_view);
2024   gtk_widget_realize (tree_view);
2025
2026   while (gtk_events_pending ())
2027     gtk_main_iteration ();
2028
2029   gtk_tree_store_prepend (store, &iter, NULL);
2030   gtk_tree_store_set (store, &iter,
2031                       0, "hallo", 1, 1, -1);
2032
2033   gtk_tree_store_append (store, &child_iter, &iter);
2034   gtk_tree_store_set (store, &child_iter,
2035                       0, "toemaar", 1, 1, -1);
2036
2037   gtk_tree_store_append (store, &child_iter2, &child_iter);
2038   gtk_tree_store_set (store, &child_iter2,
2039                       0, "very deep", 1, 1, -1);
2040
2041   append_path = gtk_tree_model_get_path (GTK_TREE_MODEL (store), &child_iter2);
2042
2043   gtk_tree_store_append (store, &child_iter, &iter);
2044   gtk_tree_store_set (store, &child_iter,
2045                       0, "sja", 1, 1, -1);
2046
2047   gtk_tree_store_append (store, &child_iter, &iter);
2048   gtk_tree_store_set (store, &child_iter,
2049                       0, "some word", 1, -1, -1);
2050
2051   /* Expand and collapse the tree */
2052   gtk_tree_view_expand_all (GTK_TREE_VIEW (tree_view));
2053   while (gtk_events_pending ())
2054     gtk_main_iteration ();
2055
2056   gtk_tree_view_collapse_all (GTK_TREE_VIEW (tree_view));
2057   while (gtk_events_pending ())
2058     gtk_main_iteration ();
2059
2060   /* Add another it */
2061   g_object_set_data (G_OBJECT (filter), "private-hide-negative-numbers",
2062                      GINT_TO_POINTER (TRUE));
2063
2064   if (gtk_tree_model_get_iter (GTK_TREE_MODEL (store), &iter, append_path))
2065     {
2066       gtk_tree_store_append (store, &child_iter, &iter);
2067       gtk_tree_store_set (store, &child_iter,
2068                           0, "new new new !!", 1, 1, -1);
2069     }
2070   gtk_tree_path_free (append_path);
2071
2072   /* Expand */
2073   gtk_tree_view_expand_all (GTK_TREE_VIEW (tree_view));
2074   while (gtk_events_pending ())
2075     gtk_main_iteration ();
2076 }
2077
2078
2079 static gint
2080 specific_sort_filter_remove_node_compare_func (GtkTreeModel  *model,
2081                                                GtkTreeIter   *iter1,
2082                                                GtkTreeIter   *iter2,
2083                                                gpointer       data)
2084 {
2085   return -1;
2086 }
2087
2088 static gboolean
2089 specific_sort_filter_remove_node_visible_func (GtkTreeModel  *model,
2090                                                GtkTreeIter   *iter,
2091                                                gpointer       data)
2092 {
2093   char *item = NULL;
2094
2095   /* Do reference the model */
2096   gtk_tree_model_get (model, iter, 0, &item, -1);
2097   g_free (item);
2098
2099   return FALSE;
2100 }
2101
2102 static void
2103 specific_sort_filter_remove_node (void)
2104 {
2105   /* This test is based on one of the test cases I found in my
2106    * old test cases directory.  I unfortunately do not have a record
2107    * from who this test case originated.  -Kris.
2108    *
2109    * General idea:
2110    *  - Create tree store, sort, filter models.  The sort model has
2111    *    a default sort func that is enabled, filter model a visible func
2112    *    that defaults to returning FALSE.
2113    *  - Remove a node from the tree store.
2114    */
2115
2116   GtkTreeIter iter;
2117   GtkTreeStore *store;
2118   GtkTreeModel *filter;
2119   GtkTreeModel *sort;
2120
2121   GtkWidget *window;
2122   GtkWidget *tree_view;
2123
2124   store = gtk_tree_store_new (1, G_TYPE_STRING);
2125   gtk_tree_store_append (store, &iter, NULL);
2126   gtk_tree_store_set (store, &iter, 0, "Hello1", -1);
2127
2128   gtk_tree_store_append (store, &iter, NULL);
2129   gtk_tree_store_set (store, &iter, 0, "Hello2", -1);
2130
2131   sort = gtk_tree_model_sort_new_with_model (GTK_TREE_MODEL (store));
2132   gtk_tree_sortable_set_default_sort_func (GTK_TREE_SORTABLE (sort),
2133                                            specific_sort_filter_remove_node_compare_func, NULL, NULL);
2134
2135   filter = gtk_tree_model_filter_new (sort, NULL);
2136   gtk_tree_model_filter_set_visible_func (GTK_TREE_MODEL_FILTER (filter),
2137                                           specific_sort_filter_remove_node_visible_func,
2138                                           filter, NULL);
2139
2140
2141   window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
2142   tree_view = gtk_tree_view_new_with_model (filter);
2143   gtk_container_add (GTK_CONTAINER (window), tree_view);
2144   gtk_widget_realize (tree_view);
2145
2146   while (gtk_events_pending ())
2147     gtk_main_iteration ();
2148
2149   /* Remove a node */
2150   gtk_tree_model_get_iter_first (GTK_TREE_MODEL (store), &iter);
2151   gtk_tree_model_iter_next (GTK_TREE_MODEL (store), &iter);
2152   gtk_tree_store_remove (store, &iter);
2153
2154   while (gtk_events_pending ())
2155     gtk_main_iteration ();
2156 }
2157
2158
2159 static void
2160 specific_sort_filter_remove_root (void)
2161 {
2162   /* This test is based on one of the test cases I found in my
2163    * old test cases directory.  I unfortunately do not have a record
2164    * from who this test case originated.  -Kris.
2165    */
2166
2167   GtkTreeModel *model, *sort, *filter;
2168   GtkTreeIter root, mid, leaf;
2169   GtkTreePath *path;
2170
2171   model = GTK_TREE_MODEL (gtk_tree_store_new (1, G_TYPE_INT));
2172   gtk_tree_store_append (GTK_TREE_STORE (model), &root, NULL);
2173   gtk_tree_store_append (GTK_TREE_STORE (model), &mid, &root);
2174   gtk_tree_store_append (GTK_TREE_STORE (model), &leaf, &mid);
2175
2176   path = gtk_tree_model_get_path (model, &mid);
2177
2178   sort = gtk_tree_model_sort_new_with_model (model);
2179   filter = gtk_tree_model_filter_new (sort, path);
2180
2181   gtk_tree_store_remove (GTK_TREE_STORE (model), &root);
2182
2183   g_object_unref (filter);
2184   g_object_unref (sort);
2185   g_object_unref (model);
2186 }
2187
2188
2189 static void
2190 specific_root_mixed_visibility (void)
2191 {
2192   int i;
2193   GtkTreeModel *filter;
2194   /* A bit nasty, apologies */
2195   FilterTest fixture;
2196
2197   fixture.store = gtk_tree_store_new (2, G_TYPE_STRING, G_TYPE_BOOLEAN);
2198
2199   for (i = 0; i < LEVEL_LENGTH; i++)
2200     {
2201       GtkTreeIter iter;
2202
2203       gtk_tree_store_insert (fixture.store, &iter, NULL, i);
2204       if (i % 2 == 0)
2205         create_tree_store_set_values (fixture.store, &iter, TRUE);
2206       else
2207         create_tree_store_set_values (fixture.store, &iter, FALSE);
2208     }
2209
2210   filter = gtk_tree_model_filter_new (GTK_TREE_MODEL (fixture.store), NULL);
2211   fixture.filter = GTK_TREE_MODEL_FILTER (filter);
2212   fixture.monitor = NULL;
2213
2214   gtk_tree_model_filter_set_visible_column (fixture.filter, 1);
2215
2216   /* In order to trigger the potential bug, we should not access
2217    * the filter model here (so don't call the check functions).
2218    */
2219
2220   /* Change visibility of an odd row to TRUE */
2221   set_path_visibility (&fixture, "3", TRUE);
2222   check_filter_model (&fixture);
2223   check_level_length (fixture.filter, NULL, 4);
2224 }
2225
2226
2227
2228 static gboolean
2229 specific_has_child_filter_filter_func (GtkTreeModel *model,
2230                                        GtkTreeIter  *iter,
2231                                        gpointer      data)
2232 {
2233   return gtk_tree_model_iter_has_child (model, iter);
2234 }
2235
2236 static void
2237 specific_has_child_filter (void)
2238 {
2239   GtkTreeModel *filter;
2240   GtkTreeIter iter, root;
2241   /* A bit nasty, apologies */
2242   FilterTest fixture;
2243
2244   fixture.store = gtk_tree_store_new (2, G_TYPE_STRING, G_TYPE_BOOLEAN);
2245   filter = gtk_tree_model_filter_new (GTK_TREE_MODEL (fixture.store), NULL);
2246   fixture.filter = GTK_TREE_MODEL_FILTER (filter);
2247   fixture.monitor = NULL;
2248
2249   /* We will filter on parent state using a filter function.  We will
2250    * manually keep the boolean column in sync, so that we can use
2251    * check_filter_model() to check the consistency of the model.
2252    */
2253   /* FIXME: We need a check_filter_model() that is not tied to LEVEL_LENGTH
2254    * to be able to check the structure here.  We keep the calls to
2255    * check_filter_model() commented out until then.
2256    */
2257   gtk_tree_model_filter_set_visible_func (fixture.filter,
2258                                           specific_has_child_filter_filter_func,
2259                                           NULL, NULL);
2260
2261   gtk_tree_store_append (fixture.store, &root, NULL);
2262   create_tree_store_set_values (fixture.store, &root, FALSE);
2263
2264   /* check_filter_model (&fixture); */
2265   check_level_length (fixture.filter, NULL, 0);
2266
2267   gtk_tree_store_append (fixture.store, &iter, &root);
2268   create_tree_store_set_values (fixture.store, &iter, TRUE);
2269
2270   /* Parent must now be visible.  Do the level length check first,
2271    * to avoid modifying the child model triggering a row-changed to
2272    * the filter model.
2273    */
2274   check_level_length (fixture.filter, NULL, 1);
2275   check_level_length (fixture.filter, "0", 0);
2276
2277   set_path_visibility (&fixture, "0", TRUE);
2278   /* check_filter_model (&fixture); */
2279
2280   gtk_tree_store_append (fixture.store, &root, NULL);
2281   check_level_length (fixture.filter, NULL, 1);
2282
2283   gtk_tree_store_append (fixture.store, &iter, &root);
2284   check_level_length (fixture.filter, NULL, 2);
2285   check_level_length (fixture.filter, "1", 0);
2286
2287   create_tree_store_set_values (fixture.store, &root, TRUE);
2288   create_tree_store_set_values (fixture.store, &iter, TRUE);
2289
2290   /* check_filter_model (&fixture); */
2291
2292   gtk_tree_store_append (fixture.store, &iter, &root);
2293   create_tree_store_set_values (fixture.store, &iter, TRUE);
2294   check_level_length (fixture.filter, NULL, 2);
2295   check_level_length (fixture.filter, "0", 0);
2296   check_level_length (fixture.filter, "1", 0);
2297
2298   /* Now remove one of the remaining child rows */
2299   gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL (fixture.store),
2300                                        &iter, "0:0");
2301   gtk_tree_store_remove (fixture.store, &iter);
2302
2303   check_level_length (fixture.filter, NULL, 1);
2304   check_level_length (fixture.filter, "0", 0);
2305
2306   set_path_visibility (&fixture, "0", FALSE);
2307   /* check_filter_model (&fixture); */
2308 }
2309
2310
2311 static gboolean
2312 specific_root_has_child_filter_filter_func (GtkTreeModel *model,
2313                                             GtkTreeIter  *iter,
2314                                             gpointer      data)
2315 {
2316   int depth;
2317   GtkTreePath *path;
2318
2319   path = gtk_tree_model_get_path (model, iter);
2320   depth = gtk_tree_path_get_depth (path);
2321   gtk_tree_path_free (path);
2322
2323   if (depth > 1)
2324     return TRUE;
2325   /* else */
2326   return gtk_tree_model_iter_has_child (model, iter);
2327 }
2328
2329 static void
2330 specific_root_has_child_filter (void)
2331 {
2332   GtkTreeModel *filter;
2333   GtkTreeIter iter, root;
2334   /* A bit nasty, apologies */
2335   FilterTest fixture;
2336
2337   /* This is a variation on the above test case wherein the has-child
2338    * check for visibility only applies to root level nodes.
2339    */
2340
2341   fixture.store = gtk_tree_store_new (2, G_TYPE_STRING, G_TYPE_BOOLEAN);
2342   filter = gtk_tree_model_filter_new (GTK_TREE_MODEL (fixture.store), NULL);
2343   fixture.filter = GTK_TREE_MODEL_FILTER (filter);
2344   fixture.monitor = NULL;
2345
2346   /* We will filter on parent state using a filter function.  We will
2347    * manually keep the boolean column in sync, so that we can use
2348    * check_filter_model() to check the consistency of the model.
2349    */
2350   /* FIXME: We need a check_filter_model() that is not tied to LEVEL_LENGTH
2351    * to be able to check the structure here.  We keep the calls to
2352    * check_filter_model() commented out until then.
2353    */
2354   gtk_tree_model_filter_set_visible_func (fixture.filter,
2355                                           specific_root_has_child_filter_filter_func,
2356                                           NULL, NULL);
2357
2358   gtk_tree_store_append (fixture.store, &root, NULL);
2359   create_tree_store_set_values (fixture.store, &root, FALSE);
2360
2361   /* check_filter_model (&fixture); */
2362   check_level_length (fixture.filter, NULL, 0);
2363
2364   gtk_tree_store_append (fixture.store, &iter, &root);
2365   create_tree_store_set_values (fixture.store, &iter, TRUE);
2366
2367   /* Parent must now be visible.  Do the level length check first,
2368    * to avoid modifying the child model triggering a row-changed to
2369    * the filter model.
2370    */
2371   check_level_length (fixture.filter, NULL, 1);
2372   check_level_length (fixture.filter, "0", 1);
2373
2374   set_path_visibility (&fixture, "0", TRUE);
2375   /* check_filter_model (&fixture); */
2376
2377   gtk_tree_store_append (fixture.store, &root, NULL);
2378   check_level_length (fixture.filter, NULL, 1);
2379
2380   gtk_tree_store_append (fixture.store, &iter, &root);
2381   check_level_length (fixture.filter, NULL, 2);
2382   check_level_length (fixture.filter, "1", 1);
2383
2384   create_tree_store_set_values (fixture.store, &root, TRUE);
2385   create_tree_store_set_values (fixture.store, &iter, TRUE);
2386
2387   /* check_filter_model (&fixture); */
2388
2389   gtk_tree_store_append (fixture.store, &iter, &root);
2390   create_tree_store_set_values (fixture.store, &iter, TRUE);
2391   check_level_length (fixture.filter, NULL, 2);
2392   check_level_length (fixture.filter, "0", 1);
2393   check_level_length (fixture.filter, "1", 2);
2394
2395   /* Now remove one of the remaining child rows */
2396   gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL (fixture.store),
2397                                        &iter, "0:0");
2398   gtk_tree_store_remove (fixture.store, &iter);
2399
2400   check_level_length (fixture.filter, NULL, 1);
2401   check_level_length (fixture.filter, "0", 2);
2402
2403   set_path_visibility (&fixture, "0", FALSE);
2404   /* check_filter_model (&fixture); */
2405 }
2406
2407
2408 static void
2409 specific_filter_add_child (void)
2410 {
2411   /* This test is based on one of the test cases I found in my
2412    * old test cases directory.  I unfortunately do not have a record
2413    * from who this test case originated.  -Kris.
2414    */
2415
2416   GtkTreeIter iter;
2417   GtkTreeIter iter_first;
2418   GtkTreeIter child;
2419   GtkTreeStore *store;
2420   GtkTreeModel *filter G_GNUC_UNUSED;
2421
2422   store = gtk_tree_store_new (1, G_TYPE_STRING);
2423
2424   gtk_tree_store_append (store, &iter_first, NULL);
2425   gtk_tree_store_set (store, &iter_first, 0, "Hello", -1);
2426
2427   gtk_tree_store_append (store, &iter, NULL);
2428   gtk_tree_store_set (store, &iter, 0, "Hello", -1);
2429
2430   gtk_tree_store_append (store, &iter, NULL);
2431   gtk_tree_store_set (store, &iter, 0, "Hello", -1);
2432
2433   gtk_tree_store_append (store, &iter, NULL);
2434   gtk_tree_store_set (store, &iter, 0, "Hello", -1);
2435
2436   filter = gtk_tree_model_filter_new (GTK_TREE_MODEL (store), NULL);
2437
2438   gtk_tree_store_set (store, &iter, 0, "Hello", -1);
2439   gtk_tree_store_append (store, &child, &iter_first);
2440   gtk_tree_store_set (store, &child, 0, "Hello", -1);
2441 }
2442
2443 static void
2444 specific_list_store_clear (void)
2445 {
2446   GtkTreeIter iter;
2447   GtkListStore *list;
2448   GtkTreeModel *filter;
2449   GtkWidget *view G_GNUC_UNUSED;
2450
2451   list = gtk_list_store_new (1, G_TYPE_INT);
2452   gtk_list_store_insert_with_values (list, &iter, 0, 0, 1, -1);
2453   gtk_list_store_insert_with_values (list, &iter, 1, 0, 2, -1);
2454   gtk_list_store_insert_with_values (list, &iter, 2, 0, 3, -1);
2455   gtk_list_store_insert_with_values (list, &iter, 3, 0, 4, -1);
2456   gtk_list_store_insert_with_values (list, &iter, 4, 0, 5, -1);
2457   gtk_list_store_insert_with_values (list, &iter, 5, 0, 6, -1);
2458   gtk_list_store_insert_with_values (list, &iter, 6, 0, 7, -1);
2459   gtk_list_store_insert_with_values (list, &iter, 7, 0, 8, -1);
2460
2461   filter = gtk_tree_model_filter_new (GTK_TREE_MODEL (list), NULL);
2462   view = gtk_tree_view_new_with_model (filter);
2463
2464   gtk_list_store_clear (list);
2465 }
2466
2467 static void
2468 specific_sort_ref_leaf_and_remove_ancestor (void)
2469 {
2470   GtkTreeIter iter, child, child2, child3;
2471   GtkTreeStore *tree;
2472   GtkTreeModel *sort;
2473   GtkTreePath *path;
2474   GtkTreeRowReference *rowref;
2475   GtkWidget *view G_GNUC_UNUSED;
2476
2477   tree = gtk_tree_store_new (1, G_TYPE_INT);
2478   gtk_tree_store_insert_with_values (tree, &iter, NULL, 0, 0, 1, -1);
2479   gtk_tree_store_insert_with_values (tree, &iter, NULL, 1, 0, 2, -1);
2480   gtk_tree_store_insert_with_values (tree, &iter, NULL, 2, 0, 3, -1);
2481   gtk_tree_store_insert_with_values (tree, &iter, NULL, 3, 0, 4, -1);
2482
2483   gtk_tree_store_insert_with_values (tree, &child, &iter, 0, 0, 50, -1);
2484   gtk_tree_store_insert_with_values (tree, &child2, &child, 0, 0, 6, -1);
2485   gtk_tree_store_insert_with_values (tree, &child3, &child2, 0, 0, 7, -1);
2486
2487   sort = gtk_tree_model_sort_new_with_model (GTK_TREE_MODEL (tree));
2488   view = gtk_tree_view_new_with_model (sort);
2489   gtk_tree_view_expand_all (GTK_TREE_VIEW (view));
2490
2491   path = gtk_tree_path_new_from_indices (3, 0, 0, 0, -1);
2492   rowref = gtk_tree_row_reference_new (sort, path);
2493   gtk_tree_path_free (path);
2494
2495   path = gtk_tree_path_new_from_indices (3, 0, 0, 0, -1);
2496   rowref = gtk_tree_row_reference_new (sort, path);
2497   gtk_tree_path_free (path);
2498
2499   path = gtk_tree_path_new_from_indices (3, 0, -1);
2500   rowref = gtk_tree_row_reference_new (sort, path);
2501   gtk_tree_path_free (path);
2502
2503   path = gtk_tree_path_new_from_indices (3, -1);
2504   rowref = gtk_tree_row_reference_new (sort, path);
2505   gtk_tree_path_free (path);
2506
2507   /* Deleting a parent */
2508   path = gtk_tree_path_new_from_indices (3, 0, -1);
2509   gtk_tree_model_get_iter (GTK_TREE_MODEL (tree), &iter, path);
2510   gtk_tree_store_remove (tree, &iter);
2511   gtk_tree_path_free (path);
2512
2513   gtk_tree_row_reference_free (rowref);
2514 }
2515
2516 static void
2517 specific_ref_leaf_and_remove_ancestor (void)
2518 {
2519   GtkTreeIter iter, child, child2, child3;
2520   GtkTreeStore *tree;
2521   GtkTreeModel *filter;
2522   GtkTreePath *path;
2523   GtkTreeRowReference *rowref;
2524   GtkWidget *view G_GNUC_UNUSED;
2525
2526   tree = gtk_tree_store_new (1, G_TYPE_INT);
2527   gtk_tree_store_insert_with_values (tree, &iter, NULL, 0, 0, 1, -1);
2528   gtk_tree_store_insert_with_values (tree, &iter, NULL, 1, 0, 2, -1);
2529   gtk_tree_store_insert_with_values (tree, &iter, NULL, 2, 0, 3, -1);
2530   gtk_tree_store_insert_with_values (tree, &iter, NULL, 3, 0, 4, -1);
2531
2532   gtk_tree_store_insert_with_values (tree, &child, &iter, 0, 0, 50, -1);
2533   gtk_tree_store_insert_with_values (tree, &child2, &child, 0, 0, 6, -1);
2534   gtk_tree_store_insert_with_values (tree, &child3, &child2, 0, 0, 7, -1);
2535
2536   filter = gtk_tree_model_filter_new (GTK_TREE_MODEL (tree), NULL);
2537   view = gtk_tree_view_new_with_model (filter);
2538   gtk_tree_view_expand_all (GTK_TREE_VIEW (view));
2539
2540   path = gtk_tree_path_new_from_indices (3, 0, 0, 0, -1);
2541   rowref = gtk_tree_row_reference_new (filter, path);
2542   gtk_tree_path_free (path);
2543
2544   path = gtk_tree_path_new_from_indices (3, 0, 0, 0, -1);
2545   rowref = gtk_tree_row_reference_new (filter, path);
2546   gtk_tree_path_free (path);
2547
2548   path = gtk_tree_path_new_from_indices (3, 0, -1);
2549   rowref = gtk_tree_row_reference_new (filter, path);
2550   gtk_tree_path_free (path);
2551
2552   path = gtk_tree_path_new_from_indices (3, -1);
2553   rowref = gtk_tree_row_reference_new (filter, path);
2554   gtk_tree_path_free (path);
2555
2556   /* Deleting a parent */
2557   path = gtk_tree_path_new_from_indices (3, 0, -1);
2558   gtk_tree_model_get_iter (GTK_TREE_MODEL (tree), &iter, path);
2559   gtk_tree_store_remove (tree, &iter);
2560   gtk_tree_path_free (path);
2561
2562   gtk_tree_row_reference_free (rowref);
2563 }
2564
2565 static void
2566 specific_virtual_ref_leaf_and_remove_ancestor (void)
2567 {
2568   GtkTreeIter iter, child, child2, child3;
2569   GtkTreeStore *tree;
2570   GtkTreeModel *filter;
2571   GtkTreePath *path;
2572   GtkTreeRowReference *rowref;
2573   GtkWidget *view G_GNUC_UNUSED;
2574
2575   tree = gtk_tree_store_new (1, G_TYPE_INT);
2576   gtk_tree_store_insert_with_values (tree, &iter, NULL, 0, 0, 1, -1);
2577   gtk_tree_store_insert_with_values (tree, &iter, NULL, 1, 0, 2, -1);
2578   gtk_tree_store_insert_with_values (tree, &iter, NULL, 2, 0, 3, -1);
2579   gtk_tree_store_insert_with_values (tree, &iter, NULL, 3, 0, 4, -1);
2580
2581   gtk_tree_store_insert_with_values (tree, &child, &iter, 0, 0, 50, -1);
2582   gtk_tree_store_insert_with_values (tree, &child2, &child, 0, 0, 6, -1);
2583   gtk_tree_store_insert_with_values (tree, &child3, &child2, 0, 0, 7, -1);
2584
2585   /* Set a virtual root of 3:0 */
2586   path = gtk_tree_path_new_from_indices (3, 0, -1);
2587   filter = gtk_tree_model_filter_new (GTK_TREE_MODEL (tree), path);
2588   gtk_tree_path_free (path);
2589
2590   view = gtk_tree_view_new_with_model (filter);
2591   gtk_tree_view_expand_all (GTK_TREE_VIEW (view));
2592
2593   path = gtk_tree_path_new_from_indices (0, 0, -1);
2594   rowref = gtk_tree_row_reference_new (filter, path);
2595   gtk_tree_path_free (path);
2596
2597   path = gtk_tree_path_new_from_indices (0, 0, -1);
2598   rowref = gtk_tree_row_reference_new (filter, path);
2599   gtk_tree_path_free (path);
2600
2601   path = gtk_tree_path_new_from_indices (0, -1);
2602   rowref = gtk_tree_row_reference_new (filter, path);
2603   gtk_tree_path_free (path);
2604
2605   /* Deleting the virtual root */
2606   path = gtk_tree_path_new_from_indices (3, 0, -1);
2607   gtk_tree_model_get_iter (GTK_TREE_MODEL (tree), &iter, path);
2608   gtk_tree_store_remove (tree, &iter);
2609   gtk_tree_path_free (path);
2610
2611   gtk_tree_row_reference_free (rowref);
2612 }
2613
2614
2615 static int
2616 specific_bug_301558_sort_func (GtkTreeModel *model,
2617                                GtkTreeIter  *a,
2618                                GtkTreeIter  *b,
2619                                gpointer      data)
2620 {
2621   int i, j;
2622
2623   gtk_tree_model_get (model, a, 0, &i, -1);
2624   gtk_tree_model_get (model, b, 0, &j, -1);
2625
2626   return j - i;
2627 }
2628
2629 static void
2630 specific_bug_301558 (void)
2631 {
2632   /* Test case for GNOME Bugzilla bug 301558 provided by
2633    * Markku Vire.
2634    */
2635   GtkTreeStore *tree;
2636   GtkTreeModel *filter;
2637   GtkTreeModel *sort;
2638   GtkTreeIter root, iter, iter2;
2639   GtkWidget *view G_GNUC_UNUSED;
2640   int i;
2641   gboolean add;
2642
2643   g_test_bug ("301558");
2644
2645   tree = gtk_tree_store_new (2, G_TYPE_INT, G_TYPE_BOOLEAN);
2646   gtk_tree_store_append (tree, &iter, NULL);
2647   gtk_tree_store_set (tree, &iter, 0, 123, 1, TRUE, -1);
2648   gtk_tree_store_append (tree, &iter2, &iter);
2649   gtk_tree_store_set (tree, &iter2, 0, 73, 1, TRUE, -1);
2650
2651   sort = gtk_tree_model_sort_new_with_model (GTK_TREE_MODEL (tree));
2652   gtk_tree_sortable_set_default_sort_func (GTK_TREE_SORTABLE (sort),
2653                                            specific_bug_301558_sort_func,
2654                                            NULL, NULL);
2655
2656   filter = gtk_tree_model_filter_new (sort, NULL);
2657   gtk_tree_model_filter_set_visible_column (GTK_TREE_MODEL_FILTER (filter), 1);
2658
2659   view = gtk_tree_view_new_with_model (filter);
2660
2661   while (gtk_events_pending ())
2662     gtk_main_iteration ();
2663
2664   add = TRUE;
2665
2666   for (i = 0; i < 10; i++)
2667     {
2668       if (!gtk_tree_model_get_iter_first (GTK_TREE_MODEL (tree), &root))
2669         g_assert_not_reached ();
2670
2671       if (add)
2672         {
2673           gtk_tree_store_append (tree, &iter, &root);
2674           gtk_tree_store_set (tree, &iter, 0, 456, 1, TRUE, -1);
2675         }
2676       else
2677         {
2678           int n;
2679           n = gtk_tree_model_iter_n_children (GTK_TREE_MODEL (tree), &root);
2680           gtk_tree_model_iter_nth_child (GTK_TREE_MODEL (tree), &iter,
2681                                          &root, n - 1);
2682           gtk_tree_store_remove (tree, &iter);
2683         }
2684
2685       add = !add;
2686     }
2687 }
2688
2689
2690 static gboolean
2691 specific_bug_311955_filter_func (GtkTreeModel *model,
2692                                  GtkTreeIter  *iter,
2693                                  gpointer      data)
2694 {
2695   int value;
2696
2697   gtk_tree_model_get (model, iter, 0, &value, -1);
2698
2699   return (value != 0);
2700 }
2701
2702 static void
2703 specific_bug_311955 (void)
2704 {
2705   /* This is a test case for GNOME Bugzilla bug 311955.  It was written
2706    * by Markku Vire.
2707    */
2708   GtkTreeIter iter, child, root;
2709   GtkTreeStore *store;
2710   GtkTreeModel *sort;
2711   GtkTreeModel *filter;
2712
2713   GtkWidget *window G_GNUC_UNUSED;
2714   GtkWidget *tree_view;
2715   int i;
2716   int n;
2717
2718   g_test_bug ("311955");
2719
2720   store = gtk_tree_store_new (1, G_TYPE_INT);
2721
2722   gtk_tree_store_append (store, &root, NULL);
2723   gtk_tree_store_set (store, &root, 0, 33, -1);
2724
2725   gtk_tree_store_append (store, &iter, &root);
2726   gtk_tree_store_set (store, &iter, 0, 50, -1);
2727
2728   gtk_tree_store_append (store, &iter, NULL);
2729   gtk_tree_store_set (store, &iter, 0, 22, -1);
2730
2731   sort = gtk_tree_model_sort_new_with_model (GTK_TREE_MODEL (store));
2732   filter = gtk_tree_model_filter_new (sort, NULL);
2733
2734   gtk_tree_model_filter_set_visible_func (GTK_TREE_MODEL_FILTER (filter),
2735                                           specific_bug_311955_filter_func,
2736                                           NULL, NULL);
2737
2738   window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
2739   tree_view = gtk_tree_view_new_with_model (filter);
2740   g_object_unref (store);
2741
2742   gtk_tree_view_expand_all (GTK_TREE_VIEW (tree_view));
2743
2744   while (gtk_events_pending ())
2745     gtk_main_iteration ();
2746
2747   /* Fill model */
2748   for (i = 0; i < 4; i++)
2749     {
2750       gtk_tree_model_get_iter_first (GTK_TREE_MODEL (store), &root);
2751
2752       gtk_tree_store_append (store, &iter, &root);
2753
2754       if (i < 3)
2755         gtk_tree_store_set (store, &iter, 0, i, -1);
2756
2757       if (i % 2 == 0)
2758         {
2759           gtk_tree_store_append (store, &child, &iter);
2760           gtk_tree_store_set (store, &child, 0, 10, -1);
2761         }
2762     }
2763
2764   while (gtk_events_pending ())
2765     gtk_main_iteration ();
2766
2767   /* Remove bottommost child from the tree. */
2768   gtk_tree_model_get_iter_first (GTK_TREE_MODEL (store), &root);
2769   n = gtk_tree_model_iter_n_children (GTK_TREE_MODEL (store), &root);
2770
2771   if (gtk_tree_model_iter_nth_child (GTK_TREE_MODEL (store), &iter, &root, n - 2))
2772     {
2773       if (gtk_tree_model_iter_children (GTK_TREE_MODEL (store), &child, &iter))
2774         gtk_tree_store_remove (store, &child);
2775     }
2776   else
2777     g_assert_not_reached ();
2778 }
2779
2780 static void
2781 specific_bug_346800 (void)
2782 {
2783   /* This is a test case for GNOME Bugzilla bug 346800.  It was written
2784    * by Jonathan Matthew.
2785    */
2786
2787   GtkTreeIter node_iters[50];
2788   GtkTreeIter child_iters[50];
2789   GtkTreeModel *model;
2790   GtkTreeModelFilter *filter;
2791   GtkTreeStore *store;
2792   GType *columns;
2793   int i;
2794   int items = 50;
2795   columns = g_new (GType, 2);
2796   columns[0] = G_TYPE_STRING;
2797   columns[1] = G_TYPE_BOOLEAN;
2798   store = gtk_tree_store_newv (2, columns);
2799   model = GTK_TREE_MODEL (store);
2800
2801   g_test_bug ("346800");
2802
2803   filter = GTK_TREE_MODEL_FILTER (gtk_tree_model_filter_new (model, NULL));
2804   gtk_tree_model_filter_set_visible_column (filter, 1);
2805
2806   for (i=0; i<items; i++)
2807     {
2808       /* allocate random amounts of junk, otherwise the filter model's arrays can expand without moving */
2809
2810       g_malloc (138);
2811       gtk_tree_store_append (store, &node_iters[i], NULL);
2812       gtk_tree_store_set (store, &node_iters[i],
2813                           0, "something",
2814                           1, ((i%6) == 0) ? FALSE : TRUE,
2815                           -1);
2816
2817       g_malloc (47);
2818       gtk_tree_store_append (store, &child_iters[i], &node_iters[i]);
2819       gtk_tree_store_set (store, &child_iters[i],
2820                           0, "something else",
2821                           1, FALSE,
2822                           -1);
2823       gtk_tree_model_filter_refilter (filter);
2824
2825       if (i > 6)
2826         {
2827           gtk_tree_store_set (GTK_TREE_STORE (model), &child_iters[i-1], 1,
2828                               (i & 1) ? TRUE : FALSE, -1);
2829           gtk_tree_model_filter_refilter (filter);
2830
2831           gtk_tree_store_set (GTK_TREE_STORE (model), &child_iters[i-2], 1,
2832                               (i & 1) ? FALSE: TRUE, -1);
2833           gtk_tree_model_filter_refilter (filter);
2834         }
2835     }
2836 }
2837
2838 static gboolean
2839 specific_bug_464173_visible_func (GtkTreeModel *model,
2840                                   GtkTreeIter  *iter,
2841                                   gpointer      data)
2842 {
2843   gboolean *visible = (gboolean *)data;
2844
2845   return *visible;
2846 }
2847
2848 static void
2849 specific_bug_464173 (void)
2850 {
2851   /* Test case for GNOME Bugzilla bug 464173, test case written
2852    * by Andreas Koehler.
2853    */
2854   GtkTreeStore *model;
2855   GtkTreeModelFilter *f_model;
2856   GtkTreeIter iter1, iter2;
2857   GtkWidget *view G_GNUC_UNUSED;
2858   gboolean visible = TRUE;
2859
2860   g_test_bug ("464173");
2861
2862   model = gtk_tree_store_new (1, G_TYPE_STRING);
2863   gtk_tree_store_append (model, &iter1, NULL);
2864   gtk_tree_store_set (model, &iter1, 0, "Foo", -1);
2865   gtk_tree_store_append (model, &iter2, &iter1);
2866   gtk_tree_store_set (model, &iter2, 0, "Bar", -1);
2867
2868   f_model = GTK_TREE_MODEL_FILTER (gtk_tree_model_filter_new (GTK_TREE_MODEL(model), NULL));
2869   gtk_tree_model_filter_set_visible_func (f_model,
2870                                           specific_bug_464173_visible_func,
2871                                           &visible, NULL);
2872
2873   view = gtk_tree_view_new_with_model (GTK_TREE_MODEL (f_model));
2874
2875   visible = FALSE;
2876   gtk_tree_model_filter_refilter (f_model);
2877 }
2878
2879
2880 static gboolean
2881 specific_bug_540201_filter_func (GtkTreeModel *model,
2882                                  GtkTreeIter  *iter,
2883                                  gpointer      data)
2884 {
2885   gboolean has_children;
2886
2887   has_children = gtk_tree_model_iter_has_child (model, iter);
2888
2889   return has_children;
2890 }
2891
2892 static void
2893 specific_bug_540201 (void)
2894 {
2895   /* Test case for GNOME Bugzilla bug 540201, steps provided by
2896    * Charles Day.
2897    */
2898   GtkTreeIter iter, root;
2899   GtkTreeStore *store;
2900   GtkTreeModel *filter;
2901
2902   GtkWidget *tree_view G_GNUC_UNUSED;
2903
2904   g_test_bug ("540201");
2905
2906   store = gtk_tree_store_new (1, G_TYPE_INT);
2907
2908   gtk_tree_store_append (store, &root, NULL);
2909   gtk_tree_store_set (store, &root, 0, 33, -1);
2910
2911   filter = gtk_tree_model_filter_new (GTK_TREE_MODEL (store), NULL);
2912   tree_view = gtk_tree_view_new_with_model (filter);
2913
2914   gtk_tree_model_filter_set_visible_func (GTK_TREE_MODEL_FILTER (filter),
2915                                           specific_bug_540201_filter_func,
2916                                           NULL, NULL);
2917
2918   gtk_tree_store_append (store, &iter, &root);
2919   gtk_tree_store_set (store, &iter, 0, 50, -1);
2920
2921   gtk_tree_store_append (store, &iter, &root);
2922   gtk_tree_store_set (store, &iter, 0, 22, -1);
2923
2924
2925   gtk_tree_store_append (store, &root, NULL);
2926   gtk_tree_store_set (store, &root, 0, 33, -1);
2927
2928   gtk_tree_store_append (store, &iter, &root);
2929   gtk_tree_store_set (store, &iter, 0, 22, -1);
2930 }
2931
2932
2933 static gboolean
2934 specific_bug_549287_visible_func (GtkTreeModel *model,
2935                                   GtkTreeIter  *iter,
2936                                   gpointer      data)
2937 {
2938   gboolean result = FALSE;
2939
2940   result = gtk_tree_model_iter_has_child (model, iter);
2941
2942   return result;
2943 }
2944
2945 static void
2946 specific_bug_549287 (void)
2947 {
2948   /* Test case for GNOME Bugzilla bug 529287, provided by Julient Puydt */
2949
2950   int i;
2951   GtkTreeStore *store;
2952   GtkTreeModel *filtered;
2953   GtkWidget *view G_GNUC_UNUSED;
2954   GtkTreeIter iter;
2955   GtkTreeIter *swap, *parent, *child;
2956
2957   g_test_bug ("529287");
2958
2959   store = gtk_tree_store_new (1, G_TYPE_STRING);
2960   filtered = gtk_tree_model_filter_new (GTK_TREE_MODEL (store), NULL);
2961   gtk_tree_model_filter_set_visible_func (GTK_TREE_MODEL_FILTER (filtered),
2962                                           specific_bug_549287_visible_func,
2963                                           NULL, NULL);
2964
2965   view = gtk_tree_view_new_with_model (filtered);
2966
2967   for (i = 0; i < 4; i++)
2968     {
2969       if (gtk_tree_model_get_iter_first (GTK_TREE_MODEL (store), &iter))
2970         {
2971           parent = gtk_tree_iter_copy (&iter);
2972           child = gtk_tree_iter_copy (&iter);
2973
2974           while (gtk_tree_model_iter_nth_child (GTK_TREE_MODEL (store),
2975                                                 child, parent, 0))
2976             {
2977
2978               swap = parent;
2979               parent = child;
2980               child = swap;
2981             }
2982
2983           gtk_tree_store_append (store, child, parent);
2984           gtk_tree_store_set (store, child,
2985                               0, "Something",
2986                               -1);
2987
2988           gtk_tree_iter_free (parent);
2989           gtk_tree_iter_free (child);
2990         }
2991       else
2992         {
2993           gtk_tree_store_append (store, &iter, NULL);
2994           gtk_tree_store_set (store, &iter,
2995                               0, "Something",
2996                               -1);
2997         }
2998
2999       /* since we inserted something, we changed the visibility conditions: */
3000       gtk_tree_model_filter_refilter (GTK_TREE_MODEL_FILTER (filtered));
3001     }
3002 }
3003
3004 /* main */
3005
3006 void
3007 register_filter_model_tests (void)
3008 {
3009   g_test_add ("/TreeModelFilter/self/verify-test-suite",
3010               FilterTest, NULL,
3011               filter_test_setup,
3012               verify_test_suite,
3013               filter_test_teardown);
3014
3015   g_test_add ("/TreeModelFilter/self/verify-test-suite/vroot/depth-1",
3016               FilterTest, gtk_tree_path_new_from_indices (2, -1),
3017               filter_test_setup,
3018               verify_test_suite_vroot,
3019               filter_test_teardown);
3020   g_test_add ("/TreeModelFilter/self/verify-test-suite/vroot/depth-2",
3021               FilterTest, gtk_tree_path_new_from_indices (2, 3, -1),
3022               filter_test_setup,
3023               verify_test_suite_vroot,
3024               filter_test_teardown);
3025
3026
3027   g_test_add ("/TreeModelFilter/filled/hide-root-level",
3028               FilterTest, NULL,
3029               filter_test_setup,
3030               filled_hide_root_level,
3031               filter_test_teardown);
3032   g_test_add ("/TreeModelFilter/filled/hide-child-levels",
3033               FilterTest, NULL,
3034               filter_test_setup,
3035               filled_hide_child_levels,
3036               filter_test_teardown);
3037
3038   g_test_add ("/TreeModelFilter/filled/hide-root-level/vroot",
3039               FilterTest, gtk_tree_path_new_from_indices (2, -1),
3040               filter_test_setup,
3041               filled_vroot_hide_root_level,
3042               filter_test_teardown);
3043   g_test_add ("/TreeModelFilter/filled/hide-child-levels/vroot",
3044               FilterTest, gtk_tree_path_new_from_indices (2, -1),
3045               filter_test_setup,
3046               filled_vroot_hide_child_levels,
3047               filter_test_teardown);
3048
3049
3050   g_test_add ("/TreeModelFilter/empty/show-nodes",
3051               FilterTest, NULL,
3052               filter_test_setup_empty,
3053               empty_show_nodes,
3054               filter_test_teardown);
3055   g_test_add ("/TreeModelFilter/empty/show-multiple-nodes",
3056               FilterTest, NULL,
3057               filter_test_setup_empty,
3058               empty_show_multiple_nodes,
3059               filter_test_teardown);
3060
3061   g_test_add ("/TreeModelFilter/empty/show-nodes/vroot",
3062               FilterTest, gtk_tree_path_new_from_indices (2, -1),
3063               filter_test_setup_empty,
3064               empty_vroot_show_nodes,
3065               filter_test_teardown);
3066   g_test_add ("/TreeModelFilter/empty/show-multiple-nodes/vroot",
3067               FilterTest, gtk_tree_path_new_from_indices (2, -1),
3068               filter_test_setup_empty,
3069               empty_vroot_show_multiple_nodes,
3070               filter_test_teardown);
3071
3072
3073   g_test_add ("/TreeModelFilter/unfiltered/hide-single",
3074               FilterTest, NULL,
3075               filter_test_setup_unfiltered,
3076               unfiltered_hide_single,
3077               filter_test_teardown);
3078   g_test_add ("/TreeModelFilter/unfiltered/hide-single-child",
3079               FilterTest, NULL,
3080               filter_test_setup_unfiltered,
3081               unfiltered_hide_single_child,
3082               filter_test_teardown);
3083   g_test_add ("/TreeModelFilter/unfiltered/hide-single-multi-level",
3084               FilterTest, NULL,
3085               filter_test_setup_unfiltered,
3086               unfiltered_hide_single_multi_level,
3087               filter_test_teardown);
3088
3089   g_test_add ("/TreeModelFilter/unfiltered/hide-single/vroot",
3090               FilterTest, gtk_tree_path_new_from_indices (2, -1),
3091               filter_test_setup_unfiltered,
3092               unfiltered_vroot_hide_single,
3093               filter_test_teardown);
3094   g_test_add ("/TreeModelFilter/unfiltered/hide-single-child/vroot",
3095               FilterTest, gtk_tree_path_new_from_indices (2, -1),
3096               filter_test_setup_unfiltered,
3097               unfiltered_vroot_hide_single_child,
3098               filter_test_teardown);
3099   g_test_add ("/TreeModelFilter/unfiltered/hide-single-multi-level/vroot",
3100               FilterTest, gtk_tree_path_new_from_indices (2, -1),
3101               filter_test_setup_unfiltered,
3102               unfiltered_vroot_hide_single_multi_level,
3103               filter_test_teardown);
3104
3105
3106
3107   g_test_add ("/TreeModelFilter/unfiltered/show-single",
3108               FilterTest, NULL,
3109               filter_test_setup_empty_unfiltered,
3110               unfiltered_show_single,
3111               filter_test_teardown);
3112   g_test_add ("/TreeModelFilter/unfiltered/show-single-child",
3113               FilterTest, NULL,
3114               filter_test_setup_empty_unfiltered,
3115               unfiltered_show_single_child,
3116               filter_test_teardown);
3117   g_test_add ("/TreeModelFilter/unfiltered/show-single-multi-level",
3118               FilterTest, NULL,
3119               filter_test_setup_empty_unfiltered,
3120               unfiltered_show_single_multi_level,
3121               filter_test_teardown);
3122
3123   g_test_add ("/TreeModelFilter/unfiltered/show-single/vroot",
3124               FilterTest, gtk_tree_path_new_from_indices (2, -1),
3125               filter_test_setup_empty_unfiltered,
3126               unfiltered_vroot_show_single,
3127               filter_test_teardown);
3128   g_test_add ("/TreeModelFilter/unfiltered/show-single-child/vroot",
3129               FilterTest, gtk_tree_path_new_from_indices (2, -1),
3130               filter_test_setup_empty_unfiltered,
3131               unfiltered_vroot_show_single_child,
3132               filter_test_teardown);
3133   g_test_add ("/TreeModelFilter/unfiltered/show-single-multi-level/vroot",
3134               FilterTest, gtk_tree_path_new_from_indices (2, -1),
3135               filter_test_setup_empty_unfiltered,
3136               unfiltered_vroot_show_single_multi_level,
3137               filter_test_teardown);
3138
3139   g_test_add_func ("/TreeModelFilter/specific/remove-node",
3140                    specific_remove_node);
3141   g_test_add_func ("/TreeModelFilter/specific/remove-node-vroot",
3142                    specific_remove_node_vroot);
3143   g_test_add_func ("/TreeModelFilter/specific/remove-vroot-ancestor",
3144                    specific_remove_vroot_ancestor);
3145
3146   g_test_add_func ("/TreeModelFilter/specific/path-dependent-filter",
3147                    specific_path_dependent_filter);
3148   g_test_add_func ("/TreeModelFilter/specific/append-after-collapse",
3149                    specific_append_after_collapse);
3150   g_test_add_func ("/TreeModelFilter/specific/sort-filter-remove-node",
3151                    specific_sort_filter_remove_node);
3152   g_test_add_func ("/TreeModelFilter/specific/sort-filter-remove-root",
3153                    specific_sort_filter_remove_root);
3154   g_test_add_func ("/TreeModelFilter/specific/root-mixed-visibility",
3155                    specific_root_mixed_visibility);
3156   g_test_add_func ("/TreeModelFilter/specific/has-child-filter",
3157                    specific_has_child_filter);
3158   g_test_add_func ("/TreeModelFilter/specific/root-has-child-filter",
3159                    specific_root_has_child_filter);
3160   g_test_add_func ("/TreeModelFilter/specific/filter-add-child",
3161                    specific_filter_add_child);
3162   g_test_add_func ("/TreeModelFilter/specific/list-store-clear",
3163                    specific_list_store_clear);
3164   g_test_add_func ("/TreeModelFilter/specific/sort-ref-leaf-and-remove-ancestor",
3165                    specific_sort_ref_leaf_and_remove_ancestor);
3166   g_test_add_func ("/TreeModelFilter/specific/ref-leaf-and-remove-ancestor",
3167                    specific_ref_leaf_and_remove_ancestor);
3168   g_test_add_func ("/TreeModelFilter/specific/virtual-ref-leaf-and-remove-ancestor",
3169                    specific_virtual_ref_leaf_and_remove_ancestor);
3170
3171   g_test_add_func ("/TreeModelFilter/specific/bug-301558",
3172                    specific_bug_301558);
3173   g_test_add_func ("/TreeModelFilter/specific/bug-311955",
3174                    specific_bug_311955);
3175   g_test_add_func ("/TreeModelFilter/specific/bug-346800",
3176                    specific_bug_346800);
3177   g_test_add_func ("/TreeModelFilter/specific/bug-464173",
3178                    specific_bug_464173);
3179   g_test_add_func ("/TreeModelFilter/specific/bug-540201",
3180                    specific_bug_540201);
3181   g_test_add_func ("/TreeModelFilter/specific/bug-549287",
3182                    specific_bug_549287);
3183 }