• Skip to content
  • Skip to link menu
Trinity API Reference
  • Trinity API Reference
  • kate
 

kate

  • kate
  • part
test_regression.cpp
1 
26 #include <stdlib.h>
27 #include <sys/time.h>
28 #include <sys/resource.h>
29 #include <sys/types.h>
30 #include <unistd.h>
31 #include <pwd.h>
32 #include <signal.h>
33 
34 #include <tdeapplication.h>
35 #include <kstandarddirs.h>
36 #include <tqimage.h>
37 #include <tqfile.h>
38 #include "test_regression.h"
39 #include <unistd.h>
40 #include <stdio.h>
41 
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>
49 
50 #include <tqcolor.h>
51 #include <tqcursor.h>
52 #include <tqdir.h>
53 #include <tqevent.h>
54 #include <tqobject.h>
55 #include <tqpushbutton.h>
56 #include <tqscrollview.h>
57 #include <tqstring.h>
58 #include <tqregexp.h>
59 #include <tqtextstream.h>
60 #include <tqvaluelist.h>
61 #include <tqwidget.h>
62 #include <tqfileinfo.h>
63 #include <tqtimer.h>
64 #include <kstatusbar.h>
65 #include <tqfileinfo.h>
66 
67 #include "katedocument.h"
68 #include "kateview.h"
69 #include <tdeparts/browserextension.h>
70 #include "katejscript.h"
71 #include "katedocumenthelpers.h"
72 #include "kateconfig.h"
73 #include "../interfaces/katecmd.h"
74 
75 using namespace KJS;
76 
77 #define BASE_DIR_CONFIG "/.testkateregression-3.5"
78 
79 //BEGIN TestJScriptEnv
80 
81 TestJScriptEnv::TestJScriptEnv(KateDocument *part) {
82  ExecState *exec = m_interpreter->globalExec();
83 
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));
87 
88  *m_view = KJS::Object(wv);
89  *m_document = KJS::Object(wd);
90  m_output = new OutputObject(exec, part, v);
91  m_output->ref();
92 
93  // recreate properties
94  m_interpreter->globalObject().put(exec, "document", *m_document);
95  m_interpreter->globalObject().put(exec, "view", *m_view);
96  // create new properties
97  m_interpreter->globalObject().put(exec, "output", KJS::Object(m_output));
98  // add convenience shortcuts
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));
103 }
104 
105 TestJScriptEnv::~TestJScriptEnv() {
106  m_output->deref();
107 }
108 
109 //END TestJScriptEnv
110 
111 //BEGIN KateViewObject
112 
113 KateViewObject::KateViewObject(ExecState *exec, KateView *v, ObjectImp *fallback)
114  : view(v), fallback(fallback)
115 {
116 // put a function
117 #define PUT_FUNC(name, enumval) \
118  putDirect(#name, new KateViewFunction(exec,v,KateViewFunction::enumval,1), DontEnum)
119  fallback->ref();
120 
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);
153  PUT_FUNC(end, End);
154  PUT_FUNC(shiftEnd, ShiftEnd);
155  PUT_FUNC(up, Up);
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);
169  PUT_FUNC(top, Top);
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);
175 #undef PUT_FUNC
176 }
177 
178 KateViewObject::~KateViewObject()
179 {
180  fallback->deref();
181 }
182 
183 const ClassInfo *KateViewObject::classInfo() const {
184  // evil hack II: disguise as fallback, otherwise we can't fall back
185  return fallback->classInfo();
186 }
187 
188 Value KateViewObject::get(ExecState *exec, const Identifier &propertyName) const
189 {
190  ValueImp *val = getDirect(propertyName);
191  if (val)
192  return Value(val);
193 
194  return fallback->get(exec, propertyName);
195 }
196 
197 //END KateViewObject
198 
199 //BEGIN KateViewFunction
200 
201 KateViewFunction::KateViewFunction(ExecState */*exec*/, KateView *v, int _id, int length)
202 {
203  m_view = v;
204  id = _id;
205  putDirect("length",length);
206 }
207 
208 bool KateViewFunction::implementsCall() const
209 {
210  return true;
211 }
212 
213 Value KateViewFunction::call(ExecState *exec, Object &/*thisObj*/, const List &args)
214 {
215  // calls a function repeatedly as specified by its first parameter (once
216  // if not specified).
217 #define REP_CALL(enumval, func) \
218  case enumval: {\
219  int cnt = 1;\
220  if (args.size() > 0) cnt = args[0].toInt32(exec);\
221  while (cnt-- > 0) { m_view->func(); }\
222  return Undefined();\
223  }
224  switch (id) {
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);
239  REP_CALL(End, end);
240  REP_CALL(ShiftEnd, shiftEnd);
241  REP_CALL(Up, up);
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);
255  REP_CALL(Top, top);
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);
261  case Type: {
262  UString str = args[0].toString(exec);
263  TQString res = str.qstring();
264  return Boolean(m_view->doc()->typeChars(m_view, res));
265  }
266  }
267 
268  return Undefined();
269 #undef REP_CALL
270 }
271 
272 //END KateViewFunction
273 
274 //BEGIN OutputObject
275 
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);
283 
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);
290 
291 }
292 
293 OutputObject::~OutputObject() {
294 }
295 
296 KJS::UString OutputObject::className() const {
297  return UString("OutputObject");
298 }
299 
300 //END OutputObject
301 
302 //BEGIN OutputFunction
303 
304 OutputFunction::OutputFunction(KJS::ExecState *exec, OutputObject *output, int _id, int length)
305  : o(output)
306 {
307  id = _id;
308  if (length >= 0)
309  putDirect("length",length);
310 }
311 
312 bool OutputFunction::implementsCall() const
313 {
314  return true;
315 }
316 
317 KJS::Value OutputFunction::call(KJS::ExecState *exec, KJS::Object &thisObj, const KJS::List &args)
318 {
319  if (!*o->changed) *o->outstr = TQString();
320 
321  switch (id) {
322  case Write:
323  case Writeln: {
324  // Gather all parameters and concatenate to string
325  TQString res;
326  for (int i = 0; i < args.size(); i++) {
327  res += args[i].toString(exec).qstring();
328  }
329 
330  if (id == Writeln)
331  res += "\n";
332 
333  *o->outstr += res;
334  break;
335  }
336  case WriteCursorPositionln:
337  case WriteCursorPosition: {
338  // Gather all parameters and concatenate to string
339  TQString res;
340  for (int i = 0; i < args.size(); i++) {
341  res += args[i].toString(exec).qstring();
342  }
343 
344  // Append cursor position
345  uint l, c;
346  o->view->cursorPosition(&l, &c);
347  res += "(" + TQString::number(l) + "," + TQString::number(c) + ")";
348 
349  if (id == WriteCursorPositionln)
350  res += "\n";
351 
352  *o->outstr += res;
353  break;
354  }
355  }
356 
357  *o->changed = true;
358  return Undefined();
359 }
360 
361 //END OutputFunction
362 
363 // -------------------------------------------------------------------------
364 
365 const char failureSnapshotPrefix[] = "testkateregressionrc-FS.";
366 
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);
372 }
373 
374 static TDECmdLineOptions options[] =
375 {
376  { "b", 0, 0 },
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 },
379  { "d", 0, 0 },
380  { "debug", "Do not supress debug output", 0},
381  { "g", 0, 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 },
385  { "s", 0, 0 } ,
386  { "show", "Show the window while running tests", 0 } ,
387  { "t", 0, 0 } ,
388  { "test <filename>", "Only run a single test. Multiple options allowed.", 0 } ,
389  { "o", 0, 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 } ,
393  TDECmdLineLastOption
394 };
395 
396 int main(int argc, char *argv[])
397 {
398  // forget about any settings
399  passwd* pw = getpwuid( getuid() );
400  if (!pw) {
401  fprintf(stderr, "dang, I don't even know who I am.\n");
402  exit(1);
403  }
404 
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 );
410 
411 // signal( SIGALRM, signal_handler );
412 
413  TDECmdLineArgs::init(argc, argv, "testregression", "TestRegression",
414  "Regression tester for kate", "1.0");
415  TDECmdLineArgs::addCmdLineOptions(options);
416 
417  TDECmdLineArgs *args = TDECmdLineArgs::parsedArgs( );
418 
419  TQCString baseDir = args->getOption("base");
420  TQCString baseDirConfigFile(::getenv("HOME") + TQCString(BASE_DIR_CONFIG));
421  {
422  TQFile baseDirConfig(baseDirConfigFile);
423  if (baseDirConfig.open(IO_ReadOnly)) {
424  TQTextStream bds(&baseDirConfig);
425  baseDir = bds.readLine().latin1();
426  }
427  }
428 
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"
434  "\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"
438  "\t%s\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"
443  "", TDECmdLineArgs::appName(),
444  (const char *)baseDirConfigFile,
445  (const char *)baseDirConfigFile);
446  ::exit( 1 );
447  }
448 
449  int testcase_index = 0;
450  if (baseDir.isEmpty()) baseDir = args->arg(testcase_index++);
451 
452  TQFileInfo bdInfo(baseDir);
453  baseDir = TQFile::encodeName(bdInfo.absFilePath());
454 
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]);
460  exit(1);
461  }
462  }
463 
464  TDEApplication a;
465  a.disableAutoDcopRegistration();
466  a.setStyle("windows");
467  KSimpleConfig cfg( "testkateregressionrc" );
468  cfg.setGroup("Kate Document Defaults");
469  cfg.writeEntry("Basic Config Flags",
470  KateDocumentConfig::cfBackspaceIndents
471 // | KateDocumentConfig::cfWordWrap
472 // | KateDocumentConfig::cfRemoveSpaces
473  | KateDocumentConfig::cfWrapCursor
474 // | KateDocumentConfig::cfAutoBrackets
475 // | KateDocumentConfig::cfTabIndentsMode
476 // | KateDocumentConfig::cfOvr
477  | KateDocumentConfig::cfKeepIndentProfile
478  | KateDocumentConfig::cfKeepExtraSpaces
479  | KateDocumentConfig::cfTabIndents
480  | KateDocumentConfig::cfShowTabs
481  | KateDocumentConfig::cfSpaceIndent
482  | KateDocumentConfig::cfSmartHome
483  | KateDocumentConfig::cfTabInsertsTab
484 // | KateDocumentConfig::cfReplaceTabsDyn
485 // | KateDocumentConfig::cfRemoveTrailingDyn
486  | KateDocumentConfig::cfDoxygenAutoTyping
487 // | KateDocumentConfig::cfMixedIndent
488  | KateDocumentConfig::cfIndentPastedText
489  );
490  cfg.sync();
491 
492  int rv = 1;
493 
494  {
495  KSimpleConfig dc( "kdebugrc" );
496  // FIXME adapt to kate
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 );
506  }
507  dc.sync();
508 
509  kdClearDebugConfig();
510  }
511 
512  // create widgets
513  KateFactory *fac = KateFactory::self();
514  TDEMainWindow *toplevel = new TDEMainWindow();
515  KateDocument *part = new KateDocument(/*bSingleViewMode*/true,
516  /*bBrowserView*/false,
517  /*bReadOnly*/false,
518  /*parentWidget*/toplevel,
519  /*widgetName*/"testkate");
520  part->readConfig(&cfg);
521 
522  toplevel->setCentralWidget( part->widget() );
523 
524  Q_ASSERT(part->config()->configFlags() & KateDocumentConfig::cfDoxygenAutoTyping);
525 
526  bool visual = false;
527  if (args->isSet("show"))
528  visual = true;
529 
530  a.setTopWidget(part->widget());
531  a.setMainWidget( toplevel );
532  if ( visual )
533  toplevel->show();
534 
535  // we're not interested
536  toplevel->statusBar()->hide();
537 
538  if (!getenv("TDE_DEBUG")) {
539  // set ulimits
540  rlimit vmem_limit = { 256*1024*1024, RLIM_INFINITY }; // 256Mb Memory should suffice
541  setrlimit(RLIMIT_AS, &vmem_limit);
542  rlimit stack_limit = { 8*1024*1024, RLIM_INFINITY }; // 8Mb Memory should suffice
543  setrlimit(RLIMIT_STACK, &stack_limit);
544  }
545 
546  // run the tests
547  RegressionTest *regressionTest = new RegressionTest(part,
548  &cfg,
549  baseDir,
550  args->getOption("output"),
551  args->isSet("genoutput"));
552  TQObject::connect(part->browserExtension(), TQT_SIGNAL(openURLRequest(const KURL &, const KParts::URLArgs &)),
553  regressionTest, TQT_SLOT(slotOpenURL(const KURL&, const KParts::URLArgs &)));
554  TQObject::connect(part->browserExtension(), TQT_SIGNAL(resizeTopLevelWidget( int, int )),
555  regressionTest, TQT_SLOT(resizeTopLevelWidget( int, int )));
556 
557  regressionTest->m_keepOutput = args->isSet("keep-output");
558  regressionTest->m_showGui = args->isSet("show");
559 
560  {
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),
567  failureSnapshot);
568  }
569 
570  if (args->isSet("save-failures")) {
571  TQString failureSaver = args->getOption("save-failures");
572  regressionTest->setFailureSnapshotSaver(
573  new KSimpleConfig(failureSnapshotPrefix + failureSaver, false),
574  failureSaver);
575  }
576 
577  bool result = false;
578  QCStringList tests = args->getOptionList("test");
579  // merge testcases specified on command line
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);
585  if (!result) break;
586  }
587  else
588  result = regressionTest->runTests();
589 
590  if (result) {
591  if (args->isSet("genoutput")) {
592  printf("\nOutput generation completed.\n");
593  }
594  else {
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());
607  printf( "\n" );
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());
613  printf( "\n" );
614  if ( regressionTest->m_errors )
615  printf("Errors: %d\n",regressionTest->m_errors);
616 
617  TQFile list( regressionTest->m_outputDir + "/links.html" );
618  list.open( IO_WriteOnly|IO_Append );
619  TQString link, cl;
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.tqwriteBlock( link.latin1(), link.length() );
632  list.close();
633  }
634  }
635 
636  // Only return a 0 exit code if all tests were successful
637  if (regressionTest->m_failures_work == 0 && regressionTest->m_errors == 0)
638  rv = 0;
639 
640  // cleanup
641  delete regressionTest;
642  delete part;
643  delete toplevel;
644 // delete fac;
645 
646  return rv;
647 }
648 
649 // -------------------------------------------------------------------------
650 
651 RegressionTest *RegressionTest::curr = 0;
652 
653 RegressionTest::RegressionTest(KateDocument *part, TDEConfig *baseConfig,
654  const TQString &baseDir,
655  const TQString &outputDir, bool _genOutput)
656  : TQObject(part)
657 {
658  m_part = part;
659  m_view = static_cast<KateView *>(m_part->widget());
660  m_baseConfig = baseConfig;
661  m_baseDir = baseDir;
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";
667  else
668  m_outputDir = outputDir;
669  createMissingDirs(m_outputDir + "/");
670  m_keepOutput = false;
671  m_genOutput = _genOutput;
672  m_failureComp = 0;
673  m_failureSave = 0;
674  m_showGui = false;
675  m_passes_work = m_passes_fail = m_passes_new = 0;
676  m_failures_work = m_failures_fail = m_failures_new = 0;
677  m_errors = 0;
678 
679  ::unlink( TQFile::encodeName( m_outputDir + "/links.html" ) );
680  TQFile f( m_outputDir + "/empty.html" );
681  TQString s;
682  f.open( IO_WriteOnly | IO_Truncate );
683  s = "<html><body>Follow the white rabbit";
684  f.tqwriteBlock( s.latin1(), s.length() );
685  f.close();
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.tqwriteBlock( s.latin1(), s.length() );
690  f.close();
691 
692  curr = this;
693 }
694 
695 #include <tqobjectlist.h>
696 
697 static TQStringList readListFile( const TQString &filename )
698 {
699  // Read ignore file for this directory
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());
707  exit(1);
708  }
709  TQTextStream ignoreStream(&ignoreFile);
710  TQString line;
711  while (!(line = ignoreStream.readLine()).isNull())
712  ignoreFiles.append(line);
713  ignoreFile.close();
714  }
715  return ignoreFiles;
716 }
717 
718 RegressionTest::~RegressionTest()
719 {
720  // Important! Delete comparison config *first* as saver config
721  // might point to the same physical file.
722  delete m_failureComp;
723  delete m_failureSave;
724 }
725 
726 void RegressionTest::setFailureSnapshotConfig(TDEConfig *cfg, const TQString &sname)
727 {
728  Q_ASSERT(cfg);
729  m_failureComp = cfg;
730  m_failureComp->setGroup(sname);
731 }
732 
733 void RegressionTest::setFailureSnapshotSaver(TDEConfig *cfg, const TQString &sname)
734 {
735  Q_ASSERT(cfg);
736  m_failureSave = cfg;
737  m_failureSave->setGroup(sname);
738 }
739 
740 TQStringList RegressionTest::concatListFiles(const TQString &relPath, const TQString &filename)
741 {
742  TQStringList cmds;
743  int pos = relPath.findRev('/');
744  if (pos >= 0)
745  cmds += concatListFiles(relPath.left(pos), filename);
746  cmds += readListFile(m_baseDir + "/tests/" + relPath + "/" + filename);
747  return cmds;
748 }
749 
750 bool RegressionTest::runTests(TQString relPath, bool mustExist, int known_failure)
751 {
752  m_currentOutput = TQString::null;
753 
754  if (!TQFile(m_baseDir + "/tests/"+relPath).exists()) {
755  fprintf(stderr,"%s: No such file or directory\n",relPath.latin1());
756  return false;
757  }
758 
759  TQString fullPath = m_baseDir + "/tests/"+relPath;
760  TQFileInfo info(fullPath);
761 
762  if (!info.exists() && mustExist) {
763  fprintf(stderr,"%s: No such file or directory\n",relPath.latin1());
764  return false;
765  }
766 
767  if (!info.isReadable() && mustExist) {
768  fprintf(stderr,"%s: Access denied\n",relPath.latin1());
769  return false;
770  }
771 
772  if (info.isDir()) {
773  TQStringList ignoreFiles = readListFile( m_baseDir + "/tests/"+relPath+"/ignore" );
774  TQStringList failureFiles = readListFile( m_baseDir + "/tests/"+relPath+"/KNOWN_FAILURES" );
775 
776  // Run each test in this directory, recusively
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;
781 
782  if (filename.startsWith(".") || ignoreFiles.contains(filename) )
783  continue;
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);
790  }
791  }
792  else if (info.isFile()) {
793 
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;
801  // gather commands
802  // directory-specific commands
803  TQStringList commands = concatListFiles(relPath, ".kateconfig-commands");
804  // testcase-specific commands
805  commands += readListFile(m_currentBase + "/" + filename + "-commands");
806 
807  rereadConfig(); // reset options to default
808  if ( filename.endsWith(".txt") ) {
809 #if 0
810  if ( relPath.startsWith( "domts/" ) && !m_runJS )
811  return true;
812  if ( relPath.startsWith( "ecma/" ) && !m_runJS )
813  return true;
814 #endif
815 // if ( m_runHTML )
816  testStaticFile(relPath, commands);
817  }
818  else if (mustExist) {
819  fprintf(stderr,"%s: Not a valid test file (must be .txt)\n",relPath.latin1());
820  return false;
821  }
822  } else if (mustExist) {
823  fprintf(stderr,"%s: Not a regular file\n",relPath.latin1());
824  return false;
825  }
826 
827  return true;
828 }
829 
830 void RegressionTest::createLink( const TQString& test, int failures )
831 {
832  createMissingDirs( m_outputDir + "/" + test + "-compare.html" );
833 
834  TQFile list( m_outputDir + "/links.html" );
835  list.open( IO_WriteOnly|IO_Append );
836  TQString link;
837  link = TQString( "<a href=\"%1\" target=\"content\" title=\"%2\">" )
838  .arg( test + "-compare.html" )
839  .arg( test );
840  link += m_currentTest;
841  link += "</a> ";
842  if (failures & NewFailure)
843  link += "<span style=\"font-weight:bold;color:red\">";
844  link += "[";
845  if ( failures & ResultFailure )
846  link += "R";
847  link += "]";
848  if (failures & NewFailure)
849  link += "</span>";
850  link += "<br>\n";
851  list.tqwriteBlock( link.latin1(), link.length() );
852  list.close();
853 }
854 
861 static TQString makeRelativePath(const TQString &base, const TQString &path)
862 {
863  TQString absBase = TQFileInfo(base).absFilePath();
864  TQString absPath = TQFileInfo(path).absFilePath();
865 // kdDebug() << "absPath: \"" << absPath << "\"" << endl;
866 // kdDebug() << "absBase: \"" << absBase << "\"" << endl;
867 
868  // walk up to common ancestor directory
869  int pos = 0;
870  do {
871  pos++;
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);
876 // kdDebug() << "cmpPathComp: \"" << cmpPathComp.string() << "\"" << endl;
877 // kdDebug() << "cmpBaseComp: \"" << cmpBaseComp.string() << "\"" << endl;
878 // kdDebug() << "pos: " << pos << " newpos: " << newpos << endl;
879  if (cmpPathComp.string() != cmpBaseComp.string()) { pos--; break; }
880  pos = newpos;
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;
884 
885 // kdDebug() << "basepos " << basepos << " pathpos " << pathpos << endl;
886 
887  TQString rel;
888  {
889  TQConstString relBase(absBase.unicode() + basepos, absBase.length() - basepos);
890  TQConstString relPath(absPath.unicode() + pathpos, absPath.length() - pathpos);
891  // generate as many .. as there are path elements in relBase
892  if (relBase.string().length() > 0) {
893  for (int i = relBase.string().contains('/'); i > 0; --i)
894  rel += "../";
895  rel += "..";
896  if (relPath.string().length() > 0) rel += "/";
897  }
898  rel += relPath.string();
899  }
900  return rel;
901 }
902 
904 static void pause(int msec)
905 {
906  TQTime t;
907  t.start();
908  do {
909  kapp->processEvents();
910  } while (t.elapsed() < msec);
911 }
912 
913 void RegressionTest::doFailureReport( const TQString& test, int failures )
914 {
915  if ( failures == NoFailure ) {
916  ::unlink( TQFile::encodeName( m_outputDir + "/" + test + "-compare.html" ) );
917  return;
918  }
919 
920  createLink( test, failures );
921 
922  TQFile compare( m_outputDir + "/" + test + "-compare.html" );
923 
924  TQString testFile = TQFileInfo(test).fileName();
925 
926  TQString renderDiff;
927  TQString domDiff;
928 
929  TQString relOutputDir = makeRelativePath(m_baseDir, m_outputDir);
930 
931  // are blocking reads possible with TDEProcess?
932  char pwd[PATH_MAX];
933  (void) getcwd( pwd, PATH_MAX );
934  chdir( TQFile::encodeName( m_baseDir ) );
935 
936  if ( failures & ResultFailure ) {
937  domDiff += "<pre>";
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( '<', "&lt;" );
944  line = line.replace( '>', "&gt;" );
945  domDiff += line + "\n";
946  }
947  delete is;
948  pclose( pipe );
949  domDiff += "</pre>";
950  }
951 
952  chdir( pwd );
953 
954  // create a relative path so that it works via web as well. ugly
955  TQString relpath = makeRelativePath(m_outputDir + "/"
956  + TQFileInfo(test).dirPath(), m_baseDir);
957 
958  compare.open( IO_WriteOnly|IO_Truncate );
959  TQString cl;
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"
968  "var t = 1;\n"
969  "var lastb=0;\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"
976  "}\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"
980  "}" );
981  cl += TQString ( "function runSlideShow(){\n"
982  " document.getElementById('image').src = pics[t].src;\n"
983  " if (doflicker)\n"
984  " t = 1 - t;\n"
985  " setTimeout('runSlideShow()', 200);\n"
986  "}\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"
990  " lastb = b;\n"
991  "}\n"
992  "function showRender() { doflicker=0;toggleVisible('render')\n"
993  "}\n"
994  "function showDom() { doflicker=0;toggleVisible('dom')\n"
995  "}\n"
996  "</script>\n");
997 
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"
1002  "</style>\n" );
1003 
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>&nbsp;\n";
1008  if ( domDiff.length() )
1009  cl += "<span id='b5' class='button' onclick='showDom();m(5);'>D-DIFF</span>&nbsp;\n";
1010  // The test file always exists - except for checkOutput called from *.js files
1011  if ( TQFile::exists( m_baseDir + "/tests/"+ test ) )
1012  cl += TQString( "<a class=button href=\"%1\">HTML</a>&nbsp;" )
1013  .arg( relpath+"/tests/"+test );
1014 
1015  cl += TQString( "<hr>"
1016  "<img style='border: solid 5px gray' src=\"%1\" id='image'>" )
1017  .arg( relpath+"/baseline/"+test+"-dump.png" );
1018 
1019  cl += "<div id='render' class='diff'>" + renderDiff + "</div>";
1020  cl += "<div id='dom' class='diff'>" + domDiff + "</div>";
1021 
1022  cl += "</body></html>";
1023  compare.tqwriteBlock( cl.latin1(), cl.length() );
1024  compare.close();
1025 }
1026 
1027 void RegressionTest::testStaticFile(const TQString & filename, const TQStringList &commands)
1028 {
1029  tqApp->mainWidget()->resize( 800, 600); // restore size
1030 
1031  // Set arguments
1032  KParts::URLArgs args;
1033  if (filename.endsWith(".txt")) args.serviceType = "text/plain";
1034  m_part->browserExtension()->setURLArgs(args);
1035  // load page
1036  KURL url;
1037  url.setProtocol("file");
1038  url.setPath(TQFileInfo(m_baseDir + "/tests/"+filename).absFilePath());
1039  m_part->openURL(url);
1040 
1041  // inject commands
1042  for (TQStringList::ConstIterator cit = commands.begin(); cit != commands.end(); ++cit) {
1043  TQString str = (*cit).stripWhiteSpace();
1044  if (str.isEmpty() || str.startsWith("#")) continue;
1045  Kate::Command *cmd = KateCmd::self()->queryCommand(str);
1046  if (cmd) {
1047  TQString msg;
1048  if (!cmd->exec(m_view, str, msg))
1049  fprintf(stderr, "ERROR executing command '%s': %s\n", str.latin1(), msg.latin1());
1050  }
1051  }
1052 
1053  pause(200);
1054 
1055  Q_ASSERT(m_part->config()->configFlags() & KateDocumentConfig::cfDoxygenAutoTyping);
1056 
1057  bool script_error = false;
1058  {
1059  // Execute script
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");
1065  }
1066 
1067  int back_known_failures = m_known_failures;
1068 
1069  if (!script_error) goto bail_out;
1070 
1071  if (m_showGui) kapp->processEvents();
1072 
1073  if ( m_genOutput ) {
1074  reportResult(checkOutput(filename+"-result"), "result");
1075  } else {
1076  int failures = NoFailure;
1077 
1078  // compare with output file
1079  if ( m_known_failures & ResultFailure)
1080  m_known_failures = AllFailure;
1081  bool newfail;
1082  if ( !reportResult( checkOutput(filename+"-result"), "result", &newfail ) )
1083  failures |= ResultFailure;
1084  if (newfail)
1085  failures |= NewFailure;
1086 
1087  doFailureReport(filename, failures );
1088  }
1089 
1090 bail_out:
1091  m_known_failures = back_known_failures;
1092  m_part->setModified(false);
1093  m_part->closeURL();
1094 }
1095 
1096 bool RegressionTest::evalJS(Interpreter &interp, const TQString &filename, bool ignore_nonexistent)
1097 {
1098  TQString fullSourceName = filename;
1099  TQFile sourceFile(fullSourceName);
1100 
1101  if (!sourceFile.open(IO_ReadOnly)) {
1102  if (!ignore_nonexistent) {
1103  fprintf(stderr,"ERROR reading file %s\n",fullSourceName.latin1());
1104  m_errors++;
1105  }
1106  return ignore_nonexistent;
1107  }
1108 
1109  TQTextStream stream ( &sourceFile );
1110  stream.setEncoding( TQTextStream::UnicodeUTF8 );
1111  TQString code = stream.read();
1112  sourceFile.close();
1113 
1114  saw_failure = false;
1115  ignore_errors = false;
1116  Completion c = interp.evaluate(UString( code ) );
1117 
1118  if ( /*report_result &&*/ !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());
1122  m_errors++;
1123  return false;
1124  }
1125  }
1126  return true;
1127 }
1128 
1129 class GlobalImp : public ObjectImp {
1130 public:
1131  virtual UString className() const { return "global"; }
1132 };
1133 
1134 RegressionTest::CheckResult RegressionTest::checkOutput(const TQString &againstFilename)
1135 {
1136  TQString absFilename = TQFileInfo(m_baseDir + "/baseline/" + againstFilename).absFilePath();
1137  if ( svnIgnored( absFilename ) ) {
1138  m_known_failures = NoFailure;
1139  return Ignored;
1140  }
1141 
1142  CheckResult result = Success;
1143 
1144  // compare result to existing file
1145  TQString outputFilename = TQFileInfo(m_outputDir + "/" + againstFilename).absFilePath();
1146  bool kf = false;
1147  if ( m_known_failures & AllFailure )
1148  kf = true;
1149  if ( kf )
1150  outputFilename += "-KF";
1151 
1152  if ( m_genOutput )
1153  outputFilename = absFilename;
1154 
1155  // get existing content
1156  TQString data;
1157  if (m_outputCustomised) {
1158  data = m_outputString;
1159  } else {
1160  data = m_part->text();
1161  }
1162 
1163  TQFile file(absFilename);
1164  if (file.open(IO_ReadOnly)) {
1165  TQTextStream stream ( &file );
1166  stream.setEncoding( TQTextStream::UnicodeUTF8 );
1167 
1168  TQString fileData = stream.read();
1169 
1170  result = ( fileData == data ) ? Success : Failure;
1171  if ( !m_genOutput && result == Success && !m_keepOutput ) {
1172  ::unlink( TQFile::encodeName( outputFilename ) );
1173  return Success;
1174  }
1175  } else if (!m_genOutput) {
1176  fprintf(stderr, "Error reading file %s\n", absFilename.latin1());
1177  result = Failure;
1178  }
1179 
1180  // generate result file
1181  createMissingDirs( outputFilename );
1182  TQFile file2(outputFilename);
1183  if (!file2.open(IO_WriteOnly)) {
1184  fprintf(stderr,"Error writing to file %s\n",outputFilename.latin1());
1185  exit(1);
1186  }
1187 
1188  TQTextStream stream2(&file2);
1189  stream2.setEncoding( TQTextStream::UnicodeUTF8 );
1190  stream2 << data;
1191  if ( m_genOutput )
1192  printf("Generated %s\n", outputFilename.latin1());
1193 
1194  return result;
1195 }
1196 
1197 void RegressionTest::rereadConfig()
1198 {
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);
1203 }
1204 
1205 bool RegressionTest::reportResult(CheckResult result, const TQString & description, bool *newfail)
1206 {
1207  if ( result == Ignored ) {
1208  //printf("IGNORED: ");
1209  //printDescription( description );
1210  return true; // no error
1211  } else
1212  return reportResult( result == Success, description, newfail );
1213 }
1214 
1215 bool RegressionTest::reportResult(bool passed, const TQString & description, bool *newfail)
1216 {
1217  if (newfail) *newfail = false;
1218 
1219  if (m_genOutput)
1220  return true;
1221 
1222  TQString filename(m_currentTest + "-" + description);
1223  if (!m_currentCategory.isEmpty())
1224  filename = m_currentCategory + "/" + filename;
1225 
1226  const bool oldfailed = m_failureComp && m_failureComp->readNumEntry(filename);
1227  if (passed) {
1228  if ( m_known_failures & AllFailure ) {
1229  printf("PASS (unexpected!)");
1230  m_passes_fail++;
1231  } else {
1232  printf("PASS");
1233  m_passes_work++;
1234  }
1235  if (oldfailed) {
1236  printf(" (new)");
1237  m_passes_new++;
1238  }
1239  if (m_failureSave)
1240  m_failureSave->deleteEntry(filename);
1241  }
1242  else {
1243  if ( m_known_failures & AllFailure ) {
1244  printf("FAIL (known)");
1245  m_failures_fail++;
1246  passed = true; // we knew about it
1247  } else {
1248  printf("FAIL");
1249  m_failures_work++;
1250  }
1251  if (!oldfailed && m_failureComp) {
1252  printf(" (new)");
1253  m_failures_new++;
1254  if (newfail) *newfail = true;
1255  }
1256  if (m_failureSave)
1257  m_failureSave->writeEntry(filename, 1);
1258  }
1259  printf(": ");
1260 
1261  printDescription( description );
1262  return passed;
1263 }
1264 
1265 void RegressionTest::printDescription(const TQString& description)
1266 {
1267  if (!m_currentCategory.isEmpty())
1268  printf("%s/", m_currentCategory.latin1());
1269 
1270  printf("%s", m_currentTest.latin1());
1271 
1272  if (!description.isEmpty()) {
1273  TQString desc = description;
1274  desc.replace( '\n', ' ' );
1275  printf(" [%s]", desc.latin1());
1276  }
1277 
1278  printf("\n");
1279  fflush(stdout);
1280 }
1281 
1282 void RegressionTest::createMissingDirs(const TQString & filename)
1283 {
1284  TQFileInfo dif(filename);
1285  TQFileInfo dirInfo( dif.dirPath() );
1286  if (dirInfo.exists())
1287  return;
1288 
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('/');
1295  if (slashPos < 0)
1296  break;
1297  parentPath = parentPath.left(slashPos);
1298  pathComponents.prepend(parentPath);
1299  parentDir = TQFileInfo(parentPath);
1300  }
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());
1305  exit(1);
1306  }
1307  }
1308 }
1309 
1310 void RegressionTest::slotOpenURL(const KURL &url, const KParts::URLArgs &args)
1311 {
1312  m_part->browserExtension()->setURLArgs( args );
1313 
1314  m_part->openURL(url);
1315 }
1316 
1317 bool RegressionTest::svnIgnored( const TQString &filename )
1318 {
1319  TQFileInfo fi( filename );
1320  TQString ignoreFilename = fi.dirPath() + "/svnignore";
1321  TQFile ignoreFile(ignoreFilename);
1322  if (!ignoreFile.open(IO_ReadOnly))
1323  return false;
1324 
1325  TQTextStream ignoreStream(&ignoreFile);
1326  TQString line;
1327  while (!(line = ignoreStream.readLine()).isNull()) {
1328  if ( line == fi.fileName() )
1329  return true;
1330  }
1331  ignoreFile.close();
1332  return false;
1333 }
1334 
1335 void RegressionTest::resizeTopLevelWidget( int w, int h )
1336 {
1337  tqApp->mainWidget()->resize( w, h );
1338  // Since we're not visible, this doesn't have an immediate effect, TQWidget posts the event
1339  TQApplication::sendPostedEvents( 0, TQEvent::Resize );
1340 }
1341 
1342 #include "test_regression.moc"
TDEConfig
KURL
TDECmdLineArgs
TDECmdLineArgs::addCmdLineOptions
static void addCmdLineOptions(const TDECmdLineOptions *options, const char *name=0, const char *id=0, const char *afterId=0)
TDECmdLineArgs::appName
static const char * appName()
TDEApplication
TDECmdLineArgs::getOption
TQCString getOption(const char *option) const
Kate::Command::exec
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, msg for status.
TDEMainWindow
TDECmdLineArgs::parsedArgs
static TDECmdLineArgs * parsedArgs(const char *id=0)
KURL::setPath
void setPath(const TQString &path)
Kate::Command
Kate Commands.
Definition: document.h:96
OutputFunction
Customizing output to result-files.
Definition: test_regression.h:146
TDECmdLineArgs::init
static void init(int _argc, char **_argv, const char *_appname, const char *programName, const char *_description, const char *_version, bool noKApp=false)
KParts::URLArgs
KJS
Cool, this is all we need here.
Definition: katejscript.cpp:53
TDECmdLineArgs::count
int count() const
OutputObject
Customizing output to result-files.
Definition: test_regression.h:122
TDECmdLineArgs::getOptionList
QCStringList getOptionList(const char *option) const
TDECmdLineArgs::isSet
bool isSet(const char *option) const
kdClearDebugConfig
void kdClearDebugConfig()
KSimpleConfig
KParts::URLArgs::serviceType
TQString serviceType
TDECmdLineArgs::arg
const char * arg(int n) const
KURL::setProtocol
void setProtocol(const TQString &_txt)
TDECmdLineOptions

kate

Skip menu "kate"
  • Main Page
  • Namespace List
  • Class Hierarchy
  • Alphabetical List
  • Class List
  • File List
  • Namespace Members
  • Class Members
  • Related Pages

kate

Skip menu "kate"
  • arts
  • dcop
  • dnssd
  • interfaces
  •   kspeech
  •     interface
  •     library
  •   tdetexteditor
  • kate
  • kded
  • kdoctools
  • kimgio
  • kjs
  • libtdemid
  • libtdescreensaver
  •     tdecore
  • tdeabc
  • tdecmshell
  • tdecore
  • tdefx
  • tdehtml
  • tdeinit
  • tdeio
  •   bookmarks
  •   httpfilter
  •   kpasswdserver
  •   kssl
  • tdeioslave
  •   http
  •   tdefile
  •   tdeio
  •   tdeioexec
  • tdemdi
  •   tdemdi
  • tdenewstuff
  • tdeparts
  • tdeprint
  • tderandr
  • tderesources
  • tdespell2
  • tdesu
  • tdeui
  • tdeunittest
  • tdeutils
  • tdewallet
Generated for kate by doxygen 1.8.8
This website is maintained by Timothy Pearson.