diff options
-rw-r--r-- | src/plugins/autotest/testcodeparser.cpp | 126 | ||||
-rw-r--r-- | src/plugins/autotest/testconfiguration.cpp | 40 | ||||
-rw-r--r-- | src/plugins/autotest/testconfiguration.h | 1 | ||||
-rw-r--r-- | src/plugins/autotest/testnavigationwidget.cpp | 16 | ||||
-rw-r--r-- | src/plugins/autotest/testtreeitem.cpp | 147 | ||||
-rw-r--r-- | src/plugins/autotest/testtreeitem.h | 100 | ||||
-rw-r--r-- | src/plugins/autotest/testtreeitemdelegate.cpp | 2 | ||||
-rw-r--r-- | src/plugins/autotest/testtreemodel.cpp | 251 | ||||
-rw-r--r-- | src/plugins/autotest/testtreemodel.h | 10 | ||||
-rw-r--r-- | src/plugins/autotest/testvisitor.cpp | 15 |
10 files changed, 314 insertions, 394 deletions
diff --git a/src/plugins/autotest/testcodeparser.cpp b/src/plugins/autotest/testcodeparser.cpp index e9ecc29726..76c0de19cc 100644 --- a/src/plugins/autotest/testcodeparser.cpp +++ b/src/plugins/autotest/testcodeparser.cpp @@ -428,6 +428,31 @@ static QMap<QString, TestCodeLocationList> checkForDataTags(const QString &fileN /****** end of helpers ******/ +static void checkQmlDocumentForTestCode(QFutureInterface<TestParseResult> futureInterface, + const QmlJS::Document::Ptr &qmlJSDoc, + const QString &proFile = QString()) +{ + QmlJS::AST::Node *ast = qmlJSDoc->ast(); + QTC_ASSERT(ast, return); + 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(); + + TestParseResult parseResult(TestTreeModel::QuickTest); + parseResult.proFile = proFile; + parseResult.functions = testFunctions; + if (!testCaseName.isEmpty()) { + parseResult.fileName = tcLocationAndType.m_name; + parseResult.testCaseName = testCaseName; + parseResult.line = tcLocationAndType.m_line; + parseResult.column = tcLocationAndType.m_column; + } + futureInterface.reportResult(parseResult); +} + static void handleQtQuickTest(QFutureInterface<TestParseResult> futureInterface, CPlusPlus::Document::Ptr document) { @@ -437,32 +462,17 @@ static void handleQtQuickTest(QFutureInterface<TestParseResult> futureInterface, return; const QString cppFileName = document->fileName(); + QList<CppTools::ProjectPart::Ptr> ppList = modelManager->projectPart(cppFileName); + QTC_ASSERT(!ppList.isEmpty(), return); + const QString &proFile = ppList.at(0)->projectFile; + const QString srcDir = quickTestSrcDir(modelManager, cppFileName); if (srcDir.isEmpty()) return; const QList<QmlJS::Document::Ptr> qmlDocs = scanDirectoryForQuickTestQmlFiles(srcDir); - foreach (const QmlJS::Document::Ptr &qmlJSDoc, qmlDocs) { - QmlJS::AST::Node *ast = qmlJSDoc->ast(); - QTC_ASSERT(ast, continue); - 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(); - - TestParseResult parseResult(TestTreeModel::QuickTest); - parseResult.referencingFile = cppFileName; - parseResult.functions = testFunctions; - if (!testCaseName.isEmpty()) { - parseResult.fileName = tcLocationAndType.m_name; - parseResult.testCaseName = testCaseName; - parseResult.line = tcLocationAndType.m_line; - parseResult.column = tcLocationAndType.m_column; - } - futureInterface.reportResult(parseResult); - } + foreach (const QmlJS::Document::Ptr &qmlJSDoc, qmlDocs) + checkQmlDocumentForTestCode(futureInterface, qmlJSDoc, proFile); } static void handleGTest(QFutureInterface<TestParseResult> futureInterface, const QString &filePath) @@ -480,14 +490,14 @@ static void handleGTest(QFutureInterface<TestParseResult> futureInterface, const const CppTools::CppModelManager *cppMM = CppTools::CppModelManager::instance(); QList<CppTools::ProjectPart::Ptr> ppList = cppMM->projectPart(filePath); if (ppList.size()) - proFile = ppList.at(0)->projectFile; + proFile = ppList.first()->projectFile; foreach (const GTestCaseSpec &testSpec, result.keys()) { TestParseResult parseResult(TestTreeModel::GoogleTest); parseResult.fileName = filePath; parseResult.testCaseName = testSpec.testCaseName; parseResult.parameterized = testSpec.parameterized; - parseResult.referencingFile = proFile; + parseResult.proFile = proFile; parseResult.dataTagsOrTestSets.insert(QString(), result.value(testSpec)); futureInterface.reportResult(parseResult); } @@ -495,7 +505,7 @@ static void handleGTest(QFutureInterface<TestParseResult> futureInterface, const static void checkDocumentForTestCode(QFutureInterface<TestParseResult> futureInterface, CPlusPlus::Document::Ptr document, - const QString &referencingFile = QString()) + QMap<QString, QString> testCaseNames) { const QString fileName = document->fileName(); const CppTools::CppModelManager *modelManager = CppTools::CppModelManager::instance(); @@ -508,11 +518,13 @@ static void checkDocumentForTestCode(QFutureInterface<TestParseResult> futureInt if (includesQtQuickTest(document, modelManager)) { handleQtQuickTest(futureInterface, document); - return; - } - - if (includesQtTest(document, modelManager) && qtTestLibDefined(modelManager, fileName)) { + } else if (testCaseNames.contains(fileName) // if we do a reparse + || (includesQtTest(document, modelManager) + && qtTestLibDefined(modelManager, fileName))) { QString testCaseName(testClass(modelManager, document)); + // we might be in a reparse without the original entry point with the QTest::qExec() + if (testCaseName.isEmpty()) + testCaseName = testCaseNames.value(fileName); if (!testCaseName.isEmpty()) { unsigned line = 0; unsigned column = 0; @@ -521,8 +533,6 @@ static void checkDocumentForTestCode(QFutureInterface<TestParseResult> futureInt if (declaringDoc.isNull()) return; - const bool hasReferencingFile = declaringDoc->fileName() != document->fileName(); - TestVisitor visitor(testCaseName); visitor.accept(declaringDoc->globalNamespace()); const QMap<QString, TestCodeLocationAndType> testFunctions = visitor.privateSlots(); @@ -530,7 +540,7 @@ static void checkDocumentForTestCode(QFutureInterface<TestParseResult> futureInt QMap<QString, TestCodeLocationList> dataTags = checkForDataTags(declaringDoc->fileName(), testFunctions); - if (hasReferencingFile) + if (declaringDoc->fileName() != document->fileName()) dataTags.unite(checkForDataTags(document->fileName(), testFunctions)); TestParseResult parseResult(TestTreeModel::AutoTest); @@ -540,27 +550,13 @@ static void checkDocumentForTestCode(QFutureInterface<TestParseResult> futureInt parseResult.column = column; parseResult.functions = testFunctions; parseResult.dataTagsOrTestSets = dataTags; - if (hasReferencingFile) - parseResult.referencingFile = fileName; + parseResult.proFile = projParts.first()->projectFile; futureInterface.reportResult(parseResult); - return; } - } - - if (includesGTest(document, modelManager)) { - if (hasGTestNames(document)) { + } else if (includesGTest(document, modelManager)) { + if (hasGTestNames(document)) handleGTest(futureInterface, document->fileName()); - 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 (!referencingFile.isEmpty()) { - CPlusPlus::Snapshot snapshot = modelManager->snapshot(); - if (snapshot.contains(referencingFile)) - checkDocumentForTestCode(futureInterface, snapshot.find(referencingFile).value()); } } @@ -569,21 +565,22 @@ static void checkDocumentForTestCode(QFutureInterface<TestParseResult> futureInt static bool parsingHasFailed; static void performParse(QFutureInterface<TestParseResult> &futureInterface, - const QStringList &list, const QMap<QString, QString> &referencingFiles) + const QStringList &list, const QMap<QString, QString> testCaseNames) { int progressValue = 0; futureInterface.setProgressRange(0, list.size()); futureInterface.setProgressValue(progressValue); CppTools::CppModelManager *cppMM = CppTools::CppModelManager::instance(); CPlusPlus::Snapshot snapshot = cppMM->snapshot(); + QmlJS::Snapshot qmlSnapshot = QmlJSTools::Internal::ModelManager::instance()->snapshot(); foreach (const QString &file, list) { - if (snapshot.contains(file)) { + if (file.endsWith(QLatin1String(".qml"))) { + checkQmlDocumentForTestCode(futureInterface, qmlSnapshot.document(file)); + } else if (snapshot.contains(file)) { CPlusPlus::Document::Ptr doc = snapshot.find(file).value(); futureInterface.setProgressValue(++progressValue); - const QString &referencingFile = referencingFiles.value(file); - checkDocumentForTestCode(futureInterface, doc, - list.contains(referencingFile) ? QString() : referencingFile); + checkDocumentForTestCode(futureInterface, doc, testCaseNames); } else { parsingHasFailed |= (CppTools::ProjectFile::classify(file) != CppTools::ProjectFile::Unclassified); @@ -617,10 +614,11 @@ void TestCodeParser::onCppDocumentUpdated(const CPlusPlus::Document::Ptr &docume void TestCodeParser::onQmlDocumentUpdated(const QmlJS::Document::Ptr &document) { + const QString &fileName = document->fileName(); if (m_codeModelParsing) { if (!m_fullUpdatePostponed) { m_partialUpdatePostponed = true; - m_postponedFiles.insert(document->fileName()); + m_postponedFiles.insert(fileName); } return; } @@ -628,18 +626,12 @@ void TestCodeParser::onQmlDocumentUpdated(const QmlJS::Document::Ptr &document) ProjectExplorer::Project *project = ProjectExplorer::SessionManager::startupProject(); if (!project) return; - const QString fileName = document->fileName(); if (!project->files(ProjectExplorer::Project::AllFiles).contains(fileName)) { // what if the file is not listed inside the pro file, but will be used anyway? return; } - const CPlusPlus::Snapshot snapshot = CppTools::CppModelManager::instance()->snapshot(); - const QString &referencingFile = m_model->referencingFiles().value(fileName); - if (!referencingFile.isEmpty() && snapshot.contains(referencingFile)) { - qCDebug(LOG) << "calling scanForTests with cached referencing files" - << "(onQmlDocumentUpdated)"; - scanForTests(QStringList(referencingFile)); - } + + scanForTests(QStringList(fileName)); } void TestCodeParser::onStartupProjectChanged(ProjectExplorer::Project *project) @@ -724,16 +716,20 @@ void TestCodeParser::scanForTests(const QStringList &fileList) parsingHasFailed = false; - QMap<QString, QString> referencingFiles = m_model->referencingFiles(); + QMap<QString, QString> testCaseNames; if (isFullParse) { + // remove qml files as they will be found automatically by the referencing cpp file + list = Utils::filtered(list, [] (const QString &fn) { + return !fn.endsWith(QLatin1String(".qml")); + }); m_model->markAllForRemoval(); } else { + testCaseNames = m_model->testCaseNamesForFiles(list); foreach (const QString &filePath, list) m_model->markForRemoval(filePath); } - QFuture<TestParseResult> future - = Utils::runAsync(&performParse, list, referencingFiles); + QFuture<TestParseResult> future = Utils::runAsync(&performParse, list, testCaseNames); m_futureWatcher.setFuture(future); if (list.size() > 5) { Core::ProgressManager::addTask(future, tr("Scanning for Tests"), diff --git a/src/plugins/autotest/testconfiguration.cpp b/src/plugins/autotest/testconfiguration.cpp index 3c0463ec1b..ffacd05d1a 100644 --- a/src/plugins/autotest/testconfiguration.cpp +++ b/src/plugins/autotest/testconfiguration.cpp @@ -63,25 +63,7 @@ TestConfiguration::~TestConfiguration() m_testCases.clear(); } -void basicProjectInformation(Project *project, const QString &mainFilePath, QString *proFile, - QString *displayName, Project **targetProject) -{ - CppTools::CppModelManager *cppMM = CppTools::CppModelManager::instance(); - QList<CppTools::ProjectPart::Ptr> projParts = cppMM->projectInfo(project).projectParts(); - - foreach (const CppTools::ProjectPart::Ptr &part, projParts) { - foreach (const CppTools::ProjectFile currentFile, part->files) { - if (currentFile.path == mainFilePath) { - *proFile = part->projectFile; - *displayName = part->displayName; - *targetProject = part->project; - return; - } - } - } -} - -void basicProjectInformation(Project *project, const QString &proFile, QString *displayName, +void completeBasicProjectInformation(Project *project, const QString &proFile, QString *displayName, Project **targetProject) { CppTools::CppModelManager *cppMM = CppTools::CppModelManager::instance(); @@ -105,7 +87,7 @@ static bool isLocal(RunConfiguration *runConfiguration) void TestConfiguration::completeTestInformation() { - QTC_ASSERT(!m_mainFilePath.isEmpty() || !m_proFile.isEmpty(), return); + QTC_ASSERT(!m_proFile.isEmpty(), return); Project *project = SessionManager::startupProject(); if (!project) @@ -114,7 +96,6 @@ void TestConfiguration::completeTestInformation() QString targetFile; QString targetName; QString workDir; - QString proFile = m_proFile; QString displayName; QString buildDir; Project *targetProject = 0; @@ -123,10 +104,7 @@ void TestConfiguration::completeTestInformation() bool guessedRunConfiguration = false; setProject(0); - if (m_proFile.isEmpty()) - basicProjectInformation(project, m_mainFilePath, &proFile, &displayName, &targetProject); - else - basicProjectInformation(project, proFile, &displayName, &targetProject); + completeBasicProjectInformation(project, m_proFile, &displayName, &targetProject); Target *target = project->activeTarget(); if (!target) @@ -135,7 +113,7 @@ void TestConfiguration::completeTestInformation() BuildTargetInfoList appTargets = target->applicationTargets(); foreach (const BuildTargetInfo &bti, appTargets.list) { // some project manager store line/column information as well inside ProjectPart - if (bti.isValid() && proFile.startsWith(bti.projectFilePath.toString())) { + if (bti.isValid() && m_proFile.startsWith(bti.projectFilePath.toString())) { targetFile = Utils::HostOsInfo::withExecutableSuffix(bti.targetFilePath.toString()); targetName = bti.targetName; break; @@ -146,8 +124,8 @@ void TestConfiguration::completeTestInformation() if (auto buildConfig = target->activeBuildConfiguration()) { const QString buildBase = buildConfig->buildDirectory().toString(); const QString projBase = targetProject->projectDirectory().toString(); - if (proFile.startsWith(projBase)) - buildDir = QFileInfo(buildBase + proFile.mid(projBase.length())).absolutePath(); + if (m_proFile.startsWith(projBase)) + buildDir = QFileInfo(buildBase + m_proFile.mid(projBase.length())).absolutePath(); } } @@ -180,7 +158,6 @@ void TestConfiguration::completeTestInformation() } } - setProFile(proFile); setDisplayName(displayName); if (hasDesktopTarget) { @@ -215,11 +192,6 @@ void TestConfiguration::setTestCaseCount(int count) m_testCaseCount = count; } -void TestConfiguration::setMainFilePath(const QString &mainFile) -{ - m_mainFilePath = mainFile; -} - void TestConfiguration::setTargetFile(const QString &targetFile) { m_targetFile = targetFile; diff --git a/src/plugins/autotest/testconfiguration.h b/src/plugins/autotest/testconfiguration.h index 6e9cc8fc34..f3bcbbd161 100644 --- a/src/plugins/autotest/testconfiguration.h +++ b/src/plugins/autotest/testconfiguration.h @@ -51,7 +51,6 @@ public: void setTestCases(const QStringList &testCases); void setTestCaseCount(int count); - void setMainFilePath(const QString &mainFile); void setTargetFile(const QString &targetFile); void setTargetName(const QString &targetName); void setProFile(const QString &proFile); diff --git a/src/plugins/autotest/testnavigationwidget.cpp b/src/plugins/autotest/testnavigationwidget.cpp index a8432e70be..963fec32b6 100644 --- a/src/plugins/autotest/testnavigationwidget.cpp +++ b/src/plugins/autotest/testnavigationwidget.cpp @@ -110,12 +110,9 @@ void TestNavigationWidget::contextMenuEvent(QContextMenuEvent *event) // do not provide this menu entry for unnamed Quick Tests as it makes no sense int type = index.data(TypeRole).toInt(); const QString &unnamed = tr(Constants::UNNAMED_QUICKTESTS); - if ((type == TestTreeItem::TestFunction && index.parent().data().toString() != unnamed) - || (type == TestTreeItem::TestClass && index.data().toString() != unnamed) - || (type == TestTreeItem::TestDataTag) - || (type == TestTreeItem::GTestCase) - || (type == TestTreeItem::GTestCaseParameterized) - || (type == TestTreeItem::GTestName)) { + if ((type == TestTreeItem::TestFunctionOrSet && index.parent().data().toString() != unnamed) + || (type == TestTreeItem::TestCase && index.data().toString() != unnamed) + || (type == TestTreeItem::TestDataTag)) { runThisTest = new QAction(tr("Run This Test"), &menu); runThisTest->setEnabled(enabled); connect(runThisTest, &QAction::triggered, @@ -259,11 +256,8 @@ void TestNavigationWidget::onRunThisTestTriggered() return; TestTreeItem *item = static_cast<TestTreeItem *>(sourceIndex.internalPointer()); - if (item->type() == TestTreeItem::TestClass || item->type() == TestTreeItem::TestFunction - || item->type() == TestTreeItem::TestDataTag - || item->type() == TestTreeItem::GTestCase - || item->type() == TestTreeItem::GTestCaseParameterized - || item->type() == TestTreeItem::GTestName) { + if (item->type() == TestTreeItem::TestCase || item->type() == TestTreeItem::TestFunctionOrSet + || item->type() == TestTreeItem::TestDataTag) { if (TestConfiguration *configuration = m_model->getTestConfiguration(item)) { TestRunner *runner = TestRunner::instance(); runner->setSelectedTests( {configuration} ); diff --git a/src/plugins/autotest/testtreeitem.cpp b/src/plugins/autotest/testtreeitem.cpp index 0fe72e40fa..1d7e5fb10e 100644 --- a/src/plugins/autotest/testtreeitem.cpp +++ b/src/plugins/autotest/testtreeitem.cpp @@ -42,20 +42,9 @@ TestTreeItem::TestTreeItem(const QString &name, const QString &filePath, Type ty m_filePath(filePath), m_type(type), m_line(0), - m_state(Enabled), m_markedForRemoval(false) { - switch (m_type) { - case TestClass: - case TestFunction: - case GTestCase: - case GTestCaseParameterized: - case GTestName: - m_checked = Qt::Checked; - break; - default: - m_checked = Qt::Unchecked; - } + m_checked = (m_type == TestCase || m_type == TestFunctionOrSet) ? Qt::Checked : Qt::Unchecked; } static QIcon testTreeIcon(TestTreeItem::Type type) @@ -66,8 +55,6 @@ static QIcon testTreeIcon(TestTreeItem::Type type) QIcon(QLatin1String(":/images/func.png")), QIcon(QLatin1String(":/images/data.png")) }; - if (type == TestTreeItem::GTestCase || type == TestTreeItem::GTestCaseParameterized) - return icons[1]; if (int(type) >= int(sizeof icons / sizeof *icons)) return icons[2]; @@ -82,12 +69,10 @@ QVariant TestTreeItem::data(int /*column*/, int role) const return QString(m_name + QObject::tr(" (none)")); else if (m_name.isEmpty()) return QObject::tr(Constants::UNNAMED_QUICKTESTS); - else if (m_type == GTestCaseParameterized) - return QString(m_name + QObject::tr(" [parameterized]")); else return m_name; case Qt::ToolTipRole: - if (m_type == TestClass && m_name.isEmpty()) { + if (m_type == TestCase && m_name.isEmpty()) { return QObject::tr("<p>Give all test cases a name to ensure correct behavior " "when running test cases and to be able to select them.</p>"); } @@ -101,12 +86,9 @@ QVariant TestTreeItem::data(int /*column*/, int role) const case TestSpecialFunction: case TestDataTag: return QVariant(); - case TestClass: - case GTestCase: - case GTestCaseParameterized: + case TestCase: return m_name.isEmpty() ? QVariant() : checked(); - case TestFunction: - case GTestName: + case TestFunctionOrSet: if (parentItem() && parentItem()->name().isEmpty()) return QVariant(); return checked(); @@ -123,17 +105,15 @@ QVariant TestTreeItem::data(int /*column*/, int role) const case TestDataFunction: case TestSpecialFunction: return true; - case TestClass: + case TestCase: return m_name.isEmpty(); - case TestFunction: + case TestFunctionOrSet: return parentItem() ? parentItem()->name().isEmpty() : false; default: return false; } case TypeRole: return m_type; - case StateRole: - return (int)m_state; } return QVariant(); } @@ -171,22 +151,6 @@ bool TestTreeItem::modifyDataTagContent(const QString &fileName, return hasBeenModified; } -bool TestTreeItem::modifyGTestSetContent(const QString &fileName, const QString &referencingFile, - const TestCodeLocationAndType &location) -{ - bool hasBeenModified = modifyFilePath(fileName); - if (m_referencingFile != referencingFile) { - m_referencingFile = referencingFile; - hasBeenModified = true; - } - hasBeenModified |= modifyLineAndColumn(location.m_line, location.m_column); - if (m_state != location.m_state) { - m_state = location.m_state; - hasBeenModified = true; - } - return hasBeenModified; -} - bool TestTreeItem::modifyLineAndColumn(unsigned line, unsigned column) { bool hasBeenModified = false; @@ -204,15 +168,12 @@ bool TestTreeItem::modifyLineAndColumn(unsigned line, unsigned column) void TestTreeItem::setChecked(const Qt::CheckState checkState) { switch (m_type) { - case TestFunction: - case GTestName: { + case TestFunctionOrSet: { m_checked = (checkState == Qt::Unchecked ? Qt::Unchecked : Qt::Checked); parentItem()->revalidateCheckState(); break; } - case TestClass: - case GTestCase: - case GTestCaseParameterized: { + case TestCase: { Qt::CheckState usedState = (checkState == Qt::Unchecked ? Qt::Unchecked : Qt::Checked); for (int row = 0, count = childCount(); row < count; ++row) childItem(row)->setChecked(usedState); @@ -226,11 +187,8 @@ void TestTreeItem::setChecked(const Qt::CheckState checkState) Qt::CheckState TestTreeItem::checked() const { switch (m_type) { - case TestClass: - case TestFunction: - case GTestCase: - case GTestCaseParameterized: - case GTestName: + case TestCase: + case TestFunctionOrSet: return m_checked; case TestDataFunction: case TestSpecialFunction: @@ -271,11 +229,10 @@ TestTreeItem *TestTreeItem::findChildByName(const QString &name) }); } -TestTreeItem *TestTreeItem::findChildByFiles(const QString &filePath, - const QString &referencingFile) +TestTreeItem *TestTreeItem::findChildByFile(const QString &filePath) { - return findChildBy([filePath, referencingFile](const TestTreeItem *other) -> bool { - return other->filePath() == filePath && other->referencingFile() == referencingFile; + return findChildBy([filePath](const TestTreeItem *other) -> bool { + return other->filePath() == filePath; }); } @@ -286,16 +243,6 @@ TestTreeItem *TestTreeItem::findChildByNameAndFile(const QString &name, const QS }); } -TestTreeItem *TestTreeItem::findChildByNameTypeAndFile(const QString &name, TestTreeItem::Type type, - const QString &referencingFile) -{ - return findChildBy([name, type, referencingFile](const TestTreeItem *other) -> bool { - return other->referencingFile() == referencingFile - && other->name() == name - && other->type() == type; - }); -} - void TestTreeItem::revalidateCheckState() { if (childCount() == 0) @@ -352,9 +299,8 @@ TestTreeItem *TestTreeItem::findChildBy(CompareFunction compare) AutoTestTreeItem *AutoTestTreeItem::createTestItem(const TestParseResult &result) { - AutoTestTreeItem *item = new AutoTestTreeItem(result.testCaseName, result.fileName, - TestTreeItem::TestClass); - item->setReferencingFile(result.referencingFile); + AutoTestTreeItem *item = new AutoTestTreeItem(result.testCaseName, result.fileName, TestCase); + item->setProFile(result.proFile); item->setLine(result.line); item->setColumn(result.column); @@ -392,9 +338,8 @@ AutoTestTreeItem *AutoTestTreeItem::createDataTagItem(const QString &fileName, QuickTestTreeItem *QuickTestTreeItem::createTestItem(const TestParseResult &result) { - QuickTestTreeItem *item = new QuickTestTreeItem(result.testCaseName, result.fileName, - TestTreeItem::TestClass); - item->setReferencingFile(result.referencingFile); + QuickTestTreeItem *item = new QuickTestTreeItem(result.testCaseName, result.fileName, TestCase); + item->setProFile(result.proFile); item->setLine(result.line); item->setColumn(result.column); foreach (const QString &functionName, result.functions.keys()) @@ -413,7 +358,7 @@ QuickTestTreeItem *QuickTestTreeItem::createFunctionItem(const QString &function QuickTestTreeItem *QuickTestTreeItem::createUnnamedQuickTestItem(const TestParseResult &result) { - QuickTestTreeItem *item = new QuickTestTreeItem(QString(), QString(), TestTreeItem::TestClass); + QuickTestTreeItem *item = new QuickTestTreeItem(QString(), QString(), TestCase); foreach (const QString &functionName, result.functions.keys()) item->appendChild(createUnnamedQuickFunctionItem(functionName, result)); return item; @@ -426,15 +371,16 @@ QuickTestTreeItem *QuickTestTreeItem::createUnnamedQuickFunctionItem(const QStri QuickTestTreeItem *item = new QuickTestTreeItem(functionName, location.m_name, location.m_type); item->setLine(location.m_line); item->setColumn(location.m_column); - item->setReferencingFile(result.referencingFile); + item->setProFile(result.proFile); return item; } GoogleTestTreeItem *GoogleTestTreeItem::createTestItem(const TestParseResult &result) { - GoogleTestTreeItem *item = new GoogleTestTreeItem(result.testCaseName, QString(), - result.parameterized ? TestTreeItem::GTestCaseParameterized : TestTreeItem::GTestCase); - item->setReferencingFile(result.referencingFile); + GoogleTestTreeItem *item = new GoogleTestTreeItem(result.testCaseName, QString(), TestCase); + item->setProFile(result.proFile); + if (result.parameterized) + item->setState(Parameterized); foreach (const TestCodeLocationAndType &location, result.dataTagsOrTestSets.first()) item->appendChild(createTestSetItem(result, location)); return item; @@ -445,12 +391,55 @@ GoogleTestTreeItem *GoogleTestTreeItem::createTestSetItem(const TestParseResult { GoogleTestTreeItem *item = new GoogleTestTreeItem(location.m_name, result.fileName, location.m_type); - item->setState(location.m_state); + item->setStates(location.m_state); item->setLine(location.m_line); item->setColumn(location.m_column); - item->setReferencingFile(result.referencingFile); + item->setProFile(result.proFile); return item; } +QVariant GoogleTestTreeItem::data(int column, int role) const +{ + switch (role) { + case Qt::DisplayRole: + if (type() == TestCase) { + if (m_state & Parameterized) + return QString(name() + QObject::tr(" [parameterized]")); + return name(); + } + break; + case StateRole: + return (int)m_state; + default: + break; + } + return TestTreeItem::data(column, role); +} + +bool GoogleTestTreeItem::modifyTestSetContent(const QString &fileName, + const TestCodeLocationAndType &location) +{ + bool hasBeenModified = modifyFilePath(fileName); + hasBeenModified |= modifyLineAndColumn(location.m_line, location.m_column); + if (m_state != location.m_state) { + m_state = location.m_state; + hasBeenModified = true; + } + return hasBeenModified; +} + +TestTreeItem *GoogleTestTreeItem::findChildByNameStateAndFile(const QString &name, + GoogleTestTreeItem::TestStates state, + const QString &referencingFile) +{ + return findChildBy([name, state, referencingFile](const TestTreeItem *other) -> bool { + GoogleTestTreeItem *gtestItem = const_cast<TestTreeItem *>(other)->asGoogleTestTreeItem(); + return other->proFile() == referencingFile + && other->name() == name + && gtestItem->state() == state; + }); +} + + } // namespace Internal } // namespace Autotest diff --git a/src/plugins/autotest/testtreeitem.h b/src/plugins/autotest/testtreeitem.h index 4f85430479..b807199a56 100644 --- a/src/plugins/autotest/testtreeitem.h +++ b/src/plugins/autotest/testtreeitem.h @@ -57,25 +57,13 @@ public: enum Type { Root, - TestClass, - TestFunction, + TestCase, + TestFunctionOrSet, TestDataTag, TestDataFunction, - TestSpecialFunction, - GTestCase, - GTestCaseParameterized, - GTestName + TestSpecialFunction }; - enum TestState - { - Enabled = 0x00, - Disabled = 0x01, - }; - - Q_FLAGS(TestState) - Q_DECLARE_FLAGS(TestStates, TestState) - TestTreeItem(const QString &name = QString(), const QString &filePath = QString(), Type type = Root); @@ -84,8 +72,6 @@ public: bool modifyTestCaseContent(const QString &name, unsigned line, unsigned column); bool modifyTestFunctionContent(const TestCodeLocationAndType &location); bool modifyDataTagContent(const QString &fileName, const TestCodeLocationAndType &location); - bool modifyGTestSetContent(const QString &fileName, const QString &referencingFile, - const TestCodeLocationAndType &location); bool modifyLineAndColumn(unsigned line, unsigned column); const QString name() const { return m_name; } @@ -96,13 +82,11 @@ public: unsigned line() const { return m_line; } void setColumn(unsigned column) { m_column = column; } unsigned column() const { return m_column; } - QString referencingFile() const { return m_referencingFile; } - void setReferencingFile(const QString &referencingFile) { m_referencingFile = referencingFile; } + QString proFile() const { return m_proFile; } + void setProFile(const QString &proFile) { m_proFile = proFile; } void setChecked(const Qt::CheckState checked); Qt::CheckState checked() const; Type type() const { return m_type; } - void setState(TestStates states) { m_state = states; } - TestStates state() const { return m_state; } void markForRemoval(bool mark); void markForRemovalRecursively(bool mark); bool markedForRemoval() const { return m_markedForRemoval; } @@ -110,48 +94,35 @@ public: TestTreeItem *childItem(int row) const; TestTreeItem *findChildByName(const QString &name); - TestTreeItem *findChildByFiles(const QString &filePath, const QString &referencingFile); + TestTreeItem *findChildByFile(const QString &filePath); TestTreeItem *findChildByNameAndFile(const QString &name, const QString &filePath); - TestTreeItem *findChildByNameTypeAndFile(const QString &name, - TestTreeItem::Type type, const QString &referencingFile); virtual AutoTestTreeItem *asAutoTestTreeItem() { return 0; } virtual QuickTestTreeItem *asQuickTestTreeItem() { return 0; } virtual GoogleTestTreeItem *asGoogleTestTreeItem() { return 0; } + virtual const AutoTestTreeItem *asAutoTestTreeItem() const { return 0; } + virtual const QuickTestTreeItem *asQuickTestTreeItem() const { return 0; } + virtual const GoogleTestTreeItem *asGoogleTestTreeItem() const { return 0; } -private: - void revalidateCheckState(); +protected: bool modifyFilePath(const QString &filePath); - bool modifyName(const QString &name); - typedef std::function<bool(const TestTreeItem *)> CompareFunction; TestTreeItem *findChildBy(CompareFunction compare); +private: + void revalidateCheckState(); + bool modifyName(const QString &name); + QString m_name; QString m_filePath; Qt::CheckState m_checked; Type m_type; unsigned m_line; unsigned m_column; - QString m_referencingFile; - TestStates m_state; + QString m_proFile; bool m_markedForRemoval; }; -struct TestCodeLocationAndType { - QString m_name; // tag name for m_type == TEST_DATATAG, file name for other values - unsigned m_line; - unsigned m_column; - TestTreeItem::Type m_type; - TestTreeItem::TestStates m_state; -}; - -struct GTestCaseSpec -{ - QString testCaseName; - bool parameterized; -}; - typedef QVector<TestCodeLocationAndType> TestCodeLocationList; class AutoTestTreeItem : public TestTreeItem @@ -161,6 +132,7 @@ public: Type type = Root) : TestTreeItem(name, filePath, type) {} virtual AutoTestTreeItem *asAutoTestTreeItem() override { return this; } + virtual const AutoTestTreeItem *asAutoTestTreeItem() const override { return this; } static AutoTestTreeItem *createTestItem(const TestParseResult &result); static AutoTestTreeItem *createFunctionItem(const QString &functionName, @@ -177,6 +149,7 @@ public: Type type = Root) : TestTreeItem(name, filePath, type) {} virtual QuickTestTreeItem *asQuickTestTreeItem() override { return this; } + virtual const QuickTestTreeItem *asQuickTestTreeItem() const override { return this; } static QuickTestTreeItem *createTestItem(const TestParseResult &result); static QuickTestTreeItem *createFunctionItem(const QString &functionName, @@ -189,15 +162,52 @@ public: class GoogleTestTreeItem : public TestTreeItem { public: + enum TestState + { + Enabled = 0x00, + Disabled = 0x01, + Parameterized = 0x02, + }; + + Q_FLAGS(TestState) + Q_DECLARE_FLAGS(TestStates, TestState) + GoogleTestTreeItem(const QString &name = QString(), const QString &filePath = QString(), - Type type = Root) : TestTreeItem(name, filePath, type) {} + Type type = Root) : TestTreeItem(name, filePath, type), m_state(Enabled) {} virtual GoogleTestTreeItem *asGoogleTestTreeItem() override { return this; } + virtual const GoogleTestTreeItem *asGoogleTestTreeItem() const override { return this; } static GoogleTestTreeItem *createTestItem(const TestParseResult &result); static GoogleTestTreeItem *createTestSetItem(const TestParseResult &result, const TestCodeLocationAndType &location); + QVariant data(int column, int role) const override; + + void setStates(TestStates states) { m_state = states; } + void setState(TestState state) { m_state |= state; } + TestStates state() const { return m_state; } + bool modifyTestSetContent(const QString &fileName, const TestCodeLocationAndType &location); + TestTreeItem *findChildByNameStateAndFile(const QString &name, + GoogleTestTreeItem::TestStates state, + const QString &proFile); + +private: + GoogleTestTreeItem::TestStates m_state; +}; + +struct TestCodeLocationAndType { + QString m_name; // tag name for m_type == TEST_DATATAG, file name for other values + unsigned m_line; + unsigned m_column; + TestTreeItem::Type m_type; + GoogleTestTreeItem::TestStates m_state; +}; + +struct GTestCaseSpec +{ + QString testCaseName; + bool parameterized; }; } // namespace Internal diff --git a/src/plugins/autotest/testtreeitemdelegate.cpp b/src/plugins/autotest/testtreeitemdelegate.cpp index e5cc237aa5..9771385c8a 100644 --- a/src/plugins/autotest/testtreeitemdelegate.cpp +++ b/src/plugins/autotest/testtreeitemdelegate.cpp @@ -71,7 +71,7 @@ void TestTreeItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem & } // paint disabled googletests in gray - if (index.data(StateRole).toInt() & TestTreeItem::Disabled) + if (index.data(StateRole).toInt() & GoogleTestTreeItem::Disabled) opt.palette.setColor(QPalette::Text, QColor(0xa0, 0xa0, 0xa0)); QStyledItemDelegate::paint(painter, opt, index); diff --git a/src/plugins/autotest/testtreemodel.cpp b/src/plugins/autotest/testtreemodel.cpp index 81048db307..e474e5304a 100644 --- a/src/plugins/autotest/testtreemodel.cpp +++ b/src/plugins/autotest/testtreemodel.cpp @@ -44,43 +44,11 @@ namespace Autotest { namespace Internal { -class ReferencingFilesFinder : public Utils::TreeItemVisitor -{ -public: - ReferencingFilesFinder() {} - - bool preVisit(Utils::TreeItem *item) override - { - // 0 = invisible root, 1 = main categories, 2 = test cases, 3 = test functions - return item->level() < 4; - } - - void visit(Utils::TreeItem *item) override - { - // skip invisible root item - if (!item->parent()) - return; - - if (auto testItem = static_cast<TestTreeItem *>(item)) { - if (!testItem->filePath().isEmpty() && !testItem->referencingFile().isEmpty()) - m_referencingFiles.insert(testItem->filePath(), testItem->referencingFile()); - } - } - - QMap<QString, QString> referencingFiles() const { return m_referencingFiles; } - -private: - QMap<QString, QString> m_referencingFiles; - -}; - -/***********************************************************************************************/ - TestTreeModel::TestTreeModel(QObject *parent) : TreeModel(parent), - m_autoTestRootItem(new TestTreeItem(tr("Auto Tests"), QString(), TestTreeItem::Root)), - m_quickTestRootItem(new TestTreeItem(tr("Qt Quick Tests"), QString(), TestTreeItem::Root)), - m_googleTestRootItem(new TestTreeItem(tr("Google Tests"), QString(), TestTreeItem::Root)), + m_autoTestRootItem(new AutoTestTreeItem(tr("Auto Tests"), QString(), TestTreeItem::Root)), + m_quickTestRootItem(new QuickTestTreeItem(tr("Qt Quick Tests"), QString(), TestTreeItem::Root)), + m_googleTestRootItem(new GoogleTestTreeItem(tr("Google Tests"), QString(), TestTreeItem::Root)), m_parser(new TestCodeParser(this)), m_connectionsInitialized(false) { @@ -174,14 +142,11 @@ bool TestTreeModel::setData(const QModelIndex &index, const QVariant &value, int emit dataChanged(index, index); if (role == Qt::CheckStateRole) { switch (item->type()) { - case TestTreeItem::TestClass: - case TestTreeItem::GTestCase: - case TestTreeItem::GTestCaseParameterized: + case TestTreeItem::TestCase: if (item->childCount() > 0) emit dataChanged(index.child(0, 0), index.child(item->childCount() - 1, 0)); break; - case TestTreeItem::TestFunction: - case TestTreeItem::GTestName: + case TestTreeItem::TestFunctionOrSet: emit dataChanged(index.parent(), index.parent()); break; default: // avoid warning regarding unhandled enum member @@ -200,14 +165,11 @@ Qt::ItemFlags TestTreeModel::flags(const QModelIndex &index) const TestTreeItem *item = static_cast<TestTreeItem *>(itemForIndex(index)); switch(item->type()) { - case TestTreeItem::TestClass: - case TestTreeItem::GTestCase: - case TestTreeItem::GTestCaseParameterized: + case TestTreeItem::TestCase: if (item->name().isEmpty()) return Qt::ItemIsEnabled | Qt::ItemIsSelectable; return Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsTristate | Qt::ItemIsUserCheckable; - case TestTreeItem::TestFunction: - case TestTreeItem::GTestName: + case TestTreeItem::TestFunctionOrSet: if (item->parentItem()->name().isEmpty()) return Qt::ItemIsEnabled | Qt::ItemIsSelectable; return Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsUserCheckable; @@ -241,55 +203,51 @@ QList<TestConfiguration *> TestTreeModel::getAllTestCases() const TestConfiguration *tc = new TestConfiguration(child->name(), QStringList(), child->childCount()); - tc->setMainFilePath(child->filePath()); + tc->setProFile(child->proFile()); tc->setProject(project); result << tc; } // get all Quick Tests - QMap<QString, int> foundMains; + QMap<QString, int> foundProFiles; for (int row = 0, count = m_quickTestRootItem->childCount(); row < count; ++row) { const TestTreeItem *child = m_quickTestRootItem->childItem(row); // unnamed Quick Tests must be handled separately if (child->name().isEmpty()) { for (int childRow = 0, ccount = child->childCount(); childRow < ccount; ++ childRow) { const TestTreeItem *grandChild = child->childItem(childRow); - const QString mainFile = grandChild->referencingFile(); - foundMains.insert(mainFile, foundMains.contains(mainFile) - ? foundMains.value(mainFile) + 1 : 1); + const QString &proFile = grandChild->proFile(); + foundProFiles.insert(proFile, foundProFiles[proFile] + 1); } continue; } // named Quick Test - const QString mainFile = child->referencingFile(); - foundMains.insert(mainFile, foundMains.contains(mainFile) - ? foundMains.value(mainFile) + child->childCount() - : child->childCount()); + const QString &proFile = child->proFile(); + foundProFiles.insert(proFile, foundProFiles[proFile] + child->childCount()); } - // create TestConfiguration for each main - foreach (const QString &mainFile, foundMains.keys()) { + // create TestConfiguration for each project file + foreach (const QString &proFile, foundProFiles.keys()) { TestConfiguration *tc = new TestConfiguration(QString(), QStringList(), - foundMains.value(mainFile)); - tc->setMainFilePath(mainFile); + foundProFiles.value(proFile)); + tc->setProFile(proFile); tc->setProject(project); result << tc; } - foundMains.clear(); + foundProFiles.clear(); // get all Google Tests for (int row = 0, count = m_googleTestRootItem->childCount(); row < count; ++row) { const TestTreeItem *child = m_googleTestRootItem->childItem(row); for (int childRow = 0, childCount = child->childCount(); childRow < childCount; ++childRow) { - const QString &proFilePath = child->childItem(childRow)->referencingFile(); - foundMains.insert(proFilePath, foundMains.contains(proFilePath) - ? foundMains.value(proFilePath) + 1 : 1); + const QString &proFilePath = child->childItem(childRow)->proFile(); + foundProFiles.insert(proFilePath, foundProFiles[proFilePath] + 1); } } - foreach (const QString &proFile, foundMains.keys()) { + foreach (const QString &proFile, foundProFiles.keys()) { TestConfiguration *tc = new TestConfiguration(QString(), QStringList(), - foundMains.value(proFile)); + foundProFiles.value(proFile)); tc->setProFile(proFile); tc->setProject(project); tc->setTestType(TestTypeGTest); @@ -316,7 +274,7 @@ QList<TestConfiguration *> TestTreeModel::getSelectedTests() const continue; case Qt::Checked: testConfiguration = new TestConfiguration(child->name(), QStringList(), child->childCount()); - testConfiguration->setMainFilePath(child->filePath()); + testConfiguration->setProFile(child->proFile()); testConfiguration->setProject(project); result << testConfiguration; continue; @@ -332,7 +290,7 @@ QList<TestConfiguration *> TestTreeModel::getSelectedTests() const } testConfiguration = new TestConfiguration(childName, testCases); - testConfiguration->setMainFilePath(child->filePath()); + testConfiguration->setProFile(child->proFile()); testConfiguration->setProject(project); result << testConfiguration; } @@ -342,24 +300,24 @@ QList<TestConfiguration *> TestTreeModel::getSelectedTests() const // on and on and on... // TODO: do this later on for Auto Tests as well to support strange setups? or redo the model - QMap<QString, TestConfiguration *> foundMains; + QMap<QString, TestConfiguration *> foundProFiles; if (TestTreeItem *unnamed = unnamedQuickTests()) { for (int childRow = 0, ccount = unnamed->childCount(); childRow < ccount; ++ childRow) { const TestTreeItem *grandChild = unnamed->childItem(childRow); - const QString mainFile = grandChild->referencingFile(); - if (foundMains.contains(mainFile)) { + const QString &proFile = grandChild->proFile(); + if (foundProFiles.contains(proFile)) { QTC_ASSERT(testConfiguration, qWarning() << "Illegal state (unnamed Quick Test listed as named)"; return QList<TestConfiguration *>()); - foundMains[mainFile]->setTestCaseCount(testConfiguration->testCaseCount() + 1); + foundProFiles[proFile]->setTestCaseCount(testConfiguration->testCaseCount() + 1); } else { testConfiguration = new TestConfiguration(QString(), QStringList()); testConfiguration->setTestCaseCount(1); testConfiguration->setUnnamedOnly(true); - testConfiguration->setMainFilePath(mainFile); + testConfiguration->setProFile(proFile); testConfiguration->setProject(project); - foundMains.insert(mainFile, testConfiguration); + foundProFiles.insert(proFile, testConfiguration); } } } @@ -381,13 +339,13 @@ QList<TestConfiguration *> TestTreeModel::getSelectedTests() const int grandChildCount = child->childCount(); for (int grandChildRow = 0; grandChildRow < grandChildCount; ++grandChildRow) { const TestTreeItem *grandChild = child->childItem(grandChildRow); - if (grandChild->type() != TestTreeItem::TestFunction) + if (grandChild->type() != TestTreeItem::TestFunctionOrSet) continue; testFunctions << child->name() + QLatin1String("::") + grandChild->name(); } TestConfiguration *tc; - if (foundMains.contains(child->referencingFile())) { - tc = foundMains[child->referencingFile()]; + if (foundProFiles.contains(child->proFile())) { + tc = foundProFiles[child->proFile()]; QStringList oldFunctions(tc->testCases()); // if oldFunctions.size() is 0 this test configuration is used for at least one // unnamed test case @@ -400,15 +358,15 @@ QList<TestConfiguration *> TestTreeModel::getSelectedTests() const } } else { tc = new TestConfiguration(QString(), testFunctions); - tc->setMainFilePath(child->referencingFile()); + tc->setProFile(child->proFile()); tc->setProject(project); - foundMains.insert(child->referencingFile(), tc); + foundProFiles.insert(child->proFile(), tc); } break; } } - foreach (TestConfiguration *config, foundMains.values()) { + foreach (TestConfiguration *config, foundProFiles.values()) { if (!config->unnamedOnly()) result << config; else @@ -419,18 +377,18 @@ QList<TestConfiguration *> TestTreeModel::getSelectedTests() const QMap<QString, QStringList> proFilesWithEnabledTestSets; for (int row = 0, count = m_googleTestRootItem->childCount(); row < count; ++row) { - const TestTreeItem *child = m_googleTestRootItem->childItem(row); + const auto child = m_googleTestRootItem->childItem(row)->asGoogleTestTreeItem(); if (child->checked() == Qt::Unchecked) // add this test name to disabled list ? continue; int grandChildCount = child->childCount(); for (int grandChildRow = 0; grandChildRow < grandChildCount; ++grandChildRow) { const TestTreeItem *grandChild = child->childItem(grandChildRow); - const QString &proFile = grandChild->referencingFile(); + const QString &proFile = grandChild->proFile(); QStringList enabled = proFilesWithEnabledTestSets.value(proFile); if (grandChild->checked() == Qt::Checked) { QString testSpecifier = child->name() + QLatin1Char('.') + grandChild->name(); - if (child->type() == TestTreeItem::GTestCaseParameterized) { + if (child->state() & GoogleTestTreeItem::Parameterized) { testSpecifier.prepend(QLatin1String("*/")); testSpecifier.append(QLatin1String("/*")); } @@ -460,8 +418,8 @@ TestConfiguration *TestTreeModel::getTestConfiguration(const TestTreeItem *item) TestConfiguration *config = 0; switch (item->type()) { - case TestTreeItem::TestClass: { - if (item->parent() == m_quickTestRootItem) { + case TestTreeItem::TestCase: { + if (item->asQuickTestTreeItem()) { // Quick Test TestCase QStringList testFunctions; for (int row = 0, count = item->childCount(); row < count; ++row) { @@ -469,29 +427,52 @@ TestConfiguration *TestTreeModel::getTestConfiguration(const TestTreeItem *item) + item->childItem(row)->name(); } config = new TestConfiguration(QString(), testFunctions); - config->setMainFilePath(item->referencingFile()); + config->setProFile(item->proFile()); config->setProject(project); - } else { + } else if (item->asAutoTestTreeItem()) { // normal auto test config = new TestConfiguration(item->name(), QStringList(), item->childCount()); - config->setMainFilePath(item->filePath()); + config->setProFile(item->proFile()); config->setProject(project); + } else if (auto gtestItem = item->asGoogleTestTreeItem()) { + QString testSpecifier = item->name() + QLatin1String(".*"); + if (gtestItem->state() & GoogleTestTreeItem::Parameterized) + testSpecifier.prepend(QLatin1String("*/")); + + if (int childCount = item->childCount()) { + config = new TestConfiguration(QString(), QStringList(testSpecifier)); + config->setTestCaseCount(childCount); + config->setProFile(item->proFile()); + config->setProject(project); + config->setTestType(TestTypeGTest); + } } break; } - case TestTreeItem::TestFunction: { - const TestTreeItem *parent = item->parentItem(); - if (parent->parent() == m_quickTestRootItem) { + case TestTreeItem::TestFunctionOrSet: { + TestTreeItem *parent = item->parentItem(); + if (parent->asQuickTestTreeItem()) { // it's a Quick Test function of a named TestCase QStringList testFunction(parent->name() + QLatin1String("::") + item->name()); config = new TestConfiguration(QString(), testFunction); - config->setMainFilePath(parent->referencingFile()); + config->setProFile(parent->proFile()); config->setProject(project); - } else { + } else if (parent->asAutoTestTreeItem()){ // normal auto test config = new TestConfiguration(parent->name(), QStringList() << item->name()); - config->setMainFilePath(parent->filePath()); + config->setProFile(parent->proFile()); + config->setProject(project); + } else if (auto gtestParent = parent->asGoogleTestTreeItem()) { + QString testSpecifier = parent->name() + QLatin1Char('.') + item->name(); + + if (gtestParent->state() & GoogleTestTreeItem::Parameterized) { + testSpecifier.prepend(QLatin1String("*/")); + testSpecifier.append(QLatin1String("/*")); + } + config = new TestConfiguration(QString(), QStringList(testSpecifier)); + config->setProFile(item->proFile()); config->setProject(project); + config->setTestType(TestTypeGTest); } break; } @@ -502,39 +483,10 @@ TestConfiguration *TestTreeModel::getTestConfiguration(const TestTreeItem *item) return 0; const QString functionWithTag = function->name() + QLatin1Char(':') + item->name(); config = new TestConfiguration(parent->name(), QStringList() << functionWithTag); - config->setMainFilePath(parent->filePath()); + config->setProFile(parent->proFile()); config->setProject(project); break; } - case TestTreeItem::GTestCase: - case TestTreeItem::GTestCaseParameterized: { - QString testSpecifier = item->name() + QLatin1String(".*"); - if (item->type() == TestTreeItem::GTestCaseParameterized) - testSpecifier.prepend(QLatin1String("*/")); - - if (int childCount = item->childCount()) { - config = new TestConfiguration(QString(), QStringList(testSpecifier)); - config->setTestCaseCount(childCount); - config->setProFile(item->childItem(0)->referencingFile()); - config->setProject(project); - config->setTestType(TestTypeGTest); - } - break; - } - case TestTreeItem::GTestName: { - const TestTreeItem *parent = item->parentItem(); - QString testSpecifier = parent->name() + QLatin1Char('.') + item->name(); - - if (parent->type() == TestTreeItem::GTestCaseParameterized) { - testSpecifier.prepend(QLatin1String("*/")); - testSpecifier.append(QLatin1String("/*")); - } - config = new TestConfiguration(QString(), QStringList(testSpecifier)); - config->setProFile(item->referencingFile()); - config->setProject(project); - config->setTestType(TestTypeGTest); - break; - } // not supported items default: return 0; @@ -589,19 +541,16 @@ void TestTreeModel::markForRemoval(const QString &filePath) TestTreeItem *root = rootItemForType(type); for (int childRow = root->childCount() - 1; childRow >= 0; --childRow) { TestTreeItem *child = root->childItem(childRow); - if (child->markedForRemoval()) - continue; // Qt + named Quick Tests - if (child->filePath() == filePath || child->referencingFile() == filePath) { - child->markForRemovalRecursively(true); + if (child->filePath() == filePath) { + child->markForRemoval(true); } else { // unnamed Quick Tests and GTest and Qt Tests with separated source/header int grandChildRow = child->childCount() - 1; for ( ; grandChildRow >= 0; --grandChildRow) { TestTreeItem *grandChild = child->childItem(grandChildRow); - if (grandChild->filePath() == filePath - || grandChild->referencingFile() == filePath) { - grandChild->markForRemovalRecursively(true); + if (grandChild->filePath() == filePath) { + grandChild->markForRemoval(true); } } } @@ -621,6 +570,26 @@ void TestTreeModel::sweep() emit testTreeModelChanged(); } +QMap<QString, QString> TestTreeModel::testCaseNamesForFiles(QStringList files) +{ + QMap<QString, QString> result; + if (!m_autoTestRootItem) + return result; + + for (int row = 0, count = m_autoTestRootItem->childCount(); row < count; ++row) { + const TestTreeItem *child = m_autoTestRootItem->childItem(row); + if (files.contains(child->filePath())) { + result.insert(child->filePath(), child->name()); + } + for (int childRow = 0, children = child->childCount(); childRow < children; ++childRow) { + const TestTreeItem *grandChild = child->childItem(childRow); + if (files.contains(grandChild->filePath())) + result.insert(grandChild->filePath(), child->name()); + } + } + return result; +} + /** * @note after calling this function emit testTreeModelChanged() if it returns true */ @@ -648,13 +617,6 @@ bool TestTreeModel::sweepChildren(TestTreeItem *item) return hasChanged; } -QMap<QString, QString> TestTreeModel::referencingFiles() const -{ - ReferencingFilesFinder finder; - rootItem()->walkTree(&finder); - return finder.referencingFiles(); -} - void TestTreeModel::onParseResultReady(const TestParseResult &result) { switch (result.type) { @@ -692,7 +654,7 @@ void TestTreeModel::handleParseResult(const TestParseResult &result) QTC_ASSERT(false, return); // should never happen, just to avoid warning } - TestTreeItem *toBeModified = root->findChildByFiles(result.fileName, result.referencingFile); + TestTreeItem *toBeModified = root->findChildByFile(result.fileName); // if there's no matching item, add the new one if (!toBeModified) { if (result.type == AutoTest) @@ -761,17 +723,18 @@ void TestTreeModel::handleUnnamedQuickParseResult(const TestParseResult &result) func, result)); continue; } - functionItem->modifyLineAndColumn(result.line, result.column); + functionItem->modifyLineAndColumn(location.m_line, location.m_column); functionItem->markForRemoval(false); } } void TestTreeModel::handleGTestParseResult(const TestParseResult &result) { - TestTreeItem::Type type = result.parameterized ? TestTreeItem::GTestCaseParameterized - : TestTreeItem::GTestCase; - TestTreeItem *toBeModified = m_googleTestRootItem->findChildByNameTypeAndFile( - result.testCaseName, type, result.referencingFile); + GoogleTestTreeItem::TestStates states = GoogleTestTreeItem::Enabled; + if (result.parameterized) + states |= GoogleTestTreeItem::Parameterized; + TestTreeItem *toBeModified = m_googleTestRootItem->findChildByNameStateAndFile( + result.testCaseName, states, result.proFile); if (!toBeModified) { m_googleTestRootItem->appendChild(GoogleTestTreeItem::createTestItem(result)); return; @@ -784,8 +747,8 @@ void TestTreeModel::handleGTestParseResult(const TestParseResult &result) toBeModified->appendChild(GoogleTestTreeItem::createTestSetItem(result, location)); continue; } - bool changed = testSetItem->modifyGTestSetContent(result.fileName, - result.referencingFile, location); + bool changed = testSetItem->asGoogleTestTreeItem()->modifyTestSetContent( + result.fileName, location); testSetItem->markForRemoval(false); if (changed) emit dataChanged(indexForItem(testSetItem), indexForItem(testSetItem)); diff --git a/src/plugins/autotest/testtreemodel.h b/src/plugins/autotest/testtreemodel.h index 1bbe6d929f..3ef8c11738 100644 --- a/src/plugins/autotest/testtreemodel.h +++ b/src/plugins/autotest/testtreemodel.h @@ -81,7 +81,7 @@ public: void markAllForRemoval(); void markForRemoval(const QString &filePath); void sweep(); - QMap<QString, QString> referencingFiles() const; + QMap<QString, QString> testCaseNamesForFiles(QStringList files); signals: void testTreeModelChanged(); @@ -104,9 +104,9 @@ private: explicit TestTreeModel(QObject *parent = 0); void setupParsingConnections(); - TestTreeItem *m_autoTestRootItem; - TestTreeItem *m_quickTestRootItem; - TestTreeItem *m_googleTestRootItem; + AutoTestTreeItem *m_autoTestRootItem; + QuickTestTreeItem *m_quickTestRootItem; + GoogleTestTreeItem *m_googleTestRootItem; TestCodeParser *m_parser; bool m_connectionsInitialized; QAtomicInt m_refCounter; @@ -151,7 +151,7 @@ struct TestParseResult TestTreeModel::Type type; QString fileName; - QString referencingFile; + QString proFile; QString testCaseName; unsigned line = 0; unsigned column = 0; diff --git a/src/plugins/autotest/testvisitor.cpp b/src/plugins/autotest/testvisitor.cpp index 40819dfccd..d33d57c6b2 100644 --- a/src/plugins/autotest/testvisitor.cpp +++ b/src/plugins/autotest/testvisitor.cpp @@ -94,8 +94,7 @@ bool TestVisitor::visit(CPlusPlus::Class *symbol) else if (name.endsWith(QLatin1String("_data"))) locationAndType.m_type = TestTreeItem::TestDataFunction; else - locationAndType.m_type = TestTreeItem::TestFunction; - locationAndType.m_state = TestTreeItem::Enabled; + locationAndType.m_type = TestTreeItem::TestFunctionOrSet; m_privSlots.insert(name, locationAndType); } } @@ -225,7 +224,6 @@ bool TestDataFunctionVisitor::visit(CPlusPlus::CallAST *ast) locationAndType.m_column = column - 1; locationAndType.m_line = line; locationAndType.m_type = TestTreeItem::TestDataTag; - locationAndType.m_state = TestTreeItem::Enabled; m_currentTags.append(locationAndType); } } @@ -302,7 +300,7 @@ bool TestQmlVisitor::visit(QmlJS::AST::UiObjectDefinition *ast) m_testCaseLocation.m_name = m_currentDoc->fileName(); m_testCaseLocation.m_line = sourceLocation.startLine; m_testCaseLocation.m_column = sourceLocation.startColumn - 1; - m_testCaseLocation.m_type = TestTreeItem::TestClass; + m_testCaseLocation.m_type = TestTreeItem::TestCase; return true; } @@ -335,9 +333,8 @@ bool TestQmlVisitor::visit(QmlJS::AST::FunctionDeclaration *ast) else if (name.endsWith(QLatin1String("_data"))) locationAndType.m_type = TestTreeItem::TestDataFunction; else - locationAndType.m_type = TestTreeItem::TestFunction; + locationAndType.m_type = TestTreeItem::TestFunctionOrSet; - locationAndType.m_state = TestTreeItem::Enabled; m_testFunctions.insert(name.toString(), locationAndType); } return false; @@ -389,9 +386,9 @@ bool GTestVisitor::visit(CPlusPlus::FunctionDefinitionAST *ast) locationAndType.m_name = disabled ? testName.mid(9) : testName; locationAndType.m_line = line; locationAndType.m_column = column - 1; - locationAndType.m_type = TestTreeItem::GTestName; - locationAndType.m_state = (disabled || disabledCase) ? TestTreeItem::Disabled - : TestTreeItem::Enabled; + locationAndType.m_type = TestTreeItem::TestFunctionOrSet; + locationAndType.m_state = (disabled || disabledCase) ? GoogleTestTreeItem::Disabled + : GoogleTestTreeItem::Enabled; GTestCaseSpec spec; spec.testCaseName = disabledCase ? testCaseName.mid(9) : testCaseName; spec.parameterized = TestUtils::isGTestParameterized(prettyName); |