summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorJason McDonald <jason.mcdonald@nokia.com>2011-09-02 19:08:21 +1000
committerQt by Nokia <qt-info@nokia.com>2011-09-23 00:34:23 +0200
commit51589e834e086de93a121a1c628c3492d88a15a7 (patch)
tree6d1506f12c3dc9eb37d8471e8e0b1d1a821c2cac /src
parent157fc88f90c42c6ff1b47b1bad018565fe63f626 (diff)
Allow tests to log to multiple destinations
Each destination and the format of output to write there is specified by adding "-o filename,format" to the command-line. The special filename "-" indicates that the log output is written to the standard output stream, though standard output can be used as a destination at most once. The old-style testlib output options are still supported, but can only be used to specify one logging destination, as before. If no logging options are given on the command-line, a plain text log will go to the console, as before. To log to the console in plain text and to the file "test_output" in xunit format, one would invoke a test in the following way: tst_foo -o test_output,xunitxml -o -,txt This commit also enhances the selftests to test with multiple loggers, but negative tests (e.g. bad combinations of command-line options) are left for future task QTBUG-21567. Task-number: QTBUG-20615 Change-Id: If91e752bc7001657e15e427aba9d25ab0a29a0b0 Reviewed-on: http://codereview.qt-project.org/4125 Reviewed-by: Qt Sanity Bot <qt_sanity_bot@ovi.com> Reviewed-by: Rohan McGovern <rohan.mcgovern@nokia.com>
Diffstat (limited to 'src')
-rw-r--r--src/testlib/qtestcase.cpp67
-rw-r--r--src/testlib/qtestlog.cpp192
-rw-r--r--src/testlib/qtestlog_p.h5
3 files changed, 200 insertions, 64 deletions
diff --git a/src/testlib/qtestcase.cpp b/src/testlib/qtestcase.cpp
index 9bb591989d..b49d5c2aa5 100644
--- a/src/testlib/qtestcase.cpp
+++ b/src/testlib/qtestcase.cpp
@@ -1004,11 +1004,28 @@ Q_TESTLIB_EXPORT void qtest_qParseArgs(int argc, char *argv[], bool qml)
const char *logFilename = 0;
const char *testOptions =
- " Output options:\n"
- " -xunitxml : Outputs results as XML XUnit document\n"
- " -xml : Outputs results as XML document\n"
- " -lightxml : Outputs results as stream of XML tags\n"
- " -o filename : Writes all output into a file\n"
+ " New-style logging options:\n"
+ " -o filename,format : Output results to file in the specified format\n"
+ " Use - to output to stdout\n"
+ " Valid formats are:\n"
+ " txt : Plain text\n"
+ " xunitxml : XML XUnit document\n"
+ " xml : XML document\n"
+ " lightxml : A stream of XML tags\n"
+ "\n"
+ " *** Multiple loggers can be specified, but at most one can log to stdout.\n"
+ "\n"
+ " Old-style logging options:\n"
+ " -o filename : Write the output into file\n"
+ " -txt : Output results in Plain Text\n"
+ " -xunitxml : Output results as XML XUnit document\n"
+ " -xml : Output results as XML document\n"
+ " -lightxml : Output results as stream of XML tags\n"
+ "\n"
+ " *** If no output file is specified, stdout is assumed.\n"
+ " *** If no output format is specified, -txt is assumed.\n"
+ "\n"
+ " Detail options:\n"
" -silent : Only outputs warnings and failures\n"
" -v1 : Print enter messages for each testfunction\n"
" -v2 : Also print out each QVERIFY/QCOMPARE/QTEST\n"
@@ -1065,6 +1082,8 @@ Q_TESTLIB_EXPORT void qtest_qParseArgs(int argc, char *argv[], bool qml)
qPrintTestSlots(stdout);
exit(0);
}
+ } else if (strcmp(argv[i], "-txt") == 0) {
+ logFormat = QTestLog::Plain;
} else if (strcmp(argv[i], "-xunitxml") == 0) {
logFormat = QTestLog::XunitXML;
} else if (strcmp(argv[i], "-xml") == 0) {
@@ -1081,11 +1100,38 @@ Q_TESTLIB_EXPORT void qtest_qParseArgs(int argc, char *argv[], bool qml)
QSignalDumper::startDump();
} else if (strcmp(argv[i], "-o") == 0) {
if (i + 1 >= argc) {
- fprintf(stderr, "-o needs an extra parameter specifying the filename\n");
+ fprintf(stderr, "-o needs an extra parameter specifying the filename and optional format\n");
exit(1);
+ }
+ ++i;
+ // Do we have the old or new style -o option?
+ char *filename = new char[strlen(argv[i])+1];
+ char *format = new char[strlen(argv[i])+1];
+ if (sscanf(argv[i], "%[^,],%s", filename, format) == 1) {
+ // Old-style
+ logFilename = argv[i];
} else {
- logFilename = argv[++i];
+ // New-style
+ if (strcmp(format, "txt") == 0)
+ logFormat = QTestLog::Plain;
+ else if (strcmp(format, "lightxml") == 0)
+ logFormat = QTestLog::LightXML;
+ else if (strcmp(format, "xml") == 0)
+ logFormat = QTestLog::XML;
+ else if (strcmp(format, "xunitxml") == 0)
+ logFormat = QTestLog::XunitXML;
+ else {
+ fprintf(stderr, "output format must be one of txt, lightxml, xml or xunitxml\n");
+ exit(1);
+ }
+ if (strcmp(filename, "-") == 0 && QTestLog::loggerUsingStdout()) {
+ fprintf(stderr, "only one logger can log to stdout\n");
+ exit(1);
+ }
+ QTestLog::addLogger(logFormat, filename);
}
+ delete [] filename;
+ delete [] format;
} else if (strcmp(argv[i], "-eventdelay") == 0) {
if (i + 1 >= argc) {
fprintf(stderr, "-eventdelay needs an extra parameter to indicate the delay(ms)\n");
@@ -1248,8 +1294,11 @@ Q_TESTLIB_EXPORT void qtest_qParseArgs(int argc, char *argv[], bool qml)
}
}
- // Create the logger
- QTestLog::initLogger(logFormat, logFilename);
+ // If no loggers were created by the long version of the -o command-line
+ // option, create a logger using whatever filename and format were
+ // set using the old-style command-line options.
+ if (QTestLog::loggerCount() == 0)
+ QTestLog::addLogger(logFormat, logFilename);
}
QBenchmarkResult qMedian(const QList<QBenchmarkResult> &container)
diff --git a/src/testlib/qtestlog.cpp b/src/testlib/qtestlog.cpp
index d53b00ca7f..f3b416d3d1 100644
--- a/src/testlib/qtestlog.cpp
+++ b/src/testlib/qtestlog.cpp
@@ -82,12 +82,103 @@ namespace QTest {
static IgnoreResultList *ignoreResultList = 0;
- static QTestLog::LogMode logMode = QTestLog::Plain;
+ struct LoggerList
+ {
+ QAbstractTestLogger *logger;
+ LoggerList *next;
+ };
+
+ class TestLoggers
+ {
+ public:
+ static void addLogger(QAbstractTestLogger *logger)
+ {
+ LoggerList *l = new LoggerList;
+ l->logger = logger;
+ l->next = loggers;
+ loggers = l;
+ }
+
+ static void destroyLoggers()
+ {
+ while (loggers) {
+ LoggerList *l = loggers;
+ loggers = loggers->next;
+ delete l->logger;
+ delete l;
+ }
+ }
+
+#define FOREACH_LOGGER(operation) \
+ LoggerList *l = loggers; \
+ while (l) { \
+ QAbstractTestLogger *logger = l->logger; \
+ Q_UNUSED(logger); \
+ operation; \
+ l = l->next; \
+ }
+
+ static void startLogging()
+ {
+ FOREACH_LOGGER(logger->startLogging());
+ }
+
+ static void stopLogging()
+ {
+ FOREACH_LOGGER(logger->stopLogging());
+ }
+
+ static void enterTestFunction(const char *function)
+ {
+ FOREACH_LOGGER(logger->enterTestFunction(function));
+ }
+
+ static void leaveTestFunction()
+ {
+ FOREACH_LOGGER(logger->leaveTestFunction());
+ }
+
+ static void addIncident(QAbstractTestLogger::IncidentTypes type, const char *description,
+ const char *file = 0, int line = 0)
+ {
+ FOREACH_LOGGER(logger->addIncident(type, description, file, line));
+ }
+
+ static void addBenchmarkResult(const QBenchmarkResult &result)
+ {
+ FOREACH_LOGGER(logger->addBenchmarkResult(result));
+ }
+
+ static void addMessage(QAbstractTestLogger::MessageTypes type, const char *message,
+ const char *file = 0, int line = 0)
+ {
+ FOREACH_LOGGER(logger->addMessage(type, message, file, line));
+ }
+
+ static void outputString(const char *msg)
+ {
+ FOREACH_LOGGER(logger->outputString(msg));
+ }
+
+ static int loggerCount()
+ {
+ int count = 0;
+ FOREACH_LOGGER(++count);
+ return count;
+ }
+
+ private:
+ static LoggerList *loggers;
+ };
+
+#undef FOREACH_LOGGER
+
+ LoggerList *TestLoggers::loggers = 0;
+ static bool loggerUsingStdout = false;
+
static int verbosity = 0;
static int maxWarnings = 2002;
- static QAbstractTestLogger *testLogger = 0;
-
static QtMsgHandler oldMessageHandler;
static bool handleIgnoredMessage(QtMsgType type, const char *msg)
@@ -118,11 +209,11 @@ namespace QTest {
{
static QBasicAtomicInt counter = Q_BASIC_ATOMIC_INITIALIZER(QTest::maxWarnings);
- if (!msg || !QTest::testLogger) {
+ if (!msg || QTest::TestLoggers::loggerCount() == 0) {
// if this goes wrong, something is seriously broken.
qInstallMsgHandler(oldMessageHandler);
QTEST_ASSERT(msg);
- QTEST_ASSERT(QTest::testLogger);
+ QTEST_ASSERT(QTest::TestLoggers::loggerCount() != 0);
}
if (handleIgnoredMessage(type, msg))
@@ -134,7 +225,7 @@ namespace QTest {
return;
if (!counter.deref()) {
- QTest::testLogger->addMessage(QAbstractTestLogger::QSystem,
+ QTest::TestLoggers::addMessage(QAbstractTestLogger::QSystem,
"Maximum amount of warnings exceeded. Use -maxwarnings to override.");
return;
}
@@ -142,16 +233,16 @@ namespace QTest {
switch (type) {
case QtDebugMsg:
- QTest::testLogger->addMessage(QAbstractTestLogger::QDebug, msg);
+ QTest::TestLoggers::addMessage(QAbstractTestLogger::QDebug, msg);
break;
case QtCriticalMsg:
- QTest::testLogger->addMessage(QAbstractTestLogger::QSystem, msg);
+ QTest::TestLoggers::addMessage(QAbstractTestLogger::QSystem, msg);
break;
case QtWarningMsg:
- QTest::testLogger->addMessage(QAbstractTestLogger::QWarning, msg);
+ QTest::TestLoggers::addMessage(QAbstractTestLogger::QWarning, msg);
break;
case QtFatalMsg:
- QTest::testLogger->addMessage(QAbstractTestLogger::QFatal, msg);
+ QTest::TestLoggers::addMessage(QAbstractTestLogger::QFatal, msg);
/* Right now, we're inside the custom message handler and we're
* being qt_message_output in qglobal.cpp. After we return from
* this function, it will proceed with calling exit() and abort()
@@ -167,10 +258,9 @@ namespace QTest {
void QTestLog::enterTestFunction(const char* function)
{
- QTEST_ASSERT(QTest::testLogger);
QTEST_ASSERT(function);
- QTest::testLogger->enterTestFunction(function);
+ QTest::TestLoggers::enterTestFunction(function);
}
int QTestLog::unhandledIgnoreMessages()
@@ -186,21 +276,17 @@ int QTestLog::unhandledIgnoreMessages()
void QTestLog::leaveTestFunction()
{
- QTEST_ASSERT(QTest::testLogger);
-
QTest::IgnoreResultList::clearList(QTest::ignoreResultList);
- QTest::testLogger->leaveTestFunction();
+ QTest::TestLoggers::leaveTestFunction();
}
void QTestLog::printUnhandledIgnoreMessages()
{
- QTEST_ASSERT(QTest::testLogger);
-
char msg[1024];
QTest::IgnoreResultList *list = QTest::ignoreResultList;
while (list) {
QTest::qt_snprintf(msg, 1024, "Did not receive message: \"%s\"", list->msg);
- QTest::testLogger->addMessage(QAbstractTestLogger::Info, msg);
+ QTest::TestLoggers::addMessage(QAbstractTestLogger::Info, msg);
list = list->next;
}
@@ -208,110 +294,110 @@ void QTestLog::printUnhandledIgnoreMessages()
void QTestLog::addPass(const char *msg)
{
- QTEST_ASSERT(QTest::testLogger);
QTEST_ASSERT(msg);
- QTest::testLogger->addIncident(QAbstractTestLogger::Pass, msg);
+ QTest::TestLoggers::addIncident(QAbstractTestLogger::Pass, msg);
}
void QTestLog::addFail(const char *msg, const char *file, int line)
{
- QTEST_ASSERT(QTest::testLogger);
QTEST_ASSERT(msg);
- QTest::testLogger->addIncident(QAbstractTestLogger::Fail, msg, file, line);
+ QTest::TestLoggers::addIncident(QAbstractTestLogger::Fail, msg, file, line);
}
void QTestLog::addXFail(const char *msg, const char *file, int line)
{
- QTEST_ASSERT(QTest::testLogger);
QTEST_ASSERT(msg);
QTEST_ASSERT(file);
- QTest::testLogger->addIncident(QAbstractTestLogger::XFail, msg, file, line);
+ QTest::TestLoggers::addIncident(QAbstractTestLogger::XFail, msg, file, line);
}
void QTestLog::addXPass(const char *msg, const char *file, int line)
{
- QTEST_ASSERT(QTest::testLogger);
QTEST_ASSERT(msg);
QTEST_ASSERT(file);
- QTest::testLogger->addIncident(QAbstractTestLogger::XPass, msg, file, line);
+ QTest::TestLoggers::addIncident(QAbstractTestLogger::XPass, msg, file, line);
}
void QTestLog::addSkip(const char *msg, const char *file, int line)
{
- QTEST_ASSERT(QTest::testLogger);
QTEST_ASSERT(msg);
QTEST_ASSERT(file);
- QTest::testLogger->addMessage(QAbstractTestLogger::Skip, msg, file, line);
+ QTest::TestLoggers::addMessage(QAbstractTestLogger::Skip, msg, file, line);
}
void QTestLog::addBenchmarkResult(const QBenchmarkResult &result)
{
- QTEST_ASSERT(QTest::testLogger);
- QTest::testLogger->addBenchmarkResult(result);
+ QTest::TestLoggers::addBenchmarkResult(result);
}
void QTestLog::startLogging()
{
- QTEST_ASSERT(QTest::testLogger);
- QTest::testLogger->startLogging();
+ QTest::TestLoggers::startLogging();
QTest::oldMessageHandler = qInstallMsgHandler(QTest::messageHandler);
}
void QTestLog::stopLogging()
{
qInstallMsgHandler(QTest::oldMessageHandler);
-
- QTEST_ASSERT(QTest::testLogger);
- QTest::testLogger->stopLogging();
- delete QTest::testLogger;
- QTest::testLogger = 0;
+ QTest::TestLoggers::stopLogging();
+ QTest::TestLoggers::destroyLoggers();
+ QTest::loggerUsingStdout = false;
}
-void QTestLog::initLogger(LogMode mode, const char *filename)
+void QTestLog::addLogger(LogMode mode, const char *filename)
{
- QTest::logMode = mode;
+ if (filename && strcmp(filename, "-") == 0)
+ filename = 0;
+ if (!filename)
+ QTest::loggerUsingStdout = true;
+ QAbstractTestLogger *logger = 0;
switch (mode) {
case QTestLog::Plain:
- QTest::testLogger = new QPlainTestLogger(filename);
+ logger = new QPlainTestLogger(filename);
break;
case QTestLog::XML:
- QTest::testLogger = new QXmlTestLogger(QXmlTestLogger::Complete, filename);
+ logger = new QXmlTestLogger(QXmlTestLogger::Complete, filename);
break;
case QTestLog::LightXML:
- QTest::testLogger = new QXmlTestLogger(QXmlTestLogger::Light, filename);
+ logger = new QXmlTestLogger(QXmlTestLogger::Light, filename);
break;
case QTestLog::XunitXML:
- QTest::testLogger = new QXunitTestLogger(filename);
+ logger = new QXunitTestLogger(filename);
break;
}
- QTEST_ASSERT(QTest::testLogger);
+ QTEST_ASSERT(logger);
+ QTest::TestLoggers::addLogger(logger);
}
-void QTestLog::warn(const char *msg)
+int QTestLog::loggerCount()
{
- QTEST_ASSERT(QTest::testLogger);
- QTEST_ASSERT(msg);
+ return QTest::TestLoggers::loggerCount();
+}
- QTest::testLogger->addMessage(QAbstractTestLogger::Warn, msg);
+bool QTestLog::loggerUsingStdout()
+{
+ return QTest::loggerUsingStdout;
}
-void QTestLog::info(const char *msg, const char *file, int line)
+void QTestLog::warn(const char *msg)
{
QTEST_ASSERT(msg);
- if (QTest::testLogger)
- QTest::testLogger->addMessage(QAbstractTestLogger::Info, msg, file, line);
+ if (QTest::TestLoggers::loggerCount() > 0)
+ QTest::TestLoggers::addMessage(QAbstractTestLogger::Warn, msg);
}
-QTestLog::LogMode QTestLog::logMode()
+void QTestLog::info(const char *msg, const char *file, int line)
{
- return QTest::logMode;
+ QTEST_ASSERT(msg);
+
+ QTest::TestLoggers::addMessage(QAbstractTestLogger::Info, msg, file, line);
}
void QTestLog::setVerboseLevel(int level)
diff --git a/src/testlib/qtestlog_p.h b/src/testlib/qtestlog_p.h
index f06382978f..fe37469dc6 100644
--- a/src/testlib/qtestlog_p.h
+++ b/src/testlib/qtestlog_p.h
@@ -83,9 +83,10 @@ public:
static void startLogging();
static void stopLogging();
- static void initLogger(LogMode mode, const char *filename);
+ static void addLogger(LogMode mode, const char *filename);
- static LogMode logMode();
+ static int loggerCount();
+ static bool loggerUsingStdout();
static void setVerboseLevel(int level);
static int verboseLevel();