forked from qt-creator/qt-creator
AutoTest: Take precompiled headers into account
Test frameworks might be added to the precompiled headers. This in turn would make some pre-checks whether a file has to be processed or not fail. Fixes: QTCREATORBUG-25821 Change-Id: Iff69c1a83889cb6f79a3e3f9b2e59c5383989ccd Reviewed-by: Christian Stenger <christian.stenger@qt.io> Reviewed-by: David Schulz <david.schulz@qt.io>
This commit is contained in:
@@ -84,7 +84,9 @@ static bool includesBoostTest(const CPlusPlus::Document::Ptr &doc,
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
return CppParser::precompiledHeaderContains(snapshot,
|
||||
Utils::FilePath::fromString(doc->fileName()),
|
||||
boostTestHpp);
|
||||
}
|
||||
|
||||
static bool hasBoostTestMacros(const CPlusPlus::Document::Ptr &doc)
|
||||
|
@@ -86,6 +86,12 @@ static bool includesCatchHeader(const CPlusPlus::Document::Ptr &doc,
|
||||
}
|
||||
}
|
||||
|
||||
for (const QString &catchHeader : catchHeaders) {
|
||||
if (CppParser::precompiledHeaderContains(snapshot,
|
||||
Utils::FilePath::fromString(doc->fileName()),
|
||||
catchHeader))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -109,13 +115,24 @@ bool CatchTestParser::processDocument(QFutureInterface<TestParseResultPtr> futur
|
||||
const Utils::FilePath &fileName)
|
||||
{
|
||||
CPlusPlus::Document::Ptr doc = document(fileName);
|
||||
if (doc.isNull() || !includesCatchHeader(doc, m_cppSnapshot) || !hasCatchNames(doc))
|
||||
if (doc.isNull() || !includesCatchHeader(doc, m_cppSnapshot))
|
||||
return false;
|
||||
|
||||
const CppTools::CppModelManager *modelManager = CppTools::CppModelManager::instance();
|
||||
const QString &filePath = doc->fileName();
|
||||
const QByteArray &fileContent = getFileContent(fileName);
|
||||
|
||||
if (!hasCatchNames(doc)) {
|
||||
const QRegularExpression regex("\\b(SCENARIO|(TEMPLATE_(PRODUCT_)?)?TEST_CASE(_METHOD)?|"
|
||||
"TEMPLATE_TEST_CASE(_METHOD)?_SIG|"
|
||||
"TEMPLATE_PRODUCT_TEST_CASE(_METHOD)?_SIG|"
|
||||
"TEMPLATE_LIST_TEST_CASE_METHOD|METHOD_AS_TEST_CASE|"
|
||||
"REGISTER_TEST_CASE)");
|
||||
if (!regex.match(QString::fromUtf8(fileContent)).hasMatch())
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
const QList<CppTools::ProjectPart::Ptr> projectParts = modelManager->projectPart(fileName);
|
||||
if (projectParts.isEmpty()) // happens if shutting down while parsing
|
||||
return false;
|
||||
|
@@ -32,6 +32,9 @@
|
||||
#include <cpptools/cppmodelmanager.h>
|
||||
#include <cpptools/projectpart.h>
|
||||
|
||||
#include <QRegularExpression>
|
||||
#include <QRegularExpressionMatch>
|
||||
|
||||
namespace Autotest {
|
||||
namespace Internal {
|
||||
|
||||
@@ -69,7 +72,9 @@ static bool includesGTest(const CPlusPlus::Document::Ptr &doc,
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
return CppParser::precompiledHeaderContains(snapshot,
|
||||
Utils::FilePath::fromString(doc->fileName()),
|
||||
gtestH);
|
||||
}
|
||||
|
||||
static bool hasGTestNames(const CPlusPlus::Document::Ptr &document)
|
||||
@@ -91,12 +96,18 @@ bool GTestParser::processDocument(QFutureInterface<TestParseResultPtr> futureInt
|
||||
const Utils::FilePath &fileName)
|
||||
{
|
||||
CPlusPlus::Document::Ptr doc = document(fileName);
|
||||
if (doc.isNull() || !includesGTest(doc, m_cppSnapshot) || !hasGTestNames(doc))
|
||||
if (doc.isNull() || !includesGTest(doc, m_cppSnapshot))
|
||||
return false;
|
||||
|
||||
const CppTools::CppModelManager *modelManager = CppTools::CppModelManager::instance();
|
||||
const QString &filePath = doc->fileName();
|
||||
const QByteArray &fileContent = getFileContent(fileName);
|
||||
if (!hasGTestNames(doc)) {
|
||||
const QRegularExpression regex("\\b(TEST(_[FP])?|TYPED_TEST(_P)?|(GTEST_TEST))");
|
||||
if (!regex.match(QString::fromUtf8(fileContent)).hasMatch())
|
||||
return false;
|
||||
}
|
||||
|
||||
const QString &filePath = doc->fileName();
|
||||
const CppTools::CppModelManager *modelManager = CppTools::CppModelManager::instance();
|
||||
CPlusPlus::Document::Ptr document = m_cppSnapshot.preprocessedDocument(fileContent, fileName);
|
||||
document->check();
|
||||
CPlusPlus::AST *ast = document->translationUnit()->ast();
|
||||
|
@@ -28,6 +28,10 @@
|
||||
#include <coreplugin/editormanager/editormanager.h>
|
||||
#include <cpptools/cppmodelmanager.h>
|
||||
#include <utils/textfileformat.h>
|
||||
#include <utils/algorithm.h>
|
||||
|
||||
#include <QRegularExpression>
|
||||
#include <QRegularExpressionMatch>
|
||||
|
||||
namespace Autotest {
|
||||
|
||||
@@ -69,6 +73,39 @@ QByteArray CppParser::getFileContent(const Utils::FilePath &filePath) const
|
||||
return fileContent;
|
||||
}
|
||||
|
||||
bool precompiledHeaderContains(const CPlusPlus::Snapshot &snapshot,
|
||||
const Utils::FilePath &filePath,
|
||||
const std::function<bool(const QString &)> &checker)
|
||||
{
|
||||
const CppTools::CppModelManager *modelManager = CppTools::CppModelManager::instance();
|
||||
const QList<CppTools::ProjectPart::Ptr> projectParts = modelManager->projectPart(filePath);
|
||||
if (projectParts.isEmpty())
|
||||
return false;
|
||||
const QStringList precompiledHeaders = projectParts.first()->precompiledHeaders;
|
||||
auto headerContains = [&](const QString &header){
|
||||
return Utils::anyOf(snapshot.allIncludesForDocument(header), checker);
|
||||
};
|
||||
return Utils::anyOf(precompiledHeaders, headerContains);
|
||||
}
|
||||
|
||||
bool CppParser::precompiledHeaderContains(const CPlusPlus::Snapshot &snapshot,
|
||||
const Utils::FilePath &filePath,
|
||||
const QString &headerFilePath)
|
||||
{
|
||||
return Autotest::precompiledHeaderContains(snapshot, filePath, [&](const QString &include) {
|
||||
return include.endsWith(headerFilePath);
|
||||
});
|
||||
}
|
||||
|
||||
bool CppParser::precompiledHeaderContains(const CPlusPlus::Snapshot &snapshot,
|
||||
const Utils::FilePath &filePath,
|
||||
const QRegularExpression &headerFileRegex)
|
||||
{
|
||||
return Autotest::precompiledHeaderContains(snapshot, filePath, [&](const QString &include) {
|
||||
return headerFileRegex.match(include).hasMatch();
|
||||
});
|
||||
}
|
||||
|
||||
void CppParser::release()
|
||||
{
|
||||
m_cppSnapshot = CPlusPlus::Snapshot();
|
||||
|
@@ -33,6 +33,10 @@
|
||||
|
||||
#include <QFutureInterface>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
class QRegularExpression;
|
||||
QT_END_NAMESPACE
|
||||
|
||||
namespace Autotest {
|
||||
|
||||
class ITestFramework;
|
||||
@@ -85,6 +89,12 @@ public:
|
||||
|
||||
CPlusPlus::Document::Ptr document(const Utils::FilePath &fileName);
|
||||
|
||||
static bool precompiledHeaderContains(const CPlusPlus::Snapshot &snapshot,
|
||||
const Utils::FilePath &filePath,
|
||||
const QString &headerFilePath);
|
||||
static bool precompiledHeaderContains(const CPlusPlus::Snapshot &snapshot,
|
||||
const Utils::FilePath &filePath,
|
||||
const QRegularExpression &headerFileRegex);
|
||||
protected:
|
||||
CPlusPlus::Snapshot m_cppSnapshot;
|
||||
CppTools::WorkingCopy m_workingCopy;
|
||||
|
@@ -32,6 +32,8 @@
|
||||
#include <cplusplus/TypeOfExpression.h>
|
||||
#include <utils/algorithm.h>
|
||||
|
||||
#include <QRegularExpressionMatchIterator>
|
||||
|
||||
namespace Autotest {
|
||||
namespace Internal {
|
||||
|
||||
@@ -78,6 +80,14 @@ static bool includesQtTest(const CPlusPlus::Document::Ptr &doc, const CPlusPlus:
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
for (const QString &prefix : expectedHeaderPrefixes) {
|
||||
if (CppParser::precompiledHeaderContains(snapshot,
|
||||
Utils::FilePath::fromString(doc->fileName()),
|
||||
QString("%1/qtest.h").arg(prefix))) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -120,7 +130,19 @@ TestCases QtTestParser::testCases(const CppTools::CppModelManager *modelManager,
|
||||
CPlusPlus::AST *ast = document->translationUnit()->ast();
|
||||
TestAstVisitor astVisitor(document, m_cppSnapshot);
|
||||
astVisitor.accept(ast);
|
||||
if (!astVisitor.testCases().isEmpty())
|
||||
return astVisitor.testCases();
|
||||
|
||||
// check pch usage - might give false positives, but we can't do better without cost
|
||||
TestCases result;
|
||||
const QRegularExpression regex("\\bQTEST_(APPLESS_|GUILESS_)?MAIN"
|
||||
"\\s*\\(\\s*([[:alnum:]]+)\\s*\\)");
|
||||
QRegularExpressionMatchIterator it = regex.globalMatch(QString::fromUtf8(fileContent));
|
||||
while (it.hasNext()) {
|
||||
const QRegularExpressionMatch match = it.next();
|
||||
result.append({match.captured(2), false});
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
static CPlusPlus::Document::Ptr declaringDocument(CPlusPlus::Document::Ptr doc,
|
||||
|
@@ -87,6 +87,14 @@ static bool includesQtQuickTest(const CPlusPlus::Document::Ptr &doc,
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
for (const QString &prefix : expectedHeaderPrefixes) {
|
||||
if (CppParser::precompiledHeaderContains(snapshot,
|
||||
Utils::FilePath::fromString(doc->fileName()),
|
||||
QString("%1/quicktest.h").arg(prefix))) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -115,6 +123,7 @@ static QString quickTestSrcDir(const CppTools::CppModelManager *cppMM,
|
||||
QString QuickTestParser::quickTestName(const CPlusPlus::Document::Ptr &doc) const
|
||||
{
|
||||
const QList<CPlusPlus::Document::MacroUse> macros = doc->macroUses();
|
||||
const Utils::FilePath filePath = Utils::FilePath::fromString(doc->fileName());
|
||||
|
||||
for (const CPlusPlus::Document::MacroUse ¯o : macros) {
|
||||
if (!macro.isFunctionLike())
|
||||
@@ -122,22 +131,45 @@ QString QuickTestParser::quickTestName(const CPlusPlus::Document::Ptr &doc) cons
|
||||
const QByteArray name = macro.macro().name();
|
||||
if (QuickTestUtils::isQuickTestMacro(name)) {
|
||||
CPlusPlus::Document::Block arg = macro.arguments().at(0);
|
||||
return QLatin1String(getFileContent(Utils::FilePath::fromString(doc->fileName()))
|
||||
return QLatin1String(getFileContent(filePath)
|
||||
.mid(int(arg.bytesBegin()), int(arg.bytesEnd() - arg.bytesBegin())));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
const QByteArray &fileContent = getFileContent(filePath);
|
||||
// check for using quick_test_main() directly
|
||||
const QString fileName = doc->fileName();
|
||||
const QByteArray &fileContent = getFileContent(Utils::FilePath::fromString(fileName));
|
||||
CPlusPlus::Document::Ptr document = m_cppSnapshot.preprocessedDocument(fileContent, fileName);
|
||||
CPlusPlus::Document::Ptr document = m_cppSnapshot.preprocessedDocument(fileContent, filePath);
|
||||
if (document.isNull())
|
||||
return QString();
|
||||
document->check();
|
||||
CPlusPlus::AST *ast = document->translationUnit()->ast();
|
||||
QuickTestAstVisitor astVisitor(document, m_cppSnapshot);
|
||||
astVisitor.accept(ast);
|
||||
if (!astVisitor.testBaseName().isEmpty())
|
||||
return astVisitor.testBaseName();
|
||||
|
||||
// check for precompiled headers
|
||||
static QStringList expectedHeaderPrefixes
|
||||
= Utils::HostOsInfo::isMacHost()
|
||||
? QStringList({"QtQuickTest.framework/Headers", "QtQuickTest"})
|
||||
: QStringList({"QtQuickTest"});
|
||||
bool pchIncludes = false;
|
||||
for (const QString &prefix : expectedHeaderPrefixes) {
|
||||
if (CppParser::precompiledHeaderContains(m_cppSnapshot, filePath,
|
||||
QString("%1/quicktest.h").arg(prefix))) {
|
||||
pchIncludes = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (pchIncludes) {
|
||||
const QRegularExpression regex("\\bQUICK_TEST_(MAIN|OPENGL_MAIN|MAIN_WITH_SETUP)");
|
||||
const QRegularExpressionMatch match = regex.match(QString::fromUtf8(fileContent));
|
||||
if (match.hasMatch())
|
||||
return match.captured(); // we do not care for the name, just return something non-empty
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
QList<Document::Ptr> QuickTestParser::scanDirectoryForQuickTestQmlFiles(const QString &srcDir)
|
||||
|
Reference in New Issue
Block a user