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