AutoTest: Prefer ITestParser to ITestFramework in TestCodeParser

Preserves the level of abstraction.

Change-Id: I01354fc8fcdf846dd2ef2a20fce12f6e9c4756b2
Reviewed-by: Christian Stenger <christian.stenger@qt.io>
This commit is contained in:
Bernhard Beschow
2021-01-01 19:19:33 +01:00
parent 2674e9c62e
commit c16f8ce988
3 changed files with 29 additions and 37 deletions

View File

@@ -108,7 +108,7 @@ void TestCodeParser::setState(State state)
} }
} }
void TestCodeParser::syncTestFrameworks(const QList<ITestFramework *> &frameworks) void TestCodeParser::syncTestFrameworks(const QList<ITestParser *> &parsers)
{ {
if (m_parserState != Idle) { if (m_parserState != Idle) {
// there's a running parse // there's a running parse
@@ -116,13 +116,8 @@ void TestCodeParser::syncTestFrameworks(const QList<ITestFramework *> &framework
m_postponedFiles.clear(); m_postponedFiles.clear();
Core::ProgressManager::cancelTasks(Constants::TASK_PARSE); Core::ProgressManager::cancelTasks(Constants::TASK_PARSE);
} }
m_testCodeParsers.clear(); qCDebug(LOG) << "Setting" << parsers << "as current parsers";
qCDebug(LOG) << "Setting" << frameworks << "as current parsers"; m_testCodeParsers = parsers;
for (ITestFramework *framework : frameworks) {
ITestParser *testParser = framework->testParser();
QTC_ASSERT(testParser, continue); // buildsystem based frameworks have no code parser
m_testCodeParsers.append(testParser);
}
} }
void TestCodeParser::emitUpdateTestTree(ITestParser *parser) void TestCodeParser::emitUpdateTestTree(ITestParser *parser)
@@ -130,7 +125,7 @@ void TestCodeParser::emitUpdateTestTree(ITestParser *parser)
if (m_testCodeParsers.isEmpty()) if (m_testCodeParsers.isEmpty())
return; return;
if (parser) if (parser)
m_updateParsers.insert(parser->framework()); m_updateParsers.insert(parser);
else else
m_updateParsers.clear(); m_updateParsers.clear();
if (m_singleShotScheduled) { if (m_singleShotScheduled) {
@@ -143,18 +138,18 @@ void TestCodeParser::emitUpdateTestTree(ITestParser *parser)
QTimer::singleShot(1000, this, [this]() { updateTestTree(m_updateParsers); }); QTimer::singleShot(1000, this, [this]() { updateTestTree(m_updateParsers); });
} }
void TestCodeParser::updateTestTree(const QSet<ITestFramework *> &frameworks) void TestCodeParser::updateTestTree(const QSet<ITestParser *> &parsers)
{ {
m_singleShotScheduled = false; m_singleShotScheduled = false;
if (m_codeModelParsing) { if (m_codeModelParsing) {
m_fullUpdatePostponed = true; m_fullUpdatePostponed = true;
m_partialUpdatePostponed = false; m_partialUpdatePostponed = false;
m_postponedFiles.clear(); m_postponedFiles.clear();
if (frameworks.isEmpty()) { if (parsers.isEmpty()) {
m_updateParsers.clear(); m_updateParsers.clear();
} else { } else {
for (ITestFramework *framework : frameworks) for (ITestParser *parser : parsers)
m_updateParsers.insert(framework); m_updateParsers.insert(parser);
} }
return; return;
} }
@@ -164,9 +159,11 @@ void TestCodeParser::updateTestTree(const QSet<ITestFramework *> &frameworks)
m_fullUpdatePostponed = false; m_fullUpdatePostponed = false;
qCDebug(LOG) << "calling scanForTests (updateTestTree)"; qCDebug(LOG) << "calling scanForTests (updateTestTree)";
TestFrameworks sortedFrameworks = Utils::toList(frameworks); QList<ITestParser *> sortedParsers = Utils::toList(parsers);
Utils::sort(sortedFrameworks, &ITestFramework::priority); Utils::sort(sortedParsers, [](const ITestParser *lhs, const ITestParser *rhs) {
scanForTests(QStringList(), sortedFrameworks); return lhs->framework()->priority() < rhs->framework()->priority();
});
scanForTests(QStringList(), sortedParsers);
} }
/****** threaded parsing stuff *******/ /****** threaded parsing stuff *******/
@@ -296,7 +293,7 @@ static void parseFileForTests(const QList<ITestParser *> &parsers,
} }
} }
void TestCodeParser::scanForTests(const QStringList &fileList, const QList<ITestFramework *> &parsers) void TestCodeParser::scanForTests(const QStringList &fileList, const QList<ITestParser *> &parsers)
{ {
if (m_parserState == Shutdown || m_testCodeParsers.isEmpty()) if (m_parserState == Shutdown || m_testCodeParsers.isEmpty())
return; return;
@@ -337,18 +334,16 @@ void TestCodeParser::scanForTests(const QStringList &fileList, const QList<ITest
return !fn.endsWith(".qml"); return !fn.endsWith(".qml");
}); });
if (!parsers.isEmpty()) { if (!parsers.isEmpty()) {
for (ITestFramework *framework : parsers) { for (ITestParser *parser : parsers) {
QTC_ASSERT(framework->testParser(), continue); // mark only frameworks with a parser parser->framework()->rootNode()->markForRemovalRecursively(true);
framework->rootNode()->markForRemovalRecursively(true);
} }
} else { } else {
emit requestRemoveAllFrameworkItems(); emit requestRemoveAllFrameworkItems();
} }
} else if (!parsers.isEmpty()) { } else if (!parsers.isEmpty()) {
for (ITestFramework *framework : parsers) { for (ITestParser *parser: parsers) {
for (const QString &filePath : qAsConst(list)) { for (const QString &filePath : qAsConst(list)) {
QTC_ASSERT(framework->testParser(), continue); parser->framework()->rootNode()->markForRemovalRecursively(filePath);
framework->rootNode()->markForRemovalRecursively(filePath);
} }
} }
} else { } else {
@@ -359,9 +354,7 @@ void TestCodeParser::scanForTests(const QStringList &fileList, const QList<ITest
QTC_ASSERT(!(isFullParse && list.isEmpty()), onFinished(); return); QTC_ASSERT(!(isFullParse && list.isEmpty()), onFinished(); return);
// use only a single parser or all current active? // use only a single parser or all current active?
const QList<ITestParser *> codeParsers const QList<ITestParser *> codeParsers = parsers.isEmpty() ? m_testCodeParsers : parsers;
= parsers.isEmpty() ? m_testCodeParsers
: Utils::transform(parsers, &ITestFramework::testParser);
qCDebug(LOG) << QDateTime::currentDateTime().toString("hh:mm:ss.zzz") << "StartParsing"; qCDebug(LOG) << QDateTime::currentDateTime().toString("hh:mm:ss.zzz") << "StartParsing";
for (ITestParser *parser : codeParsers) for (ITestParser *parser : codeParsers)
parser->init(list, isFullParse); parser->init(list, isFullParse);

View File

@@ -43,8 +43,6 @@ namespace ProjectExplorer { class Project; }
namespace Autotest { namespace Autotest {
class ITestFramework;
namespace Internal { namespace Internal {
class TestCodeParser : public QObject class TestCodeParser : public QObject
@@ -64,7 +62,7 @@ public:
State state() const { return m_parserState; } State state() const { return m_parserState; }
bool isParsing() const { return m_parserState == PartialParse || m_parserState == FullParse; } bool isParsing() const { return m_parserState == PartialParse || m_parserState == FullParse; }
void setDirty() { m_dirty = true; } void setDirty() { m_dirty = true; }
void syncTestFrameworks(const QList<ITestFramework *> &frameworks); void syncTestFrameworks(const QList<ITestParser *> &parsers);
#ifdef WITH_TESTS #ifdef WITH_TESTS
bool furtherParsingExpected() const bool furtherParsingExpected() const
{ return m_singleShotScheduled || m_fullUpdatePostponed || m_partialUpdatePostponed; } { return m_singleShotScheduled || m_fullUpdatePostponed || m_partialUpdatePostponed; }
@@ -81,7 +79,7 @@ signals:
public: public:
void emitUpdateTestTree(ITestParser *parser = nullptr); void emitUpdateTestTree(ITestParser *parser = nullptr);
void updateTestTree(const QSet<ITestFramework *> &frameworks = {}); void updateTestTree(const QSet<ITestParser *> &parsers = {});
void onCppDocumentUpdated(const CPlusPlus::Document::Ptr &document); void onCppDocumentUpdated(const CPlusPlus::Document::Ptr &document);
void onQmlDocumentUpdated(const QmlJS::Document::Ptr &document); void onQmlDocumentUpdated(const QmlJS::Document::Ptr &document);
void onStartupProjectChanged(ProjectExplorer::Project *project); void onStartupProjectChanged(ProjectExplorer::Project *project);
@@ -91,7 +89,7 @@ public:
private: private:
bool postponed(const QStringList &fileList); bool postponed(const QStringList &fileList);
void scanForTests(const QStringList &fileList = QStringList(), void scanForTests(const QStringList &fileList = QStringList(),
const QList<ITestFramework *> &parserIds = {}); const QList<ITestParser *> &parsers = {});
// qml files must be handled slightly different // qml files must be handled slightly different
void onDocumentUpdated(const QString &fileName, bool isQmlFile = false); void onDocumentUpdated(const QString &fileName, bool isQmlFile = false);
@@ -117,7 +115,7 @@ private:
QFutureWatcher<TestParseResultPtr> m_futureWatcher; QFutureWatcher<TestParseResultPtr> m_futureWatcher;
QList<ITestParser *> m_testCodeParsers; // ptrs are still owned by TestFrameworkManager QList<ITestParser *> m_testCodeParsers; // ptrs are still owned by TestFrameworkManager
QTimer m_reparseTimer; QTimer m_reparseTimer;
QSet<ITestFramework *> m_updateParsers; QSet<ITestParser *> m_updateParsers;
QThreadPool *m_threadPool = nullptr; QThreadPool *m_threadPool = nullptr;
}; };

View File

@@ -321,9 +321,10 @@ void TestTreeModel::synchronizeTestFrameworks()
}); });
} }
const auto sortedParsers = Utils::transform(sorted, &ITestFramework::testParser);
// pre-check to avoid further processing when frameworks are unchanged // pre-check to avoid further processing when frameworks are unchanged
Utils::TreeItem *invisibleRoot = rootItem(); Utils::TreeItem *invisibleRoot = rootItem();
QSet<ITestFramework *> newlyAdded; QSet<ITestParser *> newlyAdded;
QList<ITestTreeItem *> oldFrameworkRoots; QList<ITestTreeItem *> oldFrameworkRoots;
for (Utils::TreeItem *oldFrameworkRoot : *invisibleRoot) for (Utils::TreeItem *oldFrameworkRoot : *invisibleRoot)
oldFrameworkRoots.append(static_cast<ITestTreeItem *>(oldFrameworkRoot)); oldFrameworkRoots.append(static_cast<ITestTreeItem *>(oldFrameworkRoot));
@@ -331,11 +332,11 @@ void TestTreeModel::synchronizeTestFrameworks()
for (ITestTreeItem *oldFrameworkRoot : oldFrameworkRoots) for (ITestTreeItem *oldFrameworkRoot : oldFrameworkRoots)
takeItem(oldFrameworkRoot); // do NOT delete the ptr is still held by TestFrameworkManager takeItem(oldFrameworkRoot); // do NOT delete the ptr is still held by TestFrameworkManager
for (ITestFramework *framework : qAsConst(sorted)) { for (ITestParser *parser : sortedParsers) {
TestTreeItem *frameworkRootNode = framework->rootNode(); TestTreeItem *frameworkRootNode = parser->framework()->rootNode();
invisibleRoot->appendChild(frameworkRootNode); invisibleRoot->appendChild(frameworkRootNode);
if (!oldFrameworkRoots.removeOne(frameworkRootNode)) if (!oldFrameworkRoots.removeOne(frameworkRootNode))
newlyAdded.insert(framework); newlyAdded.insert(parser);
} }
for (ITestTreeItem *oldFrameworkRoot : oldFrameworkRoots) { for (ITestTreeItem *oldFrameworkRoot : oldFrameworkRoots) {
if (oldFrameworkRoot->testBase()->type() == ITestBase::Framework) if (oldFrameworkRoot->testBase()->type() == ITestBase::Framework)
@@ -344,7 +345,7 @@ void TestTreeModel::synchronizeTestFrameworks()
invisibleRoot->appendChild(oldFrameworkRoot); invisibleRoot->appendChild(oldFrameworkRoot);
} }
m_parser->syncTestFrameworks(sorted); m_parser->syncTestFrameworks(sortedParsers);
if (!newlyAdded.isEmpty()) if (!newlyAdded.isEmpty())
m_parser->updateTestTree(newlyAdded); m_parser->updateTestTree(newlyAdded);
emit updatedActiveFrameworks(invisibleRoot->childCount()); emit updatedActiveFrameworks(invisibleRoot->childCount());