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