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