forked from qt-creator/qt-creator
		
	AutoTest: Move test framework related code...
...into files and respective sub folders. Change-Id: Ic80d693bd73993a6e74b6d422349e47276e8cb6e Reviewed-by: David Schulz <david.schulz@theqtcompany.com>
This commit is contained in:
		@@ -26,30 +26,25 @@
 | 
			
		||||
#include "autotestconstants.h"
 | 
			
		||||
#include "autotest_utils.h"
 | 
			
		||||
#include "testcodeparser.h"
 | 
			
		||||
#include "testvisitor.h"
 | 
			
		||||
 | 
			
		||||
// FIXME
 | 
			
		||||
#include "qtest/qttestparser.h"
 | 
			
		||||
#include "quick/quicktestparser.h"
 | 
			
		||||
#include "gtest/googletestparser.h"
 | 
			
		||||
// end of FIXME
 | 
			
		||||
 | 
			
		||||
#include <coreplugin/editormanager/editormanager.h>
 | 
			
		||||
#include <coreplugin/progressmanager/futureprogress.h>
 | 
			
		||||
#include <coreplugin/progressmanager/progressmanager.h>
 | 
			
		||||
 | 
			
		||||
#include <cplusplus/LookupContext.h>
 | 
			
		||||
#include <cplusplus/TypeOfExpression.h>
 | 
			
		||||
 | 
			
		||||
#include <cpptools/cpptoolsconstants.h>
 | 
			
		||||
#include <cpptools/cppmodelmanager.h>
 | 
			
		||||
#include <cpptools/cppworkingcopy.h>
 | 
			
		||||
 | 
			
		||||
#include <projectexplorer/project.h>
 | 
			
		||||
#include <projectexplorer/session.h>
 | 
			
		||||
 | 
			
		||||
#include <qmljs/parser/qmljsast_p.h>
 | 
			
		||||
#include <qmljs/qmljsdialect.h>
 | 
			
		||||
#include <qmljstools/qmljsmodelmanager.h>
 | 
			
		||||
 | 
			
		||||
#include <utils/algorithm.h>
 | 
			
		||||
#include <utils/qtcassert.h>
 | 
			
		||||
#include <utils/runextensions.h>
 | 
			
		||||
#include <utils/textfileformat.h>
 | 
			
		||||
 | 
			
		||||
#include <QDirIterator>
 | 
			
		||||
#include <QFuture>
 | 
			
		||||
@@ -160,468 +155,6 @@ void TestCodeParser::updateTestTree()
 | 
			
		||||
    scanForTests();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/****** scan for QTest related stuff helpers ******/
 | 
			
		||||
 | 
			
		||||
static QByteArray getFileContent(QString filePath)
 | 
			
		||||
{
 | 
			
		||||
    QByteArray fileContent;
 | 
			
		||||
    CppTools::CppModelManager *cppMM = CppTools::CppModelManager::instance();
 | 
			
		||||
    CppTools::WorkingCopy wc = cppMM->workingCopy();
 | 
			
		||||
    if (wc.contains(filePath)) {
 | 
			
		||||
        fileContent = wc.source(filePath);
 | 
			
		||||
    } else {
 | 
			
		||||
        QString error;
 | 
			
		||||
        const QTextCodec *codec = Core::EditorManager::defaultTextCodec();
 | 
			
		||||
        if (Utils::TextFileFormat::readFileUTF8(filePath, codec, &fileContent, &error)
 | 
			
		||||
                != Utils::TextFileFormat::ReadSuccess) {
 | 
			
		||||
            qDebug() << "Failed to read file" << filePath << ":" << error;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    return fileContent;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static bool includesQtTest(const CPlusPlus::Document::Ptr &doc, const CPlusPlus::Snapshot &snapshot)
 | 
			
		||||
{
 | 
			
		||||
    static QStringList expectedHeaderPrefixes
 | 
			
		||||
            = Utils::HostOsInfo::isMacHost()
 | 
			
		||||
            ? QStringList({ QLatin1String("QtTest.framework/Headers"), QLatin1String("QtTest") })
 | 
			
		||||
            : QStringList({ QLatin1String("QtTest") });
 | 
			
		||||
 | 
			
		||||
    const QList<CPlusPlus::Document::Include> includes = doc->resolvedIncludes();
 | 
			
		||||
 | 
			
		||||
    foreach (const CPlusPlus::Document::Include &inc, includes) {
 | 
			
		||||
        // TODO this short cut works only for #include <QtTest>
 | 
			
		||||
        // bad, as there could be much more different approaches
 | 
			
		||||
        if (inc.unresolvedFileName() == QLatin1String("QtTest")) {
 | 
			
		||||
            foreach (const QString &prefix, expectedHeaderPrefixes) {
 | 
			
		||||
                if (inc.resolvedFileName().endsWith(QString::fromLatin1("%1/QtTest").arg(prefix)))
 | 
			
		||||
                    return true;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    const QSet<QString> allIncludes = snapshot.allIncludesForDocument(doc->fileName());
 | 
			
		||||
    foreach (const QString &include, allIncludes) {
 | 
			
		||||
        foreach (const QString &prefix, expectedHeaderPrefixes) {
 | 
			
		||||
        if (include.endsWith(QString::fromLatin1("%1/qtest.h").arg(prefix)))
 | 
			
		||||
            return true;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    return false;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static bool includesQtQuickTest(const CPlusPlus::Document::Ptr &doc,
 | 
			
		||||
                                const CPlusPlus::Snapshot &snapshot)
 | 
			
		||||
{
 | 
			
		||||
    static QStringList expectedHeaderPrefixes
 | 
			
		||||
            = Utils::HostOsInfo::isMacHost()
 | 
			
		||||
            ? QStringList({ QLatin1String("QtQuickTest.framework/Headers"),
 | 
			
		||||
                            QLatin1String("QtQuickTest") })
 | 
			
		||||
            : QStringList({ QLatin1String("QtQuickTest") });
 | 
			
		||||
 | 
			
		||||
    const QList<CPlusPlus::Document::Include> includes = doc->resolvedIncludes();
 | 
			
		||||
 | 
			
		||||
    foreach (const CPlusPlus::Document::Include &inc, includes) {
 | 
			
		||||
        if (inc.unresolvedFileName() == QLatin1String("QtQuickTest/quicktest.h")) {
 | 
			
		||||
            foreach (const QString &prefix, expectedHeaderPrefixes) {
 | 
			
		||||
                if (inc.resolvedFileName().endsWith(
 | 
			
		||||
                            QString::fromLatin1("%1/quicktest.h").arg(prefix))) {
 | 
			
		||||
                    return true;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    foreach (const QString &include, snapshot.allIncludesForDocument(doc->fileName())) {
 | 
			
		||||
        foreach (const QString &prefix, expectedHeaderPrefixes) {
 | 
			
		||||
            if (include.endsWith(QString::fromLatin1("%1/quicktest.h").arg(prefix)))
 | 
			
		||||
                return true;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    return false;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static bool includesGTest(const CPlusPlus::Document::Ptr &doc,
 | 
			
		||||
                          const CPlusPlus::Snapshot &snapshot)
 | 
			
		||||
{
 | 
			
		||||
    const QString gtestH = QLatin1String("gtest/gtest.h");
 | 
			
		||||
    foreach (const CPlusPlus::Document::Include &inc, doc->resolvedIncludes()) {
 | 
			
		||||
        if (inc.resolvedFileName().endsWith(gtestH))
 | 
			
		||||
            return true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    foreach (const QString &include, snapshot.allIncludesForDocument(doc->fileName())) {
 | 
			
		||||
        if (include.endsWith(gtestH))
 | 
			
		||||
            return true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return false;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static bool qtTestLibDefined(const QString &fileName)
 | 
			
		||||
{
 | 
			
		||||
    const QList<CppTools::ProjectPart::Ptr> parts =
 | 
			
		||||
            CppTools::CppModelManager::instance()->projectPart(fileName);
 | 
			
		||||
    if (parts.size() > 0)
 | 
			
		||||
        return parts.at(0)->projectDefines.contains("#define QT_TESTLIB_LIB");
 | 
			
		||||
    return false;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static QString quickTestSrcDir(const CppTools::CppModelManager *cppMM,
 | 
			
		||||
                               const QString &fileName)
 | 
			
		||||
{
 | 
			
		||||
    static const QByteArray qtsd(" QUICK_TEST_SOURCE_DIR ");
 | 
			
		||||
    const QList<CppTools::ProjectPart::Ptr> parts = cppMM->projectPart(fileName);
 | 
			
		||||
    if (parts.size() > 0) {
 | 
			
		||||
        QByteArray projDefines(parts.at(0)->projectDefines);
 | 
			
		||||
        foreach (const QByteArray &line, projDefines.split('\n')) {
 | 
			
		||||
            if (line.contains(qtsd)) {
 | 
			
		||||
                QByteArray result = line.mid(line.indexOf(qtsd) + qtsd.length());
 | 
			
		||||
                if (result.startsWith('"'))
 | 
			
		||||
                    result.remove(result.length() - 1, 1).remove(0, 1);
 | 
			
		||||
                if (result.startsWith("\\\""))
 | 
			
		||||
                    result.remove(result.length() - 2, 2).remove(0, 2);
 | 
			
		||||
                return QLatin1String(result);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    return QString();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static QString testClass(const CppTools::CppModelManager *modelManager,
 | 
			
		||||
                         const CPlusPlus::Snapshot &snapshot, const QString &fileName)
 | 
			
		||||
{
 | 
			
		||||
    const QByteArray &fileContent = getFileContent(fileName);
 | 
			
		||||
    CPlusPlus::Document::Ptr document = modelManager->document(fileName);
 | 
			
		||||
    if (document.isNull())
 | 
			
		||||
        return QString();
 | 
			
		||||
 | 
			
		||||
    const QList<CPlusPlus::Document::MacroUse> macros = document->macroUses();
 | 
			
		||||
 | 
			
		||||
    foreach (const CPlusPlus::Document::MacroUse ¯o, macros) {
 | 
			
		||||
        if (!macro.isFunctionLike())
 | 
			
		||||
            continue;
 | 
			
		||||
        const QByteArray name = macro.macro().name();
 | 
			
		||||
        if (TestUtils::isQTestMacro(name)) {
 | 
			
		||||
            const CPlusPlus::Document::Block arg = macro.arguments().at(0);
 | 
			
		||||
            return QLatin1String(fileContent.mid(arg.bytesBegin(),
 | 
			
		||||
                                                 arg.bytesEnd() - arg.bytesBegin()));
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    // check if one has used a self-defined macro or QTest::qExec() directly
 | 
			
		||||
    document = snapshot.preprocessedDocument(fileContent, fileName);
 | 
			
		||||
    document->check();
 | 
			
		||||
    CPlusPlus::AST *ast = document->translationUnit()->ast();
 | 
			
		||||
    TestAstVisitor astVisitor(document);
 | 
			
		||||
    astVisitor.accept(ast);
 | 
			
		||||
    return astVisitor.className();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static QString quickTestName(const CPlusPlus::Document::Ptr &doc)
 | 
			
		||||
{
 | 
			
		||||
    const QList<CPlusPlus::Document::MacroUse> macros = doc->macroUses();
 | 
			
		||||
 | 
			
		||||
    foreach (const CPlusPlus::Document::MacroUse ¯o, macros) {
 | 
			
		||||
        if (!macro.isFunctionLike())
 | 
			
		||||
            continue;
 | 
			
		||||
        const QByteArray name = macro.macro().name();
 | 
			
		||||
        if (TestUtils::isQuickTestMacro(name)) {
 | 
			
		||||
            CPlusPlus::Document::Block arg = macro.arguments().at(0);
 | 
			
		||||
            return QLatin1String(getFileContent(doc->fileName())
 | 
			
		||||
                                 .mid(arg.bytesBegin(), arg.bytesEnd() - arg.bytesBegin()));
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    return QString();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static bool hasGTestNames(const CPlusPlus::Document::Ptr &document)
 | 
			
		||||
{
 | 
			
		||||
    foreach (const CPlusPlus::Document::MacroUse ¯o, document->macroUses()) {
 | 
			
		||||
        if (!macro.isFunctionLike())
 | 
			
		||||
            continue;
 | 
			
		||||
        if (TestUtils::isGTestMacro(QLatin1String(macro.macro().name()))) {
 | 
			
		||||
            const QVector<CPlusPlus::Document::Block> args = macro.arguments();
 | 
			
		||||
            if (args.size() != 2)
 | 
			
		||||
                continue;
 | 
			
		||||
            return true;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    return false;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static QList<QmlJS::Document::Ptr> scanDirectoryForQuickTestQmlFiles(const QString &srcDir)
 | 
			
		||||
{
 | 
			
		||||
    QStringList dirs(srcDir);
 | 
			
		||||
    QmlJS::ModelManagerInterface *qmlJsMM = QmlJSTools::Internal::ModelManager::instance();
 | 
			
		||||
    // make sure even files not listed in pro file are available inside the snapshot
 | 
			
		||||
    QFutureInterface<void> future;
 | 
			
		||||
    QmlJS::PathsAndLanguages paths;
 | 
			
		||||
    paths.maybeInsert(Utils::FileName::fromString(srcDir), QmlJS::Dialect::Qml);
 | 
			
		||||
    const bool emitDocumentChanges = false;
 | 
			
		||||
    const bool onlyTheLib = false;
 | 
			
		||||
    QmlJS::ModelManagerInterface::importScan(future, qmlJsMM->workingCopy(), paths, qmlJsMM,
 | 
			
		||||
        emitDocumentChanges, onlyTheLib);
 | 
			
		||||
 | 
			
		||||
    const QmlJS::Snapshot snapshot = QmlJSTools::Internal::ModelManager::instance()->snapshot();
 | 
			
		||||
    QDirIterator it(srcDir, QDir::Dirs | QDir::NoDotAndDotDot, QDirIterator::Subdirectories);
 | 
			
		||||
    while (it.hasNext()) {
 | 
			
		||||
        it.next();
 | 
			
		||||
        QFileInfo fi(it.fileInfo().canonicalFilePath());
 | 
			
		||||
        dirs << fi.filePath();
 | 
			
		||||
    }
 | 
			
		||||
    QList<QmlJS::Document::Ptr> foundDocs;
 | 
			
		||||
 | 
			
		||||
    foreach (const QString &path, dirs) {
 | 
			
		||||
        const QList<QmlJS::Document::Ptr> docs = snapshot.documentsInDirectory(path);
 | 
			
		||||
        foreach (const QmlJS::Document::Ptr &doc, docs) {
 | 
			
		||||
            const QString fileName(QFileInfo(doc->fileName()).fileName());
 | 
			
		||||
            if (fileName.startsWith(QLatin1String("tst_")) && fileName.endsWith(QLatin1String(".qml")))
 | 
			
		||||
                foundDocs << doc;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return foundDocs;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static CPlusPlus::Document::Ptr declaringDocument(CPlusPlus::Document::Ptr doc,
 | 
			
		||||
                                                  const CPlusPlus::Snapshot &snapshot,
 | 
			
		||||
                                                  const QString &testCaseName,
 | 
			
		||||
                                                  unsigned *line, unsigned *column)
 | 
			
		||||
{
 | 
			
		||||
    CPlusPlus::Document::Ptr declaringDoc = doc;
 | 
			
		||||
    CPlusPlus::TypeOfExpression typeOfExpr;
 | 
			
		||||
    typeOfExpr.init(doc, snapshot);
 | 
			
		||||
 | 
			
		||||
    QList<CPlusPlus::LookupItem> lookupItems = typeOfExpr(testCaseName.toUtf8(),
 | 
			
		||||
                                                          doc->globalNamespace());
 | 
			
		||||
    if (lookupItems.size()) {
 | 
			
		||||
        if (CPlusPlus::Symbol *symbol = lookupItems.first().declaration()) {
 | 
			
		||||
            if (CPlusPlus::Class *toeClass = symbol->asClass()) {
 | 
			
		||||
                const QString declFileName = QLatin1String(toeClass->fileId()->chars(),
 | 
			
		||||
                                                           toeClass->fileId()->size());
 | 
			
		||||
                declaringDoc = snapshot.document(declFileName);
 | 
			
		||||
                *line = toeClass->line();
 | 
			
		||||
                *column = toeClass->column() - 1;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    return declaringDoc;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static QSet<QString> filesWithDataFunctionDefinitions(
 | 
			
		||||
            const QMap<QString, TestCodeLocationAndType> &testFunctions)
 | 
			
		||||
{
 | 
			
		||||
    QSet<QString> result;
 | 
			
		||||
    QMap<QString, TestCodeLocationAndType>::ConstIterator it = testFunctions.begin();
 | 
			
		||||
    const QMap<QString, TestCodeLocationAndType>::ConstIterator end = testFunctions.end();
 | 
			
		||||
 | 
			
		||||
    for ( ; it != end; ++it) {
 | 
			
		||||
        const QString &key = it.key();
 | 
			
		||||
        if (key.endsWith(QLatin1String("_data")) && testFunctions.contains(key.left(key.size() - 5)))
 | 
			
		||||
            result.insert(it.value().m_name);
 | 
			
		||||
    }
 | 
			
		||||
    return result;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static QMap<QString, TestCodeLocationList> checkForDataTags(const QString &fileName,
 | 
			
		||||
            const CPlusPlus::Snapshot &snapshot)
 | 
			
		||||
{
 | 
			
		||||
    const QByteArray fileContent = getFileContent(fileName);
 | 
			
		||||
    CPlusPlus::Document::Ptr document = snapshot.preprocessedDocument(fileContent, fileName);
 | 
			
		||||
    document->check();
 | 
			
		||||
    CPlusPlus::AST *ast = document->translationUnit()->ast();
 | 
			
		||||
    TestDataFunctionVisitor visitor(document);
 | 
			
		||||
    visitor.accept(ast);
 | 
			
		||||
    return visitor.dataTags();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/****** end of helpers ******/
 | 
			
		||||
 | 
			
		||||
static bool checkQmlDocumentForQuickTestCode(QFutureInterface<TestParseResultPtr> futureInterface,
 | 
			
		||||
                                             const QmlJS::Document::Ptr &qmlJSDoc,
 | 
			
		||||
                                             const QString &proFile = QString())
 | 
			
		||||
{
 | 
			
		||||
    if (qmlJSDoc.isNull())
 | 
			
		||||
        return false;
 | 
			
		||||
    QmlJS::AST::Node *ast = qmlJSDoc->ast();
 | 
			
		||||
    QTC_ASSERT(ast, return false);
 | 
			
		||||
    TestQmlVisitor qmlVisitor(qmlJSDoc);
 | 
			
		||||
    QmlJS::AST::Node::accept(ast, &qmlVisitor);
 | 
			
		||||
 | 
			
		||||
    const QString testCaseName = qmlVisitor.testCaseName();
 | 
			
		||||
    const TestCodeLocationAndType tcLocationAndType = qmlVisitor.testCaseLocation();
 | 
			
		||||
    const QMap<QString, TestCodeLocationAndType> &testFunctions = qmlVisitor.testFunctions();
 | 
			
		||||
 | 
			
		||||
    QuickTestParseResult *parseResult = new QuickTestParseResult;
 | 
			
		||||
    parseResult->proFile = proFile;
 | 
			
		||||
    parseResult->itemType = TestTreeItem::TestCase;
 | 
			
		||||
    QMap<QString, TestCodeLocationAndType>::ConstIterator it = testFunctions.begin();
 | 
			
		||||
    const QMap<QString, TestCodeLocationAndType>::ConstIterator end = testFunctions.end();
 | 
			
		||||
    for ( ; it != end; ++it) {
 | 
			
		||||
        const TestCodeLocationAndType &loc = it.value();
 | 
			
		||||
        QuickTestParseResult *funcResult = new QuickTestParseResult;
 | 
			
		||||
        funcResult->name = it.key();
 | 
			
		||||
        funcResult->displayName = it.key();
 | 
			
		||||
        funcResult->itemType = loc.m_type;
 | 
			
		||||
        funcResult->fileName = loc.m_name;
 | 
			
		||||
        funcResult->line = loc.m_line;
 | 
			
		||||
        funcResult->column = loc.m_column;
 | 
			
		||||
        funcResult->proFile = proFile;
 | 
			
		||||
 | 
			
		||||
        parseResult->children.append(funcResult);
 | 
			
		||||
    }
 | 
			
		||||
    if (!testCaseName.isEmpty()) {
 | 
			
		||||
        parseResult->fileName = tcLocationAndType.m_name;
 | 
			
		||||
        parseResult->name = testCaseName;
 | 
			
		||||
        parseResult->line = tcLocationAndType.m_line;
 | 
			
		||||
        parseResult->column = tcLocationAndType.m_column;
 | 
			
		||||
    }
 | 
			
		||||
    futureInterface.reportResult(TestParseResultPtr(parseResult));
 | 
			
		||||
    return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static bool handleQtTest(QFutureInterface<TestParseResultPtr> futureInterface,
 | 
			
		||||
                         CPlusPlus::Document::Ptr document,
 | 
			
		||||
                         const CPlusPlus::Snapshot &snapshot,
 | 
			
		||||
                         const QString &oldTestCaseName)
 | 
			
		||||
{
 | 
			
		||||
    const CppTools::CppModelManager *modelManager = CppTools::CppModelManager::instance();
 | 
			
		||||
    const QString &fileName = document->fileName();
 | 
			
		||||
    QString testCaseName(testClass(modelManager, snapshot, fileName));
 | 
			
		||||
    // we might be in a reparse without the original entry point with the QTest::qExec()
 | 
			
		||||
    if (testCaseName.isEmpty())
 | 
			
		||||
        testCaseName = oldTestCaseName;
 | 
			
		||||
    if (!testCaseName.isEmpty()) {
 | 
			
		||||
        unsigned line = 0;
 | 
			
		||||
        unsigned column = 0;
 | 
			
		||||
        CPlusPlus::Document::Ptr declaringDoc = declaringDocument(document, snapshot, testCaseName,
 | 
			
		||||
                                                                  &line, &column);
 | 
			
		||||
        if (declaringDoc.isNull())
 | 
			
		||||
            return false;
 | 
			
		||||
 | 
			
		||||
        TestVisitor visitor(testCaseName);
 | 
			
		||||
        visitor.accept(declaringDoc->globalNamespace());
 | 
			
		||||
        if (!visitor.resultValid())
 | 
			
		||||
            return false;
 | 
			
		||||
 | 
			
		||||
        const QMap<QString, TestCodeLocationAndType> &testFunctions = visitor.privateSlots();
 | 
			
		||||
        const QSet<QString> &files = filesWithDataFunctionDefinitions(testFunctions);
 | 
			
		||||
 | 
			
		||||
        // TODO: change to QHash<>
 | 
			
		||||
        QMap<QString, TestCodeLocationList> dataTags;
 | 
			
		||||
        foreach (const QString &file, files)
 | 
			
		||||
            dataTags.unite(checkForDataTags(file, snapshot));
 | 
			
		||||
 | 
			
		||||
        QtTestParseResult *parseResult = new QtTestParseResult;
 | 
			
		||||
        parseResult->itemType = TestTreeItem::TestCase;
 | 
			
		||||
        parseResult->fileName = declaringDoc->fileName();
 | 
			
		||||
        parseResult->name = testCaseName;
 | 
			
		||||
        parseResult->displayName = testCaseName;
 | 
			
		||||
        parseResult->line = line;
 | 
			
		||||
        parseResult->column = column;
 | 
			
		||||
        parseResult->proFile = modelManager->projectPart(fileName).first()->projectFile;
 | 
			
		||||
        QMap<QString, TestCodeLocationAndType>::ConstIterator it = testFunctions.begin();
 | 
			
		||||
        const QMap<QString, TestCodeLocationAndType>::ConstIterator end = testFunctions.end();
 | 
			
		||||
        for ( ; it != end; ++it) {
 | 
			
		||||
            const TestCodeLocationAndType &location = it.value();
 | 
			
		||||
            QtTestParseResult *func = new QtTestParseResult;
 | 
			
		||||
            func->itemType = location.m_type;
 | 
			
		||||
            func->name = testCaseName + QLatin1String("::") + it.key();
 | 
			
		||||
            func->displayName = it.key();
 | 
			
		||||
            func->fileName = location.m_name;
 | 
			
		||||
            func->line = location.m_line;
 | 
			
		||||
            func->column = location.m_column;
 | 
			
		||||
 | 
			
		||||
            foreach (const TestCodeLocationAndType &tag, dataTags.value(func->name)) {
 | 
			
		||||
                QtTestParseResult *dataTag = new QtTestParseResult;
 | 
			
		||||
                dataTag->itemType = tag.m_type;
 | 
			
		||||
                dataTag->name = tag.m_name;
 | 
			
		||||
                dataTag->displayName = tag.m_name;
 | 
			
		||||
                dataTag->fileName = testFunctions.value(it.key() + QLatin1String("_data")).m_name;
 | 
			
		||||
                dataTag->line = tag.m_line;
 | 
			
		||||
                dataTag->column = tag.m_column;
 | 
			
		||||
 | 
			
		||||
                func->children.append(dataTag);
 | 
			
		||||
            }
 | 
			
		||||
            parseResult->children.append(func);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        futureInterface.reportResult(TestParseResultPtr(parseResult));
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
    return false;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static bool handleQtQuickTest(QFutureInterface<TestParseResultPtr> futureInterface,
 | 
			
		||||
                              CPlusPlus::Document::Ptr document)
 | 
			
		||||
{
 | 
			
		||||
    const CppTools::CppModelManager *modelManager = CppTools::CppModelManager::instance();
 | 
			
		||||
    if (quickTestName(document).isEmpty())
 | 
			
		||||
        return false;
 | 
			
		||||
 | 
			
		||||
    const QString cppFileName = document->fileName();
 | 
			
		||||
    QList<CppTools::ProjectPart::Ptr> ppList = modelManager->projectPart(cppFileName);
 | 
			
		||||
    QTC_ASSERT(!ppList.isEmpty(), return false);
 | 
			
		||||
    const QString &proFile = ppList.at(0)->projectFile;
 | 
			
		||||
 | 
			
		||||
    const QString srcDir = quickTestSrcDir(modelManager, cppFileName);
 | 
			
		||||
    if (srcDir.isEmpty())
 | 
			
		||||
        return false;
 | 
			
		||||
 | 
			
		||||
    const QList<QmlJS::Document::Ptr> qmlDocs = scanDirectoryForQuickTestQmlFiles(srcDir);
 | 
			
		||||
    bool result = false;
 | 
			
		||||
    foreach (const QmlJS::Document::Ptr &qmlJSDoc, qmlDocs)
 | 
			
		||||
        result |= checkQmlDocumentForQuickTestCode(futureInterface, qmlJSDoc, proFile);
 | 
			
		||||
    return result;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static bool handleGTest(QFutureInterface<TestParseResultPtr> futureInterface,
 | 
			
		||||
                        const CPlusPlus::Document::Ptr &doc,
 | 
			
		||||
                        const CPlusPlus::Snapshot &snapshot)
 | 
			
		||||
{
 | 
			
		||||
    const CppTools::CppModelManager *modelManager = CppTools::CppModelManager::instance();
 | 
			
		||||
    const QString &filePath = doc->fileName();
 | 
			
		||||
    const QByteArray &fileContent = getFileContent(filePath);
 | 
			
		||||
    CPlusPlus::Document::Ptr document = snapshot.preprocessedDocument(fileContent, filePath);
 | 
			
		||||
    document->check();
 | 
			
		||||
    CPlusPlus::AST *ast = document->translationUnit()->ast();
 | 
			
		||||
    GTestVisitor visitor(document);
 | 
			
		||||
    visitor.accept(ast);
 | 
			
		||||
 | 
			
		||||
    QMap<GTestCaseSpec, GTestCodeLocationList> result = visitor.gtestFunctions();
 | 
			
		||||
    QString proFile;
 | 
			
		||||
    const QList<CppTools::ProjectPart::Ptr> &ppList = modelManager->projectPart(filePath);
 | 
			
		||||
    if (ppList.size())
 | 
			
		||||
        proFile = ppList.first()->projectFile;
 | 
			
		||||
 | 
			
		||||
    foreach (const GTestCaseSpec &testSpec, result.keys()) {
 | 
			
		||||
        GoogleTestParseResult *parseResult = new GoogleTestParseResult;
 | 
			
		||||
        parseResult->itemType = TestTreeItem::TestCase;
 | 
			
		||||
        parseResult->fileName = filePath;
 | 
			
		||||
        parseResult->name = testSpec.testCaseName;
 | 
			
		||||
        parseResult->parameterized = testSpec.parameterized;
 | 
			
		||||
        parseResult->typed = testSpec.typed;
 | 
			
		||||
        parseResult->disabled = testSpec.disabled;
 | 
			
		||||
        parseResult->proFile = proFile;
 | 
			
		||||
 | 
			
		||||
        foreach (const GTestCodeLocationAndType &location, result.value(testSpec)) {
 | 
			
		||||
            GoogleTestParseResult *testSet = new GoogleTestParseResult;
 | 
			
		||||
            testSet->name = location.m_name;
 | 
			
		||||
            testSet->fileName = filePath;
 | 
			
		||||
            testSet->line = location.m_line;
 | 
			
		||||
            testSet->column = location.m_column;
 | 
			
		||||
            testSet->disabled = location.m_state & GoogleTestTreeItem::Disabled;
 | 
			
		||||
            testSet->itemType = location.m_type;
 | 
			
		||||
            testSet->proFile = proFile;
 | 
			
		||||
 | 
			
		||||
            parseResult->children.append(testSet);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        futureInterface.reportResult(TestParseResultPtr(parseResult));
 | 
			
		||||
    }
 | 
			
		||||
    return !result.keys().isEmpty();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// used internally to indicate a parse that failed due to having triggered a parse for a file that
 | 
			
		||||
// is not (yet) part of the CppModelManager's snapshot
 | 
			
		||||
static bool parsingHasFailed;
 | 
			
		||||
@@ -882,90 +415,5 @@ void TestCodeParser::onPartialParsingFinished()
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
TestTreeItem *QtTestParseResult::createTestTreeItem() const
 | 
			
		||||
{
 | 
			
		||||
    return itemType == TestTreeItem::Root ? 0 : AutoTestTreeItem::createTestItem(this);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
TestTreeItem *QuickTestParseResult::createTestTreeItem() const
 | 
			
		||||
{
 | 
			
		||||
    if (itemType == TestTreeItem::Root || itemType == TestTreeItem::TestDataTag)
 | 
			
		||||
        return 0;
 | 
			
		||||
    return QuickTestTreeItem::createTestItem(this);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
TestTreeItem *GoogleTestParseResult::createTestTreeItem() const
 | 
			
		||||
{
 | 
			
		||||
    if (itemType == TestTreeItem::TestCase || itemType == TestTreeItem::TestFunctionOrSet)
 | 
			
		||||
        return GoogleTestTreeItem::createTestItem(this);
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void CppParser::init(const QStringList &filesToParse)
 | 
			
		||||
{
 | 
			
		||||
    Q_UNUSED(filesToParse);
 | 
			
		||||
    m_cppSnapshot = CppTools::CppModelManager::instance()->snapshot();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool CppParser::selectedForBuilding(const QString &fileName)
 | 
			
		||||
{
 | 
			
		||||
    QList<CppTools::ProjectPart::Ptr> projParts =
 | 
			
		||||
            CppTools::CppModelManager::instance()->projectPart(fileName);
 | 
			
		||||
 | 
			
		||||
    return projParts.size() && projParts.at(0)->selectedForBuilding;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
void QtTestParser::init(const QStringList &filesToParse)
 | 
			
		||||
{
 | 
			
		||||
    m_testCaseNames = TestTreeModel::instance()->testCaseNamesForFiles(filesToParse);
 | 
			
		||||
    CppParser::init(filesToParse);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool QtTestParser::processDocument(QFutureInterface<TestParseResultPtr> futureInterface,
 | 
			
		||||
                                   const QString &fileName)
 | 
			
		||||
{
 | 
			
		||||
    if (!m_cppSnapshot.contains(fileName) || !selectedForBuilding(fileName))
 | 
			
		||||
        return false;
 | 
			
		||||
    CPlusPlus::Document::Ptr doc = m_cppSnapshot.find(fileName).value();
 | 
			
		||||
    const QString &oldName = m_testCaseNames.value(fileName);
 | 
			
		||||
    if ((!includesQtTest(doc, m_cppSnapshot) || !qtTestLibDefined(fileName)) && oldName.isEmpty())
 | 
			
		||||
        return false;
 | 
			
		||||
 | 
			
		||||
    return handleQtTest(futureInterface, doc, m_cppSnapshot, oldName);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void QuickTestParser::init(const QStringList &filesToParse)
 | 
			
		||||
{
 | 
			
		||||
    m_qmlSnapshot = QmlJSTools::Internal::ModelManager::instance()->snapshot();
 | 
			
		||||
    CppParser::init(filesToParse);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool QuickTestParser::processDocument(QFutureInterface<TestParseResultPtr> futureInterface,
 | 
			
		||||
                                      const QString &fileName)
 | 
			
		||||
{
 | 
			
		||||
    if (fileName.endsWith(".qml")) {
 | 
			
		||||
        QmlJS::Document::Ptr qmlJSDoc = m_qmlSnapshot.document(fileName);
 | 
			
		||||
        return checkQmlDocumentForQuickTestCode(futureInterface, qmlJSDoc);
 | 
			
		||||
    }
 | 
			
		||||
    if (!m_cppSnapshot.contains(fileName) || !selectedForBuilding(fileName))
 | 
			
		||||
        return false;
 | 
			
		||||
    CPlusPlus::Document::Ptr document = m_cppSnapshot.find(fileName).value();
 | 
			
		||||
    if (!includesQtQuickTest(document, m_cppSnapshot))
 | 
			
		||||
        return false;
 | 
			
		||||
    return handleQtQuickTest(futureInterface, document);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool GoogleTestParser::processDocument(QFutureInterface<TestParseResultPtr> futureInterface,
 | 
			
		||||
                                       const QString &fileName)
 | 
			
		||||
{
 | 
			
		||||
    if (!m_cppSnapshot.contains(fileName) || !selectedForBuilding(fileName))
 | 
			
		||||
        return false;
 | 
			
		||||
    CPlusPlus::Document::Ptr document = m_cppSnapshot.find(fileName).value();
 | 
			
		||||
    if (!includesGTest(document, m_cppSnapshot) || !hasGTestNames(document))
 | 
			
		||||
        return false;
 | 
			
		||||
    return handleGTest(futureInterface, document, m_cppSnapshot);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
} // namespace Internal
 | 
			
		||||
} // namespace Autotest
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user