diff options
Diffstat (limited to 'khtml/test_regression.cpp')
-rw-r--r-- | khtml/test_regression.cpp | 1644 |
1 files changed, 0 insertions, 1644 deletions
diff --git a/khtml/test_regression.cpp b/khtml/test_regression.cpp deleted file mode 100644 index 172e63e4a..000000000 --- a/khtml/test_regression.cpp +++ /dev/null @@ -1,1644 +0,0 @@ -/** - * This file is part of the KDE project - * - * Copyright (C) 2001,2003 Peter Kelly (pmk@post.com) - * Copyright (C) 2003,2004 Stephan Kulow (coolo@kde.org) - * Copyright (C) 2004 Dirk Mueller ( mueller@kde.org ) - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public License - * along with this library; see the file COPYING.LIB. If not, write to - * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - */ - -#include <stdlib.h> -#include <sys/time.h> -#include <sys/resource.h> -#include <sys/types.h> -#include <unistd.h> -#include <pwd.h> -#include <signal.h> - -#include <kapplication.h> -#include <kstandarddirs.h> -#include <tqimage.h> -#include <tqfile.h> -#include "test_regression.h" -#include <unistd.h> -#include <stdio.h> - -#include "css/cssstyleselector.h" -#include <dom_string.h> -#include "rendering/render_style.h" -#include "rendering/render_layer.h" -#include "khtmldefaults.h" - -//We don't use the default fonts, though, but traditional testregression ones -#undef HTML_DEFAULT_VIEW_FONT -#undef HTML_DEFAULT_VIEW_FIXED_FONT -#undef HTML_DEFAULT_VIEW_SERIF_FONT -#undef HTML_DEFAULT_VIEW_SANSSERIF_FONT -#undef HTML_DEFAULT_VIEW_CURSIVE_FONT -#undef HTML_DEFAULT_VIEW_FANTASY_FONT -#define HTML_DEFAULT_VIEW_FONT "helvetica" -#define HTML_DEFAULT_VIEW_FIXED_FONT "courier" -#define HTML_DEFAULT_VIEW_SERIF_FONT "times" -#define HTML_DEFAULT_VIEW_SANSSERIF_FONT "helvetica" -#define HTML_DEFAULT_VIEW_CURSIVE_FONT "helvetica" -#define HTML_DEFAULT_VIEW_FANTASY_FONT "helvetica" - - -#include <kaction.h> -#include <kcmdlineargs.h> -#include "khtml_factory.h" -#include <kio/job.h> -#include <kmainwindow.h> -#include <ksimpleconfig.h> -#include <kglobalsettings.h> - -#include <tqcolor.h> -#include <tqcursor.h> -#include <tqdir.h> -#include <tqobject.h> -#include <tqpushbutton.h> -#include <tqscrollview.h> -#include <tqstring.h> -#include <tqtextstream.h> -#include <tqvaluelist.h> -#include <tqwidget.h> -#include <tqfileinfo.h> -#include <tqtimer.h> -#include <kstatusbar.h> -#include <tqfileinfo.h> - -#include "misc/decoder.h" -#include "dom/dom2_range.h" -#include "dom/dom_exception.h" -#include "dom/html_document.h" -#include "html/htmltokenizer.h" -#include "khtml_part.h" -#include "khtmlpart_p.h" -#include <kparts/browserextension.h> - -#include "khtmlview.h" -#include "rendering/render_replaced.h" -#include "xml/dom_docimpl.h" -#include "html/html_baseimpl.h" -#include "dom/dom_doc.h" -#include "misc/loader.h" -#include "ecma/kjs_binding.h" -#include "ecma/kjs_dom.h" -#include "ecma/kjs_window.h" -#include "ecma/kjs_binding.h" -#include "ecma/kjs_proxy.h" - -using namespace khtml; -using namespace DOM; -using namespace KJS; - -static bool visual = false; -static pid_t xvfb; - -// ------------------------------------------------------------------------- - -PartMonitor *PartMonitor::sm_highestMonitor = NULL; - -PartMonitor::PartMonitor(KHTMLPart *_part) -{ - m_part = _part; - m_completed = false; - connect(m_part,TQT_SIGNAL(completed()),this,TQT_SLOT(partCompleted())); - m_timer_waits = 200; - m_timeout_timer = new TQTimer(this); -} - -PartMonitor::~PartMonitor() -{ - if (this == sm_highestMonitor) - sm_highestMonitor = 0; -} - - -void PartMonitor::waitForCompletion() -{ - if (!m_completed) { - - if (sm_highestMonitor) - return; - - sm_highestMonitor = this; - - kapp->enter_loop(); - - //connect(m_timeout_timer, TQT_SIGNAL(timeout()), this, TQT_SLOT( timeout() ) ); - //m_timeout_timer->stop(); - //m_timeout_timer->start( visual ? 100 : 2, true ); - } - - TQTimer::singleShot( 0, this, TQT_SLOT( finishTimers() ) ); - kapp->enter_loop(); -} - -void PartMonitor::timeout() -{ - kapp->exit_loop(); -} - -void PartMonitor::finishTimers() -{ - KJS::Window *w = KJS::Window::retrieveWindow( m_part ); - --m_timer_waits; - if ( m_timer_waits && (w && w->winq->hasTimers()) || m_part->inProgress()) { - // wait a bit - TQTimer::singleShot( 10, this, TQT_SLOT(finishTimers() ) ); - return; - } - kapp->exit_loop(); -} - -void PartMonitor::partCompleted() -{ - m_completed = true; - RenderWidget::flushWidgetResizes(); - m_timeout_timer->stop(); - connect(m_timeout_timer, TQT_SIGNAL(timeout()),this, TQT_SLOT( timeout() ) ); - m_timeout_timer->start( visual ? 100 : 2, true ); - disconnect(m_part,TQT_SIGNAL(completed()),this,TQT_SLOT(partCompleted())); -} - -static void signal_handler( int ) -{ - printf( "timeout\n" ); - abort(); -} -// ------------------------------------------------------------------------- - -RegTestObject::RegTestObject(ExecState *exec, RegressionTest *_regTest) -{ - m_regTest = _regTest; - putDirect("print",new RegTestFunction(exec,m_regTest,RegTestFunction::Print,1), DontEnum); - putDirect("reportResult",new RegTestFunction(exec,m_regTest,RegTestFunction::ReportResult,3), DontEnum); - putDirect("checkOutput",new RegTestFunction(exec,m_regTest,RegTestFunction::CheckOutput,1), DontEnum); - // add "quit" for compatibility with the mozilla js shell - putDirect("quit", new RegTestFunction(exec,m_regTest,RegTestFunction::Quit,1), DontEnum ); -} - -RegTestFunction::RegTestFunction(ExecState* /*exec*/, RegressionTest *_regTest, int _id, int length) -{ - m_regTest = _regTest; - id = _id; - putDirect("length",length); -} - -bool RegTestFunction::implementsCall() const -{ - return true; -} - -Value RegTestFunction::call(ExecState *exec, Object &/*thisObj*/, const List &args) -{ - Value result = Undefined(); - if ( m_regTest->ignore_errors ) - return result; - - switch (id) { - case Print: { - UString str = args[0].toString(exec); - if ( str.qstring().lower().find( "failed!" ) >= 0 ) - m_regTest->saw_failure = true; - TQString res = str.qstring().replace('\007', ""); - m_regTest->m_currentOutput += res + "\n"; - break; - } - case ReportResult: { - bool passed = args[0].toBoolean(exec); - TQString description = args[1].toString(exec).qstring(); - if (args[1].isA(UndefinedType) || args[1].isA(NullType)) - description = TQString::null; - m_regTest->reportResult(passed,description); - if ( !passed ) - m_regTest->saw_failure = true; - break; - } - case CheckOutput: { - DOM::DocumentImpl* docimpl = static_cast<DOM::DocumentImpl*>( m_regTest->m_part->document().handle() ); - if ( docimpl && docimpl->view() && docimpl->renderer() ) - { - docimpl->updateRendering(); - docimpl->view()->layout(); - } - TQString filename = args[0].toString(exec).qstring(); - filename = RegressionTest::curr->m_currentCategory+"/"+filename; - int failures = RegressionTest::NoFailure; - if ( m_regTest->m_genOutput ) { - if ( !m_regTest->reportResult( m_regTest->checkOutput(filename+"-dom"), - "Script-generated " + filename + "-dom") ) - failures |= RegressionTest::DomFailure; - if ( !m_regTest->reportResult( m_regTest->checkOutput(filename+"-render"), - "Script-generated " + filename + "-render") ) - failures |= RegressionTest::RenderFailure; - } else { - // compare with output file - if ( !m_regTest->reportResult( m_regTest->checkOutput(filename+"-dom"), "DOM") ) - failures |= RegressionTest::DomFailure; - if ( !m_regTest->reportResult( m_regTest->checkOutput(filename+"-render"), "RENDER") ) - failures |= RegressionTest::RenderFailure; - } - RegressionTest::curr->doFailureReport( filename, failures ); - break; - } - case Quit: - m_regTest->reportResult(true, - "Called quit" ); - if ( !m_regTest->saw_failure ) - m_regTest->ignore_errors = true; - break; - } - - return result; -} - -// ------------------------------------------------------------------------- - -KHTMLPartObject::KHTMLPartObject(ExecState *exec, KHTMLPart *_part) -{ - m_part = _part; - putDirect("openPage", new KHTMLPartFunction(exec,m_part,KHTMLPartFunction::OpenPage,1), DontEnum); - putDirect("openPageAsUrl", new KHTMLPartFunction(exec,m_part,KHTMLPartFunction::OpenPageAsUrl,1), DontEnum); - putDirect("begin", new KHTMLPartFunction(exec,m_part,KHTMLPartFunction::Begin,1), DontEnum); - putDirect("write", new KHTMLPartFunction(exec,m_part,KHTMLPartFunction::Write,1), DontEnum); - putDirect("end", new KHTMLPartFunction(exec,m_part,KHTMLPartFunction::End,0), DontEnum); - putDirect("executeScript", new KHTMLPartFunction(exec,m_part,KHTMLPartFunction::ExecuteScript,0), DontEnum); - putDirect("processEvents", new KHTMLPartFunction(exec,m_part,KHTMLPartFunction::ProcessEvents,0), DontEnum); -} - -Value KHTMLPartObject::get(ExecState *exec, const Identifier &propertyName) const -{ - if (propertyName == "document") - return getDOMNode(exec,m_part->document()); - else if (propertyName == "window") - return Object(KJS::Window::retrieveWindow(m_part)); - else - return ObjectImp::get(exec,propertyName); -} - -KHTMLPartFunction::KHTMLPartFunction(ExecState */*exec*/, KHTMLPart *_part, int _id, int length) -{ - m_part = _part; - id = _id; - putDirect("length",length); -} - -bool KHTMLPartFunction::implementsCall() const -{ - return true; -} - -Value KHTMLPartFunction::call(ExecState *exec, Object &/*thisObj*/, const List &args) -{ - Value result = Undefined(); - - switch (id) { - case OpenPage: { - if (args[0].type() == NullType || args[0].type() == NullType) { - exec->setException(Error::create(exec, GeneralError,"No filename specified")); - return Undefined(); - } - - TQString filename = args[0].toString(exec).qstring(); - TQString fullFilename = TQFileInfo(RegressionTest::curr->m_currentBase+"/"+filename).absFilePath(); - KURL url; - url.setProtocol("file"); - url.setPath(fullFilename); - PartMonitor pm(m_part); - m_part->openURL(url); - pm.waitForCompletion(); - kapp->processEvents(60000); - break; - } - case OpenPageAsUrl: { - if (args[0].type() == NullType || args[0].type() == UndefinedType) { - exec->setException(Error::create(exec, GeneralError,"No filename specified")); - return Undefined(); - } - if (args[1].type() == NullType || args[1].type() == UndefinedType) { - exec->setException(Error::create(exec, GeneralError,"No url specified")); - return Undefined(); - } - - TQString filename = args[0].toString(exec).qstring(); - TQString url = args[1].toString(exec).qstring(); - TQFile file(RegressionTest::curr->m_currentBase+"/"+filename); - if (!file.open(IO_ReadOnly)) { - exec->setException(Error::create(exec, GeneralError, - TQString("Error reading " + filename).latin1())); - } - else { - TQByteArray fileData; - TQDataStream stream(fileData,IO_WriteOnly); - char buf[1024]; - int bytesread; - while (!file.atEnd()) { - bytesread = file.tqreadBlock(buf,1024); - stream.writeRawBytes(buf,bytesread); - } - file.close(); - TQString contents(fileData); - PartMonitor pm(m_part); - m_part->begin(KURL( url )); - m_part->write(contents); - m_part->end(); - pm.waitForCompletion(); - } - kapp->processEvents(60000); - break; - } - case Begin: { - TQString url = args[0].toString(exec).qstring(); - m_part->begin(KURL( url )); - break; - } - case Write: { - TQString str = args[0].toString(exec).qstring(); - m_part->write(str); - break; - } - case End: { - m_part->end(); - kapp->processEvents(60000); - break; - } - case ExecuteScript: { - TQString code = args[0].toString(exec).qstring(); - Completion comp; - KJSProxy *proxy = m_part->jScript(); - proxy->evaluate("",0,code,0,&comp); - if (comp.complType() == Throw) - exec->setException(comp.value()); - kapp->processEvents(60000); - break; - } - case ProcessEvents: { - kapp->processEvents(60000); - break; - } - } - - return result; -} - -// ------------------------------------------------------------------------- - -static KCmdLineOptions options[] = -{ - { "b", 0, 0 }, - { "base <base_dir>", "Directory containing tests, basedir and output directories.", 0}, - { "d", 0, 0 }, - { "debug", "Do not supress debug output", 0}, - { "g", 0, 0 } , - { "genoutput", "Regenerate baseline (instead of checking)", 0 } , - { "s", 0, 0 } , - { "show", "Show the window while running tests", 0 } , - { "t", 0, 0 } , - { "test <filename>", "Only run a single test. Multiple options allowed.", 0 } , - { "js", "Only run .js tests", 0 }, - { "html", "Only run .html tests", 0}, - { "noxvfb", "Do not use Xvfb", 0}, - { "o", 0, 0 }, - { "output <directory>", "Put output in <directory> instead of <base_dir>/output", 0 } , - { "+[base_dir]", "Directory containing tests,basedir and output directories. Only regarded if -b is not specified.", 0 } , - { "+[testcases]", "Relative path to testcase, or directory of testcases to be run (equivalent to -t).", 0 } , - KCmdLineLastOption -}; - -static bool existsDir(TQCString dir) -{ - struct stat st; - - return (!stat(dir.data(), &st) && S_ISDIR(st.st_mode)); -} - -int main(int argc, char *argv[]) -{ - // forget about any settings - passwd* pw = getpwuid( getuid() ); - if (!pw) { - fprintf(stderr, "dang, I don't even know who I am.\n"); - exit(1); - } - - TQString kh("/var/tmp/%1_non_existant"); - kh = kh.arg( pw->pw_name ); - setenv( "TDEHOME", kh.latin1(), 1 ); - setenv( "LC_ALL", "C", 1 ); - setenv( "LANG", "C", 1 ); - - signal( SIGALRM, signal_handler ); - - // workaround various Qt crashes by always enforcing a TrueColor visual - TQApplication::setColorSpec( TQApplication::ManyColor ); - - TDECmdLineArgs::init(argc, argv, "testregression", "TestRegression", - "Regression tester for khtml", "1.0"); - TDECmdLineArgs::addCmdLineOptions(options); - - TDECmdLineArgs *args = TDECmdLineArgs::parsedArgs( ); - - TQCString baseDir = args->getOption("base"); - - if ( args->count() < 1 && baseDir.isEmpty() ) { - TDECmdLineArgs::usage(); - ::exit( 1 ); - } - - int testcase_index = 0; - if (baseDir.isEmpty()) baseDir = args->arg(testcase_index++); - - TQFileInfo bdInfo(baseDir); - baseDir = TQFile::encodeName(bdInfo.absFilePath()); - - const char *subdirs[] = {"tests", "baseline", "output", "resources"}; - for ( int i = 0; i < 3; i++ ) { - TQFileInfo sourceDir(TQFile::encodeName( baseDir ) + "/" + subdirs[i]); - if ( !sourceDir.exists() || !sourceDir.isDir() ) { - fprintf(stderr,"ERROR: Source directory \"%s/%s\": no such directory.\n", (const char *)baseDir, subdirs[i]); - exit(1); - } - } - - if (args->isSet("xvfb")) - { - TQString xvfbPath = KStandardDirs::findExe("Xvfb"); - if ( xvfbPath.isEmpty() ) { - fprintf( stderr, "[test_regression] ERROR: We need Xvfb to be installed for reliable results\n" ); - exit( 1 ); - } - - TQCString xvfbPath8 = TQFile::encodeName(xvfbPath); - TQStringList fpaths; - fpaths.append(baseDir+"/resources"); - - const char* const fontdirs[] = { "75dpi", "misc", "Type1" }; - const char* const fontpaths[] = {"/usr/share/fonts/", "/usr/X11/lib/X11/fonts/", - "/usr/lib/X11/fonts/", "/usr/share/fonts/X11/" }; - - for (size_t fp=0; fp < sizeof(fontpaths)/sizeof(*fontpaths); ++fp) - for (size_t fd=0; fd < sizeof(fontdirs)/sizeof(*fontdirs); ++fd) - if (existsDir(TQCString(fontpaths[fp])+TQCString(fontdirs[fd]))) - if (strcmp(fontdirs[fd] , "Type1")) - fpaths.append(TQCString(fontpaths[fp])+TQCString(fontdirs[fd])+":unscaled"); - else - fpaths.append(TQCString(fontpaths[fp])+TQCString(fontdirs[fd])); - - xvfb = fork(); - if ( !xvfb ) { - TQCString buffer = fpaths.join(",").latin1(); - execl( xvfbPath8.data(), xvfbPath8.data(), "-once", "-dpi", "100", "-screen", "0", - "1024x768x16", "-ac", "-fp", buffer.data(), ":47", (char*)NULL ); - } - - setenv( "DISPLAY", ":47", 1 ); - } - - TDEApplication a; - a.disableAutoDcopRegistration(); - a.setStyle( "windows" ); - KSimpleConfig sc1( "cryptodefaults" ); - sc1.setGroup( "Warnings" ); - sc1.writeEntry( "OnUnencrypted", false ); - a.config()->setGroup( "Notification Messages" ); - a.config()->writeEntry( "kjscupguard_alarmhandler", true ); - a.config()->setGroup("HTML Settings"); - a.config()->writeEntry("ReportJSErrors", false); - TDEConfig cfg( "khtmlrc" ); - cfg.setGroup("HTML Settings"); - cfg.writeEntry( "StandardFont", HTML_DEFAULT_VIEW_SANSSERIF_FONT ); - cfg.writeEntry( "FixedFont", HTML_DEFAULT_VIEW_FIXED_FONT ); - cfg.writeEntry( "SerifFont", HTML_DEFAULT_VIEW_SERIF_FONT ); - cfg.writeEntry( "SansSerifFont", HTML_DEFAULT_VIEW_SANSSERIF_FONT ); - cfg.writeEntry( "CursiveFont", HTML_DEFAULT_VIEW_CURSIVE_FONT ); - cfg.writeEntry( "FantasyFont", HTML_DEFAULT_VIEW_FANTASY_FONT ); - cfg.writeEntry( "MinimumFontSize", HTML_DEFAULT_MIN_FONT_SIZE ); - cfg.writeEntry( "MediumFontSize", 10 ); - cfg.writeEntry( "Fonts", TQStringList() ); - cfg.writeEntry( "DefaultEncoding", "" ); - cfg.setGroup("Java/JavaScript Settings"); - cfg.writeEntry( "WindowOpenPolicy", KHTMLSettings::KJSWindowOpenAllow); - - cfg.sync(); - - int rv = 1; - - if ( !args->isSet( "debug" ) ) { - KSimpleConfig dc( "kdebugrc" ); - static int areas[] = { 1000, 6000, 6005, 6010, 6020, 6030, - 6031, 6035, 6036, 6040, 6041, 6045, - 6050, 6060, 6061, 7000, 7006, 170, - 171, 7101, 7002, 7019, 7027, 7014, - 7011, 6070, 6080, 6090, 0}; - for ( int i = 0; areas[i]; ++i ) { - dc.setGroup( TQString::number( areas[i] ) ); - dc.writeEntry( "InfoOutput", 4 ); - } - dc.sync(); - - kdClearDebugConfig(); - } - - // create widgets - KHTMLFactory *fac = new KHTMLFactory(); - KMainWindow *toplevel = new KMainWindow(); - KHTMLPart *part = new KHTMLPart( toplevel, 0, toplevel, 0, KHTMLPart::BrowserViewGUI ); - - toplevel->setCentralWidget( part->widget() ); - part->setJScriptEnabled(true); - - part->executeScript(DOM::Node(), ""); // force the part to create an interpreter -// part->setJavaEnabled(true); - - if (args->isSet("show")) - visual = true; - - a.setTopWidget(part->widget()); - a.setMainWidget( toplevel ); - if ( visual ) - toplevel->show(); - - // we're not interested - toplevel->statusBar()->hide(); - - if (!getenv("TDE_DEBUG")) { - // set ulimits - rlimit vmem_limit = { 256*1024*1024, RLIM_INFINITY }; // 256Mb Memory should suffice - setrlimit(RLIMIT_AS, &vmem_limit); - rlimit stack_limit = { 8*1024*1024, RLIM_INFINITY }; // 8Mb Memory should suffice - setrlimit(RLIMIT_STACK, &stack_limit); - } - - // run the tests - RegressionTest *regressionTest = new RegressionTest(part, - baseDir, - args->getOption("output"), - args->isSet("genoutput"), - !args->isSet( "html" ), - !args->isSet( "js" )); - TQObject::connect(part->browserExtension(), TQT_SIGNAL(openURLRequest(const KURL &, const KParts::URLArgs &)), - regressionTest, TQT_SLOT(slotOpenURL(const KURL&, const KParts::URLArgs &))); - TQObject::connect(part->browserExtension(), TQT_SIGNAL(resizeTopLevelWidget( int, int )), - regressionTest, TQT_SLOT(resizeTopLevelWidget( int, int ))); - - bool result = false; - QCStringList tests = args->getOptionList("test"); - // merge testcases specified on command line - for (; testcase_index < args->count(); testcase_index++) - tests << args->arg(testcase_index); - if (tests.count() > 0) - for (TQValueListConstIterator<TQCString> it = tests.begin(); it != tests.end(); ++it) { - result = regressionTest->runTests(*it,true); - if (!result) break; - } - else - result = regressionTest->runTests(); - - if (result) { - if (args->isSet("genoutput")) { - printf("\nOutput generation completed.\n"); - } - else { - printf("\nTests completed.\n"); - printf("Total: %d\n", - regressionTest->m_passes_work+ - regressionTest->m_passes_fail+ - regressionTest->m_failures_work+ - regressionTest->m_failures_fail+ - regressionTest->m_errors); - printf("Passes: %d",regressionTest->m_passes_work); - if ( regressionTest->m_passes_fail ) - printf( " (%d unexpected passes)\n", regressionTest->m_passes_fail ); - else - printf( "\n" ); - printf("Failures: %d",regressionTest->m_failures_work); - if ( regressionTest->m_failures_fail ) - printf( " (%d expected failures)\n", regressionTest->m_failures_fail ); - else - printf( "\n" ); - if ( regressionTest->m_errors ) - printf("Errors: %d\n",regressionTest->m_errors); - - TQFile list( regressionTest->m_outputDir + "/links.html" ); - list.open( IO_WriteOnly|IO_Append ); - TQString link, cl; - link = TQString( "<hr>%1 failures. (%2 expected failures)" ) - .arg(regressionTest->m_failures_work ) - .arg( regressionTest->m_failures_fail ); - list.tqwriteBlock( link.latin1(), link.length() ); - list.close(); - } - } - - // Only return a 0 exit code if all tests were successful - if (regressionTest->m_failures_work == 0 && regressionTest->m_errors == 0) - rv = 0; - - // cleanup - delete regressionTest; - delete part; - delete toplevel; - delete fac; - - khtml::Cache::clear(); - khtml::CSSStyleSelector::clear(); - khtml::RenderStyle::cleanup(); - - kill( xvfb, SIGINT ); - - return rv; -} - -// ------------------------------------------------------------------------- - -RegressionTest *RegressionTest::curr = 0; - -RegressionTest::RegressionTest(KHTMLPart *part, const TQString &baseDir, const TQString &outputDir, - bool _genOutput, bool runJS, bool runHTML) - : TQObject(part) -{ - m_part = part; - m_baseDir = baseDir; - m_baseDir = m_baseDir.replace( "//", "/" ); - if ( m_baseDir.endsWith( "/" ) ) - m_baseDir = m_baseDir.left( m_baseDir.length() - 1 ); - if (outputDir.isEmpty()) - m_outputDir = m_baseDir + "/output"; - else { - createMissingDirs(outputDir + "/"); - m_outputDir = outputDir; - } - m_genOutput = _genOutput; - m_runJS = runJS; - m_runHTML = runHTML; - m_passes_work = m_passes_fail = 0; - m_failures_work = m_failures_fail = 0; - m_errors = 0; - - ::unlink( TQFile::encodeName( m_outputDir + "/links.html" ) ); - TQFile f( m_outputDir + "/empty.html" ); - TQString s; - f.open( IO_WriteOnly | IO_Truncate ); - s = "<html><body>Follow the white rabbit"; - f.tqwriteBlock( s.latin1(), s.length() ); - f.close(); - f.setName( m_outputDir + "/index.html" ); - f.open( IO_WriteOnly | IO_Truncate ); - s = "<html><frameset cols=150,*><frame src=links.html><frame name=content src=empty.html>"; - f.tqwriteBlock( s.latin1(), s.length() ); - f.close(); - - m_paintBuffer = 0; - - curr = this; -} - -#include <tqobjectlist.h> - -static TQStringList readListFile( const TQString &filename ) -{ - // Read ignore file for this directory - TQString ignoreFilename = filename; - TQFileInfo ignoreInfo(ignoreFilename); - TQStringList ignoreFiles; - if (ignoreInfo.exists()) { - TQFile ignoreFile(ignoreFilename); - if (!ignoreFile.open(IO_ReadOnly)) { - fprintf(stderr,"Can't open %s\n",ignoreFilename.latin1()); - exit(1); - } - TQTextStream ignoreStream(&ignoreFile); - TQString line; - while (!(line = ignoreStream.readLine()).isNull()) - ignoreFiles.append(line); - ignoreFile.close(); - } - return ignoreFiles; -} - -RegressionTest::~RegressionTest() -{ - delete m_paintBuffer; -} - -bool RegressionTest::runTests(TQString relPath, bool mustExist, int known_failure) -{ - m_currentOutput = TQString::null; - - if (!TQFile(m_baseDir + "/tests/"+relPath).exists()) { - fprintf(stderr,"%s: No such file or directory\n",relPath.latin1()); - return false; - } - - TQString fullPath = m_baseDir + "/tests/"+relPath; - TQFileInfo info(fullPath); - - if (!info.exists() && mustExist) { - fprintf(stderr,"%s: No such file or directory\n",relPath.latin1()); - return false; - } - - if (!info.isReadable() && mustExist) { - fprintf(stderr,"%s: Access denied\n",relPath.latin1()); - return false; - } - - if (info.isDir()) { - TQStringList ignoreFiles = readListFile( m_baseDir + "/tests/"+relPath+"/ignore" ); - TQStringList failureFiles = readListFile( m_baseDir + "/tests/"+relPath+"/KNOWN_FAILURES" ); - - // Run each test in this directory, recusively - TQDir sourceDir(m_baseDir + "/tests/"+relPath); - for (uint fileno = 0; fileno < sourceDir.count(); fileno++) { - TQString filename = sourceDir[fileno]; - TQString relFilename = relPath.isEmpty() ? filename : relPath+"/"+filename; - - if (filename == "." || filename == ".." || ignoreFiles.contains(filename) ) - continue; - int failure_type = NoFailure; - if ( failureFiles.contains( filename ) ) - failure_type |= AllFailure; - if ( failureFiles.contains ( filename + "-render" ) ) - failure_type |= RenderFailure; - if ( failureFiles.contains ( filename + "-dump.png" ) ) - failure_type |= PaintFailure; - if ( failureFiles.contains ( filename + "-dom" ) ) - failure_type |= DomFailure; - runTests(relFilename, false, failure_type ); - } - } - else if (info.isFile()) { - - alarm( 400 ); - - khtml::Cache::init(); - - TQString relativeDir = TQFileInfo(relPath).dirPath(); - TQString filename = info.fileName(); - m_currentBase = m_baseDir + "/tests/"+relativeDir; - m_currentCategory = relativeDir; - m_currentTest = filename; - m_known_failures = known_failure; - if ( filename.endsWith(".html") || filename.endsWith( ".htm" ) || filename.endsWith( ".xhtml" ) || filename.endsWith( ".xml" ) ) { - if ( relPath.startsWith( "domts/" ) && !m_runJS ) - return true; - if ( relPath.startsWith( "ecma/" ) && !m_runJS ) - return true; - if ( m_runHTML ) - testStaticFile(relPath); - } - else if (filename.endsWith(".js")) { - if ( m_runJS ) - testJSFile(relPath); - } - else if (mustExist) { - fprintf(stderr,"%s: Not a valid test file (must be .htm(l) or .js)\n",relPath.latin1()); - return false; - } - } else if (mustExist) { - fprintf(stderr,"%s: Not a regular file\n",relPath.latin1()); - return false; - } - - return true; -} - -void RegressionTest::getPartDOMOutput( TQTextStream &outputStream, KHTMLPart* part, uint indent ) -{ - Node node = part->document(); - while (!node.isNull()) { - // process - - for (uint i = 0; i < indent; i++) - outputStream << " "; - outputStream << node.nodeName().string(); - - switch (node.nodeType()) { - case Node::ELEMENT_NODE: { - // Sort strings to ensure consistent output - TQStringList attrNames; - NamedNodeMap attrs = node.attributes(); - for (uint a = 0; a < attrs.length(); a++) - attrNames.append(attrs.item(a).nodeName().string()); - attrNames.sort(); - - TQStringList::iterator it; - Element elem(node); - for (it = attrNames.begin(); it != attrNames.end(); ++it) { - TQString name = *it; - TQString value = elem.getAttribute(*it).string(); - outputStream << " " << name << "=\"" << value << "\""; - } - if ( node.handle()->id() == ID_FRAME ) { - outputStream << endl; - TQString frameName = static_cast<DOM::HTMLFrameElementImpl *>( node.handle() )->name.string(); - KHTMLPart* frame = part->findFrame( frameName ); - Q_ASSERT( frame ); - if ( frame ) - getPartDOMOutput( outputStream, frame, indent ); - } - break; - } - case Node::ATTRIBUTE_NODE: - // Should not be present in tree - assert(false); - break; - case Node::TEXT_NODE: - outputStream << " \"" << Text(node).data().string() << "\""; - break; - case Node::CDATA_SECTION_NODE: - outputStream << " \"" << CDATASection(node).data().string() << "\""; - break; - case Node::ENTITY_REFERENCE_NODE: - break; - case Node::ENTITY_NODE: - break; - case Node::PROCESSING_INSTRUCTION_NODE: - break; - case Node::COMMENT_NODE: - outputStream << " \"" << Comment(node).data().string() << "\""; - break; - case Node::DOCUMENT_NODE: - break; - case Node::DOCUMENT_TYPE_NODE: - break; - case Node::DOCUMENT_FRAGMENT_NODE: - // Should not be present in tree - assert(false); - break; - case Node::NOTATION_NODE: - break; - default: - assert(false); - break; - } - - outputStream << endl; - - if (!node.firstChild().isNull()) { - node = node.firstChild(); - indent++; - } - else if (!node.nextSibling().isNull()) { - node = node.nextSibling(); - } - else { - while (!node.isNull() && node.nextSibling().isNull()) { - node = node.parentNode(); - indent--; - } - if (!node.isNull()) - node = node.nextSibling(); - } - } -} - -void RegressionTest::dumpRenderTree( TQTextStream &outputStream, KHTMLPart* part ) -{ - DOM::DocumentImpl* doc = static_cast<DocumentImpl*>( part->document().handle() ); - if ( !doc || !doc->renderer() ) - return; - doc->renderer()->layer()->dump( outputStream ); - - // Dump frames if any - // Get list of names instead of frames() to sort the list alphabetically - TQStringList names = part->frameNames(); - names.sort(); - for ( TQStringList::iterator it = names.begin(); it != names.end(); ++it ) { - outputStream << "FRAME: " << (*it) << "\n"; - KHTMLPart* frame = part->findFrame( (*it) ); - Q_ASSERT( frame ); - if ( frame ) - dumpRenderTree( outputStream, frame ); - } -} - -TQString RegressionTest::getPartOutput( OutputType type) -{ - // dump out the contents of the rendering & DOM trees - TQString dump; - TQTextStream outputStream(dump,IO_WriteOnly); - - if ( type == RenderTree ) { - dumpRenderTree( outputStream, m_part ); - } else { - assert( type == DOMTree ); - getPartDOMOutput( outputStream, m_part, 0 ); - } - - dump.replace( m_baseDir + "/tests", TQString::fromLatin1( "REGRESSION_SRCDIR" ) ); - return dump; -} - -TQImage RegressionTest::renderToImage() -{ - int ew = m_part->view()->contentsWidth(); - int eh = m_part->view()->contentsHeight(); - - if (ew * eh > 4000 * 4000) // don't DoS us - return TQImage(); - - TQImage img( ew, eh, 32 ); - img.fill( 0xff0000 ); - if (!m_paintBuffer ) - m_paintBuffer = new TQPixmap( 512, 128, -1, TQPixmap::MemoryOptim ); - - for ( int py = 0; py < eh; py += 128 ) { - for ( int px = 0; px < ew; px += 512 ) { - TQPainter* tp = new TQPainter; - tp->begin( m_paintBuffer ); - tp->translate( -px, -py ); - tp->fillRect(px, py, 512, 128, Qt::magenta); - m_part->document().handle()->renderer()->layer()->paint( tp, TQRect( px, py, 512, 128 ) ); - tp->end(); - delete tp; - - // now fill the chunk into our image - TQImage chunk = m_paintBuffer->convertToImage(); - assert( chunk.depth() == 32 ); - for ( int y = 0; y < 128 && py + y < eh; ++y ) - memcpy( img.scanLine( py+y ) + px*4, chunk.scanLine( y ), kMin( 512, ew-px )*4 ); - } - } - - assert( img.depth() == 32 ); - return img; -} - -bool RegressionTest::imageEqual( const TQImage &lhsi, const TQImage &rhsi ) -{ - if ( lhsi.width() != rhsi.width() || lhsi.height() != rhsi.height() ) { - kdDebug() << "dimensions different " << lhsi.size() << " " << rhsi.size() << endl; - return false; - } - int w = lhsi.width(); - int h = lhsi.height(); - int bytes = lhsi.bytesPerLine(); - - for ( int y = 0; y < h; ++y ) - { - QRgb* ls = ( QRgb* ) lhsi.scanLine( y ); - QRgb* rs = ( QRgb* ) rhsi.scanLine( y ); - if ( memcmp( ls, rs, bytes ) ) { - for ( int x = 0; x < w; ++x ) { - QRgb l = ls[x]; - QRgb r = rs[x]; - if ( ( abs( tqRed( l ) - tqRed(r ) ) < 20 ) && - ( abs( tqGreen( l ) - tqGreen(r ) ) < 20 ) && - ( abs( tqBlue( l ) - tqBlue(r ) ) < 20 ) ) - continue; - kdDebug() << "pixel (" << x << ", " << y << ") is different " << TQColor( lhsi.pixel ( x, y ) ) << " " << TQColor( rhsi.pixel ( x, y ) ) << endl; - return false; - } - } - } - - return true; -} - -void RegressionTest::createLink( const TQString& test, int failures ) -{ - createMissingDirs( m_outputDir + "/" + test + "-compare.html" ); - - TQFile list( m_outputDir + "/links.html" ); - list.open( IO_WriteOnly|IO_Append ); - TQString link; - link = TQString( "<a href=\"%1\" target=\"content\" title=\"%2\">" ) - .arg( test + "-compare.html" ) - .arg( test ); - link += m_currentTest; - link += "</a> ["; - if ( failures & DomFailure ) - link += "D"; - if ( failures & RenderFailure ) - link += "R"; - if ( failures & PaintFailure ) - link += "P"; - link += "]<br>\n"; - list.tqwriteBlock( link.latin1(), link.length() ); - list.close(); -} - -void RegressionTest::doJavascriptReport( const TQString &test ) -{ - TQFile compare( m_outputDir + "/" + test + "-compare.html" ); - if ( !compare.open( IO_WriteOnly|IO_Truncate ) ) - kdDebug() << "failed to open " << m_outputDir + "/" + test + "-compare.html" << endl; - TQString cl; - cl = TQString( "<html><head><title>%1</title>" ).arg( test ); - cl += "<body><tt>"; - TQString text = "\n" + m_currentOutput; - text.replace( '<', "<" ); - text.replace( '>', ">" ); - text.replace( TQRegExp( "\nFAILED" ), "\n<span style='color: red'>FAILED</span>" ); - text.replace( TQRegExp( "\nFAIL" ), "\n<span style='color: red'>FAIL</span>" ); - text.replace( TQRegExp( "\nPASSED" ), "\n<span style='color: green'>PASSED</span>" ); - text.replace( TQRegExp( "\nPASS" ), "\n<span style='color: green'>PASS</span>" ); - if ( text.at( 0 ) == '\n' ) - text = text.mid( 1, text.length() ); - text.replace( '\n', "<br>\n" ); - cl += text; - cl += "</tt></body></html>"; - compare.tqwriteBlock( cl.latin1(), cl.length() ); - compare.close(); -} - -/** returns the path in a way that is relatively reachable from base. - * @param base base directory (must not include trailing slash) - * @param path directory/file to be relatively reached by base - * @return path with all elements replaced by .. and concerning path elements - * to be relatively reachable from base. - */ -static TQString makeRelativePath(const TQString &base, const TQString &path) -{ - TQString absBase = TQFileInfo(base).absFilePath(); - TQString absPath = TQFileInfo(path).absFilePath(); -// kdDebug() << "absPath: \"" << absPath << "\"" << endl; -// kdDebug() << "absBase: \"" << absBase << "\"" << endl; - - // walk up to common ancestor directory - int pos = 0; - do { - pos++; - int newpos = absBase.find('/', pos); - if (newpos == -1) newpos = absBase.length(); - TQConstString cmpPathComp(absPath.unicode() + pos, newpos - pos); - TQConstString cmpBaseComp(absBase.unicode() + pos, newpos - pos); -// kdDebug() << "cmpPathComp: \"" << cmpPathComp.string() << "\"" << endl; -// kdDebug() << "cmpBaseComp: \"" << cmpBaseComp.string() << "\"" << endl; -// kdDebug() << "pos: " << pos << " newpos: " << newpos << endl; - if (cmpPathComp.string() != cmpBaseComp.string()) { pos--; break; } - pos = newpos; - } while (pos < (int)absBase.length() && pos < (int)absPath.length()); - int basepos = pos < (int)absBase.length() ? pos + 1 : pos; - int pathpos = pos < (int)absPath.length() ? pos + 1 : pos; - -// kdDebug() << "basepos " << basepos << " pathpos " << pathpos << endl; - - TQString rel; - { - TQConstString relBase(absBase.unicode() + basepos, absBase.length() - basepos); - TQConstString relPath(absPath.unicode() + pathpos, absPath.length() - pathpos); - // generate as many .. as there are path elements in relBase - if (relBase.string().length() > 0) { - for (int i = relBase.string().contains('/'); i > 0; --i) - rel += "../"; - rel += ".."; - if (relPath.string().length() > 0) rel += "/"; - } - rel += relPath.string(); - } - return rel; -} - -void RegressionTest::doFailureReport( const TQString& test, int failures ) -{ - if ( failures == NoFailure ) { - ::unlink( TQFile::encodeName( m_outputDir + "/" + test + "-compare.html" ) ); - return; - } - - createLink( test, failures ); - - if ( failures & JSFailure ) { - doJavascriptReport( test ); - return; // no support for both kind - } - - TQFile compare( m_outputDir + "/" + test + "-compare.html" ); - - TQString testFile = TQFileInfo(test).fileName(); - - TQString renderDiff; - TQString domDiff; - - TQString relOutputDir = makeRelativePath(m_baseDir, m_outputDir); - - // are blocking reads possible with TDEProcess? - char pwd[PATH_MAX]; - (void) getcwd( pwd, PATH_MAX ); - chdir( TQFile::encodeName( m_baseDir ) ); - - if ( failures & RenderFailure ) { - renderDiff += "<pre>"; - FILE *pipe = popen( TQString::fromLatin1( "diff -u baseline/%1-render %3/%2-render" ) - .arg ( test, test, relOutputDir ).latin1(), "r" ); - TQTextIStream *is = new TQTextIStream( pipe ); - for ( int line = 0; line < 100 && !is->eof(); ++line ) { - TQString line = is->readLine(); - line = line.replace( '<', "<" ); - line = line.replace( '>', ">" ); - renderDiff += line + "\n"; - } - delete is; - pclose( pipe ); - renderDiff += "</pre>"; - } - - if ( failures & DomFailure ) { - domDiff += "<pre>"; - FILE *pipe = popen( TQString::fromLatin1( "diff -u baseline/%1-dom %3/%2-dom" ) - .arg ( test, test, relOutputDir ).latin1(), "r" ); - TQTextIStream *is = new TQTextIStream( pipe ); - for ( int line = 0; line < 100 && !is->eof(); ++line ) { - TQString line = is->readLine(); - line = line.replace( '<', "<" ); - line = line.replace( '>', ">" ); - domDiff += line + "\n"; - } - delete is; - pclose( pipe ); - domDiff += "</pre>"; - } - - chdir( pwd ); - - // create a relative path so that it works via web as well. ugly - TQString relpath = makeRelativePath(m_outputDir + "/" - + TQFileInfo(test).dirPath(), m_baseDir); - - compare.open( IO_WriteOnly|IO_Truncate ); - TQString cl; - cl = TQString( "<html><head><title>%1</title>" ).arg( test ); - cl += TQString( "<script>\n" - "var pics = new Array();\n" - "pics[0]=new Image();\n" - "pics[0].src = '%1';\n" - "pics[1]=new Image();\n" - "pics[1].src = '%2';\n" - "var doflicker = 1;\n" - "var t = 1;\n" - "var lastb=0;\n" ) - .arg( relpath+"/baseline/"+test+"-dump.png" ) - .arg( testFile+"-dump.png" ); - cl += TQString( "function toggleVisible(visible) {\n" - " document.getElementById('render').style.visibility= visible == 'render' ? 'visible' : 'hidden';\n" - " document.getElementById('image').style.visibility= visible == 'image' ? 'visible' : 'hidden';\n" - " document.getElementById('dom').style.visibility= visible == 'dom' ? 'visible' : 'hidden';\n" - "}\n" - "function show() { document.getElementById('image').src = pics[t].src; " - "document.getElementById('image').style.borderColor = t && !doflicker ? 'red' : 'gray';\n" - "toggleVisible('image');\n" - "}" ); - cl += TQString ( "function runSlideShow(){\n" - " document.getElementById('image').src = pics[t].src;\n" - " if (doflicker)\n" - " t = 1 - t;\n" - " setTimeout('runSlideShow()', 200);\n" - "}\n" - "function m(b) { if (b == lastb) return; document.getElementById('b'+b).className='buttondown';\n" - " var e = document.getElementById('b'+lastb);\n" - " if(e) e.className='button';\n" - " lastb = b;\n" - "}\n" - "function showRender() { doflicker=0;toggleVisible('render')\n" - "}\n" - "function showDom() { doflicker=0;toggleVisible('dom')\n" - "}\n" - "</script>\n"); - - cl += TQString ("<style>\n" - ".buttondown { cursor: pointer; padding: 0px 20px; color: white; background-color: blue; border: inset blue 2px;}\n" - ".button { cursor: pointer; padding: 0px 20px; color: black; background-color: white; border: outset blue 2px;}\n" - ".diff { position: absolute; left: 10px; top: 100px; visibility: hidden; border: 1px black solid; background-color: white; color: black; /* width: 800; height: 600; overflow: scroll; */ }\n" - "</style>\n" ); - - if ( failures & PaintFailure ) - cl += TQString( "<body onload=\"m(1); show(); runSlideShow();\"" ); - else if ( failures & RenderFailure ) - cl += TQString( "<body onload=\"m(4); toggleVisible('render');\"" ); - else - cl += TQString( "<body onload=\"m(5); toggleVisible('dom');\"" ); - cl += TQString(" text=black bgcolor=gray>\n<h1>%3</h1>\n" ).arg( test ); - if ( failures & PaintFailure ) - cl += TQString ( "<span id='b1' class='buttondown' onclick=\"doflicker=1;show();m(1)\">FLICKER</span> \n" - "<span id='b2' class='button' onclick=\"doflicker=0;t=0;show();m(2)\">BASE</span> \n" - "<span id='b3' class='button' onclick=\"doflicker=0;t=1;show();m(3)\">OUT</span> \n" ); - if ( renderDiff.length() ) - cl += "<span id='b4' class='button' onclick='showRender();m(4)'>R-DIFF</span> \n"; - if ( domDiff.length() ) - cl += "<span id='b5' class='button' onclick='showDom();m(5);'>D-DIFF</span> \n"; - // The test file always exists - except for checkOutput called from *.js files - if ( TQFile::exists( m_baseDir + "/tests/"+ test ) ) - cl += TQString( "<a class=button href=\"%1\">HTML</a> " ) - .arg( relpath+"/tests/"+test ); - - cl += TQString( "<hr>" - "<img style='border: solid 5px gray' src=\"%1\" id='image'>" ) - .arg( relpath+"/baseline/"+test+"-dump.png" ); - - cl += "<div id='render' class='diff'>" + renderDiff + "</div>"; - cl += "<div id='dom' class='diff'>" + domDiff + "</div>"; - - cl += "</body></html>"; - compare.tqwriteBlock( cl.latin1(), cl.length() ); - compare.close(); -} - -void RegressionTest::testStaticFile(const TQString & filename) -{ - tqApp->mainWidget()->resize( 800, 600); // restore size - - // Set arguments - KParts::URLArgs args; - if (filename.endsWith(".html") || filename.endsWith(".htm")) args.serviceType = "text/html"; - else if (filename.endsWith(".xhtml")) args.serviceType = "application/xhtml+xml"; - else if (filename.endsWith(".xml")) args.serviceType = "text/xml"; - m_part->browserExtension()->setURLArgs(args); - // load page - KURL url; - url.setProtocol("file"); - url.setPath(TQFileInfo(m_baseDir + "/tests/"+filename).absFilePath()); - PartMonitor pm(m_part); - m_part->openURL(url); - pm.waitForCompletion(); - m_part->closeURL(); - - if ( filename.startsWith( "domts/" ) ) { - TQString functionname; - - KJS::Completion comp = m_part->jScriptInterpreter()->evaluate("exposeTestFunctionNames();"); - /* - * Error handling - */ - KJS::ExecState *exec = m_part->jScriptInterpreter()->globalExec(); - if ( comp.complType() == ReturnValue || comp.complType() == Normal ) - { - if (comp.value().isValid() && comp.value().isA(ObjectType) && - (Object::dynamicCast(comp.value()).className() == "Array" ) ) - { - Object argArrayObj = Object::dynamicCast(comp.value()); - unsigned int length = argArrayObj. - get(exec,lengthPropertyName). - toUInt32(exec); - if ( length == 1 ) - functionname = argArrayObj.get(exec, 0).toString(exec).qstring(); - } - } - if ( functionname.isNull() ) { - kdDebug() << "DOM " << filename << " doesn't expose 1 function name - ignoring" << endl; - return; - } - - KJS::Completion comp2 = m_part->jScriptInterpreter()->evaluate("setUpPage(); " + functionname + "();" ); - bool success = ( comp2.complType() == ReturnValue || comp2.complType() == Normal ); - TQString description = "DOMTS"; - if ( comp2.complType() == Throw ) { - KJS::Value val = comp2.value(); - KJS::Object obj = Object::dynamicCast(val); - if ( obj.isValid() && obj.hasProperty( exec, "jsUnitMessage" ) ) - description = obj.get( exec, "jsUnitMessage" ).toString( exec ).qstring(); - else - description = comp2.value().toString( exec ).qstring(); - } - reportResult( success, description ); - - if (!success && !m_known_failures) - doFailureReport( filename, JSFailure ); - return; - } - - int back_known_failures = m_known_failures; - - if ( m_genOutput ) { - if ( m_known_failures & DomFailure) - m_known_failures = AllFailure; - reportResult( checkOutput(filename+"-dom"), "DOM" ); - if ( m_known_failures & RenderFailure ) - m_known_failures = AllFailure; - reportResult( checkOutput(filename+"-render"), "RENDER" ); - if ( m_known_failures & PaintFailure ) - m_known_failures = AllFailure; - renderToImage().save(m_baseDir + "/baseline/" + filename + "-dump.png","PNG", 60); - printf("Generated %s\n", TQString( m_baseDir + "/baseline/" + filename + "-dump.png" ).latin1() ); - reportResult( true, "PAINT" ); - } else { - int failures = NoFailure; - - // compare with output file - if ( m_known_failures & DomFailure) - m_known_failures = AllFailure; - if ( !reportResult( checkOutput(filename+"-dom"), "DOM" ) ) - failures |= DomFailure; - - if ( m_known_failures & RenderFailure ) - m_known_failures = AllFailure; - if ( !reportResult( checkOutput(filename+"-render"), "RENDER" ) ) - failures |= RenderFailure; - - if ( m_known_failures & PaintFailure ) - m_known_failures = AllFailure; - if (!reportResult( checkPaintdump(filename), "PAINT") ) - failures |= PaintFailure; - - doFailureReport(filename, failures ); - } - - m_known_failures = back_known_failures; -} - -void RegressionTest::evalJS( ScriptInterpreter &interp, const TQString &filename, bool report_result ) -{ - TQString fullSourceName = filename; - TQFile sourceFile(fullSourceName); - - if (!sourceFile.open(IO_ReadOnly)) { - fprintf(stderr,"Error reading file %s\n",fullSourceName.latin1()); - exit(1); - } - - TQTextStream stream ( &sourceFile ); - stream.setEncoding( TQTextStream::UnicodeUTF8 ); - TQString code = stream.read(); - sourceFile.close(); - - saw_failure = false; - ignore_errors = false; - Completion c = interp.evaluate(UString( code ) ); - - if ( report_result && !ignore_errors) { - bool expected_failure = filename.endsWith( "-n.js" ); - if (c.complType() == Throw) { - TQString errmsg = c.value().toString(interp.globalExec()).qstring(); - if ( !expected_failure ) { - printf( "ERROR: %s (%s)\n",filename.latin1(), errmsg.latin1()); - m_errors++; - } else { - reportResult( true, TQString( "Expected Failure: %1" ).arg( errmsg ) ); - } - } else if ( saw_failure ) { - if ( !expected_failure ) - doFailureReport( m_currentCategory + "/" + m_currentTest, JSFailure ); - reportResult( expected_failure, "saw 'failed!'" ); - } else { - reportResult( !expected_failure, "passed" ); - } - } -} - -class GlobalImp : public ObjectImp { -public: - virtual UString className() const { return "global"; } -}; - -void RegressionTest::testJSFile(const TQString & filename ) -{ - tqApp->mainWidget()->resize( 800, 600); // restore size - - // create interpreter - // note: this is different from the interpreter used by the part, - // it contains regression test-specific objects & functions - Object global(new GlobalImp()); - khtml::ChildFrame frame; - frame.m_part = m_part; - ScriptInterpreter interp(global,&frame); - ExecState *exec = interp.globalExec(); - - global.put(exec, "part", Object(new KHTMLPartObject(exec,m_part))); - global.put(exec, "regtest", Object(new RegTestObject(exec,this))); - global.put(exec, "debug", Object(new RegTestFunction(exec,this,RegTestFunction::Print,1) ) ); - global.put(exec, "print", Object(new RegTestFunction(exec,this,RegTestFunction::Print,1) ) ); - - TQStringList dirs = TQStringList::split( '/', filename ); - // NOTE: the basename is of little interest here, but the last basedir change - // isn't taken in account - TQString basedir = m_baseDir + "/tests/"; - for ( TQStringList::ConstIterator it = dirs.begin(); it != dirs.end(); ++it ) - { - if ( ! ::access( TQFile::encodeName( basedir + "shell.js" ), R_OK ) ) - evalJS( interp, basedir + "shell.js", false ); - basedir += *it + "/"; - } - evalJS( interp, m_baseDir + "/tests/"+ filename, true ); -} - -RegressionTest::CheckResult RegressionTest::checkPaintdump(const TQString &filename) -{ - TQString againstFilename( filename + "-dump.png" ); - TQString absFilename = TQFileInfo(m_baseDir + "/baseline/" + againstFilename).absFilePath(); - if ( svnIgnored( absFilename ) ) { - m_known_failures = NoFailure; - return Ignored; - } - CheckResult result = Failure; - - TQImage baseline; - baseline.load( absFilename, "PNG"); - TQImage output = renderToImage(); - if ( !imageEqual( baseline, output ) ) { - TQString outputFilename = m_outputDir + "/" + againstFilename; - createMissingDirs(outputFilename ); - - bool kf = false; - if ( m_known_failures & AllFailure ) - kf = true; - else if ( m_known_failures & PaintFailure ) - kf = true; - if ( kf ) - outputFilename += "-KF"; - - output.save(outputFilename, "PNG", 60); - } - else { - ::unlink( TQFile::encodeName( m_outputDir + "/" + againstFilename ) ); - result = Success; - } - return result; -} - -RegressionTest::CheckResult RegressionTest::checkOutput(const TQString &againstFilename) -{ - TQString absFilename = TQFileInfo(m_baseDir + "/baseline/" + againstFilename).absFilePath(); - if ( svnIgnored( absFilename ) ) { - m_known_failures = NoFailure; - return Ignored; - } - - bool domOut = againstFilename.endsWith( "-dom" ); - TQString data = getPartOutput( domOut ? DOMTree : RenderTree ); - data.remove( char( 13 ) ); - - CheckResult result = Success; - - // compare result to existing file - TQString outputFilename = TQFileInfo(m_outputDir + "/" + againstFilename).absFilePath(); - bool kf = false; - if ( m_known_failures & AllFailure ) - kf = true; - else if ( domOut && ( m_known_failures & DomFailure ) ) - kf = true; - else if ( !domOut && ( m_known_failures & RenderFailure ) ) - kf = true; - if ( kf ) - outputFilename += "-KF"; - - if ( m_genOutput ) - outputFilename = absFilename; - - TQFile file(absFilename); - if (file.open(IO_ReadOnly)) { - TQTextStream stream ( &file ); - stream.setEncoding( TQTextStream::UnicodeUTF8 ); - - TQString fileData = stream.read(); - - result = ( fileData == data ) ? Success : Failure; - if ( !m_genOutput && result == Success ) { - ::unlink( TQFile::encodeName( outputFilename ) ); - return Success; - } - } - - // generate result file - createMissingDirs( outputFilename ); - TQFile file2(outputFilename); - if (!file2.open(IO_WriteOnly)) { - fprintf(stderr,"Error writing to file %s\n",outputFilename.latin1()); - exit(1); - } - - TQTextStream stream2(&file2); - stream2.setEncoding( TQTextStream::UnicodeUTF8 ); - stream2 << data; - if ( m_genOutput ) - printf("Generated %s\n", outputFilename.latin1()); - - return result; -} - -bool RegressionTest::reportResult(CheckResult result, const TQString & description) -{ - if ( result == Ignored ) { - //printf("IGNORED: "); - //printDescription( description ); - return true; // no error - } else - return reportResult( result == Success, description ); -} - -bool RegressionTest::reportResult(bool passed, const TQString & description) -{ - if (m_genOutput) - return true; - - if (passed) { - if ( m_known_failures & AllFailure ) { - printf("PASS (unexpected!): "); - m_passes_fail++; - } else { - printf("PASS: "); - m_passes_work++; - } - } - else { - if ( m_known_failures & AllFailure ) { - printf("FAIL (known): "); - m_failures_fail++; - passed = true; // we knew about it - } else { - printf("FAIL: "); - m_failures_work++; - } - } - - printDescription( description ); - return passed; -} - -void RegressionTest::printDescription(const TQString& description) -{ - if (!m_currentCategory.isEmpty()) - printf("%s/", m_currentCategory.latin1()); - - printf("%s", m_currentTest.latin1()); - - if (!description.isEmpty()) { - TQString desc = description; - desc.replace( '\n', ' ' ); - printf(" [%s]", desc.latin1()); - } - - printf("\n"); - fflush(stdout); -} - -void RegressionTest::createMissingDirs(const TQString & filename) -{ - TQFileInfo dif(filename); - TQFileInfo dirInfo( dif.dirPath() ); - if (dirInfo.exists()) - return; - - TQStringList pathComponents; - TQFileInfo parentDir = dirInfo; - pathComponents.prepend(parentDir.absFilePath()); - while (!parentDir.exists()) { - TQString parentPath = parentDir.absFilePath(); - int slashPos = parentPath.findRev('/'); - if (slashPos < 0) - break; - parentPath = parentPath.left(slashPos); - pathComponents.prepend(parentPath); - parentDir = TQFileInfo(parentPath); - } - for (uint pathno = 1; pathno < pathComponents.count(); pathno++) { - if (!TQFileInfo(pathComponents[pathno]).exists() && - !TQDir(pathComponents[pathno-1]).mkdir(pathComponents[pathno])) { - fprintf(stderr,"Error creating directory %s\n",pathComponents[pathno].latin1()); - exit(1); - } - } -} - -void RegressionTest::slotOpenURL(const KURL &url, const KParts::URLArgs &args) -{ - m_part->browserExtension()->setURLArgs( args ); - - PartMonitor pm(m_part); - m_part->openURL(url); - pm.waitForCompletion(); -} - -bool RegressionTest::svnIgnored( const TQString &filename ) -{ - TQFileInfo fi( filename ); - TQString ignoreFilename = fi.dirPath() + "/svnignore"; - TQFile ignoreFile(ignoreFilename); - if (!ignoreFile.open(IO_ReadOnly)) - return false; - - TQTextStream ignoreStream(&ignoreFile); - TQString line; - while (!(line = ignoreStream.readLine()).isNull()) { - if ( line == fi.fileName() ) - return true; - } - ignoreFile.close(); - return false; -} - -void RegressionTest::resizeTopLevelWidget( int w, int h ) -{ - tqApp->mainWidget()->resize( w, h ); - // Since we're not visible, this doesn't have an immediate effect, TQWidget posts the event - TQApplication::sendPostedEvents( 0, TQEvent::Resize ); -} - -#include "test_regression.moc" |