]> Pileus Git - ~andy/gtk/blob - tests/autotestfilechooser.c
7597bf52a5f8c45e39e83369815407bf6f933eca
[~andy/gtk] / tests / autotestfilechooser.c
1 /* GTK - The GIMP Toolkit
2  * autotestfilechooser.c: Automated unit tests for the GtkFileChooser widget
3  * Copyright (C) 2005, Novell, Inc.
4  *
5  * Authors:
6  *   Federico Mena-Quintero <federico@novell.com>
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Lesser General Public
10  * License as published by the Free Software Foundation; either
11  * version 2 of the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with this library; if not, write to the
20  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
21  * Boston, MA 02111-1307, USA.
22  */
23
24 #define GTK_FILE_SYSTEM_ENABLE_UNSUPPORTED
25
26 #include <config.h>
27 #include <glib/gprintf.h>
28 #include <gtk/gtk.h>
29 #include "gtk/gtkfilechooserprivate.h"
30 #include "gtk/gtkfilechooserdefault.h"
31 #include "gtk/gtkfilechooserentry.h"
32
33 static void
34 log_test (gboolean passed, const char *test_name, ...)
35 {
36   va_list args;
37   char *str;
38
39   va_start (args, test_name);
40   str = g_strdup_vprintf (test_name, args);
41   va_end (args);
42
43   g_printf ("%s: %s\n", passed ? "PASSED" : "FAILED", str);
44   g_free (str);
45 }
46
47 static const GtkFileChooserAction open_actions[] = {
48   GTK_FILE_CHOOSER_ACTION_OPEN,
49   GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER
50 };
51
52 static const GtkFileChooserAction save_actions[] = {
53   GTK_FILE_CHOOSER_ACTION_SAVE,
54   GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER
55 };
56
57
58 static gboolean
59 has_action (const GtkFileChooserAction *actions,
60             int n_actions,
61             GtkFileChooserAction sought_action)
62 {
63   int i;
64
65   for (i = 0; i < n_actions; i++)
66     if (actions[i] == sought_action)
67       return TRUE;
68
69   return FALSE;
70 }
71
72 static const char *
73 get_action_name (GtkFileChooserAction action)
74 {
75   GEnumClass *enum_class;
76   GEnumValue *enum_value;
77
78   enum_class = g_type_class_peek (GTK_TYPE_FILE_CHOOSER_ACTION);
79   if (!enum_class)
80     g_error ("BUG: get_action_name(): no GEnumClass for GTK_TYPE_FILE_CHOOSER_ACTION");
81
82   enum_value = g_enum_get_value (enum_class, (int) action);
83   if (!enum_value)
84     g_error ("BUG: get_action_name(): no GEnumValue for GtkFileChooserAction %d", (int) action);
85
86   return enum_value->value_name;
87 }
88
89 static GtkFileChooserDefault *
90 get_impl_from_dialog (GtkWidget *dialog)
91 {
92   GtkFileChooserDialog *d;
93   GtkFileChooserDialogPrivate *dialog_priv;
94   GtkFileChooserWidget *chooser_widget;
95   GtkFileChooserWidgetPrivate *widget_priv;
96   GtkFileChooserDefault *impl;
97
98   d = GTK_FILE_CHOOSER_DIALOG (dialog);
99   dialog_priv = d->priv;
100   chooser_widget = GTK_FILE_CHOOSER_WIDGET (dialog_priv->widget);
101   if (!chooser_widget)
102     g_error ("BUG: dialog_priv->widget is not a GtkFileChooserWidget");
103
104   widget_priv = chooser_widget->priv;
105   impl = (GtkFileChooserDefault *) (widget_priv->impl);
106   if (!impl)
107     g_error ("BUG: widget_priv->impl is not a GtkFileChooserDefault");
108
109   return impl;
110 }
111
112 static gboolean
113 test_widgets_for_current_action (GtkFileChooserDialog *dialog,
114                                  GtkFileChooserAction  expected_action)
115 {
116   GtkFileChooserDefault *impl;
117   gboolean passed;
118
119   if (gtk_file_chooser_get_action (GTK_FILE_CHOOSER (dialog)) != expected_action)
120     return FALSE;
121
122   impl = get_impl_from_dialog (GTK_WIDGET (dialog));
123
124   g_assert (impl->action == expected_action);
125
126   passed = TRUE;
127
128   /* OPEN implies that the "new folder" button is hidden; otherwise it is shown */
129   if (impl->action == GTK_FILE_CHOOSER_ACTION_OPEN)
130     passed = passed && !GTK_WIDGET_VISIBLE (impl->browse_new_folder_button);
131   else
132     passed = passed && GTK_WIDGET_VISIBLE (impl->browse_new_folder_button);
133
134   /* Check that the widgets are present/visible or not */
135   if (has_action (open_actions, G_N_ELEMENTS (open_actions), impl->action))
136     {
137       passed = passed && (impl->save_widgets == NULL
138                           && impl->save_file_name_entry == NULL
139                           && impl->save_folder_label == NULL
140                           && impl->save_folder_combo == NULL
141                           && impl->save_expander == NULL
142                           && GTK_IS_CONTAINER (impl->browse_widgets) && GTK_WIDGET_DRAWABLE (impl->browse_widgets));
143     }
144   else if (has_action (save_actions, G_N_ELEMENTS (save_actions), impl->action))
145     {
146       /* FIXME: we can't use GTK_IS_FILE_CHOOSER_ENTRY() because it uses
147        * _gtk_file_chooser_entry_get_type(), which is a non-exported symbol.
148        * So, we just test impl->save_file_name_entry for being non-NULL
149        */
150       passed = passed && (GTK_IS_CONTAINER (impl->save_widgets) && GTK_WIDGET_DRAWABLE (impl->save_widgets)
151                           && impl->save_file_name_entry != NULL && GTK_WIDGET_DRAWABLE (impl->save_file_name_entry)
152                           && GTK_IS_LABEL (impl->save_folder_label) && GTK_WIDGET_DRAWABLE (impl->save_folder_label)
153                           && GTK_IS_COMBO_BOX (impl->save_folder_combo) && GTK_WIDGET_DRAWABLE (impl->save_folder_combo)
154                           && GTK_IS_EXPANDER (impl->save_expander) && GTK_WIDGET_DRAWABLE (impl->save_expander)
155                           && GTK_IS_CONTAINER (impl->browse_widgets));
156
157       /* FIXME: we are in a SAVE mode; test the visibility and sensitivity of
158        * the children that change depending on the state of the expander.
159        */
160     }
161   else
162     {
163       g_error ("BAD TEST: test_widgets_for_current_action() doesn't know about %s", get_action_name (impl->action));
164       passed = FALSE;
165     }
166
167   return passed;
168 }
169
170 typedef gboolean (* ForeachActionCallback) (GtkFileChooserDialog *dialog,
171                                             GtkFileChooserAction  action,
172                                             gpointer              user_data);
173
174 static gboolean
175 foreach_action (GtkFileChooserDialog *dialog,
176                 ForeachActionCallback callback,
177                 gpointer              user_data)
178 {
179   GEnumClass *enum_class;
180   int i;
181
182   enum_class = g_type_class_peek (GTK_TYPE_FILE_CHOOSER_ACTION);
183   if (!enum_class)
184     g_error ("BUG: get_action_name(): no GEnumClass for GTK_TYPE_FILE_CHOOSER_ACTION");
185
186   for (i = 0; i < enum_class->n_values; i++)
187     {
188       GEnumValue *enum_value;
189       GtkFileChooserAction action;
190       gboolean passed;
191
192       enum_value = enum_class->values + i;
193       action = enum_value->value;
194
195       passed = (* callback) (dialog, action, user_data);
196       if (!passed)
197         return FALSE;
198     }
199
200   return TRUE;
201 }
202
203 struct action_closure {
204   GtkFileChooserAction from_action;
205 };
206
207 static gboolean
208 switch_from_to_action_cb (GtkFileChooserDialog *dialog,
209                           GtkFileChooserAction  action,
210                           gpointer              user_data)
211 {
212   struct action_closure *closure;
213   gboolean passed;
214
215   closure = user_data;
216
217   gtk_file_chooser_set_action (GTK_FILE_CHOOSER (dialog), closure->from_action);
218
219   passed = test_widgets_for_current_action (dialog, closure->from_action);
220   log_test (passed, "switch_from_to_action_cb(): reset to action %s", get_action_name (closure->from_action));
221   if (!passed)
222     return FALSE;
223
224   gtk_file_chooser_set_action (GTK_FILE_CHOOSER (dialog), action);
225
226   passed = test_widgets_for_current_action (dialog, action);
227   log_test (passed, "switch_from_to_action_cb(): transition from %s to %s",
228             get_action_name (closure->from_action),
229             get_action_name (action));
230   return passed;
231 }
232
233 static gboolean
234 switch_from_action_cb (GtkFileChooserDialog *dialog,
235                        GtkFileChooserAction  action,
236                        gpointer              user_data)
237 {
238   struct action_closure closure;
239
240   closure.from_action = action;
241
242   return foreach_action (dialog, switch_from_to_action_cb, &closure);
243 }
244
245 static gboolean
246 test_action_widgets (void)
247 {
248   GtkWidget *dialog;
249   GtkFileChooserAction action;
250   gboolean passed;
251
252   dialog = gtk_file_chooser_dialog_new ("Test file chooser",
253                                         NULL,
254                                         GTK_FILE_CHOOSER_ACTION_OPEN,
255                                         GTK_STOCK_CANCEL,
256                                         GTK_RESPONSE_CANCEL,
257                                         GTK_STOCK_OK,
258                                         GTK_RESPONSE_ACCEPT,
259                                         NULL);
260   gtk_widget_show_now (dialog);
261
262   action = gtk_file_chooser_get_action (GTK_FILE_CHOOSER (dialog));
263
264   passed = test_widgets_for_current_action (GTK_FILE_CHOOSER_DIALOG (dialog), action);
265   log_test (passed, "test_action_widgets(): widgets for initial action %s", get_action_name (action));
266   if (!passed)
267     return FALSE;
268
269   passed = foreach_action (GTK_FILE_CHOOSER_DIALOG (dialog), switch_from_action_cb, NULL);
270   log_test (passed, "test_action_widgets(): all transitions through property change");
271
272   gtk_widget_destroy (dialog);
273
274   return passed;
275 }
276
277 static gboolean
278 test_reload_sequence (gboolean set_folder_before_map)
279 {
280   GtkWidget *dialog;
281   GtkFileChooserDefault *impl;
282   gboolean passed;
283
284   passed = TRUE;
285
286   dialog = gtk_file_chooser_dialog_new ("Test file chooser",
287                                         NULL,
288                                         GTK_FILE_CHOOSER_ACTION_OPEN,
289                                         GTK_STOCK_CANCEL,
290                                         GTK_RESPONSE_CANCEL,
291                                         GTK_STOCK_OK,
292                                         GTK_RESPONSE_ACCEPT,
293                                         NULL);
294   impl = get_impl_from_dialog (dialog);
295
296   if (set_folder_before_map)
297     {
298       gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (dialog), g_get_home_dir ());
299
300       passed = (impl->current_folder != NULL
301                 && impl->browse_files_model != NULL
302                 && (impl->load_state == LOAD_PRELOAD || impl->load_state == LOAD_LOADING || impl->load_state == LOAD_FINISHED)
303                 && impl->reload_state == RELOAD_HAS_FOLDER
304                 && (impl->load_state == LOAD_PRELOAD ? (impl->load_timeout_id != 0) : TRUE)
305                 && ((impl->load_state == LOAD_LOADING || impl->load_state == LOAD_FINISHED)
306                     ? (impl->load_timeout_id == 0 && impl->sort_model != NULL)
307                     : TRUE));
308     }
309   else
310     {
311       /* Initially, no folder is not loaded or pending */
312       passed = passed && (impl->current_folder == NULL
313                           && impl->sort_model == NULL
314                           && impl->browse_files_model == NULL
315                           && impl->load_state == LOAD_EMPTY
316                           && impl->reload_state == RELOAD_EMPTY
317                           && impl->load_timeout_id == 0);
318     }
319
320   if (!passed)
321     return FALSE;
322
323   /* After mapping, it is loading some folder, either the one that was explicitly set or the default one */
324
325   gtk_widget_show_now (dialog);
326
327   passed = (impl->current_folder != NULL
328             && impl->browse_files_model != NULL
329             && (impl->load_state == LOAD_PRELOAD || impl->load_state == LOAD_LOADING || impl->load_state == LOAD_FINISHED)
330             && impl->reload_state == RELOAD_HAS_FOLDER
331             && (impl->load_state == LOAD_PRELOAD ? (impl->load_timeout_id != 0) : TRUE)
332             && ((impl->load_state == LOAD_LOADING || impl->load_state == LOAD_FINISHED)
333                 ? (impl->load_timeout_id == 0 && impl->sort_model != NULL)
334                 : TRUE));
335   if (!passed)
336     return FALSE;
337
338   /* Unmap it; we should still have a folder */
339
340   gtk_widget_hide (dialog);
341
342   passed = (impl->current_folder != NULL
343             && impl->browse_files_model != NULL
344             && (impl->load_state == LOAD_PRELOAD || impl->load_state == LOAD_LOADING || impl->load_state == LOAD_FINISHED)
345             && impl->reload_state == RELOAD_WAS_UNMAPPED
346             && (impl->load_state == LOAD_PRELOAD ? (impl->load_timeout_id != 0) : TRUE)
347             && ((impl->load_state == LOAD_LOADING || impl->load_state == LOAD_FINISHED)
348                 ? (impl->load_timeout_id == 0 && impl->sort_model != NULL)
349                 : TRUE));
350   if (!passed)
351     return FALSE;
352
353   /* Map it again! */
354
355   gtk_widget_show_now (dialog);
356   
357   passed = (impl->current_folder != NULL
358             && impl->browse_files_model != NULL
359             && (impl->load_state == LOAD_PRELOAD || impl->load_state == LOAD_LOADING || impl->load_state == LOAD_FINISHED)
360             && impl->reload_state == RELOAD_HAS_FOLDER
361             && (impl->load_state == LOAD_PRELOAD ? (impl->load_timeout_id != 0) : TRUE)
362             && ((impl->load_state == LOAD_LOADING || impl->load_state == LOAD_FINISHED)
363                 ? (impl->load_timeout_id == 0 && impl->sort_model != NULL)
364                 : TRUE));
365   if (!passed)
366     return FALSE;
367
368   gtk_widget_destroy (dialog);
369
370   return passed;
371 }
372
373 static gboolean
374 test_reload (void)
375 {
376   gboolean passed;
377
378   passed = test_reload_sequence (FALSE);
379   log_test (passed, "test_reload(): create and use the default folder");
380   if (!passed)
381     return FALSE;
382
383   passed = test_reload_sequence (TRUE);
384   log_test (passed, "test_reload(): set a folder explicitly before mapping");
385
386   return passed;
387 }
388
389 int
390 main (int argc, char **argv)
391 {
392   gtk_init (&argc, &argv);
393
394   test_action_widgets ();
395   test_reload ();
396
397   return 0;
398 }