/* * Copyright (C) 2010 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ #include "config.h" #include "TestInvocation.h" #include "PlatformWebView.h" #include "StringFunctions.h" #include "TestController.h" #include <climits> #include <cstdio> #include <WebKit2/WKDictionary.h> #include <WebKit2/WKContextPrivate.h> #include <WebKit2/WKInspector.h> #include <WebKit2/WKRetainPtr.h> #include <wtf/OwnArrayPtr.h> #include <wtf/PassOwnArrayPtr.h> #if OS(WINDOWS) #include <direct.h> // For _getcwd. #define getcwd _getcwd // MSDN says getcwd is deprecated. #define PATH_MAX _MAX_PATH #endif using namespace WebKit; using namespace std; namespace WTR { static WKURLRef createWKURL(const char* pathOrURL) { if (strstr(pathOrURL, "http://") || strstr(pathOrURL, "https://") || strstr(pathOrURL, "file://")) return WKURLCreateWithUTF8CString(pathOrURL); // Creating from filesytem path. size_t length = strlen(pathOrURL); if (!length) return 0; // FIXME: Remove the "localhost/" suffix once <http://webkit.org/b/55683> is fixed. const char* filePrefix = "file://localhost/"; static const size_t prefixLength = strlen(filePrefix); #if OS(WINDOWS) const char separator = '\\'; bool isAbsolutePath = length >= 3 && pathOrURL[1] == ':' && pathOrURL[2] == separator; #else const char separator = '/'; bool isAbsolutePath = pathOrURL[0] == separator; #endif OwnArrayPtr<char> buffer; if (isAbsolutePath) { buffer = adoptArrayPtr(new char[prefixLength + length + 1]); strcpy(buffer.get(), filePrefix); strcpy(buffer.get() + prefixLength, pathOrURL); } else { buffer = adoptArrayPtr(new char[prefixLength + PATH_MAX + length + 2]); // 1 for the separator strcpy(buffer.get(), filePrefix); if (!getcwd(buffer.get() + prefixLength, PATH_MAX)) return 0; size_t numCharacters = strlen(buffer.get()); buffer[numCharacters] = separator; strcpy(buffer.get() + numCharacters + 1, pathOrURL); } return WKURLCreateWithUTF8CString(buffer.get()); } TestInvocation::TestInvocation(const std::string& pathOrURL) : m_url(AdoptWK, createWKURL(pathOrURL.c_str())) , m_pathOrURL(pathOrURL) , m_dumpPixels(false) , m_gotInitialResponse(false) , m_gotFinalMessage(false) , m_gotRepaint(false) , m_error(false) { } TestInvocation::~TestInvocation() { } void TestInvocation::setIsPixelTest(const std::string& expectedPixelHash) { m_dumpPixels = true; m_expectedPixelHash = expectedPixelHash; } static const unsigned w3cSVGWidth = 480; static const unsigned w3cSVGHeight = 360; static const unsigned normalWidth = 800; static const unsigned normalHeight = 600; static void sizeWebViewForCurrentTest(const char* pathOrURL) { bool isSVGW3CTest = strstr(pathOrURL, "svg/W3C-SVG-1.1") || strstr(pathOrURL, "svg\\W3C-SVG-1.1"); if (isSVGW3CTest) TestController::shared().mainWebView()->resizeTo(w3cSVGWidth, w3cSVGHeight); else TestController::shared().mainWebView()->resizeTo(normalWidth, normalHeight); } static bool shouldOpenWebInspector(const char* pathOrURL) { return strstr(pathOrURL, "inspector/") || strstr(pathOrURL, "inspector\\"); } void TestInvocation::invoke() { sizeWebViewForCurrentTest(m_pathOrURL.c_str()); WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("BeginTest")); WKRetainPtr<WKBooleanRef> dumpPixels = adoptWK(WKBooleanCreate(m_dumpPixels)); WKContextPostMessageToInjectedBundle(TestController::shared().context(), messageName.get(), dumpPixels.get()); TestController::shared().runUntil(m_gotInitialResponse, TestController::ShortTimeout); if (!m_gotInitialResponse) { dump("Timed out waiting for initial response from web process\n"); return; } if (m_error) { dump("FAIL\n"); return; } if (shouldOpenWebInspector(m_pathOrURL.c_str())) WKInspectorShow(WKPageGetInspector(TestController::shared().mainWebView()->page())); WKPageLoadURL(TestController::shared().mainWebView()->page(), m_url.get()); TestController::shared().runUntil(m_gotFinalMessage, TestController::LongTimeout); if (!m_gotFinalMessage) dump("Timed out waiting for final message from web process\n"); else if (m_error) dump("FAIL\n"); WKInspectorClose(WKPageGetInspector(TestController::shared().mainWebView()->page())); } void TestInvocation::dump(const char* stringToDump) { printf("Content-Type: text/plain\n"); printf("%s", stringToDump); fputs("#EOF\n", stdout); fputs("#EOF\n", stderr); fflush(stdout); fflush(stderr); } void TestInvocation::didReceiveMessageFromInjectedBundle(WKStringRef messageName, WKTypeRef messageBody) { if (WKStringIsEqualToUTF8CString(messageName, "Error")) { // Set all states to true to stop spinning the runloop. m_gotInitialResponse = true; m_gotFinalMessage = true; m_error = true; TestController::shared().notifyDone(); return; } if (WKStringIsEqualToUTF8CString(messageName, "Ack")) { ASSERT(WKGetTypeID(messageBody) == WKStringGetTypeID()); WKStringRef messageBodyString = static_cast<WKStringRef>(messageBody); if (WKStringIsEqualToUTF8CString(messageBodyString, "BeginTest")) { m_gotInitialResponse = true; TestController::shared().notifyDone(); return; } ASSERT_NOT_REACHED(); } if (WKStringIsEqualToUTF8CString(messageName, "Done")) { ASSERT(WKGetTypeID(messageBody) == WKDictionaryGetTypeID()); WKDictionaryRef messageBodyDictionary = static_cast<WKDictionaryRef>(messageBody); WKRetainPtr<WKStringRef> textOutputKey(AdoptWK, WKStringCreateWithUTF8CString("TextOutput")); WKStringRef textOutput = static_cast<WKStringRef>(WKDictionaryGetItemForKey(messageBodyDictionary, textOutputKey.get())); WKRetainPtr<WKStringRef> pixelResultKey = adoptWK(WKStringCreateWithUTF8CString("PixelResult")); WKImageRef pixelResult = static_cast<WKImageRef>(WKDictionaryGetItemForKey(messageBodyDictionary, pixelResultKey.get())); ASSERT(!pixelResult || m_dumpPixels); // Dump text. dump(toSTD(textOutput).c_str()); // Dump pixels (if necessary). if (m_dumpPixels && pixelResult) dumpPixelsAndCompareWithExpected(pixelResult); fputs("#EOF\n", stdout); fflush(stdout); fflush(stderr); m_gotFinalMessage = true; TestController::shared().notifyDone(); return; } ASSERT_NOT_REACHED(); } WKRetainPtr<WKTypeRef> TestInvocation::didReceiveSynchronousMessageFromInjectedBundle(WKStringRef /*messageName*/, WKTypeRef /*messageBody*/) { ASSERT_NOT_REACHED(); return 0; } } // namespace WTR