Resource Load Statistics: Add alternate classification method
[WebKit-https.git] / Tools / WebKitTestRunner / TestInvocation.cpp
1 /*
2  * Copyright (C) 2010-2017 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 "UIScriptController.h"
34 #include "WebCoreTestSupport.h"
35 #include <WebKit/WKContextPrivate.h>
36 #include <WebKit/WKCookieManager.h>
37 #include <WebKit/WKData.h>
38 #include <WebKit/WKDictionary.h>
39 #include <WebKit/WKInspector.h>
40 #include <WebKit/WKPagePrivate.h>
41 #include <WebKit/WKRetainPtr.h>
42 #include <WebKit/WKWebsiteDataStoreRef.h>
43 #include <climits>
44 #include <cstdio>
45 #include <unistd.h>
46 #include <wtf/StdLibExtras.h>
47 #include <wtf/text/CString.h>
48
49 #if PLATFORM(MAC) && !PLATFORM(IOS)
50 #include <Carbon/Carbon.h>
51 #endif
52
53 #if PLATFORM(COCOA)
54 #include <WebKit/WKPagePrivateMac.h>
55 #endif
56
57 using namespace JSC;
58 using namespace WebKit;
59 using namespace std;
60
61 namespace WTR {
62
63 TestInvocation::TestInvocation(WKURLRef url, const TestOptions& options)
64     : m_options(options)
65     , m_url(url)
66 {
67     WKRetainPtr<WKStringRef> urlString = adoptWK(WKURLCopyString(m_url.get()));
68
69     size_t stringLength = WKStringGetLength(urlString.get());
70
71     Vector<char> urlVector;
72     urlVector.resize(stringLength + 1);
73
74     WKStringGetUTF8CString(urlString.get(), urlVector.data(), stringLength + 1);
75
76     m_urlString = String(urlVector.data(), stringLength);
77 }
78
79 TestInvocation::~TestInvocation()
80 {
81     if (m_pendingUIScriptInvocationData)
82         m_pendingUIScriptInvocationData->testInvocation = nullptr;
83 }
84
85 WKURLRef TestInvocation::url() const
86 {
87     return m_url.get();
88 }
89
90 bool TestInvocation::urlContains(const char* searchString) const
91 {
92     return m_urlString.contains(searchString, false);
93 }
94
95 void TestInvocation::setIsPixelTest(const std::string& expectedPixelHash)
96 {
97     m_dumpPixels = true;
98     m_expectedPixelHash = expectedPixelHash;
99 }
100
101 double TestInvocation::shortTimeout() const
102 {
103     if (!m_timeout) {
104         // Running WKTR directly, without webkitpy.
105         return TestController::defaultShortTimeout;
106     }
107
108     // This is not exactly correct for the way short timeout is used - it should not depend on whether a test is "slow",
109     // but it currently does. There is no way to know what a normal test's timeout is, as webkitpy only passes timeouts
110     // for each test individually.
111     // But there shouldn't be any observable negative consequences from this.
112     return m_timeout / 1000. / 2;
113 }
114
115 bool TestInvocation::shouldLogFrameLoadDelegates() const
116 {
117     return urlContains("loading/");
118 }
119
120 bool TestInvocation::shouldLogHistoryClientCallbacks() const
121 {
122     return urlContains("globalhistory/");
123 }
124
125 void TestInvocation::invoke()
126 {
127     TestController::singleton().configureViewForTest(*this);
128
129     WKPageSetAddsVisitedLinks(TestController::singleton().mainWebView()->page(), false);
130
131     m_textOutput.clear();
132
133     TestController::singleton().setShouldLogHistoryClientCallbacks(shouldLogHistoryClientCallbacks());
134
135     WKCookieManagerSetHTTPCookieAcceptPolicy(WKContextGetCookieManager(TestController::singleton().context()), kWKHTTPCookieAcceptPolicyOnlyFromMainDocumentDomain);
136
137     // FIXME: We should clear out visited links here.
138
139     WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("BeginTest"));
140     WKRetainPtr<WKMutableDictionaryRef> beginTestMessageBody = adoptWK(WKMutableDictionaryCreate());
141
142     WKRetainPtr<WKStringRef> dumpFrameLoadDelegatesKey = adoptWK(WKStringCreateWithUTF8CString("DumpFrameLoadDelegates"));
143     WKRetainPtr<WKBooleanRef> dumpFrameLoadDelegatesValue = adoptWK(WKBooleanCreate(shouldLogFrameLoadDelegates()));
144     WKDictionarySetItem(beginTestMessageBody.get(), dumpFrameLoadDelegatesKey.get(), dumpFrameLoadDelegatesValue.get());
145
146     WKRetainPtr<WKStringRef> useFlexibleViewportKey = adoptWK(WKStringCreateWithUTF8CString("UseFlexibleViewport"));
147     WKRetainPtr<WKBooleanRef> useFlexibleViewportValue = adoptWK(WKBooleanCreate(options().useFlexibleViewport));
148     WKDictionarySetItem(beginTestMessageBody.get(), useFlexibleViewportKey.get(), useFlexibleViewportValue.get());
149
150     WKRetainPtr<WKStringRef> dumpPixelsKey = adoptWK(WKStringCreateWithUTF8CString("DumpPixels"));
151     WKRetainPtr<WKBooleanRef> dumpPixelsValue = adoptWK(WKBooleanCreate(m_dumpPixels));
152     WKDictionarySetItem(beginTestMessageBody.get(), dumpPixelsKey.get(), dumpPixelsValue.get());
153
154     WKRetainPtr<WKStringRef> useWaitToDumpWatchdogTimerKey = adoptWK(WKStringCreateWithUTF8CString("UseWaitToDumpWatchdogTimer"));
155     WKRetainPtr<WKBooleanRef> useWaitToDumpWatchdogTimerValue = adoptWK(WKBooleanCreate(TestController::singleton().useWaitToDumpWatchdogTimer()));
156     WKDictionarySetItem(beginTestMessageBody.get(), useWaitToDumpWatchdogTimerKey.get(), useWaitToDumpWatchdogTimerValue.get());
157
158     WKRetainPtr<WKStringRef> timeoutKey = adoptWK(WKStringCreateWithUTF8CString("Timeout"));
159     WKRetainPtr<WKUInt64Ref> timeoutValue = adoptWK(WKUInt64Create(m_timeout));
160     WKDictionarySetItem(beginTestMessageBody.get(), timeoutKey.get(), timeoutValue.get());
161
162     WKRetainPtr<WKStringRef> dumpJSConsoleLogInStdErrKey = adoptWK(WKStringCreateWithUTF8CString("DumpJSConsoleLogInStdErr"));
163     WKRetainPtr<WKBooleanRef> dumpJSConsoleLogInStdErrValue = adoptWK(WKBooleanCreate(m_dumpJSConsoleLogInStdErr));
164     WKDictionarySetItem(beginTestMessageBody.get(), dumpJSConsoleLogInStdErrKey.get(), dumpJSConsoleLogInStdErrValue.get());
165
166     WKPagePostMessageToInjectedBundle(TestController::singleton().mainWebView()->page(), messageName.get(), beginTestMessageBody.get());
167
168     bool shouldOpenExternalURLs = false;
169
170     TestController::singleton().runUntil(m_gotInitialResponse, shortTimeout());
171     if (!m_gotInitialResponse) {
172         m_errorMessage = "Timed out waiting for initial response from web process\n";
173         m_webProcessIsUnresponsive = true;
174         goto end;
175     }
176     if (m_error)
177         goto end;
178
179     WKPageLoadURLWithShouldOpenExternalURLsPolicy(TestController::singleton().mainWebView()->page(), m_url.get(), shouldOpenExternalURLs);
180
181     TestController::singleton().runUntil(m_gotFinalMessage, TestController::noTimeout);
182     if (m_error)
183         goto end;
184
185     dumpResults();
186
187 end:
188 #if !PLATFORM(IOS)
189     if (m_gotInitialResponse)
190         WKInspectorClose(WKPageGetInspector(TestController::singleton().mainWebView()->page()));
191 #endif // !PLATFORM(IOS)
192
193     if (m_webProcessIsUnresponsive)
194         dumpWebProcessUnresponsiveness();
195     else if (TestController::singleton().resetStateToConsistentValues(m_options))
196         return;
197
198     // The process is unresponsive, so let's start a new one.
199     TestController::singleton().terminateWebContentProcess();
200     // Make sure that we have a process, as invoke() will need one to send bundle messages for the next test.
201     TestController::singleton().reattachPageToWebProcess();
202 }
203
204 void TestInvocation::dumpWebProcessUnresponsiveness()
205 {
206     dumpWebProcessUnresponsiveness(m_errorMessage.c_str());
207 }
208
209 void TestInvocation::dumpWebProcessUnresponsiveness(const char* errorMessage)
210 {
211     fprintf(stderr, "%s", errorMessage);
212     char buffer[1024] = { };
213 #if PLATFORM(COCOA)
214     pid_t pid = WKPageGetProcessIdentifier(TestController::singleton().mainWebView()->page());
215     snprintf(buffer, sizeof(buffer), "#PROCESS UNRESPONSIVE - %s (pid %ld)\n", TestController::webProcessName(), static_cast<long>(pid));
216 #else
217     snprintf(buffer, sizeof(buffer), "#PROCESS UNRESPONSIVE - %s\n", TestController::webProcessName());
218 #endif
219
220     dump(errorMessage, buffer, true);
221     
222     if (!TestController::singleton().usingServerMode())
223         return;
224     
225     if (isatty(fileno(stdin)) || isatty(fileno(stderr)))
226         fputs("Grab an image of the stack, then hit enter...\n", stderr);
227     
228     if (!fgets(buffer, sizeof(buffer), stdin) || strcmp(buffer, "#SAMPLE FINISHED\n"))
229         fprintf(stderr, "Failed receive expected sample response, got:\n\t\"%s\"\nContinuing...\n", buffer);
230 }
231
232 void TestInvocation::dump(const char* textToStdout, const char* textToStderr, bool seenError)
233 {
234     printf("Content-Type: text/plain\n");
235     if (textToStdout)
236         fputs(textToStdout, stdout);
237     if (textToStderr)
238         fputs(textToStderr, stderr);
239
240     fputs("#EOF\n", stdout);
241     fputs("#EOF\n", stderr);
242     if (seenError)
243         fputs("#EOF\n", stdout);
244     fflush(stdout);
245     fflush(stderr);
246 }
247
248 void TestInvocation::forceRepaintDoneCallback(WKErrorRef error, void* context)
249 {
250     // The context may not be valid any more, e.g. if WebKit is invalidating callbacks at process exit.
251     if (error)
252         return;
253
254     TestInvocation* testInvocation = static_cast<TestInvocation*>(context);
255     RELEASE_ASSERT(TestController::singleton().isCurrentInvocation(testInvocation));
256
257     testInvocation->m_gotRepaint = true;
258     TestController::singleton().notifyDone();
259 }
260
261 void TestInvocation::dumpResults()
262 {
263     if (m_textOutput.length() || !m_audioResult)
264         dump(m_textOutput.toString().utf8().data());
265     else
266         dumpAudio(m_audioResult.get());
267
268     if (m_dumpPixels) {
269         if (m_pixelResult)
270             dumpPixelsAndCompareWithExpected(m_pixelResult.get(), m_repaintRects.get(), TestInvocation::SnapshotResultType::WebContents);
271         else if (m_pixelResultIsPending) {
272             m_gotRepaint = false;
273             WKPageForceRepaint(TestController::singleton().mainWebView()->page(), this, TestInvocation::forceRepaintDoneCallback);
274             TestController::singleton().runUntil(m_gotRepaint, shortTimeout());
275             if (!m_gotRepaint) {
276                 m_errorMessage = "Timed out waiting for pre-pixel dump repaint\n";
277                 m_webProcessIsUnresponsive = true;
278                 return;
279             }
280
281             WKRetainPtr<WKImageRef> windowSnapshot = TestController::singleton().mainWebView()->windowSnapshotImage();
282             dumpPixelsAndCompareWithExpected(windowSnapshot.get(), m_repaintRects.get(), TestInvocation::SnapshotResultType::WebView);
283         }
284     }
285
286     fputs("#EOF\n", stdout);
287     fflush(stdout);
288     fflush(stderr);
289 }
290
291 void TestInvocation::dumpAudio(WKDataRef audioData)
292 {
293     size_t length = WKDataGetSize(audioData);
294     if (!length)
295         return;
296
297     const unsigned char* data = WKDataGetBytes(audioData);
298
299     printf("Content-Type: audio/wav\n");
300     printf("Content-Length: %lu\n", static_cast<unsigned long>(length));
301
302     fwrite(data, 1, length, stdout);
303     printf("#EOF\n");
304     fprintf(stderr, "#EOF\n");
305 }
306
307 bool TestInvocation::compareActualHashToExpectedAndDumpResults(const char actualHash[33])
308 {
309     // Compute the hash of the bitmap context pixels
310     fprintf(stdout, "\nActualHash: %s\n", actualHash);
311
312     if (!m_expectedPixelHash.length())
313         return false;
314
315     ASSERT(m_expectedPixelHash.length() == 32);
316     fprintf(stdout, "\nExpectedHash: %s\n", m_expectedPixelHash.c_str());
317
318     // FIXME: Do case insensitive compare.
319     return m_expectedPixelHash == actualHash;
320 }
321
322 void TestInvocation::didReceiveMessageFromInjectedBundle(WKStringRef messageName, WKTypeRef messageBody)
323 {
324     if (WKStringIsEqualToUTF8CString(messageName, "Error")) {
325         // Set all states to true to stop spinning the runloop.
326         m_gotInitialResponse = true;
327         m_gotFinalMessage = true;
328         m_error = true;
329         m_errorMessage = "FAIL\n";
330         TestController::singleton().notifyDone();
331         return;
332     }
333
334     if (WKStringIsEqualToUTF8CString(messageName, "Ack")) {
335         ASSERT(WKGetTypeID(messageBody) == WKStringGetTypeID());
336         WKStringRef messageBodyString = static_cast<WKStringRef>(messageBody);
337         if (WKStringIsEqualToUTF8CString(messageBodyString, "BeginTest")) {
338             m_gotInitialResponse = true;
339             TestController::singleton().notifyDone();
340             return;
341         }
342
343         ASSERT_NOT_REACHED();
344     }
345
346     if (WKStringIsEqualToUTF8CString(messageName, "Done")) {
347         ASSERT(WKGetTypeID(messageBody) == WKDictionaryGetTypeID());
348         WKDictionaryRef messageBodyDictionary = static_cast<WKDictionaryRef>(messageBody);
349
350         WKRetainPtr<WKStringRef> pixelResultIsPendingKey = adoptWK(WKStringCreateWithUTF8CString("PixelResultIsPending"));
351         WKBooleanRef pixelResultIsPending = static_cast<WKBooleanRef>(WKDictionaryGetItemForKey(messageBodyDictionary, pixelResultIsPendingKey.get()));
352         m_pixelResultIsPending = WKBooleanGetValue(pixelResultIsPending);
353
354         if (!m_pixelResultIsPending) {
355             WKRetainPtr<WKStringRef> pixelResultKey = adoptWK(WKStringCreateWithUTF8CString("PixelResult"));
356             m_pixelResult = static_cast<WKImageRef>(WKDictionaryGetItemForKey(messageBodyDictionary, pixelResultKey.get()));
357             ASSERT(!m_pixelResult || m_dumpPixels);
358         }
359
360         WKRetainPtr<WKStringRef> repaintRectsKey = adoptWK(WKStringCreateWithUTF8CString("RepaintRects"));
361         m_repaintRects = static_cast<WKArrayRef>(WKDictionaryGetItemForKey(messageBodyDictionary, repaintRectsKey.get()));
362
363         WKRetainPtr<WKStringRef> audioResultKey =  adoptWK(WKStringCreateWithUTF8CString("AudioResult"));
364         m_audioResult = static_cast<WKDataRef>(WKDictionaryGetItemForKey(messageBodyDictionary, audioResultKey.get()));
365
366         m_gotFinalMessage = true;
367         TestController::singleton().notifyDone();
368         return;
369     }
370
371     if (WKStringIsEqualToUTF8CString(messageName, "TextOutput")) {
372         ASSERT(WKGetTypeID(messageBody) == WKStringGetTypeID());
373         WKStringRef textOutput = static_cast<WKStringRef>(messageBody);
374         m_textOutput.append(toWTFString(textOutput));
375         return;
376     }
377
378     if (WKStringIsEqualToUTF8CString(messageName, "DumpToStdErr")) {
379         ASSERT(WKGetTypeID(messageBody) == WKStringGetTypeID());
380         WKStringRef textOutput = static_cast<WKStringRef>(messageBody);
381         fprintf(stderr, "%s", toWTFString(textOutput).utf8().data());
382         return;
383     }
384
385     if (WKStringIsEqualToUTF8CString(messageName, "BeforeUnloadReturnValue")) {
386         ASSERT(WKGetTypeID(messageBody) == WKBooleanGetTypeID());
387         WKBooleanRef beforeUnloadReturnValue = static_cast<WKBooleanRef>(messageBody);
388         TestController::singleton().setBeforeUnloadReturnValue(WKBooleanGetValue(beforeUnloadReturnValue));
389         return;
390     }
391     
392     if (WKStringIsEqualToUTF8CString(messageName, "AddChromeInputField")) {
393         TestController::singleton().mainWebView()->addChromeInputField();
394         WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("CallAddChromeInputFieldCallback"));
395         WKPagePostMessageToInjectedBundle(TestController::singleton().mainWebView()->page(), messageName.get(), 0);
396         return;
397     }
398
399     if (WKStringIsEqualToUTF8CString(messageName, "RemoveChromeInputField")) {
400         TestController::singleton().mainWebView()->removeChromeInputField();
401         WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("CallRemoveChromeInputFieldCallback"));
402         WKPagePostMessageToInjectedBundle(TestController::singleton().mainWebView()->page(), messageName.get(), 0);
403         return;
404     }
405     
406     if (WKStringIsEqualToUTF8CString(messageName, "FocusWebView")) {
407         TestController::singleton().mainWebView()->makeWebViewFirstResponder();
408         WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("CallFocusWebViewCallback"));
409         WKPagePostMessageToInjectedBundle(TestController::singleton().mainWebView()->page(), messageName.get(), 0);
410         return;
411     }
412
413     if (WKStringIsEqualToUTF8CString(messageName, "SetBackingScaleFactor")) {
414         ASSERT(WKGetTypeID(messageBody) == WKDoubleGetTypeID());
415         double backingScaleFactor = WKDoubleGetValue(static_cast<WKDoubleRef>(messageBody));
416         WKPageSetCustomBackingScaleFactor(TestController::singleton().mainWebView()->page(), backingScaleFactor);
417
418         WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("CallSetBackingScaleFactorCallback"));
419         WKPagePostMessageToInjectedBundle(TestController::singleton().mainWebView()->page(), messageName.get(), 0);
420         return;
421     }
422
423     if (WKStringIsEqualToUTF8CString(messageName, "SimulateWebNotificationClick")) {
424         ASSERT(WKGetTypeID(messageBody) == WKUInt64GetTypeID());
425         uint64_t notificationID = WKUInt64GetValue(static_cast<WKUInt64Ref>(messageBody));
426         TestController::singleton().simulateWebNotificationClick(notificationID);
427         return;
428     }
429
430     if (WKStringIsEqualToUTF8CString(messageName, "SetAddsVisitedLinks")) {
431         ASSERT(WKGetTypeID(messageBody) == WKBooleanGetTypeID());
432         WKBooleanRef enabledWK = static_cast<WKBooleanRef>(messageBody);
433         WKPageSetAddsVisitedLinks(TestController::singleton().mainWebView()->page(), WKBooleanGetValue(enabledWK));
434         return;
435     }
436
437     if (WKStringIsEqualToUTF8CString(messageName, "SetGeolocationPermission")) {
438         ASSERT(WKGetTypeID(messageBody) == WKBooleanGetTypeID());
439         WKBooleanRef enabledWK = static_cast<WKBooleanRef>(messageBody);
440         TestController::singleton().setGeolocationPermission(WKBooleanGetValue(enabledWK));
441         return;
442     }
443
444     if (WKStringIsEqualToUTF8CString(messageName, "SetMockGeolocationPosition")) {
445         ASSERT(WKGetTypeID(messageBody) == WKDictionaryGetTypeID());
446         WKDictionaryRef messageBodyDictionary = static_cast<WKDictionaryRef>(messageBody);
447
448         WKRetainPtr<WKStringRef> latitudeKeyWK(AdoptWK, WKStringCreateWithUTF8CString("latitude"));
449         WKDoubleRef latitudeWK = static_cast<WKDoubleRef>(WKDictionaryGetItemForKey(messageBodyDictionary, latitudeKeyWK.get()));
450         double latitude = WKDoubleGetValue(latitudeWK);
451
452         WKRetainPtr<WKStringRef> longitudeKeyWK(AdoptWK, WKStringCreateWithUTF8CString("longitude"));
453         WKDoubleRef longitudeWK = static_cast<WKDoubleRef>(WKDictionaryGetItemForKey(messageBodyDictionary, longitudeKeyWK.get()));
454         double longitude = WKDoubleGetValue(longitudeWK);
455
456         WKRetainPtr<WKStringRef> accuracyKeyWK(AdoptWK, WKStringCreateWithUTF8CString("accuracy"));
457         WKDoubleRef accuracyWK = static_cast<WKDoubleRef>(WKDictionaryGetItemForKey(messageBodyDictionary, accuracyKeyWK.get()));
458         double accuracy = WKDoubleGetValue(accuracyWK);
459
460         WKRetainPtr<WKStringRef> providesAltitudeKeyWK(AdoptWK, WKStringCreateWithUTF8CString("providesAltitude"));
461         WKBooleanRef providesAltitudeWK = static_cast<WKBooleanRef>(WKDictionaryGetItemForKey(messageBodyDictionary, providesAltitudeKeyWK.get()));
462         bool providesAltitude = WKBooleanGetValue(providesAltitudeWK);
463
464         WKRetainPtr<WKStringRef> altitudeKeyWK(AdoptWK, WKStringCreateWithUTF8CString("altitude"));
465         WKDoubleRef altitudeWK = static_cast<WKDoubleRef>(WKDictionaryGetItemForKey(messageBodyDictionary, altitudeKeyWK.get()));
466         double altitude = WKDoubleGetValue(altitudeWK);
467
468         WKRetainPtr<WKStringRef> providesAltitudeAccuracyKeyWK(AdoptWK, WKStringCreateWithUTF8CString("providesAltitudeAccuracy"));
469         WKBooleanRef providesAltitudeAccuracyWK = static_cast<WKBooleanRef>(WKDictionaryGetItemForKey(messageBodyDictionary, providesAltitudeAccuracyKeyWK.get()));
470         bool providesAltitudeAccuracy = WKBooleanGetValue(providesAltitudeAccuracyWK);
471
472         WKRetainPtr<WKStringRef> altitudeAccuracyKeyWK(AdoptWK, WKStringCreateWithUTF8CString("altitudeAccuracy"));
473         WKDoubleRef altitudeAccuracyWK = static_cast<WKDoubleRef>(WKDictionaryGetItemForKey(messageBodyDictionary, altitudeAccuracyKeyWK.get()));
474         double altitudeAccuracy = WKDoubleGetValue(altitudeAccuracyWK);
475
476         WKRetainPtr<WKStringRef> providesHeadingKeyWK(AdoptWK, WKStringCreateWithUTF8CString("providesHeading"));
477         WKBooleanRef providesHeadingWK = static_cast<WKBooleanRef>(WKDictionaryGetItemForKey(messageBodyDictionary, providesHeadingKeyWK.get()));
478         bool providesHeading = WKBooleanGetValue(providesHeadingWK);
479
480         WKRetainPtr<WKStringRef> headingKeyWK(AdoptWK, WKStringCreateWithUTF8CString("heading"));
481         WKDoubleRef headingWK = static_cast<WKDoubleRef>(WKDictionaryGetItemForKey(messageBodyDictionary, headingKeyWK.get()));
482         double heading = WKDoubleGetValue(headingWK);
483
484         WKRetainPtr<WKStringRef> providesSpeedKeyWK(AdoptWK, WKStringCreateWithUTF8CString("providesSpeed"));
485         WKBooleanRef providesSpeedWK = static_cast<WKBooleanRef>(WKDictionaryGetItemForKey(messageBodyDictionary, providesSpeedKeyWK.get()));
486         bool providesSpeed = WKBooleanGetValue(providesSpeedWK);
487
488         WKRetainPtr<WKStringRef> speedKeyWK(AdoptWK, WKStringCreateWithUTF8CString("speed"));
489         WKDoubleRef speedWK = static_cast<WKDoubleRef>(WKDictionaryGetItemForKey(messageBodyDictionary, speedKeyWK.get()));
490         double speed = WKDoubleGetValue(speedWK);
491
492         TestController::singleton().setMockGeolocationPosition(latitude, longitude, accuracy, providesAltitude, altitude, providesAltitudeAccuracy, altitudeAccuracy, providesHeading, heading, providesSpeed, speed);
493         return;
494     }
495
496     if (WKStringIsEqualToUTF8CString(messageName, "SetMockGeolocationPositionUnavailableError")) {
497         ASSERT(WKGetTypeID(messageBody) == WKStringGetTypeID());
498         WKStringRef errorMessage = static_cast<WKStringRef>(messageBody);
499         TestController::singleton().setMockGeolocationPositionUnavailableError(errorMessage);
500         return;
501     }
502
503     if (WKStringIsEqualToUTF8CString(messageName, "SetUserMediaPermission")) {
504         ASSERT(WKGetTypeID(messageBody) == WKBooleanGetTypeID());
505         WKBooleanRef enabledWK = static_cast<WKBooleanRef>(messageBody);
506         TestController::singleton().setUserMediaPermission(WKBooleanGetValue(enabledWK));
507         return;
508     }
509
510     if (WKStringIsEqualToUTF8CString(messageName, "SetUserMediaPersistentPermissionForOrigin")) {
511         ASSERT(WKGetTypeID(messageBody) == WKDictionaryGetTypeID());
512         WKDictionaryRef messageBodyDictionary = static_cast<WKDictionaryRef>(messageBody);
513
514         WKRetainPtr<WKStringRef> permissionKeyWK(AdoptWK, WKStringCreateWithUTF8CString("permission"));
515         WKBooleanRef permissionWK = static_cast<WKBooleanRef>(WKDictionaryGetItemForKey(messageBodyDictionary, permissionKeyWK.get()));
516         bool permission = WKBooleanGetValue(permissionWK);
517
518         WKRetainPtr<WKStringRef> originKey(AdoptWK, WKStringCreateWithUTF8CString("origin"));
519         WKStringRef originWK = static_cast<WKStringRef>(WKDictionaryGetItemForKey(messageBodyDictionary, originKey.get()));
520
521         WKRetainPtr<WKStringRef> parentOriginKey(AdoptWK, WKStringCreateWithUTF8CString("parentOrigin"));
522         WKStringRef parentOriginWK = static_cast<WKStringRef>(WKDictionaryGetItemForKey(messageBodyDictionary, parentOriginKey.get()));
523
524         TestController::singleton().setUserMediaPersistentPermissionForOrigin(permission, originWK, parentOriginWK);
525         return;
526     }
527
528     if (WKStringIsEqualToUTF8CString(messageName, "ResetUserMediaPermissionRequestCountForOrigin")) {
529         ASSERT(WKGetTypeID(messageBody) == WKDictionaryGetTypeID());
530         WKDictionaryRef messageBodyDictionary = static_cast<WKDictionaryRef>(messageBody);
531
532         WKRetainPtr<WKStringRef> originKey(AdoptWK, WKStringCreateWithUTF8CString("origin"));
533         WKStringRef originWK = static_cast<WKStringRef>(WKDictionaryGetItemForKey(messageBodyDictionary, originKey.get()));
534
535         WKRetainPtr<WKStringRef> parentOriginKey(AdoptWK, WKStringCreateWithUTF8CString("parentOrigin"));
536         WKStringRef parentOriginWK = static_cast<WKStringRef>(WKDictionaryGetItemForKey(messageBodyDictionary, parentOriginKey.get()));
537         
538         TestController::singleton().resetUserMediaPermissionRequestCountForOrigin(originWK, parentOriginWK);
539         return;
540     }
541
542     if (WKStringIsEqualToUTF8CString(messageName, "SetCacheModel")) {
543         ASSERT(WKGetTypeID(messageBody) == WKUInt64GetTypeID());
544         uint64_t model = WKUInt64GetValue(static_cast<WKUInt64Ref>(messageBody));
545         WKContextSetCacheModel(TestController::singleton().context(), model);
546         return;
547     }
548
549     if (WKStringIsEqualToUTF8CString(messageName, "SetCustomPolicyDelegate")) {
550         ASSERT(WKGetTypeID(messageBody) == WKDictionaryGetTypeID());
551         WKDictionaryRef messageBodyDictionary = static_cast<WKDictionaryRef>(messageBody);
552
553         WKRetainPtr<WKStringRef> enabledKeyWK(AdoptWK, WKStringCreateWithUTF8CString("enabled"));
554         WKBooleanRef enabledWK = static_cast<WKBooleanRef>(WKDictionaryGetItemForKey(messageBodyDictionary, enabledKeyWK.get()));
555         bool enabled = WKBooleanGetValue(enabledWK);
556
557         WKRetainPtr<WKStringRef> permissiveKeyWK(AdoptWK, WKStringCreateWithUTF8CString("permissive"));
558         WKBooleanRef permissiveWK = static_cast<WKBooleanRef>(WKDictionaryGetItemForKey(messageBodyDictionary, permissiveKeyWK.get()));
559         bool permissive = WKBooleanGetValue(permissiveWK);
560
561         TestController::singleton().setCustomPolicyDelegate(enabled, permissive);
562         return;
563     }
564
565     if (WKStringIsEqualToUTF8CString(messageName, "SetHidden")) {
566         ASSERT(WKGetTypeID(messageBody) == WKDictionaryGetTypeID());
567         WKDictionaryRef messageBodyDictionary = static_cast<WKDictionaryRef>(messageBody);
568
569         WKRetainPtr<WKStringRef> isInitialKeyWK(AdoptWK, WKStringCreateWithUTF8CString("hidden"));
570         WKBooleanRef hiddenWK = static_cast<WKBooleanRef>(WKDictionaryGetItemForKey(messageBodyDictionary, isInitialKeyWK.get()));
571         bool hidden = WKBooleanGetValue(hiddenWK);
572
573         TestController::singleton().setHidden(hidden);
574         return;
575     }
576
577     if (WKStringIsEqualToUTF8CString(messageName, "ProcessWorkQueue")) {
578         if (TestController::singleton().workQueueManager().processWorkQueue()) {
579             WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("WorkQueueProcessedCallback"));
580             WKPagePostMessageToInjectedBundle(TestController::singleton().mainWebView()->page(), messageName.get(), 0);
581         }
582         return;
583     }
584
585     if (WKStringIsEqualToUTF8CString(messageName, "QueueBackNavigation")) {
586         ASSERT(WKGetTypeID(messageBody) == WKUInt64GetTypeID());
587         uint64_t stepCount = WKUInt64GetValue(static_cast<WKUInt64Ref>(messageBody));
588         TestController::singleton().workQueueManager().queueBackNavigation(stepCount);
589         return;
590     }
591
592     if (WKStringIsEqualToUTF8CString(messageName, "QueueForwardNavigation")) {
593         ASSERT(WKGetTypeID(messageBody) == WKUInt64GetTypeID());
594         uint64_t stepCount = WKUInt64GetValue(static_cast<WKUInt64Ref>(messageBody));
595         TestController::singleton().workQueueManager().queueForwardNavigation(stepCount);
596         return;
597     }
598
599     if (WKStringIsEqualToUTF8CString(messageName, "QueueLoad")) {
600         ASSERT(WKGetTypeID(messageBody) == WKDictionaryGetTypeID());
601         WKDictionaryRef loadDataDictionary = static_cast<WKDictionaryRef>(messageBody);
602
603         WKRetainPtr<WKStringRef> urlKey(AdoptWK, WKStringCreateWithUTF8CString("url"));
604         WKStringRef urlWK = static_cast<WKStringRef>(WKDictionaryGetItemForKey(loadDataDictionary, urlKey.get()));
605
606         WKRetainPtr<WKStringRef> targetKey(AdoptWK, WKStringCreateWithUTF8CString("target"));
607         WKStringRef targetWK = static_cast<WKStringRef>(WKDictionaryGetItemForKey(loadDataDictionary, targetKey.get()));
608
609         WKRetainPtr<WKStringRef> shouldOpenExternalURLsKey(AdoptWK, WKStringCreateWithUTF8CString("shouldOpenExternalURLs"));
610         WKBooleanRef shouldOpenExternalURLsValueWK = static_cast<WKBooleanRef>(WKDictionaryGetItemForKey(loadDataDictionary, shouldOpenExternalURLsKey.get()));
611
612         TestController::singleton().workQueueManager().queueLoad(toWTFString(urlWK), toWTFString(targetWK), WKBooleanGetValue(shouldOpenExternalURLsValueWK));
613         return;
614     }
615
616     if (WKStringIsEqualToUTF8CString(messageName, "QueueLoadHTMLString")) {
617         ASSERT(WKGetTypeID(messageBody) == WKDictionaryGetTypeID());
618         WKDictionaryRef loadDataDictionary = static_cast<WKDictionaryRef>(messageBody);
619
620         WKRetainPtr<WKStringRef> contentKey(AdoptWK, WKStringCreateWithUTF8CString("content"));
621         WKStringRef contentWK = static_cast<WKStringRef>(WKDictionaryGetItemForKey(loadDataDictionary, contentKey.get()));
622
623         WKRetainPtr<WKStringRef> baseURLKey(AdoptWK, WKStringCreateWithUTF8CString("baseURL"));
624         WKStringRef baseURLWK = static_cast<WKStringRef>(WKDictionaryGetItemForKey(loadDataDictionary, baseURLKey.get()));
625
626         WKRetainPtr<WKStringRef> unreachableURLKey(AdoptWK, WKStringCreateWithUTF8CString("unreachableURL"));
627         WKStringRef unreachableURLWK = static_cast<WKStringRef>(WKDictionaryGetItemForKey(loadDataDictionary, unreachableURLKey.get()));
628
629         TestController::singleton().workQueueManager().queueLoadHTMLString(toWTFString(contentWK), baseURLWK ? toWTFString(baseURLWK) : String(), unreachableURLWK ? toWTFString(unreachableURLWK) : String());
630         return;
631     }
632
633     if (WKStringIsEqualToUTF8CString(messageName, "QueueReload")) {
634         TestController::singleton().workQueueManager().queueReload();
635         return;
636     }
637
638     if (WKStringIsEqualToUTF8CString(messageName, "QueueLoadingScript")) {
639         ASSERT(WKGetTypeID(messageBody) == WKStringGetTypeID());
640         WKStringRef script = static_cast<WKStringRef>(messageBody);
641         TestController::singleton().workQueueManager().queueLoadingScript(toWTFString(script));
642         return;
643     }
644
645     if (WKStringIsEqualToUTF8CString(messageName, "QueueNonLoadingScript")) {
646         ASSERT(WKGetTypeID(messageBody) == WKStringGetTypeID());
647         WKStringRef script = static_cast<WKStringRef>(messageBody);
648         TestController::singleton().workQueueManager().queueNonLoadingScript(toWTFString(script));
649         return;
650     }
651
652     if (WKStringIsEqualToUTF8CString(messageName, "SetRejectsProtectionSpaceAndContinueForAuthenticationChallenges")) {
653         ASSERT(WKGetTypeID(messageBody) == WKBooleanGetTypeID());
654         WKBooleanRef value = static_cast<WKBooleanRef>(messageBody);
655         TestController::singleton().setRejectsProtectionSpaceAndContinueForAuthenticationChallenges(WKBooleanGetValue(value));
656         return;
657     }
658
659     if (WKStringIsEqualToUTF8CString(messageName, "SetHandlesAuthenticationChallenges")) {
660         ASSERT(WKGetTypeID(messageBody) == WKBooleanGetTypeID());
661         WKBooleanRef value = static_cast<WKBooleanRef>(messageBody);
662         TestController::singleton().setHandlesAuthenticationChallenges(WKBooleanGetValue(value));
663         return;
664     }
665
666     if (WKStringIsEqualToUTF8CString(messageName, "SetShouldLogCanAuthenticateAgainstProtectionSpace")) {
667         ASSERT(WKGetTypeID(messageBody) == WKBooleanGetTypeID());
668         WKBooleanRef value = static_cast<WKBooleanRef>(messageBody);
669         TestController::singleton().setShouldLogCanAuthenticateAgainstProtectionSpace(WKBooleanGetValue(value));
670         return;
671     }
672
673     if (WKStringIsEqualToUTF8CString(messageName, "SetAuthenticationUsername")) {
674         ASSERT(WKGetTypeID(messageBody) == WKStringGetTypeID());
675         WKStringRef username = static_cast<WKStringRef>(messageBody);
676         TestController::singleton().setAuthenticationUsername(toWTFString(username));
677         return;
678     }
679
680     if (WKStringIsEqualToUTF8CString(messageName, "SetAuthenticationPassword")) {
681         ASSERT(WKGetTypeID(messageBody) == WKStringGetTypeID());
682         WKStringRef password = static_cast<WKStringRef>(messageBody);
683         TestController::singleton().setAuthenticationPassword(toWTFString(password));
684         return;
685     }
686
687     if (WKStringIsEqualToUTF8CString(messageName, "SetBlockAllPlugins")) {
688         ASSERT(WKGetTypeID(messageBody) == WKBooleanGetTypeID());
689         WKBooleanRef shouldBlock = static_cast<WKBooleanRef>(messageBody);
690         TestController::singleton().setBlockAllPlugins(WKBooleanGetValue(shouldBlock));
691         return;
692     }
693
694     if (WKStringIsEqualToUTF8CString(messageName, "SetShouldDecideNavigationPolicyAfterDelay")) {
695         ASSERT(WKGetTypeID(messageBody) == WKBooleanGetTypeID());
696         WKBooleanRef value = static_cast<WKBooleanRef>(messageBody);
697         TestController::singleton().setShouldDecideNavigationPolicyAfterDelay(WKBooleanGetValue(value));
698         return;
699     }
700
701     if (WKStringIsEqualToUTF8CString(messageName, "SetNavigationGesturesEnabled")) {
702         ASSERT(WKGetTypeID(messageBody) == WKBooleanGetTypeID());
703         WKBooleanRef value = static_cast<WKBooleanRef>(messageBody);
704         TestController::singleton().setNavigationGesturesEnabled(WKBooleanGetValue(value));
705         return;
706     }
707     
708     if (WKStringIsEqualToUTF8CString(messageName, "SetIgnoresViewportScaleLimits")) {
709         ASSERT(WKGetTypeID(messageBody) == WKBooleanGetTypeID());
710         WKBooleanRef value = static_cast<WKBooleanRef>(messageBody);
711         TestController::singleton().setIgnoresViewportScaleLimits(WKBooleanGetValue(value));
712         return;
713     }
714
715     if (WKStringIsEqualToUTF8CString(messageName, "SetShouldDownloadUndisplayableMIMETypes")) {
716         ASSERT(WKGetTypeID(messageBody) == WKBooleanGetTypeID());
717         WKBooleanRef value = static_cast<WKBooleanRef>(messageBody);
718         TestController::singleton().setShouldDownloadUndisplayableMIMETypes(WKBooleanGetValue(value));
719         return;
720     }
721
722     if (WKStringIsEqualToUTF8CString(messageName, "RunUIProcessScript")) {
723         WKDictionaryRef messageBodyDictionary = static_cast<WKDictionaryRef>(messageBody);
724         WKRetainPtr<WKStringRef> scriptKey(AdoptWK, WKStringCreateWithUTF8CString("Script"));
725         WKRetainPtr<WKStringRef> callbackIDKey(AdoptWK, WKStringCreateWithUTF8CString("CallbackID"));
726
727         UIScriptInvocationData* invocationData = new UIScriptInvocationData();
728         invocationData->testInvocation = this;
729         invocationData->callbackID = (unsigned)WKUInt64GetValue(static_cast<WKUInt64Ref>(WKDictionaryGetItemForKey(messageBodyDictionary, callbackIDKey.get())));
730         invocationData->scriptString = static_cast<WKStringRef>(WKDictionaryGetItemForKey(messageBodyDictionary, scriptKey.get()));
731         m_pendingUIScriptInvocationData = invocationData;
732         WKPageCallAfterNextPresentationUpdate(TestController::singleton().mainWebView()->page(), invocationData, runUISideScriptAfterUpdateCallback);
733         return;
734     }
735
736     ASSERT_NOT_REACHED();
737 }
738
739 WKRetainPtr<WKTypeRef> TestInvocation::didReceiveSynchronousMessageFromInjectedBundle(WKStringRef messageName, WKTypeRef messageBody)
740 {
741     if (WKStringIsEqualToUTF8CString(messageName, "SetWindowIsKey")) {
742         ASSERT(WKGetTypeID(messageBody) == WKBooleanGetTypeID());
743         WKBooleanRef isKeyValue = static_cast<WKBooleanRef>(messageBody);
744         TestController::singleton().mainWebView()->setWindowIsKey(WKBooleanGetValue(isKeyValue));
745         return nullptr;
746     }
747
748     if (WKStringIsEqualToUTF8CString(messageName, "SetViewSize")) {
749         ASSERT(WKGetTypeID(messageBody) == WKDictionaryGetTypeID());
750
751         WKDictionaryRef messageBodyDictionary = static_cast<WKDictionaryRef>(messageBody);
752         WKRetainPtr<WKStringRef> widthKey(AdoptWK, WKStringCreateWithUTF8CString("width"));
753         WKRetainPtr<WKStringRef> heightKey(AdoptWK, WKStringCreateWithUTF8CString("height"));
754
755         WKDoubleRef widthWK = static_cast<WKDoubleRef>(WKDictionaryGetItemForKey(messageBodyDictionary, widthKey.get()));
756         WKDoubleRef heightWK = static_cast<WKDoubleRef>(WKDictionaryGetItemForKey(messageBodyDictionary, heightKey.get()));
757
758         TestController::singleton().mainWebView()->resizeTo(WKDoubleGetValue(widthWK), WKDoubleGetValue(heightWK));
759         return nullptr;
760     }
761
762     if (WKStringIsEqualToUTF8CString(messageName, "IsGeolocationClientActive")) {
763         bool isActive = TestController::singleton().isGeolocationProviderActive();
764         WKRetainPtr<WKTypeRef> result(AdoptWK, WKBooleanCreate(isActive));
765         return result;
766     }
767
768     if (WKStringIsEqualToUTF8CString(messageName, "IsWorkQueueEmpty")) {
769         bool isEmpty = TestController::singleton().workQueueManager().isWorkQueueEmpty();
770         WKRetainPtr<WKTypeRef> result(AdoptWK, WKBooleanCreate(isEmpty));
771         return result;
772     }
773
774     if (WKStringIsEqualToUTF8CString(messageName, "SecureEventInputIsEnabled")) {
775 #if PLATFORM(MAC) && !PLATFORM(IOS)
776         WKRetainPtr<WKBooleanRef> result(AdoptWK, WKBooleanCreate(IsSecureEventInputEnabled()));
777 #else
778         WKRetainPtr<WKBooleanRef> result(AdoptWK, WKBooleanCreate(false));
779 #endif
780         return result;
781     }
782
783     if (WKStringIsEqualToUTF8CString(messageName, "SetAlwaysAcceptCookies")) {
784         WKBooleanRef accept = static_cast<WKBooleanRef>(messageBody);
785         WKHTTPCookieAcceptPolicy policy = WKBooleanGetValue(accept) ? kWKHTTPCookieAcceptPolicyAlways : kWKHTTPCookieAcceptPolicyOnlyFromMainDocumentDomain;
786         // FIXME: This updates the policy in WebProcess and in NetworkProcess asynchronously, which might break some tests' expectations.
787         WKCookieManagerSetHTTPCookieAcceptPolicy(WKContextGetCookieManager(TestController::singleton().context()), policy);
788         return nullptr;
789     }
790
791     if (WKStringIsEqualToUTF8CString(messageName, "ImageCountInGeneralPasteboard")) {
792         unsigned count = TestController::singleton().imageCountInGeneralPasteboard();
793         WKRetainPtr<WKUInt64Ref> result(AdoptWK, WKUInt64Create(count));
794         return result;
795     }
796     
797     if (WKStringIsEqualToUTF8CString(messageName, "DeleteAllIndexedDatabases")) {
798         WKWebsiteDataStoreRemoveAllIndexedDatabases(WKContextGetWebsiteDataStore(TestController::singleton().context()));
799         return nullptr;
800     }
801
802 #if PLATFORM(MAC)
803     if (WKStringIsEqualToUTF8CString(messageName, "ConnectMockGamepad")) {
804         ASSERT(WKGetTypeID(messageBody) == WKUInt64GetTypeID());
805
806         uint64_t index = WKUInt64GetValue(static_cast<WKUInt64Ref>(messageBody));
807         WebCoreTestSupport::connectMockGamepad(index);
808         
809         return nullptr;
810     }
811
812     if (WKStringIsEqualToUTF8CString(messageName, "DisconnectMockGamepad")) {
813         ASSERT(WKGetTypeID(messageBody) == WKUInt64GetTypeID());
814
815         uint64_t index = WKUInt64GetValue(static_cast<WKUInt64Ref>(messageBody));
816         WebCoreTestSupport::disconnectMockGamepad(index);
817
818         return nullptr;
819     }
820
821     if (WKStringIsEqualToUTF8CString(messageName, "SetMockGamepadDetails")) {
822         ASSERT(WKGetTypeID(messageBody) == WKDictionaryGetTypeID());
823
824         WKDictionaryRef messageBodyDictionary = static_cast<WKDictionaryRef>(messageBody);
825         WKRetainPtr<WKStringRef> gamepadIndexKey(AdoptWK, WKStringCreateWithUTF8CString("GamepadIndex"));
826         WKRetainPtr<WKStringRef> gamepadIDKey(AdoptWK, WKStringCreateWithUTF8CString("GamepadID"));
827         WKRetainPtr<WKStringRef> axisCountKey(AdoptWK, WKStringCreateWithUTF8CString("AxisCount"));
828         WKRetainPtr<WKStringRef> buttonCountKey(AdoptWK, WKStringCreateWithUTF8CString("ButtonCount"));
829
830         WKUInt64Ref gamepadIndex = static_cast<WKUInt64Ref>(WKDictionaryGetItemForKey(messageBodyDictionary, gamepadIndexKey.get()));
831         WKStringRef gamepadID = static_cast<WKStringRef>(WKDictionaryGetItemForKey(messageBodyDictionary, gamepadIDKey.get()));
832         WKUInt64Ref axisCount = static_cast<WKUInt64Ref>(WKDictionaryGetItemForKey(messageBodyDictionary, axisCountKey.get()));
833         WKUInt64Ref buttonCount = static_cast<WKUInt64Ref>(WKDictionaryGetItemForKey(messageBodyDictionary, buttonCountKey.get()));
834
835         WebCoreTestSupport::setMockGamepadDetails(WKUInt64GetValue(gamepadIndex), toWTFString(gamepadID), WKUInt64GetValue(axisCount), WKUInt64GetValue(buttonCount));
836         return nullptr;
837     }
838
839     if (WKStringIsEqualToUTF8CString(messageName, "SetMockGamepadAxisValue")) {
840         ASSERT(WKGetTypeID(messageBody) == WKDictionaryGetTypeID());
841
842         WKDictionaryRef messageBodyDictionary = static_cast<WKDictionaryRef>(messageBody);
843         WKRetainPtr<WKStringRef> gamepadIndexKey(AdoptWK, WKStringCreateWithUTF8CString("GamepadIndex"));
844         WKRetainPtr<WKStringRef> axisIndexKey(AdoptWK, WKStringCreateWithUTF8CString("AxisIndex"));
845         WKRetainPtr<WKStringRef> valueKey(AdoptWK, WKStringCreateWithUTF8CString("Value"));
846
847         WKUInt64Ref gamepadIndex = static_cast<WKUInt64Ref>(WKDictionaryGetItemForKey(messageBodyDictionary, gamepadIndexKey.get()));
848         WKUInt64Ref axisIndex = static_cast<WKUInt64Ref>(WKDictionaryGetItemForKey(messageBodyDictionary, axisIndexKey.get()));
849         WKDoubleRef value = static_cast<WKDoubleRef>(WKDictionaryGetItemForKey(messageBodyDictionary, valueKey.get()));
850
851         WebCoreTestSupport::setMockGamepadAxisValue(WKUInt64GetValue(gamepadIndex), WKUInt64GetValue(axisIndex), WKDoubleGetValue(value));
852
853         return nullptr;
854     }
855
856     if (WKStringIsEqualToUTF8CString(messageName, "SetMockGamepadButtonValue")) {
857         ASSERT(WKGetTypeID(messageBody) == WKDictionaryGetTypeID());
858
859         WKDictionaryRef messageBodyDictionary = static_cast<WKDictionaryRef>(messageBody);
860         WKRetainPtr<WKStringRef> gamepadIndexKey(AdoptWK, WKStringCreateWithUTF8CString("GamepadIndex"));
861         WKRetainPtr<WKStringRef> buttonIndexKey(AdoptWK, WKStringCreateWithUTF8CString("ButtonIndex"));
862         WKRetainPtr<WKStringRef> valueKey(AdoptWK, WKStringCreateWithUTF8CString("Value"));
863
864         WKUInt64Ref gamepadIndex = static_cast<WKUInt64Ref>(WKDictionaryGetItemForKey(messageBodyDictionary, gamepadIndexKey.get()));
865         WKUInt64Ref buttonIndex = static_cast<WKUInt64Ref>(WKDictionaryGetItemForKey(messageBodyDictionary, buttonIndexKey.get()));
866         WKDoubleRef value = static_cast<WKDoubleRef>(WKDictionaryGetItemForKey(messageBodyDictionary, valueKey.get()));
867
868         WebCoreTestSupport::setMockGamepadButtonValue(WKUInt64GetValue(gamepadIndex), WKUInt64GetValue(buttonIndex), WKDoubleGetValue(value));
869
870         return nullptr;
871     }
872 #endif // PLATFORM(MAC)
873
874     if (WKStringIsEqualToUTF8CString(messageName, "UserMediaPermissionRequestCountForOrigin")) {
875         ASSERT(WKGetTypeID(messageBody) == WKDictionaryGetTypeID());
876         WKDictionaryRef messageBodyDictionary = static_cast<WKDictionaryRef>(messageBody);
877
878         WKRetainPtr<WKStringRef> originKey(AdoptWK, WKStringCreateWithUTF8CString("origin"));
879         WKStringRef originWK = static_cast<WKStringRef>(WKDictionaryGetItemForKey(messageBodyDictionary, originKey.get()));
880
881         WKRetainPtr<WKStringRef> parentOriginKey(AdoptWK, WKStringCreateWithUTF8CString("parentOrigin"));
882         WKStringRef parentOriginWK = static_cast<WKStringRef>(WKDictionaryGetItemForKey(messageBodyDictionary, parentOriginKey.get()));
883         
884         unsigned count = TestController::singleton().userMediaPermissionRequestCountForOrigin(originWK, parentOriginWK);
885         WKRetainPtr<WKUInt64Ref> result(AdoptWK, WKUInt64Create(count));
886         return result;
887     }
888
889     if (WKStringIsEqualToUTF8CString(messageName, "SetStatisticsPrevalentResource")) {
890         ASSERT(WKGetTypeID(messageBody) == WKDictionaryGetTypeID());
891
892         WKDictionaryRef messageBodyDictionary = static_cast<WKDictionaryRef>(messageBody);
893         WKRetainPtr<WKStringRef> hostNameKey(AdoptWK, WKStringCreateWithUTF8CString("HostName"));
894         WKRetainPtr<WKStringRef> valueKey(AdoptWK, WKStringCreateWithUTF8CString("Value"));
895
896         WKStringRef hostName = static_cast<WKStringRef>(WKDictionaryGetItemForKey(messageBodyDictionary, hostNameKey.get()));
897         WKBooleanRef value = static_cast<WKBooleanRef>(WKDictionaryGetItemForKey(messageBodyDictionary, valueKey.get()));
898
899         TestController::singleton().setStatisticsPrevalentResource(hostName, WKBooleanGetValue(value));
900         return nullptr;
901     }
902
903     if (WKStringIsEqualToUTF8CString(messageName, "IsStatisticsPrevalentResource")) {
904         ASSERT(WKGetTypeID(messageBody) == WKStringGetTypeID());
905
906         WKStringRef hostName = static_cast<WKStringRef>(messageBody);
907         bool isPrevalent = TestController::singleton().isStatisticsPrevalentResource(hostName);
908         WKRetainPtr<WKTypeRef> result(AdoptWK, WKBooleanCreate(isPrevalent));
909         return result;
910     }
911
912     if (WKStringIsEqualToUTF8CString(messageName, "SetStatisticsHasHadUserInteraction")) {
913         ASSERT(WKGetTypeID(messageBody) == WKDictionaryGetTypeID());
914         
915         WKDictionaryRef messageBodyDictionary = static_cast<WKDictionaryRef>(messageBody);
916         WKRetainPtr<WKStringRef> hostNameKey(AdoptWK, WKStringCreateWithUTF8CString("HostName"));
917         WKRetainPtr<WKStringRef> valueKey(AdoptWK, WKStringCreateWithUTF8CString("Value"));
918         
919         WKStringRef hostName = static_cast<WKStringRef>(WKDictionaryGetItemForKey(messageBodyDictionary, hostNameKey.get()));
920         WKBooleanRef value = static_cast<WKBooleanRef>(WKDictionaryGetItemForKey(messageBodyDictionary, valueKey.get()));
921         
922         TestController::singleton().setStatisticsHasHadUserInteraction(hostName, WKBooleanGetValue(value));
923         return nullptr;
924     }
925
926     if (WKStringIsEqualToUTF8CString(messageName, "IsStatisticsHasHadUserInteraction")) {
927         ASSERT(WKGetTypeID(messageBody) == WKStringGetTypeID());
928         
929         WKStringRef hostName = static_cast<WKStringRef>(messageBody);
930         bool hasHadUserInteraction = TestController::singleton().isStatisticsHasHadUserInteraction(hostName);
931         WKRetainPtr<WKTypeRef> result(AdoptWK, WKBooleanCreate(hasHadUserInteraction));
932         return result;
933     }
934     
935     if (WKStringIsEqualToUTF8CString(messageName, "SetStatisticsSubframeUnderTopFrameOrigin")) {
936         ASSERT(WKGetTypeID(messageBody) == WKDictionaryGetTypeID());
937         
938         WKDictionaryRef messageBodyDictionary = static_cast<WKDictionaryRef>(messageBody);
939         WKRetainPtr<WKStringRef> hostNameKey(AdoptWK, WKStringCreateWithUTF8CString("HostName"));
940         WKRetainPtr<WKStringRef> topFrameHostNameKey(AdoptWK, WKStringCreateWithUTF8CString("TopFrameHostName"));
941         
942         WKStringRef hostName = static_cast<WKStringRef>(WKDictionaryGetItemForKey(messageBodyDictionary, hostNameKey.get()));
943         WKStringRef topFrameHostName = static_cast<WKStringRef>(WKDictionaryGetItemForKey(messageBodyDictionary, topFrameHostNameKey.get()));
944
945         TestController::singleton().setStatisticsSubframeUnderTopFrameOrigin(hostName, topFrameHostName);
946         return nullptr;
947     }
948     
949     if (WKStringIsEqualToUTF8CString(messageName, "SetStatisticsSubresourceUnderTopFrameOrigin")) {
950         ASSERT(WKGetTypeID(messageBody) == WKDictionaryGetTypeID());
951         
952         WKDictionaryRef messageBodyDictionary = static_cast<WKDictionaryRef>(messageBody);
953         WKRetainPtr<WKStringRef> hostNameKey(AdoptWK, WKStringCreateWithUTF8CString("HostName"));
954         WKRetainPtr<WKStringRef> topFrameHostNameKey(AdoptWK, WKStringCreateWithUTF8CString("TopFrameHostName"));
955         
956         WKStringRef hostName = static_cast<WKStringRef>(WKDictionaryGetItemForKey(messageBodyDictionary, hostNameKey.get()));
957         WKStringRef topFrameHostName = static_cast<WKStringRef>(WKDictionaryGetItemForKey(messageBodyDictionary, topFrameHostNameKey.get()));
958         
959         TestController::singleton().setStatisticsSubresourceUnderTopFrameOrigin(hostName, topFrameHostName);
960         return nullptr;
961     }
962     
963     if (WKStringIsEqualToUTF8CString(messageName, "SetStatisticsSubresourceUniqueRedirectTo")) {
964         ASSERT(WKGetTypeID(messageBody) == WKDictionaryGetTypeID());
965         
966         WKDictionaryRef messageBodyDictionary = static_cast<WKDictionaryRef>(messageBody);
967         WKRetainPtr<WKStringRef> hostNameKey(AdoptWK, WKStringCreateWithUTF8CString("HostName"));
968         WKRetainPtr<WKStringRef> hostNameRedirectedToKey(AdoptWK, WKStringCreateWithUTF8CString("HostNameRedirectedTo"));
969         
970         WKStringRef hostName = static_cast<WKStringRef>(WKDictionaryGetItemForKey(messageBodyDictionary, hostNameKey.get()));
971         WKStringRef hostNameRedirectedTo = static_cast<WKStringRef>(WKDictionaryGetItemForKey(messageBodyDictionary, hostNameRedirectedToKey.get()));
972         
973         TestController::singleton().setStatisticsSubresourceUniqueRedirectTo(hostName, hostNameRedirectedTo);
974         return nullptr;
975     }
976
977     if (WKStringIsEqualToUTF8CString(messageName, "SetStatisticsTimeToLiveUserInteraction")) {
978         ASSERT(WKGetTypeID(messageBody) == WKDoubleGetTypeID());
979         WKDoubleRef seconds = static_cast<WKDoubleRef>(messageBody);
980         TestController::singleton().setStatisticsTimeToLiveUserInteraction(WKDoubleGetValue(seconds));
981         return nullptr;
982     }
983     
984     if (WKStringIsEqualToUTF8CString(messageName, "StatisticsFireDataModificationHandler")) {
985         TestController::singleton().statisticsFireDataModificationHandler();
986         return nullptr;
987     }
988     
989     if (WKStringIsEqualToUTF8CString(messageName, "StatisticsNotifyPagesWhenDataRecordsWereScanned")) {
990         ASSERT(WKGetTypeID(messageBody) == WKBooleanGetTypeID());
991         WKBooleanRef value = static_cast<WKBooleanRef>(messageBody);
992         TestController::singleton().setStatisticsNotifyPagesWhenDataRecordsWereScanned(WKBooleanGetValue(value));
993         return nullptr;
994     }
995
996     if (WKStringIsEqualToUTF8CString(messageName, "StatisticsShouldClassifyResourcesBeforeDataRecordsRemoval")) {
997         ASSERT(WKGetTypeID(messageBody) == WKBooleanGetTypeID());
998         WKBooleanRef value = static_cast<WKBooleanRef>(messageBody);
999         TestController::singleton().setStatisticsShouldClassifyResourcesBeforeDataRecordsRemoval(WKBooleanGetValue(value));
1000         return nullptr;
1001     }
1002
1003     if (WKStringIsEqualToUTF8CString(messageName, "SetStatisticsMinimumTimeBetweeenDataRecordsRemoval")) {
1004         ASSERT(WKGetTypeID(messageBody) == WKDoubleGetTypeID());
1005         WKDoubleRef seconds = static_cast<WKDoubleRef>(messageBody);
1006         TestController::singleton().setStatisticsMinimumTimeBetweeenDataRecordsRemoval(WKDoubleGetValue(seconds));
1007         return nullptr;
1008     }
1009     
1010     if (WKStringIsEqualToUTF8CString(messageName, "StatisticsResetToConsistentState")) {
1011         TestController::singleton().statisticsResetToConsistentState();
1012         return nullptr;
1013     }
1014
1015     ASSERT_NOT_REACHED();
1016     return nullptr;
1017 }
1018
1019 void TestInvocation::runUISideScriptAfterUpdateCallback(WKErrorRef, void* context)
1020 {
1021     UIScriptInvocationData* data = static_cast<UIScriptInvocationData*>(context);
1022     if (TestInvocation* invocation = data->testInvocation) {
1023         RELEASE_ASSERT(TestController::singleton().isCurrentInvocation(invocation));
1024         invocation->runUISideScript(data->scriptString.get(), data->callbackID);
1025     }
1026     delete data;
1027 }
1028
1029 void TestInvocation::runUISideScript(WKStringRef script, unsigned scriptCallbackID)
1030 {
1031     m_pendingUIScriptInvocationData = nullptr;
1032
1033     if (!m_UIScriptContext)
1034         m_UIScriptContext = std::make_unique<UIScriptContext>(*this);
1035     
1036     m_UIScriptContext->runUIScript(toWTFString(script), scriptCallbackID);
1037 }
1038
1039 void TestInvocation::uiScriptDidComplete(const String& result, unsigned scriptCallbackID)
1040 {
1041     WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("CallUISideScriptCallback"));
1042
1043     WKRetainPtr<WKMutableDictionaryRef> messageBody(AdoptWK, WKMutableDictionaryCreate());
1044     WKRetainPtr<WKStringRef> resultKey(AdoptWK, WKStringCreateWithUTF8CString("Result"));
1045     WKRetainPtr<WKStringRef> callbackIDKey(AdoptWK, WKStringCreateWithUTF8CString("CallbackID"));
1046     WKRetainPtr<WKUInt64Ref> callbackIDValue = adoptWK(WKUInt64Create(scriptCallbackID));
1047
1048     WKDictionarySetItem(messageBody.get(), resultKey.get(), toWK(result).get());
1049     WKDictionarySetItem(messageBody.get(), callbackIDKey.get(), callbackIDValue.get());
1050
1051     WKPagePostMessageToInjectedBundle(TestController::singleton().mainWebView()->page(), messageName.get(), messageBody.get());
1052 }
1053
1054 void TestInvocation::outputText(const WTF::String& text)
1055 {
1056     m_textOutput.append(text);
1057 }
1058
1059 void TestInvocation::didBeginSwipe()
1060 {
1061     WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("CallDidBeginSwipeCallback"));
1062     WKPagePostMessageToInjectedBundle(TestController::singleton().mainWebView()->page(), messageName.get(), 0);
1063 }
1064
1065 void TestInvocation::willEndSwipe()
1066 {
1067     WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("CallWillEndSwipeCallback"));
1068     WKPagePostMessageToInjectedBundle(TestController::singleton().mainWebView()->page(), messageName.get(), 0);
1069 }
1070
1071 void TestInvocation::didEndSwipe()
1072 {
1073     WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("CallDidEndSwipeCallback"));
1074     WKPagePostMessageToInjectedBundle(TestController::singleton().mainWebView()->page(), messageName.get(), 0);
1075 }
1076
1077 void TestInvocation::didRemoveSwipeSnapshot()
1078 {
1079     WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("CallDidRemoveSwipeSnapshotCallback"));
1080     WKPagePostMessageToInjectedBundle(TestController::singleton().mainWebView()->page(), messageName.get(), 0);
1081 }
1082
1083 void TestInvocation::notifyDownloadDone()
1084 {
1085     WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("NotifyDownloadDone"));
1086     WKPagePostMessageToInjectedBundle(TestController::singleton().mainWebView()->page(), messageName.get(), 0);
1087 }
1088
1089 } // namespace WTR