[gtk+] Have the unit test check if the filter model emits the right signals



commit bf573a1e1ef913e309ffcab1feb4bc5ee8da1a3d
Author: Kristian Rietveld <kris gtk org>
Date:   Sat Sep 5 15:57:25 2009 +0200

    Have the unit test check if the filter model emits the right signals

 gtk/tests/filtermodel.c |  612 ++++++++++++++++++++++++++++++++++++++++++++++-
 1 files changed, 610 insertions(+), 2 deletions(-)
---
diff --git a/gtk/tests/filtermodel.c b/gtk/tests/filtermodel.c
index 77f7231..52e0d51 100644
--- a/gtk/tests/filtermodel.c
+++ b/gtk/tests/filtermodel.c
@@ -74,6 +74,218 @@ create_tree_store (int      depth,
   return store;
 }
 
+/*
+ * Signal monitor
+ */
+
+typedef enum
+{
+  ROW_INSERTED,
+  ROW_DELETED,
+  ROW_CHANGED,
+  ROW_HAS_CHILD_TOGGLED,
+  ROWS_REORDERED,
+  LAST_SIGNAL
+}
+SignalName;
+
+typedef struct
+{
+  SignalName signal;
+  GtkTreePath *path;
+}
+Signal;
+
+
+static Signal *
+signal_new (SignalName signal, GtkTreePath *path)
+{
+  Signal *s;
+
+  s = g_new0 (Signal, 1);
+  s->signal = signal;
+  s->path = gtk_tree_path_copy (path);
+
+  return s;
+}
+
+static void
+signal_free (Signal *s)
+{
+  if (s->path)
+    gtk_tree_path_free (s->path);
+
+  g_free (s);
+}
+
+
+typedef struct
+{
+  GQueue *queue;
+  GtkTreeModel *client;
+  guint signal_ids[LAST_SIGNAL];
+}
+SignalMonitor;
+
+
+static void
+signal_monitor_generic_handler (SignalMonitor *m,
+                                SignalName     signal,
+                                GtkTreeModel  *model,
+                                GtkTreePath   *path)
+{
+  Signal *s;
+
+  g_return_if_fail (m->client == model);
+  g_return_if_fail (!g_queue_is_empty (m->queue));
+
+#if 0
+  /* For debugging: output signals that are coming in.  Leaks memory. */
+  g_print ("signal=%d  path=%s\n", signal, gtk_tree_path_to_string (path));
+#endif
+
+  s = g_queue_peek_tail (m->queue);
+
+  g_return_if_fail (s->signal == signal);
+
+  s = g_queue_pop_tail (m->queue);
+
+  g_return_if_fail (!gtk_tree_path_compare (path, s->path));
+
+  signal_free (s);
+}
+
+static void
+signal_monitor_row_inserted (GtkTreeModel *model,
+                             GtkTreePath  *path,
+                             GtkTreeIter  *iter,
+                             gpointer      data)
+{
+  signal_monitor_generic_handler (data, ROW_INSERTED,
+                                  model, path);
+}
+
+static void
+signal_monitor_row_deleted (GtkTreeModel *model,
+                            GtkTreePath  *path,
+                            gpointer      data)
+{
+  signal_monitor_generic_handler (data, ROW_DELETED,
+                                  model, path);
+}
+
+static void
+signal_monitor_row_changed (GtkTreeModel *model,
+                            GtkTreePath  *path,
+                            GtkTreeIter  *iter,
+                            gpointer      data)
+{
+  signal_monitor_generic_handler (data, ROW_CHANGED,
+                                  model, path);
+}
+
+static void
+signal_monitor_row_has_child_toggled (GtkTreeModel *model,
+                                      GtkTreePath  *path,
+                                      GtkTreeIter  *iter,
+                                      gpointer      data)
+{
+  signal_monitor_generic_handler (data, ROW_HAS_CHILD_TOGGLED,
+                                  model, path);
+}
+
+static void
+signal_monitor_rows_reordered (GtkTreeModel *model,
+                               GtkTreePath  *path,
+                               GtkTreeIter  *iter,
+                               gint         *new_order,
+                               gpointer      data)
+{
+  signal_monitor_generic_handler (data, ROWS_REORDERED,
+                                  model, path);
+}
+
+static SignalMonitor *
+signal_monitor_new (GtkTreeModel *client)
+{
+  SignalMonitor *m;
+
+  m = g_new0 (SignalMonitor, 1);
+  m->client = g_object_ref (client);
+  m->queue = g_queue_new ();
+
+  m->signal_ids[ROW_INSERTED] = g_signal_connect (client,
+                                                  "row-inserted",
+                                                  G_CALLBACK (signal_monitor_row_inserted),
+                                                  m);
+  m->signal_ids[ROW_DELETED] = g_signal_connect (client,
+                                                 "row-deleted",
+                                                 G_CALLBACK (signal_monitor_row_deleted),
+                                                 m);
+  m->signal_ids[ROW_CHANGED] = g_signal_connect (client,
+                                                 "row-changed",
+                                                 G_CALLBACK (signal_monitor_row_changed),
+                                                 m);
+  m->signal_ids[ROW_HAS_CHILD_TOGGLED] = g_signal_connect (client,
+                                                           "row-has-child-toggled",
+                                                           G_CALLBACK (signal_monitor_row_has_child_toggled),
+                                                           m);
+  m->signal_ids[ROWS_REORDERED] = g_signal_connect (client,
+                                                    "rows-reordered",
+                                                    G_CALLBACK (signal_monitor_rows_reordered),
+                                                    m);
+
+  return m;
+}
+
+static void
+signal_monitor_free (SignalMonitor *m)
+{
+  int i;
+
+  for (i = 0; i < LAST_SIGNAL; i++)
+    g_signal_handler_disconnect (m->client, m->signal_ids[i]);
+
+  g_object_unref (m->client);
+
+  if (m->queue)
+    g_queue_free (m->queue);
+
+  g_free (m);
+}
+
+static void
+signal_monitor_assert_is_empty (SignalMonitor *m)
+{
+  g_assert (g_queue_is_empty (m->queue));
+}
+
+static void
+signal_monitor_append_signal_path (SignalMonitor *m,
+                                   SignalName     signal,
+                                   GtkTreePath   *path)
+{
+  Signal *s;
+
+  s = signal_new (signal, path);
+  g_queue_push_head (m->queue, s);
+}
+
+static void
+signal_monitor_append_signal (SignalMonitor *m,
+                              SignalName     signal,
+                              const gchar   *path_string)
+{
+  Signal *s;
+  GtkTreePath *path;
+
+  path = gtk_tree_path_new_from_string (path_string);
+
+  s = signal_new (signal, path);
+  g_queue_push_head (m->queue, s);
+
+  gtk_tree_path_free (path);
+}
 
 /*
  * Fixture
@@ -85,6 +297,8 @@ typedef struct
 
   GtkTreeStore *store;
   GtkTreeModelFilter *filter;
+
+  SignalMonitor *monitor;
 } FilterTest;
 
 static void
@@ -111,6 +325,8 @@ filter_test_setup_generic (FilterTest    *fixture,
    * side.
    */
   fixture->tree_view = gtk_tree_view_new_with_model (filter);
+
+  fixture->monitor = signal_monitor_new (filter);
 }
 
 static void
@@ -141,6 +357,202 @@ filter_test_setup_empty_unfiltered (FilterTest    *fixture,
   filter_test_setup_generic (fixture, test_data, 3, TRUE, TRUE);
 }
 
+static GtkTreePath *
+strip_virtual_root (GtkTreePath *path,
+                    GtkTreePath *root_path)
+{
+  GtkTreePath *real_path;
+
+  if (root_path)
+    {
+      int j;
+      int depth = gtk_tree_path_get_depth (path);
+      int root_depth = gtk_tree_path_get_depth (root_path);
+
+      real_path = gtk_tree_path_new ();
+
+      for (j = 0; j < depth - root_depth; j++)
+        gtk_tree_path_append_index (real_path,
+                                    gtk_tree_path_get_indices (path)[root_depth + j]);
+    }
+  else
+    real_path = gtk_tree_path_copy (path);
+
+  return real_path;
+}
+
+static void
+filter_test_append_refilter_signals_recurse (FilterTest  *fixture,
+                                             GtkTreePath *store_path,
+                                             GtkTreePath *filter_path,
+                                             int          depth,
+                                             GtkTreePath *root_path)
+{
+  int i;
+  int rows_deleted = 0;
+  GtkTreeIter iter;
+
+  gtk_tree_path_down (store_path);
+  gtk_tree_path_down (filter_path);
+
+  gtk_tree_model_get_iter (GTK_TREE_MODEL (fixture->store),
+                           &iter, store_path);
+
+  for (i = 0; i < LEVEL_LENGTH; i++)
+    {
+      gboolean visible;
+      GtkTreePath *real_path;
+
+      gtk_tree_model_get (GTK_TREE_MODEL (fixture->store), &iter,
+                          1, &visible,
+                          -1);
+
+      if (root_path &&
+          (!gtk_tree_path_is_descendant (store_path, root_path)
+           || !gtk_tree_path_compare (store_path, root_path)))
+        {
+          if (!gtk_tree_path_compare (store_path, root_path))
+            {
+              if (depth > 1
+                  && gtk_tree_model_iter_has_child (GTK_TREE_MODEL (fixture->store),
+                                                    &iter))
+                {
+                  GtkTreePath *store_copy;
+                  GtkTreePath *filter_copy;
+
+                  store_copy = gtk_tree_path_copy (store_path);
+                  filter_copy = gtk_tree_path_copy (filter_path);
+                  filter_test_append_refilter_signals_recurse (fixture,
+                                                               store_copy,
+                                                               filter_copy,
+                                                               depth - 1,
+                                                               root_path);
+                  gtk_tree_path_free (store_copy);
+                  gtk_tree_path_free (filter_copy);
+                }
+            }
+
+          gtk_tree_path_next (store_path);
+          gtk_tree_model_iter_next (GTK_TREE_MODEL (fixture->store), &iter);
+
+          if (visible)
+            gtk_tree_path_next (filter_path);
+
+          continue;
+        }
+
+      real_path = strip_virtual_root (filter_path, root_path);
+
+      if (visible)
+        {
+          /* This row will be inserted */
+          signal_monitor_append_signal_path (fixture->monitor, ROW_CHANGED,
+                                             real_path);
+          signal_monitor_append_signal_path (fixture->monitor,
+                                             ROW_HAS_CHILD_TOGGLED,
+                                             real_path);
+
+          if (depth > 1
+              && gtk_tree_model_iter_has_child (GTK_TREE_MODEL (fixture->store),
+                                                &iter))
+            {
+              GtkTreePath *store_copy;
+              GtkTreePath *filter_copy;
+
+              store_copy = gtk_tree_path_copy (store_path);
+              filter_copy = gtk_tree_path_copy (filter_path);
+              filter_test_append_refilter_signals_recurse (fixture,
+                                                           store_copy,
+                                                           filter_copy,
+                                                           depth - 1,
+                                                           root_path);
+              gtk_tree_path_free (store_copy);
+              gtk_tree_path_free (filter_copy);
+            }
+
+          gtk_tree_path_next (filter_path);
+        }
+      else
+        {
+          /* This row will be deleted */
+          rows_deleted++;
+          signal_monitor_append_signal_path (fixture->monitor, ROW_DELETED,
+                                             real_path);
+        }
+
+      gtk_tree_path_free (real_path);
+
+      gtk_tree_path_next (store_path);
+      gtk_tree_model_iter_next (GTK_TREE_MODEL (fixture->store), &iter);
+    }
+
+  if (rows_deleted == LEVEL_LENGTH
+      && gtk_tree_path_get_depth (filter_path) > 1)
+    {
+      GtkTreePath *real_path;
+
+      gtk_tree_path_up (store_path);
+      gtk_tree_path_up (filter_path);
+
+      /* A row-has-child-toggled will be emitted on the parent */
+      if (!root_path
+          || (root_path
+              && gtk_tree_path_is_descendant (store_path, root_path)
+              && gtk_tree_path_compare (store_path, root_path)))
+        {
+          real_path = strip_virtual_root (filter_path, root_path);
+          signal_monitor_append_signal_path (fixture->monitor,
+                                             ROW_HAS_CHILD_TOGGLED,
+                                             real_path);
+
+          gtk_tree_path_free (real_path);
+        }
+    }
+}
+
+static void
+filter_test_append_refilter_signals (FilterTest *fixture,
+                                     int         depth)
+{
+  /* A special function that walks the tree store like the
+   * model validation functions below.
+   */
+  GtkTreePath *path;
+  GtkTreePath *filter_path;
+
+  path = gtk_tree_path_new ();
+  filter_path = gtk_tree_path_new ();
+  filter_test_append_refilter_signals_recurse (fixture,
+                                               path,
+                                               filter_path,
+                                               depth,
+                                               NULL);
+  gtk_tree_path_free (path);
+  gtk_tree_path_free (filter_path);
+}
+
+static void
+filter_test_append_refilter_signals_with_vroot (FilterTest  *fixture,
+                                                int          depth,
+                                                GtkTreePath *root_path)
+{
+  /* A special function that walks the tree store like the
+   * model validation functions below.
+   */
+  GtkTreePath *path;
+  GtkTreePath *filter_path;
+
+  path = gtk_tree_path_new ();
+  filter_path = gtk_tree_path_new ();
+  filter_test_append_refilter_signals_recurse (fixture,
+                                               path,
+                                               filter_path,
+                                               depth,
+                                               root_path);
+  gtk_tree_path_free (path);
+  gtk_tree_path_free (filter_path);
+}
+
 static void
 filter_test_enable_filter (FilterTest *fixture)
 {
@@ -152,6 +564,8 @@ static void
 filter_test_teardown (FilterTest    *fixture,
                       gconstpointer  test_data)
 {
+  signal_monitor_free (fixture->monitor);
+
   g_object_unref (fixture->filter);
   g_object_unref (fixture->store);
 }
@@ -247,6 +661,9 @@ check_filter_model (FilterTest *fixture)
 {
   GtkTreePath *path;
 
+  if (fixture->monitor)
+    signal_monitor_assert_is_empty (fixture->monitor);
+
   path = gtk_tree_path_new ();
 
   check_filter_model_recurse (fixture, path, gtk_tree_path_copy (path));
@@ -256,6 +673,9 @@ static void
 check_filter_model_with_root (FilterTest  *fixture,
                               GtkTreePath *path)
 {
+  if (fixture->monitor)
+    signal_monitor_assert_is_empty (fixture->monitor);
+
   check_filter_model_recurse (fixture,
                               gtk_tree_path_copy (path),
                               gtk_tree_path_new ());
@@ -345,20 +765,26 @@ static void
 filled_hide_root_level (FilterTest    *fixture,
                         gconstpointer  user_data)
 {
+  signal_monitor_append_signal (fixture->monitor, ROW_DELETED, "2");
   set_path_visibility (fixture, "2", FALSE);
   check_filter_model (fixture);
   check_level_length (fixture->filter, NULL, LEVEL_LENGTH - 1);
 
+  signal_monitor_append_signal (fixture->monitor, ROW_DELETED, "0");
   set_path_visibility (fixture, "0", FALSE);
   check_filter_model (fixture);
   check_level_length (fixture->filter, NULL, LEVEL_LENGTH - 2);
 
+  signal_monitor_append_signal (fixture->monitor, ROW_DELETED, "2");
   set_path_visibility (fixture, "4", FALSE);
   check_filter_model (fixture);
   check_level_length (fixture->filter, NULL, LEVEL_LENGTH - 3);
 
 
   /* Hide remaining */
+  signal_monitor_append_signal (fixture->monitor, ROW_DELETED, "0");
+  signal_monitor_append_signal (fixture->monitor, ROW_DELETED, "0");
+
   set_path_visibility (fixture, "1", FALSE);
   check_level_length (fixture->filter, NULL, LEVEL_LENGTH - 4);
 
@@ -368,6 +794,11 @@ filled_hide_root_level (FilterTest    *fixture,
   check_filter_model (fixture);
 
   /* Show some */
+  signal_monitor_append_signal (fixture->monitor, ROW_INSERTED, "0");
+  signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "0");
+  signal_monitor_append_signal (fixture->monitor, ROW_INSERTED, "1");
+  signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "1");
+
   set_path_visibility (fixture, "1", TRUE);
   check_level_length (fixture->filter, NULL, LEVEL_LENGTH - 4);
 
@@ -381,11 +812,13 @@ static void
 filled_hide_child_levels (FilterTest    *fixture,
                           gconstpointer  user_data)
 {
+  signal_monitor_append_signal (fixture->monitor, ROW_DELETED, "0:2");
   set_path_visibility (fixture, "0:2", FALSE);
   check_filter_model (fixture);
   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
   check_level_length (fixture->filter, "0", LEVEL_LENGTH - 1);
 
+  signal_monitor_append_signal (fixture->monitor, ROW_DELETED, "0:3");
   set_path_visibility (fixture, "0:4", FALSE);
   check_filter_model (fixture);
   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
@@ -404,19 +837,34 @@ filled_hide_child_levels (FilterTest    *fixture,
   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
   check_level_length (fixture->filter, "0", LEVEL_LENGTH - 2);
 
-  set_path_visibility (fixture, "0:4", TRUE);
   /* Since "0:2" is hidden, "0:4" must be "0:3" in the filter model */
+  signal_monitor_append_signal (fixture->monitor, ROW_INSERTED, "0:3");
+  /* FIXME: Actually, the filter model should not be emitted the
+   * row-has-child-toggled signal here.  *However* an extraneous emission
+   * of this signal does not hurt and is allowed.
+   */
+  signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "0:3");
+  set_path_visibility (fixture, "0:4", TRUE);
   check_filter_model (fixture);
   check_level_length (fixture->filter, "0:3", 0);
 
+  signal_monitor_append_signal (fixture->monitor, ROW_INSERTED, "0:2");
+  signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "0:2");
   set_path_visibility (fixture, "0:2", TRUE);
   check_filter_model (fixture);
   check_level_length (fixture->filter, "0:2", LEVEL_LENGTH);
   check_level_length (fixture->filter, "0:3", LEVEL_LENGTH);
   check_level_length (fixture->filter, "0:4", 0);
 
+  /* FIXME: We are missing a row-has-child-toggled signal for path "0:4" */
+  signal_monitor_append_signal (fixture->monitor, ROW_INSERTED, "0:4:0");
+  signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "0:4:0");
+  signal_monitor_append_signal (fixture->monitor, ROW_INSERTED, "0:4:1");
+  signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "0:4:1");
+
   set_path_visibility (fixture, "0:4:2", TRUE);
   set_path_visibility (fixture, "0:4:4", TRUE);
+  signal_monitor_assert_is_empty (fixture->monitor);
   check_level_length (fixture->filter, "0:4", 2);
 }
 
@@ -474,10 +922,12 @@ filled_vroot_hide_root_level (FilterTest    *fixture,
   check_filter_model_with_root (fixture, path);
 
   /* Now test changes in the virtual root level */
+  signal_monitor_append_signal (fixture->monitor, ROW_DELETED, "2");
   set_path_visibility (fixture, "2:2", FALSE);
   check_filter_model_with_root (fixture, path);
   check_level_length (fixture->filter, NULL, LEVEL_LENGTH - 1);
 
+  signal_monitor_append_signal (fixture->monitor, ROW_DELETED, "3");
   set_path_visibility (fixture, "2:4", FALSE);
   check_filter_model_with_root (fixture, path);
   check_level_length (fixture->filter, NULL, LEVEL_LENGTH - 2);
@@ -486,6 +936,8 @@ filled_vroot_hide_root_level (FilterTest    *fixture,
   check_filter_model_with_root (fixture, path);
   check_level_length (fixture->filter, NULL, LEVEL_LENGTH - 2);
 
+  signal_monitor_append_signal (fixture->monitor, ROW_INSERTED, "3");
+  signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "3");
   set_path_visibility (fixture, "2:4", TRUE);
   check_filter_model_with_root (fixture, path);
   check_level_length (fixture->filter, NULL, LEVEL_LENGTH - 1);
@@ -494,6 +946,10 @@ filled_vroot_hide_root_level (FilterTest    *fixture,
   check_filter_model_with_root (fixture, path);
   check_level_length (fixture->filter, NULL, LEVEL_LENGTH - 1);
 
+  signal_monitor_append_signal (fixture->monitor, ROW_DELETED, "0");
+  signal_monitor_append_signal (fixture->monitor, ROW_DELETED, "0");
+  signal_monitor_append_signal (fixture->monitor, ROW_DELETED, "0");
+  signal_monitor_append_signal (fixture->monitor, ROW_DELETED, "0");
   set_path_visibility (fixture, "2:0", FALSE);
   set_path_visibility (fixture, "2:1", FALSE);
   set_path_visibility (fixture, "2:2", FALSE);
@@ -510,10 +966,13 @@ filled_vroot_hide_root_level (FilterTest    *fixture,
   check_filter_model_with_root (fixture, path);
   check_level_length (fixture->filter, NULL, 0);
 
+  signal_monitor_append_signal (fixture->monitor, ROW_INSERTED, "0");
+  signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "0");
   set_path_visibility (fixture, "2:4", TRUE);
   check_filter_model_with_root (fixture, path);
   check_level_length (fixture->filter, NULL, LEVEL_LENGTH - 4);
 
+  signal_monitor_append_signal (fixture->monitor, ROW_DELETED, "0");
   set_path_visibility (fixture, "2:4", FALSE);
   check_filter_model_with_root (fixture, path);
   check_level_length (fixture->filter, NULL, 0);
@@ -522,6 +981,12 @@ filled_vroot_hide_root_level (FilterTest    *fixture,
   check_filter_model_with_root (fixture, path);
   check_level_length (fixture->filter, NULL, 0);
 
+  signal_monitor_append_signal (fixture->monitor, ROW_INSERTED, "0");
+  signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "0");
+  signal_monitor_append_signal (fixture->monitor, ROW_INSERTED, "1");
+  signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "1");
+  signal_monitor_append_signal (fixture->monitor, ROW_INSERTED, "2");
+  signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "2");
   set_path_visibility (fixture, "2:0", TRUE);
   set_path_visibility (fixture, "2:1", TRUE);
   set_path_visibility (fixture, "2:2", TRUE);
@@ -539,11 +1004,13 @@ filled_vroot_hide_child_levels (FilterTest    *fixture,
 {
   GtkTreePath *path = (GtkTreePath *)user_data;
 
+  signal_monitor_append_signal (fixture->monitor, ROW_DELETED, "0:2");
   set_path_visibility (fixture, "2:0:2", FALSE);
   check_filter_model_with_root (fixture, path);
   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
   check_level_length (fixture->filter, "0", LEVEL_LENGTH - 1);
 
+  signal_monitor_append_signal (fixture->monitor, ROW_DELETED, "0:3");
   set_path_visibility (fixture, "2:0:4", FALSE);
   check_filter_model_with_root (fixture, path);
   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
@@ -562,17 +1029,31 @@ filled_vroot_hide_child_levels (FilterTest    *fixture,
   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
   check_level_length (fixture->filter, "0", LEVEL_LENGTH - 2);
 
-  set_path_visibility (fixture, "2:0:4", TRUE);
   /* Since "0:2" is hidden, "0:4" must be "0:3" in the filter model */
+  signal_monitor_append_signal (fixture->monitor, ROW_INSERTED, "0:3");
+  /* FIXME: Actually, the filter model should not be emitted the
+   * row-has-child-toggled signal here.  *However* an extraneous emission
+   * of this signal does not hurt and is allowed.
+   */
+  signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "0:3");
+  set_path_visibility (fixture, "2:0:4", TRUE);
   check_filter_model_with_root (fixture, path);
   check_level_length (fixture->filter, "0:3", 0);
 
+  signal_monitor_append_signal (fixture->monitor, ROW_INSERTED, "0:2");
+  signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "0:2");
   set_path_visibility (fixture, "2:0:2", TRUE);
   check_filter_model_with_root (fixture, path);
   check_level_length (fixture->filter, "0:2", LEVEL_LENGTH);
   check_level_length (fixture->filter, "0:3", LEVEL_LENGTH);
   check_level_length (fixture->filter, "0:4", 0);
 
+  /* FIXME: We are missing a row-has-child-toggled signal for path "0:4" */
+  /* FIXME: Inconsistency!  For the non-vroot case we also receive two
+   * row-has-child-toggled signals here.
+   */
+  signal_monitor_append_signal (fixture->monitor, ROW_INSERTED, "0:4:0");
+  signal_monitor_append_signal (fixture->monitor, ROW_INSERTED, "0:4:1");
   set_path_visibility (fixture, "2:0:4:2", TRUE);
   set_path_visibility (fixture, "2:0:4:4", TRUE);
   check_level_length (fixture->filter, "0:4", 2);
@@ -586,6 +1067,8 @@ empty_show_nodes (FilterTest    *fixture,
   check_filter_model (fixture);
   check_level_length (fixture->filter, NULL, 0);
 
+  signal_monitor_append_signal (fixture->monitor, ROW_INSERTED, "0");
+  signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "0");
   set_path_visibility (fixture, "3", TRUE);
   check_filter_model (fixture);
   check_level_length (fixture->filter, NULL, 1);
@@ -596,6 +1079,8 @@ empty_show_nodes (FilterTest    *fixture,
   check_level_length (fixture->filter, NULL, 1);
   check_level_length (fixture->filter, "0", 0);
 
+  signal_monitor_append_signal (fixture->monitor, ROW_INSERTED, "0:0");
+  signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "0:0");
   set_path_visibility (fixture, "3:2", TRUE);
   check_filter_model (fixture);
   check_level_length (fixture->filter, NULL, 1);
@@ -603,10 +1088,13 @@ empty_show_nodes (FilterTest    *fixture,
   check_level_length (fixture->filter, "0:0", 1);
   check_level_length (fixture->filter, "0:0:0", 0);
 
+  signal_monitor_append_signal (fixture->monitor, ROW_DELETED, "0");
   set_path_visibility (fixture, "3", FALSE);
   check_filter_model (fixture);
   check_level_length (fixture->filter, NULL, 0);
 
+  signal_monitor_append_signal (fixture->monitor, ROW_INSERTED, "0");
+  signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "0");
   set_path_visibility (fixture, "3:2:1", TRUE);
   set_path_visibility (fixture, "3", TRUE);
   check_filter_model (fixture);
@@ -633,6 +1121,8 @@ empty_vroot_show_nodes (FilterTest    *fixture,
   check_filter_model_with_root (fixture, path);
   check_level_length (fixture->filter, NULL, 0);
 
+  signal_monitor_append_signal (fixture->monitor, ROW_INSERTED, "0");
+  signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "0");
   set_path_visibility (fixture, "2:2", TRUE);
   check_filter_model_with_root (fixture, path);
   check_level_length (fixture->filter, NULL, 1);
@@ -643,10 +1133,13 @@ empty_vroot_show_nodes (FilterTest    *fixture,
   check_filter_model_with_root (fixture, path);
   check_level_length (fixture->filter, NULL, 1);
 
+  signal_monitor_append_signal (fixture->monitor, ROW_DELETED, "0");
   set_path_visibility (fixture, "2:2", FALSE);
   check_filter_model_with_root (fixture, path);
   check_level_length (fixture->filter, NULL, 0);
 
+  signal_monitor_append_signal (fixture->monitor, ROW_INSERTED, "0");
+  signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "0");
   set_path_visibility (fixture, "2:2:1", TRUE);
   set_path_visibility (fixture, "2:2", TRUE);
   check_filter_model_with_root (fixture, path);
@@ -661,10 +1154,17 @@ unfiltered_hide_single (FilterTest    *fixture,
                         gconstpointer  user_data)
 
 {
+  signal_monitor_append_signal (fixture->monitor, ROW_CHANGED, "2");
+  signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "2");
   set_path_visibility (fixture, "2", FALSE);
 
+  signal_monitor_assert_is_empty (fixture->monitor);
   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
 
+  /* The view only shows the root level, so the filter model only has
+   * the first two levels cached.
+   */
+  filter_test_append_refilter_signals (fixture, 2);
   filter_test_enable_filter (fixture);
 
   check_filter_model (fixture);
@@ -676,11 +1176,18 @@ unfiltered_hide_single_child (FilterTest    *fixture,
                               gconstpointer  user_data)
 
 {
+  signal_monitor_append_signal (fixture->monitor, ROW_CHANGED, "2:2");
+  signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "2:2");
   set_path_visibility (fixture, "2:2", FALSE);
 
+  signal_monitor_assert_is_empty (fixture->monitor);
   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
   check_level_length (fixture->filter, "2", LEVEL_LENGTH);
 
+  /* The view only shows the root level, so the filter model only has
+   * the first two levels cached.
+   */
+  filter_test_append_refilter_signals (fixture, 2);
   filter_test_enable_filter (fixture);
 
   check_filter_model (fixture);
@@ -693,19 +1200,30 @@ unfiltered_hide_single_multi_level (FilterTest    *fixture,
                                     gconstpointer  user_data)
 
 {
+  /* This row is not shown, so its signal is not propagated */
   set_path_visibility (fixture, "2:2:2", FALSE);
+
+  signal_monitor_append_signal (fixture->monitor, ROW_CHANGED, "2:2");
+  signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "2:2");
   set_path_visibility (fixture, "2:2", FALSE);
 
+  signal_monitor_assert_is_empty (fixture->monitor);
   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
   check_level_length (fixture->filter, "2", LEVEL_LENGTH);
   check_level_length (fixture->filter, "2:2", LEVEL_LENGTH);
 
+  /* The view only shows the root level, so the filter model only has
+   * the first two levels cached.
+   */
+  filter_test_append_refilter_signals (fixture, 2);
   filter_test_enable_filter (fixture);
 
   check_filter_model (fixture);
   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
   check_level_length (fixture->filter, "2", LEVEL_LENGTH - 1);
 
+  signal_monitor_append_signal (fixture->monitor, ROW_INSERTED, "2:2");
+  signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "2:2");
   set_path_visibility (fixture, "2:2", TRUE);
 
   check_filter_model (fixture);
@@ -722,10 +1240,18 @@ unfiltered_vroot_hide_single (FilterTest    *fixture,
 {
   GtkTreePath *path = (GtkTreePath *)user_data;
 
+  signal_monitor_append_signal (fixture->monitor, ROW_CHANGED, "2");
+  signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "2");
   set_path_visibility (fixture, "2:2", FALSE);
 
+  signal_monitor_assert_is_empty (fixture->monitor);
   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
 
+  /* The view only shows the root level, so the filter model only has
+   * the first two levels cached.  (We add an additional level to
+   * take the virtual root into account).
+   */
+  filter_test_append_refilter_signals_with_vroot (fixture, 3, path);
   filter_test_enable_filter (fixture);
 
   check_filter_model_with_root (fixture, path);
@@ -739,11 +1265,19 @@ unfiltered_vroot_hide_single_child (FilterTest    *fixture,
 {
   GtkTreePath *path = (GtkTreePath *)user_data;
 
+  signal_monitor_append_signal (fixture->monitor, ROW_CHANGED, "2:2");
+  signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "2:2");
   set_path_visibility (fixture, "2:2:2", FALSE);
 
+  signal_monitor_assert_is_empty (fixture->monitor);
   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
   check_level_length (fixture->filter, "2", LEVEL_LENGTH);
 
+  /* The view only shows the root level, so the filter model only has
+   * the first two levels cached.  (We add an additional level to take
+   * the virtual root into account).
+   */
+  filter_test_append_refilter_signals_with_vroot (fixture, 3, path);
   filter_test_enable_filter (fixture);
 
   check_filter_model_with_root (fixture, path);
@@ -758,19 +1292,30 @@ unfiltered_vroot_hide_single_multi_level (FilterTest    *fixture,
 {
   GtkTreePath *path = (GtkTreePath *)user_data;
 
+  /* This row is not shown, so its signal is not propagated */
   set_path_visibility (fixture, "2:2:2:2", FALSE);
+
+  signal_monitor_append_signal (fixture->monitor, ROW_CHANGED, "2:2");
+  signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "2:2");
   set_path_visibility (fixture, "2:2:2", FALSE);
 
+  signal_monitor_assert_is_empty (fixture->monitor);
   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
   check_level_length (fixture->filter, "2", LEVEL_LENGTH);
   check_level_length (fixture->filter, "2:2", LEVEL_LENGTH);
 
+  /* The view only shows the root level, so the filter model only has
+   * the first two levels cached.
+   */
+  filter_test_append_refilter_signals_with_vroot (fixture, 3, path);
   filter_test_enable_filter (fixture);
 
   check_filter_model_with_root (fixture, path);
   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
   check_level_length (fixture->filter, "2", LEVEL_LENGTH - 1);
 
+  signal_monitor_append_signal (fixture->monitor, ROW_INSERTED, "2:2");
+  signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "2:2");
   set_path_visibility (fixture, "2:2:2", TRUE);
 
   check_filter_model_with_root (fixture, path);
@@ -786,10 +1331,17 @@ unfiltered_show_single (FilterTest    *fixture,
                         gconstpointer  user_data)
 
 {
+  signal_monitor_append_signal (fixture->monitor, ROW_CHANGED, "2");
+  signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "2");
   set_path_visibility (fixture, "2", TRUE);
 
+  signal_monitor_assert_is_empty (fixture->monitor);
   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
 
+  /* The view only shows the root level, so the filter model only has
+   * the first two levels cached.
+   */
+  filter_test_append_refilter_signals (fixture, 2);
   filter_test_enable_filter (fixture);
 
   check_filter_model (fixture);
@@ -801,11 +1353,18 @@ unfiltered_show_single_child (FilterTest    *fixture,
                               gconstpointer  user_data)
 
 {
+  signal_monitor_append_signal (fixture->monitor, ROW_CHANGED, "2:2");
+  signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "2:2");
   set_path_visibility (fixture, "2:2", TRUE);
 
+  signal_monitor_assert_is_empty (fixture->monitor);
   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
   check_level_length (fixture->filter, "2", LEVEL_LENGTH);
 
+  /* The view only shows the root level, so the filter model only has
+   * the first two levels cached.
+   */
+  filter_test_append_refilter_signals (fixture, 3);
   filter_test_enable_filter (fixture);
 
   check_filter_model (fixture);
@@ -814,7 +1373,10 @@ unfiltered_show_single_child (FilterTest    *fixture,
   /* From here we are filtered, "2" in the real model is "0" in the filter
    * model.
    */
+  signal_monitor_append_signal (fixture->monitor, ROW_INSERTED, "0");
+  signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "0");
   set_path_visibility (fixture, "2", TRUE);
+  signal_monitor_assert_is_empty (fixture->monitor);
   check_level_length (fixture->filter, NULL, 1);
   check_level_length (fixture->filter, "0", 1);
 }
@@ -824,13 +1386,24 @@ unfiltered_show_single_multi_level (FilterTest    *fixture,
                                     gconstpointer  user_data)
 
 {
+  /* The view is not showing this row (collapsed state), so it is not
+   * referenced.  The signal should not go through.
+   */
   set_path_visibility (fixture, "2:2:2", TRUE);
+
+  signal_monitor_append_signal (fixture->monitor, ROW_CHANGED, "2:2");
+  signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "2:2");
   set_path_visibility (fixture, "2:2", TRUE);
 
+  signal_monitor_assert_is_empty (fixture->monitor);
   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
   check_level_length (fixture->filter, "2", LEVEL_LENGTH);
   check_level_length (fixture->filter, "2:2", LEVEL_LENGTH);
 
+  /* The view only shows the root level, so the filter model only has
+   * the first two levels cached.
+   */
+  filter_test_append_refilter_signals (fixture, 3);
   filter_test_enable_filter (fixture);
 
   check_filter_model (fixture);
@@ -839,6 +1412,8 @@ unfiltered_show_single_multi_level (FilterTest    *fixture,
   /* From here we are filtered, "2" in the real model is "0" in the filter
    * model.
    */
+  signal_monitor_append_signal (fixture->monitor, ROW_INSERTED, "0");
+  signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "0");
   set_path_visibility (fixture, "2", TRUE);
   check_filter_model (fixture);
   check_level_length (fixture->filter, NULL, 1);
@@ -854,10 +1429,17 @@ unfiltered_vroot_show_single (FilterTest    *fixture,
 {
   GtkTreePath *path = (GtkTreePath *)user_data;
 
+  signal_monitor_append_signal (fixture->monitor, ROW_CHANGED, "2");
+  signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "2");
   set_path_visibility (fixture, "2:2", TRUE);
 
+  signal_monitor_assert_is_empty (fixture->monitor);
   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
 
+  /* The view only shows the root level, so the filter model only has
+   * the first two levels cached.
+   */
+  filter_test_append_refilter_signals_with_vroot (fixture, 3, path);
   filter_test_enable_filter (fixture);
 
   check_filter_model_with_root (fixture, path);
@@ -871,11 +1453,18 @@ unfiltered_vroot_show_single_child (FilterTest    *fixture,
 {
   GtkTreePath *path = (GtkTreePath *)user_data;
 
+  signal_monitor_append_signal (fixture->monitor, ROW_CHANGED, "2:2");
+  signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "2:2");
   set_path_visibility (fixture, "2:2:2", TRUE);
 
+  signal_monitor_assert_is_empty (fixture->monitor);
   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
   check_level_length (fixture->filter, "2", LEVEL_LENGTH);
 
+  /* The view only shows the root level, so the filter model only has
+   * the first two levels cached.
+   */
+  filter_test_append_refilter_signals_with_vroot (fixture, 2, path);
   filter_test_enable_filter (fixture);
 
   check_filter_model_with_root (fixture, path);
@@ -884,7 +1473,10 @@ unfiltered_vroot_show_single_child (FilterTest    *fixture,
   /* From here we are filtered, "2" in the real model is "0" in the filter
    * model.
    */
+  signal_monitor_append_signal (fixture->monitor, ROW_INSERTED, "0");
+  signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "0");
   set_path_visibility (fixture, "2:2", TRUE);
+  signal_monitor_assert_is_empty (fixture->monitor);
   check_level_length (fixture->filter, NULL, 1);
   check_level_length (fixture->filter, "0", 1);
 }
@@ -896,13 +1488,24 @@ unfiltered_vroot_show_single_multi_level (FilterTest    *fixture,
 {
   GtkTreePath *path = (GtkTreePath *)user_data;
 
+  /* The view is not showing this row (collapsed state), so it is not
+   * referenced.  The signal should not go through.
+   */
   set_path_visibility (fixture, "2:2:2:2", TRUE);
+
+  signal_monitor_append_signal (fixture->monitor, ROW_CHANGED, "2:2");
+  signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "2:2");
   set_path_visibility (fixture, "2:2:2", TRUE);
 
+  signal_monitor_assert_is_empty (fixture->monitor);
   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
   check_level_length (fixture->filter, "2", LEVEL_LENGTH);
   check_level_length (fixture->filter, "2:2", LEVEL_LENGTH);
 
+  /* The view only shows the root level, so the filter model only has
+   * the first two levels cached.
+   */
+  filter_test_append_refilter_signals_with_vroot (fixture, 4, path);
   filter_test_enable_filter (fixture);
 
   check_filter_model_with_root (fixture, path);
@@ -911,6 +1514,8 @@ unfiltered_vroot_show_single_multi_level (FilterTest    *fixture,
   /* From here we are filtered, "2" in the real model is "0" in the filter
    * model.
    */
+  signal_monitor_append_signal (fixture->monitor, ROW_INSERTED, "0");
+  signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "0");
   set_path_visibility (fixture, "2:2", TRUE);
   check_filter_model_with_root (fixture, path);
   check_level_length (fixture->filter, NULL, 1);
@@ -1214,6 +1819,7 @@ specific_root_mixed_visibility (void)
 
   filter = gtk_tree_model_filter_new (GTK_TREE_MODEL (fixture.store), NULL);
   fixture.filter = GTK_TREE_MODEL_FILTER (filter);
+  fixture.monitor = NULL;
 
   gtk_tree_model_filter_set_visible_column (fixture.filter, 1);
 
@@ -1248,6 +1854,7 @@ specific_has_child_filter (void)
   fixture.store = gtk_tree_store_new (2, G_TYPE_STRING, G_TYPE_BOOLEAN);
   filter = gtk_tree_model_filter_new (GTK_TREE_MODEL (fixture.store), NULL);
   fixture.filter = GTK_TREE_MODEL_FILTER (filter);
+  fixture.monitor = NULL;
 
   /* We will filter on parent state using a filter function.  We will
    * manually keep the boolean column in sync, so that we can use
@@ -1344,6 +1951,7 @@ specific_root_has_child_filter (void)
   fixture.store = gtk_tree_store_new (2, G_TYPE_STRING, G_TYPE_BOOLEAN);
   filter = gtk_tree_model_filter_new (GTK_TREE_MODEL (fixture.store), NULL);
   fixture.filter = GTK_TREE_MODEL_FILTER (filter);
+  fixture.monitor = NULL;
 
   /* We will filter on parent state using a filter function.  We will
    * manually keep the boolean column in sync, so that we can use



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