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