2.17.0
[platform/upstream/glib.git] / gio / tests / live-g-file.c
1 /* GLib testing framework examples and tests
2  * Copyright (C) 2008 Red Hat, Inc.
3  * Authors: Tomas Bzatek <tbzatek@redhat.com>
4  *
5  * This work is provided "as is"; redistribution and modification
6  * in whole or in part, in any medium, physical or electronic is
7  * permitted without restriction.
8  *
9  * This work is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12  *
13  * In no event shall the authors or contributors be liable for any
14  * direct, indirect, incidental, special, exemplary, or consequential
15  * damages (including, but not limited to, procurement of substitute
16  * goods or services; loss of use, data, or profits; or business
17  * interruption) however caused and on any theory of liability, whether
18  * in contract, strict liability, or tort (including negligence or
19  * otherwise) arising in any way out of the use of this software, even
20  * if advised of the possibility of such damage.
21  */
22
23 #include <glib/gtestutils.h>
24 #include <glib/glib.h>
25 #include <gio/gio.h>
26 #include <stdlib.h>
27 #include <string.h>
28
29
30 #define DEFAULT_TEST_DIR                "testdir_live-g-file"
31
32 #define PATTERN_FILE_SIZE       0x10000
33 #define TEST_HANDLE_SPECIAL     TRUE
34
35 enum StructureExtraFlags
36 {
37   TEST_DELETE_NORMAL = 1 << 0,
38   TEST_DELETE_TRASH = 1 << 1,
39   TEST_DELETE_NON_EMPTY = 1 << 2,
40   TEST_DELETE_FAILURE = 1 << 3,
41   TEST_NOT_EXISTS = 1 << 4,
42   TEST_ENUMERATE_FILE = 1 << 5,
43   TEST_NO_ACCESS = 1 << 6,
44   TEST_COPY = 1 << 7,
45   TEST_MOVE = 1 << 8,
46   TEST_COPY_ERROR_RECURSE = 1 << 9,
47   TEST_ALREADY_EXISTS = 1 << 10,
48   TEST_TARGET_IS_FILE = 1 << 11,
49   TEST_CREATE = 1 << 12,
50   TEST_REPLACE = 1 << 13,
51   TEST_APPEND = 1 << 14,
52   TEST_OPEN = 1 << 15,
53   TEST_OVERWRITE = 1 << 16,
54   TEST_INVALID_SYMLINK = 1 << 17,
55 };
56
57 struct StructureItem
58 {
59   const char *filename;
60   const char *link_to;
61   GFileType file_type;
62   GFileCreateFlags create_flags;
63   guint32 mode;
64   gboolean handle_special;
65   enum StructureExtraFlags extra_flags;
66 };
67
68 #define TEST_DIR_NO_ACCESS              "dir_no-access"
69 #define TEST_DIR_NO_WRITE               "dir_no-write"
70 #define TEST_DIR_TARGET                 "dir-target"
71 #define TEST_NAME_NOT_EXISTS    "not_exists"
72 #define TEST_TARGET_FILE                "target-file"
73
74
75 static const struct StructureItem sample_struct[] = {
76 /*       filename                               link    file_type                               create_flags            mode | handle_special | extra_flags              */
77     {"dir1",                            NULL,   G_FILE_TYPE_DIRECTORY,  G_FILE_CREATE_NONE, 0, 0, TEST_DELETE_NORMAL | TEST_DELETE_NON_EMPTY | TEST_REPLACE | TEST_OPEN},
78     {"dir1/subdir",                     NULL,   G_FILE_TYPE_DIRECTORY,  G_FILE_CREATE_NONE, 0, 0, TEST_COPY     | TEST_COPY_ERROR_RECURSE | TEST_APPEND},
79     {"dir2",                            NULL,   G_FILE_TYPE_DIRECTORY,  G_FILE_CREATE_NONE, 0, 0, TEST_DELETE_NORMAL | TEST_MOVE | TEST_CREATE},
80     {TEST_DIR_TARGET,           NULL,   G_FILE_TYPE_DIRECTORY,  G_FILE_CREATE_NONE, 0, 0, TEST_COPY | TEST_COPY_ERROR_RECURSE},
81     {TEST_DIR_NO_ACCESS,        NULL,   G_FILE_TYPE_DIRECTORY,  G_FILE_CREATE_PRIVATE, S_IRUSR + S_IWUSR + S_IRGRP + S_IWGRP + S_IROTH + S_IWOTH, 0, TEST_NO_ACCESS | TEST_OPEN},
82     {TEST_DIR_NO_WRITE,         NULL,   G_FILE_TYPE_DIRECTORY,  G_FILE_CREATE_PRIVATE, S_IRUSR + S_IXUSR + S_IRGRP + S_IXGRP + S_IROTH + S_IXOTH, 0, 0},
83     {TEST_TARGET_FILE,          NULL,   G_FILE_TYPE_REGULAR,    G_FILE_CREATE_NONE, 0, 0, TEST_COPY | TEST_OPEN},
84         {"normal_file",                 NULL,   G_FILE_TYPE_REGULAR,    G_FILE_CREATE_NONE, 0, 0, TEST_ENUMERATE_FILE | TEST_CREATE | TEST_OVERWRITE},
85         {"normal_file-symlink", "normal_file",  G_FILE_TYPE_SYMBOLIC_LINK, G_FILE_CREATE_NONE, 0, 0, TEST_ENUMERATE_FILE | TEST_COPY | TEST_OPEN},
86     {"executable_file",         NULL,   G_FILE_TYPE_REGULAR,    G_FILE_CREATE_NONE, S_IRWXU + S_IRWXG + S_IRWXO, 0, TEST_DELETE_TRASH | TEST_COPY | TEST_OPEN | TEST_OVERWRITE | TEST_REPLACE},
87     {"private_file",            NULL,   G_FILE_TYPE_REGULAR,    G_FILE_CREATE_PRIVATE, 0, 0, TEST_COPY | TEST_OPEN | TEST_OVERWRITE | TEST_APPEND},
88     {"normal_file2",            NULL,   G_FILE_TYPE_REGULAR,    G_FILE_CREATE_NONE, 0, 0, TEST_COPY | TEST_OVERWRITE | TEST_REPLACE},
89     {"readonly_file",           NULL,   G_FILE_TYPE_REGULAR,    G_FILE_CREATE_NONE, S_IRUSR + S_IRGRP + S_IROTH, 0, TEST_DELETE_NORMAL | TEST_OPEN},
90     {"UTF_p\xc5\x99\xc3\xadli\xc5\xa1 \xc5\xbelu\xc5\xa5ou\xc4\x8dk\xc3\xbd k\xc5\xaf\xc5\x88",
91                                                 NULL,   G_FILE_TYPE_REGULAR,    G_FILE_CREATE_NONE, 0, 0, TEST_COPY | TEST_CREATE | TEST_OPEN | TEST_OVERWRITE},
92     {"dir_p\xc5\x99\xc3\xadli\xc5\xa1 \xc5\xbelu\xc5\xa5ou\xc4\x8dk\xc3\xbd k\xc5\xaf\xc5\x88",
93                                                 NULL,   G_FILE_TYPE_DIRECTORY,  G_FILE_CREATE_NONE, 0, 0, TEST_DELETE_NORMAL | TEST_CREATE},
94     {"pattern_file",            NULL,   G_FILE_TYPE_REGULAR,    G_FILE_CREATE_NONE, 0, TEST_HANDLE_SPECIAL, TEST_COPY | TEST_OPEN | TEST_APPEND},
95     {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},
96     {TEST_NAME_NOT_EXISTS,      NULL,   G_FILE_TYPE_REGULAR,    G_FILE_CREATE_NONE, 0, TEST_HANDLE_SPECIAL, TEST_DELETE_TRASH | TEST_NOT_EXISTS | TEST_MOVE},
97     {"not_exists2",                     NULL,   G_FILE_TYPE_REGULAR,    G_FILE_CREATE_NONE, 0, TEST_HANDLE_SPECIAL, TEST_NOT_EXISTS | TEST_CREATE},
98     {"not_exists3",                     NULL,   G_FILE_TYPE_REGULAR,    G_FILE_CREATE_NONE, 0, TEST_HANDLE_SPECIAL, TEST_NOT_EXISTS | TEST_REPLACE},
99     {"not_exists4",                     NULL,   G_FILE_TYPE_REGULAR,    G_FILE_CREATE_NONE, 0, TEST_HANDLE_SPECIAL, TEST_NOT_EXISTS | TEST_APPEND},
100     {"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},
101         {"lost_symlink",                "nowhere",      G_FILE_TYPE_SYMBOLIC_LINK, G_FILE_CREATE_NONE, 0, 0, TEST_COPY | TEST_DELETE_NORMAL | TEST_OPEN | TEST_INVALID_SYMLINK},
102   };
103
104 static gboolean write_test;
105 static gboolean verbose;
106 static gboolean posix_compat;
107
108 #define log(msg...) if (verbose)  g_print (msg)
109
110 static GFile *
111 create_empty_file (GFile * parent, const char *filename,
112                    GFileCreateFlags create_flags)
113 {
114   GFile *child;
115   gboolean res;
116   GError *error;
117   GFileOutputStream *outs;
118
119   child = g_file_get_child (parent, filename);
120   g_assert (child != NULL);
121
122   error = NULL;
123   outs = g_file_replace (child, NULL, FALSE, create_flags, NULL, &error);
124   g_assert (error == NULL);
125   g_assert (outs != NULL);
126   error = NULL;
127   res = g_output_stream_close (G_OUTPUT_STREAM (outs), NULL, &error);
128   g_object_unref (outs);
129   return child;
130 }
131
132 static GFile *
133 create_empty_dir (GFile * parent, const char *filename)
134 {
135   GFile *child;
136   gboolean res;
137   GError *error;
138
139   child = g_file_get_child (parent, filename);
140   g_assert (child != NULL);
141   error = NULL;
142   res = g_file_make_directory (child, NULL, &error);
143   g_assert_cmpint (res, ==, TRUE);
144   g_assert (error == NULL);
145   return child;
146 }
147
148 static GFile *
149 create_symlink (GFile * parent, const char *filename, const char *points_to)
150 {
151   GFile *child;
152   gboolean res;
153   GError *error;
154
155   child = g_file_get_child (parent, filename);
156   g_assert (child != NULL);
157   error = NULL;
158   res = g_file_make_symbolic_link (child, points_to, NULL, &error);
159   g_assert_cmpint (res, ==, TRUE);
160   g_assert (error == NULL);
161   return child;
162 }
163
164 static void
165 test_create_structure (gconstpointer test_data)
166 {
167   GFile *root;
168   GFile *child;
169   gboolean res;
170   GError *error;
171   GFileOutputStream *outs;
172   GDataOutputStream *outds;
173   int i;
174   struct StructureItem item;
175
176   g_assert (test_data != NULL);
177   log ("\n  Going to create testing structure in '%s'...\n",
178        (char *) test_data);
179
180   root = g_file_new_for_commandline_arg ((char *) test_data);
181   g_assert (root != NULL);
182
183   /*  create root directory  */
184   res = g_file_make_directory (root, NULL, NULL);
185   /*  don't care about errors here  */
186
187   /*  create any other items  */
188   for (i = 0; i < G_N_ELEMENTS (sample_struct); i++)
189     {
190       item = sample_struct[i];
191       if ((item.handle_special)
192           || ((!posix_compat)
193               && (item.file_type == G_FILE_TYPE_SYMBOLIC_LINK)))
194         continue;
195
196       child = NULL;
197       switch (item.file_type)
198         {
199         case G_FILE_TYPE_REGULAR:
200           log ("    Creating file '%s'...\n", item.filename);
201           child = create_empty_file (root, item.filename, item.create_flags);
202           break;
203         case G_FILE_TYPE_DIRECTORY:
204           log ("    Creating directory '%s'...\n", item.filename);
205           child = create_empty_dir (root, item.filename);
206           break;
207         case G_FILE_TYPE_SYMBOLIC_LINK:
208           log ("    Creating symlink '%s' --> '%s'...\n", item.filename,
209                item.link_to);
210           child = create_symlink (root, item.filename, item.link_to);
211           break;
212         default:
213           break;
214         }
215       g_assert (child != NULL);
216
217       if ((item.mode > 0) && (posix_compat))
218         {
219           error = NULL;
220           res =
221             g_file_set_attribute_uint32 (child, G_FILE_ATTRIBUTE_UNIX_MODE,
222                                          item.mode,
223                                          G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
224                                          NULL, &error);
225           g_assert_cmpint (res, ==, TRUE);
226           g_assert (error == NULL);
227         }
228
229       g_object_unref (child);
230     }
231
232   /*  create a pattern file  */
233   log ("    Creating pattern file...");
234   child = g_file_get_child (root, "pattern_file");
235   g_assert (child != NULL);
236
237   error = NULL;
238   outs =
239     g_file_replace (child, NULL, FALSE, G_FILE_CREATE_NONE, NULL, &error);
240   g_assert (error == NULL);
241
242   g_assert (outs != NULL);
243   outds = g_data_output_stream_new (G_OUTPUT_STREAM (outs));
244   g_assert (outds != NULL);
245   for (i = 0; i < PATTERN_FILE_SIZE; i++)
246     {
247       error = NULL;
248       res = g_data_output_stream_put_byte (outds, i % 256, NULL, &error);
249       g_assert (error == NULL);
250     }
251   error = NULL;
252   res = g_output_stream_close (G_OUTPUT_STREAM (outs), NULL, &error);
253   g_assert (error == NULL);
254   g_object_unref (outds);
255   g_object_unref (outs);
256   g_object_unref (child);
257   log (" done.\n");
258
259   g_object_unref (root);
260 }
261
262 static GFile *
263 file_exists (GFile * parent, const char *filename, gboolean * result)
264 {
265   GFile *child;
266   gboolean res;
267
268   if (result)
269     *result = FALSE;
270
271   child = g_file_get_child (parent, filename);
272   g_assert (child != NULL);
273   res = g_file_query_exists (child, NULL);
274   if (result)
275     *result = res;
276
277   return child;
278 }
279
280 static void
281 test_attributes (struct StructureItem item, GFileInfo * info)
282 {
283   GFileType ftype;
284   guint32 mode;
285   const char *name, *display_name, *edit_name, *copy_name, *symlink_target;
286   gboolean utf8_valid;
287   gboolean has_attr;
288   gboolean is_symlink;
289   gboolean can_read, can_write;
290
291   /*  standard::type  */
292   has_attr = g_file_info_has_attribute (info, G_FILE_ATTRIBUTE_STANDARD_TYPE);
293   g_assert_cmpint (has_attr, ==, TRUE);
294   ftype = g_file_info_get_file_type (info);
295   g_assert_cmpint (ftype, !=, G_FILE_TYPE_UNKNOWN);
296   g_assert_cmpint (ftype, ==, item.file_type);
297
298   /*  unix::mode  */
299   if ((item.mode > 0) && (posix_compat))
300     {
301       mode =
302         g_file_info_get_attribute_uint32 (info,
303                                           G_FILE_ATTRIBUTE_UNIX_MODE) & 0xFFF;
304       g_assert_cmpint (mode, ==, item.mode);
305     }
306
307   /*  access::can-read  */
308   if (item.file_type != G_FILE_TYPE_SYMBOLIC_LINK)
309     {
310       can_read =
311         g_file_info_get_attribute_boolean (info,
312                                            G_FILE_ATTRIBUTE_ACCESS_CAN_READ);
313       g_assert_cmpint (can_read, ==, TRUE);
314     }
315
316   /*  access::can-write  */
317   if ((write_test) && ((item.extra_flags & TEST_OVERWRITE) == TEST_OVERWRITE))
318     {
319       can_write =
320         g_file_info_get_attribute_boolean (info,
321                                            G_FILE_ATTRIBUTE_ACCESS_CAN_WRITE);
322       g_assert_cmpint (can_write, ==, TRUE);
323     }
324
325   /*  standard::name  */
326   name = g_file_info_get_name (info);
327   g_assert (name != NULL);
328
329   /*  standard::display-name  */
330   display_name = g_file_info_get_display_name (info);
331   g_assert (display_name != NULL);
332   utf8_valid = g_utf8_validate (display_name, -1, NULL);
333   g_assert_cmpint (utf8_valid, ==, TRUE);
334
335   /*  standard::edit-name  */
336   edit_name = g_file_info_get_edit_name (info);
337   if (edit_name)
338     {
339       utf8_valid = g_utf8_validate (edit_name, -1, NULL);
340       g_assert_cmpint (utf8_valid, ==, TRUE);
341     }
342
343   /*  standard::copy-name  */
344   copy_name =
345     g_file_info_get_attribute_string (info,
346                                       G_FILE_ATTRIBUTE_STANDARD_COPY_NAME);
347   if (copy_name)
348     {
349       utf8_valid = g_utf8_validate (copy_name, -1, NULL);
350       g_assert_cmpint (utf8_valid, ==, TRUE);
351     }
352
353   /*  standard::is-symlink  */
354   if (posix_compat)
355     {
356       is_symlink = g_file_info_get_is_symlink (info);
357       g_assert_cmpint (is_symlink, ==,
358                        item.file_type == G_FILE_TYPE_SYMBOLIC_LINK);
359     }
360
361   /*  standard::symlink-target  */
362   if ((item.file_type == G_FILE_TYPE_SYMBOLIC_LINK) && (posix_compat))
363     {
364       symlink_target = g_file_info_get_symlink_target (info);
365       g_assert_cmpstr (symlink_target, ==, item.link_to);
366     }
367 }
368
369 static void
370 test_initial_structure (gconstpointer test_data)
371 {
372   GFile *root;
373   GFile *child;
374   gboolean res;
375   GError *error;
376   GFileInputStream *ins;
377   int i;
378   GFileInfo *info;
379   guint32 size;
380   guchar *buffer;
381   gssize read, total_read;
382   struct StructureItem item;
383
384
385   g_assert (test_data != NULL);
386   log ("\n  Testing sample structure in '%s'...\n", (char *) test_data);
387
388   root = g_file_new_for_commandline_arg ((char *) test_data);
389   g_assert (root != NULL);
390   res = g_file_query_exists (root, NULL);
391   g_assert_cmpint (res, ==, TRUE);
392
393   /*  test the structure  */
394   for (i = 0; i < G_N_ELEMENTS (sample_struct); i++)
395     {
396       item = sample_struct[i];
397       if (((!posix_compat) && (item.file_type == G_FILE_TYPE_SYMBOLIC_LINK))
398           || (item.handle_special))
399         continue;
400
401       log ("    Testing file '%s'...\n", item.filename);
402
403       child = file_exists (root, item.filename, &res);
404       g_assert (child != NULL);
405       g_assert_cmpint (res, ==, TRUE);
406
407       error = NULL;
408       info =
409         g_file_query_info (child, "*", G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
410                            NULL, &error);
411       g_assert (error == NULL);
412       g_assert (info != NULL);
413
414       test_attributes (item, info);
415
416       g_object_unref (child);
417     }
418
419   /*  read and test the pattern file  */
420   log ("    Testing pattern file...\n");
421   child = file_exists (root, "pattern_file", &res);
422   g_assert (child != NULL);
423   g_assert_cmpint (res, ==, TRUE);
424
425   error = NULL;
426   info =
427     g_file_query_info (child, "*", G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, NULL,
428                        &error);
429   g_assert (error == NULL);
430   g_assert (info != NULL);
431   size = g_file_info_get_size (info);
432   g_assert_cmpint (size, ==, PATTERN_FILE_SIZE);
433
434   error = NULL;
435   ins = g_file_read (child, NULL, &error);
436   g_assert (ins != NULL);
437   g_assert (error == NULL);
438
439   buffer = g_malloc (PATTERN_FILE_SIZE);
440   total_read = 0;
441
442   while (total_read < PATTERN_FILE_SIZE)
443     {
444       error = NULL;
445       read =
446         g_input_stream_read (G_INPUT_STREAM (ins), buffer + total_read,
447                              PATTERN_FILE_SIZE, NULL, &error);
448       g_assert (error == NULL);
449       total_read += read;
450       log ("      read %d bytes, total = %d of %d.\n", read, total_read,
451            PATTERN_FILE_SIZE);
452     }
453   g_assert_cmpint (total_read, ==, PATTERN_FILE_SIZE);
454
455   error = NULL;
456   res = g_input_stream_close (G_INPUT_STREAM (ins), NULL, &error);
457   g_assert (error == NULL);
458   g_assert_cmpint (res, ==, TRUE);
459
460   for (i = 0; i < PATTERN_FILE_SIZE; i++)
461     g_assert_cmpint (*(buffer + i), ==, i % 256);
462
463   g_object_unref (ins);
464   g_object_unref (child);
465   g_free (buffer);
466   g_object_unref (root);
467 }
468
469 static void
470 traverse_recurse_dirs (GFile * parent, GFile * root)
471 {
472   gboolean res;
473   GError *error;
474   GFileEnumerator *enumerator;
475   GFileInfo *info;
476   GFile *descend;
477   char *relative_path;
478   int i;
479   gboolean found;
480
481   g_assert (root != NULL);
482
483   error = NULL;
484   enumerator =
485     g_file_enumerate_children (parent, "*",
486                                G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, NULL,
487                                &error);
488   g_assert (enumerator != NULL);
489   g_assert (error == NULL);
490
491   error = NULL;
492   info = g_file_enumerator_next_file (enumerator, NULL, &error);
493   while ((info) && (!error))
494     {
495       descend = g_file_get_child (parent, g_file_info_get_name (info));
496       g_assert (descend != NULL);
497       relative_path = g_file_get_relative_path (root, descend);
498       g_assert (relative_path != NULL);
499
500       found = FALSE;
501       for (i = 0; i < G_N_ELEMENTS (sample_struct); i++)
502         {
503           if (strcmp (sample_struct[i].filename, relative_path) == 0)
504             {
505               /*  test the attributes again  */
506               test_attributes (sample_struct[i], info);
507
508               found = TRUE;
509               break;
510             }
511         }
512       g_assert_cmpint (found, ==, TRUE);
513
514       log ("  Found file %s, relative to root: %s\n",
515            g_file_info_get_display_name (info), relative_path);
516
517       if (g_file_info_get_file_type (info) == G_FILE_TYPE_DIRECTORY)
518         traverse_recurse_dirs (descend, root);
519
520       g_object_unref (descend);
521       error = NULL;
522       info = g_file_enumerator_next_file (enumerator, NULL, &error);
523     }
524   g_assert (error == NULL);
525
526   error = NULL;
527   res = g_file_enumerator_close (enumerator, NULL, &error);
528   g_assert_cmpint (res, ==, TRUE);
529   g_assert (error == NULL);
530 }
531
532 static void
533 test_traverse_structure (gconstpointer test_data)
534 {
535   GFile *root;
536   gboolean res;
537
538   g_assert (test_data != NULL);
539   log ("\n  Traversing through the sample structure in '%s'...\n",
540        (char *) test_data);
541
542   root = g_file_new_for_commandline_arg ((char *) test_data);
543   g_assert (root != NULL);
544   res = g_file_query_exists (root, NULL);
545   g_assert_cmpint (res, ==, TRUE);
546
547   traverse_recurse_dirs (root, root);
548
549   g_object_unref (root);
550 }
551
552
553
554
555 static void
556 test_enumerate (gconstpointer test_data)
557 {
558   GFile *root, *child;
559   gboolean res;
560   GError *error;
561   GFileEnumerator *enumerator;
562   GFileInfo *info;
563   int i;
564   struct StructureItem item;
565
566
567   g_assert (test_data != NULL);
568   log ("\n  Test enumerate '%s'...\n", (char *) test_data);
569
570   root = g_file_new_for_commandline_arg ((char *) test_data);
571   g_assert (root != NULL);
572   res = g_file_query_exists (root, NULL);
573   g_assert_cmpint (res, ==, TRUE);
574
575
576   for (i = 0; i < G_N_ELEMENTS (sample_struct); i++)
577     {
578       item = sample_struct[i];
579       if ((!posix_compat) && (item.file_type == G_FILE_TYPE_SYMBOLIC_LINK))
580         continue;
581
582       if (((item.extra_flags & TEST_NOT_EXISTS) == TEST_NOT_EXISTS) ||
583           (((item.extra_flags & TEST_NO_ACCESS) == TEST_NO_ACCESS)
584            && posix_compat)
585           || ((item.extra_flags & TEST_ENUMERATE_FILE) ==
586               TEST_ENUMERATE_FILE))
587         {
588           log ("    Testing file '%s'\n", item.filename);
589           child = g_file_get_child (root, item.filename);
590           g_assert (child != NULL);
591           error = NULL;
592           enumerator =
593             g_file_enumerate_children (child, "*",
594                                        G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
595                                        NULL, &error);
596
597           if ((item.extra_flags & TEST_NOT_EXISTS) == TEST_NOT_EXISTS)
598             {
599               g_assert (enumerator == NULL);
600               g_assert_cmpint (error->code, ==, G_IO_ERROR_NOT_FOUND);
601             }
602           if ((item.extra_flags & TEST_ENUMERATE_FILE) == TEST_ENUMERATE_FILE)
603             {
604               g_assert (enumerator == NULL);
605               g_assert_cmpint (error->code, ==, G_IO_ERROR_NOT_DIRECTORY);
606             }
607           if ((item.extra_flags & TEST_NO_ACCESS) == TEST_NO_ACCESS)
608             {
609               g_assert (enumerator != NULL);
610
611               error = NULL;
612               info = g_file_enumerator_next_file (enumerator, NULL, &error);
613               g_assert (info == NULL);
614               g_assert (error == NULL);
615               /*  no items should be found, no error should be logged  */
616             }
617
618           if (error)
619             g_error_free (error);
620
621           if (enumerator)
622             {
623               error = NULL;
624               res = g_file_enumerator_close (enumerator, NULL, &error);
625               g_assert_cmpint (res, ==, TRUE);
626               g_assert (error == NULL);
627             }
628           g_object_unref (child);
629         }
630     }
631   g_object_unref (root);
632 }
633
634 static void
635 do_copy_move (GFile * root, struct StructureItem item, const char *target_dir,
636               enum StructureExtraFlags extra_flags)
637 {
638   GFile *dst_dir, *src_file, *dst_file;
639   gboolean res;
640   GError *error;
641
642   log ("    do_copy_move: '%s' --> '%s'\n", item.filename, target_dir);
643
644   dst_dir = g_file_get_child (root, target_dir);
645   g_assert (dst_dir != NULL);
646   src_file = g_file_get_child (root, item.filename);
647   g_assert (src_file != NULL);
648   dst_file = g_file_get_child (dst_dir, item.filename);
649   g_assert (dst_file != NULL);
650
651   error = NULL;
652   if ((item.extra_flags & TEST_COPY) == TEST_COPY)
653     res =
654       g_file_copy (src_file, dst_file,
655                    G_FILE_COPY_NOFOLLOW_SYMLINKS |
656                    ((extra_flags ==
657                      TEST_OVERWRITE) ? G_FILE_COPY_OVERWRITE :
658                     G_FILE_COPY_NONE), NULL, NULL, NULL, &error);
659   else
660     res =
661       g_file_move (src_file, dst_file, G_FILE_COPY_NOFOLLOW_SYMLINKS, NULL,
662                    NULL, NULL, &error);
663
664   if (error)
665     log ("       res = %d, error code %d = %s\n", res, error->code,
666          error->message);
667
668   /*  copying file/directory to itself (".")  */
669   if (((item.extra_flags & TEST_NOT_EXISTS) != TEST_NOT_EXISTS) &&
670       (extra_flags == TEST_ALREADY_EXISTS))
671     {
672       g_assert_cmpint (res, ==, FALSE);
673       g_assert_cmpint (error->code, ==, G_IO_ERROR_EXISTS);
674     }
675   /*  target file is a file, overwrite is not set  */
676   else if (((item.extra_flags & TEST_NOT_EXISTS) != TEST_NOT_EXISTS) &&
677            (extra_flags == TEST_TARGET_IS_FILE))
678     {
679       g_assert_cmpint (res, ==, FALSE);
680       if (item.file_type == G_FILE_TYPE_DIRECTORY)
681         g_assert_cmpint (error->code, ==, G_IO_ERROR_WOULD_RECURSE);
682       else
683         g_assert_cmpint (error->code, ==, G_IO_ERROR_NOT_DIRECTORY);
684     }
685   /*  source file is directory  */
686   else if ((item.extra_flags & TEST_COPY_ERROR_RECURSE) ==
687            TEST_COPY_ERROR_RECURSE)
688     {
689       g_assert_cmpint (res, ==, FALSE);
690       g_assert_cmpint (error->code, ==, G_IO_ERROR_WOULD_RECURSE);
691     }
692   /*  source or target path doesn't exist  */
693   else if (((item.extra_flags & TEST_NOT_EXISTS) == TEST_NOT_EXISTS) ||
694            (extra_flags == TEST_NOT_EXISTS))
695     {
696       g_assert_cmpint (res, ==, FALSE);
697       g_assert_cmpint (error->code, ==, G_IO_ERROR_NOT_FOUND);
698     }
699   /*  source or target path permission denied  */
700   else if (((item.extra_flags & TEST_NO_ACCESS) == TEST_NO_ACCESS) ||
701            (extra_flags == TEST_NO_ACCESS))
702     {
703       g_assert_cmpint (res, ==, FALSE);
704       g_assert_cmpint (error->code, ==, G_IO_ERROR_PERMISSION_DENIED);
705     }
706   /*  no error should be found, all exceptions defined above  */
707   else
708     {
709       g_assert_cmpint (res, ==, TRUE);
710       g_assert (error == NULL);
711     }
712
713   if (error)
714     g_error_free (error);
715
716
717   g_object_unref (dst_dir);
718   g_object_unref (src_file);
719   g_object_unref (dst_file);
720 }
721
722 static void
723 test_copy_move (gconstpointer test_data)
724 {
725   GFile *root;
726   gboolean res;
727   int i;
728   struct StructureItem item;
729
730   log ("\n");
731
732   g_assert (test_data != NULL);
733   root = g_file_new_for_commandline_arg ((char *) test_data);
734   g_assert (root != NULL);
735   res = g_file_query_exists (root, NULL);
736   g_assert_cmpint (res, ==, TRUE);
737
738
739   for (i = 0; i < G_N_ELEMENTS (sample_struct); i++)
740     {
741       item = sample_struct[i];
742
743       if ((!posix_compat) && (item.file_type == G_FILE_TYPE_SYMBOLIC_LINK))
744         continue;
745
746       if (((item.extra_flags & TEST_COPY) == TEST_COPY) ||
747           ((item.extra_flags & TEST_MOVE) == TEST_MOVE))
748         {
749           /*  test copy/move to a directory, expecting no errors if source files exist  */
750           do_copy_move (root, item, TEST_DIR_TARGET, 0);
751
752           /*  some files have been already moved so we can't count with them in the tests  */
753           if ((item.extra_flags & TEST_COPY) == TEST_COPY)
754             {
755               /*  test overwrite for flagged files  */
756               if ((item.extra_flags & TEST_OVERWRITE) == TEST_OVERWRITE)
757                 {
758                   do_copy_move (root, item, TEST_DIR_TARGET, TEST_OVERWRITE);
759                 }
760               /*  source = target, should return G_IO_ERROR_EXISTS  */
761               do_copy_move (root, item, ".", TEST_ALREADY_EXISTS);
762               /*  target is file  */
763               do_copy_move (root, item, TEST_TARGET_FILE,
764                             TEST_TARGET_IS_FILE);
765               /*  target path is invalid  */
766               do_copy_move (root, item, TEST_NAME_NOT_EXISTS,
767                             TEST_NOT_EXISTS);
768
769               /*  tests on POSIX-compatible filesystems  */
770               if (posix_compat)
771                 {
772                   /*  target directory is not accessible (no execute flag)  */
773                   do_copy_move (root, item, TEST_DIR_NO_ACCESS,
774                                 TEST_NO_ACCESS);
775                   /*  target directory is readonly  */
776                   do_copy_move (root, item, TEST_DIR_NO_WRITE,
777                                 TEST_NO_ACCESS);
778                 }
779             }
780         }
781     }
782   g_object_unref (root);
783 }
784
785 static void
786 test_create (gconstpointer test_data)
787 {
788   GFile *root, *child;
789   gboolean res;
790   GError *error;
791   int i;
792   struct StructureItem item;
793   GFileOutputStream *os;
794
795   g_assert (test_data != NULL);
796   log ("\n");
797
798   root = g_file_new_for_commandline_arg ((char *) test_data);
799   g_assert (root != NULL);
800   res = g_file_query_exists (root, NULL);
801   g_assert_cmpint (res, ==, TRUE);
802
803   for (i = 0; i < G_N_ELEMENTS (sample_struct); i++)
804     {
805       item = sample_struct[i];
806
807       if (((item.extra_flags & TEST_CREATE) == TEST_CREATE) ||
808           ((item.extra_flags & TEST_REPLACE) == TEST_REPLACE) ||
809           ((item.extra_flags & TEST_APPEND) == TEST_APPEND))
810         {
811           log ("  test_create: '%s'\n", item.filename);
812
813           child = g_file_get_child (root, item.filename);
814           g_assert (child != NULL);
815           error = NULL;
816           os = NULL;
817
818           if ((item.extra_flags & TEST_CREATE) == TEST_CREATE)
819             os = g_file_create (child, item.create_flags, NULL, &error);
820           else if ((item.extra_flags & TEST_REPLACE) == TEST_REPLACE)
821             os =
822               g_file_replace (child, NULL, TRUE, item.create_flags, NULL,
823                               &error);
824           else if ((item.extra_flags & TEST_APPEND) == TEST_APPEND)
825             os = g_file_append_to (child, item.create_flags, NULL, &error);
826
827
828           if (error)
829             log ("       error code %d = %s\n", error->code, error->message);
830
831           if (((item.extra_flags & TEST_NOT_EXISTS) == 0) &&
832               ((item.extra_flags & TEST_CREATE) == TEST_CREATE))
833             {
834               g_assert (os == NULL);
835               g_assert (error != NULL);
836               g_assert_cmpint (error->code, ==, G_IO_ERROR_EXISTS);
837             }
838           else if (item.file_type == G_FILE_TYPE_DIRECTORY)
839             {
840               g_assert (os == NULL);
841               g_assert (error != NULL);
842               if ((item.extra_flags & TEST_CREATE) == TEST_CREATE)
843                 g_assert_cmpint (error->code, ==, G_IO_ERROR_EXISTS);
844               else
845                 g_assert_cmpint (error->code, ==, G_IO_ERROR_IS_DIRECTORY);
846             }
847           else
848             {
849               g_assert (os != NULL);
850               g_assert (error == NULL);
851             }
852
853           if (error)
854             g_error_free (error);
855
856           if (os)
857             {
858               error = NULL;
859               res =
860                 g_output_stream_close (G_OUTPUT_STREAM (os), NULL, &error);
861               if (error)
862                 log ("         g_output_stream_close: error %d = %s\n",
863                      error->code, error->message);
864               g_assert_cmpint (res, ==, TRUE);
865               g_assert (error == NULL);
866             }
867           g_object_unref (child);
868         }
869     }
870   g_object_unref (root);
871 }
872
873 static void
874 test_open (gconstpointer test_data)
875 {
876   GFile *root, *child;
877   gboolean res;
878   GError *error;
879   int i;
880   struct StructureItem item;
881   GFileInputStream *input_stream;
882
883   g_assert (test_data != NULL);
884   log ("\n");
885
886   root = g_file_new_for_commandline_arg ((char *) test_data);
887   g_assert (root != NULL);
888   res = g_file_query_exists (root, NULL);
889   g_assert_cmpint (res, ==, TRUE);
890
891   for (i = 0; i < G_N_ELEMENTS (sample_struct); i++)
892     {
893       item = sample_struct[i];
894
895       if ((!posix_compat) && (item.file_type == G_FILE_TYPE_SYMBOLIC_LINK))
896         continue;
897
898       if ((item.extra_flags & TEST_OPEN) == TEST_OPEN)
899         {
900           log ("  test_open: '%s'\n", item.filename);
901
902           child = g_file_get_child (root, item.filename);
903           g_assert (child != NULL);
904           error = NULL;
905           input_stream = g_file_read (child, NULL, &error);
906
907           if (((item.extra_flags & TEST_NOT_EXISTS) == TEST_NOT_EXISTS) ||
908               ((item.extra_flags & TEST_INVALID_SYMLINK) ==
909                TEST_INVALID_SYMLINK))
910             {
911               g_assert (input_stream == NULL);
912               g_assert_cmpint (error->code, ==, G_IO_ERROR_NOT_FOUND);
913             }
914           else if (item.file_type == G_FILE_TYPE_DIRECTORY)
915             {
916               g_assert (input_stream == NULL);
917               g_assert_cmpint (error->code, ==, G_IO_ERROR_IS_DIRECTORY);
918             }
919           else
920             {
921               g_assert (input_stream != NULL);
922               g_assert (error == NULL);
923             }
924
925           if (error)
926             g_error_free (error);
927
928           if (input_stream)
929             {
930               error = NULL;
931               res =
932                 g_input_stream_close (G_INPUT_STREAM (input_stream), NULL,
933                                       &error);
934               g_assert_cmpint (res, ==, TRUE);
935               g_assert (error == NULL);
936             }
937           g_object_unref (child);
938         }
939     }
940   g_object_unref (root);
941 }
942
943 static void
944 test_delete (gconstpointer test_data)
945 {
946   GFile *root;
947   GFile *child;
948   gboolean res;
949   GError *error;
950   int i;
951   struct StructureItem item;
952
953   g_assert (test_data != NULL);
954   log ("\n");
955
956   root = g_file_new_for_commandline_arg ((char *) test_data);
957   g_assert (root != NULL);
958   res = g_file_query_exists (root, NULL);
959   g_assert_cmpint (res, ==, TRUE);
960
961   for (i = 0; i < G_N_ELEMENTS (sample_struct); i++)
962     {
963       item = sample_struct[i];
964
965       if ((!posix_compat) && (item.file_type == G_FILE_TYPE_SYMBOLIC_LINK))
966         continue;
967
968       if (((item.extra_flags & TEST_DELETE_NORMAL) == TEST_DELETE_NORMAL) ||
969           ((item.extra_flags & TEST_DELETE_TRASH) == TEST_DELETE_TRASH))
970         {
971           child = file_exists (root, item.filename, &res);
972           g_assert (child != NULL);
973           /*  we don't care about result here  */
974
975           log ("  Deleting %s, path = %s\n", item.filename,
976                g_file_get_path (child));
977           error = NULL;
978           if ((item.extra_flags & TEST_DELETE_NORMAL) == TEST_DELETE_NORMAL)
979             res = g_file_delete (child, NULL, &error);
980           else
981             res = g_file_trash (child, NULL, &error);
982
983           if ((item.extra_flags & TEST_DELETE_NON_EMPTY) ==
984               TEST_DELETE_NON_EMPTY)
985             {
986               g_assert_cmpint (res, ==, FALSE);
987               g_assert (error != NULL);
988               g_assert_cmpint (error->code, ==, G_IO_ERROR_NOT_EMPTY);
989             }
990           if ((item.extra_flags & TEST_DELETE_FAILURE) == TEST_DELETE_FAILURE)
991             {
992               g_assert_cmpint (res, ==, FALSE);
993               g_assert (error != NULL);
994               g_assert_cmpint (error->code, !=, 0);
995             }
996           if ((item.extra_flags & TEST_NOT_EXISTS) == TEST_NOT_EXISTS)
997             {
998               g_assert_cmpint (res, ==, FALSE);
999               g_assert (error != NULL);
1000               g_assert_cmpint (error->code, ==, G_IO_ERROR_NOT_FOUND);
1001             }
1002
1003           if (error)
1004             {
1005               log ("      result = %d, error = %s\n", res, error->message);
1006               g_error_free (error);
1007             }
1008
1009           g_object_unref (child);
1010         }
1011     }
1012   g_object_unref (root);
1013 }
1014
1015
1016 static void
1017 cleanup_dir_recurse (GFile *parent, GFile *root)
1018 {
1019   gboolean res;
1020   GError *error;
1021   GFileEnumerator *enumerator;
1022   GFileInfo *info;
1023   GFile *descend;
1024   char *relative_path;
1025
1026   g_assert (root != NULL);
1027
1028   error = NULL;
1029   enumerator =
1030     g_file_enumerate_children (parent, "*",
1031                                G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, NULL,
1032                                &error);
1033   if (! enumerator)
1034           return;
1035
1036   error = NULL;
1037   info = g_file_enumerator_next_file (enumerator, NULL, &error);
1038   while ((info) && (!error))
1039     {
1040       descend = g_file_get_child (parent, g_file_info_get_name (info));
1041       g_assert (descend != NULL);
1042       relative_path = g_file_get_relative_path (root, descend);
1043       g_assert (relative_path != NULL);
1044
1045       log ("    deleting '%s'\n", g_file_info_get_display_name (info));
1046
1047       if (g_file_info_get_file_type (info) == G_FILE_TYPE_DIRECTORY)
1048           cleanup_dir_recurse (descend, root);
1049       
1050       error = NULL;
1051       res = g_file_delete (descend, NULL, &error);
1052       g_assert_cmpint (res, ==, TRUE);
1053
1054       g_object_unref (descend);
1055       error = NULL;
1056       info = g_file_enumerator_next_file (enumerator, NULL, &error);
1057     }
1058   g_assert (error == NULL);
1059
1060   error = NULL;
1061   res = g_file_enumerator_close (enumerator, NULL, &error);
1062   g_assert_cmpint (res, ==, TRUE);
1063   g_assert (error == NULL);
1064 }
1065
1066 static void
1067 prep_clean_structure (gconstpointer test_data)
1068 {
1069   GFile *root;
1070   
1071   g_assert (test_data != NULL);
1072   log ("\n  Cleaning target testing structure in '%s'...\n",
1073        (char *) test_data);
1074
1075   root = g_file_new_for_commandline_arg ((char *) test_data);
1076   g_assert (root != NULL);
1077   
1078   cleanup_dir_recurse (root, root);
1079
1080   g_file_delete (root, NULL, NULL);
1081   
1082   g_object_unref (root);
1083 }
1084
1085 int
1086 main (int argc, char *argv[])
1087 {
1088   static gboolean only_create_struct;
1089   static char *target_path;
1090   GError *error;
1091   GOptionContext *context;
1092
1093   static GOptionEntry cmd_entries[] = {
1094     {"read-write", 'w', 0, G_OPTION_ARG_NONE, &write_test,
1095      "Perform write tests (incl. structure creation)", NULL},
1096     {"create-struct", 'c', 0, G_OPTION_ARG_NONE, &only_create_struct,
1097      "Only create testing structure (no tests)", NULL},
1098     {"verbose", 'v', 0, G_OPTION_ARG_NONE, &verbose, "Be verbose", NULL},
1099     {"posix", 'x', 0, G_OPTION_ARG_NONE, &posix_compat,
1100      "Test POSIX-specific features (unix permissions, symlinks)", NULL},
1101     {NULL}
1102   };
1103
1104   verbose = FALSE;
1105   write_test = FALSE;
1106   only_create_struct = FALSE;
1107   target_path = NULL;
1108   posix_compat = FALSE;
1109
1110   /*  strip all gtester-specific args  */
1111   g_type_init ();
1112   g_test_init (&argc, &argv, NULL);
1113
1114   /*  no extra parameters specified, assume we're executed from glib test suite  */ 
1115   if (argc < 2)
1116     {
1117           verbose = TRUE;
1118           write_test = TRUE;
1119           only_create_struct = FALSE;
1120           target_path = DEFAULT_TEST_DIR;
1121 #ifdef G_PLATFORM_WIN32
1122           posix_compat = FALSE;
1123 #else
1124           posix_compat = TRUE;
1125 #endif
1126     }
1127   
1128   /*  add trailing args  */
1129   error = NULL;
1130   context = g_option_context_new ("target_path");
1131   g_option_context_add_main_entries (context, cmd_entries, NULL);
1132   if (!g_option_context_parse (context, &argc, &argv, &error))
1133     {
1134       g_print ("option parsing failed: %s\n", error->message);
1135       return g_test_run ();
1136     }
1137
1138   /*  remaining arg should is the target path; we don't care of the extra args here  */ 
1139   if (argc >= 2)
1140     target_path = strdup (argv[1]);
1141   
1142   if (! target_path) 
1143     {
1144       g_print ("error: target path was not specified\n");
1145       g_print (g_option_context_get_help (context, TRUE, NULL));
1146       return g_test_run ();
1147     }
1148
1149   
1150   /*  Write test - clean target directory first  */
1151   /*    this can be also considered as a test - enumerate + delete  */ 
1152   if (write_test || only_create_struct)
1153     g_test_add_data_func ("/live-g-file/prep_clean_structure", target_path,
1154                   prep_clean_structure);
1155   
1156   /*  Write test - create new testing structure  */
1157   if (write_test || only_create_struct)
1158     g_test_add_data_func ("/live-g-file/create_structure", target_path,
1159                           test_create_structure);
1160
1161   /*  Read test - test the sample structure - expect defined attributes to be there  */
1162   if (!only_create_struct)
1163     g_test_add_data_func ("/live-g-file/test_initial_structure", target_path,
1164                           test_initial_structure);
1165
1166   /*  Read test - test traverse the structure - no special file should appear  */
1167   if (!only_create_struct)
1168     g_test_add_data_func ("/live-g-file/test_traverse_structure", target_path,
1169                           test_traverse_structure);
1170
1171   /*  Read test - enumerate  */
1172   if (!only_create_struct)
1173     g_test_add_data_func ("/live-g-file/test_enumerate", target_path,
1174                           test_enumerate);
1175
1176   /*  Read test - open (g_file_read())  */
1177   if (!only_create_struct)
1178     g_test_add_data_func ("/live-g-file/test_open", target_path, test_open);
1179
1180   /*  Write test - create  */
1181   if (write_test && (!only_create_struct))
1182     g_test_add_data_func ("/live-g-file/test_create", target_path,
1183                           test_create);
1184
1185   /*  Write test - copy, move  */
1186   if (write_test && (!only_create_struct))
1187     g_test_add_data_func ("/live-g-file/test_copy_move", target_path,
1188                           test_copy_move);
1189
1190   /*  Write test - delete, trash  */
1191   if (write_test && (!only_create_struct))
1192     g_test_add_data_func ("/live-g-file/test_delete", target_path,
1193                           test_delete);
1194
1195   if (write_test || only_create_struct)
1196     g_test_add_data_func ("/live-g-file/final_clean", target_path,
1197                   prep_clean_structure);
1198
1199   return g_test_run ();
1200
1201 }