Install all test data
[platform/upstream/glib.git] / gio / tests / live-g-file.c
index 08e4d12..6edc99a 100644 (file)
@@ -23,6 +23,9 @@
 #include <glib/glib.h>
 #include <gio/gio.h>
 #include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <sys/types.h>
 #include <string.h>
 #include <sys/stat.h>
 
@@ -51,6 +54,8 @@ enum StructureExtraFlags
   TEST_OPEN = 1 << 15,
   TEST_OVERWRITE = 1 << 16,
   TEST_INVALID_SYMLINK = 1 << 17,
+  TEST_HIDDEN = 1 << 18,
+  TEST_DOT_HIDDEN = 1 << 19,
 };
 
 struct StructureItem
@@ -98,20 +103,37 @@ static const struct StructureItem sample_struct[] = {
     {"not_exists4",                    NULL,   G_FILE_TYPE_REGULAR,    G_FILE_CREATE_NONE, 0, TEST_HANDLE_SPECIAL, TEST_NOT_EXISTS | TEST_APPEND},
     {"dir_no-execute/file",    NULL,   G_FILE_TYPE_REGULAR,    G_FILE_CREATE_NONE, 0, TEST_HANDLE_SPECIAL, TEST_DELETE_NORMAL | TEST_DELETE_FAILURE | TEST_NOT_EXISTS | TEST_OPEN},
        {"lost_symlink",                "nowhere",      G_FILE_TYPE_SYMBOLIC_LINK, G_FILE_CREATE_NONE, 0, 0, TEST_COPY | TEST_DELETE_NORMAL | TEST_OPEN | TEST_INVALID_SYMLINK},
+    {"dir_hidden",             NULL,   G_FILE_TYPE_DIRECTORY,  G_FILE_CREATE_NONE, 0, 0, 0},
+    {"dir_hidden/.hidden",             NULL,   G_FILE_TYPE_REGULAR,    G_FILE_CREATE_NONE, 0, TEST_HANDLE_SPECIAL, 0},
+    {"dir_hidden/.a-hidden-file",      NULL,   G_FILE_TYPE_REGULAR,    G_FILE_CREATE_NONE, 0, 0, TEST_HIDDEN},
+    {"dir_hidden/file-in-.hidden1",    NULL,   G_FILE_TYPE_REGULAR,    G_FILE_CREATE_NONE, 0, 0, TEST_HIDDEN | TEST_DOT_HIDDEN},
+    {"dir_hidden/file-in-.hidden2",    NULL,   G_FILE_TYPE_REGULAR,    G_FILE_CREATE_NONE, 0, 0, TEST_HIDDEN | TEST_DOT_HIDDEN},
   };
 
+static gboolean test_suite;
 static gboolean write_test;
 static gboolean verbose;
 static gboolean posix_compat;
 
+#ifdef G_HAVE_ISO_VARARGS
+#define log(...) if (verbose)  g_print (__VA_ARGS__)
+#elif defined(G_HAVE_GNUC_VARARGS)
 #define log(msg...) if (verbose)  g_print (msg)
+#else  /* no varargs macros */
+static void log (const g_char *format, ...)
+{
+  va_list args;
+  va_start (args, format);
+  if (verbose) g_print (format, args);
+  va_end (args);
+}
+#endif
 
 static GFile *
 create_empty_file (GFile * parent, const char *filename,
                   GFileCreateFlags create_flags)
 {
   GFile *child;
-  gboolean res;
   GError *error;
   GFileOutputStream *outs;
 
@@ -123,7 +145,7 @@ create_empty_file (GFile * parent, const char *filename,
   g_assert_no_error (error);
   g_assert (outs != NULL);
   error = NULL;
-  res = g_output_stream_close (G_OUTPUT_STREAM (outs), NULL, &error);
+  g_output_stream_close (G_OUTPUT_STREAM (outs), NULL, &error);
   g_object_unref (outs);
   return child;
 }
@@ -169,7 +191,7 @@ test_create_structure (gconstpointer test_data)
   GError *error;
   GFileOutputStream *outs;
   GDataOutputStream *outds;
-  int i;
+  guint i;
   struct StructureItem item;
 
   g_assert (test_data != NULL);
@@ -208,6 +230,10 @@ test_create_structure (gconstpointer test_data)
               item.link_to);
          child = create_symlink (root, item.filename, item.link_to);
          break;
+        case G_FILE_TYPE_UNKNOWN:
+        case G_FILE_TYPE_SPECIAL:
+        case G_FILE_TYPE_SHORTCUT:
+        case G_FILE_TYPE_MOUNTABLE:
        default:
          break;
        }
@@ -225,6 +251,24 @@ test_create_structure (gconstpointer test_data)
          g_assert_no_error (error);
        }
 
+      if ((item.extra_flags & TEST_DOT_HIDDEN) == TEST_DOT_HIDDEN)
+       {
+         gchar *dir, *path, *basename;
+         FILE *f;
+
+         dir = g_path_get_dirname (item.filename);
+         basename = g_path_get_basename (item.filename);
+         path = g_build_filename (test_data, dir, ".hidden", NULL);
+
+         f = fopen (path, "a");
+         fprintf (f, "%s\n", basename);
+         fclose (f);
+
+         g_free (dir);
+         g_free (path);
+         g_free (basename);
+       }
+
       g_object_unref (child);
     }
 
@@ -285,6 +329,7 @@ test_attributes (struct StructureItem item, GFileInfo * info)
   gboolean utf8_valid;
   gboolean has_attr;
   gboolean is_symlink;
+  gboolean is_hidden;
   gboolean can_read, can_write;
 
   /*  standard::type  */
@@ -363,6 +408,15 @@ test_attributes (struct StructureItem item, GFileInfo * info)
       symlink_target = g_file_info_get_symlink_target (info);
       g_assert_cmpstr (symlink_target, ==, item.link_to);
     }
+
+  /*  standard::is-hidden  */
+  if ((item.extra_flags & TEST_HIDDEN) == TEST_HIDDEN)
+    {
+      is_hidden =
+       g_file_info_get_attribute_boolean (info,
+                                          G_FILE_ATTRIBUTE_STANDARD_IS_HIDDEN);
+      g_assert_cmpint (is_hidden, ==, TRUE);
+    }
 }
 
 static void
@@ -373,7 +427,7 @@ test_initial_structure (gconstpointer test_data)
   gboolean res;
   GError *error;
   GFileInputStream *ins;
-  int i;
+  guint i;
   GFileInfo *info;
   guint32 size;
   guchar *buffer;
@@ -413,6 +467,7 @@ test_initial_structure (gconstpointer test_data)
       test_attributes (item, info);
 
       g_object_unref (child);
+      g_object_unref (info);
     }
 
   /*  read and test the pattern file  */
@@ -429,6 +484,7 @@ test_initial_structure (gconstpointer test_data)
   g_assert (info != NULL);
   size = g_file_info_get_size (info);
   g_assert_cmpint (size, ==, PATTERN_FILE_SIZE);
+  g_object_unref (info);
 
   error = NULL;
   ins = g_file_read (child, NULL, &error);
@@ -446,8 +502,8 @@ test_initial_structure (gconstpointer test_data)
                             PATTERN_FILE_SIZE, NULL, &error);
       g_assert_no_error (error);
       total_read += read;
-      log ("      read %d bytes, total = %d of %d.\n", read, total_read,
-          PATTERN_FILE_SIZE);
+      log ("      read %"G_GSSIZE_FORMAT" bytes, total = %"G_GSSIZE_FORMAT" of %d.\n",
+          read, total_read, PATTERN_FILE_SIZE);
     }
   g_assert_cmpint (total_read, ==, PATTERN_FILE_SIZE);
 
@@ -474,7 +530,7 @@ traverse_recurse_dirs (GFile * parent, GFile * root)
   GFileInfo *info;
   GFile *descend;
   char *relative_path;
-  int i;
+  guint i;
   gboolean found;
 
   g_assert (root != NULL);
@@ -487,11 +543,13 @@ traverse_recurse_dirs (GFile * parent, GFile * root)
   g_assert (enumerator != NULL);
   g_assert_no_error (error);
 
+  g_assert (g_file_enumerator_get_container (enumerator) == parent);
+
   error = NULL;
   info = g_file_enumerator_next_file (enumerator, NULL, &error);
   while ((info) && (!error))
     {
-      descend = g_file_get_child (parent, g_file_info_get_name (info));
+      descend = g_file_enumerator_get_child (enumerator, info);
       g_assert (descend != NULL);
       relative_path = g_file_get_relative_path (root, descend);
       g_assert (relative_path != NULL);
@@ -518,6 +576,9 @@ traverse_recurse_dirs (GFile * parent, GFile * root)
 
       g_object_unref (descend);
       error = NULL;
+      g_object_unref (info);
+      g_free (relative_path);
+
       info = g_file_enumerator_next_file (enumerator, NULL, &error);
     }
   g_assert_no_error (error);
@@ -526,6 +587,9 @@ traverse_recurse_dirs (GFile * parent, GFile * root)
   res = g_file_enumerator_close (enumerator, NULL, &error);
   g_assert_cmpint (res, ==, TRUE);
   g_assert_no_error (error);
+  g_assert (g_file_enumerator_is_closed (enumerator));
+
+  g_object_unref (enumerator);
 }
 
 static void
@@ -559,7 +623,7 @@ test_enumerate (gconstpointer test_data)
   GError *error;
   GFileEnumerator *enumerator;
   GFileInfo *info;
-  int i;
+  guint i;
   struct StructureItem item;
 
 
@@ -623,6 +687,8 @@ test_enumerate (gconstpointer test_data)
              res = g_file_enumerator_close (enumerator, NULL, &error);
              g_assert_cmpint (res, ==, TRUE);
              g_assert_no_error (error);
+
+              g_object_unref (enumerator);
            }
          g_object_unref (child);
        }
@@ -676,10 +742,7 @@ do_copy_move (GFile * root, struct StructureItem item, const char *target_dir,
           (extra_flags == TEST_TARGET_IS_FILE))
     {
       g_assert_cmpint (res, ==, FALSE);
-      if (item.file_type == G_FILE_TYPE_DIRECTORY)
-       g_assert_error (error, G_IO_ERROR, G_IO_ERROR_WOULD_RECURSE);
-      else
-       g_assert_error (error, G_IO_ERROR, G_IO_ERROR_NOT_DIRECTORY);
+      g_assert_error (error, G_IO_ERROR, G_IO_ERROR_NOT_DIRECTORY);
     }
   /*  source file is directory  */
   else if ((item.extra_flags & TEST_COPY_ERROR_RECURSE) ==
@@ -699,8 +762,17 @@ do_copy_move (GFile * root, struct StructureItem item, const char *target_dir,
   else if (((item.extra_flags & TEST_NO_ACCESS) == TEST_NO_ACCESS) ||
           (extra_flags == TEST_NO_ACCESS))
     {
-      g_assert_cmpint (res, ==, FALSE);
-      g_assert_error (error, G_IO_ERROR, G_IO_ERROR_PERMISSION_DENIED);
+      /* This works for root, see bug #552912 */
+      if (test_suite && getuid () == 0)
+       {
+         g_assert_cmpint (res, ==, TRUE);
+         g_assert_no_error (error);
+       }
+      else
+       {
+         g_assert_cmpint (res, ==, FALSE);
+         g_assert_error (error, G_IO_ERROR, G_IO_ERROR_PERMISSION_DENIED);
+       }
     }
   /*  no error should be found, all exceptions defined above  */
   else
@@ -723,7 +795,7 @@ test_copy_move (gconstpointer test_data)
 {
   GFile *root;
   gboolean res;
-  int i;
+  guint i;
   struct StructureItem item;
 
   log ("\n");
@@ -787,7 +859,7 @@ test_create (gconstpointer test_data)
   GFile *root, *child;
   gboolean res;
   GError *error;
-  int i;
+  guint i;
   struct StructureItem item;
   GFileOutputStream *os;
 
@@ -860,6 +932,7 @@ test_create (gconstpointer test_data)
                     error->code, error->message);
              g_assert_cmpint (res, ==, TRUE);
              g_assert_no_error (error);
+              g_object_unref (os);
            }
          g_object_unref (child);
        }
@@ -873,7 +946,7 @@ test_open (gconstpointer test_data)
   GFile *root, *child;
   gboolean res;
   GError *error;
-  int i;
+  guint i;
   struct StructureItem item;
   GFileInputStream *input_stream;
 
@@ -930,6 +1003,7 @@ test_open (gconstpointer test_data)
                                      &error);
              g_assert_cmpint (res, ==, TRUE);
              g_assert_no_error (error);
+              g_object_unref (input_stream);
            }
          g_object_unref (child);
        }
@@ -944,8 +1018,9 @@ test_delete (gconstpointer test_data)
   GFile *child;
   gboolean res;
   GError *error;
-  int i;
+  guint i;
   struct StructureItem item;
+  gchar *path;
 
   g_assert (test_data != NULL);
   log ("\n");
@@ -969,8 +1044,10 @@ test_delete (gconstpointer test_data)
          g_assert (child != NULL);
          /*  we don't care about result here  */
 
-         log ("  Deleting %s, path = %s\n", item.filename,
-              g_file_get_path (child));
+          path = g_file_get_path (child);
+         log ("  Deleting %s, path = %s\n", item.filename, path);
+          g_free (path);
+
          error = NULL;
          if ((item.extra_flags & TEST_DELETE_NORMAL) == TEST_DELETE_NORMAL)
            res = g_file_delete (child, NULL, &error);
@@ -1006,6 +1083,94 @@ test_delete (gconstpointer test_data)
   g_object_unref (root);
 }
 
+static void
+test_make_directory_with_parents (gconstpointer test_data)
+{
+  GFile *root, *child, *grandchild, *greatgrandchild;
+  gboolean res;
+  GError *error = NULL;
+
+  g_assert (test_data != NULL);
+
+  root = g_file_new_for_commandline_arg ((char *) test_data);
+  g_assert (root != NULL);
+  res = g_file_query_exists (root, NULL);
+  g_assert_cmpint (res, ==, TRUE);
+
+  child = g_file_get_child (root, "a");
+  grandchild = g_file_get_child (child, "b");
+  greatgrandchild = g_file_get_child (grandchild, "c");
+
+  /* Check that we can successfully make directory hierarchies of
+   * depth 1, 2, or 3
+   */
+  res = g_file_make_directory_with_parents (child, NULL, &error);
+  g_assert_cmpint (res, ==, TRUE);
+  g_assert_no_error (error);
+  res = g_file_query_exists (child, NULL);
+  g_assert_cmpint (res, ==, TRUE);
+
+  g_file_delete (child, NULL, NULL);
+
+  res = g_file_make_directory_with_parents (grandchild, NULL, &error);
+  g_assert_cmpint (res, ==, TRUE);
+  g_assert_no_error (error);
+  res = g_file_query_exists (grandchild, NULL);
+  g_assert_cmpint (res, ==, TRUE);
+
+  g_file_delete (grandchild, NULL, NULL);
+  g_file_delete (child, NULL, NULL);
+
+  res = g_file_make_directory_with_parents (greatgrandchild, NULL, &error);
+  g_assert_cmpint (res, ==, TRUE);
+  g_assert_no_error (error);
+  res = g_file_query_exists (greatgrandchild, NULL);
+  g_assert_cmpint (res, ==, TRUE);
+
+  g_file_delete (greatgrandchild, NULL, NULL);
+  g_file_delete (grandchild, NULL, NULL);
+  g_file_delete (child, NULL, NULL);
+
+  /* Now test failure by trying to create a directory hierarchy
+   * where a ancestor exists but is read-only
+   */
+
+  /* No obvious way to do this on Windows */
+  if (!posix_compat)
+    goto out;
+
+#ifndef G_PLATFORM_WIN32
+  if (getuid() == 0) /* permissions are ignored for root */
+    goto out;
+#endif
+
+  g_file_make_directory (child, NULL, NULL);
+  g_assert_cmpint (res, ==, TRUE);
+
+  res = g_file_set_attribute_uint32 (child,
+                                     G_FILE_ATTRIBUTE_UNIX_MODE,
+                                     S_IRUSR + S_IXUSR, /* -r-x------ */
+                                     G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
+                                     NULL, NULL);
+  g_assert_cmpint (res, ==, TRUE);
+
+  res = g_file_make_directory_with_parents (grandchild, NULL, &error);
+  g_assert_cmpint (res, ==, FALSE);
+  g_assert_error (error, G_IO_ERROR, G_IO_ERROR_PERMISSION_DENIED);
+  g_clear_error (&error);
+
+  res = g_file_make_directory_with_parents (greatgrandchild, NULL, &error);
+  g_assert_cmpint (res, ==, FALSE);
+  g_assert_error (error, G_IO_ERROR, G_IO_ERROR_PERMISSION_DENIED);
+  g_clear_error (&error);
+
+out:
+  g_object_unref (greatgrandchild);
+  g_object_unref (grandchild);
+  g_object_unref (child);
+  g_object_unref (root);
+}
+
 
 static void
 cleanup_dir_recurse (GFile *parent, GFile *root)
@@ -1019,11 +1184,10 @@ cleanup_dir_recurse (GFile *parent, GFile *root)
 
   g_assert (root != NULL);
 
-  error = NULL;
   enumerator =
     g_file_enumerate_children (parent, "*",
                               G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, NULL,
-                              &error);
+                              NULL);
   if (! enumerator)
          return;
 
@@ -1031,10 +1195,11 @@ cleanup_dir_recurse (GFile *parent, GFile *root)
   info = g_file_enumerator_next_file (enumerator, NULL, &error);
   while ((info) && (!error))
     {
-      descend = g_file_get_child (parent, g_file_info_get_name (info));
+      descend = g_file_enumerator_get_child (enumerator, info);
       g_assert (descend != NULL);
       relative_path = g_file_get_relative_path (root, descend);
       g_assert (relative_path != NULL);
+      g_free (relative_path);
 
       log ("    deleting '%s'\n", g_file_info_get_display_name (info));
 
@@ -1047,6 +1212,8 @@ cleanup_dir_recurse (GFile *parent, GFile *root)
 
       g_object_unref (descend);
       error = NULL;
+      g_object_unref (info);
+
       info = g_file_enumerator_next_file (enumerator, NULL, &error);
     }
   g_assert_no_error (error);
@@ -1055,6 +1222,8 @@ cleanup_dir_recurse (GFile *parent, GFile *root)
   res = g_file_enumerator_close (enumerator, NULL, &error);
   g_assert_cmpint (res, ==, TRUE);
   g_assert_no_error (error);
+
+  g_object_unref (enumerator);
 }
 
 static void
@@ -1080,7 +1249,7 @@ int
 main (int argc, char *argv[])
 {
   static gboolean only_create_struct;
-  static char *target_path;
+  const char *target_path;
   GError *error;
   GOptionContext *context;
 
@@ -1095,6 +1264,7 @@ main (int argc, char *argv[])
     {NULL}
   };
 
+  test_suite = FALSE;
   verbose = FALSE;
   write_test = FALSE;
   only_create_struct = FALSE;
@@ -1102,12 +1272,12 @@ main (int argc, char *argv[])
   posix_compat = FALSE;
 
   /*  strip all gtester-specific args  */
-  g_type_init ();
   g_test_init (&argc, &argv, NULL);
 
   /*  no extra parameters specified, assume we're executed from glib test suite  */ 
   if (argc < 2)
     {
+         test_suite = TRUE;
          verbose = TRUE;
          write_test = TRUE;
          only_create_struct = FALSE;
@@ -1136,10 +1306,11 @@ main (int argc, char *argv[])
   if (! target_path) 
     {
       g_print ("error: target path was not specified\n");
-      g_print (g_option_context_get_help (context, TRUE, NULL));
+      g_print ("%s", g_option_context_get_help (context, TRUE, NULL));
       return g_test_run ();
     }
 
+  g_option_context_free (context);
   
   /*  Write test - clean target directory first  */
   /*    this can be also considered as a test - enumerate + delete  */ 
@@ -1186,6 +1357,11 @@ main (int argc, char *argv[])
     g_test_add_data_func ("/live-g-file/test_delete", target_path,
                          test_delete);
 
+  /*  Write test - make_directory_with_parents */
+  if (write_test && (!only_create_struct))
+    g_test_add_data_func ("/live-g-file/test_make_directory_with_parents", target_path,
+                         test_make_directory_with_parents);
+
   if (write_test || only_create_struct)
     g_test_add_data_func ("/live-g-file/final_clean", target_path,
                  prep_clean_structure);