1 /* 2 * Copyright (C) 2008 Holger Hans Peter Freyther 3 * Copyright (C) 2009, 2010 Collabora Ltd. 4 * 5 * This library is free software; you can redistribute it and/or 6 * modify it under the terms of the GNU Library General Public 7 * License as published by the Free Software Foundation; either 8 * version 2 of the License, or (at your option) any later version. 9 * 10 * This library is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 * Library General Public License for more details. 14 * 15 * You should have received a copy of the GNU Library General Public License 16 * along with this library; see the file COPYING.LIB. If not, write to 17 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 18 * Boston, MA 02110-1301, USA. 19 */ 20 21 #include "test_utils.h" 22 23 #include <errno.h> 24 #include <unistd.h> 25 #include <string.h> 26 27 #include <glib.h> 28 #include <glib/gstdio.h> 29 #include <gtk/gtk.h> 30 #include <webkit/webkit.h> 31 32 #if GTK_CHECK_VERSION(2, 14, 0) 33 34 GMainLoop* loop; 35 SoupSession *session; 36 char* base_uri; 37 38 /* For real request testing */ 39 static void 40 server_callback(SoupServer* server, SoupMessage* msg, 41 const char* path, GHashTable* query, 42 SoupClientContext* context, gpointer data) 43 { 44 if (msg->method != SOUP_METHOD_GET) { 45 soup_message_set_status(msg, SOUP_STATUS_NOT_IMPLEMENTED); 46 return; 47 } 48 49 soup_message_set_status(msg, SOUP_STATUS_OK); 50 51 if (g_str_equal(path, "/favicon.ico")) { 52 char* contents; 53 gsize length; 54 GError* error = NULL; 55 56 g_file_get_contents("blank.ico", &contents, &length, &error); 57 g_assert(!error); 58 59 soup_message_body_append(msg->response_body, SOUP_MEMORY_TAKE, contents, length); 60 } else if (g_str_equal(path, "/bigdiv.html")) { 61 char* contents = g_strdup("<html><body><a id=\"link\" href=\"http://abc.def\">test</a><div style=\"background-color: green; height: 1200px;\"></div></body></html>"); 62 soup_message_body_append(msg->response_body, SOUP_MEMORY_TAKE, contents, strlen(contents)); 63 } else if (g_str_equal(path, "/iframe.html")) { 64 char* contents = g_strdup("<html><body id=\"some-content\"><div style=\"background-color: green; height: 50px;\"></div><iframe src=\"bigdiv.html\"></iframe></body></html>"); 65 soup_message_body_append(msg->response_body, SOUP_MEMORY_TAKE, contents, strlen(contents)); 66 } else { 67 char* contents = g_strdup("<html><body>test</body></html>"); 68 soup_message_body_append(msg->response_body, SOUP_MEMORY_TAKE, contents, strlen(contents)); 69 } 70 71 soup_message_body_complete(msg->response_body); 72 } 73 74 static void idle_quit_loop_cb(WebKitWebView* web_view, GParamSpec* pspec, gpointer data) 75 { 76 if (webkit_web_view_get_load_status(web_view) == WEBKIT_LOAD_FINISHED || 77 webkit_web_view_get_load_status(web_view) == WEBKIT_LOAD_FAILED) 78 g_main_loop_quit(loop); 79 } 80 81 static void icon_uri_changed_cb(WebKitWebView* web_view, GParamSpec* pspec, gpointer data) 82 { 83 gboolean* been_here = (gboolean*)data; 84 char* expected_uri; 85 86 g_assert_cmpstr(g_param_spec_get_name(pspec), ==, "icon-uri"); 87 88 expected_uri = g_strdup_printf("%sfavicon.ico", base_uri); 89 g_assert_cmpstr(webkit_web_view_get_icon_uri(web_view), ==, expected_uri); 90 g_free(expected_uri); 91 92 *been_here = TRUE; 93 } 94 95 static void icon_loaded_cb(WebKitWebView* web_view, char* icon_uri, gpointer data) 96 { 97 gboolean* been_here = (gboolean*)data; 98 char* expected_uri = g_strdup_printf("%sfavicon.ico", base_uri); 99 g_assert_cmpstr(icon_uri, ==, expected_uri); 100 g_free(expected_uri); 101 102 g_assert_cmpstr(icon_uri, ==, webkit_web_view_get_icon_uri(web_view)); 103 104 *been_here = TRUE; 105 } 106 107 static void test_webkit_web_view_icon_uri() 108 { 109 gboolean been_to_uri_changed = FALSE; 110 gboolean been_to_icon_loaded = FALSE; 111 WebKitWebView* view = WEBKIT_WEB_VIEW(webkit_web_view_new()); 112 g_object_ref_sink(G_OBJECT(view)); 113 114 loop = g_main_loop_new(NULL, TRUE); 115 116 g_object_connect(G_OBJECT(view), 117 "signal::notify::progress", idle_quit_loop_cb, NULL, 118 "signal::notify::icon-uri", icon_uri_changed_cb, &been_to_uri_changed, 119 "signal::icon-loaded", icon_loaded_cb, &been_to_icon_loaded, 120 NULL); 121 122 webkit_web_view_load_uri(view, base_uri); 123 124 g_main_loop_run(loop); 125 126 g_assert(been_to_uri_changed); 127 g_assert(been_to_icon_loaded); 128 129 g_object_unref(view); 130 } 131 132 static gboolean map_event_cb(GtkWidget *widget, GdkEvent* event, gpointer data) 133 { 134 GMainLoop* loop = (GMainLoop*)data; 135 g_main_loop_quit(loop); 136 137 return FALSE; 138 } 139 140 static void test_webkit_web_view_grab_focus() 141 { 142 char* uri = g_strconcat(base_uri, "iframe.html", NULL); 143 GtkWidget* window = gtk_window_new(GTK_WINDOW_POPUP); 144 GtkWidget* scrolled_window = gtk_scrolled_window_new(NULL, NULL); 145 WebKitWebView* view = WEBKIT_WEB_VIEW(webkit_web_view_new()); 146 GtkAdjustment* adjustment; 147 148 gtk_window_set_default_size(GTK_WINDOW(window), 400, 200); 149 150 gtk_container_add(GTK_CONTAINER(window), scrolled_window); 151 gtk_container_add(GTK_CONTAINER(scrolled_window), GTK_WIDGET(view)); 152 153 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled_window), 154 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); 155 156 loop = g_main_loop_new(NULL, TRUE); 157 158 g_signal_connect(view, "notify::progress", G_CALLBACK (idle_quit_loop_cb), NULL); 159 160 /* Wait for window to show up */ 161 gtk_widget_show_all(window); 162 g_signal_connect(window, "map-event", 163 G_CALLBACK(map_event_cb), loop); 164 g_main_loop_run(loop); 165 166 /* Load a page with a big div that will cause scrollbars to appear */ 167 webkit_web_view_load_uri(view, uri); 168 g_main_loop_run(loop); 169 170 adjustment = gtk_scrolled_window_get_vadjustment(GTK_SCROLLED_WINDOW(scrolled_window)); 171 g_assert_cmpfloat(gtk_adjustment_get_value(adjustment), ==, 0.0); 172 173 /* Since webkit_web_view_execute_script does not return a value, 174 it is impossible to know if an inner document has focus after 175 a node of it was focused via .focus() method. 176 The code below is an workaround: if the node has focus, a scroll 177 action is performed and afterward it is checked if the adjustment 178 has to be different from 0. 179 */ 180 char script[] = "var innerDoc = document.defaultView.frames[0].document; \ 181 innerDoc.getElementById(\"link\").focus(); \ 182 if (innerDoc.hasFocus()) \ 183 window.scrollBy(0, 100);"; 184 185 /* Focus an element using JavaScript */ 186 webkit_web_view_execute_script(view, script); 187 188 /* Make sure the ScrolledWindow noticed the scroll */ 189 g_assert_cmpfloat(gtk_adjustment_get_value(adjustment), !=, 0.0); 190 191 g_free(uri); 192 gtk_widget_destroy(window); 193 } 194 195 static void do_test_webkit_web_view_adjustments(gboolean with_page_cache) 196 { 197 char* effective_uri = g_strconcat(base_uri, "bigdiv.html", NULL); 198 char* second_uri = g_strconcat(base_uri, "iframe.html", NULL); 199 GtkWidget* window = gtk_window_new(GTK_WINDOW_TOPLEVEL); 200 GtkWidget* scrolled_window = gtk_scrolled_window_new(NULL, NULL); 201 WebKitWebView* view = WEBKIT_WEB_VIEW(webkit_web_view_new()); 202 GtkAdjustment* adjustment; 203 double lower; 204 double upper; 205 206 if (with_page_cache) { 207 WebKitWebSettings* settings = webkit_web_view_get_settings(view); 208 g_object_set(settings, "enable-page-cache", TRUE, NULL); 209 } 210 211 gtk_window_set_default_size(GTK_WINDOW(window), 400, 200); 212 213 gtk_container_add(GTK_CONTAINER(window), scrolled_window); 214 gtk_container_add(GTK_CONTAINER(scrolled_window), GTK_WIDGET(view)); 215 216 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled_window), 217 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); 218 219 loop = g_main_loop_new(NULL, TRUE); 220 221 g_object_connect(G_OBJECT(view), 222 "signal::notify::progress", idle_quit_loop_cb, NULL, 223 NULL); 224 225 /* Wait for window to show up */ 226 gtk_widget_show_all(window); 227 g_signal_connect(window, "map-event", 228 G_CALLBACK(map_event_cb), loop); 229 g_main_loop_run(loop); 230 231 /* Load a page with a big div that will cause scrollbars to appear */ 232 webkit_web_view_load_uri(view, effective_uri); 233 g_main_loop_run(loop); 234 235 adjustment = gtk_scrolled_window_get_vadjustment(GTK_SCROLLED_WINDOW(scrolled_window)); 236 g_assert_cmpfloat(gtk_adjustment_get_value(adjustment), ==, 0.0); 237 238 lower = gtk_adjustment_get_lower(adjustment); 239 upper = gtk_adjustment_get_upper(adjustment); 240 241 /* Scroll the view using JavaScript */ 242 webkit_web_view_execute_script(view, "window.scrollBy(0, 100)"); 243 244 /* Make sure the ScrolledWindow noticed the scroll */ 245 g_assert_cmpfloat(gtk_adjustment_get_value(adjustment), ==, 100.0); 246 247 /* Load a second URI */ 248 webkit_web_view_load_uri(view, second_uri); 249 g_main_loop_run(loop); 250 251 /* Make sure the scrollbar has been reset */ 252 g_assert_cmpfloat(gtk_adjustment_get_value(adjustment), ==, 0.0); 253 254 /* Go back */ 255 webkit_web_view_go_back(view); 256 257 /* When using page cache, go_back will return syncronously */ 258 if (!with_page_cache) 259 g_main_loop_run(loop); 260 261 /* Make sure GTK+ has time to process the changes in size, for the adjusments */ 262 while (gtk_events_pending()) 263 gtk_main_iteration(); 264 265 /* Make sure upper and lower bounds have been restored correctly */ 266 g_assert_cmpfloat(lower, ==, gtk_adjustment_get_lower(adjustment)); 267 g_assert_cmpfloat(upper, ==, gtk_adjustment_get_upper(adjustment)); 268 269 /* This assert is temporarily disabled until we fix the following bug: */ 270 /* https://bugs.webkit.org/show_bug.cgi?id=57315 */ 271 /* It should be re-enabled ASAP. */ 272 /* g_assert_cmpfloat(gtk_adjustment_get_value(adjustment), ==, 100.0); */ 273 274 g_free(effective_uri); 275 g_free(second_uri); 276 277 gtk_widget_destroy(window); 278 } 279 280 static void test_webkit_web_view_adjustments() 281 { 282 /* Test this with page cache disabled, and enabled. */ 283 do_test_webkit_web_view_adjustments(FALSE); 284 do_test_webkit_web_view_adjustments(TRUE); 285 } 286 287 gboolean delayed_destroy(gpointer data) 288 { 289 gtk_widget_destroy(GTK_WIDGET(data)); 290 g_main_loop_quit(loop); 291 return FALSE; 292 } 293 294 static void test_webkit_web_view_destroy() 295 { 296 GtkWidget* window; 297 GtkWidget* web_view; 298 299 window = gtk_window_new(GTK_WINDOW_TOPLEVEL); 300 web_view = webkit_web_view_new(); 301 302 gtk_container_add(GTK_CONTAINER(window), web_view); 303 304 gtk_widget_show_all(window); 305 306 loop = g_main_loop_new(NULL, TRUE); 307 308 g_signal_connect(window, "map-event", 309 G_CALLBACK(map_event_cb), loop); 310 g_main_loop_run(loop); 311 312 g_idle_add(delayed_destroy, web_view); 313 g_main_loop_run(loop); 314 315 gtk_widget_destroy(window); 316 } 317 318 static void test_webkit_web_view_window_features() 319 { 320 GtkWidget* window; 321 GtkWidget* web_view; 322 323 window = gtk_window_new(GTK_WINDOW_TOPLEVEL); 324 web_view = webkit_web_view_new(); 325 326 gtk_container_add(GTK_CONTAINER(window), web_view); 327 328 gtk_widget_show_all(window); 329 330 loop = g_main_loop_new(NULL, TRUE); 331 332 g_signal_connect(window, "map-event", 333 G_CALLBACK(map_event_cb), loop); 334 g_main_loop_run(loop); 335 336 /* Bug #36144 */ 337 g_object_set(G_OBJECT(web_view), "window-features", NULL, NULL); 338 339 gtk_widget_destroy(window); 340 } 341 342 int main(int argc, char** argv) 343 { 344 SoupServer* server; 345 SoupURI* soup_uri; 346 347 g_thread_init(NULL); 348 gtk_test_init(&argc, &argv, NULL); 349 350 /* Hopefully make test independent of the path it's called from. */ 351 testutils_relative_chdir("Source/WebKit/gtk/tests/resources/test.html", argv[0]); 352 353 server = soup_server_new(SOUP_SERVER_PORT, 0, NULL); 354 soup_server_run_async(server); 355 356 soup_server_add_handler(server, NULL, server_callback, NULL, NULL); 357 358 soup_uri = soup_uri_new("http://127.0.0.1/"); 359 soup_uri_set_port(soup_uri, soup_server_get_port(server)); 360 361 base_uri = soup_uri_to_string(soup_uri, FALSE); 362 soup_uri_free(soup_uri); 363 364 g_test_bug_base("https://bugs.webkit.org/"); 365 g_test_add_func("/webkit/webview/icon-uri", test_webkit_web_view_icon_uri); 366 g_test_add_func("/webkit/webview/adjustments", test_webkit_web_view_adjustments); 367 g_test_add_func("/webkit/webview/destroy", test_webkit_web_view_destroy); 368 g_test_add_func("/webkit/webview/grab_focus", test_webkit_web_view_grab_focus); 369 g_test_add_func("/webkit/webview/window-features", test_webkit_web_view_window_features); 370 371 return g_test_run (); 372 } 373 374 #else 375 int main(int argc, char** argv) 376 { 377 g_critical("You will need gtk-2.14.0 to run the unit tests. Doing nothing now."); 378 return 0; 379 } 380 381 #endif 382