aboutsummaryrefslogtreecommitdiffstats
path: root/src/plugins/autotest/testresultmodel.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/plugins/autotest/testresultmodel.cpp')
-rw-r--r--src/plugins/autotest/testresultmodel.cpp261
1 files changed, 155 insertions, 106 deletions
diff --git a/src/plugins/autotest/testresultmodel.cpp b/src/plugins/autotest/testresultmodel.cpp
index deb6e1dfae..a3c6ec28a8 100644
--- a/src/plugins/autotest/testresultmodel.cpp
+++ b/src/plugins/autotest/testresultmodel.cpp
@@ -23,10 +23,11 @@
**
****************************************************************************/
+#include "testresultmodel.h"
#include "autotesticons.h"
#include "autotestplugin.h"
#include "testresultdelegate.h"
-#include "testresultmodel.h"
+#include "testrunner.h"
#include "testsettings.h"
#include <projectexplorer/projectexplorericons.h>
@@ -45,7 +46,7 @@ TestResultItem::TestResultItem(const TestResultPtr &testResult)
{
}
-static QIcon testResultIcon(Result::Type result) {
+static QIcon testResultIcon(ResultType result) {
const static QIcon icons[] = {
Icons::RESULT_PASS.icon(),
Icons::RESULT_FAIL.icon(),
@@ -62,29 +63,27 @@ static QIcon testResultIcon(Result::Type result) {
Icons::RESULT_MESSAGEWARN.icon(),
Icons::RESULT_MESSAGEFATAL.icon(),
Icons::RESULT_MESSAGEFATAL.icon(), // System gets same handling as Fatal for now
- QIcon(),
- Icons::RESULT_MESSAGEPASSWARN.icon(),
- Icons::RESULT_MESSAGEFAILWARN.icon(),
ProjectExplorer::Icons::DESKTOP_DEVICE.icon(), // for now
}; // provide an icon for unknown??
- if (result < 0 || result >= Result::MessageInternal) {
+ if (result < ResultType::FIRST_TYPE || result >= ResultType::MessageInternal) {
switch (result) {
- case Result::MessageTestCaseSuccess:
- return icons[Result::Pass];
- case Result::MessageTestCaseFail:
- return icons[Result::Fail];
- case Result::MessageTestCaseSuccessWarn:
- return icons[16];
- case Result::MessageTestCaseFailWarn:
- return icons[17];
- case Result::Application:
- return icons[18];
+ case ResultType::Application:
+ return icons[15];
default:
return QIcon();
}
}
- return icons[result];
+ return icons[int(result)];
+}
+
+static QIcon testSummaryIcon(const Utils::optional<TestResultItem::SummaryEvaluation> &summary)
+{
+ if (!summary)
+ return QIcon();
+ if (summary->failed)
+ return summary->warnings ? Icons::RESULT_MESSAGEFAILWARN.icon() : Icons::RESULT_FAIL.icon();
+ return summary->warnings ? Icons::RESULT_MESSAGEPASSWARN.icon() : Icons::RESULT_PASS.icon();
}
QVariant TestResultItem::data(int column, int role) const
@@ -93,9 +92,11 @@ QVariant TestResultItem::data(int column, int role) const
case Qt::DecorationRole: {
if (!m_testResult)
return QVariant();
- const Result::Type result = m_testResult->result();
- if (result == Result::MessageLocation && parent())
+ const ResultType result = m_testResult->result();
+ if (result == ResultType::MessageLocation && parent())
return parent()->data(column, role);
+ if (result == ResultType::TestStart)
+ return testSummaryIcon(m_summaryResult);
return testResultIcon(result);
}
case Qt::DisplayRole:
@@ -112,50 +113,72 @@ void TestResultItem::updateDescription(const QString &description)
m_testResult->setDescription(description);
}
-void TestResultItem::updateResult(bool &changed, Result::Type addedChildType)
+static bool isSignificant(ResultType type)
+{
+ switch (type) {
+ case ResultType::Benchmark:
+ case ResultType::MessageInfo:
+ case ResultType::MessageInternal:
+ case ResultType::TestEnd:
+ return false;
+ case ResultType::MessageLocation:
+ case ResultType::MessageCurrentTest:
+ case ResultType::Application:
+ case ResultType::Invalid:
+ QTC_ASSERT_STRING("Got unexpedted type in isSignificant check");
+ return false;
+ default:
+ return true;
+ }
+}
+
+void TestResultItem::updateResult(bool &changed, ResultType addedChildType,
+ const Utils::optional<SummaryEvaluation> &summary)
{
changed = false;
- const Result::Type old = m_testResult->result();
- if (old == Result::MessageTestCaseFailWarn) // can't become worse
+ if (m_testResult->result() != ResultType::TestStart)
return;
- if (!TestResult::isMessageCaseStart(old))
+
+ if (!isSignificant(addedChildType) || (addedChildType == ResultType::TestStart && !summary))
return;
- Result::Type newResult = old;
+ if (m_summaryResult.has_value() && m_summaryResult->failed && m_summaryResult->warnings)
+ return; // can't become worse
+
+ SummaryEvaluation newResult = m_summaryResult.value_or(SummaryEvaluation());
switch (addedChildType) {
- case Result::Fail:
- case Result::MessageFatal:
- case Result::UnexpectedPass:
- case Result::MessageTestCaseFail:
- newResult = (old == Result::MessageTestCaseSuccessWarn) ? Result::MessageTestCaseFailWarn
- : Result::MessageTestCaseFail;
+ case ResultType::Fail:
+ case ResultType::MessageFatal:
+ case ResultType::UnexpectedPass:
+ if (newResult.failed)
+ return;
+ newResult.failed = true;
break;
- case Result::MessageTestCaseFailWarn:
- newResult = Result::MessageTestCaseFailWarn;
+ case ResultType::ExpectedFail:
+ case ResultType::MessageWarn:
+ case ResultType::MessageSystem:
+ case ResultType::Skip:
+ case ResultType::BlacklistedFail:
+ case ResultType::BlacklistedPass:
+ case ResultType::BlacklistedXFail:
+ case ResultType::BlacklistedXPass:
+ if (newResult.warnings)
+ return;
+ newResult.warnings = true;
break;
- case Result::ExpectedFail:
- case Result::MessageWarn:
- case Result::MessageSystem:
- case Result::Skip:
- case Result::BlacklistedFail:
- case Result::BlacklistedPass:
- case Result::BlacklistedXFail:
- case Result::BlacklistedXPass:
- case Result::MessageTestCaseSuccessWarn:
- newResult = (old == Result::MessageTestCaseFail) ? Result::MessageTestCaseFailWarn
- : Result::MessageTestCaseSuccessWarn;
- break;
- case Result::Pass:
- case Result::MessageTestCaseSuccess:
- newResult = (old == Result::MessageIntermediate || old == Result::MessageTestCaseStart)
- ? Result::MessageTestCaseSuccess : old;
+ case ResultType::TestStart:
+ if (summary) {
+ newResult.failed |= summary->failed;
+ newResult.warnings |= summary->warnings;
+ }
break;
default:
break;
}
- changed = old != newResult;
+ changed = !m_summaryResult.has_value() || m_summaryResult.value() != newResult;
+
if (changed)
- m_testResult->setResult(newResult);
+ m_summaryResult.emplace(newResult);
}
TestResultItem *TestResultItem::intermediateFor(const TestResultItem *item) const
@@ -165,7 +188,7 @@ TestResultItem *TestResultItem::intermediateFor(const TestResultItem *item) cons
for (int row = childCount() - 1; row >= 0; --row) {
TestResultItem *child = childAt(row);
const TestResult *testResult = child->testResult();
- if (testResult->result() != Result::MessageIntermediate)
+ if (testResult->result() != ResultType::TestStart)
continue;
if (testResult->isIntermediateFor(otherResult))
return child;
@@ -177,17 +200,30 @@ TestResultItem *TestResultItem::createAndAddIntermediateFor(const TestResultItem
{
TestResultPtr result(m_testResult->createIntermediateResultFor(child->testResult()));
QTC_ASSERT(!result.isNull(), return nullptr);
- result->setResult(Result::MessageIntermediate);
+ result->setResult(ResultType::TestStart);
TestResultItem *intermediate = new TestResultItem(result);
appendChild(intermediate);
return intermediate;
}
+QString TestResultItem::resultString() const
+{
+ if (testResult()->result() != ResultType::TestStart)
+ return TestResult::resultToString(testResult()->result());
+ if (!m_summaryResult)
+ return QString();
+ return m_summaryResult->failed ? QString("FAIL") : QString("PASS");
+}
+
/********************************* TestResultModel *****************************************/
TestResultModel::TestResultModel(QObject *parent)
: Utils::TreeModel<TestResultItem>(new TestResultItem(TestResultPtr()), parent)
{
+ connect(TestRunner::instance(), &TestRunner::reportSummary,
+ this, [this](const QString &id, const QHash<ResultType, int> &summary){
+ m_reportedSummary.insert(id, summary);
+ });
}
void TestResultModel::updateParent(const TestResultItem *item)
@@ -198,7 +234,7 @@ void TestResultModel::updateParent(const TestResultItem *item)
if (parentItem == rootItem()) // do not update invisible root item
return;
bool changed = false;
- parentItem->updateResult(changed, item->testResult()->result());
+ parentItem->updateResult(changed, item->testResult()->result(), item->summaryResult());
if (!changed)
return;
emit dataChanged(parentItem->index(), parentItem->index());
@@ -208,12 +244,12 @@ void TestResultModel::updateParent(const TestResultItem *item)
void TestResultModel::addTestResult(const TestResultPtr &testResult, bool autoExpand)
{
const int lastRow = rootItem()->childCount() - 1;
- if (testResult->result() == Result::MessageCurrentTest) {
+ if (testResult->result() == ResultType::MessageCurrentTest) {
// MessageCurrentTest should always be the last top level item
if (lastRow >= 0) {
TestResultItem *current = rootItem()->childAt(lastRow);
const TestResult *result = current->testResult();
- if (result && result->result() == Result::MessageCurrentTest) {
+ if (result && result->result() == ResultType::MessageCurrentTest) {
current->updateDescription(testResult->description());
emit dataChanged(current->index(), current->index());
return;
@@ -224,12 +260,9 @@ void TestResultModel::addTestResult(const TestResultPtr &testResult, bool autoEx
return;
}
- if (testResult->result() == Result::MessageDisabledTests)
- m_disabled += testResult->line();
- m_testResultCount[testResult->result()]++;
+ m_testResultCount[testResult->id()][testResult->result()]++;
TestResultItem *newItem = new TestResultItem(testResult);
-
TestResultItem *root = nullptr;
if (AutotestPlugin::settings()->displayApplication) {
const QString application = testResult->id();
@@ -241,7 +274,7 @@ void TestResultModel::addTestResult(const TestResultPtr &testResult, bool autoEx
if (!root) {
TestResult *tmpAppResult = new TestResult(application, application);
- tmpAppResult->setResult(Result::Application);
+ tmpAppResult->setResult(ResultType::Application);
root = new TestResultItem(TestResultPtr(tmpAppResult));
if (lastRow >= 0)
rootItem()->insertChild(lastRow, root);
@@ -262,7 +295,7 @@ void TestResultModel::addTestResult(const TestResultPtr &testResult, bool autoEx
if (lastRow >= 0) {
TestResultItem *current = rootItem()->childAt(lastRow);
const TestResult *result = current->testResult();
- if (result && result->result() == Result::MessageCurrentTest) {
+ if (result && result->result() == ResultType::MessageCurrentTest) {
rootItem()->insertChild(current->index().row(), newItem);
return;
}
@@ -275,7 +308,7 @@ void TestResultModel::addTestResult(const TestResultPtr &testResult, bool autoEx
void TestResultModel::removeCurrentTestMessage()
{
TestResultItem *currentMessageItem = rootItem()->findFirstLevelChild([](TestResultItem *it) {
- return (it->testResult()->result() == Result::MessageCurrentTest);
+ return (it->testResult()->result() == ResultType::MessageCurrentTest);
});
if (currentMessageItem)
destroyItem(currentMessageItem);
@@ -285,6 +318,7 @@ void TestResultModel::clearTestResults()
{
clear();
m_testResultCount.clear();
+ m_reportedSummary.clear();
m_disabled = 0;
m_fileNames.clear();
m_maxWidthOfFileName = 0;
@@ -305,7 +339,7 @@ void TestResultModel::recalculateMaxWidthOfFileName(const QFont &font)
m_maxWidthOfFileName = 0;
for (const QString &fileName : m_fileNames) {
int pos = fileName.lastIndexOf('/');
- m_maxWidthOfFileName = qMax(m_maxWidthOfFileName, fm.width(fileName.mid(pos + 1)));
+ m_maxWidthOfFileName = qMax(m_maxWidthOfFileName, fm.horizontalAdvance(fileName.mid(pos + 1)));
}
}
@@ -313,7 +347,7 @@ void TestResultModel::addFileName(const QString &fileName)
{
const QFontMetrics fm(m_measurementFont);
int pos = fileName.lastIndexOf('/');
- m_maxWidthOfFileName = qMax(m_maxWidthOfFileName, fm.width(fileName.mid(pos + 1)));
+ m_maxWidthOfFileName = qMax(m_maxWidthOfFileName, fm.horizontalAdvance(fileName.mid(pos + 1)));
m_fileNames.insert(fileName);
}
@@ -329,11 +363,26 @@ int TestResultModel::maxWidthOfLineNumber(const QFont &font)
if (m_widthOfLineNumber == 0 || font != m_measurementFont) {
QFontMetrics fm(font);
m_measurementFont = font;
- m_widthOfLineNumber = fm.width("88888");
+ m_widthOfLineNumber = fm.horizontalAdvance("88888");
}
return m_widthOfLineNumber;
}
+int TestResultModel::resultTypeCount(ResultType type) const
+{
+ int result = 0;
+
+ for (auto resultsForId : m_testResultCount.values())
+ result += resultsForId.value(type, 0);
+
+ for (auto id : m_reportedSummary.keys()) {
+ if (int counted = m_testResultCount.value(id).value(type))
+ result -= counted;
+ result += m_reportedSummary[id].value(type);
+ }
+ return result;
+}
+
TestResultItem *TestResultModel::findParentItemFor(const TestResultItem *item,
const TestResultItem *startItem) const
{
@@ -387,42 +436,39 @@ TestResultFilterModel::TestResultFilterModel(TestResultModel *sourceModel, QObje
void TestResultFilterModel::enableAllResultTypes(bool enabled)
{
if (enabled) {
- m_enabled << Result::Pass << Result::Fail << Result::ExpectedFail
- << Result::UnexpectedPass << Result::Skip << Result::MessageDebug
- << Result::MessageWarn << Result::MessageInternal << Result::MessageLocation
- << Result::MessageFatal << Result::Invalid << Result::BlacklistedPass
- << Result::BlacklistedFail << Result::BlacklistedXFail << Result::BlacklistedXPass
- << Result::Benchmark << Result::MessageIntermediate
- << Result::MessageCurrentTest << Result::MessageTestCaseStart
- << Result::MessageTestCaseSuccess << Result::MessageTestCaseSuccessWarn
- << Result::MessageTestCaseFail << Result::MessageTestCaseFailWarn
- << Result::MessageTestCaseEnd
- << Result::MessageInfo << Result::MessageSystem << Result::Application;
+ m_enabled << ResultType::Pass << ResultType::Fail << ResultType::ExpectedFail
+ << ResultType::UnexpectedPass << ResultType::Skip << ResultType::MessageDebug
+ << ResultType::MessageWarn << ResultType::MessageInternal << ResultType::MessageLocation
+ << ResultType::MessageFatal << ResultType::Invalid << ResultType::BlacklistedPass
+ << ResultType::BlacklistedFail << ResultType::BlacklistedXFail << ResultType::BlacklistedXPass
+ << ResultType::Benchmark
+ << ResultType::MessageCurrentTest << ResultType::TestStart << ResultType::TestEnd
+ << ResultType::MessageInfo << ResultType::MessageSystem << ResultType::Application;
} else {
m_enabled.clear();
- m_enabled << Result::MessageFatal << Result::MessageSystem;
+ m_enabled << ResultType::MessageFatal << ResultType::MessageSystem;
}
invalidateFilter();
}
-void TestResultFilterModel::toggleTestResultType(Result::Type type)
+void TestResultFilterModel::toggleTestResultType(ResultType type)
{
if (m_enabled.contains(type)) {
m_enabled.remove(type);
- if (type == Result::MessageInternal)
- m_enabled.remove(Result::MessageTestCaseEnd);
- if (type == Result::MessageDebug)
- m_enabled.remove(Result::MessageInfo);
- if (type == Result::MessageWarn)
- m_enabled.remove(Result::MessageSystem);
+ if (type == ResultType::MessageInternal)
+ m_enabled.remove(ResultType::TestEnd);
+ if (type == ResultType::MessageDebug)
+ m_enabled.remove(ResultType::MessageInfo);
+ if (type == ResultType::MessageWarn)
+ m_enabled.remove(ResultType::MessageSystem);
} else {
m_enabled.insert(type);
- if (type == Result::MessageInternal)
- m_enabled.insert(Result::MessageTestCaseEnd);
- if (type == Result::MessageDebug)
- m_enabled.insert(Result::MessageInfo);
- if (type == Result::MessageWarn)
- m_enabled.insert(Result::MessageSystem);
+ if (type == ResultType::MessageInternal)
+ m_enabled.insert(ResultType::TestEnd);
+ if (type == ResultType::MessageDebug)
+ m_enabled.insert(ResultType::MessageInfo);
+ if (type == ResultType::MessageWarn)
+ m_enabled.insert(ResultType::MessageSystem);
}
invalidateFilter();
}
@@ -442,38 +488,41 @@ const TestResult *TestResultFilterModel::testResult(const QModelIndex &index) co
return m_sourceModel->testResult(mapToSource(index));
}
+TestResultItem *TestResultFilterModel::itemForIndex(const QModelIndex &index) const
+{
+ return index.isValid() ? m_sourceModel->itemForIndex(mapToSource(index)) : nullptr;
+}
+
bool TestResultFilterModel::filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const
{
QModelIndex index = m_sourceModel->index(sourceRow, 0, sourceParent);
if (!index.isValid())
return false;
- Result::Type resultType = m_sourceModel->testResult(index)->result();
- switch (resultType) {
- case Result::MessageTestCaseSuccess:
- return m_enabled.contains(Result::Pass);
- case Result::MessageTestCaseFail:
- case Result::MessageTestCaseSuccessWarn:
- case Result::MessageTestCaseFailWarn:
+ ResultType resultType = m_sourceModel->testResult(index)->result();
+ if (resultType == ResultType::TestStart) {
+ TestResultItem *item = m_sourceModel->itemForIndex(index);
+ QTC_ASSERT(item, return false);
+ if (!item->summaryResult())
+ return true;
return acceptTestCaseResult(index);
- default:
- return m_enabled.contains(resultType);
}
+ return m_enabled.contains(resultType);
}
bool TestResultFilterModel::acceptTestCaseResult(const QModelIndex &srcIndex) const
{
for (int row = 0, count = m_sourceModel->rowCount(srcIndex); row < count; ++row) {
const QModelIndex &child = m_sourceModel->index(row, 0, srcIndex);
- Result::Type type = m_sourceModel->testResult(child)->result();
- if (type == Result::MessageTestCaseSuccess)
- type = Result::Pass;
- if (type == Result::MessageTestCaseFail || type == Result::MessageTestCaseFailWarn
- || type == Result::MessageTestCaseSuccessWarn) {
+ TestResultItem *item = m_sourceModel->itemForIndex(child);
+ ResultType type = item->testResult()->result();
+
+ if (type == ResultType::TestStart) {
+ if (!item->summaryResult())
+ return true;
if (acceptTestCaseResult(child))
return true;
- } else if (m_enabled.contains(type)) {
+ } else if (m_enabled.contains(type))
return true;
- }
}
return false;
}