diff options
Diffstat (limited to 'Tools/WebKitTestRunner')
24 files changed, 566 insertions, 54 deletions
diff --git a/Tools/WebKitTestRunner/InjectedBundle/InjectedBundle.cpp b/Tools/WebKitTestRunner/InjectedBundle/InjectedBundle.cpp index d042431..00933bd 100644 --- a/Tools/WebKitTestRunner/InjectedBundle/InjectedBundle.cpp +++ b/Tools/WebKitTestRunner/InjectedBundle/InjectedBundle.cpp @@ -72,7 +72,7 @@ void InjectedBundle::didReceiveMessage(WKBundleRef bundle, WKStringRef messageNa static_cast<InjectedBundle*>(const_cast<void*>(clientInfo))->didReceiveMessage(messageName, messageBody); } -void InjectedBundle::initialize(WKBundleRef bundle) +void InjectedBundle::initialize(WKBundleRef bundle, WKTypeRef initializationUserData) { m_bundle = bundle; @@ -86,6 +86,8 @@ void InjectedBundle::initialize(WKBundleRef bundle) }; WKBundleSetClient(m_bundle, &client); + platformInitialize(initializationUserData); + activateFonts(); WKBundleActivateMacFontAscentHack(m_bundle); } @@ -173,7 +175,15 @@ void InjectedBundle::done() setTopLoadingFrame(0); WKRetainPtr<WKStringRef> doneMessageName(AdoptWK, WKStringCreateWithUTF8CString("Done")); - WKRetainPtr<WKStringRef> doneMessageBody(AdoptWK, WKStringCreateWithUTF8CString(m_outputStream.str().c_str())); + WKRetainPtr<WKMutableDictionaryRef> doneMessageBody(AdoptWK, WKMutableDictionaryCreate()); + + WKRetainPtr<WKStringRef> textOutputKey(AdoptWK, WKStringCreateWithUTF8CString("TextOutput")); + WKRetainPtr<WKStringRef> textOutput(AdoptWK, WKStringCreateWithUTF8CString(m_outputStream.str().c_str())); + WKDictionaryAddItem(doneMessageBody.get(), textOutputKey.get(), textOutput.get()); + + WKRetainPtr<WKStringRef> textOnlyKey(AdoptWK, WKStringCreateWithUTF8CString("TextOnly")); + WKRetainPtr<WKBooleanRef> textOnly(AdoptWK, WKBooleanCreate(!m_layoutTestController->shouldDumpPixels())); + WKDictionaryAddItem(doneMessageBody.get(), textOnlyKey.get(), textOnly.get()); WKBundlePostMessage(m_bundle, doneMessageName.get(), doneMessageBody.get()); diff --git a/Tools/WebKitTestRunner/InjectedBundle/InjectedBundle.h b/Tools/WebKitTestRunner/InjectedBundle/InjectedBundle.h index 741ade4..41b1b31 100644 --- a/Tools/WebKitTestRunner/InjectedBundle/InjectedBundle.h +++ b/Tools/WebKitTestRunner/InjectedBundle/InjectedBundle.h @@ -45,7 +45,7 @@ public: static InjectedBundle& shared(); // Initialize the InjectedBundle. - void initialize(WKBundleRef); + void initialize(WKBundleRef, WKTypeRef initializationUserData); WKBundleRef bundle() const { return m_bundle; } WKBundlePageGroupRef pageGroup() const { return m_pageGroup; } @@ -82,6 +82,7 @@ private: void didInitializePageGroup(WKBundlePageGroupRef); void didReceiveMessage(WKStringRef messageName, WKTypeRef messageBody); + void platformInitialize(WKTypeRef initializationUserData); void resetLocalSettings(); void beginTesting(); diff --git a/Tools/WebKitTestRunner/InjectedBundle/InjectedBundleMain.cpp b/Tools/WebKitTestRunner/InjectedBundle/InjectedBundleMain.cpp index c4cf892..4e7f58b 100644 --- a/Tools/WebKitTestRunner/InjectedBundle/InjectedBundleMain.cpp +++ b/Tools/WebKitTestRunner/InjectedBundle/InjectedBundleMain.cpp @@ -33,5 +33,5 @@ extern "C" #endif void WKBundleInitialize(WKBundleRef bundle, WKTypeRef initializationUserData) { - WTR::InjectedBundle::shared().initialize(bundle); + WTR::InjectedBundle::shared().initialize(bundle, initializationUserData); } diff --git a/Tools/WebKitTestRunner/InjectedBundle/InjectedBundlePage.cpp b/Tools/WebKitTestRunner/InjectedBundle/InjectedBundlePage.cpp index 739da3b..3ce081e 100644 --- a/Tools/WebKitTestRunner/InjectedBundle/InjectedBundlePage.cpp +++ b/Tools/WebKitTestRunner/InjectedBundle/InjectedBundlePage.cpp @@ -256,6 +256,8 @@ void InjectedBundlePage::reset() WKBundlePageSetTextZoomFactor(m_page, 1); m_previousTestBackForwardListItem = adoptWK(WKBundleBackForwardListCopyItemAtIndex(WKBundlePageGetBackForwardList(m_page), 0)); + + WKBundleFrameClearOpener(WKBundlePageGetMainFrame(m_page)); } // Loader Client Callbacks @@ -493,6 +495,15 @@ void InjectedBundlePage::dump() InjectedBundle::shared().layoutTestController()->invalidateWaitToDumpWatchdogTimer(); + // Force a paint before dumping. This matches DumpRenderTree on Windows. (DumpRenderTree on Mac + // does this at a slightly different time.) See <http://webkit.org/b/55469> for details. + WKBundlePageForceRepaint(m_page); + + WKBundleFrameRef frame = WKBundlePageGetMainFrame(m_page); + string url = toSTD(adoptWK(WKURLCopyString(adoptWK(WKBundleFrameCopyURL(frame)).get()))); + if (strstr(url.c_str(), "dumpAsText/")) + InjectedBundle::shared().layoutTestController()->dumpAsText(); + switch (InjectedBundle::shared().layoutTestController()->whatToDump()) { case LayoutTestController::RenderTree: { WKRetainPtr<WKStringRef> text(AdoptWK, WKBundlePageCopyRenderTreeExternalRepresentation(m_page)); @@ -635,6 +646,7 @@ WKURLRequestRef InjectedBundlePage::willSendRequestForFrame(WKBundlePageRef, WKB return 0; } + WKRetain(request); return request; } diff --git a/Tools/WebKitTestRunner/InjectedBundle/LayoutTestController.cpp b/Tools/WebKitTestRunner/InjectedBundle/LayoutTestController.cpp index 4707ed8..96a0d47 100644 --- a/Tools/WebKitTestRunner/InjectedBundle/LayoutTestController.cpp +++ b/Tools/WebKitTestRunner/InjectedBundle/LayoutTestController.cpp @@ -94,6 +94,7 @@ LayoutTestController::LayoutTestController() , m_dumpEditingCallbacks(false) , m_dumpStatusCallbacks(false) , m_dumpTitleChanges(false) + , m_dumpPixels(true) , m_waitToDump(false) , m_testRepaint(false) , m_testRepaintSweepHorizontally(false) @@ -116,6 +117,12 @@ void LayoutTestController::display() // FIXME: actually implement, once we want pixel tests } +void LayoutTestController::dumpAsText() +{ + m_whatToDump = MainFrameText; + m_dumpPixels = false; +} + void LayoutTestController::waitUntilDone() { m_waitToDump = true; diff --git a/Tools/WebKitTestRunner/InjectedBundle/LayoutTestController.h b/Tools/WebKitTestRunner/InjectedBundle/LayoutTestController.h index 9271124..6733380 100644 --- a/Tools/WebKitTestRunner/InjectedBundle/LayoutTestController.h +++ b/Tools/WebKitTestRunner/InjectedBundle/LayoutTestController.h @@ -55,7 +55,7 @@ public: void makeWindowObject(JSContextRef, JSObjectRef windowObject, JSValueRef* exception); // The basics. - void dumpAsText() { m_whatToDump = MainFrameText; } + void dumpAsText(); void dumpChildFramesAsText() { m_whatToDump = AllFramesText; } void waitUntilDone(); void notifyDone(); @@ -114,6 +114,7 @@ public: bool shouldDumpMainFrameScrollPosition() const { return m_whatToDump == RenderTree; } bool shouldDumpStatusCallbacks() const { return m_dumpStatusCallbacks; } bool shouldDumpTitleChanges() const { return m_dumpTitleChanges; } + bool shouldDumpPixels() const { return m_dumpPixels; } bool waitToDump() const { return m_waitToDump; } void waitToDumpWatchdogTimerFired(); @@ -154,6 +155,7 @@ private: bool m_dumpEditingCallbacks; bool m_dumpStatusCallbacks; bool m_dumpTitleChanges; + bool m_dumpPixels; bool m_waitToDump; // True if waitUntilDone() has been called, but notifyDone() has not yet been called. bool m_testRepaint; bool m_testRepaintSweepHorizontally; diff --git a/Tools/WebKitTestRunner/InjectedBundle/mac/InjectedBundleMac.mm b/Tools/WebKitTestRunner/InjectedBundle/mac/InjectedBundleMac.mm new file mode 100644 index 0000000..7cb8dfa --- /dev/null +++ b/Tools/WebKitTestRunner/InjectedBundle/mac/InjectedBundleMac.mm @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2011 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 "InjectedBundle.h" + +namespace WTR { + +void InjectedBundle::platformInitialize(WKTypeRef) +{ + NSDictionary *dict = [NSDictionary dictionaryWithObjectsAndKeys: + [NSNumber numberWithInteger:4], @"AppleAntiAliasingThreshold", + [NSNumber numberWithInteger:0], @"AppleFontSmoothing", + [NSNumber numberWithBool:NO], @"AppleScrollAnimationEnabled", + [NSNumber numberWithBool:NO], @"NSOverlayScrollersEnabled", + @"Always", @"AppleShowScrollBars", + nil]; + + [[NSUserDefaults standardUserDefaults] registerDefaults:dict]; +} + +} // namespace WTR diff --git a/Tools/WebKitTestRunner/InjectedBundle/qt/InjectedBundle.pro b/Tools/WebKitTestRunner/InjectedBundle/qt/InjectedBundle.pro index 24db4b8..6838205 100644 --- a/Tools/WebKitTestRunner/InjectedBundle/qt/InjectedBundle.pro +++ b/Tools/WebKitTestRunner/InjectedBundle/qt/InjectedBundle.pro @@ -24,6 +24,7 @@ SOURCES += \ ../LayoutTestController.h \ ../Bindings/JSWrapper.cpp \ ActivateFontsQt.cpp \ + InjectedBundleQt.cpp \ LayoutTestControllerQt.cpp \ $$GENERATED_SOURCES_DIR/JSEventSendingController.cpp \ $$GENERATED_SOURCES_DIR/JSGCController.cpp \ @@ -45,27 +46,29 @@ HEADERS += \ include(../../../../Source/WebKit.pri) include(../../../../Source/JavaScriptCore/JavaScriptCore.pri) -addJavaScriptCoreLib(../../../JavaScriptCore) +prependJavaScriptCoreLib(../../../JavaScriptCore) include(../../../../Source/WebKit2/WebKit2.pri) -addWebKit2Lib(../../../WebKit2) +prependWebKit2Lib(../../../WebKit2) -INCLUDEPATH += \ +INCLUDEPATH = \ $$PWD \ $$PWD/.. \ $$PWD/../.. \ $$PWD/../Bindings \ + $$PWD/../../../../Source \ $$PWD/../../../../Source/JavaScriptCore \ - $$PWD/../../../../Source/JavaScriptCore/wtf \ + $$PWD/../../../../Source/JavaScriptCore/ForwardingHeaders \ + $$PWD/../../../../Source/JavaScriptCore/wtf/unicode \ $$PWD/../../../../Source/WebCore \ $$PWD/../../../../Source/WebCore/platform/text \ $$PWD/../../../../Source/WebKit2 \ $$PWD/../../../../Source/WebKit2/Shared \ - $$GENERATED_SOURCES_DIR - -INCLUDEPATH += \ + $$OUTPUT_DIR/include/QtWebKit \ $$OUTPUT_DIR/include \ + $$GENERATED_SOURCES_DIR \ $$WC_GENERATED_SOURCES_DIR + PREFIX_HEADER = $$PWD/../../WebKitTestRunnerPrefix.h *-g++*:QMAKE_CXXFLAGS += "-include $$PREFIX_HEADER" diff --git a/Tools/WebKitTestRunner/InjectedBundle/qt/InjectedBundleQt.cpp b/Tools/WebKitTestRunner/InjectedBundle/qt/InjectedBundleQt.cpp new file mode 100644 index 0000000..52502ed --- /dev/null +++ b/Tools/WebKitTestRunner/InjectedBundle/qt/InjectedBundleQt.cpp @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2011 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 "InjectedBundle.h" + +namespace WTR { + +void InjectedBundle::platformInitialize(WKTypeRef) +{ +} + +} // namespace WTR diff --git a/Tools/WebKitTestRunner/InjectedBundle/win/InjectedBundleWin.cpp b/Tools/WebKitTestRunner/InjectedBundle/win/InjectedBundleWin.cpp new file mode 100644 index 0000000..af8eaed --- /dev/null +++ b/Tools/WebKitTestRunner/InjectedBundle/win/InjectedBundleWin.cpp @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2011 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 "InjectedBundle.h" + +namespace WTR { + +static HANDLE webProcessCrashingEvent; + +static LONG WINAPI exceptionFilter(EXCEPTION_POINTERS*) +{ + // Let the UI process know right away that we crashed. It might take a long time for us to + // finish crashing if a crash log is being saved. + ::SetEvent(webProcessCrashingEvent); + + return EXCEPTION_CONTINUE_SEARCH; +} + +void InjectedBundle::platformInitialize(WKTypeRef initializationUserData) +{ + ::SetUnhandledExceptionFilter(exceptionFilter); + + ASSERT_ARG(initializationUserData, initializationUserData); + ASSERT_ARG(initializationUserData, WKGetTypeID(initializationUserData) == WKStringGetTypeID()); + + WKStringRef string = static_cast<WKStringRef>(initializationUserData); + Vector<char> buffer(WKStringGetMaximumUTF8CStringSize(string)); + WKStringGetUTF8CString(string, buffer.data(), buffer.size()); + + // The UI process should already have created this event. We're just getting another HANDLE to it. + webProcessCrashingEvent = ::CreateEventA(0, FALSE, FALSE, buffer.data()); + ASSERT(webProcessCrashingEvent); +} + +} // namespace WTR diff --git a/Tools/WebKitTestRunner/TestController.cpp b/Tools/WebKitTestRunner/TestController.cpp index 6f5b9a7..d12fff6 100644 --- a/Tools/WebKitTestRunner/TestController.cpp +++ b/Tools/WebKitTestRunner/TestController.cpp @@ -63,6 +63,8 @@ TestController::TestController(int argc, const char* argv[]) , m_doneResetting(false) , m_longTimeout(defaultLongTimeout) , m_shortTimeout(defaultShortTimeout) + , m_didPrintWebProcessCrashedMessage(false) + , m_shouldExitWhenWebProcessCrashes(true) { initialize(argc, argv); controller = this; @@ -327,7 +329,8 @@ void TestController::initialize(int argc, const char* argv[]) 0, // didBecomeUnresponsive 0, // didBecomeResponsive processDidCrash, // processDidCrash - 0 // didChangeBackForwardList + 0, // didChangeBackForwardList + 0 // shouldGoToBackForwardListItem }; WKPageSetPageLoaderClient(m_mainWebView->page(), &pageLoaderClient); } @@ -383,8 +386,20 @@ bool TestController::runTest(const char* test) return false; } + std::string pathOrURL(test); + std::string expectedPixelHash; + size_t separatorPos = pathOrURL.find("'"); + if (separatorPos != std::string::npos) { + pathOrURL = std::string(std::string(test), 0, separatorPos); + expectedPixelHash = std::string(std::string(test), separatorPos + 1); + } + m_state = RunningTest; - m_currentInvocation.set(new TestInvocation(test)); + + m_currentInvocation.set(new TestInvocation(pathOrURL)); + if (m_dumpPixels) + m_currentInvocation->setIsPixelTest(expectedPixelHash); + m_currentInvocation->invoke(); m_currentInvocation.clear(); @@ -395,7 +410,7 @@ void TestController::runTestingServerLoop() { char filenameBuffer[2048]; while (fgets(filenameBuffer, sizeof(filenameBuffer), stdin)) { - char *newLineCharacter = strchr(filenameBuffer, '\n'); + char* newLineCharacter = strchr(filenameBuffer, '\n'); if (newLineCharacter) *newLineCharacter = '\0'; @@ -417,7 +432,6 @@ void TestController::run() break; } } - } void TestController::runUntil(bool& done, TimeoutDuration timeoutDuration) @@ -458,7 +472,7 @@ void TestController::didFinishLoadForFrame(WKPageRef page, WKFrameRef frame, WKT void TestController::processDidCrash(WKPageRef page, const void* clientInfo) { - static_cast<TestController*>(const_cast<void*>(clientInfo))->processDidCrash(page); + static_cast<TestController*>(const_cast<void*>(clientInfo))->processDidCrash(); } void TestController::didFinishLoadForFrame(WKPageRef page, WKFrameRef frame) @@ -477,10 +491,18 @@ void TestController::didFinishLoadForFrame(WKPageRef page, WKFrameRef frame) shared().notifyDone(); } -void TestController::processDidCrash(WKPageRef page) +void TestController::processDidCrash() { - fputs("#CRASHED - WebProcess\n", stderr); - fflush(stderr); + // This function can be called multiple times when crash logs are being saved on Windows, so + // ensure we only print the crashed message once. + if (!m_didPrintWebProcessCrashedMessage) { + fputs("#CRASHED - WebProcess\n", stderr); + fflush(stderr); + m_didPrintWebProcessCrashedMessage = true; + } + + if (m_shouldExitWhenWebProcessCrashes) + exit(1); } } // namespace WTR diff --git a/Tools/WebKitTestRunner/TestController.h b/Tools/WebKitTestRunner/TestController.h index fe37952..0630e2b 100644 --- a/Tools/WebKitTestRunner/TestController.h +++ b/Tools/WebKitTestRunner/TestController.h @@ -83,7 +83,7 @@ private: void didFinishLoadForFrame(WKPageRef page, WKFrameRef frame); static void processDidCrash(WKPageRef, const void* clientInfo); - void processDidCrash(WKPageRef); + void processDidCrash(); static WKPageRef createOtherPage(WKPageRef oldPage, WKDictionaryRef, WKEventModifiers, WKEventMouseButton, const void*); @@ -117,6 +117,9 @@ private: double m_longTimeout; double m_shortTimeout; + + bool m_didPrintWebProcessCrashedMessage; + bool m_shouldExitWhenWebProcessCrashes; }; } // namespace WTR diff --git a/Tools/WebKitTestRunner/TestInvocation.cpp b/Tools/WebKitTestRunner/TestInvocation.cpp index 3af184a..3227be9 100644 --- a/Tools/WebKitTestRunner/TestInvocation.cpp +++ b/Tools/WebKitTestRunner/TestInvocation.cpp @@ -30,6 +30,7 @@ #include "TestController.h" #include <climits> #include <cstdio> +#include <WebKit2/WKDictionary.h> #include <WebKit2/WKContextPrivate.h> #include <WebKit2/WKInspector.h> #include <WebKit2/WKRetainPtr.h> @@ -57,7 +58,8 @@ static WKURLRef createWKURL(const char* pathOrURL) if (!length) return 0; - const char* filePrefix = "file://"; + // 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 = '\\'; @@ -85,18 +87,25 @@ static WKURLRef createWKURL(const char* pathOrURL) return WKURLCreateWithUTF8CString(buffer.get()); } -TestInvocation::TestInvocation(const char* pathOrURL) - : m_url(AdoptWK, createWKURL(pathOrURL)) - , m_pathOrURL(fastStrDup(pathOrURL)) +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() { - fastFree(m_pathOrURL); +} + +void TestInvocation::setIsPixelTest(const std::string& expectedPixelHash) +{ + m_dumpPixels = true; + m_expectedPixelHash = expectedPixelHash; } static const unsigned w3cSVGWidth = 480; @@ -104,7 +113,7 @@ static const unsigned w3cSVGHeight = 360; static const unsigned normalWidth = 800; static const unsigned normalHeight = 600; -static void sizeWebViewForCurrentTest(char* pathOrURL) +static void sizeWebViewForCurrentTest(const char* pathOrURL) { bool isSVGW3CTest = strstr(pathOrURL, "svg/W3C-SVG-1.1") || strstr(pathOrURL, "svg\\W3C-SVG-1.1"); @@ -116,12 +125,12 @@ static void sizeWebViewForCurrentTest(char* pathOrURL) static bool shouldOpenWebInspector(const char* pathOrURL) { - return strstr(pathOrURL, "inspector/"); + return strstr(pathOrURL, "inspector/") || strstr(pathOrURL, "inspector\\"); } void TestInvocation::invoke() { - sizeWebViewForCurrentTest(m_pathOrURL); + sizeWebViewForCurrentTest(m_pathOrURL.c_str()); WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("BeginTest")); WKContextPostMessageToInjectedBundle(TestController::shared().context(), messageName.get(), 0); @@ -136,7 +145,7 @@ void TestInvocation::invoke() return; } - if (shouldOpenWebInspector(m_pathOrURL)) + if (shouldOpenWebInspector(m_pathOrURL.c_str())) WKInspectorShow(WKPageGetInspector(TestController::shared().mainWebView()->page())); WKPageLoadURL(TestController::shared().mainWebView()->page(), m_url.get()); @@ -156,11 +165,7 @@ void TestInvocation::dump(const char* stringToDump) printf("%s", stringToDump); fputs("#EOF\n", stdout); - fputs("#EOF\n", stdout); fputs("#EOF\n", stderr); - - fflush(stdout); - fflush(stderr); } void TestInvocation::didReceiveMessageFromInjectedBundle(WKStringRef messageName, WKTypeRef messageBody) @@ -187,11 +192,26 @@ void TestInvocation::didReceiveMessageFromInjectedBundle(WKStringRef messageName } if (WKStringIsEqualToUTF8CString(messageName, "Done")) { - ASSERT(WKGetTypeID(messageBody) == WKStringGetTypeID()); - WKStringRef messageBodyString = static_cast<WKStringRef>(messageBody); + 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> textOnlyKey(AdoptWK, WKStringCreateWithUTF8CString("TextOnly")); + bool textOnly = WKBooleanGetValue(static_cast<WKBooleanRef>(WKDictionaryGetItemForKey(messageBodyDictionary, textOnlyKey.get()))); + + // Dump text. + dump(toSTD(textOutput).c_str()); - dump(toSTD(messageBodyString).c_str()); + // Dump pixels (if necessary). + if (m_dumpPixels && !textOnly) + dumpPixelsAndCompareWithExpected(); + fputs("#EOF\n", stdout); + fflush(stdout); + fflush(stderr); + m_gotFinalMessage = true; TestController::shared().notifyDone(); return; diff --git a/Tools/WebKitTestRunner/TestInvocation.h b/Tools/WebKitTestRunner/TestInvocation.h index efc6635..d5a4af9 100644 --- a/Tools/WebKitTestRunner/TestInvocation.h +++ b/Tools/WebKitTestRunner/TestInvocation.h @@ -26,6 +26,7 @@ #ifndef TestInvocation_h #define TestInvocation_h +#include <string> #include <WebKit2/WKRetainPtr.h> #include <wtf/Noncopyable.h> @@ -34,22 +35,29 @@ namespace WTR { class TestInvocation { WTF_MAKE_NONCOPYABLE(TestInvocation); public: - TestInvocation(const char*); + TestInvocation(const std::string& pathOrURL); ~TestInvocation(); + void setIsPixelTest(const std::string& expectedPixelHash); + void invoke(); void didReceiveMessageFromInjectedBundle(WKStringRef messageName, WKTypeRef messageBody); WKRetainPtr<WKTypeRef> didReceiveSynchronousMessageFromInjectedBundle(WKStringRef messageName, WKTypeRef messageBody); private: void dump(const char*); - + void dumpPixelsAndCompareWithExpected(); + WKRetainPtr<WKURLRef> m_url; - char* m_pathOrURL; + std::string m_pathOrURL; + + bool m_dumpPixels; + std::string m_expectedPixelHash; // Invocation state bool m_gotInitialResponse; bool m_gotFinalMessage; + bool m_gotRepaint; bool m_error; }; diff --git a/Tools/WebKitTestRunner/WebKitTestRunner.xcodeproj/project.pbxproj b/Tools/WebKitTestRunner/WebKitTestRunner.xcodeproj/project.pbxproj index 8428403..62105cd 100644 --- a/Tools/WebKitTestRunner/WebKitTestRunner.xcodeproj/project.pbxproj +++ b/Tools/WebKitTestRunner/WebKitTestRunner.xcodeproj/project.pbxproj @@ -47,6 +47,8 @@ BC7934AC1190658C005EA8E2 /* WebKit2.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = BC7934AB1190658C005EA8E2 /* WebKit2.framework */; }; BC7934E811906846005EA8E2 /* PlatformWebViewMac.mm in Sources */ = {isa = PBXBuildFile; fileRef = BC7934E711906846005EA8E2 /* PlatformWebViewMac.mm */; }; BC8C795C11D2785D004535A1 /* TestControllerMac.mm in Sources */ = {isa = PBXBuildFile; fileRef = BC8C795B11D2785D004535A1 /* TestControllerMac.mm */; }; + BC8DAD5D1315C0EC00EC96FC /* TestInvocationMac.mm in Sources */ = {isa = PBXBuildFile; fileRef = BC8DAD5B1315C0EC00EC96FC /* TestInvocationMac.mm */; }; + BC8DAD7B1316D91000EC96FC /* InjectedBundleMac.mm in Sources */ = {isa = PBXBuildFile; fileRef = BC8DAD771316D7B900EC96FC /* InjectedBundleMac.mm */; }; BC8FD8CA120E527F00F3E71A /* EventSendingController.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BC8FD8C9120E527F00F3E71A /* EventSendingController.cpp */; }; BC8FD8D2120E545B00F3E71A /* JSEventSendingController.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BC8FD8D0120E545B00F3E71A /* JSEventSendingController.cpp */; }; BC952C0D11F3B965003398B4 /* JSWrapper.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BC952C0C11F3B965003398B4 /* JSWrapper.cpp */; }; @@ -113,6 +115,8 @@ BC7934DD119066EC005EA8E2 /* PlatformWebView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PlatformWebView.h; sourceTree = "<group>"; }; BC7934E711906846005EA8E2 /* PlatformWebViewMac.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = PlatformWebViewMac.mm; sourceTree = "<group>"; }; BC8C795B11D2785D004535A1 /* TestControllerMac.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = TestControllerMac.mm; sourceTree = "<group>"; }; + BC8DAD5B1315C0EC00EC96FC /* TestInvocationMac.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = TestInvocationMac.mm; sourceTree = "<group>"; }; + BC8DAD771316D7B900EC96FC /* InjectedBundleMac.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = InjectedBundleMac.mm; sourceTree = "<group>"; }; BC8FD8C8120E527F00F3E71A /* EventSendingController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = EventSendingController.h; sourceTree = "<group>"; }; BC8FD8C9120E527F00F3E71A /* EventSendingController.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = EventSendingController.cpp; sourceTree = "<group>"; }; BC8FD8CB120E52B000F3E71A /* EventSendingController.idl */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = EventSendingController.idl; sourceTree = "<group>"; }; @@ -218,6 +222,7 @@ isa = PBXGroup; children = ( 65EB859F11EC67CC0034D300 /* ActivateFonts.mm */, + BC8DAD771316D7B900EC96FC /* InjectedBundleMac.mm */, ); path = mac; sourceTree = "<group>"; @@ -278,6 +283,7 @@ BC7933FF118F7C84005EA8E2 /* main.mm */, BC7934E711906846005EA8E2 /* PlatformWebViewMac.mm */, BC8C795B11D2785D004535A1 /* TestControllerMac.mm */, + BC8DAD5B1315C0EC00EC96FC /* TestInvocationMac.mm */, ); path = mac; sourceTree = "<group>"; @@ -440,6 +446,7 @@ BC793431118F7F19005EA8E2 /* TestController.cpp in Sources */, BC7934E811906846005EA8E2 /* PlatformWebViewMac.mm in Sources */, BCD7D2F811921278006DB7EE /* TestInvocation.cpp in Sources */, + BC8DAD5D1315C0EC00EC96FC /* TestInvocationMac.mm in Sources */, BC8C795C11D2785D004535A1 /* TestControllerMac.mm in Sources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -457,6 +464,7 @@ BC952F1F11F3C652003398B4 /* JSLayoutTestController.cpp in Sources */, BC14E4DB120E02D000826C0C /* GCController.cpp in Sources */, BC14E4EA120E03D800826C0C /* JSGCController.cpp in Sources */, + BC8DAD7B1316D91000EC96FC /* InjectedBundleMac.mm in Sources */, BC8FD8CA120E527F00F3E71A /* EventSendingController.cpp in Sources */, BC8FD8D2120E545B00F3E71A /* JSEventSendingController.cpp in Sources */, C0CE720B1247C93300BC0EC4 /* LayoutTestControllerMac.mm in Sources */, diff --git a/Tools/WebKitTestRunner/mac/PlatformWebViewMac.mm b/Tools/WebKitTestRunner/mac/PlatformWebViewMac.mm index b68f6a3..8415692 100644 --- a/Tools/WebKitTestRunner/mac/PlatformWebViewMac.mm +++ b/Tools/WebKitTestRunner/mac/PlatformWebViewMac.mm @@ -34,7 +34,7 @@ PlatformWebView::PlatformWebView(WKContextRef contextRef, WKPageGroupRef pageGro NSRect windowRect = NSOffsetRect(rect, -10000, [[[NSScreen screens] objectAtIndex:0] frame].size.height - rect.size.height + 10000); m_window = [[NSWindow alloc] initWithContentRect:windowRect styleMask:NSBorderlessWindowMask backing:NSBackingStoreBuffered defer:YES]; - [m_window setColorSpace:[[NSScreen mainScreen] colorSpace]]; + [m_window setColorSpace:[NSColorSpace genericRGBColorSpace]]; [[m_window contentView] addSubview:m_view]; [m_window orderBack:nil]; [m_window setAutodisplay:NO]; diff --git a/Tools/WebKitTestRunner/mac/TestInvocationMac.mm b/Tools/WebKitTestRunner/mac/TestInvocationMac.mm new file mode 100644 index 0000000..13a0295 --- /dev/null +++ b/Tools/WebKitTestRunner/mac/TestInvocationMac.mm @@ -0,0 +1,156 @@ +/* + * Copyright (C) 2011 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 "TestInvocation.h" + +#include "PlatformWebView.h" +#include "TestController.h" +#include <ImageIO/CGImageDestination.h> +#include <LaunchServices/UTCoreTypes.h> +#include <WebKit2/WKPage.h> +#include <wtf/RetainPtr.h> + +#define COMMON_DIGEST_FOR_OPENSSL +#include <CommonCrypto/CommonDigest.h> + +namespace WTR { + +static CGContextRef createCGContextFromPlatformView(PlatformWebView* platformWebView) +{ + WKView* view = platformWebView->platformView(); + [view display]; + + NSSize webViewSize = [view frame].size; + size_t pixelsWide = static_cast<size_t>(webViewSize.width); + size_t pixelsHigh = static_cast<size_t>(webViewSize.height); + size_t rowBytes = (4 * pixelsWide + 63) & ~63; + void* buffer = calloc(pixelsHigh, rowBytes); + + CGColorSpaceRef colorSpace = CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB); + CGContextRef context = CGBitmapContextCreate(buffer, pixelsWide, pixelsHigh, 8, rowBytes, colorSpace, kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Host); + CGColorSpaceRelease(colorSpace); + + CGImageRef image = CGWindowListCreateImage(CGRectNull, kCGWindowListOptionIncludingWindow, [[view window] windowNumber], kCGWindowImageBoundsIgnoreFraming | kCGWindowImageShouldBeOpaque); + CGContextDrawImage(context, CGRectMake(0, 0, CGImageGetWidth(image), CGImageGetHeight(image)), image); + CGImageRelease(image); + + return context; +} + +void computeMD5HashStringForContext(CGContextRef bitmapContext, char hashString[33]) +{ + ASSERT(CGBitmapContextGetBitsPerPixel(bitmapContext) == 32); // ImageDiff assumes 32 bit RGBA, we must as well. + size_t pixelsHigh = CGBitmapContextGetHeight(bitmapContext); + size_t pixelsWide = CGBitmapContextGetWidth(bitmapContext); + size_t bytesPerRow = CGBitmapContextGetBytesPerRow(bitmapContext); + + // We need to swap the bytes to ensure consistent hashes independently of endianness + MD5_CTX md5Context; + MD5_Init(&md5Context); + unsigned char* bitmapData = static_cast<unsigned char*>(CGBitmapContextGetData(bitmapContext)); + if ((CGBitmapContextGetBitmapInfo(bitmapContext) & kCGBitmapByteOrderMask) == kCGBitmapByteOrder32Big) { + for (unsigned row = 0; row < pixelsHigh; row++) { + uint32_t buffer[pixelsWide]; + for (unsigned column = 0; column < pixelsWide; column++) + buffer[column] = OSReadLittleInt32(bitmapData, 4 * column); + MD5_Update(&md5Context, buffer, 4 * pixelsWide); + bitmapData += bytesPerRow; + } + } else { + for (unsigned row = 0; row < pixelsHigh; row++) { + MD5_Update(&md5Context, bitmapData, 4 * pixelsWide); + bitmapData += bytesPerRow; + } + } + + unsigned char hash[16]; + MD5_Final(hash, &md5Context); + + hashString[0] = '\0'; + for (int i = 0; i < 16; i++) + snprintf(hashString, 33, "%s%02x", hashString, hash[i]); +} + +static void dumpBitmap(CGContextRef bitmapContext) +{ + RetainPtr<CGImageRef> image(AdoptCF, CGBitmapContextCreateImage(bitmapContext)); + RetainPtr<CFMutableDataRef> imageData(AdoptCF, CFDataCreateMutable(0, 0)); + RetainPtr<CGImageDestinationRef> imageDest(AdoptCF, CGImageDestinationCreateWithData(imageData.get(), kUTTypePNG, 1, 0)); + CGImageDestinationAddImage(imageDest.get(), image.get(), 0); + CGImageDestinationFinalize(imageDest.get()); + + const unsigned char* data = CFDataGetBytePtr(imageData.get()); + const size_t dataLength = CFDataGetLength(imageData.get()); + + + fprintf(stdout, "Content-Type: %s\n", "image/png"); + fprintf(stdout, "Content-Length: %lu\n", static_cast<unsigned long>(dataLength)); + + const size_t bytesToWriteInOneChunk = 1 << 15; + size_t dataRemainingToWrite = dataLength; + while (dataRemainingToWrite) { + size_t bytesToWriteInThisChunk = std::min(dataRemainingToWrite, bytesToWriteInOneChunk); + size_t bytesWritten = fwrite(data, 1, bytesToWriteInThisChunk, stdout); + if (bytesWritten != bytesToWriteInThisChunk) + break; + dataRemainingToWrite -= bytesWritten; + data += bytesWritten; + } +} + +static void forceRepaintFunction(WKErrorRef, void* context) +{ + *static_cast<bool*>(context) = true; +} + +void TestInvocation::dumpPixelsAndCompareWithExpected() +{ + WKPageForceRepaint(TestController::shared().mainWebView()->page(), &m_gotRepaint, forceRepaintFunction); + TestController::shared().runUntil(m_gotRepaint, TestController::LongTimeout); + + CGContextRef context = createCGContextFromPlatformView(TestController::shared().mainWebView()); + + // Compute the hash of the bitmap context pixels + char actualHash[33]; + computeMD5HashStringForContext(context, actualHash); + fprintf(stdout, "\nActualHash: %s\n", actualHash); + + // Check the computed hash against the expected one and dump image on mismatch + bool hashesMatch = false; + if (m_expectedPixelHash.length() > 0) { + ASSERT(m_expectedPixelHash.length() == 32); + + fprintf(stdout, "\nExpectedHash: %s\n", m_expectedPixelHash.c_str()); + + // FIXME: Do case insensitive compare. + if (m_expectedPixelHash == actualHash) + hashesMatch = true; + } + + if (!hashesMatch) + dumpBitmap(context); +} + +} // namespace WTR diff --git a/Tools/WebKitTestRunner/qt/TestInvocationQt.cpp b/Tools/WebKitTestRunner/qt/TestInvocationQt.cpp new file mode 100644 index 0000000..b5fbda4 --- /dev/null +++ b/Tools/WebKitTestRunner/qt/TestInvocationQt.cpp @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2011 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 "TestInvocation.h" + +namespace WTR { + +void TestInvocation::dumpPixelsAndCompareWithExpected() +{ +} + +} // namespace WTR diff --git a/Tools/WebKitTestRunner/qt/WebKitTestRunner.pro b/Tools/WebKitTestRunner/qt/WebKitTestRunner.pro index de648ea..d6579a4 100644 --- a/Tools/WebKitTestRunner/qt/WebKitTestRunner.pro +++ b/Tools/WebKitTestRunner/qt/WebKitTestRunner.pro @@ -8,12 +8,6 @@ GENERATED_SOURCES_DIR = ../generated include(../../../Source/WebKit.pri) -!CONFIG(release, debug|release) { - OBJECTS_DIR = obj/debug -} else { # Release - OBJECTS_DIR = obj/release -} - DEFINES += USE_SYSTEM_MALLOC=1 INCLUDEPATH += \ @@ -48,6 +42,7 @@ SOURCES = \ main.cpp \ PlatformWebViewQt.cpp \ TestControllerQt.cpp \ + TestInvocationQt.cpp \ $$BASEDIR/TestController.cpp \ $$BASEDIR/TestInvocation.cpp \ @@ -68,4 +63,4 @@ linux-* { } include(../../../Source/JavaScriptCore/JavaScriptCore.pri) -addJavaScriptCoreLib(../../JavaScriptCore) +prependJavaScriptCoreLib(../../JavaScriptCore) diff --git a/Tools/WebKitTestRunner/win/InjectedBundle.vcproj b/Tools/WebKitTestRunner/win/InjectedBundle.vcproj index f615d50..eec770b 100644 --- a/Tools/WebKitTestRunner/win/InjectedBundle.vcproj +++ b/Tools/WebKitTestRunner/win/InjectedBundle.vcproj @@ -439,6 +439,10 @@ > </File> <File + RelativePath="..\InjectedBundle\win\InjectedBundleWin.cpp" + > + </File> + <File RelativePath="..\InjectedBundle\EventSendingController.cpp" > </File> diff --git a/Tools/WebKitTestRunner/win/PlatformWebViewWin.cpp b/Tools/WebKitTestRunner/win/PlatformWebViewWin.cpp index c132275..e75ccc8 100644 --- a/Tools/WebKitTestRunner/win/PlatformWebViewWin.cpp +++ b/Tools/WebKitTestRunner/win/PlatformWebViewWin.cpp @@ -54,6 +54,7 @@ PlatformWebView::PlatformWebView(WKContextRef contextRef, WKPageGroupRef pageGro RECT viewRect = {0, 0, 800, 600}; m_window = CreateWindowExW(0, hostWindowClassName, L"WebKitTestRunner", WS_OVERLAPPEDWINDOW, 0 /*XOFFSET*/, 0 /*YOFFSET*/, viewRect.right, viewRect.bottom, 0, 0, GetModuleHandle(0), 0); m_view = WKViewCreate(viewRect, contextRef, pageGroupRef, m_window); + WKViewSetIsInWindow(m_view, true); } PlatformWebView::~PlatformWebView() diff --git a/Tools/WebKitTestRunner/win/TestControllerWin.cpp b/Tools/WebKitTestRunner/win/TestControllerWin.cpp index 5af5503..6201cf7 100644 --- a/Tools/WebKitTestRunner/win/TestControllerWin.cpp +++ b/Tools/WebKitTestRunner/win/TestControllerWin.cpp @@ -38,6 +38,13 @@ using namespace std; namespace WTR { +static HANDLE webProcessCrashingEvent; +static const char webProcessCrashingEventName[] = "WebKitTestRunner.WebProcessCrashing"; +// This is the longest we'll wait (in seconds) for the web process to finish crashing and a crash +// log to be saved. This interval should be just a tiny bit longer than it will ever reasonably +// take to save a crash log. +static const double maximumWaitForWebProcessToCrash = 60; + #ifdef DEBUG_ALL const LPWSTR testPluginDirectoryName = L"TestNetscapePlugin_Debug"; const char* injectedBundleDLL = "\\InjectedBundle_debug.dll"; @@ -96,6 +103,11 @@ void TestController::notifyDone() void TestController::platformInitialize() { + // Cygwin calls ::SetErrorMode(SEM_FAILCRITICALERRORS), which we will inherit. This is bad for + // testing/debugging, as it causes the post-mortem debugger not to be invoked. We reset the + // error mode here to work around Cygwin's behavior. See <http://webkit.org/b/55222>. + ::SetErrorMode(0); + ::SetUnhandledExceptionFilter(exceptionFilter); _setmode(1, _O_BINARY); @@ -104,6 +116,8 @@ void TestController::platformInitialize() // Add the QuickTime dll directory to PATH or QT 7.6 will fail to initialize on systems // linked with older versions of qtmlclientlib.dll. addQTDirToPATH(); + + webProcessCrashingEvent = ::CreateEventA(0, FALSE, FALSE, webProcessCrashingEventName); } void TestController::initializeInjectedBundlePath() @@ -124,19 +138,26 @@ void TestController::initializeTestPluginDirectory() m_testPluginDirectory.adopt(WKStringCreateWithCFString(testPluginDirectoryPath.get())); } -void TestController::platformRunUntil(bool& done, double timeout) +enum RunLoopResult { TimedOut, ObjectSignaled, ConditionSatisfied }; + +static RunLoopResult runRunLoopUntil(bool& condition, HANDLE object, double timeout) { DWORD end = ::GetTickCount() + timeout * 1000; - while (!done) { + while (!condition) { DWORD now = ::GetTickCount(); if (now > end) - return; + return TimedOut; - DWORD result = ::MsgWaitForMultipleObjectsEx(0, 0, end - now, QS_ALLINPUT, 0); + DWORD objectCount = object ? 1 : 0; + const HANDLE* objects = object ? &object : 0; + DWORD result = ::MsgWaitForMultipleObjectsEx(objectCount, objects, end - now, QS_ALLINPUT, MWMO_INPUTAVAILABLE); if (result == WAIT_TIMEOUT) - return; + return TimedOut; - ASSERT(result == WAIT_OBJECT_0); + if (objectCount && result >= WAIT_OBJECT_0 && result < WAIT_OBJECT_0 + objectCount) + return ObjectSignaled; + + ASSERT(result == WAIT_OBJECT_0 + objectCount); // There are messages in the queue. Process them. MSG msg; while (::PeekMessageW(&msg, 0, 0, 0, PM_REMOVE)) { @@ -144,12 +165,45 @@ void TestController::platformRunUntil(bool& done, double timeout) ::DispatchMessageW(&msg); } } + + return ConditionSatisfied; +} + +void TestController::platformRunUntil(bool& done, double timeout) +{ + RunLoopResult result = runRunLoopUntil(done, webProcessCrashingEvent, timeout); + if (result == TimedOut || result == ConditionSatisfied) + return; + ASSERT(result == ObjectSignaled); + + // The web process is crashing. A crash log might be being saved, which can take a long + // time, and we don't want to time out while that happens. + + // First, let the test harness know this happened so it won't think we've hung. But + // make sure we don't exit just yet! + m_shouldExitWhenWebProcessCrashes = false; + processDidCrash(); + m_shouldExitWhenWebProcessCrashes = true; + + // Then spin a run loop until it finishes crashing to give time for a crash log to be saved. If + // it takes too long for a crash log to be saved, we'll just give up. + bool neverSetCondition = false; + result = runRunLoopUntil(neverSetCondition, 0, maximumWaitForWebProcessToCrash); + ASSERT_UNUSED(result, result == TimedOut); + exit(1); +} + +static WKRetainPtr<WKStringRef> toWK(const char* string) +{ + return WKRetainPtr<WKStringRef>(AdoptWK, WKStringCreateWithUTF8CString(string)); } void TestController::platformInitializeContext() { // FIXME: Make DRT pass with Windows native controls. <http://webkit.org/b/25592> WKContextSetShouldPaintNativeControls(m_context.get(), false); + + WKContextSetInitializationUserDataForInjectedBundle(m_context.get(), toWK(webProcessCrashingEventName).get()); } void TestController::runModal(PlatformWebView*) diff --git a/Tools/WebKitTestRunner/win/TestInvocationWin.cpp b/Tools/WebKitTestRunner/win/TestInvocationWin.cpp new file mode 100644 index 0000000..b5fbda4 --- /dev/null +++ b/Tools/WebKitTestRunner/win/TestInvocationWin.cpp @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2011 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 "TestInvocation.h" + +namespace WTR { + +void TestInvocation::dumpPixelsAndCompareWithExpected() +{ +} + +} // namespace WTR diff --git a/Tools/WebKitTestRunner/win/WebKitTestRunner.vcproj b/Tools/WebKitTestRunner/win/WebKitTestRunner.vcproj index 09dea95..e12338a 100644 --- a/Tools/WebKitTestRunner/win/WebKitTestRunner.vcproj +++ b/Tools/WebKitTestRunner/win/WebKitTestRunner.vcproj @@ -401,6 +401,10 @@ RelativePath=".\TestControllerWin.cpp" > </File> + <File + RelativePath=".\TestInvocationWin.cpp" + > + </File> </Filter> <File RelativePath="..\PlatformWebView.h" |