2018-09-17 01:56:41 +00:00
|
|
|
/* GtkRBTree tests.
|
|
|
|
*
|
|
|
|
* Copyright (C) 2011, Red Hat, Inc.
|
|
|
|
* Authors: Benjamin Otte <otte@gnome.org>
|
|
|
|
*
|
|
|
|
* This library is free software; you can redistribute it and/or
|
|
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
|
|
* License as published by the Free Software Foundation; either
|
|
|
|
* version 2 of the License, or (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This library is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
* 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, see <http://www.gnu.org/licenses/>.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <locale.h>
|
|
|
|
|
|
|
|
#include <gtk/gtk.h>
|
|
|
|
|
|
|
|
static GQuark number_quark;
|
|
|
|
static GQuark changes_quark;
|
|
|
|
|
|
|
|
static guint
|
|
|
|
get (GListModel *model,
|
|
|
|
guint position)
|
|
|
|
{
|
|
|
|
GObject *object = g_list_model_get_item (model, position);
|
2019-12-04 12:51:04 +00:00
|
|
|
guint number;
|
2018-09-17 01:56:41 +00:00
|
|
|
g_assert (object != NULL);
|
2019-12-04 12:51:04 +00:00
|
|
|
number = GPOINTER_TO_UINT (g_object_get_qdata (object, number_quark));
|
|
|
|
g_object_unref (object);
|
|
|
|
return number;
|
2018-09-17 01:56:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static char *
|
|
|
|
model_to_string (GListModel *model)
|
|
|
|
{
|
|
|
|
GString *string = g_string_new (NULL);
|
|
|
|
guint i;
|
|
|
|
|
|
|
|
for (i = 0; i < g_list_model_get_n_items (model); i++)
|
|
|
|
{
|
|
|
|
if (i > 0)
|
|
|
|
g_string_append (string, " ");
|
|
|
|
g_string_append_printf (string, "%u", get (model, i));
|
|
|
|
}
|
|
|
|
|
|
|
|
return g_string_free (string, FALSE);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
splice (GListStore *store,
|
|
|
|
guint pos,
|
|
|
|
guint removed,
|
|
|
|
guint *numbers,
|
|
|
|
guint added)
|
|
|
|
{
|
2018-10-09 08:22:28 +00:00
|
|
|
GObject **objects = g_newa (GObject *, added);
|
2018-09-17 01:56:41 +00:00
|
|
|
guint i;
|
|
|
|
|
|
|
|
for (i = 0; i < added; i++)
|
|
|
|
{
|
|
|
|
/* 0 cannot be differentiated from NULL, so don't use it */
|
|
|
|
g_assert (numbers[i] != 0);
|
|
|
|
objects[i] = g_object_new (G_TYPE_OBJECT, NULL);
|
|
|
|
g_object_set_qdata (objects[i], number_quark, GUINT_TO_POINTER (numbers[i]));
|
|
|
|
}
|
|
|
|
|
|
|
|
g_list_store_splice (store, pos, removed, (gpointer *) objects, added);
|
|
|
|
|
|
|
|
for (i = 0; i < added; i++)
|
|
|
|
g_object_unref (objects[i]);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
add (GListStore *store,
|
|
|
|
guint number)
|
|
|
|
{
|
|
|
|
GObject *object;
|
|
|
|
|
|
|
|
/* 0 cannot be differentiated from NULL, so don't use it */
|
|
|
|
g_assert (number != 0);
|
|
|
|
|
|
|
|
object = g_object_new (G_TYPE_OBJECT, NULL);
|
|
|
|
g_object_set_qdata (object, number_quark, GUINT_TO_POINTER (number));
|
|
|
|
g_list_store_append (store, object);
|
|
|
|
g_object_unref (object);
|
|
|
|
}
|
|
|
|
|
2020-07-24 22:32:01 +00:00
|
|
|
static void
|
|
|
|
insert (GListStore *store,
|
|
|
|
guint position,
|
|
|
|
guint number)
|
|
|
|
{
|
|
|
|
GObject *object;
|
|
|
|
|
|
|
|
/* 0 cannot be differentiated from NULL, so don't use it */
|
|
|
|
g_assert (number != 0);
|
|
|
|
|
|
|
|
object = g_object_new (G_TYPE_OBJECT, NULL);
|
|
|
|
g_object_set_qdata (object, number_quark, GUINT_TO_POINTER (number));
|
|
|
|
g_list_store_insert (store, position, object);
|
|
|
|
g_object_unref (object);
|
|
|
|
}
|
|
|
|
|
2018-09-17 01:56:41 +00:00
|
|
|
#define assert_model(model, expected) G_STMT_START{ \
|
|
|
|
char *s = model_to_string (G_LIST_MODEL (model)); \
|
|
|
|
if (!g_str_equal (s, expected)) \
|
|
|
|
g_assertion_message_cmpstr (G_LOG_DOMAIN, __FILE__, __LINE__, G_STRFUNC, \
|
|
|
|
#model " == " #expected, s, "==", expected); \
|
|
|
|
g_free (s); \
|
|
|
|
}G_STMT_END
|
|
|
|
|
|
|
|
#define assert_changes(model, expected) G_STMT_START{ \
|
|
|
|
GString *changes = g_object_get_qdata (G_OBJECT (model), changes_quark); \
|
|
|
|
if (!g_str_equal (changes->str, expected)) \
|
|
|
|
g_assertion_message_cmpstr (G_LOG_DOMAIN, __FILE__, __LINE__, G_STRFUNC, \
|
|
|
|
#model " == " #expected, changes->str, "==", expected); \
|
|
|
|
g_string_set_size (changes, 0); \
|
|
|
|
}G_STMT_END
|
|
|
|
|
2020-07-24 22:32:01 +00:00
|
|
|
#define ignore_changes(model) G_STMT_START{ \
|
|
|
|
GString *changes = g_object_get_qdata (G_OBJECT (model), changes_quark); \
|
|
|
|
g_string_set_size (changes, 0); \
|
|
|
|
}G_STMT_END
|
|
|
|
|
2018-09-17 01:56:41 +00:00
|
|
|
static GListStore *
|
|
|
|
new_empty_store (void)
|
|
|
|
{
|
|
|
|
return g_list_store_new (G_TYPE_OBJECT);
|
|
|
|
}
|
|
|
|
|
|
|
|
static GListStore *
|
|
|
|
new_store (guint *numbers)
|
|
|
|
{
|
|
|
|
GListStore *store = new_empty_store ();
|
|
|
|
guint i;
|
|
|
|
|
|
|
|
for (i = 0; numbers[i] != 0; i++)
|
|
|
|
add (store, numbers[i]);
|
|
|
|
|
|
|
|
return store;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
items_changed (GListModel *model,
|
|
|
|
guint position,
|
|
|
|
guint removed,
|
|
|
|
guint added,
|
|
|
|
GString *changes)
|
|
|
|
{
|
|
|
|
g_assert (removed != 0 || added != 0);
|
|
|
|
|
|
|
|
if (changes->len)
|
|
|
|
g_string_append (changes, ", ");
|
|
|
|
|
|
|
|
if (removed == 1 && added == 0)
|
|
|
|
{
|
|
|
|
g_string_append_printf (changes, "-%u", position);
|
|
|
|
}
|
|
|
|
else if (removed == 0 && added == 1)
|
|
|
|
{
|
|
|
|
g_string_append_printf (changes, "+%u", position);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
g_string_append_printf (changes, "%u", position);
|
|
|
|
if (removed > 0)
|
|
|
|
g_string_append_printf (changes, "-%u", removed);
|
|
|
|
if (added > 0)
|
|
|
|
g_string_append_printf (changes, "+%u", added);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
free_changes (gpointer data)
|
|
|
|
{
|
|
|
|
GString *changes = data;
|
|
|
|
|
|
|
|
/* all changes must have been checked via assert_changes() before */
|
|
|
|
g_assert_cmpstr (changes->str, ==, "");
|
|
|
|
|
|
|
|
g_string_free (changes, TRUE);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
compare_modulo (gconstpointer first,
|
|
|
|
gconstpointer second,
|
|
|
|
gpointer modulo)
|
|
|
|
{
|
|
|
|
guint mod = GPOINTER_TO_UINT (modulo);
|
|
|
|
|
|
|
|
return (GPOINTER_TO_UINT (g_object_get_qdata (G_OBJECT (first), number_quark)) % mod)
|
|
|
|
- (GPOINTER_TO_UINT (g_object_get_qdata (G_OBJECT (second), number_quark)) % mod);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
compare (gconstpointer first,
|
|
|
|
gconstpointer second,
|
|
|
|
gpointer unused)
|
|
|
|
{
|
|
|
|
return GPOINTER_TO_UINT (g_object_get_qdata (G_OBJECT (first), number_quark))
|
|
|
|
- GPOINTER_TO_UINT (g_object_get_qdata (G_OBJECT (second), number_quark));
|
|
|
|
}
|
|
|
|
|
|
|
|
static GtkSortListModel *
|
|
|
|
new_model (gpointer model)
|
|
|
|
{
|
|
|
|
GtkSortListModel *result;
|
|
|
|
GString *changes;
|
|
|
|
|
|
|
|
g_assert (model == NULL || G_IS_LIST_MODEL (model));
|
|
|
|
|
|
|
|
if (model)
|
2019-12-03 04:44:22 +00:00
|
|
|
{
|
|
|
|
GtkSorter *sorter;
|
|
|
|
|
|
|
|
sorter = gtk_custom_sorter_new (compare, NULL, NULL);
|
|
|
|
result = gtk_sort_list_model_new (model, sorter);
|
|
|
|
g_object_unref (sorter);
|
|
|
|
}
|
2018-09-17 01:56:41 +00:00
|
|
|
else
|
2020-07-04 19:47:48 +00:00
|
|
|
result = gtk_sort_list_model_new (NULL, NULL);
|
2018-09-17 01:56:41 +00:00
|
|
|
|
|
|
|
changes = g_string_new ("");
|
|
|
|
g_object_set_qdata_full (G_OBJECT(result), changes_quark, changes, free_changes);
|
|
|
|
g_signal_connect (result, "items-changed", G_CALLBACK (items_changed), changes);
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
test_create_empty (void)
|
|
|
|
{
|
|
|
|
GtkSortListModel *sort;
|
|
|
|
|
|
|
|
sort = new_model (NULL);
|
|
|
|
assert_model (sort, "");
|
|
|
|
assert_changes (sort, "");
|
|
|
|
|
|
|
|
g_object_unref (sort);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
test_create (void)
|
|
|
|
{
|
|
|
|
GtkSortListModel *sort;
|
|
|
|
GListStore *store;
|
|
|
|
|
|
|
|
store = new_store ((guint[]) { 4, 8, 2, 6, 10, 0 });
|
|
|
|
sort = new_model (store);
|
|
|
|
assert_model (sort, "2 4 6 8 10");
|
|
|
|
assert_changes (sort, "");
|
|
|
|
|
|
|
|
g_object_unref (store);
|
|
|
|
assert_model (sort, "2 4 6 8 10");
|
|
|
|
assert_changes (sort, "");
|
|
|
|
|
|
|
|
g_object_unref (sort);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
test_set_model (void)
|
|
|
|
{
|
|
|
|
GtkSortListModel *sort;
|
|
|
|
GListStore *store;
|
|
|
|
|
|
|
|
sort = new_model (NULL);
|
|
|
|
assert_model (sort, "");
|
|
|
|
assert_changes (sort, "");
|
|
|
|
|
|
|
|
store = new_store ((guint[]) { 4, 8, 2, 6, 10, 0 });
|
|
|
|
gtk_sort_list_model_set_model (sort, G_LIST_MODEL (store));
|
|
|
|
assert_model (sort, "4 8 2 6 10");
|
|
|
|
assert_changes (sort, "0+5");
|
|
|
|
|
|
|
|
gtk_sort_list_model_set_model (sort, NULL);
|
|
|
|
assert_model (sort, "");
|
|
|
|
assert_changes (sort, "0-5");
|
|
|
|
|
|
|
|
g_object_unref (sort);
|
|
|
|
|
|
|
|
|
|
|
|
sort = new_model (store);
|
|
|
|
assert_model (sort, "2 4 6 8 10");
|
|
|
|
assert_changes (sort, "");
|
|
|
|
|
|
|
|
gtk_sort_list_model_set_model (sort, NULL);
|
|
|
|
assert_model (sort, "");
|
|
|
|
assert_changes (sort, "0-5");
|
|
|
|
|
|
|
|
gtk_sort_list_model_set_model (sort, G_LIST_MODEL (store));
|
|
|
|
assert_model (sort, "2 4 6 8 10");
|
|
|
|
assert_changes (sort, "0+5");
|
|
|
|
|
|
|
|
g_object_unref (store);
|
|
|
|
g_object_unref (sort);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2019-12-03 04:44:22 +00:00
|
|
|
test_set_sorter (void)
|
2018-09-17 01:56:41 +00:00
|
|
|
{
|
|
|
|
GtkSortListModel *sort;
|
2019-12-03 04:44:22 +00:00
|
|
|
GtkSorter *sorter;
|
2018-09-17 01:56:41 +00:00
|
|
|
GListStore *store;
|
|
|
|
|
|
|
|
store = new_store ((guint[]) { 4, 8, 2, 6, 10, 0 });
|
|
|
|
sort = new_model (store);
|
|
|
|
assert_model (sort, "2 4 6 8 10");
|
|
|
|
assert_changes (sort, "");
|
|
|
|
|
2019-12-03 04:44:22 +00:00
|
|
|
sorter = gtk_custom_sorter_new (compare_modulo, GUINT_TO_POINTER (5), NULL);
|
|
|
|
gtk_sort_list_model_set_sorter (sort, sorter);
|
|
|
|
g_object_unref (sorter);
|
2018-09-17 01:56:41 +00:00
|
|
|
assert_model (sort, "10 6 2 8 4");
|
|
|
|
assert_changes (sort, "0-5+5");
|
|
|
|
|
2019-12-03 04:44:22 +00:00
|
|
|
gtk_sort_list_model_set_sorter (sort, NULL);
|
2018-09-17 01:56:41 +00:00
|
|
|
assert_model (sort, "4 8 2 6 10");
|
|
|
|
assert_changes (sort, "0-5+5");
|
|
|
|
|
2019-12-03 04:44:22 +00:00
|
|
|
sorter = gtk_custom_sorter_new (compare, NULL, NULL);
|
|
|
|
gtk_sort_list_model_set_sorter (sort, sorter);
|
|
|
|
g_object_unref (sorter);
|
2018-09-17 01:56:41 +00:00
|
|
|
assert_model (sort, "2 4 6 8 10");
|
sortlistmodel: Split the SortItem into 2 arrays
Instead of one item keeping the item + its position and sorting that
list, keep the items in 1 array and put the positions into a 2nd array.
This is generally slower while sorting, but allows multiple improvements:
1. We can replace items with keys
This allows avoiding multiple slow lookups when using complex
comparisons
2. We can keep multiple position arrays
This allows doing a sorting in the background without actually
emitting items-changed() until the array is completely sorted.
3. The main list tracks the items in the original model
So only a single memmove() is necessary there, while the old version
had to upgrade the position in every item.
Benchmarks:
sorting a model of simple strings
old new
256,000 items 256ms 268ms
512,000 items 569ms 638ms
sorting a model of file trees, directories first, by size
old new
64,000 items 350ms 364ms
128,000 items 667ms 691ms
removing half the model
old new
512,000 items 24ms 15ms
1,024,000 items 49ms 25ms
2020-07-21 01:09:10 +00:00
|
|
|
assert_changes (sort, "0-4+4");
|
2018-09-17 01:56:41 +00:00
|
|
|
|
|
|
|
g_object_unref (store);
|
|
|
|
g_object_unref (sort);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
test_add_items (void)
|
|
|
|
{
|
|
|
|
GtkSortListModel *sort;
|
|
|
|
GListStore *store;
|
|
|
|
|
|
|
|
/* add beginning */
|
|
|
|
store = new_store ((guint[]) { 51, 99, 100, 49, 50, 0 });
|
|
|
|
sort = new_model (store);
|
|
|
|
assert_model (sort, "49 50 51 99 100");
|
|
|
|
assert_changes (sort, "");
|
|
|
|
splice (store, 4, 0, (guint[]) { 1, 2 }, 2);
|
|
|
|
assert_model (sort, "1 2 49 50 51 99 100");
|
|
|
|
assert_changes (sort, "0+2");
|
|
|
|
g_object_unref (store);
|
|
|
|
g_object_unref (sort);
|
|
|
|
|
|
|
|
/* add middle */
|
|
|
|
store = new_store ((guint[]) { 99, 100, 1, 2, 0 });
|
|
|
|
sort = new_model (store);
|
|
|
|
assert_model (sort, "1 2 99 100");
|
|
|
|
assert_changes (sort, "");
|
|
|
|
splice (store, 2, 0, (guint[]) { 49, 50, 51 }, 3);
|
|
|
|
assert_model (sort, "1 2 49 50 51 99 100");
|
|
|
|
assert_changes (sort, "2+3");
|
|
|
|
g_object_unref (store);
|
|
|
|
g_object_unref (sort);
|
|
|
|
|
|
|
|
/* add end */
|
|
|
|
store = new_store ((guint[]) { 51, 49, 1, 2, 50, 0 });
|
|
|
|
sort = new_model (store);
|
|
|
|
assert_model (sort, "1 2 49 50 51");
|
|
|
|
assert_changes (sort, "");
|
|
|
|
splice (store, 1, 0, (guint[]) { 99, 100 }, 2);
|
|
|
|
assert_model (sort, "1 2 49 50 51 99 100");
|
|
|
|
assert_changes (sort, "5+2");
|
|
|
|
g_object_unref (store);
|
|
|
|
g_object_unref (sort);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
test_remove_items (void)
|
|
|
|
{
|
|
|
|
GtkSortListModel *sort;
|
|
|
|
GListStore *store;
|
|
|
|
|
|
|
|
/* remove beginning */
|
|
|
|
store = new_store ((guint[]) { 51, 99, 100, 49, 1, 2, 50, 0 });
|
|
|
|
sort = new_model (store);
|
|
|
|
assert_model (sort, "1 2 49 50 51 99 100");
|
|
|
|
assert_changes (sort, "");
|
|
|
|
splice (store, 4, 2, NULL, 0);
|
|
|
|
assert_model (sort, "49 50 51 99 100");
|
|
|
|
assert_changes (sort, "0-2");
|
|
|
|
g_object_unref (store);
|
|
|
|
g_object_unref (sort);
|
|
|
|
|
|
|
|
/* remove middle */
|
|
|
|
store = new_store ((guint[]) { 99, 100, 51, 49, 50, 1, 2, 0 });
|
|
|
|
sort = new_model (store);
|
|
|
|
assert_model (sort, "1 2 49 50 51 99 100");
|
|
|
|
assert_changes (sort, "");
|
|
|
|
splice (store, 2, 3, NULL, 0);
|
|
|
|
assert_model (sort, "1 2 99 100");
|
|
|
|
assert_changes (sort, "2-3");
|
|
|
|
g_object_unref (store);
|
|
|
|
g_object_unref (sort);
|
|
|
|
|
|
|
|
/* remove end */
|
|
|
|
store = new_store ((guint[]) { 51, 99, 100, 49, 1, 2, 50, 0 });
|
|
|
|
sort = new_model (store);
|
|
|
|
assert_model (sort, "1 2 49 50 51 99 100");
|
|
|
|
assert_changes (sort, "");
|
|
|
|
splice (store, 1, 2, NULL, 0);
|
|
|
|
assert_model (sort, "1 2 49 50 51");
|
|
|
|
assert_changes (sort, "5-2");
|
|
|
|
g_object_unref (store);
|
|
|
|
g_object_unref (sort);
|
|
|
|
}
|
|
|
|
|
2020-07-16 13:16:30 +00:00
|
|
|
static void
|
|
|
|
test_stability (void)
|
|
|
|
{
|
|
|
|
GtkSortListModel *sort;
|
|
|
|
GListStore *store;
|
|
|
|
GtkSorter *sorter;
|
2020-07-24 22:32:01 +00:00
|
|
|
|
2020-07-16 13:16:30 +00:00
|
|
|
store = new_store ((guint[]) { 11, 31, 21, 1, 0 });
|
|
|
|
sort = new_model (store);
|
|
|
|
assert_model (sort, "1 11 21 31");
|
|
|
|
assert_changes (sort, "");
|
|
|
|
|
|
|
|
sorter = gtk_custom_sorter_new (compare_modulo, GUINT_TO_POINTER (5), NULL);
|
|
|
|
gtk_sort_list_model_set_sorter (sort, sorter);
|
|
|
|
g_object_unref (sorter);
|
|
|
|
assert_model (sort, "11 31 21 1");
|
|
|
|
assert_changes (sort, "0-4+4");
|
|
|
|
|
|
|
|
g_object_unref (store);
|
|
|
|
g_object_unref (sort);
|
|
|
|
}
|
|
|
|
|
2020-07-24 22:32:01 +00:00
|
|
|
static GListStore *
|
|
|
|
new_shuffled_store (guint size)
|
|
|
|
{
|
|
|
|
GListStore *store = new_empty_store ();
|
|
|
|
guint i;
|
|
|
|
|
|
|
|
add (store, 1);
|
|
|
|
|
|
|
|
for (i = 1; i < size; i++)
|
|
|
|
insert (store, g_random_int_range (0, i), i + 1);
|
|
|
|
|
|
|
|
return store;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Test that we don't crash when things are removed from the
|
|
|
|
* model while it is incrementally sorting.
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
test_incremental_remove (void)
|
|
|
|
{
|
|
|
|
GListStore *store;
|
|
|
|
GtkSortListModel *model;
|
|
|
|
GtkSorter *sorter;
|
|
|
|
guint i;
|
|
|
|
GListStore *removed;
|
|
|
|
const guint n_items = 100000;
|
|
|
|
|
|
|
|
store = new_shuffled_store (n_items);
|
|
|
|
model = new_model (NULL);
|
|
|
|
gtk_sort_list_model_set_incremental (model, TRUE);
|
|
|
|
|
|
|
|
gtk_sort_list_model_set_model (model, G_LIST_MODEL (store));
|
|
|
|
|
|
|
|
sorter = gtk_custom_sorter_new (compare, NULL, NULL);
|
|
|
|
gtk_sort_list_model_set_sorter (model, sorter);
|
|
|
|
g_object_unref (sorter);
|
|
|
|
|
|
|
|
removed = g_list_store_new (G_TYPE_OBJECT);
|
|
|
|
|
|
|
|
while (gtk_sort_list_model_get_pending (model) != 0)
|
|
|
|
{
|
|
|
|
g_main_context_iteration (NULL, TRUE);
|
|
|
|
|
|
|
|
/* randomly remove items while the sort is ongoing */
|
|
|
|
if (g_list_model_get_n_items (G_LIST_MODEL (removed)) < 100)
|
|
|
|
{
|
|
|
|
guint position;
|
|
|
|
|
|
|
|
position = g_random_int_range (0, g_list_model_get_n_items (G_LIST_MODEL (store)) - 10);
|
|
|
|
for (i = 0; i < 10; i++)
|
|
|
|
{
|
|
|
|
GObject *item = g_list_model_get_item (G_LIST_MODEL (store), position + i);
|
|
|
|
g_list_store_append (removed, item);
|
|
|
|
g_object_unref (item);
|
|
|
|
}
|
|
|
|
g_list_store_splice (store, position, 10, NULL, 0);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
g_assert_cmpuint (gtk_sort_list_model_get_pending (model), ==, 0);
|
|
|
|
|
|
|
|
gtk_sort_list_model_set_incremental (model, FALSE);
|
|
|
|
|
|
|
|
/* add them back */
|
|
|
|
for (i = 0; i < g_list_model_get_n_items (G_LIST_MODEL (removed)); i++)
|
|
|
|
{
|
|
|
|
GObject *item = g_list_model_get_item (G_LIST_MODEL (removed), i);
|
|
|
|
g_list_store_append (store, item);
|
|
|
|
g_object_unref (item);
|
|
|
|
}
|
|
|
|
|
|
|
|
g_assert_cmpuint (g_list_model_get_n_items (G_LIST_MODEL (model)), ==, n_items);
|
|
|
|
|
|
|
|
for (i = 0; i < g_list_model_get_n_items (G_LIST_MODEL (model)); i++)
|
|
|
|
g_assert_cmpuint (i + 1, ==, get (G_LIST_MODEL (model), i));
|
|
|
|
|
|
|
|
ignore_changes (model);
|
|
|
|
|
|
|
|
g_object_unref (store);
|
|
|
|
g_object_unref (model);
|
|
|
|
g_object_unref (removed);
|
|
|
|
}
|
|
|
|
|
2020-07-24 23:28:21 +00:00
|
|
|
static void
|
|
|
|
test_out_of_bounds_access (void)
|
|
|
|
{
|
|
|
|
GtkSortListModel *sort;
|
|
|
|
GListStore *store;
|
|
|
|
gpointer item;
|
|
|
|
|
|
|
|
store = new_store ((guint[]) { 4, 8, 2, 6, 10, 0 });
|
|
|
|
sort = new_model (store);
|
|
|
|
|
|
|
|
item = g_list_model_get_item (G_LIST_MODEL (sort), GTK_INVALID_LIST_POSITION);
|
|
|
|
g_assert_null (item);
|
|
|
|
|
|
|
|
g_object_unref (store);
|
|
|
|
g_object_unref (sort);
|
|
|
|
}
|
|
|
|
|
2018-09-17 01:56:41 +00:00
|
|
|
int
|
|
|
|
main (int argc, char *argv[])
|
|
|
|
{
|
|
|
|
g_test_init (&argc, &argv, NULL);
|
|
|
|
setlocale (LC_ALL, "C");
|
|
|
|
|
|
|
|
number_quark = g_quark_from_static_string ("Hell and fire was spawned to be released.");
|
|
|
|
changes_quark = g_quark_from_static_string ("What did I see? Can I believe what I saw?");
|
|
|
|
|
|
|
|
g_test_add_func ("/sortlistmodel/create_empty", test_create_empty);
|
|
|
|
g_test_add_func ("/sortlistmodel/create", test_create);
|
|
|
|
g_test_add_func ("/sortlistmodel/set-model", test_set_model);
|
2019-12-03 04:44:22 +00:00
|
|
|
g_test_add_func ("/sortlistmodel/set-sorter", test_set_sorter);
|
2018-09-17 02:29:40 +00:00
|
|
|
#if GLIB_CHECK_VERSION (2, 58, 0) /* g_list_store_splice() is broken before 2.58 */
|
2018-09-17 01:56:41 +00:00
|
|
|
g_test_add_func ("/sortlistmodel/add_items", test_add_items);
|
|
|
|
g_test_add_func ("/sortlistmodel/remove_items", test_remove_items);
|
2018-09-17 02:29:40 +00:00
|
|
|
#endif
|
2020-07-16 13:16:30 +00:00
|
|
|
g_test_add_func ("/sortlistmodel/stability", test_stability);
|
2020-07-24 22:32:01 +00:00
|
|
|
g_test_add_func ("/sortlistmodel/incremental/remove", test_incremental_remove);
|
2020-07-24 23:28:21 +00:00
|
|
|
g_test_add_func ("/sortlistmodel/oob-access", test_out_of_bounds_access);
|
2018-09-17 01:56:41 +00:00
|
|
|
|
|
|
|
return g_test_run ();
|
|
|
|
}
|