]> Pileus Git - ~andy/gtk/blobdiff - gtk/tests/filtermodel.c
Change FSF Address
[~andy/gtk] / gtk / tests / filtermodel.c
index 04f3307450a69665947190885add5db249cd4f8f..507ceefa305aa785314ff5b51a929236f39cc238 100644 (file)
  * Lesser General Public License for more details.
  *
  * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
  */
 
 #include <gtk/gtk.h>
+#include <string.h>
 
+#include "treemodel.h"
+#include "gtktreemodelrefcount.h"
 
 /* Left to do:
  *   - Proper coverage checking to see if the unit tests cover
  *     all possible cases.
- *   - Verify if the ref counting is done properly for both the
- *     normal ref_count and the zero_ref_count.  One way to test
- *     this area is by collapsing/expanding branches on the view
- *     that is connected to the filter model.
  *   - Check if the iterator stamp is incremented at the correct times.
+ *
+ * For more thorough testing:
+ *   - Test with randomized models.
+ *   - Extensively test a filter model wrapping a sort model,
+ *     or a sort model wrapping a filter model by:
+ *       # Checking structure.
+ *       # Checking for correct signals emissions.
+ *       # Checking correct reference counting.
+ *       # Tests should be done with the sort and filter model
+ *         in various filtering and sorting states.
  */
 
 
@@ -90,278 +97,6 @@ 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;
-
-static const char *
-signal_name_to_string (SignalName signal)
-{
-  switch (signal)
-    {
-      case ROW_INSERTED:
-          return "row-inserted";
-
-      case ROW_DELETED:
-          return "row-deleted";
-
-      case ROW_CHANGED:
-          return "row-changed";
-
-      case ROW_HAS_CHILD_TOGGLED:
-          return "row-has-child-toggled";
-
-      case ROWS_REORDERED:
-          return "rows-reordered";
-
-      default:
-          /* Fall through */
-          break;
-    }
-
-  return "(unknown)";
-}
-
-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;
-  gulong signal_ids[LAST_SIGNAL];
-}
-SignalMonitor;
-
-
-static void
-signal_monitor_generic_handler (SignalMonitor *m,
-                                SignalName     signal,
-                                GtkTreeModel  *model,
-                                GtkTreePath   *path)
-{
-  Signal *s;
-
-  if (g_queue_is_empty (m->queue))
-    {
-      gchar *path_str;
-
-      path_str = gtk_tree_path_to_string (path);
-      g_error ("Signal queue empty, got signal %s path %s\n",
-               signal_name_to_string (signal), path_str);
-      g_free (path_str);
-
-      g_assert_not_reached ();
-    }
-
-  if (m->client != model)
-    {
-      g_error ("Model mismatch; expected %p, got %p\n",
-               m->client, model);
-      g_assert_not_reached ();
-    }
-
-  s = g_queue_peek_tail (m->queue);
-
-#if 0
-  /* For debugging: output signals that are coming in.  Leaks memory. */
-  g_print ("signal=%s path=%s\n", signal_name_to_string (signal),
-           gtk_tree_path_to_string (path));
-#endif
-
-  if (s->signal != signal
-      || gtk_tree_path_compare (s->path, path) != 0)
-    {
-      gchar *path_str, *s_path_str;
-
-      s_path_str = gtk_tree_path_to_string (s->path);
-      path_str = gtk_tree_path_to_string (path);
-
-      g_error ("Signals don't match; expected signal %s path %s, got signal %s path %s\n",
-               signal_name_to_string (s->signal), s_path_str,
-               signal_name_to_string (signal), path_str);
-
-      g_free (s_path_str);
-      g_free (path_str);
-
-      g_assert_not_reached ();
-    }
-
-  s = g_queue_pop_tail (m->queue);
-
-  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
  */
@@ -1274,11 +1009,13 @@ filled_vroot_hide_child_levels (FilterTest    *fixture,
   check_level_length (fixture->filter, "0:3", LEVEL_LENGTH);
   check_level_length (fixture->filter, "0:4", 0);
 
-  /* Once 0:4:0 got inserted, 0:4 became a parent */
-  signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "0:4");
+  /* Once 0:4:0 got inserted, 0:4 became a parent. However, 0:4 is not
+   * visible, so no signal should be emitted.
+   */
   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);
+  signal_monitor_assert_is_empty (fixture->monitor);
 }
 
 static void
@@ -1337,6 +1074,7 @@ filled_vroot_hide_child_levels_root_expanded (FilterTest    *fixture,
   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);
+  signal_monitor_assert_is_empty (fixture->monitor);
 }
 
 static void
@@ -2235,118 +1973,486 @@ unfiltered_vroot_show_single_multi_level_root_expanded (FilterTest    *fixture,
   check_level_length (fixture->filter, "0:0", 1);
 }
 
-
 static void
-insert_before (void)
+unfiltered_rows_reordered_root_level (FilterTest    *fixture,
+                                      gconstpointer  user_data)
 {
-  GtkTreeStore *store;
-  GtkTreeModel *filter;
-  GtkWidget *tree_view;
-  SignalMonitor *monitor;
-  GtkTreeIter iter;
-  GtkTreeIter last_iter;
+  int order0[] = { 1, 2, 3, 4, 0 };
+  int order1[] = { 0, 2, 1, 3, 4 };
+  int order2[] = { 4, 0, 1, 2, 3 };
+  GtkTreeIter iter0, iter1, iter2, iter3, iter4;
   GtkTreePath *path;
 
-  /* This tests two aspects of the row-inserted handling:
-   *   1) If the newly inserted node was already handled by building
-   *      the root level, don't handle it a second time.
-   *   2) Offsets of existing nodes must be updated when a new
-   *      node is inserted.
-   */
+  gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL (fixture->store),
+                                       &iter0, "0");
+  gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL (fixture->store),
+                                       &iter1, "1");
+  gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL (fixture->store),
+                                       &iter2, "2");
+  gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL (fixture->store),
+                                       &iter3, "3");
+  gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL (fixture->store),
+                                       &iter4, "4");
 
-  store = gtk_tree_store_new (2, G_TYPE_STRING, G_TYPE_BOOLEAN);
-  filter = gtk_tree_model_filter_new (GTK_TREE_MODEL (store), NULL);
-  gtk_tree_model_filter_set_visible_column (GTK_TREE_MODEL_FILTER (filter),
-                                            1);
+  path = gtk_tree_path_new ();
+  signal_monitor_append_signal_reordered (fixture->monitor,
+                                          ROWS_REORDERED,
+                                          path, order0, 5);
+  gtk_tree_store_move_after (fixture->store, &iter0, &iter4);
+  signal_monitor_assert_is_empty (fixture->monitor);
 
-  tree_view = gtk_tree_view_new_with_model (filter);
-  monitor = signal_monitor_new (filter);
+  signal_monitor_append_signal_reordered (fixture->monitor,
+                                          ROWS_REORDERED,
+                                          path, order1, 5);
+  gtk_tree_store_move_after (fixture->store, &iter2, &iter3);
+  signal_monitor_assert_is_empty (fixture->monitor);
 
-  check_level_length (GTK_TREE_MODEL_FILTER (filter), NULL, 0);
+  signal_monitor_append_signal_reordered (fixture->monitor,
+                                          ROWS_REORDERED,
+                                          path, order2, 5);
+  gtk_tree_store_move_before (fixture->store, &iter0, &iter1);
+  signal_monitor_assert_is_empty (fixture->monitor);
 
-  /* Insert 0 */
-  path = gtk_tree_path_new_from_indices (0, -1);
-  signal_monitor_append_signal_path (monitor, ROW_INSERTED, path);
   gtk_tree_path_free (path);
+}
 
-  gtk_tree_store_insert_with_values (store, &iter, NULL, 0,
-                                     0, "Foo", 1, TRUE, -1);
-
-  signal_monitor_assert_is_empty (monitor);
-  check_level_length (GTK_TREE_MODEL_FILTER (filter), NULL, 1);
+static void
+unfiltered_rows_reordered_child_level (FilterTest    *fixture,
+                                       gconstpointer  user_data)
+{
+  int order0[] = { 1, 2, 3, 4, 0 };
+  int order1[] = { 0, 2, 1, 3, 4 };
+  int order2[] = { 4, 0, 1, 2, 3 };
+  GtkTreeIter iter0, iter1, iter2, iter3, iter4;
+  GtkTreePath *path;
 
-  /* Insert 1 */
-  path = gtk_tree_path_new_from_indices (1, -1);
-  signal_monitor_append_signal_path (monitor, ROW_INSERTED, path);
-  gtk_tree_path_free (path);
+  /* Expand row 0 */
+  path = gtk_tree_path_new_from_indices (0, -1);
+  gtk_tree_view_expand_row (GTK_TREE_VIEW (fixture->tree_view), path, FALSE);
 
-  gtk_tree_store_insert_with_values (store, &iter, NULL, 1,
-                                     0, "Foo", 1, TRUE, -1);
-  last_iter = iter;
+  gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL (fixture->store),
+                                       &iter0, "0:0");
+  gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL (fixture->store),
+                                       &iter1, "0:1");
+  gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL (fixture->store),
+                                       &iter2, "0:2");
+  gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL (fixture->store),
+                                       &iter3, "0:3");
+  gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL (fixture->store),
+                                       &iter4, "0:4");
 
-  signal_monitor_assert_is_empty (monitor);
-  check_level_length (GTK_TREE_MODEL_FILTER (filter), NULL, 2);
+  signal_monitor_append_signal_reordered (fixture->monitor,
+                                          ROWS_REORDERED,
+                                          path, order0, 5);
+  gtk_tree_store_move_after (fixture->store, &iter0, &iter4);
+  signal_monitor_assert_is_empty (fixture->monitor);
 
-  /* Insert on 1 again -- invisible */
-  gtk_tree_store_insert_with_values (store, &iter, NULL, 1,
-                                     0, "Foo", 1, FALSE, -1);
+  signal_monitor_append_signal_reordered (fixture->monitor,
+                                          ROWS_REORDERED,
+                                          path, order1, 5);
+  gtk_tree_store_move_after (fixture->store, &iter2, &iter3);
+  signal_monitor_assert_is_empty (fixture->monitor);
 
-  signal_monitor_assert_is_empty (monitor);
-  check_level_length (GTK_TREE_MODEL_FILTER (filter), NULL, 2);
+  signal_monitor_append_signal_reordered (fixture->monitor,
+                                          ROWS_REORDERED,
+                                          path, order2, 5);
+  gtk_tree_store_move_before (fixture->store, &iter0, &iter1);
+  signal_monitor_assert_is_empty (fixture->monitor);
 
-  /* Insert on 1 again -- visible */
-  path = gtk_tree_path_new_from_indices (1, -1);
-  signal_monitor_append_signal_path (monitor, ROW_INSERTED, path);
   gtk_tree_path_free (path);
+}
 
-  gtk_tree_store_insert_with_values (store, &iter, NULL, 1,
-                                     0, "Foo", 1, TRUE, -1);
+static void
+filtered_rows_reordered_root_level_first_hidden (FilterTest    *fixture,
+                                                 gconstpointer  user_data)
+{
+  int order0[] = { 1, 2, 3, 0 };
+  int order1[] = { 0, 2, 1, 3 };
+  int order2[] = { 3, 0, 1, 2 };
+  GtkTreeIter iter1, iter2, iter3, iter4;
+  GtkTreePath *path;
 
-  signal_monitor_assert_is_empty (monitor);
-  check_level_length (GTK_TREE_MODEL_FILTER (filter), NULL, 3);
+  /* Hide middle path */
+  signal_monitor_append_signal (fixture->monitor,
+                                ROW_DELETED, "0");
+  set_path_visibility (fixture, "0", FALSE);
+  signal_monitor_assert_is_empty (fixture->monitor);
 
-  /* Modify the iter that should be at the last position and check the
-   * signal we get.
-   */
-  path = gtk_tree_path_new_from_indices (2, -1);
-  signal_monitor_append_signal_path (monitor, ROW_CHANGED, path);
-  gtk_tree_path_free (path);
+  gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL (fixture->store),
+                                       &iter1, "1");
+  gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL (fixture->store),
+                                       &iter2, "2");
+  gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL (fixture->store),
+                                       &iter3, "3");
+  gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL (fixture->store),
+                                       &iter4, "4");
 
-  gtk_tree_store_set (store, &last_iter, 0, "Foo changed", -1);
+  path = gtk_tree_path_new ();
+  signal_monitor_append_signal_reordered (fixture->monitor,
+                                          ROWS_REORDERED,
+                                          path, order0, 4);
+  gtk_tree_store_move_after (fixture->store, &iter1, &iter4);
+  signal_monitor_assert_is_empty (fixture->monitor);
 
-  signal_monitor_assert_is_empty (monitor);
-  check_level_length (GTK_TREE_MODEL_FILTER (filter), NULL, 3);
+  signal_monitor_append_signal_reordered (fixture->monitor,
+                                          ROWS_REORDERED,
+                                          path, order1, 4);
+  gtk_tree_store_move_after (fixture->store, &iter3, &iter4);
+  signal_monitor_assert_is_empty (fixture->monitor);
+
+  signal_monitor_append_signal_reordered (fixture->monitor,
+                                          ROWS_REORDERED,
+                                          path, order2, 4);
+  gtk_tree_store_move_before (fixture->store, &iter1, &iter2);
+  signal_monitor_assert_is_empty (fixture->monitor);
+
+  gtk_tree_path_free (path);
 }
 
 static void
-insert_child (void)
+filtered_rows_reordered_root_level_middle_hidden (FilterTest    *fixture,
+                                                  gconstpointer  user_data)
 {
-  GtkTreeStore *store;
-  GtkTreeModel *filter;
-  GtkWidget *tree_view;
-  SignalMonitor *monitor;
-  GtkTreeIter parent, iter;
+  int order0[] = { 1, 2, 3, 0 };
+  int order1[] = { 0, 2, 1, 3 };
+  int order2[] = { 3, 0, 1, 2 };
+  GtkTreeIter iter0, iter1, iter3, iter4;
   GtkTreePath *path;
 
-  store = gtk_tree_store_new (2, G_TYPE_STRING, G_TYPE_BOOLEAN);
+  /* Hide middle path */
+  signal_monitor_append_signal (fixture->monitor,
+                                ROW_DELETED, "2");
+  set_path_visibility (fixture, "2", FALSE);
+  signal_monitor_assert_is_empty (fixture->monitor);
 
-  gtk_tree_store_insert_with_values (store, &parent, NULL, 0,
-                                     0, "Parent", 1, TRUE, -1);
+  gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL (fixture->store),
+                                       &iter0, "0");
+  gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL (fixture->store),
+                                       &iter1, "1");
+  gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL (fixture->store),
+                                       &iter3, "3");
+  gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL (fixture->store),
+                                       &iter4, "4");
 
+  path = gtk_tree_path_new ();
+  signal_monitor_append_signal_reordered (fixture->monitor,
+                                          ROWS_REORDERED,
+                                          path, order0, 4);
+  gtk_tree_store_move_after (fixture->store, &iter0, &iter4);
+  signal_monitor_assert_is_empty (fixture->monitor);
 
-  filter = gtk_tree_model_filter_new (GTK_TREE_MODEL (store), NULL);
-  gtk_tree_model_filter_set_visible_column (GTK_TREE_MODEL_FILTER (filter),
-                                            1);
+  signal_monitor_append_signal_reordered (fixture->monitor,
+                                          ROWS_REORDERED,
+                                          path, order1, 4);
+  gtk_tree_store_move_after (fixture->store, &iter3, &iter4);
+  signal_monitor_assert_is_empty (fixture->monitor);
 
-  tree_view = gtk_tree_view_new_with_model (filter);
-  monitor = signal_monitor_new (filter);
+  signal_monitor_append_signal_reordered (fixture->monitor,
+                                          ROWS_REORDERED,
+                                          path, order2, 4);
+  gtk_tree_store_move_before (fixture->store, &iter0, &iter1);
+  signal_monitor_assert_is_empty (fixture->monitor);
 
-  /* Insert child -- invisible */
-  path = gtk_tree_path_new_from_indices (0, -1);
-  signal_monitor_append_signal_path (monitor, ROW_HAS_CHILD_TOGGLED, path);
-  /* The signal is received twice, once a pass through from GtkTreeStore
-   * and one generated by GtkTreeModelFilter.  Not accurate, but cannot
-   * hurt.
+  gtk_tree_path_free (path);
+}
+
+static void
+filtered_rows_reordered_child_level_first_hidden (FilterTest    *fixture,
+                                                  gconstpointer  user_data)
+{
+  int order0[] = { 1, 2, 3, 0 };
+  int order1[] = { 0, 2, 1, 3 };
+  int order2[] = { 3, 0, 1, 2 };
+  GtkTreeIter iter1, iter2, iter3, iter4;
+  GtkTreePath *path;
+
+  /* Expand row 0 */
+  path = gtk_tree_path_new_from_indices (0, -1);
+  gtk_tree_view_expand_row (GTK_TREE_VIEW (fixture->tree_view), path, TRUE);
+
+  /* Hide middle path */
+  signal_monitor_append_signal (fixture->monitor,
+                                ROW_DELETED, "0:0");
+  set_path_visibility (fixture, "0:0", FALSE);
+  signal_monitor_assert_is_empty (fixture->monitor);
+
+  gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL (fixture->store),
+                                       &iter1, "0:1");
+  gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL (fixture->store),
+                                       &iter2, "0:2");
+  gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL (fixture->store),
+                                       &iter3, "0:3");
+  gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL (fixture->store),
+                                       &iter4, "0:4");
+
+  signal_monitor_append_signal_reordered (fixture->monitor,
+                                          ROWS_REORDERED,
+                                          path, order0, 4);
+  gtk_tree_store_move_after (fixture->store, &iter1, &iter4);
+  signal_monitor_assert_is_empty (fixture->monitor);
+
+  signal_monitor_append_signal_reordered (fixture->monitor,
+                                          ROWS_REORDERED,
+                                          path, order1, 4);
+  gtk_tree_store_move_after (fixture->store, &iter3, &iter4);
+  signal_monitor_assert_is_empty (fixture->monitor);
+
+  signal_monitor_append_signal_reordered (fixture->monitor,
+                                          ROWS_REORDERED,
+                                          path, order2, 4);
+  gtk_tree_store_move_before (fixture->store, &iter1, &iter2);
+  signal_monitor_assert_is_empty (fixture->monitor);
+
+  gtk_tree_path_free (path);
+}
+
+static void
+filtered_rows_reordered_child_level_middle_hidden (FilterTest    *fixture,
+                                                   gconstpointer  user_data)
+{
+  int order0[] = { 1, 2, 3, 0 };
+  int order1[] = { 0, 2, 1, 3 };
+  int order2[] = { 3, 0, 1, 2 };
+  GtkTreeIter iter0, iter1, iter3, iter4;
+  GtkTreePath *path;
+
+  /* Expand row 0 */
+  path = gtk_tree_path_new_from_indices (0, -1);
+  gtk_tree_view_expand_row (GTK_TREE_VIEW (fixture->tree_view), path, FALSE);
+
+  /* Hide middle path */
+  signal_monitor_append_signal (fixture->monitor,
+                                ROW_DELETED, "0:2");
+  set_path_visibility (fixture, "0:2", FALSE);
+  signal_monitor_assert_is_empty (fixture->monitor);
+
+  gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL (fixture->store),
+                                       &iter0, "0:0");
+  gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL (fixture->store),
+                                       &iter1, "0:1");
+  gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL (fixture->store),
+                                       &iter3, "0:3");
+  gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL (fixture->store),
+                                       &iter4, "0:4");
+
+  signal_monitor_append_signal_reordered (fixture->monitor,
+                                          ROWS_REORDERED,
+                                          path, order0, 4);
+  gtk_tree_store_move_after (fixture->store, &iter0, &iter4);
+  signal_monitor_assert_is_empty (fixture->monitor);
+
+  signal_monitor_append_signal_reordered (fixture->monitor,
+                                          ROWS_REORDERED,
+                                          path, order1, 4);
+  gtk_tree_store_move_after (fixture->store, &iter3, &iter4);
+  signal_monitor_assert_is_empty (fixture->monitor);
+
+  signal_monitor_append_signal_reordered (fixture->monitor,
+                                          ROWS_REORDERED,
+                                          path, order2, 4);
+  gtk_tree_store_move_before (fixture->store, &iter0, &iter1);
+  signal_monitor_assert_is_empty (fixture->monitor);
+
+  gtk_tree_path_free (path);
+}
+
+static void
+filtered_rows_reordered_child_level_4_hidden (FilterTest    *fixture,
+                                              gconstpointer  user_data)
+{
+  int order0[] = { 0 };
+  GtkTreeIter iter1, iter4;
+  GtkTreePath *path;
+
+  /* Expand row 0 */
+  path = gtk_tree_path_new_from_indices (0, -1);
+  gtk_tree_view_expand_row (GTK_TREE_VIEW (fixture->tree_view), path, FALSE);
+
+  /* Hide last 4 paths */
+  signal_monitor_append_signal (fixture->monitor,
+                                ROW_DELETED, "0:4");
+  signal_monitor_append_signal (fixture->monitor,
+                                ROW_DELETED, "0:3");
+  signal_monitor_append_signal (fixture->monitor,
+                                ROW_DELETED, "0:2");
+  signal_monitor_append_signal (fixture->monitor,
+                                ROW_DELETED, "0:0");
+  set_path_visibility (fixture, "0:4", FALSE);
+  set_path_visibility (fixture, "0:3", FALSE);
+  set_path_visibility (fixture, "0:2", FALSE);
+  set_path_visibility (fixture, "0:0", FALSE);
+  signal_monitor_assert_is_empty (fixture->monitor);
+
+  gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL (fixture->store),
+                                       &iter1, "0:1");
+  gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL (fixture->store),
+                                       &iter4, "0:4");
+
+  signal_monitor_append_signal_reordered (fixture->monitor,
+                                          ROWS_REORDERED,
+                                          path, order0, 1);
+  gtk_tree_store_move_after (fixture->store, &iter1, &iter4);
+  signal_monitor_assert_is_empty (fixture->monitor);
+
+  gtk_tree_path_free (path);
+}
+
+static void
+filtered_rows_reordered_child_level_all_hidden (FilterTest    *fixture,
+                                                gconstpointer  user_data)
+{
+  GtkTreeIter iter1, iter4;
+  GtkTreePath *path;
+
+  /* Expand row 0 */
+  path = gtk_tree_path_new_from_indices (0, -1);
+  gtk_tree_view_expand_row (GTK_TREE_VIEW (fixture->tree_view), path, FALSE);
+  gtk_tree_path_free (path);
+
+  /* Hide last 4 paths */
+  signal_monitor_append_signal (fixture->monitor,
+                                ROW_DELETED, "0:4");
+  signal_monitor_append_signal (fixture->monitor,
+                                ROW_DELETED, "0:3");
+  signal_monitor_append_signal (fixture->monitor,
+                                ROW_DELETED, "0:2");
+  signal_monitor_append_signal (fixture->monitor,
+                                ROW_DELETED, "0:1");
+  signal_monitor_append_signal (fixture->monitor,
+                                ROW_DELETED, "0:0");
+  signal_monitor_append_signal (fixture->monitor,
+                                ROW_HAS_CHILD_TOGGLED, "0");
+  set_path_visibility (fixture, "0:4", FALSE);
+  set_path_visibility (fixture, "0:3", FALSE);
+  set_path_visibility (fixture, "0:2", FALSE);
+  set_path_visibility (fixture, "0:1", FALSE);
+  set_path_visibility (fixture, "0:0", FALSE);
+  signal_monitor_assert_is_empty (fixture->monitor);
+
+  gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL (fixture->store),
+                                       &iter1, "0:1");
+  gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL (fixture->store),
+                                       &iter4, "0:4");
+
+  gtk_tree_store_move_after (fixture->store, &iter1, &iter4);
+  signal_monitor_assert_is_empty (fixture->monitor);
+}
+
+static void
+insert_before (void)
+{
+  GtkTreeStore *store;
+  GtkTreeModel *filter;
+  GtkWidget *tree_view;
+  SignalMonitor *monitor;
+  GtkTreeIter iter;
+  GtkTreeIter last_iter;
+  GtkTreePath *path;
+
+  /* This tests two aspects of the row-inserted handling:
+   *   1) If the newly inserted node was already handled by building
+   *      the root level, don't handle it a second time.
+   *   2) Offsets of existing nodes must be updated when a new
+   *      node is inserted.
+   */
+
+  store = gtk_tree_store_new (2, G_TYPE_STRING, G_TYPE_BOOLEAN);
+  filter = gtk_tree_model_filter_new (GTK_TREE_MODEL (store), NULL);
+  gtk_tree_model_filter_set_visible_column (GTK_TREE_MODEL_FILTER (filter),
+                                            1);
+
+  tree_view = gtk_tree_view_new_with_model (filter);
+  monitor = signal_monitor_new (filter);
+
+  check_level_length (GTK_TREE_MODEL_FILTER (filter), NULL, 0);
+
+  /* Insert 0 */
+  path = gtk_tree_path_new_from_indices (0, -1);
+  signal_monitor_append_signal_path (monitor, ROW_INSERTED, path);
+  gtk_tree_path_free (path);
+
+  gtk_tree_store_insert_with_values (store, &iter, NULL, 0,
+                                     0, "Foo", 1, TRUE, -1);
+
+  signal_monitor_assert_is_empty (monitor);
+  check_level_length (GTK_TREE_MODEL_FILTER (filter), NULL, 1);
+
+  /* Insert 1 */
+  path = gtk_tree_path_new_from_indices (1, -1);
+  signal_monitor_append_signal_path (monitor, ROW_INSERTED, path);
+  gtk_tree_path_free (path);
+
+  gtk_tree_store_insert_with_values (store, &iter, NULL, 1,
+                                     0, "Foo", 1, TRUE, -1);
+  last_iter = iter;
+
+  signal_monitor_assert_is_empty (monitor);
+  check_level_length (GTK_TREE_MODEL_FILTER (filter), NULL, 2);
+
+  /* Insert on 1 again -- invisible */
+  gtk_tree_store_insert_with_values (store, &iter, NULL, 1,
+                                     0, "Foo", 1, FALSE, -1);
+
+  signal_monitor_assert_is_empty (monitor);
+  check_level_length (GTK_TREE_MODEL_FILTER (filter), NULL, 2);
+
+  /* Insert on 1 again -- visible */
+  path = gtk_tree_path_new_from_indices (1, -1);
+  signal_monitor_append_signal_path (monitor, ROW_INSERTED, path);
+  gtk_tree_path_free (path);
+
+  gtk_tree_store_insert_with_values (store, &iter, NULL, 1,
+                                     0, "Foo", 1, TRUE, -1);
+
+  signal_monitor_assert_is_empty (monitor);
+  check_level_length (GTK_TREE_MODEL_FILTER (filter), NULL, 3);
+
+  /* Modify the iter that should be at the last position and check the
+   * signal we get.
+   */
+  path = gtk_tree_path_new_from_indices (2, -1);
+  signal_monitor_append_signal_path (monitor, ROW_CHANGED, path);
+  gtk_tree_path_free (path);
+
+  gtk_tree_store_set (store, &last_iter, 0, "Foo changed", -1);
+
+  signal_monitor_assert_is_empty (monitor);
+  check_level_length (GTK_TREE_MODEL_FILTER (filter), NULL, 3);
+
+  g_object_unref (filter);
+  g_object_unref (store);
+  gtk_widget_destroy (tree_view);
+}
+
+static void
+insert_child (void)
+{
+  GtkTreeStore *store;
+  GtkTreeModel *filter;
+  GtkWidget *tree_view;
+  SignalMonitor *monitor;
+  GtkTreeIter parent, iter;
+  GtkTreePath *path;
+
+  store = gtk_tree_store_new (2, G_TYPE_STRING, G_TYPE_BOOLEAN);
+
+  gtk_tree_store_insert_with_values (store, &parent, NULL, 0,
+                                     0, "Parent", 1, TRUE, -1);
+
+
+  filter = gtk_tree_model_filter_new (GTK_TREE_MODEL (store), NULL);
+  gtk_tree_model_filter_set_visible_column (GTK_TREE_MODEL_FILTER (filter),
+                                            1);
+
+  tree_view = gtk_tree_view_new_with_model (filter);
+  monitor = signal_monitor_new (filter);
+
+  /* Insert child -- invisible */
+  path = gtk_tree_path_new_from_indices (0, -1);
+  signal_monitor_append_signal_path (monitor, ROW_HAS_CHILD_TOGGLED, path);
+  /* The signal is received twice, once a pass through from GtkTreeStore
+   * and one generated by GtkTreeModelFilter.  Not accurate, but cannot
+   * hurt.
    */
   signal_monitor_append_signal_path (monitor, ROW_HAS_CHILD_TOGGLED, path);
   gtk_tree_path_free (path);
@@ -2375,6 +2481,10 @@ insert_child (void)
 
   signal_monitor_assert_is_empty (monitor);
   check_level_length (GTK_TREE_MODEL_FILTER (filter), NULL, 1);
+
+  g_object_unref (filter);
+  g_object_unref (store);
+  gtk_widget_destroy (tree_view);
 }
 
 
@@ -2404,83 +2514,2069 @@ remove_node (void)
   gtk_list_store_remove (list, &iter3);
   gtk_list_store_remove (list, &iter2);
 
-  gtk_widget_destroy (view);
-  g_object_unref (filter);
-  g_object_unref (list);
-}
+  gtk_widget_destroy (view);
+  g_object_unref (filter);
+  g_object_unref (list);
+}
+
+static void
+remove_node_vroot (void)
+{
+  GtkTreeIter parent, root;
+  GtkTreeIter iter, iter1, iter2, iter3;
+  GtkTreeStore *tree;
+  GtkTreeModel *filter;
+  GtkTreePath *path;
+  GtkWidget *view G_GNUC_UNUSED;
+
+  tree = gtk_tree_store_new (1, G_TYPE_INT);
+  gtk_tree_store_insert_with_values (tree, &parent, NULL, 0, 0, 0, -1);
+  gtk_tree_store_insert_with_values (tree, &root, &parent, 0, 0, 0, -1);
+
+  gtk_tree_store_insert_with_values (tree, &iter1, &root, 0, 0, 1, -1);
+  gtk_tree_store_insert_with_values (tree, &iter, &root, 1, 0, 2, -1);
+  gtk_tree_store_insert_with_values (tree, &iter, &root, 2, 0, 3, -1);
+  gtk_tree_store_insert_with_values (tree, &iter, &root, 3, 0, 4, -1);
+  gtk_tree_store_insert_with_values (tree, &iter, &root, 4, 0, 5, -1);
+  gtk_tree_store_insert_with_values (tree, &iter, &root, 5, 0, 6, -1);
+  gtk_tree_store_insert_with_values (tree, &iter2, &root, 6, 0, 7, -1);
+  gtk_tree_store_insert_with_values (tree, &iter3, &root, 7, 0, 8, -1);
+
+  path = gtk_tree_path_new_from_indices (0, 0, -1);
+  filter = gtk_tree_model_filter_new (GTK_TREE_MODEL (tree), path);
+  gtk_tree_path_free (path);
+
+  view = gtk_tree_view_new_with_model (filter);
+
+  gtk_tree_store_remove (tree, &iter1);
+  gtk_tree_store_remove (tree, &iter3);
+  gtk_tree_store_remove (tree, &iter2);
+
+  gtk_widget_destroy (view);
+  g_object_unref (filter);
+  g_object_unref (tree);
+}
+
+static void
+remove_vroot_ancestor (void)
+{
+  GtkTreeIter parent, root;
+  GtkTreeIter iter, iter1, iter2, iter3;
+  GtkTreeStore *tree;
+  GtkTreeModel *filter;
+  GtkTreePath *path;
+  GtkWidget *view G_GNUC_UNUSED;
+
+  tree = gtk_tree_store_new (1, G_TYPE_INT);
+  gtk_tree_store_insert_with_values (tree, &parent, NULL, 0, 0, 0, -1);
+  gtk_tree_store_insert_with_values (tree, &root, &parent, 0, 0, 0, -1);
+
+  gtk_tree_store_insert_with_values (tree, &iter1, &root, 0, 0, 1, -1);
+  gtk_tree_store_insert_with_values (tree, &iter, &root, 1, 0, 2, -1);
+  gtk_tree_store_insert_with_values (tree, &iter, &root, 2, 0, 3, -1);
+  gtk_tree_store_insert_with_values (tree, &iter, &root, 3, 0, 4, -1);
+  gtk_tree_store_insert_with_values (tree, &iter, &root, 4, 0, 5, -1);
+  gtk_tree_store_insert_with_values (tree, &iter, &root, 5, 0, 6, -1);
+  gtk_tree_store_insert_with_values (tree, &iter2, &root, 6, 0, 7, -1);
+  gtk_tree_store_insert_with_values (tree, &iter3, &root, 7, 0, 8, -1);
+
+  path = gtk_tree_path_new_from_indices (0, 0, -1);
+  filter = gtk_tree_model_filter_new (GTK_TREE_MODEL (tree), path);
+  gtk_tree_path_free (path);
+
+  view = gtk_tree_view_new_with_model (filter);
+
+  gtk_tree_store_remove (tree, &parent);
+
+  gtk_widget_destroy (view);
+  g_object_unref (filter);
+  g_object_unref (tree);
+}
+
+static void
+ref_count_single_level (void)
+{
+  GtkTreeIter iter[5];
+  GtkTreeModel *model;
+  GtkTreeModelRefCount *ref_model;
+  GtkTreeModel *filter_model;
+  GtkWidget *tree_view;
+
+  model = gtk_tree_model_ref_count_new ();
+  ref_model = GTK_TREE_MODEL_REF_COUNT (model);
+
+  gtk_tree_store_append (GTK_TREE_STORE (model), &iter[0], NULL);
+  gtk_tree_store_append (GTK_TREE_STORE (model), &iter[1], NULL);
+  gtk_tree_store_append (GTK_TREE_STORE (model), &iter[2], NULL);
+  gtk_tree_store_append (GTK_TREE_STORE (model), &iter[3], NULL);
+  gtk_tree_store_append (GTK_TREE_STORE (model), &iter[4], NULL);
+
+  assert_root_level_unreferenced (ref_model);
+
+  filter_model = gtk_tree_model_filter_new (model, NULL);
+  tree_view = gtk_tree_view_new_with_model (filter_model);
+
+  assert_node_ref_count (ref_model, &iter[0], 2);
+  assert_node_ref_count (ref_model, &iter[1], 1);
+  assert_node_ref_count (ref_model, &iter[2], 1);
+  assert_node_ref_count (ref_model, &iter[3], 1);
+  assert_node_ref_count (ref_model, &iter[4], 1);
+
+  gtk_widget_destroy (tree_view);
+
+  assert_node_ref_count (ref_model, &iter[0], 1);
+  assert_node_ref_count (ref_model, &iter[1], 0);
+  assert_node_ref_count (ref_model, &iter[2], 0);
+  assert_node_ref_count (ref_model, &iter[3], 0);
+  assert_node_ref_count (ref_model, &iter[4], 0);
+
+  g_object_unref (filter_model);
+
+  assert_node_ref_count (ref_model, &iter[0], 0);
+
+  g_object_unref (ref_model);
+}
+
+static void
+ref_count_two_levels (void)
+{
+  GtkTreeIter parent1, parent2, iter, iter_first;
+  GtkTreeModel *model;
+  GtkTreeModelRefCount *ref_model;
+  GtkTreeModel *filter_model;
+  GtkWidget *tree_view;
+
+  model = gtk_tree_model_ref_count_new ();
+  ref_model = GTK_TREE_MODEL_REF_COUNT (model);
+
+  gtk_tree_store_append (GTK_TREE_STORE (model), &parent1, NULL);
+  gtk_tree_store_append (GTK_TREE_STORE (model), &parent2, NULL);
+  gtk_tree_store_append (GTK_TREE_STORE (model), &iter_first, &parent2);
+  gtk_tree_store_append (GTK_TREE_STORE (model), &iter, &parent2);
+  gtk_tree_store_append (GTK_TREE_STORE (model), &iter, &parent2);
+
+  assert_entire_model_unreferenced (ref_model);
+
+  filter_model = gtk_tree_model_filter_new (model, NULL);
+  tree_view = gtk_tree_view_new_with_model (filter_model);
+
+  /* This is quite confusing:
+   *  - node 0 has a ref count of 2 because it is referenced as the
+   *    first node in a level and by the tree view.
+   *  - node 1 has a ref count of 2 because it is referenced by its
+   *    child level and by the tree view.
+   */
+  assert_root_level_referenced (ref_model, 2);
+  assert_node_ref_count (ref_model, &iter_first, 1);
+  assert_node_ref_count (ref_model, &iter, 0);
+
+  gtk_tree_view_expand_all (GTK_TREE_VIEW (tree_view));
+
+  assert_node_ref_count (ref_model, &parent1, 2);
+  assert_node_ref_count (ref_model, &parent2, 2);
+  assert_node_ref_count (ref_model, &iter_first, 2);
+  assert_node_ref_count (ref_model, &iter, 1);
+
+  gtk_tree_view_collapse_all (GTK_TREE_VIEW (tree_view));
+
+  /* The child level is not destroyed because its parent is visible */
+  assert_node_ref_count (ref_model, &parent1, 2);
+  assert_node_ref_count (ref_model, &parent2, 2);
+  assert_node_ref_count (ref_model, &iter_first, 1);
+  assert_node_ref_count (ref_model, &iter, 0);
+
+  gtk_tree_model_filter_clear_cache (GTK_TREE_MODEL_FILTER (filter_model));
+
+  assert_node_ref_count (ref_model, &parent1, 2);
+  assert_node_ref_count (ref_model, &parent2, 2);
+  assert_node_ref_count (ref_model, &iter_first, 1);
+  assert_node_ref_count (ref_model, &iter, 0);
+
+  gtk_widget_destroy (tree_view);
+
+  assert_root_level_referenced (ref_model, 1);
+  assert_node_ref_count (ref_model, &iter_first, 1);
+  assert_node_ref_count (ref_model, &iter, 0);
+
+  gtk_tree_model_filter_clear_cache (GTK_TREE_MODEL_FILTER (filter_model));
+
+  /* The root level and first level remain cached, only the references on the
+   * first nodes of these levels are kept.
+   */
+  assert_node_ref_count (ref_model, &parent1, 1);
+  assert_node_ref_count (ref_model, &parent2, 1);
+  assert_node_ref_count (ref_model, &iter_first, 1);
+  assert_node_ref_count (ref_model, &iter, 0);
+
+  g_object_unref (filter_model);
+  g_object_unref (ref_model);
+}
+
+static void
+ref_count_three_levels (void)
+{
+  GtkTreeIter grandparent1, grandparent2, parent1, parent2;
+  GtkTreeIter iter_parent1, iter_parent2, iter_parent2_first;
+  GtkTreeModel *model;
+  GtkTreeModelRefCount *ref_model;
+  GtkTreeModel *filter_model;
+  GtkTreePath *path;
+  GtkWidget *tree_view;
+
+  model = gtk_tree_model_ref_count_new ();
+  ref_model = GTK_TREE_MODEL_REF_COUNT (model);
+
+  /* + grandparent1
+   * + grandparent2
+   *   + parent1
+   *     + iter_parent1
+   *   + parent2
+   *     + iter_parent2_first
+   *     + iter_parent2
+   */
+
+  gtk_tree_store_append (GTK_TREE_STORE (model), &grandparent1, NULL);
+  gtk_tree_store_append (GTK_TREE_STORE (model), &grandparent2, NULL);
+  gtk_tree_store_append (GTK_TREE_STORE (model), &parent1, &grandparent2);
+  gtk_tree_store_append (GTK_TREE_STORE (model), &iter_parent1, &parent1);
+  gtk_tree_store_append (GTK_TREE_STORE (model), &parent2, &grandparent2);
+  gtk_tree_store_append (GTK_TREE_STORE (model), &iter_parent2_first, &parent2);
+  gtk_tree_store_append (GTK_TREE_STORE (model), &iter_parent2, &parent2);
+
+  assert_entire_model_unreferenced (ref_model);
+
+  filter_model = gtk_tree_model_filter_new (model, NULL);
+  tree_view = gtk_tree_view_new_with_model (filter_model);
+
+  /* This is quite confusing:
+   *  - node 0 has a ref count of 2 because it is referenced as the
+   *    first node in a level and by the tree view.
+   *  - node 1 has a ref count of 2 because it is referenced by its
+   *    child level and by the tree view.
+   */
+  assert_root_level_referenced (ref_model, 2);
+  assert_node_ref_count (ref_model, &parent1, 1);
+  assert_node_ref_count (ref_model, &parent2, 0);
+  assert_level_unreferenced (ref_model, &parent1);
+  assert_level_unreferenced (ref_model, &parent2);
+
+  path = gtk_tree_path_new_from_indices (1, -1);
+  gtk_tree_view_expand_row (GTK_TREE_VIEW (tree_view), path, FALSE);
+
+  assert_node_ref_count (ref_model, &grandparent1, 2);
+  assert_node_ref_count (ref_model, &grandparent2, 2);
+  assert_node_ref_count (ref_model, &parent1, 3);
+  assert_node_ref_count (ref_model, &parent2, 2);
+  assert_node_ref_count (ref_model, &iter_parent1, 1);
+  assert_node_ref_count (ref_model, &iter_parent2_first, 1);
+  assert_node_ref_count (ref_model, &iter_parent2, 0);
+
+  gtk_tree_view_expand_row (GTK_TREE_VIEW (tree_view), path, TRUE);
+
+  assert_node_ref_count (ref_model, &grandparent1, 2);
+  assert_node_ref_count (ref_model, &grandparent2, 2);
+  assert_node_ref_count (ref_model, &parent1, 3);
+  assert_node_ref_count (ref_model, &parent2, 2);
+  assert_node_ref_count (ref_model, &iter_parent1, 2);
+  assert_node_ref_count (ref_model, &iter_parent2_first, 2);
+  assert_node_ref_count (ref_model, &iter_parent2, 1);
+
+  gtk_tree_view_collapse_all (GTK_TREE_VIEW (tree_view));
+
+  assert_node_ref_count (ref_model, &grandparent1, 2);
+  assert_node_ref_count (ref_model, &grandparent2, 2);
+  assert_node_ref_count (ref_model, &parent1, 2);
+  assert_node_ref_count (ref_model, &parent2, 1);
+  assert_node_ref_count (ref_model, &iter_parent1, 1);
+  assert_node_ref_count (ref_model, &iter_parent2_first, 1);
+  assert_node_ref_count (ref_model, &iter_parent2, 0);
+
+  gtk_tree_model_filter_clear_cache (GTK_TREE_MODEL_FILTER (filter_model));
+
+  assert_node_ref_count (ref_model, &grandparent1, 2);
+  assert_node_ref_count (ref_model, &grandparent2, 2);
+  assert_node_ref_count (ref_model, &parent1, 1);
+  assert_node_ref_count (ref_model, &parent2, 0);
+  assert_node_ref_count (ref_model, &iter_parent1, 0);
+  assert_node_ref_count (ref_model, &iter_parent2_first, 0);
+  assert_node_ref_count (ref_model, &iter_parent2, 0);
+
+  gtk_tree_view_expand_row (GTK_TREE_VIEW (tree_view), path, FALSE);
+
+  assert_node_ref_count (ref_model, &grandparent1, 2);
+  assert_node_ref_count (ref_model, &grandparent2, 2);
+  assert_node_ref_count (ref_model, &parent1, 3);
+  assert_node_ref_count (ref_model, &parent2, 2);
+  assert_node_ref_count (ref_model, &iter_parent1, 1);
+  assert_node_ref_count (ref_model, &iter_parent2_first, 1);
+  assert_node_ref_count (ref_model, &iter_parent2, 0);
+
+  gtk_tree_path_append_index (path, 1);
+  gtk_tree_view_expand_row (GTK_TREE_VIEW (tree_view), path, FALSE);
+
+  assert_node_ref_count (ref_model, &grandparent1, 2);
+  assert_node_ref_count (ref_model, &grandparent2, 2);
+  assert_node_ref_count (ref_model, &parent1, 3);
+  assert_node_ref_count (ref_model, &parent2, 2);
+  assert_node_ref_count (ref_model, &iter_parent1, 1);
+  assert_node_ref_count (ref_model, &iter_parent2_first, 2);
+  assert_node_ref_count (ref_model, &iter_parent2, 1);
+
+  gtk_tree_view_collapse_row (GTK_TREE_VIEW (tree_view), path);
+
+  assert_node_ref_count (ref_model, &grandparent1, 2);
+  assert_node_ref_count (ref_model, &grandparent2, 2);
+  assert_node_ref_count (ref_model, &parent1, 3);
+  assert_node_ref_count (ref_model, &parent2, 2);
+  assert_node_ref_count (ref_model, &iter_parent1, 1);
+  assert_node_ref_count (ref_model, &iter_parent2_first, 1);
+  assert_node_ref_count (ref_model, &iter_parent2, 0);
+
+  gtk_tree_model_filter_clear_cache (GTK_TREE_MODEL_FILTER (filter_model));
+
+  assert_node_ref_count (ref_model, &grandparent1, 2);
+  assert_node_ref_count (ref_model, &grandparent2, 2);
+  assert_node_ref_count (ref_model, &parent1, 3);
+  assert_node_ref_count (ref_model, &parent2, 2);
+  assert_node_ref_count (ref_model, &iter_parent1, 1);
+  assert_node_ref_count (ref_model, &iter_parent2_first, 1);
+  assert_node_ref_count (ref_model, &iter_parent2, 0);
+
+  gtk_tree_path_up (path);
+  gtk_tree_view_collapse_row (GTK_TREE_VIEW (tree_view), path);
+  gtk_tree_path_free (path);
+
+  assert_node_ref_count (ref_model, &grandparent1, 2);
+  assert_node_ref_count (ref_model, &grandparent2, 2);
+  assert_node_ref_count (ref_model, &parent1, 2);
+  assert_node_ref_count (ref_model, &parent2, 1);
+  assert_node_ref_count (ref_model, &iter_parent1, 1);
+  assert_node_ref_count (ref_model, &iter_parent2_first, 1);
+  assert_node_ref_count (ref_model, &iter_parent2, 0);
+
+  gtk_tree_model_filter_clear_cache (GTK_TREE_MODEL_FILTER (filter_model));
+
+  assert_node_ref_count (ref_model, &grandparent1, 2);
+  assert_node_ref_count (ref_model, &grandparent2, 2);
+  assert_node_ref_count (ref_model, &parent1, 1);
+  assert_node_ref_count (ref_model, &parent2, 0);
+  assert_node_ref_count (ref_model, &iter_parent1, 0);
+  assert_node_ref_count (ref_model, &iter_parent2_first, 0);
+  assert_node_ref_count (ref_model, &iter_parent2, 0);
+
+  gtk_widget_destroy (tree_view);
+
+  gtk_tree_model_filter_clear_cache (GTK_TREE_MODEL_FILTER (filter_model));
+
+  /* The root level and first level remain cached, only the references on the
+   * first nodes of these levels are kept.  Grandparent2 is the parent
+   * of the first level with parent1, so grandparent2 keeps a reference
+   * as well.
+   */
+  assert_node_ref_count (ref_model, &grandparent1, 1);
+  assert_node_ref_count (ref_model, &grandparent2, 1);
+  assert_node_ref_count (ref_model, &parent1, 1);
+  assert_node_ref_count (ref_model, &parent2, 0);
+  assert_node_ref_count (ref_model, &iter_parent1, 0);
+  assert_node_ref_count (ref_model, &iter_parent2_first, 0);
+  assert_node_ref_count (ref_model, &iter_parent2, 0);
+
+  g_object_unref (filter_model);
+  g_object_unref (ref_model);
+}
+
+static void
+ref_count_delete_row (void)
+{
+  GtkTreeIter grandparent1, grandparent2, parent1, parent2;
+  GtkTreeIter iter_parent1, iter_parent2, iter_parent2_first;
+  GtkTreeModel *model;
+  GtkTreeModelRefCount *ref_model;
+  GtkTreeModel *filter_model;
+  GtkTreePath *path;
+  GtkWidget *tree_view;
+
+  model = gtk_tree_model_ref_count_new ();
+  ref_model = GTK_TREE_MODEL_REF_COUNT (model);
+
+  /* + grandparent1
+   * + grandparent2
+   *   + parent1
+   *     + iter_parent1
+   *   + parent2
+   *     + iter_parent2_first
+   *     + iter_parent2
+   */
+
+  gtk_tree_store_append (GTK_TREE_STORE (model), &grandparent1, NULL);
+  gtk_tree_store_append (GTK_TREE_STORE (model), &grandparent2, NULL);
+  gtk_tree_store_append (GTK_TREE_STORE (model), &parent1, &grandparent2);
+  gtk_tree_store_append (GTK_TREE_STORE (model), &iter_parent1, &parent1);
+  gtk_tree_store_append (GTK_TREE_STORE (model), &parent2, &grandparent2);
+  gtk_tree_store_append (GTK_TREE_STORE (model), &iter_parent2_first, &parent2);
+  gtk_tree_store_append (GTK_TREE_STORE (model), &iter_parent2, &parent2);
+
+  assert_entire_model_unreferenced (ref_model);
+
+  filter_model = gtk_tree_model_filter_new (model, NULL);
+  tree_view = gtk_tree_view_new_with_model (filter_model);
+
+  assert_root_level_referenced (ref_model, 2);
+  assert_node_ref_count (ref_model, &parent1, 1);
+  assert_node_ref_count (ref_model, &parent2, 0);
+  assert_level_unreferenced (ref_model, &parent1);
+  assert_level_unreferenced (ref_model, &parent2);
+
+  path = gtk_tree_path_new_from_indices (1, -1);
+  gtk_tree_view_expand_row (GTK_TREE_VIEW (tree_view), path, TRUE);
+  gtk_tree_path_free (path);
+
+  assert_node_ref_count (ref_model, &grandparent1, 2);
+  assert_node_ref_count (ref_model, &grandparent2, 2);
+  assert_node_ref_count (ref_model, &parent1, 3);
+  assert_node_ref_count (ref_model, &parent2, 2);
+  assert_node_ref_count (ref_model, &iter_parent1, 2);
+  assert_node_ref_count (ref_model, &iter_parent2_first, 2);
+  assert_node_ref_count (ref_model, &iter_parent2, 1);
+
+  gtk_tree_store_remove (GTK_TREE_STORE (model), &iter_parent2);
+
+  assert_node_ref_count (ref_model, &grandparent1, 2);
+  assert_node_ref_count (ref_model, &grandparent2, 2);
+  assert_node_ref_count (ref_model, &parent1, 3);
+  assert_node_ref_count (ref_model, &parent2, 2);
+  assert_node_ref_count (ref_model, &iter_parent1, 2);
+  assert_node_ref_count (ref_model, &iter_parent2_first, 2);
+
+  gtk_tree_store_remove (GTK_TREE_STORE (model), &parent1);
+
+  assert_node_ref_count (ref_model, &grandparent1, 2);
+  assert_node_ref_count (ref_model, &grandparent2, 2);
+  assert_node_ref_count (ref_model, &parent2, 3);
+  assert_level_referenced (ref_model, 2, &parent2);
+
+  gtk_tree_store_remove (GTK_TREE_STORE (model), &grandparent2);
+
+  assert_node_ref_count (ref_model, &grandparent1, 2);
+
+  gtk_tree_model_filter_clear_cache (GTK_TREE_MODEL_FILTER (filter_model));
+
+  assert_node_ref_count (ref_model, &grandparent1, 2);
+
+  gtk_widget_destroy (tree_view);
+  gtk_tree_model_filter_clear_cache (GTK_TREE_MODEL_FILTER (filter_model));
+
+  assert_node_ref_count (ref_model, &grandparent1, 1);
+
+  g_object_unref (filter_model);
+
+  assert_node_ref_count (ref_model, &grandparent1, 0);
+
+  g_object_unref (ref_model);
+}
+
+static void
+ref_count_filter_row_length_1 (void)
+{
+  GtkTreeIter level1_1;
+  GtkTreeIter level2_1;
+  GtkTreeIter level3_1;
+  GtkTreeIter level4_1;
+  GtkTreeModel *model;
+  GtkTreeModelRefCount *ref_model;
+  GtkTreeModel *filter_model;
+  GtkTreePath *path;
+  GtkWidget *tree_view;
+  GType column_types[] = { G_TYPE_BOOLEAN };
+
+  model = gtk_tree_model_ref_count_new ();
+  ref_model = GTK_TREE_MODEL_REF_COUNT (model);
+
+  gtk_tree_store_set_column_types (GTK_TREE_STORE (model), 1,
+                                   column_types);
+
+
+  /* + level1_1
+   *   + level2_1
+   *     + level3_1
+   *       + level4_1
+   *
+   * Node level1_1 is expanded.  This makes that levels 1 and 2 are
+   * visible.  Level 3 is cached because its parent is visible.  Level 4
+   * is not cached.
+   */
+
+  gtk_tree_store_append (GTK_TREE_STORE (model), &level1_1, NULL);
+  gtk_tree_store_append (GTK_TREE_STORE (model), &level2_1, &level1_1);
+  gtk_tree_store_append (GTK_TREE_STORE (model), &level3_1, &level2_1);
+  gtk_tree_store_append (GTK_TREE_STORE (model), &level4_1, &level3_1);
+
+  gtk_tree_store_set (GTK_TREE_STORE (model), &level1_1, 0, TRUE, -1);
+  gtk_tree_store_set (GTK_TREE_STORE (model), &level2_1, 0, TRUE, -1);
+  gtk_tree_store_set (GTK_TREE_STORE (model), &level3_1, 0, TRUE, -1);
+  gtk_tree_store_set (GTK_TREE_STORE (model), &level4_1, 0, TRUE, -1);
+
+  assert_entire_model_unreferenced (ref_model);
+
+  filter_model = gtk_tree_model_filter_new (model, NULL);
+  gtk_tree_model_filter_set_visible_column (GTK_TREE_MODEL_FILTER (filter_model), 0);
+  tree_view = gtk_tree_view_new_with_model (filter_model);
+
+  assert_node_ref_count (ref_model, &level1_1, 3);
+  assert_node_ref_count (ref_model, &level2_1, 1);
+  assert_node_ref_count (ref_model, &level3_1, 0);
+  assert_node_ref_count (ref_model, &level4_1, 0);
+
+  path = gtk_tree_path_new_from_indices (0, -1);
+  gtk_tree_view_expand_row (GTK_TREE_VIEW (tree_view), path, FALSE);
+  gtk_tree_path_free (path);
+
+  assert_node_ref_count (ref_model, &level1_1, 3);
+  assert_node_ref_count (ref_model, &level2_1, 3);
+  assert_node_ref_count (ref_model, &level3_1, 1);
+  assert_node_ref_count (ref_model, &level4_1, 0);
+
+  gtk_tree_store_set (GTK_TREE_STORE (model), &level4_1, 0, FALSE, -1);
+
+  assert_node_ref_count (ref_model, &level1_1, 3);
+  assert_node_ref_count (ref_model, &level2_1, 3);
+  assert_node_ref_count (ref_model, &level3_1, 1);
+  assert_node_ref_count (ref_model, &level4_1, 0);
+
+  /* level3_1 has a visible parent, so the node is kept in the cache. */
+  gtk_tree_store_set (GTK_TREE_STORE (model), &level3_1, 0, FALSE, -1);
+
+  assert_node_ref_count (ref_model, &level1_1, 3);
+  assert_node_ref_count (ref_model, &level2_1, 3);
+  assert_node_ref_count (ref_model, &level3_1, 1);
+  assert_node_ref_count (ref_model, &level4_1, 0);
+
+  /* level2_1 has a visible parent, so is kept in the cache.  However,
+   * the external reference should be released.
+   */
+  gtk_tree_store_set (GTK_TREE_STORE (model), &level2_1, 0, FALSE, -1);
+
+  assert_node_ref_count (ref_model, &level1_1, 3);
+  assert_node_ref_count (ref_model, &level2_1, 1);
+  assert_node_ref_count (ref_model, &level3_1, 0);
+  assert_node_ref_count (ref_model, &level4_1, 0);
+
+  gtk_tree_store_set (GTK_TREE_STORE (model), &level1_1, 0, FALSE, -1);
+
+  assert_node_ref_count (ref_model, &level1_1, 2);
+  assert_node_ref_count (ref_model, &level2_1, 1);
+  assert_node_ref_count (ref_model, &level3_1, 0);
+  assert_node_ref_count (ref_model, &level4_1, 0);
+
+  gtk_widget_destroy (tree_view);
+  gtk_tree_model_filter_clear_cache (GTK_TREE_MODEL_FILTER (filter_model));
+
+  assert_node_ref_count (ref_model, &level1_1, 2);
+  assert_node_ref_count (ref_model, &level2_1, 1);
+
+  g_object_unref (filter_model);
+
+  assert_node_ref_count (ref_model, &level1_1, 0);
+
+  g_object_unref (ref_model);
+}
+
+static void
+ref_count_filter_row_length_1_remove_in_root_level (void)
+{
+  GtkTreeIter level1_1;
+  GtkTreeIter level2_1;
+  GtkTreeIter level3_1;
+  GtkTreeIter level4_1;
+  GtkTreeModel *model;
+  GtkTreeModelRefCount *ref_model;
+  GtkTreeModel *filter_model;
+  GtkTreePath *path;
+  GtkWidget *tree_view;
+  GType column_types[] = { G_TYPE_BOOLEAN };
+
+  model = gtk_tree_model_ref_count_new ();
+  ref_model = GTK_TREE_MODEL_REF_COUNT (model);
+
+  gtk_tree_store_set_column_types (GTK_TREE_STORE (model), 1,
+                                   column_types);
+
+
+  /* + level1_1
+   *   + level2_1
+   *     + level3_1
+   *       + level4_1
+   */
+
+  gtk_tree_store_append (GTK_TREE_STORE (model), &level1_1, NULL);
+  gtk_tree_store_append (GTK_TREE_STORE (model), &level2_1, &level1_1);
+  gtk_tree_store_append (GTK_TREE_STORE (model), &level3_1, &level2_1);
+  gtk_tree_store_append (GTK_TREE_STORE (model), &level4_1, &level3_1);
+
+  gtk_tree_store_set (GTK_TREE_STORE (model), &level1_1, 0, TRUE, -1);
+  gtk_tree_store_set (GTK_TREE_STORE (model), &level2_1, 0, TRUE, -1);
+  gtk_tree_store_set (GTK_TREE_STORE (model), &level3_1, 0, TRUE, -1);
+  gtk_tree_store_set (GTK_TREE_STORE (model), &level4_1, 0, TRUE, -1);
+
+  assert_entire_model_unreferenced (ref_model);
+
+  filter_model = gtk_tree_model_filter_new (model, NULL);
+  gtk_tree_model_filter_set_visible_column (GTK_TREE_MODEL_FILTER (filter_model), 0);
+  tree_view = gtk_tree_view_new_with_model (filter_model);
+
+  assert_node_ref_count (ref_model, &level1_1, 3);
+  assert_node_ref_count (ref_model, &level2_1, 1);
+  assert_node_ref_count (ref_model, &level3_1, 0);
+  assert_node_ref_count (ref_model, &level4_1, 0);
+
+  path = gtk_tree_path_new_from_indices (0, -1);
+  gtk_tree_view_expand_row (GTK_TREE_VIEW (tree_view), path, TRUE);
+  gtk_tree_path_free (path);
+
+  assert_node_ref_count (ref_model, &level1_1, 3);
+  assert_node_ref_count (ref_model, &level2_1, 3);
+  assert_node_ref_count (ref_model, &level3_1, 3);
+  assert_node_ref_count (ref_model, &level4_1, 2);
+
+  gtk_tree_store_set (GTK_TREE_STORE (model), &level1_1, 0, FALSE, -1);
+
+  assert_node_ref_count (ref_model, &level1_1, 2);
+  assert_node_ref_count (ref_model, &level2_1, 1);
+  assert_node_ref_count (ref_model, &level3_1, 0);
+  assert_node_ref_count (ref_model, &level4_1, 0);
+
+  gtk_widget_destroy (tree_view);
+  gtk_tree_model_filter_clear_cache (GTK_TREE_MODEL_FILTER (filter_model));
+
+  assert_node_ref_count (ref_model, &level1_1, 2);
+  assert_node_ref_count (ref_model, &level2_1, 1);
+  assert_node_ref_count (ref_model, &level3_1, 0);
+  assert_node_ref_count (ref_model, &level4_1, 0);
+
+  g_object_unref (filter_model);
+
+  assert_node_ref_count (ref_model, &level1_1, 0);
+  assert_node_ref_count (ref_model, &level2_1, 0);
+  assert_node_ref_count (ref_model, &level3_1, 0);
+  assert_node_ref_count (ref_model, &level4_1, 0);
+
+  g_object_unref (ref_model);
+}
+
+static void
+ref_count_filter_row_length_1_remove_in_child_level (void)
+{
+  GtkTreeIter level1_1;
+  GtkTreeIter level2_1;
+  GtkTreeIter level3_1;
+  GtkTreeIter level4_1;
+  GtkTreeModel *model;
+  GtkTreeModelRefCount *ref_model;
+  GtkTreeModel *filter_model;
+  GtkTreePath *path;
+  GtkWidget *tree_view;
+  GType column_types[] = { G_TYPE_BOOLEAN };
+
+  model = gtk_tree_model_ref_count_new ();
+  ref_model = GTK_TREE_MODEL_REF_COUNT (model);
+
+  gtk_tree_store_set_column_types (GTK_TREE_STORE (model), 1,
+                                   column_types);
+
+
+  /* + level1_1
+   *   + level2_1
+   *     + level3_1
+   *       + level4_1
+   */
+
+  gtk_tree_store_append (GTK_TREE_STORE (model), &level1_1, NULL);
+  gtk_tree_store_append (GTK_TREE_STORE (model), &level2_1, &level1_1);
+  gtk_tree_store_append (GTK_TREE_STORE (model), &level3_1, &level2_1);
+  gtk_tree_store_append (GTK_TREE_STORE (model), &level4_1, &level3_1);
+
+  gtk_tree_store_set (GTK_TREE_STORE (model), &level1_1, 0, TRUE, -1);
+  gtk_tree_store_set (GTK_TREE_STORE (model), &level2_1, 0, TRUE, -1);
+  gtk_tree_store_set (GTK_TREE_STORE (model), &level3_1, 0, TRUE, -1);
+  gtk_tree_store_set (GTK_TREE_STORE (model), &level4_1, 0, TRUE, -1);
+
+  assert_entire_model_unreferenced (ref_model);
+
+  filter_model = gtk_tree_model_filter_new (model, NULL);
+  gtk_tree_model_filter_set_visible_column (GTK_TREE_MODEL_FILTER (filter_model), 0);
+  tree_view = gtk_tree_view_new_with_model (filter_model);
+
+  assert_node_ref_count (ref_model, &level1_1, 3);
+  assert_node_ref_count (ref_model, &level2_1, 1);
+  assert_node_ref_count (ref_model, &level3_1, 0);
+  assert_node_ref_count (ref_model, &level4_1, 0);
+
+  path = gtk_tree_path_new_from_indices (0, -1);
+  gtk_tree_view_expand_row (GTK_TREE_VIEW (tree_view), path, TRUE);
+  gtk_tree_path_free (path);
+
+  assert_node_ref_count (ref_model, &level1_1, 3);
+  assert_node_ref_count (ref_model, &level2_1, 3);
+  assert_node_ref_count (ref_model, &level3_1, 3);
+  assert_node_ref_count (ref_model, &level4_1, 2);
+
+  gtk_tree_store_set (GTK_TREE_STORE (model), &level2_1, 0, FALSE, -1);
+
+  assert_node_ref_count (ref_model, &level1_1, 3);
+  assert_node_ref_count (ref_model, &level2_1, 1);
+  assert_node_ref_count (ref_model, &level3_1, 0);
+  assert_node_ref_count (ref_model, &level4_1, 0);
+
+  gtk_widget_destroy (tree_view);
+  gtk_tree_model_filter_clear_cache (GTK_TREE_MODEL_FILTER (filter_model));
+
+  assert_node_ref_count (ref_model, &level1_1, 2);
+  assert_node_ref_count (ref_model, &level2_1, 1);
+  assert_node_ref_count (ref_model, &level3_1, 0);
+  assert_node_ref_count (ref_model, &level4_1, 0);
+
+  g_object_unref (filter_model);
+
+  assert_node_ref_count (ref_model, &level1_1, 0);
+  assert_node_ref_count (ref_model, &level2_1, 0);
+  assert_node_ref_count (ref_model, &level3_1, 0);
+  assert_node_ref_count (ref_model, &level4_1, 0);
+
+  g_object_unref (ref_model);
+}
+
+static void
+ref_count_filter_row_length_gt_1 (void)
+{
+  GtkTreeIter level1_1, level1_2;
+  GtkTreeIter level2_1, level2_2;
+  GtkTreeIter level3_1, level3_2;
+  GtkTreeIter level4_1, level4_2;
+  GtkTreeModel *model;
+  GtkTreeModelRefCount *ref_model;
+  GtkTreeModel *filter_model;
+  GtkTreePath *path;
+  GtkWidget *tree_view;
+  GType column_types[] = { G_TYPE_BOOLEAN };
+
+  model = gtk_tree_model_ref_count_new ();
+  ref_model = GTK_TREE_MODEL_REF_COUNT (model);
+
+  gtk_tree_store_set_column_types (GTK_TREE_STORE (model), 1,
+                                   column_types);
+
+
+  /* + level1_1
+   * + level1_2
+   *   + level2_1
+   *   + level2_2
+   *     + level3_1
+   *     + level3_2
+   *       + level4_1
+   *       + level4_2
+   *
+   * Node level1_2 is expanded.  This makes that levels 1 and 2 are
+   * visible.  Level 3 is cached because its parent is visible.  Level 4
+   * is not cached.
+   */
+
+  gtk_tree_store_append (GTK_TREE_STORE (model), &level1_1, NULL);
+  gtk_tree_store_append (GTK_TREE_STORE (model), &level1_2, NULL);
+  gtk_tree_store_append (GTK_TREE_STORE (model), &level2_1, &level1_2);
+  gtk_tree_store_append (GTK_TREE_STORE (model), &level2_2, &level1_2);
+  gtk_tree_store_append (GTK_TREE_STORE (model), &level3_1, &level2_2);
+  gtk_tree_store_append (GTK_TREE_STORE (model), &level3_2, &level2_2);
+  gtk_tree_store_append (GTK_TREE_STORE (model), &level4_1, &level3_2);
+  gtk_tree_store_append (GTK_TREE_STORE (model), &level4_2, &level3_2);
+
+  gtk_tree_store_set (GTK_TREE_STORE (model), &level1_1, 0, TRUE, -1);
+  gtk_tree_store_set (GTK_TREE_STORE (model), &level1_2, 0, TRUE, -1);
+  gtk_tree_store_set (GTK_TREE_STORE (model), &level2_1, 0, TRUE, -1);
+  gtk_tree_store_set (GTK_TREE_STORE (model), &level2_2, 0, TRUE, -1);
+  gtk_tree_store_set (GTK_TREE_STORE (model), &level3_1, 0, TRUE, -1);
+  gtk_tree_store_set (GTK_TREE_STORE (model), &level3_2, 0, TRUE, -1);
+  gtk_tree_store_set (GTK_TREE_STORE (model), &level4_1, 0, TRUE, -1);
+  gtk_tree_store_set (GTK_TREE_STORE (model), &level4_2, 0, TRUE, -1);
+
+  assert_entire_model_unreferenced (ref_model);
+
+  filter_model = gtk_tree_model_filter_new (model, NULL);
+  gtk_tree_model_filter_set_visible_column (GTK_TREE_MODEL_FILTER (filter_model), 0);
+  tree_view = gtk_tree_view_new_with_model (filter_model);
+
+  assert_node_ref_count (ref_model, &level1_1, 2);
+  assert_node_ref_count (ref_model, &level1_2, 2);
+  assert_node_ref_count (ref_model, &level2_1, 1);
+  assert_node_ref_count (ref_model, &level2_2, 0);
+  assert_node_ref_count (ref_model, &level3_1, 0);
+  assert_node_ref_count (ref_model, &level3_2, 0);
+  assert_node_ref_count (ref_model, &level4_1, 0);
+  assert_node_ref_count (ref_model, &level4_2, 0);
+
+  path = gtk_tree_path_new_from_indices (1, -1);
+  gtk_tree_view_expand_row (GTK_TREE_VIEW (tree_view), path, FALSE);
+  gtk_tree_path_free (path);
+
+  assert_node_ref_count (ref_model, &level1_1, 2);
+  assert_node_ref_count (ref_model, &level1_2, 2);
+  assert_node_ref_count (ref_model, &level2_1, 2);
+  assert_node_ref_count (ref_model, &level2_2, 2);
+  assert_node_ref_count (ref_model, &level3_1, 1);
+  assert_node_ref_count (ref_model, &level3_2, 0);
+  assert_node_ref_count (ref_model, &level4_1, 0);
+  assert_node_ref_count (ref_model, &level4_2, 0);
+
+  gtk_tree_store_set (GTK_TREE_STORE (model), &level4_1, 0, FALSE, -1);
+
+  assert_node_ref_count (ref_model, &level1_1, 2);
+  assert_node_ref_count (ref_model, &level1_2, 2);
+  assert_node_ref_count (ref_model, &level2_1, 2);
+  assert_node_ref_count (ref_model, &level2_2, 2);
+  assert_node_ref_count (ref_model, &level3_1, 1);
+  assert_node_ref_count (ref_model, &level3_2, 0);
+  assert_node_ref_count (ref_model, &level4_1, 0);
+  assert_node_ref_count (ref_model, &level4_2, 0);
+
+  gtk_tree_store_set (GTK_TREE_STORE (model), &level3_1, 0, FALSE, -1);
+
+  assert_node_ref_count (ref_model, &level1_1, 2);
+  assert_node_ref_count (ref_model, &level1_2, 2);
+  assert_node_ref_count (ref_model, &level2_1, 2);
+  assert_node_ref_count (ref_model, &level2_2, 2);
+  assert_node_ref_count (ref_model, &level3_1, 0);
+  assert_node_ref_count (ref_model, &level3_2, 1);
+  assert_node_ref_count (ref_model, &level4_1, 0);
+  assert_node_ref_count (ref_model, &level4_2, 0);
+
+  gtk_tree_store_set (GTK_TREE_STORE (model), &level2_2, 0, FALSE, -1);
+
+  assert_node_ref_count (ref_model, &level1_1, 2);
+  assert_node_ref_count (ref_model, &level1_2, 2);
+  assert_node_ref_count (ref_model, &level2_1, 2);
+  assert_node_ref_count (ref_model, &level2_2, 0);
+  assert_node_ref_count (ref_model, &level3_1, 0);
+  assert_node_ref_count (ref_model, &level3_2, 0);
+  assert_node_ref_count (ref_model, &level4_1, 0);
+  assert_node_ref_count (ref_model, &level4_2, 0);
+
+  gtk_tree_store_set (GTK_TREE_STORE (model), &level1_2, 0, FALSE, -1);
+
+  assert_node_ref_count (ref_model, &level1_1, 2);
+  assert_node_ref_count (ref_model, &level1_2, 0);
+  assert_node_ref_count (ref_model, &level2_1, 0);
+  assert_node_ref_count (ref_model, &level2_2, 0);
+  assert_node_ref_count (ref_model, &level3_1, 0);
+  assert_node_ref_count (ref_model, &level3_2, 0);
+  assert_node_ref_count (ref_model, &level4_1, 0);
+  assert_node_ref_count (ref_model, &level4_2, 0);
+
+  gtk_widget_destroy (tree_view);
+  gtk_tree_model_filter_clear_cache (GTK_TREE_MODEL_FILTER (filter_model));
+
+  assert_node_ref_count (ref_model, &level1_1, 1);
+
+  g_object_unref (filter_model);
+
+  assert_node_ref_count (ref_model, &level1_1, 0);
+
+  g_object_unref (ref_model);
+}
+
+static void
+ref_count_filter_row_length_gt_1_visible_children (void)
+{
+  GtkTreeIter level1_1, level1_2;
+  GtkTreeIter level2_1, level2_2;
+  GtkTreeIter level3_1, level3_2;
+  GtkTreeIter level4_1, level4_2;
+  GtkTreeModel *model;
+  GtkTreeModelRefCount *ref_model;
+  GtkTreeModel *filter_model;
+  GtkTreePath *path;
+  GtkWidget *tree_view;
+  GType column_types[] = { G_TYPE_BOOLEAN };
+
+  model = gtk_tree_model_ref_count_new ();
+  ref_model = GTK_TREE_MODEL_REF_COUNT (model);
+
+  gtk_tree_store_set_column_types (GTK_TREE_STORE (model), 1,
+                                   column_types);
+
+
+  /* + level1_1
+   * + level1_2
+   *   + level2_1
+   *   + level2_2
+   *     + level3_1
+   *     + level3_2
+   *       + level4_1
+   *       + level4_2
+   */
+
+  gtk_tree_store_append (GTK_TREE_STORE (model), &level1_1, NULL);
+  gtk_tree_store_append (GTK_TREE_STORE (model), &level1_2, NULL);
+  gtk_tree_store_append (GTK_TREE_STORE (model), &level2_1, &level1_2);
+  gtk_tree_store_append (GTK_TREE_STORE (model), &level2_2, &level1_2);
+  gtk_tree_store_append (GTK_TREE_STORE (model), &level3_1, &level2_2);
+  gtk_tree_store_append (GTK_TREE_STORE (model), &level3_2, &level2_2);
+  gtk_tree_store_append (GTK_TREE_STORE (model), &level4_1, &level3_2);
+  gtk_tree_store_append (GTK_TREE_STORE (model), &level4_2, &level3_2);
+
+  gtk_tree_store_set (GTK_TREE_STORE (model), &level1_1, 0, TRUE, -1);
+  gtk_tree_store_set (GTK_TREE_STORE (model), &level1_2, 0, TRUE, -1);
+  gtk_tree_store_set (GTK_TREE_STORE (model), &level2_1, 0, TRUE, -1);
+  gtk_tree_store_set (GTK_TREE_STORE (model), &level2_2, 0, TRUE, -1);
+  gtk_tree_store_set (GTK_TREE_STORE (model), &level3_1, 0, TRUE, -1);
+  gtk_tree_store_set (GTK_TREE_STORE (model), &level3_2, 0, TRUE, -1);
+  gtk_tree_store_set (GTK_TREE_STORE (model), &level4_1, 0, TRUE, -1);
+  gtk_tree_store_set (GTK_TREE_STORE (model), &level4_2, 0, TRUE, -1);
+
+  assert_entire_model_unreferenced (ref_model);
+
+  filter_model = gtk_tree_model_filter_new (model, NULL);
+  gtk_tree_model_filter_set_visible_column (GTK_TREE_MODEL_FILTER (filter_model), 0);
+  tree_view = gtk_tree_view_new_with_model (filter_model);
+
+  assert_node_ref_count (ref_model, &level1_1, 2);
+  assert_node_ref_count (ref_model, &level1_2, 2);
+  assert_node_ref_count (ref_model, &level2_1, 1);
+  assert_node_ref_count (ref_model, &level2_2, 0);
+  assert_node_ref_count (ref_model, &level3_1, 0);
+  assert_node_ref_count (ref_model, &level3_2, 0);
+  assert_node_ref_count (ref_model, &level4_1, 0);
+  assert_node_ref_count (ref_model, &level4_2, 0);
+
+  path = gtk_tree_path_new_from_indices (1, -1);
+  gtk_tree_view_expand_row (GTK_TREE_VIEW (tree_view), path, TRUE);
+  gtk_tree_path_free (path);
+
+  assert_node_ref_count (ref_model, &level1_1, 2);
+  assert_node_ref_count (ref_model, &level1_2, 2);
+  assert_node_ref_count (ref_model, &level2_1, 2);
+  assert_node_ref_count (ref_model, &level2_2, 2);
+  assert_node_ref_count (ref_model, &level3_1, 2);
+  assert_node_ref_count (ref_model, &level3_2, 2);
+  assert_node_ref_count (ref_model, &level4_1, 2);
+  assert_node_ref_count (ref_model, &level4_2, 1);
+
+  gtk_tree_store_set (GTK_TREE_STORE (model), &level2_2, 0, FALSE, -1);
+
+  assert_node_ref_count (ref_model, &level1_1, 2);
+  assert_node_ref_count (ref_model, &level1_2, 2);
+  assert_node_ref_count (ref_model, &level2_1, 2);
+  assert_node_ref_count (ref_model, &level2_2, 0);
+  assert_node_ref_count (ref_model, &level3_1, 0);
+  assert_node_ref_count (ref_model, &level3_2, 0);
+  assert_node_ref_count (ref_model, &level4_1, 0);
+  assert_node_ref_count (ref_model, &level4_2, 0);
+
+  gtk_widget_destroy (tree_view);
+  gtk_tree_model_filter_clear_cache (GTK_TREE_MODEL_FILTER (filter_model));
+
+  assert_node_ref_count (ref_model, &level1_1, 1);
+  assert_node_ref_count (ref_model, &level1_2, 1);
+  assert_node_ref_count (ref_model, &level2_1, 1);
+  assert_node_ref_count (ref_model, &level2_2, 0);
+  assert_node_ref_count (ref_model, &level3_1, 0);
+  assert_node_ref_count (ref_model, &level3_2, 0);
+  assert_node_ref_count (ref_model, &level4_1, 0);
+  assert_node_ref_count (ref_model, &level4_2, 0);
+
+  g_object_unref (filter_model);
+
+  assert_node_ref_count (ref_model, &level1_1, 0);
+  assert_node_ref_count (ref_model, &level1_2, 0);
+  assert_node_ref_count (ref_model, &level2_1, 0);
+  assert_node_ref_count (ref_model, &level2_2, 0);
+  assert_node_ref_count (ref_model, &level3_1, 0);
+  assert_node_ref_count (ref_model, &level3_2, 0);
+  assert_node_ref_count (ref_model, &level4_1, 0);
+  assert_node_ref_count (ref_model, &level4_2, 0);
+
+  g_object_unref (ref_model);
+}
+
+static void
+ref_count_cleanup (void)
+{
+  GtkTreeIter grandparent1, grandparent2, parent1, parent2;
+  GtkTreeIter iter_parent1, iter_parent2, iter_parent2_first;
+  GtkTreeModel *model;
+  GtkTreeModelRefCount *ref_model;
+  GtkTreeModel *filter_model;
+  GtkWidget *tree_view;
+
+  model = gtk_tree_model_ref_count_new ();
+  ref_model = GTK_TREE_MODEL_REF_COUNT (model);
+
+  /* + grandparent1
+   * + grandparent2
+   *   + parent1
+   *     + iter_parent1
+   *   + parent2
+   *     + iter_parent2_first
+   *     + iter_parent2
+   */
+
+  gtk_tree_store_append (GTK_TREE_STORE (model), &grandparent1, NULL);
+  gtk_tree_store_append (GTK_TREE_STORE (model), &grandparent2, NULL);
+  gtk_tree_store_append (GTK_TREE_STORE (model), &parent1, &grandparent2);
+  gtk_tree_store_append (GTK_TREE_STORE (model), &iter_parent1, &parent1);
+  gtk_tree_store_append (GTK_TREE_STORE (model), &parent2, &grandparent2);
+  gtk_tree_store_append (GTK_TREE_STORE (model), &iter_parent2_first, &parent2);
+  gtk_tree_store_append (GTK_TREE_STORE (model), &iter_parent2, &parent2);
+
+  filter_model = gtk_tree_model_filter_new (model, NULL);
+  tree_view = gtk_tree_view_new_with_model (filter_model);
+
+  gtk_tree_view_expand_all (GTK_TREE_VIEW (tree_view));
+
+  assert_node_ref_count (ref_model, &grandparent1, 2);
+  assert_node_ref_count (ref_model, &grandparent2, 2);
+  assert_node_ref_count (ref_model, &parent1, 3);
+  assert_node_ref_count (ref_model, &parent2, 2);
+  assert_node_ref_count (ref_model, &iter_parent1, 2);
+  assert_node_ref_count (ref_model, &iter_parent2_first, 2);
+  assert_node_ref_count (ref_model, &iter_parent2, 1);
+
+  gtk_widget_destroy (tree_view);
+
+  assert_node_ref_count (ref_model, &grandparent1, 1);
+  assert_node_ref_count (ref_model, &grandparent2, 1);
+  assert_node_ref_count (ref_model, &parent1, 2);
+  assert_node_ref_count (ref_model, &parent2, 1);
+  assert_node_ref_count (ref_model, &iter_parent1, 1);
+  assert_node_ref_count (ref_model, &iter_parent2_first, 1);
+  assert_node_ref_count (ref_model, &iter_parent2, 0);
+
+  gtk_tree_model_filter_clear_cache (GTK_TREE_MODEL_FILTER (filter_model));
+
+  /* The root level and first level remain cached, only the references on the
+   * first nodes of these levels are kept.  Grandparent2 is the parent
+   * of the first level with parent1, so grandparent2 keeps a reference
+   * as well.
+   */
+  assert_node_ref_count (ref_model, &grandparent1, 1);
+  assert_node_ref_count (ref_model, &grandparent2, 1);
+  assert_node_ref_count (ref_model, &parent1, 1);
+  assert_node_ref_count (ref_model, &parent2, 0);
+  assert_node_ref_count (ref_model, &iter_parent1, 0);
+  assert_node_ref_count (ref_model, &iter_parent2_first, 0);
+  assert_node_ref_count (ref_model, &iter_parent2, 0);
+
+  g_object_unref (filter_model);
+  g_object_unref (ref_model);
+}
+
+static void
+ref_count_row_ref (void)
+{
+  GtkTreeIter grandparent1, grandparent2, parent1, parent2;
+  GtkTreeIter iter_parent1, iter_parent2, iter_parent2_first;
+  GtkTreeModel *model;
+  GtkTreeModelRefCount *ref_model;
+  GtkTreeModel *filter_model;
+  GtkWidget *tree_view;
+  GtkTreePath *path;
+  GtkTreeRowReference *row_ref;
+
+  model = gtk_tree_model_ref_count_new ();
+  ref_model = GTK_TREE_MODEL_REF_COUNT (model);
+
+  /* + grandparent1
+   * + grandparent2
+   *   + parent1
+   *     + iter_parent1
+   *   + parent2
+   *     + iter_parent2
+   *     + iter_parent2
+   */
+
+  gtk_tree_store_append (GTK_TREE_STORE (model), &grandparent1, NULL);
+  gtk_tree_store_append (GTK_TREE_STORE (model), &grandparent2, NULL);
+  gtk_tree_store_append (GTK_TREE_STORE (model), &parent1, &grandparent2);
+  gtk_tree_store_append (GTK_TREE_STORE (model), &iter_parent1, &parent1);
+  gtk_tree_store_append (GTK_TREE_STORE (model), &parent2, &grandparent2);
+  gtk_tree_store_append (GTK_TREE_STORE (model), &iter_parent2_first, &parent2);
+  gtk_tree_store_append (GTK_TREE_STORE (model), &iter_parent2, &parent2);
+
+  filter_model = gtk_tree_model_filter_new (model, NULL);
+  tree_view = gtk_tree_view_new_with_model (filter_model);
+
+  path = gtk_tree_path_new_from_indices (1, 1, 1, -1);
+  row_ref = gtk_tree_row_reference_new (filter_model, path);
+  gtk_tree_path_free (path);
+
+  assert_node_ref_count (ref_model, &grandparent1, 2);
+  assert_node_ref_count (ref_model, &grandparent2, 3);
+  assert_node_ref_count (ref_model, &parent1, 1);
+  assert_node_ref_count (ref_model, &parent2, 2);
+  assert_node_ref_count (ref_model, &iter_parent1, 0);
+  assert_node_ref_count (ref_model, &iter_parent2_first, 1);
+  assert_node_ref_count (ref_model, &iter_parent2, 1);
+
+  gtk_tree_row_reference_free (row_ref);
+
+  assert_node_ref_count (ref_model, &grandparent1, 2);
+  assert_node_ref_count (ref_model, &grandparent2, 2);
+  assert_node_ref_count (ref_model, &parent1, 1);
+  assert_node_ref_count (ref_model, &parent2, 1);
+  assert_node_ref_count (ref_model, &iter_parent1, 0);
+  assert_node_ref_count (ref_model, &iter_parent2_first, 1);
+  assert_node_ref_count (ref_model, &iter_parent2, 0);
+
+  path = gtk_tree_path_new_from_indices (1, 1, 1, -1);
+  row_ref = gtk_tree_row_reference_new (filter_model, path);
+  gtk_tree_path_free (path);
+
+  assert_node_ref_count (ref_model, &grandparent1, 2);
+  assert_node_ref_count (ref_model, &grandparent2, 3);
+  assert_node_ref_count (ref_model, &parent1, 1);
+  assert_node_ref_count (ref_model, &parent2, 2);
+  assert_node_ref_count (ref_model, &iter_parent1, 0);
+  assert_node_ref_count (ref_model, &iter_parent2_first, 1);
+  assert_node_ref_count (ref_model, &iter_parent2, 1);
+
+  gtk_tree_store_remove (GTK_TREE_STORE (model), &parent2);
+
+  assert_node_ref_count (ref_model, &grandparent1, 2);
+  assert_node_ref_count (ref_model, &grandparent2, 2);
+  assert_node_ref_count (ref_model, &parent1, 1);
+  assert_node_ref_count (ref_model, &iter_parent1, 0);
+
+  gtk_tree_row_reference_free (row_ref);
+
+  assert_node_ref_count (ref_model, &grandparent1, 2);
+  assert_node_ref_count (ref_model, &grandparent2, 2);
+  assert_node_ref_count (ref_model, &parent1, 1);
+  assert_node_ref_count (ref_model, &iter_parent1, 0);
+
+  gtk_widget_destroy (tree_view);
+
+  gtk_tree_model_filter_clear_cache (GTK_TREE_MODEL_FILTER (filter_model));
+
+  /* The root level and first level remain cached, only the references on the
+   * first nodes of these levels are kept.  Grandparent2 is the parent
+   * of the first level with parent1, so grandparent2 keeps a reference
+   * as well.
+   */
+  assert_node_ref_count (ref_model, &grandparent1, 1);
+  assert_node_ref_count (ref_model, &grandparent2, 1);
+  assert_node_ref_count (ref_model, &parent1, 1);
+
+  g_object_unref (filter_model);
+  g_object_unref (ref_model);
+}
+
+static void
+ref_count_transfer_root_level_insert (void)
+{
+  GtkTreeIter grandparent1, grandparent2, grandparent3;
+  GtkTreeIter new_node;
+  GtkTreeModel *model;
+  GtkTreeModelRefCount *ref_model;
+  GtkTreeModel *filter_model;
+  GtkWidget *tree_view;
+
+  model = gtk_tree_model_ref_count_new ();
+  ref_model = GTK_TREE_MODEL_REF_COUNT (model);
+
+  /* + grandparent1
+   * + grandparent2
+   * + grandparent3
+   */
+
+  gtk_tree_store_append (GTK_TREE_STORE (model), &grandparent1, NULL);
+  gtk_tree_store_append (GTK_TREE_STORE (model), &grandparent2, NULL);
+  gtk_tree_store_append (GTK_TREE_STORE (model), &grandparent3, NULL);
+
+  filter_model = gtk_tree_model_filter_new (model, NULL);
+  tree_view = gtk_tree_view_new_with_model (filter_model);
+
+  assert_node_ref_count (ref_model, &grandparent1, 2);
+  assert_node_ref_count (ref_model, &grandparent2, 1);
+  assert_node_ref_count (ref_model, &grandparent3, 1);
+
+  gtk_tree_store_prepend (GTK_TREE_STORE (model), &new_node, NULL);
+
+  assert_node_ref_count (ref_model, &new_node, 2);
+  assert_node_ref_count (ref_model, &grandparent1, 1);
+  assert_node_ref_count (ref_model, &grandparent2, 1);
+  assert_node_ref_count (ref_model, &grandparent3, 1);
+
+  gtk_widget_destroy (tree_view);
+  g_object_unref (filter_model);
+  g_object_unref (ref_model);
+}
+
+static void
+ref_count_transfer_root_level_remove (void)
+{
+  GtkTreeIter grandparent1, grandparent2, grandparent3;
+  GtkTreeModel *model;
+  GtkTreeModelRefCount *ref_model;
+  GtkTreeModel *filter_model;
+  GtkWidget *tree_view;
+
+  model = gtk_tree_model_ref_count_new ();
+  ref_model = GTK_TREE_MODEL_REF_COUNT (model);
+
+  /* + grandparent1
+   * + grandparent2
+   * + grandparent3
+   */
+
+  gtk_tree_store_append (GTK_TREE_STORE (model), &grandparent1, NULL);
+  gtk_tree_store_append (GTK_TREE_STORE (model), &grandparent2, NULL);
+  gtk_tree_store_append (GTK_TREE_STORE (model), &grandparent3, NULL);
+
+  filter_model = gtk_tree_model_filter_new (model, NULL);
+  tree_view = gtk_tree_view_new_with_model (filter_model);
+
+  assert_node_ref_count (ref_model, &grandparent1, 2);
+  assert_node_ref_count (ref_model, &grandparent2, 1);
+  assert_node_ref_count (ref_model, &grandparent3, 1);
+
+  gtk_tree_store_remove (GTK_TREE_STORE (model), &grandparent1);
+
+  assert_node_ref_count (ref_model, &grandparent2, 2);
+  assert_node_ref_count (ref_model, &grandparent3, 1);
+
+  gtk_tree_store_remove (GTK_TREE_STORE (model), &grandparent2);
+
+  assert_node_ref_count (ref_model, &grandparent3, 2);
+
+  gtk_widget_destroy (tree_view);
+  g_object_unref (filter_model);
+  g_object_unref (ref_model);
+}
+
+static void
+ref_count_transfer_root_level_remove_filtered (void)
+{
+  GtkTreeIter grandparent1, grandparent2, grandparent3, grandparent4;
+  GtkTreeModel *model;
+  GtkTreeModelRefCount *ref_model;
+  GtkTreeModel *filter_model;
+  GtkWidget *tree_view;
+  GType column_types[] = { G_TYPE_BOOLEAN };
+
+  model = gtk_tree_model_ref_count_new ();
+  ref_model = GTK_TREE_MODEL_REF_COUNT (model);
+
+  gtk_tree_store_set_column_types (GTK_TREE_STORE (model), 1,
+                                   column_types);
+
+  /* + grandparent1
+   * + grandparent2
+   * + grandparent3
+   * + grandparent4
+   */
+
+  gtk_tree_store_append (GTK_TREE_STORE (model), &grandparent1, NULL);
+  gtk_tree_store_append (GTK_TREE_STORE (model), &grandparent2, NULL);
+  gtk_tree_store_append (GTK_TREE_STORE (model), &grandparent3, NULL);
+  gtk_tree_store_append (GTK_TREE_STORE (model), &grandparent4, NULL);
+
+  /* Filter first node */
+  gtk_tree_store_set (GTK_TREE_STORE (model), &grandparent1, 0, FALSE, -1);
+  gtk_tree_store_set (GTK_TREE_STORE (model), &grandparent2, 0, TRUE, -1);
+  gtk_tree_store_set (GTK_TREE_STORE (model), &grandparent3, 0, TRUE, -1);
+  gtk_tree_store_set (GTK_TREE_STORE (model), &grandparent4, 0, TRUE, -1);
+
+  filter_model = gtk_tree_model_filter_new (model, NULL);
+  gtk_tree_model_filter_set_visible_column (GTK_TREE_MODEL_FILTER (filter_model), 0);
+  tree_view = gtk_tree_view_new_with_model (filter_model);
+
+  assert_node_ref_count (ref_model, &grandparent1, 0);
+  assert_node_ref_count (ref_model, &grandparent2, 2);
+  assert_node_ref_count (ref_model, &grandparent3, 1);
+  assert_node_ref_count (ref_model, &grandparent4, 1);
+
+  gtk_tree_store_remove (GTK_TREE_STORE (model), &grandparent2);
+
+  assert_node_ref_count (ref_model, &grandparent1, 0);
+  assert_node_ref_count (ref_model, &grandparent3, 2);
+  assert_node_ref_count (ref_model, &grandparent4, 1);
+
+  gtk_tree_store_remove (GTK_TREE_STORE (model), &grandparent3);
+
+  assert_node_ref_count (ref_model, &grandparent1, 0);
+  assert_node_ref_count (ref_model, &grandparent4, 2);
+
+  gtk_tree_store_remove (GTK_TREE_STORE (model), &grandparent4);
+
+  /* Check level length to get root level cached again */
+  check_level_length (GTK_TREE_MODEL_FILTER (filter_model), NULL, 0);
+
+  assert_node_ref_count (ref_model, &grandparent1, 1);
+
+  gtk_tree_store_append (GTK_TREE_STORE (model), &grandparent2, NULL);
+
+  assert_node_ref_count (ref_model, &grandparent1, 1);
+  assert_node_ref_count (ref_model, &grandparent2, 0);
+
+  gtk_tree_store_set (GTK_TREE_STORE (model), &grandparent2, 0, TRUE, -1);
+
+  assert_node_ref_count (ref_model, &grandparent1, 1);
+  assert_node_ref_count (ref_model, &grandparent2, 1);
+
+  check_level_length (GTK_TREE_MODEL_FILTER (filter_model), NULL, 1);
+
+  gtk_widget_destroy (tree_view);
+  g_object_unref (filter_model);
+  g_object_unref (ref_model);
+}
+
+static void
+ref_count_transfer_root_level_reordered (void)
+{
+  GtkTreeIter grandparent1, grandparent2, grandparent3;
+  GtkTreeModel *model;
+  GtkTreeModelRefCount *ref_model;
+  GtkTreeModel *filter_model;
+  GtkWidget *tree_view;
+
+  model = gtk_tree_model_ref_count_new ();
+  ref_model = GTK_TREE_MODEL_REF_COUNT (model);
+
+  /* + grandparent1
+   * + grandparent2
+   * + grandparent3
+   */
+
+  gtk_tree_store_append (GTK_TREE_STORE (model), &grandparent1, NULL);
+  gtk_tree_store_append (GTK_TREE_STORE (model), &grandparent2, NULL);
+  gtk_tree_store_append (GTK_TREE_STORE (model), &grandparent3, NULL);
+
+  filter_model = gtk_tree_model_filter_new (model, NULL);
+  tree_view = gtk_tree_view_new_with_model (filter_model);
+
+  assert_node_ref_count (ref_model, &grandparent1, 2);
+  assert_node_ref_count (ref_model, &grandparent2, 1);
+  assert_node_ref_count (ref_model, &grandparent3, 1);
+
+  /* gtk_tree_store_move() will emit rows-reordered */
+  gtk_tree_store_move_after (GTK_TREE_STORE (model),
+                             &grandparent1, &grandparent3);
+
+  assert_node_ref_count (ref_model, &grandparent2, 2);
+  assert_node_ref_count (ref_model, &grandparent3, 1);
+  assert_node_ref_count (ref_model, &grandparent1, 1);
+
+  gtk_widget_destroy (tree_view);
+  g_object_unref (filter_model);
+  g_object_unref (ref_model);
+}
+
+static void
+ref_count_transfer_root_level_reordered_filtered (void)
+{
+  GtkTreeIter grandparent1, grandparent2, grandparent3;
+  GtkTreeModel *model;
+  GtkTreeModelRefCount *ref_model;
+  GtkTreeModel *filter_model;
+  GtkWidget *tree_view;
+  GType column_types[] = { G_TYPE_BOOLEAN };
+
+  model = gtk_tree_model_ref_count_new ();
+  ref_model = GTK_TREE_MODEL_REF_COUNT (model);
+
+  gtk_tree_store_set_column_types (GTK_TREE_STORE (model), 1,
+                                   column_types);
+
+  /* + grandparent1
+   * + grandparent2
+   * + grandparent3
+   */
+
+  gtk_tree_store_append (GTK_TREE_STORE (model), &grandparent1, NULL);
+  gtk_tree_store_append (GTK_TREE_STORE (model), &grandparent2, NULL);
+  gtk_tree_store_append (GTK_TREE_STORE (model), &grandparent3, NULL);
+
+  /* Test with 1 node filtered */
+  gtk_tree_store_set (GTK_TREE_STORE (model), &grandparent2, 0, TRUE, -1);
+  gtk_tree_store_set (GTK_TREE_STORE (model), &grandparent3, 0, TRUE, -1);
+
+  filter_model = gtk_tree_model_filter_new (model, NULL);
+  gtk_tree_model_filter_set_visible_column (GTK_TREE_MODEL_FILTER (filter_model), 0);
+  tree_view = gtk_tree_view_new_with_model (filter_model);
+
+  assert_node_ref_count (ref_model, &grandparent1, 0);
+  assert_node_ref_count (ref_model, &grandparent2, 2);
+  assert_node_ref_count (ref_model, &grandparent3, 1);
+
+  /* Move the invisible node grandparent1 */
+
+  /* gtk_tree_store_move() will emit rows-reordered */
+  gtk_tree_store_move_after (GTK_TREE_STORE (model),
+                             &grandparent1, &grandparent3);
+
+  assert_node_ref_count (ref_model, &grandparent2, 2);
+  assert_node_ref_count (ref_model, &grandparent3, 1);
+  assert_node_ref_count (ref_model, &grandparent1, 0);
+
+  /* Move the invisible node grandparent1 */
+
+  /* gtk_tree_store_move() will emit rows-reordered */
+  gtk_tree_store_move_before (GTK_TREE_STORE (model),
+                              &grandparent1, &grandparent2);
+
+  assert_node_ref_count (ref_model, &grandparent1, 0);
+  assert_node_ref_count (ref_model, &grandparent2, 2);
+  assert_node_ref_count (ref_model, &grandparent3, 1);
+
+  /* Now swap grandparent2 and grandparent3, first reference must transfer */
+  /* gtk_tree_store_swap() will emit rows-reordered */
+  gtk_tree_store_swap (GTK_TREE_STORE (model),
+                       &grandparent2, &grandparent3);
+
+  assert_node_ref_count (ref_model, &grandparent1, 0);
+  assert_node_ref_count (ref_model, &grandparent3, 2);
+  assert_node_ref_count (ref_model, &grandparent2, 1);
+
+  /* Swap back */
+  gtk_tree_store_swap (GTK_TREE_STORE (model),
+                       &grandparent2, &grandparent3);
+
+  assert_node_ref_count (ref_model, &grandparent1, 0);
+  assert_node_ref_count (ref_model, &grandparent2, 2);
+  assert_node_ref_count (ref_model, &grandparent3, 1);
+
+  gtk_tree_store_set (GTK_TREE_STORE (model), &grandparent1, 0, TRUE, -1);
+
+  assert_node_ref_count (ref_model, &grandparent1, 2);
+  assert_node_ref_count (ref_model, &grandparent2, 1);
+  assert_node_ref_count (ref_model, &grandparent3, 1);
+
+  /* Test with two nodes filtered */
+  gtk_tree_store_set (GTK_TREE_STORE (model), &grandparent1, 0, FALSE, -1);
+  gtk_tree_store_set (GTK_TREE_STORE (model), &grandparent2, 0, FALSE, -1);
+
+  assert_node_ref_count (ref_model, &grandparent1, 0);
+  assert_node_ref_count (ref_model, &grandparent2, 0);
+  assert_node_ref_count (ref_model, &grandparent3, 2);
+
+  /* gtk_tree_store_move() will emit rows-reordered */
+  gtk_tree_store_move_before (GTK_TREE_STORE (model),
+                             &grandparent3, &grandparent1);
+
+  assert_node_ref_count (ref_model, &grandparent3, 2);
+  assert_node_ref_count (ref_model, &grandparent2, 0);
+  assert_node_ref_count (ref_model, &grandparent1, 0);
+
+  gtk_widget_destroy (tree_view);
+  g_object_unref (filter_model);
+  g_object_unref (ref_model);
+}
+
+static void
+ref_count_transfer_root_level_filter (void)
+{
+  GtkTreeIter grandparent1, grandparent2, grandparent3, grandparent4;
+  GtkTreeIter new_node;
+  GtkTreeModel *model;
+  GtkTreeModelRefCount *ref_model;
+  GtkTreeModel *filter_model;
+  GtkWidget *tree_view;
+  GType column_types[] = { G_TYPE_BOOLEAN };
+
+  model = gtk_tree_model_ref_count_new ();
+  ref_model = GTK_TREE_MODEL_REF_COUNT (model);
+
+  gtk_tree_store_set_column_types (GTK_TREE_STORE (model), 1,
+                                   column_types);
+
+  /* + grandparent1
+   * + grandparent2
+   * + grandparent3
+   * + grandparent4
+   */
+
+  gtk_tree_store_append (GTK_TREE_STORE (model), &grandparent1, NULL);
+  gtk_tree_store_append (GTK_TREE_STORE (model), &grandparent2, NULL);
+  gtk_tree_store_append (GTK_TREE_STORE (model), &grandparent3, NULL);
+  gtk_tree_store_append (GTK_TREE_STORE (model), &grandparent4, NULL);
+
+  /* Filter first node */
+  gtk_tree_store_set (GTK_TREE_STORE (model), &grandparent1, 0, FALSE, -1);
+  gtk_tree_store_set (GTK_TREE_STORE (model), &grandparent2, 0, TRUE, -1);
+  gtk_tree_store_set (GTK_TREE_STORE (model), &grandparent3, 0, TRUE, -1);
+  gtk_tree_store_set (GTK_TREE_STORE (model), &grandparent4, 0, TRUE, -1);
+
+  filter_model = gtk_tree_model_filter_new (model, NULL);
+  gtk_tree_model_filter_set_visible_column (GTK_TREE_MODEL_FILTER (filter_model), 0);
+  tree_view = gtk_tree_view_new_with_model (filter_model);
+
+  assert_node_ref_count (ref_model, &grandparent1, 0);
+  assert_node_ref_count (ref_model, &grandparent2, 2);
+  assert_node_ref_count (ref_model, &grandparent3, 1);
+  assert_node_ref_count (ref_model, &grandparent4, 1);
+
+  gtk_tree_store_set (GTK_TREE_STORE (model), &grandparent2, 0, FALSE, -1);
+
+  assert_node_ref_count (ref_model, &grandparent1, 0);
+  assert_node_ref_count (ref_model, &grandparent2, 0);
+  assert_node_ref_count (ref_model, &grandparent3, 2);
+  assert_node_ref_count (ref_model, &grandparent4, 1);
+
+  gtk_tree_store_set (GTK_TREE_STORE (model), &grandparent3, 0, FALSE, -1);
+
+  assert_node_ref_count (ref_model, &grandparent1, 0);
+  assert_node_ref_count (ref_model, &grandparent2, 0);
+  assert_node_ref_count (ref_model, &grandparent3, 0);
+  assert_node_ref_count (ref_model, &grandparent4, 2);
+
+  gtk_tree_store_set (GTK_TREE_STORE (model), &grandparent4, 0, FALSE, -1);
+
+  assert_node_ref_count (ref_model, &grandparent1, 0);
+  assert_node_ref_count (ref_model, &grandparent2, 0);
+  assert_node_ref_count (ref_model, &grandparent3, 0);
+  assert_node_ref_count (ref_model, &grandparent4, 1);
+
+  gtk_tree_store_set (GTK_TREE_STORE (model), &grandparent2, 0, TRUE, -1);
+
+  assert_node_ref_count (ref_model, &grandparent1, 0);
+  assert_node_ref_count (ref_model, &grandparent2, 2);
+  assert_node_ref_count (ref_model, &grandparent3, 0);
+  assert_node_ref_count (ref_model, &grandparent4, 0);
+
+  gtk_tree_store_set (GTK_TREE_STORE (model), &grandparent2, 0, FALSE, -1);
+
+  assert_node_ref_count (ref_model, &grandparent1, 0);
+  assert_node_ref_count (ref_model, &grandparent2, 0);
+  assert_node_ref_count (ref_model, &grandparent3, 0);
+  assert_node_ref_count (ref_model, &grandparent4, 1);
+
+  gtk_tree_store_set (GTK_TREE_STORE (model), &grandparent1, 0, TRUE, -1);
+
+  assert_node_ref_count (ref_model, &grandparent1, 2);
+  assert_node_ref_count (ref_model, &grandparent2, 0);
+  assert_node_ref_count (ref_model, &grandparent3, 0);
+  assert_node_ref_count (ref_model, &grandparent4, 0);
+
+  gtk_tree_store_prepend (GTK_TREE_STORE (model), &new_node, NULL);
+
+  assert_node_ref_count (ref_model, &new_node, 0);
+  assert_node_ref_count (ref_model, &grandparent1, 2);
+  assert_node_ref_count (ref_model, &grandparent2, 0);
+  assert_node_ref_count (ref_model, &grandparent3, 0);
+  assert_node_ref_count (ref_model, &grandparent4, 0);
+
+  gtk_tree_store_set (GTK_TREE_STORE (model), &grandparent1, 0, FALSE, -1);
+
+  assert_node_ref_count (ref_model, &new_node, 0);
+  assert_node_ref_count (ref_model, &grandparent1, 0);
+  assert_node_ref_count (ref_model, &grandparent2, 0);
+  assert_node_ref_count (ref_model, &grandparent3, 0);
+  assert_node_ref_count (ref_model, &grandparent4, 1);
+
+  gtk_tree_store_remove (GTK_TREE_STORE (model), &new_node);
+  gtk_tree_store_prepend (GTK_TREE_STORE (model), &new_node, NULL);
+
+  assert_node_ref_count (ref_model, &new_node, 0);
+  assert_node_ref_count (ref_model, &grandparent1, 0);
+  assert_node_ref_count (ref_model, &grandparent2, 0);
+  assert_node_ref_count (ref_model, &grandparent3, 0);
+  assert_node_ref_count (ref_model, &grandparent4, 1);
+
+  gtk_tree_store_set (GTK_TREE_STORE (model), &new_node, 0, TRUE, -1);
+
+  assert_node_ref_count (ref_model, &new_node, 2);
+  assert_node_ref_count (ref_model, &grandparent1, 0);
+  assert_node_ref_count (ref_model, &grandparent2, 0);
+  assert_node_ref_count (ref_model, &grandparent3, 0);
+  assert_node_ref_count (ref_model, &grandparent4, 0);
+
+  gtk_tree_store_set (GTK_TREE_STORE (model), &grandparent2, 0, TRUE, -1);
+  gtk_tree_store_remove (GTK_TREE_STORE (model), &new_node);
+
+  assert_node_ref_count (ref_model, &grandparent1, 0);
+  assert_node_ref_count (ref_model, &grandparent2, 2);
+  assert_node_ref_count (ref_model, &grandparent3, 0);
+  assert_node_ref_count (ref_model, &grandparent4, 0);
+
+  gtk_tree_store_set (GTK_TREE_STORE (model), &grandparent4, 0, TRUE, -1);
+  gtk_tree_store_remove (GTK_TREE_STORE (model), &grandparent2);
+
+  gtk_widget_destroy (tree_view);
+  g_object_unref (filter_model);
+  g_object_unref (ref_model);
+}
+
+static void
+ref_count_transfer_child_level_insert (void)
+{
+  GtkTreeIter grandparent1;
+  GtkTreeIter parent1, parent2, parent3;
+  GtkTreeIter new_node;
+  GtkTreeModel *model;
+  GtkTreeModelRefCount *ref_model;
+  GtkTreeModel *filter_model;
+  GtkWidget *tree_view;
+
+  model = gtk_tree_model_ref_count_new ();
+  ref_model = GTK_TREE_MODEL_REF_COUNT (model);
+
+  /* + grandparent1
+   *   + parent1
+   *   + parent2
+   *   + parent3
+   */
+
+  gtk_tree_store_append (GTK_TREE_STORE (model), &grandparent1, NULL);
+  gtk_tree_store_append (GTK_TREE_STORE (model), &parent1, &grandparent1);
+  gtk_tree_store_append (GTK_TREE_STORE (model), &parent2, &grandparent1);
+  gtk_tree_store_append (GTK_TREE_STORE (model), &parent3, &grandparent1);
+
+  filter_model = gtk_tree_model_filter_new (model, NULL);
+  tree_view = gtk_tree_view_new_with_model (filter_model);
+
+  assert_node_ref_count (ref_model, &grandparent1, 3);
+  assert_node_ref_count (ref_model, &parent1, 1);
+  assert_node_ref_count (ref_model, &parent2, 0);
+  assert_node_ref_count (ref_model, &parent3, 0);
+
+  gtk_tree_store_prepend (GTK_TREE_STORE (model), &new_node, &grandparent1);
+
+  assert_node_ref_count (ref_model, &grandparent1, 3);
+  assert_node_ref_count (ref_model, &new_node, 1);
+  assert_node_ref_count (ref_model, &parent1, 0);
+  assert_node_ref_count (ref_model, &parent2, 0);
+  assert_node_ref_count (ref_model, &parent3, 0);
+
+  gtk_widget_destroy (tree_view);
+  g_object_unref (filter_model);
+  g_object_unref (ref_model);
+}
+
+static void
+ref_count_transfer_child_level_remove (void)
+{
+  GtkTreeIter grandparent1;
+  GtkTreeIter parent1, parent2, parent3;
+  GtkTreeModel *model;
+  GtkTreeModelRefCount *ref_model;
+  GtkTreeModel *filter_model;
+  GtkWidget *tree_view;
+
+  model = gtk_tree_model_ref_count_new ();
+  ref_model = GTK_TREE_MODEL_REF_COUNT (model);
+
+  /* + grandparent1
+   *   + parent1
+   *   + parent2
+   *   + parent3
+   */
+
+  gtk_tree_store_append (GTK_TREE_STORE (model), &grandparent1, NULL);
+  gtk_tree_store_append (GTK_TREE_STORE (model), &parent1, &grandparent1);
+  gtk_tree_store_append (GTK_TREE_STORE (model), &parent2, &grandparent1);
+  gtk_tree_store_append (GTK_TREE_STORE (model), &parent3, &grandparent1);
+
+  filter_model = gtk_tree_model_filter_new (model, NULL);
+  tree_view = gtk_tree_view_new_with_model (filter_model);
+
+  assert_node_ref_count (ref_model, &grandparent1, 3);
+  assert_node_ref_count (ref_model, &parent1, 1);
+  assert_node_ref_count (ref_model, &parent2, 0);
+  assert_node_ref_count (ref_model, &parent3, 0);
+
+  gtk_tree_store_remove (GTK_TREE_STORE (model), &parent1);
+
+  assert_node_ref_count (ref_model, &grandparent1, 3);
+  assert_node_ref_count (ref_model, &parent2, 1);
+  assert_node_ref_count (ref_model, &parent3, 0);
+
+  gtk_tree_store_remove (GTK_TREE_STORE (model), &parent2);
+
+  assert_node_ref_count (ref_model, &grandparent1, 3);
+  assert_node_ref_count (ref_model, &parent3, 1);
+
+  gtk_widget_destroy (tree_view);
+  g_object_unref (filter_model);
+  g_object_unref (ref_model);
+}
+
+static void
+ref_count_transfer_child_level_remove_filtered (void)
+{
+  GtkTreeIter grandparent1;
+  GtkTreeIter parent1, parent2, parent3, parent4;
+  GtkTreeModel *model;
+  GtkTreeModelRefCount *ref_model;
+  GtkTreeModel *filter_model;
+  GtkWidget *tree_view;
+  GType column_types[] = { G_TYPE_BOOLEAN };
+
+  model = gtk_tree_model_ref_count_new ();
+  ref_model = GTK_TREE_MODEL_REF_COUNT (model);
+
+  gtk_tree_store_set_column_types (GTK_TREE_STORE (model), 1,
+                                   column_types);
+
+  /* + grandparent1
+   *   + parent1
+   *   + parent2
+   *   + parent3
+   *   + parent4
+   */
+
+  gtk_tree_store_append (GTK_TREE_STORE (model), &grandparent1, NULL);
+  gtk_tree_store_append (GTK_TREE_STORE (model), &parent1, &grandparent1);
+  gtk_tree_store_append (GTK_TREE_STORE (model), &parent2, &grandparent1);
+  gtk_tree_store_append (GTK_TREE_STORE (model), &parent3, &grandparent1);
+  gtk_tree_store_append (GTK_TREE_STORE (model), &parent4, &grandparent1);
+
+  /* Filter first node */
+  gtk_tree_store_set (GTK_TREE_STORE (model), &grandparent1, 0, TRUE, -1);
+  gtk_tree_store_set (GTK_TREE_STORE (model), &parent1, 0, FALSE, -1);
+  gtk_tree_store_set (GTK_TREE_STORE (model), &parent2, 0, TRUE, -1);
+  gtk_tree_store_set (GTK_TREE_STORE (model), &parent3, 0, TRUE, -1);
+  gtk_tree_store_set (GTK_TREE_STORE (model), &parent4, 0, TRUE, -1);
+
+  filter_model = gtk_tree_model_filter_new (model, NULL);
+  gtk_tree_model_filter_set_visible_column (GTK_TREE_MODEL_FILTER (filter_model), 0);
+  tree_view = gtk_tree_view_new_with_model (filter_model);
+
+  assert_node_ref_count (ref_model, &grandparent1, 3);
+  assert_node_ref_count (ref_model, &parent1, 0);
+  assert_node_ref_count (ref_model, &parent2, 1);
+  assert_node_ref_count (ref_model, &parent3, 0);
+  assert_node_ref_count (ref_model, &parent4, 0);
+
+  gtk_tree_store_remove (GTK_TREE_STORE (model), &parent2);
+
+  assert_node_ref_count (ref_model, &grandparent1, 3);
+  assert_node_ref_count (ref_model, &parent1, 0);
+  assert_node_ref_count (ref_model, &parent3, 1);
+  assert_node_ref_count (ref_model, &parent4, 0);
+
+  gtk_tree_store_remove (GTK_TREE_STORE (model), &parent3);
+
+  assert_node_ref_count (ref_model, &grandparent1, 3);
+  assert_node_ref_count (ref_model, &parent1, 0);
+  assert_node_ref_count (ref_model, &parent4, 1);
+
+  gtk_tree_store_remove (GTK_TREE_STORE (model), &parent4);
+
+  /* Check level length to get level cached again */
+  check_level_length (GTK_TREE_MODEL_FILTER (filter_model), "0", 0);
+
+  assert_node_ref_count (ref_model, &grandparent1, 3);
+  assert_node_ref_count (ref_model, &parent1, 1);
+
+  gtk_tree_store_append (GTK_TREE_STORE (model), &parent2, &grandparent1);
+
+  assert_node_ref_count (ref_model, &grandparent1, 3);
+  assert_node_ref_count (ref_model, &parent1, 1);
+  assert_node_ref_count (ref_model, &parent2, 0);
+
+  gtk_tree_store_set (GTK_TREE_STORE (model), &parent2, 0, TRUE, -1);
+
+  assert_node_ref_count (ref_model, &grandparent1, 3);
+  assert_node_ref_count (ref_model, &parent1, 1);
+  assert_node_ref_count (ref_model, &parent2, 0);
+
+  check_level_length (GTK_TREE_MODEL_FILTER (filter_model), "0", 1);
+
+  gtk_widget_destroy (tree_view);
+  g_object_unref (filter_model);
+  g_object_unref (ref_model);
+}
+
+static void
+ref_count_transfer_child_level_reordered (void)
+{
+  GtkTreeIter grandparent1;
+  GtkTreeIter parent1, parent2, parent3;
+  GtkTreeModel *model;
+  GtkTreeModelRefCount *ref_model;
+  GtkTreeModel *filter_model;
+  GtkWidget *tree_view;
+
+  model = gtk_tree_model_ref_count_new ();
+  ref_model = GTK_TREE_MODEL_REF_COUNT (model);
+
+  /* + grandparent1
+   *   + parent1
+   *   + parent2
+   *   + parent3
+   */
+
+  gtk_tree_store_append (GTK_TREE_STORE (model), &grandparent1, NULL);
+  gtk_tree_store_append (GTK_TREE_STORE (model), &parent1, &grandparent1);
+  gtk_tree_store_append (GTK_TREE_STORE (model), &parent2, &grandparent1);
+  gtk_tree_store_append (GTK_TREE_STORE (model), &parent3, &grandparent1);
+
+  filter_model = gtk_tree_model_filter_new (model, NULL);
+  tree_view = gtk_tree_view_new_with_model (filter_model);
+
+  assert_node_ref_count (ref_model, &grandparent1, 3);
+  assert_node_ref_count (ref_model, &parent1, 1);
+  assert_node_ref_count (ref_model, &parent2, 0);
+  assert_node_ref_count (ref_model, &parent3, 0);
+
+  /* gtk_tree_store_move() will emit rows-reordered */
+  gtk_tree_store_move_after (GTK_TREE_STORE (model),
+                             &parent1, &parent3);
+
+  assert_node_ref_count (ref_model, &grandparent1, 3);
+  assert_node_ref_count (ref_model, &parent2, 1);
+  assert_node_ref_count (ref_model, &parent3, 0);
+  assert_node_ref_count (ref_model, &parent1, 0);
+
+  gtk_widget_destroy (tree_view);
+  g_object_unref (filter_model);
+  g_object_unref (ref_model);
+}
+
+static void
+ref_count_transfer_child_level_reordered_filtered (void)
+{
+  GtkTreeIter grandparent1;
+  GtkTreeIter parent1, parent2, parent3;
+  GtkTreeModel *model;
+  GtkTreeModelRefCount *ref_model;
+  GtkTreeModel *filter_model;
+  GtkWidget *tree_view;
+  GType column_types[] = { G_TYPE_BOOLEAN };
+
+  model = gtk_tree_model_ref_count_new ();
+  ref_model = GTK_TREE_MODEL_REF_COUNT (model);
+
+  gtk_tree_store_set_column_types (GTK_TREE_STORE (model), 1,
+                                   column_types);
+
+  /* + grandparent1
+   *   + parent1
+   *   + parent2
+   *   + parent3
+   */
+
+  gtk_tree_store_append (GTK_TREE_STORE (model), &grandparent1, NULL);
+  gtk_tree_store_append (GTK_TREE_STORE (model), &parent1, &grandparent1);
+  gtk_tree_store_append (GTK_TREE_STORE (model), &parent2, &grandparent1);
+  gtk_tree_store_append (GTK_TREE_STORE (model), &parent3, &grandparent1);
+
+  /* Test with 1 node filtered (parent1) */
+  gtk_tree_store_set (GTK_TREE_STORE (model), &grandparent1, 0, TRUE, -1);
+  gtk_tree_store_set (GTK_TREE_STORE (model), &parent2, 0, TRUE, -1);
+  gtk_tree_store_set (GTK_TREE_STORE (model), &parent3, 0, TRUE, -1);
+
+  filter_model = gtk_tree_model_filter_new (model, NULL);
+  gtk_tree_model_filter_set_visible_column (GTK_TREE_MODEL_FILTER (filter_model), 0);
+  tree_view = gtk_tree_view_new_with_model (filter_model);
+
+  assert_node_ref_count (ref_model, &grandparent1, 3);
+  assert_node_ref_count (ref_model, &parent1, 0);
+  assert_node_ref_count (ref_model, &parent2, 1);
+  assert_node_ref_count (ref_model, &parent3, 0);
+
+  /* Move invisible node parent 1 */
+
+  /* gtk_tree_store_move() will emit rows-reordered */
+  gtk_tree_store_move_after (GTK_TREE_STORE (model),
+                             &parent1, &parent3);
+
+  assert_node_ref_count (ref_model, &grandparent1, 3);
+  assert_node_ref_count (ref_model, &parent2, 1);
+  assert_node_ref_count (ref_model, &parent3, 0);
+  assert_node_ref_count (ref_model, &parent1, 0);
+
+  /* Move invisible node parent 1 */
+
+  /* gtk_tree_store_move() will emit rows-reordered */
+  gtk_tree_store_move_before (GTK_TREE_STORE (model),
+                              &parent1, &parent2);
+
+  assert_node_ref_count (ref_model, &grandparent1, 3);
+  assert_node_ref_count (ref_model, &parent1, 0);
+  assert_node_ref_count (ref_model, &parent2, 1);
+  assert_node_ref_count (ref_model, &parent3, 0);
+
+  /* Now swap parent2 and parent2, first reference must transfer */
+  /* gtk_tree_store_swap() will emit rows-reordered */
+  gtk_tree_store_swap (GTK_TREE_STORE (model),
+                       &parent2, &parent3);
+
+  assert_node_ref_count (ref_model, &grandparent1, 3);
+  assert_node_ref_count (ref_model, &parent1, 0);
+  assert_node_ref_count (ref_model, &parent3, 1);
+  assert_node_ref_count (ref_model, &parent2, 0);
+
+  /* Swap back */
+  gtk_tree_store_swap (GTK_TREE_STORE (model),
+                       &parent2, &parent3);
+
+  assert_node_ref_count (ref_model, &grandparent1, 3);
+  assert_node_ref_count (ref_model, &parent1, 0);
+  assert_node_ref_count (ref_model, &parent2, 1);
+  assert_node_ref_count (ref_model, &parent3, 0);
+
+  gtk_tree_store_set (GTK_TREE_STORE (model), &parent1, 0, TRUE, -1);
+
+  assert_node_ref_count (ref_model, &parent1, 1);
+  assert_node_ref_count (ref_model, &parent2, 0);
+  assert_node_ref_count (ref_model, &parent3, 0);
+
+  /* Test with two nodes filtered */
+  gtk_tree_store_set (GTK_TREE_STORE (model), &parent1, 0, FALSE, -1);
+  gtk_tree_store_set (GTK_TREE_STORE (model), &parent2, 0, FALSE, -1);
+
+  assert_node_ref_count (ref_model, &parent1, 0);
+  assert_node_ref_count (ref_model, &parent2, 0);
+  assert_node_ref_count (ref_model, &parent3, 1);
+
+  /* gtk_tree_store_move() will emit rows-reordered */
+  gtk_tree_store_move_before (GTK_TREE_STORE (model),
+                             &parent3, &parent1);
+
+  assert_node_ref_count (ref_model, &parent3, 1);
+  assert_node_ref_count (ref_model, &parent2, 0);
+  assert_node_ref_count (ref_model, &parent1, 0);
+
+  gtk_widget_destroy (tree_view);
+  g_object_unref (filter_model);
+  g_object_unref (ref_model);
+}
+
+static void
+ref_count_transfer_child_level_filter (void)
+{
+  GtkTreeIter root;
+  GtkTreeIter grandparent1, grandparent2, grandparent3, grandparent4;
+  GtkTreeIter new_node;
+  GtkTreeModel *model;
+  GtkTreeModelRefCount *ref_model;
+  GtkTreeModel *filter_model;
+  GtkWidget *tree_view;
+  GType column_types[] = { G_TYPE_BOOLEAN };
+
+  model = gtk_tree_model_ref_count_new ();
+  ref_model = GTK_TREE_MODEL_REF_COUNT (model);
+
+  gtk_tree_store_set_column_types (GTK_TREE_STORE (model), 1,
+                                   column_types);
+
+  /* + root
+   *    + grandparent1
+   *    + grandparent2
+   *    + grandparent3
+   *    + grandparent4
+   */
+
+  gtk_tree_store_append (GTK_TREE_STORE (model), &root, NULL);
+  gtk_tree_store_append (GTK_TREE_STORE (model), &grandparent1, &root);
+  gtk_tree_store_append (GTK_TREE_STORE (model), &grandparent2, &root);
+  gtk_tree_store_append (GTK_TREE_STORE (model), &grandparent3, &root);
+  gtk_tree_store_append (GTK_TREE_STORE (model), &grandparent4, &root);
+
+  /* Filter first node */
+  gtk_tree_store_set (GTK_TREE_STORE (model), &root, 0, TRUE, -1);
+  gtk_tree_store_set (GTK_TREE_STORE (model), &grandparent1, 0, FALSE, -1);
+  gtk_tree_store_set (GTK_TREE_STORE (model), &grandparent2, 0, TRUE, -1);
+  gtk_tree_store_set (GTK_TREE_STORE (model), &grandparent3, 0, TRUE, -1);
+  gtk_tree_store_set (GTK_TREE_STORE (model), &grandparent4, 0, TRUE, -1);
+
+  filter_model = gtk_tree_model_filter_new (model, NULL);
+  gtk_tree_model_filter_set_visible_column (GTK_TREE_MODEL_FILTER (filter_model), 0);
+  tree_view = gtk_tree_view_new_with_model (filter_model);
+
+  assert_node_ref_count (ref_model, &grandparent1, 0);
+  assert_node_ref_count (ref_model, &grandparent2, 1);
+  assert_node_ref_count (ref_model, &grandparent3, 0);
+  assert_node_ref_count (ref_model, &grandparent4, 0);
+
+  gtk_tree_store_set (GTK_TREE_STORE (model), &grandparent2, 0, FALSE, -1);
+
+  assert_node_ref_count (ref_model, &grandparent1, 0);
+  assert_node_ref_count (ref_model, &grandparent2, 0);
+  assert_node_ref_count (ref_model, &grandparent3, 1);
+  assert_node_ref_count (ref_model, &grandparent4, 0);
+
+  gtk_tree_store_set (GTK_TREE_STORE (model), &grandparent3, 0, FALSE, -1);
+
+  assert_node_ref_count (ref_model, &grandparent1, 0);
+  assert_node_ref_count (ref_model, &grandparent2, 0);
+  assert_node_ref_count (ref_model, &grandparent3, 0);
+  assert_node_ref_count (ref_model, &grandparent4, 1);
+
+  gtk_tree_store_set (GTK_TREE_STORE (model), &grandparent4, 0, FALSE, -1);
+
+  assert_node_ref_count (ref_model, &grandparent1, 0);
+  assert_node_ref_count (ref_model, &grandparent2, 0);
+  assert_node_ref_count (ref_model, &grandparent3, 0);
+  assert_node_ref_count (ref_model, &grandparent4, 1);
+
+  gtk_tree_store_set (GTK_TREE_STORE (model), &grandparent2, 0, TRUE, -1);
+
+  assert_node_ref_count (ref_model, &grandparent1, 0);
+  assert_node_ref_count (ref_model, &grandparent2, 1);
+  assert_node_ref_count (ref_model, &grandparent3, 0);
+  assert_node_ref_count (ref_model, &grandparent4, 0);
 
-static void
-remove_node_vroot (void)
-{
-  GtkTreeIter parent, root;
-  GtkTreeIter iter, iter1, iter2, iter3;
-  GtkTreeStore *tree;
-  GtkTreeModel *filter;
-  GtkTreePath *path;
-  GtkWidget *view G_GNUC_UNUSED;
+  gtk_tree_store_set (GTK_TREE_STORE (model), &grandparent2, 0, FALSE, -1);
 
-  tree = gtk_tree_store_new (1, G_TYPE_INT);
-  gtk_tree_store_insert_with_values (tree, &parent, NULL, 0, 0, 0, -1);
-  gtk_tree_store_insert_with_values (tree, &root, &parent, 0, 0, 0, -1);
+  assert_node_ref_count (ref_model, &grandparent1, 0);
+  assert_node_ref_count (ref_model, &grandparent2, 0);
+  assert_node_ref_count (ref_model, &grandparent3, 0);
+  assert_node_ref_count (ref_model, &grandparent4, 1);
 
-  gtk_tree_store_insert_with_values (tree, &iter1, &root, 0, 0, 1, -1);
-  gtk_tree_store_insert_with_values (tree, &iter, &root, 1, 0, 2, -1);
-  gtk_tree_store_insert_with_values (tree, &iter, &root, 2, 0, 3, -1);
-  gtk_tree_store_insert_with_values (tree, &iter, &root, 3, 0, 4, -1);
-  gtk_tree_store_insert_with_values (tree, &iter, &root, 4, 0, 5, -1);
-  gtk_tree_store_insert_with_values (tree, &iter, &root, 5, 0, 6, -1);
-  gtk_tree_store_insert_with_values (tree, &iter2, &root, 6, 0, 7, -1);
-  gtk_tree_store_insert_with_values (tree, &iter3, &root, 7, 0, 8, -1);
+  gtk_tree_store_set (GTK_TREE_STORE (model), &grandparent1, 0, TRUE, -1);
 
-  path = gtk_tree_path_new_from_indices (0, 0, -1);
-  filter = gtk_tree_model_filter_new (GTK_TREE_MODEL (tree), path);
-  gtk_tree_path_free (path);
+  assert_node_ref_count (ref_model, &grandparent1, 1);
+  assert_node_ref_count (ref_model, &grandparent2, 0);
+  assert_node_ref_count (ref_model, &grandparent3, 0);
+  assert_node_ref_count (ref_model, &grandparent4, 0);
 
-  view = gtk_tree_view_new_with_model (filter);
+  gtk_tree_store_prepend (GTK_TREE_STORE (model), &new_node, &root);
 
-  gtk_tree_store_remove (tree, &iter1);
-  gtk_tree_store_remove (tree, &iter3);
-  gtk_tree_store_remove (tree, &iter2);
+  assert_node_ref_count (ref_model, &new_node, 0);
+  assert_node_ref_count (ref_model, &grandparent1, 1);
+  assert_node_ref_count (ref_model, &grandparent2, 0);
+  assert_node_ref_count (ref_model, &grandparent3, 0);
+  assert_node_ref_count (ref_model, &grandparent4, 0);
 
-  gtk_widget_destroy (view);
-  g_object_unref (filter);
-  g_object_unref (tree);
-}
+  gtk_tree_store_set (GTK_TREE_STORE (model), &grandparent1, 0, FALSE, -1);
 
-static void
-remove_vroot_ancestor (void)
-{
-  GtkTreeIter parent, root;
-  GtkTreeIter iter, iter1, iter2, iter3;
-  GtkTreeStore *tree;
-  GtkTreeModel *filter;
-  GtkTreePath *path;
-  GtkWidget *view G_GNUC_UNUSED;
+  assert_node_ref_count (ref_model, &new_node, 0);
+  assert_node_ref_count (ref_model, &grandparent1, 0);
+  assert_node_ref_count (ref_model, &grandparent2, 0);
+  assert_node_ref_count (ref_model, &grandparent3, 0);
+  assert_node_ref_count (ref_model, &grandparent4, 1);
 
-  tree = gtk_tree_store_new (1, G_TYPE_INT);
-  gtk_tree_store_insert_with_values (tree, &parent, NULL, 0, 0, 0, -1);
-  gtk_tree_store_insert_with_values (tree, &root, &parent, 0, 0, 0, -1);
+  gtk_tree_store_remove (GTK_TREE_STORE (model), &new_node);
+  gtk_tree_store_prepend (GTK_TREE_STORE (model), &new_node, &root);
 
-  gtk_tree_store_insert_with_values (tree, &iter1, &root, 0, 0, 1, -1);
-  gtk_tree_store_insert_with_values (tree, &iter, &root, 1, 0, 2, -1);
-  gtk_tree_store_insert_with_values (tree, &iter, &root, 2, 0, 3, -1);
-  gtk_tree_store_insert_with_values (tree, &iter, &root, 3, 0, 4, -1);
-  gtk_tree_store_insert_with_values (tree, &iter, &root, 4, 0, 5, -1);
-  gtk_tree_store_insert_with_values (tree, &iter, &root, 5, 0, 6, -1);
-  gtk_tree_store_insert_with_values (tree, &iter2, &root, 6, 0, 7, -1);
-  gtk_tree_store_insert_with_values (tree, &iter3, &root, 7, 0, 8, -1);
+  assert_node_ref_count (ref_model, &new_node, 0);
+  assert_node_ref_count (ref_model, &grandparent1, 0);
+  assert_node_ref_count (ref_model, &grandparent2, 0);
+  assert_node_ref_count (ref_model, &grandparent3, 0);
+  assert_node_ref_count (ref_model, &grandparent4, 1);
 
-  path = gtk_tree_path_new_from_indices (0, 0, -1);
-  filter = gtk_tree_model_filter_new (GTK_TREE_MODEL (tree), path);
-  gtk_tree_path_free (path);
+  gtk_tree_store_set (GTK_TREE_STORE (model), &new_node, 0, TRUE, -1);
 
-  view = gtk_tree_view_new_with_model (filter);
+  assert_node_ref_count (ref_model, &new_node, 1);
+  assert_node_ref_count (ref_model, &grandparent1, 0);
+  assert_node_ref_count (ref_model, &grandparent2, 0);
+  assert_node_ref_count (ref_model, &grandparent3, 0);
+  assert_node_ref_count (ref_model, &grandparent4, 0);
 
-  gtk_tree_store_remove (tree, &parent);
+  gtk_tree_store_set (GTK_TREE_STORE (model), &grandparent2, 0, TRUE, -1);
+  gtk_tree_store_remove (GTK_TREE_STORE (model), &new_node);
 
-  gtk_widget_destroy (view);
-  g_object_unref (filter);
-  g_object_unref (tree);
+  assert_node_ref_count (ref_model, &grandparent1, 0);
+  assert_node_ref_count (ref_model, &grandparent2, 1);
+  assert_node_ref_count (ref_model, &grandparent3, 0);
+  assert_node_ref_count (ref_model, &grandparent4, 0);
+
+  gtk_tree_store_set (GTK_TREE_STORE (model), &grandparent4, 0, TRUE, -1);
+  gtk_tree_store_remove (GTK_TREE_STORE (model), &grandparent2);
+
+  gtk_widget_destroy (tree_view);
+  g_object_unref (filter_model);
+  g_object_unref (ref_model);
 }
 
 
@@ -2913,6 +5009,10 @@ specific_has_child_filter (void)
   set_path_visibility (&fixture, "0", FALSE);
   /* check_filter_model (&fixture); */
   signal_monitor_assert_is_empty (fixture.monitor);
+
+  g_object_unref (fixture.filter);
+  g_object_unref (fixture.store);
+  gtk_widget_destroy (tree_view);
 }
 
 
@@ -3073,6 +5173,10 @@ specific_root_has_child_filter (void)
   set_path_visibility (&fixture, "0", FALSE);
   /* check_filter_model (&fixture); */
   signal_monitor_assert_is_empty (fixture.monitor);
+
+  g_object_unref (fixture.filter);
+  g_object_unref (fixture.store);
+  gtk_widget_destroy (tree_view);
 }
 
 static void
@@ -3179,6 +5283,10 @@ specific_has_child_filter_on_sort_model (void)
   set_path_visibility (&fixture, "0", FALSE);
   /* check_filter_model (&fixture); */
   signal_monitor_assert_is_empty (fixture.monitor);
+
+  g_object_unref (fixture.filter);
+  g_object_unref (fixture.store);
+  gtk_widget_destroy (tree_view);
 }
 
 static gboolean
@@ -3296,11 +5404,16 @@ specific_at_least_2_children_filter (void)
   set_path_visibility (&fixture, "0", FALSE);
   /* check_filter_model (&fixture); */
   signal_monitor_assert_is_empty (fixture.monitor);
+
+  g_object_unref (fixture.filter);
+  g_object_unref (fixture.store);
+  gtk_widget_destroy (tree_view);
 }
 
 static void
 specific_at_least_2_children_filter_on_sort_model (void)
 {
+  GtkTreeRowReference *ref;
   GtkTreeModel *filter;
   GtkTreeModel *sort_model;
   GtkTreeIter iter, root;
@@ -3337,7 +5450,6 @@ specific_at_least_2_children_filter_on_sort_model (void)
 
     {
       GtkTreePath *path = gtk_tree_path_new_from_indices (0, 0, -1);
-      GtkTreeRowReference *ref;
 
       ref = gtk_tree_row_reference_new (sort_model, path);
       gtk_tree_path_free (path);
@@ -3372,6 +5484,11 @@ specific_at_least_2_children_filter_on_sort_model (void)
   gtk_tree_store_append (fixture.store, &root, NULL);
   check_level_length (fixture.filter, NULL, 1);
   signal_monitor_assert_is_empty (fixture.monitor);
+
+  gtk_tree_row_reference_free (ref);
+  g_object_unref (fixture.filter);
+  g_object_unref (fixture.store);
+  gtk_widget_destroy (tree_view);
 }
 
 
@@ -4315,6 +6432,330 @@ specific_bug_621076 (void)
   g_object_unref (filter);
 }
 
+static void
+specific_bug_657353_related (void)
+{
+  GtkTreeIter node1, node2, node3, node4;
+  GtkTreeModel *model;
+  GtkTreeModelRefCount *ref_model;
+  GtkTreeModel *filter_model;
+  GtkWidget *tree_view;
+  GType column_types[] = { G_TYPE_BOOLEAN };
+
+  /* gtk_tree_model_filter_rows_reordered() used to have a problem to
+   * not properly transfer the first ref count when the first node in
+   * the level does not have elt->offset == 0.  This test checks for
+   * that.  This bug could cause the faulty condition
+   *   elt->ext_ref_count > elt->ref_count
+   * to raise.
+   */
+
+  model = gtk_tree_model_ref_count_new ();
+  ref_model = GTK_TREE_MODEL_REF_COUNT (model);
+
+  gtk_tree_store_set_column_types (GTK_TREE_STORE (model), 1,
+                                   column_types);
+
+  gtk_tree_store_append (GTK_TREE_STORE (model), &node1, NULL);
+  gtk_tree_store_append (GTK_TREE_STORE (model), &node2, NULL);
+  gtk_tree_store_append (GTK_TREE_STORE (model), &node3, NULL);
+  gtk_tree_store_append (GTK_TREE_STORE (model), &node4, NULL);
+
+  /* Hide the first node */
+  gtk_tree_store_set (GTK_TREE_STORE (model), &node1, 0, FALSE, -1);
+  gtk_tree_store_set (GTK_TREE_STORE (model), &node2, 0, TRUE, -1);
+  gtk_tree_store_set (GTK_TREE_STORE (model), &node3, 0, TRUE, -1);
+  gtk_tree_store_set (GTK_TREE_STORE (model), &node4, 0, TRUE, -1);
+
+  filter_model = gtk_tree_model_filter_new (model, NULL);
+  gtk_tree_model_filter_set_visible_column (GTK_TREE_MODEL_FILTER (filter_model), 0);
+  tree_view = gtk_tree_view_new_with_model (filter_model);
+
+  assert_node_ref_count (ref_model, &node1, 0);
+  assert_node_ref_count (ref_model, &node2, 2);
+  assert_node_ref_count (ref_model, &node3, 1);
+  assert_node_ref_count (ref_model, &node4, 1);
+
+  /* Swap nodes 2 and 3 */
+
+  /* gtk_tree_store_swap() will emit rows-reordered */
+  gtk_tree_store_swap (GTK_TREE_STORE (model),
+                       &node2, &node3);
+
+  assert_node_ref_count (ref_model, &node1, 0);
+  assert_node_ref_count (ref_model, &node3, 2);
+  assert_node_ref_count (ref_model, &node2, 1);
+  assert_node_ref_count (ref_model, &node4, 1);
+
+  /* Hide node 3 */
+  gtk_tree_store_set (GTK_TREE_STORE (model), &node3, 0, FALSE, -1);
+
+  assert_node_ref_count (ref_model, &node1, 0);
+  assert_node_ref_count (ref_model, &node3, 0);
+  assert_node_ref_count (ref_model, &node2, 2);
+  assert_node_ref_count (ref_model, &node4, 1);
+
+  gtk_widget_destroy (tree_view);
+  g_object_unref (filter_model);
+  g_object_unref (ref_model);
+}
+
+static gboolean
+specific_bug_657353_visible_func (GtkTreeModel *model,
+                                  GtkTreeIter  *iter,
+                                  gpointer      data)
+{
+  gchar *str;
+  gboolean ret = FALSE;
+
+  gtk_tree_model_get (model, iter, 0, &str, -1);
+  ret = strstr (str, "hidden") ? FALSE : TRUE;
+  g_free (str);
+
+  return ret;
+}
+
+static void
+specific_bug_657353 (void)
+{
+  GtkListStore *store;
+  GtkTreeModel *sort_model;
+  GtkTreeModel *filter_model;
+  GtkTreeIter iter, iter_a, iter_b, iter_c;
+  GtkWidget *tree_view;
+
+  /* This is a very carefully crafted test case that is triggering the
+   * situation described in bug 657353.
+   *
+   *   GtkListStore acts like EphyCompletionModel
+   *   GtkTreeModelSort acts like the sort model added in
+   *                      ephy_location_entry_set_completion.
+   *   GtkTreeModelFilter acts like the filter model in
+   *                      GtkEntryCompletion.
+   */
+
+  /* Set up a model that's wrapped in a GtkTreeModelSort.  The first item
+   * will be hidden.
+   */
+  store = gtk_list_store_new (1, G_TYPE_STRING);
+  gtk_list_store_insert_with_values (store, &iter_b, 0, 0, "BBB hidden", -1);
+  gtk_list_store_insert_with_values (store, &iter, 1, 0, "EEE", -1);
+  gtk_list_store_insert_with_values (store, &iter, 2, 0, "DDD", -1);
+  gtk_list_store_insert_with_values (store, &iter_c, 3, 0, "CCC", -1);
+
+  sort_model = gtk_tree_model_sort_new_with_model (GTK_TREE_MODEL (store));
+
+  filter_model = gtk_tree_model_filter_new (sort_model, NULL);
+  gtk_tree_model_filter_set_visible_func (GTK_TREE_MODEL_FILTER (filter_model),
+                                          specific_bug_657353_visible_func,
+                                          filter_model, NULL);
+
+  tree_view = gtk_tree_view_new_with_model (filter_model);
+
+  /* This triggers emission of rows-reordered.  The elt with offset == 0
+   * is hidden, which used to cause misbehavior.  (The first reference should
+   * have moved to CCC, which did not happen).
+   */
+  gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (sort_model),
+                                        0, GTK_SORT_ASCENDING);
+
+  /* By inserting another item that will appear at the first position, a
+   * reference transfer is done from CCC (which failed to get this reference
+   * earlier) to AAA.  At this point, the rule
+   * elt->ref_count >= elt->ext_ref_count is broken for CCC.
+   */
+  gtk_list_store_insert_with_values (store, &iter_a, 6, 0, "AAA", -1);
+
+  /* When we hide CCC, the references cannot be correctly released, because
+   * CCC failed to get a reference during rows-reordered.  The faulty condition
+   * only manifests itself here with MODEL_FILTER_DEBUG disabled (as is usual
+   * in production).
+   */
+  gtk_list_store_set (store, &iter_c, 0, "CCC hidden", -1);
+
+  gtk_widget_destroy (tree_view);
+  g_object_unref (filter_model);
+  g_object_unref (sort_model);
+  g_object_unref (store);
+}
+
+static void
+specific_bug_658696 (void)
+{
+  GtkTreeStore *store;
+  GtkTreeModel *filter;
+  GtkTreePath *vroot;
+  GtkTreeIter iter;
+
+  store = create_tree_store (4, TRUE);
+
+  vroot = gtk_tree_path_new_from_indices (0, 0, -1);
+  filter = gtk_tree_model_filter_new (GTK_TREE_MODEL (store), vroot);
+  gtk_tree_path_free (vroot);
+
+  /* This used to cause a crash in gtk_tree_model_filter_check_ancestors() */
+  gtk_tree_store_append (store, &iter, NULL);
+
+  g_object_unref (store);
+  g_object_unref (filter);
+}
+
+static gboolean
+specific_bug_659022_visible_func (GtkTreeModel *model,
+                                  GtkTreeIter  *iter,
+                                  gpointer      data)
+{
+  GtkTreeIter tmp;
+
+  if (!gtk_tree_model_iter_parent (model, &tmp, iter))
+    {
+      if (gtk_tree_model_iter_n_children (model, iter) >= 2)
+        return TRUE;
+      else
+        return FALSE;
+    }
+
+  return TRUE;
+}
+
+static void
+specific_bug_659022_row_changed_emission (void)
+{
+  GtkTreeModel *filter;
+  GtkTreeModel *model;
+  GtkTreeIter parent, child, child2;
+  GtkTreePath *path;
+  GtkWidget *tree_view;
+
+  model = gtk_tree_model_ref_count_new ();
+
+  filter = gtk_tree_model_filter_new (model, NULL);
+  gtk_tree_model_filter_set_visible_func (GTK_TREE_MODEL_FILTER (filter),
+                                          specific_bug_659022_visible_func,
+                                          NULL, NULL);
+
+  tree_view = gtk_tree_view_new_with_model (GTK_TREE_MODEL (filter));
+
+  gtk_tree_store_insert (GTK_TREE_STORE (model), &parent, NULL, 0);
+  gtk_tree_store_insert (GTK_TREE_STORE (model), &child, &parent, 0);
+  gtk_tree_store_insert (GTK_TREE_STORE (model), &child2, &parent, 0);
+
+  gtk_tree_view_expand_all (GTK_TREE_VIEW (tree_view));
+
+  gtk_tree_model_filter_refilter (GTK_TREE_MODEL_FILTER (filter));
+
+  gtk_tree_store_remove (GTK_TREE_STORE (model), &child2);
+
+  gtk_tree_model_filter_refilter (GTK_TREE_MODEL_FILTER (filter));
+
+  path = gtk_tree_model_get_path (model, &child);
+  gtk_tree_model_row_changed (model, path, &child);
+  gtk_tree_path_free (path);
+
+  gtk_widget_destroy (tree_view);
+  g_object_unref (filter);
+  g_object_unref (model);
+}
+
+static void
+specific_bug_659022_row_deleted_node_invisible (void)
+{
+  GtkTreeModel *filter;
+  GtkTreeModel *model;
+  GtkTreeIter parent, child;
+  GtkTreeIter parent2, child2, child3;
+  GtkWidget *tree_view;
+
+  model = gtk_tree_model_ref_count_new ();
+
+  filter = gtk_tree_model_filter_new (model, NULL);
+  gtk_tree_model_filter_set_visible_func (GTK_TREE_MODEL_FILTER (filter),
+                                          specific_bug_659022_visible_func,
+                                          NULL, NULL);
+
+  tree_view = gtk_tree_view_new_with_model (GTK_TREE_MODEL (filter));
+
+  gtk_tree_store_insert (GTK_TREE_STORE (model), &parent, NULL, 0);
+  gtk_tree_store_insert (GTK_TREE_STORE (model), &child, &parent, 0);
+
+  gtk_tree_store_insert (GTK_TREE_STORE (model), &parent2, NULL, 0);
+  gtk_tree_store_insert (GTK_TREE_STORE (model), &child2, &parent2, 0);
+  gtk_tree_store_insert (GTK_TREE_STORE (model), &child3, &parent2, 0);
+
+  gtk_tree_view_expand_all (GTK_TREE_VIEW (tree_view));
+
+  gtk_tree_model_filter_refilter (GTK_TREE_MODEL_FILTER (filter));
+
+  gtk_tree_store_remove (GTK_TREE_STORE (model), &parent);
+
+  gtk_widget_destroy (tree_view);
+  g_object_unref (filter);
+  g_object_unref (model);
+}
+
+static void
+specific_bug_659022_row_deleted_free_level (void)
+{
+  GtkTreeModel *filter;
+  GtkTreeModel *model;
+  GtkTreeModelRefCount *ref_model;
+  GtkTreeIter parent, child;
+  GtkTreeIter parent2, child2, child3;
+  GtkWidget *tree_view;
+
+  model = gtk_tree_model_ref_count_new ();
+  ref_model = GTK_TREE_MODEL_REF_COUNT (model);
+
+  filter = gtk_tree_model_filter_new (model, NULL);
+  gtk_tree_model_filter_set_visible_func (GTK_TREE_MODEL_FILTER (filter),
+                                          specific_bug_659022_visible_func,
+                                          NULL, NULL);
+
+  tree_view = gtk_tree_view_new_with_model (GTK_TREE_MODEL (filter));
+
+  /* Carefully construct a model */
+  gtk_tree_store_insert (GTK_TREE_STORE (model), &parent, NULL, 0);
+  gtk_tree_store_insert (GTK_TREE_STORE (model), &child, &parent, 0);
+
+  gtk_tree_store_insert (GTK_TREE_STORE (model), &parent2, NULL, 0);
+  gtk_tree_store_insert (GTK_TREE_STORE (model), &child2, &parent2, 0);
+  gtk_tree_store_insert (GTK_TREE_STORE (model), &child3, &parent2, 0);
+
+  /* Only parent2 is visible, child3 holds first ref count for that level
+   * (Note that above, both child2 as child3 are inserted at position 0).
+   */
+  assert_node_ref_count (ref_model, &parent, 0);
+  assert_node_ref_count (ref_model, &child, 0);
+  assert_node_ref_count (ref_model, &parent2, 3);
+  assert_node_ref_count (ref_model, &child3, 1);
+  assert_node_ref_count (ref_model, &child2, 0);
+
+  /* Make sure child level is cached */
+  gtk_tree_view_expand_all (GTK_TREE_VIEW (tree_view));
+
+  assert_node_ref_count (ref_model, &parent, 0);
+  assert_node_ref_count (ref_model, &child, 0);
+  assert_node_ref_count (ref_model, &parent2, 3);
+  assert_node_ref_count (ref_model, &child3, 2);
+  assert_node_ref_count (ref_model, &child2, 1);
+
+  gtk_tree_view_collapse_all (GTK_TREE_VIEW (tree_view));
+
+  assert_node_ref_count (ref_model, &parent, 0);
+  assert_node_ref_count (ref_model, &child, 0);
+  assert_node_ref_count (ref_model, &parent2, 3);
+  assert_node_ref_count (ref_model, &child3, 1);
+  assert_node_ref_count (ref_model, &child2, 0);
+
+  /* Remove node with longer child level first */
+  gtk_tree_store_remove (GTK_TREE_STORE (model), &parent2);
+  gtk_tree_store_remove (GTK_TREE_STORE (model), &parent);
+
+  gtk_widget_destroy (tree_view);
+  g_object_unref (filter);
+  g_object_unref (model);
+}
+
 /* main */
 
 void
@@ -4505,6 +6946,49 @@ register_filter_model_tests (void)
               unfiltered_vroot_show_single_multi_level_root_expanded,
               filter_test_teardown);
 
+
+  g_test_add ("/TreeModelFilter/unfiltered/rows-reordered/root-level",
+              FilterTest, NULL,
+              filter_test_setup_unfiltered,
+              unfiltered_rows_reordered_root_level,
+              filter_test_teardown);
+  g_test_add ("/TreeModelFilter/unfiltered/rows-reordered/child-level",
+              FilterTest, NULL,
+              filter_test_setup_unfiltered,
+              unfiltered_rows_reordered_child_level,
+              filter_test_teardown);
+
+  g_test_add ("/TreeModelFilter/filtered/rows-reordered/root-level/first-hidden",
+              FilterTest, NULL,
+              filter_test_setup,
+              filtered_rows_reordered_root_level_first_hidden,
+              filter_test_teardown);
+  g_test_add ("/TreeModelFilter/filtered/rows-reordered/root-level/middle-hidden",
+              FilterTest, NULL,
+              filter_test_setup,
+              filtered_rows_reordered_root_level_middle_hidden,
+              filter_test_teardown);
+  g_test_add ("/TreeModelFilter/filtered/rows-reordered/child-level/first-hidden",
+              FilterTest, NULL,
+              filter_test_setup,
+              filtered_rows_reordered_child_level_first_hidden,
+              filter_test_teardown);
+  g_test_add ("/TreeModelFilter/filtered/rows-reordered/child-level/middle-hidden",
+              FilterTest, NULL,
+              filter_test_setup,
+              filtered_rows_reordered_child_level_middle_hidden,
+              filter_test_teardown);
+  g_test_add ("/TreeModelFilter/filtered/rows-reordered/child-level/4-hidden",
+              FilterTest, NULL,
+              filter_test_setup,
+              filtered_rows_reordered_child_level_4_hidden,
+              filter_test_teardown);
+  g_test_add ("/TreeModelFilter/filtered/rows-reordered/child-level/all-hidden",
+              FilterTest, NULL,
+              filter_test_setup,
+              filtered_rows_reordered_child_level_all_hidden,
+              filter_test_teardown);
+
   /* Inserts in child models after creation of filter model */
   g_test_add_func ("/TreeModelFilter/insert/before",
                    insert_before);
@@ -4519,6 +7003,58 @@ register_filter_model_tests (void)
   g_test_add_func ("/TreeModelFilter/remove/vroot-ancestor",
                    remove_vroot_ancestor);
 
+  /* Reference counting */
+  g_test_add_func ("/TreeModelFilter/ref-count/single-level",
+                   ref_count_single_level);
+  g_test_add_func ("/TreeModelFilter/ref-count/two-levels",
+                   ref_count_two_levels);
+  g_test_add_func ("/TreeModelFilter/ref-count/three-levels",
+                   ref_count_three_levels);
+  g_test_add_func ("/TreeModelFilter/ref-count/delete-row",
+                   ref_count_delete_row);
+  g_test_add_func ("/TreeModelFilter/ref-count/filter-row/length-1",
+                   ref_count_filter_row_length_1);
+  g_test_add_func ("/TreeModelFilter/ref-count/filter-row/length-1-remove-in-root-level",
+                   ref_count_filter_row_length_1_remove_in_root_level);
+  g_test_add_func ("/TreeModelFilter/ref-count/filter-row/length-1-remove-in-child-level",
+                   ref_count_filter_row_length_1_remove_in_child_level);
+  g_test_add_func ("/TreeModelFilter/ref-count/filter-row/length-gt-1",
+                   ref_count_filter_row_length_gt_1);
+  g_test_add_func ("/TreeModelFilter/ref-count/filter-row/length-gt-1-visible-children",
+                   ref_count_filter_row_length_gt_1_visible_children);
+  g_test_add_func ("/TreeModelFilter/ref-count/cleanup",
+                   ref_count_cleanup);
+  g_test_add_func ("/TreeModelFilter/ref-count/row-ref",
+                   ref_count_row_ref);
+
+  /* Reference counting, transfer of first reference on
+   * first node in level.  This is a GtkTreeModelFilter-specific
+   * feature.
+   */
+  g_test_add_func ("/TreeModelFilter/ref-count/transfer/root-level/insert",
+                   ref_count_transfer_root_level_insert);
+  g_test_add_func ("/TreeModelFilter/ref-count/transfer/root-level/remove",
+                   ref_count_transfer_root_level_remove);
+  g_test_add_func ("/TreeModelFilter/ref-count/transfer/root-level/remove/filtered",
+                   ref_count_transfer_root_level_remove_filtered);
+  g_test_add_func ("/TreeModelFilter/ref-count/transfer/root-level/reordered",
+                   ref_count_transfer_root_level_reordered);
+  g_test_add_func ("/TreeModelFilter/ref-count/transfer/root-level/reordered/filtered",
+                   ref_count_transfer_root_level_reordered_filtered);
+  g_test_add_func ("/TreeModelFilter/ref-count/transfer/root-level/filter",
+                   ref_count_transfer_root_level_filter);
+  g_test_add_func ("/TreeModelFilter/ref-count/transfer/child-level/insert",
+                   ref_count_transfer_child_level_insert);
+  g_test_add_func ("/TreeModelFilter/ref-count/transfer/child-level/remove",
+                   ref_count_transfer_child_level_remove);
+  g_test_add_func ("/TreeModelFilter/ref-count/transfer/child-level/remove/filtered",
+                   ref_count_transfer_child_level_remove_filtered);
+  g_test_add_func ("/TreeModelFilter/ref-count/transfer/child-level/reordered",
+                   ref_count_transfer_child_level_reordered);
+  g_test_add_func ("/TreeModelFilter/ref-count/transfer/child-level/reordered/filtered",
+                   ref_count_transfer_child_level_reordered_filtered);
+  g_test_add_func ("/TreeModelFilter/ref-count/transfer/child-level/filter",
+                   ref_count_transfer_child_level_filter);
 
   g_test_add_func ("/TreeModelFilter/specific/path-dependent-filter",
                    specific_path_dependent_filter);
@@ -4567,4 +7103,16 @@ register_filter_model_tests (void)
                    specific_bug_549287);
   g_test_add_func ("/TreeModelFilter/specific/bug-621076",
                    specific_bug_621076);
+  g_test_add_func ("/TreeModelFilter/specific/bug-657353-related",
+                   specific_bug_657353_related);
+  g_test_add_func ("/TreeModelFilter/specific/bug-657353",
+                   specific_bug_657353);
+  g_test_add_func ("/TreeModelFilter/specific/bug-658696",
+                   specific_bug_658696);
+  g_test_add_func ("/TreeModelFilter/specific/bug-659022/row-changed-emission",
+                   specific_bug_659022_row_changed_emission);
+  g_test_add_func ("/TreeModelFilter/specific/bug-659022/row-deleted-node-invisible",
+                   specific_bug_659022_row_deleted_node_invisible);
+  g_test_add_func ("/TreeModelFilter/specific/bug-659022/row-deleted-free-level",
+                   specific_bug_659022_row_deleted_free_level);
 }