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
24static GQuark number_quark;
25static GQuark changes_quark;
26
27static guint
28get (GListModel *model,
29 guint position)
30{
31 GObject *object = g_list_model_get_item (list: 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
39static char *
40model_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 (list: model); i++)
46 {
47 if (i > 0)
48 g_string_append (string, val: " ");
49 g_string_append_printf (string, format: "%u", get (model, position: i));
50 }
51
52 return g_string_free (string, FALSE);
53}
54
55static GListStore *
56new_store (guint start,
57 guint end,
58 guint step);
59
60static void
61add (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, quark: number_quark, GUINT_TO_POINTER (number));
71 g_list_store_append (store, item: 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
96static GListStore *
97new_empty_store (void)
98{
99 return g_list_store_new (G_TYPE_OBJECT);
100}
101
102static GListStore *
103new_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, number: i);
112
113 return store;
114}
115
116static void
117items_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 (string: changes, val: ", ");
127
128 if (removed == 1 && added == 0)
129 {
130 g_string_append_printf (string: changes, format: "-%u", position);
131 }
132 else if (removed == 0 && added == 1)
133 {
134 g_string_append_printf (string: changes, format: "+%u", position);
135 }
136 else
137 {
138 g_string_append_printf (string: changes, format: "%u", position);
139 if (removed > 0)
140 g_string_append_printf (string: changes, format: "-%u", removed);
141 if (added > 0)
142 g_string_append_printf (string: changes, format: "+%u", added);
143 }
144}
145
146static void
147free_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 (string: changes, TRUE);
155}
156
157static GtkFilterListModel *
158new_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 (ptr: gtk_custom_filter_new (match_func: filter_func, user_data: 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 (init: "");
172 g_object_set_qdata_full (G_OBJECT(result), quark: changes_quark, data: changes, destroy: free_changes);
173 g_signal_connect (result, "items-changed", G_CALLBACK (items_changed), changes);
174
175 return result;
176}
177
178static gboolean
179is_smaller_than (gpointer item,
180 gpointer data)
181{
182 return g_object_get_qdata (object: item, quark: number_quark) < data;
183}
184
185static gboolean
186is_larger_than (gpointer item,
187 gpointer data)
188{
189 return g_object_get_qdata (object: item, quark: number_quark) > data;
190}
191
192static gboolean
193is_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
199static gboolean
200is_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
206static void
207test_create (void)
208{
209 GtkFilterListModel *filter;
210
211 filter = new_model (size: 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 (object: filter);
215
216 filter = new_model (size: 10, filter_func: 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 (object: filter);
220
221 filter = new_model (size: 10, filter_func: 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 (object: filter);
225
226 filter = new_model (size: 10, filter_func: is_smaller_than, GUINT_TO_POINTER (0));
227 assert_model (filter, "");
228 assert_changes (filter, "");
229 g_object_unref (object: filter);
230}
231
232static void
233test_empty_set_filter (void)
234{
235 GtkFilterListModel *filter;
236 GtkFilter *custom;
237
238 filter = new_model (size: 10, NULL, NULL);
239 custom = GTK_FILTER (ptr: gtk_custom_filter_new (match_func: is_smaller_than, GUINT_TO_POINTER (20), NULL));
240 gtk_filter_list_model_set_filter (self: filter, filter: custom);
241 g_object_unref (object: custom);
242 assert_model (filter, "1 2 3 4 5 6 7 8 9 10");
243 assert_changes (filter, "");
244 g_object_unref (object: filter);
245
246 filter = new_model (size: 10, NULL, NULL);
247 custom = GTK_FILTER (ptr: gtk_custom_filter_new (match_func: is_smaller_than, GUINT_TO_POINTER (7), NULL));
248 gtk_filter_list_model_set_filter (self: filter, filter: custom);
249 g_object_unref (object: custom);
250 assert_model (filter, "1 2 3 4 5 6");
251 assert_changes (filter, "6-4");
252 g_object_unref (object: filter);
253
254 filter = new_model (size: 10, NULL, NULL);
255 custom = GTK_FILTER (ptr: gtk_custom_filter_new (match_func: is_smaller_than, GUINT_TO_POINTER (0), NULL));
256 gtk_filter_list_model_set_filter (self: filter, filter: custom);
257 g_object_unref (object: custom);
258 assert_model (filter, "");
259 assert_changes (filter, "0-10");
260 g_object_unref (object: filter);
261
262 filter = new_model (size: 10, NULL, NULL);
263 custom = GTK_FILTER (ptr: gtk_custom_filter_new (match_func: is_larger_than, GUINT_TO_POINTER (0), NULL));
264 gtk_filter_list_model_set_filter (self: filter, filter: custom);
265 g_object_unref (object: custom);
266 assert_model (filter, "1 2 3 4 5 6 7 8 9 10");
267 assert_changes (filter, "");
268 g_object_unref (object: filter);
269
270 filter = new_model (size: 10, NULL, NULL);
271 custom = GTK_FILTER (ptr: gtk_custom_filter_new (match_func: is_larger_than, GUINT_TO_POINTER (3), NULL));
272 gtk_filter_list_model_set_filter (self: filter, filter: custom);
273 g_object_unref (object: custom);
274 assert_model (filter, "4 5 6 7 8 9 10");
275 assert_changes (filter, "0-3");
276 g_object_unref (object: filter);
277
278 filter = new_model (size: 10, NULL, NULL);
279 custom = GTK_FILTER (ptr: gtk_custom_filter_new (match_func: is_larger_than, GUINT_TO_POINTER (20), NULL));
280 gtk_filter_list_model_set_filter (self: filter, filter: custom);
281 g_object_unref (object: custom);
282 assert_model (filter, "");
283 assert_changes (filter, "0-10");
284 g_object_unref (object: filter);
285
286 filter = new_model (size: 10, NULL, NULL);
287 custom = GTK_FILTER (ptr: gtk_custom_filter_new (match_func: is_near, GUINT_TO_POINTER (5), NULL));
288 gtk_filter_list_model_set_filter (self: filter, filter: custom);
289 g_object_unref (object: custom);
290 assert_model (filter, "3 4 5 6 7");
291 assert_changes (filter, "0-10+5");
292 g_object_unref (object: filter);
293
294 filter = new_model (size: 10, NULL, NULL);
295 custom = GTK_FILTER (ptr: gtk_custom_filter_new (match_func: is_not_near, GUINT_TO_POINTER (5), NULL));
296 gtk_filter_list_model_set_filter (self: filter, filter: custom);
297 g_object_unref (object: custom);
298 assert_model (filter, "1 2 8 9 10");
299 assert_changes (filter, "2-5");
300 g_object_unref (object: filter);
301}
302
303static void
304test_change_filter (void)
305{
306 GtkFilterListModel *filter;
307 GtkFilter *custom;
308
309 filter = new_model (size: 10, filter_func: 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 (ptr: gtk_custom_filter_new (match_func: is_not_near, GUINT_TO_POINTER (6), NULL));
314 gtk_filter_list_model_set_filter (self: filter, filter: custom);
315 g_object_unref (object: custom);
316 assert_model (filter, "1 2 3 9 10");
317 assert_changes (filter, "2-1+1");
318
319 custom = GTK_FILTER (ptr: gtk_custom_filter_new (match_func: is_not_near, GUINT_TO_POINTER (9), NULL));
320 gtk_filter_list_model_set_filter (self: filter, filter: custom);
321 g_object_unref (object: custom);
322 assert_model (filter, "1 2 3 4 5 6");
323 assert_changes (filter, "3-2+3");
324
325 custom = GTK_FILTER (ptr: gtk_custom_filter_new (match_func: is_smaller_than, GUINT_TO_POINTER (6), NULL));
326 gtk_filter_list_model_set_filter (self: filter, filter: custom);
327 g_object_unref (object: custom);
328 assert_model (filter, "1 2 3 4 5");
329 assert_changes (filter, "-5");
330
331 custom = GTK_FILTER (ptr: gtk_custom_filter_new (match_func: is_larger_than, GUINT_TO_POINTER (4), NULL));
332 gtk_filter_list_model_set_filter (self: filter, filter: custom);
333 g_object_unref (object: custom);
334 assert_model (filter, "5 6 7 8 9 10");
335 assert_changes (filter, "0-5+6");
336
337 custom = GTK_FILTER (ptr: gtk_custom_filter_new (match_func: is_not_near, GUINT_TO_POINTER (2), NULL));
338 gtk_filter_list_model_set_filter (self: filter, filter: custom);
339 g_object_unref (object: custom);
340 assert_model (filter, "5 6 7 8 9 10");
341 assert_changes (filter, "");
342
343 custom = GTK_FILTER (ptr: gtk_custom_filter_new (match_func: is_not_near, GUINT_TO_POINTER (4), NULL));
344 gtk_filter_list_model_set_filter (self: filter, filter: custom);
345 g_object_unref (object: custom);
346 assert_model (filter, "1 7 8 9 10");
347 assert_changes (filter, "0-2+1");
348
349 g_object_unref (object: filter);
350}
351
352static void
353test_incremental (void)
354{
355 GtkFilterListModel *filter;
356 GtkFilter *custom;
357
358 /* everything is filtered */
359 filter = new_model (size: 1000, filter_func: is_larger_than, GUINT_TO_POINTER (10000));
360 gtk_filter_list_model_set_incremental (self: filter, TRUE);
361 assert_model (filter, "");
362 assert_changes (filter, "");
363
364 custom = GTK_FILTER (ptr: gtk_custom_filter_new (match_func: is_near, GUINT_TO_POINTER (512), NULL));
365 gtk_filter_list_model_set_filter (self: filter, filter: custom);
366 g_object_unref (object: 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 (object: filter);
377}
378
379static void
380test_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 (self: filter, model: G_LIST_MODEL (ptr: store));
393 g_object_unref (object: 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 (ptr: gtk_every_filter_new ());
399 gtk_filter_list_model_set_filter (self: filter, filter: f);
400 g_object_unref (object: 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 (object: filter);
406}
407
408int
409main (int argc, char *argv[])
410{
411 (g_test_init) (argc: &argc, argv: &argv, NULL);
412 setlocale (LC_ALL, locale: "C");
413
414 number_quark = g_quark_from_static_string (string: "Hell and fire was spawned to be released.");
415 changes_quark = g_quark_from_static_string (string: "What did I see? Can I believe what I saw?");
416
417 g_test_add_func (testpath: "/filterlistmodel/create", test_func: test_create);
418 g_test_add_func (testpath: "/filterlistmodel/empty_set_filter", test_func: test_empty_set_filter);
419 g_test_add_func (testpath: "/filterlistmodel/change_filter", test_func: test_change_filter);
420 g_test_add_func (testpath: "/filterlistmodel/incremental", test_func: test_incremental);
421 g_test_add_func (testpath: "/filterlistmodel/empty", test_func: test_empty);
422
423 return g_test_run ();
424}
425

source code of gtk/testsuite/gtk/filterlistmodel.c