Add an async file create/write/read/delete test
[platform/upstream/glib.git] / gio / tests / file.c
1 #include <string.h>
2 #include <gio/gio.h>
3 #include <gio/gfiledescriptorbased.h>
4
5 static void
6 test_basic (void)
7 {
8   GFile *file;
9   gchar *s;
10
11   file = g_file_new_for_path ("./some/directory/testfile");
12
13   s = g_file_get_basename (file);
14   g_assert_cmpstr (s, ==, "testfile");
15   g_free (s);
16
17   s = g_file_get_uri (file);
18   g_assert (g_str_has_prefix (s, "file://"));
19   g_assert (g_str_has_suffix (s, "/some/directory/testfile"));
20   g_free (s);
21
22   g_assert (g_file_has_uri_scheme (file, "file"));
23   s = g_file_get_uri_scheme (file);
24   g_assert_cmpstr (s, ==, "file");
25   g_free (s);
26
27   g_object_unref (file);
28 }
29
30 static void
31 test_parent (void)
32 {
33   GFile *file;
34   GFile *file2;
35   GFile *parent;
36   GFile *root;
37
38   file = g_file_new_for_path ("./some/directory/testfile");
39   file2 = g_file_new_for_path ("./some/directory");
40   root = g_file_new_for_path ("/");
41
42   g_assert (g_file_has_parent (file, file2));
43
44   parent = g_file_get_parent (file);
45   g_assert (g_file_equal (parent, file2));
46   g_object_unref (parent);
47
48   g_assert (g_file_get_parent (root) == NULL);
49
50   g_object_unref (file);
51   g_object_unref (file2);
52   g_object_unref (root);
53 }
54
55 static void
56 test_child (void)
57 {
58   GFile *file;
59   GFile *child;
60   GFile *child2;
61
62   file = g_file_new_for_path ("./some/directory");
63   child = g_file_get_child (file, "child");
64   g_assert (g_file_has_parent (child, file));
65
66   child2 = g_file_get_child_for_display_name (file, "child2", NULL);
67   g_assert (g_file_has_parent (child2, file));
68
69   g_object_unref (child);
70   g_object_unref (child2);
71   g_object_unref (file);
72 }
73
74 static void
75 test_type (void)
76 {
77   GFile *file;
78   GFileType type;
79
80   file = g_file_new_for_path (SRCDIR "/file.c");
81   type = g_file_query_file_type (file, 0, NULL);
82   g_assert_cmpint (type, ==, G_FILE_TYPE_REGULAR);
83   g_object_unref (file);
84
85   file = g_file_new_for_path (SRCDIR "/schema-tests");
86   type = g_file_query_file_type (file, 0, NULL);
87   g_assert_cmpint (type, ==, G_FILE_TYPE_DIRECTORY);
88   g_object_unref (file);
89 }
90
91
92 typedef struct
93 {
94   GFile *file;
95   GFileMonitor *monitor;
96   GOutputStream *ostream;
97   GInputStream *istream;
98   GMainLoop *loop;
99   gint buffersize;
100   gint monitor_created;
101   gint monitor_deleted;
102   gint monitor_changed;
103   gchar *monitor_path;
104   gint pos;
105   gchar *data;
106   gchar *buffer;
107   guint timeout;
108 } CreateDeleteData;
109
110 static void
111 monitor_changed (GFileMonitor      *monitor,
112                  GFile             *file,
113                  GFile             *other_file,
114                  GFileMonitorEvent  event_type,
115                  gpointer           user_data)
116 {
117   CreateDeleteData *data = user_data;
118
119   g_assert_cmpstr (data->monitor_path, ==, g_file_get_path (file));
120
121   if (event_type == G_FILE_MONITOR_EVENT_CREATED)
122     data->monitor_created++;
123   if (event_type == G_FILE_MONITOR_EVENT_DELETED)
124     data->monitor_deleted++;
125   if (event_type == G_FILE_MONITOR_EVENT_CHANGED)
126     data->monitor_changed++;
127 }
128
129
130 static gboolean
131 quit_idle (gpointer user_data)
132 {
133   CreateDeleteData *data = user_data;
134
135   g_source_remove (data->timeout); 
136   g_main_loop_quit (data->loop);
137
138   return FALSE;
139 }
140
141 static void
142 iclosed_cb (GObject      *source,
143             GAsyncResult *res,
144             gpointer      user_data)
145 {
146   CreateDeleteData *data = user_data;
147   GError *error;
148   gboolean ret;
149
150   error = NULL;
151   ret = g_input_stream_close_finish (data->istream, res, &error);
152   g_assert_no_error (error);
153   g_assert (ret);
154
155   g_assert (g_input_stream_is_closed (data->istream));
156
157   ret = g_file_delete (data->file, NULL, &error);
158   g_assert (ret);
159   g_assert_no_error (error);
160
161   /* work around file monitor bug:
162    * inotify events are only processed every 1000 ms, regardless
163    * of the rate limit set on the file monitor
164    */
165   g_timeout_add (2000, quit_idle, data);
166 }
167
168 static void
169 read_cb (GObject      *source,
170          GAsyncResult *res,
171          gpointer      user_data)
172 {
173   CreateDeleteData *data = user_data;
174   GError *error;
175   gssize size;
176
177   error = NULL;
178   size = g_input_stream_read_finish (data->istream, res, &error);
179   g_assert_no_error (error);
180
181   data->pos += size;
182   if (data->pos < strlen (data->data))
183     {
184       g_input_stream_read_async (data->istream,
185                                  data->buffer + data->pos,
186                                  strlen (data->data) - data->pos,
187                                  0,
188                                  NULL,
189                                  read_cb,
190                                  data);
191     }
192   else
193     {
194       g_assert_cmpstr (data->buffer, ==, data->data);
195       g_assert (!g_input_stream_is_closed (data->istream));
196       g_input_stream_close_async (data->istream, 0, NULL, iclosed_cb, data);
197     }
198 }
199
200 static void
201 ipending_cb (GObject      *source,
202              GAsyncResult *res,
203              gpointer      user_data)
204 {
205   CreateDeleteData *data = user_data;
206   GError *error;
207   gssize size;
208
209   error = NULL;
210   size = g_input_stream_read_finish (data->istream, res, &error);
211   g_assert_error (error, G_IO_ERROR, G_IO_ERROR_PENDING);
212   g_error_free (error);
213 }
214
215 static void
216 skipped_cb (GObject      *source,
217             GAsyncResult *res,
218             gpointer      user_data)
219 {
220   CreateDeleteData *data = user_data;
221   GError *error;
222   gssize size;
223
224   error = NULL;
225   size = g_input_stream_skip_finish (data->istream, res, &error);
226   g_assert_no_error (error);
227   g_assert_cmpint (size, ==, data->pos);
228
229   g_input_stream_read_async (data->istream,
230                              data->buffer + data->pos,
231                              strlen (data->data) - data->pos,
232                              0,
233                              NULL,
234                              read_cb,
235                              data);
236   /* check that we get a pending error */
237   g_input_stream_read_async (data->istream,
238                              data->buffer + data->pos,
239                              strlen (data->data) - data->pos,
240                              0,
241                              NULL,
242                              ipending_cb,
243                              data);
244 }
245
246 static void
247 opened_cb (GObject      *source,
248            GAsyncResult *res,
249            gpointer      user_data)
250 {
251   GFileInputStream *base;
252   CreateDeleteData *data = user_data;
253   GError *error;
254
255   error = NULL;
256   base = g_file_read_finish (data->file, res, &error);
257   g_assert_no_error (error);
258
259   if (data->buffersize == 0)
260     data->istream = G_INPUT_STREAM (g_object_ref (base));
261   else
262     data->istream = g_buffered_input_stream_new_sized (G_INPUT_STREAM (base), data->buffersize);
263   g_object_unref (base);
264
265   data->buffer = g_new0 (gchar, strlen (data->data) + 1);
266
267   /* copy initial segment directly, then skip */
268   memcpy (data->buffer, data->data, 10);
269   data->pos = 10;
270
271   g_input_stream_skip_async (data->istream,
272                              10,
273                              0,
274                              NULL,
275                              skipped_cb,
276                              data);
277 }
278
279 static void
280 oclosed_cb (GObject      *source,
281             GAsyncResult *res,
282             gpointer      user_data)
283 {
284   CreateDeleteData *data = user_data;
285   GError *error;
286   gboolean ret;
287
288   error = NULL;
289   ret = g_output_stream_close_finish (data->ostream, res, &error);
290   g_assert_no_error (error);
291   g_assert (ret);
292   g_assert (g_output_stream_is_closed (data->ostream));
293
294   g_file_read_async (data->file, 0, NULL, opened_cb, data);
295 }
296
297 static void
298 written_cb (GObject      *source,
299             GAsyncResult *res,
300             gpointer      user_data)
301 {
302   CreateDeleteData *data = user_data;
303   gssize size;
304   GError *error;
305
306   error = NULL;
307   size = g_output_stream_write_finish (data->ostream, res, &error);
308   g_assert_no_error (error);
309
310   data->pos += size;
311   if (data->pos < strlen (data->data))
312     {
313       g_output_stream_write_async (data->ostream,
314                                    data->data + data->pos,
315                                    strlen (data->data) - data->pos,
316                                    0,
317                                    NULL,
318                                    written_cb,
319                                    data);
320     }
321   else
322     {
323       g_assert (!g_output_stream_is_closed (data->ostream));
324       g_output_stream_close_async (data->ostream, 0, NULL, oclosed_cb, data);
325     }
326 }
327
328 static void
329 opending_cb (GObject      *source,
330              GAsyncResult *res,
331              gpointer      user_data)
332 {
333   CreateDeleteData *data = user_data;
334   GError *error;
335   gssize size;
336
337   error = NULL;
338   size = g_output_stream_write_finish (data->ostream, res, &error);
339   g_assert_error (error, G_IO_ERROR, G_IO_ERROR_PENDING);
340   g_error_free (error);
341 }
342
343 static void
344 created_cb (GObject      *source,
345             GAsyncResult *res,
346             gpointer      user_data)
347 {
348   GFileOutputStream *base;
349   CreateDeleteData *data = user_data;
350   GError *error;
351
352   error = NULL;
353   base = g_file_create_finish (G_FILE (source), res, &error);
354   g_assert_no_error (error);
355   g_assert (g_file_query_exists  (data->file, NULL));
356
357   if (data->buffersize == 0)
358     data->ostream = G_OUTPUT_STREAM (g_object_ref (base));
359   else
360     data->ostream = g_buffered_output_stream_new_sized (G_OUTPUT_STREAM (base), data->buffersize);
361   g_object_unref (base);
362
363   g_output_stream_write_async (data->ostream,
364                                data->data,
365                                strlen (data->data),
366                                0,
367                                NULL,
368                                written_cb,
369                                data);
370   /* check that we get a pending error */
371   g_output_stream_write_async (data->ostream,
372                                data->data,
373                                strlen (data->data),
374                                0,
375                                NULL,
376                                opending_cb,
377                                data);
378 }
379
380 static gboolean
381 stop_timeout (gpointer data)
382 {
383   g_assert_not_reached ();
384
385   return FALSE;
386 }
387
388 /*
389  * This test does a fully async create-write-read-delete.
390  * Callbackistan.
391  */
392 static void
393 test_create_delete (gconstpointer d)
394 {
395   gint fd;
396   GError *error;
397   CreateDeleteData *data;
398
399   data = g_new0 (CreateDeleteData, 1);
400
401   data->buffersize = GPOINTER_TO_INT (d);
402   data->data = "abcdefghijklmnopqrstuvxyzABCDEFGHIJKLMNOPQRSTUVXYZ0123456789";
403   data->pos = 0;
404
405   error = NULL;
406   fd = g_file_open_tmp ("g_file_create_delete_XXXXXX", &data->monitor_path, &error);
407   g_assert_no_error (error);
408   unlink (data->monitor_path);
409   close (fd);
410
411   data->file = g_file_new_for_path (data->monitor_path);
412   g_assert (!g_file_query_exists  (data->file, NULL));
413
414   data->monitor = g_file_monitor_file (data->file, 0, NULL, &error);
415   g_file_monitor_set_rate_limit (data->monitor, 100);
416   g_assert_no_error (error);
417
418   g_signal_connect (data->monitor, "changed", G_CALLBACK (monitor_changed), data);
419
420   data->loop = g_main_loop_new (NULL, FALSE);
421
422   data->timeout = g_timeout_add (5000, stop_timeout, NULL);
423
424   g_file_create_async (data->file, 0, 0, NULL, created_cb, data);
425
426   g_main_loop_run (data->loop);
427
428   g_assert_cmpint (data->monitor_created, ==, 1);
429   g_assert_cmpint (data->monitor_deleted, ==, 1);
430   g_assert_cmpint (data->monitor_changed, >, 0);
431
432   g_assert (!g_file_monitor_is_cancelled (data->monitor));
433   g_file_monitor_cancel (data->monitor);
434   g_assert (g_file_monitor_is_cancelled (data->monitor));
435
436   g_main_loop_unref (data->loop);
437   g_object_unref (data->monitor);
438   g_object_unref (data->ostream);
439   g_object_unref (data->istream);
440   g_object_unref (data->file);
441   g_free (data->monitor_path);
442   g_free (data->buffer);
443   g_free (data);
444 }
445
446 int
447 main (int argc, char *argv[])
448 {
449   g_type_init ();
450
451   g_test_init (&argc, &argv, NULL);
452
453   g_test_add_func ("/file/basic", test_basic);
454   g_test_add_func ("/file/parent", test_parent);
455   g_test_add_func ("/file/child", test_child);
456   g_test_add_func ("/file/type", test_type);
457   g_test_add_data_func ("/file/async-create-delete/0", GINT_TO_POINTER (0), test_create_delete);
458   g_test_add_data_func ("/file/async-create-delete/1", GINT_TO_POINTER (1), test_create_delete);
459   g_test_add_data_func ("/file/async-create-delete/10", GINT_TO_POINTER (10), test_create_delete);
460   g_test_add_data_func ("/file/async-create-delete/25", GINT_TO_POINTER (25), test_create_delete);
461   g_test_add_data_func ("/file/async-create-delete/4096", GINT_TO_POINTER (4096), test_create_delete);
462
463   return g_test_run ();
464 }