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