forked from qt-creator/qt-creator
Decouple code parser and model
Additionally some minor refactorings to increase readability. Change-Id: I0be120fcedcf31dbb0116d84f0d3c23cf95e7d91 Reviewed-by: Andre Poenitz <andre.poenitz@theqtcompany.com>
This commit is contained in:
@@ -19,8 +19,6 @@
|
|||||||
#include "autotestconstants.h"
|
#include "autotestconstants.h"
|
||||||
#include "testcodeparser.h"
|
#include "testcodeparser.h"
|
||||||
#include "testinfo.h"
|
#include "testinfo.h"
|
||||||
#include "testtreeitem.h"
|
|
||||||
#include "testtreemodel.h"
|
|
||||||
#include "testvisitor.h"
|
#include "testvisitor.h"
|
||||||
|
|
||||||
#include <coreplugin/progressmanager/progressmanager.h>
|
#include <coreplugin/progressmanager/progressmanager.h>
|
||||||
@@ -41,6 +39,7 @@
|
|||||||
#include <qmljs/qmljsdialect.h>
|
#include <qmljs/qmljsdialect.h>
|
||||||
#include <qmljstools/qmljsmodelmanager.h>
|
#include <qmljstools/qmljsmodelmanager.h>
|
||||||
|
|
||||||
|
#include <utils/qtcassert.h>
|
||||||
#include <utils/textfileformat.h>
|
#include <utils/textfileformat.h>
|
||||||
|
|
||||||
namespace Autotest {
|
namespace Autotest {
|
||||||
@@ -89,8 +88,7 @@ void TestCodeParser::updateTestTree()
|
|||||||
qDebug("updating TestTreeModel");
|
qDebug("updating TestTreeModel");
|
||||||
|
|
||||||
clearMaps();
|
clearMaps();
|
||||||
m_model->removeAllAutoTests();
|
emit cacheCleared();
|
||||||
m_model->removeAllQuickTests();
|
|
||||||
|
|
||||||
if (ProjectExplorer::Project *project = currentProject()) {
|
if (ProjectExplorer::Project *project = currentProject()) {
|
||||||
if (auto qmakeProject = qobject_cast<QmakeProjectManager::QmakeProject *>(project)) {
|
if (auto qmakeProject = qobject_cast<QmakeProjectManager::QmakeProject *>(project)) {
|
||||||
@@ -316,25 +314,24 @@ static CPlusPlus::Document::Ptr declaringDocument(CPlusPlus::Document::Ptr doc,
|
|||||||
return declaringDoc;
|
return declaringDoc;
|
||||||
}
|
}
|
||||||
|
|
||||||
static TestTreeItem *constructTestTreeItem(const QString &fileName,
|
static TestTreeItem constructTestTreeItem(const QString &fileName,
|
||||||
const QString &mainFile, // used for Quick Tests only
|
const QString &mainFile, // used for Quick Tests only
|
||||||
const QString &testCaseName,
|
const QString &testCaseName,
|
||||||
int line, int column,
|
int line, int column,
|
||||||
const QMap<QString, TestCodeLocationAndType> functions,
|
const QMap<QString, TestCodeLocationAndType> functions)
|
||||||
TestTreeItem *rootItem)
|
|
||||||
{
|
{
|
||||||
TestTreeItem *treeItem = new TestTreeItem(testCaseName, fileName, TestTreeItem::TEST_CLASS, rootItem);
|
TestTreeItem treeItem(testCaseName, fileName, TestTreeItem::TEST_CLASS);
|
||||||
treeItem->setMainFile(mainFile); // used for Quick Tests only
|
treeItem.setMainFile(mainFile); // used for Quick Tests only
|
||||||
treeItem->setLine(line);
|
treeItem.setLine(line);
|
||||||
treeItem->setColumn(column);
|
treeItem.setColumn(column);
|
||||||
|
|
||||||
foreach (const QString &functionName, functions.keys()) {
|
foreach (const QString &functionName, functions.keys()) {
|
||||||
const TestCodeLocationAndType locationAndType = functions.value(functionName);
|
const TestCodeLocationAndType locationAndType = functions.value(functionName);
|
||||||
TestTreeItem *treeItemChild = new TestTreeItem(functionName, locationAndType.m_fileName,
|
TestTreeItem *treeItemChild = new TestTreeItem(functionName, locationAndType.m_fileName,
|
||||||
locationAndType.m_type, treeItem);
|
locationAndType.m_type, &treeItem);
|
||||||
treeItemChild->setLine(locationAndType.m_line);
|
treeItemChild->setLine(locationAndType.m_line);
|
||||||
treeItemChild->setColumn(locationAndType.m_column);
|
treeItemChild->setColumn(locationAndType.m_column);
|
||||||
treeItem->appendChild(treeItemChild);
|
treeItem.appendChild(treeItemChild);
|
||||||
}
|
}
|
||||||
return treeItem;
|
return treeItem;
|
||||||
}
|
}
|
||||||
@@ -372,13 +369,9 @@ void TestCodeParser::checkDocumentForTestCode(CPlusPlus::Document::Ptr document)
|
|||||||
visitor.accept(declaringDoc->globalNamespace());
|
visitor.accept(declaringDoc->globalNamespace());
|
||||||
const QMap<QString, TestCodeLocationAndType> testFunctions = visitor.privateSlots();
|
const QMap<QString, TestCodeLocationAndType> testFunctions = visitor.privateSlots();
|
||||||
|
|
||||||
const QModelIndex autoTestRootIndex = m_model->index(0, 0);
|
TestTreeItem item = constructTestTreeItem(declaringDoc->fileName(), QString(),
|
||||||
TestTreeItem *autoTestRootItem = static_cast<TestTreeItem *>(autoTestRootIndex.internalPointer());
|
testCaseName, line, column, testFunctions);
|
||||||
|
updateModelAndCppDocMap(document, declaringDoc->fileName(), item);
|
||||||
TestTreeItem *ttItem = constructTestTreeItem(declaringDoc->fileName(), QString(),
|
|
||||||
testCaseName, line, column, testFunctions,
|
|
||||||
autoTestRootItem);
|
|
||||||
updateModelAndCppDocMap(document, declaringDoc->fileName(), ttItem, autoTestRootItem);
|
|
||||||
} else {
|
} else {
|
||||||
// could not find the class to test, but QTest is included and QT_TESTLIB_LIB defined
|
// could not find the class to test, but QTest is included and QT_TESTLIB_LIB defined
|
||||||
// maybe file is only a referenced file
|
// maybe file is only a referenced file
|
||||||
@@ -388,8 +381,8 @@ void TestCodeParser::checkDocumentForTestCode(CPlusPlus::Document::Ptr document)
|
|||||||
if (snapshot.contains(info.referencingFile())) {
|
if (snapshot.contains(info.referencingFile())) {
|
||||||
checkDocumentForTestCode(snapshot.find(info.referencingFile()).value());
|
checkDocumentForTestCode(snapshot.find(info.referencingFile()).value());
|
||||||
} else { // no referencing file too, so this test case is no more a test case
|
} else { // no referencing file too, so this test case is no more a test case
|
||||||
m_model->removeAutoTestSubtreeByFilePath(fileName);
|
|
||||||
m_cppDocMap.remove(fileName);
|
m_cppDocMap.remove(fileName);
|
||||||
|
emit testItemsRemoved(fileName, TestTreeModel::AutoTest);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -403,21 +396,15 @@ void TestCodeParser::handleQtQuickTest(CPlusPlus::Document::Ptr document)
|
|||||||
if (quickTestName(document).isEmpty())
|
if (quickTestName(document).isEmpty())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
const QString fileName = document->fileName();
|
const QString cppFileName = document->fileName();
|
||||||
const QString srcDir = quickTestSrcDir(modelManager, fileName);
|
const QString srcDir = quickTestSrcDir(modelManager, cppFileName);
|
||||||
if (srcDir.isEmpty())
|
if (srcDir.isEmpty())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
const QModelIndex quickTestRootIndex = m_model->index(1, 0);
|
|
||||||
TestTreeItem *quickTestRootItem = static_cast<TestTreeItem *>(quickTestRootIndex.internalPointer());
|
|
||||||
|
|
||||||
const QList<QmlJS::Document::Ptr> qmlDocs = scanDirectoryForQuickTestQmlFiles(srcDir);
|
const QList<QmlJS::Document::Ptr> qmlDocs = scanDirectoryForQuickTestQmlFiles(srcDir);
|
||||||
foreach (const QmlJS::Document::Ptr &qmlJSDoc, qmlDocs) {
|
foreach (const QmlJS::Document::Ptr &qmlJSDoc, qmlDocs) {
|
||||||
QmlJS::AST::Node *ast = qmlJSDoc->ast();
|
QmlJS::AST::Node *ast = qmlJSDoc->ast();
|
||||||
if (!ast) {
|
QTC_ASSERT(ast, continue);
|
||||||
qDebug() << "ast is zero pointer" << qmlJSDoc->fileName(); // should not happen
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
TestQmlVisitor qmlVisitor(qmlJSDoc);
|
TestQmlVisitor qmlVisitor(qmlJSDoc);
|
||||||
QmlJS::AST::Node::accept(ast, &qmlVisitor);
|
QmlJS::AST::Node::accept(ast, &qmlVisitor);
|
||||||
|
|
||||||
@@ -426,24 +413,18 @@ void TestCodeParser::handleQtQuickTest(CPlusPlus::Document::Ptr document)
|
|||||||
const QMap<QString, TestCodeLocationAndType> testFunctions = qmlVisitor.testFunctions();
|
const QMap<QString, TestCodeLocationAndType> testFunctions = qmlVisitor.testFunctions();
|
||||||
|
|
||||||
if (testCaseName.isEmpty()) {
|
if (testCaseName.isEmpty()) {
|
||||||
// remove found test functions before re-adding them
|
updateUnnamedQuickTests(qmlJSDoc->fileName(), cppFileName, testFunctions);
|
||||||
removeUnnamedQuickTests(qmlJSDoc->fileName(), testFunctions.keys());
|
|
||||||
// re-create TestTreeItem for unnamed Quick Tests
|
|
||||||
recreateUnnamedQuickTest(testFunctions, fileName, quickTestRootItem);
|
|
||||||
continue;
|
continue;
|
||||||
} // end of handling test cases without name property
|
} // end of handling test cases without name property
|
||||||
|
|
||||||
// construct new/modified TestTreeItem
|
// construct new/modified TestTreeItem
|
||||||
TestTreeItem *testTreeItem
|
TestTreeItem testTreeItem
|
||||||
= constructTestTreeItem(tcLocationAndType.m_fileName, fileName, testCaseName,
|
= constructTestTreeItem(tcLocationAndType.m_fileName, cppFileName, testCaseName,
|
||||||
tcLocationAndType.m_line, tcLocationAndType.m_column,
|
tcLocationAndType.m_line, tcLocationAndType.m_column,
|
||||||
testFunctions, quickTestRootItem);
|
testFunctions);
|
||||||
|
|
||||||
// update model and internal map
|
// update model and internal map
|
||||||
const QmlJS::Document::Ptr qmlDoc =
|
updateModelAndQuickDocMap(qmlJSDoc, cppFileName, testTreeItem);
|
||||||
QmlJSTools::Internal::ModelManager::instance()->snapshot().document(tcLocationAndType.m_fileName);
|
|
||||||
updateModelAndQuickDocMap(qmlDoc, qmlJSDoc->fileName(), fileName, testTreeItem,
|
|
||||||
quickTestRootItem);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -489,15 +470,9 @@ void TestCodeParser::onQmlDocumentUpdated(const QmlJS::Document::Ptr &document)
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
// special case of having unnamed TestCases
|
// special case of having unnamed TestCases
|
||||||
TestTreeItem *unnamed = m_model->unnamedQuickTests();
|
const QString &mainFile = m_model->getMainFileForUnnamedQuickTest(fileName);
|
||||||
for (int row = 0, count = unnamed->childCount(); row < count; ++row) {
|
if (!mainFile.isEmpty() && snapshot.contains(mainFile))
|
||||||
const TestTreeItem *child = unnamed->child(row);
|
checkDocumentForTestCode(snapshot.document(mainFile));
|
||||||
if (fileName == child->filePath()) {
|
|
||||||
if (snapshot.contains(child->mainFile()))
|
|
||||||
checkDocumentForTestCode(snapshot.document(child->mainFile()));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void TestCodeParser::removeFiles(const QStringList &files)
|
void TestCodeParser::removeFiles(const QStringList &files)
|
||||||
@@ -537,7 +512,7 @@ void TestCodeParser::removeTestsIfNecessary(const QString &fileName)
|
|||||||
// check if this file was listed before and remove if necessary (switched config,...)
|
// check if this file was listed before and remove if necessary (switched config,...)
|
||||||
if (m_cppDocMap.contains(fileName)) {
|
if (m_cppDocMap.contains(fileName)) {
|
||||||
m_cppDocMap.remove(fileName);
|
m_cppDocMap.remove(fileName);
|
||||||
m_model->removeAutoTestSubtreeByFilePath(fileName);
|
emit testItemsRemoved(fileName, TestTreeModel::AutoTest);
|
||||||
} else { // handle Qt Quick Tests
|
} else { // handle Qt Quick Tests
|
||||||
QList<QString> toBeRemoved;
|
QList<QString> toBeRemoved;
|
||||||
foreach (const QString &file, m_quickDocMap.keys()) {
|
foreach (const QString &file, m_quickDocMap.keys()) {
|
||||||
@@ -551,21 +526,15 @@ void TestCodeParser::removeTestsIfNecessary(const QString &fileName)
|
|||||||
}
|
}
|
||||||
foreach (const QString &file, toBeRemoved) {
|
foreach (const QString &file, toBeRemoved) {
|
||||||
m_quickDocMap.remove(file);
|
m_quickDocMap.remove(file);
|
||||||
m_model->removeQuickTestSubtreeByFilePath(file);
|
emit testItemsRemoved(file, TestTreeModel::QuickTest);
|
||||||
}
|
}
|
||||||
// unnamed Quick Tests must be handled separately
|
// unnamed Quick Tests must be handled separately
|
||||||
QSet<QString> filePaths;
|
QSet<QString> filePaths;
|
||||||
QList<QString> functionNames;
|
QList<QString> functionNames;
|
||||||
if (TestTreeItem *unnamedQT = m_model->unnamedQuickTests()) {
|
if (m_model->hasUnnamedQuickTests()) {
|
||||||
for (int i = 0; i < unnamedQT->childCount(); ++i) {
|
m_model->qmlFilesAndFunctionNamesForMainFile(fileName, &filePaths, &functionNames);
|
||||||
const TestTreeItem *child = unnamedQT->child(i);
|
|
||||||
if (child->mainFile() == fileName) {
|
|
||||||
filePaths.insert(child->filePath());
|
|
||||||
functionNames.append(child->name());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
foreach (const QString &file, filePaths)
|
foreach (const QString &file, filePaths)
|
||||||
m_model->removeUnnamedQuickTests(file);
|
emit testItemsRemoved(file, TestTreeModel::QuickTest);
|
||||||
// update info map
|
// update info map
|
||||||
TestInfo unnamedInfo = m_quickDocMap[tr(Constants::UNNAMED_QUICKTESTS)];
|
TestInfo unnamedInfo = m_quickDocMap[tr(Constants::UNNAMED_QUICKTESTS)];
|
||||||
QStringList functions = unnamedInfo.testFunctions();
|
QStringList functions = unnamedInfo.testFunctions();
|
||||||
@@ -576,6 +545,8 @@ void TestCodeParser::removeTestsIfNecessary(const QString &fileName)
|
|||||||
m_quickDocMap.remove(tr(Constants::UNNAMED_QUICKTESTS));
|
m_quickDocMap.remove(tr(Constants::UNNAMED_QUICKTESTS));
|
||||||
else
|
else
|
||||||
m_quickDocMap.insert(tr(Constants::UNNAMED_QUICKTESTS), unnamedInfo);
|
m_quickDocMap.insert(tr(Constants::UNNAMED_QUICKTESTS), unnamedInfo);
|
||||||
|
} else {
|
||||||
|
m_quickDocMap.remove(tr(Constants::UNNAMED_QUICKTESTS));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -589,7 +560,7 @@ void TestCodeParser::removeTestsIfNecessaryByProFile(const QString &proFile)
|
|||||||
}
|
}
|
||||||
foreach (const QString &fileName, fList) {
|
foreach (const QString &fileName, fList) {
|
||||||
m_cppDocMap.remove(fileName);
|
m_cppDocMap.remove(fileName);
|
||||||
m_model->removeAutoTestSubtreeByFilePath(fileName);
|
emit testItemsRemoved(fileName, TestTreeModel::AutoTest);
|
||||||
}
|
}
|
||||||
fList.clear();
|
fList.clear();
|
||||||
foreach (const QString &fileName, m_quickDocMap.keys()) {
|
foreach (const QString &fileName, m_quickDocMap.keys()) {
|
||||||
@@ -598,105 +569,23 @@ void TestCodeParser::removeTestsIfNecessaryByProFile(const QString &proFile)
|
|||||||
}
|
}
|
||||||
foreach (const QString &fileName, fList) {
|
foreach (const QString &fileName, fList) {
|
||||||
m_quickDocMap.remove(fileName);
|
m_quickDocMap.remove(fileName);
|
||||||
m_model->removeQuickTestSubtreeByFilePath(fileName);
|
emit testItemsRemoved(fileName, TestTreeModel::QuickTest);
|
||||||
}
|
}
|
||||||
// handle unnamed Quick Tests
|
// handle unnamed Quick Tests
|
||||||
fList.clear(); // will now be re-used as function names storage
|
const QSet<QString> &filePaths = m_model->qmlFilesForProFile(proFile);
|
||||||
QSet<QString> filePaths;
|
foreach (const QString &fileName, filePaths)
|
||||||
CppTools::CppModelManager *cppMM = CppTools::CppModelManager::instance();
|
emit unnamedQuickTestsRemoved(fileName);
|
||||||
if (TestTreeItem *unnamedQT = m_model->unnamedQuickTests()) {
|
|
||||||
for (int i = 0; i < unnamedQT->childCount(); ++i) {
|
|
||||||
const TestTreeItem *child = unnamedQT->child(i);
|
|
||||||
QList<CppTools::ProjectPart::Ptr> ppList = cppMM->projectPart(child->mainFile());
|
|
||||||
if (ppList.size() && ppList.at(0)->projectFile == proFile) {
|
|
||||||
filePaths.insert(child->filePath());
|
|
||||||
fList.append(child->name());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
foreach (const QString &filePath, filePaths) {
|
|
||||||
m_model->removeUnnamedQuickTests(filePath);
|
|
||||||
}
|
|
||||||
// update info map
|
// update info map
|
||||||
TestInfo unnamedInfo = m_quickDocMap[tr(Constants::UNNAMED_QUICKTESTS)];
|
TestInfo unnamedInfo = m_quickDocMap.value(tr(Constants::UNNAMED_QUICKTESTS),
|
||||||
QStringList functions = unnamedInfo.testFunctions();
|
TestInfo(QString(), QStringList(), 666));
|
||||||
foreach (const QString &function, fList)
|
|
||||||
functions.removeOne(function);
|
unnamedInfo.setTestFunctions(m_model->getUnnamedQuickTestFunctions());
|
||||||
unnamedInfo.setTestFunctions(functions);
|
if (unnamedInfo.testFunctions().isEmpty())
|
||||||
if (functions.size() == 0)
|
|
||||||
m_quickDocMap.remove(tr(Constants::UNNAMED_QUICKTESTS));
|
m_quickDocMap.remove(tr(Constants::UNNAMED_QUICKTESTS));
|
||||||
else
|
else
|
||||||
m_quickDocMap.insert(tr(Constants::UNNAMED_QUICKTESTS), unnamedInfo);
|
m_quickDocMap.insert(tr(Constants::UNNAMED_QUICKTESTS), unnamedInfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
void TestCodeParser::removeUnnamedQuickTests(const QString &fileName,
|
|
||||||
const QStringList &testFunctions)
|
|
||||||
{
|
|
||||||
// if this test case was named before remove it
|
|
||||||
if (m_quickDocMap.contains(fileName)) {
|
|
||||||
m_model->removeQuickTestSubtreeByFilePath(fileName);
|
|
||||||
m_quickDocMap.remove(fileName);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (m_model->unnamedQuickTests()) {
|
|
||||||
// remove unnamed quick tests that are already found for this qml file
|
|
||||||
if (m_model->removeUnnamedQuickTests(fileName)) {
|
|
||||||
// make sure m_quickDocMap does not have a inconsistent state now
|
|
||||||
TestInfo testInfo = m_quickDocMap[tr(Constants::UNNAMED_QUICKTESTS)];
|
|
||||||
QStringList testFunctionNames = testInfo.testFunctions();
|
|
||||||
foreach (const QString &func, testFunctions)
|
|
||||||
testFunctionNames.removeOne(func);
|
|
||||||
testInfo.setTestFunctions(testFunctionNames);
|
|
||||||
if (testFunctionNames.size() == 0)
|
|
||||||
m_quickDocMap.remove(tr(Constants::UNNAMED_QUICKTESTS));
|
|
||||||
else
|
|
||||||
m_quickDocMap.insert(tr(Constants::UNNAMED_QUICKTESTS), testInfo);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void TestCodeParser::recreateUnnamedQuickTest(const QMap<QString, TestCodeLocationAndType> &testFunctions,
|
|
||||||
const QString &mainFile, TestTreeItem *rootItem)
|
|
||||||
{
|
|
||||||
TestTreeItem *testTreeItem = new TestTreeItem(QString(), QString(), TestTreeItem::TEST_CLASS,
|
|
||||||
rootItem);
|
|
||||||
TestTreeItem *unnamedQTItem = m_model->unnamedQuickTests();
|
|
||||||
// if there are still other unnamed Quick Tests re-parent them to the new
|
|
||||||
if (unnamedQTItem) {
|
|
||||||
for (int i = 0, count = unnamedQTItem->childCount(); i < count; ++i) {
|
|
||||||
TestTreeItem *child = new TestTreeItem(*unnamedQTItem->child(i));
|
|
||||||
child->setParent(testTreeItem);
|
|
||||||
testTreeItem->appendChild(child);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// add test functions of the current
|
|
||||||
foreach (const QString &function, testFunctions.keys()) {
|
|
||||||
const TestCodeLocationAndType locationAndType = testFunctions.value(function);
|
|
||||||
TestTreeItem *testTreeFunction = new TestTreeItem(function, locationAndType.m_fileName,
|
|
||||||
locationAndType.m_type, testTreeItem);
|
|
||||||
testTreeFunction->setLine(locationAndType.m_line);
|
|
||||||
testTreeFunction->setColumn(locationAndType.m_column);
|
|
||||||
testTreeFunction->setMainFile(mainFile);
|
|
||||||
testTreeItem->appendChild(testTreeFunction);
|
|
||||||
}
|
|
||||||
|
|
||||||
TestInfo info = m_quickDocMap.contains(tr(Constants::UNNAMED_QUICKTESTS))
|
|
||||||
? m_quickDocMap[tr(Constants::UNNAMED_QUICKTESTS)]
|
|
||||||
: TestInfo(QString(), QStringList(), 666);
|
|
||||||
QStringList originalFunctions(info.testFunctions());
|
|
||||||
foreach (const QString &function, testFunctions.keys())
|
|
||||||
originalFunctions.append(function);
|
|
||||||
info.setTestFunctions(originalFunctions);
|
|
||||||
|
|
||||||
if (unnamedQTItem) {
|
|
||||||
m_model->modifyQuickTestSubtree(unnamedQTItem->row(), testTreeItem);
|
|
||||||
delete testTreeItem;
|
|
||||||
} else {
|
|
||||||
m_model->addQuickTest(testTreeItem);
|
|
||||||
}
|
|
||||||
m_quickDocMap.insert(tr(Constants::UNNAMED_QUICKTESTS), info);
|
|
||||||
}
|
|
||||||
|
|
||||||
void TestCodeParser::onTaskStarted(Core::Id type)
|
void TestCodeParser::onTaskStarted(Core::Id type)
|
||||||
{
|
{
|
||||||
if (type != CppTools::Constants::TASK_INDEX
|
if (type != CppTools::Constants::TASK_INDEX
|
||||||
@@ -715,13 +604,31 @@ void TestCodeParser::onAllTasksFinished(Core::Id type)
|
|||||||
updateTestTree();
|
updateTestTree();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void TestCodeParser::updateUnnamedQuickTests(const QString &fileName, const QString &mainFile,
|
||||||
|
const QMap<QString, TestCodeLocationAndType> &functions)
|
||||||
|
{
|
||||||
|
// if this test case was named before remove it
|
||||||
|
m_quickDocMap.remove(fileName);
|
||||||
|
emit testItemsRemoved(fileName, TestTreeModel::QuickTest);
|
||||||
|
|
||||||
|
emit unnamedQuickTestsUpdated(fileName, mainFile, functions);
|
||||||
|
|
||||||
|
if (m_model->hasUnnamedQuickTests()) {
|
||||||
|
TestInfo info = m_quickDocMap.value(tr(Constants::UNNAMED_QUICKTESTS),
|
||||||
|
TestInfo(QString(), QStringList(), 666));
|
||||||
|
info.setTestFunctions(m_model->getUnnamedQuickTestFunctions());
|
||||||
|
m_quickDocMap.insert(tr(Constants::UNNAMED_QUICKTESTS), info);
|
||||||
|
} else {
|
||||||
|
m_quickDocMap.remove(tr(Constants::UNNAMED_QUICKTESTS));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void TestCodeParser::updateModelAndCppDocMap(CPlusPlus::Document::Ptr document,
|
void TestCodeParser::updateModelAndCppDocMap(CPlusPlus::Document::Ptr document,
|
||||||
const QString &declFileName,
|
const QString &declaringFile, TestTreeItem &testItem)
|
||||||
TestTreeItem *testItem, TestTreeItem *rootItem)
|
|
||||||
{
|
{
|
||||||
const CppTools::CppModelManager *cppMM = CppTools::CppModelManager::instance();
|
const CppTools::CppModelManager *cppMM = CppTools::CppModelManager::instance();
|
||||||
const QString fileName = document->fileName();
|
const QString fileName = document->fileName();
|
||||||
const QString testCaseName = testItem->name();
|
const QString testCaseName = testItem.name();
|
||||||
QString proFile;
|
QString proFile;
|
||||||
const QList<CppTools::ProjectPart::Ptr> ppList = cppMM->projectPart(fileName);
|
const QList<CppTools::ProjectPart::Ptr> ppList = cppMM->projectPart(fileName);
|
||||||
if (ppList.size())
|
if (ppList.size())
|
||||||
@@ -729,71 +636,57 @@ void TestCodeParser::updateModelAndCppDocMap(CPlusPlus::Document::Ptr document,
|
|||||||
|
|
||||||
if (m_cppDocMap.contains(fileName)) {
|
if (m_cppDocMap.contains(fileName)) {
|
||||||
QStringList files = QStringList() << fileName;
|
QStringList files = QStringList() << fileName;
|
||||||
if (fileName != declFileName)
|
if (fileName != declaringFile)
|
||||||
files << declFileName;
|
files << declaringFile;
|
||||||
foreach (const QString &file, files) {
|
foreach (const QString &file, files) {
|
||||||
const bool setReferencingFile = (files.size() == 2 && file == declFileName);
|
const bool setReferencingFile = (files.size() == 2 && file == declaringFile);
|
||||||
const int count = rootItem->childCount();
|
emit testItemModified(testItem, TestTreeModel::AutoTest, file);
|
||||||
for (int i = 0; i < count; ++i) {
|
TestInfo testInfo(testCaseName, testItem.getChildNames(),
|
||||||
TestTreeItem *currentItem = rootItem->child(i);
|
|
||||||
if (currentItem->filePath() == file) {
|
|
||||||
m_model->modifyAutoTestSubtree(i, testItem);
|
|
||||||
TestInfo testInfo(testCaseName, testItem->getChildNames(),
|
|
||||||
document->revision(), document->editorRevision());
|
document->revision(), document->editorRevision());
|
||||||
testInfo.setProfile(proFile);
|
testInfo.setProfile(proFile);
|
||||||
if (setReferencingFile)
|
if (setReferencingFile)
|
||||||
testInfo.setReferencingFile(fileName);
|
testInfo.setReferencingFile(fileName);
|
||||||
m_cppDocMap.insert(file, testInfo);
|
m_cppDocMap.insert(file, testInfo);
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
delete testItem; // this item is no more needed as model updates the original with its content
|
|
||||||
} else {
|
} else {
|
||||||
m_model->addAutoTest(testItem);
|
emit testItemCreated(testItem, TestTreeModel::AutoTest);
|
||||||
TestInfo ti(testCaseName, testItem->getChildNames(),
|
TestInfo ti(testCaseName, testItem.getChildNames(),
|
||||||
document->revision(), document->editorRevision());
|
document->revision(), document->editorRevision());
|
||||||
ti.setProfile(proFile);
|
ti.setProfile(proFile);
|
||||||
m_cppDocMap.insert(fileName, ti);
|
m_cppDocMap.insert(fileName, ti);
|
||||||
if (declFileName != fileName) {
|
if (declaringFile != fileName) {
|
||||||
ti.setReferencingFile(fileName);
|
ti.setReferencingFile(fileName);
|
||||||
m_cppDocMap.insert(declFileName, ti);
|
m_cppDocMap.insert(declaringFile, ti);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void TestCodeParser::updateModelAndQuickDocMap(QmlJS::Document::Ptr qmlDoc, const QString ¤tQmlJSFile,
|
void TestCodeParser::updateModelAndQuickDocMap(QmlJS::Document::Ptr document,
|
||||||
const QString &referencingFileName,
|
const QString &referencingFile,
|
||||||
TestTreeItem *testItem, TestTreeItem *rootItem)
|
TestTreeItem &testItem)
|
||||||
{
|
{
|
||||||
const CppTools::CppModelManager *cppMM = CppTools::CppModelManager::instance();
|
const CppTools::CppModelManager *cppMM = CppTools::CppModelManager::instance();
|
||||||
const QString fileName = qmlDoc->fileName();
|
const QString fileName = document->fileName();
|
||||||
QString proFile;
|
QString proFile;
|
||||||
QList<CppTools::ProjectPart::Ptr> ppList = cppMM->projectPart(referencingFileName);
|
QList<CppTools::ProjectPart::Ptr> ppList = cppMM->projectPart(referencingFile);
|
||||||
if (ppList.size())
|
if (ppList.size())
|
||||||
proFile = ppList.at(0)->projectFile;
|
proFile = ppList.at(0)->projectFile;
|
||||||
|
|
||||||
if (m_quickDocMap.contains(fileName)) {
|
if (m_quickDocMap.contains(fileName)) {
|
||||||
for (int i = 0; i < rootItem->childCount(); ++i) {
|
emit testItemModified(testItem, TestTreeModel::QuickTest, fileName);
|
||||||
if (rootItem->child(i)->filePath() == fileName) {
|
TestInfo testInfo(testItem.name(), testItem.getChildNames(), 0, document->editorRevision());
|
||||||
m_model->modifyQuickTestSubtree(i, testItem);
|
testInfo.setReferencingFile(referencingFile);
|
||||||
TestInfo testInfo(testItem->name(), testItem->getChildNames(), 0, qmlDoc->editorRevision());
|
|
||||||
testInfo.setReferencingFile(referencingFileName);
|
|
||||||
testInfo.setProfile(proFile);
|
testInfo.setProfile(proFile);
|
||||||
m_quickDocMap.insert(fileName, testInfo);
|
m_quickDocMap.insert(fileName, testInfo);
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
delete testItem; // this item is no more needed as model updates the original with its content
|
|
||||||
} else {
|
} else {
|
||||||
// if it was formerly unnamed remove the respective items
|
// if it was formerly unnamed remove the respective items
|
||||||
removeUnnamedQuickTests(currentQmlJSFile, testItem->getChildNames());
|
emit unnamedQuickTestsRemoved(fileName);
|
||||||
|
|
||||||
m_model->addQuickTest(testItem);
|
emit testItemCreated(testItem, TestTreeModel::QuickTest);
|
||||||
TestInfo testInfo(testItem->name(), testItem->getChildNames(), 0, qmlDoc->editorRevision());
|
TestInfo testInfo(testItem.name(), testItem.getChildNames(), 0, document->editorRevision());
|
||||||
testInfo.setReferencingFile(referencingFileName);
|
testInfo.setReferencingFile(referencingFile);
|
||||||
testInfo.setProfile(proFile);
|
testInfo.setProfile(proFile);
|
||||||
m_quickDocMap.insert(testItem->filePath(), testInfo);
|
m_quickDocMap.insert(testItem.filePath(), testInfo);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -19,6 +19,9 @@
|
|||||||
#ifndef TESTCODEPARSER_H
|
#ifndef TESTCODEPARSER_H
|
||||||
#define TESTCODEPARSER_H
|
#define TESTCODEPARSER_H
|
||||||
|
|
||||||
|
#include "testtreeitem.h"
|
||||||
|
#include "testtreemodel.h"
|
||||||
|
|
||||||
#include <cplusplus/CppDocument.h>
|
#include <cplusplus/CppDocument.h>
|
||||||
|
|
||||||
#include <qmljs/qmljsdocument.h>
|
#include <qmljs/qmljsdocument.h>
|
||||||
@@ -35,8 +38,6 @@ namespace Internal {
|
|||||||
|
|
||||||
struct TestCodeLocationAndType;
|
struct TestCodeLocationAndType;
|
||||||
class TestInfo;
|
class TestInfo;
|
||||||
class TestTreeModel;
|
|
||||||
class TestTreeItem;
|
|
||||||
|
|
||||||
class TestCodeParser : public QObject
|
class TestCodeParser : public QObject
|
||||||
{
|
{
|
||||||
@@ -46,6 +47,14 @@ public:
|
|||||||
virtual ~TestCodeParser();
|
virtual ~TestCodeParser();
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
|
void cacheCleared();
|
||||||
|
void testItemCreated(const TestTreeItem &item, TestTreeModel::Type type);
|
||||||
|
void testItemsCreated(const QList<TestTreeItem> &itemList, TestTreeModel::Type type);
|
||||||
|
void testItemModified(TestTreeItem tItem, TestTreeModel::Type type, const QString &file);
|
||||||
|
void testItemsRemoved(const QString &filePath, TestTreeModel::Type type);
|
||||||
|
void unnamedQuickTestsUpdated(const QString &filePath, const QString &mainFile,
|
||||||
|
const QMap<QString, TestCodeLocationAndType> &functions);
|
||||||
|
void unnamedQuickTestsRemoved(const QString &filePath);
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void emitUpdateTestTree();
|
void emitUpdateTestTree();
|
||||||
@@ -63,16 +72,15 @@ private:
|
|||||||
void clearMaps();
|
void clearMaps();
|
||||||
void removeTestsIfNecessary(const QString &fileName);
|
void removeTestsIfNecessary(const QString &fileName);
|
||||||
void removeTestsIfNecessaryByProFile(const QString &proFile);
|
void removeTestsIfNecessaryByProFile(const QString &proFile);
|
||||||
void removeUnnamedQuickTests(const QString &fileName, const QStringList &testFunctions);
|
|
||||||
void recreateUnnamedQuickTest(const QMap<QString, TestCodeLocationAndType> &testFunctions,
|
|
||||||
const QString &mainFile, TestTreeItem *rootItem);
|
|
||||||
void onTaskStarted(Core::Id type);
|
void onTaskStarted(Core::Id type);
|
||||||
void onAllTasksFinished(Core::Id type);
|
void onAllTasksFinished(Core::Id type);
|
||||||
void updateModelAndCppDocMap(CPlusPlus::Document::Ptr document, const QString &declFileName,
|
void updateUnnamedQuickTests(const QString &fileName, const QString &mainFile,
|
||||||
TestTreeItem *testItem, TestTreeItem *rootItem);
|
const QMap<QString, TestCodeLocationAndType> &functions);
|
||||||
void updateModelAndQuickDocMap(QmlJS::Document::Ptr qmlDoc, const QString ¤tQmlJSFile,
|
void updateModelAndCppDocMap(CPlusPlus::Document::Ptr document,
|
||||||
const QString &referencingFileName,
|
const QString &declaringFile, TestTreeItem &testItem);
|
||||||
TestTreeItem *testItem, TestTreeItem *rootItem);
|
void updateModelAndQuickDocMap(QmlJS::Document::Ptr document,
|
||||||
|
const QString &referencingFile, TestTreeItem &testItem);
|
||||||
|
|
||||||
TestTreeModel *m_model;
|
TestTreeModel *m_model;
|
||||||
QMap<QString, TestInfo> m_cppDocMap;
|
QMap<QString, TestInfo> m_cppDocMap;
|
||||||
|
|||||||
@@ -71,7 +71,7 @@ TestTreeItem::TestTreeItem(const TestTreeItem &other)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
TestTreeItem *TestTreeItem::child(int row)
|
TestTreeItem *TestTreeItem::child(int row) const
|
||||||
{
|
{
|
||||||
return m_children.at(row);
|
return m_children.at(row);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -41,7 +41,7 @@ public:
|
|||||||
virtual ~TestTreeItem();
|
virtual ~TestTreeItem();
|
||||||
TestTreeItem(const TestTreeItem& other);
|
TestTreeItem(const TestTreeItem& other);
|
||||||
|
|
||||||
TestTreeItem *child(int row);
|
TestTreeItem *child(int row) const;
|
||||||
TestTreeItem *parent() const;
|
TestTreeItem *parent() const;
|
||||||
void appendChild(TestTreeItem *child);
|
void appendChild(TestTreeItem *child);
|
||||||
int row() const;
|
int row() const;
|
||||||
@@ -80,6 +80,13 @@ private:
|
|||||||
QList<TestTreeItem *> m_children;
|
QList<TestTreeItem *> m_children;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct TestCodeLocationAndType {
|
||||||
|
QString m_fileName;
|
||||||
|
unsigned m_line;
|
||||||
|
unsigned m_column;
|
||||||
|
TestTreeItem::Type m_type;
|
||||||
|
};
|
||||||
|
|
||||||
} // namespace Internal
|
} // namespace Internal
|
||||||
} // namespace Autotest
|
} // namespace Autotest
|
||||||
|
|
||||||
|
|||||||
@@ -50,6 +50,17 @@ TestTreeModel::TestTreeModel(QObject *parent) :
|
|||||||
{
|
{
|
||||||
m_rootItem->appendChild(m_autoTestRootItem);
|
m_rootItem->appendChild(m_autoTestRootItem);
|
||||||
m_rootItem->appendChild(m_quickTestRootItem);
|
m_rootItem->appendChild(m_quickTestRootItem);
|
||||||
|
|
||||||
|
connect(m_parser, &TestCodeParser::cacheCleared, this, &TestTreeModel::removeAllTestItems);
|
||||||
|
connect(m_parser, &TestCodeParser::testItemCreated, this, &TestTreeModel::addTestTreeItem);
|
||||||
|
connect(m_parser, &TestCodeParser::testItemsCreated, this, &TestTreeModel::addTestTreeItems);
|
||||||
|
connect(m_parser, &TestCodeParser::testItemModified, this, &TestTreeModel::modifyTestTreeItem);
|
||||||
|
connect(m_parser, &TestCodeParser::testItemsRemoved, this, &TestTreeModel::removeTestTreeItems);
|
||||||
|
connect(m_parser, &TestCodeParser::unnamedQuickTestsUpdated,
|
||||||
|
this, &TestTreeModel::updateUnnamedQuickTest);
|
||||||
|
connect(m_parser, &TestCodeParser::unnamedQuickTestsRemoved,
|
||||||
|
this, &TestTreeModel::removeUnnamedQuickTests);
|
||||||
|
|
||||||
m_parser->updateTestTree();
|
m_parser->updateTestTree();
|
||||||
|
|
||||||
// CppTools::CppModelManagerInterface *cppMM = CppTools::CppModelManagerInterface::instance();
|
// CppTools::CppModelManagerInterface *cppMM = CppTools::CppModelManagerInterface::instance();
|
||||||
@@ -524,6 +535,62 @@ QList<TestConfiguration *> TestTreeModel::getSelectedTests() const
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QString TestTreeModel::getMainFileForUnnamedQuickTest(const QString &qmlFile) const
|
||||||
|
{
|
||||||
|
const TestTreeItem *unnamed = unnamedQuickTests();
|
||||||
|
for (int row = 0, count = unnamed->childCount(); row < count; ++row) {
|
||||||
|
const TestTreeItem *child = unnamed->child(row);
|
||||||
|
if (qmlFile == child->filePath())
|
||||||
|
return child->mainFile();
|
||||||
|
}
|
||||||
|
return QString();
|
||||||
|
}
|
||||||
|
|
||||||
|
void TestTreeModel::qmlFilesAndFunctionNamesForMainFile(const QString &mainFile,
|
||||||
|
QSet<QString> *filePaths,
|
||||||
|
QList<QString> *functionNames) const
|
||||||
|
{
|
||||||
|
TestTreeItem *unnamed = unnamedQuickTests();
|
||||||
|
for (int i = 0; i < unnamed->childCount(); ++i) {
|
||||||
|
const TestTreeItem *child = unnamed->child(i);
|
||||||
|
if (child->mainFile() == mainFile) {
|
||||||
|
filePaths->insert(child->filePath());
|
||||||
|
functionNames->append(child->name());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QList<QString> TestTreeModel::getUnnamedQuickTestFunctions() const
|
||||||
|
{
|
||||||
|
TestTreeItem *unnamed = unnamedQuickTests();
|
||||||
|
if (unnamed)
|
||||||
|
return unnamed->getChildNames();
|
||||||
|
return QList<QString>();
|
||||||
|
}
|
||||||
|
|
||||||
|
QSet<QString> TestTreeModel::qmlFilesForProFile(const QString &proFile) const
|
||||||
|
{
|
||||||
|
QSet<QString> filePaths;
|
||||||
|
CppTools::CppModelManager *modelManager = CppTools::CppModelManager::instance();
|
||||||
|
if (TestTreeItem *unnamed = unnamedQuickTests()) {
|
||||||
|
for (int i = 0; i < unnamed->childCount(); ++i) {
|
||||||
|
const TestTreeItem *child = unnamed->child(i);
|
||||||
|
QList<CppTools::ProjectPart::Ptr> ppList = modelManager->projectPart(child->mainFile());
|
||||||
|
if (ppList.size() && ppList.at(0)->projectFile == proFile)
|
||||||
|
filePaths.insert(child->filePath());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return filePaths;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool TestTreeModel::hasUnnamedQuickTests() const
|
||||||
|
{
|
||||||
|
for (int row = 0, count = m_quickTestRootItem->childCount(); row < count; ++row)
|
||||||
|
if (m_quickTestRootItem->child(row)->name().isEmpty())
|
||||||
|
return true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
TestTreeItem *TestTreeModel::unnamedQuickTests() const
|
TestTreeItem *TestTreeModel::unnamedQuickTests() const
|
||||||
{
|
{
|
||||||
for (int row = 0, count = m_quickTestRootItem->childCount(); row < count; ++row) {
|
for (int row = 0, count = m_quickTestRootItem->childCount(); row < count; ++row) {
|
||||||
@@ -534,163 +601,202 @@ TestTreeItem *TestTreeModel::unnamedQuickTests() const
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void TestTreeModel::modifyAutoTestSubtree(int row, TestTreeItem *newItem)
|
void TestTreeModel::removeUnnamedQuickTests(const QString &filePath)
|
||||||
{
|
|
||||||
QModelIndex toBeModifiedIndex = index(0, 0).child(row, 0);
|
|
||||||
modifyTestSubtree(toBeModifiedIndex, newItem);
|
|
||||||
}
|
|
||||||
|
|
||||||
void TestTreeModel::removeAutoTestSubtreeByFilePath(const QString &file)
|
|
||||||
{
|
|
||||||
const QModelIndex atRootIndex = index(0, 0);
|
|
||||||
const int count = rowCount(atRootIndex);
|
|
||||||
for (int row = 0; row < count; ++row) {
|
|
||||||
const QModelIndex childIndex = atRootIndex.child(row, 0);
|
|
||||||
TestTreeItem *childItem = static_cast<TestTreeItem *>(childIndex.internalPointer());
|
|
||||||
if (file == childItem->filePath()) {
|
|
||||||
removeRow(row, atRootIndex);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
emit testTreeModelChanged();
|
|
||||||
}
|
|
||||||
|
|
||||||
void TestTreeModel::addAutoTest(TestTreeItem *newItem)
|
|
||||||
{
|
|
||||||
beginInsertRows(index(0, 0), m_autoTestRootItem->childCount(), m_autoTestRootItem->childCount());
|
|
||||||
m_autoTestRootItem->appendChild(newItem);
|
|
||||||
endInsertRows();
|
|
||||||
emit testTreeModelChanged();
|
|
||||||
}
|
|
||||||
|
|
||||||
void TestTreeModel::removeAllAutoTests()
|
|
||||||
{
|
|
||||||
beginResetModel();
|
|
||||||
m_autoTestRootItem->removeChildren();
|
|
||||||
endResetModel();
|
|
||||||
emit testTreeModelChanged();
|
|
||||||
}
|
|
||||||
|
|
||||||
void TestTreeModel::modifyQuickTestSubtree(int row, TestTreeItem *newItem)
|
|
||||||
{
|
|
||||||
QModelIndex toBeModifiedIndex = index(1, 0).child(row, 0);
|
|
||||||
modifyTestSubtree(toBeModifiedIndex, newItem);
|
|
||||||
}
|
|
||||||
|
|
||||||
void TestTreeModel::removeQuickTestSubtreeByFilePath(const QString &file)
|
|
||||||
{
|
|
||||||
const QModelIndex qtRootIndex = index(1, 0);
|
|
||||||
for (int row = 0, count = rowCount(qtRootIndex); row < count; ++row) {
|
|
||||||
const QModelIndex childIndex = qtRootIndex.child(row, 0);
|
|
||||||
const TestTreeItem *childItem = static_cast<TestTreeItem *>(childIndex.internalPointer());
|
|
||||||
if (file == childItem->filePath()) {
|
|
||||||
removeRow(row, qtRootIndex);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
emit testTreeModelChanged();
|
|
||||||
}
|
|
||||||
|
|
||||||
void TestTreeModel::addQuickTest(TestTreeItem *newItem)
|
|
||||||
{
|
|
||||||
beginInsertRows(index(1, 0), m_quickTestRootItem->childCount(), m_quickTestRootItem->childCount());
|
|
||||||
m_quickTestRootItem->appendChild(newItem);
|
|
||||||
endInsertRows();
|
|
||||||
emit testTreeModelChanged();
|
|
||||||
}
|
|
||||||
|
|
||||||
void TestTreeModel::removeAllQuickTests()
|
|
||||||
{
|
|
||||||
beginResetModel();
|
|
||||||
m_quickTestRootItem->removeChildren();
|
|
||||||
endResetModel();
|
|
||||||
emit testTreeModelChanged();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool TestTreeModel::removeUnnamedQuickTests(const QString &filePath)
|
|
||||||
{
|
{
|
||||||
TestTreeItem *unnamedQT = unnamedQuickTests();
|
TestTreeItem *unnamedQT = unnamedQuickTests();
|
||||||
if (!unnamedQT)
|
if (!unnamedQT)
|
||||||
return false;
|
return;
|
||||||
|
|
||||||
bool removed = false;
|
|
||||||
const QModelIndex unnamedQTIndex = index(1, 0).child(unnamedQT->row(), 0);
|
const QModelIndex unnamedQTIndex = index(1, 0).child(unnamedQT->row(), 0);
|
||||||
for (int childRow = unnamedQT->childCount() - 1; childRow >= 0; --childRow) {
|
for (int childRow = unnamedQT->childCount() - 1; childRow >= 0; --childRow) {
|
||||||
const TestTreeItem *child = unnamedQT->child(childRow);
|
const TestTreeItem *child = unnamedQT->child(childRow);
|
||||||
if (filePath == child->filePath())
|
if (filePath == child->filePath())
|
||||||
removed |= removeRow(childRow, unnamedQTIndex);
|
removeRow(childRow, unnamedQTIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (unnamedQT->childCount() == 0)
|
if (unnamedQT->childCount() == 0)
|
||||||
removeRow(unnamedQT->row(), unnamedQTIndex.parent());
|
removeRow(unnamedQT->row(), unnamedQTIndex.parent());
|
||||||
emit testTreeModelChanged();
|
emit testTreeModelChanged();
|
||||||
return removed;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void TestTreeModel::modifyTestSubtree(QModelIndex &toBeModifiedIndex, TestTreeItem *newItem)
|
void TestTreeModel::addTestTreeItem(const TestTreeItem &item, TestTreeModel::Type type)
|
||||||
|
{
|
||||||
|
TestTreeItem *parent = rootItemForType(type);
|
||||||
|
QModelIndex index = rootIndexForType(type);
|
||||||
|
TestTreeItem *toBeAdded = new TestTreeItem(item);
|
||||||
|
toBeAdded->setParent(parent);
|
||||||
|
|
||||||
|
beginInsertRows(index, parent->childCount(), parent->childCount());
|
||||||
|
parent->appendChild(toBeAdded);
|
||||||
|
endInsertRows();
|
||||||
|
emit testTreeModelChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
void TestTreeModel::addTestTreeItems(const QList<TestTreeItem> &itemList, TestTreeModel::Type type)
|
||||||
|
{
|
||||||
|
TestTreeItem *parent = rootItemForType(type);
|
||||||
|
QModelIndex index = rootIndexForType(type);
|
||||||
|
|
||||||
|
beginInsertRows(index, parent->childCount(), parent->childCount() + itemList.size() - 1);
|
||||||
|
foreach (const TestTreeItem &item, itemList) {
|
||||||
|
TestTreeItem *toBeAdded = new TestTreeItem(item);
|
||||||
|
toBeAdded->setParent(parent);
|
||||||
|
parent->appendChild(toBeAdded);
|
||||||
|
}
|
||||||
|
endInsertRows();
|
||||||
|
emit testTreeModelChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
void TestTreeModel::updateUnnamedQuickTest(const QString &fileName, const QString &mainFile,
|
||||||
|
const QMap<QString, TestCodeLocationAndType> &functions)
|
||||||
|
{
|
||||||
|
removeUnnamedQuickTests(fileName);
|
||||||
|
TestTreeItem unnamed = hasUnnamedQuickTests()
|
||||||
|
? TestTreeItem(*unnamedQuickTests())
|
||||||
|
: TestTreeItem(QString(), QString(), TestTreeItem::TEST_CLASS, rootItemForType(QuickTest));
|
||||||
|
|
||||||
|
foreach (const QString &functionName, functions.keys()) {
|
||||||
|
const TestCodeLocationAndType locationAndType = functions.value(functionName);
|
||||||
|
TestTreeItem *testFunction = new TestTreeItem(functionName, locationAndType.m_fileName,
|
||||||
|
locationAndType.m_type, &unnamed);
|
||||||
|
testFunction->setLine(locationAndType.m_line);
|
||||||
|
testFunction->setColumn(locationAndType.m_column);
|
||||||
|
testFunction->setMainFile(mainFile);
|
||||||
|
unnamed.appendChild(testFunction);
|
||||||
|
}
|
||||||
|
if (hasUnnamedQuickTests())
|
||||||
|
modifyTestTreeItem(unnamed, QuickTest, QString());
|
||||||
|
else
|
||||||
|
addTestTreeItem(unnamed, QuickTest);
|
||||||
|
}
|
||||||
|
|
||||||
|
void TestTreeModel::modifyTestTreeItem(TestTreeItem item, TestTreeModel::Type type, const QString &file)
|
||||||
|
{
|
||||||
|
QModelIndex index = rootIndexForType(type);
|
||||||
|
TestTreeItem *parent = rootItemForType(type);
|
||||||
|
item.setParent(parent);
|
||||||
|
if (file.isEmpty()) {
|
||||||
|
if (TestTreeItem *unnamed = unnamedQuickTests()) {
|
||||||
|
index = index.child(unnamed->row(), 0);
|
||||||
|
modifyTestSubtree(index, item);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for (int row = 0; row < parent->childCount(); ++row) {
|
||||||
|
if (parent->child(row)->filePath() == file) {
|
||||||
|
index = index.child(row, 0);
|
||||||
|
modifyTestSubtree(index, item);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void TestTreeModel::removeAllTestItems()
|
||||||
|
{
|
||||||
|
beginResetModel();
|
||||||
|
m_autoTestRootItem->removeChildren();
|
||||||
|
m_quickTestRootItem->removeChildren();
|
||||||
|
endResetModel();
|
||||||
|
emit testTreeModelChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
void TestTreeModel::removeTestTreeItems(const QString &filePath, Type type)
|
||||||
|
{
|
||||||
|
bool removed = false;
|
||||||
|
const QModelIndex rootIndex = rootIndexForType(type);
|
||||||
|
const int count = rowCount(rootIndex);
|
||||||
|
for (int row = count - 1; row >= 0; --row) {
|
||||||
|
const QModelIndex childIndex = rootIndex.child(row, 0);
|
||||||
|
TestTreeItem *childItem = static_cast<TestTreeItem *>(childIndex.internalPointer());
|
||||||
|
if (filePath == childItem->filePath())
|
||||||
|
removed |= removeRow(row, rootIndex);
|
||||||
|
}
|
||||||
|
if (removed)
|
||||||
|
emit testTreeModelChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
TestTreeItem *TestTreeModel::rootItemForType(TestTreeModel::Type type)
|
||||||
|
{
|
||||||
|
switch (type) {
|
||||||
|
case AutoTest:
|
||||||
|
return m_autoTestRootItem;
|
||||||
|
case QuickTest:
|
||||||
|
return m_quickTestRootItem;
|
||||||
|
}
|
||||||
|
QTC_ASSERT(false, return 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
QModelIndex TestTreeModel::rootIndexForType(TestTreeModel::Type type)
|
||||||
|
{
|
||||||
|
switch (type) {
|
||||||
|
case AutoTest:
|
||||||
|
return index(0, 0);
|
||||||
|
case QuickTest:
|
||||||
|
return index(1, 0);
|
||||||
|
}
|
||||||
|
QTC_ASSERT(false, return QModelIndex());
|
||||||
|
}
|
||||||
|
|
||||||
|
void TestTreeModel::modifyTestSubtree(QModelIndex &toBeModifiedIndex, const TestTreeItem &newItem)
|
||||||
|
|
||||||
{
|
{
|
||||||
if (!toBeModifiedIndex.isValid())
|
if (!toBeModifiedIndex.isValid())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
static QVector<int> modificationRoles = QVector<int>() << Qt::DisplayRole
|
|
||||||
<< Qt::ToolTipRole << LinkRole;
|
|
||||||
TestTreeItem *toBeModifiedItem = static_cast<TestTreeItem *>(toBeModifiedIndex.internalPointer());
|
TestTreeItem *toBeModifiedItem = static_cast<TestTreeItem *>(toBeModifiedIndex.internalPointer());
|
||||||
if (toBeModifiedItem->modifyContent(newItem))
|
if (toBeModifiedItem->modifyContent(&newItem))
|
||||||
emit dataChanged(toBeModifiedIndex, toBeModifiedIndex, modificationRoles);
|
emit dataChanged(toBeModifiedIndex, toBeModifiedIndex,
|
||||||
|
QVector<int>() << Qt::DisplayRole << Qt::ToolTipRole << LinkRole);
|
||||||
|
|
||||||
// process sub-items as well...
|
// process sub-items as well...
|
||||||
const int childCount = toBeModifiedItem->childCount();
|
const int childCount = toBeModifiedItem->childCount();
|
||||||
const int newChildCount = newItem->childCount();
|
const int newChildCount = newItem.childCount();
|
||||||
|
|
||||||
// for keeping the CheckState on modifications
|
// for keeping the CheckState on modifications
|
||||||
// TODO might still fail for duplicate entries (e.g. unnamed Quick Tests)
|
// TODO might still fail for duplicate entries
|
||||||
QHash<QString, Qt::CheckState> originalItems;
|
QHash<QString, Qt::CheckState> checkStates;
|
||||||
for (int row = 0; row < childCount; ++row) {
|
for (int row = 0; row < childCount; ++row) {
|
||||||
const TestTreeItem *child = toBeModifiedItem->child(row);
|
const TestTreeItem *child = toBeModifiedItem->child(row);
|
||||||
originalItems.insert(child->name(), child->checked());
|
checkStates.insert(child->name(), child->checked());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (childCount <= newChildCount) {
|
if (childCount <= newChildCount) {
|
||||||
for (int row = 0; row < childCount; ++row) {
|
processChildren(toBeModifiedIndex, newItem, childCount, checkStates);
|
||||||
QModelIndex child = toBeModifiedIndex.child(row, 0);
|
// add additional items
|
||||||
TestTreeItem *toBeModifiedChild = toBeModifiedItem->child(row);
|
|
||||||
TestTreeItem *modifiedChild = newItem->child(row);
|
|
||||||
if (toBeModifiedChild->modifyContent(modifiedChild)) {
|
|
||||||
emit dataChanged(child, child, modificationRoles);
|
|
||||||
}
|
|
||||||
if (originalItems.contains(toBeModifiedChild->name())) {
|
|
||||||
Qt::CheckState state = originalItems.value(toBeModifiedChild->name());
|
|
||||||
if (state != toBeModifiedChild->checked()) {
|
|
||||||
toBeModifiedChild->setChecked(state);
|
|
||||||
emit dataChanged(child, child, QVector<int>() << Qt::CheckStateRole);
|
|
||||||
}
|
|
||||||
} else { // newly added (BAD: happens for renaming as well)
|
|
||||||
toBeModifiedChild->setChecked(Qt::Checked);
|
|
||||||
emit dataChanged(child, child, QVector<int>() << Qt::CheckStateRole);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (childCount < newChildCount) { // add aditional items
|
|
||||||
for (int row = childCount; row < newChildCount; ++row) {
|
for (int row = childCount; row < newChildCount; ++row) {
|
||||||
TestTreeItem *newChild = newItem->child(row);
|
TestTreeItem *newChild = newItem.child(row);
|
||||||
TestTreeItem *toBeAdded = new TestTreeItem(*newChild);
|
TestTreeItem *toBeAdded = new TestTreeItem(*newChild);
|
||||||
toBeAdded->setParent(toBeModifiedItem);
|
toBeAdded->setParent(toBeModifiedItem);
|
||||||
|
if (checkStates.contains(toBeAdded->name())
|
||||||
|
&& checkStates.value(toBeAdded->name()) != Qt::Checked)
|
||||||
|
toBeAdded->setChecked(checkStates.value(toBeAdded->name()));
|
||||||
beginInsertRows(toBeModifiedIndex, row, row);
|
beginInsertRows(toBeModifiedIndex, row, row);
|
||||||
toBeModifiedItem->appendChild(toBeAdded);
|
toBeModifiedItem->appendChild(toBeAdded);
|
||||||
endInsertRows();
|
endInsertRows();
|
||||||
if (originalItems.contains(toBeAdded->name())
|
|
||||||
&& originalItems.value(toBeAdded->name()) != Qt::Checked)
|
|
||||||
toBeAdded->setChecked(originalItems.value(toBeAdded->name()));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
for (int row = 0; row < newChildCount; ++row) {
|
processChildren(toBeModifiedIndex, newItem, newChildCount, checkStates);
|
||||||
QModelIndex child = toBeModifiedIndex.child(row, 0);
|
// remove rest of the items
|
||||||
|
removeRows(newChildCount, childCount - newChildCount, toBeModifiedIndex);
|
||||||
|
}
|
||||||
|
emit testTreeModelChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
void TestTreeModel::processChildren(QModelIndex &parentIndex, const TestTreeItem &newItem,
|
||||||
|
const int upperBound,
|
||||||
|
const QHash<QString, Qt::CheckState> &checkStates)
|
||||||
|
{
|
||||||
|
static QVector<int> modificationRoles = QVector<int>() << Qt::DisplayRole
|
||||||
|
<< Qt::ToolTipRole << LinkRole;
|
||||||
|
TestTreeItem *toBeModifiedItem = static_cast<TestTreeItem *>(parentIndex.internalPointer());
|
||||||
|
for (int row = 0; row < upperBound; ++row) {
|
||||||
|
QModelIndex child = parentIndex.child(row, 0);
|
||||||
TestTreeItem *toBeModifiedChild = toBeModifiedItem->child(row);
|
TestTreeItem *toBeModifiedChild = toBeModifiedItem->child(row);
|
||||||
TestTreeItem *modifiedChild = newItem->child(row);
|
TestTreeItem *modifiedChild = newItem.child(row);
|
||||||
if (toBeModifiedChild->modifyContent(modifiedChild))
|
if (toBeModifiedChild->modifyContent(modifiedChild))
|
||||||
emit dataChanged(child, child, modificationRoles);
|
emit dataChanged(child, child, modificationRoles);
|
||||||
if (originalItems.contains(toBeModifiedChild->name())) {
|
if (checkStates.contains(toBeModifiedChild->name())) {
|
||||||
Qt::CheckState state = originalItems.value(toBeModifiedChild->name());
|
Qt::CheckState state = checkStates.value(toBeModifiedChild->name());
|
||||||
if (state != toBeModifiedChild->checked()) {
|
if (state != toBeModifiedChild->checked()) {
|
||||||
toBeModifiedChild->setChecked(state);
|
toBeModifiedChild->setChecked(state);
|
||||||
emit dataChanged(child, child, QVector<int>() << Qt::CheckStateRole);
|
emit dataChanged(child, child, QVector<int>() << Qt::CheckStateRole);
|
||||||
@@ -699,10 +805,7 @@ void TestTreeModel::modifyTestSubtree(QModelIndex &toBeModifiedIndex, TestTreeIt
|
|||||||
toBeModifiedChild->setChecked(Qt::Checked);
|
toBeModifiedChild->setChecked(Qt::Checked);
|
||||||
emit dataChanged(child, child, QVector<int>() << Qt::CheckStateRole);
|
emit dataChanged(child, child, QVector<int>() << Qt::CheckStateRole);
|
||||||
}
|
}
|
||||||
} // remove rest of the items
|
|
||||||
removeRows(newChildCount, childCount - newChildCount, toBeModifiedIndex);
|
|
||||||
}
|
}
|
||||||
emit testTreeModelChanged();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/***************************** Sort/Filter Model **********************************/
|
/***************************** Sort/Filter Model **********************************/
|
||||||
|
|||||||
@@ -37,6 +37,7 @@ namespace {
|
|||||||
namespace Autotest {
|
namespace Autotest {
|
||||||
namespace Internal {
|
namespace Internal {
|
||||||
|
|
||||||
|
struct TestCodeLocationAndType;
|
||||||
class TestCodeParser;
|
class TestCodeParser;
|
||||||
class TestInfo;
|
class TestInfo;
|
||||||
class TestTreeItem;
|
class TestTreeItem;
|
||||||
@@ -45,6 +46,11 @@ class TestTreeModel : public QAbstractItemModel
|
|||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
|
enum Type {
|
||||||
|
AutoTest,
|
||||||
|
QuickTest
|
||||||
|
};
|
||||||
|
|
||||||
static TestTreeModel* instance();
|
static TestTreeModel* instance();
|
||||||
~TestTreeModel();
|
~TestTreeModel();
|
||||||
|
|
||||||
@@ -62,18 +68,13 @@ public:
|
|||||||
bool hasTests() const;
|
bool hasTests() const;
|
||||||
QList<TestConfiguration *> getAllTestCases() const;
|
QList<TestConfiguration *> getAllTestCases() const;
|
||||||
QList<TestConfiguration *> getSelectedTests() const;
|
QList<TestConfiguration *> getSelectedTests() const;
|
||||||
TestTreeItem *unnamedQuickTests() const;
|
QString getMainFileForUnnamedQuickTest(const QString &qmlFile) const;
|
||||||
|
void qmlFilesAndFunctionNamesForMainFile(const QString &mainFile, QSet<QString> *filePaths,
|
||||||
|
QList<QString> *functionNames) const;
|
||||||
|
QList<QString> getUnnamedQuickTestFunctions() const;
|
||||||
|
QSet<QString> qmlFilesForProFile(const QString &proFile) const;
|
||||||
|
bool hasUnnamedQuickTests() const;
|
||||||
|
|
||||||
void modifyAutoTestSubtree(int row, TestTreeItem *newItem);
|
|
||||||
void removeAutoTestSubtreeByFilePath(const QString &file);
|
|
||||||
void addAutoTest(TestTreeItem *newItem);
|
|
||||||
void removeAllAutoTests();
|
|
||||||
|
|
||||||
void modifyQuickTestSubtree(int row, TestTreeItem *newItem);
|
|
||||||
void removeQuickTestSubtreeByFilePath(const QString &file);
|
|
||||||
void addQuickTest(TestTreeItem *newItem);
|
|
||||||
void removeAllQuickTests();
|
|
||||||
bool removeUnnamedQuickTests(const QString &filePath);
|
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void testTreeModelChanged();
|
void testTreeModelChanged();
|
||||||
@@ -81,8 +82,23 @@ signals:
|
|||||||
public slots:
|
public slots:
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
void addTestTreeItem(const TestTreeItem &item, Type type);
|
||||||
|
void addTestTreeItems(const QList<TestTreeItem> &itemList, Type type);
|
||||||
|
void updateUnnamedQuickTest(const QString &fileName, const QString &mainFile,
|
||||||
|
const QMap<QString, TestCodeLocationAndType> &functions);
|
||||||
|
void modifyTestTreeItem(TestTreeItem item, Type type, const QString &file);
|
||||||
|
void removeAllTestItems();
|
||||||
|
void removeTestTreeItems(const QString &filePath, Type type);
|
||||||
|
void removeUnnamedQuickTests(const QString &filePath);
|
||||||
|
|
||||||
|
TestTreeItem *unnamedQuickTests() const;
|
||||||
|
TestTreeItem *rootItemForType(Type type);
|
||||||
|
QModelIndex rootIndexForType(Type type);
|
||||||
|
|
||||||
explicit TestTreeModel(QObject *parent = 0);
|
explicit TestTreeModel(QObject *parent = 0);
|
||||||
void modifyTestSubtree(QModelIndex &toBeModifiedIndex, TestTreeItem *newItem);
|
void modifyTestSubtree(QModelIndex &toBeModifiedIndex, const TestTreeItem &newItem);
|
||||||
|
void processChildren(QModelIndex &parentIndex, const TestTreeItem &newItem,
|
||||||
|
const int upperBound, const QHash<QString, Qt::CheckState> &checkStates);
|
||||||
|
|
||||||
TestTreeItem *m_rootItem;
|
TestTreeItem *m_rootItem;
|
||||||
TestTreeItem *m_autoTestRootItem;
|
TestTreeItem *m_autoTestRootItem;
|
||||||
|
|||||||
@@ -35,13 +35,6 @@
|
|||||||
namespace Autotest {
|
namespace Autotest {
|
||||||
namespace Internal {
|
namespace Internal {
|
||||||
|
|
||||||
struct TestCodeLocationAndType {
|
|
||||||
QString m_fileName;
|
|
||||||
unsigned m_line;
|
|
||||||
unsigned m_column;
|
|
||||||
TestTreeItem::Type m_type;
|
|
||||||
};
|
|
||||||
|
|
||||||
class TestVisitor : public CPlusPlus::SymbolVisitor
|
class TestVisitor : public CPlusPlus::SymbolVisitor
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|||||||
Reference in New Issue
Block a user