1 /* GtkStringList tests
2  *
3  * Copyright (C) 2020, Red Hat, Inc.
4  * Authors: Matthias Clasen
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 <gtk/gtk.h>
21 
22 static GQuark changes_quark;
23 
24 static char *
model_to_string(GListModel * model)25 model_to_string (GListModel *model)
26 {
27   GtkStringList *self = GTK_STRING_LIST (model);
28   GString *string = g_string_new (NULL);
29   guint i;
30 
31   for (i = 0; i < g_list_model_get_n_items (model); i++)
32     {
33       if (i > 0)
34         g_string_append (string, " ");
35       g_string_append_printf (string, "%s", gtk_string_list_get_string (self, i));
36     }
37 
38   return g_string_free (string, FALSE);
39 }
40 
41 #define assert_model(model, expected) G_STMT_START{ \
42   char *s = model_to_string (G_LIST_MODEL (model)); \
43   if (!g_str_equal (s, expected)) \
44      g_assertion_message_cmpstr (G_LOG_DOMAIN, __FILE__, __LINE__, G_STRFUNC, \
45          #model " == " #expected, s, "==", expected); \
46   g_free (s); \
47 }G_STMT_END
48 
49 #define assert_changes(model, expected) G_STMT_START{ \
50   GString *changes = g_object_get_qdata (G_OBJECT (model), changes_quark); \
51   if (!g_str_equal (changes->str, expected)) \
52      g_assertion_message_cmpstr (G_LOG_DOMAIN, __FILE__, __LINE__, G_STRFUNC, \
53          #model " == " #expected, changes->str, "==", expected); \
54   g_string_set_size (changes, 0); \
55 }G_STMT_END
56 
57 static void
items_changed(GListModel * model,guint position,guint removed,guint added,GString * changes)58 items_changed (GListModel *model,
59                guint       position,
60                guint       removed,
61                guint       added,
62                GString    *changes)
63 {
64   g_assert_true (removed != 0 || added != 0);
65 
66   if (changes->len)
67     g_string_append (changes, ", ");
68 
69   if (removed == 1 && added == 0)
70     {
71       g_string_append_printf (changes, "-%u", position);
72     }
73   else if (removed == 0 && added == 1)
74     {
75       g_string_append_printf (changes, "+%u", position);
76     }
77   else
78     {
79       g_string_append_printf (changes, "%u", position);
80       if (removed > 0)
81         g_string_append_printf (changes, "-%u", removed);
82       if (added > 0)
83         g_string_append_printf (changes, "+%u", added);
84     }
85 }
86 
87 static void
free_changes(gpointer data)88 free_changes (gpointer data)
89 {
90   GString *changes = data;
91 
92   /* all changes must have been checked via assert_changes() before */
93   g_assert_cmpstr (changes->str, ==, "");
94 
95   g_string_free (changes, TRUE);
96 }
97 
98 static GtkStringList *
new_model(const char ** strings)99 new_model (const char **strings)
100 {
101   GtkStringList *result;
102   GString *changes;
103 
104   result = gtk_string_list_new (strings);
105   changes = g_string_new ("");
106   g_object_set_qdata_full (G_OBJECT(result), changes_quark, changes, free_changes);
107   g_signal_connect (result, "items-changed", G_CALLBACK (items_changed), changes);
108 
109   return result;
110 }
111 
112 static void
test_string_object(void)113 test_string_object (void)
114 {
115   GtkStringObject *so;
116 
117   so = gtk_string_object_new ("Hello");
118   g_assert_cmpstr (gtk_string_object_get_string (so), ==, "Hello");
119   g_object_unref (so);
120 }
121 
122 static void
test_create_empty(void)123 test_create_empty (void)
124 {
125   GtkStringList *list;
126 
127   list = new_model ((const char *[]){ NULL });
128 
129   g_assert_true (g_type_is_a (g_list_model_get_item_type (G_LIST_MODEL (list)), G_TYPE_OBJECT));
130 
131   assert_model (list, "");
132   assert_changes (list, "");
133 
134   g_object_unref (list);
135 }
136 
137 static void
test_create_strv(void)138 test_create_strv (void)
139 {
140   GtkStringList *list;
141 
142   list = new_model ((const char *[]){ "a", "b", "c", NULL });
143 
144   assert_model (list, "a b c");
145   assert_changes (list, "");
146 
147   g_object_unref (list);
148 }
149 
150 static void
test_create_builder(void)151 test_create_builder (void)
152 {
153   const char *ui =
154 "<interface>"
155 "  <object class=\"GtkStringList\" id=\"list\">"
156 "    <items>"
157 "      <item translatable=\"yes\" context=\"ctx\" comments=\"none\">a</item>"
158 "      <item>b</item>"
159 "      <item>c</item>"
160 "    </items>"
161 "  </object>"
162 "</interface>";
163   GtkBuilder *builder;
164   GtkStringList *list;
165 
166   builder = gtk_builder_new_from_string (ui, -1);
167   list = GTK_STRING_LIST (gtk_builder_get_object (builder, "list"));
168   assert_model (list, "a b c");
169 
170   g_object_unref (builder);
171 }
172 
173 static void
test_get_string(void)174 test_get_string (void)
175 {
176   GtkStringList *list;
177 
178   list = new_model ((const char *[]){ "a", "b", "c", NULL });
179 
180   assert_model (list, "a b c");
181 
182   g_assert_cmpstr (gtk_string_list_get_string (list, 0), ==, "a");
183   g_assert_cmpstr (gtk_string_list_get_string (list, 1), ==, "b");
184   g_assert_cmpstr (gtk_string_list_get_string (list, 2), ==, "c");
185   g_assert_null (gtk_string_list_get_string (list, 3));
186 
187   g_object_unref (list);
188 }
189 
190 static void
test_splice(void)191 test_splice (void)
192 {
193   GtkStringList *list;
194 
195   list = new_model ((const char *[]){ "a", "b", "c", "d", "e", NULL });
196 
197   assert_model (list, "a b c d e");
198 
199   gtk_string_list_splice (list, 2, 2, (const char *[]){ "x", "y", "z", NULL });
200 
201   assert_model (list, "a b x y z e");
202   assert_changes (list, "2-2+3");
203 
204   g_object_unref (list);
205 }
206 
207 static void
test_add_remove(void)208 test_add_remove (void)
209 {
210   GtkStringList *list;
211 
212   list = new_model ((const char *[]){ "a", "b", "c", "d", "e", NULL });
213 
214   assert_model (list, "a b c d e");
215 
216   gtk_string_list_remove (list, 2);
217 
218   assert_model (list, "a b d e");
219   assert_changes (list, "-2");
220 
221   gtk_string_list_append (list, "x");
222 
223   assert_model (list, "a b d e x");
224   assert_changes (list, "+4");
225 
226   g_object_unref (list);
227 }
228 
229 static void
test_take(void)230 test_take (void)
231 {
232   GtkStringList *list;
233 
234   list = new_model ((const char *[]){ NULL });
235 
236   assert_model (list, "");
237 
238   gtk_string_list_take (list, g_strdup_printf ("%d dollars", (int)1e6));
239   assert_model (list, "1000000 dollars");
240   assert_changes (list, "+0");
241 
242   g_object_unref (list);
243 }
244 
245 int
main(int argc,char * argv[])246 main (int argc, char *argv[])
247 {
248   (g_test_init) (&argc, &argv, NULL);
249 
250   changes_quark = g_quark_from_static_string ("What did I see? Can I believe what I saw?");
251 
252   g_test_add_func ("/stringobject/basic", test_string_object);
253   g_test_add_func ("/stringlist/create/empty", test_create_empty);
254   g_test_add_func ("/stringlist/create/strv", test_create_strv);
255   g_test_add_func ("/stringlist/create/builder", test_create_builder);
256   g_test_add_func ("/stringlist/get_string", test_get_string);
257   g_test_add_func ("/stringlist/splice", test_splice);
258   g_test_add_func ("/stringlist/add_remove", test_add_remove);
259   g_test_add_func ("/stringlist/take", test_take);
260 
261   return g_test_run ();
262 }
263