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 
26 static guint
get(GListModel * model,guint position)27 get (GListModel *model,
28      guint       position)
29 {
30   GObject *object = g_list_model_get_item (model, position);
31   guint ret;
32   g_assert_nonnull (object);
33   ret = GPOINTER_TO_UINT (g_object_get_qdata (object, number_quark));
34   g_object_unref (object);
35   return ret;
36 }
37 
38 static char *
get_string(gpointer object)39 get_string (gpointer object)
40 {
41   return g_strdup_printf ("%u", GPOINTER_TO_UINT (g_object_get_qdata (object, number_quark)));
42 }
43 
44 static void
append_digit(GString * s,guint digit)45 append_digit (GString *s,
46               guint    digit)
47 {
48   static const char *names[10] = { NULL, "one", "two", "three", "four", "five", "six", "seven", "eight", "nine" };
49 
50   if (digit == 0)
51     return;
52 
53   g_assert_cmpint (digit, <, 10);
54 
55   if (s->len)
56     g_string_append_c (s, ' ');
57   g_string_append (s, names[digit]);
58 }
59 
60 static void
append_below_thousand(GString * s,guint n)61 append_below_thousand (GString *s,
62                        guint    n)
63 {
64   if (n >= 100)
65     {
66       append_digit (s, n / 100);
67       g_string_append (s, " hundred");
68       n %= 100;
69     }
70 
71   if (n >= 20)
72     {
73       const char *names[10] = { NULL, NULL, "twenty", "thirty", "forty", "fifty", "sixty", "seventy", "eighty", "ninety" };
74       if (s->len)
75         g_string_append_c (s, ' ');
76       g_string_append (s, names [n / 10]);
77       n %= 10;
78     }
79 
80   if (n >= 10)
81     {
82       const char *names[10] = { "ten", "eleven", "twelve", "thirteen", "fourteen",
83                                 "fifteen", "sixteen", "seventeen", "eighteen", "nineteen" };
84       if (s->len)
85         g_string_append_c (s, ' ');
86       g_string_append (s, names [n - 10]);
87     }
88   else
89     {
90       append_digit (s, n);
91     }
92 }
93 
94 static char *
get_spelled_out(gpointer object)95 get_spelled_out (gpointer object)
96 {
97   guint n = GPOINTER_TO_UINT (g_object_get_qdata (object, number_quark));
98   GString *s;
99 
100   g_assert_cmpint (n, <, 1000000);
101 
102   if (n == 0)
103     return g_strdup ("Zero");
104 
105   s = g_string_new (NULL);
106 
107   if (n >= 1000)
108     {
109       append_below_thousand (s, n / 1000);
110       g_string_append (s, " thousand");
111       n %= 1000;
112     }
113 
114   append_below_thousand (s, n);
115 
116   /* Capitalize first letter so we can do case-sensitive matching */
117   s->str[0] = g_ascii_toupper (s->str[0]);
118 
119   return g_string_free (s, FALSE);
120 }
121 
122 static char *
model_to_string(GListModel * model)123 model_to_string (GListModel *model)
124 {
125   GString *string = g_string_new (NULL);
126   guint i;
127 
128   for (i = 0; i < g_list_model_get_n_items (model); i++)
129     {
130       if (i > 0)
131         g_string_append (string, " ");
132       g_string_append_printf (string, "%u", get (model, i));
133     }
134 
135   return g_string_free (string, FALSE);
136 }
137 
138 static GListStore *
139 new_store (guint start,
140            guint end,
141            guint step);
142 
143 static void
add(GListStore * store,guint number)144 add (GListStore *store,
145      guint       number)
146 {
147   GObject *object;
148 
149   /* 0 cannot be differentiated from NULL, so don't use it */
150   g_assert_cmpint (number, !=, 0);
151 
152   object = g_object_new (G_TYPE_OBJECT, NULL);
153   g_object_set_qdata (object, number_quark, GUINT_TO_POINTER (number));
154   g_list_store_append (store, object);
155   g_object_unref (object);
156 }
157 
158 #define assert_model(model, expected) G_STMT_START{ \
159   char *s = model_to_string (G_LIST_MODEL (model)); \
160   if (!g_str_equal (s, expected)) \
161      g_assertion_message_cmpstr (G_LOG_DOMAIN, __FILE__, __LINE__, G_STRFUNC, \
162          #model " == " #expected, s, "==", expected); \
163   g_free (s); \
164 }G_STMT_END
165 
166 static GListStore *
new_empty_store(void)167 new_empty_store (void)
168 {
169   return g_list_store_new (G_TYPE_OBJECT);
170 }
171 
172 static GListStore *
new_store(guint start,guint end,guint step)173 new_store (guint start,
174            guint end,
175            guint step)
176 {
177   GListStore *store = new_empty_store ();
178   guint i;
179 
180   for (i = start; i <= end; i += step)
181     add (store, i);
182 
183   return store;
184 }
185 
186 static GtkFilterListModel *
new_model(guint size,GtkFilter * filter)187 new_model (guint      size,
188            GtkFilter *filter)
189 {
190   GtkFilterListModel *result;
191 
192   result = gtk_filter_list_model_new (g_object_ref (G_LIST_MODEL (new_store (1, size, 1))), g_object_ref (filter));
193 
194   return result;
195 }
196 
197 static gboolean
divisible_by(gpointer item,gpointer data)198 divisible_by (gpointer item,
199               gpointer data)
200 {
201   return GPOINTER_TO_UINT (g_object_get_qdata (item, number_quark)) % GPOINTER_TO_UINT (data) == 0;
202 }
203 
204 static void
test_simple(void)205 test_simple (void)
206 {
207   GtkFilterListModel *model;
208   GtkFilter *filter;
209 
210   filter = GTK_FILTER (gtk_custom_filter_new (divisible_by, GUINT_TO_POINTER (3), NULL));
211   model = new_model (20, filter);
212   g_object_unref (filter);
213   assert_model (model, "3 6 9 12 15 18");
214   g_object_unref (model);
215 }
216 
217 static void
test_any_simple(void)218 test_any_simple (void)
219 {
220   GtkFilterListModel *model;
221   GtkFilter *any, *filter1, *filter2;
222   gpointer item;
223 
224   any = GTK_FILTER (gtk_any_filter_new ());
225   filter1 = GTK_FILTER (gtk_custom_filter_new (divisible_by, GUINT_TO_POINTER (3), NULL));
226   filter2 = GTK_FILTER (gtk_custom_filter_new (divisible_by, GUINT_TO_POINTER (5), NULL));
227 
228   model = new_model (20, any);
229   assert_model (model, "");
230 
231   gtk_multi_filter_append (GTK_MULTI_FILTER (any), filter1);
232   assert_model (model, "3 6 9 12 15 18");
233 
234   gtk_multi_filter_append (GTK_MULTI_FILTER (any), filter2);
235   assert_model (model, "3 5 6 9 10 12 15 18 20");
236 
237   g_assert_true (g_list_model_get_item_type (G_LIST_MODEL (any)) == GTK_TYPE_FILTER);
238   g_assert_cmpuint (2, ==, g_list_model_get_n_items (G_LIST_MODEL (any)));
239   item = g_list_model_get_item (G_LIST_MODEL (any), 1);
240   g_assert_true (GTK_FILTER (item) == filter2);
241   g_object_unref (item);
242 
243   gtk_multi_filter_remove (GTK_MULTI_FILTER (any), 0);
244   assert_model (model, "5 10 15 20");
245 
246   /* doesn't exist */
247   gtk_multi_filter_remove (GTK_MULTI_FILTER (any), 10);
248   assert_model (model, "5 10 15 20");
249 
250   gtk_multi_filter_remove (GTK_MULTI_FILTER (any), 0);
251   assert_model (model, "");
252 
253   g_object_unref (model);
254   g_object_unref (any);
255 }
256 
257 static void
test_string_simple(void)258 test_string_simple (void)
259 {
260   GtkFilterListModel *model;
261   GtkFilter *filter;
262 
263   filter = GTK_FILTER (gtk_string_filter_new (
264                gtk_cclosure_expression_new (G_TYPE_STRING,
265                                             NULL,
266                                             0, NULL,
267                                             G_CALLBACK (get_string),
268                                             NULL, NULL)));
269 
270   model = new_model (20, filter);
271   assert_model (model, "1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20");
272 
273   gtk_string_filter_set_search (GTK_STRING_FILTER (filter), "1");
274   assert_model (model, "1 10 11 12 13 14 15 16 17 18 19");
275 
276   g_object_unref (model);
277   g_object_unref (filter);
278 }
279 
280 static void
test_string_properties(void)281 test_string_properties (void)
282 {
283   GtkFilterListModel *model;
284   GtkFilter *filter;
285   GtkExpression *expr;
286 
287   expr = gtk_cclosure_expression_new (G_TYPE_STRING,
288                                       NULL,
289                                       0, NULL,
290                                       G_CALLBACK (get_spelled_out),
291                                       NULL, NULL);
292   filter = GTK_FILTER (gtk_string_filter_new (expr));
293   g_assert_true (expr == gtk_string_filter_get_expression (GTK_STRING_FILTER (filter)));
294 
295   model = new_model (1000, filter);
296   gtk_string_filter_set_search (GTK_STRING_FILTER (filter), "thirte");
297   assert_model (model, "13 113 213 313 413 513 613 713 813 913");
298 
299   gtk_string_filter_set_search (GTK_STRING_FILTER (filter), "thirteen");
300   assert_model (model, "13 113 213 313 413 513 613 713 813 913");
301 
302   gtk_string_filter_set_ignore_case (GTK_STRING_FILTER (filter), FALSE);
303   assert_model (model, "113 213 313 413 513 613 713 813 913");
304 
305   gtk_string_filter_set_search (GTK_STRING_FILTER (filter), "Thirteen");
306   assert_model (model, "13");
307 
308   gtk_string_filter_set_match_mode (GTK_STRING_FILTER (filter), GTK_STRING_FILTER_MATCH_MODE_PREFIX);
309   assert_model (model, "13");
310 
311   gtk_string_filter_set_match_mode (GTK_STRING_FILTER (filter), GTK_STRING_FILTER_MATCH_MODE_EXACT);
312   assert_model (model, "13");
313 
314   gtk_string_filter_set_ignore_case (GTK_STRING_FILTER (filter), TRUE);
315   assert_model (model, "13");
316 
317   gtk_string_filter_set_match_mode (GTK_STRING_FILTER (filter), GTK_STRING_FILTER_MATCH_MODE_PREFIX);
318   assert_model (model, "13");
319 
320   gtk_string_filter_set_match_mode (GTK_STRING_FILTER (filter), GTK_STRING_FILTER_MATCH_MODE_SUBSTRING);
321   assert_model (model, "13 113 213 313 413 513 613 713 813 913");
322 
323   g_object_unref (model);
324   g_object_unref (filter);
325 }
326 
327 static void
test_bool_simple(void)328 test_bool_simple (void)
329 {
330   GtkFilterListModel *model;
331   GtkExpression *expr;
332   GtkFilter *filter;
333 
334   filter = GTK_FILTER (gtk_bool_filter_new (
335                gtk_cclosure_expression_new (G_TYPE_BOOLEAN,
336                                             NULL,
337                                             0, NULL,
338                                             G_CALLBACK (divisible_by),
339                                             GUINT_TO_POINTER (3), NULL)));
340   model = new_model (20, filter);
341   assert_model (model, "3 6 9 12 15 18");
342 
343   gtk_bool_filter_set_invert (GTK_BOOL_FILTER (filter), TRUE);
344   g_assert_true (gtk_bool_filter_get_invert (GTK_BOOL_FILTER (filter)));
345   assert_model (model, "1 2 4 5 7 8 10 11 13 14 16 17 19 20");
346 
347   gtk_bool_filter_set_invert (GTK_BOOL_FILTER (filter), FALSE);
348   g_assert_false (gtk_bool_filter_get_invert (GTK_BOOL_FILTER (filter)));
349   assert_model (model, "3 6 9 12 15 18");
350 
351   expr = gtk_cclosure_expression_new (G_TYPE_BOOLEAN,
352                                       NULL,
353                                       0, NULL,
354                                       G_CALLBACK (divisible_by),
355                                       GUINT_TO_POINTER (5), NULL);
356   gtk_bool_filter_set_expression (GTK_BOOL_FILTER (filter), expr);
357   g_assert_true (expr == gtk_bool_filter_get_expression (GTK_BOOL_FILTER (filter)));
358   gtk_expression_unref (expr);
359   assert_model (model, "5 10 15 20");
360 
361   gtk_bool_filter_set_invert (GTK_BOOL_FILTER (filter), TRUE);
362   assert_model (model, "1 2 3 4 6 7 8 9 11 12 13 14 16 17 18 19");
363 
364   gtk_bool_filter_set_expression (GTK_BOOL_FILTER (filter), NULL);
365   assert_model (model, "");
366 
367   gtk_bool_filter_set_invert (GTK_BOOL_FILTER (filter), FALSE);
368   assert_model (model, "");
369 
370   g_object_unref (filter);
371   g_object_unref (model);
372 }
373 
374 static void
test_every_dispose(void)375 test_every_dispose (void)
376 {
377   GtkFilter *filter, *filter1, *filter2;
378 
379   filter = GTK_FILTER (gtk_every_filter_new ());
380 
381   filter1 = GTK_FILTER (gtk_custom_filter_new (divisible_by, GUINT_TO_POINTER (3), NULL));
382   filter2 = GTK_FILTER (gtk_custom_filter_new (divisible_by, GUINT_TO_POINTER (5), NULL));
383 
384   g_object_ref (filter1);
385   g_object_ref (filter2);
386 
387   gtk_multi_filter_append (GTK_MULTI_FILTER (filter), filter1);
388   gtk_multi_filter_append (GTK_MULTI_FILTER (filter), filter2);
389 
390   g_object_unref (filter);
391 
392   g_object_unref (filter1);
393   g_object_unref (filter2);
394 }
395 
396 int
main(int argc,char * argv[])397 main (int argc, char *argv[])
398 {
399   (g_test_init) (&argc, &argv, NULL);
400   setlocale (LC_ALL, "C");
401 
402   number_quark = g_quark_from_static_string ("Hell and fire was spawned to be released.");
403 
404   g_test_add_func ("/filter/simple", test_simple);
405   g_test_add_func ("/filter/any/simple", test_any_simple);
406   g_test_add_func ("/filter/string/simple", test_string_simple);
407   g_test_add_func ("/filter/string/properties", test_string_properties);
408   g_test_add_func ("/filter/bool/simple", test_bool_simple);
409   g_test_add_func ("/filter/every/dispose", test_every_dispose);
410 
411   return g_test_run ();
412 }
413