diff options
Diffstat (limited to 'src/plugins/autotest/testtreemodel.cpp')
-rw-r--r-- | src/plugins/autotest/testtreemodel.cpp | 144 |
1 files changed, 89 insertions, 55 deletions
diff --git a/src/plugins/autotest/testtreemodel.cpp b/src/plugins/autotest/testtreemodel.cpp index 22d4b3921e..13d62216f2 100644 --- a/src/plugins/autotest/testtreemodel.cpp +++ b/src/plugins/autotest/testtreemodel.cpp @@ -39,14 +39,20 @@ #include <texteditor/texteditor.h> #include <utils/qtcassert.h> +using namespace ProjectExplorer; +using namespace Autotest::Internal; + namespace Autotest { -using namespace Internal; +static Q_LOGGING_CATEGORY(LOG, "qtc.autotest.frameworkmanager", QtWarningMsg) + +static TestTreeModel *s_instance = nullptr; -TestTreeModel::TestTreeModel(QObject *parent) : - TreeModel<>(parent), - m_parser(new TestCodeParser(this)) +TestTreeModel::TestTreeModel(TestCodeParser *parser) : + m_parser(parser) { + s_instance = this; + connect(m_parser, &TestCodeParser::aboutToPerformFullParse, this, &TestTreeModel::removeAllTestItems, Qt::QueuedConnection); connect(m_parser, &TestCodeParser::testParseResultReady, @@ -55,22 +61,21 @@ TestTreeModel::TestTreeModel(QObject *parent) : this, &TestTreeModel::sweep, Qt::QueuedConnection); connect(m_parser, &TestCodeParser::parsingFailed, this, &TestTreeModel::sweep, Qt::QueuedConnection); + connect(m_parser, &TestCodeParser::requestRemoveAll, + this, &TestTreeModel::markAllForRemoval); + connect(m_parser, &TestCodeParser::requestRemoval, + this, &TestTreeModel::markForRemoval); setupParsingConnections(); } -static TestTreeModel *s_instance = nullptr; - TestTreeModel *TestTreeModel::instance() { - if (!s_instance) - s_instance = new TestTreeModel; return s_instance; } TestTreeModel::~TestTreeModel() { - removeTestRootNodes(); s_instance = nullptr; } @@ -82,9 +87,13 @@ void TestTreeModel::setupParsingConnections() m_parser->setDirty(); m_parser->setState(TestCodeParser::Idle); - ProjectExplorer::SessionManager *sm = ProjectExplorer::SessionManager::instance(); - connect(sm, &ProjectExplorer::SessionManager::startupProjectChanged, - m_parser, &TestCodeParser::onStartupProjectChanged); + SessionManager *sm = SessionManager::instance(); + 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(); connect(cppMM, &CppTools::CppModelManager::documentUpdated, @@ -205,23 +214,25 @@ QList<TestTreeItem *> TestTreeModel::testItemsByName(const QString &testName) void TestTreeModel::synchronizeTestFrameworks() { ProjectExplorer::Project *project = ProjectExplorer::SessionManager::startupProject(); - QList<Core::Id> sortedIds; - TestFrameworkManager *manager = TestFrameworkManager::instance(); + TestFrameworks sorted; const QVariant useGlobal = project ? project->namedSettings(Constants::SK_USE_GLOBAL) : QVariant(); if (!useGlobal.isValid() || AutotestPlugin::projectSettings(project)->useGlobalSettings()) { - sortedIds = manager->sortedActiveFrameworkIds(); + sorted = Utils::filtered(TestFrameworkManager::registeredFrameworks(), + &ITestFramework::active); + qCDebug(LOG) << "Active frameworks sorted by priority" << sorted; } else { // we've got custom project settings const TestProjectSettings *settings = AutotestPlugin::projectSettings(project); - const QMap<Core::Id, bool> active = settings->activeFrameworks(); - sortedIds = Utils::filtered(active.keys(), [active](const Core::Id &id) { - return active.value(id); + const QMap<ITestFramework *, bool> active = settings->activeFrameworks(); + sorted = Utils::filtered(active.keys(), [active](ITestFramework *framework) { + return active.value(framework); }); + Utils::sort(sorted, &ITestFramework::priority); } // pre-check to avoid further processing when frameworks are unchanged Utils::TreeItem *invisibleRoot = rootItem(); - QSet<Core::Id> newlyAdded; + QSet<ITestFramework *> newlyAdded; QList<Utils::TreeItem *> oldFrameworkRoots; for (Utils::TreeItem *oldFrameworkRoot : *invisibleRoot) oldFrameworkRoots.append(oldFrameworkRoot); @@ -229,19 +240,19 @@ void TestTreeModel::synchronizeTestFrameworks() for (Utils::TreeItem *oldFrameworkRoot : oldFrameworkRoots) takeItem(oldFrameworkRoot); // do NOT delete the ptr is still held by TestFrameworkManager - for (const Core::Id &id : sortedIds) { - TestTreeItem *frameworkRootNode = manager->rootNodeForTestFramework(id); + for (ITestFramework *framework : sorted) { + TestTreeItem *frameworkRootNode = framework->rootNode(); invisibleRoot->appendChild(frameworkRootNode); if (!oldFrameworkRoots.removeOne(frameworkRootNode)) - newlyAdded.insert(id); + newlyAdded.insert(framework); } for (Utils::TreeItem *oldFrameworkRoot : oldFrameworkRoots) oldFrameworkRoot->removeChildren(); - m_parser->syncTestFrameworks(sortedIds); + m_parser->syncTestFrameworks(sorted); if (!newlyAdded.isEmpty()) m_parser->updateTestTree(newlyAdded); - emit updatedActiveFrameworks(sortedIds.size()); + emit updatedActiveFrameworks(sorted.size()); } void TestTreeModel::filterAndInsert(TestTreeItem *item, TestTreeItem *root, bool groupingEnabled) @@ -255,12 +266,12 @@ void TestTreeModel::filterAndInsert(TestTreeItem *item, TestTreeItem *root, bool insertItemInParent(filtered, root, groupingEnabled); } -void TestTreeModel::rebuild(const QList<Core::Id> &frameworkIds) +void TestTreeModel::rebuild(const QList<Utils::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 (const Utils::Id &id : frameworkIds) { + ITestFramework *framework = TestFrameworkManager::frameworkForId(id); + TestTreeItem *frameworkRoot = framework->rootNode(); + const bool groupingEnabled = framework->grouping(); for (int row = frameworkRoot->childCount() - 1; row >= 0; --row) { auto testItem = frameworkRoot->childAt(row); if (testItem->type() == TestTreeItem::GroupNode) { @@ -282,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) @@ -395,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); } } @@ -450,16 +490,14 @@ void TestTreeModel::revalidateCheckState(TestTreeItem *item) void TestTreeModel::onParseResultReady(const TestParseResultPtr result) { - TestTreeItem *rootNode - = TestFrameworkManager::instance()->rootNodeForTestFramework(result->frameworkId); + TestTreeItem *rootNode = result->framework->rootNode(); QTC_ASSERT(rootNode, return); handleParseResult(result.data(), rootNode); } void TestTreeModel::handleParseResult(const TestParseResult *result, TestTreeItem *parentNode) { - const bool groupingEnabled = - TestFrameworkManager::instance()->groupingEnabled(result->frameworkId); + const bool groupingEnabled = result->framework->grouping(); // lookup existing items if (TestTreeItem *toBeModified = parentNode->find(result)) { // found existing item... Do not remove @@ -485,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); } @@ -500,41 +545,30 @@ void TestTreeModel::removeAllTestItems() emit testTreeModelChanged(); } -void TestTreeModel::removeTestRootNodes() -{ - const Utils::TreeItem *invisibleRoot = rootItem(); - const int frameworkRootCount = invisibleRoot ? invisibleRoot->childCount() : 0; - for (int row = frameworkRootCount - 1; row >= 0; --row) { - Utils::TreeItem *item = invisibleRoot->childAt(row); - item->removeChildren(); - takeItem(item); // do NOT delete the item as it's still a ptr held by TestFrameworkManager - } -} - #ifdef WITH_TESTS // we're inside tests - so use some internal knowledge to make testing easier static TestTreeItem *qtRootNode() { - return TestFrameworkManager::instance()->rootNodeForTestFramework( - Core::Id(Constants::FRAMEWORK_PREFIX).withSuffix("QtTest")); + auto id = Utils::Id(Constants::FRAMEWORK_PREFIX).withSuffix("QtTest"); + return TestFrameworkManager::frameworkForId(id)->rootNode(); } static TestTreeItem *quickRootNode() { - return TestFrameworkManager::instance()->rootNodeForTestFramework( - Core::Id(Constants::FRAMEWORK_PREFIX).withSuffix("QtQuickTest")); + auto id = Utils::Id(Constants::FRAMEWORK_PREFIX).withSuffix("QtQuickTest"); + return TestFrameworkManager::frameworkForId(id)->rootNode(); } static TestTreeItem *gtestRootNode() { - return TestFrameworkManager::instance()->rootNodeForTestFramework( - Core::Id(Constants::FRAMEWORK_PREFIX).withSuffix("GTest")); + auto id = Utils::Id(Constants::FRAMEWORK_PREFIX).withSuffix("GTest"); + return TestFrameworkManager::frameworkForId(id)->rootNode(); } static TestTreeItem *boostTestRootNode() { - return TestFrameworkManager::instance()->rootNodeForTestFramework( - Core::Id(Constants::FRAMEWORK_PREFIX).withSuffix("Boost")); + auto id = Utils::Id(Constants::FRAMEWORK_PREFIX).withSuffix("Boost"); + return TestFrameworkManager::frameworkForId(id)->rootNode(); } int TestTreeModel::autoTestsCount() const |