summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEd Baak <ed.baak@nokia.com>2010-07-29 09:04:01 +1000
committerEd Baak <ed.baak@nokia.com>2010-07-29 09:04:01 +1000
commitab5fbe577829fedf5416d5d0835b67dbaeb88688 (patch)
treecd96ef8d26ef431462a4b7c250aeb8e090d3fd18
parent533711dbd5534efa85d22a1519f233bb9e1ceefd (diff)
Experiment with using old test results clases
-rw-r--r--libqsystemtest/qkeystring.cpp405
-rw-r--r--libqsystemtest/qkeystring.h46
-rw-r--r--libqsystemtest/qtest.cpp14
-rw-r--r--libqsystemtest/qtest.h115
-rw-r--r--libqsystemtest/qtestlog.cpp596
-rw-r--r--libqsystemtest/qtestlog.h154
-rw-r--r--libqsystemtest/qtestresult.cpp2570
-rw-r--r--libqsystemtest/qtestresult.h131
-rw-r--r--qtuitest-host.pri6
9 files changed, 4037 insertions, 0 deletions
diff --git a/libqsystemtest/qkeystring.cpp b/libqsystemtest/qkeystring.cpp
new file mode 100644
index 0000000..36cf409
--- /dev/null
+++ b/libqsystemtest/qkeystring.cpp
@@ -0,0 +1,405 @@
+/****************************************************************************
+ **
+ ** Declaration of QKeyString class.
+ **
+ ** Copyright (C) 1992-$THISYEAR$ Trolltech AS. All rights reserved.
+ **
+ ** This file is part of the QTest library.
+ ** EDITIONS: NONE
+ **
+ ** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+ ** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ **
+ ****************************************************************************/
+
+#include "qtest.h"
+#include "qkeystring.h"
+
+/*!
+ \class QKeyString qkeystring.h
+ \brief The QKeyString class provides lightweight xml style formatted strings.
+
+ Use this class if you want to exchange a set of values using a single string:
+ the keystring.
+ You can add more data to the keystring by specifying a keyname and a value
+ and can then use the findKey functions to retrieve this data again from the string.
+ A typical use is:
+ \code
+ int myFirstValue = 1;
+ QString mySecondValue = "This is my data";
+
+ QKeyString myString;
+ myString.addKey("KEY1",myFirstValue);
+ myString.addKey("KEY2",mySecondValue);
+ \endcode
+ After this myString looks like:
+ \code
+ <KEY1>1</KEY1><KEY2>This is my data</KEY2>
+ \endcode
+
+ Now you can e.g. save the string in a QSetting, save it to a file, send it to a
+ receiver using a socket connection or whatever you like.
+ The receiving side then can use the findKey functions to retrieve the data.
+*/
+
+/*!
+ Creates an empty keystring.
+*/
+
+QKeyString::QKeyString()
+{
+}
+
+/*!
+ Creates a keystring and fills it with \a s.
+*/
+
+QKeyString::QKeyString( const QString &s ) : QString(s)
+{
+}
+
+/*!
+ The destructor.
+*/
+
+QKeyString::~QKeyString()
+{
+}
+
+/*!
+ Adds a new \a key /\a value pair to the keystring instance.
+ The format being used by addKey is \code<key>value</key>.\endcode
+ If the key already exists it is replaced by the new value.
+*/
+
+void QKeyString::addKey( const QString &key, const QString &value )
+{
+ setKey( key, value );
+}
+
+/*!
+ \overload
+ The int \a value is first converted to a string and then inserted into the
+ instance.
+*/
+
+void QKeyString::addKey( const QString &key, int value )
+{
+ QString tmp;
+ tmp.sprintf("%d",value);
+ setKey( key, tmp );
+}
+
+/*!
+ \internal
+ Converts \a value to an XML type string.
+*/
+void QKeyString::rawToXml( QString &value )
+{
+// if (value.find( '\n' ) >= 0)
+// qDebug( "rawToXml: " + value );
+ int pos;
+
+ // convert & into &amp;
+ pos = 0;
+ do {
+ pos = value.indexOf( "&", pos );
+ if (pos >= 0) {
+ value.remove(pos,1);
+ value.insert(pos,"&amp;");
+ pos++;
+ }
+ } while (pos >= 0);
+
+ // convert < into &lt;
+ pos = 0;
+ do {
+ pos = value.indexOf( "<", pos );
+ if (pos >= 0) {
+ value.remove(pos,1);
+ value.insert(pos,"&lt;");
+ pos++;
+ }
+ } while (pos >= 0);
+
+ // convert > into &gt;
+ pos = 0;
+ do {
+ pos = value.indexOf( ">", pos );
+ if (pos >= 0) {
+ value.remove(pos,1);
+ value.insert(pos,"&gt;");
+ pos++;
+ }
+ } while (pos >= 0);
+
+ // convert \n into &br;
+ pos = 0;
+ do {
+ pos = value.indexOf( '\n', pos );
+ if (pos >= 0) {
+ value.remove(pos,1);
+ value.insert(pos,"&br;");
+// qDebug( "found a crlf" );
+ pos++;
+ }
+ } while (pos >= 0);
+}
+
+/*!
+ \internal
+ Converts \a value from XML to a 'raw' type string.
+*/
+void QKeyString::xmlToRaw( QString &value )
+{
+ int pos;
+
+ // convert &br; into \n
+ pos = 0;
+ do {
+ pos = value.indexOf( "&br;", pos );
+ if (pos >= 0) {
+ value.remove(pos,4);
+ value.insert(pos,'\n');
+ pos++;
+ }
+ } while (pos >= 0);
+
+ // convert &gt; into >
+ pos = 0;
+ do {
+ pos = value.indexOf( "&gt;", pos );
+ if (pos >= 0) {
+ value.remove(pos,4);
+ value.insert(pos,">");
+ pos++;
+ }
+ } while (pos >= 0);
+
+ // convert &lt; into <
+ pos = 0;
+ do {
+ pos = value.indexOf( "&lt;", pos );
+ if (pos >= 0) {
+ value.remove(pos,4);
+ value.insert(pos,"<");
+ pos++;
+ }
+ } while (pos >= 0);
+
+ // convert &amp; into &
+ pos = 0;
+ do {
+ pos = value.indexOf( "&amp;", pos );
+ if (pos >= 0) {
+ value.remove(pos,5);
+ value.insert(pos,"&");
+ pos++;
+ }
+ } while (pos >= 0);
+}
+
+/*!
+ Sets an existing \a key to the specified \a value.
+ If the key does not exist yet it is appended.
+ The format being used by setKey is \code<key>value</key>\endcode
+*/
+
+void QKeyString::setKey( const QString &key, const QString &value )
+{
+ if (key == "") {
+ qWarning( "QKeyString::setKey()... using an empty key is not allowed" );
+ return;
+ }
+
+ QString val( value );
+ rawToXml( val );
+
+ int pos1, pos2;
+ pos1 = mid(0).indexOf( "<"+key+">" );
+ if (pos1>=0) {
+ pos2 = mid(0).indexOf( "</"+key+">",pos1);
+ if (pos2 > pos1) {
+ pos1+= key.length()+2;
+ remove( pos1, pos2-pos1 );
+ insert( pos1, val );
+ return;
+ }
+ }
+
+ QString S;
+ S = "<" + key + ">" + val + "</" + key + ">";
+ append( S );
+}
+
+/*!
+ \overload
+ The int \a value is first converted to a string and then inserted into the
+ instance.
+*/
+
+void QKeyString::setKey( const QString &key, int value )
+{
+ QString tmp;
+ tmp.sprintf("%d",value);
+ setKey( key, tmp );
+}
+
+/*!
+ Searches for \a key in the keystring instance and returns the associated
+ value into \a keyValue if found.
+ This functions returns TRUE if the specified key is found and returns FALSE in
+ all other cases.
+ The bool \a resetIfNotFound can be used to specify what needs to happen if the
+ key is not found. If \a resetIfNotFound == TRUE (the default) and the specified
+ \a key is not found the returned \a keyValue will be "".
+ If \a resetIfNotFound == FALSE and the specified \a key is not found the returned
+ \a keyValue will be undefined, e.g. it will have the same value as before the
+ function was called.
+*/
+
+// NOTE: see the bottom of the file for optimization issues.
+bool QKeyString::findKey( const QString &key, QString &keyValue, bool resetIfNotFound ) const
+{
+ int pos1, pos2;
+ pos1 = mid(0).indexOf( "<"+key+">" );
+ if (pos1>=0) {
+ pos2 = mid(0).indexOf( "</"+key+">",pos1 );
+ if (pos2 > pos1) {
+ pos1+= key.length()+2;
+ keyValue = mid(pos1,pos2-pos1);
+ xmlToRaw( keyValue );
+ return TRUE;
+ }
+ }
+
+ if (resetIfNotFound)
+ keyValue = "";
+
+ return FALSE;
+}
+
+/*!
+ \overload
+ If the specified \a key is found an attempt is made to convert the associated
+ keyValue to an int.
+ The function returns TRUE if both the key is found and the conversion is
+ successfull.
+ If the key is not found and \a resetIfNotFound is set to TRUE (the default),
+ \a value will be set to 0 (zero) else if \a resetIfNotFound is FALSE it will
+ be left to the value with which the function was called.
+*/
+
+bool QKeyString::findKey( const QString &key, int &value, bool resetIfNotFound ) const
+{
+ QString tmp;
+ if (findKey(key,tmp,FALSE)) {
+ bool ok;
+ value = tmp.toInt(&ok);
+ if (!ok && resetIfNotFound)
+ value = 0;
+ return ok;
+ } else {
+ if (resetIfNotFound)
+ value = 0;
+ return FALSE;
+ }
+}
+
+/*!
+ Removes the specified \a key + associated text from the string.
+ If the key is not found the returned string will be an exact copy
+ of the current contents of the keystring instance.
+ Example:
+ \code
+ QKeyString s;
+ ...
+ // s == "<FOO>This is a foo text</FOO><BAR>This is a bar text</BAR>"
+ s.removeKey("FOO");
+ // s == "<BAR>This is a bar text</BAR>"
+ \endcode
+*/
+
+QString QKeyString::removeKey( const QString &key )
+{
+ QString retValue;
+ int pos1, pos2;
+ pos1 = mid(0).indexOf( "<"+key+">");
+ if (pos1 >= 0) {
+ pos2 = mid(0).indexOf( "</"+key+">",pos1);
+ if (pos2 > pos1) {
+ int len = pos2 - pos1 + key.length()+3;
+ retValue = remove(pos1,len);
+ return retValue;
+ }
+ }
+
+ return left(length());
+}
+
+/*
+This was an attempt to do some performance optimizations for findKey.
+With short (typical) strings the gain was ~40% e.g. 3.1 seconds with the existing code and
+1.9 seconds with the experimental code for 50000 searches!.
+But with longer strings the existing code required 3.3 seconds and the experimental code
+required 20!!!!
+
+So no real optimization.
+Also 3.3 seconds to do 50000 searches is not really bad.
+
+int locateKey( const QString &src, const QString &key, uint startPos = 0 )
+{
+ for (uint s=startPos; s<src.length(); s++) {
+ if (src.at(s) == '<') {
+ if (src.at(s+key.length()+1) == '>') {
+ if (src.mid(s,key.length()) == key)
+ return s;
+ }
+ }
+ }
+ return -1;
+}
+
+void QKeyString::xmlToRaw2( QString &value )
+{
+ int pos;
+
+ // convert <br> into \n
+ do {
+ pos = locateKey( value, "br" );
+ if (pos > 0) {
+ value.remove(pos,4);
+ value.insert(pos,'\n');
+ }
+ } while (pos >= 0);
+
+ // convert <&br> into <br>
+ do {
+ pos = locateKey( value, "&br" );
+ if (pos >= 0) {
+ value.remove(pos,5);
+ value.insert(pos,"<br>");
+ }
+ } while (pos >= 0);
+}
+
+ bool QKeyString::findKey2( const QString &key, QString &keyValue, bool resetIfNotFound ) const
+{
+ int pos1, pos2;
+ pos1 = locateKey( *this, key );
+ if (pos1>=0) {
+ pos2 = locateKey( *this, "/" + key, pos1 );
+ if (pos2 > pos1) {
+ pos1+= key.length()+2;
+ keyValue = mid( pos1, pos2-pos1 );
+ xmlToRaw2( keyValue );
+ return TRUE;
+ }
+ }
+
+ if (resetIfNotFound)
+ keyValue = "";
+
+ return FALSE;
+}
+*/
diff --git a/libqsystemtest/qkeystring.h b/libqsystemtest/qkeystring.h
new file mode 100644
index 0000000..771260d
--- /dev/null
+++ b/libqsystemtest/qkeystring.h
@@ -0,0 +1,46 @@
+/****************************************************************************
+ **
+ ** Definition of QKeyString class.
+ **
+ ** Copyright (C) 1992-$THISYEAR$ Trolltech AS. All rights reserved.
+ **
+ ** This file is part of the QTest library.
+ ** EDITIONS: NONE
+ **
+ ** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+ ** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ **
+ ****************************************************************************/
+
+#ifndef QKEYSTRING_H
+#define QKEYSTRING_H
+
+#include "qtest.h"
+#include <QString>
+
+class QKeyString : public QString
+{
+public:
+ QKeyString();
+ QKeyString( const QString &s );
+ virtual ~QKeyString();
+
+ void addKey( const QString &key, const QString &value );
+ void setKey( const QString &key, const QString &value );
+ bool findKey( const QString &key, QString &keyValue, bool resetIfNotFound = TRUE ) const;
+
+ void addKey( const QString &key, int value );
+ void setKey( const QString &key, int value );
+ bool findKey( const QString &key, int &value, bool resetIfNotFound = TRUE ) const;
+
+ QString removeKey( const QString &key );
+
+//private:
+ static void rawToXml( QString &value );
+ static void xmlToRaw( QString &value );
+};
+
+#endif
+
+
+
diff --git a/libqsystemtest/qtest.cpp b/libqsystemtest/qtest.cpp
new file mode 100644
index 0000000..67aa8ac
--- /dev/null
+++ b/libqsystemtest/qtest.cpp
@@ -0,0 +1,14 @@
+/****************************************************************************
+ **
+ ** Declaration of QTest class.
+ **
+ ** Copyright (C) 1992-$THISYEAR$ Trolltech AS. All rights reserved.
+ **
+ ** This file is part of the QTest library.
+ ** EDITIONS: NONE
+ **
+ ** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+ ** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ **
+ ****************************************************************************/
+
diff --git a/libqsystemtest/qtest.h b/libqsystemtest/qtest.h
new file mode 100644
index 0000000..559f7ae
--- /dev/null
+++ b/libqsystemtest/qtest.h
@@ -0,0 +1,115 @@
+/****************************************************************************
+ **
+ ** Definition of QTest class.
+ **
+ ** Copyright (C) 1992-$THISYEAR$ Trolltech AS. All rights reserved.
+ **
+ ** This file is part of the QTest library.
+ ** EDITIONS: NONE
+ **
+ ** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+ ** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ **
+ ****************************************************************************/
+
+#ifndef QTEST_H
+#define QTEST_H
+
+#define QTEST_VERSION "1.2.0"
+
+class QTestSocket;
+class QMouseEvent;
+class QTimer;
+class QTabWidget;
+class QLabel;
+
+#ifdef Q_OS_TEMP
+// remove the 'nonstandard extension used: '<funcName>'
+// uses SEH and '<obj>' has destructor'
+#pragma warning(disable: 4509)
+#endif
+
+# define EV_PROCESS_TIME_LIMIT
+# define EV_PROCESS_TIME_LIMIT_X2
+
+
+#define QTESTLOG_INTERNFATAL 99
+#define REMOTE_CONNECT_ERROR 98
+#define QTESTSOCKET_OPEN_ERROR 97 // QTestConnection::open couldn't open a connection
+
+#define OPENREMOTE_BUG 80
+#define OPENREMOTE_UNKNOWNERROR 79
+#define OPENREMOTE_NETWORKFAILURE 78
+#define OPENREMOTE_CONNECTIONREFUSED 77
+#define OPENREMOTE_NOFILES 76
+#define OPENREMOTE_IMPOSSIBLE 75
+#define OPENREMOTE_INTERNALERROR 74
+#define OPENREMOTE_NORESOURCES 73
+#define OPENREMOTE_INACCESSIBLE 72
+#define OPENREMOTE_ALREADYBOUND 71
+
+
+// ------------------------------
+// ------------------------------
+// ------------------------------
+
+/*!
+ \enum QTestLog::LearnMode
+ Possible values:
+ None: Learnmode is off,
+ LearnNew: The system asks for verification of new (unknown) and erroneous widget snapshots.
+ LearnAll: The system asks for verification for each and every widget snapshot.
+*/
+
+// just a bunch of symbols to prevent polluting the namespace
+class QTest
+{
+public:
+
+enum LearnMode { None, LearnNew, LearnAll };
+enum TestFailMode { Abort, Continue };
+enum TestResult {
+ Invalid, // 0
+ PassSelf, // 1
+ FailSelf, // 2
+ PassCompile, // 3
+ FailCompile, // 4
+ PassTest, // 5
+ FailTest, // 6
+ PassUnexpected, // 7
+ FailExpected, // 8
+ Warn, // 9
+ __Error, // 10 Reserved for Test Framework related errors
+ Msg, // 11
+ Note, // 12 used to be a Comment, but the function is named addComment and the string is NOTE
+ MakeRes, // 13
+ SkipAll, // 14
+ QDebug, // 15 qDebug message
+ QFatal, // 16 qFatal message
+ QWarning, // 17 qWarning message
+ DetectedConfiguration, // 18
+ DetectedStyle, // 19
+ Printf, // 20
+ IgnoreResult, // 21
+ StartingTestcase, // 22
+ FinishedTestcase, // 23
+ InternFatal, // 24 Internal Fatal error
+ Totals, // 25 Used to report the totals (passes, failures and skips)
+ TestFunction_, // 26 Used to report which function is currently being executed
+ Performance, // 27 Used to report performance values
+ StartingBuild, // 28
+ FinishedBuild, // 29
+ TestState, // 30 The current state of the testframework, e.g. initializing, running, cleanup, etc.
+ StartingScript, // 31 Used to indicate start stop of a script being executed
+ FinishedScript, // 32
+ PassScript, // 33
+ FailScript, // 34
+ ScriptRes, // 35
+ ExpectFailure, // 36
+ RemoteIgnoreResult, // 37
+ Retest, // 38
+ SkipSingle
+ };
+};
+
+#endif
diff --git a/libqsystemtest/qtestlog.cpp b/libqsystemtest/qtestlog.cpp
new file mode 100644
index 0000000..50c7c8e
--- /dev/null
+++ b/libqsystemtest/qtestlog.cpp
@@ -0,0 +1,596 @@
+/****************************************************************************
+ **
+ ** Declaration of QTestLog class.
+ **
+ ** Copyright (C) 1992-$THISYEAR$ Trolltech AS. All rights reserved.
+ **
+ ** This file is part of the QTest library.
+ ** EDITIONS: NONE
+ **
+ ** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+ ** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ **
+ ****************************************************************************/
+
+#include "qtest.h"
+#include "qtestlog.h"
+#include "qkeystring.h"
+//#include "qsystem.h"
+
+#include <QFile>
+#include <QTextStream>
+#include <QApplication>
+
+#include <stdlib.h>
+
+// The 'normal'qDebug can't be used in QTestLog because qDebug is catched and converted into a
+// logresult. This is not what we want here because this interferes with the process flow that we are testing.
+// So we use a macro to convert qDebug into a call to addResult which bypasses the qDebug catching mechanism.
+#if defined(qDebug)
+# undef qDebug
+#endif
+#define qDebug( a ) \
+ addResult( QTest::QDebug, QString("%1").arg( a ), "" );
+
+QTestLog::QTestLog()
+{
+ log_file = 0;
+ log_stream = 0;
+ logging_disabled = FALSE;
+ raw_mode = FALSE;
+ is_gui_mode = FALSE;
+ cache_enabled = FALSE;
+}
+
+QTestLog::~QTestLog()
+{
+}
+
+void QTestLog::selectGUIMode()
+{
+ is_gui_mode = TRUE;
+}
+
+QString QTestLog::resultToStr( QTest::TestResult res )
+{
+ QString result = QTestResult::resultToStr( res );
+
+#ifndef Q_OS_TEMP
+/*
+ Color values:
+ 0;30 = black
+ 0;31 = red
+ 0;32 = green
+ 0;33 = brown
+ 0;34 = blue 4 (darkest)
+ 0;35 = purple
+ 0;36 = blue 2
+ 0;37 = l grey
+ 1;30 = d grey
+ 1;31 = l red
+ 1;32 = l green
+ 1;33 = yellow :-(
+ 1;34 = blue 3
+ 1;35 = l purple
+ 1;36 = blue 1 (lightest)
+ 1;37 = ?
+*/
+ QString colored_mode;
+ // FIXME QSystem::getEnvKey( "QTEST_COLORED", colored_mode );
+ if (colored_mode.isEmpty()) {
+ // keep this for backward compatibility
+ colored_mode = "0";
+ if ( (getenv( "QTEST_COLORED" ) != 0) )
+ colored_mode = "1";
+ }
+ if ( !isLogging() && (true /*QTestSettings::coloringEnabled()*/) && (colored_mode == "1") ) {
+ if ( result.startsWith( "FAIL" ) )
+ result = "\033[0;31m" + result + "\033[0m"; //red
+ else if ( result.startsWith( "PASS" ) )
+ result = "\033[0;32m" + result + "\033[0m"; //green
+ else if ( result.startsWith( "SKIP" ) )
+ result = "\033[0;37m" + result + "\033[0m"; //gray
+ else if ( result.startsWith( "PERFORM" ) )
+ result = "\033[1;34m" + result + "\033[0m"; //blue 3
+ else if ( result.startsWith( "QDEBUG" ) || result.startsWith( "QWARN" ) ||
+ result.startsWith( "WARNING" ) )
+ result = "\033[0;33m" + result + "\033[0m"; //brown (I don't like yellow, it's unreadable on my screen)
+// result = "\033[1;33m" + result + "\033[0m"; //yellow
+ else if ( result.startsWith( "QFATAL" ) || result.startsWith( "ERROR" ) ||
+ result.startsWith( "XFAIL" ) || result.startsWith( "XPASS" ) )
+ result = "\033[1;31m" + result + "\033[0m"; //light red
+ }
+#endif
+
+ return result;
+}
+
+bool QTestLog::isLoggingToFile()
+{
+ return log_file != 0;
+}
+
+void QTestLog::cacheResults( bool doCache )
+{
+ if (!cache_enabled || !doCache)
+ cached_results.clear();
+ cache_enabled = doCache;
+}
+
+void QTestLog::flushCachedResults()
+{
+ cache_enabled = FALSE;
+ for (uint i=0; i<(uint)(cached_results.count()); i++) {
+ QString s = cached_results[i];
+ writeLog( QKeyString(s) );
+ }
+ // make sure we don't append the same results multiple times
+ cached_results.clear();
+}
+
+bool QTestLog::setLoggingFile( const QString &fileName, bool append )
+{
+ closeLogging();
+
+ if (log_file != 0)
+ delete log_file;
+ log_file = 0;
+
+ if (fileName.isEmpty())
+ return FALSE;
+
+ log_file = new QFile( fileName );
+ int options = QFile::WriteOnly;
+ if (append)
+ options |= QFile::Append;
+ if ( log_file->open( (QIODevice::OpenModeFlag)options) ) {
+ log_stream = new QTextStream( log_file );
+ flushCachedResults();
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+/*
+ Stops the logging of testresults to a logfile and closes the file.
+ After the call any further logging is send to stdout again.
+*/
+
+void QTestLog::closeLogging()
+{
+ if (log_stream != 0)
+ delete log_stream;
+ log_stream = 0;
+ if (log_file != 0) {
+ log_file->close();
+ delete log_file;
+ }
+ log_file = 0;
+}
+
+void QTestLog::setConfiguration( const QString &test,
+ const QString &hostName ,
+ const QString &OSName ,
+ const QString &config ,
+ const QString &makeSpec )
+{
+ QString cfg = hostName +
+ ", " + OSName +
+ ", " + config +
+ ", " + makeSpec;
+ writeLog( QTest::DetectedConfiguration, test, cfg );
+}
+
+void QTestLog::writeLog( QTestResult::TestResult result,
+ const QString &test,
+ const QString &reason,
+ const QString &dataTag,
+ const QString &file,
+ const int line )
+{
+ QTestResultRecord rec( result, test, reason, dataTag, file, QString("%1").arg(line), "" );
+ writeLog( rec );
+}
+
+void QTestLog::writeLog( const QKeyString &tmp )
+{
+ QTestResultRecord rec( tmp );
+ writeLog( rec );
+}
+
+void QTestLog::writeLog( QTestResultRecord rec )
+{
+ if (loggingDisabled())
+ return;
+
+ QString test = rec.testName();
+
+ if (cache_enabled) {
+ cached_results.append( rec.keyString() );
+ return;
+ }
+
+ if (is_gui_mode) { //qvalidator
+ if (rec.result == QTest::FailTest ||
+ rec.result == QTest::FailCompile) {
+ emit logResult( rec.keyString() );
+ }
+ }
+
+ if ( rawLoggingMode() ) {
+ if (is_gui_mode) {
+ emit logEvent( rec.keyString() );
+ } else {
+ if (isLogging() ) {
+ QString key_string = rec.keyString(); // just for debugging...
+ *log_stream << rec.keyString() << "\n";
+ log_stream->flush();
+ } else {
+ // FIXME OutputDebugString( rec.keyString() );
+ }
+ }
+ } else {
+ QString S;
+ if (rec.result == QTest::StartingTestcase ||
+ rec.result == QTest::FinishedTestcase) {
+ QString insert;
+ if (rec.result == QTest::StartingTestcase)
+ insert = "Start testing of ";
+ else
+ insert = "Finished testing of ";
+ insert += test;
+ int c = (78 - insert.length()) / 2;
+ if (c < 78) {
+ while ((int)S.length() < c)
+ S += "*";
+ }
+ S += " " + insert + " ";
+ while (S.length() < 78)
+ S += "*";
+
+ } else if (rec.result == QTest::StartingBuild ||
+ rec.result == QTest::FinishedBuild) {
+ QString insert;
+ if (rec.result == QTest::StartingBuild)
+ insert = "Start building of ";
+ else
+ insert = "Finished building of ";
+ insert += test;
+ int c = (78 - insert.length()) / 2;
+ if (c < 78) {
+ while ((int)S.length() < c)
+ S += "*";
+ }
+ S += " " + insert + " ";
+ while (S.length() < 78)
+ S += "*";
+
+ } else if (rec.result == QTest::StartingScript ||
+ rec.result == QTest::FinishedScript) {
+ QString insert;
+ if (rec.result == QTest::StartingScript)
+ insert = "Start script execution on ";
+ else
+ insert = "Finished script execution on ";
+ insert += test;
+ int c = (78 - insert.length()) / 2;
+ if (c < 78) {
+ while ((int)S.length() < c)
+ S += "*";
+ }
+ S += " " + insert + " ";
+ while (S.length() < 78)
+ S += "*";
+
+ } else {
+ S = resultToStr( rec.result ) + ": ";
+
+ if (rec.result != QTest::Note &&
+ rec.result != QTest::StartingTestcase &&
+ rec.result != QTest::StartingBuild &&
+ rec.result != QTest::StartingScript &&
+ rec.result != QTest::FinishedTestcase &&
+ rec.result != QTest::FinishedBuild &&
+ rec.result != QTest::FinishedScript &&
+ rec.result != QTest::DetectedConfiguration &&
+ rec.result != QTest::DetectedStyle &&
+ rec.result != QTest::ScriptRes &&
+ rec.result != QTest::MakeRes) {
+ if (test != "" ) {
+ S += test;
+
+ if (test.indexOf( "::") > 0) {
+ if ( rec.result != QTest::PassTest &&
+ rec.result != QTest::IgnoreResult &&
+ rec.dataTag != "" ) {
+ S += QString( "(%1) " ).arg( rec.dataTag );
+ } else {
+ S += "() ";
+ }
+ } else {
+ S += " ";
+ }
+ }
+ }
+
+ if (rec.result == QTest::IgnoreResult) {
+ // ignoreResult is a message in a message.
+ // the actual res is hidden in the dataTag, so we decode it here.
+ int actual_res = rec.dataTag.toInt();
+ // and present it in the string
+ S += "Ignore a '" + resultToStr( (QTest::TestResult)actual_res ).simplified() + "' with string '" + rec.reason + "'";
+ } else {
+ if ( rec.reason != "" )
+ S += rec.reason;
+ }
+
+ if ( rec.file != "" ) {
+ if (rec.line > -1)
+ S += "\n Loc: " + rec.file;
+
+ if (rec.line > -1)
+ S += QString("::%1").arg(rec.line);
+ }
+
+ if ( rec.comment != "" ) {
+ S += " " + rec.comment;
+ }
+ }
+
+ if (is_gui_mode) {
+ emit logEvent( S );
+ } else {
+ if (isLogging() ) {
+ if (log_stream != 0) {
+ *log_stream << S << "\n";
+ log_stream->flush();
+ }
+ } else {
+ if (rec.result == QTest::IgnoreResult ||
+ rec.result == QTest::RemoteIgnoreResult)
+ return;
+//FIXME OutputDebugString( QString(S).ucs2() );
+ }
+ }
+ }
+}
+
+void QTestLog::disableLogging( bool disable )
+{
+ logging_disabled = disable;
+}
+
+bool QTestLog::loggingDisabled()
+{
+ return logging_disabled;
+}
+
+bool QTestLog::isLogging() const
+{
+ return log_stream != 0;
+}
+
+void QTestLog::setRawLoggingMode( bool enableRaw )
+{
+ raw_mode = enableRaw;
+}
+
+bool QTestLog::rawLoggingMode()
+{
+ return raw_mode;
+}
+
+QString QTestLog::fileName()
+{
+ if (log_file != 0)
+ return log_file->fileName();
+ return "";
+}
+
+// -----------------------------------------------
+
+bool QTestSettings::coloring_disabled = FALSE;
+bool QTestSettings::verbose_mode = FALSE;
+bool QTestSettings::wait_at_end = FALSE;
+bool QTestSettings::brief_mode = FALSE;
+QTest::LearnMode QTestSettings::learn_mode = QTest::None;
+bool QTestSettings::debug_mode = FALSE;
+bool QTestSettings::is_gui_test = FALSE;
+bool QTestSettings::show_performance = TRUE;
+bool QTestSettings::show_qdebug = TRUE;
+QString QTestSettings::cur_configuration = "";
+bool QTestSettings::logging_to_ftp = FALSE;
+bool QTestSettings::prompt_mode = FALSE;
+
+QTestSettings::QTestSettings()
+{
+}
+
+QTestSettings::~QTestSettings()
+{
+}
+
+void QTestSettings::setPromptMode( bool on )
+{
+ prompt_mode = on;
+}
+
+bool QTestSettings::promptMode()
+{
+ return prompt_mode;
+}
+
+/*!
+ Returns the learn mode of the instance.
+
+ In 'learn new' mode the user is asked for confirmation when a pixmap/snapshot is
+ not yet available in the associated testbase or when it does exist but is different
+ from the pixmap/snapshot taken from the widget under test (e.g. expected and actual
+ pixmap/snapshot are different).
+
+ In 'learn all' mode the user is asked for confirmation for each and every pixmap/
+ snapshot taken from the widget under test.
+
+ In either mode, if the user accepts the pixmap/snapshot it is appended (or replaced)
+ to the testbase.
+
+ \sa setLearnMode()
+*/
+
+QTest::LearnMode QTestSettings::learnMode()
+{
+ return learn_mode;
+}
+
+/*!
+ Sets the learning mode of the test instance to \a newMode.
+ The learning mode is typically set by means of a command line parameter and should
+ never be called directly in your testcase.
+*/
+
+void QTestSettings::setLearnMode( QTest::LearnMode newMode )
+{
+ learn_mode = newMode;
+}
+
+void QTestSettings::setBriefLoggingMode( bool enableBrief )
+{
+ brief_mode = enableBrief;
+}
+
+bool QTestSettings::briefMode()
+{
+ return brief_mode;
+}
+
+void QTestSettings::setDebugMode( bool debugOn )
+{
+ debug_mode = debugOn;
+}
+
+bool QTestSettings::debugMode()
+{
+ return debug_mode;
+}
+
+void QTestSettings::setVerbose( bool verbose )
+{
+ verbose_mode = verbose;
+}
+
+bool QTestSettings::verbose()
+{
+ return verbose_mode;
+}
+
+/*!
+ If \a doWait is TRUE the testresult will present a "press a key to continue"
+ message after the testcase has completed.
+ After the message is shown the testcase will halt until a key is pressed.
+*/
+
+void QTestSettings::setWaitAtEnd( bool doWait )
+{
+ wait_at_end = doWait;
+}
+
+bool QTestSettings::waitAtEnd()
+{
+ return wait_at_end;
+}
+
+void QTestSettings::enableColoring( bool enable )
+{
+ coloring_disabled = !enable;
+}
+
+bool QTestSettings::coloringEnabled()
+{
+ return !coloring_disabled;
+}
+
+void QTestSettings::setGuiTest( bool isGuiTest )
+{
+ is_gui_test = isGuiTest;
+}
+
+bool QTestSettings::isGuiTest()
+{
+ return is_gui_test;
+}
+
+void QTestSettings::setShowPerformance( bool show )
+{
+ show_performance = show;
+}
+
+bool QTestSettings::showPerformance()
+{
+ return show_performance;
+}
+
+void QTestSettings::setShowQDebug( bool show )
+{
+ show_qdebug = show;
+}
+
+bool QTestSettings::showQDebug()
+{
+ return show_qdebug;
+}
+
+void QTestSettings::setLoggingToFtp( bool isLogging )
+{
+ logging_to_ftp = isLogging;
+}
+
+bool QTestSettings::loggingToFtp()
+{
+ return logging_to_ftp;
+}
+
+void QTestSettings::setConfiguration( const QString &hostName ,
+ const QString &OSName ,
+ const QString &configuration ,
+ const QString &makeSpec )
+{
+ cur_configuration = hostName +
+ ", " + OSName +
+ ", " + configuration +
+ ", " + makeSpec;
+}
+
+bool QTestSettings::getConfiguration( const QString &configLine,
+ QString &hostName ,
+ QString &OSName ,
+ QString &configuration ,
+ QString &makeSpec )
+{
+ QString qtVersion, qtConfiguration;
+
+ QStringList sl = configLine.split( "," );
+ if (sl.count() == 4) {
+ hostName = sl[0].simplified();
+ OSName = sl[1].simplified();
+ qtVersion = "";
+ qtConfiguration = sl[2].simplified();
+ configuration = qtConfiguration;
+ makeSpec = sl[3].simplified();
+ } else {
+ qtConfiguration = sl[0].simplified();
+ hostName = "";
+ OSName = "";
+ configuration = "";
+ makeSpec = "";
+ return FALSE;
+ }
+
+ return (hostName != "" && OSName != ""); // allow for config string without an actual config and makespec (which is the case for scripts)
+}
+
+QString QTestSettings::curConfiguration()
+{
+ return cur_configuration;
+}
+
diff --git a/libqsystemtest/qtestlog.h b/libqsystemtest/qtestlog.h
new file mode 100644
index 0000000..0662bb0
--- /dev/null
+++ b/libqsystemtest/qtestlog.h
@@ -0,0 +1,154 @@
+/****************************************************************************
+ **
+ ** Definition of QTestLog class.
+ **
+ ** Copyright (C) 1992-$THISYEAR$ Trolltech AS. All rights reserved.
+ **
+ ** This file is part of the QTest library.
+ ** EDITIONS: NONE
+ **
+ ** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+ ** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ **
+ ****************************************************************************/
+
+#ifndef QTESTLOG_H
+#define QTESTLOG_H
+
+#include "qtest.h"
+#include "qtestresult.h"
+
+#include <QString>
+#include <QStringList>
+#include <QObject>
+
+class QFile;
+class QTextStream;
+
+class QTestSettings : public QObject
+{
+public:
+ QTestSettings();
+ ~QTestSettings();
+
+ static void enableColoring( bool enable );
+ static bool coloringEnabled();
+
+ static void setLearnMode( QTest::LearnMode newMode );
+ static QTest::LearnMode learnMode();
+
+ static void setVerbose( bool verbose );
+ static bool verbose();
+
+ static void setBriefLoggingMode( bool enableBrief );
+ static bool briefMode();
+
+ static void setDebugMode( bool debugOn );
+ static bool debugMode();
+
+ static void setPromptMode( bool on );
+ static bool promptMode();
+
+ static void setWaitAtEnd( bool doWait );
+ static bool waitAtEnd();
+
+ static void setGuiTest( bool isGuiTest );
+ static bool isGuiTest();
+
+ static void setShowPerformance( bool show );
+ static bool showPerformance();
+
+ static void setShowQDebug( bool show );
+ static bool showQDebug();
+
+ static void setLoggingToFtp( bool isLogging );
+ static bool loggingToFtp();
+
+ static void setConfiguration( const QString &hostName ,
+ const QString &OSName ,
+ const QString &config ,
+ const QString &makeSpec );
+ static bool getConfiguration( const QString &configLine,
+ QString &hostName ,
+ QString &OSName ,
+ QString &configuration ,
+ QString &ccVersion );
+ static QString curConfiguration();
+
+private:
+ static bool brief_mode;
+ static bool coloring_disabled;
+ static QTest::LearnMode learn_mode;
+ static bool debug_mode;
+ static bool verbose_mode;
+ static bool wait_at_end;
+ static bool is_gui_test;
+ static bool show_performance;
+ static bool show_qdebug;
+ static bool logging_to_ftp;
+ static QString cur_configuration;
+ static bool prompt_mode;
+};
+
+
+class QTestLog : public QObject
+{
+ Q_OBJECT
+
+public:
+ QTestLog();
+ virtual ~QTestLog();
+
+ void selectGUIMode();
+
+ QString resultToStr( QTest::TestResult res );
+
+ void writeLog( QTestResultRecord rec );
+ void writeLog( QTestResult::TestResult result,
+ const QString &test,
+ const QString &reason,
+ const QString &dataTag = "",
+ const QString &file = "",
+ const int line = -1 );
+ void writeLog( const QKeyString &tmp );
+
+ void setConfiguration( const QString &test,
+ const QString &hostName ,
+ const QString &OSName ,
+ const QString &config ,
+ const QString &makeSpec );
+
+ QString fileName();
+ bool setLoggingFile( const QString &fileName, bool append = FALSE );
+ bool isLoggingToFile();
+ void closeLogging();
+ bool isLogging() const;
+
+ void setRawLoggingMode( bool enableRaw );
+ bool rawLoggingMode();
+
+ void disableLogging( bool disable );
+ bool loggingDisabled();
+
+ void cacheResults( bool doCache );
+ void flushCachedResults();
+
+signals:
+ void logEvent( const QString &s );
+ void logResult( const QKeyString &s );
+ void logScreen( const QString &s );
+
+private:
+ QFile *log_file;
+ QTextStream *log_stream;
+
+ bool logging_disabled;
+ bool raw_mode;
+
+ QStringList cached_results;
+ bool cache_enabled;
+ bool is_gui_mode;
+};
+
+#endif
+
diff --git a/libqsystemtest/qtestresult.cpp b/libqsystemtest/qtestresult.cpp
new file mode 100644
index 0000000..c7bfb5f
--- /dev/null
+++ b/libqsystemtest/qtestresult.cpp
@@ -0,0 +1,2570 @@
+/****************************************************************************
+ **
+ ** Declaration of QTestResult class.
+ **
+ ** Copyright (C) 1992-$THISYEAR$ Trolltech AS. All rights reserved.
+ **
+ ** This file is part of the QTest library.
+ ** EDITIONS: NONE
+ **
+ ** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+ ** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ **
+ ****************************************************************************/
+
+#include "qtest.h"
+#include "qtestresult.h"
+#include "qtestlog.h"
+//#include "qsystem.h"
+
+#include <QDir>
+#include <QTextStream>
+#include <QTime>
+
+#ifndef QTEST_SUPPORT
+# include "qtestremote.h"
+#endif
+
+QTestResult testResult;
+
+class QTestResultTestCase;
+class QTestResultTestFunc;
+class QTestResultTestData;
+
+class ExpectedFailures
+{
+public:
+ ExpectedFailures();
+ virtual ~ExpectedFailures();
+
+ bool isFailExpected( int dataIndex, QString &comment, bool &abort, bool reset );
+ void setFailure( int dataIndex, QString comment, QTest::TestFailMode mode );
+ void clear();
+ void reset();
+
+private:
+ struct ExpectedFailRec
+ {
+ QTest::TestFailMode mode;
+ int index;
+ QString comment;
+ ExpectedFailRec *next;
+ };
+ void append( int index, QString comment, QTest::TestFailMode mode );
+ bool getFailure( uint index, ExpectedFailRec *&rec );
+ uint count();
+
+private:
+ ExpectedFailRec *first_expected_fail;
+};
+
+class IgnoreResults
+{
+public:
+ IgnoreResults();
+ virtual ~IgnoreResults();
+
+ void ignoreResult( const QTest::TestResult res, const QString &reason, bool exactMatch );
+ bool mustIgnoreResult( QTest::TestResult res, const QString &reason );
+ bool resetIgnoreResult( QString &errors );
+ bool getIgnoreResultIndex( QTest::TestResult res, const QString &reason, int &index );
+
+private:
+ QStringList ignore_result;
+};
+
+class QTestResultTestBase : public QObject
+{
+public:
+ QTestResultTestBase( QTestResultTestCase *test_case, QObject *parent );
+ virtual ~QTestResultTestBase();
+
+ void appendResult( bool spontaneous, QTest::TestResult result,
+ const QString &reason,
+ const QString &file = "",
+ int line = -1,
+ const QString &comment = "" );
+
+ virtual void ignoreResult( bool remote, const QTest::TestResult res, const QString &reason, bool exactMatch );
+ bool resetIgnoreResult( bool remote, QString &errors );
+
+ void setRetest( bool busy );
+ void resetResult();
+
+ virtual void setExpectedFailure( int dataIndex, QString comment, QTest::TestFailMode mode );
+
+ QTestResultTestCase* curTestCase();
+
+ QTest::TestResult result() const;
+ void setResult( QTest::TestResult res );
+
+protected:
+ ExpectedFailures expected_failures;
+ IgnoreResults local_ignores;
+ IgnoreResults remote_ignores;
+ QString last_result;
+ uint warning_count;
+ QTestResultTestCase *test_case;
+ bool retest_busy;
+ bool skip_all;
+
+ QTest::TestResult test_result;
+};
+
+class QTestResultTestCase : public QTestResultTestBase
+{
+public:
+ QTestResultTestCase();
+ QTestResultTestCase( const QString &name );
+ virtual ~QTestResultTestCase();
+
+ void setName( const QString &name, bool verbose = TRUE, bool build = FALSE );
+ QString name();
+
+ void setCurrentTestFunction( const QString &name );
+ QString curFunctionName( bool fullName ) const;
+ uint totalTests() const;
+ uint noOfExecutedTests() const;
+
+ void setCurrentTestData( const QString &dataTag );
+ QString curDataTag();
+ int curDataIndex() const;
+ uint curDataCount() const;
+
+ void setCurrentTestLocation(QTestResult::TestLocation loc);
+ QTestResult::TestLocation currentTestLocation();
+
+ QTestResultTestFunc* findFunction( const QString &funcName );
+ QTestResultTestFunc* curFunction();
+
+ bool curTestPassed();
+ bool curTestVerified();
+ bool curTestFailed();
+ bool curTestSkipped();
+
+ // returns the number of skips for the current testfunction
+ uint curSkipCount() const;
+
+ // returns the total number of skipped tests
+ uint totalSkipped() const;
+
+ // returns the total number of passed tests
+ uint totalPassed() const;
+
+ // returns the total number of failed tests
+ uint totalFailed() const;
+
+ virtual void ignoreResult( bool remote, const QTest::TestResult res, const QString &reason, bool exactMatch );
+ virtual void setExpectedFailure( int dataIndex, QString comment, QTest::TestFailMode mode );
+
+ void addResult( bool spontaneous,
+ QTest::TestResult result,
+ const QString &reason,
+ const QString &file = "",
+ int line = -1,
+ const QString &comment = "" );
+
+ QTestLog* testLog();
+ void writeLog( QTestResultRecord rec );
+
+ void retest( bool busy );
+
+private:
+ QTestLog test_log;
+ QString m_name;
+ QTestResultTestFunc *m_first;
+ QTestResultTestFunc *cur_func;
+ QTime timer;
+ QTestResult::TestLocation cur_test_location;
+
+ bool build_mode;
+};
+
+class QTestResultTestFunc : public QTestResultTestBase
+{
+public:
+ QTestResultTestFunc( const QString &funcName, QTestResultTestCase *parent );
+ virtual ~QTestResultTestFunc();
+
+ QString name();
+
+ QTestResultTestFunc *next();
+ void setNext( QTestResultTestFunc *n );
+
+ void setCurrentTestData( const QString &name );
+ QTestResultTestData* findData( const QString &dataName );
+ QTestResultTestData* curData();
+ QString curDataTag();
+ int curDataIndex();
+
+ uint dataCount();
+ uint skipCount();
+ uint failCount();
+ uint passCount();
+
+ bool passed( bool current );
+ bool verified( bool current );
+ bool failed( bool current );
+ bool skipped( bool current );
+ bool hasFailures();
+
+ void ignoreResult( bool remote, const QTest::TestResult res, const QString &reason, bool exactMatch );
+ virtual void setExpectedFailure( int dataIndex, QString comment, QTest::TestFailMode mode );
+
+ void addResult( bool spontaneous,
+ QTest::TestResult result,
+ const QString &reason,
+ const QString &file = "",
+ int line = -1,
+ const QString &comment = "" );
+
+ void retest( bool busy );
+
+protected:
+ friend class QTestResultTestCase;
+
+private:
+ QString func_name;
+ QTestResultTestData *first_data;
+ QTestResultTestFunc *next_func;
+ QTestResultTestData *cur_data;
+};
+
+class QTestResultTestData : public QTestResultTestBase
+{
+public:
+ QTestResultTestData( const QString &tagName, bool skipAll, QTestResultTestFunc *parent );
+ virtual ~QTestResultTestData();
+
+ QString name();
+ QString dataTag();
+
+ QTestResultTestData* next();
+ void setNext( QTestResultTestData *n );
+
+ void addResult( bool spontaneous,
+ QTest::TestResult result,
+ const QString &reason,
+ const QString &file = "",
+ int line = -1,
+ const QString &comment = "" );
+
+ bool verified();
+
+ void retest( bool busy );
+ virtual void setExpectedFailure( int dataIndex, QString comment, QTest::TestFailMode mode );
+
+protected:
+ friend class QTestResultTestFunc;
+
+private:
+ QString data_name;
+ QTestResultTestData *next_data;
+};
+
+/*!
+ \class QTestResult qtestresult.h
+ \brief The QTestResult class processes testresults from the executed testcase and
+ sends these results to a configured output.
+
+ The class is typically called by QTestCase and doesn't need any direct intervention
+ from a user, but if you have a desire to add additional information into the testresult
+ you can do so.
+
+ Simply create an instance of QTestResult and call one of it's functions. QTestResult is
+ a singleton class and will always point at the same instance, i.e. there is only one testresult
+ to which all messages will be appended.
+
+ If you work inside your testcase you don't even have to create a QTestResult instance: QTestCase
+ has a predifed instance named testResult that is accessible from your derived testcase.
+
+ \sa QTestCase
+ \link testing.html Introduction to testing \endlink
+ \link overview.html QTest overview \endlink
+*/
+
+class QTestResultSuite : public QObject
+{
+public:
+ QTestResultSuite();
+ virtual ~QTestResultSuite();
+
+ QTestResultTestCase* testCase();
+
+private:
+ QTestResultTestCase *test_case;
+};
+
+/*!
+ \enum QTestResult::TestLocation
+ Possible values can be NoWhere, DataFunc, InitFunc, Func, CleanupFunc, Starting, LaunchApps, InitTestCase, Executing, KillApps, CleanupTestCase.
+*/
+
+#ifndef QTEST_SUPPORT
+
+ QtMsgHandler oldMsgHandler;
+
+/*
+ Message handler that converts qDebug, qWarning and qFatal messages into test results.
+*/
+
+static void testCaseMsgHandler( QtMsgType type, const char *msg )
+{
+ // Avoid infinite recursion: it is possible that one function we call from
+ // the message handler will call qWarning(), etc. -- ignore such messages.
+ static bool alreadyCalled = FALSE;
+ static char *secondMsg = 0;
+ static QtMsgType secondType;
+ if ( alreadyCalled ) {
+ if ( !secondMsg ) {
+ const int msgSize = 256;
+ secondMsg = new char[msgSize];
+ strncpy( secondMsg, msg, msgSize-1 );
+ secondMsg[msgSize-1] = 0;
+ secondType = type;
+ }
+ return;
+ }
+ alreadyCalled = TRUE;
+
+ QString s;
+ s = QString( "%1" ).arg( msg );
+
+ switch ( type ) {
+ case QtDebugMsg:
+ //FIXME This is an ugly hack that I don't like at all.
+ if (!s.startsWith( "Qt: gdb: -nograb added to command-line options.") && !s.startsWith( "Connected to VFB server:" ) )
+ testResult.addResult( QTest::QDebug, s );
+ break;
+ case QtWarningMsg:
+ if (s.startsWith("ASSERT:")) {
+ if (testResult.debugMode()) {
+ testResult.addWarning( s ); // adding a warning to the testresult should be safe...
+ oldMsgHandler( type, msg );
+ } else {
+ testResult.addFatal( s );
+ }
+ } else {
+ testResult.addResult( QTest::QWarning, s );
+ }
+ break;
+ case QtFatalMsg:
+ if (testResult.debugMode()) {
+ testResult.addWarning( "<<< QFatal >>> "+ s ); // adding a warning to the testresult should be safe...
+ if (oldMsgHandler != 0)
+ oldMsgHandler( type, msg );
+ } else {
+ testResult.addFatal( s );
+ }
+ break;
+ default:
+
+ { /* do nothing, avoid compiler warnings */ }
+ }
+ if ( secondMsg ) {
+ QString typeStr;
+ switch ( secondType ) {
+ case QtDebugMsg:
+ typeStr = "qDebug()";
+ break;
+ case QtWarningMsg:
+ typeStr = "qWarning()";
+ break;
+ case QtFatalMsg:
+ typeStr = "qFatal()";
+ break;
+ default:
+ { /* do nothing, avoid compiler warnings */ }
+ }
+ testResult.addWarning( QString("Received a %1 in the message handler: '%2'").arg(typeStr).arg(secondMsg) );
+ delete[] secondMsg;
+ secondMsg = 0;
+ }
+
+ alreadyCalled = FALSE;
+}
+#endif
+
+QTestResultSuite p;
+
+// ***************************************************
+// ***************************************************
+
+/*!
+ The constructor. QTestResult is a singleton class, so all instances of it will end up
+ with the same private instance.
+*/
+QTestResult::QTestResult()
+{
+}
+
+/*!
+ Destroys the instance.
+*/
+QTestResult::~QTestResult()
+{
+}
+
+/*!
+ \internal
+*/
+void QTestResult::installMsgHandler()
+{
+#ifndef QTEST_SUPPORT
+ oldMsgHandler = qInstallMsgHandler( testCaseMsgHandler );
+#endif
+}
+
+/*!
+ Appends a fatal \a message to the testresult and then aborts the testcase execution.
+*/
+void QTestResult::addFatal( const QString &message )
+{
+ p.testCase()->addResult( TRUE, QTest::QFatal, message );
+}
+
+/*!
+ Appends a \a message to the testresult.
+*/
+void QTestResult::addMessage( const QString &message )
+{
+ p.testCase()->addResult( TRUE, QTest::Msg, message );
+}
+
+/*!
+ Appends an error \a message to the testresult.
+*/
+void QTestResult::addError( const QString &message )
+{
+ p.testCase()->addResult( TRUE, QTest::__Error, message );
+}
+
+/*!
+ Adds a \a note to the testresult.
+*/
+void QTestResult::addNote( const QString &note )
+{
+ p.testCase()->addResult( TRUE, QTest::Note, note );
+}
+
+/*!
+ Appends a skip message to the testresult that is clarified by a\a reason.
+ If \a skipAll is set to TRUE all instances of the current testfunction will be skipped
+ and only one skip message will be appended to the testresult. If \a skipAll is set to
+ FALSE every execution of the testfunction will result in a separate skip warning in the
+ testresult.
+ The \a file and \a line values will be shown in the testresult to identify the codeline
+ on which the skip occurred.
+*/
+void QTestResult::skip( const QString &reason, bool skipAll,
+ const QString &file, int line )
+{
+ if (skipAll)
+ p.testCase()->addResult( TRUE, QTest::SkipAll, reason, file, line, "" );
+ else
+ p.testCase()->addResult( TRUE, QTest::SkipSingle, reason, file, line, "" );
+}
+
+/*!
+ Appends a warning message described by \a text to the testresult.
+ The testresult assumes the warning has occurred in the current testcase/testfunction
+ (as set by setTestFunction()).
+*/
+void QTestResult::addWarning( const QString &text )
+{
+ p.testCase()->addResult( TRUE, QTest::Warn, text );
+
+}
+
+/*!
+ Creates a string describing a test failure using the given parameters and appends
+ the string to the testresult.
+ The testresult assumes the fail has occurred in the current testcase/testfunction
+ (as set by setTestFunction()). The \a text describes the problem and \a file and
+ \a line finally refer to the actual line in the testfunction where the problem occurred.
+*/
+void QTestResult::addFailure( const QString &text, const QString &file, int line )
+{
+ p.testCase()->addResult( TRUE, QTest::FailTest, text, file, line, "" );
+}
+
+/*!
+ \obsolete
+ Please use ignoreResult() in new code.
+*/
+/*
+void QTestResult::setIgnoreResult( const QTest::TestResult res, const QString &reason, bool exactMatch )
+{
+ ignoreResult( res, reason, exactMatch );
+}
+*/
+
+/*!
+ Instructs the testresult to ignore a \a result of the specified \a reason
+ When the result is reported it will NOT be shown in the testresult
+ and the test will not abort, even if it is a failure.
+ ignoreResult may be called multiple times to define a series of results to be ignored.
+ If \a exactMatch is TRUE, the specified string must match the logged string exactly
+ else the specified \a result is expected to be the start of a reported result.
+*/
+void QTestResult::ignoreResult( const QTest::TestResult result, const QString &reason, bool exactMatch )
+{
+ p.testCase()->ignoreResult( FALSE, result, reason, exactMatch );
+}
+
+/*!
+ Informs the testresult that \a result with \a reason must be ignored.
+ This means that the testresult is actually waiting for the specified result to be logged.
+ When the logging happens the result is ignored (i.e. not shown), but if the logging does not
+ occur then this is treated as a failure.
+ If \a exactMatch is TRUE then the specified \a reason must be exactly the same as the
+ one that is logged, and if \a exactMatch is FALSE then the \a reason is expected to be
+ start of the logged string.
+*/
+void QTestResult::remoteIgnoreResult( const QTest::TestResult result, const QString &reason, bool exactMatch )
+{
+ p.testCase()->ignoreResult( TRUE, result, reason, exactMatch );
+}
+
+/*!
+ Returns the number of tests that are executed.
+*/
+uint QTestResult::noOfExecutedTests() const
+{
+ return p.testCase()->noOfExecutedTests();
+}
+
+/*!
+ Returns the number of detected failures.
+*/
+uint QTestResult::noOfFailures() const
+{
+ return p.testCase()->totalFailed();
+}
+/*!
+ Returns the number of detected passes.
+*/
+uint QTestResult::noOfPasses() const
+{
+ return p.testCase()->totalPassed();
+}
+
+/*!
+ Sets the name of the testcase that is currently being executed to \a testCaseName.
+ If \a verbose is set to TRUE all logging is done in verbose mode, if set to FALSE then
+ build results are cached and are only shown when the build actually fails.
+ The \a build parameter determines what information is shown for the testcase, i.e if
+ \a build is TRUE the "build time" is shown and if FALSE then the "execution time" is shown, etc.
+*/
+void QTestResult::setCurrentTestCase( const QString &testCaseName, bool verbose, bool build )
+{
+ p.testCase()->setName( testCaseName, verbose, build );
+}
+
+/*!
+ Returns the name of the current testcase.
+*/
+QString QTestResult::curTestCase()
+{
+ return p.testCase()->name();
+}
+
+/*!
+ Sets the name of the testfunction that is currently being executed to \a testFunc.
+*/
+void QTestResult::setCurrentTestFunction( const QString &testFunc )
+{
+ p.testCase()->setCurrentTestFunction( testFunc );
+}
+
+/*!
+ Sets the name of the testdata that is currently being used to \a dataTag.
+*/
+void QTestResult::setCurrentTestData( const QString &dataTag )
+{
+ p.testCase()->setCurrentTestData( dataTag );
+}
+
+/*!
+ Returns the current data index, i.e. the zero based index of the dataset that is
+ currently being executed.
+*/
+int QTestResult::curDataIndex() const
+{
+ return p.testCase()->curDataIndex();
+}
+
+/*!
+ Sets the current testlocation to \a loc.
+*/
+void QTestResult::setCurrentTestLocation(TestLocation loc)
+{
+ p.testCase()->setCurrentTestLocation( loc );
+}
+
+/*!
+ Returns the current testlocation.
+*/
+QTestResult::TestLocation QTestResult::currentTestLocation()
+{
+ return p.testCase()->currentTestLocation();
+}
+
+/*!
+ Informs the testresult whether a retest is busy or not. If \a busy is set to TRUE then
+ logged failures are ignored (not logged).
+*/
+void QTestResult::retest( bool busy )
+{
+ p.testCase()->retest( busy );
+}
+
+/*!
+ \internal
+ Formats a testresult message using \a resType, \a result, \a dataTag,
+ \a file, \a line and \a comment and appends the
+ message to the logging file. If no logging file has been specified the
+ message will be send to stdout.
+ The \a resType specifies the type of the result e.g. TestFailure,
+ TestPass, CompileFailure, etc.
+ The \a result is the string that describes the result e.g. 'Expected and actual
+ values are not the same'.
+ The \a dataTag is the unique string that is associated with the dataset that was
+ in use when the result was logged.
+ The \a file and \a line describe the location in the testcase where the problem
+ occurred.
+ The \a comment is an additional string that only contains information in special
+ cases like when an expected failure occurs.
+ The \a halt variable finally stops the execution of the testfunction if it's value
+ is set to TRUE.
+*/
+void QTestResult::addResult( const TestResult result,
+ const QString &reason,
+ const QString &file,
+ int line,
+ const QString &comment )
+{
+ p.testCase()->addResult( TRUE, result, reason, file, line, comment );
+}
+
+/*!
+ Decodes \a keyString and uses the decoded information to add a result.
+*/
+
+void QTestResult::addResult( const QString &keyString )
+{
+ QTestResultRecord rec( keyString );
+ p.testCase()->addResult( TRUE, rec.result, rec.reason, rec.file, rec.line, rec.comment );
+}
+
+/*!
+ Writes \a dbgtxt to the debugging log output.
+*/
+void QTestResult::debugLog( const QString &dbgtxt )
+{
+ p.testCase()->addResult( TRUE, QTest::QDebug, dbgtxt );
+}
+
+/*!
+ Triggers the testresult to expect a failure when the testfunction is executed.
+ The \a dataIndex specifies the index to the testdata for which the failure is expected.
+ A value of -1 means 'all' applied testdata, a value of 0 or higher references a specific dataset.
+ If the testfunction is executed with the specified dataIndex it 'should' throw a failure. If that
+ happens the testresult will record the failure as an expected failure and will add the specified
+ \a comment to the result to give a clue as to why this failure was expected. If the testfunction
+ doesn't fail (e.g. it passes) this will be recorded as an unexpected pass.
+ The \a mode can be set to Abort or Continue. Abort means the testfunction will abort and Continue
+ obviously means the testfunction will continue.
+*/
+void QTestResult::setExpectedFailure( int dataIndex, QString comment, TestFailMode mode )
+{
+ p.testCase()->setExpectedFailure( dataIndex, comment, mode );
+}
+
+/*!
+ Returns the current datatag for the testfunction being executed.
+*/
+QString QTestResult::curDataTag()
+{
+ return p.testCase()->curDataTag();
+}
+
+/*!
+ \internal
+*/
+void QTestResult::addMakeResult( const QString &result )
+{
+ p.testCase()->addResult( TRUE, QTest::MakeRes, result );
+}
+
+/*!
+ Returns the current testfunction name. If \a fullName is TRUE a fully qualified
+ name of testcase::testfunc is returned.
+*/
+QString QTestResult::curTestFunc( bool fullName ) const
+{
+ return p.testCase()->curFunctionName( fullName );
+}
+
+/*!
+ Adds a success line (PASS) with the specified \a text to the testresult.
+*/
+void QTestResult::addSuccess( const QString &text, const QString &file, int line )
+{
+ p.testCase()->addResult( TRUE, QTest::PassTest, text, file, line );
+}
+
+/*!
+ \internal
+ Returns a pointer to the current testlog instance.
+*/
+QTestLog* QTestResult::testLog()
+{
+ return p.testCase()->testLog();
+}
+
+/*!
+ Signals the logging module that the specified \a line in \a fileName is
+ about to be executed. When an error occurs, the given fileName and line
+ number are used to report the error.
+*/
+
+bool QTestResult::enterCheckPoint( const QString &fileName, int line )
+{
+ // Not using these parameters at the moment. But the intention is that I will use them in future
+ Q_UNUSED( fileName );
+ Q_UNUSED( line );
+
+ return !checkPointError( 0 );
+}
+
+/*!
+ Returns TRUE and a \a reason if an error has occurred since the last call
+ to enterCheckPoint.
+*/
+
+bool QTestResult::checkPointError( QString *reason )
+{
+ if (p.testCase()->curTestFailed() || p.testCase()->curTestSkipped()) {
+ if (reason != 0)
+ *reason = "Sorry, i'll have to figure out what the reason was";
+ return TRUE;
+ }
+ return FALSE;
+}
+
+/*!
+ Returns TRUE if the current test has passed, and \a withSkips returns TRUE if one
+ or more of the datasets where skipped.
+*/
+
+bool QTestResult::currentTestPassed( bool &withSkips ) const
+{
+ withSkips = p.testCase()->curTestSkipped();
+ return p.testCase()->curTestPassed();
+}
+
+/*!
+ Returns the result string that is associated with the given \a res value.
+*/
+
+QString QTestResult::resultToStr( QTest::TestResult res )
+{
+ QString result;
+
+ switch (res)
+ {
+ case QTest::PassCompile:
+ result = "PASS ";
+ break;
+ case QTest::PassSelf:
+ result = "PASS ";
+ break;
+ case QTest::PassTest:
+ result = "PASS ";
+ break;
+ case QTest::FailCompile:
+ result = "FAIL! ";
+ break;
+ case QTest::FailSelf:
+ result = "FAIL! ";
+ break;
+ case QTest::FailTest:
+ result = "FAIL! ";
+ break;
+ case QTest::PassUnexpected:
+ result = "XPASS ";
+ break;
+ case QTest::FailExpected:
+ result = "XFAIL ";
+ break;
+ case QTest::SkipAll:
+ case QTest::SkipSingle:
+ result = "SKIP ";
+ break;
+ case QTest::Warn:
+ result = "WARNING";
+ break;
+ case QTest::__Error:
+ result = "ERROR ";
+ break;
+ case QTest::MakeRes:
+ result = "$";
+ break;
+ case QTest::ScriptRes:
+ result = "$";
+ break;
+ case QTest::Note:
+ result = "NOTE ";
+ break;
+ case QTest::Totals:
+ result = "TOTALS ";
+ break;
+ case QTest::Msg:
+ result = "MSG ";
+ break;
+ case QTest::QDebug:
+ result = "QDEBUG ";
+ break;
+ case QTest::QFatal:
+ result = "QFATAL ";
+ break;
+ case QTest::InternFatal:
+ result = "FATAL! ";
+ break;
+ case QTest::QWarning:
+ result = "QWARN ";
+ break;
+ case QTest::DetectedConfiguration:
+ result = "CONFIG ";
+ break;
+ case QTest::DetectedStyle:
+ result = "STYLE ";
+ break;
+ case QTest::Printf:
+ result = "PRINTF ";
+ break;
+ case QTest::IgnoreResult:
+ result = "IGNORE ";
+ break;
+ case QTest::RemoteIgnoreResult:
+ result = "IGNORE2";
+ break;
+ case QTest::StartingTestcase:
+ case QTest::StartingBuild:
+ case QTest::StartingScript:
+ case QTest::FinishedTestcase:
+ case QTest::FinishedBuild:
+ case QTest::FinishedScript:
+ result = "NOTE ";
+ break;
+ case QTest::TestFunction_:
+ result = "TF ";
+ break;
+ case QTest::TestState:
+ result = "STATE ";
+ break;
+ case QTest::Performance:
+ result = "PERFORM";
+ break;
+ default:
+ result = "???? ";
+ break;
+ }
+ return result;
+}
+
+/*!
+ Returns the learn mode of the testcase.
+*/
+
+QTest::LearnMode QTestResult::learnMode()
+{
+ return QTestSettings::learnMode();
+}
+
+/*!
+ Returns TRUE if the testcase is running in debug mode (as set on the command line).
+*/
+
+bool QTestResult::debugMode() const
+{
+ return QTestSettings::debugMode();
+}
+
+/*!
+ Returns the current configuration.
+*/
+
+QString QTestResult::curConfiguration()
+{
+ return QTestSettings::curConfiguration();
+}
+
+/*!
+ Sets the currently used configuration to \a hostName, \a OSName, \a config and \a makeSpec.
+*/
+
+void QTestResult::setConfiguration( const QString &hostName,
+ const QString &OSName,
+ const QString &config,
+ const QString &makeSpec )
+{
+ QTestSettings::setConfiguration( hostName, OSName, config, makeSpec );
+ addResult( QTest::DetectedConfiguration,
+ QTestSettings::curConfiguration(),
+ "",
+ -1,
+ "" );
+}
+
+/*!
+ Returns TRUE of the current test failed.
+*/
+
+bool QTestResult::currentTestFailed() const
+{
+ return p.testCase()->curTestFailed();
+}
+
+#ifdef QTEST_SUPPORT
+
+bool QTestResult::loadResult( const QString &logging_file, bool &isConsoleApp )
+{
+ isConsoleApp = FALSE;
+
+ QDir D;
+ if (!D.exists( logging_file )) {
+ return FALSE;
+ }
+
+ QFile F( logging_file );
+ if (!F.open(QFile::ReadOnly)) {
+ addFailure( "Internal error: Couldn't open logresults", "", -1 );
+ return FALSE;
+ }
+
+ QTextStream ds( &F );
+ QString Snext = "";
+ QString S = "";
+ while (!ds.atEnd()) {
+
+ S = "";
+ while (!ds.atEnd()) {
+ S += Snext;
+ Snext = ds.readLine();
+ if (!Snext.startsWith( "<RESULT>" )) {
+ // this line is part from the previous line
+ if (S != "")
+ S += "\n";
+ S += Snext;
+ Snext = "";
+ } else {
+ if (S != "")
+ break;
+ }
+ }
+
+ if (S != "") {
+ QTestResultRecord rec;
+ if (rec.decode( S )) {
+ if (rec.result == QTest::DetectedStyle) {
+ isConsoleApp = rec.reason.startsWith( "Console" );
+ }
+
+ processLogResult( S );
+ }
+ }
+ }
+
+ return TRUE;
+}
+
+bool equalConfigs( const QString &c1, const QString &c2 )
+{
+ QStringList cl1 = c1.split( "," );
+ QStringList cl2 = c2.split( "," );
+
+ if (cl1.count() < 1 || cl2.count() < 1)
+ return FALSE;
+ if (cl1[0] != cl2[0])
+ return FALSE;
+
+ if (cl1.count() < 2 || cl2.count() < 2)
+ return FALSE;
+ if (cl1[1] != cl2[1])
+ return FALSE;
+
+ if (cl1.count() < 3 || cl2.count() < 3)
+ return FALSE;
+ QStringList cl3 = cl1[2].split( " " );
+ QStringList cl4 = cl2[2].split( " " );
+ cl3.sort();
+ cl4.sort();
+ int cl3_count = 0;
+ int cl4_count = 0;
+ while (cl3_count < cl3.count() || cl4_count < cl4.count()) {
+ QString tmp_c1 = cl3[cl3_count];
+ QString tmp_c2 = cl4[cl4_count];
+
+ if (tmp_c1 != tmp_c2) {
+ if (tmp_c1 == "-no-xft") {
+ cl4_count--;
+ } else if (tmp_c2 == "-no-xft") {
+ cl3_count--;
+ } else {
+// qDebug( "cl3 = " + tmp_c1 + ", cl4 = " + tmp_c2);
+ return FALSE;
+ }
+ }
+ cl3_count++;
+ cl4_count++;
+ }
+ return TRUE;
+}
+
+void QTestResult::processLogResult( const QString &S )
+{
+ QTestResultRecord rec;
+ if (!rec.decode( S )) {
+ return;
+ }
+
+ if (rec.testCase != curTestCase()) {
+ setCurrentTestCase( rec.testCase );
+ } else {
+ if (curTestFunc(FALSE) != rec.testFunc) {
+ if (!curTestFunc(FALSE).isEmpty())
+ setCurrentTestFunction( "" );
+ setCurrentTestFunction( rec.testFunc );
+ }
+ QString my_data_tag;
+ if ( rec.dataTag == "") {
+ my_data_tag = "NO_TESTDATA";
+ } else {
+ my_data_tag = rec.dataTag;
+ }
+ if (my_data_tag != curDataTag())
+ setCurrentTestData( my_data_tag );
+ }
+
+ switch (rec.result)
+ {
+ case QTest::ExpectFailure:
+ {
+ int dataIndex = rec.line;
+ int mode = rec.comment.toInt();
+ setExpectedFailure( dataIndex, rec.reason, (QTest::TestFailMode)mode );
+ break;
+ }
+ case QTest::IgnoreResult:
+ {
+ int ignore_res = rec.line;
+ int exact_match = rec.comment.toInt();
+ ignoreResult( (QTest::TestResult)ignore_res, rec.reason, exact_match == 1 );
+ break;
+ }
+ case QTest::RemoteIgnoreResult:
+ {
+ int ignore_res = rec.line;
+ int exact_match = rec.comment.toInt();
+ remoteIgnoreResult( (QTest::TestResult)ignore_res, rec.reason, exact_match == 1 );
+ break;
+ }
+ case QTest::Retest:
+ {
+ int busy = rec.comment.toInt();
+ retest( busy == 1 );
+ break;
+ }
+ case QTest::Note:
+ {
+ if (!rec.reason.startsWith( "Testcase took " ) &&
+ !rec.reason.startsWith( "Started at" ))
+ addResult( S );
+ break;
+ }
+ case QTest::StartingTestcase:
+ case QTest::FinishedTestcase:
+ case QTest::StartingBuild:
+ case QTest::FinishedBuild:
+ case QTest::StartingScript:
+ case QTest::FinishedScript:
+ case QTest::Totals:
+ case QTest::TestFunction_:
+ {
+ // discard result
+ break;
+ }
+ case QTest::DetectedConfiguration:
+ {
+ if (curConfiguration() == "") {
+ // no config detected yet (which is pretty unlikely to happen)
+ addResult( S );
+// addLogging( S, FALSE );
+ } else {
+ if (!equalConfigs( curConfiguration(), rec.reason)) {
+ addWarning( "Configuration mismatch: \n actual : '" + rec.reason + "'\n expected: '" + curConfiguration() + "'" );
+ } else {
+ // just ignore the reported configuration.
+ // We already know and have logged the config.
+ // This is the only silent case and should be the normal behaviour
+ }
+ }
+ break;
+ }
+ default:
+ {
+ addResult( S );
+ }
+ }
+}
+#endif
+
+// -----------------------------------------------------------------------
+
+QTestResultSuite::QTestResultSuite()
+{
+ test_case = new QTestResultTestCase;
+}
+
+QTestResultSuite::~QTestResultSuite()
+{
+ delete test_case;
+ test_case = 0;
+}
+
+QTestResultTestCase* QTestResultSuite::testCase()
+{
+ return test_case;
+}
+
+// ----------------------------------------------------------------
+
+QTestResultRecord::QTestResultRecord()
+{
+}
+
+QTestResultRecord::QTestResultRecord( const QString &keyString )
+{
+ decode( keyString );
+}
+
+QTestResultRecord::QTestResultRecord( QTest::TestResult result, const QString &test, const QString &reason, const QString &dataset, const QString &file, const QString &line, const QString &comment )
+{
+ this->result = result;
+ int pos = test.indexOf( "::" );
+ if (pos >= 0) {
+ testCase = test.left(pos);
+ testFunc = test.mid(pos+2);
+ } else {
+ testCase = test;
+ testFunc = "";
+ }
+ this->reason = reason;
+ this->dataTag = dataset;
+ this->file = file;
+ this->line = line.toInt();
+ this->comment = comment;
+}
+
+QString QTestResultRecord::keyString()
+{
+ QKeyString key_string;
+ key_string.addKey( "RESULT", result );
+ QString test = testCase;
+ if (!testFunc.isEmpty())
+ test += "::" + testFunc;
+ key_string.addKey( "TEST", test );
+ if (reason != "")
+ key_string.addKey( "REASON", reason );
+ if (dataTag != "")
+ key_string.addKey( "DATATAG", dataTag );
+ if (file != "")
+ key_string.addKey( "FILE", file );
+ if (line != -1)
+ key_string.addKey( "LINE", line );
+ if (comment != "")
+ key_string.addKey( "COMMENT", comment );
+
+ return key_string;
+}
+
+QString QTestResultRecord::testName()
+{
+ QString ret = testCase;
+ if (testFunc != "")
+ {
+ ret+= "::";
+ ret += testFunc;
+ }
+ return ret;
+}
+
+bool QTestResultRecord::decode( const QString &logText )
+{
+ QKeyString key_string = logText;
+
+ QString test;
+ key_string.findKey( "TEST", test, TRUE );
+ int pos = test.indexOf( "::" );
+ if (pos >= 0) {
+ testCase = test.left(pos);
+ testFunc = test.mid(pos+2);
+ } else {
+ testCase = test;
+ testFunc = "";
+ }
+
+ key_string.findKey( "DATATAG", dataTag, TRUE );
+
+ int i;
+ if (!key_string.findKey( "RESULT", i ))
+ return FALSE;
+ result = (QTest::TestResult)i;
+
+ key_string.findKey( "REASON", reason );
+
+ key_string.findKey( "COMMENT", comment );
+ key_string.findKey( "FILE", file );
+ QString sLine;
+ if (!key_string.findKey( "LINE", sLine ))
+ line = -1;
+ else
+ line = sLine.toInt();
+ return TRUE;
+}
+
+bool QTestResultRecord::passed()
+{
+ if (result == QTest::PassSelf ||
+ result == QTest::PassSelf ||
+ result == QTest::PassCompile ||
+ result == QTest::PassTest ||
+ result == QTest::PassScript )
+ return TRUE;
+
+ return FALSE;
+}
+
+// ----------------------------------------------------------------
+
+// The max number of warnings we want to log per execution of a testfunction/dataset
+#define MAX_WARNINGS_PER_FUNCTION 100
+
+QTestResultTestBase::QTestResultTestBase( QTestResultTestCase *testCase, QObject *parent ) : QObject( parent )
+{
+ warning_count = 0;
+ test_case = testCase;
+ last_result = "";
+ test_result = QTest::Invalid;
+ retest_busy = FALSE;
+ skip_all = FALSE;
+}
+
+QTestResultTestBase::~QTestResultTestBase()
+{
+}
+
+QTestResultTestCase* QTestResultTestBase::curTestCase()
+{
+ return test_case;
+}
+
+void QTestResultTestBase::setRetest( bool busy )
+{
+ retest_busy = busy;
+ test_result = QTest::Invalid;
+ if (testResult.testLog()->rawLoggingMode()) {
+ appendResult( TRUE, QTest::Retest, "", "", -1, QString( "%1" ).arg( busy ) );
+ }
+}
+
+void QTestResultTestBase::resetResult()
+{
+ retest_busy = FALSE;
+ test_result = QTest::Invalid;
+}
+
+QTest::TestResult QTestResultTestBase::result() const
+{
+ return test_result;
+}
+
+void QTestResultTestBase::setResult( QTest::TestResult res )
+{
+ // first filter out 'pseudo' results
+ if (res != QTest::PassSelf &&
+ res != QTest::PassCompile &&
+ res != QTest::PassTest &&
+ res != QTest::PassScript &&
+ res != QTest::PassUnexpected &&
+ res != QTest::SkipAll &&
+ res != QTest::SkipSingle &&
+ res != QTest::FailSelf &&
+ res != QTest::FailCompile &&
+ res != QTest::FailTest &&
+ res != QTest::FailExpected &&
+ res != QTest::FailScript &&
+ res != QTest::QFatal &&
+ res != QTest::__Error &&
+ res != QTest::InternFatal)
+ return;
+
+ // a result can go from unknown to passed/skipped/failed
+ // and from passed to skipped/failed
+ if (test_result == QTest::Invalid ||
+ test_result == QTest::PassSelf ||
+ test_result == QTest::PassCompile ||
+ test_result == QTest::PassUnexpected ||
+ test_result == QTest::PassTest ||
+ test_result == QTest::PassScript )
+ test_result = res;
+}
+
+void QTestResultTestBase::appendResult( bool spontaneous,
+ QTest::TestResult result,
+ const QString &reason,
+ const QString &file,
+ int line,
+ const QString &comment )
+{
+ QString sLine;
+ sLine.sprintf("%d",line);
+ QTestResultRecord rec( result, test_case->curFunctionName( TRUE ), reason, test_case->curDataTag(), file, sLine, comment );
+
+ if (rec.result == QTest::QWarning) {
+ if ( warning_count < MAX_WARNINGS_PER_FUNCTION ) {
+ warning_count++;
+ } else if ( warning_count == MAX_WARNINGS_PER_FUNCTION ) {
+ warning_count++; // we only want the message once.
+ rec.reason = "Max amount of warnings are logged, further warnings will be skipped";
+ } else {
+ // The result is skipped (which is what this is all about)
+ return;
+ }
+ }
+
+#ifndef QTEST_SUPPORT
+ if ( spontaneous ) {
+ QTestRemote remote;
+ remote.postMessage( "RAW_RESULT", rec.keyString() );
+ }
+#endif
+
+ // filter out equal (repeating) messages
+ // but let qDebug and qFatal pass unfiltered
+ if (rec.result != QTest::QDebug &&
+ rec.result != QTest::QFatal &&
+ rec.result != QTest::InternFatal &&
+ (rec.keyString() == last_result) ) {
+ return;
+ }
+
+ if ( rec.result == QTest::PassTest ) {
+ QString comment;
+ bool abort;
+ if (expected_failures.isFailExpected( test_case->curDataIndex(), comment, abort, TRUE )) {
+ appendResult( FALSE, QTest::PassUnexpected, "Expected a failure, but test passed instead", rec.file, rec.line, comment );
+ return;
+ }
+ }
+
+ if ( rec.result == QTest::FailTest ) {
+ QString comment;
+ bool abort;
+ if (expected_failures.isFailExpected( test_case->curDataIndex(), comment, abort, TRUE )) {
+ if (local_ignores.mustIgnoreResult( QTest::FailExpected, comment ) ) {
+ // append a pass so that we know that we have successfully tested something
+ appendResult( FALSE, QTest::PassTest, "" );
+ return;
+ } else {
+ // append a new failure and ignore the current one
+ appendResult( FALSE, QTest::FailExpected, comment, rec.file, rec.line, comment );
+ return;
+ }
+ }
+ }
+
+ if ( rec.result == QTest::IgnoreResult ||
+ rec.result == QTest::RemoteIgnoreResult ||
+ rec.result == QTest::ExpectFailure ) {
+ return;
+ }
+
+ if (spontaneous && local_ignores.mustIgnoreResult( rec.result, rec.reason ) ) {
+ // append a pass so that we know that we have successfully tested something
+ appendResult( FALSE, QTest::PassTest, "" );
+ return;
+ }
+
+ if (remote_ignores.mustIgnoreResult( rec.result, rec.reason ) ) {
+ // append a pass so that we know that we have successfully tested something
+ appendResult( FALSE, QTest::PassTest, "" );
+ return;
+ }
+
+ setResult( rec.result );
+
+ if (!retest_busy)
+ last_result = rec.keyString();
+
+
+ if ( rec.result == QTest::SkipAll && skip_all ) {
+ // don't log the same skip a second time.
+ return;
+ }
+
+ if (rec.result == QTest::QDebug && !QTestSettings::showQDebug())
+ return;
+
+ if (rec.result == QTest::Performance && !QTestSettings::showPerformance())
+ return;
+
+ if (QTestSettings::briefMode()) {
+ if (rec.result == QTest::Warn ||
+ rec.result == QTest::Msg ||
+ rec.result == QTest::Note ||
+ rec.result == QTest::MakeRes ||
+ rec.result == QTest::ScriptRes ||
+ rec.result == QTest::SkipSingle ||
+ rec.result == QTest::SkipAll ||
+ rec.result == QTest::Printf )
+ return;
+ }
+
+ if (rec.passed()) {
+//#ifndef QTEST_SUPPORT
+ if (rec.line >= -1)
+ return;
+//#endif
+ rec.file = "";
+ rec.line = -1;
+ }
+
+ // Don't log anything if we are re-testing the same testfunction multiple times.
+ if (retest_busy) {
+ if (rec.passed())
+ retest_busy = FALSE;
+ }
+
+ if (!retest_busy) {
+ test_case->writeLog( rec );
+ }
+}
+
+void QTestResultTestBase::ignoreResult( bool remote, const QTest::TestResult res, const QString &reason, bool exactMatch )
+{
+ if (remote) {
+#ifndef QTEST_SUPPORT
+ appendResult( TRUE, QTest::RemoteIgnoreResult, reason, "", (int)res, QString( "%1" ).arg( exactMatch ) );
+#else
+ remote_ignores.ignoreResult( res, reason, exactMatch );
+#endif
+ } else {
+ appendResult( TRUE, QTest::IgnoreResult, reason, "", (int)res, QString( "%1" ).arg( exactMatch ) );
+ local_ignores.ignoreResult( res, reason, exactMatch );
+ }
+}
+
+bool QTestResultTestBase::resetIgnoreResult( bool remote, QString &errors )
+{
+ if (remote)
+ return remote_ignores.resetIgnoreResult( errors );
+ else
+ return local_ignores.resetIgnoreResult( errors );
+}
+
+IgnoreResults::IgnoreResults()
+{
+ ignore_result.clear();
+}
+
+IgnoreResults::~IgnoreResults()
+{
+}
+
+void IgnoreResults::ignoreResult( const QTest::TestResult res, const QString &reason, bool exactMatch )
+{
+# ifndef QT_DEBUG
+ // Warnings and Debugs are not output in release versions anymore
+ if ( res == QTest::QWarning || res == QTest::QDebug )
+ return;
+# endif
+
+ QKeyString k;
+ k.addKey( "RES", res );
+ k.addKey( "TXT", reason );
+ int count = 0;
+ k.addKey( "COUNT", count );
+ if (exactMatch)
+ k.addKey( "EXACT", QString("1") );
+ ignore_result.append( k );
+}
+
+bool IgnoreResults::mustIgnoreResult( QTest::TestResult res, const QString &reason )
+{
+ int index;
+ if (!getIgnoreResultIndex( res, reason, index )) {
+ return FALSE;
+ }
+
+ QString S = ignore_result[index];
+ QKeyString r(S);
+ int count;
+ r.findKey( "COUNT", count );
+ count++;
+ r.setKey( "COUNT", count );
+ ignore_result.removeAll( S );
+ ignore_result.append( r );
+ return TRUE;
+}
+
+bool IgnoreResults::resetIgnoreResult( QString &errors )
+{
+ if (ignore_result.count() == 0) {
+ return FALSE;
+ }
+
+ bool retValue = FALSE;
+
+ int i;
+ // first we check how much results we have missed
+ for (i=0; i<(int)(ignore_result.count()); i++) {
+ QKeyString k( ignore_result[i] );
+ int count;
+ k.findKey( "COUNT", count );
+ if (count == 0) {
+ retValue = TRUE;
+ }
+ }
+
+ // next output all the results we missed as a failure
+ // and halt after the last failure.
+ errors = "Ignore result failures:";
+ if (retValue == TRUE) {
+ for (i=0; i<(int)(ignore_result.count()); i++) {
+ QKeyString k( ignore_result[i] );
+ QString reason;
+ QString res;
+ int iRes;
+ k.findKey( "RES", iRes );
+ res = QTestResult::resultToStr( (QTest::TestResult)iRes );
+ k.findKey( "TXT", reason );
+ int count;
+ k.findKey( "COUNT", count );
+ QString exact;
+ k.findKey( "EXACT", exact );
+ bool exact_match = (exact == "1");
+ if (count == 0) {
+ res = res.simplified();
+ QString prefix = " that starts with text: '";
+ if (exact_match)
+ prefix = " that matches text: '";
+
+ errors += "\n Did not catch a " + res + prefix + reason + "'.";
+ }
+ }
+ }
+ ignore_result.clear();
+ return retValue;
+}
+
+bool IgnoreResults::getIgnoreResultIndex( QTest::TestResult res, const QString &reason, int &index )
+{
+ index = -1;
+
+ if ( ignore_result.count() == 0) {
+ return FALSE;
+ }
+
+ for (int i=0; i<(int)(ignore_result.count()); i++) {
+ QKeyString SS(ignore_result[i]);
+ int ires;
+ SS.findKey( "RES", ires );
+ QString ireason;
+ SS.findKey( "TXT", ireason );
+ QString exact;
+ SS.findKey( "EXACT", exact );
+ bool exact_match = (exact == "1");
+
+ if (ires == res &&
+ ( (!exact_match && reason.startsWith(ireason)) ||
+ (reason == ireason))) {
+ index = i;
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
+
+void QTestResultTestBase::setExpectedFailure( int dataIndex, QString reason, QTest::TestFailMode mode )
+{
+ appendResult( TRUE, QTest::ExpectFailure, reason, "", dataIndex, QString( "%1" ).arg( mode ) );
+ expected_failures.setFailure( dataIndex, reason, mode );
+}
+
+ExpectedFailures::ExpectedFailures()
+{
+ first_expected_fail = 0;
+}
+
+ExpectedFailures::~ExpectedFailures()
+{
+ clear();
+}
+
+void ExpectedFailures::clear()
+{
+ ExpectedFailRec *next;
+ ExpectedFailRec *cur;
+ cur = first_expected_fail;
+ while (cur != 0) {
+ next = cur->next;
+ delete cur;
+ cur = next;
+ }
+ first_expected_fail = 0;
+}
+
+uint ExpectedFailures::count()
+{
+ uint count = 0;
+ ExpectedFailRec *cur;
+ cur = first_expected_fail;
+ while (cur != 0) {
+ count++;
+ cur = cur->next;
+ }
+ return count;
+}
+
+bool ExpectedFailures::getFailure( uint index, ExpectedFailRec *&rec )
+{
+ uint count = 0;
+ rec = first_expected_fail;
+ while (rec != 0) {
+ if (count == index)
+ return TRUE;
+ count++;
+ rec = rec->next;
+ }
+ rec = 0;
+ return FALSE;
+}
+
+/*!
+ Returns TRUE if the currently executed testfunction is expected to fail when the testdata
+ referenced to by \a dataIndex is applied to the function.
+ If the fail is expected, e.g. the function returns TRUE, the \a comment returns a string that
+ returns information on why the fail is expected. This information is entered in the expectFail
+ function call that is used to set up the expected failure.
+
+ If \a reset is TRUE, the expected failures will be reset after the first call to a verify,
+ compare or test, e.g. the next call to a verify, compare or test function will not result in
+ an expected failure anymore.
+
+ The \a abort parameter returns TRUE if the fail was expected and the execution of the function
+ should be aborted.
+*/
+
+bool ExpectedFailures::isFailExpected( int dataIndex, QString &comment, bool &abort, bool reset )
+{
+ if (dataIndex == -1)
+ return FALSE;
+
+ if (count() == 0)
+ return FALSE;
+
+ // return a TRUE if we expect a fail for every testdata
+ ExpectedFailRec *rec;
+ if (getFailure( 0, rec ) && rec->index == -1) {
+ comment = rec->comment;
+ abort = rec->mode == QTest::Abort;
+ if ( reset )
+ clear();
+ return TRUE;
+ }
+
+ for (uint i=0; i<count(); i++) {
+ if (getFailure( i, rec ) && rec->index == dataIndex) {
+ comment = rec->comment;
+ abort = rec->mode == QTest::Abort;
+ if ( reset )
+ clear();
+ return TRUE;
+ }
+ }
+
+ if ( reset )
+ clear();
+ return FALSE;
+}
+
+void ExpectedFailures::setFailure( int dataIndex, QString comment, QTest::TestFailMode mode )
+{
+ if (dataIndex == -1) {
+ clear();
+ append( dataIndex, comment, mode );
+ } else {
+ ExpectedFailRec *rec;
+ if (count() == 1 &&
+ getFailure( 0, rec ) &&
+ rec->index == -1)
+ return;
+ append( dataIndex, comment, mode );
+ }
+}
+
+void ExpectedFailures::append( int index, QString comment, QTest::TestFailMode mode )
+{
+ ExpectedFailRec *tmp;
+ tmp = new ExpectedFailRec;
+ tmp->index = index;
+ tmp->comment = comment;
+ tmp->mode = mode;
+ tmp->next = 0;
+
+ if (first_expected_fail == 0)
+ first_expected_fail = tmp;
+ else {
+ ExpectedFailRec *cur;
+ cur = first_expected_fail;
+ while (cur) {
+ if (cur->next == 0) {
+ cur->next = tmp;
+ return;
+ }
+ cur = cur->next;
+ }
+ }
+}
+
+// -------------------------------------------------------------------
+
+QTestResultTestCase::QTestResultTestCase( const QString &name ) : QTestResultTestBase( this, 0 )
+{
+ m_name = name;
+ m_first = 0;
+ cur_func = 0;
+ build_mode = FALSE;
+}
+
+QTestResultTestCase::QTestResultTestCase() : QTestResultTestBase( this, 0 )
+{
+ m_name = "";
+ m_first = 0;
+ cur_func = 0;
+ build_mode = FALSE;
+}
+
+QTestResultTestCase::~QTestResultTestCase()
+{
+ delete m_first;
+ m_first = 0;
+}
+
+QTestLog* QTestResultTestCase::testLog()
+{
+ return &test_log;
+}
+
+void QTestResultTestCase::writeLog( QTestResultRecord rec )
+{
+ test_log.writeLog( rec );
+}
+
+void QTestResultTestCase::setName( const QString &name, bool verbose, bool build )
+{
+ if (name.isEmpty()) {
+ if (m_name.isEmpty())
+ return;
+
+ if (cur_func != 0)
+ setCurrentTestFunction( "" );
+
+ if (!testResult.testLog()->rawLoggingMode()) {
+ QString errors;
+ if (local_ignores.resetIgnoreResult( errors ))
+ addResult( FALSE, QTest::FailTest, errors );
+ if (remote_ignores.resetIgnoreResult( errors ))
+ addResult( FALSE, QTest::FailTest, errors );
+
+ if (build_mode) {
+// FIXME: this fails when building qpe??
+// if (totalFailed() == 0 && totalPassed() == 0)
+// addResult( FALSE, QTest::FailTest, "Nothing is tested at all." );
+ } else {
+#ifndef QTEST_SUPPORT
+ if (totalTests() == 0)
+ addResult( FALSE, QTest::FailTest, "Nothing is tested at all." );
+#endif
+ }
+
+ if (!build_mode)
+ addResult( TRUE, QTest::Totals, QString("%1 passed, %2 failed, %3 skipped").arg(totalPassed()).arg(totalFailed()).arg(totalSkipped()));
+
+ QString txt = QString("Testcase took %1 ms to ").arg(timer.elapsed());
+ if (build_mode)
+ txt += "compile.";
+ else
+ txt += "execute.";
+ addResult( TRUE, QTest::Note, txt );
+ }
+
+ if (build_mode) {
+ addResult( TRUE, QTest::FinishedBuild, "", "", -1, "" );
+ } else {
+ addResult( TRUE, QTest::FinishedTestcase, "", "", -1, "" );
+ }
+
+ if (totalFailed() > 0) {
+ test_log.flushCachedResults();
+ } else {
+ test_log.cacheResults( FALSE );
+ }
+
+ m_name = name;
+ resetResult();
+ } else {
+ if (m_name == name) {
+ return; // current testcase is running already
+ } else if (!m_name.isEmpty() ) {
+ setName( "" ); // close a previous testcase
+ }
+ Q_ASSERT( curFunction() == 0 );
+
+ test_log.cacheResults( !verbose && !QTestSettings::verbose() );
+
+ m_name = name;
+
+ build_mode = build;
+ if (build) {
+ addResult( TRUE, QTest::StartingBuild, "", "", -1, "" );
+ } else {
+ addResult( TRUE, QTest::StartingTestcase, "", "", -1, "" );
+ }
+
+#ifndef QTEST_SUPPORT
+ //FIXME addResult( TRUE, QTest::DetectedStyle, QSystem::curStyle() + "-" + QSystem::screenInfo() );
+ //FIXME addResult( TRUE, QTest::Note, "Tested with QTest version: " QTEST_VERSION );
+#endif
+
+ QDateTime cur = QDateTime::currentDateTime();
+ addResult( TRUE, QTest::Note, "Started at: " + cur.toString() );
+ timer.start();
+ }
+
+ delete m_first;
+ m_first = 0;
+ cur_func = 0;
+}
+
+QString QTestResultTestCase::name()
+{
+ return m_name;
+}
+
+QString QTestResultTestCase::curFunctionName( bool fullName ) const
+{
+ QString S;
+ if (fullName) {
+ S = m_name;
+ if (cur_func != 0 && !cur_func->name().isEmpty())
+ S+= "::"+ cur_func->name();
+ } else {
+ if (cur_func != 0 && !cur_func->name().isEmpty())
+ S = cur_func->name();
+ }
+
+ return S;
+}
+
+QTestResultTestFunc* QTestResultTestCase::findFunction( const QString &funcName )
+{
+ QTestResultTestFunc *f = m_first;
+ while (f != 0) {
+ if (f->name() == funcName)
+ return f;
+ else
+ f = f->next();
+ }
+
+ return 0;
+}
+
+void QTestResultTestCase::setCurrentTestFunction( const QString &funcName )
+{
+ if (funcName.isEmpty()) {
+ if ( cur_func == 0 )
+ return;
+
+ if (cur_func->cur_data != 0)
+ cur_func->setCurrentTestData( "" );
+
+ if (!testResult.testLog()->rawLoggingMode()) {
+ QString errors;
+ if (cur_func->resetIgnoreResult( FALSE, errors ))
+ addResult( FALSE, QTest::FailTest, errors );
+ if (cur_func->resetIgnoreResult( TRUE, errors ))
+ addResult( FALSE, QTest::FailTest, errors );
+
+ if (!cur_func->hasFailures()) {
+ if (curDataCount() == curSkipCount() &&
+ curSkipCount() > 0) {
+ // don't show a PASS
+ } else {
+ QString S = "";
+ if (curSkipCount() > 0)
+ S = QString("Passed with %1 skipped tests.").arg( curSkipCount() );
+ appendResult( FALSE, QTest::PassTest, S, "", -2 );
+ }
+ }
+ }
+
+ // blow away the selftest if it was successfull
+ if (cur_func->name() == "SelfTest" && m_first != 0 && m_first->next() == 0) {
+ if (cur_func->passed( TRUE )) {
+ delete cur_func;
+ cur_func = 0;
+ m_first = 0;
+ }
+ }
+
+ cur_func = 0;
+ } else {
+ if (cur_func != 0 && cur_func->name() == funcName)
+ return;
+
+ QTestResultTestFunc *tmp = findFunction( funcName );
+ if (tmp != 0) {
+ cur_func = tmp;
+ return;
+ }
+
+ tmp = new QTestResultTestFunc( funcName, this );
+ if (m_first == 0) {
+ m_first = tmp;
+ } else {
+ QTestResultTestFunc *last = m_first;
+ while (last->next() != 0)
+ last = last->next();
+ last->setNext( tmp );
+ }
+ cur_func = tmp;
+ }
+}
+
+void QTestResultTestCase::setCurrentTestData( const QString &dataTag )
+{
+ if (cur_func != 0) {
+ cur_func->setCurrentTestData( dataTag );
+ }
+}
+
+QTestResultTestFunc* QTestResultTestCase::curFunction()
+{
+ return cur_func;
+}
+
+QTestResult::TestLocation QTestResultTestCase::currentTestLocation()
+{
+ return cur_test_location;
+}
+
+void QTestResultTestCase::setCurrentTestLocation( QTestResult::TestLocation loc )
+{
+ cur_test_location = loc;
+}
+
+
+uint QTestResultTestCase::totalTests() const
+{
+ uint count = 0;
+ QTestResultTestFunc *f = m_first;
+ while (f != 0) {
+ count++;
+ f = f->next();
+ }
+
+ return count;
+}
+
+uint QTestResultTestCase::noOfExecutedTests() const
+{
+ // for the moment lets assume these are the same
+ return totalTests();
+}
+
+int QTestResultTestCase::curDataIndex() const
+{
+ if (cur_func != 0) {
+ return cur_func->curDataIndex();
+ }
+ return -1;
+}
+
+QString QTestResultTestCase::curDataTag()
+{
+ if (cur_func != 0) {
+ return cur_func->curDataTag();
+ }
+ return "";
+}
+
+uint QTestResultTestCase::curDataCount() const
+{
+ if (cur_func != 0) {
+ return cur_func->dataCount();
+ }
+ return 0;
+}
+
+uint QTestResultTestCase::curSkipCount() const
+{
+ if (cur_func != 0) {
+ return cur_func->skipCount();
+ }
+ return 0;
+}
+
+bool QTestResultTestCase::curTestPassed()
+{
+ if (cur_func != 0) {
+ return cur_func->passed( FALSE );
+ }
+ return FALSE;
+}
+
+bool QTestResultTestCase::curTestVerified()
+{
+ if (cur_func != 0) {
+ return cur_func->verified( FALSE );
+ }
+ return FALSE;
+}
+
+bool QTestResultTestCase::curTestFailed()
+{
+ if (cur_func != 0) {
+ return cur_func->failed( TRUE );
+ } else {
+ if (result() == QTest::FailSelf ||
+ result() == QTest::FailCompile ||
+ result() == QTest::FailTest ||
+ result() == QTest::QFatal ||
+ result() == QTest::FailExpected ||
+ result() == QTest::FailScript )
+ return TRUE;
+ }
+ return FALSE;
+}
+
+bool QTestResultTestCase::curTestSkipped()
+{
+ if (cur_func != 0) {
+ return cur_func->skipped( TRUE );
+ }
+ return FALSE;
+}
+
+uint QTestResultTestCase::totalSkipped() const
+{
+ uint count = 0;
+ QTestResultTestFunc *f = m_first;
+ while (f != 0) {
+ count+= f->skipCount();
+ f = f->next();
+ }
+
+ return count;
+}
+
+uint QTestResultTestCase::totalPassed() const
+{
+ uint count = 0;
+
+ if (result() == QTest::PassSelf ||
+ result() == QTest::PassCompile ||
+ result() == QTest::PassTest ||
+ result() == QTest::PassScript)
+ count++;
+
+ QTestResultTestFunc *f = m_first;
+ while (f != 0) {
+ count+= f->passCount();
+ f = f->next();
+ }
+
+ return count;
+}
+
+uint QTestResultTestCase::totalFailed() const
+{
+ uint count = 0;
+
+ if (result() == QTest::FailSelf ||
+ result() == QTest::FailCompile ||
+ result() == QTest::FailTest ||
+ result() == QTest::FailScript ||
+ result() == QTest::QFatal ||
+ result() == QTest::FailExpected ||
+ result() == QTest::PassUnexpected)
+ count++;
+
+ QTestResultTestFunc *f = m_first;
+ while (f != 0) {
+ count+= f->failCount();
+ f = f->next();
+ }
+
+ return count;
+}
+
+void QTestResultTestCase::ignoreResult( bool remote, const QTest::TestResult res, const QString &reason, bool exactMatch )
+{
+ if (cur_func != 0)
+ cur_func->ignoreResult( remote, res, reason, exactMatch );
+ else
+ QTestResultTestBase::ignoreResult( remote, res, reason, exactMatch );
+}
+
+void QTestResultTestCase::setExpectedFailure( int dataIndex, QString comment, QTest::TestFailMode mode )
+{
+ if (cur_func != 0)
+ cur_func->setExpectedFailure( dataIndex, comment, mode );
+ else
+ QTestResultTestBase::setExpectedFailure( dataIndex, comment, mode );
+}
+
+void QTestResultTestCase::addResult( bool spontaneous,
+ QTest::TestResult result,
+ const QString &reason,
+ const QString &file,
+ int line,
+ const QString &comment )
+{
+ if (cur_func != 0)
+ cur_func->addResult( spontaneous, result, reason, file, line, comment );
+ else
+ appendResult( spontaneous, result, reason, file, line, comment );
+}
+
+void QTestResultTestCase::retest( bool busy )
+{
+ if (cur_func != 0)
+ cur_func->retest( busy );
+ else
+ setRetest( busy );
+}
+
+// ********************************************
+
+QTestResultTestFunc::QTestResultTestFunc( const QString &funcName, QTestResultTestCase *parent ) : QTestResultTestBase( parent, parent )
+{
+ func_name = funcName;
+ next_func = 0;
+ first_data = 0;
+ cur_data = 0;
+}
+
+QTestResultTestFunc::~QTestResultTestFunc()
+{
+ delete first_data;
+ first_data = 0;
+
+ delete next_func;
+ next_func = 0;
+}
+
+QString QTestResultTestFunc::name()
+{
+ return func_name;
+}
+
+QTestResultTestFunc *QTestResultTestFunc::next()
+{
+ return next_func;
+}
+
+void QTestResultTestFunc::setNext( QTestResultTestFunc *n )
+{
+ next_func = n;
+}
+
+void QTestResultTestFunc::setCurrentTestData( const QString &dataName )
+{
+ if (dataName.isEmpty()) {
+ if (cur_data == 0 )
+ return;
+
+ if (!cur_data->verified())
+ addResult( TRUE, QTest::FailTest, "Nothing is tested in this testfunction." );
+
+ if (!testResult.testLog()->rawLoggingMode()) {
+ QString errors;
+ if (cur_data->resetIgnoreResult( FALSE, errors ))
+ addResult( FALSE, QTest::FailTest, errors );
+ if (cur_data->resetIgnoreResult( TRUE, errors ))
+ addResult( FALSE, QTest::FailTest, errors );
+ }
+
+ cur_data = 0;
+ } else {
+ if (cur_data != 0 && cur_data->name() == dataName)
+ return;
+
+ QTestResultTestData *tmp = findData( dataName );
+ if (tmp != 0) {
+ cur_data = tmp;
+
+ // wipe the previous result if we want to redo the same test
+ if (cur_data->retest_busy)
+ cur_data->resetResult();
+// cur_data->retest( FALSE );
+
+ return;
+ }
+
+ tmp = new QTestResultTestData( dataName, skip_all, this );
+ if (first_data == 0) {
+ first_data = tmp;
+ } else {
+ QTestResultTestData *last = first_data;
+ while (last->next() != 0)
+ last = last->next();
+ last->setNext( tmp );
+ }
+ cur_data = tmp;
+ }
+}
+
+QTestResultTestData* QTestResultTestFunc::findData( const QString &dataName )
+{
+ QTestResultTestData *d = first_data;
+ while (d != 0) {
+ if (d->dataTag() == dataName)
+ return d;
+ else
+ d = d->next();
+ }
+
+ return 0;
+}
+
+uint QTestResultTestFunc::dataCount()
+{
+ uint count = 0;
+ QTestResultTestData *d = first_data;
+ while (d != 0) {
+ count++;
+ d = d->next();
+ }
+ return count;
+}
+
+uint QTestResultTestFunc::skipCount()
+{
+ uint count = 0;
+ QTestResultTestData *d = first_data;
+ while (d != 0) {
+ if (d->result() == QTest::SkipSingle ||
+ d->result() == QTest::SkipAll)
+ count++;
+ d = d->next();
+ }
+ if (count == 0 && skip_all)
+ count = 1;
+ return count;
+}
+
+uint QTestResultTestFunc::failCount()
+{
+ uint count = 0;
+ QTestResultTestData *d = first_data;
+ while (d != 0) {
+ if (d->result() == QTest::FailSelf ||
+ d->result() == QTest::FailCompile ||
+ d->result() == QTest::FailTest ||
+ d->result() == QTest::FailScript ||
+ d->result() == QTest::FailExpected ||
+ d->result() == QTest::PassUnexpected)
+ count++;
+ d = d->next();
+ }
+ return count;
+}
+
+uint QTestResultTestFunc::passCount()
+{
+ uint count = 0;
+ QTestResultTestData *d = first_data;
+ while (d != 0) {
+ if (d->result() == QTest::PassSelf ||
+ d->result() == QTest::PassCompile ||
+ d->result() == QTest::PassTest ||
+ d->result() == QTest::PassScript)
+ count++;
+ d = d->next();
+ }
+ return count;
+}
+
+QTestResultTestData* QTestResultTestFunc::curData()
+{
+ return cur_data;
+}
+
+QString QTestResultTestFunc::curDataTag()
+{
+ if (cur_data != 0)
+ return cur_data->name();
+ return "";
+}
+
+int QTestResultTestFunc::curDataIndex()
+{
+ if (cur_data != 0) {
+ int count = 0;
+ QTestResultTestData *d = first_data;
+ while (d != 0 && d != cur_data) {
+ count++;
+ d = d->next();
+ }
+ return count;
+ }
+ return 0;
+}
+
+bool QTestResultTestFunc::passed( bool current )
+{
+ // a test hasn't passed if no test has been executed
+ if (first_data == 0)
+ return FALSE;
+
+ QTestResultTestData *d = first_data;
+ if (current)
+ d = cur_data;
+ while (d != 0) {
+ // a test didn't pass if no result is reported or if it is reported as failed
+ if (d->result() == QTest::Invalid ||
+ d->result() == QTest::FailSelf ||
+ d->result() == QTest::FailCompile ||
+ d->result() == QTest::FailTest ||
+ d->result() == QTest::QFatal ||
+ d->result() == QTest::FailExpected ||
+ d->result() == QTest::FailScript )
+ return FALSE;
+ if (current)
+ d = 0;
+ else
+ d = d->next();
+ }
+
+ return TRUE;
+}
+
+bool QTestResultTestFunc::verified( bool current )
+{
+ // a function isn't verified if no test has been executed
+ if (first_data == 0)
+ return FALSE;
+
+ QTestResultTestData *d = first_data;
+ if (current)
+ d = cur_data;
+ while (d != 0) {
+ if (!d->verified())
+ return FALSE;
+ if (current)
+ d = 0;
+ else
+ d = d->next();
+ }
+
+ return TRUE;
+}
+
+bool QTestResultTestFunc::hasFailures()
+{
+ // a test hasn't passed if no test has been executed
+ if (first_data == 0)
+ return TRUE;
+
+// qDebug( func_name );
+
+ QTestResultTestData *d = first_data;
+ while (d != 0) {
+ // a test failed if it didn't pass and isn't skipped
+ if (d->result() != QTest::PassSelf &&
+ d->result() != QTest::PassCompile &&
+ d->result() != QTest::PassTest &&
+ d->result() != QTest::PassScript &&
+ d->result() != QTest::SkipAll &&
+ d->result() != QTest::SkipSingle)
+ return TRUE;
+ d = d->next();
+ }
+
+ return FALSE;
+}
+
+bool QTestResultTestFunc::skipped( bool current )
+{
+ QTestResultTestData *d = first_data;
+ if (current)
+ d = cur_data;
+ while (d != 0) {
+ if (d->result() == QTest::SkipAll ||
+ d->result() == QTest::SkipSingle)
+ return TRUE;
+ if (current)
+ d = 0;
+ else
+ d = d->next();
+ }
+ if (result() == QTest::SkipAll ||
+ result() == QTest::SkipSingle)
+ return TRUE;
+
+ return FALSE;
+}
+
+bool QTestResultTestFunc::failed( bool current )
+{
+ QTestResultTestData *d = first_data;
+ if (current)
+ d = cur_data;
+ while (d != 0) {
+ if (d->result() == QTest::FailSelf ||
+ d->result() == QTest::FailCompile ||
+ d->result() == QTest::FailTest ||
+ d->result() == QTest::QFatal ||
+ d->result() == QTest::FailExpected ||
+ d->result() == QTest::FailScript )
+ return TRUE;
+ if (current)
+ d = 0;
+ else
+ d = d->next();
+ }
+
+ if (result() == QTest::FailSelf ||
+ result() == QTest::FailCompile ||
+ result() == QTest::FailTest ||
+ result() == QTest::QFatal ||
+ result() == QTest::FailExpected ||
+ result() == QTest::FailScript )
+ return TRUE;
+
+ return FALSE;
+}
+
+void QTestResultTestFunc::ignoreResult( bool remote, const QTest::TestResult res, const QString &reason, bool exactMatch )
+{
+ if (cur_data != 0)
+ cur_data->ignoreResult( remote, res, reason, exactMatch );
+ else
+ QTestResultTestBase::ignoreResult( remote, res, reason, exactMatch );
+}
+
+void QTestResultTestFunc::addResult( bool spontaneous,
+ QTest::TestResult result,
+ const QString &reason,
+ const QString &file,
+ int line,
+ const QString &comment)
+{
+ if (comment == "SKIP_ALL") {
+ skip_all = TRUE;
+ }
+ if (cur_data != 0)
+ cur_data->addResult( spontaneous, result, reason, file, line, comment );
+ else
+ appendResult( spontaneous, result, reason, file, line, comment );
+}
+
+void QTestResultTestFunc::retest( bool busy )
+{
+ if (cur_data != 0)
+ cur_data->retest( busy );
+ else
+ setRetest( busy );
+}
+
+void QTestResultTestFunc::setExpectedFailure( int dataIndex, QString comment, QTest::TestFailMode mode )
+{
+ if (cur_data != 0)
+ cur_data->setExpectedFailure( dataIndex, comment, mode );
+ else
+ QTestResultTestBase::setExpectedFailure( dataIndex, comment, mode );
+}
+
+// ********************************************
+
+QTestResultTestData::QTestResultTestData( const QString &dataName, bool skipAll, QTestResultTestFunc *parent ) : QTestResultTestBase( parent->curTestCase(), parent )
+{
+ data_name = dataName;
+ next_data = 0;
+ skip_all = skipAll;
+}
+
+QTestResultTestData::~QTestResultTestData()
+{
+// qDebug( QString( "QTestResultTestData::~QTestResultTestData()... %1").arg(data_name).toLatin1() );
+
+ delete next_data;
+ next_data = 0;
+}
+
+QString QTestResultTestData::name()
+{
+ return data_name;
+}
+
+QString QTestResultTestData::dataTag()
+{
+ return data_name;
+}
+
+QTestResultTestData* QTestResultTestData::next()
+{
+ return next_data;
+}
+
+void QTestResultTestData::setNext( QTestResultTestData *n )
+{
+ next_data = n;
+}
+
+void QTestResultTestData::addResult( bool spontaneous,
+ QTest::TestResult result,
+ const QString &reason,
+ const QString &file,
+ int line,
+ const QString &comment)
+{
+ appendResult( spontaneous, result, reason, file, line, comment );
+}
+
+bool QTestResultTestData::verified()
+{
+ // a test isn't verified if no result is reported
+ if (result() == QTest::Invalid)
+ return FALSE;
+ return TRUE;
+}
+
+void QTestResultTestData::retest( bool busy )
+{
+ setRetest( busy );
+}
+
+void QTestResultTestData::setExpectedFailure( int dataIndex, QString comment, QTest::TestFailMode mode )
+{
+ QTestResultTestBase::setExpectedFailure( dataIndex, comment, mode );
+}
+
+// ----------------------------------------------------------------
+
diff --git a/libqsystemtest/qtestresult.h b/libqsystemtest/qtestresult.h
new file mode 100644
index 0000000..a8e4a98
--- /dev/null
+++ b/libqsystemtest/qtestresult.h
@@ -0,0 +1,131 @@
+/****************************************************************************
+ **
+ ** Definition of QTestResult class.
+ **
+ ** Copyright (C) 1992-$THISYEAR$ Trolltech AS. All rights reserved.
+ **
+ ** This file is part of the QTest library.
+ ** EDITIONS: NONE
+ **
+ ** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+ ** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ **
+ ****************************************************************************/
+
+#ifndef QTESTRESULT_H
+#define QTESTRESULT_H
+
+#include "qtest.h"
+#include "qkeystring.h"
+
+#include <QString>
+
+#define QTEST_SUPPORT
+
+class QTestLog;
+class QTestResult;
+
+class QTestResultRecord : public QTest
+{
+public:
+ QTestResultRecord();
+ QTestResultRecord( const QString &keyString );
+ QTestResultRecord( TestResult result, const QString &test, const QString &reason, const QString &dataset, const QString &file, const QString &line, const QString &comment );
+
+ QString testName();
+ bool passed();
+
+ QString keyString();
+ bool decode( const QString &logText );
+
+ QString testCase;
+ QString testFunc;
+ QString dataTag;
+ TestResult result;
+ QString reason;
+ QString file;
+ int line;
+ QString comment;
+};
+
+class QTestResult : public QTest
+{
+public:
+ QTestResult();
+ virtual ~QTestResult();
+
+ static QTestLog* testLog();
+ static void installMsgHandler();
+
+ enum TestLocation { NoWhere = 0, DataFunc = 1, InitFunc = 2, Func = 3, CleanupFunc = 4, Starting = 100, LaunchApps, InitTestCase, Executing, KillApps, CleanupTestCase };
+ void setCurrentTestLocation(TestLocation loc);
+ TestLocation currentTestLocation();
+
+ void setCurrentTestCase( const QString &testCaseName, bool verbose = TRUE, bool build = FALSE );
+ QString curTestCase();
+
+ void setCurrentTestFunction( const QString &testFunc );
+ QString curTestFunc( bool fullName ) const;
+
+ void setCurrentTestData( const QString &dataTag );
+ QString curDataTag();
+ int curDataIndex() const;
+
+ void setConfiguration( const QString &hostName,
+ const QString &OSName,
+ const QString &config,
+ const QString &makeSpec );
+ QString curConfiguration();
+
+ bool enterCheckPoint( const QString &fileName, int line );
+ bool checkPointError( QString *reason = 0 );
+
+ void skip( const QString &reason, bool skipAll, const QString &file, int line );
+ void addNote( const QString &comment );
+ void addMessage( const QString &message );
+ void addWarning( const QString &text );
+ void addError( const QString &text );
+ void addFatal( const QString &message );
+ void addFailure( const QString &text, const QString &file, int line );
+ void addSuccess( const QString &text, const QString &file, int line );
+ void addMakeResult( const QString &result );
+
+ void addResult( const TestResult result,
+ const QString &reason,
+ const QString &file = "",
+ int line = -1,
+ const QString &extraInfo = "" );
+ void addResult( const QString &keyString );
+
+ void debugLog( const QString &dbgtxt );
+
+ void setExpectedFailure( int dataIndex, QString comment, TestFailMode mode );
+
+ void ignoreResult( const QTest::TestResult res, const QString &reason, bool exactMatch = FALSE );
+ void remoteIgnoreResult( const QTest::TestResult res, const QString &reason, bool exactMatch = FALSE );
+
+ uint noOfExecutedTests() const;
+ uint noOfFailures() const;
+ uint noOfPasses() const;
+ bool currentTestPassed( bool &withSkips ) const;
+ bool currentTestFailed() const;
+
+ bool debugMode() const;
+ QTest::LearnMode learnMode();
+// void showQDebug( bool show );
+// void showPerformance( bool show );
+
+ // obsolete function that is kept for backward compatibility.
+// void setIgnoreResult( const QTest::TestResult res, const QString &reason, bool exactMatch = FALSE );
+
+ static QString resultToStr( QTest::TestResult res );
+ void retest( bool busy );
+
+#ifdef QTEST_SUPPORT
+ bool loadResult( const QString &logging_file, bool &isConsoleApp );
+ void processLogResult( const QString &S );
+#endif
+};
+
+#endif
+
diff --git a/qtuitest-host.pri b/qtuitest-host.pri
index 7f579a2..2abb783 100644
--- a/qtuitest-host.pri
+++ b/qtuitest-host.pri
@@ -39,6 +39,9 @@ SEMI_PRIVATE_HEADERS += \
$$QTUITEST_SRC/libqsystemtest/qtestverifydlg_p.h
HEADERS +=\
+ $$QTUITEST_SRC/libqsystemtest/qtestlog.h \
+ $$QTUITEST_SRC/libqsystemtest/qtestresult.h \
+ $$QTUITEST_SRC/libqsystemtest/qkeystring.h \
$$QTUITEST_SRC/libqsystemtest/qabstracttest.h \
$$QTUITEST_SRC/libqsystemtest/qsystemtest.h \
$$QTUITEST_SRC/libqsystemtest/qtestide.h \
@@ -50,6 +53,9 @@ HEADERS +=\
$$QTUITEST_SRC/libqsystemtest/meegotestcontrol.h
SOURCES +=\
+ $$QTUITEST_SRC/libqsystemtest/qtestlog.cpp \
+ $$QTUITEST_SRC/libqsystemtest/qtestresult.cpp \
+ $$QTUITEST_SRC/libqsystemtest/qkeystring.cpp \
# $$QTUITEST_SRC/libqsystemtest/gracefulquit.cpp \
$$QTUITEST_SRC/libqsystemtest/qtestide.cpp \
$$QTUITEST_SRC/libqsystemtest/qabstracttest.cpp \