Home | History | Annotate | Download | only in WebKitTestRunner
      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