forked from qt-creator/qt-creator
AutoTest: Restore former check state on reparse
When reparsing while modifying a file it can happen that the parse failed for some reason or did not provide full information due to syntax errors the code model cannot cope with. This in turn can purge items from the test tree. Re-adding the items in a later reparse had just added the item and did not take care of (former) check states. Add simple caching mechanism to keep track of check states and use them if available. Task-number: QTCREATORBUG-24099 Change-Id: I3ca04f5fd58810df71582972e6fe96a00cfc48f1 Reviewed-by: David Schulz <david.schulz@qt.io>
This commit is contained in:
@@ -334,6 +334,7 @@ void TestCodeParser::scanForTests(const QStringList &fileList, const QList<ITest
|
||||
}
|
||||
|
||||
parsingHasFailed = false;
|
||||
TestTreeModel::instance()->updateCheckStateCache();
|
||||
if (isFullParse) {
|
||||
// remove qml files as they will be found automatically by the referencing cpp file
|
||||
list = Utils::filtered(list, [] (const QString &fn) {
|
||||
|
@@ -134,6 +134,7 @@ public:
|
||||
virtual bool shouldBeAddedAfterFiltering() const { return true; }
|
||||
virtual QSet<QString> internalTargets() const;
|
||||
|
||||
QString cacheName() const { return m_filePath + ':' + m_name; }
|
||||
protected:
|
||||
void copyBasicDataFrom(const TestTreeItem *other);
|
||||
typedef std::function<bool(const TestTreeItem *)> CompareFunction;
|
||||
|
@@ -91,6 +91,8 @@ void TestTreeModel::setupParsingConnections()
|
||||
connect(sm, &SessionManager::startupProjectChanged, [this](Project *project) {
|
||||
synchronizeTestFrameworks(); // we might have project settings
|
||||
m_parser->onStartupProjectChanged(project);
|
||||
m_checkStateCache.clear(); // TODO persist to project settings?
|
||||
m_itemUseCache.clear();
|
||||
});
|
||||
|
||||
CppTools::CppModelManager *cppMM = CppTools::CppModelManager::instance();
|
||||
@@ -291,6 +293,28 @@ void TestTreeModel::rebuild(const QList<Core::Id> &frameworkIds)
|
||||
}
|
||||
}
|
||||
|
||||
void TestTreeModel::updateCheckStateCache()
|
||||
{
|
||||
// raise generation for cached items and drop anything reaching 10th generation
|
||||
const QList<QString> cachedNames = m_itemUseCache.keys();
|
||||
for (const QString &cachedName : cachedNames) {
|
||||
auto it = m_itemUseCache.find(cachedName);
|
||||
if (it.value()++ >= 10) {
|
||||
m_itemUseCache.erase(it);
|
||||
m_checkStateCache.remove(cachedName);
|
||||
}
|
||||
}
|
||||
|
||||
for (Utils::TreeItem *rootNode : *rootItem()) {
|
||||
rootNode->forAllChildren([this](Utils::TreeItem *child) {
|
||||
auto childItem = static_cast<TestTreeItem *>(child);
|
||||
const QString cacheName = childItem->cacheName();
|
||||
m_checkStateCache.insert(cacheName, childItem->checked());
|
||||
m_itemUseCache[cacheName] = 0; // explicitly mark as 0-generation
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void TestTreeModel::removeFiles(const QStringList &files)
|
||||
{
|
||||
for (const QString &file : files)
|
||||
@@ -404,14 +428,21 @@ void TestTreeModel::insertItemInParent(TestTreeItem *item, TestTreeItem *root, b
|
||||
// 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));
|
||||
applyParentCheckState(otherItem, child);
|
||||
// use check state of the original
|
||||
child->setData(0, item->childAt(row)->checked(), Qt::CheckStateRole);
|
||||
otherItem->appendChild(child);
|
||||
revalidateCheckState(child);
|
||||
}
|
||||
delete item;
|
||||
} else {
|
||||
// we could try to add a non-checked item to a checked group or vice versa
|
||||
applyParentCheckState(parentNode, item);
|
||||
// restore former check state if available
|
||||
auto cached = m_checkStateCache.find(item->cacheName());
|
||||
if (cached != m_checkStateCache.end())
|
||||
item->setData(0, cached.value(), Qt::CheckStateRole);
|
||||
else
|
||||
applyParentCheckState(parentNode, item);
|
||||
parentNode->appendChild(item);
|
||||
revalidateCheckState(parentNode);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -492,6 +523,13 @@ void TestTreeModel::handleParseResult(const TestParseResult *result, TestTreeIte
|
||||
TestTreeItem *newItem = result->createTestTreeItem();
|
||||
QTC_ASSERT(newItem, return);
|
||||
|
||||
// restore former check state if available
|
||||
newItem->forAllChildren([this](Utils::TreeItem *child) {
|
||||
auto childItem = static_cast<TestTreeItem *>(child);
|
||||
auto cached = m_checkStateCache.find(childItem->cacheName());
|
||||
if (cached != m_checkStateCache.end())
|
||||
childItem->setData(0, cached.value(), Qt::CheckStateRole);
|
||||
});
|
||||
// it might be necessary to "split" created item
|
||||
filterAndInsert(newItem, parentNode, groupingEnabled);
|
||||
}
|
||||
|
@@ -66,6 +66,7 @@ public:
|
||||
void synchronizeTestFrameworks();
|
||||
void rebuild(const QList<Core::Id> &frameworkIds);
|
||||
|
||||
void updateCheckStateCache();
|
||||
#ifdef WITH_TESTS
|
||||
int autoTestsCount() const;
|
||||
int namedQuickTestsCount() const;
|
||||
@@ -103,6 +104,8 @@ private:
|
||||
QList<TestTreeItem *> testItemsByName(TestTreeItem *root, const QString &testName);
|
||||
|
||||
Internal::TestCodeParser *m_parser = nullptr;
|
||||
QHash<QString, Qt::CheckState> m_checkStateCache; // could be enhanced to store expanded as well
|
||||
QHash<QString, int> m_itemUseCache;
|
||||
};
|
||||
|
||||
namespace Internal {
|
||||
|
Reference in New Issue
Block a user