diff options
author | Christian Stenger <christian.stenger@theqtcompany.com> | 2015-12-07 10:21:50 +0100 |
---|---|---|
committer | Christian Stenger <christian.stenger@theqtcompany.com> | 2016-01-05 14:51:31 +0000 |
commit | 42def5bb051dec49efbb62ce507db30571b16a3c (patch) | |
tree | a0e025e280eaca6022e484c4d34a495f565c3e69 | |
parent | e72cfeefbaf78bc6bc2fc0ac6b3f2c6171d61e42 (diff) |
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>
-rw-r--r-- | plugins/autotest/autotest.pro | 1 | ||||
-rw-r--r-- | plugins/autotest/autotest.qbs | 1 | ||||
-rw-r--r-- | plugins/autotest/autotest_utils.h | 39 | ||||
-rw-r--r-- | plugins/autotest/testcodeparser.cpp | 62 | ||||
-rw-r--r-- | plugins/autotest/testcodeparser.h | 1 | ||||
-rw-r--r-- | plugins/autotest/testtreeitem.h | 5 | ||||
-rw-r--r-- | plugins/autotest/testvisitor.cpp | 47 | ||||
-rw-r--r-- | plugins/autotest/testvisitor.h | 15 |
8 files changed, 170 insertions, 1 deletions
diff --git a/plugins/autotest/autotest.pro b/plugins/autotest/autotest.pro index 1a411d3490..f360aac5b8 100644 --- a/plugins/autotest/autotest.pro +++ b/plugins/autotest/autotest.pro @@ -38,6 +38,7 @@ HEADERS += \ testcodeparser.h \ autotestplugin.h \ autotest_global.h \ + autotest_utils.h \ autotestconstants.h \ testrunner.h \ testconfiguration.h \ diff --git a/plugins/autotest/autotest.qbs b/plugins/autotest/autotest.qbs index 704394044c..b5696184e7 100644 --- a/plugins/autotest/autotest.qbs +++ b/plugins/autotest/autotest.qbs @@ -32,6 +32,7 @@ QtcCommercialPlugin { "autotest.qrc", "autotesticons.h", "autotest_global.h", + "autotest_utils.h", "autotestconstants.h", "autotestplugin.cpp", "autotestplugin.h", diff --git a/plugins/autotest/autotest_utils.h b/plugins/autotest/autotest_utils.h new file mode 100644 index 0000000000..a9f1ba45bf --- /dev/null +++ b/plugins/autotest/autotest_utils.h @@ -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 diff --git a/plugins/autotest/testcodeparser.cpp b/plugins/autotest/testcodeparser.cpp index 6f32e8dc58..bf1aab0399 100644 --- a/plugins/autotest/testcodeparser.cpp +++ b/plugins/autotest/testcodeparser.cpp @@ -18,6 +18,7 @@ ****************************************************************************/ #include "autotestconstants.h" +#include "autotest_utils.h" #include "testcodeparser.h" #include "testinfo.h" #include "testvisitor.h" @@ -223,6 +224,26 @@ static bool includesQtQuickTest(const CPlusPlus::Document::Ptr &doc, 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, const QString &fileName) { @@ -298,6 +319,24 @@ static QString quickTestName(const CPlusPlus::Document::Ptr &doc) 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) { QStringList dirs(srcDir); @@ -494,6 +533,15 @@ void TestCodeParser::checkDocumentForTestCode(CPlusPlus::Document::Ptr document) 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 // maybe file is only a referenced file 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) { if (m_codeModelParsing) { diff --git a/plugins/autotest/testcodeparser.h b/plugins/autotest/testcodeparser.h index 3c5529f63a..d966b363d4 100644 --- a/plugins/autotest/testcodeparser.h +++ b/plugins/autotest/testcodeparser.h @@ -82,6 +82,7 @@ public slots: void updateTestTree(); void checkDocumentForTestCode(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 onQmlDocumentUpdated(const QmlJS::Document::Ptr &document); diff --git a/plugins/autotest/testtreeitem.h b/plugins/autotest/testtreeitem.h index 19cd4adf7e..c228b325a6 100644 --- a/plugins/autotest/testtreeitem.h +++ b/plugins/autotest/testtreeitem.h @@ -47,7 +47,10 @@ public: TestFunction, TestDataTag, TestDataFunction, - TestSpecialFunction + TestSpecialFunction, + GTestCase, // should we distinguish between Case and Fixture? + GTestName, + GTestNameDisabled }; TestTreeItem(const QString &name = QString(), const QString &filePath = QString(), diff --git a/plugins/autotest/testvisitor.cpp b/plugins/autotest/testvisitor.cpp index 6074d76ac9..9a0c51961d 100644 --- a/plugins/autotest/testvisitor.cpp +++ b/plugins/autotest/testvisitor.cpp @@ -17,6 +17,7 @@ ** ****************************************************************************/ +#include "autotest_utils.h" #include "testvisitor.h" #include <cplusplus/FullySpecifiedType.h> @@ -339,5 +340,51 @@ bool TestQmlVisitor::visit(QmlJS::AST::StringLiteral *ast) 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 Autotest diff --git a/plugins/autotest/testvisitor.h b/plugins/autotest/testvisitor.h index 4441eb26f8..bbccffd4e1 100644 --- a/plugins/autotest/testvisitor.h +++ b/plugins/autotest/testvisitor.h @@ -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 Autotest |