28 #include <sys/resource.h>
29 #include <sys/types.h>
34 #include <tdeapplication.h>
35 #include <kstandarddirs.h>
38 #include "test_regression.h"
42 #include <tdeaction.h>
43 #include <tdecmdlineargs.h>
44 #include "katefactory.h"
45 #include <tdeio/job.h>
46 #include <tdemainwindow.h>
47 #include <ksimpleconfig.h>
48 #include <tdeglobalsettings.h>
55 #include <tqpushbutton.h>
56 #include <tqscrollview.h>
59 #include <tqtextstream.h>
60 #include <tqvaluelist.h>
62 #include <tqfileinfo.h>
64 #include <kstatusbar.h>
65 #include <tqfileinfo.h>
67 #include "katedocument.h"
69 #include <tdeparts/browserextension.h>
70 #include "katejscript.h"
71 #include "katedocumenthelpers.h"
72 #include "kateconfig.h"
73 #include "../interfaces/katecmd.h"
77 #define BASE_DIR_CONFIG "/.testkateregression-3.5"
81 TestJScriptEnv::TestJScriptEnv(KateDocument *part) {
82 ExecState *exec = m_interpreter->globalExec();
84 KJS::ObjectImp *wd = wrapDocument(m_interpreter->globalExec(), part);
85 KateView *v =
static_cast<KateView *
>(part->widget());
86 KJS::ObjectImp *wv =
new KateViewObject(exec, v, wrapView(m_interpreter->globalExec(), v));
88 *m_view = KJS::Object(wv);
89 *m_document = KJS::Object(wd);
94 m_interpreter->globalObject().put(exec,
"document", *m_document);
95 m_interpreter->globalObject().put(exec,
"view", *m_view);
97 m_interpreter->globalObject().put(exec,
"output", KJS::Object(m_output));
99 m_interpreter->globalObject().put(exec,
"d", *m_document);
100 m_interpreter->globalObject().put(exec,
"v", *m_view);
101 m_interpreter->globalObject().put(exec,
"out", KJS::Object(m_output));
102 m_interpreter->globalObject().put(exec,
"o", KJS::Object(m_output));
105 TestJScriptEnv::~TestJScriptEnv() {
113 KateViewObject::KateViewObject(ExecState *exec, KateView *v, ObjectImp *fallback)
114 : view(v), fallback(fallback)
117 #define PUT_FUNC(name, enumval) \
118 putDirect(#name, new KateViewFunction(exec,v,KateViewFunction::enumval,1), DontEnum)
121 PUT_FUNC(keyReturn, KeyReturn);
122 PUT_FUNC(enter, KeyReturn);
123 PUT_FUNC(type, Type);
124 PUT_FUNC(keyDelete, KeyDelete);
125 PUT_FUNC(deleteWordRight, DeleteWordRight);
126 PUT_FUNC(transpose, Transpose);
127 PUT_FUNC(cursorLeft, CursorLeft);
128 PUT_FUNC(cursorPrev, CursorLeft);
129 PUT_FUNC(left, CursorLeft);
130 PUT_FUNC(prev, CursorLeft);
131 PUT_FUNC(shiftCursorLeft, ShiftCursorLeft);
132 PUT_FUNC(shiftCursorPrev, ShiftCursorLeft);
133 PUT_FUNC(shiftLeft, ShiftCursorLeft);
134 PUT_FUNC(shiftPrev, ShiftCursorLeft);
135 PUT_FUNC(cursorRight, CursorRight);
136 PUT_FUNC(cursorNext, CursorRight);
137 PUT_FUNC(right, CursorRight);
138 PUT_FUNC(next, CursorRight);
139 PUT_FUNC(shiftCursorRight, ShiftCursorRight);
140 PUT_FUNC(shiftCursorNext, ShiftCursorRight);
141 PUT_FUNC(shiftRight, ShiftCursorRight);
142 PUT_FUNC(shiftNext, ShiftCursorRight);
143 PUT_FUNC(wordLeft, WordLeft);
144 PUT_FUNC(wordPrev, WordLeft);
145 PUT_FUNC(shiftWordLeft, ShiftWordLeft);
146 PUT_FUNC(shiftWordPrev, ShiftWordLeft);
147 PUT_FUNC(wordRight, WordRight);
148 PUT_FUNC(wordNext, WordRight);
149 PUT_FUNC(shiftWordRight, ShiftWordRight);
150 PUT_FUNC(shiftWordNext, ShiftWordRight);
151 PUT_FUNC(home, Home);
152 PUT_FUNC(shiftHome, ShiftHome);
154 PUT_FUNC(shiftEnd, ShiftEnd);
156 PUT_FUNC(shiftUp, ShiftUp);
157 PUT_FUNC(down, Down);
158 PUT_FUNC(shiftDown, ShiftDown);
159 PUT_FUNC(scrollUp, ScrollUp);
160 PUT_FUNC(scrollDown, ScrollDown);
161 PUT_FUNC(topOfView, TopOfView);
162 PUT_FUNC(shiftTopOfView, ShiftTopOfView);
163 PUT_FUNC(bottomOfView, BottomOfView);
164 PUT_FUNC(shiftBottomOfView, ShiftBottomOfView);
165 PUT_FUNC(pageUp, PageUp);
166 PUT_FUNC(shiftPageUp, ShiftPageUp);
167 PUT_FUNC(pageDown, PageDown);
168 PUT_FUNC(shiftPageDown, ShiftPageDown);
170 PUT_FUNC(shiftTop, ShiftTop);
171 PUT_FUNC(bottom, Bottom);
172 PUT_FUNC(shiftBottom, ShiftBottom);
173 PUT_FUNC(toMatchingBracket, ToMatchingBracket);
174 PUT_FUNC(shiftToMatchingBracket, ShiftToMatchingBracket);
178 KateViewObject::~KateViewObject()
183 const ClassInfo *KateViewObject::classInfo()
const {
185 return fallback->classInfo();
188 Value KateViewObject::get(ExecState *exec,
const Identifier &propertyName)
const
190 ValueImp *val = getDirect(propertyName);
194 return fallback->get(exec, propertyName);
201 KateViewFunction::KateViewFunction(ExecState *, KateView *v,
int _id,
int length)
205 putDirect(
"length",length);
208 bool KateViewFunction::implementsCall()
const
213 Value KateViewFunction::call(ExecState *exec, Object &,
const List &args)
217 #define REP_CALL(enumval, func) \
220 if (args.size() > 0) cnt = args[0].toInt32(exec);\
221 while (cnt-- > 0) { m_view->func(); }\
225 REP_CALL(KeyReturn, keyReturn);
226 REP_CALL(KeyDelete, keyDelete);
227 REP_CALL(DeleteWordRight, deleteWordRight);
228 REP_CALL(Transpose, transpose);
229 REP_CALL(CursorLeft, cursorLeft);
230 REP_CALL(ShiftCursorLeft, shiftCursorLeft);
231 REP_CALL(CursorRight, cursorRight);
232 REP_CALL(ShiftCursorRight, shiftCursorRight);
233 REP_CALL(WordLeft, wordLeft);
234 REP_CALL(ShiftWordLeft, shiftWordLeft);
235 REP_CALL(WordRight, wordRight);
236 REP_CALL(ShiftWordRight, shiftWordRight);
237 REP_CALL(Home, home);
238 REP_CALL(ShiftHome, shiftHome);
240 REP_CALL(ShiftEnd, shiftEnd);
242 REP_CALL(ShiftUp, shiftUp);
243 REP_CALL(Down, down);
244 REP_CALL(ShiftDown, shiftDown);
245 REP_CALL(ScrollUp, scrollUp);
246 REP_CALL(ScrollDown, scrollDown);
247 REP_CALL(TopOfView, topOfView);
248 REP_CALL(ShiftTopOfView, shiftTopOfView);
249 REP_CALL(BottomOfView, bottomOfView);
250 REP_CALL(ShiftBottomOfView, shiftBottomOfView);
251 REP_CALL(PageUp, pageUp);
252 REP_CALL(ShiftPageUp, shiftPageUp);
253 REP_CALL(PageDown, pageDown);
254 REP_CALL(ShiftPageDown, shiftPageDown);
256 REP_CALL(ShiftTop, shiftTop);
257 REP_CALL(Bottom, bottom);
258 REP_CALL(ShiftBottom, shiftBottom);
259 REP_CALL(ToMatchingBracket, toMatchingBracket);
260 REP_CALL(ShiftToMatchingBracket, shiftToMatchingBracket);
262 UString str = args[0].toString(exec);
263 TQString res = str.qstring();
264 return Boolean(m_view->doc()->typeChars(m_view, res));
276 OutputObject::OutputObject(KJS::ExecState *exec, KateDocument *d, KateView *v) : doc(d), view(v), changed(0), outstr(0) {
277 putDirect(
"write",
new OutputFunction(exec,
this,OutputFunction::Write,-1), DontEnum);
278 putDirect(
"print",
new OutputFunction(exec,
this,OutputFunction::Write,-1), DontEnum);
279 putDirect(
"writeln",
new OutputFunction(exec,
this,OutputFunction::Writeln,-1), DontEnum);
280 putDirect(
"println",
new OutputFunction(exec,
this,OutputFunction::Writeln,-1), DontEnum);
281 putDirect(
"writeLn",
new OutputFunction(exec,
this,OutputFunction::Writeln,-1), DontEnum);
282 putDirect(
"printLn",
new OutputFunction(exec,
this,OutputFunction::Writeln,-1), DontEnum);
284 putDirect(
"writeCursorPosition",
new OutputFunction(exec,
this,OutputFunction::WriteCursorPosition,-1), DontEnum);
285 putDirect(
"cursorPosition",
new OutputFunction(exec,
this,OutputFunction::WriteCursorPosition,-1), DontEnum);
286 putDirect(
"pos",
new OutputFunction(exec,
this,OutputFunction::WriteCursorPosition,-1), DontEnum);
287 putDirect(
"writeCursorPositionln",
new OutputFunction(exec,
this,OutputFunction::WriteCursorPositionln,-1), DontEnum);
288 putDirect(
"cursorPositionln",
new OutputFunction(exec,
this,OutputFunction::WriteCursorPositionln,-1), DontEnum);
289 putDirect(
"posln",
new OutputFunction(exec,
this,OutputFunction::WriteCursorPositionln,-1), DontEnum);
293 OutputObject::~OutputObject() {
296 KJS::UString OutputObject::className()
const {
297 return UString(
"OutputObject");
304 OutputFunction::OutputFunction(KJS::ExecState *exec,
OutputObject *output,
int _id,
int length)
309 putDirect(
"length",length);
312 bool OutputFunction::implementsCall()
const
317 KJS::Value OutputFunction::call(KJS::ExecState *exec, KJS::Object &thisObj,
const KJS::List &args)
319 if (!*o->changed) *o->outstr = TQString();
326 for (
int i = 0; i < args.size(); i++) {
327 res += args[i].toString(exec).qstring();
336 case WriteCursorPositionln:
337 case WriteCursorPosition: {
340 for (
int i = 0; i < args.size(); i++) {
341 res += args[i].toString(exec).qstring();
346 o->view->cursorPosition(&l, &c);
347 res +=
"(" + TQString::number(l) +
"," + TQString::number(c) +
")";
349 if (
id == WriteCursorPositionln)
365 const char failureSnapshotPrefix[] =
"testkateregressionrc-FS.";
367 static TQString findMostRecentFailureSnapshot() {
368 TQDir dir(kapp->dirs()->saveLocation(
"config"),
369 TQString(failureSnapshotPrefix)+
"*",
370 TQDir::Time, TQDir::Files);
371 return dir[0].mid(
sizeof failureSnapshotPrefix - 1);
377 {
"base <base_dir>",
"Directory containing tests, basedir and output directories.", 0},
378 {
"cmp-failures <snapshot>",
"Compare failures of this testrun against snapshot <snapshot>. Defaults to the most recently captured failure snapshot or none if none exists.", 0 },
380 {
"debug",
"Do not supress debug output", 0},
382 {
"genoutput",
"Regenerate baseline (instead of checking)", 0 } ,
383 {
"keep-output",
"Keep output files even on success", 0 },
384 {
"save-failures <snapshot>",
"Save failures of this testrun as failure snapshot <snapshot>", 0 },
386 {
"show",
"Show the window while running tests", 0 } ,
388 {
"test <filename>",
"Only run a single test. Multiple options allowed.", 0 } ,
390 {
"output <directory>",
"Put output in <directory> instead of <base_dir>/output", 0 } ,
391 {
"+[base_dir]",
"Directory containing tests,basedir and output directories. Only regarded if -b is not specified.", 0 } ,
392 {
"+[testcases]",
"Relative path to testcase, or directory of testcases to be run (equivalent to -t).", 0 } ,
396 int main(
int argc,
char *argv[])
399 passwd* pw = getpwuid( getuid() );
401 fprintf(stderr,
"dang, I don't even know who I am.\n");
405 TQString kh(
"/var/tmp/%1_kate_non_existent");
406 kh = kh.arg( pw->pw_name );
407 setenv(
"TDEHOME", kh.latin1(), 1 );
408 setenv(
"LC_ALL",
"C", 1 );
409 setenv(
"LANG",
"C", 1 );
414 "Regression tester for kate",
"1.0");
419 TQCString baseDir = args->
getOption(
"base");
420 TQCString baseDirConfigFile(::getenv(
"HOME") + TQCString(BASE_DIR_CONFIG));
422 TQFile baseDirConfig(baseDirConfigFile);
423 if (baseDirConfig.open(IO_ReadOnly)) {
424 TQTextStream bds(&baseDirConfig);
425 baseDir = bds.readLine().latin1();
429 if ( args->
count() < 1 && baseDir.isEmpty() ) {
430 printf(
"For regression testing, make sure to have checked out the kate regression\n"
431 "testsuite from svn:\n"
432 "\tsvn co \"https://<user>@svn.kde.org:/home/kde/trunk/tests/katetests/regression\"\n"
433 "Remember the root path into which you checked out the testsuite.\n"
435 printf(
"%s needs the root path of the kate regression\n"
436 "testsuite to function properly\n"
437 "By default, the root path is looked up in the file\n"
439 "If it doesn't exist yet, create it by invoking\n"
440 "\techo \"<root-path>\" > %s\n"
441 "You may override the location by specifying the root explicitly on the\n"
442 "command line with option -b\n"
444 (
const char *)baseDirConfigFile,
445 (
const char *)baseDirConfigFile);
449 int testcase_index = 0;
450 if (baseDir.isEmpty()) baseDir = args->
arg(testcase_index++);
452 TQFileInfo bdInfo(baseDir);
453 baseDir = TQFile::encodeName(bdInfo.absFilePath());
455 const char *subdirs[] = {
"tests",
"baseline",
"output",
"resources"};
456 for (
int i = 0; i < 2; i++ ) {
457 TQFileInfo sourceDir(TQFile::encodeName( baseDir ) +
"/" + subdirs[i]);
458 if ( !sourceDir.exists() || !sourceDir.isDir() ) {
459 fprintf(stderr,
"ERROR: Source directory \"%s/%s\": no such directory.\n", (
const char *)baseDir, subdirs[i]);
466 a.setStyle(
"windows");
468 cfg.setGroup(
"Kate Document Defaults");
469 cfg.writeEntry(
"Basic Config Flags",
470 KateDocumentConfig::cfBackspaceIndents
473 | KateDocumentConfig::cfWrapCursor
477 | KateDocumentConfig::cfKeepIndentProfile
478 | KateDocumentConfig::cfKeepExtraSpaces
479 | KateDocumentConfig::cfTabIndents
480 | KateDocumentConfig::cfShowTabs
481 | KateDocumentConfig::cfSpaceIndent
482 | KateDocumentConfig::cfSmartHome
483 | KateDocumentConfig::cfTabInsertsTab
486 | KateDocumentConfig::cfDoxygenAutoTyping
488 | KateDocumentConfig::cfIndentPastedText
497 static int areas[] = { 1000, 13000, 13001, 13002, 13010,
498 13020, 13025, 13030, 13033, 13035,
499 13040, 13050, 13051, 7000, 7006, 170,
500 171, 7101, 7002, 7019, 7027, 7014,
501 7001, 7011, 6070, 6080, 6090, 0};
502 int channel = args->
isSet(
"debug" ) ? 2 : 4;
503 for (
int i = 0; areas[i]; ++i ) {
504 dc.setGroup( TQString::number( areas[i] ) );
505 dc.writeEntry(
"InfoOutput", channel );
513 KateFactory *fac = KateFactory::self();
515 KateDocument *part =
new KateDocument(
true,
520 part->readConfig(&cfg);
522 toplevel->setCentralWidget( part->widget() );
524 Q_ASSERT(part->config()->configFlags() & KateDocumentConfig::cfDoxygenAutoTyping);
527 if (args->
isSet(
"show"))
531 a.setMainWidget( toplevel );
538 if (!getenv(
"TDE_DEBUG")) {
540 rlimit vmem_limit = { 256*1024*1024, RLIM_INFINITY };
541 setrlimit(RLIMIT_AS, &vmem_limit);
542 rlimit stack_limit = { 8*1024*1024, RLIM_INFINITY };
543 setrlimit(RLIMIT_STACK, &stack_limit);
547 RegressionTest *regressionTest =
new RegressionTest(part,
551 args->
isSet(
"genoutput"));
552 TQObject::connect(part->browserExtension(), TQ_SIGNAL(openURLRequest(
const KURL &,
const KParts::URLArgs &)),
554 TQObject::connect(part->browserExtension(), TQ_SIGNAL(resizeTopLevelWidget(
int,
int )),
555 regressionTest, TQ_SLOT(resizeTopLevelWidget(
int,
int )));
557 regressionTest->m_keepOutput = args->
isSet(
"keep-output");
558 regressionTest->m_showGui = args->
isSet(
"show");
561 TQString failureSnapshot = args->
getOption(
"cmp-failures");
562 if (failureSnapshot.isEmpty())
563 failureSnapshot = findMostRecentFailureSnapshot();
564 if (!failureSnapshot.isEmpty())
565 regressionTest->setFailureSnapshotConfig(
566 new KSimpleConfig(failureSnapshotPrefix + failureSnapshot,
true),
570 if (args->
isSet(
"save-failures")) {
571 TQString failureSaver = args->
getOption(
"save-failures");
572 regressionTest->setFailureSnapshotSaver(
573 new KSimpleConfig(failureSnapshotPrefix + failureSaver,
false),
580 for (; testcase_index < args->
count(); testcase_index++)
581 tests << args->
arg(testcase_index);
582 if (tests.count() > 0)
583 for (TQValueListConstIterator<TQCString> it = tests.begin(); it != tests.end(); ++it) {
584 result = regressionTest->runTests(*it,
true);
588 result = regressionTest->runTests();
591 if (args->
isSet(
"genoutput")) {
592 printf(
"\nOutput generation completed.\n");
595 printf(
"\nTests completed.\n");
596 printf(
"Total: %d\n",
597 regressionTest->m_passes_work+
598 regressionTest->m_passes_fail+
599 regressionTest->m_failures_work+
600 regressionTest->m_failures_fail+
601 regressionTest->m_errors);
602 printf(
"Passes: %d",regressionTest->m_passes_work);
603 if ( regressionTest->m_passes_fail )
604 printf(
" (%d unexpected passes)", regressionTest->m_passes_fail );
605 if (regressionTest->m_passes_new)
606 printf(
" (%d new since %s)", regressionTest->m_passes_new, regressionTest->m_failureComp->group().latin1());
608 printf(
"Failures: %d",regressionTest->m_failures_work);
609 if ( regressionTest->m_failures_fail )
610 printf(
" (%d expected failures)", regressionTest->m_failures_fail );
611 if ( regressionTest->m_failures_new )
612 printf(
" (%d new since %s)", regressionTest->m_failures_new, regressionTest->m_failureComp->group().latin1());
614 if ( regressionTest->m_errors )
615 printf(
"Errors: %d\n",regressionTest->m_errors);
617 TQFile list( regressionTest->m_outputDir +
"/links.html" );
618 list.open( IO_WriteOnly|IO_Append );
620 link = TQString(
"<hr>%1 failures. (%2 expected failures)" )
621 .arg(regressionTest->m_failures_work )
622 .arg( regressionTest->m_failures_fail );
623 if (regressionTest->m_failures_new)
624 link += TQString(
" <span style=\"color:red;font-weight:bold\">(%1 new failures since %2)</span>")
625 .arg(regressionTest->m_failures_new)
626 .arg(regressionTest->m_failureComp->group());
627 if (regressionTest->m_passes_new)
628 link += TQString(
" <p style=\"color:green;font-weight:bold\">%1 new passes since %2</p>")
629 .arg(regressionTest->m_passes_new)
630 .arg(regressionTest->m_failureComp->group());
631 list.writeBlock( link.latin1(), link.length() );
637 if (regressionTest->m_failures_work == 0 && regressionTest->m_errors == 0)
641 delete regressionTest;
651 RegressionTest *RegressionTest::curr = 0;
653 RegressionTest::RegressionTest(KateDocument *part,
TDEConfig *baseConfig,
654 const TQString &baseDir,
655 const TQString &outputDir,
bool _genOutput)
659 m_view =
static_cast<KateView *
>(m_part->widget());
660 m_baseConfig = baseConfig;
662 m_baseDir = m_baseDir.replace(
"//",
"/" );
663 if ( m_baseDir.endsWith(
"/" ) )
664 m_baseDir = m_baseDir.left( m_baseDir.length() - 1 );
665 if (outputDir.isEmpty())
666 m_outputDir = m_baseDir +
"/output";
668 m_outputDir = outputDir;
669 createMissingDirs(m_outputDir +
"/");
670 m_keepOutput =
false;
671 m_genOutput = _genOutput;
675 m_passes_work = m_passes_fail = m_passes_new = 0;
676 m_failures_work = m_failures_fail = m_failures_new = 0;
679 ::unlink( TQFile::encodeName( m_outputDir +
"/links.html" ) );
680 TQFile f( m_outputDir +
"/empty.html" );
682 f.open( IO_WriteOnly | IO_Truncate );
683 s =
"<html><body>Follow the white rabbit";
684 f.writeBlock( s.latin1(), s.length() );
686 f.setName( m_outputDir +
"/index.html" );
687 f.open( IO_WriteOnly | IO_Truncate );
688 s =
"<html><frameset cols=150,*><frame src=links.html><frame name=content src=empty.html>";
689 f.writeBlock( s.latin1(), s.length() );
695 #include <tqobjectlist.h>
697 static TQStringList readListFile(
const TQString &filename )
700 TQString ignoreFilename = filename;
701 TQFileInfo ignoreInfo(ignoreFilename);
702 TQStringList ignoreFiles;
703 if (ignoreInfo.exists()) {
704 TQFile ignoreFile(ignoreFilename);
705 if (!ignoreFile.open(IO_ReadOnly)) {
706 fprintf(stderr,
"Can't open %s\n",ignoreFilename.latin1());
709 TQTextStream ignoreStream(&ignoreFile);
711 while (!(line = ignoreStream.readLine()).isNull())
712 ignoreFiles.append(line);
718 RegressionTest::~RegressionTest()
722 delete m_failureComp;
723 delete m_failureSave;
726 void RegressionTest::setFailureSnapshotConfig(
TDEConfig *cfg,
const TQString &sname)
733 void RegressionTest::setFailureSnapshotSaver(
TDEConfig *cfg,
const TQString &sname)
740 TQStringList RegressionTest::concatListFiles(
const TQString &relPath,
const TQString &filename)
743 int pos = relPath.findRev(
'/');
745 cmds += concatListFiles(relPath.left(pos), filename);
746 cmds += readListFile(m_baseDir +
"/tests/" + relPath +
"/" + filename);
750 bool RegressionTest::runTests(TQString relPath,
bool mustExist,
int known_failure)
752 m_currentOutput = TQString::null;
754 if (!TQFile(m_baseDir +
"/tests/"+relPath).exists()) {
755 fprintf(stderr,
"%s: No such file or directory\n",relPath.latin1());
759 TQString fullPath = m_baseDir +
"/tests/"+relPath;
760 TQFileInfo info(fullPath);
762 if (!info.exists() && mustExist) {
763 fprintf(stderr,
"%s: No such file or directory\n",relPath.latin1());
767 if (!info.isReadable() && mustExist) {
768 fprintf(stderr,
"%s: Access denied\n",relPath.latin1());
773 TQStringList ignoreFiles = readListFile( m_baseDir +
"/tests/"+relPath+
"/ignore" );
774 TQStringList failureFiles = readListFile( m_baseDir +
"/tests/"+relPath+
"/KNOWN_FAILURES" );
777 TQDir sourceDir(m_baseDir +
"/tests/"+relPath);
778 for (uint fileno = 0; fileno < sourceDir.count(); fileno++) {
779 TQString filename = sourceDir[fileno];
780 TQString relFilename = relPath.isEmpty() ? filename : relPath+
"/"+filename;
782 if (filename.startsWith(
".") || ignoreFiles.contains(filename) )
784 int failure_type = NoFailure;
785 if ( failureFiles.contains( filename ) )
786 failure_type |= AllFailure;
787 if ( failureFiles.contains ( filename +
"-result" ) )
788 failure_type |= ResultFailure;
789 runTests(relFilename,
false, failure_type);
792 else if (info.isFile()) {
794 TQString relativeDir = TQFileInfo(relPath).dirPath();
795 TQString filename = info.fileName();
796 m_currentBase = m_baseDir +
"/tests/"+relativeDir;
797 m_currentCategory = relativeDir;
798 m_currentTest = filename;
799 m_known_failures = known_failure;
800 m_outputCustomised =
false;
803 TQStringList commands = concatListFiles(relPath,
".kateconfig-commands");
805 commands += readListFile(m_currentBase +
"/" + filename +
"-commands");
808 if ( filename.endsWith(
".txt") ) {
810 if ( relPath.startsWith(
"domts/" ) && !m_runJS )
812 if ( relPath.startsWith(
"ecma/" ) && !m_runJS )
816 testStaticFile(relPath, commands);
818 else if (mustExist) {
819 fprintf(stderr,
"%s: Not a valid test file (must be .txt)\n",relPath.latin1());
822 }
else if (mustExist) {
823 fprintf(stderr,
"%s: Not a regular file\n",relPath.latin1());
830 void RegressionTest::createLink(
const TQString& test,
int failures )
832 createMissingDirs( m_outputDir +
"/" + test +
"-compare.html" );
834 TQFile list( m_outputDir +
"/links.html" );
835 list.open( IO_WriteOnly|IO_Append );
837 link = TQString(
"<a href=\"%1\" target=\"content\" title=\"%2\">" )
838 .arg( test +
"-compare.html" )
840 link += m_currentTest;
842 if (failures & NewFailure)
843 link +=
"<span style=\"font-weight:bold;color:red\">";
845 if ( failures & ResultFailure )
848 if (failures & NewFailure)
851 list.writeBlock( link.latin1(), link.length() );
861 static TQString makeRelativePath(
const TQString &base,
const TQString &path)
863 TQString absBase = TQFileInfo(base).absFilePath();
864 TQString absPath = TQFileInfo(path).absFilePath();
872 int newpos = absBase.find(
'/', pos);
873 if (newpos == -1) newpos = absBase.length();
874 TQConstString cmpPathComp(absPath.unicode() + pos, newpos - pos);
875 TQConstString cmpBaseComp(absBase.unicode() + pos, newpos - pos);
879 if (cmpPathComp.string() != cmpBaseComp.string()) { pos--;
break; }
881 }
while (pos < (
int)absBase.length() && pos < (
int)absPath.length());
882 int basepos = pos < (int)absBase.length() ? pos + 1 : pos;
883 int pathpos = pos < (int)absPath.length() ? pos + 1 : pos;
889 TQConstString relBase(absBase.unicode() + basepos, absBase.length() - basepos);
890 TQConstString relPath(absPath.unicode() + pathpos, absPath.length() - pathpos);
892 if (relBase.string().length() > 0) {
893 for (
int i = relBase.string().contains(
'/'); i > 0; --i)
896 if (relPath.string().length() > 0) rel +=
"/";
898 rel += relPath.string();
904 static void pause(
int msec)
909 kapp->processEvents();
910 }
while (t.elapsed() < msec);
913 void RegressionTest::doFailureReport(
const TQString& test,
int failures )
915 if ( failures == NoFailure ) {
916 ::unlink( TQFile::encodeName( m_outputDir +
"/" + test +
"-compare.html" ) );
920 createLink( test, failures );
922 TQFile compare( m_outputDir +
"/" + test +
"-compare.html" );
924 TQString testFile = TQFileInfo(test).fileName();
929 TQString relOutputDir = makeRelativePath(m_baseDir, m_outputDir);
933 (void) getcwd( pwd, PATH_MAX );
934 chdir( TQFile::encodeName( m_baseDir ) );
936 if ( failures & ResultFailure ) {
938 FILE *pipe = popen( TQString::fromLatin1(
"diff -u baseline/%1-result %3/%2-result" )
939 .arg ( test, test, relOutputDir ).latin1(),
"r" );
940 TQTextIStream *is =
new TQTextIStream( pipe );
941 for (
int line = 0; line < 100 && !is->eof(); ++line ) {
942 TQString line = is->readLine();
943 line = line.replace(
'<',
"<" );
944 line = line.replace(
'>',
">" );
945 domDiff += line +
"\n";
955 TQString relpath = makeRelativePath(m_outputDir +
"/"
956 + TQFileInfo(test).dirPath(), m_baseDir);
958 compare.open( IO_WriteOnly|IO_Truncate );
960 cl = TQString(
"<html><head><title>%1</title>" ).arg( test );
961 cl += TQString(
"<script>\n"
962 "var pics = new Array();\n"
963 "pics[0]=new Image();\n"
964 "pics[0].src = '%1';\n"
965 "pics[1]=new Image();\n"
966 "pics[1].src = '%2';\n"
967 "var doflicker = 1;\n"
970 .arg( relpath+
"/baseline/"+test+
"-dump.png" )
971 .arg( testFile+
"-dump.png" );
972 cl += TQString(
"function toggleVisible(visible) {\n"
973 " document.getElementById('render').style.visibility= visible == 'render' ? 'visible' : 'hidden';\n"
974 " document.getElementById('image').style.visibility= visible == 'image' ? 'visible' : 'hidden';\n"
975 " document.getElementById('dom').style.visibility= visible == 'dom' ? 'visible' : 'hidden';\n"
977 "function show() { document.getElementById('image').src = pics[t].src; "
978 "document.getElementById('image').style.borderColor = t && !doflicker ? 'red' : 'gray';\n"
979 "toggleVisible('image');\n"
981 cl += TQString (
"function runSlideShow(){\n"
982 " document.getElementById('image').src = pics[t].src;\n"
985 " setTimeout('runSlideShow()', 200);\n"
987 "function m(b) { if (b == lastb) return; document.getElementById('b'+b).className='buttondown';\n"
988 " var e = document.getElementById('b'+lastb);\n"
989 " if(e) e.className='button';\n"
992 "function showRender() { doflicker=0;toggleVisible('render')\n"
994 "function showDom() { doflicker=0;toggleVisible('dom')\n"
998 cl += TQString (
"<style>\n"
999 ".buttondown { cursor: pointer; padding: 0px 20px; color: white; background-color: blue; border: inset blue 2px;}\n"
1000 ".button { cursor: pointer; padding: 0px 20px; color: black; background-color: white; border: outset blue 2px;}\n"
1001 ".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"
1004 cl += TQString(
"<body onload=\"m(5); toggleVisible('dom');\"" );
1005 cl += TQString(
" text=black bgcolor=gray>\n<h1>%3</h1>\n" ).arg( test );
1006 if ( renderDiff.length() )
1007 cl +=
"<span id='b4' class='button' onclick='showRender();m(4)'>R-DIFF</span> \n";
1008 if ( domDiff.length() )
1009 cl +=
"<span id='b5' class='button' onclick='showDom();m(5);'>D-DIFF</span> \n";
1011 if ( TQFile::exists( m_baseDir +
"/tests/"+ test ) )
1012 cl += TQString(
"<a class=button href=\"%1\">HTML</a> " )
1013 .arg( relpath+
"/tests/"+test );
1015 cl += TQString(
"<hr>"
1016 "<img style='border: solid 5px gray' src=\"%1\" id='image'>" )
1017 .arg( relpath+
"/baseline/"+test+
"-dump.png" );
1019 cl +=
"<div id='render' class='diff'>" + renderDiff +
"</div>";
1020 cl +=
"<div id='dom' class='diff'>" + domDiff +
"</div>";
1022 cl +=
"</body></html>";
1023 compare.writeBlock( cl.latin1(), cl.length() );
1027 void RegressionTest::testStaticFile(
const TQString & filename,
const TQStringList &commands)
1029 tqApp->mainWidget()->resize( 800, 600);
1033 if (filename.endsWith(
".txt")) args.
serviceType =
"text/plain";
1034 m_part->browserExtension()->setURLArgs(args);
1038 url.
setPath(TQFileInfo(m_baseDir +
"/tests/"+filename).absFilePath());
1039 m_part->openURL(url);
1042 for (TQStringList::ConstIterator cit = commands.begin(); cit != commands.end(); ++cit) {
1043 TQString str = (*cit).stripWhiteSpace();
1044 if (str.isEmpty() || str.startsWith(
"#"))
continue;
1048 if (!cmd->
exec(m_view, str, msg))
1049 fprintf(stderr,
"ERROR executing command '%s': %s\n", str.latin1(), msg.latin1());
1055 Q_ASSERT(m_part->config()->configFlags() & KateDocumentConfig::cfDoxygenAutoTyping);
1057 bool script_error =
false;
1060 TestJScriptEnv jsenv(m_part);
1061 jsenv.output()->setChangedFlag(&m_outputCustomised);
1062 jsenv.output()->setOutputString(&m_outputString);
1063 script_error = evalJS(jsenv.interpreter(), m_baseDir +
"/tests/"+TQFileInfo(filename).dirPath()+
"/.kateconfig-script",
true)
1064 && evalJS(jsenv.interpreter(), m_baseDir +
"/tests/"+filename+
"-script");
1067 int back_known_failures = m_known_failures;
1069 if (!script_error)
goto bail_out;
1071 if (m_showGui) kapp->processEvents();
1073 if ( m_genOutput ) {
1074 reportResult(checkOutput(filename+
"-result"),
"result");
1076 int failures = NoFailure;
1079 if ( m_known_failures & ResultFailure)
1080 m_known_failures = AllFailure;
1082 if ( !reportResult( checkOutput(filename+
"-result"),
"result", &newfail ) )
1083 failures |= ResultFailure;
1085 failures |= NewFailure;
1087 doFailureReport(filename, failures );
1091 m_known_failures = back_known_failures;
1092 m_part->setModified(
false);
1096 bool RegressionTest::evalJS(Interpreter &interp,
const TQString &filename,
bool ignore_nonexistent)
1098 TQString fullSourceName = filename;
1099 TQFile sourceFile(fullSourceName);
1101 if (!sourceFile.open(IO_ReadOnly)) {
1102 if (!ignore_nonexistent) {
1103 fprintf(stderr,
"ERROR reading file %s\n",fullSourceName.latin1());
1106 return ignore_nonexistent;
1109 TQTextStream stream ( &sourceFile );
1110 stream.setEncoding( TQTextStream::UnicodeUTF8 );
1111 TQString code = stream.read();
1114 saw_failure =
false;
1115 ignore_errors =
false;
1116 Completion c = interp.evaluate(UString( code ) );
1118 if ( !ignore_errors) {
1119 if (c.complType() == Throw) {
1120 TQString errmsg = c.value().toString(interp.globalExec()).qstring();
1121 printf(
"ERROR: %s (%s)\n",filename.latin1(), errmsg.latin1());
1129 class GlobalImp :
public ObjectImp {
1131 virtual UString className()
const {
return "global"; }
1134 RegressionTest::CheckResult RegressionTest::checkOutput(
const TQString &againstFilename)
1136 TQString absFilename = TQFileInfo(m_baseDir +
"/baseline/" + againstFilename).absFilePath();
1137 if ( svnIgnored( absFilename ) ) {
1138 m_known_failures = NoFailure;
1142 CheckResult result = Success;
1145 TQString outputFilename = TQFileInfo(m_outputDir +
"/" + againstFilename).absFilePath();
1147 if ( m_known_failures & AllFailure )
1150 outputFilename +=
"-KF";
1153 outputFilename = absFilename;
1157 if (m_outputCustomised) {
1158 data = m_outputString;
1160 data = m_part->text();
1163 TQFile file(absFilename);
1164 if (file.open(IO_ReadOnly)) {
1165 TQTextStream stream ( &file );
1166 stream.setEncoding( TQTextStream::UnicodeUTF8 );
1168 TQString fileData = stream.read();
1170 result = ( fileData == data ) ? Success : Failure;
1171 if ( !m_genOutput && result == Success && !m_keepOutput ) {
1172 ::unlink( TQFile::encodeName( outputFilename ) );
1175 }
else if (!m_genOutput) {
1176 fprintf(stderr,
"Error reading file %s\n", absFilename.latin1());
1181 createMissingDirs( outputFilename );
1182 TQFile file2(outputFilename);
1183 if (!file2.open(IO_WriteOnly)) {
1184 fprintf(stderr,
"Error writing to file %s\n",outputFilename.latin1());
1188 TQTextStream stream2(&file2);
1189 stream2.setEncoding( TQTextStream::UnicodeUTF8 );
1192 printf(
"Generated %s\n", outputFilename.latin1());
1197 void RegressionTest::rereadConfig()
1199 m_baseConfig->setGroup(
"Kate Document Defaults");
1200 m_part->config()->readConfig(m_baseConfig);
1201 m_baseConfig->setGroup(
"Kate View Defaults");
1202 m_view->config()->readConfig(m_baseConfig);
1205 bool RegressionTest::reportResult(CheckResult result,
const TQString & description,
bool *newfail)
1207 if ( result == Ignored ) {
1212 return reportResult( result == Success, description, newfail );
1215 bool RegressionTest::reportResult(
bool passed,
const TQString & description,
bool *newfail)
1217 if (newfail) *newfail =
false;
1222 TQString filename(m_currentTest +
"-" + description);
1223 if (!m_currentCategory.isEmpty())
1224 filename = m_currentCategory +
"/" + filename;
1226 const bool oldfailed = m_failureComp && m_failureComp->readNumEntry(filename);
1228 if ( m_known_failures & AllFailure ) {
1229 printf(
"PASS (unexpected!)");
1240 m_failureSave->deleteEntry(filename);
1243 if ( m_known_failures & AllFailure ) {
1244 printf(
"FAIL (known)");
1251 if (!oldfailed && m_failureComp) {
1254 if (newfail) *newfail =
true;
1257 m_failureSave->writeEntry(filename, 1);
1261 printDescription( description );
1265 void RegressionTest::printDescription(
const TQString& description)
1267 if (!m_currentCategory.isEmpty())
1268 printf(
"%s/", m_currentCategory.latin1());
1270 printf(
"%s", m_currentTest.latin1());
1274 desc.replace(
'\n',
' ' );
1275 printf(
" [%s]", desc.latin1());
1282 void RegressionTest::createMissingDirs(
const TQString & filename)
1284 TQFileInfo dif(filename);
1285 TQFileInfo dirInfo( dif.dirPath() );
1286 if (dirInfo.exists())
1289 TQStringList pathComponents;
1290 TQFileInfo parentDir = dirInfo;
1291 pathComponents.prepend(parentDir.absFilePath());
1292 while (!parentDir.exists()) {
1293 TQString parentPath = parentDir.absFilePath();
1294 int slashPos = parentPath.findRev(
'/');
1297 parentPath = parentPath.left(slashPos);
1298 pathComponents.prepend(parentPath);
1299 parentDir = TQFileInfo(parentPath);
1301 for (uint pathno = 1; pathno < pathComponents.count(); pathno++) {
1302 if (!TQFileInfo(pathComponents[pathno]).exists() &&
1303 !TQDir(pathComponents[pathno-1]).mkdir(pathComponents[pathno])) {
1304 fprintf(stderr,
"Error creating directory %s\n",pathComponents[pathno].latin1());
1312 m_part->browserExtension()->setURLArgs( args );
1314 m_part->openURL(url);
1317 bool RegressionTest::svnIgnored(
const TQString &filename )
1319 TQFileInfo fi( filename );
1320 TQString ignoreFilename = fi.dirPath() +
"/svnignore";
1321 TQFile ignoreFile(ignoreFilename);
1322 if (!ignoreFile.open(IO_ReadOnly))
1325 TQTextStream ignoreStream(&ignoreFile);
1327 while (!(line = ignoreStream.readLine()).isNull()) {
1328 if ( line == fi.fileName() )
1335 void RegressionTest::resizeTopLevelWidget(
int w,
int h )
1337 tqApp->mainWidget()->resize( w, h );
1339 TQApplication::sendPostedEvents( 0, TQEvent::Resize );
1342 #include "test_regression.moc"
void setPath(const TQString &path)
void setProtocol(const TQString &_txt)
virtual bool exec(View *view, const TQString &cmd, TQString &msg)=0
Execute this command for the given view and cmd string, return a bool about success,...
Customizing output to result-files.
Customizing output to result-files.
void setTopWidget(TQWidget *topWidget)
static void disableAutoDcopRegistration()
bool isSet(const char *option) const
static const char * appName()
QCStringList getOptionList(const char *option) const
static TDECmdLineArgs * parsedArgs(const char *id=0)
static void addCmdLineOptions(const TDECmdLineOptions *options, const char *name=0, const char *id=0, const char *afterId=0)
TQCString getOption(const char *option) const
const char * arg(int n) const
static void init(int _argc, char **_argv, const char *_appname, const char *programName, const char *_description, const char *_version, bool noKApp=false)
void setGroup(const TQString &group)
void kdClearDebugConfig()
Cool, this is all we need here.
TQString description(StdAccel id)