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