<https://webkit.org/b/42704> WebKitTestRunner needs to print history delegate information
[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 <climits>
34 #include <cstdio>
35 #include <WebKit2/WKContextPrivate.h>
36 #include <WebKit2/WKData.h>
37 #include <WebKit2/WKDictionary.h>
38 #include <WebKit2/WKInspector.h>
39 #include <WebKit2/WKRetainPtr.h>
40 #include <wtf/PassOwnPtr.h>
41 #include <wtf/StdLibExtras.h>
42 #include <wtf/text/CString.h>
43
44 #if PLATFORM(MAC) && !PLATFORM(IOS)
45 #include <Carbon/Carbon.h>
46 #endif
47
48 #if PLATFORM(COCOA)
49 #include <WebKit2/WKPagePrivateMac.h>
50 #endif
51
52 #include <unistd.h> // For getcwd.
53
54 using namespace WebKit;
55 using namespace std;
56
57 namespace WTR {
58
59 static WKURLRef createWKURL(const char* pathOrURL)
60 {
61     if (strstr(pathOrURL, "http://") || strstr(pathOrURL, "https://") || strstr(pathOrURL, "file://"))
62         return WKURLCreateWithUTF8CString(pathOrURL);
63
64     // Creating from filesytem path.
65     size_t length = strlen(pathOrURL);
66     if (!length)
67         return 0;
68
69     const char separator = '/';
70     bool isAbsolutePath = pathOrURL[0] == separator;
71     const char* filePrefix = "file://";
72     static const size_t prefixLength = strlen(filePrefix);
73
74     std::unique_ptr<char[]> buffer;
75     if (isAbsolutePath) {
76         buffer = std::make_unique<char[]>(prefixLength + length + 1);
77         strcpy(buffer.get(), filePrefix);
78         strcpy(buffer.get() + prefixLength, pathOrURL);
79     } else {
80         buffer = std::make_unique<char[]>(prefixLength + PATH_MAX + length + 2); // 1 for the separator
81         strcpy(buffer.get(), filePrefix);
82         if (!getcwd(buffer.get() + prefixLength, PATH_MAX))
83             return 0;
84         size_t numCharacters = strlen(buffer.get());
85         buffer[numCharacters] = separator;
86         strcpy(buffer.get() + numCharacters + 1, pathOrURL);
87     }
88
89     return WKURLCreateWithUTF8CString(buffer.get());
90 }
91
92 TestInvocation::TestInvocation(const std::string& pathOrURL)
93     : m_url(AdoptWK, createWKURL(pathOrURL.c_str()))
94     , m_pathOrURL(pathOrURL)
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 }
104
105 TestInvocation::~TestInvocation()
106 {
107 }
108
109 void TestInvocation::setIsPixelTest(const std::string& expectedPixelHash)
110 {
111     m_dumpPixels = true;
112     m_expectedPixelHash = expectedPixelHash;
113 }
114
115 void TestInvocation::setCustomTimeout(int timeout)
116 {
117     m_timeout = timeout;
118 }
119
120 static void sizeWebViewForCurrentTest(const char* pathOrURL)
121 {
122     bool isSVGW3CTest = strstr(pathOrURL, "svg/W3C-SVG-1.1") || strstr(pathOrURL, "svg\\W3C-SVG-1.1");
123
124     if (isSVGW3CTest)
125         TestController::shared().mainWebView()->resizeTo(TestController::w3cSVGViewWidth, TestController::w3cSVGViewHeight);
126     else
127         TestController::shared().mainWebView()->resizeTo(TestController::viewWidth, TestController::viewHeight);
128 }
129
130 static void changeWindowScaleIfNeeded(const char* pathOrURL)
131 {
132     WTF::String localPathOrUrl = String(pathOrURL);
133     bool needsHighDPIWindow = localPathOrUrl.findIgnoringCase("hidpi-") != notFound;
134     TestController::shared().mainWebView()->changeWindowScaleIfNeeded(needsHighDPIWindow ? 2 : 1);
135 }
136
137 static bool shouldLogFrameLoadDelegates(const char* pathOrURL)
138 {
139     return strstr(pathOrURL, "loading/");
140 }
141
142 #if PLATFORM(COCOA)
143 static bool shouldUseThreadedScrolling(const char* pathOrURL)
144 {
145     return strstr(pathOrURL, "tiled-drawing/") || strstr(pathOrURL, "tiled-drawing\\");
146 }
147 #endif
148
149 static bool shouldLogHistoryClientCallbacks(const char* pathOrURL)
150 {
151     return strstr(pathOrURL, "globalhistory/");
152 }
153
154 static void updateThreadedScrollingForCurrentTest(const char* pathOrURL)
155 {
156 #if PLATFORM(COCOA)
157     WKRetainPtr<WKMutableDictionaryRef> viewOptions = adoptWK(WKMutableDictionaryCreate());
158     WKRetainPtr<WKStringRef> useThreadedScrollingKey = adoptWK(WKStringCreateWithUTF8CString("ThreadedScrolling"));
159     WKRetainPtr<WKBooleanRef> useThreadedScrollingValue = adoptWK(WKBooleanCreate(shouldUseThreadedScrolling(pathOrURL)));
160     WKDictionarySetItem(viewOptions.get(), useThreadedScrollingKey.get(), useThreadedScrollingValue.get());
161
162     WKRetainPtr<WKStringRef> useRemoteLayerTreeKey = adoptWK(WKStringCreateWithUTF8CString("RemoteLayerTree"));
163     WKRetainPtr<WKBooleanRef> useRemoteLayerTreeValue = adoptWK(WKBooleanCreate(TestController::shared().shouldUseRemoteLayerTree()));
164     WKDictionarySetItem(viewOptions.get(), useRemoteLayerTreeKey.get(), useRemoteLayerTreeValue.get());
165
166     TestController::shared().ensureViewSupportsOptions(viewOptions.get());
167 #else
168     UNUSED_PARAM(pathOrURL);
169 #endif
170 }
171
172 static bool shouldUseFixedLayout(const char* pathOrURL)
173 {
174 #if ENABLE(CSS_DEVICE_ADAPTATION)
175     if (strstr(pathOrURL, "device-adapt/") || strstr(pathOrURL, "device-adapt\\"))
176         return true;
177 #endif
178
179 #if USE(TILED_BACKING_STORE) && PLATFORM(EFL)
180     if (strstr(pathOrURL, "sticky/") || strstr(pathOrURL, "sticky\\"))
181         return true;
182 #endif
183     return false;
184
185     UNUSED_PARAM(pathOrURL);
186 }
187
188 static void updateLayoutType(const char* pathOrURL)
189 {
190     WKRetainPtr<WKMutableDictionaryRef> viewOptions = adoptWK(WKMutableDictionaryCreate());
191     WKRetainPtr<WKStringRef> useFixedLayoutKey = adoptWK(WKStringCreateWithUTF8CString("UseFixedLayout"));
192     WKRetainPtr<WKBooleanRef> useFixedLayoutValue = adoptWK(WKBooleanCreate(shouldUseFixedLayout(pathOrURL)));
193     WKDictionarySetItem(viewOptions.get(), useFixedLayoutKey.get(), useFixedLayoutValue.get());
194
195     TestController::shared().ensureViewSupportsOptions(viewOptions.get());
196 }
197
198 void TestInvocation::invoke()
199 {
200     TestController::TimeoutDuration timeoutToUse = TestController::LongTimeout;
201     changeWindowScaleIfNeeded(m_pathOrURL.c_str());
202     sizeWebViewForCurrentTest(m_pathOrURL.c_str());
203     updateLayoutType(m_pathOrURL.c_str());
204     updateThreadedScrollingForCurrentTest(m_pathOrURL.c_str());
205
206     m_textOutput.clear();
207
208     TestController::shared().setShouldLogHistoryClientCallbacks(shouldLogHistoryClientCallbacks(m_pathOrURL.c_str()));
209
210     WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("BeginTest"));
211     WKRetainPtr<WKMutableDictionaryRef> beginTestMessageBody = adoptWK(WKMutableDictionaryCreate());
212
213     WKRetainPtr<WKStringRef> dumpFrameLoadDelegatesKey = adoptWK(WKStringCreateWithUTF8CString("DumpFrameLoadDelegates"));
214     WKRetainPtr<WKBooleanRef> dumpFrameLoadDelegatesValue = adoptWK(WKBooleanCreate(shouldLogFrameLoadDelegates(m_pathOrURL.c_str())));
215     WKDictionarySetItem(beginTestMessageBody.get(), dumpFrameLoadDelegatesKey.get(), dumpFrameLoadDelegatesValue.get());
216
217     WKRetainPtr<WKStringRef> dumpPixelsKey = adoptWK(WKStringCreateWithUTF8CString("DumpPixels"));
218     WKRetainPtr<WKBooleanRef> dumpPixelsValue = adoptWK(WKBooleanCreate(m_dumpPixels));
219     WKDictionarySetItem(beginTestMessageBody.get(), dumpPixelsKey.get(), dumpPixelsValue.get());
220
221     WKRetainPtr<WKStringRef> useWaitToDumpWatchdogTimerKey = adoptWK(WKStringCreateWithUTF8CString("UseWaitToDumpWatchdogTimer"));
222     WKRetainPtr<WKBooleanRef> useWaitToDumpWatchdogTimerValue = adoptWK(WKBooleanCreate(TestController::shared().useWaitToDumpWatchdogTimer()));
223     WKDictionarySetItem(beginTestMessageBody.get(), useWaitToDumpWatchdogTimerKey.get(), useWaitToDumpWatchdogTimerValue.get());
224
225     WKRetainPtr<WKStringRef> timeoutKey = adoptWK(WKStringCreateWithUTF8CString("Timeout"));
226     WKRetainPtr<WKUInt64Ref> timeoutValue = adoptWK(WKUInt64Create(m_timeout));
227     WKDictionarySetItem(beginTestMessageBody.get(), timeoutKey.get(), timeoutValue.get());
228
229     WKContextPostMessageToInjectedBundle(TestController::shared().context(), messageName.get(), beginTestMessageBody.get());
230
231     TestController::shared().runUntil(m_gotInitialResponse, TestController::ShortTimeout);
232     if (!m_gotInitialResponse) {
233         m_errorMessage = "Timed out waiting for initial response from web process\n";
234         m_webProcessIsUnresponsive = true;
235         goto end;
236     }
237     if (m_error)
238         goto end;
239
240     WKPageLoadURL(TestController::shared().mainWebView()->page(), m_url.get());
241
242     if (TestController::shared().useWaitToDumpWatchdogTimer()) {
243         if (m_timeout > 0)
244             timeoutToUse = TestController::CustomTimeout;
245     } else
246         timeoutToUse = TestController::NoTimeout;
247     TestController::shared().runUntil(m_gotFinalMessage, timeoutToUse);
248
249     if (!m_gotFinalMessage) {
250         m_errorMessage = "Timed out waiting for final message from web process\n";
251         m_webProcessIsUnresponsive = true;
252         goto end;
253     }
254     if (m_error)
255         goto end;
256
257     dumpResults();
258
259 end:
260 #if ENABLE(INSPECTOR) && !PLATFORM(IOS)
261     if (m_gotInitialResponse)
262         WKInspectorClose(WKPageGetInspector(TestController::shared().mainWebView()->page()));
263 #endif // ENABLE(INSPECTOR)
264
265     if (m_webProcessIsUnresponsive)
266         dumpWebProcessUnresponsiveness();
267     else if (!TestController::shared().resetStateToConsistentValues()) {
268         m_errorMessage = "Timed out loading about:blank before the next test";
269         dumpWebProcessUnresponsiveness();
270     }
271 }
272
273 void TestInvocation::dumpWebProcessUnresponsiveness()
274 {
275     dumpWebProcessUnresponsiveness(m_errorMessage.c_str());
276 }
277
278 void TestInvocation::dumpWebProcessUnresponsiveness(const char* errorMessage)
279 {
280     const char* errorMessageToStderr = 0;
281 #if PLATFORM(COCOA)
282     char buffer[64];
283     pid_t pid = WKPageGetProcessIdentifier(TestController::shared().mainWebView()->page());
284     sprintf(buffer, "#PROCESS UNRESPONSIVE - WebProcess (pid %ld)\n", static_cast<long>(pid));
285     errorMessageToStderr = buffer;
286 #else
287     errorMessageToStderr = "#PROCESS UNRESPONSIVE - WebProcess";
288 #endif
289
290     dump(errorMessage, errorMessageToStderr, true);
291 }
292
293 void TestInvocation::dump(const char* textToStdout, const char* textToStderr, bool seenError)
294 {
295     printf("Content-Type: text/plain\n");
296     if (textToStdout)
297         fputs(textToStdout, stdout);
298     if (textToStderr)
299         fputs(textToStderr, stderr);
300
301     fputs("#EOF\n", stdout);
302     fputs("#EOF\n", stderr);
303     if (seenError)
304         fputs("#EOF\n", stdout);
305     fflush(stdout);
306     fflush(stderr);
307 }
308
309 void TestInvocation::forceRepaintDoneCallback(WKErrorRef, void* context)
310 {
311     TestInvocation* testInvocation = static_cast<TestInvocation*>(context);
312     testInvocation->m_gotRepaint = true;
313     TestController::shared().notifyDone();
314 }
315
316 void TestInvocation::dumpResults()
317 {
318     if (m_textOutput.length() || !m_audioResult)
319         dump(m_textOutput.toString().utf8().data());
320     else
321         dumpAudio(m_audioResult.get());
322
323     if (m_dumpPixels && m_pixelResult) {
324         if (PlatformWebView::windowSnapshotEnabled()) {
325             m_gotRepaint = false;
326             WKPageForceRepaint(TestController::shared().mainWebView()->page(), this, TestInvocation::forceRepaintDoneCallback);
327             TestController::shared().runUntil(m_gotRepaint, TestController::ShortTimeout);
328             if (!m_gotRepaint) {
329                 m_errorMessage = "Timed out waiting for pre-pixel dump repaint\n";
330                 m_webProcessIsUnresponsive = true;
331                 return;
332             }
333         }
334         dumpPixelsAndCompareWithExpected(m_pixelResult.get(), m_repaintRects.get());
335     }
336
337     fputs("#EOF\n", stdout);
338     fflush(stdout);
339     fflush(stderr);
340 }
341
342 void TestInvocation::dumpAudio(WKDataRef audioData)
343 {
344     size_t length = WKDataGetSize(audioData);
345     if (!length)
346         return;
347
348     const unsigned char* data = WKDataGetBytes(audioData);
349
350     printf("Content-Type: audio/wav\n");
351     printf("Content-Length: %lu\n", static_cast<unsigned long>(length));
352
353     fwrite(data, 1, length, stdout);
354     printf("#EOF\n");
355     fprintf(stderr, "#EOF\n");
356 }
357
358 bool TestInvocation::compareActualHashToExpectedAndDumpResults(const char actualHash[33])
359 {
360     // Compute the hash of the bitmap context pixels
361     fprintf(stdout, "\nActualHash: %s\n", actualHash);
362
363     if (!m_expectedPixelHash.length())
364         return false;
365
366     ASSERT(m_expectedPixelHash.length() == 32);
367     fprintf(stdout, "\nExpectedHash: %s\n", m_expectedPixelHash.c_str());
368
369     // FIXME: Do case insensitive compare.
370     return m_expectedPixelHash == actualHash;
371 }
372
373 void TestInvocation::didReceiveMessageFromInjectedBundle(WKStringRef messageName, WKTypeRef messageBody)
374 {
375     if (WKStringIsEqualToUTF8CString(messageName, "Error")) {
376         // Set all states to true to stop spinning the runloop.
377         m_gotInitialResponse = true;
378         m_gotFinalMessage = true;
379         m_error = true;
380         m_errorMessage = "FAIL\n";
381         TestController::shared().notifyDone();
382         return;
383     }
384
385     if (WKStringIsEqualToUTF8CString(messageName, "Ack")) {
386         ASSERT(WKGetTypeID(messageBody) == WKStringGetTypeID());
387         WKStringRef messageBodyString = static_cast<WKStringRef>(messageBody);
388         if (WKStringIsEqualToUTF8CString(messageBodyString, "BeginTest")) {
389             m_gotInitialResponse = true;
390             TestController::shared().notifyDone();
391             return;
392         }
393
394         ASSERT_NOT_REACHED();
395     }
396
397     if (WKStringIsEqualToUTF8CString(messageName, "Done")) {
398         ASSERT(WKGetTypeID(messageBody) == WKDictionaryGetTypeID());
399         WKDictionaryRef messageBodyDictionary = static_cast<WKDictionaryRef>(messageBody);
400
401         WKRetainPtr<WKStringRef> pixelResultKey = adoptWK(WKStringCreateWithUTF8CString("PixelResult"));
402         m_pixelResult = static_cast<WKImageRef>(WKDictionaryGetItemForKey(messageBodyDictionary, pixelResultKey.get()));
403         ASSERT(!m_pixelResult || m_dumpPixels);
404
405         WKRetainPtr<WKStringRef> repaintRectsKey = adoptWK(WKStringCreateWithUTF8CString("RepaintRects"));
406         m_repaintRects = static_cast<WKArrayRef>(WKDictionaryGetItemForKey(messageBodyDictionary, repaintRectsKey.get()));
407
408         WKRetainPtr<WKStringRef> audioResultKey =  adoptWK(WKStringCreateWithUTF8CString("AudioResult"));
409         m_audioResult = static_cast<WKDataRef>(WKDictionaryGetItemForKey(messageBodyDictionary, audioResultKey.get()));
410
411         m_gotFinalMessage = true;
412         TestController::shared().notifyDone();
413         return;
414     }
415
416     if (WKStringIsEqualToUTF8CString(messageName, "TextOutput")) {
417         ASSERT(WKGetTypeID(messageBody) == WKStringGetTypeID());
418         WKStringRef textOutput = static_cast<WKStringRef>(messageBody);
419         m_textOutput.append(toWTFString(textOutput));
420         return;
421     }
422
423     if (WKStringIsEqualToUTF8CString(messageName, "BeforeUnloadReturnValue")) {
424         ASSERT(WKGetTypeID(messageBody) == WKBooleanGetTypeID());
425         WKBooleanRef beforeUnloadReturnValue = static_cast<WKBooleanRef>(messageBody);
426         TestController::shared().setBeforeUnloadReturnValue(WKBooleanGetValue(beforeUnloadReturnValue));
427         return;
428     }
429     
430     if (WKStringIsEqualToUTF8CString(messageName, "AddChromeInputField")) {
431         TestController::shared().mainWebView()->addChromeInputField();
432         WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("CallAddChromeInputFieldCallback"));
433         WKContextPostMessageToInjectedBundle(TestController::shared().context(), messageName.get(), 0);
434         return;
435     }
436
437     if (WKStringIsEqualToUTF8CString(messageName, "RemoveChromeInputField")) {
438         TestController::shared().mainWebView()->removeChromeInputField();
439         WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("CallRemoveChromeInputFieldCallback"));
440         WKContextPostMessageToInjectedBundle(TestController::shared().context(), messageName.get(), 0);
441         return;
442     }
443     
444     if (WKStringIsEqualToUTF8CString(messageName, "FocusWebView")) {
445         TestController::shared().mainWebView()->makeWebViewFirstResponder();
446         WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("CallFocusWebViewCallback"));
447         WKContextPostMessageToInjectedBundle(TestController::shared().context(), messageName.get(), 0);
448         return;
449     }
450
451     if (WKStringIsEqualToUTF8CString(messageName, "SetBackingScaleFactor")) {
452         ASSERT(WKGetTypeID(messageBody) == WKDoubleGetTypeID());
453         double backingScaleFactor = WKDoubleGetValue(static_cast<WKDoubleRef>(messageBody));
454         WKPageSetCustomBackingScaleFactor(TestController::shared().mainWebView()->page(), backingScaleFactor);
455
456         WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("CallSetBackingScaleFactorCallback"));
457         WKContextPostMessageToInjectedBundle(TestController::shared().context(), messageName.get(), 0);
458         return;
459     }
460
461     if (WKStringIsEqualToUTF8CString(messageName, "SimulateWebNotificationClick")) {
462         ASSERT(WKGetTypeID(messageBody) == WKUInt64GetTypeID());
463         uint64_t notificationID = WKUInt64GetValue(static_cast<WKUInt64Ref>(messageBody));
464         TestController::shared().simulateWebNotificationClick(notificationID);
465         return;
466     }
467
468     if (WKStringIsEqualToUTF8CString(messageName, "SetGeolocationPermission")) {
469         ASSERT(WKGetTypeID(messageBody) == WKBooleanGetTypeID());
470         WKBooleanRef enabledWK = static_cast<WKBooleanRef>(messageBody);
471         TestController::shared().setGeolocationPermission(WKBooleanGetValue(enabledWK));
472         return;
473     }
474
475     if (WKStringIsEqualToUTF8CString(messageName, "SetMockGeolocationPosition")) {
476         ASSERT(WKGetTypeID(messageBody) == WKDictionaryGetTypeID());
477         WKDictionaryRef messageBodyDictionary = static_cast<WKDictionaryRef>(messageBody);
478
479         WKRetainPtr<WKStringRef> latitudeKeyWK(AdoptWK, WKStringCreateWithUTF8CString("latitude"));
480         WKDoubleRef latitudeWK = static_cast<WKDoubleRef>(WKDictionaryGetItemForKey(messageBodyDictionary, latitudeKeyWK.get()));
481         double latitude = WKDoubleGetValue(latitudeWK);
482
483         WKRetainPtr<WKStringRef> longitudeKeyWK(AdoptWK, WKStringCreateWithUTF8CString("longitude"));
484         WKDoubleRef longitudeWK = static_cast<WKDoubleRef>(WKDictionaryGetItemForKey(messageBodyDictionary, longitudeKeyWK.get()));
485         double longitude = WKDoubleGetValue(longitudeWK);
486
487         WKRetainPtr<WKStringRef> accuracyKeyWK(AdoptWK, WKStringCreateWithUTF8CString("accuracy"));
488         WKDoubleRef accuracyWK = static_cast<WKDoubleRef>(WKDictionaryGetItemForKey(messageBodyDictionary, accuracyKeyWK.get()));
489         double accuracy = WKDoubleGetValue(accuracyWK);
490
491         WKRetainPtr<WKStringRef> providesAltitudeKeyWK(AdoptWK, WKStringCreateWithUTF8CString("providesAltitude"));
492         WKBooleanRef providesAltitudeWK = static_cast<WKBooleanRef>(WKDictionaryGetItemForKey(messageBodyDictionary, providesAltitudeKeyWK.get()));
493         bool providesAltitude = WKBooleanGetValue(providesAltitudeWK);
494
495         WKRetainPtr<WKStringRef> altitudeKeyWK(AdoptWK, WKStringCreateWithUTF8CString("altitude"));
496         WKDoubleRef altitudeWK = static_cast<WKDoubleRef>(WKDictionaryGetItemForKey(messageBodyDictionary, altitudeKeyWK.get()));
497         double altitude = WKDoubleGetValue(altitudeWK);
498
499         WKRetainPtr<WKStringRef> providesAltitudeAccuracyKeyWK(AdoptWK, WKStringCreateWithUTF8CString("providesAltitudeAccuracy"));
500         WKBooleanRef providesAltitudeAccuracyWK = static_cast<WKBooleanRef>(WKDictionaryGetItemForKey(messageBodyDictionary, providesAltitudeAccuracyKeyWK.get()));
501         bool providesAltitudeAccuracy = WKBooleanGetValue(providesAltitudeAccuracyWK);
502
503         WKRetainPtr<WKStringRef> altitudeAccuracyKeyWK(AdoptWK, WKStringCreateWithUTF8CString("altitudeAccuracy"));
504         WKDoubleRef altitudeAccuracyWK = static_cast<WKDoubleRef>(WKDictionaryGetItemForKey(messageBodyDictionary, altitudeAccuracyKeyWK.get()));
505         double altitudeAccuracy = WKDoubleGetValue(altitudeAccuracyWK);
506
507         WKRetainPtr<WKStringRef> providesHeadingKeyWK(AdoptWK, WKStringCreateWithUTF8CString("providesHeading"));
508         WKBooleanRef providesHeadingWK = static_cast<WKBooleanRef>(WKDictionaryGetItemForKey(messageBodyDictionary, providesHeadingKeyWK.get()));
509         bool providesHeading = WKBooleanGetValue(providesHeadingWK);
510
511         WKRetainPtr<WKStringRef> headingKeyWK(AdoptWK, WKStringCreateWithUTF8CString("heading"));
512         WKDoubleRef headingWK = static_cast<WKDoubleRef>(WKDictionaryGetItemForKey(messageBodyDictionary, headingKeyWK.get()));
513         double heading = WKDoubleGetValue(headingWK);
514
515         WKRetainPtr<WKStringRef> providesSpeedKeyWK(AdoptWK, WKStringCreateWithUTF8CString("providesSpeed"));
516         WKBooleanRef providesSpeedWK = static_cast<WKBooleanRef>(WKDictionaryGetItemForKey(messageBodyDictionary, providesSpeedKeyWK.get()));
517         bool providesSpeed = WKBooleanGetValue(providesSpeedWK);
518
519         WKRetainPtr<WKStringRef> speedKeyWK(AdoptWK, WKStringCreateWithUTF8CString("speed"));
520         WKDoubleRef speedWK = static_cast<WKDoubleRef>(WKDictionaryGetItemForKey(messageBodyDictionary, speedKeyWK.get()));
521         double speed = WKDoubleGetValue(speedWK);
522
523         TestController::shared().setMockGeolocationPosition(latitude, longitude, accuracy, providesAltitude, altitude, providesAltitudeAccuracy, altitudeAccuracy, providesHeading, heading, providesSpeed, speed);
524         return;
525     }
526
527     if (WKStringIsEqualToUTF8CString(messageName, "SetMockGeolocationPositionUnavailableError")) {
528         ASSERT(WKGetTypeID(messageBody) == WKStringGetTypeID());
529         WKStringRef errorMessage = static_cast<WKStringRef>(messageBody);
530         TestController::shared().setMockGeolocationPositionUnavailableError(errorMessage);
531         return;
532     }
533
534     if (WKStringIsEqualToUTF8CString(messageName, "SetCustomPolicyDelegate")) {
535         ASSERT(WKGetTypeID(messageBody) == WKDictionaryGetTypeID());
536         WKDictionaryRef messageBodyDictionary = static_cast<WKDictionaryRef>(messageBody);
537
538         WKRetainPtr<WKStringRef> enabledKeyWK(AdoptWK, WKStringCreateWithUTF8CString("enabled"));
539         WKBooleanRef enabledWK = static_cast<WKBooleanRef>(WKDictionaryGetItemForKey(messageBodyDictionary, enabledKeyWK.get()));
540         bool enabled = WKBooleanGetValue(enabledWK);
541
542         WKRetainPtr<WKStringRef> permissiveKeyWK(AdoptWK, WKStringCreateWithUTF8CString("permissive"));
543         WKBooleanRef permissiveWK = static_cast<WKBooleanRef>(WKDictionaryGetItemForKey(messageBodyDictionary, permissiveKeyWK.get()));
544         bool permissive = WKBooleanGetValue(permissiveWK);
545
546         TestController::shared().setCustomPolicyDelegate(enabled, permissive);
547         return;
548     }
549
550     if (WKStringIsEqualToUTF8CString(messageName, "SetHidden")) {
551         ASSERT(WKGetTypeID(messageBody) == WKDictionaryGetTypeID());
552         WKDictionaryRef messageBodyDictionary = static_cast<WKDictionaryRef>(messageBody);
553
554         WKRetainPtr<WKStringRef> isInitialKeyWK(AdoptWK, WKStringCreateWithUTF8CString("hidden"));
555         WKBooleanRef hiddenWK = static_cast<WKBooleanRef>(WKDictionaryGetItemForKey(messageBodyDictionary, isInitialKeyWK.get()));
556         bool hidden = WKBooleanGetValue(hiddenWK);
557
558         TestController::shared().setHidden(hidden);
559         return;
560     }
561
562     if (WKStringIsEqualToUTF8CString(messageName, "ProcessWorkQueue")) {
563         if (TestController::shared().workQueueManager().processWorkQueue()) {
564             WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("WorkQueueProcessedCallback"));
565             WKContextPostMessageToInjectedBundle(TestController::shared().context(), messageName.get(), 0);
566         }
567         return;
568     }
569
570     if (WKStringIsEqualToUTF8CString(messageName, "QueueBackNavigation")) {
571         ASSERT(WKGetTypeID(messageBody) == WKUInt64GetTypeID());
572         uint64_t stepCount = WKUInt64GetValue(static_cast<WKUInt64Ref>(messageBody));
573         TestController::shared().workQueueManager().queueBackNavigation(stepCount);
574         return;
575     }
576
577     if (WKStringIsEqualToUTF8CString(messageName, "QueueForwardNavigation")) {
578         ASSERT(WKGetTypeID(messageBody) == WKUInt64GetTypeID());
579         uint64_t stepCount = WKUInt64GetValue(static_cast<WKUInt64Ref>(messageBody));
580         TestController::shared().workQueueManager().queueForwardNavigation(stepCount);
581         return;
582     }
583
584     if (WKStringIsEqualToUTF8CString(messageName, "QueueLoad")) {
585         ASSERT(WKGetTypeID(messageBody) == WKDictionaryGetTypeID());
586         WKDictionaryRef loadDataDictionary = static_cast<WKDictionaryRef>(messageBody);
587
588         WKRetainPtr<WKStringRef> urlKey(AdoptWK, WKStringCreateWithUTF8CString("url"));
589         WKStringRef urlWK = static_cast<WKStringRef>(WKDictionaryGetItemForKey(loadDataDictionary, urlKey.get()));
590
591         WKRetainPtr<WKStringRef> targetKey(AdoptWK, WKStringCreateWithUTF8CString("target"));
592         WKStringRef targetWK = static_cast<WKStringRef>(WKDictionaryGetItemForKey(loadDataDictionary, targetKey.get()));
593
594         TestController::shared().workQueueManager().queueLoad(toWTFString(urlWK), toWTFString(targetWK));
595         return;
596     }
597
598     if (WKStringIsEqualToUTF8CString(messageName, "QueueLoadHTMLString")) {
599         ASSERT(WKGetTypeID(messageBody) == WKDictionaryGetTypeID());
600         WKDictionaryRef loadDataDictionary = static_cast<WKDictionaryRef>(messageBody);
601
602         WKRetainPtr<WKStringRef> contentKey(AdoptWK, WKStringCreateWithUTF8CString("content"));
603         WKStringRef contentWK = static_cast<WKStringRef>(WKDictionaryGetItemForKey(loadDataDictionary, contentKey.get()));
604
605         WKRetainPtr<WKStringRef> baseURLKey(AdoptWK, WKStringCreateWithUTF8CString("baseURL"));
606         WKStringRef baseURLWK = static_cast<WKStringRef>(WKDictionaryGetItemForKey(loadDataDictionary, baseURLKey.get()));
607
608         WKRetainPtr<WKStringRef> unreachableURLKey(AdoptWK, WKStringCreateWithUTF8CString("unreachableURL"));
609         WKStringRef unreachableURLWK = static_cast<WKStringRef>(WKDictionaryGetItemForKey(loadDataDictionary, unreachableURLKey.get()));
610
611         TestController::shared().workQueueManager().queueLoadHTMLString(toWTFString(contentWK), baseURLWK ? toWTFString(baseURLWK) : String(), unreachableURLWK ? toWTFString(unreachableURLWK) : String());
612         return;
613     }
614
615     if (WKStringIsEqualToUTF8CString(messageName, "QueueReload")) {
616         TestController::shared().workQueueManager().queueReload();
617         return;
618     }
619
620     if (WKStringIsEqualToUTF8CString(messageName, "QueueLoadingScript")) {
621         ASSERT(WKGetTypeID(messageBody) == WKStringGetTypeID());
622         WKStringRef script = static_cast<WKStringRef>(messageBody);
623         TestController::shared().workQueueManager().queueLoadingScript(toWTFString(script));
624         return;
625     }
626
627     if (WKStringIsEqualToUTF8CString(messageName, "QueueNonLoadingScript")) {
628         ASSERT(WKGetTypeID(messageBody) == WKStringGetTypeID());
629         WKStringRef script = static_cast<WKStringRef>(messageBody);
630         TestController::shared().workQueueManager().queueNonLoadingScript(toWTFString(script));
631         return;
632     }
633
634     if (WKStringIsEqualToUTF8CString(messageName, "SetHandlesAuthenticationChallenge")) {
635         ASSERT(WKGetTypeID(messageBody) == WKBooleanGetTypeID());
636         WKBooleanRef value = static_cast<WKBooleanRef>(messageBody);
637         TestController::shared().setHandlesAuthenticationChallenges(WKBooleanGetValue(value));
638         return;
639     }
640
641     if (WKStringIsEqualToUTF8CString(messageName, "SetAuthenticationUsername")) {
642         ASSERT(WKGetTypeID(messageBody) == WKStringGetTypeID());
643         WKStringRef username = static_cast<WKStringRef>(messageBody);
644         TestController::shared().setAuthenticationUsername(toWTFString(username));
645         return;
646     }
647
648     if (WKStringIsEqualToUTF8CString(messageName, "SetAuthenticationPassword")) {
649         ASSERT(WKGetTypeID(messageBody) == WKStringGetTypeID());
650         WKStringRef password = static_cast<WKStringRef>(messageBody);
651         TestController::shared().setAuthenticationPassword(toWTFString(password));
652         return;
653     }
654
655     if (WKStringIsEqualToUTF8CString(messageName, "SetBlockAllPlugins")) {
656         ASSERT(WKGetTypeID(messageBody) == WKBooleanGetTypeID());
657         WKBooleanRef shouldBlock = static_cast<WKBooleanRef>(messageBody);
658         TestController::shared().setBlockAllPlugins(WKBooleanGetValue(shouldBlock));
659         return;
660     }
661
662     ASSERT_NOT_REACHED();
663 }
664
665 WKRetainPtr<WKTypeRef> TestInvocation::didReceiveSynchronousMessageFromInjectedBundle(WKStringRef messageName, WKTypeRef messageBody)
666 {
667     if (WKStringIsEqualToUTF8CString(messageName, "SetWindowIsKey")) {
668         ASSERT(WKGetTypeID(messageBody) == WKBooleanGetTypeID());
669         WKBooleanRef isKeyValue = static_cast<WKBooleanRef>(messageBody);
670         TestController::shared().mainWebView()->setWindowIsKey(WKBooleanGetValue(isKeyValue));
671         return 0;
672     }
673
674     if (WKStringIsEqualToUTF8CString(messageName, "IsWorkQueueEmpty")) {
675         bool isEmpty = TestController::shared().workQueueManager().isWorkQueueEmpty();
676         WKRetainPtr<WKTypeRef> result(AdoptWK, WKBooleanCreate(isEmpty));
677         return result;
678     }
679
680     if (WKStringIsEqualToUTF8CString(messageName, "SecureEventInputIsEnabled")) {
681 #if PLATFORM(MAC) && !PLATFORM(IOS)
682         WKRetainPtr<WKBooleanRef> result(AdoptWK, WKBooleanCreate(IsSecureEventInputEnabled()));
683 #else
684         WKRetainPtr<WKBooleanRef> result(AdoptWK, WKBooleanCreate(false));
685 #endif
686         return result;
687     }
688     ASSERT_NOT_REACHED();
689     return 0;
690 }
691
692 void TestInvocation::outputText(const WTF::String& text)
693 {
694     m_textOutput.append(text);
695 }
696
697 } // namespace WTR