blob: cadecaf8f05fc81d59d70d50a697e49a33999a50 [file] [log] [blame] [edit]
/*
* Copyright (C) 2008 Kevin Ollivier <kevino@theolliviers.com>
*
* 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.
* 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
* its contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY APPLE 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 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 "DumpRenderTree.h"
#include "TestRunner.h"
#include "WorkQueue.h"
#include "WorkQueueItem.h"
#include <JavaScriptCore/JavaScript.h>
#include <wx/wx.h>
#include "WebView.h"
#include "WebFrame.h"
#include "WebBrowserShell.h"
#include <wtf/Assertions.h>
#include <cassert>
#include <stdlib.h>
#include <string.h>
#include <time.h>
volatile bool done = true;
volatile bool notified = false;
static bool printSeparators = true;
static int dumpPixelsForAllTests = false;
static int dumpPixelsForCurrentTest;
static int dumpTree = 1;
time_t startTime; // to detect timeouts / failed tests
using namespace std;
using namespace WebKit;
FILE* logOutput;
RefPtr<TestRunner> gTestRunner;
static WebView* webView;
static wxTimer* idleTimer;
const unsigned timeOut = 10;
const unsigned maxViewHeight = 600;
const unsigned maxViewWidth = 800;
class LayoutWebViewEventHandler : public wxEvtHandler {
public:
LayoutWebViewEventHandler(WebView* webView)
: m_webView(webView)
{
}
void bindEvents()
{
m_webView->Connect(wxEVT_WEBVIEW_LOAD, WebViewLoadEventHandler(LayoutWebViewEventHandler::OnLoadEvent), 0, this);
m_webView->Connect(wxEVT_WEBVIEW_JS_ALERT, WebViewAlertEventHandler(LayoutWebViewEventHandler::OnAlertEvent), 0, this);
m_webView->Connect(wxEVT_WEBVIEW_JS_CONFIRM, WebViewConfirmEventHandler(LayoutWebViewEventHandler::OnConfirmEvent), 0, this);
m_webView->Connect(wxEVT_WEBVIEW_JS_PROMPT, WebViewPromptEventHandler(LayoutWebViewEventHandler::OnPromptEvent), 0, this);
m_webView->Connect(wxEVT_WEBVIEW_CONSOLE_MESSAGE, WebViewConsoleMessageEventHandler(LayoutWebViewEventHandler::OnConsoleMessageEvent), 0, this);
m_webView->Connect(wxEVT_WEBVIEW_RECEIVED_TITLE, WebViewReceivedTitleEventHandler(LayoutWebViewEventHandler::OnReceivedTitleEvent), 0, this);
m_webView->Connect(wxEVT_WEBVIEW_WINDOW_OBJECT_CLEARED, WebViewWindowObjectClearedEventHandler(LayoutWebViewEventHandler::OnWindowObjectClearedEvent), 0, this);
}
void OnLoadEvent(WebViewLoadEvent& event)
{
if (event.GetState() == WEBVIEW_LOAD_FAILED || event.GetState() == WEBVIEW_LOAD_STOPPED)
done = true;
if (event.GetState() == WEBVIEW_LOAD_ONLOAD_HANDLED) {
done = true;
if (!gTestRunner->waitToDump() || notified) {
dump();
}
}
}
void OnAlertEvent(WebViewAlertEvent& event)
{
wxFprintf(stdout, "ALERT: %S\n", event.GetMessage());
}
void OnConfirmEvent(WebViewConfirmEvent& event)
{
wxFprintf(stdout, "CONFIRM: %S\n", event.GetMessage());
event.SetReturnCode(1);
}
void OnPromptEvent(WebViewPromptEvent& event)
{
wxFprintf(stdout, "PROMPT: %S, default text: %S\n", event.GetMessage(), event.GetResponse());
event.SetReturnCode(1);
}
void OnConsoleMessageEvent(WebViewConsoleMessageEvent& event)
{
fprintf(stdout, "CONSOLE MESSAGE: ");
if (event.GetLineNumber())
fprintf(stdout, "line %d: ", event.GetLineNumber());
wxFprintf(stdout, "%S\n", event.GetMessage());
}
void OnReceivedTitleEvent(WebViewReceivedTitleEvent& event)
{
if (gTestRunner->dumpTitleChanges() && !done)
wxFprintf(stdout, "TITLE CHANGED: '%S'\n", event.GetTitle());
}
void OnWindowObjectClearedEvent(WebViewWindowObjectClearedEvent& event)
{
JSValueRef exception = 0;
gTestRunner->makeWindowObject(event.GetJSContext(), event.GetWindowObject(), &exception);
}
private:
WebView* m_webView;
};
void notifyDoneFired()
{
notified = true;
if (done)
dump();
}
LayoutWebViewEventHandler* eventHandler = 0;
static wxString dumpFramesAsText(WebFrame* frame)
{
// TODO: implement this. leaving this here so we don't forget this case.
if (gTestRunner->dumpChildFramesAsText()) {
}
return frame->GetInnerText();
}
void dump()
{
if (!done)
return;
if (gTestRunner->waitToDump() && !notified)
return;
if (dumpTree) {
const char* result = 0;
bool dumpAsText = gTestRunner->dumpAsText();
wxString str;
if (gTestRunner->dumpAsText())
str = dumpFramesAsText(webView->GetMainFrame());
else
str = webView->GetMainFrame()->GetExternalRepresentation();
result = str.ToUTF8();
if (!result) {
const char* errorMessage;
if (gTestRunner->dumpAsText())
errorMessage = "WebFrame::GetInnerText";
else
errorMessage = "WebFrame::GetExternalRepresentation";
printf("ERROR: 0 result from %s", errorMessage);
} else {
printf("%s\n", result);
}
if (gTestRunner->dumpBackForwardList()) {
// FIXME: not implemented
}
if (printSeparators) {
puts("#EOF");
fputs("#EOF\n", stderr);
fflush(stdout);
fflush(stderr);
}
}
if (dumpPixelsForCurrentTest
&& gTestRunner->generatePixelResults()
&& !gTestRunner->dumpDOMAsWebArchive()
&& !gTestRunner->dumpSourceAsWebArchive()) {
// FIXME: Add support for dumping pixels
fflush(stdout);
}
puts("#EOF");
fflush(stdout);
fflush(stderr);
gTestRunner.clear();
}
static void runTest(const wxString inputLine)
{
done = false;
time(&startTime);
TestCommand command = parseInputLine(std::string(inputLine.ToAscii()));
string& pathOrURL = command.pathOrURL;
dumpPixelsForCurrentTest = command.shouldDumpPixels || dumpPixelsForAllTests;
// CURL isn't happy if we don't have a protocol.
size_t http = pathOrURL.find("http://");
if (http == string::npos)
pathOrURL.insert(0, "file://");
gTestRunner = TestRunner::create(pathOrURL, command.expectedPixelHash);
if (!gTestRunner) {
wxTheApp->ExitMainLoop();
}
WorkQueue::shared()->clear();
WorkQueue::shared()->setFrozen(false);
webView->LoadURL(wxString(pathOrURL.c_str(), wxConvUTF8));
// wait until load completes and the results are dumped
while (!done)
wxSafeYield();
}
class MyApp : public wxApp
{
public:
virtual bool OnInit();
private:
wxLog* logger;
};
IMPLEMENT_APP(MyApp)
bool MyApp::OnInit()
{
logOutput = fopen("output.txt", "ab");
if (logOutput) {
logger = new wxLogStderr(logOutput);
wxLog::SetActiveTarget(logger);
}
wxLogMessage(wxT("Starting DumpRenderTool, %d args.\n"), argc);
for (int i = 1; i < argc; ++i) {
wxString option = wxString(argv[i]);
if (!option.CmpNoCase(_T("--notree"))) {
dumpTree = false;
continue;
}
if (!option.CmpNoCase(_T("--tree"))) {
dumpTree = true;
continue;
}
if (!option.CmpNoCase(_T("--pixel-tests"))) {
dumpPixelsForAllTests = true;
continue;
}
}
wxInitAllImageHandlers();
// create the main application window
WebBrowserShell* webFrame = new WebBrowserShell(_T("wxWebKit DumpRenderTree App"), "about:blank");
SetTopWindow(webFrame);
webView = webFrame->webview;
webView->SetSize(wxSize(maxViewWidth, maxViewHeight));
if (!eventHandler) {
eventHandler = new LayoutWebViewEventHandler(webView);
eventHandler->bindEvents();
}
int optind = 1;
time(&startTime);
wxString option_str = wxString(argv[optind]);
if (argc == optind+1 && option_str.Find(_T("-")) == 0) {
char filenameBuffer[2048];
while (fgets(filenameBuffer, sizeof(filenameBuffer), stdin)) {
wxString filename = wxString::FromUTF8(filenameBuffer);
char* newLineCharacter = strchr(filenameBuffer, '\n');
if (newLineCharacter)
*newLineCharacter = '\0';
if (strlen(filenameBuffer) == 0)
return 0;
wxLogMessage(wxT("Running test %S.\n"), filenameBuffer);
runTest(filename);
}
} else {
printSeparators = (optind < argc - 1 || (dumpPixelsForCurrentTest && dumpTree));
for (int i = optind; i != argc; ++i) {
runTest(wxTheApp->argv[1]);
}
}
webFrame->Close();
delete eventHandler;
wxLog::SetActiveTarget(0);
delete logger;
fclose(logOutput);
// returning false shuts the app down
return false;
}