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 41 #if OS(WINDOWS) 42 #include <direct.h> // For _getcwd. 43 #define getcwd _getcwd // MSDN says getcwd is deprecated. 44 #define PATH_MAX _MAX_PATH 45 #endif 46 47 using namespace WebKit; 48 using namespace std; 49 50 namespace WTR { 51 52 static WKURLRef createWKURL(const char* pathOrURL) 53 { 54 if (strstr(pathOrURL, "http://") || strstr(pathOrURL, "https://") || strstr(pathOrURL, "file://")) 55 return WKURLCreateWithUTF8CString(pathOrURL); 56 57 // Creating from filesytem path. 58 size_t length = strlen(pathOrURL); 59 if (!length) 60 return 0; 61 62 // FIXME: Remove the "localhost/" suffix once <http://webkit.org/b/55683> is fixed. 63 const char* filePrefix = "file://localhost/"; 64 static const size_t prefixLength = strlen(filePrefix); 65 #if OS(WINDOWS) 66 const char separator = '\\'; 67 bool isAbsolutePath = length >= 3 && pathOrURL[1] == ':' && pathOrURL[2] == separator; 68 #else 69 const char separator = '/'; 70 bool isAbsolutePath = pathOrURL[0] == separator; 71 #endif 72 73 OwnArrayPtr<char> buffer; 74 if (isAbsolutePath) { 75 buffer = adoptArrayPtr(new char[prefixLength + length + 1]); 76 strcpy(buffer.get(), filePrefix); 77 strcpy(buffer.get() + prefixLength, pathOrURL); 78 } else { 79 buffer = adoptArrayPtr(new char[prefixLength + PATH_MAX + length + 2]); // 1 for the separator 80 strcpy(buffer.get(), filePrefix); 81 if (!getcwd(buffer.get() + prefixLength, PATH_MAX)) 82 return 0; 83 size_t numCharacters = strlen(buffer.get()); 84 buffer[numCharacters] = separator; 85 strcpy(buffer.get() + numCharacters + 1, pathOrURL); 86 } 87 88 return WKURLCreateWithUTF8CString(buffer.get()); 89 } 90 91 TestInvocation::TestInvocation(const std::string& pathOrURL) 92 : m_url(AdoptWK, createWKURL(pathOrURL.c_str())) 93 , m_pathOrURL(pathOrURL) 94 , m_dumpPixels(false) 95 , m_gotInitialResponse(false) 96 , m_gotFinalMessage(false) 97 , m_gotRepaint(false) 98 , m_error(false) 99 { 100 } 101 102 TestInvocation::~TestInvocation() 103 { 104 } 105 106 void TestInvocation::setIsPixelTest(const std::string& expectedPixelHash) 107 { 108 m_dumpPixels = true; 109 m_expectedPixelHash = expectedPixelHash; 110 } 111 112 static const unsigned w3cSVGWidth = 480; 113 static const unsigned w3cSVGHeight = 360; 114 static const unsigned normalWidth = 800; 115 static const unsigned normalHeight = 600; 116 117 static void sizeWebViewForCurrentTest(const char* pathOrURL) 118 { 119 bool isSVGW3CTest = strstr(pathOrURL, "svg/W3C-SVG-1.1") || strstr(pathOrURL, "svg\\W3C-SVG-1.1"); 120 121 if (isSVGW3CTest) 122 TestController::shared().mainWebView()->resizeTo(w3cSVGWidth, w3cSVGHeight); 123 else 124 TestController::shared().mainWebView()->resizeTo(normalWidth, normalHeight); 125 } 126 127 static bool shouldOpenWebInspector(const char* pathOrURL) 128 { 129 return strstr(pathOrURL, "inspector/") || strstr(pathOrURL, "inspector\\"); 130 } 131 132 void TestInvocation::invoke() 133 { 134 sizeWebViewForCurrentTest(m_pathOrURL.c_str()); 135 136 WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("BeginTest")); 137 WKRetainPtr<WKBooleanRef> dumpPixels = adoptWK(WKBooleanCreate(m_dumpPixels)); 138 WKContextPostMessageToInjectedBundle(TestController::shared().context(), messageName.get(), dumpPixels.get()); 139 140 TestController::shared().runUntil(m_gotInitialResponse, TestController::ShortTimeout); 141 if (!m_gotInitialResponse) { 142 dump("Timed out waiting for initial response from web process\n"); 143 return; 144 } 145 if (m_error) { 146 dump("FAIL\n"); 147 return; 148 } 149 150 if (shouldOpenWebInspector(m_pathOrURL.c_str())) 151 WKInspectorShow(WKPageGetInspector(TestController::shared().mainWebView()->page())); 152 153 WKPageLoadURL(TestController::shared().mainWebView()->page(), m_url.get()); 154 155 TestController::shared().runUntil(m_gotFinalMessage, TestController::LongTimeout); 156 if (!m_gotFinalMessage) 157 dump("Timed out waiting for final message from web process\n"); 158 else if (m_error) 159 dump("FAIL\n"); 160 161 WKInspectorClose(WKPageGetInspector(TestController::shared().mainWebView()->page())); 162 } 163 164 void TestInvocation::dump(const char* stringToDump) 165 { 166 printf("Content-Type: text/plain\n"); 167 printf("%s", stringToDump); 168 169 fputs("#EOF\n", stdout); 170 fputs("#EOF\n", stderr); 171 fflush(stdout); 172 fflush(stderr); 173 } 174 175 void TestInvocation::didReceiveMessageFromInjectedBundle(WKStringRef messageName, WKTypeRef messageBody) 176 { 177 if (WKStringIsEqualToUTF8CString(messageName, "Error")) { 178 // Set all states to true to stop spinning the runloop. 179 m_gotInitialResponse = true; 180 m_gotFinalMessage = true; 181 m_error = true; 182 TestController::shared().notifyDone(); 183 return; 184 } 185 186 if (WKStringIsEqualToUTF8CString(messageName, "Ack")) { 187 ASSERT(WKGetTypeID(messageBody) == WKStringGetTypeID()); 188 WKStringRef messageBodyString = static_cast<WKStringRef>(messageBody); 189 if (WKStringIsEqualToUTF8CString(messageBodyString, "BeginTest")) { 190 m_gotInitialResponse = true; 191 TestController::shared().notifyDone(); 192 return; 193 } 194 195 ASSERT_NOT_REACHED(); 196 } 197 198 if (WKStringIsEqualToUTF8CString(messageName, "Done")) { 199 ASSERT(WKGetTypeID(messageBody) == WKDictionaryGetTypeID()); 200 WKDictionaryRef messageBodyDictionary = static_cast<WKDictionaryRef>(messageBody); 201 202 WKRetainPtr<WKStringRef> textOutputKey(AdoptWK, WKStringCreateWithUTF8CString("TextOutput")); 203 WKStringRef textOutput = static_cast<WKStringRef>(WKDictionaryGetItemForKey(messageBodyDictionary, textOutputKey.get())); 204 205 WKRetainPtr<WKStringRef> pixelResultKey = adoptWK(WKStringCreateWithUTF8CString("PixelResult")); 206 WKImageRef pixelResult = static_cast<WKImageRef>(WKDictionaryGetItemForKey(messageBodyDictionary, pixelResultKey.get())); 207 ASSERT(!pixelResult || m_dumpPixels); 208 209 // Dump text. 210 dump(toSTD(textOutput).c_str()); 211 212 // Dump pixels (if necessary). 213 if (m_dumpPixels && pixelResult) 214 dumpPixelsAndCompareWithExpected(pixelResult); 215 216 fputs("#EOF\n", stdout); 217 fflush(stdout); 218 fflush(stderr); 219 220 m_gotFinalMessage = true; 221 TestController::shared().notifyDone(); 222 return; 223 } 224 225 ASSERT_NOT_REACHED(); 226 } 227 228 WKRetainPtr<WKTypeRef> TestInvocation::didReceiveSynchronousMessageFromInjectedBundle(WKStringRef /*messageName*/, WKTypeRef /*messageBody*/) 229 { 230 ASSERT_NOT_REACHED(); 231 return 0; 232 } 233 234 } // namespace WTR 235