[gtksourceview/wip/regex-search: 4/5] Search: rename test programs



commit fd69414e3b5865d75501aab6c588ba360a1afcf0
Author: Sébastien Wilmet <swilmet gnome org>
Date:   Sat Jul 27 20:26:42 2013 +0200

    Search: rename test programs
    
    test-search -> test-search-context
    test-search-ui -> test-search
    
    (I didn't like the name test-search-ui)

 gtksourceview/gtksourcebuffer.c                    |    2 +-
 tests/Makefile.am                                  |   26 +-
 tests/test-search-context.c                        |  886 ++++++++++++++++
 tests/test-search-ui.c                             |  489 ---------
 tests/test-search.c                                | 1054 ++++++--------------
 ...-ui.gresource.xml => test-search.gresource.xml} |    2 +-
 tests/{test-search-ui.ui => test-search.ui}        |    0
 7 files changed, 1229 insertions(+), 1230 deletions(-)
---
diff --git a/gtksourceview/gtksourcebuffer.c b/gtksourceview/gtksourcebuffer.c
index 8274e32..7bbf348 100644
--- a/gtksourceview/gtksourcebuffer.c
+++ b/gtksourceview/gtksourcebuffer.c
@@ -123,7 +123,7 @@
  *   </para>
  *   <para>
  *     In the GtkSourceView source code, there is an example of how to use the
- *     search and replace API: see the tests/test-search-ui.c file. It is a mini
+ *     search and replace API: see the tests/test-search.c file. It is a mini
  *     application for the search and replace, with a basic user interface.
  *   </para>
  * </refsect2>
diff --git a/tests/Makefile.am b/tests/Makefile.am
index 814be07..10452e8 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -15,13 +15,13 @@ TESTS = $(UNIT_TEST_PROGS)
 
 BUILT_SOURCES =                                \
        test-completion-resources.c     \
-       test-search-ui-resources.c
+       test-search-resources.c
 
 test-completion-resources.c: test-completion.gresource.xml $(shell $(GLIB_COMPILE_RESOURCES) 
--generate-dependencies $(srcdir)/test-completion.gresource.xml)
        $(AM_V_GEN) $(GLIB_COMPILE_RESOURCES) --target=$@ --sourcedir=$(srcdir) --generate-source 
$(srcdir)/test-completion.gresource.xml
 
-test-search-ui-resources.c: test-search-ui.gresource.xml $(shell $(GLIB_COMPILE_RESOURCES) 
--generate-dependencies $(srcdir)/test-search-ui.gresource.xml)
-       $(AM_V_GEN) $(GLIB_COMPILE_RESOURCES) --target=$@ --sourcedir=$(srcdir) --generate-source 
$(srcdir)/test-search-ui.gresource.xml
+test-search-resources.c: test-search.gresource.xml $(shell $(GLIB_COMPILE_RESOURCES) --generate-dependencies 
$(srcdir)/test-search.gresource.xml)
+       $(AM_V_GEN) $(GLIB_COMPILE_RESOURCES) --target=$@ --sourcedir=$(srcdir) --generate-source 
$(srcdir)/test-search.gresource.xml
 
 TEST_PROGS = test-widget
 test_widget_SOURCES = test-widget.c
@@ -39,11 +39,11 @@ test_completion_LDADD =             \
        $(DEP_LIBS)                     \
        $(TESTS_LIBS)
 
-TEST_PROGS += test-search-ui
-test_search_ui_SOURCES =               \
-       test-search-ui.c                \
-       test-search-ui-resources.c
-test_search_ui_LDADD =                                         \
+TEST_PROGS += test-search
+test_search_SOURCES =          \
+       test-search.c           \
+       test-search-resources.c
+test_search_LDADD =                                            \
        $(top_builddir)/gtksourceview/libgtksourceview-3.0.la   \
        $(DEP_LIBS)                                             \
        $(TESTS_LIBS)
@@ -140,9 +140,9 @@ test_undo_manager_LDADD =                                   \
        $(DEP_LIBS)                                             \
        $(TESTS_LIBS)
 
-UNIT_TEST_PROGS += test-search
-test_search_SOURCES = test-search.c
-test_search_LDADD =                                                    \
+UNIT_TEST_PROGS += test-search-context
+test_search_context_SOURCES = test-search-context.c
+test_search_context_LDADD =                                            \
        $(top_builddir)/gtksourceview/libgtksourceview-3.0.la           \
        $(top_builddir)/gtksourceview/libgtksourceview-private.la       \
        $(DEP_LIBS)                                                     \
@@ -165,8 +165,8 @@ EXTRA_DIST =                                \
        styles/classic.xml              \
        test-completion.gresource.xml   \
        test-completion.ui              \
-       test-search-ui.gresource.xml    \
-       test-search-ui.ui               \
+       test-search.gresource.xml       \
+       test-search.ui                  \
        $(python_tests)
 
 -include $(top_srcdir)/git.mk
diff --git a/tests/test-search-context.c b/tests/test-search-context.c
new file mode 100644
index 0000000..d313fc7
--- /dev/null
+++ b/tests/test-search-context.c
@@ -0,0 +1,886 @@
+/*
+ * test-search-context.c
+ * This file is part of GtkSourceView
+ *
+ * Copyright (C) 2013 - Sébastien Wilmet <swilmet gnome org>
+ *
+ * GtkSourceView is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * GtkSourceView is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#include <gtk/gtk.h>
+#include <gtksourceview/gtksource.h>
+
+typedef struct
+{
+       gint match_start_offset;
+       gint match_end_offset;
+       guint found : 1;
+} SearchResult;
+
+typedef struct
+{
+       SearchResult *results;
+       gint result_num;
+       guint forward : 1;
+} AsyncData;
+
+static void check_async_search_results (GtkSourceBuffer *source_buffer,
+                                       SearchResult    *results,
+                                       gboolean         forward,
+                                       gboolean         start_check);
+
+static void
+flush_queue (void)
+{
+       while (gtk_events_pending ())
+       {
+               gtk_main_iteration ();
+       }
+}
+
+/* Without insertion or deletion of text in the buffer afterwards. */
+static void
+test_occurrences_count_simple (void)
+{
+       GtkSourceBuffer *buffer = gtk_source_buffer_new (NULL);
+       GtkTextIter iter;
+       gint occurrences_count;
+
+       gtk_text_buffer_get_start_iter (GTK_TEXT_BUFFER (buffer), &iter);
+       gtk_text_buffer_insert (GTK_TEXT_BUFFER (buffer), &iter, "Some foo\nSome bar\n", -1);
+       flush_queue ();
+       occurrences_count = gtk_source_buffer_get_search_occurrences_count (buffer);
+       g_assert_cmpint (occurrences_count, ==, 0);
+
+       gtk_source_buffer_set_search_text (buffer, "world");
+       flush_queue ();
+       occurrences_count = gtk_source_buffer_get_search_occurrences_count (buffer);
+       g_assert_cmpint (occurrences_count, ==, 0);
+
+       gtk_source_buffer_set_search_text (buffer, "Some");
+       flush_queue ();
+       occurrences_count = gtk_source_buffer_get_search_occurrences_count (buffer);
+       g_assert_cmpint (occurrences_count, ==, 2);
+
+       gtk_source_buffer_set_search_text (buffer, "foo");
+       flush_queue ();
+       occurrences_count = gtk_source_buffer_get_search_occurrences_count (buffer);
+       g_assert_cmpint (occurrences_count, ==, 1);
+
+       gtk_source_buffer_set_search_text (buffer, "world");
+       flush_queue ();
+       occurrences_count = gtk_source_buffer_get_search_occurrences_count (buffer);
+       g_assert_cmpint (occurrences_count, ==, 0);
+
+       g_object_unref (buffer);
+}
+
+static void
+test_occurrences_count_with_insert (void)
+{
+       GtkSourceBuffer *source_buffer = gtk_source_buffer_new (NULL);
+       GtkTextBuffer *text_buffer = GTK_TEXT_BUFFER (source_buffer);
+       GtkTextIter iter;
+       gint occurrences_count;
+
+       /* Contents: "foobar" */
+       gtk_text_buffer_get_start_iter (text_buffer, &iter);
+       gtk_text_buffer_insert (text_buffer, &iter, "foobar", -1);
+
+       gtk_source_buffer_set_search_text (source_buffer, "foo");
+       flush_queue ();
+       occurrences_count = gtk_source_buffer_get_search_occurrences_count (source_buffer);
+       g_assert_cmpint (occurrences_count, ==, 1);
+
+       /* Contents: "foobar " */
+       gtk_text_buffer_get_end_iter (text_buffer, &iter);
+       gtk_text_buffer_insert (text_buffer, &iter, " ", -1);
+       flush_queue ();
+       occurrences_count = gtk_source_buffer_get_search_occurrences_count (source_buffer);
+       g_assert_cmpint (occurrences_count, ==, 1);
+
+       /* Contents: "foobar foobeer" */
+       gtk_text_buffer_get_end_iter (text_buffer, &iter);
+       gtk_text_buffer_insert (text_buffer, &iter, "foobeer", -1);
+       flush_queue ();
+       occurrences_count = gtk_source_buffer_get_search_occurrences_count (source_buffer);
+       g_assert_cmpint (occurrences_count, ==, 2);
+
+       /* Contents: "foo bar foobeer" */
+       gtk_text_buffer_get_iter_at_offset (text_buffer, &iter, 3);
+       gtk_text_buffer_insert (text_buffer, &iter, " ", -1);
+       flush_queue ();
+       occurrences_count = gtk_source_buffer_get_search_occurrences_count (source_buffer);
+       g_assert_cmpint (occurrences_count, ==, 2);
+
+       /* Contents: "foto bar foobeer" */
+       gtk_text_buffer_get_iter_at_offset (text_buffer, &iter, 2);
+       gtk_text_buffer_insert (text_buffer, &iter, "t", -1);
+       flush_queue ();
+       occurrences_count = gtk_source_buffer_get_search_occurrences_count (source_buffer);
+       g_assert_cmpint (occurrences_count, ==, 1);
+
+       /* Contents: "footo bar foobeer" */
+       gtk_text_buffer_get_iter_at_offset (text_buffer, &iter, 2);
+       gtk_text_buffer_insert (text_buffer, &iter, "o", -1);
+       flush_queue ();
+       occurrences_count = gtk_source_buffer_get_search_occurrences_count (source_buffer);
+       g_assert_cmpint (occurrences_count, ==, 2);
+
+       /* Contents: "foofooto bar foobeer" */
+       gtk_text_buffer_get_start_iter (text_buffer, &iter);
+       gtk_text_buffer_insert (text_buffer, &iter, "foo", -1);
+       flush_queue ();
+       occurrences_count = gtk_source_buffer_get_search_occurrences_count (source_buffer);
+       g_assert_cmpint (occurrences_count, ==, 3);
+
+       /* Contents: "fooTfooto bar foobeer" */
+       gtk_text_buffer_get_iter_at_offset (text_buffer, &iter, 3);
+       gtk_text_buffer_insert (text_buffer, &iter, "T", -1);
+       flush_queue ();
+       occurrences_count = gtk_source_buffer_get_search_occurrences_count (source_buffer);
+       g_assert_cmpint (occurrences_count, ==, 3);
+
+       g_object_unref (source_buffer);
+}
+
+static void
+test_occurrences_count_with_delete (void)
+{
+       GtkSourceBuffer *source_buffer = gtk_source_buffer_new (NULL);
+       GtkTextBuffer *text_buffer = GTK_TEXT_BUFFER (source_buffer);
+       GtkTextIter start;
+       GtkTextIter end;
+       gint occurrences_count;
+
+       gtk_source_buffer_set_search_text (source_buffer, "foo");
+
+       /* Contents: "foo" -> "" */
+       gtk_text_buffer_set_text (text_buffer, "foo", -1);
+       flush_queue ();
+       occurrences_count = gtk_source_buffer_get_search_occurrences_count (source_buffer);
+       g_assert_cmpint (occurrences_count, ==, 1);
+
+       gtk_text_buffer_get_bounds (text_buffer, &start, &end);
+       gtk_text_buffer_delete (text_buffer, &start, &end);
+       flush_queue ();
+       occurrences_count = gtk_source_buffer_get_search_occurrences_count (source_buffer);
+       g_assert_cmpint (occurrences_count, ==, 0);
+
+       /* Contents: "foo" -> "oo" */
+       gtk_text_buffer_set_text (text_buffer, "foo", -1);
+       flush_queue ();
+       occurrences_count = gtk_source_buffer_get_search_occurrences_count (source_buffer);
+       g_assert_cmpint (occurrences_count, ==, 1);
+
+       gtk_text_buffer_get_start_iter (text_buffer, &start);
+       gtk_text_buffer_get_iter_at_offset (text_buffer, &end, 1);
+       gtk_text_buffer_delete (text_buffer, &start, &end);
+       flush_queue ();
+       occurrences_count = gtk_source_buffer_get_search_occurrences_count (source_buffer);
+       g_assert_cmpint (occurrences_count, ==, 0);
+
+       /* Contents: "foobar foobeer" -> "foobar" */
+       gtk_text_buffer_set_text (text_buffer, "foobar foobeer", -1);
+       flush_queue ();
+       occurrences_count = gtk_source_buffer_get_search_occurrences_count (source_buffer);
+       g_assert_cmpint (occurrences_count, ==, 2);
+
+       gtk_text_buffer_get_iter_at_offset (text_buffer, &start, 6);
+       gtk_text_buffer_get_end_iter (text_buffer, &end);
+       gtk_text_buffer_delete (text_buffer, &start, &end);
+       flush_queue ();
+       occurrences_count = gtk_source_buffer_get_search_occurrences_count (source_buffer);
+       g_assert_cmpint (occurrences_count, ==, 1);
+
+       /* Contents: "foo[foo]foo" -> "foofoo" */
+       gtk_text_buffer_set_text (text_buffer, "foofoofoo", -1);
+       flush_queue ();
+       occurrences_count = gtk_source_buffer_get_search_occurrences_count (source_buffer);
+       g_assert_cmpint (occurrences_count, ==, 3);
+
+       gtk_text_buffer_get_iter_at_offset (text_buffer, &start, 3);
+       gtk_text_buffer_get_iter_at_offset (text_buffer, &end, 6);
+       gtk_text_buffer_delete (text_buffer, &start, &end);
+       flush_queue ();
+       occurrences_count = gtk_source_buffer_get_search_occurrences_count (source_buffer);
+       g_assert_cmpint (occurrences_count, ==, 2);
+
+       /* Contents: "fo[of]oo" -> "fooo" */
+       gtk_text_buffer_get_iter_at_offset (text_buffer, &start, 2);
+       gtk_text_buffer_get_iter_at_offset (text_buffer, &end, 4);
+       gtk_text_buffer_delete (text_buffer, &start, &end);
+       flush_queue ();
+       occurrences_count = gtk_source_buffer_get_search_occurrences_count (source_buffer);
+       g_assert_cmpint (occurrences_count, ==, 1);
+
+       /* Contents: "foto" -> "foo" */
+       gtk_text_buffer_set_text (text_buffer, "foto", -1);
+       flush_queue ();
+       occurrences_count = gtk_source_buffer_get_search_occurrences_count (source_buffer);
+       g_assert_cmpint (occurrences_count, ==, 0);
+
+       gtk_text_buffer_get_iter_at_offset (text_buffer, &start, 2);
+       gtk_text_buffer_get_iter_at_offset (text_buffer, &end, 3);
+       gtk_text_buffer_delete (text_buffer, &start, &end);
+       flush_queue ();
+       occurrences_count = gtk_source_buffer_get_search_occurrences_count (source_buffer);
+       g_assert_cmpint (occurrences_count, ==, 1);
+
+       g_object_unref (source_buffer);
+}
+
+static void
+test_occurrences_count_multiple_lines (void)
+{
+       GtkSourceBuffer *source_buffer = gtk_source_buffer_new (NULL);
+       GtkTextBuffer *text_buffer = GTK_TEXT_BUFFER (source_buffer);
+       gint occurrences_count;
+
+       gtk_source_buffer_set_search_text (source_buffer, "world\nhello");
+
+       gtk_text_buffer_set_text (text_buffer, "hello world\nhello world\nhello world\n", -1);
+       flush_queue ();
+       occurrences_count = gtk_source_buffer_get_search_occurrences_count (source_buffer);
+       g_assert_cmpint (occurrences_count, ==, 2);
+
+       gtk_source_buffer_set_search_text (source_buffer, "world\n");
+       flush_queue ();
+       occurrences_count = gtk_source_buffer_get_search_occurrences_count (source_buffer);
+       g_assert_cmpint (occurrences_count, ==, 3);
+
+       gtk_source_buffer_set_search_text (source_buffer, "\nhello world\n");
+       flush_queue ();
+       occurrences_count = gtk_source_buffer_get_search_occurrences_count (source_buffer);
+       g_assert_cmpint (occurrences_count, ==, 1);
+
+       g_object_unref (source_buffer);
+}
+
+static void
+test_case_sensitivity (void)
+{
+       GtkSourceBuffer *source_buffer = gtk_source_buffer_new (NULL);
+       GtkTextBuffer *text_buffer = GTK_TEXT_BUFFER (source_buffer);
+       gboolean case_sensitive;
+       gint occurrences_count;
+
+       gtk_text_buffer_set_text (text_buffer, "Case", -1);
+       gtk_source_buffer_set_search_text (source_buffer, "case");
+
+       gtk_source_buffer_set_case_sensitive_search (source_buffer, TRUE);
+       case_sensitive = gtk_source_buffer_get_case_sensitive_search (source_buffer);
+       g_assert (case_sensitive);
+
+       flush_queue ();
+       occurrences_count = gtk_source_buffer_get_search_occurrences_count (source_buffer);
+       g_assert_cmpint (occurrences_count, ==, 0);
+
+       gtk_source_buffer_set_case_sensitive_search (source_buffer, FALSE);
+       case_sensitive = gtk_source_buffer_get_case_sensitive_search (source_buffer);
+       g_assert (!case_sensitive);
+
+       flush_queue ();
+       occurrences_count = gtk_source_buffer_get_search_occurrences_count (source_buffer);
+       g_assert_cmpint (occurrences_count, ==, 1);
+
+       g_object_unref (source_buffer);
+}
+
+static void
+test_search_at_word_boundaries (void)
+{
+       GtkSourceBuffer *source_buffer = gtk_source_buffer_new (NULL);
+       GtkTextBuffer *text_buffer = GTK_TEXT_BUFFER (source_buffer);
+       gboolean at_word_boundaries;
+       gint occurrences_count;
+
+       gtk_text_buffer_set_text (text_buffer, "AtWordBoundaries AtWord", -1);
+       gtk_source_buffer_set_search_text (source_buffer, "AtWord");
+
+       gtk_source_buffer_set_search_at_word_boundaries (source_buffer, TRUE);
+       at_word_boundaries = gtk_source_buffer_get_search_at_word_boundaries (source_buffer);
+       g_assert (at_word_boundaries);
+
+       flush_queue ();
+       occurrences_count = gtk_source_buffer_get_search_occurrences_count (source_buffer);
+       g_assert_cmpint (occurrences_count, ==, 1);
+
+       gtk_source_buffer_set_search_at_word_boundaries (source_buffer, FALSE);
+       at_word_boundaries = gtk_source_buffer_get_search_at_word_boundaries (source_buffer);
+       g_assert (!at_word_boundaries);
+
+       flush_queue ();
+       occurrences_count = gtk_source_buffer_get_search_occurrences_count (source_buffer);
+       g_assert_cmpint (occurrences_count, ==, 2);
+
+       g_object_unref (source_buffer);
+}
+
+static void
+check_search_results (GtkSourceBuffer *source_buffer,
+                     SearchResult    *results,
+                     gboolean         forward)
+{
+       GtkTextIter iter;
+       GtkTextBuffer *text_buffer = GTK_TEXT_BUFFER (source_buffer);
+
+       gtk_text_buffer_get_start_iter (text_buffer, &iter);
+
+       do
+       {
+               gint i;
+               gboolean found;
+               GtkTextIter match_start;
+               GtkTextIter match_end;
+
+               i = gtk_text_iter_get_offset (&iter);
+
+               if (forward)
+               {
+                       found = gtk_source_buffer_forward_search (source_buffer,
+                                                                 &iter,
+                                                                 &match_start,
+                                                                 &match_end);
+               }
+               else
+               {
+                       found = gtk_source_buffer_backward_search (source_buffer,
+                                                                  &iter,
+                                                                  &match_start,
+                                                                  &match_end);
+               }
+
+               g_assert (found == results[i].found);
+
+               if (found)
+               {
+                       gint match_start_offset = gtk_text_iter_get_offset (&match_start);
+                       gint match_end_offset = gtk_text_iter_get_offset (&match_end);
+
+                       g_assert_cmpint (match_start_offset, ==, results[i].match_start_offset);
+                       g_assert_cmpint (match_end_offset, ==, results[i].match_end_offset);
+               }
+       }
+       while (gtk_text_iter_forward_char (&iter));
+}
+
+static void
+finish_check_result (GtkSourceBuffer *source_buffer,
+                    GAsyncResult    *result,
+                    AsyncData       *data)
+{
+       GtkTextIter match_start;
+       GtkTextIter match_end;
+       gboolean found;
+       SearchResult search_result = data->results[data->result_num];
+
+       if (data->forward)
+       {
+               found = gtk_source_buffer_forward_search_finish (source_buffer,
+                                                                result,
+                                                                &match_start,
+                                                                &match_end,
+                                                                NULL);
+       }
+       else
+       {
+               found = gtk_source_buffer_backward_search_finish (source_buffer,
+                                                                 result,
+                                                                 &match_start,
+                                                                 &match_end,
+                                                                 NULL);
+       }
+
+       g_assert (found == search_result.found);
+
+       if (found)
+       {
+               gint match_start_offset = gtk_text_iter_get_offset (&match_start);
+               gint match_end_offset = gtk_text_iter_get_offset (&match_end);
+
+               g_assert_cmpint (match_start_offset, ==, search_result.match_start_offset);
+               g_assert_cmpint (match_end_offset, ==, search_result.match_end_offset);
+       }
+
+       check_async_search_results (source_buffer,
+                                   data->results,
+                                   data->forward,
+                                   FALSE);
+
+       g_slice_free (AsyncData, data);
+}
+
+static void
+check_async_search_results (GtkSourceBuffer *source_buffer,
+                           SearchResult    *results,
+                           gboolean         forward,
+                           gboolean         start_check)
+{
+       static GtkTextIter iter;
+       GtkTextBuffer *text_buffer = GTK_TEXT_BUFFER (source_buffer);
+       AsyncData *data;
+
+       if (start_check)
+       {
+               gtk_text_buffer_get_start_iter (text_buffer, &iter);
+       }
+       else if (!gtk_text_iter_forward_char (&iter))
+       {
+               gtk_main_quit ();
+               return;
+       }
+
+       data = g_slice_new (AsyncData);
+       data->results = results;
+       data->result_num = gtk_text_iter_get_offset (&iter);
+       data->forward = forward;
+
+       if (forward)
+       {
+               gtk_source_buffer_forward_search_async (source_buffer,
+                                                       &iter,
+                                                       NULL,
+                                                       (GAsyncReadyCallback)finish_check_result,
+                                                       data);
+       }
+       else
+       {
+               gtk_source_buffer_backward_search_async (source_buffer,
+                                                        &iter,
+                                                        NULL,
+                                                        (GAsyncReadyCallback)finish_check_result,
+                                                        data);
+       }
+}
+
+static void
+test_forward_search (void)
+{
+       GtkSourceBuffer *source_buffer = gtk_source_buffer_new (NULL);
+       GtkTextBuffer *text_buffer = GTK_TEXT_BUFFER (source_buffer);
+       gboolean wrap_around;
+
+       static SearchResult results1[] =
+       {
+               { 0, 2, TRUE },
+               { 2, 4, TRUE },
+               { 2, 4, TRUE },
+               { 0, 2, TRUE },
+               { 0, 2, TRUE }
+       };
+
+       static SearchResult results2[] =
+       {
+               { 0, 2, TRUE },
+               { 2, 4, TRUE },
+               { 2, 4, TRUE },
+               { 0, 0, FALSE },
+               { 0, 0, FALSE }
+       };
+
+       gtk_text_buffer_set_text (text_buffer, "aaaa", -1);
+       gtk_source_buffer_set_search_text (source_buffer, "aa");
+
+       /* Wrap around: TRUE */
+
+       gtk_source_buffer_set_search_wrap_around (source_buffer, TRUE);
+       wrap_around = gtk_source_buffer_get_search_wrap_around (source_buffer);
+       g_assert (wrap_around);
+
+       check_search_results (source_buffer, results1, TRUE);
+
+       g_test_trap_subprocess ("/Search/forward/subprocess/async-wrap-around", 0, 0);
+       g_test_trap_assert_passed ();
+
+       /* Wrap around: FALSE */
+
+       gtk_source_buffer_set_search_wrap_around (source_buffer, FALSE);
+       wrap_around = gtk_source_buffer_get_search_wrap_around (source_buffer);
+       g_assert (!wrap_around);
+
+       check_search_results (source_buffer, results2, TRUE);
+
+       g_test_trap_subprocess ("/Search/forward/subprocess/async-normal", 0, 0);
+       g_test_trap_assert_passed ();
+
+       g_object_unref (source_buffer);
+}
+
+static void
+test_async_forward_search_normal (void)
+{
+       GtkSourceBuffer *source_buffer = gtk_source_buffer_new (NULL);
+       GtkTextBuffer *text_buffer = GTK_TEXT_BUFFER (source_buffer);
+
+       static SearchResult results[] =
+       {
+               { 0, 2, TRUE },
+               { 2, 4, TRUE },
+               { 2, 4, TRUE },
+               { 0, 0, FALSE },
+               { 0, 0, FALSE }
+       };
+
+       gtk_text_buffer_set_text (text_buffer, "aaaa", -1);
+       gtk_source_buffer_set_search_text (source_buffer, "aa");
+       gtk_source_buffer_set_search_wrap_around (source_buffer, FALSE);
+
+       check_async_search_results (source_buffer, results, TRUE, TRUE);
+
+       gtk_main ();
+       g_object_unref (source_buffer);
+}
+
+static void
+test_async_forward_search_wrap_around (void)
+{
+       GtkSourceBuffer *source_buffer = gtk_source_buffer_new (NULL);
+       GtkTextBuffer *text_buffer = GTK_TEXT_BUFFER (source_buffer);
+
+       static SearchResult results[] =
+       {
+               { 0, 2, TRUE },
+               { 2, 4, TRUE },
+               { 2, 4, TRUE },
+               { 0, 2, TRUE },
+               { 0, 2, TRUE }
+       };
+
+       gtk_text_buffer_set_text (text_buffer, "aaaa", -1);
+       gtk_source_buffer_set_search_text (source_buffer, "aa");
+       gtk_source_buffer_set_search_wrap_around (source_buffer, TRUE);
+
+       check_async_search_results (source_buffer, results, TRUE, TRUE);
+
+       gtk_main ();
+       g_object_unref (source_buffer);
+}
+
+static void
+test_backward_search (void)
+{
+       GtkSourceBuffer *source_buffer = gtk_source_buffer_new (NULL);
+       GtkTextBuffer *text_buffer = GTK_TEXT_BUFFER (source_buffer);
+
+       static SearchResult results1[] =
+       {
+               { 2, 4, TRUE },
+               { 2, 4, TRUE },
+               { 0, 2, TRUE },
+               { 0, 2, TRUE },
+               { 2, 4, TRUE }
+       };
+
+       static SearchResult results2[] =
+       {
+               { 0, 0, FALSE },
+               { 0, 0, FALSE },
+               { 0, 2, TRUE },
+               { 0, 2, TRUE },
+               { 2, 4, TRUE }
+       };
+
+       gtk_text_buffer_set_text (text_buffer, "aaaa", -1);
+       gtk_source_buffer_set_search_text (source_buffer, "aa");
+
+       /* Wrap around: TRUE */
+
+       gtk_source_buffer_set_search_wrap_around (source_buffer, TRUE);
+       check_search_results (source_buffer, results1, FALSE);
+
+       g_test_trap_subprocess ("/Search/backward/subprocess/async-wrap-around", 0, 0);
+       g_test_trap_assert_passed ();
+
+       /* Wrap around: FALSE */
+
+       gtk_source_buffer_set_search_wrap_around (source_buffer, FALSE);
+       check_search_results (source_buffer, results2, FALSE);
+
+       g_test_trap_subprocess ("/Search/backward/subprocess/async-normal", 0, 0);
+       g_test_trap_assert_passed ();
+
+       g_object_unref (source_buffer);
+}
+
+static void
+test_async_backward_search_normal (void)
+{
+       GtkSourceBuffer *source_buffer = gtk_source_buffer_new (NULL);
+       GtkTextBuffer *text_buffer = GTK_TEXT_BUFFER (source_buffer);
+
+       static SearchResult results[] =
+       {
+               { 0, 0, FALSE },
+               { 0, 0, FALSE },
+               { 0, 2, TRUE },
+               { 0, 2, TRUE },
+               { 2, 4, TRUE }
+       };
+
+       gtk_text_buffer_set_text (text_buffer, "aaaa", -1);
+       gtk_source_buffer_set_search_text (source_buffer, "aa");
+       gtk_source_buffer_set_search_wrap_around (source_buffer, FALSE);
+
+       check_async_search_results (source_buffer, results, FALSE, TRUE);
+
+       gtk_main ();
+       g_object_unref (source_buffer);
+}
+
+static void
+test_async_backward_search_wrap_around (void)
+{
+       GtkSourceBuffer *source_buffer = gtk_source_buffer_new (NULL);
+       GtkTextBuffer *text_buffer = GTK_TEXT_BUFFER (source_buffer);
+
+       static SearchResult results[] =
+       {
+               { 2, 4, TRUE },
+               { 2, 4, TRUE },
+               { 0, 2, TRUE },
+               { 0, 2, TRUE },
+               { 2, 4, TRUE }
+       };
+
+       gtk_text_buffer_set_text (text_buffer, "aaaa", -1);
+       gtk_source_buffer_set_search_text (source_buffer, "aa");
+       gtk_source_buffer_set_search_wrap_around (source_buffer, TRUE);
+
+       check_async_search_results (source_buffer, results, FALSE, TRUE);
+
+       gtk_main ();
+       g_object_unref (source_buffer);
+}
+
+static void
+test_highlight (void)
+{
+       GtkSourceBuffer *source_buffer = gtk_source_buffer_new (NULL);
+       gboolean highlight;
+
+       gtk_source_buffer_set_highlight_search (source_buffer, TRUE);
+       highlight = gtk_source_buffer_get_highlight_search (source_buffer);
+       g_assert (highlight);
+
+       gtk_source_buffer_set_highlight_search (source_buffer, FALSE);
+       highlight = gtk_source_buffer_get_highlight_search (source_buffer);
+       g_assert (!highlight);
+
+       g_object_unref (source_buffer);
+}
+
+static void
+test_get_search_text (void)
+{
+       GtkSourceBuffer *source_buffer = gtk_source_buffer_new (NULL);
+       const gchar *search_text;
+
+       search_text = gtk_source_buffer_get_search_text (source_buffer);
+       g_assert (search_text == NULL);
+
+       gtk_source_buffer_set_search_text (source_buffer, "");
+       search_text = gtk_source_buffer_get_search_text (source_buffer);
+       g_assert (search_text == NULL);
+
+       gtk_source_buffer_set_search_text (source_buffer, "search-text");
+       search_text = gtk_source_buffer_get_search_text (source_buffer);
+       g_assert_cmpstr (search_text, ==, "search-text");
+
+       g_object_unref (source_buffer);
+}
+
+static void
+test_occurrence_position (void)
+{
+       GtkSourceBuffer *source_buffer = gtk_source_buffer_new (NULL);
+       GtkTextBuffer *text_buffer = GTK_TEXT_BUFFER (source_buffer);
+       GtkTextIter start;
+       GtkTextIter end;
+       gint pos;
+
+       gtk_text_buffer_set_text (text_buffer, "aaaa", -1);
+       gtk_source_buffer_set_search_text (source_buffer, "aa");
+       flush_queue ();
+
+       gtk_text_buffer_get_start_iter (text_buffer, &start);
+       end = start;
+       gtk_text_iter_forward_chars (&end, 2);
+
+       pos = gtk_source_buffer_get_search_occurrence_position (source_buffer, &start, &end);
+       g_assert_cmpint (pos, ==, 1);
+
+       gtk_text_iter_forward_char (&start);
+       gtk_text_iter_forward_char (&end);
+       pos = gtk_source_buffer_get_search_occurrence_position (source_buffer, &start, &end);
+       g_assert_cmpint (pos, ==, 0);
+
+       gtk_text_iter_forward_char (&start);
+       gtk_text_iter_forward_char (&end);
+       pos = gtk_source_buffer_get_search_occurrence_position (source_buffer, &start, &end);
+       g_assert_cmpint (pos, ==, 2);
+
+       g_object_unref (source_buffer);
+}
+
+static void
+test_replace (void)
+{
+       GtkSourceBuffer *source_buffer = gtk_source_buffer_new (NULL);
+       GtkTextBuffer *text_buffer = GTK_TEXT_BUFFER (source_buffer);
+       GtkTextIter start;
+       GtkTextIter end;
+       gboolean replaced;
+       gchar *contents;
+
+       gtk_text_buffer_set_text (text_buffer, "aaaa", -1);
+       gtk_source_buffer_set_search_text (source_buffer, "aa");
+       flush_queue ();
+
+       gtk_text_buffer_get_iter_at_offset (text_buffer, &start, 1);
+       gtk_text_buffer_get_iter_at_offset (text_buffer, &end, 3);
+
+       replaced = gtk_source_buffer_search_replace (source_buffer, &start, &end, "bb", 2);
+       g_assert (!replaced);
+
+       gtk_text_buffer_get_iter_at_offset (text_buffer, &start, 2);
+       gtk_text_buffer_get_iter_at_offset (text_buffer, &end, 4);
+
+       replaced = gtk_source_buffer_search_replace (source_buffer, &start, &end, "bb", 2);
+       g_assert (replaced);
+
+       gtk_text_buffer_get_start_iter (text_buffer, &start);
+       gtk_text_buffer_get_end_iter (text_buffer, &end);
+
+       contents = gtk_text_iter_get_visible_text (&start, &end);
+       g_assert_cmpstr (contents, ==, "aabb");
+
+       g_free (contents);
+       g_object_unref (source_buffer);
+}
+
+static void
+test_replace_all (void)
+{
+       GtkSourceBuffer *source_buffer = gtk_source_buffer_new (NULL);
+       GtkTextBuffer *text_buffer = GTK_TEXT_BUFFER (source_buffer);
+       gint nb_replacements;
+       GtkTextIter start;
+       GtkTextIter end;
+       gchar *contents;
+
+       gtk_text_buffer_set_text (text_buffer, "aaaa", -1);
+       gtk_source_buffer_set_search_text (source_buffer, "aa");
+       flush_queue ();
+
+       nb_replacements = gtk_source_buffer_search_replace_all (source_buffer, "bb", 2);
+       g_assert_cmpint (nb_replacements, ==, 2);
+
+       gtk_text_buffer_get_start_iter (text_buffer, &start);
+       gtk_text_buffer_get_end_iter (text_buffer, &end);
+
+       contents = gtk_text_iter_get_visible_text (&start, &end);
+       g_assert_cmpstr (contents, ==, "bbbb");
+
+       g_free (contents);
+       g_object_unref (source_buffer);
+}
+
+static void
+test_regex (void)
+{
+       GtkSourceBuffer *source_buffer = gtk_source_buffer_new (NULL);
+       GtkTextBuffer *text_buffer = GTK_TEXT_BUFFER (source_buffer);
+       gboolean regex_enabled;
+       gint occurrences_count;
+       GtkTextIter start;
+       GtkTextIter end;
+       gchar *contents;
+
+       gtk_text_buffer_set_text (text_buffer, "hello\nworld\n", -1);
+       gtk_source_buffer_set_regex_search (source_buffer, TRUE);
+       regex_enabled = gtk_source_buffer_get_regex_search (source_buffer);
+       g_assert (regex_enabled);
+
+       /* Simple regex */
+
+       gtk_source_buffer_set_search_text (source_buffer, "\\w+");
+       flush_queue ();
+       occurrences_count = gtk_source_buffer_get_search_occurrences_count (source_buffer);
+       g_assert_cmpint (occurrences_count, ==, 2);
+
+       /* Test partial matching */
+
+       gtk_source_buffer_set_search_text (source_buffer, "(.*\n)*");
+       flush_queue ();
+       occurrences_count = gtk_source_buffer_get_search_occurrences_count (source_buffer);
+       g_assert_cmpint (occurrences_count, ==, 1);
+
+       /* Test replace */
+
+       gtk_text_buffer_set_text (text_buffer, "aa#bb", -1);
+       gtk_source_buffer_set_search_text (source_buffer, "(\\w+)#(\\w+)");
+       flush_queue ();
+
+       gtk_text_buffer_get_start_iter (text_buffer, &start);
+       gtk_text_buffer_get_end_iter (text_buffer, &end);
+       gtk_source_buffer_search_replace (source_buffer, &start, &end, "\\2#\\1", -1);
+
+       gtk_text_buffer_get_start_iter (text_buffer, &start);
+       gtk_text_buffer_get_end_iter (text_buffer, &end);
+       contents = gtk_text_iter_get_visible_text (&start, &end);
+       g_assert_cmpstr (contents, ==, "bb#aa");
+       g_free (contents);
+
+       /* Test replace all */
+
+       gtk_text_buffer_set_text (text_buffer, "aa#bb cc#dd", -1);
+       gtk_source_buffer_search_replace_all (source_buffer, "\\2#\\1", -1);
+
+       gtk_text_buffer_get_start_iter (text_buffer, &start);
+       gtk_text_buffer_get_end_iter (text_buffer, &end);
+       contents = gtk_text_iter_get_visible_text (&start, &end);
+       g_assert_cmpstr (contents, ==, "bb#aa dd#cc");
+       g_free (contents);
+
+       g_object_unref (source_buffer);
+}
+
+int
+main (int argc, char **argv)
+{
+       gtk_test_init (&argc, &argv);
+
+       g_test_add_func ("/Search/occurrences-count/simple", test_occurrences_count_simple);
+       g_test_add_func ("/Search/occurrences-count/with-insert", test_occurrences_count_with_insert);
+       g_test_add_func ("/Search/occurrences-count/with-delete", test_occurrences_count_with_delete);
+       g_test_add_func ("/Search/occurrences-count/multiple-lines", test_occurrences_count_multiple_lines);
+       g_test_add_func ("/Search/case-sensitivity", test_case_sensitivity);
+       g_test_add_func ("/Search/at-word-boundaries", test_search_at_word_boundaries);
+       g_test_add_func ("/Search/forward", test_forward_search);
+       g_test_add_func ("/Search/forward/subprocess/async-normal", test_async_forward_search_normal);
+       g_test_add_func ("/Search/forward/subprocess/async-wrap-around", 
test_async_forward_search_wrap_around);
+       g_test_add_func ("/Search/backward", test_backward_search);
+       g_test_add_func ("/Search/backward/subprocess/async-normal", test_async_backward_search_normal);
+       g_test_add_func ("/Search/backward/subprocess/async-wrap-around", 
test_async_backward_search_wrap_around);
+       g_test_add_func ("/Search/highlight", test_highlight);
+       g_test_add_func ("/Search/get-search-text", test_get_search_text);
+       g_test_add_func ("/Search/occurrence-position", test_occurrence_position);
+       g_test_add_func ("/Search/replace", test_replace);
+       g_test_add_func ("/Search/replace", test_replace_all);
+       g_test_add_func ("/Search/regex", test_regex);
+
+       return g_test_run ();
+}
diff --git a/tests/test-search.c b/tests/test-search.c
index 46dea98..22df00a 100644
--- a/tests/test-search.c
+++ b/tests/test-search.c
@@ -1,4 +1,4 @@
-/*
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8; coding: utf-8 -*-
  * test-search.c
  * This file is part of GtkSourceView
  *
@@ -21,867 +21,469 @@
 
 #include <gtk/gtk.h>
 #include <gtksourceview/gtksource.h>
-#include "gtksourceview/gtksourcesearchcontext.h"
 
-typedef struct
-{
-       gint match_start_offset;
-       gint match_end_offset;
-       guint found : 1;
-} SearchResult;
-
-typedef struct
-{
-       SearchResult *results;
-       gint result_num;
-       guint forward : 1;
-} AsyncData;
+#define TEST_TYPE_SEARCH_UI             (test_search_ui_get_type ())
+#define TEST_SEARCH_UI(obj)             (G_TYPE_CHECK_INSTANCE_CAST ((obj), TEST_TYPE_SEARCH_UI, 
TestSearchUI))
+#define TEST_SEARCH_UI_CLASS(klass)     (G_TYPE_CHECK_CLASS_CAST ((klass), TEST_TYPE_SEARCH_UI, 
TestSearchUIClass))
+#define TEST_IS_SEARCH_UI(obj)          (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TEST_TYPE_SEARCH_UI))
+#define TEST_IS_SEARCH_UI_CLASS(klass)  (G_TYPE_CHECK_CLASS_TYPE ((klass), TEST_TYPE_SEARCH_UI))
+#define TEST_SEARCH_UI_GET_CLASS(obj)   (G_TYPE_INSTANCE_GET_CLASS ((obj), TEST_TYPE_SEARCH_UI, 
TestSearchUIClass))
 
-static void check_async_search_results (GtkSourceBuffer *source_buffer,
-                                       SearchResult    *results,
-                                       gboolean         forward,
-                                       gboolean         start_check);
-
-static void
-flush_queue (void)
-{
-       while (gtk_events_pending ())
-       {
-               gtk_main_iteration ();
-       }
-}
+typedef struct _TestSearchUI        TestSearchUI;
+typedef struct _TestSearchUIClass   TestSearchUIClass;
+typedef struct _TestSearchUIPrivate TestSearchUIPrivate;
 
-/* Without insertion or deletion of text in the buffer afterwards. */
-static void
-test_occurrences_count_simple (void)
+struct _TestSearchUI
 {
-       GtkSourceBuffer *buffer = gtk_source_buffer_new (NULL);
-       GtkTextIter iter;
-       gint occurrences_count;
-
-       gtk_text_buffer_get_start_iter (GTK_TEXT_BUFFER (buffer), &iter);
-       gtk_text_buffer_insert (GTK_TEXT_BUFFER (buffer), &iter, "Some foo\nSome bar\n", -1);
-       flush_queue ();
-       occurrences_count = gtk_source_buffer_get_search_occurrences_count (buffer);
-       g_assert_cmpint (occurrences_count, ==, 0);
-
-       gtk_source_buffer_set_search_text (buffer, "world");
-       flush_queue ();
-       occurrences_count = gtk_source_buffer_get_search_occurrences_count (buffer);
-       g_assert_cmpint (occurrences_count, ==, 0);
-
-       gtk_source_buffer_set_search_text (buffer, "Some");
-       flush_queue ();
-       occurrences_count = gtk_source_buffer_get_search_occurrences_count (buffer);
-       g_assert_cmpint (occurrences_count, ==, 2);
-
-       gtk_source_buffer_set_search_text (buffer, "foo");
-       flush_queue ();
-       occurrences_count = gtk_source_buffer_get_search_occurrences_count (buffer);
-       g_assert_cmpint (occurrences_count, ==, 1);
-
-       gtk_source_buffer_set_search_text (buffer, "world");
-       flush_queue ();
-       occurrences_count = gtk_source_buffer_get_search_occurrences_count (buffer);
-       g_assert_cmpint (occurrences_count, ==, 0);
-
-       g_object_unref (buffer);
-}
-
-static void
-test_occurrences_count_with_insert (void)
-{
-       GtkSourceBuffer *source_buffer = gtk_source_buffer_new (NULL);
-       GtkTextBuffer *text_buffer = GTK_TEXT_BUFFER (source_buffer);
-       GtkTextIter iter;
-       gint occurrences_count;
+       GtkGrid parent;
+       TestSearchUIPrivate *priv;
+};
 
-       /* Contents: "foobar" */
-       gtk_text_buffer_get_start_iter (text_buffer, &iter);
-       gtk_text_buffer_insert (text_buffer, &iter, "foobar", -1);
-
-       gtk_source_buffer_set_search_text (source_buffer, "foo");
-       flush_queue ();
-       occurrences_count = gtk_source_buffer_get_search_occurrences_count (source_buffer);
-       g_assert_cmpint (occurrences_count, ==, 1);
-
-       /* Contents: "foobar " */
-       gtk_text_buffer_get_end_iter (text_buffer, &iter);
-       gtk_text_buffer_insert (text_buffer, &iter, " ", -1);
-       flush_queue ();
-       occurrences_count = gtk_source_buffer_get_search_occurrences_count (source_buffer);
-       g_assert_cmpint (occurrences_count, ==, 1);
-
-       /* Contents: "foobar foobeer" */
-       gtk_text_buffer_get_end_iter (text_buffer, &iter);
-       gtk_text_buffer_insert (text_buffer, &iter, "foobeer", -1);
-       flush_queue ();
-       occurrences_count = gtk_source_buffer_get_search_occurrences_count (source_buffer);
-       g_assert_cmpint (occurrences_count, ==, 2);
-
-       /* Contents: "foo bar foobeer" */
-       gtk_text_buffer_get_iter_at_offset (text_buffer, &iter, 3);
-       gtk_text_buffer_insert (text_buffer, &iter, " ", -1);
-       flush_queue ();
-       occurrences_count = gtk_source_buffer_get_search_occurrences_count (source_buffer);
-       g_assert_cmpint (occurrences_count, ==, 2);
-
-       /* Contents: "foto bar foobeer" */
-       gtk_text_buffer_get_iter_at_offset (text_buffer, &iter, 2);
-       gtk_text_buffer_insert (text_buffer, &iter, "t", -1);
-       flush_queue ();
-       occurrences_count = gtk_source_buffer_get_search_occurrences_count (source_buffer);
-       g_assert_cmpint (occurrences_count, ==, 1);
-
-       /* Contents: "footo bar foobeer" */
-       gtk_text_buffer_get_iter_at_offset (text_buffer, &iter, 2);
-       gtk_text_buffer_insert (text_buffer, &iter, "o", -1);
-       flush_queue ();
-       occurrences_count = gtk_source_buffer_get_search_occurrences_count (source_buffer);
-       g_assert_cmpint (occurrences_count, ==, 2);
-
-       /* Contents: "foofooto bar foobeer" */
-       gtk_text_buffer_get_start_iter (text_buffer, &iter);
-       gtk_text_buffer_insert (text_buffer, &iter, "foo", -1);
-       flush_queue ();
-       occurrences_count = gtk_source_buffer_get_search_occurrences_count (source_buffer);
-       g_assert_cmpint (occurrences_count, ==, 3);
-
-       /* Contents: "fooTfooto bar foobeer" */
-       gtk_text_buffer_get_iter_at_offset (text_buffer, &iter, 3);
-       gtk_text_buffer_insert (text_buffer, &iter, "T", -1);
-       flush_queue ();
-       occurrences_count = gtk_source_buffer_get_search_occurrences_count (source_buffer);
-       g_assert_cmpint (occurrences_count, ==, 3);
-
-       g_object_unref (source_buffer);
-}
-
-static void
-test_occurrences_count_with_delete (void)
+struct _TestSearchUIClass
 {
-       GtkSourceBuffer *source_buffer = gtk_source_buffer_new (NULL);
-       GtkTextBuffer *text_buffer = GTK_TEXT_BUFFER (source_buffer);
-       GtkTextIter start;
-       GtkTextIter end;
-       gint occurrences_count;
-
-       gtk_source_buffer_set_search_text (source_buffer, "foo");
-
-       /* Contents: "foo" -> "" */
-       gtk_text_buffer_set_text (text_buffer, "foo", -1);
-       flush_queue ();
-       occurrences_count = gtk_source_buffer_get_search_occurrences_count (source_buffer);
-       g_assert_cmpint (occurrences_count, ==, 1);
-
-       gtk_text_buffer_get_bounds (text_buffer, &start, &end);
-       gtk_text_buffer_delete (text_buffer, &start, &end);
-       flush_queue ();
-       occurrences_count = gtk_source_buffer_get_search_occurrences_count (source_buffer);
-       g_assert_cmpint (occurrences_count, ==, 0);
-
-       /* Contents: "foo" -> "oo" */
-       gtk_text_buffer_set_text (text_buffer, "foo", -1);
-       flush_queue ();
-       occurrences_count = gtk_source_buffer_get_search_occurrences_count (source_buffer);
-       g_assert_cmpint (occurrences_count, ==, 1);
-
-       gtk_text_buffer_get_start_iter (text_buffer, &start);
-       gtk_text_buffer_get_iter_at_offset (text_buffer, &end, 1);
-       gtk_text_buffer_delete (text_buffer, &start, &end);
-       flush_queue ();
-       occurrences_count = gtk_source_buffer_get_search_occurrences_count (source_buffer);
-       g_assert_cmpint (occurrences_count, ==, 0);
-
-       /* Contents: "foobar foobeer" -> "foobar" */
-       gtk_text_buffer_set_text (text_buffer, "foobar foobeer", -1);
-       flush_queue ();
-       occurrences_count = gtk_source_buffer_get_search_occurrences_count (source_buffer);
-       g_assert_cmpint (occurrences_count, ==, 2);
-
-       gtk_text_buffer_get_iter_at_offset (text_buffer, &start, 6);
-       gtk_text_buffer_get_end_iter (text_buffer, &end);
-       gtk_text_buffer_delete (text_buffer, &start, &end);
-       flush_queue ();
-       occurrences_count = gtk_source_buffer_get_search_occurrences_count (source_buffer);
-       g_assert_cmpint (occurrences_count, ==, 1);
-
-       /* Contents: "foo[foo]foo" -> "foofoo" */
-       gtk_text_buffer_set_text (text_buffer, "foofoofoo", -1);
-       flush_queue ();
-       occurrences_count = gtk_source_buffer_get_search_occurrences_count (source_buffer);
-       g_assert_cmpint (occurrences_count, ==, 3);
-
-       gtk_text_buffer_get_iter_at_offset (text_buffer, &start, 3);
-       gtk_text_buffer_get_iter_at_offset (text_buffer, &end, 6);
-       gtk_text_buffer_delete (text_buffer, &start, &end);
-       flush_queue ();
-       occurrences_count = gtk_source_buffer_get_search_occurrences_count (source_buffer);
-       g_assert_cmpint (occurrences_count, ==, 2);
-
-       /* Contents: "fo[of]oo" -> "fooo" */
-       gtk_text_buffer_get_iter_at_offset (text_buffer, &start, 2);
-       gtk_text_buffer_get_iter_at_offset (text_buffer, &end, 4);
-       gtk_text_buffer_delete (text_buffer, &start, &end);
-       flush_queue ();
-       occurrences_count = gtk_source_buffer_get_search_occurrences_count (source_buffer);
-       g_assert_cmpint (occurrences_count, ==, 1);
-
-       /* Contents: "foto" -> "foo" */
-       gtk_text_buffer_set_text (text_buffer, "foto", -1);
-       flush_queue ();
-       occurrences_count = gtk_source_buffer_get_search_occurrences_count (source_buffer);
-       g_assert_cmpint (occurrences_count, ==, 0);
-
-       gtk_text_buffer_get_iter_at_offset (text_buffer, &start, 2);
-       gtk_text_buffer_get_iter_at_offset (text_buffer, &end, 3);
-       gtk_text_buffer_delete (text_buffer, &start, &end);
-       flush_queue ();
-       occurrences_count = gtk_source_buffer_get_search_occurrences_count (source_buffer);
-       g_assert_cmpint (occurrences_count, ==, 1);
-
-       g_object_unref (source_buffer);
-}
+       GtkGridClass parent_class;
+};
 
-static void
-test_occurrences_count_multiple_lines (void)
+struct _TestSearchUIPrivate
 {
-       GtkSourceBuffer *source_buffer = gtk_source_buffer_new (NULL);
-       GtkTextBuffer *text_buffer = GTK_TEXT_BUFFER (source_buffer);
-       gint occurrences_count;
+       GtkSourceView *source_view;
+       GtkSourceBuffer *source_buffer;
+       GtkEntry *replace_entry;
+       GtkLabel *label_occurrences;
+       GtkLabel *label_regex_error;
 
-       gtk_source_buffer_set_search_text (source_buffer, "world\nhello");
+       guint idle_update_label_id;
+};
 
-       gtk_text_buffer_set_text (text_buffer, "hello world\nhello world\nhello world\n", -1);
-       flush_queue ();
-       occurrences_count = gtk_source_buffer_get_search_occurrences_count (source_buffer);
-       g_assert_cmpint (occurrences_count, ==, 2);
+GType test_search_ui_get_type (void);
 
-       gtk_source_buffer_set_search_text (source_buffer, "world\n");
-       flush_queue ();
-       occurrences_count = gtk_source_buffer_get_search_occurrences_count (source_buffer);
-       g_assert_cmpint (occurrences_count, ==, 3);
-
-       gtk_source_buffer_set_search_text (source_buffer, "\nhello world\n");
-       flush_queue ();
-       occurrences_count = gtk_source_buffer_get_search_occurrences_count (source_buffer);
-       g_assert_cmpint (occurrences_count, ==, 1);
-
-       g_object_unref (source_buffer);
-}
+G_DEFINE_TYPE_WITH_PRIVATE (TestSearchUI, test_search_ui, GTK_TYPE_GRID)
 
 static void
-test_case_sensitivity (void)
+open_file (TestSearchUI *search,
+          const gchar  *filename)
 {
-       GtkSourceBuffer *source_buffer = gtk_source_buffer_new (NULL);
-       GtkTextBuffer *text_buffer = GTK_TEXT_BUFFER (source_buffer);
-       gboolean case_sensitive;
-       gint occurrences_count;
+       gchar *contents;
+       GError *error = NULL;
+       GtkSourceLanguageManager *language_manager;
+       GtkSourceLanguage *language;
+       GtkTextIter iter;
 
-       gtk_text_buffer_set_text (text_buffer, "Case", -1);
-       gtk_source_buffer_set_search_text (source_buffer, "case");
+       if (!g_file_get_contents (filename, &contents, NULL, &error))
+       {
+               g_error ("Impossible to load file: %s", error->message);
+       }
 
-       gtk_source_buffer_set_case_sensitive_search (source_buffer, TRUE);
-       case_sensitive = gtk_source_buffer_get_case_sensitive_search (source_buffer);
-       g_assert (case_sensitive);
+       gtk_text_buffer_set_text (GTK_TEXT_BUFFER (search->priv->source_buffer),
+                                 contents,
+                                 -1);
 
-       flush_queue ();
-       occurrences_count = gtk_source_buffer_get_search_occurrences_count (source_buffer);
-       g_assert_cmpint (occurrences_count, ==, 0);
+       language_manager = gtk_source_language_manager_get_default ();
+       language = gtk_source_language_manager_get_language (language_manager, "c");
+       gtk_source_buffer_set_language (search->priv->source_buffer, language);
 
-       gtk_source_buffer_set_case_sensitive_search (source_buffer, FALSE);
-       case_sensitive = gtk_source_buffer_get_case_sensitive_search (source_buffer);
-       g_assert (!case_sensitive);
+       gtk_text_buffer_get_start_iter (GTK_TEXT_BUFFER (search->priv->source_buffer),
+                                       &iter);
 
-       flush_queue ();
-       occurrences_count = gtk_source_buffer_get_search_occurrences_count (source_buffer);
-       g_assert_cmpint (occurrences_count, ==, 1);
+       gtk_text_buffer_select_range (GTK_TEXT_BUFFER (search->priv->source_buffer),
+                                     &iter,
+                                     &iter);
 
-       g_object_unref (source_buffer);
+       g_free (contents);
 }
 
 static void
-test_search_at_word_boundaries (void)
+update_label_occurrences (TestSearchUI *search)
 {
-       GtkSourceBuffer *source_buffer = gtk_source_buffer_new (NULL);
-       GtkTextBuffer *text_buffer = GTK_TEXT_BUFFER (source_buffer);
-       gboolean at_word_boundaries;
        gint occurrences_count;
+       GtkTextIter select_start;
+       GtkTextIter select_end;
+       gint occurrence_pos;
+       gchar *text;
 
-       gtk_text_buffer_set_text (text_buffer, "AtWordBoundaries AtWord", -1);
-       gtk_source_buffer_set_search_text (source_buffer, "AtWord");
-
-       gtk_source_buffer_set_search_at_word_boundaries (source_buffer, TRUE);
-       at_word_boundaries = gtk_source_buffer_get_search_at_word_boundaries (source_buffer);
-       g_assert (at_word_boundaries);
-
-       flush_queue ();
-       occurrences_count = gtk_source_buffer_get_search_occurrences_count (source_buffer);
-       g_assert_cmpint (occurrences_count, ==, 1);
+       occurrences_count = gtk_source_buffer_get_search_occurrences_count (search->priv->source_buffer);
 
-       gtk_source_buffer_set_search_at_word_boundaries (source_buffer, FALSE);
-       at_word_boundaries = gtk_source_buffer_get_search_at_word_boundaries (source_buffer);
-       g_assert (!at_word_boundaries);
+       gtk_text_buffer_get_selection_bounds (GTK_TEXT_BUFFER (search->priv->source_buffer),
+                                             &select_start,
+                                             &select_end);
 
-       flush_queue ();
-       occurrences_count = gtk_source_buffer_get_search_occurrences_count (source_buffer);
-       g_assert_cmpint (occurrences_count, ==, 2);
+       occurrence_pos = gtk_source_buffer_get_search_occurrence_position (search->priv->source_buffer,
+                                                                          &select_start,
+                                                                          &select_end);
 
-       g_object_unref (source_buffer);
-}
-
-static void
-check_search_results (GtkSourceBuffer *source_buffer,
-                     SearchResult    *results,
-                     gboolean         forward)
-{
-       GtkTextIter iter;
-       GtkTextBuffer *text_buffer = GTK_TEXT_BUFFER (source_buffer);
-
-       gtk_text_buffer_get_start_iter (text_buffer, &iter);
-
-       do
+       if (occurrences_count == -1)
        {
-               gint i;
-               gboolean found;
-               GtkTextIter match_start;
-               GtkTextIter match_end;
-
-               i = gtk_text_iter_get_offset (&iter);
-
-               if (forward)
-               {
-                       found = gtk_source_buffer_forward_search (source_buffer,
-                                                                 &iter,
-                                                                 &match_start,
-                                                                 &match_end);
-               }
-               else
-               {
-                       found = gtk_source_buffer_backward_search (source_buffer,
-                                                                  &iter,
-                                                                  &match_start,
-                                                                  &match_end);
-               }
-
-               g_assert (found == results[i].found);
-
-               if (found)
-               {
-                       gint match_start_offset = gtk_text_iter_get_offset (&match_start);
-                       gint match_end_offset = gtk_text_iter_get_offset (&match_end);
-
-                       g_assert_cmpint (match_start_offset, ==, results[i].match_start_offset);
-                       g_assert_cmpint (match_end_offset, ==, results[i].match_end_offset);
-               }
+               text = g_strdup ("");
        }
-       while (gtk_text_iter_forward_char (&iter));
-}
-
-static void
-finish_check_result (GtkSourceBuffer *source_buffer,
-                    GAsyncResult    *result,
-                    AsyncData       *data)
-{
-       GtkTextIter match_start;
-       GtkTextIter match_end;
-       gboolean found;
-       SearchResult search_result = data->results[data->result_num];
-
-       if (data->forward)
+       else if (occurrence_pos == -1)
        {
-               found = gtk_source_buffer_forward_search_finish (source_buffer,
-                                                                result,
-                                                                &match_start,
-                                                                &match_end,
-                                                                NULL);
+               text = g_strdup_printf ("%u occurrences", occurrences_count);
        }
        else
        {
-               found = gtk_source_buffer_backward_search_finish (source_buffer,
-                                                                 result,
-                                                                 &match_start,
-                                                                 &match_end,
-                                                                 NULL);
-       }
-
-       g_assert (found == search_result.found);
-
-       if (found)
-       {
-               gint match_start_offset = gtk_text_iter_get_offset (&match_start);
-               gint match_end_offset = gtk_text_iter_get_offset (&match_end);
-
-               g_assert_cmpint (match_start_offset, ==, search_result.match_start_offset);
-               g_assert_cmpint (match_end_offset, ==, search_result.match_end_offset);
+               text = g_strdup_printf ("%d of %u", occurrence_pos, occurrences_count);
        }
 
-       check_async_search_results (source_buffer,
-                                   data->results,
-                                   data->forward,
-                                   FALSE);
-
-       g_slice_free (AsyncData, data);
+       gtk_label_set_text (search->priv->label_occurrences, text);
+       g_free (text);
 }
 
 static void
-check_async_search_results (GtkSourceBuffer *source_buffer,
-                           SearchResult    *results,
-                           gboolean         forward,
-                           gboolean         start_check)
+update_label_regex_error (TestSearchUI *search)
 {
-       static GtkTextIter iter;
-       GtkTextBuffer *text_buffer = GTK_TEXT_BUFFER (source_buffer);
-       AsyncData *data;
-
-       if (start_check)
-       {
-               gtk_text_buffer_get_start_iter (text_buffer, &iter);
-       }
-       else if (!gtk_text_iter_forward_char (&iter))
-       {
-               gtk_main_quit ();
-               return;
-       }
+       GError *error;
 
-       data = g_slice_new (AsyncData);
-       data->results = results;
-       data->result_num = gtk_text_iter_get_offset (&iter);
-       data->forward = forward;
+       error = gtk_source_buffer_get_regex_search_error (search->priv->source_buffer);
 
-       if (forward)
+       if (error == NULL)
        {
-               gtk_source_buffer_forward_search_async (source_buffer,
-                                                       &iter,
-                                                       NULL,
-                                                       (GAsyncReadyCallback)finish_check_result,
-                                                       data);
+               gtk_label_set_text (search->priv->label_regex_error, "");
+               gtk_widget_hide (GTK_WIDGET (search->priv->label_regex_error));
        }
        else
        {
-               gtk_source_buffer_backward_search_async (source_buffer,
-                                                        &iter,
-                                                        NULL,
-                                                        (GAsyncReadyCallback)finish_check_result,
-                                                        data);
+               gtk_label_set_text (search->priv->label_regex_error, error->message);
+               gtk_widget_show (GTK_WIDGET (search->priv->label_regex_error));
+               g_error_free (error);
        }
 }
 
+/* The search entry is a GtkSearchEntry. The "changed" signal is delayed on a
+ * GtkSearchEntry (but not with a simple GtkEntry). That's why the
+ * "notify::text" signal is used instead.
+ * With the "changed" signal, the search highlighting takes some time to be
+ * updated, while with the notify signal, it is immediate.
+ *
+ * See https://bugzilla.gnome.org/show_bug.cgi?id=700229
+ */
 static void
-test_forward_search (void)
+search_entry_text_notify_cb (TestSearchUI *search,
+                            GParamSpec   *spec,
+                            GtkEntry     *entry)
 {
-       GtkSourceBuffer *source_buffer = gtk_source_buffer_new (NULL);
-       GtkTextBuffer *text_buffer = GTK_TEXT_BUFFER (source_buffer);
-       gboolean wrap_around;
-
-       static SearchResult results1[] =
-       {
-               { 0, 2, TRUE },
-               { 2, 4, TRUE },
-               { 2, 4, TRUE },
-               { 0, 2, TRUE },
-               { 0, 2, TRUE }
-       };
-
-       static SearchResult results2[] =
-       {
-               { 0, 2, TRUE },
-               { 2, 4, TRUE },
-               { 2, 4, TRUE },
-               { 0, 0, FALSE },
-               { 0, 0, FALSE }
-       };
-
-       gtk_text_buffer_set_text (text_buffer, "aaaa", -1);
-       gtk_source_buffer_set_search_text (source_buffer, "aa");
-
-       /* Wrap around: TRUE */
-
-       gtk_source_buffer_set_search_wrap_around (source_buffer, TRUE);
-       wrap_around = gtk_source_buffer_get_search_wrap_around (source_buffer);
-       g_assert (wrap_around);
-
-       check_search_results (source_buffer, results1, TRUE);
-
-       g_test_trap_subprocess ("/Search/forward/subprocess/async-wrap-around", 0, 0);
-       g_test_trap_assert_passed ();
-
-       /* Wrap around: FALSE */
-
-       gtk_source_buffer_set_search_wrap_around (source_buffer, FALSE);
-       wrap_around = gtk_source_buffer_get_search_wrap_around (source_buffer);
-       g_assert (!wrap_around);
-
-       check_search_results (source_buffer, results2, TRUE);
+       const gchar *text = gtk_entry_get_text (entry);
+       gchar *unescaped_text = gtk_source_utils_unescape_search_text (text);
 
-       g_test_trap_subprocess ("/Search/forward/subprocess/async-normal", 0, 0);
-       g_test_trap_assert_passed ();
-
-       g_object_unref (source_buffer);
+       gtk_source_buffer_set_search_text (search->priv->source_buffer, unescaped_text);
+       g_free (unescaped_text);
 }
 
 static void
-test_async_forward_search_normal (void)
+select_search_occurrence (TestSearchUI      *search,
+                         const GtkTextIter *match_start,
+                         const GtkTextIter *match_end)
 {
-       GtkSourceBuffer *source_buffer = gtk_source_buffer_new (NULL);
-       GtkTextBuffer *text_buffer = GTK_TEXT_BUFFER (source_buffer);
-
-       static SearchResult results[] =
-       {
-               { 0, 2, TRUE },
-               { 2, 4, TRUE },
-               { 2, 4, TRUE },
-               { 0, 0, FALSE },
-               { 0, 0, FALSE }
-       };
+       GtkTextMark *insert;
 
-       gtk_text_buffer_set_text (text_buffer, "aaaa", -1);
-       gtk_source_buffer_set_search_text (source_buffer, "aa");
-       gtk_source_buffer_set_search_wrap_around (source_buffer, FALSE);
+       gtk_text_buffer_select_range (GTK_TEXT_BUFFER (search->priv->source_buffer),
+                                     match_start,
+                                     match_end);
 
-       check_async_search_results (source_buffer, results, TRUE, TRUE);
+       insert = gtk_text_buffer_get_insert (GTK_TEXT_BUFFER (search->priv->source_buffer));
 
-       gtk_main ();
-       g_object_unref (source_buffer);
+       gtk_text_view_scroll_mark_onscreen (GTK_TEXT_VIEW (search->priv->source_view),
+                                           insert);
 }
 
 static void
-test_async_forward_search_wrap_around (void)
+backward_search_finished (GtkSourceBuffer *buffer,
+                         GAsyncResult    *result,
+                         TestSearchUI    *search)
 {
-       GtkSourceBuffer *source_buffer = gtk_source_buffer_new (NULL);
-       GtkTextBuffer *text_buffer = GTK_TEXT_BUFFER (source_buffer);
+       GtkTextIter match_start;
+       GtkTextIter match_end;
 
-       static SearchResult results[] =
+       if (gtk_source_buffer_backward_search_finish (buffer,
+                                                     result,
+                                                     &match_start,
+                                                     &match_end,
+                                                     NULL))
        {
-               { 0, 2, TRUE },
-               { 2, 4, TRUE },
-               { 2, 4, TRUE },
-               { 0, 2, TRUE },
-               { 0, 2, TRUE }
-       };
+               select_search_occurrence (search, &match_start, &match_end);
+       }
+}
 
-       gtk_text_buffer_set_text (text_buffer, "aaaa", -1);
-       gtk_source_buffer_set_search_text (source_buffer, "aa");
-       gtk_source_buffer_set_search_wrap_around (source_buffer, TRUE);
+static void
+button_previous_clicked_cb (TestSearchUI *search,
+                           GtkButton    *button)
+{
+       GtkTextIter start_at;
 
-       check_async_search_results (source_buffer, results, TRUE, TRUE);
+       gtk_text_buffer_get_selection_bounds (GTK_TEXT_BUFFER (search->priv->source_buffer),
+                                             &start_at,
+                                             NULL);
 
-       gtk_main ();
-       g_object_unref (source_buffer);
+       gtk_source_buffer_backward_search_async (search->priv->source_buffer,
+                                                &start_at,
+                                                NULL,
+                                                (GAsyncReadyCallback)backward_search_finished,
+                                                search);
 }
 
 static void
-test_backward_search (void)
+forward_search_finished (GtkSourceBuffer *buffer,
+                        GAsyncResult    *result,
+                        TestSearchUI    *search)
 {
-       GtkSourceBuffer *source_buffer = gtk_source_buffer_new (NULL);
-       GtkTextBuffer *text_buffer = GTK_TEXT_BUFFER (source_buffer);
+       GtkTextIter match_start;
+       GtkTextIter match_end;
 
-       static SearchResult results1[] =
+       if (gtk_source_buffer_forward_search_finish (buffer,
+                                                    result,
+                                                    &match_start,
+                                                    &match_end,
+                                                    NULL))
        {
-               { 2, 4, TRUE },
-               { 2, 4, TRUE },
-               { 0, 2, TRUE },
-               { 0, 2, TRUE },
-               { 2, 4, TRUE }
-       };
-
-       static SearchResult results2[] =
-       {
-               { 0, 0, FALSE },
-               { 0, 0, FALSE },
-               { 0, 2, TRUE },
-               { 0, 2, TRUE },
-               { 2, 4, TRUE }
-       };
-
-       gtk_text_buffer_set_text (text_buffer, "aaaa", -1);
-       gtk_source_buffer_set_search_text (source_buffer, "aa");
-
-       /* Wrap around: TRUE */
-
-       gtk_source_buffer_set_search_wrap_around (source_buffer, TRUE);
-       check_search_results (source_buffer, results1, FALSE);
-
-       g_test_trap_subprocess ("/Search/backward/subprocess/async-wrap-around", 0, 0);
-       g_test_trap_assert_passed ();
-
-       /* Wrap around: FALSE */
-
-       gtk_source_buffer_set_search_wrap_around (source_buffer, FALSE);
-       check_search_results (source_buffer, results2, FALSE);
-
-       g_test_trap_subprocess ("/Search/backward/subprocess/async-normal", 0, 0);
-       g_test_trap_assert_passed ();
-
-       g_object_unref (source_buffer);
+               select_search_occurrence (search, &match_start, &match_end);
+       }
 }
 
 static void
-test_async_backward_search_normal (void)
+button_next_clicked_cb (TestSearchUI *search,
+                       GtkButton    *button)
 {
-       GtkSourceBuffer *source_buffer = gtk_source_buffer_new (NULL);
-       GtkTextBuffer *text_buffer = GTK_TEXT_BUFFER (source_buffer);
-
-       static SearchResult results[] =
-       {
-               { 0, 0, FALSE },
-               { 0, 0, FALSE },
-               { 0, 2, TRUE },
-               { 0, 2, TRUE },
-               { 2, 4, TRUE }
-       };
+       GtkTextIter start_at;
 
-       gtk_text_buffer_set_text (text_buffer, "aaaa", -1);
-       gtk_source_buffer_set_search_text (source_buffer, "aa");
-       gtk_source_buffer_set_search_wrap_around (source_buffer, FALSE);
+       gtk_text_buffer_get_selection_bounds (GTK_TEXT_BUFFER (search->priv->source_buffer),
+                                             NULL,
+                                             &start_at);
 
-       check_async_search_results (source_buffer, results, FALSE, TRUE);
+       gtk_source_buffer_forward_search_async (search->priv->source_buffer,
+                                               &start_at,
+                                               NULL,
+                                               (GAsyncReadyCallback)forward_search_finished,
+                                               search);
+}
 
-       gtk_main ();
-       g_object_unref (source_buffer);
+static void
+button_replace_clicked_cb (TestSearchUI *search,
+                          GtkButton    *button)
+{
+       GtkTextIter match_start;
+       GtkTextIter match_end;
+       GtkTextIter iter;
+       GtkEntryBuffer *entry_buffer;
+       gint replace_length;
+
+       gtk_text_buffer_get_selection_bounds (GTK_TEXT_BUFFER (search->priv->source_buffer),
+                                             &match_start,
+                                             &match_end);
+
+       entry_buffer = gtk_entry_get_buffer (search->priv->replace_entry);
+       replace_length = gtk_entry_buffer_get_bytes (entry_buffer);
+
+       gtk_source_buffer_search_replace (search->priv->source_buffer,
+                                         &match_start,
+                                         &match_end,
+                                         gtk_entry_get_text (search->priv->replace_entry),
+                                         replace_length);
+
+       gtk_text_buffer_get_selection_bounds (GTK_TEXT_BUFFER (search->priv->source_buffer),
+                                             NULL,
+                                             &iter);
+
+       gtk_source_buffer_forward_search_async (search->priv->source_buffer,
+                                               &iter,
+                                               NULL,
+                                               (GAsyncReadyCallback)forward_search_finished,
+                                               search);
 }
 
 static void
-test_async_backward_search_wrap_around (void)
+button_replace_all_clicked_cb (TestSearchUI *search,
+                              GtkButton    *button)
 {
-       GtkSourceBuffer *source_buffer = gtk_source_buffer_new (NULL);
-       GtkTextBuffer *text_buffer = GTK_TEXT_BUFFER (source_buffer);
+       GtkEntryBuffer *entry_buffer = gtk_entry_get_buffer (search->priv->replace_entry);
+       gint replace_length = gtk_entry_buffer_get_bytes (entry_buffer);
 
-       static SearchResult results[] =
-       {
-               { 2, 4, TRUE },
-               { 2, 4, TRUE },
-               { 0, 2, TRUE },
-               { 0, 2, TRUE },
-               { 2, 4, TRUE }
-       };
+       gtk_source_buffer_search_replace_all (search->priv->source_buffer,
+                                             gtk_entry_get_text (search->priv->replace_entry),
+                                             replace_length);
+}
 
-       gtk_text_buffer_set_text (text_buffer, "aaaa", -1);
-       gtk_source_buffer_set_search_text (source_buffer, "aa");
-       gtk_source_buffer_set_search_wrap_around (source_buffer, TRUE);
+static gboolean
+update_label_idle_cb (TestSearchUI *search)
+{
+       search->priv->idle_update_label_id = 0;
 
-       check_async_search_results (source_buffer, results, FALSE, TRUE);
+       update_label_occurrences (search);
 
-       gtk_main ();
-       g_object_unref (source_buffer);
+       return G_SOURCE_REMOVE;
 }
 
 static void
-test_highlight (void)
+mark_set_cb (GtkTextBuffer *buffer,
+            GtkTextIter   *location,
+            GtkTextMark   *mark,
+            TestSearchUI  *search)
 {
-       GtkSourceBuffer *source_buffer = gtk_source_buffer_new (NULL);
-       gboolean highlight;
+       GtkTextMark *insert;
+       GtkTextMark *selection_bound;
 
-       gtk_source_buffer_set_highlight_search (source_buffer, TRUE);
-       highlight = gtk_source_buffer_get_highlight_search (source_buffer);
-       g_assert (highlight);
+       insert = gtk_text_buffer_get_insert (buffer);
+       selection_bound = gtk_text_buffer_get_selection_bound (buffer);
 
-       gtk_source_buffer_set_highlight_search (source_buffer, FALSE);
-       highlight = gtk_source_buffer_get_highlight_search (source_buffer);
-       g_assert (!highlight);
-
-       g_object_unref (source_buffer);
+       if ((mark == insert || mark == selection_bound) &&
+           search->priv->idle_update_label_id == 0)
+       {
+               search->priv->idle_update_label_id = g_idle_add ((GSourceFunc)update_label_idle_cb,
+                                                                search);
+       }
 }
 
 static void
-test_get_search_text (void)
+highlight_toggled_cb (TestSearchUI    *search,
+                     GtkToggleButton *button)
 {
-       GtkSourceBuffer *source_buffer = gtk_source_buffer_new (NULL);
-       const gchar *search_text;
-
-       search_text = gtk_source_buffer_get_search_text (source_buffer);
-       g_assert (search_text == NULL);
-
-       gtk_source_buffer_set_search_text (source_buffer, "");
-       search_text = gtk_source_buffer_get_search_text (source_buffer);
-       g_assert (search_text == NULL);
-
-       gtk_source_buffer_set_search_text (source_buffer, "search-text");
-       search_text = gtk_source_buffer_get_search_text (source_buffer);
-       g_assert_cmpstr (search_text, ==, "search-text");
-
-       g_object_unref (source_buffer);
+       gtk_source_buffer_set_highlight_search (search->priv->source_buffer,
+                                               gtk_toggle_button_get_active (button));
 }
 
 static void
-test_occurrence_position (void)
+match_case_toggled_cb (TestSearchUI    *search,
+                      GtkToggleButton *button)
 {
-       GtkSourceBuffer *source_buffer = gtk_source_buffer_new (NULL);
-       GtkTextBuffer *text_buffer = GTK_TEXT_BUFFER (source_buffer);
-       GtkTextIter start;
-       GtkTextIter end;
-       gint pos;
-
-       gtk_text_buffer_set_text (text_buffer, "aaaa", -1);
-       gtk_source_buffer_set_search_text (source_buffer, "aa");
-       flush_queue ();
-
-       gtk_text_buffer_get_start_iter (text_buffer, &start);
-       end = start;
-       gtk_text_iter_forward_chars (&end, 2);
-
-       pos = gtk_source_buffer_get_search_occurrence_position (source_buffer, &start, &end);
-       g_assert_cmpint (pos, ==, 1);
-
-       gtk_text_iter_forward_char (&start);
-       gtk_text_iter_forward_char (&end);
-       pos = gtk_source_buffer_get_search_occurrence_position (source_buffer, &start, &end);
-       g_assert_cmpint (pos, ==, 0);
-
-       gtk_text_iter_forward_char (&start);
-       gtk_text_iter_forward_char (&end);
-       pos = gtk_source_buffer_get_search_occurrence_position (source_buffer, &start, &end);
-       g_assert_cmpint (pos, ==, 2);
-
-       g_object_unref (source_buffer);
+       gtk_source_buffer_set_case_sensitive_search (search->priv->source_buffer,
+                                                    gtk_toggle_button_get_active (button));
 }
 
 static void
-test_replace (void)
+at_word_boundaries_toggled_cb (TestSearchUI    *search,
+                              GtkToggleButton *button)
 {
-       GtkSourceBuffer *source_buffer = gtk_source_buffer_new (NULL);
-       GtkTextBuffer *text_buffer = GTK_TEXT_BUFFER (source_buffer);
-       GtkTextIter start;
-       GtkTextIter end;
-       gboolean replaced;
-       gchar *contents;
-
-       gtk_text_buffer_set_text (text_buffer, "aaaa", -1);
-       gtk_source_buffer_set_search_text (source_buffer, "aa");
-       flush_queue ();
-
-       gtk_text_buffer_get_iter_at_offset (text_buffer, &start, 1);
-       gtk_text_buffer_get_iter_at_offset (text_buffer, &end, 3);
+       gtk_source_buffer_set_search_at_word_boundaries (search->priv->source_buffer,
+                                                        gtk_toggle_button_get_active (button));
+}
 
-       replaced = gtk_source_buffer_search_replace (source_buffer, &start, &end, "bb", 2);
-       g_assert (!replaced);
+static void
+wrap_around_toggled_cb (TestSearchUI    *search,
+                       GtkToggleButton *button)
+{
+       gtk_source_buffer_set_search_wrap_around (search->priv->source_buffer,
+                                                 gtk_toggle_button_get_active (button));
+}
 
-       gtk_text_buffer_get_iter_at_offset (text_buffer, &start, 2);
-       gtk_text_buffer_get_iter_at_offset (text_buffer, &end, 4);
+static void
+regex_toggled_cb (TestSearchUI    *search,
+                 GtkToggleButton *button)
+{
+       gtk_source_buffer_set_regex_search (search->priv->source_buffer,
+                                           gtk_toggle_button_get_active (button));
+}
 
-       replaced = gtk_source_buffer_search_replace (source_buffer, &start, &end, "bb", 2);
-       g_assert (replaced);
+static void
+test_search_ui_dispose (GObject *object)
+{
+       TestSearchUI *search = TEST_SEARCH_UI (object);
 
-       gtk_text_buffer_get_start_iter (text_buffer, &start);
-       gtk_text_buffer_get_end_iter (text_buffer, &end);
+       g_clear_object (&search->priv->source_buffer);
 
-       contents = gtk_text_iter_get_visible_text (&start, &end);
-       g_assert_cmpstr (contents, ==, "aabb");
+       G_OBJECT_CLASS (test_search_ui_parent_class)->dispose (object);
+}
 
-       g_free (contents);
-       g_object_unref (source_buffer);
+static void
+test_search_ui_class_init (TestSearchUIClass *klass)
+{
+       GObjectClass *object_class = G_OBJECT_CLASS (klass);
+       GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
+
+       object_class->dispose = test_search_ui_dispose;
+
+       gtk_widget_class_set_template_from_resource (widget_class,
+                                                    "/org/gnome/gtksourceview/tests/ui/test-search.ui");
+
+       gtk_widget_class_bind_template_child_private (widget_class, TestSearchUI, source_view);
+       gtk_widget_class_bind_template_child_private (widget_class, TestSearchUI, replace_entry);
+       gtk_widget_class_bind_template_child_private (widget_class, TestSearchUI, label_occurrences);
+       gtk_widget_class_bind_template_child_private (widget_class, TestSearchUI, label_regex_error);
+
+       gtk_widget_class_bind_template_callback (widget_class, search_entry_text_notify_cb);
+       gtk_widget_class_bind_template_callback (widget_class, button_previous_clicked_cb);
+       gtk_widget_class_bind_template_callback (widget_class, button_next_clicked_cb);
+       gtk_widget_class_bind_template_callback (widget_class, button_replace_clicked_cb);
+       gtk_widget_class_bind_template_callback (widget_class, button_replace_all_clicked_cb);
+
+       /* It is also possible to bind the properties with
+        * g_object_bind_property(), between the check buttons and the source
+        * buffer. But GtkBuilder and Glade don't support that yet.
+        */
+       gtk_widget_class_bind_template_callback (widget_class, highlight_toggled_cb);
+       gtk_widget_class_bind_template_callback (widget_class, match_case_toggled_cb);
+       gtk_widget_class_bind_template_callback (widget_class, at_word_boundaries_toggled_cb);
+       gtk_widget_class_bind_template_callback (widget_class, wrap_around_toggled_cb);
+       gtk_widget_class_bind_template_callback (widget_class, regex_toggled_cb);
 }
 
 static void
-test_replace_all (void)
+test_search_ui_init (TestSearchUI *search)
 {
-       GtkSourceBuffer *source_buffer = gtk_source_buffer_new (NULL);
-       GtkTextBuffer *text_buffer = GTK_TEXT_BUFFER (source_buffer);
-       gint nb_replacements;
-       GtkTextIter start;
-       GtkTextIter end;
-       gchar *contents;
+       PangoFontDescription *font;
 
-       gtk_text_buffer_set_text (text_buffer, "aaaa", -1);
-       gtk_source_buffer_set_search_text (source_buffer, "aa");
-       flush_queue ();
+       search->priv = test_search_ui_get_instance_private (search);
 
-       nb_replacements = gtk_source_buffer_search_replace_all (source_buffer, "bb", 2);
-       g_assert_cmpint (nb_replacements, ==, 2);
+       gtk_widget_init_template (GTK_WIDGET (search));
 
-       gtk_text_buffer_get_start_iter (text_buffer, &start);
-       gtk_text_buffer_get_end_iter (text_buffer, &end);
+       font = pango_font_description_from_string ("Monospace 10");
+       gtk_widget_override_font (GTK_WIDGET (search->priv->source_view), font);
+       pango_font_description_free (font);
 
-       contents = gtk_text_iter_get_visible_text (&start, &end);
-       g_assert_cmpstr (contents, ==, "bbbb");
+       /* Workaround for https://bugzilla.gnome.org/show_bug.cgi?id=643732:
+        * "Source view is created with a GtkTextBuffer instead of GtkSourceBuffer"
+        */
+       search->priv->source_buffer = gtk_source_buffer_new (NULL);
 
-       g_free (contents);
-       g_object_unref (source_buffer);
-}
+       gtk_text_view_set_buffer (GTK_TEXT_VIEW (search->priv->source_view),
+                                 GTK_TEXT_BUFFER (search->priv->source_buffer));
 
-static void
-test_regex (void)
-{
-       GtkSourceBuffer *source_buffer = gtk_source_buffer_new (NULL);
-       GtkTextBuffer *text_buffer = GTK_TEXT_BUFFER (source_buffer);
-       gboolean regex_enabled;
-       gint occurrences_count;
-       GtkTextIter start;
-       GtkTextIter end;
-       gchar *contents;
+       open_file (search, TOP_SRCDIR "/gtksourceview/gtksourcesearchcontext.c");
 
-       gtk_text_buffer_set_text (text_buffer, "hello\nworld\n", -1);
-       gtk_source_buffer_set_regex_search (source_buffer, TRUE);
-       regex_enabled = gtk_source_buffer_get_regex_search (source_buffer);
-       g_assert (regex_enabled);
+       g_signal_connect_swapped (search->priv->source_buffer,
+                                 "notify::search-occurrences-count",
+                                 G_CALLBACK (update_label_occurrences),
+                                 search);
 
-       /* Simple regex */
+       g_signal_connect (search->priv->source_buffer,
+                         "mark-set",
+                         G_CALLBACK (mark_set_cb),
+                         search);
 
-       gtk_source_buffer_set_search_text (source_buffer, "\\w+");
-       flush_queue ();
-       occurrences_count = gtk_source_buffer_get_search_occurrences_count (source_buffer);
-       g_assert_cmpint (occurrences_count, ==, 2);
+       g_signal_connect_swapped (search->priv->source_buffer,
+                                 "notify::regex-search-error",
+                                 G_CALLBACK (update_label_regex_error),
+                                 search);
 
-       /* Test partial matching */
+       update_label_regex_error (search);
+}
 
-       gtk_source_buffer_set_search_text (source_buffer, "(.*\n)*");
-       flush_queue ();
-       occurrences_count = gtk_source_buffer_get_search_occurrences_count (source_buffer);
-       g_assert_cmpint (occurrences_count, ==, 1);
+static TestSearchUI *
+test_search_ui_new (void)
+{
+       return g_object_new (test_search_ui_get_type (), NULL);
+}
 
-       /* Test replace */
+gint
+main (gint argc, gchar *argv[])
+{
+       GtkWidget *window;
+       TestSearchUI *search;
 
-       gtk_text_buffer_set_text (text_buffer, "aa#bb", -1);
-       gtk_source_buffer_set_search_text (source_buffer, "(\\w+)#(\\w+)");
-       flush_queue ();
+       gtk_init (&argc, &argv);
 
-       gtk_text_buffer_get_start_iter (text_buffer, &start);
-       gtk_text_buffer_get_end_iter (text_buffer, &end);
-       gtk_source_buffer_search_replace (source_buffer, &start, &end, "\\2#\\1", -1);
+       window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
 
-       gtk_text_buffer_get_start_iter (text_buffer, &start);
-       gtk_text_buffer_get_end_iter (text_buffer, &end);
-       contents = gtk_text_iter_get_visible_text (&start, &end);
-       g_assert_cmpstr (contents, ==, "bb#aa");
-       g_free (contents);
+       gtk_window_set_default_size (GTK_WINDOW (window), 700, 500);
 
-       /* Test replace all */
+       g_signal_connect (window,
+                         "destroy",
+                         G_CALLBACK (gtk_main_quit),
+                         NULL);
 
-       gtk_text_buffer_set_text (text_buffer, "aa#bb cc#dd", -1);
-       gtk_source_buffer_search_replace_all (source_buffer, "\\2#\\1", -1);
+       search = test_search_ui_new ();
+       gtk_container_add (GTK_CONTAINER (window), GTK_WIDGET (search));
 
-       gtk_text_buffer_get_start_iter (text_buffer, &start);
-       gtk_text_buffer_get_end_iter (text_buffer, &end);
-       contents = gtk_text_iter_get_visible_text (&start, &end);
-       g_assert_cmpstr (contents, ==, "bb#aa dd#cc");
-       g_free (contents);
+       gtk_widget_show (window);
 
-       g_object_unref (source_buffer);
-}
+       gtk_main ();
 
-int
-main (int argc, char **argv)
-{
-       gtk_test_init (&argc, &argv);
-
-       g_test_add_func ("/Search/occurrences-count/simple", test_occurrences_count_simple);
-       g_test_add_func ("/Search/occurrences-count/with-insert", test_occurrences_count_with_insert);
-       g_test_add_func ("/Search/occurrences-count/with-delete", test_occurrences_count_with_delete);
-       g_test_add_func ("/Search/occurrences-count/multiple-lines", test_occurrences_count_multiple_lines);
-       g_test_add_func ("/Search/case-sensitivity", test_case_sensitivity);
-       g_test_add_func ("/Search/at-word-boundaries", test_search_at_word_boundaries);
-       g_test_add_func ("/Search/forward", test_forward_search);
-       g_test_add_func ("/Search/forward/subprocess/async-normal", test_async_forward_search_normal);
-       g_test_add_func ("/Search/forward/subprocess/async-wrap-around", 
test_async_forward_search_wrap_around);
-       g_test_add_func ("/Search/backward", test_backward_search);
-       g_test_add_func ("/Search/backward/subprocess/async-normal", test_async_backward_search_normal);
-       g_test_add_func ("/Search/backward/subprocess/async-wrap-around", 
test_async_backward_search_wrap_around);
-       g_test_add_func ("/Search/highlight", test_highlight);
-       g_test_add_func ("/Search/get-search-text", test_get_search_text);
-       g_test_add_func ("/Search/occurrence-position", test_occurrence_position);
-       g_test_add_func ("/Search/replace", test_replace);
-       g_test_add_func ("/Search/replace", test_replace_all);
-       g_test_add_func ("/Search/regex", test_regex);
-
-       return g_test_run ();
+       return 0;
 }
diff --git a/tests/test-search-ui.gresource.xml b/tests/test-search.gresource.xml
similarity index 68%
rename from tests/test-search-ui.gresource.xml
rename to tests/test-search.gresource.xml
index 1577bad..8cfee5b 100644
--- a/tests/test-search-ui.gresource.xml
+++ b/tests/test-search.gresource.xml
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <gresources>
   <gresource prefix="/org/gnome/gtksourceview/tests/ui">
-    <file preprocess="xml-stripblanks">test-search-ui.ui</file>
+    <file preprocess="xml-stripblanks">test-search.ui</file>
   </gresource>
 </gresources>
diff --git a/tests/test-search-ui.ui b/tests/test-search.ui
similarity index 100%
rename from tests/test-search-ui.ui
rename to tests/test-search.ui


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