1 /* GTK - The GIMP Toolkit
2 * autotestfilechooser.c: Automated unit tests for the GtkFileChooser widget
3 * Copyright (C) 2005, Novell, Inc.
6 * Federico Mena-Quintero <federico@novell.com>
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.
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.
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.
24 #define GTK_FILE_SYSTEM_ENABLE_UNSUPPORTED
28 #include <glib/gprintf.h>
30 #include "gtk/gtkfilechooserprivate.h"
31 #include "gtk/gtkfilechooserdefault.h"
32 #include "gtk/gtkfilechooserentry.h"
35 log_test (gboolean passed, const char *test_name, ...)
40 va_start (args, test_name);
41 str = g_strdup_vprintf (test_name, args);
44 g_printf ("%s: %s\n", passed ? "PASSED" : "FAILED", str);
48 static const GtkFileChooserAction open_actions[] = {
49 GTK_FILE_CHOOSER_ACTION_OPEN,
50 GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER
53 static const GtkFileChooserAction save_actions[] = {
54 GTK_FILE_CHOOSER_ACTION_SAVE,
55 GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER
60 has_action (const GtkFileChooserAction *actions,
62 GtkFileChooserAction sought_action)
66 for (i = 0; i < n_actions; i++)
67 if (actions[i] == sought_action)
74 get_action_name (GtkFileChooserAction action)
76 GEnumClass *enum_class;
77 GEnumValue *enum_value;
79 enum_class = g_type_class_peek (GTK_TYPE_FILE_CHOOSER_ACTION);
81 g_error ("BUG: get_action_name(): no GEnumClass for GTK_TYPE_FILE_CHOOSER_ACTION");
83 enum_value = g_enum_get_value (enum_class, (int) action);
85 g_error ("BUG: get_action_name(): no GEnumValue for GtkFileChooserAction %d", (int) action);
87 return enum_value->value_name;
90 static GtkFileChooserDefault *
91 get_impl_from_dialog (GtkWidget *dialog)
93 GtkFileChooserDialog *d;
94 GtkFileChooserDialogPrivate *dialog_priv;
95 GtkFileChooserWidget *chooser_widget;
96 GtkFileChooserWidgetPrivate *widget_priv;
97 GtkFileChooserDefault *impl;
99 d = GTK_FILE_CHOOSER_DIALOG (dialog);
100 dialog_priv = d->priv;
101 chooser_widget = GTK_FILE_CHOOSER_WIDGET (dialog_priv->widget);
103 g_error ("BUG: dialog_priv->widget is not a GtkFileChooserWidget");
105 widget_priv = chooser_widget->priv;
106 impl = (GtkFileChooserDefault *) (widget_priv->impl);
108 g_error ("BUG: widget_priv->impl is not a GtkFileChooserDefault");
114 test_widgets_for_current_action (GtkFileChooserDialog *dialog,
115 GtkFileChooserAction expected_action)
117 GtkFileChooserDefault *impl;
120 if (gtk_file_chooser_get_action (GTK_FILE_CHOOSER (dialog)) != expected_action)
123 impl = get_impl_from_dialog (GTK_WIDGET (dialog));
125 g_assert (impl->action == expected_action);
129 /* OPEN implies that the "new folder" button is hidden; otherwise it is shown */
130 if (impl->action == GTK_FILE_CHOOSER_ACTION_OPEN)
131 passed = passed && !GTK_WIDGET_VISIBLE (impl->browse_new_folder_button);
133 passed = passed && GTK_WIDGET_VISIBLE (impl->browse_new_folder_button);
135 /* Check that the widgets are present/visible or not */
136 if (has_action (open_actions, G_N_ELEMENTS (open_actions), impl->action))
138 passed = passed && (impl->save_widgets == NULL
139 && impl->save_file_name_entry == NULL
140 && impl->save_folder_label == NULL
141 && impl->save_folder_combo == NULL
142 && impl->save_expander == NULL
143 && GTK_IS_CONTAINER (impl->browse_widgets) && GTK_WIDGET_DRAWABLE (impl->browse_widgets));
145 else if (has_action (save_actions, G_N_ELEMENTS (save_actions), impl->action))
147 /* FIXME: we can't use GTK_IS_FILE_CHOOSER_ENTRY() because it uses
148 * _gtk_file_chooser_entry_get_type(), which is a non-exported symbol.
149 * So, we just test impl->save_file_name_entry for being non-NULL
151 passed = passed && (GTK_IS_CONTAINER (impl->save_widgets) && GTK_WIDGET_DRAWABLE (impl->save_widgets)
152 && impl->save_file_name_entry != NULL && GTK_WIDGET_DRAWABLE (impl->save_file_name_entry)
153 && GTK_IS_LABEL (impl->save_folder_label) && GTK_WIDGET_DRAWABLE (impl->save_folder_label)
154 && GTK_IS_COMBO_BOX (impl->save_folder_combo) && GTK_WIDGET_DRAWABLE (impl->save_folder_combo)
155 && GTK_IS_EXPANDER (impl->save_expander) && GTK_WIDGET_DRAWABLE (impl->save_expander)
156 && GTK_IS_CONTAINER (impl->browse_widgets));
158 /* FIXME: we are in a SAVE mode; test the visibility and sensitivity of
159 * the children that change depending on the state of the expander.
164 g_error ("BAD TEST: test_widgets_for_current_action() doesn't know about %s", get_action_name (impl->action));
171 typedef gboolean (* ForeachActionCallback) (GtkFileChooserDialog *dialog,
172 GtkFileChooserAction action,
176 foreach_action (GtkFileChooserDialog *dialog,
177 ForeachActionCallback callback,
180 GEnumClass *enum_class;
183 enum_class = g_type_class_peek (GTK_TYPE_FILE_CHOOSER_ACTION);
185 g_error ("BUG: get_action_name(): no GEnumClass for GTK_TYPE_FILE_CHOOSER_ACTION");
187 for (i = 0; i < enum_class->n_values; i++)
189 GEnumValue *enum_value;
190 GtkFileChooserAction action;
193 enum_value = enum_class->values + i;
194 action = enum_value->value;
196 passed = (* callback) (dialog, action, user_data);
204 struct action_closure {
205 GtkFileChooserAction from_action;
209 switch_from_to_action_cb (GtkFileChooserDialog *dialog,
210 GtkFileChooserAction action,
213 struct action_closure *closure;
218 gtk_file_chooser_set_action (GTK_FILE_CHOOSER (dialog), closure->from_action);
220 passed = test_widgets_for_current_action (dialog, closure->from_action);
221 log_test (passed, "switch_from_to_action_cb(): reset to action %s", get_action_name (closure->from_action));
225 gtk_file_chooser_set_action (GTK_FILE_CHOOSER (dialog), action);
227 passed = test_widgets_for_current_action (dialog, action);
228 log_test (passed, "switch_from_to_action_cb(): transition from %s to %s",
229 get_action_name (closure->from_action),
230 get_action_name (action));
235 switch_from_action_cb (GtkFileChooserDialog *dialog,
236 GtkFileChooserAction action,
239 struct action_closure closure;
241 closure.from_action = action;
243 return foreach_action (dialog, switch_from_to_action_cb, &closure);
247 test_action_widgets (void)
250 GtkFileChooserAction action;
253 dialog = gtk_file_chooser_dialog_new ("Test file chooser",
255 GTK_FILE_CHOOSER_ACTION_OPEN,
261 gtk_widget_show_now (dialog);
263 action = gtk_file_chooser_get_action (GTK_FILE_CHOOSER (dialog));
265 passed = test_widgets_for_current_action (GTK_FILE_CHOOSER_DIALOG (dialog), action);
266 log_test (passed, "test_action_widgets(): widgets for initial action %s", get_action_name (action));
270 passed = foreach_action (GTK_FILE_CHOOSER_DIALOG (dialog), switch_from_action_cb, NULL);
271 log_test (passed, "test_action_widgets(): all transitions through property change");
273 gtk_widget_destroy (dialog);
279 test_reload_sequence (gboolean set_folder_before_map)
282 GtkFileChooserDefault *impl;
285 char *current_working_dir;
289 current_working_dir = g_get_current_dir ();
291 dialog = gtk_file_chooser_dialog_new ("Test file chooser",
293 GTK_FILE_CHOOSER_ACTION_OPEN,
299 impl = get_impl_from_dialog (dialog);
301 if (set_folder_before_map)
303 gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (dialog), g_get_home_dir ());
305 passed = passed && (impl->current_folder != NULL
306 && impl->browse_files_model != NULL
307 && (impl->load_state == LOAD_PRELOAD || impl->load_state == LOAD_LOADING || impl->load_state == LOAD_FINISHED)
308 && impl->reload_state == RELOAD_HAS_FOLDER
309 && (impl->load_state == LOAD_PRELOAD ? (impl->load_timeout_id != 0) : TRUE)
310 && ((impl->load_state == LOAD_LOADING || impl->load_state == LOAD_FINISHED)
311 ? (impl->load_timeout_id == 0 && impl->sort_model != NULL)
314 folder = gtk_file_chooser_get_current_folder (GTK_FILE_CHOOSER (dialog));
315 passed = passed && (folder != NULL && strcmp (folder, g_get_home_dir()) == 0);
320 /* Initially, no folder is not loaded or pending */
321 passed = passed && (impl->current_folder == NULL
322 && impl->sort_model == NULL
323 && impl->browse_files_model == NULL
324 && impl->load_state == LOAD_EMPTY
325 && impl->reload_state == RELOAD_EMPTY
326 && impl->load_timeout_id == 0);
328 folder = gtk_file_chooser_get_current_folder (GTK_FILE_CHOOSER (dialog));
329 passed = passed && (folder != NULL && strcmp (folder, current_working_dir) == 0);
332 log_test (passed, "test_reload_sequence(): initial status");
334 /* After mapping, it is loading some folder, either the one that was explicitly set or the default one */
336 gtk_widget_show_now (dialog);
338 passed = passed && (impl->current_folder != NULL
339 && impl->browse_files_model != NULL
340 && (impl->load_state == LOAD_PRELOAD || impl->load_state == LOAD_LOADING || impl->load_state == LOAD_FINISHED)
341 && impl->reload_state == RELOAD_HAS_FOLDER
342 && (impl->load_state == LOAD_PRELOAD ? (impl->load_timeout_id != 0) : TRUE)
343 && ((impl->load_state == LOAD_LOADING || impl->load_state == LOAD_FINISHED)
344 ? (impl->load_timeout_id == 0 && impl->sort_model != NULL)
347 folder = gtk_file_chooser_get_current_folder (GTK_FILE_CHOOSER (dialog));
348 if (set_folder_before_map)
349 passed = passed && (folder != NULL && strcmp (folder, g_get_home_dir()) == 0);
351 passed = passed && (folder != NULL && strcmp (folder, current_working_dir) == 0);
355 log_test (passed, "test_reload_sequence(): status after map");
357 /* Unmap it; we should still have a folder */
359 gtk_widget_hide (dialog);
361 passed = passed && (impl->current_folder != NULL
362 && impl->browse_files_model != NULL
363 && (impl->load_state == LOAD_PRELOAD || impl->load_state == LOAD_LOADING || impl->load_state == LOAD_FINISHED)
364 && impl->reload_state == RELOAD_WAS_UNMAPPED
365 && (impl->load_state == LOAD_PRELOAD ? (impl->load_timeout_id != 0) : TRUE)
366 && ((impl->load_state == LOAD_LOADING || impl->load_state == LOAD_FINISHED)
367 ? (impl->load_timeout_id == 0 && impl->sort_model != NULL)
370 folder = gtk_file_chooser_get_current_folder (GTK_FILE_CHOOSER (dialog));
371 if (set_folder_before_map)
372 passed = passed && (folder != NULL && strcmp (folder, g_get_home_dir()) == 0);
374 passed = passed && (folder != NULL && strcmp (folder, current_working_dir) == 0);
378 log_test (passed, "test_reload_sequence(): status after unmap");
382 gtk_widget_show_now (dialog);
384 passed = passed && (impl->current_folder != NULL
385 && impl->browse_files_model != NULL
386 && (impl->load_state == LOAD_PRELOAD || impl->load_state == LOAD_LOADING || impl->load_state == LOAD_FINISHED)
387 && impl->reload_state == RELOAD_HAS_FOLDER
388 && (impl->load_state == LOAD_PRELOAD ? (impl->load_timeout_id != 0) : TRUE)
389 && ((impl->load_state == LOAD_LOADING || impl->load_state == LOAD_FINISHED)
390 ? (impl->load_timeout_id == 0 && impl->sort_model != NULL)
393 folder = gtk_file_chooser_get_current_folder (GTK_FILE_CHOOSER (dialog));
394 if (set_folder_before_map)
395 passed = passed && (folder != NULL && strcmp (folder, g_get_home_dir()) == 0);
397 passed = passed && (folder != NULL && strcmp (folder, current_working_dir) == 0);
401 log_test (passed, "test_reload_sequence(): status after re-map");
403 gtk_widget_destroy (dialog);
404 g_free (current_working_dir);
414 passed = test_reload_sequence (FALSE);
415 log_test (passed, "test_reload(): create and use the default folder");
419 passed = test_reload_sequence (TRUE);
420 log_test (passed, "test_reload(): set a folder explicitly before mapping");
426 test_button_folder_states_for_action (GtkFileChooserAction action, gboolean use_dialog, gboolean set_folder_on_dialog)
433 char *current_working_dir;
434 gboolean must_have_cwd;
438 current_working_dir = g_get_current_dir ();
439 must_have_cwd = !(use_dialog && set_folder_on_dialog);
441 window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
445 dialog = gtk_file_chooser_dialog_new ("Test", NULL, action,
446 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
447 GTK_STOCK_OK, GTK_RESPONSE_ACCEPT,
449 button = gtk_file_chooser_button_new_with_dialog (dialog);
451 if (set_folder_on_dialog)
452 gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (dialog), g_get_home_dir ());
456 button = gtk_file_chooser_button_new ("Test", action);
457 dialog = NULL; /* keep gcc happy */
460 gtk_container_add (GTK_CONTAINER (window), button);
462 /* Pre-map; no folder is set */
464 folder = gtk_file_chooser_get_current_folder (GTK_FILE_CHOOSER (button));
466 passed = passed && (folder != NULL && strcmp (folder, current_working_dir) == 0);
468 passed = passed && (folder != NULL && strcmp (folder, g_get_home_dir()) == 0);
470 log_test (passed, "test_button_folder_states_for_action(): %s, use_dialog=%d, set_folder_on_dialog=%d, pre-map, %s",
471 get_action_name (action),
473 set_folder_on_dialog,
474 must_have_cwd ? "must have $cwd" : "must have explicit folder");
476 /* Map; folder should be set */
478 gtk_widget_show_all (window);
479 gtk_widget_show_now (window);
480 folder = gtk_file_chooser_get_current_folder (GTK_FILE_CHOOSER (button));
483 passed = passed && (folder != NULL && strcmp (folder, current_working_dir) == 0);
485 passed = passed && (folder != NULL && strcmp (folder, g_get_home_dir()) == 0);
487 log_test (passed, "test_button_folder_states_for_action(): %s, use_dialog=%d, set_folder_on_dialog=%d, mapped, %s",
488 get_action_name (action),
490 set_folder_on_dialog,
491 must_have_cwd ? "must have $cwd" : "must have explicit folder");
494 /* Unmap; folder should be set */
496 gtk_widget_hide (window);
497 folder = gtk_file_chooser_get_current_folder (GTK_FILE_CHOOSER (button));
500 passed = passed && (folder != NULL && strcmp (folder, current_working_dir) == 0);
502 passed = passed && (folder != NULL && strcmp (folder, g_get_home_dir()) == 0);
504 log_test (passed, "test_button_folder_states_for_action(): %s, use_dialog=%d, set_folder_on_dialog=%d, unmapped, %s",
505 get_action_name (action),
507 set_folder_on_dialog,
508 must_have_cwd ? "must have $cwd" : "must have explicit folder");
511 /* Re-map; folder should be set */
513 gtk_widget_show_now (window);
514 folder = gtk_file_chooser_get_current_folder (GTK_FILE_CHOOSER (button));
517 passed = passed && (folder != NULL && strcmp (folder, current_working_dir) == 0);
519 passed = passed && (folder != NULL && strcmp (folder, g_get_home_dir()) == 0);
521 log_test (passed, "test_button_folder_states_for_action(): %s, use_dialog=%d, set_folder_on_dialog=%d, re-mapped, %s",
522 get_action_name (action),
524 set_folder_on_dialog,
525 must_have_cwd ? "must have $cwd" : "must have explicit folder");
528 g_free (current_working_dir);
530 gtk_widget_destroy (window);
536 test_button_folder_states (void)
538 /* GtkFileChooserButton only supports OPEN and SELECT_FOLDER */
539 static const GtkFileChooserAction actions_to_test[] = {
540 GTK_FILE_CHOOSER_ACTION_OPEN,
541 GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER
548 for (i = 0; i < G_N_ELEMENTS (actions_to_test); i++)
550 passed = passed && test_button_folder_states_for_action (actions_to_test[i], FALSE, FALSE);
551 passed = passed && test_button_folder_states_for_action (actions_to_test[i], TRUE, FALSE);
552 passed = passed && test_button_folder_states_for_action (actions_to_test[i], TRUE, TRUE);
553 log_test (passed, "test_button_folder_states(): action %s", get_action_name (actions_to_test[i]));
556 log_test (passed, "test_button_folder_states(): all supported actions");
560 static int num_warnings;
561 static int num_errors;
562 static int num_critical_errors;
565 log_override_cb (const gchar *log_domain,
566 GLogLevelFlags log_level,
567 const gchar *message,
570 if (log_level & G_LOG_LEVEL_WARNING)
573 if (log_level & G_LOG_LEVEL_ERROR)
576 if (log_level & G_LOG_LEVEL_CRITICAL)
577 num_critical_errors++;
579 g_log_default_handler (log_domain, log_level, message, user_data);
583 main (int argc, char **argv)
585 static const char *domains[] = {
586 "Glib", "GLib-GObject", "GModule", "GThread", "Pango", "Gdk", "GdkPixbuf", "Gtk", "libgnomevfs"
590 gboolean zero_warnings;
591 gboolean zero_errors;
592 gboolean zero_critical_errors;
595 for (i = 0; i < G_N_ELEMENTS (domains); i++)
596 g_log_set_handler (domains[i],
597 G_LOG_FLAG_RECURSION | G_LOG_FLAG_FATAL | G_LOG_LEVEL_ERROR | G_LOG_LEVEL_CRITICAL | G_LOG_LEVEL_WARNING,
598 log_override_cb, NULL);
600 gtk_init (&argc, &argv);
602 passed = test_action_widgets ();
603 passed = passed && test_reload ();
604 passed = passed && test_button_folder_states ();
605 log_test (passed, "main(): main tests");
607 zero_warnings = num_warnings == 0;
608 zero_errors = num_errors == 0;
609 zero_critical_errors = num_critical_errors == 0;
611 log_test (zero_warnings, "main(): zero warnings (actual number %d)", num_warnings);
612 log_test (zero_errors, "main(): zero errors (actual number %d)", num_errors);
613 log_test (zero_critical_errors, "main(): zero critical errors (actual number %d)", num_critical_errors);
615 passed = passed && zero_warnings && zero_errors && zero_critical_errors;
617 log_test (passed, "main(): ALL TESTS");