1 /* 2 * Copyright (C) 2009 Igalia S.L. 3 * 4 * This library is free software; you can redistribute it and/or 5 * modify it under the terms of the GNU Library 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 * Library General Public License for more details. 13 * 14 * You should have received a copy of the GNU Library General Public License 15 * along with this library; see the file COPYING.LIB. If not, write to 16 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 17 * Boston, MA 02110-1301, USA. 18 */ 19 20 #include <errno.h> 21 #include <unistd.h> 22 #include <glib.h> 23 #include <glib/gstdio.h> 24 #include <gtk/gtk.h> 25 #include <webkit/webkit.h> 26 27 #if GLIB_CHECK_VERSION(2, 16, 0) && GTK_CHECK_VERSION(2, 14, 0) 28 29 static const char* contents = "<html><body><p>This is a test. This is the second sentence. And this the third.</p></body></html>"; 30 31 static const char* contentsWithNewlines = "<html><body><p>This is a test. \n\nThis\n is the second sentence. And this the third.</p></body></html>"; 32 33 static const char* contentsInTextarea = "<html><body><textarea cols='80'>This is a test. This is the second sentence. And this the third.</textarea></body></html>"; 34 35 static const char* contentsInTextInput = "<html><body><input type='text' size='80' value='This is a test. This is the second sentence. And this the third.'/></body></html>"; 36 37 static const char* contentsInParagraphAndBodySimple = "<html><body><p>This is a test.</p>Hello world.</body></html>"; 38 39 static const char* contentsInParagraphAndBodyModerate = "<html><body><p>This is a test.</p>Hello world.<br /><font color='#00cc00'>This sentence is green.</font><br />This one is not.</body></html>"; 40 41 static gboolean bail_out(GMainLoop* loop) 42 { 43 if (g_main_loop_is_running(loop)) 44 g_main_loop_quit(loop); 45 46 return FALSE; 47 } 48 49 typedef gchar* (*AtkGetTextFunction) (AtkText*, gint, AtkTextBoundary, gint*, gint*); 50 51 static void test_get_text_function(AtkText* text_obj, AtkGetTextFunction fn, AtkTextBoundary boundary, gint offset, const char* text_result, gint start_offset_result, gint end_offset_result) 52 { 53 gint start_offset, end_offset; 54 char* text; 55 56 text = fn(text_obj, offset, boundary, &start_offset, &end_offset); 57 g_assert_cmpstr(text, ==, text_result); 58 g_assert_cmpint(start_offset, ==, start_offset_result); 59 g_assert_cmpint(end_offset, ==, end_offset_result); 60 g_free(text); 61 } 62 63 static void run_get_text_tests(AtkText* text_obj) 64 { 65 char* text = atk_text_get_text(text_obj, 0, -1); 66 g_assert_cmpstr(text, ==, "This is a test. This is the second sentence. And this the third."); 67 g_free(text); 68 69 /* ATK_TEXT_BOUNDARY_CHAR */ 70 test_get_text_function(text_obj, atk_text_get_text_at_offset, ATK_TEXT_BOUNDARY_CHAR, 71 0, "T", 0, 1); 72 73 test_get_text_function(text_obj, atk_text_get_text_after_offset, ATK_TEXT_BOUNDARY_CHAR, 74 0, "h", 1, 2); 75 76 test_get_text_function(text_obj, atk_text_get_text_before_offset, ATK_TEXT_BOUNDARY_CHAR, 77 0, "", 0, 0); 78 79 test_get_text_function(text_obj, atk_text_get_text_before_offset, ATK_TEXT_BOUNDARY_CHAR, 80 1, "T", 0, 1); 81 82 /* ATK_TEXT_BOUNDARY_WORD_START */ 83 test_get_text_function(text_obj, atk_text_get_text_at_offset, ATK_TEXT_BOUNDARY_WORD_START, 84 0, "This ", 0, 5); 85 86 test_get_text_function(text_obj, atk_text_get_text_at_offset, ATK_TEXT_BOUNDARY_WORD_START, 87 4, "This ", 0, 5); 88 89 test_get_text_function(text_obj, atk_text_get_text_at_offset, ATK_TEXT_BOUNDARY_WORD_START, 90 10, "test. ", 10, 16); 91 92 test_get_text_function(text_obj, atk_text_get_text_at_offset, ATK_TEXT_BOUNDARY_WORD_START, 93 58, "third.", 58, 64); 94 95 test_get_text_function(text_obj, atk_text_get_text_before_offset, ATK_TEXT_BOUNDARY_WORD_START, 96 5, "This ", 0, 5); 97 98 test_get_text_function(text_obj, atk_text_get_text_before_offset, ATK_TEXT_BOUNDARY_WORD_START, 99 7, "This ", 0, 5); 100 101 test_get_text_function(text_obj, atk_text_get_text_after_offset, ATK_TEXT_BOUNDARY_WORD_START, 102 0, "is ", 5, 8); 103 104 test_get_text_function(text_obj, atk_text_get_text_after_offset, ATK_TEXT_BOUNDARY_WORD_START, 105 4, "is ", 5, 8); 106 107 test_get_text_function(text_obj, atk_text_get_text_after_offset, ATK_TEXT_BOUNDARY_WORD_START, 108 3, "is ", 5, 8); 109 110 /* ATK_TEXT_BOUNDARY_WORD_END */ 111 test_get_text_function(text_obj, atk_text_get_text_at_offset, ATK_TEXT_BOUNDARY_WORD_END, 112 0, "This", 0, 4); 113 114 test_get_text_function(text_obj, atk_text_get_text_at_offset, ATK_TEXT_BOUNDARY_WORD_END, 115 4, " is", 4, 7); 116 117 test_get_text_function(text_obj, atk_text_get_text_at_offset, ATK_TEXT_BOUNDARY_WORD_END, 118 5, " is", 4, 7); 119 120 test_get_text_function(text_obj, atk_text_get_text_at_offset, ATK_TEXT_BOUNDARY_WORD_END, 121 9, " test", 9, 14); 122 123 test_get_text_function(text_obj, atk_text_get_text_before_offset, ATK_TEXT_BOUNDARY_WORD_END, 124 5, "This", 0, 4); 125 126 test_get_text_function(text_obj, atk_text_get_text_before_offset, ATK_TEXT_BOUNDARY_WORD_END, 127 4, "This", 0, 4); 128 129 test_get_text_function(text_obj, atk_text_get_text_before_offset, ATK_TEXT_BOUNDARY_WORD_END, 130 7, " is", 4, 7); 131 132 test_get_text_function(text_obj, atk_text_get_text_after_offset, ATK_TEXT_BOUNDARY_WORD_END, 133 5, " a", 7, 9); 134 135 test_get_text_function(text_obj, atk_text_get_text_after_offset, ATK_TEXT_BOUNDARY_WORD_END, 136 4, " a", 7, 9); 137 138 test_get_text_function(text_obj, atk_text_get_text_at_offset, ATK_TEXT_BOUNDARY_WORD_END, 139 58, " third", 57, 63); 140 141 /* ATK_TEXT_BOUNDARY_SENTENCE_START */ 142 test_get_text_function(text_obj, atk_text_get_text_at_offset, ATK_TEXT_BOUNDARY_SENTENCE_START, 143 0, "This is a test. ", 0, 16); 144 145 test_get_text_function(text_obj, atk_text_get_text_at_offset, ATK_TEXT_BOUNDARY_SENTENCE_START, 146 15, "This is a test. ", 0, 16); 147 148 test_get_text_function(text_obj, atk_text_get_text_after_offset, ATK_TEXT_BOUNDARY_SENTENCE_START, 149 0, "This is the second sentence. ", 16, 45); 150 151 test_get_text_function(text_obj, atk_text_get_text_after_offset, ATK_TEXT_BOUNDARY_SENTENCE_START, 152 15, "This is the second sentence. ", 16, 45); 153 154 test_get_text_function(text_obj, atk_text_get_text_before_offset, ATK_TEXT_BOUNDARY_SENTENCE_START, 155 16, "This is a test. ", 0, 16); 156 157 test_get_text_function(text_obj, atk_text_get_text_before_offset, ATK_TEXT_BOUNDARY_SENTENCE_START, 158 44, "This is a test. ", 0, 16); 159 160 test_get_text_function(text_obj, atk_text_get_text_before_offset, ATK_TEXT_BOUNDARY_SENTENCE_START, 161 15, "", 0, 0); 162 163 /* ATK_TEXT_BOUNDARY_SENTENCE_END */ 164 test_get_text_function(text_obj, atk_text_get_text_at_offset, ATK_TEXT_BOUNDARY_SENTENCE_END, 165 0, "This is a test.", 0, 15); 166 167 test_get_text_function(text_obj, atk_text_get_text_at_offset, ATK_TEXT_BOUNDARY_SENTENCE_END, 168 15, " This is the second sentence.", 15, 44); 169 170 test_get_text_function(text_obj, atk_text_get_text_at_offset, ATK_TEXT_BOUNDARY_SENTENCE_END, 171 16, " This is the second sentence.", 15, 44); 172 173 test_get_text_function(text_obj, atk_text_get_text_at_offset, ATK_TEXT_BOUNDARY_SENTENCE_END, 174 17, " This is the second sentence.", 15, 44); 175 176 test_get_text_function(text_obj, atk_text_get_text_after_offset, ATK_TEXT_BOUNDARY_SENTENCE_END, 177 0, " This is the second sentence.", 15, 44); 178 179 test_get_text_function(text_obj, atk_text_get_text_after_offset, ATK_TEXT_BOUNDARY_SENTENCE_END, 180 15, " And this the third.", 44, 64); 181 182 test_get_text_function(text_obj, atk_text_get_text_before_offset, ATK_TEXT_BOUNDARY_SENTENCE_END, 183 16, "This is a test.", 0, 15); 184 185 test_get_text_function(text_obj, atk_text_get_text_before_offset, ATK_TEXT_BOUNDARY_SENTENCE_END, 186 15, "This is a test.", 0, 15); 187 188 test_get_text_function(text_obj, atk_text_get_text_before_offset, ATK_TEXT_BOUNDARY_SENTENCE_END, 189 14, "", 0, 0); 190 191 test_get_text_function(text_obj, atk_text_get_text_before_offset, ATK_TEXT_BOUNDARY_SENTENCE_END, 192 44, " This is the second sentence.", 15, 44); 193 194 /* It's trick to test these properly right now, since our a11y 195 implementation splits different lines in different a11y 196 items */ 197 /* ATK_TEXT_BOUNDARY_LINE_START */ 198 test_get_text_function(text_obj, atk_text_get_text_at_offset, ATK_TEXT_BOUNDARY_LINE_START, 199 0, "This is a test. This is the second sentence. And this the third.", 0, 64); 200 201 /* ATK_TEXT_BOUNDARY_LINE_END */ 202 test_get_text_function(text_obj, atk_text_get_text_at_offset, ATK_TEXT_BOUNDARY_LINE_END, 203 0, "This is a test. This is the second sentence. And this the third.", 0, 64); 204 } 205 206 static void test_webkit_atk_get_text_at_offset_forms(void) 207 { 208 WebKitWebView* webView; 209 AtkObject* obj; 210 GMainLoop* loop; 211 AtkText* text_obj; 212 213 webView = WEBKIT_WEB_VIEW(webkit_web_view_new()); 214 g_object_ref_sink(webView); 215 GtkAllocation alloc = { 0, 0, 800, 600 }; 216 gtk_widget_size_allocate(GTK_WIDGET(webView), &alloc); 217 webkit_web_view_load_string(webView, contents, NULL, NULL, NULL); 218 loop = g_main_loop_new(NULL, TRUE); 219 220 g_timeout_add(100, (GSourceFunc)bail_out, loop); 221 g_main_loop_run(loop); 222 223 /* Get to the inner AtkText object */ 224 obj = gtk_widget_get_accessible(GTK_WIDGET(webView)); 225 g_assert(obj); 226 obj = atk_object_ref_accessible_child(obj, 0); 227 g_assert(obj); 228 229 text_obj = ATK_TEXT(obj); 230 g_assert(ATK_IS_TEXT(text_obj)); 231 232 run_get_text_tests(text_obj); 233 234 g_object_unref(webView); 235 } 236 237 static void test_webkit_atk_get_text_at_offset(void) 238 { 239 WebKitWebView* webView; 240 AtkObject* obj; 241 GMainLoop* loop; 242 AtkText* text_obj; 243 244 webView = WEBKIT_WEB_VIEW(webkit_web_view_new()); 245 g_object_ref_sink(webView); 246 GtkAllocation alloc = { 0, 0, 800, 600 }; 247 gtk_widget_size_allocate(GTK_WIDGET(webView), &alloc); 248 webkit_web_view_load_string(webView, contents, NULL, NULL, NULL); 249 loop = g_main_loop_new(NULL, TRUE); 250 251 g_timeout_add(100, (GSourceFunc)bail_out, loop); 252 g_main_loop_run(loop); 253 254 /* Get to the inner AtkText object */ 255 obj = gtk_widget_get_accessible(GTK_WIDGET(webView)); 256 g_assert(obj); 257 obj = atk_object_ref_accessible_child(obj, 0); 258 g_assert(obj); 259 260 text_obj = ATK_TEXT(obj); 261 g_assert(ATK_IS_TEXT(text_obj)); 262 263 run_get_text_tests(text_obj); 264 265 g_object_unref(webView); 266 } 267 268 static void test_webkit_atk_get_text_at_offset_newlines(void) 269 { 270 WebKitWebView* webView; 271 AtkObject* obj; 272 GMainLoop* loop; 273 AtkText* text_obj; 274 275 webView = WEBKIT_WEB_VIEW(webkit_web_view_new()); 276 g_object_ref_sink(webView); 277 GtkAllocation alloc = { 0, 0, 800, 600 }; 278 gtk_widget_size_allocate(GTK_WIDGET(webView), &alloc); 279 webkit_web_view_load_string(webView, contentsWithNewlines, NULL, NULL, NULL); 280 loop = g_main_loop_new(NULL, TRUE); 281 282 g_timeout_add(100, (GSourceFunc)bail_out, loop); 283 g_main_loop_run(loop); 284 285 /* Get to the inner AtkText object */ 286 obj = gtk_widget_get_accessible(GTK_WIDGET(webView)); 287 g_assert(obj); 288 obj = atk_object_ref_accessible_child(obj, 0); 289 g_assert(obj); 290 291 text_obj = ATK_TEXT(obj); 292 g_assert(ATK_IS_TEXT(text_obj)); 293 294 run_get_text_tests(text_obj); 295 296 g_object_unref(webView); 297 } 298 299 static void test_webkit_atk_get_text_at_offset_textarea(void) 300 { 301 WebKitWebView* webView; 302 AtkObject* obj; 303 GMainLoop* loop; 304 AtkText* text_obj; 305 306 webView = WEBKIT_WEB_VIEW(webkit_web_view_new()); 307 g_object_ref_sink(webView); 308 GtkAllocation alloc = { 0, 0, 800, 600 }; 309 gtk_widget_size_allocate(GTK_WIDGET(webView), &alloc); 310 webkit_web_view_load_string(webView, contentsInTextarea, NULL, NULL, NULL); 311 loop = g_main_loop_new(NULL, TRUE); 312 313 g_timeout_add(100, (GSourceFunc)bail_out, loop); 314 g_main_loop_run(loop); 315 316 /* Get to the inner AtkText object */ 317 obj = gtk_widget_get_accessible(GTK_WIDGET(webView)); 318 g_assert(obj); 319 obj = atk_object_ref_accessible_child(obj, 0); 320 g_assert(obj); 321 obj = atk_object_ref_accessible_child(obj, 0); 322 g_assert(obj); 323 324 text_obj = ATK_TEXT(obj); 325 g_assert(ATK_IS_TEXT(text_obj)); 326 327 run_get_text_tests(text_obj); 328 329 g_object_unref(webView); 330 } 331 332 static void test_webkit_atk_get_text_at_offset_text_input(void) 333 { 334 WebKitWebView* webView; 335 AtkObject* obj; 336 GMainLoop* loop; 337 AtkText* text_obj; 338 339 webView = WEBKIT_WEB_VIEW(webkit_web_view_new()); 340 g_object_ref_sink(webView); 341 GtkAllocation alloc = { 0, 0, 800, 600 }; 342 gtk_widget_size_allocate(GTK_WIDGET(webView), &alloc); 343 webkit_web_view_load_string(webView, contentsInTextInput, NULL, NULL, NULL); 344 loop = g_main_loop_new(NULL, TRUE); 345 346 g_timeout_add(100, (GSourceFunc)bail_out, loop); 347 g_main_loop_run(loop); 348 349 /* Get to the inner AtkText object */ 350 obj = gtk_widget_get_accessible(GTK_WIDGET(webView)); 351 g_assert(obj); 352 obj = atk_object_ref_accessible_child(obj, 0); 353 g_assert(obj); 354 obj = atk_object_ref_accessible_child(obj, 0); 355 g_assert(obj); 356 357 text_obj = ATK_TEXT(obj); 358 g_assert(ATK_IS_TEXT(text_obj)); 359 360 run_get_text_tests(text_obj); 361 362 g_object_unref(webView); 363 } 364 365 static void testWebkitAtkGetTextInParagraphAndBodySimple(void) 366 { 367 WebKitWebView* webView; 368 AtkObject* obj; 369 AtkObject* obj1; 370 AtkObject* obj2; 371 GMainLoop* loop; 372 AtkText* textObj1; 373 AtkText* textObj2; 374 375 webView = WEBKIT_WEB_VIEW(webkit_web_view_new()); 376 g_object_ref_sink(webView); 377 GtkAllocation alloc = { 0, 0, 800, 600 }; 378 gtk_widget_size_allocate(GTK_WIDGET(webView), &alloc); 379 webkit_web_view_load_string(webView, contentsInParagraphAndBodySimple, NULL, NULL, NULL); 380 loop = g_main_loop_new(NULL, TRUE); 381 382 g_timeout_add(100, (GSourceFunc)bail_out, loop); 383 g_main_loop_run(loop); 384 385 /* Get to the inner AtkText object */ 386 obj = gtk_widget_get_accessible(GTK_WIDGET(webView)); 387 g_assert(obj); 388 obj1 = atk_object_ref_accessible_child(obj, 0); 389 g_assert(obj1); 390 obj2 = atk_object_ref_accessible_child(obj, 1); 391 g_assert(obj2); 392 393 textObj1 = ATK_TEXT(obj1); 394 g_assert(ATK_IS_TEXT(textObj1)); 395 textObj2 = ATK_TEXT(obj2); 396 g_assert(ATK_IS_TEXT(textObj2)); 397 398 char *text = atk_text_get_text(textObj1, 0, -1); 399 g_assert_cmpstr(text, ==, "This is a test."); 400 401 text = atk_text_get_text(textObj2, 0, 12); 402 g_assert_cmpstr(text, ==, "Hello world."); 403 404 g_object_unref(obj1); 405 g_object_unref(obj2); 406 g_object_unref(webView); 407 } 408 409 static void testWebkitAtkGetTextInParagraphAndBodyModerate(void) 410 { 411 WebKitWebView* webView; 412 AtkObject* obj; 413 AtkObject* obj1; 414 AtkObject* obj2; 415 GMainLoop* loop; 416 AtkText* textObj1; 417 AtkText* textObj2; 418 419 webView = WEBKIT_WEB_VIEW(webkit_web_view_new()); 420 g_object_ref_sink(webView); 421 GtkAllocation alloc = { 0, 0, 800, 600 }; 422 gtk_widget_size_allocate(GTK_WIDGET(webView), &alloc); 423 webkit_web_view_load_string(webView, contentsInParagraphAndBodyModerate, NULL, NULL, NULL); 424 loop = g_main_loop_new(NULL, TRUE); 425 426 g_timeout_add(100, (GSourceFunc)bail_out, loop); 427 g_main_loop_run(loop); 428 429 /* Get to the inner AtkText object */ 430 obj = gtk_widget_get_accessible(GTK_WIDGET(webView)); 431 g_assert(obj); 432 obj1 = atk_object_ref_accessible_child(obj, 0); 433 g_assert(obj1); 434 obj2 = atk_object_ref_accessible_child(obj, 1); 435 g_assert(obj2); 436 437 textObj1 = ATK_TEXT(obj1); 438 g_assert(ATK_IS_TEXT(textObj1)); 439 textObj2 = ATK_TEXT(obj2); 440 g_assert(ATK_IS_TEXT(textObj2)); 441 442 char *text = atk_text_get_text(textObj1, 0, -1); 443 g_assert_cmpstr(text, ==, "This is a test."); 444 445 text = atk_text_get_text(textObj2, 0, 53); 446 g_assert_cmpstr(text, ==, "Hello world.\nThis sentence is green.\nThis one is not."); 447 448 g_object_unref(obj1); 449 g_object_unref(obj2); 450 g_object_unref(webView); 451 } 452 453 int main(int argc, char** argv) 454 { 455 g_thread_init(NULL); 456 gtk_test_init(&argc, &argv, NULL); 457 458 g_test_bug_base("https://bugs.webkit.org/"); 459 g_test_add_func("/webkit/atk/get_text_at_offset", test_webkit_atk_get_text_at_offset); 460 g_test_add_func("/webkit/atk/get_text_at_offset_forms", test_webkit_atk_get_text_at_offset_forms); 461 g_test_add_func("/webkit/atk/get_text_at_offset_newlines", test_webkit_atk_get_text_at_offset_newlines); 462 g_test_add_func("/webkit/atk/get_text_at_offset_textarea", test_webkit_atk_get_text_at_offset_textarea); 463 g_test_add_func("/webkit/atk/get_text_at_offset_text_input", test_webkit_atk_get_text_at_offset_text_input); 464 g_test_add_func("/webkit/atk/getTextInParagraphAndBodySimple", testWebkitAtkGetTextInParagraphAndBodySimple); 465 g_test_add_func("/webkit/atk/getTextInParagraphAndBodyModerate", testWebkitAtkGetTextInParagraphAndBodyModerate); 466 return g_test_run (); 467 } 468 469 #else 470 int main(int argc, char** argv) 471 { 472 g_critical("You will need at least glib-2.16.0 and gtk-2.14.0 to run the unit tests. Doing nothing now."); 473 return 0; 474 } 475 476 #endif 477