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   guint number;
32   GObject *object = g_list_model_get_item (model, position);
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 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 = g_newa (GObject *, added);
101   guint i;
102 
103   for (i = 0; i < added; i++)
104     objects[i] = make_object (numbers[i]);
105 
106   g_list_store_splice (store, pos, removed, (gpointer *) objects, added);
107 
108   for (i = 0; i < added; i++)
109     g_object_unref (objects[i]);
110 }
111 
112 static void
add(GListStore * store,guint number)113 add (GListStore *store,
114      guint       number)
115 {
116   GObject *object = make_object (number);
117   g_list_store_append (store, object);
118   g_object_unref (object);
119 }
120 
121 static void
insert(GListStore * store,guint position,guint number)122 insert (GListStore *store,
123         guint position,
124         guint number)
125 {
126   GObject *object = make_object (number);
127   g_list_store_insert (store, position, object);
128   g_object_unref (object);
129 }
130 
131 #define assert_model(model, expected) G_STMT_START{ \
132   char *s = model_to_string (G_LIST_MODEL (model)); \
133   if (!g_str_equal (s, expected)) \
134      g_assertion_message_cmpstr (G_LOG_DOMAIN, __FILE__, __LINE__, G_STRFUNC, \
135          #model " == " #expected, s, "==", expected); \
136   g_free (s); \
137 }G_STMT_END
138 
139 #define ignore_changes(model) G_STMT_START{ \
140   GString *changes = g_object_get_qdata (G_OBJECT (model), changes_quark); \
141   g_string_set_size (changes, 0); \
142 }G_STMT_END
143 
144 #define assert_changes(model, expected) G_STMT_START{ \
145   GString *changes = g_object_get_qdata (G_OBJECT (model), changes_quark); \
146   if (!g_str_equal (changes->str, expected)) \
147      g_assertion_message_cmpstr (G_LOG_DOMAIN, __FILE__, __LINE__, G_STRFUNC, \
148          #model " == " #expected, changes->str, "==", expected); \
149   g_string_set_size (changes, 0); \
150 }G_STMT_END
151 
152 #define assert_selection(model, expected) G_STMT_START{ \
153   char *s = selection_to_string (G_LIST_MODEL (model)); \
154   if (!g_str_equal (s, expected)) \
155      g_assertion_message_cmpstr (G_LOG_DOMAIN, __FILE__, __LINE__, G_STRFUNC, \
156          #model " == " #expected, s, "==", expected); \
157   g_free (s); \
158 }G_STMT_END
159 
160 #define assert_selection_changes(model, expected) G_STMT_START{ \
161   GString *changes = g_object_get_qdata (G_OBJECT (model), selection_quark); \
162   if (!g_str_equal (changes->str, expected)) \
163      g_assertion_message_cmpstr (G_LOG_DOMAIN, __FILE__, __LINE__, G_STRFUNC, \
164          #model " == " #expected, changes->str, "==", expected); \
165   g_string_set_size (changes, 0); \
166 }G_STMT_END
167 
168 #define ignore_selection_changes(model) G_STMT_START{ \
169   GString *changes = g_object_get_qdata (G_OBJECT (model), selection_quark); \
170   g_string_set_size (changes, 0); \
171 }G_STMT_END
172 
173 static GListStore *
new_empty_store(void)174 new_empty_store (void)
175 {
176   return g_list_store_new (G_TYPE_OBJECT);
177 }
178 
179 static GListStore *
new_store(guint start,guint end,guint step)180 new_store (guint start,
181            guint end,
182            guint step)
183 {
184   GListStore *store = new_empty_store ();
185   guint i;
186 
187   for (i = start; i <= end; i += step)
188     add (store, i);
189 
190   return store;
191 }
192 
193 static void
items_changed(GListModel * model,guint position,guint removed,guint added,GString * changes)194 items_changed (GListModel *model,
195                guint       position,
196                guint       removed,
197                guint       added,
198                GString    *changes)
199 {
200   g_assert_true (removed != 0 || added != 0);
201 
202   if (changes->len)
203     g_string_append (changes, ", ");
204 
205   if (removed == 1 && added == 0)
206     {
207       g_string_append_printf (changes, "-%u", position);
208     }
209   else if (removed == 0 && added == 1)
210     {
211       g_string_append_printf (changes, "+%u", position);
212     }
213   else
214     {
215       g_string_append_printf (changes, "%u", position);
216       if (removed > 0)
217         g_string_append_printf (changes, "-%u", removed);
218       if (added > 0)
219         g_string_append_printf (changes, "+%u", added);
220     }
221 }
222 
223 static void
selection_changed(GListModel * model,guint position,guint n_items,GString * changes)224 selection_changed (GListModel *model,
225                    guint       position,
226                    guint       n_items,
227                    GString    *changes)
228 {
229   if (changes->len)
230     g_string_append (changes, ", ");
231 
232   g_string_append_printf (changes, "%u:%u", position, n_items);
233 }
234 
235 static void
free_changes(gpointer data)236 free_changes (gpointer data)
237 {
238   GString *changes = data;
239 
240   /* all changes must have been checked via assert_changes() before */
241   g_assert_cmpstr (changes->str, ==, "");
242 
243   g_string_free (changes, TRUE);
244 }
245 
246 static GtkSelectionModel *
new_model(GListStore * store,gboolean autoselect,gboolean can_unselect)247 new_model (GListStore *store, gboolean autoselect, gboolean can_unselect)
248 {
249   GtkSelectionModel *result;
250   GString *changes;
251 
252   result = GTK_SELECTION_MODEL (gtk_single_selection_new (g_object_ref (G_LIST_MODEL (store))));
253 
254   /* We want to return an empty selection unless autoselect is true,
255    * so undo the initial selection due to autoselect defaulting to TRUE.
256    */
257   gtk_single_selection_set_autoselect (GTK_SINGLE_SELECTION (result), FALSE);
258   gtk_single_selection_set_can_unselect (GTK_SINGLE_SELECTION (result), TRUE);
259   gtk_selection_model_unselect_item (result, 0);
260   assert_selection (result, "");
261 
262   gtk_single_selection_set_autoselect (GTK_SINGLE_SELECTION (result), autoselect);
263   gtk_single_selection_set_can_unselect (GTK_SINGLE_SELECTION (result), can_unselect);
264 
265   changes = g_string_new ("");
266   g_object_set_qdata_full (G_OBJECT(result), changes_quark, changes, free_changes);
267   g_signal_connect (result, "items-changed", G_CALLBACK (items_changed), changes);
268 
269   changes = g_string_new ("");
270   g_object_set_qdata_full (G_OBJECT(result), selection_quark, changes, free_changes);
271   g_signal_connect (result, "selection-changed", G_CALLBACK (selection_changed), changes);
272 
273   return result;
274 }
275 
276 static void
test_create(void)277 test_create (void)
278 {
279   GtkSelectionModel *selection;
280   GListStore *store;
281 
282   if (glib_check_version (2, 59, 0) != NULL)
283     {
284       g_test_skip ("g_list_store_get_item() has overflow issues before GLIB 2.59.0");
285       return;
286     }
287 
288   store = new_store (1, 5, 2);
289   selection = new_model (store, FALSE, FALSE);
290   g_assert_false (gtk_single_selection_get_autoselect (GTK_SINGLE_SELECTION (selection)));
291 
292   assert_model (selection, "1 3 5");
293   assert_changes (selection, "");
294   assert_selection (selection, "");
295   assert_selection_changes (selection, "");
296 
297   g_object_unref (store);
298 
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   GtkSingleSelection *selection;
311 
312   selection = gtk_single_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 
324   if (glib_check_version (2, 58, 0) != NULL)
325     {
326       g_test_skip ("g_list_store_splice() is broken before GLIB 2.58.0");
327       return;
328     }
329 
330   store = new_store (1, 5, 1);
331   selection = new_model (store, FALSE, FALSE);
332   assert_model (selection, "1 2 3 4 5");
333   assert_changes (selection, "");
334   assert_selection (selection, "");
335   assert_selection_changes (selection, "");
336 
337   g_list_store_remove (store, 3);
338   assert_model (selection, "1 2 3 5");
339   assert_changes (selection, "-3");
340   assert_selection (selection, "");
341   assert_selection_changes (selection, "");
342 
343   insert (store, 3, 99);
344   assert_model (selection, "1 2 3 99 5");
345   assert_changes (selection, "+3");
346   assert_selection (selection, "");
347   assert_selection_changes (selection, "");
348 
349   splice (store, 3, 2, (guint[]) { 97 }, 1);
350   assert_model (selection, "1 2 3 97");
351   assert_changes (selection, "3-2+1");
352   assert_selection (selection, "");
353   assert_selection_changes (selection, "");
354 
355   g_object_unref (selection);
356   g_object_unref (store);
357 }
358 
359 static void
test_selection(void)360 test_selection (void)
361 {
362   GtkSelectionModel *selection;
363   GListStore *store;
364   gboolean ret;
365 
366   if (glib_check_version (2, 59, 0) != NULL)
367     {
368       g_test_skip ("g_list_store_get_item() has overflow issues before GLIB 2.59.0");
369       return;
370     }
371 
372   store = new_store (1, 5, 1);
373   selection = new_model (store, TRUE, FALSE);
374   assert_selection (selection, "1");
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, "0:4");
381 
382   ret = gtk_selection_model_unselect_item (selection, 3);
383   g_assert_false (ret);
384   assert_selection (selection, "4");
385   assert_selection_changes (selection, "");
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:3");
391 
392   ret = gtk_selection_model_select_range (selection, 3, 2, FALSE);
393   g_assert_false (ret);
394   assert_selection (selection, "2");
395   assert_selection_changes (selection, "");
396 
397   ret = gtk_selection_model_unselect_range (selection, 4, 2);
398   g_assert_false (ret);
399   assert_selection (selection, "2");
400   assert_selection_changes (selection, "");
401 
402   ret = gtk_selection_model_select_all (selection);
403   g_assert_false (ret);
404   assert_selection (selection, "2");
405   assert_selection_changes (selection, "");
406 
407   ret = gtk_selection_model_unselect_all (selection);
408   g_assert_false (ret);
409   assert_selection (selection, "2");
410   assert_selection_changes (selection, "");
411 
412   g_object_unref (store);
413   g_object_unref (selection);
414 }
415 
416 static void
test_autoselect(void)417 test_autoselect (void)
418 {
419   GtkSelectionModel *selection;
420   GListStore *store;
421 
422   if (glib_check_version (2, 59, 0) != NULL)
423     {
424       g_test_skip ("g_list_store_get_item() has overflow issues before GLIB 2.59.0");
425       return;
426     }
427 
428   store = new_empty_store ();
429   selection = new_model (store, TRUE, FALSE);
430   assert_model (selection, "");
431   assert_changes (selection, "");
432   assert_selection (selection, "");
433   assert_selection_changes (selection, "");
434 
435   add (store, 1);
436   assert_model (selection, "1");
437   assert_changes (selection, "+0");
438   assert_selection (selection, "1");
439   assert_selection_changes (selection, "");
440 
441   splice (store, 0, 1, (guint[]) { 7, 8, 9 }, 3);
442   assert_model (selection, "7 8 9");
443   assert_changes (selection, "0-1+3");
444   assert_selection (selection, "7");
445   assert_selection_changes (selection, "");
446 
447   splice (store, 0, 0, (guint[]) { 5, 6 }, 2);
448   assert_model (selection, "5 6 7 8 9");
449   assert_changes (selection, "0+2");
450   assert_selection (selection, "7");
451   assert_selection_changes (selection, "");
452 
453   g_list_store_remove (store, 2);
454   assert_model (selection, "5 6 8 9");
455   assert_changes (selection, "2-2+1");
456   assert_selection (selection, "8");
457   assert_selection_changes (selection, "");
458 
459   splice (store, 2, 2, NULL, 0);
460   assert_model (selection, "5 6");
461   assert_changes (selection, "1-3+1");
462   assert_selection (selection, "6");
463   assert_selection_changes (selection, "");
464 
465   splice (store, 0, 2, (guint[]) { 1, 2 }, 2);
466   assert_model (selection, "1 2");
467   assert_changes (selection, "0-2+2");
468   assert_selection (selection, "2");
469   assert_selection_changes (selection, "");
470 
471   g_list_store_remove (store, 0);
472   assert_model (selection, "2");
473   assert_changes (selection, "-0");
474   assert_selection (selection, "2");
475   assert_selection_changes (selection, "");
476 
477   g_list_store_remove (store, 0);
478   assert_model (selection, "");
479   assert_changes (selection, "-0");
480   assert_selection (selection, "");
481   assert_selection_changes (selection, "");
482 
483   g_object_unref (store);
484   g_object_unref (selection);
485 }
486 
487 static void
test_autoselect_toggle(void)488 test_autoselect_toggle (void)
489 {
490   GtkSelectionModel *selection;
491   GListStore *store;
492 
493   if (glib_check_version (2, 59, 0) != NULL)
494     {
495       g_test_skip ("g_list_store_get_item() has overflow issues before GLIB 2.59.0");
496       return;
497     }
498 
499   store = new_store (1, 1, 1);
500   selection = new_model (store, TRUE, TRUE);
501   assert_model (selection, "1");
502   assert_changes (selection, "");
503   assert_selection (selection, "1");
504   assert_selection_changes (selection, "");
505 
506   gtk_single_selection_set_autoselect (GTK_SINGLE_SELECTION (selection), FALSE);
507   assert_model (selection, "1");
508   assert_changes (selection, "");
509   assert_selection (selection, "1");
510   assert_selection_changes (selection, "");
511 
512   gtk_selection_model_unselect_item (selection, 0);
513   assert_model (selection, "1");
514   assert_changes (selection, "");
515   assert_selection (selection, "");
516   assert_selection_changes (selection, "0:1");
517 
518   gtk_single_selection_set_autoselect (GTK_SINGLE_SELECTION (selection), TRUE);
519   assert_model (selection, "1");
520   assert_changes (selection, "");
521   assert_selection (selection, "1");
522   assert_selection_changes (selection, "0:1");
523 
524   g_object_unref (store);
525   g_object_unref (selection);
526 }
527 
528 static void
test_can_unselect(void)529 test_can_unselect (void)
530 {
531   GtkSelectionModel *selection;
532   GListStore *store;
533   gboolean ret;
534 
535   if (glib_check_version (2, 59, 0) != NULL)
536     {
537       g_test_skip ("g_list_store_get_item() has overflow issues before GLIB 2.59.0");
538       return;
539     }
540 
541   store = new_store (1, 5, 1);
542   selection = new_model (store, TRUE, FALSE);
543   assert_selection (selection, "1");
544   assert_selection_changes (selection, "");
545 
546   ret = gtk_selection_model_unselect_item (selection, 0);
547   g_assert_false (ret);
548   assert_selection (selection, "1");
549   assert_selection_changes (selection, "");
550 
551   gtk_single_selection_set_can_unselect (GTK_SINGLE_SELECTION (selection), TRUE);
552 
553   assert_selection (selection, "1");
554   ret = gtk_selection_model_unselect_item (selection, 0);
555   g_assert_true (ret);
556   assert_selection (selection, "");
557   assert_selection_changes (selection, "0:1");
558 
559   ignore_changes (selection);
560 
561   g_object_unref (store);
562   g_object_unref (selection);
563 }
564 
565 static int
sort_inverse(gconstpointer a,gconstpointer b,gpointer data)566 sort_inverse (gconstpointer a, gconstpointer b, gpointer data)
567 {
568   int ia = GPOINTER_TO_UINT (g_object_get_qdata (G_OBJECT (a), number_quark));
569   int ib = GPOINTER_TO_UINT (g_object_get_qdata (G_OBJECT (b), number_quark));
570 
571   return ib - ia;
572 }
573 
574 static void
test_persistence(void)575 test_persistence (void)
576 {
577   GtkSelectionModel *selection;
578   GListStore *store;
579 
580   if (glib_check_version (2, 59, 0) != NULL)
581     {
582       g_test_skip ("g_list_store_get_item() has overflow issues before GLIB 2.59.0");
583       return;
584     }
585 
586   store = new_store (1, 5, 1);
587   selection = new_model (store, TRUE, FALSE);
588   assert_selection (selection, "1");
589   assert_selection_changes (selection, "");
590   g_assert_true (gtk_selection_model_is_selected (selection, 0));
591   g_assert_false (gtk_selection_model_is_selected (selection, 4));
592 
593   g_list_store_sort (store, sort_inverse, NULL);
594 
595   assert_selection (selection, "1");
596   assert_selection_changes (selection, "");
597   g_assert_false (gtk_selection_model_is_selected (selection, 0));
598   g_assert_true (gtk_selection_model_is_selected (selection, 4));
599 
600   ignore_changes (selection);
601 
602   g_object_unref (store);
603   g_object_unref (selection);
604 }
605 
606 static void
check_get_selection(GtkSelectionModel * selection)607 check_get_selection (GtkSelectionModel *selection)
608 {
609   GtkBitset *set;
610   guint i, n_items;
611 
612   set = gtk_selection_model_get_selection (selection);
613 
614   n_items = g_list_model_get_n_items (G_LIST_MODEL (selection));
615   if (n_items == 0)
616     {
617       g_assert_true (gtk_bitset_is_empty (set));
618     }
619   else
620     {
621       for (i = 0; i < n_items; i++)
622         {
623           g_assert_cmpint (gtk_bitset_contains (set, i), ==, gtk_selection_model_is_selected (selection, i));
624         }
625 
626       /* check that out-of-range has no bits set */
627       g_assert_cmpint (gtk_bitset_get_maximum (set), <, g_list_model_get_n_items (G_LIST_MODEL (selection)));
628     }
629 
630   gtk_bitset_unref (set);
631 }
632 
633 static void
test_query_range(void)634 test_query_range (void)
635 {
636   GtkSelectionModel *selection;
637   GListStore *store;
638 
639   store = new_store (1, 5, 1);
640   selection = new_model (store, TRUE, TRUE);
641   check_get_selection (selection);
642 
643   gtk_selection_model_unselect_item (selection, 0);
644   check_get_selection (selection);
645 
646   gtk_selection_model_select_item (selection, 2,  TRUE);
647   check_get_selection (selection);
648 
649   gtk_selection_model_select_item (selection, 4, TRUE);
650   check_get_selection (selection);
651 
652   ignore_selection_changes (selection);
653 
654   g_object_unref (store);
655   g_object_unref (selection);
656 }
657 
658 static void
test_set_model(void)659 test_set_model (void)
660 {
661   GtkSelectionModel *selection;
662   GListStore *store;
663   GListModel *m1, *m2;
664 
665   store = new_store (1, 5, 1);
666   m1 = G_LIST_MODEL (store);
667   m2 = G_LIST_MODEL (gtk_slice_list_model_new (g_object_ref (m1), 0, 3));
668   selection = new_model (store, TRUE, TRUE);
669   assert_selection (selection, "1");
670   assert_selection_changes (selection, "");
671 
672   /* we retain the selected item across model changes */
673   gtk_single_selection_set_model (GTK_SINGLE_SELECTION (selection), m2);
674   assert_changes (selection, "0-5+3");
675   assert_selection (selection, "1");
676   assert_selection_changes (selection, "");
677 
678   gtk_single_selection_set_model (GTK_SINGLE_SELECTION (selection), NULL);
679   assert_changes (selection, "0-3");
680   assert_selection (selection, "");
681   assert_selection_changes (selection, "");
682 
683   gtk_single_selection_set_autoselect (GTK_SINGLE_SELECTION (selection), FALSE);
684   gtk_single_selection_set_model (GTK_SINGLE_SELECTION (selection), m2);
685   assert_changes (selection, "0+3");
686   assert_selection (selection, "");
687   assert_selection_changes (selection, "");
688 
689   /* we retain no selected item across model changes */
690   gtk_single_selection_set_model (GTK_SINGLE_SELECTION (selection), m1);
691   assert_changes (selection, "0-3+5");
692   assert_selection (selection, "");
693   assert_selection_changes (selection, "");
694 
695   gtk_single_selection_set_selected (GTK_SINGLE_SELECTION (selection), 4);
696   assert_selection (selection, "5");
697   assert_selection_changes (selection, "4:1");
698 
699   gtk_single_selection_set_model (GTK_SINGLE_SELECTION (selection), m2);
700   assert_changes (selection, "0-5+3");
701   assert_selection (selection, "");
702   assert_selection_changes (selection, "");
703 
704   g_object_unref (m2);
705   g_object_unref (m1);
706   g_object_unref (selection);
707 }
708 
709 static void
test_empty(void)710 test_empty (void)
711 {
712   GtkSingleSelection *selection;
713   GListStore *store;
714 
715   selection = gtk_single_selection_new (NULL);
716 
717   g_assert_cmpuint (g_list_model_get_n_items (G_LIST_MODEL (selection)), ==, 0);
718   g_assert_null (g_list_model_get_item (G_LIST_MODEL (selection), 11));
719 
720   store = g_list_store_new (G_TYPE_OBJECT);
721   gtk_single_selection_set_model (selection, G_LIST_MODEL (store));
722   g_object_unref (store);
723 
724   g_assert_cmpuint (g_list_model_get_n_items (G_LIST_MODEL (selection)), ==, 0);
725   g_assert_null (g_list_model_get_item (G_LIST_MODEL (selection), 11));
726 
727   g_object_unref (selection);
728 }
729 
730 int
main(int argc,char * argv[])731 main (int argc, char *argv[])
732 {
733   (g_test_init) (&argc, &argv, NULL);
734   setlocale (LC_ALL, "C");
735 
736   number_quark = g_quark_from_static_string ("Hell and fire was spawned to be released.");
737   changes_quark = g_quark_from_static_string ("What did I see? Can I believe what I saw?");
738   selection_quark = g_quark_from_static_string ("Mana mana, badibidibi");
739 
740   g_test_add_func ("/singleselection/create", test_create);
741   g_test_add_func ("/singleselection/create-empty", test_create_empty);
742   g_test_add_func ("/singleselection/autoselect", test_autoselect);
743   g_test_add_func ("/singleselection/autoselect-toggle", test_autoselect_toggle);
744   g_test_add_func ("/singleselection/selection", test_selection);
745   g_test_add_func ("/singleselection/can-unselect", test_can_unselect);
746   g_test_add_func ("/singleselection/persistence", test_persistence);
747   g_test_add_func ("/singleselection/query-range", test_query_range);
748   g_test_add_func ("/singleselection/changes", test_changes);
749   g_test_add_func ("/singleselection/set-model", test_set_model);
750   g_test_add_func ("/singleselection/empty", test_empty);
751 
752   return g_test_run ();
753 }
754