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