From 329bc4e22109bbf7633d22ff2a50e4f10628a783 Mon Sep 17 00:00:00 2001
From: Federico Mena Quintero <federico@ximian.com>
Date: Thu, 15 Sep 2005 21:51:31 +0000
Subject: [PATCH] Start a set of automated tests for the file chooser. The only
 test in

2005-09-15  Federico Mena Quintero  <federico@ximian.com>

	* tests/autotestfilechooser.c: Start a set of automated tests for
	the file chooser.  The only test in there right now doesn't pass
	yet.  It specifies the intended behavior of the first optimization
	of a series which I'll do on the file chooser (see
	http://primates.ximian.com/~federico/news-2005-09.html#14 for the
	details of this optimization).

	* tests/Makefile.am: Added autotestfilechooser.c.

	* gtk/gtkfilechooserprivate.h (struct
	_GtkFileChooserDialogPrivate): Move all the file chooser's private
	structures to here, so that they can be accessed by
	tests/autotestfilechooser.c:  _GtkFileChooserDialogPrivate,
	_GtkFileChooserWidgetPrivate, LoadState, _GtkFileChooserDefault.

	* gtk/gtkfilechooserdialog.c: See above.

	* gtk/gtkfilechooserwidget.c: See above.

	* gtk/gtkfilechooserdefault.c: See above.
---
 ChangeLog                   |  23 ++++
 ChangeLog.pre-2-10          |  23 ++++
 gtk/gtkfilechooserdefault.c | 117 +----------------
 gtk/gtkfilechooserdialog.c  |  14 +-
 gtk/gtkfilechooserprivate.h | 203 +++++++++++++++++++++++++++++
 gtk/gtkfilechooserwidget.c  |   8 +-
 gtk/gtkfilesystemmodel.c    |  51 +-------
 tests/Makefile.am           |   6 +
 tests/autotestfilechooser.c | 252 ++++++++++++++++++++++++++++++++++++
 9 files changed, 511 insertions(+), 186 deletions(-)
 create mode 100644 tests/autotestfilechooser.c

diff --git a/ChangeLog b/ChangeLog
index 0a54245216..e30404f080 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,26 @@
+2005-09-15  Federico Mena Quintero  <federico@ximian.com>
+
+	* tests/autotestfilechooser.c: Start a set of automated tests for
+	the file chooser.  The only test in there right now doesn't pass
+	yet.  It specifies the intended behavior of the first optimization
+	of a series which I'll do on the file chooser (see
+	http://primates.ximian.com/~federico/news-2005-09.html#14 for the
+	details of this optimization).
+
+	* tests/Makefile.am: Added autotestfilechooser.c.
+
+	* gtk/gtkfilechooserprivate.h (struct
+	_GtkFileChooserDialogPrivate): Move all the file chooser's private
+	structures to here, so that they can be accessed by
+	tests/autotestfilechooser.c:  _GtkFileChooserDialogPrivate,
+	_GtkFileChooserWidgetPrivate, LoadState, _GtkFileChooserDefault.
+
+	* gtk/gtkfilechooserdialog.c: See above.
+
+	* gtk/gtkfilechooserwidget.c: See above.
+
+	* gtk/gtkfilechooserdefault.c: See above.
+
 Thu Sep 15 15:27:55 2005  Tim Janik  <timj@imendio.com>
 
 	* gtk/gtkwindow.c: 
diff --git a/ChangeLog.pre-2-10 b/ChangeLog.pre-2-10
index 0a54245216..e30404f080 100644
--- a/ChangeLog.pre-2-10
+++ b/ChangeLog.pre-2-10
@@ -1,3 +1,26 @@
+2005-09-15  Federico Mena Quintero  <federico@ximian.com>
+
+	* tests/autotestfilechooser.c: Start a set of automated tests for
+	the file chooser.  The only test in there right now doesn't pass
+	yet.  It specifies the intended behavior of the first optimization
+	of a series which I'll do on the file chooser (see
+	http://primates.ximian.com/~federico/news-2005-09.html#14 for the
+	details of this optimization).
+
+	* tests/Makefile.am: Added autotestfilechooser.c.
+
+	* gtk/gtkfilechooserprivate.h (struct
+	_GtkFileChooserDialogPrivate): Move all the file chooser's private
+	structures to here, so that they can be accessed by
+	tests/autotestfilechooser.c:  _GtkFileChooserDialogPrivate,
+	_GtkFileChooserWidgetPrivate, LoadState, _GtkFileChooserDefault.
+
+	* gtk/gtkfilechooserdialog.c: See above.
+
+	* gtk/gtkfilechooserwidget.c: See above.
+
+	* gtk/gtkfilechooserdefault.c: See above.
+
 Thu Sep 15 15:27:55 2005  Tim Janik  <timj@imendio.com>
 
 	* gtk/gtkwindow.c: 
diff --git a/gtk/gtkfilechooserdefault.c b/gtk/gtkfilechooserdefault.c
index 3a79c8b1d3..99974b014f 100644
--- a/gtk/gtkfilechooserdefault.c
+++ b/gtk/gtkfilechooserdefault.c
@@ -32,6 +32,7 @@
 #include "gtkentry.h"
 #include "gtkeventbox.h"
 #include "gtkexpander.h"
+#include "gtkfilechooserprivate.h"
 #include "gtkfilechooserdefault.h"
 #include "gtkfilechooserembed.h"
 #include "gtkfilechooserentry.h"
@@ -59,11 +60,7 @@
 #include "gtktable.h"
 #include "gtktreednd.h"
 #include "gtktreeprivate.h"
-#include "gtktreeview.h"
-#include "gtktreemodelsort.h"
 #include "gtktreeselection.h"
-#include "gtktreestore.h"
-#include "gtktooltips.h"
 #include "gtktypebuiltins.h"
 #include "gtkvbox.h"
 
@@ -145,13 +142,6 @@ typedef struct _GtkFileChooserDefaultClass GtkFileChooserDefaultClass;
 #define GTK_IS_FILE_CHOOSER_DEFAULT_CLASS(klass)  (G_TYPE_CHECK_CLASS_TYPE ((klass), GTK_TYPE_FILE_CHOOSER_DEFAULT))
 #define GTK_FILE_CHOOSER_DEFAULT_GET_CLASS(obj)   (G_TYPE_INSTANCE_GET_CLASS ((obj), GTK_TYPE_FILE_CHOOSER_DEFAULT, GtkFileChooserDefaultClass))
 
-typedef enum {
-  LOAD_EMPTY,			/* There is no model */
-  LOAD_PRELOAD,			/* Model is loading and a timer is running; model isn't inserted into the tree yet */
-  LOAD_LOADING,			/* Timeout expired, model is inserted into the tree, but not fully loaded yet */
-  LOAD_FINISHED			/* Model is fully loaded and inserted into the tree */
-} LoadState;
-
 #define MAX_LOADING_TIME 500
 
 struct _GtkFileChooserDefaultClass
@@ -159,111 +149,6 @@ struct _GtkFileChooserDefaultClass
   GtkVBoxClass parent_class;
 };
 
-struct _GtkFileChooserDefault
-{
-  GtkVBox parent_instance;
-
-  GtkFileChooserAction action;
-
-  GtkFileSystem *file_system;
-
-  /* Save mode widgets */
-  GtkWidget *save_widgets;
-
-  GtkWidget *save_file_name_entry;
-  GtkWidget *save_folder_label;
-  GtkWidget *save_folder_combo;
-  GtkWidget *save_expander;
-
-  /* The file browsing widgets */
-  GtkWidget *browse_widgets;
-  GtkWidget *browse_shortcuts_tree_view;
-  GtkWidget *browse_shortcuts_add_button;
-  GtkWidget *browse_shortcuts_remove_button;
-  GtkWidget *browse_shortcuts_popup_menu;
-  GtkWidget *browse_shortcuts_popup_menu_remove_item;
-  GtkWidget *browse_shortcuts_popup_menu_rename_item;
-  GtkWidget *browse_files_tree_view;
-  GtkWidget *browse_files_popup_menu;
-  GtkWidget *browse_files_popup_menu_add_shortcut_item;
-  GtkWidget *browse_files_popup_menu_hidden_files_item;
-  GtkWidget *browse_new_folder_button;
-  GtkWidget *browse_path_bar;
-
-  GtkFileSystemModel *browse_files_model;
-
-  GtkWidget *filter_combo_hbox;
-  GtkWidget *filter_combo;
-  GtkWidget *preview_box;
-  GtkWidget *preview_label;
-  GtkWidget *preview_widget;
-  GtkWidget *extra_align;
-  GtkWidget *extra_widget;
-
-  GtkListStore *shortcuts_model;
-  GtkTreeModel *shortcuts_filter_model;
-
-  GtkTreeModelSort *sort_model;
-
-  LoadState load_state;
-  guint load_timeout_id;
-
-  GSList *pending_select_paths;
-
-  GtkFileFilter *current_filter;
-  GSList *filters;
-
-  GtkTooltips *tooltips;
-
-  gboolean has_home;
-  gboolean has_desktop;
-
-  int num_volumes;
-  int num_shortcuts;
-  int num_bookmarks;
-
-  gulong volumes_changed_id;
-  gulong bookmarks_changed_id;
-
-  GtkFilePath *current_volume_path;
-  GtkFilePath *current_folder;
-  GtkFilePath *preview_path;
-  char *preview_display_name;
-
-  GtkTreeViewColumn *list_name_column;
-  GtkCellRenderer *list_name_renderer;
-
-  GSource *edited_idle;
-  char *edited_new_text;
-
-  gulong settings_signal_id;
-  int icon_size;
-
-  gulong toplevel_set_focus_id;
-  GtkWidget *toplevel_last_focus_widget;
-
-#if 0
-  GdkDragContext *shortcuts_drag_context;
-  GSource *shortcuts_drag_outside_idle;
-#endif
-
-  /* Flags */
-
-  guint local_only : 1;
-  guint preview_widget_active : 1;
-  guint use_preview_label : 1;
-  guint select_multiple : 1;
-  guint show_hidden : 1;
-  guint do_overwrite_confirmation : 1;
-  guint list_sort_ascending : 1;
-  guint changing_folder : 1;
-  guint shortcuts_current_folder_active : 1;
-
-#if 0
-  guint shortcuts_drag_outside : 1;
-#endif
-};
-
 /* Signal IDs */
 enum {
   LOCATION_POPUP,
diff --git a/gtk/gtkfilechooserdialog.c b/gtk/gtkfilechooserdialog.c
index d84f0ba3e3..db1e574410 100644
--- a/gtk/gtkfilechooserdialog.c
+++ b/gtk/gtkfilechooserdialog.c
@@ -19,6 +19,7 @@
  */
 
 #include <config.h>
+#include "gtkfilechooserprivate.h"
 #include "gtkfilechooserdialog.h"
 #include "gtkfilechooserwidget.h"
 #include "gtkfilechooserutils.h"
@@ -30,19 +31,6 @@
 
 #include <stdarg.h>
 
-struct _GtkFileChooserDialogPrivate
-{
-  GtkWidget *widget;
-  
-  char *file_system;
-
-  /* for use with GtkFileChooserEmbed */
-  gint default_width;
-  gint default_height;
-  gboolean resize_horizontally;
-  gboolean resize_vertically;
-};
-
 #define GTK_FILE_CHOOSER_DIALOG_GET_PRIVATE(o)  (GTK_FILE_CHOOSER_DIALOG (o)->priv)
 
 static void gtk_file_chooser_dialog_class_init (GtkFileChooserDialogClass *class);
diff --git a/gtk/gtkfilechooserprivate.h b/gtk/gtkfilechooserprivate.h
index 45ec0b9146..0efc915ef1 100644
--- a/gtk/gtkfilechooserprivate.h
+++ b/gtk/gtkfilechooserprivate.h
@@ -23,6 +23,13 @@
 
 #include "gtkfilechooser.h"
 #include "gtkfilesystem.h"
+#include "gtkfilesystemmodel.h"
+#include "gtkliststore.h"
+#include "gtktooltips.h"
+#include "gtktreemodelsort.h"
+#include "gtktreestore.h"
+#include "gtktreeview.h"
+#include "gtkvbox.h"
 
 G_BEGIN_DECLS
 
@@ -93,6 +100,202 @@ gboolean       _gtk_file_chooser_remove_shortcut_folder  (GtkFileChooser    *cho
 							  const GtkFilePath *path,
 							  GError           **error);
 
+/* GtkFileChooserDialog private */
+
+struct _GtkFileChooserDialogPrivate
+{
+  GtkWidget *widget;
+  
+  char *file_system;
+
+  /* for use with GtkFileChooserEmbed */
+  gint default_width;
+  gint default_height;
+  gboolean resize_horizontally;
+  gboolean resize_vertically;
+};
+
+
+/* GtkFileChooserWidget private */
+
+struct _GtkFileChooserWidgetPrivate
+{
+  GtkWidget *impl;
+
+  char *file_system;
+};
+
+
+/* GtkFileChooserDefault private */
+
+typedef enum {
+  LOAD_EMPTY,			/* There is no model */
+  LOAD_PRELOAD,			/* Model is loading and a timer is running; model isn't inserted into the tree yet */
+  LOAD_LOADING,			/* Timeout expired, model is inserted into the tree, but not fully loaded yet */
+  LOAD_FINISHED			/* Model is fully loaded and inserted into the tree */
+} LoadState;
+
+struct _GtkFileChooserDefault
+{
+  GtkVBox parent_instance;
+
+  GtkFileChooserAction action;
+
+  GtkFileSystem *file_system;
+
+  /* Save mode widgets */
+  GtkWidget *save_widgets;
+
+  GtkWidget *save_file_name_entry;
+  GtkWidget *save_folder_label;
+  GtkWidget *save_folder_combo;
+  GtkWidget *save_expander;
+
+  /* The file browsing widgets */
+  GtkWidget *browse_widgets;
+  GtkWidget *browse_shortcuts_tree_view;
+  GtkWidget *browse_shortcuts_add_button;
+  GtkWidget *browse_shortcuts_remove_button;
+  GtkWidget *browse_shortcuts_popup_menu;
+  GtkWidget *browse_shortcuts_popup_menu_remove_item;
+  GtkWidget *browse_shortcuts_popup_menu_rename_item;
+  GtkWidget *browse_files_tree_view;
+  GtkWidget *browse_files_popup_menu;
+  GtkWidget *browse_files_popup_menu_add_shortcut_item;
+  GtkWidget *browse_files_popup_menu_hidden_files_item;
+  GtkWidget *browse_new_folder_button;
+  GtkWidget *browse_path_bar;
+
+  GtkFileSystemModel *browse_files_model;
+
+  GtkWidget *filter_combo_hbox;
+  GtkWidget *filter_combo;
+  GtkWidget *preview_box;
+  GtkWidget *preview_label;
+  GtkWidget *preview_widget;
+  GtkWidget *extra_align;
+  GtkWidget *extra_widget;
+
+  GtkListStore *shortcuts_model;
+  GtkTreeModel *shortcuts_filter_model;
+
+  GtkTreeModelSort *sort_model;
+
+  LoadState load_state;
+  guint load_timeout_id;
+
+  GSList *pending_select_paths;
+
+  GtkFileFilter *current_filter;
+  GSList *filters;
+
+  GtkTooltips *tooltips;
+
+  gboolean has_home;
+  gboolean has_desktop;
+
+  int num_volumes;
+  int num_shortcuts;
+  int num_bookmarks;
+
+  gulong volumes_changed_id;
+  gulong bookmarks_changed_id;
+
+  GtkFilePath *current_volume_path;
+  GtkFilePath *current_folder;
+  GtkFilePath *preview_path;
+  char *preview_display_name;
+
+  GtkTreeViewColumn *list_name_column;
+  GtkCellRenderer *list_name_renderer;
+
+  GSource *edited_idle;
+  char *edited_new_text;
+
+  gulong settings_signal_id;
+  int icon_size;
+
+  gulong toplevel_set_focus_id;
+  GtkWidget *toplevel_last_focus_widget;
+
+#if 0
+  GdkDragContext *shortcuts_drag_context;
+  GSource *shortcuts_drag_outside_idle;
+#endif
+
+  /* Flags */
+
+  guint local_only : 1;
+  guint preview_widget_active : 1;
+  guint use_preview_label : 1;
+  guint select_multiple : 1;
+  guint show_hidden : 1;
+  guint do_overwrite_confirmation : 1;
+  guint list_sort_ascending : 1;
+  guint changing_folder : 1;
+  guint shortcuts_current_folder_active : 1;
+
+#if 0
+  guint shortcuts_drag_outside : 1;
+#endif
+};
+
+
+/* GtkFileSystemModel private */
+
+typedef struct _FileModelNode           FileModelNode;
+
+struct _GtkFileSystemModel
+{
+  GObject parent_instance;
+
+  GtkFileSystem  *file_system;
+  GtkFileInfoType types;
+  FileModelNode  *roots;
+  GtkFileFolder  *root_folder;
+  GtkFilePath    *root_path;
+
+  GtkFileSystemModelFilter filter_func;
+  gpointer filter_data;
+
+  GSList *idle_clears;
+  GSource *idle_clear_source;
+  GSource *idle_finished_loading_source;
+
+  gushort max_depth;
+  
+  guint show_hidden : 1;
+  guint show_folders : 1;
+  guint show_files : 1;
+  guint folders_only : 1;
+  guint has_editable : 1;
+};
+
+struct _FileModelNode
+{
+  GtkFilePath *path;
+  FileModelNode *next;
+
+  GtkFileInfo *info;
+  GtkFileFolder *folder;
+  
+  FileModelNode *children;
+  FileModelNode *parent;
+  GtkFileSystemModel *model;
+
+  guint ref_count;
+  guint n_referenced_children;
+
+  gushort depth;
+
+  guint has_dummy : 1;
+  guint is_dummy : 1;
+  guint is_visible : 1;
+  guint loaded : 1;
+  guint idle_clear : 1;
+};
+
+
 G_END_DECLS
 
 #endif /* __GTK_FILE_CHOOSER_PRIVATE_H__ */
diff --git a/gtk/gtkfilechooserwidget.c b/gtk/gtkfilechooserwidget.c
index 645b0b0d57..c065f67f65 100644
--- a/gtk/gtkfilechooserwidget.c
+++ b/gtk/gtkfilechooserwidget.c
@@ -19,6 +19,7 @@
  */
 
 #include <config.h>
+#include "gtkfilechooserprivate.h"
 #include "gtkfilechooserwidget.h"
 #include "gtkfilechooserdefault.h"
 #include "gtkfilechooserutils.h"
@@ -27,13 +28,6 @@
 #include "gtkintl.h"
 #include "gtkalias.h"
 
-struct _GtkFileChooserWidgetPrivate
-{
-  GtkWidget *impl;
-
-  char *file_system;
-};
-
 #define GTK_FILE_CHOOSER_WIDGET_GET_PRIVATE(o)  (GTK_FILE_CHOOSER_WIDGET (o)->priv)
 
 static void gtk_file_chooser_widget_class_init   (GtkFileChooserWidgetClass *class);
diff --git a/gtk/gtkfilesystemmodel.c b/gtk/gtkfilesystemmodel.c
index 9c2dd30607..b2ad218ea9 100644
--- a/gtk/gtkfilesystemmodel.c
+++ b/gtk/gtkfilesystemmodel.c
@@ -21,6 +21,7 @@
 #include <config.h>
 #include <string.h>
 
+#include "gtkfilechooserprivate.h"
 #include "gtkfilesystemmodel.h"
 #include "gtkfilesystem.h"
 #include "gtkintl.h"
@@ -30,7 +31,6 @@
 #include "gtkalias.h"
 
 typedef struct _GtkFileSystemModelClass GtkFileSystemModelClass;
-typedef struct _FileModelNode           FileModelNode;
 
 #define GTK_FILE_SYSTEM_MODEL_CLASS(klass)     (G_TYPE_CHECK_CLASS_CAST ((klass), GTK_TYPE_FILE_SYSTEM_MODEL, GtkFileSystemModelClass))
 #define GTK_IS_FILE_SYSTEM_MODEL_CLASS(klass)  (G_TYPE_CHECK_CLASS_TYPE ((klass), GTK_TYPE_FILE_SYSTEM_MODEL))
@@ -45,55 +45,6 @@ struct _GtkFileSystemModelClass
   void (*finished_loading) (GtkFileSystemModel *model);
 };
 
-struct _GtkFileSystemModel
-{
-  GObject parent_instance;
-
-  GtkFileSystem  *file_system;
-  GtkFileInfoType types;
-  FileModelNode  *roots;
-  GtkFileFolder  *root_folder;
-  GtkFilePath    *root_path;
-
-  GtkFileSystemModelFilter filter_func;
-  gpointer filter_data;
-
-  GSList *idle_clears;
-  GSource *idle_clear_source;
-  GSource *idle_finished_loading_source;
-
-  gushort max_depth;
-  
-  guint show_hidden : 1;
-  guint show_folders : 1;
-  guint show_files : 1;
-  guint folders_only : 1;
-  guint has_editable : 1;
-};
-
-struct _FileModelNode
-{
-  GtkFilePath *path;
-  FileModelNode *next;
-
-  GtkFileInfo *info;
-  GtkFileFolder *folder;
-  
-  FileModelNode *children;
-  FileModelNode *parent;
-  GtkFileSystemModel *model;
-
-  guint ref_count;
-  guint n_referenced_children;
-
-  gushort depth;
-
-  guint has_dummy : 1;
-  guint is_dummy : 1;
-  guint is_visible : 1;
-  guint loaded : 1;
-  guint idle_clear : 1;
-};
 
 static void gtk_file_system_model_class_init   (GtkFileSystemModelClass *class);
 static void gtk_file_system_model_iface_init   (GtkTreeModelIface       *iface);
diff --git a/tests/Makefile.am b/tests/Makefile.am
index a2bc7e7935..58fdf41be7 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -27,6 +27,7 @@ endif
 
 
 noinst_PROGRAMS =			\
+	autotestfilechooser		\
 	simple				\
 	testcairo			\
 	testcalendar			\
@@ -73,6 +74,7 @@ noinst_PROGRAMS =			\
 	testmerge			\
 	testactions
 
+autotestfilechooser_DEPENDENCIES = $(TEST_DEPS)
 simple_DEPENDENCIES = $(TEST_DEPS)
 testicontheme_DEPENDENCIES = $(TEST_DEPS)
 testiconview_DEPENDENCIES = $(TEST_DEPS)
@@ -113,6 +115,7 @@ testxinerama_DEPENDENCIES = $(TEST_DEPS)
 testmerge_DEPENDENCIES = $(TEST_DEPS)
 testactions_DEPENDENCIES = $(TEST_DEPS)
 
+autotestfilechooser_LDADD = $(LDADDS)
 simple_LDADD = $(LDADDS)
 testcairo_LDADD = $(LDADDS)
 testcalendar_LDADD = $(LDADDS)
@@ -160,6 +163,9 @@ pixbuf_threads_LDADD = $(LDADDS) $(GLIB_LIBS)
 testmerge_LDADD = $(LDADDS)
 testactions_LDADD = $(LDADDS)
 
+autotestfilechooser_SOURCES =	\
+	autotestfilechooser.c
+
 testfilechooser_SOURCES = 	\
 	prop-editor.c		\
 	testfilechooser.c 	
diff --git a/tests/autotestfilechooser.c b/tests/autotestfilechooser.c
new file mode 100644
index 0000000000..0ba2683333
--- /dev/null
+++ b/tests/autotestfilechooser.c
@@ -0,0 +1,252 @@
+#define GTK_FILE_SYSTEM_ENABLE_UNSUPPORTED
+
+#include <config.h>
+#include <glib/gprintf.h>
+#include <gtk/gtk.h>
+#include "gtk/gtkfilechooserprivate.h"
+#include "gtk/gtkfilechooserdefault.h"
+#include "gtk/gtkfilechooserentry.h"
+
+static void
+log_test (gboolean passed, const char *test_name, ...)
+{
+  va_list args;
+  char *str;
+
+  va_start (args, test_name);
+  str = g_strdup_vprintf (test_name, args);
+  va_end (args);
+
+  g_printf ("%s: %s\n", passed ? "PASSED" : "FAILED", str);
+  g_free (str);
+}
+
+static const GtkFileChooserAction open_actions[] = {
+  GTK_FILE_CHOOSER_ACTION_OPEN,
+  GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER
+};
+
+static const GtkFileChooserAction save_actions[] = {
+  GTK_FILE_CHOOSER_ACTION_SAVE,
+  GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER
+};
+
+
+static gboolean
+has_action (const GtkFileChooserAction *actions,
+	    int n_actions,
+	    GtkFileChooserAction sought_action)
+{
+  int i;
+
+  for (i = 0; i < n_actions; i++)
+    if (actions[i] == sought_action)
+      return TRUE;
+
+  return FALSE;
+}
+
+static const char *
+get_action_name (GtkFileChooserAction action)
+{
+  GEnumClass *enum_class;
+  GEnumValue *enum_value;
+
+  enum_class = g_type_class_peek (GTK_TYPE_FILE_CHOOSER_ACTION);
+  if (!enum_class)
+    g_error ("BUG: get_action_name(): no GEnumClass for GTK_TYPE_FILE_CHOOSER_ACTION");
+
+  enum_value = g_enum_get_value (enum_class, (int) action);
+  if (!enum_value)
+    g_error ("BUG: get_action_name(): no GEnumValue for GtkFileChooserAction %d", (int) action);
+
+  return enum_value->value_name;
+}
+
+static gboolean
+test_widgets_for_current_action (GtkFileChooserDialog *dialog,
+				 GtkFileChooserAction  expected_action)
+{
+  GtkFileChooserDialogPrivate *dialog_priv;
+  GtkFileChooserWidget *chooser_widget;
+  GtkFileChooserWidgetPrivate *widget_priv;
+  GtkFileChooserDefault *impl;
+  gboolean passed;
+
+  if (gtk_file_chooser_get_action (GTK_FILE_CHOOSER (dialog)) != expected_action)
+    return FALSE;
+
+  dialog_priv = dialog->priv;
+  chooser_widget = GTK_FILE_CHOOSER_WIDGET (dialog_priv->widget);
+  if (!chooser_widget)
+    g_error ("BUG: dialog_priv->widget is not a GtkFileChooserWidget");
+
+  widget_priv = chooser_widget->priv;
+  impl = (GtkFileChooserDefault *) (widget_priv->impl);
+  if (!impl)
+    g_error ("BUG: widget_priv->impl is not a GtkFileChooserDefault");
+
+  g_assert (impl->action == expected_action);
+
+  passed = TRUE;
+
+  /* OPEN implies that the "new folder" button is hidden; otherwise it is shown */
+  if (impl->action == GTK_FILE_CHOOSER_ACTION_OPEN)
+    passed = passed && !GTK_WIDGET_VISIBLE (impl->browse_new_folder_button);
+  else
+    passed = passed && GTK_WIDGET_VISIBLE (impl->browse_new_folder_button);
+
+  /* Check that the widgets are present/visible or not */
+  if (has_action (open_actions, G_N_ELEMENTS (open_actions), impl->action))
+    {
+      passed = passed && (impl->save_widgets == NULL
+			  && impl->save_file_name_entry == NULL
+			  && impl->save_folder_label == NULL
+			  && impl->save_folder_combo == NULL
+			  && impl->save_expander == NULL
+			  && GTK_IS_CONTAINER (impl->browse_widgets) && GTK_WIDGET_DRAWABLE (impl->browse_widgets));
+    }
+  else if (has_action (save_actions, G_N_ELEMENTS (save_actions), impl->action))
+    {
+      /* FIXME: we can't use GTK_IS_FILE_CHOOSER_ENTRY() because it uses
+       * _gtk_file_chooser_entry_get_type(), which is a non-exported symbol.
+       * So, we just test impl->save_file_name_entry for being non-NULL
+       */
+      passed = passed && (GTK_IS_CONTAINER (impl->save_widgets) && GTK_WIDGET_DRAWABLE (impl->save_widgets)
+			  && impl->save_file_name_entry != NULL && GTK_WIDGET_DRAWABLE (impl->save_file_name_entry)
+			  && GTK_IS_LABEL (impl->save_folder_label) && GTK_WIDGET_DRAWABLE (impl->save_folder_label)
+			  && GTK_IS_COMBO_BOX (impl->save_folder_combo) && GTK_WIDGET_DRAWABLE (impl->save_folder_combo)
+			  && GTK_IS_EXPANDER (impl->save_expander) && GTK_WIDGET_DRAWABLE (impl->save_expander)
+			  && GTK_IS_CONTAINER (impl->browse_widgets));
+
+      /* FIXME: we are in a SAVE mode; test the visibility and sensitivity of
+       * the children that change depending on the state of the expander.
+       */
+    }
+  else
+    {
+      g_error ("BAD TEST: test_widgets_for_current_action() doesn't know about %s", get_action_name (impl->action));
+      passed = FALSE;
+    }
+
+  return passed;
+}
+
+typedef gboolean (* ForeachActionCallback) (GtkFileChooserDialog *dialog,
+					    GtkFileChooserAction  action,
+					    gpointer              user_data);
+
+static gboolean
+foreach_action (GtkFileChooserDialog *dialog,
+		ForeachActionCallback callback,
+		gpointer              user_data)
+{
+  GEnumClass *enum_class;
+  int i;
+
+  enum_class = g_type_class_peek (GTK_TYPE_FILE_CHOOSER_ACTION);
+  if (!enum_class)
+    g_error ("BUG: get_action_name(): no GEnumClass for GTK_TYPE_FILE_CHOOSER_ACTION");
+
+  for (i = 0; i < enum_class->n_values; i++)
+    {
+      GEnumValue *enum_value;
+      GtkFileChooserAction action;
+      gboolean passed;
+
+      enum_value = enum_class->values + i;
+      action = enum_value->value;
+
+      passed = (* callback) (dialog, action, user_data);
+      if (!passed)
+	return FALSE;
+    }
+
+  return TRUE;
+}
+
+struct action_closure {
+  GtkFileChooserAction from_action;
+};
+
+static gboolean
+switch_from_to_action_cb (GtkFileChooserDialog *dialog,
+			  GtkFileChooserAction  action,
+			  gpointer              user_data)
+{
+  struct action_closure *closure;
+  gboolean passed;
+
+  closure = user_data;
+
+  gtk_file_chooser_set_action (GTK_FILE_CHOOSER (dialog), closure->from_action);
+
+  passed = test_widgets_for_current_action (dialog, closure->from_action);
+  log_test (passed, "switch_from_to_action_cb(): reset to action %s", get_action_name (closure->from_action));
+  if (!passed)
+    return FALSE;
+
+  gtk_file_chooser_set_action (GTK_FILE_CHOOSER (dialog), action);
+
+  passed = test_widgets_for_current_action (dialog, action);
+  log_test (passed, "switch_from_to_action_cb(): transition from %s to %s",
+	    get_action_name (closure->from_action),
+	    get_action_name (action));
+  return passed;
+}
+
+static gboolean
+switch_from_action_cb (GtkFileChooserDialog *dialog,
+		       GtkFileChooserAction  action,
+		       gpointer              user_data)
+{
+  struct action_closure closure;
+
+  closure.from_action = action;
+
+  return foreach_action (dialog, switch_from_to_action_cb, &closure);
+}
+
+static gboolean
+test_action_widgets (GtkFileChooserDialog *dialog)
+{
+  GtkFileChooserAction action;
+  gboolean passed;
+
+  action = gtk_file_chooser_get_action (GTK_FILE_CHOOSER (dialog));
+
+  passed = test_widgets_for_current_action (dialog, action);
+  log_test (passed, "test_action_widgets(): widgets for initial action %s", get_action_name (action));
+  if (!passed)
+    return FALSE;
+
+  passed = foreach_action (dialog, switch_from_action_cb, NULL);
+  log_test (passed, "test_action_widgets(): all transitions through property change");
+
+  return passed;
+}
+
+
+int
+main (int argc, char **argv)
+{
+  GtkWidget *dialog;
+
+  gtk_init (&argc, &argv);
+
+  dialog = gtk_file_chooser_dialog_new ("Test file chooser",
+					NULL,
+					GTK_FILE_CHOOSER_ACTION_OPEN,
+					GTK_STOCK_CANCEL,
+					GTK_RESPONSE_CANCEL,
+					GTK_STOCK_OK,
+					GTK_RESPONSE_ACCEPT,
+					NULL);
+  gtk_widget_show (dialog);
+
+  test_action_widgets (GTK_FILE_CHOOSER_DIALOG (dialog));
+
+  gtk_widget_destroy (dialog);
+
+  return 0;
+}
-- 
GitLab