AutoTest: Add option to disable derived checks

Previously the quick test parser would always check each symbol
its interested in to see if it might be derived from "TestCase".
This is very expensive.

This patch adds an option allowing the user to
enable or disable the check.

By default the check is disabled.

Change-Id: Ia6b230b344add672e53ad7fb52845c78a2914b99
Reviewed-by: Christian Stenger <christian.stenger@qt.io>
This commit is contained in:
Marcus Tillmanns
2023-01-18 08:15:08 +01:00
parent 978639b995
commit 3873bcf2a4
8 changed files with 57 additions and 8 deletions

View File

@@ -463,6 +463,11 @@
inside the spin box next to it. Set the number to 0 if you want no limit inside the spin box next to it. Set the number to 0 if you want no limit
at all. The default number is 2000. at all. The default number is 2000.
To check for Qt Quick Tests that are derived from TestCase select the
\uicontrol {Check for derived Qt Quick tests} check box.
Note: this feature is rather expensive and will increase the
scan time significantly.
\section2 Specifying Settings for Running Google Tests \section2 Specifying Settings for Running Google Tests
To specify settings for running Google tests, select \uicontrol Edit > To specify settings for running Google tests, select \uicontrol Edit >

View File

@@ -4,8 +4,11 @@
#include "autotestunittests.h" #include "autotestunittests.h"
#include "testcodeparser.h" #include "testcodeparser.h"
#include "testframeworkmanager.h"
#include "testtreemodel.h" #include "testtreemodel.h"
#include "qtest/qttestsettings.h"
#include <cppeditor/cppmodelmanager.h> #include <cppeditor/cppmodelmanager.h>
#include <cppeditor/cpptoolstestcase.h> #include <cppeditor/cpptoolstestcase.h>
#include <cppeditor/projectinfo.h> #include <cppeditor/projectinfo.h>
@@ -72,6 +75,12 @@ void AutoTestUnitTests::initTestCase()
m_checkBoost = true; m_checkBoost = true;
} }
} }
// Enable quick check for derived tests
static const Utils::Id id = Utils::Id("AutoTest.Framework.QtTest");
static_cast<Autotest::Internal::QtTestSettings *>(
TestFrameworkManager::frameworkForId(id)->testSettings())
->quickCheckForDerivedTests.setValue(true);
} }
void AutoTestUnitTests::cleanupTestCase() void AutoTestUnitTests::cleanupTestCase()

View File

@@ -72,6 +72,14 @@ QtTestSettings::QtTestSettings()
maxWarnings.setDefaultValue(2000); maxWarnings.setDefaultValue(2000);
maxWarnings.setSpecialValueText(Tr::tr("Unlimited")); maxWarnings.setSpecialValueText(Tr::tr("Unlimited"));
maxWarnings.setEnabler(&limitWarnings); maxWarnings.setEnabler(&limitWarnings);
registerAspect(&quickCheckForDerivedTests);
quickCheckForDerivedTests.setSettingsKey("QuickCheckForDerivedTests");
quickCheckForDerivedTests.setDefaultValue(false);
quickCheckForDerivedTests.setLabelText(Tr::tr("Check for derived Qt Quick tests"));
quickCheckForDerivedTests.setToolTip(
Tr::tr("Search for Qt Quick tests that are derived from TestCase.\nWarning: Enabling this "
"feature significantly increases scan time."));
} }
QString QtTestSettings::metricsTypeToOption(const MetricsType type) QString QtTestSettings::metricsTypeToOption(const MetricsType type)
@@ -114,6 +122,8 @@ QtTestSettingsPage::QtTestSettingsPage(QtTestSettings *settings, Id settingsId)
title(Tr::tr("Benchmark Metrics")), title(Tr::tr("Benchmark Metrics")),
Column { s.metrics } Column { s.metrics }
}, },
br,
s.quickCheckForDerivedTests,
}; };
Column { Row { col, st }, st }.attachTo(widget); Column { Row { col, st }, st }.attachTo(widget);

View File

@@ -33,6 +33,7 @@ public:
Utils::BoolAspect logSignalsSlots; Utils::BoolAspect logSignalsSlots;
Utils::BoolAspect limitWarnings; Utils::BoolAspect limitWarnings;
Utils::IntegerAspect maxWarnings; Utils::IntegerAspect maxWarnings;
Utils::BoolAspect quickCheckForDerivedTests;
}; };
class QtTestSettingsPage final : public Core::IOptionsPage class QtTestSettingsPage final : public Core::IOptionsPage

View File

@@ -8,6 +8,7 @@
#include "quicktest_utils.h" #include "quicktest_utils.h"
#include "../testcodeparser.h" #include "../testcodeparser.h"
#include "../testtreemodel.h" #include "../testtreemodel.h"
#include "../qtest/qttestsettings.h"
#include <cppeditor/cppmodelmanager.h> #include <cppeditor/cppmodelmanager.h>
#include <cppeditor/projectpart.h> #include <cppeditor/projectpart.h>
@@ -201,14 +202,15 @@ QList<Document::Ptr> QuickTestParser::scanDirectoryForQuickTestQmlFiles(const Ut
static bool checkQmlDocumentForQuickTestCode(QFutureInterface<TestParseResultPtr> &futureInterface, static bool checkQmlDocumentForQuickTestCode(QFutureInterface<TestParseResultPtr> &futureInterface,
const Document::Ptr &qmlJSDoc, const Document::Ptr &qmlJSDoc,
ITestFramework *framework, ITestFramework *framework,
const Utils::FilePath &proFile = Utils::FilePath()) const Utils::FilePath &proFile = Utils::FilePath(),
bool checkForDerivedTest = false)
{ {
if (qmlJSDoc.isNull()) if (qmlJSDoc.isNull())
return false; return false;
AST::Node *ast = qmlJSDoc->ast(); AST::Node *ast = qmlJSDoc->ast();
QTC_ASSERT(ast, return false); QTC_ASSERT(ast, return false);
Snapshot snapshot = ModelManagerInterface::instance()->snapshot(); Snapshot snapshot = ModelManagerInterface::instance()->snapshot();
TestQmlVisitor qmlVisitor(qmlJSDoc, snapshot); TestQmlVisitor qmlVisitor(qmlJSDoc, snapshot, checkForDerivedTest);
AST::Node::accept(ast, &qmlVisitor); AST::Node::accept(ast, &qmlVisitor);
if (!qmlVisitor.isValid()) if (!qmlVisitor.isValid())
return false; return false;
@@ -272,7 +274,11 @@ bool QuickTestParser::handleQtQuickTest(QFutureInterface<TestParseResultPtr> &fu
for (const Document::Ptr &qmlJSDoc : qmlDocs) { for (const Document::Ptr &qmlJSDoc : qmlDocs) {
if (futureInterface.isCanceled()) if (futureInterface.isCanceled())
break; break;
result |= checkQmlDocumentForQuickTestCode(futureInterface, qmlJSDoc, framework, proFile); result |= checkQmlDocumentForQuickTestCode(futureInterface,
qmlJSDoc,
framework,
proFile,
m_checkForDerivedTests);
} }
return result; return result;
} }
@@ -354,6 +360,10 @@ void QuickTestParser::init(const Utils::FilePaths &filesToParse, bool fullParse)
// get rid of all cached main cpp files // get rid of all cached main cpp files
m_mainCppFiles.clear(); m_mainCppFiles.clear();
} }
auto qtSettings = static_cast<QtTestSettings *>(framework()->testSettings());
m_checkForDerivedTests = qtSettings->quickCheckForDerivedTests.value();
CppParser::init(filesToParse, fullParse); CppParser::init(filesToParse, fullParse);
} }
@@ -372,7 +382,11 @@ bool QuickTestParser::processDocument(QFutureInterface<TestParseResultPtr> &futu
if (proFile.isEmpty()) if (proFile.isEmpty())
return false; return false;
Document::Ptr qmlJSDoc = m_qmlSnapshot.document(fileName); Document::Ptr qmlJSDoc = m_qmlSnapshot.document(fileName);
return checkQmlDocumentForQuickTestCode(futureInterface, qmlJSDoc, framework(), proFile); return checkQmlDocumentForQuickTestCode(futureInterface,
qmlJSDoc,
framework(),
proFile,
m_checkForDerivedTests);
} }
CPlusPlus::Document::Ptr cppdoc = document(fileName); CPlusPlus::Document::Ptr cppdoc = document(fileName);

View File

@@ -33,7 +33,8 @@ public:
private: private:
bool handleQtQuickTest(QFutureInterface<TestParseResultPtr> &futureInterface, bool handleQtQuickTest(QFutureInterface<TestParseResultPtr> &futureInterface,
CPlusPlus::Document::Ptr document, ITestFramework *framework); CPlusPlus::Document::Ptr document,
ITestFramework *framework);
void handleDirectoryChanged(const QString &directory); void handleDirectoryChanged(const QString &directory);
void doUpdateWatchPaths(const QStringList &directories); void doUpdateWatchPaths(const QStringList &directories);
QString quickTestName(const CPlusPlus::Document::Ptr &doc) const; QString quickTestName(const CPlusPlus::Document::Ptr &doc) const;
@@ -43,6 +44,7 @@ private:
QFileSystemWatcher m_directoryWatcher; QFileSystemWatcher m_directoryWatcher;
QMap<QString, QMap<QString, QDateTime> > m_watchedFiles; QMap<QString, QMap<QString, QDateTime> > m_watchedFiles;
QMap<Utils::FilePath, Utils::FilePath> m_mainCppFiles; QMap<Utils::FilePath, Utils::FilePath> m_mainCppFiles;
bool m_checkForDerivedTests = false;
}; };
} // namespace Internal } // namespace Internal

View File

@@ -18,9 +18,12 @@ namespace Internal {
static QStringList specialFunctions({"initTestCase", "cleanupTestCase", "init", "cleanup"}); static QStringList specialFunctions({"initTestCase", "cleanupTestCase", "init", "cleanup"});
TestQmlVisitor::TestQmlVisitor(QmlJS::Document::Ptr doc, const QmlJS::Snapshot &snapshot) TestQmlVisitor::TestQmlVisitor(QmlJS::Document::Ptr doc,
const QmlJS::Snapshot &snapshot,
bool checkForDerivedTest)
: m_currentDoc(doc) : m_currentDoc(doc)
, m_snapshot(snapshot) , m_snapshot(snapshot)
, m_checkForDerivedTest(checkForDerivedTest)
{ {
} }
@@ -68,8 +71,10 @@ bool TestQmlVisitor::visit(QmlJS::AST::UiObjectDefinition *ast)
const QStringView name = ast->qualifiedTypeNameId->name; const QStringView name = ast->qualifiedTypeNameId->name;
m_objectIsTestStack.push(false); m_objectIsTestStack.push(false);
if (name != QLatin1String("TestCase")) { if (name != QLatin1String("TestCase")) {
if (!isDerivedFromTestCase(ast->qualifiedTypeNameId, m_currentDoc, m_snapshot)) if (!m_checkForDerivedTest
|| !isDerivedFromTestCase(ast->qualifiedTypeNameId, m_currentDoc, m_snapshot)) {
return true; return true;
}
} else if (!documentImportsQtTest(m_currentDoc.data())) { } else if (!documentImportsQtTest(m_currentDoc.data())) {
return true; // find nested TestCase items as well return true; // find nested TestCase items as well
} }

View File

@@ -26,7 +26,9 @@ public:
class TestQmlVisitor : public QmlJS::AST::Visitor class TestQmlVisitor : public QmlJS::AST::Visitor
{ {
public: public:
explicit TestQmlVisitor(QmlJS::Document::Ptr doc, const QmlJS::Snapshot &snapshot); TestQmlVisitor(QmlJS::Document::Ptr doc,
const QmlJS::Snapshot &snapshot,
bool checkForDerivedTest);
bool visit(QmlJS::AST::UiObjectDefinition *ast) override; bool visit(QmlJS::AST::UiObjectDefinition *ast) override;
void endVisit(QmlJS::AST::UiObjectDefinition *ast) override; void endVisit(QmlJS::AST::UiObjectDefinition *ast) override;
@@ -48,6 +50,7 @@ private:
QVector<QuickTestCaseSpec> m_testCases; QVector<QuickTestCaseSpec> m_testCases;
QStack<bool> m_objectIsTestStack; QStack<bool> m_objectIsTestStack;
bool m_expectTestCaseName = false; bool m_expectTestCaseName = false;
bool m_checkForDerivedTest = false;
}; };
class QuickTestAstVisitor : public CPlusPlus::ASTVisitor class QuickTestAstVisitor : public CPlusPlus::ASTVisitor