2022-08-19 15:59:36 +02:00
|
|
|
// Copyright (C) 2016 The Qt Company Ltd.
|
2022-12-21 10:12:09 +01:00
|
|
|
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
2014-10-07 15:51:02 +02:00
|
|
|
|
2019-05-24 14:34:01 +02:00
|
|
|
#include "testresultmodel.h"
|
2020-10-09 13:07:55 +02:00
|
|
|
|
2016-11-03 16:35:55 +01:00
|
|
|
#include "autotesticons.h"
|
2023-06-27 10:48:31 +02:00
|
|
|
#include "testresultspane.h"
|
2019-05-24 14:34:01 +02:00
|
|
|
#include "testrunner.h"
|
2019-02-01 12:24:56 +01:00
|
|
|
#include "testsettings.h"
|
2020-09-11 14:30:15 +02:00
|
|
|
#include "testtreeitem.h"
|
|
|
|
|
#include "testtreemodel.h"
|
2014-10-07 15:51:02 +02:00
|
|
|
|
2019-02-01 12:24:56 +01:00
|
|
|
#include <projectexplorer/projectexplorericons.h>
|
2023-06-22 14:58:11 +02:00
|
|
|
#include <utils/algorithm.h>
|
2016-05-04 16:41:15 +02:00
|
|
|
#include <utils/qtcassert.h>
|
|
|
|
|
|
2014-10-07 15:51:02 +02:00
|
|
|
#include <QFontMetrics>
|
|
|
|
|
#include <QIcon>
|
2023-06-27 10:48:31 +02:00
|
|
|
#include <QToolButton>
|
2014-10-07 15:51:02 +02:00
|
|
|
|
2023-01-16 15:00:15 +01:00
|
|
|
using namespace Utils;
|
|
|
|
|
|
2014-10-07 15:51:02 +02:00
|
|
|
namespace Autotest {
|
|
|
|
|
namespace Internal {
|
|
|
|
|
|
2015-08-20 15:59:15 +02:00
|
|
|
/********************************* TestResultItem ******************************************/
|
2014-10-07 15:51:02 +02:00
|
|
|
|
2023-01-14 16:25:51 +01:00
|
|
|
TestResultItem::TestResultItem(const TestResult &testResult)
|
2015-08-20 15:59:15 +02:00
|
|
|
: m_testResult(testResult)
|
2014-10-07 15:51:02 +02:00
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
2019-02-06 14:11:19 +01:00
|
|
|
static QIcon testResultIcon(ResultType result) {
|
2016-11-03 16:35:55 +01:00
|
|
|
const static QIcon icons[] = {
|
|
|
|
|
Icons::RESULT_PASS.icon(),
|
|
|
|
|
Icons::RESULT_FAIL.icon(),
|
|
|
|
|
Icons::RESULT_XFAIL.icon(),
|
|
|
|
|
Icons::RESULT_XPASS.icon(),
|
|
|
|
|
Icons::RESULT_SKIP.icon(),
|
|
|
|
|
Icons::RESULT_BLACKLISTEDPASS.icon(),
|
|
|
|
|
Icons::RESULT_BLACKLISTEDFAIL.icon(),
|
2019-01-24 08:53:31 +01:00
|
|
|
Icons::RESULT_BLACKLISTEDXPASS.icon(),
|
|
|
|
|
Icons::RESULT_BLACKLISTEDXFAIL.icon(),
|
2016-11-03 16:35:55 +01:00
|
|
|
Icons::RESULT_BENCHMARK.icon(),
|
|
|
|
|
Icons::RESULT_MESSAGEDEBUG.icon(),
|
|
|
|
|
Icons::RESULT_MESSAGEDEBUG.icon(), // Info gets the same handling as Debug for now
|
|
|
|
|
Icons::RESULT_MESSAGEWARN.icon(),
|
|
|
|
|
Icons::RESULT_MESSAGEFATAL.icon(),
|
|
|
|
|
Icons::RESULT_MESSAGEFATAL.icon(), // System gets same handling as Fatal for now
|
2019-12-11 11:28:06 +01:00
|
|
|
Icons::RESULT_MESSAGEFATAL.icon(), // Error gets same handling as Fatal for now
|
2019-02-01 12:24:56 +01:00
|
|
|
ProjectExplorer::Icons::DESKTOP_DEVICE.icon(), // for now
|
2014-10-21 13:10:37 +02:00
|
|
|
}; // provide an icon for unknown??
|
2014-10-07 15:51:02 +02:00
|
|
|
|
2019-02-06 14:11:19 +01:00
|
|
|
if (result < ResultType::FIRST_TYPE || result >= ResultType::MessageInternal) {
|
2015-08-20 15:59:15 +02:00
|
|
|
switch (result) {
|
2019-02-06 14:11:19 +01:00
|
|
|
case ResultType::Application:
|
2019-12-11 11:28:06 +01:00
|
|
|
return icons[16];
|
2015-08-20 15:59:15 +02:00
|
|
|
default:
|
|
|
|
|
return QIcon();
|
|
|
|
|
}
|
|
|
|
|
}
|
2019-02-06 14:11:19 +01:00
|
|
|
return icons[int(result)];
|
2014-10-07 15:51:02 +02:00
|
|
|
}
|
|
|
|
|
|
2022-08-26 10:30:00 +02:00
|
|
|
static QIcon testSummaryIcon(const std::optional<TestResultItem::SummaryEvaluation> &summary)
|
2019-04-15 16:08:10 +02:00
|
|
|
{
|
|
|
|
|
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();
|
|
|
|
|
}
|
|
|
|
|
|
2015-08-20 15:59:15 +02:00
|
|
|
QVariant TestResultItem::data(int column, int role) const
|
2014-10-07 15:51:02 +02:00
|
|
|
{
|
2016-02-29 09:56:30 +01:00
|
|
|
switch (role) {
|
2018-08-18 21:48:34 +03:00
|
|
|
case Qt::DecorationRole: {
|
2023-01-14 16:25:51 +01:00
|
|
|
if (!m_testResult.isValid())
|
|
|
|
|
return {};
|
|
|
|
|
const ResultType result = m_testResult.result();
|
2019-02-06 14:11:19 +01:00
|
|
|
if (result == ResultType::MessageLocation && parent())
|
2018-08-18 21:48:34 +03:00
|
|
|
return parent()->data(column, role);
|
2019-04-15 16:08:10 +02:00
|
|
|
if (result == ResultType::TestStart)
|
|
|
|
|
return testSummaryIcon(m_summaryResult);
|
2018-08-18 21:48:34 +03:00
|
|
|
return testResultIcon(result);
|
|
|
|
|
}
|
2016-02-29 09:56:30 +01:00
|
|
|
case Qt::DisplayRole:
|
2023-01-14 16:25:51 +01:00
|
|
|
return m_testResult.isValid() ? m_testResult.outputString(true) : QVariant();
|
2016-02-29 09:56:30 +01:00
|
|
|
default:
|
2023-01-16 15:00:15 +01:00
|
|
|
return TreeItem::data(column, role);
|
2016-02-29 09:56:30 +01:00
|
|
|
}
|
2015-08-20 15:59:15 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void TestResultItem::updateDescription(const QString &description)
|
|
|
|
|
{
|
2023-01-14 16:25:51 +01:00
|
|
|
QTC_ASSERT(m_testResult.isValid(), return);
|
|
|
|
|
m_testResult.setDescription(description);
|
2015-08-20 15:59:15 +02:00
|
|
|
}
|
|
|
|
|
|
2019-04-15 16:08:10 +02:00
|
|
|
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:
|
2021-09-06 13:41:25 +02:00
|
|
|
QTC_ASSERT_STRING("Got unexpected type in isSignificant check");
|
2019-04-15 16:08:10 +02:00
|
|
|
return false;
|
|
|
|
|
default:
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void TestResultItem::updateResult(bool &changed, ResultType addedChildType,
|
2022-08-26 10:30:00 +02:00
|
|
|
const std::optional<SummaryEvaluation> &summary)
|
2015-08-20 15:59:15 +02:00
|
|
|
{
|
2017-12-13 13:10:00 +01:00
|
|
|
changed = false;
|
2023-01-14 16:25:51 +01:00
|
|
|
if (m_testResult.result() != ResultType::TestStart)
|
2017-12-13 13:10:00 +01:00
|
|
|
return;
|
2019-04-15 16:08:10 +02:00
|
|
|
|
|
|
|
|
if (!isSignificant(addedChildType) || (addedChildType == ResultType::TestStart && !summary))
|
2015-08-20 15:59:15 +02:00
|
|
|
return;
|
|
|
|
|
|
2019-04-15 16:08:10 +02:00
|
|
|
if (m_summaryResult.has_value() && m_summaryResult->failed && m_summaryResult->warnings)
|
|
|
|
|
return; // can't become worse
|
|
|
|
|
|
|
|
|
|
SummaryEvaluation newResult = m_summaryResult.value_or(SummaryEvaluation());
|
2017-12-13 13:10:00 +01:00
|
|
|
switch (addedChildType) {
|
2019-02-06 14:11:19 +01:00
|
|
|
case ResultType::Fail:
|
|
|
|
|
case ResultType::MessageFatal:
|
|
|
|
|
case ResultType::UnexpectedPass:
|
2019-04-15 16:08:10 +02:00
|
|
|
if (newResult.failed)
|
|
|
|
|
return;
|
|
|
|
|
newResult.failed = true;
|
2017-12-13 13:10:00 +01:00
|
|
|
break;
|
2019-02-06 14:11:19 +01:00
|
|
|
case ResultType::ExpectedFail:
|
|
|
|
|
case ResultType::MessageWarn:
|
|
|
|
|
case ResultType::MessageSystem:
|
|
|
|
|
case ResultType::Skip:
|
|
|
|
|
case ResultType::BlacklistedFail:
|
|
|
|
|
case ResultType::BlacklistedPass:
|
|
|
|
|
case ResultType::BlacklistedXFail:
|
|
|
|
|
case ResultType::BlacklistedXPass:
|
2019-04-15 16:08:10 +02:00
|
|
|
if (newResult.warnings)
|
|
|
|
|
return;
|
|
|
|
|
newResult.warnings = true;
|
2017-12-13 13:10:00 +01:00
|
|
|
break;
|
2019-04-15 16:08:10 +02:00
|
|
|
case ResultType::TestStart:
|
|
|
|
|
if (summary) {
|
|
|
|
|
newResult.failed |= summary->failed;
|
|
|
|
|
newResult.warnings |= summary->warnings;
|
|
|
|
|
}
|
2017-12-13 13:10:00 +01:00
|
|
|
break;
|
|
|
|
|
default:
|
2019-01-31 15:45:28 +01:00
|
|
|
break;
|
2014-10-07 15:51:02 +02:00
|
|
|
}
|
2019-04-15 16:08:10 +02:00
|
|
|
changed = !m_summaryResult.has_value() || m_summaryResult.value() != newResult;
|
|
|
|
|
|
2017-12-13 13:10:00 +01:00
|
|
|
if (changed)
|
2019-04-15 16:08:10 +02:00
|
|
|
m_summaryResult.emplace(newResult);
|
2016-10-31 13:11:52 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TestResultItem *TestResultItem::intermediateFor(const TestResultItem *item) const
|
|
|
|
|
{
|
|
|
|
|
QTC_ASSERT(item, return nullptr);
|
2023-01-14 16:25:51 +01:00
|
|
|
const TestResult otherResult = item->testResult();
|
2016-10-31 13:11:52 +01:00
|
|
|
for (int row = childCount() - 1; row >= 0; --row) {
|
2019-02-06 08:57:33 +01:00
|
|
|
TestResultItem *child = childAt(row);
|
2023-01-14 16:25:51 +01:00
|
|
|
const TestResult testResult = child->testResult();
|
|
|
|
|
if (testResult.result() != ResultType::TestStart)
|
2016-10-31 13:11:52 +01:00
|
|
|
continue;
|
2023-01-14 16:25:51 +01:00
|
|
|
if (testResult.isIntermediateFor(otherResult))
|
2016-10-31 13:11:52 +01:00
|
|
|
return child;
|
|
|
|
|
}
|
2017-02-13 10:05:06 +01:00
|
|
|
return nullptr;
|
2016-10-31 13:11:52 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TestResultItem *TestResultItem::createAndAddIntermediateFor(const TestResultItem *child)
|
|
|
|
|
{
|
2023-01-14 16:25:51 +01:00
|
|
|
TestResult result = child->testResult().intermediateResult();
|
|
|
|
|
QTC_ASSERT(result.isValid(), return nullptr);
|
|
|
|
|
result.setResult(ResultType::TestStart);
|
2016-10-31 13:11:52 +01:00
|
|
|
TestResultItem *intermediate = new TestResultItem(result);
|
|
|
|
|
appendChild(intermediate);
|
2023-06-27 10:48:31 +02:00
|
|
|
// FIXME: make the expand button's state easier accessible
|
|
|
|
|
auto widgets = TestResultsPane::instance()->toolBarWidgets();
|
|
|
|
|
if (!widgets.empty()) {
|
|
|
|
|
if (QToolButton *expand = qobject_cast<QToolButton *>(widgets.at(0))) {
|
|
|
|
|
if (expand->isChecked()) {
|
|
|
|
|
QMetaObject::invokeMethod(TestResultsPane::instance(),
|
|
|
|
|
[intermediate] { intermediate->expand(); },
|
|
|
|
|
Qt::QueuedConnection);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2016-10-31 13:11:52 +01:00
|
|
|
return intermediate;
|
|
|
|
|
}
|
|
|
|
|
|
2019-04-15 16:08:10 +02:00
|
|
|
QString TestResultItem::resultString() const
|
|
|
|
|
{
|
2023-01-14 16:25:51 +01:00
|
|
|
if (testResult().result() != ResultType::TestStart)
|
|
|
|
|
return TestResult::resultToString(testResult().result());
|
2019-04-15 16:08:10 +02:00
|
|
|
if (!m_summaryResult)
|
2023-01-14 16:25:51 +01:00
|
|
|
return {};
|
2019-04-15 16:08:10 +02:00
|
|
|
return m_summaryResult->failed ? QString("FAIL") : QString("PASS");
|
|
|
|
|
}
|
|
|
|
|
|
2023-02-28 09:15:40 +01:00
|
|
|
//! \return true if descendant types have changed, false otherwise
|
|
|
|
|
bool TestResultItem::updateDescendantTypes(ResultType t)
|
|
|
|
|
{
|
|
|
|
|
if (t == ResultType::TestStart || t == ResultType::TestEnd) // these are special
|
|
|
|
|
return false;
|
|
|
|
|
|
2023-06-22 14:58:11 +02:00
|
|
|
return Utils::insert(m_descendantsTypes, t);
|
2023-02-28 09:15:40 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool TestResultItem::descendantTypesContainsAnyOf(const QSet<ResultType> &types) const
|
|
|
|
|
{
|
|
|
|
|
return !m_descendantsTypes.isEmpty() && m_descendantsTypes.intersects(types);
|
|
|
|
|
}
|
|
|
|
|
|
2015-08-20 15:59:15 +02:00
|
|
|
/********************************* TestResultModel *****************************************/
|
|
|
|
|
|
|
|
|
|
TestResultModel::TestResultModel(QObject *parent)
|
2023-01-16 15:00:15 +01:00
|
|
|
: TreeModel<TestResultItem>(new TestResultItem({}), parent)
|
2015-08-20 15:59:15 +02:00
|
|
|
{
|
2019-05-24 14:34:01 +02:00
|
|
|
connect(TestRunner::instance(), &TestRunner::reportSummary,
|
|
|
|
|
this, [this](const QString &id, const QHash<ResultType, int> &summary){
|
|
|
|
|
m_reportedSummary.insert(id, summary);
|
|
|
|
|
});
|
2014-10-07 15:51:02 +02:00
|
|
|
}
|
|
|
|
|
|
2017-12-13 13:10:00 +01:00
|
|
|
void TestResultModel::updateParent(const TestResultItem *item)
|
|
|
|
|
{
|
|
|
|
|
QTC_ASSERT(item, return);
|
2023-01-14 16:25:51 +01:00
|
|
|
QTC_ASSERT(item->testResult().isValid(), return);
|
2019-02-06 08:57:33 +01:00
|
|
|
TestResultItem *parentItem = item->parent();
|
2017-12-13 13:10:00 +01:00
|
|
|
if (parentItem == rootItem()) // do not update invisible root item
|
|
|
|
|
return;
|
|
|
|
|
bool changed = false;
|
2023-01-14 16:25:51 +01:00
|
|
|
parentItem->updateResult(changed, item->testResult().result(), item->summaryResult());
|
2023-02-28 09:15:40 +01:00
|
|
|
bool changedType = parentItem->updateDescendantTypes(item->testResult().result());
|
|
|
|
|
if (!changed && !changedType)
|
2017-12-13 13:10:00 +01:00
|
|
|
return;
|
|
|
|
|
emit dataChanged(parentItem->index(), parentItem->index());
|
2019-02-06 08:57:33 +01:00
|
|
|
updateParent(parentItem);
|
2017-12-13 13:10:00 +01:00
|
|
|
}
|
|
|
|
|
|
2020-09-11 14:30:15 +02:00
|
|
|
static bool isFailed(ResultType type)
|
|
|
|
|
{
|
|
|
|
|
switch (type) {
|
|
|
|
|
case ResultType::Fail: case ResultType::UnexpectedPass: case ResultType::MessageFatal:
|
|
|
|
|
return true;
|
|
|
|
|
default:
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-01-14 16:25:51 +01:00
|
|
|
void TestResultModel::addTestResult(const TestResult &testResult, bool autoExpand)
|
2015-08-20 15:59:15 +02:00
|
|
|
{
|
2016-10-31 13:11:52 +01:00
|
|
|
const int lastRow = rootItem()->childCount() - 1;
|
2023-01-14 16:25:51 +01:00
|
|
|
if (testResult.result() == ResultType::MessageCurrentTest) {
|
2015-12-07 08:26:54 +01:00
|
|
|
// MessageCurrentTest should always be the last top level item
|
2015-08-20 15:59:15 +02:00
|
|
|
if (lastRow >= 0) {
|
2019-02-06 08:57:33 +01:00
|
|
|
TestResultItem *current = rootItem()->childAt(lastRow);
|
2023-01-14 16:25:51 +01:00
|
|
|
const TestResult result = current->testResult();
|
|
|
|
|
if (result.isValid() && result.result() == ResultType::MessageCurrentTest) {
|
|
|
|
|
current->updateDescription(testResult.description());
|
2015-08-20 15:59:15 +02:00
|
|
|
emit dataChanged(current->index(), current->index());
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2015-12-09 07:52:15 +01:00
|
|
|
rootItem()->appendChild(new TestResultItem(testResult));
|
2015-08-20 15:59:15 +02:00
|
|
|
return;
|
2014-12-05 14:01:16 +01:00
|
|
|
}
|
|
|
|
|
|
2023-01-14 16:25:51 +01:00
|
|
|
m_testResultCount[testResult.id()][testResult.result()]++;
|
2016-10-31 10:32:34 +01:00
|
|
|
|
2015-12-09 07:52:15 +01:00
|
|
|
TestResultItem *newItem = new TestResultItem(testResult);
|
2019-02-01 12:24:56 +01:00
|
|
|
TestResultItem *root = nullptr;
|
2023-05-12 11:00:00 +02:00
|
|
|
if (TestSettings::instance()->displayApplication()) {
|
2023-01-14 16:25:51 +01:00
|
|
|
const QString application = testResult.id();
|
2019-02-01 12:24:56 +01:00
|
|
|
if (!application.isEmpty()) {
|
2019-02-06 08:57:33 +01:00
|
|
|
root = rootItem()->findFirstLevelChild([&application](TestResultItem *child) {
|
|
|
|
|
QTC_ASSERT(child, return false);
|
2023-01-14 16:25:51 +01:00
|
|
|
return child->testResult().id() == application;
|
2019-02-06 08:57:33 +01:00
|
|
|
});
|
|
|
|
|
|
2019-02-01 12:24:56 +01:00
|
|
|
if (!root) {
|
2023-01-14 16:25:51 +01:00
|
|
|
TestResult tmpAppResult(application, application);
|
|
|
|
|
tmpAppResult.setResult(ResultType::Application);
|
|
|
|
|
root = new TestResultItem(tmpAppResult);
|
2019-02-01 12:24:56 +01:00
|
|
|
if (lastRow >= 0)
|
|
|
|
|
rootItem()->insertChild(lastRow, root);
|
|
|
|
|
else
|
|
|
|
|
rootItem()->appendChild(root);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TestResultItem *parentItem = findParentItemFor(newItem, root);
|
2023-01-14 16:25:51 +01:00
|
|
|
addFileName(testResult.fileName().fileName()); // ensure we calculate the results pane correctly
|
2016-10-31 13:11:52 +01:00
|
|
|
if (parentItem) {
|
|
|
|
|
parentItem->appendChild(newItem);
|
2020-07-09 09:14:03 +02:00
|
|
|
if (autoExpand) {
|
2023-06-22 15:22:35 +02:00
|
|
|
QMetaObject::invokeMethod(this, [parentItem]{ parentItem->expand(); },
|
|
|
|
|
Qt::QueuedConnection);
|
2020-07-09 09:14:03 +02:00
|
|
|
}
|
2017-12-13 13:10:00 +01:00
|
|
|
updateParent(newItem);
|
2016-10-31 13:11:52 +01:00
|
|
|
} else {
|
|
|
|
|
if (lastRow >= 0) {
|
2019-02-06 08:57:33 +01:00
|
|
|
TestResultItem *current = rootItem()->childAt(lastRow);
|
2023-01-14 16:25:51 +01:00
|
|
|
const TestResult result = current->testResult();
|
|
|
|
|
if (result.isValid() && result.result() == ResultType::MessageCurrentTest) {
|
2016-10-31 13:11:52 +01:00
|
|
|
rootItem()->insertChild(current->index().row(), newItem);
|
2015-12-09 09:46:33 +01:00
|
|
|
return;
|
2015-08-20 15:59:15 +02:00
|
|
|
}
|
|
|
|
|
}
|
2016-10-31 13:11:52 +01:00
|
|
|
// there is no MessageCurrentTest at the last row, but we have a toplevel item - just add it
|
|
|
|
|
rootItem()->appendChild(newItem);
|
2014-12-05 14:01:16 +01:00
|
|
|
}
|
2020-09-11 14:30:15 +02:00
|
|
|
|
2023-01-14 16:25:51 +01:00
|
|
|
if (isFailed(testResult.result())) {
|
|
|
|
|
if (const ITestTreeItem *it = testResult.findTestTreeItem()) {
|
2020-09-11 14:30:15 +02:00
|
|
|
TestTreeModel *model = TestTreeModel::instance();
|
|
|
|
|
model->setData(model->indexForItem(it), true, FailedRole);
|
|
|
|
|
}
|
|
|
|
|
}
|
2014-10-07 15:51:02 +02:00
|
|
|
}
|
|
|
|
|
|
2014-12-05 14:01:16 +01:00
|
|
|
void TestResultModel::removeCurrentTestMessage()
|
|
|
|
|
{
|
2019-02-06 08:57:33 +01:00
|
|
|
TestResultItem *currentMessageItem = rootItem()->findFirstLevelChild([](TestResultItem *it) {
|
2023-01-14 16:25:51 +01:00
|
|
|
return (it->testResult().result() == ResultType::MessageCurrentTest);
|
2019-02-06 08:57:33 +01:00
|
|
|
});
|
|
|
|
|
if (currentMessageItem)
|
|
|
|
|
destroyItem(currentMessageItem);
|
2014-12-05 14:01:16 +01:00
|
|
|
}
|
|
|
|
|
|
2014-10-07 15:51:02 +02:00
|
|
|
void TestResultModel::clearTestResults()
|
|
|
|
|
{
|
2015-08-20 15:59:15 +02:00
|
|
|
clear();
|
2014-11-05 15:27:49 +01:00
|
|
|
m_testResultCount.clear();
|
2019-05-24 14:34:01 +02:00
|
|
|
m_reportedSummary.clear();
|
2015-12-14 12:48:58 +01:00
|
|
|
m_disabled = 0;
|
2016-10-31 13:11:52 +01:00
|
|
|
m_fileNames.clear();
|
2014-10-21 13:10:37 +02:00
|
|
|
m_maxWidthOfFileName = 0;
|
|
|
|
|
m_widthOfLineNumber = 0;
|
2014-10-07 15:51:02 +02:00
|
|
|
}
|
|
|
|
|
|
2023-01-14 16:25:51 +01:00
|
|
|
TestResult TestResultModel::testResult(const QModelIndex &idx)
|
2014-10-07 15:51:02 +02:00
|
|
|
{
|
2015-08-20 15:59:15 +02:00
|
|
|
if (idx.isValid())
|
2019-02-06 08:57:33 +01:00
|
|
|
return itemForIndex(idx)->testResult();
|
2023-01-14 16:25:51 +01:00
|
|
|
return {};
|
2014-10-07 15:51:02 +02:00
|
|
|
}
|
|
|
|
|
|
2016-10-31 13:11:52 +01:00
|
|
|
void TestResultModel::recalculateMaxWidthOfFileName(const QFont &font)
|
2014-10-07 15:51:02 +02:00
|
|
|
{
|
2015-08-20 15:59:15 +02:00
|
|
|
const QFontMetrics fm(font);
|
2016-10-31 13:11:52 +01:00
|
|
|
m_maxWidthOfFileName = 0;
|
2022-10-07 14:46:06 +02:00
|
|
|
for (const QString &fileName : std::as_const(m_fileNames)) {
|
2021-05-26 15:50:03 +02:00
|
|
|
m_maxWidthOfFileName = qMax(m_maxWidthOfFileName, fm.horizontalAdvance(fileName));
|
2014-10-07 15:51:02 +02:00
|
|
|
}
|
2016-10-31 13:11:52 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void TestResultModel::addFileName(const QString &fileName)
|
|
|
|
|
{
|
|
|
|
|
const QFontMetrics fm(m_measurementFont);
|
2021-05-26 15:50:03 +02:00
|
|
|
m_maxWidthOfFileName = qMax(m_maxWidthOfFileName, fm.horizontalAdvance(fileName));
|
2016-10-31 13:11:52 +01:00
|
|
|
m_fileNames.insert(fileName);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int TestResultModel::maxWidthOfFileName(const QFont &font)
|
|
|
|
|
{
|
|
|
|
|
if (font != m_measurementFont)
|
|
|
|
|
recalculateMaxWidthOfFileName(font);
|
2014-10-07 15:51:02 +02:00
|
|
|
return m_maxWidthOfFileName;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int TestResultModel::maxWidthOfLineNumber(const QFont &font)
|
|
|
|
|
{
|
|
|
|
|
if (m_widthOfLineNumber == 0 || font != m_measurementFont) {
|
|
|
|
|
QFontMetrics fm(font);
|
|
|
|
|
m_measurementFont = font;
|
2019-02-11 10:32:46 +01:00
|
|
|
m_widthOfLineNumber = fm.horizontalAdvance("88888");
|
2014-10-07 15:51:02 +02:00
|
|
|
}
|
|
|
|
|
return m_widthOfLineNumber;
|
|
|
|
|
}
|
|
|
|
|
|
2019-05-24 14:34:01 +02:00
|
|
|
int TestResultModel::resultTypeCount(ResultType type) const
|
|
|
|
|
{
|
|
|
|
|
int result = 0;
|
2020-12-08 15:41:46 +01:00
|
|
|
for (auto it = m_testResultCount.cbegin(); it != m_testResultCount.cend(); ++it) {
|
2020-09-23 09:17:39 +02:00
|
|
|
// if we got a result count from the framework prefer that over our counted results
|
2020-12-08 15:41:46 +01:00
|
|
|
int reported = m_reportedSummary[it.key()].value(type);
|
|
|
|
|
result += reported != 0 ? reported : it.value().value(type);
|
2019-05-24 14:34:01 +02:00
|
|
|
}
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
2016-10-31 13:11:52 +01:00
|
|
|
TestResultItem *TestResultModel::findParentItemFor(const TestResultItem *item,
|
|
|
|
|
const TestResultItem *startItem) const
|
|
|
|
|
{
|
|
|
|
|
QTC_ASSERT(item, return nullptr);
|
|
|
|
|
TestResultItem *root = startItem ? const_cast<TestResultItem *>(startItem) : nullptr;
|
2023-01-14 16:25:51 +01:00
|
|
|
const TestResult result = item->testResult();
|
|
|
|
|
const QString &name = result.name();
|
|
|
|
|
const QString &id = result.id();
|
2016-10-31 13:11:52 +01:00
|
|
|
|
2016-12-19 13:54:53 +01:00
|
|
|
if (root == nullptr && !name.isEmpty()) {
|
2016-10-31 13:11:52 +01:00
|
|
|
for (int row = rootItem()->childCount() - 1; row >= 0; --row) {
|
2019-02-06 08:57:33 +01:00
|
|
|
TestResultItem *tmp = rootItem()->childAt(row);
|
2023-01-14 16:25:51 +01:00
|
|
|
const TestResult tmpTestResult = tmp->testResult();
|
|
|
|
|
if (tmpTestResult.id() == id && tmpTestResult.name() == name) {
|
2016-10-31 13:11:52 +01:00
|
|
|
root = tmp;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (root == nullptr)
|
|
|
|
|
return root;
|
|
|
|
|
|
|
|
|
|
bool needsIntermediate = false;
|
2023-01-16 15:00:15 +01:00
|
|
|
auto predicate = [result, &needsIntermediate](TreeItem *it) {
|
2016-10-31 13:11:52 +01:00
|
|
|
TestResultItem *currentItem = static_cast<TestResultItem *>(it);
|
2023-01-14 16:25:51 +01:00
|
|
|
return currentItem->testResult().isDirectParentOf(result, &needsIntermediate);
|
2016-10-31 13:11:52 +01:00
|
|
|
};
|
2019-02-06 08:57:33 +01:00
|
|
|
TestResultItem *parent = root->reverseFindAnyChild(predicate);
|
2016-10-31 13:11:52 +01:00
|
|
|
if (parent) {
|
|
|
|
|
if (needsIntermediate) {
|
|
|
|
|
// check if the intermediate is present already
|
|
|
|
|
if (TestResultItem *intermediate = parent->intermediateFor(item))
|
|
|
|
|
return intermediate;
|
|
|
|
|
return parent->createAndAddIntermediateFor(item);
|
|
|
|
|
}
|
|
|
|
|
return parent;
|
|
|
|
|
}
|
|
|
|
|
return root;
|
|
|
|
|
}
|
|
|
|
|
|
2014-10-21 13:10:37 +02:00
|
|
|
/********************************** Filter Model **********************************/
|
|
|
|
|
|
|
|
|
|
TestResultFilterModel::TestResultFilterModel(TestResultModel *sourceModel, QObject *parent)
|
|
|
|
|
: QSortFilterProxyModel(parent),
|
|
|
|
|
m_sourceModel(sourceModel)
|
|
|
|
|
{
|
|
|
|
|
setSourceModel(sourceModel);
|
2019-04-16 09:21:36 +02:00
|
|
|
enableAllResultTypes(true);
|
2014-10-21 13:10:37 +02:00
|
|
|
}
|
|
|
|
|
|
2019-04-16 09:21:36 +02:00
|
|
|
void TestResultFilterModel::enableAllResultTypes(bool enabled)
|
2014-10-21 13:10:37 +02:00
|
|
|
{
|
2019-04-16 09:21:36 +02:00
|
|
|
if (enabled) {
|
2019-05-08 12:41:25 +02:00
|
|
|
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
|
2023-02-28 09:15:40 +01:00
|
|
|
<< ResultType::MessageCurrentTest
|
2019-12-11 11:28:06 +01:00
|
|
|
<< ResultType::MessageInfo << ResultType::MessageSystem << ResultType::Application
|
|
|
|
|
<< ResultType::MessageError;
|
2019-04-16 09:21:36 +02:00
|
|
|
} else {
|
|
|
|
|
m_enabled.clear();
|
2019-12-11 11:28:06 +01:00
|
|
|
m_enabled << ResultType::MessageFatal << ResultType::MessageSystem
|
|
|
|
|
<< ResultType::MessageError;
|
2019-04-16 09:21:36 +02:00
|
|
|
}
|
2014-10-21 13:10:37 +02:00
|
|
|
invalidateFilter();
|
|
|
|
|
}
|
|
|
|
|
|
2019-02-06 14:11:19 +01:00
|
|
|
void TestResultFilterModel::toggleTestResultType(ResultType type)
|
2014-10-21 13:10:37 +02:00
|
|
|
{
|
2023-06-22 14:58:11 +02:00
|
|
|
if (m_enabled.remove(type)) {
|
2019-02-06 14:11:19 +01:00
|
|
|
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);
|
2014-10-21 13:10:37 +02:00
|
|
|
} else {
|
|
|
|
|
m_enabled.insert(type);
|
2019-02-06 14:11:19 +01:00
|
|
|
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);
|
2014-10-21 13:10:37 +02:00
|
|
|
}
|
|
|
|
|
invalidateFilter();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void TestResultFilterModel::clearTestResults()
|
|
|
|
|
{
|
|
|
|
|
m_sourceModel->clearTestResults();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool TestResultFilterModel::hasResults()
|
|
|
|
|
{
|
|
|
|
|
return rowCount(QModelIndex());
|
|
|
|
|
}
|
|
|
|
|
|
2023-01-14 16:25:51 +01:00
|
|
|
TestResult TestResultFilterModel::testResult(const QModelIndex &index) const
|
2014-10-21 13:10:37 +02:00
|
|
|
{
|
|
|
|
|
return m_sourceModel->testResult(mapToSource(index));
|
|
|
|
|
}
|
|
|
|
|
|
2019-04-15 16:08:10 +02:00
|
|
|
TestResultItem *TestResultFilterModel::itemForIndex(const QModelIndex &index) const
|
|
|
|
|
{
|
|
|
|
|
return index.isValid() ? m_sourceModel->itemForIndex(mapToSource(index)) : nullptr;
|
|
|
|
|
}
|
|
|
|
|
|
2014-10-21 13:10:37 +02:00
|
|
|
bool TestResultFilterModel::filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const
|
|
|
|
|
{
|
|
|
|
|
QModelIndex index = m_sourceModel->index(sourceRow, 0, sourceParent);
|
|
|
|
|
if (!index.isValid())
|
|
|
|
|
return false;
|
2023-02-28 09:15:40 +01:00
|
|
|
|
2023-01-14 16:25:51 +01:00
|
|
|
const ResultType resultType = m_sourceModel->testResult(index).result();
|
2019-04-15 16:08:10 +02:00
|
|
|
if (resultType == ResultType::TestStart) {
|
2023-02-28 09:15:40 +01:00
|
|
|
auto item = m_sourceModel->itemForIndex(index);
|
|
|
|
|
return item && item->descendantTypesContainsAnyOf(m_enabled);
|
|
|
|
|
} else if (resultType == ResultType::TestEnd) {
|
|
|
|
|
auto item = m_sourceModel->itemForIndex(index);
|
|
|
|
|
if (!item)
|
|
|
|
|
return false;
|
|
|
|
|
auto parent = item->parent();
|
|
|
|
|
return parent && parent->descendantTypesContainsAnyOf(m_enabled);
|
2016-06-15 13:28:50 +02:00
|
|
|
}
|
|
|
|
|
|
2023-02-28 09:15:40 +01:00
|
|
|
return m_enabled.contains(resultType);
|
2014-10-21 13:10:37 +02:00
|
|
|
}
|
|
|
|
|
|
2014-10-07 15:51:02 +02:00
|
|
|
} // namespace Internal
|
|
|
|
|
} // namespace Autotest
|