2 * Copyright (C) 2010, 2011, 2012 Apple Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
14 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23 * THE POSSIBILITY OF SUCH DAMAGE.
27 #include "TestInvocation.h"
29 #include "PlatformWebView.h"
30 #include "StringFunctions.h"
31 #include "TestController.h"
34 #include <WebKit2/WKDictionary.h>
35 #include <WebKit2/WKContextPrivate.h>
36 #include <WebKit2/WKInspector.h>
37 #include <WebKit2/WKRetainPtr.h>
38 #include <wtf/OwnArrayPtr.h>
39 #include <wtf/PassOwnArrayPtr.h>
40 #include <wtf/text/CString.h>
43 #include <direct.h> // For _getcwd.
44 #define getcwd _getcwd // MSDN says getcwd is deprecated.
45 #define PATH_MAX _MAX_PATH
47 #include <unistd.h> // For getcwd.
50 using namespace WebKit;
55 static WKURLRef createWKURL(const char* pathOrURL)
57 if (strstr(pathOrURL, "http://") || strstr(pathOrURL, "https://") || strstr(pathOrURL, "file://"))
58 return WKURLCreateWithUTF8CString(pathOrURL);
60 // Creating from filesytem path.
61 size_t length = strlen(pathOrURL);
66 const char separator = '\\';
67 bool isAbsolutePath = length >= 3 && pathOrURL[1] == ':' && pathOrURL[2] == separator;
68 // FIXME: Remove the "localhost/" suffix once <http://webkit.org/b/55683> is fixed.
69 const char* filePrefix = "file://localhost/";
71 const char separator = '/';
72 bool isAbsolutePath = pathOrURL[0] == separator;
73 const char* filePrefix = "file://";
75 static const size_t prefixLength = strlen(filePrefix);
77 OwnArrayPtr<char> buffer;
79 buffer = adoptArrayPtr(new char[prefixLength + length + 1]);
80 strcpy(buffer.get(), filePrefix);
81 strcpy(buffer.get() + prefixLength, pathOrURL);
83 buffer = adoptArrayPtr(new char[prefixLength + PATH_MAX + length + 2]); // 1 for the separator
84 strcpy(buffer.get(), filePrefix);
85 if (!getcwd(buffer.get() + prefixLength, PATH_MAX))
87 size_t numCharacters = strlen(buffer.get());
88 buffer[numCharacters] = separator;
89 strcpy(buffer.get() + numCharacters + 1, pathOrURL);
92 return WKURLCreateWithUTF8CString(buffer.get());
95 TestInvocation::TestInvocation(const std::string& pathOrURL)
96 : m_url(AdoptWK, createWKURL(pathOrURL.c_str()))
97 , m_pathOrURL(pathOrURL)
99 , m_gotInitialResponse(false)
100 , m_gotFinalMessage(false)
101 , m_gotRepaint(false)
106 TestInvocation::~TestInvocation()
110 void TestInvocation::setIsPixelTest(const std::string& expectedPixelHash)
113 m_expectedPixelHash = expectedPixelHash;
116 static const unsigned w3cSVGWidth = 480;
117 static const unsigned w3cSVGHeight = 360;
118 static const unsigned normalWidth = 800;
119 static const unsigned normalHeight = 600;
121 static void sizeWebViewForCurrentTest(const char* pathOrURL)
123 bool isSVGW3CTest = strstr(pathOrURL, "svg/W3C-SVG-1.1") || strstr(pathOrURL, "svg\\W3C-SVG-1.1");
126 TestController::shared().mainWebView()->resizeTo(w3cSVGWidth, w3cSVGHeight);
128 TestController::shared().mainWebView()->resizeTo(normalWidth, normalHeight);
130 static bool shouldLogFrameLoadDelegates(const char* pathOrURL)
132 return strstr(pathOrURL, "loading/");
135 #if ENABLE(INSPECTOR)
136 static bool shouldOpenWebInspector(const char* pathOrURL)
138 return strstr(pathOrURL, "inspector/") || strstr(pathOrURL, "inspector\\");
142 void TestInvocation::invoke()
144 sizeWebViewForCurrentTest(m_pathOrURL.c_str());
146 WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("BeginTest"));
147 WKRetainPtr<WKMutableDictionaryRef> beginTestMessageBody = adoptWK(WKMutableDictionaryCreate());
149 WKRetainPtr<WKStringRef> dumpFrameLoadDelegatesKey = adoptWK(WKStringCreateWithUTF8CString("DumpFrameLoadDelegates"));
150 WKRetainPtr<WKBooleanRef> dumpFrameLoadDelegatesValue = adoptWK(WKBooleanCreate(shouldLogFrameLoadDelegates(m_pathOrURL.c_str())));
151 WKDictionaryAddItem(beginTestMessageBody.get(), dumpFrameLoadDelegatesKey.get(), dumpFrameLoadDelegatesValue.get());
153 WKRetainPtr<WKStringRef> dumpPixelsKey = adoptWK(WKStringCreateWithUTF8CString("DumpPixels"));
154 WKRetainPtr<WKBooleanRef> dumpPixelsValue = adoptWK(WKBooleanCreate(m_dumpPixels));
155 WKDictionaryAddItem(beginTestMessageBody.get(), dumpPixelsKey.get(), dumpPixelsValue.get());
157 WKRetainPtr<WKStringRef> useWaitToDumpWatchdogTimerKey = adoptWK(WKStringCreateWithUTF8CString("UseWaitToDumpWatchdogTimer"));
158 WKRetainPtr<WKBooleanRef> useWaitToDumpWatchdogTimerValue = adoptWK(WKBooleanCreate(TestController::shared().useWaitToDumpWatchdogTimer()));
159 WKDictionaryAddItem(beginTestMessageBody.get(), useWaitToDumpWatchdogTimerKey.get(), useWaitToDumpWatchdogTimerValue.get());
161 WKContextPostMessageToInjectedBundle(TestController::shared().context(), messageName.get(), beginTestMessageBody.get());
163 TestController::shared().runUntil(m_gotInitialResponse, TestController::ShortTimeout);
164 if (!m_gotInitialResponse) {
165 dump("Timed out waiting for initial response from web process\n");
173 #if ENABLE(INSPECTOR)
174 if (shouldOpenWebInspector(m_pathOrURL.c_str()))
175 WKInspectorShow(WKPageGetInspector(TestController::shared().mainWebView()->page()));
176 #endif // ENABLE(INSPECTOR)
178 WKPageLoadURL(TestController::shared().mainWebView()->page(), m_url.get());
180 TestController::shared().runUntil(m_gotFinalMessage, TestController::shared().useWaitToDumpWatchdogTimer() ? TestController::LongTimeout : TestController::NoTimeout);
181 if (!m_gotFinalMessage)
182 dump("Timed out waiting for final message from web process\n");
186 #if ENABLE(INSPECTOR)
187 WKInspectorClose(WKPageGetInspector(TestController::shared().mainWebView()->page()));
188 #endif // ENABLE(INSPECTOR)
191 void TestInvocation::dump(const char* stringToDump, bool singleEOF)
193 printf("Content-Type: text/plain\n");
194 printf("%s", stringToDump);
196 fputs("#EOF\n", stdout);
197 fputs("#EOF\n", stderr);
199 fputs("#EOF\n", stdout);
204 bool TestInvocation::compareActualHashToExpectedAndDumpResults(const char actualHash[33])
206 // Compute the hash of the bitmap context pixels
207 fprintf(stdout, "\nActualHash: %s\n", actualHash);
209 if (!m_expectedPixelHash.length())
212 ASSERT(m_expectedPixelHash.length() == 32);
213 fprintf(stdout, "\nExpectedHash: %s\n", m_expectedPixelHash.c_str());
215 // FIXME: Do case insensitive compare.
216 return m_expectedPixelHash == actualHash;
219 void TestInvocation::didReceiveMessageFromInjectedBundle(WKStringRef messageName, WKTypeRef messageBody)
221 if (WKStringIsEqualToUTF8CString(messageName, "Error")) {
222 // Set all states to true to stop spinning the runloop.
223 m_gotInitialResponse = true;
224 m_gotFinalMessage = true;
226 TestController::shared().notifyDone();
230 if (WKStringIsEqualToUTF8CString(messageName, "Ack")) {
231 ASSERT(WKGetTypeID(messageBody) == WKStringGetTypeID());
232 WKStringRef messageBodyString = static_cast<WKStringRef>(messageBody);
233 if (WKStringIsEqualToUTF8CString(messageBodyString, "BeginTest")) {
234 m_gotInitialResponse = true;
235 TestController::shared().notifyDone();
239 ASSERT_NOT_REACHED();
242 if (WKStringIsEqualToUTF8CString(messageName, "Done")) {
243 ASSERT(WKGetTypeID(messageBody) == WKDictionaryGetTypeID());
244 WKDictionaryRef messageBodyDictionary = static_cast<WKDictionaryRef>(messageBody);
246 WKRetainPtr<WKStringRef> textOutputKey(AdoptWK, WKStringCreateWithUTF8CString("TextOutput"));
247 WKStringRef textOutput = static_cast<WKStringRef>(WKDictionaryGetItemForKey(messageBodyDictionary, textOutputKey.get()));
249 WKRetainPtr<WKStringRef> pixelResultKey = adoptWK(WKStringCreateWithUTF8CString("PixelResult"));
250 WKImageRef pixelResult = static_cast<WKImageRef>(WKDictionaryGetItemForKey(messageBodyDictionary, pixelResultKey.get()));
251 ASSERT(!pixelResult || m_dumpPixels);
253 WKRetainPtr<WKStringRef> repaintRectsKey = adoptWK(WKStringCreateWithUTF8CString("RepaintRects"));
254 WKArrayRef repaintRects = static_cast<WKArrayRef>(WKDictionaryGetItemForKey(messageBodyDictionary, repaintRectsKey.get()));
257 dump(toWTFString(textOutput).utf8().data(), true);
259 // Dump pixels (if necessary).
260 if (m_dumpPixels && pixelResult)
261 dumpPixelsAndCompareWithExpected(pixelResult, repaintRects);
263 fputs("#EOF\n", stdout);
267 m_gotFinalMessage = true;
268 TestController::shared().notifyDone();
272 if (WKStringIsEqualToUTF8CString(messageName, "BeforeUnloadReturnValue")) {
273 ASSERT(WKGetTypeID(messageBody) == WKBooleanGetTypeID());
274 WKBooleanRef beforeUnloadReturnValue = static_cast<WKBooleanRef>(messageBody);
275 TestController::shared().setBeforeUnloadReturnValue(WKBooleanGetValue(beforeUnloadReturnValue));
279 if (WKStringIsEqualToUTF8CString(messageName, "AddChromeInputField")) {
280 TestController::shared().mainWebView()->addChromeInputField();
281 WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("CallAddChromeInputFieldCallback"));
282 WKContextPostMessageToInjectedBundle(TestController::shared().context(), messageName.get(), 0);
286 if (WKStringIsEqualToUTF8CString(messageName, "RemoveChromeInputField")) {
287 TestController::shared().mainWebView()->removeChromeInputField();
288 WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("CallRemoveChromeInputFieldCallback"));
289 WKContextPostMessageToInjectedBundle(TestController::shared().context(), messageName.get(), 0);
293 if (WKStringIsEqualToUTF8CString(messageName, "FocusWebView")) {
294 TestController::shared().mainWebView()->makeWebViewFirstResponder();
295 WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("CallFocusWebViewCallback"));
296 WKContextPostMessageToInjectedBundle(TestController::shared().context(), messageName.get(), 0);
300 if (WKStringIsEqualToUTF8CString(messageName, "SetBackingScaleFactor")) {
301 ASSERT(WKGetTypeID(messageBody) == WKDoubleGetTypeID());
302 double backingScaleFactor = WKDoubleGetValue(static_cast<WKDoubleRef>(messageBody));
303 WKPageSetCustomBackingScaleFactor(TestController::shared().mainWebView()->page(), backingScaleFactor);
305 WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("CallSetBackingScaleFactorCallback"));
306 WKContextPostMessageToInjectedBundle(TestController::shared().context(), messageName.get(), 0);
310 ASSERT_NOT_REACHED();
313 WKRetainPtr<WKTypeRef> TestInvocation::didReceiveSynchronousMessageFromInjectedBundle(WKStringRef messageName, WKTypeRef messageBody)
315 if (WKStringIsEqualToUTF8CString(messageName, "SetWindowIsKey")) {
316 ASSERT(WKGetTypeID(messageBody) == WKBooleanGetTypeID());
317 WKBooleanRef isKeyValue = static_cast<WKBooleanRef>(messageBody);
318 TestController::shared().mainWebView()->setWindowIsKey(WKBooleanGetValue(isKeyValue));
322 if (WKStringIsEqualToUTF8CString(messageName, "SetMainFrameIsFirstResponder")) {
323 ASSERT(WKGetTypeID(messageBody) == WKBooleanGetTypeID());
324 WKBooleanRef isFirstResponder = static_cast<WKBooleanRef>(messageBody);
325 TestController::shared().mainWebView()->setMainFrameIsFirstResponder(WKBooleanGetValue(isFirstResponder));
329 ASSERT_NOT_REACHED();