346 lines
		
	
	
		
			9.0 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			346 lines
		
	
	
		
			9.0 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /* Main wrapper for TreeModel test suite.
 | |
|  * Copyright (C) 2011  Kristian Rietveld  <kris@gtk.org>
 | |
|  *
 | |
|  * This library is free software; you can redistribute it and/or
 | |
|  * modify it under the terms of the GNU Lesser General Public
 | |
|  * License as published by the Free Software Foundation; either
 | |
|  * version 2 of the License, or (at your option) any later version.
 | |
|  *
 | |
|  * This library is distributed in the hope that it will be useful,
 | |
|  * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | |
|  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 | |
|  * Lesser General Public License for more details.
 | |
|  *
 | |
|  * You should have received a copy of the GNU Lesser General Public
 | |
|  * License along with this library. If not, see <http://www.gnu.org/licenses/>.
 | |
|  */
 | |
| 
 | |
| #include <gtk/gtk.h>
 | |
| 
 | |
| #include "treemodel.h"
 | |
| 
 | |
| int
 | |
| main (int    argc,
 | |
|       char **argv)
 | |
| {
 | |
|   gtk_test_init (&argc, &argv, NULL);
 | |
| 
 | |
|   g_test_bug_base ("http://bugzilla.gnome.org/");
 | |
| 
 | |
|   register_list_store_tests ();
 | |
|   register_tree_store_tests ();
 | |
|   register_model_ref_count_tests ();
 | |
|   register_sort_model_tests ();
 | |
|   register_filter_model_tests ();
 | |
| 
 | |
|   return g_test_run ();
 | |
| }
 | |
| 
 | |
| /*
 | |
|  * Signal monitor
 | |
|  */
 | |
| 
 | |
| static const char *
 | |
| signal_name_to_string (SignalName signal)
 | |
| {
 | |
|   switch (signal)
 | |
|     {
 | |
|       case ROW_INSERTED:
 | |
|           return "row-inserted";
 | |
| 
 | |
|       case ROW_DELETED:
 | |
|           return "row-deleted";
 | |
| 
 | |
|       case ROW_CHANGED:
 | |
|           return "row-changed";
 | |
| 
 | |
|       case ROW_HAS_CHILD_TOGGLED:
 | |
|           return "row-has-child-toggled";
 | |
| 
 | |
|       case ROWS_REORDERED:
 | |
|           return "rows-reordered";
 | |
| 
 | |
|       default:
 | |
|           /* Fall through */
 | |
|           break;
 | |
|     }
 | |
| 
 | |
|   return "(unknown)";
 | |
| }
 | |
| 
 | |
| typedef struct
 | |
| {
 | |
|   SignalName signal;
 | |
|   GtkTreePath *path;
 | |
| 
 | |
|   /* For rows-reordered */
 | |
|   int *new_order;
 | |
|   int len;
 | |
| }
 | |
| Signal;
 | |
| 
 | |
| 
 | |
| static Signal *
 | |
| signal_new (SignalName signal, GtkTreePath *path)
 | |
| {
 | |
|   Signal *s;
 | |
| 
 | |
|   s = g_new0 (Signal, 1);
 | |
|   s->signal = signal;
 | |
|   s->path = gtk_tree_path_copy (path);
 | |
|   s->new_order = NULL;
 | |
| 
 | |
|   return s;
 | |
| }
 | |
| 
 | |
| static Signal *
 | |
| signal_new_with_order (SignalName signal, GtkTreePath *path,
 | |
|                        int *new_order, int len)
 | |
| {
 | |
|   Signal *s = signal_new (signal, path);
 | |
| 
 | |
|   s->new_order = new_order;
 | |
|   s->len = len;
 | |
| 
 | |
|   return s;
 | |
| }
 | |
| 
 | |
| static void
 | |
| signal_free (Signal *s)
 | |
| {
 | |
|   if (s->path)
 | |
|     gtk_tree_path_free (s->path);
 | |
| 
 | |
|   g_free (s);
 | |
| }
 | |
| 
 | |
| 
 | |
| struct _SignalMonitor
 | |
| {
 | |
|   GQueue *queue;
 | |
|   GtkTreeModel *client;
 | |
|   gulong signal_ids[LAST_SIGNAL];
 | |
| };
 | |
| 
 | |
| 
 | |
| static void
 | |
| signal_monitor_generic_handler (SignalMonitor *m,
 | |
|                                 SignalName     signal,
 | |
|                                 GtkTreeModel  *model,
 | |
|                                 GtkTreeIter   *iter,
 | |
|                                 GtkTreePath   *path,
 | |
|                                 int           *new_order)
 | |
| {
 | |
|   Signal *s;
 | |
| 
 | |
|   if (g_queue_is_empty (m->queue))
 | |
|     {
 | |
|       gchar *path_str;
 | |
| 
 | |
|       path_str = gtk_tree_path_to_string (path);
 | |
|       g_error ("Signal queue empty, got signal %s path %s",
 | |
|                signal_name_to_string (signal), path_str);
 | |
|       g_free (path_str);
 | |
| 
 | |
|       g_assert_not_reached ();
 | |
|     }
 | |
| 
 | |
|   if (m->client != model)
 | |
|     {
 | |
|       g_error ("Model mismatch; expected %p, got %p",
 | |
|                m->client, model);
 | |
|       g_assert_not_reached ();
 | |
|     }
 | |
| 
 | |
|   s = g_queue_peek_tail (m->queue);
 | |
| 
 | |
| #if 0
 | |
|   /* For debugging: output signals that are coming in.  Leaks memory. */
 | |
|   g_print ("signal=%s path=%s\n", signal_name_to_string (signal),
 | |
|            gtk_tree_path_to_string (path));
 | |
| #endif
 | |
| 
 | |
|   if (s->signal != signal ||
 | |
|       (gtk_tree_path_get_depth (s->path) == 0 &&
 | |
|        gtk_tree_path_get_depth (path) != 0) ||
 | |
|       (gtk_tree_path_get_depth (s->path) != 0 &&
 | |
|        gtk_tree_path_compare (s->path, path) != 0))
 | |
|     {
 | |
|       gchar *path_str, *s_path_str;
 | |
| 
 | |
|       s_path_str = gtk_tree_path_to_string (s->path);
 | |
|       path_str = gtk_tree_path_to_string (path);
 | |
| 
 | |
|       g_error ("Signals don't match; expected signal %s path %s, got signal %s path %s",
 | |
|                signal_name_to_string (s->signal), s_path_str,
 | |
|                signal_name_to_string (signal), path_str);
 | |
| 
 | |
|       g_free (s_path_str);
 | |
|       g_free (path_str);
 | |
| 
 | |
|       g_assert_not_reached ();
 | |
|     }
 | |
| 
 | |
|   if (signal == ROWS_REORDERED && s->new_order != NULL)
 | |
|     {
 | |
|       int i, len;
 | |
| 
 | |
|       g_assert (new_order != NULL);
 | |
| 
 | |
|       len = gtk_tree_model_iter_n_children (model, iter);
 | |
|       g_assert (s->len == len);
 | |
| 
 | |
|       for (i = 0; i < len; i++)
 | |
|         g_assert (s->new_order[i] == new_order[i]);
 | |
|     }
 | |
| 
 | |
|   s = g_queue_pop_tail (m->queue);
 | |
| 
 | |
|   signal_free (s);
 | |
| }
 | |
| 
 | |
| static void
 | |
| signal_monitor_row_inserted (GtkTreeModel *model,
 | |
|                              GtkTreePath  *path,
 | |
|                              GtkTreeIter  *iter,
 | |
|                              gpointer      data)
 | |
| {
 | |
|   signal_monitor_generic_handler (data, ROW_INSERTED,
 | |
|                                   model, iter, path, NULL);
 | |
| }
 | |
| 
 | |
| static void
 | |
| signal_monitor_row_deleted (GtkTreeModel *model,
 | |
|                             GtkTreePath  *path,
 | |
|                             gpointer      data)
 | |
| {
 | |
|   signal_monitor_generic_handler (data, ROW_DELETED,
 | |
|                                   model, NULL, path, NULL);
 | |
| }
 | |
| 
 | |
| static void
 | |
| signal_monitor_row_changed (GtkTreeModel *model,
 | |
|                             GtkTreePath  *path,
 | |
|                             GtkTreeIter  *iter,
 | |
|                             gpointer      data)
 | |
| {
 | |
|   signal_monitor_generic_handler (data, ROW_CHANGED,
 | |
|                                   model, iter, path, NULL);
 | |
| }
 | |
| 
 | |
| static void
 | |
| signal_monitor_row_has_child_toggled (GtkTreeModel *model,
 | |
|                                       GtkTreePath  *path,
 | |
|                                       GtkTreeIter  *iter,
 | |
|                                       gpointer      data)
 | |
| {
 | |
|   signal_monitor_generic_handler (data, ROW_HAS_CHILD_TOGGLED,
 | |
|                                   model, iter, path, NULL);
 | |
| }
 | |
| 
 | |
| static void
 | |
| signal_monitor_rows_reordered (GtkTreeModel *model,
 | |
|                                GtkTreePath  *path,
 | |
|                                GtkTreeIter  *iter,
 | |
|                                gint         *new_order,
 | |
|                                gpointer      data)
 | |
| {
 | |
|   signal_monitor_generic_handler (data, ROWS_REORDERED,
 | |
|                                   model, iter, path, new_order);
 | |
| }
 | |
| 
 | |
| SignalMonitor *
 | |
| signal_monitor_new (GtkTreeModel *client)
 | |
| {
 | |
|   SignalMonitor *m;
 | |
| 
 | |
|   m = g_new0 (SignalMonitor, 1);
 | |
|   m->client = g_object_ref (client);
 | |
|   m->queue = g_queue_new ();
 | |
| 
 | |
|   m->signal_ids[ROW_INSERTED] = g_signal_connect (client,
 | |
|                                                   "row-inserted",
 | |
|                                                   G_CALLBACK (signal_monitor_row_inserted),
 | |
|                                                   m);
 | |
|   m->signal_ids[ROW_DELETED] = g_signal_connect (client,
 | |
|                                                  "row-deleted",
 | |
|                                                  G_CALLBACK (signal_monitor_row_deleted),
 | |
|                                                  m);
 | |
|   m->signal_ids[ROW_CHANGED] = g_signal_connect (client,
 | |
|                                                  "row-changed",
 | |
|                                                  G_CALLBACK (signal_monitor_row_changed),
 | |
|                                                  m);
 | |
|   m->signal_ids[ROW_HAS_CHILD_TOGGLED] = g_signal_connect (client,
 | |
|                                                            "row-has-child-toggled",
 | |
|                                                            G_CALLBACK (signal_monitor_row_has_child_toggled),
 | |
|                                                            m);
 | |
|   m->signal_ids[ROWS_REORDERED] = g_signal_connect (client,
 | |
|                                                     "rows-reordered",
 | |
|                                                     G_CALLBACK (signal_monitor_rows_reordered),
 | |
|                                                     m);
 | |
| 
 | |
|   return m;
 | |
| }
 | |
| 
 | |
| void
 | |
| signal_monitor_free (SignalMonitor *m)
 | |
| {
 | |
|   int i;
 | |
| 
 | |
|   for (i = 0; i < LAST_SIGNAL; i++)
 | |
|     g_signal_handler_disconnect (m->client, m->signal_ids[i]);
 | |
| 
 | |
|   g_object_unref (m->client);
 | |
| 
 | |
|   if (m->queue)
 | |
|     g_queue_free (m->queue);
 | |
| 
 | |
|   g_free (m);
 | |
| }
 | |
| 
 | |
| void
 | |
| signal_monitor_assert_is_empty (SignalMonitor *m)
 | |
| {
 | |
|   g_assert (g_queue_is_empty (m->queue));
 | |
| }
 | |
| 
 | |
| void
 | |
| signal_monitor_append_signal_path (SignalMonitor *m,
 | |
|                                    SignalName     signal,
 | |
|                                    GtkTreePath   *path)
 | |
| {
 | |
|   Signal *s;
 | |
| 
 | |
|   s = signal_new (signal, path);
 | |
|   g_queue_push_head (m->queue, s);
 | |
| }
 | |
| 
 | |
| void
 | |
| signal_monitor_append_signal_reordered (SignalMonitor *m,
 | |
|                                         SignalName     signal,
 | |
|                                         GtkTreePath   *path,
 | |
|                                         int           *new_order,
 | |
|                                         int            len)
 | |
| {
 | |
|   Signal *s;
 | |
| 
 | |
|   s = signal_new_with_order (signal, path, new_order, len);
 | |
|   g_queue_push_head (m->queue, s);
 | |
| }
 | |
| 
 | |
| void
 | |
| signal_monitor_append_signal (SignalMonitor *m,
 | |
|                               SignalName     signal,
 | |
|                               const gchar   *path_string)
 | |
| {
 | |
|   Signal *s;
 | |
|   GtkTreePath *path;
 | |
| 
 | |
|   path = gtk_tree_path_new_from_string (path_string);
 | |
| 
 | |
|   s = signal_new (signal, path);
 | |
|   g_queue_push_head (m->queue, s);
 | |
| 
 | |
|   gtk_tree_path_free (path);
 | |
| }
 | 
