1/* Main wrapper for TreeModel test suite.
2 * Copyright (C) 2011 Kristian Rietveld <kris@gtk.org>
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
8 *
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
13 *
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library. If not, see <http://www.gnu.org/licenses/>.
16 */
17
18#include <gtk/gtk.h>
19
20#include "treemodel.h"
21
22int
23main (int argc,
24 char **argv)
25{
26 gtk_test_init (argcp: &argc, argvp: &argv, NULL);
27
28 register_list_store_tests ();
29 register_tree_store_tests ();
30 register_model_ref_count_tests ();
31 register_sort_model_tests ();
32 register_filter_model_tests ();
33
34 return g_test_run ();
35}
36
37/*
38 * Signal monitor
39 */
40
41static const char *
42signal_name_to_string (SignalName signal)
43{
44 switch (signal)
45 {
46 case ROW_INSERTED:
47 return "row-inserted";
48
49 case ROW_DELETED:
50 return "row-deleted";
51
52 case ROW_CHANGED:
53 return "row-changed";
54
55 case ROW_HAS_CHILD_TOGGLED:
56 return "row-has-child-toggled";
57
58 case ROWS_REORDERED:
59 return "rows-reordered";
60
61 case LAST_SIGNAL:
62 default:
63 g_assert_not_reached ();
64 }
65
66 return "(unknown)";
67}
68
69typedef struct
70{
71 SignalName signal;
72 GtkTreePath *path;
73
74 /* For rows-reordered */
75 int *new_order;
76 int len;
77}
78Signal;
79
80
81static Signal *
82signal_new (SignalName signal, GtkTreePath *path)
83{
84 Signal *s;
85
86 s = g_new0 (Signal, 1);
87 s->signal = signal;
88 s->path = gtk_tree_path_copy (path);
89 s->new_order = NULL;
90
91 return s;
92}
93
94static Signal *
95signal_new_with_order (SignalName signal, GtkTreePath *path,
96 int *new_order, int len)
97{
98 Signal *s = signal_new (signal, path);
99
100 s->new_order = new_order;
101 s->len = len;
102
103 return s;
104}
105
106static void
107signal_free (Signal *s)
108{
109 if (s->path)
110 gtk_tree_path_free (path: s->path);
111
112 g_free (mem: s);
113}
114
115
116struct _SignalMonitor
117{
118 GQueue *queue;
119 GtkTreeModel *client;
120 gulong signal_ids[LAST_SIGNAL];
121};
122
123
124static void
125signal_monitor_generic_handler (SignalMonitor *m,
126 SignalName signal,
127 GtkTreeModel *model,
128 GtkTreeIter *iter,
129 GtkTreePath *path,
130 int *new_order)
131{
132 Signal *s;
133
134 if (g_queue_is_empty (queue: m->queue))
135 {
136 char *path_str;
137
138 path_str = gtk_tree_path_to_string (path);
139 g_error ("Signal queue empty, got signal %s path %s",
140 signal_name_to_string (signal), path_str);
141 g_free (mem: path_str);
142
143 g_assert_not_reached ();
144 }
145
146 if (m->client != model)
147 {
148 g_error ("Model mismatch; expected %p, got %p",
149 m->client, model);
150 g_assert_not_reached ();
151 }
152
153 s = g_queue_peek_tail (queue: m->queue);
154
155#if 0
156 /* For debugging: output signals that are coming in. Leaks memory. */
157 g_print ("signal=%s path=%s\n", signal_name_to_string (signal),
158 gtk_tree_path_to_string (path));
159#endif
160
161 if (s->signal != signal ||
162 (gtk_tree_path_get_depth (path: s->path) == 0 &&
163 gtk_tree_path_get_depth (path) != 0) ||
164 (gtk_tree_path_get_depth (path: s->path) != 0 &&
165 gtk_tree_path_compare (a: s->path, b: path) != 0))
166 {
167 char *path_str, *s_path_str;
168
169 s_path_str = gtk_tree_path_to_string (path: s->path);
170 path_str = gtk_tree_path_to_string (path);
171
172 g_error ("Signals don't match; expected signal %s path %s, got signal %s path %s",
173 signal_name_to_string (s->signal), s_path_str,
174 signal_name_to_string (signal), path_str);
175
176 g_free (mem: s_path_str);
177 g_free (mem: path_str);
178
179 g_assert_not_reached ();
180 }
181
182 if (signal == ROWS_REORDERED && s->new_order != NULL)
183 {
184 int i, len;
185
186 g_assert_nonnull (new_order);
187
188 len = gtk_tree_model_iter_n_children (tree_model: model, iter);
189 g_assert_cmpint (s->len, ==, len);
190
191 for (i = 0; i < len; i++)
192 g_assert_cmpint (s->new_order[i], ==, new_order[i]);
193 }
194
195 s = g_queue_pop_tail (queue: m->queue);
196
197 signal_free (s);
198}
199
200static void
201signal_monitor_row_inserted (GtkTreeModel *model,
202 GtkTreePath *path,
203 GtkTreeIter *iter,
204 gpointer data)
205{
206 signal_monitor_generic_handler (m: data, signal: ROW_INSERTED,
207 model, iter, path, NULL);
208}
209
210static void
211signal_monitor_row_deleted (GtkTreeModel *model,
212 GtkTreePath *path,
213 gpointer data)
214{
215 signal_monitor_generic_handler (m: data, signal: ROW_DELETED,
216 model, NULL, path, NULL);
217}
218
219static void
220signal_monitor_row_changed (GtkTreeModel *model,
221 GtkTreePath *path,
222 GtkTreeIter *iter,
223 gpointer data)
224{
225 signal_monitor_generic_handler (m: data, signal: ROW_CHANGED,
226 model, iter, path, NULL);
227}
228
229static void
230signal_monitor_row_has_child_toggled (GtkTreeModel *model,
231 GtkTreePath *path,
232 GtkTreeIter *iter,
233 gpointer data)
234{
235 signal_monitor_generic_handler (m: data, signal: ROW_HAS_CHILD_TOGGLED,
236 model, iter, path, NULL);
237}
238
239static void
240signal_monitor_rows_reordered (GtkTreeModel *model,
241 GtkTreePath *path,
242 GtkTreeIter *iter,
243 int *new_order,
244 gpointer data)
245{
246 signal_monitor_generic_handler (m: data, signal: ROWS_REORDERED,
247 model, iter, path, new_order);
248}
249
250SignalMonitor *
251signal_monitor_new (GtkTreeModel *client)
252{
253 SignalMonitor *m;
254
255 m = g_new0 (SignalMonitor, 1);
256 m->client = g_object_ref (client);
257 m->queue = g_queue_new ();
258
259 m->signal_ids[ROW_INSERTED] = g_signal_connect (client,
260 "row-inserted",
261 G_CALLBACK (signal_monitor_row_inserted),
262 m);
263 m->signal_ids[ROW_DELETED] = g_signal_connect (client,
264 "row-deleted",
265 G_CALLBACK (signal_monitor_row_deleted),
266 m);
267 m->signal_ids[ROW_CHANGED] = g_signal_connect (client,
268 "row-changed",
269 G_CALLBACK (signal_monitor_row_changed),
270 m);
271 m->signal_ids[ROW_HAS_CHILD_TOGGLED] = g_signal_connect (client,
272 "row-has-child-toggled",
273 G_CALLBACK (signal_monitor_row_has_child_toggled),
274 m);
275 m->signal_ids[ROWS_REORDERED] = g_signal_connect (client,
276 "rows-reordered",
277 G_CALLBACK (signal_monitor_rows_reordered),
278 m);
279
280 return m;
281}
282
283void
284signal_monitor_free (SignalMonitor *m)
285{
286 int i;
287
288 for (i = 0; i < LAST_SIGNAL; i++)
289 g_signal_handler_disconnect (instance: m->client, handler_id: m->signal_ids[i]);
290
291 g_object_unref (object: m->client);
292
293 if (m->queue)
294 g_queue_free (queue: m->queue);
295
296 g_free (mem: m);
297}
298
299void
300signal_monitor_assert_is_empty (SignalMonitor *m)
301{
302 g_assert_true (g_queue_is_empty (m->queue));
303}
304
305void
306signal_monitor_append_signal_path (SignalMonitor *m,
307 SignalName signal,
308 GtkTreePath *path)
309{
310 Signal *s;
311
312 s = signal_new (signal, path);
313 g_queue_push_head (queue: m->queue, data: s);
314}
315
316void
317signal_monitor_append_signal_reordered (SignalMonitor *m,
318 SignalName signal,
319 GtkTreePath *path,
320 int *new_order,
321 int len)
322{
323 Signal *s;
324
325 s = signal_new_with_order (signal, path, new_order, len);
326 g_queue_push_head (queue: m->queue, data: s);
327}
328
329void
330signal_monitor_append_signal (SignalMonitor *m,
331 SignalName signal,
332 const char *path_string)
333{
334 Signal *s;
335 GtkTreePath *path;
336
337 path = gtk_tree_path_new_from_string (path: path_string);
338
339 s = signal_new (signal, path);
340 g_queue_push_head (queue: m->queue, data: s);
341
342 gtk_tree_path_free (path);
343}
344

source code of gtk/testsuite/gtk/treemodel.c