1 /* GtkRBTree tests.
2 *
3 * Copyright (C) 2011, Red Hat, Inc.
4 * Authors: Benjamin Otte <otte@gnome.org>
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20 #include <locale.h>
21
22 #include <gtk/gtk.h>
23
24 static GQuark number_quark;
25 static GQuark changes_quark;
26
27 static guint
get(GListModel * model,guint position)28 get (GListModel *model,
29 guint position)
30 {
31 GObject *object = g_list_model_get_item (model, position);
32 guint number;
33 g_assert_nonnull (object);
34 number = GPOINTER_TO_UINT (g_object_get_qdata (object, number_quark));
35 g_object_unref (object);
36 return number;
37 }
38
39 static char *
model_to_string(GListModel * model)40 model_to_string (GListModel *model)
41 {
42 GString *string = g_string_new (NULL);
43 guint i;
44
45 for (i = 0; i < g_list_model_get_n_items (model); i++)
46 {
47 if (i > 0)
48 g_string_append (string, " ");
49 g_string_append_printf (string, "%u", get (model, i));
50 }
51
52 return g_string_free (string, FALSE);
53 }
54
55 static GListStore *
56 new_store (guint start,
57 guint end,
58 guint step);
59
60 static void
splice(GListStore * store,guint pos,guint removed,guint * numbers,guint added)61 splice (GListStore *store,
62 guint pos,
63 guint removed,
64 guint *numbers,
65 guint added)
66 {
67 GObject **objects = g_newa (GObject *, added);
68 guint i;
69
70 for (i = 0; i < added; i++)
71 {
72 /* 0 cannot be differentiated from NULL, so don't use it */
73 g_assert_cmpint (numbers[i], !=, 0);
74 objects[i] = g_object_new (G_TYPE_OBJECT, NULL);
75 g_object_set_qdata (objects[i], number_quark, GUINT_TO_POINTER (numbers[i]));
76 }
77
78 g_list_store_splice (store, pos, removed, (gpointer *) objects, added);
79
80 for (i = 0; i < added; i++)
81 g_object_unref (objects[i]);
82 }
83
84 static void
insert(GListStore * store,guint pos,guint number)85 insert (GListStore *store,
86 guint pos,
87 guint number)
88 {
89 GObject *object;
90
91 /* 0 cannot be differentiated from NULL, so don't use it */
92 g_assert_cmpint (number, !=, 0);
93
94 object = g_object_new (G_TYPE_OBJECT, NULL);
95 g_object_set_qdata (object, number_quark, GUINT_TO_POINTER (number));
96 g_list_store_insert (store, pos, object);
97 g_object_unref (object);
98 }
99
100 static void
add(GListStore * store,guint number)101 add (GListStore *store,
102 guint number)
103 {
104 GObject *object;
105
106 /* 0 cannot be differentiated from NULL, so don't use it */
107 g_assert_cmpint (number, !=, 0);
108
109 object = g_object_new (G_TYPE_OBJECT, NULL);
110 g_object_set_qdata (object, number_quark, GUINT_TO_POINTER (number));
111 g_list_store_append (store, object);
112 g_object_unref (object);
113 }
114
115 static GListStore *
add_store(GListStore * store,guint start,guint end,guint step)116 add_store (GListStore *store,
117 guint start,
118 guint end,
119 guint step)
120 {
121 GListStore *child;
122
123 child = new_store (start, end, step);
124 g_list_store_append (store, child);
125 g_object_unref (child);
126
127 return child;
128 }
129
130 #define assert_model(model, expected) G_STMT_START{ \
131 char *s = model_to_string (G_LIST_MODEL (model)); \
132 if (!g_str_equal (s, expected)) \
133 g_assertion_message_cmpstr (G_LOG_DOMAIN, __FILE__, __LINE__, G_STRFUNC, \
134 #model " == " #expected, s, "==", expected); \
135 g_free (s); \
136 }G_STMT_END
137
138 #define assert_changes(model, expected) G_STMT_START{ \
139 GString *changes = g_object_get_qdata (G_OBJECT (model), changes_quark); \
140 if (!g_str_equal (changes->str, expected)) \
141 g_assertion_message_cmpstr (G_LOG_DOMAIN, __FILE__, __LINE__, G_STRFUNC, \
142 #model " == " #expected, changes->str, "==", expected); \
143 g_string_set_size (changes, 0); \
144 }G_STMT_END
145
146 static GListStore *
new_empty_store(void)147 new_empty_store (void)
148 {
149 return g_list_store_new (G_TYPE_OBJECT);
150 }
151
152 static GListStore *
new_store(guint start,guint end,guint step)153 new_store (guint start,
154 guint end,
155 guint step)
156 {
157 GListStore *store = new_empty_store ();
158 guint i;
159
160 for (i = start; i <= end; i += step)
161 add (store, i);
162
163 return store;
164 }
165
166 static void
items_changed(GListModel * model,guint position,guint removed,guint added,GString * changes)167 items_changed (GListModel *model,
168 guint position,
169 guint removed,
170 guint added,
171 GString *changes)
172 {
173 g_assert_true (removed != 0 || added != 0);
174
175 if (changes->len)
176 g_string_append (changes, ", ");
177
178 if (removed == 1 && added == 0)
179 {
180 g_string_append_printf (changes, "-%u", position);
181 }
182 else if (removed == 0 && added == 1)
183 {
184 g_string_append_printf (changes, "+%u", position);
185 }
186 else
187 {
188 g_string_append_printf (changes, "%u", position);
189 if (removed > 0)
190 g_string_append_printf (changes, "-%u", removed);
191 if (added > 0)
192 g_string_append_printf (changes, "+%u", added);
193 }
194 }
195
196 static void
free_changes(gpointer data)197 free_changes (gpointer data)
198 {
199 GString *changes = data;
200
201 /* all changes must have been checked via assert_changes() before */
202 g_assert_cmpstr (changes->str, ==, "");
203
204 g_string_free (changes, TRUE);
205 }
206
207 static GtkFlattenListModel *
new_model(GListStore * store)208 new_model (GListStore *store)
209 {
210 GtkFlattenListModel *result;
211 GString *changes;
212
213 if (store)
214 g_object_ref (store);
215 result = gtk_flatten_list_model_new (G_LIST_MODEL (store));
216 changes = g_string_new ("");
217 g_object_set_qdata_full (G_OBJECT(result), changes_quark, changes, free_changes);
218 g_signal_connect (result, "items-changed", G_CALLBACK (items_changed), changes);
219
220 return result;
221 }
222
223 static void
test_create_empty(void)224 test_create_empty (void)
225 {
226 GtkFlattenListModel *flat;
227
228 flat = new_model (NULL);
229 assert_model (flat, "");
230 assert_changes (flat, "");
231
232 g_object_unref (flat);
233 }
234
235 static void
test_create(void)236 test_create (void)
237 {
238 GtkFlattenListModel *flat;
239 GListStore *model;
240
241 model = g_list_store_new (G_TYPE_LIST_MODEL);
242 add_store (model, 1, 3, 1);
243 add_store (model, 4, 4, 1);
244 add_store (model, 5, 7, 1);
245 add_store (model, 8, 10, 1);
246 flat = new_model (model);
247 assert_model (flat, "1 2 3 4 5 6 7 8 9 10");
248 assert_changes (flat, "");
249
250 g_object_unref (model);
251 assert_model (flat, "1 2 3 4 5 6 7 8 9 10");
252 assert_changes (flat, "");
253
254 g_object_unref (flat);
255 }
256
257 static void
test_model_add(void)258 test_model_add (void)
259 {
260 GtkFlattenListModel *flat;
261 GListStore *model;
262
263 model = g_list_store_new (G_TYPE_LIST_MODEL);
264 flat = new_model (model);
265 assert_model (flat, "");
266 assert_changes (flat, "");
267
268 add_store (model, 1, 3, 1);
269 add_store (model, 4, 4, 1);
270 add_store (model, 5, 7, 1);
271 add_store (model, 8, 10, 1);
272
273 assert_model (flat, "1 2 3 4 5 6 7 8 9 10");
274 assert_changes (flat, "0+3, +3, 4+3, 7+3");
275
276 g_object_unref (model);
277 g_object_unref (flat);
278 }
279
280 static void
test_submodel_add(void)281 test_submodel_add (void)
282 {
283 GtkFlattenListModel *flat;
284 GListStore *model, *store[4];
285
286 model = g_list_store_new (G_TYPE_LIST_MODEL);
287 flat = new_model (model);
288 assert_model (flat, "");
289 assert_changes (flat, "");
290
291 store[0] = add_store (model, 2, 3, 1);
292 store[1] = add_store (model, 4, 4, 1);
293 store[2] = add_store (model, 5, 4, 1);
294 store[3] = add_store (model, 8, 8, 1);
295 assert_model (flat, "2 3 4 8");
296 assert_changes (flat, "0+2, +2, +3");
297
298 insert (store[0], 0, 1);
299 splice (store[2], 0, 0, (guint[3]) { 5, 6, 7 }, 3);
300 splice (store[3], 1, 0, (guint[2]) { 9, 10 }, 2);
301 assert_model (flat, "1 2 3 4 5 6 7 8 9 10");
302 assert_changes (flat, "+0, 4+3, 8+2");
303
304 g_object_unref (model);
305 g_object_unref (flat);
306 }
307
308 static void
test_submodel_add2(void)309 test_submodel_add2 (void)
310 {
311 GtkFlattenListModel *flat;
312 GListStore *model, *store[3];
313
314 model = g_list_store_new (G_TYPE_LIST_MODEL);
315 flat = new_model (model);
316 assert_model (flat, "");
317 assert_changes (flat, "");
318
319 store[0] = add_store (model, 1, 0, 0);
320 store[1] = add_store (model, 1, 0, 0);
321 store[2] = add_store (model, 1, 0, 0);
322
323 assert_model (flat, "");
324 assert_changes (flat, "");
325
326 add (store[0], 1);
327 assert_model (flat, "1");
328 assert_changes (flat, "+0");
329
330 add (store[1], 3);
331 assert_model (flat, "1 3");
332 assert_changes (flat, "+1");
333
334 add (store[0], 2);
335 assert_model (flat, "1 2 3");
336 assert_changes (flat, "+1");
337
338 add (store[1], 4);
339 assert_model (flat, "1 2 3 4");
340 assert_changes (flat, "+3");
341
342 g_object_unref (model);
343 g_object_unref (flat);
344 }
345
346 static void
test_model_remove(void)347 test_model_remove (void)
348 {
349 GtkFlattenListModel *flat;
350 GListStore *model;
351
352 model = g_list_store_new (G_TYPE_LIST_MODEL);
353 add_store (model, 1, 3, 1);
354 add_store (model, 4, 4, 1);
355 add_store (model, 5, 7, 1);
356 add_store (model, 8, 10, 1);
357 flat = new_model (model);
358 assert_model (flat, "1 2 3 4 5 6 7 8 9 10");
359 assert_changes (flat, "");
360
361 splice (model, 1, 2, NULL, 0);
362 g_list_store_remove (model, 1);
363 g_list_store_remove (model, 0);
364 g_object_unref (model);
365 assert_model (flat, "");
366 assert_changes (flat, "3-4, 3-3, 0-3");
367
368 g_object_unref (flat);
369 }
370
371 static void
test_submodel_remove(void)372 test_submodel_remove (void)
373 {
374 GtkFlattenListModel *flat;
375 GListStore *model, *store[4];
376
377 model = g_list_store_new (G_TYPE_LIST_MODEL);
378 store[0] = add_store (model, 1, 3, 1);
379 store[1] = add_store (model, 4, 4, 1);
380 store[2] = add_store (model, 5, 7, 1);
381 store[3] = add_store (model, 8, 10, 1);
382 flat = new_model (model);
383 assert_model (flat, "1 2 3 4 5 6 7 8 9 10");
384 assert_changes (flat, "");
385
386 g_list_store_remove (store[0], 0);
387 splice (store[2], 0, 3, NULL, 0);
388 splice (store[3], 1, 2, NULL, 0);
389 g_object_unref (model);
390
391 assert_model (flat, "2 3 4 8");
392 assert_changes (flat, "-0, 3-3, 4-2");
393
394 g_object_unref (flat);
395 }
396
397 int
main(int argc,char * argv[])398 main (int argc, char *argv[])
399 {
400 (g_test_init) (&argc, &argv, NULL);
401 setlocale (LC_ALL, "C");
402
403 number_quark = g_quark_from_static_string ("Hell and fire was spawned to be released.");
404 changes_quark = g_quark_from_static_string ("What did I see? Can I believe what I saw?");
405
406 g_test_add_func ("/flattenlistmodel/create_empty", test_create_empty);
407 g_test_add_func ("/flattenlistmodel/create", test_create);
408 g_test_add_func ("/flattenlistmodel/model/add", test_model_add);
409 #if GLIB_CHECK_VERSION (2, 58, 0) /* g_list_store_splice() is broken before 2.58 */
410 g_test_add_func ("/flattenlistmodel/submodel/add", test_submodel_add);
411 g_test_add_func ("/flattenlistmodel/submodel/add2", test_submodel_add2);
412 g_test_add_func ("/flattenlistmodel/model/remove", test_model_remove);
413 g_test_add_func ("/flattenlistmodel/submodel/remove", test_submodel_remove);
414 #endif
415
416 return g_test_run ();
417 }
418