6ed4a38e30115abd106b5bcebdf583aca2948bfd
[WebKit-https.git] / Source / WebKit2 / UIProcess / API / gtk / tests / TestWebKitWebView.cpp
1 /*
2  * Copyright (C) 2011 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 Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2,1 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 "config.h"
21 #include "WebViewTest.h"
22 #include <JavaScriptCore/JSStringRef.h>
23 #include <JavaScriptCore/JSValueRef.h>
24 #include <glib/gstdio.h>
25 #include <wtf/HashSet.h>
26 #include <wtf/gobject/GRefPtr.h>
27 #include <wtf/text/StringHash.h>
28
29 static void testWebViewDefaultContext(WebViewTest* test, gconstpointer)
30 {
31     g_assert(webkit_web_view_get_context(test->m_webView) == webkit_web_context_get_default());
32
33     // Check that a web view created with g_object_new has the default context.
34     GRefPtr<WebKitWebView> webView = WEBKIT_WEB_VIEW(g_object_new(WEBKIT_TYPE_WEB_VIEW, NULL));
35     g_assert(webkit_web_view_get_context(webView.get()) == webkit_web_context_get_default());
36 }
37
38 static void testWebViewCustomCharset(WebViewTest* test, gconstpointer)
39 {
40     g_assert(!webkit_web_view_get_custom_charset(test->m_webView));
41     webkit_web_view_set_custom_charset(test->m_webView, "utf8");
42     g_assert_cmpstr(webkit_web_view_get_custom_charset(test->m_webView), ==, "utf8");
43     // Go back to the default charset.
44     webkit_web_view_set_custom_charset(test->m_webView, 0);
45     g_assert(!webkit_web_view_get_custom_charset(test->m_webView));
46 }
47
48 static void testWebViewSettings(WebViewTest* test, gconstpointer)
49 {
50     WebKitSettings* defaultSettings = webkit_web_view_get_settings(test->m_webView);
51     test->assertObjectIsDeletedWhenTestFinishes(G_OBJECT(defaultSettings));
52     g_assert(defaultSettings);
53     g_assert(webkit_settings_get_enable_javascript(defaultSettings));
54
55     GRefPtr<WebKitSettings> newSettings = adoptGRef(webkit_settings_new());
56     test->assertObjectIsDeletedWhenTestFinishes(G_OBJECT(newSettings.get()));
57     g_object_set(G_OBJECT(newSettings.get()), "enable-javascript", FALSE, NULL);
58     webkit_web_view_set_settings(test->m_webView, newSettings.get());
59
60     WebKitSettings* settings = webkit_web_view_get_settings(test->m_webView);
61     g_assert(settings != defaultSettings);
62     g_assert(!webkit_settings_get_enable_javascript(settings));
63
64     GRefPtr<GtkWidget> webView2 = webkit_web_view_new();
65     test->assertObjectIsDeletedWhenTestFinishes(G_OBJECT(webView2.get()));
66     webkit_web_view_set_settings(WEBKIT_WEB_VIEW(webView2.get()), settings);
67     g_assert(webkit_web_view_get_settings(WEBKIT_WEB_VIEW(webView2.get())) == settings);
68
69     GRefPtr<WebKitSettings> newSettings2 = adoptGRef(webkit_settings_new());
70     test->assertObjectIsDeletedWhenTestFinishes(G_OBJECT(newSettings2.get()));
71     webkit_web_view_set_settings(WEBKIT_WEB_VIEW(webView2.get()), newSettings2.get());
72     settings = webkit_web_view_get_settings(WEBKIT_WEB_VIEW(webView2.get()));
73     g_assert(settings == newSettings2.get());
74     g_assert(webkit_settings_get_enable_javascript(settings));
75 }
76
77 static const char* kAlertDialogMessage = "WebKitGTK+ alert dialog message";
78 static const char* kConfirmDialogMessage = "WebKitGTK+ confirm dialog message";
79 static const char* kPromptDialogMessage = "WebKitGTK+ prompt dialog message";
80 static const char* kPromptDialogReturnedText = "WebKitGTK+ prompt dialog returned text";
81
82 class UIClientTest: public WebViewTest {
83 public:
84     MAKE_GLIB_TEST_FIXTURE(UIClientTest);
85
86     enum WebViewEvents {
87         Create,
88         ReadyToShow,
89         RunAsModal,
90         Close
91     };
92
93     class WindowProperties {
94     public:
95         WindowProperties()
96             : m_isNull(true)
97             , m_toolbarVisible(true)
98             , m_statusbarVisible(true)
99             , m_scrollbarsVisible(true)
100             , m_menubarVisible(true)
101             , m_locationbarVisible(true)
102             , m_resizable(true)
103             , m_fullscreen(false)
104         {
105             memset(&m_geometry, 0, sizeof(GdkRectangle));
106         }
107
108         WindowProperties(WebKitWindowProperties* windowProperties)
109             : m_isNull(false)
110             , m_toolbarVisible(webkit_window_properties_get_toolbar_visible(windowProperties))
111             , m_statusbarVisible(webkit_window_properties_get_statusbar_visible(windowProperties))
112             , m_scrollbarsVisible(webkit_window_properties_get_scrollbars_visible(windowProperties))
113             , m_menubarVisible(webkit_window_properties_get_menubar_visible(windowProperties))
114             , m_locationbarVisible(webkit_window_properties_get_locationbar_visible(windowProperties))
115             , m_resizable(webkit_window_properties_get_resizable(windowProperties))
116             , m_fullscreen(webkit_window_properties_get_fullscreen(windowProperties))
117         {
118             webkit_window_properties_get_geometry(windowProperties, &m_geometry);
119         }
120
121         WindowProperties(GdkRectangle* geometry, bool toolbarVisible, bool statusbarVisible, bool scrollbarsVisible, bool menubarVisible,
122                          bool locationbarVisible, bool resizable, bool fullscreen)
123             : m_isNull(false)
124             , m_geometry(*geometry)
125             , m_toolbarVisible(toolbarVisible)
126             , m_statusbarVisible(statusbarVisible)
127             , m_scrollbarsVisible(scrollbarsVisible)
128             , m_menubarVisible(menubarVisible)
129             , m_locationbarVisible(locationbarVisible)
130             , m_resizable(resizable)
131             , m_fullscreen(fullscreen)
132         {
133         }
134
135         bool isNull() const { return m_isNull; }
136
137         void assertEqual(const WindowProperties& other) const
138         {
139             g_assert_cmpint(m_geometry.x, ==, other.m_geometry.x);
140             g_assert_cmpint(m_geometry.y, ==, other.m_geometry.y);
141             g_assert_cmpint(m_geometry.width, ==, other.m_geometry.width);
142             g_assert_cmpint(m_geometry.height, ==, other.m_geometry.height);
143             g_assert_cmpint(static_cast<int>(m_toolbarVisible), ==, static_cast<int>(other.m_toolbarVisible));
144             g_assert_cmpint(static_cast<int>(m_statusbarVisible), ==, static_cast<int>(other.m_statusbarVisible));
145             g_assert_cmpint(static_cast<int>(m_scrollbarsVisible), ==, static_cast<int>(other.m_scrollbarsVisible));
146             g_assert_cmpint(static_cast<int>(m_menubarVisible), ==, static_cast<int>(other.m_menubarVisible));
147             g_assert_cmpint(static_cast<int>(m_locationbarVisible), ==, static_cast<int>(other.m_locationbarVisible));
148             g_assert_cmpint(static_cast<int>(m_resizable), ==, static_cast<int>(other.m_resizable));
149             g_assert_cmpint(static_cast<int>(m_fullscreen), ==, static_cast<int>(other.m_fullscreen));
150         }
151
152     private:
153         bool m_isNull;
154
155         GdkRectangle m_geometry;
156
157         bool m_toolbarVisible;
158         bool m_statusbarVisible;
159         bool m_scrollbarsVisible;
160         bool m_menubarVisible;
161         bool m_locationbarVisible;
162
163         bool m_resizable;
164         bool m_fullscreen;
165     };
166
167     static void windowPropertiesNotifyCallback(GObject*, GParamSpec* paramSpec, UIClientTest* test)
168     {
169         test->m_windowPropertiesChanged.add(g_param_spec_get_name(paramSpec));
170     }
171
172     static GtkWidget* viewCreateCallback(WebKitWebView* webView, UIClientTest* test)
173     {
174         return test->viewCreate(webView);
175     }
176
177     static void viewReadyToShowCallback(WebKitWebView* webView, UIClientTest* test)
178     {
179         test->viewReadyToShow(webView);
180     }
181
182     static void viewCloseCallback(WebKitWebView* webView, UIClientTest* test)
183     {
184         test->viewClose(webView);
185     }
186
187     void scriptAlert(WebKitScriptDialog* dialog)
188     {
189         switch (m_scriptDialogType) {
190         case WEBKIT_SCRIPT_DIALOG_ALERT:
191             g_assert_cmpstr(webkit_script_dialog_get_message(dialog), ==, kAlertDialogMessage);
192             break;
193         case WEBKIT_SCRIPT_DIALOG_CONFIRM:
194             g_assert(m_scriptDialogConfirmed);
195             g_assert_cmpstr(webkit_script_dialog_get_message(dialog), ==, "confirmed");
196
197             break;
198         case WEBKIT_SCRIPT_DIALOG_PROMPT:
199             g_assert_cmpstr(webkit_script_dialog_get_message(dialog), ==, kPromptDialogReturnedText);
200             break;
201         }
202
203         g_main_loop_quit(m_mainLoop);
204     }
205
206     void scriptConfirm(WebKitScriptDialog* dialog)
207     {
208         g_assert_cmpstr(webkit_script_dialog_get_message(dialog), ==, kConfirmDialogMessage);
209         m_scriptDialogConfirmed = !m_scriptDialogConfirmed;
210         webkit_script_dialog_confirm_set_confirmed(dialog, m_scriptDialogConfirmed);
211     }
212
213     void scriptPrompt(WebKitScriptDialog* dialog)
214     {
215         g_assert_cmpstr(webkit_script_dialog_get_message(dialog), ==, kPromptDialogMessage);
216         g_assert_cmpstr(webkit_script_dialog_prompt_get_default_text(dialog), ==, "default");
217         webkit_script_dialog_prompt_set_text(dialog, kPromptDialogReturnedText);
218     }
219
220     static gboolean scriptDialog(WebKitWebView*, WebKitScriptDialog* dialog, UIClientTest* test)
221     {
222         switch (webkit_script_dialog_get_dialog_type(dialog)) {
223         case WEBKIT_SCRIPT_DIALOG_ALERT:
224             test->scriptAlert(dialog);
225             break;
226         case WEBKIT_SCRIPT_DIALOG_CONFIRM:
227             test->scriptConfirm(dialog);
228             break;
229         case WEBKIT_SCRIPT_DIALOG_PROMPT:
230             test->scriptPrompt(dialog);
231             break;
232         }
233
234         return TRUE;
235     }
236
237     static void mouseTargetChanged(WebKitWebView*, WebKitHitTestResult* hitTestResult, guint modifiers, UIClientTest* test)
238     {
239         g_assert(WEBKIT_IS_HIT_TEST_RESULT(hitTestResult));
240         test->assertObjectIsDeletedWhenTestFinishes(G_OBJECT(hitTestResult));
241
242         test->m_mouseTargetHitTestResult = hitTestResult;
243         test->m_mouseTargetModifiers = modifiers;
244         g_main_loop_quit(test->m_mainLoop);
245     }
246
247     static gboolean permissionRequested(WebKitWebView*, WebKitPermissionRequest* request, UIClientTest* test)
248     {
249         g_assert(WEBKIT_IS_PERMISSION_REQUEST(request));
250         test->assertObjectIsDeletedWhenTestFinishes(G_OBJECT(request));
251
252         if (test->m_allowPermissionRequests)
253             webkit_permission_request_allow(request);
254         else
255             webkit_permission_request_deny(request);
256
257         return TRUE;
258     }
259
260     UIClientTest()
261         : m_scriptDialogType(WEBKIT_SCRIPT_DIALOG_ALERT)
262         , m_scriptDialogConfirmed(true)
263         , m_allowPermissionRequests(false)
264         , m_mouseTargetModifiers(0)
265     {
266         webkit_settings_set_javascript_can_open_windows_automatically(webkit_web_view_get_settings(m_webView), TRUE);
267         g_signal_connect(m_webView, "create", G_CALLBACK(viewCreateCallback), this);
268         g_signal_connect(m_webView, "script-dialog", G_CALLBACK(scriptDialog), this);
269         g_signal_connect(m_webView, "mouse-target-changed", G_CALLBACK(mouseTargetChanged), this);
270         g_signal_connect(m_webView, "permission-request", G_CALLBACK(permissionRequested), this);
271     }
272
273     ~UIClientTest()
274     {
275         g_signal_handlers_disconnect_matched(m_webView, G_SIGNAL_MATCH_DATA, 0, 0, 0, 0, this);
276     }
277
278     void waitUntilMainLoopFinishes()
279     {
280         g_main_loop_run(m_mainLoop);
281     }
282
283     void setExpectedWindowProperties(const WindowProperties& windowProperties)
284     {
285         m_windowProperties = windowProperties;
286     }
287
288     WebKitHitTestResult* moveMouseAndWaitUntilMouseTargetChanged(int x, int y, unsigned int mouseModifiers = 0)
289     {
290         mouseMoveTo(x, y, mouseModifiers);
291         g_main_loop_run(m_mainLoop);
292         return m_mouseTargetHitTestResult.get();
293     }
294
295     virtual GtkWidget* viewCreate(WebKitWebView* webView)
296     {
297         g_assert(webView == m_webView);
298
299         GtkWidget* newWebView = webkit_web_view_new_with_context(webkit_web_view_get_context(webView));
300         g_object_ref_sink(newWebView);
301
302         m_webViewEvents.append(Create);
303
304         WebKitWindowProperties* windowProperties = webkit_web_view_get_window_properties(WEBKIT_WEB_VIEW(newWebView));
305         g_assert(windowProperties);
306         assertObjectIsDeletedWhenTestFinishes(G_OBJECT(windowProperties));
307         m_windowPropertiesChanged.clear();
308
309         g_signal_connect(windowProperties, "notify", G_CALLBACK(windowPropertiesNotifyCallback), this);
310         g_signal_connect(newWebView, "ready-to-show", G_CALLBACK(viewReadyToShowCallback), this);
311         g_signal_connect(newWebView, "close", G_CALLBACK(viewCloseCallback), this);
312
313         return newWebView;
314     }
315
316     virtual void viewReadyToShow(WebKitWebView* webView)
317     {
318         g_assert(webView != m_webView);
319
320         WebKitWindowProperties* windowProperties = webkit_web_view_get_window_properties(webView);
321         g_assert(windowProperties);
322         if (!m_windowProperties.isNull())
323             WindowProperties(windowProperties).assertEqual(m_windowProperties);
324
325         m_webViewEvents.append(ReadyToShow);
326     }
327
328     virtual void viewClose(WebKitWebView* webView)
329     {
330         g_assert(webView != m_webView);
331
332         m_webViewEvents.append(Close);
333         g_object_unref(webView);
334
335         g_main_loop_quit(m_mainLoop);
336     }
337
338     Vector<WebViewEvents> m_webViewEvents;
339     WebKitScriptDialogType m_scriptDialogType;
340     bool m_scriptDialogConfirmed;
341     bool m_allowPermissionRequests;
342     WindowProperties m_windowProperties;
343     HashSet<WTF::String> m_windowPropertiesChanged;
344     GRefPtr<WebKitHitTestResult> m_mouseTargetHitTestResult;
345     unsigned int m_mouseTargetModifiers;
346 };
347
348 static void testWebViewCreateReadyClose(UIClientTest* test, gconstpointer)
349 {
350     test->loadHtml("<html><body onLoad=\"window.open().close();\"></html>", 0);
351     test->waitUntilMainLoopFinishes();
352
353     Vector<UIClientTest::WebViewEvents>& events = test->m_webViewEvents;
354     g_assert_cmpint(events.size(), ==, 3);
355     g_assert_cmpint(events[0], ==, UIClientTest::Create);
356     g_assert_cmpint(events[1], ==, UIClientTest::ReadyToShow);
357     g_assert_cmpint(events[2], ==, UIClientTest::Close);
358 }
359
360 static gboolean checkMimeTypeForFilter(GtkFileFilter* filter, const gchar* mimeType)
361 {
362     GtkFileFilterInfo filterInfo;
363     filterInfo.contains = GTK_FILE_FILTER_MIME_TYPE;
364     filterInfo.mime_type = mimeType;
365     return gtk_file_filter_filter(filter, &filterInfo);
366 }
367
368 class ModalDialogsTest: public UIClientTest {
369 public:
370     MAKE_GLIB_TEST_FIXTURE(ModalDialogsTest);
371
372     static void dialogRunAsModalCallback(WebKitWebView* webView, ModalDialogsTest* test)
373     {
374         g_assert(webView != test->m_webView);
375         test->m_webViewEvents.append(RunAsModal);
376     }
377
378     GtkWidget* viewCreate(WebKitWebView* webView)
379     {
380         g_assert(webView == m_webView);
381
382         GtkWidget* newWebView = UIClientTest::viewCreate(webView);
383         g_signal_connect(newWebView, "run-as-modal", G_CALLBACK(dialogRunAsModalCallback), this);
384         return newWebView;
385     }
386
387     void viewReadyToShow(WebKitWebView* webView)
388     {
389         g_assert(webView != m_webView);
390         m_webViewEvents.append(ReadyToShow);
391     }
392 };
393
394 static void testWebViewAllowModalDialogs(ModalDialogsTest* test, gconstpointer)
395 {
396     WebKitSettings* settings = webkit_web_view_get_settings(test->m_webView);
397     webkit_settings_set_allow_modal_dialogs(settings, TRUE);
398
399     test->loadHtml("<html><body onload=\"window.showModalDialog('data:text/html,<html><body/><script>window.close();</script></html>')\"></body></html>", 0);
400     test->waitUntilMainLoopFinishes();
401
402     Vector<UIClientTest::WebViewEvents>& events = test->m_webViewEvents;
403     g_assert_cmpint(events.size(), ==, 4);
404     g_assert_cmpint(events[0], ==, UIClientTest::Create);
405     g_assert_cmpint(events[1], ==, UIClientTest::ReadyToShow);
406     g_assert_cmpint(events[2], ==, UIClientTest::RunAsModal);
407     g_assert_cmpint(events[3], ==, UIClientTest::Close);
408 }
409
410 static void testWebViewDisallowModalDialogs(ModalDialogsTest* test, gconstpointer)
411 {
412     WebKitSettings* settings = webkit_web_view_get_settings(test->m_webView);
413     webkit_settings_set_allow_modal_dialogs(settings, FALSE);
414
415     test->loadHtml("<html><body onload=\"window.showModalDialog('data:text/html,<html><body/><script>window.close();</script></html>')\"></body></html>", 0);
416     // We need to use a timeout here because the viewClose() function
417     // won't ever be called as the dialog won't be created.
418     test->wait(1);
419
420     Vector<UIClientTest::WebViewEvents>& events = test->m_webViewEvents;
421     g_assert_cmpint(events.size(), ==, 0);
422 }
423
424 static void testWebViewJavaScriptDialogs(UIClientTest* test, gconstpointer)
425 {
426     static const char* htmlOnLoadFormat = "<html><body onLoad=\"%s\"></body></html>";
427     static const char* jsAlertFormat = "alert('%s')";
428     static const char* jsConfirmFormat = "do { confirmed = confirm('%s'); } while (!confirmed); alert('confirmed');";
429     static const char* jsPromptFormat = "alert(prompt('%s', 'default'));";
430
431     test->m_scriptDialogType = WEBKIT_SCRIPT_DIALOG_ALERT;
432     GOwnPtr<char> alertDialogMessage(g_strdup_printf(jsAlertFormat, kAlertDialogMessage));
433     GOwnPtr<char> alertHTML(g_strdup_printf(htmlOnLoadFormat, alertDialogMessage.get()));
434     test->loadHtml(alertHTML.get(), 0);
435     test->waitUntilMainLoopFinishes();
436
437     test->m_scriptDialogType = WEBKIT_SCRIPT_DIALOG_CONFIRM;
438     GOwnPtr<char> confirmDialogMessage(g_strdup_printf(jsConfirmFormat, kConfirmDialogMessage));
439     GOwnPtr<char> confirmHTML(g_strdup_printf(htmlOnLoadFormat, confirmDialogMessage.get()));
440     test->loadHtml(confirmHTML.get(), 0);
441     test->waitUntilMainLoopFinishes();
442
443     test->m_scriptDialogType = WEBKIT_SCRIPT_DIALOG_PROMPT;
444     GOwnPtr<char> promptDialogMessage(g_strdup_printf(jsPromptFormat, kPromptDialogMessage));
445     GOwnPtr<char> promptHTML(g_strdup_printf(htmlOnLoadFormat, promptDialogMessage.get()));
446     test->loadHtml(promptHTML.get(), 0);
447     test->waitUntilMainLoopFinishes();
448 }
449
450 static void testWebViewWindowProperties(UIClientTest* test, gconstpointer)
451 {
452     static const char* windowProrpertiesString = "left=100,top=150,width=400,height=400,location=no,menubar=no,status=no,toolbar=no,scrollbars=no";
453     GdkRectangle geometry = { 100, 150, 400, 400 };
454     test->setExpectedWindowProperties(UIClientTest::WindowProperties(&geometry, false, false, false, false, false, true, false));
455
456     GOwnPtr<char> htmlString(g_strdup_printf("<html><body onLoad=\"window.open('', '', '%s').close();\"></body></html>", windowProrpertiesString));
457     test->loadHtml(htmlString.get(), 0);
458     test->waitUntilMainLoopFinishes();
459
460     static const char* propertiesChanged[] = {
461         "geometry", "locationbar-visible", "menubar-visible", "statusbar-visible", "toolbar-visible", "scrollbars-visible"
462     };
463     for (size_t i = 0; i < G_N_ELEMENTS(propertiesChanged); ++i)
464         g_assert(test->m_windowPropertiesChanged.contains(propertiesChanged[i]));
465
466     Vector<UIClientTest::WebViewEvents>& events = test->m_webViewEvents;
467     g_assert_cmpint(events.size(), ==, 3);
468     g_assert_cmpint(events[0], ==, UIClientTest::Create);
469     g_assert_cmpint(events[1], ==, UIClientTest::ReadyToShow);
470     g_assert_cmpint(events[2], ==, UIClientTest::Close);
471 }
472
473 static void testWebViewMouseTarget(UIClientTest* test, gconstpointer)
474 {
475     test->showInWindowAndWaitUntilMapped(GTK_WINDOW_TOPLEVEL);
476
477     const char* linksHoveredHTML =
478         "<html><body>"
479         " <a style='position:absolute; left:1; top:1' href='http://www.webkitgtk.org' title='WebKitGTK+ Title'>WebKitGTK+ Website</a>"
480         " <img style='position:absolute; left:1; top:10' src='0xdeadbeef' width=5 height=5></img>"
481         " <a style='position:absolute; left:1; top:20' href='http://www.webkitgtk.org/logo' title='WebKitGTK+ Logo'><img src='0xdeadbeef' width=5 height=5></img></a>"
482         " <video style='position:absolute; left:1; top:30' width=10 height=10 controls='controls'><source src='movie.ogg' type='video/ogg' /></video>"
483         " <input style='position:absolute; left:1; top:50' size='10'></input>"
484         " <div style='position:absolute; left:1; top:70; width:30; height:30; overflow:scroll'>&nbsp;</div>"
485         "</body></html>";
486
487     test->loadHtml(linksHoveredHTML, "file:///");
488     test->waitUntilLoadFinished();
489
490     // Move over link.
491     WebKitHitTestResult* hitTestResult = test->moveMouseAndWaitUntilMouseTargetChanged(1, 1);
492     g_assert(webkit_hit_test_result_context_is_link(hitTestResult));
493     g_assert(!webkit_hit_test_result_context_is_image(hitTestResult));
494     g_assert(!webkit_hit_test_result_context_is_media(hitTestResult));
495     g_assert(!webkit_hit_test_result_context_is_editable(hitTestResult));
496     g_assert_cmpstr(webkit_hit_test_result_get_link_uri(hitTestResult), ==, "http://www.webkitgtk.org/");
497     g_assert_cmpstr(webkit_hit_test_result_get_link_title(hitTestResult), ==, "WebKitGTK+ Title");
498     g_assert_cmpstr(webkit_hit_test_result_get_link_label(hitTestResult), ==, "WebKitGTK+ Website");
499     g_assert(!test->m_mouseTargetModifiers);
500
501     // Move out of the link.
502     hitTestResult = test->moveMouseAndWaitUntilMouseTargetChanged(0, 0);
503     g_assert(!webkit_hit_test_result_context_is_link(hitTestResult));
504     g_assert(!webkit_hit_test_result_context_is_image(hitTestResult));
505     g_assert(!webkit_hit_test_result_context_is_media(hitTestResult));
506     g_assert(!webkit_hit_test_result_context_is_editable(hitTestResult));
507     g_assert(!test->m_mouseTargetModifiers);
508
509     // Move over image with GDK_CONTROL_MASK.
510     hitTestResult = test->moveMouseAndWaitUntilMouseTargetChanged(1, 10, GDK_CONTROL_MASK);
511     g_assert(!webkit_hit_test_result_context_is_link(hitTestResult));
512     g_assert(webkit_hit_test_result_context_is_image(hitTestResult));
513     g_assert(!webkit_hit_test_result_context_is_media(hitTestResult));
514     g_assert(!webkit_hit_test_result_context_is_editable(hitTestResult));
515     g_assert(!webkit_hit_test_result_context_is_scrollbar(hitTestResult));
516     g_assert_cmpstr(webkit_hit_test_result_get_image_uri(hitTestResult), ==, "file:///0xdeadbeef");
517     g_assert(test->m_mouseTargetModifiers & GDK_CONTROL_MASK);
518
519     // Move over image link.
520     hitTestResult = test->moveMouseAndWaitUntilMouseTargetChanged(1, 20);
521     g_assert(webkit_hit_test_result_context_is_link(hitTestResult));
522     g_assert(webkit_hit_test_result_context_is_image(hitTestResult));
523     g_assert(!webkit_hit_test_result_context_is_media(hitTestResult));
524     g_assert(!webkit_hit_test_result_context_is_editable(hitTestResult));
525     g_assert(!webkit_hit_test_result_context_is_scrollbar(hitTestResult));
526     g_assert_cmpstr(webkit_hit_test_result_get_link_uri(hitTestResult), ==, "http://www.webkitgtk.org/logo");
527     g_assert_cmpstr(webkit_hit_test_result_get_image_uri(hitTestResult), ==, "file:///0xdeadbeef");
528     g_assert_cmpstr(webkit_hit_test_result_get_link_title(hitTestResult), ==, "WebKitGTK+ Logo");
529     g_assert(!webkit_hit_test_result_get_link_label(hitTestResult));
530     g_assert(!test->m_mouseTargetModifiers);
531
532     // Move over media.
533     hitTestResult = test->moveMouseAndWaitUntilMouseTargetChanged(1, 30);
534     g_assert(!webkit_hit_test_result_context_is_link(hitTestResult));
535     g_assert(!webkit_hit_test_result_context_is_image(hitTestResult));
536     g_assert(webkit_hit_test_result_context_is_media(hitTestResult));
537     g_assert(!webkit_hit_test_result_context_is_editable(hitTestResult));
538     g_assert(!webkit_hit_test_result_context_is_scrollbar(hitTestResult));
539     g_assert_cmpstr(webkit_hit_test_result_get_media_uri(hitTestResult), ==, "file:///movie.ogg");
540     g_assert(!test->m_mouseTargetModifiers);
541
542     // Mover over input.
543     hitTestResult = test->moveMouseAndWaitUntilMouseTargetChanged(5, 55);
544     g_assert(!webkit_hit_test_result_context_is_link(hitTestResult));
545     g_assert(!webkit_hit_test_result_context_is_image(hitTestResult));
546     g_assert(!webkit_hit_test_result_context_is_media(hitTestResult));
547     g_assert(!webkit_hit_test_result_context_is_scrollbar(hitTestResult));
548     g_assert(webkit_hit_test_result_context_is_editable(hitTestResult));
549     g_assert(!test->m_mouseTargetModifiers);
550
551     // Move over scrollbar.
552     hitTestResult = test->moveMouseAndWaitUntilMouseTargetChanged(5, 95);
553     g_assert(!webkit_hit_test_result_context_is_link(hitTestResult));
554     g_assert(!webkit_hit_test_result_context_is_image(hitTestResult));
555     g_assert(!webkit_hit_test_result_context_is_media(hitTestResult));
556     g_assert(!webkit_hit_test_result_context_is_editable(hitTestResult));
557     g_assert(webkit_hit_test_result_context_is_scrollbar(hitTestResult));
558     g_assert(!test->m_mouseTargetModifiers);
559 }
560
561 static void testWebViewPermissionRequests(UIClientTest* test, gconstpointer)
562 {
563     // Some versions of geoclue give a runtime warning because it tries
564     // to register the error quark twice. See https://bugs.webkit.org/show_bug.cgi?id=89858.
565     // Make warnings non-fatal for this test to make it pass.
566     test->removeLogFatalFlag(G_LOG_LEVEL_WARNING);
567     test->showInWindowAndWaitUntilMapped();
568     static const char* geolocationRequestHTML =
569         "<html>"
570         "  <script>"
571         "  function runTest()"
572         "  {"
573         "    navigator.geolocation.getCurrentPosition(function(p) { document.title = \"OK\" },"
574         "                                             function(e) { document.title = e.code });"
575         "  }"
576         "  </script>"
577         "  <body onload='runTest();'></body>"
578         "</html>";
579
580     // Test denying a permission request.
581     test->m_allowPermissionRequests = false;
582     test->loadHtml(geolocationRequestHTML, 0);
583     test->waitUntilTitleChanged();
584
585     // According to the Geolocation API specification, '1' is the
586     // error code returned for the PERMISSION_DENIED error.
587     // http://dev.w3.org/geo/api/spec-source.html#position_error_interface
588     const gchar* result = webkit_web_view_get_title(test->m_webView);
589     g_assert_cmpstr(result, ==, "1");
590
591     // Test allowing a permission request.
592     test->m_allowPermissionRequests = true;
593     test->loadHtml(geolocationRequestHTML, 0);
594     test->waitUntilTitleChanged();
595
596     // Check that we did not get the PERMISSION_DENIED error now.
597     result = webkit_web_view_get_title(test->m_webView);
598     g_assert_cmpstr(result, !=, "1");
599     test->addLogFatalFlag(G_LOG_LEVEL_WARNING);
600 }
601
602 static void testWebViewZoomLevel(WebViewTest* test, gconstpointer)
603 {
604     g_assert_cmpfloat(webkit_web_view_get_zoom_level(test->m_webView), ==, 1);
605     webkit_web_view_set_zoom_level(test->m_webView, 2.5);
606     g_assert_cmpfloat(webkit_web_view_get_zoom_level(test->m_webView), ==, 2.5);
607
608     webkit_settings_set_zoom_text_only(webkit_web_view_get_settings(test->m_webView), TRUE);
609     // The zoom level shouldn't change when zoom-text-only setting changes.
610     g_assert_cmpfloat(webkit_web_view_get_zoom_level(test->m_webView), ==, 2.5);
611 }
612
613 static void testWebViewRunJavaScript(WebViewTest* test, gconstpointer)
614 {
615     static const char* html = "<html><body><a id='WebKitLink' href='http://www.webkitgtk.org/' title='WebKitGTK+ Title'>WebKitGTK+ Website</a></body></html>";
616     test->loadHtml(html, 0);
617     test->waitUntilLoadFinished();
618
619     GOwnPtr<GError> error;
620     WebKitJavascriptResult* javascriptResult = test->runJavaScriptAndWaitUntilFinished("window.document.getElementById('WebKitLink').title;", &error.outPtr());
621     g_assert(javascriptResult);
622     g_assert(!error.get());
623     GOwnPtr<char> valueString(WebViewTest::javascriptResultToCString(javascriptResult));
624     g_assert_cmpstr(valueString.get(), ==, "WebKitGTK+ Title");
625
626     javascriptResult = test->runJavaScriptAndWaitUntilFinished("window.document.getElementById('WebKitLink').href;", &error.outPtr());
627     g_assert(javascriptResult);
628     g_assert(!error.get());
629     valueString.set(WebViewTest::javascriptResultToCString(javascriptResult));
630     g_assert_cmpstr(valueString.get(), ==, "http://www.webkitgtk.org/");
631
632     javascriptResult = test->runJavaScriptAndWaitUntilFinished("window.document.getElementById('WebKitLink').textContent", &error.outPtr());
633     g_assert(javascriptResult);
634     g_assert(!error.get());
635     valueString.set(WebViewTest::javascriptResultToCString(javascriptResult));
636     g_assert_cmpstr(valueString.get(), ==, "WebKitGTK+ Website");
637
638     javascriptResult = test->runJavaScriptAndWaitUntilFinished("a = 25;", &error.outPtr());
639     g_assert(javascriptResult);
640     g_assert(!error.get());
641     g_assert_cmpfloat(WebViewTest::javascriptResultToNumber(javascriptResult), ==, 25);
642
643     javascriptResult = test->runJavaScriptAndWaitUntilFinished("a = 2.5;", &error.outPtr());
644     g_assert(javascriptResult);
645     g_assert(!error.get());
646     g_assert_cmpfloat(WebViewTest::javascriptResultToNumber(javascriptResult), ==, 2.5);
647
648     javascriptResult = test->runJavaScriptAndWaitUntilFinished("a = true", &error.outPtr());
649     g_assert(javascriptResult);
650     g_assert(!error.get());
651     g_assert(WebViewTest::javascriptResultToBoolean(javascriptResult));
652
653     javascriptResult = test->runJavaScriptAndWaitUntilFinished("a = false", &error.outPtr());
654     g_assert(javascriptResult);
655     g_assert(!error.get());
656     g_assert(!WebViewTest::javascriptResultToBoolean(javascriptResult));
657
658     javascriptResult = test->runJavaScriptAndWaitUntilFinished("a = null", &error.outPtr());
659     g_assert(javascriptResult);
660     g_assert(!error.get());
661     g_assert(WebViewTest::javascriptResultIsNull(javascriptResult));
662
663     javascriptResult = test->runJavaScriptAndWaitUntilFinished("function Foo() { a = 25; } Foo();", &error.outPtr());
664     g_assert(javascriptResult);
665     g_assert(!error.get());
666     g_assert(WebViewTest::javascriptResultIsUndefined(javascriptResult));
667
668     javascriptResult = test->runJavaScriptFromGResourceAndWaitUntilFinished("/org/webkit/webkit2gtk/tests/link-title.js", &error.outPtr());
669     g_assert(javascriptResult);
670     g_assert(!error.get());
671     valueString.set(WebViewTest::javascriptResultToCString(javascriptResult));
672     g_assert_cmpstr(valueString.get(), ==, "WebKitGTK+ Title");
673
674     javascriptResult = test->runJavaScriptFromGResourceAndWaitUntilFinished("/wrong/path/to/resource.js", &error.outPtr());
675     g_assert(!javascriptResult);
676     g_assert_error(error.get(), G_RESOURCE_ERROR, G_RESOURCE_ERROR_NOT_FOUND);
677     error.clear();
678
679     javascriptResult = test->runJavaScriptAndWaitUntilFinished("foo();", &error.outPtr());
680     g_assert(!javascriptResult);
681     g_assert_error(error.get(), WEBKIT_JAVASCRIPT_ERROR, WEBKIT_JAVASCRIPT_ERROR_SCRIPT_FAILED);
682 }
683
684 class FileChooserTest: public UIClientTest {
685 public:
686     MAKE_GLIB_TEST_FIXTURE(FileChooserTest);
687
688     FileChooserTest()
689     {
690         g_signal_connect(m_webView, "run-file-chooser", G_CALLBACK(runFileChooserCallback), this);
691     }
692
693     static gboolean runFileChooserCallback(WebKitWebView*, WebKitFileChooserRequest* request, FileChooserTest* test)
694     {
695         test->runFileChooser(request);
696         return TRUE;
697     }
698
699     void runFileChooser(WebKitFileChooserRequest* request)
700     {
701         assertObjectIsDeletedWhenTestFinishes(G_OBJECT(request));
702         m_fileChooserRequest = request;
703         g_main_loop_quit(m_mainLoop);
704     }
705
706     WebKitFileChooserRequest* clickMouseButtonAndWaitForFileChooserRequest(int x, int y)
707     {
708         clickMouseButton(x, y);
709         g_main_loop_run(m_mainLoop);
710         return m_fileChooserRequest.get();
711     }
712
713 private:
714     GRefPtr<WebKitFileChooserRequest> m_fileChooserRequest;
715 };
716
717 static void testWebViewFileChooserRequest(FileChooserTest* test, gconstpointer)
718 {
719     test->showInWindowAndWaitUntilMapped();
720     static const char* fileChooserHTMLFormat = "<html><body><input style='position:absolute;left:0;top:0;margin:0;padding:0' type='file' %s/></body></html>";
721
722     // Multiple selections not allowed, no MIME filtering.
723     GOwnPtr<char> simpleFileUploadHTML(g_strdup_printf(fileChooserHTMLFormat, ""));
724     test->loadHtml(simpleFileUploadHTML.get(), 0);
725     test->waitUntilLoadFinished();
726     WebKitFileChooserRequest* fileChooserRequest = test->clickMouseButtonAndWaitForFileChooserRequest(5, 5);
727     g_assert(!webkit_file_chooser_request_get_select_multiple(fileChooserRequest));
728
729     const gchar* const* mimeTypes = webkit_file_chooser_request_get_mime_types(fileChooserRequest);
730     g_assert(!mimeTypes);
731     GtkFileFilter* filter = webkit_file_chooser_request_get_mime_types_filter(fileChooserRequest);
732     g_assert(!filter);
733     const gchar* const* selectedFiles = webkit_file_chooser_request_get_selected_files(fileChooserRequest);
734     g_assert(!selectedFiles);
735     webkit_file_chooser_request_cancel(fileChooserRequest);
736
737     // Multiple selections allowed, no MIME filtering, some pre-selected files.
738     GOwnPtr<char> multipleSelectionFileUploadHTML(g_strdup_printf(fileChooserHTMLFormat, "multiple"));
739     test->loadHtml(multipleSelectionFileUploadHTML.get(), 0);
740     test->waitUntilLoadFinished();
741     fileChooserRequest = test->clickMouseButtonAndWaitForFileChooserRequest(5, 5);
742     g_assert(webkit_file_chooser_request_get_select_multiple(fileChooserRequest));
743
744     mimeTypes = webkit_file_chooser_request_get_mime_types(fileChooserRequest);
745     g_assert(!mimeTypes);
746     filter = webkit_file_chooser_request_get_mime_types_filter(fileChooserRequest);
747     g_assert(!filter);
748     selectedFiles = webkit_file_chooser_request_get_selected_files(fileChooserRequest);
749     g_assert(!selectedFiles);
750
751     // Select some files.
752     const gchar* filesToSelect[4] = { "/foo", "/foo/bar", "/foo/bar/baz", 0 };
753     webkit_file_chooser_request_select_files(fileChooserRequest, filesToSelect);
754
755     // Check the files that have been just selected.
756     selectedFiles = webkit_file_chooser_request_get_selected_files(fileChooserRequest);
757     g_assert(selectedFiles);
758     g_assert_cmpstr(selectedFiles[0], ==, "/foo");
759     g_assert_cmpstr(selectedFiles[1], ==, "/foo/bar");
760     g_assert_cmpstr(selectedFiles[2], ==, "/foo/bar/baz");
761     g_assert(!selectedFiles[3]);
762
763     // Perform another request to check if the list of files selected
764     // in the previous step appears now as part of the new request.
765     fileChooserRequest = test->clickMouseButtonAndWaitForFileChooserRequest(5, 5);
766     selectedFiles = webkit_file_chooser_request_get_selected_files(fileChooserRequest);
767     g_assert(selectedFiles);
768     g_assert_cmpstr(selectedFiles[0], ==, "/foo");
769     g_assert_cmpstr(selectedFiles[1], ==, "/foo/bar");
770     g_assert_cmpstr(selectedFiles[2], ==, "/foo/bar/baz");
771     g_assert(!selectedFiles[3]);
772     webkit_file_chooser_request_cancel(fileChooserRequest);
773
774     // Multiple selections not allowed, only accept images, audio and video files..
775     GOwnPtr<char> mimeFilteredFileUploadHTML(g_strdup_printf(fileChooserHTMLFormat, "accept='audio/*,video/*,image/*'"));
776     test->loadHtml(mimeFilteredFileUploadHTML.get(), 0);
777     test->waitUntilLoadFinished();
778     fileChooserRequest = test->clickMouseButtonAndWaitForFileChooserRequest(5, 5);
779     g_assert(!webkit_file_chooser_request_get_select_multiple(fileChooserRequest));
780
781     mimeTypes = webkit_file_chooser_request_get_mime_types(fileChooserRequest);
782     g_assert(mimeTypes);
783     g_assert_cmpstr(mimeTypes[0], ==, "audio/*");
784     g_assert_cmpstr(mimeTypes[1], ==, "video/*");
785     g_assert_cmpstr(mimeTypes[2], ==, "image/*");
786     g_assert(!mimeTypes[3]);
787
788     filter = webkit_file_chooser_request_get_mime_types_filter(fileChooserRequest);
789     g_assert(GTK_IS_FILE_FILTER(filter));
790     g_assert(checkMimeTypeForFilter(filter, "audio/*"));
791     g_assert(checkMimeTypeForFilter(filter, "video/*"));
792     g_assert(checkMimeTypeForFilter(filter, "image/*"));
793
794     selectedFiles = webkit_file_chooser_request_get_selected_files(fileChooserRequest);
795     g_assert(!selectedFiles);
796     webkit_file_chooser_request_cancel(fileChooserRequest);
797 }
798
799 class FullScreenClientTest: public WebViewTest {
800 public:
801     MAKE_GLIB_TEST_FIXTURE(FullScreenClientTest);
802
803     enum FullScreenEvent {
804         None,
805         Enter,
806         Leave
807     };
808
809     static gboolean viewEnterFullScreenCallback(WebKitWebView*, FullScreenClientTest* test)
810     {
811         test->m_event = Enter;
812         g_main_loop_quit(test->m_mainLoop);
813         return FALSE;
814     }
815
816     static gboolean viewLeaveFullScreenCallback(WebKitWebView*, FullScreenClientTest* test)
817     {
818         test->m_event = Leave;
819         g_main_loop_quit(test->m_mainLoop);
820         return FALSE;
821     }
822
823     FullScreenClientTest()
824         : m_event(None)
825     {
826         webkit_settings_set_enable_fullscreen(webkit_web_view_get_settings(m_webView), TRUE);
827         g_signal_connect(m_webView, "enter-fullscreen", G_CALLBACK(viewEnterFullScreenCallback), this);
828         g_signal_connect(m_webView, "leave-fullscreen", G_CALLBACK(viewLeaveFullScreenCallback), this);
829     }
830
831     ~FullScreenClientTest()
832     {
833         g_signal_handlers_disconnect_matched(m_webView, G_SIGNAL_MATCH_DATA, 0, 0, 0, 0, this);
834     }
835
836     void requestFullScreenAndWaitUntilEnteredFullScreen()
837     {
838         m_event = None;
839         webkit_web_view_run_javascript(m_webView, "document.documentElement.webkitRequestFullScreen();", 0, 0, 0);
840         g_main_loop_run(m_mainLoop);
841     }
842
843     static gboolean leaveFullScreenIdle(FullScreenClientTest* test)
844     {
845         test->keyStroke(GDK_KEY_Escape);
846         return FALSE;
847     }
848
849     void leaveFullScreenAndWaitUntilLeftFullScreen()
850     {
851         m_event = None;
852         g_idle_add(reinterpret_cast<GSourceFunc>(leaveFullScreenIdle), this);
853         g_main_loop_run(m_mainLoop);
854     }
855
856     FullScreenEvent m_event;
857 };
858
859 static void testWebViewFullScreen(FullScreenClientTest* test, gconstpointer)
860 {
861     test->showInWindowAndWaitUntilMapped();
862     test->loadHtml("<html><body>FullScreen test</body></html>", 0);
863     test->waitUntilLoadFinished();
864     test->requestFullScreenAndWaitUntilEnteredFullScreen();
865     g_assert_cmpint(test->m_event, ==, FullScreenClientTest::Enter);
866     test->leaveFullScreenAndWaitUntilLeftFullScreen();
867     g_assert_cmpint(test->m_event, ==, FullScreenClientTest::Leave);
868 }
869
870 static void testWebViewCanShowMIMEType(WebViewTest* test, gconstpointer)
871 {
872     // Supported MIME types.
873     g_assert(webkit_web_view_can_show_mime_type(test->m_webView, "text/html"));
874     g_assert(webkit_web_view_can_show_mime_type(test->m_webView, "text/plain"));
875     g_assert(webkit_web_view_can_show_mime_type(test->m_webView, "image/jpeg"));
876
877     // Unsupported MIME types.
878     g_assert(!webkit_web_view_can_show_mime_type(test->m_webView, "text/vcard"));
879     g_assert(!webkit_web_view_can_show_mime_type(test->m_webView, "application/pdf"));
880     g_assert(!webkit_web_view_can_show_mime_type(test->m_webView, "application/zip"));
881     g_assert(!webkit_web_view_can_show_mime_type(test->m_webView, "application/octet-stream"));
882
883     // Plugins are only supported when enabled.
884     webkit_web_context_set_additional_plugins_directory(webkit_web_view_get_context(test->m_webView), WEBKIT_TEST_PLUGIN_DIR);
885     g_assert(webkit_web_view_can_show_mime_type(test->m_webView, "application/x-webkit-test-netscape"));
886     webkit_settings_set_enable_plugins(webkit_web_view_get_settings(test->m_webView), FALSE);
887     g_assert(!webkit_web_view_can_show_mime_type(test->m_webView, "application/x-webkit-test-netscape"));
888 }
889
890 class FormClientTest: public WebViewTest {
891 public:
892     MAKE_GLIB_TEST_FIXTURE(FormClientTest);
893
894     static void submitFormCallback(WebKitWebView*, WebKitFormSubmissionRequest* request, FormClientTest* test)
895     {
896         test->submitForm(request);
897     }
898
899     FormClientTest()
900         : m_submitPositionX(0)
901         , m_submitPositionY(0)
902     {
903         g_signal_connect(m_webView, "submit-form", G_CALLBACK(submitFormCallback), this);
904     }
905
906     ~FormClientTest()
907     {
908         g_signal_handlers_disconnect_matched(m_webView, G_SIGNAL_MATCH_DATA, 0, 0, 0, 0, this);
909     }
910
911     void submitForm(WebKitFormSubmissionRequest* request)
912     {
913         assertObjectIsDeletedWhenTestFinishes(G_OBJECT(request));
914         m_request = request;
915         webkit_form_submission_request_submit(request);
916         quitMainLoop();
917     }
918
919     GHashTable* waitUntilFormSubmittedAndGetTextFields()
920     {
921         g_main_loop_run(m_mainLoop);
922         return webkit_form_submission_request_get_text_fields(m_request.get());
923     }
924
925     static gboolean doClickIdleCallback(FormClientTest* test)
926     {
927         test->clickMouseButton(test->m_submitPositionX, test->m_submitPositionY, 1);
928         return FALSE;
929     }
930
931     void submitFormAtPosition(int x, int y)
932     {
933         m_submitPositionX = x;
934         m_submitPositionY = y;
935         g_idle_add(reinterpret_cast<GSourceFunc>(doClickIdleCallback), this);
936     }
937
938     int m_submitPositionX;
939     int m_submitPositionY;
940     GRefPtr<WebKitFormSubmissionRequest> m_request;
941 };
942
943 static void testWebViewSubmitForm(FormClientTest* test, gconstpointer)
944 {
945     test->showInWindowAndWaitUntilMapped();
946
947     const char* formHTML =
948         "<html><body>"
949         " <form action='#'>"
950         "  <input type='text' name='text1' value='value1'>"
951         "  <input type='text' name='text2' value='value2'>"
952         "  <input type='password' name='password' value='secret'>"
953         "  <textarea cols='5' rows='5' name='textarea'>Text</textarea>"
954         "  <input type='hidden' name='hidden1' value='hidden1'>"
955         "  <input type='submit' value='Submit' style='position:absolute; left:1; top:1' size='10'>"
956         " </form>"
957         "</body></html>";
958
959     test->loadHtml(formHTML, "file:///");
960     test->waitUntilLoadFinished();
961
962     test->submitFormAtPosition(5, 5);
963     GHashTable* values = test->waitUntilFormSubmittedAndGetTextFields();
964     g_assert(values);
965     g_assert_cmpuint(g_hash_table_size(values), ==, 3);
966     g_assert_cmpstr(static_cast<char*>(g_hash_table_lookup(values, "text1")), ==, "value1");
967     g_assert_cmpstr(static_cast<char*>(g_hash_table_lookup(values, "text2")), ==, "value2");
968     g_assert_cmpstr(static_cast<char*>(g_hash_table_lookup(values, "password")), ==, "secret");
969 }
970
971 class SaveWebViewTest: public WebViewTest {
972 public:
973     MAKE_GLIB_TEST_FIXTURE(SaveWebViewTest);
974
975     SaveWebViewTest()
976         : m_tempDirectory(g_dir_make_tmp("WebKit2SaveViewTest-XXXXXX", 0))
977     {
978     }
979
980     ~SaveWebViewTest()
981     {
982         if (G_IS_FILE(m_file.get()))
983             g_file_delete(m_file.get(), 0, 0);
984
985         if (G_IS_INPUT_STREAM(m_inputStream.get()))
986             g_input_stream_close(m_inputStream.get(), 0, 0);
987
988         if (m_tempDirectory)
989             g_rmdir(m_tempDirectory.get());
990     }
991
992     static void webViewSavedToStreamCallback(GObject* object, GAsyncResult* result, SaveWebViewTest* test)
993     {
994         GOwnPtr<GError> error;
995         test->m_inputStream = adoptGRef(webkit_web_view_save_finish(test->m_webView, result, &error.outPtr()));
996         g_assert(G_IS_INPUT_STREAM(test->m_inputStream.get()));
997         g_assert(!error);
998
999         test->quitMainLoop();
1000     }
1001
1002     static void webViewSavedToFileCallback(GObject* object, GAsyncResult* result, SaveWebViewTest* test)
1003     {
1004         GOwnPtr<GError> error;
1005         g_assert(webkit_web_view_save_to_file_finish(test->m_webView, result, &error.outPtr()));
1006         g_assert(!error);
1007
1008         test->quitMainLoop();
1009     }
1010
1011     void saveAndWaitForStream()
1012     {
1013         webkit_web_view_save(m_webView, WEBKIT_SAVE_MODE_MHTML, 0, reinterpret_cast<GAsyncReadyCallback>(webViewSavedToStreamCallback), this);
1014         g_main_loop_run(m_mainLoop);
1015     }
1016
1017     void saveAndWaitForFile()
1018     {
1019         m_saveDestinationFilePath.set(g_build_filename(m_tempDirectory.get(), "testWebViewSaveResult.mht", NULL));
1020         m_file = adoptGRef(g_file_new_for_path(m_saveDestinationFilePath.get()));
1021         webkit_web_view_save_to_file(m_webView, m_file.get(), WEBKIT_SAVE_MODE_MHTML, 0, reinterpret_cast<GAsyncReadyCallback>(webViewSavedToFileCallback), this);
1022         g_main_loop_run(m_mainLoop);
1023     }
1024
1025     GOwnPtr<char> m_tempDirectory;
1026     GOwnPtr<char> m_saveDestinationFilePath;
1027     GRefPtr<GInputStream> m_inputStream;
1028     GRefPtr<GFile> m_file;
1029 };
1030
1031 static void testWebViewSave(SaveWebViewTest* test, gconstpointer)
1032 {
1033     test->loadHtml("<html>"
1034                    "<body>"
1035                    "  <p>A paragraph with plain text</p>"
1036                    "  <p>"
1037                    "    A red box: <img src='data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAIAAAACCAIAAAD91JpzAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH3AYWDTMVwnSZnwAAAB1pVFh0Q29tbWVudAAAAAAAQ3JlYXRlZCB3aXRoIEdJTVBkLmUHAAAAFklEQVQI12P8z8DAwMDAxMDAwMDAAAANHQEDK+mmyAAAAABJRU5ErkJggg=='></br>"
1038                    "    A blue box: <img src='data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAIAAAACCAIAAAD91JpzAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH3AYWDTMvBHhALQAAAB1pVFh0Q29tbWVudAAAAAAAQ3JlYXRlZCB3aXRoIEdJTVBkLmUHAAAAFklEQVQI12Nk4PnPwMDAxMDAwMDAAAALrwEPPIs1pgAAAABJRU5ErkJggg=='>"
1039                    "  </p>"
1040                    "</body>"
1041                    "</html>", 0);
1042     test->waitUntilLoadFinished();
1043
1044     // Write to a file and to an input stream.
1045     test->saveAndWaitForFile();
1046     test->saveAndWaitForStream();
1047
1048     // We should have exactly the same amount of bytes in the file
1049     // than those coming from the GInputStream. We don't compare the
1050     // strings read since the 'Date' field and the boundaries will be
1051     // different on each case. MHTML functionality will be tested by
1052     // Layout tests, so checking the amount of bytes is enough.
1053     GOwnPtr<GError> error;
1054     gchar buffer[512] = { 0 };
1055     gssize readBytes = 0;
1056     gssize totalBytesFromStream = 0;
1057     while (readBytes = g_input_stream_read(test->m_inputStream.get(), &buffer, 512, 0, &error.outPtr())) {
1058         g_assert(!error);
1059         totalBytesFromStream += readBytes;
1060     }
1061
1062     // Check that the file exists and that it contains the same amount of bytes.
1063     GRefPtr<GFileInfo> fileInfo = adoptGRef(g_file_query_info(test->m_file.get(), G_FILE_ATTRIBUTE_STANDARD_SIZE, static_cast<GFileQueryInfoFlags>(0), 0, 0));
1064     g_assert_cmpint(g_file_info_get_size(fileInfo.get()), ==, totalBytesFromStream);
1065 }
1066
1067 static void testWebViewMode(WebViewTest* test, gconstpointer)
1068 {
1069     static const char* indexHTML = "<html><body><p>Test Web View Mode</p></body></html>";
1070
1071     // Web mode.
1072     g_assert_cmpuint(webkit_web_view_get_view_mode(test->m_webView), ==, WEBKIT_VIEW_MODE_WEB);
1073     test->loadHtml(indexHTML, 0);
1074     test->waitUntilLoadFinished();
1075     WebKitJavascriptResult* javascriptResult = test->runJavaScriptAndWaitUntilFinished("window.document.body.textContent;", 0);
1076     GOwnPtr<char> valueString(WebViewTest::javascriptResultToCString(javascriptResult));
1077     g_assert_cmpstr(valueString.get(), ==, "Test Web View Mode");
1078
1079     // Source mode.
1080     webkit_web_view_set_view_mode(test->m_webView, WEBKIT_VIEW_MODE_SOURCE);
1081     test->loadHtml(indexHTML, 0);
1082     test->waitUntilLoadFinished();
1083     javascriptResult = test->runJavaScriptAndWaitUntilFinished("window.document.body.textContent;", 0);
1084     valueString.set(WebViewTest::javascriptResultToCString(javascriptResult));
1085     g_assert_cmpstr(valueString.get(), ==, indexHTML);
1086 }
1087
1088 void beforeAll()
1089 {
1090     WebViewTest::add("WebKitWebView", "default-context", testWebViewDefaultContext);
1091     WebViewTest::add("WebKitWebView", "custom-charset", testWebViewCustomCharset);
1092     WebViewTest::add("WebKitWebView", "settings", testWebViewSettings);
1093     UIClientTest::add("WebKitWebView", "create-ready-close", testWebViewCreateReadyClose);
1094     ModalDialogsTest::add("WebKitWebView", "allow-modal-dialogs", testWebViewAllowModalDialogs);
1095     ModalDialogsTest::add("WebKitWebView", "disallow-modal-dialogs", testWebViewDisallowModalDialogs);
1096     UIClientTest::add("WebKitWebView", "javascript-dialogs", testWebViewJavaScriptDialogs);
1097     UIClientTest::add("WebKitWebView", "window-properties", testWebViewWindowProperties);
1098     UIClientTest::add("WebKitWebView", "mouse-target", testWebViewMouseTarget);
1099     UIClientTest::add("WebKitWebView", "permission-requests", testWebViewPermissionRequests);
1100     WebViewTest::add("WebKitWebView", "zoom-level", testWebViewZoomLevel);
1101     WebViewTest::add("WebKitWebView", "run-javascript", testWebViewRunJavaScript);
1102     FileChooserTest::add("WebKitWebView", "file-chooser-request", testWebViewFileChooserRequest);
1103     FullScreenClientTest::add("WebKitWebView", "fullscreen", testWebViewFullScreen);
1104     WebViewTest::add("WebKitWebView", "can-show-mime-type", testWebViewCanShowMIMEType);
1105     FormClientTest::add("WebKitWebView", "submit-form", testWebViewSubmitForm);
1106     SaveWebViewTest::add("WebKitWebView", "save", testWebViewSave);
1107     WebViewTest::add("WebKitWebView", "view-mode", testWebViewMode);
1108 }
1109
1110 void afterAll()
1111 {
1112 }