diff --git a/tests/autotestfilesystem.c b/tests/autotestfilesystem.c new file mode 100644 index 0000000000..33bd6ba4b0 --- /dev/null +++ b/tests/autotestfilesystem.c @@ -0,0 +1,719 @@ +/* GTK - The GIMP Toolkit + * autotestfilesystem.c: Automated tests for GtkFileSystem implementations + * Copyright (C) 2005, Novell, Inc. + * + * Authors: + * Federico Mena-Quintero + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#define GTK_FILE_SYSTEM_ENABLE_UNSUPPORTED + +#include +#include +#include +#include +#include +#include + +#define CALLBACK_TIMEOUT_MS 3000 /* Period after which the callback must have been called */ +#define CANCEL_TIMEOUT_MS 100 /* We'll sleep for this much time before cancelling */ + +#define GET_FOLDER_FILENAME "/etc" +#define GET_INFO_FILENAME "/etc/passwd" +#define CREATE_FOLDER_FILENAME "/tmp/autotestfilesystem-tmp" +#define VOLUME_MOUNT_FILENAME "/" + +/* This is stolen from gtkfilechooserdefault.c:set_file_system_backend() */ +static GtkFileSystem * +get_file_system (void) +{ + GtkFileSystem *file_system = NULL; + +#if 1 + file_system = gtk_file_system_create ("gnome-vfs"); +#else + GtkSettings *settings = gtk_settings_get_default (); + gchar *default_backend = NULL; + + g_object_get (settings, "gtk-file-chooser-backend", &default_backend, NULL); + if (default_backend) + { + file_system = gtk_file_system_create (default_backend); + g_free (default_backend); + } + + if (!file_system) + { +#if defined (G_OS_UNIX) + file_system = gtk_file_system_unix_new (); +#elif defined (G_OS_WIN32) + file_system = gtk_file_system_win32_new (); +#else +#error "No default filesystem implementation on the platform" +#endif + } + +#endif + + return file_system; +} + + + +/***** Testing infrastructure *****/ + +typedef struct { + gboolean callback_was_called; + gboolean timeout_was_called; +} TestCallbackClosure; + +static void +notify_callback_called (TestCallbackClosure *closure) +{ + closure->callback_was_called = TRUE; + gtk_main_quit (); +} + +static gboolean +timeout_cb (gpointer data) +{ + TestCallbackClosure *closure; + + closure = data; + + closure->timeout_was_called = TRUE; + gtk_main_quit (); + + return FALSE; +} + +static void +wait_for_callback (TestCallbackClosure *closure) +{ + g_timeout_add (CALLBACK_TIMEOUT_MS, timeout_cb, closure); + gtk_main (); +} + +typedef struct { + const char *test_name; + gboolean callback_must_be_called; + gpointer (* setup_fn) (GtkFileSystem *file_system, gboolean *success, char **failure_reason, + TestCallbackClosure *callback_closure); + void (* cleanup_fn) (gpointer data, gboolean *success, char **failure_reason); +} TestSpec; + +static gboolean +run_test (TestSpec *test_spec) +{ + GtkFileSystem *file_system; + TestCallbackClosure closure; + gboolean success_setup, success_cleanup; + gpointer test_data; + gboolean callback_success; + gboolean passed; + char *setup_failure_reason; + char *cleanup_failure_reason; + + file_system = get_file_system (); + if (!file_system) + { + printf ("FAIL: test \"%s\"\n", test_spec->test_name); + printf (" could not create file system!\n"); + return FALSE; + } + + closure.callback_was_called = FALSE; + closure.timeout_was_called = FALSE; + + success_setup = success_cleanup = callback_success = FALSE; + setup_failure_reason = cleanup_failure_reason = NULL; + + test_data = test_spec->setup_fn (file_system, &success_setup, &setup_failure_reason, &closure); + if (success_setup) + { + wait_for_callback (&closure); + + test_spec->cleanup_fn (test_data, &success_cleanup, &cleanup_failure_reason); + + callback_success = (test_spec->callback_must_be_called == closure.callback_was_called); + } + + g_object_unref (file_system); + + passed = (success_setup && success_cleanup && callback_success); + + printf ("%s: test \"%s\"\n", passed ? "PASS" : "FAIL", test_spec->test_name); + + if (!passed) + { + if (!success_setup) + printf (" failure during setup: %s\n", + setup_failure_reason ? setup_failure_reason : "unknown failure"); + else + { + if (!success_cleanup) + printf (" failure during cleanup: %s\n", + cleanup_failure_reason ? cleanup_failure_reason : "unknown failure"); + + if (!callback_success) + printf (" callback %s called but it %s called\n", + test_spec->callback_must_be_called ? "MUST BE" : "MUST NOT BE", + closure.callback_was_called ? "WAS" : "WAS NOT"); + } + } + + g_free (setup_failure_reason); + g_free (cleanup_failure_reason); + + return passed; +} + +static gboolean +run_tests (TestSpec *test_specs, int num_tests) +{ + int i; + int num_passed; + + num_passed = 0; + + for (i = 0; i < num_tests; i++) + if (run_test (test_specs + i)) + num_passed++; + + if (num_passed == num_tests) + printf ("ALL TESTS PASSED\n"); + else + printf ("%d of %d tests FAILED\n", (num_tests - num_passed), num_tests); + + return (num_passed == num_tests); +} + + + +/***** Test functions *****/ + +static void +sleep_and_cancel_handle (GtkFileSystemHandle *handle) +{ + g_usleep (CANCEL_TIMEOUT_MS * 1000); + gtk_file_system_cancel_operation (handle); +} + +/* get_folder */ + +struct get_folder_data { + TestCallbackClosure *callback_closure; + GtkFileSystemHandle *handle; + GtkFileFolder *folder; +}; + +static void +get_folder_cb (GtkFileSystemHandle *handle, + GtkFileFolder *folder, + const GError *error, + gpointer data) +{ + struct get_folder_data *get_folder_data; + + get_folder_data = data; + get_folder_data->folder = folder; + notify_callback_called (get_folder_data->callback_closure); +} + +static gpointer +get_folder_generic_setup (GtkFileSystem *file_system, gboolean *success, char **failure_reason, + TestCallbackClosure *callback_closure) +{ + struct get_folder_data *get_folder_data; + GtkFilePath *path; + + path = gtk_file_system_filename_to_path (file_system, GET_FOLDER_FILENAME); + if (!path) + { + *success = FALSE; + *failure_reason = g_strdup_printf ("could not turn \"%s\" into a GtkFilePath", GET_FOLDER_FILENAME); + return NULL; + } + + get_folder_data = g_new (struct get_folder_data, 1); + + get_folder_data->callback_closure = callback_closure; + get_folder_data->folder = NULL; + + get_folder_data->handle = gtk_file_system_get_folder (file_system, + path, + GTK_FILE_INFO_ALL, + get_folder_cb, + get_folder_data); + gtk_file_path_free (path); + + if (!get_folder_data->handle) + { + g_free (get_folder_data); + *success = FALSE; + *failure_reason = g_strdup ("gtk_file_system_get_folder() returned a NULL handle"); + return NULL; + } + + *success = TRUE; + + return get_folder_data; +} + +static gpointer +get_folder_no_cancel_setup (GtkFileSystem *file_system, gboolean *success, char **failure_reason, + TestCallbackClosure *callback_closure) +{ + return get_folder_generic_setup (file_system, success, failure_reason, callback_closure); +} + +static void +get_folder_cleanup (gpointer data, gboolean *success, char **failure_reason) +{ + struct get_folder_data *get_folder_data; + + get_folder_data = data; + + if (get_folder_data->folder) + g_object_unref (get_folder_data->folder); + + g_free (get_folder_data); + + *success = TRUE; +} + +static gpointer +get_folder_with_cancel_setup (GtkFileSystem *file_system, gboolean *success, char **failure_reason, + TestCallbackClosure *callback_closure) +{ + struct get_folder_data *get_folder_data; + + get_folder_data = get_folder_generic_setup (file_system, success, failure_reason, callback_closure); + + if (*success) + sleep_and_cancel_handle (get_folder_data->handle); + + return get_folder_data; +} + +/* get_info */ + +struct get_info_data { + TestCallbackClosure *callback_closure; + GtkFileSystemHandle *handle; +}; + +static void +get_info_cb (GtkFileSystemHandle *handle, + const GtkFileInfo *file_info, + const GError *error, + gpointer data) +{ + struct get_info_data *get_info_data; + + get_info_data = data; + notify_callback_called (get_info_data->callback_closure); +} + +static gpointer +get_info_generic_setup (GtkFileSystem *file_system, gboolean *success, char **failure_reason, + TestCallbackClosure *callback_closure) +{ + GtkFilePath *path; + struct get_info_data *get_info_data; + + path = gtk_file_system_filename_to_path (file_system, GET_INFO_FILENAME); + if (!path) + { + *success = FALSE; + *failure_reason = g_strdup_printf ("could not turn \"%s\" into a GtkFilePath", GET_INFO_FILENAME); + return NULL; + } + + get_info_data = g_new (struct get_info_data, 1); + + get_info_data->callback_closure = callback_closure; + get_info_data->handle = gtk_file_system_get_info (file_system, + path, + GTK_FILE_INFO_ALL, + get_info_cb, + get_info_data); + gtk_file_path_free (path); + + if (!get_info_data->handle) + { + g_free (get_info_data); + *success = FALSE; + *failure_reason = g_strdup ("gtk_file_system_get_info() returned a NULL handle"); + return NULL; + } + + *success = TRUE; + return get_info_data; +} + +static gpointer +get_info_no_cancel_setup (GtkFileSystem *file_system, gboolean *success, char **failure_reason, + TestCallbackClosure *callback_closure) +{ + return get_info_generic_setup (file_system, success, failure_reason, callback_closure); +} + +static void +get_info_cleanup (gpointer data, gboolean *success, char **failure_reason) +{ + struct get_info_data *get_info_data; + + get_info_data = data; + g_free (get_info_data); + + *success = TRUE; +} + +static gpointer +get_info_with_cancel_setup (GtkFileSystem *file_system, gboolean *success, char **failure_reason, + TestCallbackClosure *callback_closure) +{ + struct get_info_data *get_info_data; + + get_info_data = get_info_generic_setup (file_system, success, failure_reason, callback_closure); + + if (*success) + sleep_and_cancel_handle (get_info_data->handle); + + return get_info_data; +} + +/* create_folder */ + +struct create_folder_data { + TestCallbackClosure *callback_closure; + GtkFileSystemHandle *handle; +}; + +static void +create_folder_cb (GtkFileSystemHandle *handle, + const GtkFilePath *path, + const GError *error, + gpointer data) +{ + struct get_folder_data *get_folder_data; + + get_folder_data = data; + notify_callback_called (get_folder_data->callback_closure); +} + +static gpointer +create_folder_generic_setup (GtkFileSystem *file_system, gboolean *success, char **failure_reason, + TestCallbackClosure *callback_closure) +{ + GtkFilePath *path; + struct create_folder_data *create_folder_data; + + path = gtk_file_system_filename_to_path (file_system, CREATE_FOLDER_FILENAME); + if (!path) + { + *success = FALSE; + *failure_reason = g_strdup_printf ("could not turn \"%s\" into a GtkFilePath", CREATE_FOLDER_FILENAME); + return NULL; + } + + create_folder_data = g_new (struct create_folder_data, 1); + + create_folder_data->callback_closure = callback_closure; + create_folder_data->handle = gtk_file_system_create_folder (file_system, + path, + create_folder_cb, + create_folder_data); + gtk_file_path_free (path); + + if (!create_folder_data->handle) + { + g_free (create_folder_data); + *success = FALSE; + *failure_reason = g_strdup ("gtk_file_system_create_folder() returned a NULL handle"); + return NULL; + } + + *success = TRUE; + return create_folder_data; +} + +static gpointer +create_folder_no_cancel_setup (GtkFileSystem *file_system, gboolean *success, char **failure_reason, + TestCallbackClosure *callback_closure) +{ + return create_folder_generic_setup (file_system, success, failure_reason, callback_closure); +} + +static void +create_folder_cleanup (gpointer data, gboolean *success, char **failure_reason) +{ + struct create_folder_data *create_folder_data; + + create_folder_data = data; + + rmdir (CREATE_FOLDER_FILENAME); + + g_free (create_folder_data); + + *success = TRUE; +} + +static gpointer +create_folder_with_cancel_setup (GtkFileSystem *file_system, gboolean *success, char **failure_reason, + TestCallbackClosure *callback_closure) +{ + struct create_folder_data *create_folder_data; + + create_folder_data = create_folder_generic_setup (file_system, success, failure_reason, callback_closure); + + if (*success) + sleep_and_cancel_handle (create_folder_data->handle); + + return create_folder_data; +} + +/* volume_mount */ + +struct volume_mount_data { + TestCallbackClosure *callback_closure; + GtkFileSystemVolume *volume; + GtkFileSystemHandle *handle; +}; + +static void +volume_mount_cb (GtkFileSystemHandle *handle, + GtkFileSystemVolume *volume, + const GError *error, + gpointer data) +{ + struct volume_mount_data *volume_mount_data; + + volume_mount_data = data; + notify_callback_called (volume_mount_data->callback_closure); +} + +static gpointer +volume_mount_generic_setup (GtkFileSystem *file_system, gboolean *success, char **failure_reason, + TestCallbackClosure *callback_closure) +{ + GtkFilePath *path; + struct volume_mount_data *volume_mount_data; + + path = gtk_file_system_filename_to_path (file_system, VOLUME_MOUNT_FILENAME); + if (!path) + { + *success = FALSE; + *failure_reason = g_strdup_printf ("could not turn \"%s\" into a GtkFilePath", VOLUME_MOUNT_FILENAME); + return NULL; + } + + volume_mount_data = g_new (struct volume_mount_data, 1); + + volume_mount_data->callback_closure = callback_closure; + volume_mount_data->volume = gtk_file_system_get_volume_for_path (file_system, path); + gtk_file_path_free (path); + + if (!volume_mount_data->volume) + { + g_free (volume_mount_data); + *success = FALSE; + *failure_reason = g_strdup ("gtk_file_system_get_volume_for_path() returned a NULL volume"); + return NULL; + } + + volume_mount_data->handle = gtk_file_system_volume_mount (file_system, + volume_mount_data->volume, + volume_mount_cb, + volume_mount_data); + if (!volume_mount_data->handle) + { + g_object_unref (volume_mount_data->volume); + g_free (volume_mount_data); + *success = FALSE; + *failure_reason = g_strdup ("gtk_file_system_volume_mount() returned a NULL handle"); + return NULL; + } + + *success = TRUE; + return volume_mount_data; +} + +static gpointer +volume_mount_no_cancel_setup (GtkFileSystem *file_system, gboolean *success, char **failure_reason, + TestCallbackClosure *callback_closure) +{ + return volume_mount_generic_setup (file_system, success, failure_reason, callback_closure); +} + +static void +volume_mount_cleanup (gpointer data, gboolean *success, char **failure_reason) +{ + struct volume_mount_data *volume_mount_data; + + volume_mount_data = data; + + g_object_unref (volume_mount_data->volume); + g_free (volume_mount_data); + + *success = TRUE; +} + +static gpointer +volume_mount_with_cancel_setup (GtkFileSystem *file_system, gboolean *success, char **failure_reason, + TestCallbackClosure *callback_closure) +{ + struct volume_mount_data *volume_mount_data; + + volume_mount_data = volume_mount_generic_setup (file_system, success, failure_reason, callback_closure); + + if (*success) + sleep_and_cancel_handle (volume_mount_data->handle); + + return volume_mount_data; +} + +/* tests */ + +static TestSpec tests[] = { + { + "get_folder no cancel", + TRUE, + get_folder_no_cancel_setup, + get_folder_cleanup + }, + { + "get_folder with cancel", + FALSE, + get_folder_with_cancel_setup, + get_folder_cleanup + }, + { + "get_info no cancel", + TRUE, + get_info_no_cancel_setup, + get_info_cleanup + }, + { + "get_info with cancel", + FALSE, + get_info_with_cancel_setup, + get_info_cleanup + }, + { + "create_folder no cancel", + TRUE, + create_folder_no_cancel_setup, + create_folder_cleanup + }, + { + "create_folder with cancel", + FALSE, + create_folder_with_cancel_setup, + create_folder_cleanup + }, + { + "volume_mount no cancel", + TRUE, + volume_mount_no_cancel_setup, + volume_mount_cleanup + }, + { + "volume_mount with cancel", + FALSE, + volume_mount_with_cancel_setup, + volume_mount_cleanup + } +}; + + + +/***** main *****/ + +static GLogFunc default_log_handler; +static int num_warnings; +static int num_errors; +static int num_critical_errors; + +static void +log_override_cb (const gchar *log_domain, + GLogLevelFlags log_level, + const gchar *message, + gpointer user_data) +{ + if (log_level & G_LOG_LEVEL_WARNING) + num_warnings++; + + if (log_level & G_LOG_LEVEL_ERROR) + num_errors++; + + if (log_level & G_LOG_LEVEL_CRITICAL) + num_critical_errors++; + + (* default_log_handler) (log_domain, log_level, message, user_data); +} + +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); +} + +int +main (int argc, char **argv) +{ + gboolean passed; + gboolean zero_warnings; + gboolean zero_errors; + gboolean zero_critical_errors; + + default_log_handler = g_log_set_default_handler (log_override_cb, NULL); + + gtk_init (&argc, &argv); + + /* Start tests */ + + passed = run_tests (tests, G_N_ELEMENTS (tests)); + + /* Warnings and errors */ + + zero_warnings = num_warnings == 0; + zero_errors = num_errors == 0; + zero_critical_errors = num_critical_errors == 0; + + log_test (zero_warnings, "main(): zero warnings (actual number %d)", num_warnings); + log_test (zero_errors, "main(): zero errors (actual number %d)", num_errors); + log_test (zero_critical_errors, "main(): zero critical errors (actual number %d)", num_critical_errors); + + /* Done */ + + passed = passed && zero_warnings && zero_errors && zero_critical_errors; + + log_test (passed, "main(): ALL TESTS"); + + return 0; +}