AutoTest: Introduce ITestTreeItem

Preparation for having separated test tree items with a
common base.

Change-Id: I3735f582cc96910e971f5a41c799cc0729a10a58
Reviewed-by: David Schulz <david.schulz@qt.io>
This commit is contained in:
Christian Stenger
2020-10-12 14:11:10 +02:00
parent b057ea1ab8
commit 55298cc211
14 changed files with 313 additions and 256 deletions

View File

@@ -286,7 +286,7 @@ TestConfiguration *BoostTestTreeItem::testConfiguration() const
if (itemType == TestSuite || itemType == TestCase) {
QStringList testCases;
if (itemType == TestSuite) {
forFirstLevelChildren([&testCases](TestTreeItem *child) {
forFirstLevelChildItems([&testCases](TestTreeItem *child) {
QTC_ASSERT(child, return);
if (auto boostItem = static_cast<BoostTestTreeItem *>(child)) {
if (boostItem->enabled()) {

View File

@@ -89,7 +89,7 @@ TestTreeItem *CatchTreeItem::find(const TestParseResult *result)
if (static_cast<CatchFramework *>(result->base)->grouping()) {
const QString path = QFileInfo(result->fileName).absolutePath();
for (int row = 0; row < childCount(); ++row) {
TestTreeItem *group = childAt(row);
TestTreeItem *group = childItem(row);
if (group->filePath() != path)
continue;
if (auto groupChild = group->findChildByFile(result->fileName))
@@ -192,7 +192,7 @@ static void collectTestInfo(const TestTreeItem *item,
QTC_ASSERT(item, return);
const int childCount = item->childCount();
if (item->type() == TestTreeItem::GroupNode) {
item->forFirstLevelChildren([&testCasesForProfile, ignoreCheckState](TestTreeItem *it) {
item->forFirstLevelChildItems([&testCasesForProfile, ignoreCheckState](TestTreeItem *it) {
collectTestInfo(it, testCasesForProfile, ignoreCheckState);
});
return;
@@ -201,14 +201,14 @@ static void collectTestInfo(const TestTreeItem *item,
QTC_ASSERT(childCount != 0, return);
QTC_ASSERT(item->type() == TestTreeItem::TestSuite, return);
if (ignoreCheckState || item->checked() == Qt::Checked) {
const QString &projectFile = item->childAt(0)->proFile();
item->forAllChildren([&testCasesForProfile, &projectFile](TestTreeItem *it) {
const QString &projectFile = item->childItem(0)->proFile();
item->forAllChildItems([&testCasesForProfile, &projectFile](TestTreeItem *it) {
CatchTreeItem *current = static_cast<CatchTreeItem *>(it);
testCasesForProfile[projectFile].names.append(current->testCasesString());
});
testCasesForProfile[projectFile].internalTargets.unite(item->internalTargets());
} else if (item->checked() == Qt::PartiallyChecked) {
item->forFirstLevelChildren([&testCasesForProfile](TestTreeItem *child) {
item->forFirstLevelChildItems([&testCasesForProfile](TestTreeItem *child) {
QTC_ASSERT(child->type() == TestTreeItem::TestCase, return);
if (child->checked() == Qt::Checked) {
CatchTreeItem *current = static_cast<CatchTreeItem *>(child);
@@ -227,7 +227,7 @@ static void collectFailedTestInfo(const CatchTreeItem *item,
QTC_ASSERT(item, return);
QTC_ASSERT(item->type() == TestTreeItem::Root, return);
item->forAllChildren([&testCasesForProfile](TestTreeItem *it) {
item->forAllChildItems([&testCasesForProfile](TestTreeItem *it) {
QTC_ASSERT(it, return);
CatchTreeItem *parent = static_cast<CatchTreeItem *>(it->parentItem());
QTC_ASSERT(parent, return);
@@ -283,7 +283,7 @@ QList<TestConfiguration *> CatchTreeItem::getTestConfigurationsForFile(const Uti
const QString filePath = fileName.toString();
for (int row = 0, count = childCount(); row < count; ++row) {
const TestTreeItem *item = childAt(row);
const TestTreeItem *item = childItem(row);
QTC_ASSERT(item, continue);
if (childAt(row)->name() != filePath)
@@ -292,7 +292,7 @@ QList<TestConfiguration *> CatchTreeItem::getTestConfigurationsForFile(const Uti
CatchConfiguration *testConfig = nullptr;
QStringList testCases;
item->forFirstLevelChildren([&testCases](TestTreeItem *child) {
item->forFirstLevelChildItems([&testCases](TestTreeItem *child) {
CatchTreeItem *current = static_cast<CatchTreeItem *>(child);
testCases << current->testCasesString();
});
@@ -326,9 +326,8 @@ QList<TestConfiguration *> CatchTreeItem::getTestConfigurations(bool ignoreCheck
return result;
QHash<QString, CatchTestCases> testCasesForProfile;
forFirstLevelChildren([&testCasesForProfile, ignoreCheckState](TestTreeItem *item) {
collectTestInfo(item, testCasesForProfile, ignoreCheckState);
});
for (int row = 0, end = childCount(); row < end; ++row)
collectTestInfo(childItem(row), testCasesForProfile, ignoreCheckState);
for (auto it = testCasesForProfile.begin(), end = testCasesForProfile.end(); it != end; ++it) {
for (const QString &target : qAsConst(it.value().internalTargets)) {

View File

@@ -230,13 +230,13 @@ static void collectTestInfo(const GTestTreeItem *item,
QTC_ASSERT(childCount != 0, return);
QTC_ASSERT(item->type() == TestTreeItem::TestSuite, return);
if (ignoreCheckState || item->checked() == Qt::Checked) {
const QString &projectFile = item->childAt(0)->proFile();
const QString &projectFile = item->childItem(0)->proFile();
testCasesForProFile[projectFile].filters.append(
gtestFilter(item->state()).arg(item->name()).arg('*'));
testCasesForProFile[projectFile].testSetCount += childCount - 1;
testCasesForProFile[projectFile].internalTargets.unite(item->internalTargets());
} else if (item->checked() == Qt::PartiallyChecked) {
item->forFirstLevelChildren([&testCasesForProFile, item](TestTreeItem *child){
item->forFirstLevelChildItems([&testCasesForProFile, item](TestTreeItem *child){
QTC_ASSERT(child->type() == TestTreeItem::TestCase, return);
if (child->checked() == Qt::Checked) {
testCasesForProFile[child->proFile()].filters.append(
@@ -254,7 +254,7 @@ static void collectFailedTestInfo(const GTestTreeItem *item,
QTC_ASSERT(item, return);
QTC_ASSERT(item->type() == TestTreeItem::Root, return);
item->forAllChildren([&testCasesForProfile](TestTreeItem *it) {
item->forAllChildItems([&testCasesForProfile](TestTreeItem *it) {
QTC_ASSERT(it, return);
GTestTreeItem *parent = static_cast<GTestTreeItem *>(it->parentItem());
QTC_ASSERT(parent, return);
@@ -340,7 +340,7 @@ QList<TestConfiguration *> GTestTreeItem::getTestConfigurationsForFile(const Uti
QHash<QString, GTestCases> testCases;
const QString &file = fileName.toString();
forAllChildren([&testCases, &file](TestTreeItem *node) {
forAllChildItems([&testCases, &file](TestTreeItem *node) {
if (node->type() == Type::TestCase && node->filePath() == file) {
QTC_ASSERT(node->parentItem(), return);
const GTestTreeItem *testCase = static_cast<GTestTreeItem *>(node->parentItem());
@@ -469,7 +469,7 @@ TestTreeItem *GTestTreeItem::createParentGroupNode() const
return new GTestTreeItem(framework(), base.baseName(), fileInfo.absolutePath(), TestTreeItem::GroupNode);
} else { // GTestFilter
QTC_ASSERT(childCount(), return nullptr); // paranoia
const TestTreeItem *firstChild = childAt(0);
const TestTreeItem *firstChild = childItem(0);
const QString activeFilter = GTestFramework::currentGTestFilter();
const QString fullTestName = name() + '.' + firstChild->name();
const QString groupNodeName =
@@ -497,7 +497,7 @@ TestTreeItem *GTestTreeItem::findChildByNameStateAndFile(const QString &name,
GTestTreeItem::TestStates state,
const QString &proFile) const
{
return findFirstLevelChild([name, state, proFile](const TestTreeItem *other) {
return findFirstLevelChildItem([name, state, proFile](const TestTreeItem *other) {
const GTestTreeItem *gtestItem = static_cast<const GTestTreeItem *>(other);
return other->proFile() == proFile && other->name() == name && gtestItem->state() == state;
});

View File

@@ -38,7 +38,7 @@ template<class T>
class ItemDataCache
{
public:
void insert(TestTreeItem *item, const T &value) { m_cache[item->cacheName()] = {0, value}; }
void insert(ITestTreeItem *item, const T &value) { m_cache[item->cacheName()] = {0, value}; }
void evolve()
{
auto it = m_cache.begin(), end = m_cache.end();
@@ -46,7 +46,7 @@ public:
it = it->generation++ >= maxGen ? m_cache.erase(it) : ++it;
}
Utils::optional<T> get(TestTreeItem *item)
Utils::optional<T> get(ITestTreeItem *item)
{
auto entry = m_cache.find(item->cacheName());
if (entry == m_cache.end())

View File

@@ -53,10 +53,10 @@ QHash<QString, QString> testCaseNamesForFiles(ITestFramework *framework, const Q
TestTreeItem *rootNode = framework->rootNode();
QTC_ASSERT(rootNode, return result);
rootNode->forFirstLevelChildren([&result, &files](TestTreeItem *child) {
rootNode->forFirstLevelChildren([&result, &files](ITestTreeItem *child) {
if (files.contains(child->filePath()))
result.insert(child->filePath(), child->name());
child->forFirstLevelChildren([&result, &files, child](TestTreeItem *grandChild) {
child->forFirstLevelChildren([&result, &files, child](ITestTreeItem *grandChild) {
if (files.contains(grandChild->filePath()))
result.insert(grandChild->filePath(), child->name());
});
@@ -70,7 +70,7 @@ QMultiHash<QString, QString> alternativeFiles(ITestFramework *framework, const Q
TestTreeItem *rootNode = framework->rootNode();
QTC_ASSERT(rootNode, return result);
rootNode->forFirstLevelChildren([&result, &files](TestTreeItem *child) {
rootNode->forFirstLevelChildren([&result, &files](ITestTreeItem *child) {
const QString &baseFilePath = child->filePath();
for (int childRow = 0, count = child->childCount(); childRow < count; ++childRow) {
auto grandChild = static_cast<const QtTestTreeItem *>(child->childAt(childRow));

View File

@@ -154,7 +154,7 @@ static void fillTestConfigurationsFromCheckState(const TestTreeItem *item,
QTC_ASSERT(item, return);
if (item->type() == TestTreeItem::GroupNode) {
for (int row = 0, count = item->childCount(); row < count; ++row)
fillTestConfigurationsFromCheckState(item->childAt(row), testConfigurations);
fillTestConfigurationsFromCheckState(item->childItem(row), testConfigurations);
return;
}
QTC_ASSERT(item->type() == TestTreeItem::TestCase, return);
@@ -169,12 +169,12 @@ static void fillTestConfigurationsFromCheckState(const TestTreeItem *item,
return;
case Qt::PartiallyChecked:
QStringList testCases;
item->forFirstLevelChildren([&testCases](TestTreeItem *grandChild) {
item->forFirstLevelChildren([&testCases](ITestTreeItem *grandChild) {
if (grandChild->checked() == Qt::Checked) {
testCases << grandChild->name();
} else if (grandChild->checked() == Qt::PartiallyChecked) {
const QString funcName = grandChild->name();
grandChild->forFirstLevelChildren([&testCases, &funcName](TestTreeItem *dataTag) {
grandChild->forFirstLevelChildren([&testCases, &funcName](ITestTreeItem *dataTag) {
if (dataTag->checked() == Qt::Checked)
testCases << funcName + ':' + dataTag->name();
});
@@ -195,16 +195,16 @@ static void collectFailedTestInfo(TestTreeItem *item, QList<TestConfiguration *>
QTC_ASSERT(item, return);
if (item->type() == TestTreeItem::GroupNode) {
for (int row = 0, count = item->childCount(); row < count; ++row)
collectFailedTestInfo(item->childAt(row), testConfigs);
collectFailedTestInfo(item->childItem(row), testConfigs);
return;
}
QTC_ASSERT(item->type() == TestTreeItem::TestCase, return);
QStringList testCases;
item->forFirstLevelChildren([&testCases](TestTreeItem *func) {
item->forFirstLevelChildren([&testCases](ITestTreeItem *func) {
if (func->data(0, FailedRole).toBool()) {
testCases << func->name();
} else {
func->forFirstLevelChildren([&testCases, func](TestTreeItem *dataTag) {
func->forFirstLevelChildren([&testCases, func](ITestTreeItem *dataTag) {
if (dataTag->data(0, FailedRole).toBool())
testCases << func->name() + ':' + dataTag->name();
});
@@ -237,13 +237,13 @@ QList<TestConfiguration *> QtTestTreeItem::getAllTestConfigurations() const
if (!project || type() != Root)
return result;
forFirstLevelChildren([&result](TestTreeItem *child) {
forFirstLevelChildren([&result](ITestTreeItem *child) {
if (child->type() == TestCase) {
TestConfiguration *tc = child->testConfiguration();
QTC_ASSERT(tc, return);
result << tc;
} else if (child->type() == GroupNode) {
child->forFirstLevelChildren([&result](TestTreeItem *groupChild) {
child->forFirstLevelChildren([&result](ITestTreeItem *groupChild) {
TestConfiguration *tc = groupChild->testConfiguration();
QTC_ASSERT(tc, return);
result << tc;
@@ -261,7 +261,7 @@ QList<TestConfiguration *> QtTestTreeItem::getSelectedTestConfigurations() const
return result;
for (int row = 0, count = childCount(); row < count; ++row)
fillTestConfigurationsFromCheckState(childAt(row), result);
fillTestConfigurationsFromCheckState(childItem(row), result);
return result;
}
@@ -270,9 +270,8 @@ QList<TestConfiguration *> QtTestTreeItem::getFailedTestConfigurations() const
{
QList<TestConfiguration *> result;
QTC_ASSERT(type() == TestTreeItem::Root, return result);
forFirstLevelChildren([&result](TestTreeItem *child) {
collectFailedTestInfo(child, result);
});
for (int row = 0, end = childCount(); row < end; ++row)
collectFailedTestInfo(childItem(row), result);
return result;
}
@@ -286,7 +285,7 @@ QList<TestConfiguration *> QtTestTreeItem::getTestConfigurationsForFile(const Ut
QHash<TestTreeItem *, QStringList> testFunctions;
const QString &file = fileName.toString();
forAllChildren([&testFunctions, &file](TestTreeItem *node) {
forAllChildItems([&testFunctions, &file](TestTreeItem *node) {
if (node->type() == Type::TestFunction && node->filePath() == file) {
QTC_ASSERT(node->parentItem(), return);
TestTreeItem *testCase = node->parentItem();
@@ -314,7 +313,7 @@ TestTreeItem *QtTestTreeItem::find(const TestParseResult *result)
if (static_cast<QtTestFramework *>(result->base)->grouping()) {
const QString path = QFileInfo(result->fileName).absolutePath();
for (int row = 0; row < childCount(); ++row) {
TestTreeItem *group = childAt(row);
TestTreeItem *group = childItem(row);
if (group->filePath() != path)
continue;
if (auto groupChild = group->findChildByFile(result->fileName))
@@ -394,7 +393,7 @@ bool QtTestTreeItem::isGroupable() const
TestTreeItem *QtTestTreeItem::findChildByNameAndInheritance(const QString &name, bool inherited) const
{
return findFirstLevelChild([name, inherited](const TestTreeItem *other) {
return findFirstLevelChildItem([name, inherited](const TestTreeItem *other) {
const QtTestTreeItem *qtOther = static_cast<const QtTestTreeItem *>(other);
return qtOther->inherited() == inherited && qtOther->name() == name;
});

View File

@@ -52,14 +52,14 @@ QHash<QString, QString> proFilesForQmlFiles(ITestFramework *framework, const QSt
if (files.isEmpty())
return result;
rootNode->forFirstLevelChildren([&result, &files](TestTreeItem *child) {
rootNode->forFirstLevelChildItems([&result, &files](TestTreeItem *child) {
const QString &file = child->filePath();
if (!file.isEmpty() && files.contains(file)) {
const QString &proFile = child->proFile();
if (!proFile.isEmpty())
result.insert(file, proFile);
}
child->forFirstLevelChildren([&result, &files](TestTreeItem *grandChild) {
child->forFirstLevelChildItems([&result, &files](TestTreeItem *grandChild) {
const QString &file = grandChild->filePath();
if (!file.isEmpty() && files.contains(file)) {
const QString &proFile = grandChild->proFile();

View File

@@ -133,7 +133,7 @@ TestConfiguration *QuickTestTreeItem::testConfiguration() const
case TestCase: {
const QString testName = name();
QStringList testFunctions;
forFirstLevelChildren([&testFunctions, &testName](TestTreeItem *child) {
forFirstLevelChildren([&testFunctions, &testName](ITestTreeItem *child) {
if (child->type() == TestTreeItem::TestFunction)
testFunctions << testName + "::" + child->name();
});
@@ -177,7 +177,7 @@ static QList<TestConfiguration *> testConfigurationsFor(
const QString name = treeItem->name();
QStringList functions;
treeItem->forFirstLevelChildren([&functions, &name, &predicate](TestTreeItem *child) {
treeItem->forFirstLevelChildItems([&functions, &name, &predicate](TestTreeItem *child) {
if (predicate(child))
functions << name + "::" + child->name();
});
@@ -228,10 +228,10 @@ QList<TestConfiguration *> QuickTestTreeItem::getAllTestConfigurations() const
return result;
QHash<QString, Tests> testsForProfile;
forFirstLevelChildren([&testsForProfile](TestTreeItem *child) {
forFirstLevelChildItems([&testsForProfile](TestTreeItem *child) {
// unnamed Quick Tests must be handled separately
if (child->name().isEmpty()) {
child->forFirstLevelChildren([&testsForProfile](TestTreeItem *grandChild) {
child->forFirstLevelChildItems([&testsForProfile](TestTreeItem *grandChild) {
const QString &proFile = grandChild->proFile();
++(testsForProfile[proFile].testCount);
testsForProfile[proFile].internalTargets = grandChild->internalTargets();
@@ -242,7 +242,7 @@ QList<TestConfiguration *> QuickTestTreeItem::getAllTestConfigurations() const
if (child->type() == TestCase) {
addTestsForItem(testsForProfile[child->proFile()], child);
} else if (child->type() == GroupNode) {
child->forFirstLevelChildren([&testsForProfile](TestTreeItem *grandChild) {
child->forFirstLevelChildItems([&testsForProfile](TestTreeItem *grandChild) {
addTestsForItem(testsForProfile[grandChild->proFile()], grandChild);
});
}
@@ -292,7 +292,7 @@ TestTreeItem *QuickTestTreeItem::find(const TestParseResult *result)
return unnamedQuickTests();
if (static_cast<QuickTestFramework *>(result->base)->grouping()) {
const QString path = QFileInfo(result->fileName).absolutePath();
TestTreeItem *group = findFirstLevelChild([path](TestTreeItem *group) {
TestTreeItem *group = findFirstLevelChildItem([path](TestTreeItem *group) {
return group->filePath() == path;
});
return group ? group->findChildByNameAndFile(result->name, result->fileName) : nullptr;
@@ -348,14 +348,14 @@ bool QuickTestTreeItem::modify(const TestParseResult *result)
}
}
bool QuickTestTreeItem::lessThan(const TestTreeItem *other, TestTreeItem::SortMode mode) const
bool QuickTestTreeItem::lessThan(const ITestTreeItem *other, TestTreeItem::SortMode mode) const
{
// handle special item (<unnamed>)
if (name().isEmpty())
return false;
if (other->name().isEmpty())
return true;
return TestTreeItem::lessThan(other, mode);
return ITestTreeItem::lessThan(other, mode);
}
bool QuickTestTreeItem::isGroupNodeFor(const TestTreeItem *other) const
@@ -405,7 +405,7 @@ void QuickTestTreeItem::markForRemovalRecursively(const QString &filePath)
const QString proFile = parser->projectFileForMainCppFile(filePath);
if (!proFile.isEmpty()) {
TestTreeItem *root = framework()->rootNode();
root->forAllChildren([proFile](TestTreeItem *it) {
root->forAllChildItems([proFile](TestTreeItem *it) {
if (it->proFile() == proFile)
it->markForRemoval(true);
});
@@ -417,7 +417,7 @@ TestTreeItem *QuickTestTreeItem::findChildByFileNameAndType(const QString &fileP
TestTreeItem::Type tType)
{
return findFirstLevelChild([filePath, name, tType](const TestTreeItem *other) {
return findFirstLevelChildItem([filePath, name, tType](const TestTreeItem *other) {
return other->type() == tType && other->name() == name && other->filePath() == filePath;
});
}
@@ -425,7 +425,7 @@ TestTreeItem *QuickTestTreeItem::findChildByFileNameAndType(const QString &fileP
TestTreeItem *QuickTestTreeItem::findChildByNameFileAndLine(const QString &name,
const QString &filePath, int line)
{
return findFirstLevelChild([name, filePath, line](const TestTreeItem *other) {
return findFirstLevelChildItem([name, filePath, line](const TestTreeItem *other) {
return other->filePath() == filePath && other->line() == line && other->name() == name;
});
}
@@ -435,7 +435,7 @@ TestTreeItem *QuickTestTreeItem::unnamedQuickTests() const
if (type() != Root)
return nullptr;
return findFirstLevelChild([](TestTreeItem *child) { return child->name().isEmpty(); });
return findFirstLevelChildItem([](TestTreeItem *child) { return child->name().isEmpty(); });
}
} // namespace Internal

View File

@@ -54,7 +54,7 @@ public:
TestTreeItem *find(const TestParseResult *result) override;
TestTreeItem *findChild(const TestTreeItem *other) override;
bool modify(const TestParseResult *result) override;
bool lessThan(const TestTreeItem *other, SortMode mode) const override;
bool lessThan(const ITestTreeItem *other, SortMode mode) const override;
bool isGroupNodeFor(const TestTreeItem *other) const override;
bool removeOnSweepIfEmpty() const override;
TestTreeItem *createParentGroupNode() const override;

View File

@@ -242,7 +242,7 @@ void TestNavigationWidget::updateExpandedStateCache()
for (Utils::TreeItem *rootNode : *m_model->rootItem()) {
rootNode->forAllChildren([this](Utils::TreeItem *child) {
m_expandedStateCache.insert(static_cast<TestTreeItem *>(child),
m_expandedStateCache.insert(static_cast<ITestTreeItem *>(child),
m_view->isExpanded(child->index()));
});
}
@@ -322,7 +322,7 @@ void TestNavigationWidget::reapplyCachedExpandedState()
using namespace Utils;
for (TreeItem *rootNode : *m_model->rootItem()) {
rootNode->forAllChildren([this](TreeItem *child) {
optional<bool> cached = m_expandedStateCache.get(static_cast<TestTreeItem *>(child));
optional<bool> cached = m_expandedStateCache.get(static_cast<ITestTreeItem *>(child));
if (cached.has_value()) {
QModelIndex index = child->index();
if (m_view->isExpanded(index) != cached.value())

View File

@@ -40,27 +40,6 @@
namespace Autotest {
TestTreeItem::TestTreeItem(ITestBase *testBase, const QString &name,
const QString &filePath, Type type)
: m_testBase(testBase),
m_name(name),
m_filePath(filePath),
m_type(type)
{
switch (m_type) {
case Root:
case GroupNode:
case TestSuite:
case TestCase:
case TestFunction:
m_checked = Qt::Checked;
break;
default:
m_checked = Qt::Unchecked;
break;
}
}
static QIcon testTreeIcon(TestTreeItem::Type type)
{
static QIcon icons[] = {
@@ -77,7 +56,15 @@ static QIcon testTreeIcon(TestTreeItem::Type type)
return icons[type];
}
QVariant TestTreeItem::data(int /*column*/, int role) const
ITestTreeItem::ITestTreeItem(ITestBase *testBase, const QString &name,
const QString &filePath, Type type)
: m_testBase(testBase)
, m_name(name)
, m_filePath(filePath)
, m_type(type)
{}
QVariant ITestTreeItem::data(int /*column*/, int role) const
{
switch (role) {
case Qt::DisplayRole:
@@ -91,13 +78,6 @@ QVariant TestTreeItem::data(int /*column*/, int role) const
return testTreeIcon(m_type);
case Qt::CheckStateRole:
return QVariant();
case LinkRole: {
if (m_type == GroupNode)
return QVariant();
QVariant itemLink;
itemLink.setValue(Utils::Link(m_filePath, int(m_line), int(m_column)));
return itemLink;
}
case ItalicRole:
return false;
case TypeRole:
@@ -110,7 +90,7 @@ QVariant TestTreeItem::data(int /*column*/, int role) const
return QVariant();
}
bool TestTreeItem::setData(int /*column*/, const QVariant &data, int role)
bool ITestTreeItem::setData(int /*column*/, const QVariant &data, int role)
{
if (role == Qt::CheckStateRole) {
Qt::CheckState old = m_checked;
@@ -122,10 +102,10 @@ bool TestTreeItem::setData(int /*column*/, const QVariant &data, int role)
return false;
}
Qt::ItemFlags TestTreeItem::flags(int /*column*/) const
Qt::ItemFlags ITestTreeItem::flags(int /*column*/) const
{
static const Qt::ItemFlags defaultFlags = Qt::ItemIsEnabled | Qt::ItemIsSelectable;
switch (m_type) {
switch (type()) {
case Root:
case GroupNode:
return Qt::ItemIsEnabled | Qt::ItemIsAutoTristate | Qt::ItemIsUserCheckable;
@@ -139,6 +119,70 @@ Qt::ItemFlags TestTreeItem::flags(int /*column*/) const
}
}
Qt::CheckState ITestTreeItem::checked() const
{
return m_checked;
}
bool ITestTreeItem::lessThan(const ITestTreeItem *other, ITestTreeItem::SortMode mode) const
{
const QString &lhs = data(0, Qt::DisplayRole).toString();
const QString &rhs = other->data(0, Qt::DisplayRole).toString();
switch (mode) {
case Alphabetically:
if (lhs == rhs)
return index().row() > other->index().row();
return lhs > rhs;
case Naturally: {
if (type() == GroupNode && other->type() == GroupNode)
return 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) {
return leftLink.targetLine == rightLink.targetLine
? leftLink.targetColumn > rightLink.targetColumn
: leftLink.targetLine > rightLink.targetLine;
}
return leftLink.targetFileName > rightLink.targetFileName;
}
}
return true;
}
/****************************** TestTreeItem ********************************************/
TestTreeItem::TestTreeItem(ITestBase *testBase, const QString &name,
const QString &filePath, Type type)
: ITestTreeItem(testBase, name, filePath, type)
{
switch (type) {
case Root:
case GroupNode:
case TestSuite:
case TestCase:
case TestFunction:
m_checked = Qt::Checked;
break;
default:
m_checked = Qt::Unchecked;
break;
}
}
QVariant TestTreeItem::data(int column, int role) const
{
if (role == LinkRole) {
if (type() == GroupNode)
return QVariant();
QVariant itemLink;
itemLink.setValue(Utils::Link(filePath(), line(), int(m_column)));
return itemLink;
}
return ITestTreeItem::data(column, role);
}
bool TestTreeItem::modifyTestCaseOrSuiteContent(const TestParseResult *result)
{
bool hasBeenModified = modifyName(result->name);
@@ -164,8 +208,8 @@ bool TestTreeItem::modifyDataTagContent(const TestParseResult *result)
bool TestTreeItem::modifyLineAndColumn(const TestParseResult *result)
{
bool hasBeenModified = false;
if (m_line != result->line) {
m_line = result->line;
if (line() != result->line) {
setLine(result->line);
hasBeenModified = true;
}
if (m_column != result->column) {
@@ -175,21 +219,6 @@ bool TestTreeItem::modifyLineAndColumn(const TestParseResult *result)
return hasBeenModified;
}
Qt::CheckState TestTreeItem::checked() const
{
switch (m_type) {
case Root:
case GroupNode:
case TestSuite:
case TestCase:
case TestFunction:
case TestDataTag:
return m_checked;
default:
return Qt::Unchecked;
}
}
void TestTreeItem::markForRemoval(bool mark)
{
m_status = mark ? MarkedForRemoval : Cleared;
@@ -199,19 +228,24 @@ void TestTreeItem::markForRemovalRecursively(bool mark)
{
markForRemoval(mark);
for (int row = 0, count = childCount(); row < count; ++row)
childAt(row)->markForRemovalRecursively(mark);
childItem(row)->markForRemovalRecursively(mark);
}
void TestTreeItem::markForRemovalRecursively(const QString &filePath)
void TestTreeItem::markForRemovalRecursively(const QString &filepath)
{
bool mark = m_filePath == filePath;
forFirstLevelChildren([&mark, &filePath](TestTreeItem *child) {
child->markForRemovalRecursively(filePath);
bool mark = filePath() == filepath;
forFirstLevelChildItems([&mark, &filepath](TestTreeItem *child) {
child->markForRemovalRecursively(filepath);
mark &= child->markedForRemoval();
});
markForRemoval(mark);
}
TestTreeItem *TestTreeItem::childItem(int at) const
{
return static_cast<TestTreeItem *>(childAt(at));
}
TestTreeItem *TestTreeItem::parentItem() const
{
return static_cast<TestTreeItem *>(parent());
@@ -219,26 +253,27 @@ TestTreeItem *TestTreeItem::parentItem() const
TestTreeItem *TestTreeItem::findChildByName(const QString &name)
{
return findFirstLevelChild([name](const TestTreeItem *other) { return other->name() == name; });
return findFirstLevelChildItem([name](const TestTreeItem *other) {
return other->name() == name;
});
}
TestTreeItem *TestTreeItem::findChildByFile(const QString &filePath)
{
return findFirstLevelChild([filePath](const TestTreeItem *other) {
return findFirstLevelChildItem([filePath](const TestTreeItem *other) {
return other->filePath() == filePath;
});
}
TestTreeItem *TestTreeItem::findChildByFileAndType(const QString &filePath, Type tType)
{
return findFirstLevelChild([filePath, tType](const TestTreeItem *other) {
return findFirstLevelChildItem([filePath, tType](const TestTreeItem *other) {
return other->type() == tType && other->filePath() == filePath;
});
}
});}
TestTreeItem *TestTreeItem::findChildByNameAndFile(const QString &name, const QString &filePath)
{
return findFirstLevelChild([name, filePath](const TestTreeItem *other) {
return findFirstLevelChildItem([name, filePath](const TestTreeItem *other) {
return other->filePath() == filePath && other->name() == name;
});
}
@@ -258,53 +293,11 @@ TestConfiguration *TestTreeItem::asConfiguration(TestRunMode mode) const
return nullptr;
}
QList<TestConfiguration *> TestTreeItem::getAllTestConfigurations() const
{
return QList<TestConfiguration *>();
}
QList<TestConfiguration *> TestTreeItem::getSelectedTestConfigurations() const
{
return QList<TestConfiguration *>();
}
QList<TestConfiguration *> TestTreeItem::getFailedTestConfigurations() const
{
return QList<TestConfiguration *>();
}
QList<TestConfiguration *> TestTreeItem::getTestConfigurationsForFile(const Utils::FilePath &) const
{
return QList<TestConfiguration *>();
}
bool TestTreeItem::lessThan(const TestTreeItem *other, SortMode mode) const
{
const QString &lhs = data(0, Qt::DisplayRole).toString();
const QString &rhs = other->data(0, Qt::DisplayRole).toString();
switch (mode) {
case Alphabetically:
if (lhs == rhs)
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) {
return leftLink.targetLine == rightLink.targetLine
? leftLink.targetColumn > rightLink.targetColumn
: leftLink.targetLine > rightLink.targetLine;
}
return leftLink.targetFileName > rightLink.targetFileName;
}
}
return true;
}
bool TestTreeItem::isGroupNodeFor(const TestTreeItem *other) const
{
QTC_ASSERT(other, return false);
@@ -323,47 +316,74 @@ bool TestTreeItem::isGroupable() const
QSet<QString> TestTreeItem::internalTargets() const
{
auto cppMM = CppTools::CppModelManager::instance();
const QList<CppTools::ProjectPart::Ptr> projectParts = cppMM->projectPart(m_filePath);
const QList<CppTools::ProjectPart::Ptr> projectParts = cppMM->projectPart(filePath());
// if we have no project parts it's most likely a header with declarations only and CMake based
if (projectParts.isEmpty())
return TestTreeItem::dependingInternalTargets(cppMM, m_filePath);
return TestTreeItem::dependingInternalTargets(cppMM, filePath());
QSet<QString> targets;
for (const CppTools::ProjectPart::Ptr &part : projectParts) {
targets.insert(part->buildSystemTarget);
if (part->buildTargetType != ProjectExplorer::BuildTargetType::Executable)
targets.unite(TestTreeItem::dependingInternalTargets(cppMM, m_filePath));
targets.unite(TestTreeItem::dependingInternalTargets(cppMM, filePath()));
}
return targets;
}
void TestTreeItem::forAllChildItems(const std::function<void(TestTreeItem *)> &pred) const
{
for (int row = 0, end = childCount(); row < end; ++row) {
TestTreeItem *child = childItem(row);
pred(child);
child->forAllChildItems(pred);
}
}
void TestTreeItem::forFirstLevelChildItems(const std::function<void(TestTreeItem *)> &pred) const
{
for (int row = 0, end = childCount(); row < end; ++row)
pred(childItem(row));
}
TestTreeItem *TestTreeItem::findFirstLevelChildItem(const std::function<bool(TestTreeItem *)> &pred) const
{
for (int row = 0, end = childCount(); row < end; ++row) {
TestTreeItem *child = childItem(row);
if (pred(child))
return child;
}
return nullptr;
}
void TestTreeItem::copyBasicDataFrom(const TestTreeItem *other)
{
if (!other)
return;
m_name = other->m_name;
m_filePath = other->m_filePath;
m_type = other->m_type;
m_checked = other->m_checked;
m_failed = other->m_failed;
m_line = other->m_line;
setName(other->name());
setFilePath(other->filePath());
setType(other->type());
setLine(other->line());
setData(0, other->checked(), Qt::CheckStateRole);
setData(0, other->data(0, FailedRole), FailedRole);
m_column = other->m_column;
m_proFile = other->m_proFile;
m_status = other->m_status;
}
inline bool TestTreeItem::modifyFilePath(const QString &filePath)
inline bool TestTreeItem::modifyFilePath(const QString &filepath)
{
if (m_filePath != filePath) {
m_filePath = filePath;
if (filePath() != filepath) {
setFilePath(filepath);
return true;
}
return false;
}
inline bool TestTreeItem::modifyName(const QString &name)
inline bool TestTreeItem::modifyName(const QString &newName)
{
if (m_name != name) {
m_name = name;
if (name() != newName) {
setName(newName);
return true;
}
return false;
@@ -371,7 +391,7 @@ inline bool TestTreeItem::modifyName(const QString &name)
ITestFramework *TestTreeItem::framework() const
{
return static_cast<ITestFramework *>(m_testBase);
return static_cast<ITestFramework *>(testBase());
}
/*

View File

@@ -53,7 +53,7 @@ class TestConfiguration;
class TestParseResult;
enum class TestRunMode;
class TestTreeItem : public Utils::TypedTreeItem<TestTreeItem>
class ITestTreeItem : public Utils::TypedTreeItem<ITestTreeItem>
{
public:
@@ -74,6 +74,51 @@ public:
Naturally
};
explicit ITestTreeItem(ITestBase *testBase,
const QString &name = QString(),
const QString &filePath = QString(),
Type type = Root);
virtual QVariant data(int column, int role) const override;
virtual bool setData(int column, const QVariant &data, int role) override;
virtual Qt::ItemFlags flags(int column) const override;
virtual Qt::CheckState checked() const;
virtual bool canProvideTestConfiguration() const { return false; }
virtual TestConfiguration *testConfiguration() const { return nullptr; }
virtual QList<TestConfiguration *> getAllTestConfigurations() const { return {}; }
virtual QList<TestConfiguration *> getSelectedTestConfigurations() const { return {}; }
virtual QList<TestConfiguration *> getFailedTestConfigurations() const { return {}; }
const QString name() const { return m_name; }
void setName(const QString &name) { m_name = name; }
const QString filePath() const { return m_filePath; }
void setFilePath(const QString &filePath) { m_filePath = filePath; }
Type type() const { return m_type; }
int line() const { return m_line; }
void setLine(int line) { m_line = line;}
ITestBase *testBase() const { return m_testBase; }
virtual bool lessThan(const ITestTreeItem *other, SortMode mode) const;
QString cacheName() const { return m_filePath + ':' + m_name; }
protected:
void setType(Type type) { m_type = type; }
Qt::CheckState m_checked = Qt::Checked;
private:
ITestBase *m_testBase = nullptr; // not owned
QString m_name;
QString m_filePath;
Type m_type;
int m_line = 0;
bool m_failed = false;
};
class TestTreeItem : public ITestTreeItem
{
public:
explicit TestTreeItem(ITestBase *testBase,
const QString &name = QString(),
const QString &filePath = QString(),
@@ -81,32 +126,23 @@ public:
virtual TestTreeItem *copyWithoutChildren() = 0;
virtual QVariant data(int column, int role) const override;
virtual bool setData(int column, const QVariant &data, int role) override;
virtual Qt::ItemFlags flags(int column) const override;
bool modifyTestCaseOrSuiteContent(const TestParseResult *result);
bool modifyTestFunctionContent(const TestParseResult *result);
bool modifyDataTagContent(const TestParseResult *result);
bool modifyLineAndColumn(const TestParseResult *result);
ITestFramework *framework() const;
const QString name() const { return m_name; }
void setName(const QString &name) { m_name = name; }
const QString filePath() const { return m_filePath; }
void setFilePath(const QString &filePath) { m_filePath = filePath; }
void setLine(int line) { m_line = line;}
int line() const { return m_line; }
void setColumn(int column) { m_column = column; }
int column() const { return m_column; }
QString proFile() const { return m_proFile; }
void setProFile(const QString &proFile) { m_proFile = proFile; }
virtual Qt::CheckState checked() const;
Type type() const { return m_type; }
void markForRemoval(bool mark);
void markForRemovalRecursively(bool mark);
virtual void markForRemovalRecursively(const QString &filePath);
virtual bool removeOnSweepIfEmpty() const { return m_type == GroupNode; }
virtual void markForRemovalRecursively(const QString &filepath);
virtual bool removeOnSweepIfEmpty() const { return type() == GroupNode; }
bool markedForRemoval() const { return m_status == MarkedForRemoval; }
bool newlyAdded() const { return m_status == NewlyAdded; }
TestTreeItem *childItem(int at) const;
TestTreeItem *parentItem() const;
TestTreeItem *findChildByName(const QString &name);
@@ -114,16 +150,10 @@ public:
TestTreeItem *findChildByFileAndType(const QString &filePath, Type type);
TestTreeItem *findChildByNameAndFile(const QString &name, const QString &filePath);
virtual bool canProvideTestConfiguration() const { return false; }
virtual bool canProvideDebugConfiguration() const { return false; }
virtual TestConfiguration *testConfiguration() const { return nullptr; }
virtual TestConfiguration *debugConfiguration() const { return nullptr; }
virtual bool canProvideDebugConfiguration() const { return false; }
TestConfiguration *asConfiguration(TestRunMode mode) const;
virtual QList<TestConfiguration *> getAllTestConfigurations() const;
virtual QList<TestConfiguration *> getSelectedTestConfigurations() const;
virtual QList<TestConfiguration *> getFailedTestConfigurations() const;
virtual QList<TestConfiguration *> getTestConfigurationsForFile(const Utils::FilePath &fileName) const;
virtual bool lessThan(const TestTreeItem *other, SortMode mode) const;
virtual TestTreeItem *find(const TestParseResult *result) = 0;
virtual TestTreeItem *findChild(const TestTreeItem *other) = 0;
virtual bool modify(const TestParseResult *result) = 0;
@@ -137,7 +167,9 @@ public:
virtual bool shouldBeAddedAfterFiltering() const { return true; }
virtual QSet<QString> internalTargets() const;
QString cacheName() const { return m_filePath + ':' + m_name; }
void forAllChildItems(const std::function<void(TestTreeItem *)> &pred) const;
void forFirstLevelChildItems(const std::function<void(TestTreeItem *)> &pred) const;
TestTreeItem *findFirstLevelChildItem(const std::function<bool(TestTreeItem *)> &pred) const;
protected:
void copyBasicDataFrom(const TestTreeItem *other);
typedef std::function<bool(const TestTreeItem *)> CompareFunction;
@@ -145,7 +177,7 @@ protected:
const QString &file);
private:
bool modifyFilePath(const QString &filePath);
bool modifyFilePath(const QString &filepath);
bool modifyName(const QString &name);
enum Status
@@ -155,13 +187,6 @@ private:
Cleared
};
ITestBase *m_testBase = nullptr;
QString m_name;
QString m_filePath;
Qt::CheckState m_checked;
bool m_failed = false;
Type m_type;
int m_line = 0;
int m_column = 0;
QString m_proFile;
Status m_status = NewlyAdded;

View File

@@ -119,7 +119,7 @@ bool TestTreeModel::setData(const QModelIndex &index, const QVariant &value, int
if (!index.isValid())
return false;
TestTreeItem *item = static_cast<TestTreeItem *>(index.internalPointer());
ITestTreeItem *item = static_cast<ITestTreeItem *>(index.internalPointer());
if (item && item->setData(index.column(), value, role)) {
emit dataChanged(index, index, {role});
if (role == Qt::CheckStateRole) {
@@ -131,11 +131,14 @@ bool TestTreeModel::setData(const QModelIndex &index, const QVariant &value, int
setData(idx, checked ? Qt::Checked : Qt::Unchecked, Qt::CheckStateRole);
}
}
if (item->parent() != rootItem() && item->parentItem()->checked() != checked)
revalidateCheckState(item->parentItem()); // handle parent too
if (item->parent() != rootItem()) {
auto parent = static_cast<ITestTreeItem *>(item->parent());
if (parent->checked() != checked)
revalidateCheckState(parent); // handle parent too
}
return true;
} else if (role == FailedRole) {
m_failedStateCache.insert(item, true);
} else if (role == FailedRole) { // FIXME limit to Frameworks
m_failedStateCache.insert(static_cast<TestTreeItem *>(item), true);
}
}
return false;
@@ -146,7 +149,7 @@ Qt::ItemFlags TestTreeModel::flags(const QModelIndex &index) const
if (!index.isValid())
return Qt::ItemIsEnabled | Qt::ItemIsSelectable;
TestTreeItem *item = static_cast<TestTreeItem *>(itemForIndex(index));
ITestTreeItem *item = static_cast<ITestTreeItem *>(itemForIndex(index));
return item->flags(index.column());
}
@@ -163,7 +166,7 @@ QList<TestConfiguration *> TestTreeModel::getAllTestCases() const
{
QList<TestConfiguration *> result;
for (Utils::TreeItem *frameworkRoot : *rootItem())
result.append(static_cast<TestTreeItem *>(frameworkRoot)->getAllTestConfigurations());
result.append(static_cast<ITestTreeItem *>(frameworkRoot)->getAllTestConfigurations());
return result;
}
@@ -171,7 +174,7 @@ QList<TestConfiguration *> TestTreeModel::getSelectedTests() const
{
QList<TestConfiguration *> result;
for (Utils::TreeItem *frameworkRoot : *rootItem())
result.append(static_cast<TestTreeItem *>(frameworkRoot)->getSelectedTestConfigurations());
result.append(static_cast<ITestTreeItem *>(frameworkRoot)->getSelectedTestConfigurations());
return result;
}
@@ -179,7 +182,7 @@ QList<TestConfiguration *> TestTreeModel::getFailedTests() const
{
QList<TestConfiguration *> result;
for (Utils::TreeItem *frameworkRoot : *rootItem())
result.append(static_cast<TestTreeItem *>(frameworkRoot)->getFailedTestConfigurations());
result.append(static_cast<ITestTreeItem *>(frameworkRoot)->getFailedTestConfigurations());
return result;
}
@@ -195,13 +198,13 @@ QList<TestTreeItem *> TestTreeModel::testItemsByName(TestTreeItem *root, const Q
{
QList<TestTreeItem *> result;
root->forFirstLevelChildren([&testName, &result, this](TestTreeItem *node) {
root->forFirstLevelChildItems([&testName, &result, this](TestTreeItem *node) {
if (node->type() == TestTreeItem::TestSuite || node->type() == TestTreeItem::TestCase) {
if (node->name() == testName) {
result << node;
return; // prioritize test suites and cases over test functions
}
TestTreeItem *testCase = node->findFirstLevelChild([&testName](TestTreeItem *it) {
TestTreeItem *testCase = node->findFirstLevelChildItem([&testName](TestTreeItem *it) {
QTC_ASSERT(it, return false);
return (it->type() == TestTreeItem::TestCase
|| it->type() == TestTreeItem::TestFunction) && it->name() == testName;
@@ -218,6 +221,7 @@ QList<TestTreeItem *> TestTreeModel::testItemsByName(TestTreeItem *root, const Q
QList<TestTreeItem *> TestTreeModel::testItemsByName(const QString &testName)
{
QList<TestTreeItem *> result;
// FIXME limit to frameworks
for (Utils::TreeItem *frameworkRoot : *rootItem())
result << testItemsByName(static_cast<TestTreeItem *>(frameworkRoot), testName);
@@ -286,12 +290,12 @@ void TestTreeModel::rebuild(const QList<Utils::Id> &frameworkIds)
TestTreeItem *frameworkRoot = framework->rootNode();
const bool groupingEnabled = framework->grouping();
for (int row = frameworkRoot->childCount() - 1; row >= 0; --row) {
auto testItem = frameworkRoot->childAt(row);
auto testItem = frameworkRoot->childItem(row);
if (testItem->type() == TestTreeItem::GroupNode) {
// process children of group node and delete it afterwards if necessary
for (int childRow = testItem->childCount() - 1; childRow >= 0; --childRow) {
// FIXME should this be done recursively until we have a non-GroupNode?
TestTreeItem *childTestItem = testItem->childAt(childRow);
TestTreeItem *childTestItem = testItem->childItem(childRow);
takeItem(childTestItem);
filterAndInsert(childTestItem, frameworkRoot, groupingEnabled);
}
@@ -311,8 +315,9 @@ void TestTreeModel::updateCheckStateCache()
m_checkStateCache->evolve();
for (Utils::TreeItem *rootNode : *rootItem()) {
// FIXME limit to framework items
rootNode->forAllChildren([this](Utils::TreeItem *child) {
auto childItem = static_cast<TestTreeItem *>(child);
auto childItem = static_cast<ITestTreeItem *>(child);
m_checkStateCache->insert(childItem, childItem->checked());
});
}
@@ -359,7 +364,7 @@ void TestTreeModel::markForRemoval(const QString &filePath)
for (Utils::TreeItem *frameworkRoot : *rootItem()) {
TestTreeItem *root = static_cast<TestTreeItem *>(frameworkRoot);
for (int childRow = root->childCount() - 1; childRow >= 0; --childRow) {
TestTreeItem *child = root->childAt(childRow);
TestTreeItem *child = root->childItem(childRow);
child->markForRemovalRecursively(filePath);
}
}
@@ -387,7 +392,7 @@ bool TestTreeModel::sweepChildren(TestTreeItem *item)
{
bool hasChanged = false;
for (int row = item->childCount() - 1; row >= 0; --row) {
TestTreeItem *child = item->childAt(row);
TestTreeItem *child = item->childItem(row);
if (child->type() != TestTreeItem::Root && child->markedForRemoval()) {
destroyItem(child);
@@ -411,11 +416,11 @@ static TestTreeItem *fullCopyOf(TestTreeItem *other)
QTC_ASSERT(other, return nullptr);
TestTreeItem *result = other->copyWithoutChildren();
for (int row = 0, count = other->childCount(); row < count; ++row)
result->appendChild(fullCopyOf(other->childAt(row)));
result->appendChild(fullCopyOf(other->childItem(row)));
return result;
}
static void applyParentCheckState(TestTreeItem *parent, TestTreeItem *newItem)
static void applyParentCheckState(ITestTreeItem *parent, ITestTreeItem *newItem)
{
QTC_ASSERT(parent && newItem, return);
@@ -433,7 +438,7 @@ void TestTreeModel::insertItemInParent(TestTreeItem *item, TestTreeItem *root, b
{
TestTreeItem *parentNode = root;
if (groupingEnabled && item->isGroupable()) {
parentNode = root->findFirstLevelChild([item] (const TestTreeItem *it) {
parentNode = root->findFirstLevelChildItem([item] (const TestTreeItem *it) {
return it->isGroupNodeFor(item);
});
if (!parentNode) {
@@ -448,7 +453,7 @@ void TestTreeModel::insertItemInParent(TestTreeItem *item, TestTreeItem *root, b
if (auto otherItem = parentNode->findChild(item)) {
// only handle item's children and add them to the already present one
for (int row = 0, count = item->childCount(); row < count; ++row) {
TestTreeItem *child = fullCopyOf(item->childAt(row));
TestTreeItem *child = fullCopyOf(item->childItem(row));
// use check state of the original
child->setData(0, item->childAt(row)->checked(), Qt::CheckStateRole);
otherItem->appendChild(child);
@@ -471,26 +476,22 @@ void TestTreeModel::insertItemInParent(TestTreeItem *item, TestTreeItem *root, b
}
}
void TestTreeModel::revalidateCheckState(TestTreeItem *item)
static Qt::CheckState computeCheckStateByChildren(ITestTreeItem *item)
{
QTC_ASSERT(item, return);
const TestTreeItem::Type type = item->type();
if (type == TestTreeItem::TestSpecialFunction || type == TestTreeItem::TestDataFunction
|| type == TestTreeItem::TestDataTag) {
return;
}
const Qt::CheckState oldState = Qt::CheckState(item->data(0, Qt::CheckStateRole).toInt());
Qt::CheckState newState = Qt::Checked;
bool foundChecked = false;
bool foundUnchecked = false;
bool foundPartiallyChecked = false;
for (int row = 0, count = item->childCount(); row < count; ++row) {
TestTreeItem *child = item->childAt(row);
item->forFirstLevelChildren([&](ITestTreeItem *child) {
if (foundPartiallyChecked || (foundChecked && foundUnchecked)) {
newState = Qt::PartiallyChecked;
return;
}
switch (child->type()) {
case TestTreeItem::TestDataFunction:
case TestTreeItem::TestSpecialFunction:
continue;
return;
default:
break;
}
@@ -498,18 +499,32 @@ void TestTreeModel::revalidateCheckState(TestTreeItem *item)
foundChecked |= (child->checked() == Qt::Checked);
foundUnchecked |= (child->checked() == Qt::Unchecked);
foundPartiallyChecked |= (child->checked() == Qt::PartiallyChecked);
if (foundPartiallyChecked || (foundChecked && foundUnchecked)) {
newState = Qt::PartiallyChecked;
break;
}
}
});
if (newState != Qt::PartiallyChecked)
newState = foundUnchecked ? Qt::Unchecked : Qt::Checked;
return newState;
}
void TestTreeModel::revalidateCheckState(ITestTreeItem *item)
{
QTC_ASSERT(item, return);
const ITestTreeItem::Type type = item->type();
if (type == ITestTreeItem::TestSpecialFunction || type == ITestTreeItem::TestDataFunction
|| type == ITestTreeItem::TestDataTag) {
return;
}
const Qt::CheckState oldState = Qt::CheckState(item->data(0, Qt::CheckStateRole).toInt());
Qt::CheckState newState = computeCheckStateByChildren(item);
if (oldState != newState) {
item->setData(0, newState, Qt::CheckStateRole);
emit dataChanged(item->index(), item->index(), {Qt::CheckStateRole});
if (item->parent() != rootItem() && item->parentItem()->checked() != newState)
revalidateCheckState(item->parentItem());
if (item->parent() != rootItem()) {
auto parent = static_cast<ITestTreeItem *>(item->parent());
if (parent->checked() != newState)
revalidateCheckState(parent);
}
}
}
@@ -530,7 +545,7 @@ void Autotest::TestTreeModel::onDataChanged(const QModelIndex &topLeft,
return;
for (int row = topLeft.row(), endRow = bottomRight.row(); row <= endRow; ++row) {
if (auto item = static_cast<TestTreeItem *>(itemForIndex(index(row, 0, parent))))
if (auto item = static_cast<ITestTreeItem *>(itemForIndex(index(row, 0, parent))))
m_checkStateCache->insert(item, item->checked());
}
}
@@ -564,8 +579,7 @@ void TestTreeModel::handleParseResult(const TestParseResult *result, TestTreeIte
QTC_ASSERT(newItem, return);
// restore former check state and fail state if available
newItem->forAllChildren([this](Utils::TreeItem *child) {
auto childItem = static_cast<TestTreeItem *>(child);
newItem->forAllChildItems([this](TestTreeItem *childItem) {
Utils::optional<Qt::CheckState> cached = m_checkStateCache->get(childItem);
if (cached.has_value())
childItem->setData(0, cached.value(), Qt::CheckStateRole);
@@ -635,7 +649,7 @@ TestTreeItem *TestTreeModel::unnamedQuickTests() const
if (!rootNode)
return nullptr;
return rootNode->findFirstLevelChild([](TestTreeItem *it) { return it->name().isEmpty(); });
return rootNode->findFirstLevelChildItem([](TestTreeItem *it) { return it->name().isEmpty(); });
}
int TestTreeModel::namedQuickTestsCount() const
@@ -660,8 +674,8 @@ int TestTreeModel::dataTagsCount() const
return 0;
int dataTagCount = 0;
rootNode->forFirstLevelChildren([&dataTagCount](TestTreeItem *classItem) {
classItem->forFirstLevelChildren([&dataTagCount](TestTreeItem *functionItem) {
rootNode->forFirstLevelChildren([&dataTagCount](ITestTreeItem *classItem) {
classItem->forFirstLevelChildren([&dataTagCount](ITestTreeItem *functionItem) {
dataTagCount += functionItem->childCount();
});
});
@@ -679,7 +693,7 @@ QMultiMap<QString, int> TestTreeModel::gtestNamesAndSets() const
QMultiMap<QString, int> result;
if (TestTreeItem *rootNode = gtestRootNode()) {
rootNode->forFirstLevelChildren([&result](TestTreeItem *child) {
rootNode->forFirstLevelChildren([&result](ITestTreeItem *child) {
result.insert(child->name(), child->childCount());
});
}
@@ -697,7 +711,7 @@ QMap<QString, int> TestTreeModel::boostTestSuitesAndTests() const
QMap<QString, int> result;
if (TestTreeItem *rootNode = boostTestRootNode()) {
rootNode->forFirstLevelChildren([&result](TestTreeItem *child) {
rootNode->forFirstLevelChildItems([&result](TestTreeItem *child) {
result.insert(child->name() + '|' + child->proFile(), child->childCount());
});
}
@@ -749,11 +763,11 @@ TestTreeSortFilterModel::FilterMode TestTreeSortFilterModel::toFilterMode(int f)
bool TestTreeSortFilterModel::lessThan(const QModelIndex &left, const QModelIndex &right) const
{
// root items keep the intended order
const TestTreeItem *leftItem = static_cast<TestTreeItem *>(left.internalPointer());
if (leftItem->type() == TestTreeItem::Root)
const ITestTreeItem *leftItem = static_cast<ITestTreeItem *>(left.internalPointer());
if (leftItem->type() == ITestTreeItem::Root)
return left.row() > right.row();
const TestTreeItem *rightItem = static_cast<TestTreeItem *>(right.internalPointer());
const ITestTreeItem *rightItem = static_cast<ITestTreeItem *>(right.internalPointer());
return leftItem->lessThan(rightItem, m_sortMode);
}
@@ -763,12 +777,12 @@ bool TestTreeSortFilterModel::filterAcceptsRow(int sourceRow, const QModelIndex
if (!index.isValid())
return false;
const TestTreeItem *item = static_cast<TestTreeItem *>(index.internalPointer());
const ITestTreeItem *item = static_cast<ITestTreeItem *>(index.internalPointer());
switch (item->type()) {
case TestTreeItem::TestDataFunction:
case ITestTreeItem::TestDataFunction:
return m_filterMode & ShowTestData;
case TestTreeItem::TestSpecialFunction:
case ITestTreeItem::TestSpecialFunction:
return m_filterMode & ShowInitAndCleanup;
default:
return true;

View File

@@ -104,7 +104,7 @@ private:
void removeFiles(const QStringList &files);
bool sweepChildren(TestTreeItem *item);
void insertItemInParent(TestTreeItem *item, TestTreeItem *root, bool groupingEnabled);
void revalidateCheckState(TestTreeItem *item);
void revalidateCheckState(ITestTreeItem *item);
void setupParsingConnections();
void filterAndInsert(TestTreeItem *item, TestTreeItem *root, bool groupingEnabled);
QList<TestTreeItem *> testItemsByName(TestTreeItem *root, const QString &testName);