Bug 586374 – code does not follow documentation

Properly invalidate iterators in iter_next, iter_children,
iter_nth_child and iter_parent when FALSE is returned.  ListStore was
actually already mostly in order as the GSequence pointers are very
strictly checked, but to be a little stricter we've added stamp = 0
lines.  TreeStore did not invalidate its iterators, so stamp = 0 lines
were added where appropriate.  Unit tests have been added to check this.

Fixes bug 586374, reported by Mike Gemunde.
This commit is contained in:
Kristian Rietveld 2009-07-30 21:23:47 +02:00
parent a79ef0866b
commit d743b2fbea
4 changed files with 194 additions and 7 deletions

View File

@ -494,10 +494,16 @@ static gboolean
gtk_list_store_iter_next (GtkTreeModel *tree_model,
GtkTreeIter *iter)
{
gboolean retval;
g_return_val_if_fail (GTK_LIST_STORE (tree_model)->stamp == iter->stamp, FALSE);
iter->user_data = g_sequence_iter_next (iter->user_data);
return !g_sequence_iter_is_end (iter->user_data);
retval = g_sequence_iter_is_end (iter->user_data);
if (retval)
iter->stamp = 0;
return !retval;
}
static gboolean
@ -509,7 +515,10 @@ gtk_list_store_iter_children (GtkTreeModel *tree_model,
/* this is a list, nodes have no children */
if (parent)
return FALSE;
{
iter->stamp = 0;
return FALSE;
}
if (g_sequence_get_length (list_store->seq) > 0)
{
@ -518,7 +527,10 @@ gtk_list_store_iter_children (GtkTreeModel *tree_model,
return TRUE;
}
else
return FALSE;
{
iter->stamp = 0;
return FALSE;
}
}
static gboolean
@ -551,6 +563,8 @@ gtk_list_store_iter_nth_child (GtkTreeModel *tree_model,
GtkListStore *list_store = (GtkListStore *) tree_model;
GSequenceIter *child;
iter->stamp = 0;
if (parent)
return FALSE;
@ -570,6 +584,7 @@ gtk_list_store_iter_parent (GtkTreeModel *tree_model,
GtkTreeIter *iter,
GtkTreeIter *child)
{
iter->stamp = 0;
return FALSE;
}

View File

@ -620,7 +620,10 @@ gtk_tree_store_iter_next (GtkTreeModel *tree_model,
return TRUE;
}
else
return FALSE;
{
iter->stamp = 0;
return FALSE;
}
}
static gboolean
@ -646,7 +649,10 @@ gtk_tree_store_iter_children (GtkTreeModel *tree_model,
return TRUE;
}
else
return FALSE;
{
iter->stamp = 0;
return FALSE;
}
}
static gboolean
@ -708,7 +714,10 @@ gtk_tree_store_iter_nth_child (GtkTreeModel *tree_model,
return TRUE;
}
else
return FALSE;
{
iter->stamp = 0;
return FALSE;
}
}
static gboolean
@ -733,7 +742,10 @@ gtk_tree_store_iter_parent (GtkTreeModel *tree_model,
return TRUE;
}
else
return FALSE;
{
iter->stamp = 0;
return FALSE;
}
}

View File

@ -850,6 +850,72 @@ list_store_test_move_before_single (void)
g_object_unref (store);
}
/* iter invalidation */
static void
list_store_test_iter_next_invalid (ListStore *fixture,
gconstpointer user_data)
{
GtkTreePath *path;
GtkTreeIter iter;
path = gtk_tree_path_new_from_indices (4, -1);
gtk_tree_model_get_iter (GTK_TREE_MODEL (fixture->store), &iter, path);
gtk_tree_path_free (path);
g_assert (gtk_tree_model_iter_next (GTK_TREE_MODEL (fixture->store),
&iter) == FALSE);
g_assert (gtk_list_store_iter_is_valid (fixture->store, &iter) == FALSE);
g_assert (iter.stamp == 0);
}
static void
list_store_test_iter_children_invalid (ListStore *fixture,
gconstpointer user_data)
{
GtkTreeIter iter, child;
gtk_tree_model_get_iter_first (GTK_TREE_MODEL (fixture->store), &iter);
g_assert (gtk_list_store_iter_is_valid (fixture->store, &iter) == TRUE);
g_assert (gtk_tree_model_iter_children (GTK_TREE_MODEL (fixture->store),
&child, &iter) == FALSE);
g_assert (gtk_list_store_iter_is_valid (fixture->store, &child) == FALSE);
g_assert (child.stamp == 0);
}
static void
list_store_test_iter_nth_child_invalid (ListStore *fixture,
gconstpointer user_data)
{
GtkTreeIter iter, child;
gtk_tree_model_get_iter_first (GTK_TREE_MODEL (fixture->store), &iter);
g_assert (gtk_list_store_iter_is_valid (fixture->store, &iter) == TRUE);
g_assert (gtk_tree_model_iter_nth_child (GTK_TREE_MODEL (fixture->store),
&child, &iter, 0) == FALSE);
g_assert (gtk_list_store_iter_is_valid (fixture->store, &child) == FALSE);
g_assert (child.stamp == 0);
}
static void
list_store_test_iter_parent_invalid (ListStore *fixture,
gconstpointer user_data)
{
GtkTreeIter iter, child;
gtk_tree_model_get_iter_first (GTK_TREE_MODEL (fixture->store), &child);
g_assert (gtk_list_store_iter_is_valid (fixture->store, &child) == TRUE);
g_assert (gtk_tree_model_iter_parent (GTK_TREE_MODEL (fixture->store),
&iter, &child) == FALSE);
g_assert (gtk_list_store_iter_is_valid (fixture->store, &iter) == FALSE);
g_assert (iter.stamp == 0);
}
/* main */
int
@ -958,5 +1024,19 @@ main (int argc,
g_test_add_func ("/list-store/move-before-single",
list_store_test_move_before_single);
/* iter invalidation */
g_test_add ("/list-store/iter-next-invalid", ListStore, NULL,
list_store_setup, list_store_test_iter_next_invalid,
list_store_teardown);
g_test_add ("/list-store/iter-children-invalid", ListStore, NULL,
list_store_setup, list_store_test_iter_children_invalid,
list_store_teardown);
g_test_add ("/list-store/iter-nth-child-invalid", ListStore, NULL,
list_store_setup, list_store_test_iter_nth_child_invalid,
list_store_teardown);
g_test_add ("/list-store/iter-parent-invalid", ListStore, NULL,
list_store_setup, list_store_test_iter_parent_invalid,
list_store_teardown);
return g_test_run ();
}

View File

@ -853,6 +853,72 @@ tree_store_test_move_before_single (void)
g_object_unref (store);
}
/* iter invalidation */
static void
tree_store_test_iter_next_invalid (TreeStore *fixture,
gconstpointer user_data)
{
GtkTreePath *path;
GtkTreeIter iter;
path = gtk_tree_path_new_from_indices (4, -1);
gtk_tree_model_get_iter (GTK_TREE_MODEL (fixture->store), &iter, path);
gtk_tree_path_free (path);
g_assert (gtk_tree_model_iter_next (GTK_TREE_MODEL (fixture->store),
&iter) == FALSE);
g_assert (gtk_tree_store_iter_is_valid (fixture->store, &iter) == FALSE);
g_assert (iter.stamp == 0);
}
static void
tree_store_test_iter_children_invalid (TreeStore *fixture,
gconstpointer user_data)
{
GtkTreeIter iter, child;
gtk_tree_model_get_iter_first (GTK_TREE_MODEL (fixture->store), &iter);
g_assert (gtk_tree_store_iter_is_valid (fixture->store, &iter) == TRUE);
g_assert (gtk_tree_model_iter_children (GTK_TREE_MODEL (fixture->store),
&child, &iter) == FALSE);
g_assert (gtk_tree_store_iter_is_valid (fixture->store, &child) == FALSE);
g_assert (child.stamp == 0);
}
static void
tree_store_test_iter_nth_child_invalid (TreeStore *fixture,
gconstpointer user_data)
{
GtkTreeIter iter, child;
gtk_tree_model_get_iter_first (GTK_TREE_MODEL (fixture->store), &iter);
g_assert (gtk_tree_store_iter_is_valid (fixture->store, &iter) == TRUE);
g_assert (gtk_tree_model_iter_nth_child (GTK_TREE_MODEL (fixture->store),
&child, &iter, 0) == FALSE);
g_assert (gtk_tree_store_iter_is_valid (fixture->store, &child) == FALSE);
g_assert (child.stamp == 0);
}
static void
tree_store_test_iter_parent_invalid (TreeStore *fixture,
gconstpointer user_data)
{
GtkTreeIter iter, child;
gtk_tree_model_get_iter_first (GTK_TREE_MODEL (fixture->store), &child);
g_assert (gtk_tree_store_iter_is_valid (fixture->store, &child) == TRUE);
g_assert (gtk_tree_model_iter_parent (GTK_TREE_MODEL (fixture->store),
&iter, &child) == FALSE);
g_assert (gtk_tree_store_iter_is_valid (fixture->store, &iter) == FALSE);
g_assert (iter.stamp == 0);
}
/* main */
int
@ -961,5 +1027,19 @@ main (int argc,
g_test_add_func ("/tree-store/move-before-single",
tree_store_test_move_before_single);
/* iter invalidation */
g_test_add ("/tree-store/iter-next-invalid", TreeStore, NULL,
tree_store_setup, tree_store_test_iter_next_invalid,
tree_store_teardown);
g_test_add ("/tree-store/iter-children-invalid", TreeStore, NULL,
tree_store_setup, tree_store_test_iter_children_invalid,
tree_store_teardown);
g_test_add ("/tree-store/iter-nth-child-invalid", TreeStore, NULL,
tree_store_setup, tree_store_test_iter_nth_child_invalid,
tree_store_teardown);
g_test_add ("/tree-store/iter-parent-invalid", TreeStore, NULL,
tree_store_setup, tree_store_test_iter_parent_invalid,
tree_store_teardown);
return g_test_run ();
}