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
add(GListStore * store,guint number)61 add (GListStore *store,
62 guint number)
63 {
64 GObject *object;
65
66 /* 0 cannot be differentiated from NULL, so don't use it */
67 g_assert_cmpint (number, !=, 0);
68
69 object = g_object_new (G_TYPE_OBJECT, NULL);
70 g_object_set_qdata (object, number_quark, GUINT_TO_POINTER (number));
71 g_list_store_append (store, object);
72 g_object_unref (object);
73 }
74
75 #define assert_model(model, expected) G_STMT_START{ \
76 char *s = model_to_string (G_LIST_MODEL (model)); \
77 if (!g_str_equal (s, expected)) \
78 g_assertion_message_cmpstr (G_LOG_DOMAIN, __FILE__, __LINE__, G_STRFUNC, \
79 #model " == " #expected, s, "==", expected); \
80 g_free (s); \
81 }G_STMT_END
82
83 #define assert_changes(model, expected) G_STMT_START{ \
84 GString *changes = g_object_get_qdata (G_OBJECT (model), changes_quark); \
85 if (!g_str_equal (changes->str, expected)) \
86 g_assertion_message_cmpstr (G_LOG_DOMAIN, __FILE__, __LINE__, G_STRFUNC, \
87 #model " == " #expected, changes->str, "==", expected); \
88 g_string_set_size (changes, 0); \
89 }G_STMT_END
90
91 #define ignore_changes(model) G_STMT_START{ \
92 GString *changes = g_object_get_qdata (G_OBJECT (model), changes_quark); \
93 g_string_set_size (changes, 0); \
94 }G_STMT_END
95
96 static GListStore *
new_empty_store(void)97 new_empty_store (void)
98 {
99 return g_list_store_new (G_TYPE_OBJECT);
100 }
101
102 static GListStore *
new_store(guint start,guint end,guint step)103 new_store (guint start,
104 guint end,
105 guint step)
106 {
107 GListStore *store = new_empty_store ();
108 guint i;
109
110 for (i = start; i <= end; i += step)
111 add (store, i);
112
113 return store;
114 }
115
116 static void
items_changed(GListModel * model,guint position,guint removed,guint added,GString * changes)117 items_changed (GListModel *model,
118 guint position,
119 guint removed,
120 guint added,
121 GString *changes)
122 {
123 g_assert_true (removed != 0 || added != 0);
124
125 if (changes->len)
126 g_string_append (changes, ", ");
127
128 if (removed == 1 && added == 0)
129 {
130 g_string_append_printf (changes, "-%u", position);
131 }
132 else if (removed == 0 && added == 1)
133 {
134 g_string_append_printf (changes, "+%u", position);
135 }
136 else
137 {
138 g_string_append_printf (changes, "%u", position);
139 if (removed > 0)
140 g_string_append_printf (changes, "-%u", removed);
141 if (added > 0)
142 g_string_append_printf (changes, "+%u", added);
143 }
144 }
145
146 static void
free_changes(gpointer data)147 free_changes (gpointer data)
148 {
149 GString *changes = data;
150
151 /* all changes must have been checked via assert_changes() before */
152 g_assert_cmpstr (changes->str, ==, "");
153
154 g_string_free (changes, TRUE);
155 }
156
157 static GtkFilterListModel *
new_model(guint size,GtkCustomFilterFunc filter_func,gpointer data)158 new_model (guint size,
159 GtkCustomFilterFunc filter_func,
160 gpointer data)
161 {
162 GtkFilterListModel *result;
163 GtkFilter *filter;
164 GString *changes;
165
166 if (filter_func)
167 filter = GTK_FILTER (gtk_custom_filter_new (filter_func, data, NULL));
168 else
169 filter = NULL;
170 result = gtk_filter_list_model_new (g_object_ref (G_LIST_MODEL (new_store (1, size, 1))), filter);
171 changes = g_string_new ("");
172 g_object_set_qdata_full (G_OBJECT(result), changes_quark, changes, free_changes);
173 g_signal_connect (result, "items-changed", G_CALLBACK (items_changed), changes);
174
175 return result;
176 }
177
178 static gboolean
is_smaller_than(gpointer item,gpointer data)179 is_smaller_than (gpointer item,
180 gpointer data)
181 {
182 return g_object_get_qdata (item, number_quark) < data;
183 }
184
185 static gboolean
is_larger_than(gpointer item,gpointer data)186 is_larger_than (gpointer item,
187 gpointer data)
188 {
189 return g_object_get_qdata (item, number_quark) > data;
190 }
191
192 static gboolean
is_near(gpointer item,gpointer data)193 is_near (gpointer item,
194 gpointer data)
195 {
196 return ABS (GPOINTER_TO_INT (g_object_get_qdata (item, number_quark)) - GPOINTER_TO_INT (data)) <= 2;
197 }
198
199 static gboolean
is_not_near(gpointer item,gpointer data)200 is_not_near (gpointer item,
201 gpointer data)
202 {
203 return ABS (GPOINTER_TO_INT (g_object_get_qdata (item, number_quark)) - GPOINTER_TO_INT (data)) > 2;
204 }
205
206 static void
test_create(void)207 test_create (void)
208 {
209 GtkFilterListModel *filter;
210
211 filter = new_model (10, NULL, NULL);
212 assert_model (filter, "1 2 3 4 5 6 7 8 9 10");
213 assert_changes (filter, "");
214 g_object_unref (filter);
215
216 filter = new_model (10, is_smaller_than, GUINT_TO_POINTER (20));
217 assert_model (filter, "1 2 3 4 5 6 7 8 9 10");
218 assert_changes (filter, "");
219 g_object_unref (filter);
220
221 filter = new_model (10, is_smaller_than, GUINT_TO_POINTER (7));
222 assert_model (filter, "1 2 3 4 5 6");
223 assert_changes (filter, "");
224 g_object_unref (filter);
225
226 filter = new_model (10, is_smaller_than, GUINT_TO_POINTER (0));
227 assert_model (filter, "");
228 assert_changes (filter, "");
229 g_object_unref (filter);
230 }
231
232 static void
test_empty_set_filter(void)233 test_empty_set_filter (void)
234 {
235 GtkFilterListModel *filter;
236 GtkFilter *custom;
237
238 filter = new_model (10, NULL, NULL);
239 custom = GTK_FILTER (gtk_custom_filter_new (is_smaller_than, GUINT_TO_POINTER (20), NULL));
240 gtk_filter_list_model_set_filter (filter, custom);
241 g_object_unref (custom);
242 assert_model (filter, "1 2 3 4 5 6 7 8 9 10");
243 assert_changes (filter, "");
244 g_object_unref (filter);
245
246 filter = new_model (10, NULL, NULL);
247 custom = GTK_FILTER (gtk_custom_filter_new (is_smaller_than, GUINT_TO_POINTER (7), NULL));
248 gtk_filter_list_model_set_filter (filter, custom);
249 g_object_unref (custom);
250 assert_model (filter, "1 2 3 4 5 6");
251 assert_changes (filter, "6-4");
252 g_object_unref (filter);
253
254 filter = new_model (10, NULL, NULL);
255 custom = GTK_FILTER (gtk_custom_filter_new (is_smaller_than, GUINT_TO_POINTER (0), NULL));
256 gtk_filter_list_model_set_filter (filter, custom);
257 g_object_unref (custom);
258 assert_model (filter, "");
259 assert_changes (filter, "0-10");
260 g_object_unref (filter);
261
262 filter = new_model (10, NULL, NULL);
263 custom = GTK_FILTER (gtk_custom_filter_new (is_larger_than, GUINT_TO_POINTER (0), NULL));
264 gtk_filter_list_model_set_filter (filter, custom);
265 g_object_unref (custom);
266 assert_model (filter, "1 2 3 4 5 6 7 8 9 10");
267 assert_changes (filter, "");
268 g_object_unref (filter);
269
270 filter = new_model (10, NULL, NULL);
271 custom = GTK_FILTER (gtk_custom_filter_new (is_larger_than, GUINT_TO_POINTER (3), NULL));
272 gtk_filter_list_model_set_filter (filter, custom);
273 g_object_unref (custom);
274 assert_model (filter, "4 5 6 7 8 9 10");
275 assert_changes (filter, "0-3");
276 g_object_unref (filter);
277
278 filter = new_model (10, NULL, NULL);
279 custom = GTK_FILTER (gtk_custom_filter_new (is_larger_than, GUINT_TO_POINTER (20), NULL));
280 gtk_filter_list_model_set_filter (filter, custom);
281 g_object_unref (custom);
282 assert_model (filter, "");
283 assert_changes (filter, "0-10");
284 g_object_unref (filter);
285
286 filter = new_model (10, NULL, NULL);
287 custom = GTK_FILTER (gtk_custom_filter_new (is_near, GUINT_TO_POINTER (5), NULL));
288 gtk_filter_list_model_set_filter (filter, custom);
289 g_object_unref (custom);
290 assert_model (filter, "3 4 5 6 7");
291 assert_changes (filter, "0-10+5");
292 g_object_unref (filter);
293
294 filter = new_model (10, NULL, NULL);
295 custom = GTK_FILTER (gtk_custom_filter_new (is_not_near, GUINT_TO_POINTER (5), NULL));
296 gtk_filter_list_model_set_filter (filter, custom);
297 g_object_unref (custom);
298 assert_model (filter, "1 2 8 9 10");
299 assert_changes (filter, "2-5");
300 g_object_unref (filter);
301 }
302
303 static void
test_change_filter(void)304 test_change_filter (void)
305 {
306 GtkFilterListModel *filter;
307 GtkFilter *custom;
308
309 filter = new_model (10, is_not_near, GUINT_TO_POINTER (5));
310 assert_model (filter, "1 2 8 9 10");
311 assert_changes (filter, "");
312
313 custom = GTK_FILTER (gtk_custom_filter_new (is_not_near, GUINT_TO_POINTER (6), NULL));
314 gtk_filter_list_model_set_filter (filter, custom);
315 g_object_unref (custom);
316 assert_model (filter, "1 2 3 9 10");
317 assert_changes (filter, "2-1+1");
318
319 custom = GTK_FILTER (gtk_custom_filter_new (is_not_near, GUINT_TO_POINTER (9), NULL));
320 gtk_filter_list_model_set_filter (filter, custom);
321 g_object_unref (custom);
322 assert_model (filter, "1 2 3 4 5 6");
323 assert_changes (filter, "3-2+3");
324
325 custom = GTK_FILTER (gtk_custom_filter_new (is_smaller_than, GUINT_TO_POINTER (6), NULL));
326 gtk_filter_list_model_set_filter (filter, custom);
327 g_object_unref (custom);
328 assert_model (filter, "1 2 3 4 5");
329 assert_changes (filter, "-5");
330
331 custom = GTK_FILTER (gtk_custom_filter_new (is_larger_than, GUINT_TO_POINTER (4), NULL));
332 gtk_filter_list_model_set_filter (filter, custom);
333 g_object_unref (custom);
334 assert_model (filter, "5 6 7 8 9 10");
335 assert_changes (filter, "0-5+6");
336
337 custom = GTK_FILTER (gtk_custom_filter_new (is_not_near, GUINT_TO_POINTER (2), NULL));
338 gtk_filter_list_model_set_filter (filter, custom);
339 g_object_unref (custom);
340 assert_model (filter, "5 6 7 8 9 10");
341 assert_changes (filter, "");
342
343 custom = GTK_FILTER (gtk_custom_filter_new (is_not_near, GUINT_TO_POINTER (4), NULL));
344 gtk_filter_list_model_set_filter (filter, custom);
345 g_object_unref (custom);
346 assert_model (filter, "1 7 8 9 10");
347 assert_changes (filter, "0-2+1");
348
349 g_object_unref (filter);
350 }
351
352 static void
test_incremental(void)353 test_incremental (void)
354 {
355 GtkFilterListModel *filter;
356 GtkFilter *custom;
357
358 /* everything is filtered */
359 filter = new_model (1000, is_larger_than, GUINT_TO_POINTER (10000));
360 gtk_filter_list_model_set_incremental (filter, TRUE);
361 assert_model (filter, "");
362 assert_changes (filter, "");
363
364 custom = GTK_FILTER (gtk_custom_filter_new (is_near, GUINT_TO_POINTER (512), NULL));
365 gtk_filter_list_model_set_filter (filter, custom);
366 g_object_unref (custom);
367 assert_model (filter, "");
368 assert_changes (filter, "");
369
370 while (g_main_context_pending (NULL))
371 g_main_context_iteration (NULL, TRUE);
372 assert_model (filter, "510 511 512 513 514");
373 /* implementation detail */
374 ignore_changes (filter);
375
376 g_object_unref (filter);
377 }
378
379 static void
test_empty(void)380 test_empty (void)
381 {
382 GtkFilterListModel *filter;
383 GListStore *store;
384 GtkFilter *f;
385
386 filter = gtk_filter_list_model_new (NULL, NULL);
387
388 g_assert_cmpuint (g_list_model_get_n_items (G_LIST_MODEL (filter)), ==, 0);
389 g_assert_null (g_list_model_get_item (G_LIST_MODEL (filter), 11));
390
391 store = g_list_store_new (G_TYPE_OBJECT);
392 gtk_filter_list_model_set_model (filter, G_LIST_MODEL (store));
393 g_object_unref (store);
394
395 g_assert_cmpuint (g_list_model_get_n_items (G_LIST_MODEL (filter)), ==, 0);
396 g_assert_null (g_list_model_get_item (G_LIST_MODEL (filter), 11));
397
398 f = GTK_FILTER (gtk_every_filter_new ());
399 gtk_filter_list_model_set_filter (filter, f);
400 g_object_unref (f);
401
402 g_assert_cmpuint (g_list_model_get_n_items (G_LIST_MODEL (filter)), ==, 0);
403 g_assert_null (g_list_model_get_item (G_LIST_MODEL (filter), 11));
404
405 g_object_unref (filter);
406 }
407
408 int
main(int argc,char * argv[])409 main (int argc, char *argv[])
410 {
411 (g_test_init) (&argc, &argv, NULL);
412 setlocale (LC_ALL, "C");
413
414 number_quark = g_quark_from_static_string ("Hell and fire was spawned to be released.");
415 changes_quark = g_quark_from_static_string ("What did I see? Can I believe what I saw?");
416
417 g_test_add_func ("/filterlistmodel/create", test_create);
418 g_test_add_func ("/filterlistmodel/empty_set_filter", test_empty_set_filter);
419 g_test_add_func ("/filterlistmodel/change_filter", test_change_filter);
420 g_test_add_func ("/filterlistmodel/incremental", test_incremental);
421 g_test_add_func ("/filterlistmodel/empty", test_empty);
422
423 return g_test_run ();
424 }
425