283cc34c8aca0b9005dbabee1a0b825597cb3e04
[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 "WebNotificationPresenter.h"
52 #include "WebPrintParams.h"
53 #include "WebScriptSource.h"
54 #include "WebSecurityPolicy.h"
55 #include "WebSettings.h"
56 #include "WebSurroundingText.h"
57 #include "WebView.h"
58 #include "WebViewHost.h"
59 #include "WebWorkerInfo.h"
60 #include "platform/WebData.h"
61 #include "platform/WebSerializedScriptValue.h"
62 #include "platform/WebSize.h"
63 #include "platform/WebURL.h"
64 #include "v8/include/v8.h"
65 #include "webkit/support/webkit_support.h"
66 #include <algorithm>
67 #include <cctype>
68 #include <cstdlib>
69 #include <limits>
70 #include <sstream>
71 #include <wtf/OwnArrayPtr.h>
72 #include <wtf/text/WTFString.h>
73
74 #if OS(LINUX) || OS(ANDROID)
75 #include "linux/WebFontRendering.h"
76 #endif
77
78 using namespace WebCore;
79 using namespace WebKit;
80 using namespace WebTestRunner;
81 using namespace std;
82
83 DRTTestRunner::DRTTestRunner(TestShell* shell)
84     : m_shell(shell)
85     , m_closeRemainingWindows(false)
86     , m_showDebugLayerTree(false)
87     , m_workQueue(this)
88 {
89
90     // Initialize the map that associates methods of this class with the names
91     // they will use when called by JavaScript. The actual binding of those
92     // names to their methods will be done by calling bindToJavaScript() (defined
93     // by CppBoundClass, the parent to DRTTestRunner).
94 #if ENABLE(INPUT_SPEECH)
95     bindMethod("addMockSpeechInputResult", &DRTTestRunner::addMockSpeechInputResult);
96     bindMethod("setMockSpeechInputDumpRect", &DRTTestRunner::setMockSpeechInputDumpRect);
97 #endif
98 #if ENABLE(SCRIPTED_SPEECH)
99     bindMethod("addMockSpeechRecognitionResult", &DRTTestRunner::addMockSpeechRecognitionResult);
100     bindMethod("setMockSpeechRecognitionError", &DRTTestRunner::setMockSpeechRecognitionError);
101     bindMethod("wasMockSpeechRecognitionAborted", &DRTTestRunner::wasMockSpeechRecognitionAborted);
102 #endif
103     bindMethod("display", &DRTTestRunner::display);
104     bindMethod("displayInvalidatedRegion", &DRTTestRunner::displayInvalidatedRegion);
105 #if ENABLE(NOTIFICATIONS)
106     bindMethod("grantWebNotificationPermission", &DRTTestRunner::grantWebNotificationPermission);
107 #endif
108     bindMethod("notifyDone", &DRTTestRunner::notifyDone);
109     bindMethod("queueBackNavigation", &DRTTestRunner::queueBackNavigation);
110     bindMethod("queueForwardNavigation", &DRTTestRunner::queueForwardNavigation);
111     bindMethod("queueLoadingScript", &DRTTestRunner::queueLoadingScript);
112     bindMethod("queueLoad", &DRTTestRunner::queueLoad);
113     bindMethod("queueLoadHTMLString", &DRTTestRunner::queueLoadHTMLString);
114     bindMethod("queueNonLoadingScript", &DRTTestRunner::queueNonLoadingScript);
115     bindMethod("queueReload", &DRTTestRunner::queueReload);
116     bindMethod("setCloseRemainingWindowsWhenComplete", &DRTTestRunner::setCloseRemainingWindowsWhenComplete);
117     bindMethod("setCustomPolicyDelegate", &DRTTestRunner::setCustomPolicyDelegate);
118     bindMethod("setWillSendRequestClearHeader", &DRTTestRunner::setWillSendRequestClearHeader);
119     bindMethod("setWillSendRequestReturnsNull", &DRTTestRunner::setWillSendRequestReturnsNull);
120     bindMethod("setWillSendRequestReturnsNullOnRedirect", &DRTTestRunner::setWillSendRequestReturnsNullOnRedirect);
121 #if ENABLE(NOTIFICATIONS)
122     bindMethod("simulateLegacyWebNotificationClick", &DRTTestRunner::simulateLegacyWebNotificationClick);
123 #endif
124     bindMethod("waitForPolicyDelegate", &DRTTestRunner::waitForPolicyDelegate);
125     bindMethod("waitUntilDone", &DRTTestRunner::waitUntilDone);
126     bindMethod("windowCount", &DRTTestRunner::windowCount);
127
128
129     // Shared properties.
130     // webHistoryItemCount is used by tests in LayoutTests\http\tests\history
131     bindProperty("webHistoryItemCount", &m_webHistoryItemCount);
132     bindProperty("interceptPostMessage", &m_interceptPostMessage);
133 }
134
135 DRTTestRunner::~DRTTestRunner()
136 {
137 }
138
139 DRTTestRunner::WorkQueue::~WorkQueue()
140 {
141     reset();
142 }
143
144 void DRTTestRunner::WorkQueue::processWorkSoon()
145 {
146     if (m_controller->m_shell->webViewHost()->topLoadingFrame())
147         return;
148
149     if (!m_queue.isEmpty()) {
150         // We delay processing queued work to avoid recursion problems.
151         postTask(new WorkQueueTask(this));
152     } else if (!m_controller->m_waitUntilDone)
153         m_controller->m_shell->testFinished();
154 }
155
156 void DRTTestRunner::WorkQueue::processWork()
157 {
158     TestShell* shell = m_controller->m_shell;
159     // Quit doing work once a load is in progress.
160     while (!m_queue.isEmpty()) {
161         bool startedLoad = m_queue.first()->run(shell);
162         delete m_queue.takeFirst();
163         if (startedLoad)
164             return;
165     }
166
167     if (!m_controller->m_waitUntilDone && !shell->webViewHost()->topLoadingFrame())
168         shell->testFinished();
169 }
170
171 void DRTTestRunner::WorkQueue::reset()
172 {
173     m_frozen = false;
174     while (!m_queue.isEmpty())
175         delete m_queue.takeFirst();
176 }
177
178 void DRTTestRunner::WorkQueue::addWork(WorkItem* work)
179 {
180     if (m_frozen) {
181         delete work;
182         return;
183     }
184     m_queue.append(work);
185 }
186
187 void DRTTestRunner::waitUntilDone(const CppArgumentList&, CppVariant* result)
188 {
189     if (!webkit_support::BeingDebugged())
190         postDelayedTask(new NotifyDoneTimedOutTask(this), m_shell->layoutTestTimeout());
191     m_waitUntilDone = true;
192     result->setNull();
193 }
194
195 void DRTTestRunner::notifyDone(const CppArgumentList&, CppVariant* result)
196 {
197     // Test didn't timeout. Kill the timeout timer.
198     taskList()->revokeAll();
199
200     completeNotifyDone(false);
201     result->setNull();
202 }
203
204 void DRTTestRunner::completeNotifyDone(bool isTimeout)
205 {
206     if (m_waitUntilDone && !m_shell->webViewHost()->topLoadingFrame() && m_workQueue.isEmpty()) {
207         if (isTimeout)
208             m_shell->testTimedOut();
209         else
210             m_shell->testFinished();
211     }
212     m_waitUntilDone = false;
213 }
214
215 class WorkItemBackForward : public DRTTestRunner::WorkItem {
216 public:
217     WorkItemBackForward(int distance) : m_distance(distance) { }
218     bool run(TestShell* shell)
219     {
220         shell->goToOffset(m_distance);
221         return true; // FIXME: Did it really start a navigation?
222     }
223
224 private:
225     int m_distance;
226 };
227
228 void DRTTestRunner::queueBackNavigation(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 void DRTTestRunner::queueForwardNavigation(const CppArgumentList& arguments, CppVariant* result)
236 {
237     if (arguments.size() > 0 && arguments[0].isNumber())
238         m_workQueue.addWork(new WorkItemBackForward(arguments[0].toInt32()));
239     result->setNull();
240 }
241
242 class WorkItemReload : public DRTTestRunner::WorkItem {
243 public:
244     bool run(TestShell* shell)
245     {
246         shell->reload();
247         return true;
248     }
249 };
250
251 void DRTTestRunner::queueReload(const CppArgumentList&, CppVariant* result)
252 {
253     m_workQueue.addWork(new WorkItemReload);
254     result->setNull();
255 }
256
257 class WorkItemLoadingScript : public DRTTestRunner::WorkItem {
258 public:
259     WorkItemLoadingScript(const string& script) : m_script(script) { }
260     bool run(TestShell* shell)
261     {
262         shell->webView()->mainFrame()->executeScript(WebScriptSource(WebString::fromUTF8(m_script)));
263         return true; // FIXME: Did it really start a navigation?
264     }
265
266 private:
267     string m_script;
268 };
269
270 class WorkItemNonLoadingScript : public DRTTestRunner::WorkItem {
271 public:
272     WorkItemNonLoadingScript(const string& script) : m_script(script) { }
273     bool run(TestShell* shell)
274     {
275         shell->webView()->mainFrame()->executeScript(WebScriptSource(WebString::fromUTF8(m_script)));
276         return false;
277     }
278
279 private:
280     string m_script;
281 };
282
283 void DRTTestRunner::queueLoadingScript(const CppArgumentList& arguments, CppVariant* result)
284 {
285     if (arguments.size() > 0 && arguments[0].isString())
286         m_workQueue.addWork(new WorkItemLoadingScript(arguments[0].toString()));
287     result->setNull();
288 }
289
290 void DRTTestRunner::queueNonLoadingScript(const CppArgumentList& arguments, CppVariant* result)
291 {
292     if (arguments.size() > 0 && arguments[0].isString())
293         m_workQueue.addWork(new WorkItemNonLoadingScript(arguments[0].toString()));
294     result->setNull();
295 }
296
297 class WorkItemLoad : public DRTTestRunner::WorkItem {
298 public:
299     WorkItemLoad(const WebURL& url, const WebString& target)
300         : m_url(url)
301         , m_target(target) { }
302     bool run(TestShell* shell)
303     {
304         shell->webViewHost()->loadURLForFrame(m_url, m_target);
305         return true; // FIXME: Did it really start a navigation?
306     }
307
308 private:
309     WebURL m_url;
310     WebString m_target;
311 };
312
313 void DRTTestRunner::queueLoad(const CppArgumentList& arguments, CppVariant* result)
314 {
315     if (arguments.size() > 0 && arguments[0].isString()) {
316         // FIXME: Implement WebURL::resolve() and avoid GURL.
317         GURL currentURL = m_shell->webView()->mainFrame()->document().url();
318         GURL fullURL = currentURL.Resolve(arguments[0].toString());
319
320         string target = "";
321         if (arguments.size() > 1 && arguments[1].isString())
322             target = arguments[1].toString();
323
324         m_workQueue.addWork(new WorkItemLoad(fullURL, WebString::fromUTF8(target)));
325     }
326     result->setNull();
327 }
328
329 class WorkItemLoadHTMLString : public DRTTestRunner::WorkItem  {
330 public:
331     WorkItemLoadHTMLString(const std::string& html, const WebURL& baseURL)
332         : m_html(html)
333         , m_baseURL(baseURL) { }
334     WorkItemLoadHTMLString(const std::string& html, const WebURL& baseURL, const WebURL& unreachableURL)
335         : m_html(html)
336         , m_baseURL(baseURL)
337         , m_unreachableURL(unreachableURL) { }
338     bool run(TestShell* shell)
339     {
340         shell->webView()->mainFrame()->loadHTMLString(
341             WebKit::WebData(m_html.data(), m_html.length()), m_baseURL, m_unreachableURL);
342         return true;
343     }
344
345 private:
346     std::string m_html;
347     WebURL m_baseURL;
348     WebURL m_unreachableURL;
349 };
350
351 void DRTTestRunner::queueLoadHTMLString(const CppArgumentList& arguments, CppVariant* result)
352 {
353     if (arguments.size() > 0 && arguments[0].isString()) {
354         string html = arguments[0].toString();
355         WebURL baseURL(GURL(""));
356         if (arguments.size() > 1 && arguments[1].isString())
357             baseURL = WebURL(GURL(arguments[1].toString()));
358         if (arguments.size() > 2 && arguments[2].isString())
359             m_workQueue.addWork(new WorkItemLoadHTMLString(html, baseURL, WebURL(GURL(arguments[2].toString()))));
360         else
361             m_workQueue.addWork(new WorkItemLoadHTMLString(html, baseURL));
362     }
363     result->setNull();
364 }
365
366 void DRTTestRunner::reset()
367 {
368     TestRunner::reset();
369     m_waitUntilDone = false;
370     m_webHistoryItemCount.set(0);
371     m_interceptPostMessage.set(false);
372
373     if (m_closeRemainingWindows)
374         m_shell->closeRemainingWindows();
375     else
376         m_closeRemainingWindows = true;
377     m_workQueue.reset();
378 }
379
380 void DRTTestRunner::locationChangeDone()
381 {
382     m_webHistoryItemCount.set(m_shell->navigationEntryCount());
383
384     // No more new work after the first complete load.
385     m_workQueue.setFrozen(true);
386
387     if (!m_waitUntilDone)
388         m_workQueue.processWorkSoon();
389 }
390
391 void DRTTestRunner::policyDelegateDone()
392 {
393     ASSERT(m_waitUntilDone);
394     m_shell->testFinished();
395     m_waitUntilDone = false;
396 }
397
398 void DRTTestRunner::windowCount(const CppArgumentList&, CppVariant* result)
399 {
400     result->set(static_cast<int>(m_shell->windowCount()));
401 }
402
403 void DRTTestRunner::setCloseRemainingWindowsWhenComplete(const CppArgumentList& arguments, CppVariant* result)
404 {
405     if (arguments.size() > 0 && arguments[0].isBool())
406         m_closeRemainingWindows = arguments[0].value.boolValue;
407     result->setNull();
408 }
409
410 void DRTTestRunner::setCustomPolicyDelegate(const CppArgumentList& arguments, CppVariant* result)
411 {
412     if (arguments.size() > 0 && arguments[0].isBool()) {
413         bool enable = arguments[0].value.boolValue;
414         bool permissive = false;
415         if (arguments.size() > 1 && arguments[1].isBool())
416             permissive = arguments[1].value.boolValue;
417         m_shell->webViewHost()->setCustomPolicyDelegate(enable, permissive);
418     }
419     result->setNull();
420 }
421
422 void DRTTestRunner::waitForPolicyDelegate(const CppArgumentList&, CppVariant* result)
423 {
424     m_shell->webViewHost()->waitForPolicyDelegate();
425     m_waitUntilDone = true;
426     result->setNull();
427 }
428
429 void DRTTestRunner::setWillSendRequestClearHeader(const CppArgumentList& arguments, CppVariant* result)
430 {
431     if (arguments.size() > 0 && arguments[0].isString()) {
432         string header = arguments[0].toString();
433         if (!header.empty())
434             m_shell->webViewHost()->addClearHeader(String::fromUTF8(header.c_str()));
435     }
436     result->setNull();
437 }
438
439 void DRTTestRunner::setWillSendRequestReturnsNullOnRedirect(const CppArgumentList& arguments, CppVariant* result)
440 {
441     if (arguments.size() > 0 && arguments[0].isBool())
442         m_shell->webViewHost()->setBlockRedirects(arguments[0].value.boolValue);
443     result->setNull();
444 }
445
446 void DRTTestRunner::setWillSendRequestReturnsNull(const CppArgumentList& arguments, CppVariant* result)
447 {
448     if (arguments.size() > 0 && arguments[0].isBool())
449         m_shell->webViewHost()->setRequestReturnNull(arguments[0].value.boolValue);
450     result->setNull();
451 }
452
453
454 #if ENABLE(NOTIFICATIONS)
455 void DRTTestRunner::grantWebNotificationPermission(const CppArgumentList& arguments, CppVariant* result)
456 {
457     if (arguments.size() != 1 || !arguments[0].isString()) {
458         result->set(false);
459         return;
460     }
461 #if ENABLE(NOTIFICATIONS) || ENABLE(LEGACY_NOTIFICATIONS)
462     m_shell->notificationPresenter()->grantPermission(cppVariantToWebString(arguments[0]));
463 #endif
464     result->set(true);
465 }
466
467 void DRTTestRunner::simulateLegacyWebNotificationClick(const CppArgumentList& arguments, CppVariant* result)
468 {
469     if (arguments.size() != 1 || !arguments[0].isString()) {
470         result->set(false);
471         return;
472     }
473 #if ENABLE(NOTIFICATIONS) || ENABLE(LEGACY_NOTIFICATIONS)
474     if (m_shell->notificationPresenter()->simulateClick(cppVariantToWebString(arguments[0])))
475         result->set(true);
476     else
477 #endif
478         result->set(false);
479 }
480 #endif
481
482 void DRTTestRunner::display(const CppArgumentList& arguments, CppVariant* result)
483 {
484     WebViewHost* host = m_shell->webViewHost();
485     const WebKit::WebSize& size = m_shell->webView()->size();
486     WebRect rect(0, 0, size.width, size.height);
487     host->proxy()->setPaintRect(rect);
488     host->paintInvalidatedRegion();
489     host->displayRepaintMask();
490     result->setNull();
491 }
492
493 void DRTTestRunner::displayInvalidatedRegion(const CppArgumentList& arguments, CppVariant* result)
494 {
495     WebViewHost* host = m_shell->webViewHost();
496     host->paintInvalidatedRegion();
497     host->displayRepaintMask();
498     result->setNull();
499 }
500
501 #if ENABLE(INPUT_SPEECH)
502 void DRTTestRunner::addMockSpeechInputResult(const CppArgumentList& arguments, CppVariant* result)
503 {
504     result->setNull();
505     if (arguments.size() < 3 || !arguments[0].isString() || !arguments[1].isNumber() || !arguments[2].isString())
506         return;
507
508     if (MockWebSpeechInputController* controller = m_shell->webViewHost()->speechInputControllerMock())
509         controller->addMockRecognitionResult(cppVariantToWebString(arguments[0]), arguments[1].toDouble(), cppVariantToWebString(arguments[2]));
510 }
511
512 void DRTTestRunner::setMockSpeechInputDumpRect(const CppArgumentList& arguments, CppVariant* result)
513 {
514     result->setNull();
515     if (arguments.size() < 1 || !arguments[0].isBool())
516         return;
517
518     if (MockWebSpeechInputController* controller = m_shell->webViewHost()->speechInputControllerMock())
519         controller->setDumpRect(arguments[0].value.boolValue);
520 }
521 #endif
522
523 #if ENABLE(SCRIPTED_SPEECH)
524 void DRTTestRunner::addMockSpeechRecognitionResult(const CppArgumentList& arguments, CppVariant* result)
525 {
526     result->setNull();
527     if (arguments.size() < 2 || !arguments[0].isString() || !arguments[1].isNumber())
528         return;
529
530     if (MockWebSpeechRecognizer* recognizer = m_shell->webViewHost()->mockSpeechRecognizer())
531         recognizer->addMockResult(cppVariantToWebString(arguments[0]), arguments[1].toDouble());
532 }
533
534 void DRTTestRunner::setMockSpeechRecognitionError(const CppArgumentList& arguments, CppVariant* result)
535 {
536     result->setNull();
537     if (arguments.size() != 2 || !arguments[0].isString() || !arguments[1].isString())
538         return;
539
540     if (MockWebSpeechRecognizer* recognizer = m_shell->webViewHost()->mockSpeechRecognizer())
541         recognizer->setError(cppVariantToWebString(arguments[0]), cppVariantToWebString(arguments[1]));
542 }
543
544 void DRTTestRunner::wasMockSpeechRecognitionAborted(const CppArgumentList&, CppVariant* result)
545 {
546     result->set(false);
547     if (MockWebSpeechRecognizer* recognizer = m_shell->webViewHost()->mockSpeechRecognizer())
548         result->set(recognizer->wasAborted());
549 }
550 #endif