9d819f3cce3df375437741b7e96de4cc42432bcd
[platform/upstream/glib.git] / gio / tests / file.c
1 #include <string.h>
2 #include <stdio.h>
3 #include <stdlib.h>
4 #include <gio/gio.h>
5 #include <gio/gfiledescriptorbased.h>
6 #ifdef G_OS_UNIX
7 #include <sys/stat.h>
8 #endif
9
10 static void
11 test_basic (void)
12 {
13   GFile *file;
14   gchar *s;
15
16   file = g_file_new_for_path ("./some/directory/testfile");
17
18   s = g_file_get_basename (file);
19   g_assert_cmpstr (s, ==, "testfile");
20   g_free (s);
21
22   s = g_file_get_uri (file);
23   g_assert (g_str_has_prefix (s, "file://"));
24   g_assert (g_str_has_suffix (s, "/some/directory/testfile"));
25   g_free (s);
26
27   g_assert (g_file_has_uri_scheme (file, "file"));
28   s = g_file_get_uri_scheme (file);
29   g_assert_cmpstr (s, ==, "file");
30   g_free (s);
31
32   g_object_unref (file);
33 }
34
35 static void
36 test_parent (void)
37 {
38   GFile *file;
39   GFile *file2;
40   GFile *parent;
41   GFile *root;
42
43   file = g_file_new_for_path ("./some/directory/testfile");
44   file2 = g_file_new_for_path ("./some/directory");
45   root = g_file_new_for_path ("/");
46
47   g_assert (g_file_has_parent (file, file2));
48
49   parent = g_file_get_parent (file);
50   g_assert (g_file_equal (parent, file2));
51   g_object_unref (parent);
52
53   g_assert (g_file_get_parent (root) == NULL);
54
55   g_object_unref (file);
56   g_object_unref (file2);
57   g_object_unref (root);
58 }
59
60 static void
61 test_child (void)
62 {
63   GFile *file;
64   GFile *child;
65   GFile *child2;
66
67   file = g_file_new_for_path ("./some/directory");
68   child = g_file_get_child (file, "child");
69   g_assert (g_file_has_parent (child, file));
70
71   child2 = g_file_get_child_for_display_name (file, "child2", NULL);
72   g_assert (g_file_has_parent (child2, file));
73
74   g_object_unref (child);
75   g_object_unref (child2);
76   g_object_unref (file);
77 }
78
79 static void
80 test_type (void)
81 {
82   GFile *datapath_f;
83   GFile *file;
84   GFileType type;
85   GError *error = NULL;
86
87   datapath_f = g_file_new_for_path (g_test_get_dir (G_TEST_DIST));
88
89   file = g_file_get_child (datapath_f, "g-icon.c");
90   type = g_file_query_file_type (file, 0, NULL);
91   g_assert_cmpint (type, ==, G_FILE_TYPE_REGULAR);
92   g_object_unref (file);
93
94   file = g_file_get_child (datapath_f, "cert-tests");
95   type = g_file_query_file_type (file, 0, NULL);
96   g_assert_cmpint (type, ==, G_FILE_TYPE_DIRECTORY);
97
98   g_file_read (file, NULL, &error);
99   g_assert_error (error, G_IO_ERROR, G_IO_ERROR_IS_DIRECTORY);
100   g_error_free (error);
101   g_object_unref (file);
102
103   g_object_unref (datapath_f);
104 }
105
106 static void
107 test_parse_name (void)
108 {
109   GFile *file;
110   gchar *name;
111
112   file = g_file_new_for_uri ("file://somewhere");
113   name = g_file_get_parse_name (file);
114   g_assert_cmpstr (name, ==, "file://somewhere");
115   g_object_unref (file);
116   g_free (name);
117
118   file = g_file_parse_name ("~foo");
119   name = g_file_get_parse_name (file);
120   g_assert (name != NULL);
121   g_object_unref (file);
122   g_free (name);
123 }
124
125 typedef struct
126 {
127   GFile *file;
128   GFileMonitor *monitor;
129   GOutputStream *ostream;
130   GInputStream *istream;
131   GMainLoop *loop;
132   gint buffersize;
133   gint monitor_created;
134   gint monitor_deleted;
135   gint monitor_changed;
136   gchar *monitor_path;
137   gint pos;
138   gchar *data;
139   gchar *buffer;
140   guint timeout;
141 } CreateDeleteData;
142
143 static void
144 monitor_changed (GFileMonitor      *monitor,
145                  GFile             *file,
146                  GFile             *other_file,
147                  GFileMonitorEvent  event_type,
148                  gpointer           user_data)
149 {
150   CreateDeleteData *data = user_data;
151   gchar *path;
152
153   path = g_file_get_path (file);
154   g_assert_cmpstr (data->monitor_path, ==, path);
155   g_free (path);
156
157   if (event_type == G_FILE_MONITOR_EVENT_CREATED)
158     data->monitor_created++;
159   if (event_type == G_FILE_MONITOR_EVENT_DELETED)
160     data->monitor_deleted++;
161   if (event_type == G_FILE_MONITOR_EVENT_CHANGED)
162     data->monitor_changed++;
163 }
164
165
166 static gboolean
167 quit_idle (gpointer user_data)
168 {
169   CreateDeleteData *data = user_data;
170
171   g_source_remove (data->timeout); 
172   g_main_loop_quit (data->loop);
173
174   return FALSE;
175 }
176
177 static void
178 iclosed_cb (GObject      *source,
179             GAsyncResult *res,
180             gpointer      user_data)
181 {
182   CreateDeleteData *data = user_data;
183   GError *error;
184   gboolean ret;
185
186   error = NULL;
187   ret = g_input_stream_close_finish (data->istream, res, &error);
188   g_assert_no_error (error);
189   g_assert (ret);
190
191   g_assert (g_input_stream_is_closed (data->istream));
192
193   ret = g_file_delete (data->file, NULL, &error);
194   g_assert (ret);
195   g_assert_no_error (error);
196
197   /* work around file monitor bug:
198    * inotify events are only processed every 1000 ms, regardless
199    * of the rate limit set on the file monitor
200    */
201   g_timeout_add (2000, quit_idle, data);
202 }
203
204 static void
205 read_cb (GObject      *source,
206          GAsyncResult *res,
207          gpointer      user_data)
208 {
209   CreateDeleteData *data = user_data;
210   GError *error;
211   gssize size;
212
213   error = NULL;
214   size = g_input_stream_read_finish (data->istream, res, &error);
215   g_assert_no_error (error);
216
217   data->pos += size;
218   if (data->pos < strlen (data->data))
219     {
220       g_input_stream_read_async (data->istream,
221                                  data->buffer + data->pos,
222                                  strlen (data->data) - data->pos,
223                                  0,
224                                  NULL,
225                                  read_cb,
226                                  data);
227     }
228   else
229     {
230       g_assert_cmpstr (data->buffer, ==, data->data);
231       g_assert (!g_input_stream_is_closed (data->istream));
232       g_input_stream_close_async (data->istream, 0, NULL, iclosed_cb, data);
233     }
234 }
235
236 static void
237 ipending_cb (GObject      *source,
238              GAsyncResult *res,
239              gpointer      user_data)
240 {
241   CreateDeleteData *data = user_data;
242   GError *error;
243
244   error = NULL;
245   g_input_stream_read_finish (data->istream, res, &error);
246   g_assert_error (error, G_IO_ERROR, G_IO_ERROR_PENDING);
247   g_error_free (error);
248 }
249
250 static void
251 skipped_cb (GObject      *source,
252             GAsyncResult *res,
253             gpointer      user_data)
254 {
255   CreateDeleteData *data = user_data;
256   GError *error;
257   gssize size;
258
259   error = NULL;
260   size = g_input_stream_skip_finish (data->istream, res, &error);
261   g_assert_no_error (error);
262   g_assert_cmpint (size, ==, data->pos);
263
264   g_input_stream_read_async (data->istream,
265                              data->buffer + data->pos,
266                              strlen (data->data) - data->pos,
267                              0,
268                              NULL,
269                              read_cb,
270                              data);
271   /* check that we get a pending error */
272   g_input_stream_read_async (data->istream,
273                              data->buffer + data->pos,
274                              strlen (data->data) - data->pos,
275                              0,
276                              NULL,
277                              ipending_cb,
278                              data);
279 }
280
281 static void
282 opened_cb (GObject      *source,
283            GAsyncResult *res,
284            gpointer      user_data)
285 {
286   GFileInputStream *base;
287   CreateDeleteData *data = user_data;
288   GError *error;
289
290   error = NULL;
291   base = g_file_read_finish (data->file, res, &error);
292   g_assert_no_error (error);
293
294   if (data->buffersize == 0)
295     data->istream = G_INPUT_STREAM (g_object_ref (base));
296   else
297     data->istream = g_buffered_input_stream_new_sized (G_INPUT_STREAM (base), data->buffersize);
298   g_object_unref (base);
299
300   data->buffer = g_new0 (gchar, strlen (data->data) + 1);
301
302   /* copy initial segment directly, then skip */
303   memcpy (data->buffer, data->data, 10);
304   data->pos = 10;
305
306   g_input_stream_skip_async (data->istream,
307                              10,
308                              0,
309                              NULL,
310                              skipped_cb,
311                              data);
312 }
313
314 static void
315 oclosed_cb (GObject      *source,
316             GAsyncResult *res,
317             gpointer      user_data)
318 {
319   CreateDeleteData *data = user_data;
320   GError *error;
321   gboolean ret;
322
323   error = NULL;
324   ret = g_output_stream_close_finish (data->ostream, res, &error);
325   g_assert_no_error (error);
326   g_assert (ret);
327   g_assert (g_output_stream_is_closed (data->ostream));
328
329   g_file_read_async (data->file, 0, NULL, opened_cb, data);
330 }
331
332 static void
333 written_cb (GObject      *source,
334             GAsyncResult *res,
335             gpointer      user_data)
336 {
337   CreateDeleteData *data = user_data;
338   gssize size;
339   GError *error;
340
341   error = NULL;
342   size = g_output_stream_write_finish (data->ostream, res, &error);
343   g_assert_no_error (error);
344
345   data->pos += size;
346   if (data->pos < strlen (data->data))
347     {
348       g_output_stream_write_async (data->ostream,
349                                    data->data + data->pos,
350                                    strlen (data->data) - data->pos,
351                                    0,
352                                    NULL,
353                                    written_cb,
354                                    data);
355     }
356   else
357     {
358       g_assert (!g_output_stream_is_closed (data->ostream));
359       g_output_stream_close_async (data->ostream, 0, NULL, oclosed_cb, data);
360     }
361 }
362
363 static void
364 opending_cb (GObject      *source,
365              GAsyncResult *res,
366              gpointer      user_data)
367 {
368   CreateDeleteData *data = user_data;
369   GError *error;
370
371   error = NULL;
372   g_output_stream_write_finish (data->ostream, res, &error);
373   g_assert_error (error, G_IO_ERROR, G_IO_ERROR_PENDING);
374   g_error_free (error);
375 }
376
377 static void
378 created_cb (GObject      *source,
379             GAsyncResult *res,
380             gpointer      user_data)
381 {
382   GFileOutputStream *base;
383   CreateDeleteData *data = user_data;
384   GError *error;
385
386   error = NULL;
387   base = g_file_create_finish (G_FILE (source), res, &error);
388   g_assert_no_error (error);
389   g_assert (g_file_query_exists  (data->file, NULL));
390
391   if (data->buffersize == 0)
392     data->ostream = G_OUTPUT_STREAM (g_object_ref (base));
393   else
394     data->ostream = g_buffered_output_stream_new_sized (G_OUTPUT_STREAM (base), data->buffersize);
395   g_object_unref (base);
396
397   g_output_stream_write_async (data->ostream,
398                                data->data,
399                                strlen (data->data),
400                                0,
401                                NULL,
402                                written_cb,
403                                data);
404   /* check that we get a pending error */
405   g_output_stream_write_async (data->ostream,
406                                data->data,
407                                strlen (data->data),
408                                0,
409                                NULL,
410                                opending_cb,
411                                data);
412 }
413
414 static gboolean
415 stop_timeout (gpointer data)
416 {
417   g_assert_not_reached ();
418
419   return FALSE;
420 }
421
422 /*
423  * This test does a fully async create-write-read-delete.
424  * Callbackistan.
425  */
426 static void
427 test_create_delete (gconstpointer d)
428 {
429   GError *error;
430   CreateDeleteData *data;
431   GFileIOStream *iostream;
432
433   data = g_new0 (CreateDeleteData, 1);
434
435   data->buffersize = GPOINTER_TO_INT (d);
436   data->data = "abcdefghijklmnopqrstuvxyzABCDEFGHIJKLMNOPQRSTUVXYZ0123456789";
437   data->pos = 0;
438
439   data->file = g_file_new_tmp ("g_file_create_delete_XXXXXX",
440                                &iostream, NULL);
441   g_assert (data->file != NULL);
442   g_object_unref (iostream);
443
444   data->monitor_path = g_file_get_path (data->file);
445   remove (data->monitor_path);
446
447   g_assert (!g_file_query_exists  (data->file, NULL));
448
449   error = NULL;
450   data->monitor = g_file_monitor_file (data->file, 0, NULL, &error);
451   g_assert_no_error (error);
452
453   /* This test doesn't work with GPollFileMonitor, because it assumes
454    * that the monitor will notice a create immediately followed by a
455    * delete, rather than coalescing them into nothing.
456    */
457   if (!strcmp (G_OBJECT_TYPE_NAME (data->monitor), "GPollFileMonitor"))
458     {
459       g_print ("skipping test for this GFileMonitor implementation");
460       goto skip;
461     }
462
463   g_file_monitor_set_rate_limit (data->monitor, 100);
464
465   g_signal_connect (data->monitor, "changed", G_CALLBACK (monitor_changed), data);
466
467   data->loop = g_main_loop_new (NULL, FALSE);
468
469   data->timeout = g_timeout_add (5000, stop_timeout, NULL);
470
471   g_file_create_async (data->file, 0, 0, NULL, created_cb, data);
472
473   g_main_loop_run (data->loop);
474
475   g_assert_cmpint (data->monitor_created, ==, 1);
476   g_assert_cmpint (data->monitor_deleted, ==, 1);
477   g_assert_cmpint (data->monitor_changed, >, 0);
478
479   g_assert (!g_file_monitor_is_cancelled (data->monitor));
480   g_file_monitor_cancel (data->monitor);
481   g_assert (g_file_monitor_is_cancelled (data->monitor));
482
483   g_main_loop_unref (data->loop);
484   g_object_unref (data->ostream);
485   g_object_unref (data->istream);
486
487  skip:
488   g_object_unref (data->monitor);
489   g_object_unref (data->file);
490   free (data->monitor_path);
491   g_free (data->buffer);
492   g_free (data);
493 }
494
495 static const gchar *replace_data =
496     "/**\n"
497     " * g_file_replace_contents_async:\n"
498     " * @file: input #GFile.\n"
499     " * @contents: string of contents to replace the file with.\n"
500     " * @length: the length of @contents in bytes.\n"
501     " * @etag: (allow-none): a new <link linkend=\"gfile-etag\">entity tag</link> for the @file, or %NULL\n"
502     " * @make_backup: %TRUE if a backup should be created.\n"
503     " * @flags: a set of #GFileCreateFlags.\n"
504     " * @cancellable: optional #GCancellable object, %NULL to ignore.\n"
505     " * @callback: a #GAsyncReadyCallback to call when the request is satisfied\n"
506     " * @user_data: the data to pass to callback function\n"
507     " * \n"
508     " * Starts an asynchronous replacement of @file with the given \n"
509     " * @contents of @length bytes. @etag will replace the document's\n"
510     " * current entity tag.\n"
511     " * \n"
512     " * When this operation has completed, @callback will be called with\n"
513     " * @user_user data, and the operation can be finalized with \n"
514     " * g_file_replace_contents_finish().\n"
515     " * \n"
516     " * If @cancellable is not %NULL, then the operation can be cancelled by\n"
517     " * triggering the cancellable object from another thread. If the operation\n"
518     " * was cancelled, the error %G_IO_ERROR_CANCELLED will be returned. \n"
519     " * \n"
520     " * If @make_backup is %TRUE, this function will attempt to \n"
521     " * make a backup of @file.\n"
522     " **/\n";
523
524 typedef struct
525 {
526   GFile *file;
527   const gchar *data;
528   GMainLoop *loop;
529   gboolean again;
530 } ReplaceLoadData;
531
532 static void replaced_cb (GObject      *source,
533                          GAsyncResult *res,
534                          gpointer      user_data);
535
536 static void
537 loaded_cb (GObject      *source,
538            GAsyncResult *res,
539            gpointer      user_data)
540 {
541   ReplaceLoadData *data = user_data;
542   gboolean ret;
543   GError *error;
544   gchar *contents;
545   gsize length;
546
547   error = NULL;
548   ret = g_file_load_contents_finish (data->file, res, &contents, &length, NULL, &error);
549   g_assert (ret);
550   g_assert_no_error (error);
551   g_assert_cmpint (length, ==, strlen (data->data));
552   g_assert_cmpstr (contents, ==, data->data);
553
554   g_free (contents);
555
556   if (data->again)
557     {
558       data->again = FALSE;
559       data->data = "pi pa po";
560
561       g_file_replace_contents_async (data->file,
562                                      data->data,
563                                      strlen (data->data),
564                                      NULL,
565                                      FALSE,
566                                      0,
567                                      NULL,
568                                      replaced_cb,
569                                      data);
570     }
571   else
572     {
573        error = NULL;
574        ret = g_file_delete (data->file, NULL, &error);
575        g_assert_no_error (error);
576        g_assert (ret);
577        g_assert (!g_file_query_exists (data->file, NULL));
578
579        g_main_loop_quit (data->loop);
580     }
581 }
582
583 static void
584 replaced_cb (GObject      *source,
585              GAsyncResult *res,
586              gpointer      user_data)
587 {
588   ReplaceLoadData *data = user_data;
589   GError *error;
590
591   error = NULL;
592   g_file_replace_contents_finish (data->file, res, NULL, &error);
593   g_assert_no_error (error);
594
595   g_file_load_contents_async (data->file, NULL, loaded_cb, data);
596 }
597
598 static void
599 test_replace_load (void)
600 {
601   ReplaceLoadData *data;
602   gchar *path;
603   GFileIOStream *iostream;
604
605   data = g_new0 (ReplaceLoadData, 1);
606   data->again = TRUE;
607   data->data = replace_data;
608
609   data->file = g_file_new_tmp ("g_file_replace_load_XXXXXX",
610                                &iostream, NULL);
611   g_assert (data->file != NULL);
612   g_object_unref (iostream);
613
614   path = g_file_get_path (data->file);
615   remove (path);
616
617   g_assert (!g_file_query_exists (data->file, NULL));
618
619   data->loop = g_main_loop_new (NULL, FALSE);
620
621   g_file_replace_contents_async (data->file,
622                                  data->data,
623                                  strlen (data->data),
624                                  NULL,
625                                  FALSE,
626                                  0,
627                                  NULL,
628                                  replaced_cb,
629                                  data);
630
631   g_main_loop_run (data->loop);
632
633   g_main_loop_unref (data->loop);
634   g_object_unref (data->file);
635   g_free (data);
636   free (path);
637 }
638
639 static void
640 test_replace_cancel (void)
641 {
642   GFile *tmpdir, *file;
643   GFileOutputStream *ostream;
644   GFileEnumerator *fenum;
645   GFileInfo *info;
646   GCancellable *cancellable;
647   gchar *path;
648   gsize nwrote;
649   GError *error = NULL;
650
651   g_test_bug ("629301");
652
653   path = g_dir_make_tmp ("g_file_replace_cancel_XXXXXX", &error);
654   g_assert_no_error (error);
655   tmpdir = g_file_new_for_path (path);
656   g_free (path);
657
658   file = g_file_get_child (tmpdir, "file");
659   g_file_replace_contents (file,
660                            replace_data,
661                            strlen (replace_data),
662                            NULL, FALSE, 0, NULL,
663                            NULL, &error);
664   g_assert_no_error (error);
665
666   ostream = g_file_replace (file, NULL, TRUE, 0, NULL, &error);
667   g_assert_no_error (error);
668
669   g_output_stream_write_all (G_OUTPUT_STREAM (ostream),
670                              replace_data, strlen (replace_data),
671                              &nwrote, NULL, &error);
672   g_assert_no_error (error);
673   g_assert_cmpint (nwrote, ==, strlen (replace_data));
674
675   /* At this point there should be two files; the original and the
676    * temporary.
677    */
678   fenum = g_file_enumerate_children (tmpdir, NULL, 0, NULL, &error);
679   g_assert_no_error (error);
680
681   info = g_file_enumerator_next_file (fenum, NULL, &error);
682   g_assert_no_error (error);
683   g_assert (info != NULL);
684   g_object_unref (info);
685   info = g_file_enumerator_next_file (fenum, NULL, &error);
686   g_assert_no_error (error);
687   g_assert (info != NULL);
688   g_object_unref (info);
689
690   g_file_enumerator_close (fenum, NULL, &error);
691   g_assert_no_error (error);
692   g_object_unref (fenum);
693
694   /* Make sure the temporary gets deleted even if we cancel. */
695   cancellable = g_cancellable_new ();
696   g_cancellable_cancel (cancellable);
697   g_output_stream_close (G_OUTPUT_STREAM (ostream), cancellable, &error);
698   g_assert_error (error, G_IO_ERROR, G_IO_ERROR_CANCELLED);
699   g_clear_error (&error);
700
701   g_object_unref (cancellable);
702   g_object_unref (ostream);
703
704   g_file_delete (file, NULL, &error);
705   g_assert_no_error (error);
706   g_object_unref (file);
707
708   /* This will only succeed if the temp file was deleted. */
709   g_file_delete (tmpdir, NULL, &error);
710   g_assert_no_error (error);
711   g_object_unref (tmpdir);
712 }
713
714 static void
715 on_file_deleted (GObject      *object,
716                  GAsyncResult *result,
717                  gpointer      user_data)
718 {
719   GError *local_error = NULL;
720   GMainLoop *loop = user_data;
721
722   (void) g_file_delete_finish ((GFile*)object, result, &local_error);
723   g_assert_no_error (local_error);
724
725   g_main_loop_quit (loop);
726 }
727
728 static void
729 test_async_delete (void)
730 {
731   GFile *file;
732   GFileIOStream *iostream;
733   GError *local_error = NULL;
734   GError **error = &local_error;
735   GMainLoop *loop;
736
737   file = g_file_new_tmp ("g_file_delete_XXXXXX",
738                          &iostream, error);
739   g_assert_no_error (local_error);
740   g_object_unref (iostream);
741
742   g_assert (g_file_query_exists (file, NULL));
743
744   loop = g_main_loop_new (NULL, TRUE);
745
746   g_file_delete_async (file, G_PRIORITY_DEFAULT, NULL, on_file_deleted, loop);
747
748   g_main_loop_run (loop);
749
750   g_assert (!g_file_query_exists (file, NULL));
751
752   g_main_loop_unref (loop);
753   g_object_unref (file);
754 }
755
756 #ifdef G_OS_UNIX
757 static void
758 test_copy_preserve_mode (void)
759 {
760   GFile *tmpfile;
761   GFile *dest_tmpfile;
762   GFileInfo *dest_info;
763   GFileIOStream *iostream;
764   GError *local_error = NULL;
765   GError **error = &local_error;
766   guint32 romode = S_IFREG | 0600;
767   guint32 dest_mode;
768
769   tmpfile = g_file_new_tmp ("tmp-copy-preserve-modeXXXXXX",
770                             &iostream, error);
771   g_assert_no_error (local_error);
772   g_io_stream_close ((GIOStream*)iostream, NULL, error);
773   g_assert_no_error (local_error);
774   g_clear_object (&iostream);
775
776   g_file_set_attribute (tmpfile, G_FILE_ATTRIBUTE_UNIX_MODE, G_FILE_ATTRIBUTE_TYPE_UINT32,
777                         &romode, G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
778                         NULL, error);
779   g_assert_no_error (local_error);
780
781   dest_tmpfile = g_file_new_tmp ("tmp-copy-preserve-modeXXXXXX",
782                                  &iostream, error);
783   g_assert_no_error (local_error);
784   g_io_stream_close ((GIOStream*)iostream, NULL, error);
785   g_assert_no_error (local_error);
786   g_clear_object (&iostream);
787
788   g_file_copy (tmpfile, dest_tmpfile, G_FILE_COPY_OVERWRITE | G_FILE_COPY_NOFOLLOW_SYMLINKS | G_FILE_COPY_ALL_METADATA,
789                NULL, NULL, NULL, error);
790   g_assert_no_error (local_error);
791
792   dest_info = g_file_query_info (dest_tmpfile, G_FILE_ATTRIBUTE_UNIX_MODE, G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
793                                  NULL, error);
794   g_assert_no_error (local_error);
795
796   dest_mode = g_file_info_get_attribute_uint32 (dest_info, G_FILE_ATTRIBUTE_UNIX_MODE);
797   
798   g_assert_cmpint (dest_mode, ==, romode);
799
800   (void) g_file_delete (tmpfile, NULL, NULL);
801   (void) g_file_delete (dest_tmpfile, NULL, NULL);
802   
803   g_clear_object (&tmpfile);
804   g_clear_object (&dest_tmpfile);
805   g_clear_object (&dest_info);
806 }
807 #endif
808
809 int
810 main (int argc, char *argv[])
811 {
812   g_test_init (&argc, &argv, NULL);
813
814   g_test_bug_base ("http://bugzilla.gnome.org/");
815
816   g_test_add_func ("/file/basic", test_basic);
817   g_test_add_func ("/file/parent", test_parent);
818   g_test_add_func ("/file/child", test_child);
819   g_test_add_func ("/file/type", test_type);
820   g_test_add_func ("/file/parse-name", test_parse_name);
821   g_test_add_data_func ("/file/async-create-delete/0", GINT_TO_POINTER (0), test_create_delete);
822   g_test_add_data_func ("/file/async-create-delete/1", GINT_TO_POINTER (1), test_create_delete);
823   g_test_add_data_func ("/file/async-create-delete/10", GINT_TO_POINTER (10), test_create_delete);
824   g_test_add_data_func ("/file/async-create-delete/25", GINT_TO_POINTER (25), test_create_delete);
825   g_test_add_data_func ("/file/async-create-delete/4096", GINT_TO_POINTER (4096), test_create_delete);
826   g_test_add_func ("/file/replace-load", test_replace_load);
827   g_test_add_func ("/file/replace-cancel", test_replace_cancel);
828   g_test_add_func ("/file/async-delete", test_async_delete);
829 #ifdef G_OS_UNIX
830   g_test_add_func ("/file/copy-preserve-mode", test_copy_preserve_mode);
831 #endif
832
833   return g_test_run ();
834 }