1/*
2 * Copyright (C) 2008 Holger Hans Peter Freyther
3 * Copyright (C) 2009 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 <errno.h>
22#include <unistd.h>
23#include <glib.h>
24#include <glib/gstdio.h>
25#include <gtk/gtk.h>
26#include <webkit/webkit.h>
27
28#if GTK_CHECK_VERSION(2, 14, 0)
29
30static int numberOfFramesCreated = 0;
31
32static void createFrameSignalTestFrameCreatedCallback(WebKitWebView* webView, WebKitWebFrame* frame, gpointer data)
33{
34    numberOfFramesCreated++;
35}
36
37static gboolean createFrameSignalTestTimeout(gpointer data)
38{
39    g_assert_cmpint(numberOfFramesCreated, ==, 2);
40    g_main_loop_quit((GMainLoop*) data);
41    return FALSE;
42}
43
44static void test_webkit_web_frame_created_signal(void)
45{
46    GtkWidget* webView;
47    GtkWidget* window;
48    GMainLoop* loop = g_main_loop_new(NULL, TRUE);
49
50    window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
51
52    webView = webkit_web_view_new();
53    g_signal_connect(webView, "frame-created", G_CALLBACK(createFrameSignalTestFrameCreatedCallback), loop);
54
55    // We want to ensure that exactly two create-frame signals are
56    // fired and no more, so we set a timeout here. There does not appear
57    // to be a simple way via the API to figure out when all frames have
58    // loaded.
59    g_timeout_add(500, createFrameSignalTestTimeout, loop);
60
61    gtk_container_add(GTK_CONTAINER(window), webView);
62    gtk_widget_show(window);
63    gtk_widget_show(webView);
64
65    webkit_web_view_load_string(WEBKIT_WEB_VIEW(webView),
66        "<html><body>Frames!"
67        "<iframe></iframe>"
68        "<iframe></iframe>"
69        "</body></html>",
70        "text/html", "utf-8", "file://");
71    g_main_loop_run(loop);
72}
73
74static void test_webkit_web_frame_create_destroy(void)
75{
76    GtkWidget *webView;
77    GtkWidget *window;
78
79    g_test_bug("21837");
80    webView = webkit_web_view_new();
81    g_object_ref_sink(webView);
82    g_assert_cmpint(G_OBJECT(webView)->ref_count, ==, 1);
83    // This crashed with the original version
84    g_object_unref(webView);
85
86    g_test_bug("25042");
87    window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
88    webView = webkit_web_view_new();
89    gtk_container_add(GTK_CONTAINER(window), webView);
90    gtk_widget_show(window);
91    gtk_widget_show(webView);
92    gtk_widget_destroy(webView);
93}
94
95static void test_webkit_web_frame_lifetime(void)
96{
97    WebKitWebView* webView;
98    WebKitWebFrame* webFrame;
99    g_test_bug("21837");
100
101    webView = WEBKIT_WEB_VIEW(webkit_web_view_new());
102    g_object_ref_sink(webView);
103    g_assert_cmpint(G_OBJECT(webView)->ref_count, ==, 1);
104    webFrame = webkit_web_view_get_main_frame(webView);
105    g_assert_cmpint(G_OBJECT(webFrame)->ref_count, ==, 1);
106
107    // Add dummy reference on the WebKitWebFrame to keep it alive
108    g_object_ref(webFrame);
109    g_assert_cmpint(G_OBJECT(webFrame)->ref_count, ==, 2);
110
111    // This crashed with the original version
112    g_object_unref(webView);
113
114    // Make sure that the frame got deleted as well. We did this
115    // by adding an extra ref on the WebKitWebFrame and we should
116    // be the one holding the last reference.
117    g_assert_cmpint(G_OBJECT(webFrame)->ref_count, ==, 1);
118    g_object_unref(webFrame);
119}
120
121static gboolean print_requested_cb(WebKitWebView* webView, WebKitWebFrame* webFrame, GMainLoop* loop)
122{
123    g_object_set_data(G_OBJECT(webView), "signal-handled", GINT_TO_POINTER(TRUE));
124    g_main_loop_quit(loop);
125    return TRUE;
126}
127
128static void print_timeout(GMainLoop* loop)
129{
130    if (g_main_loop_is_running(loop))
131        g_main_loop_quit(loop);
132}
133
134static void test_webkit_web_frame_printing(void)
135{
136    WebKitWebView* webView;
137
138    webView = WEBKIT_WEB_VIEW(webkit_web_view_new());
139    g_object_ref_sink(webView);
140    g_assert_cmpint(G_OBJECT(webView)->ref_count, ==, 1);
141
142    webkit_web_view_load_string(webView,
143                                "<html><body><h1>WebKitGTK+!</h1></body></html>",
144                                "text/html",
145                                "utf-8",
146                                "file://");
147
148    GMainLoop* loop = g_main_loop_new(NULL, TRUE);
149
150    // Does javascript print() work correctly?
151    g_signal_connect(webView, "print-requested",
152                     G_CALLBACK(print_requested_cb),
153                     loop);
154
155    g_object_set_data(G_OBJECT(webView), "signal-handled", GINT_TO_POINTER(FALSE));
156    webkit_web_view_execute_script (webView, "print();");
157
158    // Give javascriptcore some time to process the print request, but
159    // prepare a timeout to avoid it running forever in case the signal is
160    // never emitted.
161    g_timeout_add(1000, (GSourceFunc)print_timeout, loop);
162    g_main_loop_run(loop);
163
164    g_assert_cmpint(GPOINTER_TO_INT(g_object_get_data(G_OBJECT(webView), "signal-handled")), ==, TRUE);
165
166    // Does printing directly to a file?
167    GError *error = NULL;
168    gchar* temporaryFilename = NULL;
169    gint fd = g_file_open_tmp ("webkit-testwebframe-XXXXXX", &temporaryFilename, &error);
170    close(fd);
171
172    if (error) {
173        g_critical("Failed to open a temporary file for writing: %s.", error->message);
174        g_error_free(error);
175        goto cleanup;
176    }
177
178    // We delete the file, so that we can easily figure out that the
179    // file got printed;
180    if (g_unlink(temporaryFilename) == -1) {
181        g_warning("Failed to delete the temporary file: %s.\nThis may cause the test to be bogus.", g_strerror(errno));
182    }
183
184    WebKitWebFrame* webFrame = webkit_web_view_get_main_frame(webView);
185    GtkPrintOperation* operation = gtk_print_operation_new();
186    GtkPrintOperationAction action = GTK_PRINT_OPERATION_ACTION_EXPORT;
187    GtkPrintOperationResult result;
188
189    gtk_print_operation_set_export_filename(operation, temporaryFilename);
190    result = webkit_web_frame_print_full (webFrame, operation, action, NULL);
191
192    g_assert_cmpint(result, ==, GTK_PRINT_OPERATION_RESULT_APPLY);
193    g_assert_cmpint(g_file_test(temporaryFilename, G_FILE_TEST_IS_REGULAR), ==, TRUE);
194
195    g_unlink(temporaryFilename);
196    g_object_unref(operation);
197cleanup:
198    g_object_unref(webView);
199    g_free(temporaryFilename);
200}
201
202static void test_webkit_web_frame_response()
203{
204    WebKitWebFrame* frame = g_object_new(WEBKIT_TYPE_WEB_FRAME, NULL);
205    WebKitNetworkResponse* response = webkit_web_frame_get_network_response(frame);
206    g_assert(!response);
207    g_object_unref(frame);
208}
209
210int main(int argc, char** argv)
211{
212    g_thread_init(NULL);
213    gtk_test_init(&argc, &argv, NULL);
214
215    g_test_bug_base("https://bugs.webkit.org/");
216    g_test_add_func("/webkit/webview/create_destroy", test_webkit_web_frame_create_destroy);
217    g_test_add_func("/webkit/webview/frame-created_signal", test_webkit_web_frame_created_signal);
218    g_test_add_func("/webkit/webframe/lifetime", test_webkit_web_frame_lifetime);
219    g_test_add_func("/webkit/webview/printing", test_webkit_web_frame_printing);
220    g_test_add_func("/webkit/webview/response", test_webkit_web_frame_response);
221    return g_test_run ();
222}
223
224#else
225int main(int argc, char** argv)
226{
227    g_critical("You will need gtk-2.14.0 to run the unit tests. Doing nothing now.");
228    return 0;
229}
230
231#endif
232