Add some more cases to the app-id unit tests
[glib.git] / gio / tests / testfilemonitor.c
blob229fd2142ab6c21935da915e68b927fa724e5d30
1 #include <stdlib.h>
2 #include <gio/gio.h>
4 /* These tests were written for the inotify implementation.
5 * Other implementations may require slight adjustments in
6 * the tests, e.g. the length of timeouts
7 */
9 typedef struct
11 gint event_type;
12 gchar *file;
13 gchar *other_file;
14 gint step;
15 } RecordedEvent;
17 static void
18 free_recorded_event (RecordedEvent *event)
20 g_free (event->file);
21 g_free (event->other_file);
22 g_free (event);
25 typedef struct
27 GFile *file;
28 GFileMonitor *monitor;
29 GMainLoop *loop;
30 gint step;
31 GList *events;
32 } TestData;
34 #if 0
35 static void
36 output_event (RecordedEvent *event)
38 if (event->step >= 0)
39 g_print (">>>> step %d\n", event->step);
40 else
42 GTypeClass *class;
44 class = g_type_class_ref (g_type_from_name ("GFileMonitorEvent"));
45 g_print ("%s file=%s other_file=%s\n",
46 g_enum_get_value (G_ENUM_CLASS (class), event->event_type)->value_nick,
47 event->file,
48 event->other_file);
49 g_type_class_unref (class);
53 static void
54 output_events (GList *list)
56 GList *l;
58 g_print (">>>output events\n");
59 for (l = list; l; l = l->next)
60 output_event ((RecordedEvent *)l->data);
62 #endif
64 /* a placeholder for temp file names we don't want to compare */
65 static const gchar DONT_CARE[] = "";
67 static void
68 check_expected_event (gint i,
69 RecordedEvent *e1,
70 RecordedEvent *e2)
72 g_assert_cmpint (e1->step, ==, e2->step);
73 if (e1->step < 0)
74 return;
76 g_assert_cmpint (e1->event_type, ==, e2->event_type);
78 if (e1->file != DONT_CARE)
79 g_assert_cmpstr (e1->file, ==, e2->file);
81 if (e1->other_file != DONT_CARE)
82 g_assert_cmpstr (e1->other_file, ==, e2->other_file);
85 static void
86 check_expected_events (RecordedEvent *expected,
87 gsize n_expected,
88 GList *recorded)
90 gint i;
91 GList *l;
93 g_assert_cmpint (n_expected, ==, g_list_length (recorded));
95 for (i = 0, l = recorded; i < n_expected; i++, l = l->next)
97 RecordedEvent *e1 = &expected[i];
98 RecordedEvent *e2 = (RecordedEvent *)l->data;
100 check_expected_event (i, e1, e2);
104 static void
105 record_event (TestData *data,
106 gint event_type,
107 const gchar *file,
108 const gchar *other_file,
109 gint step)
111 RecordedEvent *event;
113 event = g_new0 (RecordedEvent, 1);
114 event->event_type = event_type;
115 event->file = g_strdup (file);
116 event->other_file = g_strdup (other_file);
117 event->step = step;
119 data->events = g_list_append (data->events, event);
122 static void
123 monitor_changed (GFileMonitor *monitor,
124 GFile *file,
125 GFile *other_file,
126 GFileMonitorEvent event_type,
127 gpointer user_data)
129 TestData *data = user_data;
130 gchar *basename, *other_base;
132 basename = g_file_get_basename (file);
133 if (other_file)
134 other_base = g_file_get_basename (other_file);
135 else
136 other_base = NULL;
138 record_event (data, event_type, basename, other_base, -1);
140 g_free (basename);
141 g_free (other_base);
144 static gboolean
145 atomic_replace_step (gpointer user_data)
147 TestData *data = user_data;
148 GError *error = NULL;
150 switch (data->step)
152 case 0:
153 record_event (data, -1, NULL, NULL, 0);
154 g_file_replace_contents (data->file, "step 0", 6, NULL, FALSE, G_FILE_CREATE_NONE, NULL, NULL, &error);
155 g_assert_no_error (error);
156 break;
157 case 1:
158 record_event (data, -1, NULL, NULL, 1);
159 g_file_replace_contents (data->file, "step 1", 6, NULL, FALSE, G_FILE_CREATE_NONE, NULL, NULL, &error);
160 g_assert_no_error (error);
161 break;
162 case 2:
163 record_event (data, -1, NULL, NULL, 2);
164 g_file_delete (data->file, NULL, NULL);
165 break;
166 case 3:
167 record_event (data, -1, NULL, NULL, 3);
168 g_main_loop_quit (data->loop);
169 return G_SOURCE_REMOVE;
172 data->step++;
174 return G_SOURCE_CONTINUE;
177 /* this is the output we expect from the above steps */
178 static RecordedEvent atomic_replace_output[] = {
179 { -1, NULL, NULL, 0 },
180 { G_FILE_MONITOR_EVENT_CREATED, "atomic_replace_file", NULL, -1 },
181 { G_FILE_MONITOR_EVENT_CHANGED, "atomic_replace_file", NULL, -1 },
182 { G_FILE_MONITOR_EVENT_CHANGES_DONE_HINT, "atomic_replace_file", NULL, -1 },
183 { -1, NULL, NULL, 1 },
184 { G_FILE_MONITOR_EVENT_RENAMED, (gchar*)DONT_CARE, "atomic_replace_file", -1 },
185 { -1, NULL, NULL, 2 },
186 { G_FILE_MONITOR_EVENT_DELETED, "atomic_replace_file", NULL, -1 },
187 { -1, NULL, NULL, 3 }
190 static void
191 test_atomic_replace (void)
193 GError *error = NULL;
194 TestData data;
196 data.step = 0;
197 data.events = NULL;
199 data.file = g_file_new_for_path ("atomic_replace_file");
200 g_file_delete (data.file, NULL, NULL);
202 data.monitor = g_file_monitor_file (data.file, G_FILE_MONITOR_WATCH_MOVES, NULL, &error);
203 g_assert_no_error (error);
205 g_file_monitor_set_rate_limit (data.monitor, 200);
206 g_signal_connect (data.monitor, "changed", G_CALLBACK (monitor_changed), &data);
208 data.loop = g_main_loop_new (NULL, TRUE);
210 g_timeout_add (500, atomic_replace_step, &data);
212 g_main_loop_run (data.loop);
214 /*output_events (data.events);*/
215 check_expected_events (atomic_replace_output, G_N_ELEMENTS (atomic_replace_output), data.events);
217 g_list_free_full (data.events, (GDestroyNotify)free_recorded_event);
218 g_main_loop_unref (data.loop);
219 g_object_unref (data.monitor);
220 g_object_unref (data.file);
223 static gboolean
224 change_step (gpointer user_data)
226 TestData *data = user_data;
227 GOutputStream *stream;
228 GError *error = NULL;
229 guint32 mode = 0660;
231 switch (data->step)
233 case 0:
234 record_event (data, -1, NULL, NULL, 0);
235 g_file_replace_contents (data->file, "step 0", 6, NULL, FALSE, G_FILE_CREATE_NONE, NULL, NULL, &error);
236 g_assert_no_error (error);
237 break;
238 case 1:
239 record_event (data, -1, NULL, NULL, 1);
240 stream = (GOutputStream *)g_file_append_to (data->file, G_FILE_CREATE_NONE, NULL, &error);
241 g_assert_no_error (error);
242 g_output_stream_write_all (stream, " step 1", 7, NULL, NULL, &error);
243 g_assert_no_error (error);
244 g_output_stream_close (stream, NULL, &error);
245 g_assert_no_error (error);
246 break;
247 case 2:
248 record_event (data, -1, NULL, NULL, 2);
249 g_file_set_attribute (data->file,
250 G_FILE_ATTRIBUTE_UNIX_MODE,
251 G_FILE_ATTRIBUTE_TYPE_UINT32,
252 &mode,
253 G_FILE_QUERY_INFO_NONE,
254 NULL,
255 &error);
256 g_assert_no_error (error);
257 break;
258 case 3:
259 record_event (data, -1, NULL, NULL, 3);
260 g_file_delete (data->file, NULL, NULL);
261 break;
262 case 4:
263 record_event (data, -1, NULL, NULL, 4);
264 g_main_loop_quit (data->loop);
265 return G_SOURCE_REMOVE;
268 data->step++;
270 return G_SOURCE_CONTINUE;
273 /* this is the output we expect from the above steps */
274 static RecordedEvent change_output[] = {
275 { -1, NULL, NULL, 0 },
276 { G_FILE_MONITOR_EVENT_CREATED, "change_file", NULL, -1 },
277 { G_FILE_MONITOR_EVENT_CHANGED, "change_file", NULL, -1 },
278 { G_FILE_MONITOR_EVENT_CHANGES_DONE_HINT, "change_file", NULL, -1 },
279 { -1, NULL, NULL, 1 },
280 { G_FILE_MONITOR_EVENT_CHANGED, "change_file", NULL, -1 },
281 { G_FILE_MONITOR_EVENT_CHANGES_DONE_HINT, "change_file", NULL, -1 },
282 { -1, NULL, NULL, 2 },
283 { G_FILE_MONITOR_EVENT_ATTRIBUTE_CHANGED, "change_file", NULL, -1 },
284 { -1, NULL, NULL, 3 },
285 { G_FILE_MONITOR_EVENT_DELETED, "change_file", NULL, -1 },
286 { -1, NULL, NULL, 4 }
289 static void
290 test_file_changes (void)
292 GError *error = NULL;
293 TestData data;
295 data.step = 0;
296 data.events = NULL;
298 data.file = g_file_new_for_path ("change_file");
299 g_file_delete (data.file, NULL, NULL);
301 data.monitor = g_file_monitor_file (data.file, G_FILE_MONITOR_WATCH_MOVES, NULL, &error);
302 g_assert_no_error (error);
304 g_file_monitor_set_rate_limit (data.monitor, 200);
305 g_signal_connect (data.monitor, "changed", G_CALLBACK (monitor_changed), &data);
307 data.loop = g_main_loop_new (NULL, TRUE);
309 g_timeout_add (500, change_step, &data);
311 g_main_loop_run (data.loop);
313 /*output_events (data.events);*/
314 check_expected_events (change_output, G_N_ELEMENTS (change_output), data.events);
316 g_list_free_full (data.events, (GDestroyNotify)free_recorded_event);
317 g_main_loop_unref (data.loop);
318 g_object_unref (data.monitor);
319 g_object_unref (data.file);
322 static gboolean
323 dir_step (gpointer user_data)
325 TestData *data = user_data;
326 GFile *parent, *file, *file2;
327 GError *error = NULL;
329 switch (data->step)
331 case 1:
332 record_event (data, -1, NULL, NULL, 1);
333 parent = g_file_get_parent (data->file);
334 file = g_file_get_child (parent, "dir_test_file");
335 g_file_replace_contents (file, "step 1", 6, NULL, FALSE, G_FILE_CREATE_NONE, NULL, NULL, &error);
336 g_assert_no_error (error);
337 g_object_unref (file);
338 g_object_unref (parent);
339 break;
340 case 2:
341 record_event (data, -1, NULL, NULL, 2);
342 parent = g_file_get_parent (data->file);
343 file = g_file_get_child (parent, "dir_test_file");
344 file2 = g_file_get_child (data->file, "dir_test_file");
345 g_file_move (file, file2, G_FILE_COPY_NONE, NULL, NULL, NULL, &error);
346 g_assert_no_error (error);
347 g_object_unref (file);
348 g_object_unref (file2);
349 g_object_unref (parent);
350 break;
351 case 3:
352 record_event (data, -1, NULL, NULL, 3);
353 file = g_file_get_child (data->file, "dir_test_file");
354 file2 = g_file_get_child (data->file, "dir_test_file2");
355 g_file_move (file, file2, G_FILE_COPY_NONE, NULL, NULL, NULL, &error);
356 g_assert_no_error (error);
357 g_object_unref (file);
358 g_object_unref (file2);
359 break;
360 case 4:
361 record_event (data, -1, NULL, NULL, 4);
362 parent = g_file_get_parent (data->file);
363 file = g_file_get_child (data->file, "dir_test_file2");
364 file2 = g_file_get_child (parent, "dir_test_file2");
365 g_file_move (file, file2, G_FILE_COPY_NONE, NULL, NULL, NULL, &error);
366 g_assert_no_error (error);
367 g_file_delete (file2, NULL, NULL);
368 g_object_unref (file);
369 g_object_unref (file2);
370 g_object_unref (parent);
371 break;
372 case 5:
373 record_event (data, -1, NULL, NULL, 5);
374 g_file_delete (data->file, NULL, NULL);
375 break;
376 case 6:
377 record_event (data, -1, NULL, NULL, 6);
378 g_main_loop_quit (data->loop);
379 return G_SOURCE_REMOVE;
382 data->step++;
384 return G_SOURCE_CONTINUE;
387 /* this is the output we expect from the above steps */
388 static RecordedEvent dir_output[] = {
389 { -1, NULL, NULL, 1 },
390 { -1, NULL, NULL, 2 },
391 { G_FILE_MONITOR_EVENT_MOVED_IN, "dir_test_file", NULL, -1 },
392 { -1, NULL, NULL, 3 },
393 { G_FILE_MONITOR_EVENT_RENAMED, "dir_test_file", "dir_test_file2", -1 },
394 { -1, NULL, NULL, 4 },
395 { G_FILE_MONITOR_EVENT_MOVED_OUT, "dir_test_file2", NULL, -1 },
396 { -1, NULL, NULL, 5 },
397 { G_FILE_MONITOR_EVENT_DELETED, "dir_monitor_test", NULL, -1 },
398 { -1, NULL, NULL, 6 }
401 static void
402 test_dir_monitor (void)
404 GError *error = NULL;
405 TestData data;
407 data.step = 0;
408 data.events = NULL;
410 data.file = g_file_new_for_path ("dir_monitor_test");
411 g_file_delete (data.file, NULL, NULL);
412 g_file_make_directory (data.file, NULL, &error);
414 data.monitor = g_file_monitor_directory (data.file, G_FILE_MONITOR_WATCH_MOVES, NULL, &error);
415 g_assert_no_error (error);
417 g_file_monitor_set_rate_limit (data.monitor, 200);
418 g_signal_connect (data.monitor, "changed", G_CALLBACK (monitor_changed), &data);
420 data.loop = g_main_loop_new (NULL, TRUE);
422 g_timeout_add (500, dir_step, &data);
424 g_main_loop_run (data.loop);
426 /*output_events (data.events);*/
427 check_expected_events (dir_output, G_N_ELEMENTS (dir_output), data.events);
429 g_list_free_full (data.events, (GDestroyNotify)free_recorded_event);
430 g_main_loop_unref (data.loop);
431 g_object_unref (data.monitor);
432 g_object_unref (data.file);
435 static gboolean
436 nodir_step (gpointer user_data)
438 TestData *data = user_data;
439 GFile *parent;
440 GError *error = NULL;
442 switch (data->step)
444 case 0:
445 record_event (data, -1, NULL, NULL, 0);
446 parent = g_file_get_parent (data->file);
447 g_file_make_directory (parent, NULL, &error);
448 g_assert_no_error (error);
449 g_object_unref (parent);
450 break;
451 case 1:
452 record_event (data, -1, NULL, NULL, 1);
453 g_file_replace_contents (data->file, "step 1", 6, NULL, FALSE, G_FILE_CREATE_NONE, NULL, NULL, &error);
454 g_assert_no_error (error);
455 break;
456 case 2:
457 record_event (data, -1, NULL, NULL, 2);
458 g_file_delete (data->file, NULL, &error);
459 g_assert_no_error (error);
460 break;
461 case 3:
462 record_event (data, -1, NULL, NULL, 3);
463 parent = g_file_get_parent (data->file);
464 g_file_delete (parent, NULL, &error);
465 g_assert_no_error (error);
466 g_object_unref (parent);
467 break;
468 case 4:
469 record_event (data, -1, NULL, NULL, 4);
470 g_main_loop_quit (data->loop);
471 return G_SOURCE_REMOVE;
474 data->step++;
476 return G_SOURCE_CONTINUE;
479 static RecordedEvent nodir_output[] = {
480 { -1, NULL, NULL, 0 },
481 { G_FILE_MONITOR_EVENT_CREATED, "nosuchfile", NULL, -1 },
482 { G_FILE_MONITOR_EVENT_CHANGES_DONE_HINT, "nosuchfile", NULL, -1 },
483 { -1, NULL, NULL, 1 },
484 { G_FILE_MONITOR_EVENT_CREATED, "nosuchfile", NULL, -1 },
485 { G_FILE_MONITOR_EVENT_CHANGED, "nosuchfile", NULL, -1 },
486 { G_FILE_MONITOR_EVENT_CHANGES_DONE_HINT, "nosuchfile", NULL, -1 },
487 { -1, NULL, NULL, 2 },
488 { G_FILE_MONITOR_EVENT_DELETED, "nosuchfile", NULL, -1 },
489 { -1, NULL, NULL, 3 },
490 { -1, NULL, NULL, 4 }
493 static void
494 test_dir_non_existent (void)
496 TestData data;
497 GError *error = NULL;
499 data.step = 0;
500 data.events = NULL;
502 data.file = g_file_new_for_path ("nosuchdir/nosuchfile");
503 data.monitor = g_file_monitor_file (data.file, G_FILE_MONITOR_WATCH_MOVES, NULL, &error);
504 g_assert_no_error (error);
506 g_file_monitor_set_rate_limit (data.monitor, 200);
507 g_signal_connect (data.monitor, "changed", G_CALLBACK (monitor_changed), &data);
509 data.loop = g_main_loop_new (NULL, TRUE);
511 /* we need a long timeout here, since the inotify implementation only scans
512 * for missing files every 4 seconds.
514 g_timeout_add (5000, nodir_step, &data);
516 g_main_loop_run (data.loop);
518 /*output_events (data.events);*/
519 check_expected_events (nodir_output, G_N_ELEMENTS (nodir_output), data.events);
521 g_list_free_full (data.events, (GDestroyNotify)free_recorded_event);
522 g_main_loop_unref (data.loop);
523 g_object_unref (data.monitor);
524 g_object_unref (data.file);
527 static gboolean
528 cross_dir_step (gpointer user_data)
530 TestData *data = user_data;
531 GFile *file, *file2;
532 GError *error = NULL;
534 switch (data[0].step)
536 case 0:
537 record_event (&data[0], -1, NULL, NULL, 0);
538 record_event (&data[1], -1, NULL, NULL, 0);
539 file = g_file_get_child (data[1].file, "a");
540 g_file_replace_contents (file, "step 0", 6, NULL, FALSE, G_FILE_CREATE_NONE, NULL, NULL, &error);
541 g_assert_no_error (error);
542 g_object_unref (file);
543 break;
544 case 1:
545 record_event (&data[0], -1, NULL, NULL, 1);
546 record_event (&data[1], -1, NULL, NULL, 1);
547 file = g_file_get_child (data[1].file, "a");
548 file2 = g_file_get_child (data[0].file, "a");
549 g_file_move (file, file2, 0, NULL, NULL, NULL, &error);
550 g_assert_no_error (error);
551 g_object_unref (file);
552 g_object_unref (file2);
553 break;
554 case 2:
555 record_event (&data[0], -1, NULL, NULL, 2);
556 record_event (&data[1], -1, NULL, NULL, 2);
557 file2 = g_file_get_child (data[0].file, "a");
558 g_file_delete (file2, NULL, NULL);
559 g_file_delete (data[0].file, NULL, NULL);
560 g_file_delete (data[1].file, NULL, NULL);
561 g_object_unref (file2);
562 break;
563 case 3:
564 record_event (&data[0], -1, NULL, NULL, 3);
565 record_event (&data[1], -1, NULL, NULL, 3);
566 g_main_loop_quit (data->loop);
567 return G_SOURCE_REMOVE;
570 data->step++;
572 return G_SOURCE_CONTINUE;
575 static RecordedEvent cross_dir_a_output[] = {
576 { -1, NULL, NULL, 0 },
577 { -1, NULL, NULL, 1 },
578 { G_FILE_MONITOR_EVENT_CREATED, "a", NULL, -1 },
579 { G_FILE_MONITOR_EVENT_CHANGES_DONE_HINT, "a", NULL, -1 },
580 { -1, NULL, NULL, 2 },
581 { G_FILE_MONITOR_EVENT_DELETED, "a", NULL, -1 },
582 { G_FILE_MONITOR_EVENT_DELETED, "cross_dir_a", NULL, -1 },
583 { -1, NULL, NULL, 3 },
586 static RecordedEvent cross_dir_b_output[] = {
587 { -1, NULL, NULL, 0 },
588 { G_FILE_MONITOR_EVENT_CREATED, "a", NULL, -1 },
589 { G_FILE_MONITOR_EVENT_CHANGED, "a", NULL, -1 },
590 { G_FILE_MONITOR_EVENT_CHANGES_DONE_HINT, "a", NULL, -1 },
591 { -1, NULL, NULL, 1 },
592 { G_FILE_MONITOR_EVENT_MOVED_OUT, "a", "a", -1 },
593 { -1, NULL, NULL, 2 },
594 { G_FILE_MONITOR_EVENT_DELETED, "cross_dir_b", NULL, -1 },
595 { -1, NULL, NULL, 3 },
597 static void
598 test_cross_dir_moves (void)
600 GError *error = NULL;
601 TestData data[2];
603 data[0].step = 0;
604 data[0].events = NULL;
606 data[0].file = g_file_new_for_path ("cross_dir_a");
607 g_file_delete (data[0].file, NULL, NULL);
608 g_file_make_directory (data[0].file, NULL, &error);
610 data[0].monitor = g_file_monitor_directory (data[0].file, 0, NULL, &error);
611 g_assert_no_error (error);
613 g_file_monitor_set_rate_limit (data[0].monitor, 200);
614 g_signal_connect (data[0].monitor, "changed", G_CALLBACK (monitor_changed), &data[0]);
616 data[1].step = 0;
617 data[1].events = NULL;
619 data[1].file = g_file_new_for_path ("cross_dir_b");
620 g_file_delete (data[1].file, NULL, NULL);
621 g_file_make_directory (data[1].file, NULL, &error);
623 data[1].monitor = g_file_monitor_directory (data[1].file, G_FILE_MONITOR_WATCH_MOVES, NULL, &error);
624 g_assert_no_error (error);
626 g_file_monitor_set_rate_limit (data[1].monitor, 200);
627 g_signal_connect (data[1].monitor, "changed", G_CALLBACK (monitor_changed), &data[1]);
629 data[0].loop = g_main_loop_new (NULL, TRUE);
631 g_timeout_add (500, cross_dir_step, data);
633 g_main_loop_run (data[0].loop);
635 #if 0
636 g_print ("monitor a:\n");
637 output_events (data[0].events);
638 g_print ("monitor b:\n");
639 output_events (data[1].events);
640 #endif
642 check_expected_events (cross_dir_a_output, G_N_ELEMENTS (cross_dir_a_output), data[0].events);
643 check_expected_events (cross_dir_b_output, G_N_ELEMENTS (cross_dir_b_output), data[1].events);
645 g_list_free_full (data[0].events, (GDestroyNotify)free_recorded_event);
646 g_main_loop_unref (data[0].loop);
647 g_object_unref (data[0].monitor);
648 g_object_unref (data[0].file);
650 g_list_free_full (data[1].events, (GDestroyNotify)free_recorded_event);
651 g_object_unref (data[1].monitor);
652 g_object_unref (data[1].file);
656 main (int argc, char *argv[])
658 g_test_init (&argc, &argv, NULL);
660 g_test_add_func ("/monitor/atomic-replace", test_atomic_replace);
661 g_test_add_func ("/monitor/file-changes", test_file_changes);
662 g_test_add_func ("/monitor/dir-monitor", test_dir_monitor);
663 g_test_add_func ("/monitor/dir-not-existent", test_dir_non_existent);
664 g_test_add_func ("/monitor/cross-dir-moves", test_cross_dir_moves);
666 return g_test_run ();