summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristian Stenger <christian.stenger@theqtcompany.com>2015-05-13 16:07:31 +0200
committerChristian Stenger <christian.stenger@theqtcompany.com>2015-06-12 13:15:53 +0300
commit4605814c1d48f31fd150f32c2687596aeb3cb74e (patch)
treee5a740eac23f861482df44824dd63a628b736d93
parent9d4509540b7a67fcb4f4087708eb207164bdee5f (diff)
downloadqt-creator-4605814c1d48f31fd150f32c2687596aeb3cb74e.tar.gz
Parse Squish's XML output and put it on results pane
Change-Id: I5206a30f11b96bd0ab1a3a360b8f5e8fec0fe5f1 Reviewed-by: Riitta-Leena Miettinen <riitta-leena.miettinen@theqtcompany.com> Reviewed-by: Robert Loehning <robert.loehning@theqtcompany.com>
-rw-r--r--plugins/autotest/autotest.pro6
-rw-r--r--plugins/autotest/autotest.qbs4
-rw-r--r--plugins/autotest/squishxmloutputhandler.cpp293
-rw-r--r--plugins/autotest/squishxmloutputhandler.h54
-rw-r--r--plugins/autotest/testresult.cpp68
-rw-r--r--plugins/autotest/testresult.h24
-rw-r--r--plugins/autotest/testresultdelegate.cpp7
-rw-r--r--plugins/autotest/testresultdelegate.h4
-rw-r--r--plugins/autotest/testresultmodel.cpp33
-rw-r--r--plugins/autotest/testresultmodel.h6
-rw-r--r--plugins/autotest/testresultspane.cpp18
-rw-r--r--plugins/autotest/testresultspane.h1
-rw-r--r--plugins/autotest/testsquishtools.cpp29
-rw-r--r--plugins/autotest/testsquishtools.h4
14 files changed, 534 insertions, 17 deletions
diff --git a/plugins/autotest/autotest.pro b/plugins/autotest/autotest.pro
index 85ab704576..df61df9fe6 100644
--- a/plugins/autotest/autotest.pro
+++ b/plugins/autotest/autotest.pro
@@ -32,7 +32,8 @@ SOURCES += \
testsquishfilehandler.cpp \
opensquishsuitesdialog.cpp \
testsquishutils.cpp \
- testsquishtools.cpp
+ testsquishtools.cpp \
+ squishxmloutputhandler.cpp
HEADERS += \
squishsettings.h \
@@ -60,7 +61,8 @@ HEADERS += \
testsquishfilehandler.h \
opensquishsuitesdialog.h \
testsquishutils.h \
- testsquishtools.h
+ testsquishtools.h \
+ squishxmloutputhandler.h
RESOURCES += \
autotest.qrc
diff --git a/plugins/autotest/autotest.qbs b/plugins/autotest/autotest.qbs
index faf80f0484..18f76116ec 100644
--- a/plugins/autotest/autotest.qbs
+++ b/plugins/autotest/autotest.qbs
@@ -79,7 +79,9 @@ QtcPlugin {
"testsquishutils.cpp",
"testsquishutils.h",
"testsquishtools.cpp",
- "testsquishtools.h"
+ "testsquishtools.h",
+ "squishxmloutputhandler.cpp",
+ "squishxmloutputhandler.h"
]
Group {
diff --git a/plugins/autotest/squishxmloutputhandler.cpp b/plugins/autotest/squishxmloutputhandler.cpp
new file mode 100644
index 0000000000..c9e5aad8fd
--- /dev/null
+++ b/plugins/autotest/squishxmloutputhandler.cpp
@@ -0,0 +1,293 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 The Qt Company Ltd
+** All rights reserved.
+** For any questions to The Qt Company, please use contact form at
+** http://www.qt.io/contact-us
+**
+** This file is part of the Qt Creator Enterprise Auto Test Add-on.
+**
+** Licensees holding valid Qt Enterprise licenses may use this file in
+** accordance with the Qt Enterprise License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company.
+**
+** If you have questions regarding the use of this file, please use
+** contact form at http://www.qt.io/contact-us
+**
+****************************************************************************/
+
+#include "squishxmloutputhandler.h"
+#include "testresultspane.h"
+
+#include <utils/qtcassert.h>
+
+#include <QDebug>
+#include <QDateTime>
+#include <QFile>
+#include <QXmlStreamWriter>
+
+namespace Autotest {
+namespace Internal {
+
+SquishXmlOutputHandler::SquishXmlOutputHandler(QObject *parent) : QObject(parent)
+{
+ connect(this, &SquishXmlOutputHandler::testResultCreated,
+ TestResultsPane::instance(), &TestResultsPane::addTestResult, Qt::QueuedConnection);
+}
+
+void SquishXmlOutputHandler::clearForNextRun()
+{
+ m_xmlReader.clear();
+}
+
+void SquishXmlOutputHandler::mergeResultFiles(const QStringList &reportFiles,
+ const QString &resultsDirectory,
+ const QString &suiteName, QString *errorMessage)
+{
+ QFile resultsXML(QString::fromLatin1("%1/results.xml").arg(resultsDirectory));
+ if (resultsXML.exists()) {
+ if (errorMessage)
+ *errorMessage = tr("Could not merge results into single results.xml.\n"
+ "Destination file \"%1\" already exists.").arg(resultsXML.fileName());
+ return;
+ }
+
+ if (!resultsXML.open(QFile::WriteOnly)) {
+ if (errorMessage)
+ *errorMessage = tr("Could not merge results into single results.xml.\n"
+ "Failed to open file \"%1\"").arg(resultsXML.fileName());
+ return;
+ }
+
+ QXmlStreamWriter xmlWriter(&resultsXML);
+ xmlWriter.writeStartDocument(QLatin1String("1.0"));
+ bool isFirstReport = true;
+ bool isFirstTest = true;
+ QString lastEpilogTime;
+ foreach (const QString &caseResult, reportFiles) {
+ QFile currentResultsFile(caseResult);
+ if (!currentResultsFile.exists())
+ continue;
+ if (!currentResultsFile.open(QFile::ReadOnly))
+ continue;
+ QXmlStreamReader reader(&currentResultsFile);
+ while (!reader.atEnd()) {
+ QXmlStreamReader::TokenType type = reader.readNext();
+ switch (type) {
+ case QXmlStreamReader::StartElement: {
+ const QStringRef tagName = reader.name();
+ // SquishReport of the first results.xml will be taken as is and as this is a
+ // merged results.xml we add another test tag holding the suite's name
+ if (tagName == QLatin1String("SquishReport")) {
+ if (isFirstReport) {
+ xmlWriter.writeStartElement(tagName.toString());
+ xmlWriter.writeAttributes(reader.attributes());
+ xmlWriter.writeStartElement(QLatin1String("test"));
+ xmlWriter.writeAttribute(QLatin1String("name"), suiteName);
+ isFirstReport = false;
+ }
+ break;
+ }
+ if (isFirstTest && tagName == QLatin1String("test")) {
+ // the prolog tag of the first results.xml holds the start time of the suite
+ // we already wrote the test tag for the suite, but haven't added the start
+ // time as we didn't know about it, so store information of the current test
+ // tag (case name), read ahead (prolog tag), write prolog (suite's test tag)
+ // and finally write test tag (case name) - the prolog tag (for test case)
+ // will be written outside the if
+ const QXmlStreamAttributes testAttributes = reader.attributes();
+ QXmlStreamReader::TokenType token;
+ while (!reader.atEnd()) {
+ token = reader.readNext();
+ if (token != QXmlStreamReader::Characters)
+ break;
+ }
+ const QStringRef prolog = reader.name();
+ QTC_ASSERT(token == QXmlStreamReader::StartElement
+ && prolog == QLatin1String("prolog"),
+ if (errorMessage)
+ *errorMessage = tr("Error while parsing first test result.");
+ return);
+ xmlWriter.writeStartElement(prolog.toString());
+ xmlWriter.writeAttributes(reader.attributes());
+ xmlWriter.writeEndElement();
+ xmlWriter.writeStartElement(QLatin1String("test"));
+ xmlWriter.writeAttributes(testAttributes);
+ isFirstTest = false;
+ } else if (tagName == QLatin1String("epilog")) {
+ lastEpilogTime
+ = reader.attributes().value(QLatin1String("time")).toString();
+ }
+ xmlWriter.writeCurrentToken(reader);
+ break;
+ }
+ case QXmlStreamReader::EndElement:
+ if (reader.name() != QLatin1String("SquishReport"))
+ xmlWriter.writeCurrentToken(reader);
+ break;
+ case QXmlStreamReader::Characters:
+ xmlWriter.writeCurrentToken(reader);
+ break;
+ // ignore the rest
+ default:
+ break;
+ }
+ }
+ currentResultsFile.close();
+ }
+ if (!lastEpilogTime.isEmpty()) {
+ xmlWriter.writeStartElement(QLatin1String("epilog"));
+ xmlWriter.writeAttribute(QLatin1String("time"), lastEpilogTime);
+ xmlWriter.writeEndElement();
+ }
+ xmlWriter.writeEndDocument();
+}
+
+Result::Type resultFromString(const QString &type)
+{
+ if (type == QLatin1String("LOG"))
+ return Result::SQUISH_LOG;
+ if (type == QLatin1String("PASS"))
+ return Result::SQUISH_PASS;
+ if (type == QLatin1String("FAIL"))
+ return Result::SQUISH_FAIL;
+ if (type == QLatin1String("WARNING"))
+ return Result::SQUISH_WARN;
+ if (type == QLatin1String("XFAIL"))
+ return Result::SQUISH_EXPECTED_FAIL;
+ if (type == QLatin1String("XPASS"))
+ return Result::UNEXPECTED_PASS;
+ if (type == QLatin1String("FATAL"))
+ return Result::SQUISH_FATAL;
+ if (type == QLatin1String("ERROR"))
+ return Result::SQUISH_ERROR;
+ return Result::SQUISH_LOG;
+}
+
+// this method uses the XML reader to parse output of the Squish results.xml and put it into an
+// item that can be used to display inside the test results pane
+void SquishXmlOutputHandler::outputAvailable(const QByteArray &output)
+{
+ static QString name;
+ static QString details;
+ static QString logDetails;
+ static QString time;
+ static QString file;
+ static Result::Type type;
+ static int line = 0;
+ static bool prepend = false;
+
+ m_xmlReader.addData(output);
+
+ while (!m_xmlReader.atEnd()) {
+ QXmlStreamReader::TokenType tokenType = m_xmlReader.readNext();
+ switch (tokenType) {
+ case QXmlStreamReader::StartDocument:
+ case QXmlStreamReader::EndDocument:
+ break;
+ case QXmlStreamReader::StartElement: {
+ const QString currentName = m_xmlReader.name().toString();
+ // tags verification, message, epilog and test will start a new entry, so, reset values
+ if (currentName == QLatin1String("verification")
+ || currentName == QLatin1String("message")
+ || currentName == QLatin1String("epilog")
+ || currentName == QLatin1String("test")) {
+ name = currentName;
+ details.clear();
+ logDetails.clear();
+ time.clear();
+ file.clear();
+ line = 0;
+ type = Result::SQUISH_LOG;
+ } else if (currentName == QLatin1String("result")) {
+ // result tag won't add another entry, but gives more information on enclosing tag
+ name = currentName;
+ }
+
+ // description tag could provide information that must be prepended to the former entry
+ if (currentName == QLatin1String("description")) {
+ prepend = (name == QLatin1String("result") && m_xmlReader.attributes().isEmpty());
+ } else {
+ foreach (const QXmlStreamAttribute &att, m_xmlReader.attributes()) {
+ const QString attributeName = att.name().toString();
+ if (attributeName == QLatin1String("time"))
+ time = QDateTime::fromString(att.value().toString(), Qt::ISODate)
+ .toString(QLatin1String("MMM dd, yyyy h:mm:ss AP"));
+ else if (attributeName == QLatin1String("file"))
+ file = att.value().toString();
+ else if (attributeName == QLatin1String("line"))
+ line = att.value().toInt();
+ else if (attributeName == QLatin1String("type"))
+ type = resultFromString(att.value().toString());
+ else if (attributeName == QLatin1String("name"))
+ logDetails = att.value().toString();
+ }
+ }
+ // handle prolog (test) elements already within the start tag
+ if (currentName == QLatin1String("prolog")) {
+ TestResult result(QString(), QString(), QString(), Result::SQUISH_START,
+ logDetails + QLatin1Char('\n') + time);
+ result.setFileName(file);
+ result.setLine(line);
+ emit testResultCreated(result);
+ }
+ break;
+ }
+ case QXmlStreamReader::EndElement: {
+ const QString currentName = m_xmlReader.name().toString();
+ // description and result tags are handled differently, test tags are handled by
+ // prolog tag (which is handled in QXmlStreamReader::StartElement already),
+ // SquishReport tags will be ignored completely
+ if (currentName == QLatin1String("epilog")) {
+ TestResult result(QString(), QString(), QString(), Result::SQUISH_END, time);
+ emit testResultCreated(result);
+ } else if (currentName != QLatin1String("description")
+ && currentName != QLatin1String("prolog")
+ && currentName != QLatin1String("test")
+ && currentName != QLatin1String("result")
+ && currentName != QLatin1String("SquishReport")) {
+ QString description;
+ if (!logDetails.isEmpty())
+ description = logDetails + QLatin1Char('\n');
+
+ TestResult result(QString(), QString(), QString(), type);
+ result.setDescription(description + details.trimmed() + QLatin1Char('\n') + time);
+ result.setFileName(file);
+ result.setLine(line);
+ emit testResultCreated(result);
+ }
+ break;
+ }
+ case QXmlStreamReader::Characters: {
+ QStringRef text = m_xmlReader.text();
+ if (m_xmlReader.isCDATA() || !text.trimmed().isEmpty()) {
+ if (!m_xmlReader.isCDATA())
+ text = text.trimmed();
+ if (prepend) {
+ if (!logDetails.isEmpty() && (text == QLatin1String("Verified")
+ || text == QLatin1String("Not Verified"))) {
+ logDetails.prepend(text + QLatin1String(": "));
+ } else {
+ logDetails = text.toString();
+ }
+ } else {
+ details.append(text).append(QLatin1Char('\n'));
+ }
+ }
+ break;
+ }
+ default:
+ break;
+ }
+ }
+
+ if (m_xmlReader.hasError()) {
+ // kind of expected as we get the output piece by piece
+ if (m_xmlReader.error() != QXmlStreamReader::PrematureEndOfDocumentError)
+ qWarning() << m_xmlReader.error() << m_xmlReader.errorString();
+ }
+}
+
+} // namespace Internal
+} // namespace Autotest
diff --git a/plugins/autotest/squishxmloutputhandler.h b/plugins/autotest/squishxmloutputhandler.h
new file mode 100644
index 0000000000..abc59cc5dc
--- /dev/null
+++ b/plugins/autotest/squishxmloutputhandler.h
@@ -0,0 +1,54 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 The Qt Company Ltd
+** All rights reserved.
+** For any questions to The Qt Company, please use contact form at
+** http://www.qt.io/contact-us
+**
+** This file is part of the Qt Creator Enterprise Auto Test Add-on.
+**
+** Licensees holding valid Qt Enterprise licenses may use this file in
+** accordance with the Qt Enterprise License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company.
+**
+** If you have questions regarding the use of this file, please use
+** contact form at http://www.qt.io/contact-us
+**
+****************************************************************************/
+
+#ifndef SQUISHXMLOUTPUTHANDLER_H
+#define SQUISHXMLOUTPUTHANDLER_H
+
+#include "testresult.h"
+
+#include <QObject>
+#include <QXmlStreamReader>
+
+namespace Autotest {
+namespace Internal {
+
+class SquishXmlOutputHandler : public QObject
+{
+ Q_OBJECT
+public:
+ explicit SquishXmlOutputHandler(QObject *parent = 0);
+ void clearForNextRun();
+
+ static void mergeResultFiles(const QStringList &reportFiles, const QString &resultsDirectory,
+ const QString &suiteName, QString *errorMessage = 0);
+
+signals:
+ void testResultCreated(const TestResult &testResult);
+
+public slots:
+ void outputAvailable(const QByteArray &output);
+
+private:
+ QXmlStreamReader m_xmlReader;
+};
+
+} // namespace Internal
+} // namespace Autotest
+
+#endif // SQUISHXMLOUTPUTHANDLER_H
diff --git a/plugins/autotest/testresult.cpp b/plugins/autotest/testresult.cpp
index 6a054a4c7d..2fe919e873 100644
--- a/plugins/autotest/testresult.cpp
+++ b/plugins/autotest/testresult.cpp
@@ -19,6 +19,8 @@
#include "testresult.h"
+#include <utils/qtcassert.h>
+
namespace Autotest {
namespace Internal {
@@ -93,6 +95,22 @@ Result::Type TestResult::toResultType(int rt)
return Result::MESSAGE_INTERNAL;
case Result::MESSAGE_CURRENT_TEST:
return Result::MESSAGE_CURRENT_TEST;
+ case Result::SQUISH_LOG:
+ return Result::SQUISH_LOG;
+ case Result::SQUISH_PASS:
+ return Result::SQUISH_PASS;
+ case Result::SQUISH_FAIL:
+ return Result::SQUISH_FAIL;
+ case Result::SQUISH_EXPECTED_FAIL:
+ return Result::SQUISH_EXPECTED_FAIL;
+ case Result::SQUISH_UNEXPECTED_PASS:
+ return Result::SQUISH_UNEXPECTED_PASS;
+ case Result::SQUISH_WARN:
+ return Result::SQUISH_WARN;
+ case Result::SQUISH_FATAL:
+ return Result::SQUISH_FATAL;
+ case Result::SQUISH_START:
+ return Result::SQUISH_START;
default:
return Result::UNKNOWN;
}
@@ -126,6 +144,26 @@ QString TestResult::resultToString(const Result::Type type)
return QLatin1String("BPASS");
case Result::BLACKLISTED_FAIL:
return QLatin1String("BFAIL");
+ case Result::SQUISH_LOG:
+ return QLatin1String("Log");
+ case Result::SQUISH_PASS:
+ return QLatin1String("Pass");
+ case Result::SQUISH_FAIL:
+ return QLatin1String("Fail");
+ case Result::SQUISH_ERROR:
+ return QLatin1String("Error");
+ case Result::SQUISH_FATAL:
+ return QLatin1String("Fatal");
+ case Result::SQUISH_EXPECTED_FAIL:
+ return QLatin1String("Expected Fail");
+ case Result::SQUISH_UNEXPECTED_PASS:
+ return QLatin1String("Unexpected Pass");
+ case Result::SQUISH_WARN:
+ return QLatin1String("Warning");
+ case Result::SQUISH_START:
+ return QLatin1String("Start");
+ case Result::SQUISH_END:
+ return QLatin1String("Test finished");
default:
return QLatin1String("UNKNOWN");
}
@@ -157,9 +195,37 @@ QColor TestResult::colorForType(const Result::Type type)
case Result::MESSAGE_INTERNAL:
case Result::MESSAGE_CURRENT_TEST:
return QColor("transparent");
+ case Result::SQUISH_LOG:
+ case Result::SQUISH_START:
+ case Result::SQUISH_END:
+ return QColor(0, 0, 0);
+ case Result::SQUISH_PASS:
+ return QColor(0, 0x99, 0);
+ case Result::SQUISH_FAIL:
+ case Result::SQUISH_ERROR:
+ return QColor(0xa0, 0, 0);
+ case Result::SQUISH_EXPECTED_FAIL:
+ return QColor(0, 0xff, 0);
+ case Result::SQUISH_UNEXPECTED_PASS:
+ return QColor(0xff, 0, 0);
+ case Result::SQUISH_WARN:
+ return QColor(0x86, 0, 0x86);
+ case Result::SQUISH_FATAL:
+ return QColor(0x64, 0, 0);
default:
- return QColor("#000000");
+ return QColor(0, 0, 0);
+ }
+}
+
+QString TestResult::maxString(const Result::Type type)
+{
+ if ((type >= Result::QTEST_GROUP_BEGIN && type <= Result::QTEST_GROUP_END)
+ || type == Result::UNKNOWN) {
+ return QLatin1String("UNKNOWN");
+ } else if (type >= Result::SQUISH_GROUP_BEGIN && type <= Result::SQUISH_GROUP_END) {
+ return QLatin1String("Unexpected Pass");
}
+ QTC_ASSERT(false, return QString());
}
bool operator==(const TestResult &t1, const TestResult &t2)
diff --git a/plugins/autotest/testresult.h b/plugins/autotest/testresult.h
index c1d6d5eac4..5037808daa 100644
--- a/plugins/autotest/testresult.h
+++ b/plugins/autotest/testresult.h
@@ -29,6 +29,7 @@ namespace Internal {
namespace Result{
enum Type {
+ // QTest / Quick Test
PASS,
FAIL,
EXPECTED_FAIL,
@@ -42,9 +43,27 @@ enum Type {
MESSAGE_FATAL,
MESSAGE_INTERNAL,
MESSAGE_CURRENT_TEST,
- UNKNOWN // ???
+ // Squish
+ SQUISH_LOG,
+ SQUISH_PASS,
+ SQUISH_FAIL,
+ SQUISH_EXPECTED_FAIL,
+ SQUISH_UNEXPECTED_PASS,
+ SQUISH_WARN,
+ SQUISH_ERROR,
+ SQUISH_FATAL,
+ SQUISH_START,
+ SQUISH_END,
+ // ???
+ UNKNOWN,
+
+ // group stuff
+ QTEST_GROUP_BEGIN = PASS,
+ QTEST_GROUP_END = MESSAGE_CURRENT_TEST,
+ SQUISH_GROUP_BEGIN = SQUISH_LOG,
+ SQUISH_GROUP_END = SQUISH_END
};
-}
+} // namespace Result
class TestResult
{
@@ -70,6 +89,7 @@ public:
static Result::Type toResultType(int rt);
static QString resultToString(const Result::Type type);
static QColor colorForType(const Result::Type type);
+ static QString maxString(const Result::Type type);
private:
QString m_class;
diff --git a/plugins/autotest/testresultdelegate.cpp b/plugins/autotest/testresultdelegate.cpp
index 0eedd68eef..158e98e7d8 100644
--- a/plugins/autotest/testresultdelegate.cpp
+++ b/plugins/autotest/testresultdelegate.cpp
@@ -73,9 +73,9 @@ void TestResultDelegate::paint(QPainter *painter, const QStyleOptionViewItem &op
painter->setPen(foreground);
TestResultFilterModel *resultFilterModel = static_cast<TestResultFilterModel *>(view->model());
TestResultModel *resultModel = static_cast<TestResultModel *>(resultFilterModel->sourceModel());
- LayoutPositions positions(opt, resultModel);
TestResult testResult = resultModel->testResult(resultFilterModel->mapToSource(index));
Result::Type type = testResult.result();
+ LayoutPositions positions(opt, resultModel, type);
QIcon icon = index.data(Qt::DecorationRole).value<QIcon>();
if (!icon.isNull())
@@ -119,6 +119,7 @@ void TestResultDelegate::paint(QPainter *painter, const QStyleOptionViewItem &op
output.append(QLatin1Char('\n')).append(desc.mid(breakPos));
}
break;
+ // SQUISH_XYZ will be handled with default as well
default:
output = desc;
if (!selected)
@@ -194,7 +195,8 @@ QSize TestResultDelegate::sizeHint(const QStyleOptionViewItem &option, const QMo
int fontHeight = fm.height();
TestResultFilterModel *resultFilterModel = static_cast<TestResultFilterModel *>(view->model());
TestResultModel *resultModel = static_cast<TestResultModel *>(resultFilterModel->sourceModel());
- LayoutPositions positions(opt, resultModel);
+ LayoutPositions positions(opt, resultModel,
+ TestResult::toResultType(index.data(Result::TypeRole).toInt()));
QSize s;
s.setWidth(opt.rect.width());
@@ -228,6 +230,7 @@ QSize TestResultDelegate::sizeHint(const QStyleOptionViewItem &option, const QMo
output.append(QLatin1Char('\n')).append(desc.mid(breakPos));
}
break;
+ // SQUISH_XYZ will be handled with default as well
default:
output = desc;
}
diff --git a/plugins/autotest/testresultdelegate.h b/plugins/autotest/testresultdelegate.h
index 8bc5d58ad8..3f06017643 100644
--- a/plugins/autotest/testresultdelegate.h
+++ b/plugins/autotest/testresultdelegate.h
@@ -48,7 +48,7 @@ private:
class LayoutPositions
{
public:
- LayoutPositions(QStyleOptionViewItemV4 &options, TestResultModel *model)
+ LayoutPositions(QStyleOptionViewItemV4 &options, TestResultModel *model, Result::Type type)
: m_totalWidth(options.rect.width()),
m_maxFileLength(model->maxWidthOfFileName(options.font)),
m_maxLineLength(model->maxWidthOfLineNumber(options.font)),
@@ -56,7 +56,7 @@ private:
m_top(options.rect.top()),
m_bottom(options.rect.bottom())
{
- m_typeAreaWidth = QFontMetrics(options.font).width(QLatin1String("XXXXXXXX"));
+ m_typeAreaWidth = QFontMetrics(options.font).width(TestResult::maxString(type));
int flexibleArea = lineAreaLeft() - textAreaLeft() - ITEM_SPACING;
if (m_maxFileLength > flexibleArea / 2)
m_realFileLength = flexibleArea / 2;
diff --git a/plugins/autotest/testresultmodel.cpp b/plugins/autotest/testresultmodel.cpp
index ee10470032..03fc6fb79a 100644
--- a/plugins/autotest/testresultmodel.cpp
+++ b/plugins/autotest/testresultmodel.cpp
@@ -107,6 +107,9 @@ QVariant TestResultModel::data(const QModelIndex &index, int role) const
const TestResult &tr = m_testResults.at(index.row());
return testResultIcon(tr.result());
}
+ if (role == Result::TypeRole) {
+ return m_testResults.at(index.row()).result();
+ }
return QVariant();
}
@@ -124,7 +127,8 @@ void TestResultModel::addTestResult(const TestResult &testResult)
const QModelIndex changed = index(m_testResults.size() - 1, 0, QModelIndex());
emit dataChanged(changed, changed);
} else {
- if (!isCurrentTestMssg && position) // decrement only if at least one other item
+ // decrement only if last message was of type MESSAGE_CURRENT_TEST
+ if (!isCurrentTestMssg && lastMssg.result() == Result::MESSAGE_CURRENT_TEST)
--position;
beginInsertRows(QModelIndex(), position, position);
m_testResults.insert(position, testResult);
@@ -222,7 +226,11 @@ void TestResultFilterModel::enableAllResultTypes()
<< Result::MESSAGE_WARN << Result::MESSAGE_INTERNAL
<< Result::MESSAGE_FATAL << Result::UNKNOWN << Result::BLACKLISTED_PASS
<< Result::BLACKLISTED_FAIL << Result::BENCHMARK
- << Result::MESSAGE_CURRENT_TEST;
+ << Result::MESSAGE_CURRENT_TEST
+ << Result::SQUISH_LOG << Result::SQUISH_PASS << Result::SQUISH_FAIL
+ << Result::SQUISH_EXPECTED_FAIL << Result::SQUISH_UNEXPECTED_PASS
+ << Result::SQUISH_WARN << Result::SQUISH_ERROR << Result::SQUISH_FATAL
+ << Result::SQUISH_START << Result::SQUISH_END;
invalidateFilter();
}
@@ -233,7 +241,26 @@ void TestResultFilterModel::toggleTestResultType(Result::Type type)
} else {
m_enabled.insert(type);
}
- invalidateFilter();
+
+ switch (type) {
+ case Result::PASS:
+ toggleTestResultType(Result::SQUISH_PASS);
+ break;
+ case Result::FAIL:
+ toggleTestResultType(Result::SQUISH_FAIL);
+ break;
+ case Result::EXPECTED_FAIL:
+ toggleTestResultType(Result::SQUISH_EXPECTED_FAIL);
+ break;
+ case Result::UNEXPECTED_PASS:
+ toggleTestResultType(Result::SQUISH_UNEXPECTED_PASS);
+ break;
+ case Result::MESSAGE_WARN:
+ toggleTestResultType(Result::SQUISH_WARN);
+ break;
+ default:
+ invalidateFilter();
+ }
}
void TestResultFilterModel::clearTestResults()
diff --git a/plugins/autotest/testresultmodel.h b/plugins/autotest/testresultmodel.h
index 97f3a3a53c..c6924291a5 100644
--- a/plugins/autotest/testresultmodel.h
+++ b/plugins/autotest/testresultmodel.h
@@ -30,6 +30,12 @@
namespace Autotest {
namespace Internal {
+namespace Result {
+ enum ItemRole {
+ TypeRole = Qt::UserRole
+ };
+} // namespace Result
+
class TestResultModel : public QAbstractItemModel
{
Q_OBJECT
diff --git a/plugins/autotest/testresultspane.cpp b/plugins/autotest/testresultspane.cpp
index 1378b6cfcd..d2425ce80b 100644
--- a/plugins/autotest/testresultspane.cpp
+++ b/plugins/autotest/testresultspane.cpp
@@ -170,6 +170,23 @@ void TestResultsPane::addLogoutput(const QString &output)
m_runnerServerLog->appendPlainText(output);
}
+void TestResultsPane::updateSquishSummaryLabel()
+{
+ const int passes = m_model->resultTypeCount(Result::SQUISH_PASS)
+ + m_model->resultTypeCount(Result::SQUISH_EXPECTED_FAIL);
+ const int fails = m_model->resultTypeCount(Result::SQUISH_FAIL)
+ + m_model->resultTypeCount(Result::SQUISH_UNEXPECTED_PASS);
+
+ const QString labelText = tr("<p><b>Test summary:</b>&nbsp;&nbsp; %1 passes, %2 fails, "
+ "%3 fatals, %4 errors, %5 warnings.</p>")
+ .arg(passes).arg(fails).arg(m_model->resultTypeCount(Result::SQUISH_FATAL))
+ .arg(m_model->resultTypeCount(Result::SQUISH_ERROR))
+ .arg(m_model->resultTypeCount(Result::SQUISH_WARN));
+
+ m_summaryLabel->setText(labelText);
+ m_summaryWidget->setVisible(true);
+}
+
QWidget *TestResultsPane::outputWidget(QWidget *parent)
{
if (m_outputPane) {
@@ -331,6 +348,7 @@ void TestResultsPane::initializeFilterMenu()
textAndType.insert(Result::MESSAGE_DEBUG, tr("Debug Messages"));
textAndType.insert(Result::MESSAGE_WARN, tr("Warning Messages"));
textAndType.insert(Result::MESSAGE_INTERNAL, tr("Internal Messages"));
+ textAndType.insert(Result::SQUISH_LOG, tr("Log Messages"));
foreach (Result::Type result, textAndType.keys()) {
QAction *action = new QAction(m_filterMenu);
action->setText(textAndType.value(result));
diff --git a/plugins/autotest/testresultspane.h b/plugins/autotest/testresultspane.h
index 765b6ff9ff..a448fe6f04 100644
--- a/plugins/autotest/testresultspane.h
+++ b/plugins/autotest/testresultspane.h
@@ -76,6 +76,7 @@ signals:
public slots:
void addTestResult(const TestResult &result);
void addLogoutput(const QString &output);
+ void updateSquishSummaryLabel();
private slots:
void onItemActivated(const QModelIndex &index);
diff --git a/plugins/autotest/testsquishtools.cpp b/plugins/autotest/testsquishtools.cpp
index 49739271ee..62bde4e62b 100644
--- a/plugins/autotest/testsquishtools.cpp
+++ b/plugins/autotest/testsquishtools.cpp
@@ -21,6 +21,7 @@
#include "squishsettings.h"
#include "testsquishtools.h"
#include "testresultspane.h"
+#include "squishxmloutputhandler.h"
#include <QDebug> // TODO remove
@@ -56,10 +57,16 @@ TestSquishTools::TestSquishTools(QObject *parent)
m_state(Idle),
m_currentResultsXML(0),
m_resultsFileWatcher(0),
- m_testRunning(false)
+ m_testRunning(false),
+ m_xmlOutputHandler(0)
{
+ TestResultsPane *resultPane = TestResultsPane::instance();
connect(this, &TestSquishTools::logOutputReceived,
- TestResultsPane::instance(), &TestResultsPane::addLogoutput, Qt::QueuedConnection);
+ resultPane, &TestResultsPane::addLogoutput, Qt::QueuedConnection);
+ connect(this, &TestSquishTools::squishTestRunStarted,
+ resultPane, &TestResultsPane::clearContents);
+ connect(this, &TestSquishTools::squishTestRunFinished,
+ resultPane, &TestResultsPane::updateSquishSummaryLabel);
}
TestSquishTools::~TestSquishTools()
@@ -80,6 +87,9 @@ TestSquishTools::~TestSquishTools()
delete m_serverProcess;
m_serverProcess = 0;
}
+
+ if (m_xmlOutputHandler)
+ delete m_xmlOutputHandler;
}
struct SquishToolsSettings
@@ -135,6 +145,12 @@ void TestSquishTools::runTestCases(const QString &suitePath, const QStringList &
<< QLatin1String("--resultdir")
<< QDir::toNativeSeparators(m_currentResultsDirectory);
+ if (m_xmlOutputHandler)
+ delete m_xmlOutputHandler;
+ m_xmlOutputHandler = new SquishXmlOutputHandler(this);
+ connect(this, &TestSquishTools::resultOutputCreated,
+ m_xmlOutputHandler, &SquishXmlOutputHandler::outputAvailable, Qt::QueuedConnection);
+
m_testRunning = true;
emit squishTestRunStarted();
startSquishServer(RunTestRequested);
@@ -212,9 +228,14 @@ void TestSquishTools::setState(TestSquishTools::State state)
if (m_testCases.isEmpty()) {
m_request = ServerStopRequested;
stopSquishServer();
- // TODO merge result files
+ QString error;
+ SquishXmlOutputHandler::mergeResultFiles(m_reportFiles, m_currentResultsDirectory,
+ QDir(m_suitePath).dirName(), &error);
+ if (!error.isEmpty())
+ QMessageBox::critical(Core::ICore::dialogParent(), tr("Error"), error);
logrotateTestResults();
} else {
+ m_xmlOutputHandler->clearForNextRun();
startSquishRunner();
}
break;
@@ -590,7 +611,7 @@ void TestSquishTools::onRunnerOutput(const QString)
if (firstNonWhitespace(output) == '<') {
// output that must be used for the TestResultsPane
- qDebug() << "RunnerOutput:" << output;
+ emit resultOutputCreated(output);
} else {
foreach (const QByteArray &line, output.split('\n')) {
const QByteArray trimmed = line.trimmed();
diff --git a/plugins/autotest/testsquishtools.h b/plugins/autotest/testsquishtools.h
index 65e23312ac..45e09a4719 100644
--- a/plugins/autotest/testsquishtools.h
+++ b/plugins/autotest/testsquishtools.h
@@ -33,6 +33,8 @@ QT_END_NAMESPACE
namespace Autotest {
namespace Internal {
+class SquishXmlOutputHandler;
+
class TestSquishTools : public QObject
{
Q_OBJECT
@@ -64,6 +66,7 @@ signals:
void logOutputReceived(const QString &output);
void squishTestRunStarted();
void squishTestRunFinished();
+ void resultOutputCreated(const QByteArray &output);
private:
enum Request
@@ -113,6 +116,7 @@ private:
QWindowList m_lastTopLevelWindows;
bool m_testRunning;
qint64 m_readResultsCount;
+ SquishXmlOutputHandler *m_xmlOutputHandler;
};
} // namespace Internal