Files
qt-creator/src/plugins/autotest/testresultmodel.cpp
Christian Stenger d7dc7159b2 AutoTest: Filter out test case summary as well
If results are filtered and the filtering results in omitting
all entries of a test case filter out the test case as well.

Change-Id: Icd3b18566ed45a68b2ee630a2f13be80257f6b26
Reviewed-by: David Schulz <david.schulz@theqtcompany.com>
Reviewed-by: Christian Stenger <christian.stenger@qt.io>
2016-06-17 04:58:52 +00:00

366 lines
12 KiB
C++

/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#include "testresultdelegate.h"
#include "testresultmodel.h"
#include <utils/qtcassert.h>
#include <QFontMetrics>
#include <QIcon>
namespace Autotest {
namespace Internal {
/********************************* TestResultItem ******************************************/
TestResultItem::TestResultItem(const TestResultPtr &testResult)
: m_testResult(testResult)
{
}
TestResultItem::~TestResultItem()
{
}
static QIcon testResultIcon(Result::Type result) {
static QIcon icons[11] = {
QIcon(QLatin1String(":/images/pass.png")),
QIcon(QLatin1String(":/images/fail.png")),
QIcon(QLatin1String(":/images/xfail.png")),
QIcon(QLatin1String(":/images/xpass.png")),
QIcon(QLatin1String(":/images/skip.png")),
QIcon(QLatin1String(":/images/blacklisted_pass.png")),
QIcon(QLatin1String(":/images/blacklisted_fail.png")),
QIcon(QLatin1String(":/images/benchmark.png")),
QIcon(QLatin1String(":/images/debug.png")),
QIcon(QLatin1String(":/images/warn.png")),
QIcon(QLatin1String(":/images/fatal.png")),
}; // provide an icon for unknown??
if (result < 0 || result >= Result::MessageInternal) {
switch (result) {
case Result::MessageTestCaseSuccess:
return icons[Result::Pass];
case Result::MessageTestCaseFail:
return icons[Result::Fail];
case Result::MessageTestCaseWarn:
return icons[Result::MessageWarn];
default:
return QIcon();
}
}
return icons[result];
}
QVariant TestResultItem::data(int column, int role) const
{
switch (role) {
case Qt::DecorationRole:
return m_testResult ? testResultIcon(m_testResult->result()) : QVariant();
case Qt::DisplayRole:
return m_testResult ? m_testResult->outputString(true) : QVariant();
default:
return Utils::TreeItem::data(column, role);
}
}
void TestResultItem::updateDescription(const QString &description)
{
QTC_ASSERT(m_testResult, return);
m_testResult->setDescription(description);
}
void TestResultItem::updateResult()
{
if (m_testResult->result() != Result::MessageTestCaseStart)
return;
Result::Type newResult = Result::MessageTestCaseSuccess;
foreach (Utils::TreeItem *child, children()) {
const TestResult *current = static_cast<TestResultItem *>(child)->testResult();
if (current) {
switch (current->result()) {
case Result::Fail:
case Result::MessageFatal:
case Result::UnexpectedPass:
m_testResult->setResult(Result::MessageTestCaseFail);
return;
case Result::ExpectedFail:
case Result::MessageWarn:
case Result::Skip:
case Result::BlacklistedFail:
case Result::BlacklistedPass:
newResult = Result::MessageTestCaseWarn;
break;
default: {}
}
}
}
m_testResult->setResult(newResult);
}
/********************************* TestResultModel *****************************************/
TestResultModel::TestResultModel(QObject *parent)
: Utils::TreeModel(parent),
m_widthOfLineNumber(0),
m_maxWidthOfFileName(0),
m_disabled(0)
{
}
QVariant TestResultModel::data(const QModelIndex &idx, int role) const
{
if (!idx.isValid())
return QVariant();
if (role == Qt::DecorationRole || role == Qt::DisplayRole)
return itemForIndex(idx)->data(0, role);
return QVariant();
}
void TestResultModel::addTestResult(const TestResultPtr &testResult, bool autoExpand)
{
const bool isCurrentTestMssg = testResult->result() == Result::MessageCurrentTest;
QVector<Utils::TreeItem *> topLevelItems = rootItem()->children();
int lastRow = topLevelItems.size() - 1;
// we'll add the new item, so raising it's counter
if (!isCurrentTestMssg) {
int count = m_testResultCount.value(testResult->result(), 0);
if (testResult->result() == Result::MessageDisabledTests)
m_disabled += testResult->line();
m_testResultCount.insert(testResult->result(), ++count);
} else {
// MessageCurrentTest should always be the last top level item
if (lastRow >= 0) {
TestResultItem *current = static_cast<TestResultItem *>(topLevelItems.at(lastRow));
const TestResult *result = current->testResult();
if (result && result->result() == Result::MessageCurrentTest) {
current->updateDescription(testResult->description());
emit dataChanged(current->index(), current->index());
return;
}
}
rootItem()->appendChild(new TestResultItem(testResult));
return;
}
TestResultItem *newItem = new TestResultItem(testResult);
// FIXME this might be totally wrong... we need some more unique information!
if (!testResult->name().isEmpty()) {
for (int row = lastRow; row >= 0; --row) {
TestResultItem *current = static_cast<TestResultItem *>(topLevelItems.at(row));
const TestResult *result = current->testResult();
if (result && result->name() == testResult->name()) {
current->appendChild(newItem);
if (autoExpand)
current->expand();
if (testResult->result() == Result::MessageTestCaseEnd) {
current->updateResult();
emit dataChanged(current->index(), current->index());
}
return;
}
}
}
// if we have a MessageCurrentTest present, add the new top level item before it
if (lastRow >= 0) {
TestResultItem *current = static_cast<TestResultItem *>(topLevelItems.at(lastRow));
const TestResult *result = current->testResult();
if (result && result->result() == Result::MessageCurrentTest) {
rootItem()->insertChild(current->index().row(), newItem);
return;
}
}
rootItem()->appendChild(newItem);
}
void TestResultModel::removeCurrentTestMessage()
{
QVector<Utils::TreeItem *> topLevelItems = rootItem()->children();
for (int row = topLevelItems.size() - 1; row >= 0; --row) {
TestResultItem *current = static_cast<TestResultItem *>(topLevelItems.at(row));
if (current->testResult()->result() == Result::MessageCurrentTest) {
delete takeItem(current);
break;
}
}
}
void TestResultModel::clearTestResults()
{
clear();
m_testResultCount.clear();
m_disabled = 0;
m_processedIndices.clear();
m_maxWidthOfFileName = 0;
m_widthOfLineNumber = 0;
}
const TestResult *TestResultModel::testResult(const QModelIndex &idx)
{
if (idx.isValid())
return static_cast<TestResultItem *>(itemForIndex(idx))->testResult();
return 0;
}
int TestResultModel::maxWidthOfFileName(const QFont &font)
{
if (font != m_measurementFont) {
m_processedIndices.clear();
m_maxWidthOfFileName = 0;
m_measurementFont = font;
}
const QFontMetrics fm(font);
const QVector<Utils::TreeItem *> &topLevelItems = rootItem()->children();
const int count = topLevelItems.size();
for (int row = 0; row < count; ++row) {
int processed = row < m_processedIndices.size() ? m_processedIndices.at(row) : 0;
const QVector<Utils::TreeItem *> &children = topLevelItems.at(row)->children();
const int itemCount = children.size();
if (processed < itemCount) {
for (int childRow = processed; childRow < itemCount; ++childRow) {
const TestResultItem *item = static_cast<TestResultItem *>(children.at(childRow));
if (const TestResult *result = item->testResult()) {
QString fileName = result->fileName();
const int pos = fileName.lastIndexOf(QLatin1Char('/'));
if (pos != -1)
fileName = fileName.mid(pos + 1);
m_maxWidthOfFileName = qMax(m_maxWidthOfFileName, fm.width(fileName));
}
}
if (row < m_processedIndices.size())
m_processedIndices.replace(row, itemCount);
else
m_processedIndices.insert(row, itemCount);
}
}
return m_maxWidthOfFileName;
}
int TestResultModel::maxWidthOfLineNumber(const QFont &font)
{
if (m_widthOfLineNumber == 0 || font != m_measurementFont) {
QFontMetrics fm(font);
m_measurementFont = font;
m_widthOfLineNumber = fm.width(QLatin1String("88888"));
}
return m_widthOfLineNumber;
}
/********************************** Filter Model **********************************/
TestResultFilterModel::TestResultFilterModel(TestResultModel *sourceModel, QObject *parent)
: QSortFilterProxyModel(parent),
m_sourceModel(sourceModel)
{
setSourceModel(sourceModel);
enableAllResultTypes();
}
void TestResultFilterModel::enableAllResultTypes()
{
m_enabled << Result::Pass << Result::Fail << Result::ExpectedFail
<< Result::UnexpectedPass << Result::Skip << Result::MessageDebug
<< Result::MessageWarn << Result::MessageInternal
<< Result::MessageFatal << Result::Invalid << Result::BlacklistedPass
<< Result::BlacklistedFail << Result::Benchmark
<< Result::MessageCurrentTest << Result::MessageTestCaseStart
<< Result::MessageTestCaseSuccess << Result::MessageTestCaseWarn
<< Result::MessageTestCaseFail << Result::MessageTestCaseEnd
<< Result::MessageTestCaseRepetition;
invalidateFilter();
}
void TestResultFilterModel::toggleTestResultType(Result::Type type)
{
if (m_enabled.contains(type)) {
m_enabled.remove(type);
if (type == Result::MessageInternal)
m_enabled.remove(Result::MessageTestCaseEnd);
} else {
m_enabled.insert(type);
if (type == Result::MessageInternal)
m_enabled.insert(Result::MessageTestCaseEnd);
}
invalidateFilter();
}
void TestResultFilterModel::clearTestResults()
{
m_sourceModel->clearTestResults();
}
bool TestResultFilterModel::hasResults()
{
return rowCount(QModelIndex());
}
const TestResult *TestResultFilterModel::testResult(const QModelIndex &index) const
{
return m_sourceModel->testResult(mapToSource(index));
}
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::MessageTestCaseWarn:
return acceptTestCaseResult(index);
default:
return m_enabled.contains(resultType);
}
}
bool TestResultFilterModel::acceptTestCaseResult(const QModelIndex &index) const
{
Utils::TreeItem *item = m_sourceModel->itemForIndex(index);
QTC_ASSERT(item, return false);
for (const Utils::TreeItem *child : item->children()) {
const TestResultItem *resultItem = static_cast<const TestResultItem *>(child);
if (m_enabled.contains(resultItem->testResult()->result()))
return true;
}
return false;
}
} // namespace Internal
} // namespace Autotest