]> Pileus Git - ~andy/gtk/blob - gtk/tests/filtermodel.c
Update filter model ref count tests to reflect changes in rules
[~andy/gtk] / gtk / tests / filtermodel.c
1 /* Extensive GtkTreeModelFilter tests.
2  * Copyright (C) 2009,2011  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 #include "treemodel.h"
23 #include "gtktreemodelrefcount.h"
24
25 /* Left to do:
26  *   - Proper coverage checking to see if the unit tests cover
27  *     all possible cases.
28  *   - Check if the iterator stamp is incremented at the correct times.
29  *
30  * For more thorough testing:
31  *   - Test with randomized models.
32  *   - Extensively test a filter model wrapping a sort model,
33  *     or a sort model wrapping a filter model by:
34  *       # Checking structure.
35  *       # Checking for correct signals emissions.
36  *       # Checking correct reference counting.
37  *       # Tests should be done with the sort and filter model
38  *         in various filtering and sorting states.
39  */
40
41
42 /*
43  * Model creation
44  */
45
46 #define LEVEL_LENGTH 5
47
48 static void
49 create_tree_store_set_values (GtkTreeStore *store,
50                               GtkTreeIter  *iter,
51                               gboolean      visible)
52 {
53   GtkTreePath *path;
54   gchar *path_string;
55
56   path = gtk_tree_model_get_path (GTK_TREE_MODEL (store), iter);
57   path_string = gtk_tree_path_to_string (path);
58
59   gtk_tree_store_set (store, iter,
60                       0, path_string,
61                       1, visible,
62                       -1);
63
64   gtk_tree_path_free (path);
65   g_free (path_string);
66 }
67
68 static void
69 create_tree_store_recurse (int           depth,
70                            GtkTreeStore *store,
71                            GtkTreeIter  *parent,
72                            gboolean      visible)
73 {
74   int i;
75
76   for (i = 0; i < LEVEL_LENGTH; i++)
77     {
78       GtkTreeIter iter;
79
80       gtk_tree_store_insert (store, &iter, parent, i);
81       create_tree_store_set_values (store, &iter, visible);
82
83       if (depth > 0)
84         create_tree_store_recurse (depth - 1, store, &iter, visible);
85     }
86 }
87
88 static GtkTreeStore *
89 create_tree_store (int      depth,
90                    gboolean visible)
91 {
92   GtkTreeStore *store;
93
94   store = gtk_tree_store_new (2, G_TYPE_STRING, G_TYPE_BOOLEAN);
95
96   create_tree_store_recurse (depth, store, NULL, visible);
97
98   return store;
99 }
100
101 /*
102  * Fixture
103  */
104
105 typedef struct
106 {
107   GtkWidget *tree_view;
108
109   GtkTreeStore *store;
110   GtkTreeModelFilter *filter;
111
112   SignalMonitor *monitor;
113
114   guint block_signals : 1;
115 } FilterTest;
116
117
118 static void
119 filter_test_store_signal (FilterTest *fixture)
120 {
121   if (fixture->block_signals)
122     g_signal_stop_emission_by_name (fixture->store, "row-changed");
123 }
124
125
126 static void
127 filter_test_setup_generic (FilterTest    *fixture,
128                            gconstpointer  test_data,
129                            int            depth,
130                            gboolean       empty,
131                            gboolean       unfiltered)
132 {
133   const GtkTreePath *vroot = test_data;
134   GtkTreeModel *filter;
135
136   fixture->store = create_tree_store (depth, !empty);
137
138   g_signal_connect_swapped (fixture->store, "row-changed",
139                             G_CALLBACK (filter_test_store_signal), fixture);
140
141   /* Please forgive me for casting const away. */
142   filter = gtk_tree_model_filter_new (GTK_TREE_MODEL (fixture->store),
143                                       (GtkTreePath *)vroot);
144   fixture->filter = GTK_TREE_MODEL_FILTER (filter);
145
146   if (!unfiltered)
147     gtk_tree_model_filter_set_visible_column (fixture->filter, 1);
148
149   /* We need a tree view that's listening to get ref counting from that
150    * side.
151    */
152   fixture->tree_view = gtk_tree_view_new_with_model (filter);
153
154   fixture->monitor = signal_monitor_new (filter);
155 }
156
157 static void
158 filter_test_setup_expand_root (FilterTest *fixture)
159 {
160   int i;
161   GtkTreePath *path;
162
163   path = gtk_tree_path_new_from_indices (0, -1);
164
165   for (i = 0; i < LEVEL_LENGTH; i++)
166     {
167       gtk_tree_view_expand_row (GTK_TREE_VIEW (fixture->tree_view),
168                                 path, FALSE);
169       gtk_tree_path_next (path);
170     }
171   gtk_tree_path_free (path);
172 }
173
174 static void
175 filter_test_setup (FilterTest    *fixture,
176                    gconstpointer  test_data)
177 {
178   filter_test_setup_generic (fixture, test_data, 3, FALSE, FALSE);
179 }
180
181 static void
182 filter_test_setup_empty (FilterTest    *fixture,
183                          gconstpointer  test_data)
184 {
185   filter_test_setup_generic (fixture, test_data, 3, TRUE, FALSE);
186 }
187
188 static void
189 filter_test_setup_unfiltered (FilterTest    *fixture,
190                               gconstpointer  test_data)
191 {
192   filter_test_setup_generic (fixture, test_data, 3, FALSE, TRUE);
193 }
194
195 static void
196 filter_test_setup_unfiltered_root_expanded (FilterTest    *fixture,
197                                             gconstpointer  test_data)
198 {
199   filter_test_setup_unfiltered (fixture, test_data);
200   filter_test_setup_expand_root (fixture);
201 }
202
203 static void
204 filter_test_setup_empty_unfiltered (FilterTest    *fixture,
205                                     gconstpointer  test_data)
206 {
207   filter_test_setup_generic (fixture, test_data, 3, TRUE, TRUE);
208 }
209
210 static void
211 filter_test_setup_empty_unfiltered_root_expanded (FilterTest    *fixture,
212                                                   gconstpointer  test_data)
213 {
214   filter_test_setup_empty_unfiltered (fixture, test_data);
215   filter_test_setup_expand_root (fixture);
216 }
217
218 static GtkTreePath *
219 strip_virtual_root (GtkTreePath *path,
220                     GtkTreePath *root_path)
221 {
222   GtkTreePath *real_path;
223
224   if (root_path)
225     {
226       int j;
227       int depth = gtk_tree_path_get_depth (path);
228       int root_depth = gtk_tree_path_get_depth (root_path);
229
230       real_path = gtk_tree_path_new ();
231
232       for (j = 0; j < depth - root_depth; j++)
233         gtk_tree_path_append_index (real_path,
234                                     gtk_tree_path_get_indices (path)[root_depth + j]);
235     }
236   else
237     real_path = gtk_tree_path_copy (path);
238
239   return real_path;
240 }
241
242 static int
243 count_visible (FilterTest  *fixture,
244                GtkTreePath *store_path)
245 {
246   int i;
247   int n_visible = 0;
248   GtkTreeIter iter;
249
250   gtk_tree_model_get_iter (GTK_TREE_MODEL (fixture->store),
251                            &iter, store_path);
252
253   for (i = 0; i < LEVEL_LENGTH; i++)
254     {
255       gboolean visible;
256
257       gtk_tree_model_get (GTK_TREE_MODEL (fixture->store), &iter,
258                           1, &visible,
259                           -1);
260
261       if (visible)
262         n_visible++;
263     }
264
265   return n_visible;
266 }
267
268 static void
269 filter_test_append_refilter_signals_recurse (FilterTest  *fixture,
270                                              GtkTreePath *store_path,
271                                              GtkTreePath *filter_path,
272                                              int          depth,
273                                              GtkTreePath *root_path)
274 {
275   int i;
276   int rows_deleted = 0;
277   GtkTreeIter iter;
278
279   gtk_tree_path_down (store_path);
280   gtk_tree_path_down (filter_path);
281
282   gtk_tree_model_get_iter (GTK_TREE_MODEL (fixture->store),
283                            &iter, store_path);
284
285   for (i = 0; i < LEVEL_LENGTH; i++)
286     {
287       gboolean visible;
288       GtkTreePath *real_path;
289
290       gtk_tree_model_get (GTK_TREE_MODEL (fixture->store), &iter,
291                           1, &visible,
292                           -1);
293
294       if (root_path &&
295           (!gtk_tree_path_is_descendant (store_path, root_path)
296            || !gtk_tree_path_compare (store_path, root_path)))
297         {
298           if (!gtk_tree_path_compare (store_path, root_path))
299             {
300               if (depth > 1
301                   && gtk_tree_model_iter_has_child (GTK_TREE_MODEL (fixture->store),
302                                                     &iter))
303                 {
304                   GtkTreePath *store_copy;
305                   GtkTreePath *filter_copy;
306
307                   store_copy = gtk_tree_path_copy (store_path);
308                   filter_copy = gtk_tree_path_copy (filter_path);
309                   filter_test_append_refilter_signals_recurse (fixture,
310                                                                store_copy,
311                                                                filter_copy,
312                                                                depth - 1,
313                                                                root_path);
314                   gtk_tree_path_free (store_copy);
315                   gtk_tree_path_free (filter_copy);
316                 }
317             }
318
319           gtk_tree_path_next (store_path);
320           gtk_tree_model_iter_next (GTK_TREE_MODEL (fixture->store), &iter);
321
322           if (visible)
323             gtk_tree_path_next (filter_path);
324
325           continue;
326         }
327
328       real_path = strip_virtual_root (filter_path, root_path);
329
330       if (visible)
331         {
332           /* This row will be inserted */
333           signal_monitor_append_signal_path (fixture->monitor, ROW_CHANGED,
334                                              real_path);
335
336           if (gtk_tree_model_iter_has_child (GTK_TREE_MODEL (fixture->store),
337                                              &iter))
338             {
339               signal_monitor_append_signal_path (fixture->monitor,
340                                                  ROW_HAS_CHILD_TOGGLED,
341                                                  real_path);
342
343               if (depth > 1)
344                 {
345                   GtkTreePath *store_copy;
346                   GtkTreePath *filter_copy;
347
348                   store_copy = gtk_tree_path_copy (store_path);
349                   filter_copy = gtk_tree_path_copy (filter_path);
350                   filter_test_append_refilter_signals_recurse (fixture,
351                                                                store_copy,
352                                                                filter_copy,
353                                                                depth - 1,
354                                                                root_path);
355                   gtk_tree_path_free (store_copy);
356                   gtk_tree_path_free (filter_copy);
357                 }
358               else if (depth == 1)
359                 {
360                   GtkTreePath *tmp_path;
361
362                   /* If all child rows are invisible, then the last row to
363                    * become invisible will emit row-has-child-toggled on the
364                    * parent.
365                    */
366
367                   tmp_path = gtk_tree_path_copy (store_path);
368                   gtk_tree_path_append_index (tmp_path, 0);
369
370                   if (count_visible (fixture, tmp_path) == 0)
371                     signal_monitor_append_signal_path (fixture->monitor,
372                                                        ROW_HAS_CHILD_TOGGLED,
373                                                        real_path);
374
375                   gtk_tree_path_free (tmp_path);
376                 }
377             }
378
379           gtk_tree_path_next (filter_path);
380         }
381       else
382         {
383           /* This row will be deleted */
384           rows_deleted++;
385           signal_monitor_append_signal_path (fixture->monitor, ROW_DELETED,
386                                              real_path);
387         }
388
389       gtk_tree_path_free (real_path);
390
391       gtk_tree_path_next (store_path);
392       gtk_tree_model_iter_next (GTK_TREE_MODEL (fixture->store), &iter);
393     }
394
395   if (rows_deleted == LEVEL_LENGTH
396       && gtk_tree_path_get_depth (filter_path) > 1)
397     {
398       GtkTreePath *real_path;
399
400       gtk_tree_path_up (store_path);
401       gtk_tree_path_up (filter_path);
402
403       /* A row-has-child-toggled will be emitted on the parent */
404       if (!root_path
405           || (root_path
406               && gtk_tree_path_is_descendant (store_path, root_path)
407               && gtk_tree_path_compare (store_path, root_path)))
408         {
409           real_path = strip_virtual_root (filter_path, root_path);
410           signal_monitor_append_signal_path (fixture->monitor,
411                                              ROW_HAS_CHILD_TOGGLED,
412                                              real_path);
413
414           gtk_tree_path_free (real_path);
415         }
416     }
417 }
418
419 static void
420 filter_test_append_refilter_signals (FilterTest *fixture,
421                                      int         depth)
422 {
423   /* A special function that walks the tree store like the
424    * model validation functions below.
425    */
426   GtkTreePath *path;
427   GtkTreePath *filter_path;
428
429   path = gtk_tree_path_new ();
430   filter_path = gtk_tree_path_new ();
431   filter_test_append_refilter_signals_recurse (fixture,
432                                                path,
433                                                filter_path,
434                                                depth,
435                                                NULL);
436   gtk_tree_path_free (path);
437   gtk_tree_path_free (filter_path);
438 }
439
440 static void
441 filter_test_append_refilter_signals_with_vroot (FilterTest  *fixture,
442                                                 int          depth,
443                                                 GtkTreePath *root_path)
444 {
445   /* A special function that walks the tree store like the
446    * model validation functions below.
447    */
448   GtkTreePath *path;
449   GtkTreePath *filter_path;
450
451   path = gtk_tree_path_new ();
452   filter_path = gtk_tree_path_new ();
453   filter_test_append_refilter_signals_recurse (fixture,
454                                                path,
455                                                filter_path,
456                                                depth,
457                                                root_path);
458   gtk_tree_path_free (path);
459   gtk_tree_path_free (filter_path);
460 }
461
462 static void
463 filter_test_enable_filter (FilterTest *fixture)
464 {
465   gtk_tree_model_filter_set_visible_column (fixture->filter, 1);
466   gtk_tree_model_filter_refilter (fixture->filter);
467 }
468
469 static void
470 filter_test_block_signals (FilterTest *fixture)
471 {
472   fixture->block_signals = TRUE;
473 }
474
475 static void
476 filter_test_unblock_signals (FilterTest *fixture)
477 {
478   fixture->block_signals = FALSE;
479 }
480
481 static void
482 filter_test_teardown (FilterTest    *fixture,
483                       gconstpointer  test_data)
484 {
485   signal_monitor_free (fixture->monitor);
486
487   gtk_widget_destroy (fixture->tree_view);
488
489   g_object_unref (fixture->filter);
490   g_object_unref (fixture->store);
491 }
492
493 /*
494  * Model structure validation
495  */
496
497 static void
498 check_filter_model_recurse (FilterTest  *fixture,
499                             GtkTreePath *store_parent_path,
500                             GtkTreePath *filter_parent_path)
501 {
502   int i;
503   GtkTreeIter store_iter;
504   GtkTreeIter filter_iter;
505   gboolean store_has_next, filter_has_next;
506
507   gtk_tree_path_down (store_parent_path);
508   gtk_tree_path_down (filter_parent_path);
509
510   store_has_next = gtk_tree_model_get_iter (GTK_TREE_MODEL (fixture->store),
511                                             &store_iter, store_parent_path);
512   filter_has_next = gtk_tree_model_get_iter (GTK_TREE_MODEL (fixture->filter),
513                                              &filter_iter, filter_parent_path);
514
515   for (i = 0; i < LEVEL_LENGTH; i++)
516     {
517       gboolean visible;
518
519       g_return_if_fail (store_has_next == TRUE);
520
521       gtk_tree_model_get (GTK_TREE_MODEL (fixture->store),
522                           &store_iter,
523                           1, &visible,
524                           -1);
525
526       if (visible)
527         {
528           GtkTreePath *tmp;
529           gchar *filter_str, *store_str;
530
531           g_return_if_fail (filter_has_next == TRUE);
532
533           /* Verify path */
534           tmp = gtk_tree_model_get_path (GTK_TREE_MODEL (fixture->filter),
535                                          &filter_iter);
536           g_return_if_fail (gtk_tree_path_compare (tmp, filter_parent_path) == 0);
537
538           /* Verify model content */
539           gtk_tree_model_get (GTK_TREE_MODEL (fixture->store),
540                               &store_iter,
541                               0, &store_str,
542                               -1);
543           gtk_tree_model_get (GTK_TREE_MODEL (fixture->filter),
544                               &filter_iter,
545                               0, &filter_str,
546                               -1);
547
548           g_return_if_fail (g_strcmp0 (store_str, filter_str) == 0);
549
550           g_free (store_str);
551           g_free (filter_str);
552
553           if (gtk_tree_model_iter_has_child (GTK_TREE_MODEL (fixture->filter),
554                                              &filter_iter))
555             {
556               g_return_if_fail (gtk_tree_model_iter_has_child (GTK_TREE_MODEL (fixture->store), &store_iter));
557
558               check_filter_model_recurse (fixture,
559                                           gtk_tree_path_copy (store_parent_path),
560                                           tmp);
561             }
562           else
563             /* Only when we do not recurse we need to free tmp */
564             gtk_tree_path_free (tmp);
565
566           gtk_tree_path_next (filter_parent_path);
567           filter_has_next = gtk_tree_model_iter_next (GTK_TREE_MODEL (fixture->filter), &filter_iter);
568         }
569
570       gtk_tree_path_next (store_parent_path);
571       store_has_next = gtk_tree_model_iter_next (GTK_TREE_MODEL (fixture->store), &store_iter);
572     }
573
574   /* Both models should have no more content! */
575   g_return_if_fail (store_has_next == FALSE);
576   g_return_if_fail (filter_has_next == FALSE);
577
578   gtk_tree_path_free (store_parent_path);
579   gtk_tree_path_free (filter_parent_path);
580 }
581
582 static void
583 check_filter_model (FilterTest *fixture)
584 {
585   GtkTreePath *path;
586
587   if (fixture->monitor)
588     signal_monitor_assert_is_empty (fixture->monitor);
589
590   path = gtk_tree_path_new ();
591
592   check_filter_model_recurse (fixture, path, gtk_tree_path_copy (path));
593 }
594
595 static void
596 check_filter_model_with_root (FilterTest  *fixture,
597                               GtkTreePath *path)
598 {
599   if (fixture->monitor)
600     signal_monitor_assert_is_empty (fixture->monitor);
601
602   check_filter_model_recurse (fixture,
603                               gtk_tree_path_copy (path),
604                               gtk_tree_path_new ());
605 }
606
607 /* Helpers */
608
609 static void
610 check_level_length (GtkTreeModelFilter *filter,
611                     const gchar        *level,
612                     const int           expected_length)
613 {
614   if (!level)
615     {
616       int model_length;
617
618       model_length = gtk_tree_model_iter_n_children (GTK_TREE_MODEL (filter), NULL);
619       g_assert_cmpint (model_length, ==, expected_length);
620     }
621   else
622     {
623       int model_length;
624       gboolean retrieved_iter = FALSE;
625       GtkTreeIter iter;
626
627       retrieved_iter = gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL (filter),
628                                                             &iter, level);
629       g_return_if_fail (retrieved_iter);
630       model_length = gtk_tree_model_iter_n_children (GTK_TREE_MODEL (filter), &iter);
631       g_assert_cmpint (model_length, ==, expected_length);
632     }
633 }
634
635 static void
636 set_path_visibility (FilterTest  *fixture,
637                      const gchar *path,
638                      gboolean     visible)
639 {
640   GtkTreeIter store_iter;
641
642   gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL (fixture->store),
643                                        &store_iter, path);
644   gtk_tree_store_set (fixture->store, &store_iter,
645                       1, visible,
646                       -1);
647 }
648
649 #if 0
650 static void
651 insert_path_with_visibility (FilterTest  *fixture,
652                              const gchar *path_string,
653                              gboolean     visible)
654 {
655   int position;
656   GtkTreePath *path;
657   GtkTreeIter parent, iter;
658
659   path = gtk_tree_path_new_from_string (path_string);
660   position = gtk_tree_path_get_indices (path)[gtk_tree_path_get_depth (path)];
661   gtk_tree_path_up (path);
662
663   if (gtk_tree_model_get_iter (GTK_TREE_MODEL (fixture->store), &parent, path))
664     {
665       gtk_tree_store_insert (fixture->store, &iter, &parent, position);
666       create_tree_store_set_values (fixture->store, &iter, visible);
667     }
668   gtk_tree_path_free (path);
669 }
670 #endif
671
672 /*
673  * The actual tests.
674  */
675
676 static void
677 verify_test_suite (FilterTest    *fixture,
678                    gconstpointer  user_data)
679 {
680   check_filter_model (fixture);
681 }
682
683 static void
684 verify_test_suite_vroot (FilterTest    *fixture,
685                          gconstpointer  user_data)
686 {
687   check_filter_model_with_root (fixture, (GtkTreePath *)user_data);
688 }
689
690
691 static void
692 filled_hide_root_level (FilterTest    *fixture,
693                         gconstpointer  user_data)
694 {
695   signal_monitor_append_signal (fixture->monitor, ROW_DELETED, "2");
696   set_path_visibility (fixture, "2", FALSE);
697   check_filter_model (fixture);
698   check_level_length (fixture->filter, NULL, LEVEL_LENGTH - 1);
699
700   signal_monitor_append_signal (fixture->monitor, ROW_DELETED, "0");
701   set_path_visibility (fixture, "0", FALSE);
702   check_filter_model (fixture);
703   check_level_length (fixture->filter, NULL, LEVEL_LENGTH - 2);
704
705   signal_monitor_append_signal (fixture->monitor, ROW_DELETED, "2");
706   set_path_visibility (fixture, "4", FALSE);
707   check_filter_model (fixture);
708   check_level_length (fixture->filter, NULL, LEVEL_LENGTH - 3);
709
710
711   /* Hide remaining */
712   signal_monitor_append_signal (fixture->monitor, ROW_DELETED, "0");
713   signal_monitor_append_signal (fixture->monitor, ROW_DELETED, "0");
714
715   set_path_visibility (fixture, "1", FALSE);
716   check_level_length (fixture->filter, NULL, LEVEL_LENGTH - 4);
717
718   set_path_visibility (fixture, "3", FALSE);
719   check_level_length (fixture->filter, NULL, LEVEL_LENGTH - 5);
720
721   check_filter_model (fixture);
722
723   /* Show some */
724   signal_monitor_append_signal (fixture->monitor, ROW_INSERTED, "0");
725   signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "0");
726   signal_monitor_append_signal (fixture->monitor, ROW_INSERTED, "1");
727   signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "1");
728
729   set_path_visibility (fixture, "1", TRUE);
730   check_level_length (fixture->filter, NULL, LEVEL_LENGTH - 4);
731
732   set_path_visibility (fixture, "3", TRUE);
733   check_level_length (fixture->filter, NULL, LEVEL_LENGTH - 3);
734
735   check_filter_model (fixture);
736 }
737
738 static void
739 filled_hide_child_levels (FilterTest    *fixture,
740                           gconstpointer  user_data)
741 {
742   set_path_visibility (fixture, "0:2", FALSE);
743   check_filter_model (fixture);
744   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
745   check_level_length (fixture->filter, "0", LEVEL_LENGTH - 1);
746
747   set_path_visibility (fixture, "0:4", FALSE);
748   check_filter_model (fixture);
749   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
750   check_level_length (fixture->filter, "0", LEVEL_LENGTH - 2);
751
752   set_path_visibility (fixture, "0:4:3", FALSE);
753   check_filter_model (fixture);
754   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
755   check_level_length (fixture->filter, "0", LEVEL_LENGTH - 2);
756
757   set_path_visibility (fixture, "0:4:0", FALSE);
758   set_path_visibility (fixture, "0:4:1", FALSE);
759   set_path_visibility (fixture, "0:4:2", FALSE);
760   set_path_visibility (fixture, "0:4:4", FALSE);
761   check_filter_model (fixture);
762   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
763   check_level_length (fixture->filter, "0", LEVEL_LENGTH - 2);
764
765   /* Since "0:2" is hidden, "0:4" must be "0:3" in the filter model */
766   set_path_visibility (fixture, "0:4", TRUE);
767   check_filter_model (fixture);
768   check_level_length (fixture->filter, "0:3", 0);
769
770   set_path_visibility (fixture, "0:2", TRUE);
771   check_filter_model (fixture);
772   check_level_length (fixture->filter, "0:2", LEVEL_LENGTH);
773   check_level_length (fixture->filter, "0:3", LEVEL_LENGTH);
774   check_level_length (fixture->filter, "0:4", 0);
775
776   /* Once 0:4:0 got inserted, 0:4 became a parent.  Because 0:4 is
777    * not visible, not signals are emitted.
778    */
779   set_path_visibility (fixture, "0:4:2", TRUE);
780   set_path_visibility (fixture, "0:4:4", TRUE);
781   signal_monitor_assert_is_empty (fixture->monitor);
782   check_level_length (fixture->filter, "0:4", 2);
783 }
784
785 static void
786 filled_hide_child_levels_root_expanded (FilterTest    *fixture,
787                                         gconstpointer  user_data)
788 {
789   GtkTreePath *path;
790
791   path = gtk_tree_path_new_from_indices (0, -1);
792   gtk_tree_view_expand_row (GTK_TREE_VIEW (fixture->tree_view), path, FALSE);
793   gtk_tree_path_free (path);
794
795   signal_monitor_append_signal (fixture->monitor, ROW_DELETED, "0:2");
796   set_path_visibility (fixture, "0:2", FALSE);
797   check_filter_model (fixture);
798   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
799   check_level_length (fixture->filter, "0", LEVEL_LENGTH - 1);
800
801   signal_monitor_append_signal (fixture->monitor, ROW_DELETED, "0:3");
802   set_path_visibility (fixture, "0:4", FALSE);
803   check_filter_model (fixture);
804   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
805   check_level_length (fixture->filter, "0", LEVEL_LENGTH - 2);
806
807   set_path_visibility (fixture, "0:4:3", FALSE);
808   check_filter_model (fixture);
809   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
810   check_level_length (fixture->filter, "0", LEVEL_LENGTH - 2);
811
812   set_path_visibility (fixture, "0:4:0", FALSE);
813   set_path_visibility (fixture, "0:4:1", FALSE);
814   set_path_visibility (fixture, "0:4:2", FALSE);
815   set_path_visibility (fixture, "0:4:4", FALSE);
816   check_filter_model (fixture);
817   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
818   check_level_length (fixture->filter, "0", LEVEL_LENGTH - 2);
819
820   /* Since "0:2" is hidden, "0:4" must be "0:3" in the filter model */
821   signal_monitor_append_signal (fixture->monitor, ROW_INSERTED, "0:3");
822   signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "0:3");
823   set_path_visibility (fixture, "0:4", TRUE);
824   check_filter_model (fixture);
825   check_level_length (fixture->filter, "0:3", 0);
826
827   signal_monitor_append_signal (fixture->monitor, ROW_INSERTED, "0:2");
828   signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "0:2");
829   set_path_visibility (fixture, "0:2", TRUE);
830   check_filter_model (fixture);
831   check_level_length (fixture->filter, "0:2", LEVEL_LENGTH);
832   check_level_length (fixture->filter, "0:3", LEVEL_LENGTH);
833   check_level_length (fixture->filter, "0:4", 0);
834
835   /* has-child-toggled for 0:4 is required.  */
836   signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "0:4");
837   set_path_visibility (fixture, "0:4:2", TRUE);
838   set_path_visibility (fixture, "0:4:4", TRUE);
839   signal_monitor_assert_is_empty (fixture->monitor);
840   check_level_length (fixture->filter, "0:4", 2);
841 }
842
843
844 static void
845 filled_vroot_hide_root_level (FilterTest    *fixture,
846                               gconstpointer  user_data)
847 {
848   GtkTreePath *path = (GtkTreePath *)user_data;
849
850   /* These changes do not affect the filter's root level */
851   set_path_visibility (fixture, "0", FALSE);
852   check_filter_model_with_root (fixture, path);
853   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
854   check_level_length (fixture->filter, "0", LEVEL_LENGTH);
855
856   set_path_visibility (fixture, "4", FALSE);
857   check_filter_model_with_root (fixture, path);
858   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
859   check_level_length (fixture->filter, "0", LEVEL_LENGTH);
860
861   /* Even though we set the virtual root parent node to FALSE,
862    * the virtual root contents remain.
863    */
864   set_path_visibility (fixture, "2", FALSE);
865   check_filter_model_with_root (fixture, path);
866   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
867   check_level_length (fixture->filter, "0", LEVEL_LENGTH);
868
869   /* No change */
870   set_path_visibility (fixture, "1", FALSE);
871   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
872   check_level_length (fixture->filter, "0", LEVEL_LENGTH);
873
874   set_path_visibility (fixture, "3", FALSE);
875   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
876   check_level_length (fixture->filter, "0", LEVEL_LENGTH);
877
878   check_filter_model_with_root (fixture, path);
879
880   /* Show some */
881   set_path_visibility (fixture, "2", TRUE);
882   check_filter_model_with_root (fixture, path);
883   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
884   check_level_length (fixture->filter, "0", LEVEL_LENGTH);
885
886   set_path_visibility (fixture, "1", TRUE);
887   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
888   check_level_length (fixture->filter, "0", LEVEL_LENGTH);
889
890   set_path_visibility (fixture, "3", TRUE);
891   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
892   check_level_length (fixture->filter, "0", LEVEL_LENGTH);
893
894   check_filter_model_with_root (fixture, path);
895
896   /* Now test changes in the virtual root level */
897   signal_monitor_append_signal (fixture->monitor, ROW_DELETED, "2");
898   set_path_visibility (fixture, "2:2", FALSE);
899   check_filter_model_with_root (fixture, path);
900   check_level_length (fixture->filter, NULL, LEVEL_LENGTH - 1);
901
902   signal_monitor_append_signal (fixture->monitor, ROW_DELETED, "3");
903   set_path_visibility (fixture, "2:4", FALSE);
904   check_filter_model_with_root (fixture, path);
905   check_level_length (fixture->filter, NULL, LEVEL_LENGTH - 2);
906
907   set_path_visibility (fixture, "1:4", FALSE);
908   check_filter_model_with_root (fixture, path);
909   check_level_length (fixture->filter, NULL, LEVEL_LENGTH - 2);
910
911   signal_monitor_append_signal (fixture->monitor, ROW_INSERTED, "3");
912   signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "3");
913   set_path_visibility (fixture, "2:4", TRUE);
914   check_filter_model_with_root (fixture, path);
915   check_level_length (fixture->filter, NULL, LEVEL_LENGTH - 1);
916
917   set_path_visibility (fixture, "2", FALSE);
918   check_filter_model_with_root (fixture, path);
919   check_level_length (fixture->filter, NULL, LEVEL_LENGTH - 1);
920
921   signal_monitor_append_signal (fixture->monitor, ROW_DELETED, "0");
922   signal_monitor_append_signal (fixture->monitor, ROW_DELETED, "0");
923   signal_monitor_append_signal (fixture->monitor, ROW_DELETED, "0");
924   signal_monitor_append_signal (fixture->monitor, ROW_DELETED, "0");
925   set_path_visibility (fixture, "2:0", FALSE);
926   set_path_visibility (fixture, "2:1", FALSE);
927   set_path_visibility (fixture, "2:2", FALSE);
928   set_path_visibility (fixture, "2:3", FALSE);
929   set_path_visibility (fixture, "2:4", FALSE);
930   check_filter_model_with_root (fixture, path);
931   check_level_length (fixture->filter, NULL, 0);
932
933   set_path_visibility (fixture, "2", TRUE);
934   check_filter_model_with_root (fixture, path);
935   check_level_length (fixture->filter, NULL, 0);
936
937   set_path_visibility (fixture, "1:4", FALSE);
938   check_filter_model_with_root (fixture, path);
939   check_level_length (fixture->filter, NULL, 0);
940
941   signal_monitor_append_signal (fixture->monitor, ROW_INSERTED, "0");
942   signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "0");
943   set_path_visibility (fixture, "2:4", TRUE);
944   check_filter_model_with_root (fixture, path);
945   check_level_length (fixture->filter, NULL, LEVEL_LENGTH - 4);
946
947   signal_monitor_append_signal (fixture->monitor, ROW_DELETED, "0");
948   set_path_visibility (fixture, "2:4", FALSE);
949   check_filter_model_with_root (fixture, path);
950   check_level_length (fixture->filter, NULL, 0);
951
952   set_path_visibility (fixture, "2", FALSE);
953   check_filter_model_with_root (fixture, path);
954   check_level_length (fixture->filter, NULL, 0);
955
956   signal_monitor_append_signal (fixture->monitor, ROW_INSERTED, "0");
957   signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "0");
958   signal_monitor_append_signal (fixture->monitor, ROW_INSERTED, "1");
959   signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "1");
960   signal_monitor_append_signal (fixture->monitor, ROW_INSERTED, "2");
961   signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "2");
962   set_path_visibility (fixture, "2:0", TRUE);
963   set_path_visibility (fixture, "2:1", TRUE);
964   set_path_visibility (fixture, "2:2", TRUE);
965   check_filter_model_with_root (fixture, path);
966   check_level_length (fixture->filter, NULL, LEVEL_LENGTH - 2);
967
968   set_path_visibility (fixture, "2", TRUE);
969   check_filter_model_with_root (fixture, path);
970   check_level_length (fixture->filter, NULL, LEVEL_LENGTH - 2);
971 }
972
973 static void
974 filled_vroot_hide_child_levels (FilterTest    *fixture,
975                                 gconstpointer  user_data)
976 {
977   GtkTreePath *path = (GtkTreePath *)user_data;
978
979   set_path_visibility (fixture, "2:0:2", FALSE);
980   check_filter_model_with_root (fixture, path);
981   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
982   check_level_length (fixture->filter, "0", LEVEL_LENGTH - 1);
983
984   set_path_visibility (fixture, "2:0:4", FALSE);
985   check_filter_model_with_root (fixture, path);
986   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
987   check_level_length (fixture->filter, "0", LEVEL_LENGTH - 2);
988
989   set_path_visibility (fixture, "2:0:4:3", FALSE);
990   check_filter_model_with_root (fixture, path);
991   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
992   check_level_length (fixture->filter, "0", LEVEL_LENGTH - 2);
993
994   set_path_visibility (fixture, "2:0:4:0", FALSE);
995   set_path_visibility (fixture, "2:0:4:1", FALSE);
996   set_path_visibility (fixture, "2:0:4:2", FALSE);
997   set_path_visibility (fixture, "2:0:4:4", FALSE);
998   check_filter_model_with_root (fixture, path);
999   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
1000   check_level_length (fixture->filter, "0", LEVEL_LENGTH - 2);
1001
1002   /* Since "0:2" is hidden, "0:4" must be "0:3" in the filter model */
1003   set_path_visibility (fixture, "2:0:4", TRUE);
1004   check_filter_model_with_root (fixture, path);
1005   check_level_length (fixture->filter, "0:3", 0);
1006
1007   set_path_visibility (fixture, "2:0:2", TRUE);
1008   check_filter_model_with_root (fixture, path);
1009   check_level_length (fixture->filter, "0:2", LEVEL_LENGTH);
1010   check_level_length (fixture->filter, "0:3", LEVEL_LENGTH);
1011   check_level_length (fixture->filter, "0:4", 0);
1012
1013   /* Once 0:4:0 got inserted, 0:4 became a parent. However, 0:4 is not
1014    * visible, so no signal should be emitted.
1015    */
1016   set_path_visibility (fixture, "2:0:4:2", TRUE);
1017   set_path_visibility (fixture, "2:0:4:4", TRUE);
1018   check_level_length (fixture->filter, "0:4", 2);
1019   signal_monitor_assert_is_empty (fixture->monitor);
1020 }
1021
1022 static void
1023 filled_vroot_hide_child_levels_root_expanded (FilterTest    *fixture,
1024                                               gconstpointer  user_data)
1025 {
1026   GtkTreePath *path = (GtkTreePath *)user_data;
1027   GtkTreePath *tmp_path;
1028
1029   tmp_path = gtk_tree_path_new_from_indices (0, -1);
1030   gtk_tree_view_expand_row (GTK_TREE_VIEW (fixture->tree_view), tmp_path, FALSE);
1031   gtk_tree_path_free (tmp_path);
1032
1033   signal_monitor_append_signal (fixture->monitor, ROW_DELETED, "0:2");
1034   set_path_visibility (fixture, "2:0:2", FALSE);
1035   check_filter_model_with_root (fixture, path);
1036   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
1037   check_level_length (fixture->filter, "0", LEVEL_LENGTH - 1);
1038
1039   signal_monitor_append_signal (fixture->monitor, ROW_DELETED, "0:3");
1040   set_path_visibility (fixture, "2:0:4", FALSE);
1041   check_filter_model_with_root (fixture, path);
1042   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
1043   check_level_length (fixture->filter, "0", LEVEL_LENGTH - 2);
1044
1045   set_path_visibility (fixture, "2:0:4:3", FALSE);
1046   check_filter_model_with_root (fixture, path);
1047   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
1048   check_level_length (fixture->filter, "0", LEVEL_LENGTH - 2);
1049
1050   set_path_visibility (fixture, "2:0:4:0", FALSE);
1051   set_path_visibility (fixture, "2:0:4:1", FALSE);
1052   set_path_visibility (fixture, "2:0:4:2", FALSE);
1053   set_path_visibility (fixture, "2:0:4:4", FALSE);
1054   check_filter_model_with_root (fixture, path);
1055   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
1056   check_level_length (fixture->filter, "0", LEVEL_LENGTH - 2);
1057
1058   /* Since "0:2" is hidden, "0:4" must be "0:3" in the filter model */
1059   signal_monitor_append_signal (fixture->monitor, ROW_INSERTED, "0:3");
1060   signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "0:3");
1061   set_path_visibility (fixture, "2:0:4", TRUE);
1062   check_filter_model_with_root (fixture, path);
1063   check_level_length (fixture->filter, "0:3", 0);
1064
1065   signal_monitor_append_signal (fixture->monitor, ROW_INSERTED, "0:2");
1066   signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "0:2");
1067   set_path_visibility (fixture, "2:0:2", TRUE);
1068   check_filter_model_with_root (fixture, path);
1069   check_level_length (fixture->filter, "0:2", LEVEL_LENGTH);
1070   check_level_length (fixture->filter, "0:3", LEVEL_LENGTH);
1071   check_level_length (fixture->filter, "0:4", 0);
1072
1073   /* Once 0:4:0 got inserted, 0:4 became a parent */
1074   signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "0:4");
1075   set_path_visibility (fixture, "2:0:4:2", TRUE);
1076   set_path_visibility (fixture, "2:0:4:4", TRUE);
1077   check_level_length (fixture->filter, "0:4", 2);
1078   signal_monitor_assert_is_empty (fixture->monitor);
1079 }
1080
1081 static void
1082 empty_show_nodes (FilterTest    *fixture,
1083                   gconstpointer  user_data)
1084 {
1085   check_filter_model (fixture);
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   set_path_visibility (fixture, "3", TRUE);
1091   check_filter_model (fixture);
1092   check_level_length (fixture->filter, NULL, 1);
1093   check_level_length (fixture->filter, "0", 0);
1094
1095   set_path_visibility (fixture, "3:2:2", TRUE);
1096   check_filter_model (fixture);
1097   check_level_length (fixture->filter, NULL, 1);
1098   check_level_length (fixture->filter, "0", 0);
1099
1100   signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "0");
1101   set_path_visibility (fixture, "3:2", TRUE);
1102   check_filter_model (fixture);
1103   check_level_length (fixture->filter, NULL, 1);
1104   check_level_length (fixture->filter, "0", 1);
1105   check_level_length (fixture->filter, "0:0", 1);
1106   check_level_length (fixture->filter, "0:0:0", 0);
1107
1108   signal_monitor_append_signal (fixture->monitor, ROW_DELETED, "0");
1109   set_path_visibility (fixture, "3", FALSE);
1110   check_filter_model (fixture);
1111   check_level_length (fixture->filter, NULL, 0);
1112
1113   signal_monitor_append_signal (fixture->monitor, ROW_INSERTED, "0");
1114   signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "0");
1115   set_path_visibility (fixture, "3:2:1", TRUE);
1116   set_path_visibility (fixture, "3", TRUE);
1117   check_filter_model (fixture);
1118   check_level_length (fixture->filter, NULL, 1);
1119   check_level_length (fixture->filter, "0", 1);
1120   check_level_length (fixture->filter, "0:0", 2);
1121   check_level_length (fixture->filter, "0:0:0", 0);
1122 }
1123
1124 static void
1125 empty_show_multiple_nodes (FilterTest    *fixture,
1126                            gconstpointer  user_data)
1127 {
1128   GtkTreeIter iter;
1129   GtkTreePath *changed_path;
1130
1131   check_filter_model (fixture);
1132   check_level_length (fixture->filter, NULL, 0);
1133
1134   signal_monitor_append_signal (fixture->monitor, ROW_INSERTED, "0");
1135   signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "0");
1136   signal_monitor_append_signal (fixture->monitor, ROW_INSERTED, "1");
1137   signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "1");
1138
1139   /* We simulate a change in visible func condition with this.  The
1140    * visibility state of multiple nodes changes at once, we emit row-changed
1141    * for these nodes (and others) after that.
1142    */
1143   filter_test_block_signals (fixture);
1144   set_path_visibility (fixture, "3", TRUE);
1145   set_path_visibility (fixture, "4", TRUE);
1146   filter_test_unblock_signals (fixture);
1147
1148   changed_path = gtk_tree_path_new ();
1149   gtk_tree_path_append_index (changed_path, 2);
1150   gtk_tree_model_get_iter (GTK_TREE_MODEL (fixture->store),
1151                            &iter, changed_path);
1152   /* Invisible node - so no signals expected */
1153   gtk_tree_model_row_changed (GTK_TREE_MODEL (fixture->store),
1154                               changed_path, &iter);
1155
1156   gtk_tree_path_next (changed_path);
1157   gtk_tree_model_iter_next (GTK_TREE_MODEL (fixture->store), &iter);
1158   gtk_tree_model_row_changed (GTK_TREE_MODEL (fixture->store),
1159                               changed_path, &iter);
1160
1161   gtk_tree_path_next (changed_path);
1162   gtk_tree_model_iter_next (GTK_TREE_MODEL (fixture->store), &iter);
1163   gtk_tree_model_row_changed (GTK_TREE_MODEL (fixture->store),
1164                               changed_path, &iter);
1165
1166   gtk_tree_path_free (changed_path);
1167
1168   check_filter_model (fixture);
1169   check_level_length (fixture->filter, NULL, 2);
1170   check_level_length (fixture->filter, "0", 0);
1171
1172   set_path_visibility (fixture, "3:2:2", TRUE);
1173   check_filter_model (fixture);
1174   check_level_length (fixture->filter, NULL, 2);
1175   check_level_length (fixture->filter, "0", 0);
1176
1177   signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "0");
1178   set_path_visibility (fixture, "3:2", TRUE);
1179   check_filter_model (fixture);
1180   check_level_length (fixture->filter, NULL, 2);
1181   check_level_length (fixture->filter, "0", 1);
1182   check_level_length (fixture->filter, "0:0", 1);
1183   check_level_length (fixture->filter, "0:0:0", 0);
1184
1185   signal_monitor_append_signal (fixture->monitor, ROW_DELETED, "0");
1186   set_path_visibility (fixture, "3", FALSE);
1187   check_filter_model (fixture);
1188   check_level_length (fixture->filter, NULL, 1);
1189
1190   signal_monitor_append_signal (fixture->monitor, ROW_INSERTED, "0");
1191   signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "0");
1192   set_path_visibility (fixture, "3:2:1", TRUE);
1193   set_path_visibility (fixture, "3", TRUE);
1194   check_filter_model (fixture);
1195   check_level_length (fixture->filter, NULL, 2);
1196   check_level_length (fixture->filter, "0", 1);
1197   check_level_length (fixture->filter, "0:0", 2);
1198   check_level_length (fixture->filter, "0:0:0", 0);
1199 }
1200
1201 static void
1202 empty_vroot_show_nodes (FilterTest    *fixture,
1203                         gconstpointer  user_data)
1204 {
1205   GtkTreePath *path = (GtkTreePath *)user_data;
1206
1207   check_filter_model_with_root (fixture, path);
1208   check_level_length (fixture->filter, NULL, 0);
1209
1210   set_path_visibility (fixture, "2", TRUE);
1211   check_filter_model_with_root (fixture, path);
1212   check_level_length (fixture->filter, NULL, 0);
1213
1214   set_path_visibility (fixture, "2:2:2", TRUE);
1215   check_filter_model_with_root (fixture, path);
1216   check_level_length (fixture->filter, NULL, 0);
1217
1218   signal_monitor_append_signal (fixture->monitor, ROW_INSERTED, "0");
1219   signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "0");
1220   set_path_visibility (fixture, "2:2", TRUE);
1221   check_filter_model_with_root (fixture, path);
1222   check_level_length (fixture->filter, NULL, 1);
1223   check_level_length (fixture->filter, "0", 1);
1224   check_level_length (fixture->filter, "0:0", 0);
1225
1226   set_path_visibility (fixture, "3", TRUE);
1227   check_filter_model_with_root (fixture, path);
1228   check_level_length (fixture->filter, NULL, 1);
1229
1230   signal_monitor_append_signal (fixture->monitor, ROW_DELETED, "0");
1231   set_path_visibility (fixture, "2:2", FALSE);
1232   check_filter_model_with_root (fixture, path);
1233   check_level_length (fixture->filter, NULL, 0);
1234
1235   signal_monitor_append_signal (fixture->monitor, ROW_INSERTED, "0");
1236   signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "0");
1237   set_path_visibility (fixture, "2:2:1", TRUE);
1238   set_path_visibility (fixture, "2:2", TRUE);
1239   check_filter_model_with_root (fixture, path);
1240   check_level_length (fixture->filter, NULL, 1);
1241   check_level_length (fixture->filter, "0", 2);
1242   check_level_length (fixture->filter, "0:1", 0);
1243 }
1244
1245 static void
1246 empty_vroot_show_multiple_nodes (FilterTest    *fixture,
1247                                  gconstpointer  user_data)
1248 {
1249   GtkTreeIter iter;
1250   GtkTreePath *changed_path;
1251   GtkTreePath *path = (GtkTreePath *)user_data;
1252
1253   check_filter_model_with_root (fixture, path);
1254   check_level_length (fixture->filter, NULL, 0);
1255
1256   /* We simulate a change in visible func condition with this.  The
1257    * visibility state of multiple nodes changes at once, we emit row-changed
1258    * for these nodes (and others) after that.
1259    */
1260   filter_test_block_signals (fixture);
1261   set_path_visibility (fixture, "2", TRUE);
1262   set_path_visibility (fixture, "3", TRUE);
1263   filter_test_unblock_signals (fixture);
1264
1265   changed_path = gtk_tree_path_new ();
1266   gtk_tree_path_append_index (changed_path, 1);
1267   gtk_tree_model_get_iter (GTK_TREE_MODEL (fixture->store),
1268                            &iter, changed_path);
1269   gtk_tree_model_row_changed (GTK_TREE_MODEL (fixture->store),
1270                               changed_path, &iter);
1271
1272   gtk_tree_path_next (changed_path);
1273   gtk_tree_model_iter_next (GTK_TREE_MODEL (fixture->store), &iter);
1274   gtk_tree_model_row_changed (GTK_TREE_MODEL (fixture->store),
1275                               changed_path, &iter);
1276
1277   gtk_tree_path_next (changed_path);
1278   gtk_tree_model_iter_next (GTK_TREE_MODEL (fixture->store), &iter);
1279   gtk_tree_model_row_changed (GTK_TREE_MODEL (fixture->store),
1280                               changed_path, &iter);
1281
1282   gtk_tree_path_next (changed_path);
1283   gtk_tree_model_iter_next (GTK_TREE_MODEL (fixture->store), &iter);
1284   gtk_tree_model_row_changed (GTK_TREE_MODEL (fixture->store),
1285                               changed_path, &iter);
1286
1287   gtk_tree_path_free (changed_path);
1288
1289   check_filter_model_with_root (fixture, path);
1290   check_level_length (fixture->filter, NULL, 0);
1291
1292   set_path_visibility (fixture, "2:2:2", TRUE);
1293   check_filter_model_with_root (fixture, path);
1294   check_level_length (fixture->filter, NULL, 0);
1295
1296   signal_monitor_append_signal (fixture->monitor, ROW_INSERTED, "0");
1297   signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "0");
1298   signal_monitor_append_signal (fixture->monitor, ROW_INSERTED, "1");
1299   signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "1");
1300
1301   /* Again, we simulate a call to refilter */
1302   filter_test_block_signals (fixture);
1303   set_path_visibility (fixture, "2:2", TRUE);
1304   set_path_visibility (fixture, "2:3", TRUE);
1305   filter_test_unblock_signals (fixture);
1306
1307   changed_path = gtk_tree_path_new ();
1308   gtk_tree_path_append_index (changed_path, 2);
1309   gtk_tree_path_append_index (changed_path, 1);
1310   gtk_tree_model_get_iter (GTK_TREE_MODEL (fixture->store),
1311                            &iter, changed_path);
1312   gtk_tree_model_row_changed (GTK_TREE_MODEL (fixture->store),
1313                               changed_path, &iter);
1314
1315   gtk_tree_path_next (changed_path);
1316   gtk_tree_model_iter_next (GTK_TREE_MODEL (fixture->store), &iter);
1317   gtk_tree_model_row_changed (GTK_TREE_MODEL (fixture->store),
1318                               changed_path, &iter);
1319
1320   gtk_tree_path_next (changed_path);
1321   gtk_tree_model_iter_next (GTK_TREE_MODEL (fixture->store), &iter);
1322   gtk_tree_model_row_changed (GTK_TREE_MODEL (fixture->store),
1323                               changed_path, &iter);
1324
1325   gtk_tree_path_next (changed_path);
1326   gtk_tree_model_iter_next (GTK_TREE_MODEL (fixture->store), &iter);
1327   gtk_tree_model_row_changed (GTK_TREE_MODEL (fixture->store),
1328                               changed_path, &iter);
1329
1330   gtk_tree_path_free (changed_path);
1331
1332   check_filter_model_with_root (fixture, path);
1333   check_level_length (fixture->filter, NULL, 2);
1334   check_level_length (fixture->filter, "0", 1);
1335   check_level_length (fixture->filter, "0:0", 0);
1336
1337   set_path_visibility (fixture, "3", TRUE);
1338   check_filter_model_with_root (fixture, path);
1339   check_level_length (fixture->filter, NULL, 2);
1340
1341   signal_monitor_append_signal (fixture->monitor, ROW_DELETED, "0");
1342   set_path_visibility (fixture, "2:2", FALSE);
1343   check_filter_model_with_root (fixture, path);
1344   check_level_length (fixture->filter, NULL, 1);
1345
1346   signal_monitor_append_signal (fixture->monitor, ROW_INSERTED, "0");
1347   signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "0");
1348   set_path_visibility (fixture, "2:2:1", TRUE);
1349   set_path_visibility (fixture, "2:2", TRUE);
1350   check_filter_model_with_root (fixture, path);
1351   check_level_length (fixture->filter, NULL, 2);
1352   check_level_length (fixture->filter, "0", 2);
1353   check_level_length (fixture->filter, "0:1", 0);
1354 }
1355
1356
1357 static void
1358 unfiltered_hide_single (FilterTest    *fixture,
1359                         gconstpointer  user_data)
1360
1361 {
1362   signal_monitor_append_signal (fixture->monitor, ROW_CHANGED, "2");
1363   signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "2");
1364   set_path_visibility (fixture, "2", FALSE);
1365
1366   signal_monitor_assert_is_empty (fixture->monitor);
1367   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
1368
1369   /* The view only shows the root level, so we only expect signals
1370    * for the root level.
1371    */
1372   filter_test_append_refilter_signals (fixture, 1);
1373   filter_test_enable_filter (fixture);
1374
1375   check_filter_model (fixture);
1376   check_level_length (fixture->filter, NULL, LEVEL_LENGTH - 1);
1377 }
1378
1379 static void
1380 unfiltered_hide_single_root_expanded (FilterTest    *fixture,
1381                                       gconstpointer  user_data)
1382
1383 {
1384   signal_monitor_append_signal (fixture->monitor, ROW_CHANGED, "2");
1385   signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "2");
1386   set_path_visibility (fixture, "2", FALSE);
1387
1388   signal_monitor_assert_is_empty (fixture->monitor);
1389   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
1390
1391   filter_test_append_refilter_signals (fixture, 2);
1392   filter_test_enable_filter (fixture);
1393
1394   check_filter_model (fixture);
1395   check_level_length (fixture->filter, NULL, LEVEL_LENGTH - 1);
1396 }
1397
1398 static void
1399 unfiltered_hide_single_child (FilterTest    *fixture,
1400                               gconstpointer  user_data)
1401
1402 {
1403   /* This row is not shown, so its signal is not propagated */
1404   set_path_visibility (fixture, "2:2", FALSE);
1405
1406   signal_monitor_assert_is_empty (fixture->monitor);
1407   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
1408   check_level_length (fixture->filter, "2", LEVEL_LENGTH);
1409
1410   /* The view only shows the root level, so we only expect signals
1411    * for the root level.
1412    */
1413   filter_test_append_refilter_signals (fixture, 0);
1414   filter_test_enable_filter (fixture);
1415
1416   check_filter_model (fixture);
1417   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
1418   check_level_length (fixture->filter, "2", LEVEL_LENGTH - 1);
1419 }
1420
1421 static void
1422 unfiltered_hide_single_child_root_expanded (FilterTest    *fixture,
1423                                             gconstpointer  user_data)
1424
1425 {
1426   signal_monitor_append_signal (fixture->monitor, ROW_CHANGED, "2:2");
1427   signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "2:2");
1428   set_path_visibility (fixture, "2:2", FALSE);
1429
1430   signal_monitor_assert_is_empty (fixture->monitor);
1431   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
1432   check_level_length (fixture->filter, "2", LEVEL_LENGTH);
1433
1434   filter_test_append_refilter_signals (fixture, 2);
1435   filter_test_enable_filter (fixture);
1436
1437   check_filter_model (fixture);
1438   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
1439   check_level_length (fixture->filter, "2", LEVEL_LENGTH - 1);
1440 }
1441
1442 static void
1443 unfiltered_hide_single_multi_level (FilterTest    *fixture,
1444                                     gconstpointer  user_data)
1445
1446 {
1447   /* This row is not shown, so its signal is not propagated */
1448   set_path_visibility (fixture, "2:2:2", FALSE);
1449
1450   /* This row is not shown, so its signal is not propagated */
1451   set_path_visibility (fixture, "2:2", FALSE);
1452
1453   signal_monitor_assert_is_empty (fixture->monitor);
1454   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
1455   check_level_length (fixture->filter, "2", LEVEL_LENGTH);
1456   check_level_length (fixture->filter, "2:2", LEVEL_LENGTH);
1457
1458   /* The view only shows the root level, so we only expect signals
1459    * for the root level.
1460    */
1461   filter_test_append_refilter_signals (fixture, 1);
1462   filter_test_enable_filter (fixture);
1463
1464   check_filter_model (fixture);
1465   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
1466   check_level_length (fixture->filter, "2", LEVEL_LENGTH - 1);
1467
1468   set_path_visibility (fixture, "2:2", TRUE);
1469
1470   check_filter_model (fixture);
1471   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
1472   check_level_length (fixture->filter, "2", LEVEL_LENGTH);
1473   check_level_length (fixture->filter, "2:2", LEVEL_LENGTH - 1);
1474 }
1475
1476 static void
1477 unfiltered_hide_single_multi_level_root_expanded (FilterTest    *fixture,
1478                                                   gconstpointer  user_data)
1479
1480 {
1481   /* This row is not shown, so its signal is not propagated */
1482   set_path_visibility (fixture, "2:2:2", FALSE);
1483
1484   signal_monitor_append_signal (fixture->monitor, ROW_CHANGED, "2:2");
1485   signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "2:2");
1486   set_path_visibility (fixture, "2:2", FALSE);
1487
1488   signal_monitor_assert_is_empty (fixture->monitor);
1489   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
1490   check_level_length (fixture->filter, "2", LEVEL_LENGTH);
1491   check_level_length (fixture->filter, "2:2", LEVEL_LENGTH);
1492
1493   filter_test_append_refilter_signals (fixture, 2);
1494   filter_test_enable_filter (fixture);
1495
1496   check_filter_model (fixture);
1497   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
1498   check_level_length (fixture->filter, "2", LEVEL_LENGTH - 1);
1499
1500   signal_monitor_append_signal (fixture->monitor, ROW_INSERTED, "2:2");
1501   signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "2:2");
1502   set_path_visibility (fixture, "2:2", TRUE);
1503
1504   check_filter_model (fixture);
1505   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
1506   check_level_length (fixture->filter, "2", LEVEL_LENGTH);
1507   check_level_length (fixture->filter, "2:2", LEVEL_LENGTH - 1);
1508 }
1509
1510
1511
1512 static void
1513 unfiltered_vroot_hide_single (FilterTest    *fixture,
1514                               gconstpointer  user_data)
1515
1516 {
1517   GtkTreePath *path = (GtkTreePath *)user_data;
1518
1519   signal_monitor_append_signal (fixture->monitor, ROW_CHANGED, "2");
1520   signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "2");
1521   set_path_visibility (fixture, "2:2", FALSE);
1522
1523   signal_monitor_assert_is_empty (fixture->monitor);
1524   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
1525
1526   /* The view only shows the root level, so we only expect signals
1527    * for the root level.  (Though for the depth argument, we have to
1528    * take the virtual root into account).
1529    */
1530   filter_test_append_refilter_signals_with_vroot (fixture, 2, path);
1531   filter_test_enable_filter (fixture);
1532
1533   check_filter_model_with_root (fixture, path);
1534   check_level_length (fixture->filter, NULL, LEVEL_LENGTH - 1);
1535 }
1536
1537 static void
1538 unfiltered_vroot_hide_single_child (FilterTest    *fixture,
1539                                     gconstpointer  user_data)
1540
1541 {
1542   GtkTreePath *path = (GtkTreePath *)user_data;
1543
1544   /* Not visible, so no signal will be received. */
1545   set_path_visibility (fixture, "2:2:2", FALSE);
1546
1547   signal_monitor_assert_is_empty (fixture->monitor);
1548   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
1549   check_level_length (fixture->filter, "2", LEVEL_LENGTH);
1550
1551   /* The view only shows the root level, so we only expect signals
1552    * for the root level.  (Though for the depth argument, we have to
1553    * take the virtual root into account).
1554    */
1555   filter_test_append_refilter_signals_with_vroot (fixture, 2, path);
1556   filter_test_enable_filter (fixture);
1557
1558   check_filter_model_with_root (fixture, path);
1559   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
1560   check_level_length (fixture->filter, "2", LEVEL_LENGTH - 1);
1561 }
1562
1563 static void
1564 unfiltered_vroot_hide_single_child_root_expanded (FilterTest    *fixture,
1565                                                   gconstpointer  user_data)
1566
1567 {
1568   GtkTreePath *path = (GtkTreePath *)user_data;
1569
1570   signal_monitor_append_signal (fixture->monitor, ROW_CHANGED, "2:2");
1571   signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "2:2");
1572   set_path_visibility (fixture, "2:2:2", FALSE);
1573
1574   signal_monitor_assert_is_empty (fixture->monitor);
1575   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
1576   check_level_length (fixture->filter, "2", LEVEL_LENGTH);
1577
1578   filter_test_append_refilter_signals_with_vroot (fixture, 3, path);
1579   filter_test_enable_filter (fixture);
1580
1581   check_filter_model_with_root (fixture, path);
1582   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
1583   check_level_length (fixture->filter, "2", LEVEL_LENGTH - 1);
1584 }
1585
1586 static void
1587 unfiltered_vroot_hide_single_multi_level (FilterTest    *fixture,
1588                                           gconstpointer  user_data)
1589
1590 {
1591   GtkTreePath *path = (GtkTreePath *)user_data;
1592
1593   /* This row is not shown, so its signal is not propagated */
1594   set_path_visibility (fixture, "2:2:2:2", FALSE);
1595
1596   /* Not shown, so no signal */
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   /* We only expect signals for the root level.  The depth is 2
1605    * because we have to take the virtual root into account.
1606    */
1607   filter_test_append_refilter_signals_with_vroot (fixture, 2, 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   /* Not shown, so no signal */
1615   set_path_visibility (fixture, "2:2:2", TRUE);
1616
1617   check_filter_model_with_root (fixture, path);
1618   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
1619   check_level_length (fixture->filter, "2", LEVEL_LENGTH);
1620   check_level_length (fixture->filter, "2:2", LEVEL_LENGTH - 1);
1621 }
1622
1623 static void
1624 unfiltered_vroot_hide_single_multi_level_root_expanded (FilterTest    *fixture,
1625                                                         gconstpointer  user_data)
1626
1627 {
1628   GtkTreePath *path = (GtkTreePath *)user_data;
1629
1630   /* This row is not shown, so its signal is not propagated */
1631   set_path_visibility (fixture, "2:2:2:2", FALSE);
1632
1633   signal_monitor_append_signal (fixture->monitor, ROW_CHANGED, "2:2");
1634   signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "2:2");
1635   set_path_visibility (fixture, "2:2:2", FALSE);
1636
1637   signal_monitor_assert_is_empty (fixture->monitor);
1638   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
1639   check_level_length (fixture->filter, "2", LEVEL_LENGTH);
1640   check_level_length (fixture->filter, "2:2", LEVEL_LENGTH);
1641
1642   filter_test_append_refilter_signals_with_vroot (fixture, 3, path);
1643   filter_test_enable_filter (fixture);
1644
1645   check_filter_model_with_root (fixture, path);
1646   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
1647   check_level_length (fixture->filter, "2", LEVEL_LENGTH - 1);
1648
1649   signal_monitor_append_signal (fixture->monitor, ROW_INSERTED, "2:2");
1650   signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "2:2");
1651   set_path_visibility (fixture, "2:2:2", TRUE);
1652
1653   check_filter_model_with_root (fixture, path);
1654   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
1655   check_level_length (fixture->filter, "2", LEVEL_LENGTH);
1656   check_level_length (fixture->filter, "2:2", LEVEL_LENGTH - 1);
1657 }
1658
1659 static void
1660 unfiltered_show_single (FilterTest    *fixture,
1661                         gconstpointer  user_data)
1662
1663 {
1664   signal_monitor_append_signal (fixture->monitor, ROW_CHANGED, "2");
1665   signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "2");
1666   set_path_visibility (fixture, "2", TRUE);
1667
1668   signal_monitor_assert_is_empty (fixture->monitor);
1669   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
1670
1671   /* We only expect signals for the root level */
1672   filter_test_append_refilter_signals (fixture, 1);
1673   filter_test_enable_filter (fixture);
1674
1675   check_filter_model (fixture);
1676   check_level_length (fixture->filter, NULL, 1);
1677 }
1678
1679 static void
1680 unfiltered_show_single_child (FilterTest    *fixture,
1681                               gconstpointer  user_data)
1682
1683 {
1684   set_path_visibility (fixture, "2:2", TRUE);
1685
1686   signal_monitor_assert_is_empty (fixture->monitor);
1687   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
1688   check_level_length (fixture->filter, "2", LEVEL_LENGTH);
1689
1690   /* We only expect signals for the root level */
1691   filter_test_append_refilter_signals (fixture, 1);
1692   filter_test_enable_filter (fixture);
1693
1694   check_filter_model (fixture);
1695   check_level_length (fixture->filter, NULL, 0);
1696
1697   /* From here we are filtered, "2" in the real model is "0" in the filter
1698    * model.
1699    */
1700   signal_monitor_append_signal (fixture->monitor, ROW_INSERTED, "0");
1701   signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "0");
1702   set_path_visibility (fixture, "2", TRUE);
1703   signal_monitor_assert_is_empty (fixture->monitor);
1704   check_level_length (fixture->filter, NULL, 1);
1705   check_level_length (fixture->filter, "0", 1);
1706 }
1707
1708 static void
1709 unfiltered_show_single_child_root_expanded (FilterTest    *fixture,
1710                                             gconstpointer  user_data)
1711
1712 {
1713   signal_monitor_append_signal (fixture->monitor, ROW_CHANGED, "2:2");
1714   signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "2:2");
1715   set_path_visibility (fixture, "2:2", TRUE);
1716
1717   signal_monitor_assert_is_empty (fixture->monitor);
1718   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
1719   check_level_length (fixture->filter, "2", LEVEL_LENGTH);
1720
1721   filter_test_append_refilter_signals (fixture, 2);
1722   filter_test_enable_filter (fixture);
1723
1724   check_filter_model (fixture);
1725   check_level_length (fixture->filter, NULL, 0);
1726
1727   /* From here we are filtered, "2" in the real model is "0" in the filter
1728    * model.
1729    */
1730   signal_monitor_append_signal (fixture->monitor, ROW_INSERTED, "0");
1731   signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "0");
1732   set_path_visibility (fixture, "2", TRUE);
1733   signal_monitor_assert_is_empty (fixture->monitor);
1734   check_level_length (fixture->filter, NULL, 1);
1735   check_level_length (fixture->filter, "0", 1);
1736 }
1737
1738 static void
1739 unfiltered_show_single_multi_level (FilterTest    *fixture,
1740                                     gconstpointer  user_data)
1741
1742 {
1743   /* The view is not showing these rows (collapsed state), so it is not
1744    * referenced.  The signal should not go through.
1745    */
1746   set_path_visibility (fixture, "2:2:2", TRUE);
1747   set_path_visibility (fixture, "2:2", TRUE);
1748
1749   signal_monitor_assert_is_empty (fixture->monitor);
1750   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
1751   check_level_length (fixture->filter, "2", LEVEL_LENGTH);
1752   check_level_length (fixture->filter, "2:2", LEVEL_LENGTH);
1753
1754   /* We only expect signals for the first level */
1755   filter_test_append_refilter_signals (fixture, 1);
1756   filter_test_enable_filter (fixture);
1757
1758   check_filter_model (fixture);
1759   check_level_length (fixture->filter, NULL, 0);
1760
1761   /* From here we are filtered, "2" in the real model is "0" in the filter
1762    * model.
1763    */
1764   signal_monitor_append_signal (fixture->monitor, ROW_INSERTED, "0");
1765   signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "0");
1766   set_path_visibility (fixture, "2", TRUE);
1767   check_filter_model (fixture);
1768   check_level_length (fixture->filter, NULL, 1);
1769   check_level_length (fixture->filter, "0", 1);
1770   check_level_length (fixture->filter, "0:0", 1);
1771 }
1772
1773 static void
1774 unfiltered_show_single_multi_level_root_expanded (FilterTest    *fixture,
1775                                                   gconstpointer  user_data)
1776
1777 {
1778   /* The view is not showing this row (collapsed state), so it is not
1779    * referenced.  The signal should not go through.
1780    */
1781   set_path_visibility (fixture, "2:2:2", TRUE);
1782
1783   signal_monitor_append_signal (fixture->monitor, ROW_CHANGED, "2:2");
1784   signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "2:2");
1785   set_path_visibility (fixture, "2:2", TRUE);
1786
1787   signal_monitor_assert_is_empty (fixture->monitor);
1788   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
1789   check_level_length (fixture->filter, "2", LEVEL_LENGTH);
1790   check_level_length (fixture->filter, "2:2", LEVEL_LENGTH);
1791
1792   filter_test_append_refilter_signals (fixture, 2);
1793   filter_test_enable_filter (fixture);
1794
1795   check_filter_model (fixture);
1796   check_level_length (fixture->filter, NULL, 0);
1797
1798   /* From here we are filtered, "2" in the real model is "0" in the filter
1799    * model.
1800    */
1801   signal_monitor_append_signal (fixture->monitor, ROW_INSERTED, "0");
1802   signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "0");
1803   set_path_visibility (fixture, "2", TRUE);
1804   check_filter_model (fixture);
1805   check_level_length (fixture->filter, NULL, 1);
1806   check_level_length (fixture->filter, "0", 1);
1807   check_level_length (fixture->filter, "0:0", 1);
1808 }
1809
1810 static void
1811 unfiltered_vroot_show_single (FilterTest    *fixture,
1812                               gconstpointer  user_data)
1813
1814 {
1815   GtkTreePath *path = (GtkTreePath *)user_data;
1816
1817   signal_monitor_append_signal (fixture->monitor, ROW_CHANGED, "2");
1818   signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "2");
1819   set_path_visibility (fixture, "2:2", TRUE);
1820
1821   signal_monitor_assert_is_empty (fixture->monitor);
1822   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
1823
1824   /* The view only shows the root level, so the filter model only has
1825    * the first two levels cached.
1826    */
1827   filter_test_append_refilter_signals_with_vroot (fixture, 2, path);
1828   filter_test_enable_filter (fixture);
1829
1830   check_filter_model_with_root (fixture, path);
1831   check_level_length (fixture->filter, NULL, 1);
1832 }
1833
1834 static void
1835 unfiltered_vroot_show_single_child (FilterTest    *fixture,
1836                                     gconstpointer  user_data)
1837
1838 {
1839   GtkTreePath *path = (GtkTreePath *)user_data;
1840
1841   set_path_visibility (fixture, "2:2:2", TRUE);
1842
1843   signal_monitor_assert_is_empty (fixture->monitor);
1844   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
1845   check_level_length (fixture->filter, "2", LEVEL_LENGTH);
1846
1847   /* The view only shows the root level, so the filter model only has
1848    * the first two levels cached.
1849    */
1850   filter_test_append_refilter_signals_with_vroot (fixture, 2, path);
1851   filter_test_enable_filter (fixture);
1852
1853   check_filter_model_with_root (fixture, path);
1854   check_level_length (fixture->filter, NULL, 0);
1855
1856   /* From here we are filtered, "2" in the real model is "0" in the filter
1857    * model.
1858    */
1859   signal_monitor_append_signal (fixture->monitor, ROW_INSERTED, "0");
1860   signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "0");
1861   set_path_visibility (fixture, "2:2", TRUE);
1862   signal_monitor_assert_is_empty (fixture->monitor);
1863   check_level_length (fixture->filter, NULL, 1);
1864   check_level_length (fixture->filter, "0", 1);
1865 }
1866
1867 static void
1868 unfiltered_vroot_show_single_child_root_expanded (FilterTest    *fixture,
1869                                                   gconstpointer  user_data)
1870
1871 {
1872   GtkTreePath *path = (GtkTreePath *)user_data;
1873
1874   signal_monitor_append_signal (fixture->monitor, ROW_CHANGED, "2:2");
1875   signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "2:2");
1876   set_path_visibility (fixture, "2:2:2", TRUE);
1877
1878   signal_monitor_assert_is_empty (fixture->monitor);
1879   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
1880   check_level_length (fixture->filter, "2", LEVEL_LENGTH);
1881
1882   filter_test_append_refilter_signals_with_vroot (fixture, 3, path);
1883   filter_test_enable_filter (fixture);
1884
1885   check_filter_model_with_root (fixture, path);
1886   check_level_length (fixture->filter, NULL, 0);
1887
1888   /* From here we are filtered, "2" in the real model is "0" in the filter
1889    * model.
1890    */
1891   signal_monitor_append_signal (fixture->monitor, ROW_INSERTED, "0");
1892   signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "0");
1893   set_path_visibility (fixture, "2:2", TRUE);
1894   signal_monitor_assert_is_empty (fixture->monitor);
1895   check_level_length (fixture->filter, NULL, 1);
1896   check_level_length (fixture->filter, "0", 1);
1897 }
1898
1899
1900 static void
1901 unfiltered_vroot_show_single_multi_level (FilterTest    *fixture,
1902                                           gconstpointer  user_data)
1903
1904 {
1905   GtkTreePath *path = (GtkTreePath *)user_data;
1906
1907   /* The view is not showing this row (collapsed state), so it is not
1908    * referenced.  The signal should not go through.
1909    */
1910   set_path_visibility (fixture, "2:2:2:2", TRUE);
1911
1912   set_path_visibility (fixture, "2:2:2", TRUE);
1913
1914   signal_monitor_assert_is_empty (fixture->monitor);
1915   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
1916   check_level_length (fixture->filter, "2", LEVEL_LENGTH);
1917   check_level_length (fixture->filter, "2:2", LEVEL_LENGTH);
1918
1919   /* We only expect signals for the root level */
1920   filter_test_append_refilter_signals_with_vroot (fixture, 2, path);
1921   filter_test_enable_filter (fixture);
1922
1923   check_filter_model_with_root (fixture, path);
1924   check_level_length (fixture->filter, NULL, 0);
1925
1926   /* From here we are filtered, "2" in the real model is "0" in the filter
1927    * model.
1928    */
1929   signal_monitor_append_signal (fixture->monitor, ROW_INSERTED, "0");
1930   signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "0");
1931   set_path_visibility (fixture, "2:2", TRUE);
1932   check_filter_model_with_root (fixture, path);
1933   check_level_length (fixture->filter, NULL, 1);
1934   check_level_length (fixture->filter, "0", 1);
1935   check_level_length (fixture->filter, "0:0", 1);
1936 }
1937
1938 static void
1939 unfiltered_vroot_show_single_multi_level_root_expanded (FilterTest    *fixture,
1940                                                         gconstpointer  user_data)
1941
1942 {
1943   GtkTreePath *path = (GtkTreePath *)user_data;
1944
1945   /* The view is not showing this row (collapsed state), so it is not
1946    * referenced.  The signal should not go through.
1947    */
1948   set_path_visibility (fixture, "2:2:2:2", TRUE);
1949
1950   signal_monitor_append_signal (fixture->monitor, ROW_CHANGED, "2:2");
1951   signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "2:2");
1952   set_path_visibility (fixture, "2:2:2", TRUE);
1953
1954   signal_monitor_assert_is_empty (fixture->monitor);
1955   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
1956   check_level_length (fixture->filter, "2", LEVEL_LENGTH);
1957   check_level_length (fixture->filter, "2:2", LEVEL_LENGTH);
1958
1959   filter_test_append_refilter_signals_with_vroot (fixture, 3, path);
1960   filter_test_enable_filter (fixture);
1961
1962   check_filter_model_with_root (fixture, path);
1963   check_level_length (fixture->filter, NULL, 0);
1964
1965   /* From here we are filtered, "2" in the real model is "0" in the filter
1966    * model.
1967    */
1968   signal_monitor_append_signal (fixture->monitor, ROW_INSERTED, "0");
1969   signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "0");
1970   set_path_visibility (fixture, "2:2", TRUE);
1971   check_filter_model_with_root (fixture, path);
1972   check_level_length (fixture->filter, NULL, 1);
1973   check_level_length (fixture->filter, "0", 1);
1974   check_level_length (fixture->filter, "0:0", 1);
1975 }
1976
1977 static void
1978 unfiltered_rows_reordered_root_level (FilterTest    *fixture,
1979                                       gconstpointer  user_data)
1980 {
1981   int order0[] = { 1, 2, 3, 4, 0 };
1982   int order1[] = { 0, 2, 1, 3, 4 };
1983   int order2[] = { 4, 0, 1, 2, 3 };
1984   GtkTreeIter iter0, iter1, iter2, iter3, iter4;
1985   GtkTreePath *path;
1986
1987   gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL (fixture->store),
1988                                        &iter0, "0");
1989   gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL (fixture->store),
1990                                        &iter1, "1");
1991   gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL (fixture->store),
1992                                        &iter2, "2");
1993   gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL (fixture->store),
1994                                        &iter3, "3");
1995   gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL (fixture->store),
1996                                        &iter4, "4");
1997
1998   path = gtk_tree_path_new ();
1999   signal_monitor_append_signal_reordered (fixture->monitor,
2000                                           ROWS_REORDERED,
2001                                           path, order0, 5);
2002   gtk_tree_store_move_after (fixture->store, &iter0, &iter4);
2003   signal_monitor_assert_is_empty (fixture->monitor);
2004
2005   signal_monitor_append_signal_reordered (fixture->monitor,
2006                                           ROWS_REORDERED,
2007                                           path, order1, 5);
2008   gtk_tree_store_move_after (fixture->store, &iter2, &iter3);
2009   signal_monitor_assert_is_empty (fixture->monitor);
2010
2011   signal_monitor_append_signal_reordered (fixture->monitor,
2012                                           ROWS_REORDERED,
2013                                           path, order2, 5);
2014   gtk_tree_store_move_before (fixture->store, &iter0, &iter1);
2015   signal_monitor_assert_is_empty (fixture->monitor);
2016
2017   gtk_tree_path_free (path);
2018 }
2019
2020 static void
2021 unfiltered_rows_reordered_child_level (FilterTest    *fixture,
2022                                        gconstpointer  user_data)
2023 {
2024   int order0[] = { 1, 2, 3, 4, 0 };
2025   int order1[] = { 0, 2, 1, 3, 4 };
2026   int order2[] = { 4, 0, 1, 2, 3 };
2027   GtkTreeIter iter0, iter1, iter2, iter3, iter4;
2028   GtkTreePath *path;
2029
2030   /* Expand row 0 */
2031   path = gtk_tree_path_new_from_indices (0, -1);
2032   gtk_tree_view_expand_row (GTK_TREE_VIEW (fixture->tree_view), path, FALSE);
2033
2034   gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL (fixture->store),
2035                                        &iter0, "0:0");
2036   gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL (fixture->store),
2037                                        &iter1, "0:1");
2038   gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL (fixture->store),
2039                                        &iter2, "0:2");
2040   gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL (fixture->store),
2041                                        &iter3, "0:3");
2042   gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL (fixture->store),
2043                                        &iter4, "0:4");
2044
2045   signal_monitor_append_signal_reordered (fixture->monitor,
2046                                           ROWS_REORDERED,
2047                                           path, order0, 5);
2048   gtk_tree_store_move_after (fixture->store, &iter0, &iter4);
2049   signal_monitor_assert_is_empty (fixture->monitor);
2050
2051   signal_monitor_append_signal_reordered (fixture->monitor,
2052                                           ROWS_REORDERED,
2053                                           path, order1, 5);
2054   gtk_tree_store_move_after (fixture->store, &iter2, &iter3);
2055   signal_monitor_assert_is_empty (fixture->monitor);
2056
2057   signal_monitor_append_signal_reordered (fixture->monitor,
2058                                           ROWS_REORDERED,
2059                                           path, order2, 5);
2060   gtk_tree_store_move_before (fixture->store, &iter0, &iter1);
2061   signal_monitor_assert_is_empty (fixture->monitor);
2062
2063   gtk_tree_path_free (path);
2064 }
2065
2066 static void
2067 filtered_rows_reordered_root_level_first_hidden (FilterTest    *fixture,
2068                                                  gconstpointer  user_data)
2069 {
2070   int order0[] = { 1, 2, 3, 0 };
2071   int order1[] = { 0, 2, 1, 3 };
2072   int order2[] = { 3, 0, 1, 2 };
2073   GtkTreeIter iter1, iter2, iter3, iter4;
2074   GtkTreePath *path;
2075
2076   /* Hide middle path */
2077   signal_monitor_append_signal (fixture->monitor,
2078                                 ROW_DELETED, "0");
2079   set_path_visibility (fixture, "0", FALSE);
2080   signal_monitor_assert_is_empty (fixture->monitor);
2081
2082   gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL (fixture->store),
2083                                        &iter1, "1");
2084   gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL (fixture->store),
2085                                        &iter2, "2");
2086   gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL (fixture->store),
2087                                        &iter3, "3");
2088   gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL (fixture->store),
2089                                        &iter4, "4");
2090
2091   path = gtk_tree_path_new ();
2092   signal_monitor_append_signal_reordered (fixture->monitor,
2093                                           ROWS_REORDERED,
2094                                           path, order0, 4);
2095   gtk_tree_store_move_after (fixture->store, &iter1, &iter4);
2096   signal_monitor_assert_is_empty (fixture->monitor);
2097
2098   signal_monitor_append_signal_reordered (fixture->monitor,
2099                                           ROWS_REORDERED,
2100                                           path, order1, 4);
2101   gtk_tree_store_move_after (fixture->store, &iter3, &iter4);
2102   signal_monitor_assert_is_empty (fixture->monitor);
2103
2104   signal_monitor_append_signal_reordered (fixture->monitor,
2105                                           ROWS_REORDERED,
2106                                           path, order2, 4);
2107   gtk_tree_store_move_before (fixture->store, &iter1, &iter2);
2108   signal_monitor_assert_is_empty (fixture->monitor);
2109
2110   gtk_tree_path_free (path);
2111 }
2112
2113 static void
2114 filtered_rows_reordered_root_level_middle_hidden (FilterTest    *fixture,
2115                                                   gconstpointer  user_data)
2116 {
2117   int order0[] = { 1, 2, 3, 0 };
2118   int order1[] = { 0, 2, 1, 3 };
2119   int order2[] = { 3, 0, 1, 2 };
2120   GtkTreeIter iter0, iter1, iter3, iter4;
2121   GtkTreePath *path;
2122
2123   /* Hide middle path */
2124   signal_monitor_append_signal (fixture->monitor,
2125                                 ROW_DELETED, "2");
2126   set_path_visibility (fixture, "2", FALSE);
2127   signal_monitor_assert_is_empty (fixture->monitor);
2128
2129   gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL (fixture->store),
2130                                        &iter0, "0");
2131   gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL (fixture->store),
2132                                        &iter1, "1");
2133   gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL (fixture->store),
2134                                        &iter3, "3");
2135   gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL (fixture->store),
2136                                        &iter4, "4");
2137
2138   path = gtk_tree_path_new ();
2139   signal_monitor_append_signal_reordered (fixture->monitor,
2140                                           ROWS_REORDERED,
2141                                           path, order0, 4);
2142   gtk_tree_store_move_after (fixture->store, &iter0, &iter4);
2143   signal_monitor_assert_is_empty (fixture->monitor);
2144
2145   signal_monitor_append_signal_reordered (fixture->monitor,
2146                                           ROWS_REORDERED,
2147                                           path, order1, 4);
2148   gtk_tree_store_move_after (fixture->store, &iter3, &iter4);
2149   signal_monitor_assert_is_empty (fixture->monitor);
2150
2151   signal_monitor_append_signal_reordered (fixture->monitor,
2152                                           ROWS_REORDERED,
2153                                           path, order2, 4);
2154   gtk_tree_store_move_before (fixture->store, &iter0, &iter1);
2155   signal_monitor_assert_is_empty (fixture->monitor);
2156
2157   gtk_tree_path_free (path);
2158 }
2159
2160 static void
2161 filtered_rows_reordered_child_level_first_hidden (FilterTest    *fixture,
2162                                                   gconstpointer  user_data)
2163 {
2164   int order0[] = { 1, 2, 3, 0 };
2165   int order1[] = { 0, 2, 1, 3 };
2166   int order2[] = { 3, 0, 1, 2 };
2167   GtkTreeIter iter1, iter2, iter3, iter4;
2168   GtkTreePath *path;
2169
2170   /* Expand row 0 */
2171   path = gtk_tree_path_new_from_indices (0, -1);
2172   gtk_tree_view_expand_row (GTK_TREE_VIEW (fixture->tree_view), path, TRUE);
2173
2174   /* Hide middle path */
2175   signal_monitor_append_signal (fixture->monitor,
2176                                 ROW_DELETED, "0:0");
2177   set_path_visibility (fixture, "0:0", FALSE);
2178   signal_monitor_assert_is_empty (fixture->monitor);
2179
2180   gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL (fixture->store),
2181                                        &iter1, "0:1");
2182   gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL (fixture->store),
2183                                        &iter2, "0:2");
2184   gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL (fixture->store),
2185                                        &iter3, "0:3");
2186   gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL (fixture->store),
2187                                        &iter4, "0:4");
2188
2189   signal_monitor_append_signal_reordered (fixture->monitor,
2190                                           ROWS_REORDERED,
2191                                           path, order0, 4);
2192   gtk_tree_store_move_after (fixture->store, &iter1, &iter4);
2193   signal_monitor_assert_is_empty (fixture->monitor);
2194
2195   signal_monitor_append_signal_reordered (fixture->monitor,
2196                                           ROWS_REORDERED,
2197                                           path, order1, 4);
2198   gtk_tree_store_move_after (fixture->store, &iter3, &iter4);
2199   signal_monitor_assert_is_empty (fixture->monitor);
2200
2201   signal_monitor_append_signal_reordered (fixture->monitor,
2202                                           ROWS_REORDERED,
2203                                           path, order2, 4);
2204   gtk_tree_store_move_before (fixture->store, &iter1, &iter2);
2205   signal_monitor_assert_is_empty (fixture->monitor);
2206
2207   gtk_tree_path_free (path);
2208 }
2209
2210 static void
2211 filtered_rows_reordered_child_level_middle_hidden (FilterTest    *fixture,
2212                                                    gconstpointer  user_data)
2213 {
2214   int order0[] = { 1, 2, 3, 0 };
2215   int order1[] = { 0, 2, 1, 3 };
2216   int order2[] = { 3, 0, 1, 2 };
2217   GtkTreeIter iter0, iter1, iter3, iter4;
2218   GtkTreePath *path;
2219
2220   /* Expand row 0 */
2221   path = gtk_tree_path_new_from_indices (0, -1);
2222   gtk_tree_view_expand_row (GTK_TREE_VIEW (fixture->tree_view), path, FALSE);
2223
2224   /* Hide middle path */
2225   signal_monitor_append_signal (fixture->monitor,
2226                                 ROW_DELETED, "0:2");
2227   set_path_visibility (fixture, "0:2", FALSE);
2228   signal_monitor_assert_is_empty (fixture->monitor);
2229
2230   gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL (fixture->store),
2231                                        &iter0, "0:0");
2232   gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL (fixture->store),
2233                                        &iter1, "0:1");
2234   gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL (fixture->store),
2235                                        &iter3, "0:3");
2236   gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL (fixture->store),
2237                                        &iter4, "0:4");
2238
2239   signal_monitor_append_signal_reordered (fixture->monitor,
2240                                           ROWS_REORDERED,
2241                                           path, order0, 4);
2242   gtk_tree_store_move_after (fixture->store, &iter0, &iter4);
2243   signal_monitor_assert_is_empty (fixture->monitor);
2244
2245   signal_monitor_append_signal_reordered (fixture->monitor,
2246                                           ROWS_REORDERED,
2247                                           path, order1, 4);
2248   gtk_tree_store_move_after (fixture->store, &iter3, &iter4);
2249   signal_monitor_assert_is_empty (fixture->monitor);
2250
2251   signal_monitor_append_signal_reordered (fixture->monitor,
2252                                           ROWS_REORDERED,
2253                                           path, order2, 4);
2254   gtk_tree_store_move_before (fixture->store, &iter0, &iter1);
2255   signal_monitor_assert_is_empty (fixture->monitor);
2256
2257   gtk_tree_path_free (path);
2258 }
2259
2260 static void
2261 filtered_rows_reordered_child_level_4_hidden (FilterTest    *fixture,
2262                                               gconstpointer  user_data)
2263 {
2264   int order0[] = { 0 };
2265   GtkTreeIter iter1, iter4;
2266   GtkTreePath *path;
2267
2268   /* Expand row 0 */
2269   path = gtk_tree_path_new_from_indices (0, -1);
2270   gtk_tree_view_expand_row (GTK_TREE_VIEW (fixture->tree_view), path, FALSE);
2271
2272   /* Hide last 4 paths */
2273   signal_monitor_append_signal (fixture->monitor,
2274                                 ROW_DELETED, "0:4");
2275   signal_monitor_append_signal (fixture->monitor,
2276                                 ROW_DELETED, "0:3");
2277   signal_monitor_append_signal (fixture->monitor,
2278                                 ROW_DELETED, "0:2");
2279   signal_monitor_append_signal (fixture->monitor,
2280                                 ROW_DELETED, "0:0");
2281   set_path_visibility (fixture, "0:4", FALSE);
2282   set_path_visibility (fixture, "0:3", FALSE);
2283   set_path_visibility (fixture, "0:2", FALSE);
2284   set_path_visibility (fixture, "0:0", FALSE);
2285   signal_monitor_assert_is_empty (fixture->monitor);
2286
2287   gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL (fixture->store),
2288                                        &iter1, "0:1");
2289   gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL (fixture->store),
2290                                        &iter4, "0:4");
2291
2292   signal_monitor_append_signal_reordered (fixture->monitor,
2293                                           ROWS_REORDERED,
2294                                           path, order0, 1);
2295   gtk_tree_store_move_after (fixture->store, &iter1, &iter4);
2296   signal_monitor_assert_is_empty (fixture->monitor);
2297
2298   gtk_tree_path_free (path);
2299 }
2300
2301 static void
2302 filtered_rows_reordered_child_level_all_hidden (FilterTest    *fixture,
2303                                                 gconstpointer  user_data)
2304 {
2305   GtkTreeIter iter1, iter4;
2306   GtkTreePath *path;
2307
2308   /* Expand row 0 */
2309   path = gtk_tree_path_new_from_indices (0, -1);
2310   gtk_tree_view_expand_row (GTK_TREE_VIEW (fixture->tree_view), path, FALSE);
2311   gtk_tree_path_free (path);
2312
2313   /* Hide last 4 paths */
2314   signal_monitor_append_signal (fixture->monitor,
2315                                 ROW_DELETED, "0:4");
2316   signal_monitor_append_signal (fixture->monitor,
2317                                 ROW_DELETED, "0:3");
2318   signal_monitor_append_signal (fixture->monitor,
2319                                 ROW_DELETED, "0:2");
2320   signal_monitor_append_signal (fixture->monitor,
2321                                 ROW_DELETED, "0:1");
2322   signal_monitor_append_signal (fixture->monitor,
2323                                 ROW_DELETED, "0:0");
2324   signal_monitor_append_signal (fixture->monitor,
2325                                 ROW_HAS_CHILD_TOGGLED, "0");
2326   set_path_visibility (fixture, "0:4", FALSE);
2327   set_path_visibility (fixture, "0:3", FALSE);
2328   set_path_visibility (fixture, "0:2", FALSE);
2329   set_path_visibility (fixture, "0:1", FALSE);
2330   set_path_visibility (fixture, "0:0", FALSE);
2331   signal_monitor_assert_is_empty (fixture->monitor);
2332
2333   gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL (fixture->store),
2334                                        &iter1, "0:1");
2335   gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL (fixture->store),
2336                                        &iter4, "0:4");
2337
2338   gtk_tree_store_move_after (fixture->store, &iter1, &iter4);
2339   signal_monitor_assert_is_empty (fixture->monitor);
2340 }
2341
2342 static void
2343 insert_before (void)
2344 {
2345   GtkTreeStore *store;
2346   GtkTreeModel *filter;
2347   GtkWidget *tree_view;
2348   SignalMonitor *monitor;
2349   GtkTreeIter iter;
2350   GtkTreeIter last_iter;
2351   GtkTreePath *path;
2352
2353   /* This tests two aspects of the row-inserted handling:
2354    *   1) If the newly inserted node was already handled by building
2355    *      the root level, don't handle it a second time.
2356    *   2) Offsets of existing nodes must be updated when a new
2357    *      node is inserted.
2358    */
2359
2360   store = gtk_tree_store_new (2, G_TYPE_STRING, G_TYPE_BOOLEAN);
2361   filter = gtk_tree_model_filter_new (GTK_TREE_MODEL (store), NULL);
2362   gtk_tree_model_filter_set_visible_column (GTK_TREE_MODEL_FILTER (filter),
2363                                             1);
2364
2365   tree_view = gtk_tree_view_new_with_model (filter);
2366   monitor = signal_monitor_new (filter);
2367
2368   check_level_length (GTK_TREE_MODEL_FILTER (filter), NULL, 0);
2369
2370   /* Insert 0 */
2371   path = gtk_tree_path_new_from_indices (0, -1);
2372   signal_monitor_append_signal_path (monitor, ROW_INSERTED, path);
2373   gtk_tree_path_free (path);
2374
2375   gtk_tree_store_insert_with_values (store, &iter, NULL, 0,
2376                                      0, "Foo", 1, TRUE, -1);
2377
2378   signal_monitor_assert_is_empty (monitor);
2379   check_level_length (GTK_TREE_MODEL_FILTER (filter), NULL, 1);
2380
2381   /* Insert 1 */
2382   path = gtk_tree_path_new_from_indices (1, -1);
2383   signal_monitor_append_signal_path (monitor, ROW_INSERTED, path);
2384   gtk_tree_path_free (path);
2385
2386   gtk_tree_store_insert_with_values (store, &iter, NULL, 1,
2387                                      0, "Foo", 1, TRUE, -1);
2388   last_iter = iter;
2389
2390   signal_monitor_assert_is_empty (monitor);
2391   check_level_length (GTK_TREE_MODEL_FILTER (filter), NULL, 2);
2392
2393   /* Insert on 1 again -- invisible */
2394   gtk_tree_store_insert_with_values (store, &iter, NULL, 1,
2395                                      0, "Foo", 1, FALSE, -1);
2396
2397   signal_monitor_assert_is_empty (monitor);
2398   check_level_length (GTK_TREE_MODEL_FILTER (filter), NULL, 2);
2399
2400   /* Insert on 1 again -- visible */
2401   path = gtk_tree_path_new_from_indices (1, -1);
2402   signal_monitor_append_signal_path (monitor, ROW_INSERTED, path);
2403   gtk_tree_path_free (path);
2404
2405   gtk_tree_store_insert_with_values (store, &iter, NULL, 1,
2406                                      0, "Foo", 1, TRUE, -1);
2407
2408   signal_monitor_assert_is_empty (monitor);
2409   check_level_length (GTK_TREE_MODEL_FILTER (filter), NULL, 3);
2410
2411   /* Modify the iter that should be at the last position and check the
2412    * signal we get.
2413    */
2414   path = gtk_tree_path_new_from_indices (2, -1);
2415   signal_monitor_append_signal_path (monitor, ROW_CHANGED, path);
2416   gtk_tree_path_free (path);
2417
2418   gtk_tree_store_set (store, &last_iter, 0, "Foo changed", -1);
2419
2420   signal_monitor_assert_is_empty (monitor);
2421   check_level_length (GTK_TREE_MODEL_FILTER (filter), NULL, 3);
2422 }
2423
2424 static void
2425 insert_child (void)
2426 {
2427   GtkTreeStore *store;
2428   GtkTreeModel *filter;
2429   GtkWidget *tree_view;
2430   SignalMonitor *monitor;
2431   GtkTreeIter parent, iter;
2432   GtkTreePath *path;
2433
2434   store = gtk_tree_store_new (2, G_TYPE_STRING, G_TYPE_BOOLEAN);
2435
2436   gtk_tree_store_insert_with_values (store, &parent, NULL, 0,
2437                                      0, "Parent", 1, TRUE, -1);
2438
2439
2440   filter = gtk_tree_model_filter_new (GTK_TREE_MODEL (store), NULL);
2441   gtk_tree_model_filter_set_visible_column (GTK_TREE_MODEL_FILTER (filter),
2442                                             1);
2443
2444   tree_view = gtk_tree_view_new_with_model (filter);
2445   monitor = signal_monitor_new (filter);
2446
2447   /* Insert child -- invisible */
2448   path = gtk_tree_path_new_from_indices (0, -1);
2449   signal_monitor_append_signal_path (monitor, ROW_HAS_CHILD_TOGGLED, path);
2450   /* The signal is received twice, once a pass through from GtkTreeStore
2451    * and one generated by GtkTreeModelFilter.  Not accurate, but cannot
2452    * hurt.
2453    */
2454   signal_monitor_append_signal_path (monitor, ROW_HAS_CHILD_TOGGLED, path);
2455   gtk_tree_path_free (path);
2456
2457   gtk_tree_store_insert_with_values (store, &iter, &parent, 1,
2458                                      0, "Child", 1, FALSE, -1);
2459
2460   signal_monitor_assert_is_empty (monitor);
2461   check_level_length (GTK_TREE_MODEL_FILTER (filter), NULL, 1);
2462
2463   /* Insert child */
2464   path = gtk_tree_path_new_from_indices (0, 0, -1);
2465   gtk_tree_path_up (path); /* 0 */
2466   signal_monitor_append_signal_path (monitor, ROW_HAS_CHILD_TOGGLED, path);
2467   gtk_tree_path_free (path);
2468
2469   gtk_tree_store_insert_with_values (store, &iter, &parent, 0,
2470                                      0, "Child", 1, TRUE, -1);
2471
2472   signal_monitor_assert_is_empty (monitor);
2473   check_level_length (GTK_TREE_MODEL_FILTER (filter), NULL, 1);
2474
2475   /* Insert child -- invisible */
2476   gtk_tree_store_insert_with_values (store, &iter, &parent, 1,
2477                                      0, "Child", 1, FALSE, -1);
2478
2479   signal_monitor_assert_is_empty (monitor);
2480   check_level_length (GTK_TREE_MODEL_FILTER (filter), NULL, 1);
2481 }
2482
2483
2484
2485 static void
2486 remove_node (void)
2487 {
2488   GtkTreeIter iter, iter1, iter2, iter3;
2489   GtkListStore *list;
2490   GtkTreeModel *filter;
2491   GtkWidget *view G_GNUC_UNUSED;
2492
2493   list = gtk_list_store_new (1, G_TYPE_INT);
2494   gtk_list_store_insert_with_values (list, &iter1, 0, 0, 1, -1);
2495   gtk_list_store_insert_with_values (list, &iter, 1, 0, 2, -1);
2496   gtk_list_store_insert_with_values (list, &iter, 2, 0, 3, -1);
2497   gtk_list_store_insert_with_values (list, &iter, 3, 0, 4, -1);
2498   gtk_list_store_insert_with_values (list, &iter, 4, 0, 5, -1);
2499   gtk_list_store_insert_with_values (list, &iter, 5, 0, 6, -1);
2500   gtk_list_store_insert_with_values (list, &iter2, 6, 0, 7, -1);
2501   gtk_list_store_insert_with_values (list, &iter3, 7, 0, 8, -1);
2502
2503   filter = gtk_tree_model_filter_new (GTK_TREE_MODEL (list), NULL);
2504   view = gtk_tree_view_new_with_model (filter);
2505
2506   gtk_list_store_remove (list, &iter1);
2507   gtk_list_store_remove (list, &iter3);
2508   gtk_list_store_remove (list, &iter2);
2509
2510   gtk_widget_destroy (view);
2511   g_object_unref (filter);
2512   g_object_unref (list);
2513 }
2514
2515 static void
2516 remove_node_vroot (void)
2517 {
2518   GtkTreeIter parent, root;
2519   GtkTreeIter iter, iter1, iter2, iter3;
2520   GtkTreeStore *tree;
2521   GtkTreeModel *filter;
2522   GtkTreePath *path;
2523   GtkWidget *view G_GNUC_UNUSED;
2524
2525   tree = gtk_tree_store_new (1, G_TYPE_INT);
2526   gtk_tree_store_insert_with_values (tree, &parent, NULL, 0, 0, 0, -1);
2527   gtk_tree_store_insert_with_values (tree, &root, &parent, 0, 0, 0, -1);
2528
2529   gtk_tree_store_insert_with_values (tree, &iter1, &root, 0, 0, 1, -1);
2530   gtk_tree_store_insert_with_values (tree, &iter, &root, 1, 0, 2, -1);
2531   gtk_tree_store_insert_with_values (tree, &iter, &root, 2, 0, 3, -1);
2532   gtk_tree_store_insert_with_values (tree, &iter, &root, 3, 0, 4, -1);
2533   gtk_tree_store_insert_with_values (tree, &iter, &root, 4, 0, 5, -1);
2534   gtk_tree_store_insert_with_values (tree, &iter, &root, 5, 0, 6, -1);
2535   gtk_tree_store_insert_with_values (tree, &iter2, &root, 6, 0, 7, -1);
2536   gtk_tree_store_insert_with_values (tree, &iter3, &root, 7, 0, 8, -1);
2537
2538   path = gtk_tree_path_new_from_indices (0, 0, -1);
2539   filter = gtk_tree_model_filter_new (GTK_TREE_MODEL (tree), path);
2540   gtk_tree_path_free (path);
2541
2542   view = gtk_tree_view_new_with_model (filter);
2543
2544   gtk_tree_store_remove (tree, &iter1);
2545   gtk_tree_store_remove (tree, &iter3);
2546   gtk_tree_store_remove (tree, &iter2);
2547
2548   gtk_widget_destroy (view);
2549   g_object_unref (filter);
2550   g_object_unref (tree);
2551 }
2552
2553 static void
2554 remove_vroot_ancestor (void)
2555 {
2556   GtkTreeIter parent, root;
2557   GtkTreeIter iter, iter1, iter2, iter3;
2558   GtkTreeStore *tree;
2559   GtkTreeModel *filter;
2560   GtkTreePath *path;
2561   GtkWidget *view G_GNUC_UNUSED;
2562
2563   tree = gtk_tree_store_new (1, G_TYPE_INT);
2564   gtk_tree_store_insert_with_values (tree, &parent, NULL, 0, 0, 0, -1);
2565   gtk_tree_store_insert_with_values (tree, &root, &parent, 0, 0, 0, -1);
2566
2567   gtk_tree_store_insert_with_values (tree, &iter1, &root, 0, 0, 1, -1);
2568   gtk_tree_store_insert_with_values (tree, &iter, &root, 1, 0, 2, -1);
2569   gtk_tree_store_insert_with_values (tree, &iter, &root, 2, 0, 3, -1);
2570   gtk_tree_store_insert_with_values (tree, &iter, &root, 3, 0, 4, -1);
2571   gtk_tree_store_insert_with_values (tree, &iter, &root, 4, 0, 5, -1);
2572   gtk_tree_store_insert_with_values (tree, &iter, &root, 5, 0, 6, -1);
2573   gtk_tree_store_insert_with_values (tree, &iter2, &root, 6, 0, 7, -1);
2574   gtk_tree_store_insert_with_values (tree, &iter3, &root, 7, 0, 8, -1);
2575
2576   path = gtk_tree_path_new_from_indices (0, 0, -1);
2577   filter = gtk_tree_model_filter_new (GTK_TREE_MODEL (tree), path);
2578   gtk_tree_path_free (path);
2579
2580   view = gtk_tree_view_new_with_model (filter);
2581
2582   gtk_tree_store_remove (tree, &parent);
2583
2584   gtk_widget_destroy (view);
2585   g_object_unref (filter);
2586   g_object_unref (tree);
2587 }
2588
2589 static void
2590 ref_count_single_level (void)
2591 {
2592   GtkTreeIter iter[5];
2593   GtkTreeModel *model;
2594   GtkTreeModelRefCount *ref_model;
2595   GtkTreeModel *filter_model;
2596   GtkWidget *tree_view;
2597
2598   model = gtk_tree_model_ref_count_new ();
2599   ref_model = GTK_TREE_MODEL_REF_COUNT (model);
2600
2601   gtk_tree_store_append (GTK_TREE_STORE (model), &iter[0], NULL);
2602   gtk_tree_store_append (GTK_TREE_STORE (model), &iter[1], NULL);
2603   gtk_tree_store_append (GTK_TREE_STORE (model), &iter[2], NULL);
2604   gtk_tree_store_append (GTK_TREE_STORE (model), &iter[3], NULL);
2605   gtk_tree_store_append (GTK_TREE_STORE (model), &iter[4], NULL);
2606
2607   assert_root_level_unreferenced (ref_model);
2608
2609   filter_model = gtk_tree_model_filter_new (model, NULL);
2610   tree_view = gtk_tree_view_new_with_model (filter_model);
2611
2612   assert_node_ref_count (ref_model, &iter[0], 2);
2613   assert_node_ref_count (ref_model, &iter[1], 1);
2614   assert_node_ref_count (ref_model, &iter[2], 1);
2615   assert_node_ref_count (ref_model, &iter[3], 1);
2616   assert_node_ref_count (ref_model, &iter[4], 1);
2617
2618   gtk_widget_destroy (tree_view);
2619
2620   assert_node_ref_count (ref_model, &iter[0], 1);
2621   assert_node_ref_count (ref_model, &iter[1], 0);
2622   assert_node_ref_count (ref_model, &iter[2], 0);
2623   assert_node_ref_count (ref_model, &iter[3], 0);
2624   assert_node_ref_count (ref_model, &iter[4], 0);
2625
2626   g_object_unref (filter_model);
2627
2628   assert_node_ref_count (ref_model, &iter[0], 0);
2629
2630   g_object_unref (ref_model);
2631 }
2632
2633 static void
2634 ref_count_two_levels (void)
2635 {
2636   GtkTreeIter parent1, parent2, iter, iter_first;
2637   GtkTreeModel *model;
2638   GtkTreeModelRefCount *ref_model;
2639   GtkTreeModel *filter_model;
2640   GtkWidget *tree_view;
2641
2642   model = gtk_tree_model_ref_count_new ();
2643   ref_model = GTK_TREE_MODEL_REF_COUNT (model);
2644
2645   gtk_tree_store_append (GTK_TREE_STORE (model), &parent1, NULL);
2646   gtk_tree_store_append (GTK_TREE_STORE (model), &parent2, NULL);
2647   gtk_tree_store_append (GTK_TREE_STORE (model), &iter_first, &parent2);
2648   gtk_tree_store_append (GTK_TREE_STORE (model), &iter, &parent2);
2649   gtk_tree_store_append (GTK_TREE_STORE (model), &iter, &parent2);
2650
2651   assert_entire_model_unreferenced (ref_model);
2652
2653   filter_model = gtk_tree_model_filter_new (model, NULL);
2654   tree_view = gtk_tree_view_new_with_model (filter_model);
2655
2656   /* This is quite confusing:
2657    *  - node 0 has a ref count of 2 because it is referenced as the
2658    *    first node in a level and by the tree view.
2659    *  - node 1 has a ref count of 2 because it is referenced by its
2660    *    child level and by the tree view.
2661    */
2662   assert_root_level_referenced (ref_model, 2);
2663   assert_node_ref_count (ref_model, &iter_first, 1);
2664   assert_node_ref_count (ref_model, &iter, 0);
2665
2666   gtk_tree_view_expand_all (GTK_TREE_VIEW (tree_view));
2667
2668   assert_node_ref_count (ref_model, &parent1, 2);
2669   assert_node_ref_count (ref_model, &parent2, 2);
2670   assert_node_ref_count (ref_model, &iter_first, 2);
2671   assert_node_ref_count (ref_model, &iter, 1);
2672
2673   gtk_tree_view_collapse_all (GTK_TREE_VIEW (tree_view));
2674
2675   /* The child level is not destroyed because its parent is visible */
2676   assert_node_ref_count (ref_model, &parent1, 2);
2677   assert_node_ref_count (ref_model, &parent2, 2);
2678   assert_node_ref_count (ref_model, &iter_first, 1);
2679   assert_node_ref_count (ref_model, &iter, 0);
2680
2681   gtk_tree_model_filter_clear_cache (GTK_TREE_MODEL_FILTER (filter_model));
2682
2683   assert_node_ref_count (ref_model, &parent1, 2);
2684   assert_node_ref_count (ref_model, &parent2, 2);
2685   assert_node_ref_count (ref_model, &iter_first, 1);
2686   assert_node_ref_count (ref_model, &iter, 0);
2687
2688   gtk_widget_destroy (tree_view);
2689
2690   assert_root_level_referenced (ref_model, 1);
2691   assert_node_ref_count (ref_model, &iter_first, 1);
2692   assert_node_ref_count (ref_model, &iter, 0);
2693
2694   gtk_tree_model_filter_clear_cache (GTK_TREE_MODEL_FILTER (filter_model));
2695
2696   /* The root level and first level remain cached, only the references on the
2697    * first nodes of these levels are kept.
2698    */
2699   assert_node_ref_count (ref_model, &parent1, 1);
2700   assert_node_ref_count (ref_model, &parent2, 1);
2701   assert_node_ref_count (ref_model, &iter_first, 1);
2702   assert_node_ref_count (ref_model, &iter, 0);
2703
2704   g_object_unref (filter_model);
2705   g_object_unref (ref_model);
2706 }
2707
2708 static void
2709 ref_count_three_levels (void)
2710 {
2711   GtkTreeIter grandparent1, grandparent2, parent1, parent2;
2712   GtkTreeIter iter_parent1, iter_parent2, iter_parent2_first;
2713   GtkTreeModel *model;
2714   GtkTreeModelRefCount *ref_model;
2715   GtkTreeModel *filter_model;
2716   GtkTreePath *path;
2717   GtkWidget *tree_view;
2718
2719   model = gtk_tree_model_ref_count_new ();
2720   ref_model = GTK_TREE_MODEL_REF_COUNT (model);
2721
2722   /* + grandparent1
2723    * + grandparent2
2724    *   + parent1
2725    *     + iter_parent1
2726    *   + parent2
2727    *     + iter_parent2_first
2728    *     + iter_parent2
2729    */
2730
2731   gtk_tree_store_append (GTK_TREE_STORE (model), &grandparent1, NULL);
2732   gtk_tree_store_append (GTK_TREE_STORE (model), &grandparent2, NULL);
2733   gtk_tree_store_append (GTK_TREE_STORE (model), &parent1, &grandparent2);
2734   gtk_tree_store_append (GTK_TREE_STORE (model), &iter_parent1, &parent1);
2735   gtk_tree_store_append (GTK_TREE_STORE (model), &parent2, &grandparent2);
2736   gtk_tree_store_append (GTK_TREE_STORE (model), &iter_parent2_first, &parent2);
2737   gtk_tree_store_append (GTK_TREE_STORE (model), &iter_parent2, &parent2);
2738
2739   assert_entire_model_unreferenced (ref_model);
2740
2741   filter_model = gtk_tree_model_filter_new (model, NULL);
2742   tree_view = gtk_tree_view_new_with_model (filter_model);
2743
2744   /* This is quite confusing:
2745    *  - node 0 has a ref count of 2 because it is referenced as the
2746    *    first node in a level and by the tree view.
2747    *  - node 1 has a ref count of 2 because it is referenced by its
2748    *    child level and by the tree view.
2749    */
2750   assert_root_level_referenced (ref_model, 2);
2751   assert_node_ref_count (ref_model, &parent1, 1);
2752   assert_node_ref_count (ref_model, &parent2, 0);
2753   assert_level_unreferenced (ref_model, &parent1);
2754   assert_level_unreferenced (ref_model, &parent2);
2755
2756   path = gtk_tree_path_new_from_indices (1, -1);
2757   gtk_tree_view_expand_row (GTK_TREE_VIEW (tree_view), path, FALSE);
2758
2759   assert_node_ref_count (ref_model, &grandparent1, 2);
2760   assert_node_ref_count (ref_model, &grandparent2, 2);
2761   assert_node_ref_count (ref_model, &parent1, 3);
2762   assert_node_ref_count (ref_model, &parent2, 2);
2763   assert_node_ref_count (ref_model, &iter_parent1, 1);
2764   assert_node_ref_count (ref_model, &iter_parent2_first, 1);
2765   assert_node_ref_count (ref_model, &iter_parent2, 0);
2766
2767   gtk_tree_view_expand_row (GTK_TREE_VIEW (tree_view), path, TRUE);
2768
2769   assert_node_ref_count (ref_model, &grandparent1, 2);
2770   assert_node_ref_count (ref_model, &grandparent2, 2);
2771   assert_node_ref_count (ref_model, &parent1, 3);
2772   assert_node_ref_count (ref_model, &parent2, 2);
2773   assert_node_ref_count (ref_model, &iter_parent1, 2);
2774   assert_node_ref_count (ref_model, &iter_parent2_first, 2);
2775   assert_node_ref_count (ref_model, &iter_parent2, 1);
2776
2777   gtk_tree_view_collapse_all (GTK_TREE_VIEW (tree_view));
2778
2779   assert_node_ref_count (ref_model, &grandparent1, 2);
2780   assert_node_ref_count (ref_model, &grandparent2, 2);
2781   assert_node_ref_count (ref_model, &parent1, 2);
2782   assert_node_ref_count (ref_model, &parent2, 1);
2783   assert_node_ref_count (ref_model, &iter_parent1, 1);
2784   assert_node_ref_count (ref_model, &iter_parent2_first, 1);
2785   assert_node_ref_count (ref_model, &iter_parent2, 0);
2786
2787   gtk_tree_model_filter_clear_cache (GTK_TREE_MODEL_FILTER (filter_model));
2788
2789   assert_node_ref_count (ref_model, &grandparent1, 2);
2790   assert_node_ref_count (ref_model, &grandparent2, 2);
2791   assert_node_ref_count (ref_model, &parent1, 1);
2792   assert_node_ref_count (ref_model, &parent2, 0);
2793   assert_node_ref_count (ref_model, &iter_parent1, 0);
2794   assert_node_ref_count (ref_model, &iter_parent2_first, 0);
2795   assert_node_ref_count (ref_model, &iter_parent2, 0);
2796
2797   gtk_tree_view_expand_row (GTK_TREE_VIEW (tree_view), path, FALSE);
2798
2799   assert_node_ref_count (ref_model, &grandparent1, 2);
2800   assert_node_ref_count (ref_model, &grandparent2, 2);
2801   assert_node_ref_count (ref_model, &parent1, 3);
2802   assert_node_ref_count (ref_model, &parent2, 2);
2803   assert_node_ref_count (ref_model, &iter_parent1, 1);
2804   assert_node_ref_count (ref_model, &iter_parent2_first, 1);
2805   assert_node_ref_count (ref_model, &iter_parent2, 0);
2806
2807   gtk_tree_path_append_index (path, 1);
2808   gtk_tree_view_expand_row (GTK_TREE_VIEW (tree_view), path, FALSE);
2809
2810   assert_node_ref_count (ref_model, &grandparent1, 2);
2811   assert_node_ref_count (ref_model, &grandparent2, 2);
2812   assert_node_ref_count (ref_model, &parent1, 3);
2813   assert_node_ref_count (ref_model, &parent2, 2);
2814   assert_node_ref_count (ref_model, &iter_parent1, 1);
2815   assert_node_ref_count (ref_model, &iter_parent2_first, 2);
2816   assert_node_ref_count (ref_model, &iter_parent2, 1);
2817
2818   gtk_tree_view_collapse_row (GTK_TREE_VIEW (tree_view), path);
2819
2820   assert_node_ref_count (ref_model, &grandparent1, 2);
2821   assert_node_ref_count (ref_model, &grandparent2, 2);
2822   assert_node_ref_count (ref_model, &parent1, 3);
2823   assert_node_ref_count (ref_model, &parent2, 2);
2824   assert_node_ref_count (ref_model, &iter_parent1, 1);
2825   assert_node_ref_count (ref_model, &iter_parent2_first, 1);
2826   assert_node_ref_count (ref_model, &iter_parent2, 0);
2827
2828   gtk_tree_model_filter_clear_cache (GTK_TREE_MODEL_FILTER (filter_model));
2829
2830   assert_node_ref_count (ref_model, &grandparent1, 2);
2831   assert_node_ref_count (ref_model, &grandparent2, 2);
2832   assert_node_ref_count (ref_model, &parent1, 3);
2833   assert_node_ref_count (ref_model, &parent2, 2);
2834   assert_node_ref_count (ref_model, &iter_parent1, 1);
2835   assert_node_ref_count (ref_model, &iter_parent2_first, 1);
2836   assert_node_ref_count (ref_model, &iter_parent2, 0);
2837
2838   gtk_tree_path_up (path);
2839   gtk_tree_view_collapse_row (GTK_TREE_VIEW (tree_view), path);
2840   gtk_tree_path_free (path);
2841
2842   assert_node_ref_count (ref_model, &grandparent1, 2);
2843   assert_node_ref_count (ref_model, &grandparent2, 2);
2844   assert_node_ref_count (ref_model, &parent1, 2);
2845   assert_node_ref_count (ref_model, &parent2, 1);
2846   assert_node_ref_count (ref_model, &iter_parent1, 1);
2847   assert_node_ref_count (ref_model, &iter_parent2_first, 1);
2848   assert_node_ref_count (ref_model, &iter_parent2, 0);
2849
2850   gtk_tree_model_filter_clear_cache (GTK_TREE_MODEL_FILTER (filter_model));
2851
2852   assert_node_ref_count (ref_model, &grandparent1, 2);
2853   assert_node_ref_count (ref_model, &grandparent2, 2);
2854   assert_node_ref_count (ref_model, &parent1, 1);
2855   assert_node_ref_count (ref_model, &parent2, 0);
2856   assert_node_ref_count (ref_model, &iter_parent1, 0);
2857   assert_node_ref_count (ref_model, &iter_parent2_first, 0);
2858   assert_node_ref_count (ref_model, &iter_parent2, 0);
2859
2860   gtk_widget_destroy (tree_view);
2861
2862   gtk_tree_model_filter_clear_cache (GTK_TREE_MODEL_FILTER (filter_model));
2863
2864   /* The root level and first level remain cached, only the references on the
2865    * first nodes of these levels are kept.  Grandparent2 is the parent
2866    * of the first level with parent1, so grandparent2 keeps a reference
2867    * as well.
2868    */
2869   assert_node_ref_count (ref_model, &grandparent1, 1);
2870   assert_node_ref_count (ref_model, &grandparent2, 1);
2871   assert_node_ref_count (ref_model, &parent1, 1);
2872   assert_node_ref_count (ref_model, &parent2, 0);
2873   assert_node_ref_count (ref_model, &iter_parent1, 0);
2874   assert_node_ref_count (ref_model, &iter_parent2_first, 0);
2875   assert_node_ref_count (ref_model, &iter_parent2, 0);
2876
2877   g_object_unref (filter_model);
2878   g_object_unref (ref_model);
2879 }
2880
2881 static void
2882 ref_count_delete_row (void)
2883 {
2884   GtkTreeIter grandparent1, grandparent2, parent1, parent2;
2885   GtkTreeIter iter_parent1, iter_parent2, iter_parent2_first;
2886   GtkTreeModel *model;
2887   GtkTreeModelRefCount *ref_model;
2888   GtkTreeModel *filter_model;
2889   GtkTreePath *path;
2890   GtkWidget *tree_view;
2891
2892   model = gtk_tree_model_ref_count_new ();
2893   ref_model = GTK_TREE_MODEL_REF_COUNT (model);
2894
2895   /* + grandparent1
2896    * + grandparent2
2897    *   + parent1
2898    *     + iter_parent1
2899    *   + parent2
2900    *     + iter_parent2_first
2901    *     + iter_parent2
2902    */
2903
2904   gtk_tree_store_append (GTK_TREE_STORE (model), &grandparent1, NULL);
2905   gtk_tree_store_append (GTK_TREE_STORE (model), &grandparent2, NULL);
2906   gtk_tree_store_append (GTK_TREE_STORE (model), &parent1, &grandparent2);
2907   gtk_tree_store_append (GTK_TREE_STORE (model), &iter_parent1, &parent1);
2908   gtk_tree_store_append (GTK_TREE_STORE (model), &parent2, &grandparent2);
2909   gtk_tree_store_append (GTK_TREE_STORE (model), &iter_parent2_first, &parent2);
2910   gtk_tree_store_append (GTK_TREE_STORE (model), &iter_parent2, &parent2);
2911
2912   assert_entire_model_unreferenced (ref_model);
2913
2914   filter_model = gtk_tree_model_filter_new (model, NULL);
2915   tree_view = gtk_tree_view_new_with_model (filter_model);
2916
2917   assert_root_level_referenced (ref_model, 2);
2918   assert_node_ref_count (ref_model, &parent1, 1);
2919   assert_node_ref_count (ref_model, &parent2, 0);
2920   assert_level_unreferenced (ref_model, &parent1);
2921   assert_level_unreferenced (ref_model, &parent2);
2922
2923   path = gtk_tree_path_new_from_indices (1, -1);
2924   gtk_tree_view_expand_row (GTK_TREE_VIEW (tree_view), path, TRUE);
2925   gtk_tree_path_free (path);
2926
2927   assert_node_ref_count (ref_model, &grandparent1, 2);
2928   assert_node_ref_count (ref_model, &grandparent2, 2);
2929   assert_node_ref_count (ref_model, &parent1, 3);
2930   assert_node_ref_count (ref_model, &parent2, 2);
2931   assert_node_ref_count (ref_model, &iter_parent1, 2);
2932   assert_node_ref_count (ref_model, &iter_parent2_first, 2);
2933   assert_node_ref_count (ref_model, &iter_parent2, 1);
2934
2935   gtk_tree_store_remove (GTK_TREE_STORE (model), &iter_parent2);
2936
2937   assert_node_ref_count (ref_model, &grandparent1, 2);
2938   assert_node_ref_count (ref_model, &grandparent2, 2);
2939   assert_node_ref_count (ref_model, &parent1, 3);
2940   assert_node_ref_count (ref_model, &parent2, 2);
2941   assert_node_ref_count (ref_model, &iter_parent1, 2);
2942   assert_node_ref_count (ref_model, &iter_parent2_first, 2);
2943
2944   gtk_tree_store_remove (GTK_TREE_STORE (model), &parent1);
2945
2946   assert_node_ref_count (ref_model, &grandparent1, 2);
2947   assert_node_ref_count (ref_model, &grandparent2, 2);
2948   assert_node_ref_count (ref_model, &parent2, 3);
2949   assert_level_referenced (ref_model, 2, &parent2);
2950
2951   gtk_tree_store_remove (GTK_TREE_STORE (model), &grandparent2);
2952
2953   assert_node_ref_count (ref_model, &grandparent1, 2);
2954
2955   gtk_tree_model_filter_clear_cache (GTK_TREE_MODEL_FILTER (filter_model));
2956
2957   assert_node_ref_count (ref_model, &grandparent1, 2);
2958
2959   gtk_widget_destroy (tree_view);
2960   gtk_tree_model_filter_clear_cache (GTK_TREE_MODEL_FILTER (filter_model));
2961
2962   assert_node_ref_count (ref_model, &grandparent1, 1);
2963
2964   g_object_unref (filter_model);
2965
2966   assert_node_ref_count (ref_model, &grandparent1, 0);
2967
2968   g_object_unref (ref_model);
2969 }
2970
2971 static void
2972 ref_count_cleanup (void)
2973 {
2974   GtkTreeIter grandparent1, grandparent2, parent1, parent2;
2975   GtkTreeIter iter_parent1, iter_parent2, iter_parent2_first;
2976   GtkTreeModel *model;
2977   GtkTreeModelRefCount *ref_model;
2978   GtkTreeModel *filter_model;
2979   GtkWidget *tree_view;
2980
2981   model = gtk_tree_model_ref_count_new ();
2982   ref_model = GTK_TREE_MODEL_REF_COUNT (model);
2983
2984   /* + grandparent1
2985    * + grandparent2
2986    *   + parent1
2987    *     + iter_parent1
2988    *   + parent2
2989    *     + iter_parent2_first
2990    *     + iter_parent2
2991    */
2992
2993   gtk_tree_store_append (GTK_TREE_STORE (model), &grandparent1, NULL);
2994   gtk_tree_store_append (GTK_TREE_STORE (model), &grandparent2, NULL);
2995   gtk_tree_store_append (GTK_TREE_STORE (model), &parent1, &grandparent2);
2996   gtk_tree_store_append (GTK_TREE_STORE (model), &iter_parent1, &parent1);
2997   gtk_tree_store_append (GTK_TREE_STORE (model), &parent2, &grandparent2);
2998   gtk_tree_store_append (GTK_TREE_STORE (model), &iter_parent2_first, &parent2);
2999   gtk_tree_store_append (GTK_TREE_STORE (model), &iter_parent2, &parent2);
3000
3001   filter_model = gtk_tree_model_filter_new (model, NULL);
3002   tree_view = gtk_tree_view_new_with_model (filter_model);
3003
3004   gtk_tree_view_expand_all (GTK_TREE_VIEW (tree_view));
3005
3006   assert_node_ref_count (ref_model, &grandparent1, 2);
3007   assert_node_ref_count (ref_model, &grandparent2, 2);
3008   assert_node_ref_count (ref_model, &parent1, 3);
3009   assert_node_ref_count (ref_model, &parent2, 2);
3010   assert_node_ref_count (ref_model, &iter_parent1, 2);
3011   assert_node_ref_count (ref_model, &iter_parent2_first, 2);
3012   assert_node_ref_count (ref_model, &iter_parent2, 1);
3013
3014   gtk_widget_destroy (tree_view);
3015
3016   assert_node_ref_count (ref_model, &grandparent1, 1);
3017   assert_node_ref_count (ref_model, &grandparent2, 1);
3018   assert_node_ref_count (ref_model, &parent1, 2);
3019   assert_node_ref_count (ref_model, &parent2, 1);
3020   assert_node_ref_count (ref_model, &iter_parent1, 1);
3021   assert_node_ref_count (ref_model, &iter_parent2_first, 1);
3022   assert_node_ref_count (ref_model, &iter_parent2, 0);
3023
3024   gtk_tree_model_filter_clear_cache (GTK_TREE_MODEL_FILTER (filter_model));
3025
3026   /* The root level and first level remain cached, only the references on the
3027    * first nodes of these levels are kept.  Grandparent2 is the parent
3028    * of the first level with parent1, so grandparent2 keeps a reference
3029    * as well.
3030    */
3031   assert_node_ref_count (ref_model, &grandparent1, 1);
3032   assert_node_ref_count (ref_model, &grandparent2, 1);
3033   assert_node_ref_count (ref_model, &parent1, 1);
3034   assert_node_ref_count (ref_model, &parent2, 0);
3035   assert_node_ref_count (ref_model, &iter_parent1, 0);
3036   assert_node_ref_count (ref_model, &iter_parent2_first, 0);
3037   assert_node_ref_count (ref_model, &iter_parent2, 0);
3038
3039   g_object_unref (filter_model);
3040   g_object_unref (ref_model);
3041 }
3042
3043 static void
3044 ref_count_row_ref (void)
3045 {
3046   GtkTreeIter grandparent1, grandparent2, parent1, parent2;
3047   GtkTreeIter iter_parent1, iter_parent2, iter_parent2_first;
3048   GtkTreeModel *model;
3049   GtkTreeModelRefCount *ref_model;
3050   GtkTreeModel *filter_model;
3051   GtkWidget *tree_view;
3052   GtkTreePath *path;
3053   GtkTreeRowReference *row_ref;
3054
3055   model = gtk_tree_model_ref_count_new ();
3056   ref_model = GTK_TREE_MODEL_REF_COUNT (model);
3057
3058   /* + grandparent1
3059    * + grandparent2
3060    *   + parent1
3061    *     + iter_parent1
3062    *   + parent2
3063    *     + iter_parent2
3064    *     + iter_parent2
3065    */
3066
3067   gtk_tree_store_append (GTK_TREE_STORE (model), &grandparent1, NULL);
3068   gtk_tree_store_append (GTK_TREE_STORE (model), &grandparent2, NULL);
3069   gtk_tree_store_append (GTK_TREE_STORE (model), &parent1, &grandparent2);
3070   gtk_tree_store_append (GTK_TREE_STORE (model), &iter_parent1, &parent1);
3071   gtk_tree_store_append (GTK_TREE_STORE (model), &parent2, &grandparent2);
3072   gtk_tree_store_append (GTK_TREE_STORE (model), &iter_parent2_first, &parent2);
3073   gtk_tree_store_append (GTK_TREE_STORE (model), &iter_parent2, &parent2);
3074
3075   filter_model = gtk_tree_model_filter_new (model, NULL);
3076   tree_view = gtk_tree_view_new_with_model (filter_model);
3077
3078   path = gtk_tree_path_new_from_indices (1, 1, 1, -1);
3079   row_ref = gtk_tree_row_reference_new (filter_model, path);
3080   gtk_tree_path_free (path);
3081
3082   assert_node_ref_count (ref_model, &grandparent1, 2);
3083   assert_node_ref_count (ref_model, &grandparent2, 3);
3084   assert_node_ref_count (ref_model, &parent1, 1);
3085   assert_node_ref_count (ref_model, &parent2, 2);
3086   assert_node_ref_count (ref_model, &iter_parent1, 0);
3087   assert_node_ref_count (ref_model, &iter_parent2_first, 1);
3088   assert_node_ref_count (ref_model, &iter_parent2, 1);
3089
3090   gtk_tree_row_reference_free (row_ref);
3091
3092   assert_node_ref_count (ref_model, &grandparent1, 2);
3093   assert_node_ref_count (ref_model, &grandparent2, 2);
3094   assert_node_ref_count (ref_model, &parent1, 1);
3095   assert_node_ref_count (ref_model, &parent2, 1);
3096   assert_node_ref_count (ref_model, &iter_parent1, 0);
3097   assert_node_ref_count (ref_model, &iter_parent2_first, 1);
3098   assert_node_ref_count (ref_model, &iter_parent2, 0);
3099
3100   path = gtk_tree_path_new_from_indices (1, 1, 1, -1);
3101   row_ref = gtk_tree_row_reference_new (filter_model, path);
3102   gtk_tree_path_free (path);
3103
3104   assert_node_ref_count (ref_model, &grandparent1, 2);
3105   assert_node_ref_count (ref_model, &grandparent2, 3);
3106   assert_node_ref_count (ref_model, &parent1, 1);
3107   assert_node_ref_count (ref_model, &parent2, 2);
3108   assert_node_ref_count (ref_model, &iter_parent1, 0);
3109   assert_node_ref_count (ref_model, &iter_parent2_first, 1);
3110   assert_node_ref_count (ref_model, &iter_parent2, 1);
3111
3112   gtk_tree_store_remove (GTK_TREE_STORE (model), &parent2);
3113
3114   assert_node_ref_count (ref_model, &grandparent1, 2);
3115   assert_node_ref_count (ref_model, &grandparent2, 2);
3116   assert_node_ref_count (ref_model, &parent1, 1);
3117   assert_node_ref_count (ref_model, &iter_parent1, 0);
3118
3119   gtk_tree_row_reference_free (row_ref);
3120
3121   assert_node_ref_count (ref_model, &grandparent1, 2);
3122   assert_node_ref_count (ref_model, &grandparent2, 2);
3123   assert_node_ref_count (ref_model, &parent1, 1);
3124   assert_node_ref_count (ref_model, &iter_parent1, 0);
3125
3126   gtk_widget_destroy (tree_view);
3127
3128   gtk_tree_model_filter_clear_cache (GTK_TREE_MODEL_FILTER (filter_model));
3129
3130   /* The root level and first level remain cached, only the references on the
3131    * first nodes of these levels are kept.  Grandparent2 is the parent
3132    * of the first level with parent1, so grandparent2 keeps a reference
3133    * as well.
3134    */
3135   assert_node_ref_count (ref_model, &grandparent1, 1);
3136   assert_node_ref_count (ref_model, &grandparent2, 1);
3137   assert_node_ref_count (ref_model, &parent1, 1);
3138
3139   g_object_unref (filter_model);
3140   g_object_unref (ref_model);
3141 }
3142
3143 static void
3144 ref_count_transfer_root_level_insert (void)
3145 {
3146   GtkTreeIter grandparent1, grandparent2, grandparent3;
3147   GtkTreeIter new_node;
3148   GtkTreeModel *model;
3149   GtkTreeModelRefCount *ref_model;
3150   GtkTreeModel *filter_model;
3151   GtkWidget *tree_view;
3152
3153   model = gtk_tree_model_ref_count_new ();
3154   ref_model = GTK_TREE_MODEL_REF_COUNT (model);
3155
3156   /* + grandparent1
3157    * + grandparent2
3158    * + grandparent3
3159    */
3160
3161   gtk_tree_store_append (GTK_TREE_STORE (model), &grandparent1, NULL);
3162   gtk_tree_store_append (GTK_TREE_STORE (model), &grandparent2, NULL);
3163   gtk_tree_store_append (GTK_TREE_STORE (model), &grandparent3, NULL);
3164
3165   filter_model = gtk_tree_model_filter_new (model, NULL);
3166   tree_view = gtk_tree_view_new_with_model (filter_model);
3167
3168   assert_node_ref_count (ref_model, &grandparent1, 2);
3169   assert_node_ref_count (ref_model, &grandparent2, 1);
3170   assert_node_ref_count (ref_model, &grandparent3, 1);
3171
3172   gtk_tree_store_prepend (GTK_TREE_STORE (model), &new_node, NULL);
3173
3174   assert_node_ref_count (ref_model, &new_node, 2);
3175   assert_node_ref_count (ref_model, &grandparent1, 1);
3176   assert_node_ref_count (ref_model, &grandparent2, 1);
3177   assert_node_ref_count (ref_model, &grandparent3, 1);
3178
3179   gtk_widget_destroy (tree_view);
3180   g_object_unref (filter_model);
3181   g_object_unref (ref_model);
3182 }
3183
3184 static void
3185 ref_count_transfer_root_level_reordered (void)
3186 {
3187   GtkTreeIter grandparent1, grandparent2, grandparent3;
3188   GtkTreeModel *model;
3189   GtkTreeModelRefCount *ref_model;
3190   GtkTreeModel *filter_model;
3191   GtkWidget *tree_view;
3192
3193   model = gtk_tree_model_ref_count_new ();
3194   ref_model = GTK_TREE_MODEL_REF_COUNT (model);
3195
3196   /* + grandparent1
3197    * + grandparent2
3198    * + grandparent3
3199    */
3200
3201   gtk_tree_store_append (GTK_TREE_STORE (model), &grandparent1, NULL);
3202   gtk_tree_store_append (GTK_TREE_STORE (model), &grandparent2, NULL);
3203   gtk_tree_store_append (GTK_TREE_STORE (model), &grandparent3, NULL);
3204
3205   filter_model = gtk_tree_model_filter_new (model, NULL);
3206   tree_view = gtk_tree_view_new_with_model (filter_model);
3207
3208   assert_node_ref_count (ref_model, &grandparent1, 2);
3209   assert_node_ref_count (ref_model, &grandparent2, 1);
3210   assert_node_ref_count (ref_model, &grandparent3, 1);
3211
3212   /* gtk_tree_store_move() will emit rows-reordered */
3213   gtk_tree_store_move_after (GTK_TREE_STORE (model),
3214                              &grandparent1, &grandparent3);
3215
3216   assert_node_ref_count (ref_model, &grandparent2, 2);
3217   assert_node_ref_count (ref_model, &grandparent3, 1);
3218   assert_node_ref_count (ref_model, &grandparent1, 1);
3219
3220   gtk_widget_destroy (tree_view);
3221   g_object_unref (filter_model);
3222   g_object_unref (ref_model);
3223 }
3224
3225 static void
3226 ref_count_transfer_root_level_reordered_filtered (void)
3227 {
3228   GtkTreeIter grandparent1, grandparent2, grandparent3;
3229   GtkTreeModel *model;
3230   GtkTreeModelRefCount *ref_model;
3231   GtkTreeModel *filter_model;
3232   GtkWidget *tree_view;
3233   GType column_types[] = { G_TYPE_BOOLEAN };
3234
3235   model = gtk_tree_model_ref_count_new ();
3236   ref_model = GTK_TREE_MODEL_REF_COUNT (model);
3237
3238   gtk_tree_store_set_column_types (GTK_TREE_STORE (model), 1,
3239                                    column_types);
3240
3241   /* + grandparent1
3242    * + grandparent2
3243    * + grandparent3
3244    */
3245
3246   gtk_tree_store_append (GTK_TREE_STORE (model), &grandparent1, NULL);
3247   gtk_tree_store_append (GTK_TREE_STORE (model), &grandparent2, NULL);
3248   gtk_tree_store_append (GTK_TREE_STORE (model), &grandparent3, NULL);
3249
3250   /* Test with 1 node filtered */
3251   gtk_tree_store_set (GTK_TREE_STORE (model), &grandparent2, 0, TRUE, -1);
3252   gtk_tree_store_set (GTK_TREE_STORE (model), &grandparent3, 0, TRUE, -1);
3253
3254   filter_model = gtk_tree_model_filter_new (model, NULL);
3255   gtk_tree_model_filter_set_visible_column (GTK_TREE_MODEL_FILTER (filter_model), 0);
3256   tree_view = gtk_tree_view_new_with_model (filter_model);
3257
3258   assert_node_ref_count (ref_model, &grandparent1, 0);
3259   assert_node_ref_count (ref_model, &grandparent2, 2);
3260   assert_node_ref_count (ref_model, &grandparent3, 1);
3261
3262   /* gtk_tree_store_move() will emit rows-reordered */
3263   gtk_tree_store_move_after (GTK_TREE_STORE (model),
3264                              &grandparent1, &grandparent3);
3265
3266   assert_node_ref_count (ref_model, &grandparent2, 2);
3267   assert_node_ref_count (ref_model, &grandparent3, 1);
3268   assert_node_ref_count (ref_model, &grandparent1, 0);
3269
3270   /* gtk_tree_store_move() will emit rows-reordered */
3271   gtk_tree_store_move_before (GTK_TREE_STORE (model),
3272                               &grandparent1, &grandparent2);
3273
3274   assert_node_ref_count (ref_model, &grandparent1, 0);
3275   assert_node_ref_count (ref_model, &grandparent2, 2);
3276   assert_node_ref_count (ref_model, &grandparent3, 1);
3277
3278   gtk_tree_store_set (GTK_TREE_STORE (model), &grandparent1, 0, TRUE, -1);
3279
3280   assert_node_ref_count (ref_model, &grandparent1, 2);
3281   assert_node_ref_count (ref_model, &grandparent2, 1);
3282   assert_node_ref_count (ref_model, &grandparent3, 1);
3283
3284   /* Test with two nodes filtered */
3285   gtk_tree_store_set (GTK_TREE_STORE (model), &grandparent1, 0, FALSE, -1);
3286   gtk_tree_store_set (GTK_TREE_STORE (model), &grandparent2, 0, FALSE, -1);
3287
3288   assert_node_ref_count (ref_model, &grandparent1, 0);
3289   assert_node_ref_count (ref_model, &grandparent2, 0);
3290   assert_node_ref_count (ref_model, &grandparent3, 2);
3291
3292   /* gtk_tree_store_move() will emit rows-reordered */
3293   gtk_tree_store_move_before (GTK_TREE_STORE (model),
3294                              &grandparent3, &grandparent1);
3295
3296   assert_node_ref_count (ref_model, &grandparent3, 2);
3297   assert_node_ref_count (ref_model, &grandparent2, 0);
3298   assert_node_ref_count (ref_model, &grandparent1, 0);
3299
3300   gtk_widget_destroy (tree_view);
3301   g_object_unref (filter_model);
3302   g_object_unref (ref_model);
3303 }
3304
3305 static void
3306 ref_count_transfer_child_level_insert (void)
3307 {
3308   GtkTreeIter grandparent1;
3309   GtkTreeIter parent1, parent2, parent3;
3310   GtkTreeIter new_node;
3311   GtkTreeModel *model;
3312   GtkTreeModelRefCount *ref_model;
3313   GtkTreeModel *filter_model;
3314   GtkWidget *tree_view;
3315
3316   model = gtk_tree_model_ref_count_new ();
3317   ref_model = GTK_TREE_MODEL_REF_COUNT (model);
3318
3319   /* + grandparent1
3320    *   + parent1
3321    *   + parent2
3322    *   + parent3
3323    */
3324
3325   gtk_tree_store_append (GTK_TREE_STORE (model), &grandparent1, NULL);
3326   gtk_tree_store_append (GTK_TREE_STORE (model), &parent1, &grandparent1);
3327   gtk_tree_store_append (GTK_TREE_STORE (model), &parent2, &grandparent1);
3328   gtk_tree_store_append (GTK_TREE_STORE (model), &parent3, &grandparent1);
3329
3330   filter_model = gtk_tree_model_filter_new (model, NULL);
3331   tree_view = gtk_tree_view_new_with_model (filter_model);
3332
3333   assert_node_ref_count (ref_model, &grandparent1, 3);
3334   assert_node_ref_count (ref_model, &parent1, 1);
3335   assert_node_ref_count (ref_model, &parent2, 0);
3336   assert_node_ref_count (ref_model, &parent3, 0);
3337
3338   gtk_tree_store_prepend (GTK_TREE_STORE (model), &new_node, &grandparent1);
3339
3340   assert_node_ref_count (ref_model, &grandparent1, 3);
3341   assert_node_ref_count (ref_model, &new_node, 1);
3342   assert_node_ref_count (ref_model, &parent1, 0);
3343   assert_node_ref_count (ref_model, &parent2, 0);
3344   assert_node_ref_count (ref_model, &parent3, 0);
3345
3346   gtk_widget_destroy (tree_view);
3347   g_object_unref (filter_model);
3348   g_object_unref (ref_model);
3349 }
3350
3351 static void
3352 ref_count_transfer_child_level_reordered (void)
3353 {
3354   GtkTreeIter grandparent1;
3355   GtkTreeIter parent1, parent2, parent3;
3356   GtkTreeModel *model;
3357   GtkTreeModelRefCount *ref_model;
3358   GtkTreeModel *filter_model;
3359   GtkWidget *tree_view;
3360
3361   model = gtk_tree_model_ref_count_new ();
3362   ref_model = GTK_TREE_MODEL_REF_COUNT (model);
3363
3364   /* + grandparent1
3365    *   + parent1
3366    *   + parent2
3367    *   + parent3
3368    */
3369
3370   gtk_tree_store_append (GTK_TREE_STORE (model), &grandparent1, NULL);
3371   gtk_tree_store_append (GTK_TREE_STORE (model), &parent1, &grandparent1);
3372   gtk_tree_store_append (GTK_TREE_STORE (model), &parent2, &grandparent1);
3373   gtk_tree_store_append (GTK_TREE_STORE (model), &parent3, &grandparent1);
3374
3375   filter_model = gtk_tree_model_filter_new (model, NULL);
3376   tree_view = gtk_tree_view_new_with_model (filter_model);
3377
3378   assert_node_ref_count (ref_model, &grandparent1, 3);
3379   assert_node_ref_count (ref_model, &parent1, 1);
3380   assert_node_ref_count (ref_model, &parent2, 0);
3381   assert_node_ref_count (ref_model, &parent3, 0);
3382
3383   /* gtk_tree_store_move() will emit rows-reordered */
3384   gtk_tree_store_move_after (GTK_TREE_STORE (model),
3385                              &parent1, &parent3);
3386
3387   assert_node_ref_count (ref_model, &grandparent1, 3);
3388   assert_node_ref_count (ref_model, &parent2, 1);
3389   assert_node_ref_count (ref_model, &parent3, 0);
3390   assert_node_ref_count (ref_model, &parent1, 0);
3391
3392   gtk_widget_destroy (tree_view);
3393   g_object_unref (filter_model);
3394   g_object_unref (ref_model);
3395 }
3396
3397 static void
3398 ref_count_transfer_child_level_reordered_filtered (void)
3399 {
3400   GtkTreeIter grandparent1;
3401   GtkTreeIter parent1, parent2, parent3;
3402   GtkTreeModel *model;
3403   GtkTreeModelRefCount *ref_model;
3404   GtkTreeModel *filter_model;
3405   GtkWidget *tree_view;
3406   GType column_types[] = { G_TYPE_BOOLEAN };
3407
3408   model = gtk_tree_model_ref_count_new ();
3409   ref_model = GTK_TREE_MODEL_REF_COUNT (model);
3410
3411   gtk_tree_store_set_column_types (GTK_TREE_STORE (model), 1,
3412                                    column_types);
3413
3414   /* + grandparent1
3415    *   + parent1
3416    *   + parent2
3417    *   + parent3
3418    */
3419
3420   gtk_tree_store_append (GTK_TREE_STORE (model), &grandparent1, NULL);
3421   gtk_tree_store_append (GTK_TREE_STORE (model), &parent1, &grandparent1);
3422   gtk_tree_store_append (GTK_TREE_STORE (model), &parent2, &grandparent1);
3423   gtk_tree_store_append (GTK_TREE_STORE (model), &parent3, &grandparent1);
3424
3425   /* Test with 1 node filtered (parent1) */
3426   gtk_tree_store_set (GTK_TREE_STORE (model), &grandparent1, 0, TRUE, -1);
3427   gtk_tree_store_set (GTK_TREE_STORE (model), &parent2, 0, TRUE, -1);
3428   gtk_tree_store_set (GTK_TREE_STORE (model), &parent3, 0, TRUE, -1);
3429
3430   filter_model = gtk_tree_model_filter_new (model, NULL);
3431   gtk_tree_model_filter_set_visible_column (GTK_TREE_MODEL_FILTER (filter_model), 0);
3432   tree_view = gtk_tree_view_new_with_model (filter_model);
3433
3434   assert_node_ref_count (ref_model, &grandparent1, 3);
3435   assert_node_ref_count (ref_model, &parent1, 0);
3436   assert_node_ref_count (ref_model, &parent2, 1);
3437   assert_node_ref_count (ref_model, &parent3, 0);
3438
3439   /* gtk_tree_store_move() will emit rows-reordered */
3440   gtk_tree_store_move_after (GTK_TREE_STORE (model),
3441                              &parent1, &parent3);
3442
3443   assert_node_ref_count (ref_model, &grandparent1, 3);
3444   assert_node_ref_count (ref_model, &parent2, 1);
3445   assert_node_ref_count (ref_model, &parent3, 0);
3446   assert_node_ref_count (ref_model, &parent1, 0);
3447
3448   /* gtk_tree_store_move() will emit rows-reordered */
3449   gtk_tree_store_move_before (GTK_TREE_STORE (model),
3450                               &parent1, &parent2);
3451
3452   assert_node_ref_count (ref_model, &grandparent1, 3);
3453   assert_node_ref_count (ref_model, &parent1, 0);
3454   assert_node_ref_count (ref_model, &parent2, 1);
3455   assert_node_ref_count (ref_model, &parent3, 0);
3456
3457   gtk_tree_store_set (GTK_TREE_STORE (model), &parent1, 0, TRUE, -1);
3458
3459   assert_node_ref_count (ref_model, &parent1, 1);
3460   assert_node_ref_count (ref_model, &parent2, 0);
3461   assert_node_ref_count (ref_model, &parent3, 0);
3462
3463   /* Test with two nodes filtered */
3464   gtk_tree_store_set (GTK_TREE_STORE (model), &parent1, 0, FALSE, -1);
3465   gtk_tree_store_set (GTK_TREE_STORE (model), &parent2, 0, FALSE, -1);
3466
3467   assert_node_ref_count (ref_model, &parent1, 0);
3468   assert_node_ref_count (ref_model, &parent2, 0);
3469   assert_node_ref_count (ref_model, &parent3, 1);
3470
3471   /* gtk_tree_store_move() will emit rows-reordered */
3472   gtk_tree_store_move_before (GTK_TREE_STORE (model),
3473                              &parent3, &parent1);
3474
3475   assert_node_ref_count (ref_model, &parent3, 1);
3476   assert_node_ref_count (ref_model, &parent2, 0);
3477   assert_node_ref_count (ref_model, &parent1, 0);
3478
3479   gtk_widget_destroy (tree_view);
3480   g_object_unref (filter_model);
3481   g_object_unref (ref_model);
3482 }
3483
3484 static gboolean
3485 specific_path_dependent_filter_func (GtkTreeModel *model,
3486                                      GtkTreeIter  *iter,
3487                                      gpointer      data)
3488 {
3489   GtkTreePath *path;
3490
3491   path = gtk_tree_model_get_path (model, iter);
3492   if (gtk_tree_path_get_indices (path)[0] < 4)
3493     return FALSE;
3494
3495   return TRUE;
3496 }
3497
3498 static void
3499 specific_path_dependent_filter (void)
3500 {
3501   int i;
3502   GtkTreeIter iter;
3503   GtkListStore *list;
3504   GtkTreeModel *sort;
3505   GtkTreeModel *filter;
3506
3507   list = gtk_list_store_new (1, G_TYPE_INT);
3508   gtk_list_store_insert_with_values (list, &iter, 0, 0, 1, -1);
3509   gtk_list_store_insert_with_values (list, &iter, 1, 0, 2, -1);
3510   gtk_list_store_insert_with_values (list, &iter, 2, 0, 3, -1);
3511   gtk_list_store_insert_with_values (list, &iter, 3, 0, 4, -1);
3512   gtk_list_store_insert_with_values (list, &iter, 4, 0, 5, -1);
3513   gtk_list_store_insert_with_values (list, &iter, 5, 0, 6, -1);
3514   gtk_list_store_insert_with_values (list, &iter, 6, 0, 7, -1);
3515   gtk_list_store_insert_with_values (list, &iter, 7, 0, 8, -1);
3516
3517   sort = gtk_tree_model_sort_new_with_model (GTK_TREE_MODEL (list));
3518   filter = gtk_tree_model_filter_new (GTK_TREE_MODEL (sort), NULL);
3519   gtk_tree_model_filter_set_visible_func (GTK_TREE_MODEL_FILTER (filter),
3520                                           specific_path_dependent_filter_func,
3521                                           NULL, NULL);
3522
3523   gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (sort), 0,
3524                                         GTK_SORT_DESCENDING);
3525
3526   for (i = 0; i < 4; i++)
3527     {
3528       if (gtk_tree_model_iter_nth_child (GTK_TREE_MODEL (list), &iter,
3529                                          NULL, 1))
3530         gtk_list_store_remove (list, &iter);
3531
3532       if (gtk_tree_model_iter_nth_child (GTK_TREE_MODEL (list), &iter,
3533                                          NULL, 2))
3534         gtk_list_store_remove (list, &iter);
3535     }
3536
3537   g_object_unref (filter);
3538   g_object_unref (sort);
3539   g_object_unref (list);
3540 }
3541
3542
3543 static gboolean
3544 specific_append_after_collapse_visible_func (GtkTreeModel *model,
3545                                              GtkTreeIter  *iter,
3546                                              gpointer      data)
3547 {
3548   gint number;
3549   gboolean hide_negative_numbers;
3550
3551   gtk_tree_model_get (model, iter, 1, &number, -1);
3552   hide_negative_numbers = GPOINTER_TO_INT (g_object_get_data (data, "private-hide-negative-numbers"));
3553
3554   return (number >= 0 || !hide_negative_numbers);
3555 }
3556
3557 static void
3558 specific_append_after_collapse (void)
3559 {
3560   /* This test is based on one of the test cases I found in my
3561    * old test cases directory.  I unfortunately do not have a record
3562    * from who this test case originated.  -Kris.
3563    *
3564    * General idea:
3565    * - Construct tree.
3566    * - Show tree, expand, collapse.
3567    * - Add a row.
3568    */
3569
3570   GtkTreeIter iter;
3571   GtkTreeIter child_iter;
3572   GtkTreeIter child_iter2;
3573   GtkTreePath *append_path;
3574   GtkTreeStore *store;
3575   GtkTreeModel *filter;
3576   GtkTreeModel *sort;
3577
3578   GtkWidget *window;
3579   GtkWidget *tree_view;
3580
3581   store = gtk_tree_store_new (2, G_TYPE_STRING, G_TYPE_INT);
3582
3583   filter = gtk_tree_model_filter_new (GTK_TREE_MODEL (store), NULL);
3584   g_object_set_data (G_OBJECT (filter), "private-hide-negative-numbers",
3585                      GINT_TO_POINTER (FALSE));
3586   gtk_tree_model_filter_set_visible_func (GTK_TREE_MODEL_FILTER (filter),
3587                                           specific_append_after_collapse_visible_func,
3588                                           filter, NULL);
3589
3590   sort = gtk_tree_model_sort_new_with_model (filter);
3591
3592   window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
3593   tree_view = gtk_tree_view_new_with_model (sort);
3594   gtk_container_add (GTK_CONTAINER (window), tree_view);
3595   gtk_widget_realize (tree_view);
3596
3597   while (gtk_events_pending ())
3598     gtk_main_iteration ();
3599
3600   gtk_tree_store_prepend (store, &iter, NULL);
3601   gtk_tree_store_set (store, &iter,
3602                       0, "hallo", 1, 1, -1);
3603
3604   gtk_tree_store_append (store, &child_iter, &iter);
3605   gtk_tree_store_set (store, &child_iter,
3606                       0, "toemaar", 1, 1, -1);
3607
3608   gtk_tree_store_append (store, &child_iter2, &child_iter);
3609   gtk_tree_store_set (store, &child_iter2,
3610                       0, "very deep", 1, 1, -1);
3611
3612   append_path = gtk_tree_model_get_path (GTK_TREE_MODEL (store), &child_iter2);
3613
3614   gtk_tree_store_append (store, &child_iter, &iter);
3615   gtk_tree_store_set (store, &child_iter,
3616                       0, "sja", 1, 1, -1);
3617
3618   gtk_tree_store_append (store, &child_iter, &iter);
3619   gtk_tree_store_set (store, &child_iter,
3620                       0, "some word", 1, -1, -1);
3621
3622   /* Expand and collapse the tree */
3623   gtk_tree_view_expand_all (GTK_TREE_VIEW (tree_view));
3624   while (gtk_events_pending ())
3625     gtk_main_iteration ();
3626
3627   gtk_tree_view_collapse_all (GTK_TREE_VIEW (tree_view));
3628   while (gtk_events_pending ())
3629     gtk_main_iteration ();
3630
3631   /* Add another it */
3632   g_object_set_data (G_OBJECT (filter), "private-hide-negative-numbers",
3633                      GINT_TO_POINTER (TRUE));
3634
3635   if (gtk_tree_model_get_iter (GTK_TREE_MODEL (store), &iter, append_path))
3636     {
3637       gtk_tree_store_append (store, &child_iter, &iter);
3638       gtk_tree_store_set (store, &child_iter,
3639                           0, "new new new !!", 1, 1, -1);
3640     }
3641   gtk_tree_path_free (append_path);
3642
3643   /* Expand */
3644   gtk_tree_view_expand_all (GTK_TREE_VIEW (tree_view));
3645   while (gtk_events_pending ())
3646     gtk_main_iteration ();
3647 }
3648
3649
3650 static gint
3651 specific_sort_filter_remove_node_compare_func (GtkTreeModel  *model,
3652                                                GtkTreeIter   *iter1,
3653                                                GtkTreeIter   *iter2,
3654                                                gpointer       data)
3655 {
3656   return -1;
3657 }
3658
3659 static gboolean
3660 specific_sort_filter_remove_node_visible_func (GtkTreeModel  *model,
3661                                                GtkTreeIter   *iter,
3662                                                gpointer       data)
3663 {
3664   char *item = NULL;
3665
3666   /* Do reference the model */
3667   gtk_tree_model_get (model, iter, 0, &item, -1);
3668   g_free (item);
3669
3670   return FALSE;
3671 }
3672
3673 static void
3674 specific_sort_filter_remove_node (void)
3675 {
3676   /* This test is based on one of the test cases I found in my
3677    * old test cases directory.  I unfortunately do not have a record
3678    * from who this test case originated.  -Kris.
3679    *
3680    * General idea:
3681    *  - Create tree store, sort, filter models.  The sort model has
3682    *    a default sort func that is enabled, filter model a visible func
3683    *    that defaults to returning FALSE.
3684    *  - Remove a node from the tree store.
3685    */
3686
3687   GtkTreeIter iter;
3688   GtkTreeStore *store;
3689   GtkTreeModel *filter;
3690   GtkTreeModel *sort;
3691
3692   GtkWidget *window;
3693   GtkWidget *tree_view;
3694
3695   store = gtk_tree_store_new (1, G_TYPE_STRING);
3696   gtk_tree_store_append (store, &iter, NULL);
3697   gtk_tree_store_set (store, &iter, 0, "Hello1", -1);
3698
3699   gtk_tree_store_append (store, &iter, NULL);
3700   gtk_tree_store_set (store, &iter, 0, "Hello2", -1);
3701
3702   sort = gtk_tree_model_sort_new_with_model (GTK_TREE_MODEL (store));
3703   gtk_tree_sortable_set_default_sort_func (GTK_TREE_SORTABLE (sort),
3704                                            specific_sort_filter_remove_node_compare_func, NULL, NULL);
3705
3706   filter = gtk_tree_model_filter_new (sort, NULL);
3707   gtk_tree_model_filter_set_visible_func (GTK_TREE_MODEL_FILTER (filter),
3708                                           specific_sort_filter_remove_node_visible_func,
3709                                           filter, NULL);
3710
3711
3712   window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
3713   tree_view = gtk_tree_view_new_with_model (filter);
3714   gtk_container_add (GTK_CONTAINER (window), tree_view);
3715   gtk_widget_realize (tree_view);
3716
3717   while (gtk_events_pending ())
3718     gtk_main_iteration ();
3719
3720   /* Remove a node */
3721   gtk_tree_model_get_iter_first (GTK_TREE_MODEL (store), &iter);
3722   gtk_tree_model_iter_next (GTK_TREE_MODEL (store), &iter);
3723   gtk_tree_store_remove (store, &iter);
3724
3725   while (gtk_events_pending ())
3726     gtk_main_iteration ();
3727 }
3728
3729
3730 static void
3731 specific_sort_filter_remove_root (void)
3732 {
3733   /* This test is based on one of the test cases I found in my
3734    * old test cases directory.  I unfortunately do not have a record
3735    * from who this test case originated.  -Kris.
3736    */
3737
3738   GtkTreeModel *model, *sort, *filter;
3739   GtkTreeIter root, mid, leaf;
3740   GtkTreePath *path;
3741
3742   model = GTK_TREE_MODEL (gtk_tree_store_new (1, G_TYPE_INT));
3743   gtk_tree_store_append (GTK_TREE_STORE (model), &root, NULL);
3744   gtk_tree_store_append (GTK_TREE_STORE (model), &mid, &root);
3745   gtk_tree_store_append (GTK_TREE_STORE (model), &leaf, &mid);
3746
3747   path = gtk_tree_model_get_path (model, &mid);
3748
3749   sort = gtk_tree_model_sort_new_with_model (model);
3750   filter = gtk_tree_model_filter_new (sort, path);
3751
3752   gtk_tree_path_free (path);
3753
3754   gtk_tree_store_remove (GTK_TREE_STORE (model), &root);
3755
3756   g_object_unref (filter);
3757   g_object_unref (sort);
3758   g_object_unref (model);
3759 }
3760
3761
3762 static void
3763 specific_root_mixed_visibility (void)
3764 {
3765   int i;
3766   GtkTreeModel *filter;
3767   /* A bit nasty, apologies */
3768   FilterTest fixture;
3769
3770   fixture.store = gtk_tree_store_new (2, G_TYPE_STRING, G_TYPE_BOOLEAN);
3771
3772   for (i = 0; i < LEVEL_LENGTH; i++)
3773     {
3774       GtkTreeIter iter;
3775
3776       gtk_tree_store_insert (fixture.store, &iter, NULL, i);
3777       if (i % 2 == 0)
3778         create_tree_store_set_values (fixture.store, &iter, TRUE);
3779       else
3780         create_tree_store_set_values (fixture.store, &iter, FALSE);
3781     }
3782
3783   filter = gtk_tree_model_filter_new (GTK_TREE_MODEL (fixture.store), NULL);
3784   fixture.filter = GTK_TREE_MODEL_FILTER (filter);
3785   fixture.monitor = NULL;
3786
3787   gtk_tree_model_filter_set_visible_column (fixture.filter, 1);
3788
3789   /* In order to trigger the potential bug, we should not access
3790    * the filter model here (so don't call the check functions).
3791    */
3792
3793   /* Change visibility of an odd row to TRUE */
3794   set_path_visibility (&fixture, "3", TRUE);
3795   check_filter_model (&fixture);
3796   check_level_length (fixture.filter, NULL, 4);
3797 }
3798
3799
3800
3801 static gboolean
3802 specific_has_child_filter_filter_func (GtkTreeModel *model,
3803                                        GtkTreeIter  *iter,
3804                                        gpointer      data)
3805 {
3806   return gtk_tree_model_iter_has_child (model, iter);
3807 }
3808
3809 static void
3810 specific_has_child_filter (void)
3811 {
3812   GtkTreeModel *filter;
3813   GtkTreeIter iter, root;
3814   FilterTest fixture; /* This is not how it should be done */
3815   GtkWidget *tree_view;
3816
3817   fixture.store = gtk_tree_store_new (2, G_TYPE_STRING, G_TYPE_BOOLEAN);
3818   filter = gtk_tree_model_filter_new (GTK_TREE_MODEL (fixture.store), NULL);
3819   fixture.filter = GTK_TREE_MODEL_FILTER (filter);
3820   fixture.monitor = signal_monitor_new (filter);
3821
3822   tree_view = gtk_tree_view_new_with_model (filter);
3823
3824   /* We will filter on parent state using a filter function.  We will
3825    * manually keep the boolean column in sync, so that we can use
3826    * check_filter_model() to check the consistency of the model.
3827    */
3828   /* FIXME: We need a check_filter_model() that is not tied to LEVEL_LENGTH
3829    * to be able to check the structure here.  We keep the calls to
3830    * check_filter_model() commented out until then.
3831    */
3832   gtk_tree_model_filter_set_visible_func (fixture.filter,
3833                                           specific_has_child_filter_filter_func,
3834                                           NULL, NULL);
3835
3836   /* The first node will be initially invisible: no signals */
3837   gtk_tree_store_append (fixture.store, &root, NULL);
3838   create_tree_store_set_values (fixture.store, &root, FALSE);
3839
3840   /* check_filter_model (&fixture); */
3841   check_level_length (fixture.filter, NULL, 0);
3842   signal_monitor_assert_is_empty (fixture.monitor);
3843
3844   /* Insert a child node. This will cause the parent to become visible
3845    * since there is a child now.
3846    */
3847   signal_monitor_append_signal (fixture.monitor, ROW_INSERTED, "0");
3848   signal_monitor_append_signal (fixture.monitor, ROW_HAS_CHILD_TOGGLED, "0");
3849   signal_monitor_append_signal (fixture.monitor, ROW_HAS_CHILD_TOGGLED, "0");
3850
3851   gtk_tree_store_append (fixture.store, &iter, &root);
3852   create_tree_store_set_values (fixture.store, &iter, TRUE);
3853
3854   /* Parent must now be visible.  Do the level length check first,
3855    * to avoid modifying the child model triggering a row-changed to
3856    * the filter model.
3857    */
3858   check_level_length (fixture.filter, NULL, 1);
3859   check_level_length (fixture.filter, "0", 0);
3860   signal_monitor_assert_is_empty (fixture.monitor);
3861
3862   /* This should propagate row-changed */
3863   signal_monitor_append_signal (fixture.monitor, ROW_CHANGED, "0");
3864   signal_monitor_append_signal (fixture.monitor, ROW_HAS_CHILD_TOGGLED, "0");
3865
3866   set_path_visibility (&fixture, "0", TRUE);
3867   /* check_filter_model (&fixture); */
3868   signal_monitor_assert_is_empty (fixture.monitor);
3869
3870   /* New root node, no child, so no signal */
3871   gtk_tree_store_append (fixture.store, &root, NULL);
3872   check_level_length (fixture.filter, NULL, 1);
3873   signal_monitor_assert_is_empty (fixture.monitor);
3874
3875   /* When the child comes in, this node will become visible */
3876   signal_monitor_append_signal (fixture.monitor, ROW_INSERTED, "1");
3877   signal_monitor_append_signal (fixture.monitor, ROW_HAS_CHILD_TOGGLED, "1");
3878   signal_monitor_append_signal (fixture.monitor, ROW_HAS_CHILD_TOGGLED, "1");
3879   signal_monitor_append_signal (fixture.monitor, ROW_CHANGED, "1");
3880   signal_monitor_append_signal (fixture.monitor, ROW_HAS_CHILD_TOGGLED, "1");
3881
3882   gtk_tree_store_append (fixture.store, &iter, &root);
3883   check_level_length (fixture.filter, NULL, 2);
3884   check_level_length (fixture.filter, "1", 0);
3885
3886   create_tree_store_set_values (fixture.store, &root, TRUE);
3887   create_tree_store_set_values (fixture.store, &iter, TRUE);
3888
3889   /* check_filter_model (&fixture); */
3890   signal_monitor_assert_is_empty (fixture.monitor);
3891
3892   /* Add another child for 1 */
3893   gtk_tree_store_append (fixture.store, &iter, &root);
3894   create_tree_store_set_values (fixture.store, &iter, TRUE);
3895   check_level_length (fixture.filter, NULL, 2);
3896   check_level_length (fixture.filter, "0", 0);
3897   check_level_length (fixture.filter, "1", 0);
3898   signal_monitor_assert_is_empty (fixture.monitor);
3899
3900   /* Now remove one of the remaining child rows */
3901   signal_monitor_append_signal (fixture.monitor, ROW_DELETED, "0");
3902
3903   gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL (fixture.store),
3904                                        &iter, "0:0");
3905   gtk_tree_store_remove (fixture.store, &iter);
3906
3907   check_level_length (fixture.filter, NULL, 1);
3908   check_level_length (fixture.filter, "0", 0);
3909
3910   set_path_visibility (&fixture, "0", FALSE);
3911   /* check_filter_model (&fixture); */
3912   signal_monitor_assert_is_empty (fixture.monitor);
3913 }
3914
3915
3916 static gboolean
3917 specific_root_has_child_filter_filter_func (GtkTreeModel *model,
3918                                             GtkTreeIter  *iter,
3919                                             gpointer      data)
3920 {
3921   int depth;
3922   GtkTreePath *path;
3923
3924   path = gtk_tree_model_get_path (model, iter);
3925   depth = gtk_tree_path_get_depth (path);
3926   gtk_tree_path_free (path);
3927
3928   if (depth > 1)
3929     return TRUE;
3930   /* else */
3931   return gtk_tree_model_iter_has_child (model, iter);
3932 }
3933
3934 static void
3935 specific_root_has_child_filter (void)
3936 {
3937   GtkTreeModel *filter;
3938   GtkTreeIter iter, root;
3939   FilterTest fixture; /* This is not how it should be done ... */
3940   GtkWidget *tree_view;
3941
3942   /* This is a variation on the above test case, specific has-child-filter,
3943    * herein the has-child check for visibility only applies to root level
3944    * nodes.  In this test, children are always visible because we
3945    * only filter based on the "has child" criterion.
3946    */
3947
3948   fixture.store = gtk_tree_store_new (2, G_TYPE_STRING, G_TYPE_BOOLEAN);
3949   filter = gtk_tree_model_filter_new (GTK_TREE_MODEL (fixture.store), NULL);
3950   fixture.filter = GTK_TREE_MODEL_FILTER (filter);
3951   fixture.monitor = signal_monitor_new (filter);
3952
3953   tree_view = gtk_tree_view_new_with_model (filter);
3954
3955   /* We will filter on parent state using a filter function.  We will
3956    * manually keep the boolean column in sync, so that we can use
3957    * check_filter_model() to check the consistency of the model.
3958    */
3959   /* FIXME: We need a check_filter_model() that is not tied to LEVEL_LENGTH
3960    * to be able to check the structure here.  We keep the calls to
3961    * check_filter_model() commented out until then.
3962    */
3963   gtk_tree_model_filter_set_visible_func (fixture.filter,
3964                                           specific_root_has_child_filter_filter_func,
3965                                           NULL, NULL);
3966
3967   /* Add a first node, this will be invisible initially, so no signal
3968    * should be emitted.
3969    */
3970   gtk_tree_store_append (fixture.store, &root, NULL);
3971   create_tree_store_set_values (fixture.store, &root, FALSE);
3972
3973   signal_monitor_assert_is_empty (fixture.monitor);
3974   /* check_filter_model (&fixture); */
3975   check_level_length (fixture.filter, NULL, 0);
3976
3977   /* Add a child node.  This will cause the parent to become visible,
3978    * so we expect row-inserted signals for both.
3979    */
3980   signal_monitor_append_signal (fixture.monitor, ROW_INSERTED, "0");
3981   signal_monitor_append_signal (fixture.monitor, ROW_HAS_CHILD_TOGGLED, "0");
3982   signal_monitor_append_signal (fixture.monitor, ROW_HAS_CHILD_TOGGLED, "0");
3983
3984   gtk_tree_store_append (fixture.store, &iter, &root);
3985   signal_monitor_assert_is_empty (fixture.monitor);
3986
3987   check_level_length (fixture.filter, NULL, 1);
3988   check_level_length (fixture.filter, "0", 1);
3989
3990   /* Modify the content of iter, no signals because the parent is not
3991    * expanded.
3992    */
3993   create_tree_store_set_values (fixture.store, &iter, TRUE);
3994   signal_monitor_assert_is_empty (fixture.monitor);
3995
3996   /* Parent must now be visible.  Do the level length check first,
3997    * to avoid modifying the child model triggering a row-changed to
3998    * the filter model.
3999    */
4000   check_level_length (fixture.filter, NULL, 1);
4001   check_level_length (fixture.filter, "0", 1);
4002
4003   /* Modify path 0 */
4004   signal_monitor_append_signal (fixture.monitor, ROW_CHANGED, "0");
4005   signal_monitor_append_signal (fixture.monitor, ROW_HAS_CHILD_TOGGLED, "0");
4006
4007   set_path_visibility (&fixture, "0", TRUE);
4008   /* check_filter_model (&fixture); */
4009
4010   signal_monitor_assert_is_empty (fixture.monitor);
4011
4012   /* Insert another node in the root level.  Initially invisible, so
4013    * not expecting any signal.
4014    */
4015   gtk_tree_store_append (fixture.store, &root, NULL);
4016   check_level_length (fixture.filter, NULL, 1);
4017
4018   signal_monitor_assert_is_empty (fixture.monitor);
4019
4020   /* Adding a child node which also makes parent at path 1 visible. */
4021   signal_monitor_append_signal (fixture.monitor, ROW_INSERTED, "1");
4022   signal_monitor_append_signal (fixture.monitor, ROW_HAS_CHILD_TOGGLED, "1");
4023   signal_monitor_append_signal (fixture.monitor, ROW_HAS_CHILD_TOGGLED, "1");
4024
4025   gtk_tree_store_append (fixture.store, &iter, &root);
4026   check_level_length (fixture.filter, NULL, 2);
4027   check_level_length (fixture.filter, "1", 1);
4028
4029   signal_monitor_assert_is_empty (fixture.monitor);
4030
4031   /* Check if row-changed is propagated */
4032   signal_monitor_append_signal (fixture.monitor, ROW_CHANGED, "1");
4033   signal_monitor_append_signal (fixture.monitor, ROW_HAS_CHILD_TOGGLED, "1");
4034
4035   create_tree_store_set_values (fixture.store, &root, TRUE);
4036   create_tree_store_set_values (fixture.store, &iter, TRUE);
4037   /* check_filter_model (&fixture); */
4038   signal_monitor_assert_is_empty (fixture.monitor);
4039
4040   /* Insert another child under node 1 */
4041   gtk_tree_store_append (fixture.store, &iter, &root);
4042   create_tree_store_set_values (fixture.store, &iter, TRUE);
4043   check_level_length (fixture.filter, NULL, 2);
4044   check_level_length (fixture.filter, "0", 1);
4045   check_level_length (fixture.filter, "1", 2);
4046   signal_monitor_assert_is_empty (fixture.monitor);
4047
4048   /* Set a child node to invisible.  This should not yield any
4049    * change, because filtering is only done on whether the root
4050    * node has a child, which it still has.
4051    */
4052   set_path_visibility (&fixture, "0:0", FALSE);
4053   signal_monitor_assert_is_empty (fixture.monitor);
4054
4055   /* Now remove one of the remaining child rows */
4056   signal_monitor_append_signal (fixture.monitor, ROW_HAS_CHILD_TOGGLED, "0");
4057   signal_monitor_append_signal (fixture.monitor, ROW_DELETED, "0");
4058
4059   gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL (fixture.store),
4060                                        &iter, "0:0");
4061   gtk_tree_store_remove (fixture.store, &iter);
4062
4063   check_level_length (fixture.filter, NULL, 1);
4064   check_level_length (fixture.filter, "0", 2);
4065   signal_monitor_assert_is_empty (fixture.monitor);
4066
4067   /* Set visibility of 0 to FALSE, no-op for filter model since
4068    * the child 0:0 is already gone
4069    */
4070   set_path_visibility (&fixture, "0", FALSE);
4071   /* check_filter_model (&fixture); */
4072   signal_monitor_assert_is_empty (fixture.monitor);
4073 }
4074
4075 static void
4076 specific_has_child_filter_on_sort_model (void)
4077 {
4078   GtkTreeModel *filter;
4079   GtkTreeModel *sort_model;
4080   GtkTreeIter iter, root;
4081   FilterTest fixture; /* This is not how it should be done */
4082   GtkWidget *tree_view;
4083
4084   fixture.store = gtk_tree_store_new (2, G_TYPE_STRING, G_TYPE_BOOLEAN);
4085   sort_model = gtk_tree_model_sort_new_with_model (GTK_TREE_MODEL (fixture.store));
4086   filter = gtk_tree_model_filter_new (sort_model, NULL);
4087   fixture.filter = GTK_TREE_MODEL_FILTER (filter);
4088   fixture.monitor = signal_monitor_new (filter);
4089
4090   tree_view = gtk_tree_view_new_with_model (filter);
4091
4092   /* We will filter on parent state using a filter function.  We will
4093    * manually keep the boolean column in sync, so that we can use
4094    * check_filter_model() to check the consistency of the model.
4095    */
4096   /* FIXME: We need a check_filter_model() that is not tied to LEVEL_LENGTH
4097    * to be able to check the structure here.  We keep the calls to
4098    * check_filter_model() commented out until then.
4099    */
4100   gtk_tree_model_filter_set_visible_func (fixture.filter,
4101                                           specific_has_child_filter_filter_func,
4102                                           NULL, NULL);
4103
4104   /* The first node will be initially invisible: no signals */
4105   gtk_tree_store_append (fixture.store, &root, NULL);
4106   create_tree_store_set_values (fixture.store, &root, FALSE);
4107
4108   /* check_filter_model (&fixture); */
4109   check_level_length (fixture.filter, NULL, 0);
4110   signal_monitor_assert_is_empty (fixture.monitor);
4111
4112   /* Insert a child node. This will cause the parent to become visible
4113    * since there is a child now.
4114    */
4115   signal_monitor_append_signal (fixture.monitor, ROW_INSERTED, "0");
4116   signal_monitor_append_signal (fixture.monitor, ROW_HAS_CHILD_TOGGLED, "0");
4117
4118   gtk_tree_store_append (fixture.store, &iter, &root);
4119   create_tree_store_set_values (fixture.store, &iter, TRUE);
4120
4121   /* Parent must now be visible.  Do the level length check first,
4122    * to avoid modifying the child model triggering a row-changed to
4123    * the filter model.
4124    */
4125   check_level_length (fixture.filter, NULL, 1);
4126   check_level_length (fixture.filter, "0", 0);
4127   signal_monitor_assert_is_empty (fixture.monitor);
4128
4129   /* This should propagate row-changed */
4130   signal_monitor_append_signal (fixture.monitor, ROW_CHANGED, "0");
4131   signal_monitor_append_signal (fixture.monitor, ROW_HAS_CHILD_TOGGLED, "0");
4132
4133   set_path_visibility (&fixture, "0", TRUE);
4134   /* check_filter_model (&fixture); */
4135   signal_monitor_assert_is_empty (fixture.monitor);
4136
4137   /* New root node, no child, so no signal */
4138   gtk_tree_store_append (fixture.store, &root, NULL);
4139   check_level_length (fixture.filter, NULL, 1);
4140   signal_monitor_assert_is_empty (fixture.monitor);
4141
4142   /* When the child comes in, this node will become visible */
4143   signal_monitor_append_signal (fixture.monitor, ROW_INSERTED, "1");
4144   signal_monitor_append_signal (fixture.monitor, ROW_HAS_CHILD_TOGGLED, "1");
4145   signal_monitor_append_signal (fixture.monitor, ROW_CHANGED, "1");
4146   signal_monitor_append_signal (fixture.monitor, ROW_HAS_CHILD_TOGGLED, "1");
4147
4148   gtk_tree_store_append (fixture.store, &iter, &root);
4149   check_level_length (fixture.filter, NULL, 2);
4150   check_level_length (fixture.filter, "1", 0);
4151
4152   create_tree_store_set_values (fixture.store, &root, TRUE);
4153   create_tree_store_set_values (fixture.store, &iter, TRUE);
4154
4155   /* check_filter_model (&fixture); */
4156   signal_monitor_assert_is_empty (fixture.monitor);
4157
4158   /* Add another child for 1 */
4159   gtk_tree_store_append (fixture.store, &iter, &root);
4160   create_tree_store_set_values (fixture.store, &iter, TRUE);
4161   check_level_length (fixture.filter, NULL, 2);
4162   check_level_length (fixture.filter, "0", 0);
4163   check_level_length (fixture.filter, "1", 0);
4164   signal_monitor_assert_is_empty (fixture.monitor);
4165
4166   /* Now remove one of the remaining child rows */
4167   signal_monitor_append_signal (fixture.monitor, ROW_DELETED, "0");
4168
4169   gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL (fixture.store),
4170                                        &iter, "0:0");
4171   gtk_tree_store_remove (fixture.store, &iter);
4172
4173   check_level_length (fixture.filter, NULL, 1);
4174   check_level_length (fixture.filter, "0", 0);
4175
4176   set_path_visibility (&fixture, "0", FALSE);
4177   /* check_filter_model (&fixture); */
4178   signal_monitor_assert_is_empty (fixture.monitor);
4179 }
4180
4181 static gboolean
4182 specific_at_least_2_children_filter_filter_func (GtkTreeModel *model,
4183                                                  GtkTreeIter  *iter,
4184                                                  gpointer      data)
4185 {
4186   return gtk_tree_model_iter_n_children (model, iter) >= 2;
4187 }
4188
4189 static void
4190 specific_at_least_2_children_filter (void)
4191 {
4192   GtkTreeModel *filter;
4193   GtkTreeIter iter, root;
4194   FilterTest fixture; /* This is not how it should be done */
4195   GtkWidget *tree_view;
4196
4197   fixture.store = gtk_tree_store_new (2, G_TYPE_STRING, G_TYPE_BOOLEAN);
4198   filter = gtk_tree_model_filter_new (GTK_TREE_MODEL (fixture.store), NULL);
4199   fixture.filter = GTK_TREE_MODEL_FILTER (filter);
4200   fixture.monitor = signal_monitor_new (filter);
4201
4202   tree_view = gtk_tree_view_new_with_model (filter);
4203
4204   gtk_tree_model_filter_set_visible_func (fixture.filter,
4205                                           specific_at_least_2_children_filter_filter_func,
4206                                           NULL, NULL);
4207
4208   /* The first node will be initially invisible: no signals */
4209   gtk_tree_store_append (fixture.store, &root, NULL);
4210   create_tree_store_set_values (fixture.store, &root, FALSE);
4211
4212   /* check_filter_model (&fixture); */
4213   check_level_length (fixture.filter, NULL, 0);
4214   signal_monitor_assert_is_empty (fixture.monitor);
4215
4216   /* Insert a child node.  Nothing should happen.
4217    */
4218   gtk_tree_store_append (fixture.store, &iter, &root);
4219   create_tree_store_set_values (fixture.store, &iter, TRUE);
4220
4221   check_level_length (fixture.filter, NULL, 0);
4222   signal_monitor_assert_is_empty (fixture.monitor);
4223
4224   /* Insert a second child node.  This will cause the parent to become
4225    * visible.
4226    */
4227   signal_monitor_append_signal (fixture.monitor, ROW_INSERTED, "0");
4228   signal_monitor_append_signal (fixture.monitor, ROW_HAS_CHILD_TOGGLED, "0");
4229
4230   gtk_tree_store_append (fixture.store, &iter, &root);
4231   create_tree_store_set_values (fixture.store, &iter, TRUE);
4232
4233   /* Parent must now be visible.  Do the level length check first,
4234    * to avoid modifying the child model triggering a row-changed to
4235    * the filter model.
4236    */
4237   check_level_length (fixture.filter, NULL, 1);
4238   check_level_length (fixture.filter, "0", 0);
4239   signal_monitor_assert_is_empty (fixture.monitor);
4240
4241   /* This should propagate row-changed */
4242   signal_monitor_append_signal (fixture.monitor, ROW_CHANGED, "0");
4243   signal_monitor_append_signal (fixture.monitor, ROW_HAS_CHILD_TOGGLED, "0");
4244
4245   set_path_visibility (&fixture, "0", TRUE);
4246   /* check_filter_model (&fixture); */
4247   signal_monitor_assert_is_empty (fixture.monitor);
4248
4249   /* New root node, no child, so no signal */
4250   gtk_tree_store_append (fixture.store, &root, NULL);
4251   check_level_length (fixture.filter, NULL, 1);
4252   signal_monitor_assert_is_empty (fixture.monitor);
4253
4254   /* First child, no signal, no change */
4255   gtk_tree_store_append (fixture.store, &iter, &root);
4256   check_level_length (fixture.filter, NULL, 1);
4257   signal_monitor_assert_is_empty (fixture.monitor);
4258
4259   /* When the second child comes in, this node will become visible */
4260   signal_monitor_append_signal (fixture.monitor, ROW_INSERTED, "1");
4261   signal_monitor_append_signal (fixture.monitor, ROW_HAS_CHILD_TOGGLED, "1");
4262   signal_monitor_append_signal (fixture.monitor, ROW_CHANGED, "1");
4263   signal_monitor_append_signal (fixture.monitor, ROW_HAS_CHILD_TOGGLED, "1");
4264
4265   gtk_tree_store_append (fixture.store, &iter, &root);
4266   check_level_length (fixture.filter, NULL, 2);
4267   check_level_length (fixture.filter, "1", 0);
4268
4269   create_tree_store_set_values (fixture.store, &root, TRUE);
4270   create_tree_store_set_values (fixture.store, &iter, TRUE);
4271
4272   /* check_filter_model (&fixture); */
4273   signal_monitor_assert_is_empty (fixture.monitor);
4274
4275   /* Add another child for 1 */
4276   gtk_tree_store_append (fixture.store, &iter, &root);
4277   create_tree_store_set_values (fixture.store, &iter, TRUE);
4278   check_level_length (fixture.filter, NULL, 2);
4279   check_level_length (fixture.filter, "0", 0);
4280   check_level_length (fixture.filter, "1", 0);
4281   signal_monitor_assert_is_empty (fixture.monitor);
4282
4283   /* Now remove one of the remaining child rows */
4284   signal_monitor_append_signal (fixture.monitor, ROW_DELETED, "0");
4285
4286   gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL (fixture.store),
4287                                        &iter, "0:0");
4288   gtk_tree_store_remove (fixture.store, &iter);
4289
4290   check_level_length (fixture.filter, NULL, 1);
4291   check_level_length (fixture.filter, "0", 0);
4292
4293   set_path_visibility (&fixture, "0", FALSE);
4294   /* check_filter_model (&fixture); */
4295   signal_monitor_assert_is_empty (fixture.monitor);
4296 }
4297
4298 static void
4299 specific_at_least_2_children_filter_on_sort_model (void)
4300 {
4301   GtkTreeModel *filter;
4302   GtkTreeModel *sort_model;
4303   GtkTreeIter iter, root;
4304   FilterTest fixture; /* This is not how it should be done */
4305   GtkWidget *tree_view;
4306
4307   fixture.store = gtk_tree_store_new (2, G_TYPE_STRING, G_TYPE_BOOLEAN);
4308   sort_model = gtk_tree_model_sort_new_with_model (GTK_TREE_MODEL (fixture.store));
4309   filter = gtk_tree_model_filter_new (sort_model, NULL);
4310   fixture.filter = GTK_TREE_MODEL_FILTER (filter);
4311   fixture.monitor = signal_monitor_new (filter);
4312
4313   tree_view = gtk_tree_view_new_with_model (filter);
4314
4315   gtk_tree_model_filter_set_visible_func (fixture.filter,
4316                                           specific_at_least_2_children_filter_filter_func,
4317                                           NULL, NULL);
4318
4319   /* The first node will be initially invisible: no signals */
4320   gtk_tree_store_append (fixture.store, &root, NULL);
4321   create_tree_store_set_values (fixture.store, &root, FALSE);
4322
4323   /* check_filter_model (&fixture); */
4324   check_level_length (fixture.filter, NULL, 0);
4325   signal_monitor_assert_is_empty (fixture.monitor);
4326
4327   /* Insert a child node.  Nothing should happen.
4328    */
4329   gtk_tree_store_append (fixture.store, &iter, &root);
4330   create_tree_store_set_values (fixture.store, &iter, TRUE);
4331
4332   check_level_length (fixture.filter, NULL, 0);
4333   signal_monitor_assert_is_empty (fixture.monitor);
4334
4335     {
4336       GtkTreePath *path = gtk_tree_path_new_from_indices (0, 0, -1);
4337       GtkTreeRowReference *ref;
4338
4339       ref = gtk_tree_row_reference_new (sort_model, path);
4340       gtk_tree_path_free (path);
4341     }
4342
4343   /* Insert a second child node.  This will cause the parent to become
4344    * visible.
4345    */
4346   signal_monitor_append_signal (fixture.monitor, ROW_INSERTED, "0");
4347   signal_monitor_append_signal (fixture.monitor, ROW_HAS_CHILD_TOGGLED, "0");
4348
4349   gtk_tree_store_append (fixture.store, &iter, &root);
4350   create_tree_store_set_values (fixture.store, &iter, TRUE);
4351
4352   /* Parent must now be visible.  Do the level length check first,
4353    * to avoid modifying the child model triggering a row-changed to
4354    * the filter model.
4355    */
4356   check_level_length (fixture.filter, NULL, 1);
4357   check_level_length (fixture.filter, "0", 0);
4358   signal_monitor_assert_is_empty (fixture.monitor);
4359
4360   /* This should propagate row-changed */
4361   signal_monitor_append_signal (fixture.monitor, ROW_CHANGED, "0");
4362   signal_monitor_append_signal (fixture.monitor, ROW_HAS_CHILD_TOGGLED, "0");
4363
4364   set_path_visibility (&fixture, "0", TRUE);
4365   /* check_filter_model (&fixture); */
4366   signal_monitor_assert_is_empty (fixture.monitor);
4367
4368   /* New root node, no child, so no signal */
4369   gtk_tree_store_append (fixture.store, &root, NULL);
4370   check_level_length (fixture.filter, NULL, 1);
4371   signal_monitor_assert_is_empty (fixture.monitor);
4372 }
4373
4374
4375 static void
4376 specific_filter_add_child (void)
4377 {
4378   /* This test is based on one of the test cases I found in my
4379    * old test cases directory.  I unfortunately do not have a record
4380    * from who this test case originated.  -Kris.
4381    */
4382
4383   GtkTreeIter iter;
4384   GtkTreeIter iter_first;
4385   GtkTreeIter child;
4386   GtkTreeStore *store;
4387   GtkTreeModel *filter G_GNUC_UNUSED;
4388
4389   store = gtk_tree_store_new (1, G_TYPE_STRING);
4390
4391   gtk_tree_store_append (store, &iter_first, NULL);
4392   gtk_tree_store_set (store, &iter_first, 0, "Hello", -1);
4393
4394   gtk_tree_store_append (store, &iter, NULL);
4395   gtk_tree_store_set (store, &iter, 0, "Hello", -1);
4396
4397   gtk_tree_store_append (store, &iter, NULL);
4398   gtk_tree_store_set (store, &iter, 0, "Hello", -1);
4399
4400   gtk_tree_store_append (store, &iter, NULL);
4401   gtk_tree_store_set (store, &iter, 0, "Hello", -1);
4402
4403   filter = gtk_tree_model_filter_new (GTK_TREE_MODEL (store), NULL);
4404
4405   gtk_tree_store_set (store, &iter, 0, "Hello", -1);
4406   gtk_tree_store_append (store, &child, &iter_first);
4407   gtk_tree_store_set (store, &child, 0, "Hello", -1);
4408 }
4409
4410 static void
4411 specific_list_store_clear (void)
4412 {
4413   GtkTreeIter iter;
4414   GtkListStore *list;
4415   GtkTreeModel *filter;
4416   GtkWidget *view G_GNUC_UNUSED;
4417
4418   list = gtk_list_store_new (1, G_TYPE_INT);
4419   gtk_list_store_insert_with_values (list, &iter, 0, 0, 1, -1);
4420   gtk_list_store_insert_with_values (list, &iter, 1, 0, 2, -1);
4421   gtk_list_store_insert_with_values (list, &iter, 2, 0, 3, -1);
4422   gtk_list_store_insert_with_values (list, &iter, 3, 0, 4, -1);
4423   gtk_list_store_insert_with_values (list, &iter, 4, 0, 5, -1);
4424   gtk_list_store_insert_with_values (list, &iter, 5, 0, 6, -1);
4425   gtk_list_store_insert_with_values (list, &iter, 6, 0, 7, -1);
4426   gtk_list_store_insert_with_values (list, &iter, 7, 0, 8, -1);
4427
4428   filter = gtk_tree_model_filter_new (GTK_TREE_MODEL (list), NULL);
4429   view = gtk_tree_view_new_with_model (filter);
4430
4431   gtk_list_store_clear (list);
4432 }
4433
4434 static void
4435 specific_sort_ref_leaf_and_remove_ancestor (void)
4436 {
4437   GtkTreeIter iter, child, child2, child3;
4438   GtkTreeStore *tree;
4439   GtkTreeModel *sort;
4440   GtkTreePath *path;
4441   GtkTreeRowReference *rowref;
4442   GtkWidget *view G_GNUC_UNUSED;
4443
4444   tree = gtk_tree_store_new (1, G_TYPE_INT);
4445   gtk_tree_store_insert_with_values (tree, &iter, NULL, 0, 0, 1, -1);
4446   gtk_tree_store_insert_with_values (tree, &iter, NULL, 1, 0, 2, -1);
4447   gtk_tree_store_insert_with_values (tree, &iter, NULL, 2, 0, 3, -1);
4448   gtk_tree_store_insert_with_values (tree, &iter, NULL, 3, 0, 4, -1);
4449
4450   gtk_tree_store_insert_with_values (tree, &child, &iter, 0, 0, 50, -1);
4451   gtk_tree_store_insert_with_values (tree, &child2, &child, 0, 0, 6, -1);
4452   gtk_tree_store_insert_with_values (tree, &child3, &child2, 0, 0, 7, -1);
4453
4454   sort = gtk_tree_model_sort_new_with_model (GTK_TREE_MODEL (tree));
4455   view = gtk_tree_view_new_with_model (sort);
4456   gtk_tree_view_expand_all (GTK_TREE_VIEW (view));
4457
4458   path = gtk_tree_path_new_from_indices (3, 0, 0, 0, -1);
4459   rowref = gtk_tree_row_reference_new (sort, path);
4460   gtk_tree_path_free (path);
4461
4462   path = gtk_tree_path_new_from_indices (3, 0, 0, 0, -1);
4463   rowref = gtk_tree_row_reference_new (sort, path);
4464   gtk_tree_path_free (path);
4465
4466   path = gtk_tree_path_new_from_indices (3, 0, -1);
4467   rowref = gtk_tree_row_reference_new (sort, path);
4468   gtk_tree_path_free (path);
4469
4470   path = gtk_tree_path_new_from_indices (3, -1);
4471   rowref = gtk_tree_row_reference_new (sort, path);
4472   gtk_tree_path_free (path);
4473
4474   /* Deleting a parent */
4475   path = gtk_tree_path_new_from_indices (3, 0, -1);
4476   gtk_tree_model_get_iter (GTK_TREE_MODEL (tree), &iter, path);
4477   gtk_tree_store_remove (tree, &iter);
4478   gtk_tree_path_free (path);
4479
4480   gtk_tree_row_reference_free (rowref);
4481 }
4482
4483 static void
4484 specific_ref_leaf_and_remove_ancestor (void)
4485 {
4486   GtkTreeIter iter, child, child2, child3;
4487   GtkTreeStore *tree;
4488   GtkTreeModel *filter;
4489   GtkTreePath *path;
4490   GtkTreeRowReference *rowref;
4491   GtkWidget *view G_GNUC_UNUSED;
4492
4493   tree = gtk_tree_store_new (1, G_TYPE_INT);
4494   gtk_tree_store_insert_with_values (tree, &iter, NULL, 0, 0, 1, -1);
4495   gtk_tree_store_insert_with_values (tree, &iter, NULL, 1, 0, 2, -1);
4496   gtk_tree_store_insert_with_values (tree, &iter, NULL, 2, 0, 3, -1);
4497   gtk_tree_store_insert_with_values (tree, &iter, NULL, 3, 0, 4, -1);
4498
4499   gtk_tree_store_insert_with_values (tree, &child, &iter, 0, 0, 50, -1);
4500   gtk_tree_store_insert_with_values (tree, &child2, &child, 0, 0, 6, -1);
4501   gtk_tree_store_insert_with_values (tree, &child3, &child2, 0, 0, 7, -1);
4502
4503   filter = gtk_tree_model_filter_new (GTK_TREE_MODEL (tree), NULL);
4504   view = gtk_tree_view_new_with_model (filter);
4505   gtk_tree_view_expand_all (GTK_TREE_VIEW (view));
4506
4507   path = gtk_tree_path_new_from_indices (3, 0, 0, 0, -1);
4508   rowref = gtk_tree_row_reference_new (filter, path);
4509   gtk_tree_path_free (path);
4510
4511   path = gtk_tree_path_new_from_indices (3, 0, 0, 0, -1);
4512   rowref = gtk_tree_row_reference_new (filter, path);
4513   gtk_tree_path_free (path);
4514
4515   path = gtk_tree_path_new_from_indices (3, 0, -1);
4516   rowref = gtk_tree_row_reference_new (filter, path);
4517   gtk_tree_path_free (path);
4518
4519   path = gtk_tree_path_new_from_indices (3, -1);
4520   rowref = gtk_tree_row_reference_new (filter, path);
4521   gtk_tree_path_free (path);
4522
4523   /* Deleting a parent */
4524   path = gtk_tree_path_new_from_indices (3, 0, -1);
4525   gtk_tree_model_get_iter (GTK_TREE_MODEL (tree), &iter, path);
4526   gtk_tree_store_remove (tree, &iter);
4527   gtk_tree_path_free (path);
4528
4529   gtk_tree_row_reference_free (rowref);
4530 }
4531
4532 static void
4533 specific_virtual_ref_leaf_and_remove_ancestor (void)
4534 {
4535   GtkTreeIter iter, child, child2, child3;
4536   GtkTreeStore *tree;
4537   GtkTreeModel *filter;
4538   GtkTreePath *path;
4539   GtkTreeRowReference *rowref;
4540   GtkWidget *view G_GNUC_UNUSED;
4541
4542   tree = gtk_tree_store_new (1, G_TYPE_INT);
4543   gtk_tree_store_insert_with_values (tree, &iter, NULL, 0, 0, 1, -1);
4544   gtk_tree_store_insert_with_values (tree, &iter, NULL, 1, 0, 2, -1);
4545   gtk_tree_store_insert_with_values (tree, &iter, NULL, 2, 0, 3, -1);
4546   gtk_tree_store_insert_with_values (tree, &iter, NULL, 3, 0, 4, -1);
4547
4548   gtk_tree_store_insert_with_values (tree, &child, &iter, 0, 0, 50, -1);
4549   gtk_tree_store_insert_with_values (tree, &child2, &child, 0, 0, 6, -1);
4550   gtk_tree_store_insert_with_values (tree, &child3, &child2, 0, 0, 7, -1);
4551
4552   /* Set a virtual root of 3:0 */
4553   path = gtk_tree_path_new_from_indices (3, 0, -1);
4554   filter = gtk_tree_model_filter_new (GTK_TREE_MODEL (tree), path);
4555   gtk_tree_path_free (path);
4556
4557   view = gtk_tree_view_new_with_model (filter);
4558   gtk_tree_view_expand_all (GTK_TREE_VIEW (view));
4559
4560   path = gtk_tree_path_new_from_indices (0, 0, -1);
4561   rowref = gtk_tree_row_reference_new (filter, path);
4562   gtk_tree_path_free (path);
4563
4564   path = gtk_tree_path_new_from_indices (0, 0, -1);
4565   rowref = gtk_tree_row_reference_new (filter, path);
4566   gtk_tree_path_free (path);
4567
4568   path = gtk_tree_path_new_from_indices (0, -1);
4569   rowref = gtk_tree_row_reference_new (filter, path);
4570   gtk_tree_path_free (path);
4571
4572   /* Deleting the virtual root */
4573   path = gtk_tree_path_new_from_indices (3, 0, -1);
4574   gtk_tree_model_get_iter (GTK_TREE_MODEL (tree), &iter, path);
4575   gtk_tree_store_remove (tree, &iter);
4576   gtk_tree_path_free (path);
4577
4578   gtk_tree_row_reference_free (rowref);
4579 }
4580
4581
4582 static int
4583 specific_bug_301558_sort_func (GtkTreeModel *model,
4584                                GtkTreeIter  *a,
4585                                GtkTreeIter  *b,
4586                                gpointer      data)
4587 {
4588   int i, j;
4589
4590   gtk_tree_model_get (model, a, 0, &i, -1);
4591   gtk_tree_model_get (model, b, 0, &j, -1);
4592
4593   return j - i;
4594 }
4595
4596 static void
4597 specific_bug_301558 (void)
4598 {
4599   /* Test case for GNOME Bugzilla bug 301558 provided by
4600    * Markku Vire.
4601    */
4602   GtkTreeStore *tree;
4603   GtkTreeModel *filter;
4604   GtkTreeModel *sort;
4605   GtkTreeIter root, iter, iter2;
4606   GtkWidget *view G_GNUC_UNUSED;
4607   int i;
4608   gboolean add;
4609
4610   g_test_bug ("301558");
4611
4612   tree = gtk_tree_store_new (2, G_TYPE_INT, G_TYPE_BOOLEAN);
4613   gtk_tree_store_append (tree, &iter, NULL);
4614   gtk_tree_store_set (tree, &iter, 0, 123, 1, TRUE, -1);
4615   gtk_tree_store_append (tree, &iter2, &iter);
4616   gtk_tree_store_set (tree, &iter2, 0, 73, 1, TRUE, -1);
4617
4618   sort = gtk_tree_model_sort_new_with_model (GTK_TREE_MODEL (tree));
4619   gtk_tree_sortable_set_default_sort_func (GTK_TREE_SORTABLE (sort),
4620                                            specific_bug_301558_sort_func,
4621                                            NULL, NULL);
4622
4623   filter = gtk_tree_model_filter_new (sort, NULL);
4624   gtk_tree_model_filter_set_visible_column (GTK_TREE_MODEL_FILTER (filter), 1);
4625
4626   view = gtk_tree_view_new_with_model (filter);
4627
4628   while (gtk_events_pending ())
4629     gtk_main_iteration ();
4630
4631   add = TRUE;
4632
4633   for (i = 0; i < 10; i++)
4634     {
4635       if (!gtk_tree_model_get_iter_first (GTK_TREE_MODEL (tree), &root))
4636         g_assert_not_reached ();
4637
4638       if (add)
4639         {
4640           gtk_tree_store_append (tree, &iter, &root);
4641           gtk_tree_store_set (tree, &iter, 0, 456, 1, TRUE, -1);
4642         }
4643       else
4644         {
4645           int n;
4646           n = gtk_tree_model_iter_n_children (GTK_TREE_MODEL (tree), &root);
4647           gtk_tree_model_iter_nth_child (GTK_TREE_MODEL (tree), &iter,
4648                                          &root, n - 1);
4649           gtk_tree_store_remove (tree, &iter);
4650         }
4651
4652       add = !add;
4653     }
4654 }
4655
4656
4657 static gboolean
4658 specific_bug_311955_filter_func (GtkTreeModel *model,
4659                                  GtkTreeIter  *iter,
4660                                  gpointer      data)
4661 {
4662   int value;
4663
4664   gtk_tree_model_get (model, iter, 0, &value, -1);
4665
4666   return (value != 0);
4667 }
4668
4669 static void
4670 specific_bug_311955 (void)
4671 {
4672   /* This is a test case for GNOME Bugzilla bug 311955.  It was written
4673    * by Markku Vire.
4674    */
4675   GtkTreeIter iter, child, root;
4676   GtkTreeStore *store;
4677   GtkTreeModel *sort;
4678   GtkTreeModel *filter;
4679
4680   GtkWidget *window G_GNUC_UNUSED;
4681   GtkWidget *tree_view;
4682   int i;
4683   int n;
4684   GtkTreePath *path;
4685
4686   g_test_bug ("311955");
4687
4688   store = gtk_tree_store_new (1, G_TYPE_INT);
4689
4690   gtk_tree_store_append (store, &root, NULL);
4691   gtk_tree_store_set (store, &root, 0, 33, -1);
4692
4693   gtk_tree_store_append (store, &iter, &root);
4694   gtk_tree_store_set (store, &iter, 0, 50, -1);
4695
4696   gtk_tree_store_append (store, &iter, NULL);
4697   gtk_tree_store_set (store, &iter, 0, 22, -1);
4698
4699   sort = gtk_tree_model_sort_new_with_model (GTK_TREE_MODEL (store));
4700   filter = gtk_tree_model_filter_new (sort, NULL);
4701
4702   gtk_tree_model_filter_set_visible_func (GTK_TREE_MODEL_FILTER (filter),
4703                                           specific_bug_311955_filter_func,
4704                                           NULL, NULL);
4705
4706   window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
4707   tree_view = gtk_tree_view_new_with_model (filter);
4708   g_object_unref (store);
4709
4710   gtk_tree_view_expand_all (GTK_TREE_VIEW (tree_view));
4711
4712   while (gtk_events_pending ())
4713     gtk_main_iteration ();
4714
4715   check_level_length (GTK_TREE_MODEL_FILTER (filter), NULL, 2);
4716   check_level_length (GTK_TREE_MODEL_FILTER (filter), "0", 1);
4717
4718   /* Fill model */
4719   for (i = 0; i < 4; i++)
4720     {
4721       gtk_tree_model_get_iter_first (GTK_TREE_MODEL (store), &root);
4722
4723       gtk_tree_store_append (store, &iter, &root);
4724
4725       if (i < 3)
4726         gtk_tree_store_set (store, &iter, 0, i, -1);
4727
4728       if (i % 2 == 0)
4729         {
4730           gtk_tree_store_append (store, &child, &iter);
4731           gtk_tree_store_set (store, &child, 0, 10, -1);
4732         }
4733     }
4734
4735   while (gtk_events_pending ())
4736     gtk_main_iteration ();
4737
4738   check_level_length (GTK_TREE_MODEL_FILTER (filter), "0", 3);
4739   check_level_length (GTK_TREE_MODEL_FILTER (filter), "0:2", 1);
4740
4741   /* Remove bottommost child from the tree. */
4742   gtk_tree_model_get_iter_first (GTK_TREE_MODEL (store), &root);
4743   n = gtk_tree_model_iter_n_children (GTK_TREE_MODEL (store), &root);
4744
4745   if (gtk_tree_model_iter_nth_child (GTK_TREE_MODEL (store), &iter, &root, n - 2))
4746     {
4747       if (gtk_tree_model_iter_children (GTK_TREE_MODEL (store), &child, &iter))
4748         gtk_tree_store_remove (store, &child);
4749     }
4750   else
4751     g_assert_not_reached ();
4752
4753   path = gtk_tree_path_new_from_indices (0, 2, -1);
4754   gtk_tree_view_expand_row (GTK_TREE_VIEW (tree_view), path, FALSE);
4755   gtk_tree_path_free (path);
4756
4757   check_level_length (GTK_TREE_MODEL_FILTER (filter), "0", 3);
4758   check_level_length (GTK_TREE_MODEL_FILTER (filter), "0:2", 0);
4759 }
4760
4761 static void
4762 specific_bug_311955_clean (void)
4763 {
4764   /* Cleaned up version of the test case for GNOME Bugzilla bug 311955,
4765    * which is easier to understand.
4766    */
4767   GtkTreeIter iter, child, grandchild;
4768   GtkTreeStore *store;
4769   GtkTreeModel *sort;
4770   GtkTreeModel *filter;
4771
4772   GtkWidget *tree_view;
4773   GtkTreePath *path;
4774
4775   store = gtk_tree_store_new (1, G_TYPE_INT);
4776
4777   gtk_tree_store_append (store, &iter, NULL);
4778   gtk_tree_store_set (store, &iter, 0, 1, -1);
4779
4780   gtk_tree_store_append (store, &child, &iter);
4781   gtk_tree_store_set (store, &child, 0, 1, -1);
4782
4783   sort = gtk_tree_model_sort_new_with_model (GTK_TREE_MODEL (store));
4784   filter = gtk_tree_model_filter_new (sort, NULL);
4785
4786   gtk_tree_model_filter_set_visible_func (GTK_TREE_MODEL_FILTER (filter),
4787                                           specific_bug_311955_filter_func,
4788                                           NULL, NULL);
4789
4790   tree_view = gtk_tree_view_new_with_model (filter);
4791   g_object_unref (store);
4792
4793   gtk_tree_view_expand_all (GTK_TREE_VIEW (tree_view));
4794
4795   while (gtk_events_pending ())
4796     gtk_main_iteration ();
4797
4798   check_level_length (GTK_TREE_MODEL_FILTER (filter), NULL, 1);
4799   check_level_length (GTK_TREE_MODEL_FILTER (filter), "0", 1);
4800
4801   gtk_tree_model_get_iter_first (GTK_TREE_MODEL (store), &iter);
4802
4803   gtk_tree_store_append (store, &child, &iter);
4804   gtk_tree_store_set (store, &child, 0, 0, -1);
4805
4806   gtk_tree_store_append (store, &child, &iter);
4807   gtk_tree_store_set (store, &child, 0, 1, -1);
4808
4809   gtk_tree_store_append (store, &child, &iter);
4810   gtk_tree_store_set (store, &child, 0, 1, -1);
4811
4812   gtk_tree_store_append (store, &grandchild, &child);
4813   gtk_tree_store_set (store, &grandchild, 0, 1, -1);
4814
4815   gtk_tree_store_append (store, &child, &iter);
4816   /* Don't set a value: assume 0 */
4817
4818   /* Remove leaf node, check trigger row-has-child-toggled */
4819   path = gtk_tree_path_new_from_indices (0, 3, 0, -1);
4820   gtk_tree_model_get_iter (GTK_TREE_MODEL (store), &iter, path);
4821   gtk_tree_path_free (path);
4822   gtk_tree_store_remove (store, &iter);
4823
4824   path = gtk_tree_path_new_from_indices (0, 2, -1);
4825   gtk_tree_view_expand_row (GTK_TREE_VIEW (tree_view), path, FALSE);
4826   gtk_tree_path_free (path);
4827
4828   check_level_length (GTK_TREE_MODEL_FILTER (filter), "0", 3);
4829   check_level_length (GTK_TREE_MODEL_FILTER (filter), "0:2", 0);
4830
4831   gtk_widget_destroy (tree_view);
4832 }
4833
4834 static void
4835 specific_bug_346800 (void)
4836 {
4837   /* This is a test case for GNOME Bugzilla bug 346800.  It was written
4838    * by Jonathan Matthew.
4839    */
4840
4841   GtkTreeIter node_iters[50];
4842   GtkTreeIter child_iters[50];
4843   GtkTreeModel *model;
4844   GtkTreeModelFilter *filter;
4845   GtkTreeStore *store;
4846   GType *columns;
4847   int i;
4848   int items = 50;
4849   columns = g_new (GType, 2);
4850   columns[0] = G_TYPE_STRING;
4851   columns[1] = G_TYPE_BOOLEAN;
4852   store = gtk_tree_store_newv (2, columns);
4853   model = GTK_TREE_MODEL (store);
4854
4855   g_test_bug ("346800");
4856
4857   filter = GTK_TREE_MODEL_FILTER (gtk_tree_model_filter_new (model, NULL));
4858   gtk_tree_model_filter_set_visible_column (filter, 1);
4859
4860   for (i=0; i<items; i++)
4861     {
4862       /* allocate random amounts of junk, otherwise the filter model's arrays can expand without moving */
4863
4864       g_malloc (138);
4865       gtk_tree_store_append (store, &node_iters[i], NULL);
4866       gtk_tree_store_set (store, &node_iters[i],
4867                           0, "something",
4868                           1, ((i%6) == 0) ? FALSE : TRUE,
4869                           -1);
4870
4871       g_malloc (47);
4872       gtk_tree_store_append (store, &child_iters[i], &node_iters[i]);
4873       gtk_tree_store_set (store, &child_iters[i],
4874                           0, "something else",
4875                           1, FALSE,
4876                           -1);
4877       gtk_tree_model_filter_refilter (filter);
4878
4879       if (i > 6)
4880         {
4881           gtk_tree_store_set (GTK_TREE_STORE (model), &child_iters[i-1], 1,
4882                               (i & 1) ? TRUE : FALSE, -1);
4883           gtk_tree_model_filter_refilter (filter);
4884
4885           gtk_tree_store_set (GTK_TREE_STORE (model), &child_iters[i-2], 1,
4886                               (i & 1) ? FALSE: TRUE, -1);
4887           gtk_tree_model_filter_refilter (filter);
4888         }
4889     }
4890 }
4891
4892 static gboolean
4893 specific_bug_464173_visible_func (GtkTreeModel *model,
4894                                   GtkTreeIter  *iter,
4895                                   gpointer      data)
4896 {
4897   gboolean *visible = (gboolean *)data;
4898
4899   return *visible;
4900 }
4901
4902 static void
4903 specific_bug_464173 (void)
4904 {
4905   /* Test case for GNOME Bugzilla bug 464173, test case written
4906    * by Andreas Koehler.
4907    */
4908   GtkTreeStore *model;
4909   GtkTreeModelFilter *f_model;
4910   GtkTreeIter iter1, iter2;
4911   GtkWidget *view G_GNUC_UNUSED;
4912   gboolean visible = TRUE;
4913
4914   g_test_bug ("464173");
4915
4916   model = gtk_tree_store_new (1, G_TYPE_STRING);
4917   gtk_tree_store_append (model, &iter1, NULL);
4918   gtk_tree_store_set (model, &iter1, 0, "Foo", -1);
4919   gtk_tree_store_append (model, &iter2, &iter1);
4920   gtk_tree_store_set (model, &iter2, 0, "Bar", -1);
4921
4922   f_model = GTK_TREE_MODEL_FILTER (gtk_tree_model_filter_new (GTK_TREE_MODEL(model), NULL));
4923   gtk_tree_model_filter_set_visible_func (f_model,
4924                                           specific_bug_464173_visible_func,
4925                                           &visible, NULL);
4926
4927   view = gtk_tree_view_new_with_model (GTK_TREE_MODEL (f_model));
4928
4929   visible = FALSE;
4930   gtk_tree_model_filter_refilter (f_model);
4931 }
4932
4933
4934 static gboolean
4935 specific_bug_540201_filter_func (GtkTreeModel *model,
4936                                  GtkTreeIter  *iter,
4937                                  gpointer      data)
4938 {
4939   gboolean has_children;
4940
4941   has_children = gtk_tree_model_iter_has_child (model, iter);
4942
4943   return has_children;
4944 }
4945
4946 static void
4947 specific_bug_540201 (void)
4948 {
4949   /* Test case for GNOME Bugzilla bug 540201, steps provided by
4950    * Charles Day.
4951    */
4952   GtkTreeIter iter, root;
4953   GtkTreeStore *store;
4954   GtkTreeModel *filter;
4955
4956   GtkWidget *tree_view G_GNUC_UNUSED;
4957
4958   g_test_bug ("540201");
4959
4960   store = gtk_tree_store_new (1, G_TYPE_INT);
4961
4962   gtk_tree_store_append (store, &root, NULL);
4963   gtk_tree_store_set (store, &root, 0, 33, -1);
4964
4965   filter = gtk_tree_model_filter_new (GTK_TREE_MODEL (store), NULL);
4966   tree_view = gtk_tree_view_new_with_model (filter);
4967
4968   gtk_tree_model_filter_set_visible_func (GTK_TREE_MODEL_FILTER (filter),
4969                                           specific_bug_540201_filter_func,
4970                                           NULL, NULL);
4971
4972   gtk_tree_store_append (store, &iter, &root);
4973   gtk_tree_store_set (store, &iter, 0, 50, -1);
4974
4975   gtk_tree_store_append (store, &iter, &root);
4976   gtk_tree_store_set (store, &iter, 0, 22, -1);
4977
4978
4979   gtk_tree_store_append (store, &root, NULL);
4980   gtk_tree_store_set (store, &root, 0, 33, -1);
4981
4982   gtk_tree_store_append (store, &iter, &root);
4983   gtk_tree_store_set (store, &iter, 0, 22, -1);
4984 }
4985
4986
4987 static gboolean
4988 specific_bug_549287_visible_func (GtkTreeModel *model,
4989                                   GtkTreeIter  *iter,
4990                                   gpointer      data)
4991 {
4992   gboolean result = FALSE;
4993
4994   result = gtk_tree_model_iter_has_child (model, iter);
4995
4996   return result;
4997 }
4998
4999 static void
5000 specific_bug_549287 (void)
5001 {
5002   /* Test case for GNOME Bugzilla bug 529287, provided by Julient Puydt */
5003
5004   int i;
5005   GtkTreeStore *store;
5006   GtkTreeModel *filtered;
5007   GtkWidget *view G_GNUC_UNUSED;
5008   GtkTreeIter iter;
5009   GtkTreeIter *swap, *parent, *child;
5010
5011   g_test_bug ("529287");
5012
5013   store = gtk_tree_store_new (1, G_TYPE_STRING);
5014   filtered = gtk_tree_model_filter_new (GTK_TREE_MODEL (store), NULL);
5015   gtk_tree_model_filter_set_visible_func (GTK_TREE_MODEL_FILTER (filtered),
5016                                           specific_bug_549287_visible_func,
5017                                           NULL, NULL);
5018
5019   view = gtk_tree_view_new_with_model (filtered);
5020
5021   for (i = 0; i < 4; i++)
5022     {
5023       if (gtk_tree_model_get_iter_first (GTK_TREE_MODEL (store), &iter))
5024         {
5025           parent = gtk_tree_iter_copy (&iter);
5026           child = gtk_tree_iter_copy (&iter);
5027
5028           while (gtk_tree_model_iter_nth_child (GTK_TREE_MODEL (store),
5029                                                 child, parent, 0))
5030             {
5031
5032               swap = parent;
5033               parent = child;
5034               child = swap;
5035             }
5036
5037           gtk_tree_store_append (store, child, parent);
5038           gtk_tree_store_set (store, child,
5039                               0, "Something",
5040                               -1);
5041
5042           gtk_tree_iter_free (parent);
5043           gtk_tree_iter_free (child);
5044         }
5045       else
5046         {
5047           gtk_tree_store_append (store, &iter, NULL);
5048           gtk_tree_store_set (store, &iter,
5049                               0, "Something",
5050                               -1);
5051         }
5052
5053       /* since we inserted something, we changed the visibility conditions: */
5054       gtk_tree_model_filter_refilter (GTK_TREE_MODEL_FILTER (filtered));
5055     }
5056 }
5057
5058 static gboolean
5059 specific_bug_621076_visible_func (GtkTreeModel *model,
5060                                   GtkTreeIter  *iter,
5061                                   gpointer      data)
5062 {
5063   gboolean visible = FALSE;
5064   gchar *str = NULL;
5065
5066   gtk_tree_model_get (model, iter, 0, &str, -1);
5067   if (str != NULL && g_str_has_prefix (str, "visible"))
5068     {
5069       visible = TRUE;
5070     }
5071   else
5072     {
5073       GtkTreeIter child_iter;
5074       gboolean valid;
5075
5076       /* Recursively check if we have a visible child */
5077       for (valid = gtk_tree_model_iter_children (model, &child_iter, iter);
5078            valid; valid = gtk_tree_model_iter_next (model, &child_iter))
5079         {
5080           if (specific_bug_621076_visible_func (model, &child_iter, data))
5081             {
5082               visible = TRUE;
5083               break;
5084             }
5085         }
5086     }
5087
5088   if (str)
5089     g_free (str);
5090
5091   return visible;
5092 }
5093
5094 static void
5095 specific_bug_621076 (void)
5096 {
5097   /* Test case for GNOME Bugzilla bug 621076, provided by Xavier Claessens */
5098
5099   /* This test case differs from has-child-filter and root-has-child-filter
5100    * in that the visible function both filters on content and model
5101    * structure.  Also, it is recursive.
5102    */
5103
5104   GtkTreeStore *store;
5105   GtkTreeModel *filter;
5106   GtkWidget *view;
5107   GtkTreeIter group_iter;
5108   GtkTreeIter item_iter;
5109   SignalMonitor *monitor;
5110
5111   g_test_bug ("621076");
5112
5113   store = gtk_tree_store_new (1, G_TYPE_STRING);
5114   filter = gtk_tree_model_filter_new (GTK_TREE_MODEL (store), NULL);
5115   gtk_tree_model_filter_set_visible_func (GTK_TREE_MODEL_FILTER (filter),
5116                                           specific_bug_621076_visible_func,
5117                                           NULL, NULL);
5118
5119   view = gtk_tree_view_new_with_model (filter);
5120   g_object_ref_sink (view);
5121
5122   monitor = signal_monitor_new (filter);
5123
5124   signal_monitor_append_signal (monitor, ROW_INSERTED, "0");
5125   gtk_tree_store_insert_with_values (store, &item_iter, NULL, -1,
5126                                      0, "visible-group-0",
5127                                      -1);
5128   signal_monitor_assert_is_empty (monitor);
5129
5130   /* visible-group-0 is not expanded, so ROW_INSERTED should not be emitted
5131    * for its children. However, ROW_HAS_CHILD_TOGGLED should be emitted on
5132    * visible-group-0 to tell the view that row can be expanded. */
5133   signal_monitor_append_signal (monitor, ROW_HAS_CHILD_TOGGLED, "0");
5134   signal_monitor_append_signal (monitor, ROW_HAS_CHILD_TOGGLED, "0");
5135   group_iter = item_iter;
5136   gtk_tree_store_insert_with_values (store, &item_iter, &group_iter, -1,
5137                                      0, "visible-0:0",
5138                                      -1);
5139   signal_monitor_assert_is_empty (monitor);
5140
5141   signal_monitor_append_signal (monitor, ROW_INSERTED, "1");
5142   gtk_tree_store_insert_with_values (store, &item_iter, NULL, -1,
5143                                      0, "visible-group-1",
5144                                      -1);
5145   signal_monitor_assert_is_empty (monitor);
5146
5147   /* We are adding an hidden item inside visible-group-1, so
5148    * ROW_HAS_CHILD_TOGGLED should not be emitted.  It is emitted though,
5149    * because the signal originating at TreeStore will be propagated,
5150    * as well a generated signal because the state of the parent *could*
5151    * change by a change in the model.
5152    */
5153   signal_monitor_append_signal (monitor, ROW_HAS_CHILD_TOGGLED, "1");
5154   signal_monitor_append_signal (monitor, ROW_HAS_CHILD_TOGGLED, "1");
5155   group_iter = item_iter;
5156   gtk_tree_store_insert_with_values (store, &item_iter, &group_iter, -1,
5157                                      0, "group-1:0",
5158                                      -1);
5159   signal_monitor_assert_is_empty (monitor);
5160
5161   /* This group is invisible and its parent too. Nothing should be emitted */
5162   group_iter = item_iter;
5163   gtk_tree_store_insert_with_values (store, &item_iter, &group_iter, -1,
5164                                      0, "group-1:0:0",
5165                                      -1);
5166   signal_monitor_assert_is_empty (monitor);
5167
5168   /* Adding a visible item in this group hierarchy will make all nodes
5169    * in this path visible.  The first level should simply tell the view
5170    * that it now has a child, and the view will load the tree if needed
5171    * (depends on the expanded state).
5172    */
5173   signal_monitor_append_signal (monitor, ROW_HAS_CHILD_TOGGLED, "1");
5174   group_iter = item_iter;
5175   gtk_tree_store_insert_with_values (store, &item_iter, &group_iter, -1,
5176                                      0, "visible-1:0:0:0",
5177                                      -1);
5178   signal_monitor_assert_is_empty (monitor);
5179
5180   check_level_length (GTK_TREE_MODEL_FILTER (filter), "1", 1);
5181
5182   gtk_tree_store_insert_with_values (store, &item_iter, NULL, -1,
5183                                      0, "group-2",
5184                                      -1);
5185   signal_monitor_assert_is_empty (monitor);
5186
5187   /* Parent is invisible, and adding this invisible item won't change that,
5188    * so no signal should be emitted. */
5189   group_iter = item_iter;
5190   gtk_tree_store_insert_with_values (store, NULL, &group_iter, -1,
5191                                      0, "invisible-2:0",
5192                                      -1);
5193   signal_monitor_assert_is_empty (monitor);
5194
5195   /* This makes group-2 visible, so it gets inserted and tells it has
5196    * children.
5197    */
5198   signal_monitor_append_signal (monitor, ROW_INSERTED, "2");
5199   signal_monitor_append_signal (monitor, ROW_HAS_CHILD_TOGGLED, "2");
5200   gtk_tree_store_insert_with_values (store, NULL, &group_iter, -1,
5201                                      0, "visible-2:1",
5202                                      -1);
5203   signal_monitor_assert_is_empty (monitor);
5204
5205   /* group-2 is already visible, so this time it is a normal insertion */
5206   gtk_tree_store_insert_with_values (store, NULL, &group_iter, -1,
5207                                      0, "visible-2:2",
5208                                      -1);
5209   signal_monitor_assert_is_empty (monitor);
5210
5211
5212   gtk_tree_store_insert_with_values (store, &item_iter, NULL, -1,
5213                                      0, "group-3",
5214                                      -1);
5215   signal_monitor_assert_is_empty (monitor);
5216
5217   /* Parent is invisible, and adding this invisible item won't change that,
5218    * so no signal should be emitted. */
5219   group_iter = item_iter;
5220   gtk_tree_store_insert_with_values (store, NULL, &group_iter, -1,
5221                                      0, "invisible-3:0",
5222                                      -1);
5223   signal_monitor_assert_is_empty (monitor);
5224
5225   gtk_tree_store_insert_with_values (store, &item_iter, &group_iter, -1,
5226                                      0, "invisible-3:1",
5227                                      -1);
5228   signal_monitor_assert_is_empty (monitor);
5229
5230   /* This will make group 3 visible. */
5231   signal_monitor_append_signal (monitor, ROW_INSERTED, "3");
5232   signal_monitor_append_signal (monitor, ROW_HAS_CHILD_TOGGLED, "3");
5233   signal_monitor_append_signal (monitor, ROW_HAS_CHILD_TOGGLED, "3");
5234   gtk_tree_store_set (store, &item_iter, 0, "visible-3:1", -1);
5235   signal_monitor_assert_is_empty (monitor);
5236
5237   /* Make sure all groups are expanded, so the filter has the tree cached */
5238   gtk_tree_view_expand_all (GTK_TREE_VIEW (view));
5239   while (gtk_events_pending ())
5240     gtk_main_iteration ();
5241
5242   /* Should only yield a row-changed */
5243   signal_monitor_append_signal (monitor, ROW_CHANGED, "3:0");
5244   gtk_tree_store_set (store, &item_iter, 0, "visible-3:1", -1);
5245   signal_monitor_assert_is_empty (monitor);
5246
5247   /* Now remove/hide some items. If a group loses its last item, the group
5248    * should be deleted instead of the item.
5249    */
5250
5251   signal_monitor_append_signal (monitor, ROW_DELETED, "2:1");
5252   gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL (store), &item_iter, "2:2");
5253   gtk_tree_store_remove (store, &item_iter);
5254   signal_monitor_assert_is_empty (monitor);
5255
5256   signal_monitor_append_signal (monitor, ROW_DELETED, "2:0");
5257   signal_monitor_append_signal (monitor, ROW_HAS_CHILD_TOGGLED, "2");
5258   signal_monitor_append_signal (monitor, ROW_DELETED, "2");
5259   gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL (store), &item_iter, "2:1");
5260   gtk_tree_store_set (store, &item_iter, 0, "invisible-2:1", -1);
5261   signal_monitor_assert_is_empty (monitor);
5262
5263   signal_monitor_append_signal (monitor, ROW_DELETED, "1:0:0:0");
5264   signal_monitor_append_signal (monitor, ROW_HAS_CHILD_TOGGLED, "1:0:0");
5265   signal_monitor_append_signal (monitor, ROW_DELETED, "1:0");
5266   signal_monitor_append_signal (monitor, ROW_HAS_CHILD_TOGGLED, "1");
5267   gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL (store), &item_iter, "1:0:0:0");
5268   gtk_tree_store_remove (store, &item_iter);
5269   signal_monitor_assert_is_empty (monitor);
5270
5271   /* Hide a group using row-changed instead of row-deleted */
5272   /* Caution: group 2 is gone, so offsets of the signals have moved. */
5273   signal_monitor_append_signal (monitor, ROW_DELETED, "2:0");
5274   signal_monitor_append_signal (monitor, ROW_HAS_CHILD_TOGGLED, "2");
5275   signal_monitor_append_signal (monitor, ROW_DELETED, "2");
5276   gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL (store), &item_iter,
5277                                        "3:1");
5278   gtk_tree_store_set (store, &item_iter, 0, "invisible-3:1", -1);
5279   signal_monitor_assert_is_empty (monitor);
5280
5281 #if 0
5282   {
5283     GtkWidget *window;
5284     GtkTreeViewColumn *col;
5285
5286     gtk_tree_view_expand_all (GTK_TREE_VIEW (view));
5287
5288     col = gtk_tree_view_column_new_with_attributes ("foo",
5289         gtk_cell_renderer_text_new (),
5290         "text", 0, NULL);
5291     gtk_tree_view_append_column (GTK_TREE_VIEW (view), col);
5292
5293     window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
5294     g_signal_connect (window, "delete-event",
5295         G_CALLBACK (gtk_widget_destroy), NULL);
5296     g_signal_connect (window, "destroy",
5297         G_CALLBACK (gtk_main_quit), NULL);
5298
5299     gtk_container_add (GTK_CONTAINER (window), view);
5300
5301     gtk_widget_show (view);
5302     gtk_widget_show (window);
5303
5304     gtk_main ();
5305   }
5306 #endif
5307
5308   /* Cleanup */
5309   signal_monitor_free (monitor);
5310   g_object_unref (view);
5311   g_object_unref (store);
5312   g_object_unref (filter);
5313 }
5314
5315 /* main */
5316
5317 void
5318 register_filter_model_tests (void)
5319 {
5320   g_test_add ("/TreeModelFilter/self/verify-test-suite",
5321               FilterTest, NULL,
5322               filter_test_setup,
5323               verify_test_suite,
5324               filter_test_teardown);
5325
5326   g_test_add ("/TreeModelFilter/self/verify-test-suite/vroot/depth-1",
5327               FilterTest, gtk_tree_path_new_from_indices (2, -1),
5328               filter_test_setup,
5329               verify_test_suite_vroot,
5330               filter_test_teardown);
5331   g_test_add ("/TreeModelFilter/self/verify-test-suite/vroot/depth-2",
5332               FilterTest, gtk_tree_path_new_from_indices (2, 3, -1),
5333               filter_test_setup,
5334               verify_test_suite_vroot,
5335               filter_test_teardown);
5336
5337
5338   g_test_add ("/TreeModelFilter/filled/hide-root-level",
5339               FilterTest, NULL,
5340               filter_test_setup,
5341               filled_hide_root_level,
5342               filter_test_teardown);
5343   g_test_add ("/TreeModelFilter/filled/hide-child-levels",
5344               FilterTest, NULL,
5345               filter_test_setup,
5346               filled_hide_child_levels,
5347               filter_test_teardown);
5348   g_test_add ("/TreeModelFilter/filled/hide-child-levels/root-expanded",
5349               FilterTest, NULL,
5350               filter_test_setup,
5351               filled_hide_child_levels_root_expanded,
5352               filter_test_teardown);
5353
5354   g_test_add ("/TreeModelFilter/filled/hide-root-level/vroot",
5355               FilterTest, gtk_tree_path_new_from_indices (2, -1),
5356               filter_test_setup,
5357               filled_vroot_hide_root_level,
5358               filter_test_teardown);
5359   g_test_add ("/TreeModelFilter/filled/hide-child-levels/vroot",
5360               FilterTest, gtk_tree_path_new_from_indices (2, -1),
5361               filter_test_setup,
5362               filled_vroot_hide_child_levels,
5363               filter_test_teardown);
5364   g_test_add ("/TreeModelFilter/filled/hide-child-levels/vroot-root-expanded",
5365               FilterTest, gtk_tree_path_new_from_indices (2, -1),
5366               filter_test_setup,
5367               filled_vroot_hide_child_levels_root_expanded,
5368               filter_test_teardown);
5369
5370
5371   g_test_add ("/TreeModelFilter/empty/show-nodes",
5372               FilterTest, NULL,
5373               filter_test_setup_empty,
5374               empty_show_nodes,
5375               filter_test_teardown);
5376   g_test_add ("/TreeModelFilter/empty/show-multiple-nodes",
5377               FilterTest, NULL,
5378               filter_test_setup_empty,
5379               empty_show_multiple_nodes,
5380               filter_test_teardown);
5381
5382   g_test_add ("/TreeModelFilter/empty/show-nodes/vroot",
5383               FilterTest, gtk_tree_path_new_from_indices (2, -1),
5384               filter_test_setup_empty,
5385               empty_vroot_show_nodes,
5386               filter_test_teardown);
5387   g_test_add ("/TreeModelFilter/empty/show-multiple-nodes/vroot",
5388               FilterTest, gtk_tree_path_new_from_indices (2, -1),
5389               filter_test_setup_empty,
5390               empty_vroot_show_multiple_nodes,
5391               filter_test_teardown);
5392
5393
5394   g_test_add ("/TreeModelFilter/unfiltered/hide-single",
5395               FilterTest, NULL,
5396               filter_test_setup_unfiltered,
5397               unfiltered_hide_single,
5398               filter_test_teardown);
5399   g_test_add ("/TreeModelFilter/unfiltered/hide-single/root-expanded",
5400               FilterTest, NULL,
5401               filter_test_setup_unfiltered_root_expanded,
5402               unfiltered_hide_single_root_expanded,
5403               filter_test_teardown);
5404   g_test_add ("/TreeModelFilter/unfiltered/hide-single-child",
5405               FilterTest, NULL,
5406               filter_test_setup_unfiltered,
5407               unfiltered_hide_single_child,
5408               filter_test_teardown);
5409   g_test_add ("/TreeModelFilter/unfiltered/hide-single-child/root-expanded",
5410               FilterTest, NULL,
5411               filter_test_setup_unfiltered_root_expanded,
5412               unfiltered_hide_single_child_root_expanded,
5413               filter_test_teardown);
5414   g_test_add ("/TreeModelFilter/unfiltered/hide-single-multi-level",
5415               FilterTest, NULL,
5416               filter_test_setup_unfiltered,
5417               unfiltered_hide_single_multi_level,
5418               filter_test_teardown);
5419   g_test_add ("/TreeModelFilter/unfiltered/hide-single-multi-level/root-expanded",
5420               FilterTest, NULL,
5421               filter_test_setup_unfiltered_root_expanded,
5422               unfiltered_hide_single_multi_level_root_expanded,
5423               filter_test_teardown);
5424
5425   g_test_add ("/TreeModelFilter/unfiltered/hide-single/vroot",
5426               FilterTest, gtk_tree_path_new_from_indices (2, -1),
5427               filter_test_setup_unfiltered,
5428               unfiltered_vroot_hide_single,
5429               filter_test_teardown);
5430   g_test_add ("/TreeModelFilter/unfiltered/hide-single-child/vroot",
5431               FilterTest, gtk_tree_path_new_from_indices (2, -1),
5432               filter_test_setup_unfiltered,
5433               unfiltered_vroot_hide_single_child,
5434               filter_test_teardown);
5435   g_test_add ("/TreeModelFilter/unfiltered/hide-single-child/vroot/root-expanded",
5436               FilterTest, gtk_tree_path_new_from_indices (2, -1),
5437               filter_test_setup_unfiltered_root_expanded,
5438               unfiltered_vroot_hide_single_child_root_expanded,
5439               filter_test_teardown);
5440   g_test_add ("/TreeModelFilter/unfiltered/hide-single-multi-level/vroot",
5441               FilterTest, gtk_tree_path_new_from_indices (2, -1),
5442               filter_test_setup_unfiltered,
5443               unfiltered_vroot_hide_single_multi_level,
5444               filter_test_teardown);
5445   g_test_add ("/TreeModelFilter/unfiltered/hide-single-multi-level/vroot/root-expanded",
5446               FilterTest, gtk_tree_path_new_from_indices (2, -1),
5447               filter_test_setup_unfiltered_root_expanded,
5448               unfiltered_vroot_hide_single_multi_level_root_expanded,
5449               filter_test_teardown);
5450
5451
5452
5453   g_test_add ("/TreeModelFilter/unfiltered/show-single",
5454               FilterTest, NULL,
5455               filter_test_setup_empty_unfiltered,
5456               unfiltered_show_single,
5457               filter_test_teardown);
5458   g_test_add ("/TreeModelFilter/unfiltered/show-single-child",
5459               FilterTest, NULL,
5460               filter_test_setup_empty_unfiltered,
5461               unfiltered_show_single_child,
5462               filter_test_teardown);
5463   g_test_add ("/TreeModelFilter/unfiltered/show-single-child/root-expanded",
5464               FilterTest, NULL,
5465               filter_test_setup_empty_unfiltered_root_expanded,
5466               unfiltered_show_single_child_root_expanded,
5467               filter_test_teardown);
5468   g_test_add ("/TreeModelFilter/unfiltered/show-single-multi-level",
5469               FilterTest, NULL,
5470               filter_test_setup_empty_unfiltered,
5471               unfiltered_show_single_multi_level,
5472               filter_test_teardown);
5473   g_test_add ("/TreeModelFilter/unfiltered/show-single-multi-level/root-expanded",
5474               FilterTest, NULL,
5475               filter_test_setup_empty_unfiltered_root_expanded,
5476               unfiltered_show_single_multi_level_root_expanded,
5477               filter_test_teardown);
5478
5479   g_test_add ("/TreeModelFilter/unfiltered/show-single/vroot",
5480               FilterTest, gtk_tree_path_new_from_indices (2, -1),
5481               filter_test_setup_empty_unfiltered,
5482               unfiltered_vroot_show_single,
5483               filter_test_teardown);
5484   g_test_add ("/TreeModelFilter/unfiltered/show-single-child/vroot",
5485               FilterTest, gtk_tree_path_new_from_indices (2, -1),
5486               filter_test_setup_empty_unfiltered,
5487               unfiltered_vroot_show_single_child,
5488               filter_test_teardown);
5489   g_test_add ("/TreeModelFilter/unfiltered/show-single-child/vroot/root-expanded",
5490               FilterTest, gtk_tree_path_new_from_indices (2, -1),
5491               filter_test_setup_empty_unfiltered_root_expanded,
5492               unfiltered_vroot_show_single_child_root_expanded,
5493               filter_test_teardown);
5494   g_test_add ("/TreeModelFilter/unfiltered/show-single-multi-level/vroot",
5495               FilterTest, gtk_tree_path_new_from_indices (2, -1),
5496               filter_test_setup_empty_unfiltered,
5497               unfiltered_vroot_show_single_multi_level,
5498               filter_test_teardown);
5499   g_test_add ("/TreeModelFilter/unfiltered/show-single-multi-level/vroot/root-expanded",
5500               FilterTest, gtk_tree_path_new_from_indices (2, -1),
5501               filter_test_setup_empty_unfiltered_root_expanded,
5502               unfiltered_vroot_show_single_multi_level_root_expanded,
5503               filter_test_teardown);
5504
5505
5506   g_test_add ("/TreeModelFilter/unfiltered/rows-reordered/root-level",
5507               FilterTest, NULL,
5508               filter_test_setup_unfiltered,
5509               unfiltered_rows_reordered_root_level,
5510               filter_test_teardown);
5511   g_test_add ("/TreeModelFilter/unfiltered/rows-reordered/child-level",
5512               FilterTest, NULL,
5513               filter_test_setup_unfiltered,
5514               unfiltered_rows_reordered_child_level,
5515               filter_test_teardown);
5516
5517   g_test_add ("/TreeModelFilter/filtered/rows-reordered/root-level/first-hidden",
5518               FilterTest, NULL,
5519               filter_test_setup,
5520               filtered_rows_reordered_root_level_first_hidden,
5521               filter_test_teardown);
5522   g_test_add ("/TreeModelFilter/filtered/rows-reordered/root-level/middle-hidden",
5523               FilterTest, NULL,
5524               filter_test_setup,
5525               filtered_rows_reordered_root_level_middle_hidden,
5526               filter_test_teardown);
5527   g_test_add ("/TreeModelFilter/filtered/rows-reordered/child-level/first-hidden",
5528               FilterTest, NULL,
5529               filter_test_setup,
5530               filtered_rows_reordered_child_level_first_hidden,
5531               filter_test_teardown);
5532   g_test_add ("/TreeModelFilter/filtered/rows-reordered/child-level/middle-hidden",
5533               FilterTest, NULL,
5534               filter_test_setup,
5535               filtered_rows_reordered_child_level_middle_hidden,
5536               filter_test_teardown);
5537   g_test_add ("/TreeModelFilter/filtered/rows-reordered/child-level/4-hidden",
5538               FilterTest, NULL,
5539               filter_test_setup,
5540               filtered_rows_reordered_child_level_4_hidden,
5541               filter_test_teardown);
5542   g_test_add ("/TreeModelFilter/filtered/rows-reordered/child-level/all-hidden",
5543               FilterTest, NULL,
5544               filter_test_setup,
5545               filtered_rows_reordered_child_level_all_hidden,
5546               filter_test_teardown);
5547
5548   /* Inserts in child models after creation of filter model */
5549   g_test_add_func ("/TreeModelFilter/insert/before",
5550                    insert_before);
5551   g_test_add_func ("/TreeModelFilter/insert/child",
5552                    insert_child);
5553
5554   /* Removals from child model after creating of filter model */
5555   g_test_add_func ("/TreeModelFilter/remove/node",
5556                    remove_node);
5557   g_test_add_func ("/TreeModelFilter/remove/node-vroot",
5558                    remove_node_vroot);
5559   g_test_add_func ("/TreeModelFilter/remove/vroot-ancestor",
5560                    remove_vroot_ancestor);
5561
5562   /* Reference counting */
5563   g_test_add_func ("/TreeModelFilter/ref-count/single-level",
5564                    ref_count_single_level);
5565   g_test_add_func ("/TreeModelFilter/ref-count/two-levels",
5566                    ref_count_two_levels);
5567   g_test_add_func ("/TreeModelFilter/ref-count/three-levels",
5568                    ref_count_three_levels);
5569   g_test_add_func ("/TreeModelFilter/ref-count/delete-row",
5570                    ref_count_delete_row);
5571   g_test_add_func ("/TreeModelFilter/ref-count/cleanup",
5572                    ref_count_cleanup);
5573   g_test_add_func ("/TreeModelFilter/ref-count/row-ref",
5574                    ref_count_row_ref);
5575
5576   /* Reference counting, transfer of first reference on
5577    * first node in level.  This is a GtkTreeModelFilter-specific
5578    * feature.
5579    */
5580   g_test_add_func ("/TreeModelFilter/ref-count/transfer/root-level/insert",
5581                    ref_count_transfer_root_level_insert);
5582   g_test_add_func ("/TreeModelFilter/ref-count/transfer/root-level/reordered",
5583                    ref_count_transfer_root_level_reordered);
5584   g_test_add_func ("/TreeModelFilter/ref-count/transfer/root-level/reordered/filtered",
5585                    ref_count_transfer_root_level_reordered_filtered);
5586   g_test_add_func ("/TreeModelFilter/ref-count/transfer/child-level/insert",
5587                    ref_count_transfer_child_level_insert);
5588   g_test_add_func ("/TreeModelFilter/ref-count/transfer/child-level/reordered",
5589                    ref_count_transfer_child_level_reordered);
5590   g_test_add_func ("/TreeModelFilter/ref-count/transfer/child-level/reordered/filtered",
5591                    ref_count_transfer_child_level_reordered_filtered);
5592
5593   g_test_add_func ("/TreeModelFilter/specific/path-dependent-filter",
5594                    specific_path_dependent_filter);
5595   g_test_add_func ("/TreeModelFilter/specific/append-after-collapse",
5596                    specific_append_after_collapse);
5597   g_test_add_func ("/TreeModelFilter/specific/sort-filter-remove-node",
5598                    specific_sort_filter_remove_node);
5599   g_test_add_func ("/TreeModelFilter/specific/sort-filter-remove-root",
5600                    specific_sort_filter_remove_root);
5601   g_test_add_func ("/TreeModelFilter/specific/root-mixed-visibility",
5602                    specific_root_mixed_visibility);
5603   g_test_add_func ("/TreeModelFilter/specific/has-child-filter",
5604                    specific_has_child_filter);
5605   g_test_add_func ("/TreeModelFilter/specific/has-child-filter-on-sort-model",
5606                    specific_has_child_filter_on_sort_model);
5607   g_test_add_func ("/TreeModelFilter/specific/at-least-2-children-filter",
5608                    specific_at_least_2_children_filter);
5609   g_test_add_func ("/TreeModelFilter/specific/at-least-2-children-filter-on-sort-model",
5610                    specific_at_least_2_children_filter_on_sort_model);
5611   g_test_add_func ("/TreeModelFilter/specific/root-has-child-filter",
5612                    specific_root_has_child_filter);
5613   g_test_add_func ("/TreeModelFilter/specific/filter-add-child",
5614                    specific_filter_add_child);
5615   g_test_add_func ("/TreeModelFilter/specific/list-store-clear",
5616                    specific_list_store_clear);
5617   g_test_add_func ("/TreeModelFilter/specific/sort-ref-leaf-and-remove-ancestor",
5618                    specific_sort_ref_leaf_and_remove_ancestor);
5619   g_test_add_func ("/TreeModelFilter/specific/ref-leaf-and-remove-ancestor",
5620                    specific_ref_leaf_and_remove_ancestor);
5621   g_test_add_func ("/TreeModelFilter/specific/virtual-ref-leaf-and-remove-ancestor",
5622                    specific_virtual_ref_leaf_and_remove_ancestor);
5623
5624   g_test_add_func ("/TreeModelFilter/specific/bug-301558",
5625                    specific_bug_301558);
5626   g_test_add_func ("/TreeModelFilter/specific/bug-311955",
5627                    specific_bug_311955);
5628   g_test_add_func ("/TreeModelFilter/specific/bug-311955-clean",
5629                    specific_bug_311955_clean);
5630   g_test_add_func ("/TreeModelFilter/specific/bug-346800",
5631                    specific_bug_346800);
5632   g_test_add_func ("/TreeModelFilter/specific/bug-464173",
5633                    specific_bug_464173);
5634   g_test_add_func ("/TreeModelFilter/specific/bug-540201",
5635                    specific_bug_540201);
5636   g_test_add_func ("/TreeModelFilter/specific/bug-549287",
5637                    specific_bug_549287);
5638   g_test_add_func ("/TreeModelFilter/specific/bug-621076",
5639                    specific_bug_621076);
5640 }