Crash when following a Google search link to Twitter with Limit Adult Content enabled
[WebKit-https.git] / Tools / WebKitTestRunner / TestInvocation.cpp
1 /*
2  * Copyright (C) 2010, 2011, 2012 Apple Inc. All rights reserved.
3  * Copyright (C) 2012 Intel Corporation. All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
15  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
16  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
18  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
19  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
20  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
21  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
22  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
23  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
24  * THE POSSIBILITY OF SUCH DAMAGE.
25  */
26
27 #include "config.h"
28 #include "TestInvocation.h"
29
30 #include "PlatformWebView.h"
31 #include "StringFunctions.h"
32 #include "TestController.h"
33 #include <WebKit/WKContextPrivate.h>
34 #include <WebKit/WKCookieManager.h>
35 #include <WebKit/WKData.h>
36 #include <WebKit/WKDictionary.h>
37 #include <WebKit/WKInspector.h>
38 #include <WebKit/WKPagePrivate.h>
39 #include <WebKit/WKRetainPtr.h>
40 #include <climits>
41 #include <cstdio>
42 #include <wtf/StdLibExtras.h>
43 #include <wtf/text/CString.h>
44
45 #if PLATFORM(MAC) && !PLATFORM(IOS)
46 #include <Carbon/Carbon.h>
47 #endif
48
49 #if PLATFORM(COCOA)
50 #include <WebKit/WKPagePrivateMac.h>
51 #endif
52
53 #include <unistd.h> // For getcwd.
54
55 using namespace WebKit;
56 using namespace std;
57
58 namespace WTR {
59
60 static WKURLRef createWKURL(const char* pathOrURL)
61 {
62     if (strstr(pathOrURL, "http://") || strstr(pathOrURL, "https://") || strstr(pathOrURL, "file://"))
63         return WKURLCreateWithUTF8CString(pathOrURL);
64
65     // Creating from filesytem path.
66     size_t length = strlen(pathOrURL);
67     if (!length)
68         return 0;
69
70     const char separator = '/';
71     bool isAbsolutePath = pathOrURL[0] == separator;
72     const char* filePrefix = "file://";
73     static const size_t prefixLength = strlen(filePrefix);
74
75     std::unique_ptr<char[]> buffer;
76     if (isAbsolutePath) {
77         buffer = std::make_unique<char[]>(prefixLength + length + 1);
78         strcpy(buffer.get(), filePrefix);
79         strcpy(buffer.get() + prefixLength, pathOrURL);
80     } else {
81         buffer = std::make_unique<char[]>(prefixLength + PATH_MAX + length + 2); // 1 for the separator
82         strcpy(buffer.get(), filePrefix);
83         if (!getcwd(buffer.get() + prefixLength, PATH_MAX))
84             return 0;
85         size_t numCharacters = strlen(buffer.get());
86         buffer[numCharacters] = separator;
87         strcpy(buffer.get() + numCharacters + 1, pathOrURL);
88     }
89
90     return WKURLCreateWithUTF8CString(buffer.get());
91 }
92
93 TestInvocation::TestInvocation(const std::string& pathOrURL)
94     : m_url(AdoptWK, createWKURL(pathOrURL.c_str()))
95     , m_dumpPixels(false)
96     , m_timeout(0)
97     , m_gotInitialResponse(false)
98     , m_gotFinalMessage(false)
99     , m_gotRepaint(false)
100     , m_error(false)
101     , m_webProcessIsUnresponsive(false)
102 {
103     WKRetainPtr<WKStringRef> urlString = adoptWK(WKURLCopyString(m_url.get()));
104
105     size_t stringLength = WKStringGetLength(urlString.get());
106
107     Vector<char> urlVector;
108     urlVector.resize(stringLength + 1);
109
110     WKStringGetUTF8CString(urlString.get(), urlVector.data(), stringLength + 1);
111
112     m_urlString = String(urlVector.data(), stringLength);
113 }
114
115 TestInvocation::~TestInvocation()
116 {
117 }
118
119 WKURLRef TestInvocation::url() const
120 {
121     return m_url.get();
122 }
123
124 bool TestInvocation::urlContains(const char* searchString) const
125 {
126     return m_urlString.contains(searchString, false);
127 }
128
129 void TestInvocation::setIsPixelTest(const std::string& expectedPixelHash)
130 {
131     m_dumpPixels = true;
132     m_expectedPixelHash = expectedPixelHash;
133 }
134
135 bool TestInvocation::shouldLogFrameLoadDelegates()
136 {
137     return urlContains("loading/");
138 }
139
140 bool TestInvocation::shouldLogHistoryClientCallbacks()
141 {
142     return urlContains("globalhistory/");
143 }
144
145 void TestInvocation::invoke()
146 {
147     TestController::singleton().configureViewForTest(*this);
148
149     WKPageSetAddsVisitedLinks(TestController::singleton().mainWebView()->page(), false);
150
151     m_textOutput.clear();
152
153     TestController::singleton().setShouldLogHistoryClientCallbacks(shouldLogHistoryClientCallbacks());
154
155     WKCookieManagerSetHTTPCookieAcceptPolicy(WKContextGetCookieManager(TestController::singleton().context()), kWKHTTPCookieAcceptPolicyOnlyFromMainDocumentDomain);
156
157     // FIXME: We should clear out visited links here.
158
159     WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("BeginTest"));
160     WKRetainPtr<WKMutableDictionaryRef> beginTestMessageBody = adoptWK(WKMutableDictionaryCreate());
161
162     WKRetainPtr<WKStringRef> dumpFrameLoadDelegatesKey = adoptWK(WKStringCreateWithUTF8CString("DumpFrameLoadDelegates"));
163     WKRetainPtr<WKBooleanRef> dumpFrameLoadDelegatesValue = adoptWK(WKBooleanCreate(shouldLogFrameLoadDelegates()));
164     WKDictionarySetItem(beginTestMessageBody.get(), dumpFrameLoadDelegatesKey.get(), dumpFrameLoadDelegatesValue.get());
165
166     WKRetainPtr<WKStringRef> dumpPixelsKey = adoptWK(WKStringCreateWithUTF8CString("DumpPixels"));
167     WKRetainPtr<WKBooleanRef> dumpPixelsValue = adoptWK(WKBooleanCreate(m_dumpPixels));
168     WKDictionarySetItem(beginTestMessageBody.get(), dumpPixelsKey.get(), dumpPixelsValue.get());
169
170     WKRetainPtr<WKStringRef> useWaitToDumpWatchdogTimerKey = adoptWK(WKStringCreateWithUTF8CString("UseWaitToDumpWatchdogTimer"));
171     WKRetainPtr<WKBooleanRef> useWaitToDumpWatchdogTimerValue = adoptWK(WKBooleanCreate(TestController::singleton().useWaitToDumpWatchdogTimer()));
172     WKDictionarySetItem(beginTestMessageBody.get(), useWaitToDumpWatchdogTimerKey.get(), useWaitToDumpWatchdogTimerValue.get());
173
174     WKRetainPtr<WKStringRef> timeoutKey = adoptWK(WKStringCreateWithUTF8CString("Timeout"));
175     WKRetainPtr<WKUInt64Ref> timeoutValue = adoptWK(WKUInt64Create(m_timeout));
176     WKDictionarySetItem(beginTestMessageBody.get(), timeoutKey.get(), timeoutValue.get());
177
178     WKPagePostMessageToInjectedBundle(TestController::singleton().mainWebView()->page(), messageName.get(), beginTestMessageBody.get());
179
180     bool shouldOpenExternalURLs = false;
181
182     TestController::singleton().runUntil(m_gotInitialResponse, TestController::shortTimeout);
183     if (!m_gotInitialResponse) {
184         m_errorMessage = "Timed out waiting for initial response from web process\n";
185         m_webProcessIsUnresponsive = true;
186         goto end;
187     }
188     if (m_error)
189         goto end;
190
191     WKPageLoadURLWithShouldOpenExternalURLsPolicy(TestController::singleton().mainWebView()->page(), m_url.get(), shouldOpenExternalURLs);
192
193     TestController::singleton().runUntil(m_gotFinalMessage, TestController::noTimeout);
194     if (m_error)
195         goto end;
196
197     dumpResults();
198
199 end:
200 #if !PLATFORM(IOS)
201     if (m_gotInitialResponse)
202         WKInspectorClose(WKPageGetInspector(TestController::singleton().mainWebView()->page()));
203 #endif // !PLATFORM(IOS)
204
205     if (m_webProcessIsUnresponsive)
206         dumpWebProcessUnresponsiveness();
207     else if (!TestController::singleton().resetStateToConsistentValues()) {
208         // The process froze while loading about:blank, let's start a fresh one.
209         // It would be nice to report that the previous test froze after dumping results, but we have no way to do that.
210         TestController::singleton().terminateWebContentProcess();
211         // Make sure that we have a process, as invoke() will need one to send bundle messages for the next test.
212         TestController::singleton().reattachPageToWebProcess();
213     }
214 }
215
216 void TestInvocation::dumpWebProcessUnresponsiveness()
217 {
218     dumpWebProcessUnresponsiveness(m_errorMessage.c_str());
219 }
220
221 void TestInvocation::dumpWebProcessUnresponsiveness(const char* errorMessage)
222 {
223     char errorMessageToStderr[1024];
224 #if PLATFORM(COCOA)
225     pid_t pid = WKPageGetProcessIdentifier(TestController::singleton().mainWebView()->page());
226     sprintf(errorMessageToStderr, "#PROCESS UNRESPONSIVE - %s (pid %ld)\n", TestController::webProcessName(), static_cast<long>(pid));
227 #else
228     sprintf(errorMessageToStderr, "#PROCESS UNRESPONSIVE - %s", TestController::webProcessName());
229 #endif
230
231     dump(errorMessage, errorMessageToStderr, true);
232 }
233
234 void TestInvocation::dump(const char* textToStdout, const char* textToStderr, bool seenError)
235 {
236     printf("Content-Type: text/plain\n");
237     if (textToStdout)
238         fputs(textToStdout, stdout);
239     if (textToStderr)
240         fputs(textToStderr, stderr);
241
242     fputs("#EOF\n", stdout);
243     fputs("#EOF\n", stderr);
244     if (seenError)
245         fputs("#EOF\n", stdout);
246     fflush(stdout);
247     fflush(stderr);
248 }
249
250 void TestInvocation::forceRepaintDoneCallback(WKErrorRef error, void* context)
251 {
252     // The context may not be valid any more, e.g. if WebKit is invalidating callbacks at process exit.
253     if (error)
254         return;
255
256     TestInvocation* testInvocation = static_cast<TestInvocation*>(context);
257     RELEASE_ASSERT(TestController::singleton().isCurrentInvocation(testInvocation));
258
259     testInvocation->m_gotRepaint = true;
260     TestController::singleton().notifyDone();
261 }
262
263 void TestInvocation::dumpResults()
264 {
265     if (m_textOutput.length() || !m_audioResult)
266         dump(m_textOutput.toString().utf8().data());
267     else
268         dumpAudio(m_audioResult.get());
269
270     if (m_dumpPixels && m_pixelResult) {
271         m_gotRepaint = false;
272         WKPageForceRepaint(TestController::singleton().mainWebView()->page(), this, TestInvocation::forceRepaintDoneCallback);
273         TestController::singleton().runUntil(m_gotRepaint, TestController::shortTimeout);
274         if (!m_gotRepaint) {
275             m_errorMessage = "Timed out waiting for pre-pixel dump repaint\n";
276             m_webProcessIsUnresponsive = true;
277             return;
278         }
279         dumpPixelsAndCompareWithExpected(m_pixelResult.get(), m_repaintRects.get());
280     }
281
282     fputs("#EOF\n", stdout);
283     fflush(stdout);
284     fflush(stderr);
285 }
286
287 void TestInvocation::dumpAudio(WKDataRef audioData)
288 {
289     size_t length = WKDataGetSize(audioData);
290     if (!length)
291         return;
292
293     const unsigned char* data = WKDataGetBytes(audioData);
294
295     printf("Content-Type: audio/wav\n");
296     printf("Content-Length: %lu\n", static_cast<unsigned long>(length));
297
298     fwrite(data, 1, length, stdout);
299     printf("#EOF\n");
300     fprintf(stderr, "#EOF\n");
301 }
302
303 bool TestInvocation::compareActualHashToExpectedAndDumpResults(const char actualHash[33])
304 {
305     // Compute the hash of the bitmap context pixels
306     fprintf(stdout, "\nActualHash: %s\n", actualHash);
307
308     if (!m_expectedPixelHash.length())
309         return false;
310
311     ASSERT(m_expectedPixelHash.length() == 32);
312     fprintf(stdout, "\nExpectedHash: %s\n", m_expectedPixelHash.c_str());
313
314     // FIXME: Do case insensitive compare.
315     return m_expectedPixelHash == actualHash;
316 }
317
318 void TestInvocation::didReceiveMessageFromInjectedBundle(WKStringRef messageName, WKTypeRef messageBody)
319 {
320     if (WKStringIsEqualToUTF8CString(messageName, "Error")) {
321         // Set all states to true to stop spinning the runloop.
322         m_gotInitialResponse = true;
323         m_gotFinalMessage = true;
324         m_error = true;
325         m_errorMessage = "FAIL\n";
326         TestController::singleton().notifyDone();
327         return;
328     }
329
330     if (WKStringIsEqualToUTF8CString(messageName, "Ack")) {
331         ASSERT(WKGetTypeID(messageBody) == WKStringGetTypeID());
332         WKStringRef messageBodyString = static_cast<WKStringRef>(messageBody);
333         if (WKStringIsEqualToUTF8CString(messageBodyString, "BeginTest")) {
334             m_gotInitialResponse = true;
335             TestController::singleton().notifyDone();
336             return;
337         }
338
339         ASSERT_NOT_REACHED();
340     }
341
342     if (WKStringIsEqualToUTF8CString(messageName, "Done")) {
343         ASSERT(WKGetTypeID(messageBody) == WKDictionaryGetTypeID());
344         WKDictionaryRef messageBodyDictionary = static_cast<WKDictionaryRef>(messageBody);
345
346         WKRetainPtr<WKStringRef> pixelResultKey = adoptWK(WKStringCreateWithUTF8CString("PixelResult"));
347         m_pixelResult = static_cast<WKImageRef>(WKDictionaryGetItemForKey(messageBodyDictionary, pixelResultKey.get()));
348         ASSERT(!m_pixelResult || m_dumpPixels);
349
350         WKRetainPtr<WKStringRef> repaintRectsKey = adoptWK(WKStringCreateWithUTF8CString("RepaintRects"));
351         m_repaintRects = static_cast<WKArrayRef>(WKDictionaryGetItemForKey(messageBodyDictionary, repaintRectsKey.get()));
352
353         WKRetainPtr<WKStringRef> audioResultKey =  adoptWK(WKStringCreateWithUTF8CString("AudioResult"));
354         m_audioResult = static_cast<WKDataRef>(WKDictionaryGetItemForKey(messageBodyDictionary, audioResultKey.get()));
355
356         m_gotFinalMessage = true;
357         TestController::singleton().notifyDone();
358         return;
359     }
360
361     if (WKStringIsEqualToUTF8CString(messageName, "TextOutput")) {
362         ASSERT(WKGetTypeID(messageBody) == WKStringGetTypeID());
363         WKStringRef textOutput = static_cast<WKStringRef>(messageBody);
364         m_textOutput.append(toWTFString(textOutput));
365         return;
366     }
367
368     if (WKStringIsEqualToUTF8CString(messageName, "BeforeUnloadReturnValue")) {
369         ASSERT(WKGetTypeID(messageBody) == WKBooleanGetTypeID());
370         WKBooleanRef beforeUnloadReturnValue = static_cast<WKBooleanRef>(messageBody);
371         TestController::singleton().setBeforeUnloadReturnValue(WKBooleanGetValue(beforeUnloadReturnValue));
372         return;
373     }
374     
375     if (WKStringIsEqualToUTF8CString(messageName, "AddChromeInputField")) {
376         TestController::singleton().mainWebView()->addChromeInputField();
377         WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("CallAddChromeInputFieldCallback"));
378         WKPagePostMessageToInjectedBundle(TestController::singleton().mainWebView()->page(), messageName.get(), 0);
379         return;
380     }
381
382     if (WKStringIsEqualToUTF8CString(messageName, "RemoveChromeInputField")) {
383         TestController::singleton().mainWebView()->removeChromeInputField();
384         WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("CallRemoveChromeInputFieldCallback"));
385         WKPagePostMessageToInjectedBundle(TestController::singleton().mainWebView()->page(), messageName.get(), 0);
386         return;
387     }
388     
389     if (WKStringIsEqualToUTF8CString(messageName, "FocusWebView")) {
390         TestController::singleton().mainWebView()->makeWebViewFirstResponder();
391         WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("CallFocusWebViewCallback"));
392         WKPagePostMessageToInjectedBundle(TestController::singleton().mainWebView()->page(), messageName.get(), 0);
393         return;
394     }
395
396     if (WKStringIsEqualToUTF8CString(messageName, "SetBackingScaleFactor")) {
397         ASSERT(WKGetTypeID(messageBody) == WKDoubleGetTypeID());
398         double backingScaleFactor = WKDoubleGetValue(static_cast<WKDoubleRef>(messageBody));
399         WKPageSetCustomBackingScaleFactor(TestController::singleton().mainWebView()->page(), backingScaleFactor);
400
401         WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("CallSetBackingScaleFactorCallback"));
402         WKPagePostMessageToInjectedBundle(TestController::singleton().mainWebView()->page(), messageName.get(), 0);
403         return;
404     }
405
406     if (WKStringIsEqualToUTF8CString(messageName, "SimulateWebNotificationClick")) {
407         ASSERT(WKGetTypeID(messageBody) == WKUInt64GetTypeID());
408         uint64_t notificationID = WKUInt64GetValue(static_cast<WKUInt64Ref>(messageBody));
409         TestController::singleton().simulateWebNotificationClick(notificationID);
410         return;
411     }
412
413     if (WKStringIsEqualToUTF8CString(messageName, "SetAddsVisitedLinks")) {
414         ASSERT(WKGetTypeID(messageBody) == WKBooleanGetTypeID());
415         WKBooleanRef enabledWK = static_cast<WKBooleanRef>(messageBody);
416         WKPageSetAddsVisitedLinks(TestController::singleton().mainWebView()->page(), WKBooleanGetValue(enabledWK));
417         return;
418     }
419
420     if (WKStringIsEqualToUTF8CString(messageName, "SetGeolocationPermission")) {
421         ASSERT(WKGetTypeID(messageBody) == WKBooleanGetTypeID());
422         WKBooleanRef enabledWK = static_cast<WKBooleanRef>(messageBody);
423         TestController::singleton().setGeolocationPermission(WKBooleanGetValue(enabledWK));
424         return;
425     }
426
427     if (WKStringIsEqualToUTF8CString(messageName, "SetMockGeolocationPosition")) {
428         ASSERT(WKGetTypeID(messageBody) == WKDictionaryGetTypeID());
429         WKDictionaryRef messageBodyDictionary = static_cast<WKDictionaryRef>(messageBody);
430
431         WKRetainPtr<WKStringRef> latitudeKeyWK(AdoptWK, WKStringCreateWithUTF8CString("latitude"));
432         WKDoubleRef latitudeWK = static_cast<WKDoubleRef>(WKDictionaryGetItemForKey(messageBodyDictionary, latitudeKeyWK.get()));
433         double latitude = WKDoubleGetValue(latitudeWK);
434
435         WKRetainPtr<WKStringRef> longitudeKeyWK(AdoptWK, WKStringCreateWithUTF8CString("longitude"));
436         WKDoubleRef longitudeWK = static_cast<WKDoubleRef>(WKDictionaryGetItemForKey(messageBodyDictionary, longitudeKeyWK.get()));
437         double longitude = WKDoubleGetValue(longitudeWK);
438
439         WKRetainPtr<WKStringRef> accuracyKeyWK(AdoptWK, WKStringCreateWithUTF8CString("accuracy"));
440         WKDoubleRef accuracyWK = static_cast<WKDoubleRef>(WKDictionaryGetItemForKey(messageBodyDictionary, accuracyKeyWK.get()));
441         double accuracy = WKDoubleGetValue(accuracyWK);
442
443         WKRetainPtr<WKStringRef> providesAltitudeKeyWK(AdoptWK, WKStringCreateWithUTF8CString("providesAltitude"));
444         WKBooleanRef providesAltitudeWK = static_cast<WKBooleanRef>(WKDictionaryGetItemForKey(messageBodyDictionary, providesAltitudeKeyWK.get()));
445         bool providesAltitude = WKBooleanGetValue(providesAltitudeWK);
446
447         WKRetainPtr<WKStringRef> altitudeKeyWK(AdoptWK, WKStringCreateWithUTF8CString("altitude"));
448         WKDoubleRef altitudeWK = static_cast<WKDoubleRef>(WKDictionaryGetItemForKey(messageBodyDictionary, altitudeKeyWK.get()));
449         double altitude = WKDoubleGetValue(altitudeWK);
450
451         WKRetainPtr<WKStringRef> providesAltitudeAccuracyKeyWK(AdoptWK, WKStringCreateWithUTF8CString("providesAltitudeAccuracy"));
452         WKBooleanRef providesAltitudeAccuracyWK = static_cast<WKBooleanRef>(WKDictionaryGetItemForKey(messageBodyDictionary, providesAltitudeAccuracyKeyWK.get()));
453         bool providesAltitudeAccuracy = WKBooleanGetValue(providesAltitudeAccuracyWK);
454
455         WKRetainPtr<WKStringRef> altitudeAccuracyKeyWK(AdoptWK, WKStringCreateWithUTF8CString("altitudeAccuracy"));
456         WKDoubleRef altitudeAccuracyWK = static_cast<WKDoubleRef>(WKDictionaryGetItemForKey(messageBodyDictionary, altitudeAccuracyKeyWK.get()));
457         double altitudeAccuracy = WKDoubleGetValue(altitudeAccuracyWK);
458
459         WKRetainPtr<WKStringRef> providesHeadingKeyWK(AdoptWK, WKStringCreateWithUTF8CString("providesHeading"));
460         WKBooleanRef providesHeadingWK = static_cast<WKBooleanRef>(WKDictionaryGetItemForKey(messageBodyDictionary, providesHeadingKeyWK.get()));
461         bool providesHeading = WKBooleanGetValue(providesHeadingWK);
462
463         WKRetainPtr<WKStringRef> headingKeyWK(AdoptWK, WKStringCreateWithUTF8CString("heading"));
464         WKDoubleRef headingWK = static_cast<WKDoubleRef>(WKDictionaryGetItemForKey(messageBodyDictionary, headingKeyWK.get()));
465         double heading = WKDoubleGetValue(headingWK);
466
467         WKRetainPtr<WKStringRef> providesSpeedKeyWK(AdoptWK, WKStringCreateWithUTF8CString("providesSpeed"));
468         WKBooleanRef providesSpeedWK = static_cast<WKBooleanRef>(WKDictionaryGetItemForKey(messageBodyDictionary, providesSpeedKeyWK.get()));
469         bool providesSpeed = WKBooleanGetValue(providesSpeedWK);
470
471         WKRetainPtr<WKStringRef> speedKeyWK(AdoptWK, WKStringCreateWithUTF8CString("speed"));
472         WKDoubleRef speedWK = static_cast<WKDoubleRef>(WKDictionaryGetItemForKey(messageBodyDictionary, speedKeyWK.get()));
473         double speed = WKDoubleGetValue(speedWK);
474
475         TestController::singleton().setMockGeolocationPosition(latitude, longitude, accuracy, providesAltitude, altitude, providesAltitudeAccuracy, altitudeAccuracy, providesHeading, heading, providesSpeed, speed);
476         return;
477     }
478
479     if (WKStringIsEqualToUTF8CString(messageName, "SetMockGeolocationPositionUnavailableError")) {
480         ASSERT(WKGetTypeID(messageBody) == WKStringGetTypeID());
481         WKStringRef errorMessage = static_cast<WKStringRef>(messageBody);
482         TestController::singleton().setMockGeolocationPositionUnavailableError(errorMessage);
483         return;
484     }
485
486     if (WKStringIsEqualToUTF8CString(messageName, "SetUserMediaPermission")) {
487         ASSERT(WKGetTypeID(messageBody) == WKBooleanGetTypeID());
488         WKBooleanRef enabledWK = static_cast<WKBooleanRef>(messageBody);
489         TestController::singleton().setUserMediaPermission(WKBooleanGetValue(enabledWK));
490         return;
491     }
492
493     if (WKStringIsEqualToUTF8CString(messageName, "SetCacheModel")) {
494         ASSERT(WKGetTypeID(messageBody) == WKUInt64GetTypeID());
495         uint64_t model = WKUInt64GetValue(static_cast<WKUInt64Ref>(messageBody));
496         WKContextSetCacheModel(TestController::singleton().context(), model);
497         return;
498     }
499
500     if (WKStringIsEqualToUTF8CString(messageName, "SetCustomPolicyDelegate")) {
501         ASSERT(WKGetTypeID(messageBody) == WKDictionaryGetTypeID());
502         WKDictionaryRef messageBodyDictionary = static_cast<WKDictionaryRef>(messageBody);
503
504         WKRetainPtr<WKStringRef> enabledKeyWK(AdoptWK, WKStringCreateWithUTF8CString("enabled"));
505         WKBooleanRef enabledWK = static_cast<WKBooleanRef>(WKDictionaryGetItemForKey(messageBodyDictionary, enabledKeyWK.get()));
506         bool enabled = WKBooleanGetValue(enabledWK);
507
508         WKRetainPtr<WKStringRef> permissiveKeyWK(AdoptWK, WKStringCreateWithUTF8CString("permissive"));
509         WKBooleanRef permissiveWK = static_cast<WKBooleanRef>(WKDictionaryGetItemForKey(messageBodyDictionary, permissiveKeyWK.get()));
510         bool permissive = WKBooleanGetValue(permissiveWK);
511
512         TestController::singleton().setCustomPolicyDelegate(enabled, permissive);
513         return;
514     }
515
516     if (WKStringIsEqualToUTF8CString(messageName, "SetHidden")) {
517         ASSERT(WKGetTypeID(messageBody) == WKDictionaryGetTypeID());
518         WKDictionaryRef messageBodyDictionary = static_cast<WKDictionaryRef>(messageBody);
519
520         WKRetainPtr<WKStringRef> isInitialKeyWK(AdoptWK, WKStringCreateWithUTF8CString("hidden"));
521         WKBooleanRef hiddenWK = static_cast<WKBooleanRef>(WKDictionaryGetItemForKey(messageBodyDictionary, isInitialKeyWK.get()));
522         bool hidden = WKBooleanGetValue(hiddenWK);
523
524         TestController::singleton().setHidden(hidden);
525         return;
526     }
527
528     if (WKStringIsEqualToUTF8CString(messageName, "ProcessWorkQueue")) {
529         if (TestController::singleton().workQueueManager().processWorkQueue()) {
530             WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("WorkQueueProcessedCallback"));
531             WKPagePostMessageToInjectedBundle(TestController::singleton().mainWebView()->page(), messageName.get(), 0);
532         }
533         return;
534     }
535
536     if (WKStringIsEqualToUTF8CString(messageName, "QueueBackNavigation")) {
537         ASSERT(WKGetTypeID(messageBody) == WKUInt64GetTypeID());
538         uint64_t stepCount = WKUInt64GetValue(static_cast<WKUInt64Ref>(messageBody));
539         TestController::singleton().workQueueManager().queueBackNavigation(stepCount);
540         return;
541     }
542
543     if (WKStringIsEqualToUTF8CString(messageName, "QueueForwardNavigation")) {
544         ASSERT(WKGetTypeID(messageBody) == WKUInt64GetTypeID());
545         uint64_t stepCount = WKUInt64GetValue(static_cast<WKUInt64Ref>(messageBody));
546         TestController::singleton().workQueueManager().queueForwardNavigation(stepCount);
547         return;
548     }
549
550     if (WKStringIsEqualToUTF8CString(messageName, "QueueLoad")) {
551         ASSERT(WKGetTypeID(messageBody) == WKDictionaryGetTypeID());
552         WKDictionaryRef loadDataDictionary = static_cast<WKDictionaryRef>(messageBody);
553
554         WKRetainPtr<WKStringRef> urlKey(AdoptWK, WKStringCreateWithUTF8CString("url"));
555         WKStringRef urlWK = static_cast<WKStringRef>(WKDictionaryGetItemForKey(loadDataDictionary, urlKey.get()));
556
557         WKRetainPtr<WKStringRef> targetKey(AdoptWK, WKStringCreateWithUTF8CString("target"));
558         WKStringRef targetWK = static_cast<WKStringRef>(WKDictionaryGetItemForKey(loadDataDictionary, targetKey.get()));
559
560         WKRetainPtr<WKStringRef> shouldOpenExternalURLsKey(AdoptWK, WKStringCreateWithUTF8CString("shouldOpenExternalURLs"));
561         WKBooleanRef shouldOpenExternalURLsValueWK = static_cast<WKBooleanRef>(WKDictionaryGetItemForKey(loadDataDictionary, shouldOpenExternalURLsKey.get()));
562
563         TestController::singleton().workQueueManager().queueLoad(toWTFString(urlWK), toWTFString(targetWK), WKBooleanGetValue(shouldOpenExternalURLsValueWK));
564         return;
565     }
566
567     if (WKStringIsEqualToUTF8CString(messageName, "QueueLoadHTMLString")) {
568         ASSERT(WKGetTypeID(messageBody) == WKDictionaryGetTypeID());
569         WKDictionaryRef loadDataDictionary = static_cast<WKDictionaryRef>(messageBody);
570
571         WKRetainPtr<WKStringRef> contentKey(AdoptWK, WKStringCreateWithUTF8CString("content"));
572         WKStringRef contentWK = static_cast<WKStringRef>(WKDictionaryGetItemForKey(loadDataDictionary, contentKey.get()));
573
574         WKRetainPtr<WKStringRef> baseURLKey(AdoptWK, WKStringCreateWithUTF8CString("baseURL"));
575         WKStringRef baseURLWK = static_cast<WKStringRef>(WKDictionaryGetItemForKey(loadDataDictionary, baseURLKey.get()));
576
577         WKRetainPtr<WKStringRef> unreachableURLKey(AdoptWK, WKStringCreateWithUTF8CString("unreachableURL"));
578         WKStringRef unreachableURLWK = static_cast<WKStringRef>(WKDictionaryGetItemForKey(loadDataDictionary, unreachableURLKey.get()));
579
580         TestController::singleton().workQueueManager().queueLoadHTMLString(toWTFString(contentWK), baseURLWK ? toWTFString(baseURLWK) : String(), unreachableURLWK ? toWTFString(unreachableURLWK) : String());
581         return;
582     }
583
584     if (WKStringIsEqualToUTF8CString(messageName, "QueueReload")) {
585         TestController::singleton().workQueueManager().queueReload();
586         return;
587     }
588
589     if (WKStringIsEqualToUTF8CString(messageName, "QueueLoadingScript")) {
590         ASSERT(WKGetTypeID(messageBody) == WKStringGetTypeID());
591         WKStringRef script = static_cast<WKStringRef>(messageBody);
592         TestController::singleton().workQueueManager().queueLoadingScript(toWTFString(script));
593         return;
594     }
595
596     if (WKStringIsEqualToUTF8CString(messageName, "QueueNonLoadingScript")) {
597         ASSERT(WKGetTypeID(messageBody) == WKStringGetTypeID());
598         WKStringRef script = static_cast<WKStringRef>(messageBody);
599         TestController::singleton().workQueueManager().queueNonLoadingScript(toWTFString(script));
600         return;
601     }
602
603     if (WKStringIsEqualToUTF8CString(messageName, "SetHandlesAuthenticationChallenge")) {
604         ASSERT(WKGetTypeID(messageBody) == WKBooleanGetTypeID());
605         WKBooleanRef value = static_cast<WKBooleanRef>(messageBody);
606         TestController::singleton().setHandlesAuthenticationChallenges(WKBooleanGetValue(value));
607         return;
608     }
609
610     if (WKStringIsEqualToUTF8CString(messageName, "SetAuthenticationUsername")) {
611         ASSERT(WKGetTypeID(messageBody) == WKStringGetTypeID());
612         WKStringRef username = static_cast<WKStringRef>(messageBody);
613         TestController::singleton().setAuthenticationUsername(toWTFString(username));
614         return;
615     }
616
617     if (WKStringIsEqualToUTF8CString(messageName, "SetAuthenticationPassword")) {
618         ASSERT(WKGetTypeID(messageBody) == WKStringGetTypeID());
619         WKStringRef password = static_cast<WKStringRef>(messageBody);
620         TestController::singleton().setAuthenticationPassword(toWTFString(password));
621         return;
622     }
623
624     if (WKStringIsEqualToUTF8CString(messageName, "SetBlockAllPlugins")) {
625         ASSERT(WKGetTypeID(messageBody) == WKBooleanGetTypeID());
626         WKBooleanRef shouldBlock = static_cast<WKBooleanRef>(messageBody);
627         TestController::singleton().setBlockAllPlugins(WKBooleanGetValue(shouldBlock));
628         return;
629     }
630
631     if (WKStringIsEqualToUTF8CString(messageName, "SetShouldDecideNavigationPolicyAfterDelay")) {
632         ASSERT(WKGetTypeID(messageBody) == WKBooleanGetTypeID());
633         WKBooleanRef value = static_cast<WKBooleanRef>(messageBody);
634         TestController::singleton().setShouldDecideNavigationPolicyAfterDelay(WKBooleanGetValue(value));
635         return;
636     }
637
638     ASSERT_NOT_REACHED();
639 }
640
641 WKRetainPtr<WKTypeRef> TestInvocation::didReceiveSynchronousMessageFromInjectedBundle(WKStringRef messageName, WKTypeRef messageBody)
642 {
643     if (WKStringIsEqualToUTF8CString(messageName, "SetWindowIsKey")) {
644         ASSERT(WKGetTypeID(messageBody) == WKBooleanGetTypeID());
645         WKBooleanRef isKeyValue = static_cast<WKBooleanRef>(messageBody);
646         TestController::singleton().mainWebView()->setWindowIsKey(WKBooleanGetValue(isKeyValue));
647         return 0;
648     }
649
650     if (WKStringIsEqualToUTF8CString(messageName, "IsGeolocationClientActive")) {
651         bool isActive = TestController::singleton().isGeolocationProviderActive();
652         WKRetainPtr<WKTypeRef> result(AdoptWK, WKBooleanCreate(isActive));
653         return result;
654     }
655
656     if (WKStringIsEqualToUTF8CString(messageName, "IsWorkQueueEmpty")) {
657         bool isEmpty = TestController::singleton().workQueueManager().isWorkQueueEmpty();
658         WKRetainPtr<WKTypeRef> result(AdoptWK, WKBooleanCreate(isEmpty));
659         return result;
660     }
661
662     if (WKStringIsEqualToUTF8CString(messageName, "SecureEventInputIsEnabled")) {
663 #if PLATFORM(MAC) && !PLATFORM(IOS)
664         WKRetainPtr<WKBooleanRef> result(AdoptWK, WKBooleanCreate(IsSecureEventInputEnabled()));
665 #else
666         WKRetainPtr<WKBooleanRef> result(AdoptWK, WKBooleanCreate(false));
667 #endif
668         return result;
669     }
670
671     if (WKStringIsEqualToUTF8CString(messageName, "SetAlwaysAcceptCookies")) {
672         WKBooleanRef accept = static_cast<WKBooleanRef>(messageBody);
673         WKHTTPCookieAcceptPolicy policy = WKBooleanGetValue(accept) ? kWKHTTPCookieAcceptPolicyAlways : kWKHTTPCookieAcceptPolicyOnlyFromMainDocumentDomain;
674         // FIXME: This updates the policy in WebProcess and in NetworkProcess asynchronously, which might break some tests' expectations.
675         WKCookieManagerSetHTTPCookieAcceptPolicy(WKContextGetCookieManager(TestController::singleton().context()), policy);
676         return 0;
677     }
678
679     ASSERT_NOT_REACHED();
680     return 0;
681 }
682
683 void TestInvocation::outputText(const WTF::String& text)
684 {
685     m_textOutput.append(text);
686 }
687
688 } // namespace WTR