forked from qt-creator/qt-creator
Add basic support for gtest
This patch provides the basics for detecting the googletest related code. Change-Id: I34da3e02596cdc0805f79633ecf2176807390fc1 Reviewed-by: Nikolai Kosjar <nikolai.kosjar@theqtcompany.com>
This commit is contained in:
@@ -38,6 +38,7 @@ HEADERS += \
|
|||||||
testcodeparser.h \
|
testcodeparser.h \
|
||||||
autotestplugin.h \
|
autotestplugin.h \
|
||||||
autotest_global.h \
|
autotest_global.h \
|
||||||
|
autotest_utils.h \
|
||||||
autotestconstants.h \
|
autotestconstants.h \
|
||||||
testrunner.h \
|
testrunner.h \
|
||||||
testconfiguration.h \
|
testconfiguration.h \
|
||||||
|
@@ -32,6 +32,7 @@ QtcCommercialPlugin {
|
|||||||
"autotest.qrc",
|
"autotest.qrc",
|
||||||
"autotesticons.h",
|
"autotesticons.h",
|
||||||
"autotest_global.h",
|
"autotest_global.h",
|
||||||
|
"autotest_utils.h",
|
||||||
"autotestconstants.h",
|
"autotestconstants.h",
|
||||||
"autotestplugin.cpp",
|
"autotestplugin.cpp",
|
||||||
"autotestplugin.h",
|
"autotestplugin.h",
|
||||||
|
39
plugins/autotest/autotest_utils.h
Normal file
39
plugins/autotest/autotest_utils.h
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
/****************************************************************************
|
||||||
|
**
|
||||||
|
** Copyright (C) 2015 The Qt Company Ltd
|
||||||
|
** All rights reserved.
|
||||||
|
** For any questions to The Qt Company, please use contact form at
|
||||||
|
** http://www.qt.io/contact-us
|
||||||
|
**
|
||||||
|
** This file is part of the Qt Creator Enterprise Auto Test Add-on.
|
||||||
|
**
|
||||||
|
** Licensees holding valid Qt Enterprise licenses may use this file in
|
||||||
|
** accordance with the Qt Enterprise License Agreement provided with the
|
||||||
|
** Software or, alternatively, in accordance with the terms contained in
|
||||||
|
** a written agreement between you and The Qt Company.
|
||||||
|
**
|
||||||
|
** If you have questions regarding the use of this file, please use
|
||||||
|
** contact form at http://www.qt.io/contact-us
|
||||||
|
**
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
#ifndef AUTOTEST_UTILS_H
|
||||||
|
#define AUTOTEST_UTILS_H
|
||||||
|
|
||||||
|
#include <QStringList>
|
||||||
|
|
||||||
|
namespace AutoTest {
|
||||||
|
namespace Internal {
|
||||||
|
|
||||||
|
static bool isGTestMacro(const QString ¯o)
|
||||||
|
{
|
||||||
|
static QStringList valid = {
|
||||||
|
QStringLiteral("TEST"), QStringLiteral("TEST_F"), QStringLiteral("TEST_P")
|
||||||
|
};
|
||||||
|
return valid.contains(macro);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Internal
|
||||||
|
} // namespace AutoTest
|
||||||
|
|
||||||
|
#endif // AUTOTEST_UTILS_H
|
@@ -18,6 +18,7 @@
|
|||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
|
|
||||||
#include "autotestconstants.h"
|
#include "autotestconstants.h"
|
||||||
|
#include "autotest_utils.h"
|
||||||
#include "testcodeparser.h"
|
#include "testcodeparser.h"
|
||||||
#include "testinfo.h"
|
#include "testinfo.h"
|
||||||
#include "testvisitor.h"
|
#include "testvisitor.h"
|
||||||
@@ -223,6 +224,26 @@ static bool includesQtQuickTest(const CPlusPlus::Document::Ptr &doc,
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool includesGTest(const CPlusPlus::Document::Ptr &doc,
|
||||||
|
const CppTools::CppModelManager *cppMM)
|
||||||
|
{
|
||||||
|
const QString gtestH = QLatin1String("gtest/gtest.h");
|
||||||
|
foreach (const CPlusPlus::Document::Include &inc, doc->resolvedIncludes()) {
|
||||||
|
if (inc.resolvedFileName().endsWith(gtestH))
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cppMM) {
|
||||||
|
const CPlusPlus::Snapshot snapshot = cppMM->snapshot();
|
||||||
|
foreach (const QString &include, snapshot.allIncludesForDocument(doc->fileName())) {
|
||||||
|
if (include.endsWith(gtestH))
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
static bool qtTestLibDefined(const CppTools::CppModelManager *cppMM,
|
static bool qtTestLibDefined(const CppTools::CppModelManager *cppMM,
|
||||||
const QString &fileName)
|
const QString &fileName)
|
||||||
{
|
{
|
||||||
@@ -298,6 +319,24 @@ static QString quickTestName(const CPlusPlus::Document::Ptr &doc)
|
|||||||
return QString();
|
return QString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static QSet<QString> testNames(CPlusPlus::Document::Ptr &document)
|
||||||
|
{
|
||||||
|
QSet<QString> result;
|
||||||
|
foreach (const CPlusPlus::Document::MacroUse ¯o, document->macroUses()) {
|
||||||
|
if (!macro.isFunctionLike())
|
||||||
|
continue;
|
||||||
|
if (AutoTest::Internal::isGTestMacro(QLatin1String(macro.macro().name()))) {
|
||||||
|
const QVector<CPlusPlus::Document::Block> args = macro.arguments();
|
||||||
|
if (args.size() != 2)
|
||||||
|
continue;
|
||||||
|
const CPlusPlus::Document::Block name = args.first();
|
||||||
|
result.insert(QLatin1String(getFileContent(document->fileName())
|
||||||
|
.mid(name.bytesBegin(), name.bytesEnd() - name.bytesBegin())));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
static QList<QmlJS::Document::Ptr> scanDirectoryForQuickTestQmlFiles(const QString &srcDir)
|
static QList<QmlJS::Document::Ptr> scanDirectoryForQuickTestQmlFiles(const QString &srcDir)
|
||||||
{
|
{
|
||||||
QStringList dirs(srcDir);
|
QStringList dirs(srcDir);
|
||||||
@@ -494,6 +533,15 @@ void TestCodeParser::checkDocumentForTestCode(CPlusPlus::Document::Ptr document)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (includesGTest(document, modelManager)) {
|
||||||
|
const QSet<QString> &names = testNames(document);
|
||||||
|
if (!names.isEmpty()) {
|
||||||
|
handleGTest(document->fileName(), names);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// could not find the class to test, or QTest is not included and QT_TESTLIB_LIB defined
|
// could not find the class to test, or QTest is not included and QT_TESTLIB_LIB defined
|
||||||
// maybe file is only a referenced file
|
// maybe file is only a referenced file
|
||||||
if (m_cppDocMap.contains(fileName)) {
|
if (m_cppDocMap.contains(fileName)) {
|
||||||
@@ -547,6 +595,20 @@ void TestCodeParser::handleQtQuickTest(CPlusPlus::Document::Ptr document)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void TestCodeParser::handleGTest(const QString &filePath, const QSet<QString> &names)
|
||||||
|
{
|
||||||
|
const QByteArray &fileContent = getFileContent(filePath);
|
||||||
|
const CPlusPlus::Snapshot snapshot = CPlusPlus::CppModelManagerBase::instance()->snapshot();
|
||||||
|
CPlusPlus::Document::Ptr document = snapshot.preprocessedDocument(fileContent, filePath);
|
||||||
|
document->check();
|
||||||
|
CPlusPlus::AST *ast = document->translationUnit()->ast();
|
||||||
|
GTestVisitor visitor(document);
|
||||||
|
visitor.accept(ast);
|
||||||
|
|
||||||
|
QMap<QString, TestCodeLocationList> result = visitor.gtestFunctions();
|
||||||
|
QTC_CHECK(names.contains(result.keys().toSet()));
|
||||||
|
}
|
||||||
|
|
||||||
void TestCodeParser::onCppDocumentUpdated(const CPlusPlus::Document::Ptr &document)
|
void TestCodeParser::onCppDocumentUpdated(const CPlusPlus::Document::Ptr &document)
|
||||||
{
|
{
|
||||||
if (m_codeModelParsing) {
|
if (m_codeModelParsing) {
|
||||||
|
@@ -82,6 +82,7 @@ public slots:
|
|||||||
void updateTestTree();
|
void updateTestTree();
|
||||||
void checkDocumentForTestCode(CPlusPlus::Document::Ptr document);
|
void checkDocumentForTestCode(CPlusPlus::Document::Ptr document);
|
||||||
void handleQtQuickTest(CPlusPlus::Document::Ptr document);
|
void handleQtQuickTest(CPlusPlus::Document::Ptr document);
|
||||||
|
void handleGTest(const QString &filePath, const QSet<QString> &names);
|
||||||
|
|
||||||
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);
|
||||||
|
@@ -47,7 +47,10 @@ public:
|
|||||||
TestFunction,
|
TestFunction,
|
||||||
TestDataTag,
|
TestDataTag,
|
||||||
TestDataFunction,
|
TestDataFunction,
|
||||||
TestSpecialFunction
|
TestSpecialFunction,
|
||||||
|
GTestCase, // should we distinguish between Case and Fixture?
|
||||||
|
GTestName,
|
||||||
|
GTestNameDisabled
|
||||||
};
|
};
|
||||||
|
|
||||||
TestTreeItem(const QString &name = QString(), const QString &filePath = QString(),
|
TestTreeItem(const QString &name = QString(), const QString &filePath = QString(),
|
||||||
|
@@ -17,6 +17,7 @@
|
|||||||
**
|
**
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
|
|
||||||
|
#include "autotest_utils.h"
|
||||||
#include "testvisitor.h"
|
#include "testvisitor.h"
|
||||||
|
|
||||||
#include <cplusplus/FullySpecifiedType.h>
|
#include <cplusplus/FullySpecifiedType.h>
|
||||||
@@ -339,5 +340,51 @@ bool TestQmlVisitor::visit(QmlJS::AST::StringLiteral *ast)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/********************** Google Test Function AST Visitor **********************/
|
||||||
|
|
||||||
|
GTestVisitor::GTestVisitor(CPlusPlus::Document::Ptr doc)
|
||||||
|
: CPlusPlus::ASTVisitor(doc->translationUnit())
|
||||||
|
, m_document(doc)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
bool GTestVisitor::visit(CPlusPlus::FunctionDefinitionAST *ast)
|
||||||
|
{
|
||||||
|
if (!ast || !ast->declarator || !ast->declarator->core_declarator)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
CPlusPlus::DeclaratorIdAST *id = ast->declarator->core_declarator->asDeclaratorId();
|
||||||
|
if (!id || !ast->symbol || ast->symbol->argumentCount() != 2)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
CPlusPlus::LookupContext lc;
|
||||||
|
const QString prettyName = m_overview.prettyName(lc.fullyQualifiedName(ast->symbol));
|
||||||
|
if (!AutoTest::Internal::isGTestMacro(prettyName))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
CPlusPlus::Argument *testCaseNameArg = ast->symbol->argumentAt(0)->asArgument();
|
||||||
|
CPlusPlus::Argument *testNameArg = ast->symbol->argumentAt(1)->asArgument();
|
||||||
|
if (testCaseNameArg && testNameArg) {
|
||||||
|
const QString &testCaseName = m_overview.prettyType(testCaseNameArg->type());
|
||||||
|
const QString &testName = m_overview.prettyType(testNameArg->type());
|
||||||
|
|
||||||
|
bool disabled = testName.startsWith(QLatin1String("DISABLED_"));
|
||||||
|
unsigned line = 0;
|
||||||
|
unsigned column = 0;
|
||||||
|
unsigned token = id->firstToken();
|
||||||
|
m_document->translationUnit()->getTokenStartPosition(token, &line, &column);
|
||||||
|
|
||||||
|
TestCodeLocationAndType locationAndType;
|
||||||
|
locationAndType.m_name = disabled ? testName.mid(9) : testName;
|
||||||
|
locationAndType.m_line = line;
|
||||||
|
locationAndType.m_column = column - 1;
|
||||||
|
locationAndType.m_type = disabled ? TestTreeItem::GTestNameDisabled
|
||||||
|
: TestTreeItem::GTestName;
|
||||||
|
m_gtestFunctions[testCaseName].append(locationAndType);
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace Internal
|
} // namespace Internal
|
||||||
} // namespace Autotest
|
} // namespace Autotest
|
||||||
|
@@ -123,6 +123,21 @@ private:
|
|||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class GTestVisitor : public CPlusPlus::ASTVisitor
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
GTestVisitor(CPlusPlus::Document::Ptr doc);
|
||||||
|
bool visit(CPlusPlus::FunctionDefinitionAST *ast);
|
||||||
|
|
||||||
|
QMap<QString, TestCodeLocationList> gtestFunctions() const { return m_gtestFunctions; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
CPlusPlus::Document::Ptr m_document;
|
||||||
|
CPlusPlus::Overview m_overview;
|
||||||
|
QMap<QString, TestCodeLocationList> m_gtestFunctions;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
} // namespace Internal
|
} // namespace Internal
|
||||||
} // namespace Autotest
|
} // namespace Autotest
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user