Web Inspector: Disabling Inspector causes build failure on Windows
[WebKit-https.git] / Tools / WebKitTestRunner / TestInvocation.cpp
1 /*
2  * Copyright (C) 2010 Apple Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
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.
12  *
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.
24  */
25
26 #include "config.h"
27 #include "TestInvocation.h"
28
29 #include "PlatformWebView.h"
30 #include "StringFunctions.h"
31 #include "TestController.h"
32 #include <climits>
33 #include <cstdio>
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>
41
42 #if OS(WINDOWS)
43 #include <direct.h> // For _getcwd.
44 #define getcwd _getcwd // MSDN says getcwd is deprecated.
45 #define PATH_MAX _MAX_PATH
46 #else
47 #include <unistd.h> // For getcwd.
48 #endif
49
50 using namespace WebKit;
51 using namespace std;
52
53 namespace WTR {
54
55 static WKURLRef createWKURL(const char* pathOrURL)
56 {
57     if (strstr(pathOrURL, "http://") || strstr(pathOrURL, "https://") || strstr(pathOrURL, "file://"))
58         return WKURLCreateWithUTF8CString(pathOrURL);
59
60     // Creating from filesytem path.
61     size_t length = strlen(pathOrURL);
62     if (!length)
63         return 0;
64
65 #if OS(WINDOWS)
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/";
70 #else
71     const char separator = '/';
72     bool isAbsolutePath = pathOrURL[0] == separator;
73     const char* filePrefix = "file://";
74 #endif
75     static const size_t prefixLength = strlen(filePrefix);
76
77     OwnArrayPtr<char> buffer;
78     if (isAbsolutePath) {
79         buffer = adoptArrayPtr(new char[prefixLength + length + 1]);
80         strcpy(buffer.get(), filePrefix);
81         strcpy(buffer.get() + prefixLength, pathOrURL);
82     } else {
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))
86             return 0;
87         size_t numCharacters = strlen(buffer.get());
88         buffer[numCharacters] = separator;
89         strcpy(buffer.get() + numCharacters + 1, pathOrURL);
90     }
91
92     return WKURLCreateWithUTF8CString(buffer.get());
93 }
94
95 TestInvocation::TestInvocation(const std::string& pathOrURL)
96     : m_url(AdoptWK, createWKURL(pathOrURL.c_str()))
97     , m_pathOrURL(pathOrURL)
98     , m_dumpPixels(false)
99     , m_skipPixelTestOption(false)
100     , m_gotInitialResponse(false)
101     , m_gotFinalMessage(false)
102     , m_gotRepaint(false)
103     , m_error(false)
104 {
105 }
106
107 TestInvocation::~TestInvocation()
108 {
109 }
110
111 void TestInvocation::setIsPixelTest(const std::string& expectedPixelHash)
112 {
113     if (m_skipPixelTestOption && !expectedPixelHash.length())
114         return;
115     m_dumpPixels = true;
116     m_expectedPixelHash = expectedPixelHash;
117 }
118
119 static const unsigned w3cSVGWidth = 480;
120 static const unsigned w3cSVGHeight = 360;
121 static const unsigned normalWidth = 800;
122 static const unsigned normalHeight = 600;
123
124 static void sizeWebViewForCurrentTest(const char* pathOrURL)
125 {
126     bool isSVGW3CTest = strstr(pathOrURL, "svg/W3C-SVG-1.1") || strstr(pathOrURL, "svg\\W3C-SVG-1.1");
127
128     if (isSVGW3CTest)
129         TestController::shared().mainWebView()->resizeTo(w3cSVGWidth, w3cSVGHeight);
130     else
131         TestController::shared().mainWebView()->resizeTo(normalWidth, normalHeight);
132 }
133
134 static bool shouldOpenWebInspector(const char* pathOrURL)
135 {
136     return strstr(pathOrURL, "inspector/") || strstr(pathOrURL, "inspector\\");
137 }
138
139 void TestInvocation::invoke()
140 {
141     sizeWebViewForCurrentTest(m_pathOrURL.c_str());
142
143     WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("BeginTest"));
144     WKRetainPtr<WKMutableDictionaryRef> beginTestMessageBody = adoptWK(WKMutableDictionaryCreate());
145
146     WKRetainPtr<WKStringRef> dumpPixelsKey = adoptWK(WKStringCreateWithUTF8CString("DumpPixels"));
147     WKRetainPtr<WKBooleanRef> dumpPixelsValue = adoptWK(WKBooleanCreate(m_dumpPixels));
148     WKDictionaryAddItem(beginTestMessageBody.get(), dumpPixelsKey.get(), dumpPixelsValue.get());
149
150     WKRetainPtr<WKStringRef> useWaitToDumpWatchdogTimerKey = adoptWK(WKStringCreateWithUTF8CString("UseWaitToDumpWatchdogTimer"));
151     WKRetainPtr<WKBooleanRef> useWaitToDumpWatchdogTimerValue = adoptWK(WKBooleanCreate(TestController::shared().useWaitToDumpWatchdogTimer()));
152     WKDictionaryAddItem(beginTestMessageBody.get(), useWaitToDumpWatchdogTimerKey.get(), useWaitToDumpWatchdogTimerValue.get());
153
154     WKContextPostMessageToInjectedBundle(TestController::shared().context(), messageName.get(), beginTestMessageBody.get());
155
156     TestController::shared().runUntil(m_gotInitialResponse, TestController::ShortTimeout);
157     if (!m_gotInitialResponse) {
158         dump("Timed out waiting for initial response from web process\n");
159         return;
160     }
161     if (m_error) {
162         dump("FAIL\n");
163         return;
164     }
165
166 #if ENABLE(INSPECTOR)
167     if (shouldOpenWebInspector(m_pathOrURL.c_str()))
168         WKInspectorShow(WKPageGetInspector(TestController::shared().mainWebView()->page()));
169 #endif // ENABLE(INSPECTOR)        
170
171     WKPageLoadURL(TestController::shared().mainWebView()->page(), m_url.get());
172
173     TestController::shared().runUntil(m_gotFinalMessage, TestController::shared().useWaitToDumpWatchdogTimer() ? TestController::LongTimeout : TestController::NoTimeout);
174     if (!m_gotFinalMessage)
175         dump("Timed out waiting for final message from web process\n");
176     else if (m_error)
177         dump("FAIL\n");
178
179 #if ENABLE(INSPECTOR)
180     WKInspectorClose(WKPageGetInspector(TestController::shared().mainWebView()->page()));
181 #endif // ENABLE(INSPECTOR)
182 }
183
184 void TestInvocation::dump(const char* stringToDump, bool singleEOF)
185 {
186     printf("Content-Type: text/plain\n");
187     printf("%s", stringToDump);
188
189     fputs("#EOF\n", stdout);
190     fputs("#EOF\n", stderr);
191     if (!singleEOF)
192         fputs("#EOF\n", stdout);
193     fflush(stdout);
194     fflush(stderr);
195 }
196
197 bool TestInvocation::compareActualHashToExpectedAndDumpResults(const char actualHash[33])
198 {
199     // Compute the hash of the bitmap context pixels
200     fprintf(stdout, "\nActualHash: %s\n", actualHash);
201
202     if (!m_expectedPixelHash.length())
203         return false;
204
205     ASSERT(m_expectedPixelHash.length() == 32);
206     fprintf(stdout, "\nExpectedHash: %s\n", m_expectedPixelHash.c_str());
207
208     // FIXME: Do case insensitive compare.
209     return m_expectedPixelHash == actualHash;
210 }
211
212 void TestInvocation::didReceiveMessageFromInjectedBundle(WKStringRef messageName, WKTypeRef messageBody)
213 {
214     if (WKStringIsEqualToUTF8CString(messageName, "Error")) {
215         // Set all states to true to stop spinning the runloop.
216         m_gotInitialResponse = true;
217         m_gotFinalMessage = true;
218         m_error = true;
219         TestController::shared().notifyDone();
220         return;
221     }
222
223     if (WKStringIsEqualToUTF8CString(messageName, "Ack")) {
224         ASSERT(WKGetTypeID(messageBody) == WKStringGetTypeID());
225         WKStringRef messageBodyString = static_cast<WKStringRef>(messageBody);
226         if (WKStringIsEqualToUTF8CString(messageBodyString, "BeginTest")) {
227             m_gotInitialResponse = true;
228             TestController::shared().notifyDone();
229             return;
230         }
231
232         ASSERT_NOT_REACHED();
233     }
234
235     if (WKStringIsEqualToUTF8CString(messageName, "Done")) {
236         ASSERT(WKGetTypeID(messageBody) == WKDictionaryGetTypeID());
237         WKDictionaryRef messageBodyDictionary = static_cast<WKDictionaryRef>(messageBody);
238
239         WKRetainPtr<WKStringRef> textOutputKey(AdoptWK, WKStringCreateWithUTF8CString("TextOutput"));
240         WKStringRef textOutput = static_cast<WKStringRef>(WKDictionaryGetItemForKey(messageBodyDictionary, textOutputKey.get()));
241
242         WKRetainPtr<WKStringRef> pixelResultKey = adoptWK(WKStringCreateWithUTF8CString("PixelResult"));
243         WKImageRef pixelResult = static_cast<WKImageRef>(WKDictionaryGetItemForKey(messageBodyDictionary, pixelResultKey.get()));
244         ASSERT(!pixelResult || m_dumpPixels);
245         
246         WKRetainPtr<WKStringRef> repaintRectsKey = adoptWK(WKStringCreateWithUTF8CString("RepaintRects"));
247         WKArrayRef repaintRects = static_cast<WKArrayRef>(WKDictionaryGetItemForKey(messageBodyDictionary, repaintRectsKey.get()));        
248
249         // Dump text.
250         dump(toWTFString(textOutput).utf8().data(), true);
251
252         // Dump pixels (if necessary).
253         if (m_dumpPixels && pixelResult)
254             dumpPixelsAndCompareWithExpected(pixelResult, repaintRects);
255
256         fputs("#EOF\n", stdout);
257         fflush(stdout);
258         fflush(stderr);
259         
260         m_gotFinalMessage = true;
261         TestController::shared().notifyDone();
262         return;
263     }
264     
265     if (WKStringIsEqualToUTF8CString(messageName, "BeforeUnloadReturnValue")) {
266         ASSERT(WKGetTypeID(messageBody) == WKBooleanGetTypeID());
267         WKBooleanRef beforeUnloadReturnValue = static_cast<WKBooleanRef>(messageBody);
268         TestController::shared().setBeforeUnloadReturnValue(WKBooleanGetValue(beforeUnloadReturnValue));
269         return;
270     }
271     
272     if (WKStringIsEqualToUTF8CString(messageName, "AddChromeInputField")) {
273         TestController::shared().mainWebView()->addChromeInputField();
274         WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("CallAddChromeInputFieldCallback"));
275         WKContextPostMessageToInjectedBundle(TestController::shared().context(), messageName.get(), 0);
276         return;
277     }
278
279     if (WKStringIsEqualToUTF8CString(messageName, "RemoveChromeInputField")) {
280         TestController::shared().mainWebView()->removeChromeInputField();
281         WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("CallRemoveChromeInputFieldCallback"));
282         WKContextPostMessageToInjectedBundle(TestController::shared().context(), messageName.get(), 0);
283         return;
284     }
285     
286     if (WKStringIsEqualToUTF8CString(messageName, "FocusWebView")) {
287         TestController::shared().mainWebView()->makeWebViewFirstResponder();
288         WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("CallFocusWebViewCallback"));
289         WKContextPostMessageToInjectedBundle(TestController::shared().context(), messageName.get(), 0);
290         return;
291     }
292
293     if (WKStringIsEqualToUTF8CString(messageName, "SetBackingScaleFactor")) {
294         ASSERT(WKGetTypeID(messageBody) == WKDoubleGetTypeID());
295         double backingScaleFactor = WKDoubleGetValue(static_cast<WKDoubleRef>(messageBody));
296         WKPageSetCustomBackingScaleFactor(TestController::shared().mainWebView()->page(), backingScaleFactor);
297
298         WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("CallSetBackingScaleFactorCallback"));
299         WKContextPostMessageToInjectedBundle(TestController::shared().context(), messageName.get(), 0);
300         return;
301     }
302
303     ASSERT_NOT_REACHED();
304 }
305
306 WKRetainPtr<WKTypeRef> TestInvocation::didReceiveSynchronousMessageFromInjectedBundle(WKStringRef messageName, WKTypeRef messageBody)
307 {
308     if (WKStringIsEqualToUTF8CString(messageName, "SetWindowIsKey")) {
309         ASSERT(WKGetTypeID(messageBody) == WKBooleanGetTypeID());
310         WKBooleanRef isKeyValue = static_cast<WKBooleanRef>(messageBody);
311         TestController::shared().mainWebView()->setWindowIsKey(WKBooleanGetValue(isKeyValue));
312         return 0;
313     }
314
315     ASSERT_NOT_REACHED();
316     return 0;
317 }
318
319 } // namespace WTR