1/* GTK - The GIMP Toolkit
2 * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
8 *
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
13 *
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library. If not, see <http://www.gnu.org/licenses/>.
16 */
17
18#include "config.h"
19#include <stdio.h>
20#include <string.h>
21
22#include <gtk/gtk.h>
23
24static void
25test_empty_search (void)
26{
27 GtkTextBuffer *buffer;
28 GtkTextIter it, s, e;
29 gboolean res;
30
31 buffer = gtk_text_buffer_new (NULL);
32 gtk_text_buffer_set_text (buffer, text: "This is some foo text", len: -1);
33
34 /* search from start forward */
35 gtk_text_buffer_get_start_iter (buffer, iter: &it);
36 res = gtk_text_iter_forward_search (iter: &it, str: "", flags: 0, match_start: &s, match_end: &e, NULL);
37 g_assert_true (res);
38 g_assert_cmpint (gtk_text_iter_get_offset (&s), ==, gtk_text_iter_get_offset (&e));
39 g_assert_cmpint (gtk_text_iter_get_offset (&s), ==, 1);
40
41 /* search from end backward */
42 gtk_text_buffer_get_end_iter (buffer, iter: &it);
43 res = gtk_text_iter_backward_search (iter: &it, str: "", flags: 0, match_start: &s, match_end: &e, NULL);
44 g_assert_true (res);
45 g_assert_cmpint (gtk_text_iter_get_offset (&s), ==, gtk_text_iter_get_offset (&e));
46 g_assert_cmpint (gtk_text_iter_get_offset (&s), ==, 20);
47}
48
49static void
50check_found_forward (const char *haystack,
51 const char *needle,
52 GtkTextSearchFlags flags,
53 int expected_start,
54 int expected_end,
55 const char *expected_string)
56{
57 GtkTextBuffer *buffer;
58 GtkTextIter i, s, e;
59 gboolean res;
60 char *text;
61
62 buffer = gtk_text_buffer_new (NULL);
63
64 gtk_text_buffer_set_text (buffer, text: haystack, len: -1);
65
66 /* TODO: add test with limit before, after and in the middle
67 of expected start and end */
68
69 /* search from start forward */
70 gtk_text_buffer_get_start_iter (buffer, iter: &i);
71 res = gtk_text_iter_forward_search (iter: &i, str: needle, flags, match_start: &s, match_end: &e, NULL);
72 g_assert_true (res);
73 g_assert_cmpint (expected_start, ==, gtk_text_iter_get_offset (&s));
74 g_assert_cmpint (expected_end, ==, gtk_text_iter_get_offset (&e));
75 text = gtk_text_iter_get_text (start: &s, end: &e);
76 g_assert_cmpstr (expected_string, ==, text);
77 g_free (mem: text);
78
79 g_object_unref (object: buffer);
80}
81
82static void
83check_found_backward (const char *haystack,
84 const char *needle,
85 GtkTextSearchFlags flags,
86 int expected_start,
87 int expected_end,
88 const char *expected_string)
89{
90 GtkTextBuffer *buffer;
91 GtkTextIter i, s, e;
92 gboolean res;
93 char *text;
94
95 buffer = gtk_text_buffer_new (NULL);
96
97 gtk_text_buffer_set_text (buffer, text: haystack, len: -1);
98
99 /* search from end backward */
100 gtk_text_buffer_get_end_iter (buffer, iter: &i);
101 res = gtk_text_iter_backward_search (iter: &i, str: needle, flags, match_start: &s, match_end: &e, NULL);
102 g_assert_true (res);
103 g_assert_cmpint (expected_start, ==, gtk_text_iter_get_offset (&s));
104 g_assert_cmpint (expected_end, ==, gtk_text_iter_get_offset (&e));
105 text = gtk_text_iter_get_text (start: &s, end: &e);
106 g_assert_cmpstr (expected_string, ==, text);
107 g_free (mem: text);
108
109 g_object_unref (object: buffer);
110}
111
112static void
113check_not_found (const char *haystack,
114 const char *needle,
115 GtkTextSearchFlags flags)
116{
117 GtkTextBuffer *buffer;
118 GtkTextIter i, s, e;
119 gboolean res;
120
121 buffer = gtk_text_buffer_new (NULL);
122
123 gtk_text_buffer_set_text (buffer, text: haystack, len: -1);
124
125 /* search from start forward */
126 gtk_text_buffer_get_start_iter (buffer, iter: &i);
127 res = gtk_text_iter_forward_search (iter: &i, str: needle, flags, match_start: &s, match_end: &e, NULL);
128 g_assert_false (res);
129
130 /* search from end backward */
131 gtk_text_buffer_get_end_iter (buffer, iter: &i);
132 res = gtk_text_iter_backward_search (iter: &i, str: needle, flags, match_start: &s, match_end: &e, NULL);
133 g_assert_false (res);
134
135 g_object_unref (object: buffer);
136}
137
138static void
139test_search_full_buffer (void)
140{
141 check_found_forward (haystack: "foo", needle: "foo", flags: 0, expected_start: 0, expected_end: 3, expected_string: "foo");
142 check_found_backward (haystack: "foo", needle: "foo", flags: 0, expected_start: 0, expected_end: 3, expected_string: "foo");
143 check_found_forward (haystack: "foo", needle: "foo", flags: GTK_TEXT_SEARCH_CASE_INSENSITIVE, expected_start: 0, expected_end: 3, expected_string: "foo");
144 check_found_backward (haystack: "foo", needle: "foo", flags: GTK_TEXT_SEARCH_CASE_INSENSITIVE, expected_start: 0, expected_end: 3, expected_string: "foo");
145 check_found_forward (haystack: "foo", needle: "Foo", flags: GTK_TEXT_SEARCH_CASE_INSENSITIVE, expected_start: 0, expected_end: 3, expected_string: "foo");
146 check_found_backward (haystack: "foo", needle: "Foo", flags: GTK_TEXT_SEARCH_CASE_INSENSITIVE, expected_start: 0, expected_end: 3, expected_string: "foo");
147}
148
149static void
150test_search (void)
151{
152 /* simple match */
153 check_found_forward (haystack: "This is some foo text", needle: "foo", flags: 0, expected_start: 13, expected_end: 16, expected_string: "foo");
154 check_found_backward (haystack: "This is some foo text", needle: "foo", flags: 0, expected_start: 13, expected_end: 16, expected_string: "foo");
155 check_not_found (haystack: "This is some foo text", needle: "Foo", flags: 0);
156
157 /* different matches for forward and backward */
158 check_found_forward (haystack: "This is some foo foo text", needle: "foo", flags: 0, expected_start: 13, expected_end: 16, expected_string: "foo");
159 check_found_backward (haystack: "This is some foo foo text", needle: "foo", flags: 0, expected_start: 17, expected_end: 20, expected_string: "foo");
160
161 /* new lines in the haystack */
162 check_found_forward (haystack: "This is some\nfoo text", needle: "foo", flags: 0, expected_start: 13, expected_end: 16, expected_string: "foo");
163 check_found_backward (haystack: "This is some\nfoo text", needle: "foo", flags: 0, expected_start: 13, expected_end: 16, expected_string: "foo");
164 check_found_forward (haystack: "This is some foo\nfoo text", needle: "foo", flags: 0, expected_start: 13, expected_end: 16, expected_string: "foo");
165 check_found_backward (haystack: "This is some foo\nfoo text", needle: "foo", flags: 0, expected_start: 17, expected_end: 20, expected_string: "foo");
166 check_not_found (haystack: "This is some\nfoo text", needle: "Foo", flags: 0);
167
168 /* end of buffer */
169 check_found_forward (haystack: "This is some\ntext foo", needle: "foo", flags: 0, expected_start: 18, expected_end: 21, expected_string: "foo");
170 check_found_backward (haystack: "This is some\ntext foo", needle: "foo", flags: 0, expected_start: 18, expected_end: 21, expected_string: "foo");
171 check_not_found (haystack: "This is some\ntext foo", needle: "Foo", flags: 0);
172
173 /* multiple lines in the needle */
174 check_found_forward (haystack: "This is some foo\nfoo text", needle: "foo\nfoo", flags: 0, expected_start: 13, expected_end: 20, expected_string: "foo\nfoo");
175 check_found_backward (haystack: "This is some foo\nfoo text", needle: "foo\nfoo", flags: 0, expected_start: 13, expected_end: 20, expected_string: "foo\nfoo");
176 check_not_found (haystack: "This is some foo\nfoo text", needle: "Foo\nfoo", flags: 0);
177
178 /* check also that different composition of utf8 characters
179 (e.g. accented letters) match */
180
181 check_found_forward (haystack: "This is some \303\200 text", needle: "\303\200", flags: 0, expected_start: 13, expected_end: 14, expected_string: "\303\200");
182 check_found_forward (haystack: "This is some \303\200 text", needle: "some \303\200", flags: 0, expected_start: 8, expected_end: 14, expected_string: "some \303\200");
183 check_found_forward (haystack: "This is some \303\200 text", needle: "\303\200 text", flags: 0, expected_start: 13, expected_end: 19, expected_string: "\303\200 text");
184 check_found_forward (haystack: "This is some \303\200 text", needle: "some \303\200 text", flags: 0, expected_start: 8, expected_end: 19, expected_string: "some \303\200 text");
185 check_found_backward (haystack: "This is some \303\240 text", needle: "\303\240", flags: 0, expected_start: 13, expected_end: 14, expected_string: "\303\240");
186 check_found_backward (haystack: "This is some \303\240 text", needle: "some \303\240", flags: 0, expected_start: 8, expected_end: 14, expected_string: "some \303\240");
187 check_found_backward (haystack: "This is some \303\240 text", needle: "\303\240 text", flags: 0, expected_start: 13, expected_end: 19, expected_string: "\303\240 text");
188 check_found_backward (haystack: "This is some \303\240 text", needle: "some \303\240 text", flags: 0, expected_start: 8, expected_end: 19, expected_string: "some \303\240 text");
189
190 /* multi-byte characters outside the needle */
191 check_found_forward (haystack: "\303\200 aa", needle: "aa", flags: 0, expected_start: 2, expected_end: 4, expected_string: "aa");
192 check_found_forward (haystack: "aa \303\200", needle: "aa", flags: 0, expected_start: 0, expected_end: 2, expected_string: "aa");
193 check_found_backward (haystack: "\303\200 aa", needle: "aa", flags: 0, expected_start: 2, expected_end: 4, expected_string: "aa");
194 check_found_backward (haystack: "aa \303\200", needle: "aa", flags: 0, expected_start: 0, expected_end: 2, expected_string: "aa");
195}
196
197static void
198test_search_caseless (void)
199{
200 GtkTextSearchFlags flags;
201
202 flags = GTK_TEXT_SEARCH_CASE_INSENSITIVE;
203
204 /* simple match */
205 check_found_forward (haystack: "This is some foo text", needle: "foo", flags, expected_start: 13, expected_end: 16, expected_string: "foo");
206 check_found_forward (haystack: "This is some foo text", needle: "Foo", flags, expected_start: 13, expected_end: 16, expected_string: "foo");
207 check_found_forward (haystack: "This is some Foo text", needle: "foo", flags, expected_start: 13, expected_end: 16, expected_string: "Foo");
208 check_found_backward (haystack: "This is some foo text", needle: "foo", flags, expected_start: 13, expected_end: 16, expected_string: "foo");
209 check_found_backward (haystack: "This is some foo text", needle: "Foo", flags, expected_start: 13, expected_end: 16, expected_string: "foo");
210 check_found_backward (haystack: "This is some Foo text", needle: "foo", flags, expected_start: 13, expected_end: 16, expected_string: "Foo");
211
212 /* check also that different composition of utf8 characters
213 (e.g. accented letters) match */
214
215 /* different matches for forward and backward */
216 check_found_forward (haystack: "This is some foo foo text", needle: "foo", flags, expected_start: 13, expected_end: 16, expected_string: "foo");
217 check_found_forward (haystack: "This is some foo foo text", needle: "Foo", flags, expected_start: 13, expected_end: 16, expected_string: "foo");
218 check_found_forward (haystack: "This is some Foo foo text", needle: "foo", flags, expected_start: 13, expected_end: 16, expected_string: "Foo");
219 check_found_forward (haystack: "This is some \303\200 \303\240 text", needle: "\303\240", flags, expected_start: 13, expected_end: 14, expected_string: "\303\200");
220 check_found_forward (haystack: "This is some \303\200 \303\240 text", needle: "\303\200", flags, expected_start: 13, expected_end: 14, expected_string: "\303\200");
221 check_found_forward (haystack: "This is some \303\200 \303\240 text", needle: "a\314\200", flags, expected_start: 13, expected_end: 14, expected_string: "\303\200");
222 check_found_backward (haystack: "This is some foo foo text", needle: "foo", flags, expected_start: 17, expected_end: 20, expected_string: "foo");
223 check_found_backward (haystack: "This is some foo foo text", needle: "Foo", flags, expected_start: 17, expected_end: 20, expected_string: "foo");
224 check_found_backward (haystack: "This is some foo Foo text", needle: "foo", flags, expected_start: 17, expected_end: 20, expected_string: "Foo");
225 check_found_backward (haystack: "This is some \303\200 \303\240 text", needle: "\303\240", flags, expected_start: 15, expected_end: 16, expected_string: "\303\240");
226 check_found_backward (haystack: "This is some \303\200 \303\240 text", needle: "\303\200", flags, expected_start: 15, expected_end: 16, expected_string: "\303\240");
227 check_found_backward (haystack: "This is some \303\200 \303\240 text", needle: "a\314\200", flags, expected_start: 15, expected_end: 16, expected_string: "\303\240");
228
229 /* new lines in the haystack */
230 check_found_forward (haystack: "This is some\nfoo text", needle: "foo", flags, expected_start: 13, expected_end: 16, expected_string: "foo");
231 check_found_forward (haystack: "This is some\nfoo text", needle: "Foo", flags, expected_start: 13, expected_end: 16, expected_string: "foo");
232 check_found_forward (haystack: "This is some\nFoo text", needle: "foo", flags, expected_start: 13, expected_end: 16, expected_string: "Foo");
233 check_found_forward (haystack: "This is some\n\303\200 text", needle: "\303\240", flags, expected_start: 13, expected_end: 14, expected_string: "\303\200");
234 check_found_forward (haystack: "This is some\n\303\200 text", needle: "a\314\200", flags, expected_start: 13, expected_end: 14, expected_string: "\303\200");
235 check_found_backward (haystack: "This is some\nfoo text", needle: "foo", flags, expected_start: 13, expected_end: 16, expected_string: "foo");
236 check_found_backward (haystack: "This is some\nfoo text", needle: "Foo", flags, expected_start: 13, expected_end: 16, expected_string: "foo");
237 check_found_backward (haystack: "This is some\nFoo text", needle: "foo", flags, expected_start: 13, expected_end: 16, expected_string: "Foo");
238 check_found_backward (haystack: "This is some\n\303\200 text", needle: "\303\240", flags, expected_start: 13, expected_end: 14, expected_string: "\303\200");
239 check_found_backward (haystack: "This is some\n\303\200 text", needle: "a\314\200", flags, expected_start: 13, expected_end: 14, expected_string: "\303\200");
240 check_found_forward (haystack: "This is some foo\nfoo text", needle: "foo", flags, expected_start: 13, expected_end: 16, expected_string: "foo");
241 check_found_forward (haystack: "This is some foo\nfoo text", needle: "Foo", flags, expected_start: 13, expected_end: 16, expected_string: "foo");
242 check_found_forward (haystack: "This is some Foo\nfoo text", needle: "foo", flags, expected_start: 13, expected_end: 16, expected_string: "Foo");
243 check_found_forward (haystack: "This is some \303\200\n\303\200 text", needle: "\303\240", flags, expected_start: 13, expected_end: 14, expected_string: "\303\200");
244 check_found_forward (haystack: "This is some \303\200\n\303\200 text", needle: "a\314\200", flags, expected_start: 13, expected_end: 14, expected_string: "\303\200");
245 check_found_backward (haystack: "This is some foo\nfoo text", needle: "foo", flags, expected_start: 17, expected_end: 20, expected_string: "foo");
246 check_found_backward (haystack: "This is some foo\nfoo text", needle: "Foo", flags, expected_start: 17, expected_end: 20, expected_string: "foo");
247 check_found_backward (haystack: "This is some foo\nFoo text", needle: "foo", flags, expected_start: 17, expected_end: 20, expected_string: "Foo");
248 check_found_backward (haystack: "This is some \303\200\n\303\200 text", needle: "\303\240", flags, expected_start: 15, expected_end: 16, expected_string: "\303\200");
249 check_found_backward (haystack: "This is some \303\200\n\303\200 text", needle: "a\314\200", flags, expected_start: 15, expected_end: 16, expected_string: "\303\200");
250
251 /* end of buffer */
252 check_found_forward (haystack: "This is some\ntext foo", needle: "foo", flags, expected_start: 18, expected_end: 21, expected_string: "foo");
253 check_found_forward (haystack: "This is some\ntext foo", needle: "Foo", flags, expected_start: 18, expected_end: 21, expected_string: "foo");
254 check_found_forward (haystack: "This is some\ntext Foo", needle: "foo", flags, expected_start: 18, expected_end: 21, expected_string: "Foo");
255 check_found_forward (haystack: "This is some\ntext \303\200", needle: "\303\240", flags, expected_start: 18, expected_end: 19, expected_string: "\303\200");
256 check_found_forward (haystack: "This is some\ntext \303\200", needle: "a\314\200", flags, expected_start: 18, expected_end: 19, expected_string: "\303\200");
257 check_found_backward (haystack: "This is some\ntext foo", needle: "foo", flags, expected_start: 18, expected_end: 21, expected_string: "foo");
258 check_found_backward (haystack: "This is some\ntext foo", needle: "Foo", flags, expected_start: 18, expected_end: 21, expected_string: "foo");
259 check_found_backward (haystack: "This is some\ntext Foo", needle: "foo", flags, expected_start: 18, expected_end: 21, expected_string: "Foo");
260 check_found_backward (haystack: "This is some\ntext \303\200", needle: "\303\240", flags, expected_start: 18, expected_end: 19, expected_string: "\303\200");
261 check_found_backward (haystack: "This is some\ntext \303\200", needle: "a\314\200", flags, expected_start: 18, expected_end: 19, expected_string: "\303\200");
262
263 /* multiple lines in the needle */
264 check_found_forward (haystack: "This is some foo\nfoo text", needle: "foo\nfoo", flags, expected_start: 13, expected_end: 20, expected_string: "foo\nfoo");
265 check_found_forward (haystack: "This is some foo\nfoo text", needle: "Foo\nFoo", flags, expected_start: 13, expected_end: 20, expected_string: "foo\nfoo");
266 check_found_forward (haystack: "This is some Foo\nFoo text", needle: "foo\nfoo", flags, expected_start: 13, expected_end: 20, expected_string: "Foo\nFoo");
267 check_found_forward (haystack: "This is some \303\200\n\303\200 text", needle: "\303\240\n\303\240", flags, expected_start: 13, expected_end: 16, expected_string: "\303\200\n\303\200");
268 check_found_forward (haystack: "This is some \303\200\n\303\200 text", needle: "a\314\200\na\314\200", flags, expected_start: 13, expected_end: 16, expected_string: "\303\200\n\303\200");
269 check_found_backward (haystack: "This is some foo\nfoo text", needle: "foo\nfoo", flags, expected_start: 13, expected_end: 20, expected_string: "foo\nfoo");
270 check_found_backward (haystack: "This is some foo\nfoo text", needle: "Foo\nFoo", flags, expected_start: 13, expected_end: 20, expected_string: "foo\nfoo");
271 check_found_backward (haystack: "This is some Foo\nFoo text", needle: "foo\nfoo", flags, expected_start: 13, expected_end: 20, expected_string: "Foo\nFoo");
272 check_found_backward (haystack: "This is some \303\200\n\303\200 text", needle: "\303\240\n\303\240", flags, expected_start: 13, expected_end: 16, expected_string: "\303\200\n\303\200");
273 check_found_backward (haystack: "This is some \303\200\n\303\200 text", needle: "a\314\200\na\314\200", flags, expected_start: 13, expected_end: 16, expected_string: "\303\200\n\303\200");
274
275 /* multi-byte characters outside the needle */
276 check_found_forward (haystack: "\303\200 aa", needle: "aa", flags, expected_start: 2, expected_end: 4, expected_string: "aa");
277 check_found_forward (haystack: "aa \303\200", needle: "aa", flags, expected_start: 0, expected_end: 2, expected_string: "aa");
278 check_found_backward (haystack: "\303\200 aa", needle: "aa", flags, expected_start: 2, expected_end: 4, expected_string: "aa");
279 check_found_backward (haystack: "aa \303\200", needle: "aa", flags, expected_start: 0, expected_end: 2, expected_string: "aa");
280}
281
282static void
283test_forward_to_tag_toggle (void)
284{
285 GtkTextBuffer *buffer;
286 GtkTextTag *bold_tag;
287 GtkTextTag *editable_tag;
288 GtkTextIter iter;
289 int offset;
290 gboolean ret;
291
292 buffer = gtk_text_buffer_new (NULL);
293
294 bold_tag = gtk_text_buffer_create_tag (buffer, tag_name: "bold",
295 first_property_name: "weight", PANGO_WEIGHT_BOLD,
296 NULL);
297
298 editable_tag = gtk_text_buffer_create_tag (buffer, tag_name: "not-editable",
299 first_property_name: "editable", FALSE,
300 NULL);
301
302 gtk_text_buffer_get_start_iter (buffer, iter: &iter);
303
304 gtk_text_buffer_insert (buffer, iter: &iter, text: "a", len: -1);
305 gtk_text_buffer_insert_with_tags (buffer, iter: &iter, text: "b", len: -1, first_tag: bold_tag, NULL);
306 gtk_text_buffer_insert_with_tags (buffer, iter: &iter, text: "c", len: -1, first_tag: editable_tag, NULL);
307
308 /* Go to the first "on" toggle */
309 gtk_text_buffer_get_start_iter (buffer, iter: &iter);
310 ret = gtk_text_iter_forward_to_tag_toggle (iter: &iter, NULL);
311 g_assert_true (ret);
312 offset = gtk_text_iter_get_offset (iter: &iter);
313 g_assert_cmpint (offset, ==, 1);
314
315 /* Go to the last "off" toggle for the bold tag */
316 ret = gtk_text_iter_forward_to_tag_toggle (iter: &iter, tag: bold_tag);
317 g_assert_true (ret);
318 offset = gtk_text_iter_get_offset (iter: &iter);
319 g_assert_cmpint (offset, ==, 2);
320
321 ret = gtk_text_iter_forward_to_tag_toggle (iter: &iter, tag: bold_tag);
322 g_assert_false (ret);
323
324 /* Go to the first "on" toggle for the editable tag */
325 gtk_text_buffer_get_start_iter (buffer, iter: &iter);
326 ret = gtk_text_iter_forward_to_tag_toggle (iter: &iter, tag: editable_tag);
327 g_assert_true (ret);
328 offset = gtk_text_iter_get_offset (iter: &iter);
329 g_assert_cmpint (offset, ==, 2);
330
331 /* Test with the end iter */
332 gtk_text_buffer_get_end_iter (buffer, iter: &iter);
333 ret = gtk_text_iter_forward_to_tag_toggle (iter: &iter, tag: editable_tag);
334 g_assert_false (ret);
335
336 g_object_unref (object: buffer);
337}
338
339static void
340check_forward_line_end (const char *buffer_text,
341 int initial_offset,
342 int result_offset,
343 gboolean ret)
344{
345 GtkTextBuffer *buffer;
346 GtkTextIter iter;
347
348 buffer = gtk_text_buffer_new (NULL);
349 gtk_text_buffer_set_text (buffer, text: buffer_text, len: -1);
350
351 gtk_text_buffer_get_iter_at_offset (buffer, iter: &iter, char_offset: initial_offset);
352
353 g_assert_cmpint (ret, ==, gtk_text_iter_forward_to_line_end (&iter));
354 g_assert_cmpint (result_offset, ==, gtk_text_iter_get_offset (&iter));
355
356 g_object_unref (object: buffer);
357}
358
359static void
360test_forward_to_line_end (void)
361{
362 check_forward_line_end(buffer_text: "a", initial_offset: 0, result_offset: 1, FALSE);
363 check_forward_line_end(buffer_text: "a\n", initial_offset: 0, result_offset: 1, TRUE);
364 check_forward_line_end(buffer_text: "a\r\n", initial_offset: 0, result_offset: 1, TRUE);
365 check_forward_line_end(buffer_text: "a\na\n", initial_offset: 1, result_offset: 3, TRUE);
366 check_forward_line_end(buffer_text: "a\na\n\n", initial_offset: 1, result_offset: 3, TRUE);
367 check_forward_line_end(buffer_text: "a\r\na\n", initial_offset: 1, result_offset: 4, TRUE);
368 check_forward_line_end(buffer_text: "a\r\na\r\n\r\n", initial_offset: 1, result_offset: 4, TRUE);
369}
370
371static void
372check_word_boundaries (const char *buffer_text,
373 int offset,
374 gboolean starts_word,
375 gboolean ends_word,
376 gboolean inside_word)
377{
378 GtkTextBuffer *buffer;
379 GtkTextIter iter;
380
381 buffer = gtk_text_buffer_new (NULL);
382 gtk_text_buffer_set_text (buffer, text: buffer_text, len: -1);
383
384 gtk_text_buffer_get_iter_at_offset (buffer, iter: &iter, char_offset: offset);
385
386 g_assert_cmpint (starts_word, ==, gtk_text_iter_starts_word (&iter));
387 g_assert_cmpint (ends_word, ==, gtk_text_iter_ends_word (&iter));
388 g_assert_cmpint (inside_word, ==, gtk_text_iter_inside_word (&iter));
389
390 g_object_unref (object: buffer);
391}
392
393static void
394check_forward_word_end (const char *buffer_text,
395 int initial_offset,
396 int result_offset,
397 gboolean ret)
398{
399 GtkTextBuffer *buffer;
400 GtkTextIter iter;
401
402 buffer = gtk_text_buffer_new (NULL);
403 gtk_text_buffer_set_text (buffer, text: buffer_text, len: -1);
404
405 gtk_text_buffer_get_iter_at_offset (buffer, iter: &iter, char_offset: initial_offset);
406
407 g_assert_cmpint (ret, ==, gtk_text_iter_forward_word_end (&iter));
408 g_assert_cmpint (result_offset, ==, gtk_text_iter_get_offset (&iter));
409
410 g_object_unref (object: buffer);
411}
412
413static void
414check_backward_word_start (const char *buffer_text,
415 int initial_offset,
416 int result_offset,
417 gboolean ret)
418{
419 GtkTextBuffer *buffer;
420 GtkTextIter iter;
421
422 buffer = gtk_text_buffer_new (NULL);
423 gtk_text_buffer_set_text (buffer, text: buffer_text, len: -1);
424
425 gtk_text_buffer_get_iter_at_offset (buffer, iter: &iter, char_offset: initial_offset);
426
427 g_assert_cmpint (ret, ==, gtk_text_iter_backward_word_start (&iter));
428 g_assert_cmpint (result_offset, ==, gtk_text_iter_get_offset (&iter));
429
430 g_object_unref (object: buffer);
431}
432
433static void
434test_word_boundaries (void)
435{
436 /* Test with trivial content. The word boundaries are anyway determined by
437 * Pango and can change in the future for corner cases.
438 */
439
440 check_word_boundaries (buffer_text: "ab ", offset: 0, TRUE, FALSE, TRUE);
441 check_word_boundaries (buffer_text: "ab ", offset: 1, FALSE, FALSE, TRUE);
442 check_word_boundaries (buffer_text: "ab ", offset: 2, FALSE, TRUE, FALSE);
443 check_word_boundaries (buffer_text: "ab ", offset: 3, FALSE, FALSE, FALSE);
444 check_word_boundaries (buffer_text: "", offset: 0, FALSE, FALSE, FALSE);
445
446 check_forward_word_end (buffer_text: "ab ", initial_offset: 0, result_offset: 2, TRUE);
447 check_forward_word_end (buffer_text: "ab ", initial_offset: 1, result_offset: 2, TRUE);
448 check_forward_word_end (buffer_text: "ab ", initial_offset: 2, result_offset: 2, FALSE);
449 check_forward_word_end (buffer_text: "ab ", initial_offset: 3, result_offset: 3, FALSE);
450 check_forward_word_end (buffer_text: "ab", initial_offset: 0, result_offset: 2, FALSE);
451 check_forward_word_end (buffer_text: "ab\n", initial_offset: 2, result_offset: 2, FALSE);
452
453 check_backward_word_start (buffer_text: " ab", initial_offset: 3, result_offset: 1, TRUE);
454 check_backward_word_start (buffer_text: " ab", initial_offset: 2, result_offset: 1, TRUE);
455 check_backward_word_start (buffer_text: " ab", initial_offset: 1, result_offset: 1, FALSE);
456 check_backward_word_start (buffer_text: " ab", initial_offset: 0, result_offset: 0, FALSE);
457 check_backward_word_start (buffer_text: "ab", initial_offset: 2, result_offset: 0, TRUE);
458}
459
460static void
461check_forward_visible_word_end (GtkTextBuffer *buffer,
462 int initial_offset,
463 int result_offset,
464 gboolean ret)
465{
466 GtkTextIter iter;
467
468 gtk_text_buffer_get_iter_at_offset (buffer, iter: &iter, char_offset: initial_offset);
469
470 g_assert_cmpint (ret, ==, gtk_text_iter_forward_visible_word_end (&iter));
471 g_assert_cmpint (result_offset, ==, gtk_text_iter_get_offset (&iter));
472}
473
474static void
475check_backward_visible_word_start (GtkTextBuffer *buffer,
476 int initial_offset,
477 int result_offset,
478 gboolean ret)
479{
480 GtkTextIter iter;
481
482 gtk_text_buffer_get_iter_at_offset (buffer, iter: &iter, char_offset: initial_offset);
483
484 g_assert_cmpint (ret, ==, gtk_text_iter_backward_visible_word_start (&iter));
485 g_assert_cmpint (result_offset, ==, gtk_text_iter_get_offset (&iter));
486}
487
488static void
489test_visible_word_boundaries (void)
490{
491 /* Test with trivial content. The word boundaries are anyway determined by
492 * Pango and can change in the future for corner cases.
493 */
494
495 GtkTextBuffer *buffer;
496 GtkTextTag *invisible_tag;
497 GtkTextIter iter;
498
499 buffer = gtk_text_buffer_new (NULL);
500
501 invisible_tag = gtk_text_buffer_create_tag (buffer, NULL,
502 first_property_name: "invisible", TRUE,
503 NULL);
504
505 /* Buffer contents: " a b c " with " b " invisible */
506 gtk_text_buffer_get_start_iter (buffer, iter: &iter);
507 gtk_text_buffer_insert (buffer, iter: &iter, text: " a", len: -1);
508 gtk_text_buffer_insert_with_tags (buffer, iter: &iter, text: " b ", len: -1, first_tag: invisible_tag, NULL);
509 gtk_text_buffer_insert (buffer, iter: &iter, text: "c ", len: -1);
510
511 check_forward_visible_word_end (buffer, initial_offset: 0, result_offset: 6, TRUE);
512 check_forward_visible_word_end (buffer, initial_offset: 1, result_offset: 6, TRUE);
513 check_forward_visible_word_end (buffer, initial_offset: 2, result_offset: 6, TRUE);
514 check_forward_visible_word_end (buffer, initial_offset: 3, result_offset: 6, TRUE);
515 check_forward_visible_word_end (buffer, initial_offset: 4, result_offset: 6, TRUE);
516 check_forward_visible_word_end (buffer, initial_offset: 5, result_offset: 6, TRUE);
517 check_forward_visible_word_end (buffer, initial_offset: 6, result_offset: 6, FALSE);
518 check_forward_visible_word_end (buffer, initial_offset: 7, result_offset: 7, FALSE);
519
520 check_backward_visible_word_start (buffer, initial_offset: 7, result_offset: 5, TRUE); /* FIXME result_offset should be 1 */
521 check_backward_visible_word_start (buffer, initial_offset: 6, result_offset: 5, TRUE); /* FIXME result_offset should be 1 */
522 check_backward_visible_word_start (buffer, initial_offset: 5, result_offset: 1, TRUE);
523 check_backward_visible_word_start (buffer, initial_offset: 4, result_offset: 1, TRUE);
524 check_backward_visible_word_start (buffer, initial_offset: 3, result_offset: 1, TRUE);
525 check_backward_visible_word_start (buffer, initial_offset: 2, result_offset: 1, TRUE);
526 check_backward_visible_word_start (buffer, initial_offset: 1, result_offset: 1, FALSE);
527 check_backward_visible_word_start (buffer, initial_offset: 0, result_offset: 0, FALSE);
528
529 gtk_text_buffer_set_text (buffer, text: "ab", len: -1);
530 check_forward_visible_word_end (buffer, initial_offset: 0, result_offset: 2, FALSE);
531
532 /* Buffer contents: "b c " with "b" invisible */
533 gtk_text_buffer_set_text (buffer, text: "", len: -1);
534 gtk_text_buffer_get_start_iter (buffer, iter: &iter);
535 gtk_text_buffer_insert_with_tags (buffer, iter: &iter, text: "b", len: -1, first_tag: invisible_tag, NULL);
536 gtk_text_buffer_insert (buffer, iter: &iter, text: " c ", len: -1);
537
538 check_forward_visible_word_end (buffer, initial_offset: 0, result_offset: 1, TRUE); /* FIXME result_offset should be 3 */
539
540 g_object_unref (object: buffer);
541}
542
543static void
544check_is_cursor_position (const char *buffer_text,
545 int offset,
546 gboolean ret)
547{
548 GtkTextBuffer *buffer;
549 GtkTextIter iter;
550
551 buffer = gtk_text_buffer_new (NULL);
552 gtk_text_buffer_set_text (buffer, text: buffer_text, len: -1);
553
554 gtk_text_buffer_get_iter_at_offset (buffer, iter: &iter, char_offset: offset);
555 g_assert_cmpint (ret, ==, gtk_text_iter_is_cursor_position (&iter));
556
557 g_object_unref (object: buffer);
558}
559
560static void
561check_cursor_position (const char *buffer_text,
562 gboolean forward,
563 int initial_offset,
564 int result_offset,
565 gboolean ret)
566{
567 GtkTextBuffer *buffer;
568 GtkTextIter iter;
569
570 buffer = gtk_text_buffer_new (NULL);
571 gtk_text_buffer_set_text (buffer, text: buffer_text, len: -1);
572
573 gtk_text_buffer_get_iter_at_offset (buffer, iter: &iter, char_offset: initial_offset);
574
575 if (forward)
576 g_assert_cmpint (ret, ==, gtk_text_iter_forward_cursor_position (&iter));
577 else
578 g_assert_cmpint (ret, ==, gtk_text_iter_backward_cursor_position (&iter));
579
580 g_assert_cmpint (result_offset, ==, gtk_text_iter_get_offset (&iter));
581
582 g_object_unref (object: buffer);
583}
584
585static void
586test_cursor_positions (void)
587{
588 check_is_cursor_position (buffer_text: "a\r\n", offset: 0, TRUE);
589 check_is_cursor_position (buffer_text: "a\r\n", offset: 1, TRUE);
590 check_is_cursor_position (buffer_text: "a\r\n", offset: 2, FALSE);
591 check_is_cursor_position (buffer_text: "a\r\n", offset: 3, TRUE);
592 check_is_cursor_position (buffer_text: "", offset: 0, TRUE);
593
594 /* forward */
595 check_cursor_position (buffer_text: "a\r\nb", TRUE, initial_offset: 0, result_offset: 1, TRUE);
596 check_cursor_position (buffer_text: "a\r\nb", TRUE, initial_offset: 1, result_offset: 3, TRUE);
597 check_cursor_position (buffer_text: "a\r\nb", TRUE, initial_offset: 2, result_offset: 3, TRUE);
598 check_cursor_position (buffer_text: "a\r\nb", TRUE, initial_offset: 3, result_offset: 4, FALSE);
599 check_cursor_position (buffer_text: "a\r\nb", TRUE, initial_offset: 4, result_offset: 4, FALSE);
600 check_cursor_position (buffer_text: "a\n", TRUE, initial_offset: 1, result_offset: 2, FALSE);
601
602 /* backward */
603 check_cursor_position (buffer_text: "a\r\nb", FALSE, initial_offset: 4, result_offset: 3, TRUE);
604 check_cursor_position (buffer_text: "a\r\nb", FALSE, initial_offset: 3, result_offset: 1, TRUE);
605 check_cursor_position (buffer_text: "a\r\nb", FALSE, initial_offset: 2, result_offset: 1, TRUE);
606 check_cursor_position (buffer_text: "a\r\nb", FALSE, initial_offset: 1, result_offset: 0, TRUE);
607 check_cursor_position (buffer_text: "a\r\nb", FALSE, initial_offset: 0, result_offset: 0, FALSE);
608}
609
610static void
611check_visible_cursor_position (GtkTextBuffer *buffer,
612 gboolean forward,
613 int initial_offset,
614 int result_offset,
615 gboolean ret)
616{
617 GtkTextIter iter;
618
619 gtk_text_buffer_get_iter_at_offset (buffer, iter: &iter, char_offset: initial_offset);
620
621 if (forward)
622 g_assert_cmpint (ret, ==, gtk_text_iter_forward_visible_cursor_position (&iter));
623 else
624 g_assert_cmpint (ret, ==, gtk_text_iter_backward_visible_cursor_position (&iter));
625
626 g_assert_cmpint (result_offset, ==, gtk_text_iter_get_offset (&iter));
627}
628
629static void
630test_visible_cursor_positions (void)
631{
632 GtkTextBuffer *buffer;
633 GtkTextTag *invisible_tag;
634 GtkTextIter iter;
635
636 buffer = gtk_text_buffer_new (NULL);
637
638 invisible_tag = gtk_text_buffer_create_tag (buffer, NULL,
639 first_property_name: "invisible", TRUE,
640 NULL);
641
642 /* Buffer contents: "abcd" with 'bc' invisible */
643 gtk_text_buffer_get_start_iter (buffer, iter: &iter);
644 gtk_text_buffer_insert (buffer, iter: &iter, text: "a", len: -1);
645 gtk_text_buffer_insert_with_tags (buffer, iter: &iter, text: "bc", len: -1, first_tag: invisible_tag, NULL);
646 gtk_text_buffer_insert (buffer, iter: &iter, text: "d", len: -1);
647
648 /* forward */
649 check_visible_cursor_position (buffer, TRUE, initial_offset: 0, result_offset: 3, TRUE);
650 check_visible_cursor_position (buffer, TRUE, initial_offset: 1, result_offset: 3, TRUE);
651 check_visible_cursor_position (buffer, TRUE, initial_offset: 2, result_offset: 3, TRUE);
652 check_visible_cursor_position (buffer, TRUE, initial_offset: 3, result_offset: 4, FALSE);
653 check_visible_cursor_position (buffer, TRUE, initial_offset: 4, result_offset: 4, FALSE);
654
655 /* backward */
656 check_visible_cursor_position (buffer, FALSE, initial_offset: 4, result_offset: 3, TRUE);
657 check_visible_cursor_position (buffer, FALSE, initial_offset: 3, result_offset: 0, TRUE);
658 check_visible_cursor_position (buffer, FALSE, initial_offset: 2, result_offset: 0, TRUE);
659 check_visible_cursor_position (buffer, FALSE, initial_offset: 1, result_offset: 0, TRUE);
660 check_visible_cursor_position (buffer, FALSE, initial_offset: 0, result_offset: 0, FALSE);
661
662 g_object_unref (object: buffer);
663}
664
665static void
666check_sentence_boundaries (const char *buffer_text,
667 int offset,
668 gboolean starts_sentence,
669 gboolean ends_sentence,
670 gboolean inside_sentence)
671{
672 GtkTextBuffer *buffer;
673 GtkTextIter iter;
674
675 buffer = gtk_text_buffer_new (NULL);
676 gtk_text_buffer_set_text (buffer, text: buffer_text, len: -1);
677
678 gtk_text_buffer_get_iter_at_offset (buffer, iter: &iter, char_offset: offset);
679
680 g_assert_cmpint (starts_sentence, ==, gtk_text_iter_starts_sentence (&iter));
681 g_assert_cmpint (ends_sentence, ==, gtk_text_iter_ends_sentence (&iter));
682 g_assert_cmpint (inside_sentence, ==, gtk_text_iter_inside_sentence (&iter));
683
684 g_object_unref (object: buffer);
685}
686
687static void
688check_forward_sentence_end (const char *buffer_text,
689 int initial_offset,
690 int result_offset,
691 gboolean ret)
692{
693 GtkTextBuffer *buffer;
694 GtkTextIter iter;
695
696 buffer = gtk_text_buffer_new (NULL);
697 gtk_text_buffer_set_text (buffer, text: buffer_text, len: -1);
698
699 gtk_text_buffer_get_iter_at_offset (buffer, iter: &iter, char_offset: initial_offset);
700
701 g_assert_cmpint (ret, ==, gtk_text_iter_forward_sentence_end (&iter));
702 g_assert_cmpint (result_offset, ==, gtk_text_iter_get_offset (&iter));
703
704 g_object_unref (object: buffer);
705}
706
707static void
708check_backward_sentence_start (const char *buffer_text,
709 int initial_offset,
710 int result_offset,
711 gboolean ret)
712{
713 GtkTextBuffer *buffer;
714 GtkTextIter iter;
715
716 buffer = gtk_text_buffer_new (NULL);
717 gtk_text_buffer_set_text (buffer, text: buffer_text, len: -1);
718
719 gtk_text_buffer_get_iter_at_offset (buffer, iter: &iter, char_offset: initial_offset);
720
721 g_assert_cmpint (ret, ==, gtk_text_iter_backward_sentence_start (&iter));
722 g_assert_cmpint (result_offset, ==, gtk_text_iter_get_offset (&iter));
723
724 g_object_unref (object: buffer);
725}
726
727static void
728test_sentence_boundaries (void)
729{
730 check_sentence_boundaries (buffer_text: "Hi. ", offset: 0, TRUE, FALSE, TRUE);
731 check_sentence_boundaries (buffer_text: "Hi. ", offset: 1, FALSE, FALSE, TRUE);
732 check_sentence_boundaries (buffer_text: "Hi. ", offset: 2, FALSE, FALSE, TRUE);
733 check_sentence_boundaries (buffer_text: "Hi. ", offset: 3, FALSE, TRUE, FALSE);
734 check_sentence_boundaries (buffer_text: "Hi. ", offset: 4, FALSE, FALSE, FALSE);
735 check_sentence_boundaries (buffer_text: "", offset: 0, FALSE, FALSE, FALSE);
736
737 check_forward_sentence_end (buffer_text: "Hi. ", initial_offset: 0, result_offset: 3, TRUE);
738 check_forward_sentence_end (buffer_text: "Hi. ", initial_offset: 1, result_offset: 3, TRUE);
739 check_forward_sentence_end (buffer_text: "Hi. ", initial_offset: 2, result_offset: 3, TRUE);
740 check_forward_sentence_end (buffer_text: "Hi. ", initial_offset: 3, result_offset: 3, FALSE);
741 check_forward_sentence_end (buffer_text: "Hi. ", initial_offset: 4, result_offset: 4, FALSE);
742 check_forward_sentence_end (buffer_text: "Hi.", initial_offset: 0, result_offset: 3, FALSE);
743 check_forward_sentence_end (buffer_text: "Hi.\n", initial_offset: 3, result_offset: 3, FALSE);
744
745 check_backward_sentence_start (buffer_text: " Hi.", initial_offset: 4, result_offset: 1, TRUE);
746 check_backward_sentence_start (buffer_text: " Hi.", initial_offset: 3, result_offset: 1, TRUE);
747 check_backward_sentence_start (buffer_text: " Hi.", initial_offset: 2, result_offset: 1, TRUE);
748 check_backward_sentence_start (buffer_text: " Hi.", initial_offset: 1, result_offset: 1, FALSE);
749 check_backward_sentence_start (buffer_text: " Hi.", initial_offset: 0, result_offset: 0, FALSE);
750}
751
752static void
753test_backward_line (void)
754{
755 GtkTextBuffer *buffer;
756 GtkTextIter iter, start, end;
757 gboolean ret;
758 int offset;
759
760 buffer = gtk_text_buffer_new (NULL);
761 gtk_text_buffer_get_start_iter (buffer, iter: &iter);
762 gtk_text_buffer_insert (buffer, iter: &iter, text: "Hi line 1\nHi line 2", len: -1);
763
764 /* Go to middle of first line */
765 gtk_text_iter_backward_line (iter: &iter);
766 gtk_text_iter_set_line_offset (iter: &iter, char_on_line: 4);
767
768 /* Now insert some chars with gtk_text_buffer_insert_range() */
769 gtk_text_buffer_get_end_iter (buffer, iter: &end);
770 start = end;
771 gtk_text_iter_backward_cursor_positions (iter: &start, count: 5);
772 gtk_text_buffer_insert_range (buffer, iter: &iter, start: &start, end: &end);
773
774 /* Check we are still at the first line */
775 g_assert_cmpint (gtk_text_iter_get_line (&iter), ==, 0);
776
777 /* Now a call to gtk_text_iter_backward_line() should return TRUE
778 and move &iter to start of the line, or return FALSE if &iter
779 was already at start of the line, so in both cases &iter should
780 be at the start of the line, so check that */
781 ret = gtk_text_iter_backward_line (iter: &iter);
782 g_assert_true (ret);
783 offset = gtk_text_iter_get_line_offset (iter: &iter);
784 g_assert_cmpint (offset, ==, 0);
785
786 g_object_unref (object: buffer);
787}
788
789int
790main (int argc, char** argv)
791{
792 gtk_test_init (argcp: &argc, argvp: &argv);
793
794 g_test_add_func (testpath: "/TextIter/Search Empty", test_func: test_empty_search);
795 g_test_add_func (testpath: "/TextIter/Search Full Buffer", test_func: test_search_full_buffer);
796 g_test_add_func (testpath: "/TextIter/Search", test_func: test_search);
797 g_test_add_func (testpath: "/TextIter/Search Caseless", test_func: test_search_caseless);
798 g_test_add_func (testpath: "/TextIter/Forward To Tag Toggle", test_func: test_forward_to_tag_toggle);
799 g_test_add_func (testpath: "/TextIter/Forward To Line End", test_func: test_forward_to_line_end);
800 g_test_add_func (testpath: "/TextIter/Word Boundaries", test_func: test_word_boundaries);
801 g_test_add_func (testpath: "/TextIter/Visible Word Boundaries", test_func: test_visible_word_boundaries);
802 g_test_add_func (testpath: "/TextIter/Cursor Positions", test_func: test_cursor_positions);
803 g_test_add_func (testpath: "/TextIter/Visible Cursor Positions", test_func: test_visible_cursor_positions);
804 g_test_add_func (testpath: "/TextIter/Sentence Boundaries", test_func: test_sentence_boundaries);
805 g_test_add_func (testpath: "/TextIter/Backward line", test_func: test_backward_line);
806
807 return g_test_run();
808}
809

source code of gtk/testsuite/gtk/textiter.c