1/*
2 * Copyright (C) 2012 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 "config.h"
21
22#include "WebViewTest.h"
23#include <wtf/Vector.h>
24#include <wtf/glib/GRefPtr.h>
25
26class InspectorTest: public WebViewTest {
27public:
28 MAKE_GLIB_TEST_FIXTURE(InspectorTest);
29
30 enum InspectorEvents {
31 OpenWindow,
32 BringToFront,
33 Closed,
34 Attach,
35 Detach
36 };
37
38 static gboolean openWindowCallback(WebKitWebInspector*, InspectorTest* test)
39 {
40 return test->openWindow();
41 }
42
43 static gboolean bringToFrontCallback(WebKitWebInspector*, InspectorTest* test)
44 {
45 return test->bringToFront();
46 }
47
48 static void closedCallback(WebKitWebInspector*, InspectorTest* test)
49 {
50 return test->closed();
51 }
52
53 static gboolean attachCallback(WebKitWebInspector*, InspectorTest* test)
54 {
55 return test->attach();
56 }
57
58 static gboolean detachCallback(WebKitWebInspector*, InspectorTest* test)
59 {
60 return test->detach();
61 }
62
63 static const unsigned gMinimumAttachedInspectorWidth = 750;
64 static const unsigned gMinimumAttachedInspectorHeight = 250;
65
66 InspectorTest()
67 : WebViewTest()
68 , m_inspector(webkit_web_view_get_inspector(m_webView))
69 {
70 webkit_settings_set_enable_developer_extras(webkit_web_view_get_settings(m_webView), TRUE);
71 assertObjectIsDeletedWhenTestFinishes(G_OBJECT(m_inspector));
72 g_signal_connect(m_inspector, "open-window", G_CALLBACK(openWindowCallback), this);
73 g_signal_connect(m_inspector, "bring-to-front", G_CALLBACK(bringToFrontCallback), this);
74 g_signal_connect(m_inspector, "closed", G_CALLBACK(closedCallback), this);
75 g_signal_connect(m_inspector, "attach", G_CALLBACK(attachCallback), this);
76 g_signal_connect(m_inspector, "detach", G_CALLBACK(detachCallback), this);
77 }
78
79 ~InspectorTest()
80 {
81 g_signal_handlers_disconnect_matched(m_inspector, G_SIGNAL_MATCH_DATA, 0, 0, 0, 0, this);
82 }
83
84 virtual bool openWindow()
85 {
86 m_events.append(OpenWindow);
87 g_main_loop_quit(m_mainLoop);
88 return TRUE;
89 }
90
91 virtual bool bringToFront()
92 {
93 m_events.append(BringToFront);
94 g_main_loop_quit(m_mainLoop);
95 return FALSE;
96 }
97
98 virtual void closed()
99 {
100 m_events.append(Closed);
101 }
102
103 virtual bool attach()
104 {
105 m_events.append(Attach);
106 return TRUE;
107 }
108
109 virtual bool detach()
110 {
111 m_events.append(Detach);
112 return TRUE;
113 }
114
115
116 static gboolean showIdle(InspectorTest* test)
117 {
118 webkit_web_inspector_show(test->m_inspector);
119 return FALSE;
120 }
121
122 void show()
123 {
124 g_idle_add(reinterpret_cast<GSourceFunc>(showIdle), this);
125 g_main_loop_run(m_mainLoop);
126 }
127
128 static void canAttachChanged(InspectorTest* test)
129 {
130 g_main_loop_quit(test->m_mainLoop);
131 }
132
133 void resizeViewAndAttach()
134 {
135 // Resize the view to make room for the inspector.
136 if (!webkit_web_inspector_get_can_attach(m_inspector)) {
137 unsigned long handler = g_signal_connect_swapped(m_inspector, "notify::can-attach", G_CALLBACK(canAttachChanged), this);
138 resizeView(gMinimumAttachedInspectorWidth, (gMinimumAttachedInspectorHeight + 1) * 4 / 3);
139 g_main_loop_run(m_mainLoop);
140 g_signal_handler_disconnect(m_inspector, handler);
141 }
142
143 g_assert_true(webkit_web_inspector_get_can_attach(m_inspector));
144 webkit_web_inspector_attach(m_inspector);
145 }
146
147 static gboolean detachIdle(InspectorTest* test)
148 {
149 webkit_web_inspector_detach(test->m_inspector);
150 return FALSE;
151 }
152
153 void detachAndWaitUntilWindowOpened()
154 {
155 g_idle_add(reinterpret_cast<GSourceFunc>(detachIdle), this);
156 g_main_loop_run(m_mainLoop);
157 }
158
159 void close()
160 {
161 webkit_web_inspector_close(m_inspector);
162 }
163
164 WebKitWebInspector* m_inspector;
165 Vector<InspectorEvents> m_events;
166};
167
168static void testInspectorDefault(InspectorTest* test, gconstpointer)
169{
170 test->showInWindowAndWaitUntilMapped(GTK_WINDOW_TOPLEVEL);
171 test->resizeView(200, 200);
172 test->loadHtml("<html><body><p>WebKitGTK+ Inspector test</p></body></html>", 0);
173 test->waitUntilLoadFinished();
174
175 test->show();
176 // We don't add the view to a container, so consume the weak ref with GRefPtr.
177 GRefPtr<WebKitWebViewBase> inspectorView = webkit_web_inspector_get_web_view(test->m_inspector);
178 g_assert_nonnull(inspectorView.get());
179 test->assertObjectIsDeletedWhenTestFinishes(G_OBJECT(inspectorView.get()));
180 g_assert_false(webkit_web_inspector_is_attached(test->m_inspector));
181 g_assert_cmpuint(webkit_web_inspector_get_attached_height(test->m_inspector), ==, 0);
182 g_assert_false(webkit_web_inspector_get_can_attach(test->m_inspector));
183 Vector<InspectorTest::InspectorEvents>& events = test->m_events;
184 g_assert_cmpint(events.size(), ==, 1);
185 g_assert_cmpint(events[0], ==, InspectorTest::OpenWindow);
186 test->m_events.clear();
187
188 test->show();
189 events = test->m_events;
190 g_assert_cmpint(events.size(), ==, 1);
191 g_assert_cmpint(events[0], ==, InspectorTest::BringToFront);
192 test->m_events.clear();
193
194 test->resizeViewAndAttach();
195 g_assert_true(webkit_web_inspector_is_attached(test->m_inspector));
196 g_assert_cmpuint(webkit_web_inspector_get_attached_height(test->m_inspector), >=, InspectorTest::gMinimumAttachedInspectorHeight);
197 events = test->m_events;
198 g_assert_cmpint(events.size(), ==, 1);
199 g_assert_cmpint(events[0], ==, InspectorTest::Attach);
200 test->m_events.clear();
201
202 test->detachAndWaitUntilWindowOpened();
203 g_assert_false(webkit_web_inspector_is_attached(test->m_inspector));
204 events = test->m_events;
205 g_assert_cmpint(events.size(), ==, 2);
206 g_assert_cmpint(events[0], ==, InspectorTest::Detach);
207 g_assert_cmpint(events[1], ==, InspectorTest::OpenWindow);
208 test->m_events.clear();
209
210 test->close();
211 events = test->m_events;
212 g_assert_cmpint(events.size(), ==, 1);
213 g_assert_cmpint(events[0], ==, InspectorTest::Closed);
214 test->m_events.clear();
215}
216
217class CustomInspectorTest: public InspectorTest {
218public:
219 MAKE_GLIB_TEST_FIXTURE(CustomInspectorTest);
220
221 CustomInspectorTest()
222 : InspectorTest()
223 , m_inspectorWindow(0)
224 {
225 }
226
227 ~CustomInspectorTest()
228 {
229 if (m_inspectorWindow)
230 gtk_widget_destroy(m_inspectorWindow);
231 }
232
233 bool openWindow()
234 {
235 g_assert_null(m_inspectorWindow);
236 m_inspectorWindow = gtk_window_new(GTK_WINDOW_TOPLEVEL);
237 WebKitWebViewBase* inspectorView = webkit_web_inspector_get_web_view(m_inspector);
238 g_assert_nonnull(inspectorView);
239 gtk_container_add(GTK_CONTAINER(m_inspectorWindow), GTK_WIDGET(inspectorView));
240 gtk_widget_show_all(m_inspectorWindow);
241
242 return InspectorTest::openWindow();
243 }
244
245 void closed()
246 {
247 if (m_inspectorWindow) {
248 gtk_widget_destroy(m_inspectorWindow);
249 m_inspectorWindow = 0;
250 }
251
252 return InspectorTest::closed();
253 }
254
255 bool attach()
256 {
257 GRefPtr<WebKitWebViewBase> inspectorView = webkit_web_inspector_get_web_view(m_inspector);
258 if (m_inspectorWindow) {
259 gtk_container_remove(GTK_CONTAINER(m_inspectorWindow), GTK_WIDGET(inspectorView.get()));
260 gtk_widget_destroy(m_inspectorWindow);
261 m_inspectorWindow = 0;
262 }
263
264 GtkWidget* pane;
265 if (gtk_bin_get_child(GTK_BIN(m_parentWindow)) == GTK_WIDGET(m_webView)) {
266 GRefPtr<WebKitWebView> inspectedView = m_webView;
267 gtk_container_remove(GTK_CONTAINER(m_parentWindow), GTK_WIDGET(m_webView));
268 pane = gtk_paned_new(GTK_ORIENTATION_VERTICAL);
269 gtk_paned_add1(GTK_PANED(pane), GTK_WIDGET(m_webView));
270 gtk_container_add(GTK_CONTAINER(m_parentWindow), pane);
271 gtk_widget_show_all(pane);
272 } else
273 pane = gtk_bin_get_child(GTK_BIN(m_parentWindow));
274 gtk_paned_set_position(GTK_PANED(pane), webkit_web_inspector_get_attached_height(m_inspector));
275 gtk_paned_add2(GTK_PANED(pane), GTK_WIDGET(inspectorView.get()));
276
277 return InspectorTest::attach();
278 }
279
280 bool detach()
281 {
282 GRefPtr<WebKitWebViewBase> inspectorView = webkit_web_inspector_get_web_view(m_inspector);
283 GtkWidget* pane = gtk_bin_get_child(GTK_BIN(m_parentWindow));
284 g_assert_true(GTK_IS_PANED(pane));
285 gtk_container_remove(GTK_CONTAINER(pane), GTK_WIDGET(inspectorView.get()));
286 return InspectorTest::detach();
287 }
288
289 void destroyWindow()
290 {
291 g_assert_nonnull(m_inspectorWindow);
292 gtk_widget_destroy(m_inspectorWindow);
293 m_inspectorWindow = 0;
294 }
295
296 GtkWidget* m_inspectorWindow;
297};
298
299static void testInspectorManualAttachDetach(CustomInspectorTest* test, gconstpointer)
300{
301 test->showInWindowAndWaitUntilMapped(GTK_WINDOW_TOPLEVEL);
302 test->resizeView(200, 200);
303 test->loadHtml("<html><body><p>WebKitGTK+ Inspector test</p></body></html>", 0);
304 test->waitUntilLoadFinished();
305
306 test->show();
307 test->assertObjectIsDeletedWhenTestFinishes(G_OBJECT(webkit_web_inspector_get_web_view(test->m_inspector)));
308 g_assert_false(webkit_web_inspector_is_attached(test->m_inspector));
309 Vector<InspectorTest::InspectorEvents>& events = test->m_events;
310 g_assert_cmpint(events.size(), ==, 1);
311 g_assert_cmpint(events[0], ==, InspectorTest::OpenWindow);
312 test->m_events.clear();
313
314 test->resizeViewAndAttach();
315 g_assert_true(webkit_web_inspector_is_attached(test->m_inspector));
316 g_assert_cmpuint(webkit_web_inspector_get_attached_height(test->m_inspector), >=, InspectorTest::gMinimumAttachedInspectorHeight);
317 events = test->m_events;
318 g_assert_cmpint(events.size(), ==, 1);
319 g_assert_cmpint(events[0], ==, InspectorTest::Attach);
320 test->m_events.clear();
321
322 test->detachAndWaitUntilWindowOpened();
323 g_assert_false(webkit_web_inspector_is_attached(test->m_inspector));
324 events = test->m_events;
325 g_assert_cmpint(events.size(), ==, 2);
326 g_assert_cmpint(events[0], ==, InspectorTest::Detach);
327 g_assert_cmpint(events[1], ==, InspectorTest::OpenWindow);
328 test->m_events.clear();
329
330 test->resizeViewAndAttach();
331 g_assert_true(webkit_web_inspector_is_attached(test->m_inspector));
332 test->m_events.clear();
333 test->close();
334 events = test->m_events;
335 g_assert_cmpint(events.size(), ==, 2);
336 g_assert_cmpint(events[0], ==, InspectorTest::Detach);
337 g_assert_cmpint(events[1], ==, InspectorTest::Closed);
338 test->m_events.clear();
339}
340
341static void testInspectorCustomContainerDestroyed(CustomInspectorTest* test, gconstpointer)
342{
343 test->showInWindowAndWaitUntilMapped(GTK_WINDOW_TOPLEVEL);
344 test->resizeView(200, 200);
345 test->loadHtml("<html><body><p>WebKitGTK+ Inspector test</p></body></html>", 0);
346 test->waitUntilLoadFinished();
347
348 test->show();
349 test->assertObjectIsDeletedWhenTestFinishes(G_OBJECT(webkit_web_inspector_get_web_view(test->m_inspector)));
350 g_assert_false(webkit_web_inspector_is_attached(test->m_inspector));
351
352 test->m_events.clear();
353 test->destroyWindow();
354 Vector<InspectorTest::InspectorEvents>& events = test->m_events;
355 g_assert_cmpint(events.size(), ==, 1);
356 g_assert_cmpint(events[0], ==, InspectorTest::Closed);
357 test->m_events.clear();
358}
359
360void beforeAll()
361{
362 InspectorTest::add("WebKitWebInspector", "default", testInspectorDefault);
363 CustomInspectorTest::add("WebKitWebInspector", "manual-attach-detach", testInspectorManualAttachDetach);
364 CustomInspectorTest::add("WebKitWebInspector", "custom-container-destroyed", testInspectorCustomContainerDestroyed);
365}
366
367void afterAll()
368{
369}
370