Fixed somtimes focus ring is shown twice.
[framework/web/webkit-efl.git] / Tools / WebKitTestRunner / TestInvocation.cpp
1 /*
2  * Copyright (C) 2010, 2011, 2012 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_gotInitialResponse(false)
100     , m_gotFinalMessage(false)
101     , m_gotRepaint(false)
102     , m_error(false)
103 {
104 }
105
106 TestInvocation::~TestInvocation()
107 {
108 }
109
110 void TestInvocation::setIsPixelTest(const std::string& expectedPixelHash)
111 {
112     m_dumpPixels = true;
113     m_expectedPixelHash = expectedPixelHash;
114 }
115
116 static const unsigned w3cSVGWidth = 480;
117 static const unsigned w3cSVGHeight = 360;
118 static const unsigned normalWidth = 800;
119 static const unsigned normalHeight = 600;
120
121 static void sizeWebViewForCurrentTest(const char* pathOrURL)
122 {
123     bool isSVGW3CTest = strstr(pathOrURL, "svg/W3C-SVG-1.1") || strstr(pathOrURL, "svg\\W3C-SVG-1.1");
124
125     if (isSVGW3CTest)
126         TestController::shared().mainWebView()->resizeTo(w3cSVGWidth, w3cSVGHeight);
127     else
128         TestController::shared().mainWebView()->resizeTo(normalWidth, normalHeight);
129 }
130 static bool shouldLogFrameLoadDelegates(const char* pathOrURL)
131 {
132     return strstr(pathOrURL, "loading/");
133 }
134
135 #if ENABLE(INSPECTOR)
136 static bool shouldOpenWebInspector(const char* pathOrURL)
137 {
138     return strstr(pathOrURL, "inspector/") || strstr(pathOrURL, "inspector\\");
139 }
140 #endif
141
142 void TestInvocation::invoke()
143 {
144     sizeWebViewForCurrentTest(m_pathOrURL.c_str());
145
146     WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("BeginTest"));
147     WKRetainPtr<WKMutableDictionaryRef> beginTestMessageBody = adoptWK(WKMutableDictionaryCreate());
148
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());
152
153     WKRetainPtr<WKStringRef> dumpPixelsKey = adoptWK(WKStringCreateWithUTF8CString("DumpPixels"));
154     WKRetainPtr<WKBooleanRef> dumpPixelsValue = adoptWK(WKBooleanCreate(m_dumpPixels));
155     WKDictionaryAddItem(beginTestMessageBody.get(), dumpPixelsKey.get(), dumpPixelsValue.get());
156
157     WKRetainPtr<WKStringRef> useWaitToDumpWatchdogTimerKey = adoptWK(WKStringCreateWithUTF8CString("UseWaitToDumpWatchdogTimer"));
158     WKRetainPtr<WKBooleanRef> useWaitToDumpWatchdogTimerValue = adoptWK(WKBooleanCreate(TestController::shared().useWaitToDumpWatchdogTimer()));
159     WKDictionaryAddItem(beginTestMessageBody.get(), useWaitToDumpWatchdogTimerKey.get(), useWaitToDumpWatchdogTimerValue.get());
160
161     WKContextPostMessageToInjectedBundle(TestController::shared().context(), messageName.get(), beginTestMessageBody.get());
162
163     TestController::shared().runUntil(m_gotInitialResponse, TestController::ShortTimeout);
164     if (!m_gotInitialResponse) {
165         dump("Timed out waiting for initial response from web process\n");
166         return;
167     }
168     if (m_error) {
169         dump("FAIL\n");
170         return;
171     }
172
173 #if ENABLE(INSPECTOR)
174     if (shouldOpenWebInspector(m_pathOrURL.c_str()))
175         WKInspectorShow(WKPageGetInspector(TestController::shared().mainWebView()->page()));
176 #endif // ENABLE(INSPECTOR)        
177
178     WKPageLoadURL(TestController::shared().mainWebView()->page(), m_url.get());
179
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");
183     else if (m_error)
184         dump("FAIL\n");
185
186 #if ENABLE(INSPECTOR)
187     WKInspectorClose(WKPageGetInspector(TestController::shared().mainWebView()->page()));
188 #endif // ENABLE(INSPECTOR)
189 }
190
191 void TestInvocation::dump(const char* stringToDump, bool singleEOF)
192 {
193     printf("Content-Type: text/plain\n");
194     printf("%s", stringToDump);
195
196     fputs("#EOF\n", stdout);
197     fputs("#EOF\n", stderr);
198     if (!singleEOF)
199         fputs("#EOF\n", stdout);
200     fflush(stdout);
201     fflush(stderr);
202 }
203
204 bool TestInvocation::compareActualHashToExpectedAndDumpResults(const char actualHash[33])
205 {
206     // Compute the hash of the bitmap context pixels
207     fprintf(stdout, "\nActualHash: %s\n", actualHash);
208
209     if (!m_expectedPixelHash.length())
210         return false;
211
212     ASSERT(m_expectedPixelHash.length() == 32);
213     fprintf(stdout, "\nExpectedHash: %s\n", m_expectedPixelHash.c_str());
214
215     // FIXME: Do case insensitive compare.
216     return m_expectedPixelHash == actualHash;
217 }
218
219 void TestInvocation::didReceiveMessageFromInjectedBundle(WKStringRef messageName, WKTypeRef messageBody)
220 {
221     if (WKStringIsEqualToUTF8CString(messageName, "Error")) {
222         // Set all states to true to stop spinning the runloop.
223         m_gotInitialResponse = true;
224         m_gotFinalMessage = true;
225         m_error = true;
226         TestController::shared().notifyDone();
227         return;
228     }
229
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();
236             return;
237         }
238
239         ASSERT_NOT_REACHED();
240     }
241
242     if (WKStringIsEqualToUTF8CString(messageName, "Done")) {
243         ASSERT(WKGetTypeID(messageBody) == WKDictionaryGetTypeID());
244         WKDictionaryRef messageBodyDictionary = static_cast<WKDictionaryRef>(messageBody);
245
246         WKRetainPtr<WKStringRef> textOutputKey(AdoptWK, WKStringCreateWithUTF8CString("TextOutput"));
247         WKStringRef textOutput = static_cast<WKStringRef>(WKDictionaryGetItemForKey(messageBodyDictionary, textOutputKey.get()));
248
249         WKRetainPtr<WKStringRef> pixelResultKey = adoptWK(WKStringCreateWithUTF8CString("PixelResult"));
250         WKImageRef pixelResult = static_cast<WKImageRef>(WKDictionaryGetItemForKey(messageBodyDictionary, pixelResultKey.get()));
251         ASSERT(!pixelResult || m_dumpPixels);
252         
253         WKRetainPtr<WKStringRef> repaintRectsKey = adoptWK(WKStringCreateWithUTF8CString("RepaintRects"));
254         WKArrayRef repaintRects = static_cast<WKArrayRef>(WKDictionaryGetItemForKey(messageBodyDictionary, repaintRectsKey.get()));        
255
256         // Dump text.
257         dump(toWTFString(textOutput).utf8().data(), true);
258
259         // Dump pixels (if necessary).
260         if (m_dumpPixels && pixelResult)
261             dumpPixelsAndCompareWithExpected(pixelResult, repaintRects);
262
263         fputs("#EOF\n", stdout);
264         fflush(stdout);
265         fflush(stderr);
266         
267         m_gotFinalMessage = true;
268         TestController::shared().notifyDone();
269         return;
270     }
271     
272     if (WKStringIsEqualToUTF8CString(messageName, "BeforeUnloadReturnValue")) {
273         ASSERT(WKGetTypeID(messageBody) == WKBooleanGetTypeID());
274         WKBooleanRef beforeUnloadReturnValue = static_cast<WKBooleanRef>(messageBody);
275         TestController::shared().setBeforeUnloadReturnValue(WKBooleanGetValue(beforeUnloadReturnValue));
276         return;
277     }
278     
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);
283         return;
284     }
285
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);
290         return;
291     }
292     
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);
297         return;
298     }
299
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);
304
305         WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("CallSetBackingScaleFactorCallback"));
306         WKContextPostMessageToInjectedBundle(TestController::shared().context(), messageName.get(), 0);
307         return;
308     }
309
310     ASSERT_NOT_REACHED();
311 }
312
313 WKRetainPtr<WKTypeRef> TestInvocation::didReceiveSynchronousMessageFromInjectedBundle(WKStringRef messageName, WKTypeRef messageBody)
314 {
315     if (WKStringIsEqualToUTF8CString(messageName, "SetWindowIsKey")) {
316         ASSERT(WKGetTypeID(messageBody) == WKBooleanGetTypeID());
317         WKBooleanRef isKeyValue = static_cast<WKBooleanRef>(messageBody);
318         TestController::shared().mainWebView()->setWindowIsKey(WKBooleanGetValue(isKeyValue));
319         return 0;
320     }
321
322     if (WKStringIsEqualToUTF8CString(messageName, "SetMainFrameIsFirstResponder")) {
323         ASSERT(WKGetTypeID(messageBody) == WKBooleanGetTypeID());
324         WKBooleanRef isFirstResponder = static_cast<WKBooleanRef>(messageBody);
325         TestController::shared().mainWebView()->setMainFrameIsFirstResponder(WKBooleanGetValue(isFirstResponder));
326         return 0;
327     }
328
329     ASSERT_NOT_REACHED();
330     return 0;
331 }
332
333 } // namespace WTR