/*
* test-search-context.c
* This file is part of GtkSourceView
*
* Copyright (C) 2013, 2015, 2016 - 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;
guint has_wrapped_around : 1;
} SearchResult;
typedef struct
{
SearchResult *results;
gint result_num;
guint forward : 1;
} AsyncData;
static void check_async_search_results (GtkSourceSearchContext *context,
SearchResult *results,
gboolean forward,
gboolean start_check);
static gchar *
get_buffer_contents (GtkTextBuffer *buffer)
{
GtkTextIter start;
GtkTextIter end;
gtk_text_buffer_get_bounds (buffer, &start, &end);
return gtk_text_iter_get_visible_text (&start, &end);
}
/* If we are running from the source dir (e.g. during make check)
* we override the path to read from the data dir.
*/
static void
init_style_scheme_manager (void)
{
gchar *dir;
dir = g_build_filename (TOP_SRCDIR, "data", "styles", NULL);
if (g_file_test (dir, G_FILE_TEST_IS_DIR))
{
GtkSourceStyleSchemeManager *manager;
gchar **dirs;
manager = gtk_source_style_scheme_manager_get_default ();
dirs = g_new0 (gchar *, 2);
dirs[0] = dir;
gtk_source_style_scheme_manager_set_search_path (manager, dirs);
g_strfreev (dirs);
}
else
{
g_free (dir);
}
}
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 *source_buffer = gtk_source_buffer_new (NULL);
GtkTextBuffer *text_buffer = GTK_TEXT_BUFFER (source_buffer);
GtkSourceSearchSettings *settings = gtk_source_search_settings_new ();
GtkSourceSearchContext *context = gtk_source_search_context_new (source_buffer, settings);
GtkTextIter iter;
gint occurrences_count;
gtk_text_buffer_get_start_iter (text_buffer, &iter);
gtk_text_buffer_insert (text_buffer, &iter, "Some foo\nSome bar\n", -1);
flush_queue ();
occurrences_count = gtk_source_search_context_get_occurrences_count (context);
g_assert_cmpint (occurrences_count, ==, 0);
gtk_source_search_settings_set_search_text (settings, "world");
flush_queue ();
occurrences_count = gtk_source_search_context_get_occurrences_count (context);
g_assert_cmpint (occurrences_count, ==, 0);
gtk_source_search_settings_set_search_text (settings, "Some");
flush_queue ();
occurrences_count = gtk_source_search_context_get_occurrences_count (context);
g_assert_cmpint (occurrences_count, ==, 2);
gtk_source_search_settings_set_search_text (settings, "foo");
flush_queue ();
occurrences_count = gtk_source_search_context_get_occurrences_count (context);
g_assert_cmpint (occurrences_count, ==, 1);
gtk_source_search_settings_set_search_text (settings, "world");
flush_queue ();
occurrences_count = gtk_source_search_context_get_occurrences_count (context);
g_assert_cmpint (occurrences_count, ==, 0);
g_object_unref (source_buffer);
g_object_unref (settings);
g_object_unref (context);
}
static void
test_occurrences_count_with_insert (void)
{
GtkSourceBuffer *source_buffer = gtk_source_buffer_new (NULL);
GtkTextBuffer *text_buffer = GTK_TEXT_BUFFER (source_buffer);
GtkSourceSearchSettings *settings = gtk_source_search_settings_new ();
GtkSourceSearchContext *context = gtk_source_search_context_new (source_buffer, settings);
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_search_settings_set_search_text (settings, "foo");
flush_queue ();
occurrences_count = gtk_source_search_context_get_occurrences_count (context);
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_search_context_get_occurrences_count (context);
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_search_context_get_occurrences_count (context);
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_search_context_get_occurrences_count (context);
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_search_context_get_occurrences_count (context);
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_search_context_get_occurrences_count (context);
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_search_context_get_occurrences_count (context);
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_search_context_get_occurrences_count (context);
g_assert_cmpint (occurrences_count, ==, 3);
g_object_unref (source_buffer);
g_object_unref (settings);
g_object_unref (context);
}
static void
test_occurrences_count_with_delete (void)
{
GtkSourceBuffer *source_buffer = gtk_source_buffer_new (NULL);
GtkTextBuffer *text_buffer = GTK_TEXT_BUFFER (source_buffer);
GtkSourceSearchSettings *settings = gtk_source_search_settings_new ();
GtkSourceSearchContext *context = gtk_source_search_context_new (source_buffer, settings);
GtkTextIter start;
GtkTextIter end;
gint occurrences_count;
gtk_source_search_settings_set_search_text (settings, "foo");
/* Contents: "foo" -> "" */
gtk_text_buffer_set_text (text_buffer, "foo", -1);
flush_queue ();
occurrences_count = gtk_source_search_context_get_occurrences_count (context);
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_search_context_get_occurrences_count (context);
g_assert_cmpint (occurrences_count, ==, 0);
/* Contents: "foo" -> "oo" */
gtk_text_buffer_set_text (text_buffer, "foo", -1);
flush_queue ();
occurrences_count = gtk_source_search_context_get_occurrences_count (context);
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_search_context_get_occurrences_count (context);
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_search_context_get_occurrences_count (context);
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_search_context_get_occurrences_count (context);
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_search_context_get_occurrences_count (context);
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_search_context_get_occurrences_count (context);
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_search_context_get_occurrences_count (context);
g_assert_cmpint (occurrences_count, ==, 1);
/* Contents: "foto" -> "foo" */
gtk_text_buffer_set_text (text_buffer, "foto", -1);
flush_queue ();
occurrences_count = gtk_source_search_context_get_occurrences_count (context);
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_search_context_get_occurrences_count (context);
g_assert_cmpint (occurrences_count, ==, 1);
g_object_unref (source_buffer);
g_object_unref (settings);
g_object_unref (context);
}
static void
test_occurrences_count_multiple_lines (void)
{
GtkSourceBuffer *source_buffer = gtk_source_buffer_new (NULL);
GtkTextBuffer *text_buffer = GTK_TEXT_BUFFER (source_buffer);
GtkSourceSearchSettings *settings = gtk_source_search_settings_new ();
GtkSourceSearchContext *context = gtk_source_search_context_new (source_buffer, settings);
gint occurrences_count;
gtk_source_search_settings_set_search_text (settings, "world\nhello");
gtk_text_buffer_set_text (text_buffer, "hello world\nhello world\nhello world\n", -1);
flush_queue ();
occurrences_count = gtk_source_search_context_get_occurrences_count (context);
g_assert_cmpint (occurrences_count, ==, 2);
gtk_source_search_settings_set_search_text (settings, "world\n");
flush_queue ();
occurrences_count = gtk_source_search_context_get_occurrences_count (context);
g_assert_cmpint (occurrences_count, ==, 3);
gtk_source_search_settings_set_search_text (settings, "\nhello world\n");
flush_queue ();
occurrences_count = gtk_source_search_context_get_occurrences_count (context);
g_assert_cmpint (occurrences_count, ==, 1);
g_object_unref (source_buffer);
g_object_unref (settings);
g_object_unref (context);
}
static void
test_case_sensitivity (void)
{
GtkSourceBuffer *source_buffer = gtk_source_buffer_new (NULL);
GtkTextBuffer *text_buffer = GTK_TEXT_BUFFER (source_buffer);
GtkSourceSearchSettings *settings = gtk_source_search_settings_new ();
GtkSourceSearchContext *context = gtk_source_search_context_new (source_buffer, settings);
gboolean case_sensitive;
gint occurrences_count;
gtk_text_buffer_set_text (text_buffer, "Case", -1);
gtk_source_search_settings_set_search_text (settings, "case");
gtk_source_search_settings_set_case_sensitive (settings, TRUE);
case_sensitive = gtk_source_search_settings_get_case_sensitive (settings);
g_assert (case_sensitive);
flush_queue ();
occurrences_count = gtk_source_search_context_get_occurrences_count (context);
g_assert_cmpint (occurrences_count, ==, 0);
gtk_source_search_settings_set_case_sensitive (settings, FALSE);
case_sensitive = gtk_source_search_settings_get_case_sensitive (settings);
g_assert (!case_sensitive);
flush_queue ();
occurrences_count = gtk_source_search_context_get_occurrences_count (context);
g_assert_cmpint (occurrences_count, ==, 1);
g_object_unref (source_buffer);
g_object_unref (settings);
g_object_unref (context);
}
static void
test_search_at_word_boundaries (void)
{
GtkSourceBuffer *source_buffer = gtk_source_buffer_new (NULL);
GtkTextBuffer *text_buffer = GTK_TEXT_BUFFER (source_buffer);
GtkSourceSearchSettings *settings = gtk_source_search_settings_new ();
GtkSourceSearchContext *context = gtk_source_search_context_new (source_buffer, settings);
GtkTextIter iter;
gboolean at_word_boundaries;
gint occurrences_count;
gtk_text_buffer_set_text (text_buffer, "AtWordBoundaries AtWord", -1);
gtk_source_search_settings_set_search_text (settings, "AtWord");
gtk_source_search_settings_set_at_word_boundaries (settings, TRUE);
at_word_boundaries = gtk_source_search_settings_get_at_word_boundaries (settings);
g_assert (at_word_boundaries);
flush_queue ();
occurrences_count = gtk_source_search_context_get_occurrences_count (context);
g_assert_cmpint (occurrences_count, ==, 1);
/* Contents: "AtWordBoundaries AtWord AtWord" */
gtk_text_buffer_get_iter_at_offset (text_buffer, &iter, 16);
gtk_text_buffer_insert (text_buffer, &iter, " AtWord", -1);
flush_queue ();
occurrences_count = gtk_source_search_context_get_occurrences_count (context);
g_assert_cmpint (occurrences_count, ==, 2);
/* Contents: "AtWordBoundaries AtWordd AtWord" */
gtk_text_buffer_get_iter_at_offset (text_buffer, &iter, 23);
gtk_text_buffer_insert (text_buffer, &iter, "d", -1);
flush_queue ();
occurrences_count = gtk_source_search_context_get_occurrences_count (context);
g_assert_cmpint (occurrences_count, ==, 1);
gtk_source_search_settings_set_at_word_boundaries (settings, FALSE);
at_word_boundaries = gtk_source_search_settings_get_at_word_boundaries (settings);
g_assert (!at_word_boundaries);
flush_queue ();
occurrences_count = gtk_source_search_context_get_occurrences_count (context);
g_assert_cmpint (occurrences_count, ==, 3);
/* Word with underscores */
gtk_text_buffer_set_text (text_buffer, "_hello_world_ _hello_", -1);
gtk_source_search_settings_set_search_text (settings, "_hello_");
gtk_source_search_settings_set_at_word_boundaries (settings, TRUE);
flush_queue ();
occurrences_count = gtk_source_search_context_get_occurrences_count (context);
g_assert_cmpint (occurrences_count, ==, 1);
gtk_source_search_settings_set_at_word_boundaries (settings, FALSE);
flush_queue ();
occurrences_count = gtk_source_search_context_get_occurrences_count (context);
g_assert_cmpint (occurrences_count, ==, 2);
g_object_unref (source_buffer);
g_object_unref (settings);
g_object_unref (context);
}
static void
check_search_results (GtkSourceBuffer *source_buffer,
GtkSourceSearchContext *context,
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;
gboolean has_wrapped_around;
GtkTextIter match_start;
GtkTextIter match_end;
i = gtk_text_iter_get_offset (&iter);
if (forward)
{
found = gtk_source_search_context_forward2 (context,
&iter,
&match_start,
&match_end,
&has_wrapped_around);
}
else
{
found = gtk_source_search_context_backward2 (context,
&iter,
&match_start,
&match_end,
&has_wrapped_around);
}
g_assert_cmpint (found, ==, results[i].found);
g_assert_cmpint (has_wrapped_around, ==, results[i].has_wrapped_around);
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 (GtkSourceSearchContext *context,
GAsyncResult *result,
AsyncData *data)
{
GtkTextIter match_start;
GtkTextIter match_end;
gboolean found;
gboolean has_wrapped_around;
SearchResult search_result = data->results[data->result_num];
if (data->forward)
{
found = gtk_source_search_context_forward_finish2 (context,
result,
&match_start,
&match_end,
&has_wrapped_around,
NULL);
}
else
{
found = gtk_source_search_context_backward_finish2 (context,
result,
&match_start,
&match_end,
&has_wrapped_around,
NULL);
}
g_assert_cmpint (found, ==, search_result.found);
g_assert_cmpint (has_wrapped_around, ==, search_result.has_wrapped_around);
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 (context,
data->results,
data->forward,
FALSE);
g_slice_free (AsyncData, data);
}
static void
check_async_search_results (GtkSourceSearchContext *context,
SearchResult *results,
gboolean forward,
gboolean start_check)
{
GtkSourceBuffer *source_buffer = gtk_source_search_context_get_buffer (context);
GtkTextBuffer *text_buffer = GTK_TEXT_BUFFER (source_buffer);
static GtkTextIter iter;
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_search_context_forward_async (context,
&iter,
NULL,
(GAsyncReadyCallback)finish_check_result,
data);
}
else
{
gtk_source_search_context_backward_async (context,
&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);
GtkSourceSearchSettings *settings = gtk_source_search_settings_new ();
GtkSourceSearchContext *context = gtk_source_search_context_new (source_buffer, settings);
gboolean wrap_around;
static SearchResult results1[] =
{
{ 0, 2, TRUE, FALSE },
{ 2, 4, TRUE, FALSE },
{ 2, 4, TRUE, FALSE },
{ 0, 2, TRUE, TRUE },
{ 0, 2, TRUE, TRUE }
};
static SearchResult results2[] =
{
{ 0, 2, TRUE, FALSE },
{ 2, 4, TRUE, FALSE },
{ 2, 4, TRUE, FALSE },
{ 0, 0, FALSE, FALSE },
{ 0, 0, FALSE, FALSE }
};
gtk_text_buffer_set_text (text_buffer, "aaaa", -1);
gtk_source_search_settings_set_search_text (settings, "aa");
/* Wrap around: TRUE */
gtk_source_search_settings_set_wrap_around (settings, TRUE);
wrap_around = gtk_source_search_settings_get_wrap_around (settings);
g_assert (wrap_around);
check_search_results (source_buffer, context, results1, TRUE);
gtk_source_search_settings_set_regex_enabled (settings, TRUE);
check_search_results (source_buffer, context, results1, TRUE);
gtk_source_search_settings_set_regex_enabled (settings, FALSE);
g_test_trap_subprocess ("/Search/forward/subprocess/async-wrap-around",
0,
G_TEST_SUBPROCESS_INHERIT_STDERR);
g_test_trap_assert_passed ();
/* Wrap around: FALSE */
gtk_source_search_settings_set_wrap_around (settings, FALSE);
wrap_around = gtk_source_search_settings_get_wrap_around (settings);
g_assert (!wrap_around);
check_search_results (source_buffer, context, results2, TRUE);
gtk_source_search_settings_set_regex_enabled (settings, TRUE);
check_search_results (source_buffer, context, results2, TRUE);
gtk_source_search_settings_set_regex_enabled (settings, FALSE);
g_test_trap_subprocess ("/Search/forward/subprocess/async-normal",
0,
G_TEST_SUBPROCESS_INHERIT_STDERR);
g_test_trap_assert_passed ();
g_object_unref (source_buffer);
g_object_unref (settings);
g_object_unref (context);
}
static void
test_async_forward_search_normal (void)
{
GtkSourceBuffer *source_buffer = gtk_source_buffer_new (NULL);
GtkTextBuffer *text_buffer = GTK_TEXT_BUFFER (source_buffer);
GtkSourceSearchSettings *settings = gtk_source_search_settings_new ();
GtkSourceSearchContext *context = gtk_source_search_context_new (source_buffer, settings);
static SearchResult results[] =
{
{ 0, 2, TRUE, FALSE },
{ 2, 4, TRUE, FALSE },
{ 2, 4, TRUE, FALSE },
{ 0, 0, FALSE, FALSE },
{ 0, 0, FALSE, FALSE }
};
gtk_text_buffer_set_text (text_buffer, "aaaa", -1);
gtk_source_search_settings_set_search_text (settings, "aa");
check_async_search_results (context, results, TRUE, TRUE);
gtk_main ();
g_object_unref (source_buffer);
g_object_unref (settings);
g_object_unref (context);
}
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);
GtkSourceSearchSettings *settings = gtk_source_search_settings_new ();
GtkSourceSearchContext *context = gtk_source_search_context_new (source_buffer, settings);
static SearchResult results[] =
{
{ 0, 2, TRUE, FALSE },
{ 2, 4, TRUE, FALSE },
{ 2, 4, TRUE, FALSE },
{ 0, 2, TRUE, TRUE },
{ 0, 2, TRUE, TRUE }
};
gtk_text_buffer_set_text (text_buffer, "aaaa", -1);
gtk_source_search_settings_set_search_text (settings, "aa");
gtk_source_search_settings_set_wrap_around (settings, TRUE);
check_async_search_results (context, results, TRUE, TRUE);
gtk_main ();
g_object_unref (source_buffer);
g_object_unref (settings);
g_object_unref (context);
}
static void
test_backward_search (void)
{
GtkSourceBuffer *source_buffer = gtk_source_buffer_new (NULL);
GtkTextBuffer *text_buffer = GTK_TEXT_BUFFER (source_buffer);
GtkSourceSearchSettings *settings = gtk_source_search_settings_new ();
GtkSourceSearchContext *context = gtk_source_search_context_new (source_buffer, settings);
static SearchResult results1[] =
{
{ 2, 4, TRUE, TRUE },
{ 2, 4, TRUE, TRUE },
{ 0, 2, TRUE, FALSE },
{ 0, 2, TRUE, FALSE },
{ 2, 4, TRUE, FALSE }
};
static SearchResult results2[] =
{
{ 0, 0, FALSE, FALSE },
{ 0, 0, FALSE, FALSE },
{ 0, 2, TRUE, FALSE },
{ 0, 2, TRUE, FALSE },
{ 2, 4, TRUE, FALSE }
};
gtk_text_buffer_set_text (text_buffer, "aaaa", -1);
gtk_source_search_settings_set_search_text (settings, "aa");
/* Wrap around: TRUE */
gtk_source_search_settings_set_wrap_around (settings, TRUE);
check_search_results (source_buffer, context, results1, FALSE);
gtk_source_search_settings_set_regex_enabled (settings, TRUE);
check_search_results (source_buffer, context, results1, FALSE);
gtk_source_search_settings_set_regex_enabled (settings, FALSE);
g_test_trap_subprocess ("/Search/backward/subprocess/async-wrap-around",
0,
G_TEST_SUBPROCESS_INHERIT_STDERR);
g_test_trap_assert_passed ();
/* Wrap around: FALSE */
gtk_source_search_settings_set_wrap_around (settings, FALSE);
check_search_results (source_buffer, context, results2, FALSE);
gtk_source_search_settings_set_regex_enabled (settings, TRUE);
check_search_results (source_buffer, context, results2, FALSE);
gtk_source_search_settings_set_regex_enabled (settings, FALSE);
g_test_trap_subprocess ("/Search/backward/subprocess/async-normal",
0,
G_TEST_SUBPROCESS_INHERIT_STDERR);
g_test_trap_assert_passed ();
g_object_unref (source_buffer);
g_object_unref (settings);
g_object_unref (context);
}
static void
test_async_backward_search_normal (void)
{
GtkSourceBuffer *source_buffer = gtk_source_buffer_new (NULL);
GtkTextBuffer *text_buffer = GTK_TEXT_BUFFER (source_buffer);
GtkSourceSearchSettings *settings = gtk_source_search_settings_new ();
GtkSourceSearchContext *context = gtk_source_search_context_new (source_buffer, settings);
static SearchResult results[] =
{
{ 0, 0, FALSE, FALSE },
{ 0, 0, FALSE, FALSE },
{ 0, 2, TRUE, FALSE },
{ 0, 2, TRUE, FALSE },
{ 2, 4, TRUE, FALSE }
};
gtk_text_buffer_set_text (text_buffer, "aaaa", -1);
gtk_source_search_settings_set_search_text (settings, "aa");
check_async_search_results (context, results, FALSE, TRUE);
gtk_main ();
g_object_unref (source_buffer);
g_object_unref (settings);
g_object_unref (context);
}
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);
GtkSourceSearchSettings *settings = gtk_source_search_settings_new ();
GtkSourceSearchContext *context = gtk_source_search_context_new (source_buffer, settings);
static SearchResult results[] =
{
{ 2, 4, TRUE, TRUE },
{ 2, 4, TRUE, TRUE },
{ 0, 2, TRUE, FALSE },
{ 0, 2, TRUE, FALSE },
{ 2, 4, TRUE, FALSE }
};
gtk_text_buffer_set_text (text_buffer, "aaaa", -1);
gtk_source_search_settings_set_search_text (settings, "aa");
gtk_source_search_settings_set_wrap_around (settings, TRUE);
check_async_search_results (context, results, FALSE, TRUE);
gtk_main ();
g_object_unref (source_buffer);
g_object_unref (settings);
g_object_unref (context);
}
static void
test_highlight (void)
{
GtkSourceBuffer *source_buffer = gtk_source_buffer_new (NULL);
GtkSourceSearchContext *context1 = gtk_source_search_context_new (source_buffer, NULL);
GtkSourceSearchContext *context2 = gtk_source_search_context_new (source_buffer, NULL);
gboolean highlight;
gtk_source_search_context_set_highlight (context1, TRUE);
highlight = gtk_source_search_context_get_highlight (context1);
g_assert (highlight);
gtk_source_search_context_set_highlight (context2, FALSE);
highlight = gtk_source_search_context_get_highlight (context2);
g_assert (!highlight);
g_object_unref (source_buffer);
g_object_unref (context1);
g_object_unref (context2);
}
static void
test_get_search_text (void)
{
GtkSourceSearchSettings *settings = gtk_source_search_settings_new ();
const gchar *search_text;
search_text = gtk_source_search_settings_get_search_text (settings);
g_assert (search_text == NULL);
gtk_source_search_settings_set_search_text (settings, "");
search_text = gtk_source_search_settings_get_search_text (settings);
g_assert (search_text == NULL);
gtk_source_search_settings_set_search_text (settings, "search-text");
search_text = gtk_source_search_settings_get_search_text (settings);
g_assert_cmpstr (search_text, ==, "search-text");
g_object_unref (settings);
}
static void
test_occurrence_position (void)
{
GtkSourceBuffer *source_buffer = gtk_source_buffer_new (NULL);
GtkTextBuffer *text_buffer = GTK_TEXT_BUFFER (source_buffer);
GtkSourceSearchSettings *settings = gtk_source_search_settings_new ();
GtkSourceSearchContext *context = gtk_source_search_context_new (source_buffer, settings);
GtkTextIter start;
GtkTextIter end;
gint pos;
gtk_text_buffer_set_text (text_buffer, "aaaa", -1);
gtk_source_search_settings_set_search_text (settings, "aa");
flush_queue ();
gtk_text_buffer_get_start_iter (text_buffer, &start);
end = start;
gtk_text_iter_forward_chars (&end, 2);
pos = gtk_source_search_context_get_occurrence_position (context, &start, &end);
g_assert_cmpint (pos, ==, 1);
gtk_text_iter_forward_char (&start);
gtk_text_iter_forward_char (&end);
pos = gtk_source_search_context_get_occurrence_position (context, &start, &end);
g_assert_cmpint (pos, ==, 0);
gtk_text_iter_forward_char (&start);
gtk_text_iter_forward_char (&end);
pos = gtk_source_search_context_get_occurrence_position (context, &start, &end);
g_assert_cmpint (pos, ==, 2);
g_object_unref (source_buffer);
g_object_unref (settings);
g_object_unref (context);
}
static void
test_replace (void)
{
GtkSourceBuffer *source_buffer = gtk_source_buffer_new (NULL);
GtkTextBuffer *text_buffer = GTK_TEXT_BUFFER (source_buffer);
GtkSourceSearchSettings *settings = gtk_source_search_settings_new ();
GtkSourceSearchContext *context = gtk_source_search_context_new (source_buffer, settings);
GtkTextIter start;
GtkTextIter end;
gint offset;
gboolean replaced;
gchar *contents;
gtk_text_buffer_set_text (text_buffer, "aaaa", -1);
gtk_source_search_settings_set_search_text (settings, "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_search_context_replace2 (context, &start, &end, "bbb", -1, NULL);
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_search_context_replace2 (context, &start, &end, "bbb", -1, NULL);
g_assert (replaced);
offset = gtk_text_iter_get_offset (&start);
g_assert_cmpint (offset, ==, 2);
offset = gtk_text_iter_get_offset (&end);
g_assert_cmpint (offset, ==, 5);
contents = get_buffer_contents (text_buffer);
g_assert_cmpstr (contents, ==, "aabbb");
g_free (contents);
g_object_unref (source_buffer);
g_object_unref (settings);
g_object_unref (context);
}
static void
test_replace_all (void)
{
GtkSourceBuffer *source_buffer = gtk_source_buffer_new (NULL);
GtkTextBuffer *text_buffer = GTK_TEXT_BUFFER (source_buffer);
GtkSourceSearchSettings *settings = gtk_source_search_settings_new ();
GtkSourceSearchContext *context = gtk_source_search_context_new (source_buffer, settings);
gint nb_replacements;
gchar *contents;
gtk_text_buffer_set_text (text_buffer, "aaaa", -1);
gtk_source_search_settings_set_search_text (settings, "aa");
flush_queue ();
nb_replacements = gtk_source_search_context_replace_all (context, "bb", 2, NULL);
g_assert_cmpint (nb_replacements, ==, 2);
contents = get_buffer_contents (text_buffer);
g_assert_cmpstr (contents, ==, "bbbb");
g_free (contents);
g_object_unref (source_buffer);
g_object_unref (settings);
g_object_unref (context);
}
static void
test_regex_basics (void)
{
GtkSourceBuffer *source_buffer = gtk_source_buffer_new (NULL);
GtkTextBuffer *text_buffer = GTK_TEXT_BUFFER (source_buffer);
GtkSourceSearchSettings *settings = gtk_source_search_settings_new ();
GtkSourceSearchContext *context = gtk_source_search_context_new (source_buffer, settings);
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_search_settings_set_regex_enabled (settings, TRUE);
regex_enabled = gtk_source_search_settings_get_regex_enabled (settings);
g_assert (regex_enabled);
/* Simple regex */
gtk_source_search_settings_set_search_text (settings, "\\w+");
flush_queue ();
occurrences_count = gtk_source_search_context_get_occurrences_count (context);
g_assert_cmpint (occurrences_count, ==, 2);
/* Test partial matching */
gtk_source_search_settings_set_search_text (settings, "(.*\n)*");
flush_queue ();
occurrences_count = gtk_source_search_context_get_occurrences_count (context);
g_assert_cmpint (occurrences_count, ==, 1);
/* Test replace */
gtk_text_buffer_set_text (text_buffer, "aa#bb", -1);
gtk_source_search_settings_set_search_text (settings, "(\\w+)#(\\w+)");
flush_queue ();
gtk_text_buffer_get_start_iter (text_buffer, &start);
gtk_text_buffer_get_end_iter (text_buffer, &end);
gtk_source_search_context_replace2 (context, &start, &end, "\\2#\\1", -1, NULL);
g_assert (gtk_text_iter_is_start (&start));
g_assert (gtk_text_iter_is_end (&end));
contents = get_buffer_contents (text_buffer);
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_search_context_replace_all (context, "\\2#\\1", -1, NULL);
contents = get_buffer_contents (text_buffer);
g_assert_cmpstr (contents, ==, "bb#aa dd#cc");
g_free (contents);
g_object_unref (source_buffer);
g_object_unref (settings);
g_object_unref (context);
}
static void
test_regex_at_word_boundaries (void)
{
GtkSourceBuffer *source_buffer = gtk_source_buffer_new (NULL);
GtkTextBuffer *text_buffer = GTK_TEXT_BUFFER (source_buffer);
GtkSourceSearchSettings *settings = gtk_source_search_settings_new ();
GtkSourceSearchContext *context = gtk_source_search_context_new (source_buffer, settings);
GtkTextIter iter;
GtkTextIter match_start;
GtkTextIter match_end;
gboolean has_wrapped_around;
gboolean found;
gint offset;
gchar *content;
gtk_text_buffer_set_text (text_buffer, "1234\n12345\n1234", -1);
gtk_source_search_settings_set_regex_enabled (settings, TRUE);
gtk_source_search_settings_set_at_word_boundaries (settings, TRUE);
gtk_source_search_settings_set_search_text (settings, "\\d{4}");
gtk_text_buffer_get_start_iter (text_buffer, &iter);
found = gtk_source_search_context_forward2 (context,
&iter,
&match_start,
&match_end,
&has_wrapped_around);
g_assert (found);
g_assert (!has_wrapped_around);
offset = gtk_text_iter_get_offset (&match_start);
g_assert_cmpint (offset, ==, 0);
offset = gtk_text_iter_get_offset (&match_end);
g_assert_cmpint (offset, ==, 4);
iter = match_end;
found = gtk_source_search_context_forward2 (context,
&iter,
&match_start,
&match_end,
&has_wrapped_around);
g_assert (found);
g_assert (!has_wrapped_around);
offset = gtk_text_iter_get_offset (&match_start);
g_assert_cmpint (offset, ==, 11);
offset = gtk_text_iter_get_offset (&match_end);
g_assert_cmpint (offset, ==, 15);
/* Test replace, see https://bugzilla.gnome.org/show_bug.cgi?id=740810 */
gtk_text_buffer_set_text (text_buffer, "&aa", -1);
gtk_source_search_settings_set_search_text (settings, "aa");
flush_queue ();
gtk_text_buffer_get_iter_at_offset (text_buffer, &match_start, 1);
gtk_text_buffer_get_end_iter (text_buffer, &match_end);
gtk_source_search_context_replace2 (context, &match_start, &match_end, "bbb", -1, NULL);
offset = gtk_text_iter_get_offset (&match_start);
g_assert_cmpint (offset, ==, 1);
g_assert (gtk_text_iter_is_end (&match_end));
content = get_buffer_contents (text_buffer);
g_assert_cmpstr (content, ==, "&bbb");
g_free (content);
/* Test replace multi-byte character */
gtk_text_buffer_set_text (text_buffer, "–aa", -1);
gtk_source_search_settings_set_search_text (settings, "aa");
flush_queue ();
gtk_text_buffer_get_iter_at_offset (text_buffer, &match_start, 1);
gtk_text_buffer_get_end_iter (text_buffer, &match_end);
gtk_source_search_context_replace2 (context, &match_start, &match_end, "bbb", -1, NULL);
offset = gtk_text_iter_get_offset (&match_start);
g_assert_cmpint (offset, ==, 1);
g_assert (gtk_text_iter_is_end (&match_end));
content = get_buffer_contents (text_buffer);
g_assert_cmpstr (content, ==, "–bbb");
g_free (content);
g_object_unref (source_buffer);
g_object_unref (settings);
g_object_unref (context);
}
static void
test_regex_look_behind (void)
{
GtkSourceBuffer *source_buffer = gtk_source_buffer_new (NULL);
GtkTextBuffer *text_buffer = GTK_TEXT_BUFFER (source_buffer);
GtkSourceSearchSettings *settings = gtk_source_search_settings_new ();
GtkSourceSearchContext *context = gtk_source_search_context_new (source_buffer, settings);
GtkTextIter iter;
GtkTextIter match_start;
GtkTextIter match_end;
gint count;
gint pos;
gint offset;
gboolean has_wrapped_around;
gboolean found;
gchar *contents;
GError *error = NULL;
gtk_text_buffer_set_text (text_buffer, "12\n23\n123\n23\n12", -1);
gtk_source_search_settings_set_regex_enabled (settings, TRUE);
gtk_source_search_settings_set_search_text (settings, "(?<=1)23");
flush_queue ();
/* Occurrences count */
count = gtk_source_search_context_get_occurrences_count (context);
g_assert_cmpint (count, ==, 1);
/* Forward search */
gtk_text_buffer_get_start_iter (text_buffer, &iter);
found = gtk_source_search_context_forward2 (context,
&iter,
&match_start,
&match_end,
&has_wrapped_around);
g_assert (found);
g_assert (!has_wrapped_around);
offset = gtk_text_iter_get_offset (&match_start);
g_assert_cmpint (offset, ==, 7);
offset = gtk_text_iter_get_offset (&match_end);
g_assert_cmpint (offset, ==, 9);
/* Backward search */
gtk_text_buffer_get_end_iter (text_buffer, &iter);
found = gtk_source_search_context_backward2 (context,
&iter,
&match_start,
&match_end,
&has_wrapped_around);
g_assert (found);
g_assert (!has_wrapped_around);
offset = gtk_text_iter_get_offset (&match_start);
g_assert_cmpint (offset, ==, 7);
offset = gtk_text_iter_get_offset (&match_end);
g_assert_cmpint (offset, ==, 9);
/* Occurrence position */
pos = gtk_source_search_context_get_occurrence_position (context, &match_start, &match_end);
g_assert_cmpint (pos, ==, 1);
/* Replace */
gtk_source_search_context_replace2 (context, &match_start, &match_end, "R", -1, &error);
g_assert_no_error (error);
contents = get_buffer_contents (text_buffer);
g_assert_cmpstr (contents, ==, "12\n23\n1R\n23\n12");
g_free (contents);
/* Replace all */
gtk_text_buffer_set_text (text_buffer, "12\n23\n123 123\n23\n12", -1);
flush_queue ();
gtk_source_search_context_replace_all (context, "R", -1, &error);
g_assert_no_error (error);
contents = get_buffer_contents (text_buffer);
g_assert_cmpstr (contents, ==, "12\n23\n1R 1R\n23\n12");
g_free (contents);
g_object_unref (source_buffer);
g_object_unref (settings);
g_object_unref (context);
}
static void
test_regex_look_ahead (void)
{
GtkSourceBuffer *source_buffer = gtk_source_buffer_new (NULL);
GtkTextBuffer *text_buffer = GTK_TEXT_BUFFER (source_buffer);
GtkSourceSearchSettings *settings = gtk_source_search_settings_new ();
GtkSourceSearchContext *context = gtk_source_search_context_new (source_buffer, settings);
GtkTextIter iter;
GtkTextIter match_start;
GtkTextIter match_end;
gint count;
gint pos;
gint offset;
gboolean has_wrapped_around;
gboolean found;
gchar *contents;
GError *error = NULL;
gtk_text_buffer_set_text (text_buffer, "12\n23\n123\n23\n12", -1);
gtk_source_search_settings_set_regex_enabled (settings, TRUE);
gtk_source_search_settings_set_search_text (settings, "12(?=3)");
flush_queue ();
/* Occurrences count */
count = gtk_source_search_context_get_occurrences_count (context);
g_assert_cmpint (count, ==, 1);
/* Forward search */
gtk_text_buffer_get_start_iter (text_buffer, &iter);
found = gtk_source_search_context_forward2 (context,
&iter,
&match_start,
&match_end,
&has_wrapped_around);
g_assert (found);
g_assert (!has_wrapped_around);
offset = gtk_text_iter_get_offset (&match_start);
g_assert_cmpint (offset, ==, 6);
offset = gtk_text_iter_get_offset (&match_end);
g_assert_cmpint (offset, ==, 8);
/* Backward search */
gtk_text_buffer_get_end_iter (text_buffer, &iter);
found = gtk_source_search_context_backward2 (context,
&iter,
&match_start,
&match_end,
&has_wrapped_around);
g_assert (found);
g_assert (!has_wrapped_around);
offset = gtk_text_iter_get_offset (&match_start);
g_assert_cmpint (offset, ==, 6);
offset = gtk_text_iter_get_offset (&match_end);
g_assert_cmpint (offset, ==, 8);
/* Occurrence position */
pos = gtk_source_search_context_get_occurrence_position (context, &match_start, &match_end);
g_assert_cmpint (pos, ==, 1);
/* Replace */
gtk_source_search_context_replace2 (context, &match_start, &match_end, "R", -1, &error);
g_assert_no_error (error);
contents = get_buffer_contents (text_buffer);
g_assert_cmpstr (contents, ==, "12\n23\nR3\n23\n12");
g_free (contents);
/* Replace all */
gtk_text_buffer_set_text (text_buffer, "12\n23\n123 123\n23\n12", -1);
flush_queue ();
gtk_source_search_context_replace_all (context, "R", -1, &error);
g_assert_no_error (error);
contents = get_buffer_contents (text_buffer);
g_assert_cmpstr (contents, ==, "12\n23\nR3 R3\n23\n12");
g_free (contents);
g_object_unref (source_buffer);
g_object_unref (settings);
g_object_unref (context);
}
static void
test_destroy_buffer_during_search (void)
{
GtkSourceBuffer *source_buffer = gtk_source_buffer_new (NULL);
GtkTextBuffer *text_buffer = GTK_TEXT_BUFFER (source_buffer);
GtkSourceSearchSettings *settings = gtk_source_search_settings_new ();
GtkSourceSearchContext *context = gtk_source_search_context_new (source_buffer, settings);
gtk_text_buffer_set_text (text_buffer, "y", -1);
gtk_source_search_settings_set_search_text (settings, "y");
/* Destroy buffer during search. */
g_object_unref (source_buffer);
flush_queue ();
/* Test also a new search when buffer already destroyed. */
gtk_source_search_settings_set_search_text (settings, "x");
flush_queue ();
g_object_unref (settings);
g_object_unref (context);
}
int
main (int argc, char **argv)
{
gtk_test_init (&argc, &argv);
init_style_scheme_manager ();
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_all", test_replace_all);
g_test_add_func ("/Search/regex/basics", test_regex_basics);
g_test_add_func ("/Search/regex/at-word-boundaries", test_regex_at_word_boundaries);
g_test_add_func ("/Search/regex/look-behind", test_regex_look_behind);
g_test_add_func ("/Search/regex/look-ahead", test_regex_look_ahead);
g_test_add_func ("/Search/destroy-buffer-during-search", test_destroy_buffer_during_search);
return g_test_run ();
}