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
18 free_recorded_event (RecordedEvent
*event
)
21 g_free (event
->other_file
);
28 GFileMonitor
*monitor
;
36 output_event (RecordedEvent
*event
)
39 g_print (">>>> step %d\n", event
->step
);
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
,
49 g_type_class_unref (class);
54 output_events (GList
*list
)
58 g_print (">>>output events\n");
59 for (l
= list
; l
; l
= l
->next
)
60 output_event ((RecordedEvent
*)l
->data
);
64 /* a placeholder for temp file names we don't want to compare */
65 static const gchar DONT_CARE
[] = "";
68 check_expected_event (gint i
,
72 g_assert_cmpint (e1
->step
, ==, e2
->step
);
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
);
86 check_expected_events (RecordedEvent
*expected
,
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
);
105 record_event (TestData
*data
,
108 const gchar
*other_file
,
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
);
119 data
->events
= g_list_append (data
->events
, event
);
123 monitor_changed (GFileMonitor
*monitor
,
126 GFileMonitorEvent event_type
,
129 TestData
*data
= user_data
;
130 gchar
*basename
, *other_base
;
132 basename
= g_file_get_basename (file
);
134 other_base
= g_file_get_basename (other_file
);
138 record_event (data
, event_type
, basename
, other_base
, -1);
145 atomic_replace_step (gpointer user_data
)
147 TestData
*data
= user_data
;
148 GError
*error
= NULL
;
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
);
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
);
163 record_event (data
, -1, NULL
, NULL
, 2);
164 g_file_delete (data
->file
, NULL
, NULL
);
167 record_event (data
, -1, NULL
, NULL
, 3);
168 g_main_loop_quit (data
->loop
);
169 return G_SOURCE_REMOVE
;
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 }
191 test_atomic_replace (void)
193 GError
*error
= 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
);
224 change_step (gpointer user_data
)
226 TestData
*data
= user_data
;
227 GOutputStream
*stream
;
228 GError
*error
= NULL
;
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
);
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
);
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
,
253 G_FILE_QUERY_INFO_NONE
,
256 g_assert_no_error (error
);
259 record_event (data
, -1, NULL
, NULL
, 3);
260 g_file_delete (data
->file
, NULL
, NULL
);
263 record_event (data
, -1, NULL
, NULL
, 4);
264 g_main_loop_quit (data
->loop
);
265 return G_SOURCE_REMOVE
;
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 }
290 test_file_changes (void)
292 GError
*error
= 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
);
323 dir_step (gpointer user_data
)
325 TestData
*data
= user_data
;
326 GFile
*parent
, *file
, *file2
;
327 GError
*error
= NULL
;
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
);
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
);
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
);
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
);
373 record_event (data
, -1, NULL
, NULL
, 5);
374 g_file_delete (data
->file
, NULL
, NULL
);
377 record_event (data
, -1, NULL
, NULL
, 6);
378 g_main_loop_quit (data
->loop
);
379 return G_SOURCE_REMOVE
;
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 }
402 test_dir_monitor (void)
404 GError
*error
= 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
);
436 nodir_step (gpointer user_data
)
438 TestData
*data
= user_data
;
440 GError
*error
= NULL
;
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
);
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
);
457 record_event (data
, -1, NULL
, NULL
, 2);
458 g_file_delete (data
->file
, NULL
, &error
);
459 g_assert_no_error (error
);
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
);
469 record_event (data
, -1, NULL
, NULL
, 4);
470 g_main_loop_quit (data
->loop
);
471 return G_SOURCE_REMOVE
;
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 }
494 test_dir_non_existent (void)
497 GError
*error
= 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
);
528 cross_dir_step (gpointer user_data
)
530 TestData
*data
= user_data
;
532 GError
*error
= NULL
;
534 switch (data
[0].step
)
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
);
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
);
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
);
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
;
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 },
598 test_cross_dir_moves (void)
600 GError
*error
= NULL
;
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]);
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
);
636 g_print ("monitor a:\n");
637 output_events (data
[0].events
);
638 g_print ("monitor b:\n");
639 output_events (data
[1].events
);
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 ();