mirror of
https://gitlab.gnome.org/GNOME/glib.git
synced 2025-08-03 16:03:40 +02:00
Add some file monitoring tests
Add a new test which checks that atomically replacing a file that is being monitored by GFileMonitor produced the expected events. The test can easily be expanded to cover other file monitoring scenarios.
This commit is contained in:
@@ -64,6 +64,7 @@ test_programs = \
|
||||
vfs \
|
||||
volumemonitor \
|
||||
glistmodel \
|
||||
testfilemonitor \
|
||||
$(NULL)
|
||||
|
||||
uninstalled_test_programs = \
|
||||
|
226
gio/tests/testfilemonitor.c
Normal file
226
gio/tests/testfilemonitor.c
Normal file
@@ -0,0 +1,226 @@
|
||||
#include <stdlib.h>
|
||||
#include <gio/gio.h>
|
||||
|
||||
typedef struct
|
||||
{
|
||||
gint event_type;
|
||||
gchar *file;
|
||||
gchar *other_file;
|
||||
gint step;
|
||||
} RecordedEvent;
|
||||
|
||||
static void
|
||||
free_recorded_event (RecordedEvent *event)
|
||||
{
|
||||
g_free (event->file);
|
||||
g_free (event->other_file);
|
||||
g_free (event);
|
||||
}
|
||||
|
||||
typedef struct
|
||||
{
|
||||
GFile *file;
|
||||
GFileMonitor *monitor;
|
||||
GMainLoop *loop;
|
||||
gint step;
|
||||
GList *events;
|
||||
GString *output;
|
||||
} TestData;
|
||||
|
||||
#if 0
|
||||
static void
|
||||
output_event (RecordedEvent *event)
|
||||
{
|
||||
if (event->step >= 0)
|
||||
g_print (">>>> step %d\n", event->step);
|
||||
else
|
||||
{
|
||||
GTypeClass *class;
|
||||
|
||||
class = g_type_class_ref (g_type_from_name ("GFileMonitorEvent"));
|
||||
g_print ("%s file=%s other_file=%s\n",
|
||||
g_enum_get_value (G_ENUM_CLASS (class), event->event_type)->value_nick,
|
||||
event->file,
|
||||
event->other_file);
|
||||
g_type_class_unref (class);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
output_events (GList *list)
|
||||
{
|
||||
GList *l;
|
||||
|
||||
g_print (">>>output events\n");
|
||||
for (l = list; l; l = l->next)
|
||||
output_event ((RecordedEvent *)l->data);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* a placeholder for temp file names we don't want to compare */
|
||||
static const gchar DONT_CARE[] = "";
|
||||
|
||||
static void
|
||||
check_expected_event (gint i,
|
||||
RecordedEvent *e1,
|
||||
RecordedEvent *e2)
|
||||
{
|
||||
g_assert_cmpint (e1->step, ==, e2->step);
|
||||
if (e1->step < 0)
|
||||
return;
|
||||
|
||||
g_assert_cmpint (e1->event_type, ==, e2->event_type);
|
||||
|
||||
if (e1->file != DONT_CARE)
|
||||
g_assert_cmpstr (e1->file, ==, e2->file);
|
||||
|
||||
if (e1->other_file != DONT_CARE)
|
||||
g_assert_cmpstr (e1->other_file, ==, e2->other_file);
|
||||
}
|
||||
|
||||
static void
|
||||
check_expected_events (RecordedEvent *expected,
|
||||
gsize n_expected,
|
||||
GList *recorded)
|
||||
{
|
||||
gint i;
|
||||
GList *l;
|
||||
|
||||
g_assert_cmpint (n_expected, ==, g_list_length (recorded));
|
||||
|
||||
for (i = 0, l = recorded; i < n_expected; i++, l = l->next)
|
||||
{
|
||||
RecordedEvent *e1 = &expected[i];
|
||||
RecordedEvent *e2 = (RecordedEvent *)l->data;
|
||||
|
||||
check_expected_event (i, e1, e2);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
record_event (TestData *data,
|
||||
gint event_type,
|
||||
const gchar *file,
|
||||
const gchar *other_file,
|
||||
gint step)
|
||||
{
|
||||
RecordedEvent *event;
|
||||
|
||||
event = g_new0 (RecordedEvent, 1);
|
||||
event->event_type = event_type;
|
||||
event->file = g_strdup (file);
|
||||
event->other_file = g_strdup (other_file);
|
||||
event->step = step;
|
||||
|
||||
data->events = g_list_append (data->events, event);
|
||||
}
|
||||
|
||||
static void
|
||||
monitor_changed (GFileMonitor *monitor,
|
||||
GFile *file,
|
||||
GFile *other_file,
|
||||
GFileMonitorEvent event_type,
|
||||
gpointer user_data)
|
||||
{
|
||||
TestData *data = user_data;
|
||||
gchar *basename, *other_base;
|
||||
|
||||
basename = g_file_get_basename (file);
|
||||
if (other_file)
|
||||
other_base = g_file_get_basename (other_file);
|
||||
else
|
||||
other_base = NULL;
|
||||
|
||||
record_event (data, event_type, basename, other_base, -1);
|
||||
|
||||
g_free (basename);
|
||||
g_free (other_base);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
atomic_replace_step (gpointer user_data)
|
||||
{
|
||||
TestData *data = user_data;
|
||||
GError *error = NULL;
|
||||
|
||||
switch (data->step)
|
||||
{
|
||||
case 0:
|
||||
record_event (data, -1, NULL, NULL, 0);
|
||||
g_file_replace_contents (data->file, "step 0", 6, NULL, FALSE, G_FILE_CREATE_NONE, NULL, NULL, &error);
|
||||
g_assert_no_error (error);
|
||||
break;
|
||||
case 1:
|
||||
record_event (data, -1, NULL, NULL, 1);
|
||||
g_file_replace_contents (data->file, "step 1", 6, NULL, FALSE, G_FILE_CREATE_NONE, NULL, NULL, &error);
|
||||
g_assert_no_error (error);
|
||||
break;
|
||||
case 2:
|
||||
record_event (data, -1, NULL, NULL, 2);
|
||||
g_main_loop_quit (data->loop);
|
||||
return G_SOURCE_REMOVE;
|
||||
}
|
||||
|
||||
data->step++;
|
||||
|
||||
return G_SOURCE_CONTINUE;
|
||||
}
|
||||
|
||||
/* this is the output we expect from the above steps */
|
||||
static RecordedEvent atomic_replace_output[] = {
|
||||
{ -1, NULL, NULL, 0 },
|
||||
{ G_FILE_MONITOR_EVENT_CREATED, "atomic_replace_file", NULL, -1 },
|
||||
{ G_FILE_MONITOR_EVENT_CHANGED, "atomic_replace_file", NULL, -1 },
|
||||
{ G_FILE_MONITOR_EVENT_CHANGES_DONE_HINT, "atomic_replace_file", NULL, -1 },
|
||||
{ -1, NULL, NULL, 1 },
|
||||
{ G_FILE_MONITOR_EVENT_RENAMED, (gchar*)DONT_CARE, "atomic_replace_file", -1 },
|
||||
{ -1, NULL, NULL, 2 },
|
||||
};
|
||||
|
||||
static void
|
||||
test_atomic_replace (void)
|
||||
{
|
||||
GError *error = NULL;
|
||||
TestData data;
|
||||
|
||||
data.output = g_string_new ("");
|
||||
data.step = 0;
|
||||
data.events = NULL;
|
||||
|
||||
data.file = g_file_new_for_path ("atomic_replace_file");
|
||||
g_file_delete (data.file, NULL, NULL);
|
||||
|
||||
data.monitor = g_file_monitor_file (data.file, G_FILE_MONITOR_WATCH_MOVES, NULL, &error);
|
||||
g_assert_no_error (error);
|
||||
|
||||
g_file_monitor_set_rate_limit (data.monitor, 200);
|
||||
g_signal_connect (data.monitor, "changed", G_CALLBACK (monitor_changed), &data);
|
||||
|
||||
data.loop = g_main_loop_new (NULL, TRUE);
|
||||
|
||||
g_timeout_add (1000, atomic_replace_step, &data);
|
||||
|
||||
g_main_loop_run (data.loop);
|
||||
|
||||
/*output_events (data.events);*/
|
||||
check_expected_events (atomic_replace_output, G_N_ELEMENTS (atomic_replace_output), data.events);
|
||||
|
||||
/* clean up */
|
||||
g_file_delete (data.file, NULL, NULL);
|
||||
|
||||
g_list_free_full (data.events, (GDestroyNotify)free_recorded_event);
|
||||
g_main_loop_unref (data.loop);
|
||||
g_object_unref (data.monitor);
|
||||
g_object_unref (data.file);
|
||||
g_string_free (data.output, TRUE);
|
||||
}
|
||||
|
||||
int
|
||||
main (int argc, char *argv[])
|
||||
{
|
||||
g_test_init (&argc, &argv, NULL);
|
||||
|
||||
g_test_add_func ("/monitor/atomic-replace", test_atomic_replace);
|
||||
|
||||
return g_test_run ();
|
||||
}
|
Reference in New Issue
Block a user