Add some more cases to the app-id unit tests
[glib.git] / gio / tests / file.c
blob7791837911dccde6e2ffb8bc15495fbaa02a6729
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
10 static void
11 test_basic (void)
13 GFile *file;
14 gchar *s;
16 file = g_file_new_for_path ("./some/directory/testfile");
18 s = g_file_get_basename (file);
19 g_assert_cmpstr (s, ==, "testfile");
20 g_free (s);
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);
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);
32 g_object_unref (file);
35 static void
36 test_parent (void)
38 GFile *file;
39 GFile *file2;
40 GFile *parent;
41 GFile *root;
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 ("/");
47 g_assert (g_file_has_parent (file, file2));
49 parent = g_file_get_parent (file);
50 g_assert (g_file_equal (parent, file2));
51 g_object_unref (parent);
53 g_assert (g_file_get_parent (root) == NULL);
55 g_object_unref (file);
56 g_object_unref (file2);
57 g_object_unref (root);
60 static void
61 test_child (void)
63 GFile *file;
64 GFile *child;
65 GFile *child2;
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));
71 child2 = g_file_get_child_for_display_name (file, "child2", NULL);
72 g_assert (g_file_has_parent (child2, file));
74 g_object_unref (child);
75 g_object_unref (child2);
76 g_object_unref (file);
79 static void
80 test_type (void)
82 GFile *datapath_f;
83 GFile *file;
84 GFileType type;
85 GError *error = NULL;
87 datapath_f = g_file_new_for_path (g_test_get_dir (G_TEST_DIST));
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);
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);
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);
103 g_object_unref (datapath_f);
106 static void
107 test_parse_name (void)
109 GFile *file;
110 gchar *name;
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);
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);
125 typedef struct
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;
143 static void
144 monitor_changed (GFileMonitor *monitor,
145 GFile *file,
146 GFile *other_file,
147 GFileMonitorEvent event_type,
148 gpointer user_data)
150 CreateDeleteData *data = user_data;
151 gchar *path;
153 path = g_file_get_path (file);
154 g_assert_cmpstr (data->monitor_path, ==, path);
155 g_free (path);
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++;
166 static gboolean
167 quit_idle (gpointer user_data)
169 CreateDeleteData *data = user_data;
171 g_source_remove (data->timeout);
172 g_main_loop_quit (data->loop);
174 return FALSE;
177 static void
178 iclosed_cb (GObject *source,
179 GAsyncResult *res,
180 gpointer user_data)
182 CreateDeleteData *data = user_data;
183 GError *error;
184 gboolean ret;
186 error = NULL;
187 ret = g_input_stream_close_finish (data->istream, res, &error);
188 g_assert_no_error (error);
189 g_assert (ret);
191 g_assert (g_input_stream_is_closed (data->istream));
193 ret = g_file_delete (data->file, NULL, &error);
194 g_assert (ret);
195 g_assert_no_error (error);
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
201 g_timeout_add (2000, quit_idle, data);
204 static void
205 read_cb (GObject *source,
206 GAsyncResult *res,
207 gpointer user_data)
209 CreateDeleteData *data = user_data;
210 GError *error;
211 gssize size;
213 error = NULL;
214 size = g_input_stream_read_finish (data->istream, res, &error);
215 g_assert_no_error (error);
217 data->pos += size;
218 if (data->pos < strlen (data->data))
220 g_input_stream_read_async (data->istream,
221 data->buffer + data->pos,
222 strlen (data->data) - data->pos,
224 NULL,
225 read_cb,
226 data);
228 else
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);
236 static void
237 ipending_cb (GObject *source,
238 GAsyncResult *res,
239 gpointer user_data)
241 CreateDeleteData *data = user_data;
242 GError *error;
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);
250 static void
251 skipped_cb (GObject *source,
252 GAsyncResult *res,
253 gpointer user_data)
255 CreateDeleteData *data = user_data;
256 GError *error;
257 gssize size;
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);
264 g_input_stream_read_async (data->istream,
265 data->buffer + data->pos,
266 strlen (data->data) - data->pos,
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,
276 NULL,
277 ipending_cb,
278 data);
281 static void
282 opened_cb (GObject *source,
283 GAsyncResult *res,
284 gpointer user_data)
286 GFileInputStream *base;
287 CreateDeleteData *data = user_data;
288 GError *error;
290 error = NULL;
291 base = g_file_read_finish (data->file, res, &error);
292 g_assert_no_error (error);
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);
300 data->buffer = g_new0 (gchar, strlen (data->data) + 1);
302 /* copy initial segment directly, then skip */
303 memcpy (data->buffer, data->data, 10);
304 data->pos = 10;
306 g_input_stream_skip_async (data->istream,
309 NULL,
310 skipped_cb,
311 data);
314 static void
315 oclosed_cb (GObject *source,
316 GAsyncResult *res,
317 gpointer user_data)
319 CreateDeleteData *data = user_data;
320 GError *error;
321 gboolean ret;
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));
329 g_file_read_async (data->file, 0, NULL, opened_cb, data);
332 static void
333 written_cb (GObject *source,
334 GAsyncResult *res,
335 gpointer user_data)
337 CreateDeleteData *data = user_data;
338 gssize size;
339 GError *error;
341 error = NULL;
342 size = g_output_stream_write_finish (data->ostream, res, &error);
343 g_assert_no_error (error);
345 data->pos += size;
346 if (data->pos < strlen (data->data))
348 g_output_stream_write_async (data->ostream,
349 data->data + data->pos,
350 strlen (data->data) - data->pos,
352 NULL,
353 written_cb,
354 data);
356 else
358 g_assert (!g_output_stream_is_closed (data->ostream));
359 g_output_stream_close_async (data->ostream, 0, NULL, oclosed_cb, data);
363 static void
364 opending_cb (GObject *source,
365 GAsyncResult *res,
366 gpointer user_data)
368 CreateDeleteData *data = user_data;
369 GError *error;
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);
377 static void
378 created_cb (GObject *source,
379 GAsyncResult *res,
380 gpointer user_data)
382 GFileOutputStream *base;
383 CreateDeleteData *data = user_data;
384 GError *error;
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));
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);
397 g_output_stream_write_async (data->ostream,
398 data->data,
399 strlen (data->data),
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),
409 NULL,
410 opending_cb,
411 data);
414 static gboolean
415 stop_timeout (gpointer data)
417 g_assert_not_reached ();
419 return FALSE;
423 * This test does a fully async create-write-read-delete.
424 * Callbackistan.
426 static void
427 test_create_delete (gconstpointer d)
429 GError *error;
430 CreateDeleteData *data;
431 GFileIOStream *iostream;
433 data = g_new0 (CreateDeleteData, 1);
435 data->buffersize = GPOINTER_TO_INT (d);
436 data->data = "abcdefghijklmnopqrstuvxyzABCDEFGHIJKLMNOPQRSTUVXYZ0123456789";
437 data->pos = 0;
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);
444 data->monitor_path = g_file_get_path (data->file);
445 remove (data->monitor_path);
447 g_assert (!g_file_query_exists (data->file, NULL));
449 error = NULL;
450 data->monitor = g_file_monitor_file (data->file, 0, NULL, &error);
451 g_assert_no_error (error);
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.
457 if (!strcmp (G_OBJECT_TYPE_NAME (data->monitor), "GPollFileMonitor"))
459 g_test_skip ("skipping test for this GFileMonitor implementation");
460 goto skip;
463 g_file_monitor_set_rate_limit (data->monitor, 100);
465 g_signal_connect (data->monitor, "changed", G_CALLBACK (monitor_changed), data);
467 data->loop = g_main_loop_new (NULL, FALSE);
469 data->timeout = g_timeout_add (5000, stop_timeout, NULL);
471 g_file_create_async (data->file, 0, 0, NULL, created_cb, data);
473 g_main_loop_run (data->loop);
475 g_assert_cmpint (data->monitor_created, ==, 1);
476 g_assert_cmpint (data->monitor_deleted, ==, 1);
477 g_assert_cmpint (data->monitor_changed, >, 0);
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));
483 g_main_loop_unref (data->loop);
484 g_object_unref (data->ostream);
485 g_object_unref (data->istream);
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);
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: (nullable): 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";
524 typedef struct
526 GFile *file;
527 const gchar *data;
528 GMainLoop *loop;
529 gboolean again;
530 } ReplaceLoadData;
532 static void replaced_cb (GObject *source,
533 GAsyncResult *res,
534 gpointer user_data);
536 static void
537 loaded_cb (GObject *source,
538 GAsyncResult *res,
539 gpointer user_data)
541 ReplaceLoadData *data = user_data;
542 gboolean ret;
543 GError *error;
544 gchar *contents;
545 gsize length;
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);
554 g_free (contents);
556 if (data->again)
558 data->again = FALSE;
559 data->data = "pi pa po";
561 g_file_replace_contents_async (data->file,
562 data->data,
563 strlen (data->data),
564 NULL,
565 FALSE,
567 NULL,
568 replaced_cb,
569 data);
571 else
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));
579 g_main_loop_quit (data->loop);
583 static void
584 replaced_cb (GObject *source,
585 GAsyncResult *res,
586 gpointer user_data)
588 ReplaceLoadData *data = user_data;
589 GError *error;
591 error = NULL;
592 g_file_replace_contents_finish (data->file, res, NULL, &error);
593 g_assert_no_error (error);
595 g_file_load_contents_async (data->file, NULL, loaded_cb, data);
598 static void
599 test_replace_load (void)
601 ReplaceLoadData *data;
602 gchar *path;
603 GFileIOStream *iostream;
605 data = g_new0 (ReplaceLoadData, 1);
606 data->again = TRUE;
607 data->data = replace_data;
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);
614 path = g_file_get_path (data->file);
615 remove (path);
617 g_assert (!g_file_query_exists (data->file, NULL));
619 data->loop = g_main_loop_new (NULL, FALSE);
621 g_file_replace_contents_async (data->file,
622 data->data,
623 strlen (data->data),
624 NULL,
625 FALSE,
627 NULL,
628 replaced_cb,
629 data);
631 g_main_loop_run (data->loop);
633 g_main_loop_unref (data->loop);
634 g_object_unref (data->file);
635 g_free (data);
636 free (path);
639 static void
640 test_replace_cancel (void)
642 GFile *tmpdir, *file;
643 GFileOutputStream *ostream;
644 GFileEnumerator *fenum;
645 GFileInfo *info;
646 GCancellable *cancellable;
647 gchar *path;
648 gsize nwrote;
649 guint count;
650 GError *error = NULL;
652 g_test_bug ("629301");
654 path = g_dir_make_tmp ("g_file_replace_cancel_XXXXXX", &error);
655 g_assert_no_error (error);
656 tmpdir = g_file_new_for_path (path);
657 g_free (path);
659 file = g_file_get_child (tmpdir, "file");
660 g_file_replace_contents (file,
661 replace_data,
662 strlen (replace_data),
663 NULL, FALSE, 0, NULL,
664 NULL, &error);
665 g_assert_no_error (error);
667 ostream = g_file_replace (file, NULL, TRUE, 0, NULL, &error);
668 g_assert_no_error (error);
670 g_output_stream_write_all (G_OUTPUT_STREAM (ostream),
671 replace_data, strlen (replace_data),
672 &nwrote, NULL, &error);
673 g_assert_no_error (error);
674 g_assert_cmpint (nwrote, ==, strlen (replace_data));
676 /* At this point there should be two files; the original and the
677 * temporary.
679 fenum = g_file_enumerate_children (tmpdir, NULL, 0, NULL, &error);
680 g_assert_no_error (error);
682 info = g_file_enumerator_next_file (fenum, NULL, &error);
683 g_assert_no_error (error);
684 g_assert (info != NULL);
685 g_object_unref (info);
686 info = g_file_enumerator_next_file (fenum, NULL, &error);
687 g_assert_no_error (error);
688 g_assert (info != NULL);
689 g_object_unref (info);
691 g_file_enumerator_close (fenum, NULL, &error);
692 g_assert_no_error (error);
693 g_object_unref (fenum);
695 /* Also test the g_file_enumerator_iterate() API */
696 fenum = g_file_enumerate_children (tmpdir, NULL, 0, NULL, &error);
697 g_assert_no_error (error);
698 count = 0;
700 while (TRUE)
702 gboolean ret = g_file_enumerator_iterate (fenum, &info, NULL, NULL, &error);
703 g_assert (ret);
704 g_assert_no_error (error);
705 if (!info)
706 break;
707 count++;
709 g_assert_cmpint (count, ==, 2);
711 g_file_enumerator_close (fenum, NULL, &error);
712 g_assert_no_error (error);
713 g_object_unref (fenum);
715 /* Now test just getting child from the g_file_enumerator_iterate() API */
716 fenum = g_file_enumerate_children (tmpdir, "standard::name", 0, NULL, &error);
717 g_assert_no_error (error);
718 count = 0;
720 while (TRUE)
722 GFile *child;
723 gboolean ret = g_file_enumerator_iterate (fenum, NULL, &child, NULL, &error);
725 g_assert (ret);
726 g_assert_no_error (error);
728 if (!child)
729 break;
731 g_assert (G_IS_FILE (child));
732 count++;
734 g_assert_cmpint (count, ==, 2);
736 g_file_enumerator_close (fenum, NULL, &error);
737 g_assert_no_error (error);
738 g_object_unref (fenum);
740 /* Make sure the temporary gets deleted even if we cancel. */
741 cancellable = g_cancellable_new ();
742 g_cancellable_cancel (cancellable);
743 g_output_stream_close (G_OUTPUT_STREAM (ostream), cancellable, &error);
744 g_assert_error (error, G_IO_ERROR, G_IO_ERROR_CANCELLED);
745 g_clear_error (&error);
747 g_object_unref (cancellable);
748 g_object_unref (ostream);
750 g_file_delete (file, NULL, &error);
751 g_assert_no_error (error);
752 g_object_unref (file);
754 /* This will only succeed if the temp file was deleted. */
755 g_file_delete (tmpdir, NULL, &error);
756 g_assert_no_error (error);
757 g_object_unref (tmpdir);
760 static void
761 on_file_deleted (GObject *object,
762 GAsyncResult *result,
763 gpointer user_data)
765 GError *local_error = NULL;
766 GMainLoop *loop = user_data;
768 (void) g_file_delete_finish ((GFile*)object, result, &local_error);
769 g_assert_no_error (local_error);
771 g_main_loop_quit (loop);
774 static void
775 test_async_delete (void)
777 GFile *file;
778 GFileIOStream *iostream;
779 GError *local_error = NULL;
780 GError **error = &local_error;
781 GMainLoop *loop;
783 file = g_file_new_tmp ("g_file_delete_XXXXXX",
784 &iostream, error);
785 g_assert_no_error (local_error);
786 g_object_unref (iostream);
788 g_assert (g_file_query_exists (file, NULL));
790 loop = g_main_loop_new (NULL, TRUE);
792 g_file_delete_async (file, G_PRIORITY_DEFAULT, NULL, on_file_deleted, loop);
794 g_main_loop_run (loop);
796 g_assert (!g_file_query_exists (file, NULL));
798 g_main_loop_unref (loop);
799 g_object_unref (file);
802 #ifdef G_OS_UNIX
803 static void
804 test_copy_preserve_mode (void)
806 GFile *tmpfile;
807 GFile *dest_tmpfile;
808 GFileInfo *dest_info;
809 GFileIOStream *iostream;
810 GError *local_error = NULL;
811 GError **error = &local_error;
812 guint32 romode = S_IFREG | 0600;
813 guint32 dest_mode;
815 tmpfile = g_file_new_tmp ("tmp-copy-preserve-modeXXXXXX",
816 &iostream, error);
817 g_assert_no_error (local_error);
818 g_io_stream_close ((GIOStream*)iostream, NULL, error);
819 g_assert_no_error (local_error);
820 g_clear_object (&iostream);
822 g_file_set_attribute (tmpfile, G_FILE_ATTRIBUTE_UNIX_MODE, G_FILE_ATTRIBUTE_TYPE_UINT32,
823 &romode, G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
824 NULL, error);
825 g_assert_no_error (local_error);
827 dest_tmpfile = g_file_new_tmp ("tmp-copy-preserve-modeXXXXXX",
828 &iostream, error);
829 g_assert_no_error (local_error);
830 g_io_stream_close ((GIOStream*)iostream, NULL, error);
831 g_assert_no_error (local_error);
832 g_clear_object (&iostream);
834 g_file_copy (tmpfile, dest_tmpfile, G_FILE_COPY_OVERWRITE | G_FILE_COPY_NOFOLLOW_SYMLINKS | G_FILE_COPY_ALL_METADATA,
835 NULL, NULL, NULL, error);
836 g_assert_no_error (local_error);
838 dest_info = g_file_query_info (dest_tmpfile, G_FILE_ATTRIBUTE_UNIX_MODE, G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
839 NULL, error);
840 g_assert_no_error (local_error);
842 dest_mode = g_file_info_get_attribute_uint32 (dest_info, G_FILE_ATTRIBUTE_UNIX_MODE);
844 g_assert_cmpint (dest_mode, ==, romode);
846 (void) g_file_delete (tmpfile, NULL, NULL);
847 (void) g_file_delete (dest_tmpfile, NULL, NULL);
849 g_clear_object (&tmpfile);
850 g_clear_object (&dest_tmpfile);
851 g_clear_object (&dest_info);
853 #endif
855 static gchar *
856 splice_to_string (GInputStream *stream,
857 GError **error)
859 GMemoryOutputStream *buffer = NULL;
860 char *ret = NULL;
862 buffer = (GMemoryOutputStream*)g_memory_output_stream_new (NULL, 0, g_realloc, g_free);
863 if (g_output_stream_splice ((GOutputStream*)buffer, stream, 0, NULL, error) < 0)
864 goto out;
866 if (!g_output_stream_write ((GOutputStream*)buffer, "\0", 1, NULL, error))
867 goto out;
869 if (!g_output_stream_close ((GOutputStream*)buffer, NULL, error))
870 goto out;
872 ret = g_memory_output_stream_steal_data (buffer);
873 out:
874 g_clear_object (&buffer);
875 return ret;
878 static guint64
879 get_size_from_du (const gchar *path)
881 GSubprocess *du;
882 gchar *result;
883 gchar *endptr;
884 guint64 size;
885 GError *error = NULL;
887 du = g_subprocess_new (G_SUBPROCESS_FLAGS_STDOUT_PIPE,
888 &error,
889 "du", "--bytes", "-s", path, NULL);
890 g_assert_no_error (error);
892 result = splice_to_string (g_subprocess_get_stdout_pipe (du), &error);
893 g_assert_no_error (error);
895 size = g_ascii_strtoll (result, &endptr, 10);
897 g_object_unref (du);
898 g_free (result);
900 return size;
903 static void
904 test_measure (void)
906 GFile *file;
907 guint64 size;
908 guint64 num_bytes;
909 guint64 num_dirs;
910 guint64 num_files;
911 GError *error = NULL;
912 gboolean ok;
913 gchar *path;
915 path = g_test_build_filename (G_TEST_DIST, "desktop-files", NULL);
916 file = g_file_new_for_path (path);
918 if (g_find_program_in_path ("du"))
920 size = get_size_from_du (path);
922 else
924 g_test_message ("du not found, skipping byte measurement");
925 size = 0;
928 ok = g_file_measure_disk_usage (file,
929 G_FILE_MEASURE_APPARENT_SIZE,
930 NULL,
931 NULL,
932 NULL,
933 &num_bytes,
934 &num_dirs,
935 &num_files,
936 &error);
937 g_assert (ok);
938 g_assert_no_error (error);
940 if (size > 0)
941 g_assert_cmpuint (num_bytes, ==, size);
942 g_assert_cmpuint (num_dirs, ==, 6);
943 g_assert_cmpuint (num_files, ==, 30);
945 g_object_unref (file);
946 g_free (path);
949 typedef struct {
950 guint64 expected_bytes;
951 guint64 expected_dirs;
952 guint64 expected_files;
953 gint progress_count;
954 guint64 progress_bytes;
955 guint64 progress_dirs;
956 guint64 progress_files;
957 } MeasureData;
959 static void
960 measure_progress (gboolean reporting,
961 guint64 current_size,
962 guint64 num_dirs,
963 guint64 num_files,
964 gpointer user_data)
966 MeasureData *data = user_data;
968 data->progress_count += 1;
970 g_assert_cmpuint (current_size, >=, data->progress_bytes);
971 g_assert_cmpuint (num_dirs, >=, data->progress_dirs);
972 g_assert_cmpuint (num_files, >=, data->progress_files);
974 data->progress_bytes = current_size;
975 data->progress_dirs = num_dirs;
976 data->progress_files = num_files;
979 static void
980 measure_done (GObject *source,
981 GAsyncResult *res,
982 gpointer user_data)
984 MeasureData *data = user_data;
985 guint64 num_bytes, num_dirs, num_files;
986 GError *error = NULL;
987 gboolean ok;
989 ok = g_file_measure_disk_usage_finish (G_FILE (source), res, &num_bytes, &num_dirs, &num_files, &error);
990 g_assert (ok);
991 g_assert_no_error (error);
993 if (data->expected_bytes > 0)
994 g_assert_cmpuint (data->expected_bytes, ==, num_bytes);
995 g_assert_cmpuint (data->expected_dirs, ==, num_dirs);
996 g_assert_cmpuint (data->expected_files, ==, num_files);
998 g_assert_cmpuint (data->progress_count, >, 0);
999 g_assert_cmpuint (num_bytes, >=, data->progress_bytes);
1000 g_assert_cmpuint (num_dirs, >=, data->progress_dirs);
1001 g_assert_cmpuint (num_files, >=, data->progress_files);
1003 g_free (data);
1004 g_object_unref (source);
1007 static void
1008 test_measure_async (void)
1010 gchar *path;
1011 GFile *file;
1012 MeasureData *data;
1014 data = g_new (MeasureData, 1);
1016 data->progress_count = 0;
1017 data->progress_bytes = 0;
1018 data->progress_files = 0;
1019 data->progress_dirs = 0;
1021 path = g_test_build_filename (G_TEST_DIST, "desktop-files", NULL);
1022 file = g_file_new_for_path (path);
1024 if (g_find_program_in_path ("du"))
1026 data->expected_bytes = get_size_from_du (path);
1028 else
1030 g_test_message ("du not found, skipping byte measurement");
1031 data->expected_bytes = 0;
1034 g_free (path);
1036 data->expected_dirs = 6;
1037 data->expected_files = 30;
1039 g_file_measure_disk_usage_async (file,
1040 G_FILE_MEASURE_APPARENT_SIZE,
1041 0, NULL,
1042 measure_progress, data,
1043 measure_done, data);
1047 main (int argc, char *argv[])
1049 g_test_init (&argc, &argv, NULL);
1051 g_test_bug_base ("http://bugzilla.gnome.org/");
1053 g_test_add_func ("/file/basic", test_basic);
1054 g_test_add_func ("/file/parent", test_parent);
1055 g_test_add_func ("/file/child", test_child);
1056 g_test_add_func ("/file/type", test_type);
1057 g_test_add_func ("/file/parse-name", test_parse_name);
1058 g_test_add_data_func ("/file/async-create-delete/0", GINT_TO_POINTER (0), test_create_delete);
1059 g_test_add_data_func ("/file/async-create-delete/1", GINT_TO_POINTER (1), test_create_delete);
1060 g_test_add_data_func ("/file/async-create-delete/10", GINT_TO_POINTER (10), test_create_delete);
1061 g_test_add_data_func ("/file/async-create-delete/25", GINT_TO_POINTER (25), test_create_delete);
1062 g_test_add_data_func ("/file/async-create-delete/4096", GINT_TO_POINTER (4096), test_create_delete);
1063 g_test_add_func ("/file/replace-load", test_replace_load);
1064 g_test_add_func ("/file/replace-cancel", test_replace_cancel);
1065 g_test_add_func ("/file/async-delete", test_async_delete);
1066 #ifdef G_OS_UNIX
1067 g_test_add_func ("/file/copy-preserve-mode", test_copy_preserve_mode);
1068 #endif
1069 g_test_add_func ("/file/measure", test_measure);
1070 g_test_add_func ("/file/measure-async", test_measure_async);
1072 return g_test_run ();