[nautilus] Undo/redo, search tests, test library and more



commit 375c9ee792e1aa876ce314896a9b9c020ef5a522
Author: Alexandru Fazakas <alex fazakas97 gmail com>
Date:   Tue Aug 28 12:35:46 2018 +0000

    Undo/redo, search tests, test library and more

 src/nautilus-file-operations.c                     |   62 +-
 src/nautilus-file-operations.h                     |   20 +-
 src/nautilus-file-utilities.c                      |    4 +-
 src/nautilus-search-engine.c                       |  125 +-
 src/nautilus-search-engine.h                       |    4 +
 src/nautilus-search-provider.h                     |    7 +
 test/automated/displayless/meson.build             |   11 +-
 .../displayless/test-file-operations-copy-files.c  |  964 +++++++---
 .../displayless/test-file-operations-move-files.c  | 1874 ++++++++++++++++----
 .../test-file-operations-trash-or-delete.c         |  385 ++--
 .../test-nautilus-search-engine-model.c            |   72 +
 .../test-nautilus-search-engine-simple.c           |   68 +
 .../test-nautilus-search-engine-tracker.c          |  106 ++
 .../displayless/test-nautilus-search-engine.c      |   50 +-
 test/automated/displayless/test-utilities.c        |  555 ++++++
 test/automated/displayless/test-utilities.h        |   34 +
 16 files changed, 3464 insertions(+), 877 deletions(-)
---
diff --git a/src/nautilus-file-operations.c b/src/nautilus-file-operations.c
index 5951d0040..f3cf2ca0f 100644
--- a/src/nautilus-file-operations.c
+++ b/src/nautilus-file-operations.c
@@ -2530,9 +2530,7 @@ setup_delete_job (GList                  *files,
 static void
 trash_or_delete_internal_sync (GList                  *files,
                                GtkWindow              *parent_window,
-                               gboolean                try_trash,
-                               NautilusDeleteCallback  done_callback,
-                               gpointer                done_callback_data)
+                               gboolean                try_trash)
 {
     GTask *task;
     DeleteJob *job;
@@ -2540,13 +2538,17 @@ trash_or_delete_internal_sync (GList                  *files,
     job = setup_delete_job (files,
                             parent_window,
                             try_trash,
-                            done_callback,
-                            done_callback_data);
+                            NULL,
+                            NULL);
 
-    task = g_task_new (NULL, NULL, delete_task_done, job);
+    task = g_task_new (NULL, NULL, NULL, job);
     g_task_set_task_data (task, job, NULL);
     g_task_run_in_thread_sync (task, trash_or_delete_internal);
     g_object_unref (task);
+    /* Since g_task_run_in_thread_sync doesn't work with callbacks (in this case not reaching
+     * delete_task_done) we need to set up the undo information ourselves.
+     */
+    delete_task_done (NULL, NULL, job);
 }
 
 static void
@@ -2572,25 +2574,15 @@ trash_or_delete_internal_async (GList                  *files,
 }
 
 void
-nautilus_file_operations_trash_or_delete_sync (GList                  *files,
-                                               GtkWindow              *parent_window,
-                                               NautilusDeleteCallback  done_callback,
-                                               gpointer                done_callback_data)
+nautilus_file_operations_trash_or_delete_sync (GList                  *files)
 {
-    trash_or_delete_internal_sync (files, parent_window,
-                                   TRUE,
-                                   done_callback, done_callback_data);
+    trash_or_delete_internal_sync (files, NULL, TRUE);
 }
 
 void
-nautilus_file_operations_delete_sync (GList                  *files,
-                                      GtkWindow              *parent_window,
-                                      NautilusDeleteCallback  done_callback,
-                                      gpointer                done_callback_data)
+nautilus_file_operations_delete_sync (GList                  *files)
 {
-    trash_or_delete_internal_sync (files, parent_window,
-                                   FALSE,
-                                   done_callback, done_callback_data);
+    trash_or_delete_internal_sync (files, NULL, FALSE);
 }
 
 void
@@ -5782,24 +5774,25 @@ nautilus_file_operations_copy (GTask        *task,
 
 void
 nautilus_file_operations_copy_sync (GList *files,
-                                    GFile *target_dir,
-                                    GtkWindow *parent_window,
-                                    NautilusCopyCallback done_callback,
-                                    gpointer done_callback_data)
+                                    GFile *target_dir)
 {
     GTask *task;
     CopyMoveJob *job;
 
     job = copy_job_setup (files,
                            target_dir,
-                           parent_window,
-                           done_callback,
-                           done_callback_data);
+                           NULL,
+                           NULL,
+                           NULL);
 
-    task = g_task_new (NULL, job->common.cancellable, copy_task_done, job);
+    task = g_task_new (NULL, job->common.cancellable, NULL, job);
     g_task_set_task_data (task, job, NULL);
     g_task_run_in_thread_sync (task, nautilus_file_operations_copy);
     g_object_unref (task);
+    /* Since g_task_run_in_thread_sync doesn't work with callbacks (in this case not reaching
+     * copy_task_done) we need to set up the undo information ourselves.
+     */
+    copy_task_done (NULL, NULL, job);
 }
 
 void
@@ -6305,19 +6298,20 @@ move_job_setup (GList                *files,
 
 void
 nautilus_file_operations_move_sync (GList                *files,
-                                    GFile                *target_dir,
-                                    GtkWindow            *parent_window,
-                                    NautilusCopyCallback  done_callback,
-                                    gpointer              done_callback_data)
+                                    GFile                *target_dir)
 {
     GTask *task;
     CopyMoveJob *job;
 
-    job = move_job_setup (files, target_dir, parent_window, done_callback, done_callback_data);
-    task = g_task_new (NULL, job->common.cancellable, move_task_done, job);
+    job = move_job_setup (files, target_dir, NULL, NULL, NULL);
+    task = g_task_new (NULL, job->common.cancellable, NULL, job);
     g_task_set_task_data (task, job, NULL);
     g_task_run_in_thread_sync (task, nautilus_file_operations_move);
     g_object_unref (task);
+    /* Since g_task_run_in_thread_sync doesn't work with callbacks (in this case not reaching
+     * move_task_done) we need to set up the undo information ourselves.
+     */
+    move_task_done (NULL, NULL, job);
 }
 
 void
diff --git a/src/nautilus-file-operations.h b/src/nautilus-file-operations.h
index 5eaa95bdd..c9f0ae79a 100644
--- a/src/nautilus-file-operations.h
+++ b/src/nautilus-file-operations.h
@@ -76,14 +76,8 @@ void nautilus_file_operations_new_file_from_template (GtkWidget               *p
                                                      NautilusCreateCallback   done_callback,
                                                      gpointer                 data);
 
-void nautilus_file_operations_trash_or_delete_sync (GList                  *files,
-                                                    GtkWindow              *parent_window,
-                                                    NautilusDeleteCallback  done_callback,
-                                                    gpointer                done_callback_data);
-void nautilus_file_operations_delete_sync (GList                  *files,
-                                           GtkWindow              *parent_window,
-                                           NautilusDeleteCallback  done_callback,
-                                           gpointer                done_callback_data);
+void nautilus_file_operations_trash_or_delete_sync (GList                  *files);
+void nautilus_file_operations_delete_sync (GList                  *files);
 void nautilus_file_operations_trash_or_delete_async (GList                  *files,
                                                      GtkWindow              *parent_window,
                                                      NautilusDeleteCallback  done_callback,
@@ -126,10 +120,7 @@ void nautilus_file_operations_copy_async (GList                *files,
                                           NautilusCopyCallback  done_callback,
                                           gpointer              done_callback_data);
 void nautilus_file_operations_copy_sync (GList                *files,
-                                         GFile                *target_dir,
-                                         GtkWindow            *parent_window,
-                                         NautilusCopyCallback  done_callback,
-                                         gpointer              done_callback_data);
+                                         GFile                *target_dir);
 
 void nautilus_file_operations_move_async (GList                *files,
                                           GFile                *target_dir,
@@ -137,10 +128,7 @@ void nautilus_file_operations_move_async (GList                *files,
                                           NautilusCopyCallback  done_callback,
                                           gpointer              done_callback_data);
 void nautilus_file_operations_move_sync (GList                *files,
-                                         GFile                *target_dir,
-                                         GtkWindow            *parent_window,
-                                         NautilusCopyCallback  done_callback,
-                                         gpointer              done_callback_data);
+                                         GFile                *target_dir);
 
 void nautilus_file_operations_duplicate (GList                *files,
                                         GtkWindow            *parent_window,
diff --git a/src/nautilus-file-utilities.c b/src/nautilus-file-utilities.c
index 66117891a..575c138cf 100644
--- a/src/nautilus-file-utilities.c
+++ b/src/nautilus-file-utilities.c
@@ -819,9 +819,7 @@ ensure_dirs_task_ready_cb (GObject      *_source,
 
         nautilus_file_operations_move_sync
             (locations,
-            original_dir_location,
-            data->parent_window,
-            NULL, NULL);
+            original_dir_location);
 
         g_list_free_full (locations, g_object_unref);
         g_object_unref (original_dir_location);
diff --git a/src/nautilus-search-engine.c b/src/nautilus-search-engine.c
index 5f0fa85c1..23c1c7e88 100644
--- a/src/nautilus-search-engine.c
+++ b/src/nautilus-search-engine.c
@@ -25,7 +25,6 @@
 
 #include "nautilus-file.h"
 #include "nautilus-search-engine-model.h"
-#include "nautilus-search-provider.h"
 #include <glib/gi18n.h>
 #define DEBUG_FLAG NAUTILUS_DEBUG_SEARCH
 #include "nautilus-debug.h"
@@ -84,7 +83,7 @@ nautilus_search_engine_set_query (NautilusSearchProvider *provider,
 }
 
 static void
-search_engine_start_real (NautilusSearchEngine *engine)
+search_engine_start_real_setup (NautilusSearchEngine *engine)
 {
     NautilusSearchEnginePrivate *priv;
 
@@ -96,26 +95,142 @@ search_engine_start_real (NautilusSearchEngine *engine)
 
     priv->restart = FALSE;
 
-    DEBUG ("Search engine start real");
+    DEBUG ("Search engine start real setup");
 
     g_object_ref (engine);
+}
+
+static void
+search_engine_start_real_tracker (NautilusSearchEngine *engine)
+{
+    NautilusSearchEnginePrivate *priv;
 
+    priv = nautilus_search_engine_get_instance_private (engine);
+    
     priv->providers_running++;
     nautilus_search_provider_start (NAUTILUS_SEARCH_PROVIDER (priv->tracker));
+}
+
+static void
+search_engine_start_real_recent (NautilusSearchEngine *engine)
+{
+    NautilusSearchEnginePrivate *priv;
 
+    priv = nautilus_search_engine_get_instance_private (engine);
+    
     priv->providers_running++;
     nautilus_search_provider_start (NAUTILUS_SEARCH_PROVIDER (priv->recent));
+}
+
+static void
+search_engine_start_real_model (NautilusSearchEngine *engine)
+{
+    NautilusSearchEnginePrivate *priv;
 
+    priv = nautilus_search_engine_get_instance_private (engine);
     if (nautilus_search_engine_model_get_model (priv->model))
     {
         priv->providers_running++;
         nautilus_search_provider_start (NAUTILUS_SEARCH_PROVIDER (priv->model));
     }
+}
+
+static void
+search_engine_start_real_simple (NautilusSearchEngine *engine)
+{
+    NautilusSearchEnginePrivate *priv;
 
+    priv = nautilus_search_engine_get_instance_private (engine);
     priv->providers_running++;
+
     nautilus_search_provider_start (NAUTILUS_SEARCH_PROVIDER (priv->simple));
 }
 
+static void
+search_engine_start_real (NautilusSearchEngine       *engine,
+                          NautilusSearchEngineTarget  target_engine)
+{
+    search_engine_start_real_setup (engine);
+
+    switch (target_engine)
+    {
+        case NAUTILUS_SEARCH_ENGINE_TRACKER_ENGINE:
+        {
+            search_engine_start_real_tracker (engine);
+        }
+        break;
+
+        case NAUTILUS_SEARCH_ENGINE_RECENT_ENGINE:
+        {
+            search_engine_start_real_recent (engine);
+        }
+        break;
+
+        case NAUTILUS_SEARCH_ENGINE_MODEL_ENGINE:
+        {
+            search_engine_start_real_model (engine);
+        }
+        break;
+
+        case NAUTILUS_SEARCH_ENGINE_SIMPLE_ENGINE:
+        {
+            search_engine_start_real_simple (engine);
+        }
+        break;
+
+        case NAUTILUS_SEARCH_ENGINE_ALL_ENGINES:
+        default:
+        {
+            search_engine_start_real_tracker (engine);
+            search_engine_start_real_recent (engine);
+            search_engine_start_real_model (engine);
+            search_engine_start_real_simple (engine);
+        }
+    }
+}
+
+void
+nautilus_search_engine_start_by_target (NautilusSearchProvider     *provider,
+                                        NautilusSearchEngineTarget  target_engine)
+{
+    NautilusSearchEngine *engine;
+    NautilusSearchEnginePrivate *priv;
+    gint num_finished;
+
+    engine = NAUTILUS_SEARCH_ENGINE (provider);
+    priv = nautilus_search_engine_get_instance_private (engine);
+
+    DEBUG ("Search engine start");
+
+    num_finished = priv->providers_error + priv->providers_finished;
+
+    if (priv->running)
+    {
+        if (num_finished == priv->providers_running &&
+            priv->restart)
+        {
+            search_engine_start_real (engine, target_engine);
+        }
+
+        return;
+    }
+
+    priv->running = TRUE;
+
+    g_object_notify (G_OBJECT (provider), "running");
+
+    if (num_finished < priv->providers_running)
+    {
+        priv->restart = TRUE;
+    }
+    else
+    {
+        search_engine_start_real (engine, target_engine);
+    }
+}
+
+
+
 static void
 nautilus_search_engine_start (NautilusSearchProvider *provider)
 {
@@ -135,7 +250,7 @@ nautilus_search_engine_start (NautilusSearchProvider *provider)
         if (num_finished == priv->providers_running &&
             priv->restart)
         {
-            search_engine_start_real (engine);
+            search_engine_start_real (engine, NAUTILUS_SEARCH_ENGINE_ALL_ENGINES);
         }
 
         return;
@@ -151,7 +266,7 @@ nautilus_search_engine_start (NautilusSearchProvider *provider)
     }
     else
     {
-        search_engine_start_real (engine);
+        search_engine_start_real (engine, NAUTILUS_SEARCH_ENGINE_ALL_ENGINES);
     }
 }
 
diff --git a/src/nautilus-search-engine.h b/src/nautilus-search-engine.h
index 62d767377..33c3644be 100644
--- a/src/nautilus-search-engine.h
+++ b/src/nautilus-search-engine.h
@@ -25,6 +25,7 @@
 
 #include "nautilus-directory.h"
 #include "nautilus-search-engine-model.h"
+#include "nautilus-search-provider.h"
 
 G_BEGIN_DECLS
 
@@ -42,3 +43,6 @@ NautilusSearchEngineModel *
                       nautilus_search_engine_get_model_provider (NautilusSearchEngine *engine);
 
 G_END_DECLS
+
+void nautilus_search_engine_start_by_target (NautilusSearchProvider     *provider,
+                                             NautilusSearchEngineTarget  taregt_engine);
\ No newline at end of file
diff --git a/src/nautilus-search-provider.h b/src/nautilus-search-provider.h
index c25d16161..a1ff6f3a1 100644
--- a/src/nautilus-search-provider.h
+++ b/src/nautilus-search-provider.h
@@ -28,6 +28,13 @@ typedef enum {
   NAUTILUS_SEARCH_PROVIDER_STATUS_RESTARTING
 } NautilusSearchProviderStatus;
 
+typedef enum {
+  NAUTILUS_SEARCH_ENGINE_ALL_ENGINES,
+  NAUTILUS_SEARCH_ENGINE_TRACKER_ENGINE,
+  NAUTILUS_SEARCH_ENGINE_RECENT_ENGINE,
+  NAUTILUS_SEARCH_ENGINE_MODEL_ENGINE,
+  NAUTILUS_SEARCH_ENGINE_SIMPLE_ENGINE,
+} NautilusSearchEngineTarget;
 
 #define NAUTILUS_TYPE_SEARCH_PROVIDER (nautilus_search_provider_get_type ())
 
diff --git a/test/automated/displayless/meson.build b/test/automated/displayless/meson.build
index c3eebbad4..58f0b853b 100644
--- a/test/automated/displayless/meson.build
+++ b/test/automated/displayless/meson.build
@@ -17,6 +17,15 @@ tests = [
   ['test-nautilus-search-engine', [
     'test-nautilus-search-engine.c'
   ]],
+  ['test-nautilus-search-engine-simple', [
+    'test-nautilus-search-engine-simple.c'
+  ]],
+  ['test-nautilus-search-engine-model', [
+    'test-nautilus-search-engine-model.c'
+  ]],
+  ['test-nautilus-search-engine-tracker', [
+    'test-nautilus-search-engine-tracker.c'
+  ]],
   ['test-file-operations-copy-files', [
     'test-file-operations-copy-files.c'
   ]],
@@ -28,7 +37,7 @@ tests = [
 foreach t: tests
   test(
     t[0],
-    executable(t[0], t[1], dependencies: libnautilus_dep),
+    executable(t[0], t[1], files('test-utilities.c'), dependencies: libnautilus_dep),
     env: [
       test_env,
       'G_TEST_BUILDDIR=@0@'.format(meson.current_build_dir()),
diff --git a/test/automated/displayless/test-file-operations-copy-files.c 
b/test/automated/displayless/test-file-operations-copy-files.c
index 30829d85f..8147adf8a 100644
--- a/test/automated/displayless/test-file-operations-copy-files.c
+++ b/test/automated/displayless/test-file-operations-copy-files.c
@@ -1,11 +1,4 @@
-#include <glib.h>
-#include "src/nautilus-directory.h"
-#include "src/nautilus-file-utilities.h"
-#include "src/nautilus-search-directory.h"
-#include "src/nautilus-directory.h"
-#include "src/nautilus-file-operations.c"
-#include <unistd.h>
-#include "eel/eel-string.h"
+#include "test-utilities.h"
 
 static void
 test_copy_one_file (void)
@@ -16,41 +9,67 @@ test_copy_one_file (void)
     g_autoptr (GFile) file = NULL;
     g_autoptr (GFile) result_file = NULL;
     g_autolist (GFile) files = NULL;
-    GFileOutputStream *out = NULL;
-    g_autoptr (GError) error = NULL;
+
+    create_one_file ("copy");
 
     root = g_file_new_for_path (g_get_tmp_dir ());
+    g_assert_true (root != NULL);
+
     first_dir = g_file_get_child (root, "copy_first_dir");
     g_assert_true (first_dir != NULL);
-    g_file_make_directory (first_dir, NULL, NULL);
 
     file = g_file_get_child (first_dir, "copy_first_dir_child");
     g_assert_true (file != NULL);
-    out = g_file_create (file, G_FILE_CREATE_NONE, NULL, &error);
-    if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_EXISTS))
-    {
-        g_object_unref (out);
-    }
     files = g_list_prepend (files, g_object_ref (file));
 
     second_dir = g_file_get_child (root, "copy_second_dir");
     g_assert_true (second_dir != NULL);
-    g_file_make_directory (second_dir, NULL, NULL);
 
     nautilus_file_operations_copy_sync (files,
-                                        second_dir,
-                                        NULL,
-                                        NULL,
-                                        NULL);
+                                        second_dir);
 
     result_file = g_file_get_child (second_dir, "copy_first_dir_child");
     g_assert_true (g_file_query_exists (result_file, NULL));
     g_assert_true (g_file_query_exists (file, NULL));
 
-    g_assert_true (g_file_delete (result_file, NULL, NULL));
-    g_assert_true (g_file_delete (file, NULL, NULL));
-    g_assert_true (g_file_delete (first_dir, NULL, NULL));
-    g_assert_true (g_file_delete (second_dir, NULL, NULL));
+    empty_directory_by_prefix (root, "copy");
+}
+
+static void
+test_copy_one_file_undo (void)
+{
+    g_autoptr (GFile) root = NULL;
+    g_autoptr (GFile) first_dir = NULL;
+    g_autoptr (GFile) second_dir = NULL;
+    g_autoptr (GFile) file = NULL;
+    g_autoptr (GFile) result_file = NULL;
+    g_autolist (GFile) files = NULL;
+
+    create_one_file ("copy");
+
+    root = g_file_new_for_path (g_get_tmp_dir ());
+    g_assert_true (root != NULL);
+
+    first_dir = g_file_get_child (root, "copy_first_dir");
+    g_assert_true (first_dir != NULL);
+
+    file = g_file_get_child (first_dir, "copy_first_dir_child");
+    g_assert_true (file != NULL);
+    files = g_list_prepend (files, g_object_ref (file));
+
+    second_dir = g_file_get_child (root, "copy_second_dir");
+    g_assert_true (second_dir != NULL);
+
+    nautilus_file_operations_copy_sync (files,
+                                        second_dir);
+
+    test_operation_undo ();
+
+    result_file = g_file_get_child (second_dir, "copy_first_dir_child");
+    g_assert_false (g_file_query_exists (result_file, NULL));
+    g_assert_true (g_file_query_exists (file, NULL));
+
+    empty_directory_by_prefix (root, "copy");
 }
 
 static void
@@ -63,327 +82,600 @@ test_copy_one_empty_directory (void)
     g_autoptr (GFile) result_file = NULL;
     g_autolist (GFile) files = NULL;
 
+    create_one_empty_directory ("copy");
+
     root = g_file_new_for_path (g_get_tmp_dir ());
+    g_assert_true (root != NULL);
     first_dir = g_file_get_child (root, "copy_first_dir");
     g_assert_true (first_dir != NULL);
-    g_file_make_directory (first_dir, NULL, NULL);
 
     file = g_file_get_child (first_dir, "copy_first_dir_child");
     g_assert_true (file != NULL);
-    g_file_make_directory (file, NULL, NULL);
     files = g_list_prepend (files, g_object_ref (file));
 
     second_dir = g_file_get_child (root, "copy_second_dir");
     g_assert_true (second_dir != NULL);
-    g_file_make_directory (second_dir, NULL, NULL);
 
     nautilus_file_operations_copy_sync (files,
-                                        second_dir,
-                                        NULL,
-                                        NULL,
-                                        NULL);
+                                        second_dir);
 
     result_file = g_file_get_child (second_dir, "copy_first_dir_child");
     g_assert_true (g_file_query_exists (result_file, NULL));
     g_assert_true (g_file_query_exists (file, NULL));
 
-    g_assert_true (g_file_delete (result_file, NULL, NULL));
-    g_assert_true (g_file_delete (file, NULL, NULL));
-    g_assert_true (g_file_delete (first_dir, NULL, NULL));
-    g_assert_true (g_file_delete (second_dir, NULL, NULL));
+    empty_directory_by_prefix (root, "copy");
 }
 
 static void
-test_copy_directories_small (void)
+test_copy_one_empty_directory_undo (void)
+{
+    g_autoptr (GFile) root = NULL;
+    g_autoptr (GFile) first_dir = NULL;
+    g_autoptr (GFile) second_dir = NULL;
+    g_autoptr (GFile) file = NULL;
+    g_autoptr (GFile) result_file = NULL;
+    g_autolist (GFile) files = NULL;
+
+    create_one_empty_directory ("copy");
+
+    root = g_file_new_for_path (g_get_tmp_dir ());
+    g_assert_true (root != NULL);
+    first_dir = g_file_get_child (root, "copy_first_dir");
+    g_assert_true (first_dir != NULL);
+
+    file = g_file_get_child (first_dir, "copy_first_dir_child");
+    g_assert_true (file != NULL);
+    files = g_list_prepend (files, g_object_ref (file));
+
+    second_dir = g_file_get_child (root, "copy_second_dir");
+    g_assert_true (second_dir != NULL);
+
+    nautilus_file_operations_copy_sync (files,
+                                        second_dir);
+
+    test_operation_undo ();
+
+    result_file = g_file_get_child (second_dir, "copy_first_dir_child");
+    g_assert_false (g_file_query_exists (result_file, NULL));
+
+    g_assert_true (g_file_query_exists (file, NULL));
+
+    empty_directory_by_prefix (root, "copy");
+}
+
+static void
+test_copy_files_small (void)
 {
     g_autoptr (GFile) root = NULL;
     g_autoptr (GFile) file = NULL;
     g_autoptr (GFile) dir = NULL;
     g_autolist (GFile) files = NULL;
-    g_autofree gchar *file_name = NULL;
+    gchar *file_name;
+
+    create_multiple_files ("copy", 10);
 
     root = g_file_new_for_path (g_get_tmp_dir ());
+    g_assert_true (root != NULL);
 
     for (int i = 0; i < 10; i++)
     {
         file_name = g_strdup_printf ("copy_file_%i", i);
         file = g_file_get_child (root, file_name);
+        g_free (file_name);
         g_assert_true (file != NULL);
-        g_file_make_directory (file, NULL, NULL);
         files = g_list_prepend (files, g_object_ref (file));
     }
 
     dir = g_file_get_child (root, "copy_dir");
     g_assert_true (dir != NULL);
-    g_file_make_directory (dir, NULL, NULL);
 
     nautilus_file_operations_copy_sync (files,
-                                        dir,
-                                        NULL,
-                                        NULL,
-                                        NULL);
+                                        dir);
 
     for (int i = 0; i < 10; i++)
     {
         file_name = g_strdup_printf ("copy_file_%i", i);
         file = g_file_get_child (dir, file_name);
         g_assert_true (g_file_query_exists (file, NULL));
-        g_assert_true (g_file_delete (file, NULL, NULL));
         file = g_file_get_child (root, file_name);
+        g_free (file_name);
         g_assert_true (g_file_query_exists (file, NULL));
-        g_assert_true (g_file_delete (file, NULL, NULL));
     }
 
     g_assert_true (g_file_query_exists (dir, NULL));
-    g_assert_true (g_file_delete (dir, NULL, NULL));
+
+    empty_directory_by_prefix (root, "copy");
 }
 
 static void
-test_copy_directories_medium (void)
+test_copy_files_small_undo (void)
 {
     g_autoptr (GFile) root = NULL;
     g_autoptr (GFile) file = NULL;
     g_autoptr (GFile) dir = NULL;
     g_autolist (GFile) files = NULL;
-    g_autofree gchar *file_name = NULL;
+    gchar *file_name;
+
+    create_multiple_files ("copy", 10);
 
     root = g_file_new_for_path (g_get_tmp_dir ());
+    g_assert_true (root != NULL);
+
+    for (int i = 0; i < 10; i++)
+    {
+        file_name = g_strdup_printf ("copy_file_%i", i);
+        file = g_file_get_child (root, file_name);
+        g_free (file_name);
+        g_assert_true (file != NULL);
+        files = g_list_prepend (files, g_object_ref (file));
+    }
+
+    dir = g_file_get_child (root, "copy_dir");
+    g_assert_true (dir != NULL);
+
+    nautilus_file_operations_copy_sync (files,
+                                        dir);
+
+    test_operation_undo ();
+
+    for (int i = 0; i < 10; i++)
+    {
+        file_name = g_strdup_printf ("copy_file_%i", i);
+        file = g_file_get_child (dir, file_name);
+        g_assert_false (g_file_query_exists (file, NULL));
+        file = g_file_get_child (root, file_name);
+        g_free (file_name);
+        g_assert_true (g_file_query_exists (file, NULL));
+    }
+
+    g_assert_true (g_file_query_exists (dir, NULL));
+
+    empty_directory_by_prefix (root, "copy");
+}
+
+static void
+test_copy_files_medium (void)
+{
+    g_autoptr (GFile) root = NULL;
+    g_autoptr (GFile) file = NULL;
+    g_autoptr (GFile) dir = NULL;
+    g_autolist (GFile) files = NULL;
+    gchar *file_name;
+
+    create_multiple_files ("copy", 1000);
+
+    root = g_file_new_for_path (g_get_tmp_dir ());
+    g_assert_true (root != NULL);
 
     for (int i = 0; i < 1000; i++)
     {
         file_name = g_strdup_printf ("copy_file_%i", i);
         file = g_file_get_child (root, file_name);
+        g_free (file_name);
         g_assert_true (file != NULL);
-        g_file_make_directory (file, NULL, NULL);
         files = g_list_prepend (files, g_object_ref (file));
     }
 
     dir = g_file_get_child (root, "copy_dir");
     g_assert_true (dir != NULL);
-    g_file_make_directory (dir, NULL, NULL);
 
     nautilus_file_operations_copy_sync (files,
-                                        dir,
-                                        NULL,
-                                        NULL,
-                                        NULL);
+                                        dir);
 
     for (int i = 0; i < 1000; i++)
     {
         file_name = g_strdup_printf ("copy_file_%i", i);
         file = g_file_get_child (dir, file_name);
         g_assert_true (g_file_query_exists (file, NULL));
-        g_assert_true (g_file_delete (file, NULL, NULL));
         file = g_file_get_child (root, file_name);
+        g_free (file_name);
         g_assert_true (g_file_query_exists (file, NULL));
-        g_assert_true (g_file_delete (file, NULL, NULL));
     }
 
     g_assert_true (g_file_query_exists (dir, NULL));
-    g_assert_true (g_file_delete (dir, NULL, NULL));
+
+    empty_directory_by_prefix (root, "copy");
 }
 
+static void
+test_copy_files_medium_undo (void)
+{
+    g_autoptr (GFile) root = NULL;
+    g_autoptr (GFile) file = NULL;
+    g_autoptr (GFile) dir = NULL;
+    g_autolist (GFile) files = NULL;
+    gchar *file_name;
+
+    create_multiple_files ("copy", 1000);
+
+    root = g_file_new_for_path (g_get_tmp_dir ());
+    g_assert_true (root != NULL);
+
+    for (int i = 0; i < 1000; i++)
+    {
+        file_name = g_strdup_printf ("copy_file_%i", i);
+        file = g_file_get_child (root, file_name);
+        g_free (file_name);
+        g_assert_true (file != NULL);
+        files = g_list_prepend (files, g_object_ref (file));
+    }
+
+    dir = g_file_get_child (root, "copy_dir");
+    g_assert_true (dir != NULL);
+
+    nautilus_file_operations_copy_sync (files,
+                                        dir);
+    test_operation_undo ();
+
+    for (int i = 0; i < 1000; i++)
+    {
+        file_name = g_strdup_printf ("copy_file_%i", i);
+        file = g_file_get_child (dir, file_name);
+        g_assert_false (g_file_query_exists (file, NULL));
+        file = g_file_get_child (root, file_name);
+        g_free (file_name);
+        g_assert_true (g_file_query_exists (file, NULL));
+    }
+
+    g_assert_true (g_file_query_exists (dir, NULL));
+
+    empty_directory_by_prefix (root, "copy");
+}
 
 static void
-test_copy_directories_large (void)
+test_copy_files_large (void)
 {
     g_autoptr (GFile) root = NULL;
     g_autoptr (GFile) file = NULL;
     g_autoptr (GFile) dir = NULL;
     g_autolist (GFile) files = NULL;
-    g_autofree gchar *file_name = NULL;
+    gchar *file_name;
+
+    create_multiple_files ("copy", 10000);
 
     root = g_file_new_for_path (g_get_tmp_dir ());
+    g_assert_true (root != NULL);
 
     for (int i = 0; i < 10000; i++)
     {
         file_name = g_strdup_printf ("copy_file_%i", i);
         file = g_file_get_child (root, file_name);
         g_assert_true (file != NULL);
-        g_file_make_directory (file, NULL, NULL);
         files = g_list_prepend (files, g_object_ref (file));
     }
 
     dir = g_file_get_child (root, "copy_dir");
     g_assert_true (dir != NULL);
-    g_file_make_directory (dir, NULL, NULL);
 
     nautilus_file_operations_copy_sync (files,
-                                        dir,
-                                        NULL,
-                                        NULL,
-                                        NULL);
+                                        dir);
 
     for (int i = 0; i < 10000; i++)
     {
         file_name = g_strdup_printf ("copy_file_%i", i);
         file = g_file_get_child (dir, file_name);
         g_assert_true (g_file_query_exists (file, NULL));
-        g_assert_true (g_file_delete (file, NULL, NULL));
         file = g_file_get_child (root, file_name);
         g_assert_true (g_file_query_exists (file, NULL));
-        g_assert_true (g_file_delete (file, NULL, NULL));
     }
 
     g_assert_true (g_file_query_exists (dir, NULL));
-    g_assert_true (g_file_delete (dir, NULL, NULL));
+
+    empty_directory_by_prefix (root, "copy");
 }
 
+static void
+test_copy_files_large_undo (void)
+{
+    g_autoptr (GFile) root = NULL;
+    g_autoptr (GFile) file = NULL;
+    g_autoptr (GFile) dir = NULL;
+    g_autolist (GFile) files = NULL;
+    gchar *file_name;
+
+    create_multiple_files ("copy", 10000);
+
+    root = g_file_new_for_path (g_get_tmp_dir ());
+    g_assert_true (root != NULL);
+
+    for (int i = 0; i < 10000; i++)
+    {
+        file_name = g_strdup_printf ("copy_file_%i", i);
+        file = g_file_get_child (root, file_name);
+        g_free (file_name);
+        g_assert_true (file != NULL);
+        files = g_list_prepend (files, g_object_ref (file));
+    }
+
+    dir = g_file_get_child (root, "copy_dir");
+    g_assert_true (dir != NULL);
+
+    nautilus_file_operations_copy_sync (files,
+                                        dir);
+
+    test_operation_undo ();
+
+    for (int i = 0; i < 10000; i++)
+    {
+        file_name = g_strdup_printf ("copy_file_%i", i);
+        file = g_file_get_child (dir, file_name);
+        g_assert_false (g_file_query_exists (file, NULL));
+        file = g_file_get_child (root, file_name);
+        g_free (file_name);
+        g_assert_true (g_file_query_exists (file, NULL));
+    }
+
+    g_assert_true (g_file_query_exists (dir, NULL));
+
+    empty_directory_by_prefix (root, "copy");
+}
 
 static void
-test_copy_files_small (void)
+test_copy_directories_small (void)
 {
     g_autoptr (GFile) root = NULL;
     g_autoptr (GFile) file = NULL;
     g_autoptr (GFile) dir = NULL;
     g_autolist (GFile) files = NULL;
-    g_autofree gchar *file_name = NULL;
-    GFileOutputStream *out = NULL;
+    gchar *file_name;
+
+    create_multiple_directories ("copy", 10);
 
     root = g_file_new_for_path (g_get_tmp_dir ());
+    g_assert_true (root != NULL);
 
     for (int i = 0; i < 10; i++)
     {
-        g_autoptr (GError) error = NULL;
-
         file_name = g_strdup_printf ("copy_file_%i", i);
         file = g_file_get_child (root, file_name);
+        g_free (file_name);
         g_assert_true (file != NULL);
-        out = g_file_create (file, G_FILE_CREATE_NONE, NULL, &error);
-        if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_EXISTS))
-        {
-            g_object_unref (out);
-        }
         files = g_list_prepend (files, g_object_ref (file));
     }
 
     dir = g_file_get_child (root, "copy_dir");
     g_assert_true (dir != NULL);
-    g_file_make_directory (dir, NULL, NULL);
 
     nautilus_file_operations_copy_sync (files,
-                                        dir,
-                                        NULL,
-                                        NULL,
-                                        NULL);
+                                        dir);
 
     for (int i = 0; i < 10; i++)
     {
         file_name = g_strdup_printf ("copy_file_%i", i);
         file = g_file_get_child (dir, file_name);
         g_assert_true (g_file_query_exists (file, NULL));
-        g_assert_true (g_file_delete (file, NULL, NULL));
         file = g_file_get_child (root, file_name);
+        g_free (file_name);
         g_assert_true (g_file_query_exists (file, NULL));
-        g_assert_true (g_file_delete (file, NULL, NULL));
     }
 
     g_assert_true (g_file_query_exists (dir, NULL));
-    g_assert_true (g_file_delete (dir, NULL, NULL));
+
+    empty_directory_by_prefix (root, "copy");
 }
 
 static void
-test_copy_files_medium (void)
+test_copy_directories_small_undo (void)
+{
+    g_autoptr (GFile) root = NULL;
+    g_autoptr (GFile) file = NULL;
+    g_autoptr (GFile) dir = NULL;
+    g_autolist (GFile) files = NULL;
+    gchar *file_name;
+
+    create_multiple_directories ("copy", 10);
+
+    root = g_file_new_for_path (g_get_tmp_dir ());
+    g_assert_true (root != NULL);
+
+    for (int i = 0; i < 10; i++)
+    {
+        file_name = g_strdup_printf ("copy_file_%i", i);
+        file = g_file_get_child (root, file_name);
+        g_free (file_name);
+        g_assert_true (file != NULL);
+        files = g_list_prepend (files, g_object_ref (file));
+    }
+
+    dir = g_file_get_child (root, "copy_dir");
+    g_assert_true (dir != NULL);
+
+    nautilus_file_operations_copy_sync (files,
+                                        dir);
+
+    test_operation_undo ();
+
+    for (int i = 0; i < 10; i++)
+    {
+        file_name = g_strdup_printf ("copy_file_%i", i);
+        file = g_file_get_child (dir, file_name);
+        g_assert_false (g_file_query_exists (file, NULL));
+        file = g_file_get_child (root, file_name);
+        g_free (file_name);
+        g_assert_true (g_file_query_exists (file, NULL));
+    }
+
+    g_assert_true (g_file_query_exists (dir, NULL));
+
+    empty_directory_by_prefix (root, "copy");
+}
+
+static void
+test_copy_directories_medium (void)
 {
     g_autoptr (GFile) root = NULL;
     g_autoptr (GFile) file = NULL;
     g_autoptr (GFile) dir = NULL;
     g_autolist (GFile) files = NULL;
-    g_autofree gchar *file_name = NULL;
-    GFileOutputStream *out = NULL;
+    gchar *file_name;
+
+    create_multiple_directories ("copy", 1000);
 
     root = g_file_new_for_path (g_get_tmp_dir ());
+    g_assert_true (root != NULL);
 
     for (int i = 0; i < 1000; i++)
     {
-        g_autoptr (GError) error = NULL;
+        file_name = g_strdup_printf ("copy_file_%i", i);
+        file = g_file_get_child (root, file_name);
+        g_free (file_name);
+        g_assert_true (file != NULL);
+        files = g_list_prepend (files, g_object_ref (file));
+    }
 
+    dir = g_file_get_child (root, "copy_dir");
+    g_assert_true (dir != NULL);
+
+    nautilus_file_operations_copy_sync (files,
+                                        dir);
+
+    for (int i = 0; i < 1000; i++)
+    {
+        file_name = g_strdup_printf ("copy_file_%i", i);
+        file = g_file_get_child (dir, file_name);
+        g_assert_true (g_file_query_exists (file, NULL));
+        file = g_file_get_child (root, file_name);
+        g_free (file_name);
+        g_assert_true (g_file_query_exists (file, NULL));
+    }
+
+    g_assert_true (g_file_query_exists (dir, NULL));
+
+    empty_directory_by_prefix (root, "copy");
+}
+
+static void
+test_copy_directories_medium_undo (void)
+{
+    g_autoptr (GFile) root = NULL;
+    g_autoptr (GFile) file = NULL;
+    g_autoptr (GFile) dir = NULL;
+    g_autolist (GFile) files = NULL;
+    gchar *file_name;
+
+    create_multiple_directories ("copy", 1000);
+
+    root = g_file_new_for_path (g_get_tmp_dir ());
+    g_assert_true (root != NULL);
+
+    for (int i = 0; i < 1000; i++)
+    {
         file_name = g_strdup_printf ("copy_file_%i", i);
         file = g_file_get_child (root, file_name);
+        g_free (file_name);
         g_assert_true (file != NULL);
-        out = g_file_create (file, G_FILE_CREATE_NONE, NULL, &error);
-        if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_EXISTS))
-        {
-            g_object_unref (out);
-        }
         files = g_list_prepend (files, g_object_ref (file));
     }
 
     dir = g_file_get_child (root, "copy_dir");
     g_assert_true (dir != NULL);
-    g_file_make_directory (dir, NULL, NULL);
 
     nautilus_file_operations_copy_sync (files,
-                                        dir,
-                                        NULL,
-                                        NULL,
-                                        NULL);
+                                        dir);
+
+    test_operation_undo ();
 
     for (int i = 0; i < 1000; i++)
+    {
+        file_name = g_strdup_printf ("copy_file_%i", i);
+        file = g_file_get_child (dir, file_name);
+        g_assert_false (g_file_query_exists (file, NULL));
+        file = g_file_get_child (root, file_name);
+        g_free (file_name);
+        g_assert_true (g_file_query_exists (file, NULL));
+    }
+
+    g_assert_true (g_file_query_exists (dir, NULL));
+
+    empty_directory_by_prefix (root, "copy");
+}
+
+static void
+test_copy_directories_large (void)
+{
+    g_autoptr (GFile) root = NULL;
+    g_autoptr (GFile) file = NULL;
+    g_autoptr (GFile) dir = NULL;
+    g_autolist (GFile) files = NULL;
+    gchar *file_name;
+
+    create_multiple_directories ("copy", 10000);
+
+    root = g_file_new_for_path (g_get_tmp_dir ());
+    g_assert_true (root != NULL);
+
+    for (int i = 0; i < 10000; i++)
+    {
+        file_name = g_strdup_printf ("copy_file_%i", i);
+        file = g_file_get_child (root, file_name);
+        g_free (file_name);
+        g_assert_true (file != NULL);
+        files = g_list_prepend (files, g_object_ref (file));
+    }
+
+    dir = g_file_get_child (root, "copy_dir");
+    g_assert_true (dir != NULL);
+
+    nautilus_file_operations_copy_sync (files,
+                                        dir);
+
+    for (int i = 0; i < 10000; i++)
     {
         file_name = g_strdup_printf ("copy_file_%i", i);
         file = g_file_get_child (dir, file_name);
         g_assert_true (g_file_query_exists (file, NULL));
-        g_assert_true (g_file_delete (file, NULL, NULL));
         file = g_file_get_child (root, file_name);
+        g_free (file_name);
         g_assert_true (g_file_query_exists (file, NULL));
-        g_assert_true (g_file_delete (file, NULL, NULL));
     }
 
     g_assert_true (g_file_query_exists (dir, NULL));
-    g_assert_true (g_file_delete (dir, NULL, NULL));
+
+    empty_directory_by_prefix (root, "copy");
 }
 
 static void
-test_copy_files_large (void)
+test_copy_directories_large_undo (void)
 {
     g_autoptr (GFile) root = NULL;
     g_autoptr (GFile) file = NULL;
     g_autoptr (GFile) dir = NULL;
     g_autolist (GFile) files = NULL;
-    g_autofree gchar *file_name = NULL;
-    GFileOutputStream *out = NULL;
+    gchar *file_name;
+
+    create_multiple_directories ("copy", 10000);
 
     root = g_file_new_for_path (g_get_tmp_dir ());
+    g_assert_true (root != NULL);
 
     for (int i = 0; i < 10000; i++)
     {
-        g_autoptr (GError) error = NULL;
-
         file_name = g_strdup_printf ("copy_file_%i", i);
         file = g_file_get_child (root, file_name);
         g_assert_true (file != NULL);
-        out = g_file_create (file, G_FILE_CREATE_NONE, NULL, &error);
-        if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_EXISTS))
-        {
-            g_object_unref (out);
-        }
+        g_free (file_name);
         files = g_list_prepend (files, g_object_ref (file));
     }
 
     dir = g_file_get_child (root, "copy_dir");
     g_assert_true (dir != NULL);
-    g_file_make_directory (dir, NULL, NULL);
 
     nautilus_file_operations_copy_sync (files,
-                                        dir,
-                                        NULL,
-                                        NULL,
-                                        NULL);
+                                        dir);
+
+    test_operation_undo ();
 
     for (int i = 0; i < 10000; i++)
     {
         file_name = g_strdup_printf ("copy_file_%i", i);
         file = g_file_get_child (dir, file_name);
-        g_assert_true (g_file_query_exists (file, NULL));
-        g_assert_true (g_file_delete (file, NULL, NULL));
+        g_assert_false (g_file_query_exists (file, NULL));
         file = g_file_get_child (root, file_name);
+        g_free (file_name);
         g_assert_true (g_file_query_exists (file, NULL));
-        g_assert_true (g_file_delete (file, NULL, NULL));
     }
 
     g_assert_true (g_file_query_exists (dir, NULL));
-    g_assert_true (g_file_delete (dir, NULL, NULL));
 }
 
 /* The hierarchy looks like this:
@@ -392,7 +684,7 @@ test_copy_files_large (void)
  * We're copying first_dir to second_dir.
  */
 static void
-test_copy_first_hierarchy (void)
+test_copy_full_directory (void)
 {
     g_autoptr (GFile) root = NULL;
     g_autoptr (GFile) first_dir = NULL;
@@ -401,39 +693,76 @@ test_copy_first_hierarchy (void)
     g_autoptr (GFile) result_file = NULL;
     g_autolist (GFile) files = NULL;
 
+    create_one_file ("copy");
+
     root = g_file_new_for_path (g_get_tmp_dir ());
+    g_assert_true (root != NULL);
+
     first_dir = g_file_get_child (root, "copy_first_dir");
     files = g_list_prepend (files, g_object_ref (first_dir));
     g_assert_true (first_dir != NULL);
-    g_file_make_directory (first_dir, NULL, NULL);
 
     file = g_file_get_child (first_dir, "copy_first_dir_child");
     g_assert_true (file != NULL);
-    g_file_make_directory (file, NULL, NULL);
 
     second_dir = g_file_get_child (root, "copy_second_dir");
     g_assert_true (second_dir != NULL);
-    g_file_make_directory (second_dir, NULL, NULL);
 
     nautilus_file_operations_copy_sync (files,
-                                        second_dir,
-                                        NULL,
-                                        NULL,
-                                        NULL);
+                                        second_dir);
 
     result_file = g_file_get_child (second_dir, "copy_first_dir");
     g_assert_true (g_file_query_exists (result_file, NULL));
     file = g_file_get_child (result_file, "copy_first_dir_child");
     g_assert_true (g_file_query_exists (file, NULL));
 
-    g_assert_true (g_file_delete (file, NULL, NULL));
-    g_assert_true (g_file_delete (result_file, NULL, NULL));
-    g_assert_true (g_file_delete (second_dir, NULL, NULL));
+    file = g_file_get_child (first_dir, "copy_first_dir_child");
+    g_assert_true (g_file_query_exists (file, NULL));
+    g_assert_true (g_file_query_exists (first_dir, NULL));
+
+    empty_directory_by_prefix (root, "copy");
+}
+
+static void
+test_copy_full_directory_undo (void)
+{
+    g_autoptr (GFile) root = NULL;
+    g_autoptr (GFile) first_dir = NULL;
+    g_autoptr (GFile) second_dir = NULL;
+    g_autoptr (GFile) file = NULL;
+    g_autoptr (GFile) result_file = NULL;
+    g_autolist (GFile) files = NULL;
+
+    create_one_file ("copy");
+
+    root = g_file_new_for_path (g_get_tmp_dir ());
+    g_assert_true (root != NULL);
+
+    first_dir = g_file_get_child (root, "copy_first_dir");
+    files = g_list_prepend (files, g_object_ref (first_dir));
+    g_assert_true (first_dir != NULL);
+
+    file = g_file_get_child (first_dir, "copy_first_dir_child");
+    g_assert_true (file != NULL);
+
+    second_dir = g_file_get_child (root, "copy_second_dir");
+    g_assert_true (second_dir != NULL);
+
+    nautilus_file_operations_copy_sync (files,
+                                        second_dir);
+
+    test_operation_undo ();
+
+    result_file = g_file_get_child (second_dir, "copy_first_dir");
+    g_assert_false (g_file_query_exists (result_file, NULL));
+    file = g_file_get_child (result_file, "copy_first_dir_child");
+    g_assert_false (g_file_query_exists (file, NULL));
 
     file = g_file_get_child (first_dir, "copy_first_dir_child");
     g_assert_true (g_file_query_exists (file, NULL));
-    g_assert_true (g_file_delete (file, NULL, NULL));
     g_assert_true (g_file_query_exists (first_dir, NULL));
+
+    empty_directory_by_prefix (root, "copy");
 }
 
 /* The hierarchy looks like this:
@@ -443,7 +772,7 @@ test_copy_first_hierarchy (void)
  * We're copying first_dir to second_dir.
  */
 static void
-test_copy_second_hierarchy (void)
+test_copy_first_hierarchy (void)
 {
     g_autoptr (GFile) root = NULL;
     g_autoptr (GFile) first_dir = NULL;
@@ -452,52 +781,94 @@ test_copy_second_hierarchy (void)
     g_autoptr (GFile) result_file = NULL;
     g_autolist (GFile) files = NULL;
 
+    create_first_hierarchy ("copy");
+
     root = g_file_new_for_path (g_get_tmp_dir ());
+    g_assert_true (root != NULL);
+
     first_dir = g_file_get_child (root, "copy_first_dir");
     files = g_list_prepend (files, g_object_ref (first_dir));
     g_assert_true (first_dir != NULL);
-    g_file_make_directory (first_dir, NULL, NULL);
 
     file = g_file_get_child (first_dir, "copy_first_child");
     g_assert_true (file != NULL);
-    g_file_make_directory (file, NULL, NULL);
     file = g_file_get_child (first_dir, "copy_second_child");
     g_assert_true (file != NULL);
-    g_file_make_directory (file, NULL, NULL);
 
     second_dir = g_file_get_child (root, "copy_second_dir");
     g_assert_true (second_dir != NULL);
-    g_file_make_directory (second_dir, NULL, NULL);
 
     nautilus_file_operations_copy_sync (files,
-                                        second_dir,
-                                        NULL,
-                                        NULL,
-                                        NULL);
+                                        second_dir);
 
     result_file = g_file_get_child (second_dir, "copy_first_dir");
     g_assert_true (g_file_query_exists (result_file, NULL));
     file = g_file_get_child (result_file, "copy_first_child");
     g_assert_true (g_file_query_exists (file, NULL));
-    g_assert_true (g_file_delete (file, NULL, NULL));
 
     file = g_file_get_child (result_file, "copy_second_child");
     g_assert_true (g_file_query_exists (file, NULL));
-    g_assert_true (g_file_delete (file, NULL, NULL));
 
-    g_assert_true (g_file_delete (result_file, NULL, NULL));
+    file = g_file_get_child (first_dir, "copy_first_child");
+    g_assert_true (g_file_query_exists (file, NULL));
+
+    file = g_file_get_child (first_dir, "copy_second_child");
+    g_assert_true (g_file_query_exists (file, NULL));
+
+    g_assert_true (g_file_query_exists (first_dir, NULL));
+
+    empty_directory_by_prefix (root, "copy");
+}
+
+static void
+test_copy_first_hierarchy_undo (void)
+{
+    g_autoptr (GFile) root = NULL;
+    g_autoptr (GFile) first_dir = NULL;
+    g_autoptr (GFile) second_dir = NULL;
+    g_autoptr (GFile) file = NULL;
+    g_autoptr (GFile) result_file = NULL;
+    g_autolist (GFile) files = NULL;
+
+    create_first_hierarchy ("copy");
+
+    root = g_file_new_for_path (g_get_tmp_dir ());
+    g_assert_true (root != NULL);
+
+    first_dir = g_file_get_child (root, "copy_first_dir");
+    files = g_list_prepend (files, g_object_ref (first_dir));
+    g_assert_true (first_dir != NULL);
+
+    file = g_file_get_child (first_dir, "copy_first_child");
+    g_assert_true (file != NULL);
+    file = g_file_get_child (first_dir, "copy_second_child");
+    g_assert_true (file != NULL);
+
+    second_dir = g_file_get_child (root, "copy_second_dir");
+    g_assert_true (second_dir != NULL);
+
+    nautilus_file_operations_copy_sync (files,
+                                        second_dir);
+
+    test_operation_undo ();
+
+    result_file = g_file_get_child (second_dir, "copy_first_dir");
+    g_assert_false (g_file_query_exists (result_file, NULL));
+    file = g_file_get_child (result_file, "copy_first_child");
+    g_assert_false (g_file_query_exists (file, NULL));
+
+    file = g_file_get_child (result_file, "copy_second_child");
+    g_assert_false (g_file_query_exists (file, NULL));
 
     file = g_file_get_child (first_dir, "copy_first_child");
     g_assert_true (g_file_query_exists (file, NULL));
-    g_file_delete (file, NULL, NULL);
 
     file = g_file_get_child (first_dir, "copy_second_child");
     g_assert_true (g_file_query_exists (file, NULL));
-    g_file_delete (file, NULL, NULL);    
 
     g_assert_true (g_file_query_exists (first_dir, NULL));
-    g_file_delete (first_dir, NULL, NULL);
-    g_assert_true (g_file_delete (second_dir, NULL, NULL));
+
+    empty_directory_by_prefix (root, "copy");
 }
 
 /* The hierarchy looks like this:
@@ -506,7 +877,7 @@ test_copy_second_hierarchy (void)
  * We're copying first_dir to second_dir.
  */
 static void
-test_copy_third_hierarchy (void)
+test_copy_second_hierarchy (void)
 {
     g_autoptr (GFile) root = NULL;
     g_autoptr (GFile) first_dir = NULL;
@@ -515,28 +886,23 @@ test_copy_third_hierarchy (void)
     g_autoptr (GFile) result_file = NULL;
     g_autolist (GFile) files = NULL;
 
+    create_second_hierarchy ("copy");
+
     root = g_file_new_for_path (g_get_tmp_dir ());
     first_dir = g_file_get_child (root, "copy_first_dir");
     files = g_list_prepend (files, g_object_ref (first_dir));
     g_assert_true (first_dir != NULL);
-    g_file_make_directory (first_dir, NULL, NULL);
 
     file = g_file_get_child (first_dir, "copy_first_child");
     g_assert_true (file != NULL);
-    g_file_make_directory (file, NULL, NULL);
     file = g_file_get_child (file, "copy_second_child");
     g_assert_true (file != NULL);
-    g_file_make_directory (file, NULL, NULL);
 
     second_dir = g_file_get_child (root, "copy_second_dir");
     g_assert_true (second_dir != NULL);
-    g_file_make_directory (second_dir, NULL, NULL);
 
     nautilus_file_operations_copy_sync (files,
-                                        second_dir,
-                                        NULL,
-                                        NULL,
-                                        NULL);
+                                        second_dir);
 
     result_file = g_file_get_child (second_dir, "copy_first_dir");
     g_assert_true (g_file_query_exists (result_file, NULL));
@@ -545,24 +911,67 @@ test_copy_third_hierarchy (void)
 
     file = g_file_get_child (file, "copy_second_child");
     g_assert_true (g_file_query_exists (file, NULL));
-    g_assert_true (g_file_delete (file, NULL, NULL));
 
     file = g_file_get_child (result_file, "copy_first_child");
     g_assert_true (g_file_query_exists (file, NULL));
-    g_assert_true (g_file_delete (file, NULL, NULL));
 
-    g_assert_true (g_file_delete (result_file, NULL, NULL));
+    file = g_file_get_child (first_dir, "copy_first_child");
+    file = g_file_get_child (file, "copy_second_child");
+
+    file = g_file_get_child (first_dir, "copy_first_child");
+
+    empty_directory_by_prefix (root, "copy");
+}
+
+static void
+test_copy_second_hierarchy_undo (void)
+{
+    g_autoptr (GFile) root = NULL;
+    g_autoptr (GFile) first_dir = NULL;
+    g_autoptr (GFile) second_dir = NULL;
+    g_autoptr (GFile) file = NULL;
+    g_autoptr (GFile) result_file = NULL;
+    g_autolist (GFile) files = NULL;
+
+    create_second_hierarchy ("copy");
+
+    root = g_file_new_for_path (g_get_tmp_dir ());
+    g_assert_true (root != NULL);
+
+    first_dir = g_file_get_child (root, "copy_first_dir");
+    files = g_list_prepend (files, g_object_ref (first_dir));
+    g_assert_true (first_dir != NULL);
 
     file = g_file_get_child (first_dir, "copy_first_child");
+    g_assert_true (file != NULL);
+    file = g_file_get_child (file, "copy_second_child");
+    g_assert_true (file != NULL);
+
+    second_dir = g_file_get_child (root, "copy_second_dir");
+    g_assert_true (second_dir != NULL);
+
+    nautilus_file_operations_copy_sync (files,
+                                        second_dir);
+
+    test_operation_undo ();
+
+    result_file = g_file_get_child (second_dir, "copy_first_dir");
+    g_assert_false (g_file_query_exists (result_file, NULL));
+    file = g_file_get_child (result_file, "copy_first_child");
+    g_assert_false (g_file_query_exists (file, NULL));
+
     file = g_file_get_child (file, "copy_second_child");
-    g_assert_true (g_file_delete (file, NULL, NULL));
+    g_assert_false (g_file_query_exists (file, NULL));
+
+    file = g_file_get_child (result_file, "copy_first_child");
+    g_assert_false (g_file_query_exists (file, NULL));
 
     file = g_file_get_child (first_dir, "copy_first_child");
-    g_assert_true (g_file_delete (file, NULL, NULL));
+    file = g_file_get_child (file, "copy_second_child");
 
-    g_assert_true (g_file_delete (first_dir, NULL, NULL));
+    file = g_file_get_child (first_dir, "copy_first_child");
 
-    g_assert_true (g_file_delete (second_dir, NULL, NULL));
+    empty_directory_by_prefix (root, "copy");
 }
 
 /* The hierarchy looks like this:
@@ -572,7 +981,7 @@ test_copy_third_hierarchy (void)
  * We're copying first_dir to second_dir.
  */
 static void
-test_copy_fourth_hierarchy (void)
+test_copy_third_hierarchy (void)
 {
     g_autoptr (GFile) root = NULL;
     g_autoptr (GFile) first_dir = NULL;
@@ -581,37 +990,32 @@ test_copy_fourth_hierarchy (void)
     g_autoptr (GFile) result_file = NULL;
     g_autolist (GFile) files = NULL;
 
+    create_third_hierarchy ("copy");
+
     root = g_file_new_for_path (g_get_tmp_dir ());
+    g_assert_true (root != NULL);
+
     first_dir = g_file_get_child (root, "copy_first_dir");
     files = g_list_prepend (files, g_object_ref (first_dir));
     g_assert_true (first_dir != NULL);
-    g_file_make_directory (first_dir, NULL, NULL);
 
     file = g_file_get_child (first_dir, "copy_first_dir_dir1");
     g_assert_true (file != NULL);
-    g_file_make_directory (file, NULL, NULL);
 
     file = g_file_get_child (file, "copy_dir1_child");
     g_assert_true (file != NULL);
-    g_file_make_directory (file, NULL, NULL);
 
     file = g_file_get_child (first_dir, "copy_first_dir_dir2");
     g_assert_true (file != NULL);
-    g_file_make_directory (file, NULL, NULL);
 
     file = g_file_get_child (file, "copy_dir2_child");
     g_assert_true (file != NULL);
-    g_file_make_directory (file, NULL, NULL);
 
     second_dir = g_file_get_child (root, "copy_second_dir");
     g_assert_true (second_dir != NULL);
-    g_file_make_directory (second_dir, NULL, NULL);
 
     nautilus_file_operations_copy_sync (files,
-                                        second_dir,
-                                        NULL,
-                                        NULL,
-                                        NULL);
+                                        second_dir);
 
     result_file = g_file_get_child (second_dir, "copy_first_dir");
 
@@ -620,41 +1024,100 @@ test_copy_fourth_hierarchy (void)
     g_assert_true (g_file_query_exists (file, NULL));
     file = g_file_get_child (file, "copy_dir1_child");
     g_assert_true (g_file_query_exists (file, NULL));
-    g_assert_true (g_file_delete (file, NULL, NULL));
     file = g_file_get_child (result_file, "copy_first_dir_dir1");
-    g_assert_true (g_file_delete (file, NULL, NULL));
 
     file = g_file_get_child (result_file, "copy_first_dir_dir2");
     g_assert_true (g_file_query_exists (file, NULL));
     file = g_file_get_child (file, "copy_dir2_child");
     g_assert_true (g_file_query_exists (file, NULL));
-    g_assert_true (g_file_delete (file, NULL, NULL));
     file = g_file_get_child (result_file, "copy_first_dir_dir2");
-    g_assert_true (g_file_delete (file, NULL, NULL));
 
-    g_assert_true (g_file_delete (result_file, NULL, NULL));
+    file = g_file_get_child (first_dir, "copy_first_dir_dir1");
+    g_assert_true (g_file_query_exists (file, NULL));
+    file = g_file_get_child (file, "copy_dir1_child");
+    g_assert_true (g_file_query_exists (file, NULL));
+    file = g_file_get_child (first_dir, "copy_first_dir_dir1");
+
+    file = g_file_get_child (first_dir, "copy_first_dir_dir2");
+    g_assert_true (g_file_query_exists (file, NULL));
+    file = g_file_get_child (file, "copy_dir2_child");
+    g_assert_true (g_file_query_exists (file, NULL));
+    file = g_file_get_child (first_dir, "copy_first_dir_dir2");
+    g_assert_true (g_file_query_exists (file, NULL));
+
+    g_assert_true (g_file_query_exists (first_dir, NULL));
+
+    empty_directory_by_prefix (root, "copy");
+}
+
+static void
+test_copy_third_hierarchy_undo (void)
+{
+    g_autoptr (GFile) root = NULL;
+    g_autoptr (GFile) first_dir = NULL;
+    g_autoptr (GFile) second_dir = NULL;
+    g_autoptr (GFile) file = NULL;
+    g_autoptr (GFile) result_file = NULL;
+    g_autolist (GFile) files = NULL;
+
+    create_third_hierarchy ("copy");
+
+    root = g_file_new_for_path (g_get_tmp_dir ());
+    g_assert_true (root != NULL);
+
+    first_dir = g_file_get_child (root, "copy_first_dir");
+    files = g_list_prepend (files, g_object_ref (first_dir));
+    g_assert_true (first_dir != NULL);
+
+    file = g_file_get_child (first_dir, "copy_first_dir_dir1");
+    g_assert_true (file != NULL);
+
+    file = g_file_get_child (file, "copy_dir1_child");
+    g_assert_true (file != NULL);
+
+    file = g_file_get_child (first_dir, "copy_first_dir_dir2");
+    g_assert_true (file != NULL);
+
+    file = g_file_get_child (file, "copy_dir2_child");
+    g_assert_true (file != NULL);
+
+    second_dir = g_file_get_child (root, "copy_second_dir");
+    g_assert_true (second_dir != NULL);
+
+    nautilus_file_operations_copy_sync (files,
+                                        second_dir);
+
+    test_operation_undo ();
+
+    result_file = g_file_get_child (second_dir, "copy_first_dir");
+
+    g_assert_false (g_file_query_exists (result_file, NULL));
+    file = g_file_get_child (result_file, "copy_first_dir_dir1");
+    g_assert_false (g_file_query_exists (file, NULL));
+    file = g_file_get_child (file, "copy_dir1_child");
+    g_assert_false (g_file_query_exists (file, NULL));
+
+    file = g_file_get_child (result_file, "copy_first_dir_dir2");
+    g_assert_false (g_file_query_exists (file, NULL));
+    file = g_file_get_child (file, "copy_dir2_child");
+    g_assert_false (g_file_query_exists (file, NULL));
 
     file = g_file_get_child (first_dir, "copy_first_dir_dir1");
     g_assert_true (g_file_query_exists (file, NULL));
     file = g_file_get_child (file, "copy_dir1_child");
     g_assert_true (g_file_query_exists (file, NULL));
-    g_assert_true (g_file_delete (file, NULL, NULL));
     file = g_file_get_child (first_dir, "copy_first_dir_dir1");
-    g_assert_true (g_file_delete (file, NULL, NULL));
 
     file = g_file_get_child (first_dir, "copy_first_dir_dir2");
     g_assert_true (g_file_query_exists (file, NULL));
     file = g_file_get_child (file, "copy_dir2_child");
     g_assert_true (g_file_query_exists (file, NULL));
-    g_assert_true  (g_file_delete (file, NULL, NULL));
     file = g_file_get_child (first_dir, "copy_first_dir_dir2");
     g_assert_true (g_file_query_exists (file, NULL));
-    g_assert_true (g_file_delete (file, NULL, NULL));
 
     g_assert_true (g_file_query_exists (first_dir, NULL));
-    g_assert_true (g_file_delete (first_dir, NULL, NULL));
 
-    g_assert_true (g_file_delete (second_dir, NULL, NULL));
+    empty_directory_by_prefix (root, "copy");
 }
 
 /* The hierarchy looks like this:
@@ -664,7 +1127,7 @@ test_copy_fourth_hierarchy (void)
  * We're copying first_dir and second_dir to third_dir.
  */
 static void
-test_copy_fifth_hierarchy (void)
+test_copy_fourth_hierarchy (void)
 {
     g_autoptr (GFile) root = NULL;
     g_autoptr (GFile) first_dir = NULL;
@@ -674,62 +1137,109 @@ test_copy_fifth_hierarchy (void)
     g_autoptr (GFile) result_file = NULL;
     g_autolist (GFile) files = NULL;
 
+    create_fourth_hierarchy ("copy");
+
     root = g_file_new_for_path (g_get_tmp_dir ());
+    g_assert_true (root != NULL);
+
     first_dir = g_file_get_child (root, "copy_first_dir");
     files = g_list_prepend (files, g_object_ref (first_dir));
     g_assert_true (first_dir != NULL);
-    g_file_make_directory (first_dir, NULL, NULL);
 
     file = g_file_get_child (first_dir, "copy_first_dir_child");
     g_assert_true (file != NULL);
-    g_file_make_directory (file, NULL, NULL);
 
     second_dir = g_file_get_child (root, "copy_second_dir");
     files = g_list_prepend (files, g_object_ref (second_dir));
     g_assert_true (second_dir != NULL);
-    g_file_make_directory (second_dir, NULL, NULL);
 
     file = g_file_get_child (second_dir, "copy_second_dir_child");
     g_assert_true (file != NULL);
-    g_file_make_directory (file, NULL, NULL);
 
     third_dir = g_file_get_child (root, "copy_third_dir");
     g_assert_true (third_dir != NULL);
-    g_file_make_directory (third_dir, NULL, NULL);
 
     nautilus_file_operations_copy_sync (files,
-                                        third_dir,
-                                        NULL,
-                                        NULL,
-                                        NULL);
+                                        third_dir);
 
     result_file = g_file_get_child (third_dir, "copy_first_dir");
     g_assert_true (g_file_query_exists (result_file, NULL));
     file = g_file_get_child (result_file, "copy_first_dir_child");
     g_assert_true (g_file_query_exists (file, NULL));
-    g_assert_true (g_file_delete (file, NULL, NULL));
-    g_assert_true (g_file_delete (result_file, NULL, NULL));
 
     result_file = g_file_get_child (third_dir, "copy_second_dir");
     g_assert_true (g_file_query_exists (result_file, NULL));
     file = g_file_get_child (result_file, "copy_second_dir_child");
     g_assert_true (g_file_query_exists (file, NULL));
-    g_assert_true (g_file_delete (file, NULL, NULL));
-    g_assert_true (g_file_delete (result_file, NULL, NULL));
 
     file = g_file_get_child (first_dir, "copy_first_dir_child");
     g_assert_true (g_file_query_exists (file, NULL));
-    g_assert_true (g_file_delete (file, NULL, NULL));
     g_assert_true (g_file_query_exists (first_dir, NULL));
-    g_assert_true (g_file_delete (first_dir, NULL, NULL));
 
     file = g_file_get_child (second_dir, "copy_second_dir_child");
     g_assert_true (g_file_query_exists (file, NULL));
-    g_assert_true (g_file_delete (file, NULL, NULL));
     g_assert_true (g_file_query_exists (second_dir, NULL));
-    g_assert_true (g_file_delete (second_dir, NULL, NULL));
 
-    g_assert_true (g_file_delete (third_dir, NULL, NULL));
+    empty_directory_by_prefix (root, "copy");
+}
+
+static void
+test_copy_fourth_hierarchy_undo (void)
+{
+    g_autoptr (GFile) root = NULL;
+    g_autoptr (GFile) first_dir = NULL;
+    g_autoptr (GFile) second_dir = NULL;
+    g_autoptr (GFile) third_dir = NULL;
+    g_autoptr (GFile) file = NULL;
+    g_autoptr (GFile) result_file = NULL;
+    g_autolist (GFile) files = NULL;
+
+    create_fourth_hierarchy ("copy");
+
+    root = g_file_new_for_path (g_get_tmp_dir ());
+    g_assert_true (root != NULL);
+
+    first_dir = g_file_get_child (root, "copy_first_dir");
+    files = g_list_prepend (files, g_object_ref (first_dir));
+    g_assert_true (first_dir != NULL);
+
+    file = g_file_get_child (first_dir, "copy_first_dir_child");
+    g_assert_true (file != NULL);
+
+    second_dir = g_file_get_child (root, "copy_second_dir");
+    files = g_list_prepend (files, g_object_ref (second_dir));
+    g_assert_true (second_dir != NULL);
+
+    file = g_file_get_child (second_dir, "copy_second_dir_child");
+    g_assert_true (file != NULL);
+
+    third_dir = g_file_get_child (root, "copy_third_dir");
+    g_assert_true (third_dir != NULL);
+
+    nautilus_file_operations_copy_sync (files,
+                                        third_dir);
+
+    test_operation_undo ();
+
+    result_file = g_file_get_child (third_dir, "copy_first_dir");
+    g_assert_false (g_file_query_exists (result_file, NULL));
+    file = g_file_get_child (result_file, "copy_first_dir_child");
+    g_assert_false (g_file_query_exists (file, NULL));
+
+    result_file = g_file_get_child (third_dir, "copy_second_dir");
+    g_assert_false (g_file_query_exists (result_file, NULL));
+    file = g_file_get_child (result_file, "copy_second_dir_child");
+    g_assert_false (g_file_query_exists (file, NULL));
+
+    file = g_file_get_child (first_dir, "copy_first_dir_child");
+    g_assert_true (g_file_query_exists (file, NULL));
+    g_assert_true (g_file_query_exists (first_dir, NULL));
+
+    file = g_file_get_child (second_dir, "copy_second_dir_child");
+    g_assert_true (g_file_query_exists (file, NULL));
+    g_assert_true (g_file_query_exists (second_dir, NULL));
+
+    empty_directory_by_prefix (root, "copy");
 }
 
 static void
@@ -737,30 +1247,56 @@ setup_test_suite (void)
 {
     g_test_add_func ("/test-copy-one-file/1.0",
                      test_copy_one_file);
+    g_test_add_func ("/test-copy-one-file-undo/1.0",
+                     test_copy_one_file_undo);
     g_test_add_func ("/test-copy-one-empty-directory/1.0",
                      test_copy_one_empty_directory);
+    g_test_add_func ("/test-copy-one-empty-directory-undo/1.0",
+                     test_copy_one_empty_directory_undo);
     g_test_add_func ("/test-copy-files/1.0",
                      test_copy_files_small);
+    g_test_add_func ("/test-copy-files-undo/1.0",
+                     test_copy_files_small_undo);
     g_test_add_func ("/test-copy-files/1.1",
                      test_copy_files_medium);
+    g_test_add_func ("/test-copy-files-undo/1.1",
+                     test_copy_files_medium_undo);
     g_test_add_func ("/test-copy-files/1.2",
                      test_copy_files_large);
+    g_test_add_func ("/test-copy-files-undo/1.2",
+                     test_copy_files_large_undo);
     g_test_add_func ("/test-copy-directories/1.0",
                      test_copy_directories_small);
+    g_test_add_func ("/test-copy-directories-undo/1.0",
+                     test_copy_directories_small_undo);
     g_test_add_func ("/test-copy-directories/1.1",
                      test_copy_directories_medium);
+    g_test_add_func ("/test-copy-directories-undo/1.1",
+                     test_copy_directories_medium_undo);
     g_test_add_func ("/test-copy-directories/1.2",
                      test_copy_directories_large);
+    g_test_add_func ("/test-copy-directories-undo/1.2",
+                     test_copy_directories_large_undo);
     g_test_add_func ("/test-copy-hierarchy/1.0",
-                     test_copy_first_hierarchy);
+                     test_copy_full_directory);
+    g_test_add_func ("/test-copy-hierarchy-undo/1.0",
+                     test_copy_full_directory_undo);
     g_test_add_func ("/test-copy-hierarchy/1.1",
-                     test_copy_second_hierarchy);
+                     test_copy_first_hierarchy);
+    g_test_add_func ("/test-copy-hierarchy-undo/1.1",
+                     test_copy_first_hierarchy_undo);
     g_test_add_func ("/test-copy-hierarchy/1.2",
-                     test_copy_third_hierarchy);
+                     test_copy_second_hierarchy);
+    g_test_add_func ("/test-copy-hierarchy-undo/1.2",
+                     test_copy_second_hierarchy_undo);
     g_test_add_func ("/test-copy-hierarchy/1.3",
-                     test_copy_fourth_hierarchy);
+                     test_copy_third_hierarchy);
+    g_test_add_func ("/test-copy-hierarchy-undo/1.3",
+                     test_copy_third_hierarchy_undo);
     g_test_add_func ("/test-copy-hierarchy/1.4",
-                     test_copy_fifth_hierarchy);
+                     test_copy_fourth_hierarchy);
+    g_test_add_func ("/test-copy-hierarchy-undo/1.4",
+                     test_copy_fourth_hierarchy_undo);
 }
 
 int
@@ -768,10 +1304,10 @@ main (int argc, char *argv[])
 {
     g_autoptr (NautilusFileUndoManager) undo_manager = NULL;
 
+    undo_manager = nautilus_file_undo_manager_new ();
     g_test_init (&argc, &argv, NULL);
     g_test_set_nonfatal_assertions ();
     nautilus_ensure_extension_points();
-    undo_manager = nautilus_file_undo_manager_new ();
 
     setup_test_suite ();
 
diff --git a/test/automated/displayless/test-file-operations-move-files.c 
b/test/automated/displayless/test-file-operations-move-files.c
index 1b2e678aa..6b476e7fa 100644
--- a/test/automated/displayless/test-file-operations-move-files.c
+++ b/test/automated/displayless/test-file-operations-move-files.c
@@ -1,13 +1,4 @@
-#include <glib.h>
-#include <glib/gprintf.h>
-#include "src/nautilus-directory.h"
-#include "src/nautilus-file-utilities.h"
-#include "src/nautilus-search-directory.h"
-#include "src/nautilus-directory.h"
-#include "src/nautilus-file-operations.c"
-#include "src/nautilus-file-undo-manager.h"
-#include <unistd.h>
-#include "eel/eel-string.h"
+#include "test-utilities.h"
 
 static void
 test_move_one_file (void)
@@ -18,40 +9,107 @@ test_move_one_file (void)
     g_autoptr (GFile) file = NULL;
     g_autoptr (GFile) result_file = NULL;
     g_autolist (GFile) files = NULL;
-    GFileOutputStream *out = NULL;
-    g_autoptr (GError) error = NULL;
+
+    create_one_file ("move");
 
     root = g_file_new_for_path (g_get_tmp_dir ());
-    first_dir = g_file_get_child (root, "first_dir");
+    g_assert_true (root != NULL);
+
+    first_dir = g_file_get_child (root, "move_first_dir");
     g_assert_true (first_dir != NULL);
-    g_file_make_directory (first_dir, NULL, NULL);
 
-    file = g_file_get_child (first_dir, "first_dir_child");
+    file = g_file_get_child (first_dir, "move_first_dir_child");
     g_assert_true (file != NULL);
-    out = g_file_create (file, G_FILE_CREATE_NONE, NULL, &error);
-    if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_EXISTS))
-    {
-        g_object_unref (out);
-    }
     files = g_list_prepend (files, g_object_ref (file));
 
-    second_dir = g_file_get_child (root, "second_dir");
+    second_dir = g_file_get_child (root, "move_second_dir");
     g_assert_true (second_dir != NULL);
-    g_file_make_directory (second_dir, NULL, NULL);
 
     nautilus_file_operations_move_sync (files,
-                                        second_dir,
-                                        NULL,
-                                        NULL,
-                                        NULL);
+                                        second_dir);
+
+    result_file = g_file_get_child (second_dir, "move_first_dir_child");
 
-    result_file = g_file_get_child (second_dir, "first_dir_child");
     g_assert_true (g_file_query_exists (result_file, NULL));
     g_assert_false (g_file_query_exists (file, NULL));
 
-    g_assert_true (g_file_delete (result_file, NULL, NULL));
-    g_assert_true (g_file_delete (first_dir, NULL, NULL));
-    g_assert_true (g_file_delete (second_dir, NULL, NULL));
+    empty_directory_by_prefix (root, "move");
+}
+
+static void
+test_move_one_file_undo (void)
+{
+    g_autoptr (GFile) root = NULL;
+    g_autoptr (GFile) first_dir = NULL;
+    g_autoptr (GFile) second_dir = NULL;
+    g_autoptr (GFile) file = NULL;
+    g_autoptr (GFile) result_file = NULL;
+    g_autolist (GFile) files = NULL;
+
+    create_one_file ("move");
+
+    root = g_file_new_for_path (g_get_tmp_dir ());
+    g_assert_true (root != NULL);
+
+    first_dir = g_file_get_child (root, "move_first_dir");
+    g_assert_true (first_dir != NULL);
+
+    file = g_file_get_child (first_dir, "move_first_dir_child");
+    g_assert_true (file != NULL);
+    files = g_list_prepend (files, g_object_ref (file));
+
+    second_dir = g_file_get_child (root, "move_second_dir");
+    g_assert_true (second_dir != NULL);
+
+    nautilus_file_operations_move_sync (files,
+                                        second_dir);
+
+    test_operation_undo ();
+
+    result_file = g_file_get_child (second_dir, "move_first_dir_child");
+
+    g_assert_false (g_file_query_exists (result_file, NULL));
+    g_assert_true (g_file_query_exists (file, NULL));
+
+    empty_directory_by_prefix (root, "move");
+}
+
+static void
+test_move_one_file_undo_redo (void)
+{
+    g_autoptr (GFile) root = NULL;
+    g_autoptr (GFile) first_dir = NULL;
+    g_autoptr (GFile) second_dir = NULL;
+    g_autoptr (GFile) file = NULL;
+    g_autoptr (GFile) result_file = NULL;
+    g_autolist (GFile) files = NULL;
+
+    create_one_file ("move");
+
+    root = g_file_new_for_path (g_get_tmp_dir ());
+    g_assert_true (root != NULL);
+
+    first_dir = g_file_get_child (root, "move_first_dir");
+    g_assert_true (first_dir != NULL);
+
+    file = g_file_get_child (first_dir, "move_first_dir_child");
+    g_assert_true (file != NULL);
+    files = g_list_prepend (files, g_object_ref (file));
+
+    second_dir = g_file_get_child (root, "move_second_dir");
+    g_assert_true (second_dir != NULL);
+
+    nautilus_file_operations_move_sync (files,
+                                        second_dir);
+
+    test_operation_undo_redo ();
+
+    result_file = g_file_get_child (second_dir, "move_first_dir_child");
+
+    g_assert_true (g_file_query_exists (result_file, NULL));
+    g_assert_false (g_file_query_exists (file, NULL));
+
+    empty_directory_by_prefix (root, "move");
 }
 
 static void
@@ -64,321 +122,1288 @@ test_move_one_empty_directory (void)
     g_autoptr (GFile) result_file = NULL;
     g_autolist (GFile) files = NULL;
 
+    create_one_empty_directory ("move");
+
+    root = g_file_new_for_path (g_get_tmp_dir ());
+    g_assert_true (root != NULL);
+
+    first_dir = g_file_get_child (root, "move_first_dir");
+    g_assert_true (first_dir != NULL);
+
+    file = g_file_get_child (first_dir, "move_first_dir_child");
+    g_assert_true (file != NULL);
+    files = g_list_prepend (files, g_object_ref (file));
+
+    second_dir = g_file_get_child (root, "move_second_dir");
+    g_assert_true (second_dir != NULL);
+
+    nautilus_file_operations_move_sync (files,
+                                        second_dir);
+
+    result_file = g_file_get_child (second_dir, "move_first_dir_child");
+    g_assert_true (g_file_query_exists (result_file, NULL));
+    g_assert_false (g_file_query_exists (file, NULL));
+
+    empty_directory_by_prefix (root, "move");
+}
+
+static void
+test_move_one_empty_directory_undo (void)
+{
+    g_autoptr (GFile) root = NULL;
+    g_autoptr (GFile) first_dir = NULL;
+    g_autoptr (GFile) second_dir = NULL;
+    g_autoptr (GFile) file = NULL;
+    g_autoptr (GFile) result_file = NULL;
+    g_autolist (GFile) files = NULL;
+
+    create_one_empty_directory ("move");
+ 
     root = g_file_new_for_path (g_get_tmp_dir ());
-    first_dir = g_file_get_child (root, "first_dir");
+    g_assert_true (root != NULL);
+
+    first_dir = g_file_get_child (root, "move_first_dir");
     g_assert_true (first_dir != NULL);
-    g_file_make_directory (first_dir, NULL, NULL);
 
-    file = g_file_get_child (first_dir, "first_dir_child");
+    file = g_file_get_child (first_dir, "move_first_dir_child");
     g_assert_true (file != NULL);
-    g_file_make_directory (file, NULL, NULL);
     files = g_list_prepend (files, g_object_ref (file));
 
-    second_dir = g_file_get_child (root, "second_dir");
+    second_dir = g_file_get_child (root, "move_second_dir");
     g_assert_true (second_dir != NULL);
-    g_file_make_directory (second_dir, NULL, NULL);
 
     nautilus_file_operations_move_sync (files,
-                                        second_dir,
-                                        NULL,
-                                        NULL,
-                                        NULL);
+                                        second_dir);
+
+    test_operation_undo ();
+
+    result_file = g_file_get_child (second_dir, "move_first_dir_child");
+    g_assert_false (g_file_query_exists (result_file, NULL));
+    g_assert_true (g_file_query_exists (file, NULL));
+
+    empty_directory_by_prefix (root, "move");
+}
+
+static void
+test_move_one_empty_directory_undo_redo (void)
+{
+    g_autoptr (GFile) root = NULL;
+    g_autoptr (GFile) first_dir = NULL;
+    g_autoptr (GFile) second_dir = NULL;
+    g_autoptr (GFile) file = NULL;
+    g_autoptr (GFile) result_file = NULL;
+    g_autolist (GFile) files = NULL;
+
+    create_one_empty_directory ("move");
+
+    root = g_file_new_for_path (g_get_tmp_dir ());
+    g_assert_true (root != NULL);
+
+    first_dir = g_file_get_child (root, "move_first_dir");
+    g_assert_true (first_dir != NULL);
+
+    file = g_file_get_child (first_dir, "move_first_dir_child");
+    g_assert_true (file != NULL);
+    files = g_list_prepend (files, g_object_ref (file));
+
+    second_dir = g_file_get_child (root, "move_second_dir");
+    g_assert_true (second_dir != NULL);
+
+    nautilus_file_operations_move_sync (files,
+                                        second_dir);
+
+    test_operation_undo_redo ();
 
-    result_file = g_file_get_child (second_dir, "first_dir_child");
+    result_file = g_file_get_child (second_dir, "move_first_dir_child");
     g_assert_true (g_file_query_exists (result_file, NULL));
     g_assert_false (g_file_query_exists (file, NULL));
 
-    g_assert_true (g_file_delete (result_file, NULL, NULL));
-    g_assert_true (g_file_delete (first_dir, NULL, NULL));
-    g_assert_true (g_file_delete (second_dir, NULL, NULL));
+    empty_directory_by_prefix (root, "move");
 }
 
 static void
-test_move_directories_small (void)
+test_move_files_small (void)
 {
     g_autoptr (GFile) root = NULL;
     g_autoptr (GFile) file = NULL;
     g_autoptr (GFile) dir = NULL;
     g_autolist (GFile) files = NULL;
-    g_autofree gchar *file_name = NULL;
+    gchar *file_name;
+
+    create_multiple_files ("move", 10);
 
     root = g_file_new_for_path (g_get_tmp_dir ());
+    g_assert_true (root != NULL);
 
     for (int i = 0; i < 10; i++)
     {
-        file_name = g_strdup_printf ("file_%i", i);
+        file_name = g_strdup_printf ("move_file_%i", i);
         file = g_file_get_child (root, file_name);
+        g_free (file_name);
         g_assert_true (file != NULL);
-        g_file_make_directory (file, NULL, NULL);
         files = g_list_prepend (files, g_object_ref (file));
     }
 
-    dir = g_file_get_child (root, "dir");
+    dir = g_file_get_child (root, "move_dir");
     g_assert_true (dir != NULL);
-    g_file_make_directory (dir, NULL, NULL);
 
     nautilus_file_operations_move_sync (files,
-                                        dir,
-                                        NULL,
-                                        NULL,
-                                        NULL);
+                                        dir);
 
     for (int i = 0; i < 10; i++)
     {
-        file_name = g_strdup_printf ("file_%i", i);
+        file_name = g_strdup_printf ("move_file_%i", i);
         file = g_file_get_child (dir, file_name);
+        g_free (file_name);
         g_assert_true (g_file_query_exists (file, NULL));
-        g_assert_true (g_file_delete (file, NULL, NULL));
     }
 
     g_assert_true (g_file_query_exists (dir, NULL));
-    g_assert_true (g_file_delete (dir, NULL, NULL));
+
+    empty_directory_by_prefix (root, "move");
 }
 
 static void
-test_move_directories_medium (void)
+test_move_files_small_undo (void)
+{
+    g_autoptr (GFile) root = NULL;
+    g_autoptr (GFile) file = NULL;
+    g_autoptr (GFile) dir = NULL;
+    g_autolist (GFile) files = NULL;
+    gchar *file_name;
+
+    create_multiple_files ("move", 10);
+
+    root = g_file_new_for_path (g_get_tmp_dir ());
+    g_assert_true (root != NULL);
+
+    for (int i = 0; i < 10; i++)
+    {
+        file_name = g_strdup_printf ("move_file_%i", i);
+        file = g_file_get_child (root, file_name);
+        g_free (file_name);
+        g_assert_true (file != NULL);
+        files = g_list_prepend (files, g_object_ref (file));
+    }
+
+    dir = g_file_get_child (root, "move_dir");
+    g_assert_true (dir != NULL);
+
+    nautilus_file_operations_move_sync (files,
+                                        dir);
+
+    test_operation_undo ();
+
+    for (int i = 0; i < 10; i++)
+    {
+        file_name = g_strdup_printf ("move_file_%i", i);
+        file = g_file_get_child (dir, file_name);
+        g_assert_false (g_file_query_exists (file, NULL));
+        file = g_file_get_child (root, file_name);
+        g_free (file_name);
+        g_assert_true (g_file_query_exists (file, NULL));
+    }
+
+    g_assert_true (g_file_query_exists (dir, NULL));
+
+    empty_directory_by_prefix (root, "move");
+}
+
+static void
+test_move_files_small_undo_redo (void)
 {
     g_autoptr (GFile) root = NULL;
     g_autoptr (GFile) file = NULL;
     g_autoptr (GFile) dir = NULL;
     g_autolist (GFile) files = NULL;
-    g_autofree gchar *file_name = NULL;
+    gchar *file_name;
+
+    create_multiple_files ("move", 10);
 
     root = g_file_new_for_path (g_get_tmp_dir ());
+    g_assert_true (root != NULL);
 
-    for (int i = 0; i < 1000; i++)
+    for (int i = 0; i < 10; i++)
     {
-        file_name = g_strdup_printf ("file_%i", i);
+        file_name = g_strdup_printf ("move_file_%i", i);
         file = g_file_get_child (root, file_name);
+        g_free (file_name);
         g_assert_true (file != NULL);
-        g_file_make_directory (file, NULL, NULL);
         files = g_list_prepend (files, g_object_ref (file));
     }
 
-    dir = g_file_get_child (root, "dir");
+    dir = g_file_get_child (root, "move_dir");
     g_assert_true (dir != NULL);
-    g_file_make_directory (dir, NULL, NULL);
 
     nautilus_file_operations_move_sync (files,
-                                        dir,
-                                        NULL,
-                                        NULL,
-                                        NULL);
+                                        dir);
+
+    test_operation_undo_redo ();
 
-    for (int i = 0; i < 1000; i++)
+    for (int i = 0; i < 10; i++)
     {
-        file_name = g_strdup_printf ("file_%i", i);
+        file_name = g_strdup_printf ("move_file_%i", i);
         file = g_file_get_child (dir, file_name);
+        g_free (file_name);
         g_assert_true (g_file_query_exists (file, NULL));
-        g_assert_true (g_file_delete (file, NULL, NULL));
     }
 
     g_assert_true (g_file_query_exists (dir, NULL));
-    g_assert_true (g_file_delete (dir, NULL, NULL));
+
+    empty_directory_by_prefix (root, "move");
 }
 
-/* Test not included as it would timeout on the CI. */
+static void
+test_move_files_medium (void)
+{
+    g_autoptr (GFile) root = NULL;
+    g_autoptr (GFile) file = NULL;
+    g_autoptr (GFile) dir = NULL;
+    g_autolist (GFile) files = NULL;
+    gchar *file_name;
+
+    create_multiple_files ("move", 50);
 
-/*static void
-test_move_directories_large (void)
+    root = g_file_new_for_path (g_get_tmp_dir ());
+    g_assert_true (root != NULL);
+
+    for (int i = 0; i < 50; i++)
+    {
+        file_name = g_strdup_printf ("move_file_%i", i);
+        file = g_file_get_child (root, file_name);
+        g_free (file_name);
+        g_assert_true (file != NULL);
+        files = g_list_prepend (files, g_object_ref (file));
+    }
+
+    dir = g_file_get_child (root, "move_dir");
+    g_assert_true (dir != NULL);
+
+    nautilus_file_operations_move_sync (files,
+                                        dir);
+
+    for (int i = 0; i < 50; i++)
+    {
+        file_name = g_strdup_printf ("move_file_%i", i);
+        file = g_file_get_child (dir, file_name);
+        g_free (file_name);
+        g_assert_true (g_file_query_exists (file, NULL));
+    }
+
+    g_assert_true (g_file_query_exists (dir, NULL));
+
+    empty_directory_by_prefix (root, "move");
+}
+
+static void
+test_move_files_medium_undo (void)
 {
     g_autoptr (GFile) root = NULL;
     g_autoptr (GFile) file = NULL;
     g_autoptr (GFile) dir = NULL;
     g_autolist (GFile) files = NULL;
-    g_autofree gchar *file_name = NULL;
+    gchar *file_name;
+
+    create_multiple_files ("move", 50);
 
     root = g_file_new_for_path (g_get_tmp_dir ());
 
-    for (int i = 0; i < 10000; i++)
+    for (int i = 0; i < 50; i++)
     {
-        file_name = g_strdup_printf ("file_%i", i);
+        file_name = g_strdup_printf ("move_file_%i", i);
         file = g_file_get_child (root, file_name);
+        g_free (file_name);
         g_assert_true (file != NULL);
-        g_file_make_directory (file, NULL, NULL);
         files = g_list_prepend (files, g_object_ref (file));
     }
 
-    dir = g_file_get_child (root, "dir");
+    dir = g_file_get_child (root, "move_dir");
     g_assert_true (dir != NULL);
-    g_file_make_directory (dir, NULL, NULL);
 
     nautilus_file_operations_move_sync (files,
-                                        dir,
-                                        NULL,
-                                        NULL,
-                                        NULL);
+                                        dir);
 
-    for (int i = 0; i < 10000; i++)
+    test_operation_undo ();
+
+    for (int i = 0; i < 50; i++)
     {
-        file_name = g_strdup_printf ("file_%i", i);
+        file_name = g_strdup_printf ("move_file_%i", i);
         file = g_file_get_child (dir, file_name);
+        g_assert_false (g_file_query_exists (file, NULL));
+        file = g_file_get_child (root, file_name);
+        g_free (file_name);
         g_assert_true (g_file_query_exists (file, NULL));
-        g_assert_true (g_file_delete (file, NULL, NULL));
     }
 
     g_assert_true (g_file_query_exists (dir, NULL));
-    g_assert_true (g_file_delete (dir, NULL, NULL));
-}*/
 
+    empty_directory_by_prefix (root, "move");
+}
 
 static void
-test_move_files_small (void)
+test_move_files_medium_undo_redo (void)
 {
     g_autoptr (GFile) root = NULL;
     g_autoptr (GFile) file = NULL;
     g_autoptr (GFile) dir = NULL;
     g_autolist (GFile) files = NULL;
-    g_autofree gchar *file_name = NULL;
-    GFileOutputStream *out = NULL;
+    gchar *file_name;
+
+    create_multiple_files ("move", 50);
 
     root = g_file_new_for_path (g_get_tmp_dir ());
+    g_assert_true (root != NULL);
 
-    for (int i = 0; i < 10; i++)
+    for (int i = 0; i < 50; i++)
+    {
+        file_name = g_strdup_printf ("move_file_%i", i);
+        file = g_file_get_child (root, file_name);
+        g_free (file_name);
+        g_assert_true (file != NULL);
+        files = g_list_prepend (files, g_object_ref (file));
+    }
+
+    dir = g_file_get_child (root, "move_dir");
+    g_assert_true (dir != NULL);
+
+    nautilus_file_operations_move_sync (files,
+                                        dir);
+
+    test_operation_undo_redo ();
+
+    for (int i = 0; i < 50; i++)
     {
-        g_autoptr (GError) error = NULL;
+        file_name = g_strdup_printf ("move_file_%i", i);
+        file = g_file_get_child (dir, file_name);
+        g_free (file_name);
+        g_assert_true (g_file_query_exists (file, NULL));
+    }
+
+    g_assert_true (g_file_query_exists (dir, NULL));
+
+    empty_directory_by_prefix (root, "move");
+}
+
+static void
+test_move_files_large (void)
+{
+    g_autoptr (GFile) root = NULL;
+    g_autoptr (GFile) file = NULL;
+    g_autoptr (GFile) dir = NULL;
+    g_autolist (GFile) files = NULL;
+    gchar *file_name;
 
-        file_name = g_strdup_printf ("file_%i", i);
+    create_multiple_files ("move", 500);
+
+    root = g_file_new_for_path (g_get_tmp_dir ());
+
+    for (int i = 0; i < 500; i++)
+    {
+        file_name = g_strdup_printf ("move_file_%i", i);
         file = g_file_get_child (root, file_name);
+        g_free (file_name);
         g_assert_true (file != NULL);
-        out = g_file_create (file, G_FILE_CREATE_NONE, NULL, &error);
-        if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_EXISTS))
-        {
-            g_object_unref (out);
-        }
         files = g_list_prepend (files, g_object_ref (file));
     }
 
-    dir = g_file_get_child (root, "dir");
+    dir = g_file_get_child (root, "move_dir");
     g_assert_true (dir != NULL);
-    g_file_make_directory (dir, NULL, NULL);
 
     nautilus_file_operations_move_sync (files,
-                                        dir,
-                                        NULL,
-                                        NULL,
-                                        NULL);
+                                        dir);
 
-    for (int i = 0; i < 10; i++)
+    test_operation_undo ();
+
+    for (int i = 0; i < 500; i++)
     {
-        file_name = g_strdup_printf ("file_%i", i);
+        file_name = g_strdup_printf ("move_file_%i", i);
         file = g_file_get_child (dir, file_name);
+        g_assert_false (g_file_query_exists (file, NULL));
+        file = g_file_get_child (root, file_name);
+        g_free (file_name);
         g_assert_true (g_file_query_exists (file, NULL));
-        g_assert_true (g_file_delete (file, NULL, NULL));
     }
 
     g_assert_true (g_file_query_exists (dir, NULL));
-    g_assert_true (g_file_delete (dir, NULL, NULL));
+
+    empty_directory_by_prefix (root, "move");
 }
 
 static void
-test_move_files_medium (void)
+test_move_files_large_undo (void)
+{
+    g_autoptr (GFile) root = NULL;
+    g_autoptr (GFile) file = NULL;
+    g_autoptr (GFile) dir = NULL;
+    g_autolist (GFile) files = NULL;
+    gchar *file_name;
+
+    create_multiple_files ("move", 500);
+
+    root = g_file_new_for_path (g_get_tmp_dir ());
+    g_assert_true (root != NULL);
+
+    for (int i = 0; i < 500; i++)
+    {
+        file_name = g_strdup_printf ("move_file_%i", i);
+        file = g_file_get_child (root, file_name);
+        g_free (file_name);
+        g_assert_true (file != NULL);
+        files = g_list_prepend (files, g_object_ref (file));
+    }
+
+    dir = g_file_get_child (root, "move_dir");
+    g_assert_true (dir != NULL);
+
+    nautilus_file_operations_move_sync (files,
+                                        dir);
+    test_operation_undo_redo ();
+
+    for (int i = 0; i < 500; i++)
+    {
+        file_name = g_strdup_printf ("move_file_%i", i);
+        file = g_file_get_child (dir, file_name);
+        g_free (file_name);
+        g_assert_true (g_file_query_exists (file, NULL));
+    }
+
+    g_assert_true (g_file_query_exists (dir, NULL));
+
+    empty_directory_by_prefix (root, "move");
+}
+
+static void
+test_move_files_large_undo_redo (void)
+{
+    g_autoptr (GFile) root = NULL;
+    g_autoptr (GFile) file = NULL;
+    g_autoptr (GFile) dir = NULL;
+    g_autolist (GFile) files = NULL;
+    gchar *file_name;
+
+    create_multiple_files ("move", 500);
+
+    root = g_file_new_for_path (g_get_tmp_dir ());
+    g_assert_true (root != NULL);
+
+    for (int i = 0; i < 500; i++)
+    {
+        file_name = g_strdup_printf ("move_file_%i", i);
+        file = g_file_get_child (root, file_name);
+        g_free (file_name);
+        g_assert_true (file != NULL);
+        files = g_list_prepend (files, g_object_ref (file));
+    }
+
+    dir = g_file_get_child (root, "move_dir");
+    g_assert_true (dir != NULL);
+
+    nautilus_file_operations_move_sync (files,
+                                        dir);
+
+    test_operation_undo_redo ();
+
+    for (int i = 0; i < 500; i++)
+    {
+        file_name = g_strdup_printf ("move_file_%i", i);
+        file = g_file_get_child (dir, file_name);
+        g_free (file_name);
+        g_assert_true (g_file_query_exists (file, NULL));
+    }
+
+    g_assert_true (g_file_query_exists (dir, NULL));
+
+    empty_directory_by_prefix (root, "move");
+}
+
+static void
+test_move_directories_small (void)
+{
+    g_autoptr (GFile) root = NULL;
+    g_autoptr (GFile) file = NULL;
+    g_autoptr (GFile) dir = NULL;
+    g_autolist (GFile) files = NULL;
+    gchar *file_name;
+
+    create_multiple_directories ("move", 10);
+
+    root = g_file_new_for_path (g_get_tmp_dir ());
+    g_assert_true (root != NULL);
+
+    for (int i = 0; i < 10; i++)
+    {
+        file_name = g_strdup_printf ("move_file_%i", i);
+        file = g_file_get_child (root, file_name);
+        g_free (file_name);
+        g_assert_true (file != NULL);
+        files = g_list_prepend (files, g_object_ref (file));
+    }
+
+    dir = g_file_get_child (root, "move_dir");
+    g_assert_true (dir != NULL);
+
+    nautilus_file_operations_move_sync (files,
+                                        dir);
+
+    for (int i = 0; i < 10; i++)
+    {
+        file_name = g_strdup_printf ("move_file_%i", i);
+        file = g_file_get_child (dir, file_name);
+        g_free (file_name);
+        g_assert_true (g_file_query_exists (file, NULL));
+    }
+
+    g_assert_true (g_file_query_exists (dir, NULL));
+
+    empty_directory_by_prefix (root, "move");
+}
+
+static void
+test_move_directories_small_undo (void)
+{
+    g_autoptr (GFile) root = NULL;
+    g_autoptr (GFile) file = NULL;
+    g_autoptr (GFile) dir = NULL;
+    g_autolist (GFile) files = NULL;
+    gchar *file_name;
+
+    create_multiple_directories ("move", 10);
+
+    root = g_file_new_for_path (g_get_tmp_dir ());
+
+    for (int i = 0; i < 10; i++)
+    {
+        file_name = g_strdup_printf ("move_file_%i", i);
+        file = g_file_get_child (root, file_name);
+        g_free (file_name);
+        g_assert_true (file != NULL);
+        files = g_list_prepend (files, g_object_ref (file));
+    }
+
+    dir = g_file_get_child (root, "move_dir");
+    g_assert_true (dir != NULL);
+
+    nautilus_file_operations_move_sync (files,
+                                        dir);
+
+    test_operation_undo ();
+
+    for (int i = 0; i < 10; i++)
+    {
+        file_name = g_strdup_printf ("move_file_%i", i);
+        file = g_file_get_child (dir, file_name);
+        g_assert_false (g_file_query_exists (file, NULL));
+        file = g_file_get_child (root, file_name);
+        g_free (file_name);
+        g_assert_true (g_file_query_exists (file, NULL));
+    }
+
+    g_assert_true (g_file_query_exists (dir, NULL));
+
+    empty_directory_by_prefix (root, "move");
+}
+
+static void
+test_move_directories_small_undo_redo (void)
+{
+    g_autoptr (GFile) root = NULL;
+    g_autoptr (GFile) file = NULL;
+    g_autoptr (GFile) dir = NULL;
+    g_autolist (GFile) files = NULL;
+    gchar *file_name;
+
+    create_multiple_files ("move", 10);
+
+    root = g_file_new_for_path (g_get_tmp_dir ());
+    g_assert_true (root != NULL);
+
+    for (int i = 0; i < 10; i++)
+    {
+        file_name = g_strdup_printf ("move_file_%i", i);
+        file = g_file_get_child (root, file_name);
+        g_free (file_name);
+        g_assert_true (file != NULL);
+        files = g_list_prepend (files, g_object_ref (file));
+    }
+
+    dir = g_file_get_child (root, "move_dir");
+    g_assert_true (dir != NULL);
+
+    nautilus_file_operations_move_sync (files,
+                                        dir);
+
+    test_operation_undo_redo ();
+
+    for (int i = 0; i < 10; i++)
+    {
+        file_name = g_strdup_printf ("move_file_%i", i);
+        file = g_file_get_child (dir, file_name);
+        g_free (file_name);
+        g_assert_true (g_file_query_exists (file, NULL));
+    }
+
+    g_assert_true (g_file_query_exists (dir, NULL));
+
+    empty_directory_by_prefix (root, "move");
+}
+
+static void
+test_move_directories_medium (void)
+{
+    g_autoptr (GFile) root = NULL;
+    g_autoptr (GFile) file = NULL;
+    g_autoptr (GFile) dir = NULL;
+    g_autolist (GFile) files = NULL;
+    gchar *file_name;
+
+    create_multiple_directories ("move", 50);
+
+    root = g_file_new_for_path (g_get_tmp_dir ());
+    g_assert_true (root != NULL);
+
+    for (int i = 0; i < 50; i++)
+    {
+        file_name = g_strdup_printf ("move_file_%i", i);
+        file = g_file_get_child (root, file_name);
+        g_free (file_name);
+        g_assert_true (file != NULL);
+        files = g_list_prepend (files, g_object_ref (file));
+    }
+
+    dir = g_file_get_child (root, "move_dir");
+    g_assert_true (dir != NULL);
+
+    nautilus_file_operations_move_sync (files,
+                                        dir);
+
+    for (int i = 0; i < 50; i++)
+    {
+        file_name = g_strdup_printf ("move_file_%i", i);
+        file = g_file_get_child (dir, file_name);
+        g_free (file_name);
+        g_assert_true (g_file_query_exists (file, NULL));
+    }
+
+    g_assert_true (g_file_query_exists (dir, NULL));
+
+    empty_directory_by_prefix (root, "move");
+}
+
+static void
+test_move_directories_medium_undo (void)
+{
+    g_autoptr (GFile) root = NULL;
+    g_autoptr (GFile) file = NULL;
+    g_autoptr (GFile) dir = NULL;
+    g_autolist (GFile) files = NULL;
+    gchar *file_name;
+
+    create_multiple_directories ("move", 50);
+
+    root = g_file_new_for_path (g_get_tmp_dir ());
+
+    for (int i = 0; i < 50; i++)
+    {
+        file_name = g_strdup_printf ("move_file_%i", i);
+        file = g_file_get_child (root, file_name);
+        g_free (file_name);
+        g_assert_true (file != NULL);
+        files = g_list_prepend (files, g_object_ref (file));
+    }
+
+    dir = g_file_get_child (root, "move_dir");
+    g_assert_true (dir != NULL);
+
+    nautilus_file_operations_move_sync (files,
+                                        dir);
+
+    test_operation_undo ();
+
+    for (int i = 0; i < 50; i++)
+    {
+        file_name = g_strdup_printf ("move_file_%i", i);
+        file = g_file_get_child (dir, file_name);
+        g_assert_false (g_file_query_exists (file, NULL));
+        file = g_file_get_child (root, file_name);
+        g_free (file_name);
+        g_assert_true (g_file_query_exists (file, NULL));
+    }
+
+    g_assert_true (g_file_query_exists (dir, NULL));
+
+    empty_directory_by_prefix (root, "move");
+}
+
+static void
+test_move_directories_medium_undo_redo (void)
+{
+    g_autoptr (GFile) root = NULL;
+    g_autoptr (GFile) file = NULL;
+    g_autoptr (GFile) dir = NULL;
+    g_autolist (GFile) files = NULL;
+    gchar *file_name;
+
+    create_multiple_files ("move", 50);
+
+    root = g_file_new_for_path (g_get_tmp_dir ());
+    g_assert_true (root != NULL);
+
+    for (int i = 0; i < 50; i++)
+    {
+        file_name = g_strdup_printf ("move_file_%i", i);
+        file = g_file_get_child (root, file_name);
+        g_free (file_name);
+        g_assert_true (file != NULL);
+        files = g_list_prepend (files, g_object_ref (file));
+    }
+
+    dir = g_file_get_child (root, "move_dir");
+    g_assert_true (dir != NULL);
+
+    nautilus_file_operations_move_sync (files,
+                                        dir);
+
+    test_operation_undo_redo ();
+
+    for (int i = 0; i < 50; i++)
+    {
+        file_name = g_strdup_printf ("move_file_%i", i);
+        file = g_file_get_child (dir, file_name);
+        g_free (file_name);
+        g_assert_true (g_file_query_exists (file, NULL));
+    }
+
+    g_assert_true (g_file_query_exists (dir, NULL));
+
+    empty_directory_by_prefix (root, "move");
+}
+
+static void
+test_move_directories_large (void)
+{
+    g_autoptr (GFile) root = NULL;
+    g_autoptr (GFile) file = NULL;
+    g_autoptr (GFile) dir = NULL;
+    g_autolist (GFile) files = NULL;
+    gchar *file_name;
+
+    create_multiple_directories ("move", 500);
+
+    root = g_file_new_for_path (g_get_tmp_dir ());
+    g_assert_true (root != NULL);
+
+    for (int i = 0; i < 500; i++)
+    {
+        file_name = g_strdup_printf ("move_file_%i", i);
+        file = g_file_get_child (root, file_name);
+        g_free (file_name);
+        g_assert_true (file != NULL);
+        files = g_list_prepend (files, g_object_ref (file));
+    }
+
+    dir = g_file_get_child (root, "move_dir");
+    g_assert_true (dir != NULL);
+
+    nautilus_file_operations_move_sync (files,
+                                        dir);
+
+    for (int i = 0; i < 500; i++)
+    {
+        file_name = g_strdup_printf ("move_file_%i", i);
+        file = g_file_get_child (dir, file_name);
+        g_free (file_name);
+        g_assert_true (g_file_query_exists (file, NULL));
+    }
+
+    g_assert_true (g_file_query_exists (dir, NULL));
+
+    empty_directory_by_prefix (root, "move");
+}
+
+static void
+test_move_directories_large_undo (void)
+{
+    g_autoptr (GFile) root = NULL;
+    g_autoptr (GFile) file = NULL;
+    g_autoptr (GFile) dir = NULL;
+    g_autolist (GFile) files = NULL;
+    gchar *file_name;
+
+    create_multiple_directories ("move", 500);
+
+    root = g_file_new_for_path (g_get_tmp_dir ());
+
+    for (int i = 0; i < 500; i++)
+    {
+        file_name = g_strdup_printf ("move_file_%i", i);
+        file = g_file_get_child (root, file_name);
+        g_free (file_name);
+        g_assert_true (file != NULL);
+        files = g_list_prepend (files, g_object_ref (file));
+    }
+
+    dir = g_file_get_child (root, "move_dir");
+    g_assert_true (dir != NULL);
+
+    nautilus_file_operations_move_sync (files,
+                                        dir);
+
+    test_operation_undo ();
+
+    for (int i = 0; i < 500; i++)
+    {
+        file_name = g_strdup_printf ("move_file_%i", i);
+        file = g_file_get_child (dir, file_name);
+        g_assert_false (g_file_query_exists (file, NULL));
+        file = g_file_get_child (root, file_name);
+        g_free (file_name);
+        g_assert_true (g_file_query_exists (file, NULL));
+    }
+
+    g_assert_true (g_file_query_exists (dir, NULL));
+
+    empty_directory_by_prefix (root, "move");
+}
+
+static void
+test_move_directories_large_undo_redo (void)
+{
+    g_autoptr (GFile) root = NULL;
+    g_autoptr (GFile) file = NULL;
+    g_autoptr (GFile) dir = NULL;
+    g_autolist (GFile) files = NULL;
+    gchar *file_name;
+
+    create_multiple_directories ("move", 500);
+
+    root = g_file_new_for_path (g_get_tmp_dir ());
+    g_assert_true (root != NULL);
+
+    for (int i = 0; i < 500; i++)
+    {
+        file_name = g_strdup_printf ("move_file_%i", i);
+        file = g_file_get_child (root, file_name);
+        g_free (file_name);
+        g_assert_true (file != NULL);
+        files = g_list_prepend (files, g_object_ref (file));
+    }
+
+    dir = g_file_get_child (root, "move_dir");
+    g_assert_true (dir != NULL);
+
+    nautilus_file_operations_move_sync (files,
+                                        dir);
+
+    test_operation_undo_redo ();
+
+    for (int i = 0; i < 500; i++)
+    {
+        file_name = g_strdup_printf ("move_file_%i", i);
+        file = g_file_get_child (dir, file_name);
+        g_free (file_name);
+        g_assert_true (g_file_query_exists (file, NULL));
+    }
+
+    g_assert_true (g_file_query_exists (dir, NULL));
+
+    empty_directory_by_prefix (root, "move");
+}
+
+/* The hierarchy looks like this:
+ * /tmp/first_dir/first_dir_child
+ * /tmp/second_dir
+ * We're moving first_dir to second_dir.
+ */
+static void
+test_move_full_directory (void)
+{
+    g_autoptr (GFile) root = NULL;
+    g_autoptr (GFile) first_dir = NULL;
+    g_autoptr (GFile) second_dir = NULL;
+    g_autoptr (GFile) file = NULL;
+    g_autoptr (GFile) result_file = NULL;
+    g_autolist (GFile) files = NULL;
+
+    create_one_file ("move");
+
+    root = g_file_new_for_path (g_get_tmp_dir ());
+    g_assert_true (root != NULL);
+
+    first_dir = g_file_get_child (root, "move_first_dir");
+    files = g_list_prepend (files, g_object_ref (first_dir));
+    g_assert_true (first_dir != NULL);
+
+    file = g_file_get_child (first_dir, "move_first_dir_child");
+    g_assert_true (file != NULL);
+
+    second_dir = g_file_get_child (root, "move_second_dir");
+    g_assert_true (second_dir != NULL);
+
+    nautilus_file_operations_move_sync (files,
+                                        second_dir);
+
+    result_file = g_file_get_child (second_dir, "move_first_dir");
+    g_assert_true (g_file_query_exists (result_file, NULL));
+    file = g_file_get_child (result_file, "move_first_dir_child");
+    g_assert_true (g_file_query_exists (file, NULL));
+
+    file = g_file_get_child (first_dir, "move_first_dir_child");
+    g_assert_false (g_file_query_exists (file, NULL));
+    g_assert_false (g_file_query_exists (first_dir, NULL));
+
+    empty_directory_by_prefix (root, "move");
+}
+
+static void
+test_move_full_directory_undo (void)
+{
+    g_autoptr (GFile) root = NULL;
+    g_autoptr (GFile) first_dir = NULL;
+    g_autoptr (GFile) second_dir = NULL;
+    g_autoptr (GFile) file = NULL;
+    g_autoptr (GFile) result_file = NULL;
+    g_autolist (GFile) files = NULL;
+
+    create_one_file ("move");
+
+    root = g_file_new_for_path (g_get_tmp_dir ());
+    g_assert_true (root != NULL);
+
+    first_dir = g_file_get_child (root, "move_first_dir");
+    files = g_list_prepend (files, g_object_ref (first_dir));
+    g_assert_true (first_dir != NULL);
+
+    file = g_file_get_child (first_dir, "move_first_dir_child");
+    g_assert_true (file != NULL);
+
+    second_dir = g_file_get_child (root, "move_second_dir");
+    g_assert_true (second_dir != NULL);
+
+    nautilus_file_operations_move_sync (files,
+                                        second_dir);
+
+    test_operation_undo ();
+
+    result_file = g_file_get_child (second_dir, "move_first_dir");
+    g_assert_false (g_file_query_exists (result_file, NULL));
+    file = g_file_get_child (result_file, "move_first_dir_child");
+    g_assert_false (g_file_query_exists (file, NULL));
+
+    file = g_file_get_child (first_dir, "move_first_dir_child");
+    g_assert_true (g_file_query_exists (file, NULL));
+
+    empty_directory_by_prefix (root, "move");
+}
+
+static void
+test_move_full_directory_undo_redo (void)
+{
+    g_autoptr (GFile) root = NULL;
+    g_autoptr (GFile) first_dir = NULL;
+    g_autoptr (GFile) second_dir = NULL;
+    g_autoptr (GFile) file = NULL;
+    g_autoptr (GFile) result_file = NULL;
+    g_autolist (GFile) files = NULL;
+
+    create_one_file ("move");
+
+    root = g_file_new_for_path (g_get_tmp_dir ());
+    g_assert_true (root != NULL);
+
+    first_dir = g_file_get_child (root, "move_first_dir");
+    files = g_list_prepend (files, g_object_ref (first_dir));
+    g_assert_true (first_dir != NULL);
+
+    file = g_file_get_child (first_dir, "move_first_dir_child");
+    g_assert_true (file != NULL);
+
+    second_dir = g_file_get_child (root, "move_second_dir");
+    g_assert_true (second_dir != NULL);
+
+    nautilus_file_operations_move_sync (files,
+                                        second_dir);
+
+    test_operation_undo_redo ();
+
+    result_file = g_file_get_child (second_dir, "move_first_dir");
+    g_assert_true (g_file_query_exists (result_file, NULL));
+    file = g_file_get_child (result_file, "move_first_dir_child");
+    g_assert_true (g_file_query_exists (file, NULL));
+
+    file = g_file_get_child (first_dir, "move_first_dir_child");
+    g_assert_false (g_file_query_exists (file, NULL));
+    g_assert_false (g_file_query_exists (first_dir, NULL));
+
+    empty_directory_by_prefix (root, "move");
+}
+
+/* The hierarchy looks like this:
+ * /tmp/first_dir/first_child
+ * /tmp/first_dir/second_child
+ * /tmp/second_dir
+ * We're moving first_dir to second_dir.
+ */
+static void
+test_move_first_hierarchy (void)
+{
+    g_autoptr (GFile) root = NULL;
+    g_autoptr (GFile) first_dir = NULL;
+    g_autoptr (GFile) second_dir = NULL;
+    g_autoptr (GFile) file = NULL;
+    g_autoptr (GFile) result_file = NULL;
+    g_autolist (GFile) files = NULL;
+
+    create_first_hierarchy ("move");
+
+    root = g_file_new_for_path (g_get_tmp_dir ());
+    g_assert_true (root != NULL);
+
+    first_dir = g_file_get_child (root, "move_first_dir");
+    files = g_list_prepend (files, g_object_ref (first_dir));
+    g_assert_true (first_dir != NULL);
+
+    file = g_file_get_child (first_dir, "move_first_child");
+    g_assert_true (file != NULL);
+    file = g_file_get_child (first_dir, "move_second_child");
+    g_assert_true (file != NULL);
+
+    second_dir = g_file_get_child (root, "move_second_dir");
+    g_assert_true (second_dir != NULL);
+
+    nautilus_file_operations_move_sync (files,
+                                        second_dir);
+
+    result_file = g_file_get_child (second_dir, "move_first_dir");
+    g_assert_true (g_file_query_exists (result_file, NULL));
+    file = g_file_get_child (result_file, "move_first_child");
+    g_assert_true (g_file_query_exists (file, NULL));
+
+    file = g_file_get_child (result_file, "move_second_child");
+    g_assert_true (g_file_query_exists (file, NULL));
+
+    file = g_file_get_child (first_dir, "move_first_child");
+    g_assert_false (g_file_query_exists (file, NULL));
+
+    file = g_file_get_child (first_dir, "move_second_child");
+    g_assert_false (g_file_query_exists (file, NULL));    
+
+    g_assert_false (g_file_query_exists (first_dir, NULL));
+
+    empty_directory_by_prefix (root, "move");
+}
+
+static void
+test_move_first_hierarchy_undo (void)
+{
+    g_autoptr (GFile) root = NULL;
+    g_autoptr (GFile) first_dir = NULL;
+    g_autoptr (GFile) second_dir = NULL;
+    g_autoptr (GFile) file = NULL;
+    g_autoptr (GFile) result_file = NULL;
+    g_autolist (GFile) files = NULL;
+
+    create_first_hierarchy ("move");
+
+    root = g_file_new_for_path (g_get_tmp_dir ());
+    g_assert_true (root != NULL);
+
+    first_dir = g_file_get_child (root, "move_first_dir");
+    files = g_list_prepend (files, g_object_ref (first_dir));
+    g_assert_true (first_dir != NULL);
+
+    file = g_file_get_child (first_dir, "move_first_child");
+    g_assert_true (file != NULL);
+    file = g_file_get_child (first_dir, "move_second_child");
+    g_assert_true (file != NULL);
+
+    second_dir = g_file_get_child (root, "move_second_dir");
+    g_assert_true (second_dir != NULL);
+
+    nautilus_file_operations_move_sync (files,
+                                        second_dir);
+
+    test_operation_undo ();
+
+    result_file = g_file_get_child (second_dir, "move_first_dir");
+    g_assert_false (g_file_query_exists (result_file, NULL));
+    file = g_file_get_child (result_file, "move_first_child");
+    g_assert_false (g_file_query_exists (file, NULL));
+
+    file = g_file_get_child (result_file, "move_second_child");
+    g_assert_false (g_file_query_exists (file, NULL));
+
+    file = g_file_get_child (first_dir, "move_first_child");
+    g_assert_true (g_file_query_exists (file, NULL));
+
+    file = g_file_get_child (first_dir, "move_second_child");
+    g_assert_true (g_file_query_exists (file, NULL));    
+
+    g_assert_true (g_file_query_exists (first_dir, NULL));
+
+    empty_directory_by_prefix (root, "move");
+}
+
+static void
+test_move_first_hierarchy_undo_redo (void)
+{
+    g_autoptr (GFile) root = NULL;
+    g_autoptr (GFile) first_dir = NULL;
+    g_autoptr (GFile) second_dir = NULL;
+    g_autoptr (GFile) file = NULL;
+    g_autoptr (GFile) result_file = NULL;
+    g_autolist (GFile) files = NULL;
+
+    create_first_hierarchy ("move");
+
+    root = g_file_new_for_path (g_get_tmp_dir ());
+    g_assert_true (root != NULL);
+
+    first_dir = g_file_get_child (root, "move_first_dir");
+    files = g_list_prepend (files, g_object_ref (first_dir));
+    g_assert_true (first_dir != NULL);
+
+    file = g_file_get_child (first_dir, "move_first_child");
+    g_assert_true (file != NULL);
+    file = g_file_get_child (first_dir, "move_second_child");
+    g_assert_true (file != NULL);
+
+    second_dir = g_file_get_child (root, "move_second_dir");
+    g_assert_true (second_dir != NULL);
+
+    nautilus_file_operations_move_sync (files,
+                                        second_dir);
+
+    test_operation_undo_redo ();
+
+    result_file = g_file_get_child (second_dir, "move_first_dir");
+    g_assert_true (g_file_query_exists (result_file, NULL));
+    file = g_file_get_child (result_file, "move_first_child");
+    g_assert_true (g_file_query_exists (file, NULL));
+
+    file = g_file_get_child (result_file, "move_second_child");
+    g_assert_true (g_file_query_exists (file, NULL));
+
+    file = g_file_get_child (first_dir, "move_first_child");
+    g_assert_false (g_file_query_exists (file, NULL));
+
+    file = g_file_get_child (first_dir, "move_second_child");
+    g_assert_false (g_file_query_exists (file, NULL));    
+
+    g_assert_false (g_file_query_exists (first_dir, NULL));
+
+    empty_directory_by_prefix (root, "move");
+}
+
+/* The hierarchy looks like this:
+ * /tmp/first_dir/first_child/second_child
+ * /tmp/second_dir
+ * We're moving first_dir to second_dir.
+ */
+static void
+test_move_second_hierarchy (void)
 {
     g_autoptr (GFile) root = NULL;
+    g_autoptr (GFile) first_dir = NULL;
+    g_autoptr (GFile) second_dir = NULL;
     g_autoptr (GFile) file = NULL;
-    g_autoptr (GFile) dir = NULL;
+    g_autoptr (GFile) result_file = NULL;
     g_autolist (GFile) files = NULL;
-    g_autofree gchar *file_name = NULL;
-    GFileOutputStream *out = NULL;
+
+    create_second_hierarchy ("move");
 
     root = g_file_new_for_path (g_get_tmp_dir ());
+    g_assert_true (root != NULL);
 
-    for (int i = 0; i < 1000; i++)
-    {
-        g_autoptr (GError) error = NULL;
+    first_dir = g_file_get_child (root, "move_first_dir");
+    files = g_list_prepend (files, g_object_ref (first_dir));
+    g_assert_true (first_dir != NULL);
 
-        file_name = g_strdup_printf ("file_%i", i);
-        file = g_file_get_child (root, file_name);
-        g_assert_true (file != NULL);
-        out = g_file_create (file, G_FILE_CREATE_NONE, NULL, &error);
-        if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_EXISTS))
-        {
-            g_object_unref (out);
-        }
-        files = g_list_prepend (files, g_object_ref (file));
-    }
+    file = g_file_get_child (first_dir, "move_first_child");
+    g_assert_true (file != NULL);
+    file = g_file_get_child (file, "move_second_child");
+    g_assert_true (file != NULL);
 
-    dir = g_file_get_child (root, "dir");
-    g_assert_true (dir != NULL);
-    g_file_make_directory (dir, NULL, NULL);
+    second_dir = g_file_get_child (root, "move_second_dir");
+    g_assert_true (second_dir != NULL);
 
     nautilus_file_operations_move_sync (files,
-                                        dir,
-                                        NULL,
-                                        NULL,
-                                        NULL);
+                                        second_dir);
 
-    for (int i = 0; i < 1000; i++)
-    {
-        file_name = g_strdup_printf ("file_%i", i);
-        file = g_file_get_child (dir, file_name);
-        g_assert_true (g_file_query_exists (file, NULL));
-        g_assert_true (g_file_delete (file, NULL, NULL));
-    }
+    result_file = g_file_get_child (second_dir, "move_first_dir");
+    g_assert_true (g_file_query_exists (result_file, NULL));
+    file = g_file_get_child (result_file, "move_first_child");
+    g_assert_true (g_file_query_exists (file, NULL));
 
-    g_assert_true (g_file_query_exists (dir, NULL));
-    g_assert_true (g_file_delete (dir, NULL, NULL));
-}
+    file = g_file_get_child (file, "move_second_child");
+    g_assert_true (g_file_query_exists (file, NULL));
+
+    file = g_file_get_child (result_file, "move_first_child");
+    g_assert_true (g_file_query_exists (file, NULL));
+
+    file = g_file_get_child (first_dir, "move_first_child");
+    g_assert_false (g_file_query_exists (file, NULL));
+    file = g_file_get_child (file, "move_second_child");
+    g_assert_false (g_file_query_exists (file, NULL));
 
+    g_assert_false (g_file_query_exists (first_dir, NULL));
 
-/* Test not included as it would timeout on the CI. */
+    empty_directory_by_prefix (root, "move");
+}
 
-/*static void
-test_move_files_large (void)
+static void
+test_move_second_hierarchy_undo (void)
 {
     g_autoptr (GFile) root = NULL;
+    g_autoptr (GFile) first_dir = NULL;
+    g_autoptr (GFile) second_dir = NULL;
     g_autoptr (GFile) file = NULL;
-    g_autoptr (GFile) dir = NULL;
+    g_autoptr (GFile) result_file = NULL;
     g_autolist (GFile) files = NULL;
-    g_autofree gchar *file_name = NULL;
-    GFileOutputStream *out = NULL;
+
+    create_second_hierarchy ("move");
 
     root = g_file_new_for_path (g_get_tmp_dir ());
+    g_assert_true (root != NULL);
 
-    for (int i = 0; i < 10000; i++)
-    {
-        g_autoptr (GError) error = NULL;
+    first_dir = g_file_get_child (root, "move_first_dir");
+    files = g_list_prepend (files, g_object_ref (first_dir));
+    g_assert_true (first_dir != NULL);
 
-        file_name = g_strdup_printf ("file_%i", i);
-        file = g_file_get_child (root, file_name);
-        g_assert_true (file != NULL);
-        out = g_file_create (file, G_FILE_CREATE_NONE, NULL, &error);
-        if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_EXISTS))
-        {
-            g_object_unref (out);
-        }
-        files = g_list_prepend (files, g_object_ref (file));
-    }
+    file = g_file_get_child (first_dir, "move_first_child");
+    g_assert_true (file != NULL);
+    file = g_file_get_child (file, "move_second_child");
+    g_assert_true (file != NULL);
 
-    dir = g_file_get_child (root, "dir");
-    g_assert_true (dir != NULL);
-    g_file_make_directory (dir, NULL, NULL);
+    second_dir = g_file_get_child (root, "move_second_dir");
+    g_assert_true (second_dir != NULL);
 
     nautilus_file_operations_move_sync (files,
-                                        dir,
-                                        NULL,
-                                        NULL,
-                                        NULL);
+                                        second_dir);
 
-    for (int i = 0; i < 10000; i++)
-    {
-        file_name = g_strdup_printf ("file_%i", i);
-        file = g_file_get_child (dir, file_name);
-        g_assert_true (g_file_query_exists (file, NULL));
-        g_assert_true (g_file_delete (file, NULL, NULL));
-    }
+    test_operation_undo ();
 
-    g_assert_true (g_file_query_exists (dir, NULL));
-    g_assert_true (g_file_delete (dir, NULL, NULL));
-}*/
+    result_file = g_file_get_child (second_dir, "move_first_dir");
+    g_assert_false (g_file_query_exists (result_file, NULL));
+    file = g_file_get_child (result_file, "move_first_child");
+    g_assert_false (g_file_query_exists (file, NULL));
+
+    file = g_file_get_child (file, "move_second_child");
+    g_assert_false (g_file_query_exists (file, NULL));
+
+    file = g_file_get_child (first_dir, "move_first_child");
+    file = g_file_get_child (file, "move_second_child");
+    g_assert_true (g_file_query_exists (file, NULL));
+
+    file = g_file_get_child (first_dir, "move_first_child");
+    g_assert_true (g_file_query_exists (file, NULL));
+
+    g_assert_true (g_file_query_exists (first_dir, NULL));
+
+    empty_directory_by_prefix (root, "move");
+}
 
-/* The hierarchy looks like this:
- * /tmp/first_dir/first_dir_child
- * /tmp/second_dir
- * We're moving first_dir to second_dir.
- */
 static void
-test_move_first_hierarchy (void)
+test_move_second_hierarchy_undo_redo (void)
 {
     g_autoptr (GFile) root = NULL;
     g_autoptr (GFile) first_dir = NULL;
@@ -387,48 +1412,61 @@ test_move_first_hierarchy (void)
     g_autoptr (GFile) result_file = NULL;
     g_autolist (GFile) files = NULL;
 
+    create_second_hierarchy ("move");
+
     root = g_file_new_for_path (g_get_tmp_dir ());
-    first_dir = g_file_get_child (root, "first_dir");
+    g_assert_true (root != NULL);
+
+    first_dir = g_file_get_child (root, "move_first_dir");
     files = g_list_prepend (files, g_object_ref (first_dir));
     g_assert_true (first_dir != NULL);
     g_file_make_directory (first_dir, NULL, NULL);
 
-    file = g_file_get_child (first_dir, "first_dir_child");
+    file = g_file_get_child (first_dir, "move_first_child");
+    g_assert_true (file != NULL);
+    g_file_make_directory (file, NULL, NULL);
+    file = g_file_get_child (file, "move_second_child");
     g_assert_true (file != NULL);
     g_file_make_directory (file, NULL, NULL);
 
-    second_dir = g_file_get_child (root, "second_dir");
+    second_dir = g_file_get_child (root, "move_second_dir");
     g_assert_true (second_dir != NULL);
     g_file_make_directory (second_dir, NULL, NULL);
 
     nautilus_file_operations_move_sync (files,
-                                        second_dir,
-                                        NULL,
-                                        NULL,
-                                        NULL);
+                                        second_dir);
+
+    test_operation_undo_redo ();
 
-    result_file = g_file_get_child (second_dir, "first_dir");
+    result_file = g_file_get_child (second_dir, "move_first_dir");
     g_assert_true (g_file_query_exists (result_file, NULL));
-    file = g_file_get_child (result_file, "first_dir_child");
+    file = g_file_get_child (result_file, "move_first_child");
     g_assert_true (g_file_query_exists (file, NULL));
 
-    g_assert_true (g_file_delete (file, NULL, NULL));
-    g_assert_true (g_file_delete (result_file, NULL, NULL));
-    g_assert_true (g_file_delete (second_dir, NULL, NULL));
+    file = g_file_get_child (file, "move_second_child");
+    g_assert_true (g_file_query_exists (file, NULL));
+
+    file = g_file_get_child (result_file, "move_first_child");
+    g_assert_true (g_file_query_exists (file, NULL));
 
-    file = g_file_get_child (first_dir, "first_dir_child");
+    file = g_file_get_child (first_dir, "move_first_child");
     g_assert_false (g_file_query_exists (file, NULL));
+    file = g_file_get_child (file, "move_second_child");
+    g_assert_false (g_file_query_exists (file, NULL));
+
     g_assert_false (g_file_query_exists (first_dir, NULL));
+
+    empty_directory_by_prefix (root, "move");
 }
 
 /* The hierarchy looks like this:
- * /tmp/first_dir/first_child
- * /tmp/first_dir/second_child
+ * /tmp/first_dir/first_dir_dir1/dir1_child
+ * /tmp/first_dir/first_dir_dir2/dir2_child
  * /tmp/second_dir
  * We're moving first_dir to second_dir.
  */
 static void
-test_move_second_hierarchy (void)
+test_move_third_hierarchy (void)
 {
     g_autoptr (GFile) root = NULL;
     g_autoptr (GFile) first_dir = NULL;
@@ -437,58 +1475,65 @@ test_move_second_hierarchy (void)
     g_autoptr (GFile) result_file = NULL;
     g_autolist (GFile) files = NULL;
 
+    create_third_hierarchy ("move");
+
     root = g_file_new_for_path (g_get_tmp_dir ());
-    first_dir = g_file_get_child (root, "first_dir");
+    first_dir = g_file_get_child (root, "move_first_dir");
     files = g_list_prepend (files, g_object_ref (first_dir));
     g_assert_true (first_dir != NULL);
-    g_file_make_directory (first_dir, NULL, NULL);
 
-    file = g_file_get_child (first_dir, "first_child");
+    file = g_file_get_child (first_dir, "move_first_dir_dir1");
     g_assert_true (file != NULL);
-    g_file_make_directory (file, NULL, NULL);
-    file = g_file_get_child (first_dir, "second_child");
+
+    file = g_file_get_child (file, "move_dir1_child");
+    g_assert_true (file != NULL);
+
+    file = g_file_get_child (first_dir, "move_first_dir_dir2");
     g_assert_true (file != NULL);
-    g_file_make_directory (file, NULL, NULL);
 
-    second_dir = g_file_get_child (root, "second_dir");
+    file = g_file_get_child (file, "move_dir2_child");
+    g_assert_true (file != NULL);
+
+    second_dir = g_file_get_child (root, "move_second_dir");
     g_assert_true (second_dir != NULL);
-    g_file_make_directory (second_dir, NULL, NULL);
 
     nautilus_file_operations_move_sync (files,
-                                        second_dir,
-                                        NULL,
-                                        NULL,
-                                        NULL);
+                                        second_dir);
+
+    result_file = g_file_get_child (second_dir, "move_first_dir");
 
-    result_file = g_file_get_child (second_dir, "first_dir");
     g_assert_true (g_file_query_exists (result_file, NULL));
-    file = g_file_get_child (result_file, "first_child");
+    file = g_file_get_child (result_file, "move_first_dir_dir1");
     g_assert_true (g_file_query_exists (file, NULL));
-    g_assert_true (g_file_delete (file, NULL, NULL));
+    file = g_file_get_child (file, "move_dir1_child");
+    file = g_file_get_child (result_file, "move_first_dir_dir1");
 
-    file = g_file_get_child (result_file, "second_child");
+    file = g_file_get_child (result_file, "move_first_dir_dir2");
     g_assert_true (g_file_query_exists (file, NULL));
-    g_assert_true (g_file_delete (file, NULL, NULL));
-
-    g_assert_true (g_file_delete (result_file, NULL, NULL));
+    file = g_file_get_child (file, "move_dir2_child");
+    g_assert_true (g_file_query_exists (file, NULL));
+    file = g_file_get_child (result_file, "move_first_dir_dir2");
 
-    file = g_file_get_child (first_dir, "first_child");
+    file = g_file_get_child (first_dir, "move_first_dir_dir1");
     g_assert_false (g_file_query_exists (file, NULL));
+    file = g_file_get_child (file, "move_dir1_child");
+    g_assert_false (g_file_query_exists (file, NULL));
+    file = g_file_get_child (first_dir, "move_first_dir_dir1");
 
-    file = g_file_get_child (first_dir, "second_child");
-    g_assert_false (g_file_query_exists (file, NULL));    
+    file = g_file_get_child (first_dir, "move_first_dir_dir2");
+    g_assert_false (g_file_query_exists (file, NULL));
+    file = g_file_get_child (file, "move_dir2_child");
+    g_assert_false (g_file_query_exists (file, NULL));
+    file = g_file_get_child (first_dir, "move_first_dir_dir2");
+    g_assert_false (g_file_query_exists (file, NULL));
 
     g_assert_false (g_file_query_exists (first_dir, NULL));
-    g_assert_true (g_file_delete (second_dir, NULL, NULL));
+
+    empty_directory_by_prefix (root, "move");
 }
 
-/* The hierarchy looks like this:
- * /tmp/first_dir/first_child/second_child
- * /tmp/second_dir
- * We're moving first_dir to second_dir.
- */
 static void
-test_move_third_hierarchy (void)
+test_move_third_hierarchy_undo (void)
 {
     g_autoptr (GFile) root = NULL;
     g_autoptr (GFile) first_dir = NULL;
@@ -497,62 +1542,67 @@ test_move_third_hierarchy (void)
     g_autoptr (GFile) result_file = NULL;
     g_autolist (GFile) files = NULL;
 
+    create_third_hierarchy ("move");
+
     root = g_file_new_for_path (g_get_tmp_dir ());
-    first_dir = g_file_get_child (root, "first_dir");
+    g_assert_true (root != NULL);
+
+    first_dir = g_file_get_child (root, "move_first_dir");
     files = g_list_prepend (files, g_object_ref (first_dir));
     g_assert_true (first_dir != NULL);
-    g_file_make_directory (first_dir, NULL, NULL);
 
-    file = g_file_get_child (first_dir, "first_child");
+    file = g_file_get_child (first_dir, "move_first_dir_dir1");
     g_assert_true (file != NULL);
-    g_file_make_directory (file, NULL, NULL);
-    file = g_file_get_child (file, "second_child");
+
+    file = g_file_get_child (file, "move_dir1_child");
+    g_assert_true (file != NULL);
+
+    file = g_file_get_child (first_dir, "move_first_dir_dir2");
+    g_assert_true (file != NULL);
+
+    file = g_file_get_child (file, "move_dir2_child");
     g_assert_true (file != NULL);
-    g_file_make_directory (file, NULL, NULL);
 
-    second_dir = g_file_get_child (root, "second_dir");
+    second_dir = g_file_get_child (root, "move_second_dir");
     g_assert_true (second_dir != NULL);
-    g_file_make_directory (second_dir, NULL, NULL);
 
     nautilus_file_operations_move_sync (files,
-                                        second_dir,
-                                        NULL,
-                                        NULL,
-                                        NULL);
-
-    result_file = g_file_get_child (second_dir, "first_dir");
-    g_assert_true (g_file_query_exists (result_file, NULL));
-    file = g_file_get_child (result_file, "first_child");
-    g_assert_true (g_file_query_exists (file, NULL));
+                                        second_dir);
 
-    file = g_file_get_child (file, "second_child");
-    g_assert_true (g_file_query_exists (file, NULL));
-    g_assert_true (g_file_delete (file, NULL, NULL));
+    test_operation_undo ();
 
-    file = g_file_get_child (result_file, "first_child");
-    g_assert_true (g_file_query_exists (file, NULL));
-    g_assert_true (g_file_delete (file, NULL, NULL));
+    result_file = g_file_get_child (second_dir, "move_first_dir");
 
-    g_assert_true (g_file_delete (result_file, NULL, NULL));
+    g_assert_false (g_file_query_exists (result_file, NULL));
+    file = g_file_get_child (result_file, "move_first_dir_dir1");
+    g_assert_false (g_file_query_exists (file, NULL));
+    file = g_file_get_child (file, "move_dir1_child");
+    g_assert_false (g_file_query_exists (file, NULL));
 
-    file = g_file_get_child (first_dir, "first_child");
+    file = g_file_get_child (result_file, "move_first_dir_dir2");
     g_assert_false (g_file_query_exists (file, NULL));
-    file = g_file_get_child (file, "second_child");
+    file = g_file_get_child (file, "move_dir2_child");
     g_assert_false (g_file_query_exists (file, NULL));
 
-    g_assert_false (g_file_query_exists (first_dir, NULL));
+    file = g_file_get_child (first_dir, "move_first_dir_dir1");
+    g_assert_true (g_file_query_exists (file, NULL));
+    file = g_file_get_child (file, "move_dir1_child");
+    g_assert_true (g_file_query_exists (file, NULL));
+    file = g_file_get_child (first_dir, "move_first_dir_dir1");
+
+    file = g_file_get_child (first_dir, "move_first_dir_dir2");
+    g_assert_true (g_file_query_exists (file, NULL));
+    file = g_file_get_child (file, "move_dir2_child");
+    g_assert_true (g_file_query_exists (file, NULL));
+    file = g_file_get_child (first_dir, "move_first_dir_dir2");
+
+    g_assert_true (g_file_query_exists (first_dir, NULL));
 
     g_assert_true (g_file_delete (second_dir, NULL, NULL));
 }
 
-/* The hierarchy looks like this:
- * /tmp/first_dir/first_dir_dir1/dir1_child
- * /tmp/first_dir/first_dir_dir2/dir2_child
- * /tmp/second_dir
- * We're moving first_dir to second_dir.
- */
 static void
-test_move_fourth_hierarchy (void)
+test_move_third_hierarchy_undo_redo (void)
 {
     g_autoptr (GFile) root = NULL;
     g_autoptr (GFile) first_dir = NULL;
@@ -561,75 +1611,65 @@ test_move_fourth_hierarchy (void)
     g_autoptr (GFile) result_file = NULL;
     g_autolist (GFile) files = NULL;
 
+    create_third_hierarchy ("move");
+
     root = g_file_new_for_path (g_get_tmp_dir ());
-    first_dir = g_file_get_child (root, "first_dir");
+    g_assert_true (root != NULL);
+
+    first_dir = g_file_get_child (root, "move_first_dir");
     files = g_list_prepend (files, g_object_ref (first_dir));
     g_assert_true (first_dir != NULL);
-    g_file_make_directory (first_dir, NULL, NULL);
 
-    file = g_file_get_child (first_dir, "first_dir_dir1");
+    file = g_file_get_child (first_dir, "move_first_dir_dir1");
     g_assert_true (file != NULL);
-    g_file_make_directory (file, NULL, NULL);
 
-    file = g_file_get_child (file, "dir1_child");
+    file = g_file_get_child (file, "move_dir1_child");
     g_assert_true (file != NULL);
-    g_file_make_directory (file, NULL, NULL);
 
-    file = g_file_get_child (first_dir, "first_dir_dir2");
+    file = g_file_get_child (first_dir, "move_first_dir_dir2");
     g_assert_true (file != NULL);
-    g_file_make_directory (file, NULL, NULL);
 
-    file = g_file_get_child (file, "dir2_child");
+    file = g_file_get_child (file, "move_dir2_child");
     g_assert_true (file != NULL);
-    g_file_make_directory (file, NULL, NULL);
 
-    second_dir = g_file_get_child (root, "second_dir");
+    second_dir = g_file_get_child (root, "move_second_dir");
     g_assert_true (second_dir != NULL);
-    g_file_make_directory (second_dir, NULL, NULL);
 
     nautilus_file_operations_move_sync (files,
-                                        second_dir,
-                                        NULL,
-                                        NULL,
-                                        NULL);
+                                        second_dir);
+
+    test_operation_undo_redo ();
 
-    result_file = g_file_get_child (second_dir, "first_dir");
+    result_file = g_file_get_child (second_dir, "move_first_dir");
 
     g_assert_true (g_file_query_exists (result_file, NULL));
-    file = g_file_get_child (result_file, "first_dir_dir1");
+    file = g_file_get_child (result_file, "move_first_dir_dir1");
     g_assert_true (g_file_query_exists (file, NULL));
-    file = g_file_get_child (file, "dir1_child");
-    g_assert_true (g_file_delete (file, NULL, NULL));
-    file = g_file_get_child (result_file, "first_dir_dir1");
-    g_assert_true (g_file_delete (file, NULL, NULL));
+    file = g_file_get_child (file, "move_dir1_child");
+    file = g_file_get_child (result_file, "move_first_dir_dir1");
 
-    file = g_file_get_child (result_file, "first_dir_dir2");
+    file = g_file_get_child (result_file, "move_first_dir_dir2");
     g_assert_true (g_file_query_exists (file, NULL));
-    file = g_file_get_child (file, "dir2_child");
+    file = g_file_get_child (file, "move_dir2_child");
     g_assert_true (g_file_query_exists (file, NULL));
-    g_assert_true (g_file_delete (file, NULL, NULL));
-    file = g_file_get_child (result_file, "first_dir_dir2");
-    g_assert_true (g_file_delete (file, NULL, NULL));
+    file = g_file_get_child (result_file, "move_first_dir_dir2");
 
-    g_assert_true (g_file_delete (result_file, NULL, NULL));
-
-    file = g_file_get_child (first_dir, "first_dir_dir1");
+    file = g_file_get_child (first_dir, "move_first_dir_dir1");
     g_assert_false (g_file_query_exists (file, NULL));
-    file = g_file_get_child (file, "dir1_child");
+    file = g_file_get_child (file, "move_dir1_child");
     g_assert_false (g_file_query_exists (file, NULL));
-    file = g_file_get_child (first_dir, "first_dir_dir1");
-    g_assert_false (g_file_delete (file, NULL, NULL));
+    file = g_file_get_child (first_dir, "move_first_dir_dir1");
 
-    file = g_file_get_child (first_dir, "first_dir_dir2");
+    file = g_file_get_child (first_dir, "move_first_dir_dir2");
     g_assert_false (g_file_query_exists (file, NULL));
-    file = g_file_get_child (file, "dir2_child");
+    file = g_file_get_child (file, "move_dir2_child");
     g_assert_false (g_file_query_exists (file, NULL));
-    file = g_file_get_child (first_dir, "first_dir_dir2");
+    file = g_file_get_child (first_dir, "move_first_dir_dir2");
     g_assert_false (g_file_query_exists (file, NULL));
 
     g_assert_false (g_file_query_exists (first_dir, NULL));
 
-    g_assert_true (g_file_delete (second_dir, NULL, NULL));
+    empty_directory_by_prefix (root, "move");
 }
 
 /* The hierarchy looks like this:
@@ -639,7 +1679,7 @@ test_move_fourth_hierarchy (void)
  * We're moving first_dir and second_dir to third_dir.
  */
 static void
-test_move_fifth_hierarchy (void)
+test_move_fourth_hierarchy (void)
 {
     g_autoptr (GFile) root = NULL;
     g_autoptr (GFile) first_dir = NULL;
@@ -649,58 +1689,162 @@ test_move_fifth_hierarchy (void)
     g_autoptr (GFile) result_file = NULL;
     g_autolist (GFile) files = NULL;
 
+    create_fourth_hierarchy ("move");
+
     root = g_file_new_for_path (g_get_tmp_dir ());
-    first_dir = g_file_get_child (root, "first_dir");
+    first_dir = g_file_get_child (root, "move_first_dir");
     files = g_list_prepend (files, g_object_ref (first_dir));
     g_assert_true (first_dir != NULL);
-    g_file_make_directory (first_dir, NULL, NULL);
 
-    file = g_file_get_child (first_dir, "first_dir_child");
+    file = g_file_get_child (first_dir, "move_first_dir_child");
     g_assert_true (file != NULL);
-    g_file_make_directory (file, NULL, NULL);
 
-    second_dir = g_file_get_child (root, "second_dir");
+    second_dir = g_file_get_child (root, "move_second_dir");
     files = g_list_prepend (files, g_object_ref (second_dir));
     g_assert_true (second_dir != NULL);
-    g_file_make_directory (second_dir, NULL, NULL);
 
-    file = g_file_get_child (second_dir, "second_dir_child");
+    file = g_file_get_child (second_dir, "move_second_dir_child");
+    g_assert_true (file != NULL);
+
+    third_dir = g_file_get_child (root, "move_third_dir");
+    g_assert_true (third_dir != NULL);
+
+    nautilus_file_operations_move_sync (files,
+                                        third_dir);
+
+    result_file = g_file_get_child (third_dir, "move_first_dir");
+    g_assert_true (g_file_query_exists (result_file, NULL));
+    file = g_file_get_child (result_file, "move_first_dir_child");
+    g_assert_true (g_file_query_exists (file, NULL));
+
+    result_file = g_file_get_child (third_dir, "move_second_dir");
+    g_assert_true (g_file_query_exists (result_file, NULL));
+    file = g_file_get_child (result_file, "move_second_dir_child");
+    g_assert_true (g_file_query_exists (file, NULL));
+
+    file = g_file_get_child (first_dir, "move_first_dir_child");
+    g_assert_false (g_file_query_exists (file, NULL));
+    g_assert_false (g_file_query_exists (first_dir, NULL));
+
+    file = g_file_get_child (second_dir, "move_second_dir_child");
+    g_assert_false (g_file_query_exists (file, NULL));
+    g_assert_false (g_file_query_exists (second_dir, NULL));
+
+    empty_directory_by_prefix (root, "move");
+}
+
+static void
+test_move_fourth_hierarchy_undo (void)
+{
+    g_autoptr (GFile) root = NULL;
+    g_autoptr (GFile) first_dir = NULL;
+    g_autoptr (GFile) second_dir = NULL;
+    g_autoptr (GFile) third_dir = NULL;
+    g_autoptr (GFile) file = NULL;
+    g_autoptr (GFile) result_file = NULL;
+    g_autolist (GFile) files = NULL;
+
+    create_fourth_hierarchy ("move");
+
+    root = g_file_new_for_path (g_get_tmp_dir ());
+    first_dir = g_file_get_child (root, "move_first_dir");
+    files = g_list_prepend (files, g_object_ref (first_dir));
+    g_assert_true (first_dir != NULL);
+
+    file = g_file_get_child (first_dir, "move_first_dir_child");
+    g_assert_true (file != NULL);
+
+    second_dir = g_file_get_child (root, "move_second_dir");
+    files = g_list_prepend (files, g_object_ref (second_dir));
+    g_assert_true (second_dir != NULL);
+
+    file = g_file_get_child (second_dir, "move_second_dir_child");
+    g_assert_true (file != NULL);
+
+    third_dir = g_file_get_child (root, "move_third_dir");
+    g_assert_true (third_dir != NULL);
+
+    nautilus_file_operations_move_sync (files,
+                                        third_dir);
+
+    test_operation_undo ();
+
+    result_file = g_file_get_child (third_dir, "move_first_dir");
+    g_assert_false (g_file_query_exists (result_file, NULL));
+    file = g_file_get_child (result_file, "move_first_dir_child");
+    g_assert_false (g_file_query_exists (file, NULL));
+
+    result_file = g_file_get_child (third_dir, "move_second_dir");
+    g_assert_false (g_file_query_exists (result_file, NULL));
+    file = g_file_get_child (result_file, "move_second_dir_child");
+    g_assert_false (g_file_query_exists (file, NULL));
+
+    file = g_file_get_child (first_dir, "move_first_dir_child");
+    g_assert_true (g_file_query_exists (file, NULL));
+    g_assert_true (g_file_query_exists (first_dir, NULL));
+
+    file = g_file_get_child (second_dir, "move_second_dir_child");
+    g_assert_true (g_file_query_exists (file, NULL));
+    g_assert_true (g_file_query_exists (second_dir, NULL));
+
+    empty_directory_by_prefix (root, "move");
+}
+
+static void
+test_move_fourth_hierarchy_undo_redo (void)
+{
+    g_autoptr (GFile) root = NULL;
+    g_autoptr (GFile) first_dir = NULL;
+    g_autoptr (GFile) second_dir = NULL;
+    g_autoptr (GFile) third_dir = NULL;
+    g_autoptr (GFile) file = NULL;
+    g_autoptr (GFile) result_file = NULL;
+    g_autolist (GFile) files = NULL;
+
+    create_fourth_hierarchy ("move");
+
+    root = g_file_new_for_path (g_get_tmp_dir ());
+    first_dir = g_file_get_child (root, "move_first_dir");
+    files = g_list_prepend (files, g_object_ref (first_dir));
+    g_assert_true (first_dir != NULL);
+
+    file = g_file_get_child (first_dir, "move_first_dir_child");
     g_assert_true (file != NULL);
-    g_file_make_directory (file, NULL, NULL);
 
-    third_dir = g_file_get_child (root, "third_dir");
+    second_dir = g_file_get_child (root, "move_second_dir");
+    files = g_list_prepend (files, g_object_ref (second_dir));
+    g_assert_true (second_dir != NULL);
+
+    file = g_file_get_child (second_dir, "move_second_dir_child");
+    g_assert_true (file != NULL);
+
+    third_dir = g_file_get_child (root, "move_third_dir");
     g_assert_true (third_dir != NULL);
-    g_file_make_directory (third_dir, NULL, NULL);
 
     nautilus_file_operations_move_sync (files,
-                                        third_dir,
-                                        NULL,
-                                        NULL,
-                                        NULL);
+                                        third_dir);
+
+    test_operation_undo_redo ();
 
-    result_file = g_file_get_child (third_dir, "first_dir");
+    result_file = g_file_get_child (third_dir, "move_first_dir");
     g_assert_true (g_file_query_exists (result_file, NULL));
-    file = g_file_get_child (result_file, "first_dir_child");
+    file = g_file_get_child (result_file, "move_first_dir_child");
     g_assert_true (g_file_query_exists (file, NULL));
-    g_assert_true (g_file_delete (file, NULL, NULL));
-    g_assert_true (g_file_delete (result_file, NULL, NULL));
 
-    result_file = g_file_get_child (third_dir, "second_dir");
+    result_file = g_file_get_child (third_dir, "move_second_dir");
     g_assert_true (g_file_query_exists (result_file, NULL));
-    file = g_file_get_child (result_file, "second_dir_child");
+    file = g_file_get_child (result_file, "move_second_dir_child");
     g_assert_true (g_file_query_exists (file, NULL));
-    g_assert_true (g_file_delete (file, NULL, NULL));
-    g_assert_true (g_file_delete (result_file, NULL, NULL));
 
-    file = g_file_get_child (first_dir, "first_dir_child");
+    file = g_file_get_child (first_dir, "move_first_dir_child");
     g_assert_false (g_file_query_exists (file, NULL));
     g_assert_false (g_file_query_exists (first_dir, NULL));
 
-    file = g_file_get_child (second_dir, "second_dir_child");
+    file = g_file_get_child (second_dir, "move_second_dir_child");
     g_assert_false (g_file_query_exists (file, NULL));
     g_assert_false (g_file_query_exists (second_dir, NULL));
 
-    g_assert_true (g_file_delete (third_dir, NULL, NULL));
+    empty_directory_by_prefix (root, "move");
 }
 
 static void
@@ -708,30 +1852,82 @@ setup_test_suite (void)
 {
     g_test_add_func ("/test-move-one-file/1.0",
                      test_move_one_file);
+    g_test_add_func ("/test-move-one-file-undo/1.0",
+                     test_move_one_file_undo);
+    g_test_add_func ("/test-move-one-file-undo-redo/1.0",
+                     test_move_one_file_undo_redo);
     g_test_add_func ("/test-move-one-empty-directory/1.0",
                      test_move_one_empty_directory);
+    g_test_add_func ("/test-move-one-empty-directory-undo/1.0",
+                     test_move_one_empty_directory_undo);
+    g_test_add_func ("/test-move-one-empty-directory-undo-redo/1.0",
+                     test_move_one_empty_directory_undo_redo);
     g_test_add_func ("/test-move-files/1.0",
                      test_move_files_small);
+    g_test_add_func ("/test-move-files-undo/1.0",
+                     test_move_files_small_undo);
+    g_test_add_func ("/test-move-files-undo-redo/1.0",
+                     test_move_files_small_undo_redo);
     g_test_add_func ("/test-move-files/1.1",
                      test_move_files_medium);
-    // g_test_add_func ("/test-move-files/1.2",
-    //                  test_move_files_large);
+    g_test_add_func ("/test-move-files-undo/1.1",
+                     test_move_files_medium_undo);
+    g_test_add_func ("/test-move-files-undo-redo/1.1",
+                     test_move_files_medium_undo_redo);
+    g_test_add_func ("/test-move-files/1.2",
+                     test_move_files_large);
+    g_test_add_func ("/test-move-files-undo/1.2",
+                     test_move_files_large_undo);
+    g_test_add_func ("/test-move-files-undo-redo/1.2",
+                     test_move_files_large_undo_redo);
     g_test_add_func ("/test-move-directories/1.0",
                      test_move_directories_small);
+    g_test_add_func ("/test-move-directories-undo/1.0",
+                     test_move_directories_small_undo);
+    g_test_add_func ("/test-move-directories-undo-redo/1.0",
+                     test_move_directories_small_undo_redo);
     g_test_add_func ("/test-move-directories/1.1",
                      test_move_directories_medium);
-    // g_test_add_func ("/test-move-directories/1.2",
-    //                  test_move_directories_large);
+    g_test_add_func ("/test-move-directories-undo/1.1",
+                     test_move_directories_medium_undo);
+    g_test_add_func ("/test-move-directories-undo-redo/1.1",
+                     test_move_directories_medium_undo_redo);
+    g_test_add_func ("/test-move-directories/1.2",
+                     test_move_directories_large);
+    g_test_add_func ("/test-move-directories-undo/1.2",
+                     test_move_directories_large_undo);
+    g_test_add_func ("/test-move-directories-undo-redo/1.2",
+                     test_move_directories_large_undo_redo);
     g_test_add_func ("/test-move-hierarchy/1.0",
-                     test_move_first_hierarchy);
+                     test_move_full_directory);
+    g_test_add_func ("/test-move-hierarchy-undo/1.0",
+                     test_move_full_directory_undo);
+    g_test_add_func ("/test-move-hierarchy-undo-redo/1.0",
+                     test_move_full_directory_undo_redo);
     g_test_add_func ("/test-move-hierarchy/1.1",
-                     test_move_second_hierarchy);
+                     test_move_first_hierarchy);
+    g_test_add_func ("/test-move-hierarchy-undo/1.1",
+                     test_move_first_hierarchy_undo);
+    g_test_add_func ("/test-move-hierarchy-undo-redo/1.1",
+                     test_move_first_hierarchy_undo_redo);
     g_test_add_func ("/test-move-hierarchy/1.2",
-                     test_move_third_hierarchy);
+                     test_move_second_hierarchy);
+    g_test_add_func ("/test-move-hierarchy-undo/1.2",
+                     test_move_second_hierarchy_undo);
+    g_test_add_func ("/test-move-hierarchy-undo-redo/1.2",
+                     test_move_second_hierarchy_undo_redo);
     g_test_add_func ("/test-move-hierarchy/1.3",
-                     test_move_fourth_hierarchy);
+                     test_move_third_hierarchy);
+    g_test_add_func ("/test-move-hierarchy-undo/1.3",
+                     test_move_third_hierarchy_undo);
+    g_test_add_func ("/test-move-hierarchy-undo-redo/1.3",
+                     test_move_third_hierarchy_undo_redo);
     g_test_add_func ("/test-move-hierarchy/1.4",
-                     test_move_fifth_hierarchy);
+                     test_move_fourth_hierarchy);
+    g_test_add_func ("/test-move-hierarchy-undo/1.4",
+                     test_move_fourth_hierarchy_undo);
+    g_test_add_func ("/test-move-hierarchy-undo-redo/1.4",
+                     test_move_fourth_hierarchy_undo_redo);
 }
 
 int
@@ -739,10 +1935,10 @@ main (int argc, char *argv[])
 {
     g_autoptr (NautilusFileUndoManager) undo_manager = NULL;
 
+    undo_manager = nautilus_file_undo_manager_new ();
     g_test_init (&argc, &argv, NULL);
     g_test_set_nonfatal_assertions ();
     nautilus_ensure_extension_points();
-    undo_manager = nautilus_file_undo_manager_new ();
 
     setup_test_suite ();
 
diff --git a/test/automated/displayless/test-file-operations-trash-or-delete.c 
b/test/automated/displayless/test-file-operations-trash-or-delete.c
index e6115ec70..21a451340 100644
--- a/test/automated/displayless/test-file-operations-trash-or-delete.c
+++ b/test/automated/displayless/test-file-operations-trash-or-delete.c
@@ -1,11 +1,4 @@
-#include <glib.h>
-#include "src/nautilus-directory.h"
-#include "src/nautilus-file-utilities.h"
-#include "src/nautilus-search-directory.h"
-#include "src/nautilus-directory.h"
-#include "src/nautilus-file-operations.c"
-#include <unistd.h>
-#include "eel/eel-string.h"
+#include "test-utilities.h"
 
 static void
 test_trash_one_file (void)
@@ -14,31 +7,24 @@ test_trash_one_file (void)
     g_autoptr (GFile) first_dir = NULL;
     g_autoptr (GFile) file = NULL;
     g_autolist (GFile) files = NULL;
-    GFileOutputStream *out = NULL;
-    g_autoptr (GError) error = NULL;
+
+    create_one_file ("trash_or_delete");
 
     root = g_file_new_for_path (g_get_tmp_dir ());
+    g_assert_true (root != NULL);
+
     first_dir = g_file_get_child (root, "trash_or_delete_first_dir");
     g_assert_true (first_dir != NULL);
-    g_file_make_directory (first_dir, NULL, NULL);
 
     file = g_file_get_child (first_dir, "trash_or_delete_first_dir_child");
     g_assert_true (file != NULL);
-    out = g_file_create (file, G_FILE_CREATE_NONE, NULL, &error);
-    if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_EXISTS))
-    {
-        g_object_unref (out);
-    }
     files = g_list_prepend (files, g_object_ref (file));
 
-    trash_or_delete_internal_sync (files,
-                                   NULL,
-                                   TRUE,
-                                   NULL,
-                                   NULL);
+    nautilus_file_operations_trash_or_delete_sync (files);
 
     g_assert_false (g_file_query_exists (file, NULL));
-    g_assert_true (g_file_delete (first_dir, NULL, NULL));
+
+    empty_directory_by_prefix (root, "trash_or_delete");
 }
 
 static void
@@ -47,40 +33,36 @@ test_trash_more_files_func (gint files_to_trash)
     g_autoptr (GFile) root = NULL;
     g_autoptr (GFile) file = NULL;
     g_autolist (GFile) files = NULL;
-    GFileOutputStream *out = NULL;
+
+    create_multiple_files ("trash_or_delete", files_to_trash);
  
     root = g_file_new_for_path (g_get_tmp_dir ());
+    g_assert_true (root != NULL);
  
     for (int i = 0; i < files_to_trash; i++)
     {
-        g_autofree gchar *file_name = NULL;
-        g_autoptr (GError) error = NULL;
+        gchar *file_name;
  
         file_name = g_strdup_printf ("trash_or_delete_file_%i", i);
         file = g_file_get_child (root, file_name);
+        g_free (file_name);
         g_assert_true (file != NULL);
-        out = g_file_create (file, G_FILE_CREATE_NONE, NULL, &error);
-        if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_EXISTS))
-        {
-            g_object_unref (out);
-        }
         files = g_list_prepend (files, g_object_ref (file));
     }
  
-    trash_or_delete_internal_sync (files,
-                                   NULL,
-                                   TRUE,
-                                   NULL,
-                                   NULL);
+    nautilus_file_operations_trash_or_delete_sync (files);
  
     for (int i = 0; i < files_to_trash; i++)
     {
-        g_autofree gchar *file_name = NULL;
+        gchar *file_name;
 
         file_name = g_strdup_printf ("trash_or_delete_file_%i", i);
         file = g_file_get_child (root, file_name);
+        g_free (file_name);
         g_assert_false (g_file_query_exists (file, NULL));
     }
+
+    empty_directory_by_prefix (root, "trash_or_delete");
 }
 
 static void
@@ -96,31 +78,24 @@ test_delete_one_file (void)
     g_autoptr (GFile) first_dir = NULL;
     g_autoptr (GFile) file = NULL;
     g_autolist (GFile) files = NULL;
-    GFileOutputStream *out = NULL;
-    g_autoptr (GError) error = NULL;
+
+    create_one_file ("trash_or_delete");
 
     root = g_file_new_for_path (g_get_tmp_dir ());
+    g_assert_true (root != NULL);
+
     first_dir = g_file_get_child (root, "trash_or_delete_first_dir");
     g_assert_true (first_dir != NULL);
-    g_file_make_directory (first_dir, NULL, NULL);
 
     file = g_file_get_child (first_dir, "trash_or_delete_first_dir_child");
     g_assert_true (file != NULL);
-    out = g_file_create (file, G_FILE_CREATE_NONE, NULL, &error);
-    if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_EXISTS))
-    {
-        g_object_unref (out);
-    }
     files = g_list_prepend (files, g_object_ref (file));
 
-    trash_or_delete_internal_sync (files,
-                                   NULL,
-                                   TRUE,
-                                   NULL,
-                                   NULL);
+    nautilus_file_operations_delete_sync (files);
 
     g_assert_false (g_file_query_exists (file, NULL));
-    g_assert_true (g_file_delete (first_dir, NULL, NULL));
+
+    empty_directory_by_prefix (root, "trash_or_delete");
 }
 
 static void
@@ -129,40 +104,36 @@ test_delete_more_files_func (gint files_to_delete)
     g_autoptr (GFile) root = NULL;
     g_autoptr (GFile) file = NULL;
     g_autolist (GFile) files = NULL;
-    GFileOutputStream *out = NULL;
+
+    create_multiple_files ("trash_or_delete", files_to_delete);
  
     root = g_file_new_for_path (g_get_tmp_dir ());
+    g_assert_true (root != NULL);
  
     for (int i = 0; i < files_to_delete; i++)
     {
-        g_autofree gchar *file_name = NULL;
-        g_autoptr (GError) error = NULL;
+        gchar *file_name;
  
         file_name = g_strdup_printf ("trash_or_delete_file_%i", i);
         file = g_file_get_child (root, file_name);
+        g_free (file_name);
         g_assert_true (file != NULL);
-        out = g_file_create (file, G_FILE_CREATE_NONE, NULL, &error);
-        if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_EXISTS))
-        {
-            g_object_unref (out);
-        }
         files = g_list_prepend (files, g_object_ref (file));
     }
  
-    trash_or_delete_internal_sync (files,
-                                   NULL,
-                                   FALSE,
-                                   NULL,
-                                   NULL);
+    nautilus_file_operations_delete_sync (files);
  
     for (int i = 0; i < files_to_delete; i++)
     {
-        g_autofree gchar *file_name = NULL;
+        gchar *file_name;
 
         file_name = g_strdup_printf ("trash_or_delete_file_%i", i);
         file = g_file_get_child (root, file_name);
+        g_free (file_name);
         g_assert_false (g_file_query_exists (file, NULL));
     }
+
+    empty_directory_by_prefix (root, "trash_or_delete");
 }
 
 static void
@@ -176,22 +147,27 @@ test_trash_one_empty_directory (void)
 {
     g_autoptr (GFile) root = NULL;
     g_autoptr (GFile) first_dir = NULL;
+    g_autoptr (GFile) file = NULL;
     g_autolist (GFile) files = NULL;
 
+    create_one_empty_directory ("trash_or_delete");
+
     root = g_file_new_for_path (g_get_tmp_dir ());
+    g_assert_true (root != NULL);
+
     first_dir = g_file_get_child (root, "trash_or_delete_first_dir");
     g_assert_true (first_dir != NULL);
-    g_file_make_directory (first_dir, NULL, NULL);
 
-    files = g_list_prepend (files, g_object_ref (first_dir));
+    file = g_file_get_child (first_dir, "trash_or_delete_first_dir_child");
+    g_assert_true (file != NULL);
 
-    trash_or_delete_internal_sync (files,
-                                   NULL,
-                                   TRUE,
-                                   NULL,
-                                   NULL);
+    files = g_list_prepend (files, g_object_ref (file));
 
-    g_assert_false (g_file_query_exists (first_dir, NULL));
+    nautilus_file_operations_trash_or_delete_sync (files);
+
+    g_assert_false (g_file_query_exists (file, NULL));
+
+    empty_directory_by_prefix (root, "trash_or_delete");
 }
 
 static void
@@ -201,35 +177,37 @@ test_trash_more_empty_directories_func (gint directories_to_trash)
     g_autoptr (GFile) file = NULL;
     g_autoptr (GFile) dir = NULL;
     g_autolist (GFile) files = NULL;
+
+    create_multiple_directories ("trash_or_delete", directories_to_trash);
  
     root = g_file_new_for_path (g_get_tmp_dir ());
+    g_assert_true (root != NULL);
  
     for (int i = 0; i < directories_to_trash; i++)
     {
-        g_autofree gchar *file_name = NULL;
+        gchar *file_name;
 
         file_name = g_strdup_printf ("trash_or_delete_file_%i", i);
         file = g_file_get_child (root, file_name);
+        g_free (file_name);
         g_assert_true (file != NULL);
-        g_file_make_directory (file, NULL, NULL);
         files = g_list_prepend (files, g_object_ref (file));
     }
  
-    trash_or_delete_internal_sync (files,
-                                   NULL,
-                                   TRUE,
-                                   NULL,
-                                   NULL);
+    nautilus_file_operations_trash_or_delete_sync (files);
 
     for (int i = 0; i < directories_to_trash; i++)
     {
-        g_autofree gchar *file_name = NULL;
+        gchar *file_name;
 
         file_name = g_strdup_printf ("trash_or_delete_file_%i", i);
         file = g_file_get_child (root, file_name);
+        g_free (file_name);
         g_assert_true (file != NULL);
         g_assert_false (g_file_query_exists (file, NULL));
     }
+
+    empty_directory_by_prefix (root, "trash_or_delete");
 }
 
 static void
@@ -243,22 +221,26 @@ test_delete_one_empty_directory (void)
 {
     g_autoptr (GFile) root = NULL;
     g_autoptr (GFile) first_dir = NULL;
+    g_autoptr (GFile) file = NULL;
     g_autolist (GFile) files = NULL;
 
+    create_one_empty_directory ("trash_or_delete");
+
     root = g_file_new_for_path (g_get_tmp_dir ());
+    g_assert_true (root != NULL);
+
     first_dir = g_file_get_child (root, "trash_or_delete_first_dir");
     g_assert_true (first_dir != NULL);
-    g_file_make_directory (first_dir, NULL, NULL);
+    file = g_file_get_child (first_dir, "trash_or_delete_first_dir_child");
+    g_assert_true (file != NULL);
 
-    files = g_list_prepend (files, g_object_ref (first_dir));
+    files = g_list_prepend (files, g_object_ref (file));
 
-    trash_or_delete_internal_sync (files,
-                                   NULL,
-                                   FALSE,
-                                   NULL,
-                                   NULL);
+    nautilus_file_operations_delete_sync (files);
 
-    g_assert_false (g_file_query_exists (first_dir, NULL));
+    g_assert_false (g_file_query_exists (file, NULL));
+
+    empty_directory_by_prefix (root, "trash_or_delete");
 }
 
 static void
@@ -268,35 +250,38 @@ test_delete_more_empty_directories_func (gint directories_to_delete)
     g_autoptr (GFile) file = NULL;
     g_autoptr (GFile) dir = NULL;
     g_autolist (GFile) files = NULL;
+
+    create_multiple_directories ("trash_or_delete", directories_to_delete);
  
     root = g_file_new_for_path (g_get_tmp_dir ());
+    g_assert_true (root != NULL);
  
     for (int i = 0; i < directories_to_delete; i++)
     {
-        g_autofree gchar *file_name = NULL;
+        gchar *file_name;
 
         file_name = g_strdup_printf ("trash_or_delete_file_%i", i);
         file = g_file_get_child (root, file_name);
+        g_free (file_name);
         g_assert_true (file != NULL);
-        g_file_make_directory (file, NULL, NULL);
         files = g_list_prepend (files, g_object_ref (file));
     }
  
-    trash_or_delete_internal_sync (files,
-                                   NULL,
-                                   FALSE,
-                                   NULL,
-                                   NULL);
+    nautilus_file_operations_delete_sync (files);
+
 
     for (int i = 0; i < directories_to_delete; i++)
     {
-        g_autofree gchar *file_name = NULL;
+        gchar *file_name;
 
         file_name = g_strdup_printf ("trash_or_delete_file_%i", i);
         file = g_file_get_child (root, file_name);
+        g_free (file_name);
         g_assert_true (file != NULL);
         g_assert_false (g_file_query_exists (file, NULL));
     }
+
+    empty_directory_by_prefix (root, "trash_or_delete");
 }
 
 static void
@@ -305,72 +290,37 @@ test_delete_more_empty_directories (void)
     test_delete_more_empty_directories_func (100);
 }
 
+/* The hierarchy looks like this:
+ * /tmp/first_dir/first_dir_child
+ * We're trashing first_dir.
+ */
 static void
-test_trash_one_full_directory (void)
+test_trash_full_directory (void)
 {
     g_autoptr (GFile) root = NULL;
     g_autoptr (GFile) first_dir = NULL;
     g_autoptr (GFile) file = NULL;
     g_autolist (GFile) files = NULL;
-    GFileOutputStream *out = NULL;
-    g_autoptr (GError) error = NULL;
+
+    create_one_file ("trash_or_delete");
 
     root = g_file_new_for_path (g_get_tmp_dir ());
+    g_assert_true (root != NULL);
+
     first_dir = g_file_get_child (root, "trash_or_delete_first_dir");
     g_assert_true (first_dir != NULL);
-    g_file_make_directory (first_dir, NULL, NULL);
 
     file = g_file_get_child (first_dir, "trash_or_delete_first_dir_child");
     g_assert_true (file != NULL);
-    out = g_file_create (file, G_FILE_CREATE_NONE, NULL, &error);
-    if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_EXISTS))
-    {
-        g_object_unref (out);
-    }
 
     files = g_list_prepend (files, g_object_ref (first_dir));
 
-    trash_or_delete_internal_sync (files,
-                                   NULL,
-                                   TRUE,
-                                   NULL,
-                                   NULL);
+    nautilus_file_operations_trash_or_delete_sync (files);
 
     g_assert_false (g_file_query_exists (first_dir, NULL));
     g_assert_false (g_file_query_exists (file, NULL));
-}
-
-/* The hierarchy looks like this:
- * /tmp/first_dir/first_dir_child
- * We're trashing first_dir.
- */
-static void
-test_trash_first_hierarchy (void)
-{
-    g_autoptr (GFile) root = NULL;
-    g_autoptr (GFile) first_dir = NULL;
-    g_autoptr (GFile) file = NULL;
-    g_autolist (GFile) files = NULL;
- 
-    root = g_file_new_for_path (g_get_tmp_dir ());
-    first_dir = g_file_get_child (root, "trash_or_delete_first_dir");
-    files = g_list_prepend (files, g_object_ref (first_dir));
-    g_assert_true (first_dir != NULL);
-    g_file_make_directory (first_dir, NULL, NULL);
- 
-    file = g_file_get_child (first_dir, "trash_or_delete_first_dir_child");
-    g_assert_true (file != NULL);
-    g_file_make_directory (file, NULL, NULL);
- 
-    trash_or_delete_internal_sync (files,
-                                   NULL,
-                                   TRUE,
-                                   NULL,
-                                   NULL);
-
-    g_assert_false (g_file_query_exists (file, NULL));
 
-    g_assert_false (g_file_query_exists (first_dir, NULL)); 
+    empty_directory_by_prefix (root, "trash_or_delete");
 }
  
 /* The hierarchy looks like this:
@@ -379,31 +329,28 @@ test_trash_first_hierarchy (void)
  * We're trashing first_dir.
  */
 static void
-test_trash_second_hierarchy (void)
+test_trash_first_hierarchy (void)
 {
     g_autoptr (GFile) root = NULL;
     g_autoptr (GFile) first_dir = NULL;
     g_autoptr (GFile) file = NULL;
     g_autolist (GFile) files = NULL;
+
+    create_first_hierarchy ("trash_or_delete");
  
     root = g_file_new_for_path (g_get_tmp_dir ());
+    g_assert_true (root != NULL);
+
     first_dir = g_file_get_child (root, "trash_or_delete_first_dir");
     files = g_list_prepend (files, g_object_ref (first_dir));
     g_assert_true (first_dir != NULL);
-    g_file_make_directory (first_dir, NULL, NULL);
  
     file = g_file_get_child (first_dir, "trash_or_delete_first_child");
     g_assert_true (file != NULL);
-    g_file_make_directory (file, NULL, NULL);
     file = g_file_get_child (first_dir, "trash_or_delete_second_child");
     g_assert_true (file != NULL);
-    g_file_make_directory (file, NULL, NULL);
 
-    trash_or_delete_internal_sync (files,
-                                   NULL,
-                                   TRUE,
-                                   NULL,
-                                   NULL);
+    nautilus_file_operations_trash_or_delete_sync (files);
 
     file = g_file_get_child (first_dir, "trash_or_delete_first_dir_child");
     g_assert_false (g_file_query_exists (file, NULL));
@@ -412,6 +359,8 @@ test_trash_second_hierarchy (void)
     g_assert_false (g_file_query_exists (file, NULL));
 
     g_assert_false (g_file_query_exists (first_dir, NULL));
+
+    empty_directory_by_prefix (root, "trash_or_delete");
  }
 
 /* We're creating 50 directories each containing one file
@@ -424,111 +373,75 @@ test_trash_third_hierarchy (void)
     g_autoptr (GFile) directory = NULL;
     g_autoptr (GFile) file = NULL;
     g_autolist (GFile) files = NULL;
- 
+
+    create_multiple_full_directories ("trash_or_delete", 50);
+
     root = g_file_new_for_path (g_get_tmp_dir ());
+    g_assert_true (root != NULL);
 
     for (int i = 0; i < 50; i++)
     {
-        g_autofree gchar *file_name = NULL;
+        gchar *file_name;
 
         file_name = g_strdup_printf ("trash_or_delete_directory_%i", i);
 
         directory = g_file_get_child (root, file_name);
-        g_file_make_directory (directory, NULL, NULL);
+        g_free (file_name);
         files = g_list_prepend (files, g_object_ref (directory));
-
-        file_name = g_strdup_printf ("trash_or_delete_file_%i", i);
-        file = g_file_get_child (directory, file_name);
-        g_file_make_directory (file, NULL, NULL);
     }
  
-    trash_or_delete_internal_sync (files,
-                                   NULL,
-                                   TRUE,
-                                   NULL,
-                                   NULL);
+    nautilus_file_operations_trash_or_delete_sync (files);
 
     for (int i = 0; i < 50; i++)
     {
-        g_autofree gchar *file_name = NULL;
+        gchar *file_name;
 
         file_name = g_strdup_printf ("trash_or_delete_directory_%i", i);
 
         directory = g_file_get_child (root, file_name);
+        g_free (file_name);
         g_assert_false (g_file_query_exists (directory, NULL));
 
         file_name = g_strdup_printf ("trash_or_delete_file_%i", i);
         file = g_file_get_child (directory, file_name);
+        g_free (file_name);
         g_assert_false (g_file_query_exists (file, NULL));
     }
+
+    empty_directory_by_prefix (root, "trash_or_delete");
 }
 
+/* The hierarchy looks like this:
+ * /tmp/first_dir/first_dir_child
+ * We're deleting first_dir.
+ */
 static void
-test_delete_one_full_directory (void)
+test_delete_full_directory (void)
 {
     g_autoptr (GFile) root = NULL;
     g_autoptr (GFile) first_dir = NULL;
     g_autoptr (GFile) file = NULL;
     g_autolist (GFile) files = NULL;
-    GFileOutputStream *out = NULL;
-    g_autoptr (GError) error = NULL;
+
+    create_one_file ("trash_or_delete");
 
     root = g_file_new_for_path (g_get_tmp_dir ());
+    g_assert_true (root != NULL);
+
     first_dir = g_file_get_child (root, "trash_or_delete_first_dir");
     g_assert_true (first_dir != NULL);
-    g_file_make_directory (first_dir, NULL, NULL);
 
     file = g_file_get_child (first_dir, "trash_or_delete_first_dir_child");
     g_assert_true (file != NULL);
-    out = g_file_create (file, G_FILE_CREATE_NONE, NULL, &error);
-    if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_EXISTS))
-    {
-        g_object_unref (out);
-    }
 
     files = g_list_prepend (files, g_object_ref (first_dir));
 
-    trash_or_delete_internal_sync (files,
-                                   NULL,
-                                   FALSE,
-                                   NULL,
-                                   NULL);
+    nautilus_file_operations_delete_sync (files);
 
     g_assert_false (g_file_query_exists (first_dir, NULL));
     g_assert_false (g_file_query_exists (file, NULL));
-}
 
-/* The hierarchy looks like this:
- * /tmp/first_dir/first_dir_child
- * We're deleting first_dir.
- */
-static void
-test_delete_first_hierarchy (void)
-{
-    g_autoptr (GFile) root = NULL;
-    g_autoptr (GFile) first_dir = NULL;
-    g_autoptr (GFile) file = NULL;
-    g_autolist (GFile) files = NULL;
- 
-    root = g_file_new_for_path (g_get_tmp_dir ());
-    first_dir = g_file_get_child (root, "trash_or_delete_first_dir");
-    files = g_list_prepend (files, g_object_ref (first_dir));
-    g_assert_true (first_dir != NULL);
-    g_file_make_directory (first_dir, NULL, NULL);
- 
-    file = g_file_get_child (first_dir, "trash_or_delete_first_dir_child");
-    g_assert_true (file != NULL);
-    g_file_make_directory (file, NULL, NULL);
- 
-    trash_or_delete_internal_sync (files,
-                                   NULL,
-                                   FALSE,
-                                   NULL,
-                                   NULL);
-
-    g_assert_false (g_file_query_exists (file, NULL));
-
-    g_assert_false (g_file_query_exists (first_dir, NULL)); 
+    empty_directory_by_prefix (root, "trash_or_delete");
 }
  
 /* The hierarchy looks like this:
@@ -537,31 +450,28 @@ test_delete_first_hierarchy (void)
  * We're deleting first_dir.
  */
 static void
-test_delete_second_hierarchy (void)
+test_delete_first_hierarchy (void)
 {
     g_autoptr (GFile) root = NULL;
     g_autoptr (GFile) first_dir = NULL;
     g_autoptr (GFile) file = NULL;
     g_autolist (GFile) files = NULL;
+
+    create_first_hierarchy ("trash_or_delete");
  
     root = g_file_new_for_path (g_get_tmp_dir ());
+    g_assert_true (root != NULL);
+
     first_dir = g_file_get_child (root, "trash_or_delete_first_dir");
     files = g_list_prepend (files, g_object_ref (first_dir));
     g_assert_true (first_dir != NULL);
-    g_file_make_directory (first_dir, NULL, NULL);
  
     file = g_file_get_child (first_dir, "trash_or_delete_first_child");
     g_assert_true (file != NULL);
-    g_file_make_directory (file, NULL, NULL);
     file = g_file_get_child (first_dir, "trash_or_delete_second_child");
     g_assert_true (file != NULL);
-    g_file_make_directory (file, NULL, NULL);
 
-    trash_or_delete_internal_sync (files,
-                                   NULL,
-                                   FALSE,
-                                   NULL,
-                                   NULL);
+    nautilus_file_operations_delete_sync (files);
 
     file = g_file_get_child (first_dir, "trash_or_delete_first_dir_child");
     g_assert_false (g_file_query_exists (file, NULL));
@@ -570,6 +480,8 @@ test_delete_second_hierarchy (void)
     g_assert_false (g_file_query_exists (file, NULL));
 
     g_assert_false (g_file_query_exists (first_dir, NULL));
+
+    empty_directory_by_prefix (root, "trash_or_delete");
  }
 
 /* We're creating 50 directories each containing one file
@@ -582,43 +494,42 @@ test_delete_third_hierarchy (void)
     g_autoptr (GFile) directory = NULL;
     g_autoptr (GFile) file = NULL;
     g_autolist (GFile) files = NULL;
- 
+
+    create_multiple_full_directories ("trash_or_delete", 50);
+
     root = g_file_new_for_path (g_get_tmp_dir ());
+    g_assert_true (root != NULL);
 
     for (int i = 0; i < 50; i++)
     {
-        g_autofree gchar *file_name = NULL;
+        gchar *file_name;
 
         file_name = g_strdup_printf ("trash_or_delete_directory_%i", i);
 
         directory = g_file_get_child (root, file_name);
-        g_file_make_directory (directory, NULL, NULL);
+        g_free (file_name);
         files = g_list_prepend (files, g_object_ref (directory));
-
-        file_name = g_strdup_printf ("trash_or_delete_file_%i", i);
-        file = g_file_get_child (directory, file_name);
-        g_file_make_directory (file, NULL, NULL);
     }
  
-    trash_or_delete_internal_sync (files,
-                                   NULL,
-                                   FALSE,
-                                   NULL,
-                                   NULL);
+    nautilus_file_operations_delete_sync (files);
 
     for (int i = 0; i < 50; i++)
     {
-        g_autofree gchar *file_name = NULL;
+        gchar *file_name;
 
         file_name = g_strdup_printf ("trash_or_delete_directory_%i", i);
 
         directory = g_file_get_child (root, file_name);
+        g_free (file_name);
         g_assert_false (g_file_query_exists (directory, NULL));
 
         file_name = g_strdup_printf ("trash_or_delete_file_%i", i);
         file = g_file_get_child (directory, file_name);
+        g_free (file_name);
         g_assert_false (g_file_query_exists (file, NULL));
     }
+
+    empty_directory_by_prefix (root, "trash_or_delete");
 }
 
 static void
@@ -641,19 +552,15 @@ setup_test_suite (void)
     g_test_add_func ("/test-delete-more-directories/1.0",
                      test_delete_more_empty_directories);
     g_test_add_func ("/test-trash-one-full-directory/1.0",
-                     test_trash_one_full_directory);
+                     test_trash_full_directory);
     g_test_add_func ("/test-trash-one-full-directory/1.1",
                      test_trash_first_hierarchy);
-    g_test_add_func ("/test-trash-one-full-directory/1.2",
-                     test_trash_second_hierarchy);
-    g_test_add_func ("/test-trash-more-full-directories/1.6",
+    g_test_add_func ("/test-trash-more-full-directories/1.2",
                      test_trash_third_hierarchy);
     g_test_add_func ("/test-delete-one-full-directory/1.0",
-                     test_delete_one_full_directory);
+                     test_delete_full_directory);
     g_test_add_func ("/test-delete-one-full-directory/1.1",
                      test_delete_first_hierarchy);
-    g_test_add_func ("/test-delete-one-full-directory/1.2",
-                     test_delete_second_hierarchy);
     g_test_add_func ("/test-delete-more-full-directories/1.6",
                      test_delete_third_hierarchy);
 
diff --git a/test/automated/displayless/test-nautilus-search-engine-model.c 
b/test/automated/displayless/test-nautilus-search-engine-model.c
new file mode 100644
index 000000000..05086f8b7
--- /dev/null
+++ b/test/automated/displayless/test-nautilus-search-engine-model.c
@@ -0,0 +1,72 @@
+#include "test-utilities.h"
+
+static void
+hits_added_cb (NautilusSearchEngine *engine,
+               GSList               *hits)
+{
+    g_print ("Hits added for search engine model!\n");
+    for (gint hit_number = 0; hits != NULL; hits = hits->next, hit_number++)
+    {
+        g_print ("Hit %i: %s\n", hit_number, nautilus_search_hit_get_uri (hits->data));
+    }
+}
+
+static void
+finished_cb (NautilusSearchEngine         *engine,
+             NautilusSearchProviderStatus  status,
+             gpointer                      user_data)
+{
+    nautilus_search_provider_stop (NAUTILUS_SEARCH_PROVIDER (engine));
+
+    g_print ("\nNautilus search engine model finished!\n");
+
+    delete_search_file_hierarchy ("model");
+
+    g_main_loop_quit (user_data);
+}
+
+int
+main (int   argc,
+      char *argv[])
+{
+    g_autoptr (GMainLoop) loop = NULL;
+    NautilusSearchEngine *engine;
+    NautilusSearchEngineModel *model;
+    g_autoptr (NautilusDirectory) directory = NULL;
+    g_autoptr (NautilusQuery) query = NULL;
+    g_autoptr (GFile) location = NULL;
+
+    loop = g_main_loop_new (NULL, FALSE);
+
+    nautilus_ensure_extension_points ();
+    /* Needed for nautilus-query.c. 
+     * FIXME: tests are not installed, so the system does not
+     * have the gschema. Installed tests is a long term GNOME goal.
+     */
+    nautilus_global_preferences_init ();
+
+    engine = nautilus_search_engine_new ();
+    g_signal_connect (engine, "hits-added",
+                      G_CALLBACK (hits_added_cb), NULL);
+    g_signal_connect (engine, "finished",
+                      G_CALLBACK (finished_cb), loop);
+
+    query = nautilus_query_new ();
+    nautilus_query_set_text (query, "engine_model");
+    nautilus_search_provider_set_query (NAUTILUS_SEARCH_PROVIDER (engine), query);
+
+    location = g_file_new_for_path (g_get_tmp_dir ());
+    directory = nautilus_directory_get (location);
+    model = nautilus_search_engine_get_model_provider (engine);
+    nautilus_search_engine_model_set_model (model, directory);
+
+    nautilus_query_set_location (query, location);
+
+    create_search_file_hierarchy ("model");
+
+    nautilus_search_engine_start_by_target (NAUTILUS_SEARCH_PROVIDER (engine),
+                                            NAUTILUS_SEARCH_ENGINE_MODEL_ENGINE);
+
+    g_main_loop_run (loop);
+    return 0;
+}
diff --git a/test/automated/displayless/test-nautilus-search-engine-simple.c 
b/test/automated/displayless/test-nautilus-search-engine-simple.c
new file mode 100644
index 000000000..82eb865b3
--- /dev/null
+++ b/test/automated/displayless/test-nautilus-search-engine-simple.c
@@ -0,0 +1,68 @@
+#include "test-utilities.h"
+
+static void
+hits_added_cb (NautilusSearchEngine *engine,
+               GSList               *hits)
+{
+    g_print ("Hits added for search engine simple!\n");
+    for (gint hit_number = 0; hits != NULL; hits = hits->next, hit_number++)
+    {
+        g_print ("Hit %i: %s\n", hit_number, nautilus_search_hit_get_uri (hits->data));
+    }
+}
+
+static void
+finished_cb (NautilusSearchEngine         *engine,
+             NautilusSearchProviderStatus  status,
+             gpointer                      user_data)
+{
+    nautilus_search_provider_stop (NAUTILUS_SEARCH_PROVIDER (engine));
+
+    g_print ("\nNautilus search engine simple finished!\n");
+
+    delete_search_file_hierarchy ("simple");
+
+    g_main_loop_quit (user_data);
+}
+
+int
+main (int   argc,
+      char *argv[])
+{
+    g_autoptr (GMainLoop) loop = NULL;
+    NautilusSearchEngine *engine;
+    g_autoptr (NautilusDirectory) directory = NULL;
+    g_autoptr (NautilusQuery) query = NULL;
+    g_autoptr (GFile) location = NULL;
+
+    loop = g_main_loop_new (NULL, FALSE);
+
+    nautilus_ensure_extension_points ();
+    /* Needed for nautilus-query.c. 
+     * FIXME: tests are not installed, so the system does not
+     * have the gschema. Installed tests is a long term GNOME goal.
+     */
+    nautilus_global_preferences_init ();
+
+    engine = nautilus_search_engine_new ();
+    g_signal_connect (engine, "hits-added",
+                      G_CALLBACK (hits_added_cb), NULL);
+    g_signal_connect (engine, "finished",
+                      G_CALLBACK (finished_cb), loop);
+
+    query = nautilus_query_new ();
+    nautilus_query_set_text (query, "engine_simple");
+    nautilus_search_provider_set_query (NAUTILUS_SEARCH_PROVIDER (engine), query);
+
+    location = g_file_new_for_path (g_get_tmp_dir ());
+    directory = nautilus_directory_get (location);
+    nautilus_query_set_location (query, location);
+
+    create_search_file_hierarchy ("simple");
+
+    nautilus_search_engine_start_by_target (NAUTILUS_SEARCH_PROVIDER (engine),
+                                            NAUTILUS_SEARCH_ENGINE_SIMPLE_ENGINE);
+
+    g_main_loop_run (loop);
+    return 0;
+}
diff --git a/test/automated/displayless/test-nautilus-search-engine-tracker.c 
b/test/automated/displayless/test-nautilus-search-engine-tracker.c
new file mode 100644
index 000000000..13caafaba
--- /dev/null
+++ b/test/automated/displayless/test-nautilus-search-engine-tracker.c
@@ -0,0 +1,106 @@
+#include "test-utilities.h"
+
+static void
+hits_added_cb (NautilusSearchEngine *engine,
+               GSList               *hits)
+{
+    g_print ("Hits added for search engine tracker!\n");
+    for (gint hit_number = 0; hits != NULL; hits = hits->next, hit_number++)
+    {
+        g_print ("Hit %i: %s\n", hit_number, nautilus_search_hit_get_uri (hits->data));
+    }
+}
+
+static void
+finished_cb (NautilusSearchEngine         *engine,
+             NautilusSearchProviderStatus  status,
+             gpointer                      user_data)
+{
+    TrackerSparqlConnection *connection;
+    g_autofree gchar *sparql_query;
+
+    nautilus_search_provider_stop (NAUTILUS_SEARCH_PROVIDER (engine));
+
+    g_print ("\nNautilus search engine tracker finished!\n");
+
+    connection = tracker_sparql_connection_get (NULL, NULL);
+    sparql_query = g_strdup_printf ("DELETE WHERE { <nautilus-test-tracker> ?p ?o }");
+    tracker_sparql_connection_update (connection,
+                                      sparql_query,
+                                      0,
+                                      NULL,
+                                      NULL);
+
+    g_main_loop_quit (user_data);
+}
+
+int
+main (int   argc,
+      char *argv[])
+{
+    g_autoptr (GMainLoop) loop = NULL;
+    NautilusSearchEngine *engine;
+    g_autoptr (NautilusDirectory) directory = NULL;
+    g_autoptr (NautilusQuery) query = NULL;
+    g_autoptr (GFile) location = NULL;
+    TrackerSparqlConnection *connection;
+    g_autofree gchar *sparql_query;
+
+    connection = tracker_sparql_connection_get (NULL, NULL);
+
+    loop = g_main_loop_new (NULL, FALSE);
+
+    nautilus_ensure_extension_points ();
+    /* Needed for nautilus-query.c. 
+     * FIXME: tests are not installed, so the system does not
+     * have the gschema. Installed tests is a long term GNOME goal.
+     */
+    nautilus_global_preferences_init ();
+
+    engine = nautilus_search_engine_new ();
+    g_signal_connect (engine, "hits-added",
+                      G_CALLBACK (hits_added_cb), NULL);
+    g_signal_connect (engine, "finished",
+                      G_CALLBACK (finished_cb), loop);
+
+    query = nautilus_query_new ();
+    nautilus_query_set_text (query, "target");
+    nautilus_search_provider_set_query (NAUTILUS_SEARCH_PROVIDER (engine), query);
+
+    location = g_file_new_for_path (g_get_tmp_dir ());
+    directory = nautilus_directory_get (location);
+    nautilus_query_set_location (query, location);
+
+    /* This sparql query with the update call create a virtual file
+     * in tracker, so it sees a file named "target_file" in /tmp.
+     * The file's MIME type is text/plain and the name tracker is
+     * using for search is "target". For the engine tracker to hit,
+     * we also need to set the last time the file was accessed and modified,
+     * which we set to 2001-01-01, at 00:00:01 (the date needs to be a full
+     * ISO 8601 date string) and tracker:available be set to true (in order
+     * for the file to be accessible).
+     */
+
+    sparql_query = g_strdup_printf ("INSERT DATA {\n<nautilus-test-tracker> ");
+    sparql_query = g_strconcat (sparql_query, "a nfo:FileDataObject ;", NULL);
+    sparql_query = g_strconcat (sparql_query, "\na nie:InformationElement ;", NULL);
+    sparql_query = g_strconcat (sparql_query, "\nnie:url 'file:///tmp/target_file';", NULL);
+    sparql_query = g_strconcat (sparql_query, "\nnie:mimeType 'text/plain';", NULL);
+    sparql_query = g_strconcat (sparql_query, "\nnfo:fileName 'target';", NULL);
+    sparql_query = g_strconcat (sparql_query, "\nnfo:fileLastModified '2001-01-01T00:00:01Z';", NULL);
+    sparql_query = g_strconcat (sparql_query, "\nnfo:fileLastAccessed '2001-01-01T00:00:01Z';", NULL);
+    sparql_query = g_strconcat (sparql_query, "\ntracker:available true", NULL);
+    sparql_query = g_strconcat (sparql_query, ".\n}\n", NULL);
+
+    tracker_sparql_connection_update (connection,
+                                      sparql_query,
+                                      0,
+                                      NULL,
+                                      NULL);
+
+    nautilus_search_engine_start_by_target (NAUTILUS_SEARCH_PROVIDER (engine),
+                                            NAUTILUS_SEARCH_ENGINE_TRACKER_ENGINE);
+
+    g_main_loop_run (loop);
+    return 0;
+}
diff --git a/test/automated/displayless/test-nautilus-search-engine.c 
b/test/automated/displayless/test-nautilus-search-engine.c
index 8fb66aad4..d80f1fa20 100644
--- a/test/automated/displayless/test-nautilus-search-engine.c
+++ b/test/automated/displayless/test-nautilus-search-engine.c
@@ -1,18 +1,13 @@
-#include <src/nautilus-file-utilities.h>
-#include <src/nautilus-global-preferences.h>
-#include <src/nautilus-search-provider.h>
-#include <src/nautilus-search-engine.h>
-#include <gtk/gtk.h>
+#include "test-utilities.h"
 
 static void
 hits_added_cb (NautilusSearchEngine *engine,
                GSList               *hits)
 {
-    g_print ("hits added\n");
-    while (hits)
+    g_print ("Hits added for search engine!\n");
+    for (gint hit_number = 0; hits != NULL; hits = hits->next, hit_number++)
     {
-        g_print (" - %s\n", (char *) hits->data);
-        hits = hits->next;
+        g_print ("Hit %i: %s\n", hit_number, nautilus_search_hit_get_uri (hits->data));
     }
 }
 
@@ -21,7 +16,12 @@ finished_cb (NautilusSearchEngine         *engine,
              NautilusSearchProviderStatus  status,
              gpointer                      user_data)
 {
-    g_print ("finished!\n");
+    nautilus_search_provider_stop (NAUTILUS_SEARCH_PROVIDER (engine));
+
+    g_print ("\nNautilus search engine finished!\n");
+
+    delete_search_file_hierarchy ("all_engines");
+
     g_main_loop_quit (user_data);
 }
 
@@ -29,17 +29,20 @@ int
 main (int   argc,
       char *argv[])
 {
-    GMainLoop *loop;
+    g_autoptr (GMainLoop) loop = NULL;
     NautilusSearchEngine *engine;
-    NautilusSearchEngineModel *model;
-    NautilusDirectory *directory;
-    NautilusQuery *query;
-    GFile *location;
+    g_autoptr (NautilusDirectory) directory = NULL;
+    g_autoptr (NautilusQuery) query = NULL;
+    g_autoptr (GFile) location = NULL;
+    g_autoptr (GFile) file = NULL;
 
-    loop = g_main_loop_new (NULL, TRUE);
+    loop = g_main_loop_new (NULL, FALSE);
 
     nautilus_ensure_extension_points ();
-    /* Needed for nautilus-query.c. */
+    /* Needed for nautilus-query.c. 
+     * FIXME: tests are not installed, so the system does not
+     * have the gschema. Installed tests is a long term GNOME goal.
+     */
     nautilus_global_preferences_init ();
 
     engine = nautilus_search_engine_new ();
@@ -49,21 +52,16 @@ main (int   argc,
                       G_CALLBACK (finished_cb), loop);
 
     query = nautilus_query_new ();
-    nautilus_query_set_text (query, "richard hult");
+    nautilus_query_set_text (query, "engine_all_engines");
     nautilus_search_provider_set_query (NAUTILUS_SEARCH_PROVIDER (engine), query);
-    g_object_unref (query);
 
-    location = g_file_new_for_path (g_get_home_dir ());
+    location = g_file_new_for_path (g_get_tmp_dir ());
     directory = nautilus_directory_get (location);
-    g_object_unref (location);
+    nautilus_query_set_location (query, location);
 
-    model = nautilus_search_engine_get_model_provider (engine);
-    nautilus_search_engine_model_set_model (model, directory);
-    g_object_unref (directory);
+    create_search_file_hierarchy ("all_engines");
 
     nautilus_search_provider_start (NAUTILUS_SEARCH_PROVIDER (engine));
-    nautilus_search_provider_stop (NAUTILUS_SEARCH_PROVIDER (engine));
-    g_object_unref (engine);
 
     g_main_loop_run (loop);
     return 0;
diff --git a/test/automated/displayless/test-utilities.c b/test/automated/displayless/test-utilities.c
new file mode 100644
index 000000000..7b38c6849
--- /dev/null
+++ b/test/automated/displayless/test-utilities.c
@@ -0,0 +1,555 @@
+#include "test-utilities.h"
+
+void
+empty_directory_by_prefix (GFile *parent,
+                           gchar *prefix)
+{
+    g_autoptr (GFileEnumerator) enumerator = NULL;
+    g_autoptr (GFile) child = NULL;
+
+    enumerator = g_file_enumerate_children (parent,
+                                            G_FILE_ATTRIBUTE_STANDARD_NAME,
+                                            G_FILE_QUERY_INFO_NONE,
+                                            NULL,
+                                            NULL);
+
+    g_file_enumerator_iterate (enumerator, NULL, &child, NULL, NULL);
+    while (child != NULL)
+    {
+        gboolean res;
+
+        if (g_str_has_prefix (g_file_get_basename (child), prefix))
+        {
+            res = g_file_delete (child, NULL, NULL);
+            /* The directory is not empty */
+            if (!res)
+            {
+                empty_directory_by_prefix (child, prefix);
+                g_file_delete (child, NULL, NULL);
+            }
+        }
+
+        g_file_enumerator_iterate (enumerator, NULL, &child, NULL, NULL);
+    }
+}
+
+void
+create_search_file_hierarchy (gchar *search_engine)
+{
+    g_autoptr (GFile) location = NULL;
+    g_autoptr (GFile) file = NULL;
+    GFileOutputStream *out;
+    gchar *file_name;
+
+    location = g_file_new_for_path (g_get_tmp_dir ());
+
+    file_name = g_strdup_printf ("engine_%s", search_engine);
+    file = g_file_get_child (location, file_name);
+    g_free (file_name);
+    out = g_file_create (file, G_FILE_CREATE_NONE, NULL, NULL);
+    g_object_unref (out);
+
+    file_name = g_strdup_printf ("engine_%s_directory", search_engine);
+    file = g_file_get_child (location, file_name);
+    g_free (file_name);
+    g_file_make_directory (file, NULL, NULL);
+
+    file_name = g_strdup_printf ("%s_child", search_engine);
+    file = g_file_get_child (file, file_name);
+    g_free (file_name);
+    out = g_file_create (file, G_FILE_CREATE_NONE, NULL, NULL);
+    g_object_unref (out);
+
+    file_name = g_strdup_printf ("engine_%s_second_directory", search_engine);
+    file = g_file_get_child (location, file_name);
+    g_free (file_name);
+    g_file_make_directory (file, NULL, NULL);
+
+    file_name = g_strdup_printf ("engine_%s_child", search_engine);
+    file = g_file_get_child (file, file_name);
+    g_free (file_name);
+    out = g_file_create (file, G_FILE_CREATE_NONE, NULL, NULL);
+    g_object_unref (out);
+
+    file_name = g_strdup_printf ("%s_directory", search_engine);
+    file = g_file_get_child (location, file_name);
+    g_free (file_name);
+    g_file_make_directory (file, NULL, NULL);
+
+    file_name = g_strdup_printf ("engine_%s_child", search_engine);
+    file = g_file_get_child (file, file_name);
+    g_free (file_name);
+    out = g_file_create (file, G_FILE_CREATE_NONE, NULL, NULL);
+    g_object_unref (out);
+}
+
+void
+delete_search_file_hierarchy (gchar *search_engine)
+{
+    g_autoptr (GFile) location = NULL;
+    g_autoptr (GFile) file = NULL;
+    gchar *file_name;
+
+    location = g_file_new_for_path (g_get_tmp_dir ()); 
+
+    file_name = g_strdup_printf ("engine_%s", search_engine);
+    file = g_file_get_child (location, file_name);
+    g_free (file_name);
+    g_file_delete (file, NULL, NULL);
+
+    file_name = g_strdup_printf ("engine_%s_directory", search_engine);
+    file = g_file_get_child (location, file_name);
+    g_free (file_name);
+    file_name = g_strdup_printf ("%s_child", search_engine);
+    file = g_file_get_child (file, file_name);
+    g_free (file_name);
+    g_file_delete (file, NULL, NULL);
+    file_name = g_strdup_printf ("engine_%s_directory", search_engine);
+    file = g_file_get_child (location, file_name);
+    g_free (file_name);
+    g_file_delete (file, NULL, NULL);
+
+    file_name = g_strdup_printf ("engine_%s_second_directory", search_engine);
+    file = g_file_get_child (location, file_name);
+    g_free (file_name);
+    file_name = g_strdup_printf ("engine_%s_child", search_engine);
+    file = g_file_get_child (file, file_name);
+    g_free (file_name);
+    g_file_delete (file, NULL, NULL);
+    file_name = g_strdup_printf ("engine_%s_second_directory", search_engine);
+    file = g_file_get_child (location, file_name);
+    g_free (file_name);
+    g_file_delete (file, NULL, NULL);
+
+    file_name = g_strdup_printf ("%s_directory", search_engine);
+    file = g_file_get_child (location, file_name);
+    g_free (file_name);
+    file_name = g_strdup_printf ("engine_%s_child", search_engine);
+    file = g_file_get_child (file, file_name);
+    g_free (file_name);
+    g_file_delete (file, NULL, NULL);
+    file_name = g_strdup_printf ("%s_directory", search_engine);
+    file = g_file_get_child (location, file_name);
+    g_free (file_name);
+    g_file_delete (file, NULL, NULL);
+}
+
+/* This callback function quits the mainloop inside which the
+ * asynchronous undo/redo operation happens.
+ */
+
+void
+quit_loop_callback (NautilusFileUndoManager *undo_manager,
+                    GMainLoop               *loop)
+{
+    g_main_loop_quit (loop);
+}
+
+/* This undoes the last operation blocking the current main thread. */
+void
+test_operation_undo (void)
+{
+    g_autoptr (GMainLoop) loop = NULL;
+    g_autoptr (GMainContext) context = NULL;
+    gulong handler_id;
+
+    context = g_main_context_new ();
+    g_main_context_push_thread_default (context);
+    loop = g_main_loop_new (context, FALSE);
+
+    handler_id = g_signal_connect (nautilus_file_undo_manager_get (),
+                                   "undo-changed",
+                                   G_CALLBACK (quit_loop_callback),
+                                   loop);
+
+    nautilus_file_undo_manager_undo (NULL);
+
+    g_main_loop_run (loop);
+    
+    g_main_context_pop_thread_default (context);
+
+    g_signal_handler_disconnect (nautilus_file_undo_manager_get (),
+                                 handler_id);
+}
+
+/* This undoes and redoes the last move operation blocking the current main thread. */
+void
+test_operation_undo_redo (void)
+{
+    g_autoptr (GMainLoop) loop = NULL;
+    g_autoptr (GMainContext) context = NULL;
+    gulong handler_id;    
+
+    test_operation_undo ();
+
+    context = g_main_context_new ();
+    g_main_context_push_thread_default (context);
+    loop = g_main_loop_new (context, FALSE);
+
+    handler_id = g_signal_connect (nautilus_file_undo_manager_get (),
+                                   "undo-changed",
+                                   G_CALLBACK (quit_loop_callback),
+                                   loop);
+
+    nautilus_file_undo_manager_redo (NULL);
+
+    g_main_loop_run (loop);
+    
+    g_main_context_pop_thread_default (context);
+
+    g_signal_handler_disconnect (nautilus_file_undo_manager_get (),
+                                 handler_id);
+}
+
+/* Creates the following hierarchy:
+ * /tmp/`prefix`_first_dir/`prefix`_first_dir_child
+ * /tmp/`prefix`_second_dir/
+ */
+void
+create_one_file (gchar *prefix)
+{
+    g_autoptr (GFile) root = NULL;
+    g_autoptr (GFile) first_dir = NULL;
+    g_autoptr (GFile) second_dir = NULL;
+    g_autoptr (GFile) file = NULL;
+    GFileOutputStream *out;
+    gchar *file_name;
+
+    root = g_file_new_for_path (g_get_tmp_dir ());
+    g_assert_true (root != NULL);
+
+    file_name = g_strdup_printf ("%s_first_dir", prefix);
+    first_dir = g_file_get_child (root, file_name);
+    g_free (file_name);
+
+    g_assert_true (first_dir != NULL);
+    g_file_make_directory (first_dir, NULL, NULL);
+
+    file_name = g_strdup_printf ("%s_first_dir_child", prefix);
+    file = g_file_get_child (first_dir, file_name);
+    g_free (file_name);
+
+    g_assert_true (file != NULL);
+    out = g_file_create (file, G_FILE_CREATE_NONE, NULL, NULL);
+    g_object_unref (out);
+
+    file_name = g_strdup_printf ("%s_second_dir", prefix);
+    second_dir = g_file_get_child (root, file_name);
+    g_free (file_name);
+
+    g_assert_true (second_dir != NULL);
+    g_file_make_directory (second_dir, NULL, NULL);
+}
+
+/* Creates the same hierarchy as above, but all files being directories. */
+void
+create_one_empty_directory (gchar *prefix)
+{
+    g_autoptr (GFile) root = NULL;
+    g_autoptr (GFile) first_dir = NULL;
+    g_autoptr (GFile) second_dir = NULL;
+    g_autoptr (GFile) file = NULL;
+    gchar *file_name;
+
+    root = g_file_new_for_path (g_get_tmp_dir ());
+    g_assert_true (root != NULL);
+
+    file_name = g_strdup_printf ("%s_first_dir", prefix);
+    first_dir = g_file_get_child (root, file_name);
+    g_free (file_name);
+
+    g_assert_true (first_dir != NULL);
+    g_file_make_directory (first_dir, NULL, NULL);
+
+    file_name = g_strdup_printf ("%s_first_dir_child", prefix);
+    file = g_file_get_child (first_dir, file_name);
+    g_free (file_name);
+
+    g_assert_true (file != NULL);
+    g_file_make_directory (file, NULL, NULL);
+
+    file_name = g_strdup_printf ("%s_second_dir", prefix);
+    second_dir = g_file_get_child (root, file_name);
+    g_free (file_name);
+
+    g_assert_true (second_dir != NULL);
+    g_file_make_directory (second_dir, NULL, NULL);
+}
+
+void
+create_multiple_files (gchar *prefix, gint number_of_files)
+{
+    g_autoptr (GFile) root = NULL;
+    g_autoptr (GFile) file = NULL;
+    g_autoptr (GFile) dir = NULL;
+    gchar *file_name;
+
+    root = g_file_new_for_path (g_get_tmp_dir ());
+    g_assert_true (root != NULL);
+
+    for (int i = 0; i < number_of_files; i++)
+    {
+        GFileOutputStream *out;
+
+        file_name = g_strdup_printf ("%s_file_%i", prefix, i);
+        file = g_file_get_child (root, file_name);
+        g_free (file_name);
+
+        g_assert_true (file != NULL);
+        out = g_file_create (file, G_FILE_CREATE_NONE, NULL, NULL);
+        g_object_unref (out);
+    }
+
+    file_name = g_strdup_printf ("%s_dir", prefix);
+    dir = g_file_get_child (root, file_name);
+    g_free (file_name);
+
+    g_assert_true (dir != NULL);
+    g_file_make_directory (dir, NULL, NULL);
+}
+
+void
+create_multiple_directories (gchar *prefix, gint number_of_directories)
+{
+    g_autoptr (GFile) root = NULL;
+    g_autoptr (GFile) file = NULL;
+    g_autoptr (GFile) dir = NULL;
+    gchar *file_name;
+
+    root = g_file_new_for_path (g_get_tmp_dir ());
+    g_assert_true (root != NULL);
+
+    for (int i = 0; i < number_of_directories; i++)
+    {
+        file_name = g_strdup_printf ("%s_file_%i", prefix, i);
+        file = g_file_get_child (root, file_name);
+        g_free (file_name);
+
+        g_assert_true (file != NULL);
+        g_file_make_directory (file, NULL, NULL);
+    }
+
+    file_name = g_strdup_printf ("%s_dir", prefix);
+    dir = g_file_get_child (root, file_name);
+    g_free (file_name);
+
+    g_assert_true (dir != NULL);
+    g_file_make_directory (dir, NULL, NULL);
+}
+
+void
+create_first_hierarchy (gchar *prefix)
+{
+    g_autoptr (GFile) root = NULL;
+    g_autoptr (GFile) first_dir = NULL;
+    g_autoptr (GFile) second_dir = NULL;
+    g_autoptr (GFile) file = NULL;
+    g_autoptr (GFile) result_file = NULL;
+    gchar *file_name;
+
+    root = g_file_new_for_path (g_get_tmp_dir ());
+    g_assert_true (root != NULL);
+
+    file_name = g_strdup_printf ("%s_first_dir", prefix);
+    first_dir = g_file_get_child (root, file_name);
+    g_free (file_name);
+
+    g_assert_true (first_dir != NULL);
+    g_file_make_directory (first_dir, NULL, NULL);
+
+    file_name = g_strdup_printf ("%s_first_child", prefix);
+    file = g_file_get_child (first_dir, file_name);
+    g_free (file_name);
+
+    g_assert_true (file != NULL);
+    g_file_make_directory (file, NULL, NULL);
+    file_name = g_strdup_printf ("%s_second_child", prefix);
+    file = g_file_get_child (first_dir, file_name);
+    g_free (file_name);
+
+    g_assert_true (file != NULL);
+    g_file_make_directory (file, NULL, NULL);
+
+    file_name = g_strdup_printf ("%s_second_dir", prefix);
+    second_dir = g_file_get_child (root, file_name);
+    g_free (file_name);
+
+    g_assert_true (second_dir != NULL);
+    g_file_make_directory (second_dir, NULL, NULL);
+}
+
+void
+create_second_hierarchy (gchar *prefix)
+{
+    g_autoptr (GFile) root = NULL;
+    g_autoptr (GFile) first_dir = NULL;
+    g_autoptr (GFile) second_dir = NULL;
+    g_autoptr (GFile) file = NULL;
+    g_autoptr (GFile) result_file = NULL;
+    gchar *file_name;
+
+    root = g_file_new_for_path (g_get_tmp_dir ());
+    g_assert_true (root != NULL);
+
+    file_name = g_strdup_printf ("%s_first_dir", prefix);
+    first_dir = g_file_get_child (root, file_name);
+    g_free (file_name);
+
+    g_assert_true (first_dir != NULL);
+    g_file_make_directory (first_dir, NULL, NULL);
+
+    file_name = g_strdup_printf ("%s_first_child", prefix);
+    file = g_file_get_child (first_dir, file_name);
+    g_free (file_name);
+
+    g_assert_true (file != NULL);
+    g_file_make_directory (file, NULL, NULL);
+    file_name = g_strdup_printf ("%s_second_child", prefix);
+    file = g_file_get_child (file, file_name);
+    g_free (file_name);
+
+    g_assert_true (file != NULL);
+    g_file_make_directory (file, NULL, NULL);
+
+    file_name = g_strdup_printf ("%s_second_dir", prefix);
+    second_dir = g_file_get_child (root, file_name);
+    g_free (file_name);
+
+    g_assert_true (second_dir != NULL);
+    g_file_make_directory (second_dir, NULL, NULL);
+}
+
+void
+create_third_hierarchy (gchar *prefix)
+{
+    g_autoptr (GFile) root = NULL;
+    g_autoptr (GFile) first_dir = NULL;
+    g_autoptr (GFile) second_dir = NULL;
+    g_autoptr (GFile) file = NULL;
+    g_autoptr (GFile) result_file = NULL;
+    gchar *file_name;
+
+    root = g_file_new_for_path (g_get_tmp_dir ());
+    g_assert_true (root != NULL);
+
+    file_name = g_strdup_printf ("%s_first_dir", prefix);
+    first_dir = g_file_get_child (root, file_name);
+    g_free (file_name);
+
+    g_assert_true (first_dir != NULL);
+    g_file_make_directory (first_dir, NULL, NULL);
+
+    file_name = g_strdup_printf ("%s_first_dir_dir1", prefix);
+    file = g_file_get_child (first_dir, file_name);
+    g_free (file_name);
+
+    g_assert_true (file != NULL);
+    g_file_make_directory (file, NULL, NULL);
+
+    file_name = g_strdup_printf ("%s_dir1_child", prefix);
+    file = g_file_get_child (file, file_name);
+    g_free (file_name);
+
+    g_assert_true (file != NULL);
+    g_file_make_directory (file, NULL, NULL);
+
+    file_name = g_strdup_printf ("%s_first_dir_dir2", prefix);
+    file = g_file_get_child (first_dir, file_name);
+    g_free (file_name);
+
+    g_assert_true (file != NULL);
+    g_file_make_directory (file, NULL, NULL);
+
+    file_name = g_strdup_printf ("%s_dir2_child", prefix);
+    file = g_file_get_child (file, file_name);
+    g_free (file_name);
+
+    g_assert_true (file != NULL);
+    g_file_make_directory (file, NULL, NULL);
+
+    file_name = g_strdup_printf ("%s_second_dir", prefix);
+    second_dir = g_file_get_child (root, file_name);
+    g_free (file_name);
+
+    g_assert_true (second_dir != NULL);
+    g_file_make_directory (second_dir, NULL, NULL);
+}
+
+void
+create_fourth_hierarchy (gchar *prefix)
+{
+    g_autoptr (GFile) root = NULL;
+    g_autoptr (GFile) first_dir = NULL;
+    g_autoptr (GFile) second_dir = NULL;
+    g_autoptr (GFile) third_dir = NULL;
+    g_autoptr (GFile) file = NULL;
+    g_autoptr (GFile) result_file = NULL;
+    gchar *file_name;
+
+    root = g_file_new_for_path (g_get_tmp_dir ());
+    g_assert_true (root != NULL);
+
+    file_name = g_strdup_printf ("%s_first_dir", prefix);
+    first_dir = g_file_get_child (root, file_name);
+    g_free (file_name);
+
+    g_assert_true (first_dir != NULL);
+    g_file_make_directory (first_dir, NULL, NULL);
+
+    file_name = g_strdup_printf ("%s_first_dir_child", prefix);
+    file = g_file_get_child (first_dir, file_name);
+    g_free (file_name);
+
+    g_assert_true (file != NULL);
+    g_file_make_directory (file, NULL, NULL);
+
+    file_name = g_strdup_printf ("%s_second_dir", prefix);
+    second_dir = g_file_get_child (root, file_name);
+    g_free (file_name);
+
+    g_assert_true (second_dir != NULL);
+    g_file_make_directory (second_dir, NULL, NULL);
+
+    file_name = g_strdup_printf ("%s_second_dir_child", prefix);
+    file = g_file_get_child (second_dir, file_name);
+    g_free (file_name);
+
+    g_assert_true (file != NULL);
+    g_file_make_directory (file, NULL, NULL);
+
+    file_name = g_strdup_printf ("%s_third_dir", prefix);
+    third_dir = g_file_get_child (root, file_name);
+    g_free (file_name);
+
+    g_assert_true (third_dir != NULL);
+    g_file_make_directory (third_dir, NULL, NULL);
+}
+
+void
+create_multiple_full_directories (gchar *prefix, gint number_of_directories)
+{
+    g_autoptr (GFile) root = NULL;
+
+    root = g_file_new_for_path (g_get_tmp_dir ());
+    g_assert_true (root != NULL);
+
+    for (int i = 0; i < number_of_directories; i++)
+    {
+        g_autoptr (GFile) directory = NULL;
+        g_autoptr (GFile) file = NULL;
+        gchar *file_name;
+
+        file_name = g_strdup_printf ("%s_directory_%i", prefix, i);
+
+        directory = g_file_get_child (root, file_name);
+        g_free (file_name);
+
+        g_file_make_directory (directory, NULL, NULL);
+
+        file_name = g_strdup_printf ("%s_file_%i", prefix, i);
+        file = g_file_get_child (directory, file_name);
+        g_free (file_name);
+
+        g_file_make_directory (file, NULL, NULL);
+    }
+}
\ No newline at end of file
diff --git a/test/automated/displayless/test-utilities.h b/test/automated/displayless/test-utilities.h
new file mode 100644
index 000000000..878c87876
--- /dev/null
+++ b/test/automated/displayless/test-utilities.h
@@ -0,0 +1,34 @@
+#include <gio/gio.h>
+#include <src/nautilus-file-utilities.h>
+#include <src/nautilus-global-preferences.h>
+#include <src/nautilus-search-engine.h>
+#include <tracker-sparql.h>
+#include <locale.h>
+#include <src/nautilus-file-undo-manager.h>
+#include <src/nautilus-file-operations.h>
+#include <gio/gio.h>
+
+#pragma once
+
+void empty_directory_by_prefix (GFile *parent,
+                                gchar *prefix);
+
+void create_search_file_hierarchy (gchar *search_engine);
+void delete_search_file_hierarchy (gchar *search_engine);
+
+void quit_loop_callback (NautilusFileUndoManager *undo_manager,
+                         GMainLoop               *loop);
+void test_operation_undo_redo (void);
+void test_operation_undo (void);
+
+void create_one_file (gchar *prefix);
+void create_one_empty_directory (gchar *prefix);
+
+void create_multiple_files (gchar *prefix, gint number_of_files);
+void create_multiple_directories (gchar *prefix, gint number_of_directories);
+void create_multiple_full_directories (gchar *prefix, gint number_of_directories);
+
+void create_first_hierarchy (gchar *prefix);
+void create_second_hierarchy (gchar *prefix);
+void create_third_hierarchy (gchar *prefix);
+void create_fourth_hierarchy (gchar *prefix);
\ No newline at end of file


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