2016-05-11 13:02:42 +02:00
|
|
|
/****************************************************************************
|
|
|
|
|
**
|
|
|
|
|
** Copyright (C) 2016 The Qt Company Ltd.
|
|
|
|
|
** Contact: https://www.qt.io/licensing/
|
|
|
|
|
**
|
|
|
|
|
** This file is part of Qt Creator.
|
|
|
|
|
**
|
|
|
|
|
** Commercial License Usage
|
|
|
|
|
** Licensees holding valid commercial Qt licenses may use this file in
|
|
|
|
|
** accordance with the commercial license agreement provided with the
|
|
|
|
|
** Software or, alternatively, in accordance with the terms contained in
|
|
|
|
|
** a written agreement between you and The Qt Company. For licensing terms
|
|
|
|
|
** and conditions see https://www.qt.io/terms-conditions. For further
|
|
|
|
|
** information use the contact form at https://www.qt.io/contact-us.
|
|
|
|
|
**
|
|
|
|
|
** GNU General Public License Usage
|
|
|
|
|
** Alternatively, this file may be used under the terms of the GNU
|
|
|
|
|
** General Public License version 3 as published by the Free Software
|
|
|
|
|
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
|
|
|
|
|
** included in the packaging of this file. Please review the following
|
|
|
|
|
** information to ensure the GNU General Public License requirements will
|
|
|
|
|
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
|
|
|
|
|
**
|
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
|
|
#include "quicktestparser.h"
|
2022-07-13 18:31:56 +02:00
|
|
|
|
2016-05-11 13:02:42 +02:00
|
|
|
#include "quicktesttreeitem.h"
|
|
|
|
|
#include "quicktestvisitors.h"
|
|
|
|
|
#include "quicktest_utils.h"
|
2017-03-06 15:24:16 +01:00
|
|
|
#include "../testcodeparser.h"
|
2020-10-09 13:07:55 +02:00
|
|
|
#include "../testtreemodel.h"
|
2016-05-11 13:02:42 +02:00
|
|
|
|
2021-08-30 10:58:08 +02:00
|
|
|
#include <cppeditor/cppmodelmanager.h>
|
|
|
|
|
#include <cppeditor/projectpart.h>
|
2017-03-06 15:24:16 +01:00
|
|
|
#include <projectexplorer/session.h>
|
2016-05-11 13:02:42 +02:00
|
|
|
#include <qmljs/parser/qmljsast_p.h>
|
|
|
|
|
#include <qmljs/qmljsdialect.h>
|
|
|
|
|
#include <qmljstools/qmljsmodelmanager.h>
|
|
|
|
|
#include <utils/hostosinfo.h>
|
2017-06-01 11:57:57 +02:00
|
|
|
#include <utils/algorithm.h>
|
2016-05-11 13:02:42 +02:00
|
|
|
#include <utils/qtcassert.h>
|
|
|
|
|
|
2019-08-19 14:46:20 +02:00
|
|
|
using namespace QmlJS;
|
|
|
|
|
|
2016-05-11 13:02:42 +02:00
|
|
|
namespace Autotest {
|
|
|
|
|
namespace Internal {
|
|
|
|
|
|
|
|
|
|
TestTreeItem *QuickTestParseResult::createTestTreeItem() const
|
|
|
|
|
{
|
|
|
|
|
if (itemType == TestTreeItem::Root || itemType == TestTreeItem::TestDataTag)
|
2017-01-05 12:03:42 +01:00
|
|
|
return nullptr;
|
|
|
|
|
|
2021-01-25 16:31:16 +01:00
|
|
|
QuickTestTreeItem *item = new QuickTestTreeItem(framework, name, fileName, itemType);
|
2017-01-05 12:03:42 +01:00
|
|
|
item->setProFile(proFile);
|
|
|
|
|
item->setLine(line);
|
|
|
|
|
item->setColumn(column);
|
2017-02-13 10:05:06 +01:00
|
|
|
for (const TestParseResult *funcResult : children)
|
2017-01-05 12:03:42 +01:00
|
|
|
item->appendChild(funcResult->createTestTreeItem());
|
|
|
|
|
return item;
|
2016-05-11 13:02:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static bool includesQtQuickTest(const CPlusPlus::Document::Ptr &doc,
|
|
|
|
|
const CPlusPlus::Snapshot &snapshot)
|
|
|
|
|
{
|
|
|
|
|
static QStringList expectedHeaderPrefixes
|
|
|
|
|
= Utils::HostOsInfo::isMacHost()
|
2017-02-22 15:09:35 +01:00
|
|
|
? QStringList({"QtQuickTest.framework/Headers", "QtQuickTest"})
|
|
|
|
|
: QStringList({"QtQuickTest"});
|
2016-05-11 13:02:42 +02:00
|
|
|
|
|
|
|
|
const QList<CPlusPlus::Document::Include> includes = doc->resolvedIncludes();
|
|
|
|
|
|
2017-02-13 10:05:06 +01:00
|
|
|
for (const CPlusPlus::Document::Include &inc : includes) {
|
2016-09-29 12:15:43 +02:00
|
|
|
if (inc.unresolvedFileName() == "QtQuickTest/quicktest.h") {
|
2017-02-13 10:05:06 +01:00
|
|
|
for (const QString &prefix : expectedHeaderPrefixes) {
|
2016-05-11 13:02:42 +02:00
|
|
|
if (inc.resolvedFileName().endsWith(
|
2016-09-29 12:15:43 +02:00
|
|
|
QString("%1/quicktest.h").arg(prefix))) {
|
2016-05-11 13:02:42 +02:00
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2017-02-13 10:05:06 +01:00
|
|
|
for (const QString &include : snapshot.allIncludesForDocument(doc->fileName())) {
|
|
|
|
|
for (const QString &prefix : expectedHeaderPrefixes) {
|
2016-09-29 12:15:43 +02:00
|
|
|
if (include.endsWith(QString("%1/quicktest.h").arg(prefix)))
|
2016-05-11 13:02:42 +02:00
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
}
|
2021-06-04 14:28:03 +02:00
|
|
|
|
|
|
|
|
for (const QString &prefix : expectedHeaderPrefixes) {
|
|
|
|
|
if (CppParser::precompiledHeaderContains(snapshot,
|
|
|
|
|
Utils::FilePath::fromString(doc->fileName()),
|
|
|
|
|
QString("%1/quicktest.h").arg(prefix))) {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
}
|
2016-05-11 13:02:42 +02:00
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2021-08-30 10:58:08 +02:00
|
|
|
static QString quickTestSrcDir(const CppEditor::CppModelManager *cppMM,
|
2021-05-26 15:50:03 +02:00
|
|
|
const Utils::FilePath &fileName)
|
2016-05-11 13:02:42 +02:00
|
|
|
{
|
2021-08-30 10:58:08 +02:00
|
|
|
const QList<CppEditor::ProjectPart::ConstPtr> parts = cppMM->projectPart(fileName);
|
2016-05-11 13:02:42 +02:00
|
|
|
if (parts.size() > 0) {
|
2017-02-07 15:00:38 +01:00
|
|
|
const ProjectExplorer::Macros ¯os = parts.at(0)->projectMacros;
|
|
|
|
|
auto found = std::find_if(
|
2020-11-18 13:06:55 +01:00
|
|
|
macros.cbegin(),
|
|
|
|
|
macros.cend(),
|
2017-02-07 15:00:38 +01:00
|
|
|
[] (const ProjectExplorer::Macro ¯o) { return macro.key == "QUICK_TEST_SOURCE_DIR"; });
|
2020-11-18 13:06:55 +01:00
|
|
|
if (found != macros.cend()) {
|
2017-02-07 15:00:38 +01:00
|
|
|
QByteArray result = found->value;
|
|
|
|
|
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);
|
|
|
|
|
}
|
2016-05-11 13:02:42 +02:00
|
|
|
}
|
|
|
|
|
return QString();
|
|
|
|
|
}
|
|
|
|
|
|
2021-01-01 19:19:10 +01:00
|
|
|
QString QuickTestParser::quickTestName(const CPlusPlus::Document::Ptr &doc) const
|
2016-05-11 13:02:42 +02:00
|
|
|
{
|
|
|
|
|
const QList<CPlusPlus::Document::MacroUse> macros = doc->macroUses();
|
2021-06-04 14:28:03 +02:00
|
|
|
const Utils::FilePath filePath = Utils::FilePath::fromString(doc->fileName());
|
2016-05-11 13:02:42 +02:00
|
|
|
|
2017-02-13 10:05:06 +01:00
|
|
|
for (const CPlusPlus::Document::MacroUse ¯o : macros) {
|
2022-07-27 15:34:49 +02:00
|
|
|
if (!macro.isFunctionLike() || macro.arguments().isEmpty())
|
2016-05-11 13:02:42 +02:00
|
|
|
continue;
|
|
|
|
|
const QByteArray name = macro.macro().name();
|
|
|
|
|
if (QuickTestUtils::isQuickTestMacro(name)) {
|
|
|
|
|
CPlusPlus::Document::Block arg = macro.arguments().at(0);
|
2021-06-04 14:28:03 +02:00
|
|
|
return QLatin1String(getFileContent(filePath)
|
2018-07-11 15:44:51 +02:00
|
|
|
.mid(int(arg.bytesBegin()), int(arg.bytesEnd() - arg.bytesBegin())));
|
2016-05-11 13:02:42 +02:00
|
|
|
}
|
|
|
|
|
}
|
2018-07-09 10:43:31 +02:00
|
|
|
|
2021-06-04 14:28:03 +02:00
|
|
|
|
2022-07-29 12:35:38 +02:00
|
|
|
const QByteArray fileContent = getFileContent(filePath);
|
2018-07-09 10:43:31 +02:00
|
|
|
// check for using quick_test_main() directly
|
2021-06-04 14:28:03 +02:00
|
|
|
CPlusPlus::Document::Ptr document = m_cppSnapshot.preprocessedDocument(fileContent, filePath);
|
2018-07-09 10:43:31 +02:00
|
|
|
if (document.isNull())
|
|
|
|
|
return QString();
|
|
|
|
|
document->check();
|
|
|
|
|
CPlusPlus::AST *ast = document->translationUnit()->ast();
|
2021-01-01 19:19:10 +01:00
|
|
|
QuickTestAstVisitor astVisitor(document, m_cppSnapshot);
|
2018-07-09 10:43:31 +02:00
|
|
|
astVisitor.accept(ast);
|
2021-06-04 14:28:03 +02:00
|
|
|
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 {};
|
2016-05-11 13:02:42 +02:00
|
|
|
}
|
|
|
|
|
|
2022-06-20 12:35:13 +02:00
|
|
|
QList<Document::Ptr> QuickTestParser::scanDirectoryForQuickTestQmlFiles(const Utils::FilePath &srcDir)
|
2016-05-11 13:02:42 +02:00
|
|
|
{
|
2022-06-20 12:35:13 +02:00
|
|
|
Utils::FilePaths dirs({srcDir});
|
|
|
|
|
QStringList dirsStr({srcDir.toString()});
|
2019-08-19 14:46:20 +02:00
|
|
|
ModelManagerInterface *qmlJsMM = QmlJSTools::Internal::ModelManager::instance();
|
2016-05-11 13:02:42 +02:00
|
|
|
// make sure even files not listed in pro file are available inside the snapshot
|
|
|
|
|
QFutureInterface<void> future;
|
2019-08-19 14:46:20 +02:00
|
|
|
PathsAndLanguages paths;
|
2022-06-20 12:35:13 +02:00
|
|
|
paths.maybeInsert(srcDir, Dialect::Qml);
|
2020-11-18 22:42:51 +01:00
|
|
|
ModelManagerInterface::importScan(future, ModelManagerInterface::workingCopy(), paths, qmlJsMM,
|
2017-03-07 15:49:02 +01:00
|
|
|
false /*emitDocumentChanges*/, false /*onlyTheLib*/, true /*forceRescan*/ );
|
2016-05-11 13:02:42 +02:00
|
|
|
|
2019-08-19 14:46:20 +02:00
|
|
|
const Snapshot snapshot = QmlJSTools::Internal::ModelManager::instance()->snapshot();
|
2022-06-20 12:35:13 +02:00
|
|
|
|
|
|
|
|
QDirIterator it(srcDir.toString(),
|
|
|
|
|
QDir::Dirs | QDir::NoDotAndDotDot,
|
|
|
|
|
QDirIterator::Subdirectories);
|
2016-05-11 13:02:42 +02:00
|
|
|
while (it.hasNext()) {
|
|
|
|
|
it.next();
|
2022-06-20 12:35:13 +02:00
|
|
|
auto subDir = Utils::FilePath::fromFileInfo(it.fileInfo()).canonicalPath();
|
|
|
|
|
dirs.append(subDir);
|
|
|
|
|
dirsStr.append(subDir.toString());
|
2016-05-11 13:02:42 +02:00
|
|
|
}
|
2022-06-20 12:35:13 +02:00
|
|
|
QMetaObject::invokeMethod(
|
|
|
|
|
this,
|
|
|
|
|
[this, dirsStr] { QuickTestParser::doUpdateWatchPaths(dirsStr); },
|
|
|
|
|
Qt::QueuedConnection);
|
2017-03-06 15:24:16 +01:00
|
|
|
|
2019-08-19 14:46:20 +02:00
|
|
|
QList<Document::Ptr> foundDocs;
|
2016-05-11 13:02:42 +02:00
|
|
|
|
2022-06-20 12:35:13 +02:00
|
|
|
for (const Utils::FilePath &path : qAsConst(dirs)) {
|
2019-08-19 14:46:20 +02:00
|
|
|
const QList<Document::Ptr> docs = snapshot.documentsInDirectory(path);
|
|
|
|
|
for (const Document::Ptr &doc : docs) {
|
2022-06-20 12:35:13 +02:00
|
|
|
Utils::FilePath fi = doc->fileName();
|
|
|
|
|
//const QFileInfo fi(doc->fileName());
|
2017-03-06 15:18:07 +01:00
|
|
|
// using working copy above might provide no more existing files
|
|
|
|
|
if (!fi.exists())
|
|
|
|
|
continue;
|
2022-06-20 12:35:13 +02:00
|
|
|
const QString fileName = fi.fileName();
|
2016-09-29 12:15:43 +02:00
|
|
|
if (fileName.startsWith("tst_") && fileName.endsWith(".qml"))
|
2016-05-11 13:02:42 +02:00
|
|
|
foundDocs << doc;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return foundDocs;
|
|
|
|
|
}
|
|
|
|
|
|
2021-08-27 09:59:07 +02:00
|
|
|
static bool checkQmlDocumentForQuickTestCode(QFutureInterface<TestParseResultPtr> &futureInterface,
|
2019-08-19 14:46:20 +02:00
|
|
|
const Document::Ptr &qmlJSDoc,
|
2020-03-13 13:54:33 +01:00
|
|
|
ITestFramework *framework,
|
2021-05-26 15:50:03 +02:00
|
|
|
const Utils::FilePath &proFile = Utils::FilePath())
|
2016-05-11 13:02:42 +02:00
|
|
|
{
|
|
|
|
|
if (qmlJSDoc.isNull())
|
|
|
|
|
return false;
|
2019-08-19 14:46:20 +02:00
|
|
|
AST::Node *ast = qmlJSDoc->ast();
|
2016-05-11 13:02:42 +02:00
|
|
|
QTC_ASSERT(ast, return false);
|
2019-08-19 14:46:20 +02:00
|
|
|
Snapshot snapshot = ModelManagerInterface::instance()->snapshot();
|
2017-02-27 09:30:16 +01:00
|
|
|
TestQmlVisitor qmlVisitor(qmlJSDoc, snapshot);
|
2019-08-19 14:46:20 +02:00
|
|
|
AST::Node::accept(ast, &qmlVisitor);
|
2017-02-27 09:30:16 +01:00
|
|
|
if (!qmlVisitor.isValid())
|
|
|
|
|
return false;
|
2016-05-11 13:02:42 +02:00
|
|
|
|
2019-07-30 13:17:35 +02:00
|
|
|
const QVector<QuickTestCaseSpec> &testCases = qmlVisitor.testCases();
|
2019-07-26 08:28:17 +02:00
|
|
|
|
2019-07-30 13:17:35 +02:00
|
|
|
for (const QuickTestCaseSpec &testCase : testCases) {
|
|
|
|
|
const QString testCaseName = testCase.m_caseName;
|
2019-07-26 08:28:17 +02:00
|
|
|
|
2020-03-13 13:54:33 +01:00
|
|
|
QuickTestParseResult *parseResult = new QuickTestParseResult(framework);
|
2019-07-26 08:28:17 +02:00
|
|
|
parseResult->proFile = proFile;
|
|
|
|
|
parseResult->itemType = TestTreeItem::TestCase;
|
|
|
|
|
if (!testCaseName.isEmpty()) {
|
2021-06-16 16:06:34 +02:00
|
|
|
parseResult->fileName = testCase.m_locationAndType.m_filePath;
|
2019-07-26 08:28:17 +02:00
|
|
|
parseResult->name = testCaseName;
|
2019-07-30 13:17:35 +02:00
|
|
|
parseResult->line = testCase.m_locationAndType.m_line;
|
|
|
|
|
parseResult->column = testCase.m_locationAndType.m_column;
|
2019-07-26 08:28:17 +02:00
|
|
|
}
|
|
|
|
|
|
2020-06-11 16:53:11 +02:00
|
|
|
for (const auto &function : testCase.m_functions) {
|
2020-03-13 13:54:33 +01:00
|
|
|
QuickTestParseResult *funcResult = new QuickTestParseResult(framework);
|
2021-06-16 16:06:34 +02:00
|
|
|
funcResult->name = function.m_name;
|
|
|
|
|
funcResult->displayName = function.m_name;
|
|
|
|
|
funcResult->itemType = function.m_type;
|
|
|
|
|
funcResult->fileName = function.m_filePath;
|
|
|
|
|
funcResult->line = function.m_line;
|
|
|
|
|
funcResult->column = function.m_column;
|
2019-07-30 13:17:35 +02:00
|
|
|
funcResult->proFile = proFile;
|
|
|
|
|
|
|
|
|
|
parseResult->children.append(funcResult);
|
|
|
|
|
}
|
2019-07-26 08:28:17 +02:00
|
|
|
|
|
|
|
|
futureInterface.reportResult(TestParseResultPtr(parseResult));
|
2016-05-11 13:02:42 +02:00
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2021-08-27 09:59:07 +02:00
|
|
|
bool QuickTestParser::handleQtQuickTest(QFutureInterface<TestParseResultPtr> &futureInterface,
|
2017-03-20 15:42:08 +01:00
|
|
|
CPlusPlus::Document::Ptr document,
|
2020-03-13 13:54:33 +01:00
|
|
|
ITestFramework *framework)
|
2016-05-11 13:02:42 +02:00
|
|
|
{
|
2021-08-30 10:58:08 +02:00
|
|
|
const CppEditor::CppModelManager *modelManager = CppEditor::CppModelManager::instance();
|
2021-01-01 19:19:10 +01:00
|
|
|
if (quickTestName(document).isEmpty())
|
2016-05-11 13:02:42 +02:00
|
|
|
return false;
|
|
|
|
|
|
2021-08-30 10:58:08 +02:00
|
|
|
QList<CppEditor::ProjectPart::ConstPtr> ppList = modelManager->projectPart(document->fileName());
|
2016-07-08 12:53:57 +02:00
|
|
|
if (ppList.isEmpty()) // happens if shutting down while parsing
|
|
|
|
|
return false;
|
2021-05-26 15:50:03 +02:00
|
|
|
const Utils::FilePath cppFileName = Utils::FilePath::fromString(document->fileName());
|
|
|
|
|
const Utils::FilePath proFile = Utils::FilePath::fromString(ppList.at(0)->projectFile);
|
2018-07-10 14:47:40 +02:00
|
|
|
m_mainCppFiles.insert(cppFileName, proFile);
|
2022-06-20 12:35:13 +02:00
|
|
|
const Utils::FilePath srcDir = Utils::FilePath::fromString(
|
|
|
|
|
quickTestSrcDir(modelManager, cppFileName));
|
2016-05-11 13:02:42 +02:00
|
|
|
if (srcDir.isEmpty())
|
|
|
|
|
return false;
|
|
|
|
|
|
2017-03-20 15:42:08 +01:00
|
|
|
if (futureInterface.isCanceled())
|
|
|
|
|
return false;
|
2019-08-19 14:46:20 +02:00
|
|
|
const QList<Document::Ptr> qmlDocs = scanDirectoryForQuickTestQmlFiles(srcDir);
|
2016-05-11 13:02:42 +02:00
|
|
|
bool result = false;
|
2019-08-19 14:46:20 +02:00
|
|
|
for (const Document::Ptr &qmlJSDoc : qmlDocs) {
|
2017-03-20 15:42:08 +01:00
|
|
|
if (futureInterface.isCanceled())
|
|
|
|
|
break;
|
2020-03-13 13:54:33 +01:00
|
|
|
result |= checkQmlDocumentForQuickTestCode(futureInterface, qmlJSDoc, framework, proFile);
|
2017-03-20 15:42:08 +01:00
|
|
|
}
|
2016-05-11 13:02:42 +02:00
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
2017-06-01 11:57:57 +02:00
|
|
|
static QMap<QString, QDateTime> qmlFilesWithMTime(const QString &directory)
|
|
|
|
|
{
|
|
|
|
|
const QFileInfoList &qmlFiles = QDir(directory).entryInfoList({ "*.qml" },
|
|
|
|
|
QDir::Files, QDir::Name);
|
|
|
|
|
QMap<QString, QDateTime> filesAndDates;
|
|
|
|
|
for (const QFileInfo &info : qmlFiles)
|
|
|
|
|
filesAndDates.insert(info.fileName(), info.lastModified());
|
|
|
|
|
return filesAndDates;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void QuickTestParser::handleDirectoryChanged(const QString &directory)
|
|
|
|
|
{
|
|
|
|
|
const QMap<QString, QDateTime> &filesAndDates = qmlFilesWithMTime(directory);
|
|
|
|
|
const QMap<QString, QDateTime> &watched = m_watchedFiles.value(directory);
|
2020-04-29 10:32:56 +02:00
|
|
|
const QList<QString> &keys = watched.keys();
|
2017-06-01 11:57:57 +02:00
|
|
|
if (filesAndDates.keys() != keys) { // removed or added files
|
|
|
|
|
m_watchedFiles[directory] = filesAndDates;
|
|
|
|
|
TestTreeModel::instance()->parser()->emitUpdateTestTree(this);
|
|
|
|
|
} else { // we might still have different timestamps
|
|
|
|
|
const bool timestampChanged = Utils::anyOf(keys, [&](const QString &file) {
|
|
|
|
|
return filesAndDates.value(file) != watched.value(file);
|
|
|
|
|
});
|
|
|
|
|
if (timestampChanged) {
|
2021-09-02 09:41:24 +02:00
|
|
|
m_watchedFiles[directory] = filesAndDates;
|
2019-08-19 14:46:20 +02:00
|
|
|
PathsAndLanguages paths;
|
|
|
|
|
paths.maybeInsert(Utils::FilePath::fromString(directory), Dialect::Qml);
|
2017-06-01 11:57:57 +02:00
|
|
|
QFutureInterface<void> future;
|
2019-08-19 14:46:20 +02:00
|
|
|
ModelManagerInterface *qmlJsMM = ModelManagerInterface::instance();
|
2020-11-18 22:42:51 +01:00
|
|
|
ModelManagerInterface::importScan(future, ModelManagerInterface::workingCopy(), paths,
|
|
|
|
|
qmlJsMM,
|
2019-08-19 14:46:20 +02:00
|
|
|
true /*emitDocumentChanges*/,
|
|
|
|
|
false /*onlyTheLib*/,
|
|
|
|
|
true /*forceRescan*/ );
|
2017-06-01 11:57:57 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void QuickTestParser::doUpdateWatchPaths(const QStringList &directories)
|
|
|
|
|
{
|
|
|
|
|
for (const QString &dir : directories) {
|
|
|
|
|
m_directoryWatcher.addPath(dir);
|
|
|
|
|
m_watchedFiles[dir] = qmlFilesWithMTime(dir);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-03-13 13:54:33 +01:00
|
|
|
QuickTestParser::QuickTestParser(ITestFramework *framework)
|
|
|
|
|
: CppParser(framework)
|
2017-03-06 15:24:16 +01:00
|
|
|
{
|
2017-03-20 15:42:08 +01:00
|
|
|
connect(ProjectExplorer::SessionManager::instance(),
|
|
|
|
|
&ProjectExplorer::SessionManager::startupProjectChanged, [this] {
|
|
|
|
|
const QStringList &dirs = m_directoryWatcher.directories();
|
2017-03-06 15:24:16 +01:00
|
|
|
if (!dirs.isEmpty())
|
2017-03-20 15:42:08 +01:00
|
|
|
m_directoryWatcher.removePaths(dirs);
|
2017-06-01 11:57:57 +02:00
|
|
|
m_watchedFiles.clear();
|
2017-03-06 15:24:16 +01:00
|
|
|
});
|
2017-03-20 15:42:08 +01:00
|
|
|
connect(&m_directoryWatcher, &QFileSystemWatcher::directoryChanged,
|
2017-06-01 11:57:57 +02:00
|
|
|
this, &QuickTestParser::handleDirectoryChanged);
|
2017-03-06 15:24:16 +01:00
|
|
|
}
|
|
|
|
|
|
2021-05-26 15:50:03 +02:00
|
|
|
void QuickTestParser::init(const Utils::FilePaths &filesToParse, bool fullParse)
|
2016-05-11 13:02:42 +02:00
|
|
|
{
|
|
|
|
|
m_qmlSnapshot = QmlJSTools::Internal::ModelManager::instance()->snapshot();
|
2018-07-10 14:47:40 +02:00
|
|
|
if (!fullParse) {
|
|
|
|
|
// in a full parse we get the correct entry points by the respective main
|
2020-03-13 13:54:33 +01:00
|
|
|
m_proFilesForQmlFiles = QuickTestUtils::proFilesForQmlFiles(framework(), filesToParse);
|
2018-07-10 14:47:40 +02:00
|
|
|
// get rid of cached main cpp files that are going to get processed anyhow
|
2021-05-26 15:50:03 +02:00
|
|
|
for (const Utils::FilePath &file : filesToParse) {
|
2018-07-10 14:47:40 +02:00
|
|
|
if (m_mainCppFiles.contains(file)) {
|
|
|
|
|
m_mainCppFiles.remove(file);
|
|
|
|
|
if (m_mainCppFiles.isEmpty())
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
// get rid of all cached main cpp files
|
|
|
|
|
m_mainCppFiles.clear();
|
|
|
|
|
}
|
2018-01-08 15:14:33 +01:00
|
|
|
CppParser::init(filesToParse, fullParse);
|
2016-05-11 13:02:42 +02:00
|
|
|
}
|
|
|
|
|
|
2016-07-12 10:35:43 +02:00
|
|
|
void QuickTestParser::release()
|
|
|
|
|
{
|
2019-08-19 14:46:20 +02:00
|
|
|
m_qmlSnapshot = Snapshot();
|
2016-07-12 10:35:43 +02:00
|
|
|
m_proFilesForQmlFiles.clear();
|
|
|
|
|
CppParser::release();
|
|
|
|
|
}
|
|
|
|
|
|
2021-08-27 09:59:07 +02:00
|
|
|
bool QuickTestParser::processDocument(QFutureInterface<TestParseResultPtr> &futureInterface,
|
2021-05-26 15:50:03 +02:00
|
|
|
const Utils::FilePath &fileName)
|
2016-05-11 13:02:42 +02:00
|
|
|
{
|
|
|
|
|
if (fileName.endsWith(".qml")) {
|
2021-05-26 15:50:03 +02:00
|
|
|
const Utils::FilePath &proFile = m_proFilesForQmlFiles.value(fileName);
|
2016-07-12 09:45:55 +02:00
|
|
|
if (proFile.isEmpty())
|
|
|
|
|
return false;
|
2022-06-20 12:35:13 +02:00
|
|
|
Document::Ptr qmlJSDoc = m_qmlSnapshot.document(fileName);
|
2020-03-13 13:54:33 +01:00
|
|
|
return checkQmlDocumentForQuickTestCode(futureInterface, qmlJSDoc, framework(), proFile);
|
2016-05-11 13:02:42 +02:00
|
|
|
}
|
|
|
|
|
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;
|
2020-03-13 13:54:33 +01:00
|
|
|
return handleQtQuickTest(futureInterface, document, framework());
|
2016-05-11 13:02:42 +02:00
|
|
|
}
|
|
|
|
|
|
2021-05-26 15:50:03 +02:00
|
|
|
Utils::FilePath QuickTestParser::projectFileForMainCppFile(const Utils::FilePath &fileName) const
|
2018-07-10 14:47:40 +02:00
|
|
|
{
|
2021-05-26 15:50:03 +02:00
|
|
|
return m_mainCppFiles.contains(fileName) ? m_mainCppFiles.value(fileName) : Utils::FilePath();
|
2018-07-10 14:47:40 +02:00
|
|
|
}
|
|
|
|
|
|
2016-05-11 13:02:42 +02:00
|
|
|
} // namespace Internal
|
|
|
|
|
} // namespace Autotest
|