]> Pileus Git - ~andy/gtk/blob - tests/autotestfilechooser.c
Reset the internal response_requested flag, once the response triggered by file_choos...
[~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 /* TODO:
25  *
26  * - In test_reload_sequence(), test that the selection is preserved properly
27  *   between unmap/map.
28  *
29  * - More tests!
30  */
31
32 #define GTK_FILE_SYSTEM_ENABLE_UNSUPPORTED
33
34 #include <config.h>
35 #include <string.h>
36 #include <glib/gprintf.h>
37 #include <gtk/gtk.h>
38 #include "gtk/gtkfilechooserprivate.h"
39 #include "gtk/gtkfilechooserdefault.h"
40 #include "gtk/gtkfilechooserentry.h"
41
42 static void
43 log_test (gboolean passed, const char *test_name, ...)
44 {
45   va_list args;
46   char *str;
47
48   va_start (args, test_name);
49   str = g_strdup_vprintf (test_name, args);
50   va_end (args);
51
52   g_printf ("%s: %s\n", passed ? "PASSED" : "FAILED", str);
53   g_free (str);
54 }
55
56 typedef void (* SetFilenameFn) (GtkFileChooser *chooser, gpointer data);
57 typedef gboolean (* CompareFilenameFn) (GtkFileChooser *chooser, gpointer data);
58
59 struct test_set_filename_closure {
60   GtkWidget *chooser;
61   GtkWidget *accept_button;
62   gboolean focus_button;
63 };
64
65 static gboolean
66 set_filename_timeout_cb (gpointer data)
67 {
68   struct test_set_filename_closure *closure;
69
70   closure = data;
71
72   if (closure->focus_button)
73     gtk_widget_grab_focus (closure->accept_button);
74
75   gtk_button_clicked (GTK_BUTTON (closure->accept_button));
76
77   return FALSE;
78 }
79
80
81 static guint wait_for_idle_id = 0;
82
83 static gboolean
84 wait_for_idle_idle (gpointer data)
85 {
86   wait_for_idle_id = 0;
87
88   return FALSE;
89 }
90
91 static void
92 wait_for_idle (void)
93 {
94   wait_for_idle_id = g_idle_add_full (G_PRIORITY_LOW + 100,
95                                       wait_for_idle_idle,
96                                       NULL, NULL);
97
98   while (wait_for_idle_id)
99     gtk_main_iteration ();
100 }
101
102 static gboolean
103 test_set_filename (GtkFileChooserAction action,
104                    gboolean focus_button,
105                    SetFilenameFn set_filename_fn,const
106                    CompareFilenameFn compare_filename_fn,
107                    gpointer data)
108 {
109   GtkWidget *chooser;
110   struct test_set_filename_closure closure;
111   gboolean retval;
112
113   chooser = gtk_file_chooser_dialog_new ("hello", NULL, action,
114                                          GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
115                                          NULL);
116
117   closure.chooser = chooser;
118   closure.accept_button = gtk_dialog_add_button (GTK_DIALOG (chooser), GTK_STOCK_OK, GTK_RESPONSE_ACCEPT);
119   closure.focus_button = focus_button;
120
121   gtk_dialog_set_default_response (GTK_DIALOG (chooser), GTK_RESPONSE_ACCEPT);
122
123   (* set_filename_fn) (GTK_FILE_CHOOSER (chooser), data);
124
125   gdk_threads_add_timeout (2000, set_filename_timeout_cb, &closure);
126   gtk_dialog_run (GTK_DIALOG (chooser));
127
128   retval = (* compare_filename_fn) (GTK_FILE_CHOOSER (chooser), data);
129
130   gtk_widget_destroy (chooser);
131
132   return retval;
133 }
134
135 static void
136 set_filename_cb (GtkFileChooser *chooser, gpointer data)
137 {
138   const char *filename;
139
140   filename = data;
141   gtk_file_chooser_set_filename (chooser, filename);
142 }
143
144 static gboolean
145 compare_filename_cb (GtkFileChooser *chooser, gpointer data)
146 {
147   const char *filename;
148   char *out_filename;
149   gboolean retval;
150
151   filename = data;
152   out_filename = gtk_file_chooser_get_filename (chooser);
153
154   if (out_filename)
155     {
156       retval = (strcmp (out_filename, filename) == 0);
157       g_free (out_filename);
158     } else
159       retval = FALSE;
160
161   return retval;
162 }
163
164 static gboolean
165 test_black_box_set_filename (GtkFileChooserAction action, const char *filename, gboolean focus_button)
166 {
167   gboolean passed;
168
169   passed = test_set_filename (action, focus_button, set_filename_cb, compare_filename_cb, (char *) filename);
170
171   log_test (passed, "set_filename: action %d, focus_button=%s",
172             (int) action,
173             focus_button ? "TRUE" : "FALSE");
174
175   return passed;
176
177 }
178
179 struct current_name_closure {
180         const char *path;
181         const char *current_name;
182 };
183
184 static void
185 set_current_name_cb (GtkFileChooser *chooser, gpointer data)
186 {
187   struct current_name_closure *closure;
188
189   closure = data;
190
191   gtk_file_chooser_set_current_folder (chooser, closure->path);
192   gtk_file_chooser_set_current_name (chooser, closure->current_name);
193 }
194
195 static gboolean
196 compare_current_name_cb (GtkFileChooser *chooser, gpointer data)
197 {
198   struct current_name_closure *closure;
199   char *out_filename;
200   gboolean retval;
201
202   closure = data;
203
204   out_filename = gtk_file_chooser_get_filename (chooser);
205
206   if (out_filename)
207     {
208       char *filename;
209
210       filename = g_build_filename (closure->path, closure->current_name, NULL);
211       retval = (strcmp (filename, out_filename) == 0);
212       g_free (filename);
213       g_free (out_filename);
214     } else
215       retval = FALSE;
216
217   return retval;
218 }
219
220 static gboolean
221 test_black_box_set_current_name (const char *path, const char *current_name, gboolean focus_button)
222 {
223   struct current_name_closure closure;
224   gboolean passed;
225
226   closure.path = path;
227   closure.current_name = current_name;
228
229   passed = test_set_filename (GTK_FILE_CHOOSER_ACTION_SAVE, focus_button,
230                               set_current_name_cb, compare_current_name_cb, &closure);
231
232   log_test (passed, "set_current_name, focus_button=%s", focus_button ? "TRUE" : "FALSE");
233
234   return passed;
235 }
236
237 /* FIXME: fails in CREATE_FOLDER mode when FOLDER_NAME == "/" */
238
239 #if 0
240 #define FILE_NAME "/nonexistent"
241 #define FOLDER_NAME "/etc"
242 #else
243 #define FILE_NAME "/etc/passwd"
244 #define FOLDER_NAME "/etc"
245 #endif
246
247 #define CURRENT_NAME "parangaricutirimicuaro.txt"
248
249 /* https://bugzilla.novell.com/show_bug.cgi?id=184875
250  * http://bugzilla.gnome.org/show_bug.cgi?id=347066
251  */
252 static gboolean
253 test_black_box (void)
254 {
255   gboolean passed;
256   char *cwd;
257
258   passed = TRUE;
259
260   passed = passed && test_black_box_set_filename (GTK_FILE_CHOOSER_ACTION_OPEN, FILE_NAME, FALSE);
261   passed = passed && test_black_box_set_filename (GTK_FILE_CHOOSER_ACTION_OPEN, FILE_NAME, TRUE);
262   passed = passed && test_black_box_set_filename (GTK_FILE_CHOOSER_ACTION_SAVE, FILE_NAME, FALSE);
263   passed = passed && test_black_box_set_filename (GTK_FILE_CHOOSER_ACTION_SAVE, FILE_NAME, TRUE);
264   passed = passed && test_black_box_set_filename (GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER, FOLDER_NAME, FALSE);
265   passed = passed && test_black_box_set_filename (GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER, FOLDER_NAME, TRUE);
266   passed = passed && test_black_box_set_filename (GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER, FOLDER_NAME, FALSE);
267   passed = passed && test_black_box_set_filename (GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER, FOLDER_NAME, TRUE);
268
269   cwd = g_get_current_dir ();
270
271   passed = passed && test_black_box_set_current_name (cwd, CURRENT_NAME, FALSE);
272   passed = passed && test_black_box_set_current_name (cwd, CURRENT_NAME, TRUE);
273
274   g_free (cwd);
275
276   log_test (passed, "Black box tests");
277
278   return passed;
279 }
280
281 struct confirm_overwrite_closure {
282   GtkWidget *chooser;
283   GtkWidget *accept_button;
284   gint confirm_overwrite_signal_emitted;
285   gchar *extension;
286 };
287
288 static GtkFileChooserConfirmation
289 confirm_overwrite_cb (GtkFileChooser *chooser, gpointer data)
290 {
291   struct confirm_overwrite_closure *closure = data;
292
293   printf ("bling!\n");
294   closure->confirm_overwrite_signal_emitted += 1;
295
296   return GTK_FILE_CHOOSER_CONFIRMATION_ACCEPT_FILENAME;
297 }
298
299 static void
300 overwrite_response_cb (GtkFileChooser *chooser, gint response, gpointer data)
301 {
302   struct confirm_overwrite_closure *closure = data;
303   char *filename;
304
305   printf ("plong!\n");
306
307   if (response != GTK_RESPONSE_ACCEPT)
308     return;
309
310   filename = gtk_file_chooser_get_filename (chooser);
311
312   if (!g_str_has_suffix (filename, closure->extension))
313     {
314       char *basename;
315
316       basename = g_path_get_basename (filename);
317       g_free (filename);
318
319       filename = g_strconcat (basename, closure->extension, NULL);
320       gtk_file_chooser_set_current_name (chooser, filename);
321
322       g_signal_stop_emission_by_name (chooser, "response");
323       gtk_dialog_response (GTK_DIALOG (chooser), GTK_RESPONSE_ACCEPT);
324     }
325 }
326
327 static gboolean
328 confirm_overwrite_timeout_cb (gpointer data)
329 {
330   struct confirm_overwrite_closure *closure;
331
332   closure = data;
333   gtk_button_clicked (GTK_BUTTON (closure->accept_button));
334
335   return FALSE;
336 }
337
338 /* http://bugzilla.gnome.org/show_bug.cgi?id=347883 */
339 static gboolean
340 test_confirm_overwrite_for_path (const char *path, gboolean append_extension)
341 {
342   gboolean passed;
343   struct confirm_overwrite_closure closure;
344   char *filename;
345
346   passed = TRUE;
347
348   closure.extension = NULL;
349   closure.confirm_overwrite_signal_emitted = 0;
350   closure.chooser = gtk_file_chooser_dialog_new ("hello", NULL, GTK_FILE_CHOOSER_ACTION_SAVE,
351                                                  GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
352                                                  NULL);
353   closure.accept_button = gtk_dialog_add_button (GTK_DIALOG (closure.chooser),
354                                                  GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT);
355   gtk_dialog_set_default_response (GTK_DIALOG (closure.chooser), GTK_RESPONSE_ACCEPT);
356
357   gtk_file_chooser_set_do_overwrite_confirmation (GTK_FILE_CHOOSER (closure.chooser), TRUE);
358
359   g_signal_connect (closure.chooser, "confirm-overwrite",
360                     G_CALLBACK (confirm_overwrite_cb), &closure);
361
362   if (append_extension)
363     {
364       char *extension;
365
366       filename = g_path_get_dirname (path);
367       gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (closure.chooser), filename);
368       g_free (filename);
369
370       filename = g_path_get_basename (path);
371       extension = strchr (filename, '.');
372
373       if (extension)
374         {
375           closure.extension = g_strdup (extension);
376           *extension = '\0';
377         }
378
379       gtk_file_chooser_set_current_name (GTK_FILE_CHOOSER (closure.chooser), filename);
380       g_free (filename);
381
382       g_signal_connect (closure.chooser, "response",
383                         G_CALLBACK (overwrite_response_cb), &closure);
384     }
385   else
386     {
387       gtk_file_chooser_set_filename (GTK_FILE_CHOOSER (closure.chooser), path);
388     }
389
390   gdk_threads_add_timeout (2000, confirm_overwrite_timeout_cb, &closure);
391   gtk_dialog_run (GTK_DIALOG (closure.chooser));
392
393   filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (closure.chooser));
394   passed = passed && filename && (strcmp (filename, path) == 0);
395   g_free (filename);
396   
397   gtk_widget_destroy (closure.chooser);
398
399   passed = passed && (1 == closure.confirm_overwrite_signal_emitted);
400
401   log_test (passed, "Confirm overwrite for %s", path);
402
403   return passed;
404 }
405
406 static gboolean
407 test_confirm_overwrite (void)
408 {
409   gboolean passed = TRUE;
410
411   /* first test for a file we know will always exist */
412   passed = passed && test_confirm_overwrite_for_path ("/etc/passwd", FALSE); 
413   passed = passed && test_confirm_overwrite_for_path ("/etc/resolv.conf", TRUE); 
414   
415   return passed;
416 }
417
418 static const GtkFileChooserAction open_actions[] = {
419   GTK_FILE_CHOOSER_ACTION_OPEN,
420   GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER
421 };
422
423 static const GtkFileChooserAction save_actions[] = {
424   GTK_FILE_CHOOSER_ACTION_SAVE,
425   GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER
426 };
427
428
429 static gboolean
430 has_action (const GtkFileChooserAction *actions,
431             int n_actions,
432             GtkFileChooserAction sought_action)
433 {
434   int i;
435
436   for (i = 0; i < n_actions; i++)
437     if (actions[i] == sought_action)
438       return TRUE;
439
440   return FALSE;
441 }
442
443 static const char *
444 get_action_name (GtkFileChooserAction action)
445 {
446   GEnumClass *enum_class;
447   GEnumValue *enum_value;
448
449   enum_class = g_type_class_peek (GTK_TYPE_FILE_CHOOSER_ACTION);
450   if (!enum_class)
451     g_error ("BUG: get_action_name(): no GEnumClass for GTK_TYPE_FILE_CHOOSER_ACTION");
452
453   enum_value = g_enum_get_value (enum_class, (int) action);
454   if (!enum_value)
455     g_error ("BUG: get_action_name(): no GEnumValue for GtkFileChooserAction %d", (int) action);
456
457   return enum_value->value_name;
458 }
459
460 static GtkFileChooserDefault *
461 get_impl_from_dialog (GtkWidget *dialog)
462 {
463   GtkFileChooserDialog *d;
464   GtkFileChooserDialogPrivate *dialog_priv;
465   GtkFileChooserWidget *chooser_widget;
466   GtkFileChooserWidgetPrivate *widget_priv;
467   GtkFileChooserDefault *impl;
468
469   d = GTK_FILE_CHOOSER_DIALOG (dialog);
470   dialog_priv = d->priv;
471   chooser_widget = GTK_FILE_CHOOSER_WIDGET (dialog_priv->widget);
472   if (!chooser_widget)
473     g_error ("BUG: dialog_priv->widget is not a GtkFileChooserWidget");
474
475   widget_priv = chooser_widget->priv;
476   impl = (GtkFileChooserDefault *) (widget_priv->impl);
477   if (!impl)
478     g_error ("BUG: widget_priv->impl is not a GtkFileChooserDefault");
479
480   return impl;
481 }
482
483 static gboolean
484 test_widgets_for_current_action (GtkFileChooserDialog *dialog,
485                                  GtkFileChooserAction  expected_action)
486 {
487   GtkFileChooserDefault *impl;
488   gboolean passed;
489
490   if (gtk_file_chooser_get_action (GTK_FILE_CHOOSER (dialog)) != expected_action)
491     return FALSE;
492
493   impl = get_impl_from_dialog (GTK_WIDGET (dialog));
494
495   g_assert (impl->action == expected_action);
496
497   passed = TRUE;
498
499   /* OPEN implies that the "new folder" button is hidden; otherwise it is shown */
500   if (impl->action == GTK_FILE_CHOOSER_ACTION_OPEN)
501     passed = passed && !GTK_WIDGET_VISIBLE (impl->browse_new_folder_button);
502   else
503     passed = passed && GTK_WIDGET_VISIBLE (impl->browse_new_folder_button);
504
505   /* Check that the widgets are present/visible or not */
506   if (has_action (open_actions, G_N_ELEMENTS (open_actions), impl->action))
507     {
508       passed = passed && (impl->save_widgets == NULL
509                           && (impl->location_mode == LOCATION_MODE_PATH_BAR
510                               ? impl->location_entry == NULL
511                               : impl->location_entry != NULL)
512                           && impl->save_folder_label == NULL
513                           && impl->save_folder_combo == NULL
514                           && impl->save_expander == NULL
515                           && GTK_IS_CONTAINER (impl->browse_widgets) && GTK_WIDGET_DRAWABLE (impl->browse_widgets));
516     }
517   else if (has_action (save_actions, G_N_ELEMENTS (save_actions), impl->action))
518     {
519       /* FIXME: we can't use GTK_IS_FILE_CHOOSER_ENTRY() because it uses
520        * _gtk_file_chooser_entry_get_type(), which is a non-exported symbol.
521        * So, we just test impl->location_entry for being non-NULL
522        */
523       passed = passed && (GTK_IS_CONTAINER (impl->save_widgets) && GTK_WIDGET_DRAWABLE (impl->save_widgets)
524                           && impl->location_entry != NULL && GTK_WIDGET_DRAWABLE (impl->location_entry)
525                           && GTK_IS_LABEL (impl->save_folder_label) && GTK_WIDGET_DRAWABLE (impl->save_folder_label)
526                           && GTK_IS_COMBO_BOX (impl->save_folder_combo) && GTK_WIDGET_DRAWABLE (impl->save_folder_combo)
527                           && GTK_IS_EXPANDER (impl->save_expander) && GTK_WIDGET_DRAWABLE (impl->save_expander)
528                           && GTK_IS_CONTAINER (impl->browse_widgets));
529
530       /* FIXME: we are in a SAVE mode; test the visibility and sensitivity of
531        * the children that change depending on the state of the expander.
532        */
533     }
534   else
535     {
536       g_error ("BAD TEST: test_widgets_for_current_action() doesn't know about %s", get_action_name (impl->action));
537       passed = FALSE;
538     }
539
540   return passed;
541 }
542
543 typedef gboolean (* ForeachActionCallback) (GtkFileChooserDialog *dialog,
544                                             GtkFileChooserAction  action,
545                                             gpointer              user_data);
546
547 static gboolean
548 foreach_action (GtkFileChooserDialog *dialog,
549                 ForeachActionCallback callback,
550                 gpointer              user_data)
551 {
552   GEnumClass *enum_class;
553   int i;
554
555   enum_class = g_type_class_peek (GTK_TYPE_FILE_CHOOSER_ACTION);
556   if (!enum_class)
557     g_error ("BUG: get_action_name(): no GEnumClass for GTK_TYPE_FILE_CHOOSER_ACTION");
558
559   for (i = 0; i < enum_class->n_values; i++)
560     {
561       GEnumValue *enum_value;
562       GtkFileChooserAction action;
563       gboolean passed;
564
565       enum_value = enum_class->values + i;
566       action = enum_value->value;
567
568       passed = (* callback) (dialog, action, user_data);
569       if (!passed)
570         return FALSE;
571     }
572
573   return TRUE;
574 }
575
576 struct action_closure {
577   GtkFileChooserAction from_action;
578 };
579
580 static gboolean
581 switch_from_to_action_cb (GtkFileChooserDialog *dialog,
582                           GtkFileChooserAction  action,
583                           gpointer              user_data)
584 {
585   struct action_closure *closure;
586   gboolean passed;
587
588   closure = user_data;
589
590   gtk_file_chooser_set_action (GTK_FILE_CHOOSER (dialog), closure->from_action);
591
592   passed = test_widgets_for_current_action (dialog, closure->from_action);
593   log_test (passed, "switch_from_to_action_cb(): reset to action %s", get_action_name (closure->from_action));
594   if (!passed)
595     return FALSE;
596
597   gtk_file_chooser_set_action (GTK_FILE_CHOOSER (dialog), action);
598
599   passed = test_widgets_for_current_action (dialog, action);
600   log_test (passed, "switch_from_to_action_cb(): transition from %s to %s",
601             get_action_name (closure->from_action),
602             get_action_name (action));
603   return passed;
604 }
605
606 static gboolean
607 switch_from_action_cb (GtkFileChooserDialog *dialog,
608                        GtkFileChooserAction  action,
609                        gpointer              user_data)
610 {
611   struct action_closure closure;
612
613   closure.from_action = action;
614
615   return foreach_action (dialog, switch_from_to_action_cb, &closure);
616 }
617
618 static gboolean
619 test_action_widgets (void)
620 {
621   GtkWidget *dialog;
622   GtkFileChooserAction action;
623   gboolean passed;
624
625   dialog = gtk_file_chooser_dialog_new ("Test file chooser",
626                                         NULL,
627                                         GTK_FILE_CHOOSER_ACTION_OPEN,
628                                         GTK_STOCK_CANCEL,
629                                         GTK_RESPONSE_CANCEL,
630                                         GTK_STOCK_OK,
631                                         GTK_RESPONSE_ACCEPT,
632                                         NULL);
633   gtk_widget_show_now (dialog);
634
635   action = gtk_file_chooser_get_action (GTK_FILE_CHOOSER (dialog));
636
637   passed = test_widgets_for_current_action (GTK_FILE_CHOOSER_DIALOG (dialog), action);
638   log_test (passed, "test_action_widgets(): widgets for initial action %s", get_action_name (action));
639   if (!passed)
640     return FALSE;
641
642   passed = foreach_action (GTK_FILE_CHOOSER_DIALOG (dialog), switch_from_action_cb, NULL);
643   log_test (passed, "test_action_widgets(): all transitions through property change");
644
645   gtk_widget_destroy (dialog);
646
647   return passed;
648 }
649
650 static gboolean
651 test_reload_sequence (gboolean set_folder_before_map)
652 {
653   GtkWidget *dialog;
654   GtkFileChooserDefault *impl;
655   gboolean passed;
656   char *folder;
657   char *current_working_dir;
658
659   passed = TRUE;
660
661   current_working_dir = g_get_current_dir ();
662
663   dialog = gtk_file_chooser_dialog_new ("Test file chooser",
664                                         NULL,
665                                         GTK_FILE_CHOOSER_ACTION_OPEN,
666                                         GTK_STOCK_CANCEL,
667                                         GTK_RESPONSE_CANCEL,
668                                         GTK_STOCK_OK,
669                                         GTK_RESPONSE_ACCEPT,
670                                         NULL);
671   impl = get_impl_from_dialog (dialog);
672
673   if (set_folder_before_map)
674     {
675       gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (dialog), g_get_home_dir ());
676
677       wait_for_idle ();
678
679       passed = passed && (impl->current_folder != NULL
680                           && impl->browse_files_model != NULL
681                           && (impl->load_state == LOAD_PRELOAD || impl->load_state == LOAD_LOADING || impl->load_state == LOAD_FINISHED)
682                           && impl->reload_state == RELOAD_HAS_FOLDER
683                           && (impl->load_state == LOAD_PRELOAD ? (impl->load_timeout_id != 0) : TRUE)
684                           && ((impl->load_state == LOAD_LOADING || impl->load_state == LOAD_FINISHED)
685                               ? (impl->load_timeout_id == 0 && impl->sort_model != NULL)
686                               : TRUE));
687
688       wait_for_idle ();
689
690       folder = gtk_file_chooser_get_current_folder (GTK_FILE_CHOOSER (dialog));
691       passed = passed && (folder != NULL && strcmp (folder, g_get_home_dir()) == 0);
692       g_free (folder);
693     }
694   else
695     {
696       /* Initially, no folder is not loaded or pending */
697       passed = passed && (impl->current_folder == NULL
698                           && impl->sort_model == NULL
699                           && impl->browse_files_model == NULL
700                           && impl->load_state == LOAD_EMPTY
701                           && impl->reload_state == RELOAD_EMPTY
702                           && impl->load_timeout_id == 0);
703
704       wait_for_idle ();
705
706       folder = gtk_file_chooser_get_current_folder (GTK_FILE_CHOOSER (dialog));
707       passed = passed && (folder != NULL && strcmp (folder, current_working_dir) == 0);
708     }
709
710   log_test (passed, "test_reload_sequence(): initial status");
711
712   /* After mapping, it is loading some folder, either the one that was explicitly set or the default one */
713
714   gtk_widget_show_now (dialog);
715
716   wait_for_idle ();
717
718   passed = passed && (impl->current_folder != NULL
719                       && impl->browse_files_model != NULL
720                       && (impl->load_state == LOAD_PRELOAD || impl->load_state == LOAD_LOADING || impl->load_state == LOAD_FINISHED)
721                       && impl->reload_state == RELOAD_HAS_FOLDER
722                       && (impl->load_state == LOAD_PRELOAD ? (impl->load_timeout_id != 0) : TRUE)
723                       && ((impl->load_state == LOAD_LOADING || impl->load_state == LOAD_FINISHED)
724                           ? (impl->load_timeout_id == 0 && impl->sort_model != NULL)
725                           : TRUE));
726
727   folder = gtk_file_chooser_get_current_folder (GTK_FILE_CHOOSER (dialog));
728   if (set_folder_before_map)
729     passed = passed && (folder != NULL && strcmp (folder, g_get_home_dir()) == 0);
730   else
731     passed = passed && (folder != NULL && strcmp (folder, current_working_dir) == 0);
732
733   g_free (folder);
734
735   log_test (passed, "test_reload_sequence(): status after map");
736
737   /* Unmap it; we should still have a folder */
738
739   gtk_widget_hide (dialog);
740
741   wait_for_idle ();
742
743   passed = passed && (impl->current_folder != NULL
744                       && impl->browse_files_model != NULL
745                       && (impl->load_state == LOAD_PRELOAD || impl->load_state == LOAD_LOADING || impl->load_state == LOAD_FINISHED)
746                       && impl->reload_state == RELOAD_WAS_UNMAPPED
747                       && (impl->load_state == LOAD_PRELOAD ? (impl->load_timeout_id != 0) : TRUE)
748                       && ((impl->load_state == LOAD_LOADING || impl->load_state == LOAD_FINISHED)
749                           ? (impl->load_timeout_id == 0 && impl->sort_model != NULL)
750                           : TRUE));
751
752   folder = gtk_file_chooser_get_current_folder (GTK_FILE_CHOOSER (dialog));
753   if (set_folder_before_map)
754     passed = passed && (folder != NULL && strcmp (folder, g_get_home_dir()) == 0);
755   else
756     passed = passed && (folder != NULL && strcmp (folder, current_working_dir) == 0);
757
758   g_free (folder);
759
760   log_test (passed, "test_reload_sequence(): status after unmap");
761
762   /* Map it again! */
763
764   gtk_widget_show_now (dialog);
765
766   wait_for_idle ();
767
768   passed = passed && (impl->current_folder != NULL
769                       && impl->browse_files_model != NULL
770                       && (impl->load_state == LOAD_PRELOAD || impl->load_state == LOAD_LOADING || impl->load_state == LOAD_FINISHED)
771                       && impl->reload_state == RELOAD_HAS_FOLDER
772                       && (impl->load_state == LOAD_PRELOAD ? (impl->load_timeout_id != 0) : TRUE)
773                       && ((impl->load_state == LOAD_LOADING || impl->load_state == LOAD_FINISHED)
774                           ? (impl->load_timeout_id == 0 && impl->sort_model != NULL)
775                           : TRUE));
776
777   folder = gtk_file_chooser_get_current_folder (GTK_FILE_CHOOSER (dialog));
778   if (set_folder_before_map)
779     passed = passed && (folder != NULL && strcmp (folder, g_get_home_dir()) == 0);
780   else
781     passed = passed && (folder != NULL && strcmp (folder, current_working_dir) == 0);
782
783   g_free (folder);
784
785   log_test (passed, "test_reload_sequence(): status after re-map");
786
787   gtk_widget_destroy (dialog);
788   g_free (current_working_dir);
789
790   return passed;
791 }
792
793 static gboolean
794 test_reload (void)
795 {
796   gboolean passed;
797
798   passed = test_reload_sequence (FALSE);
799   log_test (passed, "test_reload(): create and use the default folder");
800   if (!passed)
801     return FALSE;
802
803   passed = test_reload_sequence (TRUE);
804   log_test (passed, "test_reload(): set a folder explicitly before mapping");
805
806   return passed;
807 }
808
809 static gboolean
810 test_button_folder_states_for_action (GtkFileChooserAction action, gboolean use_dialog, gboolean set_folder_on_dialog)
811 {
812   gboolean passed;
813   GtkWidget *window;
814   GtkWidget *button;
815   char *folder;
816   GtkWidget *dialog;
817   char *current_working_dir;
818   gboolean must_have_cwd;
819
820   passed = TRUE;
821
822   current_working_dir = g_get_current_dir ();
823   must_have_cwd = !(use_dialog && set_folder_on_dialog);
824
825   window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
826
827   if (use_dialog)
828     {
829       dialog = gtk_file_chooser_dialog_new ("Test", NULL, action,
830                                             GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
831                                             GTK_STOCK_OK, GTK_RESPONSE_ACCEPT,
832                                             NULL);
833       button = gtk_file_chooser_button_new_with_dialog (dialog);
834
835       if (set_folder_on_dialog)
836         gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (dialog), g_get_home_dir ());
837     }
838   else
839     {
840       button = gtk_file_chooser_button_new ("Test", action);
841       dialog = NULL; /* keep gcc happy */
842     }
843
844   gtk_container_add (GTK_CONTAINER (window), button);
845
846   /* Pre-map; no folder is set */
847   wait_for_idle ();
848
849   folder = gtk_file_chooser_get_current_folder (GTK_FILE_CHOOSER (button));
850   if (must_have_cwd)
851     passed = passed && (folder != NULL && strcmp (folder, current_working_dir) == 0);
852   else
853     passed = passed && (folder != NULL && strcmp (folder, g_get_home_dir()) == 0);
854
855   log_test (passed, "test_button_folder_states_for_action(): %s, use_dialog=%d, set_folder_on_dialog=%d, pre-map, %s",
856             get_action_name (action),
857             use_dialog,
858             set_folder_on_dialog,
859             must_have_cwd ? "must have $cwd" : "must have explicit folder");
860
861   /* Map; folder should be set */
862
863   gtk_widget_show_all (window);
864   gtk_widget_show_now (window);
865
866   wait_for_idle ();
867
868   folder = gtk_file_chooser_get_current_folder (GTK_FILE_CHOOSER (button));
869
870   if (must_have_cwd)
871     passed = passed && (folder != NULL && strcmp (folder, current_working_dir) == 0);
872   else
873     passed = passed && (folder != NULL && strcmp (folder, g_get_home_dir()) == 0);
874
875   log_test (passed, "test_button_folder_states_for_action(): %s, use_dialog=%d, set_folder_on_dialog=%d, mapped, %s",
876             get_action_name (action),
877             use_dialog,
878             set_folder_on_dialog,
879             must_have_cwd ? "must have $cwd" : "must have explicit folder");
880   g_free (folder);
881
882   /* Unmap; folder should be set */
883
884   gtk_widget_hide (window);
885   wait_for_idle ();
886   folder = gtk_file_chooser_get_current_folder (GTK_FILE_CHOOSER (button));
887
888   if (must_have_cwd)
889     passed = passed && (folder != NULL && strcmp (folder, current_working_dir) == 0);
890   else
891     passed = passed && (folder != NULL && strcmp (folder, g_get_home_dir()) == 0);
892
893   log_test (passed, "test_button_folder_states_for_action(): %s, use_dialog=%d, set_folder_on_dialog=%d, unmapped, %s",
894             get_action_name (action),
895             use_dialog,
896             set_folder_on_dialog,
897             must_have_cwd ? "must have $cwd" : "must have explicit folder");
898   g_free (folder);
899
900   /* Re-map; folder should be set */
901
902   gtk_widget_show_now (window);
903   folder = gtk_file_chooser_get_current_folder (GTK_FILE_CHOOSER (button));
904
905   if (must_have_cwd)
906     passed = passed && (folder != NULL && strcmp (folder, current_working_dir) == 0);
907   else
908     passed = passed && (folder != NULL && strcmp (folder, g_get_home_dir()) == 0);
909   wait_for_idle ();
910   log_test (passed, "test_button_folder_states_for_action(): %s, use_dialog=%d, set_folder_on_dialog=%d, re-mapped, %s",
911             get_action_name (action),
912             use_dialog,
913             set_folder_on_dialog,
914             must_have_cwd ? "must have $cwd" : "must have explicit folder");
915   g_free (folder);
916
917   g_free (current_working_dir);
918
919   gtk_widget_destroy (window);
920
921   return passed;
922 }
923
924 static gboolean
925 test_button_folder_states (void)
926 {
927   /* GtkFileChooserButton only supports OPEN and SELECT_FOLDER */
928   static const GtkFileChooserAction actions_to_test[] = {
929     GTK_FILE_CHOOSER_ACTION_OPEN,
930     GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER
931   };
932   gboolean passed;
933   int i;
934
935   passed = TRUE;
936
937   for (i = 0; i < G_N_ELEMENTS (actions_to_test); i++)
938     {
939       passed = passed && test_button_folder_states_for_action (actions_to_test[i], FALSE, FALSE);
940       passed = passed && test_button_folder_states_for_action (actions_to_test[i], TRUE, FALSE);
941       passed = passed && test_button_folder_states_for_action (actions_to_test[i], TRUE, TRUE);
942       log_test (passed, "test_button_folder_states(): action %s", get_action_name (actions_to_test[i]));
943     }
944
945   log_test (passed, "test_button_folder_states(): all supported actions");
946   return passed;
947 }
948
949 static gboolean
950 sleep_timeout_cb (gpointer data)
951 {
952   gtk_main_quit ();
953   return FALSE;
954 }
955
956 static void
957 sleep_in_main_loop (int milliseconds)
958 {
959   gdk_threads_add_timeout (milliseconds, sleep_timeout_cb, NULL);
960   gtk_main ();
961 }
962
963 static gboolean
964 test_folder_switch_and_filters (void)
965 {
966   gboolean passed;
967   char *cwd;
968   char *base_dir;
969   GtkFilePath *cwd_path;
970   GtkFilePath *base_dir_path;
971   GtkWidget *dialog;
972   GtkFileFilter *all_filter;
973   GtkFileFilter *txt_filter;
974   GtkFileChooserDefault *impl;
975
976   passed = TRUE;
977
978   cwd = g_get_current_dir ();
979   base_dir = g_build_filename (cwd, "file-chooser-test-dir", NULL);
980
981   dialog = gtk_file_chooser_dialog_new ("Test", NULL, GTK_FILE_CHOOSER_ACTION_OPEN,
982                                         GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
983                                         GTK_STOCK_OK, GTK_RESPONSE_ACCEPT,
984                                         NULL);
985   impl = get_impl_from_dialog (dialog);
986
987   cwd_path = gtk_file_system_filename_to_path (impl->file_system, cwd);
988   base_dir_path = gtk_file_system_filename_to_path (impl->file_system, base_dir);
989
990   passed = passed && gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (dialog), base_dir);
991   if (!passed)
992     goto out;
993
994   /* All files filter */
995
996   all_filter = gtk_file_filter_new ();
997   gtk_file_filter_set_name (all_filter, "All files");
998   gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), all_filter);
999
1000   /* *.txt filter */
1001
1002   txt_filter = gtk_file_filter_new ();
1003   gtk_file_filter_set_name (all_filter, "*.txt");
1004   gtk_file_filter_add_pattern (txt_filter, "*.txt");
1005   gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), txt_filter);
1006
1007   /* Test filter set */
1008
1009   gtk_file_chooser_set_filter (GTK_FILE_CHOOSER (dialog), all_filter);
1010   passed = passed && (gtk_file_chooser_get_filter (GTK_FILE_CHOOSER (dialog)) == all_filter);
1011
1012   gtk_file_chooser_set_filter (GTK_FILE_CHOOSER (dialog), txt_filter);
1013   passed = passed && (gtk_file_chooser_get_filter (GTK_FILE_CHOOSER (dialog)) == txt_filter);
1014
1015   log_test (passed, "test_folder_switch_and_filters(): set and get filter");
1016
1017   gtk_widget_show (dialog);
1018
1019   /* Test that filter is unchanged when we switch folders */
1020
1021   gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (dialog), cwd);
1022   sleep_in_main_loop (1000);
1023   passed = passed && (gtk_file_chooser_get_filter (GTK_FILE_CHOOSER (dialog)) == txt_filter);
1024
1025   gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (dialog), base_dir);
1026   sleep_in_main_loop (500);
1027
1028   g_signal_emit_by_name (impl->browse_path_bar, "path-clicked",
1029                          (GtkFilePath *) cwd_path,
1030                          (GtkFilePath *) base_dir_path,
1031                          FALSE);
1032   sleep_in_main_loop (500);
1033   passed = passed && (gtk_file_chooser_get_filter (GTK_FILE_CHOOSER (dialog)) == txt_filter);
1034
1035   log_test (passed, "test_folder_switch_and_filters(): filter after changing folder");
1036
1037  out:
1038   g_free (cwd);
1039   g_free (base_dir);
1040   gtk_file_path_free (cwd_path);
1041   gtk_file_path_free (base_dir_path);
1042
1043   gtk_widget_destroy (dialog);
1044
1045   log_test (passed, "test_folder_switch_and_filters(): all filter tests");
1046   return passed;
1047 }
1048
1049 static GLogFunc default_log_handler;
1050 static int num_warnings;
1051 static int num_errors;
1052 static int num_critical_errors;
1053
1054 static void
1055 log_override_cb (const gchar   *log_domain,
1056                  GLogLevelFlags log_level,
1057                  const gchar   *message,
1058                  gpointer       user_data)
1059 {
1060   if (log_level & G_LOG_LEVEL_WARNING)
1061     num_warnings++;
1062
1063   if (log_level & G_LOG_LEVEL_ERROR)
1064     num_errors++;
1065
1066   if (log_level & G_LOG_LEVEL_CRITICAL)
1067     num_critical_errors++;
1068
1069   (* default_log_handler) (log_domain, log_level, message, user_data);
1070 }
1071
1072 int
1073 main (int argc, char **argv)
1074 {
1075   gboolean passed;
1076   gboolean zero_warnings;
1077   gboolean zero_errors;
1078   gboolean zero_critical_errors;
1079
1080   default_log_handler = g_log_set_default_handler (log_override_cb, NULL);
1081   passed = TRUE;
1082
1083   gtk_init (&argc, &argv);
1084
1085   /* Start tests */
1086
1087 #if 0
1088   passed = passed && test_black_box ();
1089 #endif
1090   passed = passed && test_confirm_overwrite ();
1091 #if 0
1092   passed = passed && test_action_widgets ();
1093   passed = passed && test_reload ();
1094   passed = passed && test_button_folder_states ();
1095   passed = passed && test_folder_switch_and_filters ();
1096 #endif
1097   log_test (passed, "main(): main tests");
1098
1099   /* Warnings and errors */
1100
1101   zero_warnings = num_warnings == 0;
1102   zero_errors = num_errors == 0;
1103   zero_critical_errors = num_critical_errors == 0;
1104
1105   log_test (zero_warnings, "main(): zero warnings (actual number %d)", num_warnings);
1106   log_test (zero_errors, "main(): zero errors (actual number %d)", num_errors);
1107   log_test (zero_critical_errors, "main(): zero critical errors (actual number %d)", num_critical_errors);
1108
1109   /* Done */
1110
1111   passed = passed && zero_warnings && zero_errors && zero_critical_errors;
1112
1113   log_test (passed, "main(): ALL TESTS");
1114
1115   return 0;
1116 }