[chromium] move notification related methods to TestRunner
[WebKit-https.git] / Tools / DumpRenderTree / chromium / DRTTestRunner.cpp
1 /*
2  * Copyright (C) 2010 Google Inc. All rights reserved.
3  * Copyright (C) 2010 Pawel Hajdan (phajdan.jr@chromium.org)
4  * Copyright (C) 2012 Apple Inc. All Rights Reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions are
8  * met:
9  *
10  *     * Redistributions of source code must retain the above copyright
11  * notice, this list of conditions and the following disclaimer.
12  *     * Redistributions in binary form must reproduce the above
13  * copyright notice, this list of conditions and the following disclaimer
14  * in the documentation and/or other materials provided with the
15  * distribution.
16  *     * Neither the name of Google Inc. nor the names of its
17  * contributors may be used to endorse or promote products derived from
18  * this software without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31  */
32
33 #include "config.h"
34 #include "DRTTestRunner.h"
35
36 #include "DRTDevToolsAgent.h"
37 #include "MockWebSpeechInputController.h"
38 #include "MockWebSpeechRecognizer.h"
39 #include "Task.h"
40 #include "TestShell.h"
41 #include "WebAnimationController.h"
42 #include "WebBindings.h"
43 #include "WebConsoleMessage.h"
44 #include "WebDocument.h"
45 #include "WebElement.h"
46 #include "WebFindOptions.h"
47 #include "WebFrame.h"
48 #include "WebIDBFactory.h"
49 #include "WebInputElement.h"
50 #include "WebKit.h"
51 #include "WebPrintParams.h"
52 #include "WebScriptSource.h"
53 #include "WebSecurityPolicy.h"
54 #include "WebSettings.h"
55 #include "WebSurroundingText.h"
56 #include "WebView.h"
57 #include "WebViewHost.h"
58 #include "WebWorkerInfo.h"
59 #include "platform/WebData.h"
60 #include "platform/WebSerializedScriptValue.h"
61 #include "platform/WebSize.h"
62 #include "platform/WebURL.h"
63 #include "v8/include/v8.h"
64 #include "webkit/support/webkit_support.h"
65 #include <algorithm>
66 #include <cctype>
67 #include <cstdlib>
68 #include <limits>
69 #include <sstream>
70 #include <wtf/OwnArrayPtr.h>
71 #include <wtf/text/WTFString.h>
72
73 #if OS(LINUX) || OS(ANDROID)
74 #include "linux/WebFontRendering.h"
75 #endif
76
77 using namespace WebCore;
78 using namespace WebKit;
79 using namespace WebTestRunner;
80 using namespace std;
81
82 DRTTestRunner::DRTTestRunner(TestShell* shell)
83     : m_shell(shell)
84     , m_closeRemainingWindows(false)
85     , m_showDebugLayerTree(false)
86     , m_workQueue(this)
87 {
88
89     // Initialize the map that associates methods of this class with the names
90     // they will use when called by JavaScript. The actual binding of those
91     // names to their methods will be done by calling bindToJavaScript() (defined
92     // by CppBoundClass, the parent to DRTTestRunner).
93 #if ENABLE(INPUT_SPEECH)
94     bindMethod("addMockSpeechInputResult", &DRTTestRunner::addMockSpeechInputResult);
95     bindMethod("setMockSpeechInputDumpRect", &DRTTestRunner::setMockSpeechInputDumpRect);
96 #endif
97 #if ENABLE(SCRIPTED_SPEECH)
98     bindMethod("addMockSpeechRecognitionResult", &DRTTestRunner::addMockSpeechRecognitionResult);
99     bindMethod("setMockSpeechRecognitionError", &DRTTestRunner::setMockSpeechRecognitionError);
100     bindMethod("wasMockSpeechRecognitionAborted", &DRTTestRunner::wasMockSpeechRecognitionAborted);
101 #endif
102     bindMethod("display", &DRTTestRunner::display);
103     bindMethod("displayInvalidatedRegion", &DRTTestRunner::displayInvalidatedRegion);
104     bindMethod("notifyDone", &DRTTestRunner::notifyDone);
105     bindMethod("queueBackNavigation", &DRTTestRunner::queueBackNavigation);
106     bindMethod("queueForwardNavigation", &DRTTestRunner::queueForwardNavigation);
107     bindMethod("queueLoadingScript", &DRTTestRunner::queueLoadingScript);
108     bindMethod("queueLoad", &DRTTestRunner::queueLoad);
109     bindMethod("queueLoadHTMLString", &DRTTestRunner::queueLoadHTMLString);
110     bindMethod("queueNonLoadingScript", &DRTTestRunner::queueNonLoadingScript);
111     bindMethod("queueReload", &DRTTestRunner::queueReload);
112     bindMethod("setCloseRemainingWindowsWhenComplete", &DRTTestRunner::setCloseRemainingWindowsWhenComplete);
113     bindMethod("setCustomPolicyDelegate", &DRTTestRunner::setCustomPolicyDelegate);
114     bindMethod("setWillSendRequestClearHeader", &DRTTestRunner::setWillSendRequestClearHeader);
115     bindMethod("setWillSendRequestReturnsNull", &DRTTestRunner::setWillSendRequestReturnsNull);
116     bindMethod("setWillSendRequestReturnsNullOnRedirect", &DRTTestRunner::setWillSendRequestReturnsNullOnRedirect);
117     bindMethod("waitForPolicyDelegate", &DRTTestRunner::waitForPolicyDelegate);
118     bindMethod("waitUntilDone", &DRTTestRunner::waitUntilDone);
119     bindMethod("windowCount", &DRTTestRunner::windowCount);
120
121
122     // Shared properties.
123     // webHistoryItemCount is used by tests in LayoutTests\http\tests\history
124     bindProperty("webHistoryItemCount", &m_webHistoryItemCount);
125     bindProperty("interceptPostMessage", &m_interceptPostMessage);
126 }
127
128 DRTTestRunner::~DRTTestRunner()
129 {
130 }
131
132 DRTTestRunner::WorkQueue::~WorkQueue()
133 {
134     reset();
135 }
136
137 void DRTTestRunner::WorkQueue::processWorkSoon()
138 {
139     if (m_controller->m_shell->webViewHost()->topLoadingFrame())
140         return;
141
142     if (!m_queue.isEmpty()) {
143         // We delay processing queued work to avoid recursion problems.
144         postTask(new WorkQueueTask(this));
145     } else if (!m_controller->m_waitUntilDone)
146         m_controller->m_shell->testFinished();
147 }
148
149 void DRTTestRunner::WorkQueue::processWork()
150 {
151     TestShell* shell = m_controller->m_shell;
152     // Quit doing work once a load is in progress.
153     while (!m_queue.isEmpty()) {
154         bool startedLoad = m_queue.first()->run(shell);
155         delete m_queue.takeFirst();
156         if (startedLoad)
157             return;
158     }
159
160     if (!m_controller->m_waitUntilDone && !shell->webViewHost()->topLoadingFrame())
161         shell->testFinished();
162 }
163
164 void DRTTestRunner::WorkQueue::reset()
165 {
166     m_frozen = false;
167     while (!m_queue.isEmpty())
168         delete m_queue.takeFirst();
169 }
170
171 void DRTTestRunner::WorkQueue::addWork(WorkItem* work)
172 {
173     if (m_frozen) {
174         delete work;
175         return;
176     }
177     m_queue.append(work);
178 }
179
180 void DRTTestRunner::waitUntilDone(const CppArgumentList&, CppVariant* result)
181 {
182     if (!webkit_support::BeingDebugged())
183         postDelayedTask(new NotifyDoneTimedOutTask(this), m_shell->layoutTestTimeout());
184     m_waitUntilDone = true;
185     result->setNull();
186 }
187
188 void DRTTestRunner::notifyDone(const CppArgumentList&, CppVariant* result)
189 {
190     // Test didn't timeout. Kill the timeout timer.
191     taskList()->revokeAll();
192
193     completeNotifyDone(false);
194     result->setNull();
195 }
196
197 void DRTTestRunner::completeNotifyDone(bool isTimeout)
198 {
199     if (m_waitUntilDone && !m_shell->webViewHost()->topLoadingFrame() && m_workQueue.isEmpty()) {
200         if (isTimeout)
201             m_shell->testTimedOut();
202         else
203             m_shell->testFinished();
204     }
205     m_waitUntilDone = false;
206 }
207
208 class WorkItemBackForward : public DRTTestRunner::WorkItem {
209 public:
210     WorkItemBackForward(int distance) : m_distance(distance) { }
211     bool run(TestShell* shell)
212     {
213         shell->goToOffset(m_distance);
214         return true; // FIXME: Did it really start a navigation?
215     }
216
217 private:
218     int m_distance;
219 };
220
221 void DRTTestRunner::queueBackNavigation(const CppArgumentList& arguments, CppVariant* result)
222 {
223     if (arguments.size() > 0 && arguments[0].isNumber())
224         m_workQueue.addWork(new WorkItemBackForward(-arguments[0].toInt32()));
225     result->setNull();
226 }
227
228 void DRTTestRunner::queueForwardNavigation(const CppArgumentList& arguments, CppVariant* result)
229 {
230     if (arguments.size() > 0 && arguments[0].isNumber())
231         m_workQueue.addWork(new WorkItemBackForward(arguments[0].toInt32()));
232     result->setNull();
233 }
234
235 class WorkItemReload : public DRTTestRunner::WorkItem {
236 public:
237     bool run(TestShell* shell)
238     {
239         shell->reload();
240         return true;
241     }
242 };
243
244 void DRTTestRunner::queueReload(const CppArgumentList&, CppVariant* result)
245 {
246     m_workQueue.addWork(new WorkItemReload);
247     result->setNull();
248 }
249
250 class WorkItemLoadingScript : public DRTTestRunner::WorkItem {
251 public:
252     WorkItemLoadingScript(const string& script) : m_script(script) { }
253     bool run(TestShell* shell)
254     {
255         shell->webView()->mainFrame()->executeScript(WebScriptSource(WebString::fromUTF8(m_script)));
256         return true; // FIXME: Did it really start a navigation?
257     }
258
259 private:
260     string m_script;
261 };
262
263 class WorkItemNonLoadingScript : public DRTTestRunner::WorkItem {
264 public:
265     WorkItemNonLoadingScript(const string& script) : m_script(script) { }
266     bool run(TestShell* shell)
267     {
268         shell->webView()->mainFrame()->executeScript(WebScriptSource(WebString::fromUTF8(m_script)));
269         return false;
270     }
271
272 private:
273     string m_script;
274 };
275
276 void DRTTestRunner::queueLoadingScript(const CppArgumentList& arguments, CppVariant* result)
277 {
278     if (arguments.size() > 0 && arguments[0].isString())
279         m_workQueue.addWork(new WorkItemLoadingScript(arguments[0].toString()));
280     result->setNull();
281 }
282
283 void DRTTestRunner::queueNonLoadingScript(const CppArgumentList& arguments, CppVariant* result)
284 {
285     if (arguments.size() > 0 && arguments[0].isString())
286         m_workQueue.addWork(new WorkItemNonLoadingScript(arguments[0].toString()));
287     result->setNull();
288 }
289
290 class WorkItemLoad : public DRTTestRunner::WorkItem {
291 public:
292     WorkItemLoad(const WebURL& url, const WebString& target)
293         : m_url(url)
294         , m_target(target) { }
295     bool run(TestShell* shell)
296     {
297         shell->webViewHost()->loadURLForFrame(m_url, m_target);
298         return true; // FIXME: Did it really start a navigation?
299     }
300
301 private:
302     WebURL m_url;
303     WebString m_target;
304 };
305
306 void DRTTestRunner::queueLoad(const CppArgumentList& arguments, CppVariant* result)
307 {
308     if (arguments.size() > 0 && arguments[0].isString()) {
309         // FIXME: Implement WebURL::resolve() and avoid GURL.
310         GURL currentURL = m_shell->webView()->mainFrame()->document().url();
311         GURL fullURL = currentURL.Resolve(arguments[0].toString());
312
313         string target = "";
314         if (arguments.size() > 1 && arguments[1].isString())
315             target = arguments[1].toString();
316
317         m_workQueue.addWork(new WorkItemLoad(fullURL, WebString::fromUTF8(target)));
318     }
319     result->setNull();
320 }
321
322 class WorkItemLoadHTMLString : public DRTTestRunner::WorkItem  {
323 public:
324     WorkItemLoadHTMLString(const std::string& html, const WebURL& baseURL)
325         : m_html(html)
326         , m_baseURL(baseURL) { }
327     WorkItemLoadHTMLString(const std::string& html, const WebURL& baseURL, const WebURL& unreachableURL)
328         : m_html(html)
329         , m_baseURL(baseURL)
330         , m_unreachableURL(unreachableURL) { }
331     bool run(TestShell* shell)
332     {
333         shell->webView()->mainFrame()->loadHTMLString(
334             WebKit::WebData(m_html.data(), m_html.length()), m_baseURL, m_unreachableURL);
335         return true;
336     }
337
338 private:
339     std::string m_html;
340     WebURL m_baseURL;
341     WebURL m_unreachableURL;
342 };
343
344 void DRTTestRunner::queueLoadHTMLString(const CppArgumentList& arguments, CppVariant* result)
345 {
346     if (arguments.size() > 0 && arguments[0].isString()) {
347         string html = arguments[0].toString();
348         WebURL baseURL(GURL(""));
349         if (arguments.size() > 1 && arguments[1].isString())
350             baseURL = WebURL(GURL(arguments[1].toString()));
351         if (arguments.size() > 2 && arguments[2].isString())
352             m_workQueue.addWork(new WorkItemLoadHTMLString(html, baseURL, WebURL(GURL(arguments[2].toString()))));
353         else
354             m_workQueue.addWork(new WorkItemLoadHTMLString(html, baseURL));
355     }
356     result->setNull();
357 }
358
359 void DRTTestRunner::reset()
360 {
361     TestRunner::reset();
362     m_waitUntilDone = false;
363     m_webHistoryItemCount.set(0);
364     m_interceptPostMessage.set(false);
365
366     if (m_closeRemainingWindows)
367         m_shell->closeRemainingWindows();
368     else
369         m_closeRemainingWindows = true;
370     m_workQueue.reset();
371 }
372
373 void DRTTestRunner::locationChangeDone()
374 {
375     m_webHistoryItemCount.set(m_shell->navigationEntryCount());
376
377     // No more new work after the first complete load.
378     m_workQueue.setFrozen(true);
379
380     if (!m_waitUntilDone)
381         m_workQueue.processWorkSoon();
382 }
383
384 void DRTTestRunner::policyDelegateDone()
385 {
386     ASSERT(m_waitUntilDone);
387     m_shell->testFinished();
388     m_waitUntilDone = false;
389 }
390
391 void DRTTestRunner::windowCount(const CppArgumentList&, CppVariant* result)
392 {
393     result->set(static_cast<int>(m_shell->windowCount()));
394 }
395
396 void DRTTestRunner::setCloseRemainingWindowsWhenComplete(const CppArgumentList& arguments, CppVariant* result)
397 {
398     if (arguments.size() > 0 && arguments[0].isBool())
399         m_closeRemainingWindows = arguments[0].value.boolValue;
400     result->setNull();
401 }
402
403 void DRTTestRunner::setCustomPolicyDelegate(const CppArgumentList& arguments, CppVariant* result)
404 {
405     if (arguments.size() > 0 && arguments[0].isBool()) {
406         bool enable = arguments[0].value.boolValue;
407         bool permissive = false;
408         if (arguments.size() > 1 && arguments[1].isBool())
409             permissive = arguments[1].value.boolValue;
410         m_shell->webViewHost()->setCustomPolicyDelegate(enable, permissive);
411     }
412     result->setNull();
413 }
414
415 void DRTTestRunner::waitForPolicyDelegate(const CppArgumentList&, CppVariant* result)
416 {
417     m_shell->webViewHost()->waitForPolicyDelegate();
418     m_waitUntilDone = true;
419     result->setNull();
420 }
421
422 void DRTTestRunner::setWillSendRequestClearHeader(const CppArgumentList& arguments, CppVariant* result)
423 {
424     if (arguments.size() > 0 && arguments[0].isString()) {
425         string header = arguments[0].toString();
426         if (!header.empty())
427             m_shell->webViewHost()->addClearHeader(String::fromUTF8(header.c_str()));
428     }
429     result->setNull();
430 }
431
432 void DRTTestRunner::setWillSendRequestReturnsNullOnRedirect(const CppArgumentList& arguments, CppVariant* result)
433 {
434     if (arguments.size() > 0 && arguments[0].isBool())
435         m_shell->webViewHost()->setBlockRedirects(arguments[0].value.boolValue);
436     result->setNull();
437 }
438
439 void DRTTestRunner::setWillSendRequestReturnsNull(const CppArgumentList& arguments, CppVariant* result)
440 {
441     if (arguments.size() > 0 && arguments[0].isBool())
442         m_shell->webViewHost()->setRequestReturnNull(arguments[0].value.boolValue);
443     result->setNull();
444 }
445
446 void DRTTestRunner::display(const CppArgumentList& arguments, CppVariant* result)
447 {
448     WebViewHost* host = m_shell->webViewHost();
449     const WebKit::WebSize& size = m_shell->webView()->size();
450     WebRect rect(0, 0, size.width, size.height);
451     host->proxy()->setPaintRect(rect);
452     host->paintInvalidatedRegion();
453     host->displayRepaintMask();
454     result->setNull();
455 }
456
457 void DRTTestRunner::displayInvalidatedRegion(const CppArgumentList& arguments, CppVariant* result)
458 {
459     WebViewHost* host = m_shell->webViewHost();
460     host->paintInvalidatedRegion();
461     host->displayRepaintMask();
462     result->setNull();
463 }
464
465 #if ENABLE(INPUT_SPEECH)
466 void DRTTestRunner::addMockSpeechInputResult(const CppArgumentList& arguments, CppVariant* result)
467 {
468     result->setNull();
469     if (arguments.size() < 3 || !arguments[0].isString() || !arguments[1].isNumber() || !arguments[2].isString())
470         return;
471
472     if (MockWebSpeechInputController* controller = m_shell->webViewHost()->speechInputControllerMock())
473         controller->addMockRecognitionResult(cppVariantToWebString(arguments[0]), arguments[1].toDouble(), cppVariantToWebString(arguments[2]));
474 }
475
476 void DRTTestRunner::setMockSpeechInputDumpRect(const CppArgumentList& arguments, CppVariant* result)
477 {
478     result->setNull();
479     if (arguments.size() < 1 || !arguments[0].isBool())
480         return;
481
482     if (MockWebSpeechInputController* controller = m_shell->webViewHost()->speechInputControllerMock())
483         controller->setDumpRect(arguments[0].value.boolValue);
484 }
485 #endif
486
487 #if ENABLE(SCRIPTED_SPEECH)
488 void DRTTestRunner::addMockSpeechRecognitionResult(const CppArgumentList& arguments, CppVariant* result)
489 {
490     result->setNull();
491     if (arguments.size() < 2 || !arguments[0].isString() || !arguments[1].isNumber())
492         return;
493
494     if (MockWebSpeechRecognizer* recognizer = m_shell->webViewHost()->mockSpeechRecognizer())
495         recognizer->addMockResult(cppVariantToWebString(arguments[0]), arguments[1].toDouble());
496 }
497
498 void DRTTestRunner::setMockSpeechRecognitionError(const CppArgumentList& arguments, CppVariant* result)
499 {
500     result->setNull();
501     if (arguments.size() != 2 || !arguments[0].isString() || !arguments[1].isString())
502         return;
503
504     if (MockWebSpeechRecognizer* recognizer = m_shell->webViewHost()->mockSpeechRecognizer())
505         recognizer->setError(cppVariantToWebString(arguments[0]), cppVariantToWebString(arguments[1]));
506 }
507
508 void DRTTestRunner::wasMockSpeechRecognitionAborted(const CppArgumentList&, CppVariant* result)
509 {
510     result->set(false);
511     if (MockWebSpeechRecognizer* recognizer = m_shell->webViewHost()->mockSpeechRecognizer())
512         result->set(recognizer->wasAborted());
513 }
514 #endif