[gtk+] Add thorough unit test for bug #621076



commit 22adfc67e532795da7b12a8402922108ccb9bd2c
Author: Xavier Claessens <xclaesse gmail com>
Date:   Fri May 20 20:25:24 2011 +0200

    Add thorough unit test for bug #621076
    
    Minor edits and additions by Kristian Rietveld.

 gtk/tests/filtermodel.c |  259 +++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 259 insertions(+), 0 deletions(-)
---
diff --git a/gtk/tests/filtermodel.c b/gtk/tests/filtermodel.c
index 946ec71..6675729 100644
--- a/gtk/tests/filtermodel.c
+++ b/gtk/tests/filtermodel.c
@@ -3250,6 +3250,263 @@ specific_bug_549287 (void)
     }
 }
 
+static gboolean
+specific_bug_621076_visible_func (GtkTreeModel *model,
+                                  GtkTreeIter  *iter,
+                                  gpointer      data)
+{
+  gboolean visible = FALSE;
+  gchar *str;
+
+  gtk_tree_model_get (model, iter, 0, &str, -1);
+  if (str != NULL && g_str_has_prefix (str, "visible"))
+    {
+      visible = TRUE;
+    }
+  else
+    {
+      GtkTreeIter child_iter;
+      gboolean valid;
+
+      /* Recursively check if we have a visible child */
+      for (valid = gtk_tree_model_iter_children (model, &child_iter, iter);
+           valid; valid = gtk_tree_model_iter_next (model, &child_iter))
+        {
+          gtk_tree_model_get (model, &child_iter, 0, &str, -1);
+          if (specific_bug_621076_visible_func (model, &child_iter, data))
+            {
+              visible = TRUE;
+              break;
+            }
+        }
+    }
+
+  return visible;
+}
+
+static void
+specific_bug_621076 (void)
+{
+  /* Test case for GNOME Bugzilla bug 621076, provided by Xavier Claessens */
+
+  /* This test case differs from has-child-filter and root-has-child-filter
+   * in that the visible function both filters on content and model
+   * structure.  Also, it is recursive.
+   */
+
+  GtkTreeStore *store;
+  GtkTreeModel *filter;
+  GtkWidget *view;
+  GtkTreeIter group_iter;
+  GtkTreeIter item_iter;
+  SignalMonitor *monitor;
+
+  g_test_bug ("621076");
+
+  store = gtk_tree_store_new (1, G_TYPE_STRING);
+  filter = gtk_tree_model_filter_new (GTK_TREE_MODEL (store), NULL);
+  gtk_tree_model_filter_set_visible_func (GTK_TREE_MODEL_FILTER (filter),
+                                          specific_bug_621076_visible_func,
+                                          NULL, NULL);
+
+  view = gtk_tree_view_new_with_model (filter);
+  g_object_ref_sink (view);
+
+  monitor = signal_monitor_new (filter);
+
+  signal_monitor_append_signal (monitor, ROW_INSERTED, "0");
+  gtk_tree_store_insert_with_values (store, &item_iter, NULL, -1,
+                                     0, "visible-group-0",
+                                     -1);
+  signal_monitor_assert_is_empty (monitor);
+
+  /* visible-group-0 is not expanded, so ROW_INSERTED should not be emitted
+   * for its children. However, ROW_HAS_CHILD_TOGGLED should be emitted on
+   * visible-group-0 to tell the view that row can be expanded. */
+  signal_monitor_append_signal (monitor, ROW_HAS_CHILD_TOGGLED, "0");
+  signal_monitor_append_signal (monitor, ROW_HAS_CHILD_TOGGLED, "0");
+  group_iter = item_iter;
+  gtk_tree_store_insert_with_values (store, &item_iter, &group_iter, -1,
+                                     0, "visible-0:0",
+                                     -1);
+  signal_monitor_assert_is_empty (monitor);
+
+  signal_monitor_append_signal (monitor, ROW_INSERTED, "1");
+  gtk_tree_store_insert_with_values (store, &item_iter, NULL, -1,
+                                     0, "visible-group-1",
+                                     -1);
+  signal_monitor_assert_is_empty (monitor);
+
+  /* We are adding an hidden item inside visible-group-1, so
+   * ROW_HAS_CHILD_TOGGLED should not be emitted.  It is emitted though,
+   * because the signal originating at TreeStore will be propagated,
+   * as well a generated signal because the state of the parent *could*
+   * change by a change in the model.
+   */
+  signal_monitor_append_signal (monitor, ROW_HAS_CHILD_TOGGLED, "1");
+  signal_monitor_append_signal (monitor, ROW_HAS_CHILD_TOGGLED, "1");
+  group_iter = item_iter;
+  gtk_tree_store_insert_with_values (store, &item_iter, &group_iter, -1,
+                                     0, "group-1:0",
+                                     -1);
+  signal_monitor_assert_is_empty (monitor);
+
+  /* This group is invisible and its parent too. Nothing should be emitted */
+  group_iter = item_iter;
+  gtk_tree_store_insert_with_values (store, &item_iter, &group_iter, -1,
+                                     0, "group-1:0:0",
+                                     -1);
+  signal_monitor_assert_is_empty (monitor);
+
+  /* Adding a visible item in this group hierarchy will make all nodes
+   * in this path visible.  The first level should simply tell the view
+   * that it now has a child, and the view will load the tree if needed
+   * (depends on the expanded state).
+   */
+  signal_monitor_append_signal (monitor, ROW_HAS_CHILD_TOGGLED, "1");
+  group_iter = item_iter;
+  gtk_tree_store_insert_with_values (store, &item_iter, &group_iter, -1,
+                                     0, "visible-1:0:0:0",
+                                     -1);
+  signal_monitor_assert_is_empty (monitor);
+
+  check_level_length (GTK_TREE_MODEL_FILTER (filter), "1", 1);
+
+  gtk_tree_store_insert_with_values (store, &item_iter, NULL, -1,
+                                     0, "group-2",
+                                     -1);
+  signal_monitor_assert_is_empty (monitor);
+
+  /* Parent is invisible, and adding this invisible item won't change that,
+   * so no signal should be emitted. */
+  group_iter = item_iter;
+  gtk_tree_store_insert_with_values (store, NULL, &group_iter, -1,
+                                     0, "invisible-2:0",
+                                     -1);
+  signal_monitor_assert_is_empty (monitor);
+
+  /* This makes group-2 visible, so it gets inserted and tells it has
+   * children.
+   */
+  signal_monitor_append_signal (monitor, ROW_INSERTED, "2");
+  signal_monitor_append_signal (monitor, ROW_HAS_CHILD_TOGGLED, "2");
+  gtk_tree_store_insert_with_values (store, NULL, &group_iter, -1,
+                                     0, "visible-2:1",
+                                     -1);
+  signal_monitor_assert_is_empty (monitor);
+
+  /* group-2 is already visible, so this time it is a normal insertion */
+  signal_monitor_append_signal (monitor, ROW_INSERTED, "2:1");
+  gtk_tree_store_insert_with_values (store, NULL, &group_iter, -1,
+                                     0, "visible-2:2",
+                                     -1);
+  signal_monitor_assert_is_empty (monitor);
+
+
+  gtk_tree_store_insert_with_values (store, &item_iter, NULL, -1,
+                                     0, "group-3",
+                                     -1);
+  signal_monitor_assert_is_empty (monitor);
+
+  /* Parent is invisible, and adding this invisible item won't change that,
+   * so no signal should be emitted. */
+  group_iter = item_iter;
+  gtk_tree_store_insert_with_values (store, NULL, &group_iter, -1,
+                                     0, "invisible-3:0",
+                                     -1);
+  signal_monitor_assert_is_empty (monitor);
+
+  gtk_tree_store_insert_with_values (store, &item_iter, &group_iter, -1,
+                                     0, "invisible-3:1",
+                                     -1);
+  signal_monitor_assert_is_empty (monitor);
+
+  /* This will make group 3 visible. */
+  signal_monitor_append_signal (monitor, ROW_INSERTED, "3");
+  signal_monitor_append_signal (monitor, ROW_HAS_CHILD_TOGGLED, "3");
+  signal_monitor_append_signal (monitor, ROW_INSERTED, "3:0");
+  signal_monitor_append_signal (monitor, ROW_HAS_CHILD_TOGGLED, "3");
+  gtk_tree_store_set (store, &item_iter, 0, "visible-3:1", -1);
+  signal_monitor_assert_is_empty (monitor);
+
+  /* Make sure all groups are expanded, so the filter has the tree cached */
+  gtk_tree_view_expand_all (GTK_TREE_VIEW (view));
+  while (gtk_events_pending ())
+    gtk_main_iteration ();
+
+  /* Should only yield a row-changed */
+  signal_monitor_append_signal (monitor, ROW_CHANGED, "3:0");
+  gtk_tree_store_set (store, &item_iter, 0, "visible-3:1", -1);
+  signal_monitor_assert_is_empty (monitor);
+
+  /* Now remove/hide some items. If a group loses its last item, the group
+   * should be deleted instead of the item.
+   */
+
+  signal_monitor_append_signal (monitor, ROW_DELETED, "2:1");
+  gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL (store), &item_iter, "2:2");
+  gtk_tree_store_remove (store, &item_iter);
+  signal_monitor_assert_is_empty (monitor);
+
+  signal_monitor_append_signal (monitor, ROW_DELETED, "2:0");
+  signal_monitor_append_signal (monitor, ROW_HAS_CHILD_TOGGLED, "2");
+  signal_monitor_append_signal (monitor, ROW_DELETED, "2");
+  gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL (store), &item_iter, "2:1");
+  gtk_tree_store_set (store, &item_iter, 0, "invisible-2:1", -1);
+  signal_monitor_assert_is_empty (monitor);
+
+  signal_monitor_append_signal (monitor, ROW_DELETED, "1:0:0:0");
+  signal_monitor_append_signal (monitor, ROW_HAS_CHILD_TOGGLED, "1:0:0");
+  signal_monitor_append_signal (monitor, ROW_DELETED, "1:0");
+  signal_monitor_append_signal (monitor, ROW_HAS_CHILD_TOGGLED, "1");
+  gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL (store), &item_iter, "1:0:0:0");
+  gtk_tree_store_remove (store, &item_iter);
+  signal_monitor_assert_is_empty (monitor);
+
+  /* Hide a group using row-changed instead of row-deleted */
+  /* Caution: group 2 is gone, so offsets of the signals have moved. */
+  signal_monitor_append_signal (monitor, ROW_DELETED, "2:0");
+  signal_monitor_append_signal (monitor, ROW_HAS_CHILD_TOGGLED, "2");
+  signal_monitor_append_signal (monitor, ROW_DELETED, "2");
+  gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL (store), &item_iter,
+                                       "3:1");
+  gtk_tree_store_set (store, &item_iter, 0, "invisible-3:1", -1);
+  signal_monitor_assert_is_empty (monitor);
+
+#if 0
+  {
+    GtkWidget *window;
+    GtkTreeViewColumn *col;
+
+    gtk_tree_view_expand_all (GTK_TREE_VIEW (view));
+
+    col = gtk_tree_view_column_new_with_attributes ("foo",
+        gtk_cell_renderer_text_new (),
+        "text", 0, NULL);
+    gtk_tree_view_append_column (GTK_TREE_VIEW (view), col);
+
+    window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
+    g_signal_connect (window, "delete-event",
+        G_CALLBACK (gtk_widget_destroy), NULL);
+    g_signal_connect (window, "destroy",
+        G_CALLBACK (gtk_main_quit), NULL);
+
+    gtk_container_add (GTK_CONTAINER (window), view);
+
+    gtk_widget_show (view);
+    gtk_widget_show (window);
+
+    gtk_main ();
+  }
+#endif
+
+  /* Cleanup */
+  signal_monitor_free (monitor);
+  g_object_unref (view);
+  g_object_unref (store);
+  g_object_unref (filter);
+}
+
 /* main */
 
 void
@@ -3437,4 +3694,6 @@ register_filter_model_tests (void)
                    specific_bug_540201);
   g_test_add_func ("/TreeModelFilter/specific/bug-549287",
                    specific_bug_549287);
+  g_test_add_func ("/TreeModelFilter/specific/bug-621076",
+                   specific_bug_621076);
 }



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]