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
22 int
main(int argc,char ** argv)23 main (int argc,
24 char **argv)
25 {
26 gtk_test_init (&argc, &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
41 static const char *
signal_name_to_string(SignalName signal)42 signal_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
69 typedef struct
70 {
71 SignalName signal;
72 GtkTreePath *path;
73
74 /* For rows-reordered */
75 int *new_order;
76 int len;
77 }
78 Signal;
79
80
81 static Signal *
signal_new(SignalName signal,GtkTreePath * path)82 signal_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
94 static Signal *
signal_new_with_order(SignalName signal,GtkTreePath * path,int * new_order,int len)95 signal_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
106 static void
signal_free(Signal * s)107 signal_free (Signal *s)
108 {
109 if (s->path)
110 gtk_tree_path_free (s->path);
111
112 g_free (s);
113 }
114
115
116 struct _SignalMonitor
117 {
118 GQueue *queue;
119 GtkTreeModel *client;
120 gulong signal_ids[LAST_SIGNAL];
121 };
122
123
124 static void
signal_monitor_generic_handler(SignalMonitor * m,SignalName signal,GtkTreeModel * model,GtkTreeIter * iter,GtkTreePath * path,int * new_order)125 signal_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 (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 (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 (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 (s->path) == 0 &&
163 gtk_tree_path_get_depth (path) != 0) ||
164 (gtk_tree_path_get_depth (s->path) != 0 &&
165 gtk_tree_path_compare (s->path, path) != 0))
166 {
167 char *path_str, *s_path_str;
168
169 s_path_str = gtk_tree_path_to_string (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 (s_path_str);
177 g_free (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 (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 (m->queue);
196
197 signal_free (s);
198 }
199
200 static void
signal_monitor_row_inserted(GtkTreeModel * model,GtkTreePath * path,GtkTreeIter * iter,gpointer data)201 signal_monitor_row_inserted (GtkTreeModel *model,
202 GtkTreePath *path,
203 GtkTreeIter *iter,
204 gpointer data)
205 {
206 signal_monitor_generic_handler (data, ROW_INSERTED,
207 model, iter, path, NULL);
208 }
209
210 static void
signal_monitor_row_deleted(GtkTreeModel * model,GtkTreePath * path,gpointer data)211 signal_monitor_row_deleted (GtkTreeModel *model,
212 GtkTreePath *path,
213 gpointer data)
214 {
215 signal_monitor_generic_handler (data, ROW_DELETED,
216 model, NULL, path, NULL);
217 }
218
219 static void
signal_monitor_row_changed(GtkTreeModel * model,GtkTreePath * path,GtkTreeIter * iter,gpointer data)220 signal_monitor_row_changed (GtkTreeModel *model,
221 GtkTreePath *path,
222 GtkTreeIter *iter,
223 gpointer data)
224 {
225 signal_monitor_generic_handler (data, ROW_CHANGED,
226 model, iter, path, NULL);
227 }
228
229 static void
signal_monitor_row_has_child_toggled(GtkTreeModel * model,GtkTreePath * path,GtkTreeIter * iter,gpointer data)230 signal_monitor_row_has_child_toggled (GtkTreeModel *model,
231 GtkTreePath *path,
232 GtkTreeIter *iter,
233 gpointer data)
234 {
235 signal_monitor_generic_handler (data, ROW_HAS_CHILD_TOGGLED,
236 model, iter, path, NULL);
237 }
238
239 static void
signal_monitor_rows_reordered(GtkTreeModel * model,GtkTreePath * path,GtkTreeIter * iter,int * new_order,gpointer data)240 signal_monitor_rows_reordered (GtkTreeModel *model,
241 GtkTreePath *path,
242 GtkTreeIter *iter,
243 int *new_order,
244 gpointer data)
245 {
246 signal_monitor_generic_handler (data, ROWS_REORDERED,
247 model, iter, path, new_order);
248 }
249
250 SignalMonitor *
signal_monitor_new(GtkTreeModel * client)251 signal_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
283 void
signal_monitor_free(SignalMonitor * m)284 signal_monitor_free (SignalMonitor *m)
285 {
286 int i;
287
288 for (i = 0; i < LAST_SIGNAL; i++)
289 g_signal_handler_disconnect (m->client, m->signal_ids[i]);
290
291 g_object_unref (m->client);
292
293 if (m->queue)
294 g_queue_free (m->queue);
295
296 g_free (m);
297 }
298
299 void
signal_monitor_assert_is_empty(SignalMonitor * m)300 signal_monitor_assert_is_empty (SignalMonitor *m)
301 {
302 g_assert_true (g_queue_is_empty (m->queue));
303 }
304
305 void
signal_monitor_append_signal_path(SignalMonitor * m,SignalName signal,GtkTreePath * path)306 signal_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 (m->queue, s);
314 }
315
316 void
signal_monitor_append_signal_reordered(SignalMonitor * m,SignalName signal,GtkTreePath * path,int * new_order,int len)317 signal_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 (m->queue, s);
327 }
328
329 void
signal_monitor_append_signal(SignalMonitor * m,SignalName signal,const char * path_string)330 signal_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_string);
338
339 s = signal_new (signal, path);
340 g_queue_push_head (m->queue, s);
341
342 gtk_tree_path_free (path);
343 }
344