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