2014-10-07 12:30:54 +02:00
|
|
|
/****************************************************************************
|
|
|
|
|
**
|
2016-01-22 10:37:55 +01:00
|
|
|
** Copyright (C) 2016 The Qt Company Ltd.
|
|
|
|
|
** Contact: https://www.qt.io/licensing/
|
2014-10-07 12:30:54 +02:00
|
|
|
**
|
2016-01-22 10:37:55 +01:00
|
|
|
** This file is part of Qt Creator.
|
2014-10-07 12:30:54 +02:00
|
|
|
**
|
2016-01-22 10:37:55 +01:00
|
|
|
** Commercial License Usage
|
|
|
|
|
** Licensees holding valid commercial Qt licenses may use this file in
|
|
|
|
|
** accordance with the commercial license agreement provided with the
|
2014-10-07 12:30:54 +02:00
|
|
|
** Software or, alternatively, in accordance with the terms contained in
|
2016-01-22 10:37:55 +01:00
|
|
|
** 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.
|
2014-10-07 12:30:54 +02:00
|
|
|
**
|
2016-01-22 10:37:55 +01:00
|
|
|
** 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.
|
2014-10-07 12:30:54 +02:00
|
|
|
**
|
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
2014-11-11 17:30:34 +01:00
|
|
|
#include "autotestconstants.h"
|
2016-02-01 15:12:10 +01:00
|
|
|
#include "autotestplugin.h"
|
2014-10-07 12:30:54 +02:00
|
|
|
#include "testcodeparser.h"
|
2016-02-01 15:12:10 +01:00
|
|
|
#include "testsettings.h"
|
2014-10-07 12:30:54 +02:00
|
|
|
#include "testtreeitem.h"
|
|
|
|
|
#include "testtreemodel.h"
|
|
|
|
|
|
2014-10-21 13:10:37 +02:00
|
|
|
#include <cpptools/cppmodelmanager.h>
|
2014-10-07 15:51:02 +02:00
|
|
|
#include <projectexplorer/project.h>
|
|
|
|
|
#include <projectexplorer/session.h>
|
2015-02-12 15:48:24 +01:00
|
|
|
#include <qmljs/qmljsmodelmanagerinterface.h>
|
2014-10-21 13:10:37 +02:00
|
|
|
#include <texteditor/texteditor.h>
|
2015-04-27 16:11:28 +02:00
|
|
|
#include <utils/qtcassert.h>
|
2014-10-21 13:10:37 +02:00
|
|
|
|
2014-10-07 12:30:54 +02:00
|
|
|
namespace Autotest {
|
|
|
|
|
namespace Internal {
|
|
|
|
|
|
|
|
|
|
TestTreeModel::TestTreeModel(QObject *parent) :
|
2015-09-10 15:32:12 +02:00
|
|
|
TreeModel(parent),
|
2016-02-23 15:56:52 +01:00
|
|
|
m_autoTestRootItem(new AutoTestTreeItem(tr("Auto Tests"), QString(), TestTreeItem::Root)),
|
|
|
|
|
m_quickTestRootItem(new QuickTestTreeItem(tr("Qt Quick Tests"), QString(), TestTreeItem::Root)),
|
|
|
|
|
m_googleTestRootItem(new GoogleTestTreeItem(tr("Google Tests"), QString(), TestTreeItem::Root)),
|
2015-02-12 15:48:24 +01:00
|
|
|
m_parser(new TestCodeParser(this)),
|
2015-02-19 11:19:59 +01:00
|
|
|
m_connectionsInitialized(false)
|
2014-10-07 12:30:54 +02:00
|
|
|
{
|
2015-09-10 15:32:12 +02:00
|
|
|
rootItem()->appendChild(m_autoTestRootItem);
|
|
|
|
|
rootItem()->appendChild(m_quickTestRootItem);
|
2015-12-07 15:15:00 +01:00
|
|
|
rootItem()->appendChild(m_googleTestRootItem);
|
2015-02-05 16:07:45 +01:00
|
|
|
|
2016-01-25 13:05:12 +01:00
|
|
|
connect(m_parser, &TestCodeParser::aboutToPerformFullParse, this,
|
2015-02-13 15:44:18 +01:00
|
|
|
&TestTreeModel::removeAllTestItems, Qt::QueuedConnection);
|
2016-02-03 15:59:59 +01:00
|
|
|
connect(m_parser, &TestCodeParser::testParseResultReady,
|
|
|
|
|
this, &TestTreeModel::onParseResultReady, Qt::QueuedConnection);
|
2016-01-25 13:05:12 +01:00
|
|
|
connect(m_parser, &TestCodeParser::parsingFinished,
|
|
|
|
|
this, &TestTreeModel::sweep, Qt::QueuedConnection);
|
|
|
|
|
connect(m_parser, &TestCodeParser::parsingFailed,
|
|
|
|
|
this, &TestTreeModel::sweep, Qt::QueuedConnection);
|
2014-10-07 12:30:54 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static TestTreeModel *m_instance = 0;
|
|
|
|
|
|
|
|
|
|
TestTreeModel *TestTreeModel::instance()
|
|
|
|
|
{
|
|
|
|
|
if (!m_instance)
|
|
|
|
|
m_instance = new TestTreeModel;
|
|
|
|
|
return m_instance;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TestTreeModel::~TestTreeModel()
|
|
|
|
|
{
|
|
|
|
|
m_instance = 0;
|
|
|
|
|
}
|
|
|
|
|
|
2015-02-12 15:48:24 +01:00
|
|
|
void TestTreeModel::enableParsing()
|
|
|
|
|
{
|
2015-04-15 09:34:11 +02:00
|
|
|
m_refCounter.ref();
|
2016-02-01 15:12:10 +01:00
|
|
|
setupParsingConnections();
|
|
|
|
|
}
|
2015-07-27 13:54:27 +02:00
|
|
|
|
2016-02-01 15:12:10 +01:00
|
|
|
void TestTreeModel::enableParsingFromSettings()
|
|
|
|
|
{
|
|
|
|
|
setupParsingConnections();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void TestTreeModel::setupParsingConnections()
|
|
|
|
|
{
|
2015-07-27 13:54:27 +02:00
|
|
|
if (!m_connectionsInitialized)
|
|
|
|
|
m_parser->setDirty();
|
|
|
|
|
|
2015-02-19 11:19:59 +01:00
|
|
|
m_parser->setState(TestCodeParser::Idle);
|
2015-02-12 15:48:24 +01:00
|
|
|
if (m_connectionsInitialized)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
ProjectExplorer::SessionManager *sm = ProjectExplorer::SessionManager::instance();
|
|
|
|
|
connect(sm, &ProjectExplorer::SessionManager::startupProjectChanged,
|
2015-07-27 10:44:14 +02:00
|
|
|
m_parser, &TestCodeParser::onStartupProjectChanged);
|
2015-02-12 15:48:24 +01:00
|
|
|
|
|
|
|
|
CppTools::CppModelManager *cppMM = CppTools::CppModelManager::instance();
|
|
|
|
|
connect(cppMM, &CppTools::CppModelManager::documentUpdated,
|
|
|
|
|
m_parser, &TestCodeParser::onCppDocumentUpdated, Qt::QueuedConnection);
|
|
|
|
|
connect(cppMM, &CppTools::CppModelManager::aboutToRemoveFiles,
|
2016-01-25 13:05:12 +01:00
|
|
|
this, &TestTreeModel::removeFiles, Qt::QueuedConnection);
|
2015-04-02 12:16:55 +02:00
|
|
|
connect(cppMM, &CppTools::CppModelManager::projectPartsUpdated,
|
|
|
|
|
m_parser, &TestCodeParser::onProjectPartsUpdated);
|
2015-02-12 15:48:24 +01:00
|
|
|
|
|
|
|
|
QmlJS::ModelManagerInterface *qmlJsMM = QmlJS::ModelManagerInterface::instance();
|
|
|
|
|
connect(qmlJsMM, &QmlJS::ModelManagerInterface::documentUpdated,
|
|
|
|
|
m_parser, &TestCodeParser::onQmlDocumentUpdated, Qt::QueuedConnection);
|
|
|
|
|
connect(qmlJsMM, &QmlJS::ModelManagerInterface::aboutToRemoveFiles,
|
2016-01-25 13:05:12 +01:00
|
|
|
this, &TestTreeModel::removeFiles, Qt::QueuedConnection);
|
2015-02-12 15:48:24 +01:00
|
|
|
m_connectionsInitialized = true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void TestTreeModel::disableParsing()
|
|
|
|
|
{
|
2016-02-01 15:12:10 +01:00
|
|
|
if (!m_refCounter.deref() && !AutotestPlugin::instance()->settings()->alwaysParse)
|
|
|
|
|
m_parser->setState(TestCodeParser::Disabled);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void TestTreeModel::disableParsingFromSettings()
|
|
|
|
|
{
|
|
|
|
|
if (!m_refCounter.load())
|
2015-04-15 09:34:11 +02:00
|
|
|
m_parser->setState(TestCodeParser::Disabled);
|
2015-02-12 15:48:24 +01:00
|
|
|
}
|
|
|
|
|
|
2014-10-07 12:30:54 +02:00
|
|
|
bool TestTreeModel::setData(const QModelIndex &index, const QVariant &value, int role)
|
|
|
|
|
{
|
|
|
|
|
if (!index.isValid())
|
|
|
|
|
return false;
|
|
|
|
|
|
2015-09-10 10:57:15 +02:00
|
|
|
TestTreeItem *item = static_cast<TestTreeItem *>(index.internalPointer());
|
|
|
|
|
if (item && item->setData(index.column(), value, role)) {
|
|
|
|
|
emit dataChanged(index, index);
|
|
|
|
|
if (role == Qt::CheckStateRole) {
|
|
|
|
|
switch (item->type()) {
|
2016-02-23 15:56:52 +01:00
|
|
|
case TestTreeItem::TestCase:
|
2015-09-10 10:57:15 +02:00
|
|
|
if (item->childCount() > 0)
|
2014-10-07 12:30:54 +02:00
|
|
|
emit dataChanged(index.child(0, 0), index.child(item->childCount() - 1, 0));
|
|
|
|
|
break;
|
2016-02-23 15:56:52 +01:00
|
|
|
case TestTreeItem::TestFunctionOrSet:
|
2014-10-07 12:30:54 +02:00
|
|
|
emit dataChanged(index.parent(), index.parent());
|
|
|
|
|
break;
|
|
|
|
|
default: // avoid warning regarding unhandled enum member
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
2015-09-10 10:57:15 +02:00
|
|
|
return true;
|
2014-10-07 12:30:54 +02:00
|
|
|
}
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Qt::ItemFlags TestTreeModel::flags(const QModelIndex &index) const
|
|
|
|
|
{
|
|
|
|
|
if (!index.isValid())
|
|
|
|
|
return Qt::ItemIsEnabled | Qt::ItemIsSelectable;
|
|
|
|
|
|
2015-09-10 15:32:12 +02:00
|
|
|
TestTreeItem *item = static_cast<TestTreeItem *>(itemForIndex(index));
|
2016-04-28 16:42:14 +02:00
|
|
|
return item->flags(index.column());
|
2014-10-07 12:30:54 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool TestTreeModel::hasTests() const
|
|
|
|
|
{
|
2015-12-07 15:15:00 +01:00
|
|
|
return m_autoTestRootItem->childCount() > 0 || m_quickTestRootItem->childCount() > 0
|
|
|
|
|
|| m_googleTestRootItem->childCount() > 0;
|
2014-10-07 12:30:54 +02:00
|
|
|
}
|
|
|
|
|
|
2014-10-07 15:51:02 +02:00
|
|
|
QList<TestConfiguration *> TestTreeModel::getAllTestCases() const
|
|
|
|
|
{
|
|
|
|
|
QList<TestConfiguration *> result;
|
|
|
|
|
|
2016-04-08 14:58:23 +02:00
|
|
|
result.append(m_autoTestRootItem->getAllTestConfigurations());
|
|
|
|
|
result.append(m_quickTestRootItem->getAllTestConfigurations());
|
|
|
|
|
result.append(m_googleTestRootItem->getAllTestConfigurations());
|
2014-10-07 15:51:02 +02:00
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
QList<TestConfiguration *> TestTreeModel::getSelectedTests() const
|
|
|
|
|
{
|
|
|
|
|
QList<TestConfiguration *> result;
|
2016-04-08 14:58:23 +02:00
|
|
|
result.append(m_autoTestRootItem->getSelectedTestConfigurations());
|
|
|
|
|
result.append(m_quickTestRootItem->getSelectedTestConfigurations());
|
|
|
|
|
result.append(m_googleTestRootItem->getSelectedTestConfigurations());
|
2014-10-07 15:51:02 +02:00
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
2015-04-16 14:04:36 +02:00
|
|
|
TestConfiguration *TestTreeModel::getTestConfiguration(const TestTreeItem *item) const
|
|
|
|
|
{
|
|
|
|
|
QTC_ASSERT(item != 0, return 0);
|
2016-04-08 14:58:23 +02:00
|
|
|
return item->testConfiguration();
|
2015-04-16 14:04:36 +02:00
|
|
|
}
|
|
|
|
|
|
2015-02-05 16:07:45 +01:00
|
|
|
bool TestTreeModel::hasUnnamedQuickTests() const
|
|
|
|
|
{
|
|
|
|
|
for (int row = 0, count = m_quickTestRootItem->childCount(); row < count; ++row)
|
2015-09-10 15:32:12 +02:00
|
|
|
if (m_quickTestRootItem->childItem(row)->name().isEmpty())
|
2015-02-05 16:07:45 +01:00
|
|
|
return true;
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2014-11-06 16:01:06 +01:00
|
|
|
TestTreeItem *TestTreeModel::unnamedQuickTests() const
|
|
|
|
|
{
|
|
|
|
|
for (int row = 0, count = m_quickTestRootItem->childCount(); row < count; ++row) {
|
2015-09-10 15:32:12 +02:00
|
|
|
TestTreeItem *child = m_quickTestRootItem->childItem(row);
|
2014-11-06 16:01:06 +01:00
|
|
|
if (child->name().isEmpty())
|
|
|
|
|
return child;
|
|
|
|
|
}
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2016-01-25 13:05:12 +01:00
|
|
|
void TestTreeModel::removeFiles(const QStringList &files)
|
2014-10-07 12:30:54 +02:00
|
|
|
{
|
2016-01-25 13:05:12 +01:00
|
|
|
foreach (const QString &file, files)
|
|
|
|
|
markForRemoval(file);
|
|
|
|
|
sweep();
|
2015-12-07 15:18:25 +01:00
|
|
|
}
|
|
|
|
|
|
2016-01-26 13:52:45 +01:00
|
|
|
void TestTreeModel::markAllForRemoval()
|
|
|
|
|
{
|
|
|
|
|
foreach (Utils::TreeItem *item, m_autoTestRootItem->children())
|
|
|
|
|
static_cast<TestTreeItem *>(item)->markForRemovalRecursively(true);
|
|
|
|
|
|
|
|
|
|
foreach (Utils::TreeItem *item, m_quickTestRootItem->children())
|
|
|
|
|
static_cast<TestTreeItem *>(item)->markForRemovalRecursively(true);
|
|
|
|
|
|
|
|
|
|
foreach (Utils::TreeItem *item, m_googleTestRootItem->children())
|
|
|
|
|
static_cast<TestTreeItem *>(item)->markForRemovalRecursively(true);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void TestTreeModel::markForRemoval(const QString &filePath)
|
|
|
|
|
{
|
|
|
|
|
if (filePath.isEmpty())
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
Type types[] = { AutoTest, QuickTest, GoogleTest };
|
|
|
|
|
for (Type type : types) {
|
|
|
|
|
TestTreeItem *root = rootItemForType(type);
|
|
|
|
|
for (int childRow = root->childCount() - 1; childRow >= 0; --childRow) {
|
|
|
|
|
TestTreeItem *child = root->childItem(childRow);
|
2016-04-28 16:42:14 +02:00
|
|
|
child->markForRemovalRecursively(filePath);
|
2016-01-26 13:52:45 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void TestTreeModel::sweep()
|
|
|
|
|
{
|
|
|
|
|
Type types[] = { AutoTest, QuickTest, GoogleTest };
|
|
|
|
|
for (Type type : types) {
|
|
|
|
|
TestTreeItem *root = rootItemForType(type);
|
2016-02-29 11:14:40 +01:00
|
|
|
sweepChildren(root);
|
2016-01-26 13:52:45 +01:00
|
|
|
}
|
2016-02-29 11:14:40 +01:00
|
|
|
// even if nothing has changed by the sweeping we might had parse which added or modified items
|
|
|
|
|
emit testTreeModelChanged();
|
2016-02-10 10:43:31 +01:00
|
|
|
#ifdef WITH_TESTS
|
|
|
|
|
if (m_parser->state() == TestCodeParser::Idle && !m_parser->furtherParsingExpected())
|
|
|
|
|
emit sweepingDone();
|
|
|
|
|
#endif
|
2016-01-26 13:52:45 +01:00
|
|
|
}
|
|
|
|
|
|
2016-03-09 08:17:33 +01:00
|
|
|
QHash<QString, QString> TestTreeModel::testCaseNamesForFiles(QStringList files)
|
2016-02-23 15:56:52 +01:00
|
|
|
{
|
2016-03-09 08:17:33 +01:00
|
|
|
QHash<QString, QString> result;
|
2016-02-23 15:56:52 +01:00
|
|
|
if (!m_autoTestRootItem)
|
|
|
|
|
return result;
|
|
|
|
|
|
|
|
|
|
for (int row = 0, count = m_autoTestRootItem->childCount(); row < count; ++row) {
|
|
|
|
|
const TestTreeItem *child = m_autoTestRootItem->childItem(row);
|
|
|
|
|
if (files.contains(child->filePath())) {
|
|
|
|
|
result.insert(child->filePath(), child->name());
|
|
|
|
|
}
|
|
|
|
|
for (int childRow = 0, children = child->childCount(); childRow < children; ++childRow) {
|
|
|
|
|
const TestTreeItem *grandChild = child->childItem(childRow);
|
|
|
|
|
if (files.contains(grandChild->filePath()))
|
|
|
|
|
result.insert(grandChild->filePath(), child->name());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
2016-01-26 13:52:45 +01:00
|
|
|
/**
|
|
|
|
|
* @note after calling this function emit testTreeModelChanged() if it returns true
|
|
|
|
|
*/
|
|
|
|
|
bool TestTreeModel::sweepChildren(TestTreeItem *item)
|
|
|
|
|
{
|
|
|
|
|
bool hasChanged = false;
|
|
|
|
|
for (int row = item->childCount() - 1; row >= 0; --row) {
|
|
|
|
|
TestTreeItem *child = item->childItem(row);
|
|
|
|
|
|
|
|
|
|
if (child->parentItem()->type() != TestTreeItem::Root && child->markedForRemoval()) {
|
|
|
|
|
delete takeItem(child);
|
|
|
|
|
hasChanged = true;
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
if (bool noEndNode = child->hasChildren()) {
|
|
|
|
|
hasChanged |= sweepChildren(child);
|
|
|
|
|
if (noEndNode && child->childCount() == 0) {
|
|
|
|
|
delete takeItem(child);
|
|
|
|
|
hasChanged = true;
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
}
|
2016-03-04 11:56:56 +01:00
|
|
|
hasChanged |= child->newlyAdded();
|
2016-01-26 13:52:45 +01:00
|
|
|
child->markForRemoval(false);
|
|
|
|
|
}
|
|
|
|
|
return hasChanged;
|
|
|
|
|
}
|
|
|
|
|
|
2016-04-12 12:44:56 +02:00
|
|
|
void TestTreeModel::onParseResultReady(const TestParseResultPtr result)
|
2016-02-03 15:59:59 +01:00
|
|
|
{
|
2016-04-12 12:44:56 +02:00
|
|
|
switch (result->type) {
|
2016-02-03 15:59:59 +01:00
|
|
|
case AutoTest:
|
2016-04-11 14:50:04 +02:00
|
|
|
handleQtParseResult(result);
|
2016-02-17 16:01:44 +01:00
|
|
|
break;
|
2016-02-03 15:59:59 +01:00
|
|
|
case QuickTest:
|
2016-04-11 14:50:04 +02:00
|
|
|
handleQuickParseResult(result);
|
2016-02-03 15:59:59 +01:00
|
|
|
break;
|
|
|
|
|
case GoogleTest:
|
2016-02-08 15:56:07 +01:00
|
|
|
handleGTestParseResult(result);
|
2016-02-03 15:59:59 +01:00
|
|
|
break;
|
|
|
|
|
case Invalid:
|
|
|
|
|
QTC_ASSERT(false, qWarning("TestParseResult of type Invalid unexpected."));
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2016-04-11 14:50:04 +02:00
|
|
|
void TestTreeModel::handleQtParseResult(const TestParseResultPtr result)
|
2016-02-08 15:56:07 +01:00
|
|
|
{
|
2016-04-11 14:50:04 +02:00
|
|
|
TestTreeItem *toBeModified = m_autoTestRootItem->findChildByFile(result->fileName);
|
2016-02-08 15:56:07 +01:00
|
|
|
// if there's no matching item, add the new one
|
|
|
|
|
if (!toBeModified) {
|
2016-05-03 13:03:03 +02:00
|
|
|
m_autoTestRootItem->appendChild(AutoTestTreeItem::createTestItem(result.data()));
|
2016-02-08 15:56:07 +01:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
// else we have to check level by level.. first the current level...
|
2016-05-03 13:03:03 +02:00
|
|
|
bool changed = toBeModified->modifyTestCaseContent(result->name, result->line,
|
2016-04-12 12:44:56 +02:00
|
|
|
result->column);
|
2016-02-08 15:56:07 +01:00
|
|
|
toBeModified->markForRemoval(false);
|
|
|
|
|
if (changed)
|
|
|
|
|
emit dataChanged(indexForItem(toBeModified), indexForItem(toBeModified));
|
|
|
|
|
// ...now the functions
|
2016-05-03 13:03:03 +02:00
|
|
|
foreach (const TestParseResult *funcResult, result->children) {
|
|
|
|
|
TestTreeItem *functionItem = toBeModified->findChildByName(funcResult->displayName);
|
2016-02-08 15:56:07 +01:00
|
|
|
if (!functionItem) {
|
2016-04-11 14:50:04 +02:00
|
|
|
// if there's no function matching, add the new one
|
2016-05-03 13:03:03 +02:00
|
|
|
toBeModified->appendChild(AutoTestTreeItem::createTestItem(funcResult));
|
2016-02-08 15:56:07 +01:00
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
// else we have to check level by level.. first the current level...
|
2016-05-03 13:03:03 +02:00
|
|
|
changed = functionItem->modifyTestFunctionContent(funcResult);
|
2016-02-08 15:56:07 +01:00
|
|
|
functionItem->markForRemoval(false);
|
|
|
|
|
if (changed)
|
|
|
|
|
emit dataChanged(indexForItem(functionItem), indexForItem(functionItem));
|
2016-04-11 14:50:04 +02:00
|
|
|
// ...now the data tags
|
2016-05-03 13:03:03 +02:00
|
|
|
foreach (const TestParseResult *tag, funcResult->children) {
|
|
|
|
|
TestTreeItem *dataTagItem = functionItem->findChildByName(tag->name);
|
2016-02-08 15:56:07 +01:00
|
|
|
if (!dataTagItem) {
|
2016-05-03 13:03:03 +02:00
|
|
|
functionItem->appendChild(AutoTestTreeItem::createTestItem(tag));
|
2016-02-08 15:56:07 +01:00
|
|
|
continue;
|
|
|
|
|
}
|
2016-05-03 13:03:03 +02:00
|
|
|
changed = dataTagItem->modifyDataTagContent(tag->name, tag->fileName, tag->line,
|
|
|
|
|
tag->column);
|
2016-02-08 15:56:07 +01:00
|
|
|
dataTagItem->markForRemoval(false);
|
|
|
|
|
if (changed)
|
|
|
|
|
emit dataChanged(indexForItem(dataTagItem), indexForItem(dataTagItem));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2016-04-11 14:50:04 +02:00
|
|
|
void TestTreeModel::handleQuickParseResult(const TestParseResultPtr result)
|
|
|
|
|
{
|
2016-05-03 13:03:03 +02:00
|
|
|
if (result->name.isEmpty()) {
|
2016-04-11 14:50:04 +02:00
|
|
|
handleUnnamedQuickParseResult(result);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TestTreeItem *toBeModified = m_quickTestRootItem->findChildByFile(result->fileName);
|
|
|
|
|
// if there's no matching item, add the new one
|
|
|
|
|
if (!toBeModified) {
|
2016-05-03 13:03:03 +02:00
|
|
|
m_quickTestRootItem->appendChild(QuickTestTreeItem::createTestItem(result.data()));
|
2016-04-11 14:50:04 +02:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
// else we have to check level by level.. first the current level...
|
2016-05-03 13:03:03 +02:00
|
|
|
bool changed = toBeModified->modifyTestCaseContent(result->name, result->line,
|
2016-04-11 14:50:04 +02:00
|
|
|
result->column);
|
|
|
|
|
toBeModified->markForRemoval(false);
|
|
|
|
|
if (changed)
|
|
|
|
|
emit dataChanged(indexForItem(toBeModified), indexForItem(toBeModified));
|
|
|
|
|
// ...now the functions
|
2016-05-03 13:03:03 +02:00
|
|
|
foreach (const TestParseResult *funcResult, result->children) {
|
|
|
|
|
TestTreeItem *functionItem = toBeModified->findChildByName(funcResult->name);
|
2016-04-11 14:50:04 +02:00
|
|
|
if (!functionItem) {
|
|
|
|
|
// if there's no matching, add the new one
|
2016-05-03 13:03:03 +02:00
|
|
|
toBeModified->appendChild(QuickTestTreeItem::createTestItem(funcResult));
|
2016-04-11 14:50:04 +02:00
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
// else we have to modify..
|
2016-05-03 13:03:03 +02:00
|
|
|
changed = functionItem->modifyTestFunctionContent(funcResult);
|
2016-04-11 14:50:04 +02:00
|
|
|
functionItem->markForRemoval(false);
|
|
|
|
|
if (changed)
|
|
|
|
|
emit dataChanged(indexForItem(functionItem), indexForItem(functionItem));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2016-04-12 12:44:56 +02:00
|
|
|
void TestTreeModel::handleUnnamedQuickParseResult(const TestParseResultPtr result)
|
2016-02-08 15:56:07 +01:00
|
|
|
{
|
|
|
|
|
TestTreeItem *toBeModified = unnamedQuickTests();
|
|
|
|
|
if (!toBeModified) {
|
2016-05-03 13:03:03 +02:00
|
|
|
m_quickTestRootItem->appendChild(QuickTestTreeItem::createTestItem(result.data()));
|
2016-02-08 15:56:07 +01:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
// if we have already Unnamed Quick tests we might update them..
|
2016-05-03 13:03:03 +02:00
|
|
|
foreach (const TestParseResult *funcResult, result->children) {
|
|
|
|
|
TestTreeItem *functionItem = toBeModified->findChildByNameAndFile(funcResult->name,
|
|
|
|
|
funcResult->fileName);
|
2016-02-08 15:56:07 +01:00
|
|
|
if (!functionItem) {
|
2016-05-03 13:03:03 +02:00
|
|
|
toBeModified->appendChild(QuickTestTreeItem::createTestItem(funcResult));
|
2016-02-08 15:56:07 +01:00
|
|
|
continue;
|
|
|
|
|
}
|
2016-05-03 13:03:03 +02:00
|
|
|
functionItem->modifyLineAndColumn(funcResult->line, funcResult->column);
|
2016-02-08 15:56:07 +01:00
|
|
|
functionItem->markForRemoval(false);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2016-04-12 12:44:56 +02:00
|
|
|
void TestTreeModel::handleGTestParseResult(const TestParseResultPtr result)
|
2016-02-08 15:56:07 +01:00
|
|
|
{
|
2016-05-03 13:03:03 +02:00
|
|
|
QTC_ASSERT(!result->children.isEmpty(), return);
|
|
|
|
|
const GoogleTestParseResult *parseResult = static_cast<const GoogleTestParseResult *>(result.data());
|
2016-04-11 14:50:04 +02:00
|
|
|
|
2016-02-23 15:56:52 +01:00
|
|
|
GoogleTestTreeItem::TestStates states = GoogleTestTreeItem::Enabled;
|
2016-05-03 13:03:03 +02:00
|
|
|
if (parseResult->parameterized)
|
2016-02-23 15:56:52 +01:00
|
|
|
states |= GoogleTestTreeItem::Parameterized;
|
2016-05-03 13:03:03 +02:00
|
|
|
if (parseResult->typed)
|
2016-02-22 11:23:53 +01:00
|
|
|
states |= GoogleTestTreeItem::Typed;
|
2016-02-23 15:56:52 +01:00
|
|
|
TestTreeItem *toBeModified = m_googleTestRootItem->findChildByNameStateAndFile(
|
2016-05-03 13:03:03 +02:00
|
|
|
parseResult->name, states, parseResult->proFile);
|
2016-02-08 15:56:07 +01:00
|
|
|
if (!toBeModified) {
|
2016-04-11 14:50:04 +02:00
|
|
|
m_googleTestRootItem->appendChild(GoogleTestTreeItem::createTestItem(parseResult));
|
2016-02-08 15:56:07 +01:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
// if found nothing has to be updated as all relevant members are used to find the item
|
2016-05-03 13:03:03 +02:00
|
|
|
foreach (const TestParseResult *setResult, parseResult->children) {
|
|
|
|
|
const GoogleTestParseResult *testSet = static_cast<const GoogleTestParseResult *>(setResult);
|
|
|
|
|
TestTreeItem *testSetItem = toBeModified->findChildByNameAndFile(testSet->name,
|
|
|
|
|
testSet->fileName);
|
2016-02-08 15:56:07 +01:00
|
|
|
if (!testSetItem) {
|
2016-05-03 13:03:03 +02:00
|
|
|
toBeModified->appendChild(GoogleTestTreeItem::createTestItem(testSet));
|
2016-02-08 15:56:07 +01:00
|
|
|
continue;
|
|
|
|
|
}
|
2016-05-03 13:03:03 +02:00
|
|
|
bool changed = static_cast<GoogleTestTreeItem *>(testSetItem)->modifyTestSetContent(testSet);
|
2016-02-08 15:56:07 +01:00
|
|
|
testSetItem->markForRemoval(false);
|
|
|
|
|
if (changed)
|
|
|
|
|
emit dataChanged(indexForItem(testSetItem), indexForItem(testSetItem));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2015-02-05 16:07:45 +01:00
|
|
|
void TestTreeModel::removeAllTestItems()
|
2014-11-06 16:01:06 +01:00
|
|
|
{
|
2015-02-05 16:07:45 +01:00
|
|
|
m_autoTestRootItem->removeChildren();
|
2014-11-06 16:01:06 +01:00
|
|
|
m_quickTestRootItem->removeChildren();
|
2015-12-07 15:15:00 +01:00
|
|
|
m_googleTestRootItem->removeChildren();
|
2014-11-06 16:01:06 +01:00
|
|
|
emit testTreeModelChanged();
|
|
|
|
|
}
|
|
|
|
|
|
2015-02-05 16:07:45 +01:00
|
|
|
TestTreeItem *TestTreeModel::rootItemForType(TestTreeModel::Type type)
|
|
|
|
|
{
|
|
|
|
|
switch (type) {
|
|
|
|
|
case AutoTest:
|
|
|
|
|
return m_autoTestRootItem;
|
|
|
|
|
case QuickTest:
|
|
|
|
|
return m_quickTestRootItem;
|
2015-12-07 15:15:00 +01:00
|
|
|
case GoogleTest:
|
|
|
|
|
return m_googleTestRootItem;
|
2016-02-03 15:59:59 +01:00
|
|
|
case Invalid:
|
|
|
|
|
break;
|
2015-02-05 16:07:45 +01:00
|
|
|
}
|
|
|
|
|
QTC_ASSERT(false, return 0);
|
|
|
|
|
}
|
|
|
|
|
|
2015-02-10 14:20:43 +01:00
|
|
|
#ifdef WITH_TESTS
|
|
|
|
|
int TestTreeModel::autoTestsCount() const
|
|
|
|
|
{
|
|
|
|
|
return m_autoTestRootItem ? m_autoTestRootItem->childCount() : 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int TestTreeModel::namedQuickTestsCount() const
|
|
|
|
|
{
|
|
|
|
|
return m_quickTestRootItem
|
|
|
|
|
? m_quickTestRootItem->childCount() - (hasUnnamedQuickTests() ? 1 : 0)
|
|
|
|
|
: 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int TestTreeModel::unnamedQuickTestsCount() const
|
|
|
|
|
{
|
|
|
|
|
if (TestTreeItem *unnamed = unnamedQuickTests())
|
|
|
|
|
return unnamed->childCount();
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
2015-11-02 11:06:19 +01:00
|
|
|
|
|
|
|
|
int TestTreeModel::dataTagsCount() const
|
|
|
|
|
{
|
|
|
|
|
int dataTagCount = 0;
|
|
|
|
|
foreach (Utils::TreeItem *item, m_autoTestRootItem->children()) {
|
|
|
|
|
TestTreeItem *classItem = static_cast<TestTreeItem *>(item);
|
|
|
|
|
foreach (Utils::TreeItem *functionItem, classItem->children())
|
|
|
|
|
dataTagCount += functionItem->childCount();
|
|
|
|
|
}
|
|
|
|
|
return dataTagCount;
|
|
|
|
|
}
|
2015-12-10 13:46:04 +01:00
|
|
|
|
|
|
|
|
int TestTreeModel::gtestNamesCount() const
|
|
|
|
|
{
|
|
|
|
|
return m_googleTestRootItem ? m_googleTestRootItem->childCount() : 0;
|
|
|
|
|
}
|
|
|
|
|
|
2016-01-13 09:10:11 +01:00
|
|
|
QMultiMap<QString, int> TestTreeModel::gtestNamesAndSets() const
|
2015-12-10 13:46:04 +01:00
|
|
|
{
|
2016-01-13 09:10:11 +01:00
|
|
|
QMultiMap<QString, int> result;
|
2015-12-10 13:46:04 +01:00
|
|
|
|
|
|
|
|
if (m_googleTestRootItem) {
|
|
|
|
|
for (int row = 0, count = m_googleTestRootItem->childCount(); row < count; ++row) {
|
|
|
|
|
const TestTreeItem *current = m_googleTestRootItem->childItem(row);
|
|
|
|
|
result.insert(current->name(), current->childCount());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return result;
|
|
|
|
|
}
|
2015-02-10 14:20:43 +01:00
|
|
|
#endif
|
|
|
|
|
|
2014-11-11 17:30:34 +01:00
|
|
|
/***************************** Sort/Filter Model **********************************/
|
|
|
|
|
|
|
|
|
|
TestTreeSortFilterModel::TestTreeSortFilterModel(TestTreeModel *sourceModel, QObject *parent)
|
|
|
|
|
: QSortFilterProxyModel(parent),
|
|
|
|
|
m_sourceModel(sourceModel),
|
2016-04-28 16:42:14 +02:00
|
|
|
m_sortMode(TestTreeItem::Alphabetically),
|
2014-11-11 17:30:34 +01:00
|
|
|
m_filterMode(Basic)
|
|
|
|
|
{
|
|
|
|
|
setSourceModel(sourceModel);
|
|
|
|
|
}
|
|
|
|
|
|
2016-04-28 16:42:14 +02:00
|
|
|
void TestTreeSortFilterModel::setSortMode(TestTreeItem::SortMode sortMode)
|
2014-11-11 17:30:34 +01:00
|
|
|
{
|
|
|
|
|
m_sortMode = sortMode;
|
|
|
|
|
invalidate();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void TestTreeSortFilterModel::setFilterMode(FilterMode filterMode)
|
|
|
|
|
{
|
|
|
|
|
m_filterMode = filterMode;
|
|
|
|
|
invalidateFilter();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void TestTreeSortFilterModel::toggleFilter(FilterMode filterMode)
|
|
|
|
|
{
|
|
|
|
|
m_filterMode = toFilterMode(m_filterMode ^ filterMode);
|
|
|
|
|
invalidateFilter();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TestTreeSortFilterModel::FilterMode TestTreeSortFilterModel::toFilterMode(int f)
|
|
|
|
|
{
|
|
|
|
|
switch (f) {
|
|
|
|
|
case TestTreeSortFilterModel::ShowInitAndCleanup:
|
|
|
|
|
return TestTreeSortFilterModel::ShowInitAndCleanup;
|
|
|
|
|
case TestTreeSortFilterModel::ShowTestData:
|
|
|
|
|
return TestTreeSortFilterModel::ShowTestData;
|
|
|
|
|
case TestTreeSortFilterModel::ShowAll:
|
|
|
|
|
return TestTreeSortFilterModel::ShowAll;
|
|
|
|
|
default:
|
|
|
|
|
return TestTreeSortFilterModel::Basic;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool TestTreeSortFilterModel::lessThan(const QModelIndex &left, const QModelIndex &right) const
|
|
|
|
|
{
|
2016-04-28 16:42:14 +02:00
|
|
|
// root items keep the intended order
|
2014-11-11 17:30:34 +01:00
|
|
|
const TestTreeItem *leftItem = static_cast<TestTreeItem *>(left.internalPointer());
|
2015-12-07 08:26:54 +01:00
|
|
|
if (leftItem->type() == TestTreeItem::Root)
|
2014-11-11 17:30:34 +01:00
|
|
|
return left.row() > right.row();
|
|
|
|
|
|
2016-04-28 16:42:14 +02:00
|
|
|
const TestTreeItem *rightItem = static_cast<TestTreeItem *>(right.internalPointer());
|
|
|
|
|
return leftItem->lessThan(rightItem, m_sortMode);
|
2014-11-11 17:30:34 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool TestTreeSortFilterModel::filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const
|
|
|
|
|
{
|
|
|
|
|
QModelIndex index = m_sourceModel->index(sourceRow, 0,sourceParent);
|
|
|
|
|
if (!index.isValid())
|
|
|
|
|
return false;
|
|
|
|
|
|
2014-11-13 12:31:58 +01:00
|
|
|
const TestTreeItem *item = static_cast<TestTreeItem *>(index.internalPointer());
|
2014-11-11 17:30:34 +01:00
|
|
|
|
2014-11-13 12:31:58 +01:00
|
|
|
switch (item->type()) {
|
2015-12-07 08:26:54 +01:00
|
|
|
case TestTreeItem::TestDataFunction:
|
2014-11-13 12:31:58 +01:00
|
|
|
return m_filterMode & ShowTestData;
|
2015-12-07 08:26:54 +01:00
|
|
|
case TestTreeItem::TestSpecialFunction:
|
2014-11-13 12:31:58 +01:00
|
|
|
return m_filterMode & ShowInitAndCleanup;
|
|
|
|
|
default:
|
|
|
|
|
return true;
|
|
|
|
|
}
|
2014-11-11 17:30:34 +01:00
|
|
|
}
|
|
|
|
|
|
2014-10-07 12:30:54 +02:00
|
|
|
} // namespace Internal
|
|
|
|
|
} // namespace Autotest
|