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