diff options
22 files changed, 362 insertions, 146 deletions
diff --git a/plugins/autotest/autotest.qbs b/plugins/autotest/autotest.qbs index 4a9ec9e4c8..f746d7fae1 100644 --- a/plugins/autotest/autotest.qbs +++ b/plugins/autotest/autotest.qbs @@ -7,11 +7,15 @@ QtcCommercialPlugin { Depends { name: "CppTools" } Depends { name: "CPlusPlus" } Depends { name: "ProjectExplorer" } - Depends { name: "QmakeProjectManager" } Depends { name: "QmlJS" } Depends { name: "QmlJSTools" } Depends { name: "Utils" } + pluginTestDepends: [ + "QbsProjectManager", + "QmakeProjectManager" + ] + Depends { name: "QtSupport" condition: project.testsEnabled diff --git a/plugins/autotest/autotest_dependencies.pri b/plugins/autotest/autotest_dependencies.pri index 74dc51e15b..9410d77950 100644 --- a/plugins/autotest/autotest_dependencies.pri +++ b/plugins/autotest/autotest_dependencies.pri @@ -4,8 +4,7 @@ QTC_PLUGIN_DEPENDS += \ coreplugin \ projectexplorer \ cpptools \ - qmljstools \ - qmakeprojectmanager + qmljstools CONFIG(licensechecker): QTC_PLUGIN_DEPENDS += licensechecker @@ -14,4 +13,9 @@ QTC_LIB_DEPENDS += \ qmljs \ utils +QTC_TEST_DEPENDS += \ + qbsprojectmanager \ + qmakeprojectmanager \ + qtsupport + #QTC_PLUGIN_RECOMMENDS += \ diff --git a/plugins/autotest/autotestunittests.cpp b/plugins/autotest/autotestunittests.cpp index 15f32db669..8878f75418 100644 --- a/plugins/autotest/autotestunittests.cpp +++ b/plugins/autotest/autotestunittests.cpp @@ -117,6 +117,66 @@ void AutoTestUnitTests::testCodeParser_data() QTest::newRow("mixedAutoTestAndQuickTests") << QString(m_tmpDir->path() + QLatin1String("/mixed_atp/mixed_atp.pro")) << 3 << 5 << 3; + QTest::newRow("plainAutoTestQbs") + << QString(m_tmpDir->path() + QLatin1String("/plain/plain.qbs")) + << 1 << 0 << 0; + QTest::newRow("mixedAuotTestAndQuickTestsQbs") + << QString(m_tmpDir->path() + QLatin1String("/mixed_atp/mixed_atp.qbs")) + << 3 << 5 << 3; +} + +void AutoTestUnitTests::testCodeParserSwitchStartup() +{ + QFETCH(QStringList, projectFilePaths); + QFETCH(QList<int>, expectedAutoTestsCount); + QFETCH(QList<int>, expectedNamedQuickTestsCount); + QFETCH(QList<int>, expectedUnnamedQuickTestsCount); + + NavigationWidget *navigation = NavigationWidget::instance(); + navigation->activateSubWidget(Constants::AUTOTEST_ID); + + CppTools::Tests::ProjectOpenerAndCloser projectManager; + for (int i = 0; i < projectFilePaths.size(); ++i) { + qDebug() << "Opening project" << projectFilePaths.at(i); + CppTools::ProjectInfo projectInfo = projectManager.open(projectFilePaths.at(i), true); + QVERIFY(projectInfo.isValid()); + + QSignalSpy parserSpy(m_model->parser(), SIGNAL(parsingFinished())); + QVERIFY(parserSpy.wait(20000)); + + QCOMPARE(m_model->autoTestsCount(), expectedAutoTestsCount.at(i)); + QCOMPARE(m_model->namedQuickTestsCount(), + m_isQt4 ? 0 : expectedNamedQuickTestsCount.at(i)); + QCOMPARE(m_model->unnamedQuickTestsCount(), + m_isQt4 ? 0 : expectedUnnamedQuickTestsCount.at(i)); + + QCOMPARE(m_model->parser()->autoTestsCount(), expectedAutoTestsCount.at(i)); + QCOMPARE(m_model->parser()->namedQuickTestsCount(), + m_isQt4 ? 0 : expectedNamedQuickTestsCount.at(i)); + QCOMPARE(m_model->parser()->unnamedQuickTestsCount(), + m_isQt4 ? 0 : expectedUnnamedQuickTestsCount.at(i)); + } +} + +void AutoTestUnitTests::testCodeParserSwitchStartup_data() +{ + QTest::addColumn<QStringList>("projectFilePaths"); + QTest::addColumn<QList<int> >("expectedAutoTestsCount"); + QTest::addColumn<QList<int> >("expectedNamedQuickTestsCount"); + QTest::addColumn<QList<int> >("expectedUnnamedQuickTestsCount"); + + QStringList projects = QStringList() + << QString(m_tmpDir->path() + QLatin1String("/plain/plain.pro")) + << QString(m_tmpDir->path() + QLatin1String("/mixed_atp/mixed_atp.pro")) + << QString(m_tmpDir->path() + QLatin1String("/plain/plain.qbs")) + << QString(m_tmpDir->path() + QLatin1String("/mixed_atp/mixed_atp.qbs")); + + QList<int> expectedAutoTests = QList<int>() << 1 << 3 << 1 << 3; + QList<int> expectedNamedQuickTests = QList<int>() << 0 << 5 << 0 << 5; + QList<int> expectedUnnamedQuickTests = QList<int>() << 0 << 3 << 0 << 3; + + QTest::newRow("loadMultipleProjects") + << projects << expectedAutoTests << expectedNamedQuickTests << expectedUnnamedQuickTests; } } // namespace Internal diff --git a/plugins/autotest/autotestunittests.h b/plugins/autotest/autotestunittests.h index ab2b7c1b9b..e359e4175d 100644 --- a/plugins/autotest/autotestunittests.h +++ b/plugins/autotest/autotestunittests.h @@ -43,6 +43,8 @@ private slots: void cleanupTestCase(); void testCodeParser(); void testCodeParser_data(); + void testCodeParserSwitchStartup(); + void testCodeParserSwitchStartup_data(); private: TestTreeModel *m_model; diff --git a/plugins/autotest/autotestunittests.qrc b/plugins/autotest/autotestunittests.qrc index 6fb5348e54..25ce4044fe 100644 --- a/plugins/autotest/autotestunittests.qrc +++ b/plugins/autotest/autotestunittests.qrc @@ -28,5 +28,16 @@ <file>unit_test/mixed_atp/tests/auto/quickauto/quickauto.pro</file> <file>unit_test/mixed_atp/tests/auto/quickauto2/quickauto2.pro</file> <file>unit_test/mixed_atp/tests/auto/auto.pro</file> + <file>unit_test/plain/plain.qbs</file> + <file>unit_test/plain/test_plain/test_plain.qbs</file> + <file>unit_test/mixed_atp/mixed_atp.qbs</file> + <file>unit_test/mixed_atp/src/src.qbs</file> + <file>unit_test/mixed_atp/tests/tests.qbs</file> + <file>unit_test/mixed_atp/tests/auto/auto.qbs</file> + <file>unit_test/mixed_atp/tests/auto/bench/bench.qbs</file> + <file>unit_test/mixed_atp/tests/auto/dummy/dummy.qbs</file> + <file>unit_test/mixed_atp/tests/auto/gui/gui.qbs</file> + <file>unit_test/mixed_atp/tests/auto/quickauto/quickauto.qbs</file> + <file>unit_test/mixed_atp/tests/auto/quickauto2/quickauto2.qbs</file> </qresource> </RCC> diff --git a/plugins/autotest/testcodeparser.cpp b/plugins/autotest/testcodeparser.cpp index 004f733fbd..d01fb3140f 100644 --- a/plugins/autotest/testcodeparser.cpp +++ b/plugins/autotest/testcodeparser.cpp @@ -33,11 +33,9 @@ #include <cpptools/cppmodelmanager.h> #include <cpptools/cppworkingcopy.h> +#include <projectexplorer/project.h> #include <projectexplorer/session.h> -#include <qmakeprojectmanager/qmakeproject.h> -#include <qmakeprojectmanager/qmakeprojectmanagerconstants.h> - #include <qmljs/parser/qmljsast_p.h> #include <qmljs/qmljsdialect.h> #include <qmljstools/qmljsmodelmanager.h> @@ -46,8 +44,13 @@ #include <utils/qtcassert.h> #include <utils/textfileformat.h> +#include <QDirIterator> #include <QFuture> #include <QFutureInterface> +#include <QLoggingCategory> +#include <QTimer> + +static Q_LOGGING_CATEGORY(LOG, "qtc.autotest.testcodeparser") namespace Autotest { namespace Internal { @@ -55,10 +58,11 @@ namespace Internal { TestCodeParser::TestCodeParser(TestTreeModel *parent) : QObject(parent), m_model(parent), - m_parserEnabled(true), + m_codeModelParsing(false), m_fullUpdatePostponed(false), m_partialUpdatePostponed(false), - m_dirty(true), + m_dirty(false), + m_singleShotScheduled(false), m_parserState(Disabled) { // connect to ProgressManager to postpone test parsing when CppModelManager is parsing @@ -76,61 +80,66 @@ TestCodeParser::~TestCodeParser() clearCache(); } -ProjectExplorer::Project *currentProject() -{ - const ProjectExplorer::SessionManager *session = ProjectExplorer::SessionManager::instance(); - if (!session || !session->hasProjects()) - return 0; - return session->startupProject(); -} - void TestCodeParser::setState(State state) { - // avoid triggering parse before code model parsing has finished - if (!m_parserEnabled) + qCDebug(LOG) << "setState(" << state << "), currentState:" << m_parserState; + // avoid triggering parse before code model parsing has finished, but mark as dirty + if (m_codeModelParsing) { + m_dirty = true; + qCDebug(LOG) << "Not setting new state - code model parsing is running, just marking dirty"; return; + } if ((state == Disabled || state == Idle) - && (m_parserState == PartialParse || m_parserState == FullParse)) + && (m_parserState == PartialParse || m_parserState == FullParse)) { + qCDebug(LOG) << "Not setting state, parse is running"; return; + } m_parserState = state; if (m_parserState == Disabled) { m_fullUpdatePostponed = m_partialUpdatePostponed = false; m_postponedFiles.clear(); - } else if (m_parserState == Idle && m_dirty && currentProject()) { - scanForTests(m_postponedFiles.toList()); + } else if (m_parserState == Idle && ProjectExplorer::SessionManager::startupProject()) { + if (m_fullUpdatePostponed || m_dirty) { + emitUpdateTestTree(); + } else if (m_partialUpdatePostponed) { + m_partialUpdatePostponed = false; + qCDebug(LOG) << "calling scanForTests with postponed files (setState)"; + scanForTests(m_postponedFiles.toList()); + } } } void TestCodeParser::emitUpdateTestTree() { + if (m_singleShotScheduled) { + qCDebug(LOG) << "not scheduling another updateTestTree"; + return; + } + + qCDebug(LOG) << "adding singleShot"; + m_singleShotScheduled = true; QTimer::singleShot(1000, this, SLOT(updateTestTree())); } void TestCodeParser::updateTestTree() { - if (!m_parserEnabled) { + m_singleShotScheduled = false; + if (m_codeModelParsing) { m_fullUpdatePostponed = true; + m_partialUpdatePostponed = false; + m_postponedFiles.clear(); return; } - if (ProjectExplorer::Project *project = currentProject()) { - if (auto qmakeProject = qobject_cast<QmakeProjectManager::QmakeProject *>(project)) { - if (qmakeProject->asyncUpdateState() != QmakeProjectManager::QmakeProject::Base) { - m_fullUpdatePostponed = true; - return; - } - connect(qmakeProject, &QmakeProjectManager::QmakeProject::proFilesEvaluated, - this, &TestCodeParser::onProFileEvaluated, Qt::UniqueConnection); - } - } else + if (!ProjectExplorer::SessionManager::startupProject()) return; m_fullUpdatePostponed = false; clearCache(); - emit cacheCleared(); + qCDebug(LOG) << "calling scanForTests (updateTestTree)"; scanForTests(); } @@ -370,6 +379,10 @@ static TestTreeItem constructTestTreeItem(const QString &fileName, /****** end of helpers ******/ +// 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; + void performParse(QFutureInterface<void> &futureInterface, QStringList list, TestCodeParser *testCodeParser) { @@ -384,6 +397,9 @@ void performParse(QFutureInterface<void> &futureInterface, QStringList list, CPlusPlus::Document::Ptr doc = snapshot.find(file).value(); futureInterface.setProgressValue(++progressValue); testCodeParser->checkDocumentForTestCode(doc); + } else { + parsingHasFailed |= (CppTools::ProjectFile::classify(file) + != CppTools::ProjectFile::Unclassified); } } futureInterface.setProgressValue(list.size()); @@ -482,7 +498,7 @@ void TestCodeParser::handleQtQuickTest(CPlusPlus::Document::Ptr document) void TestCodeParser::onCppDocumentUpdated(const CPlusPlus::Document::Ptr &document) { - if (!m_parserEnabled) { + if (m_codeModelParsing) { if (!m_fullUpdatePostponed) { m_partialUpdatePostponed = true; m_postponedFiles.insert(document->fileName()); @@ -490,7 +506,7 @@ void TestCodeParser::onCppDocumentUpdated(const CPlusPlus::Document::Ptr &docume return; } - ProjectExplorer::Project *project = currentProject(); + ProjectExplorer::Project *project = ProjectExplorer::SessionManager::startupProject(); if (!project) return; const QString fileName = document->fileName(); @@ -502,12 +518,13 @@ void TestCodeParser::onCppDocumentUpdated(const CPlusPlus::Document::Ptr &docume } else if (!project->files(ProjectExplorer::Project::AllFiles).contains(fileName)) { return; } + qCDebug(LOG) << "calling scanForTests (onCppDocumentUpdated)"; scanForTests(QStringList(fileName)); } void TestCodeParser::onQmlDocumentUpdated(const QmlJS::Document::Ptr &document) { - if (!m_parserEnabled) { + if (m_codeModelParsing) { if (!m_fullUpdatePostponed) { m_partialUpdatePostponed = true; m_postponedFiles.insert(document->fileName()); @@ -515,7 +532,7 @@ void TestCodeParser::onQmlDocumentUpdated(const QmlJS::Document::Ptr &document) return; } - ProjectExplorer::Project *project = currentProject(); + ProjectExplorer::Project *project = ProjectExplorer::SessionManager::startupProject(); if (!project) return; const QString fileName = document->fileName(); @@ -530,8 +547,11 @@ void TestCodeParser::onQmlDocumentUpdated(const QmlJS::Document::Ptr &document) const CPlusPlus::Snapshot snapshot = CppTools::CppModelManager::instance()->snapshot(); if (m_quickDocMap.contains(fileName) && snapshot.contains(m_quickDocMap[fileName].referencingFile())) { - if (!m_quickDocMap[fileName].referencingFile().isEmpty()) + if (!m_quickDocMap[fileName].referencingFile().isEmpty()) { + qCDebug(LOG) << "calling scanForTests with cached referencing files" + << "(onQmlDocumentUpdated)"; scanForTests(QStringList(m_quickDocMap[fileName].referencingFile())); + } } if (m_unnamedQuickDocList.size() == 0) return; @@ -539,15 +559,26 @@ void TestCodeParser::onQmlDocumentUpdated(const QmlJS::Document::Ptr &document) // special case of having unnamed TestCases const QString &mainFile = m_model->getMainFileForUnnamedQuickTest(fileName); if (!mainFile.isEmpty() && snapshot.contains(mainFile)) { + qCDebug(LOG) << "calling scanForTests with mainfile (onQmlDocumentUpdated)"; scanForTests(QStringList(mainFile)); } } +void TestCodeParser::onStartupProjectChanged(ProjectExplorer::Project *) +{ + if (m_parserState == FullParse || m_parserState == PartialParse) { + Core::ProgressManager::instance()->cancelTasks(Constants::TASK_PARSE); + } else { + clearCache(); + emitUpdateTestTree(); + } +} + void TestCodeParser::onProjectPartsUpdated(ProjectExplorer::Project *project) { - if (project != currentProject()) + if (project != ProjectExplorer::SessionManager::startupProject()) return; - if (!m_parserEnabled || m_parserState == Disabled) + if (m_codeModelParsing || m_parserState == Disabled) m_fullUpdatePostponed = true; else emitUpdateTestTree(); @@ -565,7 +596,8 @@ bool TestCodeParser::postponed(const QStringList &fileList) case Idle: return false; case PartialParse: - // partial is running, postponing a full parse + case FullParse: + // parse is running, postponing a full parse if (fileList.isEmpty()) { m_partialUpdatePostponed = false; m_postponedFiles.clear(); @@ -576,23 +608,6 @@ bool TestCodeParser::postponed(const QStringList &fileList) return true; // partial parse triggered, postpone or add current files to already postponed partial foreach (const QString &file, fileList) - m_postponedFiles.insert(file); - m_partialUpdatePostponed = true; - } - return true; - case FullParse: - // full parse is running, postponing another full parse - if (fileList.isEmpty()) { - m_partialUpdatePostponed = false; - m_postponedFiles.clear(); - m_fullUpdatePostponed = true; - } else { - // full parse already postponed, ignoring triggering a partial parse - if (m_fullUpdatePostponed) { - return true; - } - // partial parse triggered, postpone or add current files to already postponed partial - foreach (const QString &file, fileList) m_postponedFiles.insert(file); m_partialUpdatePostponed = true; } @@ -624,19 +639,23 @@ void TestCodeParser::scanForTests(const QStringList &fileList) if (postponed(fileList)) return; + m_postponedFiles.clear(); bool isFullParse = fileList.isEmpty(); bool isSmallChange = !isFullParse && fileList.size() < 6; QStringList list; if (isFullParse) { - list = currentProject()->files(ProjectExplorer::Project::AllFiles); + list = ProjectExplorer::SessionManager::startupProject()->files(ProjectExplorer::Project::AllFiles); if (list.isEmpty()) return; + qCDebug(LOG) << "setting state to FullParse (scanForTests)"; m_parserState = FullParse; } else { list << fileList; + qCDebug(LOG) << "setting state to PartialParse (scanForTests)"; m_parserState = PartialParse; } + parsingHasFailed = false; if (isSmallChange) { // no need to do this async or should we do this always async? CppTools::CppModelManager *cppMM = CppTools::CppModelManager::instance(); CPlusPlus::Snapshot snapshot = cppMM->snapshot(); @@ -644,9 +663,12 @@ void TestCodeParser::scanForTests(const QStringList &fileList) if (snapshot.contains(file)) { CPlusPlus::Document::Ptr doc = snapshot.find(file).value(); checkDocumentForTestCode(doc); + } else { + parsingHasFailed |= (CppTools::ProjectFile::classify(file) + != CppTools::ProjectFile::Unclassified); } } - emit onFinished(); + onFinished(); return; } @@ -666,6 +688,7 @@ void TestCodeParser::clearCache() m_cppDocMap.clear(); m_quickDocMap.clear(); m_unnamedQuickDocList.clear(); + emit cacheCleared(); } void TestCodeParser::removeTestsIfNecessary(const QString &fileName) @@ -704,39 +727,10 @@ void TestCodeParser::removeTestsIfNecessary(const QString &fileName) } } -void TestCodeParser::removeTestsIfNecessaryByProFile(const QString &proFile) -{ - QList<QString> fList; - foreach (const QString &fileName, m_cppDocMap.keys()) { - if (m_cppDocMap[fileName].proFile() == proFile) - fList.append(fileName); - } - foreach (const QString &fileName, fList) { - m_cppDocMap.remove(fileName); - emit testItemsRemoved(fileName, TestTreeModel::AutoTest); - } - fList.clear(); - foreach (const QString &fileName, m_quickDocMap.keys()) { - if (m_quickDocMap[fileName].proFile() == proFile) - fList.append(fileName); - } - foreach (const QString &fileName, fList) { - m_quickDocMap.remove(fileName); - emit testItemsRemoved(fileName, TestTreeModel::QuickTest); - } - // handle unnamed Quick Tests - const QSet<QString> &filePaths = m_model->qmlFilesForProFile(proFile); - foreach (const QString &fileName, filePaths) { - removeUnnamedQuickTestsByName(fileName); - emit unnamedQuickTestsRemoved(fileName); - } -} - void TestCodeParser::onTaskStarted(Core::Id type) { - if (type != CppTools::Constants::TASK_INDEX) - return; - m_parserEnabled = false; + if (type == CppTools::Constants::TASK_INDEX) + m_codeModelParsing = true; } void TestCodeParser::onAllTasksFinished(Core::Id type) @@ -744,35 +738,35 @@ void TestCodeParser::onAllTasksFinished(Core::Id type) // only CPP parsing is relevant as we trigger Qml parsing internally anyway if (type != CppTools::Constants::TASK_INDEX) return; - m_parserEnabled = true; + m_codeModelParsing = false; + // avoid illegal parser state if respective widgets became hidden while parsing setState(Idle); - - if (m_fullUpdatePostponed) - updateTestTree(); - else if (m_partialUpdatePostponed) { - m_partialUpdatePostponed = false; - QStringList tmp; - foreach (const QString &file, m_postponedFiles) - tmp << file; - m_postponedFiles.clear(); - scanForTests(tmp); - } } void TestCodeParser::onFinished() { switch (m_parserState) { case PartialParse: + qCDebug(LOG) << "setting state to Idle (onFinished, PartialParse)"; m_parserState = Idle; emit partialParsingFinished(); break; case FullParse: + qCDebug(LOG) << "setting state to Idle (onFinished, FullParse)"; m_parserState = Idle; - emit parsingFinished(); + m_dirty = parsingHasFailed; + if (m_partialUpdatePostponed || m_fullUpdatePostponed || parsingHasFailed) { + emit partialParsingFinished(); + } else { + qCDebug(LOG) << "emitting parsingFinished" + << "(onFinished, FullParse, nothing postponed, parsing succeeded)"; + emit parsingFinished(); + } m_dirty = false; break; case Disabled: // can happen if all Test related widgets become hidden while parsing + qCDebug(LOG) << "emitting parsingFinished (onFinished, Disabled)"; emit parsingFinished(); break; default: @@ -788,17 +782,24 @@ void TestCodeParser::onPartialParsingFinished() m_partialUpdatePostponed = false;m_postponedFiles.clear();); if (m_fullUpdatePostponed) { m_fullUpdatePostponed = false; + qCDebug(LOG) << "calling updateTestTree (onPartialParsingFinished)"; updateTestTree(); } else if (m_partialUpdatePostponed) { m_partialUpdatePostponed = false; - QStringList tmp; - foreach (const QString &file, m_postponedFiles) - tmp << file; - m_postponedFiles.clear(); - scanForTests(tmp); + qCDebug(LOG) << "calling scanForTests with postponed files (onPartialParsingFinished)"; + scanForTests(m_postponedFiles.toList()); } else { - m_dirty = false; - emit parsingFinished(); + m_dirty |= m_codeModelParsing; + if (m_dirty) { + emit parsingFailed(); + } else if (!m_singleShotScheduled) { + qCDebug(LOG) << "emitting parsingFinished" + << "(onPartialParsingFinished, nothing postponed, not dirty)"; + emit parsingFinished(); + } else { + qCDebug(LOG) << "not emitting parsingFinished" + << "(on PartialParsingFinished, singleshot scheduled)"; + } } } @@ -894,28 +895,6 @@ void TestCodeParser::removeUnnamedQuickTestsByName(const QString &fileName) } } -void TestCodeParser::onProFileEvaluated() -{ - ProjectExplorer::Project *project = currentProject(); - if (!project) - return; - - CppTools::CppModelManager *modelManager = CppTools::CppModelManager::instance(); - const QList<CppTools::ProjectPart::Ptr> pp = modelManager->projectInfo(project).projectParts(); - foreach (const CppTools::ProjectPart::Ptr &p, pp) { - if (!p->selectedForBuilding) - removeTestsIfNecessaryByProFile(p->projectFile); - else { - QStringList files; - foreach (auto projectFile, p->files) - files.append(projectFile.path); - // avoid illegal parser state when respective widgets became hidden while evaluating - setState(Idle); - scanForTests(files); - } - } -} - #ifdef WITH_TESTS int TestCodeParser::autoTestsCount() const { diff --git a/plugins/autotest/testcodeparser.h b/plugins/autotest/testcodeparser.h index 1b8215fe50..5bb54d9320 100644 --- a/plugins/autotest/testcodeparser.h +++ b/plugins/autotest/testcodeparser.h @@ -56,6 +56,7 @@ public: virtual ~TestCodeParser(); void setState(State state); State state() const { return m_parserState; } + void setDirty() { m_dirty = true; } #ifdef WITH_TESTS int autoTestsCount() const; @@ -74,6 +75,7 @@ signals: void unnamedQuickTestsRemoved(const QString &filePath); void parsingStarted(); void parsingFinished(); + void parsingFailed(); void partialParsingFinished(); public slots: @@ -84,16 +86,15 @@ public slots: void onCppDocumentUpdated(const CPlusPlus::Document::Ptr &document); void onQmlDocumentUpdated(const QmlJS::Document::Ptr &document); + void onStartupProjectChanged(ProjectExplorer::Project *); void onProjectPartsUpdated(ProjectExplorer::Project *project); void removeFiles(const QStringList &files); - void onProFileEvaluated(); private: bool postponed(const QStringList &fileList); void scanForTests(const QStringList &fileList = QStringList()); void clearCache(); void removeTestsIfNecessary(const QString &fileName); - void removeTestsIfNecessaryByProFile(const QString &proFile); void onTaskStarted(Core::Id type); void onAllTasksFinished(Core::Id type); @@ -111,10 +112,11 @@ private: QMap<QString, TestInfo> m_cppDocMap; QMap<QString, TestInfo> m_quickDocMap; QList<UnnamedQuickTestInfo> m_unnamedQuickDocList; - bool m_parserEnabled; + bool m_codeModelParsing; bool m_fullUpdatePostponed; bool m_partialUpdatePostponed; bool m_dirty; + bool m_singleShotScheduled; QSet<QString> m_postponedFiles; State m_parserState; }; diff --git a/plugins/autotest/testnavigationwidget.cpp b/plugins/autotest/testnavigationwidget.cpp index 9745e1a19b..ad1a496b5f 100644 --- a/plugins/autotest/testnavigationwidget.cpp +++ b/plugins/autotest/testnavigationwidget.cpp @@ -75,6 +75,8 @@ TestNavigationWidget::TestNavigationWidget(QWidget *parent) : this, &TestNavigationWidget::onParsingStarted); connect(m_model->parser(), &TestCodeParser::parsingFinished, this, &TestNavigationWidget::onParsingFinished); + connect(m_model->parser(), &TestCodeParser::parsingFailed, + this, &TestNavigationWidget::onParsingFinished); connect(m_progressTimer, &QTimer::timeout, m_progressIndicator, &Utils::ProgressIndicator::show); } diff --git a/plugins/autotest/testresultdelegate.cpp b/plugins/autotest/testresultdelegate.cpp index 5e37c64955..57dc2de847 100644 --- a/plugins/autotest/testresultdelegate.cpp +++ b/plugins/autotest/testresultdelegate.cpp @@ -269,11 +269,6 @@ QSize TestResultDelegate::sizeHint(const QStyleOptionViewItem &option, const QMo return s; } -void TestResultDelegate::emitSizeHintChanged(const QModelIndex &index) -{ - emit sizeHintChanged(index); -} - void TestResultDelegate::currentChanged(const QModelIndex ¤t, const QModelIndex &previous) { emit sizeHintChanged(current); diff --git a/plugins/autotest/testresultdelegate.h b/plugins/autotest/testresultdelegate.h index 8bc5d58ad8..0b837ed2b2 100644 --- a/plugins/autotest/testresultdelegate.h +++ b/plugins/autotest/testresultdelegate.h @@ -37,10 +37,6 @@ public: void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const; QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const; - void emitSizeHintChanged(const QModelIndex &index); - -signals: - public slots: void currentChanged(const QModelIndex ¤t, const QModelIndex &previous); diff --git a/plugins/autotest/testtreemodel.cpp b/plugins/autotest/testtreemodel.cpp index 4639cbd1e9..5eea7b7d98 100644 --- a/plugins/autotest/testtreemodel.cpp +++ b/plugins/autotest/testtreemodel.cpp @@ -96,13 +96,17 @@ TestTreeModel::~TestTreeModel() void TestTreeModel::enableParsing() { m_refCounter.ref(); + + if (!m_connectionsInitialized) + m_parser->setDirty(); + m_parser->setState(TestCodeParser::Idle); if (m_connectionsInitialized) return; ProjectExplorer::SessionManager *sm = ProjectExplorer::SessionManager::instance(); connect(sm, &ProjectExplorer::SessionManager::startupProjectChanged, - m_parser, &TestCodeParser::emitUpdateTestTree); + m_parser, &TestCodeParser::onStartupProjectChanged); CppTools::CppModelManager *cppMM = CppTools::CppModelManager::instance(); connect(cppMM, &CppTools::CppModelManager::documentUpdated, diff --git a/plugins/autotest/unit_test/mixed_atp/mixed_atp.qbs b/plugins/autotest/unit_test/mixed_atp/mixed_atp.qbs new file mode 100644 index 0000000000..dfc99c15df --- /dev/null +++ b/plugins/autotest/unit_test/mixed_atp/mixed_atp.qbs @@ -0,0 +1,8 @@ +import qbs + +Project { + references: [ + "src/src.qbs", + "tests/tests.qbs" + ] +} diff --git a/plugins/autotest/unit_test/mixed_atp/src/src.qbs b/plugins/autotest/unit_test/mixed_atp/src/src.qbs new file mode 100644 index 0000000000..5ed4dd4a36 --- /dev/null +++ b/plugins/autotest/unit_test/mixed_atp/src/src.qbs @@ -0,0 +1,11 @@ +import qbs + +CppApplication { + type: "application" + name: "Dummy Application" + + Depends { name: "Qt.gui" } + Depends { name: "Qt.widgets" } + + files: [ "main.cpp" ] +} diff --git a/plugins/autotest/unit_test/mixed_atp/tests/auto/auto.qbs b/plugins/autotest/unit_test/mixed_atp/tests/auto/auto.qbs new file mode 100644 index 0000000000..a27b392244 --- /dev/null +++ b/plugins/autotest/unit_test/mixed_atp/tests/auto/auto.qbs @@ -0,0 +1,13 @@ +import qbs + +Project { + name: "Auto tests" + + references: [ + "bench/bench.qbs", + "dummy/dummy.qbs", + "gui/gui.qbs", + "quickauto/quickauto.qbs", + "quickauto2/quickauto2.qbs" + ] +} diff --git a/plugins/autotest/unit_test/mixed_atp/tests/auto/bench/bench.qbs b/plugins/autotest/unit_test/mixed_atp/tests/auto/bench/bench.qbs new file mode 100644 index 0000000000..d10891316a --- /dev/null +++ b/plugins/autotest/unit_test/mixed_atp/tests/auto/bench/bench.qbs @@ -0,0 +1,14 @@ +import qbs + +CppApplication { + type: "application" + name: "Benchmark Auto Test" + targetName: "tst_benchtest" + + Depends { name: "cpp" } + Depends { name: "Qt.test" } + + files: [ "tst_benchtest.cpp" ] + + cpp.defines: base.concat("SRCDIR=" + path) +} diff --git a/plugins/autotest/unit_test/mixed_atp/tests/auto/dummy/dummy.qbs b/plugins/autotest/unit_test/mixed_atp/tests/auto/dummy/dummy.qbs new file mode 100644 index 0000000000..012ba11a67 --- /dev/null +++ b/plugins/autotest/unit_test/mixed_atp/tests/auto/dummy/dummy.qbs @@ -0,0 +1,12 @@ +import qbs + +CppApplication { + type: "application" + name: "Dummy auto test" + targetName: "tst_FooBar" + + Depends { name: "Qt.test" } + Depends { name: "Qt.gui" } + + files: [ "tst_foo.cpp", "tst_foo.h" ] +} diff --git a/plugins/autotest/unit_test/mixed_atp/tests/auto/gui/gui.qbs b/plugins/autotest/unit_test/mixed_atp/tests/auto/gui/gui.qbs new file mode 100644 index 0000000000..05359cf10f --- /dev/null +++ b/plugins/autotest/unit_test/mixed_atp/tests/auto/gui/gui.qbs @@ -0,0 +1,13 @@ +import qbs + +CppApplication { + name: "Gui auto test" + targetName: "tst_gui" + + Depends { name: "Qt"; submodules: [ "gui", "widgets", "test" ] } + Depends { name: "cpp" } + + files: [ "tst_guitest.cpp" ] + + cpp.defines: base.concat("SRCDIR=" + path) +} diff --git a/plugins/autotest/unit_test/mixed_atp/tests/auto/quickauto/quickauto.qbs b/plugins/autotest/unit_test/mixed_atp/tests/auto/quickauto/quickauto.qbs new file mode 100644 index 0000000000..1697cd51a2 --- /dev/null +++ b/plugins/autotest/unit_test/mixed_atp/tests/auto/quickauto/quickauto.qbs @@ -0,0 +1,33 @@ +import qbs + +CppApplication { + name: "Qt Quick auto test" + targetName: "test_mal_qtquick" + + Depends { name: "cpp" } + Depends { name: "Qt.core" } + Depends { + condition: Qt.core.versionMajor > 4 + name: "Qt.qmltest" + } + + Group { + name: "main application" + condition: Qt.core.versionMajor > 4 + + files: [ "main.cpp" ] + } + + Group { + name: "qml test files" + qbs.install: true + + files: [ + "tst_test1.qml", "tst_test2.qml", "TestDummy.qml", + "bar/tst_foo.qml", "tst_test3.qml" + ] + } + + // this should be set automatically, but it seems as if this does not happen + cpp.defines: base.concat("QUICK_TEST_SOURCE_DIR=\"" + path + "\"") +} diff --git a/plugins/autotest/unit_test/mixed_atp/tests/auto/quickauto2/quickauto2.qbs b/plugins/autotest/unit_test/mixed_atp/tests/auto/quickauto2/quickauto2.qbs new file mode 100644 index 0000000000..a5fe65fbd6 --- /dev/null +++ b/plugins/autotest/unit_test/mixed_atp/tests/auto/quickauto2/quickauto2.qbs @@ -0,0 +1,29 @@ +import qbs + +CppApplication { + name: "Qt Quick auto test 2" + targetName: "test_mal_qtquick" + + Depends { name: "cpp" } + Depends { name: "Qt.core" } + Depends { + condition: Qt.core.versionMajor > 4 + name: "Qt.qmltest" + } + + Group { + condition: Qt.core.versionMajor > 4 + name: "main application" + files: [ "main.cpp" ] + } + + Group { + name: "qml test files" + qbs.install: true + + files: [ "tst_test1.qml", "tst_test2.qml" ] + } + + // this should be set automatically, but it seems as if this does not happen + cpp.defines: base.concat("QUICK_TEST_SOURCE_DIR=\"" + path + "\"") +} diff --git a/plugins/autotest/unit_test/mixed_atp/tests/tests.qbs b/plugins/autotest/unit_test/mixed_atp/tests/tests.qbs new file mode 100644 index 0000000000..e62815789f --- /dev/null +++ b/plugins/autotest/unit_test/mixed_atp/tests/tests.qbs @@ -0,0 +1,7 @@ +import qbs + +Project { + name: "Tests" + + references: [ "auto/auto.qbs" ] +} diff --git a/plugins/autotest/unit_test/plain/plain.qbs b/plugins/autotest/unit_test/plain/plain.qbs new file mode 100644 index 0000000000..c2fe33618a --- /dev/null +++ b/plugins/autotest/unit_test/plain/plain.qbs @@ -0,0 +1,7 @@ +import qbs + +Project { + name: "Plain test project" + + references: [ "test_plain/test_plain.qbs" ] +} diff --git a/plugins/autotest/unit_test/plain/test_plain/test_plain.qbs b/plugins/autotest/unit_test/plain/test_plain/test_plain.qbs new file mode 100644 index 0000000000..1b7937ce6a --- /dev/null +++ b/plugins/autotest/unit_test/plain/test_plain/test_plain.qbs @@ -0,0 +1,10 @@ +import qbs + +CppApplication { + type: "application" // suppress bundle generation on OSX + + Depends { name: "Qt.gui" } + Depends { name: "Qt.test" } + + files: [ "tst_simple.cpp", "tst_simple.h" ] +} |