tests: add testcase for {Only,Not}ShowIn
[platform/upstream/glib.git] / gio / tests / live-g-file.c
index a5ece7f..6edc99a 100644 (file)
  * if advised of the possibility of such damage.
  */
 
-#include <glib/gtestutils.h>
 #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>
 
 #define DEFAULT_TEST_DIR               "testdir_live-g-file"
 
@@ -52,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
@@ -87,9 +91,9 @@ static const struct StructureItem sample_struct[] = {
     {"private_file",           NULL,   G_FILE_TYPE_REGULAR,    G_FILE_CREATE_PRIVATE, 0, 0, TEST_COPY | TEST_OPEN | TEST_OVERWRITE | TEST_APPEND},
     {"normal_file2",           NULL,   G_FILE_TYPE_REGULAR,    G_FILE_CREATE_NONE, 0, 0, TEST_COPY | TEST_OVERWRITE | TEST_REPLACE},
     {"readonly_file",          NULL,   G_FILE_TYPE_REGULAR,    G_FILE_CREATE_NONE, S_IRUSR + S_IRGRP + S_IROTH, 0, TEST_DELETE_NORMAL | TEST_OPEN},
-    {"UTF_p\xc5\x99\xc3\xadli\xc5\xa1 \xc5\xbelu\xc5\xa5ou\xc4\x8dk\xc3\xbd k\xc5\xaf\xc5\x88",
+    {"UTF_pr\xcc\x8ci\xcc\x81lis\xcc\x8c z",
                                                NULL,   G_FILE_TYPE_REGULAR,    G_FILE_CREATE_NONE, 0, 0, TEST_COPY | TEST_CREATE | TEST_OPEN | TEST_OVERWRITE},
-    {"dir_p\xc5\x99\xc3\xadli\xc5\xa1 \xc5\xbelu\xc5\xa5ou\xc4\x8dk\xc3\xbd k\xc5\xaf\xc5\x88",
+    {"dir_pr\xcc\x8ci\xcc\x81lis\xcc\x8c z",
                                                NULL,   G_FILE_TYPE_DIRECTORY,  G_FILE_CREATE_NONE, 0, 0, TEST_DELETE_NORMAL | TEST_CREATE},
     {"pattern_file",           NULL,   G_FILE_TYPE_REGULAR,    G_FILE_CREATE_NONE, 0, TEST_HANDLE_SPECIAL, TEST_COPY | TEST_OPEN | TEST_APPEND},
     {TEST_NAME_NOT_EXISTS,     NULL,   G_FILE_TYPE_REGULAR,    G_FILE_CREATE_NONE, 0, TEST_HANDLE_SPECIAL, TEST_DELETE_NORMAL | TEST_NOT_EXISTS | TEST_COPY | TEST_OPEN},
@@ -99,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;
 
@@ -121,10 +142,10 @@ create_empty_file (GFile * parent, const char *filename,
 
   error = NULL;
   outs = g_file_replace (child, NULL, FALSE, create_flags, NULL, &error);
-  g_assert (error == NULL);
+  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;
 }
@@ -141,7 +162,7 @@ create_empty_dir (GFile * parent, const char *filename)
   error = NULL;
   res = g_file_make_directory (child, NULL, &error);
   g_assert_cmpint (res, ==, TRUE);
-  g_assert (error == NULL);
+  g_assert_no_error (error);
   return child;
 }
 
@@ -157,7 +178,7 @@ create_symlink (GFile * parent, const char *filename, const char *points_to)
   error = NULL;
   res = g_file_make_symbolic_link (child, points_to, NULL, &error);
   g_assert_cmpint (res, ==, TRUE);
-  g_assert (error == NULL);
+  g_assert_no_error (error);
   return child;
 }
 
@@ -170,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);
@@ -209,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;
        }
@@ -223,7 +248,25 @@ test_create_structure (gconstpointer test_data)
                                         G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
                                         NULL, &error);
          g_assert_cmpint (res, ==, TRUE);
-         g_assert (error == NULL);
+         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);
@@ -237,7 +280,7 @@ test_create_structure (gconstpointer test_data)
   error = NULL;
   outs =
     g_file_replace (child, NULL, FALSE, G_FILE_CREATE_NONE, NULL, &error);
-  g_assert (error == NULL);
+  g_assert_no_error (error);
 
   g_assert (outs != NULL);
   outds = g_data_output_stream_new (G_OUTPUT_STREAM (outs));
@@ -246,11 +289,11 @@ test_create_structure (gconstpointer test_data)
     {
       error = NULL;
       res = g_data_output_stream_put_byte (outds, i % 256, NULL, &error);
-      g_assert (error == NULL);
+      g_assert_no_error (error);
     }
   error = NULL;
   res = g_output_stream_close (G_OUTPUT_STREAM (outs), NULL, &error);
-  g_assert (error == NULL);
+  g_assert_no_error (error);
   g_object_unref (outds);
   g_object_unref (outs);
   g_object_unref (child);
@@ -286,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  */
@@ -364,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
@@ -374,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;
@@ -408,12 +461,13 @@ test_initial_structure (gconstpointer test_data)
       info =
        g_file_query_info (child, "*", G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
                           NULL, &error);
-      g_assert (error == NULL);
+      g_assert_no_error (error);
       g_assert (info != NULL);
 
       test_attributes (item, info);
 
       g_object_unref (child);
+      g_object_unref (info);
     }
 
   /*  read and test the pattern file  */
@@ -426,15 +480,16 @@ test_initial_structure (gconstpointer test_data)
   info =
     g_file_query_info (child, "*", G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, NULL,
                       &error);
-  g_assert (error == NULL);
+  g_assert_no_error (error);
   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);
   g_assert (ins != NULL);
-  g_assert (error == NULL);
+  g_assert_no_error (error);
 
   buffer = g_malloc (PATTERN_FILE_SIZE);
   total_read = 0;
@@ -445,16 +500,16 @@ test_initial_structure (gconstpointer test_data)
       read =
        g_input_stream_read (G_INPUT_STREAM (ins), buffer + total_read,
                             PATTERN_FILE_SIZE, NULL, &error);
-      g_assert (error == NULL);
+      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);
 
   error = NULL;
   res = g_input_stream_close (G_INPUT_STREAM (ins), NULL, &error);
-  g_assert (error == NULL);
+  g_assert_no_error (error);
   g_assert_cmpint (res, ==, TRUE);
 
   for (i = 0; i < PATTERN_FILE_SIZE; i++)
@@ -475,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);
@@ -486,13 +541,15 @@ traverse_recurse_dirs (GFile * parent, GFile * root)
                               G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, NULL,
                               &error);
   g_assert (enumerator != NULL);
-  g_assert (error == 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);
@@ -519,14 +576,20 @@ 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 (error == NULL);
+  g_assert_no_error (error);
 
   error = NULL;
   res = g_file_enumerator_close (enumerator, NULL, &error);
   g_assert_cmpint (res, ==, TRUE);
-  g_assert (error == NULL);
+  g_assert_no_error (error);
+  g_assert (g_file_enumerator_is_closed (enumerator));
+
+  g_object_unref (enumerator);
 }
 
 static void
@@ -560,7 +623,7 @@ test_enumerate (gconstpointer test_data)
   GError *error;
   GFileEnumerator *enumerator;
   GFileInfo *info;
-  int i;
+  guint i;
   struct StructureItem item;
 
 
@@ -597,12 +660,12 @@ test_enumerate (gconstpointer test_data)
          if ((item.extra_flags & TEST_NOT_EXISTS) == TEST_NOT_EXISTS)
            {
              g_assert (enumerator == NULL);
-             g_assert_cmpint (error->code, ==, G_IO_ERROR_NOT_FOUND);
+             g_assert_error (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND);
            }
          if ((item.extra_flags & TEST_ENUMERATE_FILE) == TEST_ENUMERATE_FILE)
            {
              g_assert (enumerator == NULL);
-             g_assert_cmpint (error->code, ==, G_IO_ERROR_NOT_DIRECTORY);
+             g_assert_error (error, G_IO_ERROR, G_IO_ERROR_NOT_DIRECTORY);
            }
          if ((item.extra_flags & TEST_NO_ACCESS) == TEST_NO_ACCESS)
            {
@@ -611,7 +674,7 @@ test_enumerate (gconstpointer test_data)
              error = NULL;
              info = g_file_enumerator_next_file (enumerator, NULL, &error);
              g_assert (info == NULL);
-             g_assert (error == NULL);
+             g_assert_no_error (error);
              /*  no items should be found, no error should be logged  */
            }
 
@@ -623,7 +686,9 @@ test_enumerate (gconstpointer test_data)
              error = NULL;
              res = g_file_enumerator_close (enumerator, NULL, &error);
              g_assert_cmpint (res, ==, TRUE);
-             g_assert (error == NULL);
+             g_assert_no_error (error);
+
+              g_object_unref (enumerator);
            }
          g_object_unref (child);
        }
@@ -670,44 +735,50 @@ do_copy_move (GFile * root, struct StructureItem item, const char *target_dir,
       (extra_flags == TEST_ALREADY_EXISTS))
     {
       g_assert_cmpint (res, ==, FALSE);
-      g_assert_cmpint (error->code, ==, G_IO_ERROR_EXISTS);
+      g_assert_error (error, G_IO_ERROR, G_IO_ERROR_EXISTS);
     }
   /*  target file is a file, overwrite is not set  */
   else if (((item.extra_flags & TEST_NOT_EXISTS) != TEST_NOT_EXISTS) &&
           (extra_flags == TEST_TARGET_IS_FILE))
     {
       g_assert_cmpint (res, ==, FALSE);
-      if (item.file_type == G_FILE_TYPE_DIRECTORY)
-       g_assert_cmpint (error->code, ==, G_IO_ERROR_WOULD_RECURSE);
-      else
-       g_assert_cmpint (error->code, ==, 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) ==
           TEST_COPY_ERROR_RECURSE)
     {
       g_assert_cmpint (res, ==, FALSE);
-      g_assert_cmpint (error->code, ==, G_IO_ERROR_WOULD_RECURSE);
+      g_assert_error (error, G_IO_ERROR, G_IO_ERROR_WOULD_RECURSE);
     }
   /*  source or target path doesn't exist  */
   else if (((item.extra_flags & TEST_NOT_EXISTS) == TEST_NOT_EXISTS) ||
           (extra_flags == TEST_NOT_EXISTS))
     {
       g_assert_cmpint (res, ==, FALSE);
-      g_assert_cmpint (error->code, ==, G_IO_ERROR_NOT_FOUND);
+      g_assert_error (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND);
     }
   /*  source or target path permission denied  */
   else if (((item.extra_flags & TEST_NO_ACCESS) == TEST_NO_ACCESS) ||
           (extra_flags == TEST_NO_ACCESS))
     {
-      g_assert_cmpint (res, ==, FALSE);
-      g_assert_cmpint (error->code, ==, 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
     {
       g_assert_cmpint (res, ==, TRUE);
-      g_assert (error == NULL);
+      g_assert_no_error (error);
     }
 
   if (error)
@@ -724,7 +795,7 @@ test_copy_move (gconstpointer test_data)
 {
   GFile *root;
   gboolean res;
-  int i;
+  guint i;
   struct StructureItem item;
 
   log ("\n");
@@ -788,7 +859,7 @@ test_create (gconstpointer test_data)
   GFile *root, *child;
   gboolean res;
   GError *error;
-  int i;
+  guint i;
   struct StructureItem item;
   GFileOutputStream *os;
 
@@ -832,22 +903,20 @@ test_create (gconstpointer test_data)
              ((item.extra_flags & TEST_CREATE) == TEST_CREATE))
            {
              g_assert (os == NULL);
-             g_assert (error != NULL);
-             g_assert_cmpint (error->code, ==, G_IO_ERROR_EXISTS);
+             g_assert_error (error, G_IO_ERROR, G_IO_ERROR_EXISTS);
            }
          else if (item.file_type == G_FILE_TYPE_DIRECTORY)
            {
              g_assert (os == NULL);
-             g_assert (error != NULL);
              if ((item.extra_flags & TEST_CREATE) == TEST_CREATE)
-               g_assert_cmpint (error->code, ==, G_IO_ERROR_EXISTS);
+               g_assert_error (error, G_IO_ERROR, G_IO_ERROR_EXISTS);
              else
-               g_assert_cmpint (error->code, ==, G_IO_ERROR_IS_DIRECTORY);
+               g_assert_error (error, G_IO_ERROR, G_IO_ERROR_IS_DIRECTORY);
            }
          else
            {
              g_assert (os != NULL);
-             g_assert (error == NULL);
+             g_assert_no_error (error);
            }
 
          if (error)
@@ -862,7 +931,8 @@ test_create (gconstpointer test_data)
                log ("         g_output_stream_close: error %d = %s\n",
                     error->code, error->message);
              g_assert_cmpint (res, ==, TRUE);
-             g_assert (error == NULL);
+             g_assert_no_error (error);
+              g_object_unref (os);
            }
          g_object_unref (child);
        }
@@ -876,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;
 
@@ -909,17 +979,17 @@ test_open (gconstpointer test_data)
               TEST_INVALID_SYMLINK))
            {
              g_assert (input_stream == NULL);
-             g_assert_cmpint (error->code, ==, G_IO_ERROR_NOT_FOUND);
+             g_assert_error (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND);
            }
          else if (item.file_type == G_FILE_TYPE_DIRECTORY)
            {
              g_assert (input_stream == NULL);
-             g_assert_cmpint (error->code, ==, G_IO_ERROR_IS_DIRECTORY);
+             g_assert_error (error, G_IO_ERROR, G_IO_ERROR_IS_DIRECTORY);
            }
          else
            {
              g_assert (input_stream != NULL);
-             g_assert (error == NULL);
+             g_assert_no_error (error);
            }
 
          if (error)
@@ -932,7 +1002,8 @@ test_open (gconstpointer test_data)
                g_input_stream_close (G_INPUT_STREAM (input_stream), NULL,
                                      &error);
              g_assert_cmpint (res, ==, TRUE);
-             g_assert (error == NULL);
+             g_assert_no_error (error);
+              g_object_unref (input_stream);
            }
          g_object_unref (child);
        }
@@ -947,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");
@@ -972,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);
@@ -984,20 +1058,17 @@ test_delete (gconstpointer test_data)
              TEST_DELETE_NON_EMPTY)
            {
              g_assert_cmpint (res, ==, FALSE);
-             g_assert (error != NULL);
-             g_assert_cmpint (error->code, ==, G_IO_ERROR_NOT_EMPTY);
+             g_assert_error (error, G_IO_ERROR, G_IO_ERROR_NOT_EMPTY);
            }
          if ((item.extra_flags & TEST_DELETE_FAILURE) == TEST_DELETE_FAILURE)
            {
              g_assert_cmpint (res, ==, FALSE);
-             g_assert (error != NULL);
-             g_assert_cmpint (error->code, !=, 0);
+             g_assert_error (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND);
            }
          if ((item.extra_flags & TEST_NOT_EXISTS) == TEST_NOT_EXISTS)
            {
              g_assert_cmpint (res, ==, FALSE);
-             g_assert (error != NULL);
-             g_assert_cmpint (error->code, ==, G_IO_ERROR_NOT_FOUND);
+             g_assert_error (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND);
            }
 
          if (error)
@@ -1012,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)
@@ -1025,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;
 
@@ -1037,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));
 
@@ -1053,14 +1212,18 @@ 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 (error == NULL);
+  g_assert_no_error (error);
 
   error = NULL;
   res = g_file_enumerator_close (enumerator, NULL, &error);
   g_assert_cmpint (res, ==, TRUE);
-  g_assert (error == NULL);
+  g_assert_no_error (error);
+
+  g_object_unref (enumerator);
 }
 
 static void
@@ -1077,6 +1240,8 @@ prep_clean_structure (gconstpointer test_data)
   
   cleanup_dir_recurse (root, root);
 
+  g_file_delete (root, NULL, NULL);
+  
   g_object_unref (root);
 }
 
@@ -1084,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;
 
@@ -1099,6 +1264,7 @@ main (int argc, char *argv[])
     {NULL}
   };
 
+  test_suite = FALSE;
   verbose = FALSE;
   write_test = FALSE;
   only_create_struct = FALSE;
@@ -1106,13 +1272,12 @@ main (int argc, char *argv[])
   posix_compat = FALSE;
 
   /*  strip all gtester-specific args  */
-  g_type_init ();
-  g_thread_init (0);
   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;
@@ -1141,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  */ 
@@ -1191,5 +1357,15 @@ 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);
+
   return g_test_run ();
+
 }