]> Pileus Git - ~andy/gtk/blob - gtk/tests/filtermodel.c
Add unit test for ref tranfer in rows-reordered with filtered rows
[~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   /* Only the reference on the first node of the root level is kept. */
2697   assert_node_ref_count (ref_model, &parent1, 1);
2698   assert_node_ref_count (ref_model, &parent2, 0);
2699   assert_node_ref_count (ref_model, &iter_first, 0);
2700   assert_node_ref_count (ref_model, &iter, 0);
2701
2702   g_object_unref (filter_model);
2703   g_object_unref (ref_model);
2704 }
2705
2706 static void
2707 ref_count_three_levels (void)
2708 {
2709   GtkTreeIter grandparent1, grandparent2, parent1, parent2;
2710   GtkTreeIter iter_parent1, iter_parent2, iter_parent2_first;
2711   GtkTreeModel *model;
2712   GtkTreeModelRefCount *ref_model;
2713   GtkTreeModel *filter_model;
2714   GtkTreePath *path;
2715   GtkWidget *tree_view;
2716
2717   model = gtk_tree_model_ref_count_new ();
2718   ref_model = GTK_TREE_MODEL_REF_COUNT (model);
2719
2720   /* + grandparent1
2721    * + grandparent2
2722    *   + parent1
2723    *     + iter_parent1
2724    *   + parent2
2725    *     + iter_parent2_first
2726    *     + iter_parent2
2727    */
2728
2729   gtk_tree_store_append (GTK_TREE_STORE (model), &grandparent1, NULL);
2730   gtk_tree_store_append (GTK_TREE_STORE (model), &grandparent2, NULL);
2731   gtk_tree_store_append (GTK_TREE_STORE (model), &parent1, &grandparent2);
2732   gtk_tree_store_append (GTK_TREE_STORE (model), &iter_parent1, &parent1);
2733   gtk_tree_store_append (GTK_TREE_STORE (model), &parent2, &grandparent2);
2734   gtk_tree_store_append (GTK_TREE_STORE (model), &iter_parent2_first, &parent2);
2735   gtk_tree_store_append (GTK_TREE_STORE (model), &iter_parent2, &parent2);
2736
2737   assert_entire_model_unreferenced (ref_model);
2738
2739   filter_model = gtk_tree_model_filter_new (model, NULL);
2740   tree_view = gtk_tree_view_new_with_model (filter_model);
2741
2742   /* This is quite confusing:
2743    *  - node 0 has a ref count of 2 because it is referenced as the
2744    *    first node in a level and by the tree view.
2745    *  - node 1 has a ref count of 2 because it is referenced by its
2746    *    child level and by the tree view.
2747    */
2748   assert_root_level_referenced (ref_model, 2);
2749   assert_node_ref_count (ref_model, &parent1, 1);
2750   assert_node_ref_count (ref_model, &parent2, 0);
2751   assert_level_unreferenced (ref_model, &parent1);
2752   assert_level_unreferenced (ref_model, &parent2);
2753
2754   path = gtk_tree_path_new_from_indices (1, -1);
2755   gtk_tree_view_expand_row (GTK_TREE_VIEW (tree_view), path, FALSE);
2756
2757   assert_node_ref_count (ref_model, &grandparent1, 2);
2758   assert_node_ref_count (ref_model, &grandparent2, 2);
2759   assert_node_ref_count (ref_model, &parent1, 3);
2760   assert_node_ref_count (ref_model, &parent2, 2);
2761   assert_node_ref_count (ref_model, &iter_parent1, 1);
2762   assert_node_ref_count (ref_model, &iter_parent2_first, 1);
2763   assert_node_ref_count (ref_model, &iter_parent2, 0);
2764
2765   gtk_tree_view_expand_row (GTK_TREE_VIEW (tree_view), path, TRUE);
2766
2767   assert_node_ref_count (ref_model, &grandparent1, 2);
2768   assert_node_ref_count (ref_model, &grandparent2, 2);
2769   assert_node_ref_count (ref_model, &parent1, 3);
2770   assert_node_ref_count (ref_model, &parent2, 2);
2771   assert_node_ref_count (ref_model, &iter_parent1, 2);
2772   assert_node_ref_count (ref_model, &iter_parent2_first, 2);
2773   assert_node_ref_count (ref_model, &iter_parent2, 1);
2774
2775   gtk_tree_view_collapse_all (GTK_TREE_VIEW (tree_view));
2776
2777   assert_node_ref_count (ref_model, &grandparent1, 2);
2778   assert_node_ref_count (ref_model, &grandparent2, 2);
2779   assert_node_ref_count (ref_model, &parent1, 2);
2780   assert_node_ref_count (ref_model, &parent2, 1);
2781   assert_node_ref_count (ref_model, &iter_parent1, 1);
2782   assert_node_ref_count (ref_model, &iter_parent2_first, 1);
2783   assert_node_ref_count (ref_model, &iter_parent2, 0);
2784
2785   gtk_tree_model_filter_clear_cache (GTK_TREE_MODEL_FILTER (filter_model));
2786
2787   assert_node_ref_count (ref_model, &grandparent1, 2);
2788   assert_node_ref_count (ref_model, &grandparent2, 2);
2789   assert_node_ref_count (ref_model, &parent1, 1);
2790   assert_node_ref_count (ref_model, &parent2, 0);
2791   assert_node_ref_count (ref_model, &iter_parent1, 0);
2792   assert_node_ref_count (ref_model, &iter_parent2_first, 0);
2793   assert_node_ref_count (ref_model, &iter_parent2, 0);
2794
2795   gtk_tree_view_expand_row (GTK_TREE_VIEW (tree_view), path, FALSE);
2796
2797   assert_node_ref_count (ref_model, &grandparent1, 2);
2798   assert_node_ref_count (ref_model, &grandparent2, 2);
2799   assert_node_ref_count (ref_model, &parent1, 3);
2800   assert_node_ref_count (ref_model, &parent2, 2);
2801   assert_node_ref_count (ref_model, &iter_parent1, 1);
2802   assert_node_ref_count (ref_model, &iter_parent2_first, 1);
2803   assert_node_ref_count (ref_model, &iter_parent2, 0);
2804
2805   gtk_tree_path_append_index (path, 1);
2806   gtk_tree_view_expand_row (GTK_TREE_VIEW (tree_view), path, FALSE);
2807
2808   assert_node_ref_count (ref_model, &grandparent1, 2);
2809   assert_node_ref_count (ref_model, &grandparent2, 2);
2810   assert_node_ref_count (ref_model, &parent1, 3);
2811   assert_node_ref_count (ref_model, &parent2, 2);
2812   assert_node_ref_count (ref_model, &iter_parent1, 1);
2813   assert_node_ref_count (ref_model, &iter_parent2_first, 2);
2814   assert_node_ref_count (ref_model, &iter_parent2, 1);
2815
2816   gtk_tree_view_collapse_row (GTK_TREE_VIEW (tree_view), path);
2817
2818   assert_node_ref_count (ref_model, &grandparent1, 2);
2819   assert_node_ref_count (ref_model, &grandparent2, 2);
2820   assert_node_ref_count (ref_model, &parent1, 3);
2821   assert_node_ref_count (ref_model, &parent2, 2);
2822   assert_node_ref_count (ref_model, &iter_parent1, 1);
2823   assert_node_ref_count (ref_model, &iter_parent2_first, 1);
2824   assert_node_ref_count (ref_model, &iter_parent2, 0);
2825
2826   gtk_tree_model_filter_clear_cache (GTK_TREE_MODEL_FILTER (filter_model));
2827
2828   assert_node_ref_count (ref_model, &grandparent1, 2);
2829   assert_node_ref_count (ref_model, &grandparent2, 2);
2830   assert_node_ref_count (ref_model, &parent1, 3);
2831   assert_node_ref_count (ref_model, &parent2, 2);
2832   assert_node_ref_count (ref_model, &iter_parent1, 1);
2833   assert_node_ref_count (ref_model, &iter_parent2_first, 1);
2834   assert_node_ref_count (ref_model, &iter_parent2, 0);
2835
2836   gtk_tree_path_up (path);
2837   gtk_tree_view_collapse_row (GTK_TREE_VIEW (tree_view), path);
2838   gtk_tree_path_free (path);
2839
2840   assert_node_ref_count (ref_model, &grandparent1, 2);
2841   assert_node_ref_count (ref_model, &grandparent2, 2);
2842   assert_node_ref_count (ref_model, &parent1, 2);
2843   assert_node_ref_count (ref_model, &parent2, 1);
2844   assert_node_ref_count (ref_model, &iter_parent1, 1);
2845   assert_node_ref_count (ref_model, &iter_parent2_first, 1);
2846   assert_node_ref_count (ref_model, &iter_parent2, 0);
2847
2848   gtk_tree_model_filter_clear_cache (GTK_TREE_MODEL_FILTER (filter_model));
2849
2850   assert_node_ref_count (ref_model, &grandparent1, 2);
2851   assert_node_ref_count (ref_model, &grandparent2, 2);
2852   assert_node_ref_count (ref_model, &parent1, 1);
2853   assert_node_ref_count (ref_model, &parent2, 0);
2854   assert_node_ref_count (ref_model, &iter_parent1, 0);
2855   assert_node_ref_count (ref_model, &iter_parent2_first, 0);
2856   assert_node_ref_count (ref_model, &iter_parent2, 0);
2857
2858   gtk_widget_destroy (tree_view);
2859
2860   gtk_tree_model_filter_clear_cache (GTK_TREE_MODEL_FILTER (filter_model));
2861
2862   /* Only the reference on the first node of the root level is kept. */
2863   assert_node_ref_count (ref_model, &grandparent1, 1);
2864   assert_node_ref_count (ref_model, &grandparent2, 0);
2865   assert_node_ref_count (ref_model, &parent1, 0);
2866   assert_node_ref_count (ref_model, &parent2, 0);
2867   assert_node_ref_count (ref_model, &iter_parent1, 0);
2868   assert_node_ref_count (ref_model, &iter_parent2_first, 0);
2869   assert_node_ref_count (ref_model, &iter_parent2, 0);
2870
2871   g_object_unref (filter_model);
2872   g_object_unref (ref_model);
2873 }
2874
2875 static void
2876 ref_count_delete_row (void)
2877 {
2878   GtkTreeIter grandparent1, grandparent2, parent1, parent2;
2879   GtkTreeIter iter_parent1, iter_parent2, iter_parent2_first;
2880   GtkTreeModel *model;
2881   GtkTreeModelRefCount *ref_model;
2882   GtkTreeModel *filter_model;
2883   GtkTreePath *path;
2884   GtkWidget *tree_view;
2885
2886   model = gtk_tree_model_ref_count_new ();
2887   ref_model = GTK_TREE_MODEL_REF_COUNT (model);
2888
2889   /* + grandparent1
2890    * + grandparent2
2891    *   + parent1
2892    *     + iter_parent1
2893    *   + parent2
2894    *     + iter_parent2_first
2895    *     + iter_parent2
2896    */
2897
2898   gtk_tree_store_append (GTK_TREE_STORE (model), &grandparent1, NULL);
2899   gtk_tree_store_append (GTK_TREE_STORE (model), &grandparent2, NULL);
2900   gtk_tree_store_append (GTK_TREE_STORE (model), &parent1, &grandparent2);
2901   gtk_tree_store_append (GTK_TREE_STORE (model), &iter_parent1, &parent1);
2902   gtk_tree_store_append (GTK_TREE_STORE (model), &parent2, &grandparent2);
2903   gtk_tree_store_append (GTK_TREE_STORE (model), &iter_parent2_first, &parent2);
2904   gtk_tree_store_append (GTK_TREE_STORE (model), &iter_parent2, &parent2);
2905
2906   assert_entire_model_unreferenced (ref_model);
2907
2908   filter_model = gtk_tree_model_filter_new (model, NULL);
2909   tree_view = gtk_tree_view_new_with_model (filter_model);
2910
2911   assert_root_level_referenced (ref_model, 2);
2912   assert_node_ref_count (ref_model, &parent1, 1);
2913   assert_node_ref_count (ref_model, &parent2, 0);
2914   assert_level_unreferenced (ref_model, &parent1);
2915   assert_level_unreferenced (ref_model, &parent2);
2916
2917   path = gtk_tree_path_new_from_indices (1, -1);
2918   gtk_tree_view_expand_row (GTK_TREE_VIEW (tree_view), path, TRUE);
2919   gtk_tree_path_free (path);
2920
2921   assert_node_ref_count (ref_model, &grandparent1, 2);
2922   assert_node_ref_count (ref_model, &grandparent2, 2);
2923   assert_node_ref_count (ref_model, &parent1, 3);
2924   assert_node_ref_count (ref_model, &parent2, 2);
2925   assert_node_ref_count (ref_model, &iter_parent1, 2);
2926   assert_node_ref_count (ref_model, &iter_parent2_first, 2);
2927   assert_node_ref_count (ref_model, &iter_parent2, 1);
2928
2929   gtk_tree_store_remove (GTK_TREE_STORE (model), &iter_parent2);
2930
2931   assert_node_ref_count (ref_model, &grandparent1, 2);
2932   assert_node_ref_count (ref_model, &grandparent2, 2);
2933   assert_node_ref_count (ref_model, &parent1, 3);
2934   assert_node_ref_count (ref_model, &parent2, 2);
2935   assert_node_ref_count (ref_model, &iter_parent1, 2);
2936   assert_node_ref_count (ref_model, &iter_parent2_first, 2);
2937
2938   gtk_tree_store_remove (GTK_TREE_STORE (model), &parent1);
2939
2940   assert_node_ref_count (ref_model, &grandparent1, 2);
2941   assert_node_ref_count (ref_model, &grandparent2, 2);
2942   assert_node_ref_count (ref_model, &parent2, 3);
2943   assert_level_referenced (ref_model, 2, &parent2);
2944
2945   gtk_tree_store_remove (GTK_TREE_STORE (model), &grandparent2);
2946
2947   assert_node_ref_count (ref_model, &grandparent1, 2);
2948
2949   gtk_tree_model_filter_clear_cache (GTK_TREE_MODEL_FILTER (filter_model));
2950
2951   assert_node_ref_count (ref_model, &grandparent1, 2);
2952
2953   gtk_widget_destroy (tree_view);
2954   gtk_tree_model_filter_clear_cache (GTK_TREE_MODEL_FILTER (filter_model));
2955
2956   assert_node_ref_count (ref_model, &grandparent1, 1);
2957
2958   g_object_unref (filter_model);
2959
2960   assert_node_ref_count (ref_model, &grandparent1, 0);
2961
2962   g_object_unref (ref_model);
2963 }
2964
2965 static void
2966 ref_count_cleanup (void)
2967 {
2968   GtkTreeIter grandparent1, grandparent2, parent1, parent2;
2969   GtkTreeIter iter_parent1, iter_parent2, iter_parent2_first;
2970   GtkTreeModel *model;
2971   GtkTreeModelRefCount *ref_model;
2972   GtkTreeModel *filter_model;
2973   GtkWidget *tree_view;
2974
2975   model = gtk_tree_model_ref_count_new ();
2976   ref_model = GTK_TREE_MODEL_REF_COUNT (model);
2977
2978   /* + grandparent1
2979    * + grandparent2
2980    *   + parent1
2981    *     + iter_parent1
2982    *   + parent2
2983    *     + iter_parent2_first
2984    *     + iter_parent2
2985    */
2986
2987   gtk_tree_store_append (GTK_TREE_STORE (model), &grandparent1, NULL);
2988   gtk_tree_store_append (GTK_TREE_STORE (model), &grandparent2, NULL);
2989   gtk_tree_store_append (GTK_TREE_STORE (model), &parent1, &grandparent2);
2990   gtk_tree_store_append (GTK_TREE_STORE (model), &iter_parent1, &parent1);
2991   gtk_tree_store_append (GTK_TREE_STORE (model), &parent2, &grandparent2);
2992   gtk_tree_store_append (GTK_TREE_STORE (model), &iter_parent2_first, &parent2);
2993   gtk_tree_store_append (GTK_TREE_STORE (model), &iter_parent2, &parent2);
2994
2995   filter_model = gtk_tree_model_filter_new (model, NULL);
2996   tree_view = gtk_tree_view_new_with_model (filter_model);
2997
2998   gtk_tree_view_expand_all (GTK_TREE_VIEW (tree_view));
2999
3000   assert_node_ref_count (ref_model, &grandparent1, 2);
3001   assert_node_ref_count (ref_model, &grandparent2, 2);
3002   assert_node_ref_count (ref_model, &parent1, 3);
3003   assert_node_ref_count (ref_model, &parent2, 2);
3004   assert_node_ref_count (ref_model, &iter_parent1, 2);
3005   assert_node_ref_count (ref_model, &iter_parent2_first, 2);
3006   assert_node_ref_count (ref_model, &iter_parent2, 1);
3007
3008   gtk_widget_destroy (tree_view);
3009
3010   assert_node_ref_count (ref_model, &grandparent1, 1);
3011   assert_node_ref_count (ref_model, &grandparent2, 1);
3012   assert_node_ref_count (ref_model, &parent1, 2);
3013   assert_node_ref_count (ref_model, &parent2, 1);
3014   assert_node_ref_count (ref_model, &iter_parent1, 1);
3015   assert_node_ref_count (ref_model, &iter_parent2_first, 1);
3016   assert_node_ref_count (ref_model, &iter_parent2, 0);
3017
3018   gtk_tree_model_filter_clear_cache (GTK_TREE_MODEL_FILTER (filter_model));
3019
3020   /* Only the reference on the first node of the root level is kept. */
3021   assert_node_ref_count (ref_model, &grandparent1, 1);
3022   assert_node_ref_count (ref_model, &grandparent2, 0);
3023   assert_node_ref_count (ref_model, &parent1, 0);
3024   assert_node_ref_count (ref_model, &parent2, 0);
3025   assert_node_ref_count (ref_model, &iter_parent1, 0);
3026   assert_node_ref_count (ref_model, &iter_parent2_first, 0);
3027   assert_node_ref_count (ref_model, &iter_parent2, 0);
3028
3029   g_object_unref (filter_model);
3030   g_object_unref (ref_model);
3031 }
3032
3033 static void
3034 ref_count_row_ref (void)
3035 {
3036   GtkTreeIter grandparent1, grandparent2, parent1, parent2;
3037   GtkTreeIter iter_parent1, iter_parent2, iter_parent2_first;
3038   GtkTreeModel *model;
3039   GtkTreeModelRefCount *ref_model;
3040   GtkTreeModel *filter_model;
3041   GtkWidget *tree_view;
3042   GtkTreePath *path;
3043   GtkTreeRowReference *row_ref;
3044
3045   model = gtk_tree_model_ref_count_new ();
3046   ref_model = GTK_TREE_MODEL_REF_COUNT (model);
3047
3048   /* + grandparent1
3049    * + grandparent2
3050    *   + parent1
3051    *     + iter_parent1
3052    *   + parent2
3053    *     + iter_parent2
3054    *     + iter_parent2
3055    */
3056
3057   gtk_tree_store_append (GTK_TREE_STORE (model), &grandparent1, NULL);
3058   gtk_tree_store_append (GTK_TREE_STORE (model), &grandparent2, NULL);
3059   gtk_tree_store_append (GTK_TREE_STORE (model), &parent1, &grandparent2);
3060   gtk_tree_store_append (GTK_TREE_STORE (model), &iter_parent1, &parent1);
3061   gtk_tree_store_append (GTK_TREE_STORE (model), &parent2, &grandparent2);
3062   gtk_tree_store_append (GTK_TREE_STORE (model), &iter_parent2_first, &parent2);
3063   gtk_tree_store_append (GTK_TREE_STORE (model), &iter_parent2, &parent2);
3064
3065   filter_model = gtk_tree_model_filter_new (model, NULL);
3066   tree_view = gtk_tree_view_new_with_model (filter_model);
3067
3068   path = gtk_tree_path_new_from_indices (1, 1, 1, -1);
3069   row_ref = gtk_tree_row_reference_new (filter_model, path);
3070   gtk_tree_path_free (path);
3071
3072   assert_node_ref_count (ref_model, &grandparent1, 2);
3073   assert_node_ref_count (ref_model, &grandparent2, 3);
3074   assert_node_ref_count (ref_model, &parent1, 1);
3075   assert_node_ref_count (ref_model, &parent2, 2);
3076   assert_node_ref_count (ref_model, &iter_parent1, 0);
3077   assert_node_ref_count (ref_model, &iter_parent2_first, 1);
3078   assert_node_ref_count (ref_model, &iter_parent2, 1);
3079
3080   gtk_tree_row_reference_free (row_ref);
3081
3082   assert_node_ref_count (ref_model, &grandparent1, 2);
3083   assert_node_ref_count (ref_model, &grandparent2, 2);
3084   assert_node_ref_count (ref_model, &parent1, 1);
3085   assert_node_ref_count (ref_model, &parent2, 1);
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, 0);
3089
3090   path = gtk_tree_path_new_from_indices (1, 1, 1, -1);
3091   row_ref = gtk_tree_row_reference_new (filter_model, path);
3092   gtk_tree_path_free (path);
3093
3094   assert_node_ref_count (ref_model, &grandparent1, 2);
3095   assert_node_ref_count (ref_model, &grandparent2, 3);
3096   assert_node_ref_count (ref_model, &parent1, 1);
3097   assert_node_ref_count (ref_model, &parent2, 2);
3098   assert_node_ref_count (ref_model, &iter_parent1, 0);
3099   assert_node_ref_count (ref_model, &iter_parent2_first, 1);
3100   assert_node_ref_count (ref_model, &iter_parent2, 1);
3101
3102   gtk_tree_store_remove (GTK_TREE_STORE (model), &parent2);
3103
3104   assert_node_ref_count (ref_model, &grandparent1, 2);
3105   assert_node_ref_count (ref_model, &grandparent2, 2);
3106   assert_node_ref_count (ref_model, &parent1, 1);
3107   assert_node_ref_count (ref_model, &iter_parent1, 0);
3108
3109   gtk_tree_row_reference_free (row_ref);
3110
3111   assert_node_ref_count (ref_model, &grandparent1, 2);
3112   assert_node_ref_count (ref_model, &grandparent2, 2);
3113   assert_node_ref_count (ref_model, &parent1, 1);
3114   assert_node_ref_count (ref_model, &iter_parent1, 0);
3115
3116   gtk_widget_destroy (tree_view);
3117
3118   gtk_tree_model_filter_clear_cache (GTK_TREE_MODEL_FILTER (filter_model));
3119
3120   /* Only the reference on the first node of the root level is kept. */
3121   assert_node_ref_count (ref_model, &grandparent1, 1);
3122   assert_node_ref_count (ref_model, &grandparent2, 0);
3123   assert_node_ref_count (ref_model, &parent1, 0);
3124
3125   g_object_unref (filter_model);
3126   g_object_unref (ref_model);
3127 }
3128
3129 static void
3130 ref_count_transfer_root_level_insert (void)
3131 {
3132   GtkTreeIter grandparent1, grandparent2, grandparent3;
3133   GtkTreeIter new_node;
3134   GtkTreeModel *model;
3135   GtkTreeModelRefCount *ref_model;
3136   GtkTreeModel *filter_model;
3137   GtkWidget *tree_view;
3138
3139   model = gtk_tree_model_ref_count_new ();
3140   ref_model = GTK_TREE_MODEL_REF_COUNT (model);
3141
3142   /* + grandparent1
3143    * + grandparent2
3144    * + grandparent3
3145    */
3146
3147   gtk_tree_store_append (GTK_TREE_STORE (model), &grandparent1, NULL);
3148   gtk_tree_store_append (GTK_TREE_STORE (model), &grandparent2, NULL);
3149   gtk_tree_store_append (GTK_TREE_STORE (model), &grandparent3, NULL);
3150
3151   filter_model = gtk_tree_model_filter_new (model, NULL);
3152   tree_view = gtk_tree_view_new_with_model (filter_model);
3153
3154   assert_node_ref_count (ref_model, &grandparent1, 2);
3155   assert_node_ref_count (ref_model, &grandparent2, 1);
3156   assert_node_ref_count (ref_model, &grandparent3, 1);
3157
3158   gtk_tree_store_prepend (GTK_TREE_STORE (model), &new_node, NULL);
3159
3160   assert_node_ref_count (ref_model, &new_node, 2);
3161   assert_node_ref_count (ref_model, &grandparent1, 1);
3162   assert_node_ref_count (ref_model, &grandparent2, 1);
3163   assert_node_ref_count (ref_model, &grandparent3, 1);
3164
3165   gtk_widget_destroy (tree_view);
3166   g_object_unref (filter_model);
3167   g_object_unref (ref_model);
3168 }
3169
3170 static void
3171 ref_count_transfer_root_level_reordered (void)
3172 {
3173   GtkTreeIter grandparent1, grandparent2, grandparent3;
3174   GtkTreeModel *model;
3175   GtkTreeModelRefCount *ref_model;
3176   GtkTreeModel *filter_model;
3177   GtkWidget *tree_view;
3178
3179   model = gtk_tree_model_ref_count_new ();
3180   ref_model = GTK_TREE_MODEL_REF_COUNT (model);
3181
3182   /* + grandparent1
3183    * + grandparent2
3184    * + grandparent3
3185    */
3186
3187   gtk_tree_store_append (GTK_TREE_STORE (model), &grandparent1, NULL);
3188   gtk_tree_store_append (GTK_TREE_STORE (model), &grandparent2, NULL);
3189   gtk_tree_store_append (GTK_TREE_STORE (model), &grandparent3, NULL);
3190
3191   filter_model = gtk_tree_model_filter_new (model, NULL);
3192   tree_view = gtk_tree_view_new_with_model (filter_model);
3193
3194   assert_node_ref_count (ref_model, &grandparent1, 2);
3195   assert_node_ref_count (ref_model, &grandparent2, 1);
3196   assert_node_ref_count (ref_model, &grandparent3, 1);
3197
3198   /* gtk_tree_store_move() will emit rows-reordered */
3199   gtk_tree_store_move_after (GTK_TREE_STORE (model),
3200                              &grandparent1, &grandparent3);
3201
3202   assert_node_ref_count (ref_model, &grandparent2, 2);
3203   assert_node_ref_count (ref_model, &grandparent3, 1);
3204   assert_node_ref_count (ref_model, &grandparent1, 1);
3205
3206   gtk_widget_destroy (tree_view);
3207   g_object_unref (filter_model);
3208   g_object_unref (ref_model);
3209 }
3210
3211 static void
3212 ref_count_transfer_root_level_reordered_filtered (void)
3213 {
3214   GtkTreeIter grandparent1, grandparent2, grandparent3;
3215   GtkTreeModel *model;
3216   GtkTreeModelRefCount *ref_model;
3217   GtkTreeModel *filter_model;
3218   GtkWidget *tree_view;
3219   GType column_types[] = { G_TYPE_BOOLEAN };
3220
3221   model = gtk_tree_model_ref_count_new ();
3222   ref_model = GTK_TREE_MODEL_REF_COUNT (model);
3223
3224   gtk_tree_store_set_column_types (GTK_TREE_STORE (model), 1,
3225                                    column_types);
3226
3227   /* + grandparent1
3228    * + grandparent2
3229    * + grandparent3
3230    */
3231
3232   gtk_tree_store_append (GTK_TREE_STORE (model), &grandparent1, NULL);
3233   gtk_tree_store_append (GTK_TREE_STORE (model), &grandparent2, NULL);
3234   gtk_tree_store_append (GTK_TREE_STORE (model), &grandparent3, NULL);
3235
3236   /* Test with 1 node filtered */
3237   gtk_tree_store_set (GTK_TREE_STORE (model), &grandparent2, 0, TRUE, -1);
3238   gtk_tree_store_set (GTK_TREE_STORE (model), &grandparent3, 0, TRUE, -1);
3239
3240   filter_model = gtk_tree_model_filter_new (model, NULL);
3241   gtk_tree_model_filter_set_visible_column (GTK_TREE_MODEL_FILTER (filter_model), 0);
3242   tree_view = gtk_tree_view_new_with_model (filter_model);
3243
3244   assert_node_ref_count (ref_model, &grandparent1, 0);
3245   assert_node_ref_count (ref_model, &grandparent2, 2);
3246   assert_node_ref_count (ref_model, &grandparent3, 1);
3247
3248   /* gtk_tree_store_move() will emit rows-reordered */
3249   gtk_tree_store_move_after (GTK_TREE_STORE (model),
3250                              &grandparent1, &grandparent3);
3251
3252   assert_node_ref_count (ref_model, &grandparent2, 2);
3253   assert_node_ref_count (ref_model, &grandparent3, 1);
3254   assert_node_ref_count (ref_model, &grandparent1, 0);
3255
3256   /* gtk_tree_store_move() will emit rows-reordered */
3257   gtk_tree_store_move_before (GTK_TREE_STORE (model),
3258                               &grandparent1, &grandparent2);
3259
3260   assert_node_ref_count (ref_model, &grandparent1, 0);
3261   assert_node_ref_count (ref_model, &grandparent2, 2);
3262   assert_node_ref_count (ref_model, &grandparent3, 1);
3263
3264   gtk_tree_store_set (GTK_TREE_STORE (model), &grandparent1, 0, TRUE, -1);
3265
3266   assert_node_ref_count (ref_model, &grandparent1, 2);
3267   assert_node_ref_count (ref_model, &grandparent2, 1);
3268   assert_node_ref_count (ref_model, &grandparent3, 1);
3269
3270   /* Test with two nodes filtered */
3271   gtk_tree_store_set (GTK_TREE_STORE (model), &grandparent1, 0, FALSE, -1);
3272   gtk_tree_store_set (GTK_TREE_STORE (model), &grandparent2, 0, FALSE, -1);
3273
3274   assert_node_ref_count (ref_model, &grandparent1, 0);
3275   assert_node_ref_count (ref_model, &grandparent2, 0);
3276   assert_node_ref_count (ref_model, &grandparent3, 2);
3277
3278   /* gtk_tree_store_move() will emit rows-reordered */
3279   gtk_tree_store_move_before (GTK_TREE_STORE (model),
3280                              &grandparent3, &grandparent1);
3281
3282   assert_node_ref_count (ref_model, &grandparent3, 2);
3283   assert_node_ref_count (ref_model, &grandparent2, 0);
3284   assert_node_ref_count (ref_model, &grandparent1, 0);
3285
3286   gtk_widget_destroy (tree_view);
3287   g_object_unref (filter_model);
3288   g_object_unref (ref_model);
3289 }
3290
3291 static void
3292 ref_count_transfer_child_level_insert (void)
3293 {
3294   GtkTreeIter grandparent1;
3295   GtkTreeIter parent1, parent2, parent3;
3296   GtkTreeIter new_node;
3297   GtkTreeModel *model;
3298   GtkTreeModelRefCount *ref_model;
3299   GtkTreeModel *filter_model;
3300   GtkWidget *tree_view;
3301
3302   model = gtk_tree_model_ref_count_new ();
3303   ref_model = GTK_TREE_MODEL_REF_COUNT (model);
3304
3305   /* + grandparent1
3306    *   + parent1
3307    *   + parent2
3308    *   + parent3
3309    */
3310
3311   gtk_tree_store_append (GTK_TREE_STORE (model), &grandparent1, NULL);
3312   gtk_tree_store_append (GTK_TREE_STORE (model), &parent1, &grandparent1);
3313   gtk_tree_store_append (GTK_TREE_STORE (model), &parent2, &grandparent1);
3314   gtk_tree_store_append (GTK_TREE_STORE (model), &parent3, &grandparent1);
3315
3316   filter_model = gtk_tree_model_filter_new (model, NULL);
3317   tree_view = gtk_tree_view_new_with_model (filter_model);
3318
3319   assert_node_ref_count (ref_model, &grandparent1, 3);
3320   assert_node_ref_count (ref_model, &parent1, 1);
3321   assert_node_ref_count (ref_model, &parent2, 0);
3322   assert_node_ref_count (ref_model, &parent3, 0);
3323
3324   gtk_tree_store_prepend (GTK_TREE_STORE (model), &new_node, &grandparent1);
3325
3326   assert_node_ref_count (ref_model, &grandparent1, 3);
3327   assert_node_ref_count (ref_model, &new_node, 1);
3328   assert_node_ref_count (ref_model, &parent1, 0);
3329   assert_node_ref_count (ref_model, &parent2, 0);
3330   assert_node_ref_count (ref_model, &parent3, 0);
3331
3332   gtk_widget_destroy (tree_view);
3333   g_object_unref (filter_model);
3334   g_object_unref (ref_model);
3335 }
3336
3337 static void
3338 ref_count_transfer_child_level_reordered (void)
3339 {
3340   GtkTreeIter grandparent1;
3341   GtkTreeIter parent1, parent2, parent3;
3342   GtkTreeModel *model;
3343   GtkTreeModelRefCount *ref_model;
3344   GtkTreeModel *filter_model;
3345   GtkWidget *tree_view;
3346
3347   model = gtk_tree_model_ref_count_new ();
3348   ref_model = GTK_TREE_MODEL_REF_COUNT (model);
3349
3350   /* + grandparent1
3351    *   + parent1
3352    *   + parent2
3353    *   + parent3
3354    */
3355
3356   gtk_tree_store_append (GTK_TREE_STORE (model), &grandparent1, NULL);
3357   gtk_tree_store_append (GTK_TREE_STORE (model), &parent1, &grandparent1);
3358   gtk_tree_store_append (GTK_TREE_STORE (model), &parent2, &grandparent1);
3359   gtk_tree_store_append (GTK_TREE_STORE (model), &parent3, &grandparent1);
3360
3361   filter_model = gtk_tree_model_filter_new (model, NULL);
3362   tree_view = gtk_tree_view_new_with_model (filter_model);
3363
3364   assert_node_ref_count (ref_model, &grandparent1, 3);
3365   assert_node_ref_count (ref_model, &parent1, 1);
3366   assert_node_ref_count (ref_model, &parent2, 0);
3367   assert_node_ref_count (ref_model, &parent3, 0);
3368
3369   /* gtk_tree_store_move() will emit rows-reordered */
3370   gtk_tree_store_move_after (GTK_TREE_STORE (model),
3371                              &parent1, &parent3);
3372
3373   assert_node_ref_count (ref_model, &grandparent1, 3);
3374   assert_node_ref_count (ref_model, &parent2, 1);
3375   assert_node_ref_count (ref_model, &parent3, 0);
3376   assert_node_ref_count (ref_model, &parent1, 0);
3377
3378   gtk_widget_destroy (tree_view);
3379   g_object_unref (filter_model);
3380   g_object_unref (ref_model);
3381 }
3382
3383 static void
3384 ref_count_transfer_child_level_reordered_filtered (void)
3385 {
3386   GtkTreeIter grandparent1;
3387   GtkTreeIter parent1, parent2, parent3;
3388   GtkTreeModel *model;
3389   GtkTreeModelRefCount *ref_model;
3390   GtkTreeModel *filter_model;
3391   GtkWidget *tree_view;
3392   GType column_types[] = { G_TYPE_BOOLEAN };
3393
3394   model = gtk_tree_model_ref_count_new ();
3395   ref_model = GTK_TREE_MODEL_REF_COUNT (model);
3396
3397   gtk_tree_store_set_column_types (GTK_TREE_STORE (model), 1,
3398                                    column_types);
3399
3400   /* + grandparent1
3401    *   + parent1
3402    *   + parent2
3403    *   + parent3
3404    */
3405
3406   gtk_tree_store_append (GTK_TREE_STORE (model), &grandparent1, NULL);
3407   gtk_tree_store_append (GTK_TREE_STORE (model), &parent1, &grandparent1);
3408   gtk_tree_store_append (GTK_TREE_STORE (model), &parent2, &grandparent1);
3409   gtk_tree_store_append (GTK_TREE_STORE (model), &parent3, &grandparent1);
3410
3411   /* Test with 1 node filtered (parent1) */
3412   gtk_tree_store_set (GTK_TREE_STORE (model), &grandparent1, 0, TRUE, -1);
3413   gtk_tree_store_set (GTK_TREE_STORE (model), &parent2, 0, TRUE, -1);
3414   gtk_tree_store_set (GTK_TREE_STORE (model), &parent3, 0, TRUE, -1);
3415
3416   filter_model = gtk_tree_model_filter_new (model, NULL);
3417   gtk_tree_model_filter_set_visible_column (GTK_TREE_MODEL_FILTER (filter_model), 0);
3418   tree_view = gtk_tree_view_new_with_model (filter_model);
3419
3420   assert_node_ref_count (ref_model, &grandparent1, 3);
3421   assert_node_ref_count (ref_model, &parent1, 0);
3422   assert_node_ref_count (ref_model, &parent2, 1);
3423   assert_node_ref_count (ref_model, &parent3, 0);
3424
3425   /* gtk_tree_store_move() will emit rows-reordered */
3426   gtk_tree_store_move_after (GTK_TREE_STORE (model),
3427                              &parent1, &parent3);
3428
3429   assert_node_ref_count (ref_model, &grandparent1, 3);
3430   assert_node_ref_count (ref_model, &parent2, 1);
3431   assert_node_ref_count (ref_model, &parent3, 0);
3432   assert_node_ref_count (ref_model, &parent1, 0);
3433
3434   /* gtk_tree_store_move() will emit rows-reordered */
3435   gtk_tree_store_move_before (GTK_TREE_STORE (model),
3436                               &parent1, &parent2);
3437
3438   assert_node_ref_count (ref_model, &grandparent1, 3);
3439   assert_node_ref_count (ref_model, &parent1, 0);
3440   assert_node_ref_count (ref_model, &parent2, 1);
3441   assert_node_ref_count (ref_model, &parent3, 0);
3442
3443   gtk_tree_store_set (GTK_TREE_STORE (model), &parent1, 0, TRUE, -1);
3444
3445   assert_node_ref_count (ref_model, &parent1, 1);
3446   assert_node_ref_count (ref_model, &parent2, 0);
3447   assert_node_ref_count (ref_model, &parent3, 0);
3448
3449   /* Test with two nodes filtered */
3450   gtk_tree_store_set (GTK_TREE_STORE (model), &parent1, 0, FALSE, -1);
3451   gtk_tree_store_set (GTK_TREE_STORE (model), &parent2, 0, FALSE, -1);
3452
3453   assert_node_ref_count (ref_model, &parent1, 0);
3454   assert_node_ref_count (ref_model, &parent2, 0);
3455   assert_node_ref_count (ref_model, &parent3, 1);
3456
3457   /* gtk_tree_store_move() will emit rows-reordered */
3458   gtk_tree_store_move_before (GTK_TREE_STORE (model),
3459                              &parent3, &parent1);
3460
3461   assert_node_ref_count (ref_model, &parent3, 1);
3462   assert_node_ref_count (ref_model, &parent2, 0);
3463   assert_node_ref_count (ref_model, &parent1, 0);
3464
3465   gtk_widget_destroy (tree_view);
3466   g_object_unref (filter_model);
3467   g_object_unref (ref_model);
3468 }
3469
3470 static gboolean
3471 specific_path_dependent_filter_func (GtkTreeModel *model,
3472                                      GtkTreeIter  *iter,
3473                                      gpointer      data)
3474 {
3475   GtkTreePath *path;
3476
3477   path = gtk_tree_model_get_path (model, iter);
3478   if (gtk_tree_path_get_indices (path)[0] < 4)
3479     return FALSE;
3480
3481   return TRUE;
3482 }
3483
3484 static void
3485 specific_path_dependent_filter (void)
3486 {
3487   int i;
3488   GtkTreeIter iter;
3489   GtkListStore *list;
3490   GtkTreeModel *sort;
3491   GtkTreeModel *filter;
3492
3493   list = gtk_list_store_new (1, G_TYPE_INT);
3494   gtk_list_store_insert_with_values (list, &iter, 0, 0, 1, -1);
3495   gtk_list_store_insert_with_values (list, &iter, 1, 0, 2, -1);
3496   gtk_list_store_insert_with_values (list, &iter, 2, 0, 3, -1);
3497   gtk_list_store_insert_with_values (list, &iter, 3, 0, 4, -1);
3498   gtk_list_store_insert_with_values (list, &iter, 4, 0, 5, -1);
3499   gtk_list_store_insert_with_values (list, &iter, 5, 0, 6, -1);
3500   gtk_list_store_insert_with_values (list, &iter, 6, 0, 7, -1);
3501   gtk_list_store_insert_with_values (list, &iter, 7, 0, 8, -1);
3502
3503   sort = gtk_tree_model_sort_new_with_model (GTK_TREE_MODEL (list));
3504   filter = gtk_tree_model_filter_new (GTK_TREE_MODEL (sort), NULL);
3505   gtk_tree_model_filter_set_visible_func (GTK_TREE_MODEL_FILTER (filter),
3506                                           specific_path_dependent_filter_func,
3507                                           NULL, NULL);
3508
3509   gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (sort), 0,
3510                                         GTK_SORT_DESCENDING);
3511
3512   for (i = 0; i < 4; i++)
3513     {
3514       if (gtk_tree_model_iter_nth_child (GTK_TREE_MODEL (list), &iter,
3515                                          NULL, 1))
3516         gtk_list_store_remove (list, &iter);
3517
3518       if (gtk_tree_model_iter_nth_child (GTK_TREE_MODEL (list), &iter,
3519                                          NULL, 2))
3520         gtk_list_store_remove (list, &iter);
3521     }
3522
3523   g_object_unref (filter);
3524   g_object_unref (sort);
3525   g_object_unref (list);
3526 }
3527
3528
3529 static gboolean
3530 specific_append_after_collapse_visible_func (GtkTreeModel *model,
3531                                              GtkTreeIter  *iter,
3532                                              gpointer      data)
3533 {
3534   gint number;
3535   gboolean hide_negative_numbers;
3536
3537   gtk_tree_model_get (model, iter, 1, &number, -1);
3538   hide_negative_numbers = GPOINTER_TO_INT (g_object_get_data (data, "private-hide-negative-numbers"));
3539
3540   return (number >= 0 || !hide_negative_numbers);
3541 }
3542
3543 static void
3544 specific_append_after_collapse (void)
3545 {
3546   /* This test is based on one of the test cases I found in my
3547    * old test cases directory.  I unfortunately do not have a record
3548    * from who this test case originated.  -Kris.
3549    *
3550    * General idea:
3551    * - Construct tree.
3552    * - Show tree, expand, collapse.
3553    * - Add a row.
3554    */
3555
3556   GtkTreeIter iter;
3557   GtkTreeIter child_iter;
3558   GtkTreeIter child_iter2;
3559   GtkTreePath *append_path;
3560   GtkTreeStore *store;
3561   GtkTreeModel *filter;
3562   GtkTreeModel *sort;
3563
3564   GtkWidget *window;
3565   GtkWidget *tree_view;
3566
3567   store = gtk_tree_store_new (2, G_TYPE_STRING, G_TYPE_INT);
3568
3569   filter = gtk_tree_model_filter_new (GTK_TREE_MODEL (store), NULL);
3570   g_object_set_data (G_OBJECT (filter), "private-hide-negative-numbers",
3571                      GINT_TO_POINTER (FALSE));
3572   gtk_tree_model_filter_set_visible_func (GTK_TREE_MODEL_FILTER (filter),
3573                                           specific_append_after_collapse_visible_func,
3574                                           filter, NULL);
3575
3576   sort = gtk_tree_model_sort_new_with_model (filter);
3577
3578   window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
3579   tree_view = gtk_tree_view_new_with_model (sort);
3580   gtk_container_add (GTK_CONTAINER (window), tree_view);
3581   gtk_widget_realize (tree_view);
3582
3583   while (gtk_events_pending ())
3584     gtk_main_iteration ();
3585
3586   gtk_tree_store_prepend (store, &iter, NULL);
3587   gtk_tree_store_set (store, &iter,
3588                       0, "hallo", 1, 1, -1);
3589
3590   gtk_tree_store_append (store, &child_iter, &iter);
3591   gtk_tree_store_set (store, &child_iter,
3592                       0, "toemaar", 1, 1, -1);
3593
3594   gtk_tree_store_append (store, &child_iter2, &child_iter);
3595   gtk_tree_store_set (store, &child_iter2,
3596                       0, "very deep", 1, 1, -1);
3597
3598   append_path = gtk_tree_model_get_path (GTK_TREE_MODEL (store), &child_iter2);
3599
3600   gtk_tree_store_append (store, &child_iter, &iter);
3601   gtk_tree_store_set (store, &child_iter,
3602                       0, "sja", 1, 1, -1);
3603
3604   gtk_tree_store_append (store, &child_iter, &iter);
3605   gtk_tree_store_set (store, &child_iter,
3606                       0, "some word", 1, -1, -1);
3607
3608   /* Expand and collapse the tree */
3609   gtk_tree_view_expand_all (GTK_TREE_VIEW (tree_view));
3610   while (gtk_events_pending ())
3611     gtk_main_iteration ();
3612
3613   gtk_tree_view_collapse_all (GTK_TREE_VIEW (tree_view));
3614   while (gtk_events_pending ())
3615     gtk_main_iteration ();
3616
3617   /* Add another it */
3618   g_object_set_data (G_OBJECT (filter), "private-hide-negative-numbers",
3619                      GINT_TO_POINTER (TRUE));
3620
3621   if (gtk_tree_model_get_iter (GTK_TREE_MODEL (store), &iter, append_path))
3622     {
3623       gtk_tree_store_append (store, &child_iter, &iter);
3624       gtk_tree_store_set (store, &child_iter,
3625                           0, "new new new !!", 1, 1, -1);
3626     }
3627   gtk_tree_path_free (append_path);
3628
3629   /* Expand */
3630   gtk_tree_view_expand_all (GTK_TREE_VIEW (tree_view));
3631   while (gtk_events_pending ())
3632     gtk_main_iteration ();
3633 }
3634
3635
3636 static gint
3637 specific_sort_filter_remove_node_compare_func (GtkTreeModel  *model,
3638                                                GtkTreeIter   *iter1,
3639                                                GtkTreeIter   *iter2,
3640                                                gpointer       data)
3641 {
3642   return -1;
3643 }
3644
3645 static gboolean
3646 specific_sort_filter_remove_node_visible_func (GtkTreeModel  *model,
3647                                                GtkTreeIter   *iter,
3648                                                gpointer       data)
3649 {
3650   char *item = NULL;
3651
3652   /* Do reference the model */
3653   gtk_tree_model_get (model, iter, 0, &item, -1);
3654   g_free (item);
3655
3656   return FALSE;
3657 }
3658
3659 static void
3660 specific_sort_filter_remove_node (void)
3661 {
3662   /* This test is based on one of the test cases I found in my
3663    * old test cases directory.  I unfortunately do not have a record
3664    * from who this test case originated.  -Kris.
3665    *
3666    * General idea:
3667    *  - Create tree store, sort, filter models.  The sort model has
3668    *    a default sort func that is enabled, filter model a visible func
3669    *    that defaults to returning FALSE.
3670    *  - Remove a node from the tree store.
3671    */
3672
3673   GtkTreeIter iter;
3674   GtkTreeStore *store;
3675   GtkTreeModel *filter;
3676   GtkTreeModel *sort;
3677
3678   GtkWidget *window;
3679   GtkWidget *tree_view;
3680
3681   store = gtk_tree_store_new (1, G_TYPE_STRING);
3682   gtk_tree_store_append (store, &iter, NULL);
3683   gtk_tree_store_set (store, &iter, 0, "Hello1", -1);
3684
3685   gtk_tree_store_append (store, &iter, NULL);
3686   gtk_tree_store_set (store, &iter, 0, "Hello2", -1);
3687
3688   sort = gtk_tree_model_sort_new_with_model (GTK_TREE_MODEL (store));
3689   gtk_tree_sortable_set_default_sort_func (GTK_TREE_SORTABLE (sort),
3690                                            specific_sort_filter_remove_node_compare_func, NULL, NULL);
3691
3692   filter = gtk_tree_model_filter_new (sort, NULL);
3693   gtk_tree_model_filter_set_visible_func (GTK_TREE_MODEL_FILTER (filter),
3694                                           specific_sort_filter_remove_node_visible_func,
3695                                           filter, NULL);
3696
3697
3698   window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
3699   tree_view = gtk_tree_view_new_with_model (filter);
3700   gtk_container_add (GTK_CONTAINER (window), tree_view);
3701   gtk_widget_realize (tree_view);
3702
3703   while (gtk_events_pending ())
3704     gtk_main_iteration ();
3705
3706   /* Remove a node */
3707   gtk_tree_model_get_iter_first (GTK_TREE_MODEL (store), &iter);
3708   gtk_tree_model_iter_next (GTK_TREE_MODEL (store), &iter);
3709   gtk_tree_store_remove (store, &iter);
3710
3711   while (gtk_events_pending ())
3712     gtk_main_iteration ();
3713 }
3714
3715
3716 static void
3717 specific_sort_filter_remove_root (void)
3718 {
3719   /* This test is based on one of the test cases I found in my
3720    * old test cases directory.  I unfortunately do not have a record
3721    * from who this test case originated.  -Kris.
3722    */
3723
3724   GtkTreeModel *model, *sort, *filter;
3725   GtkTreeIter root, mid, leaf;
3726   GtkTreePath *path;
3727
3728   model = GTK_TREE_MODEL (gtk_tree_store_new (1, G_TYPE_INT));
3729   gtk_tree_store_append (GTK_TREE_STORE (model), &root, NULL);
3730   gtk_tree_store_append (GTK_TREE_STORE (model), &mid, &root);
3731   gtk_tree_store_append (GTK_TREE_STORE (model), &leaf, &mid);
3732
3733   path = gtk_tree_model_get_path (model, &mid);
3734
3735   sort = gtk_tree_model_sort_new_with_model (model);
3736   filter = gtk_tree_model_filter_new (sort, path);
3737
3738   gtk_tree_path_free (path);
3739
3740   gtk_tree_store_remove (GTK_TREE_STORE (model), &root);
3741
3742   g_object_unref (filter);
3743   g_object_unref (sort);
3744   g_object_unref (model);
3745 }
3746
3747
3748 static void
3749 specific_root_mixed_visibility (void)
3750 {
3751   int i;
3752   GtkTreeModel *filter;
3753   /* A bit nasty, apologies */
3754   FilterTest fixture;
3755
3756   fixture.store = gtk_tree_store_new (2, G_TYPE_STRING, G_TYPE_BOOLEAN);
3757
3758   for (i = 0; i < LEVEL_LENGTH; i++)
3759     {
3760       GtkTreeIter iter;
3761
3762       gtk_tree_store_insert (fixture.store, &iter, NULL, i);
3763       if (i % 2 == 0)
3764         create_tree_store_set_values (fixture.store, &iter, TRUE);
3765       else
3766         create_tree_store_set_values (fixture.store, &iter, FALSE);
3767     }
3768
3769   filter = gtk_tree_model_filter_new (GTK_TREE_MODEL (fixture.store), NULL);
3770   fixture.filter = GTK_TREE_MODEL_FILTER (filter);
3771   fixture.monitor = NULL;
3772
3773   gtk_tree_model_filter_set_visible_column (fixture.filter, 1);
3774
3775   /* In order to trigger the potential bug, we should not access
3776    * the filter model here (so don't call the check functions).
3777    */
3778
3779   /* Change visibility of an odd row to TRUE */
3780   set_path_visibility (&fixture, "3", TRUE);
3781   check_filter_model (&fixture);
3782   check_level_length (fixture.filter, NULL, 4);
3783 }
3784
3785
3786
3787 static gboolean
3788 specific_has_child_filter_filter_func (GtkTreeModel *model,
3789                                        GtkTreeIter  *iter,
3790                                        gpointer      data)
3791 {
3792   return gtk_tree_model_iter_has_child (model, iter);
3793 }
3794
3795 static void
3796 specific_has_child_filter (void)
3797 {
3798   GtkTreeModel *filter;
3799   GtkTreeIter iter, root;
3800   FilterTest fixture; /* This is not how it should be done */
3801   GtkWidget *tree_view;
3802
3803   fixture.store = gtk_tree_store_new (2, G_TYPE_STRING, G_TYPE_BOOLEAN);
3804   filter = gtk_tree_model_filter_new (GTK_TREE_MODEL (fixture.store), NULL);
3805   fixture.filter = GTK_TREE_MODEL_FILTER (filter);
3806   fixture.monitor = signal_monitor_new (filter);
3807
3808   tree_view = gtk_tree_view_new_with_model (filter);
3809
3810   /* We will filter on parent state using a filter function.  We will
3811    * manually keep the boolean column in sync, so that we can use
3812    * check_filter_model() to check the consistency of the model.
3813    */
3814   /* FIXME: We need a check_filter_model() that is not tied to LEVEL_LENGTH
3815    * to be able to check the structure here.  We keep the calls to
3816    * check_filter_model() commented out until then.
3817    */
3818   gtk_tree_model_filter_set_visible_func (fixture.filter,
3819                                           specific_has_child_filter_filter_func,
3820                                           NULL, NULL);
3821
3822   /* The first node will be initially invisible: no signals */
3823   gtk_tree_store_append (fixture.store, &root, NULL);
3824   create_tree_store_set_values (fixture.store, &root, FALSE);
3825
3826   /* check_filter_model (&fixture); */
3827   check_level_length (fixture.filter, NULL, 0);
3828   signal_monitor_assert_is_empty (fixture.monitor);
3829
3830   /* Insert a child node. This will cause the parent to become visible
3831    * since there is a child now.
3832    */
3833   signal_monitor_append_signal (fixture.monitor, ROW_INSERTED, "0");
3834   signal_monitor_append_signal (fixture.monitor, ROW_HAS_CHILD_TOGGLED, "0");
3835   signal_monitor_append_signal (fixture.monitor, ROW_HAS_CHILD_TOGGLED, "0");
3836
3837   gtk_tree_store_append (fixture.store, &iter, &root);
3838   create_tree_store_set_values (fixture.store, &iter, TRUE);
3839
3840   /* Parent must now be visible.  Do the level length check first,
3841    * to avoid modifying the child model triggering a row-changed to
3842    * the filter model.
3843    */
3844   check_level_length (fixture.filter, NULL, 1);
3845   check_level_length (fixture.filter, "0", 0);
3846   signal_monitor_assert_is_empty (fixture.monitor);
3847
3848   /* This should propagate row-changed */
3849   signal_monitor_append_signal (fixture.monitor, ROW_CHANGED, "0");
3850   signal_monitor_append_signal (fixture.monitor, ROW_HAS_CHILD_TOGGLED, "0");
3851
3852   set_path_visibility (&fixture, "0", TRUE);
3853   /* check_filter_model (&fixture); */
3854   signal_monitor_assert_is_empty (fixture.monitor);
3855
3856   /* New root node, no child, so no signal */
3857   gtk_tree_store_append (fixture.store, &root, NULL);
3858   check_level_length (fixture.filter, NULL, 1);
3859   signal_monitor_assert_is_empty (fixture.monitor);
3860
3861   /* When the child comes in, this node will become visible */
3862   signal_monitor_append_signal (fixture.monitor, ROW_INSERTED, "1");
3863   signal_monitor_append_signal (fixture.monitor, ROW_HAS_CHILD_TOGGLED, "1");
3864   signal_monitor_append_signal (fixture.monitor, ROW_HAS_CHILD_TOGGLED, "1");
3865   signal_monitor_append_signal (fixture.monitor, ROW_CHANGED, "1");
3866   signal_monitor_append_signal (fixture.monitor, ROW_HAS_CHILD_TOGGLED, "1");
3867
3868   gtk_tree_store_append (fixture.store, &iter, &root);
3869   check_level_length (fixture.filter, NULL, 2);
3870   check_level_length (fixture.filter, "1", 0);
3871
3872   create_tree_store_set_values (fixture.store, &root, TRUE);
3873   create_tree_store_set_values (fixture.store, &iter, TRUE);
3874
3875   /* check_filter_model (&fixture); */
3876   signal_monitor_assert_is_empty (fixture.monitor);
3877
3878   /* Add another child for 1 */
3879   gtk_tree_store_append (fixture.store, &iter, &root);
3880   create_tree_store_set_values (fixture.store, &iter, TRUE);
3881   check_level_length (fixture.filter, NULL, 2);
3882   check_level_length (fixture.filter, "0", 0);
3883   check_level_length (fixture.filter, "1", 0);
3884   signal_monitor_assert_is_empty (fixture.monitor);
3885
3886   /* Now remove one of the remaining child rows */
3887   signal_monitor_append_signal (fixture.monitor, ROW_DELETED, "0");
3888
3889   gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL (fixture.store),
3890                                        &iter, "0:0");
3891   gtk_tree_store_remove (fixture.store, &iter);
3892
3893   check_level_length (fixture.filter, NULL, 1);
3894   check_level_length (fixture.filter, "0", 0);
3895
3896   set_path_visibility (&fixture, "0", FALSE);
3897   /* check_filter_model (&fixture); */
3898   signal_monitor_assert_is_empty (fixture.monitor);
3899 }
3900
3901
3902 static gboolean
3903 specific_root_has_child_filter_filter_func (GtkTreeModel *model,
3904                                             GtkTreeIter  *iter,
3905                                             gpointer      data)
3906 {
3907   int depth;
3908   GtkTreePath *path;
3909
3910   path = gtk_tree_model_get_path (model, iter);
3911   depth = gtk_tree_path_get_depth (path);
3912   gtk_tree_path_free (path);
3913
3914   if (depth > 1)
3915     return TRUE;
3916   /* else */
3917   return gtk_tree_model_iter_has_child (model, iter);
3918 }
3919
3920 static void
3921 specific_root_has_child_filter (void)
3922 {
3923   GtkTreeModel *filter;
3924   GtkTreeIter iter, root;
3925   FilterTest fixture; /* This is not how it should be done ... */
3926   GtkWidget *tree_view;
3927
3928   /* This is a variation on the above test case, specific has-child-filter,
3929    * herein the has-child check for visibility only applies to root level
3930    * nodes.  In this test, children are always visible because we
3931    * only filter based on the "has child" criterion.
3932    */
3933
3934   fixture.store = gtk_tree_store_new (2, G_TYPE_STRING, G_TYPE_BOOLEAN);
3935   filter = gtk_tree_model_filter_new (GTK_TREE_MODEL (fixture.store), NULL);
3936   fixture.filter = GTK_TREE_MODEL_FILTER (filter);
3937   fixture.monitor = signal_monitor_new (filter);
3938
3939   tree_view = gtk_tree_view_new_with_model (filter);
3940
3941   /* We will filter on parent state using a filter function.  We will
3942    * manually keep the boolean column in sync, so that we can use
3943    * check_filter_model() to check the consistency of the model.
3944    */
3945   /* FIXME: We need a check_filter_model() that is not tied to LEVEL_LENGTH
3946    * to be able to check the structure here.  We keep the calls to
3947    * check_filter_model() commented out until then.
3948    */
3949   gtk_tree_model_filter_set_visible_func (fixture.filter,
3950                                           specific_root_has_child_filter_filter_func,
3951                                           NULL, NULL);
3952
3953   /* Add a first node, this will be invisible initially, so no signal
3954    * should be emitted.
3955    */
3956   gtk_tree_store_append (fixture.store, &root, NULL);
3957   create_tree_store_set_values (fixture.store, &root, FALSE);
3958
3959   signal_monitor_assert_is_empty (fixture.monitor);
3960   /* check_filter_model (&fixture); */
3961   check_level_length (fixture.filter, NULL, 0);
3962
3963   /* Add a child node.  This will cause the parent to become visible,
3964    * so we expect row-inserted signals for both.
3965    */
3966   signal_monitor_append_signal (fixture.monitor, ROW_INSERTED, "0");
3967   signal_monitor_append_signal (fixture.monitor, ROW_HAS_CHILD_TOGGLED, "0");
3968   signal_monitor_append_signal (fixture.monitor, ROW_HAS_CHILD_TOGGLED, "0");
3969
3970   gtk_tree_store_append (fixture.store, &iter, &root);
3971   signal_monitor_assert_is_empty (fixture.monitor);
3972
3973   check_level_length (fixture.filter, NULL, 1);
3974   check_level_length (fixture.filter, "0", 1);
3975
3976   /* Modify the content of iter, no signals because the parent is not
3977    * expanded.
3978    */
3979   create_tree_store_set_values (fixture.store, &iter, TRUE);
3980   signal_monitor_assert_is_empty (fixture.monitor);
3981
3982   /* Parent must now be visible.  Do the level length check first,
3983    * to avoid modifying the child model triggering a row-changed to
3984    * the filter model.
3985    */
3986   check_level_length (fixture.filter, NULL, 1);
3987   check_level_length (fixture.filter, "0", 1);
3988
3989   /* Modify path 0 */
3990   signal_monitor_append_signal (fixture.monitor, ROW_CHANGED, "0");
3991   signal_monitor_append_signal (fixture.monitor, ROW_HAS_CHILD_TOGGLED, "0");
3992
3993   set_path_visibility (&fixture, "0", TRUE);
3994   /* check_filter_model (&fixture); */
3995
3996   signal_monitor_assert_is_empty (fixture.monitor);
3997
3998   /* Insert another node in the root level.  Initially invisible, so
3999    * not expecting any signal.
4000    */
4001   gtk_tree_store_append (fixture.store, &root, NULL);
4002   check_level_length (fixture.filter, NULL, 1);
4003
4004   signal_monitor_assert_is_empty (fixture.monitor);
4005
4006   /* Adding a child node which also makes parent at path 1 visible. */
4007   signal_monitor_append_signal (fixture.monitor, ROW_INSERTED, "1");
4008   signal_monitor_append_signal (fixture.monitor, ROW_HAS_CHILD_TOGGLED, "1");
4009   signal_monitor_append_signal (fixture.monitor, ROW_HAS_CHILD_TOGGLED, "1");
4010
4011   gtk_tree_store_append (fixture.store, &iter, &root);
4012   check_level_length (fixture.filter, NULL, 2);
4013   check_level_length (fixture.filter, "1", 1);
4014
4015   signal_monitor_assert_is_empty (fixture.monitor);
4016
4017   /* Check if row-changed is propagated */
4018   signal_monitor_append_signal (fixture.monitor, ROW_CHANGED, "1");
4019   signal_monitor_append_signal (fixture.monitor, ROW_HAS_CHILD_TOGGLED, "1");
4020
4021   create_tree_store_set_values (fixture.store, &root, TRUE);
4022   create_tree_store_set_values (fixture.store, &iter, TRUE);
4023   /* check_filter_model (&fixture); */
4024   signal_monitor_assert_is_empty (fixture.monitor);
4025
4026   /* Insert another child under node 1 */
4027   gtk_tree_store_append (fixture.store, &iter, &root);
4028   create_tree_store_set_values (fixture.store, &iter, TRUE);
4029   check_level_length (fixture.filter, NULL, 2);
4030   check_level_length (fixture.filter, "0", 1);
4031   check_level_length (fixture.filter, "1", 2);
4032   signal_monitor_assert_is_empty (fixture.monitor);
4033
4034   /* Set a child node to invisible.  This should not yield any
4035    * change, because filtering is only done on whether the root
4036    * node has a child, which it still has.
4037    */
4038   set_path_visibility (&fixture, "0:0", FALSE);
4039   signal_monitor_assert_is_empty (fixture.monitor);
4040
4041   /* Now remove one of the remaining child rows */
4042   signal_monitor_append_signal (fixture.monitor, ROW_HAS_CHILD_TOGGLED, "0");
4043   signal_monitor_append_signal (fixture.monitor, ROW_DELETED, "0");
4044
4045   gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL (fixture.store),
4046                                        &iter, "0:0");
4047   gtk_tree_store_remove (fixture.store, &iter);
4048
4049   check_level_length (fixture.filter, NULL, 1);
4050   check_level_length (fixture.filter, "0", 2);
4051   signal_monitor_assert_is_empty (fixture.monitor);
4052
4053   /* Set visibility of 0 to FALSE, no-op for filter model since
4054    * the child 0:0 is already gone
4055    */
4056   set_path_visibility (&fixture, "0", FALSE);
4057   /* check_filter_model (&fixture); */
4058   signal_monitor_assert_is_empty (fixture.monitor);
4059 }
4060
4061 static void
4062 specific_has_child_filter_on_sort_model (void)
4063 {
4064   GtkTreeModel *filter;
4065   GtkTreeModel *sort_model;
4066   GtkTreeIter iter, root;
4067   FilterTest fixture; /* This is not how it should be done */
4068   GtkWidget *tree_view;
4069
4070   fixture.store = gtk_tree_store_new (2, G_TYPE_STRING, G_TYPE_BOOLEAN);
4071   sort_model = gtk_tree_model_sort_new_with_model (GTK_TREE_MODEL (fixture.store));
4072   filter = gtk_tree_model_filter_new (sort_model, NULL);
4073   fixture.filter = GTK_TREE_MODEL_FILTER (filter);
4074   fixture.monitor = signal_monitor_new (filter);
4075
4076   tree_view = gtk_tree_view_new_with_model (filter);
4077
4078   /* We will filter on parent state using a filter function.  We will
4079    * manually keep the boolean column in sync, so that we can use
4080    * check_filter_model() to check the consistency of the model.
4081    */
4082   /* FIXME: We need a check_filter_model() that is not tied to LEVEL_LENGTH
4083    * to be able to check the structure here.  We keep the calls to
4084    * check_filter_model() commented out until then.
4085    */
4086   gtk_tree_model_filter_set_visible_func (fixture.filter,
4087                                           specific_has_child_filter_filter_func,
4088                                           NULL, NULL);
4089
4090   /* The first node will be initially invisible: no signals */
4091   gtk_tree_store_append (fixture.store, &root, NULL);
4092   create_tree_store_set_values (fixture.store, &root, FALSE);
4093
4094   /* check_filter_model (&fixture); */
4095   check_level_length (fixture.filter, NULL, 0);
4096   signal_monitor_assert_is_empty (fixture.monitor);
4097
4098   /* Insert a child node. This will cause the parent to become visible
4099    * since there is a child now.
4100    */
4101   signal_monitor_append_signal (fixture.monitor, ROW_INSERTED, "0");
4102   signal_monitor_append_signal (fixture.monitor, ROW_HAS_CHILD_TOGGLED, "0");
4103
4104   gtk_tree_store_append (fixture.store, &iter, &root);
4105   create_tree_store_set_values (fixture.store, &iter, TRUE);
4106
4107   /* Parent must now be visible.  Do the level length check first,
4108    * to avoid modifying the child model triggering a row-changed to
4109    * the filter model.
4110    */
4111   check_level_length (fixture.filter, NULL, 1);
4112   check_level_length (fixture.filter, "0", 0);
4113   signal_monitor_assert_is_empty (fixture.monitor);
4114
4115   /* This should propagate row-changed */
4116   signal_monitor_append_signal (fixture.monitor, ROW_CHANGED, "0");
4117   signal_monitor_append_signal (fixture.monitor, ROW_HAS_CHILD_TOGGLED, "0");
4118
4119   set_path_visibility (&fixture, "0", TRUE);
4120   /* check_filter_model (&fixture); */
4121   signal_monitor_assert_is_empty (fixture.monitor);
4122
4123   /* New root node, no child, so no signal */
4124   gtk_tree_store_append (fixture.store, &root, NULL);
4125   check_level_length (fixture.filter, NULL, 1);
4126   signal_monitor_assert_is_empty (fixture.monitor);
4127
4128   /* When the child comes in, this node will become visible */
4129   signal_monitor_append_signal (fixture.monitor, ROW_INSERTED, "1");
4130   signal_monitor_append_signal (fixture.monitor, ROW_HAS_CHILD_TOGGLED, "1");
4131   signal_monitor_append_signal (fixture.monitor, ROW_CHANGED, "1");
4132   signal_monitor_append_signal (fixture.monitor, ROW_HAS_CHILD_TOGGLED, "1");
4133
4134   gtk_tree_store_append (fixture.store, &iter, &root);
4135   check_level_length (fixture.filter, NULL, 2);
4136   check_level_length (fixture.filter, "1", 0);
4137
4138   create_tree_store_set_values (fixture.store, &root, TRUE);
4139   create_tree_store_set_values (fixture.store, &iter, TRUE);
4140
4141   /* check_filter_model (&fixture); */
4142   signal_monitor_assert_is_empty (fixture.monitor);
4143
4144   /* Add another child for 1 */
4145   gtk_tree_store_append (fixture.store, &iter, &root);
4146   create_tree_store_set_values (fixture.store, &iter, TRUE);
4147   check_level_length (fixture.filter, NULL, 2);
4148   check_level_length (fixture.filter, "0", 0);
4149   check_level_length (fixture.filter, "1", 0);
4150   signal_monitor_assert_is_empty (fixture.monitor);
4151
4152   /* Now remove one of the remaining child rows */
4153   signal_monitor_append_signal (fixture.monitor, ROW_DELETED, "0");
4154
4155   gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL (fixture.store),
4156                                        &iter, "0:0");
4157   gtk_tree_store_remove (fixture.store, &iter);
4158
4159   check_level_length (fixture.filter, NULL, 1);
4160   check_level_length (fixture.filter, "0", 0);
4161
4162   set_path_visibility (&fixture, "0", FALSE);
4163   /* check_filter_model (&fixture); */
4164   signal_monitor_assert_is_empty (fixture.monitor);
4165 }
4166
4167 static gboolean
4168 specific_at_least_2_children_filter_filter_func (GtkTreeModel *model,
4169                                                  GtkTreeIter  *iter,
4170                                                  gpointer      data)
4171 {
4172   return gtk_tree_model_iter_n_children (model, iter) >= 2;
4173 }
4174
4175 static void
4176 specific_at_least_2_children_filter (void)
4177 {
4178   GtkTreeModel *filter;
4179   GtkTreeIter iter, root;
4180   FilterTest fixture; /* This is not how it should be done */
4181   GtkWidget *tree_view;
4182
4183   fixture.store = gtk_tree_store_new (2, G_TYPE_STRING, G_TYPE_BOOLEAN);
4184   filter = gtk_tree_model_filter_new (GTK_TREE_MODEL (fixture.store), NULL);
4185   fixture.filter = GTK_TREE_MODEL_FILTER (filter);
4186   fixture.monitor = signal_monitor_new (filter);
4187
4188   tree_view = gtk_tree_view_new_with_model (filter);
4189
4190   gtk_tree_model_filter_set_visible_func (fixture.filter,
4191                                           specific_at_least_2_children_filter_filter_func,
4192                                           NULL, NULL);
4193
4194   /* The first node will be initially invisible: no signals */
4195   gtk_tree_store_append (fixture.store, &root, NULL);
4196   create_tree_store_set_values (fixture.store, &root, FALSE);
4197
4198   /* check_filter_model (&fixture); */
4199   check_level_length (fixture.filter, NULL, 0);
4200   signal_monitor_assert_is_empty (fixture.monitor);
4201
4202   /* Insert a child node.  Nothing should happen.
4203    */
4204   gtk_tree_store_append (fixture.store, &iter, &root);
4205   create_tree_store_set_values (fixture.store, &iter, TRUE);
4206
4207   check_level_length (fixture.filter, NULL, 0);
4208   signal_monitor_assert_is_empty (fixture.monitor);
4209
4210   /* Insert a second child node.  This will cause the parent to become
4211    * visible.
4212    */
4213   signal_monitor_append_signal (fixture.monitor, ROW_INSERTED, "0");
4214   signal_monitor_append_signal (fixture.monitor, ROW_HAS_CHILD_TOGGLED, "0");
4215
4216   gtk_tree_store_append (fixture.store, &iter, &root);
4217   create_tree_store_set_values (fixture.store, &iter, TRUE);
4218
4219   /* Parent must now be visible.  Do the level length check first,
4220    * to avoid modifying the child model triggering a row-changed to
4221    * the filter model.
4222    */
4223   check_level_length (fixture.filter, NULL, 1);
4224   check_level_length (fixture.filter, "0", 0);
4225   signal_monitor_assert_is_empty (fixture.monitor);
4226
4227   /* This should propagate row-changed */
4228   signal_monitor_append_signal (fixture.monitor, ROW_CHANGED, "0");
4229   signal_monitor_append_signal (fixture.monitor, ROW_HAS_CHILD_TOGGLED, "0");
4230
4231   set_path_visibility (&fixture, "0", TRUE);
4232   /* check_filter_model (&fixture); */
4233   signal_monitor_assert_is_empty (fixture.monitor);
4234
4235   /* New root node, no child, so no signal */
4236   gtk_tree_store_append (fixture.store, &root, NULL);
4237   check_level_length (fixture.filter, NULL, 1);
4238   signal_monitor_assert_is_empty (fixture.monitor);
4239
4240   /* First child, no signal, no change */
4241   gtk_tree_store_append (fixture.store, &iter, &root);
4242   check_level_length (fixture.filter, NULL, 1);
4243   signal_monitor_assert_is_empty (fixture.monitor);
4244
4245   /* When the second child comes in, this node will become visible */
4246   signal_monitor_append_signal (fixture.monitor, ROW_INSERTED, "1");
4247   signal_monitor_append_signal (fixture.monitor, ROW_HAS_CHILD_TOGGLED, "1");
4248   signal_monitor_append_signal (fixture.monitor, ROW_CHANGED, "1");
4249   signal_monitor_append_signal (fixture.monitor, ROW_HAS_CHILD_TOGGLED, "1");
4250
4251   gtk_tree_store_append (fixture.store, &iter, &root);
4252   check_level_length (fixture.filter, NULL, 2);
4253   check_level_length (fixture.filter, "1", 0);
4254
4255   create_tree_store_set_values (fixture.store, &root, TRUE);
4256   create_tree_store_set_values (fixture.store, &iter, TRUE);
4257
4258   /* check_filter_model (&fixture); */
4259   signal_monitor_assert_is_empty (fixture.monitor);
4260
4261   /* Add another child for 1 */
4262   gtk_tree_store_append (fixture.store, &iter, &root);
4263   create_tree_store_set_values (fixture.store, &iter, TRUE);
4264   check_level_length (fixture.filter, NULL, 2);
4265   check_level_length (fixture.filter, "0", 0);
4266   check_level_length (fixture.filter, "1", 0);
4267   signal_monitor_assert_is_empty (fixture.monitor);
4268
4269   /* Now remove one of the remaining child rows */
4270   signal_monitor_append_signal (fixture.monitor, ROW_DELETED, "0");
4271
4272   gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL (fixture.store),
4273                                        &iter, "0:0");
4274   gtk_tree_store_remove (fixture.store, &iter);
4275
4276   check_level_length (fixture.filter, NULL, 1);
4277   check_level_length (fixture.filter, "0", 0);
4278
4279   set_path_visibility (&fixture, "0", FALSE);
4280   /* check_filter_model (&fixture); */
4281   signal_monitor_assert_is_empty (fixture.monitor);
4282 }
4283
4284 static void
4285 specific_at_least_2_children_filter_on_sort_model (void)
4286 {
4287   GtkTreeModel *filter;
4288   GtkTreeModel *sort_model;
4289   GtkTreeIter iter, root;
4290   FilterTest fixture; /* This is not how it should be done */
4291   GtkWidget *tree_view;
4292
4293   fixture.store = gtk_tree_store_new (2, G_TYPE_STRING, G_TYPE_BOOLEAN);
4294   sort_model = gtk_tree_model_sort_new_with_model (GTK_TREE_MODEL (fixture.store));
4295   filter = gtk_tree_model_filter_new (sort_model, NULL);
4296   fixture.filter = GTK_TREE_MODEL_FILTER (filter);
4297   fixture.monitor = signal_monitor_new (filter);
4298
4299   tree_view = gtk_tree_view_new_with_model (filter);
4300
4301   gtk_tree_model_filter_set_visible_func (fixture.filter,
4302                                           specific_at_least_2_children_filter_filter_func,
4303                                           NULL, NULL);
4304
4305   /* The first node will be initially invisible: no signals */
4306   gtk_tree_store_append (fixture.store, &root, NULL);
4307   create_tree_store_set_values (fixture.store, &root, FALSE);
4308
4309   /* check_filter_model (&fixture); */
4310   check_level_length (fixture.filter, NULL, 0);
4311   signal_monitor_assert_is_empty (fixture.monitor);
4312
4313   /* Insert a child node.  Nothing should happen.
4314    */
4315   gtk_tree_store_append (fixture.store, &iter, &root);
4316   create_tree_store_set_values (fixture.store, &iter, TRUE);
4317
4318   check_level_length (fixture.filter, NULL, 0);
4319   signal_monitor_assert_is_empty (fixture.monitor);
4320
4321     {
4322       GtkTreePath *path = gtk_tree_path_new_from_indices (0, 0, -1);
4323       GtkTreeRowReference *ref;
4324
4325       ref = gtk_tree_row_reference_new (sort_model, path);
4326       gtk_tree_path_free (path);
4327     }
4328
4329   /* Insert a second child node.  This will cause the parent to become
4330    * visible.
4331    */
4332   signal_monitor_append_signal (fixture.monitor, ROW_INSERTED, "0");
4333   signal_monitor_append_signal (fixture.monitor, ROW_HAS_CHILD_TOGGLED, "0");
4334
4335   gtk_tree_store_append (fixture.store, &iter, &root);
4336   create_tree_store_set_values (fixture.store, &iter, TRUE);
4337
4338   /* Parent must now be visible.  Do the level length check first,
4339    * to avoid modifying the child model triggering a row-changed to
4340    * the filter model.
4341    */
4342   check_level_length (fixture.filter, NULL, 1);
4343   check_level_length (fixture.filter, "0", 0);
4344   signal_monitor_assert_is_empty (fixture.monitor);
4345
4346   /* This should propagate row-changed */
4347   signal_monitor_append_signal (fixture.monitor, ROW_CHANGED, "0");
4348   signal_monitor_append_signal (fixture.monitor, ROW_HAS_CHILD_TOGGLED, "0");
4349
4350   set_path_visibility (&fixture, "0", TRUE);
4351   /* check_filter_model (&fixture); */
4352   signal_monitor_assert_is_empty (fixture.monitor);
4353
4354   /* New root node, no child, so no signal */
4355   gtk_tree_store_append (fixture.store, &root, NULL);
4356   check_level_length (fixture.filter, NULL, 1);
4357   signal_monitor_assert_is_empty (fixture.monitor);
4358 }
4359
4360
4361 static void
4362 specific_filter_add_child (void)
4363 {
4364   /* This test is based on one of the test cases I found in my
4365    * old test cases directory.  I unfortunately do not have a record
4366    * from who this test case originated.  -Kris.
4367    */
4368
4369   GtkTreeIter iter;
4370   GtkTreeIter iter_first;
4371   GtkTreeIter child;
4372   GtkTreeStore *store;
4373   GtkTreeModel *filter G_GNUC_UNUSED;
4374
4375   store = gtk_tree_store_new (1, G_TYPE_STRING);
4376
4377   gtk_tree_store_append (store, &iter_first, NULL);
4378   gtk_tree_store_set (store, &iter_first, 0, "Hello", -1);
4379
4380   gtk_tree_store_append (store, &iter, NULL);
4381   gtk_tree_store_set (store, &iter, 0, "Hello", -1);
4382
4383   gtk_tree_store_append (store, &iter, NULL);
4384   gtk_tree_store_set (store, &iter, 0, "Hello", -1);
4385
4386   gtk_tree_store_append (store, &iter, NULL);
4387   gtk_tree_store_set (store, &iter, 0, "Hello", -1);
4388
4389   filter = gtk_tree_model_filter_new (GTK_TREE_MODEL (store), NULL);
4390
4391   gtk_tree_store_set (store, &iter, 0, "Hello", -1);
4392   gtk_tree_store_append (store, &child, &iter_first);
4393   gtk_tree_store_set (store, &child, 0, "Hello", -1);
4394 }
4395
4396 static void
4397 specific_list_store_clear (void)
4398 {
4399   GtkTreeIter iter;
4400   GtkListStore *list;
4401   GtkTreeModel *filter;
4402   GtkWidget *view G_GNUC_UNUSED;
4403
4404   list = gtk_list_store_new (1, G_TYPE_INT);
4405   gtk_list_store_insert_with_values (list, &iter, 0, 0, 1, -1);
4406   gtk_list_store_insert_with_values (list, &iter, 1, 0, 2, -1);
4407   gtk_list_store_insert_with_values (list, &iter, 2, 0, 3, -1);
4408   gtk_list_store_insert_with_values (list, &iter, 3, 0, 4, -1);
4409   gtk_list_store_insert_with_values (list, &iter, 4, 0, 5, -1);
4410   gtk_list_store_insert_with_values (list, &iter, 5, 0, 6, -1);
4411   gtk_list_store_insert_with_values (list, &iter, 6, 0, 7, -1);
4412   gtk_list_store_insert_with_values (list, &iter, 7, 0, 8, -1);
4413
4414   filter = gtk_tree_model_filter_new (GTK_TREE_MODEL (list), NULL);
4415   view = gtk_tree_view_new_with_model (filter);
4416
4417   gtk_list_store_clear (list);
4418 }
4419
4420 static void
4421 specific_sort_ref_leaf_and_remove_ancestor (void)
4422 {
4423   GtkTreeIter iter, child, child2, child3;
4424   GtkTreeStore *tree;
4425   GtkTreeModel *sort;
4426   GtkTreePath *path;
4427   GtkTreeRowReference *rowref;
4428   GtkWidget *view G_GNUC_UNUSED;
4429
4430   tree = gtk_tree_store_new (1, G_TYPE_INT);
4431   gtk_tree_store_insert_with_values (tree, &iter, NULL, 0, 0, 1, -1);
4432   gtk_tree_store_insert_with_values (tree, &iter, NULL, 1, 0, 2, -1);
4433   gtk_tree_store_insert_with_values (tree, &iter, NULL, 2, 0, 3, -1);
4434   gtk_tree_store_insert_with_values (tree, &iter, NULL, 3, 0, 4, -1);
4435
4436   gtk_tree_store_insert_with_values (tree, &child, &iter, 0, 0, 50, -1);
4437   gtk_tree_store_insert_with_values (tree, &child2, &child, 0, 0, 6, -1);
4438   gtk_tree_store_insert_with_values (tree, &child3, &child2, 0, 0, 7, -1);
4439
4440   sort = gtk_tree_model_sort_new_with_model (GTK_TREE_MODEL (tree));
4441   view = gtk_tree_view_new_with_model (sort);
4442   gtk_tree_view_expand_all (GTK_TREE_VIEW (view));
4443
4444   path = gtk_tree_path_new_from_indices (3, 0, 0, 0, -1);
4445   rowref = gtk_tree_row_reference_new (sort, path);
4446   gtk_tree_path_free (path);
4447
4448   path = gtk_tree_path_new_from_indices (3, 0, 0, 0, -1);
4449   rowref = gtk_tree_row_reference_new (sort, path);
4450   gtk_tree_path_free (path);
4451
4452   path = gtk_tree_path_new_from_indices (3, 0, -1);
4453   rowref = gtk_tree_row_reference_new (sort, path);
4454   gtk_tree_path_free (path);
4455
4456   path = gtk_tree_path_new_from_indices (3, -1);
4457   rowref = gtk_tree_row_reference_new (sort, path);
4458   gtk_tree_path_free (path);
4459
4460   /* Deleting a parent */
4461   path = gtk_tree_path_new_from_indices (3, 0, -1);
4462   gtk_tree_model_get_iter (GTK_TREE_MODEL (tree), &iter, path);
4463   gtk_tree_store_remove (tree, &iter);
4464   gtk_tree_path_free (path);
4465
4466   gtk_tree_row_reference_free (rowref);
4467 }
4468
4469 static void
4470 specific_ref_leaf_and_remove_ancestor (void)
4471 {
4472   GtkTreeIter iter, child, child2, child3;
4473   GtkTreeStore *tree;
4474   GtkTreeModel *filter;
4475   GtkTreePath *path;
4476   GtkTreeRowReference *rowref;
4477   GtkWidget *view G_GNUC_UNUSED;
4478
4479   tree = gtk_tree_store_new (1, G_TYPE_INT);
4480   gtk_tree_store_insert_with_values (tree, &iter, NULL, 0, 0, 1, -1);
4481   gtk_tree_store_insert_with_values (tree, &iter, NULL, 1, 0, 2, -1);
4482   gtk_tree_store_insert_with_values (tree, &iter, NULL, 2, 0, 3, -1);
4483   gtk_tree_store_insert_with_values (tree, &iter, NULL, 3, 0, 4, -1);
4484
4485   gtk_tree_store_insert_with_values (tree, &child, &iter, 0, 0, 50, -1);
4486   gtk_tree_store_insert_with_values (tree, &child2, &child, 0, 0, 6, -1);
4487   gtk_tree_store_insert_with_values (tree, &child3, &child2, 0, 0, 7, -1);
4488
4489   filter = gtk_tree_model_filter_new (GTK_TREE_MODEL (tree), NULL);
4490   view = gtk_tree_view_new_with_model (filter);
4491   gtk_tree_view_expand_all (GTK_TREE_VIEW (view));
4492
4493   path = gtk_tree_path_new_from_indices (3, 0, 0, 0, -1);
4494   rowref = gtk_tree_row_reference_new (filter, path);
4495   gtk_tree_path_free (path);
4496
4497   path = gtk_tree_path_new_from_indices (3, 0, 0, 0, -1);
4498   rowref = gtk_tree_row_reference_new (filter, path);
4499   gtk_tree_path_free (path);
4500
4501   path = gtk_tree_path_new_from_indices (3, 0, -1);
4502   rowref = gtk_tree_row_reference_new (filter, path);
4503   gtk_tree_path_free (path);
4504
4505   path = gtk_tree_path_new_from_indices (3, -1);
4506   rowref = gtk_tree_row_reference_new (filter, path);
4507   gtk_tree_path_free (path);
4508
4509   /* Deleting a parent */
4510   path = gtk_tree_path_new_from_indices (3, 0, -1);
4511   gtk_tree_model_get_iter (GTK_TREE_MODEL (tree), &iter, path);
4512   gtk_tree_store_remove (tree, &iter);
4513   gtk_tree_path_free (path);
4514
4515   gtk_tree_row_reference_free (rowref);
4516 }
4517
4518 static void
4519 specific_virtual_ref_leaf_and_remove_ancestor (void)
4520 {
4521   GtkTreeIter iter, child, child2, child3;
4522   GtkTreeStore *tree;
4523   GtkTreeModel *filter;
4524   GtkTreePath *path;
4525   GtkTreeRowReference *rowref;
4526   GtkWidget *view G_GNUC_UNUSED;
4527
4528   tree = gtk_tree_store_new (1, G_TYPE_INT);
4529   gtk_tree_store_insert_with_values (tree, &iter, NULL, 0, 0, 1, -1);
4530   gtk_tree_store_insert_with_values (tree, &iter, NULL, 1, 0, 2, -1);
4531   gtk_tree_store_insert_with_values (tree, &iter, NULL, 2, 0, 3, -1);
4532   gtk_tree_store_insert_with_values (tree, &iter, NULL, 3, 0, 4, -1);
4533
4534   gtk_tree_store_insert_with_values (tree, &child, &iter, 0, 0, 50, -1);
4535   gtk_tree_store_insert_with_values (tree, &child2, &child, 0, 0, 6, -1);
4536   gtk_tree_store_insert_with_values (tree, &child3, &child2, 0, 0, 7, -1);
4537
4538   /* Set a virtual root of 3:0 */
4539   path = gtk_tree_path_new_from_indices (3, 0, -1);
4540   filter = gtk_tree_model_filter_new (GTK_TREE_MODEL (tree), path);
4541   gtk_tree_path_free (path);
4542
4543   view = gtk_tree_view_new_with_model (filter);
4544   gtk_tree_view_expand_all (GTK_TREE_VIEW (view));
4545
4546   path = gtk_tree_path_new_from_indices (0, 0, -1);
4547   rowref = gtk_tree_row_reference_new (filter, path);
4548   gtk_tree_path_free (path);
4549
4550   path = gtk_tree_path_new_from_indices (0, 0, -1);
4551   rowref = gtk_tree_row_reference_new (filter, path);
4552   gtk_tree_path_free (path);
4553
4554   path = gtk_tree_path_new_from_indices (0, -1);
4555   rowref = gtk_tree_row_reference_new (filter, path);
4556   gtk_tree_path_free (path);
4557
4558   /* Deleting the virtual root */
4559   path = gtk_tree_path_new_from_indices (3, 0, -1);
4560   gtk_tree_model_get_iter (GTK_TREE_MODEL (tree), &iter, path);
4561   gtk_tree_store_remove (tree, &iter);
4562   gtk_tree_path_free (path);
4563
4564   gtk_tree_row_reference_free (rowref);
4565 }
4566
4567
4568 static int
4569 specific_bug_301558_sort_func (GtkTreeModel *model,
4570                                GtkTreeIter  *a,
4571                                GtkTreeIter  *b,
4572                                gpointer      data)
4573 {
4574   int i, j;
4575
4576   gtk_tree_model_get (model, a, 0, &i, -1);
4577   gtk_tree_model_get (model, b, 0, &j, -1);
4578
4579   return j - i;
4580 }
4581
4582 static void
4583 specific_bug_301558 (void)
4584 {
4585   /* Test case for GNOME Bugzilla bug 301558 provided by
4586    * Markku Vire.
4587    */
4588   GtkTreeStore *tree;
4589   GtkTreeModel *filter;
4590   GtkTreeModel *sort;
4591   GtkTreeIter root, iter, iter2;
4592   GtkWidget *view G_GNUC_UNUSED;
4593   int i;
4594   gboolean add;
4595
4596   g_test_bug ("301558");
4597
4598   tree = gtk_tree_store_new (2, G_TYPE_INT, G_TYPE_BOOLEAN);
4599   gtk_tree_store_append (tree, &iter, NULL);
4600   gtk_tree_store_set (tree, &iter, 0, 123, 1, TRUE, -1);
4601   gtk_tree_store_append (tree, &iter2, &iter);
4602   gtk_tree_store_set (tree, &iter2, 0, 73, 1, TRUE, -1);
4603
4604   sort = gtk_tree_model_sort_new_with_model (GTK_TREE_MODEL (tree));
4605   gtk_tree_sortable_set_default_sort_func (GTK_TREE_SORTABLE (sort),
4606                                            specific_bug_301558_sort_func,
4607                                            NULL, NULL);
4608
4609   filter = gtk_tree_model_filter_new (sort, NULL);
4610   gtk_tree_model_filter_set_visible_column (GTK_TREE_MODEL_FILTER (filter), 1);
4611
4612   view = gtk_tree_view_new_with_model (filter);
4613
4614   while (gtk_events_pending ())
4615     gtk_main_iteration ();
4616
4617   add = TRUE;
4618
4619   for (i = 0; i < 10; i++)
4620     {
4621       if (!gtk_tree_model_get_iter_first (GTK_TREE_MODEL (tree), &root))
4622         g_assert_not_reached ();
4623
4624       if (add)
4625         {
4626           gtk_tree_store_append (tree, &iter, &root);
4627           gtk_tree_store_set (tree, &iter, 0, 456, 1, TRUE, -1);
4628         }
4629       else
4630         {
4631           int n;
4632           n = gtk_tree_model_iter_n_children (GTK_TREE_MODEL (tree), &root);
4633           gtk_tree_model_iter_nth_child (GTK_TREE_MODEL (tree), &iter,
4634                                          &root, n - 1);
4635           gtk_tree_store_remove (tree, &iter);
4636         }
4637
4638       add = !add;
4639     }
4640 }
4641
4642
4643 static gboolean
4644 specific_bug_311955_filter_func (GtkTreeModel *model,
4645                                  GtkTreeIter  *iter,
4646                                  gpointer      data)
4647 {
4648   int value;
4649
4650   gtk_tree_model_get (model, iter, 0, &value, -1);
4651
4652   return (value != 0);
4653 }
4654
4655 static void
4656 specific_bug_311955 (void)
4657 {
4658   /* This is a test case for GNOME Bugzilla bug 311955.  It was written
4659    * by Markku Vire.
4660    */
4661   GtkTreeIter iter, child, root;
4662   GtkTreeStore *store;
4663   GtkTreeModel *sort;
4664   GtkTreeModel *filter;
4665
4666   GtkWidget *window G_GNUC_UNUSED;
4667   GtkWidget *tree_view;
4668   int i;
4669   int n;
4670   GtkTreePath *path;
4671
4672   g_test_bug ("311955");
4673
4674   store = gtk_tree_store_new (1, G_TYPE_INT);
4675
4676   gtk_tree_store_append (store, &root, NULL);
4677   gtk_tree_store_set (store, &root, 0, 33, -1);
4678
4679   gtk_tree_store_append (store, &iter, &root);
4680   gtk_tree_store_set (store, &iter, 0, 50, -1);
4681
4682   gtk_tree_store_append (store, &iter, NULL);
4683   gtk_tree_store_set (store, &iter, 0, 22, -1);
4684
4685   sort = gtk_tree_model_sort_new_with_model (GTK_TREE_MODEL (store));
4686   filter = gtk_tree_model_filter_new (sort, NULL);
4687
4688   gtk_tree_model_filter_set_visible_func (GTK_TREE_MODEL_FILTER (filter),
4689                                           specific_bug_311955_filter_func,
4690                                           NULL, NULL);
4691
4692   window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
4693   tree_view = gtk_tree_view_new_with_model (filter);
4694   g_object_unref (store);
4695
4696   gtk_tree_view_expand_all (GTK_TREE_VIEW (tree_view));
4697
4698   while (gtk_events_pending ())
4699     gtk_main_iteration ();
4700
4701   check_level_length (GTK_TREE_MODEL_FILTER (filter), NULL, 2);
4702   check_level_length (GTK_TREE_MODEL_FILTER (filter), "0", 1);
4703
4704   /* Fill model */
4705   for (i = 0; i < 4; i++)
4706     {
4707       gtk_tree_model_get_iter_first (GTK_TREE_MODEL (store), &root);
4708
4709       gtk_tree_store_append (store, &iter, &root);
4710
4711       if (i < 3)
4712         gtk_tree_store_set (store, &iter, 0, i, -1);
4713
4714       if (i % 2 == 0)
4715         {
4716           gtk_tree_store_append (store, &child, &iter);
4717           gtk_tree_store_set (store, &child, 0, 10, -1);
4718         }
4719     }
4720
4721   while (gtk_events_pending ())
4722     gtk_main_iteration ();
4723
4724   check_level_length (GTK_TREE_MODEL_FILTER (filter), "0", 3);
4725   check_level_length (GTK_TREE_MODEL_FILTER (filter), "0:2", 1);
4726
4727   /* Remove bottommost child from the tree. */
4728   gtk_tree_model_get_iter_first (GTK_TREE_MODEL (store), &root);
4729   n = gtk_tree_model_iter_n_children (GTK_TREE_MODEL (store), &root);
4730
4731   if (gtk_tree_model_iter_nth_child (GTK_TREE_MODEL (store), &iter, &root, n - 2))
4732     {
4733       if (gtk_tree_model_iter_children (GTK_TREE_MODEL (store), &child, &iter))
4734         gtk_tree_store_remove (store, &child);
4735     }
4736   else
4737     g_assert_not_reached ();
4738
4739   path = gtk_tree_path_new_from_indices (0, 2, -1);
4740   gtk_tree_view_expand_row (GTK_TREE_VIEW (tree_view), path, FALSE);
4741   gtk_tree_path_free (path);
4742
4743   check_level_length (GTK_TREE_MODEL_FILTER (filter), "0", 3);
4744   check_level_length (GTK_TREE_MODEL_FILTER (filter), "0:2", 0);
4745 }
4746
4747 static void
4748 specific_bug_311955_clean (void)
4749 {
4750   /* Cleaned up version of the test case for GNOME Bugzilla bug 311955,
4751    * which is easier to understand.
4752    */
4753   GtkTreeIter iter, child, grandchild;
4754   GtkTreeStore *store;
4755   GtkTreeModel *sort;
4756   GtkTreeModel *filter;
4757
4758   GtkWidget *tree_view;
4759   GtkTreePath *path;
4760
4761   store = gtk_tree_store_new (1, G_TYPE_INT);
4762
4763   gtk_tree_store_append (store, &iter, NULL);
4764   gtk_tree_store_set (store, &iter, 0, 1, -1);
4765
4766   gtk_tree_store_append (store, &child, &iter);
4767   gtk_tree_store_set (store, &child, 0, 1, -1);
4768
4769   sort = gtk_tree_model_sort_new_with_model (GTK_TREE_MODEL (store));
4770   filter = gtk_tree_model_filter_new (sort, NULL);
4771
4772   gtk_tree_model_filter_set_visible_func (GTK_TREE_MODEL_FILTER (filter),
4773                                           specific_bug_311955_filter_func,
4774                                           NULL, NULL);
4775
4776   tree_view = gtk_tree_view_new_with_model (filter);
4777   g_object_unref (store);
4778
4779   gtk_tree_view_expand_all (GTK_TREE_VIEW (tree_view));
4780
4781   while (gtk_events_pending ())
4782     gtk_main_iteration ();
4783
4784   check_level_length (GTK_TREE_MODEL_FILTER (filter), NULL, 1);
4785   check_level_length (GTK_TREE_MODEL_FILTER (filter), "0", 1);
4786
4787   gtk_tree_model_get_iter_first (GTK_TREE_MODEL (store), &iter);
4788
4789   gtk_tree_store_append (store, &child, &iter);
4790   gtk_tree_store_set (store, &child, 0, 0, -1);
4791
4792   gtk_tree_store_append (store, &child, &iter);
4793   gtk_tree_store_set (store, &child, 0, 1, -1);
4794
4795   gtk_tree_store_append (store, &child, &iter);
4796   gtk_tree_store_set (store, &child, 0, 1, -1);
4797
4798   gtk_tree_store_append (store, &grandchild, &child);
4799   gtk_tree_store_set (store, &grandchild, 0, 1, -1);
4800
4801   gtk_tree_store_append (store, &child, &iter);
4802   /* Don't set a value: assume 0 */
4803
4804   /* Remove leaf node, check trigger row-has-child-toggled */
4805   path = gtk_tree_path_new_from_indices (0, 3, 0, -1);
4806   gtk_tree_model_get_iter (GTK_TREE_MODEL (store), &iter, path);
4807   gtk_tree_path_free (path);
4808   gtk_tree_store_remove (store, &iter);
4809
4810   path = gtk_tree_path_new_from_indices (0, 2, -1);
4811   gtk_tree_view_expand_row (GTK_TREE_VIEW (tree_view), path, FALSE);
4812   gtk_tree_path_free (path);
4813
4814   check_level_length (GTK_TREE_MODEL_FILTER (filter), "0", 3);
4815   check_level_length (GTK_TREE_MODEL_FILTER (filter), "0:2", 0);
4816
4817   gtk_widget_destroy (tree_view);
4818 }
4819
4820 static void
4821 specific_bug_346800 (void)
4822 {
4823   /* This is a test case for GNOME Bugzilla bug 346800.  It was written
4824    * by Jonathan Matthew.
4825    */
4826
4827   GtkTreeIter node_iters[50];
4828   GtkTreeIter child_iters[50];
4829   GtkTreeModel *model;
4830   GtkTreeModelFilter *filter;
4831   GtkTreeStore *store;
4832   GType *columns;
4833   int i;
4834   int items = 50;
4835   columns = g_new (GType, 2);
4836   columns[0] = G_TYPE_STRING;
4837   columns[1] = G_TYPE_BOOLEAN;
4838   store = gtk_tree_store_newv (2, columns);
4839   model = GTK_TREE_MODEL (store);
4840
4841   g_test_bug ("346800");
4842
4843   filter = GTK_TREE_MODEL_FILTER (gtk_tree_model_filter_new (model, NULL));
4844   gtk_tree_model_filter_set_visible_column (filter, 1);
4845
4846   for (i=0; i<items; i++)
4847     {
4848       /* allocate random amounts of junk, otherwise the filter model's arrays can expand without moving */
4849
4850       g_malloc (138);
4851       gtk_tree_store_append (store, &node_iters[i], NULL);
4852       gtk_tree_store_set (store, &node_iters[i],
4853                           0, "something",
4854                           1, ((i%6) == 0) ? FALSE : TRUE,
4855                           -1);
4856
4857       g_malloc (47);
4858       gtk_tree_store_append (store, &child_iters[i], &node_iters[i]);
4859       gtk_tree_store_set (store, &child_iters[i],
4860                           0, "something else",
4861                           1, FALSE,
4862                           -1);
4863       gtk_tree_model_filter_refilter (filter);
4864
4865       if (i > 6)
4866         {
4867           gtk_tree_store_set (GTK_TREE_STORE (model), &child_iters[i-1], 1,
4868                               (i & 1) ? TRUE : FALSE, -1);
4869           gtk_tree_model_filter_refilter (filter);
4870
4871           gtk_tree_store_set (GTK_TREE_STORE (model), &child_iters[i-2], 1,
4872                               (i & 1) ? FALSE: TRUE, -1);
4873           gtk_tree_model_filter_refilter (filter);
4874         }
4875     }
4876 }
4877
4878 static gboolean
4879 specific_bug_464173_visible_func (GtkTreeModel *model,
4880                                   GtkTreeIter  *iter,
4881                                   gpointer      data)
4882 {
4883   gboolean *visible = (gboolean *)data;
4884
4885   return *visible;
4886 }
4887
4888 static void
4889 specific_bug_464173 (void)
4890 {
4891   /* Test case for GNOME Bugzilla bug 464173, test case written
4892    * by Andreas Koehler.
4893    */
4894   GtkTreeStore *model;
4895   GtkTreeModelFilter *f_model;
4896   GtkTreeIter iter1, iter2;
4897   GtkWidget *view G_GNUC_UNUSED;
4898   gboolean visible = TRUE;
4899
4900   g_test_bug ("464173");
4901
4902   model = gtk_tree_store_new (1, G_TYPE_STRING);
4903   gtk_tree_store_append (model, &iter1, NULL);
4904   gtk_tree_store_set (model, &iter1, 0, "Foo", -1);
4905   gtk_tree_store_append (model, &iter2, &iter1);
4906   gtk_tree_store_set (model, &iter2, 0, "Bar", -1);
4907
4908   f_model = GTK_TREE_MODEL_FILTER (gtk_tree_model_filter_new (GTK_TREE_MODEL(model), NULL));
4909   gtk_tree_model_filter_set_visible_func (f_model,
4910                                           specific_bug_464173_visible_func,
4911                                           &visible, NULL);
4912
4913   view = gtk_tree_view_new_with_model (GTK_TREE_MODEL (f_model));
4914
4915   visible = FALSE;
4916   gtk_tree_model_filter_refilter (f_model);
4917 }
4918
4919
4920 static gboolean
4921 specific_bug_540201_filter_func (GtkTreeModel *model,
4922                                  GtkTreeIter  *iter,
4923                                  gpointer      data)
4924 {
4925   gboolean has_children;
4926
4927   has_children = gtk_tree_model_iter_has_child (model, iter);
4928
4929   return has_children;
4930 }
4931
4932 static void
4933 specific_bug_540201 (void)
4934 {
4935   /* Test case for GNOME Bugzilla bug 540201, steps provided by
4936    * Charles Day.
4937    */
4938   GtkTreeIter iter, root;
4939   GtkTreeStore *store;
4940   GtkTreeModel *filter;
4941
4942   GtkWidget *tree_view G_GNUC_UNUSED;
4943
4944   g_test_bug ("540201");
4945
4946   store = gtk_tree_store_new (1, G_TYPE_INT);
4947
4948   gtk_tree_store_append (store, &root, NULL);
4949   gtk_tree_store_set (store, &root, 0, 33, -1);
4950
4951   filter = gtk_tree_model_filter_new (GTK_TREE_MODEL (store), NULL);
4952   tree_view = gtk_tree_view_new_with_model (filter);
4953
4954   gtk_tree_model_filter_set_visible_func (GTK_TREE_MODEL_FILTER (filter),
4955                                           specific_bug_540201_filter_func,
4956                                           NULL, NULL);
4957
4958   gtk_tree_store_append (store, &iter, &root);
4959   gtk_tree_store_set (store, &iter, 0, 50, -1);
4960
4961   gtk_tree_store_append (store, &iter, &root);
4962   gtk_tree_store_set (store, &iter, 0, 22, -1);
4963
4964
4965   gtk_tree_store_append (store, &root, NULL);
4966   gtk_tree_store_set (store, &root, 0, 33, -1);
4967
4968   gtk_tree_store_append (store, &iter, &root);
4969   gtk_tree_store_set (store, &iter, 0, 22, -1);
4970 }
4971
4972
4973 static gboolean
4974 specific_bug_549287_visible_func (GtkTreeModel *model,
4975                                   GtkTreeIter  *iter,
4976                                   gpointer      data)
4977 {
4978   gboolean result = FALSE;
4979
4980   result = gtk_tree_model_iter_has_child (model, iter);
4981
4982   return result;
4983 }
4984
4985 static void
4986 specific_bug_549287 (void)
4987 {
4988   /* Test case for GNOME Bugzilla bug 529287, provided by Julient Puydt */
4989
4990   int i;
4991   GtkTreeStore *store;
4992   GtkTreeModel *filtered;
4993   GtkWidget *view G_GNUC_UNUSED;
4994   GtkTreeIter iter;
4995   GtkTreeIter *swap, *parent, *child;
4996
4997   g_test_bug ("529287");
4998
4999   store = gtk_tree_store_new (1, G_TYPE_STRING);
5000   filtered = gtk_tree_model_filter_new (GTK_TREE_MODEL (store), NULL);
5001   gtk_tree_model_filter_set_visible_func (GTK_TREE_MODEL_FILTER (filtered),
5002                                           specific_bug_549287_visible_func,
5003                                           NULL, NULL);
5004
5005   view = gtk_tree_view_new_with_model (filtered);
5006
5007   for (i = 0; i < 4; i++)
5008     {
5009       if (gtk_tree_model_get_iter_first (GTK_TREE_MODEL (store), &iter))
5010         {
5011           parent = gtk_tree_iter_copy (&iter);
5012           child = gtk_tree_iter_copy (&iter);
5013
5014           while (gtk_tree_model_iter_nth_child (GTK_TREE_MODEL (store),
5015                                                 child, parent, 0))
5016             {
5017
5018               swap = parent;
5019               parent = child;
5020               child = swap;
5021             }
5022
5023           gtk_tree_store_append (store, child, parent);
5024           gtk_tree_store_set (store, child,
5025                               0, "Something",
5026                               -1);
5027
5028           gtk_tree_iter_free (parent);
5029           gtk_tree_iter_free (child);
5030         }
5031       else
5032         {
5033           gtk_tree_store_append (store, &iter, NULL);
5034           gtk_tree_store_set (store, &iter,
5035                               0, "Something",
5036                               -1);
5037         }
5038
5039       /* since we inserted something, we changed the visibility conditions: */
5040       gtk_tree_model_filter_refilter (GTK_TREE_MODEL_FILTER (filtered));
5041     }
5042 }
5043
5044 static gboolean
5045 specific_bug_621076_visible_func (GtkTreeModel *model,
5046                                   GtkTreeIter  *iter,
5047                                   gpointer      data)
5048 {
5049   gboolean visible = FALSE;
5050   gchar *str = NULL;
5051
5052   gtk_tree_model_get (model, iter, 0, &str, -1);
5053   if (str != NULL && g_str_has_prefix (str, "visible"))
5054     {
5055       visible = TRUE;
5056     }
5057   else
5058     {
5059       GtkTreeIter child_iter;
5060       gboolean valid;
5061
5062       /* Recursively check if we have a visible child */
5063       for (valid = gtk_tree_model_iter_children (model, &child_iter, iter);
5064            valid; valid = gtk_tree_model_iter_next (model, &child_iter))
5065         {
5066           if (specific_bug_621076_visible_func (model, &child_iter, data))
5067             {
5068               visible = TRUE;
5069               break;
5070             }
5071         }
5072     }
5073
5074   if (str)
5075     g_free (str);
5076
5077   return visible;
5078 }
5079
5080 static void
5081 specific_bug_621076 (void)
5082 {
5083   /* Test case for GNOME Bugzilla bug 621076, provided by Xavier Claessens */
5084
5085   /* This test case differs from has-child-filter and root-has-child-filter
5086    * in that the visible function both filters on content and model
5087    * structure.  Also, it is recursive.
5088    */
5089
5090   GtkTreeStore *store;
5091   GtkTreeModel *filter;
5092   GtkWidget *view;
5093   GtkTreeIter group_iter;
5094   GtkTreeIter item_iter;
5095   SignalMonitor *monitor;
5096
5097   g_test_bug ("621076");
5098
5099   store = gtk_tree_store_new (1, G_TYPE_STRING);
5100   filter = gtk_tree_model_filter_new (GTK_TREE_MODEL (store), NULL);
5101   gtk_tree_model_filter_set_visible_func (GTK_TREE_MODEL_FILTER (filter),
5102                                           specific_bug_621076_visible_func,
5103                                           NULL, NULL);
5104
5105   view = gtk_tree_view_new_with_model (filter);
5106   g_object_ref_sink (view);
5107
5108   monitor = signal_monitor_new (filter);
5109
5110   signal_monitor_append_signal (monitor, ROW_INSERTED, "0");
5111   gtk_tree_store_insert_with_values (store, &item_iter, NULL, -1,
5112                                      0, "visible-group-0",
5113                                      -1);
5114   signal_monitor_assert_is_empty (monitor);
5115
5116   /* visible-group-0 is not expanded, so ROW_INSERTED should not be emitted
5117    * for its children. However, ROW_HAS_CHILD_TOGGLED should be emitted on
5118    * visible-group-0 to tell the view that row can be expanded. */
5119   signal_monitor_append_signal (monitor, ROW_HAS_CHILD_TOGGLED, "0");
5120   signal_monitor_append_signal (monitor, ROW_HAS_CHILD_TOGGLED, "0");
5121   group_iter = item_iter;
5122   gtk_tree_store_insert_with_values (store, &item_iter, &group_iter, -1,
5123                                      0, "visible-0:0",
5124                                      -1);
5125   signal_monitor_assert_is_empty (monitor);
5126
5127   signal_monitor_append_signal (monitor, ROW_INSERTED, "1");
5128   gtk_tree_store_insert_with_values (store, &item_iter, NULL, -1,
5129                                      0, "visible-group-1",
5130                                      -1);
5131   signal_monitor_assert_is_empty (monitor);
5132
5133   /* We are adding an hidden item inside visible-group-1, so
5134    * ROW_HAS_CHILD_TOGGLED should not be emitted.  It is emitted though,
5135    * because the signal originating at TreeStore will be propagated,
5136    * as well a generated signal because the state of the parent *could*
5137    * change by a change in the model.
5138    */
5139   signal_monitor_append_signal (monitor, ROW_HAS_CHILD_TOGGLED, "1");
5140   signal_monitor_append_signal (monitor, ROW_HAS_CHILD_TOGGLED, "1");
5141   group_iter = item_iter;
5142   gtk_tree_store_insert_with_values (store, &item_iter, &group_iter, -1,
5143                                      0, "group-1:0",
5144                                      -1);
5145   signal_monitor_assert_is_empty (monitor);
5146
5147   /* This group is invisible and its parent too. Nothing should be emitted */
5148   group_iter = item_iter;
5149   gtk_tree_store_insert_with_values (store, &item_iter, &group_iter, -1,
5150                                      0, "group-1:0:0",
5151                                      -1);
5152   signal_monitor_assert_is_empty (monitor);
5153
5154   /* Adding a visible item in this group hierarchy will make all nodes
5155    * in this path visible.  The first level should simply tell the view
5156    * that it now has a child, and the view will load the tree if needed
5157    * (depends on the expanded state).
5158    */
5159   signal_monitor_append_signal (monitor, ROW_HAS_CHILD_TOGGLED, "1");
5160   group_iter = item_iter;
5161   gtk_tree_store_insert_with_values (store, &item_iter, &group_iter, -1,
5162                                      0, "visible-1:0:0:0",
5163                                      -1);
5164   signal_monitor_assert_is_empty (monitor);
5165
5166   check_level_length (GTK_TREE_MODEL_FILTER (filter), "1", 1);
5167
5168   gtk_tree_store_insert_with_values (store, &item_iter, NULL, -1,
5169                                      0, "group-2",
5170                                      -1);
5171   signal_monitor_assert_is_empty (monitor);
5172
5173   /* Parent is invisible, and adding this invisible item won't change that,
5174    * so no signal should be emitted. */
5175   group_iter = item_iter;
5176   gtk_tree_store_insert_with_values (store, NULL, &group_iter, -1,
5177                                      0, "invisible-2:0",
5178                                      -1);
5179   signal_monitor_assert_is_empty (monitor);
5180
5181   /* This makes group-2 visible, so it gets inserted and tells it has
5182    * children.
5183    */
5184   signal_monitor_append_signal (monitor, ROW_INSERTED, "2");
5185   signal_monitor_append_signal (monitor, ROW_HAS_CHILD_TOGGLED, "2");
5186   gtk_tree_store_insert_with_values (store, NULL, &group_iter, -1,
5187                                      0, "visible-2:1",
5188                                      -1);
5189   signal_monitor_assert_is_empty (monitor);
5190
5191   /* group-2 is already visible, so this time it is a normal insertion */
5192   gtk_tree_store_insert_with_values (store, NULL, &group_iter, -1,
5193                                      0, "visible-2:2",
5194                                      -1);
5195   signal_monitor_assert_is_empty (monitor);
5196
5197
5198   gtk_tree_store_insert_with_values (store, &item_iter, NULL, -1,
5199                                      0, "group-3",
5200                                      -1);
5201   signal_monitor_assert_is_empty (monitor);
5202
5203   /* Parent is invisible, and adding this invisible item won't change that,
5204    * so no signal should be emitted. */
5205   group_iter = item_iter;
5206   gtk_tree_store_insert_with_values (store, NULL, &group_iter, -1,
5207                                      0, "invisible-3:0",
5208                                      -1);
5209   signal_monitor_assert_is_empty (monitor);
5210
5211   gtk_tree_store_insert_with_values (store, &item_iter, &group_iter, -1,
5212                                      0, "invisible-3:1",
5213                                      -1);
5214   signal_monitor_assert_is_empty (monitor);
5215
5216   /* This will make group 3 visible. */
5217   signal_monitor_append_signal (monitor, ROW_INSERTED, "3");
5218   signal_monitor_append_signal (monitor, ROW_HAS_CHILD_TOGGLED, "3");
5219   signal_monitor_append_signal (monitor, ROW_HAS_CHILD_TOGGLED, "3");
5220   gtk_tree_store_set (store, &item_iter, 0, "visible-3:1", -1);
5221   signal_monitor_assert_is_empty (monitor);
5222
5223   /* Make sure all groups are expanded, so the filter has the tree cached */
5224   gtk_tree_view_expand_all (GTK_TREE_VIEW (view));
5225   while (gtk_events_pending ())
5226     gtk_main_iteration ();
5227
5228   /* Should only yield a row-changed */
5229   signal_monitor_append_signal (monitor, ROW_CHANGED, "3:0");
5230   gtk_tree_store_set (store, &item_iter, 0, "visible-3:1", -1);
5231   signal_monitor_assert_is_empty (monitor);
5232
5233   /* Now remove/hide some items. If a group loses its last item, the group
5234    * should be deleted instead of the item.
5235    */
5236
5237   signal_monitor_append_signal (monitor, ROW_DELETED, "2:1");
5238   gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL (store), &item_iter, "2:2");
5239   gtk_tree_store_remove (store, &item_iter);
5240   signal_monitor_assert_is_empty (monitor);
5241
5242   signal_monitor_append_signal (monitor, ROW_DELETED, "2:0");
5243   signal_monitor_append_signal (monitor, ROW_HAS_CHILD_TOGGLED, "2");
5244   signal_monitor_append_signal (monitor, ROW_DELETED, "2");
5245   gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL (store), &item_iter, "2:1");
5246   gtk_tree_store_set (store, &item_iter, 0, "invisible-2:1", -1);
5247   signal_monitor_assert_is_empty (monitor);
5248
5249   signal_monitor_append_signal (monitor, ROW_DELETED, "1:0:0:0");
5250   signal_monitor_append_signal (monitor, ROW_HAS_CHILD_TOGGLED, "1:0:0");
5251   signal_monitor_append_signal (monitor, ROW_DELETED, "1:0");
5252   signal_monitor_append_signal (monitor, ROW_HAS_CHILD_TOGGLED, "1");
5253   gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL (store), &item_iter, "1:0:0:0");
5254   gtk_tree_store_remove (store, &item_iter);
5255   signal_monitor_assert_is_empty (monitor);
5256
5257   /* Hide a group using row-changed instead of row-deleted */
5258   /* Caution: group 2 is gone, so offsets of the signals have moved. */
5259   signal_monitor_append_signal (monitor, ROW_DELETED, "2:0");
5260   signal_monitor_append_signal (monitor, ROW_HAS_CHILD_TOGGLED, "2");
5261   signal_monitor_append_signal (monitor, ROW_DELETED, "2");
5262   gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL (store), &item_iter,
5263                                        "3:1");
5264   gtk_tree_store_set (store, &item_iter, 0, "invisible-3:1", -1);
5265   signal_monitor_assert_is_empty (monitor);
5266
5267 #if 0
5268   {
5269     GtkWidget *window;
5270     GtkTreeViewColumn *col;
5271
5272     gtk_tree_view_expand_all (GTK_TREE_VIEW (view));
5273
5274     col = gtk_tree_view_column_new_with_attributes ("foo",
5275         gtk_cell_renderer_text_new (),
5276         "text", 0, NULL);
5277     gtk_tree_view_append_column (GTK_TREE_VIEW (view), col);
5278
5279     window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
5280     g_signal_connect (window, "delete-event",
5281         G_CALLBACK (gtk_widget_destroy), NULL);
5282     g_signal_connect (window, "destroy",
5283         G_CALLBACK (gtk_main_quit), NULL);
5284
5285     gtk_container_add (GTK_CONTAINER (window), view);
5286
5287     gtk_widget_show (view);
5288     gtk_widget_show (window);
5289
5290     gtk_main ();
5291   }
5292 #endif
5293
5294   /* Cleanup */
5295   signal_monitor_free (monitor);
5296   g_object_unref (view);
5297   g_object_unref (store);
5298   g_object_unref (filter);
5299 }
5300
5301 /* main */
5302
5303 void
5304 register_filter_model_tests (void)
5305 {
5306   g_test_add ("/TreeModelFilter/self/verify-test-suite",
5307               FilterTest, NULL,
5308               filter_test_setup,
5309               verify_test_suite,
5310               filter_test_teardown);
5311
5312   g_test_add ("/TreeModelFilter/self/verify-test-suite/vroot/depth-1",
5313               FilterTest, gtk_tree_path_new_from_indices (2, -1),
5314               filter_test_setup,
5315               verify_test_suite_vroot,
5316               filter_test_teardown);
5317   g_test_add ("/TreeModelFilter/self/verify-test-suite/vroot/depth-2",
5318               FilterTest, gtk_tree_path_new_from_indices (2, 3, -1),
5319               filter_test_setup,
5320               verify_test_suite_vroot,
5321               filter_test_teardown);
5322
5323
5324   g_test_add ("/TreeModelFilter/filled/hide-root-level",
5325               FilterTest, NULL,
5326               filter_test_setup,
5327               filled_hide_root_level,
5328               filter_test_teardown);
5329   g_test_add ("/TreeModelFilter/filled/hide-child-levels",
5330               FilterTest, NULL,
5331               filter_test_setup,
5332               filled_hide_child_levels,
5333               filter_test_teardown);
5334   g_test_add ("/TreeModelFilter/filled/hide-child-levels/root-expanded",
5335               FilterTest, NULL,
5336               filter_test_setup,
5337               filled_hide_child_levels_root_expanded,
5338               filter_test_teardown);
5339
5340   g_test_add ("/TreeModelFilter/filled/hide-root-level/vroot",
5341               FilterTest, gtk_tree_path_new_from_indices (2, -1),
5342               filter_test_setup,
5343               filled_vroot_hide_root_level,
5344               filter_test_teardown);
5345   g_test_add ("/TreeModelFilter/filled/hide-child-levels/vroot",
5346               FilterTest, gtk_tree_path_new_from_indices (2, -1),
5347               filter_test_setup,
5348               filled_vroot_hide_child_levels,
5349               filter_test_teardown);
5350   g_test_add ("/TreeModelFilter/filled/hide-child-levels/vroot-root-expanded",
5351               FilterTest, gtk_tree_path_new_from_indices (2, -1),
5352               filter_test_setup,
5353               filled_vroot_hide_child_levels_root_expanded,
5354               filter_test_teardown);
5355
5356
5357   g_test_add ("/TreeModelFilter/empty/show-nodes",
5358               FilterTest, NULL,
5359               filter_test_setup_empty,
5360               empty_show_nodes,
5361               filter_test_teardown);
5362   g_test_add ("/TreeModelFilter/empty/show-multiple-nodes",
5363               FilterTest, NULL,
5364               filter_test_setup_empty,
5365               empty_show_multiple_nodes,
5366               filter_test_teardown);
5367
5368   g_test_add ("/TreeModelFilter/empty/show-nodes/vroot",
5369               FilterTest, gtk_tree_path_new_from_indices (2, -1),
5370               filter_test_setup_empty,
5371               empty_vroot_show_nodes,
5372               filter_test_teardown);
5373   g_test_add ("/TreeModelFilter/empty/show-multiple-nodes/vroot",
5374               FilterTest, gtk_tree_path_new_from_indices (2, -1),
5375               filter_test_setup_empty,
5376               empty_vroot_show_multiple_nodes,
5377               filter_test_teardown);
5378
5379
5380   g_test_add ("/TreeModelFilter/unfiltered/hide-single",
5381               FilterTest, NULL,
5382               filter_test_setup_unfiltered,
5383               unfiltered_hide_single,
5384               filter_test_teardown);
5385   g_test_add ("/TreeModelFilter/unfiltered/hide-single/root-expanded",
5386               FilterTest, NULL,
5387               filter_test_setup_unfiltered_root_expanded,
5388               unfiltered_hide_single_root_expanded,
5389               filter_test_teardown);
5390   g_test_add ("/TreeModelFilter/unfiltered/hide-single-child",
5391               FilterTest, NULL,
5392               filter_test_setup_unfiltered,
5393               unfiltered_hide_single_child,
5394               filter_test_teardown);
5395   g_test_add ("/TreeModelFilter/unfiltered/hide-single-child/root-expanded",
5396               FilterTest, NULL,
5397               filter_test_setup_unfiltered_root_expanded,
5398               unfiltered_hide_single_child_root_expanded,
5399               filter_test_teardown);
5400   g_test_add ("/TreeModelFilter/unfiltered/hide-single-multi-level",
5401               FilterTest, NULL,
5402               filter_test_setup_unfiltered,
5403               unfiltered_hide_single_multi_level,
5404               filter_test_teardown);
5405   g_test_add ("/TreeModelFilter/unfiltered/hide-single-multi-level/root-expanded",
5406               FilterTest, NULL,
5407               filter_test_setup_unfiltered_root_expanded,
5408               unfiltered_hide_single_multi_level_root_expanded,
5409               filter_test_teardown);
5410
5411   g_test_add ("/TreeModelFilter/unfiltered/hide-single/vroot",
5412               FilterTest, gtk_tree_path_new_from_indices (2, -1),
5413               filter_test_setup_unfiltered,
5414               unfiltered_vroot_hide_single,
5415               filter_test_teardown);
5416   g_test_add ("/TreeModelFilter/unfiltered/hide-single-child/vroot",
5417               FilterTest, gtk_tree_path_new_from_indices (2, -1),
5418               filter_test_setup_unfiltered,
5419               unfiltered_vroot_hide_single_child,
5420               filter_test_teardown);
5421   g_test_add ("/TreeModelFilter/unfiltered/hide-single-child/vroot/root-expanded",
5422               FilterTest, gtk_tree_path_new_from_indices (2, -1),
5423               filter_test_setup_unfiltered_root_expanded,
5424               unfiltered_vroot_hide_single_child_root_expanded,
5425               filter_test_teardown);
5426   g_test_add ("/TreeModelFilter/unfiltered/hide-single-multi-level/vroot",
5427               FilterTest, gtk_tree_path_new_from_indices (2, -1),
5428               filter_test_setup_unfiltered,
5429               unfiltered_vroot_hide_single_multi_level,
5430               filter_test_teardown);
5431   g_test_add ("/TreeModelFilter/unfiltered/hide-single-multi-level/vroot/root-expanded",
5432               FilterTest, gtk_tree_path_new_from_indices (2, -1),
5433               filter_test_setup_unfiltered_root_expanded,
5434               unfiltered_vroot_hide_single_multi_level_root_expanded,
5435               filter_test_teardown);
5436
5437
5438
5439   g_test_add ("/TreeModelFilter/unfiltered/show-single",
5440               FilterTest, NULL,
5441               filter_test_setup_empty_unfiltered,
5442               unfiltered_show_single,
5443               filter_test_teardown);
5444   g_test_add ("/TreeModelFilter/unfiltered/show-single-child",
5445               FilterTest, NULL,
5446               filter_test_setup_empty_unfiltered,
5447               unfiltered_show_single_child,
5448               filter_test_teardown);
5449   g_test_add ("/TreeModelFilter/unfiltered/show-single-child/root-expanded",
5450               FilterTest, NULL,
5451               filter_test_setup_empty_unfiltered_root_expanded,
5452               unfiltered_show_single_child_root_expanded,
5453               filter_test_teardown);
5454   g_test_add ("/TreeModelFilter/unfiltered/show-single-multi-level",
5455               FilterTest, NULL,
5456               filter_test_setup_empty_unfiltered,
5457               unfiltered_show_single_multi_level,
5458               filter_test_teardown);
5459   g_test_add ("/TreeModelFilter/unfiltered/show-single-multi-level/root-expanded",
5460               FilterTest, NULL,
5461               filter_test_setup_empty_unfiltered_root_expanded,
5462               unfiltered_show_single_multi_level_root_expanded,
5463               filter_test_teardown);
5464
5465   g_test_add ("/TreeModelFilter/unfiltered/show-single/vroot",
5466               FilterTest, gtk_tree_path_new_from_indices (2, -1),
5467               filter_test_setup_empty_unfiltered,
5468               unfiltered_vroot_show_single,
5469               filter_test_teardown);
5470   g_test_add ("/TreeModelFilter/unfiltered/show-single-child/vroot",
5471               FilterTest, gtk_tree_path_new_from_indices (2, -1),
5472               filter_test_setup_empty_unfiltered,
5473               unfiltered_vroot_show_single_child,
5474               filter_test_teardown);
5475   g_test_add ("/TreeModelFilter/unfiltered/show-single-child/vroot/root-expanded",
5476               FilterTest, gtk_tree_path_new_from_indices (2, -1),
5477               filter_test_setup_empty_unfiltered_root_expanded,
5478               unfiltered_vroot_show_single_child_root_expanded,
5479               filter_test_teardown);
5480   g_test_add ("/TreeModelFilter/unfiltered/show-single-multi-level/vroot",
5481               FilterTest, gtk_tree_path_new_from_indices (2, -1),
5482               filter_test_setup_empty_unfiltered,
5483               unfiltered_vroot_show_single_multi_level,
5484               filter_test_teardown);
5485   g_test_add ("/TreeModelFilter/unfiltered/show-single-multi-level/vroot/root-expanded",
5486               FilterTest, gtk_tree_path_new_from_indices (2, -1),
5487               filter_test_setup_empty_unfiltered_root_expanded,
5488               unfiltered_vroot_show_single_multi_level_root_expanded,
5489               filter_test_teardown);
5490
5491
5492   g_test_add ("/TreeModelFilter/unfiltered/rows-reordered/root-level",
5493               FilterTest, NULL,
5494               filter_test_setup_unfiltered,
5495               unfiltered_rows_reordered_root_level,
5496               filter_test_teardown);
5497   g_test_add ("/TreeModelFilter/unfiltered/rows-reordered/child-level",
5498               FilterTest, NULL,
5499               filter_test_setup_unfiltered,
5500               unfiltered_rows_reordered_child_level,
5501               filter_test_teardown);
5502
5503   g_test_add ("/TreeModelFilter/filtered/rows-reordered/root-level/first-hidden",
5504               FilterTest, NULL,
5505               filter_test_setup,
5506               filtered_rows_reordered_root_level_first_hidden,
5507               filter_test_teardown);
5508   g_test_add ("/TreeModelFilter/filtered/rows-reordered/root-level/middle-hidden",
5509               FilterTest, NULL,
5510               filter_test_setup,
5511               filtered_rows_reordered_root_level_middle_hidden,
5512               filter_test_teardown);
5513   g_test_add ("/TreeModelFilter/filtered/rows-reordered/child-level/first-hidden",
5514               FilterTest, NULL,
5515               filter_test_setup,
5516               filtered_rows_reordered_child_level_first_hidden,
5517               filter_test_teardown);
5518   g_test_add ("/TreeModelFilter/filtered/rows-reordered/child-level/middle-hidden",
5519               FilterTest, NULL,
5520               filter_test_setup,
5521               filtered_rows_reordered_child_level_middle_hidden,
5522               filter_test_teardown);
5523   g_test_add ("/TreeModelFilter/filtered/rows-reordered/child-level/4-hidden",
5524               FilterTest, NULL,
5525               filter_test_setup,
5526               filtered_rows_reordered_child_level_4_hidden,
5527               filter_test_teardown);
5528   g_test_add ("/TreeModelFilter/filtered/rows-reordered/child-level/all-hidden",
5529               FilterTest, NULL,
5530               filter_test_setup,
5531               filtered_rows_reordered_child_level_all_hidden,
5532               filter_test_teardown);
5533
5534   /* Inserts in child models after creation of filter model */
5535   g_test_add_func ("/TreeModelFilter/insert/before",
5536                    insert_before);
5537   g_test_add_func ("/TreeModelFilter/insert/child",
5538                    insert_child);
5539
5540   /* Removals from child model after creating of filter model */
5541   g_test_add_func ("/TreeModelFilter/remove/node",
5542                    remove_node);
5543   g_test_add_func ("/TreeModelFilter/remove/node-vroot",
5544                    remove_node_vroot);
5545   g_test_add_func ("/TreeModelFilter/remove/vroot-ancestor",
5546                    remove_vroot_ancestor);
5547
5548   /* Reference counting */
5549   g_test_add_func ("/TreeModelFilter/ref-count/single-level",
5550                    ref_count_single_level);
5551   g_test_add_func ("/TreeModelFilter/ref-count/two-levels",
5552                    ref_count_two_levels);
5553   g_test_add_func ("/TreeModelFilter/ref-count/three-levels",
5554                    ref_count_three_levels);
5555   g_test_add_func ("/TreeModelFilter/ref-count/delete-row",
5556                    ref_count_delete_row);
5557   g_test_add_func ("/TreeModelFilter/ref-count/cleanup",
5558                    ref_count_cleanup);
5559   g_test_add_func ("/TreeModelFilter/ref-count/row-ref",
5560                    ref_count_row_ref);
5561
5562   /* Reference counting, transfer of first reference on
5563    * first node in level.  This is a GtkTreeModelFilter-specific
5564    * feature.
5565    */
5566   g_test_add_func ("/TreeModelFilter/ref-count/transfer/root-level/insert",
5567                    ref_count_transfer_root_level_insert);
5568   g_test_add_func ("/TreeModelFilter/ref-count/transfer/root-level/reordered",
5569                    ref_count_transfer_root_level_reordered);
5570   g_test_add_func ("/TreeModelFilter/ref-count/transfer/root-level/reordered/filtered",
5571                    ref_count_transfer_root_level_reordered_filtered);
5572   g_test_add_func ("/TreeModelFilter/ref-count/transfer/child-level/insert",
5573                    ref_count_transfer_child_level_insert);
5574   g_test_add_func ("/TreeModelFilter/ref-count/transfer/child-level/reordered",
5575                    ref_count_transfer_child_level_reordered);
5576   g_test_add_func ("/TreeModelFilter/ref-count/transfer/child-level/reordered/filtered",
5577                    ref_count_transfer_child_level_reordered_filtered);
5578
5579   g_test_add_func ("/TreeModelFilter/specific/path-dependent-filter",
5580                    specific_path_dependent_filter);
5581   g_test_add_func ("/TreeModelFilter/specific/append-after-collapse",
5582                    specific_append_after_collapse);
5583   g_test_add_func ("/TreeModelFilter/specific/sort-filter-remove-node",
5584                    specific_sort_filter_remove_node);
5585   g_test_add_func ("/TreeModelFilter/specific/sort-filter-remove-root",
5586                    specific_sort_filter_remove_root);
5587   g_test_add_func ("/TreeModelFilter/specific/root-mixed-visibility",
5588                    specific_root_mixed_visibility);
5589   g_test_add_func ("/TreeModelFilter/specific/has-child-filter",
5590                    specific_has_child_filter);
5591   g_test_add_func ("/TreeModelFilter/specific/has-child-filter-on-sort-model",
5592                    specific_has_child_filter_on_sort_model);
5593   g_test_add_func ("/TreeModelFilter/specific/at-least-2-children-filter",
5594                    specific_at_least_2_children_filter);
5595   g_test_add_func ("/TreeModelFilter/specific/at-least-2-children-filter-on-sort-model",
5596                    specific_at_least_2_children_filter_on_sort_model);
5597   g_test_add_func ("/TreeModelFilter/specific/root-has-child-filter",
5598                    specific_root_has_child_filter);
5599   g_test_add_func ("/TreeModelFilter/specific/filter-add-child",
5600                    specific_filter_add_child);
5601   g_test_add_func ("/TreeModelFilter/specific/list-store-clear",
5602                    specific_list_store_clear);
5603   g_test_add_func ("/TreeModelFilter/specific/sort-ref-leaf-and-remove-ancestor",
5604                    specific_sort_ref_leaf_and_remove_ancestor);
5605   g_test_add_func ("/TreeModelFilter/specific/ref-leaf-and-remove-ancestor",
5606                    specific_ref_leaf_and_remove_ancestor);
5607   g_test_add_func ("/TreeModelFilter/specific/virtual-ref-leaf-and-remove-ancestor",
5608                    specific_virtual_ref_leaf_and_remove_ancestor);
5609
5610   g_test_add_func ("/TreeModelFilter/specific/bug-301558",
5611                    specific_bug_301558);
5612   g_test_add_func ("/TreeModelFilter/specific/bug-311955",
5613                    specific_bug_311955);
5614   g_test_add_func ("/TreeModelFilter/specific/bug-311955-clean",
5615                    specific_bug_311955_clean);
5616   g_test_add_func ("/TreeModelFilter/specific/bug-346800",
5617                    specific_bug_346800);
5618   g_test_add_func ("/TreeModelFilter/specific/bug-464173",
5619                    specific_bug_464173);
5620   g_test_add_func ("/TreeModelFilter/specific/bug-540201",
5621                    specific_bug_540201);
5622   g_test_add_func ("/TreeModelFilter/specific/bug-549287",
5623                    specific_bug_549287);
5624   g_test_add_func ("/TreeModelFilter/specific/bug-621076",
5625                    specific_bug_621076);
5626 }