forked from qt-creator/qt-creator
AutoTest: Allow grouping of test cases
Grouping of test cases can now get enabled for each registered framework. For now grouping happens only folder based. Task-number: QTCREATORBUG-17979 Change-Id: Ic0e5c0ecc76998a1aedea8aa0845f6d9b53fb179 Reviewed-by: David Schulz <david.schulz@qt.io>
This commit is contained in:
@@ -26,6 +26,7 @@
|
||||
#include "gtesttreeitem.h"
|
||||
#include "gtestconfiguration.h"
|
||||
#include "gtestparser.h"
|
||||
#include "../testframeworkmanager.h"
|
||||
|
||||
#include <cpptools/cppmodelmanager.h>
|
||||
#include <projectexplorer/session.h>
|
||||
@@ -59,6 +60,7 @@ QVariant GTestTreeItem::data(int column, int role) const
|
||||
case Qt::CheckStateRole:
|
||||
switch (type()) {
|
||||
case Root:
|
||||
case GroupNode:
|
||||
case TestCase:
|
||||
case TestFunctionOrSet:
|
||||
return checked();
|
||||
@@ -237,6 +239,22 @@ TestTreeItem *GTestTreeItem::find(const TestParseResult *result)
|
||||
states |= GTestTreeItem::Typed;
|
||||
switch (type()) {
|
||||
case Root:
|
||||
if (TestFrameworkManager::instance()->groupingEnabled(result->frameworkId)) {
|
||||
const QFileInfo fileInfo(parseResult->fileName);
|
||||
const QFileInfo base(fileInfo.absolutePath());
|
||||
for (int row = 0; row < childCount(); ++row) {
|
||||
GTestTreeItem *group = static_cast<GTestTreeItem *>(childAt(row));
|
||||
if (group->filePath() != base.absoluteFilePath())
|
||||
continue;
|
||||
if (auto groupChild = group->findChildByNameStateAndFile(parseResult->name, states,
|
||||
parseResult->proFile)) {
|
||||
return groupChild;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
return findChildByNameStateAndFile(parseResult->name, states, parseResult->proFile);
|
||||
case GroupNode:
|
||||
return findChildByNameStateAndFile(parseResult->name, states, parseResult->proFile);
|
||||
case TestCase:
|
||||
return findChildByNameAndFile(result->name, result->fileName);
|
||||
@@ -257,6 +275,13 @@ bool GTestTreeItem::modify(const TestParseResult *result)
|
||||
}
|
||||
}
|
||||
|
||||
TestTreeItem *GTestTreeItem::createParentGroupNode() const
|
||||
{
|
||||
const QFileInfo fileInfo(filePath());
|
||||
const QFileInfo base(fileInfo.absolutePath());
|
||||
return new GTestTreeItem(base.baseName(), fileInfo.absolutePath(), TestTreeItem::GroupNode);
|
||||
}
|
||||
|
||||
bool GTestTreeItem::modifyTestSetContent(const GTestParseResult *result)
|
||||
{
|
||||
bool hasBeenModified = modifyLineAndColumn(result);
|
||||
|
||||
@@ -58,6 +58,7 @@ public:
|
||||
QList<TestConfiguration *> getSelectedTestConfigurations() const override;
|
||||
TestTreeItem *find(const TestParseResult *result) override;
|
||||
bool modify(const TestParseResult *result) override;
|
||||
TestTreeItem *createParentGroupNode() const override;
|
||||
|
||||
void setStates(TestStates states) { m_state = states; }
|
||||
void setState(TestState state) { m_state |= state; }
|
||||
|
||||
@@ -69,6 +69,8 @@ public:
|
||||
|
||||
bool active() const { return m_active; }
|
||||
void setActive(bool active) { m_active = active; }
|
||||
bool grouping() const { return m_grouping; }
|
||||
void setGrouping(bool group) { m_grouping = group; }
|
||||
|
||||
protected:
|
||||
virtual ITestParser *createTestParser() const = 0;
|
||||
@@ -78,6 +80,7 @@ private:
|
||||
TestTreeItem *m_rootNode = 0;
|
||||
ITestParser *m_testParser = 0;
|
||||
bool m_active = false;
|
||||
bool m_grouping = false;
|
||||
};
|
||||
|
||||
} // namespace Internal
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
#include "qttesttreeitem.h"
|
||||
#include "qttestconfiguration.h"
|
||||
#include "qttestparser.h"
|
||||
#include "../testframeworkmanager.h"
|
||||
|
||||
#include <projectexplorer/session.h>
|
||||
#include <utils/qtcassert.h>
|
||||
@@ -227,6 +228,19 @@ TestTreeItem *QtTestTreeItem::find(const TestParseResult *result)
|
||||
|
||||
switch (type()) {
|
||||
case Root:
|
||||
if (TestFrameworkManager::instance()->groupingEnabled(result->frameworkId)) {
|
||||
const QString path = QFileInfo(result->fileName).absolutePath();
|
||||
for (int row = 0; row < childCount(); ++row) {
|
||||
TestTreeItem *group = childItem(row);
|
||||
if (group->filePath() != path)
|
||||
continue;
|
||||
if (auto groupChild = group->findChildByFile(result->fileName))
|
||||
return groupChild;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
return findChildByFile(result->fileName);
|
||||
case GroupNode:
|
||||
return findChildByFile(result->fileName);
|
||||
case TestCase: {
|
||||
const QtTestParseResult *qtResult = static_cast<const QtTestParseResult *>(result);
|
||||
@@ -259,6 +273,13 @@ bool QtTestTreeItem::modify(const TestParseResult *result)
|
||||
}
|
||||
}
|
||||
|
||||
TestTreeItem *QtTestTreeItem::createParentGroupNode() const
|
||||
{
|
||||
const QFileInfo fileInfo(filePath());
|
||||
const QFileInfo base(fileInfo.absolutePath());
|
||||
return new QtTestTreeItem(base.baseName(), fileInfo.absolutePath(), TestTreeItem::GroupNode);
|
||||
}
|
||||
|
||||
TestTreeItem *QtTestTreeItem::findChildByNameAndInheritance(const QString &name, bool inherited) const
|
||||
{
|
||||
return findChildBy([name, inherited](const TestTreeItem *other) -> bool {
|
||||
|
||||
@@ -48,6 +48,7 @@ public:
|
||||
bool modify(const TestParseResult *result) override;
|
||||
void setInherited(bool inherited) { m_inherited = inherited; }
|
||||
bool inherited() const { return m_inherited; }
|
||||
TestTreeItem *createParentGroupNode() const override;
|
||||
private:
|
||||
TestTreeItem *findChildByNameAndInheritance(const QString &name, bool inherited) const;
|
||||
QString nameSuffix() const;
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
#include "quicktesttreeitem.h"
|
||||
#include "quicktestconfiguration.h"
|
||||
#include "quicktestparser.h"
|
||||
#include "../testframeworkmanager.h"
|
||||
|
||||
#include <cpptools/cppmodelmanager.h>
|
||||
#include <projectexplorer/session.h>
|
||||
@@ -267,7 +268,22 @@ TestTreeItem *QuickTestTreeItem::find(const TestParseResult *result)
|
||||
|
||||
switch (type()) {
|
||||
case Root:
|
||||
return result->name.isEmpty() ? unnamedQuickTests() : findChildByFile(result->fileName);
|
||||
if (result->name.isEmpty())
|
||||
return unnamedQuickTests();
|
||||
if (TestFrameworkManager::instance()->groupingEnabled(result->frameworkId)) {
|
||||
const QString path = QFileInfo(result->fileName).absolutePath();
|
||||
for (int row = 0; row < childCount(); ++row) {
|
||||
TestTreeItem *group = childItem(row);
|
||||
if (group->filePath() != path)
|
||||
continue;
|
||||
if (auto groupChild = group->findChildByFile(result->fileName))
|
||||
return groupChild;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
return findChildByFile(result->fileName);
|
||||
case GroupNode:
|
||||
return findChildByFile(result->fileName);
|
||||
case TestCase:
|
||||
return name().isEmpty() ? findChildByNameAndFile(result->name, result->fileName)
|
||||
: findChildByName(result->name);
|
||||
@@ -303,6 +319,26 @@ bool QuickTestTreeItem::lessThan(const TestTreeItem *other, TestTreeItem::SortMo
|
||||
return TestTreeItem::lessThan(other, mode);
|
||||
}
|
||||
|
||||
bool QuickTestTreeItem::isGroupNodeFor(const TestTreeItem *other) const
|
||||
{
|
||||
QTC_ASSERT(other, return false);
|
||||
if (other->name().isEmpty()) // unnamed quick tests will not get grouped
|
||||
return false;
|
||||
return TestTreeItem::isGroupNodeFor(other);
|
||||
}
|
||||
|
||||
TestTreeItem *QuickTestTreeItem::createParentGroupNode() const
|
||||
{
|
||||
if (filePath().isEmpty() || name().isEmpty())
|
||||
return nullptr;
|
||||
if (type() == TestFunctionOrSet)
|
||||
return nullptr;
|
||||
|
||||
const QFileInfo fileInfo(filePath());
|
||||
const QFileInfo base(fileInfo.absolutePath());
|
||||
return new QuickTestTreeItem(base.baseName(), fileInfo.absolutePath(), TestTreeItem::GroupNode);
|
||||
}
|
||||
|
||||
QSet<QString> QuickTestTreeItem::internalTargets() const
|
||||
{
|
||||
QSet<QString> result;
|
||||
|
||||
@@ -47,6 +47,8 @@ public:
|
||||
TestTreeItem *find(const TestParseResult *result) override;
|
||||
bool modify(const TestParseResult *result) override;
|
||||
bool lessThan(const TestTreeItem *other, SortMode mode) const override;
|
||||
bool isGroupNodeFor(const TestTreeItem *other) const override;
|
||||
TestTreeItem *createParentGroupNode() const override;
|
||||
QSet<QString> internalTargets() const override;
|
||||
private:
|
||||
TestTreeItem *unnamedQuickTests() const;
|
||||
|
||||
@@ -94,8 +94,10 @@ void TestFrameworkManager::activateFrameworksFromSettings(QSharedPointer<TestSet
|
||||
{
|
||||
FrameworkIterator it = m_registeredFrameworks.begin();
|
||||
FrameworkIterator end = m_registeredFrameworks.end();
|
||||
for ( ; it != end; ++it)
|
||||
for ( ; it != end; ++it) {
|
||||
it.value()->setActive(settings->frameworks.value(it.key(), false));
|
||||
it.value()->setGrouping(settings->frameworksGrouping.value(it.key(), false));
|
||||
}
|
||||
}
|
||||
|
||||
QString TestFrameworkManager::frameworkNameForId(const Core::Id &id) const
|
||||
@@ -181,6 +183,18 @@ bool TestFrameworkManager::isActive(const Core::Id &frameworkId) const
|
||||
return framework ? framework->active() : false;
|
||||
}
|
||||
|
||||
bool TestFrameworkManager::groupingEnabled(const Core::Id &frameworkId) const
|
||||
{
|
||||
ITestFramework *framework = m_registeredFrameworks.value(frameworkId);
|
||||
return framework ? framework->grouping() : false;
|
||||
}
|
||||
|
||||
void TestFrameworkManager::setGroupingEnabledFor(const Core::Id &frameworkId, bool enabled)
|
||||
{
|
||||
if (ITestFramework *framework = m_registeredFrameworks.value(frameworkId))
|
||||
framework->setGrouping(enabled);
|
||||
}
|
||||
|
||||
bool TestFrameworkManager::hasActiveFrameworks() const
|
||||
{
|
||||
for (ITestFramework *framework : m_registeredFrameworks.values()) {
|
||||
|
||||
@@ -63,6 +63,8 @@ public:
|
||||
QSharedPointer<IFrameworkSettings> settingsForTestFramework(const Core::Id &frameworkId) const;
|
||||
void synchronizeSettings(QSettings *s);
|
||||
bool isActive(const Core::Id &frameworkId) const;
|
||||
bool groupingEnabled(const Core::Id &frameworkId) const;
|
||||
void setGroupingEnabledFor(const Core::Id &frameworkId, bool enabled);
|
||||
bool hasActiveFrameworks() const;
|
||||
|
||||
private:
|
||||
|
||||
@@ -42,6 +42,7 @@ static const char autoScrollKey[] = "AutoScrollResults";
|
||||
static const char filterScanKey[] = "FilterScan";
|
||||
static const char filtersKey[] = "WhiteListFilters";
|
||||
static const char processArgsKey[] = "ProcessArgs";
|
||||
static const char groupSuffix[] = ".group";
|
||||
|
||||
static const int defaultTimeout = 60000;
|
||||
|
||||
@@ -61,9 +62,11 @@ void TestSettings::toSettings(QSettings *s) const
|
||||
s->setValue(processArgsKey, processArgs);
|
||||
s->setValue(filterScanKey, filterScan);
|
||||
s->setValue(filtersKey, whiteListFilters);
|
||||
// store frameworks and their current active state
|
||||
for (const Core::Id &id : frameworks.keys())
|
||||
// store frameworks and their current active and grouping state
|
||||
for (const Core::Id &id : frameworks.keys()) {
|
||||
s->setValue(QLatin1String(id.name()), frameworks.value(id));
|
||||
s->setValue(QLatin1String(id.name().append(groupSuffix)), frameworksGrouping.value(id));
|
||||
}
|
||||
s->endGroup();
|
||||
}
|
||||
|
||||
@@ -82,9 +85,14 @@ void TestSettings::fromSettings(QSettings *s)
|
||||
TestFrameworkManager *frameworkManager = TestFrameworkManager::instance();
|
||||
const QList<Core::Id> ®istered = frameworkManager->registeredFrameworkIds();
|
||||
frameworks.clear();
|
||||
frameworksGrouping.clear();
|
||||
for (const Core::Id &id : registered) {
|
||||
// get their active state
|
||||
frameworks.insert(id, s->value(QLatin1String(id.name()),
|
||||
frameworkManager->isActive(id)).toBool());
|
||||
// and whether grouping is enabled
|
||||
frameworksGrouping.insert(id, s->value(QLatin1String(id.name().append(groupSuffix)),
|
||||
frameworkManager->groupingEnabled(id)).toBool());
|
||||
}
|
||||
s->endGroup();
|
||||
}
|
||||
|
||||
@@ -50,6 +50,7 @@ struct TestSettings
|
||||
bool filterScan = false;
|
||||
bool processArgs = false;
|
||||
QHash<Core::Id, bool> frameworks;
|
||||
QHash<Core::Id, bool> frameworksGrouping;
|
||||
QStringList whiteListFilters;
|
||||
};
|
||||
|
||||
|
||||
@@ -164,7 +164,7 @@ TestSettings TestSettingsWidget::settings() const
|
||||
result.autoScroll = m_ui.autoScrollCB->isChecked();
|
||||
result.processArgs = m_ui.processArgsCB->isChecked();
|
||||
result.filterScan = m_ui.filterGroupBox->isChecked();
|
||||
result.frameworks = frameworks();
|
||||
frameworkSettings(result);
|
||||
result.whiteListFilters = filters();
|
||||
return result;
|
||||
}
|
||||
@@ -180,6 +180,11 @@ void TestSettingsWidget::populateFrameworksListWidget(const QHash<Core::Id, bool
|
||||
item->setFlags(Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsUserCheckable);
|
||||
item->setCheckState(0, frameworks.value(id) ? Qt::Checked : Qt::Unchecked);
|
||||
item->setData(0, Qt::UserRole, id.toSetting());
|
||||
item->setData(1, Qt::CheckStateRole, frameworkManager->groupingEnabled(id) ? Qt::Checked
|
||||
: Qt::Unchecked);
|
||||
item->setToolTip(0, tr("Enable or disable test frameworks to be handled by the AutoTest "
|
||||
"plugin."));
|
||||
item->setToolTip(1, tr("Enable or disable grouping of test cases by folder."));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -189,18 +194,18 @@ void TestSettingsWidget::populateFiltersWidget(const QStringList &filters)
|
||||
new QTreeWidgetItem(m_ui.filterTreeWidget, {filter} );
|
||||
}
|
||||
|
||||
QHash<Core::Id, bool> TestSettingsWidget::frameworks() const
|
||||
void TestSettingsWidget::frameworkSettings(TestSettings &settings) const
|
||||
{
|
||||
QHash<Core::Id, bool> frameworks;
|
||||
const QAbstractItemModel *model = m_ui.frameworkTreeWidget->model();
|
||||
QTC_ASSERT(model, return frameworks);
|
||||
QTC_ASSERT(model, return);
|
||||
const int itemCount = model->rowCount();
|
||||
for (int row = 0; row < itemCount; ++row) {
|
||||
const QModelIndex index = model->index(row, 0);
|
||||
frameworks.insert(Core::Id::fromSetting(index.data(Qt::UserRole)),
|
||||
index.data(Qt::CheckStateRole) == Qt::Checked);
|
||||
QModelIndex idx = model->index(row, 0);
|
||||
const Core::Id id = Core::Id::fromSetting(idx.data(Qt::UserRole));
|
||||
settings.frameworks.insert(id, idx.data(Qt::CheckStateRole) == Qt::Checked);
|
||||
idx = model->index(row, 1);
|
||||
settings.frameworksGrouping.insert(id, idx.data(Qt::CheckStateRole) == Qt::Checked);
|
||||
}
|
||||
return frameworks;
|
||||
}
|
||||
|
||||
QStringList TestSettingsWidget::filters() const
|
||||
@@ -298,13 +303,20 @@ void TestSettingsPage::apply()
|
||||
bool frameworkSyncNecessary = newSettings.frameworks != m_settings->frameworks;
|
||||
bool forceReparse = newSettings.filterScan != m_settings->filterScan ||
|
||||
newSettings.whiteListFilters.toSet() != m_settings->whiteListFilters.toSet();
|
||||
const QList<Core::Id> changedIds = Utils::filtered(newSettings.frameworksGrouping.keys(),
|
||||
[newSettings, this] (const Core::Id &id) {
|
||||
return newSettings.frameworksGrouping[id] != m_settings->frameworksGrouping[id];
|
||||
});
|
||||
*m_settings = newSettings;
|
||||
m_settings->toSettings(Core::ICore::settings());
|
||||
TestFrameworkManager::instance()->activateFrameworksFromSettings(m_settings);
|
||||
TestFrameworkManager *frameworkManager = TestFrameworkManager::instance();
|
||||
frameworkManager->activateFrameworksFromSettings(m_settings);
|
||||
if (frameworkSyncNecessary)
|
||||
TestTreeModel::instance()->syncTestFrameworks();
|
||||
else if (forceReparse)
|
||||
TestTreeModel::instance()->parser()->emitUpdateTestTree();
|
||||
else if (!changedIds.isEmpty())
|
||||
TestTreeModel::instance()->rebuild(changedIds);
|
||||
}
|
||||
|
||||
} // namespace Internal
|
||||
|
||||
@@ -48,7 +48,7 @@ public:
|
||||
private:
|
||||
void populateFrameworksListWidget(const QHash<Core::Id, bool> &frameworks);
|
||||
void populateFiltersWidget(const QStringList &filters);
|
||||
QHash<Core::Id, bool> frameworks() const;
|
||||
void frameworkSettings(TestSettings &settings) const;
|
||||
QStringList filters() const;
|
||||
void onFrameworkItemChanged();
|
||||
void onAddFilterClicked();
|
||||
|
||||
@@ -183,12 +183,29 @@ Warning: this is an experimental feature and might lead to failing to execute th
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="headerHidden">
|
||||
<bool>true</bool>
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="columnCount">
|
||||
<number>2</number>
|
||||
</property>
|
||||
<attribute name="headerDefaultSectionSize">
|
||||
<number>150</number>
|
||||
</attribute>
|
||||
<column>
|
||||
<property name="text">
|
||||
<string>Framework</string>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Selects the test frameworks to be handled by the AutoTest plugin.</string>
|
||||
</property>
|
||||
</column>
|
||||
<column>
|
||||
<property name="text">
|
||||
<string>Group</string>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Enables grouping of test cases.</string>
|
||||
</property>
|
||||
</column>
|
||||
</widget>
|
||||
</item>
|
||||
|
||||
@@ -32,6 +32,7 @@
|
||||
#include <cpptools/cppmodelmanager.h>
|
||||
#include <cpptools/cpptoolsreuse.h>
|
||||
#include <texteditor/texteditor.h>
|
||||
#include <utils/utilsicons.h>
|
||||
|
||||
#include <QIcon>
|
||||
|
||||
@@ -43,21 +44,31 @@ TestTreeItem::TestTreeItem(const QString &name, const QString &filePath, Type ty
|
||||
m_filePath(filePath),
|
||||
m_type(type)
|
||||
{
|
||||
m_checked = (m_type == TestCase || m_type == TestFunctionOrSet || m_type == Root)
|
||||
? Qt::Checked : Qt::Unchecked;
|
||||
switch (m_type) {
|
||||
case Root:
|
||||
case GroupNode:
|
||||
case TestCase:
|
||||
case TestFunctionOrSet:
|
||||
m_checked = Qt::Checked;
|
||||
break;
|
||||
default:
|
||||
m_checked = Qt::Unchecked;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static QIcon testTreeIcon(TestTreeItem::Type type)
|
||||
{
|
||||
static QIcon icons[] = {
|
||||
QIcon(),
|
||||
Utils::Icons::OPENFILE.icon(),
|
||||
CPlusPlus::Icons::iconForType(CPlusPlus::Icons::ClassIconType),
|
||||
CPlusPlus::Icons::iconForType(CPlusPlus::Icons::SlotPrivateIconType),
|
||||
QIcon(":/images/data.png")
|
||||
};
|
||||
|
||||
if (int(type) >= int(sizeof icons / sizeof *icons))
|
||||
return icons[2];
|
||||
return icons[3];
|
||||
return icons[type];
|
||||
}
|
||||
|
||||
@@ -76,6 +87,8 @@ QVariant TestTreeItem::data(int /*column*/, int role) const
|
||||
case Qt::CheckStateRole:
|
||||
return QVariant();
|
||||
case LinkRole: {
|
||||
if (m_type == GroupNode)
|
||||
return QVariant();
|
||||
QVariant itemLink;
|
||||
itemLink.setValue(Utils::Link(m_filePath, m_line, m_column));
|
||||
return itemLink;
|
||||
@@ -105,6 +118,7 @@ Qt::ItemFlags TestTreeItem::flags(int /*column*/) const
|
||||
static const Qt::ItemFlags defaultFlags = Qt::ItemIsEnabled | Qt::ItemIsSelectable;
|
||||
switch (m_type) {
|
||||
case Root:
|
||||
case GroupNode:
|
||||
return Qt::ItemIsEnabled | Qt::ItemIsAutoTristate | Qt::ItemIsUserCheckable;
|
||||
case TestCase:
|
||||
return defaultFlags | Qt::ItemIsAutoTristate | Qt::ItemIsUserCheckable;
|
||||
@@ -164,6 +178,7 @@ void TestTreeItem::setChecked(const Qt::CheckState checkState)
|
||||
break;
|
||||
}
|
||||
case Root:
|
||||
case GroupNode:
|
||||
case TestFunctionOrSet:
|
||||
case TestCase: {
|
||||
Qt::CheckState usedState = (checkState == Qt::Unchecked ? Qt::Unchecked : Qt::Checked);
|
||||
@@ -185,6 +200,7 @@ Qt::CheckState TestTreeItem::checked() const
|
||||
{
|
||||
switch (m_type) {
|
||||
case Root:
|
||||
case GroupNode:
|
||||
case TestCase:
|
||||
case TestFunctionOrSet:
|
||||
case TestDataTag:
|
||||
@@ -268,6 +284,9 @@ bool TestTreeItem::lessThan(const TestTreeItem *other, SortMode mode) const
|
||||
return index().row() > other->index().row();
|
||||
return lhs > rhs;
|
||||
case Naturally: {
|
||||
if (m_type == GroupNode && other->type() == GroupNode)
|
||||
return m_filePath > other->filePath();
|
||||
|
||||
const Utils::Link &leftLink = data(0, LinkRole).value<Utils::Link>();
|
||||
const Utils::Link &rightLink = other->data(0, LinkRole).value<Utils::Link>();
|
||||
if (leftLink.targetFileName == rightLink.targetFileName) {
|
||||
@@ -282,6 +301,16 @@ bool TestTreeItem::lessThan(const TestTreeItem *other, SortMode mode) const
|
||||
}
|
||||
}
|
||||
|
||||
bool TestTreeItem::isGroupNodeFor(const TestTreeItem *other) const
|
||||
{
|
||||
QTC_ASSERT(other, return false);
|
||||
if (type() != TestTreeItem::GroupNode)
|
||||
return false;
|
||||
|
||||
// for now there's only the possibility to have 'Folder' nodes
|
||||
return QFileInfo(other->filePath()).absolutePath() == filePath();
|
||||
}
|
||||
|
||||
QSet<QString> TestTreeItem::internalTargets() const
|
||||
{
|
||||
auto cppMM = CppTools::CppModelManager::instance();
|
||||
@@ -301,7 +330,7 @@ QSet<QString> TestTreeItem::internalTargets() const
|
||||
void TestTreeItem::revalidateCheckState()
|
||||
{
|
||||
const Type ttiType = type();
|
||||
if (ttiType != TestCase && ttiType != TestFunctionOrSet && ttiType != Root)
|
||||
if (ttiType != TestCase && ttiType != TestFunctionOrSet && ttiType != Root && ttiType != GroupNode)
|
||||
return;
|
||||
if (childCount() == 0) // can this happen? (we're calling revalidateCS() on parentItem()
|
||||
return;
|
||||
@@ -323,13 +352,13 @@ void TestTreeItem::revalidateCheckState()
|
||||
foundPartiallyChecked |= (child->checked() == Qt::PartiallyChecked);
|
||||
if (foundPartiallyChecked || (foundChecked && foundUnchecked)) {
|
||||
m_checked = Qt::PartiallyChecked;
|
||||
if (ttiType == TestFunctionOrSet || ttiType == TestCase)
|
||||
if (ttiType == TestFunctionOrSet || ttiType == TestCase || ttiType == GroupNode)
|
||||
parentItem()->revalidateCheckState();
|
||||
return;
|
||||
}
|
||||
}
|
||||
m_checked = (foundUnchecked ? Qt::Unchecked : Qt::Checked);
|
||||
if (ttiType == TestFunctionOrSet || ttiType == TestCase)
|
||||
if (ttiType == TestFunctionOrSet || ttiType == TestCase || ttiType == GroupNode)
|
||||
parentItem()->revalidateCheckState();
|
||||
}
|
||||
|
||||
|
||||
@@ -55,6 +55,7 @@ public:
|
||||
enum Type
|
||||
{
|
||||
Root,
|
||||
GroupNode,
|
||||
TestCase,
|
||||
TestFunctionOrSet,
|
||||
TestDataTag,
|
||||
@@ -112,7 +113,8 @@ public:
|
||||
virtual bool lessThan(const TestTreeItem *other, SortMode mode) const;
|
||||
virtual TestTreeItem *find(const TestParseResult *result) = 0;
|
||||
virtual bool modify(const TestParseResult *result) = 0;
|
||||
|
||||
virtual bool isGroupNodeFor(const TestTreeItem *other) const;
|
||||
virtual TestTreeItem *createParentGroupNode() const = 0;
|
||||
virtual QSet<QString> internalTargets() const;
|
||||
protected:
|
||||
typedef std::function<bool(const TestTreeItem *)> CompareFunction;
|
||||
|
||||
@@ -110,6 +110,7 @@ bool TestTreeModel::setData(const QModelIndex &index, const QVariant &value, int
|
||||
if (role == Qt::CheckStateRole) {
|
||||
switch (item->type()) {
|
||||
case TestTreeItem::Root:
|
||||
case TestTreeItem::GroupNode:
|
||||
case TestTreeItem::TestCase:
|
||||
if (item->childCount() > 0)
|
||||
emit dataChanged(index.child(0, 0), index.child(item->childCount() - 1, 0));
|
||||
@@ -174,6 +175,31 @@ void TestTreeModel::syncTestFrameworks()
|
||||
emit updatedActiveFrameworks(sortedIds.size());
|
||||
}
|
||||
|
||||
void TestTreeModel::rebuild(const QList<Core::Id> &frameworkIds)
|
||||
{
|
||||
TestFrameworkManager *frameworkManager = TestFrameworkManager::instance();
|
||||
for (const Core::Id &id : frameworkIds) {
|
||||
TestTreeItem *frameworkRoot = frameworkManager->rootNodeForTestFramework(id);
|
||||
const bool groupingEnabled = TestFrameworkManager::instance()->groupingEnabled(id);
|
||||
for (int row = frameworkRoot->childCount() - 1; row >= 0; --row) {
|
||||
auto testItem = frameworkRoot->childItem(row);
|
||||
if (!groupingEnabled && testItem->type() == TestTreeItem::GroupNode) {
|
||||
// do not re-insert the GroupNode, but process its children and delete it afterwards
|
||||
for (int childRow = testItem->childCount() - 1; childRow >= 0; --childRow) {
|
||||
// FIXME should this be done recursively until we have a non-GroupNode?
|
||||
TestTreeItem *childTestItem = testItem->childItem(childRow);
|
||||
takeItem(childTestItem);
|
||||
insertItemInParent(childTestItem, frameworkRoot, groupingEnabled);
|
||||
}
|
||||
delete takeItem(testItem);
|
||||
} else {
|
||||
takeItem(testItem);
|
||||
insertItemInParent(testItem, frameworkRoot, groupingEnabled);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void TestTreeModel::removeFiles(const QStringList &files)
|
||||
{
|
||||
for (const QString &file : files)
|
||||
@@ -239,6 +265,24 @@ bool TestTreeModel::sweepChildren(TestTreeItem *item)
|
||||
return hasChanged;
|
||||
}
|
||||
|
||||
void TestTreeModel::insertItemInParent(TestTreeItem *item, TestTreeItem *root, bool groupingEnabled)
|
||||
{
|
||||
TestTreeItem *parentNode = root;
|
||||
if (groupingEnabled) {
|
||||
parentNode = root->findChildBy([item] (const TestTreeItem *it) {
|
||||
return it->isGroupNodeFor(item);
|
||||
});
|
||||
if (!parentNode) {
|
||||
parentNode = item->createParentGroupNode();
|
||||
if (!parentNode) // we might not get a group node at all
|
||||
parentNode = root;
|
||||
else
|
||||
root->appendChild(parentNode);
|
||||
}
|
||||
}
|
||||
parentNode->appendChild(item);
|
||||
}
|
||||
|
||||
void TestTreeModel::onParseResultReady(const TestParseResultPtr result)
|
||||
{
|
||||
TestTreeItem *rootNode
|
||||
@@ -249,10 +293,19 @@ void TestTreeModel::onParseResultReady(const TestParseResultPtr result)
|
||||
|
||||
void TestTreeModel::handleParseResult(const TestParseResult *result, TestTreeItem *parentNode)
|
||||
{
|
||||
const bool groupingEnabled =
|
||||
TestFrameworkManager::instance()->groupingEnabled(result->frameworkId);
|
||||
// lookup existing items
|
||||
if (TestTreeItem *toBeModified = parentNode->find(result)) {
|
||||
// found existing item... Do not remove
|
||||
toBeModified->markForRemoval(false);
|
||||
// if it's a reparse we need to mark the group node as well to avoid purging it in sweep()
|
||||
if (groupingEnabled) {
|
||||
if (auto directParent = toBeModified->parentItem()) {
|
||||
if (directParent->type() == TestTreeItem::GroupNode)
|
||||
directParent->markForRemoval(false);
|
||||
}
|
||||
}
|
||||
// modify and when content has changed inform ui
|
||||
if (toBeModified->modify(result)) {
|
||||
const QModelIndex &idx = indexForItem(toBeModified);
|
||||
@@ -266,7 +319,8 @@ void TestTreeModel::handleParseResult(const TestParseResult *result, TestTreeIte
|
||||
// if there's no matching item, add the new one
|
||||
TestTreeItem *newItem = result->createTestTreeItem();
|
||||
QTC_ASSERT(newItem, return);
|
||||
parentNode->appendChild(newItem);
|
||||
|
||||
insertItemInParent(newItem, parentNode, groupingEnabled);
|
||||
// new items are checked by default - revalidation of parents might be necessary
|
||||
if (parentNode->checked() != Qt::Checked) {
|
||||
parentNode->revalidateCheckState();
|
||||
|
||||
@@ -56,6 +56,7 @@ public:
|
||||
QList<TestConfiguration *> getSelectedTests() const;
|
||||
|
||||
void syncTestFrameworks();
|
||||
void rebuild(const QList<Core::Id> &frameworkIds);
|
||||
|
||||
#ifdef WITH_TESTS
|
||||
int autoTestsCount() const;
|
||||
@@ -86,6 +87,7 @@ private:
|
||||
void removeTestRootNodes();
|
||||
void removeFiles(const QStringList &files);
|
||||
bool sweepChildren(TestTreeItem *item);
|
||||
static void insertItemInParent(TestTreeItem *item, TestTreeItem *root, bool groupingEnabled);
|
||||
|
||||
explicit TestTreeModel(QObject *parent = 0);
|
||||
void setupParsingConnections();
|
||||
|
||||
Reference in New Issue
Block a user