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 |
27 | get (GListModel *model, |
28 | guint position) |
29 | { |
30 | GObject *object = g_list_model_get_item (list: 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 * |
39 | get_string (gpointer object) |
40 | { |
41 | return g_strdup_printf (format: "%u" , GPOINTER_TO_UINT (g_object_get_qdata (object, number_quark))); |
42 | } |
43 | |
44 | static void |
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 (string: s, val: names[digit]); |
58 | } |
59 | |
60 | static void |
61 | append_below_thousand (GString *s, |
62 | guint n) |
63 | { |
64 | if (n >= 100) |
65 | { |
66 | append_digit (s, digit: n / 100); |
67 | g_string_append (string: s, val: " 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 (string: s, val: 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 (string: s, val: names [n - 10]); |
87 | } |
88 | else |
89 | { |
90 | append_digit (s, digit: n); |
91 | } |
92 | } |
93 | |
94 | static char * |
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 (str: "Zero" ); |
104 | |
105 | s = g_string_new (NULL); |
106 | |
107 | if (n >= 1000) |
108 | { |
109 | append_below_thousand (s, n: n / 1000); |
110 | g_string_append (string: s, val: " 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 (c: s->str[0]); |
118 | |
119 | return g_string_free (string: s, FALSE); |
120 | } |
121 | |
122 | static char * |
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 (list: model); i++) |
129 | { |
130 | if (i > 0) |
131 | g_string_append (string, val: " " ); |
132 | g_string_append_printf (string, format: "%u" , get (model, position: 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 |
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, quark: number_quark, GUINT_TO_POINTER (number)); |
154 | g_list_store_append (store, item: 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 * |
167 | new_empty_store (void) |
168 | { |
169 | return g_list_store_new (G_TYPE_OBJECT); |
170 | } |
171 | |
172 | static GListStore * |
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, number: i); |
182 | |
183 | return store; |
184 | } |
185 | |
186 | static GtkFilterListModel * |
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 |
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 |
205 | test_simple (void) |
206 | { |
207 | GtkFilterListModel *model; |
208 | GtkFilter *filter; |
209 | |
210 | filter = GTK_FILTER (ptr: gtk_custom_filter_new (match_func: divisible_by, GUINT_TO_POINTER (3), NULL)); |
211 | model = new_model (size: 20, filter); |
212 | g_object_unref (object: filter); |
213 | assert_model (model, "3 6 9 12 15 18" ); |
214 | g_object_unref (object: model); |
215 | } |
216 | |
217 | static void |
218 | test_any_simple (void) |
219 | { |
220 | GtkFilterListModel *model; |
221 | GtkFilter *any, *filter1, *filter2; |
222 | gpointer item; |
223 | |
224 | any = GTK_FILTER (ptr: gtk_any_filter_new ()); |
225 | filter1 = GTK_FILTER (ptr: gtk_custom_filter_new (match_func: divisible_by, GUINT_TO_POINTER (3), NULL)); |
226 | filter2 = GTK_FILTER (ptr: gtk_custom_filter_new (match_func: divisible_by, GUINT_TO_POINTER (5), NULL)); |
227 | |
228 | model = new_model (size: 20, filter: any); |
229 | assert_model (model, "" ); |
230 | |
231 | gtk_multi_filter_append (self: GTK_MULTI_FILTER (ptr: any), filter: filter1); |
232 | assert_model (model, "3 6 9 12 15 18" ); |
233 | |
234 | gtk_multi_filter_append (self: GTK_MULTI_FILTER (ptr: any), filter: 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 (list: G_LIST_MODEL (ptr: any), position: 1); |
240 | g_assert_true (GTK_FILTER (item) == filter2); |
241 | g_object_unref (object: item); |
242 | |
243 | gtk_multi_filter_remove (self: GTK_MULTI_FILTER (ptr: any), position: 0); |
244 | assert_model (model, "5 10 15 20" ); |
245 | |
246 | /* doesn't exist */ |
247 | gtk_multi_filter_remove (self: GTK_MULTI_FILTER (ptr: any), position: 10); |
248 | assert_model (model, "5 10 15 20" ); |
249 | |
250 | gtk_multi_filter_remove (self: GTK_MULTI_FILTER (ptr: any), position: 0); |
251 | assert_model (model, "" ); |
252 | |
253 | g_object_unref (object: model); |
254 | g_object_unref (object: any); |
255 | } |
256 | |
257 | static void |
258 | test_string_simple (void) |
259 | { |
260 | GtkFilterListModel *model; |
261 | GtkFilter *filter; |
262 | |
263 | filter = GTK_FILTER (ptr: gtk_string_filter_new ( |
264 | expression: gtk_cclosure_expression_new (G_TYPE_STRING, |
265 | NULL, |
266 | n_params: 0, NULL, |
267 | G_CALLBACK (get_string), |
268 | NULL, NULL))); |
269 | |
270 | model = new_model (size: 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 (self: GTK_STRING_FILTER (ptr: filter), search: "1" ); |
274 | assert_model (model, "1 10 11 12 13 14 15 16 17 18 19" ); |
275 | |
276 | g_object_unref (object: model); |
277 | g_object_unref (object: filter); |
278 | } |
279 | |
280 | static 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 | n_params: 0, NULL, |
290 | G_CALLBACK (get_spelled_out), |
291 | NULL, NULL); |
292 | filter = GTK_FILTER (ptr: gtk_string_filter_new (expression: expr)); |
293 | g_assert_true (expr == gtk_string_filter_get_expression (GTK_STRING_FILTER (filter))); |
294 | |
295 | model = new_model (size: 1000, filter); |
296 | gtk_string_filter_set_search (self: GTK_STRING_FILTER (ptr: filter), search: "thirte" ); |
297 | assert_model (model, "13 113 213 313 413 513 613 713 813 913" ); |
298 | |
299 | gtk_string_filter_set_search (self: GTK_STRING_FILTER (ptr: filter), search: "thirteen" ); |
300 | assert_model (model, "13 113 213 313 413 513 613 713 813 913" ); |
301 | |
302 | gtk_string_filter_set_ignore_case (self: GTK_STRING_FILTER (ptr: filter), FALSE); |
303 | assert_model (model, "113 213 313 413 513 613 713 813 913" ); |
304 | |
305 | gtk_string_filter_set_search (self: GTK_STRING_FILTER (ptr: filter), search: "Thirteen" ); |
306 | assert_model (model, "13" ); |
307 | |
308 | gtk_string_filter_set_match_mode (self: GTK_STRING_FILTER (ptr: filter), mode: GTK_STRING_FILTER_MATCH_MODE_PREFIX); |
309 | assert_model (model, "13" ); |
310 | |
311 | gtk_string_filter_set_match_mode (self: GTK_STRING_FILTER (ptr: filter), mode: GTK_STRING_FILTER_MATCH_MODE_EXACT); |
312 | assert_model (model, "13" ); |
313 | |
314 | gtk_string_filter_set_ignore_case (self: GTK_STRING_FILTER (ptr: filter), TRUE); |
315 | assert_model (model, "13" ); |
316 | |
317 | gtk_string_filter_set_match_mode (self: GTK_STRING_FILTER (ptr: filter), mode: GTK_STRING_FILTER_MATCH_MODE_PREFIX); |
318 | assert_model (model, "13" ); |
319 | |
320 | gtk_string_filter_set_match_mode (self: GTK_STRING_FILTER (ptr: filter), mode: 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 (object: model); |
324 | g_object_unref (object: filter); |
325 | } |
326 | |
327 | static void |
328 | test_bool_simple (void) |
329 | { |
330 | GtkFilterListModel *model; |
331 | GtkExpression *expr; |
332 | GtkFilter *filter; |
333 | |
334 | filter = GTK_FILTER (ptr: gtk_bool_filter_new ( |
335 | expression: gtk_cclosure_expression_new (G_TYPE_BOOLEAN, |
336 | NULL, |
337 | n_params: 0, NULL, |
338 | G_CALLBACK (divisible_by), |
339 | GUINT_TO_POINTER (3), NULL))); |
340 | model = new_model (size: 20, filter); |
341 | assert_model (model, "3 6 9 12 15 18" ); |
342 | |
343 | gtk_bool_filter_set_invert (self: GTK_BOOL_FILTER (ptr: 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 (self: GTK_BOOL_FILTER (ptr: 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 | n_params: 0, NULL, |
354 | G_CALLBACK (divisible_by), |
355 | GUINT_TO_POINTER (5), NULL); |
356 | gtk_bool_filter_set_expression (self: GTK_BOOL_FILTER (ptr: filter), expression: expr); |
357 | g_assert_true (expr == gtk_bool_filter_get_expression (GTK_BOOL_FILTER (filter))); |
358 | gtk_expression_unref (self: expr); |
359 | assert_model (model, "5 10 15 20" ); |
360 | |
361 | gtk_bool_filter_set_invert (self: GTK_BOOL_FILTER (ptr: 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 (self: GTK_BOOL_FILTER (ptr: filter), NULL); |
365 | assert_model (model, "" ); |
366 | |
367 | gtk_bool_filter_set_invert (self: GTK_BOOL_FILTER (ptr: filter), FALSE); |
368 | assert_model (model, "" ); |
369 | |
370 | g_object_unref (object: filter); |
371 | g_object_unref (object: model); |
372 | } |
373 | |
374 | static void |
375 | test_every_dispose (void) |
376 | { |
377 | GtkFilter *filter, *filter1, *filter2; |
378 | |
379 | filter = GTK_FILTER (ptr: gtk_every_filter_new ()); |
380 | |
381 | filter1 = GTK_FILTER (ptr: gtk_custom_filter_new (match_func: divisible_by, GUINT_TO_POINTER (3), NULL)); |
382 | filter2 = GTK_FILTER (ptr: gtk_custom_filter_new (match_func: divisible_by, GUINT_TO_POINTER (5), NULL)); |
383 | |
384 | g_object_ref (filter1); |
385 | g_object_ref (filter2); |
386 | |
387 | gtk_multi_filter_append (self: GTK_MULTI_FILTER (ptr: filter), filter: filter1); |
388 | gtk_multi_filter_append (self: GTK_MULTI_FILTER (ptr: filter), filter: filter2); |
389 | |
390 | g_object_unref (object: filter); |
391 | |
392 | g_object_unref (object: filter1); |
393 | g_object_unref (object: filter2); |
394 | } |
395 | |
396 | int |
397 | main (int argc, char *argv[]) |
398 | { |
399 | (g_test_init) (argc: &argc, argv: &argv, NULL); |
400 | setlocale (LC_ALL, locale: "C" ); |
401 | |
402 | number_quark = g_quark_from_static_string (string: "Hell and fire was spawned to be released." ); |
403 | |
404 | g_test_add_func (testpath: "/filter/simple" , test_func: test_simple); |
405 | g_test_add_func (testpath: "/filter/any/simple" , test_func: test_any_simple); |
406 | g_test_add_func (testpath: "/filter/string/simple" , test_func: test_string_simple); |
407 | g_test_add_func (testpath: "/filter/string/properties" , test_func: test_string_properties); |
408 | g_test_add_func (testpath: "/filter/bool/simple" , test_func: test_bool_simple); |
409 | g_test_add_func (testpath: "/filter/every/dispose" , test_func: test_every_dispose); |
410 | |
411 | return g_test_run (); |
412 | } |
413 | |