1 /*
2  * Copyright (C) 2019, Red Hat, Inc.
3  * Authors: Matthias Clasen <mclasen@redhat.com>
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public
16  * License along with this library. If not, see <http://www.gnu.org/licenses/>.
17  */
18 
19 #include <locale.h>
20 
21 #include <gtk/gtk.h>
22 
23 static GQuark number_quark;
24 static GQuark changes_quark;
25 static GQuark selection_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 ret;
33   g_assert_nonnull (object);
34   ret = GPOINTER_TO_UINT (g_object_get_qdata (object, number_quark));
35   g_object_unref (object);
36   return ret;
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 char *
selection_to_string(GListModel * model)56 selection_to_string (GListModel *model)
57 {
58   GString *string = g_string_new (NULL);
59   guint i;
60 
61   for (i = 0; i < g_list_model_get_n_items (model); i++)
62     {
63       if (!gtk_selection_model_is_selected (GTK_SELECTION_MODEL (model), i))
64         continue;
65 
66       if (string->len > 0)
67         g_string_append (string, " ");
68       g_string_append_printf (string, "%u", get (model, i));
69     }
70 
71   return g_string_free (string, FALSE);
72 }
73 
74 static GListStore *
75 new_store (guint start,
76            guint end,
77            guint step);
78 
79 static GObject *
make_object(guint number)80 make_object (guint number)
81 {
82   GObject *object;
83 
84   /* 0 cannot be differentiated from NULL, so don't use it */
85   g_assert_cmpint (number, !=, 0);
86 
87   object = g_object_new (G_TYPE_OBJECT, NULL);
88   g_object_set_qdata (object, number_quark, GUINT_TO_POINTER (number));
89 
90   return object;
91 }
92 
93 static void
splice(GListStore * store,guint pos,guint removed,guint * numbers,guint added)94 splice (GListStore *store,
95         guint       pos,
96         guint       removed,
97         guint      *numbers,
98         guint       added)
99 {
100   GObject **objects;
101   guint i;
102 
103   objects = g_new0 (GObject *, added);
104 
105   for (i = 0; i < added; i++)
106     objects[i] = make_object (numbers[i]);
107 
108   g_list_store_splice (store, pos, removed, (gpointer *) objects, added);
109 
110   for (i = 0; i < added; i++)
111     g_object_unref (objects[i]);
112 
113   g_free (objects);
114 }
115 
116 static void
add(GListStore * store,guint number)117 add (GListStore *store,
118      guint       number)
119 {
120   GObject *object = make_object (number);
121   g_list_store_append (store, object);
122   g_object_unref (object);
123 }
124 
125 static void
insert(GListStore * store,guint position,guint number)126 insert (GListStore *store,
127         guint position,
128         guint number)
129 {
130   GObject *object = make_object (number);
131   g_list_store_insert (store, position, object);
132   g_object_unref (object);
133 }
134 
135 #define assert_model(model, expected) G_STMT_START{ \
136   char *s = model_to_string (G_LIST_MODEL (model)); \
137   if (!g_str_equal (s, expected)) \
138      g_assertion_message_cmpstr (G_LOG_DOMAIN, __FILE__, __LINE__, G_STRFUNC, \
139          #model " == " #expected, s, "==", expected); \
140   g_free (s); \
141 }G_STMT_END
142 
143 #define ignore_changes(model) G_STMT_START{ \
144   GString *changes = g_object_get_qdata (G_OBJECT (model), changes_quark); \
145   g_string_set_size (changes, 0); \
146 }G_STMT_END
147 
148 #define assert_changes(model, expected) G_STMT_START{ \
149   GString *changes = g_object_get_qdata (G_OBJECT (model), changes_quark); \
150   if (!g_str_equal (changes->str, expected)) \
151      g_assertion_message_cmpstr (G_LOG_DOMAIN, __FILE__, __LINE__, G_STRFUNC, \
152          #model " == " #expected, changes->str, "==", expected); \
153   g_string_set_size (changes, 0); \
154 }G_STMT_END
155 
156 #define assert_selection(model, expected) G_STMT_START{ \
157   char *s = selection_to_string (G_LIST_MODEL (model)); \
158   if (!g_str_equal (s, expected)) \
159      g_assertion_message_cmpstr (G_LOG_DOMAIN, __FILE__, __LINE__, G_STRFUNC, \
160          #model " == " #expected, s, "==", expected); \
161   g_free (s); \
162 }G_STMT_END
163 
164 #define ignore_selection_changes(model) G_STMT_START{ \
165   GString *changes = g_object_get_qdata (G_OBJECT (model), selection_quark); \
166   g_string_set_size (changes, 0); \
167 }G_STMT_END
168 
169 #define assert_selection_changes(model, expected) G_STMT_START{ \
170   GString *changes = g_object_get_qdata (G_OBJECT (model), selection_quark); \
171   if (!g_str_equal (changes->str, expected)) \
172      g_assertion_message_cmpstr (G_LOG_DOMAIN, __FILE__, __LINE__, G_STRFUNC, \
173          #model " == " #expected, changes->str, "==", expected); \
174   g_string_set_size (changes, 0); \
175 }G_STMT_END
176 
177 static GListStore *
new_empty_store(void)178 new_empty_store (void)
179 {
180   return g_list_store_new (G_TYPE_OBJECT);
181 }
182 
183 static GListStore *
new_store(guint start,guint end,guint step)184 new_store (guint start,
185            guint end,
186            guint step)
187 {
188   GListStore *store = new_empty_store ();
189   guint i;
190 
191   for (i = start; i <= end; i += step)
192     add (store, i);
193 
194   return store;
195 }
196 
197 static void
items_changed(GListModel * model,guint position,guint removed,guint added,GString * changes)198 items_changed (GListModel *model,
199                guint       position,
200                guint       removed,
201                guint       added,
202                GString    *changes)
203 {
204   g_assert_true (removed != 0 || added != 0);
205 
206   if (changes->len)
207     g_string_append (changes, ", ");
208 
209   if (removed == 1 && added == 0)
210     {
211       g_string_append_printf (changes, "-%u", position);
212     }
213   else if (removed == 0 && added == 1)
214     {
215       g_string_append_printf (changes, "+%u", position);
216     }
217   else
218     {
219       g_string_append_printf (changes, "%u", position);
220       if (removed > 0)
221         g_string_append_printf (changes, "-%u", removed);
222       if (added > 0)
223         g_string_append_printf (changes, "+%u", added);
224     }
225 }
226 
227 static void
selection_changed(GListModel * model,guint position,guint n_items,GString * changes)228 selection_changed (GListModel *model,
229                    guint       position,
230                    guint       n_items,
231                    GString    *changes)
232 {
233   if (changes->len)
234     g_string_append (changes, ", ");
235 
236   g_string_append_printf (changes, "%u:%u", position, n_items);
237 }
238 
239 static void
free_changes(gpointer data)240 free_changes (gpointer data)
241 {
242   GString *changes = data;
243 
244   /* all changes must have been checked via assert_changes() before */
245   g_assert_cmpstr (changes->str, ==, "");
246 
247   g_string_free (changes, TRUE);
248 }
249 
250 static GtkSelectionModel *
new_model(GListStore * store)251 new_model (GListStore *store)
252 {
253   GtkSelectionModel *result;
254   GString *changes;
255 
256   result = GTK_SELECTION_MODEL (gtk_multi_selection_new (g_object_ref (G_LIST_MODEL (store))));
257 
258   changes = g_string_new ("");
259   g_object_set_qdata_full (G_OBJECT(result), changes_quark, changes, free_changes);
260   g_signal_connect (result, "items-changed", G_CALLBACK (items_changed), changes);
261 
262   changes = g_string_new ("");
263   g_object_set_qdata_full (G_OBJECT(result), selection_quark, changes, free_changes);
264   g_signal_connect (result, "selection-changed", G_CALLBACK (selection_changed), changes);
265 
266   return result;
267 }
268 
269 static GtkSelectionFilterModel *
new_filter_model(GtkSelectionModel * model)270 new_filter_model (GtkSelectionModel *model)
271 {
272   GtkSelectionFilterModel *result;
273   GString *changes;
274 
275   result = gtk_selection_filter_model_new (model);
276 
277   changes = g_string_new ("");
278   g_object_set_qdata_full (G_OBJECT(result), changes_quark, changes, free_changes);
279   g_signal_connect (result, "items-changed", G_CALLBACK (items_changed), changes);
280 
281   return result;
282 }
283 
284 static void
test_create(void)285 test_create (void)
286 {
287   GtkSelectionModel *selection;
288   GListStore *store;
289 
290   store = new_store (1, 5, 2);
291   selection = new_model (store);
292 
293   assert_model (selection, "1 3 5");
294   assert_changes (selection, "");
295   assert_selection (selection, "");
296   assert_selection_changes (selection, "");
297 
298   g_object_unref (store);
299   assert_model (selection, "1 3 5");
300   assert_changes (selection, "");
301   assert_selection (selection, "");
302   assert_selection_changes (selection, "");
303 
304   g_object_unref (selection);
305 }
306 
307 static void
test_create_empty(void)308 test_create_empty (void)
309 {
310   GtkMultiSelection *selection;
311 
312   selection = gtk_multi_selection_new (NULL);
313   g_assert_cmpint (g_list_model_get_n_items (G_LIST_MODEL (selection)), ==, 0);
314 
315   g_object_unref (selection);
316 }
317 
318 static void
test_changes(void)319 test_changes (void)
320 {
321   GtkSelectionModel *selection;
322   GListStore *store;
323   gboolean ret;
324 
325   store = new_store (1, 5, 1);
326   selection = new_model (store);
327   assert_model (selection, "1 2 3 4 5");
328   assert_changes (selection, "");
329   assert_selection (selection, "");
330   assert_selection_changes (selection, "");
331 
332   g_list_store_remove (store, 3);
333   assert_model (selection, "1 2 3 5");
334   assert_changes (selection, "-3");
335   assert_selection (selection, "");
336   assert_selection_changes (selection, "");
337 
338   insert (store, 3, 99);
339   assert_model (selection, "1 2 3 99 5");
340   assert_changes (selection, "+3");
341   assert_selection (selection, "");
342   assert_selection_changes (selection, "");
343 
344   splice (store, 3, 2, (guint[]) { 97 }, 1);
345   assert_model (selection, "1 2 3 97");
346   assert_changes (selection, "3-2+1");
347   assert_selection (selection, "");
348   assert_selection_changes (selection, "");
349 
350   ret = gtk_selection_model_select_range (selection, 1, 2, FALSE);
351   g_assert_true (ret);
352   assert_selection (selection, "2 3");
353   assert_selection_changes (selection, "1:2");
354 
355   insert (store, 2, 22);
356   assert_model (selection, "1 2 22 3 97");
357   assert_changes (selection, "+2");
358   assert_selection (selection, "2 3");
359   assert_selection_changes (selection, "");
360 
361   g_object_unref (store);
362   g_object_unref (selection);
363 }
364 
365 static void
test_selection(void)366 test_selection (void)
367 {
368   GtkSelectionModel *selection;
369   GListStore *store;
370   gboolean ret;
371 
372   store = new_store (1, 5, 1);
373   selection = new_model (store);
374   assert_selection (selection, "");
375   assert_selection_changes (selection, "");
376 
377   ret = gtk_selection_model_select_item (selection, 3, FALSE);
378   g_assert_true (ret);
379   assert_selection (selection, "4");
380   assert_selection_changes (selection, "3:1");
381 
382   ret = gtk_selection_model_unselect_item (selection, 3);
383   g_assert_true (ret);
384   assert_selection (selection, "");
385   assert_selection_changes (selection, "3:1");
386 
387   ret = gtk_selection_model_select_item (selection, 1, FALSE);
388   g_assert_true (ret);
389   assert_selection (selection, "2");
390   assert_selection_changes (selection, "1:1");
391 
392   ret = gtk_selection_model_select_range (selection, 3, 2, FALSE);
393   g_assert_true (ret);
394   assert_selection (selection, "2 4 5");
395   assert_selection_changes (selection, "3:2");
396 
397   ret = gtk_selection_model_unselect_range (selection, 3, 2);
398   g_assert_true (ret);
399   assert_selection (selection, "2");
400   assert_selection_changes (selection, "3:2");
401 
402   ret = gtk_selection_model_select_all (selection);
403   g_assert_true (ret);
404   assert_selection (selection, "1 2 3 4 5");
405   assert_selection_changes (selection, "0:5");
406 
407   ret = gtk_selection_model_unselect_all (selection);
408   g_assert_true (ret);
409   assert_selection (selection, "");
410   assert_selection_changes (selection, "0:5");
411 
412   g_object_unref (store);
413   g_object_unref (selection);
414 }
415 
416 /* Verify that select_range with exclusive = TRUE
417  * sends a selection-changed signal that covers
418  * preexisting items that got unselected
419  */
420 static void
test_select_range(void)421 test_select_range (void)
422 {
423   GtkSelectionModel *selection;
424   GListStore *store;
425   gboolean ret;
426 
427   store = new_store (1, 5, 1);
428   selection = new_model (store);
429   assert_selection (selection, "");
430   assert_selection_changes (selection, "");
431 
432   ret = gtk_selection_model_select_range (selection, 2, 2, FALSE);
433   g_assert_true (ret);
434   assert_selection (selection, "3 4");
435   assert_selection_changes (selection, "2:2");
436 
437   ret = gtk_selection_model_select_range (selection, 3, 2, FALSE);
438   g_assert_true (ret);
439   assert_selection (selection, "3 4 5");
440   assert_selection_changes (selection, "4:1");
441 
442   ret = gtk_selection_model_select_range (selection, 0, 1, TRUE);
443   g_assert_true (ret);
444   assert_selection (selection, "1");
445   assert_selection_changes (selection, "0:5");
446 
447   g_object_unref (store);
448   g_object_unref (selection);
449 }
450 
451 /* Test that removing and readding items
452  * doesn't clear the selected state.
453  */
454 static void
test_readd(void)455 test_readd (void)
456 {
457   GtkSelectionModel *selection;
458   GListStore *store;
459   gboolean ret;
460 
461   store = new_store (1, 5, 1);
462 
463   selection = new_model (store);
464   assert_model (selection, "1 2 3 4 5");
465   assert_selection (selection, "");
466   assert_selection_changes (selection, "");
467 
468   ret = gtk_selection_model_select_range (selection, 2, 2, FALSE);
469   g_assert_true (ret);
470   assert_model (selection, "1 2 3 4 5");
471   assert_selection (selection, "3 4");
472   assert_selection_changes (selection, "2:2");
473 
474   g_list_model_items_changed (G_LIST_MODEL (store), 1, 3, 3);
475   assert_changes (selection, "1-3+3");
476   assert_selection (selection, "3 4");
477 
478   g_object_unref (store);
479   g_object_unref (selection);
480 }
481 
482 static void
test_set_selection(void)483 test_set_selection (void)
484 {
485   GtkSelectionModel *selection;
486   gboolean ret;
487   GListStore *store;
488   GtkBitset *selected, *mask;
489 
490   store = new_store (1, 10, 1);
491 
492   selection = new_model (store);
493   assert_model (selection, "1 2 3 4 5 6 7 8 9 10");
494   assert_selection (selection, "");
495   assert_selection_changes (selection, "");
496 
497   selected = gtk_bitset_new_empty ();
498   gtk_bitset_add_range (selected, 2, 3);
499   gtk_bitset_add_range (selected, 6, 3);
500   mask = gtk_bitset_new_empty ();
501   gtk_bitset_add_range (mask, 0, 100); /* too big on purpose */
502   ret = gtk_selection_model_set_selection (selection, selected, mask);
503   g_assert_true (ret);
504   gtk_bitset_unref (selected);
505   gtk_bitset_unref (mask);
506   assert_selection (selection, "3 4 5 7 8 9");
507   assert_selection_changes (selection, "2:7");
508 
509   selected = gtk_bitset_new_empty ();
510   mask = gtk_bitset_new_empty ();
511   gtk_bitset_add (mask, 3);
512   gtk_bitset_add (mask, 7);
513   ret = gtk_selection_model_set_selection (selection, selected, mask);
514   g_assert_true (ret);
515   gtk_bitset_unref (selected);
516   gtk_bitset_unref (mask);
517   assert_selection (selection, "3 5 7 9");
518   assert_selection_changes (selection, "3:5");
519 
520   g_object_unref (store);
521   g_object_unref (selection);
522 }
523 
524 static void
test_selection_filter(void)525 test_selection_filter (void)
526 {
527   GtkSelectionModel *selection;
528   GtkSelectionFilterModel *filter;
529   GListStore *store;
530   gboolean ret;
531 
532   store = new_store (1, 5, 1);
533   selection = new_model (store);
534   assert_selection (selection, "");
535   assert_selection_changes (selection, "");
536 
537   filter = new_filter_model (selection);
538   assert_model (filter, "");
539   assert_changes (filter, "");
540 
541   ret = gtk_selection_model_select_item (selection, 3, FALSE);
542   g_assert_true (ret);
543   assert_selection (selection, "4");
544   assert_selection_changes (selection, "3:1");
545   assert_model (filter, "4");
546   assert_changes (filter, "+0");
547 
548   ret = gtk_selection_model_unselect_item (selection, 3);
549   g_assert_true (ret);
550   assert_selection (selection, "");
551   assert_selection_changes (selection, "3:1");
552   assert_model (filter, "");
553   assert_changes (filter, "-0");
554 
555   ret = gtk_selection_model_select_item (selection, 1, FALSE);
556   g_assert_true (ret);
557   assert_selection (selection, "2");
558   assert_selection_changes (selection, "1:1");
559   assert_model (filter, "2");
560   assert_changes (filter, "+0");
561 
562   ret = gtk_selection_model_select_item (selection, 0, FALSE);
563   g_assert_true (ret);
564   assert_selection (selection, "1 2");
565   assert_selection_changes (selection, "0:1");
566   assert_model (filter, "1 2");
567   assert_changes (filter, "+0");
568 
569   ret = gtk_selection_model_unselect_item (selection, 0);
570   g_assert_true (ret);
571   assert_selection (selection, "2");
572   assert_selection_changes (selection, "0:1");
573   assert_model (filter, "2");
574   assert_changes (filter, "-0");
575 
576   ret = gtk_selection_model_select_range (selection, 3, 2, FALSE);
577   g_assert_true (ret);
578   assert_selection (selection, "2 4 5");
579   assert_selection_changes (selection, "3:2");
580   assert_model (filter, "2 4 5");
581   assert_changes (filter, "1+2");
582 
583   ret = gtk_selection_model_unselect_range (selection, 3, 2);
584   g_assert_true (ret);
585   assert_selection (selection, "2");
586   assert_selection_changes (selection, "3:2");
587   assert_model (filter, "2");
588   assert_changes (filter, "1-2");
589 
590   ret = gtk_selection_model_select_all (selection);
591   g_assert_true (ret);
592   assert_selection (selection, "1 2 3 4 5");
593   assert_selection_changes (selection, "0:5");
594   assert_model (filter, "1 2 3 4 5");
595   assert_changes (filter, "0-1+5");
596 
597   ret = gtk_selection_model_unselect_all (selection);
598   g_assert_true (ret);
599   assert_selection (selection, "");
600   assert_selection_changes (selection, "0:5");
601   assert_model (filter, "");
602   assert_changes (filter, "0-5");
603 
604   ret = gtk_selection_model_select_range (selection, 1, 3, FALSE);
605   g_assert_true (ret);
606   assert_selection (selection, "2 3 4");
607   assert_selection_changes (selection, "1:3");
608   assert_model (filter, "2 3 4");
609   assert_changes (filter, "0+3");
610 
611   insert (store, 2, 22);
612   assert_model (selection, "1 2 22 3 4 5");
613   assert_changes (selection, "+2");
614   assert_selection (selection, "2 3 4");
615   assert_selection_changes (selection, "");
616   assert_model (filter, "2 3 4");
617   assert_changes (filter, "");
618 
619   g_list_store_remove (store, 2);
620   assert_model (selection, "1 2 3 4 5");
621   assert_changes (selection, "-2");
622   assert_selection (selection, "2 3 4");
623   assert_selection_changes (selection, "");
624   assert_model (filter, "2 3 4");
625   assert_changes (filter, "");
626 
627   g_object_unref (store);
628   g_object_unref (selection);
629   g_object_unref (filter);
630 }
631 
632 static void
test_set_model(void)633 test_set_model (void)
634 {
635   GtkSelectionModel *selection;
636   GListStore *store;
637   GListModel *m1, *m2;
638   gboolean ret;
639 
640   store = new_store (1, 5, 1);
641   m1 = G_LIST_MODEL (store);
642   m2 = G_LIST_MODEL (gtk_slice_list_model_new (g_object_ref (m1), 0, 3));
643   selection = new_model (store);
644   assert_selection (selection, "");
645   assert_selection_changes (selection, "");
646 
647   ret = gtk_selection_model_select_range (selection, 1, 3, FALSE);
648   g_assert_true (ret);
649   assert_selection (selection, "2 3 4");
650   assert_selection_changes (selection, "1:3");
651 
652   /* we retain the selected item across model changes */
653   gtk_multi_selection_set_model (GTK_MULTI_SELECTION (selection), m2);
654   assert_changes (selection, "0-5+3");
655   assert_selection (selection, "2 3");
656   assert_selection_changes (selection, "");
657 
658   gtk_multi_selection_set_model (GTK_MULTI_SELECTION (selection), NULL);
659   assert_changes (selection, "0-3");
660   assert_selection (selection, "");
661   assert_selection_changes (selection, "");
662 
663   gtk_multi_selection_set_model (GTK_MULTI_SELECTION (selection), m2);
664   assert_changes (selection, "0+3");
665   assert_selection (selection, "");
666   assert_selection_changes (selection, "");
667 
668   ret = gtk_selection_model_select_all (selection);
669   g_assert_true (ret);
670   assert_selection (selection, "1 2 3");
671   assert_selection_changes (selection, "0:3");
672 
673   /* we retain no selected item across model changes */
674   gtk_multi_selection_set_model (GTK_MULTI_SELECTION (selection), m1);
675   assert_changes (selection, "0-3+5");
676   assert_selection (selection, "1 2 3");
677   assert_selection_changes (selection, "");
678 
679   g_object_unref (m2);
680   g_object_unref (m1);
681   g_object_unref (selection);
682 }
683 
684 static void
test_empty(void)685 test_empty (void)
686 {
687   GtkMultiSelection *selection;
688   GListStore *store;
689 
690   selection = gtk_multi_selection_new (NULL);
691 
692   g_assert_cmpuint (g_list_model_get_n_items (G_LIST_MODEL (selection)), ==, 0);
693   g_assert_null (g_list_model_get_item (G_LIST_MODEL (selection), 11));
694 
695   store = g_list_store_new (G_TYPE_OBJECT);
696   gtk_multi_selection_set_model (selection, G_LIST_MODEL (store));
697   g_object_unref (store);
698 
699   g_assert_cmpuint (g_list_model_get_n_items (G_LIST_MODEL (selection)), ==, 0);
700   g_assert_null (g_list_model_get_item (G_LIST_MODEL (selection), 11));
701 
702   g_object_unref (selection);
703 }
704 
705 static void
test_empty_filter(void)706 test_empty_filter (void)
707 {
708   GtkStringList *stringlist;
709   GtkMultiSelection *selection;
710   GtkSelectionFilterModel *selection_filter;
711 
712   stringlist = gtk_string_list_new (NULL);
713   gtk_string_list_append (stringlist, "first item");
714 
715   selection = gtk_multi_selection_new (G_LIST_MODEL (stringlist));
716   selection_filter = gtk_selection_filter_model_new (GTK_SELECTION_MODEL (selection));
717 
718   g_assert_cmpuint (g_list_model_get_n_items (G_LIST_MODEL (selection_filter)), ==, 0);
719   g_assert_null (g_list_model_get_item (G_LIST_MODEL (selection_filter), 11));
720 
721   g_object_unref (selection_filter);
722   g_object_unref (selection);
723 }
724 
725 int
main(int argc,char * argv[])726 main (int argc, char *argv[])
727 {
728   (g_test_init) (&argc, &argv, NULL);
729   setlocale (LC_ALL, "C");
730   g_test_bug_base ("http://bugzilla.gnome.org/show_bug.cgi?id=%s");
731 
732   number_quark = g_quark_from_static_string ("Hell and fire was spawned to be released.");
733   changes_quark = g_quark_from_static_string ("What did I see? Can I believe what I saw?");
734   selection_quark = g_quark_from_static_string ("Mana mana, badibidibi");
735 
736   g_test_add_func ("/multiselection/create", test_create);
737   g_test_add_func ("/multiselection/create-empty", test_create_empty);
738 #if GLIB_CHECK_VERSION (2, 58, 0) /* g_list_store_splice() is broken before 2.58 */
739   g_test_add_func ("/multiselection/changes", test_changes);
740 #endif
741   g_test_add_func ("/multiselection/selection", test_selection);
742   g_test_add_func ("/multiselection/select-range", test_select_range);
743   g_test_add_func ("/multiselection/readd", test_readd);
744   g_test_add_func ("/multiselection/set_selection", test_set_selection);
745   g_test_add_func ("/multiselection/selection-filter", test_selection_filter);
746   g_test_add_func ("/multiselection/set-model", test_set_model);
747   g_test_add_func ("/multiselection/empty", test_empty);
748   g_test_add_func ("/multiselection/selection-filter/empty", test_empty_filter);
749 
750   return g_test_run ();
751 }
752