[glib] Add some file monitoring tests



commit 8c32f7c448593862055a3b8de24514b76da96158
Author: Matthias Clasen <mclasen redhat com>
Date:   Wed Aug 19 07:10:55 2015 -0400

    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.

 gio/tests/Makefile.am       |    1 +
 gio/tests/testfilemonitor.c |  226 +++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 227 insertions(+), 0 deletions(-)
---
diff --git a/gio/tests/Makefile.am b/gio/tests/Makefile.am
index 143055a..12c5b67 100644
--- a/gio/tests/Makefile.am
+++ b/gio/tests/Makefile.am
@@ -64,6 +64,7 @@ test_programs = \
        vfs                                     \
        volumemonitor                           \
        glistmodel                              \
+       testfilemonitor                         \
        $(NULL)
 
 uninstalled_test_programs = \
diff --git a/gio/tests/testfilemonitor.c b/gio/tests/testfilemonitor.c
new file mode 100644
index 0000000..6f6ce89
--- /dev/null
+++ b/gio/tests/testfilemonitor.c
@@ -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 ();
+}


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]